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