[BACK]Return to date.y CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Annotation of src/usr.bin/cvs/date.y, Revision 1.1

1.1     ! jfb         1: %{
        !             2: /*     $OpenBSD$       */
        !             3:
        !             4: /*
        !             5: **  Originally written by Steven M. Bellovin <smb@research.att.com> while
        !             6: **  at the University of North Carolina at Chapel Hill.  Later tweaked by
        !             7: **  a couple of people on Usenet.  Completely overhauled by Rich $alz
        !             8: **  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
        !             9: **
        !            10: **  This grammar has 10 shift/reduce conflicts.
        !            11: **
        !            12: **  This code is in the public domain and has no copyright.
        !            13: */
        !            14: /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
        !            15: /* SUPPRESS 288 on yyerrlab *//* Label unused */
        !            16:
        !            17: #include <sys/types.h>
        !            18: #include <sys/timeb.h>
        !            19:
        !            20: #include <ctype.h>
        !            21: #include <stdio.h>
        !            22: #include <stdlib.h>
        !            23: #include <string.h>
        !            24: #include <time.h>
        !            25:
        !            26: #include "log.h"
        !            27:
        !            28: #define EPOCH          1970
        !            29: #define HOUR(x)                ((time_t)(x) * 60)
        !            30: #define SECSPERDAY     (24L * 60L * 60L)
        !            31:
        !            32:
        !            33: /* An entry in the lexical lookup table */
        !            34: typedef struct _TABLE {
        !            35:        char    *name;
        !            36:        int     type;
        !            37:        time_t  value;
        !            38: } TABLE;
        !            39:
        !            40:
        !            41: /*
        !            42: **  Daylight-savings mode:  on, off, or not yet known.
        !            43: */
        !            44: typedef enum _DSTMODE {
        !            45:        DSTon, DSToff, DSTmaybe
        !            46: } DSTMODE;
        !            47:
        !            48: /*
        !            49: **  Meridian:  am, pm, or 24-hour style.
        !            50: */
        !            51: typedef enum _MERIDIAN {
        !            52:        MERam, MERpm, MER24
        !            53: } MERIDIAN;
        !            54:
        !            55:
        !            56: /*
        !            57: **  Global variables.  We could get rid of most of these by using a good
        !            58: **  union as the yacc stack.  (This routine was originally written before
        !            59: **  yacc had the %union construct.)  Maybe someday; right now we only use
        !            60: **  the %union very rarely.
        !            61: */
        !            62: static char    *yyInput;
        !            63: static DSTMODE yyDSTmode;
        !            64: static time_t  yyDayOrdinal;
        !            65: static time_t  yyDayNumber;
        !            66: static int     yyHaveDate;
        !            67: static int     yyHaveDay;
        !            68: static int     yyHaveRel;
        !            69: static int     yyHaveTime;
        !            70: static int     yyHaveZone;
        !            71: static time_t  yyTimezone;
        !            72: static time_t  yyDay;
        !            73: static time_t  yyHour;
        !            74: static time_t  yyMinutes;
        !            75: static time_t  yyMonth;
        !            76: static time_t  yySeconds;
        !            77: static time_t  yyYear;
        !            78: static MERIDIAN        yyMeridian;
        !            79: static time_t  yyRelMonth;
        !            80: static time_t  yyRelSeconds;
        !            81:
        !            82: %}
        !            83:
        !            84: %union {
        !            85:        time_t          Number;
        !            86:        enum _MERIDIAN  Meridian;
        !            87: }
        !            88:
        !            89: %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
        !            90: %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
        !            91:
        !            92: %type  <Number>        tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
        !            93: %type  <Number>        tSEC_UNIT tSNUMBER tUNUMBER tZONE
        !            94: %type  <Meridian>      tMERIDIAN o_merid
        !            95:
        !            96: %%
        !            97:
        !            98: spec   : /* NULL */
        !            99:        | spec item
        !           100:        ;
        !           101:
        !           102: item   : time {
        !           103:                        yyHaveTime++;
        !           104:        }
        !           105:        | zone {
        !           106:                        yyHaveZone++;
        !           107:        }
        !           108:        | date {
        !           109:                        yyHaveDate++;
        !           110:        }
        !           111:        | day {
        !           112:                        yyHaveDay++;
        !           113:        }
        !           114:        | rel {
        !           115:                        yyHaveRel++;
        !           116:        }
        !           117:        | number
        !           118:        ;
        !           119:
        !           120: time   : tUNUMBER tMERIDIAN {
        !           121:                        yyHour = $1;
        !           122:                        yyMinutes = 0;
        !           123:                        yySeconds = 0;
        !           124:                        yyMeridian = $2;
        !           125:        }
        !           126:        | tUNUMBER ':' tUNUMBER o_merid {
        !           127:                        yyHour = $1;
        !           128:                        yyMinutes = $3;
        !           129:                        yySeconds = 0;
        !           130:                        yyMeridian = $4;
        !           131:        }
        !           132:        | tUNUMBER ':' tUNUMBER tSNUMBER {
        !           133:                        yyHour = $1;
        !           134:                        yyMinutes = $3;
        !           135:                        yyMeridian = MER24;
        !           136:                        yyDSTmode = DSToff;
        !           137:                        yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
        !           138:        }
        !           139:        | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
        !           140:                        yyHour = $1;
        !           141:                        yyMinutes = $3;
        !           142:                        yySeconds = $5;
        !           143:                        yyMeridian = $6;
        !           144:        }
        !           145:        | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
        !           146:                        yyHour = $1;
        !           147:                        yyMinutes = $3;
        !           148:                        yySeconds = $5;
        !           149:                        yyMeridian = MER24;
        !           150:                        yyDSTmode = DSToff;
        !           151:                        yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
        !           152:        }
        !           153:        ;
        !           154:
        !           155: zone   : tZONE {
        !           156:                        yyTimezone = $1;
        !           157:                        yyDSTmode = DSToff;
        !           158:        }
        !           159:        | tDAYZONE {
        !           160:                        yyTimezone = $1;
        !           161:                        yyDSTmode = DSTon;
        !           162:        }
        !           163:        |
        !           164:          tZONE tDST {
        !           165:                        yyTimezone = $1;
        !           166:                        yyDSTmode = DSTon;
        !           167:        }
        !           168:        ;
        !           169:
        !           170: day    : tDAY {
        !           171:                        yyDayOrdinal = 1;
        !           172:                        yyDayNumber = $1;
        !           173:        }
        !           174:        | tDAY ',' {
        !           175:                        yyDayOrdinal = 1;
        !           176:                        yyDayNumber = $1;
        !           177:        }
        !           178:        | tUNUMBER tDAY {
        !           179:                        yyDayOrdinal = $1;
        !           180:                        yyDayNumber = $2;
        !           181:        }
        !           182:        ;
        !           183:
        !           184: date   : tUNUMBER '/' tUNUMBER {
        !           185:                        yyMonth = $1;
        !           186:                        yyDay = $3;
        !           187:        }
        !           188:        | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
        !           189:                        if ($1 >= 100) {
        !           190:                yyYear = $1;
        !           191:                yyMonth = $3;
        !           192:                yyDay = $5;
        !           193:                        } else {
        !           194:                yyMonth = $1;
        !           195:                yyDay = $3;
        !           196:                yyYear = $5;
        !           197:                        }
        !           198:        }
        !           199:        | tUNUMBER tSNUMBER tSNUMBER {
        !           200:                        /* ISO 8601 format.  yyyy-mm-dd.  */
        !           201:                        yyYear = $1;
        !           202:                        yyMonth = -$2;
        !           203:                        yyDay = -$3;
        !           204:        }
        !           205:        | tUNUMBER tMONTH tSNUMBER {
        !           206:                        /* e.g. 17-JUN-1992.  */
        !           207:                        yyDay = $1;
        !           208:                        yyMonth = $2;
        !           209:                        yyYear = -$3;
        !           210:        }
        !           211:        | tMONTH tUNUMBER {
        !           212:                        yyMonth = $1;
        !           213:                        yyDay = $2;
        !           214:        }
        !           215:        | tMONTH tUNUMBER ',' tUNUMBER {
        !           216:                        yyMonth = $1;
        !           217:                        yyDay = $2;
        !           218:                        yyYear = $4;
        !           219:        }
        !           220:        | tUNUMBER tMONTH {
        !           221:                        yyMonth = $2;
        !           222:                        yyDay = $1;
        !           223:        }
        !           224:        | tUNUMBER tMONTH tUNUMBER {
        !           225:                        yyMonth = $2;
        !           226:                        yyDay = $1;
        !           227:                        yyYear = $3;
        !           228:        }
        !           229:        ;
        !           230:
        !           231: rel    : relunit tAGO {
        !           232:                        yyRelSeconds = -yyRelSeconds;
        !           233:                        yyRelMonth = -yyRelMonth;
        !           234:        }
        !           235:        | relunit
        !           236:        ;
        !           237:
        !           238: relunit        : tUNUMBER tMINUTE_UNIT {
        !           239:                        yyRelSeconds += $1 * $2 * 60L;
        !           240:        }
        !           241:        | tSNUMBER tMINUTE_UNIT {
        !           242:                        yyRelSeconds += $1 * $2 * 60L;
        !           243:        }
        !           244:        | tMINUTE_UNIT {
        !           245:                        yyRelSeconds += $1 * 60L;
        !           246:        }
        !           247:        | tSNUMBER tSEC_UNIT {
        !           248:                        yyRelSeconds += $1;
        !           249:        }
        !           250:        | tUNUMBER tSEC_UNIT {
        !           251:                        yyRelSeconds += $1;
        !           252:        }
        !           253:        | tSEC_UNIT {
        !           254:                        yyRelSeconds++;
        !           255:        }
        !           256:        | tSNUMBER tMONTH_UNIT {
        !           257:                        yyRelMonth += $1 * $2;
        !           258:        }
        !           259:        | tUNUMBER tMONTH_UNIT {
        !           260:                        yyRelMonth += $1 * $2;
        !           261:        }
        !           262:        | tMONTH_UNIT {
        !           263:                        yyRelMonth += $1;
        !           264:        }
        !           265:        ;
        !           266:
        !           267: number : tUNUMBER {
        !           268:                        if (yyHaveTime && yyHaveDate && !yyHaveRel)
        !           269:                yyYear = $1;
        !           270:                        else {
        !           271:                if($1>10000) {
        !           272:                                yyHaveDate++;
        !           273:                                yyDay= ($1)%100;
        !           274:                                yyMonth= ($1/100)%100;
        !           275:                                yyYear = $1/10000;
        !           276:                }
        !           277:                else {
        !           278:                                yyHaveTime++;
        !           279:                                if ($1 < 100) {
        !           280:                        yyHour = $1;
        !           281:                        yyMinutes = 0;
        !           282:                                }
        !           283:                                else {
        !           284:                                        yyHour = $1 / 100;
        !           285:                                        yyMinutes = $1 % 100;
        !           286:                                }
        !           287:                                yySeconds = 0;
        !           288:                                yyMeridian = MER24;
        !           289:                            }
        !           290:                        }
        !           291:        }
        !           292:        ;
        !           293:
        !           294: o_merid        : /* NULL */ {
        !           295:                $$ = MER24;
        !           296:        }
        !           297:        | tMERIDIAN {
        !           298:                $$ = $1;
        !           299:        }
        !           300:        ;
        !           301:
        !           302: %%
        !           303:
        !           304: /* Month and day table. */
        !           305: static TABLE const MonthDayTable[] = {
        !           306:        { "january",    tMONTH, 1 },
        !           307:        { "february",   tMONTH, 2 },
        !           308:        { "march",      tMONTH, 3 },
        !           309:        { "april",      tMONTH, 4 },
        !           310:        { "may",        tMONTH, 5 },
        !           311:        { "june",       tMONTH, 6 },
        !           312:        { "july",       tMONTH, 7 },
        !           313:        { "august",     tMONTH, 8 },
        !           314:        { "september",  tMONTH, 9 },
        !           315:        { "sept",       tMONTH, 9 },
        !           316:        { "october",    tMONTH, 10 },
        !           317:        { "november",   tMONTH, 11 },
        !           318:        { "december",   tMONTH, 12 },
        !           319:        { "sunday",     tDAY,   0 },
        !           320:        { "monday",     tDAY,   1 },
        !           321:        { "tuesday",    tDAY,   2 },
        !           322:        { "tues",       tDAY,   2 },
        !           323:        { "wednesday",  tDAY,   3 },
        !           324:        { "wednes",     tDAY,   3 },
        !           325:        { "thursday",   tDAY,   4 },
        !           326:        { "thur",       tDAY,   4 },
        !           327:        { "thurs",      tDAY,   4 },
        !           328:        { "friday",     tDAY,   5 },
        !           329:        { "saturday",   tDAY,   6 },
        !           330:        { NULL }
        !           331: };
        !           332:
        !           333: /* Time units table. */
        !           334: static TABLE const UnitsTable[] = {
        !           335:        { "year",       tMONTH_UNIT,    12 },
        !           336:        { "month",      tMONTH_UNIT,    1 },
        !           337:        { "fortnight",  tMINUTE_UNIT,   14 * 24 * 60 },
        !           338:        { "week",       tMINUTE_UNIT,   7 * 24 * 60 },
        !           339:        { "day",        tMINUTE_UNIT,   1 * 24 * 60 },
        !           340:        { "hour",       tMINUTE_UNIT,   60 },
        !           341:        { "minute",     tMINUTE_UNIT,   1 },
        !           342:        { "min",        tMINUTE_UNIT,   1 },
        !           343:        { "second",     tSEC_UNIT,      1 },
        !           344:        { "sec",        tSEC_UNIT,      1 },
        !           345:        { NULL }
        !           346: };
        !           347:
        !           348: /* Assorted relative-time words. */
        !           349: static TABLE const OtherTable[] = {
        !           350:        { "tomorrow",   tMINUTE_UNIT,   1 * 24 * 60 },
        !           351:        { "yesterday",  tMINUTE_UNIT,   -1 * 24 * 60 },
        !           352:        { "today",      tMINUTE_UNIT,   0 },
        !           353:        { "now",        tMINUTE_UNIT,   0 },
        !           354:        { "last",       tUNUMBER,       -1 },
        !           355:        { "this",       tMINUTE_UNIT,   0 },
        !           356:        { "next",       tUNUMBER,       2 },
        !           357:        { "first",      tUNUMBER,       1 },
        !           358: /*  { "second",                tUNUMBER,       2 }, */
        !           359:        { "third",      tUNUMBER,       3 },
        !           360:        { "fourth",     tUNUMBER,       4 },
        !           361:        { "fifth",      tUNUMBER,       5 },
        !           362:        { "sixth",      tUNUMBER,       6 },
        !           363:        { "seventh",    tUNUMBER,       7 },
        !           364:        { "eighth",     tUNUMBER,       8 },
        !           365:        { "ninth",      tUNUMBER,       9 },
        !           366:        { "tenth",      tUNUMBER,       10 },
        !           367:        { "eleventh",   tUNUMBER,       11 },
        !           368:        { "twelfth",    tUNUMBER,       12 },
        !           369:        { "ago",        tAGO,   1 },
        !           370:        { NULL }
        !           371: };
        !           372:
        !           373: /* The timezone table. */
        !           374: /* Some of these are commented out because a time_t can't store a float. */
        !           375: static TABLE const TimezoneTable[] = {
        !           376:        { "gmt",        tZONE,     HOUR( 0) },  /* Greenwich Mean */
        !           377:        { "ut", tZONE,     HOUR( 0) },  /* Universal (Coordinated) */
        !           378:        { "utc",        tZONE,     HOUR( 0) },
        !           379:        { "wet",        tZONE,     HOUR( 0) },  /* Western European */
        !           380:        { "bst",        tDAYZONE,  HOUR( 0) },  /* British Summer */
        !           381:        { "wat",        tZONE,     HOUR( 1) },  /* West Africa */
        !           382:        { "at", tZONE,     HOUR( 2) },  /* Azores */
        !           383: #if    0
        !           384:        /* For completeness.  BST is also British Summer, and GST is
        !           385:         * also Guam Standard. */
        !           386:        { "bst",        tZONE,     HOUR( 3) },  /* Brazil Standard */
        !           387:        { "gst",        tZONE,     HOUR( 3) },  /* Greenland Standard */
        !           388: #endif
        !           389: #if 0
        !           390:        { "nft",        tZONE,     HOUR(3.5) }, /* Newfoundland */
        !           391:        { "nst",        tZONE,     HOUR(3.5) }, /* Newfoundland Standard */
        !           392:        { "ndt",        tDAYZONE,  HOUR(3.5) }, /* Newfoundland Daylight */
        !           393: #endif
        !           394:        { "ast",        tZONE,     HOUR( 4) },  /* Atlantic Standard */
        !           395:        { "adt",        tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
        !           396:        { "est",        tZONE,     HOUR( 5) },  /* Eastern Standard */
        !           397:        { "edt",        tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
        !           398:        { "cst",        tZONE,     HOUR( 6) },  /* Central Standard */
        !           399:        { "cdt",        tDAYZONE,  HOUR( 6) },  /* Central Daylight */
        !           400:        { "mst",        tZONE,     HOUR( 7) },  /* Mountain Standard */
        !           401:        { "mdt",        tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
        !           402:        { "pst",        tZONE,     HOUR( 8) },  /* Pacific Standard */
        !           403:        { "pdt",        tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
        !           404:        { "yst",        tZONE,     HOUR( 9) },  /* Yukon Standard */
        !           405:        { "ydt",        tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
        !           406:        { "hst",        tZONE,     HOUR(10) },  /* Hawaii Standard */
        !           407:        { "hdt",        tDAYZONE,  HOUR(10) },  /* Hawaii Daylight */
        !           408:        { "cat",        tZONE,     HOUR(10) },  /* Central Alaska */
        !           409:        { "ahst",       tZONE,     HOUR(10) },  /* Alaska-Hawaii Standard */
        !           410:        { "nt", tZONE,     HOUR(11) },  /* Nome */
        !           411:        { "idlw",       tZONE,     HOUR(12) },  /* International Date Line West */
        !           412:        { "cet",        tZONE,     -HOUR(1) },  /* Central European */
        !           413:        { "met",        tZONE,     -HOUR(1) },  /* Middle European */
        !           414:        { "mewt",       tZONE,     -HOUR(1) },  /* Middle European Winter */
        !           415:        { "mest",       tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
        !           416:        { "swt",        tZONE,     -HOUR(1) },  /* Swedish Winter */
        !           417:        { "sst",        tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
        !           418:        { "fwt",        tZONE,     -HOUR(1) },  /* French Winter */
        !           419:        { "fst",        tDAYZONE,  -HOUR(1) },  /* French Summer */
        !           420:        { "eet",        tZONE,     -HOUR(2) },  /* Eastern Europe, USSR Zone 1 */
        !           421:        { "bt", tZONE,     -HOUR(3) },  /* Baghdad, USSR Zone 2 */
        !           422: #if 0
        !           423:        { "it", tZONE,     -HOUR(3.5) },/* Iran */
        !           424: #endif
        !           425:        { "zp4",        tZONE,     -HOUR(4) },  /* USSR Zone 3 */
        !           426:        { "zp5",        tZONE,     -HOUR(5) },  /* USSR Zone 4 */
        !           427: #if 0
        !           428:        { "ist",        tZONE,     -HOUR(5.5) },/* Indian Standard */
        !           429: #endif
        !           430:        { "zp6",        tZONE,     -HOUR(6) },  /* USSR Zone 5 */
        !           431: #if    0
        !           432:        /* For completeness.  NST is also Newfoundland Stanard, and SST is
        !           433:         * also Swedish Summer. */
        !           434:        { "nst",        tZONE,     -HOUR(6.5) },/* North Sumatra */
        !           435:        { "sst",        tZONE,     -HOUR(7) },  /* South Sumatra, USSR Zone 6 */
        !           436: #endif /* 0 */
        !           437:        { "wast",       tZONE,     -HOUR(7) },  /* West Australian Standard */
        !           438:        { "wadt",       tDAYZONE,  -HOUR(7) },  /* West Australian Daylight */
        !           439: #if 0
        !           440:        { "jt", tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
        !           441: #endif
        !           442:        { "cct",        tZONE,     -HOUR(8) },  /* China Coast, USSR Zone 7 */
        !           443:        { "jst",        tZONE,     -HOUR(9) },  /* Japan Standard, USSR Zone 8 */
        !           444: #if 0
        !           445:        { "cast",       tZONE,     -HOUR(9.5) },/* Central Australian Standard */
        !           446:        { "cadt",       tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
        !           447: #endif
        !           448:        { "east",       tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
        !           449:        { "eadt",       tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
        !           450:        { "gst",        tZONE,     -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
        !           451:        { "nzt",        tZONE,     -HOUR(12) }, /* New Zealand */
        !           452:        { "nzst",       tZONE,     -HOUR(12) }, /* New Zealand Standard */
        !           453:        { "nzdt",       tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
        !           454:        { "idle",       tZONE,     -HOUR(12) }, /* International Date Line East */
        !           455:        {  NULL  }
        !           456: };
        !           457:
        !           458: /* Military timezone table. */
        !           459: static TABLE const MilitaryTable[] = {
        !           460:        { "a",  tZONE,  HOUR(  1) },
        !           461:        { "b",  tZONE,  HOUR(  2) },
        !           462:        { "c",  tZONE,  HOUR(  3) },
        !           463:        { "d",  tZONE,  HOUR(  4) },
        !           464:        { "e",  tZONE,  HOUR(  5) },
        !           465:        { "f",  tZONE,  HOUR(  6) },
        !           466:        { "g",  tZONE,  HOUR(  7) },
        !           467:        { "h",  tZONE,  HOUR(  8) },
        !           468:        { "i",  tZONE,  HOUR(  9) },
        !           469:        { "k",  tZONE,  HOUR( 10) },
        !           470:        { "l",  tZONE,  HOUR( 11) },
        !           471:        { "m",  tZONE,  HOUR( 12) },
        !           472:        { "n",  tZONE,  HOUR(- 1) },
        !           473:        { "o",  tZONE,  HOUR(- 2) },
        !           474:        { "p",  tZONE,  HOUR(- 3) },
        !           475:        { "q",  tZONE,  HOUR(- 4) },
        !           476:        { "r",  tZONE,  HOUR(- 5) },
        !           477:        { "s",  tZONE,  HOUR(- 6) },
        !           478:        { "t",  tZONE,  HOUR(- 7) },
        !           479:        { "u",  tZONE,  HOUR(- 8) },
        !           480:        { "v",  tZONE,  HOUR(- 9) },
        !           481:        { "w",  tZONE,  HOUR(-10) },
        !           482:        { "x",  tZONE,  HOUR(-11) },
        !           483:        { "y",  tZONE,  HOUR(-12) },
        !           484:        { "z",  tZONE,  HOUR(  0) },
        !           485:        { NULL }
        !           486: };
        !           487:
        !           488:
        !           489: /* ARGSUSED */
        !           490: static int
        !           491: yyerror(char *s)
        !           492: {
        !           493:        cvs_log(LP_ERR, "%s", s);
        !           494:        return (0);
        !           495: }
        !           496:
        !           497:
        !           498: static time_t
        !           499: ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
        !           500: {
        !           501:        if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
        !           502:                return (-1);
        !           503:
        !           504:        switch (Meridian) {
        !           505:        case MER24:
        !           506:                if (Hours < 0 || Hours > 23)
        !           507:                        return (-1);
        !           508:                return (Hours * 60L + Minutes) * 60L + Seconds;
        !           509:        case MERam:
        !           510:                if (Hours < 1 || Hours > 12)
        !           511:                        return (-1);
        !           512:                if (Hours == 12)
        !           513:                        Hours = 0;
        !           514:                return (Hours * 60L + Minutes) * 60L + Seconds;
        !           515:        case MERpm:
        !           516:                if (Hours < 1 || Hours > 12)
        !           517:                        return (-1);
        !           518:                if (Hours == 12)
        !           519:                        Hours = 0;
        !           520:                return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
        !           521:        default:
        !           522:                abort ();
        !           523:        }
        !           524:        /* NOTREACHED */
        !           525: }
        !           526:
        !           527:
        !           528: /* Year is either
        !           529:  * A negative number, which means to use its absolute value (why?)
        !           530:  * A number from 0 to 99, which means a year from 1900 to 1999, or
        !           531:  * The actual year (>=100).
        !           532:  */
        !           533: static time_t
        !           534: Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes,
        !           535:     time_t Seconds, MERIDIAN Meridian, DSTMODE DSTmode)
        !           536: {
        !           537:        static int DaysInMonth[12] = {
        !           538:                31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
        !           539:        };
        !           540:        time_t  tod;
        !           541:        time_t  julian;
        !           542:        int     i;
        !           543:
        !           544:        if (Year < 0)
        !           545:                Year = -Year;
        !           546:        if (Year < 69)
        !           547:                Year += 2000;
        !           548:        else if (Year < 100) {
        !           549:                Year += 1900;
        !           550:                if (Year < EPOCH)
        !           551:                        Year += 100;
        !           552:        }
        !           553:        DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
        !           554:            ? 29 : 28;
        !           555:        /* Checking for 2038 bogusly assumes that time_t is 32 bits.  But
        !           556:           I'm too lazy to try to check for time_t overflow in another way.  */
        !           557:        if (Year < EPOCH || Year > 2038 || Month < 1 || Month > 12 ||
        !           558:            /* Lint fluff:  "conversion from long may lose accuracy" */
        !           559:             Day < 1 || Day > DaysInMonth[(int)--Month])
        !           560:                return (-1);
        !           561:
        !           562:        for (julian = Day - 1, i = 0; i < Month; i++)
        !           563:                julian += DaysInMonth[i];
        !           564:
        !           565:        for (i = EPOCH; i < Year; i++)
        !           566:                julian += 365 + (i % 4 == 0);
        !           567:        julian *= SECSPERDAY;
        !           568:        julian += yyTimezone * 60L;
        !           569:
        !           570:        if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
        !           571:                return (-1);
        !           572:        julian += tod;
        !           573:        if ((DSTmode == DSTon) ||
        !           574:            (DSTmode == DSTmaybe && localtime(&julian)->tm_isdst))
        !           575:        julian -= 60 * 60;
        !           576:        return (julian);
        !           577: }
        !           578:
        !           579:
        !           580: static time_t
        !           581: DSTcorrect(time_t Start, time_t Future)
        !           582: {
        !           583:        time_t  StartDay;
        !           584:        time_t  FutureDay;
        !           585:
        !           586:        StartDay = (localtime(&Start)->tm_hour + 1) % 24;
        !           587:        FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
        !           588:        return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
        !           589: }
        !           590:
        !           591:
        !           592: static time_t
        !           593: RelativeDate(time_t Start, time_t DayOrdinal, time_t DayNumber)
        !           594: {
        !           595:        struct tm       *tm;
        !           596:        time_t  now;
        !           597:
        !           598:        now = Start;
        !           599:        tm = localtime(&now);
        !           600:        now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
        !           601:        now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
        !           602:        return DSTcorrect(Start, now);
        !           603: }
        !           604:
        !           605:
        !           606: static time_t
        !           607: RelativeMonth(time_t Start, time_t RelMonth)
        !           608: {
        !           609:        struct tm       *tm;
        !           610:        time_t  Month;
        !           611:        time_t  Year;
        !           612:
        !           613:        if (RelMonth == 0)
        !           614:                return (0);
        !           615:        tm = localtime(&Start);
        !           616:        Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
        !           617:        Year = Month / 12;
        !           618:        Month = Month % 12 + 1;
        !           619:        return DSTcorrect(Start,
        !           620:            Convert(Month, (time_t)tm->tm_mday, Year,
        !           621:            (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
        !           622:            MER24, DSTmaybe));
        !           623: }
        !           624:
        !           625:
        !           626: static int
        !           627: LookupWord(char *buff)
        !           628: {
        !           629:        char            *p, *q;
        !           630:        int             i, abbrev;
        !           631:        const TABLE     *tp;
        !           632:
        !           633:        /* Make it lowercase. */
        !           634:        for (p = buff; *p; p++)
        !           635:                if (isupper(*p))
        !           636:                        *p = tolower(*p);
        !           637:
        !           638:        if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
        !           639:                yylval.Meridian = MERam;
        !           640:                return (tMERIDIAN);
        !           641:        }
        !           642:        if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
        !           643:                yylval.Meridian = MERpm;
        !           644:                return (tMERIDIAN);
        !           645:        }
        !           646:
        !           647:        /* See if we have an abbreviation for a month. */
        !           648:        if (strlen(buff) == 3)
        !           649:                abbrev = 1;
        !           650:        else if (strlen(buff) == 4 && buff[3] == '.') {
        !           651:                abbrev = 1;
        !           652:                buff[3] = '\0';
        !           653:        } else
        !           654:                abbrev = 0;
        !           655:
        !           656:        for (tp = MonthDayTable; tp->name; tp++) {
        !           657:                if (abbrev) {
        !           658:                        if (strncmp(buff, tp->name, 3) == 0) {
        !           659:                                yylval.Number = tp->value;
        !           660:                                return (tp->type);
        !           661:                        }
        !           662:                } else if (strcmp(buff, tp->name) == 0) {
        !           663:                        yylval.Number = tp->value;
        !           664:                        return (tp->type);
        !           665:                }
        !           666:        }
        !           667:
        !           668:        for (tp = TimezoneTable; tp->name; tp++)
        !           669:                if (strcmp(buff, tp->name) == 0) {
        !           670:                        yylval.Number = tp->value;
        !           671:                        return (tp->type);
        !           672:                }
        !           673:
        !           674:        if (strcmp(buff, "dst") == 0)
        !           675:                return (tDST);
        !           676:
        !           677:        for (tp = UnitsTable; tp->name; tp++)
        !           678:                if (strcmp(buff, tp->name) == 0) {
        !           679:                        yylval.Number = tp->value;
        !           680:                        return (tp->type);
        !           681:                }
        !           682:
        !           683:        /* Strip off any plural and try the units table again. */
        !           684:        i = strlen(buff) - 1;
        !           685:        if (buff[i] == 's') {
        !           686:                buff[i] = '\0';
        !           687:                for (tp = UnitsTable; tp->name; tp++)
        !           688:                        if (strcmp(buff, tp->name) == 0) {
        !           689:                                yylval.Number = tp->value;
        !           690:                                return (tp->type);
        !           691:                        }
        !           692:                buff[i] = 's';  /* Put back for "this" in OtherTable. */
        !           693:        }
        !           694:
        !           695:        for (tp = OtherTable; tp->name; tp++)
        !           696:                if (strcmp(buff, tp->name) == 0) {
        !           697:                        yylval.Number = tp->value;
        !           698:                        return (tp->type);
        !           699:                }
        !           700:
        !           701:        /* Military timezones. */
        !           702:        if (buff[1] == '\0' && isalpha(*buff)) {
        !           703:                for (tp = MilitaryTable; tp->name; tp++)
        !           704:                        if (strcmp(buff, tp->name) == 0) {
        !           705:                                yylval.Number = tp->value;
        !           706:                                return (tp->type);
        !           707:                        }
        !           708:        }
        !           709:
        !           710:        /* Drop out any periods and try the timezone table again. */
        !           711:        for (i = 0, p = q = buff; *q; q++)
        !           712:                if (*q != '.')
        !           713:                        *p++ = *q;
        !           714:                else
        !           715:                        i++;
        !           716:        *p = '\0';
        !           717:        if (i)
        !           718:                for (tp = TimezoneTable; tp->name; tp++)
        !           719:                        if (strcmp(buff, tp->name) == 0) {
        !           720:                                yylval.Number = tp->value;
        !           721:                                return (tp->type);
        !           722:                        }
        !           723:
        !           724:        return (tID);
        !           725: }
        !           726:
        !           727:
        !           728: static int
        !           729: yylex(void)
        !           730: {
        !           731:        char    c, *p, buff[20];
        !           732:        int     count, sign;
        !           733:
        !           734:        for (;;) {
        !           735:                while (isspace(*yyInput))
        !           736:                        yyInput++;
        !           737:
        !           738:                if (isdigit(c = *yyInput) || c == '-' || c == '+') {
        !           739:                        if (c == '-' || c == '+') {
        !           740:                                sign = c == '-' ? -1 : 1;
        !           741:                                if (!isdigit(*++yyInput))
        !           742:                                        /* skip the '-' sign */
        !           743:                                        continue;
        !           744:                        }
        !           745:                        else
        !           746:                                sign = 0;
        !           747:
        !           748:                        for (yylval.Number = 0; isdigit(c = *yyInput++); )
        !           749:                                yylval.Number = 10 * yylval.Number + c - '0';
        !           750:                        yyInput--;
        !           751:                        if (sign < 0)
        !           752:                                yylval.Number = -yylval.Number;
        !           753:                        return sign ? tSNUMBER : tUNUMBER;
        !           754:                }
        !           755:
        !           756:                if (isalpha(c)) {
        !           757:                        for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
        !           758:                                if (p < &buff[sizeof buff - 1])
        !           759:                                        *p++ = c;
        !           760:                        *p = '\0';
        !           761:                        yyInput--;
        !           762:                        return LookupWord(buff);
        !           763:                }
        !           764:                if (c != '(')
        !           765:                        return *yyInput++;
        !           766:
        !           767:                count = 0;
        !           768:                do {
        !           769:                        c = *yyInput++;
        !           770:                        if (c == '\0')
        !           771:                                return (c);
        !           772:                        if (c == '(')
        !           773:                                count++;
        !           774:                        else if (c == ')')
        !           775:                                count--;
        !           776:                } while (count > 0);
        !           777:        }
        !           778: }
        !           779:
        !           780: #define TM_YEAR_ORIGIN 1900
        !           781:
        !           782: /* Yield A - B, measured in seconds.  */
        !           783: static long
        !           784: difftm (struct tm *a, struct tm *b)
        !           785: {
        !           786:        int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
        !           787:        int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
        !           788:        int days = (
        !           789:                          /* difference in day of year */
        !           790:                          a->tm_yday - b->tm_yday
        !           791:                          /* + intervening leap days */
        !           792:                          +  ((ay >> 2) - (by >> 2))
        !           793:                          -  (ay/100 - by/100)
        !           794:                          +  ((ay/100 >> 2) - (by/100 >> 2))
        !           795:                          /* + difference in years * 365 */
        !           796:                          +  (long)(ay-by) * 365
        !           797:                          );
        !           798:        return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
        !           799:            + (a->tm_min - b->tm_min)) + (a->tm_sec - b->tm_sec));
        !           800: }
        !           801:
        !           802: time_t
        !           803: get_date(char *p, struct timeb *now)
        !           804: {
        !           805:        struct tm       *tm, gmt;
        !           806:        struct timeb    ftz;
        !           807:        time_t          Start;
        !           808:        time_t          tod;
        !           809:        time_t nowtime;
        !           810:
        !           811:        yyInput = p;
        !           812:        if (now == NULL) {
        !           813:                struct tm *gmt_ptr;
        !           814:
        !           815:                now = &ftz;
        !           816:                (void)time (&nowtime);
        !           817:
        !           818:                gmt_ptr = gmtime (&nowtime);
        !           819:                if (gmt_ptr != NULL) {
        !           820:                        /* Make a copy, in case localtime modifies *tm (I think
        !           821:                         * that comment now applies to *gmt_ptr, but I am too
        !           822:                         * lazy to dig into how gmtime and locatime allocate the
        !           823:                         * structures they return pointers to).
        !           824:                         */
        !           825:                        gmt = *gmt_ptr;
        !           826:                }
        !           827:
        !           828:                if (!(tm = localtime (&nowtime)))
        !           829:                        return (-1);
        !           830:
        !           831:                if (gmt_ptr != NULL)
        !           832:                        ftz.timezone = difftm (&gmt, tm) / 60;
        !           833:                else
        !           834:                        /* We are on a system like VMS, where the system clock is
        !           835:                           in local time and the system has no concept of timezones.
        !           836:                           Hopefully we can fake this out (for the case in which the
        !           837:                           user specifies no timezone) by just saying the timezone
        !           838:                           is zero.  */
        !           839:                        ftz.timezone = 0;
        !           840:
        !           841:                if(tm->tm_isdst)
        !           842:                        ftz.timezone += 60;
        !           843:        }
        !           844:        else {
        !           845:                nowtime = now->time;
        !           846:        }
        !           847:
        !           848:        tm = localtime(&nowtime);
        !           849:        yyYear = tm->tm_year + 1900;
        !           850:        yyMonth = tm->tm_mon + 1;
        !           851:        yyDay = tm->tm_mday;
        !           852:        yyTimezone = now->timezone;
        !           853:        yyDSTmode = DSTmaybe;
        !           854:        yyHour = 0;
        !           855:        yyMinutes = 0;
        !           856:        yySeconds = 0;
        !           857:        yyMeridian = MER24;
        !           858:        yyRelSeconds = 0;
        !           859:        yyRelMonth = 0;
        !           860:        yyHaveDate = 0;
        !           861:        yyHaveDay = 0;
        !           862:        yyHaveRel = 0;
        !           863:        yyHaveTime = 0;
        !           864:        yyHaveZone = 0;
        !           865:
        !           866:        if (yyparse() || yyHaveTime > 1 || yyHaveZone > 1 ||
        !           867:            yyHaveDate > 1 || yyHaveDay > 1)
        !           868:                return (-1);
        !           869:
        !           870:        if (yyHaveDate || yyHaveTime || yyHaveDay) {
        !           871:                Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes,
        !           872:                    yySeconds, yyMeridian, yyDSTmode);
        !           873:                if (Start < 0)
        !           874:                        return (-1);
        !           875:        } else {
        !           876:                Start = nowtime;
        !           877:                if (!yyHaveRel)
        !           878:                        Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
        !           879:        }
        !           880:
        !           881:        Start += yyRelSeconds;
        !           882:        Start += RelativeMonth(Start, yyRelMonth);
        !           883:
        !           884:        if (yyHaveDay && !yyHaveDate) {
        !           885:                tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
        !           886:                Start += tod;
        !           887:        }
        !           888:
        !           889:        /* Have to do *something* with a legitimate -1 so it's distinguishable
        !           890:         * from the error return value.  (Alternately could set errno on error.)
        !           891:         */
        !           892:        return (Start == -1) ? (0) : (Start);
        !           893: }
        !           894:
        !           895: #if defined(TEST)
        !           896: /* ARGSUSED */
        !           897: int
        !           898: main(int argc, char **argv)
        !           899: {
        !           900:        char    buff[128];
        !           901:        time_t  d;
        !           902:
        !           903:        (void)printf("Enter date, or blank line to exit.\n\t> ");
        !           904:        (void)fflush(stdout);
        !           905:        while (fgets(buff, sizeof(buff), stdin) && buff[0]) {
        !           906:                d = get_date(buff, (struct timeb *)NULL);
        !           907:                if (d == -1)
        !           908:                        (void)printf("Bad format - couldn't convert.\n");
        !           909:                else
        !           910:                        (void)printf("%s", ctime(&d));
        !           911:                (void)printf("\t> ");
        !           912:                (void)fflush(stdout);
        !           913:        }
        !           914:
        !           915:        return (0);
        !           916: }
        !           917: #endif /* defined(TEST) */