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