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