10c3983b2SBen Gras %{ 20c3983b2SBen Gras /* 30c3983b2SBen Gras ** Originally written by Steven M. Bellovin <smb@research.att.com> while 40c3983b2SBen Gras ** at the University of North Carolina at Chapel Hill. Later tweaked by 50c3983b2SBen Gras ** a couple of people on Usenet. Completely overhauled by Rich $alz 60c3983b2SBen Gras ** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990; 70c3983b2SBen Gras ** 80c3983b2SBen Gras ** This grammar has 10 shift/reduce conflicts. 90c3983b2SBen Gras ** 100c3983b2SBen Gras ** This code is in the public domain and has no copyright. 110c3983b2SBen Gras */ 120c3983b2SBen Gras /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ 130c3983b2SBen Gras /* SUPPRESS 288 on yyerrlab *//* Label unused */ 140c3983b2SBen Gras 1584d9c625SLionel Sambuc #include <sys/cdefs.h> 1684d9c625SLionel Sambuc #ifdef __RCSID 17*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: parsedate.y,v 1.20 2014/10/08 17:38:28 apb Exp $"); 1884d9c625SLionel Sambuc #endif 1984d9c625SLionel Sambuc 200c3983b2SBen Gras #include <stdio.h> 210c3983b2SBen Gras #include <ctype.h> 2284d9c625SLionel Sambuc #include <errno.h> 230c3983b2SBen Gras #include <string.h> 240c3983b2SBen Gras #include <time.h> 250c3983b2SBen Gras #include <util.h> 260c3983b2SBen Gras #include <stdlib.h> 270c3983b2SBen Gras 280c3983b2SBen Gras /* NOTES on rebuilding parsedate.c (particularly for inclusion in CVS 290c3983b2SBen Gras releases): 300c3983b2SBen Gras 310c3983b2SBen Gras We don't want to mess with all the portability hassles of alloca. 320c3983b2SBen Gras In particular, most (all?) versions of bison will use alloca in 330c3983b2SBen Gras their parser. If bison works on your system (e.g. it should work 340c3983b2SBen Gras with gcc), then go ahead and use it, but the more general solution 350c3983b2SBen Gras is to use byacc instead of bison, which should generate a portable 360c3983b2SBen Gras parser. I played with adding "#define alloca dont_use_alloca", to 370c3983b2SBen Gras give an error if the parser generator uses alloca (and thus detect 380c3983b2SBen Gras unportable parsedate.c's), but that seems to cause as many problems 390c3983b2SBen Gras as it solves. */ 400c3983b2SBen Gras 410c3983b2SBen Gras #define EPOCH 1970 420c3983b2SBen Gras #define HOUR(x) ((time_t)(x) * 60) 430c3983b2SBen Gras #define SECSPERDAY (24L * 60L * 60L) 440c3983b2SBen Gras 45*0a6a1f1dSLionel Sambuc #define USE_LOCAL_TIME 99999 /* special case for Convert() and yyTimezone */ 460c3983b2SBen Gras 470c3983b2SBen Gras /* 480c3983b2SBen Gras ** An entry in the lexical lookup table. 490c3983b2SBen Gras */ 500c3983b2SBen Gras typedef struct _TABLE { 510c3983b2SBen Gras const char *name; 520c3983b2SBen Gras int type; 530c3983b2SBen Gras time_t value; 540c3983b2SBen Gras } TABLE; 550c3983b2SBen Gras 560c3983b2SBen Gras 570c3983b2SBen Gras /* 580c3983b2SBen Gras ** Daylight-savings mode: on, off, or not yet known. 590c3983b2SBen Gras */ 600c3983b2SBen Gras typedef enum _DSTMODE { 610c3983b2SBen Gras DSTon, DSToff, DSTmaybe 620c3983b2SBen Gras } DSTMODE; 630c3983b2SBen Gras 640c3983b2SBen Gras /* 650c3983b2SBen Gras ** Meridian: am, pm, or 24-hour style. 660c3983b2SBen Gras */ 670c3983b2SBen Gras typedef enum _MERIDIAN { 680c3983b2SBen Gras MERam, MERpm, MER24 690c3983b2SBen Gras } MERIDIAN; 700c3983b2SBen Gras 710c3983b2SBen Gras 720c3983b2SBen Gras struct dateinfo { 73*0a6a1f1dSLionel Sambuc DSTMODE yyDSTmode; /* DST on/off/maybe */ 740c3983b2SBen Gras time_t yyDayOrdinal; 750c3983b2SBen Gras time_t yyDayNumber; 760c3983b2SBen Gras int yyHaveDate; 77*0a6a1f1dSLionel Sambuc int yyHaveFullYear; /* if true, year is not abbreviated. */ 78*0a6a1f1dSLionel Sambuc /* if false, need to call AdjustYear(). */ 790c3983b2SBen Gras int yyHaveDay; 800c3983b2SBen Gras int yyHaveRel; 810c3983b2SBen Gras int yyHaveTime; 820c3983b2SBen Gras int yyHaveZone; 83*0a6a1f1dSLionel Sambuc time_t yyTimezone; /* Timezone as minutes ahead/east of UTC */ 84*0a6a1f1dSLionel Sambuc time_t yyDay; /* Day of month [1-31] */ 85*0a6a1f1dSLionel Sambuc time_t yyHour; /* Hour of day [0-24] or [1-12] */ 86*0a6a1f1dSLionel Sambuc time_t yyMinutes; /* Minute of hour [0-59] */ 87*0a6a1f1dSLionel Sambuc time_t yyMonth; /* Month of year [1-12] */ 88*0a6a1f1dSLionel Sambuc time_t yySeconds; /* Second of minute [0-60] */ 89*0a6a1f1dSLionel Sambuc time_t yyYear; /* Year, see also yyHaveFullYear */ 90*0a6a1f1dSLionel Sambuc MERIDIAN yyMeridian; /* Interpret yyHour as AM/PM/24 hour clock */ 910c3983b2SBen Gras time_t yyRelMonth; 920c3983b2SBen Gras time_t yyRelSeconds; 930c3983b2SBen Gras }; 940c3983b2SBen Gras %} 950c3983b2SBen Gras 960c3983b2SBen Gras %union { 970c3983b2SBen Gras time_t Number; 980c3983b2SBen Gras enum _MERIDIAN Meridian; 990c3983b2SBen Gras } 1000c3983b2SBen Gras 1010c3983b2SBen Gras %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT 1020c3983b2SBen Gras %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST AT_SIGN 1030c3983b2SBen Gras 1040c3983b2SBen Gras %type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT 1050c3983b2SBen Gras %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE 1060c3983b2SBen Gras %type <Meridian> tMERIDIAN o_merid 1070c3983b2SBen Gras 1080c3983b2SBen Gras %parse-param { struct dateinfo *param } 1090c3983b2SBen Gras %parse-param { const char **yyInput } 1100c3983b2SBen Gras %lex-param { const char **yyInput } 1110c3983b2SBen Gras %pure-parser 1120c3983b2SBen Gras 1130c3983b2SBen Gras %% 1140c3983b2SBen Gras 1150c3983b2SBen Gras spec : /* NULL */ 1160c3983b2SBen Gras | spec item 1170c3983b2SBen Gras ; 1180c3983b2SBen Gras 1190c3983b2SBen Gras item : time { 1200c3983b2SBen Gras param->yyHaveTime++; 1210c3983b2SBen Gras } 122*0a6a1f1dSLionel Sambuc | time_numericzone { 123*0a6a1f1dSLionel Sambuc param->yyHaveTime++; 124*0a6a1f1dSLionel Sambuc param->yyHaveZone++; 125*0a6a1f1dSLionel Sambuc } 1260c3983b2SBen Gras | zone { 1270c3983b2SBen Gras param->yyHaveZone++; 1280c3983b2SBen Gras } 1290c3983b2SBen Gras | date { 1300c3983b2SBen Gras param->yyHaveDate++; 1310c3983b2SBen Gras } 1320c3983b2SBen Gras | day { 1330c3983b2SBen Gras param->yyHaveDay++; 1340c3983b2SBen Gras } 1350c3983b2SBen Gras | rel { 1360c3983b2SBen Gras param->yyHaveRel++; 1370c3983b2SBen Gras } 1380c3983b2SBen Gras | cvsstamp { 1390c3983b2SBen Gras param->yyHaveTime++; 1400c3983b2SBen Gras param->yyHaveDate++; 1410c3983b2SBen Gras param->yyHaveZone++; 1420c3983b2SBen Gras } 1430c3983b2SBen Gras | epochdate { 1440c3983b2SBen Gras param->yyHaveTime++; 1450c3983b2SBen Gras param->yyHaveDate++; 1460c3983b2SBen Gras param->yyHaveZone++; 1470c3983b2SBen Gras } 1480c3983b2SBen Gras | number 1490c3983b2SBen Gras ; 1500c3983b2SBen Gras 1510c3983b2SBen Gras cvsstamp: tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER { 1520c3983b2SBen Gras param->yyYear = $1; 1530c3983b2SBen Gras if (param->yyYear < 100) param->yyYear += 1900; 154*0a6a1f1dSLionel Sambuc param->yyHaveFullYear = 1; 1550c3983b2SBen Gras param->yyMonth = $3; 1560c3983b2SBen Gras param->yyDay = $5; 1570c3983b2SBen Gras param->yyHour = $7; 1580c3983b2SBen Gras param->yyMinutes = $9; 1590c3983b2SBen Gras param->yySeconds = $11; 1600c3983b2SBen Gras param->yyDSTmode = DSToff; 1610c3983b2SBen Gras param->yyTimezone = 0; 1620c3983b2SBen Gras } 1630c3983b2SBen Gras ; 1640c3983b2SBen Gras 16584d9c625SLionel Sambuc epochdate: AT_SIGN at_number { 16684d9c625SLionel Sambuc time_t when = $<Number>2; 1670c3983b2SBen Gras struct tm tmbuf; 1680c3983b2SBen Gras if (gmtime_r(&when, &tmbuf) != NULL) { 1690c3983b2SBen Gras param->yyYear = tmbuf.tm_year + 1900; 1700c3983b2SBen Gras param->yyMonth = tmbuf.tm_mon + 1; 1710c3983b2SBen Gras param->yyDay = tmbuf.tm_mday; 1720c3983b2SBen Gras 1730c3983b2SBen Gras param->yyHour = tmbuf.tm_hour; 1740c3983b2SBen Gras param->yyMinutes = tmbuf.tm_min; 1750c3983b2SBen Gras param->yySeconds = tmbuf.tm_sec; 1760c3983b2SBen Gras } else { 1770c3983b2SBen Gras param->yyYear = EPOCH; 1780c3983b2SBen Gras param->yyMonth = 1; 1790c3983b2SBen Gras param->yyDay = 1; 1800c3983b2SBen Gras 1810c3983b2SBen Gras param->yyHour = 0; 1820c3983b2SBen Gras param->yyMinutes = 0; 1830c3983b2SBen Gras param->yySeconds = 0; 1840c3983b2SBen Gras } 185*0a6a1f1dSLionel Sambuc param->yyHaveFullYear = 1; 1860c3983b2SBen Gras param->yyDSTmode = DSToff; 1870c3983b2SBen Gras param->yyTimezone = 0; 1880c3983b2SBen Gras } 1890c3983b2SBen Gras ; 1900c3983b2SBen Gras 19184d9c625SLionel Sambuc at_number : tUNUMBER | tSNUMBER ; 19284d9c625SLionel Sambuc 1930c3983b2SBen Gras time : tUNUMBER tMERIDIAN { 1940c3983b2SBen Gras param->yyHour = $1; 1950c3983b2SBen Gras param->yyMinutes = 0; 1960c3983b2SBen Gras param->yySeconds = 0; 1970c3983b2SBen Gras param->yyMeridian = $2; 1980c3983b2SBen Gras } 1990c3983b2SBen Gras | tUNUMBER ':' tUNUMBER o_merid { 2000c3983b2SBen Gras param->yyHour = $1; 2010c3983b2SBen Gras param->yyMinutes = $3; 2020c3983b2SBen Gras param->yySeconds = 0; 2030c3983b2SBen Gras param->yyMeridian = $4; 2040c3983b2SBen Gras } 2050c3983b2SBen Gras | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { 2060c3983b2SBen Gras param->yyHour = $1; 2070c3983b2SBen Gras param->yyMinutes = $3; 2080c3983b2SBen Gras param->yySeconds = $5; 2090c3983b2SBen Gras param->yyMeridian = $6; 2100c3983b2SBen Gras } 211*0a6a1f1dSLionel Sambuc | tUNUMBER ':' tUNUMBER ':' tUNUMBER '.' tUNUMBER { 212*0a6a1f1dSLionel Sambuc param->yyHour = $1; 213*0a6a1f1dSLionel Sambuc param->yyMinutes = $3; 214*0a6a1f1dSLionel Sambuc param->yySeconds = $5; 215*0a6a1f1dSLionel Sambuc param->yyMeridian = MER24; 216*0a6a1f1dSLionel Sambuc /* XXX: Do nothing with millis */ 217*0a6a1f1dSLionel Sambuc } 218*0a6a1f1dSLionel Sambuc ; 219*0a6a1f1dSLionel Sambuc 220*0a6a1f1dSLionel Sambuc time_numericzone : tUNUMBER ':' tUNUMBER tSNUMBER { 221*0a6a1f1dSLionel Sambuc param->yyHour = $1; 222*0a6a1f1dSLionel Sambuc param->yyMinutes = $3; 223*0a6a1f1dSLionel Sambuc param->yyMeridian = MER24; 224*0a6a1f1dSLionel Sambuc param->yyDSTmode = DSToff; 225*0a6a1f1dSLionel Sambuc param->yyTimezone = - ($4 % 100 + ($4 / 100) * 60); 226*0a6a1f1dSLionel Sambuc } 2270c3983b2SBen Gras | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { 2280c3983b2SBen Gras param->yyHour = $1; 2290c3983b2SBen Gras param->yyMinutes = $3; 2300c3983b2SBen Gras param->yySeconds = $5; 2310c3983b2SBen Gras param->yyMeridian = MER24; 2320c3983b2SBen Gras param->yyDSTmode = DSToff; 2330c3983b2SBen Gras param->yyTimezone = - ($6 % 100 + ($6 / 100) * 60); 2340c3983b2SBen Gras } 2350c3983b2SBen Gras ; 2360c3983b2SBen Gras 2370c3983b2SBen Gras zone : tZONE { 2380c3983b2SBen Gras param->yyTimezone = $1; 2390c3983b2SBen Gras param->yyDSTmode = DSToff; 2400c3983b2SBen Gras } 2410c3983b2SBen Gras | tDAYZONE { 2420c3983b2SBen Gras param->yyTimezone = $1; 2430c3983b2SBen Gras param->yyDSTmode = DSTon; 2440c3983b2SBen Gras } 2450c3983b2SBen Gras | 2460c3983b2SBen Gras tZONE tDST { 2470c3983b2SBen Gras param->yyTimezone = $1; 2480c3983b2SBen Gras param->yyDSTmode = DSTon; 2490c3983b2SBen Gras } 2500c3983b2SBen Gras ; 2510c3983b2SBen Gras 2520c3983b2SBen Gras day : tDAY { 2530c3983b2SBen Gras param->yyDayOrdinal = 1; 2540c3983b2SBen Gras param->yyDayNumber = $1; 2550c3983b2SBen Gras } 2560c3983b2SBen Gras | tDAY ',' { 2570c3983b2SBen Gras param->yyDayOrdinal = 1; 2580c3983b2SBen Gras param->yyDayNumber = $1; 2590c3983b2SBen Gras } 2600c3983b2SBen Gras | tUNUMBER tDAY { 2610c3983b2SBen Gras param->yyDayOrdinal = $1; 2620c3983b2SBen Gras param->yyDayNumber = $2; 2630c3983b2SBen Gras } 2640c3983b2SBen Gras ; 2650c3983b2SBen Gras 2660c3983b2SBen Gras date : tUNUMBER '/' tUNUMBER { 2670c3983b2SBen Gras param->yyMonth = $1; 2680c3983b2SBen Gras param->yyDay = $3; 2690c3983b2SBen Gras } 2700c3983b2SBen Gras | tUNUMBER '/' tUNUMBER '/' tUNUMBER { 2710c3983b2SBen Gras if ($1 >= 100) { 2720c3983b2SBen Gras param->yyYear = $1; 2730c3983b2SBen Gras param->yyMonth = $3; 2740c3983b2SBen Gras param->yyDay = $5; 2750c3983b2SBen Gras } else { 2760c3983b2SBen Gras param->yyMonth = $1; 2770c3983b2SBen Gras param->yyDay = $3; 2780c3983b2SBen Gras param->yyYear = $5; 2790c3983b2SBen Gras } 2800c3983b2SBen Gras } 2810c3983b2SBen Gras | tUNUMBER tSNUMBER tSNUMBER { 2820c3983b2SBen Gras /* ISO 8601 format. yyyy-mm-dd. */ 2830c3983b2SBen Gras param->yyYear = $1; 284*0a6a1f1dSLionel Sambuc param->yyHaveFullYear = 1; 2850c3983b2SBen Gras param->yyMonth = -$2; 2860c3983b2SBen Gras param->yyDay = -$3; 2870c3983b2SBen Gras } 2880c3983b2SBen Gras | tUNUMBER tMONTH tSNUMBER { 2890c3983b2SBen Gras /* e.g. 17-JUN-1992. */ 2900c3983b2SBen Gras param->yyDay = $1; 2910c3983b2SBen Gras param->yyMonth = $2; 2920c3983b2SBen Gras param->yyYear = -$3; 2930c3983b2SBen Gras } 2940c3983b2SBen Gras | tMONTH tUNUMBER { 2950c3983b2SBen Gras param->yyMonth = $1; 2960c3983b2SBen Gras param->yyDay = $2; 2970c3983b2SBen Gras } 2980c3983b2SBen Gras | tMONTH tUNUMBER ',' tUNUMBER { 2990c3983b2SBen Gras param->yyMonth = $1; 3000c3983b2SBen Gras param->yyDay = $2; 3010c3983b2SBen Gras param->yyYear = $4; 3020c3983b2SBen Gras } 3030c3983b2SBen Gras | tUNUMBER tMONTH { 3040c3983b2SBen Gras param->yyMonth = $2; 3050c3983b2SBen Gras param->yyDay = $1; 3060c3983b2SBen Gras } 3070c3983b2SBen Gras | tUNUMBER tMONTH tUNUMBER { 3080c3983b2SBen Gras param->yyMonth = $2; 3090c3983b2SBen Gras param->yyDay = $1; 3100c3983b2SBen Gras param->yyYear = $3; 3110c3983b2SBen Gras } 3120c3983b2SBen Gras ; 3130c3983b2SBen Gras 3140c3983b2SBen Gras rel : relunit tAGO { 3150c3983b2SBen Gras param->yyRelSeconds = -param->yyRelSeconds; 3160c3983b2SBen Gras param->yyRelMonth = -param->yyRelMonth; 3170c3983b2SBen Gras } 3180c3983b2SBen Gras | relunit 3190c3983b2SBen Gras ; 3200c3983b2SBen Gras 3210c3983b2SBen Gras relunit : tUNUMBER tMINUTE_UNIT { 3220c3983b2SBen Gras param->yyRelSeconds += $1 * $2 * 60L; 3230c3983b2SBen Gras } 3240c3983b2SBen Gras | tSNUMBER tMINUTE_UNIT { 3250c3983b2SBen Gras param->yyRelSeconds += $1 * $2 * 60L; 3260c3983b2SBen Gras } 3270c3983b2SBen Gras | tMINUTE_UNIT { 3280c3983b2SBen Gras param->yyRelSeconds += $1 * 60L; 3290c3983b2SBen Gras } 3300c3983b2SBen Gras | tSNUMBER tSEC_UNIT { 3310c3983b2SBen Gras param->yyRelSeconds += $1; 3320c3983b2SBen Gras } 3330c3983b2SBen Gras | tUNUMBER tSEC_UNIT { 3340c3983b2SBen Gras param->yyRelSeconds += $1; 3350c3983b2SBen Gras } 3360c3983b2SBen Gras | tSEC_UNIT { 3370c3983b2SBen Gras param->yyRelSeconds++; 3380c3983b2SBen Gras } 3390c3983b2SBen Gras | tSNUMBER tMONTH_UNIT { 3400c3983b2SBen Gras param->yyRelMonth += $1 * $2; 3410c3983b2SBen Gras } 3420c3983b2SBen Gras | tUNUMBER tMONTH_UNIT { 3430c3983b2SBen Gras param->yyRelMonth += $1 * $2; 3440c3983b2SBen Gras } 3450c3983b2SBen Gras | tMONTH_UNIT { 3460c3983b2SBen Gras param->yyRelMonth += $1; 3470c3983b2SBen Gras } 3480c3983b2SBen Gras ; 3490c3983b2SBen Gras 3500c3983b2SBen Gras number : tUNUMBER { 3510c3983b2SBen Gras if (param->yyHaveTime && param->yyHaveDate && !param->yyHaveRel) 3520c3983b2SBen Gras param->yyYear = $1; 3530c3983b2SBen Gras else { 3540c3983b2SBen Gras if($1>10000) { 3550c3983b2SBen Gras param->yyHaveDate++; 3560c3983b2SBen Gras param->yyDay= ($1)%100; 3570c3983b2SBen Gras param->yyMonth= ($1/100)%100; 3580c3983b2SBen Gras param->yyYear = $1/10000; 3590c3983b2SBen Gras } 3600c3983b2SBen Gras else { 3610c3983b2SBen Gras param->yyHaveTime++; 3620c3983b2SBen Gras if ($1 < 100) { 3630c3983b2SBen Gras param->yyHour = $1; 3640c3983b2SBen Gras param->yyMinutes = 0; 3650c3983b2SBen Gras } 3660c3983b2SBen Gras else { 3670c3983b2SBen Gras param->yyHour = $1 / 100; 3680c3983b2SBen Gras param->yyMinutes = $1 % 100; 3690c3983b2SBen Gras } 3700c3983b2SBen Gras param->yySeconds = 0; 3710c3983b2SBen Gras param->yyMeridian = MER24; 3720c3983b2SBen Gras } 3730c3983b2SBen Gras } 3740c3983b2SBen Gras } 3750c3983b2SBen Gras ; 3760c3983b2SBen Gras 3770c3983b2SBen Gras o_merid : /* NULL */ { 3780c3983b2SBen Gras $$ = MER24; 3790c3983b2SBen Gras } 3800c3983b2SBen Gras | tMERIDIAN { 3810c3983b2SBen Gras $$ = $1; 3820c3983b2SBen Gras } 3830c3983b2SBen Gras ; 3840c3983b2SBen Gras 3850c3983b2SBen Gras %% 3860c3983b2SBen Gras 3870c3983b2SBen Gras /* Month and day table. */ 38884d9c625SLionel Sambuc static const TABLE MonthDayTable[] = { 3890c3983b2SBen Gras { "january", tMONTH, 1 }, 3900c3983b2SBen Gras { "february", tMONTH, 2 }, 3910c3983b2SBen Gras { "march", tMONTH, 3 }, 3920c3983b2SBen Gras { "april", tMONTH, 4 }, 3930c3983b2SBen Gras { "may", tMONTH, 5 }, 3940c3983b2SBen Gras { "june", tMONTH, 6 }, 3950c3983b2SBen Gras { "july", tMONTH, 7 }, 3960c3983b2SBen Gras { "august", tMONTH, 8 }, 3970c3983b2SBen Gras { "september", tMONTH, 9 }, 3980c3983b2SBen Gras { "sept", tMONTH, 9 }, 3990c3983b2SBen Gras { "october", tMONTH, 10 }, 4000c3983b2SBen Gras { "november", tMONTH, 11 }, 4010c3983b2SBen Gras { "december", tMONTH, 12 }, 4020c3983b2SBen Gras { "sunday", tDAY, 0 }, 4030c3983b2SBen Gras { "monday", tDAY, 1 }, 4040c3983b2SBen Gras { "tuesday", tDAY, 2 }, 4050c3983b2SBen Gras { "tues", tDAY, 2 }, 4060c3983b2SBen Gras { "wednesday", tDAY, 3 }, 4070c3983b2SBen Gras { "wednes", tDAY, 3 }, 4080c3983b2SBen Gras { "thursday", tDAY, 4 }, 4090c3983b2SBen Gras { "thur", tDAY, 4 }, 4100c3983b2SBen Gras { "thurs", tDAY, 4 }, 4110c3983b2SBen Gras { "friday", tDAY, 5 }, 4120c3983b2SBen Gras { "saturday", tDAY, 6 }, 4130c3983b2SBen Gras { NULL, 0, 0 } 4140c3983b2SBen Gras }; 4150c3983b2SBen Gras 4160c3983b2SBen Gras /* Time units table. */ 41784d9c625SLionel Sambuc static const TABLE UnitsTable[] = { 4180c3983b2SBen Gras { "year", tMONTH_UNIT, 12 }, 4190c3983b2SBen Gras { "month", tMONTH_UNIT, 1 }, 4200c3983b2SBen Gras { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, 4210c3983b2SBen Gras { "week", tMINUTE_UNIT, 7 * 24 * 60 }, 4220c3983b2SBen Gras { "day", tMINUTE_UNIT, 1 * 24 * 60 }, 4230c3983b2SBen Gras { "hour", tMINUTE_UNIT, 60 }, 4240c3983b2SBen Gras { "minute", tMINUTE_UNIT, 1 }, 4250c3983b2SBen Gras { "min", tMINUTE_UNIT, 1 }, 4260c3983b2SBen Gras { "second", tSEC_UNIT, 1 }, 4270c3983b2SBen Gras { "sec", tSEC_UNIT, 1 }, 4280c3983b2SBen Gras { NULL, 0, 0 } 4290c3983b2SBen Gras }; 4300c3983b2SBen Gras 4310c3983b2SBen Gras /* Assorted relative-time words. */ 43284d9c625SLionel Sambuc static const TABLE OtherTable[] = { 4330c3983b2SBen Gras { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, 4340c3983b2SBen Gras { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, 4350c3983b2SBen Gras { "today", tMINUTE_UNIT, 0 }, 4360c3983b2SBen Gras { "now", tMINUTE_UNIT, 0 }, 4370c3983b2SBen Gras { "last", tUNUMBER, -1 }, 4380c3983b2SBen Gras { "this", tMINUTE_UNIT, 0 }, 4390c3983b2SBen Gras { "next", tUNUMBER, 2 }, 4400c3983b2SBen Gras { "first", tUNUMBER, 1 }, 4410c3983b2SBen Gras { "one", tUNUMBER, 1 }, 4420c3983b2SBen Gras /* { "second", tUNUMBER, 2 }, */ 4430c3983b2SBen Gras { "two", tUNUMBER, 2 }, 4440c3983b2SBen Gras { "third", tUNUMBER, 3 }, 4450c3983b2SBen Gras { "three", tUNUMBER, 3 }, 4460c3983b2SBen Gras { "fourth", tUNUMBER, 4 }, 4470c3983b2SBen Gras { "four", tUNUMBER, 4 }, 4480c3983b2SBen Gras { "fifth", tUNUMBER, 5 }, 4490c3983b2SBen Gras { "five", tUNUMBER, 5 }, 4500c3983b2SBen Gras { "sixth", tUNUMBER, 6 }, 4510c3983b2SBen Gras { "six", tUNUMBER, 6 }, 4520c3983b2SBen Gras { "seventh", tUNUMBER, 7 }, 4530c3983b2SBen Gras { "seven", tUNUMBER, 7 }, 4540c3983b2SBen Gras { "eighth", tUNUMBER, 8 }, 4550c3983b2SBen Gras { "eight", tUNUMBER, 8 }, 4560c3983b2SBen Gras { "ninth", tUNUMBER, 9 }, 4570c3983b2SBen Gras { "nine", tUNUMBER, 9 }, 4580c3983b2SBen Gras { "tenth", tUNUMBER, 10 }, 4590c3983b2SBen Gras { "ten", tUNUMBER, 10 }, 4600c3983b2SBen Gras { "eleventh", tUNUMBER, 11 }, 4610c3983b2SBen Gras { "eleven", tUNUMBER, 11 }, 4620c3983b2SBen Gras { "twelfth", tUNUMBER, 12 }, 4630c3983b2SBen Gras { "twelve", tUNUMBER, 12 }, 4640c3983b2SBen Gras { "ago", tAGO, 1 }, 4650c3983b2SBen Gras { NULL, 0, 0 } 4660c3983b2SBen Gras }; 4670c3983b2SBen Gras 4680c3983b2SBen Gras /* The timezone table. */ 4690c3983b2SBen Gras /* Some of these are commented out because a time_t can't store a float. */ 47084d9c625SLionel Sambuc static const TABLE TimezoneTable[] = { 4710c3983b2SBen Gras { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ 4720c3983b2SBen Gras { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ 4730c3983b2SBen Gras { "utc", tZONE, HOUR( 0) }, 4740c3983b2SBen Gras { "wet", tZONE, HOUR( 0) }, /* Western European */ 4750c3983b2SBen Gras { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ 4760c3983b2SBen Gras { "wat", tZONE, HOUR( 1) }, /* West Africa */ 4770c3983b2SBen Gras { "at", tZONE, HOUR( 2) }, /* Azores */ 4780c3983b2SBen Gras #if 0 4790c3983b2SBen Gras /* For completeness. BST is also British Summer, and GST is 4800c3983b2SBen Gras * also Guam Standard. */ 4810c3983b2SBen Gras { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ 4820c3983b2SBen Gras { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ 4830c3983b2SBen Gras #endif 4840c3983b2SBen Gras #if 0 4850c3983b2SBen Gras { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ 4860c3983b2SBen Gras { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ 4870c3983b2SBen Gras { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ 4880c3983b2SBen Gras #endif 4890c3983b2SBen Gras { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ 4900c3983b2SBen Gras { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ 4910c3983b2SBen Gras { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ 4920c3983b2SBen Gras { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ 4930c3983b2SBen Gras { "cst", tZONE, HOUR( 6) }, /* Central Standard */ 4940c3983b2SBen Gras { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ 4950c3983b2SBen Gras { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ 4960c3983b2SBen Gras { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ 4970c3983b2SBen Gras { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ 4980c3983b2SBen Gras { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ 4990c3983b2SBen Gras { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ 5000c3983b2SBen Gras { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ 5010c3983b2SBen Gras { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ 5020c3983b2SBen Gras { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ 5030c3983b2SBen Gras { "cat", tZONE, HOUR(10) }, /* Central Alaska */ 5040c3983b2SBen Gras { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ 5050c3983b2SBen Gras { "nt", tZONE, HOUR(11) }, /* Nome */ 5060c3983b2SBen Gras { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ 5070c3983b2SBen Gras { "cet", tZONE, -HOUR(1) }, /* Central European */ 5080c3983b2SBen Gras { "met", tZONE, -HOUR(1) }, /* Middle European */ 5090c3983b2SBen Gras { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ 5100c3983b2SBen Gras { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ 5110c3983b2SBen Gras { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ 5120c3983b2SBen Gras { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ 5130c3983b2SBen Gras { "fwt", tZONE, -HOUR(1) }, /* French Winter */ 5140c3983b2SBen Gras { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ 5150c3983b2SBen Gras { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ 5160c3983b2SBen Gras { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ 5170c3983b2SBen Gras #if 0 5180c3983b2SBen Gras { "it", tZONE, -HOUR(3.5) },/* Iran */ 5190c3983b2SBen Gras #endif 5200c3983b2SBen Gras { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ 5210c3983b2SBen Gras { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ 5220c3983b2SBen Gras #if 0 5230c3983b2SBen Gras { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ 5240c3983b2SBen Gras #endif 5250c3983b2SBen Gras { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ 5260c3983b2SBen Gras #if 0 5270c3983b2SBen Gras /* For completeness. NST is also Newfoundland Stanard, and SST is 5280c3983b2SBen Gras * also Swedish Summer. */ 5290c3983b2SBen Gras { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ 5300c3983b2SBen Gras { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ 5310c3983b2SBen Gras #endif /* 0 */ 5320c3983b2SBen Gras { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ 5330c3983b2SBen Gras { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ 5340c3983b2SBen Gras #if 0 5350c3983b2SBen Gras { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ 5360c3983b2SBen Gras #endif 5370c3983b2SBen Gras { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ 5380c3983b2SBen Gras { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ 5390c3983b2SBen Gras #if 0 5400c3983b2SBen Gras { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ 5410c3983b2SBen Gras { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ 5420c3983b2SBen Gras #endif 5430c3983b2SBen Gras { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ 5440c3983b2SBen Gras { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ 5450c3983b2SBen Gras { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ 5460c3983b2SBen Gras { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ 5470c3983b2SBen Gras { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ 5480c3983b2SBen Gras { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ 5490c3983b2SBen Gras { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ 5500c3983b2SBen Gras { NULL, 0, 0 } 5510c3983b2SBen Gras }; 5520c3983b2SBen Gras 5530c3983b2SBen Gras /* Military timezone table. */ 55484d9c625SLionel Sambuc static const TABLE MilitaryTable[] = { 5550c3983b2SBen Gras { "a", tZONE, HOUR( 1) }, 5560c3983b2SBen Gras { "b", tZONE, HOUR( 2) }, 5570c3983b2SBen Gras { "c", tZONE, HOUR( 3) }, 5580c3983b2SBen Gras { "d", tZONE, HOUR( 4) }, 5590c3983b2SBen Gras { "e", tZONE, HOUR( 5) }, 5600c3983b2SBen Gras { "f", tZONE, HOUR( 6) }, 5610c3983b2SBen Gras { "g", tZONE, HOUR( 7) }, 5620c3983b2SBen Gras { "h", tZONE, HOUR( 8) }, 5630c3983b2SBen Gras { "i", tZONE, HOUR( 9) }, 5640c3983b2SBen Gras { "k", tZONE, HOUR( 10) }, 5650c3983b2SBen Gras { "l", tZONE, HOUR( 11) }, 5660c3983b2SBen Gras { "m", tZONE, HOUR( 12) }, 5670c3983b2SBen Gras { "n", tZONE, HOUR(- 1) }, 5680c3983b2SBen Gras { "o", tZONE, HOUR(- 2) }, 5690c3983b2SBen Gras { "p", tZONE, HOUR(- 3) }, 5700c3983b2SBen Gras { "q", tZONE, HOUR(- 4) }, 5710c3983b2SBen Gras { "r", tZONE, HOUR(- 5) }, 5720c3983b2SBen Gras { "s", tZONE, HOUR(- 6) }, 5730c3983b2SBen Gras { "t", tZONE, HOUR(- 7) }, 5740c3983b2SBen Gras { "u", tZONE, HOUR(- 8) }, 5750c3983b2SBen Gras { "v", tZONE, HOUR(- 9) }, 5760c3983b2SBen Gras { "w", tZONE, HOUR(-10) }, 5770c3983b2SBen Gras { "x", tZONE, HOUR(-11) }, 5780c3983b2SBen Gras { "y", tZONE, HOUR(-12) }, 5790c3983b2SBen Gras { "z", tZONE, HOUR( 0) }, 5800c3983b2SBen Gras { NULL, 0, 0 } 5810c3983b2SBen Gras }; 5820c3983b2SBen Gras 5830c3983b2SBen Gras 5840c3983b2SBen Gras 5850c3983b2SBen Gras 5860c3983b2SBen Gras /* ARGSUSED */ 5870c3983b2SBen Gras static int 5880c3983b2SBen Gras yyerror(struct dateinfo *param, const char **inp, const char *s __unused) 5890c3983b2SBen Gras { 5900c3983b2SBen Gras return 0; 5910c3983b2SBen Gras } 5920c3983b2SBen Gras 5930c3983b2SBen Gras 594*0a6a1f1dSLionel Sambuc /* Adjust year from a value that might be abbreviated, to a full value. 595*0a6a1f1dSLionel Sambuc * e.g. convert 70 to 1970. 596*0a6a1f1dSLionel Sambuc * Input Year is either: 597*0a6a1f1dSLionel Sambuc * - A negative number, which means to use its absolute value (why?) 598*0a6a1f1dSLionel Sambuc * - A number from 0 to 99, which means a year from 1900 to 1999, or 599*0a6a1f1dSLionel Sambuc * - The actual year (>=100). 600*0a6a1f1dSLionel Sambuc * Returns the full year. */ 6010c3983b2SBen Gras static time_t 602*0a6a1f1dSLionel Sambuc AdjustYear(time_t Year) 6030c3983b2SBen Gras { 6040c3983b2SBen Gras /* XXX Y2K */ 6050c3983b2SBen Gras if (Year < 0) 6060c3983b2SBen Gras Year = -Year; 6070c3983b2SBen Gras if (Year < 70) 6080c3983b2SBen Gras Year += 2000; 6090c3983b2SBen Gras else if (Year < 100) 6100c3983b2SBen Gras Year += 1900; 611*0a6a1f1dSLionel Sambuc return Year; 612*0a6a1f1dSLionel Sambuc } 613*0a6a1f1dSLionel Sambuc 614*0a6a1f1dSLionel Sambuc static time_t 615*0a6a1f1dSLionel Sambuc Convert( 616*0a6a1f1dSLionel Sambuc time_t Month, /* month of year [1-12] */ 617*0a6a1f1dSLionel Sambuc time_t Day, /* day of month [1-31] */ 618*0a6a1f1dSLionel Sambuc time_t Year, /* year, not abbreviated in any way */ 619*0a6a1f1dSLionel Sambuc time_t Hours, /* Hour of day [0-24] */ 620*0a6a1f1dSLionel Sambuc time_t Minutes, /* Minute of hour [0-59] */ 621*0a6a1f1dSLionel Sambuc time_t Seconds, /* Second of minute [0-60] */ 622*0a6a1f1dSLionel Sambuc time_t Timezone, /* Timezone as minutes east of UTC, 623*0a6a1f1dSLionel Sambuc * or USE_LOCAL_TIME special case */ 624*0a6a1f1dSLionel Sambuc MERIDIAN Meridian, /* Hours are am/pm/24 hour clock */ 625*0a6a1f1dSLionel Sambuc DSTMODE DSTmode /* DST on/off/maybe */ 626*0a6a1f1dSLionel Sambuc ) 627*0a6a1f1dSLionel Sambuc { 628*0a6a1f1dSLionel Sambuc struct tm tm = {.tm_sec = 0}; 629*0a6a1f1dSLionel Sambuc time_t result; 6300c3983b2SBen Gras 631dba3562dSLionel Sambuc tm.tm_sec = Seconds; 632dba3562dSLionel Sambuc tm.tm_min = Minutes; 633dba3562dSLionel Sambuc tm.tm_hour = Hours + (Meridian == MERpm ? 12 : 0); 634dba3562dSLionel Sambuc tm.tm_mday = Day; 635dba3562dSLionel Sambuc tm.tm_mon = Month - 1; 636dba3562dSLionel Sambuc tm.tm_year = Year - 1900; 637dba3562dSLionel Sambuc switch (DSTmode) { 638dba3562dSLionel Sambuc case DSTon: tm.tm_isdst = 1; break; 639dba3562dSLionel Sambuc case DSToff: tm.tm_isdst = 0; break; 640dba3562dSLionel Sambuc default: tm.tm_isdst = -1; break; 6410c3983b2SBen Gras } 6420c3983b2SBen Gras 643*0a6a1f1dSLionel Sambuc if (Timezone == USE_LOCAL_TIME) { 644*0a6a1f1dSLionel Sambuc result = mktime(&tm); 645*0a6a1f1dSLionel Sambuc } else { 646*0a6a1f1dSLionel Sambuc /* We rely on mktime_z(NULL, ...) working in UTC */ 64784d9c625SLionel Sambuc result = mktime_z(NULL, &tm); 64884d9c625SLionel Sambuc result += Timezone * 60; 649*0a6a1f1dSLionel Sambuc } 650*0a6a1f1dSLionel Sambuc 651*0a6a1f1dSLionel Sambuc #if PARSEDATE_DEBUG 652*0a6a1f1dSLionel Sambuc fprintf(stderr, "%s(M=%jd D=%jd Y=%jd H=%jd M=%jd S=%jd Z=%jd" 653*0a6a1f1dSLionel Sambuc " mer=%d DST=%d)", 654*0a6a1f1dSLionel Sambuc __func__, 655*0a6a1f1dSLionel Sambuc (intmax_t)Month, (intmax_t)Day, (intmax_t)Year, 656*0a6a1f1dSLionel Sambuc (intmax_t)Hours, (intmax_t)Minutes, (intmax_t)Seconds, 657*0a6a1f1dSLionel Sambuc (intmax_t)Timezone, (int)Meridian, (int)DSTmode); 658*0a6a1f1dSLionel Sambuc fprintf(stderr, " -> %jd", (intmax_t)result); 659*0a6a1f1dSLionel Sambuc fprintf(stderr, " %s", ctime(&result)); 660*0a6a1f1dSLionel Sambuc #endif 661*0a6a1f1dSLionel Sambuc 66284d9c625SLionel Sambuc return result; 6630c3983b2SBen Gras } 6640c3983b2SBen Gras 6650c3983b2SBen Gras 6660c3983b2SBen Gras static time_t 6670c3983b2SBen Gras DSTcorrect( 6680c3983b2SBen Gras time_t Start, 6690c3983b2SBen Gras time_t Future 6700c3983b2SBen Gras ) 6710c3983b2SBen Gras { 6720c3983b2SBen Gras time_t StartDay; 6730c3983b2SBen Gras time_t FutureDay; 6740c3983b2SBen Gras struct tm *tm; 6750c3983b2SBen Gras 6760c3983b2SBen Gras if ((tm = localtime(&Start)) == NULL) 6770c3983b2SBen Gras return -1; 6780c3983b2SBen Gras StartDay = (tm->tm_hour + 1) % 24; 6790c3983b2SBen Gras 6800c3983b2SBen Gras if ((tm = localtime(&Future)) == NULL) 6810c3983b2SBen Gras return -1; 6820c3983b2SBen Gras FutureDay = (tm->tm_hour + 1) % 24; 6830c3983b2SBen Gras 6840c3983b2SBen Gras return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; 6850c3983b2SBen Gras } 6860c3983b2SBen Gras 6870c3983b2SBen Gras 6880c3983b2SBen Gras static time_t 6890c3983b2SBen Gras RelativeDate( 6900c3983b2SBen Gras time_t Start, 6910c3983b2SBen Gras time_t DayOrdinal, 6920c3983b2SBen Gras time_t DayNumber 6930c3983b2SBen Gras ) 6940c3983b2SBen Gras { 6950c3983b2SBen Gras struct tm *tm; 6960c3983b2SBen Gras time_t now; 6970c3983b2SBen Gras 6980c3983b2SBen Gras now = Start; 6990c3983b2SBen Gras tm = localtime(&now); 7000c3983b2SBen Gras now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); 7010c3983b2SBen Gras now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); 7020c3983b2SBen Gras return DSTcorrect(Start, now); 7030c3983b2SBen Gras } 7040c3983b2SBen Gras 7050c3983b2SBen Gras 7060c3983b2SBen Gras static time_t 7070c3983b2SBen Gras RelativeMonth( 7080c3983b2SBen Gras time_t Start, 7090c3983b2SBen Gras time_t RelMonth, 7100c3983b2SBen Gras time_t Timezone 7110c3983b2SBen Gras ) 7120c3983b2SBen Gras { 7130c3983b2SBen Gras struct tm *tm; 7140c3983b2SBen Gras time_t Month; 7150c3983b2SBen Gras time_t Year; 7160c3983b2SBen Gras 7170c3983b2SBen Gras if (RelMonth == 0) 7180c3983b2SBen Gras return 0; 7190c3983b2SBen Gras tm = localtime(&Start); 7200c3983b2SBen Gras if (tm == NULL) 7210c3983b2SBen Gras return -1; 7220c3983b2SBen Gras Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; 7230c3983b2SBen Gras Year = Month / 12; 7240c3983b2SBen Gras Month = Month % 12 + 1; 7250c3983b2SBen Gras return DSTcorrect(Start, 7260c3983b2SBen Gras Convert(Month, (time_t)tm->tm_mday, Year, 7270c3983b2SBen Gras (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, 7280c3983b2SBen Gras Timezone, MER24, DSTmaybe)); 7290c3983b2SBen Gras } 7300c3983b2SBen Gras 7310c3983b2SBen Gras 7320c3983b2SBen Gras static int 7330c3983b2SBen Gras LookupWord(YYSTYPE *yylval, char *buff) 7340c3983b2SBen Gras { 7350c3983b2SBen Gras register char *p; 7360c3983b2SBen Gras register char *q; 7370c3983b2SBen Gras register const TABLE *tp; 7380c3983b2SBen Gras int i; 7390c3983b2SBen Gras int abbrev; 7400c3983b2SBen Gras 7410c3983b2SBen Gras /* Make it lowercase. */ 7420c3983b2SBen Gras for (p = buff; *p; p++) 7430c3983b2SBen Gras if (isupper((unsigned char)*p)) 7440c3983b2SBen Gras *p = tolower((unsigned char)*p); 7450c3983b2SBen Gras 7460c3983b2SBen Gras if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { 7470c3983b2SBen Gras yylval->Meridian = MERam; 7480c3983b2SBen Gras return tMERIDIAN; 7490c3983b2SBen Gras } 7500c3983b2SBen Gras if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { 7510c3983b2SBen Gras yylval->Meridian = MERpm; 7520c3983b2SBen Gras return tMERIDIAN; 7530c3983b2SBen Gras } 7540c3983b2SBen Gras 7550c3983b2SBen Gras /* See if we have an abbreviation for a month. */ 7560c3983b2SBen Gras if (strlen(buff) == 3) 7570c3983b2SBen Gras abbrev = 1; 7580c3983b2SBen Gras else if (strlen(buff) == 4 && buff[3] == '.') { 7590c3983b2SBen Gras abbrev = 1; 7600c3983b2SBen Gras buff[3] = '\0'; 7610c3983b2SBen Gras } 7620c3983b2SBen Gras else 7630c3983b2SBen Gras abbrev = 0; 7640c3983b2SBen Gras 7650c3983b2SBen Gras for (tp = MonthDayTable; tp->name; tp++) { 7660c3983b2SBen Gras if (abbrev) { 7670c3983b2SBen Gras if (strncmp(buff, tp->name, 3) == 0) { 7680c3983b2SBen Gras yylval->Number = tp->value; 7690c3983b2SBen Gras return tp->type; 7700c3983b2SBen Gras } 7710c3983b2SBen Gras } 7720c3983b2SBen Gras else if (strcmp(buff, tp->name) == 0) { 7730c3983b2SBen Gras yylval->Number = tp->value; 7740c3983b2SBen Gras return tp->type; 7750c3983b2SBen Gras } 7760c3983b2SBen Gras } 7770c3983b2SBen Gras 7780c3983b2SBen Gras for (tp = TimezoneTable; tp->name; tp++) 7790c3983b2SBen Gras if (strcmp(buff, tp->name) == 0) { 7800c3983b2SBen Gras yylval->Number = tp->value; 7810c3983b2SBen Gras return tp->type; 7820c3983b2SBen Gras } 7830c3983b2SBen Gras 7840c3983b2SBen Gras if (strcmp(buff, "dst") == 0) 7850c3983b2SBen Gras return tDST; 7860c3983b2SBen Gras 7870c3983b2SBen Gras for (tp = UnitsTable; tp->name; tp++) 7880c3983b2SBen Gras if (strcmp(buff, tp->name) == 0) { 7890c3983b2SBen Gras yylval->Number = tp->value; 7900c3983b2SBen Gras return tp->type; 7910c3983b2SBen Gras } 7920c3983b2SBen Gras 7930c3983b2SBen Gras /* Strip off any plural and try the units table again. */ 7940c3983b2SBen Gras i = strlen(buff) - 1; 7950c3983b2SBen Gras if (buff[i] == 's') { 7960c3983b2SBen Gras buff[i] = '\0'; 7970c3983b2SBen Gras for (tp = UnitsTable; tp->name; tp++) 7980c3983b2SBen Gras if (strcmp(buff, tp->name) == 0) { 7990c3983b2SBen Gras yylval->Number = tp->value; 8000c3983b2SBen Gras return tp->type; 8010c3983b2SBen Gras } 8020c3983b2SBen Gras buff[i] = 's'; /* Put back for "this" in OtherTable. */ 8030c3983b2SBen Gras } 8040c3983b2SBen Gras 8050c3983b2SBen Gras for (tp = OtherTable; tp->name; tp++) 8060c3983b2SBen Gras if (strcmp(buff, tp->name) == 0) { 8070c3983b2SBen Gras yylval->Number = tp->value; 8080c3983b2SBen Gras return tp->type; 8090c3983b2SBen Gras } 8100c3983b2SBen Gras 8110c3983b2SBen Gras /* Military timezones. */ 8120c3983b2SBen Gras if (buff[1] == '\0' && isalpha((unsigned char)*buff)) { 8130c3983b2SBen Gras for (tp = MilitaryTable; tp->name; tp++) 8140c3983b2SBen Gras if (strcmp(buff, tp->name) == 0) { 8150c3983b2SBen Gras yylval->Number = tp->value; 8160c3983b2SBen Gras return tp->type; 8170c3983b2SBen Gras } 8180c3983b2SBen Gras } 8190c3983b2SBen Gras 8200c3983b2SBen Gras /* Drop out any periods and try the timezone table again. */ 8210c3983b2SBen Gras for (i = 0, p = q = buff; *q; q++) 8220c3983b2SBen Gras if (*q != '.') 8230c3983b2SBen Gras *p++ = *q; 8240c3983b2SBen Gras else 8250c3983b2SBen Gras i++; 8260c3983b2SBen Gras *p = '\0'; 8270c3983b2SBen Gras if (i) 8280c3983b2SBen Gras for (tp = TimezoneTable; tp->name; tp++) 8290c3983b2SBen Gras if (strcmp(buff, tp->name) == 0) { 8300c3983b2SBen Gras yylval->Number = tp->value; 8310c3983b2SBen Gras return tp->type; 8320c3983b2SBen Gras } 8330c3983b2SBen Gras 8340c3983b2SBen Gras return tID; 8350c3983b2SBen Gras } 8360c3983b2SBen Gras 8370c3983b2SBen Gras 8380c3983b2SBen Gras static int 8390c3983b2SBen Gras yylex(YYSTYPE *yylval, const char **yyInput) 8400c3983b2SBen Gras { 8410c3983b2SBen Gras register char c; 8420c3983b2SBen Gras register char *p; 8430c3983b2SBen Gras char buff[20]; 8440c3983b2SBen Gras int Count; 8450c3983b2SBen Gras int sign; 8460c3983b2SBen Gras const char *inp = *yyInput; 8470c3983b2SBen Gras 8480c3983b2SBen Gras for ( ; ; ) { 8490c3983b2SBen Gras while (isspace((unsigned char)*inp)) 8500c3983b2SBen Gras inp++; 8510c3983b2SBen Gras 8520c3983b2SBen Gras if (isdigit((unsigned char)(c = *inp)) || c == '-' || c == '+') { 8530c3983b2SBen Gras if (c == '-' || c == '+') { 8540c3983b2SBen Gras sign = c == '-' ? -1 : 1; 8550c3983b2SBen Gras if (!isdigit((unsigned char)*++inp)) 8560c3983b2SBen Gras /* skip the '-' sign */ 8570c3983b2SBen Gras continue; 8580c3983b2SBen Gras } 8590c3983b2SBen Gras else 8600c3983b2SBen Gras sign = 0; 8610c3983b2SBen Gras for (yylval->Number = 0; isdigit((unsigned char)(c = *inp++)); ) 8620c3983b2SBen Gras yylval->Number = 10 * yylval->Number + c - '0'; 8630c3983b2SBen Gras if (sign < 0) 8640c3983b2SBen Gras yylval->Number = -yylval->Number; 8650c3983b2SBen Gras *yyInput = --inp; 8660c3983b2SBen Gras return sign ? tSNUMBER : tUNUMBER; 8670c3983b2SBen Gras } 8680c3983b2SBen Gras if (isalpha((unsigned char)c)) { 8690c3983b2SBen Gras for (p = buff; isalpha((unsigned char)(c = *inp++)) || c == '.'; ) 8700c3983b2SBen Gras if (p < &buff[sizeof buff - 1]) 8710c3983b2SBen Gras *p++ = c; 8720c3983b2SBen Gras *p = '\0'; 8730c3983b2SBen Gras *yyInput = --inp; 8740c3983b2SBen Gras return LookupWord(yylval, buff); 8750c3983b2SBen Gras } 8760c3983b2SBen Gras if (c == '@') { 8770c3983b2SBen Gras *yyInput = ++inp; 8780c3983b2SBen Gras return AT_SIGN; 8790c3983b2SBen Gras } 8800c3983b2SBen Gras if (c != '(') { 8810c3983b2SBen Gras *yyInput = ++inp; 8820c3983b2SBen Gras return c; 8830c3983b2SBen Gras } 8840c3983b2SBen Gras Count = 0; 8850c3983b2SBen Gras do { 8860c3983b2SBen Gras c = *inp++; 8870c3983b2SBen Gras if (c == '\0') 8880c3983b2SBen Gras return c; 8890c3983b2SBen Gras if (c == '(') 8900c3983b2SBen Gras Count++; 8910c3983b2SBen Gras else if (c == ')') 8920c3983b2SBen Gras Count--; 8930c3983b2SBen Gras } while (Count > 0); 8940c3983b2SBen Gras } 8950c3983b2SBen Gras } 8960c3983b2SBen Gras 8970c3983b2SBen Gras #define TM_YEAR_ORIGIN 1900 8980c3983b2SBen Gras 8990c3983b2SBen Gras time_t 9000c3983b2SBen Gras parsedate(const char *p, const time_t *now, const int *zone) 9010c3983b2SBen Gras { 902*0a6a1f1dSLionel Sambuc struct tm local, *tm; 9030c3983b2SBen Gras time_t nowt; 9040c3983b2SBen Gras int zonet; 9050c3983b2SBen Gras time_t Start; 9060c3983b2SBen Gras time_t tod, rm; 9070c3983b2SBen Gras struct dateinfo param; 90884d9c625SLionel Sambuc int saved_errno; 90984d9c625SLionel Sambuc 91084d9c625SLionel Sambuc saved_errno = errno; 91184d9c625SLionel Sambuc errno = 0; 9120c3983b2SBen Gras 913*0a6a1f1dSLionel Sambuc if (now == NULL) { 9140c3983b2SBen Gras now = &nowt; 9150c3983b2SBen Gras (void)time(&nowt); 916*0a6a1f1dSLionel Sambuc } 917*0a6a1f1dSLionel Sambuc if (zone == NULL) { 918*0a6a1f1dSLionel Sambuc zone = &zonet; 919*0a6a1f1dSLionel Sambuc zonet = USE_LOCAL_TIME; 9200c3983b2SBen Gras if ((tm = localtime_r(now, &local)) == NULL) 9210c3983b2SBen Gras return -1; 9220c3983b2SBen Gras } else { 923*0a6a1f1dSLionel Sambuc /* 924*0a6a1f1dSLionel Sambuc * Should use the specified zone, not localtime. 925*0a6a1f1dSLionel Sambuc * Fake it using gmtime and arithmetic. 926*0a6a1f1dSLionel Sambuc * This is good enough because we use only the year/month/day, 927*0a6a1f1dSLionel Sambuc * not other fields of struct tm. 928*0a6a1f1dSLionel Sambuc */ 929*0a6a1f1dSLionel Sambuc time_t fake = *now + (*zone * 60); 930*0a6a1f1dSLionel Sambuc if ((tm = gmtime_r(&fake, &local)) == NULL) 9310c3983b2SBen Gras return -1; 9320c3983b2SBen Gras } 9330c3983b2SBen Gras param.yyYear = tm->tm_year + 1900; 9340c3983b2SBen Gras param.yyMonth = tm->tm_mon + 1; 9350c3983b2SBen Gras param.yyDay = tm->tm_mday; 9360c3983b2SBen Gras param.yyTimezone = *zone; 9370c3983b2SBen Gras param.yyDSTmode = DSTmaybe; 9380c3983b2SBen Gras param.yyHour = 0; 9390c3983b2SBen Gras param.yyMinutes = 0; 9400c3983b2SBen Gras param.yySeconds = 0; 9410c3983b2SBen Gras param.yyMeridian = MER24; 9420c3983b2SBen Gras param.yyRelSeconds = 0; 9430c3983b2SBen Gras param.yyRelMonth = 0; 9440c3983b2SBen Gras param.yyHaveDate = 0; 945*0a6a1f1dSLionel Sambuc param.yyHaveFullYear = 0; 9460c3983b2SBen Gras param.yyHaveDay = 0; 9470c3983b2SBen Gras param.yyHaveRel = 0; 9480c3983b2SBen Gras param.yyHaveTime = 0; 9490c3983b2SBen Gras param.yyHaveZone = 0; 9500c3983b2SBen Gras 9510c3983b2SBen Gras if (yyparse(¶m, &p) || param.yyHaveTime > 1 || param.yyHaveZone > 1 || 95284d9c625SLionel Sambuc param.yyHaveDate > 1 || param.yyHaveDay > 1) { 95384d9c625SLionel Sambuc errno = EINVAL; 9540c3983b2SBen Gras return -1; 95584d9c625SLionel Sambuc } 9560c3983b2SBen Gras 9570c3983b2SBen Gras if (param.yyHaveDate || param.yyHaveTime || param.yyHaveDay) { 958*0a6a1f1dSLionel Sambuc if (! param.yyHaveFullYear) { 959*0a6a1f1dSLionel Sambuc param.yyYear = AdjustYear(param.yyYear); 960*0a6a1f1dSLionel Sambuc param.yyHaveFullYear = 1; 961*0a6a1f1dSLionel Sambuc } 9620c3983b2SBen Gras Start = Convert(param.yyMonth, param.yyDay, param.yyYear, param.yyHour, 9630c3983b2SBen Gras param.yyMinutes, param.yySeconds, param.yyTimezone, 9640c3983b2SBen Gras param.yyMeridian, param.yyDSTmode); 96584d9c625SLionel Sambuc if (Start == -1 && errno != 0) 9660c3983b2SBen Gras return -1; 9670c3983b2SBen Gras } 9680c3983b2SBen Gras else { 9690c3983b2SBen Gras Start = *now; 9700c3983b2SBen Gras if (!param.yyHaveRel) 9710c3983b2SBen Gras Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; 9720c3983b2SBen Gras } 9730c3983b2SBen Gras 9740c3983b2SBen Gras Start += param.yyRelSeconds; 9750c3983b2SBen Gras rm = RelativeMonth(Start, param.yyRelMonth, param.yyTimezone); 97684d9c625SLionel Sambuc if (rm == -1 && errno != 0) 9770c3983b2SBen Gras return -1; 9780c3983b2SBen Gras Start += rm; 9790c3983b2SBen Gras 9800c3983b2SBen Gras if (param.yyHaveDay && !param.yyHaveDate) { 9810c3983b2SBen Gras tod = RelativeDate(Start, param.yyDayOrdinal, param.yyDayNumber); 9820c3983b2SBen Gras Start += tod; 9830c3983b2SBen Gras } 9840c3983b2SBen Gras 98584d9c625SLionel Sambuc if (errno == 0) 98684d9c625SLionel Sambuc errno = saved_errno; 9870c3983b2SBen Gras return Start; 9880c3983b2SBen Gras } 9890c3983b2SBen Gras 9900c3983b2SBen Gras 9910c3983b2SBen Gras #if defined(TEST) 9920c3983b2SBen Gras 9930c3983b2SBen Gras /* ARGSUSED */ 9940c3983b2SBen Gras int 99584d9c625SLionel Sambuc main(int ac, char *av[]) 9960c3983b2SBen Gras { 9970c3983b2SBen Gras char buff[128]; 9980c3983b2SBen Gras time_t d; 9990c3983b2SBen Gras 10000c3983b2SBen Gras (void)printf("Enter date, or blank line to exit.\n\t> "); 10010c3983b2SBen Gras (void)fflush(stdout); 100284d9c625SLionel Sambuc while (fgets(buff, sizeof(buff), stdin) && buff[0] != '\n') { 100384d9c625SLionel Sambuc errno = 0; 10040c3983b2SBen Gras d = parsedate(buff, NULL, NULL); 100584d9c625SLionel Sambuc if (d == -1 && errno != 0) 100684d9c625SLionel Sambuc (void)printf("Bad format - couldn't convert: %s\n", 100784d9c625SLionel Sambuc strerror(errno)); 10080c3983b2SBen Gras else 100984d9c625SLionel Sambuc (void)printf("%jd\t%s", (intmax_t)d, ctime(&d)); 10100c3983b2SBen Gras (void)printf("\t> "); 10110c3983b2SBen Gras (void)fflush(stdout); 10120c3983b2SBen Gras } 10130c3983b2SBen Gras exit(0); 10140c3983b2SBen Gras /* NOTREACHED */ 10150c3983b2SBen Gras } 10160c3983b2SBen Gras #endif /* defined(TEST) */ 1017