1/* 2 * tclGetDate.y -- 3 * 4 * Contains yacc grammar for parsing date and time strings. The output of 5 * this file should be the file tclDate.c which is used directly in the 6 * Tcl sources. Note that this file is largely obsolete in Tcl 8.5; it is 7 * only used when doing free-form date parsing, an ill-defined process 8 * anyway. 9 * 10 * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans. 11 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 12 * 13 * See the file "license.terms" for information on usage and redistribution of 14 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 15 * 16 * RCS: @(#) $Id: tclGetDate.y,v 1.38.2.1 2009/06/09 13:52:58 kennykb Exp $ 17 */ 18 19%parse-param {DateInfo* info} 20%lex-param {DateInfo* info} 21%pure-parser 22 /* %error-verbose would be nice, but our token names are meaningless */ 23%locations 24 25%{ 26/* 27 * tclDate.c -- 28 * 29 * This file is generated from a yacc grammar defined in the file 30 * tclGetDate.y. It should not be edited directly. 31 * 32 * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans. 33 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 34 * 35 * See the file "license.terms" for information on usage and redistribution of 36 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 37 * 38 */ 39#include "tclInt.h" 40 41/* 42 * Bison generates several labels that happen to be unused. MS Visual C++ 43 * doesn't like that, and complains. Tell it to shut up. 44 */ 45 46#ifdef _MSC_VER 47#pragma warning( disable : 4102 ) 48#endif /* _MSC_VER */ 49 50/* 51 * yyparse will accept a 'struct DateInfo' as its parameter; that's where the 52 * parsed fields will be returned. 53 */ 54 55typedef struct DateInfo { 56 57 Tcl_Obj* messages; /* Error messages */ 58 const char* separatrix; /* String separating messages */ 59 60 time_t dateYear; 61 time_t dateMonth; 62 time_t dateDay; 63 int dateHaveDate; 64 65 time_t dateHour; 66 time_t dateMinutes; 67 time_t dateSeconds; 68 int dateMeridian; 69 int dateHaveTime; 70 71 time_t dateTimezone; 72 int dateDSTmode; 73 int dateHaveZone; 74 75 time_t dateRelMonth; 76 time_t dateRelDay; 77 time_t dateRelSeconds; 78 int dateHaveRel; 79 80 time_t dateMonthOrdinal; 81 int dateHaveOrdinalMonth; 82 83 time_t dateDayOrdinal; 84 time_t dateDayNumber; 85 int dateHaveDay; 86 87 const char *dateStart; 88 const char *dateInput; 89 time_t *dateRelPointer; 90 91 int dateDigitCount; 92} DateInfo; 93 94#define YYMALLOC ckalloc 95#define YYFREE(x) (ckfree((void*) (x))) 96 97#define yyDSTmode (info->dateDSTmode) 98#define yyDayOrdinal (info->dateDayOrdinal) 99#define yyDayNumber (info->dateDayNumber) 100#define yyMonthOrdinal (info->dateMonthOrdinal) 101#define yyHaveDate (info->dateHaveDate) 102#define yyHaveDay (info->dateHaveDay) 103#define yyHaveOrdinalMonth (info->dateHaveOrdinalMonth) 104#define yyHaveRel (info->dateHaveRel) 105#define yyHaveTime (info->dateHaveTime) 106#define yyHaveZone (info->dateHaveZone) 107#define yyTimezone (info->dateTimezone) 108#define yyDay (info->dateDay) 109#define yyMonth (info->dateMonth) 110#define yyYear (info->dateYear) 111#define yyHour (info->dateHour) 112#define yyMinutes (info->dateMinutes) 113#define yySeconds (info->dateSeconds) 114#define yyMeridian (info->dateMeridian) 115#define yyRelMonth (info->dateRelMonth) 116#define yyRelDay (info->dateRelDay) 117#define yyRelSeconds (info->dateRelSeconds) 118#define yyRelPointer (info->dateRelPointer) 119#define yyInput (info->dateInput) 120#define yyDigitCount (info->dateDigitCount) 121 122#define EPOCH 1970 123#define START_OF_TIME 1902 124#define END_OF_TIME 2037 125 126/* 127 * The offset of tm_year of struct tm returned by localtime, gmtime, etc. 128 * Posix requires 1900. 129 */ 130 131#define TM_YEAR_BASE 1900 132 133#define HOUR(x) ((int) (60 * x)) 134#define SECSPERDAY (24L * 60L * 60L) 135#define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0)) 136 137/* 138 * An entry in the lexical lookup table. 139 */ 140 141typedef struct _TABLE { 142 const char *name; 143 int type; 144 time_t value; 145} TABLE; 146 147/* 148 * Daylight-savings mode: on, off, or not yet known. 149 */ 150 151typedef enum _DSTMODE { 152 DSTon, DSToff, DSTmaybe 153} DSTMODE; 154 155/* 156 * Meridian: am, pm, or 24-hour style. 157 */ 158 159typedef enum _MERIDIAN { 160 MERam, MERpm, MER24 161} MERIDIAN; 162 163%} 164 165%union { 166 time_t Number; 167 enum _MERIDIAN Meridian; 168} 169 170%{ 171 172/* 173 * Prototypes of internal functions. 174 */ 175 176static int LookupWord(YYSTYPE* yylvalPtr, char *buff); 177 static void TclDateerror(YYLTYPE* location, 178 DateInfo* info, const char *s); 179 static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location, 180 DateInfo* info); 181static time_t ToSeconds(time_t Hours, time_t Minutes, 182 time_t Seconds, MERIDIAN Meridian); 183MODULE_SCOPE int yyparse(DateInfo*); 184 185%} 186 187%token tAGO 188%token tDAY 189%token tDAYZONE 190%token tID 191%token tMERIDIAN 192%token tMONTH 193%token tMONTH_UNIT 194%token tSTARDATE 195%token tSEC_UNIT 196%token tSNUMBER 197%token tUNUMBER 198%token tZONE 199%token tEPOCH 200%token tDST 201%token tISOBASE 202%token tDAY_UNIT 203%token tNEXT 204 205%type <Number> tDAY 206%type <Number> tDAYZONE 207%type <Number> tMONTH 208%type <Number> tMONTH_UNIT 209%type <Number> tDST 210%type <Number> tSEC_UNIT 211%type <Number> tSNUMBER 212%type <Number> tUNUMBER 213%type <Number> tZONE 214%type <Number> tISOBASE 215%type <Number> tDAY_UNIT 216%type <Number> unit 217%type <Number> sign 218%type <Number> tNEXT 219%type <Number> tSTARDATE 220%type <Meridian> tMERIDIAN 221%type <Meridian> o_merid 222 223%% 224 225spec : /* NULL */ 226 | spec item 227 ; 228 229item : time { 230 yyHaveTime++; 231 } 232 | zone { 233 yyHaveZone++; 234 } 235 | date { 236 yyHaveDate++; 237 } 238 | ordMonth { 239 yyHaveOrdinalMonth++; 240 } 241 | day { 242 yyHaveDay++; 243 } 244 | relspec { 245 yyHaveRel++; 246 } 247 | iso { 248 yyHaveTime++; 249 yyHaveDate++; 250 } 251 | trek { 252 yyHaveTime++; 253 yyHaveDate++; 254 yyHaveRel++; 255 } 256 | number 257 ; 258 259time : tUNUMBER tMERIDIAN { 260 yyHour = $1; 261 yyMinutes = 0; 262 yySeconds = 0; 263 yyMeridian = $2; 264 } 265 | tUNUMBER ':' tUNUMBER o_merid { 266 yyHour = $1; 267 yyMinutes = $3; 268 yySeconds = 0; 269 yyMeridian = $4; 270 } 271 | tUNUMBER ':' tUNUMBER '-' tUNUMBER { 272 yyHour = $1; 273 yyMinutes = $3; 274 yyMeridian = MER24; 275 yyDSTmode = DSToff; 276 yyTimezone = ($5 % 100 + ($5 / 100) * 60); 277 ++yyHaveZone; 278 } 279 | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { 280 yyHour = $1; 281 yyMinutes = $3; 282 yySeconds = $5; 283 yyMeridian = $6; 284 } 285 | tUNUMBER ':' tUNUMBER ':' tUNUMBER '-' tUNUMBER { 286 yyHour = $1; 287 yyMinutes = $3; 288 yySeconds = $5; 289 yyMeridian = MER24; 290 yyDSTmode = DSToff; 291 yyTimezone = ($7 % 100 + ($7 / 100) * 60); 292 ++yyHaveZone; 293 } 294 ; 295 296zone : tZONE tDST { 297 yyTimezone = $1; 298 yyDSTmode = DSTon; 299 } 300 | tZONE { 301 yyTimezone = $1; 302 yyDSTmode = DSToff; 303 } 304 | tDAYZONE { 305 yyTimezone = $1; 306 yyDSTmode = DSTon; 307 } 308 ; 309 310day : tDAY { 311 yyDayOrdinal = 1; 312 yyDayNumber = $1; 313 } 314 | tDAY ',' { 315 yyDayOrdinal = 1; 316 yyDayNumber = $1; 317 } 318 | tUNUMBER tDAY { 319 yyDayOrdinal = $1; 320 yyDayNumber = $2; 321 } 322 | sign tUNUMBER tDAY { 323 yyDayOrdinal = $1 * $2; 324 yyDayNumber = $3; 325 } 326 | tNEXT tDAY { 327 yyDayOrdinal = 2; 328 yyDayNumber = $2; 329 } 330 ; 331 332date : tUNUMBER '/' tUNUMBER { 333 yyMonth = $1; 334 yyDay = $3; 335 } 336 | tUNUMBER '/' tUNUMBER '/' tUNUMBER { 337 yyMonth = $1; 338 yyDay = $3; 339 yyYear = $5; 340 } 341 | tISOBASE { 342 yyYear = $1 / 10000; 343 yyMonth = ($1 % 10000)/100; 344 yyDay = $1 % 100; 345 } 346 | tUNUMBER '-' tMONTH '-' tUNUMBER { 347 yyDay = $1; 348 yyMonth = $3; 349 yyYear = $5; 350 } 351 | tUNUMBER '-' tUNUMBER '-' tUNUMBER { 352 yyMonth = $3; 353 yyDay = $5; 354 yyYear = $1; 355 } 356 | tMONTH tUNUMBER { 357 yyMonth = $1; 358 yyDay = $2; 359 } 360 | tMONTH tUNUMBER ',' tUNUMBER { 361 yyMonth = $1; 362 yyDay = $2; 363 yyYear = $4; 364 } 365 | tUNUMBER tMONTH { 366 yyMonth = $2; 367 yyDay = $1; 368 } 369 | tEPOCH { 370 yyMonth = 1; 371 yyDay = 1; 372 yyYear = EPOCH; 373 } 374 | tUNUMBER tMONTH tUNUMBER { 375 yyMonth = $2; 376 yyDay = $1; 377 yyYear = $3; 378 } 379 ; 380 381ordMonth: tNEXT tMONTH { 382 yyMonthOrdinal = 1; 383 yyMonth = $2; 384 } 385 | tNEXT tUNUMBER tMONTH { 386 yyMonthOrdinal = $2; 387 yyMonth = $3; 388 } 389 ; 390 391iso : tISOBASE tZONE tISOBASE { 392 if ($2 != HOUR( 7)) YYABORT; 393 yyYear = $1 / 10000; 394 yyMonth = ($1 % 10000)/100; 395 yyDay = $1 % 100; 396 yyHour = $3 / 10000; 397 yyMinutes = ($3 % 10000)/100; 398 yySeconds = $3 % 100; 399 } 400 | tISOBASE tZONE tUNUMBER ':' tUNUMBER ':' tUNUMBER { 401 if ($2 != HOUR( 7)) YYABORT; 402 yyYear = $1 / 10000; 403 yyMonth = ($1 % 10000)/100; 404 yyDay = $1 % 100; 405 yyHour = $3; 406 yyMinutes = $5; 407 yySeconds = $7; 408 } 409 | tISOBASE tISOBASE { 410 yyYear = $1 / 10000; 411 yyMonth = ($1 % 10000)/100; 412 yyDay = $1 % 100; 413 yyHour = $2 / 10000; 414 yyMinutes = ($2 % 10000)/100; 415 yySeconds = $2 % 100; 416 } 417 ; 418 419trek : tSTARDATE tUNUMBER '.' tUNUMBER { 420 /* 421 * Offset computed year by -377 so that the returned years will be 422 * in a range accessible with a 32 bit clock seconds value. 423 */ 424 425 yyYear = $2/1000 + 2323 - 377; 426 yyDay = 1; 427 yyMonth = 1; 428 yyRelDay += (($2%1000)*(365 + IsLeapYear(yyYear)))/1000; 429 yyRelSeconds += $4 * 144 * 60; 430 } 431 ; 432 433relspec : relunits tAGO { 434 yyRelSeconds *= -1; 435 yyRelMonth *= -1; 436 yyRelDay *= -1; 437 } 438 | relunits 439 ; 440 441relunits : sign tUNUMBER unit { 442 *yyRelPointer += $1 * $2 * $3; 443 } 444 | tUNUMBER unit { 445 *yyRelPointer += $1 * $2; 446 } 447 | tNEXT unit { 448 *yyRelPointer += $2; 449 } 450 | tNEXT tUNUMBER unit { 451 *yyRelPointer += $2 * $3; 452 } 453 | unit { 454 *yyRelPointer += $1; 455 } 456 ; 457 458sign : '-' { 459 $$ = -1; 460 } 461 | '+' { 462 $$ = 1; 463 } 464 ; 465 466unit : tSEC_UNIT { 467 $$ = $1; 468 yyRelPointer = &yyRelSeconds; 469 } 470 | tDAY_UNIT { 471 $$ = $1; 472 yyRelPointer = &yyRelDay; 473 } 474 | tMONTH_UNIT { 475 $$ = $1; 476 yyRelPointer = &yyRelMonth; 477 } 478 ; 479 480number : tUNUMBER { 481 if (yyHaveTime && yyHaveDate && !yyHaveRel) { 482 yyYear = $1; 483 } else { 484 yyHaveTime++; 485 if (yyDigitCount <= 2) { 486 yyHour = $1; 487 yyMinutes = 0; 488 } else { 489 yyHour = $1 / 100; 490 yyMinutes = $1 % 100; 491 } 492 yySeconds = 0; 493 yyMeridian = MER24; 494 } 495 } 496 ; 497 498o_merid : /* NULL */ { 499 $$ = MER24; 500 } 501 | tMERIDIAN { 502 $$ = $1; 503 } 504 ; 505 506%% 507MODULE_SCOPE int yychar; 508MODULE_SCOPE YYSTYPE yylval; 509MODULE_SCOPE int yynerrs; 510 511/* 512 * Month and day table. 513 */ 514 515static TABLE MonthDayTable[] = { 516 { "january", tMONTH, 1 }, 517 { "february", tMONTH, 2 }, 518 { "march", tMONTH, 3 }, 519 { "april", tMONTH, 4 }, 520 { "may", tMONTH, 5 }, 521 { "june", tMONTH, 6 }, 522 { "july", tMONTH, 7 }, 523 { "august", tMONTH, 8 }, 524 { "september", tMONTH, 9 }, 525 { "sept", tMONTH, 9 }, 526 { "october", tMONTH, 10 }, 527 { "november", tMONTH, 11 }, 528 { "december", tMONTH, 12 }, 529 { "sunday", tDAY, 0 }, 530 { "monday", tDAY, 1 }, 531 { "tuesday", tDAY, 2 }, 532 { "tues", tDAY, 2 }, 533 { "wednesday", tDAY, 3 }, 534 { "wednes", tDAY, 3 }, 535 { "thursday", tDAY, 4 }, 536 { "thur", tDAY, 4 }, 537 { "thurs", tDAY, 4 }, 538 { "friday", tDAY, 5 }, 539 { "saturday", tDAY, 6 }, 540 { NULL } 541}; 542 543/* 544 * Time units table. 545 */ 546 547static TABLE UnitsTable[] = { 548 { "year", tMONTH_UNIT, 12 }, 549 { "month", tMONTH_UNIT, 1 }, 550 { "fortnight", tDAY_UNIT, 14 }, 551 { "week", tDAY_UNIT, 7 }, 552 { "day", tDAY_UNIT, 1 }, 553 { "hour", tSEC_UNIT, 60 * 60 }, 554 { "minute", tSEC_UNIT, 60 }, 555 { "min", tSEC_UNIT, 60 }, 556 { "second", tSEC_UNIT, 1 }, 557 { "sec", tSEC_UNIT, 1 }, 558 { NULL } 559}; 560 561/* 562 * Assorted relative-time words. 563 */ 564 565static TABLE OtherTable[] = { 566 { "tomorrow", tDAY_UNIT, 1 }, 567 { "yesterday", tDAY_UNIT, -1 }, 568 { "today", tDAY_UNIT, 0 }, 569 { "now", tSEC_UNIT, 0 }, 570 { "last", tUNUMBER, -1 }, 571 { "this", tSEC_UNIT, 0 }, 572 { "next", tNEXT, 1 }, 573#if 0 574 { "first", tUNUMBER, 1 }, 575 { "second", tUNUMBER, 2 }, 576 { "third", tUNUMBER, 3 }, 577 { "fourth", tUNUMBER, 4 }, 578 { "fifth", tUNUMBER, 5 }, 579 { "sixth", tUNUMBER, 6 }, 580 { "seventh", tUNUMBER, 7 }, 581 { "eighth", tUNUMBER, 8 }, 582 { "ninth", tUNUMBER, 9 }, 583 { "tenth", tUNUMBER, 10 }, 584 { "eleventh", tUNUMBER, 11 }, 585 { "twelfth", tUNUMBER, 12 }, 586#endif 587 { "ago", tAGO, 1 }, 588 { "epoch", tEPOCH, 0 }, 589 { "stardate", tSTARDATE, 0 }, 590 { NULL } 591}; 592 593/* 594 * The timezone table. (Note: This table was modified to not use any floating 595 * point constants to work around an SGI compiler bug). 596 */ 597 598static TABLE TimezoneTable[] = { 599 { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ 600 { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ 601 { "utc", tZONE, HOUR( 0) }, 602 { "uct", tZONE, HOUR( 0) }, /* Universal Coordinated Time */ 603 { "wet", tZONE, HOUR( 0) }, /* Western European */ 604 { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ 605 { "wat", tZONE, HOUR( 1) }, /* West Africa */ 606 { "at", tZONE, HOUR( 2) }, /* Azores */ 607#if 0 608 /* For completeness. BST is also British Summer, and GST is 609 * also Guam Standard. */ 610 { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ 611 { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ 612#endif 613 { "nft", tZONE, HOUR( 7/2) }, /* Newfoundland */ 614 { "nst", tZONE, HOUR( 7/2) }, /* Newfoundland Standard */ 615 { "ndt", tDAYZONE, HOUR( 7/2) }, /* Newfoundland Daylight */ 616 { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ 617 { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ 618 { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ 619 { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ 620 { "cst", tZONE, HOUR( 6) }, /* Central Standard */ 621 { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ 622 { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ 623 { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ 624 { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ 625 { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ 626 { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ 627 { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ 628 { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ 629 { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ 630 { "cat", tZONE, HOUR(10) }, /* Central Alaska */ 631 { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ 632 { "nt", tZONE, HOUR(11) }, /* Nome */ 633 { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ 634 { "cet", tZONE, -HOUR( 1) }, /* Central European */ 635 { "cest", tDAYZONE, -HOUR( 1) }, /* Central European Summer */ 636 { "met", tZONE, -HOUR( 1) }, /* Middle European */ 637 { "mewt", tZONE, -HOUR( 1) }, /* Middle European Winter */ 638 { "mest", tDAYZONE, -HOUR( 1) }, /* Middle European Summer */ 639 { "swt", tZONE, -HOUR( 1) }, /* Swedish Winter */ 640 { "sst", tDAYZONE, -HOUR( 1) }, /* Swedish Summer */ 641 { "fwt", tZONE, -HOUR( 1) }, /* French Winter */ 642 { "fst", tDAYZONE, -HOUR( 1) }, /* French Summer */ 643 { "eet", tZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 */ 644 { "bt", tZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 */ 645 { "it", tZONE, -HOUR( 7/2) }, /* Iran */ 646 { "zp4", tZONE, -HOUR( 4) }, /* USSR Zone 3 */ 647 { "zp5", tZONE, -HOUR( 5) }, /* USSR Zone 4 */ 648 { "ist", tZONE, -HOUR(11/2) }, /* Indian Standard */ 649 { "zp6", tZONE, -HOUR( 6) }, /* USSR Zone 5 */ 650#if 0 651 /* For completeness. NST is also Newfoundland Stanard, nad SST is 652 * also Swedish Summer. */ 653 { "nst", tZONE, -HOUR(13/2) }, /* North Sumatra */ 654 { "sst", tZONE, -HOUR( 7) }, /* South Sumatra, USSR Zone 6 */ 655#endif /* 0 */ 656 { "wast", tZONE, -HOUR( 7) }, /* West Australian Standard */ 657 { "wadt", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */ 658 { "jt", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */ 659 { "cct", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */ 660 { "jst", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */ 661 { "jdt", tDAYZONE, -HOUR( 9) }, /* Japan Daylight */ 662 { "kst", tZONE, -HOUR( 9) }, /* Korea Standard */ 663 { "kdt", tDAYZONE, -HOUR( 9) }, /* Korea Daylight */ 664 { "cast", tZONE, -HOUR(19/2) }, /* Central Australian Standard */ 665 { "cadt", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */ 666 { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ 667 { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ 668 { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ 669 { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ 670 { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ 671 { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ 672 { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ 673 /* ADDED BY Marco Nijdam */ 674 { "dst", tDST, HOUR( 0) }, /* DST on (hour is ignored) */ 675 /* End ADDED */ 676 { NULL } 677}; 678 679/* 680 * Military timezone table. 681 */ 682 683static TABLE MilitaryTable[] = { 684 { "a", tZONE, -HOUR( 1) }, 685 { "b", tZONE, -HOUR( 2) }, 686 { "c", tZONE, -HOUR( 3) }, 687 { "d", tZONE, -HOUR( 4) }, 688 { "e", tZONE, -HOUR( 5) }, 689 { "f", tZONE, -HOUR( 6) }, 690 { "g", tZONE, -HOUR( 7) }, 691 { "h", tZONE, -HOUR( 8) }, 692 { "i", tZONE, -HOUR( 9) }, 693 { "k", tZONE, -HOUR(10) }, 694 { "l", tZONE, -HOUR(11) }, 695 { "m", tZONE, -HOUR(12) }, 696 { "n", tZONE, HOUR( 1) }, 697 { "o", tZONE, HOUR( 2) }, 698 { "p", tZONE, HOUR( 3) }, 699 { "q", tZONE, HOUR( 4) }, 700 { "r", tZONE, HOUR( 5) }, 701 { "s", tZONE, HOUR( 6) }, 702 { "t", tZONE, HOUR( 7) }, 703 { "u", tZONE, HOUR( 8) }, 704 { "v", tZONE, HOUR( 9) }, 705 { "w", tZONE, HOUR( 10) }, 706 { "x", tZONE, HOUR( 11) }, 707 { "y", tZONE, HOUR( 12) }, 708 { "z", tZONE, HOUR( 0) }, 709 { NULL } 710}; 711 712/* 713 * Dump error messages in the bit bucket. 714 */ 715 716static void 717TclDateerror( 718 YYLTYPE* location, 719 DateInfo* infoPtr, 720 const char *s) 721{ 722 Tcl_Obj* t; 723 Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1); 724 Tcl_AppendToObj(infoPtr->messages, s, -1); 725 Tcl_AppendToObj(infoPtr->messages, " (characters ", -1); 726 t = Tcl_NewIntObj(location->first_column); 727 Tcl_IncrRefCount(t); 728 Tcl_AppendObjToObj(infoPtr->messages, t); 729 Tcl_DecrRefCount(t); 730 Tcl_AppendToObj(infoPtr->messages, "-", -1); 731 t = Tcl_NewIntObj(location->last_column); 732 Tcl_IncrRefCount(t); 733 Tcl_AppendObjToObj(infoPtr->messages, t); 734 Tcl_DecrRefCount(t); 735 Tcl_AppendToObj(infoPtr->messages, ")", -1); 736 infoPtr->separatrix = "\n"; 737} 738 739static time_t 740ToSeconds( 741 time_t Hours, 742 time_t Minutes, 743 time_t Seconds, 744 MERIDIAN Meridian) 745{ 746 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) { 747 return -1; 748 } 749 switch (Meridian) { 750 case MER24: 751 if (Hours < 0 || Hours > 23) { 752 return -1; 753 } 754 return (Hours * 60L + Minutes) * 60L + Seconds; 755 case MERam: 756 if (Hours < 1 || Hours > 12) { 757 return -1; 758 } 759 return ((Hours % 12) * 60L + Minutes) * 60L + Seconds; 760 case MERpm: 761 if (Hours < 1 || Hours > 12) { 762 return -1; 763 } 764 return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds; 765 } 766 return -1; /* Should never be reached */ 767} 768 769static int 770LookupWord( 771 YYSTYPE* yylvalPtr, 772 char *buff) 773{ 774 register char *p; 775 register char *q; 776 register TABLE *tp; 777 int i, abbrev; 778 779 /* 780 * Make it lowercase. 781 */ 782 783 Tcl_UtfToLower(buff); 784 785 if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { 786 yylvalPtr->Meridian = MERam; 787 return tMERIDIAN; 788 } 789 if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { 790 yylvalPtr->Meridian = MERpm; 791 return tMERIDIAN; 792 } 793 794 /* 795 * See if we have an abbreviation for a month. 796 */ 797 798 if (strlen(buff) == 3) { 799 abbrev = 1; 800 } else if (strlen(buff) == 4 && buff[3] == '.') { 801 abbrev = 1; 802 buff[3] = '\0'; 803 } else { 804 abbrev = 0; 805 } 806 807 for (tp = MonthDayTable; tp->name; tp++) { 808 if (abbrev) { 809 if (strncmp(buff, tp->name, 3) == 0) { 810 yylvalPtr->Number = tp->value; 811 return tp->type; 812 } 813 } else if (strcmp(buff, tp->name) == 0) { 814 yylvalPtr->Number = tp->value; 815 return tp->type; 816 } 817 } 818 819 for (tp = TimezoneTable; tp->name; tp++) { 820 if (strcmp(buff, tp->name) == 0) { 821 yylvalPtr->Number = tp->value; 822 return tp->type; 823 } 824 } 825 826 for (tp = UnitsTable; tp->name; tp++) { 827 if (strcmp(buff, tp->name) == 0) { 828 yylvalPtr->Number = tp->value; 829 return tp->type; 830 } 831 } 832 833 /* 834 * Strip off any plural and try the units table again. 835 */ 836 837 i = strlen(buff) - 1; 838 if (i > 0 && buff[i] == 's') { 839 buff[i] = '\0'; 840 for (tp = UnitsTable; tp->name; tp++) { 841 if (strcmp(buff, tp->name) == 0) { 842 yylvalPtr->Number = tp->value; 843 return tp->type; 844 } 845 } 846 } 847 848 for (tp = OtherTable; tp->name; tp++) { 849 if (strcmp(buff, tp->name) == 0) { 850 yylvalPtr->Number = tp->value; 851 return tp->type; 852 } 853 } 854 855 /* 856 * Military timezones. 857 */ 858 859 if (buff[1] == '\0' && !(*buff & 0x80) 860 && isalpha(UCHAR(*buff))) { /* INTL: ISO only */ 861 for (tp = MilitaryTable; tp->name; tp++) { 862 if (strcmp(buff, tp->name) == 0) { 863 yylvalPtr->Number = tp->value; 864 return tp->type; 865 } 866 } 867 } 868 869 /* 870 * Drop out any periods and try the timezone table again. 871 */ 872 873 for (i = 0, p = q = buff; *q; q++) { 874 if (*q != '.') { 875 *p++ = *q; 876 } else { 877 i++; 878 } 879 } 880 *p = '\0'; 881 if (i) { 882 for (tp = TimezoneTable; tp->name; tp++) { 883 if (strcmp(buff, tp->name) == 0) { 884 yylvalPtr->Number = tp->value; 885 return tp->type; 886 } 887 } 888 } 889 890 return tID; 891} 892 893static int 894TclDatelex( 895 YYSTYPE* yylvalPtr, 896 YYLTYPE* location, 897 DateInfo *info) 898{ 899 register char c; 900 register char *p; 901 char buff[20]; 902 int Count; 903 904 location->first_column = yyInput - info->dateStart; 905 for ( ; ; ) { 906 while (isspace(UCHAR(*yyInput))) { 907 yyInput++; 908 } 909 910 if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */ 911 /* 912 * Convert the string into a number; count the number of digits. 913 */ 914 915 Count = 0; 916 for (yylvalPtr->Number = 0; 917 isdigit(UCHAR(c = *yyInput++)); ) { /* INTL: digit */ 918 yylvalPtr->Number = 10 * yylvalPtr->Number + c - '0'; 919 Count++; 920 } 921 yyInput--; 922 yyDigitCount = Count; 923 924 /* 925 * A number with 6 or more digits is considered an ISO 8601 base. 926 */ 927 928 if (Count >= 6) { 929 location->last_column = yyInput - info->dateStart - 1; 930 return tISOBASE; 931 } else { 932 location->last_column = yyInput - info->dateStart - 1; 933 return tUNUMBER; 934 } 935 } 936 if (!(c & 0x80) && isalpha(UCHAR(c))) { /* INTL: ISO only. */ 937 for (p = buff; isalpha(UCHAR(c = *yyInput++)) /* INTL: ISO only. */ 938 || c == '.'; ) { 939 if (p < &buff[sizeof buff - 1]) { 940 *p++ = c; 941 } 942 } 943 *p = '\0'; 944 yyInput--; 945 location->last_column = yyInput - info->dateStart - 1; 946 return LookupWord(yylvalPtr, buff); 947 } 948 if (c != '(') { 949 location->last_column = yyInput - info->dateStart; 950 return *yyInput++; 951 } 952 Count = 0; 953 do { 954 c = *yyInput++; 955 if (c == '\0') { 956 location->last_column = yyInput - info->dateStart - 1; 957 return c; 958 } else if (c == '(') { 959 Count++; 960 } else if (c == ')') { 961 Count--; 962 } 963 } while (Count > 0); 964 } 965} 966 967int 968TclClockOldscanObjCmd( 969 ClientData clientData, /* Unused */ 970 Tcl_Interp *interp, /* Tcl interpreter */ 971 int objc, /* Count of paraneters */ 972 Tcl_Obj *CONST *objv) /* Parameters */ 973{ 974 Tcl_Obj *result, *resultElement; 975 int yr, mo, da; 976 DateInfo dateInfo; 977 DateInfo* info = &dateInfo; 978 int status; 979 980 if (objc != 5) { 981 Tcl_WrongNumArgs(interp, 1, objv, 982 "stringToParse baseYear baseMonth baseDay" ); 983 return TCL_ERROR; 984 } 985 986 yyInput = Tcl_GetString( objv[1] ); 987 dateInfo.dateStart = yyInput; 988 989 yyHaveDate = 0; 990 if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK 991 || Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK 992 || Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) { 993 return TCL_ERROR; 994 } 995 yyYear = yr; yyMonth = mo; yyDay = da; 996 997 yyHaveTime = 0; 998 yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; 999 1000 yyHaveZone = 0; 1001 yyTimezone = 0; yyDSTmode = DSTmaybe; 1002 1003 yyHaveOrdinalMonth = 0; 1004 yyMonthOrdinal = 0; 1005 1006 yyHaveDay = 0; 1007 yyDayOrdinal = 0; yyDayNumber = 0; 1008 1009 yyHaveRel = 0; 1010 yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL; 1011 1012 dateInfo.messages = Tcl_NewObj(); 1013 dateInfo.separatrix = ""; 1014 Tcl_IncrRefCount(dateInfo.messages); 1015 1016 status = yyparse(&dateInfo); 1017 if (status == 1) { 1018 Tcl_SetObjResult(interp, dateInfo.messages); 1019 Tcl_DecrRefCount(dateInfo.messages); 1020 return TCL_ERROR; 1021 } else if (status == 2) { 1022 Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); 1023 Tcl_DecrRefCount(dateInfo.messages); 1024 return TCL_ERROR; 1025 } else if (status != 0) { 1026 Tcl_SetObjResult(interp, Tcl_NewStringObj("Unknown status returned " 1027 "from date parser. Please " 1028 "report this error as a " 1029 "bug in Tcl.", -1)); 1030 Tcl_DecrRefCount(dateInfo.messages); 1031 return TCL_ERROR; 1032 } 1033 Tcl_DecrRefCount(dateInfo.messages); 1034 1035 if (yyHaveDate > 1) { 1036 Tcl_SetObjResult(interp, 1037 Tcl_NewStringObj("more than one date in string", -1)); 1038 return TCL_ERROR; 1039 } 1040 if (yyHaveTime > 1) { 1041 Tcl_SetObjResult(interp, 1042 Tcl_NewStringObj("more than one time of day in string", -1)); 1043 return TCL_ERROR; 1044 } 1045 if (yyHaveZone > 1) { 1046 Tcl_SetObjResult(interp, 1047 Tcl_NewStringObj("more than one time zone in string", -1)); 1048 return TCL_ERROR; 1049 } 1050 if (yyHaveDay > 1) { 1051 Tcl_SetObjResult(interp, 1052 Tcl_NewStringObj("more than one weekday in string", -1)); 1053 return TCL_ERROR; 1054 } 1055 if (yyHaveOrdinalMonth > 1) { 1056 Tcl_SetObjResult(interp, 1057 Tcl_NewStringObj("more than one ordinal month in string", -1)); 1058 return TCL_ERROR; 1059 } 1060 1061 result = Tcl_NewObj(); 1062 resultElement = Tcl_NewObj(); 1063 if (yyHaveDate) { 1064 Tcl_ListObjAppendElement(interp, resultElement, 1065 Tcl_NewIntObj((int) yyYear)); 1066 Tcl_ListObjAppendElement(interp, resultElement, 1067 Tcl_NewIntObj((int) yyMonth)); 1068 Tcl_ListObjAppendElement(interp, resultElement, 1069 Tcl_NewIntObj((int) yyDay)); 1070 } 1071 Tcl_ListObjAppendElement(interp, result, resultElement); 1072 1073 if (yyHaveTime) { 1074 Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj((int) 1075 ToSeconds(yyHour, yyMinutes, yySeconds, yyMeridian))); 1076 } else { 1077 Tcl_ListObjAppendElement(interp, result, Tcl_NewObj()); 1078 } 1079 1080 resultElement = Tcl_NewObj(); 1081 if (yyHaveZone) { 1082 Tcl_ListObjAppendElement(interp, resultElement, 1083 Tcl_NewIntObj((int) -yyTimezone)); 1084 Tcl_ListObjAppendElement(interp, resultElement, 1085 Tcl_NewIntObj(1 - yyDSTmode)); 1086 } 1087 Tcl_ListObjAppendElement(interp, result, resultElement); 1088 1089 resultElement = Tcl_NewObj(); 1090 if (yyHaveRel) { 1091 Tcl_ListObjAppendElement(interp, resultElement, 1092 Tcl_NewIntObj((int) yyRelMonth)); 1093 Tcl_ListObjAppendElement(interp, resultElement, 1094 Tcl_NewIntObj((int) yyRelDay)); 1095 Tcl_ListObjAppendElement(interp, resultElement, 1096 Tcl_NewIntObj((int) yyRelSeconds)); 1097 } 1098 Tcl_ListObjAppendElement(interp, result, resultElement); 1099 1100 resultElement = Tcl_NewObj(); 1101 if (yyHaveDay && !yyHaveDate) { 1102 Tcl_ListObjAppendElement(interp, resultElement, 1103 Tcl_NewIntObj((int) yyDayOrdinal)); 1104 Tcl_ListObjAppendElement(interp, resultElement, 1105 Tcl_NewIntObj((int) yyDayNumber)); 1106 } 1107 Tcl_ListObjAppendElement(interp, result, resultElement); 1108 1109 resultElement = Tcl_NewObj(); 1110 if (yyHaveOrdinalMonth) { 1111 Tcl_ListObjAppendElement(interp, resultElement, 1112 Tcl_NewIntObj((int) yyMonthOrdinal)); 1113 Tcl_ListObjAppendElement(interp, resultElement, 1114 Tcl_NewIntObj((int) yyMonth)); 1115 } 1116 Tcl_ListObjAppendElement(interp, result, resultElement); 1117 1118 Tcl_SetObjResult(interp, result); 1119 return TCL_OK; 1120} 1121 1122/* 1123 * Local Variables: 1124 * mode: c 1125 * c-basic-offset: 4 1126 * fill-column: 78 1127 * End: 1128 */ 1129