1 /* $NetBSD: zic.c,v 1.34 2012/10/25 15:04:05 martin Exp $ */ 2 /* 3 ** This file is in the public domain, so clarified as of 4 ** 2006-07-17 by Arthur David Olson. 5 */ 6 7 #if HAVE_NBTOOL_CONFIG_H 8 #include "nbtool_config.h" 9 #endif 10 11 #include <sys/cdefs.h> 12 #ifndef lint 13 __RCSID("$NetBSD: zic.c,v 1.34 2012/10/25 15:04:05 martin Exp $"); 14 #endif /* !defined lint */ 15 16 #include "version.h" 17 #include "private.h" 18 #include "locale.h" 19 #include "tzfile.h" 20 21 #define ZIC_VERSION '2' 22 23 typedef int_fast64_t zic_t; 24 25 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN 26 #define ZIC_MAX_ABBR_LEN_WO_WARN 6 27 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ 28 29 #if HAVE_SYS_STAT_H 30 #include "sys/stat.h" 31 #endif 32 #ifdef S_IRUSR 33 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 34 #else 35 #define MKDIR_UMASK 0755 36 #endif 37 38 #include "unistd.h" 39 40 /* 41 ** On some ancient hosts, predicates like `isspace(C)' are defined 42 ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard, 43 ** which says they are defined only if C == ((unsigned char) C) || C == EOF. 44 ** Neither the C Standard nor Posix require that `isascii' exist. 45 ** For portability, we check both ancient and modern requirements. 46 ** If isascii is not defined, the isascii check succeeds trivially. 47 */ 48 #include "ctype.h" 49 #ifndef isascii 50 #define isascii(x) 1 51 #endif 52 53 #define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long)) 54 #define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */ 55 56 #define end(cp) (strchr((cp), '\0')) 57 58 struct rule { 59 const char * r_filename; 60 int r_linenum; 61 const char * r_name; 62 63 int r_loyear; /* for example, 1986 */ 64 int r_hiyear; /* for example, 1986 */ 65 const char * r_yrtype; 66 int r_lowasnum; 67 int r_hiwasnum; 68 69 int r_month; /* 0..11 */ 70 71 int r_dycode; /* see below */ 72 int r_dayofmonth; 73 int r_wday; 74 75 long r_tod; /* time from midnight */ 76 int r_todisstd; /* above is standard time if TRUE */ 77 /* or wall clock time if FALSE */ 78 int r_todisgmt; /* above is GMT if TRUE */ 79 /* or local time if FALSE */ 80 long r_stdoff; /* offset from standard time */ 81 const char * r_abbrvar; /* variable part of abbreviation */ 82 83 int r_todo; /* a rule to do (used in outzone) */ 84 zic_t r_temp; /* used in outzone */ 85 }; 86 87 /* 88 ** r_dycode r_dayofmonth r_wday 89 */ 90 91 #define DC_DOM 0 /* 1..31 */ /* unused */ 92 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 93 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 94 95 struct zone { 96 const char * z_filename; 97 int z_linenum; 98 99 const char * z_name; 100 long z_gmtoff; 101 const char * z_rule; 102 const char * z_format; 103 104 long z_stdoff; 105 106 struct rule * z_rules; 107 int z_nrules; 108 109 struct rule z_untilrule; 110 zic_t z_untiltime; 111 }; 112 113 extern int getopt(int argc, char * const argv[], 114 const char * options); 115 extern int link(const char * fromname, const char * toname); 116 extern char * optarg; 117 extern int optind; 118 119 static void addtt(zic_t starttime, int type); 120 static int addtype(long gmtoff, const char * abbr, int isdst, 121 int ttisstd, int ttisgmt); 122 static void leapadd(zic_t t, int positive, int rolling, int count); 123 static void adjleap(void); 124 static void associate(void); 125 static void dolink(const char * fromfield, const char * tofield); 126 static long eitol(int i); 127 static char ** getfields(char * buf); 128 static long gethms(const char * string, const char * errstrng, 129 int signable); 130 static void infile(const char * filename); 131 static void inleap(char ** fields, int nfields); 132 static void inlink(char ** fields, int nfields); 133 static void inrule(char ** fields, int nfields); 134 static int inzcont(char ** fields, int nfields); 135 static int inzone(char ** fields, int nfields); 136 static int inzsub(char ** fields, int nfields, int iscont); 137 static int itsdir(const char * name); 138 static int lowerit(int c); 139 int main(int, char **); 140 static int mkdirs(char * filename); 141 static void newabbr(const char * abbr); 142 static long oadd(long t1, long t2); 143 static void outzone(const struct zone * zp, int ntzones); 144 static int rcomp(const void * leftp, const void * rightp); 145 static zic_t rpytime(const struct rule * rp, int wantedy); 146 static void rulesub(struct rule * rp, 147 const char * loyearp, const char * hiyearp, 148 const char * typep, const char * monthp, 149 const char * dayp, const char * timep); 150 static zic_t tadd(zic_t t1, long t2); 151 static int yearistype(int year, const char * type); 152 static int atcomp(const void *avp, const void *bvp); 153 static void updateminmax(int x); 154 155 static int charcnt; 156 static int errors; 157 static const char * filename; 158 static int leapcnt; 159 static int leapseen; 160 static int leapminyear; 161 static int leapmaxyear; 162 static int linenum; 163 static int max_abbrvar_len; 164 static int max_format_len; 165 static int max_year; 166 static int min_year; 167 static int noise; 168 static const char * rfilename; 169 static int rlinenum; 170 static const char * progname; 171 static int timecnt; 172 static int typecnt; 173 174 /* 175 ** Line codes. 176 */ 177 178 #define LC_RULE 0 179 #define LC_ZONE 1 180 #define LC_LINK 2 181 #define LC_LEAP 3 182 183 /* 184 ** Which fields are which on a Zone line. 185 */ 186 187 #define ZF_NAME 1 188 #define ZF_GMTOFF 2 189 #define ZF_RULE 3 190 #define ZF_FORMAT 4 191 #define ZF_TILYEAR 5 192 #define ZF_TILMONTH 6 193 #define ZF_TILDAY 7 194 #define ZF_TILTIME 8 195 #define ZONE_MINFIELDS 5 196 #define ZONE_MAXFIELDS 9 197 198 /* 199 ** Which fields are which on a Zone continuation line. 200 */ 201 202 #define ZFC_GMTOFF 0 203 #define ZFC_RULE 1 204 #define ZFC_FORMAT 2 205 #define ZFC_TILYEAR 3 206 #define ZFC_TILMONTH 4 207 #define ZFC_TILDAY 5 208 #define ZFC_TILTIME 6 209 #define ZONEC_MINFIELDS 3 210 #define ZONEC_MAXFIELDS 7 211 212 /* 213 ** Which files are which on a Rule line. 214 */ 215 216 #define RF_NAME 1 217 #define RF_LOYEAR 2 218 #define RF_HIYEAR 3 219 #define RF_COMMAND 4 220 #define RF_MONTH 5 221 #define RF_DAY 6 222 #define RF_TOD 7 223 #define RF_STDOFF 8 224 #define RF_ABBRVAR 9 225 #define RULE_FIELDS 10 226 227 /* 228 ** Which fields are which on a Link line. 229 */ 230 231 #define LF_FROM 1 232 #define LF_TO 2 233 #define LINK_FIELDS 3 234 235 /* 236 ** Which fields are which on a Leap line. 237 */ 238 239 #define LP_YEAR 1 240 #define LP_MONTH 2 241 #define LP_DAY 3 242 #define LP_TIME 4 243 #define LP_CORR 5 244 #define LP_ROLL 6 245 #define LEAP_FIELDS 7 246 247 /* 248 ** Year synonyms. 249 */ 250 251 #define YR_MINIMUM 0 252 #define YR_MAXIMUM 1 253 #define YR_ONLY 2 254 255 static struct rule * rules; 256 static int nrules; /* number of rules */ 257 258 static struct zone * zones; 259 static int nzones; /* number of zones */ 260 261 struct link { 262 const char * l_filename; 263 int l_linenum; 264 const char * l_from; 265 const char * l_to; 266 }; 267 268 static struct link * links; 269 static int nlinks; 270 271 struct lookup { 272 const char * l_word; 273 const int l_value; 274 }; 275 276 static struct lookup const * byword(const char * string, 277 const struct lookup * lp); 278 279 static struct lookup const line_codes[] = { 280 { "Rule", LC_RULE }, 281 { "Zone", LC_ZONE }, 282 { "Link", LC_LINK }, 283 { "Leap", LC_LEAP }, 284 { NULL, 0} 285 }; 286 287 static struct lookup const mon_names[] = { 288 { "January", TM_JANUARY }, 289 { "February", TM_FEBRUARY }, 290 { "March", TM_MARCH }, 291 { "April", TM_APRIL }, 292 { "May", TM_MAY }, 293 { "June", TM_JUNE }, 294 { "July", TM_JULY }, 295 { "August", TM_AUGUST }, 296 { "September", TM_SEPTEMBER }, 297 { "October", TM_OCTOBER }, 298 { "November", TM_NOVEMBER }, 299 { "December", TM_DECEMBER }, 300 { NULL, 0 } 301 }; 302 303 static struct lookup const wday_names[] = { 304 { "Sunday", TM_SUNDAY }, 305 { "Monday", TM_MONDAY }, 306 { "Tuesday", TM_TUESDAY }, 307 { "Wednesday", TM_WEDNESDAY }, 308 { "Thursday", TM_THURSDAY }, 309 { "Friday", TM_FRIDAY }, 310 { "Saturday", TM_SATURDAY }, 311 { NULL, 0 } 312 }; 313 314 static struct lookup const lasts[] = { 315 { "last-Sunday", TM_SUNDAY }, 316 { "last-Monday", TM_MONDAY }, 317 { "last-Tuesday", TM_TUESDAY }, 318 { "last-Wednesday", TM_WEDNESDAY }, 319 { "last-Thursday", TM_THURSDAY }, 320 { "last-Friday", TM_FRIDAY }, 321 { "last-Saturday", TM_SATURDAY }, 322 { NULL, 0 } 323 }; 324 325 static struct lookup const begin_years[] = { 326 { "minimum", YR_MINIMUM }, 327 { "maximum", YR_MAXIMUM }, 328 { NULL, 0 } 329 }; 330 331 static struct lookup const end_years[] = { 332 { "minimum", YR_MINIMUM }, 333 { "maximum", YR_MAXIMUM }, 334 { "only", YR_ONLY }, 335 { NULL, 0 } 336 }; 337 338 static struct lookup const leap_types[] = { 339 { "Rolling", TRUE }, 340 { "Stationary", FALSE }, 341 { NULL, 0 } 342 }; 343 344 static const int len_months[2][MONSPERYEAR] = { 345 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 346 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 347 }; 348 349 static const int len_years[2] = { 350 DAYSPERNYEAR, DAYSPERLYEAR 351 }; 352 353 static struct attype { 354 zic_t at; 355 unsigned char type; 356 } attypes[TZ_MAX_TIMES]; 357 static long gmtoffs[TZ_MAX_TYPES]; 358 static char isdsts[TZ_MAX_TYPES]; 359 static unsigned char abbrinds[TZ_MAX_TYPES]; 360 static char ttisstds[TZ_MAX_TYPES]; 361 static char ttisgmts[TZ_MAX_TYPES]; 362 static char chars[TZ_MAX_CHARS]; 363 static zic_t trans[TZ_MAX_LEAPS]; 364 static long corr[TZ_MAX_LEAPS]; 365 static char roll[TZ_MAX_LEAPS]; 366 367 /* 368 ** Memory allocation. 369 */ 370 371 static __pure void * 372 memcheck(void *const ptr) 373 { 374 if (ptr == NULL) { 375 const char *e = strerror(errno); 376 377 (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"), 378 progname, e); 379 exit(EXIT_FAILURE); 380 } 381 return ptr; 382 } 383 384 #define emalloc(size) memcheck(malloc(size)) 385 #define erealloc(ptr, size) memcheck(realloc((ptr), (size))) 386 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 387 #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) 388 389 /* 390 ** Error handling. 391 */ 392 393 static void 394 eats(const char *const name, const int num, const char *const rname, 395 const int rnum) 396 { 397 filename = name; 398 linenum = num; 399 rfilename = rname; 400 rlinenum = rnum; 401 } 402 403 static void 404 eat(const char *const name, const int num) 405 { 406 eats(name, num, NULL, -1); 407 } 408 409 static void 410 error(const char *const string) 411 { 412 /* 413 ** Match the format of "cc" to allow sh users to 414 ** zic ... 2>&1 | error -t "*" -v 415 ** on BSD systems. 416 */ 417 (void) fprintf(stderr, _("\"%s\", line %d: %s"), 418 filename, linenum, string); 419 if (rfilename != NULL) 420 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"), 421 rfilename, rlinenum); 422 (void) fprintf(stderr, "\n"); 423 ++errors; 424 } 425 426 static void 427 warning(const char *const string) 428 { 429 char * cp; 430 431 cp = ecpyalloc(_("warning: ")); 432 cp = ecatalloc(cp, string); 433 error(cp); 434 free(cp); 435 --errors; 436 } 437 438 static void 439 usage(FILE *stream, int status) 440 { 441 (void) fprintf(stream, _("%s: usage is %s \ 442 [ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\ 443 \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\ 444 \n\ 445 Report bugs to tz@elsie.nci.nih.gov.\n"), 446 progname, progname); 447 exit(status); 448 } 449 450 static const char * psxrules; 451 static const char * lcltime; 452 static const char * directory; 453 static const char * leapsec; 454 static const char * yitcommand; 455 456 int 457 main(int argc, char *argv[]) 458 { 459 int i; 460 int j; 461 int c; 462 463 #ifdef _POSIX_VERSION 464 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 465 #endif /* defined _POSIX_VERSION */ 466 #if HAVE_GETTEXT - 0 467 (void) setlocale(LC_MESSAGES, ""); 468 #ifdef TZ_DOMAINDIR 469 (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 470 #endif /* defined TEXTDOMAINDIR */ 471 (void) textdomain(TZ_DOMAIN); 472 #endif /* HAVE_GETTEXT */ 473 progname = argv[0]; 474 if (TYPE_BIT(zic_t) < 64) { 475 (void) fprintf(stderr, "%s: %s\n", progname, 476 _("wild compilation-time specification of zic_t")); 477 exit(EXIT_FAILURE); 478 } 479 for (i = 1; i < argc; ++i) 480 if (strcmp(argv[i], "--version") == 0) { 481 (void) printf("%s\n", TZVERSION); 482 exit(EXIT_SUCCESS); 483 } else if (strcmp(argv[i], "--help") == 0) { 484 usage(stdout, EXIT_SUCCESS); 485 } 486 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1) 487 switch (c) { 488 default: 489 usage(stderr, EXIT_FAILURE); 490 case 'd': 491 if (directory == NULL) 492 directory = optarg; 493 else { 494 (void) fprintf(stderr, 495 _("%s: More than one -d option specified\n"), 496 progname); 497 exit(EXIT_FAILURE); 498 } 499 break; 500 case 'l': 501 if (lcltime == NULL) 502 lcltime = optarg; 503 else { 504 (void) fprintf(stderr, 505 _("%s: More than one -l option specified\n"), 506 progname); 507 exit(EXIT_FAILURE); 508 } 509 break; 510 case 'p': 511 if (psxrules == NULL) 512 psxrules = optarg; 513 else { 514 (void) fprintf(stderr, 515 _("%s: More than one -p option specified\n"), 516 progname); 517 exit(EXIT_FAILURE); 518 } 519 break; 520 case 'y': 521 if (yitcommand == NULL) 522 yitcommand = optarg; 523 else { 524 (void) fprintf(stderr, 525 _("%s: More than one -y option specified\n"), 526 progname); 527 exit(EXIT_FAILURE); 528 } 529 break; 530 case 'L': 531 if (leapsec == NULL) 532 leapsec = optarg; 533 else { 534 (void) fprintf(stderr, 535 _("%s: More than one -L option specified\n"), 536 progname); 537 exit(EXIT_FAILURE); 538 } 539 break; 540 case 'v': 541 noise = TRUE; 542 break; 543 case 's': 544 (void) printf("%s: -s ignored\n", progname); 545 break; 546 } 547 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 548 usage(stderr, EXIT_FAILURE); /* usage message by request */ 549 if (directory == NULL) 550 directory = TZDIR; 551 if (yitcommand == NULL) 552 yitcommand = "yearistype"; 553 554 if (optind < argc && leapsec != NULL) { 555 infile(leapsec); 556 adjleap(); 557 } 558 559 for (i = optind; i < argc; ++i) 560 infile(argv[i]); 561 if (errors) 562 exit(EXIT_FAILURE); 563 associate(); 564 for (i = 0; i < nzones; i = j) { 565 /* 566 ** Find the next non-continuation zone entry. 567 */ 568 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 569 continue; 570 outzone(&zones[i], j - i); 571 } 572 /* 573 ** Make links. 574 */ 575 for (i = 0; i < nlinks; ++i) { 576 eat(links[i].l_filename, links[i].l_linenum); 577 dolink(links[i].l_from, links[i].l_to); 578 if (noise) 579 for (j = 0; j < nlinks; ++j) 580 if (strcmp(links[i].l_to, 581 links[j].l_from) == 0) 582 warning(_("link to link")); 583 } 584 if (lcltime != NULL) { 585 eat("command line", 1); 586 dolink(lcltime, TZDEFAULT); 587 } 588 if (psxrules != NULL) { 589 eat("command line", 1); 590 dolink(psxrules, TZDEFRULES); 591 } 592 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 593 } 594 595 static void 596 dolink(const char *const fromfield, const char *const tofield) 597 { 598 char * fromname; 599 char * toname; 600 601 if (fromfield[0] == '/') 602 fromname = ecpyalloc(fromfield); 603 else { 604 fromname = ecpyalloc(directory); 605 fromname = ecatalloc(fromname, "/"); 606 fromname = ecatalloc(fromname, fromfield); 607 } 608 if (tofield[0] == '/') 609 toname = ecpyalloc(tofield); 610 else { 611 toname = ecpyalloc(directory); 612 toname = ecatalloc(toname, "/"); 613 toname = ecatalloc(toname, tofield); 614 } 615 /* 616 ** We get to be careful here since 617 ** there's a fair chance of root running us. 618 */ 619 if (!itsdir(toname)) 620 (void) remove(toname); 621 if (link(fromname, toname) != 0) { 622 int result; 623 624 if (mkdirs(toname) != 0) 625 exit(EXIT_FAILURE); 626 627 result = link(fromname, toname); 628 #if HAVE_SYMLINK 629 if (result != 0 && 630 access(fromname, F_OK) == 0 && 631 !itsdir(fromname)) { 632 const char *s = tofield; 633 char * symlinkcontents = NULL; 634 635 while ((s = strchr(s+1, '/')) != NULL) 636 symlinkcontents = 637 ecatalloc(symlinkcontents, 638 "../"); 639 symlinkcontents = 640 ecatalloc(symlinkcontents, 641 fromname); 642 result = symlink(symlinkcontents, 643 toname); 644 if (result == 0) 645 warning(_("hard link failed, symbolic link used")); 646 free(symlinkcontents); 647 } 648 #endif /* HAVE_SYMLINK */ 649 if (result != 0) { 650 const char *e = strerror(errno); 651 652 (void) fprintf(stderr, 653 _("%s: Can't link from %s to %s: %s\n"), 654 progname, fromname, toname, e); 655 exit(EXIT_FAILURE); 656 } 657 } 658 free(fromname); 659 free(toname); 660 } 661 662 #define TIME_T_BITS_IN_FILE 64 663 static const zic_t min_time = (zic_t) -1 << (TIME_T_BITS_IN_FILE - 1); 664 static const zic_t max_time = -1 - ((zic_t) -1 << (TIME_T_BITS_IN_FILE - 1)); 665 666 static int 667 itsdir(const char *const name) 668 { 669 char * myname; 670 int accres; 671 672 myname = ecpyalloc(name); 673 myname = ecatalloc(myname, "/."); 674 accres = access(myname, F_OK); 675 free(myname); 676 return accres == 0; 677 } 678 679 /* 680 ** Associate sets of rules with zones. 681 */ 682 683 /* 684 ** Sort by rule name. 685 */ 686 687 static int 688 rcomp(const void *cp1, const void *cp2) 689 { 690 return strcmp(((const struct rule *) cp1)->r_name, 691 ((const struct rule *) cp2)->r_name); 692 } 693 694 static void 695 associate(void) 696 { 697 struct zone * zp; 698 struct rule * rp; 699 int base, out; 700 int i, j; 701 702 if (nrules != 0) { 703 (void) qsort(rules, (size_t)nrules, sizeof *rules, rcomp); 704 for (i = 0; i < nrules - 1; ++i) { 705 if (strcmp(rules[i].r_name, 706 rules[i + 1].r_name) != 0) 707 continue; 708 if (strcmp(rules[i].r_filename, 709 rules[i + 1].r_filename) == 0) 710 continue; 711 eat(rules[i].r_filename, rules[i].r_linenum); 712 warning(_("same rule name in multiple files")); 713 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 714 warning(_("same rule name in multiple files")); 715 for (j = i + 2; j < nrules; ++j) { 716 if (strcmp(rules[i].r_name, 717 rules[j].r_name) != 0) 718 break; 719 if (strcmp(rules[i].r_filename, 720 rules[j].r_filename) == 0) 721 continue; 722 if (strcmp(rules[i + 1].r_filename, 723 rules[j].r_filename) == 0) 724 continue; 725 break; 726 } 727 i = j - 1; 728 } 729 } 730 for (i = 0; i < nzones; ++i) { 731 zp = &zones[i]; 732 zp->z_rules = NULL; 733 zp->z_nrules = 0; 734 } 735 for (base = 0; base < nrules; base = out) { 736 rp = &rules[base]; 737 for (out = base + 1; out < nrules; ++out) 738 if (strcmp(rp->r_name, rules[out].r_name) != 0) 739 break; 740 for (i = 0; i < nzones; ++i) { 741 zp = &zones[i]; 742 if (strcmp(zp->z_rule, rp->r_name) != 0) 743 continue; 744 zp->z_rules = rp; 745 zp->z_nrules = out - base; 746 } 747 } 748 for (i = 0; i < nzones; ++i) { 749 zp = &zones[i]; 750 if (zp->z_nrules == 0) { 751 /* 752 ** Maybe we have a local standard time offset. 753 */ 754 eat(zp->z_filename, zp->z_linenum); 755 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"), 756 TRUE); 757 /* 758 ** Note, though, that if there's no rule, 759 ** a '%s' in the format is a bad thing. 760 */ 761 if (strchr(zp->z_format, '%') != 0) 762 error(_("%s in ruleless zone")); 763 } 764 } 765 if (errors) 766 exit(EXIT_FAILURE); 767 } 768 769 static void 770 infile(const char *name) 771 { 772 FILE * fp; 773 char ** fields; 774 char * cp; 775 const struct lookup * lp; 776 int nfields; 777 int wantcont; 778 int num; 779 char buf[BUFSIZ]; 780 781 if (strcmp(name, "-") == 0) { 782 name = _("standard input"); 783 fp = stdin; 784 } else if ((fp = fopen(name, "r")) == NULL) { 785 const char *e = strerror(errno); 786 787 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"), 788 progname, name, e); 789 exit(EXIT_FAILURE); 790 } 791 wantcont = FALSE; 792 for (num = 1; ; ++num) { 793 eat(name, num); 794 if (fgets(buf, (int) sizeof buf, fp) != buf) 795 break; 796 cp = strchr(buf, '\n'); 797 if (cp == NULL) { 798 error(_("line too long")); 799 exit(EXIT_FAILURE); 800 } 801 *cp = '\0'; 802 fields = getfields(buf); 803 nfields = 0; 804 while (fields[nfields] != NULL) { 805 static char nada; 806 807 if (strcmp(fields[nfields], "-") == 0) 808 fields[nfields] = &nada; 809 ++nfields; 810 } 811 if (nfields == 0) { 812 /* nothing to do */ 813 } else if (wantcont) { 814 wantcont = inzcont(fields, nfields); 815 } else { 816 lp = byword(fields[0], line_codes); 817 if (lp == NULL) 818 error(_("input line of unknown type")); 819 else switch ((int) (lp->l_value)) { 820 case LC_RULE: 821 inrule(fields, nfields); 822 wantcont = FALSE; 823 break; 824 case LC_ZONE: 825 wantcont = inzone(fields, nfields); 826 break; 827 case LC_LINK: 828 inlink(fields, nfields); 829 wantcont = FALSE; 830 break; 831 case LC_LEAP: 832 if (name != leapsec) 833 (void) fprintf(stderr, 834 _("%s: Leap line in non leap seconds file %s\n"), 835 progname, name); 836 else inleap(fields, nfields); 837 wantcont = FALSE; 838 break; 839 default: /* "cannot happen" */ 840 (void) fprintf(stderr, 841 _("%s: panic: Invalid l_value %d\n"), 842 progname, lp->l_value); 843 exit(EXIT_FAILURE); 844 } 845 } 846 free(fields); 847 } 848 if (ferror(fp)) { 849 (void) fprintf(stderr, _("%s: Error reading %s\n"), 850 progname, filename); 851 exit(EXIT_FAILURE); 852 } 853 if (fp != stdin && fclose(fp)) { 854 const char *e = strerror(errno); 855 856 (void) fprintf(stderr, _("%s: Error closing %s: %s\n"), 857 progname, filename, e); 858 exit(EXIT_FAILURE); 859 } 860 if (wantcont) 861 error(_("expected continuation line not found")); 862 } 863 864 /* 865 ** Convert a string of one of the forms 866 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 867 ** into a number of seconds. 868 ** A null string maps to zero. 869 ** Call error with errstring and return zero on errors. 870 */ 871 872 static long 873 gethms(const char *string, const char *const errstring, const int signable) 874 { 875 long hh; 876 int mm, ss, sign; 877 878 if (string == NULL || *string == '\0') 879 return 0; 880 if (!signable) 881 sign = 1; 882 else if (*string == '-') { 883 sign = -1; 884 ++string; 885 } else sign = 1; 886 if (sscanf(string, scheck(string, "%ld"), &hh) == 1) 887 mm = ss = 0; 888 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2) 889 ss = 0; 890 else if (sscanf(string, scheck(string, "%ld:%d:%d"), 891 &hh, &mm, &ss) != 3) { 892 error(errstring); 893 return 0; 894 } 895 if (hh < 0 || 896 mm < 0 || mm >= MINSPERHOUR || 897 ss < 0 || ss > SECSPERMIN) { 898 error(errstring); 899 return 0; 900 } 901 if (LONG_MAX / SECSPERHOUR < hh) { 902 error(_("time overflow")); 903 return 0; 904 } 905 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) 906 warning(_("24:00 not handled by pre-1998 versions of zic")); 907 if (noise && (hh > HOURSPERDAY || 908 (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 909 warning(_("values over 24 hours not handled by pre-2007 versions of zic")); 910 return oadd(eitol(sign) * hh * eitol(SECSPERHOUR), 911 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))); 912 } 913 914 static void 915 inrule(char **const fields, const int nfields) 916 { 917 static struct rule r; 918 919 if (nfields != RULE_FIELDS) { 920 error(_("wrong number of fields on Rule line")); 921 return; 922 } 923 if (*fields[RF_NAME] == '\0') { 924 error(_("nameless rule")); 925 return; 926 } 927 r.r_filename = filename; 928 r.r_linenum = linenum; 929 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE); 930 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 931 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 932 r.r_name = ecpyalloc(fields[RF_NAME]); 933 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 934 if (max_abbrvar_len < strlen(r.r_abbrvar)) 935 max_abbrvar_len = strlen(r.r_abbrvar); 936 rules = erealloc(rules, (nrules + 1) * sizeof *rules); 937 rules[nrules++] = r; 938 } 939 940 static int 941 inzone(char **const fields, const int nfields) 942 { 943 int i; 944 static char * buf; 945 946 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 947 error(_("wrong number of fields on Zone line")); 948 return FALSE; 949 } 950 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 951 buf = erealloc(buf, 132 + strlen(TZDEFAULT)); 952 (void)sprintf(buf, /* XXX: sprintf is safe */ 953 _("\"Zone %s\" line and -l option are mutually exclusive"), 954 TZDEFAULT); 955 error(buf); 956 return FALSE; 957 } 958 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 959 buf = erealloc(buf, 132 + strlen(TZDEFRULES)); 960 (void)sprintf(buf, /* XXX: sprintf is safe */ 961 _("\"Zone %s\" line and -p option are mutually exclusive"), 962 TZDEFRULES); 963 error(buf); 964 return FALSE; 965 } 966 for (i = 0; i < nzones; ++i) 967 if (zones[i].z_name != NULL && 968 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 969 buf = erealloc(buf, 132 + 970 strlen(fields[ZF_NAME]) + 971 strlen(zones[i].z_filename)); 972 (void)sprintf(buf, /* XXX: sprintf is safe */ 973 _("duplicate zone name %s (file \"%s\", line %d)"), 974 fields[ZF_NAME], 975 zones[i].z_filename, 976 zones[i].z_linenum); 977 error(buf); 978 return FALSE; 979 } 980 return inzsub(fields, nfields, FALSE); 981 } 982 983 static int 984 inzcont(char **const fields, const int nfields) 985 { 986 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 987 error(_("wrong number of fields on Zone continuation line")); 988 return FALSE; 989 } 990 return inzsub(fields, nfields, TRUE); 991 } 992 993 static int 994 inzsub(char **const fields, const int nfields, const int iscont) 995 { 996 char * cp; 997 static struct zone z; 998 int i_gmtoff, i_rule, i_format; 999 int i_untilyear, i_untilmonth; 1000 int i_untilday, i_untiltime; 1001 int hasuntil; 1002 1003 if (iscont) { 1004 i_gmtoff = ZFC_GMTOFF; 1005 i_rule = ZFC_RULE; 1006 i_format = ZFC_FORMAT; 1007 i_untilyear = ZFC_TILYEAR; 1008 i_untilmonth = ZFC_TILMONTH; 1009 i_untilday = ZFC_TILDAY; 1010 i_untiltime = ZFC_TILTIME; 1011 z.z_name = NULL; 1012 } else { 1013 i_gmtoff = ZF_GMTOFF; 1014 i_rule = ZF_RULE; 1015 i_format = ZF_FORMAT; 1016 i_untilyear = ZF_TILYEAR; 1017 i_untilmonth = ZF_TILMONTH; 1018 i_untilday = ZF_TILDAY; 1019 i_untiltime = ZF_TILTIME; 1020 z.z_name = ecpyalloc(fields[ZF_NAME]); 1021 } 1022 z.z_filename = filename; 1023 z.z_linenum = linenum; 1024 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE); 1025 if ((cp = strchr(fields[i_format], '%')) != 0) { 1026 if (*++cp != 's' || strchr(cp, '%') != 0) { 1027 error(_("invalid abbreviation format")); 1028 return FALSE; 1029 } 1030 } 1031 z.z_rule = ecpyalloc(fields[i_rule]); 1032 z.z_format = ecpyalloc(fields[i_format]); 1033 if (max_format_len < strlen(z.z_format)) 1034 max_format_len = strlen(z.z_format); 1035 hasuntil = nfields > i_untilyear; 1036 if (hasuntil) { 1037 z.z_untilrule.r_filename = filename; 1038 z.z_untilrule.r_linenum = linenum; 1039 rulesub(&z.z_untilrule, 1040 fields[i_untilyear], 1041 "only", 1042 "", 1043 (nfields > i_untilmonth) ? 1044 fields[i_untilmonth] : "Jan", 1045 (nfields > i_untilday) ? fields[i_untilday] : "1", 1046 (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 1047 z.z_untiltime = rpytime(&z.z_untilrule, 1048 z.z_untilrule.r_loyear); 1049 if (iscont && nzones > 0 && 1050 z.z_untiltime > min_time && 1051 z.z_untiltime < max_time && 1052 zones[nzones - 1].z_untiltime > min_time && 1053 zones[nzones - 1].z_untiltime < max_time && 1054 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1055 error(_( 1056 "Zone continuation line end time is not after end time of previous line" 1057 )); 1058 return FALSE; 1059 } 1060 } 1061 zones = erealloc(zones, (nzones + 1) * sizeof *zones); 1062 zones[nzones++] = z; 1063 /* 1064 ** If there was an UNTIL field on this line, 1065 ** there's more information about the zone on the next line. 1066 */ 1067 return hasuntil; 1068 } 1069 1070 static void 1071 inleap(char **const fields, const int nfields) 1072 { 1073 const char * cp; 1074 const struct lookup * lp; 1075 int i, j; 1076 int year, month, day; 1077 long dayoff, tod; 1078 zic_t t; 1079 1080 if (nfields != LEAP_FIELDS) { 1081 error(_("wrong number of fields on Leap line")); 1082 return; 1083 } 1084 dayoff = 0; 1085 cp = fields[LP_YEAR]; 1086 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 1087 /* 1088 ** Leapin' Lizards! 1089 */ 1090 error(_("invalid leaping year")); 1091 return; 1092 } 1093 if (!leapseen || leapmaxyear < year) 1094 leapmaxyear = year; 1095 if (!leapseen || leapminyear > year) 1096 leapminyear = year; 1097 leapseen = TRUE; 1098 j = EPOCH_YEAR; 1099 while (j != year) { 1100 if (year > j) { 1101 i = len_years[isleap(j)]; 1102 ++j; 1103 } else { 1104 --j; 1105 i = -len_years[isleap(j)]; 1106 } 1107 dayoff = oadd(dayoff, eitol(i)); 1108 } 1109 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1110 error(_("invalid month name")); 1111 return; 1112 } 1113 month = lp->l_value; 1114 j = TM_JANUARY; 1115 while (j != month) { 1116 i = len_months[isleap(year)][j]; 1117 dayoff = oadd(dayoff, eitol(i)); 1118 ++j; 1119 } 1120 cp = fields[LP_DAY]; 1121 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 1122 day <= 0 || day > len_months[isleap(year)][month]) { 1123 error(_("invalid day of month")); 1124 return; 1125 } 1126 dayoff = oadd(dayoff, eitol(day - 1)); 1127 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) { 1128 error(_("time before zero")); 1129 return; 1130 } 1131 if (dayoff < min_time / SECSPERDAY) { 1132 error(_("time too small")); 1133 return; 1134 } 1135 if (dayoff > max_time / SECSPERDAY) { 1136 error(_("time too large")); 1137 return; 1138 } 1139 t = (zic_t) dayoff * SECSPERDAY; 1140 tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE); 1141 cp = fields[LP_CORR]; 1142 { 1143 int positive; 1144 int count; 1145 1146 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 1147 positive = FALSE; 1148 count = 1; 1149 } else if (strcmp(cp, "--") == 0) { 1150 positive = FALSE; 1151 count = 2; 1152 } else if (strcmp(cp, "+") == 0) { 1153 positive = TRUE; 1154 count = 1; 1155 } else if (strcmp(cp, "++") == 0) { 1156 positive = TRUE; 1157 count = 2; 1158 } else { 1159 error(_("illegal CORRECTION field on Leap line")); 1160 return; 1161 } 1162 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1163 error(_( 1164 "illegal Rolling/Stationary field on Leap line" 1165 )); 1166 return; 1167 } 1168 leapadd(tadd(t, tod), positive, lp->l_value, count); 1169 } 1170 } 1171 1172 static void 1173 inlink(char **const fields, const int nfields) 1174 { 1175 struct link l; 1176 1177 if (nfields != LINK_FIELDS) { 1178 error(_("wrong number of fields on Link line")); 1179 return; 1180 } 1181 if (*fields[LF_FROM] == '\0') { 1182 error(_("blank FROM field on Link line")); 1183 return; 1184 } 1185 if (*fields[LF_TO] == '\0') { 1186 error(_("blank TO field on Link line")); 1187 return; 1188 } 1189 l.l_filename = filename; 1190 l.l_linenum = linenum; 1191 l.l_from = ecpyalloc(fields[LF_FROM]); 1192 l.l_to = ecpyalloc(fields[LF_TO]); 1193 links = erealloc(links, (nlinks + 1) * sizeof *links); 1194 links[nlinks++] = l; 1195 } 1196 1197 static void 1198 rulesub(struct rule *const rp, const char *const loyearp, 1199 const char *const hiyearp, const char *const typep, 1200 const char *const monthp, const char *const dayp, const char *const timep) 1201 { 1202 const struct lookup * lp; 1203 const char * cp; 1204 char * dp; 1205 char * ep; 1206 1207 if ((lp = byword(monthp, mon_names)) == NULL) { 1208 error(_("invalid month name")); 1209 return; 1210 } 1211 rp->r_month = lp->l_value; 1212 rp->r_todisstd = FALSE; 1213 rp->r_todisgmt = FALSE; 1214 dp = ecpyalloc(timep); 1215 if (*dp != '\0') { 1216 ep = dp + strlen(dp) - 1; 1217 switch (lowerit(*ep)) { 1218 case 's': /* Standard */ 1219 rp->r_todisstd = TRUE; 1220 rp->r_todisgmt = FALSE; 1221 *ep = '\0'; 1222 break; 1223 case 'w': /* Wall */ 1224 rp->r_todisstd = FALSE; 1225 rp->r_todisgmt = FALSE; 1226 *ep = '\0'; 1227 break; 1228 case 'g': /* Greenwich */ 1229 case 'u': /* Universal */ 1230 case 'z': /* Zulu */ 1231 rp->r_todisstd = TRUE; 1232 rp->r_todisgmt = TRUE; 1233 *ep = '\0'; 1234 break; 1235 } 1236 } 1237 rp->r_tod = gethms(dp, _("invalid time of day"), FALSE); 1238 free(dp); 1239 /* 1240 ** Year work. 1241 */ 1242 cp = loyearp; 1243 lp = byword(cp, begin_years); 1244 rp->r_lowasnum = lp == NULL; 1245 if (!rp->r_lowasnum) switch ((int) lp->l_value) { 1246 case YR_MINIMUM: 1247 rp->r_loyear = INT_MIN; 1248 break; 1249 case YR_MAXIMUM: 1250 rp->r_loyear = INT_MAX; 1251 break; 1252 default: /* "cannot happen" */ 1253 (void) fprintf(stderr, 1254 _("%s: panic: Invalid l_value %d\n"), 1255 progname, lp->l_value); 1256 exit(EXIT_FAILURE); 1257 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 1258 error(_("invalid starting year")); 1259 return; 1260 } 1261 cp = hiyearp; 1262 lp = byword(cp, end_years); 1263 rp->r_hiwasnum = lp == NULL; 1264 if (!rp->r_hiwasnum) switch ((int) lp->l_value) { 1265 case YR_MINIMUM: 1266 rp->r_hiyear = INT_MIN; 1267 break; 1268 case YR_MAXIMUM: 1269 rp->r_hiyear = INT_MAX; 1270 break; 1271 case YR_ONLY: 1272 rp->r_hiyear = rp->r_loyear; 1273 break; 1274 default: /* "cannot happen" */ 1275 (void) fprintf(stderr, 1276 _("%s: panic: Invalid l_value %d\n"), 1277 progname, lp->l_value); 1278 exit(EXIT_FAILURE); 1279 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 1280 error(_("invalid ending year")); 1281 return; 1282 } 1283 if (rp->r_loyear > rp->r_hiyear) { 1284 error(_("starting year greater than ending year")); 1285 return; 1286 } 1287 if (*typep == '\0') 1288 rp->r_yrtype = NULL; 1289 else { 1290 if (rp->r_loyear == rp->r_hiyear) { 1291 error(_("typed single year")); 1292 return; 1293 } 1294 rp->r_yrtype = ecpyalloc(typep); 1295 } 1296 /* 1297 ** Day work. 1298 ** Accept things such as: 1299 ** 1 1300 ** last-Sunday 1301 ** Sun<=20 1302 ** Sun>=7 1303 */ 1304 dp = ecpyalloc(dayp); 1305 if ((lp = byword(dp, lasts)) != NULL) { 1306 rp->r_dycode = DC_DOWLEQ; 1307 rp->r_wday = lp->l_value; 1308 rp->r_dayofmonth = len_months[1][rp->r_month]; 1309 } else { 1310 if ((ep = strchr(dp, '<')) != 0) 1311 rp->r_dycode = DC_DOWLEQ; 1312 else if ((ep = strchr(dp, '>')) != 0) 1313 rp->r_dycode = DC_DOWGEQ; 1314 else { 1315 ep = dp; 1316 rp->r_dycode = DC_DOM; 1317 } 1318 if (rp->r_dycode != DC_DOM) { 1319 *ep++ = 0; 1320 if (*ep++ != '=') { 1321 error(_("invalid day of month")); 1322 free(dp); 1323 return; 1324 } 1325 if ((lp = byword(dp, wday_names)) == NULL) { 1326 error(_("invalid weekday name")); 1327 free(dp); 1328 return; 1329 } 1330 rp->r_wday = lp->l_value; 1331 } 1332 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || 1333 rp->r_dayofmonth <= 0 || 1334 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1335 error(_("invalid day of month")); 1336 free(dp); 1337 return; 1338 } 1339 } 1340 free(dp); 1341 } 1342 1343 static void 1344 convert(const long val, char *const buf) 1345 { 1346 int i; 1347 int shift; 1348 unsigned char *const b = (unsigned char *) buf; 1349 1350 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1351 b[i] = val >> shift; 1352 } 1353 1354 static void 1355 convert64(const zic_t val, char *const buf) 1356 { 1357 int i; 1358 int shift; 1359 unsigned char *const b = (unsigned char *) buf; 1360 1361 for (i = 0, shift = 56; i < 8; ++i, shift -= 8) 1362 b[i] = val >> shift; 1363 } 1364 1365 static void 1366 puttzcode(const long val, FILE *const fp) 1367 { 1368 char buf[4]; 1369 1370 convert(val, buf); 1371 (void) fwrite(buf, sizeof buf, (size_t) 1, fp); 1372 } 1373 1374 static void 1375 puttzcode64(const zic_t val, FILE *const fp) 1376 { 1377 char buf[8]; 1378 1379 convert64(val, buf); 1380 (void) fwrite(buf, sizeof buf, (size_t) 1, fp); 1381 } 1382 1383 static int 1384 atcomp(const void *avp, const void *bvp) 1385 { 1386 const zic_t a = ((const struct attype *) avp)->at; 1387 const zic_t b = ((const struct attype *) bvp)->at; 1388 1389 return (a < b) ? -1 : (a > b); 1390 } 1391 1392 static int 1393 is32(const zic_t x) 1394 { 1395 return INT32_MIN <= x && x <= INT32_MAX; 1396 } 1397 1398 static void 1399 writezone(const char *const name, const char *const string) 1400 { 1401 FILE * fp; 1402 int i, j; 1403 int leapcnt32, leapi32; 1404 int timecnt32, timei32; 1405 int pass; 1406 static char * fullname; 1407 static const struct tzhead tzh0; 1408 static struct tzhead tzh; 1409 zic_t ats[TZ_MAX_TIMES]; 1410 unsigned char types[TZ_MAX_TIMES]; 1411 1412 /* 1413 ** Sort. 1414 */ 1415 if (timecnt > 1) 1416 (void) qsort(attypes, (size_t) timecnt, sizeof *attypes, 1417 atcomp); 1418 /* 1419 ** Optimize. 1420 */ 1421 { 1422 int fromi; 1423 int toi; 1424 1425 toi = 0; 1426 fromi = 0; 1427 while (fromi < timecnt && attypes[fromi].at < min_time) 1428 ++fromi; 1429 if (isdsts[0] == 0) 1430 while (fromi < timecnt && attypes[fromi].type == 0) 1431 ++fromi; /* handled by default rule */ 1432 for ( ; fromi < timecnt; ++fromi) { 1433 if (toi != 0 && ((attypes[fromi].at + 1434 gmtoffs[attypes[toi - 1].type]) <= 1435 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 1436 : attypes[toi - 2].type]))) { 1437 attypes[toi - 1].type = 1438 attypes[fromi].type; 1439 continue; 1440 } 1441 if (toi == 0 || 1442 attypes[toi - 1].type != attypes[fromi].type) 1443 attypes[toi++] = attypes[fromi]; 1444 } 1445 timecnt = toi; 1446 } 1447 /* 1448 ** Transfer. 1449 */ 1450 for (i = 0; i < timecnt; ++i) { 1451 ats[i] = attypes[i].at; 1452 types[i] = attypes[i].type; 1453 } 1454 /* 1455 ** Correct for leap seconds. 1456 */ 1457 for (i = 0; i < timecnt; ++i) { 1458 j = leapcnt; 1459 while (--j >= 0) 1460 if (ats[i] > trans[j] - corr[j]) { 1461 ats[i] = tadd(ats[i], corr[j]); 1462 break; 1463 } 1464 } 1465 /* 1466 ** Figure out 32-bit-limited starts and counts. 1467 */ 1468 timecnt32 = timecnt; 1469 timei32 = 0; 1470 leapcnt32 = leapcnt; 1471 leapi32 = 0; 1472 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1])) 1473 --timecnt32; 1474 while (timecnt32 > 0 && !is32(ats[timei32])) { 1475 --timecnt32; 1476 ++timei32; 1477 } 1478 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1])) 1479 --leapcnt32; 1480 while (leapcnt32 > 0 && !is32(trans[leapi32])) { 1481 --leapcnt32; 1482 ++leapi32; 1483 } 1484 fullname = erealloc(fullname, 1485 strlen(directory) + 1 + strlen(name) + 1); 1486 (void) sprintf(fullname, "%s/%s", directory, name); /* XXX: sprintf is safe */ 1487 /* 1488 ** Remove old file, if any, to snap links. 1489 */ 1490 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) { 1491 const char *e = strerror(errno); 1492 1493 (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"), 1494 progname, fullname, e); 1495 exit(EXIT_FAILURE); 1496 } 1497 if ((fp = fopen(fullname, "wb")) == NULL) { 1498 if (mkdirs(fullname) != 0) 1499 exit(EXIT_FAILURE); 1500 if ((fp = fopen(fullname, "wb")) == NULL) { 1501 const char *e = strerror(errno); 1502 1503 (void) fprintf(stderr, _("%s: Can't create %s: %s\n"), 1504 progname, fullname, e); 1505 exit(EXIT_FAILURE); 1506 } 1507 } 1508 for (pass = 1; pass <= 2; ++pass) { 1509 int thistimei, thistimecnt; 1510 int thisleapi, thisleapcnt; 1511 int thistimelim, thisleaplim; 1512 int writetype[TZ_MAX_TIMES]; 1513 int typemap[TZ_MAX_TYPES]; 1514 int thistypecnt; 1515 char thischars[TZ_MAX_CHARS]; 1516 char thischarcnt; 1517 int indmap[TZ_MAX_CHARS]; 1518 1519 if (pass == 1) { 1520 thistimei = timei32; 1521 thistimecnt = timecnt32; 1522 thisleapi = leapi32; 1523 thisleapcnt = leapcnt32; 1524 } else { 1525 thistimei = 0; 1526 thistimecnt = timecnt; 1527 thisleapi = 0; 1528 thisleapcnt = leapcnt; 1529 } 1530 thistimelim = thistimei + thistimecnt; 1531 thisleaplim = thisleapi + thisleapcnt; 1532 for (i = 0; i < typecnt; ++i) 1533 writetype[i] = thistimecnt == timecnt; 1534 if (thistimecnt == 0) { 1535 /* 1536 ** No transition times fall in the current 1537 ** (32- or 64-bit) window. 1538 */ 1539 if (typecnt != 0) 1540 writetype[typecnt - 1] = TRUE; 1541 } else { 1542 for (i = thistimei - 1; i < thistimelim; ++i) 1543 if (i >= 0) 1544 writetype[types[i]] = TRUE; 1545 /* 1546 ** For America/Godthab and Antarctica/Palmer 1547 */ 1548 if (thistimei == 0) 1549 writetype[0] = TRUE; 1550 } 1551 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH 1552 /* 1553 ** For some pre-2011 systems: if the last-to-be-written 1554 ** standard (or daylight) type has an offset different from the 1555 ** most recently used offset, 1556 ** append an (unused) copy of the most recently used type 1557 ** (to help get global "altzone" and "timezone" variables 1558 ** set correctly). 1559 */ 1560 { 1561 int mrudst, mrustd, hidst, histd, type; 1562 1563 hidst = histd = mrudst = mrustd = -1; 1564 for (i = thistimei; i < thistimelim; ++i) 1565 if (isdsts[types[i]]) 1566 mrudst = types[i]; 1567 else mrustd = types[i]; 1568 for (i = 0; i < typecnt; ++i) 1569 if (writetype[i]) { 1570 if (isdsts[i]) 1571 hidst = i; 1572 else histd = i; 1573 } 1574 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && 1575 gmtoffs[hidst] != gmtoffs[mrudst]) { 1576 isdsts[mrudst] = -1; 1577 type = addtype(gmtoffs[mrudst], 1578 &chars[abbrinds[mrudst]], 1579 TRUE, 1580 ttisstds[mrudst], 1581 ttisgmts[mrudst]); 1582 isdsts[mrudst] = TRUE; 1583 writetype[type] = TRUE; 1584 } 1585 if (histd >= 0 && mrustd >= 0 && histd != mrustd && 1586 gmtoffs[histd] != gmtoffs[mrustd]) { 1587 isdsts[mrustd] = -1; 1588 type = addtype(gmtoffs[mrustd], 1589 &chars[abbrinds[mrustd]], 1590 FALSE, 1591 ttisstds[mrustd], 1592 ttisgmts[mrustd]); 1593 isdsts[mrustd] = FALSE; 1594 writetype[type] = TRUE; 1595 } 1596 } 1597 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ 1598 thistypecnt = 0; 1599 for (i = 0; i < typecnt; ++i) 1600 typemap[i] = writetype[i] ? thistypecnt++ : -1; 1601 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i) 1602 indmap[i] = -1; 1603 thischarcnt = 0; 1604 for (i = 0; i < typecnt; ++i) { 1605 char * thisabbr; 1606 1607 if (!writetype[i]) 1608 continue; 1609 if (indmap[abbrinds[i]] >= 0) 1610 continue; 1611 thisabbr = &chars[abbrinds[i]]; 1612 for (j = 0; j < thischarcnt; ++j) 1613 if (strcmp(&thischars[j], thisabbr) == 0) 1614 break; 1615 if (j == thischarcnt) { 1616 (void) strcpy(&thischars[(int) thischarcnt], 1617 thisabbr); 1618 thischarcnt += strlen(thisabbr) + 1; 1619 } 1620 indmap[abbrinds[i]] = j; 1621 } 1622 #define DO(field) (void) fwrite(tzh.field, \ 1623 sizeof tzh.field, (size_t) 1, fp) 1624 tzh = tzh0; 1625 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); 1626 tzh.tzh_version[0] = ZIC_VERSION; 1627 convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt); 1628 convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt); 1629 convert(eitol(thisleapcnt), tzh.tzh_leapcnt); 1630 convert(eitol(thistimecnt), tzh.tzh_timecnt); 1631 convert(eitol(thistypecnt), tzh.tzh_typecnt); 1632 convert(eitol(thischarcnt), tzh.tzh_charcnt); 1633 DO(tzh_magic); 1634 DO(tzh_version); 1635 DO(tzh_reserved); 1636 DO(tzh_ttisgmtcnt); 1637 DO(tzh_ttisstdcnt); 1638 DO(tzh_leapcnt); 1639 DO(tzh_timecnt); 1640 DO(tzh_typecnt); 1641 DO(tzh_charcnt); 1642 #undef DO 1643 for (i = thistimei; i < thistimelim; ++i) 1644 if (pass == 1) 1645 puttzcode(ats[i], fp); 1646 else puttzcode64(ats[i], fp); 1647 for (i = thistimei; i < thistimelim; ++i) { 1648 unsigned char uc; 1649 1650 uc = typemap[types[i]]; 1651 (void) fwrite(&uc, sizeof uc, (size_t) 1, fp); 1652 } 1653 for (i = 0; i < typecnt; ++i) 1654 if (writetype[i]) { 1655 puttzcode(gmtoffs[i], fp); 1656 (void) putc(isdsts[i], fp); 1657 (void) putc((unsigned char) indmap[abbrinds[i]], fp); 1658 } 1659 if (thischarcnt != 0) 1660 (void) fwrite(thischars, sizeof thischars[0], 1661 (size_t) thischarcnt, fp); 1662 for (i = thisleapi; i < thisleaplim; ++i) { 1663 zic_t todo; 1664 1665 if (roll[i]) { 1666 if (timecnt == 0 || trans[i] < ats[0]) { 1667 j = 0; 1668 while (isdsts[j]) 1669 if (++j >= typecnt) { 1670 j = 0; 1671 break; 1672 } 1673 } else { 1674 j = 1; 1675 while (j < timecnt && 1676 trans[i] >= ats[j]) 1677 ++j; 1678 j = types[j - 1]; 1679 } 1680 todo = tadd(trans[i], -gmtoffs[j]); 1681 } else todo = trans[i]; 1682 if (pass == 1) 1683 puttzcode((long) todo, fp); 1684 else puttzcode64(todo, fp); 1685 puttzcode(corr[i], fp); 1686 } 1687 for (i = 0; i < typecnt; ++i) 1688 if (writetype[i]) 1689 (void) putc(ttisstds[i], fp); 1690 for (i = 0; i < typecnt; ++i) 1691 if (writetype[i]) 1692 (void) putc(ttisgmts[i], fp); 1693 } 1694 (void) fprintf(fp, "\n%s\n", string); 1695 if (ferror(fp) || fclose(fp)) { 1696 (void) fprintf(stderr, _("%s: Error writing %s\n"), 1697 progname, fullname); 1698 exit(EXIT_FAILURE); 1699 } 1700 } 1701 1702 static void 1703 doabbr(char *const abbr, const int abbrlen, const char *const format, 1704 const char *const letters, const int isdst, const int doquotes) 1705 { 1706 char * cp; 1707 char * slashp; 1708 int len; 1709 1710 slashp = strchr(format, '/'); 1711 if (slashp == NULL) { 1712 if (letters == NULL) 1713 (void) strlcpy(abbr, format, abbrlen); 1714 else (void) snprintf(abbr, abbrlen, format, letters); 1715 } else if (isdst) { 1716 (void) strlcpy(abbr, slashp + 1, abbrlen); 1717 } else { 1718 if (slashp > format) 1719 (void) strncpy(abbr, format, (size_t)(slashp - format)); 1720 abbr[slashp - format] = '\0'; 1721 } 1722 if (!doquotes) 1723 return; 1724 for (cp = abbr; *cp != '\0'; ++cp) 1725 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL && 1726 strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL) 1727 break; 1728 len = strlen(abbr); 1729 if (len > 0 && *cp == '\0') 1730 return; 1731 abbr[len + 2] = '\0'; 1732 abbr[len + 1] = '>'; 1733 for ( ; len > 0; --len) 1734 abbr[len] = abbr[len - 1]; 1735 abbr[0] = '<'; 1736 } 1737 1738 static void 1739 updateminmax(const int x) 1740 { 1741 if (min_year > x) 1742 min_year = x; 1743 if (max_year < x) 1744 max_year = x; 1745 } 1746 1747 static int 1748 stringoffset(char *result, long offset) 1749 { 1750 int hours; 1751 int minutes; 1752 int seconds; 1753 1754 result[0] = '\0'; 1755 if (offset < 0) { 1756 (void) strcpy(result, "-"); 1757 offset = -offset; 1758 } 1759 seconds = offset % SECSPERMIN; 1760 offset /= SECSPERMIN; 1761 minutes = offset % MINSPERHOUR; 1762 offset /= MINSPERHOUR; 1763 hours = offset; 1764 if (hours >= HOURSPERDAY) { 1765 result[0] = '\0'; 1766 return -1; 1767 } 1768 (void) sprintf(end(result), "%d", hours); 1769 if (minutes != 0 || seconds != 0) { 1770 (void) sprintf(end(result), ":%02d", minutes); 1771 if (seconds != 0) 1772 (void) sprintf(end(result), ":%02d", seconds); 1773 } 1774 return 0; 1775 } 1776 1777 static int 1778 stringrule(char *result, const struct rule *const rp, const long dstoff, 1779 const long gmtoff) 1780 { 1781 long tod; 1782 1783 result = end(result); 1784 if (rp->r_dycode == DC_DOM) { 1785 int month, total; 1786 1787 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) 1788 return -1; 1789 total = 0; 1790 for (month = 0; month < rp->r_month; ++month) 1791 total += len_months[0][month]; 1792 (void) sprintf(result, "J%d", total + rp->r_dayofmonth); 1793 } else { 1794 int week; 1795 1796 if (rp->r_dycode == DC_DOWGEQ) { 1797 if ((rp->r_dayofmonth % DAYSPERWEEK) != 1) 1798 return -1; 1799 week = 1 + rp->r_dayofmonth / DAYSPERWEEK; 1800 } else if (rp->r_dycode == DC_DOWLEQ) { 1801 if (rp->r_dayofmonth == len_months[1][rp->r_month]) 1802 week = 5; 1803 else { 1804 if ((rp->r_dayofmonth % DAYSPERWEEK) != 0) 1805 return -1; 1806 week = rp->r_dayofmonth / DAYSPERWEEK; 1807 } 1808 } else return -1; /* "cannot happen" */ 1809 (void) sprintf(result, "M%d.%d.%d", 1810 rp->r_month + 1, week, rp->r_wday); 1811 } 1812 tod = rp->r_tod; 1813 if (rp->r_todisgmt) 1814 tod += gmtoff; 1815 if (rp->r_todisstd && rp->r_stdoff == 0) 1816 tod += dstoff; 1817 if (tod < 0) { 1818 result[0] = '\0'; 1819 return -1; 1820 } 1821 if (tod != 2 * SECSPERMIN * MINSPERHOUR) { 1822 (void) strcat(result, "/"); 1823 if (stringoffset(end(result), tod) != 0) 1824 return -1; 1825 } 1826 return 0; 1827 } 1828 1829 static void 1830 stringzone(char *result, const int resultlen, const struct zone *const zpfirst, 1831 const int zonecount) 1832 { 1833 const struct zone * zp; 1834 struct rule * rp; 1835 struct rule * stdrp; 1836 struct rule * dstrp; 1837 int i; 1838 const char * abbrvar; 1839 1840 result[0] = '\0'; 1841 zp = zpfirst + zonecount - 1; 1842 stdrp = dstrp = NULL; 1843 for (i = 0; i < zp->z_nrules; ++i) { 1844 rp = &zp->z_rules[i]; 1845 if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX) 1846 continue; 1847 if (rp->r_yrtype != NULL) 1848 continue; 1849 if (rp->r_stdoff == 0) { 1850 if (stdrp == NULL) 1851 stdrp = rp; 1852 else return; 1853 } else { 1854 if (dstrp == NULL) 1855 dstrp = rp; 1856 else return; 1857 } 1858 } 1859 if (stdrp == NULL && dstrp == NULL) { 1860 /* 1861 ** There are no rules running through "max". 1862 ** Let's find the latest rule. 1863 */ 1864 for (i = 0; i < zp->z_nrules; ++i) { 1865 rp = &zp->z_rules[i]; 1866 if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear || 1867 (rp->r_hiyear == stdrp->r_hiyear && 1868 rp->r_month > stdrp->r_month)) 1869 stdrp = rp; 1870 } 1871 if (stdrp != NULL && stdrp->r_stdoff != 0) 1872 return; /* We end up in DST (a POSIX no-no). */ 1873 /* 1874 ** Horrid special case: if year is 2037, 1875 ** presume this is a zone handled on a year-by-year basis; 1876 ** do not try to apply a rule to the zone. 1877 */ 1878 if (stdrp != NULL && stdrp->r_hiyear == 2037) 1879 return; 1880 } 1881 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0)) 1882 return; 1883 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; 1884 doabbr(result, resultlen, zp->z_format, abbrvar, FALSE, TRUE); 1885 if (stringoffset(end(result), -zp->z_gmtoff) != 0) { 1886 result[0] = '\0'; 1887 return; 1888 } 1889 if (dstrp == NULL) 1890 return; 1891 doabbr(end(result), resultlen - strlen(result), 1892 zp->z_format, dstrp->r_abbrvar, TRUE, TRUE); 1893 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) 1894 if (stringoffset(end(result), 1895 -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) { 1896 result[0] = '\0'; 1897 return; 1898 } 1899 (void) strcat(result, ","); 1900 if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 1901 result[0] = '\0'; 1902 return; 1903 } 1904 (void) strcat(result, ","); 1905 if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 1906 result[0] = '\0'; 1907 return; 1908 } 1909 } 1910 1911 static void 1912 outzone(const struct zone *const zpfirst, const int zonecount) 1913 { 1914 const struct zone * zp; 1915 struct rule * rp; 1916 int i, j; 1917 int usestart, useuntil; 1918 zic_t starttime, untiltime; 1919 long gmtoff; 1920 long stdoff; 1921 int year; 1922 long startoff; 1923 int startttisstd; 1924 int startttisgmt; 1925 int type; 1926 char * startbuf; 1927 char * ab; 1928 char * envvar; 1929 int max_abbr_len; 1930 int max_envvar_len; 1931 int prodstic; /* all rules are min to max */ 1932 1933 max_abbr_len = 2 + max_format_len + max_abbrvar_len; 1934 max_envvar_len = 2 * max_abbr_len + 5 * 9; 1935 startbuf = emalloc(max_abbr_len + 1); 1936 ab = emalloc(max_abbr_len + 1); 1937 envvar = emalloc(max_envvar_len + 1); 1938 INITIALIZE(untiltime); 1939 INITIALIZE(starttime); 1940 /* 1941 ** Now. . .finally. . .generate some useful data! 1942 */ 1943 timecnt = 0; 1944 typecnt = 0; 1945 charcnt = 0; 1946 prodstic = zonecount == 1; 1947 /* 1948 ** Thanks to Earl Chew 1949 ** for noting the need to unconditionally initialize startttisstd. 1950 */ 1951 startttisstd = FALSE; 1952 startttisgmt = FALSE; 1953 min_year = max_year = EPOCH_YEAR; 1954 if (leapseen) { 1955 updateminmax(leapminyear); 1956 updateminmax(leapmaxyear + (leapmaxyear < INT_MAX)); 1957 } 1958 for (i = 0; i < zonecount; ++i) { 1959 zp = &zpfirst[i]; 1960 if (i < zonecount - 1) 1961 updateminmax(zp->z_untilrule.r_loyear); 1962 for (j = 0; j < zp->z_nrules; ++j) { 1963 rp = &zp->z_rules[j]; 1964 if (rp->r_lowasnum) 1965 updateminmax(rp->r_loyear); 1966 if (rp->r_hiwasnum) 1967 updateminmax(rp->r_hiyear); 1968 } 1969 } 1970 /* 1971 ** Generate lots of data if a rule can't cover all future times. 1972 */ 1973 stringzone(envvar, max_envvar_len+1, zpfirst, zonecount); 1974 if (noise && envvar[0] == '\0') { 1975 char * wp; 1976 1977 wp = ecpyalloc(_("no POSIX environment variable for zone")); 1978 wp = ecatalloc(wp, " "); 1979 wp = ecatalloc(wp, zpfirst->z_name); 1980 warning(wp); 1981 free(wp); 1982 } 1983 if (envvar[0] == '\0') { 1984 if (min_year >= INT_MIN + YEARSPERREPEAT) 1985 min_year -= YEARSPERREPEAT; 1986 else min_year = INT_MIN; 1987 if (max_year <= INT_MAX - YEARSPERREPEAT) 1988 max_year += YEARSPERREPEAT; 1989 else max_year = INT_MAX; 1990 /* 1991 ** Regardless of any of the above, 1992 ** for a "proDSTic" zone which specifies that its rules 1993 ** always have and always will be in effect, 1994 ** we only need one cycle to define the zone. 1995 */ 1996 if (prodstic) { 1997 min_year = 1900; 1998 max_year = min_year + YEARSPERREPEAT; 1999 } 2000 } 2001 /* 2002 ** For the benefit of older systems, 2003 ** generate data from 1900 through 2037. 2004 */ 2005 if (min_year > 1900) 2006 min_year = 1900; 2007 if (max_year < 2037) 2008 max_year = 2037; 2009 for (i = 0; i < zonecount; ++i) { 2010 /* 2011 ** A guess that may well be corrected later. 2012 */ 2013 stdoff = 0; 2014 zp = &zpfirst[i]; 2015 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 2016 useuntil = i < (zonecount - 1); 2017 if (useuntil && zp->z_untiltime <= min_time) 2018 continue; 2019 gmtoff = zp->z_gmtoff; 2020 eat(zp->z_filename, zp->z_linenum); 2021 *startbuf = '\0'; 2022 startoff = zp->z_gmtoff; 2023 if (zp->z_nrules == 0) { 2024 stdoff = zp->z_stdoff; 2025 doabbr(startbuf, max_abbr_len + 1, zp->z_format, 2026 NULL, stdoff != 0, FALSE); 2027 type = addtype(oadd(zp->z_gmtoff, stdoff), 2028 startbuf, stdoff != 0, startttisstd, 2029 startttisgmt); 2030 if (usestart) { 2031 addtt(starttime, type); 2032 usestart = FALSE; 2033 } else if (stdoff != 0) 2034 addtt(min_time, type); 2035 } else for (year = min_year; year <= max_year; ++year) { 2036 if (useuntil && year > zp->z_untilrule.r_hiyear) 2037 break; 2038 /* 2039 ** Mark which rules to do in the current year. 2040 ** For those to do, calculate rpytime(rp, year); 2041 */ 2042 for (j = 0; j < zp->z_nrules; ++j) { 2043 rp = &zp->z_rules[j]; 2044 eats(zp->z_filename, zp->z_linenum, 2045 rp->r_filename, rp->r_linenum); 2046 rp->r_todo = year >= rp->r_loyear && 2047 year <= rp->r_hiyear && 2048 yearistype(year, rp->r_yrtype); 2049 if (rp->r_todo) 2050 rp->r_temp = rpytime(rp, year); 2051 } 2052 for ( ; ; ) { 2053 int k; 2054 zic_t jtime, ktime; 2055 long offset; 2056 2057 INITIALIZE(ktime); 2058 if (useuntil) { 2059 /* 2060 ** Turn untiltime into UTC 2061 ** assuming the current gmtoff and 2062 ** stdoff values. 2063 */ 2064 untiltime = zp->z_untiltime; 2065 if (!zp->z_untilrule.r_todisgmt) 2066 untiltime = tadd(untiltime, 2067 -gmtoff); 2068 if (!zp->z_untilrule.r_todisstd) 2069 untiltime = tadd(untiltime, 2070 -stdoff); 2071 } 2072 /* 2073 ** Find the rule (of those to do, if any) 2074 ** that takes effect earliest in the year. 2075 */ 2076 k = -1; 2077 for (j = 0; j < zp->z_nrules; ++j) { 2078 rp = &zp->z_rules[j]; 2079 if (!rp->r_todo) 2080 continue; 2081 eats(zp->z_filename, zp->z_linenum, 2082 rp->r_filename, rp->r_linenum); 2083 offset = rp->r_todisgmt ? 0 : gmtoff; 2084 if (!rp->r_todisstd) 2085 offset = oadd(offset, stdoff); 2086 jtime = rp->r_temp; 2087 if (jtime == min_time || 2088 jtime == max_time) 2089 continue; 2090 jtime = tadd(jtime, -offset); 2091 if (k < 0 || jtime < ktime) { 2092 k = j; 2093 ktime = jtime; 2094 } 2095 } 2096 if (k < 0) 2097 break; /* go on to next year */ 2098 rp = &zp->z_rules[k]; 2099 rp->r_todo = FALSE; 2100 if (useuntil && ktime >= untiltime) 2101 break; 2102 stdoff = rp->r_stdoff; 2103 if (usestart && ktime == starttime) 2104 usestart = FALSE; 2105 if (usestart) { 2106 if (ktime < starttime) { 2107 startoff = oadd(zp->z_gmtoff, 2108 stdoff); 2109 doabbr(startbuf, 2110 max_abbr_len + 1, 2111 zp->z_format, 2112 rp->r_abbrvar, 2113 rp->r_stdoff != 0, 2114 FALSE); 2115 continue; 2116 } 2117 if (*startbuf == '\0' && 2118 startoff == oadd(zp->z_gmtoff, 2119 stdoff)) { 2120 doabbr(startbuf, 2121 max_abbr_len + 1, 2122 zp->z_format, 2123 rp->r_abbrvar, 2124 rp->r_stdoff != 2125 0, 2126 FALSE); 2127 } 2128 } 2129 eats(zp->z_filename, zp->z_linenum, 2130 rp->r_filename, rp->r_linenum); 2131 doabbr(ab, max_abbr_len+1, zp->z_format, rp->r_abbrvar, 2132 rp->r_stdoff != 0, FALSE); 2133 offset = oadd(zp->z_gmtoff, rp->r_stdoff); 2134 type = addtype(offset, ab, rp->r_stdoff != 0, 2135 rp->r_todisstd, rp->r_todisgmt); 2136 addtt(ktime, type); 2137 } 2138 } 2139 if (usestart) { 2140 if (*startbuf == '\0' && 2141 zp->z_format != NULL && 2142 strchr(zp->z_format, '%') == NULL && 2143 strchr(zp->z_format, '/') == NULL) 2144 (void)strncpy(startbuf, zp->z_format, 2145 max_abbr_len + 1 - 1); 2146 eat(zp->z_filename, zp->z_linenum); 2147 if (*startbuf == '\0') 2148 error(_("can't determine time zone abbreviation to use just after until time")); 2149 else addtt(starttime, 2150 addtype(startoff, startbuf, 2151 startoff != zp->z_gmtoff, 2152 startttisstd, 2153 startttisgmt)); 2154 } 2155 /* 2156 ** Now we may get to set starttime for the next zone line. 2157 */ 2158 if (useuntil) { 2159 startttisstd = zp->z_untilrule.r_todisstd; 2160 startttisgmt = zp->z_untilrule.r_todisgmt; 2161 starttime = zp->z_untiltime; 2162 if (!startttisstd) 2163 starttime = tadd(starttime, -stdoff); 2164 if (!startttisgmt) 2165 starttime = tadd(starttime, -gmtoff); 2166 } 2167 } 2168 writezone(zpfirst->z_name, envvar); 2169 free(startbuf); 2170 free(ab); 2171 free(envvar); 2172 } 2173 2174 static void 2175 addtt(const zic_t starttime, int type) 2176 { 2177 if (starttime <= min_time || 2178 (timecnt == 1 && attypes[0].at < min_time)) { 2179 gmtoffs[0] = gmtoffs[type]; 2180 isdsts[0] = isdsts[type]; 2181 ttisstds[0] = ttisstds[type]; 2182 ttisgmts[0] = ttisgmts[type]; 2183 if (abbrinds[type] != 0) 2184 (void) strcpy(chars, &chars[abbrinds[type]]); 2185 abbrinds[0] = 0; 2186 charcnt = strlen(chars) + 1; 2187 typecnt = 1; 2188 timecnt = 0; 2189 type = 0; 2190 } 2191 if (timecnt >= TZ_MAX_TIMES) { 2192 error(_("too many transitions?!")); 2193 exit(EXIT_FAILURE); 2194 } 2195 attypes[timecnt].at = starttime; 2196 attypes[timecnt].type = type; 2197 ++timecnt; 2198 } 2199 2200 static int 2201 addtype(const long gmtoff, const char *const abbr, const int isdst, 2202 const int ttisstd, const int ttisgmt) 2203 { 2204 int i, j; 2205 2206 if (isdst != TRUE && isdst != FALSE) { 2207 error(_("internal error - addtype called with bad isdst")); 2208 exit(EXIT_FAILURE); 2209 } 2210 if (ttisstd != TRUE && ttisstd != FALSE) { 2211 error(_("internal error - addtype called with bad ttisstd")); 2212 exit(EXIT_FAILURE); 2213 } 2214 if (ttisgmt != TRUE && ttisgmt != FALSE) { 2215 error(_("internal error - addtype called with bad ttisgmt")); 2216 exit(EXIT_FAILURE); 2217 } 2218 /* 2219 ** See if there's already an entry for this zone type. 2220 ** If so, just return its index. 2221 */ 2222 for (i = 0; i < typecnt; ++i) { 2223 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 2224 strcmp(abbr, &chars[abbrinds[i]]) == 0 && 2225 ttisstd == ttisstds[i] && 2226 ttisgmt == ttisgmts[i]) 2227 return i; 2228 } 2229 /* 2230 ** There isn't one; add a new one, unless there are already too 2231 ** many. 2232 */ 2233 if (typecnt >= TZ_MAX_TYPES) { 2234 error(_("too many local time types")); 2235 exit(EXIT_FAILURE); 2236 } 2237 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { 2238 error(_("UTC offset out of range")); 2239 exit(EXIT_FAILURE); 2240 } 2241 gmtoffs[i] = gmtoff; 2242 isdsts[i] = isdst; 2243 ttisstds[i] = ttisstd; 2244 ttisgmts[i] = ttisgmt; 2245 2246 for (j = 0; j < charcnt; ++j) 2247 if (strcmp(&chars[j], abbr) == 0) 2248 break; 2249 if (j == charcnt) 2250 newabbr(abbr); 2251 abbrinds[i] = j; 2252 ++typecnt; 2253 return i; 2254 } 2255 2256 static void 2257 leapadd(const zic_t t, const int positive, const int rolling, int count) 2258 { 2259 int i, j; 2260 2261 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 2262 error(_("too many leap seconds")); 2263 exit(EXIT_FAILURE); 2264 } 2265 for (i = 0; i < leapcnt; ++i) 2266 if (t <= trans[i]) { 2267 if (t == trans[i]) { 2268 error(_("repeated leap second moment")); 2269 exit(EXIT_FAILURE); 2270 } 2271 break; 2272 } 2273 do { 2274 for (j = leapcnt; j > i; --j) { 2275 trans[j] = trans[j - 1]; 2276 corr[j] = corr[j - 1]; 2277 roll[j] = roll[j - 1]; 2278 } 2279 trans[i] = t; 2280 corr[i] = positive ? 1L : eitol(-count); 2281 roll[i] = rolling; 2282 ++leapcnt; 2283 } while (positive && --count != 0); 2284 } 2285 2286 static void 2287 adjleap(void) 2288 { 2289 int i; 2290 long last = 0; 2291 2292 /* 2293 ** propagate leap seconds forward 2294 */ 2295 for (i = 0; i < leapcnt; ++i) { 2296 trans[i] = tadd(trans[i], last); 2297 last = corr[i] += last; 2298 } 2299 } 2300 2301 static int 2302 yearistype(const int year, const char *const type) 2303 { 2304 static char * buf; 2305 int result; 2306 2307 if (type == NULL || *type == '\0') 2308 return TRUE; 2309 buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type)); 2310 (void)sprintf(buf, "%s %d %s", yitcommand, year, type); /* XXX: sprintf is safe */ 2311 result = system(buf); 2312 if (WIFEXITED(result)) switch (WEXITSTATUS(result)) { 2313 case 0: 2314 return TRUE; 2315 case 1: 2316 return FALSE; 2317 } 2318 error(_("Wild result from command execution")); 2319 (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"), 2320 progname, buf, result); 2321 for ( ; ; ) 2322 exit(EXIT_FAILURE); 2323 } 2324 2325 static int 2326 lowerit(int a) 2327 { 2328 a = (unsigned char) a; 2329 return (isascii(a) && isupper(a)) ? tolower(a) : a; 2330 } 2331 2332 /* case-insensitive equality */ 2333 static __pure int 2334 ciequal(const char *ap, const char *bp) 2335 { 2336 while (lowerit(*ap) == lowerit(*bp++)) 2337 if (*ap++ == '\0') 2338 return TRUE; 2339 return FALSE; 2340 } 2341 2342 static __pure int 2343 itsabbr(const char *abbr, const char *word) 2344 { 2345 if (lowerit(*abbr) != lowerit(*word)) 2346 return FALSE; 2347 ++word; 2348 while (*++abbr != '\0') 2349 do { 2350 if (*word == '\0') 2351 return FALSE; 2352 } while (lowerit(*word++) != lowerit(*abbr)); 2353 return TRUE; 2354 } 2355 2356 static __pure const struct lookup * 2357 byword(const char *const word, const struct lookup *const table) 2358 { 2359 const struct lookup * foundlp; 2360 const struct lookup * lp; 2361 2362 if (word == NULL || table == NULL) 2363 return NULL; 2364 /* 2365 ** Look for exact match. 2366 */ 2367 for (lp = table; lp->l_word != NULL; ++lp) 2368 if (ciequal(word, lp->l_word)) 2369 return lp; 2370 /* 2371 ** Look for inexact match. 2372 */ 2373 foundlp = NULL; 2374 for (lp = table; lp->l_word != NULL; ++lp) 2375 if (itsabbr(word, lp->l_word)) { 2376 if (foundlp == NULL) 2377 foundlp = lp; 2378 else return NULL; /* multiple inexact matches */ 2379 } 2380 return foundlp; 2381 } 2382 2383 static char ** 2384 getfields(char *cp) 2385 { 2386 char * dp; 2387 char ** array; 2388 int nsubs; 2389 2390 if (cp == NULL) 2391 return NULL; 2392 array = emalloc((strlen(cp) + 1) * sizeof *array); 2393 nsubs = 0; 2394 for ( ; ; ) { 2395 while (isascii((unsigned char) *cp) && 2396 isspace((unsigned char) *cp)) 2397 ++cp; 2398 if (*cp == '\0' || *cp == '#') 2399 break; 2400 array[nsubs++] = dp = cp; 2401 do { 2402 if ((*dp = *cp++) != '"') 2403 ++dp; 2404 else while ((*dp = *cp++) != '"') 2405 if (*dp != '\0') 2406 ++dp; 2407 else { 2408 error(_( 2409 "Odd number of quotation marks" 2410 )); 2411 exit(1); 2412 } 2413 } while (*cp != '\0' && *cp != '#' && 2414 (!isascii(*cp) || !isspace((unsigned char) *cp))); 2415 if (isascii(*cp) && isspace((unsigned char) *cp)) 2416 ++cp; 2417 *dp = '\0'; 2418 } 2419 array[nsubs] = NULL; 2420 return array; 2421 } 2422 2423 static __pure long 2424 oadd(const long t1, const long t2) 2425 { 2426 if (t1 < 0 ? t2 < LONG_MIN - t1 : LONG_MAX - t1 < t2) { 2427 error(_("time overflow")); 2428 exit(EXIT_FAILURE); 2429 } 2430 return t1 + t2; 2431 } 2432 2433 static zic_t 2434 tadd(const zic_t t1, const long t2) 2435 { 2436 if (t1 == max_time && t2 > 0) 2437 return max_time; 2438 if (t1 == min_time && t2 < 0) 2439 return min_time; 2440 if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) { 2441 error(_("time overflow")); 2442 exit(EXIT_FAILURE); 2443 } 2444 return t1 + t2; 2445 } 2446 2447 /* 2448 ** Given a rule, and a year, compute the date - in seconds since January 1, 2449 ** 1970, 00:00 LOCAL time - in that year that the rule refers to. 2450 */ 2451 2452 static zic_t 2453 rpytime(const struct rule *const rp, const int wantedy) 2454 { 2455 int y, m, i; 2456 long dayoff; /* with a nod to Margaret O. */ 2457 zic_t t; 2458 2459 if (wantedy == INT_MIN) 2460 return min_time; 2461 if (wantedy == INT_MAX) 2462 return max_time; 2463 dayoff = 0; 2464 m = TM_JANUARY; 2465 y = EPOCH_YEAR; 2466 while (wantedy != y) { 2467 if (wantedy > y) { 2468 i = len_years[isleap(y)]; 2469 ++y; 2470 } else { 2471 --y; 2472 i = -len_years[isleap(y)]; 2473 } 2474 dayoff = oadd(dayoff, eitol(i)); 2475 } 2476 while (m != rp->r_month) { 2477 i = len_months[isleap(y)][m]; 2478 dayoff = oadd(dayoff, eitol(i)); 2479 ++m; 2480 } 2481 i = rp->r_dayofmonth; 2482 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 2483 if (rp->r_dycode == DC_DOWLEQ) 2484 --i; 2485 else { 2486 error(_("use of 2/29 in non leap-year")); 2487 exit(EXIT_FAILURE); 2488 } 2489 } 2490 --i; 2491 dayoff = oadd(dayoff, eitol(i)); 2492 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 2493 long wday; 2494 2495 #define LDAYSPERWEEK ((long) DAYSPERWEEK) 2496 wday = eitol(EPOCH_WDAY); 2497 /* 2498 ** Don't trust mod of negative numbers. 2499 */ 2500 if (dayoff >= 0) 2501 wday = (wday + dayoff) % LDAYSPERWEEK; 2502 else { 2503 wday -= ((-dayoff) % LDAYSPERWEEK); 2504 if (wday < 0) 2505 wday += LDAYSPERWEEK; 2506 } 2507 while (wday != eitol(rp->r_wday)) 2508 if (rp->r_dycode == DC_DOWGEQ) { 2509 dayoff = oadd(dayoff, (long) 1); 2510 if (++wday >= LDAYSPERWEEK) 2511 wday = 0; 2512 ++i; 2513 } else { 2514 dayoff = oadd(dayoff, (long) -1); 2515 if (--wday < 0) 2516 wday = LDAYSPERWEEK - 1; 2517 --i; 2518 } 2519 if (i < 0 || i >= len_months[isleap(y)][m]) { 2520 if (noise) 2521 warning(_("rule goes past start/end of month--\ 2522 will not work with pre-2004 versions of zic")); 2523 } 2524 } 2525 if (dayoff < min_time / SECSPERDAY) 2526 return min_time; 2527 if (dayoff > max_time / SECSPERDAY) 2528 return max_time; 2529 t = (zic_t) dayoff * SECSPERDAY; 2530 return tadd(t, rp->r_tod); 2531 } 2532 2533 static void 2534 newabbr(const char *const string) 2535 { 2536 int i; 2537 2538 if (strcmp(string, GRANDPARENTED) != 0) { 2539 const char * cp; 2540 const char * mp; 2541 2542 /* 2543 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics 2544 ** optionally followed by a + or - and a number from 1 to 14. 2545 */ 2546 cp = string; 2547 mp = NULL; 2548 while (isascii((unsigned char) *cp) && 2549 isalpha((unsigned char) *cp)) 2550 ++cp; 2551 if (cp - string == 0) 2552 mp = _("time zone abbreviation lacks alphabetic at start"); 2553 if (noise && cp - string > 3) 2554 mp = _("time zone abbreviation has more than 3 alphabetics"); 2555 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 2556 mp = _("time zone abbreviation has too many alphabetics"); 2557 if (mp == NULL && (*cp == '+' || *cp == '-')) { 2558 ++cp; 2559 if (isascii((unsigned char) *cp) && 2560 isdigit((unsigned char) *cp)) 2561 if (*cp++ == '1' && 2562 *cp >= '0' && *cp <= '4') 2563 ++cp; 2564 } 2565 if (*cp != '\0') 2566 mp = _("time zone abbreviation differs from POSIX standard"); 2567 if (mp != NULL) { 2568 char *wp = ecpyalloc(mp); 2569 wp = ecatalloc(wp, " ("); 2570 wp = ecatalloc(wp, string); 2571 wp = ecatalloc(wp, ")"); 2572 warning(wp); 2573 free(wp); 2574 } 2575 } 2576 i = strlen(string) + 1; 2577 if (charcnt + i > TZ_MAX_CHARS) { 2578 error(_("too many, or too long, time zone abbreviations")); 2579 exit(EXIT_FAILURE); 2580 } 2581 (void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1); 2582 charcnt += eitol(i); 2583 } 2584 2585 static int 2586 mkdirs(char *argname) 2587 { 2588 char * name; 2589 char * cp; 2590 2591 if (argname == NULL || *argname == '\0') 2592 return 0; 2593 cp = name = ecpyalloc(argname); 2594 while ((cp = strchr(cp + 1, '/')) != 0) { 2595 *cp = '\0'; 2596 #ifndef __NetBSD__ 2597 /* 2598 ** DOS drive specifier? 2599 */ 2600 if (isalpha((unsigned char) name[0]) && 2601 name[1] == ':' && name[2] == '\0') { 2602 *cp = '/'; 2603 continue; 2604 } 2605 #endif /* !defined __NetBSD__ */ 2606 if (!itsdir(name)) { 2607 /* 2608 ** It doesn't seem to exist, so we try to create it. 2609 ** Creation may fail because of the directory being 2610 ** created by some other multiprocessor, so we get 2611 ** to do extra checking. 2612 */ 2613 if (mkdir(name, MKDIR_UMASK) != 0) { 2614 const char *e = strerror(errno); 2615 2616 if (errno != EEXIST || !itsdir(name)) { 2617 (void) fprintf(stderr, 2618 _("%s: Can't create directory %s: %s\n"), 2619 progname, name, e); 2620 free(name); 2621 return -1; 2622 } 2623 } 2624 } 2625 *cp = '/'; 2626 } 2627 free(name); 2628 return 0; 2629 } 2630 2631 static long 2632 eitol(const int i) 2633 { 2634 long l; 2635 2636 l = i; 2637 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 2638 (void) fprintf(stderr, 2639 _("%s: %d did not sign extend correctly\n"), 2640 progname, i); 2641 exit(EXIT_FAILURE); 2642 } 2643 return l; 2644 } 2645 2646 /* 2647 ** UNIX was a registered trademark of The Open Group in 2003. 2648 */ 2649