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