zic.c revision 17214
1#ifndef lint 2#ifndef NOID 3static char elsieid[] = "@(#)zic.c 7.77"; 4#endif /* !defined NOID */ 5#endif /* !defined lint */ 6 7#include "private.h" 8#include "locale.h" 9#include "tzfile.h" 10#include <sys/stat.h> /* for umask manifest constants */ 11#include <sys/types.h> 12#include <unistd.h> 13 14/* 15** On some ancient hosts, predicates like `isspace(C)' are defined 16** only if isascii(C) || C == EOF. Modern hosts obey the C Standard, 17** which says they are defined only if C == ((unsigned char) C) || C == EOF. 18** Neither the C Standard nor Posix require that `isascii' exist. 19** For portability, we check both ancient and modern requirements. 20** If isascii is not defined, the isascii check succeeds trivially. 21*/ 22#include "ctype.h" 23#ifndef isascii 24#define isascii(x) 1 25#endif 26 27struct rule { 28 const char * r_filename; 29 int r_linenum; 30 const char * r_name; 31 32 int r_loyear; /* for example, 1986 */ 33 int r_hiyear; /* for example, 1986 */ 34 const char * r_yrtype; 35 36 int r_month; /* 0..11 */ 37 38 int r_dycode; /* see below */ 39 int r_dayofmonth; 40 int r_wday; 41 42 long r_tod; /* time from midnight */ 43 int r_todisstd; /* above is standard time if TRUE */ 44 /* or wall clock time if FALSE */ 45 int r_todisgmt; /* above is GMT if TRUE */ 46 /* or local time if FALSE */ 47 long r_stdoff; /* offset from standard time */ 48 const char * r_abbrvar; /* variable part of abbreviation */ 49 50 int r_todo; /* a rule to do (used in outzone) */ 51 time_t r_temp; /* used in outzone */ 52}; 53 54/* 55** r_dycode r_dayofmonth r_wday 56*/ 57 58#define DC_DOM 0 /* 1..31 */ /* unused */ 59#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 60#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 61 62struct zone { 63 const char * z_filename; 64 int z_linenum; 65 66 const char * z_name; 67 long z_gmtoff; 68 const char * z_rule; 69 const char * z_format; 70 71 long z_stdoff; 72 73 struct rule * z_rules; 74 int z_nrules; 75 76 struct rule z_untilrule; 77 time_t z_untiltime; 78}; 79 80extern int getopt P((int argc, char * const argv[], 81 const char * options)); 82extern char * icatalloc P((char * old, const char * new)); 83extern char * icpyalloc P((const char * string)); 84extern void ifree P((char * p)); 85extern char * imalloc P((int n)); 86extern void * irealloc P((void * old, int n)); 87extern int link P((const char * fromname, const char * toname)); 88extern char * optarg; 89extern int optind; 90extern char * scheck P((const char * string, const char * format)); 91 92static void addtt P((time_t starttime, int type)); 93static int addtype P((long gmtoff, const char * abbr, int isdst, 94 int ttisstd, int ttisgmt)); 95static void leapadd P((time_t t, int positive, int rolling, int count)); 96static void adjleap P((void)); 97static void associate P((void)); 98static int ciequal P((const char * ap, const char * bp)); 99static void convert P((long val, char * buf)); 100static void dolink P((const char * fromfile, const char * tofile)); 101static void doabbr P((char * abbr, const char * format, 102 const char * letters, int isdst)); 103static void eat P((const char * name, int num)); 104static void eats P((const char * name, int num, 105 const char * rname, int rnum)); 106static long eitol P((int i)); 107static void error P((const char * message)); 108static char ** getfields P((char * buf)); 109static long gethms P((const char * string, const char * errstrng, 110 int signable)); 111static void infile P((const char * filename)); 112static void inleap P((char ** fields, int nfields)); 113static void inlink P((char ** fields, int nfields)); 114static void inrule P((char ** fields, int nfields)); 115static int inzcont P((char ** fields, int nfields)); 116static int inzone P((char ** fields, int nfields)); 117static int inzsub P((char ** fields, int nfields, int iscont)); 118static int itsabbr P((const char * abbr, const char * word)); 119static int itsdir P((const char * name)); 120static int lowerit P((int c)); 121static char * memcheck P((char * tocheck)); 122static int mkdirs P((char * filename)); 123static void newabbr P((const char * abbr)); 124static long oadd P((long t1, long t2)); 125static void outzone P((const struct zone * zp, int ntzones)); 126static void puttzcode P((long code, FILE * fp)); 127static int rcomp P((const void * leftp, const void * rightp)); 128static time_t rpytime P((const struct rule * rp, int wantedy)); 129static void rulesub P((struct rule * rp, 130 const char * loyearp, const char * hiyearp, 131 const char * typep, const char * monthp, 132 const char * dayp, const char * timep)); 133static void setboundaries P((void)); 134static time_t tadd P((time_t t1, long t2)); 135static void usage P((void)); 136static void writezone P((const char * name)); 137static int yearistype P((int year, const char * type)); 138 139#if !HAVE_STRERROR 140static char * strerror P((int)); 141#endif /* !HAVE_STRERROR */ 142 143static int charcnt; 144static int errors; 145static const char * filename; 146static int leapcnt; 147static int linenum; 148static time_t max_time; 149static int max_year; 150static time_t min_time; 151static int min_year; 152static int noise; 153static const char * rfilename; 154static int rlinenum; 155static const char * progname; 156static int timecnt; 157static int typecnt; 158 159/* 160** Line codes. 161*/ 162 163#define LC_RULE 0 164#define LC_ZONE 1 165#define LC_LINK 2 166#define LC_LEAP 3 167 168/* 169** Which fields are which on a Zone line. 170*/ 171 172#define ZF_NAME 1 173#define ZF_GMTOFF 2 174#define ZF_RULE 3 175#define ZF_FORMAT 4 176#define ZF_TILYEAR 5 177#define ZF_TILMONTH 6 178#define ZF_TILDAY 7 179#define ZF_TILTIME 8 180#define ZONE_MINFIELDS 5 181#define ZONE_MAXFIELDS 9 182 183/* 184** Which fields are which on a Zone continuation line. 185*/ 186 187#define ZFC_GMTOFF 0 188#define ZFC_RULE 1 189#define ZFC_FORMAT 2 190#define ZFC_TILYEAR 3 191#define ZFC_TILMONTH 4 192#define ZFC_TILDAY 5 193#define ZFC_TILTIME 6 194#define ZONEC_MINFIELDS 3 195#define ZONEC_MAXFIELDS 7 196 197/* 198** Which files are which on a Rule line. 199*/ 200 201#define RF_NAME 1 202#define RF_LOYEAR 2 203#define RF_HIYEAR 3 204#define RF_COMMAND 4 205#define RF_MONTH 5 206#define RF_DAY 6 207#define RF_TOD 7 208#define RF_STDOFF 8 209#define RF_ABBRVAR 9 210#define RULE_FIELDS 10 211 212/* 213** Which fields are which on a Link line. 214*/ 215 216#define LF_FROM 1 217#define LF_TO 2 218#define LINK_FIELDS 3 219 220/* 221** Which fields are which on a Leap line. 222*/ 223 224#define LP_YEAR 1 225#define LP_MONTH 2 226#define LP_DAY 3 227#define LP_TIME 4 228#define LP_CORR 5 229#define LP_ROLL 6 230#define LEAP_FIELDS 7 231 232/* 233** Year synonyms. 234*/ 235 236#define YR_MINIMUM 0 237#define YR_MAXIMUM 1 238#define YR_ONLY 2 239 240static struct rule * rules; 241static int nrules; /* number of rules */ 242 243static struct zone * zones; 244static int nzones; /* number of zones */ 245 246struct link { 247 const char * l_filename; 248 int l_linenum; 249 const char * l_from; 250 const char * l_to; 251}; 252 253static struct link * links; 254static int nlinks; 255 256struct lookup { 257 const char * l_word; 258 const int l_value; 259}; 260 261static struct lookup const * byword P((const char * string, 262 const struct lookup * lp)); 263 264static struct lookup const line_codes[] = { 265 { "Rule", LC_RULE }, 266 { "Zone", LC_ZONE }, 267 { "Link", LC_LINK }, 268 { "Leap", LC_LEAP }, 269 { NULL, 0} 270}; 271 272static struct lookup const mon_names[] = { 273 { "January", TM_JANUARY }, 274 { "February", TM_FEBRUARY }, 275 { "March", TM_MARCH }, 276 { "April", TM_APRIL }, 277 { "May", TM_MAY }, 278 { "June", TM_JUNE }, 279 { "July", TM_JULY }, 280 { "August", TM_AUGUST }, 281 { "September", TM_SEPTEMBER }, 282 { "October", TM_OCTOBER }, 283 { "November", TM_NOVEMBER }, 284 { "December", TM_DECEMBER }, 285 { NULL, 0 } 286}; 287 288static struct lookup const wday_names[] = { 289 { "Sunday", TM_SUNDAY }, 290 { "Monday", TM_MONDAY }, 291 { "Tuesday", TM_TUESDAY }, 292 { "Wednesday", TM_WEDNESDAY }, 293 { "Thursday", TM_THURSDAY }, 294 { "Friday", TM_FRIDAY }, 295 { "Saturday", TM_SATURDAY }, 296 { NULL, 0 } 297}; 298 299static struct lookup const lasts[] = { 300 { "last-Sunday", TM_SUNDAY }, 301 { "last-Monday", TM_MONDAY }, 302 { "last-Tuesday", TM_TUESDAY }, 303 { "last-Wednesday", TM_WEDNESDAY }, 304 { "last-Thursday", TM_THURSDAY }, 305 { "last-Friday", TM_FRIDAY }, 306 { "last-Saturday", TM_SATURDAY }, 307 { NULL, 0 } 308}; 309 310static struct lookup const begin_years[] = { 311 { "minimum", YR_MINIMUM }, 312 { "maximum", YR_MAXIMUM }, 313 { NULL, 0 } 314}; 315 316static struct lookup const end_years[] = { 317 { "minimum", YR_MINIMUM }, 318 { "maximum", YR_MAXIMUM }, 319 { "only", YR_ONLY }, 320 { NULL, 0 } 321}; 322 323static struct lookup const leap_types[] = { 324 { "Rolling", TRUE }, 325 { "Stationary", FALSE }, 326 { NULL, 0 } 327}; 328 329static const int len_months[2][MONSPERYEAR] = { 330 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 331 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 332}; 333 334static const int len_years[2] = { 335 DAYSPERNYEAR, DAYSPERLYEAR 336}; 337 338static struct attype { 339 time_t at; 340 unsigned char type; 341} attypes[TZ_MAX_TIMES]; 342static long gmtoffs[TZ_MAX_TYPES]; 343static char isdsts[TZ_MAX_TYPES]; 344static unsigned char abbrinds[TZ_MAX_TYPES]; 345static char ttisstds[TZ_MAX_TYPES]; 346static char ttisgmts[TZ_MAX_TYPES]; 347static char chars[TZ_MAX_CHARS]; 348static time_t trans[TZ_MAX_LEAPS]; 349static long corr[TZ_MAX_LEAPS]; 350static char roll[TZ_MAX_LEAPS]; 351 352/* 353** Memory allocation. 354*/ 355 356static char * 357memcheck(ptr) 358char * const ptr; 359{ 360 if (ptr == NULL) { 361 const char *e = strerror(errno); 362 (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"), 363 progname, e); 364 (void) exit(EXIT_FAILURE); 365 } 366 return ptr; 367} 368 369#define emalloc(size) memcheck(imalloc(size)) 370#define erealloc(ptr, size) memcheck(irealloc((ptr), (size))) 371#define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 372#define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) 373 374/* 375** Error handling. 376*/ 377 378#if ! HAVE_STRERROR 379static char * 380strerror(errnum) 381int errnum; 382{ 383 extern char *sys_errlist[]; 384 extern int sys_nerr; 385 386 if (errnum > 0 && errnum <= sys_nerr) 387 return sys_errlist[errnum]; 388 return "Unknown system error"; 389} 390#endif /* ! HAVE_STRERROR */ 391 392static void 393eats(name, num, rname, rnum) 394const char * const name; 395const int num; 396const char * const rname; 397const int rnum; 398{ 399 filename = name; 400 linenum = num; 401 rfilename = rname; 402 rlinenum = rnum; 403} 404 405static void 406eat(name, num) 407const char * const name; 408const int num; 409{ 410 eats(name, num, (char *) NULL, -1); 411} 412 413static void 414error(string) 415const char * const string; 416{ 417 /* 418 ** Match the format of "cc" to allow sh users to 419 ** zic ... 2>&1 | error -t "*" -v 420 ** on BSD systems. 421 */ 422 (void) fprintf(stderr, _("\"%s\", line %d: %s"), 423 filename, linenum, string); 424 if (rfilename != NULL) 425 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"), 426 rfilename, rlinenum); 427 (void) fprintf(stderr, "\n"); 428 ++errors; 429} 430 431static void 432warning(string) 433const char * const string; 434{ 435 char * cp; 436 437 cp = ecpyalloc("warning: "); 438 cp = ecatalloc(cp, string); 439 error(string); 440 ifree(cp); 441 --errors; 442} 443 444static void 445usage P((void)) 446{ 447 (void) fprintf(stderr, _("%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"), 448 progname, progname); 449 (void) exit(EXIT_FAILURE); 450} 451 452static const char * psxrules; 453static const char * lcltime; 454static const char * directory; 455static const char * leapsec; 456static const char * yitcommand; 457static int sflag = FALSE; 458 459int 460main(argc, argv) 461int argc; 462char * argv[]; 463{ 464 register int i; 465 register int j; 466 register int c; 467 468#ifdef unix 469 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 470#endif /* defined unix */ 471#if HAVE_GETTEXT - 0 472 (void) setlocale(LC_MESSAGES, ""); 473#ifdef TZ_DOMAINDIR 474 (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 475#endif /* defined TEXTDOMAINDIR */ 476 (void) textdomain(TZ_DOMAIN); 477#endif /* HAVE_GETTEXT - 0 */ 478 progname = argv[0]; 479 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF) 480 switch (c) { 481 default: 482 usage(); 483 case 'd': 484 if (directory == NULL) 485 directory = optarg; 486 else { 487 (void) fprintf(stderr, 488_("%s: More than one -d option specified\n"), 489 progname); 490 (void) exit(EXIT_FAILURE); 491 } 492 break; 493 case 'l': 494 if (lcltime == NULL) 495 lcltime = optarg; 496 else { 497 (void) fprintf(stderr, 498_("%s: More than one -l option specified\n"), 499 progname); 500 (void) exit(EXIT_FAILURE); 501 } 502 break; 503 case 'p': 504 if (psxrules == NULL) 505 psxrules = optarg; 506 else { 507 (void) fprintf(stderr, 508_("%s: More than one -p option specified\n"), 509 progname); 510 (void) exit(EXIT_FAILURE); 511 } 512 break; 513 case 'y': 514 if (yitcommand == NULL) 515 yitcommand = optarg; 516 else { 517 (void) fprintf(stderr, 518_("%s: More than one -y option specified\n"), 519 progname); 520 (void) exit(EXIT_FAILURE); 521 } 522 break; 523 case 'L': 524 if (leapsec == NULL) 525 leapsec = optarg; 526 else { 527 (void) fprintf(stderr, 528_("%s: More than one -L option specified\n"), 529 progname); 530 (void) exit(EXIT_FAILURE); 531 } 532 break; 533 case 'v': 534 noise = TRUE; 535 break; 536 case 's': 537 sflag = TRUE; 538 break; 539 } 540 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 541 usage(); /* usage message by request */ 542 if (directory == NULL) 543 directory = TZDIR; 544 if (yitcommand == NULL) 545 yitcommand = "yearistype"; 546 547 setboundaries(); 548 549 if (optind < argc && leapsec != NULL) { 550 infile(leapsec); 551 adjleap(); 552 } 553 554 for (i = optind; i < argc; ++i) 555 infile(argv[i]); 556 if (errors) 557 (void) exit(EXIT_FAILURE); 558 associate(); 559 for (i = 0; i < nzones; i = j) { 560 /* 561 ** Find the next non-continuation zone entry. 562 */ 563 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 564 continue; 565 outzone(&zones[i], j - i); 566 } 567 /* 568 ** Make links. 569 */ 570 for (i = 0; i < nlinks; ++i) 571 dolink(links[i].l_from, links[i].l_to); 572 if (lcltime != NULL) 573 dolink(lcltime, TZDEFAULT); 574 if (psxrules != NULL) 575 dolink(psxrules, TZDEFRULES); 576 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 577} 578 579static void 580dolink(fromfile, tofile) 581const char * const fromfile; 582const char * const tofile; 583{ 584 register char * fromname; 585 register char * toname; 586 587 if (fromfile[0] == '/') 588 fromname = ecpyalloc(fromfile); 589 else { 590 fromname = ecpyalloc(directory); 591 fromname = ecatalloc(fromname, "/"); 592 fromname = ecatalloc(fromname, fromfile); 593 } 594 if (tofile[0] == '/') 595 toname = ecpyalloc(tofile); 596 else { 597 toname = ecpyalloc(directory); 598 toname = ecatalloc(toname, "/"); 599 toname = ecatalloc(toname, tofile); 600 } 601 /* 602 ** We get to be careful here since 603 ** there's a fair chance of root running us. 604 */ 605 if (!itsdir(toname)) 606 (void) remove(toname); 607 if (link(fromname, toname) != 0) { 608 if (mkdirs(toname) != 0) 609 (void) exit(EXIT_FAILURE); 610 if (link(fromname, toname) != 0) { 611 const char *e = strerror(errno); 612 (void) fprintf(stderr, 613 _("%s: Can't link from %s to %s: %s\n"), 614 progname, fromname, toname, e); 615 (void) exit(EXIT_FAILURE); 616 } 617 } 618 ifree(fromname); 619 ifree(toname); 620} 621 622#ifndef INT_MAX 623#define INT_MAX ((int) (((unsigned)~0)>>1)) 624#endif /* !defined INT_MAX */ 625 626#ifndef INT_MIN 627#define INT_MIN ((int) ~(((unsigned)~0)>>1)) 628#endif /* !defined INT_MIN */ 629 630/* 631** The tz file format currently allows at most 32-bit quantities. 632** This restriction should be removed before signed 32-bit values 633** wrap around in 2038, but unfortunately this will require a 634** change to the tz file format. 635*/ 636 637#define MAX_BITS_IN_FILE 32 638#define TIME_T_BITS_IN_FILE ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE) 639 640static void 641setboundaries P((void)) 642{ 643 if (TYPE_SIGNED(time_t)) { 644 min_time = ~ (time_t) 0; 645 min_time <<= TIME_T_BITS_IN_FILE - 1; 646 max_time = ~ (time_t) 0 - min_time; 647 if (sflag) 648 min_time = 0; 649 } else { 650 min_time = 0; 651 max_time = 2 - sflag; 652 max_time <<= TIME_T_BITS_IN_FILE - 1; 653 --max_time; 654 } 655 min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; 656 max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; 657} 658 659static int 660itsdir(name) 661const char * const name; 662{ 663 register char * myname; 664 register int accres; 665 666 myname = ecpyalloc(name); 667 myname = ecatalloc(myname, "/."); 668 accres = access(myname, F_OK); 669 ifree(myname); 670 return accres == 0; 671} 672 673/* 674** Associate sets of rules with zones. 675*/ 676 677/* 678** Sort by rule name. 679*/ 680 681static int 682rcomp(cp1, cp2) 683const void * cp1; 684const void * cp2; 685{ 686 return strcmp(((const struct rule *) cp1)->r_name, 687 ((const struct rule *) cp2)->r_name); 688} 689 690static void 691associate P((void)) 692{ 693 register struct zone * zp; 694 register struct rule * rp; 695 register int base, out; 696 register int i, j; 697 698 if (nrules != 0) { 699 (void) qsort((void *) rules, (size_t) nrules, 700 (size_t) sizeof *rules, rcomp); 701 for (i = 0; i < nrules - 1; ++i) { 702 if (strcmp(rules[i].r_name, 703 rules[i + 1].r_name) != 0) 704 continue; 705 if (strcmp(rules[i].r_filename, 706 rules[i + 1].r_filename) == 0) 707 continue; 708 eat(rules[i].r_filename, rules[i].r_linenum); 709 warning(_("same rule name in multiple files")); 710 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 711 warning(_("same rule name in multiple files")); 712 for (j = i + 2; j < nrules; ++j) { 713 if (strcmp(rules[i].r_name, 714 rules[j].r_name) != 0) 715 break; 716 if (strcmp(rules[i].r_filename, 717 rules[j].r_filename) == 0) 718 continue; 719 if (strcmp(rules[i + 1].r_filename, 720 rules[j].r_filename) == 0) 721 continue; 722 break; 723 } 724 i = j - 1; 725 } 726 } 727 for (i = 0; i < nzones; ++i) { 728 zp = &zones[i]; 729 zp->z_rules = NULL; 730 zp->z_nrules = 0; 731 } 732 for (base = 0; base < nrules; base = out) { 733 rp = &rules[base]; 734 for (out = base + 1; out < nrules; ++out) 735 if (strcmp(rp->r_name, rules[out].r_name) != 0) 736 break; 737 for (i = 0; i < nzones; ++i) { 738 zp = &zones[i]; 739 if (strcmp(zp->z_rule, rp->r_name) != 0) 740 continue; 741 zp->z_rules = rp; 742 zp->z_nrules = out - base; 743 } 744 } 745 for (i = 0; i < nzones; ++i) { 746 zp = &zones[i]; 747 if (zp->z_nrules == 0) { 748 /* 749 ** Maybe we have a local standard time offset. 750 */ 751 eat(zp->z_filename, zp->z_linenum); 752 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"), 753 TRUE); 754 /* 755 ** Note, though, that if there's no rule, 756 ** a '%s' in the format is a bad thing. 757 */ 758 if (strchr(zp->z_format, '%') != 0) 759 error(_("%s in ruleless zone")); 760 } 761 } 762 if (errors) 763 (void) exit(EXIT_FAILURE); 764} 765 766static void 767infile(name) 768const char * name; 769{ 770 register FILE * fp; 771 register char ** fields; 772 register char * cp; 773 register const struct lookup * lp; 774 register int nfields; 775 register int wantcont; 776 register int num; 777 char buf[BUFSIZ]; 778 779 if (strcmp(name, "-") == 0) { 780 name = _("standard input"); 781 fp = stdin; 782 } else if ((fp = fopen(name, "r")) == NULL) { 783 const char *e = strerror(errno); 784 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"), 785 progname, name, e); 786 (void) exit(EXIT_FAILURE); 787 } 788 wantcont = FALSE; 789 for (num = 1; ; ++num) { 790 eat(name, num); 791 if (fgets(buf, (int) sizeof buf, fp) != buf) 792 break; 793 cp = strchr(buf, '\n'); 794 if (cp == NULL) { 795 error(_("line too long")); 796 (void) exit(EXIT_FAILURE); 797 } 798 *cp = '\0'; 799 fields = getfields(buf); 800 nfields = 0; 801 while (fields[nfields] != NULL) { 802 static char nada; 803 804 if (strcmp(fields[nfields], "-") == 0) 805 fields[nfields] = &nada; 806 ++nfields; 807 } 808 if (nfields == 0) { 809 /* nothing to do */ 810 } else if (wantcont) { 811 wantcont = inzcont(fields, nfields); 812 } else { 813 lp = byword(fields[0], line_codes); 814 if (lp == NULL) 815 error(_("input line of unknown type")); 816 else switch ((int) (lp->l_value)) { 817 case LC_RULE: 818 inrule(fields, nfields); 819 wantcont = FALSE; 820 break; 821 case LC_ZONE: 822 wantcont = inzone(fields, nfields); 823 break; 824 case LC_LINK: 825 inlink(fields, nfields); 826 wantcont = FALSE; 827 break; 828 case LC_LEAP: 829 if (name != leapsec) 830 (void) fprintf(stderr, 831_("%s: Leap line in non leap seconds file %s\n"), 832 progname, name); 833 else inleap(fields, nfields); 834 wantcont = FALSE; 835 break; 836 default: /* "cannot happen" */ 837 (void) fprintf(stderr, 838_("%s: panic: Invalid l_value %d\n"), 839 progname, lp->l_value); 840 (void) exit(EXIT_FAILURE); 841 } 842 } 843 ifree((char *) fields); 844 } 845 if (ferror(fp)) { 846 (void) fprintf(stderr, _("%s: Error reading %s\n"), 847 progname, filename); 848 (void) exit(EXIT_FAILURE); 849 } 850 if (fp != stdin && fclose(fp)) { 851 const char *e = strerror(errno); 852 (void) fprintf(stderr, _("%s: Error closing %s: %s\n"), 853 progname, filename, e); 854 (void) exit(EXIT_FAILURE); 855 } 856 if (wantcont) 857 error(_("expected continuation line not found")); 858} 859 860/* 861** Convert a string of one of the forms 862** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 863** into a number of seconds. 864** A null string maps to zero. 865** Call error with errstring and return zero on errors. 866*/ 867 868static long 869gethms(string, errstring, signable) 870const char * string; 871const char * const errstring; 872const int signable; 873{ 874 int hh, mm, ss, sign; 875 876 if (string == NULL || *string == '\0') 877 return 0; 878 if (!signable) 879 sign = 1; 880 else if (*string == '-') { 881 sign = -1; 882 ++string; 883 } else sign = 1; 884 if (sscanf(string, scheck(string, "%d"), &hh) == 1) 885 mm = ss = 0; 886 else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) 887 ss = 0; 888 else if (sscanf(string, scheck(string, "%d:%d:%d"), 889 &hh, &mm, &ss) != 3) { 890 error(errstring); 891 return 0; 892 } 893 if (hh < 0 || hh >= HOURSPERDAY || 894 mm < 0 || mm >= MINSPERHOUR || 895 ss < 0 || ss > SECSPERMIN) { 896 error(errstring); 897 return 0; 898 } 899 return eitol(sign) * 900 (eitol(hh * MINSPERHOUR + mm) * 901 eitol(SECSPERMIN) + eitol(ss)); 902} 903 904static void 905inrule(fields, nfields) 906register char ** const fields; 907const int nfields; 908{ 909 static struct rule r; 910 911 if (nfields != RULE_FIELDS) { 912 error(_("wrong number of fields on Rule line")); 913 return; 914 } 915 if (*fields[RF_NAME] == '\0') { 916 error(_("nameless rule")); 917 return; 918 } 919 r.r_filename = filename; 920 r.r_linenum = linenum; 921 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE); 922 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 923 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 924 r.r_name = ecpyalloc(fields[RF_NAME]); 925 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 926 rules = (struct rule *) (void *) erealloc((char *) rules, 927 (int) ((nrules + 1) * sizeof *rules)); 928 rules[nrules++] = r; 929} 930 931static int 932inzone(fields, nfields) 933register char ** const fields; 934const int nfields; 935{ 936 register int i; 937 static char * buf; 938 939 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 940 error(_("wrong number of fields on Zone line")); 941 return FALSE; 942 } 943 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 944 buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT))); 945 (void) sprintf(buf, 946_("\"Zone %s\" line and -l option are mutually exclusive"), 947 TZDEFAULT); 948 error(buf); 949 return FALSE; 950 } 951 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 952 buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES))); 953 (void) sprintf(buf, 954_("\"Zone %s\" line and -p option are mutually exclusive"), 955 TZDEFRULES); 956 error(buf); 957 return FALSE; 958 } 959 for (i = 0; i < nzones; ++i) 960 if (zones[i].z_name != NULL && 961 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 962 buf = erealloc(buf, (int) (132 + 963 strlen(fields[ZF_NAME]) + 964 strlen(zones[i].z_filename))); 965 (void) sprintf(buf, 966_("duplicate zone name %s (file \"%s\", line %d)"), 967 fields[ZF_NAME], 968 zones[i].z_filename, 969 zones[i].z_linenum); 970 error(buf); 971 return FALSE; 972 } 973 return inzsub(fields, nfields, FALSE); 974} 975 976static int 977inzcont(fields, nfields) 978register char ** const fields; 979const int nfields; 980{ 981 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 982 error(_("wrong number of fields on Zone continuation line")); 983 return FALSE; 984 } 985 return inzsub(fields, nfields, TRUE); 986} 987 988static int 989inzsub(fields, nfields, iscont) 990register char ** const fields; 991const int nfields; 992const int iscont; 993{ 994 register char * cp; 995 static struct zone z; 996 register int i_gmtoff, i_rule, i_format; 997 register int i_untilyear, i_untilmonth; 998 register int i_untilday, i_untiltime; 999 register int hasuntil; 1000 1001 if (iscont) { 1002 i_gmtoff = ZFC_GMTOFF; 1003 i_rule = ZFC_RULE; 1004 i_format = ZFC_FORMAT; 1005 i_untilyear = ZFC_TILYEAR; 1006 i_untilmonth = ZFC_TILMONTH; 1007 i_untilday = ZFC_TILDAY; 1008 i_untiltime = ZFC_TILTIME; 1009 z.z_name = NULL; 1010 } else { 1011 i_gmtoff = ZF_GMTOFF; 1012 i_rule = ZF_RULE; 1013 i_format = ZF_FORMAT; 1014 i_untilyear = ZF_TILYEAR; 1015 i_untilmonth = ZF_TILMONTH; 1016 i_untilday = ZF_TILDAY; 1017 i_untiltime = ZF_TILTIME; 1018 z.z_name = ecpyalloc(fields[ZF_NAME]); 1019 } 1020 z.z_filename = filename; 1021 z.z_linenum = linenum; 1022 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid GMT offset"), TRUE); 1023 if ((cp = strchr(fields[i_format], '%')) != 0) { 1024 if (*++cp != 's' || strchr(cp, '%') != 0) { 1025 error(_("invalid abbreviation format")); 1026 return FALSE; 1027 } 1028 } 1029 z.z_rule = ecpyalloc(fields[i_rule]); 1030 z.z_format = ecpyalloc(fields[i_format]); 1031 hasuntil = nfields > i_untilyear; 1032 if (hasuntil) { 1033 z.z_untilrule.r_filename = filename; 1034 z.z_untilrule.r_linenum = linenum; 1035 rulesub(&z.z_untilrule, 1036 fields[i_untilyear], 1037 "only", 1038 "", 1039 (nfields > i_untilmonth) ? 1040 fields[i_untilmonth] : "Jan", 1041 (nfields > i_untilday) ? fields[i_untilday] : "1", 1042 (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 1043 z.z_untiltime = rpytime(&z.z_untilrule, 1044 z.z_untilrule.r_loyear); 1045 if (iscont && nzones > 0 && 1046 z.z_untiltime > min_time && 1047 z.z_untiltime < max_time && 1048 zones[nzones - 1].z_untiltime > min_time && 1049 zones[nzones - 1].z_untiltime < max_time && 1050 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1051 error(_("Zone continuation line end time is not after end time of previous line")); 1052 return FALSE; 1053 } 1054 } 1055 zones = (struct zone *) (void *) erealloc((char *) zones, 1056 (int) ((nzones + 1) * sizeof *zones)); 1057 zones[nzones++] = z; 1058 /* 1059 ** If there was an UNTIL field on this line, 1060 ** there's more information about the zone on the next line. 1061 */ 1062 return hasuntil; 1063} 1064 1065static void 1066inleap(fields, nfields) 1067register char ** const fields; 1068const int nfields; 1069{ 1070 register const char * cp; 1071 register const struct lookup * lp; 1072 register int i, j; 1073 int year, month, day; 1074 long dayoff, tod; 1075 time_t t; 1076 1077 if (nfields != LEAP_FIELDS) { 1078 error(_("wrong number of fields on Leap line")); 1079 return; 1080 } 1081 dayoff = 0; 1082 cp = fields[LP_YEAR]; 1083 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 1084 /* 1085 * Leapin' Lizards! 1086 */ 1087 error(_("invalid leaping year")); 1088 return; 1089 } 1090 j = EPOCH_YEAR; 1091 while (j != year) { 1092 if (year > j) { 1093 i = len_years[isleap(j)]; 1094 ++j; 1095 } else { 1096 --j; 1097 i = -len_years[isleap(j)]; 1098 } 1099 dayoff = oadd(dayoff, eitol(i)); 1100 } 1101 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1102 error(_("invalid month name")); 1103 return; 1104 } 1105 month = lp->l_value; 1106 j = TM_JANUARY; 1107 while (j != month) { 1108 i = len_months[isleap(year)][j]; 1109 dayoff = oadd(dayoff, eitol(i)); 1110 ++j; 1111 } 1112 cp = fields[LP_DAY]; 1113 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 1114 day <= 0 || day > len_months[isleap(year)][month]) { 1115 error(_("invalid day of month")); 1116 return; 1117 } 1118 dayoff = oadd(dayoff, eitol(day - 1)); 1119 if (dayoff < 0 && !TYPE_SIGNED(time_t)) { 1120 error(_("time before zero")); 1121 return; 1122 } 1123 t = (time_t) dayoff * SECSPERDAY; 1124 /* 1125 ** Cheap overflow check. 1126 */ 1127 if (t / SECSPERDAY != dayoff) { 1128 error(_("time overflow")); 1129 return; 1130 } 1131 tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE); 1132 cp = fields[LP_CORR]; 1133 { 1134 register int positive; 1135 int count; 1136 1137 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 1138 positive = FALSE; 1139 count = 1; 1140 } else if (strcmp(cp, "--") == 0) { 1141 positive = FALSE; 1142 count = 2; 1143 } else if (strcmp(cp, "+") == 0) { 1144 positive = TRUE; 1145 count = 1; 1146 } else if (strcmp(cp, "++") == 0) { 1147 positive = TRUE; 1148 count = 2; 1149 } else { 1150 error(_("illegal CORRECTION field on Leap line")); 1151 return; 1152 } 1153 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1154 error(_("illegal Rolling/Stationary field on Leap line")); 1155 return; 1156 } 1157 leapadd(tadd(t, tod), positive, lp->l_value, count); 1158 } 1159} 1160 1161static void 1162inlink(fields, nfields) 1163register char ** const fields; 1164const int nfields; 1165{ 1166 struct link l; 1167 1168 if (nfields != LINK_FIELDS) { 1169 error(_("wrong number of fields on Link line")); 1170 return; 1171 } 1172 if (*fields[LF_FROM] == '\0') { 1173 error(_("blank FROM field on Link line")); 1174 return; 1175 } 1176 if (*fields[LF_TO] == '\0') { 1177 error(_("blank TO field on Link line")); 1178 return; 1179 } 1180 l.l_filename = filename; 1181 l.l_linenum = linenum; 1182 l.l_from = ecpyalloc(fields[LF_FROM]); 1183 l.l_to = ecpyalloc(fields[LF_TO]); 1184 links = (struct link *) (void *) erealloc((char *) links, 1185 (int) ((nlinks + 1) * sizeof *links)); 1186 links[nlinks++] = l; 1187} 1188 1189static void 1190rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 1191register struct rule * const rp; 1192const char * const loyearp; 1193const char * const hiyearp; 1194const char * const typep; 1195const char * const monthp; 1196const char * const dayp; 1197const char * const timep; 1198{ 1199 register const struct lookup * lp; 1200 register const char * cp; 1201 register char * dp; 1202 register char * ep; 1203 1204 if ((lp = byword(monthp, mon_names)) == NULL) { 1205 error(_("invalid month name")); 1206 return; 1207 } 1208 rp->r_month = lp->l_value; 1209 rp->r_todisstd = FALSE; 1210 rp->r_todisgmt = FALSE; 1211 dp = ecpyalloc(timep); 1212 if (*dp != '\0') { 1213 ep = dp + strlen(dp) - 1; 1214 switch (lowerit(*ep)) { 1215 case 's': /* Standard */ 1216 rp->r_todisstd = TRUE; 1217 rp->r_todisgmt = FALSE; 1218 *ep = '\0'; 1219 break; 1220 case 'w': /* Wall */ 1221 rp->r_todisstd = FALSE; 1222 rp->r_todisgmt = FALSE; 1223 *ep = '\0'; 1224 case 'g': /* Greenwich */ 1225 case 'u': /* Universal */ 1226 case 'z': /* Zulu */ 1227 rp->r_todisstd = TRUE; 1228 rp->r_todisgmt = TRUE; 1229 *ep = '\0'; 1230 break; 1231 } 1232 } 1233 rp->r_tod = gethms(dp, _("invalid time of day"), FALSE); 1234 ifree(dp); 1235 /* 1236 ** Year work. 1237 */ 1238 cp = loyearp; 1239 lp = byword(cp, begin_years); 1240 if (lp != NULL) switch ((int) lp->l_value) { 1241 case YR_MINIMUM: 1242 rp->r_loyear = INT_MIN; 1243 break; 1244 case YR_MAXIMUM: 1245 rp->r_loyear = INT_MAX; 1246 break; 1247 default: /* "cannot happen" */ 1248 (void) fprintf(stderr, 1249 _("%s: panic: Invalid l_value %d\n"), 1250 progname, lp->l_value); 1251 (void) exit(EXIT_FAILURE); 1252 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 1253 error(_("invalid starting year")); 1254 return; 1255 } 1256 cp = hiyearp; 1257 if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) { 1258 case YR_MINIMUM: 1259 rp->r_hiyear = INT_MIN; 1260 break; 1261 case YR_MAXIMUM: 1262 rp->r_hiyear = INT_MAX; 1263 break; 1264 case YR_ONLY: 1265 rp->r_hiyear = rp->r_loyear; 1266 break; 1267 default: /* "cannot happen" */ 1268 (void) fprintf(stderr, 1269 _("%s: panic: Invalid l_value %d\n"), 1270 progname, lp->l_value); 1271 (void) exit(EXIT_FAILURE); 1272 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 1273 error(_("invalid ending year")); 1274 return; 1275 } 1276 if (rp->r_loyear > rp->r_hiyear) { 1277 error(_("starting year greater than ending year")); 1278 return; 1279 } 1280 if (*typep == '\0') 1281 rp->r_yrtype = NULL; 1282 else { 1283 if (rp->r_loyear == rp->r_hiyear) { 1284 error(_("typed single year")); 1285 return; 1286 } 1287 rp->r_yrtype = ecpyalloc(typep); 1288 } 1289 /* 1290 ** Day work. 1291 ** Accept things such as: 1292 ** 1 1293 ** last-Sunday 1294 ** Sun<=20 1295 ** Sun>=7 1296 */ 1297 dp = ecpyalloc(dayp); 1298 if ((lp = byword(dp, lasts)) != NULL) { 1299 rp->r_dycode = DC_DOWLEQ; 1300 rp->r_wday = lp->l_value; 1301 rp->r_dayofmonth = len_months[1][rp->r_month]; 1302 } else { 1303 if ((ep = strchr(dp, '<')) != 0) 1304 rp->r_dycode = DC_DOWLEQ; 1305 else if ((ep = strchr(dp, '>')) != 0) 1306 rp->r_dycode = DC_DOWGEQ; 1307 else { 1308 ep = dp; 1309 rp->r_dycode = DC_DOM; 1310 } 1311 if (rp->r_dycode != DC_DOM) { 1312 *ep++ = 0; 1313 if (*ep++ != '=') { 1314 error(_("invalid day of month")); 1315 ifree(dp); 1316 return; 1317 } 1318 if ((lp = byword(dp, wday_names)) == NULL) { 1319 error(_("invalid weekday name")); 1320 ifree(dp); 1321 return; 1322 } 1323 rp->r_wday = lp->l_value; 1324 } 1325 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || 1326 rp->r_dayofmonth <= 0 || 1327 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1328 error(_("invalid day of month")); 1329 ifree(dp); 1330 return; 1331 } 1332 } 1333 ifree(dp); 1334} 1335 1336static void 1337convert(val, buf) 1338const long val; 1339char * const buf; 1340{ 1341 register int i; 1342 register long shift; 1343 1344 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1345 buf[i] = val >> shift; 1346} 1347 1348static void 1349puttzcode(val, fp) 1350const long val; 1351FILE * const fp; 1352{ 1353 char buf[4]; 1354 1355 convert(val, buf); 1356 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); 1357} 1358 1359static int 1360atcomp(avp, bvp) 1361void * avp; 1362void * bvp; 1363{ 1364 if (((struct attype *) avp)->at < ((struct attype *) bvp)->at) 1365 return -1; 1366 else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at) 1367 return 1; 1368 else return 0; 1369} 1370 1371static void 1372writezone(name) 1373const char * const name; 1374{ 1375 register FILE * fp; 1376 register int i, j; 1377 static char * fullname; 1378 static struct tzhead tzh; 1379 time_t ats[TZ_MAX_TIMES]; 1380 unsigned char types[TZ_MAX_TIMES]; 1381 1382 /* 1383 ** Sort. 1384 */ 1385 if (timecnt > 1) 1386 (void) qsort((void *) attypes, (size_t) timecnt, 1387 (size_t) sizeof *attypes, atcomp); 1388 /* 1389 ** Optimize. 1390 */ 1391 { 1392 int fromi; 1393 int toi; 1394 1395 toi = 0; 1396 fromi = 0; 1397 if (isdsts[0] == 0) 1398 while (attypes[fromi].type == 0) 1399 ++fromi; /* handled by default rule */ 1400 for ( ; fromi < timecnt; ++fromi) { 1401 if (toi != 0 1402 && ((attypes[fromi].at 1403 + gmtoffs[attypes[toi - 1].type]) 1404 <= (attypes[toi - 1].at 1405 + gmtoffs[toi == 1 ? 0 1406 : attypes[toi - 2].type]))) { 1407 attypes[toi - 1].type = attypes[fromi].type; 1408 continue; 1409 } 1410 if (toi == 0 || 1411 attypes[toi - 1].type != attypes[fromi].type) 1412 attypes[toi++] = attypes[fromi]; 1413 } 1414 timecnt = toi; 1415 } 1416 /* 1417 ** Transfer. 1418 */ 1419 for (i = 0; i < timecnt; ++i) { 1420 ats[i] = attypes[i].at; 1421 types[i] = attypes[i].type; 1422 } 1423 fullname = erealloc(fullname, 1424 (int) (strlen(directory) + 1 + strlen(name) + 1)); 1425 (void) sprintf(fullname, "%s/%s", directory, name); 1426 if ((fp = fopen(fullname, "wb")) == NULL) { 1427 if (mkdirs(fullname) != 0) 1428 (void) exit(EXIT_FAILURE); 1429 if ((fp = fopen(fullname, "wb")) == NULL) { 1430 const char *e = strerror(errno); 1431 (void) fprintf(stderr, _("%s: Can't create %s: %s\n"), 1432 progname, fullname, e); 1433 (void) exit(EXIT_FAILURE); 1434 } 1435 } 1436 convert(eitol(typecnt), tzh.tzh_ttisgmtcnt); 1437 convert(eitol(typecnt), tzh.tzh_ttisstdcnt); 1438 convert(eitol(leapcnt), tzh.tzh_leapcnt); 1439 convert(eitol(timecnt), tzh.tzh_timecnt); 1440 convert(eitol(typecnt), tzh.tzh_typecnt); 1441 convert(eitol(charcnt), tzh.tzh_charcnt); 1442#define DO(field) (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp) 1443 DO(tzh_reserved); 1444 DO(tzh_ttisgmtcnt); 1445 DO(tzh_ttisstdcnt); 1446 DO(tzh_leapcnt); 1447 DO(tzh_timecnt); 1448 DO(tzh_typecnt); 1449 DO(tzh_charcnt); 1450#undef DO 1451 for (i = 0; i < timecnt; ++i) { 1452 j = leapcnt; 1453 while (--j >= 0) 1454 if (ats[i] >= trans[j]) { 1455 ats[i] = tadd(ats[i], corr[j]); 1456 break; 1457 } 1458 puttzcode((long) ats[i], fp); 1459 } 1460 if (timecnt > 0) 1461 (void) fwrite((void *) types, (size_t) sizeof types[0], 1462 (size_t) timecnt, fp); 1463 for (i = 0; i < typecnt; ++i) { 1464 puttzcode((long) gmtoffs[i], fp); 1465 (void) putc(isdsts[i], fp); 1466 (void) putc(abbrinds[i], fp); 1467 } 1468 if (charcnt != 0) 1469 (void) fwrite((void *) chars, (size_t) sizeof chars[0], 1470 (size_t) charcnt, fp); 1471 for (i = 0; i < leapcnt; ++i) { 1472 if (roll[i]) { 1473 if (timecnt == 0 || trans[i] < ats[0]) { 1474 j = 0; 1475 while (isdsts[j]) 1476 if (++j >= typecnt) { 1477 j = 0; 1478 break; 1479 } 1480 } else { 1481 j = 1; 1482 while (j < timecnt && trans[i] >= ats[j]) 1483 ++j; 1484 j = types[j - 1]; 1485 } 1486 puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp); 1487 } else puttzcode((long) trans[i], fp); 1488 puttzcode((long) corr[i], fp); 1489 } 1490 for (i = 0; i < typecnt; ++i) 1491 (void) putc(ttisstds[i], fp); 1492 for (i = 0; i < typecnt; ++i) 1493 (void) putc(ttisgmts[i], fp); 1494 if (ferror(fp) || fclose(fp)) { 1495 (void) fprintf(stderr, _("%s: Error writing %s\n"), 1496 progname, fullname); 1497 (void) exit(EXIT_FAILURE); 1498 } 1499} 1500 1501static void 1502doabbr(abbr, format, letters, isdst) 1503char * const abbr; 1504const char * const format; 1505const char * const letters; 1506const int isdst; 1507{ 1508 if (strchr(format, '/') == NULL) { 1509 if (letters == NULL) 1510 (void) strcpy(abbr, format); 1511 else (void) sprintf(abbr, format, letters); 1512 } else if (isdst) 1513 (void) strcpy(abbr, strchr(format, '/') + 1); 1514 else { 1515 (void) strcpy(abbr, format); 1516 *strchr(abbr, '/') = '\0'; 1517 } 1518} 1519 1520static void 1521outzone(zpfirst, zonecount) 1522const struct zone * const zpfirst; 1523const int zonecount; 1524{ 1525 register const struct zone * zp; 1526 register struct rule * rp; 1527 register int i, j; 1528 register int usestart, useuntil; 1529 register time_t starttime, untiltime; 1530 register long gmtoff; 1531 register long stdoff; 1532 register int year; 1533 register long startoff; 1534 register int startttisstd; 1535 register int startttisgmt; 1536 register int type; 1537 char startbuf[BUFSIZ]; 1538 1539 INITIALIZE(untiltime); 1540 INITIALIZE(starttime); 1541 /* 1542 ** Now. . .finally. . .generate some useful data! 1543 */ 1544 timecnt = 0; 1545 typecnt = 0; 1546 charcnt = 0; 1547 /* 1548 ** A guess that may well be corrected later. 1549 */ 1550 stdoff = 0; 1551 /* 1552 ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au) 1553 ** for noting the need to unconditionally initialize startttisstd. 1554 */ 1555 startttisstd = FALSE; 1556 startttisgmt = FALSE; 1557 for (i = 0; i < zonecount; ++i) { 1558 zp = &zpfirst[i]; 1559 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 1560 useuntil = i < (zonecount - 1); 1561 if (useuntil && zp->z_untiltime <= min_time) 1562 continue; 1563 gmtoff = zp->z_gmtoff; 1564 eat(zp->z_filename, zp->z_linenum); 1565 *startbuf = '\0'; 1566 startoff = zp->z_gmtoff; 1567 if (zp->z_nrules == 0) { 1568 stdoff = zp->z_stdoff; 1569 doabbr(startbuf, zp->z_format, 1570 (char *) NULL, stdoff != 0); 1571 type = addtype(oadd(zp->z_gmtoff, stdoff), 1572 startbuf, stdoff != 0, startttisstd, 1573 startttisgmt); 1574 if (usestart) { 1575 addtt(starttime, type); 1576 usestart = FALSE; 1577 } 1578 else if (stdoff != 0) 1579 addtt(min_time, type); 1580 } else for (year = min_year; year <= max_year; ++year) { 1581 if (useuntil && year > zp->z_untilrule.r_hiyear) 1582 break; 1583 /* 1584 ** Mark which rules to do in the current year. 1585 ** For those to do, calculate rpytime(rp, year); 1586 */ 1587 for (j = 0; j < zp->z_nrules; ++j) { 1588 rp = &zp->z_rules[j]; 1589 eats(zp->z_filename, zp->z_linenum, 1590 rp->r_filename, rp->r_linenum); 1591 rp->r_todo = year >= rp->r_loyear && 1592 year <= rp->r_hiyear && 1593 yearistype(year, rp->r_yrtype); 1594 if (rp->r_todo) 1595 rp->r_temp = rpytime(rp, year); 1596 } 1597 for ( ; ; ) { 1598 register int k; 1599 register time_t jtime, ktime; 1600 register long offset; 1601 char buf[BUFSIZ]; 1602 1603 INITIALIZE(ktime); 1604 if (useuntil) { 1605 /* 1606 ** Turn untiltime into GMT 1607 ** assuming the current gmtoff and 1608 ** stdoff values. 1609 */ 1610 untiltime = zp->z_untiltime; 1611 if (!zp->z_untilrule.r_todisgmt) 1612 untiltime = tadd(untiltime, 1613 -gmtoff); 1614 if (!zp->z_untilrule.r_todisstd) 1615 untiltime = tadd(untiltime, 1616 -stdoff); 1617 } 1618 /* 1619 ** Find the rule (of those to do, if any) 1620 ** that takes effect earliest in the year. 1621 */ 1622 k = -1; 1623 for (j = 0; j < zp->z_nrules; ++j) { 1624 rp = &zp->z_rules[j]; 1625 if (!rp->r_todo) 1626 continue; 1627 eats(zp->z_filename, zp->z_linenum, 1628 rp->r_filename, rp->r_linenum); 1629 offset = rp->r_todisgmt ? 0 : gmtoff; 1630 if (!rp->r_todisstd) 1631 offset = oadd(offset, stdoff); 1632 jtime = rp->r_temp; 1633 if (jtime == min_time || 1634 jtime == max_time) 1635 continue; 1636 jtime = tadd(jtime, -offset); 1637 if (k < 0 || jtime < ktime) { 1638 k = j; 1639 ktime = jtime; 1640 } 1641 } 1642 if (k < 0) 1643 break; /* go on to next year */ 1644 rp = &zp->z_rules[k]; 1645 rp->r_todo = FALSE; 1646 if (useuntil && ktime >= untiltime) 1647 break; 1648 stdoff = rp->r_stdoff; 1649 if (usestart && ktime == starttime) 1650 usestart = FALSE; 1651 if (usestart) { 1652 if (ktime < starttime) { 1653 startoff = oadd(zp->z_gmtoff, 1654 stdoff); 1655 doabbr(startbuf, zp->z_format, 1656 rp->r_abbrvar, 1657 rp->r_stdoff != 0); 1658 continue; 1659 } 1660 if (*startbuf == '\0' && 1661 startoff == oadd(zp->z_gmtoff, 1662 stdoff)) { 1663 doabbr(startbuf, zp->z_format, 1664 rp->r_abbrvar, 1665 rp->r_stdoff != 0); 1666 } 1667 } 1668 eats(zp->z_filename, zp->z_linenum, 1669 rp->r_filename, rp->r_linenum); 1670 doabbr(buf, zp->z_format, rp->r_abbrvar, 1671 rp->r_stdoff != 0); 1672 offset = oadd(zp->z_gmtoff, rp->r_stdoff); 1673 type = addtype(offset, buf, rp->r_stdoff != 0, 1674 rp->r_todisstd, rp->r_todisgmt); 1675 addtt(ktime, type); 1676 } 1677 } 1678 if (usestart) { 1679 if (*startbuf == '\0' && 1680 zp->z_format != NULL && 1681 strchr(zp->z_format, '%') == NULL && 1682 strchr(zp->z_format, '/') == NULL) 1683 (void) strcpy(startbuf, zp->z_format); 1684 eat(zp->z_filename, zp->z_linenum); 1685 if (*startbuf == '\0') 1686error(_("can't determine time zone abbrevation to use just after until time")); 1687 else addtt(starttime, 1688 addtype(startoff, startbuf, 1689 startoff != zp->z_gmtoff, 1690 startttisstd, 1691 startttisgmt)); 1692 } 1693 /* 1694 ** Now we may get to set starttime for the next zone line. 1695 */ 1696 if (useuntil) { 1697 startttisstd = zp->z_untilrule.r_todisstd; 1698 startttisgmt = zp->z_untilrule.r_todisgmt; 1699 starttime = zp->z_untiltime; 1700 if (!startttisstd) 1701 starttime = tadd(starttime, -stdoff); 1702 if (!startttisgmt) 1703 starttime = tadd(starttime, -gmtoff); 1704 } 1705 } 1706 writezone(zpfirst->z_name); 1707} 1708 1709static void 1710addtt(starttime, type) 1711const time_t starttime; 1712const int type; 1713{ 1714 if (timecnt >= TZ_MAX_TIMES) { 1715 error(_("too many transitions?!")); 1716 (void) exit(EXIT_FAILURE); 1717 } 1718 attypes[timecnt].at = starttime; 1719 attypes[timecnt].type = type; 1720 ++timecnt; 1721} 1722 1723static int 1724addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) 1725const long gmtoff; 1726const char * const abbr; 1727const int isdst; 1728const int ttisstd; 1729const int ttisgmt; 1730{ 1731 register int i, j; 1732 1733 if (isdst != TRUE && isdst != FALSE) { 1734 error(_("internal error - addtype called with bad isdst")); 1735 (void) exit(EXIT_FAILURE); 1736 } 1737 if (ttisstd != TRUE && ttisstd != FALSE) { 1738 error(_("internal error - addtype called with bad ttisstd")); 1739 (void) exit(EXIT_FAILURE); 1740 } 1741 if (ttisgmt != TRUE && ttisgmt != FALSE) { 1742 error(_("internal error - addtype called with bad ttisgmt")); 1743 (void) exit(EXIT_FAILURE); 1744 } 1745 /* 1746 ** See if there's already an entry for this zone type. 1747 ** If so, just return its index. 1748 */ 1749 for (i = 0; i < typecnt; ++i) { 1750 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 1751 strcmp(abbr, &chars[abbrinds[i]]) == 0 && 1752 ttisstd == ttisstds[i] && 1753 ttisgmt == ttisgmts[i]) 1754 return i; 1755 } 1756 /* 1757 ** There isn't one; add a new one, unless there are already too 1758 ** many. 1759 */ 1760 if (typecnt >= TZ_MAX_TYPES) { 1761 error(_("too many local time types")); 1762 (void) exit(EXIT_FAILURE); 1763 } 1764 gmtoffs[i] = gmtoff; 1765 isdsts[i] = isdst; 1766 ttisstds[i] = ttisstd; 1767 ttisgmts[i] = ttisgmt; 1768 1769 for (j = 0; j < charcnt; ++j) 1770 if (strcmp(&chars[j], abbr) == 0) 1771 break; 1772 if (j == charcnt) 1773 newabbr(abbr); 1774 abbrinds[i] = j; 1775 ++typecnt; 1776 return i; 1777} 1778 1779static void 1780leapadd(t, positive, rolling, count) 1781const time_t t; 1782const int positive; 1783const int rolling; 1784int count; 1785{ 1786 register int i, j; 1787 1788 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 1789 error(_("too many leap seconds")); 1790 (void) exit(EXIT_FAILURE); 1791 } 1792 for (i = 0; i < leapcnt; ++i) 1793 if (t <= trans[i]) { 1794 if (t == trans[i]) { 1795 error(_("repeated leap second moment")); 1796 (void) exit(EXIT_FAILURE); 1797 } 1798 break; 1799 } 1800 do { 1801 for (j = leapcnt; j > i; --j) { 1802 trans[j] = trans[j - 1]; 1803 corr[j] = corr[j - 1]; 1804 roll[j] = roll[j - 1]; 1805 } 1806 trans[i] = t; 1807 corr[i] = positive ? 1L : eitol(-count); 1808 roll[i] = rolling; 1809 ++leapcnt; 1810 } while (positive && --count != 0); 1811} 1812 1813static void 1814adjleap P((void)) 1815{ 1816 register int i; 1817 register long last = 0; 1818 1819 /* 1820 ** propagate leap seconds forward 1821 */ 1822 for (i = 0; i < leapcnt; ++i) { 1823 trans[i] = tadd(trans[i], last); 1824 last = corr[i] += last; 1825 } 1826} 1827 1828static int 1829yearistype(year, type) 1830const int year; 1831const char * const type; 1832{ 1833 static char * buf; 1834 int result; 1835 1836 if (type == NULL || *type == '\0') 1837 return TRUE; 1838 buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); 1839 (void) sprintf(buf, "%s %d %s", yitcommand, year, type); 1840 result = system(buf); 1841 if (result == 0) 1842 return TRUE; 1843 if (result == (1 << 8)) 1844 return FALSE; 1845 error(_("Wild result from command execution")); 1846 (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"), 1847 progname, buf, result); 1848 for ( ; ; ) 1849 (void) exit(EXIT_FAILURE); 1850} 1851 1852static int 1853lowerit(a) 1854int a; 1855{ 1856 a = (unsigned char) a; 1857 return (isascii(a) && isupper(a)) ? tolower(a) : a; 1858} 1859 1860static int 1861ciequal(ap, bp) /* case-insensitive equality */ 1862register const char * ap; 1863register const char * bp; 1864{ 1865 while (lowerit(*ap) == lowerit(*bp++)) 1866 if (*ap++ == '\0') 1867 return TRUE; 1868 return FALSE; 1869} 1870 1871static int 1872itsabbr(abbr, word) 1873register const char * abbr; 1874register const char * word; 1875{ 1876 if (lowerit(*abbr) != lowerit(*word)) 1877 return FALSE; 1878 ++word; 1879 while (*++abbr != '\0') 1880 do { 1881 if (*word == '\0') 1882 return FALSE; 1883 } while (lowerit(*word++) != lowerit(*abbr)); 1884 return TRUE; 1885} 1886 1887static const struct lookup * 1888byword(word, table) 1889register const char * const word; 1890register const struct lookup * const table; 1891{ 1892 register const struct lookup * foundlp; 1893 register const struct lookup * lp; 1894 1895 if (word == NULL || table == NULL) 1896 return NULL; 1897 /* 1898 ** Look for exact match. 1899 */ 1900 for (lp = table; lp->l_word != NULL; ++lp) 1901 if (ciequal(word, lp->l_word)) 1902 return lp; 1903 /* 1904 ** Look for inexact match. 1905 */ 1906 foundlp = NULL; 1907 for (lp = table; lp->l_word != NULL; ++lp) 1908 if (itsabbr(word, lp->l_word)) 1909 if (foundlp == NULL) 1910 foundlp = lp; 1911 else return NULL; /* multiple inexact matches */ 1912 return foundlp; 1913} 1914 1915static char ** 1916getfields(cp) 1917register char * cp; 1918{ 1919 register char * dp; 1920 register char ** array; 1921 register int nsubs; 1922 1923 if (cp == NULL) 1924 return NULL; 1925 array = (char **) (void *) 1926 emalloc((int) ((strlen(cp) + 1) * sizeof *array)); 1927 nsubs = 0; 1928 for ( ; ; ) { 1929 while (isascii(*cp) && isspace((unsigned char) *cp)) 1930 ++cp; 1931 if (*cp == '\0' || *cp == '#') 1932 break; 1933 array[nsubs++] = dp = cp; 1934 do { 1935 if ((*dp = *cp++) != '"') 1936 ++dp; 1937 else while ((*dp = *cp++) != '"') 1938 if (*dp != '\0') 1939 ++dp; 1940 else error(_("Odd number of quotation marks")); 1941 } while (*cp != '\0' && *cp != '#' && 1942 (!isascii(*cp) || !isspace((unsigned char) *cp))); 1943 if (isascii(*cp) && isspace((unsigned char) *cp)) 1944 ++cp; 1945 *dp = '\0'; 1946 } 1947 array[nsubs] = NULL; 1948 return array; 1949} 1950 1951static long 1952oadd(t1, t2) 1953const long t1; 1954const long t2; 1955{ 1956 register long t; 1957 1958 t = t1 + t2; 1959 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1960 error(_("time overflow")); 1961 (void) exit(EXIT_FAILURE); 1962 } 1963 return t; 1964} 1965 1966static time_t 1967tadd(t1, t2) 1968const time_t t1; 1969const long t2; 1970{ 1971 register time_t t; 1972 1973 if (t1 == max_time && t2 > 0) 1974 return max_time; 1975 if (t1 == min_time && t2 < 0) 1976 return min_time; 1977 t = t1 + t2; 1978 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1979 error(_("time overflow")); 1980 (void) exit(EXIT_FAILURE); 1981 } 1982 return t; 1983} 1984 1985/* 1986** Given a rule, and a year, compute the date - in seconds since January 1, 1987** 1970, 00:00 LOCAL time - in that year that the rule refers to. 1988*/ 1989 1990static time_t 1991rpytime(rp, wantedy) 1992register const struct rule * const rp; 1993register const int wantedy; 1994{ 1995 register int y, m, i; 1996 register long dayoff; /* with a nod to Margaret O. */ 1997 register time_t t; 1998 1999 if (wantedy == INT_MIN) 2000 return min_time; 2001 if (wantedy == INT_MAX) 2002 return max_time; 2003 dayoff = 0; 2004 m = TM_JANUARY; 2005 y = EPOCH_YEAR; 2006 while (wantedy != y) { 2007 if (wantedy > y) { 2008 i = len_years[isleap(y)]; 2009 ++y; 2010 } else { 2011 --y; 2012 i = -len_years[isleap(y)]; 2013 } 2014 dayoff = oadd(dayoff, eitol(i)); 2015 } 2016 while (m != rp->r_month) { 2017 i = len_months[isleap(y)][m]; 2018 dayoff = oadd(dayoff, eitol(i)); 2019 ++m; 2020 } 2021 i = rp->r_dayofmonth; 2022 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 2023 if (rp->r_dycode == DC_DOWLEQ) 2024 --i; 2025 else { 2026 error(_("use of 2/29 in non leap-year")); 2027 (void) exit(EXIT_FAILURE); 2028 } 2029 } 2030 --i; 2031 dayoff = oadd(dayoff, eitol(i)); 2032 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 2033 register long wday; 2034 2035#define LDAYSPERWEEK ((long) DAYSPERWEEK) 2036 wday = eitol(EPOCH_WDAY); 2037 /* 2038 ** Don't trust mod of negative numbers. 2039 */ 2040 if (dayoff >= 0) 2041 wday = (wday + dayoff) % LDAYSPERWEEK; 2042 else { 2043 wday -= ((-dayoff) % LDAYSPERWEEK); 2044 if (wday < 0) 2045 wday += LDAYSPERWEEK; 2046 } 2047 while (wday != eitol(rp->r_wday)) 2048 if (rp->r_dycode == DC_DOWGEQ) { 2049 dayoff = oadd(dayoff, (long) 1); 2050 if (++wday >= LDAYSPERWEEK) 2051 wday = 0; 2052 ++i; 2053 } else { 2054 dayoff = oadd(dayoff, (long) -1); 2055 if (--wday < 0) 2056 wday = LDAYSPERWEEK - 1; 2057 --i; 2058 } 2059 if (i < 0 || i >= len_months[isleap(y)][m]) { 2060 error(_("no day in month matches rule")); 2061 (void) exit(EXIT_FAILURE); 2062 } 2063 } 2064 if (dayoff < 0 && !TYPE_SIGNED(time_t)) 2065 return min_time; 2066 t = (time_t) dayoff * SECSPERDAY; 2067 /* 2068 ** Cheap overflow check. 2069 */ 2070 if (t / SECSPERDAY != dayoff) 2071 return (dayoff > 0) ? max_time : min_time; 2072 return tadd(t, rp->r_tod); 2073} 2074 2075static void 2076newabbr(string) 2077const char * const string; 2078{ 2079 register int i; 2080 2081 i = strlen(string) + 1; 2082 if (charcnt + i > TZ_MAX_CHARS) { 2083 error(_("too many, or too long, time zone abbreviations")); 2084 (void) exit(EXIT_FAILURE); 2085 } 2086 (void) strcpy(&chars[charcnt], string); 2087 charcnt += eitol(i); 2088} 2089 2090static int 2091mkdirs(argname) 2092char * const argname; 2093{ 2094 register char * name; 2095 register char * cp; 2096 2097 if (argname == NULL || *argname == '\0') 2098 return 0; 2099 cp = name = ecpyalloc(argname); 2100 while ((cp = strchr(cp + 1, '/')) != 0) { 2101 *cp = '\0'; 2102#ifndef unix 2103 /* 2104 ** DOS drive specifier? 2105 */ 2106 if (isalpha((unsigned char) name[0]) && 2107 name[1] == ':' && name[2] == '\0') { 2108 *cp = '/'; 2109 continue; 2110 } 2111#endif /* !defined unix */ 2112 if (!itsdir(name)) { 2113 /* 2114 ** It doesn't seem to exist, so we try to create it. 2115 */ 2116 if (mkdir(name, 0755) != 0) { 2117 const char *e = strerror(errno); 2118 (void) fprintf(stderr, 2119 _("%s: Can't create directory %s: %s\n"), 2120 progname, name, e); 2121 ifree(name); 2122 return -1; 2123 } 2124 } 2125 *cp = '/'; 2126 } 2127 ifree(name); 2128 return 0; 2129} 2130 2131static long 2132eitol(i) 2133const int i; 2134{ 2135 long l; 2136 2137 l = i; 2138 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 2139 (void) fprintf(stderr, 2140 _("%s: %d did not sign extend correctly\n"), 2141 progname, i); 2142 (void) exit(EXIT_FAILURE); 2143 } 2144 return l; 2145} 2146 2147/* 2148** UNIX was a registered trademark of UNIX System Laboratories in 1993. 2149*/ 2150