Statistics
| Branch: | Tag: | Revision:

dvbd / parsetime.y @ bfdb7446

History | View | Annotate | Download (9.12 KB)

1
%{
2
#include <time.h>
3
#include <stdlib.h>
4
#include <string.h>
5
#include "parsetime.h"
6

    
7
#define YYDEBUG 1
8

    
9
time_t currtime;
10
struct tm exectm;
11
static int isgmt;
12
static int time_only;
13

    
14
extern int yyerror(char *s);
15
extern int yylex();
16

    
17
int add_date(int number, int period);
18
%}
19

    
20
%union {
21
	char *	  	charval;
22
	int		intval;
23
}
24

    
25
%token  <charval> INT
26
%token  NOW
27
%token  AM PM
28
%token  NOON MIDNIGHT TEATIME
29
%token  SUN MON TUE WED THU FRI SAT
30
%token  TODAY TOMORROW
31
%token  NEXT
32
%token  MINUTE HOUR DAY WEEK MONTH YEAR
33
%token  JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
34
%token  <charval> WORD
35

    
36
%type <intval> inc_period
37
%type <intval> inc_number
38
%type <intval> day_of_week
39

    
40
%start timespec
41
%%
42
timespec        : date
43
		| time
44
		    {
45
			time_only = 1;
46
		    }
47
                | time date
48
                | time_or_not inc_or_dec
49
                | time_or_not date inc_or_dec
50
                | nowspec
51
                ;
52

    
53
nowspec         : now
54
                | now inc_or_dec
55
                ;
56

    
57
now		: NOW 
58
                | TOMORROW
59
		   {
60
			add_date(1, DAY);
61
		   }
62
		;
63

    
64
time_or_not     : time
65
		|
66

    
67
time            : hr24clock_hr_min
68
                | hr24clock_hr_min timezone_name
69
                | hr24clock_hour time_sep minute
70
                | hr24clock_hour time_sep minute timezone_name
71
                | hr24clock_hour am_pm
72
                | hr24clock_hour am_pm timezone_name
73
                | hr24clock_hour time_sep minute am_pm
74
                | hr24clock_hour time_sep minute am_pm timezone_name
75
                | NOON
76
		    {
77
			exectm.tm_hour = 12;
78
			exectm.tm_min = 0;
79
		    }
80
                | MIDNIGHT
81
		    {
82
			exectm.tm_hour = 0;
83
			exectm.tm_min = 0;
84
			add_date(1, DAY);
85
		    }
86
		| TEATIME
87
		    {
88
			exectm.tm_hour = 16;
89
			exectm.tm_min = 0;
90
		    }
91
                ;
92

    
93
date            : month_name day_number
94
                | month_name day_number year_number
95
                | month_name day_number ',' year_number
96
                | day_of_week
97
		   {
98
		       add_date ((6 + $1 - exectm.tm_wday) %7 + 1, DAY);
99
		   }
100
                | TODAY
101
                | TOMORROW
102
		   {
103
			add_date(1, DAY);
104
		   }
105
		| year_number '-' month_number '-' day_number
106
		| day_number '.' month_number '.' year_number
107
		| day_number '.' month_number
108
		| day_number month_name
109
		| day_number month_name year_number
110
		| month_number '/' day_number '/' year_number
111
                ;
112

    
113
inc_or_dec	: increment
114
		| decrement
115

    
116
increment       : '+' inc_number inc_period
117
		    {
118
		        add_date($2, $3);
119
		    }
120
                | NEXT inc_period		
121
		    {
122
			add_date(1, $2);
123
		    }
124
		| NEXT day_of_week
125
		    {
126
			add_date ((6 + $2 - exectm.tm_wday) %7 +1, DAY);
127
		    }
128
                ;
129

    
130
decrement	: '-' inc_number inc_period
131
		    {
132
			add_date(-$2, $3);
133
		    }
134
		;
135

    
136
inc_period      : MINUTE { $$ = MINUTE ; }
137
                | HOUR	 { $$ = HOUR ; }
138
                | DAY	 { $$ = DAY ; }
139
                | WEEK   { $$ = WEEK ; }
140
                | MONTH  { $$ = MONTH ; }
141
                | YEAR   { $$ = YEAR ; }
142
                ;
143

    
144
hr24clock_hr_min: INT
145
		    {
146
			if (strlen($1) == 4) {
147
			    exectm.tm_min = -1;
148
			    exectm.tm_hour = -1;
149
			    sscanf($1, "%2d %2d", &exectm.tm_hour,
150
				&exectm.tm_min);
151
			} else if (strlen($1) >= 5 && strlen($1) <= 8) {
152
				/* Ok, this is a kluge.  I hate design errors...  -Joey */
153
				char shallot[5];
154
				char *onion;
155

    
156
				onion=$1;
157
				memset (shallot, 0, sizeof (shallot));
158
				if (strlen($1) == 5 || strlen($1) == 7) {
159
				    strncpy (shallot,onion,1);
160
				    onion++;
161
				} else {
162
				    strncpy (shallot,onion,2);
163
				    onion+=2;
164
				}
165
				sscanf(shallot, "%d", &exectm.tm_mon);
166

    
167
				if (exectm.tm_mon < 1 || exectm.tm_mon > 12) {
168
				    yyerror("Error in month number");
169
				    YYERROR;
170
				}
171
				exectm.tm_mon--;
172

    
173
				memset (shallot, 0, sizeof (shallot));
174
				strncpy (shallot,onion,2);
175
			    	sscanf(shallot, "%d", &exectm.tm_mday);
176
				if (exectm.tm_mday < 0 || exectm.tm_mday > 31)
177
				{
178
				    yyerror("Error in day of month");
179
				    YYERROR;
180
				}
181

    
182
				onion+=2;
183
				memset (shallot, 0, sizeof (shallot));
184
				strncpy (shallot,onion,4);
185
				if ( sscanf(shallot, "%d", &exectm.tm_year) != 1) {
186
				    yyerror("Error in year");
187
				    YYERROR;
188
				}
189
				if (exectm.tm_year < 70) {
190
				    exectm.tm_year += 100;
191
				}
192
				else if (exectm.tm_year > 1900) {
193
				    exectm.tm_year -= 1900;
194
				}
195
			}
196
			else {
197
			    sscanf($1, "%d", &exectm.tm_hour);
198
			    exectm.tm_min = 0;
199
			}
200
			free($1);
201

    
202
			if (exectm.tm_min > 60 || exectm.tm_min < 0) {
203
			    yyerror("Problem in minutes specification");
204
			    YYERROR;
205
			}
206
			if (exectm.tm_hour > 24 || exectm.tm_hour < 0) {
207
			    yyerror("Problem in hours specification");
208
			    YYERROR;
209
		        }
210
		    }
211
		;
212

    
213
timezone_name	: WORD
214
		    {
215
			if (strcasecmp($1,"utc") == 0) {
216
			    isgmt = 1;
217
			}
218
			else {
219
			    yyerror("Only UTC timezone is supported");
220
			    YYERROR;
221
			}
222
			free($1);
223
		    }
224
		;
225

    
226
hr24clock_hour	: hr24clock_hr_min
227
		;
228

    
229
minute		: INT
230
                    {
231
			if (sscanf($1, "%d", &exectm.tm_min) != 1) {
232
			    yyerror("Error in minute");
233
			    YYERROR;
234
		        }
235
			free($1);
236
		    }
237
		;
238

    
239
am_pm		: AM
240
		    {
241
			if (exectm.tm_hour > 12) {
242
			    yyerror("Hour too large for AM");
243
			    YYERROR;
244
			}
245
			else if (exectm.tm_hour == 12) {
246
			    exectm.tm_hour = 0;
247
			}
248
		    }
249
		| PM
250
		    {
251
			if (exectm.tm_hour > 12) {
252
			    yyerror("Hour too large for PM");
253
			    YYERROR;
254
			}
255
			else if (exectm.tm_hour < 12) {
256
			    exectm.tm_hour +=12;
257
			}
258
		    }
259
		;
260

    
261

    
262
month_name	: JAN { exectm.tm_mon = 0; }
263
		| FEB { exectm.tm_mon = 1; }
264
		| MAR { exectm.tm_mon = 2; }
265
		| APR { exectm.tm_mon = 3; }
266
		| MAY { exectm.tm_mon = 4; }
267
		| JUN { exectm.tm_mon = 5; }
268
		| JUL { exectm.tm_mon = 6; }
269
		| AUG { exectm.tm_mon = 7; }
270
		| SEP { exectm.tm_mon = 8; }
271
		| OCT { exectm.tm_mon = 9; }
272
		| NOV { exectm.tm_mon =10; }
273
		| DEC { exectm.tm_mon =11; }
274
		;
275

    
276
month_number	: INT
277
		    {
278
			{
279
			    int mnum = -1;
280
			    sscanf($1, "%d", &mnum);
281

    
282
			    if (mnum < 1 || mnum > 12) {
283
				yyerror("Error in month number");
284
				YYERROR;
285
			    }
286
			    exectm.tm_mon = mnum -1;
287
			    free($1);
288
			}
289
		    }
290
day_number	: INT
291
                     {
292
			exectm.tm_mday = -1;
293
			sscanf($1, "%d", &exectm.tm_mday);
294
			if (exectm.tm_mday < 0 || exectm.tm_mday > 31)
295
			{
296
			    yyerror("Error in day of month");
297
			    YYERROR; 
298
			}
299
			free($1);
300
		     }
301
		;
302

    
303
year_number	: INT
304
		    { 
305
			{
306
			    int ynum;
307

    
308
			    if ( sscanf($1, "%d", &ynum) != 1) {
309
				yyerror("Error in year");
310
				YYERROR;
311
			    }
312
			    if (ynum < 70) {
313
				ynum += 100;
314
			    }
315
			    else if (ynum > 1900) {
316
				ynum -= 1900;
317
			    }
318

    
319
			    exectm.tm_year = ynum ;
320
			    free($1);
321
			}
322
		    }
323
		;
324

    
325

    
326
day_of_week	: SUN { $$ = 0; }
327
		| MON { $$ = 1; }
328
		| TUE { $$ = 2; }
329
		| WED { $$ = 3; }
330
		| THU { $$ = 4; }
331
		| FRI { $$ = 5; }
332
		| SAT { $$ = 6; }
333
		;
334

    
335
inc_number	: INT
336
		    {
337
			if (sscanf($1, "%d", &$$) != 1) {
338
			    yyerror("Unknown increment");
339
			    YYERROR;
340
		        }
341
		        free($1);
342
		    }
343
		;
344

    
345
time_sep	: ':'
346
		| '\''
347
		| '.'
348
		| 'h'
349
		| ','
350
		;
351

    
352
%%
353

    
354

    
355
time_t parsetime(int, char **);
356

    
357
time_t
358
parsetime(int argc, char **argv)
359
{
360
    time_t exectime;
361

    
362
    my_argv = argv;
363
    currtime = time(NULL);
364
    exectm = *localtime(&currtime);
365
    exectm.tm_sec = 0;
366
    exectm.tm_isdst = -1;
367
    time_only = 0;
368
    if (yyparse() == 0) {
369
	exectime = mktime(&exectm);
370
	if (exectime == (time_t)-1)
371
	    return 0;
372
	if (isgmt) {
373
	    exectime += timezone;
374
	    if (daylight) {
375
		exectime -= 3600;
376
	    }
377
	}
378
	if (time_only && (currtime > exectime)) {
379
	    exectime += 24*3600;
380
	}
381
        return exectime;
382
    }
383
    else {
384
	return 0;    
385
    }
386
}
387

    
388
#ifdef TEST_PARSER
389
/*
390

    
391
Here are some lines to test:
392

    
393
./parsetest 7AM Mar 24 2000
394
./parsetest 7AM Mar 24 00
395
./parsetest 7AM 032400
396
./parsetest 7AM 03/24/00
397
./parsetest 7AM 24.03.00
398
./parsetest 7AM Mar 24
399

    
400
./parsetest 03242000
401
./parsetest noon 03242000
402
./parsetest 5:30
403
./parsetest 4pm + 3 days
404
./parsetest 10am Jul 31
405

    
406
 */
407
int
408
main(int argc, char **argv)
409
{
410
    time_t res;
411
    res = parsetime(argc-1, &argv[1]);
412
    if (res > 0) {
413
	printf("%s",ctime(&res));
414
    }
415
    else {
416
	printf("Ooops...\n");
417
    }
418
    return 0;
419
}
420

    
421
#endif
422
int yyerror(char *s)
423
{
424
    if (last_token == NULL)
425
	last_token = "(empty)";
426
    fprintf(stderr,"%s. Last token seen: %s\n",s, last_token);
427
    return 0;
428
}
429

    
430
void
431
add_seconds(struct tm *tm, long numsec)
432
{
433
    time_t timeval;
434
    timeval = mktime(tm);
435
    if (timeval == (time_t)-1)
436
        timeval = (time_t)0;
437
    timeval += numsec;
438
    *tm = *localtime(&timeval);
439
}
440

    
441
int
442
add_date(int number, int period)
443
{
444
    switch(period) {
445
    case MINUTE:
446
	add_seconds(&exectm , 60l*number);
447
	break;
448

    
449
    case HOUR:
450
	add_seconds(&exectm, 3600l * number);
451
	break;
452

    
453
    case DAY:
454
	add_seconds(&exectm, 24*3600l * number);
455
	break;
456

    
457
    case WEEK:
458
	add_seconds(&exectm, 7*24*3600l*number);
459
	break;
460

    
461
    case MONTH:
462
	{
463
	    int newmonth = exectm.tm_mon + number;
464
	    number = 0;
465
	    while (newmonth < 0) {
466
		newmonth += 12;
467
		number --;
468
	    }
469
	    exectm.tm_mon = newmonth % 12;
470
	    number += newmonth / 12 ;
471
	}
472
	if (number == 0) {
473
	    break;
474
	}
475
	/* fall through */
476

    
477
    case YEAR:
478
	exectm.tm_year += number;
479
	break;
480

    
481
    default:
482
	yyerror("Internal parser error");
483
	fprintf(stderr,"Unexpected case %d\n", period);
484
	abort();
485
    }
486
    return 0;
487
}