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