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