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