xref: /freebsd/crypto/krb5/src/kadmin/cli/getdate.y (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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