1*7f2fe78bSCy Schubert %{
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert ** Originally written by Steven M. Bellovin <smb@research.att.com> while
4*7f2fe78bSCy Schubert ** at the University of North Carolina at Chapel Hill. Later tweaked by
5*7f2fe78bSCy Schubert ** a couple of people on Usenet. Completely overhauled by Rich $alz
6*7f2fe78bSCy Schubert ** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
7*7f2fe78bSCy Schubert ** send any email to Rich.
8*7f2fe78bSCy Schubert **
9*7f2fe78bSCy Schubert ** This grammar has four shift/reduce conflicts.
10*7f2fe78bSCy Schubert **
11*7f2fe78bSCy Schubert ** This code is in the public domain and has no copyright.
12*7f2fe78bSCy Schubert */
13*7f2fe78bSCy Schubert /* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
14*7f2fe78bSCy Schubert /* SUPPRESS 288 on yyerrlab *//* Label unused */
15*7f2fe78bSCy Schubert
16*7f2fe78bSCy Schubert #include "autoconf.h"
17*7f2fe78bSCy Schubert #include <string.h>
18*7f2fe78bSCy Schubert
19*7f2fe78bSCy Schubert /* Since the code of getdate.y is not included in the Emacs executable
20*7f2fe78bSCy Schubert itself, there is no need to #define static in this file. Even if
21*7f2fe78bSCy Schubert the code were included in the Emacs executable, it probably
22*7f2fe78bSCy Schubert wouldn't do any harm to #undef it here; this will only cause
23*7f2fe78bSCy Schubert problems if we try to write to a static variable, which I don't
24*7f2fe78bSCy Schubert think this code needs to do. */
25*7f2fe78bSCy Schubert #ifdef emacs
26*7f2fe78bSCy Schubert #undef static
27*7f2fe78bSCy Schubert #endif
28*7f2fe78bSCy Schubert
29*7f2fe78bSCy Schubert /* The following block of alloca-related preprocessor directives is here
30*7f2fe78bSCy Schubert solely to allow compilation by non GNU-C compilers of the C parser
31*7f2fe78bSCy Schubert produced from this file by old versions of bison. Newer versions of
32*7f2fe78bSCy Schubert bison include a block similar to this one in bison.simple. */
33*7f2fe78bSCy Schubert
34*7f2fe78bSCy Schubert #ifdef __GNUC__
35*7f2fe78bSCy Schubert #undef alloca
36*7f2fe78bSCy Schubert #define alloca __builtin_alloca
37*7f2fe78bSCy Schubert #else
38*7f2fe78bSCy Schubert #ifdef HAVE_ALLOCA_H
39*7f2fe78bSCy Schubert #include <alloca.h>
40*7f2fe78bSCy Schubert #else
41*7f2fe78bSCy Schubert #ifdef _AIX /* for Bison */
42*7f2fe78bSCy Schubert #pragma alloca
43*7f2fe78bSCy Schubert #else
44*7f2fe78bSCy Schubert void *alloca ();
45*7f2fe78bSCy Schubert #endif
46*7f2fe78bSCy Schubert #endif
47*7f2fe78bSCy Schubert #endif
48*7f2fe78bSCy Schubert
49*7f2fe78bSCy Schubert #include <stdio.h>
50*7f2fe78bSCy Schubert #include <ctype.h>
51*7f2fe78bSCy Schubert
52*7f2fe78bSCy Schubert #if defined(HAVE_STDLIB_H)
53*7f2fe78bSCy Schubert #include <stdlib.h>
54*7f2fe78bSCy Schubert #endif
55*7f2fe78bSCy Schubert
56*7f2fe78bSCy Schubert /* The code at the top of get_date which figures out the offset of the
57*7f2fe78bSCy Schubert current time zone checks various CPP symbols to see if special
58*7f2fe78bSCy Schubert tricks are need, but defaults to using the gettimeofday system call.
59*7f2fe78bSCy Schubert Include <sys/time.h> if that will be used. */
60*7f2fe78bSCy Schubert
61*7f2fe78bSCy Schubert #if defined(vms)
62*7f2fe78bSCy Schubert
63*7f2fe78bSCy Schubert #include <types.h>
64*7f2fe78bSCy Schubert #include <time.h>
65*7f2fe78bSCy Schubert
66*7f2fe78bSCy Schubert #else
67*7f2fe78bSCy Schubert
68*7f2fe78bSCy Schubert #include <sys/types.h>
69*7f2fe78bSCy Schubert
70*7f2fe78bSCy Schubert #ifdef HAVE_SYS_TIME_H
71*7f2fe78bSCy Schubert #include <sys/time.h>
72*7f2fe78bSCy Schubert #endif
73*7f2fe78bSCy Schubert #include <time.h>
74*7f2fe78bSCy Schubert
75*7f2fe78bSCy Schubert #ifdef timezone
76*7f2fe78bSCy Schubert #undef timezone /* needed for sgi */
77*7f2fe78bSCy Schubert #endif
78*7f2fe78bSCy Schubert
79*7f2fe78bSCy Schubert /*
80*7f2fe78bSCy Schubert ** We use the obsolete `struct my_timeb' as part of our interface!
81*7f2fe78bSCy Schubert ** Since the system doesn't have it, we define it here;
82*7f2fe78bSCy Schubert ** our callers must do likewise.
83*7f2fe78bSCy Schubert */
84*7f2fe78bSCy Schubert struct my_timeb {
85*7f2fe78bSCy Schubert time_t time; /* Seconds since the epoch */
86*7f2fe78bSCy Schubert unsigned short millitm; /* Field not used */
87*7f2fe78bSCy Schubert short timezone; /* Minutes west of GMT */
88*7f2fe78bSCy Schubert short dstflag; /* Field not used */
89*7f2fe78bSCy Schubert };
90*7f2fe78bSCy Schubert #endif /* defined(vms) */
91*7f2fe78bSCy Schubert
92*7f2fe78bSCy Schubert #if defined (STDC_HEADERS) || defined (USG)
93*7f2fe78bSCy Schubert #include <string.h>
94*7f2fe78bSCy Schubert #endif
95*7f2fe78bSCy Schubert
96*7f2fe78bSCy Schubert /* Some old versions of bison generate parsers that use bcopy.
97*7f2fe78bSCy Schubert That loses on systems that don't provide the function, so we have
98*7f2fe78bSCy Schubert to redefine it here. */
99*7f2fe78bSCy Schubert #ifndef bcopy
100*7f2fe78bSCy Schubert #define bcopy(from, to, len) memcpy ((to), (from), (len))
101*7f2fe78bSCy Schubert #endif
102*7f2fe78bSCy Schubert
103*7f2fe78bSCy Schubert extern struct tm *gmtime();
104*7f2fe78bSCy Schubert extern struct tm *localtime();
105*7f2fe78bSCy Schubert
106*7f2fe78bSCy Schubert #define yyparse getdate_yyparse
107*7f2fe78bSCy Schubert #define yylex getdate_yylex
108*7f2fe78bSCy Schubert #define yyerror getdate_yyerror
109*7f2fe78bSCy Schubert
110*7f2fe78bSCy Schubert static int getdate_yylex (void);
111*7f2fe78bSCy Schubert static int getdate_yyerror (char *);
112*7f2fe78bSCy Schubert
113*7f2fe78bSCy Schubert
114*7f2fe78bSCy Schubert #define EPOCH 1970
115*7f2fe78bSCy Schubert #define EPOCH_END 2106 /* assumes unsigned 32-bit range */
116*7f2fe78bSCy Schubert #define HOUR(x) ((time_t)(x) * 60)
117*7f2fe78bSCy Schubert #define SECSPERDAY (24L * 60L * 60L)
118*7f2fe78bSCy Schubert
119*7f2fe78bSCy Schubert
120*7f2fe78bSCy Schubert /*
121*7f2fe78bSCy Schubert ** An entry in the lexical lookup table.
122*7f2fe78bSCy Schubert */
123*7f2fe78bSCy Schubert typedef struct _TABLE {
124*7f2fe78bSCy Schubert char *name;
125*7f2fe78bSCy Schubert int type;
126*7f2fe78bSCy Schubert time_t value;
127*7f2fe78bSCy Schubert } TABLE;
128*7f2fe78bSCy Schubert
129*7f2fe78bSCy Schubert
130*7f2fe78bSCy Schubert /*
131*7f2fe78bSCy Schubert ** Daylight-savings mode: on, off, or not yet known.
132*7f2fe78bSCy Schubert */
133*7f2fe78bSCy Schubert typedef enum _DSTMODE {
134*7f2fe78bSCy Schubert DSTon, DSToff, DSTmaybe
135*7f2fe78bSCy Schubert } DSTMODE;
136*7f2fe78bSCy Schubert
137*7f2fe78bSCy Schubert /*
138*7f2fe78bSCy Schubert ** Meridian: am, pm, or 24-hour style.
139*7f2fe78bSCy Schubert */
140*7f2fe78bSCy Schubert typedef enum _MERIDIAN {
141*7f2fe78bSCy Schubert MERam, MERpm, MER24
142*7f2fe78bSCy Schubert } MERIDIAN;
143*7f2fe78bSCy Schubert
144*7f2fe78bSCy Schubert
145*7f2fe78bSCy Schubert /*
146*7f2fe78bSCy Schubert ** Global variables. We could get rid of most of these by using a good
147*7f2fe78bSCy Schubert ** union as the yacc stack. (This routine was originally written before
148*7f2fe78bSCy Schubert ** yacc had the %union construct.) Maybe someday; right now we only use
149*7f2fe78bSCy Schubert ** the %union very rarely.
150*7f2fe78bSCy Schubert */
151*7f2fe78bSCy Schubert static char *yyInput;
152*7f2fe78bSCy Schubert static DSTMODE yyDSTmode;
153*7f2fe78bSCy Schubert static time_t yyDayOrdinal;
154*7f2fe78bSCy Schubert static time_t yyDayNumber;
155*7f2fe78bSCy Schubert static int yyHaveDate;
156*7f2fe78bSCy Schubert static int yyHaveDay;
157*7f2fe78bSCy Schubert static int yyHaveRel;
158*7f2fe78bSCy Schubert static int yyHaveTime;
159*7f2fe78bSCy Schubert static int yyHaveZone;
160*7f2fe78bSCy Schubert static time_t yyTimezone;
161*7f2fe78bSCy Schubert static time_t yyDay;
162*7f2fe78bSCy Schubert static time_t yyHour;
163*7f2fe78bSCy Schubert static time_t yyMinutes;
164*7f2fe78bSCy Schubert static time_t yyMonth;
165*7f2fe78bSCy Schubert static time_t yySeconds;
166*7f2fe78bSCy Schubert static time_t yyYear;
167*7f2fe78bSCy Schubert static MERIDIAN yyMeridian;
168*7f2fe78bSCy Schubert static time_t yyRelMonth;
169*7f2fe78bSCy Schubert static time_t yyRelSeconds;
170*7f2fe78bSCy Schubert
171*7f2fe78bSCy Schubert %}
172*7f2fe78bSCy Schubert
173*7f2fe78bSCy Schubert /* This would mute the shift/reduce warnings as per header comment; however,
174*7f2fe78bSCy Schubert * it relies on bison extensions. */
175*7f2fe78bSCy Schubert /* %expect 4 */
176*7f2fe78bSCy Schubert
177*7f2fe78bSCy Schubert %union {
178*7f2fe78bSCy Schubert time_t Number;
179*7f2fe78bSCy Schubert enum _MERIDIAN Meridian;
180*7f2fe78bSCy Schubert }
181*7f2fe78bSCy Schubert
182*7f2fe78bSCy Schubert %token tAGO tID tDST tNEVER
183*7f2fe78bSCy Schubert %token <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
184*7f2fe78bSCy Schubert %token <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
185*7f2fe78bSCy Schubert %token <Meridian> tMERIDIAN
186*7f2fe78bSCy Schubert %type <Meridian> o_merid
187*7f2fe78bSCy Schubert
188*7f2fe78bSCy Schubert %%
189*7f2fe78bSCy Schubert
190*7f2fe78bSCy Schubert spec : /* NULL */
191*7f2fe78bSCy Schubert | spec item
192*7f2fe78bSCy Schubert | tNEVER {
193*7f2fe78bSCy Schubert yyYear = 1970;
194*7f2fe78bSCy Schubert yyMonth = 1;
195*7f2fe78bSCy Schubert yyDay = 1;
196*7f2fe78bSCy Schubert yyHour = yyMinutes = yySeconds = 0;
197*7f2fe78bSCy Schubert yyDSTmode = DSToff;
198*7f2fe78bSCy Schubert yyTimezone = 0; /* gmt */
199*7f2fe78bSCy Schubert yyHaveDate++;
200*7f2fe78bSCy Schubert }
201*7f2fe78bSCy Schubert ;
202*7f2fe78bSCy Schubert
203*7f2fe78bSCy Schubert item : time {
204*7f2fe78bSCy Schubert yyHaveTime++;
205*7f2fe78bSCy Schubert }
206*7f2fe78bSCy Schubert | zone {
207*7f2fe78bSCy Schubert yyHaveZone++;
208*7f2fe78bSCy Schubert }
209*7f2fe78bSCy Schubert | date {
210*7f2fe78bSCy Schubert yyHaveDate++;
211*7f2fe78bSCy Schubert }
212*7f2fe78bSCy Schubert | day {
213*7f2fe78bSCy Schubert yyHaveDay++;
214*7f2fe78bSCy Schubert }
215*7f2fe78bSCy Schubert | rel {
216*7f2fe78bSCy Schubert yyHaveRel++;
217*7f2fe78bSCy Schubert }
218*7f2fe78bSCy Schubert ;
219*7f2fe78bSCy Schubert
220*7f2fe78bSCy Schubert time : tUNUMBER tMERIDIAN {
221*7f2fe78bSCy Schubert yyHour = $1;
222*7f2fe78bSCy Schubert yyMinutes = 0;
223*7f2fe78bSCy Schubert yySeconds = 0;
224*7f2fe78bSCy Schubert yyMeridian = $2;
225*7f2fe78bSCy Schubert }
226*7f2fe78bSCy Schubert | tUNUMBER ':' tUNUMBER o_merid {
227*7f2fe78bSCy Schubert yyHour = $1;
228*7f2fe78bSCy Schubert yyMinutes = $3;
229*7f2fe78bSCy Schubert yySeconds = 0;
230*7f2fe78bSCy Schubert yyMeridian = $4;
231*7f2fe78bSCy Schubert }
232*7f2fe78bSCy Schubert | tUNUMBER ':' tUNUMBER tSNUMBER {
233*7f2fe78bSCy Schubert yyHour = $1;
234*7f2fe78bSCy Schubert yyMinutes = $3;
235*7f2fe78bSCy Schubert yyMeridian = MER24;
236*7f2fe78bSCy Schubert yyDSTmode = DSToff;
237*7f2fe78bSCy Schubert yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
238*7f2fe78bSCy Schubert }
239*7f2fe78bSCy Schubert | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
240*7f2fe78bSCy Schubert yyHour = $1;
241*7f2fe78bSCy Schubert yyMinutes = $3;
242*7f2fe78bSCy Schubert yySeconds = $5;
243*7f2fe78bSCy Schubert yyMeridian = $6;
244*7f2fe78bSCy Schubert }
245*7f2fe78bSCy Schubert | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
246*7f2fe78bSCy Schubert yyHour = $1;
247*7f2fe78bSCy Schubert yyMinutes = $3;
248*7f2fe78bSCy Schubert yySeconds = $5;
249*7f2fe78bSCy Schubert yyMeridian = MER24;
250*7f2fe78bSCy Schubert yyDSTmode = DSToff;
251*7f2fe78bSCy Schubert yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
252*7f2fe78bSCy Schubert }
253*7f2fe78bSCy Schubert ;
254*7f2fe78bSCy Schubert
255*7f2fe78bSCy Schubert zone : tZONE {
256*7f2fe78bSCy Schubert yyTimezone = $1;
257*7f2fe78bSCy Schubert yyDSTmode = DSToff;
258*7f2fe78bSCy Schubert }
259*7f2fe78bSCy Schubert | tDAYZONE {
260*7f2fe78bSCy Schubert yyTimezone = $1;
261*7f2fe78bSCy Schubert yyDSTmode = DSTon;
262*7f2fe78bSCy Schubert }
263*7f2fe78bSCy Schubert |
264*7f2fe78bSCy Schubert tZONE tDST {
265*7f2fe78bSCy Schubert yyTimezone = $1;
266*7f2fe78bSCy Schubert yyDSTmode = DSTon;
267*7f2fe78bSCy Schubert }
268*7f2fe78bSCy Schubert ;
269*7f2fe78bSCy Schubert
270*7f2fe78bSCy Schubert day : tDAY {
271*7f2fe78bSCy Schubert yyDayOrdinal = 1;
272*7f2fe78bSCy Schubert yyDayNumber = $1;
273*7f2fe78bSCy Schubert }
274*7f2fe78bSCy Schubert | tDAY ',' {
275*7f2fe78bSCy Schubert yyDayOrdinal = 1;
276*7f2fe78bSCy Schubert yyDayNumber = $1;
277*7f2fe78bSCy Schubert }
278*7f2fe78bSCy Schubert | tUNUMBER tDAY {
279*7f2fe78bSCy Schubert yyDayOrdinal = $1;
280*7f2fe78bSCy Schubert yyDayNumber = $2;
281*7f2fe78bSCy Schubert }
282*7f2fe78bSCy Schubert ;
283*7f2fe78bSCy Schubert
284*7f2fe78bSCy Schubert date : tUNUMBER '/' tUNUMBER {
285*7f2fe78bSCy Schubert yyMonth = $1;
286*7f2fe78bSCy Schubert yyDay = $3;
287*7f2fe78bSCy Schubert }
288*7f2fe78bSCy Schubert | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
289*7f2fe78bSCy Schubert yyMonth = $1;
290*7f2fe78bSCy Schubert yyDay = $3;
291*7f2fe78bSCy Schubert yyYear = $5;
292*7f2fe78bSCy Schubert }
293*7f2fe78bSCy Schubert | tUNUMBER tSNUMBER tSNUMBER {
294*7f2fe78bSCy Schubert /* ISO 8601 format. yyyy-mm-dd. */
295*7f2fe78bSCy Schubert yyYear = $1;
296*7f2fe78bSCy Schubert yyMonth = -$2;
297*7f2fe78bSCy Schubert yyDay = -$3;
298*7f2fe78bSCy Schubert }
299*7f2fe78bSCy Schubert | tUNUMBER tMONTH tSNUMBER {
300*7f2fe78bSCy Schubert /* e.g. 17-JUN-1992. */
301*7f2fe78bSCy Schubert yyDay = $1;
302*7f2fe78bSCy Schubert yyMonth = $2;
303*7f2fe78bSCy Schubert yyYear = -$3;
304*7f2fe78bSCy Schubert }
305*7f2fe78bSCy Schubert | tMONTH tUNUMBER {
306*7f2fe78bSCy Schubert yyMonth = $1;
307*7f2fe78bSCy Schubert yyDay = $2;
308*7f2fe78bSCy Schubert }
309*7f2fe78bSCy Schubert | tMONTH tUNUMBER ',' tUNUMBER {
310*7f2fe78bSCy Schubert yyMonth = $1;
311*7f2fe78bSCy Schubert yyDay = $2;
312*7f2fe78bSCy Schubert yyYear = $4;
313*7f2fe78bSCy Schubert }
314*7f2fe78bSCy Schubert | tUNUMBER tMONTH {
315*7f2fe78bSCy Schubert yyMonth = $2;
316*7f2fe78bSCy Schubert yyDay = $1;
317*7f2fe78bSCy Schubert }
318*7f2fe78bSCy Schubert | tUNUMBER tMONTH tUNUMBER {
319*7f2fe78bSCy Schubert yyMonth = $2;
320*7f2fe78bSCy Schubert yyDay = $1;
321*7f2fe78bSCy Schubert yyYear = $3;
322*7f2fe78bSCy Schubert }
323*7f2fe78bSCy Schubert ;
324*7f2fe78bSCy Schubert
325*7f2fe78bSCy Schubert rel : relunit tAGO {
326*7f2fe78bSCy Schubert yyRelSeconds = -yyRelSeconds;
327*7f2fe78bSCy Schubert yyRelMonth = -yyRelMonth;
328*7f2fe78bSCy Schubert }
329*7f2fe78bSCy Schubert | relunit
330*7f2fe78bSCy Schubert ;
331*7f2fe78bSCy Schubert
332*7f2fe78bSCy Schubert relunit : tUNUMBER tMINUTE_UNIT {
333*7f2fe78bSCy Schubert yyRelSeconds += $1 * $2 * 60L;
334*7f2fe78bSCy Schubert }
335*7f2fe78bSCy Schubert | tSNUMBER tMINUTE_UNIT {
336*7f2fe78bSCy Schubert yyRelSeconds += $1 * $2 * 60L;
337*7f2fe78bSCy Schubert }
338*7f2fe78bSCy Schubert | tMINUTE_UNIT {
339*7f2fe78bSCy Schubert yyRelSeconds += $1 * 60L;
340*7f2fe78bSCy Schubert }
341*7f2fe78bSCy Schubert | tSNUMBER tSEC_UNIT {
342*7f2fe78bSCy Schubert yyRelSeconds += $1;
343*7f2fe78bSCy Schubert }
344*7f2fe78bSCy Schubert | tUNUMBER tSEC_UNIT {
345*7f2fe78bSCy Schubert yyRelSeconds += $1;
346*7f2fe78bSCy Schubert }
347*7f2fe78bSCy Schubert | tSEC_UNIT {
348*7f2fe78bSCy Schubert yyRelSeconds++;
349*7f2fe78bSCy Schubert }
350*7f2fe78bSCy Schubert | tSNUMBER tMONTH_UNIT {
351*7f2fe78bSCy Schubert yyRelMonth += $1 * $2;
352*7f2fe78bSCy Schubert }
353*7f2fe78bSCy Schubert | tUNUMBER tMONTH_UNIT {
354*7f2fe78bSCy Schubert yyRelMonth += $1 * $2;
355*7f2fe78bSCy Schubert }
356*7f2fe78bSCy Schubert | tMONTH_UNIT {
357*7f2fe78bSCy Schubert yyRelMonth += $1;
358*7f2fe78bSCy Schubert }
359*7f2fe78bSCy Schubert ;
360*7f2fe78bSCy Schubert
361*7f2fe78bSCy Schubert o_merid : /* NULL */ {
362*7f2fe78bSCy Schubert $$ = MER24;
363*7f2fe78bSCy Schubert }
364*7f2fe78bSCy Schubert | tMERIDIAN {
365*7f2fe78bSCy Schubert $$ = $1;
366*7f2fe78bSCy Schubert }
367*7f2fe78bSCy Schubert ;
368*7f2fe78bSCy Schubert
369*7f2fe78bSCy Schubert %%
370*7f2fe78bSCy Schubert
371*7f2fe78bSCy Schubert /* Month and day table. */
372*7f2fe78bSCy Schubert static TABLE const MonthDayTable[] = {
373*7f2fe78bSCy Schubert { "january", tMONTH, 1 },
374*7f2fe78bSCy Schubert { "february", tMONTH, 2 },
375*7f2fe78bSCy Schubert { "march", tMONTH, 3 },
376*7f2fe78bSCy Schubert { "april", tMONTH, 4 },
377*7f2fe78bSCy Schubert { "may", tMONTH, 5 },
378*7f2fe78bSCy Schubert { "june", tMONTH, 6 },
379*7f2fe78bSCy Schubert { "july", tMONTH, 7 },
380*7f2fe78bSCy Schubert { "august", tMONTH, 8 },
381*7f2fe78bSCy Schubert { "september", tMONTH, 9 },
382*7f2fe78bSCy Schubert { "sept", tMONTH, 9 },
383*7f2fe78bSCy Schubert { "october", tMONTH, 10 },
384*7f2fe78bSCy Schubert { "november", tMONTH, 11 },
385*7f2fe78bSCy Schubert { "december", tMONTH, 12 },
386*7f2fe78bSCy Schubert { "sunday", tDAY, 0 },
387*7f2fe78bSCy Schubert { "monday", tDAY, 1 },
388*7f2fe78bSCy Schubert { "tuesday", tDAY, 2 },
389*7f2fe78bSCy Schubert { "tues", tDAY, 2 },
390*7f2fe78bSCy Schubert { "wednesday", tDAY, 3 },
391*7f2fe78bSCy Schubert { "wednes", tDAY, 3 },
392*7f2fe78bSCy Schubert { "thursday", tDAY, 4 },
393*7f2fe78bSCy Schubert { "thur", tDAY, 4 },
394*7f2fe78bSCy Schubert { "thurs", tDAY, 4 },
395*7f2fe78bSCy Schubert { "friday", tDAY, 5 },
396*7f2fe78bSCy Schubert { "saturday", tDAY, 6 },
397*7f2fe78bSCy Schubert { NULL }
398*7f2fe78bSCy Schubert };
399*7f2fe78bSCy Schubert
400*7f2fe78bSCy Schubert /* Time units table. */
401*7f2fe78bSCy Schubert static TABLE const UnitsTable[] = {
402*7f2fe78bSCy Schubert { "year", tMONTH_UNIT, 12 },
403*7f2fe78bSCy Schubert { "month", tMONTH_UNIT, 1 },
404*7f2fe78bSCy Schubert { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
405*7f2fe78bSCy Schubert { "week", tMINUTE_UNIT, 7 * 24 * 60 },
406*7f2fe78bSCy Schubert { "day", tMINUTE_UNIT, 1 * 24 * 60 },
407*7f2fe78bSCy Schubert { "hour", tMINUTE_UNIT, 60 },
408*7f2fe78bSCy Schubert { "minute", tMINUTE_UNIT, 1 },
409*7f2fe78bSCy Schubert { "min", tMINUTE_UNIT, 1 },
410*7f2fe78bSCy Schubert { "second", tSEC_UNIT, 1 },
411*7f2fe78bSCy Schubert { "sec", tSEC_UNIT, 1 },
412*7f2fe78bSCy Schubert { NULL }
413*7f2fe78bSCy Schubert };
414*7f2fe78bSCy Schubert
415*7f2fe78bSCy Schubert /* Assorted relative-time words. */
416*7f2fe78bSCy Schubert static TABLE const OtherTable[] = {
417*7f2fe78bSCy Schubert { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
418*7f2fe78bSCy Schubert { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
419*7f2fe78bSCy Schubert { "today", tMINUTE_UNIT, 0 },
420*7f2fe78bSCy Schubert { "now", tMINUTE_UNIT, 0 },
421*7f2fe78bSCy Schubert { "last", tUNUMBER, -1 },
422*7f2fe78bSCy Schubert { "this", tMINUTE_UNIT, 0 },
423*7f2fe78bSCy Schubert { "next", tUNUMBER, 2 },
424*7f2fe78bSCy Schubert { "first", tUNUMBER, 1 },
425*7f2fe78bSCy Schubert /* { "second", tUNUMBER, 2 }, */
426*7f2fe78bSCy Schubert { "third", tUNUMBER, 3 },
427*7f2fe78bSCy Schubert { "fourth", tUNUMBER, 4 },
428*7f2fe78bSCy Schubert { "fifth", tUNUMBER, 5 },
429*7f2fe78bSCy Schubert { "sixth", tUNUMBER, 6 },
430*7f2fe78bSCy Schubert { "seventh", tUNUMBER, 7 },
431*7f2fe78bSCy Schubert { "eighth", tUNUMBER, 8 },
432*7f2fe78bSCy Schubert { "ninth", tUNUMBER, 9 },
433*7f2fe78bSCy Schubert { "tenth", tUNUMBER, 10 },
434*7f2fe78bSCy Schubert { "eleventh", tUNUMBER, 11 },
435*7f2fe78bSCy Schubert { "twelfth", tUNUMBER, 12 },
436*7f2fe78bSCy Schubert { "ago", tAGO, 1 },
437*7f2fe78bSCy Schubert { "never", tNEVER, 0 },
438*7f2fe78bSCy Schubert { NULL }
439*7f2fe78bSCy Schubert };
440*7f2fe78bSCy Schubert
441*7f2fe78bSCy Schubert /* The timezone table. */
442*7f2fe78bSCy Schubert /* Some of these are commented out because a time_t can't store a float. */
443*7f2fe78bSCy Schubert static TABLE const TimezoneTable[] = {
444*7f2fe78bSCy Schubert { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
445*7f2fe78bSCy Schubert { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
446*7f2fe78bSCy Schubert { "utc", tZONE, HOUR( 0) },
447*7f2fe78bSCy Schubert { "wet", tZONE, HOUR( 0) }, /* Western European */
448*7f2fe78bSCy Schubert { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
449*7f2fe78bSCy Schubert { "wat", tZONE, HOUR( 1) }, /* West Africa */
450*7f2fe78bSCy Schubert { "at", tZONE, HOUR( 2) }, /* Azores */
451*7f2fe78bSCy Schubert #if 0
452*7f2fe78bSCy Schubert /* For completeness. BST is also British Summer, and GST is
453*7f2fe78bSCy Schubert * also Guam Standard. */
454*7f2fe78bSCy Schubert { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
455*7f2fe78bSCy Schubert { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
456*7f2fe78bSCy Schubert #endif
457*7f2fe78bSCy Schubert #if 0
458*7f2fe78bSCy Schubert { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
459*7f2fe78bSCy Schubert { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
460*7f2fe78bSCy Schubert { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
461*7f2fe78bSCy Schubert #endif
462*7f2fe78bSCy Schubert { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
463*7f2fe78bSCy Schubert { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
464*7f2fe78bSCy Schubert { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
465*7f2fe78bSCy Schubert { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
466*7f2fe78bSCy Schubert { "cst", tZONE, HOUR( 6) }, /* Central Standard */
467*7f2fe78bSCy Schubert { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
468*7f2fe78bSCy Schubert { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
469*7f2fe78bSCy Schubert { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
470*7f2fe78bSCy Schubert { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
471*7f2fe78bSCy Schubert { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
472*7f2fe78bSCy Schubert { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
473*7f2fe78bSCy Schubert { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
474*7f2fe78bSCy Schubert { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
475*7f2fe78bSCy Schubert { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
476*7f2fe78bSCy Schubert { "cat", tZONE, HOUR(10) }, /* Central Alaska */
477*7f2fe78bSCy Schubert { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
478*7f2fe78bSCy Schubert { "nt", tZONE, HOUR(11) }, /* Nome */
479*7f2fe78bSCy Schubert { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
480*7f2fe78bSCy Schubert { "cet", tZONE, -HOUR(1) }, /* Central European */
481*7f2fe78bSCy Schubert { "met", tZONE, -HOUR(1) }, /* Middle European */
482*7f2fe78bSCy Schubert { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
483*7f2fe78bSCy Schubert { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
484*7f2fe78bSCy Schubert { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
485*7f2fe78bSCy Schubert { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
486*7f2fe78bSCy Schubert { "fwt", tZONE, -HOUR(1) }, /* French Winter */
487*7f2fe78bSCy Schubert { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
488*7f2fe78bSCy Schubert { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
489*7f2fe78bSCy Schubert { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
490*7f2fe78bSCy Schubert #if 0
491*7f2fe78bSCy Schubert { "it", tZONE, -HOUR(3.5) },/* Iran */
492*7f2fe78bSCy Schubert #endif
493*7f2fe78bSCy Schubert { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
494*7f2fe78bSCy Schubert { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
495*7f2fe78bSCy Schubert #if 0
496*7f2fe78bSCy Schubert { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
497*7f2fe78bSCy Schubert #endif
498*7f2fe78bSCy Schubert { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
499*7f2fe78bSCy Schubert #if 0
500*7f2fe78bSCy Schubert /* For completeness. NST is also Newfoundland Stanard, and SST is
501*7f2fe78bSCy Schubert * also Swedish Summer. */
502*7f2fe78bSCy Schubert { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
503*7f2fe78bSCy Schubert { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
504*7f2fe78bSCy Schubert #endif /* 0 */
505*7f2fe78bSCy Schubert { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
506*7f2fe78bSCy Schubert { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
507*7f2fe78bSCy Schubert #if 0
508*7f2fe78bSCy Schubert { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
509*7f2fe78bSCy Schubert #endif
510*7f2fe78bSCy Schubert { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
511*7f2fe78bSCy Schubert { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
512*7f2fe78bSCy Schubert { "kst", tZONE, -HOUR(9) }, /* Korean Standard */
513*7f2fe78bSCy Schubert #if 0
514*7f2fe78bSCy Schubert { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
515*7f2fe78bSCy Schubert { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
516*7f2fe78bSCy Schubert #endif
517*7f2fe78bSCy Schubert { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
518*7f2fe78bSCy Schubert { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
519*7f2fe78bSCy Schubert { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
520*7f2fe78bSCy Schubert { "kdt", tZONE, -HOUR(10) }, /* Korean Daylight */
521*7f2fe78bSCy Schubert { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
522*7f2fe78bSCy Schubert { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
523*7f2fe78bSCy Schubert { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
524*7f2fe78bSCy Schubert { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
525*7f2fe78bSCy Schubert { NULL }
526*7f2fe78bSCy Schubert };
527*7f2fe78bSCy Schubert
528*7f2fe78bSCy Schubert /* ARGSUSED */
529*7f2fe78bSCy Schubert static int
yyerror(char * s)530*7f2fe78bSCy Schubert yyerror(char *s)
531*7f2fe78bSCy Schubert {
532*7f2fe78bSCy Schubert return 0;
533*7f2fe78bSCy Schubert }
534*7f2fe78bSCy Schubert
535*7f2fe78bSCy Schubert
536*7f2fe78bSCy Schubert static time_t
ToSeconds(time_t Hours,time_t Minutes,time_t Seconds,MERIDIAN Meridian)537*7f2fe78bSCy Schubert ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
538*7f2fe78bSCy Schubert {
539*7f2fe78bSCy Schubert if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
540*7f2fe78bSCy Schubert return -1;
541*7f2fe78bSCy Schubert switch (Meridian) {
542*7f2fe78bSCy Schubert case MER24:
543*7f2fe78bSCy Schubert if (Hours < 0 || Hours > 23)
544*7f2fe78bSCy Schubert return -1;
545*7f2fe78bSCy Schubert return (Hours * 60L + Minutes) * 60L + Seconds;
546*7f2fe78bSCy Schubert case MERam:
547*7f2fe78bSCy Schubert if (Hours < 1 || Hours > 12)
548*7f2fe78bSCy Schubert return -1;
549*7f2fe78bSCy Schubert return (Hours * 60L + Minutes) * 60L + Seconds;
550*7f2fe78bSCy Schubert case MERpm:
551*7f2fe78bSCy Schubert if (Hours < 1 || Hours > 12)
552*7f2fe78bSCy Schubert return -1;
553*7f2fe78bSCy Schubert return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
554*7f2fe78bSCy Schubert default:
555*7f2fe78bSCy Schubert abort ();
556*7f2fe78bSCy Schubert }
557*7f2fe78bSCy Schubert /* NOTREACHED */
558*7f2fe78bSCy Schubert }
559*7f2fe78bSCy Schubert
560*7f2fe78bSCy Schubert /*
561*7f2fe78bSCy Schubert * From hh:mm:ss [am|pm] mm/dd/yy [tz], compute and return the number
562*7f2fe78bSCy Schubert * of seconds since 00:00:00 1/1/70 GMT.
563*7f2fe78bSCy Schubert */
564*7f2fe78bSCy Schubert static time_t
Convert(time_t Month,time_t Day,time_t Year,time_t Hours,time_t Minutes,time_t Seconds,MERIDIAN Meridian,DSTMODE DSTmode)565*7f2fe78bSCy Schubert Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes,
566*7f2fe78bSCy Schubert time_t Seconds, MERIDIAN Meridian, DSTMODE DSTmode)
567*7f2fe78bSCy Schubert {
568*7f2fe78bSCy Schubert static int DaysInMonth[12] = {
569*7f2fe78bSCy Schubert 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
570*7f2fe78bSCy Schubert };
571*7f2fe78bSCy Schubert time_t tod;
572*7f2fe78bSCy Schubert time_t Julian;
573*7f2fe78bSCy Schubert int i;
574*7f2fe78bSCy Schubert struct tm *tm;
575*7f2fe78bSCy Schubert
576*7f2fe78bSCy Schubert if (Year < 0)
577*7f2fe78bSCy Schubert Year = -Year;
578*7f2fe78bSCy Schubert if (Year < 1900)
579*7f2fe78bSCy Schubert Year += 1900;
580*7f2fe78bSCy Schubert DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
581*7f2fe78bSCy Schubert ? 29 : 28;
582*7f2fe78bSCy Schubert if (Year < EPOCH
583*7f2fe78bSCy Schubert || Year > EPOCH_END
584*7f2fe78bSCy Schubert || Month < 1 || Month > 12
585*7f2fe78bSCy Schubert /* Lint fluff: "conversion from long may lose accuracy" */
586*7f2fe78bSCy Schubert || Day < 1 || Day > DaysInMonth[(int)--Month])
587*7f2fe78bSCy Schubert return -1;
588*7f2fe78bSCy Schubert
589*7f2fe78bSCy Schubert for (Julian = Day - 1, i = 0; i < Month; i++)
590*7f2fe78bSCy Schubert Julian += DaysInMonth[i];
591*7f2fe78bSCy Schubert for (i = EPOCH; i < Year; i++)
592*7f2fe78bSCy Schubert Julian += 365 + ((i % 4 == 0) && ((Year % 100 != 0) ||
593*7f2fe78bSCy Schubert (Year % 400 == 0)));
594*7f2fe78bSCy Schubert Julian *= SECSPERDAY;
595*7f2fe78bSCy Schubert Julian += yyTimezone * 60L;
596*7f2fe78bSCy Schubert if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
597*7f2fe78bSCy Schubert return -1;
598*7f2fe78bSCy Schubert Julian += tod;
599*7f2fe78bSCy Schubert if (DSTmode == DSTon)
600*7f2fe78bSCy Schubert Julian -= 60 * 60;
601*7f2fe78bSCy Schubert else if (DSTmode == DSTmaybe) {
602*7f2fe78bSCy Schubert tm = localtime(&Julian);
603*7f2fe78bSCy Schubert if (tm == NULL)
604*7f2fe78bSCy Schubert return -1;
605*7f2fe78bSCy Schubert else if (tm->tm_isdst)
606*7f2fe78bSCy Schubert Julian -= 60 * 60;
607*7f2fe78bSCy Schubert }
608*7f2fe78bSCy Schubert return Julian;
609*7f2fe78bSCy Schubert }
610*7f2fe78bSCy Schubert
611*7f2fe78bSCy Schubert
612*7f2fe78bSCy Schubert static time_t
DSTcorrect(time_t Start,time_t Future,int * error)613*7f2fe78bSCy Schubert DSTcorrect(time_t Start, time_t Future, int *error)
614*7f2fe78bSCy Schubert {
615*7f2fe78bSCy Schubert time_t StartDay;
616*7f2fe78bSCy Schubert time_t FutureDay;
617*7f2fe78bSCy Schubert struct tm *tm;
618*7f2fe78bSCy Schubert
619*7f2fe78bSCy Schubert tm = localtime(&Start);
620*7f2fe78bSCy Schubert if (tm == NULL) {
621*7f2fe78bSCy Schubert *error = 1;
622*7f2fe78bSCy Schubert return -1;
623*7f2fe78bSCy Schubert }
624*7f2fe78bSCy Schubert StartDay = (tm->tm_hour + 1) % 24;
625*7f2fe78bSCy Schubert tm = localtime(&Future);
626*7f2fe78bSCy Schubert if (tm == NULL) {
627*7f2fe78bSCy Schubert *error = 1;
628*7f2fe78bSCy Schubert return -1;
629*7f2fe78bSCy Schubert }
630*7f2fe78bSCy Schubert FutureDay = (tm->tm_hour + 1) % 24;
631*7f2fe78bSCy Schubert *error = 0;
632*7f2fe78bSCy Schubert return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
633*7f2fe78bSCy Schubert }
634*7f2fe78bSCy Schubert
635*7f2fe78bSCy Schubert
636*7f2fe78bSCy Schubert static time_t
RelativeDate(time_t Start,time_t DayOrdinal,time_t DayNumber,int * error)637*7f2fe78bSCy Schubert RelativeDate(time_t Start, time_t DayOrdinal, time_t DayNumber, int *error)
638*7f2fe78bSCy Schubert {
639*7f2fe78bSCy Schubert struct tm *tm;
640*7f2fe78bSCy Schubert time_t now;
641*7f2fe78bSCy Schubert
642*7f2fe78bSCy Schubert now = Start;
643*7f2fe78bSCy Schubert tm = localtime(&now);
644*7f2fe78bSCy Schubert if (tm == NULL) {
645*7f2fe78bSCy Schubert *error = 1;
646*7f2fe78bSCy Schubert return -1;
647*7f2fe78bSCy Schubert }
648*7f2fe78bSCy Schubert now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
649*7f2fe78bSCy Schubert now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
650*7f2fe78bSCy Schubert return DSTcorrect(Start, now, error);
651*7f2fe78bSCy Schubert }
652*7f2fe78bSCy Schubert
653*7f2fe78bSCy Schubert
654*7f2fe78bSCy Schubert static time_t
RelativeMonth(time_t Start,time_t RelMonth)655*7f2fe78bSCy Schubert RelativeMonth(time_t Start, time_t RelMonth)
656*7f2fe78bSCy Schubert {
657*7f2fe78bSCy Schubert struct tm *tm;
658*7f2fe78bSCy Schubert time_t Month;
659*7f2fe78bSCy Schubert time_t Year;
660*7f2fe78bSCy Schubert time_t ret;
661*7f2fe78bSCy Schubert int error;
662*7f2fe78bSCy Schubert
663*7f2fe78bSCy Schubert if (RelMonth == 0)
664*7f2fe78bSCy Schubert return 0;
665*7f2fe78bSCy Schubert tm = localtime(&Start);
666*7f2fe78bSCy Schubert if (tm == NULL)
667*7f2fe78bSCy Schubert return -1;
668*7f2fe78bSCy Schubert Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
669*7f2fe78bSCy Schubert Year = Month / 12;
670*7f2fe78bSCy Schubert Month = Month % 12 + 1;
671*7f2fe78bSCy Schubert ret = Convert(Month, (time_t)tm->tm_mday, Year,
672*7f2fe78bSCy Schubert (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
673*7f2fe78bSCy Schubert MER24, DSTmaybe);
674*7f2fe78bSCy Schubert if (ret == -1)
675*7f2fe78bSCy Schubert return ret;
676*7f2fe78bSCy Schubert ret = DSTcorrect(Start, ret, &error);
677*7f2fe78bSCy Schubert if (error)
678*7f2fe78bSCy Schubert return -1;
679*7f2fe78bSCy Schubert return ret;
680*7f2fe78bSCy Schubert }
681*7f2fe78bSCy Schubert
682*7f2fe78bSCy Schubert
683*7f2fe78bSCy Schubert static int
LookupWord(char * buff)684*7f2fe78bSCy Schubert LookupWord(char *buff)
685*7f2fe78bSCy Schubert {
686*7f2fe78bSCy Schubert char *p;
687*7f2fe78bSCy Schubert char *q;
688*7f2fe78bSCy Schubert const TABLE *tp;
689*7f2fe78bSCy Schubert int i;
690*7f2fe78bSCy Schubert int abbrev;
691*7f2fe78bSCy Schubert
692*7f2fe78bSCy Schubert /* Make it lowercase. */
693*7f2fe78bSCy Schubert for (p = buff; *p; p++)
694*7f2fe78bSCy Schubert if (isupper((int) *p))
695*7f2fe78bSCy Schubert *p = tolower((int) *p);
696*7f2fe78bSCy Schubert
697*7f2fe78bSCy Schubert if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
698*7f2fe78bSCy Schubert yylval.Meridian = MERam;
699*7f2fe78bSCy Schubert return tMERIDIAN;
700*7f2fe78bSCy Schubert }
701*7f2fe78bSCy Schubert if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
702*7f2fe78bSCy Schubert yylval.Meridian = MERpm;
703*7f2fe78bSCy Schubert return tMERIDIAN;
704*7f2fe78bSCy Schubert }
705*7f2fe78bSCy Schubert
706*7f2fe78bSCy Schubert /* See if we have an abbreviation for a month. */
707*7f2fe78bSCy Schubert if (strlen(buff) == 3)
708*7f2fe78bSCy Schubert abbrev = 1;
709*7f2fe78bSCy Schubert else if (strlen(buff) == 4 && buff[3] == '.') {
710*7f2fe78bSCy Schubert abbrev = 1;
711*7f2fe78bSCy Schubert buff[3] = '\0';
712*7f2fe78bSCy Schubert }
713*7f2fe78bSCy Schubert else
714*7f2fe78bSCy Schubert abbrev = 0;
715*7f2fe78bSCy Schubert
716*7f2fe78bSCy Schubert for (tp = MonthDayTable; tp->name; tp++) {
717*7f2fe78bSCy Schubert if (abbrev) {
718*7f2fe78bSCy Schubert if (strncmp(buff, tp->name, 3) == 0) {
719*7f2fe78bSCy Schubert yylval.Number = tp->value;
720*7f2fe78bSCy Schubert return tp->type;
721*7f2fe78bSCy Schubert }
722*7f2fe78bSCy Schubert }
723*7f2fe78bSCy Schubert else if (strcmp(buff, tp->name) == 0) {
724*7f2fe78bSCy Schubert yylval.Number = tp->value;
725*7f2fe78bSCy Schubert return tp->type;
726*7f2fe78bSCy Schubert }
727*7f2fe78bSCy Schubert }
728*7f2fe78bSCy Schubert
729*7f2fe78bSCy Schubert for (tp = TimezoneTable; tp->name; tp++)
730*7f2fe78bSCy Schubert if (strcmp(buff, tp->name) == 0) {
731*7f2fe78bSCy Schubert yylval.Number = tp->value;
732*7f2fe78bSCy Schubert return tp->type;
733*7f2fe78bSCy Schubert }
734*7f2fe78bSCy Schubert
735*7f2fe78bSCy Schubert if (strcmp(buff, "dst") == 0)
736*7f2fe78bSCy Schubert return tDST;
737*7f2fe78bSCy Schubert
738*7f2fe78bSCy Schubert for (tp = UnitsTable; tp->name; tp++)
739*7f2fe78bSCy Schubert if (strcmp(buff, tp->name) == 0) {
740*7f2fe78bSCy Schubert yylval.Number = tp->value;
741*7f2fe78bSCy Schubert return tp->type;
742*7f2fe78bSCy Schubert }
743*7f2fe78bSCy Schubert
744*7f2fe78bSCy Schubert /* Strip off any plural and try the units table again. */
745*7f2fe78bSCy Schubert i = strlen(buff) - 1;
746*7f2fe78bSCy Schubert if (buff[i] == 's') {
747*7f2fe78bSCy Schubert buff[i] = '\0';
748*7f2fe78bSCy Schubert for (tp = UnitsTable; tp->name; tp++)
749*7f2fe78bSCy Schubert if (strcmp(buff, tp->name) == 0) {
750*7f2fe78bSCy Schubert yylval.Number = tp->value;
751*7f2fe78bSCy Schubert return tp->type;
752*7f2fe78bSCy Schubert }
753*7f2fe78bSCy Schubert buff[i] = 's'; /* Put back for "this" in OtherTable. */
754*7f2fe78bSCy Schubert }
755*7f2fe78bSCy Schubert
756*7f2fe78bSCy Schubert for (tp = OtherTable; tp->name; tp++)
757*7f2fe78bSCy Schubert if (strcmp(buff, tp->name) == 0) {
758*7f2fe78bSCy Schubert yylval.Number = tp->value;
759*7f2fe78bSCy Schubert return tp->type;
760*7f2fe78bSCy Schubert }
761*7f2fe78bSCy Schubert
762*7f2fe78bSCy Schubert /* Drop out any periods and try the timezone table again. */
763*7f2fe78bSCy Schubert for (i = 0, p = q = buff; *q; q++)
764*7f2fe78bSCy Schubert if (*q != '.')
765*7f2fe78bSCy Schubert *p++ = *q;
766*7f2fe78bSCy Schubert else
767*7f2fe78bSCy Schubert i++;
768*7f2fe78bSCy Schubert *p = '\0';
769*7f2fe78bSCy Schubert if (i)
770*7f2fe78bSCy Schubert for (tp = TimezoneTable; tp->name; tp++)
771*7f2fe78bSCy Schubert if (strcmp(buff, tp->name) == 0) {
772*7f2fe78bSCy Schubert yylval.Number = tp->value;
773*7f2fe78bSCy Schubert return tp->type;
774*7f2fe78bSCy Schubert }
775*7f2fe78bSCy Schubert
776*7f2fe78bSCy Schubert return tID;
777*7f2fe78bSCy Schubert }
778*7f2fe78bSCy Schubert
779*7f2fe78bSCy Schubert
780*7f2fe78bSCy Schubert static int
yylex()781*7f2fe78bSCy Schubert yylex()
782*7f2fe78bSCy Schubert {
783*7f2fe78bSCy Schubert char c;
784*7f2fe78bSCy Schubert char *p;
785*7f2fe78bSCy Schubert char buff[20];
786*7f2fe78bSCy Schubert int Count;
787*7f2fe78bSCy Schubert int sign;
788*7f2fe78bSCy Schubert
789*7f2fe78bSCy Schubert for ( ; ; ) {
790*7f2fe78bSCy Schubert while (isspace((int) *yyInput))
791*7f2fe78bSCy Schubert yyInput++;
792*7f2fe78bSCy Schubert
793*7f2fe78bSCy Schubert c = *yyInput;
794*7f2fe78bSCy Schubert if (isdigit((int) c) || c == '-' || c == '+') {
795*7f2fe78bSCy Schubert if (c == '-' || c == '+') {
796*7f2fe78bSCy Schubert sign = c == '-' ? -1 : 1;
797*7f2fe78bSCy Schubert if (!isdigit((int) (*++yyInput)))
798*7f2fe78bSCy Schubert /* skip the '-' sign */
799*7f2fe78bSCy Schubert continue;
800*7f2fe78bSCy Schubert }
801*7f2fe78bSCy Schubert else
802*7f2fe78bSCy Schubert sign = 0;
803*7f2fe78bSCy Schubert for (yylval.Number = 0; isdigit((int) (c = *yyInput++)); )
804*7f2fe78bSCy Schubert yylval.Number = 10 * yylval.Number + c - '0';
805*7f2fe78bSCy Schubert yyInput--;
806*7f2fe78bSCy Schubert if (sign < 0)
807*7f2fe78bSCy Schubert yylval.Number = -yylval.Number;
808*7f2fe78bSCy Schubert return sign ? tSNUMBER : tUNUMBER;
809*7f2fe78bSCy Schubert }
810*7f2fe78bSCy Schubert if (isalpha((int) c)) {
811*7f2fe78bSCy Schubert for (p = buff; isalpha((int) (c = *yyInput++)) || c == '.'; )
812*7f2fe78bSCy Schubert if (p < &buff[sizeof buff - 1])
813*7f2fe78bSCy Schubert *p++ = c;
814*7f2fe78bSCy Schubert *p = '\0';
815*7f2fe78bSCy Schubert yyInput--;
816*7f2fe78bSCy Schubert return LookupWord(buff);
817*7f2fe78bSCy Schubert }
818*7f2fe78bSCy Schubert if (c != '(')
819*7f2fe78bSCy Schubert return *yyInput++;
820*7f2fe78bSCy Schubert Count = 0;
821*7f2fe78bSCy Schubert do {
822*7f2fe78bSCy Schubert c = *yyInput++;
823*7f2fe78bSCy Schubert if (c == '\0')
824*7f2fe78bSCy Schubert return c;
825*7f2fe78bSCy Schubert if (c == '(')
826*7f2fe78bSCy Schubert Count++;
827*7f2fe78bSCy Schubert else if (c == ')')
828*7f2fe78bSCy Schubert Count--;
829*7f2fe78bSCy Schubert } while (Count > 0);
830*7f2fe78bSCy Schubert }
831*7f2fe78bSCy Schubert }
832*7f2fe78bSCy Schubert
833*7f2fe78bSCy Schubert
834*7f2fe78bSCy Schubert #define TM_YEAR_ORIGIN 1900
835*7f2fe78bSCy Schubert
836*7f2fe78bSCy Schubert /* Yield A - B, measured in seconds. */
837*7f2fe78bSCy Schubert static time_t
difftm(struct tm * a,struct tm * b)838*7f2fe78bSCy Schubert difftm(struct tm *a, struct tm *b)
839*7f2fe78bSCy Schubert {
840*7f2fe78bSCy Schubert int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
841*7f2fe78bSCy Schubert int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
842*7f2fe78bSCy Schubert return
843*7f2fe78bSCy Schubert (
844*7f2fe78bSCy Schubert (
845*7f2fe78bSCy Schubert (
846*7f2fe78bSCy Schubert /* difference in day of year */
847*7f2fe78bSCy Schubert a->tm_yday - b->tm_yday
848*7f2fe78bSCy Schubert /* + intervening leap days */
849*7f2fe78bSCy Schubert + ((ay >> 2) - (by >> 2))
850*7f2fe78bSCy Schubert - (ay/100 - by/100)
851*7f2fe78bSCy Schubert + ((ay/100 >> 2) - (by/100 >> 2))
852*7f2fe78bSCy Schubert /* + difference in years * 365 */
853*7f2fe78bSCy Schubert + (time_t)(ay-by) * 365
854*7f2fe78bSCy Schubert )*24 + (a->tm_hour - b->tm_hour)
855*7f2fe78bSCy Schubert )*60 + (a->tm_min - b->tm_min)
856*7f2fe78bSCy Schubert )*60 + (a->tm_sec - b->tm_sec);
857*7f2fe78bSCy Schubert }
858*7f2fe78bSCy Schubert
859*7f2fe78bSCy Schubert /* For get_date extern declaration compatibility check... yuck. */
860*7f2fe78bSCy Schubert #include <krb5.h>
861*7f2fe78bSCy Schubert int yyparse(void);
862*7f2fe78bSCy Schubert
863*7f2fe78bSCy Schubert time_t get_date_rel(char *, time_t);
864*7f2fe78bSCy Schubert time_t get_date(char *);
865*7f2fe78bSCy Schubert
866*7f2fe78bSCy Schubert time_t
get_date_rel(char * p,time_t nowtime)867*7f2fe78bSCy Schubert get_date_rel(char *p, time_t nowtime)
868*7f2fe78bSCy Schubert {
869*7f2fe78bSCy Schubert struct my_timeb *now = NULL;
870*7f2fe78bSCy Schubert struct tm *tm, gmt;
871*7f2fe78bSCy Schubert struct my_timeb ftz;
872*7f2fe78bSCy Schubert time_t Start;
873*7f2fe78bSCy Schubert time_t tod;
874*7f2fe78bSCy Schubert time_t delta;
875*7f2fe78bSCy Schubert int error;
876*7f2fe78bSCy Schubert
877*7f2fe78bSCy Schubert yyInput = p;
878*7f2fe78bSCy Schubert if (now == NULL) {
879*7f2fe78bSCy Schubert now = &ftz;
880*7f2fe78bSCy Schubert
881*7f2fe78bSCy Schubert ftz.time = nowtime;
882*7f2fe78bSCy Schubert
883*7f2fe78bSCy Schubert if (! (tm = gmtime (&ftz.time)))
884*7f2fe78bSCy Schubert return -1;
885*7f2fe78bSCy Schubert gmt = *tm; /* Make a copy, in case localtime modifies *tm. */
886*7f2fe78bSCy Schubert tm = localtime(&ftz.time);
887*7f2fe78bSCy Schubert if (tm == NULL)
888*7f2fe78bSCy Schubert return -1;
889*7f2fe78bSCy Schubert ftz.timezone = difftm (&gmt, tm) / 60;
890*7f2fe78bSCy Schubert }
891*7f2fe78bSCy Schubert
892*7f2fe78bSCy Schubert tm = localtime(&now->time);
893*7f2fe78bSCy Schubert if (tm == NULL)
894*7f2fe78bSCy Schubert return -1;
895*7f2fe78bSCy Schubert yyYear = tm->tm_year;
896*7f2fe78bSCy Schubert yyMonth = tm->tm_mon + 1;
897*7f2fe78bSCy Schubert yyDay = tm->tm_mday;
898*7f2fe78bSCy Schubert yyTimezone = now->timezone;
899*7f2fe78bSCy Schubert yyDSTmode = DSTmaybe;
900*7f2fe78bSCy Schubert yyHour = 0;
901*7f2fe78bSCy Schubert yyMinutes = 0;
902*7f2fe78bSCy Schubert yySeconds = 0;
903*7f2fe78bSCy Schubert yyMeridian = MER24;
904*7f2fe78bSCy Schubert yyRelSeconds = 0;
905*7f2fe78bSCy Schubert yyRelMonth = 0;
906*7f2fe78bSCy Schubert yyHaveDate = 0;
907*7f2fe78bSCy Schubert yyHaveDay = 0;
908*7f2fe78bSCy Schubert yyHaveRel = 0;
909*7f2fe78bSCy Schubert yyHaveTime = 0;
910*7f2fe78bSCy Schubert yyHaveZone = 0;
911*7f2fe78bSCy Schubert
912*7f2fe78bSCy Schubert /*
913*7f2fe78bSCy Schubert * When yyparse returns, zero or more of yyHave{Time,Zone,Date,Day,Rel}
914*7f2fe78bSCy Schubert * will have been incremented. The value is number of items of
915*7f2fe78bSCy Schubert * that type that were found; for all but Rel, more than one is
916*7f2fe78bSCy Schubert * illegal.
917*7f2fe78bSCy Schubert *
918*7f2fe78bSCy Schubert * For each yyHave indicator, the following values are set:
919*7f2fe78bSCy Schubert *
920*7f2fe78bSCy Schubert * yyHaveTime:
921*7f2fe78bSCy Schubert * yyHour, yyMinutes, yySeconds: hh:mm:ss specified, initialized
922*7f2fe78bSCy Schubert * to zeros above
923*7f2fe78bSCy Schubert * yyMeridian: MERam, MERpm, or MER24
924*7f2fe78bSCy Schubert * yyTimeZone: time zone specified in minutes
925*7f2fe78bSCy Schubert * yyDSTmode: DSToff if yyTimeZone is set, otherwise unchanged
926*7f2fe78bSCy Schubert * (initialized above to DSTmaybe)
927*7f2fe78bSCy Schubert *
928*7f2fe78bSCy Schubert * yyHaveZone:
929*7f2fe78bSCy Schubert * yyTimezone: as above
930*7f2fe78bSCy Schubert * yyDSTmode: DSToff if a non-DST zone is specified, otherwise DSTon
931*7f2fe78bSCy Schubert * XXX don't understand interaction with yyHaveTime zone info
932*7f2fe78bSCy Schubert *
933*7f2fe78bSCy Schubert * yyHaveDay:
934*7f2fe78bSCy Schubert * yyDayNumber: 0-6 for Sunday-Saturday
935*7f2fe78bSCy Schubert * yyDayOrdinal: val specified with day ("second monday",
936*7f2fe78bSCy Schubert * Ordinal=2), otherwise 1
937*7f2fe78bSCy Schubert *
938*7f2fe78bSCy Schubert * yyHaveDate:
939*7f2fe78bSCy Schubert * yyMonth, yyDay, yyYear: mm/dd/yy specified, initialized to
940*7f2fe78bSCy Schubert * today above
941*7f2fe78bSCy Schubert *
942*7f2fe78bSCy Schubert * yyHaveRel:
943*7f2fe78bSCy Schubert * yyRelSeconds: seconds specified with MINUTE_UNITs ("3 hours") or
944*7f2fe78bSCy Schubert * SEC_UNITs ("30 seconds")
945*7f2fe78bSCy Schubert * yyRelMonth: months specified with MONTH_UNITs ("3 months", "1
946*7f2fe78bSCy Schubert * year")
947*7f2fe78bSCy Schubert *
948*7f2fe78bSCy Schubert * The code following yyparse turns these values into a single
949*7f2fe78bSCy Schubert * date stamp.
950*7f2fe78bSCy Schubert */
951*7f2fe78bSCy Schubert if (yyparse()
952*7f2fe78bSCy Schubert || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
953*7f2fe78bSCy Schubert return -1;
954*7f2fe78bSCy Schubert
955*7f2fe78bSCy Schubert /*
956*7f2fe78bSCy Schubert * If an absolute time specified, set Start to the equivalent Unix
957*7f2fe78bSCy Schubert * timestamp. Otherwise, set Start to now, and if we do not have
958*7f2fe78bSCy Schubert * a relatime time (ie: only yyHaveZone), decrement Start to the
959*7f2fe78bSCy Schubert * beginning of today.
960*7f2fe78bSCy Schubert *
961*7f2fe78bSCy Schubert * By having yyHaveDay in the "absolute" list, "next Monday" means
962*7f2fe78bSCy Schubert * midnight next Monday. Otherwise, "next Monday" would mean the
963*7f2fe78bSCy Schubert * time right now, next Monday. It's not clear to me why the
964*7f2fe78bSCy Schubert * current behavior is preferred.
965*7f2fe78bSCy Schubert */
966*7f2fe78bSCy Schubert if (yyHaveDate || yyHaveTime || yyHaveDay) {
967*7f2fe78bSCy Schubert Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
968*7f2fe78bSCy Schubert yyMeridian, yyDSTmode);
969*7f2fe78bSCy Schubert if (Start < 0)
970*7f2fe78bSCy Schubert return -1;
971*7f2fe78bSCy Schubert }
972*7f2fe78bSCy Schubert else {
973*7f2fe78bSCy Schubert Start = now->time;
974*7f2fe78bSCy Schubert if (!yyHaveRel)
975*7f2fe78bSCy Schubert Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
976*7f2fe78bSCy Schubert }
977*7f2fe78bSCy Schubert
978*7f2fe78bSCy Schubert /*
979*7f2fe78bSCy Schubert * Add in the relative time specified. RelativeMonth adds in the
980*7f2fe78bSCy Schubert * months, accounting for the fact that the actual length of "3
981*7f2fe78bSCy Schubert * months" depends on where you start counting.
982*7f2fe78bSCy Schubert *
983*7f2fe78bSCy Schubert * XXX By having this separate from the previous block, we are
984*7f2fe78bSCy Schubert * allowing dates like "10:00am 3 months", which means 3 months
985*7f2fe78bSCy Schubert * from 10:00am today, or even "1/1/99 two days" which means two
986*7f2fe78bSCy Schubert * days after 1/1/99.
987*7f2fe78bSCy Schubert *
988*7f2fe78bSCy Schubert * XXX Shouldn't this only be done if yyHaveRel, just for
989*7f2fe78bSCy Schubert * thoroughness?
990*7f2fe78bSCy Schubert */
991*7f2fe78bSCy Schubert Start += yyRelSeconds;
992*7f2fe78bSCy Schubert delta = RelativeMonth(Start, yyRelMonth);
993*7f2fe78bSCy Schubert if (delta == (time_t) -1)
994*7f2fe78bSCy Schubert return -1;
995*7f2fe78bSCy Schubert Start += delta;
996*7f2fe78bSCy Schubert
997*7f2fe78bSCy Schubert /*
998*7f2fe78bSCy Schubert * Now, if you specified a day of week and counter, add it in. By
999*7f2fe78bSCy Schubert * disallowing Date but allowing Time, you can say "5pm next
1000*7f2fe78bSCy Schubert * monday".
1001*7f2fe78bSCy Schubert *
1002*7f2fe78bSCy Schubert * XXX The yyHaveDay && !yyHaveDate restriction should be enforced
1003*7f2fe78bSCy Schubert * above and be able to cause failure.
1004*7f2fe78bSCy Schubert */
1005*7f2fe78bSCy Schubert if (yyHaveDay && !yyHaveDate) {
1006*7f2fe78bSCy Schubert tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber, &error);
1007*7f2fe78bSCy Schubert if (error != 0)
1008*7f2fe78bSCy Schubert return -1;
1009*7f2fe78bSCy Schubert Start += tod;
1010*7f2fe78bSCy Schubert }
1011*7f2fe78bSCy Schubert
1012*7f2fe78bSCy Schubert /* Have to do *something* with a legitimate -1 so it's distinguishable
1013*7f2fe78bSCy Schubert * from the error return value. (Alternately could set errno on error.) */
1014*7f2fe78bSCy Schubert return Start == -1 ? 0 : Start;
1015*7f2fe78bSCy Schubert }
1016*7f2fe78bSCy Schubert
1017*7f2fe78bSCy Schubert
1018*7f2fe78bSCy Schubert time_t
get_date(char * p)1019*7f2fe78bSCy Schubert get_date(char *p)
1020*7f2fe78bSCy Schubert {
1021*7f2fe78bSCy Schubert return get_date_rel(p, time(NULL));
1022*7f2fe78bSCy Schubert }
1023*7f2fe78bSCy Schubert
1024*7f2fe78bSCy Schubert
1025*7f2fe78bSCy Schubert #if defined(TEST)
1026*7f2fe78bSCy Schubert
1027*7f2fe78bSCy Schubert /* ARGSUSED */
main(int ac,char * av[])1028*7f2fe78bSCy Schubert main(int ac, char *av[])
1029*7f2fe78bSCy Schubert {
1030*7f2fe78bSCy Schubert char buff[128];
1031*7f2fe78bSCy Schubert time_t d;
1032*7f2fe78bSCy Schubert
1033*7f2fe78bSCy Schubert (void)printf("Enter date, or blank line to exit.\n\t> ");
1034*7f2fe78bSCy Schubert (void)fflush(stdout);
1035*7f2fe78bSCy Schubert while (gets(buff) && buff[0]) {
1036*7f2fe78bSCy Schubert d = get_date(buff);
1037*7f2fe78bSCy Schubert if (d == -1)
1038*7f2fe78bSCy Schubert (void)printf("Bad format - couldn't convert.\n");
1039*7f2fe78bSCy Schubert else
1040*7f2fe78bSCy Schubert (void)printf("%s", ctime(&d));
1041*7f2fe78bSCy Schubert (void)printf("\t> ");
1042*7f2fe78bSCy Schubert (void)fflush(stdout);
1043*7f2fe78bSCy Schubert }
1044*7f2fe78bSCy Schubert exit(0);
1045*7f2fe78bSCy Schubert /* NOTREACHED */
1046*7f2fe78bSCy Schubert }
1047*7f2fe78bSCy Schubert #endif /* defined(TEST) */
1048