![]() ![]() | ![]() |
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:
26: #ifdef HAVE_STDLIB_H
27: #include <stdlib.h>
28: #endif
29: #ifdef HAVE_STRING_H
30: #include <string.h>
31: #else
32: #include <strings.h>
33: #endif
34:
35: #if defined(_MSC_VER)
36: # define strtoll(s, f, b) _atoi64(s)
37: #elif !defined(HAVE_STRTOLL)
38: # if defined(HAVE_ATOLL)
39: # define strtoll(s, f, b) atoll(s)
40: # else
41: # define strtoll(s, f, b) strtol(s, f, b)
42: # endif
43: #endif
44:
45: #define TIMELIB_UNSET -99999
46:
47: #define TIMELIB_SECOND 1
48: #define TIMELIB_MINUTE 2
49: #define TIMELIB_HOUR 3
50: #define TIMELIB_DAY 4
51: #define TIMELIB_MONTH 5
52: #define TIMELIB_YEAR 6
53:
54: #define EOI 257
55:
56: #define TIMELIB_PERIOD 260
57: #define TIMELIB_ISO_DATE 261
58: #define TIMELIB_ERROR 999
59:
60: typedef unsigned char uchar;
61:
62: #define BSIZE 8192
63:
64: #define YYCTYPE uchar
65: #define YYCURSOR cursor
66: #define YYLIMIT s->lim
67: #define YYMARKER s->ptr
68: #define YYFILL(n) return EOI;
69:
70: #define RET(i) {s->cur = cursor; return i;}
71:
72: #define timelib_string_free free
73:
74: #define TIMELIB_INIT s->cur = cursor; str = timelib_string(s); ptr = str
75: #define TIMELIB_DEINIT timelib_string_free(str)
76:
77: #ifdef DEBUG_PARSER
78: #define DEBUG_OUTPUT(s) printf("%s\n", s);
79: #define YYDEBUG(s,c) { if (s != -1) { printf("state: %d ", s); printf("[%c]\n", c); } }
80: #else
81: #define DEBUG_OUTPUT(s)
82: #define YYDEBUG(s,c)
83: #endif
84:
85: #include "timelib_structs.h"
86:
87: typedef struct Scanner {
88: int fd;
89: uchar *lim, *str, *ptr, *cur, *tok, *pos;
90: unsigned int line, len;
91: struct timelib_error_container *errors;
92:
93: struct timelib_time *begin;
94: struct timelib_time *end;
95: struct timelib_rel_time *period;
96: int recurrences;
97:
98: int have_period;
99: int have_recurrences;
100: int have_date;
101: int have_begin_date;
102: int have_end_date;
103: } Scanner;
104:
105: #define HOUR(a) (int)(a * 60)
106:
107: static void add_warning(Scanner *s, char *error)
108: {
109: s->errors->warning_count++;
110: s->errors->warning_messages = realloc(s->errors->warning_messages, s->errors->warning_count * sizeof(timelib_error_message));
111: s->errors->warning_messages[s->errors->warning_count - 1].position = s->tok ? s->tok - s->str : 0;
112: s->errors->warning_messages[s->errors->warning_count - 1].character = s->tok ? *s->tok : 0;
113: s->errors->warning_messages[s->errors->warning_count - 1].message = strdup(error);
114: }
115:
116: static void add_error(Scanner *s, char *error)
117: {
118: s->errors->error_count++;
119: s->errors->error_messages = realloc(s->errors->error_messages, s->errors->error_count * sizeof(timelib_error_message));
120: s->errors->error_messages[s->errors->error_count - 1].position = s->tok ? s->tok - s->str : 0;
121: s->errors->error_messages[s->errors->error_count - 1].character = s->tok ? *s->tok : 0;
122: s->errors->error_messages[s->errors->error_count - 1].message = strdup(error);
123: }
124:
125: static char *timelib_string(Scanner *s)
126: {
127: char *tmp = calloc(1, s->cur - s->tok + 1);
128: memcpy(tmp, s->tok, s->cur - s->tok);
129:
130: return tmp;
131: }
132:
133: static timelib_sll timelib_get_nr(char **ptr, int max_length)
134: {
135: char *begin, *end, *str;
136: timelib_sll tmp_nr = TIMELIB_UNSET;
137: int len = 0;
138:
139: while ((**ptr < '0') || (**ptr > '9')) {
140: if (**ptr == '\0') {
141: return TIMELIB_UNSET;
142: }
143: ++*ptr;
144: }
145: begin = *ptr;
146: while ((**ptr >= '0') && (**ptr <= '9') && len < max_length) {
147: ++*ptr;
148: ++len;
149: }
150: end = *ptr;
151: str = calloc(1, end - begin + 1);
152: memcpy(str, begin, end - begin);
153: tmp_nr = strtoll(str, NULL, 10);
154: free(str);
155: return tmp_nr;
156: }
157:
158: static timelib_ull timelib_get_unsigned_nr(char **ptr, int max_length)
159: {
160: timelib_ull dir = 1;
161:
162: while (((**ptr < '0') || (**ptr > '9')) && (**ptr != '+') && (**ptr != '-')) {
163: if (**ptr == '\0') {
164: return TIMELIB_UNSET;
165: }
166: ++*ptr;
167: }
168:
169: while (**ptr == '+' || **ptr == '-')
170: {
171: if (**ptr == '-') {
172: dir *= -1;
173: }
174: ++*ptr;
175: }
176: return dir * timelib_get_nr(ptr, max_length);
177: }
178:
179: static long timelib_parse_tz_cor(char **ptr)
180: {
181: char *begin = *ptr, *end;
182: long tmp;
183:
184: while (isdigit(**ptr) || **ptr == ':') {
185: ++*ptr;
186: }
187: end = *ptr;
188: switch (end - begin) {
189: case 1:
190: case 2:
191: return HOUR(strtol(begin, NULL, 10));
192: break;
193: case 3:
194: case 4:
195: if (begin[1] == ':') {
196: tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 2, NULL, 10);
197: return tmp;
198: } else if (begin[2] == ':') {
199: tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10);
200: return tmp;
201: } else {
202: tmp = strtol(begin, NULL, 10);
203: return HOUR(tmp / 100) + tmp % 100;
204: }
205: case 5:
206: tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10);
207: return tmp;
208: }
209: return 0;
210: }
211:
212: static void timelib_eat_spaces(char **ptr)
213: {
214: while (**ptr == ' ' || **ptr == '\t') {
215: ++*ptr;
216: }
217: }
218:
219: static void timelib_eat_until_separator(char **ptr)
220: {
221: while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) {
222: ++*ptr;
223: }
224: }
225:
226: static long timelib_get_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_found, const timelib_tzdb *tzdb)
227: {
228: long retval = 0;
229:
230: *tz_not_found = 0;
231:
232: while (**ptr == ' ' || **ptr == '\t' || **ptr == '(') {
233: ++*ptr;
234: }
235: if ((*ptr)[0] == 'G' && (*ptr)[1] == 'M' && (*ptr)[2] == 'T' && ((*ptr)[3] == '+' || (*ptr)[3] == '-')) {
236: *ptr += 3;
237: }
238: if (**ptr == '+') {
239: ++*ptr;
240: t->is_localtime = 1;
241: t->zone_type = TIMELIB_ZONETYPE_OFFSET;
242: *tz_not_found = 0;
243: t->dst = 0;
244:
245: retval = -1 * timelib_parse_tz_cor(ptr);
246: } else if (**ptr == '-') {
247: ++*ptr;
248: t->is_localtime = 1;
249: t->zone_type = TIMELIB_ZONETYPE_OFFSET;
250: *tz_not_found = 0;
251: t->dst = 0;
252:
253: retval = timelib_parse_tz_cor(ptr);
254: }
255: while (**ptr == ')') {
256: ++*ptr;
257: }
258: return retval;
259: }
260:
261: #define timelib_split_free(arg) { \
262: int i; \
263: for (i = 0; i < arg.c; i++) { \
264: free(arg.v[i]); \
265: } \
266: if (arg.v) { \
267: free(arg.v); \
268: } \
269: }
270:
271: /* date parser's scan function too large for VC6 - VC7.x
272: drop the optimization solves the problem */
273: #ifdef PHP_WIN32
274: #pragma optimize( "", off )
275: #endif
276: static int scan(Scanner *s)
277: {
278: uchar *cursor = s->cur;
279: char *str, *ptr = NULL;
280:
281: std:
282: s->tok = cursor;
283: s->len = 0;
284: /*!re2c
285:
286: /* */
287: any = [\000-\377];
288: number = [0-9]+;
289:
290: hour24lz = [01][0-9] | "2"[0-4];
291: minutelz = [0-5][0-9];
292: monthlz = "0" [1-9] | "1" [0-2];
293: monthlzz = "0" [0-9] | "1" [0-2];
294: daylz = "0" [1-9] | [1-2][0-9] | "3" [01];
295: daylzz = "0" [0-9] | [1-2][0-9] | "3" [01];
296: secondlz = minutelz;
297: year4 = [0-9]{4};
298: weekofyear = "0"[1-9] | [1-4][0-9] | "5"[0-3];
299:
300: space = [ \t]+;
301: datetimebasic = year4 monthlz daylz "T" hour24lz minutelz secondlz "Z";
302: datetimeextended = year4 "-" monthlz "-" daylz "T" hour24lz ':' minutelz ':' secondlz "Z";
303: period = "P" (number "Y")? (number "M")? (number "W")? (number "D")? ("T" (number "H")? (number "M")? (number "S")?)?;
304: combinedrep = "P" year4 "-" monthlzz "-" daylzz "T" hour24lz ':' minutelz ':' secondlz;
305:
306: recurrences = "R" number;
307:
308: isoweekday = year4 "-"? "W" weekofyear "-"? [0-7];
309: isoweek = year4 "-"? "W" weekofyear;
310:
311: */
312:
313: /*!re2c
314: /* so that vim highlights correctly */
315: recurrences
316: {
317: DEBUG_OUTPUT("recurrences");
318: TIMELIB_INIT;
319: ptr++;
320: s->recurrences = timelib_get_unsigned_nr((char **) &ptr, 9);
321: TIMELIB_DEINIT;
322: s->have_recurrences = 1;
323: return TIMELIB_PERIOD;
324: }
325:
326: datetimebasic| datetimeextended
327: {
328: timelib_time *current;
329:
330: if (s->have_date || s->have_period) {
331: current = s->end;
332: s->have_end_date = 1;
333: } else {
334: current = s->begin;
335: s->have_begin_date = 1;
336: }
337: DEBUG_OUTPUT("datetimebasic | datetimeextended");
338: TIMELIB_INIT;
339: current->y = timelib_get_nr((char **) &ptr, 4);
340: current->m = timelib_get_nr((char **) &ptr, 2);
341: current->d = timelib_get_nr((char **) &ptr, 2);
342: current->h = timelib_get_nr((char **) &ptr, 2);
343: current->i = timelib_get_nr((char **) &ptr, 2);
344: current->s = timelib_get_nr((char **) &ptr, 2);
345: s->have_date = 1;
346: TIMELIB_DEINIT;
347: return TIMELIB_ISO_DATE;
348: }
349:
350: period
351: {
352: timelib_sll nr;
353: int in_time = 0;
354: DEBUG_OUTPUT("period");
355: TIMELIB_INIT;
356: ptr++;
357: do {
358: if ( *ptr == 'T' ) {
359: in_time = 1;
360: ptr++;
361: }
362: if ( *ptr == '\0' ) {
363: add_error(s, "Missing expected time part");
364: break;
365: }
366:
367: nr = timelib_get_unsigned_nr((char **) &ptr, 12);
368: switch (*ptr) {
369: case 'Y': s->period->y = nr; break;
370: case 'W': s->period->d = nr * 7; break;
371: case 'D': s->period->d = nr; break;
372: case 'H': s->period->h = nr; break;
373: case 'S': s->period->s = nr; break;
374: case 'M':
375: if (in_time) {
376: s->period->i = nr;
377: } else {
378: s->period->m = nr;
379: }
380: break;
381: default:
382: add_error(s, "Undefined period specifier");
383: break;
384: }
385: ptr++;
1.1.1.4 ! misho 386: } while (!s->errors->error_count && *ptr);
1.1 misho 387: s->have_period = 1;
388: TIMELIB_DEINIT;
389: return TIMELIB_PERIOD;
390: }
391:
392: combinedrep
393: {
394: DEBUG_OUTPUT("combinedrep");
395: TIMELIB_INIT;
396: s->period->y = timelib_get_unsigned_nr((char **) &ptr, 4);
397: ptr++;
398: s->period->m = timelib_get_unsigned_nr((char **) &ptr, 2);
399: ptr++;
400: s->period->d = timelib_get_unsigned_nr((char **) &ptr, 2);
401: ptr++;
402: s->period->h = timelib_get_unsigned_nr((char **) &ptr, 2);
403: ptr++;
404: s->period->i = timelib_get_unsigned_nr((char **) &ptr, 2);
405: ptr++;
406: s->period->s = timelib_get_unsigned_nr((char **) &ptr, 2);
407: s->have_period = 1;
408: TIMELIB_DEINIT;
409: return TIMELIB_PERIOD;
410: }
411:
412: [ .,\t/]
413: {
414: goto std;
415: }
416:
417: "\000"|"\n"
418: {
419: s->pos = cursor; s->line++;
420: goto std;
421: }
422:
423: any
424: {
425: add_error(s, "Unexpected character");
426: goto std;
427: }
428: */
429: }
430: #ifdef PHP_WIN32
431: #pragma optimize( "", on )
432: #endif
433:
434: /*!max:re2c */
435:
436: void timelib_strtointerval(char *s, int len,
437: timelib_time **begin, timelib_time **end,
438: timelib_rel_time **period, int *recurrences,
439: struct timelib_error_container **errors)
440: {
441: Scanner in;
442: int t;
443: char *e = s + len - 1;
444:
445: memset(&in, 0, sizeof(in));
446: in.errors = malloc(sizeof(struct timelib_error_container));
447: in.errors->warning_count = 0;
448: in.errors->warning_messages = NULL;
449: in.errors->error_count = 0;
450: in.errors->error_messages = NULL;
451:
452: if (len > 0) {
453: while (isspace(*s) && s < e) {
454: s++;
455: }
456: while (isspace(*e) && e > s) {
457: e--;
458: }
459: }
460: if (e - s < 0) {
461: add_error(&in, "Empty string");
462: if (errors) {
463: *errors = in.errors;
464: } else {
465: timelib_error_container_dtor(in.errors);
466: }
467: return;
468: }
469: e++;
470:
471: /* init cursor */
472: in.str = malloc((e - s) + YYMAXFILL);
473: memset(in.str, 0, (e - s) + YYMAXFILL);
474: memcpy(in.str, s, (e - s));
475: in.lim = in.str + (e - s) + YYMAXFILL;
476: in.cur = in.str;
477:
478: /* init value containers */
479: in.begin = timelib_time_ctor();
480: in.begin->y = TIMELIB_UNSET;
481: in.begin->d = TIMELIB_UNSET;
482: in.begin->m = TIMELIB_UNSET;
483: in.begin->h = TIMELIB_UNSET;
484: in.begin->i = TIMELIB_UNSET;
485: in.begin->s = TIMELIB_UNSET;
486: in.begin->f = 0;
487: in.begin->z = 0;
488: in.begin->dst = 0;
489: in.begin->is_localtime = 0;
490: in.begin->zone_type = TIMELIB_ZONETYPE_OFFSET;
491:
492: in.end = timelib_time_ctor();
493: in.end->y = TIMELIB_UNSET;
494: in.end->d = TIMELIB_UNSET;
495: in.end->m = TIMELIB_UNSET;
496: in.end->h = TIMELIB_UNSET;
497: in.end->i = TIMELIB_UNSET;
498: in.end->s = TIMELIB_UNSET;
499: in.end->f = 0;
500: in.end->z = 0;
501: in.end->dst = 0;
502: in.end->is_localtime = 0;
503: in.end->zone_type = TIMELIB_ZONETYPE_OFFSET;
504:
505: in.period = timelib_rel_time_ctor();
506: in.period->y = 0;
507: in.period->d = 0;
508: in.period->m = 0;
509: in.period->h = 0;
510: in.period->i = 0;
511: in.period->s = 0;
512: in.period->weekday = 0;
513: in.period->weekday_behavior = 0;
514: in.period->first_last_day_of = 0;
515: in.period->days = TIMELIB_UNSET;
516:
517: in.recurrences = 1;
518:
519: do {
520: t = scan(&in);
521: #ifdef DEBUG_PARSER
522: printf("%d\n", t);
523: #endif
524: } while(t != EOI);
525:
526: free(in.str);
527: if (errors) {
528: *errors = in.errors;
529: } else {
530: timelib_error_container_dtor(in.errors);
531: }
532: if (in.have_begin_date) {
533: *begin = in.begin;
534: } else {
535: timelib_time_dtor(in.begin);
536: }
537: if (in.have_end_date) {
538: *end = in.end;
539: } else {
540: timelib_time_dtor(in.end);
541: }
542: if (in.have_period) {
543: *period = in.period;
544: } else {
545: timelib_rel_time_dtor(in.period);
546: }
547: if (in.have_recurrences) {
548: *recurrences = in.recurrences;
549: }
550: }
551:
552:
553: /*
554: * vim: syntax=c
555: */