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