Annotation of embedaddon/sudo/plugins/sudoers/getdate.y, revision 1.1.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>