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