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