467dc85d37d520e2858932942676d35a1452b3d2
[mmh] / 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                                         }
261 {D}"-"?{MONTH}({W}at)?{w}               {
262                                         tw.tw_mday = CVT1OR2;
263                                         while ( ! isalpha( *cp++ ) )
264                                                 ;
265                                         SETMONTH;
266                                         }
267 {MONTH}{W}{D}","{W}{D}?{d}{d}{w}        {
268                                         cp++;
269                                         SETMONTH;
270                                         tw.tw_mday = CVT1OR2;
271                                         SKIPD;
272                                         for (i = 0; isdigit(*cp); )
273                                                 i = i*10 + (*cp++ - '0');
274                                         tw.tw_year = i;
275                                         }
276 {MONTH}{W}{D}{w}                        {
277                                         cp++;
278                                         SETMONTH;
279                                         tw.tw_mday = CVT1OR2;
280                                         }
281
282 {D}:{D}:{D}{W}19[6-9]{d}                {       /* hack: ctime w/o TZ */
283                                         tw.tw_hour = CVT1OR2; cp++;
284                                         tw.tw_min  = CVT1OR2; cp++;
285                                         tw.tw_sec  = CVT1OR2;
286                                         SKIPD;
287                                         tw.tw_year = CVT4; cp+=4;
288                                         }
289 {D}:{D}:{D}{w}                          {
290                                         tw.tw_hour = CVT1OR2; cp++;
291                                         tw.tw_min  = CVT1OR2; cp++;
292                                         tw.tw_sec  = CVT1OR2;
293                                         BEGIN Z;
294                                         }
295 {D}:{D}{w}                              {
296                                         tw.tw_hour = CVT1OR2; cp++;
297                                         tw.tw_min = CVT1OR2;
298                                         BEGIN Z;
299                                         }
300 {D}:{D}{w}am{w}                         {
301                                         tw.tw_hour = CVT1OR2; cp++;
302                                         if (tw.tw_hour == 12)
303                                                 tw.tw_hour = 0;
304                                         tw.tw_min  = CVT1OR2;
305                                         BEGIN Z;
306                                         }
307 {D}:{D}:{D}{w}am{w}                     {
308                                         tw.tw_hour = CVT1OR2; cp++;
309                                         if (tw.tw_hour == 12)
310                                                 tw.tw_hour = 0;
311                                         tw.tw_min  = CVT1OR2; cp++;
312                                         tw.tw_sec  = CVT1OR2;
313                                         BEGIN Z;
314                                         }
315 {D}:{D}{w}pm{w}                         {
316                                         tw.tw_hour = CVT1OR2; cp++;
317                                         if (tw.tw_hour != 12)
318                                                 tw.tw_hour += 12;
319                                         tw.tw_min  = CVT1OR2;
320                                         BEGIN Z;
321                                         }
322 {D}:{D}:{D}{w}pm{w}                     {
323                                         tw.tw_hour = CVT1OR2; cp++;
324                                         if (tw.tw_hour != 12)
325                                                 tw.tw_hour += 12;
326                                         tw.tw_min  = CVT1OR2; cp++;
327                                         tw.tw_sec  = CVT1OR2;
328                                         BEGIN Z;
329                                         }
330 [0-2]{d}{d}{d}{d}{d}{w}                 {
331                                         tw.tw_hour = CVT2; cp+=2;
332                                         tw.tw_min  = CVT2; cp+=2;
333                                         tw.tw_sec  = CVT2; cp+=2;
334                                         BEGIN Z;
335                                         }
336 19[6-9]{d}{w}                           {
337                                         /*
338                                          * Luckly, 4 digit times in the range
339                                          * 1960-1999 aren't legal as hour
340                                          * and minutes.
341                                          */
342                                         tw.tw_year = CVT4; cp+=4;
343                                         }
344 [0-2]{d}{d}{d}{w}                       {
345                                         if (tw.tw_hour || tw.tw_min 
346                                                             || tw.tw_sec) {
347                                             tw.tw_year = CVT4; cp+=4;
348                                             tw.tw_zone = 0;
349                                         } else {
350                                             tw.tw_hour = CVT2; cp+=2;
351                                             tw.tw_min  = CVT2; cp+=2;
352                                             BEGIN Z;
353                                         }
354                                         }
355 <Z>"-"?ut                               ZONE(0 * 60);
356 <Z>"-"?gmt                              ZONE(0 * 60);
357 <Z>"-"?jst                              ZONE(2 * 60);
358 <Z>"-"?jdt                              ZONED(2 * 60);
359 <Z>"-"?est                              ZONE(-5 * 60);
360 <Z>"-"?edt                              ZONED(-5 * 60);
361 <Z>"-"?cst                              ZONE(-6 * 60);
362 <Z>"-"?cdt                              ZONED(-6 * 60);
363 <Z>"-"?mst                              ZONE(-7 * 60);
364 <Z>"-"?mdt                              ZONED(-7 * 60);
365 <Z>"-"?pst                              ZONE(-8 * 60);
366 <Z>"-"?pdt                              ZONED(-8 * 60);
367 <Z>"-"?nst                              ZONE(-(3 * 60 + 30));
368 <Z>"-"?ast                              ZONE(-4 * 60);
369 <Z>"-"?adt                              ZONED(-4 * 60);
370 <Z>"-"?yst                              ZONE(-9 * 60);
371 <Z>"-"?ydt                              ZONED(-9 * 60);
372 <Z>"-"?hst                              ZONE(-10 * 60);
373 <Z>"-"?hdt                              ZONED(-10 * 60);
374 <Z>"-"?bst                              ZONED(-1 * 60);
375 <Z>[a-i]                                {
376                                         tw.tw_zone = 60 * (('a'-1) - LC(*cp));
377                                         EXPZONE; 
378                                         }
379 <Z>[k-m]                                {
380                                         tw.tw_zone = 60 * ('a' - LC(*cp));
381                                         EXPZONE; 
382                                         }
383 <Z>[n-y]                                {
384                                         tw.tw_zone = 60 * (LC(*cp) - 'm');
385                                         EXPZONE; 
386                                         }
387 <Z>"+"[0-1]{d}{d}{d}                    {
388                                         cp++;
389                                         tw.tw_zone = ((cp[0] * 10 + cp[1])
390                                                      -('0' * 10   + '0'))*60
391                                                     +((cp[2] * 10 + cp[3])
392                                                      -('0' * 10   + '0'));
393                                         EXPZONE;
394 #ifdef  DSTXXX
395                                         zonehack (&tw);
396 #endif  /* DSTXXX */
397                                         cp += 4;
398                                         }
399 <Z>"-"[0-1]{d}{d}{d}                    {
400                                         cp++;
401                                         tw.tw_zone = (('0' * 10   + '0')
402                                                      -(cp[0] * 10 + cp[1]))*60
403                                                     +(('0' * 10   + '0')
404                                                      -(cp[2] * 10 + cp[3]));
405                                         EXPZONE;
406 #ifdef  DSTXXX
407                                         zonehack (&tw);
408 #endif  /* DSTXXX */
409                                         cp += 4;
410                                         }
411 <Z>{W}{d}{d}{d}{d}                      {
412                                         SKIPD;
413                                         tw.tw_year = CVT4; cp+=4;
414                                         }
415 \n      |
416 {W}     ;
417 %%