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