. add bsd-style MLINKS to minix man set, restoring aliases (e.g. man add64 -> int64) . update daily cron script to run makewhatis and restore makewhatis in man Makefile (makedb), restores functionality of man -k . netbsd imports of man, mdocml, makewhatis, libutil, apropos . update man.conf with manpage locations, restoring man [-s] <section> . throws out some obsolete manpages
		
			
				
	
	
		
			1061 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1061 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
%{
 | 
						||
/*
 | 
						||
**  Originally written by Steven M. Bellovin <smb@research.att.com> while
 | 
						||
**  at the University of North Carolina at Chapel Hill.  Later tweaked by
 | 
						||
**  a couple of people on Usenet.  Completely overhauled by Rich $alz
 | 
						||
**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
 | 
						||
**
 | 
						||
**  This grammar has 10 shift/reduce conflicts.
 | 
						||
**
 | 
						||
**  This code is in the public domain and has no copyright.
 | 
						||
*/
 | 
						||
/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
 | 
						||
/* SUPPRESS 288 on yyerrlab *//* Label unused */
 | 
						||
 | 
						||
#include <stdio.h>
 | 
						||
#include <ctype.h>
 | 
						||
#include <string.h>
 | 
						||
#include <time.h>
 | 
						||
#include <util.h>
 | 
						||
#include <stdlib.h>
 | 
						||
 | 
						||
/* NOTES on rebuilding parsedate.c (particularly for inclusion in CVS
 | 
						||
   releases):
 | 
						||
 | 
						||
   We don't want to mess with all the portability hassles of alloca.
 | 
						||
   In particular, most (all?) versions of bison will use alloca in
 | 
						||
   their parser.  If bison works on your system (e.g. it should work
 | 
						||
   with gcc), then go ahead and use it, but the more general solution
 | 
						||
   is to use byacc instead of bison, which should generate a portable
 | 
						||
   parser.  I played with adding "#define alloca dont_use_alloca", to
 | 
						||
   give an error if the parser generator uses alloca (and thus detect
 | 
						||
   unportable parsedate.c's), but that seems to cause as many problems
 | 
						||
   as it solves.  */
 | 
						||
 | 
						||
#define EPOCH		1970
 | 
						||
#define HOUR(x)		((time_t)(x) * 60)
 | 
						||
#define SECSPERDAY	(24L * 60L * 60L)
 | 
						||
 | 
						||
 | 
						||
/*
 | 
						||
**  An entry in the lexical lookup table.
 | 
						||
*/
 | 
						||
typedef struct _TABLE {
 | 
						||
    const char	*name;
 | 
						||
    int		type;
 | 
						||
    time_t	value;
 | 
						||
} TABLE;
 | 
						||
 | 
						||
 | 
						||
/*
 | 
						||
**  Daylight-savings mode:  on, off, or not yet known.
 | 
						||
*/
 | 
						||
typedef enum _DSTMODE {
 | 
						||
    DSTon, DSToff, DSTmaybe
 | 
						||
} DSTMODE;
 | 
						||
 | 
						||
/*
 | 
						||
**  Meridian:  am, pm, or 24-hour style.
 | 
						||
*/
 | 
						||
typedef enum _MERIDIAN {
 | 
						||
    MERam, MERpm, MER24
 | 
						||
} MERIDIAN;
 | 
						||
 | 
						||
 | 
						||
struct dateinfo {
 | 
						||
	DSTMODE	yyDSTmode;
 | 
						||
	time_t	yyDayOrdinal;
 | 
						||
	time_t	yyDayNumber;
 | 
						||
	int	yyHaveDate;
 | 
						||
	int	yyHaveDay;
 | 
						||
	int	yyHaveRel;
 | 
						||
	int	yyHaveTime;
 | 
						||
	int	yyHaveZone;
 | 
						||
	time_t	yyTimezone;
 | 
						||
	time_t	yyDay;
 | 
						||
	time_t	yyHour;
 | 
						||
	time_t	yyMinutes;
 | 
						||
	time_t	yyMonth;
 | 
						||
	time_t	yySeconds;
 | 
						||
	time_t	yyYear;
 | 
						||
	MERIDIAN	yyMeridian;
 | 
						||
	time_t	yyRelMonth;
 | 
						||
	time_t	yyRelSeconds;
 | 
						||
};
 | 
						||
%}
 | 
						||
 | 
						||
%union {
 | 
						||
    time_t		Number;
 | 
						||
    enum _MERIDIAN	Meridian;
 | 
						||
}
 | 
						||
 | 
						||
%token	tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
 | 
						||
%token	tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST AT_SIGN
 | 
						||
 | 
						||
%type	<Number>	tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
 | 
						||
%type	<Number>	tSEC_UNIT tSNUMBER tUNUMBER tZONE
 | 
						||
%type	<Meridian>	tMERIDIAN o_merid
 | 
						||
 | 
						||
%parse-param	{ struct dateinfo *param }
 | 
						||
%parse-param 	{ const char **yyInput }
 | 
						||
%lex-param	{ const char **yyInput }
 | 
						||
%pure-parser
 | 
						||
 | 
						||
%%
 | 
						||
 | 
						||
spec	: /* NULL */
 | 
						||
	| spec item
 | 
						||
	;
 | 
						||
 | 
						||
item	: time {
 | 
						||
	    param->yyHaveTime++;
 | 
						||
	}
 | 
						||
	| zone {
 | 
						||
	    param->yyHaveZone++;
 | 
						||
	}
 | 
						||
	| date {
 | 
						||
	    param->yyHaveDate++;
 | 
						||
	}
 | 
						||
	| day {
 | 
						||
	    param->yyHaveDay++;
 | 
						||
	}
 | 
						||
	| rel {
 | 
						||
	    param->yyHaveRel++;
 | 
						||
	}
 | 
						||
	| cvsstamp {
 | 
						||
	    param->yyHaveTime++;
 | 
						||
	    param->yyHaveDate++;
 | 
						||
	    param->yyHaveZone++;
 | 
						||
	}
 | 
						||
	| epochdate {
 | 
						||
	    param->yyHaveTime++;
 | 
						||
	    param->yyHaveDate++;
 | 
						||
	    param->yyHaveZone++;
 | 
						||
	}
 | 
						||
	| number
 | 
						||
	;
 | 
						||
 | 
						||
cvsstamp: tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER {
 | 
						||
	    param->yyYear = $1;
 | 
						||
	    if (param->yyYear < 100) param->yyYear += 1900;
 | 
						||
	    param->yyMonth = $3;
 | 
						||
	    param->yyDay = $5;
 | 
						||
	    param->yyHour = $7;
 | 
						||
	    param->yyMinutes = $9;
 | 
						||
	    param->yySeconds = $11;
 | 
						||
	    param->yyDSTmode = DSToff;
 | 
						||
	    param->yyTimezone = 0;
 | 
						||
	}
 | 
						||
	;
 | 
						||
 | 
						||
epochdate: AT_SIGN tUNUMBER {
 | 
						||
            time_t    when = $2;
 | 
						||
            struct tm tmbuf;
 | 
						||
            if (gmtime_r(&when, &tmbuf) != NULL) {
 | 
						||
		param->yyYear = tmbuf.tm_year + 1900;
 | 
						||
		param->yyMonth = tmbuf.tm_mon + 1;
 | 
						||
		param->yyDay = tmbuf.tm_mday;
 | 
						||
 | 
						||
		param->yyHour = tmbuf.tm_hour;
 | 
						||
		param->yyMinutes = tmbuf.tm_min;
 | 
						||
		param->yySeconds = tmbuf.tm_sec;
 | 
						||
	    } else {
 | 
						||
		param->yyYear = EPOCH;
 | 
						||
		param->yyMonth = 1;
 | 
						||
		param->yyDay = 1;
 | 
						||
 | 
						||
		param->yyHour = 0;
 | 
						||
		param->yyMinutes = 0;
 | 
						||
		param->yySeconds = 0;
 | 
						||
	    }
 | 
						||
	    param->yyDSTmode = DSToff;
 | 
						||
	    param->yyTimezone = 0;
 | 
						||
	}
 | 
						||
	;
 | 
						||
 | 
						||
time	: tUNUMBER tMERIDIAN {
 | 
						||
	    param->yyHour = $1;
 | 
						||
	    param->yyMinutes = 0;
 | 
						||
	    param->yySeconds = 0;
 | 
						||
	    param->yyMeridian = $2;
 | 
						||
	}
 | 
						||
	| tUNUMBER ':' tUNUMBER o_merid {
 | 
						||
	    param->yyHour = $1;
 | 
						||
	    param->yyMinutes = $3;
 | 
						||
	    param->yySeconds = 0;
 | 
						||
	    param->yyMeridian = $4;
 | 
						||
	}
 | 
						||
	| tUNUMBER ':' tUNUMBER tSNUMBER {
 | 
						||
	    param->yyHour = $1;
 | 
						||
	    param->yyMinutes = $3;
 | 
						||
	    param->yyMeridian = MER24;
 | 
						||
	    param->yyDSTmode = DSToff;
 | 
						||
	    param->yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
 | 
						||
	}
 | 
						||
	| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
 | 
						||
	    param->yyHour = $1;
 | 
						||
	    param->yyMinutes = $3;
 | 
						||
	    param->yySeconds = $5;
 | 
						||
	    param->yyMeridian = $6;
 | 
						||
	}
 | 
						||
	| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
 | 
						||
	    param->yyHour = $1;
 | 
						||
	    param->yyMinutes = $3;
 | 
						||
	    param->yySeconds = $5;
 | 
						||
	    param->yyMeridian = MER24;
 | 
						||
	    param->yyDSTmode = DSToff;
 | 
						||
	    param->yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
 | 
						||
	}
 | 
						||
	| tUNUMBER ':' tUNUMBER ':' tUNUMBER '.' tUNUMBER {
 | 
						||
	    param->yyHour = $1;
 | 
						||
	    param->yyMinutes = $3;
 | 
						||
	    param->yySeconds = $5;
 | 
						||
	    param->yyMeridian = MER24;
 | 
						||
	    param->yyDSTmode = DSToff;
 | 
						||
/* XXX: Do nothing with millis */
 | 
						||
/*	    param->yyTimezone = ($7 % 100 + ($7 / 100) * 60); */
 | 
						||
	}
 | 
						||
	;
 | 
						||
 | 
						||
zone	: tZONE {
 | 
						||
	    param->yyTimezone = $1;
 | 
						||
	    param->yyDSTmode = DSToff;
 | 
						||
	}
 | 
						||
	| tDAYZONE {
 | 
						||
	    param->yyTimezone = $1;
 | 
						||
	    param->yyDSTmode = DSTon;
 | 
						||
	}
 | 
						||
	|
 | 
						||
	  tZONE tDST {
 | 
						||
	    param->yyTimezone = $1;
 | 
						||
	    param->yyDSTmode = DSTon;
 | 
						||
	}
 | 
						||
	;
 | 
						||
 | 
						||
day	: tDAY {
 | 
						||
	    param->yyDayOrdinal = 1;
 | 
						||
	    param->yyDayNumber = $1;
 | 
						||
	}
 | 
						||
	| tDAY ',' {
 | 
						||
	    param->yyDayOrdinal = 1;
 | 
						||
	    param->yyDayNumber = $1;
 | 
						||
	}
 | 
						||
	| tUNUMBER tDAY {
 | 
						||
	    param->yyDayOrdinal = $1;
 | 
						||
	    param->yyDayNumber = $2;
 | 
						||
	}
 | 
						||
	;
 | 
						||
 | 
						||
date	: tUNUMBER '/' tUNUMBER {
 | 
						||
	    param->yyMonth = $1;
 | 
						||
	    param->yyDay = $3;
 | 
						||
	}
 | 
						||
	| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
 | 
						||
	    if ($1 >= 100) {
 | 
						||
		param->yyYear = $1;
 | 
						||
		param->yyMonth = $3;
 | 
						||
		param->yyDay = $5;
 | 
						||
	    } else {
 | 
						||
		param->yyMonth = $1;
 | 
						||
		param->yyDay = $3;
 | 
						||
		param->yyYear = $5;
 | 
						||
	    }
 | 
						||
	}
 | 
						||
	| tUNUMBER tSNUMBER tSNUMBER {
 | 
						||
	    /* ISO 8601 format.  yyyy-mm-dd.  */
 | 
						||
	    param->yyYear = $1;
 | 
						||
	    param->yyMonth = -$2;
 | 
						||
	    param->yyDay = -$3;
 | 
						||
	}
 | 
						||
	| tUNUMBER tMONTH tSNUMBER {
 | 
						||
	    /* e.g. 17-JUN-1992.  */
 | 
						||
	    param->yyDay = $1;
 | 
						||
	    param->yyMonth = $2;
 | 
						||
	    param->yyYear = -$3;
 | 
						||
	}
 | 
						||
	| tMONTH tUNUMBER {
 | 
						||
	    param->yyMonth = $1;
 | 
						||
	    param->yyDay = $2;
 | 
						||
	}
 | 
						||
	| tMONTH tUNUMBER ',' tUNUMBER {
 | 
						||
	    param->yyMonth = $1;
 | 
						||
	    param->yyDay = $2;
 | 
						||
	    param->yyYear = $4;
 | 
						||
	}
 | 
						||
	| tUNUMBER tMONTH {
 | 
						||
	    param->yyMonth = $2;
 | 
						||
	    param->yyDay = $1;
 | 
						||
	}
 | 
						||
	| tUNUMBER tMONTH tUNUMBER {
 | 
						||
	    param->yyMonth = $2;
 | 
						||
	    param->yyDay = $1;
 | 
						||
	    param->yyYear = $3;
 | 
						||
	}
 | 
						||
	;
 | 
						||
 | 
						||
rel	: relunit tAGO {
 | 
						||
	    param->yyRelSeconds = -param->yyRelSeconds;
 | 
						||
	    param->yyRelMonth = -param->yyRelMonth;
 | 
						||
	}
 | 
						||
	| relunit
 | 
						||
	;
 | 
						||
 | 
						||
relunit	: tUNUMBER tMINUTE_UNIT {
 | 
						||
	    param->yyRelSeconds += $1 * $2 * 60L;
 | 
						||
	}
 | 
						||
	| tSNUMBER tMINUTE_UNIT {
 | 
						||
	    param->yyRelSeconds += $1 * $2 * 60L;
 | 
						||
	}
 | 
						||
	| tMINUTE_UNIT {
 | 
						||
	    param->yyRelSeconds += $1 * 60L;
 | 
						||
	}
 | 
						||
	| tSNUMBER tSEC_UNIT {
 | 
						||
	    param->yyRelSeconds += $1;
 | 
						||
	}
 | 
						||
	| tUNUMBER tSEC_UNIT {
 | 
						||
	    param->yyRelSeconds += $1;
 | 
						||
	}
 | 
						||
	| tSEC_UNIT {
 | 
						||
	    param->yyRelSeconds++;
 | 
						||
	}
 | 
						||
	| tSNUMBER tMONTH_UNIT {
 | 
						||
	    param->yyRelMonth += $1 * $2;
 | 
						||
	}
 | 
						||
	| tUNUMBER tMONTH_UNIT {
 | 
						||
	    param->yyRelMonth += $1 * $2;
 | 
						||
	}
 | 
						||
	| tMONTH_UNIT {
 | 
						||
	    param->yyRelMonth += $1;
 | 
						||
	}
 | 
						||
	;
 | 
						||
 | 
						||
number	: tUNUMBER {
 | 
						||
	    if (param->yyHaveTime && param->yyHaveDate && !param->yyHaveRel)
 | 
						||
		param->yyYear = $1;
 | 
						||
	    else {
 | 
						||
		if($1>10000) {
 | 
						||
		    param->yyHaveDate++;
 | 
						||
		    param->yyDay= ($1)%100;
 | 
						||
		    param->yyMonth= ($1/100)%100;
 | 
						||
		    param->yyYear = $1/10000;
 | 
						||
		}
 | 
						||
		else {
 | 
						||
		    param->yyHaveTime++;
 | 
						||
		    if ($1 < 100) {
 | 
						||
			param->yyHour = $1;
 | 
						||
			param->yyMinutes = 0;
 | 
						||
		    }
 | 
						||
		    else {
 | 
						||
		    	param->yyHour = $1 / 100;
 | 
						||
		    	param->yyMinutes = $1 % 100;
 | 
						||
		    }
 | 
						||
		    param->yySeconds = 0;
 | 
						||
		    param->yyMeridian = MER24;
 | 
						||
	        }
 | 
						||
	    }
 | 
						||
	}
 | 
						||
	;
 | 
						||
 | 
						||
o_merid	: /* NULL */ {
 | 
						||
	    $$ = MER24;
 | 
						||
	}
 | 
						||
	| tMERIDIAN {
 | 
						||
	    $$ = $1;
 | 
						||
	}
 | 
						||
	;
 | 
						||
 | 
						||
%%
 | 
						||
 | 
						||
/* Month and day table. */
 | 
						||
static const TABLE const MonthDayTable[] = {
 | 
						||
    { "january",	tMONTH,  1 },
 | 
						||
    { "february",	tMONTH,  2 },
 | 
						||
    { "march",		tMONTH,  3 },
 | 
						||
    { "april",		tMONTH,  4 },
 | 
						||
    { "may",		tMONTH,  5 },
 | 
						||
    { "june",		tMONTH,  6 },
 | 
						||
    { "july",		tMONTH,  7 },
 | 
						||
    { "august",		tMONTH,  8 },
 | 
						||
    { "september",	tMONTH,  9 },
 | 
						||
    { "sept",		tMONTH,  9 },
 | 
						||
    { "october",	tMONTH, 10 },
 | 
						||
    { "november",	tMONTH, 11 },
 | 
						||
    { "december",	tMONTH, 12 },
 | 
						||
    { "sunday",		tDAY, 0 },
 | 
						||
    { "monday",		tDAY, 1 },
 | 
						||
    { "tuesday",	tDAY, 2 },
 | 
						||
    { "tues",		tDAY, 2 },
 | 
						||
    { "wednesday",	tDAY, 3 },
 | 
						||
    { "wednes",		tDAY, 3 },
 | 
						||
    { "thursday",	tDAY, 4 },
 | 
						||
    { "thur",		tDAY, 4 },
 | 
						||
    { "thurs",		tDAY, 4 },
 | 
						||
    { "friday",		tDAY, 5 },
 | 
						||
    { "saturday",	tDAY, 6 },
 | 
						||
    { NULL,		0,    0 }
 | 
						||
};
 | 
						||
 | 
						||
/* Time units table. */
 | 
						||
static const TABLE const UnitsTable[] = {
 | 
						||
    { "year",		tMONTH_UNIT,	12 },
 | 
						||
    { "month",		tMONTH_UNIT,	1 },
 | 
						||
    { "fortnight",	tMINUTE_UNIT,	14 * 24 * 60 },
 | 
						||
    { "week",		tMINUTE_UNIT,	7 * 24 * 60 },
 | 
						||
    { "day",		tMINUTE_UNIT,	1 * 24 * 60 },
 | 
						||
    { "hour",		tMINUTE_UNIT,	60 },
 | 
						||
    { "minute",		tMINUTE_UNIT,	1 },
 | 
						||
    { "min",		tMINUTE_UNIT,	1 },
 | 
						||
    { "second",		tSEC_UNIT,	1 },
 | 
						||
    { "sec",		tSEC_UNIT,	1 },
 | 
						||
    { NULL,		0,		0 }
 | 
						||
};
 | 
						||
 | 
						||
/* Assorted relative-time words. */
 | 
						||
static const TABLE const OtherTable[] = {
 | 
						||
    { "tomorrow",	tMINUTE_UNIT,	1 * 24 * 60 },
 | 
						||
    { "yesterday",	tMINUTE_UNIT,	-1 * 24 * 60 },
 | 
						||
    { "today",		tMINUTE_UNIT,	0 },
 | 
						||
    { "now",		tMINUTE_UNIT,	0 },
 | 
						||
    { "last",		tUNUMBER,	-1 },
 | 
						||
    { "this",		tMINUTE_UNIT,	0 },
 | 
						||
    { "next",		tUNUMBER,	2 },
 | 
						||
    { "first",		tUNUMBER,	1 },
 | 
						||
    { "one",		tUNUMBER,	1 },
 | 
						||
/*  { "second",		tUNUMBER,	2 }, */
 | 
						||
    { "two",		tUNUMBER,	2 },
 | 
						||
    { "third",		tUNUMBER,	3 },
 | 
						||
    { "three",		tUNUMBER,	3 },
 | 
						||
    { "fourth",		tUNUMBER,	4 },
 | 
						||
    { "four",		tUNUMBER,	4 },
 | 
						||
    { "fifth",		tUNUMBER,	5 },
 | 
						||
    { "five",		tUNUMBER,	5 },
 | 
						||
    { "sixth",		tUNUMBER,	6 },
 | 
						||
    { "six",		tUNUMBER,	6 },
 | 
						||
    { "seventh",	tUNUMBER,	7 },
 | 
						||
    { "seven",		tUNUMBER,	7 },
 | 
						||
    { "eighth",		tUNUMBER,	8 },
 | 
						||
    { "eight",		tUNUMBER,	8 },
 | 
						||
    { "ninth",		tUNUMBER,	9 },
 | 
						||
    { "nine",		tUNUMBER,	9 },
 | 
						||
    { "tenth",		tUNUMBER,	10 },
 | 
						||
    { "ten",		tUNUMBER,	10 },
 | 
						||
    { "eleventh",	tUNUMBER,	11 },
 | 
						||
    { "eleven",		tUNUMBER,	11 },
 | 
						||
    { "twelfth",	tUNUMBER,	12 },
 | 
						||
    { "twelve",		tUNUMBER,	12 },
 | 
						||
    { "ago",		tAGO,	1 },
 | 
						||
    { NULL,		0,	0 }
 | 
						||
};
 | 
						||
 | 
						||
/* The timezone table. */
 | 
						||
/* Some of these are commented out because a time_t can't store a float. */
 | 
						||
static const TABLE const TimezoneTable[] = {
 | 
						||
    { "gmt",	tZONE,     HOUR( 0) },	/* Greenwich Mean */
 | 
						||
    { "ut",	tZONE,     HOUR( 0) },	/* Universal (Coordinated) */
 | 
						||
    { "utc",	tZONE,     HOUR( 0) },
 | 
						||
    { "wet",	tZONE,     HOUR( 0) },	/* Western European */
 | 
						||
    { "bst",	tDAYZONE,  HOUR( 0) },	/* British Summer */
 | 
						||
    { "wat",	tZONE,     HOUR( 1) },	/* West Africa */
 | 
						||
    { "at",	tZONE,     HOUR( 2) },	/* Azores */
 | 
						||
#if	0
 | 
						||
    /* For completeness.  BST is also British Summer, and GST is
 | 
						||
     * also Guam Standard. */
 | 
						||
    { "bst",	tZONE,     HOUR( 3) },	/* Brazil Standard */
 | 
						||
    { "gst",	tZONE,     HOUR( 3) },	/* Greenland Standard */
 | 
						||
#endif
 | 
						||
#if 0
 | 
						||
    { "nft",	tZONE,     HOUR(3.5) },	/* Newfoundland */
 | 
						||
    { "nst",	tZONE,     HOUR(3.5) },	/* Newfoundland Standard */
 | 
						||
    { "ndt",	tDAYZONE,  HOUR(3.5) },	/* Newfoundland Daylight */
 | 
						||
#endif
 | 
						||
    { "ast",	tZONE,     HOUR( 4) },	/* Atlantic Standard */
 | 
						||
    { "adt",	tDAYZONE,  HOUR( 4) },	/* Atlantic Daylight */
 | 
						||
    { "est",	tZONE,     HOUR( 5) },	/* Eastern Standard */
 | 
						||
    { "edt",	tDAYZONE,  HOUR( 5) },	/* Eastern Daylight */
 | 
						||
    { "cst",	tZONE,     HOUR( 6) },	/* Central Standard */
 | 
						||
    { "cdt",	tDAYZONE,  HOUR( 6) },	/* Central Daylight */
 | 
						||
    { "mst",	tZONE,     HOUR( 7) },	/* Mountain Standard */
 | 
						||
    { "mdt",	tDAYZONE,  HOUR( 7) },	/* Mountain Daylight */
 | 
						||
    { "pst",	tZONE,     HOUR( 8) },	/* Pacific Standard */
 | 
						||
    { "pdt",	tDAYZONE,  HOUR( 8) },	/* Pacific Daylight */
 | 
						||
    { "yst",	tZONE,     HOUR( 9) },	/* Yukon Standard */
 | 
						||
    { "ydt",	tDAYZONE,  HOUR( 9) },	/* Yukon Daylight */
 | 
						||
    { "hst",	tZONE,     HOUR(10) },	/* Hawaii Standard */
 | 
						||
    { "hdt",	tDAYZONE,  HOUR(10) },	/* Hawaii Daylight */
 | 
						||
    { "cat",	tZONE,     HOUR(10) },	/* Central Alaska */
 | 
						||
    { "ahst",	tZONE,     HOUR(10) },	/* Alaska-Hawaii Standard */
 | 
						||
    { "nt",	tZONE,     HOUR(11) },	/* Nome */
 | 
						||
    { "idlw",	tZONE,     HOUR(12) },	/* International Date Line West */
 | 
						||
    { "cet",	tZONE,     -HOUR(1) },	/* Central European */
 | 
						||
    { "met",	tZONE,     -HOUR(1) },	/* Middle European */
 | 
						||
    { "mewt",	tZONE,     -HOUR(1) },	/* Middle European Winter */
 | 
						||
    { "mest",	tDAYZONE,  -HOUR(1) },	/* Middle European Summer */
 | 
						||
    { "swt",	tZONE,     -HOUR(1) },	/* Swedish Winter */
 | 
						||
    { "sst",	tDAYZONE,  -HOUR(1) },	/* Swedish Summer */
 | 
						||
    { "fwt",	tZONE,     -HOUR(1) },	/* French Winter */
 | 
						||
    { "fst",	tDAYZONE,  -HOUR(1) },	/* French Summer */
 | 
						||
    { "eet",	tZONE,     -HOUR(2) },	/* Eastern Europe, USSR Zone 1 */
 | 
						||
    { "bt",	tZONE,     -HOUR(3) },	/* Baghdad, USSR Zone 2 */
 | 
						||
#if 0
 | 
						||
    { "it",	tZONE,     -HOUR(3.5) },/* Iran */
 | 
						||
#endif
 | 
						||
    { "zp4",	tZONE,     -HOUR(4) },	/* USSR Zone 3 */
 | 
						||
    { "zp5",	tZONE,     -HOUR(5) },	/* USSR Zone 4 */
 | 
						||
#if 0
 | 
						||
    { "ist",	tZONE,     -HOUR(5.5) },/* Indian Standard */
 | 
						||
#endif
 | 
						||
    { "zp6",	tZONE,     -HOUR(6) },	/* USSR Zone 5 */
 | 
						||
#if	0
 | 
						||
    /* For completeness.  NST is also Newfoundland Stanard, and SST is
 | 
						||
     * also Swedish Summer. */
 | 
						||
    { "nst",	tZONE,     -HOUR(6.5) },/* North Sumatra */
 | 
						||
    { "sst",	tZONE,     -HOUR(7) },	/* South Sumatra, USSR Zone 6 */
 | 
						||
#endif	/* 0 */
 | 
						||
    { "wast",	tZONE,     -HOUR(7) },	/* West Australian Standard */
 | 
						||
    { "wadt",	tDAYZONE,  -HOUR(7) },	/* West Australian Daylight */
 | 
						||
#if 0
 | 
						||
    { "jt",	tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
 | 
						||
#endif
 | 
						||
    { "cct",	tZONE,     -HOUR(8) },	/* China Coast, USSR Zone 7 */
 | 
						||
    { "jst",	tZONE,     -HOUR(9) },	/* Japan Standard, USSR Zone 8 */
 | 
						||
#if 0
 | 
						||
    { "cast",	tZONE,     -HOUR(9.5) },/* Central Australian Standard */
 | 
						||
    { "cadt",	tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
 | 
						||
#endif
 | 
						||
    { "east",	tZONE,     -HOUR(10) },	/* Eastern Australian Standard */
 | 
						||
    { "eadt",	tDAYZONE,  -HOUR(10) },	/* Eastern Australian Daylight */
 | 
						||
    { "gst",	tZONE,     -HOUR(10) },	/* Guam Standard, USSR Zone 9 */
 | 
						||
    { "nzt",	tZONE,     -HOUR(12) },	/* New Zealand */
 | 
						||
    { "nzst",	tZONE,     -HOUR(12) },	/* New Zealand Standard */
 | 
						||
    { "nzdt",	tDAYZONE,  -HOUR(12) },	/* New Zealand Daylight */
 | 
						||
    { "idle",	tZONE,     -HOUR(12) },	/* International Date Line East */
 | 
						||
    {  NULL,	0,	    0 }
 | 
						||
};
 | 
						||
 | 
						||
/* Military timezone table. */
 | 
						||
static const TABLE const MilitaryTable[] = {
 | 
						||
    { "a",	tZONE,	HOUR(  1) },
 | 
						||
    { "b",	tZONE,	HOUR(  2) },
 | 
						||
    { "c",	tZONE,	HOUR(  3) },
 | 
						||
    { "d",	tZONE,	HOUR(  4) },
 | 
						||
    { "e",	tZONE,	HOUR(  5) },
 | 
						||
    { "f",	tZONE,	HOUR(  6) },
 | 
						||
    { "g",	tZONE,	HOUR(  7) },
 | 
						||
    { "h",	tZONE,	HOUR(  8) },
 | 
						||
    { "i",	tZONE,	HOUR(  9) },
 | 
						||
    { "k",	tZONE,	HOUR( 10) },
 | 
						||
    { "l",	tZONE,	HOUR( 11) },
 | 
						||
    { "m",	tZONE,	HOUR( 12) },
 | 
						||
    { "n",	tZONE,	HOUR(- 1) },
 | 
						||
    { "o",	tZONE,	HOUR(- 2) },
 | 
						||
    { "p",	tZONE,	HOUR(- 3) },
 | 
						||
    { "q",	tZONE,	HOUR(- 4) },
 | 
						||
    { "r",	tZONE,	HOUR(- 5) },
 | 
						||
    { "s",	tZONE,	HOUR(- 6) },
 | 
						||
    { "t",	tZONE,	HOUR(- 7) },
 | 
						||
    { "u",	tZONE,	HOUR(- 8) },
 | 
						||
    { "v",	tZONE,	HOUR(- 9) },
 | 
						||
    { "w",	tZONE,	HOUR(-10) },
 | 
						||
    { "x",	tZONE,	HOUR(-11) },
 | 
						||
    { "y",	tZONE,	HOUR(-12) },
 | 
						||
    { "z",	tZONE,	HOUR(  0) },
 | 
						||
    { NULL,	0,	0 }
 | 
						||
};
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
/* ARGSUSED */
 | 
						||
static int
 | 
						||
yyerror(struct dateinfo *param, const char **inp, const char *s __unused)
 | 
						||
{
 | 
						||
  return 0;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
static time_t
 | 
						||
ToSeconds(
 | 
						||
    time_t	Hours,
 | 
						||
    time_t	Minutes,
 | 
						||
    time_t	Seconds,
 | 
						||
    MERIDIAN	Meridian
 | 
						||
)
 | 
						||
{
 | 
						||
    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
 | 
						||
	return -1;
 | 
						||
    switch (Meridian) {
 | 
						||
    case MER24:
 | 
						||
	if (Hours < 0 || Hours > 23)
 | 
						||
	    return -1;
 | 
						||
	return (Hours * 60L + Minutes) * 60L + Seconds;
 | 
						||
    case MERam:
 | 
						||
	if (Hours < 1 || Hours > 12)
 | 
						||
	    return -1;
 | 
						||
	if (Hours == 12)
 | 
						||
	    Hours = 0;
 | 
						||
	return (Hours * 60L + Minutes) * 60L + Seconds;
 | 
						||
    case MERpm:
 | 
						||
	if (Hours < 1 || Hours > 12)
 | 
						||
	    return -1;
 | 
						||
	if (Hours == 12)
 | 
						||
	    Hours = 0;
 | 
						||
	return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
 | 
						||
    default:
 | 
						||
	abort ();
 | 
						||
    }
 | 
						||
    /* NOTREACHED */
 | 
						||
}
 | 
						||
 | 
						||
static int
 | 
						||
isLeap(int year)
 | 
						||
{
 | 
						||
    return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/* Year is either
 | 
						||
   * A negative number, which means to use its absolute value (why?)
 | 
						||
   * A number from 0 to 99, which means a year from 1900 to 1999, or
 | 
						||
   * The actual year (>=100).  */
 | 
						||
static time_t
 | 
						||
Convert(
 | 
						||
    time_t	Month,
 | 
						||
    time_t	Day,
 | 
						||
    time_t	Year,
 | 
						||
    time_t	Hours,
 | 
						||
    time_t	Minutes,
 | 
						||
    time_t	Seconds,
 | 
						||
    time_t	Timezone,
 | 
						||
    MERIDIAN	Meridian,
 | 
						||
    DSTMODE	DSTmode
 | 
						||
)
 | 
						||
{
 | 
						||
    static int DaysInMonth[12] = {
 | 
						||
	31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 | 
						||
    };
 | 
						||
    time_t	tod;
 | 
						||
    time_t	Julian, oJulian;
 | 
						||
    int		i;
 | 
						||
 | 
						||
    /* XXX Y2K */
 | 
						||
    if (Year < 0)
 | 
						||
	Year = -Year;
 | 
						||
    if (Year < 70)
 | 
						||
	Year += 2000;
 | 
						||
    else if (Year < 100)
 | 
						||
	Year += 1900;
 | 
						||
    DaysInMonth[1] = isLeap(Year) ? 29 : 28;
 | 
						||
    if (Year < EPOCH || Month < 1 || Month > 12
 | 
						||
     /* Lint fluff:  "conversion from long may lose accuracy" */
 | 
						||
     || Day < 1 || Day > DaysInMonth[(int)--Month])
 | 
						||
	/* FIXME:
 | 
						||
	 * It would be nice to set a global error string here.
 | 
						||
	 * "February 30 is not a valid date" is much more informative than
 | 
						||
	 * "Can't parse date/time: 100 months" when the user input was
 | 
						||
	 * "100 months" and addition resolved that to February 30, for
 | 
						||
	 * example.  See rcs2-7 in src/sanity.sh for more. */
 | 
						||
	return -1;
 | 
						||
 | 
						||
    for (Julian = Day - 1, i = 0; i < Month; i++)
 | 
						||
	Julian += DaysInMonth[i];
 | 
						||
 | 
						||
    oJulian = Julian;
 | 
						||
    for (i = EPOCH; i < Year; i++) {
 | 
						||
	Julian += 365 + isLeap(i);
 | 
						||
	if (oJulian > Julian)
 | 
						||
	    return -1;
 | 
						||
	oJulian = Julian;
 | 
						||
    }
 | 
						||
 | 
						||
    Julian *= SECSPERDAY;
 | 
						||
    if (oJulian > Julian)
 | 
						||
	return -1;
 | 
						||
    oJulian = Julian;
 | 
						||
    Julian += Timezone * 60L;
 | 
						||
    if (Timezone > 0 && oJulian > Julian)
 | 
						||
	return -1;
 | 
						||
    oJulian = Julian;
 | 
						||
 | 
						||
    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
 | 
						||
	return -1;
 | 
						||
 | 
						||
    Julian += tod;
 | 
						||
    if (oJulian > Julian)
 | 
						||
	return -1;
 | 
						||
 | 
						||
    if (DSTmode == DSTon || (DSTmode == DSTmaybe)) {
 | 
						||
	struct tm  *tm;
 | 
						||
	if ((tm = localtime(&Julian)) == NULL)
 | 
						||
	    return -1;
 | 
						||
	if (tm->tm_isdst)
 | 
						||
	    Julian -= 60 * 60;
 | 
						||
    }
 | 
						||
    return Julian;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
static time_t
 | 
						||
DSTcorrect(
 | 
						||
    time_t	Start,
 | 
						||
    time_t	Future
 | 
						||
)
 | 
						||
{
 | 
						||
    time_t	StartDay;
 | 
						||
    time_t	FutureDay;
 | 
						||
    struct tm  *tm;
 | 
						||
 | 
						||
    if ((tm = localtime(&Start)) == NULL)
 | 
						||
	return -1;
 | 
						||
    StartDay = (tm->tm_hour + 1) % 24;
 | 
						||
 | 
						||
    if ((tm = localtime(&Future)) == NULL)
 | 
						||
	return -1;
 | 
						||
    FutureDay = (tm->tm_hour + 1) % 24;
 | 
						||
 | 
						||
    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
static time_t
 | 
						||
RelativeDate(
 | 
						||
    time_t	Start,
 | 
						||
    time_t	DayOrdinal,
 | 
						||
    time_t	DayNumber
 | 
						||
)
 | 
						||
{
 | 
						||
    struct tm	*tm;
 | 
						||
    time_t	now;
 | 
						||
 | 
						||
    now = Start;
 | 
						||
    tm = localtime(&now);
 | 
						||
    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
 | 
						||
    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
 | 
						||
    return DSTcorrect(Start, now);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
static time_t
 | 
						||
RelativeMonth(
 | 
						||
    time_t	Start,
 | 
						||
    time_t	RelMonth,
 | 
						||
    time_t	Timezone
 | 
						||
)
 | 
						||
{
 | 
						||
    struct tm	*tm;
 | 
						||
    time_t	Month;
 | 
						||
    time_t	Year;
 | 
						||
 | 
						||
    if (RelMonth == 0)
 | 
						||
	return 0;
 | 
						||
    tm = localtime(&Start);
 | 
						||
    if (tm == NULL)
 | 
						||
	return -1;
 | 
						||
    Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
 | 
						||
    Year = Month / 12;
 | 
						||
    Month = Month % 12 + 1;
 | 
						||
    return DSTcorrect(Start,
 | 
						||
	    Convert(Month, (time_t)tm->tm_mday, Year,
 | 
						||
		(time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
 | 
						||
		Timezone, MER24, DSTmaybe));
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
LookupWord(YYSTYPE *yylval, char *buff)
 | 
						||
{
 | 
						||
    register char	*p;
 | 
						||
    register char	*q;
 | 
						||
    register const TABLE	*tp;
 | 
						||
    int			i;
 | 
						||
    int			abbrev;
 | 
						||
 | 
						||
    /* Make it lowercase. */
 | 
						||
    for (p = buff; *p; p++)
 | 
						||
	if (isupper((unsigned char)*p))
 | 
						||
	    *p = tolower((unsigned char)*p);
 | 
						||
 | 
						||
    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
 | 
						||
	yylval->Meridian = MERam;
 | 
						||
	return tMERIDIAN;
 | 
						||
    }
 | 
						||
    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
 | 
						||
	yylval->Meridian = MERpm;
 | 
						||
	return tMERIDIAN;
 | 
						||
    }
 | 
						||
 | 
						||
    /* See if we have an abbreviation for a month. */
 | 
						||
    if (strlen(buff) == 3)
 | 
						||
	abbrev = 1;
 | 
						||
    else if (strlen(buff) == 4 && buff[3] == '.') {
 | 
						||
	abbrev = 1;
 | 
						||
	buff[3] = '\0';
 | 
						||
    }
 | 
						||
    else
 | 
						||
	abbrev = 0;
 | 
						||
 | 
						||
    for (tp = MonthDayTable; tp->name; tp++) {
 | 
						||
	if (abbrev) {
 | 
						||
	    if (strncmp(buff, tp->name, 3) == 0) {
 | 
						||
		yylval->Number = tp->value;
 | 
						||
		return tp->type;
 | 
						||
	    }
 | 
						||
	}
 | 
						||
	else if (strcmp(buff, tp->name) == 0) {
 | 
						||
	    yylval->Number = tp->value;
 | 
						||
	    return tp->type;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
    for (tp = TimezoneTable; tp->name; tp++)
 | 
						||
	if (strcmp(buff, tp->name) == 0) {
 | 
						||
	    yylval->Number = tp->value;
 | 
						||
	    return tp->type;
 | 
						||
	}
 | 
						||
 | 
						||
    if (strcmp(buff, "dst") == 0) 
 | 
						||
	return tDST;
 | 
						||
 | 
						||
    for (tp = UnitsTable; tp->name; tp++)
 | 
						||
	if (strcmp(buff, tp->name) == 0) {
 | 
						||
	    yylval->Number = tp->value;
 | 
						||
	    return tp->type;
 | 
						||
	}
 | 
						||
 | 
						||
    /* Strip off any plural and try the units table again. */
 | 
						||
    i = strlen(buff) - 1;
 | 
						||
    if (buff[i] == 's') {
 | 
						||
	buff[i] = '\0';
 | 
						||
	for (tp = UnitsTable; tp->name; tp++)
 | 
						||
	    if (strcmp(buff, tp->name) == 0) {
 | 
						||
		yylval->Number = tp->value;
 | 
						||
		return tp->type;
 | 
						||
	    }
 | 
						||
	buff[i] = 's';		/* Put back for "this" in OtherTable. */
 | 
						||
    }
 | 
						||
 | 
						||
    for (tp = OtherTable; tp->name; tp++)
 | 
						||
	if (strcmp(buff, tp->name) == 0) {
 | 
						||
	    yylval->Number = tp->value;
 | 
						||
	    return tp->type;
 | 
						||
	}
 | 
						||
 | 
						||
    /* Military timezones. */
 | 
						||
    if (buff[1] == '\0' && isalpha((unsigned char)*buff)) {
 | 
						||
	for (tp = MilitaryTable; tp->name; tp++)
 | 
						||
	    if (strcmp(buff, tp->name) == 0) {
 | 
						||
		yylval->Number = tp->value;
 | 
						||
		return tp->type;
 | 
						||
	    }
 | 
						||
    }
 | 
						||
 | 
						||
    /* Drop out any periods and try the timezone table again. */
 | 
						||
    for (i = 0, p = q = buff; *q; q++)
 | 
						||
	if (*q != '.')
 | 
						||
	    *p++ = *q;
 | 
						||
	else
 | 
						||
	    i++;
 | 
						||
    *p = '\0';
 | 
						||
    if (i)
 | 
						||
	for (tp = TimezoneTable; tp->name; tp++)
 | 
						||
	    if (strcmp(buff, tp->name) == 0) {
 | 
						||
		yylval->Number = tp->value;
 | 
						||
		return tp->type;
 | 
						||
	    }
 | 
						||
 | 
						||
    return tID;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
yylex(YYSTYPE *yylval, const char **yyInput)
 | 
						||
{
 | 
						||
    register char	c;
 | 
						||
    register char	*p;
 | 
						||
    char		buff[20];
 | 
						||
    int			Count;
 | 
						||
    int			sign;
 | 
						||
    const char		*inp = *yyInput;
 | 
						||
 | 
						||
    for ( ; ; ) {
 | 
						||
	while (isspace((unsigned char)*inp))
 | 
						||
	    inp++;
 | 
						||
 | 
						||
	if (isdigit((unsigned char)(c = *inp)) || c == '-' || c == '+') {
 | 
						||
	    if (c == '-' || c == '+') {
 | 
						||
		sign = c == '-' ? -1 : 1;
 | 
						||
		if (!isdigit((unsigned char)*++inp))
 | 
						||
		    /* skip the '-' sign */
 | 
						||
		    continue;
 | 
						||
	    }
 | 
						||
	    else
 | 
						||
		sign = 0;
 | 
						||
	    for (yylval->Number = 0; isdigit((unsigned char)(c = *inp++)); )
 | 
						||
		yylval->Number = 10 * yylval->Number + c - '0';
 | 
						||
	    if (sign < 0)
 | 
						||
		yylval->Number = -yylval->Number;
 | 
						||
	    *yyInput = --inp;
 | 
						||
	    return sign ? tSNUMBER : tUNUMBER;
 | 
						||
	}
 | 
						||
	if (isalpha((unsigned char)c)) {
 | 
						||
	    for (p = buff; isalpha((unsigned char)(c = *inp++)) || c == '.'; )
 | 
						||
		if (p < &buff[sizeof buff - 1])
 | 
						||
		    *p++ = c;
 | 
						||
	    *p = '\0';
 | 
						||
	    *yyInput = --inp;
 | 
						||
	    return LookupWord(yylval, buff);
 | 
						||
	}
 | 
						||
	if (c == '@') {
 | 
						||
	    *yyInput = ++inp;
 | 
						||
	    return AT_SIGN;
 | 
						||
	}
 | 
						||
	if (c != '(') {
 | 
						||
	    *yyInput = ++inp;
 | 
						||
	    return c;
 | 
						||
	}
 | 
						||
	Count = 0;
 | 
						||
	do {
 | 
						||
	    c = *inp++;
 | 
						||
	    if (c == '\0')
 | 
						||
		return c;
 | 
						||
	    if (c == '(')
 | 
						||
		Count++;
 | 
						||
	    else if (c == ')')
 | 
						||
		Count--;
 | 
						||
	} while (Count > 0);
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
#define TM_YEAR_ORIGIN 1900
 | 
						||
 | 
						||
/* Yield A - B, measured in seconds.  */
 | 
						||
static time_t
 | 
						||
difftm (struct tm *a, struct tm *b)
 | 
						||
{
 | 
						||
  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
 | 
						||
  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
 | 
						||
  int days = (
 | 
						||
	      /* difference in day of year */
 | 
						||
	      a->tm_yday - b->tm_yday
 | 
						||
	      /* + intervening leap days */
 | 
						||
	      +  ((ay >> 2) - (by >> 2))
 | 
						||
	      -  (ay/100 - by/100)
 | 
						||
	      +  ((ay/100 >> 2) - (by/100 >> 2))
 | 
						||
	      /* + difference in years * 365 */
 | 
						||
	      +  (long)(ay-by) * 365
 | 
						||
	      );
 | 
						||
  return ((time_t)60*(60*(24*days + (a->tm_hour - b->tm_hour))
 | 
						||
	      + (a->tm_min - b->tm_min))
 | 
						||
	  + (a->tm_sec - b->tm_sec));
 | 
						||
}
 | 
						||
 | 
						||
time_t
 | 
						||
parsedate(const char *p, const time_t *now, const int *zone)
 | 
						||
{
 | 
						||
    struct tm gmt, local, *gmt_ptr, *tm;
 | 
						||
    time_t		nowt;
 | 
						||
    int			zonet;
 | 
						||
    time_t		Start;
 | 
						||
    time_t		tod, rm;
 | 
						||
    struct dateinfo	param;
 | 
						||
 | 
						||
    if (now == NULL || zone == NULL) {
 | 
						||
        now = &nowt;
 | 
						||
	zone = &zonet;
 | 
						||
	(void)time(&nowt);
 | 
						||
 | 
						||
	gmt_ptr = gmtime_r(now, &gmt);
 | 
						||
	if ((tm = localtime_r(now, &local)) == NULL)
 | 
						||
	    return -1;
 | 
						||
 | 
						||
	if (gmt_ptr != NULL)
 | 
						||
	    zonet = difftm(&gmt, &local) / 60;
 | 
						||
	else
 | 
						||
	    /* We are on a system like VMS, where the system clock is
 | 
						||
	       in local time and the system has no concept of timezones.
 | 
						||
	       Hopefully we can fake this out (for the case in which the
 | 
						||
	       user specifies no timezone) by just saying the timezone
 | 
						||
	       is zero.  */
 | 
						||
	    zonet = 0;
 | 
						||
 | 
						||
	if (local.tm_isdst)
 | 
						||
	    zonet += 60;
 | 
						||
    } else {
 | 
						||
	if ((tm = localtime_r(now, &local)) == NULL)
 | 
						||
	    return -1;
 | 
						||
    }
 | 
						||
    param.yyYear = tm->tm_year + 1900;
 | 
						||
    param.yyMonth = tm->tm_mon + 1;
 | 
						||
    param.yyDay = tm->tm_mday;
 | 
						||
    param.yyTimezone = *zone;
 | 
						||
    param.yyDSTmode = DSTmaybe;
 | 
						||
    param.yyHour = 0;
 | 
						||
    param.yyMinutes = 0;
 | 
						||
    param.yySeconds = 0;
 | 
						||
    param.yyMeridian = MER24;
 | 
						||
    param.yyRelSeconds = 0;
 | 
						||
    param.yyRelMonth = 0;
 | 
						||
    param.yyHaveDate = 0;
 | 
						||
    param.yyHaveDay = 0;
 | 
						||
    param.yyHaveRel = 0;
 | 
						||
    param.yyHaveTime = 0;
 | 
						||
    param.yyHaveZone = 0;
 | 
						||
 | 
						||
    if (yyparse(¶m, &p) || param.yyHaveTime > 1 || param.yyHaveZone > 1 ||
 | 
						||
	param.yyHaveDate > 1 || param.yyHaveDay > 1)
 | 
						||
	return -1;
 | 
						||
 | 
						||
    if (param.yyHaveDate || param.yyHaveTime || param.yyHaveDay) {
 | 
						||
	Start = Convert(param.yyMonth, param.yyDay, param.yyYear, param.yyHour,
 | 
						||
	    param.yyMinutes, param.yySeconds, param.yyTimezone,
 | 
						||
	    param.yyMeridian, param.yyDSTmode);
 | 
						||
	if (Start < 0)
 | 
						||
	    return -1;
 | 
						||
    }
 | 
						||
    else {
 | 
						||
	Start = *now;
 | 
						||
	if (!param.yyHaveRel)
 | 
						||
	    Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
 | 
						||
    }
 | 
						||
 | 
						||
    Start += param.yyRelSeconds;
 | 
						||
    rm = RelativeMonth(Start, param.yyRelMonth, param.yyTimezone);
 | 
						||
    if (rm == -1)
 | 
						||
	return -1;
 | 
						||
    Start += rm;
 | 
						||
 | 
						||
    if (param.yyHaveDay && !param.yyHaveDate) {
 | 
						||
	tod = RelativeDate(Start, param.yyDayOrdinal, param.yyDayNumber);
 | 
						||
	Start += tod;
 | 
						||
    }
 | 
						||
 | 
						||
    return Start;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
#if	defined(TEST)
 | 
						||
 | 
						||
/* ARGSUSED */
 | 
						||
int
 | 
						||
main(ac, av)
 | 
						||
    int		ac;
 | 
						||
    char	*av[];
 | 
						||
{
 | 
						||
    char	buff[128];
 | 
						||
    time_t	d;
 | 
						||
 | 
						||
    (void)printf("Enter date, or blank line to exit.\n\t> ");
 | 
						||
    (void)fflush(stdout);
 | 
						||
    while (gets(buff) && buff[0]) {
 | 
						||
	d = parsedate(buff, NULL, NULL);
 | 
						||
	if (d == -1)
 | 
						||
	    (void)printf("Bad format - couldn't convert.\n");
 | 
						||
	else
 | 
						||
	    (void)printf("%s", ctime(&d));
 | 
						||
	(void)printf("\t> ");
 | 
						||
	(void)fflush(stdout);
 | 
						||
    }
 | 
						||
    exit(0);
 | 
						||
    /* NOTREACHED */
 | 
						||
}
 | 
						||
#endif	/* defined(TEST) */
 |