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