xref: /onnv-gate/usr/src/cmd/krb5/kadmin/cli/getdate.y (revision 2881:ea6360e7e1c5)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  *	Openvision retains the copyright to derivative works of
50Sstevel@tonic-gate  *	this source code.  Do *NOT* create a derivative of this
60Sstevel@tonic-gate  *	source code before consulting with your legal department.
70Sstevel@tonic-gate  *	Do *NOT* integrate *ANY* of this source code into another
80Sstevel@tonic-gate  *	product before consulting with your legal department.
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  *	For further information, read the top-level Openvision
110Sstevel@tonic-gate  *	copyright which is contained in the top-level MIT Kerberos
120Sstevel@tonic-gate  *	copyright.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
150Sstevel@tonic-gate  *
160Sstevel@tonic-gate  */
170Sstevel@tonic-gate 
180Sstevel@tonic-gate 
190Sstevel@tonic-gate %{
200Sstevel@tonic-gate /*
21*2881Smp153739  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
220Sstevel@tonic-gate  * Use is subject to license terms.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
28*2881Smp153739 **  Originally written by Steven M. Bellovin <smb@research.att.com> while
29*2881Smp153739 **  at the University of North Carolina at Chapel Hill.  Later tweaked by
30*2881Smp153739 **  a couple of people on Usenet.  Completely overhauled by Rich $alz
31*2881Smp153739 **  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
32*2881Smp153739 **  send any email to Rich.
33*2881Smp153739 **
34*2881Smp153739 **  This grammar has nine shift/reduce conflicts.
35*2881Smp153739 **
36*2881Smp153739 **  This code is in the public domain and has no copyright.
37*2881Smp153739 */
38*2881Smp153739 /* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
39*2881Smp153739 /* SUPPRESS 288 on yyerrlab *//* Label unused */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #ifdef HAVE_CONFIG_H
42*2881Smp153739 #if defined (emacs) || defined (CONFIG_BROKETS)
430Sstevel@tonic-gate #include <config.h>
440Sstevel@tonic-gate #else
450Sstevel@tonic-gate #include "config.h"
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate #endif
480Sstevel@tonic-gate #include <string.h>
490Sstevel@tonic-gate 
50*2881Smp153739 /* Since the code of getdate.y is not included in the Emacs executable
51*2881Smp153739    itself, there is no need to #define static in this file.  Even if
52*2881Smp153739    the code were included in the Emacs executable, it probably
53*2881Smp153739    wouldn't do any harm to #undef it here; this will only cause
54*2881Smp153739    problems if we try to write to a static variable, which I don't
55*2881Smp153739    think this code needs to do.  */
560Sstevel@tonic-gate #ifdef emacs
570Sstevel@tonic-gate #undef static
580Sstevel@tonic-gate #endif
590Sstevel@tonic-gate 
60*2881Smp153739 /* The following block of alloca-related preprocessor directives is here
61*2881Smp153739    solely to allow compilation by non GNU-C compilers of the C parser
62*2881Smp153739    produced from this file by old versions of bison.  Newer versions of
63*2881Smp153739    bison include a block similar to this one in bison.simple.  */
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #ifdef __GNUC__
660Sstevel@tonic-gate #undef alloca
67*2881Smp153739 #define alloca __builtin_alloca
680Sstevel@tonic-gate #else
690Sstevel@tonic-gate #ifdef HAVE_ALLOCA_H
700Sstevel@tonic-gate #include <alloca.h>
710Sstevel@tonic-gate #else
720Sstevel@tonic-gate #ifdef _AIX /* for Bison */
73*2881Smp153739  #pragma alloca
740Sstevel@tonic-gate #else
75*2881Smp153739 void *alloca ();
760Sstevel@tonic-gate #endif
770Sstevel@tonic-gate #endif
780Sstevel@tonic-gate #endif
790Sstevel@tonic-gate 
800Sstevel@tonic-gate #include <stdio.h>
810Sstevel@tonic-gate #include <ctype.h>
820Sstevel@tonic-gate 
83*2881Smp153739 #if defined(HAVE_STDLIB_H)
84*2881Smp153739 #include <stdlib.h>
85*2881Smp153739 #endif
86*2881Smp153739 
87*2881Smp153739 /* The code at the top of get_date which figures out the offset of the
88*2881Smp153739    current time zone checks various CPP symbols to see if special
89*2881Smp153739    tricks are need, but defaults to using the gettimeofday system call.
90*2881Smp153739    Include <sys/time.h> if that will be used.  */
910Sstevel@tonic-gate 
920Sstevel@tonic-gate #if	defined(vms)
930Sstevel@tonic-gate 
940Sstevel@tonic-gate #include <types.h>
950Sstevel@tonic-gate #include <time.h>
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #else
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #include <sys/types.h>
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate #ifdef TIME_WITH_SYS_TIME
1020Sstevel@tonic-gate #include <sys/time.h>
1030Sstevel@tonic-gate #include <time.h>
1040Sstevel@tonic-gate #else
1050Sstevel@tonic-gate #ifdef HAVE_SYS_TIME_H
1060Sstevel@tonic-gate #include <sys/time.h>
1070Sstevel@tonic-gate #else
1080Sstevel@tonic-gate #include <time.h>
1090Sstevel@tonic-gate #endif
1100Sstevel@tonic-gate #endif
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate #ifdef timezone
1130Sstevel@tonic-gate #undef timezone /* needed for sgi */
1140Sstevel@tonic-gate #endif
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /*
117*2881Smp153739 ** We use the obsolete `struct my_timeb' as part of our interface!
118*2881Smp153739 ** Since the system doesn't have it, we define it here;
119*2881Smp153739 ** our callers must do likewise.
120*2881Smp153739 */
1210Sstevel@tonic-gate struct my_timeb {
1220Sstevel@tonic-gate     time_t		time;		/* Seconds since the epoch	*/
1230Sstevel@tonic-gate     unsigned short	millitm;	/* Field not used		*/
1240Sstevel@tonic-gate     short		timezone;	/* Minutes west of GMT		*/
1250Sstevel@tonic-gate     short		dstflag;	/* Field not used		*/
1260Sstevel@tonic-gate };
1270Sstevel@tonic-gate #endif	/* defined(vms) */
1280Sstevel@tonic-gate 
129*2881Smp153739 #if defined (STDC_HEADERS) || defined (USG)
1300Sstevel@tonic-gate #include <string.h>
1310Sstevel@tonic-gate #endif
1320Sstevel@tonic-gate 
133*2881Smp153739 /* Some old versions of bison generate parsers that use bcopy.
134*2881Smp153739    That loses on systems that don't provide the function, so we have
135*2881Smp153739    to redefine it here.  */
136*2881Smp153739 #ifndef bcopy
137*2881Smp153739 #define bcopy(from, to, len) memcpy ((to), (from), (len))
1380Sstevel@tonic-gate #endif
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /*
1410Sstevel@tonic-gate  * The following is a hack so that it is easy to internationalize
1420Sstevel@tonic-gate  * statically declared strings. We define a wrapper function here that
1430Sstevel@tonic-gate  * will be a replacement for gettext. We the make gettext a macro that
1440Sstevel@tonic-gate  * just returns its argument, which now can be used with statically defined
1450Sstevel@tonic-gate  * strings. The conquence of this is that GETTEXT must be used to translate
1460Sstevel@tonic-gate  * a string at runtime and gettext must be used around string literals so
1470Sstevel@tonic-gate  * that xgettext command can extract them to a portable object database file.
1480Sstevel@tonic-gate  *
1490Sstevel@tonic-gate  * Thus to translate a string literal that is an argument to a function foo
1500Sstevel@tonic-gate  * the following will have to be performed:
1510Sstevel@tonic-gate  *
1520Sstevel@tonic-gate  *              foo(GETTEXT(gettext("This is a test")));
1530Sstevel@tonic-gate  *
1540Sstevel@tonic-gate  * The inner gettext call is for xgettext command to extract the string.
1550Sstevel@tonic-gate  * The C preprossesor will reduce the above to:
1560Sstevel@tonic-gate  *
1570Sstevel@tonic-gate  *              foo(GETTEXT(("This ia a test"));
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate #include <libintl.h>
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static char *
GETTEXT(const char * msgid)1630Sstevel@tonic-gate GETTEXT(const char *msgid)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	return (gettext(msgid));
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate #define	gettext(s) (s)
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate extern struct tm	*gmtime();
1720Sstevel@tonic-gate extern struct tm	*localtime();
1730Sstevel@tonic-gate 
174*2881Smp153739 #define yyparse getdate_yyparse
175*2881Smp153739 #define yylex getdate_yylex
176*2881Smp153739 #define yyerror getdate_yyerror
1770Sstevel@tonic-gate 
178*2881Smp153739 static int getdate_yylex (void);
179*2881Smp153739 static int getdate_yyerror (char *);
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 
182*2881Smp153739 #define EPOCH		1970
1830Sstevel@tonic-gate #define EPOCH_END	2099  /* Solaris 64 bit can support this at this point */
184*2881Smp153739 #define HOUR(x)		((time_t)(x) * 60)
185*2881Smp153739 #define SECSPERDAY	(24L * 60L * 60L)
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*
189*2881Smp153739 **  An entry in the lexical lookup table.
190*2881Smp153739 */
1910Sstevel@tonic-gate typedef struct _TABLE {
1920Sstevel@tonic-gate     char	*name;
1930Sstevel@tonic-gate     int		type;
1940Sstevel@tonic-gate     time_t	value;
1950Sstevel@tonic-gate } TABLE;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*
199*2881Smp153739 **  Daylight-savings mode:  on, off, or not yet known.
200*2881Smp153739 */
2010Sstevel@tonic-gate typedef enum _DSTMODE {
2020Sstevel@tonic-gate     DSTon, DSToff, DSTmaybe
2030Sstevel@tonic-gate } DSTMODE;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate /*
206*2881Smp153739 **  Meridian:  am, pm, or 24-hour style.
207*2881Smp153739 */
2080Sstevel@tonic-gate typedef enum _MERIDIAN {
2090Sstevel@tonic-gate     MERam, MERpm, MER24
2100Sstevel@tonic-gate } MERIDIAN;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
214*2881Smp153739 **  Global variables.  We could get rid of most of these by using a good
215*2881Smp153739 **  union as the yacc stack.  (This routine was originally written before
216*2881Smp153739 **  yacc had the %union construct.)  Maybe someday; right now we only use
217*2881Smp153739 **  the %union very rarely.
218*2881Smp153739 */
2190Sstevel@tonic-gate static char	*yyInput;
2200Sstevel@tonic-gate static DSTMODE	yyDSTmode;
2210Sstevel@tonic-gate static time_t	yyDayOrdinal;
2220Sstevel@tonic-gate static time_t	yyDayNumber;
2230Sstevel@tonic-gate static int	yyHaveDate;
2240Sstevel@tonic-gate static int	yyHaveDay;
2250Sstevel@tonic-gate static int	yyHaveRel;
2260Sstevel@tonic-gate static int	yyHaveTime;
2270Sstevel@tonic-gate static int	yyHaveZone;
2280Sstevel@tonic-gate static time_t	yyTimezone;
2290Sstevel@tonic-gate static time_t	yyDay;
2300Sstevel@tonic-gate static time_t	yyHour;
2310Sstevel@tonic-gate static time_t	yyMinutes;
2320Sstevel@tonic-gate static time_t	yyMonth;
2330Sstevel@tonic-gate static time_t	yySeconds;
2340Sstevel@tonic-gate static time_t	yyYear;
2350Sstevel@tonic-gate static MERIDIAN	yyMeridian;
2360Sstevel@tonic-gate static time_t	yyRelMonth;
2370Sstevel@tonic-gate static time_t	yyRelSeconds;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate %}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate %union {
2420Sstevel@tonic-gate     time_t		Number;
2430Sstevel@tonic-gate     enum _MERIDIAN	Meridian;
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate %token	tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
2470Sstevel@tonic-gate %token	tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST tNEVER
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate %type	<Number>	tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
2500Sstevel@tonic-gate %type	<Number>	tSEC_UNIT tSNUMBER tUNUMBER tZONE
2510Sstevel@tonic-gate %type	<Meridian>	tMERIDIAN o_merid
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate %%
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate spec	: /* NULL */
2560Sstevel@tonic-gate 	| spec item
257*2881Smp153739         | tNEVER {
2580Sstevel@tonic-gate 	    yyYear = 1970;
2590Sstevel@tonic-gate 	    yyMonth = 1;
2600Sstevel@tonic-gate 	    yyDay = 1;
2610Sstevel@tonic-gate 	    yyHour = yyMinutes = yySeconds = 0;
2620Sstevel@tonic-gate 	    yyDSTmode = DSToff;
2630Sstevel@tonic-gate 	    yyTimezone = 0; /* gmt */
2640Sstevel@tonic-gate 	    yyHaveDate++;
265*2881Smp153739         }
2660Sstevel@tonic-gate 	;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate item	: time {
2690Sstevel@tonic-gate 	    yyHaveTime++;
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 	| zone {
2720Sstevel@tonic-gate 	    yyHaveZone++;
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 	| date {
2750Sstevel@tonic-gate 	    yyHaveDate++;
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 	| day {
2780Sstevel@tonic-gate 	    yyHaveDay++;
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 	| rel {
2810Sstevel@tonic-gate 	    yyHaveRel++;
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 	;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate time	: tUNUMBER tMERIDIAN {
2860Sstevel@tonic-gate 	    yyHour = $1;
2870Sstevel@tonic-gate 	    yyMinutes = 0;
2880Sstevel@tonic-gate 	    yySeconds = 0;
2890Sstevel@tonic-gate 	    yyMeridian = $2;
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 	| tUNUMBER ':' tUNUMBER o_merid {
2920Sstevel@tonic-gate 	    yyHour = $1;
2930Sstevel@tonic-gate 	    yyMinutes = $3;
2940Sstevel@tonic-gate 	    yySeconds = 0;
2950Sstevel@tonic-gate 	    yyMeridian = $4;
2960Sstevel@tonic-gate 	}
2970Sstevel@tonic-gate 	| tUNUMBER ':' tUNUMBER tSNUMBER {
2980Sstevel@tonic-gate 	    yyHour = $1;
2990Sstevel@tonic-gate 	    yyMinutes = $3;
3000Sstevel@tonic-gate 	    yyMeridian = MER24;
3010Sstevel@tonic-gate 	    yyDSTmode = DSToff;
3020Sstevel@tonic-gate 	    yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 	| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
3050Sstevel@tonic-gate 	    yyHour = $1;
3060Sstevel@tonic-gate 	    yyMinutes = $3;
3070Sstevel@tonic-gate 	    yySeconds = $5;
3080Sstevel@tonic-gate 	    yyMeridian = $6;
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 	| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
3110Sstevel@tonic-gate 	    yyHour = $1;
3120Sstevel@tonic-gate 	    yyMinutes = $3;
3130Sstevel@tonic-gate 	    yySeconds = $5;
3140Sstevel@tonic-gate 	    yyMeridian = MER24;
3150Sstevel@tonic-gate 	    yyDSTmode = DSToff;
3160Sstevel@tonic-gate 	    yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 	;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate zone	: tZONE {
3210Sstevel@tonic-gate 	    yyTimezone = $1;
3220Sstevel@tonic-gate 	    yyDSTmode = DSToff;
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 	| tDAYZONE {
3250Sstevel@tonic-gate 	    yyTimezone = $1;
3260Sstevel@tonic-gate 	    yyDSTmode = DSTon;
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 	|
329*2881Smp153739 	  tZONE tDST {
3300Sstevel@tonic-gate 	    yyTimezone = $1;
3310Sstevel@tonic-gate 	    yyDSTmode = DSTon;
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 	;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate day	: tDAY {
3360Sstevel@tonic-gate 	    yyDayOrdinal = 1;
3370Sstevel@tonic-gate 	    yyDayNumber = $1;
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 	| tDAY ',' {
3400Sstevel@tonic-gate 	    yyDayOrdinal = 1;
3410Sstevel@tonic-gate 	    yyDayNumber = $1;
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 	| tUNUMBER tDAY {
3440Sstevel@tonic-gate 	    yyDayOrdinal = $1;
3450Sstevel@tonic-gate 	    yyDayNumber = $2;
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 	;
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate date	: tUNUMBER '/' tUNUMBER {
3500Sstevel@tonic-gate 	    yyMonth = $1;
3510Sstevel@tonic-gate 	    yyDay = $3;
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 	| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
3540Sstevel@tonic-gate 	    yyMonth = $1;
3550Sstevel@tonic-gate 	    yyDay = $3;
3560Sstevel@tonic-gate 	    yyYear = $5;
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 	| tUNUMBER tSNUMBER tSNUMBER {
3590Sstevel@tonic-gate 	    /* ISO 8601 format.  yyyy-mm-dd.  */
3600Sstevel@tonic-gate 	    yyYear = $1;
3610Sstevel@tonic-gate 	    yyMonth = -$2;
3620Sstevel@tonic-gate 	    yyDay = -$3;
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate 	| tUNUMBER tMONTH tSNUMBER {
3650Sstevel@tonic-gate 	    /* e.g. 17-JUN-1992.  */
3660Sstevel@tonic-gate 	    yyDay = $1;
3670Sstevel@tonic-gate 	    yyMonth = $2;
3680Sstevel@tonic-gate 	    yyYear = -$3;
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 	| tMONTH tUNUMBER {
3710Sstevel@tonic-gate 	    yyMonth = $1;
3720Sstevel@tonic-gate 	    yyDay = $2;
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 	| tMONTH tUNUMBER ',' tUNUMBER {
3750Sstevel@tonic-gate 	    yyMonth = $1;
3760Sstevel@tonic-gate 	    yyDay = $2;
3770Sstevel@tonic-gate 	    yyYear = $4;
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 	| tUNUMBER tMONTH {
3800Sstevel@tonic-gate 	    yyMonth = $2;
3810Sstevel@tonic-gate 	    yyDay = $1;
3820Sstevel@tonic-gate 	}
3830Sstevel@tonic-gate 	| tUNUMBER tMONTH tUNUMBER {
3840Sstevel@tonic-gate 	    yyMonth = $2;
3850Sstevel@tonic-gate 	    yyDay = $1;
3860Sstevel@tonic-gate 	    yyYear = $3;
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate 	;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate rel	: relunit tAGO {
3910Sstevel@tonic-gate 	    yyRelSeconds = -yyRelSeconds;
3920Sstevel@tonic-gate 	    yyRelMonth = -yyRelMonth;
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 	| relunit
3950Sstevel@tonic-gate 	;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate relunit	: tUNUMBER tMINUTE_UNIT {
3980Sstevel@tonic-gate 	    yyRelSeconds += $1 * $2 * 60L;
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 	| tSNUMBER tMINUTE_UNIT {
4010Sstevel@tonic-gate 	    yyRelSeconds += $1 * $2 * 60L;
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 	| tMINUTE_UNIT {
4040Sstevel@tonic-gate 	    yyRelSeconds += $1 * 60L;
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 	| tSNUMBER tSEC_UNIT {
4070Sstevel@tonic-gate 	    yyRelSeconds += $1;
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 	| tUNUMBER tSEC_UNIT {
4100Sstevel@tonic-gate 	    yyRelSeconds += $1;
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 	| tSEC_UNIT {
4130Sstevel@tonic-gate 	    yyRelSeconds++;
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 	| tSNUMBER tMONTH_UNIT {
4160Sstevel@tonic-gate 	    yyRelMonth += $1 * $2;
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 	| tUNUMBER tMONTH_UNIT {
4190Sstevel@tonic-gate 	    yyRelMonth += $1 * $2;
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 	| tMONTH_UNIT {
4220Sstevel@tonic-gate 	    yyRelMonth += $1;
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 	;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate o_merid	: /* NULL */ {
4270Sstevel@tonic-gate 	    $$ = MER24;
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 	| tMERIDIAN {
4300Sstevel@tonic-gate 	    $$ = $1;
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 	;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate %%
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate /* Month and day table. */
4370Sstevel@tonic-gate static TABLE const MonthDayTable[] = {
4380Sstevel@tonic-gate 	{ gettext("january"),	tMONTH,  1 },
4390Sstevel@tonic-gate 	{ gettext("february"),	tMONTH,  2 },
4400Sstevel@tonic-gate 	{ gettext("march"),	tMONTH,  3 },
4410Sstevel@tonic-gate 	{ gettext("april"),	tMONTH,  4 },
4420Sstevel@tonic-gate 	{ gettext("may"),	tMONTH,  5 },
4430Sstevel@tonic-gate 	{ gettext("june"),	tMONTH,  6 },
4440Sstevel@tonic-gate 	{ gettext("july"),	tMONTH,  7 },
4450Sstevel@tonic-gate 	{ gettext("august"),	tMONTH,  8 },
4460Sstevel@tonic-gate 	{ gettext("september"),	tMONTH,  9 },
4470Sstevel@tonic-gate 	{ gettext("sept"),	tMONTH,  9 },
4480Sstevel@tonic-gate 	{ gettext("october"),	tMONTH, 10 },
4490Sstevel@tonic-gate 	{ gettext("november"),	tMONTH, 11 },
4500Sstevel@tonic-gate 	{ gettext("december"),	tMONTH, 12 },
4510Sstevel@tonic-gate 	{ gettext("sunday"),	tDAY, 0 },
4520Sstevel@tonic-gate 	{ gettext("monday"),	tDAY, 1 },
4530Sstevel@tonic-gate 	{ gettext("tuesday"),	tDAY, 2 },
4540Sstevel@tonic-gate 	{ gettext("tues"),	tDAY, 2 },
4550Sstevel@tonic-gate 	{ gettext("wednesday"),	tDAY, 3 },
4560Sstevel@tonic-gate 	{ gettext("wednes"),	tDAY, 3 },
4570Sstevel@tonic-gate 	{ gettext("thursday"),	tDAY, 4 },
4580Sstevel@tonic-gate 	{ gettext("thur"),	tDAY, 4 },
4590Sstevel@tonic-gate 	{ gettext("thurs"),	tDAY, 4 },
4600Sstevel@tonic-gate 	{ gettext("friday"),	tDAY, 5 },
4610Sstevel@tonic-gate 	{ gettext("saturday"),	tDAY, 6 },
4620Sstevel@tonic-gate 	{ NULL }
4630Sstevel@tonic-gate };
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate /* Time units table. */
4660Sstevel@tonic-gate static TABLE const UnitsTable[] = {
4670Sstevel@tonic-gate 	{ gettext("year"),		tMONTH_UNIT,	12 },
4680Sstevel@tonic-gate 	{ gettext("month"),		tMONTH_UNIT,	1 },
4690Sstevel@tonic-gate 	{ gettext("fortnight"),	tMINUTE_UNIT,	14 * 24 * 60 },
4700Sstevel@tonic-gate 	{ gettext("week"),		tMINUTE_UNIT,	7 * 24 * 60 },
4710Sstevel@tonic-gate 	{ gettext("day"),		tMINUTE_UNIT,	1 * 24 * 60 },
4720Sstevel@tonic-gate 	{ gettext("hour"),		tMINUTE_UNIT,	60 },
4730Sstevel@tonic-gate 	{ gettext("minute"),	tMINUTE_UNIT,	1 },
4740Sstevel@tonic-gate 	{ gettext("min"),		tMINUTE_UNIT,	1 },
4750Sstevel@tonic-gate 	{ gettext("second"),	tSEC_UNIT,	1 },
4760Sstevel@tonic-gate 	{ gettext("sec"),		tSEC_UNIT,	1 },
4770Sstevel@tonic-gate 	{ NULL }
4780Sstevel@tonic-gate };
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate /* Assorted relative-time words. */
4810Sstevel@tonic-gate static TABLE const OtherTable[] = {
4820Sstevel@tonic-gate 	{ gettext("tomorrow"),	tMINUTE_UNIT,	1 * 24 * 60 },
4830Sstevel@tonic-gate 	{ gettext("yesterday"),	tMINUTE_UNIT,	-1 * 24 * 60 },
4840Sstevel@tonic-gate 	{ gettext("today"),	tMINUTE_UNIT,	0 },
4850Sstevel@tonic-gate 	{ gettext("now"),	tMINUTE_UNIT,	0 },
4860Sstevel@tonic-gate 	{ gettext("last"),	tUNUMBER,	-1 },
4870Sstevel@tonic-gate 	{ gettext("this"),	tMINUTE_UNIT,	0 },
4880Sstevel@tonic-gate 	{ gettext("next"),	tUNUMBER,	2 },
4890Sstevel@tonic-gate 	{ gettext("first"),	tUNUMBER,	1 },
4900Sstevel@tonic-gate 	/*  { gettext("second"),	tUNUMBER,	2 }, */
4910Sstevel@tonic-gate 	{ gettext("third"),	tUNUMBER,	3 },
4920Sstevel@tonic-gate 	{ gettext("fourth"),	tUNUMBER,	4 },
4930Sstevel@tonic-gate 	{ gettext("fifth"),	tUNUMBER,	5 },
4940Sstevel@tonic-gate 	{ gettext("sixth"),	tUNUMBER,	6 },
4950Sstevel@tonic-gate 	{ gettext("seventh"),	tUNUMBER,	7 },
4960Sstevel@tonic-gate 	{ gettext("eighth"),	tUNUMBER,	8 },
4970Sstevel@tonic-gate 	{ gettext("ninth"),	tUNUMBER,	9 },
4980Sstevel@tonic-gate 	{ gettext("tenth"),	tUNUMBER,	10 },
4990Sstevel@tonic-gate 	{ gettext("eleventh"),	tUNUMBER,	11 },
5000Sstevel@tonic-gate 	{ gettext("twelfth"),	tUNUMBER,	12 },
5010Sstevel@tonic-gate 	{ gettext("ago"),	tAGO,		1 },
5020Sstevel@tonic-gate 	{ gettext("never"),	tNEVER,		0 },
5030Sstevel@tonic-gate 	{ NULL }
5040Sstevel@tonic-gate };
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate /* The timezone table. */
5070Sstevel@tonic-gate /* Some of these are commented out because a time_t can't store a float. */
5080Sstevel@tonic-gate static TABLE const TimezoneTable[] = {
509*2881Smp153739 	{ gettext("gmt"),	tZONE,     HOUR( 0) },	/* Greenwich Mean */
510*2881Smp153739 	{ gettext("ut"),	tZONE,     HOUR( 0) },	/* Universal (Coordinated) */
511*2881Smp153739 	{ gettext("utc"),	tZONE,     HOUR( 0) },
512*2881Smp153739 	{ gettext("wet"),	tZONE,     HOUR( 0) },	/* Western European */
513*2881Smp153739 	{ gettext("bst"),	tDAYZONE,  HOUR( 0) },	/* British Summer */
514*2881Smp153739 	{ gettext("wat"),	tZONE,     HOUR( 1) },	/* West Africa */
515*2881Smp153739 	{ gettext("at"),	tZONE,     HOUR( 2) },	/* Azores */
5160Sstevel@tonic-gate #if	0
517*2881Smp153739     /* For completeness.  BST is also British Summer, and GST is
518*2881Smp153739      * also Guam Standard. */
519*2881Smp153739     { gettext("bst"),	tZONE,     HOUR( 3) },	/* Brazil Standard */
520*2881Smp153739     { gettext("gst"),	tZONE,     HOUR( 3) },	/* Greenland Standard */
5210Sstevel@tonic-gate #endif
5220Sstevel@tonic-gate #if 0
5230Sstevel@tonic-gate 	{ gettext("nft"),	tZONE,     HOUR(3.5) },	/* Newfoundland */
5240Sstevel@tonic-gate 	{ gettext("nst"),	tZONE,     HOUR(3.5) },	/* Newfoundland Standard */
5250Sstevel@tonic-gate 	{ gettext("ndt"),	tDAYZONE,  HOUR(3.5) },	/* Newfoundland Daylight */
5260Sstevel@tonic-gate #endif
5270Sstevel@tonic-gate 	{ gettext("ast"),	tZONE,     HOUR( 4) },	/* Atlantic Standard */
5280Sstevel@tonic-gate 	{ gettext("adt"),	tDAYZONE,  HOUR( 4) },	/* Atlantic Daylight */
5290Sstevel@tonic-gate 	{ gettext("est"),	tZONE,     HOUR( 5) },	/* Eastern Standard */
5300Sstevel@tonic-gate 	{ gettext("edt"),	tDAYZONE,  HOUR( 5) },	/* Eastern Daylight */
5310Sstevel@tonic-gate 	{ gettext("cst"),	tZONE,     HOUR( 6) },	/* Central Standard */
5320Sstevel@tonic-gate 	{ gettext("cdt"),	tDAYZONE,  HOUR( 6) },	/* Central Daylight */
5330Sstevel@tonic-gate 	{ gettext("mst"),	tZONE,     HOUR( 7) },	/* Mountain Standard */
5340Sstevel@tonic-gate 	{ gettext("mdt"),	tDAYZONE,  HOUR( 7) },	/* Mountain Daylight */
5350Sstevel@tonic-gate 	{ gettext("pst"),	tZONE,     HOUR( 8) },	/* Pacific Standard */
5360Sstevel@tonic-gate 	{ gettext("pdt"),	tDAYZONE,  HOUR( 8) },	/* Pacific Daylight */
5370Sstevel@tonic-gate 	{ gettext("yst"),	tZONE,     HOUR( 9) },	/* Yukon Standard */
5380Sstevel@tonic-gate 	{ gettext("ydt"),	tDAYZONE,  HOUR( 9) },	/* Yukon Daylight */
5390Sstevel@tonic-gate 	{ gettext("hst"),	tZONE,     HOUR(10) },	/* Hawaii Standard */
5400Sstevel@tonic-gate 	{ gettext("hdt"),	tDAYZONE,  HOUR(10) },	/* Hawaii Daylight */
5410Sstevel@tonic-gate 	{ gettext("cat"),	tZONE,     HOUR(10) },	/* Central Alaska */
5420Sstevel@tonic-gate 	{ gettext("ahst"),	tZONE,     HOUR(10) },	/* Alaska-Hawaii Standard */
5430Sstevel@tonic-gate 	{ gettext("nt"),	tZONE,     HOUR(11) },	/* Nome */
5440Sstevel@tonic-gate 	{ gettext("idlw"),	tZONE,     HOUR(12) },	/* International Date Line West */
5450Sstevel@tonic-gate 	{ gettext("cet"),	tZONE,     -HOUR(1) },	/* Central European */
5460Sstevel@tonic-gate 	{ gettext("met"),	tZONE,     -HOUR(1) },	/* Middle European */
5470Sstevel@tonic-gate 	{ gettext("mewt"),	tZONE,     -HOUR(1) },	/* Middle European Winter */
5480Sstevel@tonic-gate 	{ gettext("mest"),	tDAYZONE,  -HOUR(1) },	/* Middle European Summer */
5490Sstevel@tonic-gate 	{ gettext("swt"),	tZONE,     -HOUR(1) },	/* Swedish Winter */
5500Sstevel@tonic-gate 	{ gettext("sst"),	tDAYZONE,  -HOUR(1) },	/* Swedish Summer */
5510Sstevel@tonic-gate 	{ gettext("fwt"),	tZONE,     -HOUR(1) },	/* French Winter */
5520Sstevel@tonic-gate 	{ gettext("fst"),	tDAYZONE,  -HOUR(1) },	/* French Summer */
5530Sstevel@tonic-gate 	{ gettext("eet"),	tZONE,     -HOUR(2) },	/* Eastern Europe, USSR Zone 1 */
5540Sstevel@tonic-gate 	{ gettext("bt"),	tZONE,     -HOUR(3) },	/* Baghdad, USSR Zone 2 */
5550Sstevel@tonic-gate #if 0
5560Sstevel@tonic-gate 	{ gettext("it"),	tZONE,     -HOUR(3.5) },/* Iran */
5570Sstevel@tonic-gate #endif
5580Sstevel@tonic-gate 	{ gettext("zp4"),	tZONE,     -HOUR(4) },	/* USSR Zone 3 */
5590Sstevel@tonic-gate 	{ gettext("zp5"),	tZONE,     -HOUR(5) },	/* USSR Zone 4 */
5600Sstevel@tonic-gate #if 0
5610Sstevel@tonic-gate 	{ gettext("ist"),	tZONE,     -HOUR(5.5) },/* Indian Standard */
5620Sstevel@tonic-gate #endif
5630Sstevel@tonic-gate 	{ gettext("zp6"),	tZONE,     -HOUR(6) },	/* USSR Zone 5 */
5640Sstevel@tonic-gate #if	0
565*2881Smp153739     /* For completeness.  NST is also Newfoundland Stanard, and SST is
566*2881Smp153739      * also Swedish Summer. */
567*2881Smp153739     { gettext("nst"),	tZONE,     -HOUR(6.5) },/* North Sumatra */
568*2881Smp153739     { gettext("sst"),	tZONE,     -HOUR(7) },	/* South Sumatra, USSR Zone 6 */
5690Sstevel@tonic-gate #endif	/* 0 */
5700Sstevel@tonic-gate 	{ gettext("wast"),	tZONE,     -HOUR(7) },	/* West Australian Standard */
5710Sstevel@tonic-gate 	{ gettext("wadt"),	tDAYZONE,  -HOUR(7) },	/* West Australian Daylight */
5720Sstevel@tonic-gate #if 0
5730Sstevel@tonic-gate 	{ gettext("jt"),	tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
5740Sstevel@tonic-gate #endif
5750Sstevel@tonic-gate 	{ gettext("cct"),	tZONE,     -HOUR(8) },	/* China Coast, USSR Zone 7 */
5760Sstevel@tonic-gate 	{ gettext("jst"),	tZONE,     -HOUR(9) },	/* Japan Standard, USSR Zone 8 */
5770Sstevel@tonic-gate 	{ gettext("kst"),	tZONE,     -HOUR(9) },	/* Korean Standard */
5780Sstevel@tonic-gate #if 0
5790Sstevel@tonic-gate 	{ gettext("cast"),	tZONE,     -HOUR(9.5) },/* Central Australian Standard */
5800Sstevel@tonic-gate 	{ gettext("cadt"),	tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
5810Sstevel@tonic-gate #endif
5820Sstevel@tonic-gate 	{ gettext("east"),	tZONE,     -HOUR(10) },	/* Eastern Australian Standard */
5830Sstevel@tonic-gate 	{ gettext("eadt"),	tDAYZONE,  -HOUR(10) },	/* Eastern Australian Daylight */
5840Sstevel@tonic-gate 	{ gettext("gst"),	tZONE,     -HOUR(10) },	/* Guam Standard, USSR Zone 9 */
5850Sstevel@tonic-gate 	{ gettext("kdt"),	tZONE,     -HOUR(10) },	/* Korean Daylight */
5860Sstevel@tonic-gate 	{ gettext("nzt"),	tZONE,     -HOUR(12) },	/* New Zealand */
5870Sstevel@tonic-gate 	{ gettext("nzst"),	tZONE,     -HOUR(12) },	/* New Zealand Standard */
5880Sstevel@tonic-gate 	{ gettext("nzdt"),	tDAYZONE,  -HOUR(12) },	/* New Zealand Daylight */
5890Sstevel@tonic-gate 	{ gettext("idle"),	tZONE,     -HOUR(12) },	/* International Date Line East */
5900Sstevel@tonic-gate 	{  NULL  }
5910Sstevel@tonic-gate };
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate /* ARGSUSED */
5940Sstevel@tonic-gate static int
yyerror(s)5950Sstevel@tonic-gate yyerror(s)
596*2881Smp153739     char	*s;
5970Sstevel@tonic-gate {
598*2881Smp153739   return 0;
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate static time_t
ToSeconds(Hours,Minutes,Seconds,Meridian)603*2881Smp153739 ToSeconds(Hours, Minutes, Seconds, Meridian)
604*2881Smp153739     time_t	Hours;
605*2881Smp153739     time_t	Minutes;
606*2881Smp153739     time_t	Seconds;
607*2881Smp153739     MERIDIAN	Meridian;
6080Sstevel@tonic-gate {
609*2881Smp153739     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
610*2881Smp153739 	return -1;
611*2881Smp153739     switch (Meridian) {
612*2881Smp153739     case MER24:
613*2881Smp153739 	if (Hours < 0 || Hours > 23)
614*2881Smp153739 	    return -1;
615*2881Smp153739 	return (Hours * 60L + Minutes) * 60L + Seconds;
616*2881Smp153739     case MERam:
617*2881Smp153739 	if (Hours < 1 || Hours > 12)
618*2881Smp153739 	    return -1;
619*2881Smp153739 	return (Hours * 60L + Minutes) * 60L + Seconds;
620*2881Smp153739     case MERpm:
621*2881Smp153739 	if (Hours < 1 || Hours > 12)
622*2881Smp153739 	    return -1;
623*2881Smp153739 	return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
624*2881Smp153739     default:
625*2881Smp153739 	abort ();
626*2881Smp153739     }
627*2881Smp153739     /* NOTREACHED */
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate /*
6310Sstevel@tonic-gate  * From hh:mm:ss [am|pm] mm/dd/yy [tz], compute and return the number
6320Sstevel@tonic-gate  * of seconds since 00:00:00 1/1/70 GMT.
6330Sstevel@tonic-gate  */
6340Sstevel@tonic-gate static time_t
Convert(Month,Day,Year,Hours,Minutes,Seconds,Meridian,DSTmode)635*2881Smp153739 Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
636*2881Smp153739     time_t	Month;
637*2881Smp153739     time_t	Day;
638*2881Smp153739     time_t	Year;
639*2881Smp153739     time_t	Hours;
640*2881Smp153739     time_t	Minutes;
641*2881Smp153739     time_t	Seconds;
642*2881Smp153739     MERIDIAN	Meridian;
643*2881Smp153739     DSTMODE	DSTmode;
6440Sstevel@tonic-gate {
645*2881Smp153739     static int DaysInMonth[12] = {
646*2881Smp153739 	31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
647*2881Smp153739     };
648*2881Smp153739     time_t	tod;
649*2881Smp153739     time_t	Julian;
650*2881Smp153739     int		i;
6510Sstevel@tonic-gate 
652*2881Smp153739     if (Year < 0)
653*2881Smp153739 	Year = -Year;
654*2881Smp153739     if (Year < 1900)
655*2881Smp153739 	Year += 1900;
656*2881Smp153739     DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
657*2881Smp153739 		    ? 29 : 28;
658*2881Smp153739     if (Year < EPOCH
659*2881Smp153739 	|| Year > EPOCH_END
660*2881Smp153739 	|| Month < 1 || Month > 12
661*2881Smp153739 	/* Lint fluff:  "conversion from long may lose accuracy" */
662*2881Smp153739 	|| Day < 1 || Day > DaysInMonth[(int)--Month])
663*2881Smp153739 	 return -1;
6640Sstevel@tonic-gate 
665*2881Smp153739     for (Julian = Day - 1, i = 0; i < Month; i++)
666*2881Smp153739 	Julian += DaysInMonth[i];
667*2881Smp153739     for (i = EPOCH; i < Year; i++)
668*2881Smp153739 	 Julian += 365 + ((i % 4 == 0) && ((Year % 100 != 0) ||
669*2881Smp153739 					   (Year % 400 == 0)));
670*2881Smp153739     Julian *= SECSPERDAY;
671*2881Smp153739     Julian += yyTimezone * 60L;
672*2881Smp153739     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
673*2881Smp153739 	return -1;
674*2881Smp153739     Julian += tod;
675*2881Smp153739     if (DSTmode == DSTon
676*2881Smp153739      || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
677*2881Smp153739 	Julian -= 60 * 60;
678*2881Smp153739     return Julian;
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate static time_t
DSTcorrect(Start,Future)6830Sstevel@tonic-gate DSTcorrect(Start, Future)
684*2881Smp153739     time_t	Start;
685*2881Smp153739     time_t	Future;
6860Sstevel@tonic-gate {
687*2881Smp153739     time_t	StartDay;
688*2881Smp153739     time_t	FutureDay;
6890Sstevel@tonic-gate 
690*2881Smp153739     StartDay = (localtime(&Start)->tm_hour + 1) % 24;
691*2881Smp153739     FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
692*2881Smp153739     return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate static time_t
RelativeDate(Start,DayOrdinal,DayNumber)6970Sstevel@tonic-gate RelativeDate(Start, DayOrdinal, DayNumber)
698*2881Smp153739     time_t	Start;
699*2881Smp153739     time_t	DayOrdinal;
700*2881Smp153739     time_t	DayNumber;
7010Sstevel@tonic-gate {
702*2881Smp153739     struct tm	*tm;
703*2881Smp153739     time_t	now;
7040Sstevel@tonic-gate 
705*2881Smp153739     now = Start;
706*2881Smp153739     tm = localtime(&now);
707*2881Smp153739     now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
708*2881Smp153739     now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
709*2881Smp153739     return DSTcorrect(Start, now);
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate static time_t
RelativeMonth(Start,RelMonth)714*2881Smp153739 RelativeMonth(Start, RelMonth)
715*2881Smp153739     time_t	Start;
716*2881Smp153739     time_t	RelMonth;
7170Sstevel@tonic-gate {
718*2881Smp153739     struct tm	*tm;
719*2881Smp153739     time_t	Month;
720*2881Smp153739     time_t	Year;
721*2881Smp153739     time_t	ret;
7220Sstevel@tonic-gate 
723*2881Smp153739     if (RelMonth == 0)
724*2881Smp153739 	return 0;
725*2881Smp153739     tm = localtime(&Start);
726*2881Smp153739     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
727*2881Smp153739     Year = Month / 12;
728*2881Smp153739     Month = Month % 12 + 1;
7290Sstevel@tonic-gate     ret = Convert(Month, (time_t)tm->tm_mday, Year,
730*2881Smp153739 		  (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
731*2881Smp153739 		  MER24, DSTmaybe);
7320Sstevel@tonic-gate     if (ret == -1)
733*2881Smp153739       return ret;
7340Sstevel@tonic-gate     return DSTcorrect(Start, ret);
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate static int
LookupWord(buff)739*2881Smp153739 LookupWord(buff)
740*2881Smp153739     char		*buff;
7410Sstevel@tonic-gate {
742*2881Smp153739     register char	*p;
743*2881Smp153739     register char	*q;
744*2881Smp153739     register const TABLE	*tp;
745*2881Smp153739     int			i;
746*2881Smp153739     int			abbrev;
747*2881Smp153739 
748*2881Smp153739     /* Make it lowercase. */
749*2881Smp153739     for (p = buff; *p; p++)
750*2881Smp153739 	if (isupper((int) *p))
751*2881Smp153739 	    *p = tolower((int) *p);
7520Sstevel@tonic-gate 
753*2881Smp153739     if (strcmp(buff, gettext("am")) == 0 || strcmp(buff, gettext("a.m.")) == 0) {
754*2881Smp153739 	yylval.Meridian = MERam;
755*2881Smp153739 	return tMERIDIAN;
756*2881Smp153739     }
757*2881Smp153739     if (strcmp(buff, gettext("pm")) == 0 ||
758*2881Smp153739 	    strcmp(buff, gettext("p.m.")) == 0) {
759*2881Smp153739 	yylval.Meridian = MERpm;
760*2881Smp153739 	return tMERIDIAN;
761*2881Smp153739     }
7620Sstevel@tonic-gate 
763*2881Smp153739     /* See if we have an abbreviation for a month. */
764*2881Smp153739     if (strlen(buff) == 3)
765*2881Smp153739 	abbrev = 1;
766*2881Smp153739     else if (strlen(buff) == 4 && buff[3] == '.') {
767*2881Smp153739 	abbrev = 1;
768*2881Smp153739 	buff[3] = '\0';
769*2881Smp153739     }
770*2881Smp153739     else
771*2881Smp153739 	abbrev = 0;
772*2881Smp153739 
773*2881Smp153739     for (tp = MonthDayTable; tp->name; tp++) {
774*2881Smp153739 	if (abbrev) {
775*2881Smp153739 	    if (strncmp(buff, GETTEXT(tp->name), 3) == 0) {
776*2881Smp153739 		yylval.Number = tp->value;
777*2881Smp153739 		return tp->type;
778*2881Smp153739 	    }
7790Sstevel@tonic-gate 	}
780*2881Smp153739 	else if (strcmp(buff, GETTEXT(tp->name)) == 0) {
781*2881Smp153739 	    yylval.Number = tp->value;
782*2881Smp153739 	    return tp->type;
7830Sstevel@tonic-gate 	}
784*2881Smp153739     }
7850Sstevel@tonic-gate 
786*2881Smp153739     for (tp = TimezoneTable; tp->name; tp++)
787*2881Smp153739 	if (strcmp(buff, GETTEXT(tp->name)) == 0) {
788*2881Smp153739 	    yylval.Number = tp->value;
789*2881Smp153739 	    return tp->type;
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate 
792*2881Smp153739     if (strcmp(buff, gettext("dst")) == 0)
793*2881Smp153739 	return tDST;
7940Sstevel@tonic-gate 
795*2881Smp153739     for (tp = UnitsTable; tp->name; tp++)
796*2881Smp153739 	if (strcmp(buff, GETTEXT(tp->name)) == 0) {
797*2881Smp153739 	    yylval.Number = tp->value;
798*2881Smp153739 	    return tp->type;
799*2881Smp153739 	}
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate     /* Strip off any plural and try the units table again. */
802*2881Smp153739     i = strlen(buff) - 1;
803*2881Smp153739     if (buff[i] == 's') {
804*2881Smp153739 	buff[i] = '\0';
805*2881Smp153739 	for (tp = UnitsTable; tp->name; tp++)
806*2881Smp153739 	    if (strcmp(buff, GETTEXT(tp->name)) == 0) {
807*2881Smp153739 		yylval.Number = tp->value;
808*2881Smp153739 		return tp->type;
809*2881Smp153739 	    }
810*2881Smp153739 	buff[i] = 's';		/* Put back for "this" in OtherTable. */
811*2881Smp153739     }
812*2881Smp153739 
813*2881Smp153739     for (tp = OtherTable; tp->name; tp++)
814*2881Smp153739 	if (strcmp(buff, GETTEXT(tp->name)) == 0) {
815*2881Smp153739 	    yylval.Number = tp->value;
816*2881Smp153739 	    return tp->type;
8170Sstevel@tonic-gate 	}
8180Sstevel@tonic-gate 
819*2881Smp153739     /* Drop out any periods and try the timezone table again. */
820*2881Smp153739     for (i = 0, p = q = buff; *q; q++)
821*2881Smp153739 	if (*q != '.')
822*2881Smp153739 	    *p++ = *q;
823*2881Smp153739 	else
824*2881Smp153739 	    i++;
825*2881Smp153739     *p = '\0';
826*2881Smp153739     if (i)
827*2881Smp153739 	for (tp = TimezoneTable; tp->name; tp++)
828*2881Smp153739 	    if (strcmp(buff, GETTEXT(tp->name)) == 0) {
829*2881Smp153739 		yylval.Number = tp->value;
830*2881Smp153739 		return tp->type;
831*2881Smp153739 	    }
8320Sstevel@tonic-gate 
833*2881Smp153739     return tID;
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate static int
yylex()8380Sstevel@tonic-gate yylex()
8390Sstevel@tonic-gate {
840*2881Smp153739     register char	c;
841*2881Smp153739     register char	*p;
842*2881Smp153739     char		buff[20];
843*2881Smp153739     int			Count;
844*2881Smp153739     int			sign;
8450Sstevel@tonic-gate 
846*2881Smp153739     for ( ; ; ) {
847*2881Smp153739 	while (isspace((int) *yyInput))
848*2881Smp153739 	    yyInput++;
8490Sstevel@tonic-gate 
850*2881Smp153739 	c = *yyInput;
851*2881Smp153739 	if (isdigit((int) c) || c == '-' || c == '+') {
852*2881Smp153739 	    if (c == '-' || c == '+') {
853*2881Smp153739 		sign = c == '-' ? -1 : 1;
854*2881Smp153739 		if (!isdigit((int) (*++yyInput)))
855*2881Smp153739 		    /* skip the '-' sign */
856*2881Smp153739 		    continue;
857*2881Smp153739 	    }
858*2881Smp153739 	    else
859*2881Smp153739 		sign = 0;
860*2881Smp153739 	    for (yylval.Number = 0; isdigit((int) (c = *yyInput++)); )
861*2881Smp153739 		yylval.Number = 10 * yylval.Number + c - '0';
862*2881Smp153739 	    yyInput--;
863*2881Smp153739 	    if (sign < 0)
864*2881Smp153739 		yylval.Number = -yylval.Number;
865*2881Smp153739 	    return sign ? tSNUMBER : tUNUMBER;
8660Sstevel@tonic-gate 	}
867*2881Smp153739 	if (isalpha((int) c)) {
868*2881Smp153739 	    for (p = buff; isalpha((int) (c = *yyInput++)) || c == '.'; )
869*2881Smp153739 		if (p < &buff[sizeof buff - 1])
870*2881Smp153739 		    *p++ = c;
871*2881Smp153739 	    *p = '\0';
872*2881Smp153739 	    yyInput--;
873*2881Smp153739 	    return LookupWord(buff);
874*2881Smp153739 	}
875*2881Smp153739 	if (c != '(')
876*2881Smp153739 	    return *yyInput++;
877*2881Smp153739 	Count = 0;
878*2881Smp153739 	do {
879*2881Smp153739 	    c = *yyInput++;
880*2881Smp153739 	    if (c == '\0')
881*2881Smp153739 		return c;
882*2881Smp153739 	    if (c == '(')
883*2881Smp153739 		Count++;
884*2881Smp153739 	    else if (c == ')')
885*2881Smp153739 		Count--;
886*2881Smp153739 	} while (Count > 0);
887*2881Smp153739     }
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 
891*2881Smp153739 #define TM_YEAR_ORIGIN 1900
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate /* Yield A - B, measured in seconds.  */
8940Sstevel@tonic-gate static time_t
difftm(a,b)895*2881Smp153739 difftm(a, b)
896*2881Smp153739      struct tm *a, *b;
8970Sstevel@tonic-gate {
898*2881Smp153739   int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
899*2881Smp153739   int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
900*2881Smp153739   return
901*2881Smp153739     (
902*2881Smp153739      (
903*2881Smp153739       (
904*2881Smp153739        /* difference in day of year */
905*2881Smp153739        a->tm_yday - b->tm_yday
906*2881Smp153739        /* + intervening leap days */
907*2881Smp153739        +  ((ay >> 2) - (by >> 2))
908*2881Smp153739        -  (ay/100 - by/100)
909*2881Smp153739        +  ((ay/100 >> 2) - (by/100 >> 2))
910*2881Smp153739        /* + difference in years * 365 */
911*2881Smp153739        +  (time_t)(ay-by) * 365
912*2881Smp153739        )*24 + (a->tm_hour - b->tm_hour)
913*2881Smp153739       )*60 + (a->tm_min - b->tm_min)
914*2881Smp153739      )*60 + (a->tm_sec - b->tm_sec);
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
917*2881Smp153739 /* For get_date extern declaration compatibility check... yuck.  */
918*2881Smp153739 #include <krb5.h>
919*2881Smp153739 #include "kadmin.h"
920*2881Smp153739 
9210Sstevel@tonic-gate time_t
get_date(p)922*2881Smp153739 get_date(p)
923*2881Smp153739     char		*p;
9240Sstevel@tonic-gate {
925*2881Smp153739     struct my_timeb	*now = NULL;
926*2881Smp153739     struct tm		*tm, gmt;
927*2881Smp153739     struct my_timeb	ftz;
928*2881Smp153739     time_t		Start;
929*2881Smp153739     time_t		tod;
9300Sstevel@tonic-gate     time_t		delta;
9310Sstevel@tonic-gate 
932*2881Smp153739     yyInput = p;
933*2881Smp153739     if (now == NULL) {
934*2881Smp153739         now = &ftz;
9350Sstevel@tonic-gate 
936*2881Smp153739 	ftz.time = time((time_t *) 0);
9370Sstevel@tonic-gate 
938*2881Smp153739 	if (! (tm = gmtime (&ftz.time)))
939*2881Smp153739 	    return -1;
940*2881Smp153739 	gmt = *tm;	/* Make a copy, in case localtime modifies *tm.  */
941*2881Smp153739 	ftz.timezone = difftm (&gmt, localtime (&ftz.time)) / 60;
942*2881Smp153739     }
9430Sstevel@tonic-gate 
944*2881Smp153739     tm = localtime(&now->time);
945*2881Smp153739     yyYear = tm->tm_year;
946*2881Smp153739     yyMonth = tm->tm_mon + 1;
947*2881Smp153739     yyDay = tm->tm_mday;
948*2881Smp153739     yyTimezone = now->timezone;
949*2881Smp153739     yyDSTmode = DSTmaybe;
950*2881Smp153739     yyHour = 0;
951*2881Smp153739     yyMinutes = 0;
952*2881Smp153739     yySeconds = 0;
953*2881Smp153739     yyMeridian = MER24;
954*2881Smp153739     yyRelSeconds = 0;
955*2881Smp153739     yyRelMonth = 0;
956*2881Smp153739     yyHaveDate = 0;
957*2881Smp153739     yyHaveDay = 0;
958*2881Smp153739     yyHaveRel = 0;
959*2881Smp153739     yyHaveTime = 0;
960*2881Smp153739     yyHaveZone = 0;
9610Sstevel@tonic-gate 
962*2881Smp153739     /*
963*2881Smp153739      * When yyparse returns, zero or more of yyHave{Time,Zone,Date,Day,Rel}
964*2881Smp153739      * will have been incremented.  The value is number of items of
965*2881Smp153739      * that type that were found; for all but Rel, more than one is
966*2881Smp153739      * illegal.
967*2881Smp153739      *
968*2881Smp153739      * For each yyHave indicator, the following values are set:
969*2881Smp153739      *
970*2881Smp153739      * yyHaveTime:
971*2881Smp153739      *	yyHour, yyMinutes, yySeconds: hh:mm:ss specified, initialized
972*2881Smp153739      *				      to zeros above
973*2881Smp153739      *	yyMeridian: MERam, MERpm, or MER24
974*2881Smp153739      *	yyTimeZone: time zone specified in minutes
975*2881Smp153739      *  yyDSTmode: DSToff if yyTimeZone is set, otherwise unchanged
976*2881Smp153739      *		   (initialized above to DSTmaybe)
977*2881Smp153739      *
978*2881Smp153739      * yyHaveZone:
979*2881Smp153739      *  yyTimezone: as above
980*2881Smp153739      *  yyDSTmode: DSToff if a non-DST zone is specified, otherwise DSTon
981*2881Smp153739      *	XXX don't understand interaction with yyHaveTime zone info
982*2881Smp153739      *
983*2881Smp153739      * yyHaveDay:
984*2881Smp153739      *	yyDayNumber: 0-6 for Sunday-Saturday
985*2881Smp153739      *  yyDayOrdinal: val specified with day ("second monday",
986*2881Smp153739      *		      Ordinal=2), otherwise 1
987*2881Smp153739      *
988*2881Smp153739      * yyHaveDate:
989*2881Smp153739      *	yyMonth, yyDay, yyYear: mm/dd/yy specified, initialized to
990*2881Smp153739      *				today above
991*2881Smp153739      *
992*2881Smp153739      * yyHaveRel:
993*2881Smp153739      *	yyRelSeconds: seconds specified with MINUTE_UNITs ("3 hours") or
994*2881Smp153739      *		      SEC_UNITs ("30 seconds")
995*2881Smp153739      *  yyRelMonth: months specified with MONTH_UNITs ("3 months", "1
996*2881Smp153739      *		     year")
997*2881Smp153739      *
998*2881Smp153739      * The code following yyparse turns these values into a single
999*2881Smp153739      * date stamp.
1000*2881Smp153739      */
1001*2881Smp153739     if (yyparse()
1002*2881Smp153739      || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
1003*2881Smp153739 	return -1;
10040Sstevel@tonic-gate 
1005*2881Smp153739     /*
1006*2881Smp153739      * If an absolute time specified, set Start to the equivalent Unix
1007*2881Smp153739      * timestamp.  Otherwise, set Start to now, and if we do not have
1008*2881Smp153739      * a relatime time (ie: only yyHaveZone), decrement Start to the
1009*2881Smp153739      * beginning of today.
1010*2881Smp153739      *
1011*2881Smp153739      * By having yyHaveDay in the "absolute" list, "next Monday" means
1012*2881Smp153739      * midnight next Monday.  Otherwise, "next Monday" would mean the
1013*2881Smp153739      * time right now, next Monday.  It's not clear to me why the
1014*2881Smp153739      * current behavior is preferred.
1015*2881Smp153739      */
1016*2881Smp153739     if (yyHaveDate || yyHaveTime || yyHaveDay) {
1017*2881Smp153739 	Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
1018*2881Smp153739 		    yyMeridian, yyDSTmode);
1019*2881Smp153739 	if (Start < 0)
1020*2881Smp153739 	    return -1;
1021*2881Smp153739     }
1022*2881Smp153739     else {
1023*2881Smp153739 	Start = now->time;
1024*2881Smp153739 	if (!yyHaveRel)
1025*2881Smp153739 	    Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
1026*2881Smp153739     }
10270Sstevel@tonic-gate 
1028*2881Smp153739     /*
1029*2881Smp153739      * Add in the relative time specified.  RelativeMonth adds in the
1030*2881Smp153739      * months, accounting for the fact that the actual length of "3
1031*2881Smp153739      * months" depends on where you start counting.
1032*2881Smp153739      *
1033*2881Smp153739      * XXX By having this separate from the previous block, we are
1034*2881Smp153739      * allowing dates like "10:00am 3 months", which means 3 months
1035*2881Smp153739      * from 10:00am today, or even "1/1/99 two days" which means two
1036*2881Smp153739      * days after 1/1/99.
1037*2881Smp153739      *
1038*2881Smp153739      * XXX Shouldn't this only be done if yyHaveRel, just for
1039*2881Smp153739      * thoroughness?
1040*2881Smp153739      */
1041*2881Smp153739     Start += yyRelSeconds;
10420Sstevel@tonic-gate     delta = RelativeMonth(Start, yyRelMonth);
10430Sstevel@tonic-gate     if (delta == (time_t) -1)
1044*2881Smp153739       return -1;
10450Sstevel@tonic-gate     Start += delta;
10460Sstevel@tonic-gate 
1047*2881Smp153739     /*
1048*2881Smp153739      * Now, if you specified a day of week and counter, add it in.  By
1049*2881Smp153739      * disallowing Date but allowing Time, you can say "5pm next
1050*2881Smp153739      * monday".
1051*2881Smp153739      *
1052*2881Smp153739      * XXX The yyHaveDay && !yyHaveDate restriction should be enforced
1053*2881Smp153739      * above and be able to cause failure.
1054*2881Smp153739      */
1055*2881Smp153739     if (yyHaveDay && !yyHaveDate) {
1056*2881Smp153739 	tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
1057*2881Smp153739 	Start += tod;
1058*2881Smp153739     }
10590Sstevel@tonic-gate 
1060*2881Smp153739     /* Have to do *something* with a legitimate -1 so it's distinguishable
1061*2881Smp153739      * from the error return value.  (Alternately could set errno on error.) */
1062*2881Smp153739     return Start == -1 ? 0 : Start;
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate #if	defined(TEST)
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate /* ARGSUSED */
main(ac,av)1069*2881Smp153739 main(ac, av)
1070*2881Smp153739     int		ac;
1071*2881Smp153739     char	*av[];
10720Sstevel@tonic-gate {
1073*2881Smp153739     char	buff[128];
1074*2881Smp153739     time_t	d;
10750Sstevel@tonic-gate 
1076*2881Smp153739     (void)printf(gettext("Enter date, or blank line to exit.\n\t> "));
1077*2881Smp153739     (void)fflush(stdout);
1078*2881Smp153739     while (gets(buff) && buff[0]) {
1079*2881Smp153739 	d = get_date(buff, (struct my_timeb *)NULL);
1080*2881Smp153739 	if (d == -1)
1081*2881Smp153739 	    (void)printf(
1082*2881Smp153739 				gettext("Bad format - couldn't convert.\n"));
1083*2881Smp153739 	else
1084*2881Smp153739 	    (void)printf("%s", ctime(&d));
1085*2881Smp153739 	(void)printf("\t> ");
10860Sstevel@tonic-gate 	(void)fflush(stdout);
1087*2881Smp153739     }
1088*2881Smp153739     exit(0);
1089*2881Smp153739     /* NOTREACHED */
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate #endif	/* defined(TEST) */
1092