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