rsalz@bbn.com (Rich Salz) (09/19/90)
This is a new version of getdate.y. It has several timezone fixes, documentation on what else needs to be done, int/long problems fixed, and so on. Slightly earlier versions of this have been sent to Steve Bellovin, the original author, and the maintainers of C and B news. I don't know if/when I'll have a chance to do make the other changes Steve recommends, but I look forward to comments at any rate. /rich $alz #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: README.getdate getdate.y # Wrapped by rsalz@litchi.bbn.com on Wed Sep 19 12:42:42 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive."' if test -f 'README.getdate' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README.getdate'\" else echo shar: Extracting \"'README.getdate'\" \(2104 characters\) sed "s/^X//" >'README.getdate' <<'END_OF_FILE' X XWe've been using Steve Bellovin's getdate() routine in the Cronus project Xfor over a year. This past summer Jim Berets and I cleaned up all the Xtimezones, cleaned up some int/long problems that others have found, Xreformatted the code and cleaned it up, and contacted Steve about what Xshould else needs to be done with it. X XUnfortunately, we didn't have the time to do anything much with Steve's Xcomments, other then document them in the code, and here (thanks to Steve Xfor letting me quote some email): X Two things need to be done. First, the purpose of getdate should be X defined; many of its features were for a rather different purpose that X it's used for today. Specifically, I was implementing 'at' before X there was such a thing, and I wanted the ability to specify relative X intervals. Thus, getdate accepts things like 'two weeks'. I don't X think that code is tremendously useful. If it is, it could be X strengthened by writing a better grammar, i.e., ``two weeks after X monday'' -- currently, the word ``after'' isn't accept, and the X relationship between the day of the week and the interval is X peculiar. And that in turn goes back to the central implementation X failure: it is restricted to a simple 'int' stack, because that's all X that v6 yacc allowed. There's also a lot of reliance on global X variables, for the same reason. Using a union as the stack type, one X could store much better information, clean up the code, and make the X semantics much clearer. (As a trivial change, I suspect that the X military time zones are wrong, as I took them from RFC822 (or maybe X even 733), and I've since learned that those are incorrect. I'd drop X that entirely.) It might also be worth some effort to make the time X zone stuff more compatible with the 4.3tahoe and the SysVR3.2 stuff, X especially as regards the names of the zones. X X It was also intended to let utter novices set the date on a UNIX X machine after rebooting it and thus it accepted almost any rational X form. X XHope you find this useful. X /rich $alz END_OF_FILE if test 2104 -ne `wc -c <'README.getdate'`; then echo shar: \"'README.getdate'\" unpacked with wrong size! fi # end of 'README.getdate' fi if test -f 'getdate.y' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getdate.y'\" else echo shar: Extracting \"'getdate.y'\" \(20830 characters\) sed "s/^X//" >'getdate.y' <<'END_OF_FILE' X%{ X/* $Revision: 2.1 $ X** X** Originally written by Steven M. Bellovin <smb@research.att.com> while X** at the University of North Carolina at Chapel Hill. Later tweaked by X** a couple of people on Usenet. Completely overhauled by Rich $alz X** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990; X** send any email to Rich. X** X** This grammar has eight shift/reduce conflicts. X** X** This code is in the public domain and has no copyright. X*/ X/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */ X/* SUPPRESS 288 on yyerrlab *//* Label unused */ X#include "defs.h" X#include <stdio.h> X#include <ctype.h> X X#if defined(vms) X#include <types.h> X#include <time.h> X#else X#include <sys/types.h> X#if defined(USG) X/* X** Uncomment the next line if you need to do a tzset() call to set the X** timezone, and don't have ftime(). Some SystemV releases, I think. X*/ X/*#define NEED_TZSET */ Xstruct timeb { X time_t time; /* Seconds since the epoch */ X unsigned short millitm; /* Field not used */ X short timezone; X short dstflag; /* Field not used */ X}; X#else X#include <sys/timeb.h> X#endif /* defined(USG) */ X#if defined(BSD4_2) X#include <sys/time.h> X#else X#include <time.h> X#endif /* defined(BSD4_2) */ X#endif /* defined(vms) */ X X#if !defined(lint) && !defined(SABER) Xstatic char RCS[] = X "$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $"; X#endif /* !defined(lint) && !defined(SABER) */ X X X#define EPOCH 1970 X#define HOUR(x) (x * 60) X#define SECSPERDAY (24L * 60L * 60L) X X X/* X** An entry in the lexical lookup table. X*/ Xtypedef struct _TABLE { X char *name; X int type; X time_t value; X} TABLE; X X X/* X** Daylight-savings mode: on, off, or not yet known. X*/ Xtypedef enum _DSTMODE { X DSTon, DSToff, DSTmaybe X} DSTMODE; X X/* X** Meridian: am, pm, or 24-hour style. X*/ Xtypedef enum _MERIDIAN { X MERam, MERpm, MER24 X} MERIDIAN; X X X/* X** Global variables. We could get rid of most of these by using a good X** union as the yacc stack. (This routine was originally written before X** yacc had the %union construct.) Maybe someday; right now we only use X** the %union very rarely. X*/ Xstatic char *yyInput; Xstatic DSTMODE yyDSTmode; Xstatic time_t yyDayOrdinal; Xstatic time_t yyDayNumber; Xstatic int yyHaveDate; Xstatic int yyHaveDay; Xstatic int yyHaveRel; Xstatic int yyHaveTime; Xstatic int yyHaveZone; Xstatic time_t yyTimezone; Xstatic time_t yyDay; Xstatic time_t yyHour; Xstatic time_t yyMinutes; Xstatic time_t yyMonth; Xstatic time_t yySeconds; Xstatic time_t yyYear; Xstatic MERIDIAN yyMeridian; Xstatic time_t yyRelMonth; Xstatic time_t yyRelSeconds; X X Xextern struct tm *localtime(); X%} X X%union { X time_t Number; X enum _MERIDIAN Meridian; X} X X%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT X%token tSEC_UNIT tSNUMBER tUNUMBER tZONE X X%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT X%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE X%type <Meridian> tMERIDIAN o_merid X X%% X Xspec : /* NULL */ X | spec item X ; X Xitem : time { X yyHaveTime++; X } X | zone { X yyHaveZone++; X } X | date { X yyHaveDate++; X } X | day { X yyHaveDay++; X } X | rel { X yyHaveRel++; X } X | number X ; X Xtime : tUNUMBER tMERIDIAN { X yyHour = $1; X yyMinutes = 0; X yySeconds = 0; X yyMeridian = $2; X } X | tUNUMBER ':' tUNUMBER o_merid { X yyHour = $1; X yyMinutes = $3; X yySeconds = 0; X yyMeridian = $4; X } X | tUNUMBER ':' tUNUMBER tSNUMBER { X yyHour = $1; X yyMinutes = $3; X yyMeridian = MER24; X yyDSTmode = DSToff; X yyTimezone = - ($4 % 100 + ($4 / 100) * 60); X } X | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { X yyHour = $1; X yyMinutes = $3; X yySeconds = $5; X yyMeridian = $6; X } X | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { X yyHour = $1; X yyMinutes = $3; X yySeconds = $5; X yyMeridian = MER24; X yyDSTmode = DSToff; X yyTimezone = - ($6 % 100 + ($6 / 100) * 60); X } X ; X Xzone : tZONE { X yyTimezone = $1; X yyDSTmode = DSToff; X } X | tDAYZONE { X yyTimezone = $1; X yyDSTmode = DSTon; X } X ; X Xday : tDAY { X yyDayOrdinal = 1; X yyDayNumber = $1; X } X | tDAY ',' { X yyDayOrdinal = 1; X yyDayNumber = $1; X } X | tUNUMBER tDAY { X yyDayOrdinal = $1; X yyDayNumber = $2; X } X ; X Xdate : tUNUMBER '/' tUNUMBER { X yyMonth = $1; X yyDay = $3; X } X | tUNUMBER '/' tUNUMBER '/' tUNUMBER { X yyMonth = $1; X yyDay = $3; X yyYear = $5; X } X | tMONTH tUNUMBER { X yyMonth = $1; X yyDay = $2; X } X | tMONTH tUNUMBER ',' tUNUMBER { X yyMonth = $1; X yyDay = $2; X yyYear = $4; X } X | tUNUMBER tMONTH { X yyMonth = $2; X yyDay = $1; X } X | tUNUMBER tMONTH tUNUMBER { X yyMonth = $2; X yyDay = $1; X yyYear = $3; X } X ; X Xrel : relunit tAGO { X yyRelSeconds = -yyRelSeconds; X yyRelMonth = -yyRelMonth; X } X | relunit X ; X Xrelunit : tUNUMBER tMINUTE_UNIT { X yyRelSeconds += $1 * $2 * 60L; X } X | tSNUMBER tMINUTE_UNIT { X yyRelSeconds += $1 * $2 * 60L; X } X | tMINUTE_UNIT { X yyRelSeconds += $1 * 60L; X } X | tSNUMBER tSEC_UNIT { X yyRelSeconds += $1; X } X | tUNUMBER tSEC_UNIT { X yyRelSeconds += $1; X } X | tSEC_UNIT { X yyRelSeconds++; X } X | tSNUMBER tMONTH_UNIT { X yyRelMonth += $1 * $2; X } X | tUNUMBER tMONTH_UNIT { X yyRelMonth += $1 * $2; X } X | tMONTH_UNIT { X yyRelMonth += $1; X } X ; X Xnumber : tUNUMBER { X if (yyHaveTime && yyHaveDate && !yyHaveRel) X yyYear = $1; X else { X yyHaveTime++; X if ($1 < 100) { X yyHour = $1; X yyMinutes = 0; X } X else { X yyHour = $1 / 100; X yyMinutes = $1 % 100; X } X yySeconds = 0; X yyMeridian = MER24; X } X } X ; X Xo_merid : /* NULL */ { X $$ = MER24; X } X | tMERIDIAN { X $$ = $1; X } X ; X X%% X X/* Month and day table. */ Xstatic TABLE MonthDayTable[] = { X { "january", tMONTH, 1 }, X { "february", tMONTH, 2 }, X { "march", tMONTH, 3 }, X { "april", tMONTH, 4 }, X { "may", tMONTH, 5 }, X { "june", tMONTH, 6 }, X { "july", tMONTH, 7 }, X { "august", tMONTH, 8 }, X { "september", tMONTH, 9 }, X { "sept", tMONTH, 9 }, X { "october", tMONTH, 10 }, X { "november", tMONTH, 11 }, X { "december", tMONTH, 12 }, X { "sunday", tDAY, 0 }, X { "monday", tDAY, 1 }, X { "tuesday", tDAY, 2 }, X { "tues", tDAY, 2 }, X { "wednesday", tDAY, 3 }, X { "wednes", tDAY, 3 }, X { "thursday", tDAY, 4 }, X { "thur", tDAY, 4 }, X { "thurs", tDAY, 4 }, X { "friday", tDAY, 5 }, X { "saturday", tDAY, 6 }, X { NULL } X}; X X/* Time units table. */ Xstatic TABLE UnitsTable[] = { X { "year", tMONTH_UNIT, 12 }, X { "month", tMONTH_UNIT, 1 }, X { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, X { "week", tMINUTE_UNIT, 7 * 24 * 60 }, X { "day", tMINUTE_UNIT, 1 * 24 * 60 }, X { "hour", tMINUTE_UNIT, 60 }, X { "minute", tMINUTE_UNIT, 1 }, X { "min", tMINUTE_UNIT, 1 }, X { "second", tSEC_UNIT, 1 }, X { "sec", tSEC_UNIT, 1 }, X { NULL } X}; X X/* Assorted relative-time words. */ Xstatic TABLE OtherTable[] = { X { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, X { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, X { "today", tMINUTE_UNIT, 0 }, X { "now", tMINUTE_UNIT, 0 }, X { "last", tUNUMBER, -1 }, X { "this", tMINUTE_UNIT, 0 }, X { "next", tUNUMBER, 2 }, X { "first", tUNUMBER, 1 }, X/* { "second", tUNUMBER, 2 }, */ X { "third", tUNUMBER, 3 }, X { "fourth", tUNUMBER, 4 }, X { "fifth", tUNUMBER, 5 }, X { "sixth", tUNUMBER, 6 }, X { "seventh", tUNUMBER, 7 }, X { "eighth", tUNUMBER, 8 }, X { "ninth", tUNUMBER, 9 }, X { "tenth", tUNUMBER, 10 }, X { "eleventh", tUNUMBER, 11 }, X { "twelfth", tUNUMBER, 12 }, X { "ago", tAGO, 1 }, X { NULL } X}; X X/* The timezone table. */ Xstatic TABLE TimezoneTable[] = { X { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ X { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ X { "utc", tZONE, HOUR( 0) }, X { "wet", tZONE, HOUR( 0) }, /* Western European */ X { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ X { "wat", tZONE, HOUR( 1) }, /* West Africa */ X { "at", tZONE, HOUR( 2) }, /* Azores */ X#if 0 X /* For completeness. BST is also British Summer, and GST is X * also Guam Standard. */ X { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ X { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ X#endif X { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ X { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ X { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ X { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ X { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ X { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ X { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ X { "cst", tZONE, HOUR( 6) }, /* Central Standard */ X { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ X { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ X { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ X { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ X { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ X { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ X { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ X { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ X { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ X { "cat", tZONE, HOUR(10) }, /* Central Alaska */ X { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ X { "nt", tZONE, HOUR(11) }, /* Nome */ X { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ X { "cet", tZONE, -HOUR(1) }, /* Central European */ X { "met", tZONE, -HOUR(1) }, /* Middle European */ X { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ X { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ X { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ X { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ X { "fwt", tZONE, -HOUR(1) }, /* French Winter */ X { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ X { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ X { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ X { "it", tZONE, -HOUR(3.5) },/* Iran */ X { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ X { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ X { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ X { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ X#if 0 X /* For completeness. NST is also Newfoundland Stanard, nad SST is X * also Swedish Summer. */ X { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ X { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ X#endif /* 0 */ X { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ X { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ X { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ X { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ X { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ X { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ X { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ X { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ X { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ X { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ X { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ X { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ X { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ X { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ X { NULL } X}; X X/* Military timezone table. */ Xstatic TABLE MilitaryTable[] = { X { "a", tZONE, HOUR( 1) }, X { "b", tZONE, HOUR( 2) }, X { "c", tZONE, HOUR( 3) }, X { "d", tZONE, HOUR( 4) }, X { "e", tZONE, HOUR( 5) }, X { "f", tZONE, HOUR( 6) }, X { "g", tZONE, HOUR( 7) }, X { "h", tZONE, HOUR( 8) }, X { "i", tZONE, HOUR( 9) }, X { "k", tZONE, HOUR( 10) }, X { "l", tZONE, HOUR( 11) }, X { "m", tZONE, HOUR( 12) }, X { "n", tZONE, HOUR(- 1) }, X { "o", tZONE, HOUR(- 2) }, X { "p", tZONE, HOUR(- 3) }, X { "q", tZONE, HOUR(- 4) }, X { "r", tZONE, HOUR(- 5) }, X { "s", tZONE, HOUR(- 6) }, X { "t", tZONE, HOUR(- 7) }, X { "u", tZONE, HOUR(- 8) }, X { "v", tZONE, HOUR(- 9) }, X { "w", tZONE, HOUR(-10) }, X { "x", tZONE, HOUR(-11) }, X { "y", tZONE, HOUR(-12) }, X { "z", tZONE, HOUR( 0) }, X { NULL } X}; X X X X X/* ARGSUSED */ Xstatic Xyyerror(s) X char *s; X{ X} X X Xstatic time_t XToSeconds(Hours, Minutes, Seconds, Meridian) X time_t Hours; X time_t Minutes; X time_t Seconds; X MERIDIAN Meridian; X{ X if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) X return -1; X switch (Meridian) { X case MER24: X if (Hours < 0 || Hours > 23) X return -1; X return (Hours * 60L + Minutes) * 60L + Seconds; X case MERam: X if (Hours < 1 || Hours > 12) X return -1; X return (Hours * 60L + Minutes) * 60L + Seconds; X case MERpm: X if (Hours < 1 || Hours > 12) X return -1; X return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; X } X /* NOTREACHED */ X} X X Xstatic time_t XConvert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode) X time_t Month; X time_t Day; X time_t Year; X time_t Hours; X time_t Minutes; X time_t Seconds; X MERIDIAN Meridian; X DSTMODE DSTmode; X{ X static int DaysInMonth[12] = { X 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 X }; X time_t tod; X time_t Julian; X int i; X X if (Year < 0) X Year = -Year; X if (Year < 100) X Year += 1900; X DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) X ? 29 : 28; X if (Year < EPOCH || Year > 1999 X || Month < 1 || Month > 12 X /* Lint fluff: "conversion from long may lose accuracy" */ X || Day < 1 || Day > DaysInMonth[(int)--Month]) X return -1; X X for (Julian = Day - 1, i = 0; i < Month; i++) X Julian += DaysInMonth[i]; X for (i = EPOCH; i < Year; i++) X Julian += 365 + (i % 4 == 0); X Julian *= SECSPERDAY; X Julian += yyTimezone * 60L; X if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) X return -1; X Julian += tod; X if (DSTmode == DSTon X || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) X Julian -= 60 * 60; X return Julian; X} X X Xstatic time_t XDSTcorrect(Start, Future) X time_t Start; X time_t Future; X{ X time_t StartDay; X time_t FutureDay; X X StartDay = (localtime(&Start)->tm_hour + 1) % 24; X FutureDay = (localtime(&Future)->tm_hour + 1) % 24; X return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; X} X X Xstatic time_t XRelativeDate(Start, DayOrdinal, DayNumber) X time_t Start; X time_t DayOrdinal; X time_t DayNumber; X{ X struct tm *tm; X time_t now; X X now = Start; X tm = localtime(&now); X now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); X now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); X return DSTcorrect(Start, now); X} X X Xstatic time_t XRelativeMonth(Start, RelMonth) X time_t Start; X time_t RelMonth; X{ X struct tm *tm; X time_t Month; X time_t Year; X X if (RelMonth == 0) X return 0; X tm = localtime(&Start); X Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; X Year = Month / 12; X Month = Month % 12 + 1; X return DSTcorrect(Start, X Convert(Month, (time_t)tm->tm_mday, Year, X (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, X MER24, DSTmaybe)); X} X X Xstatic int XLookupWord(buff) X char *buff; X{ X register char *p; X register char *q; X register TABLE *tp; X int i; X int abbrev; X X /* Make it lowercase. */ X for (p = buff; *p; p++) X if (isupper(*p)) X *p = tolower(*p); X X if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { X yylval.Meridian = MERam; X return tMERIDIAN; X } X if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { X yylval.Meridian = MERpm; X return tMERIDIAN; X } X X /* See if we have an abbreviation for a month. */ X if (strlen(buff) == 3) X abbrev = 1; X else if (strlen(buff) == 4 && buff[3] == '.') { X abbrev = 1; X buff[3] = '\0'; X } X else X abbrev = 0; X X for (tp = MonthDayTable; tp->name; tp++) { X if (abbrev) { X if (strncmp(buff, tp->name, 3) == 0) { X yylval.Number = tp->value; X return tp->type; X } X } X else if (strcmp(buff, tp->name) == 0) { X yylval.Number = tp->value; X return tp->type; X } X } X X for (tp = TimezoneTable; tp->name; tp++) X if (strcmp(buff, tp->name) == 0) { X yylval.Number = tp->value; X return tp->type; X } X X for (tp = UnitsTable; tp->name; tp++) X if (strcmp(buff, tp->name) == 0) { X yylval.Number = tp->value; X return tp->type; X } X X /* Strip off any plural and try the units table again. */ X i = strlen(buff) - 1; X if (buff[i] == 's') { X buff[i] = '\0'; X for (tp = UnitsTable; tp->name; tp++) X if (strcmp(buff, tp->name) == 0) { X yylval.Number = tp->value; X return tp->type; X } X } X X for (tp = OtherTable; tp->name; tp++) X if (strcmp(buff, tp->name) == 0) { X yylval.Number = tp->value; X return tp->type; X } X X /* Military timezones. */ X if (buff[1] == '\0' && isalpha(*buff)) { X for (tp = MilitaryTable; tp->name; tp++) X if (strcmp(buff, tp->name) == 0) { X yylval.Number = tp->value; X return tp->type; X } X } X X /* Drop out any periods and try the timezone table again. */ X for (i = 0, p = q = buff; *q; q++) X if (*q != '.') X *p++ = *q; X else X i++; X *p = '\0'; X if (i) X for (tp = TimezoneTable; tp->name; tp++) X if (strcmp(buff, tp->name) == 0) { X yylval.Number = tp->value; X return tp->type; X } X X return tID; X} X X Xstatic int Xyylex() X{ X register char c; X register char *p; X char buff[20]; X int Count; X int sign; X X for ( ; ; ) { X while (isspace(*yyInput)) X yyInput++; X X if (isdigit(c = *yyInput) || c == '-' || c == '+') { X if (c == '-' || c == '+') { X sign = c == '-' ? -1 : 1; X if (!isdigit(*++yyInput)) X /* skip the '-' sign */ X continue; X } X else X sign = 0; X for (yylval.Number = 0; isdigit(c = *yyInput++); ) X yylval.Number = 10 * yylval.Number + c - '0'; X yyInput--; X if (sign < 0) X yylval.Number = -yylval.Number; X return sign ? tSNUMBER : tUNUMBER; X } X if (isalpha(c)) { X for (p = buff; isalpha(c = *yyInput++) || c == '.'; ) X if (p < &buff[sizeof buff - 1]) X *p++ = c; X *p = '\0'; X yyInput--; X return LookupWord(buff); X } X if (c != '(') X return *yyInput++; X Count = 0; X do { X c = *yyInput++; X if (c == '\0') X return c; X if (c == '(') X Count++; X else if (c == ')') X Count--; X } while (Count > 0); X } X} X X Xstatic time_t Xgetdate(p, now) X char *p; X struct timeb *now; X{ X struct tm *tm; X struct timeb ftz; X time_t Start; X time_t tod; X X yyInput = p; X if (now == NULL) { X now = &ftz; X#if defined(NEED_TZSET) X (void)time(&ftz.time); X /* Set the timezone global. */ X tzset(); X ftz.timezone = (int) timezone / 60; X#else X (void)ftime(&ftz); X#endif /* defined(NEED_TZSET) */ X } X X tm = localtime(&now->time); X yyYear = tm->tm_year; X yyMonth = tm->tm_mon + 1; X yyDay = tm->tm_mday; X yyTimezone = now->timezone; X yyDSTmode = DSTmaybe; X yyHour = 0; X yyMinutes = 0; X yySeconds = 0; X yyMeridian = MER24; X yyRelSeconds = 0; X yyRelMonth = 0; X yyHaveDate = 0; X yyHaveDay = 0; X yyHaveRel = 0; X yyHaveTime = 0; X yyHaveZone = 0; X X if (yyparse() X || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) X return -1; X X if (yyHaveDate || yyHaveTime || yyHaveDay) { X Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, X yyMeridian, yyDSTmode); X if (Start < 0) X return -1; X } X else { X Start = now->time; X if (!yyHaveRel) X Start -= ((tm->tm_hour * 60L) + tm->tm_min * 60L) + tm->tm_sec; X } X X Start += yyRelSeconds; X Start += RelativeMonth(Start, yyRelMonth); X X if (yyHaveDay && !yyHaveDate) { X tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); X Start += tod; X } X X /* Have to do *something* with a legitimate -1 so it's distinguishable X * from the error return value. (Alternately could set errno on error.) */ X return Start == -1 ? 0 : Start; X} X X X#if defined(TEST) X X/* ARGSUSED */ Xmain(ac, av) X int ac; X char *av[]; X{ X char buff[128]; X time_t d; X X (void)printf("Enter date, or blank line to exit.\n\t> "); X (void)fflush(stdout); X while (gets(buff) && buff[0]) { X d = getdate(buff, (struct timeb *)NULL); X if (d == -1) X (void)printf("Bad format - couldn't convert.\n"); X else X (void)printf("%s", ctime(&d)); X (void)printf("\t> "); X (void)fflush(stdout); X } X exit(0); X /* NOTREACHED */ X} X#endif /* defined(TEST) */ END_OF_FILE if test 20830 -ne `wc -c <'getdate.y'`; then echo shar: \"'getdate.y'\" unpacked with wrong size! fi # end of 'getdate.y' fi echo shar: End of archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.