]> diplodocus.org Git - nmh/blob - zotnet/tws/dtimep.lex
Added note that user questions are acceptable on nmh-workers.
[nmh] / zotnet / tws / dtimep.lex
1 %e 2000
2 %p 5000
3 %n 1000
4 %a 4000
5 %START Z
6 sun (sun(day)?)
7 mon (mon(day)?)
8 tue (tue(sday)?)
9 wed (wed(nesday)?)
10 thu (thu(rsday)?)
11 fri (fri(day)?)
12 sat (sat(urday)?)
13
14 DAY ({sun}|{mon}|{tue}|{wed}|{thu}|{fri}|{sat})
15
16 jan (jan(uary)?)
17 feb (feb(ruary)?)
18 mar (mar(ch)?)
19 apr (apr(il)?)
20 may (may)
21 jun (jun(e)?)
22 jul (jul(y)?)
23 aug (aug(ust)?)
24 sep (sep(tember)?)
25 oct (oct(ober)?)
26 nov (nov(ember)?)
27 dec (dec(ember)?)
28
29 MONTH ({jan}|{feb}|{mar}|{apr}|{may}|{jun}|{jul}|{aug}|{sep}|{oct}|{nov}|{dec})
30
31 w ([ \t]*)
32 W ([ \t]+)
33 D ([0-9]?[0-9])
34 d [0-9]
35 %{
36 #include <h/nmh.h>
37 #include <tws.h>
38 #if !defined(HAVE_TM_GMTOFF) && !defined(HAVE_TZSET)
39 # include <sys/timeb.h>
40 #endif
41
42 #if !defined(HAVE_TM_GMTOFF) && defined(HAVE_TZSET)
43 extern int daylight;
44 extern long timezone;
45 extern char *tzname[];
46 #endif
47
48 /*
49 * Patchable flag that says how to interpret NN/NN/NN dates. When
50 * true, we do it European style: DD/MM/YY. When false, we do it
51 * American style: MM/DD/YY. Of course, these are all non-RFC822
52 * compliant.
53 */
54 int europeandate = 0;
55
56 /*
57 * Table to convert month names to numeric month. We use the
58 * fact that the low order 5 bits of the sum of the 2nd & 3rd
59 * characters of the name is a hash with no collisions for the 12
60 * valid month names. (The mask to 5 bits maps any combination of
61 * upper and lower case into the same hash value).
62 */
63 static int month_map[] = {
64 0,
65 6, /* 1 - Jul */
66 3, /* 2 - Apr */
67 5, /* 3 - Jun */
68 0,
69 10, /* 5 - Nov */
70 0,
71 1, /* 7 - Feb */
72 11, /* 8 - Dec */
73 0,
74 0,
75 0,
76 0,
77 0,
78 0,
79 0, /*15 - Jan */
80 0,
81 0,
82 0,
83 2, /*19 - Mar */
84 0,
85 8, /*21 - Sep */
86 0,
87 9, /*23 - Oct */
88 0,
89 0,
90 4, /*26 - May */
91 0,
92 7 /*28 - Aug */
93 };
94 /*
95 * Same trick for day-of-week using the hash function
96 * (c1 & 7) + (c2 & 4)
97 */
98 static int day_map[] = {
99 0,
100 0,
101 0,
102 6, /* 3 - Sat */
103 4, /* 4 - Thu */
104 0,
105 5, /* 6 - Fri */
106 0, /* 7 - Sun */
107 2, /* 8 - Tue */
108 1 /* 9 - Mon */,
109 0,
110 3 /*11 - Wed */
111 };
112 #define SETDAY { tw.tw_wday= day_map[(cp[0] & 7) + (cp[1] & 4)];\
113 tw.tw_flags &= ~TW_SDAY; tw.tw_flags |= TW_SEXP;\
114 cp += 2; }
115 #define SETMONTH { tw.tw_mon = month_map[(cp[0] + cp[1]) & 0x1f]; gotdate++;\
116 cp += 2;\
117 SKIPD;}
118 #define CVT1OR2 (i=(*cp++ - '0'), isdigit(*cp)? i*10 + (*cp++ - '0') : i)
119 #define CVT2 ((cp[0] - '0')*10 + (cp[1] - '0'))
120 #define CVT4 ((((cp[0] - '0')*10 + (cp[1] - '0'))*10 + \
121 (cp[2] - '0'))*10 + (cp[3] - '0'))
122 #define SKIPD { while ( !isdigit(*cp++) ) ; --cp; }
123 #define EXPZONE { tw.tw_flags &= ~TW_SZONE; tw.tw_flags |= TW_SZEXP; }
124 #define ZONE(x) { tw.tw_zone=(x); EXPZONE; }
125 #define ZONED(x) { ZONE(x); tw.tw_flags |= TW_DST; }
126 #define LC(c) (isupper (c) ? tolower (c) : (c))
127
128 #ifdef DSTXXX
129 # ifdef TIME_WITH_SYS_TIME
130 # include <sys/time.h>
131 # include <time.h>
132 # else
133 # ifdef HAVE_SYS_TIME_H
134 # include <sys/time.h>
135 # else
136 # include <time.h>
137 # endif
138 # endif
139
140 static void
141 zonehack (struct tws *tw)
142 {
143 register struct tm *tm;
144
145 if (dmktime (tw) == (time_t) -1)
146 return;
147
148 tm = localtime (&tw->tw_clock);
149 if (tm->tm_isdst) {
150 tw->tw_flags |= TW_DST;
151 tw->tw_zone -= 60;
152 }
153 }
154 #endif /* DSTXXX */
155 %}
156 %%
157 %{
158 struct tws *
159 dparsetime (char *str)
160 {
161 register int i;
162 static struct tws tw;
163 register char *cp;
164 register int gotdate = 0;
165 time_t tclock;
166
167 #ifdef HAVE_TM_GMTOFF
168 struct tm *tm;
169 time_t clock;
170 #else
171 # ifndef HAVE_TZSET
172 struct timeb tb;
173 # endif /* not HAVE_TZSET */
174 #endif /* HAVE_TM_GMTOFF */
175
176 start_cond = 0;
177
178 /* Zero out the struct. */
179 memset( (char *) &tw, 0, sizeof(tw));
180
181 /* Set default time zone. */
182 #ifdef HAVE_TM_GMTOFF
183 time (&clock);
184 tm = localtime(&clock);
185 tw.tw_zone = tm->tm_gmtoff / 60;
186 if (tm->tm_isdst) /* if DST is in effect */
187 tw.tw_zone -= 60; /* reset to normal offset */
188 #else
189 # ifdef HAVE_TZSET
190 tzset();
191 tw.tw_zone = -(timezone / 60);
192 # else
193 ftime(&tb);
194 tw.tw_zone = -tb.timezone;
195 # endif /* HAVE_TZSET */
196 #endif /* HAVE_TM_GMTOFF */
197
198 while (isspace(*str))
199 str++;
200 while (1)
201 switch (cp = str, *cp ? lex_string( &str, start_cond) : 0) {
202
203 case -1:
204 if (!gotdate || tw.tw_year == 0)
205 return (struct tws *)0;
206 /* fall through */
207 case 0:
208 if (tw.tw_year == 0) {
209 /* Set default year. */
210 time (&tclock);
211 tw.tw_year = localtime(&tclock)->tm_year + 1900;
212 } else if (tw.tw_year < 100) {
213 /* assume no 2-digit years > 1999 */
214 tw.tw_year += 1900;
215 }
216 return &tw;
217
218 %}
219 {DAY}","?{w} SETDAY;
220 "("{DAY}")"(","?) {
221 cp++;
222 SETDAY;
223 }
224 {D}(("-"{D}"-")|("/"{D}"/")){D}?{d}{d}{w} {
225 if (europeandate) {
226 /* European: DD/MM/YY */
227 tw.tw_mday = CVT1OR2;
228 cp++;
229 tw.tw_mon = CVT1OR2 - 1;
230 } else {
231 /* American: MM/DD/YY */
232 tw.tw_mon = CVT1OR2 - 1;
233 cp++;
234 tw.tw_mday = CVT1OR2;
235 }
236 cp++;
237 for (i = 0; isdigit(*cp); )
238 i = i*10 + (*cp++ - '0');
239 tw.tw_year = i;
240 gotdate++; /* XXX */
241 }
242 {D}("/"|"-"){D}{w} {
243 if (europeandate) {
244 tw.tw_mday = CVT1OR2; cp++;
245 tw.tw_mon = CVT1OR2 - 1;
246 } else {
247 tw.tw_mon = CVT1OR2 - 1; cp++;
248 tw.tw_mday = CVT1OR2;
249 }
250 gotdate++;
251 }
252 {D}{w}(-)?{w}{MONTH}{w}(-)?{w}{D}?{d}{d}({W}at)?{w} {
253 tw.tw_mday = CVT1OR2;
254 while ( !isalpha(*cp++) )
255 ;
256 SETMONTH;
257 for (i = 0; isdigit(*cp); )
258 i = i*10 + (*cp++ - '0');
259 tw.tw_year = i;
260 #ifdef FIX_NON_Y2K_COMPLIANT_MUA_DATES
261 /* handle broken mua's that don't add
262 1900, or just use the last two
263 digits. Assume no email before
264 1972. */
265 if (tw.tw_year < 72)
266 tw.tw_year += 100;
267 if (tw.tw_year < 1900)
268 tw.tw_year += 1900;
269 #endif /* FIX_NON_Y2K_COMPLIANT_MUA_DATES */
270 }
271 {D}"-"?{MONTH}({W}at)?{w} {
272 tw.tw_mday = CVT1OR2;
273 while ( ! isalpha( *cp++ ) )
274 ;
275 SETMONTH;
276 }
277 {MONTH}{W}{D}","{W}{D}?{d}{d}{w} {
278 cp++;
279 SETMONTH;
280 tw.tw_mday = CVT1OR2;
281 SKIPD;
282 for (i = 0; isdigit(*cp); )
283 i = i*10 + (*cp++ - '0');
284 tw.tw_year = i;
285 }
286 {MONTH}{W}{D}{w} {
287 cp++;
288 SETMONTH;
289 tw.tw_mday = CVT1OR2;
290 }
291
292 {D}:{D}:{D}{W}19[6-9]{d} { /* hack: ctime w/o TZ */
293 tw.tw_hour = CVT1OR2; cp++;
294 tw.tw_min = CVT1OR2; cp++;
295 tw.tw_sec = CVT1OR2;
296 SKIPD;
297 tw.tw_year = CVT4; cp+=4;
298 }
299 {D}:{D}:{D}{w} {
300 tw.tw_hour = CVT1OR2; cp++;
301 tw.tw_min = CVT1OR2; cp++;
302 tw.tw_sec = CVT1OR2;
303 BEGIN Z;
304 }
305 {D}:{D}{w} {
306 tw.tw_hour = CVT1OR2; cp++;
307 tw.tw_min = CVT1OR2;
308 BEGIN Z;
309 }
310 {D}:{D}{w}am{w} {
311 tw.tw_hour = CVT1OR2; cp++;
312 if (tw.tw_hour == 12)
313 tw.tw_hour = 0;
314 tw.tw_min = CVT1OR2;
315 BEGIN Z;
316 }
317 {D}:{D}:{D}{w}am{w} {
318 tw.tw_hour = CVT1OR2; cp++;
319 if (tw.tw_hour == 12)
320 tw.tw_hour = 0;
321 tw.tw_min = CVT1OR2; cp++;
322 tw.tw_sec = CVT1OR2;
323 BEGIN Z;
324 }
325 {D}:{D}{w}pm{w} {
326 tw.tw_hour = CVT1OR2; cp++;
327 if (tw.tw_hour != 12)
328 tw.tw_hour += 12;
329 tw.tw_min = CVT1OR2;
330 BEGIN Z;
331 }
332 {D}:{D}:{D}{w}pm{w} {
333 tw.tw_hour = CVT1OR2; cp++;
334 if (tw.tw_hour != 12)
335 tw.tw_hour += 12;
336 tw.tw_min = CVT1OR2; cp++;
337 tw.tw_sec = CVT1OR2;
338 BEGIN Z;
339 }
340 [0-2]{d}{d}{d}{d}{d}{w} {
341 tw.tw_hour = CVT2; cp+=2;
342 tw.tw_min = CVT2; cp+=2;
343 tw.tw_sec = CVT2; cp+=2;
344 BEGIN Z;
345 }
346 19[6-9]{d}{w} {
347 /*
348 * Luckly, 4 digit times in the range
349 * 1960-1999 aren't legal as hour
350 * and minutes.
351 */
352 tw.tw_year = CVT4; cp+=4;
353 }
354 [0-2]{d}{d}{d}{w} {
355 if (tw.tw_hour || tw.tw_min
356 || tw.tw_sec) {
357 tw.tw_year = CVT4; cp+=4;
358 tw.tw_zone = 0;
359 } else {
360 tw.tw_hour = CVT2; cp+=2;
361 tw.tw_min = CVT2; cp+=2;
362 BEGIN Z;
363 }
364 }
365 <Z>"-"?ut ZONE(0 * 60);
366 <Z>"-"?gmt ZONE(0 * 60);
367 <Z>"-"?jst ZONE(2 * 60);
368 <Z>"-"?jdt ZONED(2 * 60);
369 <Z>"-"?est ZONE(-5 * 60);
370 <Z>"-"?edt ZONED(-5 * 60);
371 <Z>"-"?cst ZONE(-6 * 60);
372 <Z>"-"?cdt ZONED(-6 * 60);
373 <Z>"-"?mst ZONE(-7 * 60);
374 <Z>"-"?mdt ZONED(-7 * 60);
375 <Z>"-"?pst ZONE(-8 * 60);
376 <Z>"-"?pdt ZONED(-8 * 60);
377 <Z>"-"?nst ZONE(-(3 * 60 + 30));
378 <Z>"-"?ast ZONE(-4 * 60);
379 <Z>"-"?adt ZONED(-4 * 60);
380 <Z>"-"?yst ZONE(-9 * 60);
381 <Z>"-"?ydt ZONED(-9 * 60);
382 <Z>"-"?hst ZONE(-10 * 60);
383 <Z>"-"?hdt ZONED(-10 * 60);
384 <Z>"-"?bst ZONED(-1 * 60);
385 <Z>[a-i] {
386 tw.tw_zone = 60 * (('a'-1) - LC(*cp));
387 EXPZONE;
388 }
389 <Z>[k-m] {
390 tw.tw_zone = 60 * ('a' - LC(*cp));
391 EXPZONE;
392 }
393 <Z>[n-y] {
394 tw.tw_zone = 60 * (LC(*cp) - 'm');
395 EXPZONE;
396 }
397 <Z>"+"[0-1]{d}{d}{d} {
398 cp++;
399 tw.tw_zone = ((cp[0] * 10 + cp[1])
400 -('0' * 10 + '0'))*60
401 +((cp[2] * 10 + cp[3])
402 -('0' * 10 + '0'));
403 EXPZONE;
404 #ifdef DSTXXX
405 zonehack (&tw);
406 #endif /* DSTXXX */
407 cp += 4;
408 }
409 <Z>"-"[0-1]{d}{d}{d} {
410 cp++;
411 tw.tw_zone = (('0' * 10 + '0')
412 -(cp[0] * 10 + cp[1]))*60
413 +(('0' * 10 + '0')
414 -(cp[2] * 10 + cp[3]));
415 EXPZONE;
416 #ifdef DSTXXX
417 zonehack (&tw);
418 #endif /* DSTXXX */
419 cp += 4;
420 }
421 <Z>{W}{d}{d}{d}{d} {
422 SKIPD;
423 tw.tw_year = CVT4; cp+=4;
424 }
425 \n |
426 {W} ;
427 %%