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