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