1 /* $NetBSD: zic.c,v 1.81 2022/03/22 17:48:39 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.81 2022/03/22 17:48:39 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[] = 1005 "abcdefghijklmnopqrstuvwxyz" 1006 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 1007 "0123456789"; 1008 enum { prefixlen = sizeof prefix - 1, alphabetlen = sizeof alphabet - 1 }; 1009 int suffixlen = 6; 1010 char const *lastslash = strrchr(src, '/'); 1011 ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0; 1012 static unsigned short initialized; 1013 int i; 1014 1015 if (!dst) { 1016 dst = emalloc(dirlen + prefixlen + suffixlen + 1); 1017 memcpy(dst, src, dirlen); 1018 memcpy(dst + dirlen, prefix, prefixlen); 1019 dst[dirlen + prefixlen + suffixlen] = '\0'; 1020 *name = *namealloc = dst; 1021 } 1022 1023 /* This randomization is not the best, but is portable to C89. */ 1024 if (!initialized++) { 1025 unsigned now = time(NULL); 1026 srand(rand() ^ now); 1027 } 1028 for (i = 0; i < suffixlen; i++) 1029 dst[dirlen + prefixlen + i] = alphabet[rand() % alphabetlen]; 1030 } 1031 1032 /* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the 1033 name of the temporary file that will eventually be renamed to 1034 *OUTNAME. Assign the temporary file's name to both *OUTNAME and 1035 *TEMPNAME. If *TEMPNAME is null, allocate the name of any such 1036 temporary file; otherwise, reuse *TEMPNAME's storage, which is 1037 already set up and only needs its trailing suffix updated. */ 1038 static FILE * 1039 open_outfile(char const **outname, char **tempname) 1040 { 1041 #if __STDC_VERSION__ < 201112 1042 static char const fopen_mode[] = "wb"; 1043 #else 1044 static char const fopen_mode[] = "wbx"; 1045 #endif 1046 1047 FILE *fp; 1048 bool dirs_made = false; 1049 if (!*tempname) 1050 random_dirent(outname, tempname); 1051 1052 while (! (fp = fopen(*outname, fopen_mode))) { 1053 int fopen_errno = errno; 1054 if (fopen_errno == ENOENT && !dirs_made) { 1055 mkdirs(*outname, true); 1056 dirs_made = true; 1057 } else if (fopen_errno == EEXIST) 1058 random_dirent(outname, tempname); 1059 else { 1060 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), 1061 progname, directory, *outname, strerror(fopen_errno)); 1062 exit(EXIT_FAILURE); 1063 } 1064 } 1065 1066 return fp; 1067 } 1068 1069 /* If TEMPNAME, the result is in the temporary file TEMPNAME even 1070 though the user wanted it in NAME, so rename TEMPNAME to NAME. 1071 Report an error and exit if there is trouble. Also, free TEMPNAME. */ 1072 static void 1073 rename_dest(char *tempname, char const *name) 1074 { 1075 if (tempname) { 1076 if (rename(tempname, name) != 0) { 1077 int rename_errno = errno; 1078 remove(tempname); 1079 fprintf(stderr, _("%s: rename to %s/%s: %s\n"), 1080 progname, directory, name, strerror(rename_errno)); 1081 exit(EXIT_FAILURE); 1082 } 1083 free(tempname); 1084 } 1085 } 1086 1087 /* Create symlink contents suitable for symlinking FROM to TO, as a 1088 freshly allocated string. FROM should be a relative file name, and 1089 is relative to the global variable DIRECTORY. TO can be either 1090 relative or absolute. */ 1091 static char * 1092 relname(char const *target, char const *linkname) 1093 { 1094 size_t i, taillen, dotdotetcsize; 1095 size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX; 1096 char const *f = target; 1097 char *result = NULL; 1098 if (*linkname == '/') { 1099 /* Make F absolute too. */ 1100 size_t len = strlen(directory); 1101 bool needslash = len && directory[len - 1] != '/'; 1102 linksize = len + needslash + strlen(target) + 1; 1103 f = result = emalloc(linksize); 1104 strcpy(result, directory); 1105 result[len] = '/'; 1106 strcpy(result + len + needslash, target); 1107 } 1108 for (i = 0; f[i] && f[i] == linkname[i]; i++) 1109 if (f[i] == '/') 1110 dir_len = i + 1; 1111 for (; linkname[i]; i++) 1112 dotdots += linkname[i] == '/' && linkname[i - 1] != '/'; 1113 taillen = strlen(f + dir_len); 1114 dotdotetcsize = 3 * dotdots + taillen + 1; 1115 if (dotdotetcsize <= linksize) { 1116 if (!result) 1117 result = emalloc(dotdotetcsize); 1118 for (i = 0; i < dotdots; i++) 1119 memcpy(result + 3 * i, "../", 3); 1120 memmove(result + 3 * dotdots, f + dir_len, taillen + 1); 1121 } 1122 return result; 1123 } 1124 1125 static void 1126 dolink(char const *target, char const *linkname, bool staysymlink) 1127 { 1128 bool linkdirs_made = false; 1129 int link_errno; 1130 char *tempname = NULL; 1131 char const *outname = linkname; 1132 1133 check_for_signal(); 1134 1135 if (strcmp(target, "-") == 0) { 1136 if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR) 1137 return; 1138 else { 1139 char const *e = strerror(errno); 1140 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), 1141 progname, directory, linkname, e); 1142 exit(EXIT_FAILURE); 1143 } 1144 } 1145 1146 while (true) { 1147 if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW) 1148 == 0) { 1149 link_errno = 0; 1150 break; 1151 } 1152 link_errno = errno; 1153 if (link_errno == EXDEV || link_errno == ENOTSUP) 1154 break; 1155 1156 if (link_errno == EEXIST) { 1157 staysymlink &= !tempname; 1158 random_dirent(&outname, &tempname); 1159 if (staysymlink && itssymlink(linkname)) 1160 break; 1161 } else if (link_errno == ENOENT && !linkdirs_made) { 1162 mkdirs(linkname, true); 1163 linkdirs_made = true; 1164 } else { 1165 fprintf(stderr, _("%s: Can't link %s/%s to %s/%s: %s\n"), 1166 progname, directory, target, directory, outname, 1167 strerror(link_errno)); 1168 exit(EXIT_FAILURE); 1169 } 1170 } 1171 if (link_errno != 0) { 1172 bool absolute = *target == '/'; 1173 char *linkalloc = absolute ? NULL : relname(target, linkname); 1174 char const *contents = absolute ? target : linkalloc; 1175 int symlink_errno; 1176 1177 while (true) { 1178 if (symlink(contents, outname) == 0) { 1179 symlink_errno = 0; 1180 break; 1181 } 1182 symlink_errno = errno; 1183 if (symlink_errno == EEXIST) 1184 random_dirent(&outname, &tempname); 1185 else if (symlink_errno == ENOENT && !linkdirs_made) { 1186 mkdirs(linkname, true); 1187 linkdirs_made = true; 1188 } else 1189 break; 1190 } 1191 free(linkalloc); 1192 if (symlink_errno == 0) { 1193 if (link_errno != ENOTSUP && link_errno != EEXIST) 1194 warning(_("symbolic link used because hard link failed: %s"), 1195 strerror(link_errno)); 1196 } else { 1197 FILE *fp, *tp; 1198 int c; 1199 fp = fopen(target, "rb"); 1200 if (!fp) { 1201 char const *e = strerror(errno); 1202 fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), 1203 progname, directory, target, e); 1204 exit(EXIT_FAILURE); 1205 } 1206 tp = open_outfile(&outname, &tempname); 1207 while ((c = getc(fp)) != EOF) 1208 putc(c, tp); 1209 close_file(tp, directory, linkname, tempname); 1210 close_file(fp, directory, target, NULL); 1211 if (link_errno != ENOTSUP) 1212 warning(_("copy used because hard link failed: %s"), 1213 strerror(link_errno)); 1214 else if (symlink_errno != ENOTSUP) 1215 warning(_("copy used because symbolic link failed: %s"), 1216 strerror(symlink_errno)); 1217 } 1218 } 1219 rename_dest(tempname, linkname); 1220 } 1221 1222 /* Return true if NAME is a symbolic link. */ 1223 static bool 1224 itssymlink(char const *name) 1225 { 1226 char c; 1227 return 0 <= readlink(name, &c, 1); 1228 } 1229 1230 /* 1231 ** Associate sets of rules with zones. 1232 */ 1233 1234 /* 1235 ** Sort by rule name. 1236 */ 1237 1238 static int 1239 rcomp(const void *cp1, const void *cp2) 1240 { 1241 struct rule const *r1 = cp1, *r2 = cp2; 1242 return strcmp(r1->r_name, r2->r_name); 1243 } 1244 1245 static void 1246 associate(void) 1247 { 1248 struct zone * zp; 1249 struct rule * rp; 1250 ptrdiff_t i, j, base, out; 1251 1252 if (nrules != 0) { 1253 qsort(rules, (size_t)nrules, sizeof *rules, rcomp); 1254 for (i = 0; i < nrules - 1; ++i) { 1255 if (strcmp(rules[i].r_name, 1256 rules[i + 1].r_name) != 0) 1257 continue; 1258 if (strcmp(rules[i].r_filename, 1259 rules[i + 1].r_filename) == 0) 1260 continue; 1261 eat(rules[i].r_filename, rules[i].r_linenum); 1262 warning(_("same rule name in multiple files")); 1263 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 1264 warning(_("same rule name in multiple files")); 1265 for (j = i + 2; j < nrules; ++j) { 1266 if (strcmp(rules[i].r_name, 1267 rules[j].r_name) != 0) 1268 break; 1269 if (strcmp(rules[i].r_filename, 1270 rules[j].r_filename) == 0) 1271 continue; 1272 if (strcmp(rules[i + 1].r_filename, 1273 rules[j].r_filename) == 0) 1274 continue; 1275 break; 1276 } 1277 i = j - 1; 1278 } 1279 } 1280 for (i = 0; i < nzones; ++i) { 1281 zp = &zones[i]; 1282 zp->z_rules = NULL; 1283 zp->z_nrules = 0; 1284 } 1285 for (base = 0; base < nrules; base = out) { 1286 rp = &rules[base]; 1287 for (out = base + 1; out < nrules; ++out) 1288 if (strcmp(rp->r_name, rules[out].r_name) != 0) 1289 break; 1290 for (i = 0; i < nzones; ++i) { 1291 zp = &zones[i]; 1292 if (strcmp(zp->z_rule, rp->r_name) != 0) 1293 continue; 1294 zp->z_rules = rp; 1295 zp->z_nrules = out - base; 1296 } 1297 } 1298 for (i = 0; i < nzones; ++i) { 1299 zp = &zones[i]; 1300 if (zp->z_nrules == 0) { 1301 /* 1302 ** Maybe we have a local standard time offset. 1303 */ 1304 eat(zp->z_filename, zp->z_linenum); 1305 zp->z_save = getsave(zp->z_rule, &zp->z_isdst); 1306 /* 1307 ** Note, though, that if there's no rule, 1308 ** a '%s' in the format is a bad thing. 1309 */ 1310 if (zp->z_format_specifier == 's') 1311 error("%s", _("%s in ruleless zone")); 1312 } 1313 } 1314 if (errors) 1315 exit(EXIT_FAILURE); 1316 } 1317 1318 static void 1319 infile(const char *name) 1320 { 1321 FILE * fp; 1322 char ** fields; 1323 char * cp; 1324 const struct lookup * lp; 1325 int nfields; 1326 bool wantcont; 1327 lineno num; 1328 char buf[BUFSIZ]; 1329 1330 if (strcmp(name, "-") == 0) { 1331 name = _("standard input"); 1332 fp = stdin; 1333 } else if ((fp = fopen(name, "r")) == NULL) { 1334 const char *e = strerror(errno); 1335 1336 fprintf(stderr, _("%s: Can't open %s: %s\n"), 1337 progname, name, e); 1338 exit(EXIT_FAILURE); 1339 } 1340 wantcont = false; 1341 for (num = 1; ; ++num) { 1342 eat(name, num); 1343 if (fgets(buf, (int) sizeof buf, fp) != buf) 1344 break; 1345 cp = strchr(buf, '\n'); 1346 if (cp == NULL) { 1347 error(_("line too long")); 1348 exit(EXIT_FAILURE); 1349 } 1350 *cp = '\0'; 1351 fields = getfields(buf); 1352 nfields = 0; 1353 while (fields[nfields] != NULL) { 1354 static char nada; 1355 1356 if (strcmp(fields[nfields], "-") == 0) 1357 fields[nfields] = &nada; 1358 ++nfields; 1359 } 1360 if (nfields == 0) { 1361 /* nothing to do */ 1362 } else if (wantcont) { 1363 wantcont = inzcont(fields, nfields); 1364 } else { 1365 struct lookup const *line_codes 1366 = name == leapsec ? leap_line_codes : zi_line_codes; 1367 lp = byword(fields[0], line_codes); 1368 if (lp == NULL) 1369 error(_("input line of unknown type")); 1370 else switch (lp->l_value) { 1371 case LC_RULE: 1372 inrule(fields, nfields); 1373 wantcont = false; 1374 break; 1375 case LC_ZONE: 1376 wantcont = inzone(fields, nfields); 1377 break; 1378 case LC_LINK: 1379 inlink(fields, nfields); 1380 wantcont = false; 1381 break; 1382 case LC_LEAP: 1383 inleap(fields, nfields); 1384 wantcont = false; 1385 break; 1386 case LC_EXPIRES: 1387 inexpires(fields, nfields); 1388 wantcont = false; 1389 break; 1390 default: UNREACHABLE(); 1391 } 1392 } 1393 free(fields); 1394 } 1395 close_file(fp, NULL, filename, NULL); 1396 if (wantcont) 1397 error(_("expected continuation line not found")); 1398 } 1399 1400 /* 1401 ** Convert a string of one of the forms 1402 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 1403 ** into a number of seconds. 1404 ** A null string maps to zero. 1405 ** Call error with errstring and return zero on errors. 1406 */ 1407 1408 static zic_t 1409 gethms(char const *string, char const *errstring) 1410 { 1411 zic_t hh; 1412 int sign, mm = 0, ss = 0; 1413 char hhx, mmx, ssx, xr = '0', xs; 1414 int tenths = 0; 1415 bool ok = true; 1416 1417 if (string == NULL || *string == '\0') 1418 return 0; 1419 if (*string == '-') { 1420 sign = -1; 1421 ++string; 1422 } else sign = 1; 1423 switch (sscanf(string, 1424 "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c", 1425 &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) { 1426 default: ok = false; break; 1427 case 8: 1428 ok = '0' <= xr && xr <= '9'; 1429 /* fallthrough */ 1430 case 7: 1431 ok &= ssx == '.'; 1432 if (ok && noise) 1433 warning(_("fractional seconds rejected by" 1434 " pre-2018 versions of zic")); 1435 /* fallthrough */ 1436 case 5: ok &= mmx == ':'; /* fallthrough */ 1437 case 3: ok &= hhx == ':'; /* fallthrough */ 1438 case 1: break; 1439 } 1440 if (!ok) { 1441 error("%s", errstring); 1442 return 0; 1443 } 1444 if (hh < 0 || 1445 mm < 0 || mm >= MINSPERHOUR || 1446 ss < 0 || ss > SECSPERMIN) { 1447 error("%s", errstring); 1448 return 0; 1449 } 1450 if (ZIC_MAX / SECSPERHOUR < hh) { 1451 error(_("time overflow")); 1452 return 0; 1453 } 1454 ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */ 1455 if (noise && (hh > HOURSPERDAY || 1456 (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 1457 warning(_("values over 24 hours not handled by pre-2007 versions of zic")); 1458 return oadd(sign * hh * SECSPERHOUR, 1459 sign * (mm * SECSPERMIN + ss)); 1460 } 1461 1462 static zic_t 1463 getsave(char *field, bool *isdst) 1464 { 1465 int dst = -1; 1466 zic_t save; 1467 size_t fieldlen = strlen(field); 1468 if (fieldlen != 0) { 1469 char *ep = field + fieldlen - 1; 1470 switch (*ep) { 1471 case 'd': dst = 1; *ep = '\0'; break; 1472 case 's': dst = 0; *ep = '\0'; break; 1473 } 1474 } 1475 save = gethms(field, _("invalid saved time")); 1476 *isdst = dst < 0 ? save != 0 : dst; 1477 return save; 1478 } 1479 1480 static void 1481 inrule(char **fields, int nfields) 1482 { 1483 struct rule r; 1484 1485 if (nfields != RULE_FIELDS) { 1486 error(_("wrong number of fields on Rule line")); 1487 return; 1488 } 1489 switch (*fields[RF_NAME]) { 1490 case '\0': 1491 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': 1492 case '+': case '-': 1493 case '0': case '1': case '2': case '3': case '4': 1494 case '5': case '6': case '7': case '8': case '9': 1495 error(_("Invalid rule name \"%s\""), fields[RF_NAME]); 1496 return; 1497 } 1498 r.r_filename = filename; 1499 r.r_linenum = linenum; 1500 r.r_save = getsave(fields[RF_SAVE], &r.r_isdst); 1501 if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], 1502 fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], 1503 fields[RF_TOD])) 1504 return; 1505 r.r_name = ecpyalloc(fields[RF_NAME]); 1506 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 1507 if (max_abbrvar_len < strlen(r.r_abbrvar)) 1508 max_abbrvar_len = strlen(r.r_abbrvar); 1509 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); 1510 rules[nrules++] = r; 1511 } 1512 1513 static bool 1514 inzone(char **fields, int nfields) 1515 { 1516 ptrdiff_t i; 1517 1518 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 1519 error(_("wrong number of fields on Zone line")); 1520 return false; 1521 } 1522 if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) { 1523 error( 1524 _("\"Zone %s\" line and -l option are mutually exclusive"), 1525 tzdefault); 1526 return false; 1527 } 1528 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 1529 error( 1530 _("\"Zone %s\" line and -p option are mutually exclusive"), 1531 TZDEFRULES); 1532 return false; 1533 } 1534 for (i = 0; i < nzones; ++i) 1535 if (zones[i].z_name != NULL && 1536 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 1537 error(_("duplicate zone name %s" 1538 " (file \"%s\", line %"PRIdMAX")"), 1539 fields[ZF_NAME], 1540 zones[i].z_filename, 1541 zones[i].z_linenum); 1542 return false; 1543 } 1544 return inzsub(fields, nfields, false); 1545 } 1546 1547 static bool 1548 inzcont(char **fields, int nfields) 1549 { 1550 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 1551 error(_("wrong number of fields on Zone continuation line")); 1552 return false; 1553 } 1554 return inzsub(fields, nfields, true); 1555 } 1556 1557 static bool 1558 inzsub(char **fields, int nfields, bool iscont) 1559 { 1560 char * cp; 1561 char * cp1; 1562 struct zone z; 1563 size_t format_len; 1564 int i_stdoff, i_rule, i_format; 1565 int i_untilyear, i_untilmonth; 1566 int i_untilday, i_untiltime; 1567 bool hasuntil; 1568 1569 if (iscont) { 1570 i_stdoff = ZFC_STDOFF; 1571 i_rule = ZFC_RULE; 1572 i_format = ZFC_FORMAT; 1573 i_untilyear = ZFC_TILYEAR; 1574 i_untilmonth = ZFC_TILMONTH; 1575 i_untilday = ZFC_TILDAY; 1576 i_untiltime = ZFC_TILTIME; 1577 } else if (!namecheck(fields[ZF_NAME])) 1578 return false; 1579 else { 1580 i_stdoff = ZF_STDOFF; 1581 i_rule = ZF_RULE; 1582 i_format = ZF_FORMAT; 1583 i_untilyear = ZF_TILYEAR; 1584 i_untilmonth = ZF_TILMONTH; 1585 i_untilday = ZF_TILDAY; 1586 i_untiltime = ZF_TILTIME; 1587 } 1588 z.z_filename = filename; 1589 z.z_linenum = linenum; 1590 z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset")); 1591 if ((cp = strchr(fields[i_format], '%')) != 0) { 1592 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') 1593 || strchr(fields[i_format], '/')) { 1594 error(_("invalid abbreviation format")); 1595 return false; 1596 } 1597 } 1598 z.z_format_specifier = cp ? *cp : '\0'; 1599 format_len = strlen(fields[i_format]); 1600 if (max_format_len < format_len) 1601 max_format_len = format_len; 1602 hasuntil = nfields > i_untilyear; 1603 if (hasuntil) { 1604 z.z_untilrule.r_filename = filename; 1605 z.z_untilrule.r_linenum = linenum; 1606 if (!rulesub( 1607 &z.z_untilrule, 1608 fields[i_untilyear], 1609 "only", 1610 "", 1611 (nfields > i_untilmonth) ? 1612 fields[i_untilmonth] : "Jan", 1613 (nfields > i_untilday) ? fields[i_untilday] : "1", 1614 (nfields > i_untiltime) ? fields[i_untiltime] : "0")) 1615 return false; 1616 z.z_untiltime = rpytime(&z.z_untilrule, 1617 z.z_untilrule.r_loyear); 1618 if (iscont && nzones > 0 && 1619 z.z_untiltime > min_time && 1620 z.z_untiltime < max_time && 1621 zones[nzones - 1].z_untiltime > min_time && 1622 zones[nzones - 1].z_untiltime < max_time && 1623 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1624 error(_( 1625 "Zone continuation line end time is not after end time of previous line" 1626 )); 1627 return false; 1628 } 1629 } 1630 z.z_name = iscont ? NULL : ecpyalloc(fields[ZF_NAME]); 1631 z.z_rule = ecpyalloc(fields[i_rule]); 1632 z.z_format = cp1 = ecpyalloc(fields[i_format]); 1633 if (z.z_format_specifier == 'z') { 1634 cp1[cp - fields[i_format]] = 's'; 1635 if (noise) 1636 warning(_("format '%s' not handled by pre-2015 versions of zic"), 1637 fields[i_format]); 1638 } 1639 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc); 1640 zones[nzones++] = z; 1641 /* 1642 ** If there was an UNTIL field on this line, 1643 ** there's more information about the zone on the next line. 1644 */ 1645 return hasuntil; 1646 } 1647 1648 static zic_t 1649 getleapdatetime(char **fields, int nfields, bool expire_line) 1650 { 1651 const char * cp; 1652 const struct lookup * lp; 1653 zic_t i, j; 1654 zic_t year; 1655 int month, day; 1656 zic_t dayoff, tod; 1657 zic_t t; 1658 char xs; 1659 1660 dayoff = 0; 1661 cp = fields[LP_YEAR]; 1662 if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) { 1663 /* 1664 ** Leapin' Lizards! 1665 */ 1666 error(_("invalid leaping year")); 1667 return -1; 1668 } 1669 if (!expire_line) { 1670 if (!leapseen || leapmaxyear < year) 1671 leapmaxyear = year; 1672 if (!leapseen || leapminyear > year) 1673 leapminyear = year; 1674 leapseen = true; 1675 } 1676 j = EPOCH_YEAR; 1677 while (j != year) { 1678 if (year > j) { 1679 i = len_years[isleap(j)]; 1680 ++j; 1681 } else { 1682 --j; 1683 i = -len_years[isleap(j)]; 1684 } 1685 dayoff = oadd(dayoff, i); 1686 } 1687 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1688 error(_("invalid month name")); 1689 return -1; 1690 } 1691 month = lp->l_value; 1692 j = TM_JANUARY; 1693 while (j != month) { 1694 i = len_months[isleap(year)][j]; 1695 dayoff = oadd(dayoff, i); 1696 ++j; 1697 } 1698 cp = fields[LP_DAY]; 1699 if (sscanf(cp, "%d%c", &day, &xs) != 1 || 1700 day <= 0 || day > len_months[isleap(year)][month]) { 1701 error(_("invalid day of month")); 1702 return -1; 1703 } 1704 dayoff = oadd(dayoff, day - 1); 1705 if (dayoff < min_time / SECSPERDAY) { 1706 error(_("time too small")); 1707 return -1; 1708 } 1709 if (dayoff > max_time / SECSPERDAY) { 1710 error(_("time too large")); 1711 return -1; 1712 } 1713 t = dayoff * SECSPERDAY; 1714 tod = gethms(fields[LP_TIME], _("invalid time of day")); 1715 t = tadd(t, tod); 1716 if (t < 0) 1717 error(_("leap second precedes Epoch")); 1718 return t; 1719 } 1720 1721 static void 1722 inleap(char **fields, int nfields) 1723 { 1724 if (nfields != LEAP_FIELDS) 1725 error(_("wrong number of fields on Leap line")); 1726 else { 1727 zic_t t = getleapdatetime(fields, nfields, false); 1728 if (0 <= t) { 1729 struct lookup const *lp = byword(fields[LP_ROLL], leap_types); 1730 if (!lp) 1731 error(_("invalid Rolling/Stationary field on Leap line")); 1732 else { 1733 int correction = 0; 1734 if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */ 1735 correction = -1; 1736 else if (strcmp(fields[LP_CORR], "+") == 0) 1737 correction = 1; 1738 else 1739 error(_("invalid CORRECTION field on Leap line")); 1740 if (correction) 1741 leapadd(t, correction, lp->l_value); 1742 } 1743 } 1744 } 1745 } 1746 1747 static void 1748 inexpires(char **fields, int nfields) 1749 { 1750 if (nfields != EXPIRES_FIELDS) 1751 error(_("wrong number of fields on Expires line")); 1752 else if (0 <= leapexpires) 1753 error(_("multiple Expires lines")); 1754 else 1755 leapexpires = getleapdatetime(fields, nfields, true); 1756 } 1757 1758 static void 1759 inlink(char **fields, int nfields) 1760 { 1761 struct link l; 1762 1763 if (nfields != LINK_FIELDS) { 1764 error(_("wrong number of fields on Link line")); 1765 return; 1766 } 1767 if (*fields[LF_TARGET] == '\0') { 1768 error(_("blank TARGET field on Link line")); 1769 return; 1770 } 1771 if (! namecheck(fields[LF_LINKNAME])) 1772 return; 1773 l.l_filename = filename; 1774 l.l_linenum = linenum; 1775 l.l_target = ecpyalloc(fields[LF_TARGET]); 1776 l.l_linkname = ecpyalloc(fields[LF_LINKNAME]); 1777 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); 1778 links[nlinks++] = l; 1779 } 1780 1781 static bool 1782 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, 1783 const char *typep, const char *monthp, const char *dayp, 1784 const char *timep) 1785 { 1786 const struct lookup * lp; 1787 const char * cp; 1788 char * dp; 1789 char * ep; 1790 char xs; 1791 1792 if ((lp = byword(monthp, mon_names)) == NULL) { 1793 error(_("invalid month name")); 1794 return false; 1795 } 1796 rp->r_month = lp->l_value; 1797 rp->r_todisstd = false; 1798 rp->r_todisut = false; 1799 dp = ecpyalloc(timep); 1800 if (*dp != '\0') { 1801 ep = dp + strlen(dp) - 1; 1802 switch (lowerit(*ep)) { 1803 case 's': /* Standard */ 1804 rp->r_todisstd = true; 1805 rp->r_todisut = false; 1806 *ep = '\0'; 1807 break; 1808 case 'w': /* Wall */ 1809 rp->r_todisstd = false; 1810 rp->r_todisut = false; 1811 *ep = '\0'; 1812 break; 1813 case 'g': /* Greenwich */ 1814 case 'u': /* Universal */ 1815 case 'z': /* Zulu */ 1816 rp->r_todisstd = true; 1817 rp->r_todisut = true; 1818 *ep = '\0'; 1819 break; 1820 } 1821 } 1822 rp->r_tod = gethms(dp, _("invalid time of day")); 1823 free(dp); 1824 /* 1825 ** Year work. 1826 */ 1827 cp = loyearp; 1828 lp = byword(cp, begin_years); 1829 rp->r_lowasnum = lp == NULL; 1830 if (!rp->r_lowasnum) switch (lp->l_value) { 1831 case YR_MINIMUM: 1832 rp->r_loyear = ZIC_MIN; 1833 break; 1834 case YR_MAXIMUM: 1835 rp->r_loyear = ZIC_MAX; 1836 break; 1837 default: UNREACHABLE(); 1838 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) { 1839 error(_("invalid starting year")); 1840 return false; 1841 } 1842 cp = hiyearp; 1843 lp = byword(cp, end_years); 1844 rp->r_hiwasnum = lp == NULL; 1845 if (!rp->r_hiwasnum) switch (lp->l_value) { 1846 case YR_MINIMUM: 1847 rp->r_hiyear = ZIC_MIN; 1848 break; 1849 case YR_MAXIMUM: 1850 rp->r_hiyear = ZIC_MAX; 1851 break; 1852 case YR_ONLY: 1853 rp->r_hiyear = rp->r_loyear; 1854 break; 1855 default: UNREACHABLE(); 1856 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) { 1857 error(_("invalid ending year")); 1858 return false; 1859 } 1860 if (rp->r_loyear > rp->r_hiyear) { 1861 error(_("starting year greater than ending year")); 1862 return false; 1863 } 1864 if (*typep != '\0') { 1865 error(_("year type \"%s\" is unsupported; use \"-\" instead"), 1866 typep); 1867 return false; 1868 } 1869 /* 1870 ** Day work. 1871 ** Accept things such as: 1872 ** 1 1873 ** lastSunday 1874 ** last-Sunday (undocumented; warn about this) 1875 ** Sun<=20 1876 ** Sun>=7 1877 */ 1878 dp = ecpyalloc(dayp); 1879 if ((lp = byword(dp, lasts)) != NULL) { 1880 rp->r_dycode = DC_DOWLEQ; 1881 rp->r_wday = lp->l_value; 1882 rp->r_dayofmonth = len_months[1][rp->r_month]; 1883 } else { 1884 if ((ep = strchr(dp, '<')) != 0) 1885 rp->r_dycode = DC_DOWLEQ; 1886 else if ((ep = strchr(dp, '>')) != 0) 1887 rp->r_dycode = DC_DOWGEQ; 1888 else { 1889 ep = dp; 1890 rp->r_dycode = DC_DOM; 1891 } 1892 if (rp->r_dycode != DC_DOM) { 1893 *ep++ = 0; 1894 if (*ep++ != '=') { 1895 error(_("invalid day of month")); 1896 free(dp); 1897 return false; 1898 } 1899 if ((lp = byword(dp, wday_names)) == NULL) { 1900 error(_("invalid weekday name")); 1901 free(dp); 1902 return false; 1903 } 1904 rp->r_wday = lp->l_value; 1905 } 1906 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 || 1907 rp->r_dayofmonth <= 0 || 1908 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1909 error(_("invalid day of month")); 1910 free(dp); 1911 return false; 1912 } 1913 } 1914 free(dp); 1915 return true; 1916 } 1917 1918 static void 1919 convert(uint_fast32_t val, char *buf) 1920 { 1921 int i; 1922 int shift; 1923 unsigned char *const b = (unsigned char *) buf; 1924 1925 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1926 b[i] = (val >> shift) & 0xff; 1927 } 1928 1929 static void 1930 convert64(uint_fast64_t val, char *buf) 1931 { 1932 int i; 1933 int shift; 1934 unsigned char *const b = (unsigned char *) buf; 1935 1936 for (i = 0, shift = 56; i < 8; ++i, shift -= 8) 1937 b[i] = (val >> shift) & 0xff; 1938 } 1939 1940 static void 1941 puttzcode(const int_fast32_t val, FILE *const fp) 1942 { 1943 char buf[4]; 1944 1945 convert(val, buf); 1946 fwrite(buf, sizeof buf, (size_t) 1, fp); 1947 } 1948 1949 static void 1950 puttzcodepass(zic_t val, FILE *fp, int pass) 1951 { 1952 if (pass == 1) 1953 puttzcode(val, fp); 1954 else { 1955 char buf[8]; 1956 1957 convert64(val, buf); 1958 fwrite(buf, sizeof buf, (size_t) 1, fp); 1959 } 1960 } 1961 1962 static int 1963 atcomp(const void *avp, const void *bvp) 1964 { 1965 struct attype const *ap = avp, *bp = bvp; 1966 zic_t a = ap->at, b = bp->at; 1967 return a < b ? -1 : a > b; 1968 } 1969 1970 struct timerange { 1971 int defaulttype; 1972 ptrdiff_t base, count; 1973 int leapbase, leapcount; 1974 bool pretrans, leapexpiry; 1975 }; 1976 1977 static struct timerange 1978 limitrange(struct timerange r, bool locut, zic_t lo, zic_t hi, 1979 zic_t const *ats, unsigned char const *types) 1980 { 1981 /* Omit ordinary transitions < LO. */ 1982 while (0 < r.count && ats[r.base] < lo) { 1983 r.defaulttype = types[r.base]; 1984 r.count--; 1985 r.base++; 1986 } 1987 1988 /* "-00" before any -r low cutoff. */ 1989 if (min_time < lo_time) 1990 r.defaulttype = unspecifiedtype; 1991 1992 /* Omit as many initial leap seconds as possible, such that the 1993 first leap second in the truncated list is <= LO, and is a 1994 positive leap second if and only if it has a positive correction. 1995 This supports common TZif readers that assume that the first leap 1996 second is positive if and only if its correction is positive. */ 1997 while (1 < r.leapcount && trans[r.leapbase + 1] <= lo) { 1998 r.leapcount--; 1999 r.leapbase++; 2000 } 2001 while (0 < r.leapbase 2002 && ((corr[r.leapbase - 1] < corr[r.leapbase]) 2003 != (0 < corr[r.leapbase]))) { 2004 r.leapcount++; 2005 r.leapbase--; 2006 } 2007 2008 2009 /* Omit ordinary and leap second transitions greater than HI + 1. */ 2010 if (hi < max_time) { 2011 while (0 < r.count && hi + 1 < ats[r.base + r.count - 1]) 2012 r.count--; 2013 while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1]) 2014 r.leapcount--; 2015 } 2016 2017 /* Determine whether to keep the last too-low transition if no 2018 transition is exactly at LO. The kept transition will be output 2019 as a LO "transition"; see "Output a LO_TIME transition" below. 2020 This is needed when the output is truncated at the start, and is 2021 also useful when catering to buggy 32-bit clients that do not use 2022 time type 0 for timestamps before the first transition. */ 2023 r.pretrans = locut && r.base && ! (r.count && ats[r.base] == lo); 2024 2025 /* Determine whether to append an expiration to the leap second table. */ 2026 r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi; 2027 2028 return r; 2029 } 2030 2031 static void 2032 writezone(const char *const name, const char *const string, char version, 2033 int defaulttype) 2034 { 2035 FILE * fp; 2036 ptrdiff_t i, j; 2037 int pass; 2038 zic_t one = 1; 2039 zic_t y2038_boundary = one << 31; 2040 ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071; 2041 char *tempname = NULL; 2042 char const *outname = name; 2043 2044 /* Allocate the ATS and TYPES arrays via a single malloc, 2045 as this is a bit faster. */ 2046 zic_t *ats = zic_malloc(align_to(size_product(nats, sizeof *ats + 1), 2047 _Alignof(zic_t))); 2048 void *typesptr = ats + nats; 2049 unsigned char *types = typesptr; 2050 struct timerange rangeall, range32, range64; 2051 2052 /* 2053 ** Sort. 2054 */ 2055 if (timecnt > 1) 2056 qsort(attypes, (size_t) timecnt, sizeof *attypes, atcomp); 2057 /* 2058 ** Optimize. 2059 */ 2060 { 2061 ptrdiff_t fromi, toi; 2062 2063 toi = 0; 2064 fromi = 0; 2065 for ( ; fromi < timecnt; ++fromi) { 2066 if (toi != 0 2067 && ((attypes[fromi].at 2068 + utoffs[attypes[toi - 1].type]) 2069 <= (attypes[toi - 1].at 2070 + utoffs[toi == 1 ? 0 2071 : attypes[toi - 2].type]))) { 2072 attypes[toi - 1].type = 2073 attypes[fromi].type; 2074 continue; 2075 } 2076 if (toi == 0 2077 || attypes[fromi].dontmerge 2078 || (utoffs[attypes[toi - 1].type] 2079 != utoffs[attypes[fromi].type]) 2080 || (isdsts[attypes[toi - 1].type] 2081 != isdsts[attypes[fromi].type]) 2082 || (desigidx[attypes[toi - 1].type] 2083 != desigidx[attypes[fromi].type])) 2084 attypes[toi++] = attypes[fromi]; 2085 } 2086 timecnt = toi; 2087 } 2088 2089 if (noise && timecnt > 1200) { 2090 if (timecnt > TZ_MAX_TIMES) 2091 warning(_("reference clients mishandle" 2092 " more than %d transition times"), 2093 TZ_MAX_TIMES); 2094 else 2095 warning(_("pre-2014 clients may mishandle" 2096 " more than 1200 transition times")); 2097 } 2098 /* 2099 ** Transfer. 2100 */ 2101 for (i = 0; i < timecnt; ++i) { 2102 ats[i] = attypes[i].at; 2103 types[i] = attypes[i].type; 2104 } 2105 2106 /* 2107 ** Correct for leap seconds. 2108 */ 2109 for (i = 0; i < timecnt; ++i) { 2110 j = leapcnt; 2111 while (--j >= 0) 2112 if (ats[i] > trans[j] - corr[j]) { 2113 ats[i] = tadd(ats[i], corr[j]); 2114 break; 2115 } 2116 } 2117 2118 /* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1, 2119 by inserting a no-op transition at time y2038_boundary - 1. 2120 This works only for timestamps before the boundary, which 2121 should be good enough in practice as QTBUG-53071 should be 2122 long-dead by 2038. Do this after correcting for leap 2123 seconds, as the idea is to insert a transition just before 2124 32-bit time_t rolls around, and this occurs at a slightly 2125 different moment if transitions are leap-second corrected. */ 2126 if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat() 2127 && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) { 2128 ats[timecnt] = y2038_boundary - 1; 2129 types[timecnt] = types[timecnt - 1]; 2130 timecnt++; 2131 } 2132 2133 rangeall.defaulttype = defaulttype; 2134 rangeall.base = rangeall.leapbase = 0; 2135 rangeall.count = timecnt; 2136 rangeall.leapcount = leapcnt; 2137 rangeall.pretrans = rangeall.leapexpiry = false; 2138 range64 = limitrange(rangeall, min_time < lo_time, 2139 lo_time, hi_time, ats, types); 2140 range32 = limitrange(range64, true, 2141 INT32_MIN, INT32_MAX, ats, types); 2142 2143 /* TZif version 4 is needed if a no-op transition is appended to 2144 indicate the expiration of the leap second table, or if the first 2145 leap second transition is not to a +1 or -1 correction. */ 2146 for (pass = 1; pass <= 2; pass++) { 2147 struct timerange const *r = pass == 1 ? &range32 : &range64; 2148 if (pass == 1 && !want_bloat()) 2149 continue; 2150 if (r->leapexpiry) { 2151 if (noise) 2152 warning(_("%s: pre-2021b clients may mishandle" 2153 " leap second expiry"), 2154 name); 2155 version = '4'; 2156 } 2157 if (0 < r->leapcount 2158 && corr[r->leapbase] != 1 && corr[r->leapbase] != -1) { 2159 if (noise) 2160 warning(_("%s: pre-2021b clients may mishandle" 2161 " leap second table truncation"), 2162 name); 2163 version = '4'; 2164 } 2165 if (version == '4') 2166 break; 2167 } 2168 2169 fp = open_outfile(&outname, &tempname); 2170 2171 for (pass = 1; pass <= 2; ++pass) { 2172 ptrdiff_t thistimei, thistimecnt, thistimelim; 2173 int thisleapi, thisleapcnt, thisleaplim; 2174 struct tzhead tzh; 2175 int thisdefaulttype; 2176 bool hicut, pretrans, thisleapexpiry; 2177 zic_t lo; 2178 int old0; 2179 char omittype[TZ_MAX_TYPES]; 2180 int typemap[TZ_MAX_TYPES]; 2181 int thistypecnt, stdcnt, utcnt; 2182 char thischars[TZ_MAX_CHARS]; 2183 int thischarcnt; 2184 bool toomanytimes; 2185 int indmap[TZ_MAX_CHARS]; 2186 2187 if (pass == 1) { 2188 /* Arguably the default time type in the 32-bit data 2189 should be range32.defaulttype, which is suited for 2190 timestamps just before INT32_MIN. However, zic 2191 traditionally used the time type of the indefinite 2192 past instead. Internet RFC 8532 says readers should 2193 ignore 32-bit data, so this discrepancy matters only 2194 to obsolete readers where the traditional type might 2195 be more appropriate even if it's "wrong". So, use 2196 the historical zic value, unless -r specifies a low 2197 cutoff that excludes some 32-bit timestamps. */ 2198 thisdefaulttype = (lo_time <= INT32_MIN 2199 ? range64.defaulttype 2200 : range32.defaulttype); 2201 2202 thistimei = range32.base; 2203 thistimecnt = range32.count; 2204 toomanytimes = thistimecnt >> 31 >> 1 != 0; 2205 thisleapi = range32.leapbase; 2206 thisleapcnt = range32.leapcount; 2207 pretrans = range32.pretrans; 2208 thisleapexpiry = range32.leapexpiry; 2209 hicut = hi_time < INT32_MAX; 2210 } else { 2211 thisdefaulttype = range64.defaulttype; 2212 thistimei = range64.base; 2213 thistimecnt = range64.count; 2214 toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0; 2215 thisleapi = range64.leapbase; 2216 thisleapcnt = range64.leapcount; 2217 pretrans = range64.pretrans; 2218 thisleapexpiry = range64.leapexpiry; 2219 hicut = hi_time < max_time; 2220 } 2221 if (toomanytimes) 2222 error(_("too many transition times")); 2223 2224 thistimelim = thistimei + thistimecnt; 2225 memset(omittype, true, typecnt); 2226 omittype[thisdefaulttype] = false; 2227 for (i = thistimei - pretrans; i < thistimelim; i++) 2228 omittype[types[i]] = false; 2229 if (hicut) 2230 omittype[unspecifiedtype] = false; 2231 2232 /* Reorder types to make THISDEFAULTTYPE type 0. 2233 Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that 2234 THISDEFAULTTYPE appears as type 0 in the output instead 2235 of OLD0. TYPEMAP also omits unused types. */ 2236 old0 = strlen(omittype); 2237 2238 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH 2239 /* 2240 ** For some pre-2011 systems: if the last-to-be-written 2241 ** standard (or daylight) type has an offset different from the 2242 ** most recently used offset, 2243 ** append an (unused) copy of the most recently used type 2244 ** (to help get global "altzone" and "timezone" variables 2245 ** set correctly). 2246 */ 2247 if (want_bloat()) { 2248 int mrudst, mrustd, hidst, histd, type; 2249 2250 hidst = histd = mrudst = mrustd = -1; 2251 for (i = thistimei - pretrans; i < thistimelim; ++i) 2252 if (isdsts[types[i]]) 2253 mrudst = types[i]; 2254 else mrustd = types[i]; 2255 for (i = old0; i < typecnt; i++) { 2256 int h = (i == old0 ? thisdefaulttype 2257 : i == thisdefaulttype ? old0 : i); 2258 if (!omittype[h]) { 2259 if (isdsts[h]) 2260 hidst = i; 2261 else 2262 histd = i; 2263 } 2264 } 2265 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && 2266 utoffs[hidst] != utoffs[mrudst]) { 2267 isdsts[mrudst] = -1; 2268 type = addtype(utoffs[mrudst], 2269 &chars[desigidx[mrudst]], 2270 true, 2271 ttisstds[mrudst], 2272 ttisuts[mrudst]); 2273 isdsts[mrudst] = 1; 2274 omittype[type] = false; 2275 } 2276 if (histd >= 0 && mrustd >= 0 && histd != mrustd && 2277 utoffs[histd] != utoffs[mrustd]) { 2278 isdsts[mrustd] = -1; 2279 type = addtype(utoffs[mrustd], 2280 &chars[desigidx[mrustd]], 2281 false, 2282 ttisstds[mrustd], 2283 ttisuts[mrustd]); 2284 isdsts[mrustd] = 0; 2285 omittype[type] = false; 2286 } 2287 } 2288 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ 2289 thistypecnt = 0; 2290 for (i = old0; i < typecnt; i++) 2291 if (!omittype[i]) 2292 typemap[i == old0 ? thisdefaulttype 2293 : i == thisdefaulttype ? old0 : i] 2294 = thistypecnt++; 2295 2296 for (i = 0; i < (int)(sizeof indmap / sizeof indmap[0]); ++i) 2297 indmap[i] = -1; 2298 thischarcnt = stdcnt = utcnt = 0; 2299 for (i = old0; i < typecnt; i++) { 2300 char * thisabbr; 2301 2302 if (omittype[i]) 2303 continue; 2304 if (ttisstds[i]) 2305 stdcnt = thistypecnt; 2306 if (ttisuts[i]) 2307 utcnt = thistypecnt; 2308 if (indmap[desigidx[i]] >= 0) 2309 continue; 2310 thisabbr = &chars[desigidx[i]]; 2311 for (j = 0; j < thischarcnt; ++j) 2312 if (strcmp(&thischars[j], thisabbr) == 0) 2313 break; 2314 if (j == thischarcnt) { 2315 strcpy(&thischars[thischarcnt], thisabbr); 2316 thischarcnt += strlen(thisabbr) + 1; 2317 } 2318 indmap[desigidx[i]] = j; 2319 } 2320 if (pass == 1 && !want_bloat()) { 2321 pretrans = hicut = thisleapexpiry = false; 2322 thistimecnt = thisleapcnt = 0; 2323 thistypecnt = thischarcnt = 1; 2324 } 2325 #define DO(field) fwrite(tzh.field, sizeof tzh.field, (size_t) 1, fp) 2326 memset(&tzh, 0, sizeof(tzh)); 2327 memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); 2328 tzh.tzh_version[0] = version; 2329 convert(utcnt, tzh.tzh_ttisutcnt); 2330 convert(stdcnt, tzh.tzh_ttisstdcnt); 2331 convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt); 2332 convert(pretrans + thistimecnt + hicut, tzh.tzh_timecnt); 2333 convert(thistypecnt, tzh.tzh_typecnt); 2334 convert(thischarcnt, tzh.tzh_charcnt); 2335 DO(tzh_magic); 2336 DO(tzh_version); 2337 DO(tzh_reserved); 2338 DO(tzh_ttisutcnt); 2339 DO(tzh_ttisstdcnt); 2340 DO(tzh_leapcnt); 2341 DO(tzh_timecnt); 2342 DO(tzh_typecnt); 2343 DO(tzh_charcnt); 2344 #undef DO 2345 if (pass == 1 && !want_bloat()) { 2346 /* Output a minimal data block with just one time type. */ 2347 puttzcode(0, fp); /* utoff */ 2348 putc(0, fp); /* dst */ 2349 putc(0, fp); /* index of abbreviation */ 2350 putc(0, fp); /* empty-string abbreviation */ 2351 continue; 2352 } 2353 2354 /* Output a LO_TIME transition if needed; see limitrange. 2355 But do not go below the minimum representable value 2356 for this pass. */ 2357 lo = pass == 1 && lo_time < INT32_MIN ? INT32_MIN : lo_time; 2358 2359 if (pretrans) 2360 puttzcodepass(lo, fp, pass); 2361 for (i = thistimei; i < thistimelim; ++i) { 2362 puttzcodepass(ats[i], fp, pass); 2363 } 2364 if (hicut) 2365 puttzcodepass(hi_time + 1, fp, pass); 2366 for (i = thistimei - pretrans; i < thistimelim; ++i) 2367 putc(typemap[types[i]], fp); 2368 if (hicut) 2369 putc(typemap[unspecifiedtype], fp); 2370 2371 for (i = old0; i < typecnt; i++) { 2372 int h = (i == old0 ? thisdefaulttype 2373 : i == thisdefaulttype ? old0 : i); 2374 if (!omittype[h]) { 2375 puttzcode(utoffs[h], fp); 2376 putc(isdsts[h], fp); 2377 putc(indmap[desigidx[h]], fp); 2378 } 2379 } 2380 if (thischarcnt != 0) 2381 fwrite(thischars, sizeof thischars[0], 2382 (size_t) thischarcnt, fp); 2383 thisleaplim = thisleapi + thisleapcnt; 2384 for (i = thisleapi; i < thisleaplim; ++i) { 2385 zic_t todo; 2386 2387 if (roll[i]) { 2388 if (timecnt == 0 || trans[i] < ats[0]) { 2389 j = 0; 2390 while (isdsts[j]) 2391 if (++j >= typecnt) { 2392 j = 0; 2393 break; 2394 } 2395 } else { 2396 j = 1; 2397 while (j < timecnt && 2398 trans[i] >= ats[j]) 2399 ++j; 2400 j = types[j - 1]; 2401 } 2402 todo = tadd(trans[i], -utoffs[j]); 2403 } else todo = trans[i]; 2404 puttzcodepass(todo, fp, pass); 2405 puttzcode(corr[i], fp); 2406 } 2407 if (thisleapexpiry) { 2408 /* Append a no-op leap correction indicating when the leap 2409 second table expires. Although this does not conform to 2410 Internet RFC 8536, most clients seem to accept this and 2411 the plan is to amend the RFC to allow this in version 4 2412 TZif files. */ 2413 puttzcodepass(leapexpires, fp, pass); 2414 puttzcode(thisleaplim ? corr[thisleaplim - 1] : 0, fp); 2415 } 2416 if (stdcnt != 0) 2417 for (i = old0; i < typecnt; i++) 2418 if (!omittype[i]) 2419 putc(ttisstds[i], fp); 2420 if (utcnt != 0) 2421 for (i = old0; i < typecnt; i++) 2422 if (!omittype[i]) 2423 putc(ttisuts[i], fp); 2424 } 2425 fprintf(fp, "\n%s\n", string); 2426 close_file(fp, directory, name, tempname); 2427 rename_dest(tempname, name); 2428 free(ats); 2429 } 2430 2431 static char const * 2432 abbroffset(char *buf, zic_t offset) 2433 { 2434 char sign = '+'; 2435 int seconds, minutes; 2436 2437 if (offset < 0) { 2438 offset = -offset; 2439 sign = '-'; 2440 } 2441 2442 seconds = offset % SECSPERMIN; 2443 offset /= SECSPERMIN; 2444 minutes = offset % MINSPERHOUR; 2445 offset /= MINSPERHOUR; 2446 if (100 <= offset) { 2447 error(_("%%z UT offset magnitude exceeds 99:59:59")); 2448 return "%z"; 2449 } else { 2450 char *p = buf; 2451 *p++ = sign; 2452 *p++ = '0' + offset / 10; 2453 *p++ = '0' + offset % 10; 2454 if (minutes | seconds) { 2455 *p++ = '0' + minutes / 10; 2456 *p++ = '0' + minutes % 10; 2457 if (seconds) { 2458 *p++ = '0' + seconds / 10; 2459 *p++ = '0' + seconds % 10; 2460 } 2461 } 2462 *p = '\0'; 2463 return buf; 2464 } 2465 } 2466 2467 static size_t 2468 doabbr(char *abbr, size_t abbrlen, struct zone const *zp, const char *letters, 2469 bool isdst, zic_t save, bool doquotes) 2470 { 2471 char * cp; 2472 char * slashp; 2473 size_t len; 2474 char const *format = zp->z_format; 2475 2476 slashp = strchr(format, '/'); 2477 if (slashp == NULL) { 2478 char letterbuf[PERCENT_Z_LEN_BOUND + 1]; 2479 if (zp->z_format_specifier == 'z') 2480 letters = abbroffset(letterbuf, zp->z_stdoff + save); 2481 else if (!letters) 2482 letters = "%s"; 2483 snprintf(abbr, abbrlen, format, letters); 2484 } else if (isdst) { 2485 strlcpy(abbr, slashp + 1, abbrlen); 2486 } else { 2487 memcpy(abbr, format, slashp - format); 2488 abbr[slashp - format] = '\0'; 2489 } 2490 len = strlen(abbr); 2491 if (!doquotes) 2492 return len; 2493 for (cp = abbr; is_alpha(*cp); cp++) 2494 continue; 2495 if (len > 0 && *cp == '\0') 2496 return len; 2497 abbr[len + 2] = '\0'; 2498 abbr[len + 1] = '>'; 2499 memmove(abbr + 1, abbr, len); 2500 abbr[0] = '<'; 2501 return len + 2; 2502 } 2503 2504 static void 2505 updateminmax(const zic_t x) 2506 { 2507 if (min_year > x) 2508 min_year = x; 2509 if (max_year < x) 2510 max_year = x; 2511 } 2512 2513 static int 2514 stringoffset(char *result, int resultlen, zic_t offset) 2515 { 2516 int hours; 2517 int minutes; 2518 int seconds; 2519 bool negative = offset < 0; 2520 int len = negative; 2521 2522 if (negative) { 2523 offset = -offset; 2524 result[0] = '-'; 2525 } 2526 seconds = offset % SECSPERMIN; 2527 offset /= SECSPERMIN; 2528 minutes = offset % MINSPERHOUR; 2529 offset /= MINSPERHOUR; 2530 hours = offset; 2531 if (hours >= HOURSPERDAY * DAYSPERWEEK) { 2532 result[0] = '\0'; 2533 return 0; 2534 } 2535 len += snprintf(result + len, resultlen - len, "%d", hours); 2536 if (minutes != 0 || seconds != 0) { 2537 len += snprintf(result + len, resultlen - len, 2538 ":%02d", minutes); 2539 if (seconds != 0) 2540 len += snprintf(result + len, resultlen - len, 2541 ":%02d", seconds); 2542 } 2543 return len; 2544 } 2545 2546 static int 2547 stringrule(char *result, int resultlen, struct rule *const rp, zic_t save, const zic_t stdoff) 2548 { 2549 zic_t tod = rp->r_tod; 2550 int compat = 0, len = 0; 2551 2552 if (rp->r_dycode == DC_DOM) { 2553 int month, total; 2554 2555 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) 2556 return -1; 2557 total = 0; 2558 for (month = 0; month < rp->r_month; ++month) 2559 total += len_months[0][month]; 2560 /* Omit the "J" in Jan and Feb, as that's shorter. */ 2561 if (rp->r_month <= 1) 2562 len += snprintf(result + len, resultlen - len, "%d", total + rp->r_dayofmonth - 1); 2563 else 2564 len += snprintf(result + len, resultlen - len, "J%d", total + rp->r_dayofmonth); 2565 } else { 2566 int week; 2567 int wday = rp->r_wday; 2568 int wdayoff; 2569 2570 if (rp->r_dycode == DC_DOWGEQ) { 2571 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK; 2572 if (wdayoff) 2573 compat = 2013; 2574 wday -= wdayoff; 2575 tod += wdayoff * SECSPERDAY; 2576 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK; 2577 } else if (rp->r_dycode == DC_DOWLEQ) { 2578 if (rp->r_dayofmonth == len_months[1][rp->r_month]) 2579 week = 5; 2580 else { 2581 wdayoff = rp->r_dayofmonth % DAYSPERWEEK; 2582 if (wdayoff) 2583 compat = 2013; 2584 wday -= wdayoff; 2585 tod += wdayoff * SECSPERDAY; 2586 week = rp->r_dayofmonth / DAYSPERWEEK; 2587 } 2588 } else return -1; /* "cannot happen" */ 2589 if (wday < 0) 2590 wday += DAYSPERWEEK; 2591 len += snprintf(result + len, resultlen - len, "M%d.%d.%d", 2592 rp->r_month + 1, week, wday); 2593 } 2594 if (rp->r_todisut) 2595 tod += stdoff; 2596 if (rp->r_todisstd && !rp->r_isdst) 2597 tod += save; 2598 if (tod != 2 * SECSPERMIN * MINSPERHOUR) { 2599 if (len + 1 < resultlen) 2600 result[len++] = '/'; 2601 if (! stringoffset(result + len, resultlen - len, tod)) 2602 return -1; 2603 if (tod < 0) { 2604 if (compat < 2013) 2605 compat = 2013; 2606 } else if (SECSPERDAY <= tod) { 2607 if (compat < 1994) 2608 compat = 1994; 2609 } 2610 } 2611 return compat; 2612 } 2613 2614 static int 2615 rule_cmp(struct rule const *a, struct rule const *b) 2616 { 2617 if (!a) 2618 return -!!b; 2619 if (!b) 2620 return 1; 2621 if (a->r_hiyear != b->r_hiyear) 2622 return a->r_hiyear < b->r_hiyear ? -1 : 1; 2623 if (a->r_hiyear == ZIC_MAX) 2624 return 0; 2625 if (a->r_month - b->r_month != 0) 2626 return a->r_month - b->r_month; 2627 return a->r_dayofmonth - b->r_dayofmonth; 2628 } 2629 2630 static int 2631 stringzone(char *result, int resultlen, const struct zone *const zpfirst, 2632 const int zonecount) 2633 { 2634 const struct zone * zp; 2635 struct rule * rp; 2636 struct rule * stdrp; 2637 struct rule * dstrp; 2638 ptrdiff_t i; 2639 int compat = 0; 2640 int c; 2641 size_t len; 2642 int offsetlen; 2643 struct rule stdr, dstr; 2644 int dstcmp; 2645 struct rule *lastrp[2] = { NULL, NULL }; 2646 struct zone zstr[2]; 2647 struct zone const *stdzp; 2648 struct zone const *dstzp; 2649 2650 result[0] = '\0'; 2651 2652 /* Internet RFC 8536 section 5.1 says to use an empty TZ string if 2653 future timestamps are truncated. */ 2654 if (hi_time < max_time) 2655 return -1; 2656 2657 zp = zpfirst + zonecount - 1; 2658 for (i = 0; i < zp->z_nrules; ++i) { 2659 struct rule **last; 2660 int cmp; 2661 rp = &zp->z_rules[i]; 2662 last = &lastrp[rp->r_isdst]; 2663 cmp = rule_cmp(*last, rp); 2664 if (cmp < 0) 2665 *last = rp; 2666 else if (cmp == 0) 2667 return -1; 2668 } 2669 stdrp = lastrp[false]; 2670 dstrp = lastrp[true]; 2671 dstcmp = zp->z_nrules ? rule_cmp(dstrp, stdrp) : zp->z_isdst ? 1 : -1; 2672 stdzp = dstzp = zp; 2673 2674 if (dstcmp < 0) { 2675 /* Standard time all year. */ 2676 dstrp = NULL; 2677 } else if (0 < dstcmp) { 2678 /* DST all year. Use an abbreviation like 2679 "XXX3EDT4,0/0,J365/23" for EDT (-04) all year. */ 2680 zic_t save = dstrp ? dstrp->r_save : zp->z_save; 2681 if (0 <= save) 2682 { 2683 /* Positive DST, the typical case for all-year DST. 2684 Fake a timezone with negative DST. */ 2685 stdzp = &zstr[0]; 2686 dstzp = &zstr[1]; 2687 zstr[0].z_stdoff = zp->z_stdoff + 2 * save; 2688 zstr[0].z_format = "XXX"; /* Any 3 letters will do. */ 2689 zstr[0].z_format_specifier = 0; 2690 zstr[1].z_stdoff = zstr[0].z_stdoff; 2691 zstr[1].z_format = zp->z_format; 2692 zstr[1].z_format_specifier = zp->z_format_specifier; 2693 } 2694 dstr.r_month = TM_JANUARY; 2695 dstr.r_dycode = DC_DOM; 2696 dstr.r_dayofmonth = 1; 2697 dstr.r_tod = 0; 2698 dstr.r_todisstd = dstr.r_todisut = false; 2699 dstr.r_isdst = true; 2700 dstr.r_save = save < 0 ? save : -save; 2701 dstr.r_abbrvar = dstrp ? dstrp->r_abbrvar : NULL; 2702 stdr.r_month = TM_DECEMBER; 2703 stdr.r_dycode = DC_DOM; 2704 stdr.r_dayofmonth = 31; 2705 stdr.r_tod = SECSPERDAY + dstr.r_save; 2706 stdr.r_todisstd = stdr.r_todisut = false; 2707 stdr.r_isdst = false; 2708 stdr.r_save = 0; 2709 stdr.r_abbrvar = save < 0 && stdrp ? stdrp->r_abbrvar : NULL; 2710 dstrp = &dstr; 2711 stdrp = &stdr; 2712 } 2713 len = doabbr(result, resultlen, stdzp, stdrp ? stdrp->r_abbrvar : NULL, 2714 false, 0, true); 2715 offsetlen = stringoffset(result + len, resultlen - len, 2716 -stdzp->z_stdoff); 2717 if (! offsetlen) { 2718 result[0] = '\0'; 2719 return -1; 2720 } 2721 len += offsetlen; 2722 if (dstrp == NULL) 2723 return compat; 2724 len += doabbr(result + len, resultlen - len, dstzp, dstrp->r_abbrvar, 2725 dstrp->r_isdst, dstrp->r_save, true); 2726 if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) { 2727 offsetlen = stringoffset(result + len, resultlen - len, 2728 - (dstzp->z_stdoff + dstrp->r_save)); 2729 if (! offsetlen) { 2730 result[0] = '\0'; 2731 return -1; 2732 } 2733 len += offsetlen; 2734 } 2735 result[len++] = ','; 2736 c = stringrule(result + len, resultlen - len, dstrp, dstrp->r_save, stdzp->z_stdoff); 2737 if (c < 0) { 2738 result[0] = '\0'; 2739 return -1; 2740 } 2741 if (compat < c) 2742 compat = c; 2743 len += strlen(result + len); 2744 result[len++] = ','; 2745 c = stringrule(result + len, resultlen - len, stdrp, dstrp->r_save, stdzp->z_stdoff); 2746 if (c < 0) { 2747 result[0] = '\0'; 2748 return -1; 2749 } 2750 if (compat < c) 2751 compat = c; 2752 return compat; 2753 } 2754 2755 static void 2756 outzone(const struct zone *zpfirst, ptrdiff_t zonecount) 2757 { 2758 const struct zone * zp; 2759 struct rule * rp; 2760 ptrdiff_t i, j; 2761 bool usestart, useuntil; 2762 zic_t starttime, untiltime; 2763 zic_t stdoff; 2764 zic_t save; 2765 zic_t year; 2766 zic_t startoff; 2767 bool startttisstd; 2768 bool startttisut; 2769 int type; 2770 char * startbuf; 2771 char * ab; 2772 char * envvar; 2773 size_t max_abbr_len; 2774 size_t max_envvar_len; 2775 bool prodstic; /* all rules are min to max */ 2776 int compat; 2777 bool do_extend; 2778 char version; 2779 ptrdiff_t lastatmax = -1; 2780 zic_t one = 1; 2781 zic_t y2038_boundary = one << 31; 2782 zic_t max_year0; 2783 int defaulttype = -1; 2784 2785 check_for_signal(); 2786 2787 max_abbr_len = 2 + max_format_len + max_abbrvar_len; 2788 max_envvar_len = 2 * max_abbr_len + 5 * 9; 2789 startbuf = zic_malloc(max_abbr_len + 1); 2790 ab = zic_malloc(max_abbr_len + 1); 2791 envvar = zic_malloc(max_envvar_len + 1); 2792 INITIALIZE(untiltime); 2793 INITIALIZE(starttime); 2794 /* 2795 ** Now. . .finally. . .generate some useful data! 2796 */ 2797 timecnt = 0; 2798 typecnt = 0; 2799 charcnt = 0; 2800 prodstic = zonecount == 1; 2801 /* 2802 ** Thanks to Earl Chew 2803 ** for noting the need to unconditionally initialize startttisstd. 2804 */ 2805 startttisstd = false; 2806 startttisut = false; 2807 min_year = max_year = EPOCH_YEAR; 2808 if (leapseen) { 2809 updateminmax(leapminyear); 2810 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX)); 2811 } 2812 for (i = 0; i < zonecount; ++i) { 2813 zp = &zpfirst[i]; 2814 if (i < zonecount - 1) 2815 updateminmax(zp->z_untilrule.r_loyear); 2816 for (j = 0; j < zp->z_nrules; ++j) { 2817 rp = &zp->z_rules[j]; 2818 if (rp->r_lowasnum) 2819 updateminmax(rp->r_loyear); 2820 if (rp->r_hiwasnum) 2821 updateminmax(rp->r_hiyear); 2822 if (rp->r_lowasnum || rp->r_hiwasnum) 2823 prodstic = false; 2824 } 2825 } 2826 /* 2827 ** Generate lots of data if a rule can't cover all future times. 2828 */ 2829 compat = stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount); 2830 version = compat < 2013 ? '2' : '3'; 2831 do_extend = compat < 0; 2832 if (noise) { 2833 if (!*envvar) 2834 warning("%s %s", 2835 _("no POSIX environment variable for zone"), 2836 zpfirst->z_name); 2837 else if (compat != 0) { 2838 /* Circa-COMPAT clients, and earlier clients, might 2839 not work for this zone when given dates before 2840 1970 or after 2038. */ 2841 warning(_("%s: pre-%d clients may mishandle" 2842 " distant timestamps"), 2843 zpfirst->z_name, compat); 2844 } 2845 } 2846 if (do_extend) { 2847 /* 2848 ** Search through a couple of extra years past the obvious 2849 ** 400, to avoid edge cases. For example, suppose a non-POSIX 2850 ** rule applies from 2012 onwards and has transitions in March 2851 ** and September, plus some one-off transitions in November 2852 ** 2013. If zic looked only at the last 400 years, it would 2853 ** set max_year=2413, with the intent that the 400 years 2014 2854 ** through 2413 will be repeated. The last transition listed 2855 ** in the tzfile would be in 2413-09, less than 400 years 2856 ** after the last one-off transition in 2013-11. Two years 2857 ** might be overkill, but with the kind of edge cases 2858 ** available we're not sure that one year would suffice. 2859 */ 2860 enum { years_of_observations = YEARSPERREPEAT + 2 }; 2861 2862 if (min_year >= ZIC_MIN + years_of_observations) 2863 min_year -= years_of_observations; 2864 else min_year = ZIC_MIN; 2865 if (max_year <= ZIC_MAX - years_of_observations) 2866 max_year += years_of_observations; 2867 else max_year = ZIC_MAX; 2868 /* 2869 ** Regardless of any of the above, 2870 ** for a "proDSTic" zone which specifies that its rules 2871 ** always have and always will be in effect, 2872 ** we only need one cycle to define the zone. 2873 */ 2874 if (prodstic) { 2875 min_year = 1900; 2876 max_year = min_year + years_of_observations; 2877 } 2878 } 2879 max_year0 = max_year; 2880 if (want_bloat()) { 2881 /* For the benefit of older systems, 2882 generate data from 1900 through 2038. */ 2883 if (min_year > 1900) 2884 min_year = 1900; 2885 if (max_year < 2038) 2886 max_year = 2038; 2887 } 2888 2889 if (min_time < lo_time || hi_time < max_time) 2890 unspecifiedtype = addtype(0, "-00", false, false, false); 2891 2892 for (i = 0; i < zonecount; ++i) { 2893 struct rule *prevrp = NULL; 2894 zic_t prevktime; 2895 INITIALIZE(prevktime); 2896 /* 2897 ** A guess that may well be corrected later. 2898 */ 2899 save = 0; 2900 zp = &zpfirst[i]; 2901 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 2902 useuntil = i < (zonecount - 1); 2903 if (useuntil && zp->z_untiltime <= min_time) 2904 continue; 2905 stdoff = zp->z_stdoff; 2906 eat(zp->z_filename, zp->z_linenum); 2907 *startbuf = '\0'; 2908 startoff = zp->z_stdoff; 2909 if (zp->z_nrules == 0) { 2910 save = zp->z_save; 2911 doabbr(startbuf, max_abbr_len + 1, 2912 zp, NULL, zp->z_isdst, save, false); 2913 type = addtype(oadd(zp->z_stdoff, save), 2914 startbuf, zp->z_isdst, startttisstd, 2915 startttisut); 2916 if (usestart) { 2917 addtt(starttime, type); 2918 usestart = false; 2919 } else 2920 defaulttype = type; 2921 } else for (year = min_year; year <= max_year; ++year) { 2922 if (useuntil && year > zp->z_untilrule.r_hiyear) 2923 break; 2924 /* 2925 ** Mark which rules to do in the current year. 2926 ** For those to do, calculate rpytime(rp, year); 2927 ** The former TYPE field was also considered here. 2928 */ 2929 for (j = 0; j < zp->z_nrules; ++j) { 2930 rp = &zp->z_rules[j]; 2931 eats(zp->z_filename, zp->z_linenum, 2932 rp->r_filename, rp->r_linenum); 2933 rp->r_todo = year >= rp->r_loyear && 2934 year <= rp->r_hiyear; 2935 if (rp->r_todo) { 2936 rp->r_temp = rpytime(rp, year); 2937 rp->r_todo 2938 = (rp->r_temp < y2038_boundary 2939 || year <= max_year0); 2940 } 2941 } 2942 for ( ; ; ) { 2943 ptrdiff_t k; 2944 zic_t jtime, ktime; 2945 zic_t offset; 2946 2947 INITIALIZE(ktime); 2948 if (useuntil) { 2949 /* 2950 ** Turn untiltime into UT 2951 ** assuming the current stdoff and 2952 ** save values. 2953 */ 2954 untiltime = zp->z_untiltime; 2955 if (!zp->z_untilrule.r_todisut) 2956 untiltime = tadd(untiltime, 2957 -stdoff); 2958 if (!zp->z_untilrule.r_todisstd) 2959 untiltime = tadd(untiltime, 2960 -save); 2961 } 2962 /* 2963 ** Find the rule (of those to do, if any) 2964 ** that takes effect earliest in the year. 2965 */ 2966 k = -1; 2967 for (j = 0; j < zp->z_nrules; ++j) { 2968 rp = &zp->z_rules[j]; 2969 if (!rp->r_todo) 2970 continue; 2971 eats(zp->z_filename, zp->z_linenum, 2972 rp->r_filename, rp->r_linenum); 2973 offset = rp->r_todisut ? 0 : stdoff; 2974 if (!rp->r_todisstd) 2975 offset = oadd(offset, save); 2976 jtime = rp->r_temp; 2977 if (jtime == min_time || 2978 jtime == max_time) 2979 continue; 2980 jtime = tadd(jtime, -offset); 2981 if (k < 0 || jtime < ktime) { 2982 k = j; 2983 ktime = jtime; 2984 } else if (jtime == ktime) { 2985 char const *dup_rules_msg = 2986 _("two rules for same instant"); 2987 eats(zp->z_filename, zp->z_linenum, 2988 rp->r_filename, rp->r_linenum); 2989 warning("%s", dup_rules_msg); 2990 rp = &zp->z_rules[k]; 2991 eats(zp->z_filename, zp->z_linenum, 2992 rp->r_filename, rp->r_linenum); 2993 error("%s", dup_rules_msg); 2994 } 2995 } 2996 if (k < 0) 2997 break; /* go on to next year */ 2998 rp = &zp->z_rules[k]; 2999 rp->r_todo = false; 3000 if (useuntil && ktime >= untiltime) 3001 break; 3002 save = rp->r_save; 3003 if (usestart && ktime == starttime) 3004 usestart = false; 3005 if (usestart) { 3006 if (ktime < starttime) { 3007 startoff = oadd(zp->z_stdoff, 3008 save); 3009 doabbr(startbuf, 3010 max_abbr_len + 1, 3011 zp, 3012 rp->r_abbrvar, 3013 rp->r_isdst, 3014 rp->r_save, 3015 false); 3016 continue; 3017 } 3018 if (*startbuf == '\0' 3019 && startoff == oadd(zp->z_stdoff, 3020 save)) { 3021 doabbr(startbuf, 3022 max_abbr_len + 1, 3023 zp, 3024 rp->r_abbrvar, 3025 rp->r_isdst, 3026 rp->r_save, 3027 false); 3028 } 3029 } 3030 eats(zp->z_filename, zp->z_linenum, 3031 rp->r_filename, rp->r_linenum); 3032 doabbr(ab, max_abbr_len + 1, zp, rp->r_abbrvar, 3033 rp->r_isdst, rp->r_save, false); 3034 offset = oadd(zp->z_stdoff, rp->r_save); 3035 if (!want_bloat() && !useuntil && !do_extend 3036 && prevrp && lo_time <= prevktime 3037 && rp->r_hiyear == ZIC_MAX 3038 && prevrp->r_hiyear == ZIC_MAX) 3039 break; 3040 type = addtype(offset, ab, rp->r_isdst, 3041 rp->r_todisstd, rp->r_todisut); 3042 if (defaulttype < 0 && !rp->r_isdst) 3043 defaulttype = type; 3044 if (rp->r_hiyear == ZIC_MAX 3045 && ! (0 <= lastatmax 3046 && ktime < attypes[lastatmax].at)) 3047 lastatmax = timecnt; 3048 addtt(ktime, type); 3049 prevrp = rp; 3050 prevktime = ktime; 3051 } 3052 } 3053 if (usestart) { 3054 if (*startbuf == '\0' && 3055 zp->z_format != NULL && 3056 strchr(zp->z_format, '%') == NULL && 3057 strchr(zp->z_format, '/') == NULL) 3058 strncpy(startbuf, zp->z_format, 3059 max_abbr_len + 1 - 1); 3060 eat(zp->z_filename, zp->z_linenum); 3061 if (*startbuf == '\0') 3062 error(_("can't determine time zone abbreviation to use just after until time")); 3063 else { 3064 bool isdst = startoff != zp->z_stdoff; 3065 type = addtype(startoff, startbuf, isdst, 3066 startttisstd, startttisut); 3067 if (defaulttype < 0 && !isdst) 3068 defaulttype = type; 3069 addtt(starttime, type); 3070 } 3071 } 3072 /* 3073 ** Now we may get to set starttime for the next zone line. 3074 */ 3075 if (useuntil) { 3076 startttisstd = zp->z_untilrule.r_todisstd; 3077 startttisut = zp->z_untilrule.r_todisut; 3078 starttime = zp->z_untiltime; 3079 if (!startttisstd) 3080 starttime = tadd(starttime, -save); 3081 if (!startttisut) 3082 starttime = tadd(starttime, -stdoff); 3083 } 3084 } 3085 if (defaulttype < 0) 3086 defaulttype = 0; 3087 if (0 <= lastatmax) 3088 attypes[lastatmax].dontmerge = true; 3089 if (do_extend) { 3090 /* 3091 ** If we're extending the explicitly listed observations 3092 ** for 400 years because we can't fill the POSIX-TZ field, 3093 ** check whether we actually ended up explicitly listing 3094 ** observations through that period. If there aren't any 3095 ** near the end of the 400-year period, add a redundant 3096 ** one at the end of the final year, to make it clear 3097 ** that we are claiming to have definite knowledge of 3098 ** the lack of transitions up to that point. 3099 */ 3100 struct rule xr; 3101 struct attype *lastat; 3102 memset(&xr, 0, sizeof(xr)); 3103 xr.r_month = TM_JANUARY; 3104 xr.r_dycode = DC_DOM; 3105 xr.r_dayofmonth = 1; 3106 xr.r_tod = 0; 3107 for (lastat = attypes, i = 1; i < timecnt; i++) 3108 if (attypes[i].at > lastat->at) 3109 lastat = &attypes[i]; 3110 if (!lastat || lastat->at < rpytime(&xr, max_year - 1)) { 3111 addtt(rpytime(&xr, max_year + 1), 3112 lastat ? lastat->type : defaulttype); 3113 attypes[timecnt - 1].dontmerge = true; 3114 } 3115 } 3116 writezone(zpfirst->z_name, envvar, version, defaulttype); 3117 free(startbuf); 3118 free(ab); 3119 free(envvar); 3120 } 3121 3122 static void 3123 addtt(zic_t starttime, int type) 3124 { 3125 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc); 3126 attypes[timecnt].at = starttime; 3127 attypes[timecnt].dontmerge = false; 3128 attypes[timecnt].type = type; 3129 ++timecnt; 3130 } 3131 3132 static int 3133 addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut) 3134 { 3135 int i, j; 3136 3137 if (! (-1L - 2147483647L <= utoff && utoff <= 2147483647L)) { 3138 error(_("UT offset out of range")); 3139 exit(EXIT_FAILURE); 3140 } 3141 if (!want_bloat()) 3142 ttisstd = ttisut = false; 3143 3144 for (j = 0; j < charcnt; ++j) 3145 if (strcmp(&chars[j], abbr) == 0) 3146 break; 3147 if (j == charcnt) 3148 newabbr(abbr); 3149 else { 3150 /* If there's already an entry, return its index. */ 3151 for (i = 0; i < typecnt; i++) 3152 if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i] 3153 && ttisstd == ttisstds[i] && ttisut == ttisuts[i]) 3154 return i; 3155 } 3156 /* 3157 ** There isn't one; add a new one, unless there are already too 3158 ** many. 3159 */ 3160 if (typecnt >= TZ_MAX_TYPES) { 3161 error(_("too many local time types")); 3162 exit(EXIT_FAILURE); 3163 } 3164 i = typecnt++; 3165 utoffs[i] = utoff; 3166 isdsts[i] = isdst; 3167 ttisstds[i] = ttisstd; 3168 ttisuts[i] = ttisut; 3169 desigidx[i] = j; 3170 return i; 3171 } 3172 3173 static void 3174 leapadd(zic_t t, int correction, int rolling) 3175 { 3176 int i; 3177 3178 if (TZ_MAX_LEAPS <= leapcnt) { 3179 error(_("too many leap seconds")); 3180 exit(EXIT_FAILURE); 3181 } 3182 if (rolling && (lo_time != min_time || hi_time != max_time)) { 3183 error(_("Rolling leap seconds not supported with -r")); 3184 exit(EXIT_FAILURE); 3185 } 3186 for (i = 0; i < leapcnt; ++i) 3187 if (t <= trans[i]) 3188 break; 3189 memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans); 3190 memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr); 3191 memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll); 3192 trans[i] = t; 3193 corr[i] = correction; 3194 roll[i] = rolling; 3195 ++leapcnt; 3196 } 3197 3198 static void 3199 adjleap(void) 3200 { 3201 int i; 3202 zic_t last = 0; 3203 zic_t prevtrans = 0; 3204 3205 /* 3206 ** propagate leap seconds forward 3207 */ 3208 for (i = 0; i < leapcnt; ++i) { 3209 if (trans[i] - prevtrans < 28 * SECSPERDAY) { 3210 error(_("Leap seconds too close together")); 3211 exit(EXIT_FAILURE); 3212 } 3213 prevtrans = trans[i]; 3214 trans[i] = tadd(trans[i], last); 3215 last = corr[i] += last; 3216 } 3217 3218 if (0 <= leapexpires) { 3219 leapexpires = oadd(leapexpires, last); 3220 if (! (leapcnt == 0 || (trans[leapcnt - 1] < leapexpires))) { 3221 error(_("last Leap time does not precede Expires time")); 3222 exit(EXIT_FAILURE); 3223 } 3224 } 3225 } 3226 3227 /* Is A a space character in the C locale? */ 3228 static bool 3229 is_space(char a) 3230 { 3231 switch (a) { 3232 default: 3233 return false; 3234 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': 3235 return true; 3236 } 3237 } 3238 3239 /* Is A an alphabetic character in the C locale? */ 3240 static bool 3241 is_alpha(char a) 3242 { 3243 switch (a) { 3244 default: 3245 return false; 3246 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 3247 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': 3248 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': 3249 case 'V': case 'W': case 'X': case 'Y': case 'Z': 3250 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': 3251 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': 3252 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': 3253 case 'v': case 'w': case 'x': case 'y': case 'z': 3254 return true; 3255 } 3256 } 3257 3258 /* If A is an uppercase character in the C locale, return its lowercase 3259 counterpart. Otherwise, return A. */ 3260 static char 3261 lowerit(char a) 3262 { 3263 switch (a) { 3264 default: return a; 3265 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c'; 3266 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f'; 3267 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i'; 3268 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l'; 3269 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o'; 3270 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r'; 3271 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u'; 3272 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x'; 3273 case 'Y': return 'y'; case 'Z': return 'z'; 3274 } 3275 } 3276 3277 /* case-insensitive equality */ 3278 static ATTRIBUTE_PURE bool 3279 ciequal(const char *ap, const char *bp) 3280 { 3281 while (lowerit(*ap) == lowerit(*bp++)) 3282 if (*ap++ == '\0') 3283 return true; 3284 return false; 3285 } 3286 3287 static ATTRIBUTE_PURE bool 3288 itsabbr(const char *abbr, const char *word) 3289 { 3290 if (lowerit(*abbr) != lowerit(*word)) 3291 return false; 3292 ++word; 3293 while (*++abbr != '\0') 3294 do { 3295 if (*word == '\0') 3296 return false; 3297 } while (lowerit(*word++) != lowerit(*abbr)); 3298 return true; 3299 } 3300 3301 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ 3302 3303 static ATTRIBUTE_PURE bool 3304 ciprefix(char const *abbr, char const *word) 3305 { 3306 do 3307 if (!*abbr) 3308 return true; 3309 while (lowerit(*abbr++) == lowerit(*word++)); 3310 3311 return false; 3312 } 3313 3314 static const struct lookup * 3315 byword(const char *word, const struct lookup *table) 3316 { 3317 const struct lookup * foundlp; 3318 const struct lookup * lp; 3319 3320 if (word == NULL || table == NULL) 3321 return NULL; 3322 3323 /* If TABLE is LASTS and the word starts with "last" followed 3324 by a non-'-', skip the "last" and look in WDAY_NAMES instead. 3325 Warn about any usage of the undocumented prefix "last-". */ 3326 if (table == lasts && ciprefix("last", word) && word[4]) { 3327 if (word[4] == '-') 3328 warning(_("\"%s\" is undocumented; use \"last%s\" instead"), 3329 word, word + 5); 3330 else { 3331 word += 4; 3332 table = wday_names; 3333 } 3334 } 3335 3336 /* 3337 ** Look for exact match. 3338 */ 3339 for (lp = table; lp->l_word != NULL; ++lp) 3340 if (ciequal(word, lp->l_word)) 3341 return lp; 3342 /* 3343 ** Look for inexact match. 3344 */ 3345 foundlp = NULL; 3346 for (lp = table; lp->l_word != NULL; ++lp) 3347 if (ciprefix(word, lp->l_word)) { 3348 if (foundlp == NULL) 3349 foundlp = lp; 3350 else return NULL; /* multiple inexact matches */ 3351 } 3352 3353 if (foundlp && noise) { 3354 /* Warn about any backward-compatibility issue with pre-2017c zic. */ 3355 bool pre_2017c_match = false; 3356 for (lp = table; lp->l_word; lp++) 3357 if (itsabbr(word, lp->l_word)) { 3358 if (pre_2017c_match) { 3359 warning(_("\"%s\" is ambiguous in pre-2017c zic"), word); 3360 break; 3361 } 3362 pre_2017c_match = true; 3363 } 3364 } 3365 3366 return foundlp; 3367 } 3368 3369 static char ** 3370 getfields(char *cp) 3371 { 3372 char * dp; 3373 char ** array; 3374 int nsubs; 3375 3376 if (cp == NULL) 3377 return NULL; 3378 array = zic_malloc(size_product(strlen(cp) + 1, sizeof *array)); 3379 nsubs = 0; 3380 for ( ; ; ) { 3381 while (is_space(*cp)) 3382 ++cp; 3383 if (*cp == '\0' || *cp == '#') 3384 break; 3385 array[nsubs++] = dp = cp; 3386 do { 3387 if ((*dp = *cp++) != '"') 3388 ++dp; 3389 else while ((*dp = *cp++) != '"') 3390 if (*dp != '\0') 3391 ++dp; 3392 else { 3393 error(_("Odd number of quotation marks")); 3394 exit(EXIT_FAILURE); 3395 } 3396 } while (*cp && *cp != '#' && !is_space(*cp)); 3397 if (is_space(*cp)) 3398 ++cp; 3399 *dp = '\0'; 3400 } 3401 array[nsubs] = NULL; 3402 return array; 3403 } 3404 3405 static _Noreturn void 3406 time_overflow(void) 3407 { 3408 error(_("time overflow")); 3409 exit(EXIT_FAILURE); 3410 } 3411 3412 static ATTRIBUTE_PURE zic_t 3413 oadd(zic_t t1, zic_t t2) 3414 { 3415 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) 3416 time_overflow(); 3417 return t1 + t2; 3418 } 3419 3420 static ATTRIBUTE_PURE zic_t 3421 tadd(zic_t t1, zic_t t2) 3422 { 3423 if (t1 < 0) { 3424 if (t2 < min_time - t1) { 3425 if (t1 != min_time) 3426 time_overflow(); 3427 return min_time; 3428 } 3429 } else { 3430 if (max_time - t1 < t2) { 3431 if (t1 != max_time) 3432 time_overflow(); 3433 return max_time; 3434 } 3435 } 3436 return t1 + t2; 3437 } 3438 3439 /* 3440 ** Given a rule, and a year, compute the date (in seconds since January 1, 3441 ** 1970, 00:00 LOCAL time) in that year that the rule refers to. 3442 */ 3443 3444 static zic_t 3445 rpytime(const struct rule *rp, zic_t wantedy) 3446 { 3447 int m, i; 3448 zic_t dayoff; /* with a nod to Margaret O. */ 3449 zic_t t, y; 3450 int yrem; 3451 3452 if (wantedy == ZIC_MIN) 3453 return min_time; 3454 if (wantedy == ZIC_MAX) 3455 return max_time; 3456 m = TM_JANUARY; 3457 y = EPOCH_YEAR; 3458 3459 /* dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT, 3460 sans overflow. */ 3461 yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT; 3462 dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT 3463 + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0)) 3464 * DAYSPERREPEAT); 3465 /* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow. */ 3466 wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT; 3467 3468 while (wantedy != y) { 3469 i = len_years[isleap(y)]; 3470 dayoff = oadd(dayoff, i); 3471 y++; 3472 } 3473 while (m != rp->r_month) { 3474 i = len_months[isleap(y)][m]; 3475 dayoff = oadd(dayoff, i); 3476 ++m; 3477 } 3478 i = rp->r_dayofmonth; 3479 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 3480 if (rp->r_dycode == DC_DOWLEQ) 3481 --i; 3482 else { 3483 error(_("use of 2/29 in non leap-year")); 3484 exit(EXIT_FAILURE); 3485 } 3486 } 3487 --i; 3488 dayoff = oadd(dayoff, i); 3489 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 3490 /* 3491 ** Don't trust mod of negative numbers. 3492 */ 3493 zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK) 3494 % DAYSPERWEEK); 3495 while (wday != rp->r_wday) 3496 if (rp->r_dycode == DC_DOWGEQ) { 3497 dayoff = oadd(dayoff, (zic_t) 1); 3498 if (++wday >= DAYSPERWEEK) 3499 wday = 0; 3500 ++i; 3501 } else { 3502 dayoff = oadd(dayoff, (zic_t) -1); 3503 if (--wday < 0) 3504 wday = DAYSPERWEEK - 1; 3505 --i; 3506 } 3507 if (i < 0 || i >= len_months[isleap(y)][m]) { 3508 if (noise) 3509 warning(_("rule goes past start/end of month; \ 3510 will not work with pre-2004 versions of zic")); 3511 } 3512 } 3513 if (dayoff < min_time / SECSPERDAY) 3514 return min_time; 3515 if (dayoff > max_time / SECSPERDAY) 3516 return max_time; 3517 t = (zic_t) dayoff * SECSPERDAY; 3518 return tadd(t, rp->r_tod); 3519 } 3520 3521 static void 3522 newabbr(const char *string) 3523 { 3524 int i; 3525 3526 if (strcmp(string, GRANDPARENTED) != 0) { 3527 const char * cp; 3528 const char * mp; 3529 3530 cp = string; 3531 mp = NULL; 3532 while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9') 3533 || *cp == '-' || *cp == '+') 3534 ++cp; 3535 if (noise && cp - string < 3) 3536 mp = _("time zone abbreviation has fewer than 3 characters"); 3537 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 3538 mp = _("time zone abbreviation has too many characters"); 3539 if (*cp != '\0') 3540 mp = _("time zone abbreviation differs from POSIX standard"); 3541 if (mp != NULL) 3542 warning("%s (%s)", mp, string); 3543 } 3544 i = strlen(string) + 1; 3545 if (charcnt + i > TZ_MAX_CHARS) { 3546 error(_("too many, or too long, time zone abbreviations")); 3547 exit(EXIT_FAILURE); 3548 } 3549 strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1); 3550 charcnt += i; 3551 } 3552 3553 /* Ensure that the directories of ARGNAME exist, by making any missing 3554 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise, 3555 do it for ARGNAME too. Exit with failure if there is trouble. 3556 Do not consider an existing file to be trouble. */ 3557 static void 3558 mkdirs(char const *argname, bool ancestors) 3559 { 3560 char * name; 3561 char * cp; 3562 3563 cp = name = ecpyalloc(argname); 3564 3565 /* On MS-Windows systems, do not worry about drive letters or 3566 backslashes, as this should suffice in practice. Time zone 3567 names do not use drive letters and backslashes. If the -d 3568 option of zic does not name an already-existing directory, 3569 it can use slashes to separate the already-existing 3570 ancestor prefix from the to-be-created subdirectories. */ 3571 3572 /* Do not mkdir a root directory, as it must exist. */ 3573 while (*cp == '/') 3574 cp++; 3575 3576 while (cp && ((cp = strchr(cp, '/')) || !ancestors)) { 3577 if (cp) 3578 *cp = '\0'; 3579 /* 3580 ** Try to create it. It's OK if creation fails because 3581 ** the directory already exists, perhaps because some 3582 ** other process just created it. For simplicity do 3583 ** not check first whether it already exists, as that 3584 ** is checked anyway if the mkdir fails. 3585 */ 3586 if (mkdir(name, MKDIR_UMASK) != 0) { 3587 /* Do not report an error if err == EEXIST, because 3588 some other process might have made the directory 3589 in the meantime. Likewise for ENOSYS, because 3590 Solaris 10 mkdir fails with ENOSYS if the 3591 directory is an automounted mount point. */ 3592 int err = errno; 3593 if (err != EEXIST && err != ENOSYS) { 3594 error(_("%s: Can't create directory %s: %s"), 3595 progname, name, strerror(err)); 3596 exit(EXIT_FAILURE); 3597 } 3598 } 3599 if (cp) 3600 *cp++ = '/'; 3601 } 3602 free(name); 3603 } 3604