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