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