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