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