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