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