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