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