]> diplodocus.org Git - nmh/blob - sbr/dtimep.lex
4f019808c42d844a1643e0856c56c1b493a7170e
[nmh] / sbr / dtimep.lex
1 %e 2000
2 %p 5000
3 %n 1000
4 %a 4000
5 %{
6 #include <h/nmh.h>
7 #include <h/tws.h>
8
9 /* Since we're looking at a string at a time, don't worry about
10 * wrapping to the next buffer.
11 */
12 #define yywrap() 1
13 #define YY_SKIP_YYWRAP
14
15 #define YY_NO_UNPUT
16
17 /* This is the tricky thing that makes this function cool. We
18 * replace the traditional int yylex(void) declaration with our
19 * dparsetime() declaration, essentially piggy-backing off the
20 * utility of the yylex() function and adding what we need to make
21 * the parsing function useful to us.
22 */
23 #define YY_DECL struct tws *dparsetime(char *lexstr)
24
25 /* yyerminate() is called after the input string is matched to
26 * completion (actually, when the lexer reaches an EOF). The only
27 * thing that really needs to be in this macro function is the
28 * return call, which must be substituted inline into dparsetime.
29 */
30
31 #define yyterminate() (void)yy_delete_buffer(lexhandle); \
32 if(!(tw.tw_flags & TW_SUCC)) { \
33 return (struct tws *)NULL; \
34 } \
35 if(tw.tw_year < 1960) \
36 tw.tw_year += 1900; \
37 if(tw.tw_year < 1960) \
38 tw.tw_year += 100; \
39 return(&tw)
40
41 /*
42 * Patchable flag that says how to interpret NN/NN/NN dates. When
43 * true, we do it European style: DD/MM/YY. When false, we do it
44 * American style: MM/DD/YY. Of course, these are all non-RFC822
45 * compliant.
46 */
47 int europeandate = 0;
48
49 /*
50 * Table to convert month names to numeric month. We use the
51 * fact that the low order 5 bits of the sum of the 2nd & 3rd
52 * characters of the name is a hash with no collisions for the 12
53 * valid month names. (The mask to 5 bits maps any combination of
54 * upper and lower case into the same hash value).
55 */
56 static int month_map[] = {
57 0,
58 6, /* 1 - Jul */
59 3, /* 2 - Apr */
60 5, /* 3 - Jun */
61 0,
62 10, /* 5 - Nov */
63 0,
64 1, /* 7 - Feb */
65 11, /* 8 - Dec */
66 0,
67 0,
68 0,
69 0,
70 0,
71 0,
72 0, /*15 - Jan */
73 0,
74 0,
75 0,
76 2, /*19 - Mar */
77 0,
78 8, /*21 - Sep */
79 0,
80 9, /*23 - Oct */
81 0,
82 0,
83 4, /*26 - May */
84 0,
85 7 /*28 - Aug */
86 };
87
88 /*
89 * Same trick for day-of-week using the hash function
90 * (c1 & 7) + (c2 & 4)
91 */
92 static int day_map[] = {
93 0,
94 0,
95 0,
96 6, /* 3 - Sat */
97 4, /* 4 - Thu */
98 0,
99 5, /* 6 - Fri */
100 0, /* 7 - Sun */
101 2, /* 8 - Tue */
102 1 /* 9 - Mon */,
103 0,
104 3 /*11 - Wed */
105 };
106
107 /* The SET* macros will parse for the appropriate field, and leave the
108 * cp pointer at the first character after the desired field. Be
109 * careful with variable-length fields or alpha-num mixes.
110
111 * The SKIP* macros skip over characters of a particular class and
112 * leave cp at the position of the first character that doesn't match
113 * that class. Correspondingly, SKIPTO* skips until it reaches a
114 * character of a particular class.
115 */
116
117 #define INIT() { cp = yytext;}
118 #define SETWDAY() { cp++; \
119 tw.tw_wday= day_map[(cp[0] & 7) + (cp[1] & 4)]; \
120 tw.tw_flags &= ~TW_SDAY; tw.tw_flags |= TW_SEXP; \
121 SKIPA(); }
122 #define SETMON() { cp++; \
123 tw.tw_mon = month_map[(cp[0] + cp[1]) & 0x1f]; \
124 SKIPA(); }
125 #define SETMON_NUM() { tw.tw_mon = atoi(cp)-1; \
126 SKIPD(); }
127 #define SETYEAR() { tw.tw_year = atoi(cp); \
128 SKIPD(); }
129 #define SETDAY() { tw.tw_mday = atoi(cp); \
130 tw.tw_flags |= TW_YES; \
131 SKIPD(); }
132 #define SETTIME() { tw.tw_hour = atoi(cp); \
133 cp += 2; \
134 SKIPTOD(); \
135 tw.tw_min = atoi(cp); \
136 cp += 2; \
137 if(*cp == ':') { \
138 tw.tw_sec = atoi(++cp); SKIPD(); } }
139 #define SETZONE(x) { tw.tw_zone = ((x)/100)*60+(x)%100; \
140 tw.tw_flags |= TW_SZEXP; \
141 SKIPD(); }
142 #define SETDST() { tw.tw_flags |= TW_DST; }
143 #define SKIPD() { while ( isdigit(*cp++) ) ; \
144 --cp; }
145 #define SKIPTOD() { while ( !isdigit(*cp++) ) ; \
146 --cp; }
147 #define SKIPA() { while ( isalpha(*cp++) ) ; \
148 --cp; }
149 #define SKIPTOA() { while ( !isalpha(*cp++) ) ; \
150 --cp; }
151 #define SKIPSP() { while ( isspace(*cp++) ) ; \
152 --cp; }
153 #define SKIPTOSP() { while ( !isspace(*cp++) ) ; \
154 --cp; }
155 %}
156
157 sun ([Ss]un(day)?)
158 mon ([Mm]on(day)?)
159 tue ([Tt]ue(sday)?)
160 wed ([Ww]ed(nesday)?)
161 thu ([Tt]hu(rsday)?)
162 fri ([Ff]ri(day)?)
163 sat ([Ss]at(urday)?)
164
165 DAY ({sun}|{mon}|{tue}|{wed}|{thu}|{fri}|{sat})
166
167 jan ([Jj]an(uary)?)
168 feb ([Ff]eb(ruary)?)
169 mar ([Mm]ar(ch)?)
170 apr ([Aa]pr(il)?)
171 may ([Mm]ay)
172 jun ([Jj]un(e)?)
173 jul ([Jj]ul(y)?)
174 aug ([Aa]ug(ust)?)
175 sep ([Ss]ep(tember)?)
176 oct ([Oo]ct(ober)?)
177 nov ([Nn]ov(ember)?)
178 dec ([Dd]ec(ember)?)
179
180 MONTH ({jan}|{feb}|{mar}|{apr}|{may}|{jun}|{jul}|{aug}|{sep}|{oct}|{nov}|{dec})
181
182 TIME ({D}:{d}{d}(:{d}{d})?)
183
184 /* The year can either be 2 digits, or 4. However, after
185 Y2K, we found that some MUA were reporting the year 100, hence
186 the middle term here. yyterminate() resolves the actual
187 issues with 2-digit years.
188 */
189
190 YEAR (({d}{d})|(1{d}{d})|({d}{4}))
191
192 w ([ \t]*)
193 W ([ \t]+)
194 D ([0-9]?[0-9])
195 d [0-9]
196
197 %%
198 %{
199 /* This section begins the definition of dparsetime().
200 Put here any local variable definitions and initializations */
201
202 YY_BUFFER_STATE lexhandle;
203
204 register char *cp;
205 static struct tws tw;
206
207 memset(&tw,0,sizeof(struct tws));
208
209 lexhandle = yy_scan_string(lexstr);
210 %}
211
212 {DAY}","?{W}{MONTH}{W}{D}{W}{TIME}{W}{YEAR} {
213 INIT();
214 SETWDAY();
215 SKIPTOA();
216 SETMON();
217 SKIPTOD();
218 SETDAY();
219 SKIPTOD();
220 SETTIME();
221 SKIPTOD();
222 SETYEAR();
223 }
224
225 {DAY}","?{W}{D}{W}{MONTH}{W}{YEAR}{W}{TIME} {
226 INIT();
227 SETWDAY();
228 SKIPTOD();
229 SETDAY();
230 SKIPTOA();
231 SETMON();
232 SKIPTOD();
233 SETYEAR();
234 SKIPTOD();
235 SETTIME();
236 }
237 {D}{W}{MONTH}{W}{YEAR}{W}{TIME} {
238 INIT();
239 SETDAY();
240 SKIPTOA();
241 SETMON();
242 SKIPTOD();
243 SETYEAR();
244 SKIPTOD();
245 SETTIME();
246 }
247 {DAY}","?{W}{MONTH}{W}{D}","?{W}{YEAR}","?{W}{TIME} {
248 INIT();
249 SETWDAY();
250 SKIPTOA();
251 SETMON();
252 SKIPTOD();
253 SETDAY();
254 SKIPTOD();
255 SETYEAR();
256 SKIPTOD();
257 SETTIME();
258 }
259 {DAY}","?{W}{MONTH}{W}{D}","?{W}{YEAR} {
260 INIT();
261 SETWDAY();
262 SKIPTOA();
263 SETMON();
264 SKIPTOD();
265 SETDAY();
266 SKIPTOD();
267 SETYEAR();
268 }
269 {MONTH}{W}{D}","?{W}{YEAR}","?{W}{DAY} {
270 INIT();
271 SETMON();
272 SKIPTOD();
273 SETDAY();
274 SKIPTOD();
275 SETYEAR();
276 SKIPTOA();
277 SETWDAY();
278 }
279 {MONTH}{W}{D}","?{W}{YEAR} {
280 INIT();
281 SETMON();
282 SKIPTOD();
283 SETDAY();
284 SKIPTOD();
285 SETYEAR();
286 }
287 {D}("-"|"/"){D}("-"|"/"){YEAR}{W}{TIME} {
288 INIT();
289 if(europeandate) {
290 /* DD/MM/YY */
291 SETDAY();
292 SKIPTOD();
293 SETMON_NUM();
294 } else {
295 /* MM/DD/YY */
296 SETMON_NUM();
297 SKIPTOD();
298 SETDAY();
299 }
300 SKIPTOD();
301 SETYEAR();
302 SKIPTOD();
303 SETTIME();
304 }
305 {D}("-"|"/"){D}("-"|"/"){YEAR} {
306 INIT();
307 if(europeandate) {
308 /* DD/MM/YY */
309 SETDAY();
310 SKIPTOD();
311 SETMON_NUM();
312 } else {
313 /* MM/DD/YY */
314 SETMON_NUM();
315 SKIPTOD();
316 SETDAY();
317 }
318 SKIPTOD();
319 SETYEAR();
320 }
321
322 "[Aa][Mm]"
323 "[Pp][Mm]" tw.tw_hour += 12;
324
325 "+"{D}{d}{d} {
326 INIT();
327 SKIPTOD();
328 SETZONE(atoi(cp));
329 }
330 "-"{D}{d}{d} {
331 INIT();
332 SKIPTOD();
333 SETZONE(-atoi(cp));
334 }
335 "-"?("ut"|"UT") INIT(); SETZONE(0);
336 "-"?("gmt"|"GMT") INIT(); SETZONE(0);
337 "-"?("jst"|"JST") INIT(); SETZONE(200);
338 "-"?("jdt"|"JDT") INIT(); SETDST(); SETZONE(2);
339 "-"?("est"|"EST") INIT(); SETZONE(-500);
340 "-"?("edt"|"EDT") INIT(); SETDST(); SETZONE(-500);
341 "-"?("cst"|"CST") INIT(); SETZONE(-600);
342 "-"?("cdt"|"CDT") INIT(); SETDST(); SETZONE(-600);
343 "-"?("mst"|"MST") INIT(); SETZONE(-700);
344 "-"?("mdt"|"MDT") INIT(); SETDST(); SETZONE(-700);
345 "-"?("pst"|"PST") INIT(); SETZONE(-800);
346 "-"?("pdt"|"PDT") INIT(); SETDST(); SETZONE(-800);
347 "-"?("nst"|"NST") INIT(); SETZONE(-330);
348 "-"?("ast"|"AST") INIT(); SETZONE(-400);
349 "-"?("adt"|"ADT") INIT(); SETDST(); SETZONE(-400);
350 "-"?("yst"|"YST") INIT(); SETZONE(-900);
351 "-"?("ydt"|"YDT") INIT(); SETDST(); SETZONE(-900);
352 "-"?("hst"|"HST") INIT(); SETZONE(-1000);
353 "-"?("hdt"|"HDT") INIT(); SETDST(); SETZONE(-1000);
354 "-"?("bst"|"BST") INIT(); SETDST(); SETZONE(-100);
355 [a-iA-I] {
356 INIT();
357 SETZONE(100*(('a'-1) - tolower(*cp)));
358 }
359 [k-mK-M] {
360 INIT();
361 SETZONE(100*('a' - tolower(*cp)));
362 }
363 [n-yN-Y] {
364 INIT();
365 SETZONE(100*(tolower(*cp) - 'm'));
366 }
367 .|\n