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