zic.c revision 2703
1#ifndef lint 2#ifndef NOID 3static char elsieid[] = "@(#)zic.c 7.22"; 4#endif /* !defined NOID */ 5#endif /* !defined lint */ 6 7#include "private.h" 8#include "tzfile.h" 9 10struct rule { 11 const char * r_filename; 12 int r_linenum; 13 const char * r_name; 14 15 int r_loyear; /* for example, 1986 */ 16 int r_hiyear; /* for example, 1986 */ 17 const char * r_yrtype; 18 19 int r_month; /* 0..11 */ 20 21 int r_dycode; /* see below */ 22 int r_dayofmonth; 23 int r_wday; 24 25 long r_tod; /* time from midnight */ 26 int r_todisstd; /* above is standard time if TRUE */ 27 /* or wall clock time if FALSE */ 28 long r_stdoff; /* offset from standard time */ 29 const char * r_abbrvar; /* variable part of abbreviation */ 30 31 int r_todo; /* a rule to do (used in outzone) */ 32 time_t r_temp; /* used in outzone */ 33}; 34 35/* 36** r_dycode r_dayofmonth r_wday 37*/ 38 39#define DC_DOM 0 /* 1..31 */ /* unused */ 40#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 41#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 42 43struct zone { 44 const char * z_filename; 45 int z_linenum; 46 47 const char * z_name; 48 long z_gmtoff; 49 const char * z_rule; 50 const char * z_format; 51 52 long z_stdoff; 53 54 struct rule * z_rules; 55 int z_nrules; 56 57 struct rule z_untilrule; 58 time_t z_untiltime; 59}; 60 61extern int emkdir P((const char * name, int mode)); 62extern int getopt P((int argc, char * argv[], const char * options)); 63extern char * icatalloc P((char * old, const char * new)); 64extern char * icpyalloc P((const char * string)); 65extern void ifree P((char * p)); 66extern char * imalloc P((int n)); 67extern char * irealloc P((char * old, int n)); 68extern int link P((const char * fromname, const char * toname)); 69extern char * optarg; 70extern int optind; 71extern char * scheck P((const char * string, const char * format)); 72 73static void addtt P((time_t starttime, int type)); 74static int addtype P((long gmtoff, const char * abbr, int isdst, 75 int ttisstd)); 76static void leapadd P((time_t t, int positive, int rolling, int count)); 77static void adjleap P((void)); 78static void associate P((void)); 79static int ciequal P((const char * ap, const char * bp)); 80static void convert P((long val, char * buf)); 81static void dolink P((const char * fromfile, const char * tofile)); 82static void eat P((const char * name, int num)); 83static void eats P((const char * name, int num, 84 const char * rname, int rnum)); 85static long eitol P((int i)); 86static void error P((const char * message)); 87static char ** getfields P((char * buf)); 88static long gethms P((const char * string, const char * errstrng, 89 int signable)); 90static void infile P((const char * filename)); 91static void inleap P((char ** fields, int nfields)); 92static void inlink P((char ** fields, int nfields)); 93static void inrule P((char ** fields, int nfields)); 94static int inzcont P((char ** fields, int nfields)); 95static int inzone P((char ** fields, int nfields)); 96static int inzsub P((char ** fields, int nfields, int iscont)); 97static int itsabbr P((const char * abbr, const char * word)); 98static int itsdir P((const char * name)); 99static int lowerit P((int c)); 100static char * memcheck P((char * tocheck)); 101static int mkdirs P((char * filename)); 102static void newabbr P((const char * abbr)); 103static long oadd P((long t1, long t2)); 104static void outzone P((const struct zone * zp, int ntzones)); 105static void puttzcode P((long code, FILE * fp)); 106static int rcomp P((const genericptr_t leftp, const genericptr_t rightp)); 107static time_t rpytime P((const struct rule * rp, int wantedy)); 108static void rulesub P((struct rule * rp, 109 char * loyearp, char * hiyearp, 110 char * typep, char * monthp, 111 char * dayp, char * timep)); 112static void setboundaries P((void)); 113static time_t tadd P((time_t t1, long t2)); 114static void usage P((void)); 115static void writezone P((const char * name)); 116static int yearistype P((int year, const char * type)); 117 118static int charcnt; 119static int errors; 120static const char * filename; 121static int leapcnt; 122static int linenum; 123static int max_int; 124static time_t max_time; 125static int max_year; 126static int min_int; 127static time_t min_time; 128static int min_year; 129static int noise; 130static const char * rfilename; 131static int rlinenum; 132static const char * progname; 133static int timecnt; 134static int typecnt; 135static int tt_signed; 136 137/* 138** Line codes. 139*/ 140 141#define LC_RULE 0 142#define LC_ZONE 1 143#define LC_LINK 2 144#define LC_LEAP 3 145 146/* 147** Which fields are which on a Zone line. 148*/ 149 150#define ZF_NAME 1 151#define ZF_GMTOFF 2 152#define ZF_RULE 3 153#define ZF_FORMAT 4 154#define ZF_TILYEAR 5 155#define ZF_TILMONTH 6 156#define ZF_TILDAY 7 157#define ZF_TILTIME 8 158#define ZONE_MINFIELDS 5 159#define ZONE_MAXFIELDS 9 160 161/* 162** Which fields are which on a Zone continuation line. 163*/ 164 165#define ZFC_GMTOFF 0 166#define ZFC_RULE 1 167#define ZFC_FORMAT 2 168#define ZFC_TILYEAR 3 169#define ZFC_TILMONTH 4 170#define ZFC_TILDAY 5 171#define ZFC_TILTIME 6 172#define ZONEC_MINFIELDS 3 173#define ZONEC_MAXFIELDS 7 174 175/* 176** Which files are which on a Rule line. 177*/ 178 179#define RF_NAME 1 180#define RF_LOYEAR 2 181#define RF_HIYEAR 3 182#define RF_COMMAND 4 183#define RF_MONTH 5 184#define RF_DAY 6 185#define RF_TOD 7 186#define RF_STDOFF 8 187#define RF_ABBRVAR 9 188#define RULE_FIELDS 10 189 190/* 191** Which fields are which on a Link line. 192*/ 193 194#define LF_FROM 1 195#define LF_TO 2 196#define LINK_FIELDS 3 197 198/* 199** Which fields are which on a Leap line. 200*/ 201 202#define LP_YEAR 1 203#define LP_MONTH 2 204#define LP_DAY 3 205#define LP_TIME 4 206#define LP_CORR 5 207#define LP_ROLL 6 208#define LEAP_FIELDS 7 209 210/* 211** Year synonyms. 212*/ 213 214#define YR_MINIMUM 0 215#define YR_MAXIMUM 1 216#define YR_ONLY 2 217 218static struct rule * rules; 219static int nrules; /* number of rules */ 220 221static struct zone * zones; 222static int nzones; /* number of zones */ 223 224struct link { 225 const char * l_filename; 226 int l_linenum; 227 const char * l_from; 228 const char * l_to; 229}; 230 231static struct link * links; 232static int nlinks; 233 234struct lookup { 235 const char * l_word; 236 const int l_value; 237}; 238 239static struct lookup const * byword P((const char * string, 240 const struct lookup * lp)); 241 242static struct lookup const line_codes[] = { 243 { "Rule", LC_RULE }, 244 { "Zone", LC_ZONE }, 245 { "Link", LC_LINK }, 246 { "Leap", LC_LEAP }, 247 { NULL, 0} 248}; 249 250static struct lookup const mon_names[] = { 251 { "January", TM_JANUARY }, 252 { "February", TM_FEBRUARY }, 253 { "March", TM_MARCH }, 254 { "April", TM_APRIL }, 255 { "May", TM_MAY }, 256 { "June", TM_JUNE }, 257 { "July", TM_JULY }, 258 { "August", TM_AUGUST }, 259 { "September", TM_SEPTEMBER }, 260 { "October", TM_OCTOBER }, 261 { "November", TM_NOVEMBER }, 262 { "December", TM_DECEMBER }, 263 { NULL, 0 } 264}; 265 266static struct lookup const wday_names[] = { 267 { "Sunday", TM_SUNDAY }, 268 { "Monday", TM_MONDAY }, 269 { "Tuesday", TM_TUESDAY }, 270 { "Wednesday", TM_WEDNESDAY }, 271 { "Thursday", TM_THURSDAY }, 272 { "Friday", TM_FRIDAY }, 273 { "Saturday", TM_SATURDAY }, 274 { NULL, 0 } 275}; 276 277static struct lookup const lasts[] = { 278 { "last-Sunday", TM_SUNDAY }, 279 { "last-Monday", TM_MONDAY }, 280 { "last-Tuesday", TM_TUESDAY }, 281 { "last-Wednesday", TM_WEDNESDAY }, 282 { "last-Thursday", TM_THURSDAY }, 283 { "last-Friday", TM_FRIDAY }, 284 { "last-Saturday", TM_SATURDAY }, 285 { NULL, 0 } 286}; 287 288static struct lookup const begin_years[] = { 289 { "minimum", YR_MINIMUM }, 290 { "maximum", YR_MAXIMUM }, 291 { NULL, 0 } 292}; 293 294static struct lookup const end_years[] = { 295 { "minimum", YR_MINIMUM }, 296 { "maximum", YR_MAXIMUM }, 297 { "only", YR_ONLY }, 298 { NULL, 0 } 299}; 300 301static struct lookup const leap_types[] = { 302 { "Rolling", TRUE }, 303 { "Stationary", FALSE }, 304 { NULL, 0 } 305}; 306 307static const int len_months[2][MONSPERYEAR] = { 308 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 309 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 310}; 311 312static const int len_years[2] = { 313 DAYSPERNYEAR, DAYSPERLYEAR 314}; 315 316static time_t ats[TZ_MAX_TIMES]; 317static unsigned char types[TZ_MAX_TIMES]; 318static long gmtoffs[TZ_MAX_TYPES]; 319static char isdsts[TZ_MAX_TYPES]; 320static unsigned char abbrinds[TZ_MAX_TYPES]; 321static char ttisstds[TZ_MAX_TYPES]; 322static char chars[TZ_MAX_CHARS]; 323static time_t trans[TZ_MAX_LEAPS]; 324static long corr[TZ_MAX_LEAPS]; 325static char roll[TZ_MAX_LEAPS]; 326 327/* 328** Memory allocation. 329*/ 330 331static char * 332memcheck(ptr) 333char * const ptr; 334{ 335 if (ptr == NULL) { 336 (void) perror(progname); 337 (void) exit(EXIT_FAILURE); 338 } 339 return ptr; 340} 341 342#define emalloc(size) memcheck(imalloc(size)) 343#define erealloc(ptr, size) memcheck(irealloc(ptr, size)) 344#define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 345#define ecatalloc(oldp, newp) memcheck(icatalloc(oldp, newp)) 346 347/* 348** Error handling. 349*/ 350 351static void 352eats(name, num, rname, rnum) 353const char * const name; 354const int num; 355const char * const rname; 356const int rnum; 357{ 358 filename = name; 359 linenum = num; 360 rfilename = rname; 361 rlinenum = rnum; 362} 363 364static void 365eat(name, num) 366const char * const name; 367const int num; 368{ 369 eats(name, num, (char *) NULL, -1); 370} 371 372static void 373error(string) 374const char * const string; 375{ 376 /* 377 ** Match the format of "cc" to allow sh users to 378 ** zic ... 2>&1 | error -t "*" -v 379 ** on BSD systems. 380 */ 381 (void) fprintf(stderr, "\"%s\", line %d: %s", 382 filename, linenum, string); 383 if (rfilename != NULL) 384 (void) fprintf(stderr, " (rule from \"%s\", line %d)", 385 rfilename, rlinenum); 386 (void) fprintf(stderr, "\n"); 387 ++errors; 388} 389 390static void 391usage() 392{ 393 (void) fprintf(stderr, 394"%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ] \n\ 395\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n", 396 progname, progname); 397 (void) exit(EXIT_FAILURE); 398} 399 400static const char * psxrules; 401static const char * lcltime; 402static const char * directory; 403static const char * leapsec; 404static const char * yitcommand; 405static int sflag = FALSE; 406 407int 408main(argc, argv) 409int argc; 410char * argv[]; 411{ 412 register int i, j; 413 register int c; 414 415#ifdef unix 416 (void) umask(umask(022) | 022); 417#endif /* defined unix */ 418 progname = argv[0]; 419 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF) 420 switch (c) { 421 default: 422 usage(); 423 case 'd': 424 if (directory == NULL) 425 directory = optarg; 426 else { 427 (void) fprintf(stderr, 428"%s: More than one -d option specified\n", 429 progname); 430 (void) exit(EXIT_FAILURE); 431 } 432 break; 433 case 'l': 434 if (lcltime == NULL) 435 lcltime = optarg; 436 else { 437 (void) fprintf(stderr, 438"%s: More than one -l option specified\n", 439 progname); 440 (void) exit(EXIT_FAILURE); 441 } 442 break; 443 case 'p': 444 if (psxrules == NULL) 445 psxrules = optarg; 446 else { 447 (void) fprintf(stderr, 448"%s: More than one -p option specified\n", 449 progname); 450 (void) exit(EXIT_FAILURE); 451 } 452 break; 453 case 'y': 454 if (yitcommand == NULL) 455 yitcommand = optarg; 456 else { 457 (void) fprintf(stderr, 458"%s: More than one -y option specified\n", 459 progname); 460 (void) exit(EXIT_FAILURE); 461 } 462 break; 463 case 'L': 464 if (leapsec == NULL) 465 leapsec = optarg; 466 else { 467 (void) fprintf(stderr, 468"%s: More than one -L option specified\n", 469 progname); 470 (void) exit(EXIT_FAILURE); 471 } 472 break; 473 case 'v': 474 noise = TRUE; 475 break; 476 case 's': 477 sflag = TRUE; 478 break; 479 } 480 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 481 usage(); /* usage message by request */ 482 if (directory == NULL) 483 directory = TZDIR; 484 if (yitcommand == NULL) 485 yitcommand = "yearistype"; 486 487 setboundaries(); 488 489 if (optind < argc && leapsec != NULL) { 490 infile(leapsec); 491 adjleap(); 492 } 493 494 zones = (struct zone *) emalloc(0); 495 rules = (struct rule *) emalloc(0); 496 links = (struct link *) emalloc(0); 497 for (i = optind; i < argc; ++i) 498 infile(argv[i]); 499 if (errors) 500 (void) exit(EXIT_FAILURE); 501 associate(); 502 for (i = 0; i < nzones; i = j) { 503 /* 504 ** Find the next non-continuation zone entry. 505 */ 506 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 507 continue; 508 outzone(&zones[i], j - i); 509 } 510 /* 511 ** Make links. 512 */ 513 for (i = 0; i < nlinks; ++i) 514 dolink(links[i].l_from, links[i].l_to); 515 if (lcltime != NULL) 516 dolink(lcltime, TZDEFAULT); 517 if (psxrules != NULL) 518 dolink(psxrules, TZDEFRULES); 519 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 520} 521 522static void 523dolink(fromfile, tofile) 524const char * const fromfile; 525const char * const tofile; 526{ 527 register char * fromname; 528 register char * toname; 529 530 if (fromfile[0] == '/') 531 fromname = fromfile; 532 else { 533 fromname = ecpyalloc(directory); 534 fromname = ecatalloc(fromname, "/"); 535 fromname = ecatalloc(fromname, fromfile); 536 } 537 if (tofile[0] == '/') 538 toname = tofile; 539 else { 540 toname = ecpyalloc(directory); 541 toname = ecatalloc(toname, "/"); 542 toname = ecatalloc(toname, tofile); 543 } 544 /* 545 ** We get to be careful here since 546 ** there's a fair chance of root running us. 547 */ 548 if (!itsdir(toname)) 549 (void) remove(toname); 550 if (link(fromname, toname) != 0) { 551 if (mkdirs(toname) != 0) 552 (void) exit(EXIT_FAILURE); 553 if (link(fromname, toname) != 0) { 554 (void) fprintf(stderr, "%s: Can't link from %s to ", 555 progname, fromname); 556 (void) perror(toname); 557 (void) exit(EXIT_FAILURE); 558 } 559 } 560 if (fromname != fromfile) 561 ifree(fromname); 562 if (toname != tofile) 563 ifree(toname); 564} 565 566static void 567setboundaries() 568{ 569 register time_t bit; 570 register int bii; 571 572 for (bit = 1; bit > 0; bit <<= 1) 573 continue; 574 if (bit == 0) { /* time_t is an unsigned type */ 575 tt_signed = FALSE; 576 min_time = 0; 577 max_time = ~(time_t) 0; 578 if (sflag) 579 max_time >>= 1; 580 } else { 581 tt_signed = TRUE; 582 min_time = bit; 583 max_time = bit; 584 ++max_time; 585 max_time = -max_time; 586 if (sflag) 587 min_time = 0; 588 } 589 min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; 590 max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; 591 592 for (bii = 1; bii > 0; bii <<= 1) 593 continue; 594 min_int = bii; 595 max_int = -1 - bii; 596} 597 598static int 599itsdir(name) 600const char * const name; 601{ 602 register char * myname; 603 register int accres; 604 605 myname = ecpyalloc(name); 606 myname = ecatalloc(myname, "/."); 607 accres = access(myname, 0); 608 ifree(myname); 609 return accres == 0; 610} 611 612/* 613** Associate sets of rules with zones. 614*/ 615 616/* 617** Sort by rule name. 618*/ 619 620static int 621rcomp(cp1, cp2) 622const genericptr_t cp1; 623const genericptr_t cp2; 624{ 625 return strcmp(((struct rule *) cp1)->r_name, 626 ((struct rule *) cp2)->r_name); 627} 628 629static void 630associate() 631{ 632 register struct zone * zp; 633 register struct rule * rp; 634 register int base, out; 635 register int i; 636 637 if (nrules != 0) 638 (void) qsort((genericptr_t) rules, 639 (qsort_size_t) nrules, 640 (qsort_size_t) sizeof *rules, rcomp); 641 for (i = 0; i < nzones; ++i) { 642 zp = &zones[i]; 643 zp->z_rules = NULL; 644 zp->z_nrules = 0; 645 } 646 for (base = 0; base < nrules; base = out) { 647 rp = &rules[base]; 648 for (out = base + 1; out < nrules; ++out) 649 if (strcmp(rp->r_name, rules[out].r_name) != 0) 650 break; 651 for (i = 0; i < nzones; ++i) { 652 zp = &zones[i]; 653 if (strcmp(zp->z_rule, rp->r_name) != 0) 654 continue; 655 zp->z_rules = rp; 656 zp->z_nrules = out - base; 657 } 658 } 659 for (i = 0; i < nzones; ++i) { 660 zp = &zones[i]; 661 if (zp->z_nrules == 0) { 662 /* 663 ** Maybe we have a local standard time offset. 664 */ 665 eat(zp->z_filename, zp->z_linenum); 666 zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE); 667 /* 668 ** Note, though, that if there's no rule, 669 ** a '%s' in the format is a bad thing. 670 */ 671 if (strchr(zp->z_format, '%') != 0) 672 error("%s in ruleless zone"); 673 } 674 } 675 if (errors) 676 (void) exit(EXIT_FAILURE); 677} 678 679static void 680infile(name) 681const char * name; 682{ 683 register FILE * fp; 684 register char ** fields; 685 register char * cp; 686 register const struct lookup * lp; 687 register int nfields; 688 register int wantcont; 689 register int num; 690 char buf[BUFSIZ]; 691 692 if (strcmp(name, "-") == 0) { 693 name = "standard input"; 694 fp = stdin; 695 } else if ((fp = fopen(name, "r")) == NULL) { 696 (void) fprintf(stderr, "%s: Can't open ", progname); 697 (void) perror(name); 698 (void) exit(EXIT_FAILURE); 699 } 700 wantcont = FALSE; 701 for (num = 1; ; ++num) { 702 eat(name, num); 703 if (fgets(buf, (int) sizeof buf, fp) != buf) 704 break; 705 cp = strchr(buf, '\n'); 706 if (cp == NULL) { 707 error("line too long"); 708 (void) exit(EXIT_FAILURE); 709 } 710 *cp = '\0'; 711 fields = getfields(buf); 712 nfields = 0; 713 while (fields[nfields] != NULL) { 714 static char nada[1]; 715 716 if (ciequal(fields[nfields], "-")) 717 fields[nfields] = nada; 718 ++nfields; 719 } 720 if (nfields == 0) { 721 /* nothing to do */ 722 } else if (wantcont) { 723 wantcont = inzcont(fields, nfields); 724 } else { 725 lp = byword(fields[0], line_codes); 726 if (lp == NULL) 727 error("input line of unknown type"); 728 else switch ((int) (lp->l_value)) { 729 case LC_RULE: 730 inrule(fields, nfields); 731 wantcont = FALSE; 732 break; 733 case LC_ZONE: 734 wantcont = inzone(fields, nfields); 735 break; 736 case LC_LINK: 737 inlink(fields, nfields); 738 wantcont = FALSE; 739 break; 740 case LC_LEAP: 741 if (name != leapsec) 742 (void) fprintf(stderr, 743"%s: Leap line in non leap seconds file %s\n", 744 progname, name); 745 else inleap(fields, nfields); 746 wantcont = FALSE; 747 break; 748 default: /* "cannot happen" */ 749 (void) fprintf(stderr, 750"%s: panic: Invalid l_value %d\n", 751 progname, lp->l_value); 752 (void) exit(EXIT_FAILURE); 753 } 754 } 755 ifree((char *) fields); 756 } 757 if (ferror(fp)) { 758 (void) fprintf(stderr, "%s: Error reading ", progname); 759 (void) perror(filename); 760 (void) exit(EXIT_FAILURE); 761 } 762 if (fp != stdin && fclose(fp)) { 763 (void) fprintf(stderr, "%s: Error closing ", progname); 764 (void) perror(filename); 765 (void) exit(EXIT_FAILURE); 766 } 767 if (wantcont) 768 error("expected continuation line not found"); 769} 770 771/* 772** Convert a string of one of the forms 773** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 774** into a number of seconds. 775** A null string maps to zero. 776** Call error with errstring and return zero on errors. 777*/ 778 779static long 780gethms(string, errstring, signable) 781const char * string; 782const char * const errstring; 783const int signable; 784{ 785 int hh, mm, ss, sign; 786 787 if (string == NULL || *string == '\0') 788 return 0; 789 if (!signable) 790 sign = 1; 791 else if (*string == '-') { 792 sign = -1; 793 ++string; 794 } else sign = 1; 795 if (sscanf(string, scheck(string, "%d"), &hh) == 1) 796 mm = ss = 0; 797 else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) 798 ss = 0; 799 else if (sscanf(string, scheck(string, "%d:%d:%d"), 800 &hh, &mm, &ss) != 3) { 801 error(errstring); 802 return 0; 803 } 804 if (hh < 0 || hh >= HOURSPERDAY || 805 mm < 0 || mm >= MINSPERHOUR || 806 ss < 0 || ss > SECSPERMIN) { 807 error(errstring); 808 return 0; 809 } 810 return eitol(sign) * 811 (eitol(hh * MINSPERHOUR + mm) * 812 eitol(SECSPERMIN) + eitol(ss)); 813} 814 815static void 816inrule(fields, nfields) 817register char ** const fields; 818const int nfields; 819{ 820 static struct rule r; 821 822 if (nfields != RULE_FIELDS) { 823 error("wrong number of fields on Rule line"); 824 return; 825 } 826 if (*fields[RF_NAME] == '\0') { 827 error("nameless rule"); 828 return; 829 } 830 r.r_filename = filename; 831 r.r_linenum = linenum; 832 r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); 833 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 834 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 835 r.r_name = ecpyalloc(fields[RF_NAME]); 836 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 837 rules = (struct rule *) erealloc((char *) rules, 838 (int) ((nrules + 1) * sizeof *rules)); 839 rules[nrules++] = r; 840} 841 842static int 843inzone(fields, nfields) 844register char ** const fields; 845const int nfields; 846{ 847 register int i; 848 static char * buf; 849 850 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 851 error("wrong number of fields on Zone line"); 852 return FALSE; 853 } 854 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 855 buf = erealloc(buf, 132 + strlen(TZDEFAULT)); 856 (void) sprintf(buf, 857"\"Zone %s\" line and -l option are mutually exclusive", 858 TZDEFAULT); 859 error(buf); 860 return FALSE; 861 } 862 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 863 buf = erealloc(buf, 132 + strlen(TZDEFRULES)); 864 (void) sprintf(buf, 865"\"Zone %s\" line and -p option are mutually exclusive", 866 TZDEFRULES); 867 error(buf); 868 return FALSE; 869 } 870 for (i = 0; i < nzones; ++i) 871 if (zones[i].z_name != NULL && 872 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 873 buf = erealloc(buf, 132 + 874 strlen(fields[ZF_NAME]) + 875 strlen(zones[i].z_filename)); 876 (void) sprintf(buf, 877"duplicate zone name %s (file \"%s\", line %d)", 878 fields[ZF_NAME], 879 zones[i].z_filename, 880 zones[i].z_linenum); 881 error(buf); 882 return FALSE; 883 } 884 return inzsub(fields, nfields, FALSE); 885} 886 887static int 888inzcont(fields, nfields) 889register char ** const fields; 890const int nfields; 891{ 892 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 893 error("wrong number of fields on Zone continuation line"); 894 return FALSE; 895 } 896 return inzsub(fields, nfields, TRUE); 897} 898 899static int 900inzsub(fields, nfields, iscont) 901register char ** const fields; 902const int nfields; 903const int iscont; 904{ 905 register char * cp; 906 static struct zone z; 907 register int i_gmtoff, i_rule, i_format; 908 register int i_untilyear, i_untilmonth; 909 register int i_untilday, i_untiltime; 910 register int hasuntil; 911 912 if (iscont) { 913 i_gmtoff = ZFC_GMTOFF; 914 i_rule = ZFC_RULE; 915 i_format = ZFC_FORMAT; 916 i_untilyear = ZFC_TILYEAR; 917 i_untilmonth = ZFC_TILMONTH; 918 i_untilday = ZFC_TILDAY; 919 i_untiltime = ZFC_TILTIME; 920 z.z_name = NULL; 921 } else { 922 i_gmtoff = ZF_GMTOFF; 923 i_rule = ZF_RULE; 924 i_format = ZF_FORMAT; 925 i_untilyear = ZF_TILYEAR; 926 i_untilmonth = ZF_TILMONTH; 927 i_untilday = ZF_TILDAY; 928 i_untiltime = ZF_TILTIME; 929 z.z_name = ecpyalloc(fields[ZF_NAME]); 930 } 931 z.z_filename = filename; 932 z.z_linenum = linenum; 933 z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE); 934 if ((cp = strchr(fields[i_format], '%')) != 0) { 935 if (*++cp != 's' || strchr(cp, '%') != 0) { 936 error("invalid abbreviation format"); 937 return FALSE; 938 } 939 } 940 z.z_rule = ecpyalloc(fields[i_rule]); 941 z.z_format = ecpyalloc(fields[i_format]); 942 hasuntil = nfields > i_untilyear; 943 if (hasuntil) { 944 z.z_untilrule.r_filename = filename; 945 z.z_untilrule.r_linenum = linenum; 946 rulesub(&z.z_untilrule, 947 fields[i_untilyear], 948 "only", 949 "", 950 (nfields > i_untilmonth) ? 951 fields[i_untilmonth] : "Jan", 952 (nfields > i_untilday) ? fields[i_untilday] : "1", 953 (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 954 z.z_untiltime = rpytime(&z.z_untilrule, 955 z.z_untilrule.r_loyear); 956 if (iscont && nzones > 0 && 957 z.z_untiltime > min_time && 958 z.z_untiltime < max_time && 959 zones[nzones - 1].z_untiltime > min_time && 960 zones[nzones - 1].z_untiltime < max_time && 961 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 962error("Zone continuation line end time is not after end time of previous line"); 963 return FALSE; 964 } 965 } 966 zones = (struct zone *) erealloc((char *) zones, 967 (int) ((nzones + 1) * sizeof *zones)); 968 zones[nzones++] = z; 969 /* 970 ** If there was an UNTIL field on this line, 971 ** there's more information about the zone on the next line. 972 */ 973 return hasuntil; 974} 975 976static void 977inleap(fields, nfields) 978register char ** const fields; 979const int nfields; 980{ 981 register const char * cp; 982 register const struct lookup * lp; 983 register int i, j; 984 int year, month, day; 985 long dayoff, tod; 986 time_t t; 987 988 if (nfields != LEAP_FIELDS) { 989 error("wrong number of fields on Leap line"); 990 return; 991 } 992 dayoff = 0; 993 cp = fields[LP_YEAR]; 994 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 995 /* 996 * Leapin' Lizards! 997 */ 998 error("invalid leaping year"); 999 return; 1000 } 1001 j = EPOCH_YEAR; 1002 while (j != year) { 1003 if (year > j) { 1004 i = len_years[isleap(j)]; 1005 ++j; 1006 } else { 1007 --j; 1008 i = -len_years[isleap(j)]; 1009 } 1010 dayoff = oadd(dayoff, eitol(i)); 1011 } 1012 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1013 error("invalid month name"); 1014 return; 1015 } 1016 month = lp->l_value; 1017 j = TM_JANUARY; 1018 while (j != month) { 1019 i = len_months[isleap(year)][j]; 1020 dayoff = oadd(dayoff, eitol(i)); 1021 ++j; 1022 } 1023 cp = fields[LP_DAY]; 1024 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 1025 day <= 0 || day > len_months[isleap(year)][month]) { 1026 error("invalid day of month"); 1027 return; 1028 } 1029 dayoff = oadd(dayoff, eitol(day - 1)); 1030 if (dayoff < 0 && !tt_signed) { 1031 error("time before zero"); 1032 return; 1033 } 1034 t = (time_t) dayoff * SECSPERDAY; 1035 /* 1036 ** Cheap overflow check. 1037 */ 1038 if (t / SECSPERDAY != dayoff) { 1039 error("time overflow"); 1040 return; 1041 } 1042 tod = gethms(fields[LP_TIME], "invalid time of day", FALSE); 1043 cp = fields[LP_CORR]; 1044 { 1045 register int positive; 1046 int count; 1047 1048 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 1049 positive = FALSE; 1050 count = 1; 1051 } else if (strcmp(cp, "--") == 0) { 1052 positive = FALSE; 1053 count = 2; 1054 } else if (strcmp(cp, "+") == 0) { 1055 positive = TRUE; 1056 count = 1; 1057 } else if (strcmp(cp, "++") == 0) { 1058 positive = TRUE; 1059 count = 2; 1060 } else { 1061 error("illegal CORRECTION field on Leap line"); 1062 return; 1063 } 1064 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1065 error("illegal Rolling/Stationary field on Leap line"); 1066 return; 1067 } 1068 leapadd(tadd(t, tod), positive, lp->l_value, count); 1069 } 1070} 1071 1072static void 1073inlink(fields, nfields) 1074register char ** const fields; 1075const int nfields; 1076{ 1077 struct link l; 1078 1079 if (nfields != LINK_FIELDS) { 1080 error("wrong number of fields on Link line"); 1081 return; 1082 } 1083 if (*fields[LF_FROM] == '\0') { 1084 error("blank FROM field on Link line"); 1085 return; 1086 } 1087 if (*fields[LF_TO] == '\0') { 1088 error("blank TO field on Link line"); 1089 return; 1090 } 1091 l.l_filename = filename; 1092 l.l_linenum = linenum; 1093 l.l_from = ecpyalloc(fields[LF_FROM]); 1094 l.l_to = ecpyalloc(fields[LF_TO]); 1095 links = (struct link *) erealloc((char *) links, 1096 (int) ((nlinks + 1) * sizeof *links)); 1097 links[nlinks++] = l; 1098} 1099 1100static void 1101rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 1102register struct rule * const rp; 1103char * const loyearp; 1104char * const hiyearp; 1105char * const typep; 1106char * const monthp; 1107char * const dayp; 1108char * const timep; 1109{ 1110 register struct lookup const * lp; 1111 register char * cp; 1112 1113 if ((lp = byword(monthp, mon_names)) == NULL) { 1114 error("invalid month name"); 1115 return; 1116 } 1117 rp->r_month = lp->l_value; 1118 rp->r_todisstd = FALSE; 1119 cp = timep; 1120 if (*cp != '\0') { 1121 cp += strlen(cp) - 1; 1122 switch (lowerit(*cp)) { 1123 case 's': 1124 rp->r_todisstd = TRUE; 1125 *cp = '\0'; 1126 break; 1127 case 'w': 1128 rp->r_todisstd = FALSE; 1129 *cp = '\0'; 1130 break; 1131 } 1132 } 1133 rp->r_tod = gethms(timep, "invalid time of day", FALSE); 1134 /* 1135 ** Year work. 1136 */ 1137 cp = loyearp; 1138 if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) { 1139 case YR_MINIMUM: 1140 rp->r_loyear = min_int; 1141 break; 1142 case YR_MAXIMUM: 1143 rp->r_loyear = max_int; 1144 break; 1145 default: /* "cannot happen" */ 1146 (void) fprintf(stderr, 1147 "%s: panic: Invalid l_value %d\n", 1148 progname, lp->l_value); 1149 (void) exit(EXIT_FAILURE); 1150 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 1151 error("invalid starting year"); 1152 return; 1153 } 1154 cp = hiyearp; 1155 if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) { 1156 case YR_MINIMUM: 1157 rp->r_hiyear = min_int; 1158 break; 1159 case YR_MAXIMUM: 1160 rp->r_hiyear = max_int; 1161 break; 1162 case YR_ONLY: 1163 rp->r_hiyear = rp->r_loyear; 1164 break; 1165 default: /* "cannot happen" */ 1166 (void) fprintf(stderr, 1167 "%s: panic: Invalid l_value %d\n", 1168 progname, lp->l_value); 1169 (void) exit(EXIT_FAILURE); 1170 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 1171 error("invalid ending year"); 1172 return; 1173 } 1174 if (rp->r_loyear > rp->r_hiyear) { 1175 error("starting year greater than ending year"); 1176 return; 1177 } 1178 if (*typep == '\0') 1179 rp->r_yrtype = NULL; 1180 else { 1181 if (rp->r_loyear == rp->r_hiyear) { 1182 error("typed single year"); 1183 return; 1184 } 1185 rp->r_yrtype = ecpyalloc(typep); 1186 } 1187 /* 1188 ** Day work. 1189 ** Accept things such as: 1190 ** 1 1191 ** last-Sunday 1192 ** Sun<=20 1193 ** Sun>=7 1194 */ 1195 if ((lp = byword(dayp, lasts)) != NULL) { 1196 rp->r_dycode = DC_DOWLEQ; 1197 rp->r_wday = lp->l_value; 1198 rp->r_dayofmonth = len_months[1][rp->r_month]; 1199 } else { 1200 if ((cp = strchr(dayp, '<')) != 0) 1201 rp->r_dycode = DC_DOWLEQ; 1202 else if ((cp = strchr(dayp, '>')) != 0) 1203 rp->r_dycode = DC_DOWGEQ; 1204 else { 1205 cp = dayp; 1206 rp->r_dycode = DC_DOM; 1207 } 1208 if (rp->r_dycode != DC_DOM) { 1209 *cp++ = 0; 1210 if (*cp++ != '=') { 1211 error("invalid day of month"); 1212 return; 1213 } 1214 if ((lp = byword(dayp, wday_names)) == NULL) { 1215 error("invalid weekday name"); 1216 return; 1217 } 1218 rp->r_wday = lp->l_value; 1219 } 1220 if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 || 1221 rp->r_dayofmonth <= 0 || 1222 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1223 error("invalid day of month"); 1224 return; 1225 } 1226 } 1227} 1228 1229static void 1230convert(val, buf) 1231const long val; 1232char * const buf; 1233{ 1234 register int i; 1235 register long shift; 1236 1237 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1238 buf[i] = val >> shift; 1239} 1240 1241static void 1242puttzcode(val, fp) 1243const long val; 1244FILE * const fp; 1245{ 1246 char buf[4]; 1247 1248 convert(val, buf); 1249 (void) fwrite((genericptr_t) buf, 1250 (fwrite_size_t) sizeof buf, 1251 (fwrite_size_t) 1, fp); 1252} 1253 1254static void 1255writezone(name) 1256const char * const name; 1257{ 1258 register FILE * fp; 1259 register int i, j; 1260 static char * fullname; 1261 static struct tzhead tzh; 1262 1263 fullname = erealloc(fullname, 1264 strlen(directory) + 1 + strlen(name) + 1); 1265 (void) sprintf(fullname, "%s/%s", directory, name); 1266 if ((fp = fopen(fullname, "wb")) == NULL) { 1267 if (mkdirs(fullname) != 0) 1268 (void) exit(EXIT_FAILURE); 1269 if ((fp = fopen(fullname, "wb")) == NULL) { 1270 (void) fprintf(stderr, "%s: Can't create ", progname); 1271 (void) perror(fullname); 1272 (void) exit(EXIT_FAILURE); 1273 } 1274 } 1275 convert(eitol(typecnt), tzh.tzh_ttisstdcnt); 1276 convert(eitol(leapcnt), tzh.tzh_leapcnt); 1277 convert(eitol(timecnt), tzh.tzh_timecnt); 1278 convert(eitol(typecnt), tzh.tzh_typecnt); 1279 convert(eitol(charcnt), tzh.tzh_charcnt); 1280 (void) fwrite((genericptr_t) &tzh, 1281 (fwrite_size_t) sizeof tzh, 1282 (fwrite_size_t) 1, fp); 1283 for (i = 0; i < timecnt; ++i) { 1284 j = leapcnt; 1285 while (--j >= 0) 1286 if (ats[i] >= trans[j]) { 1287 ats[i] = tadd(ats[i], corr[j]); 1288 break; 1289 } 1290 puttzcode((long) ats[i], fp); 1291 } 1292 if (timecnt > 0) 1293 (void) fwrite((genericptr_t) types, 1294 (fwrite_size_t) sizeof types[0], 1295 (fwrite_size_t) timecnt, fp); 1296 for (i = 0; i < typecnt; ++i) { 1297 puttzcode((long) gmtoffs[i], fp); 1298 (void) putc(isdsts[i], fp); 1299 (void) putc(abbrinds[i], fp); 1300 } 1301 if (charcnt != 0) 1302 (void) fwrite((genericptr_t) chars, 1303 (fwrite_size_t) sizeof chars[0], 1304 (fwrite_size_t) charcnt, fp); 1305 for (i = 0; i < leapcnt; ++i) { 1306 if (roll[i]) { 1307 if (timecnt == 0 || trans[i] < ats[0]) { 1308 j = 0; 1309 while (isdsts[j]) 1310 if (++j >= typecnt) { 1311 j = 0; 1312 break; 1313 } 1314 } else { 1315 j = 1; 1316 while (j < timecnt && trans[i] >= ats[j]) 1317 ++j; 1318 j = types[j - 1]; 1319 } 1320 puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp); 1321 } else puttzcode((long) trans[i], fp); 1322 puttzcode((long) corr[i], fp); 1323 } 1324 for (i = 0; i < typecnt; ++i) 1325 (void) putc(ttisstds[i], fp); 1326 if (ferror(fp) || fclose(fp)) { 1327 (void) fprintf(stderr, "%s: Write error on ", progname); 1328 (void) perror(fullname); 1329 (void) exit(EXIT_FAILURE); 1330 } 1331} 1332 1333static void 1334outzone(zpfirst, zonecount) 1335const struct zone * const zpfirst; 1336const int zonecount; 1337{ 1338 register const struct zone * zp; 1339 register struct rule * rp; 1340 register int i, j; 1341 register int usestart, useuntil; 1342 register time_t starttime, untiltime; 1343 register long gmtoff; 1344 register long stdoff; 1345 register int year; 1346 register long startoff; 1347 register int startisdst; 1348 register int startttisstd; 1349 register int type; 1350 char startbuf[BUFSIZ]; 1351 1352 /* 1353 ** Now. . .finally. . .generate some useful data! 1354 */ 1355 timecnt = 0; 1356 typecnt = 0; 1357 charcnt = 0; 1358 /* 1359 ** A guess that may well be corrected later. 1360 */ 1361 stdoff = 0; 1362 /* 1363 ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au) 1364 ** for noting the need to unconditionally initialize startttisstd. 1365 */ 1366 startttisstd = FALSE; 1367#ifdef lint 1368 starttime = 0; 1369#endif /* defined lint */ 1370 for (i = 0; i < zonecount; ++i) { 1371 zp = &zpfirst[i]; 1372 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 1373 useuntil = i < (zonecount - 1); 1374 if (useuntil && zp->z_untiltime <= min_time) 1375 continue; 1376 gmtoff = zp->z_gmtoff; 1377 eat(zp->z_filename, zp->z_linenum); 1378 startisdst = -1; 1379 if (zp->z_nrules == 0) { 1380 stdoff = zp->z_stdoff; 1381 (void) strcpy(startbuf, zp->z_format); 1382 type = addtype(oadd(zp->z_gmtoff, stdoff), 1383 startbuf, stdoff != 0, startttisstd); 1384 if (usestart) 1385 addtt(starttime, type); 1386 else if (stdoff != 0) 1387 addtt(min_time, type); 1388 } else for (year = min_year; year <= max_year; ++year) { 1389 if (useuntil && year > zp->z_untilrule.r_hiyear) 1390 break; 1391 /* 1392 ** Mark which rules to do in the current year. 1393 ** For those to do, calculate rpytime(rp, year); 1394 */ 1395 for (j = 0; j < zp->z_nrules; ++j) { 1396 rp = &zp->z_rules[j]; 1397 eats(zp->z_filename, zp->z_linenum, 1398 rp->r_filename, rp->r_linenum); 1399 rp->r_todo = year >= rp->r_loyear && 1400 year <= rp->r_hiyear && 1401 yearistype(year, rp->r_yrtype); 1402 if (rp->r_todo) 1403 rp->r_temp = rpytime(rp, year); 1404 } 1405 for ( ; ; ) { 1406 register int k; 1407 register time_t jtime, ktime; 1408 register long offset; 1409 char buf[BUFSIZ]; 1410 1411 if (useuntil) { 1412 /* 1413 ** Turn untiltime into GMT 1414 ** assuming the current gmtoff and 1415 ** stdoff values. 1416 */ 1417 untiltime = tadd(zp->z_untiltime, 1418 -gmtoff); 1419 if (!zp->z_untilrule.r_todisstd) 1420 untiltime = tadd(untiltime, 1421 -stdoff); 1422 } 1423 /* 1424 ** Find the rule (of those to do, if any) 1425 ** that takes effect earliest in the year. 1426 */ 1427 k = -1; 1428#ifdef lint 1429 ktime = 0; 1430#endif /* defined lint */ 1431 for (j = 0; j < zp->z_nrules; ++j) { 1432 rp = &zp->z_rules[j]; 1433 if (!rp->r_todo) 1434 continue; 1435 eats(zp->z_filename, zp->z_linenum, 1436 rp->r_filename, rp->r_linenum); 1437 offset = gmtoff; 1438 if (!rp->r_todisstd) 1439 offset = oadd(offset, stdoff); 1440 jtime = rp->r_temp; 1441 if (jtime == min_time || 1442 jtime == max_time) 1443 continue; 1444 jtime = tadd(jtime, -offset); 1445 if (k < 0 || jtime < ktime) { 1446 k = j; 1447 ktime = jtime; 1448 } 1449 } 1450 if (k < 0) 1451 break; /* go on to next year */ 1452 rp = &zp->z_rules[k]; 1453 rp->r_todo = FALSE; 1454 if (useuntil && ktime >= untiltime) 1455 break; 1456 if (usestart) { 1457 if (ktime < starttime) { 1458 stdoff = rp->r_stdoff; 1459 startoff = oadd(zp->z_gmtoff, 1460 rp->r_stdoff); 1461 (void) sprintf(startbuf, zp->z_format, 1462 rp->r_abbrvar); 1463 startisdst = rp->r_stdoff != 0; 1464 continue; 1465 } 1466 usestart = FALSE; 1467 if (ktime != starttime) { 1468 if (startisdst < 0 && 1469 zp->z_gmtoff != 1470 (zp - 1)->z_gmtoff) { 1471 type = (timecnt == 0) ? 0 : 1472 types[timecnt - 1]; 1473 startoff = oadd(gmtoffs[type], 1474 -(zp - 1)->z_gmtoff); 1475 startisdst = startoff != 0; 1476 startoff = oadd(startoff, 1477 zp->z_gmtoff); 1478 (void) strcpy(startbuf, 1479 &chars[abbrinds[type]]); 1480 } 1481 if (startisdst >= 0) 1482addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd)); 1483 } 1484 } 1485 eats(zp->z_filename, zp->z_linenum, 1486 rp->r_filename, rp->r_linenum); 1487 (void) sprintf(buf, zp->z_format, 1488 rp->r_abbrvar); 1489 offset = oadd(zp->z_gmtoff, rp->r_stdoff); 1490 type = addtype(offset, buf, rp->r_stdoff != 0, 1491 rp->r_todisstd); 1492 addtt(ktime, type); 1493 stdoff = rp->r_stdoff; 1494 } 1495 } 1496 /* 1497 ** Now we may get to set starttime for the next zone line. 1498 */ 1499 if (useuntil) { 1500 starttime = tadd(zp->z_untiltime, -gmtoff); 1501 startttisstd = zp->z_untilrule.r_todisstd; 1502 if (!startttisstd) 1503 starttime = tadd(starttime, -stdoff); 1504 } 1505 } 1506 writezone(zpfirst->z_name); 1507} 1508 1509static void 1510addtt(starttime, type) 1511const time_t starttime; 1512const int type; 1513{ 1514 if (timecnt != 0 && type == types[timecnt - 1]) 1515 return; /* easy enough! */ 1516 if (timecnt == 0 && type == 0 && isdsts[0] == 0) 1517 return; /* handled by default rule */ 1518 if (timecnt >= TZ_MAX_TIMES) { 1519 error("too many transitions?!"); 1520 (void) exit(EXIT_FAILURE); 1521 } 1522 ats[timecnt] = starttime; 1523 types[timecnt] = type; 1524 ++timecnt; 1525} 1526 1527static int 1528addtype(gmtoff, abbr, isdst, ttisstd) 1529const long gmtoff; 1530const char * const abbr; 1531const int isdst; 1532const int ttisstd; 1533{ 1534 register int i, j; 1535 1536 /* 1537 ** See if there's already an entry for this zone type. 1538 ** If so, just return its index. 1539 */ 1540 for (i = 0; i < typecnt; ++i) { 1541 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 1542 strcmp(abbr, &chars[abbrinds[i]]) == 0 && 1543 ttisstd == ttisstds[i]) 1544 return i; 1545 } 1546 /* 1547 ** There isn't one; add a new one, unless there are already too 1548 ** many. 1549 */ 1550 if (typecnt >= TZ_MAX_TYPES) { 1551 error("too many local time types"); 1552 (void) exit(EXIT_FAILURE); 1553 } 1554 gmtoffs[i] = gmtoff; 1555 isdsts[i] = isdst; 1556 ttisstds[i] = ttisstd; 1557 1558 for (j = 0; j < charcnt; ++j) 1559 if (strcmp(&chars[j], abbr) == 0) 1560 break; 1561 if (j == charcnt) 1562 newabbr(abbr); 1563 abbrinds[i] = j; 1564 ++typecnt; 1565 return i; 1566} 1567 1568static void 1569leapadd(t, positive, rolling, count) 1570const time_t t; 1571const int positive; 1572const int rolling; 1573int count; 1574{ 1575 register int i, j; 1576 1577 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 1578 error("too many leap seconds"); 1579 (void) exit(EXIT_FAILURE); 1580 } 1581 for (i = 0; i < leapcnt; ++i) 1582 if (t <= trans[i]) { 1583 if (t == trans[i]) { 1584 error("repeated leap second moment"); 1585 (void) exit(EXIT_FAILURE); 1586 } 1587 break; 1588 } 1589 do { 1590 for (j = leapcnt; j > i; --j) { 1591 trans[j] = trans[j - 1]; 1592 corr[j] = corr[j - 1]; 1593 roll[j] = roll[j - 1]; 1594 } 1595 trans[i] = t; 1596 corr[i] = positive ? 1L : eitol(-count); 1597 roll[i] = rolling; 1598 ++leapcnt; 1599 } while (positive && --count != 0); 1600} 1601 1602static void 1603adjleap() 1604{ 1605 register int i; 1606 register long last = 0; 1607 1608 /* 1609 ** propagate leap seconds forward 1610 */ 1611 for (i = 0; i < leapcnt; ++i) { 1612 trans[i] = tadd(trans[i], last); 1613 last = corr[i] += last; 1614 } 1615} 1616 1617static int 1618yearistype(year, type) 1619const int year; 1620const char * const type; 1621{ 1622 static char * buf; 1623 int result; 1624 1625 if (type == NULL || *type == '\0') 1626 return TRUE; 1627 if (strcmp(type, "uspres") == 0) 1628 return (year % 4) == 0; 1629 if (strcmp(type, "nonpres") == 0) 1630 return (year % 4) != 0; 1631 buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type)); 1632 (void) sprintf(buf, "%s %d %s", yitcommand, year, type); 1633 result = system(buf); 1634 if (result == 0) 1635 return TRUE; 1636 if (result == (1 << 8)) 1637 return FALSE; 1638 error("Wild result from command execution"); 1639 (void) fprintf(stderr, "%s: command was '%s', result was %d\n", 1640 progname, buf, result); 1641 for ( ; ; ) 1642 (void) exit(EXIT_FAILURE); 1643} 1644 1645static int 1646lowerit(a) 1647const int a; 1648{ 1649 return (isascii(a) && isupper(a)) ? tolower(a) : a; 1650} 1651 1652static int 1653ciequal(ap, bp) /* case-insensitive equality */ 1654register const char * ap; 1655register const char * bp; 1656{ 1657 while (lowerit(*ap) == lowerit(*bp++)) 1658 if (*ap++ == '\0') 1659 return TRUE; 1660 return FALSE; 1661} 1662 1663static int 1664itsabbr(abbr, word) 1665register const char * abbr; 1666register const char * word; 1667{ 1668 if (lowerit(*abbr) != lowerit(*word)) 1669 return FALSE; 1670 ++word; 1671 while (*++abbr != '\0') 1672 do if (*word == '\0') 1673 return FALSE; 1674 while (lowerit(*word++) != lowerit(*abbr)); 1675 return TRUE; 1676} 1677 1678static const struct lookup * 1679byword(word, table) 1680register const char * const word; 1681register const struct lookup * const table; 1682{ 1683 register const struct lookup * foundlp; 1684 register const struct lookup * lp; 1685 1686 if (word == NULL || table == NULL) 1687 return NULL; 1688 /* 1689 ** Look for exact match. 1690 */ 1691 for (lp = table; lp->l_word != NULL; ++lp) 1692 if (ciequal(word, lp->l_word)) 1693 return lp; 1694 /* 1695 ** Look for inexact match. 1696 */ 1697 foundlp = NULL; 1698 for (lp = table; lp->l_word != NULL; ++lp) 1699 if (itsabbr(word, lp->l_word)) 1700 if (foundlp == NULL) 1701 foundlp = lp; 1702 else return NULL; /* multiple inexact matches */ 1703 return foundlp; 1704} 1705 1706static char ** 1707getfields(cp) 1708register char * cp; 1709{ 1710 register char * dp; 1711 register char ** array; 1712 register int nsubs; 1713 1714 if (cp == NULL) 1715 return NULL; 1716 array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array)); 1717 nsubs = 0; 1718 for ( ; ; ) { 1719 while (isascii(*cp) && isspace(*cp)) 1720 ++cp; 1721 if (*cp == '\0' || *cp == '#') 1722 break; 1723 array[nsubs++] = dp = cp; 1724 do { 1725 if ((*dp = *cp++) != '"') 1726 ++dp; 1727 else while ((*dp = *cp++) != '"') 1728 if (*dp != '\0') 1729 ++dp; 1730 else error("Odd number of quotation marks"); 1731 } while (*cp != '\0' && *cp != '#' && 1732 (!isascii(*cp) || !isspace(*cp))); 1733 if (isascii(*cp) && isspace(*cp)) 1734 ++cp; 1735 *dp = '\0'; 1736 } 1737 array[nsubs] = NULL; 1738 return array; 1739} 1740 1741static long 1742oadd(t1, t2) 1743const long t1; 1744const long t2; 1745{ 1746 register long t; 1747 1748 t = t1 + t2; 1749 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1750 error("time overflow"); 1751 (void) exit(EXIT_FAILURE); 1752 } 1753 return t; 1754} 1755 1756static time_t 1757tadd(t1, t2) 1758const time_t t1; 1759const long t2; 1760{ 1761 register time_t t; 1762 1763 if (t1 == max_time && t2 > 0) 1764 return max_time; 1765 if (t1 == min_time && t2 < 0) 1766 return min_time; 1767 t = t1 + t2; 1768 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1769 error("time overflow"); 1770 (void) exit(EXIT_FAILURE); 1771 } 1772 return t; 1773} 1774 1775/* 1776** Given a rule, and a year, compute the date - in seconds since January 1, 1777** 1970, 00:00 LOCAL time - in that year that the rule refers to. 1778*/ 1779 1780static time_t 1781rpytime(rp, wantedy) 1782register const struct rule * const rp; 1783register const int wantedy; 1784{ 1785 register int y, m, i; 1786 register long dayoff; /* with a nod to Margaret O. */ 1787 register time_t t; 1788 1789 if (wantedy == min_int) 1790 return min_time; 1791 if (wantedy == max_int) 1792 return max_time; 1793 dayoff = 0; 1794 m = TM_JANUARY; 1795 y = EPOCH_YEAR; 1796 while (wantedy != y) { 1797 if (wantedy > y) { 1798 i = len_years[isleap(y)]; 1799 ++y; 1800 } else { 1801 --y; 1802 i = -len_years[isleap(y)]; 1803 } 1804 dayoff = oadd(dayoff, eitol(i)); 1805 } 1806 while (m != rp->r_month) { 1807 i = len_months[isleap(y)][m]; 1808 dayoff = oadd(dayoff, eitol(i)); 1809 ++m; 1810 } 1811 i = rp->r_dayofmonth; 1812 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 1813 if (rp->r_dycode == DC_DOWLEQ) 1814 --i; 1815 else { 1816 error("use of 2/29 in non leap-year"); 1817 (void) exit(EXIT_FAILURE); 1818 } 1819 } 1820 --i; 1821 dayoff = oadd(dayoff, eitol(i)); 1822 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 1823 register long wday; 1824 1825#define LDAYSPERWEEK ((long) DAYSPERWEEK) 1826 wday = eitol(EPOCH_WDAY); 1827 /* 1828 ** Don't trust mod of negative numbers. 1829 */ 1830 if (dayoff >= 0) 1831 wday = (wday + dayoff) % LDAYSPERWEEK; 1832 else { 1833 wday -= ((-dayoff) % LDAYSPERWEEK); 1834 if (wday < 0) 1835 wday += LDAYSPERWEEK; 1836 } 1837 while (wday != eitol(rp->r_wday)) 1838 if (rp->r_dycode == DC_DOWGEQ) { 1839 dayoff = oadd(dayoff, (long) 1); 1840 if (++wday >= LDAYSPERWEEK) 1841 wday = 0; 1842 ++i; 1843 } else { 1844 dayoff = oadd(dayoff, (long) -1); 1845 if (--wday < 0) 1846 wday = LDAYSPERWEEK - 1; 1847 --i; 1848 } 1849 if (i < 0 || i >= len_months[isleap(y)][m]) { 1850 error("no day in month matches rule"); 1851 (void) exit(EXIT_FAILURE); 1852 } 1853 } 1854 if (dayoff < 0 && !tt_signed) 1855 return min_time; 1856 t = (time_t) dayoff * SECSPERDAY; 1857 /* 1858 ** Cheap overflow check. 1859 */ 1860 if (t / SECSPERDAY != dayoff) 1861 return (dayoff > 0) ? max_time : min_time; 1862 return tadd(t, rp->r_tod); 1863} 1864 1865static void 1866newabbr(string) 1867const char * const string; 1868{ 1869 register int i; 1870 1871 i = strlen(string) + 1; 1872 if (charcnt + i > TZ_MAX_CHARS) { 1873 error("too many, or too long, time zone abbreviations"); 1874 (void) exit(EXIT_FAILURE); 1875 } 1876 (void) strcpy(&chars[charcnt], string); 1877 charcnt += eitol(i); 1878} 1879 1880static int 1881mkdirs(argname) 1882char * const argname; 1883{ 1884 register char * name; 1885 register char * cp; 1886 1887 if (argname == NULL || *argname == '\0') 1888 return 0; 1889 cp = name = ecpyalloc(argname); 1890 while ((cp = strchr(cp + 1, '/')) != 0) { 1891 *cp = '\0'; 1892#ifndef unix 1893 /* 1894 ** MS-DOS drive specifier? 1895 */ 1896 if (strlen(name) == 2 && isascii(name[0]) && 1897 isalpha(name[0]) && name[1] == ':') { 1898 *cp = '/'; 1899 continue; 1900 } 1901#endif /* !defined unix */ 1902 if (!itsdir(name)) { 1903 /* 1904 ** It doesn't seem to exist, so we try to create it. 1905 */ 1906 if (emkdir(name, 0755) != 0) { 1907 (void) fprintf(stderr, 1908 "%s: Can't create directory ", 1909 progname); 1910 (void) perror(name); 1911 ifree(name); 1912 return -1; 1913 } 1914 } 1915 *cp = '/'; 1916 } 1917 ifree(name); 1918 return 0; 1919} 1920 1921static long 1922eitol(i) 1923const int i; 1924{ 1925 long l; 1926 1927 l = i; 1928 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 1929 (void) fprintf(stderr, 1930 "%s: %d did not sign extend correctly\n", 1931 progname, i); 1932 (void) exit(EXIT_FAILURE); 1933 } 1934 return l; 1935} 1936 1937/* 1938** UNIX is a registered trademark of AT&T. 1939*/ 1940