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