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 13 shift/reduce conflicts. 9 ** 10 ** This code is in the public domain and has no copyright. 11 */ 12 13 #ifdef HAVE_CONFIG_H 14 # include <config.h> 15 #endif 16 17 /* Since the code of getdate.y is not included in the Emacs executable 18 itself, there is no need to #define static in this file. Even if 19 the code were included in the Emacs executable, it probably 20 wouldn't do any harm to #undef it here; this will only cause 21 problems if we try to write to a static variable, which I don't 22 think this code needs to do. */ 23 #ifdef emacs 24 # undef static 25 #endif 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <ctype.h> 30 #include <time.h> 31 #include <string.h> 32 33 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) 34 35 #define EPOCH 1970 36 #define HOUR(x) ((x) * 60) 37 38 #define MAX_BUFF_LEN 128 /* size of buffer to read the date into */ 39 40 /* 41 ** An entry in the lexical lookup table. 42 */ 43 typedef struct _TABLE { 44 const char *name; 45 int type; 46 int value; 47 } TABLE; 48 49 50 /* 51 ** Meridian: am, pm, or 24-hour style. 52 */ 53 typedef enum _MERIDIAN { 54 MERam, MERpm, MER24 55 } MERIDIAN; 56 57 struct global { 58 int DayOrdinal; 59 int DayNumber; 60 int HaveDate; 61 int HaveDay; 62 int HaveRel; 63 int HaveTime; 64 int HaveZone; 65 int Timezone; 66 int Day; 67 int Hour; 68 int Minutes; 69 int Month; 70 int Seconds; 71 int Year; 72 MERIDIAN Meridian; 73 int RelDay; 74 int RelHour; 75 int RelMinutes; 76 int RelMonth; 77 int RelSeconds; 78 int RelYear; 79 }; 80 81 union YYSTYPE; 82 static int yylex (union YYSTYPE *lvalp, const char **yyInput); 83 static int yyerror (const char **yyInput, struct global *yy, char *s); 84 static int yyparse (const char **yyInput, struct global *yy); 85 86 #define YYENABLE_NLS 0 87 #define YYLTYPE_IS_TRIVIAL 0 88 89 %} 90 91 %name-prefix "lu_gd" 92 %define api.pure 93 94 %parse-param { const char **yyInput } 95 %lex-param { const char **yyInput } 96 %parse-param { struct global *yy } 97 98 %union { 99 int Number; 100 enum _MERIDIAN Meridian; 101 } 102 103 %token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID 104 %token tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT 105 %token tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE 106 107 %type <Number> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT 108 %type <Number> tMONTH tMONTH_UNIT 109 %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE 110 %type <Meridian> tMERIDIAN o_merid 111 112 %expect 13 113 114 %% 115 116 spec : /* NULL */ 117 | spec item 118 ; 119 120 item : time { 121 yy->HaveTime++; 122 } 123 | zone { 124 yy->HaveZone++; 125 } 126 | date { 127 yy->HaveDate++; 128 } 129 | day { 130 yy->HaveDay++; 131 } 132 | rel { 133 yy->HaveRel++; 134 } 135 | number 136 ; 137 138 time : tUNUMBER tMERIDIAN { 139 yy->Hour = $1; 140 yy->Minutes = 0; 141 yy->Seconds = 0; 142 yy->Meridian = $2; 143 } 144 | tUNUMBER ':' tUNUMBER o_merid { 145 yy->Hour = $1; 146 yy->Minutes = $3; 147 yy->Seconds = 0; 148 yy->Meridian = $4; 149 } 150 | tUNUMBER ':' tUNUMBER tSNUMBER { 151 yy->Hour = $1; 152 yy->Minutes = $3; 153 yy->Meridian = MER24; 154 yy->HaveZone++; 155 yy->Timezone = ($4 < 0 156 ? -$4 % 100 + (-$4 / 100) * 60 157 : - ($4 % 100 + ($4 / 100) * 60)); 158 } 159 | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { 160 yy->Hour = $1; 161 yy->Minutes = $3; 162 yy->Seconds = $5; 163 yy->Meridian = $6; 164 } 165 | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { 166 yy->Hour = $1; 167 yy->Minutes = $3; 168 yy->Seconds = $5; 169 yy->Meridian = MER24; 170 yy->HaveZone++; 171 yy->Timezone = ($6 < 0 172 ? -$6 % 100 + (-$6 / 100) * 60 173 : - ($6 % 100 + ($6 / 100) * 60)); 174 } 175 ; 176 177 zone : tZONE { 178 yy->Timezone = $1; 179 } 180 | tDAYZONE { 181 yy->Timezone = $1 - 60; 182 } 183 | 184 tZONE tDST { 185 yy->Timezone = $1 - 60; 186 } 187 ; 188 189 day : tDAY { 190 yy->DayOrdinal = 1; 191 yy->DayNumber = $1; 192 } 193 | tDAY ',' { 194 yy->DayOrdinal = 1; 195 yy->DayNumber = $1; 196 } 197 | tUNUMBER tDAY { 198 yy->DayOrdinal = $1; 199 yy->DayNumber = $2; 200 } 201 ; 202 203 date : tUNUMBER '/' tUNUMBER { 204 yy->Month = $1; 205 yy->Day = $3; 206 } 207 | tUNUMBER '/' tUNUMBER '/' tUNUMBER { 208 /* Interpret as YY->YY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY. 209 The goal in recognizing YY->YY/MM/DD is solely to support legacy 210 machine-generated dates like those in an RCS log listing. If 211 you want portability, use the ISO 8601 format. */ 212 if ($1 >= 1000) 213 { 214 yy->Year = $1; 215 yy->Month = $3; 216 yy->Day = $5; 217 } 218 else 219 { 220 yy->Month = $1; 221 yy->Day = $3; 222 yy->Year = $5; 223 } 224 } 225 | tUNUMBER tSNUMBER tSNUMBER { 226 /* ISO 8601 format. yy->yy-mm-dd. */ 227 yy->Year = $1; 228 yy->Month = -$2; 229 yy->Day = -$3; 230 } 231 | tUNUMBER tMONTH tSNUMBER { 232 /* e.g. 17-JUN-1992. */ 233 yy->Day = $1; 234 yy->Month = $2; 235 yy->Year = -$3; 236 } 237 | tMONTH tUNUMBER { 238 yy->Month = $1; 239 yy->Day = $2; 240 } 241 | tMONTH tUNUMBER ',' tUNUMBER { 242 yy->Month = $1; 243 yy->Day = $2; 244 yy->Year = $4; 245 } 246 | tUNUMBER tMONTH { 247 yy->Month = $2; 248 yy->Day = $1; 249 } 250 | tUNUMBER tMONTH tUNUMBER { 251 yy->Month = $2; 252 yy->Day = $1; 253 yy->Year = $3; 254 } 255 ; 256 257 rel : relunit tAGO { 258 yy->RelSeconds = -yy->RelSeconds; 259 yy->RelMinutes = -yy->RelMinutes; 260 yy->RelHour = -yy->RelHour; 261 yy->RelDay = -yy->RelDay; 262 yy->RelMonth = -yy->RelMonth; 263 yy->RelYear = -yy->RelYear; 264 } 265 | relunit 266 ; 267 268 relunit : tUNUMBER tYEAR_UNIT { 269 yy->RelYear += $1 * $2; 270 } 271 | tSNUMBER tYEAR_UNIT { 272 yy->RelYear += $1 * $2; 273 } 274 | tYEAR_UNIT { 275 yy->RelYear++; 276 } 277 | tUNUMBER tMONTH_UNIT { 278 yy->RelMonth += $1 * $2; 279 } 280 | tSNUMBER tMONTH_UNIT { 281 yy->RelMonth += $1 * $2; 282 } 283 | tMONTH_UNIT { 284 yy->RelMonth++; 285 } 286 | tUNUMBER tDAY_UNIT { 287 yy->RelDay += $1 * $2; 288 } 289 | tSNUMBER tDAY_UNIT { 290 yy->RelDay += $1 * $2; 291 } 292 | tDAY_UNIT { 293 yy->RelDay++; 294 } 295 | tUNUMBER tHOUR_UNIT { 296 yy->RelHour += $1 * $2; 297 } 298 | tSNUMBER tHOUR_UNIT { 299 yy->RelHour += $1 * $2; 300 } 301 | tHOUR_UNIT { 302 yy->RelHour++; 303 } 304 | tUNUMBER tMINUTE_UNIT { 305 yy->RelMinutes += $1 * $2; 306 } 307 | tSNUMBER tMINUTE_UNIT { 308 yy->RelMinutes += $1 * $2; 309 } 310 | tMINUTE_UNIT { 311 yy->RelMinutes++; 312 } 313 | tUNUMBER tSEC_UNIT { 314 yy->RelSeconds += $1 * $2; 315 } 316 | tSNUMBER tSEC_UNIT { 317 yy->RelSeconds += $1 * $2; 318 } 319 | tSEC_UNIT { 320 yy->RelSeconds++; 321 } 322 ; 323 324 number : tUNUMBER 325 { 326 if (yy->HaveTime && yy->HaveDate && !yy->HaveRel) 327 yy->Year = $1; 328 else 329 { 330 if ($1>10000) 331 { 332 yy->HaveDate++; 333 yy->Day= ($1)%100; 334 yy->Month= ($1/100)%100; 335 yy->Year = $1/10000; 336 } 337 else 338 { 339 yy->HaveTime++; 340 if ($1 < 100) 341 { 342 yy->Hour = $1; 343 yy->Minutes = 0; 344 } 345 else 346 { 347 yy->Hour = $1 / 100; 348 yy->Minutes = $1 % 100; 349 } 350 yy->Seconds = 0; 351 yy->Meridian = MER24; 352 } 353 } 354 } 355 ; 356 357 o_merid : /* NULL */ 358 { 359 $$ = MER24; 360 } 361 | tMERIDIAN 362 { 363 $$ = $1; 364 } 365 ; 366 367 %% 368 369 /* Month and day table. */ 370 static TABLE const MonthDayTable[] = { 371 { "january", tMONTH, 1 }, 372 { "february", tMONTH, 2 }, 373 { "march", tMONTH, 3 }, 374 { "april", tMONTH, 4 }, 375 { "may", tMONTH, 5 }, 376 { "june", tMONTH, 6 }, 377 { "july", tMONTH, 7 }, 378 { "august", tMONTH, 8 }, 379 { "september", tMONTH, 9 }, 380 { "sept", tMONTH, 9 }, 381 { "october", tMONTH, 10 }, 382 { "november", tMONTH, 11 }, 383 { "december", tMONTH, 12 }, 384 { "sunday", tDAY, 0 }, 385 { "monday", tDAY, 1 }, 386 { "tuesday", tDAY, 2 }, 387 { "tues", tDAY, 2 }, 388 { "wednesday", tDAY, 3 }, 389 { "wednes", tDAY, 3 }, 390 { "thursday", tDAY, 4 }, 391 { "thur", tDAY, 4 }, 392 { "thurs", tDAY, 4 }, 393 { "friday", tDAY, 5 }, 394 { "saturday", tDAY, 6 }, 395 { NULL, 0, 0 } 396 }; 397 398 /* Time units table. */ 399 static TABLE const UnitsTable[] = { 400 { "year", tYEAR_UNIT, 1 }, 401 { "month", tMONTH_UNIT, 1 }, 402 { "fortnight", tDAY_UNIT, 14 }, 403 { "week", tDAY_UNIT, 7 }, 404 { "day", tDAY_UNIT, 1 }, 405 { "hour", tHOUR_UNIT, 1 }, 406 { "minute", tMINUTE_UNIT, 1 }, 407 { "min", tMINUTE_UNIT, 1 }, 408 { "second", tSEC_UNIT, 1 }, 409 { "sec", tSEC_UNIT, 1 }, 410 { NULL, 0, 0 } 411 }; 412 413 /* Assorted relative-time words. */ 414 static TABLE const OtherTable[] = { 415 { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, 416 { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, 417 { "today", tMINUTE_UNIT, 0 }, 418 { "now", tMINUTE_UNIT, 0 }, 419 { "last", tUNUMBER, -1 }, 420 { "this", tMINUTE_UNIT, 0 }, 421 { "next", tUNUMBER, 2 }, 422 { "first", tUNUMBER, 1 }, 423 /* { "second", tUNUMBER, 2 }, */ 424 { "third", tUNUMBER, 3 }, 425 { "fourth", tUNUMBER, 4 }, 426 { "fifth", tUNUMBER, 5 }, 427 { "sixth", tUNUMBER, 6 }, 428 { "seventh", tUNUMBER, 7 }, 429 { "eighth", tUNUMBER, 8 }, 430 { "ninth", tUNUMBER, 9 }, 431 { "tenth", tUNUMBER, 10 }, 432 { "eleventh", tUNUMBER, 11 }, 433 { "twelfth", tUNUMBER, 12 }, 434 { "ago", tAGO, 1 }, 435 { NULL, 0, 0 } 436 }; 437 438 /* The timezone table. */ 439 static TABLE const TimezoneTable[] = { 440 { "gmt", tZONE, HOUR ( 0) }, /* Greenwich Mean */ 441 { "ut", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */ 442 { "utc", tZONE, HOUR ( 0) }, 443 { "wet", tZONE, HOUR ( 0) }, /* Western European */ 444 { "bst", tDAYZONE, HOUR ( 0) }, /* British Summer */ 445 { "wat", tZONE, HOUR ( 1) }, /* West Africa */ 446 { "at", tZONE, HOUR ( 2) }, /* Azores */ 447 { "ast", tZONE, HOUR ( 4) }, /* Atlantic Standard */ 448 { "adt", tDAYZONE, HOUR ( 4) }, /* Atlantic Daylight */ 449 { "est", tZONE, HOUR ( 5) }, /* Eastern Standard */ 450 { "edt", tDAYZONE, HOUR ( 5) }, /* Eastern Daylight */ 451 { "cst", tZONE, HOUR ( 6) }, /* Central Standard */ 452 { "cdt", tDAYZONE, HOUR ( 6) }, /* Central Daylight */ 453 { "mst", tZONE, HOUR ( 7) }, /* Mountain Standard */ 454 { "mdt", tDAYZONE, HOUR ( 7) }, /* Mountain Daylight */ 455 { "pst", tZONE, HOUR ( 8) }, /* Pacific Standard */ 456 { "pdt", tDAYZONE, HOUR ( 8) }, /* Pacific Daylight */ 457 { "yst", tZONE, HOUR ( 9) }, /* Yukon Standard */ 458 { "ydt", tDAYZONE, HOUR ( 9) }, /* Yukon Daylight */ 459 { "hst", tZONE, HOUR (10) }, /* Hawaii Standard */ 460 { "hdt", tDAYZONE, HOUR (10) }, /* Hawaii Daylight */ 461 { "cat", tZONE, HOUR (10) }, /* Central Alaska */ 462 { "ahst", tZONE, HOUR (10) }, /* Alaska-Hawaii Standard */ 463 { "nt", tZONE, HOUR (11) }, /* Nome */ 464 { "idlw", tZONE, HOUR (12) }, /* International Date Line West */ 465 { "cet", tZONE, -HOUR (1) }, /* Central European */ 466 { "met", tZONE, -HOUR (1) }, /* Middle European */ 467 { "mewt", tZONE, -HOUR (1) }, /* Middle European Winter */ 468 { "mest", tDAYZONE, -HOUR (1) }, /* Middle European Summer */ 469 { "mesz", tDAYZONE, -HOUR (1) }, /* Middle European Summer */ 470 { "swt", tZONE, -HOUR (1) }, /* Swedish Winter */ 471 { "sst", tDAYZONE, -HOUR (1) }, /* Swedish Summer */ 472 { "fwt", tZONE, -HOUR (1) }, /* French Winter */ 473 { "fst", tDAYZONE, -HOUR (1) }, /* French Summer */ 474 { "eet", tZONE, -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */ 475 { "bt", tZONE, -HOUR (3) }, /* Baghdad, USSR Zone 2 */ 476 { "zp4", tZONE, -HOUR (4) }, /* USSR Zone 3 */ 477 { "zp5", tZONE, -HOUR (5) }, /* USSR Zone 4 */ 478 { "zp6", tZONE, -HOUR (6) }, /* USSR Zone 5 */ 479 { "wst", tZONE, -HOUR (8) }, /* West Australian Standard */ 480 { "cct", tZONE, -HOUR (8) }, /* China Coast, USSR Zone 7 */ 481 { "jst", tZONE, -HOUR (9) }, /* Japan Standard, USSR Zone 8 */ 482 { "acst", tZONE, -(HOUR (9) + 30)}, /* Australian Central Standard */ 483 { "acdt", tDAYZONE, -(HOUR (9) + 30)}, /* Australian Central Daylight */ 484 { "aest", tZONE, -HOUR (10) }, /* Australian Eastern Standard */ 485 { "aedt", tDAYZONE, -HOUR (10) }, /* Australian Eastern Daylight */ 486 { "gst", tZONE, -HOUR (10) }, /* Guam Standard, USSR Zone 9 */ 487 { "nzt", tZONE, -HOUR (12) }, /* New Zealand */ 488 { "nzst", tZONE, -HOUR (12) }, /* New Zealand Standard */ 489 { "nzdt", tDAYZONE, -HOUR (12) }, /* New Zealand Daylight */ 490 { "idle", tZONE, -HOUR (12) }, /* International Date Line East */ 491 { NULL, 0, 0 } 492 }; 493 494 /* Military timezone table. */ 495 static TABLE const MilitaryTable[] = { 496 { "a", tZONE, HOUR ( 1) }, 497 { "b", tZONE, HOUR ( 2) }, 498 { "c", tZONE, HOUR ( 3) }, 499 { "d", tZONE, HOUR ( 4) }, 500 { "e", tZONE, HOUR ( 5) }, 501 { "f", tZONE, HOUR ( 6) }, 502 { "g", tZONE, HOUR ( 7) }, 503 { "h", tZONE, HOUR ( 8) }, 504 { "i", tZONE, HOUR ( 9) }, 505 { "k", tZONE, HOUR ( 10) }, 506 { "l", tZONE, HOUR ( 11) }, 507 { "m", tZONE, HOUR ( 12) }, 508 { "n", tZONE, HOUR (- 1) }, 509 { "o", tZONE, HOUR (- 2) }, 510 { "p", tZONE, HOUR (- 3) }, 511 { "q", tZONE, HOUR (- 4) }, 512 { "r", tZONE, HOUR (- 5) }, 513 { "s", tZONE, HOUR (- 6) }, 514 { "t", tZONE, HOUR (- 7) }, 515 { "u", tZONE, HOUR (- 8) }, 516 { "v", tZONE, HOUR (- 9) }, 517 { "w", tZONE, HOUR (-10) }, 518 { "x", tZONE, HOUR (-11) }, 519 { "y", tZONE, HOUR (-12) }, 520 { "z", tZONE, HOUR ( 0) }, 521 { NULL, 0, 0 } 522 }; 523 524 525 526 527 /* ARGSUSED */ 528 static int 529 yyerror (const char **yyInput, struct global *yy, char *s) 530 { 531 (void)yyInput; 532 (void)yy; 533 (void)s; 534 return 0; 535 } 536 537 static int 538 ToHour (int Hours, MERIDIAN Meridian) 539 { 540 switch (Meridian) 541 { 542 case MER24: 543 if (Hours < 0 || Hours > 23) 544 return -1; 545 return Hours; 546 case MERam: 547 if (Hours < 1 || Hours > 12) 548 return -1; 549 if (Hours == 12) 550 Hours = 0; 551 return Hours; 552 case MERpm: 553 if (Hours < 1 || Hours > 12) 554 return -1; 555 if (Hours == 12) 556 Hours = 0; 557 return Hours + 12; 558 default: 559 abort (); 560 } 561 /* NOTREACHED */ 562 } 563 564 static int 565 ToYear (int Year) 566 { 567 if (Year < 0) 568 Year = -Year; 569 570 /* XPG4 suggests that years 00-68 map to 2000-2068, and 571 years 69-99 map to 1969-1999. */ 572 if (Year < 69) 573 Year += 2000; 574 else if (Year < 100) 575 Year += 1900; 576 577 return Year; 578 } 579 580 static int 581 LookupWord (YYSTYPE *lvalp, char *buff) 582 { 583 register char *p; 584 register char *q; 585 register const TABLE *tp; 586 int i; 587 int abbrev; 588 589 /* Make it lowercase. */ 590 for (p = buff; *p; p++) 591 if (isupper ((unsigned char)*p)) 592 *p = tolower (*p); 593 594 if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) 595 { 596 lvalp->Meridian = MERam; 597 return tMERIDIAN; 598 } 599 if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) 600 { 601 lvalp->Meridian = MERpm; 602 return tMERIDIAN; 603 } 604 605 /* See if we have an abbreviation for a month. */ 606 if (strlen (buff) == 3) 607 abbrev = 1; 608 else if (strlen (buff) == 4 && buff[3] == '.') 609 { 610 abbrev = 1; 611 buff[3] = '\0'; 612 } 613 else 614 abbrev = 0; 615 616 for (tp = MonthDayTable; tp->name; tp++) 617 { 618 if (abbrev) 619 { 620 if (strncmp (buff, tp->name, 3) == 0) 621 { 622 lvalp->Number = tp->value; 623 return tp->type; 624 } 625 } 626 else if (strcmp (buff, tp->name) == 0) 627 { 628 lvalp->Number = tp->value; 629 return tp->type; 630 } 631 } 632 633 for (tp = TimezoneTable; tp->name; tp++) 634 if (strcmp (buff, tp->name) == 0) 635 { 636 lvalp->Number = tp->value; 637 return tp->type; 638 } 639 640 if (strcmp (buff, "dst") == 0) 641 return tDST; 642 643 for (tp = UnitsTable; tp->name; tp++) 644 if (strcmp (buff, tp->name) == 0) 645 { 646 lvalp->Number = tp->value; 647 return tp->type; 648 } 649 650 /* Strip off any plural and try the units table again. */ 651 i = strlen (buff) - 1; 652 if (buff[i] == 's') 653 { 654 buff[i] = '\0'; 655 for (tp = UnitsTable; tp->name; tp++) 656 if (strcmp (buff, tp->name) == 0) 657 { 658 lvalp->Number = tp->value; 659 return tp->type; 660 } 661 buff[i] = 's'; /* Put back for "this" in OtherTable. */ 662 } 663 664 for (tp = OtherTable; tp->name; tp++) 665 if (strcmp (buff, tp->name) == 0) 666 { 667 lvalp->Number = tp->value; 668 return tp->type; 669 } 670 671 /* Military timezones. */ 672 if (buff[1] == '\0' && isalpha ((unsigned char)*buff)) 673 { 674 for (tp = MilitaryTable; tp->name; tp++) 675 if (strcmp (buff, tp->name) == 0) 676 { 677 lvalp->Number = tp->value; 678 return tp->type; 679 } 680 } 681 682 /* Drop out any periods and try the timezone table again. */ 683 for (i = 0, p = q = buff; *q; q++) 684 if (*q != '.') 685 *p++ = *q; 686 else 687 i++; 688 *p = '\0'; 689 if (i) 690 for (tp = TimezoneTable; tp->name; tp++) 691 if (strcmp (buff, tp->name) == 0) 692 { 693 lvalp->Number = tp->value; 694 return tp->type; 695 } 696 697 return tID; 698 } 699 700 static int 701 yylex (YYSTYPE *lvalp, const char **yyInput) 702 { 703 register char c; 704 register char *p; 705 char buff[20]; 706 int Count; 707 int sign; 708 709 for (;;) 710 { 711 while (isspace ((unsigned char)**yyInput)) 712 (*yyInput)++; 713 714 if (ISDIGIT (c = **yyInput) || c == '-' || c == '+') 715 { 716 if (c == '-' || c == '+') 717 { 718 sign = c == '-' ? -1 : 1; 719 if (!ISDIGIT (*++*yyInput)) 720 /* skip the '-' sign */ 721 continue; 722 } 723 else 724 sign = 0; 725 for (lvalp->Number = 0; ISDIGIT (c = *(*yyInput)++);) 726 lvalp->Number = 10 * lvalp->Number + c - '0'; 727 (*yyInput)--; 728 if (sign < 0) 729 lvalp->Number = -lvalp->Number; 730 return sign ? tSNUMBER : tUNUMBER; 731 } 732 if (isalpha ((unsigned char)c)) 733 { 734 for (p = buff; (c = *(*yyInput)++, isalpha ((unsigned char)c)) 735 || c == '.';) 736 if (p < &buff[sizeof buff - 1]) 737 *p++ = c; 738 *p = '\0'; 739 (*yyInput)--; 740 return LookupWord (lvalp, buff); 741 } 742 if (c != '(') 743 return *(*yyInput)++; 744 Count = 0; 745 do 746 { 747 c = *(*yyInput)++; 748 if (c == '\0') 749 return c; 750 if (c == '(') 751 Count++; 752 else if (c == ')') 753 Count--; 754 } 755 while (Count > 0); 756 } 757 } 758 759 #define TM_YEAR_ORIGIN 1900 760 761 /* Yield A - B, measured in seconds. */ 762 static long 763 difftm (struct tm *a, struct tm *b) 764 { 765 int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); 766 int by = b->tm_year + (TM_YEAR_ORIGIN - 1); 767 long days = ( 768 /* difference in day of year */ 769 a->tm_yday - b->tm_yday 770 /* + intervening leap days */ 771 + ((ay >> 2) - (by >> 2)) 772 - (ay / 100 - by / 100) 773 + ((ay / 100 >> 2) - (by / 100 >> 2)) 774 /* + difference in years * 365 */ 775 + (long) (ay - by) * 365 776 ); 777 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) 778 + (a->tm_min - b->tm_min)) 779 + (a->tm_sec - b->tm_sec)); 780 } 781 782 time_t 783 dpl_get_date (const char *p, const time_t *now) 784 { 785 struct tm tm, tm0, *tmp; 786 struct global yy; 787 time_t Start; 788 struct tm res; 789 790 memset(&res, 0, sizeof (res)); 791 Start = now ? *now : time ((time_t *) NULL); 792 localtime_r(&Start, &res); 793 tmp = &res; 794 795 memset (&yy, 0, sizeof(yy)); 796 yy.Year = tmp->tm_year + TM_YEAR_ORIGIN; 797 yy.Month = tmp->tm_mon + 1; 798 yy.Day = tmp->tm_mday; 799 yy.Hour = tmp->tm_hour; 800 yy.Minutes = tmp->tm_min; 801 yy.Seconds = tmp->tm_sec; 802 yy.Meridian = MER24; 803 yy.RelSeconds = 0; 804 yy.RelMinutes = 0; 805 yy.RelHour = 0; 806 yy.RelDay = 0; 807 yy.RelMonth = 0; 808 yy.RelYear = 0; 809 yy.HaveDate = 0; 810 yy.HaveDay = 0; 811 yy.HaveRel = 0; 812 yy.HaveTime = 0; 813 yy.HaveZone = 0; 814 815 if (yyparse (&p, &yy) 816 || yy.HaveTime > 1 || yy.HaveZone > 1 || yy.HaveDate > 1 || yy.HaveDay > 1) 817 return -1; 818 819 tm.tm_year = ToYear (yy.Year) - TM_YEAR_ORIGIN + yy.RelYear; 820 tm.tm_mon = yy.Month - 1 + yy.RelMonth; 821 tm.tm_mday = yy.Day + yy.RelDay; 822 if (yy.HaveTime || (yy.HaveRel && !yy.HaveDate && !yy.HaveDay)) 823 { 824 tm.tm_hour = ToHour (yy.Hour, yy.Meridian); 825 if (tm.tm_hour < 0) 826 return -1; 827 tm.tm_min = yy.Minutes; 828 tm.tm_sec = yy.Seconds; 829 } 830 else 831 { 832 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 833 } 834 tm.tm_hour += yy.RelHour; 835 tm.tm_min += yy.RelMinutes; 836 tm.tm_sec += yy.RelSeconds; 837 tm.tm_isdst = -1; 838 tm0 = tm; 839 840 Start = mktime (&tm); 841 842 if (Start == (time_t) -1) 843 { 844 845 /* Guard against falsely reporting errors near the time_t boundaries 846 when parsing times in other time zones. For example, if the min 847 time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead 848 of UTC, then the min localtime value is 1970-01-01 08:00:00; if 849 we apply mktime to 1970-01-01 00:00:00 we will get an error, so 850 we apply mktime to 1970-01-02 08:00:00 instead and adjust the time 851 zone by 24 hours to compensate. This algorithm assumes that 852 there is no DST transition within a day of the time_t boundaries. */ 853 if (yy.HaveZone) 854 { 855 tm = tm0; 856 if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN) 857 { 858 tm.tm_mday++; 859 yy.Timezone -= 24 * 60; 860 } 861 else 862 { 863 tm.tm_mday--; 864 yy.Timezone += 24 * 60; 865 } 866 Start = mktime (&tm); 867 } 868 869 if (Start == (time_t) -1) 870 return Start; 871 } 872 873 if (yy.HaveDay && !yy.HaveDate) 874 { 875 tm.tm_mday += ((yy.DayNumber - tm.tm_wday + 7) % 7 876 + 7 * (yy.DayOrdinal - (0 < yy.DayOrdinal))); 877 Start = mktime (&tm); 878 if (Start == (time_t) -1) 879 return Start; 880 } 881 882 if (yy.HaveZone) 883 { 884 long delta = yy.Timezone * 60L + difftm (&tm, gmtime (&Start)); 885 if ((Start + delta < Start) != (delta < 0)) 886 return -1; /* time_t overflow */ 887 Start += delta; 888 } 889 890 return Start; 891 } 892 893