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>