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