1 /* $NetBSD: zic.c,v 1.6 1997/01/23 14:02:32 mrg 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, int abbrlen, 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, /* XXX: sprintf is safe */ 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, /* XXX: sprintf is safe */ 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, /* XXX: sprintf is safe */ 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); /* XXX: sprintf is safe */ 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, abbrlen, format, letters, isdst) 1504 char * const abbr; 1505 const int abbrlen; 1506 const char * const format; 1507 const char * const letters; 1508 const int isdst; 1509 { 1510 if (strchr(format, '/') == NULL) { 1511 if (letters == NULL) 1512 (void)strncpy(abbr, format, abbrlen - 1); 1513 else 1514 (void)snprintf(abbr, abbrlen, format, letters); 1515 } else if (isdst) 1516 (void)strncpy(abbr, strchr(format, '/') + 1, abbrlen - 1); 1517 else { 1518 (void)strncpy(abbr, format, abbrlen - 1); 1519 *strchr(abbr, '/') = '\0'; 1520 } 1521 } 1522 1523 static void 1524 outzone(zpfirst, zonecount) 1525 const struct zone * const zpfirst; 1526 const int zonecount; 1527 { 1528 register const struct zone * zp; 1529 register struct rule * rp; 1530 register int i, j; 1531 register int usestart, useuntil; 1532 register time_t starttime, untiltime; 1533 register long gmtoff; 1534 register long stdoff; 1535 register int year; 1536 register long startoff; 1537 register int startttisstd; 1538 register int startttisgmt; 1539 register int type; 1540 char startbuf[BUFSIZ]; 1541 1542 INITIALIZE(untiltime); 1543 INITIALIZE(starttime); 1544 /* 1545 ** Now. . .finally. . .generate some useful data! 1546 */ 1547 timecnt = 0; 1548 typecnt = 0; 1549 charcnt = 0; 1550 /* 1551 ** A guess that may well be corrected later. 1552 */ 1553 stdoff = 0; 1554 /* 1555 ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au) 1556 ** for noting the need to unconditionally initialize startttisstd. 1557 */ 1558 startttisstd = FALSE; 1559 startttisgmt = FALSE; 1560 for (i = 0; i < zonecount; ++i) { 1561 zp = &zpfirst[i]; 1562 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 1563 useuntil = i < (zonecount - 1); 1564 if (useuntil && zp->z_untiltime <= min_time) 1565 continue; 1566 gmtoff = zp->z_gmtoff; 1567 eat(zp->z_filename, zp->z_linenum); 1568 *startbuf = '\0'; 1569 startoff = zp->z_gmtoff; 1570 if (zp->z_nrules == 0) { 1571 stdoff = zp->z_stdoff; 1572 doabbr(startbuf, sizeof startbuf, zp->z_format, 1573 (char *) NULL, stdoff != 0); 1574 type = addtype(oadd(zp->z_gmtoff, stdoff), 1575 startbuf, stdoff != 0, startttisstd, 1576 startttisgmt); 1577 if (usestart) { 1578 addtt(starttime, type); 1579 usestart = FALSE; 1580 } 1581 else if (stdoff != 0) 1582 addtt(min_time, type); 1583 } else for (year = min_year; year <= max_year; ++year) { 1584 if (useuntil && year > zp->z_untilrule.r_hiyear) 1585 break; 1586 /* 1587 ** Mark which rules to do in the current year. 1588 ** For those to do, calculate rpytime(rp, year); 1589 */ 1590 for (j = 0; j < zp->z_nrules; ++j) { 1591 rp = &zp->z_rules[j]; 1592 eats(zp->z_filename, zp->z_linenum, 1593 rp->r_filename, rp->r_linenum); 1594 rp->r_todo = year >= rp->r_loyear && 1595 year <= rp->r_hiyear && 1596 yearistype(year, rp->r_yrtype); 1597 if (rp->r_todo) 1598 rp->r_temp = rpytime(rp, year); 1599 } 1600 for ( ; ; ) { 1601 register int k; 1602 register time_t jtime, ktime; 1603 register long offset; 1604 char buf[BUFSIZ]; 1605 1606 INITIALIZE(ktime); 1607 if (useuntil) { 1608 /* 1609 ** Turn untiltime into GMT 1610 ** assuming the current gmtoff and 1611 ** stdoff values. 1612 */ 1613 untiltime = zp->z_untiltime; 1614 if (!zp->z_untilrule.r_todisgmt) 1615 untiltime = tadd(untiltime, 1616 -gmtoff); 1617 if (!zp->z_untilrule.r_todisstd) 1618 untiltime = tadd(untiltime, 1619 -stdoff); 1620 } 1621 /* 1622 ** Find the rule (of those to do, if any) 1623 ** that takes effect earliest in the year. 1624 */ 1625 k = -1; 1626 for (j = 0; j < zp->z_nrules; ++j) { 1627 rp = &zp->z_rules[j]; 1628 if (!rp->r_todo) 1629 continue; 1630 eats(zp->z_filename, zp->z_linenum, 1631 rp->r_filename, rp->r_linenum); 1632 offset = rp->r_todisgmt ? 0 : gmtoff; 1633 if (!rp->r_todisstd) 1634 offset = oadd(offset, stdoff); 1635 jtime = rp->r_temp; 1636 if (jtime == min_time || 1637 jtime == max_time) 1638 continue; 1639 jtime = tadd(jtime, -offset); 1640 if (k < 0 || jtime < ktime) { 1641 k = j; 1642 ktime = jtime; 1643 } 1644 } 1645 if (k < 0) 1646 break; /* go on to next year */ 1647 rp = &zp->z_rules[k]; 1648 rp->r_todo = FALSE; 1649 if (useuntil && ktime >= untiltime) 1650 break; 1651 stdoff = rp->r_stdoff; 1652 if (usestart && ktime == starttime) 1653 usestart = FALSE; 1654 if (usestart) { 1655 if (ktime < starttime) { 1656 startoff = oadd(zp->z_gmtoff, 1657 stdoff); 1658 doabbr(startbuf,sizeof startbuf, 1659 zp->z_format, 1660 rp->r_abbrvar, 1661 rp->r_stdoff != 0); 1662 continue; 1663 } 1664 if (*startbuf == '\0' && 1665 startoff == oadd(zp->z_gmtoff, 1666 stdoff)) { 1667 doabbr(startbuf,sizeof startbuf, 1668 zp->z_format, 1669 rp->r_abbrvar, 1670 rp->r_stdoff != 0); 1671 } 1672 } 1673 eats(zp->z_filename, zp->z_linenum, 1674 rp->r_filename, rp->r_linenum); 1675 doabbr(buf, sizeof buf, zp->z_format, 1676 rp->r_abbrvar, rp->r_stdoff != 0); 1677 offset = oadd(zp->z_gmtoff, rp->r_stdoff); 1678 type = addtype(offset, buf, rp->r_stdoff != 0, 1679 rp->r_todisstd, rp->r_todisgmt); 1680 addtt(ktime, type); 1681 } 1682 } 1683 if (usestart) { 1684 if (*startbuf == '\0' && 1685 zp->z_format != NULL && 1686 strchr(zp->z_format, '%') == NULL && 1687 strchr(zp->z_format, '/') == NULL) 1688 (void)strncpy(startbuf, zp->z_format, 1689 sizeof(startbuf) - 1); 1690 eat(zp->z_filename, zp->z_linenum); 1691 if (*startbuf == '\0') 1692 error(_("can't determine time zone abbrevation to use just after until time")); 1693 else addtt(starttime, 1694 addtype(startoff, startbuf, 1695 startoff != zp->z_gmtoff, 1696 startttisstd, 1697 startttisgmt)); 1698 } 1699 /* 1700 ** Now we may get to set starttime for the next zone line. 1701 */ 1702 if (useuntil) { 1703 startttisstd = zp->z_untilrule.r_todisstd; 1704 startttisgmt = zp->z_untilrule.r_todisgmt; 1705 starttime = zp->z_untiltime; 1706 if (!startttisstd) 1707 starttime = tadd(starttime, -stdoff); 1708 if (!startttisgmt) 1709 starttime = tadd(starttime, -gmtoff); 1710 } 1711 } 1712 writezone(zpfirst->z_name); 1713 } 1714 1715 static void 1716 addtt(starttime, type) 1717 const time_t starttime; 1718 const int type; 1719 { 1720 if (timecnt >= TZ_MAX_TIMES) { 1721 error(_("too many transitions?!")); 1722 (void) exit(EXIT_FAILURE); 1723 } 1724 attypes[timecnt].at = starttime; 1725 attypes[timecnt].type = type; 1726 ++timecnt; 1727 } 1728 1729 static int 1730 addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) 1731 const long gmtoff; 1732 const char * const abbr; 1733 const int isdst; 1734 const int ttisstd; 1735 const int ttisgmt; 1736 { 1737 register int i, j; 1738 1739 if (isdst != TRUE && isdst != FALSE) { 1740 error(_("internal error - addtype called with bad isdst")); 1741 (void) exit(EXIT_FAILURE); 1742 } 1743 if (ttisstd != TRUE && ttisstd != FALSE) { 1744 error(_("internal error - addtype called with bad ttisstd")); 1745 (void) exit(EXIT_FAILURE); 1746 } 1747 if (ttisgmt != TRUE && ttisgmt != FALSE) { 1748 error(_("internal error - addtype called with bad ttisgmt")); 1749 (void) exit(EXIT_FAILURE); 1750 } 1751 /* 1752 ** See if there's already an entry for this zone type. 1753 ** If so, just return its index. 1754 */ 1755 for (i = 0; i < typecnt; ++i) { 1756 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 1757 strcmp(abbr, &chars[abbrinds[i]]) == 0 && 1758 ttisstd == ttisstds[i] && 1759 ttisgmt == ttisgmts[i]) 1760 return i; 1761 } 1762 /* 1763 ** There isn't one; add a new one, unless there are already too 1764 ** many. 1765 */ 1766 if (typecnt >= TZ_MAX_TYPES) { 1767 error(_("too many local time types")); 1768 (void) exit(EXIT_FAILURE); 1769 } 1770 gmtoffs[i] = gmtoff; 1771 isdsts[i] = isdst; 1772 ttisstds[i] = ttisstd; 1773 ttisgmts[i] = ttisgmt; 1774 1775 for (j = 0; j < charcnt; ++j) 1776 if (strcmp(&chars[j], abbr) == 0) 1777 break; 1778 if (j == charcnt) 1779 newabbr(abbr); 1780 abbrinds[i] = j; 1781 ++typecnt; 1782 return i; 1783 } 1784 1785 static void 1786 leapadd(t, positive, rolling, count) 1787 const time_t t; 1788 const int positive; 1789 const int rolling; 1790 int count; 1791 { 1792 register int i, j; 1793 1794 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 1795 error(_("too many leap seconds")); 1796 (void) exit(EXIT_FAILURE); 1797 } 1798 for (i = 0; i < leapcnt; ++i) 1799 if (t <= trans[i]) { 1800 if (t == trans[i]) { 1801 error(_("repeated leap second moment")); 1802 (void) exit(EXIT_FAILURE); 1803 } 1804 break; 1805 } 1806 do { 1807 for (j = leapcnt; j > i; --j) { 1808 trans[j] = trans[j - 1]; 1809 corr[j] = corr[j - 1]; 1810 roll[j] = roll[j - 1]; 1811 } 1812 trans[i] = t; 1813 corr[i] = positive ? 1L : eitol(-count); 1814 roll[i] = rolling; 1815 ++leapcnt; 1816 } while (positive && --count != 0); 1817 } 1818 1819 static void 1820 adjleap P((void)) 1821 { 1822 register int i; 1823 register long last = 0; 1824 1825 /* 1826 ** propagate leap seconds forward 1827 */ 1828 for (i = 0; i < leapcnt; ++i) { 1829 trans[i] = tadd(trans[i], last); 1830 last = corr[i] += last; 1831 } 1832 } 1833 1834 static int 1835 yearistype(year, type) 1836 const int year; 1837 const char * const type; 1838 { 1839 static char * buf; 1840 int result; 1841 1842 if (type == NULL || *type == '\0') 1843 return TRUE; 1844 buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); 1845 (void)sprintf(buf, "%s %d %s", yitcommand, year, type); /* XXX: sprintf is safe */ 1846 result = system(buf); 1847 if (result == 0) 1848 return TRUE; 1849 if (result == (1 << 8)) 1850 return FALSE; 1851 error(_("Wild result from command execution")); 1852 (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"), 1853 progname, buf, result); 1854 for ( ; ; ) 1855 (void) exit(EXIT_FAILURE); 1856 } 1857 1858 static int 1859 lowerit(a) 1860 int a; 1861 { 1862 a = (unsigned char) a; 1863 return (isascii(a) && isupper(a)) ? tolower(a) : a; 1864 } 1865 1866 static int 1867 ciequal(ap, bp) /* case-insensitive equality */ 1868 register const char * ap; 1869 register const char * bp; 1870 { 1871 while (lowerit(*ap) == lowerit(*bp++)) 1872 if (*ap++ == '\0') 1873 return TRUE; 1874 return FALSE; 1875 } 1876 1877 static int 1878 itsabbr(abbr, word) 1879 register const char * abbr; 1880 register const char * word; 1881 { 1882 if (lowerit(*abbr) != lowerit(*word)) 1883 return FALSE; 1884 ++word; 1885 while (*++abbr != '\0') 1886 do { 1887 if (*word == '\0') 1888 return FALSE; 1889 } while (lowerit(*word++) != lowerit(*abbr)); 1890 return TRUE; 1891 } 1892 1893 static const struct lookup * 1894 byword(word, table) 1895 register const char * const word; 1896 register const struct lookup * const table; 1897 { 1898 register const struct lookup * foundlp; 1899 register const struct lookup * lp; 1900 1901 if (word == NULL || table == NULL) 1902 return NULL; 1903 /* 1904 ** Look for exact match. 1905 */ 1906 for (lp = table; lp->l_word != NULL; ++lp) 1907 if (ciequal(word, lp->l_word)) 1908 return lp; 1909 /* 1910 ** Look for inexact match. 1911 */ 1912 foundlp = NULL; 1913 for (lp = table; lp->l_word != NULL; ++lp) 1914 if (itsabbr(word, lp->l_word)) 1915 if (foundlp == NULL) 1916 foundlp = lp; 1917 else return NULL; /* multiple inexact matches */ 1918 return foundlp; 1919 } 1920 1921 static char ** 1922 getfields(cp) 1923 register char * cp; 1924 { 1925 register char * dp; 1926 register char ** array; 1927 register int nsubs; 1928 1929 if (cp == NULL) 1930 return NULL; 1931 array = (char **) (void *) 1932 emalloc((int) ((strlen(cp) + 1) * sizeof *array)); 1933 nsubs = 0; 1934 for ( ; ; ) { 1935 while (isascii(*cp) && isspace((unsigned char) *cp)) 1936 ++cp; 1937 if (*cp == '\0' || *cp == '#') 1938 break; 1939 array[nsubs++] = dp = cp; 1940 do { 1941 if ((*dp = *cp++) != '"') 1942 ++dp; 1943 else while ((*dp = *cp++) != '"') 1944 if (*dp != '\0') 1945 ++dp; 1946 else error(_("Odd number of quotation marks")); 1947 } while (*cp != '\0' && *cp != '#' && 1948 (!isascii(*cp) || !isspace((unsigned char) *cp))); 1949 if (isascii(*cp) && isspace((unsigned char) *cp)) 1950 ++cp; 1951 *dp = '\0'; 1952 } 1953 array[nsubs] = NULL; 1954 return array; 1955 } 1956 1957 static long 1958 oadd(t1, t2) 1959 const long t1; 1960 const long t2; 1961 { 1962 register long t; 1963 1964 t = t1 + t2; 1965 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1966 error(_("time overflow")); 1967 (void) exit(EXIT_FAILURE); 1968 } 1969 return t; 1970 } 1971 1972 static time_t 1973 tadd(t1, t2) 1974 const time_t t1; 1975 const long t2; 1976 { 1977 register time_t t; 1978 1979 if (t1 == max_time && t2 > 0) 1980 return max_time; 1981 if (t1 == min_time && t2 < 0) 1982 return min_time; 1983 t = t1 + t2; 1984 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1985 error(_("time overflow")); 1986 (void) exit(EXIT_FAILURE); 1987 } 1988 return t; 1989 } 1990 1991 /* 1992 ** Given a rule, and a year, compute the date - in seconds since January 1, 1993 ** 1970, 00:00 LOCAL time - in that year that the rule refers to. 1994 */ 1995 1996 static time_t 1997 rpytime(rp, wantedy) 1998 register const struct rule * const rp; 1999 register const int wantedy; 2000 { 2001 register int y, m, i; 2002 register long dayoff; /* with a nod to Margaret O. */ 2003 register time_t t; 2004 2005 if (wantedy == INT_MIN) 2006 return min_time; 2007 if (wantedy == INT_MAX) 2008 return max_time; 2009 dayoff = 0; 2010 m = TM_JANUARY; 2011 y = EPOCH_YEAR; 2012 while (wantedy != y) { 2013 if (wantedy > y) { 2014 i = len_years[isleap(y)]; 2015 ++y; 2016 } else { 2017 --y; 2018 i = -len_years[isleap(y)]; 2019 } 2020 dayoff = oadd(dayoff, eitol(i)); 2021 } 2022 while (m != rp->r_month) { 2023 i = len_months[isleap(y)][m]; 2024 dayoff = oadd(dayoff, eitol(i)); 2025 ++m; 2026 } 2027 i = rp->r_dayofmonth; 2028 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 2029 if (rp->r_dycode == DC_DOWLEQ) 2030 --i; 2031 else { 2032 error(_("use of 2/29 in non leap-year")); 2033 (void) exit(EXIT_FAILURE); 2034 } 2035 } 2036 --i; 2037 dayoff = oadd(dayoff, eitol(i)); 2038 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 2039 register long wday; 2040 2041 #define LDAYSPERWEEK ((long) DAYSPERWEEK) 2042 wday = eitol(EPOCH_WDAY); 2043 /* 2044 ** Don't trust mod of negative numbers. 2045 */ 2046 if (dayoff >= 0) 2047 wday = (wday + dayoff) % LDAYSPERWEEK; 2048 else { 2049 wday -= ((-dayoff) % LDAYSPERWEEK); 2050 if (wday < 0) 2051 wday += LDAYSPERWEEK; 2052 } 2053 while (wday != eitol(rp->r_wday)) 2054 if (rp->r_dycode == DC_DOWGEQ) { 2055 dayoff = oadd(dayoff, (long) 1); 2056 if (++wday >= LDAYSPERWEEK) 2057 wday = 0; 2058 ++i; 2059 } else { 2060 dayoff = oadd(dayoff, (long) -1); 2061 if (--wday < 0) 2062 wday = LDAYSPERWEEK - 1; 2063 --i; 2064 } 2065 if (i < 0 || i >= len_months[isleap(y)][m]) { 2066 error(_("no day in month matches rule")); 2067 (void) exit(EXIT_FAILURE); 2068 } 2069 } 2070 if (dayoff < 0 && !TYPE_SIGNED(time_t)) 2071 return min_time; 2072 t = (time_t) dayoff * SECSPERDAY; 2073 /* 2074 ** Cheap overflow check. 2075 */ 2076 if (t / SECSPERDAY != dayoff) 2077 return (dayoff > 0) ? max_time : min_time; 2078 return tadd(t, rp->r_tod); 2079 } 2080 2081 static void 2082 newabbr(string) 2083 const char * const string; 2084 { 2085 register int i; 2086 2087 i = strlen(string) + 1; 2088 if (charcnt + i > TZ_MAX_CHARS) { 2089 error(_("too many, or too long, time zone abbreviations")); 2090 (void) exit(EXIT_FAILURE); 2091 } 2092 (void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1); 2093 charcnt += eitol(i); 2094 } 2095 2096 static int 2097 mkdirs(argname) 2098 char * const argname; 2099 { 2100 register char * name; 2101 register char * cp; 2102 2103 if (argname == NULL || *argname == '\0') 2104 return 0; 2105 cp = name = ecpyalloc(argname); 2106 while ((cp = strchr(cp + 1, '/')) != 0) { 2107 *cp = '\0'; 2108 #ifndef unix 2109 /* 2110 ** DOS drive specifier? 2111 */ 2112 if (isalpha((unsigned char) name[0]) && 2113 name[1] == ':' && name[2] == '\0') { 2114 *cp = '/'; 2115 continue; 2116 } 2117 #endif /* !defined unix */ 2118 if (!itsdir(name)) { 2119 /* 2120 ** It doesn't seem to exist, so we try to create it. 2121 */ 2122 if (mkdir(name, 0755) != 0) { 2123 const char *e = strerror(errno); 2124 (void) fprintf(stderr, 2125 _("%s: Can't create directory %s: %s\n"), 2126 progname, name, e); 2127 ifree(name); 2128 return -1; 2129 } 2130 } 2131 *cp = '/'; 2132 } 2133 ifree(name); 2134 return 0; 2135 } 2136 2137 static long 2138 eitol(i) 2139 const int i; 2140 { 2141 long l; 2142 2143 l = i; 2144 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 2145 (void) fprintf(stderr, 2146 _("%s: %d did not sign extend correctly\n"), 2147 progname, i); 2148 (void) exit(EXIT_FAILURE); 2149 } 2150 return l; 2151 } 2152 2153 /* 2154 ** UNIX was a registered trademark of UNIX System Laboratories in 1993. 2155 */ 2156