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