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