1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Derick Rethans <derick@derickrethans.nl> | 16 +----------------------------------------------------------------------+ 17 */ 18 19/* $Id$ */ 20 21#include "timelib.h" 22 23#include <stdio.h> 24#include <ctype.h> 25#include <math.h> 26#include <assert.h> 27 28#ifdef HAVE_STDLIB_H 29#include <stdlib.h> 30#endif 31#ifdef HAVE_STRING_H 32#include <string.h> 33#else 34#include <strings.h> 35#endif 36 37#if defined(_MSC_VER) 38# define strtoll(s, f, b) _atoi64(s) 39#elif !defined(HAVE_STRTOLL) 40# if defined(HAVE_ATOLL) 41# define strtoll(s, f, b) atoll(s) 42# else 43# define strtoll(s, f, b) strtol(s, f, b) 44# endif 45#endif 46 47#define TIMELIB_UNSET -99999 48 49#define TIMELIB_SECOND 1 50#define TIMELIB_MINUTE 2 51#define TIMELIB_HOUR 3 52#define TIMELIB_DAY 4 53#define TIMELIB_MONTH 5 54#define TIMELIB_YEAR 6 55#define TIMELIB_WEEKDAY 7 56#define TIMELIB_SPECIAL 8 57 58#define EOI 257 59#define TIME 258 60#define DATE 259 61 62#define TIMELIB_XMLRPC_SOAP 260 63#define TIMELIB_TIME12 261 64#define TIMELIB_TIME24 262 65#define TIMELIB_GNU_NOCOLON 263 66#define TIMELIB_GNU_NOCOLON_TZ 264 67#define TIMELIB_ISO_NOCOLON 265 68 69#define TIMELIB_AMERICAN 266 70#define TIMELIB_ISO_DATE 267 71#define TIMELIB_DATE_FULL 268 72#define TIMELIB_DATE_TEXT 269 73#define TIMELIB_DATE_NOCOLON 270 74#define TIMELIB_PG_YEARDAY 271 75#define TIMELIB_PG_TEXT 272 76#define TIMELIB_PG_REVERSE 273 77#define TIMELIB_CLF 274 78#define TIMELIB_DATE_NO_DAY 275 79#define TIMELIB_SHORTDATE_WITH_TIME 276 80#define TIMELIB_DATE_FULL_POINTED 277 81#define TIMELIB_TIME24_WITH_ZONE 278 82#define TIMELIB_ISO_WEEK 279 83#define TIMELIB_LF_DAY_OF_MONTH 280 84#define TIMELIB_WEEK_DAY_OF_MONTH 281 85 86#define TIMELIB_TIMEZONE 300 87#define TIMELIB_AGO 301 88 89#define TIMELIB_RELATIVE 310 90 91#define TIMELIB_ERROR 999 92 93/* Some compilers like AIX, defines uchar in sys/types.h */ 94#undef uchar 95typedef unsigned char uchar; 96 97#define BSIZE 8192 98 99#define YYCTYPE uchar 100#define YYCURSOR cursor 101#define YYLIMIT s->lim 102#define YYMARKER s->ptr 103#define YYFILL(n) return EOI; 104 105#define RET(i) {s->cur = cursor; return i;} 106 107#define timelib_string_free free 108 109#define TIMELIB_HAVE_TIME() { if (s->time->have_time) { add_error(s, "Double time specification"); timelib_string_free(str); return TIMELIB_ERROR; } else { s->time->have_time = 1; s->time->h = 0; s->time->i = 0; s->time->s = 0; s->time->f = 0; } } 110#define TIMELIB_UNHAVE_TIME() { s->time->have_time = 0; s->time->h = 0; s->time->i = 0; s->time->s = 0; s->time->f = 0; } 111#define TIMELIB_HAVE_DATE() { if (s->time->have_date) { add_error(s, "Double date specification"); timelib_string_free(str); return TIMELIB_ERROR; } else { s->time->have_date = 1; } } 112#define TIMELIB_UNHAVE_DATE() { s->time->have_date = 0; s->time->d = 0; s->time->m = 0; s->time->y = 0; } 113#define TIMELIB_HAVE_RELATIVE() { s->time->have_relative = 1; } 114#define TIMELIB_HAVE_WEEKDAY_RELATIVE() { s->time->have_relative = 1; s->time->relative.have_weekday_relative = 1; } 115#define TIMELIB_HAVE_SPECIAL_RELATIVE() { s->time->have_relative = 1; s->time->relative.have_special_relative = 1; } 116#define TIMELIB_HAVE_TZ() { s->cur = cursor; if (s->time->have_zone) { s->time->have_zone > 1 ? add_error(s, "Double timezone specification") : add_warning(s, "Double timezone specification"); timelib_string_free(str); s->time->have_zone++; return TIMELIB_ERROR; } else { s->time->have_zone++; } } 117 118#define TIMELIB_INIT s->cur = cursor; str = timelib_string(s); ptr = str 119#define TIMELIB_DEINIT timelib_string_free(str) 120#define TIMELIB_ADJUST_RELATIVE_WEEKDAY() if (in->time.have_weekday_relative && (in.rel.d > 0)) { in.rel.d -= 7; } 121 122#define TIMELIB_PROCESS_YEAR(x, l) { \ 123 if (((x) == TIMELIB_UNSET) || ((l) >= 4)) { \ 124 /* (x) = 0; */ \ 125 } else if ((x) < 100) { \ 126 if ((x) < 70) { \ 127 (x) += 2000; \ 128 } else { \ 129 (x) += 1900; \ 130 } \ 131 } \ 132} 133 134#ifdef DEBUG_PARSER 135#define DEBUG_OUTPUT(s) printf("%s\n", s); 136#define YYDEBUG(s,c) { if (s != -1) { printf("state: %d ", s); printf("[%c]\n", c); } } 137#else 138#define DEBUG_OUTPUT(s) 139#define YYDEBUG(s,c) 140#endif 141 142#include "timelib_structs.h" 143 144typedef struct timelib_elems { 145 unsigned int c; /* Number of elements */ 146 char **v; /* Values */ 147} timelib_elems; 148 149typedef struct Scanner { 150 int fd; 151 uchar *lim, *str, *ptr, *cur, *tok, *pos; 152 unsigned int line, len; 153 struct timelib_error_container *errors; 154 155 struct timelib_time *time; 156 const timelib_tzdb *tzdb; 157} Scanner; 158 159typedef struct _timelib_lookup_table { 160 const char *name; 161 int type; 162 int value; 163} timelib_lookup_table; 164 165typedef struct _timelib_relunit { 166 const char *name; 167 int unit; 168 int multiplier; 169} timelib_relunit; 170 171/* The timezone table. */ 172const static timelib_tz_lookup_table timelib_timezone_lookup[] = { 173#include "timezonemap.h" 174 { NULL, 0, 0, NULL }, 175}; 176 177const static timelib_tz_lookup_table timelib_timezone_fallbackmap[] = { 178#include "fallbackmap.h" 179 { NULL, 0, 0, NULL }, 180}; 181 182const static timelib_tz_lookup_table timelib_timezone_utc[] = { 183 { "utc", 0, 0, "UTC" }, 184}; 185 186static timelib_relunit const timelib_relunit_lookup[] = { 187 { "sec", TIMELIB_SECOND, 1 }, 188 { "secs", TIMELIB_SECOND, 1 }, 189 { "second", TIMELIB_SECOND, 1 }, 190 { "seconds", TIMELIB_SECOND, 1 }, 191 { "min", TIMELIB_MINUTE, 1 }, 192 { "mins", TIMELIB_MINUTE, 1 }, 193 { "minute", TIMELIB_MINUTE, 1 }, 194 { "minutes", TIMELIB_MINUTE, 1 }, 195 { "hour", TIMELIB_HOUR, 1 }, 196 { "hours", TIMELIB_HOUR, 1 }, 197 { "day", TIMELIB_DAY, 1 }, 198 { "days", TIMELIB_DAY, 1 }, 199 { "week", TIMELIB_DAY, 7 }, 200 { "weeks", TIMELIB_DAY, 7 }, 201 { "fortnight", TIMELIB_DAY, 14 }, 202 { "fortnights", TIMELIB_DAY, 14 }, 203 { "forthnight", TIMELIB_DAY, 14 }, 204 { "forthnights", TIMELIB_DAY, 14 }, 205 { "month", TIMELIB_MONTH, 1 }, 206 { "months", TIMELIB_MONTH, 1 }, 207 { "year", TIMELIB_YEAR, 1 }, 208 { "years", TIMELIB_YEAR, 1 }, 209 210 { "monday", TIMELIB_WEEKDAY, 1 }, 211 { "mon", TIMELIB_WEEKDAY, 1 }, 212 { "tuesday", TIMELIB_WEEKDAY, 2 }, 213 { "tue", TIMELIB_WEEKDAY, 2 }, 214 { "wednesday", TIMELIB_WEEKDAY, 3 }, 215 { "wed", TIMELIB_WEEKDAY, 3 }, 216 { "thursday", TIMELIB_WEEKDAY, 4 }, 217 { "thu", TIMELIB_WEEKDAY, 4 }, 218 { "friday", TIMELIB_WEEKDAY, 5 }, 219 { "fri", TIMELIB_WEEKDAY, 5 }, 220 { "saturday", TIMELIB_WEEKDAY, 6 }, 221 { "sat", TIMELIB_WEEKDAY, 6 }, 222 { "sunday", TIMELIB_WEEKDAY, 0 }, 223 { "sun", TIMELIB_WEEKDAY, 0 }, 224 225 { "weekday", TIMELIB_SPECIAL, TIMELIB_SPECIAL_WEEKDAY }, 226 { "weekdays", TIMELIB_SPECIAL, TIMELIB_SPECIAL_WEEKDAY }, 227 { NULL, 0, 0 } 228}; 229 230/* The relative text table. */ 231static timelib_lookup_table const timelib_reltext_lookup[] = { 232 { "first", 0, 1 }, 233 { "next", 0, 1 }, 234 { "second", 0, 2 }, 235 { "third", 0, 3 }, 236 { "fourth", 0, 4 }, 237 { "fifth", 0, 5 }, 238 { "sixth", 0, 6 }, 239 { "seventh", 0, 7 }, 240 { "eight", 0, 8 }, 241 { "eighth", 0, 8 }, 242 { "ninth", 0, 9 }, 243 { "tenth", 0, 10 }, 244 { "eleventh", 0, 11 }, 245 { "twelfth", 0, 12 }, 246 { "last", 0, -1 }, 247 { "previous", 0, -1 }, 248 { "this", 1, 0 }, 249 { NULL, 1, 0 } 250}; 251 252/* The month table. */ 253static timelib_lookup_table const timelib_month_lookup[] = { 254 { "jan", 0, 1 }, 255 { "feb", 0, 2 }, 256 { "mar", 0, 3 }, 257 { "apr", 0, 4 }, 258 { "may", 0, 5 }, 259 { "jun", 0, 6 }, 260 { "jul", 0, 7 }, 261 { "aug", 0, 8 }, 262 { "sep", 0, 9 }, 263 { "sept", 0, 9 }, 264 { "oct", 0, 10 }, 265 { "nov", 0, 11 }, 266 { "dec", 0, 12 }, 267 { "i", 0, 1 }, 268 { "ii", 0, 2 }, 269 { "iii", 0, 3 }, 270 { "iv", 0, 4 }, 271 { "v", 0, 5 }, 272 { "vi", 0, 6 }, 273 { "vii", 0, 7 }, 274 { "viii", 0, 8 }, 275 { "ix", 0, 9 }, 276 { "x", 0, 10 }, 277 { "xi", 0, 11 }, 278 { "xii", 0, 12 }, 279 280 { "january", 0, 1 }, 281 { "february", 0, 2 }, 282 { "march", 0, 3 }, 283 { "april", 0, 4 }, 284 { "may", 0, 5 }, 285 { "june", 0, 6 }, 286 { "july", 0, 7 }, 287 { "august", 0, 8 }, 288 { "september", 0, 9 }, 289 { "october", 0, 10 }, 290 { "november", 0, 11 }, 291 { "december", 0, 12 }, 292 { NULL, 0, 0 } 293}; 294 295#if 0 296static char* timelib_ltrim(char *s) 297{ 298 char *ptr = s; 299 while (ptr[0] == ' ' || ptr[0] == '\t') { 300 ptr++; 301 } 302 return ptr; 303} 304#endif 305 306#if 0 307uchar *fill(Scanner *s, uchar *cursor){ 308 if(!s->eof){ 309 unsigned int cnt = s->tok - s->bot; 310 if(cnt){ 311 memcpy(s->bot, s->tok, s->lim - s->tok); 312 s->tok = s->bot; 313 s->ptr -= cnt; 314 cursor -= cnt; 315 s->pos -= cnt; 316 s->lim -= cnt; 317 } 318 if((s->top - s->lim) < BSIZE){ 319 uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); 320 memcpy(buf, s->tok, s->lim - s->tok); 321 s->tok = buf; 322 s->ptr = &buf[s->ptr - s->bot]; 323 cursor = &buf[cursor - s->bot]; 324 s->pos = &buf[s->pos - s->bot]; 325 s->lim = &buf[s->lim - s->bot]; 326 s->top = &s->lim[BSIZE]; 327 free(s->bot); 328 s->bot = buf; 329 } 330 if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE){ 331 s->eof = &s->lim[cnt]; *(s->eof)++ = '\n'; 332 } 333 s->lim += cnt; 334 } 335 return cursor; 336} 337#endif 338 339static void add_warning(Scanner *s, char *error) 340{ 341 s->errors->warning_count++; 342 s->errors->warning_messages = realloc(s->errors->warning_messages, s->errors->warning_count * sizeof(timelib_error_message)); 343 s->errors->warning_messages[s->errors->warning_count - 1].position = s->tok ? s->tok - s->str : 0; 344 s->errors->warning_messages[s->errors->warning_count - 1].character = s->tok ? *s->tok : 0; 345 s->errors->warning_messages[s->errors->warning_count - 1].message = strdup(error); 346} 347 348static void add_error(Scanner *s, char *error) 349{ 350 s->errors->error_count++; 351 s->errors->error_messages = realloc(s->errors->error_messages, s->errors->error_count * sizeof(timelib_error_message)); 352 s->errors->error_messages[s->errors->error_count - 1].position = s->tok ? s->tok - s->str : 0; 353 s->errors->error_messages[s->errors->error_count - 1].character = s->tok ? *s->tok : 0; 354 s->errors->error_messages[s->errors->error_count - 1].message = strdup(error); 355} 356 357static void add_pbf_warning(Scanner *s, char *error, char *sptr, char *cptr) 358{ 359 s->errors->warning_count++; 360 s->errors->warning_messages = realloc(s->errors->warning_messages, s->errors->warning_count * sizeof(timelib_error_message)); 361 s->errors->warning_messages[s->errors->warning_count - 1].position = cptr - sptr; 362 s->errors->warning_messages[s->errors->warning_count - 1].character = *cptr; 363 s->errors->warning_messages[s->errors->warning_count - 1].message = strdup(error); 364} 365 366static void add_pbf_error(Scanner *s, char *error, char *sptr, char *cptr) 367{ 368 s->errors->error_count++; 369 s->errors->error_messages = realloc(s->errors->error_messages, s->errors->error_count * sizeof(timelib_error_message)); 370 s->errors->error_messages[s->errors->error_count - 1].position = cptr - sptr; 371 s->errors->error_messages[s->errors->error_count - 1].character = *cptr; 372 s->errors->error_messages[s->errors->error_count - 1].message = strdup(error); 373} 374 375static timelib_sll timelib_meridian(char **ptr, timelib_sll h) 376{ 377 timelib_sll retval = 0; 378 379 while (!strchr("AaPp", **ptr)) { 380 ++*ptr; 381 } 382 if (**ptr == 'a' || **ptr == 'A') { 383 if (h == 12) { 384 retval = -12; 385 } 386 } else if (h != 12) { 387 retval = 12; 388 } 389 ++*ptr; 390 if (**ptr == '.') { 391 *ptr += 3; 392 } else { 393 ++*ptr; 394 } 395 return retval; 396} 397 398static timelib_sll timelib_meridian_with_check(char **ptr, timelib_sll h) 399{ 400 timelib_sll retval = 0; 401 402 while (!strchr("AaPp", **ptr)) { 403 ++*ptr; 404 } 405 if (**ptr == 'a' || **ptr == 'A') { 406 if (h == 12) { 407 retval = -12; 408 } 409 } else if (h != 12) { 410 retval = 12; 411 } 412 ++*ptr; 413 if (**ptr == '.') { 414 ++*ptr; 415 if (**ptr != 'm' && **ptr != 'M') { 416 return TIMELIB_UNSET; 417 } 418 ++*ptr; 419 if (**ptr != '.' ) { 420 return TIMELIB_UNSET; 421 } 422 ++*ptr; 423 } else if (**ptr == 'm' || **ptr == 'M') { 424 ++*ptr; 425 } else { 426 return TIMELIB_UNSET; 427 } 428 return retval; 429} 430 431static char *timelib_string(Scanner *s) 432{ 433 char *tmp = calloc(1, s->cur - s->tok + 1); 434 memcpy(tmp, s->tok, s->cur - s->tok); 435 436 return tmp; 437} 438 439static timelib_sll timelib_get_nr_ex(char **ptr, int max_length, int *scanned_length) 440{ 441 char *begin, *end, *str; 442 timelib_sll tmp_nr = TIMELIB_UNSET; 443 int len = 0; 444 445 while ((**ptr < '0') || (**ptr > '9')) { 446 if (**ptr == '\0') { 447 return TIMELIB_UNSET; 448 } 449 ++*ptr; 450 } 451 begin = *ptr; 452 while ((**ptr >= '0') && (**ptr <= '9') && len < max_length) { 453 ++*ptr; 454 ++len; 455 } 456 end = *ptr; 457 if (scanned_length) { 458 *scanned_length = end - begin; 459 } 460 str = calloc(1, end - begin + 1); 461 memcpy(str, begin, end - begin); 462 tmp_nr = strtoll(str, NULL, 10); 463 free(str); 464 return tmp_nr; 465} 466 467static timelib_sll timelib_get_nr(char **ptr, int max_length) 468{ 469 return timelib_get_nr_ex(ptr, max_length, NULL); 470} 471 472static void timelib_skip_day_suffix(char **ptr) 473{ 474 if (isspace(**ptr)) { 475 return; 476 } 477 if (!strncasecmp(*ptr, "nd", 2) || !strncasecmp(*ptr, "rd", 2) ||!strncasecmp(*ptr, "st", 2) || !strncasecmp(*ptr, "th", 2)) { 478 *ptr += 2; 479 } 480} 481 482static double timelib_get_frac_nr(char **ptr, int max_length) 483{ 484 char *begin, *end, *str; 485 double tmp_nr = TIMELIB_UNSET; 486 int len = 0; 487 488 while ((**ptr != '.') && (**ptr != ':') && ((**ptr < '0') || (**ptr > '9'))) { 489 if (**ptr == '\0') { 490 return TIMELIB_UNSET; 491 } 492 ++*ptr; 493 } 494 begin = *ptr; 495 while (((**ptr == '.') || (**ptr == ':') || ((**ptr >= '0') && (**ptr <= '9'))) && len < max_length) { 496 ++*ptr; 497 ++len; 498 } 499 end = *ptr; 500 str = calloc(1, end - begin + 1); 501 memcpy(str, begin, end - begin); 502 if (str[0] == ':') { 503 str[0] = '.'; 504 } 505 tmp_nr = strtod(str, NULL); 506 free(str); 507 return tmp_nr; 508} 509 510static timelib_ull timelib_get_unsigned_nr(char **ptr, int max_length) 511{ 512 timelib_ull dir = 1; 513 514 while (((**ptr < '0') || (**ptr > '9')) && (**ptr != '+') && (**ptr != '-')) { 515 if (**ptr == '\0') { 516 return TIMELIB_UNSET; 517 } 518 ++*ptr; 519 } 520 521 while (**ptr == '+' || **ptr == '-') 522 { 523 if (**ptr == '-') { 524 dir *= -1; 525 } 526 ++*ptr; 527 } 528 return dir * timelib_get_nr(ptr, max_length); 529} 530 531static timelib_sll timelib_lookup_relative_text(char **ptr, int *behavior) 532{ 533 char *word; 534 char *begin = *ptr, *end; 535 timelib_sll value = 0; 536 const timelib_lookup_table *tp; 537 538 while ((**ptr >= 'A' && **ptr <= 'Z') || (**ptr >= 'a' && **ptr <= 'z')) { 539 ++*ptr; 540 } 541 end = *ptr; 542 word = calloc(1, end - begin + 1); 543 memcpy(word, begin, end - begin); 544 545 for (tp = timelib_reltext_lookup; tp->name; tp++) { 546 if (strcasecmp(word, tp->name) == 0) { 547 value = tp->value; 548 *behavior = tp->type; 549 } 550 } 551 552 free(word); 553 return value; 554} 555 556static timelib_sll timelib_get_relative_text(char **ptr, int *behavior) 557{ 558 while (**ptr == ' ' || **ptr == '\t' || **ptr == '-' || **ptr == '/') { 559 ++*ptr; 560 } 561 return timelib_lookup_relative_text(ptr, behavior); 562} 563 564static long timelib_lookup_month(char **ptr) 565{ 566 char *word; 567 char *begin = *ptr, *end; 568 long value = 0; 569 const timelib_lookup_table *tp; 570 571 while ((**ptr >= 'A' && **ptr <= 'Z') || (**ptr >= 'a' && **ptr <= 'z')) { 572 ++*ptr; 573 } 574 end = *ptr; 575 word = calloc(1, end - begin + 1); 576 memcpy(word, begin, end - begin); 577 578 for (tp = timelib_month_lookup; tp->name; tp++) { 579 if (strcasecmp(word, tp->name) == 0) { 580 value = tp->value; 581 } 582 } 583 584 free(word); 585 return value; 586} 587 588static long timelib_get_month(char **ptr) 589{ 590 while (**ptr == ' ' || **ptr == '\t' || **ptr == '-' || **ptr == '.' || **ptr == '/') { 591 ++*ptr; 592 } 593 return timelib_lookup_month(ptr); 594} 595 596static void timelib_eat_spaces(char **ptr) 597{ 598 while (**ptr == ' ' || **ptr == '\t') { 599 ++*ptr; 600 } 601} 602 603static void timelib_eat_until_separator(char **ptr) 604{ 605 ++*ptr; 606 while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) { 607 ++*ptr; 608 } 609} 610 611static const timelib_relunit* timelib_lookup_relunit(char **ptr) 612{ 613 char *word; 614 char *begin = *ptr, *end; 615 const timelib_relunit *tp, *value = NULL; 616 617 while (**ptr != '\0' && **ptr != ' ' && **ptr != ',' && **ptr != '\t') { 618 ++*ptr; 619 } 620 end = *ptr; 621 word = calloc(1, end - begin + 1); 622 memcpy(word, begin, end - begin); 623 624 for (tp = timelib_relunit_lookup; tp->name; tp++) { 625 if (strcasecmp(word, tp->name) == 0) { 626 value = tp; 627 break; 628 } 629 } 630 631 free(word); 632 return value; 633} 634 635static void timelib_set_relative(char **ptr, timelib_sll amount, int behavior, Scanner *s) 636{ 637 const timelib_relunit* relunit; 638 639 if (!(relunit = timelib_lookup_relunit(ptr))) { 640 return; 641 } 642 643 switch (relunit->unit) { 644 case TIMELIB_SECOND: s->time->relative.s += amount * relunit->multiplier; break; 645 case TIMELIB_MINUTE: s->time->relative.i += amount * relunit->multiplier; break; 646 case TIMELIB_HOUR: s->time->relative.h += amount * relunit->multiplier; break; 647 case TIMELIB_DAY: s->time->relative.d += amount * relunit->multiplier; break; 648 case TIMELIB_MONTH: s->time->relative.m += amount * relunit->multiplier; break; 649 case TIMELIB_YEAR: s->time->relative.y += amount * relunit->multiplier; break; 650 651 case TIMELIB_WEEKDAY: 652 TIMELIB_HAVE_WEEKDAY_RELATIVE(); 653 TIMELIB_UNHAVE_TIME(); 654 s->time->relative.d += (amount > 0 ? amount - 1 : amount) * 7; 655 s->time->relative.weekday = relunit->multiplier; 656 s->time->relative.weekday_behavior = behavior; 657 break; 658 659 case TIMELIB_SPECIAL: 660 TIMELIB_HAVE_SPECIAL_RELATIVE(); 661 TIMELIB_UNHAVE_TIME(); 662 s->time->relative.special.type = relunit->multiplier; 663 s->time->relative.special.amount = amount; 664 } 665} 666 667const static timelib_tz_lookup_table* zone_search(const char *word, long gmtoffset, int isdst) 668{ 669 int first_found = 0; 670 const timelib_tz_lookup_table *tp, *first_found_elem = NULL; 671 const timelib_tz_lookup_table *fmp; 672 673 if (strcasecmp("utc", word) == 0 || strcasecmp("gmt", word) == 0) { 674 return timelib_timezone_utc; 675 } 676 677 for (tp = timelib_timezone_lookup; tp->name; tp++) { 678 if (strcasecmp(word, tp->name) == 0) { 679 if (!first_found) { 680 first_found = 1; 681 first_found_elem = tp; 682 if (gmtoffset == -1) { 683 return tp; 684 } 685 } 686 if (tp->gmtoffset == gmtoffset) { 687 return tp; 688 } 689 } 690 } 691 if (first_found) { 692 return first_found_elem; 693 } 694 695 for (tp = timelib_timezone_lookup; tp->name; tp++) { 696 if (tp->full_tz_name && strcasecmp(word, tp->full_tz_name) == 0) { 697 if (!first_found) { 698 first_found = 1; 699 first_found_elem = tp; 700 if (gmtoffset == -1) { 701 return tp; 702 } 703 } 704 if (tp->gmtoffset == gmtoffset) { 705 return tp; 706 } 707 } 708 } 709 if (first_found) { 710 return first_found_elem; 711 } 712 713 714 /* Still didn't find anything, let's find the zone solely based on 715 * offset/isdst then */ 716 for (fmp = timelib_timezone_fallbackmap; fmp->name; fmp++) { 717 if ((fmp->gmtoffset * 3600) == gmtoffset && fmp->type == isdst) { 718 return fmp; 719 } 720 } 721 return NULL; 722} 723 724static long timelib_lookup_zone(char **ptr, int *dst, char **tz_abbr, int *found) 725{ 726 char *word; 727 char *begin = *ptr, *end; 728 long value = 0; 729 const timelib_tz_lookup_table *tp; 730 731 while (**ptr != '\0' && **ptr != ')' && **ptr != ' ') { 732 ++*ptr; 733 } 734 end = *ptr; 735 word = calloc(1, end - begin + 1); 736 memcpy(word, begin, end - begin); 737 738 if ((tp = zone_search(word, -1, 0))) { 739 value = -tp->gmtoffset / 60; 740 *dst = tp->type; 741 value += tp->type * 60; 742 *found = 1; 743 } else { 744 *found = 0; 745 } 746 747 *tz_abbr = word; 748 return value; 749} 750 751static long timelib_get_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_found, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_wrapper) 752{ 753 timelib_tzinfo *res; 754 long retval = 0; 755 756 *tz_not_found = 0; 757 758 while (**ptr == ' ' || **ptr == '\t' || **ptr == '(') { 759 ++*ptr; 760 } 761 if ((*ptr)[0] == 'G' && (*ptr)[1] == 'M' && (*ptr)[2] == 'T' && ((*ptr)[3] == '+' || (*ptr)[3] == '-')) { 762 *ptr += 3; 763 } 764 if (**ptr == '+') { 765 ++*ptr; 766 t->is_localtime = 1; 767 t->zone_type = TIMELIB_ZONETYPE_OFFSET; 768 *tz_not_found = 0; 769 t->dst = 0; 770 771 retval = -1 * timelib_parse_tz_cor(ptr); 772 } else if (**ptr == '-') { 773 ++*ptr; 774 t->is_localtime = 1; 775 t->zone_type = TIMELIB_ZONETYPE_OFFSET; 776 *tz_not_found = 0; 777 t->dst = 0; 778 779 retval = timelib_parse_tz_cor(ptr); 780 } else { 781 int found = 0; 782 long offset; 783 char *tz_abbr; 784 785 t->is_localtime = 1; 786 787 offset = timelib_lookup_zone(ptr, dst, &tz_abbr, &found); 788 if (found) { 789 t->zone_type = TIMELIB_ZONETYPE_ABBR; 790 } 791#if 0 792 /* If we found a TimeZone identifier, use it */ 793 if (tz_name) { 794 t->tz_info = timelib_parse_tzfile(tz_name); 795 t->zone_type = TIMELIB_ZONETYPE_ID; 796 } 797#endif 798 /* If we have a TimeZone identifier to start with, use it */ 799 if (strstr(tz_abbr, "/") || strcmp(tz_abbr, "UTC") == 0) { 800 if ((res = tz_wrapper(tz_abbr, tzdb)) != NULL) { 801 t->tz_info = res; 802 t->zone_type = TIMELIB_ZONETYPE_ID; 803 found++; 804 } 805 } 806 if (found && t->zone_type != TIMELIB_ZONETYPE_ID) { 807 timelib_time_tz_abbr_update(t, tz_abbr); 808 } 809 free(tz_abbr); 810 *tz_not_found = (found == 0); 811 retval = offset; 812 } 813 while (**ptr == ')') { 814 ++*ptr; 815 } 816 return retval; 817} 818 819#define timelib_split_free(arg) { \ 820 int i; \ 821 for (i = 0; i < arg.c; i++) { \ 822 free(arg.v[i]); \ 823 } \ 824 if (arg.v) { \ 825 free(arg.v); \ 826 } \ 827} 828 829static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) 830{ 831 uchar *cursor = s->cur; 832 char *str, *ptr = NULL; 833 834std: 835 s->tok = cursor; 836 s->len = 0; 837/*!re2c 838any = [\000-\377]; 839 840space = [ \t]+; 841frac = "."[0-9]+; 842 843ago = 'ago'; 844 845hour24 = [01]?[0-9] | "2"[0-4]; 846hour24lz = [01][0-9] | "2"[0-4]; 847hour12 = "0"?[1-9] | "1"[0-2]; 848minute = [0-5]?[0-9]; 849minutelz = [0-5][0-9]; 850second = minute | "60"; 851secondlz = minutelz | "60"; 852meridian = ([AaPp] "."? [Mm] "."?) [\000\t ]; 853tz = "("? [A-Za-z]{1,6} ")"? | [A-Z][a-z]+([_/-][A-Za-z]+)+; 854tzcorrection = "GMT"? [+-] hour24 ":"? minute?; 855 856daysuf = "st" | "nd" | "rd" | "th"; 857 858month = "0"? [0-9] | "1"[0-2]; 859day = (([0-2]?[0-9]) | ("3"[01])) daysuf?; 860year = [0-9]{1,4}; 861year2 = [0-9]{2}; 862year4 = [0-9]{4}; 863year4withsign = [+-]? [0-9]{4}; 864 865dayofyear = "00"[1-9] | "0"[1-9][0-9] | [1-2][0-9][0-9] | "3"[0-5][0-9] | "36"[0-6]; 866weekofyear = "0"[1-9] | [1-4][0-9] | "5"[0-3]; 867 868monthlz = "0" [0-9] | "1" [0-2]; 869daylz = "0" [0-9] | [1-2][0-9] | "3" [01]; 870 871dayfull = 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday'; 872dayabbr = 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' | 'sun'; 873dayspecial = 'weekday' | 'weekdays'; 874daytext = dayfull | dayabbr | dayspecial; 875 876monthfull = 'january' | 'february' | 'march' | 'april' | 'may' | 'june' | 'july' | 'august' | 'september' | 'october' | 'november' | 'december'; 877monthabbr = 'jan' | 'feb' | 'mar' | 'apr' | 'may' | 'jun' | 'jul' | 'aug' | 'sep' | 'sept' | 'oct' | 'nov' | 'dec'; 878monthroman = "I" | "II" | "III" | "IV" | "V" | "VI" | "VII" | "VIII" | "IX" | "X" | "XI" | "XII"; 879monthtext = monthfull | monthabbr | monthroman; 880 881/* Time formats */ 882timetiny12 = hour12 space? meridian; 883timeshort12 = hour12[:.]minutelz space? meridian; 884timelong12 = hour12[:.]minute[:.]secondlz space? meridian; 885 886timeshort24 = 't'? hour24[:.]minute; 887timelong24 = 't'? hour24[:.]minute[:.]second; 888iso8601long = 't'? hour24 [:.] minute [:.] second frac; 889 890/* iso8601shorttz = hour24 [:] minutelz space? (tzcorrection | tz); */ 891iso8601normtz = 't'? hour24 [:.] minute [:.] secondlz space? (tzcorrection | tz); 892/* iso8601longtz = hour24 [:] minute [:] secondlz frac space? (tzcorrection | tz); */ 893 894gnunocolon = 't'? hour24lz minutelz; 895/* gnunocolontz = hour24lz minutelz space? (tzcorrection | tz); */ 896iso8601nocolon = 't'? hour24lz minutelz secondlz; 897/* iso8601nocolontz = hour24lz minutelz secondlz space? (tzcorrection | tz); */ 898 899/* Date formats */ 900americanshort = month "/" day; 901american = month "/" day "/" year; 902iso8601dateslash = year4 "/" monthlz "/" daylz "/"?; 903dateslash = year4 "/" month "/" day; 904iso8601date4 = year4withsign "-" monthlz "-" daylz; 905iso8601date2 = year2 "-" monthlz "-" daylz; 906gnudateshorter = year4 "-" month; 907gnudateshort = year "-" month "-" day; 908pointeddate4 = day [.\t-] month [.-] year4; 909pointeddate2 = day [.\t] month "." year2; 910datefull = day ([ \t.-])* monthtext ([ \t.-])* year; 911datenoday = monthtext ([ .\t-])* year4; 912datenodayrev = year4 ([ .\t-])* monthtext; 913datetextual = monthtext ([ .\t-])* day [,.stndrh\t ]+ year; 914datenoyear = monthtext ([ .\t-])* day [,.stndrh\t ]*; 915datenoyearrev = day ([ .\t-])* monthtext; 916datenocolon = year4 monthlz daylz; 917 918/* Special formats */ 919soap = year4 "-" monthlz "-" daylz "T" hour24lz ":" minutelz ":" secondlz frac tzcorrection?; 920xmlrpc = year4 monthlz daylz "T" hour24 ":" minutelz ":" secondlz; 921xmlrpcnocolon = year4 monthlz daylz 't' hour24 minutelz secondlz; 922wddx = year4 "-" month "-" day "T" hour24 ":" minute ":" second; 923pgydotd = year4 "."? dayofyear; 924pgtextshort = monthabbr "-" daylz "-" year; 925pgtextreverse = year "-" monthabbr "-" daylz; 926mssqltime = hour12 ":" minutelz ":" secondlz [:.] [0-9]+ meridian; 927isoweekday = year4 "-"? "W" weekofyear "-"? [0-7]; 928isoweek = year4 "-"? "W" weekofyear; 929exif = year4 ":" monthlz ":" daylz " " hour24lz ":" minutelz ":" secondlz; 930firstdayof = 'first day of'?; 931lastdayof = 'last day of'?; 932backof = 'back of ' hour24 space? meridian?; 933frontof = 'front of ' hour24 space? meridian?; 934 935/* Common Log Format: 10/Oct/2000:13:55:36 -0700 */ 936clf = day "/" monthabbr "/" year4 ":" hour24lz ":" minutelz ":" secondlz space tzcorrection; 937 938/* Timestamp format: @1126396800 */ 939timestamp = "@" "-"? [0-9]+; 940 941/* To fix some ambiguities */ 942dateshortwithtimeshort12 = datenoyear timeshort12; 943dateshortwithtimelong12 = datenoyear timelong12; 944dateshortwithtimeshort = datenoyear timeshort24; 945dateshortwithtimelong = datenoyear timelong24; 946dateshortwithtimelongtz = datenoyear iso8601normtz; 947 948/* 949 * Relative regexps 950 */ 951reltextnumber = 'first'|'second'|'third'|'fourth'|'fifth'|'sixth'|'seventh'|'eight'|'eighth'|'ninth'|'tenth'|'eleventh'|'twelfth'; 952reltexttext = 'next'|'last'|'previous'|'this'; 953reltextunit = (('sec'|'second'|'min'|'minute'|'hour'|'day'|'fortnight'|'forthnight'|'month'|'year') 's'?) | 'weeks' | daytext; 954 955relnumber = ([+-]*[ \t]*[0-9]+); 956relative = relnumber space? (reltextunit | 'week' ); 957relativetext = (reltextnumber|reltexttext) space reltextunit; 958relativetextweek = reltexttext space 'week'; 959 960weekdayof = (reltextnumber|reltexttext) space (dayfull|dayabbr) space 'of'; 961 962*/ 963 964/*!re2c 965 /* so that vim highlights correctly */ 966 'yesterday' 967 { 968 DEBUG_OUTPUT("yesterday"); 969 TIMELIB_INIT; 970 TIMELIB_HAVE_RELATIVE(); 971 TIMELIB_UNHAVE_TIME(); 972 973 s->time->relative.d = -1; 974 TIMELIB_DEINIT; 975 return TIMELIB_RELATIVE; 976 } 977 978 'now' 979 { 980 DEBUG_OUTPUT("now"); 981 TIMELIB_INIT; 982 983 TIMELIB_DEINIT; 984 return TIMELIB_RELATIVE; 985 } 986 987 'noon' 988 { 989 DEBUG_OUTPUT("noon"); 990 TIMELIB_INIT; 991 TIMELIB_UNHAVE_TIME(); 992 TIMELIB_HAVE_TIME(); 993 s->time->h = 12; 994 995 TIMELIB_DEINIT; 996 return TIMELIB_RELATIVE; 997 } 998 999 'midnight' | 'today' 1000 { 1001 DEBUG_OUTPUT("midnight | today"); 1002 TIMELIB_INIT; 1003 TIMELIB_UNHAVE_TIME(); 1004 1005 TIMELIB_DEINIT; 1006 return TIMELIB_RELATIVE; 1007 } 1008 1009 'tomorrow' 1010 { 1011 DEBUG_OUTPUT("tomorrow"); 1012 TIMELIB_INIT; 1013 TIMELIB_HAVE_RELATIVE(); 1014 TIMELIB_UNHAVE_TIME(); 1015 1016 s->time->relative.d = 1; 1017 TIMELIB_DEINIT; 1018 return TIMELIB_RELATIVE; 1019 } 1020 1021 timestamp 1022 { 1023 timelib_ull i; 1024 1025 TIMELIB_INIT; 1026 TIMELIB_HAVE_RELATIVE(); 1027 TIMELIB_UNHAVE_DATE(); 1028 TIMELIB_UNHAVE_TIME(); 1029 TIMELIB_HAVE_TZ(); 1030 1031 i = timelib_get_unsigned_nr((char **) &ptr, 24); 1032 s->time->y = 1970; 1033 s->time->m = 1; 1034 s->time->d = 1; 1035 s->time->h = s->time->i = s->time->s = 0; 1036 s->time->f = 0.0; 1037 s->time->relative.s += i; 1038 s->time->is_localtime = 1; 1039 s->time->zone_type = TIMELIB_ZONETYPE_OFFSET; 1040 s->time->z = 0; 1041 s->time->dst = 0; 1042 1043 TIMELIB_DEINIT; 1044 return TIMELIB_RELATIVE; 1045 } 1046 1047 firstdayof | lastdayof 1048 { 1049 DEBUG_OUTPUT("firstdayof | lastdayof"); 1050 TIMELIB_INIT; 1051 TIMELIB_HAVE_RELATIVE(); 1052 1053 /* skip "last day of" or "first day of" */ 1054 if (*ptr == 'l') { 1055 s->time->relative.first_last_day_of = 2; 1056 } else { 1057 s->time->relative.first_last_day_of = 1; 1058 } 1059 1060 TIMELIB_DEINIT; 1061 return TIMELIB_LF_DAY_OF_MONTH; 1062 } 1063 1064 backof | frontof 1065 { 1066 DEBUG_OUTPUT("backof | frontof"); 1067 TIMELIB_INIT; 1068 TIMELIB_UNHAVE_TIME(); 1069 TIMELIB_HAVE_TIME(); 1070 1071 if (*ptr == 'b') { 1072 s->time->h = timelib_get_nr((char **) &ptr, 2); 1073 s->time->i = 15; 1074 } else { 1075 s->time->h = timelib_get_nr((char **) &ptr, 2) - 1; 1076 s->time->i = 45; 1077 } 1078 if (*ptr != '\0' ) { 1079 timelib_eat_spaces((char **) &ptr); 1080 s->time->h += timelib_meridian((char **) &ptr, s->time->h); 1081 } 1082 1083 TIMELIB_DEINIT; 1084 return TIMELIB_LF_DAY_OF_MONTH; 1085 } 1086 1087 weekdayof 1088 { 1089 timelib_sll i; 1090 int behavior = 0; 1091 DEBUG_OUTPUT("weekdayof"); 1092 TIMELIB_INIT; 1093 TIMELIB_HAVE_RELATIVE(); 1094 TIMELIB_HAVE_SPECIAL_RELATIVE(); 1095 1096 i = timelib_get_relative_text((char **) &ptr, &behavior); 1097 timelib_eat_spaces((char **) &ptr); 1098 if (i > 0) { /* first, second... etc */ 1099 s->time->relative.special.type = TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH; 1100 timelib_set_relative((char **) &ptr, i, 1, s); 1101 } else { /* last */ 1102 s->time->relative.special.type = TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH; 1103 timelib_set_relative((char **) &ptr, i, behavior, s); 1104 } 1105 TIMELIB_DEINIT; 1106 return TIMELIB_WEEK_DAY_OF_MONTH; 1107 } 1108 1109 timetiny12 | timeshort12 | timelong12 1110 { 1111 DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12"); 1112 TIMELIB_INIT; 1113 TIMELIB_HAVE_TIME(); 1114 s->time->h = timelib_get_nr((char **) &ptr, 2); 1115 if (*ptr == ':' || *ptr == '.') { 1116 s->time->i = timelib_get_nr((char **) &ptr, 2); 1117 if (*ptr == ':' || *ptr == '.') { 1118 s->time->s = timelib_get_nr((char **) &ptr, 2); 1119 } 1120 } 1121 s->time->h += timelib_meridian((char **) &ptr, s->time->h); 1122 TIMELIB_DEINIT; 1123 return TIMELIB_TIME12; 1124 } 1125 1126 mssqltime 1127 { 1128 DEBUG_OUTPUT("mssqltime"); 1129 TIMELIB_INIT; 1130 TIMELIB_HAVE_TIME(); 1131 s->time->h = timelib_get_nr((char **) &ptr, 2); 1132 s->time->i = timelib_get_nr((char **) &ptr, 2); 1133 if (*ptr == ':' || *ptr == '.') { 1134 s->time->s = timelib_get_nr((char **) &ptr, 2); 1135 1136 if (*ptr == ':' || *ptr == '.') { 1137 s->time->f = timelib_get_frac_nr((char **) &ptr, 8); 1138 } 1139 } 1140 timelib_eat_spaces((char **) &ptr); 1141 s->time->h += timelib_meridian((char **) &ptr, s->time->h); 1142 TIMELIB_DEINIT; 1143 return TIMELIB_TIME24_WITH_ZONE; 1144 } 1145 1146 timeshort24 | timelong24 /* | iso8601short | iso8601norm */ | iso8601long /*| iso8601shorttz | iso8601normtz | iso8601longtz*/ 1147 { 1148 int tz_not_found; 1149 DEBUG_OUTPUT("timeshort24 | timelong24 | iso8601long"); 1150 TIMELIB_INIT; 1151 TIMELIB_HAVE_TIME(); 1152 s->time->h = timelib_get_nr((char **) &ptr, 2); 1153 s->time->i = timelib_get_nr((char **) &ptr, 2); 1154 if (*ptr == ':' || *ptr == '.') { 1155 s->time->s = timelib_get_nr((char **) &ptr, 2); 1156 1157 if (*ptr == '.') { 1158 s->time->f = timelib_get_frac_nr((char **) &ptr, 8); 1159 } 1160 } 1161 1162 if (*ptr != '\0') { 1163 s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper); 1164 if (tz_not_found) { 1165 add_error(s, "The timezone could not be found in the database"); 1166 } 1167 } 1168 TIMELIB_DEINIT; 1169 return TIMELIB_TIME24_WITH_ZONE; 1170 } 1171 1172 gnunocolon 1173 { 1174 DEBUG_OUTPUT("gnunocolon"); 1175 TIMELIB_INIT; 1176 switch (s->time->have_time) { 1177 case 0: 1178 s->time->h = timelib_get_nr((char **) &ptr, 2); 1179 s->time->i = timelib_get_nr((char **) &ptr, 2); 1180 s->time->s = 0; 1181 break; 1182 case 1: 1183 s->time->y = timelib_get_nr((char **) &ptr, 4); 1184 break; 1185 default: 1186 TIMELIB_DEINIT; 1187 add_error(s, "Double time specification"); 1188 return TIMELIB_ERROR; 1189 } 1190 s->time->have_time++; 1191 TIMELIB_DEINIT; 1192 return TIMELIB_GNU_NOCOLON; 1193 } 1194/* 1195 gnunocolontz 1196 { 1197 DEBUG_OUTPUT("gnunocolontz"); 1198 TIMELIB_INIT; 1199 switch (s->time->have_time) { 1200 case 0: 1201 s->time->h = timelib_get_nr((char **) &ptr, 2); 1202 s->time->i = timelib_get_nr((char **) &ptr, 2); 1203 s->time->s = 0; 1204 s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, s->tzdb, tz_get_wrapper); 1205 break; 1206 case 1: 1207 s->time->y = timelib_get_nr((char **) &ptr, 4); 1208 break; 1209 default: 1210 TIMELIB_DEINIT; 1211 return TIMELIB_ERROR; 1212 } 1213 s->time->have_time++; 1214 TIMELIB_DEINIT; 1215 return TIMELIB_GNU_NOCOLON_TZ; 1216 } 1217*/ 1218 iso8601nocolon /*| iso8601nocolontz*/ 1219 { 1220 int tz_not_found; 1221 DEBUG_OUTPUT("iso8601nocolon"); 1222 TIMELIB_INIT; 1223 TIMELIB_HAVE_TIME(); 1224 s->time->h = timelib_get_nr((char **) &ptr, 2); 1225 s->time->i = timelib_get_nr((char **) &ptr, 2); 1226 s->time->s = timelib_get_nr((char **) &ptr, 2); 1227 1228 if (*ptr != '\0') { 1229 s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper); 1230 if (tz_not_found) { 1231 add_error(s, "The timezone could not be found in the database"); 1232 } 1233 } 1234 TIMELIB_DEINIT; 1235 return TIMELIB_ISO_NOCOLON; 1236 } 1237 1238 americanshort | american 1239 { 1240 int length = 0; 1241 DEBUG_OUTPUT("americanshort | american"); 1242 TIMELIB_INIT; 1243 TIMELIB_HAVE_DATE(); 1244 s->time->m = timelib_get_nr((char **) &ptr, 2); 1245 s->time->d = timelib_get_nr((char **) &ptr, 2); 1246 if (*ptr == '/') { 1247 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1248 TIMELIB_PROCESS_YEAR(s->time->y, length); 1249 } 1250 TIMELIB_DEINIT; 1251 return TIMELIB_AMERICAN; 1252 } 1253 1254 iso8601date4 | iso8601dateslash | dateslash 1255 { 1256 DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash"); 1257 TIMELIB_INIT; 1258 TIMELIB_HAVE_DATE(); 1259 s->time->y = timelib_get_unsigned_nr((char **) &ptr, 4); 1260 s->time->m = timelib_get_nr((char **) &ptr, 2); 1261 s->time->d = timelib_get_nr((char **) &ptr, 2); 1262 TIMELIB_DEINIT; 1263 return TIMELIB_ISO_DATE; 1264 } 1265 1266 iso8601date2 1267 { 1268 int length = 0; 1269 DEBUG_OUTPUT("iso8601date2"); 1270 TIMELIB_INIT; 1271 TIMELIB_HAVE_DATE(); 1272 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1273 s->time->m = timelib_get_nr((char **) &ptr, 2); 1274 s->time->d = timelib_get_nr((char **) &ptr, 2); 1275 TIMELIB_PROCESS_YEAR(s->time->y, length); 1276 TIMELIB_DEINIT; 1277 return TIMELIB_ISO_DATE; 1278 } 1279 1280 gnudateshorter 1281 { 1282 int length = 0; 1283 DEBUG_OUTPUT("gnudateshorter"); 1284 TIMELIB_INIT; 1285 TIMELIB_HAVE_DATE(); 1286 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1287 s->time->m = timelib_get_nr((char **) &ptr, 2); 1288 s->time->d = 1; 1289 TIMELIB_PROCESS_YEAR(s->time->y, length); 1290 TIMELIB_DEINIT; 1291 return TIMELIB_ISO_DATE; 1292 } 1293 1294 gnudateshort 1295 { 1296 int length = 0; 1297 DEBUG_OUTPUT("gnudateshort"); 1298 TIMELIB_INIT; 1299 TIMELIB_HAVE_DATE(); 1300 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1301 s->time->m = timelib_get_nr((char **) &ptr, 2); 1302 s->time->d = timelib_get_nr((char **) &ptr, 2); 1303 TIMELIB_PROCESS_YEAR(s->time->y, length); 1304 TIMELIB_DEINIT; 1305 return TIMELIB_ISO_DATE; 1306 } 1307 1308 datefull 1309 { 1310 int length = 0; 1311 DEBUG_OUTPUT("datefull"); 1312 TIMELIB_INIT; 1313 TIMELIB_HAVE_DATE(); 1314 s->time->d = timelib_get_nr((char **) &ptr, 2); 1315 timelib_skip_day_suffix((char **) &ptr); 1316 s->time->m = timelib_get_month((char **) &ptr); 1317 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1318 TIMELIB_PROCESS_YEAR(s->time->y, length); 1319 TIMELIB_DEINIT; 1320 return TIMELIB_DATE_FULL; 1321 } 1322 1323 pointeddate4 1324 { 1325 DEBUG_OUTPUT("pointed date YYYY"); 1326 TIMELIB_INIT; 1327 TIMELIB_HAVE_DATE(); 1328 s->time->d = timelib_get_nr((char **) &ptr, 2); 1329 s->time->m = timelib_get_nr((char **) &ptr, 2); 1330 s->time->y = timelib_get_nr((char **) &ptr, 4); 1331 TIMELIB_DEINIT; 1332 return TIMELIB_DATE_FULL_POINTED; 1333 } 1334 1335 pointeddate2 1336 { 1337 int length = 0; 1338 DEBUG_OUTPUT("pointed date YY"); 1339 TIMELIB_INIT; 1340 TIMELIB_HAVE_DATE(); 1341 s->time->d = timelib_get_nr((char **) &ptr, 2); 1342 s->time->m = timelib_get_nr((char **) &ptr, 2); 1343 s->time->y = timelib_get_nr_ex((char **) &ptr, 2, &length); 1344 TIMELIB_PROCESS_YEAR(s->time->y, length); 1345 TIMELIB_DEINIT; 1346 return TIMELIB_DATE_FULL_POINTED; 1347 } 1348 1349 datenoday 1350 { 1351 int length = 0; 1352 DEBUG_OUTPUT("datenoday"); 1353 TIMELIB_INIT; 1354 TIMELIB_HAVE_DATE(); 1355 s->time->m = timelib_get_month((char **) &ptr); 1356 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1357 s->time->d = 1; 1358 TIMELIB_PROCESS_YEAR(s->time->y, length); 1359 TIMELIB_DEINIT; 1360 return TIMELIB_DATE_NO_DAY; 1361 } 1362 1363 datenodayrev 1364 { 1365 int length = 0; 1366 DEBUG_OUTPUT("datenodayrev"); 1367 TIMELIB_INIT; 1368 TIMELIB_HAVE_DATE(); 1369 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1370 s->time->m = timelib_get_month((char **) &ptr); 1371 s->time->d = 1; 1372 TIMELIB_PROCESS_YEAR(s->time->y, length); 1373 TIMELIB_DEINIT; 1374 return TIMELIB_DATE_NO_DAY; 1375 } 1376 1377 datetextual | datenoyear 1378 { 1379 int length = 0; 1380 DEBUG_OUTPUT("datetextual | datenoyear"); 1381 TIMELIB_INIT; 1382 TIMELIB_HAVE_DATE(); 1383 s->time->m = timelib_get_month((char **) &ptr); 1384 s->time->d = timelib_get_nr((char **) &ptr, 2); 1385 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1386 TIMELIB_PROCESS_YEAR(s->time->y, length); 1387 TIMELIB_DEINIT; 1388 return TIMELIB_DATE_TEXT; 1389 } 1390 1391 datenoyearrev 1392 { 1393 DEBUG_OUTPUT("datenoyearrev"); 1394 TIMELIB_INIT; 1395 TIMELIB_HAVE_DATE(); 1396 s->time->d = timelib_get_nr((char **) &ptr, 2); 1397 timelib_skip_day_suffix((char **) &ptr); 1398 s->time->m = timelib_get_month((char **) &ptr); 1399 TIMELIB_DEINIT; 1400 return TIMELIB_DATE_TEXT; 1401 } 1402 1403 datenocolon 1404 { 1405 DEBUG_OUTPUT("datenocolon"); 1406 TIMELIB_INIT; 1407 TIMELIB_HAVE_DATE(); 1408 s->time->y = timelib_get_nr((char **) &ptr, 4); 1409 s->time->m = timelib_get_nr((char **) &ptr, 2); 1410 s->time->d = timelib_get_nr((char **) &ptr, 2); 1411 TIMELIB_DEINIT; 1412 return TIMELIB_DATE_NOCOLON; 1413 } 1414 1415 xmlrpc | xmlrpcnocolon | soap | wddx | exif 1416 { 1417 int tz_not_found; 1418 DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif"); 1419 TIMELIB_INIT; 1420 TIMELIB_HAVE_TIME(); 1421 TIMELIB_HAVE_DATE(); 1422 s->time->y = timelib_get_nr((char **) &ptr, 4); 1423 s->time->m = timelib_get_nr((char **) &ptr, 2); 1424 s->time->d = timelib_get_nr((char **) &ptr, 2); 1425 s->time->h = timelib_get_nr((char **) &ptr, 2); 1426 s->time->i = timelib_get_nr((char **) &ptr, 2); 1427 s->time->s = timelib_get_nr((char **) &ptr, 2); 1428 if (*ptr == '.') { 1429 s->time->f = timelib_get_frac_nr((char **) &ptr, 9); 1430 if (*ptr) { /* timezone is optional */ 1431 s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper); 1432 if (tz_not_found) { 1433 add_error(s, "The timezone could not be found in the database"); 1434 } 1435 } 1436 } 1437 TIMELIB_DEINIT; 1438 return TIMELIB_XMLRPC_SOAP; 1439 } 1440 1441 pgydotd 1442 { 1443 int length = 0; 1444 DEBUG_OUTPUT("pgydotd"); 1445 TIMELIB_INIT; 1446 TIMELIB_HAVE_DATE(); 1447 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1448 s->time->d = timelib_get_nr((char **) &ptr, 3); 1449 s->time->m = 1; 1450 TIMELIB_PROCESS_YEAR(s->time->y, length); 1451 TIMELIB_DEINIT; 1452 return TIMELIB_PG_YEARDAY; 1453 } 1454 1455 isoweekday 1456 { 1457 timelib_sll w, d; 1458 DEBUG_OUTPUT("isoweekday"); 1459 TIMELIB_INIT; 1460 TIMELIB_HAVE_DATE(); 1461 TIMELIB_HAVE_RELATIVE(); 1462 1463 s->time->y = timelib_get_nr((char **) &ptr, 4); 1464 w = timelib_get_nr((char **) &ptr, 2); 1465 d = timelib_get_nr((char **) &ptr, 1); 1466 s->time->m = 1; 1467 s->time->d = 1; 1468 s->time->relative.d = timelib_daynr_from_weeknr(s->time->y, w, d); 1469 1470 TIMELIB_DEINIT; 1471 return TIMELIB_ISO_WEEK; 1472 } 1473 1474 isoweek 1475 { 1476 timelib_sll w, d; 1477 DEBUG_OUTPUT("isoweek"); 1478 TIMELIB_INIT; 1479 TIMELIB_HAVE_DATE(); 1480 TIMELIB_HAVE_RELATIVE(); 1481 1482 s->time->y = timelib_get_nr((char **) &ptr, 4); 1483 w = timelib_get_nr((char **) &ptr, 2); 1484 d = 1; 1485 s->time->m = 1; 1486 s->time->d = 1; 1487 s->time->relative.d = timelib_daynr_from_weeknr(s->time->y, w, d); 1488 1489 TIMELIB_DEINIT; 1490 return TIMELIB_ISO_WEEK; 1491 } 1492 1493 pgtextshort 1494 { 1495 int length = 0; 1496 DEBUG_OUTPUT("pgtextshort"); 1497 TIMELIB_INIT; 1498 TIMELIB_HAVE_DATE(); 1499 s->time->m = timelib_get_month((char **) &ptr); 1500 s->time->d = timelib_get_nr((char **) &ptr, 2); 1501 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1502 TIMELIB_PROCESS_YEAR(s->time->y, length); 1503 TIMELIB_DEINIT; 1504 return TIMELIB_PG_TEXT; 1505 } 1506 1507 pgtextreverse 1508 { 1509 int length = 0; 1510 DEBUG_OUTPUT("pgtextreverse"); 1511 TIMELIB_INIT; 1512 TIMELIB_HAVE_DATE(); 1513 s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length); 1514 s->time->m = timelib_get_month((char **) &ptr); 1515 s->time->d = timelib_get_nr((char **) &ptr, 2); 1516 TIMELIB_PROCESS_YEAR(s->time->y, length); 1517 TIMELIB_DEINIT; 1518 return TIMELIB_PG_TEXT; 1519 } 1520 1521 clf 1522 { 1523 int tz_not_found; 1524 DEBUG_OUTPUT("clf"); 1525 TIMELIB_INIT; 1526 TIMELIB_HAVE_TIME(); 1527 TIMELIB_HAVE_DATE(); 1528 s->time->d = timelib_get_nr((char **) &ptr, 2); 1529 s->time->m = timelib_get_month((char **) &ptr); 1530 s->time->y = timelib_get_nr((char **) &ptr, 4); 1531 s->time->h = timelib_get_nr((char **) &ptr, 2); 1532 s->time->i = timelib_get_nr((char **) &ptr, 2); 1533 s->time->s = timelib_get_nr((char **) &ptr, 2); 1534 s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper); 1535 if (tz_not_found) { 1536 add_error(s, "The timezone could not be found in the database"); 1537 } 1538 TIMELIB_DEINIT; 1539 return TIMELIB_CLF; 1540 } 1541 1542 year4 1543 { 1544 DEBUG_OUTPUT("year4"); 1545 TIMELIB_INIT; 1546 s->time->y = timelib_get_nr((char **) &ptr, 4); 1547 TIMELIB_DEINIT; 1548 return TIMELIB_CLF; 1549 } 1550 1551 ago 1552 { 1553 DEBUG_OUTPUT("ago"); 1554 TIMELIB_INIT; 1555 s->time->relative.y = 0 - s->time->relative.y; 1556 s->time->relative.m = 0 - s->time->relative.m; 1557 s->time->relative.d = 0 - s->time->relative.d; 1558 s->time->relative.h = 0 - s->time->relative.h; 1559 s->time->relative.i = 0 - s->time->relative.i; 1560 s->time->relative.s = 0 - s->time->relative.s; 1561 s->time->relative.weekday = 0 - s->time->relative.weekday; 1562 if (s->time->relative.weekday == 0) { 1563 s->time->relative.weekday = -7; 1564 } 1565 if (s->time->relative.have_special_relative && s->time->relative.special.type == TIMELIB_SPECIAL_WEEKDAY) { 1566 s->time->relative.special.amount = 0 - s->time->relative.special.amount; 1567 } 1568 TIMELIB_DEINIT; 1569 return TIMELIB_AGO; 1570 } 1571 1572 daytext 1573 { 1574 const timelib_relunit* relunit; 1575 DEBUG_OUTPUT("daytext"); 1576 TIMELIB_INIT; 1577 TIMELIB_HAVE_RELATIVE(); 1578 TIMELIB_HAVE_WEEKDAY_RELATIVE(); 1579 TIMELIB_UNHAVE_TIME(); 1580 relunit = timelib_lookup_relunit((char**) &ptr); 1581 s->time->relative.weekday = relunit->multiplier; 1582 if (s->time->relative.weekday_behavior != 2) { 1583 s->time->relative.weekday_behavior = 1; 1584 } 1585 1586 TIMELIB_DEINIT; 1587 return TIMELIB_WEEKDAY; 1588 } 1589 1590 relativetextweek 1591 { 1592 timelib_sll i; 1593 int behavior = 0; 1594 DEBUG_OUTPUT("relativetextweek"); 1595 TIMELIB_INIT; 1596 TIMELIB_HAVE_RELATIVE(); 1597 1598 while(*ptr) { 1599 i = timelib_get_relative_text((char **) &ptr, &behavior); 1600 timelib_eat_spaces((char **) &ptr); 1601 timelib_set_relative((char **) &ptr, i, behavior, s); 1602 s->time->relative.weekday_behavior = 2; 1603 1604 /* to handle the format weekday + last/this/next week */ 1605 if (s->time->relative.have_weekday_relative == 0) { 1606 TIMELIB_HAVE_WEEKDAY_RELATIVE(); 1607 s->time->relative.weekday = 1; 1608 } 1609 } 1610 TIMELIB_DEINIT; 1611 return TIMELIB_RELATIVE; 1612 } 1613 1614 relativetext 1615 { 1616 timelib_sll i; 1617 int behavior = 0; 1618 DEBUG_OUTPUT("relativetext"); 1619 TIMELIB_INIT; 1620 TIMELIB_HAVE_RELATIVE(); 1621 1622 while(*ptr) { 1623 i = timelib_get_relative_text((char **) &ptr, &behavior); 1624 timelib_eat_spaces((char **) &ptr); 1625 timelib_set_relative((char **) &ptr, i, behavior, s); 1626 } 1627 TIMELIB_DEINIT; 1628 return TIMELIB_RELATIVE; 1629 } 1630 1631 monthfull | monthabbr 1632 { 1633 DEBUG_OUTPUT("monthtext"); 1634 TIMELIB_INIT; 1635 TIMELIB_HAVE_DATE(); 1636 s->time->m = timelib_lookup_month((char **) &ptr); 1637 TIMELIB_DEINIT; 1638 return TIMELIB_DATE_TEXT; 1639 } 1640 1641 tzcorrection | tz 1642 { 1643 int tz_not_found; 1644 DEBUG_OUTPUT("tzcorrection | tz"); 1645 TIMELIB_INIT; 1646 TIMELIB_HAVE_TZ(); 1647 s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper); 1648 if (tz_not_found) { 1649 add_error(s, "The timezone could not be found in the database"); 1650 } 1651 TIMELIB_DEINIT; 1652 return TIMELIB_TIMEZONE; 1653 } 1654 1655 dateshortwithtimeshort12 | dateshortwithtimelong12 1656 { 1657 DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12"); 1658 TIMELIB_INIT; 1659 TIMELIB_HAVE_DATE(); 1660 s->time->m = timelib_get_month((char **) &ptr); 1661 s->time->d = timelib_get_nr((char **) &ptr, 2); 1662 1663 TIMELIB_HAVE_TIME(); 1664 s->time->h = timelib_get_nr((char **) &ptr, 2); 1665 s->time->i = timelib_get_nr((char **) &ptr, 2); 1666 if (*ptr == ':' || *ptr == '.') { 1667 s->time->s = timelib_get_nr((char **) &ptr, 2); 1668 1669 if (*ptr == '.') { 1670 s->time->f = timelib_get_frac_nr((char **) &ptr, 8); 1671 } 1672 } 1673 1674 s->time->h += timelib_meridian((char **) &ptr, s->time->h); 1675 TIMELIB_DEINIT; 1676 return TIMELIB_SHORTDATE_WITH_TIME; 1677 } 1678 1679 dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz 1680 { 1681 int tz_not_found; 1682 DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz"); 1683 TIMELIB_INIT; 1684 TIMELIB_HAVE_DATE(); 1685 s->time->m = timelib_get_month((char **) &ptr); 1686 s->time->d = timelib_get_nr((char **) &ptr, 2); 1687 1688 TIMELIB_HAVE_TIME(); 1689 s->time->h = timelib_get_nr((char **) &ptr, 2); 1690 s->time->i = timelib_get_nr((char **) &ptr, 2); 1691 if (*ptr == ':') { 1692 s->time->s = timelib_get_nr((char **) &ptr, 2); 1693 1694 if (*ptr == '.') { 1695 s->time->f = timelib_get_frac_nr((char **) &ptr, 8); 1696 } 1697 } 1698 1699 if (*ptr != '\0') { 1700 s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper); 1701 if (tz_not_found) { 1702 add_error(s, "The timezone could not be found in the database"); 1703 } 1704 } 1705 TIMELIB_DEINIT; 1706 return TIMELIB_SHORTDATE_WITH_TIME; 1707 } 1708 1709 relative 1710 { 1711 timelib_ull i; 1712 DEBUG_OUTPUT("relative"); 1713 TIMELIB_INIT; 1714 TIMELIB_HAVE_RELATIVE(); 1715 1716 while(*ptr) { 1717 i = timelib_get_unsigned_nr((char **) &ptr, 24); 1718 timelib_eat_spaces((char **) &ptr); 1719 timelib_set_relative((char **) &ptr, i, 1, s); 1720 } 1721 TIMELIB_DEINIT; 1722 return TIMELIB_RELATIVE; 1723 } 1724 1725 [ .,\t] 1726 { 1727 goto std; 1728 } 1729 1730 "\000"|"\n" 1731 { 1732 s->pos = cursor; s->line++; 1733 goto std; 1734 } 1735 1736 any 1737 { 1738 add_error(s, "Unexpected character"); 1739 goto std; 1740 } 1741*/ 1742} 1743 1744/*!max:re2c */ 1745 1746timelib_time* timelib_strtotime(char *s, int len, struct timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper) 1747{ 1748 Scanner in; 1749 int t; 1750 char *e = s + len - 1; 1751 1752 memset(&in, 0, sizeof(in)); 1753 in.errors = malloc(sizeof(struct timelib_error_container)); 1754 in.errors->warning_count = 0; 1755 in.errors->warning_messages = NULL; 1756 in.errors->error_count = 0; 1757 in.errors->error_messages = NULL; 1758 1759 if (len > 0) { 1760 while (isspace(*s) && s < e) { 1761 s++; 1762 } 1763 while (isspace(*e) && e > s) { 1764 e--; 1765 } 1766 } 1767 if (e - s < 0) { 1768 in.time = timelib_time_ctor(); 1769 add_error(&in, "Empty string"); 1770 if (errors) { 1771 *errors = in.errors; 1772 } else { 1773 timelib_error_container_dtor(in.errors); 1774 } 1775 in.time->y = in.time->d = in.time->m = in.time->h = in.time->i = in.time->s = in.time->f = in.time->dst = in.time->z = TIMELIB_UNSET; 1776 in.time->is_localtime = in.time->zone_type = 0; 1777 return in.time; 1778 } 1779 e++; 1780 1781 in.str = malloc((e - s) + YYMAXFILL); 1782 memset(in.str, 0, (e - s) + YYMAXFILL); 1783 memcpy(in.str, s, (e - s)); 1784 in.lim = in.str + (e - s) + YYMAXFILL; 1785 in.cur = in.str; 1786 in.time = timelib_time_ctor(); 1787 in.time->y = TIMELIB_UNSET; 1788 in.time->d = TIMELIB_UNSET; 1789 in.time->m = TIMELIB_UNSET; 1790 in.time->h = TIMELIB_UNSET; 1791 in.time->i = TIMELIB_UNSET; 1792 in.time->s = TIMELIB_UNSET; 1793 in.time->f = TIMELIB_UNSET; 1794 in.time->z = TIMELIB_UNSET; 1795 in.time->dst = TIMELIB_UNSET; 1796 in.tzdb = tzdb; 1797 in.time->is_localtime = 0; 1798 in.time->zone_type = 0; 1799 in.time->relative.days = TIMELIB_UNSET; 1800 1801 do { 1802 t = scan(&in, tz_get_wrapper); 1803#ifdef DEBUG_PARSER 1804 printf("%d\n", t); 1805#endif 1806 } while(t != EOI); 1807 1808 /* do funky checking whether the parsed time was valid time */ 1809 if (in.time->have_time && !timelib_valid_time( in.time->h, in.time->i, in.time->s)) { 1810 add_warning(&in, "The parsed time was invalid"); 1811 } 1812 /* do funky checking whether the parsed date was valid date */ 1813 if (in.time->have_date && !timelib_valid_date( in.time->y, in.time->m, in.time->d)) { 1814 add_warning(&in, "The parsed date was invalid"); 1815 } 1816 1817 free(in.str); 1818 if (errors) { 1819 *errors = in.errors; 1820 } else { 1821 timelib_error_container_dtor(in.errors); 1822 } 1823 return in.time; 1824} 1825 1826#define TIMELIB_CHECK_NUMBER \ 1827 if (strchr("0123456789", *ptr) == NULL) \ 1828 { \ 1829 add_pbf_error(s, "Unexpected data found.", string, begin); \ 1830 } 1831 1832static void timelib_time_reset_fields(timelib_time *time) 1833{ 1834 assert(time != NULL); 1835 1836 time->y = 1970; 1837 time->m = 1; 1838 time->d = 1; 1839 time->h = time->i = time->s = 0; 1840 time->f = 0.0; 1841 time->tz_info = NULL; 1842} 1843 1844static void timelib_time_reset_unset_fields(timelib_time *time) 1845{ 1846 assert(time != NULL); 1847 1848 if (time->y == TIMELIB_UNSET ) time->y = 1970; 1849 if (time->m == TIMELIB_UNSET ) time->m = 1; 1850 if (time->d == TIMELIB_UNSET ) time->d = 1; 1851 if (time->h == TIMELIB_UNSET ) time->h = 0; 1852 if (time->i == TIMELIB_UNSET ) time->i = 0; 1853 if (time->s == TIMELIB_UNSET ) time->s = 0; 1854 if (time->f == TIMELIB_UNSET ) time->f = 0.0; 1855} 1856 1857timelib_time *timelib_parse_from_format(char *format, char *string, int len, timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper) 1858{ 1859 char *fptr = format; 1860 char *ptr = string; 1861 char *begin; 1862 timelib_sll tmp; 1863 Scanner in; 1864 Scanner *s = ∈ 1865 int allow_extra = 0; 1866 1867 memset(&in, 0, sizeof(in)); 1868 in.errors = malloc(sizeof(struct timelib_error_container)); 1869 in.errors->warning_count = 0; 1870 in.errors->warning_messages = NULL; 1871 in.errors->error_count = 0; 1872 in.errors->error_messages = NULL; 1873 1874 in.time = timelib_time_ctor(); 1875 in.time->y = TIMELIB_UNSET; 1876 in.time->d = TIMELIB_UNSET; 1877 in.time->m = TIMELIB_UNSET; 1878 in.time->h = TIMELIB_UNSET; 1879 in.time->i = TIMELIB_UNSET; 1880 in.time->s = TIMELIB_UNSET; 1881 in.time->f = TIMELIB_UNSET; 1882 in.time->z = TIMELIB_UNSET; 1883 in.time->dst = TIMELIB_UNSET; 1884 in.tzdb = tzdb; 1885 in.time->is_localtime = 0; 1886 in.time->zone_type = 0; 1887 1888 /* Loop over the format string */ 1889 while (*fptr && *ptr) { 1890 begin = ptr; 1891 switch (*fptr) { 1892 case 'D': /* three letter day */ 1893 case 'l': /* full day */ 1894 { 1895 const timelib_relunit* tmprel = 0; 1896 1897 tmprel = timelib_lookup_relunit((char **) &ptr); 1898 if (!tmprel) { 1899 add_pbf_error(s, "A textual day could not be found", string, begin); 1900 break; 1901 } else { 1902 in.time->have_relative = 1; 1903 in.time->relative.have_weekday_relative = 1; 1904 in.time->relative.weekday = tmprel->multiplier; 1905 in.time->relative.weekday_behavior = 1; 1906 } 1907 } 1908 break; 1909 case 'd': /* two digit day, with leading zero */ 1910 case 'j': /* two digit day, without leading zero */ 1911 TIMELIB_CHECK_NUMBER; 1912 if ((s->time->d = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { 1913 add_pbf_error(s, "A two digit day could not be found", string, begin); 1914 } 1915 break; 1916 case 'S': /* day suffix, ignored, nor checked */ 1917 timelib_skip_day_suffix((char **) &ptr); 1918 break; 1919 case 'z': /* day of year - resets month (0 based) - also initializes everything else to !TIMELIB_UNSET */ 1920 TIMELIB_CHECK_NUMBER; 1921 if ((tmp = timelib_get_nr((char **) &ptr, 3)) == TIMELIB_UNSET) { 1922 add_pbf_error(s, "A three digit day-of-year could not be found", string, begin); 1923 } else { 1924 s->time->m = 1; 1925 s->time->d = tmp + 1; 1926 timelib_do_normalize(s->time); 1927 } 1928 break; 1929 1930 case 'm': /* two digit month, with leading zero */ 1931 case 'n': /* two digit month, without leading zero */ 1932 TIMELIB_CHECK_NUMBER; 1933 if ((s->time->m = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { 1934 add_pbf_error(s, "A two digit month could not be found", string, begin); 1935 } 1936 break; 1937 case 'M': /* three letter month */ 1938 case 'F': /* full month */ 1939 tmp = timelib_lookup_month((char **) &ptr); 1940 if (!tmp) { 1941 add_pbf_error(s, "A textual month could not be found", string, begin); 1942 } else { 1943 s->time->m = tmp; 1944 } 1945 break; 1946 case 'y': /* two digit year */ 1947 { 1948 int length = 0; 1949 TIMELIB_CHECK_NUMBER; 1950 if ((s->time->y = timelib_get_nr_ex((char **) &ptr, 2, &length)) == TIMELIB_UNSET) { 1951 add_pbf_error(s, "A two digit year could not be found", string, begin); 1952 } 1953 TIMELIB_PROCESS_YEAR(s->time->y, length); 1954 } 1955 break; 1956 case 'Y': /* four digit year */ 1957 TIMELIB_CHECK_NUMBER; 1958 if ((s->time->y = timelib_get_nr((char **) &ptr, 4)) == TIMELIB_UNSET) { 1959 add_pbf_error(s, "A four digit year could not be found", string, begin); 1960 } 1961 break; 1962 case 'g': /* two digit hour, with leading zero */ 1963 case 'h': /* two digit hour, without leading zero */ 1964 TIMELIB_CHECK_NUMBER; 1965 if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { 1966 add_pbf_error(s, "A two digit hour could not be found", string, begin); 1967 } 1968 if (s->time->h > 12) { 1969 add_pbf_error(s, "Hour can not be higher than 12", string, begin); 1970 } 1971 break; 1972 case 'G': /* two digit hour, with leading zero */ 1973 case 'H': /* two digit hour, without leading zero */ 1974 TIMELIB_CHECK_NUMBER; 1975 if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { 1976 add_pbf_error(s, "A two digit hour could not be found", string, begin); 1977 } 1978 break; 1979 case 'a': /* am/pm/a.m./p.m. */ 1980 case 'A': /* AM/PM/A.M./P.M. */ 1981 if (s->time->h == TIMELIB_UNSET) { 1982 add_pbf_error(s, "Meridian can only come after an hour has been found", string, begin); 1983 } else if ((tmp = timelib_meridian_with_check((char **) &ptr, s->time->h)) == TIMELIB_UNSET) { 1984 add_pbf_error(s, "A meridian could not be found", string, begin); 1985 } else { 1986 s->time->h += tmp; 1987 } 1988 break; 1989 case 'i': /* two digit minute, with leading zero */ 1990 { 1991 int length; 1992 timelib_sll min; 1993 1994 TIMELIB_CHECK_NUMBER; 1995 min = timelib_get_nr_ex((char **) &ptr, 2, &length); 1996 if (min == TIMELIB_UNSET || length != 2) { 1997 add_pbf_error(s, "A two digit minute could not be found", string, begin); 1998 } else { 1999 s->time->i = min; 2000 } 2001 } 2002 break; 2003 case 's': /* two digit second, with leading zero */ 2004 { 2005 int length; 2006 timelib_sll sec; 2007 2008 TIMELIB_CHECK_NUMBER; 2009 sec = timelib_get_nr_ex((char **) &ptr, 2, &length); 2010 if (sec == TIMELIB_UNSET || length != 2) { 2011 add_pbf_error(s, "A two second minute could not be found", string, begin); 2012 } else { 2013 s->time->s = sec; 2014 } 2015 } 2016 break; 2017 case 'u': /* up to six digit millisecond */ 2018 { 2019 double f; 2020 char *tptr; 2021 2022 TIMELIB_CHECK_NUMBER; 2023 tptr = ptr; 2024 if ((f = timelib_get_nr((char **) &ptr, 6)) == TIMELIB_UNSET || (ptr - tptr < 1)) { 2025 add_pbf_error(s, "A six digit millisecond could not be found", string, begin); 2026 } else { 2027 s->time->f = (f / pow(10, (ptr - tptr))); 2028 } 2029 } 2030 break; 2031 case ' ': /* any sort of whitespace (' ' and \t) */ 2032 timelib_eat_spaces((char **) &ptr); 2033 break; 2034 case 'U': /* epoch seconds */ 2035 TIMELIB_CHECK_NUMBER; 2036 TIMELIB_HAVE_RELATIVE(); 2037 tmp = timelib_get_unsigned_nr((char **) &ptr, 24); 2038 s->time->y = 1970; 2039 s->time->m = 1; 2040 s->time->d = 1; 2041 s->time->h = s->time->i = s->time->s = 0; 2042 s->time->f = 0.0; 2043 s->time->relative.s += tmp; 2044 s->time->is_localtime = 1; 2045 s->time->zone_type = TIMELIB_ZONETYPE_OFFSET; 2046 s->time->z = 0; 2047 s->time->dst = 0; 2048 break; 2049 2050 case 'e': /* timezone */ 2051 case 'P': /* timezone */ 2052 case 'T': /* timezone */ 2053 case 'O': /* timezone */ 2054 { 2055 int tz_not_found; 2056 s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper); 2057 if (tz_not_found) { 2058 add_pbf_error(s, "The timezone could not be found in the database", string, begin); 2059 } 2060 } 2061 break; 2062 2063 case '#': /* separation symbol */ 2064 if (*ptr == ';' || *ptr == ':' || *ptr == '/' || *ptr == '.' || *ptr == ',' || *ptr == '-' || *ptr == '(' || *ptr == ')') { 2065 ++ptr; 2066 } else { 2067 add_pbf_error(s, "The separation symbol ([;:/.,-]) could not be found", string, begin); 2068 } 2069 break; 2070 2071 case ';': 2072 case ':': 2073 case '/': 2074 case '.': 2075 case ',': 2076 case '-': 2077 case '(': 2078 case ')': 2079 if (*ptr == *fptr) { 2080 ++ptr; 2081 } else { 2082 add_pbf_error(s, "The separation symbol could not be found", string, begin); 2083 } 2084 break; 2085 2086 case '!': /* reset all fields to default */ 2087 timelib_time_reset_fields(s->time); 2088 break; /* break intentionally not missing */ 2089 2090 case '|': /* reset all fields to default when not set */ 2091 timelib_time_reset_unset_fields(s->time); 2092 break; /* break intentionally not missing */ 2093 2094 case '?': /* random char */ 2095 ++ptr; 2096 break; 2097 2098 case '\\': /* escaped char */ 2099 ++fptr; 2100 if (*ptr == *fptr) { 2101 ++ptr; 2102 } else { 2103 add_pbf_error(s, "The escaped character could not be found", string, begin); 2104 } 2105 break; 2106 2107 case '*': /* random chars until a separator or number ([ \t.,:;/-0123456789]) */ 2108 timelib_eat_until_separator((char **) &ptr); 2109 break; 2110 2111 case '+': /* allow extra chars in the format */ 2112 allow_extra = 1; 2113 break; 2114 2115 default: 2116 if (*fptr != *ptr) { 2117 add_pbf_error(s, "The format separator does not match", string, begin); 2118 } 2119 ptr++; 2120 } 2121 fptr++; 2122 } 2123 if (*ptr) { 2124 if (allow_extra) { 2125 add_pbf_warning(s, "Trailing data", string, ptr); 2126 } else { 2127 add_pbf_error(s, "Trailing data", string, ptr); 2128 } 2129 } 2130 /* ignore trailing +'s */ 2131 while (*fptr == '+') { 2132 fptr++; 2133 } 2134 if (*fptr) { 2135 /* Trailing | and ! specifiers are valid. */ 2136 int done = 0; 2137 while (*fptr && !done) { 2138 switch (*fptr++) { 2139 case '!': /* reset all fields to default */ 2140 timelib_time_reset_fields(s->time); 2141 break; 2142 2143 case '|': /* reset all fields to default when not set */ 2144 timelib_time_reset_unset_fields(s->time); 2145 break; 2146 2147 default: 2148 add_pbf_error(s, "Data missing", string, ptr); 2149 done = 1; 2150 } 2151 } 2152 } 2153 2154 /* clean up a bit */ 2155 if (s->time->h != TIMELIB_UNSET || s->time->i != TIMELIB_UNSET || s->time->s != TIMELIB_UNSET) { 2156 if (s->time->h == TIMELIB_UNSET ) { 2157 s->time->h = 0; 2158 } 2159 if (s->time->i == TIMELIB_UNSET ) { 2160 s->time->i = 0; 2161 } 2162 if (s->time->s == TIMELIB_UNSET ) { 2163 s->time->s = 0; 2164 } 2165 } 2166 2167 /* do funky checking whether the parsed time was valid time */ 2168 if (s->time->h != TIMELIB_UNSET && s->time->i != TIMELIB_UNSET && 2169 s->time->s != TIMELIB_UNSET && 2170 !timelib_valid_time( s->time->h, s->time->i, s->time->s)) { 2171 add_pbf_warning(s, "The parsed time was invalid", string, ptr); 2172 } 2173 /* do funky checking whether the parsed date was valid date */ 2174 if (s->time->y != TIMELIB_UNSET && s->time->m != TIMELIB_UNSET && 2175 s->time->d != TIMELIB_UNSET && 2176 !timelib_valid_date( s->time->y, s->time->m, s->time->d)) { 2177 add_pbf_warning(s, "The parsed date was invalid", string, ptr); 2178 } 2179 2180 if (errors) { 2181 *errors = in.errors; 2182 } else { 2183 timelib_error_container_dtor(in.errors); 2184 } 2185 return in.time; 2186} 2187 2188void timelib_fill_holes(timelib_time *parsed, timelib_time *now, int options) 2189{ 2190 if (!(options & TIMELIB_OVERRIDE_TIME) && parsed->have_date && !parsed->have_time) { 2191 parsed->h = 0; 2192 parsed->i = 0; 2193 parsed->s = 0; 2194 parsed->f = 0; 2195 } 2196 if (parsed->y == TIMELIB_UNSET) parsed->y = now->y != TIMELIB_UNSET ? now->y : 0; 2197 if (parsed->d == TIMELIB_UNSET) parsed->d = now->d != TIMELIB_UNSET ? now->d : 0; 2198 if (parsed->m == TIMELIB_UNSET) parsed->m = now->m != TIMELIB_UNSET ? now->m : 0; 2199 if (parsed->h == TIMELIB_UNSET) parsed->h = now->h != TIMELIB_UNSET ? now->h : 0; 2200 if (parsed->i == TIMELIB_UNSET) parsed->i = now->i != TIMELIB_UNSET ? now->i : 0; 2201 if (parsed->s == TIMELIB_UNSET) parsed->s = now->s != TIMELIB_UNSET ? now->s : 0; 2202 if (parsed->f == TIMELIB_UNSET) parsed->f = now->f != TIMELIB_UNSET ? now->f : 0; 2203 if (parsed->z == TIMELIB_UNSET) parsed->z = now->z != TIMELIB_UNSET ? now->z : 0; 2204 if (parsed->dst == TIMELIB_UNSET) parsed->dst = now->dst != TIMELIB_UNSET ? now->dst : 0; 2205 2206 if (!parsed->tz_abbr) { 2207 parsed->tz_abbr = now->tz_abbr ? strdup(now->tz_abbr) : NULL; 2208 } 2209 if (!parsed->tz_info) { 2210 parsed->tz_info = now->tz_info ? (!(options & TIMELIB_NO_CLONE) ? timelib_tzinfo_clone(now->tz_info) : now->tz_info) : NULL; 2211 } 2212 if (parsed->zone_type == 0 && now->zone_type != 0) { 2213 parsed->zone_type = now->zone_type; 2214/* parsed->tz_abbr = now->tz_abbr ? strdup(now->tz_abbr) : NULL; 2215 parsed->tz_info = now->tz_info ? timelib_tzinfo_clone(now->tz_info) : NULL; 2216*/ parsed->is_localtime = 1; 2217 } 2218/* timelib_dump_date(parsed, 2); 2219 timelib_dump_date(now, 2); 2220*/ 2221} 2222 2223char *timelib_timezone_id_from_abbr(const char *abbr, long gmtoffset, int isdst) 2224{ 2225 const timelib_tz_lookup_table *tp; 2226 2227 tp = zone_search(abbr, gmtoffset, isdst); 2228 if (tp) { 2229 return (tp->full_tz_name); 2230 } else { 2231 return NULL; 2232 } 2233} 2234 2235const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void) 2236{ 2237 return timelib_timezone_lookup; 2238} 2239 2240#ifdef DEBUG_PARSER_STUB 2241int main(void) 2242{ 2243 timelib_time time = timelib_strtotime("May 12"); 2244 2245 printf ("%04d-%02d-%02d %02d:%02d:%02d.%-5d %+04d %1d", 2246 time.y, time.m, time.d, time.h, time.i, time.s, time.f, time.z, time.dst); 2247 if (time.have_relative) { 2248 printf ("%3dY %3dM %3dD / %3dH %3dM %3dS", 2249 time.relative.y, time.relative.m, time.relative.d, time.relative.h, time.relative.i, time.relative.s); 2250 } 2251 if (time.have_weekday_relative) { 2252 printf (" / %d", time.relative.weekday); 2253 } 2254 if (time.have_weeknr_day) { 2255 printf(" / %dW%d", time.relative.weeknr_day.weeknr, time.relative.weeknr_day.dayofweek); 2256 } 2257 return 0; 2258} 2259#endif 2260 2261/* 2262 * vim: syntax=c 2263 */ 2264