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