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