Annotation of embedaddon/sudo/plugins/sudoers/getdate.y, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>