1662cb04cSPoul-Henning Kamp %{ 2662cb04cSPoul-Henning Kamp /* 3662cb04cSPoul-Henning Kamp ** Originally written by Steven M. Bellovin <smb@research.att.com> while 4662cb04cSPoul-Henning Kamp ** at the University of North Carolina at Chapel Hill. Later tweaked by 5662cb04cSPoul-Henning Kamp ** a couple of people on Usenet. Completely overhauled by Rich $alz 6662cb04cSPoul-Henning Kamp ** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990; 7662cb04cSPoul-Henning Kamp ** 8662cb04cSPoul-Henning Kamp ** This grammar has 10 shift/reduce conflicts. 9662cb04cSPoul-Henning Kamp ** 10662cb04cSPoul-Henning Kamp ** This code is in the public domain and has no copyright. 11662cb04cSPoul-Henning Kamp ** 12662cb04cSPoul-Henning Kamp ** Picked up from CVS and slightly cleaned up by to WARNS=5 level by 13662cb04cSPoul-Henning Kamp ** Poul-Henning Kamp <phk@FreeBSD.org> 14662cb04cSPoul-Henning Kamp ** 15662cb04cSPoul-Henning Kamp ** $FreeBSD$ 16662cb04cSPoul-Henning Kamp */ 17662cb04cSPoul-Henning Kamp 18662cb04cSPoul-Henning Kamp #include <stdio.h> 19662cb04cSPoul-Henning Kamp #include <stdlib.h> 20662cb04cSPoul-Henning Kamp #include <ctype.h> 21662cb04cSPoul-Henning Kamp #include <string.h> 22662cb04cSPoul-Henning Kamp #include <sys/types.h> 23662cb04cSPoul-Henning Kamp #include <sys/time.h> 24662cb04cSPoul-Henning Kamp 25662cb04cSPoul-Henning Kamp #include "libfifolog.h" 26662cb04cSPoul-Henning Kamp 27*aaa28628SPoul-Henning Kamp #define yyparse getdate_yyparse 28662cb04cSPoul-Henning Kamp #define yylex getdate_yylex 29662cb04cSPoul-Henning Kamp #define yyerror getdate_yyerror 30662cb04cSPoul-Henning Kamp 31*aaa28628SPoul-Henning Kamp static int yyparse(void); 32662cb04cSPoul-Henning Kamp static int yylex(void); 33662cb04cSPoul-Henning Kamp static int yyerror(const char *); 34662cb04cSPoul-Henning Kamp 35662cb04cSPoul-Henning Kamp #define EPOCH 1970 36662cb04cSPoul-Henning Kamp #define HOUR(x) ((time_t)(x) * 60) 37662cb04cSPoul-Henning Kamp #define SECSPERDAY (24L * 60L * 60L) 38662cb04cSPoul-Henning Kamp 39662cb04cSPoul-Henning Kamp 40662cb04cSPoul-Henning Kamp /* 41662cb04cSPoul-Henning Kamp ** An entry in the lexical lookup table. 42662cb04cSPoul-Henning Kamp */ 43662cb04cSPoul-Henning Kamp typedef struct _TABLE { 44662cb04cSPoul-Henning Kamp const char *name; 45662cb04cSPoul-Henning Kamp int type; 46662cb04cSPoul-Henning Kamp time_t value; 47662cb04cSPoul-Henning Kamp } TABLE; 48662cb04cSPoul-Henning Kamp 49662cb04cSPoul-Henning Kamp 50662cb04cSPoul-Henning Kamp /* 51662cb04cSPoul-Henning Kamp ** Daylight-savings mode: on, off, or not yet known. 52662cb04cSPoul-Henning Kamp */ 53662cb04cSPoul-Henning Kamp typedef enum _DSTMODE { 54662cb04cSPoul-Henning Kamp DSToff, DSTon, DSTmaybe 55662cb04cSPoul-Henning Kamp } DSTMODE; 56662cb04cSPoul-Henning Kamp 57662cb04cSPoul-Henning Kamp /* 58662cb04cSPoul-Henning Kamp ** Meridian: am, pm, or 24-hour style. 59662cb04cSPoul-Henning Kamp */ 60662cb04cSPoul-Henning Kamp typedef enum _MERIDIAN { 61662cb04cSPoul-Henning Kamp MERam, MERpm, MER24 62662cb04cSPoul-Henning Kamp } MERIDIAN; 63662cb04cSPoul-Henning Kamp 64662cb04cSPoul-Henning Kamp 65662cb04cSPoul-Henning Kamp /* 66662cb04cSPoul-Henning Kamp ** Global variables. We could get rid of most of these by using a good 67662cb04cSPoul-Henning Kamp ** union as the yacc stack. (This routine was originally written before 68662cb04cSPoul-Henning Kamp ** yacc had the %union construct.) Maybe someday; right now we only use 69662cb04cSPoul-Henning Kamp ** the %union very rarely. 70662cb04cSPoul-Henning Kamp */ 71662cb04cSPoul-Henning Kamp static char *yyInput; 72662cb04cSPoul-Henning Kamp static DSTMODE yyDSTmode; 73662cb04cSPoul-Henning Kamp static time_t yyDayOrdinal; 74662cb04cSPoul-Henning Kamp static time_t yyDayNumber; 75662cb04cSPoul-Henning Kamp static int yyHaveDate; 76662cb04cSPoul-Henning Kamp static int yyHaveDay; 77662cb04cSPoul-Henning Kamp static int yyHaveRel; 78662cb04cSPoul-Henning Kamp static int yyHaveTime; 79662cb04cSPoul-Henning Kamp static int yyHaveZone; 80662cb04cSPoul-Henning Kamp static time_t yyTimezone; 81662cb04cSPoul-Henning Kamp static time_t yyDay; 82662cb04cSPoul-Henning Kamp static time_t yyHour; 83662cb04cSPoul-Henning Kamp static time_t yyMinutes; 84662cb04cSPoul-Henning Kamp static time_t yyMonth; 85662cb04cSPoul-Henning Kamp static time_t yySeconds; 86662cb04cSPoul-Henning Kamp static time_t yyYear; 87662cb04cSPoul-Henning Kamp static MERIDIAN yyMeridian; 88662cb04cSPoul-Henning Kamp static time_t yyRelMonth; 89662cb04cSPoul-Henning Kamp static time_t yyRelSeconds; 90662cb04cSPoul-Henning Kamp 91662cb04cSPoul-Henning Kamp %} 92662cb04cSPoul-Henning Kamp 93662cb04cSPoul-Henning Kamp %union { 94662cb04cSPoul-Henning Kamp time_t Number; 95662cb04cSPoul-Henning Kamp enum _MERIDIAN Meridian; 96662cb04cSPoul-Henning Kamp } 97662cb04cSPoul-Henning Kamp 98662cb04cSPoul-Henning Kamp %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT 99662cb04cSPoul-Henning Kamp %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST 100662cb04cSPoul-Henning Kamp 101662cb04cSPoul-Henning Kamp %type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT 102662cb04cSPoul-Henning Kamp %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE 103662cb04cSPoul-Henning Kamp %type <Meridian> tMERIDIAN o_merid 104662cb04cSPoul-Henning Kamp 105662cb04cSPoul-Henning Kamp %% 106662cb04cSPoul-Henning Kamp 107662cb04cSPoul-Henning Kamp spec : /* NULL */ 108662cb04cSPoul-Henning Kamp | spec item 109662cb04cSPoul-Henning Kamp ; 110662cb04cSPoul-Henning Kamp 111662cb04cSPoul-Henning Kamp item : time { 112662cb04cSPoul-Henning Kamp yyHaveTime++; 113662cb04cSPoul-Henning Kamp } 114662cb04cSPoul-Henning Kamp | zone { 115662cb04cSPoul-Henning Kamp yyHaveZone++; 116662cb04cSPoul-Henning Kamp } 117662cb04cSPoul-Henning Kamp | date { 118662cb04cSPoul-Henning Kamp yyHaveDate++; 119662cb04cSPoul-Henning Kamp } 120662cb04cSPoul-Henning Kamp | day { 121662cb04cSPoul-Henning Kamp yyHaveDay++; 122662cb04cSPoul-Henning Kamp } 123662cb04cSPoul-Henning Kamp | rel { 124662cb04cSPoul-Henning Kamp yyHaveRel++; 125662cb04cSPoul-Henning Kamp } 126662cb04cSPoul-Henning Kamp | cvsstamp { 127662cb04cSPoul-Henning Kamp yyHaveTime++; 128662cb04cSPoul-Henning Kamp yyHaveDate++; 129662cb04cSPoul-Henning Kamp yyHaveZone++; 130662cb04cSPoul-Henning Kamp } 131662cb04cSPoul-Henning Kamp | number 132662cb04cSPoul-Henning Kamp ; 133662cb04cSPoul-Henning Kamp 134662cb04cSPoul-Henning Kamp cvsstamp: tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER { 135662cb04cSPoul-Henning Kamp yyYear = $1; 136662cb04cSPoul-Henning Kamp if (yyYear < 100) yyYear += 1900; 137662cb04cSPoul-Henning Kamp yyMonth = $3; 138662cb04cSPoul-Henning Kamp yyDay = $5; 139662cb04cSPoul-Henning Kamp yyHour = $7; 140662cb04cSPoul-Henning Kamp yyMinutes = $9; 141662cb04cSPoul-Henning Kamp yySeconds = $11; 142662cb04cSPoul-Henning Kamp yyDSTmode = DSToff; 143662cb04cSPoul-Henning Kamp yyTimezone = 0; 144662cb04cSPoul-Henning Kamp } 145662cb04cSPoul-Henning Kamp ; 146662cb04cSPoul-Henning Kamp 147662cb04cSPoul-Henning Kamp time : tUNUMBER tMERIDIAN { 148662cb04cSPoul-Henning Kamp yyHour = $1; 149662cb04cSPoul-Henning Kamp yyMinutes = 0; 150662cb04cSPoul-Henning Kamp yySeconds = 0; 151662cb04cSPoul-Henning Kamp yyMeridian = $2; 152662cb04cSPoul-Henning Kamp } 153662cb04cSPoul-Henning Kamp | tUNUMBER ':' tUNUMBER o_merid { 154662cb04cSPoul-Henning Kamp yyHour = $1; 155662cb04cSPoul-Henning Kamp yyMinutes = $3; 156662cb04cSPoul-Henning Kamp yySeconds = 0; 157662cb04cSPoul-Henning Kamp yyMeridian = $4; 158662cb04cSPoul-Henning Kamp } 159662cb04cSPoul-Henning Kamp | tUNUMBER ':' tUNUMBER tSNUMBER { 160662cb04cSPoul-Henning Kamp yyHour = $1; 161662cb04cSPoul-Henning Kamp yyMinutes = $3; 162662cb04cSPoul-Henning Kamp yyMeridian = MER24; 163662cb04cSPoul-Henning Kamp yyDSTmode = DSToff; 164662cb04cSPoul-Henning Kamp yyTimezone = - ($4 % 100 + ($4 / 100) * 60); 165662cb04cSPoul-Henning Kamp } 166662cb04cSPoul-Henning Kamp | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { 167662cb04cSPoul-Henning Kamp yyHour = $1; 168662cb04cSPoul-Henning Kamp yyMinutes = $3; 169662cb04cSPoul-Henning Kamp yySeconds = $5; 170662cb04cSPoul-Henning Kamp yyMeridian = $6; 171662cb04cSPoul-Henning Kamp } 172662cb04cSPoul-Henning Kamp | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { 173662cb04cSPoul-Henning Kamp yyHour = $1; 174662cb04cSPoul-Henning Kamp yyMinutes = $3; 175662cb04cSPoul-Henning Kamp yySeconds = $5; 176662cb04cSPoul-Henning Kamp yyMeridian = MER24; 177662cb04cSPoul-Henning Kamp yyDSTmode = DSToff; 178662cb04cSPoul-Henning Kamp yyTimezone = - ($6 % 100 + ($6 / 100) * 60); 179662cb04cSPoul-Henning Kamp } 180662cb04cSPoul-Henning Kamp ; 181662cb04cSPoul-Henning Kamp 182662cb04cSPoul-Henning Kamp zone : tZONE { 183662cb04cSPoul-Henning Kamp yyTimezone = $1; 184662cb04cSPoul-Henning Kamp yyDSTmode = DSToff; 185662cb04cSPoul-Henning Kamp } 186662cb04cSPoul-Henning Kamp | tDAYZONE { 187662cb04cSPoul-Henning Kamp yyTimezone = $1; 188662cb04cSPoul-Henning Kamp yyDSTmode = DSTon; 189662cb04cSPoul-Henning Kamp } 190662cb04cSPoul-Henning Kamp | 191662cb04cSPoul-Henning Kamp tZONE tDST { 192662cb04cSPoul-Henning Kamp yyTimezone = $1; 193662cb04cSPoul-Henning Kamp yyDSTmode = DSTon; 194662cb04cSPoul-Henning Kamp } 195662cb04cSPoul-Henning Kamp ; 196662cb04cSPoul-Henning Kamp 197662cb04cSPoul-Henning Kamp day : tDAY { 198662cb04cSPoul-Henning Kamp yyDayOrdinal = 1; 199662cb04cSPoul-Henning Kamp yyDayNumber = $1; 200662cb04cSPoul-Henning Kamp } 201662cb04cSPoul-Henning Kamp | tDAY ',' { 202662cb04cSPoul-Henning Kamp yyDayOrdinal = 1; 203662cb04cSPoul-Henning Kamp yyDayNumber = $1; 204662cb04cSPoul-Henning Kamp } 205662cb04cSPoul-Henning Kamp | tUNUMBER tDAY { 206662cb04cSPoul-Henning Kamp yyDayOrdinal = $1; 207662cb04cSPoul-Henning Kamp yyDayNumber = $2; 208662cb04cSPoul-Henning Kamp } 209662cb04cSPoul-Henning Kamp ; 210662cb04cSPoul-Henning Kamp 211662cb04cSPoul-Henning Kamp date : tUNUMBER '/' tUNUMBER { 212662cb04cSPoul-Henning Kamp yyMonth = $1; 213662cb04cSPoul-Henning Kamp yyDay = $3; 214662cb04cSPoul-Henning Kamp } 215662cb04cSPoul-Henning Kamp | tUNUMBER '/' tUNUMBER '/' tUNUMBER { 216662cb04cSPoul-Henning Kamp if ($1 >= 100) { 217662cb04cSPoul-Henning Kamp yyYear = $1; 218662cb04cSPoul-Henning Kamp yyMonth = $3; 219662cb04cSPoul-Henning Kamp yyDay = $5; 220662cb04cSPoul-Henning Kamp } else { 221662cb04cSPoul-Henning Kamp yyMonth = $1; 222662cb04cSPoul-Henning Kamp yyDay = $3; 223662cb04cSPoul-Henning Kamp yyYear = $5; 224662cb04cSPoul-Henning Kamp } 225662cb04cSPoul-Henning Kamp } 226662cb04cSPoul-Henning Kamp | tUNUMBER tSNUMBER tSNUMBER { 227662cb04cSPoul-Henning Kamp /* ISO 8601 format. yyyy-mm-dd. */ 228662cb04cSPoul-Henning Kamp yyYear = $1; 229662cb04cSPoul-Henning Kamp yyMonth = -$2; 230662cb04cSPoul-Henning Kamp yyDay = -$3; 231662cb04cSPoul-Henning Kamp } 232662cb04cSPoul-Henning Kamp | tUNUMBER tMONTH tSNUMBER { 233662cb04cSPoul-Henning Kamp /* e.g. 17-JUN-1992. */ 234662cb04cSPoul-Henning Kamp yyDay = $1; 235662cb04cSPoul-Henning Kamp yyMonth = $2; 236662cb04cSPoul-Henning Kamp yyYear = -$3; 237662cb04cSPoul-Henning Kamp } 238662cb04cSPoul-Henning Kamp | tMONTH tUNUMBER { 239662cb04cSPoul-Henning Kamp yyMonth = $1; 240662cb04cSPoul-Henning Kamp yyDay = $2; 241662cb04cSPoul-Henning Kamp } 242662cb04cSPoul-Henning Kamp | tMONTH tUNUMBER ',' tUNUMBER { 243662cb04cSPoul-Henning Kamp yyMonth = $1; 244662cb04cSPoul-Henning Kamp yyDay = $2; 245662cb04cSPoul-Henning Kamp yyYear = $4; 246662cb04cSPoul-Henning Kamp } 247662cb04cSPoul-Henning Kamp | tUNUMBER tMONTH { 248662cb04cSPoul-Henning Kamp yyMonth = $2; 249662cb04cSPoul-Henning Kamp yyDay = $1; 250662cb04cSPoul-Henning Kamp } 251662cb04cSPoul-Henning Kamp | tUNUMBER tMONTH tUNUMBER { 252662cb04cSPoul-Henning Kamp yyMonth = $2; 253662cb04cSPoul-Henning Kamp yyDay = $1; 254662cb04cSPoul-Henning Kamp yyYear = $3; 255662cb04cSPoul-Henning Kamp } 256662cb04cSPoul-Henning Kamp ; 257662cb04cSPoul-Henning Kamp 258662cb04cSPoul-Henning Kamp rel : relunit tAGO { 259662cb04cSPoul-Henning Kamp yyRelSeconds = -yyRelSeconds; 260662cb04cSPoul-Henning Kamp yyRelMonth = -yyRelMonth; 261662cb04cSPoul-Henning Kamp } 262662cb04cSPoul-Henning Kamp | relunit 263662cb04cSPoul-Henning Kamp ; 264662cb04cSPoul-Henning Kamp 265662cb04cSPoul-Henning Kamp relunit : tUNUMBER tMINUTE_UNIT { 266662cb04cSPoul-Henning Kamp yyRelSeconds += $1 * $2 * 60L; 267662cb04cSPoul-Henning Kamp } 268662cb04cSPoul-Henning Kamp | tSNUMBER tMINUTE_UNIT { 269662cb04cSPoul-Henning Kamp yyRelSeconds += $1 * $2 * 60L; 270662cb04cSPoul-Henning Kamp } 271662cb04cSPoul-Henning Kamp | tMINUTE_UNIT { 272662cb04cSPoul-Henning Kamp yyRelSeconds += $1 * 60L; 273662cb04cSPoul-Henning Kamp } 274662cb04cSPoul-Henning Kamp | tSNUMBER tSEC_UNIT { 275662cb04cSPoul-Henning Kamp yyRelSeconds += $1; 276662cb04cSPoul-Henning Kamp } 277662cb04cSPoul-Henning Kamp | tUNUMBER tSEC_UNIT { 278662cb04cSPoul-Henning Kamp yyRelSeconds += $1; 279662cb04cSPoul-Henning Kamp } 280662cb04cSPoul-Henning Kamp | tSEC_UNIT { 281662cb04cSPoul-Henning Kamp yyRelSeconds++; 282662cb04cSPoul-Henning Kamp } 283662cb04cSPoul-Henning Kamp | tSNUMBER tMONTH_UNIT { 284662cb04cSPoul-Henning Kamp yyRelMonth += $1 * $2; 285662cb04cSPoul-Henning Kamp } 286662cb04cSPoul-Henning Kamp | tUNUMBER tMONTH_UNIT { 287662cb04cSPoul-Henning Kamp yyRelMonth += $1 * $2; 288662cb04cSPoul-Henning Kamp } 289662cb04cSPoul-Henning Kamp | tMONTH_UNIT { 290662cb04cSPoul-Henning Kamp yyRelMonth += $1; 291662cb04cSPoul-Henning Kamp } 292662cb04cSPoul-Henning Kamp ; 293662cb04cSPoul-Henning Kamp 294662cb04cSPoul-Henning Kamp number : tUNUMBER { 295662cb04cSPoul-Henning Kamp if (yyHaveTime && yyHaveDate && !yyHaveRel) 296662cb04cSPoul-Henning Kamp yyYear = $1; 297662cb04cSPoul-Henning Kamp else { 298662cb04cSPoul-Henning Kamp if($1>10000) { 299662cb04cSPoul-Henning Kamp yyHaveDate++; 300662cb04cSPoul-Henning Kamp yyDay= ($1)%100; 301662cb04cSPoul-Henning Kamp yyMonth= ($1/100)%100; 302662cb04cSPoul-Henning Kamp yyYear = $1/10000; 303662cb04cSPoul-Henning Kamp } 304662cb04cSPoul-Henning Kamp else { 305662cb04cSPoul-Henning Kamp yyHaveTime++; 306662cb04cSPoul-Henning Kamp if ($1 < 100) { 307662cb04cSPoul-Henning Kamp yyHour = $1; 308662cb04cSPoul-Henning Kamp yyMinutes = 0; 309662cb04cSPoul-Henning Kamp } 310662cb04cSPoul-Henning Kamp else { 311662cb04cSPoul-Henning Kamp yyHour = $1 / 100; 312662cb04cSPoul-Henning Kamp yyMinutes = $1 % 100; 313662cb04cSPoul-Henning Kamp } 314662cb04cSPoul-Henning Kamp yySeconds = 0; 315662cb04cSPoul-Henning Kamp yyMeridian = MER24; 316662cb04cSPoul-Henning Kamp } 317662cb04cSPoul-Henning Kamp } 318662cb04cSPoul-Henning Kamp } 319662cb04cSPoul-Henning Kamp ; 320662cb04cSPoul-Henning Kamp 321662cb04cSPoul-Henning Kamp o_merid : /* NULL */ { 322662cb04cSPoul-Henning Kamp $$ = MER24; 323662cb04cSPoul-Henning Kamp } 324662cb04cSPoul-Henning Kamp | tMERIDIAN { 325662cb04cSPoul-Henning Kamp $$ = $1; 326662cb04cSPoul-Henning Kamp } 327662cb04cSPoul-Henning Kamp ; 328662cb04cSPoul-Henning Kamp 329662cb04cSPoul-Henning Kamp %% 330662cb04cSPoul-Henning Kamp 331662cb04cSPoul-Henning Kamp /* Month and day table. */ 332662cb04cSPoul-Henning Kamp static TABLE const MonthDayTable[] = { 333662cb04cSPoul-Henning Kamp { "january", tMONTH, 1 }, 334662cb04cSPoul-Henning Kamp { "february", tMONTH, 2 }, 335662cb04cSPoul-Henning Kamp { "march", tMONTH, 3 }, 336662cb04cSPoul-Henning Kamp { "april", tMONTH, 4 }, 337662cb04cSPoul-Henning Kamp { "may", tMONTH, 5 }, 338662cb04cSPoul-Henning Kamp { "june", tMONTH, 6 }, 339662cb04cSPoul-Henning Kamp { "july", tMONTH, 7 }, 340662cb04cSPoul-Henning Kamp { "august", tMONTH, 8 }, 341662cb04cSPoul-Henning Kamp { "september", tMONTH, 9 }, 342662cb04cSPoul-Henning Kamp { "sept", tMONTH, 9 }, 343662cb04cSPoul-Henning Kamp { "october", tMONTH, 10 }, 344662cb04cSPoul-Henning Kamp { "november", tMONTH, 11 }, 345662cb04cSPoul-Henning Kamp { "december", tMONTH, 12 }, 346662cb04cSPoul-Henning Kamp { "sunday", tDAY, 0 }, 347662cb04cSPoul-Henning Kamp { "monday", tDAY, 1 }, 348662cb04cSPoul-Henning Kamp { "tuesday", tDAY, 2 }, 349662cb04cSPoul-Henning Kamp { "tues", tDAY, 2 }, 350662cb04cSPoul-Henning Kamp { "wednesday", tDAY, 3 }, 351662cb04cSPoul-Henning Kamp { "wednes", tDAY, 3 }, 352662cb04cSPoul-Henning Kamp { "thursday", tDAY, 4 }, 353662cb04cSPoul-Henning Kamp { "thur", tDAY, 4 }, 354662cb04cSPoul-Henning Kamp { "thurs", tDAY, 4 }, 355662cb04cSPoul-Henning Kamp { "friday", tDAY, 5 }, 356662cb04cSPoul-Henning Kamp { "saturday", tDAY, 6 }, 357662cb04cSPoul-Henning Kamp { NULL, 0, 0 } 358662cb04cSPoul-Henning Kamp }; 359662cb04cSPoul-Henning Kamp 360662cb04cSPoul-Henning Kamp /* Time units table. */ 361662cb04cSPoul-Henning Kamp static TABLE const UnitsTable[] = { 362662cb04cSPoul-Henning Kamp { "year", tMONTH_UNIT, 12 }, 363662cb04cSPoul-Henning Kamp { "month", tMONTH_UNIT, 1 }, 364662cb04cSPoul-Henning Kamp { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, 365662cb04cSPoul-Henning Kamp { "week", tMINUTE_UNIT, 7 * 24 * 60 }, 366662cb04cSPoul-Henning Kamp { "day", tMINUTE_UNIT, 1 * 24 * 60 }, 367662cb04cSPoul-Henning Kamp { "hour", tMINUTE_UNIT, 60 }, 368662cb04cSPoul-Henning Kamp { "minute", tMINUTE_UNIT, 1 }, 369662cb04cSPoul-Henning Kamp { "min", tMINUTE_UNIT, 1 }, 370662cb04cSPoul-Henning Kamp { "second", tSEC_UNIT, 1 }, 371662cb04cSPoul-Henning Kamp { "sec", tSEC_UNIT, 1 }, 372662cb04cSPoul-Henning Kamp { NULL, 0, 0 } 373662cb04cSPoul-Henning Kamp }; 374662cb04cSPoul-Henning Kamp 375662cb04cSPoul-Henning Kamp /* Assorted relative-time words. */ 376662cb04cSPoul-Henning Kamp static TABLE const OtherTable[] = { 377662cb04cSPoul-Henning Kamp { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, 378662cb04cSPoul-Henning Kamp { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, 379662cb04cSPoul-Henning Kamp { "today", tMINUTE_UNIT, 0 }, 380662cb04cSPoul-Henning Kamp { "now", tMINUTE_UNIT, 0 }, 381662cb04cSPoul-Henning Kamp { "last", tUNUMBER, -1 }, 382662cb04cSPoul-Henning Kamp { "this", tMINUTE_UNIT, 0 }, 383662cb04cSPoul-Henning Kamp { "next", tUNUMBER, 2 }, 384662cb04cSPoul-Henning Kamp { "first", tUNUMBER, 1 }, 385662cb04cSPoul-Henning Kamp /* { "second", tUNUMBER, 2 }, */ 386662cb04cSPoul-Henning Kamp { "third", tUNUMBER, 3 }, 387662cb04cSPoul-Henning Kamp { "fourth", tUNUMBER, 4 }, 388662cb04cSPoul-Henning Kamp { "fifth", tUNUMBER, 5 }, 389662cb04cSPoul-Henning Kamp { "sixth", tUNUMBER, 6 }, 390662cb04cSPoul-Henning Kamp { "seventh", tUNUMBER, 7 }, 391662cb04cSPoul-Henning Kamp { "eighth", tUNUMBER, 8 }, 392662cb04cSPoul-Henning Kamp { "ninth", tUNUMBER, 9 }, 393662cb04cSPoul-Henning Kamp { "tenth", tUNUMBER, 10 }, 394662cb04cSPoul-Henning Kamp { "eleventh", tUNUMBER, 11 }, 395662cb04cSPoul-Henning Kamp { "twelfth", tUNUMBER, 12 }, 396662cb04cSPoul-Henning Kamp { "ago", tAGO, 1 }, 397662cb04cSPoul-Henning Kamp { NULL, 0, 0 } 398662cb04cSPoul-Henning Kamp }; 399662cb04cSPoul-Henning Kamp 400662cb04cSPoul-Henning Kamp /* The timezone table. */ 401662cb04cSPoul-Henning Kamp /* Some of these are commented out because a time_t can't store a float. */ 402662cb04cSPoul-Henning Kamp static TABLE const TimezoneTable[] = { 403662cb04cSPoul-Henning Kamp { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ 404662cb04cSPoul-Henning Kamp { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ 405662cb04cSPoul-Henning Kamp { "utc", tZONE, HOUR( 0) }, 406662cb04cSPoul-Henning Kamp { "wet", tZONE, HOUR( 0) }, /* Western European */ 407662cb04cSPoul-Henning Kamp { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ 408662cb04cSPoul-Henning Kamp { "wat", tZONE, HOUR( 1) }, /* West Africa */ 409662cb04cSPoul-Henning Kamp { "at", tZONE, HOUR( 2) }, /* Azores */ 410662cb04cSPoul-Henning Kamp #if 0 411662cb04cSPoul-Henning Kamp /* For completeness. BST is also British Summer, and GST is 412662cb04cSPoul-Henning Kamp * also Guam Standard. */ 413662cb04cSPoul-Henning Kamp { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ 414662cb04cSPoul-Henning Kamp { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ 415662cb04cSPoul-Henning Kamp #endif 416662cb04cSPoul-Henning Kamp #if 0 417662cb04cSPoul-Henning Kamp { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ 418662cb04cSPoul-Henning Kamp { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ 419662cb04cSPoul-Henning Kamp { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ 420662cb04cSPoul-Henning Kamp #endif 421662cb04cSPoul-Henning Kamp { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ 422662cb04cSPoul-Henning Kamp { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ 423662cb04cSPoul-Henning Kamp { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ 424662cb04cSPoul-Henning Kamp { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ 425662cb04cSPoul-Henning Kamp { "cst", tZONE, HOUR( 6) }, /* Central Standard */ 426662cb04cSPoul-Henning Kamp { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ 427662cb04cSPoul-Henning Kamp { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ 428662cb04cSPoul-Henning Kamp { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ 429662cb04cSPoul-Henning Kamp { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ 430662cb04cSPoul-Henning Kamp { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ 431662cb04cSPoul-Henning Kamp { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ 432662cb04cSPoul-Henning Kamp { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ 433662cb04cSPoul-Henning Kamp { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ 434662cb04cSPoul-Henning Kamp { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ 435662cb04cSPoul-Henning Kamp { "cat", tZONE, HOUR(10) }, /* Central Alaska */ 436662cb04cSPoul-Henning Kamp { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ 437662cb04cSPoul-Henning Kamp { "nt", tZONE, HOUR(11) }, /* Nome */ 438662cb04cSPoul-Henning Kamp { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ 439662cb04cSPoul-Henning Kamp { "cet", tZONE, -HOUR(1) }, /* Central European */ 440662cb04cSPoul-Henning Kamp { "met", tZONE, -HOUR(1) }, /* Middle European */ 441662cb04cSPoul-Henning Kamp { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ 442662cb04cSPoul-Henning Kamp { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ 443662cb04cSPoul-Henning Kamp { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ 444662cb04cSPoul-Henning Kamp { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ 445662cb04cSPoul-Henning Kamp { "fwt", tZONE, -HOUR(1) }, /* French Winter */ 446662cb04cSPoul-Henning Kamp { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ 447662cb04cSPoul-Henning Kamp { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ 448662cb04cSPoul-Henning Kamp { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ 449662cb04cSPoul-Henning Kamp #if 0 450662cb04cSPoul-Henning Kamp { "it", tZONE, -HOUR(3.5) },/* Iran */ 451662cb04cSPoul-Henning Kamp #endif 452662cb04cSPoul-Henning Kamp { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ 453662cb04cSPoul-Henning Kamp { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ 454662cb04cSPoul-Henning Kamp #if 0 455662cb04cSPoul-Henning Kamp { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ 456662cb04cSPoul-Henning Kamp #endif 457662cb04cSPoul-Henning Kamp { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ 458662cb04cSPoul-Henning Kamp #if 0 459662cb04cSPoul-Henning Kamp /* For completeness. NST is also Newfoundland Stanard, and SST is 460662cb04cSPoul-Henning Kamp * also Swedish Summer. */ 461662cb04cSPoul-Henning Kamp { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ 462662cb04cSPoul-Henning Kamp { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ 463662cb04cSPoul-Henning Kamp #endif /* 0 */ 464662cb04cSPoul-Henning Kamp { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ 465662cb04cSPoul-Henning Kamp { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ 466662cb04cSPoul-Henning Kamp #if 0 467662cb04cSPoul-Henning Kamp { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ 468662cb04cSPoul-Henning Kamp #endif 469662cb04cSPoul-Henning Kamp { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ 470662cb04cSPoul-Henning Kamp { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ 471662cb04cSPoul-Henning Kamp #if 0 472662cb04cSPoul-Henning Kamp { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ 473662cb04cSPoul-Henning Kamp { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ 474662cb04cSPoul-Henning Kamp #endif 475662cb04cSPoul-Henning Kamp { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ 476662cb04cSPoul-Henning Kamp { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ 477662cb04cSPoul-Henning Kamp { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ 478662cb04cSPoul-Henning Kamp { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ 479662cb04cSPoul-Henning Kamp { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ 480662cb04cSPoul-Henning Kamp { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ 481662cb04cSPoul-Henning Kamp { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ 482662cb04cSPoul-Henning Kamp { NULL, 0, 0 } 483662cb04cSPoul-Henning Kamp }; 484662cb04cSPoul-Henning Kamp 485662cb04cSPoul-Henning Kamp /* Military timezone table. */ 486662cb04cSPoul-Henning Kamp static TABLE const MilitaryTable[] = { 487662cb04cSPoul-Henning Kamp { "a", tZONE, HOUR( 1) }, 488662cb04cSPoul-Henning Kamp { "b", tZONE, HOUR( 2) }, 489662cb04cSPoul-Henning Kamp { "c", tZONE, HOUR( 3) }, 490662cb04cSPoul-Henning Kamp { "d", tZONE, HOUR( 4) }, 491662cb04cSPoul-Henning Kamp { "e", tZONE, HOUR( 5) }, 492662cb04cSPoul-Henning Kamp { "f", tZONE, HOUR( 6) }, 493662cb04cSPoul-Henning Kamp { "g", tZONE, HOUR( 7) }, 494662cb04cSPoul-Henning Kamp { "h", tZONE, HOUR( 8) }, 495662cb04cSPoul-Henning Kamp { "i", tZONE, HOUR( 9) }, 496662cb04cSPoul-Henning Kamp { "k", tZONE, HOUR( 10) }, 497662cb04cSPoul-Henning Kamp { "l", tZONE, HOUR( 11) }, 498662cb04cSPoul-Henning Kamp { "m", tZONE, HOUR( 12) }, 499662cb04cSPoul-Henning Kamp { "n", tZONE, HOUR(- 1) }, 500662cb04cSPoul-Henning Kamp { "o", tZONE, HOUR(- 2) }, 501662cb04cSPoul-Henning Kamp { "p", tZONE, HOUR(- 3) }, 502662cb04cSPoul-Henning Kamp { "q", tZONE, HOUR(- 4) }, 503662cb04cSPoul-Henning Kamp { "r", tZONE, HOUR(- 5) }, 504662cb04cSPoul-Henning Kamp { "s", tZONE, HOUR(- 6) }, 505662cb04cSPoul-Henning Kamp { "t", tZONE, HOUR(- 7) }, 506662cb04cSPoul-Henning Kamp { "u", tZONE, HOUR(- 8) }, 507662cb04cSPoul-Henning Kamp { "v", tZONE, HOUR(- 9) }, 508662cb04cSPoul-Henning Kamp { "w", tZONE, HOUR(-10) }, 509662cb04cSPoul-Henning Kamp { "x", tZONE, HOUR(-11) }, 510662cb04cSPoul-Henning Kamp { "y", tZONE, HOUR(-12) }, 511662cb04cSPoul-Henning Kamp { "z", tZONE, HOUR( 0) }, 512662cb04cSPoul-Henning Kamp { NULL, 0, 0 } 513662cb04cSPoul-Henning Kamp }; 514662cb04cSPoul-Henning Kamp 515662cb04cSPoul-Henning Kamp 516662cb04cSPoul-Henning Kamp 517662cb04cSPoul-Henning Kamp 518662cb04cSPoul-Henning Kamp /* ARGSUSED */ 519662cb04cSPoul-Henning Kamp static int 520662cb04cSPoul-Henning Kamp yyerror(const char *s __unused) 521662cb04cSPoul-Henning Kamp { 522662cb04cSPoul-Henning Kamp return 0; 523662cb04cSPoul-Henning Kamp } 524662cb04cSPoul-Henning Kamp 525662cb04cSPoul-Henning Kamp 526662cb04cSPoul-Henning Kamp static time_t 527662cb04cSPoul-Henning Kamp ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian) 528662cb04cSPoul-Henning Kamp { 529662cb04cSPoul-Henning Kamp if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) 530662cb04cSPoul-Henning Kamp return -1; 531662cb04cSPoul-Henning Kamp switch (Meridian) { 532662cb04cSPoul-Henning Kamp case MER24: 533662cb04cSPoul-Henning Kamp if (Hours < 0 || Hours > 23) 534662cb04cSPoul-Henning Kamp return -1; 535662cb04cSPoul-Henning Kamp return (Hours * 60L + Minutes) * 60L + Seconds; 536662cb04cSPoul-Henning Kamp case MERam: 537662cb04cSPoul-Henning Kamp if (Hours < 1 || Hours > 12) 538662cb04cSPoul-Henning Kamp return -1; 539662cb04cSPoul-Henning Kamp if (Hours == 12) 540662cb04cSPoul-Henning Kamp Hours = 0; 541662cb04cSPoul-Henning Kamp return (Hours * 60L + Minutes) * 60L + Seconds; 542662cb04cSPoul-Henning Kamp case MERpm: 543662cb04cSPoul-Henning Kamp if (Hours < 1 || Hours > 12) 544662cb04cSPoul-Henning Kamp return -1; 545662cb04cSPoul-Henning Kamp if (Hours == 12) 546662cb04cSPoul-Henning Kamp Hours = 0; 547662cb04cSPoul-Henning Kamp return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; 548662cb04cSPoul-Henning Kamp default: 549662cb04cSPoul-Henning Kamp abort (); 550662cb04cSPoul-Henning Kamp } 551662cb04cSPoul-Henning Kamp /* NOTREACHED */ 552662cb04cSPoul-Henning Kamp } 553662cb04cSPoul-Henning Kamp 554662cb04cSPoul-Henning Kamp 555662cb04cSPoul-Henning Kamp /* Year is either 556662cb04cSPoul-Henning Kamp * A negative number, which means to use its absolute value (why?) 557662cb04cSPoul-Henning Kamp * A number from 0 to 99, which means a year from 1900 to 1999, or 558662cb04cSPoul-Henning Kamp * The actual year (>=100). */ 559662cb04cSPoul-Henning Kamp static time_t 560662cb04cSPoul-Henning Kamp Convert(time_t Month, time_t Day, time_t Year, 561662cb04cSPoul-Henning Kamp time_t Hours, time_t Minutes, time_t Seconds, 562662cb04cSPoul-Henning Kamp MERIDIAN Meridian, DSTMODE DSTmode) 563662cb04cSPoul-Henning Kamp { 564662cb04cSPoul-Henning Kamp static int DaysInMonth[12] = { 565662cb04cSPoul-Henning Kamp 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 566662cb04cSPoul-Henning Kamp }; 567662cb04cSPoul-Henning Kamp time_t tod; 568662cb04cSPoul-Henning Kamp time_t Julian; 569662cb04cSPoul-Henning Kamp int i; 570662cb04cSPoul-Henning Kamp struct tm *ltm; 571662cb04cSPoul-Henning Kamp 572662cb04cSPoul-Henning Kamp if (Year < 0) 573662cb04cSPoul-Henning Kamp Year = -Year; 574662cb04cSPoul-Henning Kamp if (Year < 69) 575662cb04cSPoul-Henning Kamp Year += 2000; 576662cb04cSPoul-Henning Kamp else if (Year < 100) 577662cb04cSPoul-Henning Kamp Year += 1900; 578662cb04cSPoul-Henning Kamp DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) 579662cb04cSPoul-Henning Kamp ? 29 : 28; 580662cb04cSPoul-Henning Kamp /* Checking for 2038 bogusly assumes that time_t is 32 bits. But 581662cb04cSPoul-Henning Kamp I'm too lazy to try to check for time_t overflow in another way. */ 582662cb04cSPoul-Henning Kamp if (Year < EPOCH || Year > 2038 583662cb04cSPoul-Henning Kamp || Month < 1 || Month > 12 584662cb04cSPoul-Henning Kamp /* Lint fluff: "conversion from long may lose accuracy" */ 585662cb04cSPoul-Henning Kamp || Day < 1 || Day > DaysInMonth[(int)--Month]) 586662cb04cSPoul-Henning Kamp /* FIXME: 587662cb04cSPoul-Henning Kamp * It would be nice to set a global error string here. 588662cb04cSPoul-Henning Kamp * "February 30 is not a valid date" is much more informative than 589662cb04cSPoul-Henning Kamp * "Can't parse date/time: 100 months" when the user input was 590662cb04cSPoul-Henning Kamp * "100 months" and addition resolved that to February 30, for 591662cb04cSPoul-Henning Kamp * example. See rcs2-7 in src/sanity.sh for more. */ 592662cb04cSPoul-Henning Kamp return -1; 593662cb04cSPoul-Henning Kamp 594662cb04cSPoul-Henning Kamp for (Julian = Day - 1, i = 0; i < Month; i++) 595662cb04cSPoul-Henning Kamp Julian += DaysInMonth[i]; 596662cb04cSPoul-Henning Kamp for (i = EPOCH; i < Year; i++) 597662cb04cSPoul-Henning Kamp Julian += 365 + (i % 4 == 0); 598662cb04cSPoul-Henning Kamp Julian *= SECSPERDAY; 599662cb04cSPoul-Henning Kamp Julian += yyTimezone * 60L; 600662cb04cSPoul-Henning Kamp if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) 601662cb04cSPoul-Henning Kamp return -1; 602662cb04cSPoul-Henning Kamp Julian += tod; 603662cb04cSPoul-Henning Kamp ltm = localtime(&Julian); 604662cb04cSPoul-Henning Kamp fprintf(stderr, "DST %d TZ %s %d\n", DSTmode, ltm->tm_zone, ltm->tm_isdst); 605662cb04cSPoul-Henning Kamp if (DSTmode == DSTon 606662cb04cSPoul-Henning Kamp || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) 607662cb04cSPoul-Henning Kamp Julian -= 60 * 60; 608662cb04cSPoul-Henning Kamp return Julian; 609662cb04cSPoul-Henning Kamp } 610662cb04cSPoul-Henning Kamp 611662cb04cSPoul-Henning Kamp 612662cb04cSPoul-Henning Kamp static time_t 613662cb04cSPoul-Henning Kamp DSTcorrect(time_t Start, time_t Future) 614662cb04cSPoul-Henning Kamp { 615662cb04cSPoul-Henning Kamp time_t StartDay; 616662cb04cSPoul-Henning Kamp time_t FutureDay; 617662cb04cSPoul-Henning Kamp 618662cb04cSPoul-Henning Kamp StartDay = (localtime(&Start)->tm_hour + 1) % 24; 619662cb04cSPoul-Henning Kamp FutureDay = (localtime(&Future)->tm_hour + 1) % 24; 620662cb04cSPoul-Henning Kamp return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; 621662cb04cSPoul-Henning Kamp } 622662cb04cSPoul-Henning Kamp 623662cb04cSPoul-Henning Kamp 624662cb04cSPoul-Henning Kamp static time_t 625662cb04cSPoul-Henning Kamp RelativeDate(time_t Start, time_t DayOrdinal, time_t DayNumber) 626662cb04cSPoul-Henning Kamp { 627662cb04cSPoul-Henning Kamp struct tm *tm; 628662cb04cSPoul-Henning Kamp time_t now; 629662cb04cSPoul-Henning Kamp 630662cb04cSPoul-Henning Kamp now = Start; 631662cb04cSPoul-Henning Kamp tm = localtime(&now); 632662cb04cSPoul-Henning Kamp now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); 633662cb04cSPoul-Henning Kamp now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); 634662cb04cSPoul-Henning Kamp return DSTcorrect(Start, now); 635662cb04cSPoul-Henning Kamp } 636662cb04cSPoul-Henning Kamp 637662cb04cSPoul-Henning Kamp 638662cb04cSPoul-Henning Kamp static time_t 639662cb04cSPoul-Henning Kamp RelativeMonth(time_t Start, time_t RelMonth) 640662cb04cSPoul-Henning Kamp { 641662cb04cSPoul-Henning Kamp struct tm *tm; 642662cb04cSPoul-Henning Kamp time_t Month; 643662cb04cSPoul-Henning Kamp time_t Year; 644662cb04cSPoul-Henning Kamp 645662cb04cSPoul-Henning Kamp if (RelMonth == 0) 646662cb04cSPoul-Henning Kamp return 0; 647662cb04cSPoul-Henning Kamp tm = localtime(&Start); 648662cb04cSPoul-Henning Kamp Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; 649662cb04cSPoul-Henning Kamp Year = Month / 12; 650662cb04cSPoul-Henning Kamp Month = Month % 12 + 1; 651662cb04cSPoul-Henning Kamp return DSTcorrect(Start, 652662cb04cSPoul-Henning Kamp Convert(Month, (time_t)tm->tm_mday, Year, 653662cb04cSPoul-Henning Kamp (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, 654662cb04cSPoul-Henning Kamp MER24, DSTmaybe)); 655662cb04cSPoul-Henning Kamp } 656662cb04cSPoul-Henning Kamp 657662cb04cSPoul-Henning Kamp 658662cb04cSPoul-Henning Kamp static int 659662cb04cSPoul-Henning Kamp LookupWord(char *buff) 660662cb04cSPoul-Henning Kamp { 661662cb04cSPoul-Henning Kamp char *p; 662662cb04cSPoul-Henning Kamp char *q; 663662cb04cSPoul-Henning Kamp const TABLE *tp; 664662cb04cSPoul-Henning Kamp int i; 665662cb04cSPoul-Henning Kamp int abbrev; 666662cb04cSPoul-Henning Kamp 667662cb04cSPoul-Henning Kamp /* Make it lowercase. */ 668662cb04cSPoul-Henning Kamp for (p = buff; *p; p++) 669662cb04cSPoul-Henning Kamp if (isupper(*p)) 670662cb04cSPoul-Henning Kamp *p = tolower(*p); 671662cb04cSPoul-Henning Kamp 672662cb04cSPoul-Henning Kamp if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { 673662cb04cSPoul-Henning Kamp yylval.Meridian = MERam; 674662cb04cSPoul-Henning Kamp return tMERIDIAN; 675662cb04cSPoul-Henning Kamp } 676662cb04cSPoul-Henning Kamp if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { 677662cb04cSPoul-Henning Kamp yylval.Meridian = MERpm; 678662cb04cSPoul-Henning Kamp return tMERIDIAN; 679662cb04cSPoul-Henning Kamp } 680662cb04cSPoul-Henning Kamp 681662cb04cSPoul-Henning Kamp /* See if we have an abbreviation for a month. */ 682662cb04cSPoul-Henning Kamp if (strlen(buff) == 3) 683662cb04cSPoul-Henning Kamp abbrev = 1; 684662cb04cSPoul-Henning Kamp else if (strlen(buff) == 4 && buff[3] == '.') { 685662cb04cSPoul-Henning Kamp abbrev = 1; 686662cb04cSPoul-Henning Kamp buff[3] = '\0'; 687662cb04cSPoul-Henning Kamp } 688662cb04cSPoul-Henning Kamp else 689662cb04cSPoul-Henning Kamp abbrev = 0; 690662cb04cSPoul-Henning Kamp 691662cb04cSPoul-Henning Kamp for (tp = MonthDayTable; tp->name; tp++) { 692662cb04cSPoul-Henning Kamp if (abbrev) { 693662cb04cSPoul-Henning Kamp if (strncmp(buff, tp->name, 3) == 0) { 694662cb04cSPoul-Henning Kamp yylval.Number = tp->value; 695662cb04cSPoul-Henning Kamp return tp->type; 696662cb04cSPoul-Henning Kamp } 697662cb04cSPoul-Henning Kamp } 698662cb04cSPoul-Henning Kamp else if (strcmp(buff, tp->name) == 0) { 699662cb04cSPoul-Henning Kamp yylval.Number = tp->value; 700662cb04cSPoul-Henning Kamp return tp->type; 701662cb04cSPoul-Henning Kamp } 702662cb04cSPoul-Henning Kamp } 703662cb04cSPoul-Henning Kamp 704662cb04cSPoul-Henning Kamp for (tp = TimezoneTable; tp->name; tp++) 705662cb04cSPoul-Henning Kamp if (strcmp(buff, tp->name) == 0) { 706662cb04cSPoul-Henning Kamp yylval.Number = tp->value; 707662cb04cSPoul-Henning Kamp return tp->type; 708662cb04cSPoul-Henning Kamp } 709662cb04cSPoul-Henning Kamp 710662cb04cSPoul-Henning Kamp if (strcmp(buff, "dst") == 0) 711662cb04cSPoul-Henning Kamp return tDST; 712662cb04cSPoul-Henning Kamp 713662cb04cSPoul-Henning Kamp for (tp = UnitsTable; tp->name; tp++) 714662cb04cSPoul-Henning Kamp if (strcmp(buff, tp->name) == 0) { 715662cb04cSPoul-Henning Kamp yylval.Number = tp->value; 716662cb04cSPoul-Henning Kamp return tp->type; 717662cb04cSPoul-Henning Kamp } 718662cb04cSPoul-Henning Kamp 719662cb04cSPoul-Henning Kamp /* Strip off any plural and try the units table again. */ 720662cb04cSPoul-Henning Kamp i = strlen(buff) - 1; 721662cb04cSPoul-Henning Kamp if (buff[i] == 's') { 722662cb04cSPoul-Henning Kamp buff[i] = '\0'; 723662cb04cSPoul-Henning Kamp for (tp = UnitsTable; tp->name; tp++) 724662cb04cSPoul-Henning Kamp if (strcmp(buff, tp->name) == 0) { 725662cb04cSPoul-Henning Kamp yylval.Number = tp->value; 726662cb04cSPoul-Henning Kamp return tp->type; 727662cb04cSPoul-Henning Kamp } 728662cb04cSPoul-Henning Kamp buff[i] = 's'; /* Put back for "this" in OtherTable. */ 729662cb04cSPoul-Henning Kamp } 730662cb04cSPoul-Henning Kamp 731662cb04cSPoul-Henning Kamp for (tp = OtherTable; tp->name; tp++) 732662cb04cSPoul-Henning Kamp if (strcmp(buff, tp->name) == 0) { 733662cb04cSPoul-Henning Kamp yylval.Number = tp->value; 734662cb04cSPoul-Henning Kamp return tp->type; 735662cb04cSPoul-Henning Kamp } 736662cb04cSPoul-Henning Kamp 737662cb04cSPoul-Henning Kamp /* Military timezones. */ 738662cb04cSPoul-Henning Kamp if (buff[1] == '\0' && isalpha(*buff)) { 739662cb04cSPoul-Henning Kamp for (tp = MilitaryTable; tp->name; tp++) 740662cb04cSPoul-Henning Kamp if (strcmp(buff, tp->name) == 0) { 741662cb04cSPoul-Henning Kamp yylval.Number = tp->value; 742662cb04cSPoul-Henning Kamp return tp->type; 743662cb04cSPoul-Henning Kamp } 744662cb04cSPoul-Henning Kamp } 745662cb04cSPoul-Henning Kamp 746662cb04cSPoul-Henning Kamp /* Drop out any periods and try the timezone table again. */ 747662cb04cSPoul-Henning Kamp for (i = 0, p = q = buff; *q; q++) 748662cb04cSPoul-Henning Kamp if (*q != '.') 749662cb04cSPoul-Henning Kamp *p++ = *q; 750662cb04cSPoul-Henning Kamp else 751662cb04cSPoul-Henning Kamp i++; 752662cb04cSPoul-Henning Kamp *p = '\0'; 753662cb04cSPoul-Henning Kamp if (i) 754662cb04cSPoul-Henning Kamp for (tp = TimezoneTable; tp->name; tp++) 755662cb04cSPoul-Henning Kamp if (strcmp(buff, tp->name) == 0) { 756662cb04cSPoul-Henning Kamp yylval.Number = tp->value; 757662cb04cSPoul-Henning Kamp return tp->type; 758662cb04cSPoul-Henning Kamp } 759662cb04cSPoul-Henning Kamp 760662cb04cSPoul-Henning Kamp return tID; 761662cb04cSPoul-Henning Kamp } 762662cb04cSPoul-Henning Kamp 763662cb04cSPoul-Henning Kamp 764662cb04cSPoul-Henning Kamp static int 76510bc3a7fSEd Schouten yylex(void) 766662cb04cSPoul-Henning Kamp { 767662cb04cSPoul-Henning Kamp char c; 768662cb04cSPoul-Henning Kamp char *p; 769662cb04cSPoul-Henning Kamp char buff[20]; 770662cb04cSPoul-Henning Kamp int Count; 771662cb04cSPoul-Henning Kamp int sign; 772662cb04cSPoul-Henning Kamp 773662cb04cSPoul-Henning Kamp for ( ; ; ) { 774662cb04cSPoul-Henning Kamp while (isspace(*yyInput)) 775662cb04cSPoul-Henning Kamp yyInput++; 776662cb04cSPoul-Henning Kamp 777662cb04cSPoul-Henning Kamp if (isdigit(c = *yyInput) || c == '-' || c == '+') { 778662cb04cSPoul-Henning Kamp if (c == '-' || c == '+') { 779662cb04cSPoul-Henning Kamp sign = c == '-' ? -1 : 1; 780662cb04cSPoul-Henning Kamp if (!isdigit(*++yyInput)) 781662cb04cSPoul-Henning Kamp /* skip the '-' sign */ 782662cb04cSPoul-Henning Kamp continue; 783662cb04cSPoul-Henning Kamp } 784662cb04cSPoul-Henning Kamp else 785662cb04cSPoul-Henning Kamp sign = 0; 786662cb04cSPoul-Henning Kamp for (yylval.Number = 0; isdigit(c = *yyInput++); ) 787662cb04cSPoul-Henning Kamp yylval.Number = 10 * yylval.Number + c - '0'; 788662cb04cSPoul-Henning Kamp yyInput--; 789662cb04cSPoul-Henning Kamp if (sign < 0) 790662cb04cSPoul-Henning Kamp yylval.Number = -yylval.Number; 791662cb04cSPoul-Henning Kamp return sign ? tSNUMBER : tUNUMBER; 792662cb04cSPoul-Henning Kamp } 793662cb04cSPoul-Henning Kamp if (isalpha(c)) { 794662cb04cSPoul-Henning Kamp for (p = buff; isalpha(c = *yyInput++) || c == '.'; ) 795662cb04cSPoul-Henning Kamp if (p < &buff[sizeof buff - 1]) 796662cb04cSPoul-Henning Kamp *p++ = c; 797662cb04cSPoul-Henning Kamp *p = '\0'; 798662cb04cSPoul-Henning Kamp yyInput--; 799662cb04cSPoul-Henning Kamp return LookupWord(buff); 800662cb04cSPoul-Henning Kamp } 801662cb04cSPoul-Henning Kamp if (c != '(') 802662cb04cSPoul-Henning Kamp return *yyInput++; 803662cb04cSPoul-Henning Kamp Count = 0; 804662cb04cSPoul-Henning Kamp do { 805662cb04cSPoul-Henning Kamp c = *yyInput++; 806662cb04cSPoul-Henning Kamp if (c == '\0') 807662cb04cSPoul-Henning Kamp return c; 808662cb04cSPoul-Henning Kamp if (c == '(') 809662cb04cSPoul-Henning Kamp Count++; 810662cb04cSPoul-Henning Kamp else if (c == ')') 811662cb04cSPoul-Henning Kamp Count--; 812662cb04cSPoul-Henning Kamp } while (Count > 0); 813662cb04cSPoul-Henning Kamp } 814662cb04cSPoul-Henning Kamp } 815662cb04cSPoul-Henning Kamp 816662cb04cSPoul-Henning Kamp #define TM_YEAR_ORIGIN 1900 817662cb04cSPoul-Henning Kamp 818662cb04cSPoul-Henning Kamp time_t 819662cb04cSPoul-Henning Kamp get_date(char *p) 820662cb04cSPoul-Henning Kamp { 821662cb04cSPoul-Henning Kamp struct tm *tm, gmt; 822662cb04cSPoul-Henning Kamp time_t Start; 823662cb04cSPoul-Henning Kamp time_t tod; 824662cb04cSPoul-Henning Kamp time_t nowtime; 825662cb04cSPoul-Henning Kamp struct tm *gmt_ptr; 826662cb04cSPoul-Henning Kamp 827662cb04cSPoul-Henning Kamp yyInput = p; 828662cb04cSPoul-Henning Kamp 829662cb04cSPoul-Henning Kamp (void)time (&nowtime); 830662cb04cSPoul-Henning Kamp 831662cb04cSPoul-Henning Kamp gmt_ptr = gmtime (&nowtime); 832662cb04cSPoul-Henning Kamp if (gmt_ptr != NULL) 833662cb04cSPoul-Henning Kamp { 834662cb04cSPoul-Henning Kamp /* Make a copy, in case localtime modifies *tm (I think 835662cb04cSPoul-Henning Kamp that comment now applies to *gmt_ptr, but I am too 836662cb04cSPoul-Henning Kamp lazy to dig into how gmtime and locatime allocate the 837662cb04cSPoul-Henning Kamp structures they return pointers to). */ 838662cb04cSPoul-Henning Kamp gmt = *gmt_ptr; 839662cb04cSPoul-Henning Kamp } 840662cb04cSPoul-Henning Kamp 841662cb04cSPoul-Henning Kamp if (! (tm = localtime (&nowtime))) 842662cb04cSPoul-Henning Kamp return -1; 843662cb04cSPoul-Henning Kamp 844662cb04cSPoul-Henning Kamp tm = localtime(&nowtime); 845662cb04cSPoul-Henning Kamp yyYear = tm->tm_year + 1900; 846662cb04cSPoul-Henning Kamp yyMonth = tm->tm_mon + 1; 847662cb04cSPoul-Henning Kamp yyDay = tm->tm_mday; 848662cb04cSPoul-Henning Kamp yyTimezone = tm->tm_gmtoff; 849662cb04cSPoul-Henning Kamp yyDSTmode = DSTmaybe; 850662cb04cSPoul-Henning Kamp yyHour = 0; 851662cb04cSPoul-Henning Kamp yyMinutes = 0; 852662cb04cSPoul-Henning Kamp yySeconds = 0; 853662cb04cSPoul-Henning Kamp yyMeridian = MER24; 854662cb04cSPoul-Henning Kamp yyRelSeconds = 0; 855662cb04cSPoul-Henning Kamp yyRelMonth = 0; 856662cb04cSPoul-Henning Kamp yyHaveDate = 0; 857662cb04cSPoul-Henning Kamp yyHaveDay = 0; 858662cb04cSPoul-Henning Kamp yyHaveRel = 0; 859662cb04cSPoul-Henning Kamp yyHaveTime = 0; 860662cb04cSPoul-Henning Kamp yyHaveZone = 0; 861662cb04cSPoul-Henning Kamp 862662cb04cSPoul-Henning Kamp if (yyparse() 863662cb04cSPoul-Henning Kamp || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) 864662cb04cSPoul-Henning Kamp return -1; 865662cb04cSPoul-Henning Kamp 866662cb04cSPoul-Henning Kamp if (yyHaveDate || yyHaveTime || yyHaveDay) { 867662cb04cSPoul-Henning Kamp Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, 868662cb04cSPoul-Henning Kamp yyMeridian, yyDSTmode); 869662cb04cSPoul-Henning Kamp if (Start < 0) 870662cb04cSPoul-Henning Kamp return -1; 871662cb04cSPoul-Henning Kamp } 872662cb04cSPoul-Henning Kamp else { 873662cb04cSPoul-Henning Kamp Start = nowtime; 874662cb04cSPoul-Henning Kamp if (!yyHaveRel) 875662cb04cSPoul-Henning Kamp Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; 876662cb04cSPoul-Henning Kamp } 877662cb04cSPoul-Henning Kamp 878662cb04cSPoul-Henning Kamp Start += yyRelSeconds; 879662cb04cSPoul-Henning Kamp Start += RelativeMonth(Start, yyRelMonth); 880662cb04cSPoul-Henning Kamp 881662cb04cSPoul-Henning Kamp if (yyHaveDay && !yyHaveDate) { 882662cb04cSPoul-Henning Kamp tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); 883662cb04cSPoul-Henning Kamp Start += tod; 884662cb04cSPoul-Henning Kamp } 885662cb04cSPoul-Henning Kamp 886662cb04cSPoul-Henning Kamp /* Have to do *something* with a legitimate -1 so it's distinguishable 887662cb04cSPoul-Henning Kamp * from the error return value. (Alternately could set errno on error.) */ 888662cb04cSPoul-Henning Kamp return Start == -1 ? 0 : Start; 889662cb04cSPoul-Henning Kamp } 890