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