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