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