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