Annotation of embedaddon/php/ext/date/lib/parse_date.re, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2010 The PHP Group |
6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Derick Rethans <derick@derickrethans.nl> |
16: +----------------------------------------------------------------------+
17: */
18:
19: /* $Id: parse_date.re 320481 2011-12-06 06:21:08Z derick $ */
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;
1076:
1077: TIMELIB_DEINIT;
1078: return TIMELIB_RELATIVE;
1079: }
1080:
1081: firstdayof | lastdayof
1082: {
1083: DEBUG_OUTPUT("firstdayof | lastdayof");
1084: TIMELIB_INIT;
1085: TIMELIB_HAVE_RELATIVE();
1086:
1087: /* skip "last day of" or "first day of" */
1088: if (*ptr == 'l') {
1089: s->time->relative.first_last_day_of = 2;
1090: } else {
1091: s->time->relative.first_last_day_of = 1;
1092: }
1093:
1094: TIMELIB_DEINIT;
1095: return TIMELIB_LF_DAY_OF_MONTH;
1096: }
1097:
1098: backof | frontof
1099: {
1100: DEBUG_OUTPUT("backof | frontof");
1101: TIMELIB_INIT;
1102: TIMELIB_UNHAVE_TIME();
1103: TIMELIB_HAVE_TIME();
1104:
1105: if (*ptr == 'b') {
1106: s->time->h = timelib_get_nr((char **) &ptr, 2);
1107: s->time->i = 15;
1108: } else {
1109: s->time->h = timelib_get_nr((char **) &ptr, 2) - 1;
1110: s->time->i = 45;
1111: }
1112: if (*ptr != '\0' ) {
1113: timelib_eat_spaces((char **) &ptr);
1114: s->time->h += timelib_meridian((char **) &ptr, s->time->h);
1115: }
1116:
1117: TIMELIB_DEINIT;
1118: return TIMELIB_LF_DAY_OF_MONTH;
1119: }
1120:
1121: weekdayof
1122: {
1123: timelib_sll i;
1124: int behavior = 0;
1125: DEBUG_OUTPUT("weekdayof");
1126: TIMELIB_INIT;
1127: TIMELIB_HAVE_RELATIVE();
1128: TIMELIB_HAVE_SPECIAL_RELATIVE();
1129:
1130: i = timelib_get_relative_text((char **) &ptr, &behavior);
1131: timelib_eat_spaces((char **) &ptr);
1132: if (i > 0) { /* first, second... etc */
1133: s->time->relative.special.type = TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH;
1134: timelib_set_relative((char **) &ptr, i, 1, s);
1135: } else { /* last */
1136: s->time->relative.special.type = TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH;
1137: timelib_set_relative((char **) &ptr, i, behavior, s);
1138: }
1139: TIMELIB_DEINIT;
1140: return TIMELIB_WEEK_DAY_OF_MONTH;
1141: }
1142:
1143: timetiny12 | timeshort12 | timelong12
1144: {
1145: DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12");
1146: TIMELIB_INIT;
1147: TIMELIB_HAVE_TIME();
1148: s->time->h = timelib_get_nr((char **) &ptr, 2);
1149: if (*ptr == ':' || *ptr == '.') {
1150: s->time->i = timelib_get_nr((char **) &ptr, 2);
1151: if (*ptr == ':' || *ptr == '.') {
1152: s->time->s = timelib_get_nr((char **) &ptr, 2);
1153: }
1154: }
1155: s->time->h += timelib_meridian((char **) &ptr, s->time->h);
1156: TIMELIB_DEINIT;
1157: return TIMELIB_TIME12;
1158: }
1159:
1160: mssqltime
1161: {
1162: DEBUG_OUTPUT("mssqltime");
1163: TIMELIB_INIT;
1164: TIMELIB_HAVE_TIME();
1165: s->time->h = timelib_get_nr((char **) &ptr, 2);
1166: s->time->i = timelib_get_nr((char **) &ptr, 2);
1167: if (*ptr == ':' || *ptr == '.') {
1168: s->time->s = timelib_get_nr((char **) &ptr, 2);
1169:
1170: if (*ptr == ':' || *ptr == '.') {
1171: s->time->f = timelib_get_frac_nr((char **) &ptr, 8);
1172: }
1173: }
1174: timelib_eat_spaces((char **) &ptr);
1175: s->time->h += timelib_meridian((char **) &ptr, s->time->h);
1176: TIMELIB_DEINIT;
1177: return TIMELIB_TIME24_WITH_ZONE;
1178: }
1179:
1180: timeshort24 | timelong24 /* | iso8601short | iso8601norm */ | iso8601long /*| iso8601shorttz | iso8601normtz | iso8601longtz*/
1181: {
1182: int tz_not_found;
1183: DEBUG_OUTPUT("timeshort24 | timelong24 | iso8601long");
1184: TIMELIB_INIT;
1185: TIMELIB_HAVE_TIME();
1186: s->time->h = timelib_get_nr((char **) &ptr, 2);
1187: s->time->i = timelib_get_nr((char **) &ptr, 2);
1188: if (*ptr == ':' || *ptr == '.') {
1189: s->time->s = timelib_get_nr((char **) &ptr, 2);
1190:
1191: if (*ptr == '.') {
1192: s->time->f = timelib_get_frac_nr((char **) &ptr, 8);
1193: }
1194: }
1195:
1196: if (*ptr != '\0') {
1197: s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
1198: if (tz_not_found) {
1199: add_error(s, "The timezone could not be found in the database");
1200: }
1201: }
1202: TIMELIB_DEINIT;
1203: return TIMELIB_TIME24_WITH_ZONE;
1204: }
1205:
1206: gnunocolon
1207: {
1208: DEBUG_OUTPUT("gnunocolon");
1209: TIMELIB_INIT;
1210: switch (s->time->have_time) {
1211: case 0:
1212: s->time->h = timelib_get_nr((char **) &ptr, 2);
1213: s->time->i = timelib_get_nr((char **) &ptr, 2);
1214: s->time->s = 0;
1215: break;
1216: case 1:
1217: s->time->y = timelib_get_nr((char **) &ptr, 4);
1218: break;
1219: default:
1220: TIMELIB_DEINIT;
1221: add_error(s, "Double time specification");
1222: return TIMELIB_ERROR;
1223: }
1224: s->time->have_time++;
1225: TIMELIB_DEINIT;
1226: return TIMELIB_GNU_NOCOLON;
1227: }
1228: /*
1229: gnunocolontz
1230: {
1231: DEBUG_OUTPUT("gnunocolontz");
1232: TIMELIB_INIT;
1233: switch (s->time->have_time) {
1234: case 0:
1235: s->time->h = timelib_get_nr((char **) &ptr, 2);
1236: s->time->i = timelib_get_nr((char **) &ptr, 2);
1237: s->time->s = 0;
1238: s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, s->tzdb, tz_get_wrapper);
1239: break;
1240: case 1:
1241: s->time->y = timelib_get_nr((char **) &ptr, 4);
1242: break;
1243: default:
1244: TIMELIB_DEINIT;
1245: return TIMELIB_ERROR;
1246: }
1247: s->time->have_time++;
1248: TIMELIB_DEINIT;
1249: return TIMELIB_GNU_NOCOLON_TZ;
1250: }
1251: */
1252: iso8601nocolon /*| iso8601nocolontz*/
1253: {
1254: int tz_not_found;
1255: DEBUG_OUTPUT("iso8601nocolon");
1256: TIMELIB_INIT;
1257: TIMELIB_HAVE_TIME();
1258: s->time->h = timelib_get_nr((char **) &ptr, 2);
1259: s->time->i = timelib_get_nr((char **) &ptr, 2);
1260: s->time->s = timelib_get_nr((char **) &ptr, 2);
1261:
1262: if (*ptr != '\0') {
1263: s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
1264: if (tz_not_found) {
1265: add_error(s, "The timezone could not be found in the database");
1266: }
1267: }
1268: TIMELIB_DEINIT;
1269: return TIMELIB_ISO_NOCOLON;
1270: }
1271:
1272: americanshort | american
1273: {
1274: int length = 0;
1275: DEBUG_OUTPUT("americanshort | american");
1276: TIMELIB_INIT;
1277: TIMELIB_HAVE_DATE();
1278: s->time->m = timelib_get_nr((char **) &ptr, 2);
1279: s->time->d = timelib_get_nr((char **) &ptr, 2);
1280: if (*ptr == '/') {
1281: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1282: TIMELIB_PROCESS_YEAR(s->time->y, length);
1283: }
1284: TIMELIB_DEINIT;
1285: return TIMELIB_AMERICAN;
1286: }
1287:
1288: iso8601date4 | iso8601dateslash | dateslash
1289: {
1290: DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash");
1291: TIMELIB_INIT;
1292: TIMELIB_HAVE_DATE();
1293: s->time->y = timelib_get_unsigned_nr((char **) &ptr, 4);
1294: s->time->m = timelib_get_nr((char **) &ptr, 2);
1295: s->time->d = timelib_get_nr((char **) &ptr, 2);
1296: TIMELIB_DEINIT;
1297: return TIMELIB_ISO_DATE;
1298: }
1299:
1300: iso8601date2
1301: {
1302: int length = 0;
1303: DEBUG_OUTPUT("iso8601date2");
1304: TIMELIB_INIT;
1305: TIMELIB_HAVE_DATE();
1306: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1307: s->time->m = timelib_get_nr((char **) &ptr, 2);
1308: s->time->d = timelib_get_nr((char **) &ptr, 2);
1309: TIMELIB_PROCESS_YEAR(s->time->y, length);
1310: TIMELIB_DEINIT;
1311: return TIMELIB_ISO_DATE;
1312: }
1313:
1314: gnudateshorter
1315: {
1316: int length = 0;
1317: DEBUG_OUTPUT("gnudateshorter");
1318: TIMELIB_INIT;
1319: TIMELIB_HAVE_DATE();
1320: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1321: s->time->m = timelib_get_nr((char **) &ptr, 2);
1322: s->time->d = 1;
1323: TIMELIB_PROCESS_YEAR(s->time->y, length);
1324: TIMELIB_DEINIT;
1325: return TIMELIB_ISO_DATE;
1326: }
1327:
1328: gnudateshort
1329: {
1330: int length = 0;
1331: DEBUG_OUTPUT("gnudateshort");
1332: TIMELIB_INIT;
1333: TIMELIB_HAVE_DATE();
1334: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1335: s->time->m = timelib_get_nr((char **) &ptr, 2);
1336: s->time->d = timelib_get_nr((char **) &ptr, 2);
1337: TIMELIB_PROCESS_YEAR(s->time->y, length);
1338: TIMELIB_DEINIT;
1339: return TIMELIB_ISO_DATE;
1340: }
1341:
1342: datefull
1343: {
1344: int length = 0;
1345: DEBUG_OUTPUT("datefull");
1346: TIMELIB_INIT;
1347: TIMELIB_HAVE_DATE();
1348: s->time->d = timelib_get_nr((char **) &ptr, 2);
1349: timelib_skip_day_suffix((char **) &ptr);
1350: s->time->m = timelib_get_month((char **) &ptr);
1351: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1352: TIMELIB_PROCESS_YEAR(s->time->y, length);
1353: TIMELIB_DEINIT;
1354: return TIMELIB_DATE_FULL;
1355: }
1356:
1357: pointeddate4
1358: {
1359: DEBUG_OUTPUT("pointed date YYYY");
1360: TIMELIB_INIT;
1361: TIMELIB_HAVE_DATE();
1362: s->time->d = timelib_get_nr((char **) &ptr, 2);
1363: s->time->m = timelib_get_nr((char **) &ptr, 2);
1364: s->time->y = timelib_get_nr((char **) &ptr, 4);
1365: TIMELIB_DEINIT;
1366: return TIMELIB_DATE_FULL_POINTED;
1367: }
1368:
1369: pointeddate2
1370: {
1371: int length = 0;
1372: DEBUG_OUTPUT("pointed date YY");
1373: TIMELIB_INIT;
1374: TIMELIB_HAVE_DATE();
1375: s->time->d = timelib_get_nr((char **) &ptr, 2);
1376: s->time->m = timelib_get_nr((char **) &ptr, 2);
1377: s->time->y = timelib_get_nr_ex((char **) &ptr, 2, &length);
1378: TIMELIB_PROCESS_YEAR(s->time->y, length);
1379: TIMELIB_DEINIT;
1380: return TIMELIB_DATE_FULL_POINTED;
1381: }
1382:
1383: datenoday
1384: {
1385: int length = 0;
1386: DEBUG_OUTPUT("datenoday");
1387: TIMELIB_INIT;
1388: TIMELIB_HAVE_DATE();
1389: s->time->m = timelib_get_month((char **) &ptr);
1390: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1391: s->time->d = 1;
1392: TIMELIB_PROCESS_YEAR(s->time->y, length);
1393: TIMELIB_DEINIT;
1394: return TIMELIB_DATE_NO_DAY;
1395: }
1396:
1397: datenodayrev
1398: {
1399: int length = 0;
1400: DEBUG_OUTPUT("datenodayrev");
1401: TIMELIB_INIT;
1402: TIMELIB_HAVE_DATE();
1403: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1404: s->time->m = timelib_get_month((char **) &ptr);
1405: s->time->d = 1;
1406: TIMELIB_PROCESS_YEAR(s->time->y, length);
1407: TIMELIB_DEINIT;
1408: return TIMELIB_DATE_NO_DAY;
1409: }
1410:
1411: datetextual | datenoyear
1412: {
1413: int length = 0;
1414: DEBUG_OUTPUT("datetextual | datenoyear");
1415: TIMELIB_INIT;
1416: TIMELIB_HAVE_DATE();
1417: s->time->m = timelib_get_month((char **) &ptr);
1418: s->time->d = timelib_get_nr((char **) &ptr, 2);
1419: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1420: TIMELIB_PROCESS_YEAR(s->time->y, length);
1421: TIMELIB_DEINIT;
1422: return TIMELIB_DATE_TEXT;
1423: }
1424:
1425: datenoyearrev
1426: {
1427: DEBUG_OUTPUT("datenoyearrev");
1428: TIMELIB_INIT;
1429: TIMELIB_HAVE_DATE();
1430: s->time->d = timelib_get_nr((char **) &ptr, 2);
1431: timelib_skip_day_suffix((char **) &ptr);
1432: s->time->m = timelib_get_month((char **) &ptr);
1433: TIMELIB_DEINIT;
1434: return TIMELIB_DATE_TEXT;
1435: }
1436:
1437: datenocolon
1438: {
1439: DEBUG_OUTPUT("datenocolon");
1440: TIMELIB_INIT;
1441: TIMELIB_HAVE_DATE();
1442: s->time->y = timelib_get_nr((char **) &ptr, 4);
1443: s->time->m = timelib_get_nr((char **) &ptr, 2);
1444: s->time->d = timelib_get_nr((char **) &ptr, 2);
1445: TIMELIB_DEINIT;
1446: return TIMELIB_DATE_NOCOLON;
1447: }
1448:
1449: xmlrpc | xmlrpcnocolon | soap | wddx | exif
1450: {
1451: int tz_not_found;
1452: DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif");
1453: TIMELIB_INIT;
1454: TIMELIB_HAVE_TIME();
1455: TIMELIB_HAVE_DATE();
1456: s->time->y = timelib_get_nr((char **) &ptr, 4);
1457: s->time->m = timelib_get_nr((char **) &ptr, 2);
1458: s->time->d = timelib_get_nr((char **) &ptr, 2);
1459: s->time->h = timelib_get_nr((char **) &ptr, 2);
1460: s->time->i = timelib_get_nr((char **) &ptr, 2);
1461: s->time->s = timelib_get_nr((char **) &ptr, 2);
1462: if (*ptr == '.') {
1463: s->time->f = timelib_get_frac_nr((char **) &ptr, 9);
1464: if (*ptr) { /* timezone is optional */
1465: s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
1466: if (tz_not_found) {
1467: add_error(s, "The timezone could not be found in the database");
1468: }
1469: }
1470: }
1471: TIMELIB_DEINIT;
1472: return TIMELIB_XMLRPC_SOAP;
1473: }
1474:
1475: pgydotd
1476: {
1477: int length = 0;
1478: DEBUG_OUTPUT("pgydotd");
1479: TIMELIB_INIT;
1480: TIMELIB_HAVE_DATE();
1481: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1482: s->time->d = timelib_get_nr((char **) &ptr, 3);
1483: s->time->m = 1;
1484: TIMELIB_PROCESS_YEAR(s->time->y, length);
1485: TIMELIB_DEINIT;
1486: return TIMELIB_PG_YEARDAY;
1487: }
1488:
1489: isoweekday
1490: {
1491: timelib_sll w, d;
1492: DEBUG_OUTPUT("isoweekday");
1493: TIMELIB_INIT;
1494: TIMELIB_HAVE_DATE();
1495: TIMELIB_HAVE_RELATIVE();
1496:
1497: s->time->y = timelib_get_nr((char **) &ptr, 4);
1498: w = timelib_get_nr((char **) &ptr, 2);
1499: d = timelib_get_nr((char **) &ptr, 1);
1500: s->time->m = 1;
1501: s->time->d = 1;
1502: s->time->relative.d = timelib_daynr_from_weeknr(s->time->y, w, d);
1503:
1504: TIMELIB_DEINIT;
1505: return TIMELIB_ISO_WEEK;
1506: }
1507:
1508: isoweek
1509: {
1510: timelib_sll w, d;
1511: DEBUG_OUTPUT("isoweek");
1512: TIMELIB_INIT;
1513: TIMELIB_HAVE_DATE();
1514: TIMELIB_HAVE_RELATIVE();
1515:
1516: s->time->y = timelib_get_nr((char **) &ptr, 4);
1517: w = timelib_get_nr((char **) &ptr, 2);
1518: d = 1;
1519: s->time->m = 1;
1520: s->time->d = 1;
1521: s->time->relative.d = timelib_daynr_from_weeknr(s->time->y, w, d);
1522:
1523: TIMELIB_DEINIT;
1524: return TIMELIB_ISO_WEEK;
1525: }
1526:
1527: pgtextshort
1528: {
1529: int length = 0;
1530: DEBUG_OUTPUT("pgtextshort");
1531: TIMELIB_INIT;
1532: TIMELIB_HAVE_DATE();
1533: s->time->m = timelib_get_month((char **) &ptr);
1534: s->time->d = timelib_get_nr((char **) &ptr, 2);
1535: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1536: TIMELIB_PROCESS_YEAR(s->time->y, length);
1537: TIMELIB_DEINIT;
1538: return TIMELIB_PG_TEXT;
1539: }
1540:
1541: pgtextreverse
1542: {
1543: int length = 0;
1544: DEBUG_OUTPUT("pgtextreverse");
1545: TIMELIB_INIT;
1546: TIMELIB_HAVE_DATE();
1547: s->time->y = timelib_get_nr_ex((char **) &ptr, 4, &length);
1548: s->time->m = timelib_get_month((char **) &ptr);
1549: s->time->d = timelib_get_nr((char **) &ptr, 2);
1550: TIMELIB_PROCESS_YEAR(s->time->y, length);
1551: TIMELIB_DEINIT;
1552: return TIMELIB_PG_TEXT;
1553: }
1554:
1555: clf
1556: {
1557: int tz_not_found;
1558: DEBUG_OUTPUT("clf");
1559: TIMELIB_INIT;
1560: TIMELIB_HAVE_TIME();
1561: TIMELIB_HAVE_DATE();
1562: s->time->d = timelib_get_nr((char **) &ptr, 2);
1563: s->time->m = timelib_get_month((char **) &ptr);
1564: s->time->y = timelib_get_nr((char **) &ptr, 4);
1565: s->time->h = timelib_get_nr((char **) &ptr, 2);
1566: s->time->i = timelib_get_nr((char **) &ptr, 2);
1567: s->time->s = timelib_get_nr((char **) &ptr, 2);
1568: s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
1569: if (tz_not_found) {
1570: add_error(s, "The timezone could not be found in the database");
1571: }
1572: TIMELIB_DEINIT;
1573: return TIMELIB_CLF;
1574: }
1575:
1576: year4
1577: {
1578: DEBUG_OUTPUT("year4");
1579: TIMELIB_INIT;
1580: s->time->y = timelib_get_nr((char **) &ptr, 4);
1581: TIMELIB_DEINIT;
1582: return TIMELIB_CLF;
1583: }
1584:
1585: ago
1586: {
1587: DEBUG_OUTPUT("ago");
1588: TIMELIB_INIT;
1589: s->time->relative.y = 0 - s->time->relative.y;
1590: s->time->relative.m = 0 - s->time->relative.m;
1591: s->time->relative.d = 0 - s->time->relative.d;
1592: s->time->relative.h = 0 - s->time->relative.h;
1593: s->time->relative.i = 0 - s->time->relative.i;
1594: s->time->relative.s = 0 - s->time->relative.s;
1595: s->time->relative.weekday = 0 - s->time->relative.weekday;
1596: if (s->time->relative.weekday == 0) {
1597: s->time->relative.weekday = -7;
1598: }
1599: if (s->time->relative.have_special_relative && s->time->relative.special.type == TIMELIB_SPECIAL_WEEKDAY) {
1600: s->time->relative.special.amount = 0 - s->time->relative.special.amount;
1601: }
1602: TIMELIB_DEINIT;
1603: return TIMELIB_AGO;
1604: }
1605:
1606: daytext
1607: {
1608: const timelib_relunit* relunit;
1609: DEBUG_OUTPUT("daytext");
1610: TIMELIB_INIT;
1611: TIMELIB_HAVE_RELATIVE();
1612: TIMELIB_HAVE_WEEKDAY_RELATIVE();
1613: TIMELIB_UNHAVE_TIME();
1614: relunit = timelib_lookup_relunit((char**) &ptr);
1615: s->time->relative.weekday = relunit->multiplier;
1616: if (s->time->relative.weekday_behavior != 2) {
1617: s->time->relative.weekday_behavior = 1;
1618: }
1619:
1620: TIMELIB_DEINIT;
1621: return TIMELIB_WEEKDAY;
1622: }
1623:
1624: relativetextweek
1625: {
1626: timelib_sll i;
1627: int behavior = 0;
1628: DEBUG_OUTPUT("relativetextweek");
1629: TIMELIB_INIT;
1630: TIMELIB_HAVE_RELATIVE();
1631:
1632: while(*ptr) {
1633: i = timelib_get_relative_text((char **) &ptr, &behavior);
1634: timelib_eat_spaces((char **) &ptr);
1635: timelib_set_relative((char **) &ptr, i, behavior, s);
1636: s->time->relative.weekday_behavior = 2;
1637:
1638: /* to handle the format weekday + last/this/next week */
1639: if (s->time->relative.have_weekday_relative == 0) {
1640: TIMELIB_HAVE_WEEKDAY_RELATIVE();
1641: s->time->relative.weekday = 1;
1642: }
1643: }
1644: TIMELIB_DEINIT;
1645: return TIMELIB_RELATIVE;
1646: }
1647:
1648: relativetext
1649: {
1650: timelib_sll i;
1651: int behavior = 0;
1652: DEBUG_OUTPUT("relativetext");
1653: TIMELIB_INIT;
1654: TIMELIB_HAVE_RELATIVE();
1655:
1656: while(*ptr) {
1657: i = timelib_get_relative_text((char **) &ptr, &behavior);
1658: timelib_eat_spaces((char **) &ptr);
1659: timelib_set_relative((char **) &ptr, i, behavior, s);
1660: }
1661: TIMELIB_DEINIT;
1662: return TIMELIB_RELATIVE;
1663: }
1664:
1665: monthfull | monthabbr
1666: {
1667: DEBUG_OUTPUT("monthtext");
1668: TIMELIB_INIT;
1669: TIMELIB_HAVE_DATE();
1670: s->time->m = timelib_lookup_month((char **) &ptr);
1671: TIMELIB_DEINIT;
1672: return TIMELIB_DATE_TEXT;
1673: }
1674:
1675: tzcorrection | tz
1676: {
1677: int tz_not_found;
1678: DEBUG_OUTPUT("tzcorrection | tz");
1679: TIMELIB_INIT;
1680: TIMELIB_HAVE_TZ();
1681: s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
1682: if (tz_not_found) {
1683: add_error(s, "The timezone could not be found in the database");
1684: }
1685: TIMELIB_DEINIT;
1686: return TIMELIB_TIMEZONE;
1687: }
1688:
1689: dateshortwithtimeshort12 | dateshortwithtimelong12
1690: {
1691: DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12");
1692: TIMELIB_INIT;
1693: TIMELIB_HAVE_DATE();
1694: s->time->m = timelib_get_month((char **) &ptr);
1695: s->time->d = timelib_get_nr((char **) &ptr, 2);
1696:
1697: TIMELIB_HAVE_TIME();
1698: s->time->h = timelib_get_nr((char **) &ptr, 2);
1699: s->time->i = timelib_get_nr((char **) &ptr, 2);
1700: if (*ptr == ':' || *ptr == '.') {
1701: s->time->s = timelib_get_nr((char **) &ptr, 2);
1702:
1703: if (*ptr == '.') {
1704: s->time->f = timelib_get_frac_nr((char **) &ptr, 8);
1705: }
1706: }
1707:
1708: s->time->h += timelib_meridian((char **) &ptr, s->time->h);
1709: TIMELIB_DEINIT;
1710: return TIMELIB_SHORTDATE_WITH_TIME;
1711: }
1712:
1713: dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz
1714: {
1715: int tz_not_found;
1716: DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz");
1717: TIMELIB_INIT;
1718: TIMELIB_HAVE_DATE();
1719: s->time->m = timelib_get_month((char **) &ptr);
1720: s->time->d = timelib_get_nr((char **) &ptr, 2);
1721:
1722: TIMELIB_HAVE_TIME();
1723: s->time->h = timelib_get_nr((char **) &ptr, 2);
1724: s->time->i = timelib_get_nr((char **) &ptr, 2);
1725: if (*ptr == ':') {
1726: s->time->s = timelib_get_nr((char **) &ptr, 2);
1727:
1728: if (*ptr == '.') {
1729: s->time->f = timelib_get_frac_nr((char **) &ptr, 8);
1730: }
1731: }
1732:
1733: if (*ptr != '\0') {
1734: s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
1735: if (tz_not_found) {
1736: add_error(s, "The timezone could not be found in the database");
1737: }
1738: }
1739: TIMELIB_DEINIT;
1740: return TIMELIB_SHORTDATE_WITH_TIME;
1741: }
1742:
1743: relative
1744: {
1745: timelib_ull i;
1746: DEBUG_OUTPUT("relative");
1747: TIMELIB_INIT;
1748: TIMELIB_HAVE_RELATIVE();
1749:
1750: while(*ptr) {
1751: i = timelib_get_unsigned_nr((char **) &ptr, 24);
1752: timelib_eat_spaces((char **) &ptr);
1753: timelib_set_relative((char **) &ptr, i, 1, s);
1754: }
1755: TIMELIB_DEINIT;
1756: return TIMELIB_RELATIVE;
1757: }
1758:
1759: [ .,\t]
1760: {
1761: goto std;
1762: }
1763:
1764: "\000"|"\n"
1765: {
1766: s->pos = cursor; s->line++;
1767: goto std;
1768: }
1769:
1770: any
1771: {
1772: add_error(s, "Unexpected character");
1773: goto std;
1774: }
1775: */
1776: }
1777:
1778: /*!max:re2c */
1779:
1780: timelib_time* timelib_strtotime(char *s, int len, struct timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper)
1781: {
1782: Scanner in;
1783: int t;
1784: char *e = s + len - 1;
1785:
1786: memset(&in, 0, sizeof(in));
1787: in.errors = malloc(sizeof(struct timelib_error_container));
1788: in.errors->warning_count = 0;
1789: in.errors->warning_messages = NULL;
1790: in.errors->error_count = 0;
1791: in.errors->error_messages = NULL;
1792:
1793: if (len > 0) {
1794: while (isspace(*s) && s < e) {
1795: s++;
1796: }
1797: while (isspace(*e) && e > s) {
1798: e--;
1799: }
1800: }
1801: if (e - s < 0) {
1802: in.time = timelib_time_ctor();
1803: add_error(&in, "Empty string");
1804: if (errors) {
1805: *errors = in.errors;
1806: } else {
1807: timelib_error_container_dtor(in.errors);
1808: }
1809: 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;
1810: in.time->is_localtime = in.time->zone_type = 0;
1811: return in.time;
1812: }
1813: e++;
1814:
1815: in.str = malloc((e - s) + YYMAXFILL);
1816: memset(in.str, 0, (e - s) + YYMAXFILL);
1817: memcpy(in.str, s, (e - s));
1818: in.lim = in.str + (e - s) + YYMAXFILL;
1819: in.cur = in.str;
1820: in.time = timelib_time_ctor();
1821: in.time->y = TIMELIB_UNSET;
1822: in.time->d = TIMELIB_UNSET;
1823: in.time->m = TIMELIB_UNSET;
1824: in.time->h = TIMELIB_UNSET;
1825: in.time->i = TIMELIB_UNSET;
1826: in.time->s = TIMELIB_UNSET;
1827: in.time->f = TIMELIB_UNSET;
1828: in.time->z = TIMELIB_UNSET;
1829: in.time->dst = TIMELIB_UNSET;
1830: in.tzdb = tzdb;
1831: in.time->is_localtime = 0;
1832: in.time->zone_type = 0;
1833:
1834: do {
1835: t = scan(&in, tz_get_wrapper);
1836: #ifdef DEBUG_PARSER
1837: printf("%d\n", t);
1838: #endif
1839: } while(t != EOI);
1840:
1841: /* do funky checking whether the parsed time was valid time */
1842: if (in.time->have_time && !timelib_valid_time( in.time->h, in.time->i, in.time->s)) {
1843: add_warning(&in, "The parsed time was invalid");
1844: }
1845: /* do funky checking whether the parsed date was valid date */
1846: if (in.time->have_date && !timelib_valid_date( in.time->y, in.time->m, in.time->d)) {
1847: add_warning(&in, "The parsed date was invalid");
1848: }
1849:
1850: free(in.str);
1851: if (errors) {
1852: *errors = in.errors;
1853: } else {
1854: timelib_error_container_dtor(in.errors);
1855: }
1856: return in.time;
1857: }
1858:
1859: #define TIMELIB_CHECK_NUMBER \
1860: if (strchr("0123456789", *ptr) == NULL) \
1861: { \
1862: add_pbf_error(s, "Unexpected data found.", string, begin); \
1863: }
1864:
1865: static void timelib_time_reset_fields(timelib_time *time)
1866: {
1867: assert(time != NULL);
1868:
1869: time->y = 1970;
1870: time->m = 1;
1871: time->d = 1;
1872: time->h = time->i = time->s = 0;
1873: time->f = 0.0;
1874: time->tz_info = NULL;
1875: }
1876:
1877: static void timelib_time_reset_unset_fields(timelib_time *time)
1878: {
1879: assert(time != NULL);
1880:
1881: if (time->y == TIMELIB_UNSET ) time->y = 1970;
1882: if (time->m == TIMELIB_UNSET ) time->m = 1;
1883: if (time->d == TIMELIB_UNSET ) time->d = 1;
1884: if (time->h == TIMELIB_UNSET ) time->h = 0;
1885: if (time->i == TIMELIB_UNSET ) time->i = 0;
1886: if (time->s == TIMELIB_UNSET ) time->s = 0;
1887: if (time->f == TIMELIB_UNSET ) time->f = 0.0;
1888: }
1889:
1890: 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)
1891: {
1892: char *fptr = format;
1893: char *ptr = string;
1894: char *begin;
1895: timelib_sll tmp;
1896: Scanner in;
1897: Scanner *s = ∈
1898: int allow_extra = 0;
1899:
1900: memset(&in, 0, sizeof(in));
1901: in.errors = malloc(sizeof(struct timelib_error_container));
1902: in.errors->warning_count = 0;
1903: in.errors->warning_messages = NULL;
1904: in.errors->error_count = 0;
1905: in.errors->error_messages = NULL;
1906:
1907: in.time = timelib_time_ctor();
1908: in.time->y = TIMELIB_UNSET;
1909: in.time->d = TIMELIB_UNSET;
1910: in.time->m = TIMELIB_UNSET;
1911: in.time->h = TIMELIB_UNSET;
1912: in.time->i = TIMELIB_UNSET;
1913: in.time->s = TIMELIB_UNSET;
1914: in.time->f = TIMELIB_UNSET;
1915: in.time->z = TIMELIB_UNSET;
1916: in.time->dst = TIMELIB_UNSET;
1917: in.tzdb = tzdb;
1918: in.time->is_localtime = 0;
1919: in.time->zone_type = 0;
1920:
1921: /* Loop over the format string */
1922: while (*fptr && *ptr) {
1923: begin = ptr;
1924: switch (*fptr) {
1925: case 'D': /* three letter day */
1926: case 'l': /* full day */
1927: {
1928: const timelib_relunit* tmprel = 0;
1929:
1930: tmprel = timelib_lookup_relunit((char **) &ptr);
1931: if (!tmprel) {
1932: add_pbf_error(s, "A textual day could not be found", string, begin);
1933: break;
1934: } else {
1935: in.time->have_relative = 1;
1936: in.time->relative.have_weekday_relative = 1;
1937: in.time->relative.weekday = tmprel->multiplier;
1938: in.time->relative.weekday_behavior = 1;
1939: }
1940: }
1941: break;
1942: case 'd': /* two digit day, with leading zero */
1943: case 'j': /* two digit day, without leading zero */
1944: TIMELIB_CHECK_NUMBER;
1945: if ((s->time->d = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
1946: add_pbf_error(s, "A two digit day could not be found", string, begin);
1947: }
1948: break;
1949: case 'S': /* day suffix, ignored, nor checked */
1950: timelib_skip_day_suffix((char **) &ptr);
1951: break;
1952: case 'z': /* day of year - resets month (0 based) - also initializes everything else to !TIMELIB_UNSET */
1953: TIMELIB_CHECK_NUMBER;
1954: if ((tmp = timelib_get_nr((char **) &ptr, 3)) == TIMELIB_UNSET) {
1955: add_pbf_error(s, "A three digit day-of-year could not be found", string, begin);
1956: } else {
1957: s->time->m = 1;
1958: s->time->d = tmp + 1;
1959: timelib_do_normalize(s->time);
1960: }
1961: break;
1962:
1963: case 'm': /* two digit month, with leading zero */
1964: case 'n': /* two digit month, without leading zero */
1965: TIMELIB_CHECK_NUMBER;
1966: if ((s->time->m = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
1967: add_pbf_error(s, "A two digit month could not be found", string, begin);
1968: }
1969: break;
1970: case 'M': /* three letter month */
1971: case 'F': /* full month */
1972: tmp = timelib_lookup_month((char **) &ptr);
1973: if (!tmp) {
1974: add_pbf_error(s, "A textual month could not be found", string, begin);
1975: } else {
1976: s->time->m = tmp;
1977: }
1978: break;
1979: case 'y': /* two digit year */
1980: {
1981: int length = 0;
1982: TIMELIB_CHECK_NUMBER;
1983: if ((s->time->y = timelib_get_nr_ex((char **) &ptr, 2, &length)) == TIMELIB_UNSET) {
1984: add_pbf_error(s, "A two digit year could not be found", string, begin);
1985: }
1986: TIMELIB_PROCESS_YEAR(s->time->y, length);
1987: }
1988: break;
1989: case 'Y': /* four digit year */
1990: TIMELIB_CHECK_NUMBER;
1991: if ((s->time->y = timelib_get_nr((char **) &ptr, 4)) == TIMELIB_UNSET) {
1992: add_pbf_error(s, "A four digit year could not be found", string, begin);
1993: }
1994: break;
1995: case 'g': /* two digit hour, with leading zero */
1996: case 'h': /* two digit hour, without leading zero */
1997: TIMELIB_CHECK_NUMBER;
1998: if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
1999: add_pbf_error(s, "A two digit hour could not be found", string, begin);
2000: }
2001: if (s->time->h > 12) {
2002: add_pbf_error(s, "Hour can not be higher than 12", string, begin);
2003: }
2004: break;
2005: case 'G': /* two digit hour, with leading zero */
2006: case 'H': /* two digit hour, without leading zero */
2007: TIMELIB_CHECK_NUMBER;
2008: if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
2009: add_pbf_error(s, "A two digit hour could not be found", string, begin);
2010: }
2011: break;
2012: case 'a': /* am/pm/a.m./p.m. */
2013: case 'A': /* AM/PM/A.M./P.M. */
2014: if (s->time->h == TIMELIB_UNSET) {
2015: add_pbf_error(s, "Meridian can only come after an hour has been found", string, begin);
2016: } else if ((tmp = timelib_meridian_with_check((char **) &ptr, s->time->h)) == TIMELIB_UNSET) {
2017: add_pbf_error(s, "A meridian could not be found", string, begin);
2018: } else {
2019: s->time->h += tmp;
2020: }
2021: break;
2022: case 'i': /* two digit minute, with leading zero */
2023: {
2024: int length;
2025: timelib_sll min;
2026:
2027: TIMELIB_CHECK_NUMBER;
2028: min = timelib_get_nr_ex((char **) &ptr, 2, &length);
2029: if (min == TIMELIB_UNSET || length != 2) {
2030: add_pbf_error(s, "A two digit minute could not be found", string, begin);
2031: } else {
2032: s->time->i = min;
2033: }
2034: }
2035: break;
2036: case 's': /* two digit second, with leading zero */
2037: {
2038: int length;
2039: timelib_sll sec;
2040:
2041: TIMELIB_CHECK_NUMBER;
2042: sec = timelib_get_nr_ex((char **) &ptr, 2, &length);
2043: if (sec == TIMELIB_UNSET || length != 2) {
2044: add_pbf_error(s, "A two second minute could not be found", string, begin);
2045: } else {
2046: s->time->s = sec;
2047: }
2048: }
2049: break;
2050: case 'u': /* up to six digit millisecond */
2051: {
2052: double f;
2053: char *tptr;
2054:
2055: TIMELIB_CHECK_NUMBER;
2056: tptr = ptr;
2057: if ((f = timelib_get_nr((char **) &ptr, 6)) == TIMELIB_UNSET || (ptr - tptr < 1)) {
2058: add_pbf_error(s, "A six digit millisecond could not be found", string, begin);
2059: } else {
2060: s->time->f = (f / pow(10, (ptr - tptr)));
2061: }
2062: }
2063: break;
2064: case ' ': /* any sort of whitespace (' ' and \t) */
2065: timelib_eat_spaces((char **) &ptr);
2066: break;
2067: case 'U': /* epoch seconds */
2068: TIMELIB_CHECK_NUMBER;
2069: TIMELIB_HAVE_RELATIVE();
2070: tmp = timelib_get_unsigned_nr((char **) &ptr, 24);
2071: s->time->y = 1970;
2072: s->time->m = 1;
2073: s->time->d = 1;
2074: s->time->h = s->time->i = s->time->s = 0;
2075: s->time->f = 0.0;
2076: s->time->relative.s += tmp;
2077: s->time->is_localtime = 1;
2078: s->time->zone_type = TIMELIB_ZONETYPE_OFFSET;
2079: s->time->z = 0;
2080: break;
2081:
2082: case 'e': /* timezone */
2083: case 'P': /* timezone */
2084: case 'T': /* timezone */
2085: case 'O': /* timezone */
2086: {
2087: int tz_not_found;
2088: s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
2089: if (tz_not_found) {
2090: add_pbf_error(s, "The timezone could not be found in the database", string, begin);
2091: }
2092: }
2093: break;
2094:
2095: case '#': /* separation symbol */
2096: if (*ptr == ';' || *ptr == ':' || *ptr == '/' || *ptr == '.' || *ptr == ',' || *ptr == '-' || *ptr == '(' || *ptr == ')') {
2097: ++ptr;
2098: } else {
2099: add_pbf_error(s, "The separation symbol ([;:/.,-]) could not be found", string, begin);
2100: }
2101: break;
2102:
2103: case ';':
2104: case ':':
2105: case '/':
2106: case '.':
2107: case ',':
2108: case '-':
2109: case '(':
2110: case ')':
2111: if (*ptr == *fptr) {
2112: ++ptr;
2113: } else {
2114: add_pbf_error(s, "The separation symbol could not be found", string, begin);
2115: }
2116: break;
2117:
2118: case '!': /* reset all fields to default */
2119: timelib_time_reset_fields(s->time);
2120: break; /* break intentionally not missing */
2121:
2122: case '|': /* reset all fields to default when not set */
2123: timelib_time_reset_unset_fields(s->time);
2124: break; /* break intentionally not missing */
2125:
2126: case '?': /* random char */
2127: ++ptr;
2128: break;
2129:
2130: case '\\': /* escaped char */
2131: *fptr++;
2132: if (*ptr == *fptr) {
2133: ++ptr;
2134: } else {
2135: add_pbf_error(s, "The escaped character could not be found", string, begin);
2136: }
2137: break;
2138:
2139: case '*': /* random chars until a separator or number ([ \t.,:;/-0123456789]) */
2140: timelib_eat_until_separator((char **) &ptr);
2141: break;
2142:
2143: case '+': /* allow extra chars in the format */
2144: allow_extra = 1;
2145: break;
2146:
2147: default:
2148: if (*fptr != *ptr) {
2149: add_pbf_error(s, "The format separator does not match", string, begin);
2150: }
2151: ptr++;
2152: }
2153: fptr++;
2154: }
2155: if (*ptr) {
2156: if (allow_extra) {
2157: add_pbf_warning(s, "Trailing data", string, ptr);
2158: } else {
2159: add_pbf_error(s, "Trailing data", string, ptr);
2160: }
2161: }
2162: /* ignore trailing +'s */
2163: while (*fptr == '+') {
2164: fptr++;
2165: }
2166: if (*fptr) {
2167: /* Trailing | and ! specifiers are valid. */
2168: int done = 0;
2169: while (*fptr && !done) {
2170: switch (*fptr++) {
2171: case '!': /* reset all fields to default */
2172: timelib_time_reset_fields(s->time);
2173: break;
2174:
2175: case '|': /* reset all fields to default when not set */
2176: timelib_time_reset_unset_fields(s->time);
2177: break;
2178:
2179: default:
2180: add_pbf_error(s, "Data missing", string, ptr);
2181: done = 1;
2182: }
2183: }
2184: }
2185:
2186: /* clean up a bit */
2187: if (s->time->h != TIMELIB_UNSET || s->time->i != TIMELIB_UNSET || s->time->s != TIMELIB_UNSET) {
2188: if (s->time->h == TIMELIB_UNSET ) {
2189: s->time->h = 0;
2190: }
2191: if (s->time->i == TIMELIB_UNSET ) {
2192: s->time->i = 0;
2193: }
2194: if (s->time->s == TIMELIB_UNSET ) {
2195: s->time->s = 0;
2196: }
2197: }
2198:
2199: /* do funky checking whether the parsed time was valid time */
2200: if (s->time->h != TIMELIB_UNSET && s->time->i != TIMELIB_UNSET &&
2201: s->time->s != TIMELIB_UNSET &&
2202: !timelib_valid_time( s->time->h, s->time->i, s->time->s)) {
2203: add_pbf_warning(s, "The parsed time was invalid", string, ptr);
2204: }
2205: /* do funky checking whether the parsed date was valid date */
2206: if (s->time->y != TIMELIB_UNSET && s->time->m != TIMELIB_UNSET &&
2207: s->time->d != TIMELIB_UNSET &&
2208: !timelib_valid_date( s->time->y, s->time->m, s->time->d)) {
2209: add_pbf_warning(s, "The parsed date was invalid", string, ptr);
2210: }
2211:
2212: if (errors) {
2213: *errors = in.errors;
2214: } else {
2215: timelib_error_container_dtor(in.errors);
2216: }
2217: return in.time;
2218: }
2219:
2220: void timelib_fill_holes(timelib_time *parsed, timelib_time *now, int options)
2221: {
2222: if (!(options & TIMELIB_OVERRIDE_TIME) && parsed->have_date && !parsed->have_time) {
2223: parsed->h = 0;
2224: parsed->i = 0;
2225: parsed->s = 0;
2226: parsed->f = 0;
2227: }
2228: if (parsed->y == TIMELIB_UNSET) parsed->y = now->y != TIMELIB_UNSET ? now->y : 0;
2229: if (parsed->d == TIMELIB_UNSET) parsed->d = now->d != TIMELIB_UNSET ? now->d : 0;
2230: if (parsed->m == TIMELIB_UNSET) parsed->m = now->m != TIMELIB_UNSET ? now->m : 0;
2231: if (parsed->h == TIMELIB_UNSET) parsed->h = now->h != TIMELIB_UNSET ? now->h : 0;
2232: if (parsed->i == TIMELIB_UNSET) parsed->i = now->i != TIMELIB_UNSET ? now->i : 0;
2233: if (parsed->s == TIMELIB_UNSET) parsed->s = now->s != TIMELIB_UNSET ? now->s : 0;
2234: if (parsed->f == TIMELIB_UNSET) parsed->f = now->f != TIMELIB_UNSET ? now->f : 0;
2235: if (parsed->z == TIMELIB_UNSET) parsed->z = now->z != TIMELIB_UNSET ? now->z : 0;
2236: if (parsed->dst == TIMELIB_UNSET) parsed->dst = now->dst != TIMELIB_UNSET ? now->dst : 0;
2237:
2238: if (!parsed->tz_abbr) {
2239: parsed->tz_abbr = now->tz_abbr ? strdup(now->tz_abbr) : NULL;
2240: }
2241: if (!parsed->tz_info) {
2242: parsed->tz_info = now->tz_info ? (!(options & TIMELIB_NO_CLONE) ? timelib_tzinfo_clone(now->tz_info) : now->tz_info) : NULL;
2243: }
2244: if (parsed->zone_type == 0 && now->zone_type != 0) {
2245: parsed->zone_type = now->zone_type;
2246: /* parsed->tz_abbr = now->tz_abbr ? strdup(now->tz_abbr) : NULL;
2247: parsed->tz_info = now->tz_info ? timelib_tzinfo_clone(now->tz_info) : NULL;
2248: */ parsed->is_localtime = 1;
2249: }
2250: /* timelib_dump_date(parsed, 2);
2251: timelib_dump_date(now, 2);
2252: */
2253: }
2254:
2255: char *timelib_timezone_id_from_abbr(const char *abbr, long gmtoffset, int isdst)
2256: {
2257: const timelib_tz_lookup_table *tp;
2258:
2259: tp = zone_search(abbr, gmtoffset, isdst);
2260: if (tp) {
2261: return (tp->full_tz_name);
2262: } else {
2263: return NULL;
2264: }
2265: }
2266:
2267: const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void)
2268: {
2269: return timelib_timezone_lookup;
2270: }
2271:
2272: #ifdef DEBUG_PARSER_STUB
2273: int main(void)
2274: {
2275: timelib_time time = timelib_strtotime("May 12");
2276:
2277: printf ("%04d-%02d-%02d %02d:%02d:%02d.%-5d %+04d %1d",
2278: time.y, time.m, time.d, time.h, time.i, time.s, time.f, time.z, time.dst);
2279: if (time.have_relative) {
2280: printf ("%3dY %3dM %3dD / %3dH %3dM %3dS",
2281: time.relative.y, time.relative.m, time.relative.d, time.relative.h, time.relative.i, time.relative.s);
2282: }
2283: if (time.have_weekday_relative) {
2284: printf (" / %d", time.relative.weekday);
2285: }
2286: if (time.have_weeknr_day) {
2287: printf(" / %dW%d", time.relative.weeknr_day.weeknr, time.relative.weeknr_day.dayofweek);
2288: }
2289: return 0;
2290: }
2291: #endif
2292:
2293: /*
2294: * vim: syntax=c
2295: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>