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