zic.c revision 23859
159191Skris#ifndef lint 2280304Sjkim#ifndef NOID 3280304Sjkimstatic char elsieid[] = "@(#)zic.c 7.77"; 4280304Sjkim#endif /* !defined NOID */ 559191Skris#endif /* !defined lint */ 659191Skris 759191Skris#include "private.h" 859191Skris#include "locale.h" 959191Skris#include "tzfile.h" 1059191Skris#include <sys/stat.h> /* for umask manifest constants */ 1159191Skris#include <sys/types.h> 1259191Skris#include <unistd.h> 1359191Skris 14280304Sjkim/* 1559191Skris** On some ancient hosts, predicates like `isspace(C)' are defined 1659191Skris** only if isascii(C) || C == EOF. Modern hosts obey the C Standard, 1759191Skris** which says they are defined only if C == ((unsigned char) C) || C == EOF. 1859191Skris** Neither the C Standard nor Posix require that `isascii' exist. 1959191Skris** For portability, we check both ancient and modern requirements. 2059191Skris** If isascii is not defined, the isascii check succeeds trivially. 2159191Skris*/ 2259191Skris#include "ctype.h" 2359191Skris#ifndef isascii 2459191Skris#define isascii(x) 1 2559191Skris#endif 2659191Skris 2759191Skrisstruct rule { 2859191Skris const char * r_filename; 2959191Skris int r_linenum; 3059191Skris const char * r_name; 3159191Skris 3259191Skris int r_loyear; /* for example, 1986 */ 3359191Skris int r_hiyear; /* for example, 1986 */ 3459191Skris const char * r_yrtype; 3559191Skris 3659191Skris int r_month; /* 0..11 */ 3759191Skris 3859191Skris int r_dycode; /* see below */ 3959191Skris int r_dayofmonth; 4059191Skris int r_wday; 4159191Skris 4259191Skris long r_tod; /* time from midnight */ 4359191Skris int r_todisstd; /* above is standard time if TRUE */ 4459191Skris /* or wall clock time if FALSE */ 4559191Skris int r_todisgmt; /* above is GMT if TRUE */ 4659191Skris /* or local time if FALSE */ 4759191Skris long r_stdoff; /* offset from standard time */ 4859191Skris const char * r_abbrvar; /* variable part of abbreviation */ 4959191Skris 5059191Skris int r_todo; /* a rule to do (used in outzone) */ 5159191Skris time_t r_temp; /* used in outzone */ 5259191Skris}; 5359191Skris 5459191Skris/* 5559191Skris** r_dycode r_dayofmonth r_wday 5659191Skris*/ 5759191Skris 5859191Skris#define DC_DOM 0 /* 1..31 */ /* unused */ 5959191Skris#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 6059191Skris#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 6159191Skris 6259191Skrisstruct zone { 6359191Skris const char * z_filename; 6459191Skris int z_linenum; 6559191Skris 66280304Sjkim const char * z_name; 67280304Sjkim long z_gmtoff; 6859191Skris const char * z_rule; 6959191Skris const char * z_format; 7059191Skris 7159191Skris long z_stdoff; 7259191Skris 7359191Skris struct rule * z_rules; 74109998Smarkm int z_nrules; 75280304Sjkim 76109998Smarkm struct rule z_untilrule; 77280304Sjkim time_t z_untiltime; 78109998Smarkm}; 79280304Sjkim 80109998Smarkmextern int getopt P((int argc, char * const argv[], 81280304Sjkim const char * options)); 82280304Sjkimextern char * icatalloc P((char * old, const char * new)); 83109998Smarkmextern char * icpyalloc P((const char * string)); 8459191Skrisextern void ifree P((char * p)); 8559191Skrisextern char * imalloc P((int n)); 8659191Skrisextern void * irealloc P((void * old, int n)); 87280304Sjkimextern int link P((const char * fromname, const char * toname)); 88280304Sjkimextern char * optarg; 89280304Sjkimextern int optind; 90280304Sjkimextern char * scheck P((const char * string, const char * format)); 91280304Sjkim 92280304Sjkimstatic void addtt P((time_t starttime, int type)); 93280304Sjkimstatic int addtype P((long gmtoff, const char * abbr, int isdst, 94280304Sjkim int ttisstd, int ttisgmt)); 95280304Sjkimstatic void leapadd P((time_t t, int positive, int rolling, int count)); 96280304Sjkimstatic void adjleap P((void)); 97280304Sjkimstatic void associate P((void)); 98280304Sjkimstatic int ciequal P((const char * ap, const char * bp)); 99280304Sjkimstatic void convert P((long val, char * buf)); 100280304Sjkimstatic void dolink P((const char * fromfile, const char * tofile)); 101280304Sjkimstatic void doabbr P((char * abbr, const char * format, 102280304Sjkim const char * letters, int isdst)); 10359191Skrisstatic void eat P((const char * name, int num)); 104109998Smarkmstatic void eats P((const char * name, int num, 105280304Sjkim const char * rname, int rnum)); 106280304Sjkimstatic long eitol P((int i)); 107280304Sjkimstatic void error P((const char * message)); 10859191Skrisstatic char ** getfields P((char * buf)); 109109998Smarkmstatic long gethms P((const char * string, const char * errstrng, 110280304Sjkim int signable)); 111280304Sjkimstatic void infile P((const char * filename)); 112280304Sjkimstatic void inleap P((char ** fields, int nfields)); 113280304Sjkimstatic void inlink P((char ** fields, int nfields)); 114280304Sjkimstatic void inrule P((char ** fields, int nfields)); 11559191Skrisstatic int inzcont P((char ** fields, int nfields)); 116109998Smarkmstatic int inzone P((char ** fields, int nfields)); 117280304Sjkimstatic int inzsub P((char ** fields, int nfields, int iscont)); 118280304Sjkimstatic int itsabbr P((const char * abbr, const char * word)); 119280304Sjkimstatic int itsdir P((const char * name)); 120280304Sjkimstatic int lowerit P((int c)); 121280304Sjkimstatic char * memcheck P((char * tocheck)); 122280304Sjkimstatic int mkdirs P((char * filename)); 12359191Skrisstatic void newabbr P((const char * abbr)); 124109998Smarkmstatic long oadd P((long t1, long t2)); 125280304Sjkimstatic void outzone P((const struct zone * zp, int ntzones)); 126280304Sjkimstatic void puttzcode P((long code, FILE * fp)); 127280304Sjkimstatic int rcomp P((const void * leftp, const void * rightp)); 128280304Sjkimstatic time_t rpytime P((const struct rule * rp, int wantedy)); 129280304Sjkimstatic void rulesub P((struct rule * rp, 130280304Sjkim const char * loyearp, const char * hiyearp, 13159191Skris const char * typep, const char * monthp, 132109998Smarkm const char * dayp, const char * timep)); 133280304Sjkimstatic void setboundaries P((void)); 134280304Sjkimstatic time_t tadd P((time_t t1, long t2)); 135280304Sjkimstatic void usage P((void)); 136280304Sjkimstatic void writezone P((const char * name)); 137280304Sjkimstatic int yearistype P((int year, const char * type)); 13859191Skris 139280304Sjkim#if !HAVE_STRERROR 14059191Skrisstatic char * strerror P((int)); 141280304Sjkim#endif /* !HAVE_STRERROR */ 142280304Sjkim 143280304Sjkimstatic int charcnt; 144280304Sjkimstatic int errors; 14559191Skrisstatic const char * filename; 14659191Skrisstatic int leapcnt; 14759191Skrisstatic int linenum; 148280304Sjkimstatic time_t max_time; 149280304Sjkimstatic int max_year; 150280304Sjkimstatic time_t min_time; 15159191Skrisstatic int min_year; 15259191Skrisstatic int noise; 153280304Sjkimstatic const char * rfilename; 154280304Sjkimstatic int rlinenum; 155280304Sjkimstatic 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 1427 /* 1428 * Remove old file, if any, to snap links. 1429 */ 1430 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) { 1431 const char *e = strerror(errno); 1432 (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"), 1433 progname, fullname, e); 1434 (void) exit(EXIT_FAILURE); 1435 } 1436 1437 if ((fp = fopen(fullname, "wb")) == NULL) { 1438 if (mkdirs(fullname) != 0) 1439 (void) exit(EXIT_FAILURE); 1440 if ((fp = fopen(fullname, "wb")) == NULL) { 1441 const char *e = strerror(errno); 1442 (void) fprintf(stderr, _("%s: Can't create %s: %s\n"), 1443 progname, fullname, e); 1444 (void) exit(EXIT_FAILURE); 1445 } 1446 } 1447 convert(eitol(typecnt), tzh.tzh_ttisgmtcnt); 1448 convert(eitol(typecnt), tzh.tzh_ttisstdcnt); 1449 convert(eitol(leapcnt), tzh.tzh_leapcnt); 1450 convert(eitol(timecnt), tzh.tzh_timecnt); 1451 convert(eitol(typecnt), tzh.tzh_typecnt); 1452 convert(eitol(charcnt), tzh.tzh_charcnt); 1453#define DO(field) (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp) 1454 DO(tzh_reserved); 1455 DO(tzh_ttisgmtcnt); 1456 DO(tzh_ttisstdcnt); 1457 DO(tzh_leapcnt); 1458 DO(tzh_timecnt); 1459 DO(tzh_typecnt); 1460 DO(tzh_charcnt); 1461#undef DO 1462 for (i = 0; i < timecnt; ++i) { 1463 j = leapcnt; 1464 while (--j >= 0) 1465 if (ats[i] >= trans[j]) { 1466 ats[i] = tadd(ats[i], corr[j]); 1467 break; 1468 } 1469 puttzcode((long) ats[i], fp); 1470 } 1471 if (timecnt > 0) 1472 (void) fwrite((void *) types, (size_t) sizeof types[0], 1473 (size_t) timecnt, fp); 1474 for (i = 0; i < typecnt; ++i) { 1475 puttzcode((long) gmtoffs[i], fp); 1476 (void) putc(isdsts[i], fp); 1477 (void) putc(abbrinds[i], fp); 1478 } 1479 if (charcnt != 0) 1480 (void) fwrite((void *) chars, (size_t) sizeof chars[0], 1481 (size_t) charcnt, fp); 1482 for (i = 0; i < leapcnt; ++i) { 1483 if (roll[i]) { 1484 if (timecnt == 0 || trans[i] < ats[0]) { 1485 j = 0; 1486 while (isdsts[j]) 1487 if (++j >= typecnt) { 1488 j = 0; 1489 break; 1490 } 1491 } else { 1492 j = 1; 1493 while (j < timecnt && trans[i] >= ats[j]) 1494 ++j; 1495 j = types[j - 1]; 1496 } 1497 puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp); 1498 } else puttzcode((long) trans[i], fp); 1499 puttzcode((long) corr[i], fp); 1500 } 1501 for (i = 0; i < typecnt; ++i) 1502 (void) putc(ttisstds[i], fp); 1503 for (i = 0; i < typecnt; ++i) 1504 (void) putc(ttisgmts[i], fp); 1505 if (ferror(fp) || fclose(fp)) { 1506 (void) fprintf(stderr, _("%s: Error writing %s\n"), 1507 progname, fullname); 1508 (void) exit(EXIT_FAILURE); 1509 } 1510} 1511 1512static void 1513doabbr(abbr, format, letters, isdst) 1514char * const abbr; 1515const char * const format; 1516const char * const letters; 1517const int isdst; 1518{ 1519 if (strchr(format, '/') == NULL) { 1520 if (letters == NULL) 1521 (void) strcpy(abbr, format); 1522 else (void) sprintf(abbr, format, letters); 1523 } else if (isdst) 1524 (void) strcpy(abbr, strchr(format, '/') + 1); 1525 else { 1526 (void) strcpy(abbr, format); 1527 *strchr(abbr, '/') = '\0'; 1528 } 1529} 1530 1531static void 1532outzone(zpfirst, zonecount) 1533const struct zone * const zpfirst; 1534const int zonecount; 1535{ 1536 register const struct zone * zp; 1537 register struct rule * rp; 1538 register int i, j; 1539 register int usestart, useuntil; 1540 register time_t starttime, untiltime; 1541 register long gmtoff; 1542 register long stdoff; 1543 register int year; 1544 register long startoff; 1545 register int startttisstd; 1546 register int startttisgmt; 1547 register int type; 1548 char startbuf[BUFSIZ]; 1549 1550 INITIALIZE(untiltime); 1551 INITIALIZE(starttime); 1552 /* 1553 ** Now. . .finally. . .generate some useful data! 1554 */ 1555 timecnt = 0; 1556 typecnt = 0; 1557 charcnt = 0; 1558 /* 1559 ** A guess that may well be corrected later. 1560 */ 1561 stdoff = 0; 1562 /* 1563 ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au) 1564 ** for noting the need to unconditionally initialize startttisstd. 1565 */ 1566 startttisstd = FALSE; 1567 startttisgmt = FALSE; 1568 for (i = 0; i < zonecount; ++i) { 1569 zp = &zpfirst[i]; 1570 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 1571 useuntil = i < (zonecount - 1); 1572 if (useuntil && zp->z_untiltime <= min_time) 1573 continue; 1574 gmtoff = zp->z_gmtoff; 1575 eat(zp->z_filename, zp->z_linenum); 1576 *startbuf = '\0'; 1577 startoff = zp->z_gmtoff; 1578 if (zp->z_nrules == 0) { 1579 stdoff = zp->z_stdoff; 1580 doabbr(startbuf, zp->z_format, 1581 (char *) NULL, stdoff != 0); 1582 type = addtype(oadd(zp->z_gmtoff, stdoff), 1583 startbuf, stdoff != 0, startttisstd, 1584 startttisgmt); 1585 if (usestart) { 1586 addtt(starttime, type); 1587 usestart = FALSE; 1588 } 1589 else if (stdoff != 0) 1590 addtt(min_time, type); 1591 } else for (year = min_year; year <= max_year; ++year) { 1592 if (useuntil && year > zp->z_untilrule.r_hiyear) 1593 break; 1594 /* 1595 ** Mark which rules to do in the current year. 1596 ** For those to do, calculate rpytime(rp, year); 1597 */ 1598 for (j = 0; j < zp->z_nrules; ++j) { 1599 rp = &zp->z_rules[j]; 1600 eats(zp->z_filename, zp->z_linenum, 1601 rp->r_filename, rp->r_linenum); 1602 rp->r_todo = year >= rp->r_loyear && 1603 year <= rp->r_hiyear && 1604 yearistype(year, rp->r_yrtype); 1605 if (rp->r_todo) 1606 rp->r_temp = rpytime(rp, year); 1607 } 1608 for ( ; ; ) { 1609 register int k; 1610 register time_t jtime, ktime; 1611 register long offset; 1612 char buf[BUFSIZ]; 1613 1614 INITIALIZE(ktime); 1615 if (useuntil) { 1616 /* 1617 ** Turn untiltime into GMT 1618 ** assuming the current gmtoff and 1619 ** stdoff values. 1620 */ 1621 untiltime = zp->z_untiltime; 1622 if (!zp->z_untilrule.r_todisgmt) 1623 untiltime = tadd(untiltime, 1624 -gmtoff); 1625 if (!zp->z_untilrule.r_todisstd) 1626 untiltime = tadd(untiltime, 1627 -stdoff); 1628 } 1629 /* 1630 ** Find the rule (of those to do, if any) 1631 ** that takes effect earliest in the year. 1632 */ 1633 k = -1; 1634 for (j = 0; j < zp->z_nrules; ++j) { 1635 rp = &zp->z_rules[j]; 1636 if (!rp->r_todo) 1637 continue; 1638 eats(zp->z_filename, zp->z_linenum, 1639 rp->r_filename, rp->r_linenum); 1640 offset = rp->r_todisgmt ? 0 : gmtoff; 1641 if (!rp->r_todisstd) 1642 offset = oadd(offset, stdoff); 1643 jtime = rp->r_temp; 1644 if (jtime == min_time || 1645 jtime == max_time) 1646 continue; 1647 jtime = tadd(jtime, -offset); 1648 if (k < 0 || jtime < ktime) { 1649 k = j; 1650 ktime = jtime; 1651 } 1652 } 1653 if (k < 0) 1654 break; /* go on to next year */ 1655 rp = &zp->z_rules[k]; 1656 rp->r_todo = FALSE; 1657 if (useuntil && ktime >= untiltime) 1658 break; 1659 stdoff = rp->r_stdoff; 1660 if (usestart && ktime == starttime) 1661 usestart = FALSE; 1662 if (usestart) { 1663 if (ktime < starttime) { 1664 startoff = oadd(zp->z_gmtoff, 1665 stdoff); 1666 doabbr(startbuf, zp->z_format, 1667 rp->r_abbrvar, 1668 rp->r_stdoff != 0); 1669 continue; 1670 } 1671 if (*startbuf == '\0' && 1672 startoff == oadd(zp->z_gmtoff, 1673 stdoff)) { 1674 doabbr(startbuf, zp->z_format, 1675 rp->r_abbrvar, 1676 rp->r_stdoff != 0); 1677 } 1678 } 1679 eats(zp->z_filename, zp->z_linenum, 1680 rp->r_filename, rp->r_linenum); 1681 doabbr(buf, zp->z_format, rp->r_abbrvar, 1682 rp->r_stdoff != 0); 1683 offset = oadd(zp->z_gmtoff, rp->r_stdoff); 1684 type = addtype(offset, buf, rp->r_stdoff != 0, 1685 rp->r_todisstd, rp->r_todisgmt); 1686 addtt(ktime, type); 1687 } 1688 } 1689 if (usestart) { 1690 if (*startbuf == '\0' && 1691 zp->z_format != NULL && 1692 strchr(zp->z_format, '%') == NULL && 1693 strchr(zp->z_format, '/') == NULL) 1694 (void) strcpy(startbuf, zp->z_format); 1695 eat(zp->z_filename, zp->z_linenum); 1696 if (*startbuf == '\0') 1697error(_("can't determine time zone abbrevation to use just after until time")); 1698 else addtt(starttime, 1699 addtype(startoff, startbuf, 1700 startoff != zp->z_gmtoff, 1701 startttisstd, 1702 startttisgmt)); 1703 } 1704 /* 1705 ** Now we may get to set starttime for the next zone line. 1706 */ 1707 if (useuntil) { 1708 startttisstd = zp->z_untilrule.r_todisstd; 1709 startttisgmt = zp->z_untilrule.r_todisgmt; 1710 starttime = zp->z_untiltime; 1711 if (!startttisstd) 1712 starttime = tadd(starttime, -stdoff); 1713 if (!startttisgmt) 1714 starttime = tadd(starttime, -gmtoff); 1715 } 1716 } 1717 writezone(zpfirst->z_name); 1718} 1719 1720static void 1721addtt(starttime, type) 1722const time_t starttime; 1723const int type; 1724{ 1725 if (timecnt >= TZ_MAX_TIMES) { 1726 error(_("too many transitions?!")); 1727 (void) exit(EXIT_FAILURE); 1728 } 1729 attypes[timecnt].at = starttime; 1730 attypes[timecnt].type = type; 1731 ++timecnt; 1732} 1733 1734static int 1735addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) 1736const long gmtoff; 1737const char * const abbr; 1738const int isdst; 1739const int ttisstd; 1740const int ttisgmt; 1741{ 1742 register int i, j; 1743 1744 if (isdst != TRUE && isdst != FALSE) { 1745 error(_("internal error - addtype called with bad isdst")); 1746 (void) exit(EXIT_FAILURE); 1747 } 1748 if (ttisstd != TRUE && ttisstd != FALSE) { 1749 error(_("internal error - addtype called with bad ttisstd")); 1750 (void) exit(EXIT_FAILURE); 1751 } 1752 if (ttisgmt != TRUE && ttisgmt != FALSE) { 1753 error(_("internal error - addtype called with bad ttisgmt")); 1754 (void) exit(EXIT_FAILURE); 1755 } 1756 /* 1757 ** See if there's already an entry for this zone type. 1758 ** If so, just return its index. 1759 */ 1760 for (i = 0; i < typecnt; ++i) { 1761 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 1762 strcmp(abbr, &chars[abbrinds[i]]) == 0 && 1763 ttisstd == ttisstds[i] && 1764 ttisgmt == ttisgmts[i]) 1765 return i; 1766 } 1767 /* 1768 ** There isn't one; add a new one, unless there are already too 1769 ** many. 1770 */ 1771 if (typecnt >= TZ_MAX_TYPES) { 1772 error(_("too many local time types")); 1773 (void) exit(EXIT_FAILURE); 1774 } 1775 gmtoffs[i] = gmtoff; 1776 isdsts[i] = isdst; 1777 ttisstds[i] = ttisstd; 1778 ttisgmts[i] = ttisgmt; 1779 1780 for (j = 0; j < charcnt; ++j) 1781 if (strcmp(&chars[j], abbr) == 0) 1782 break; 1783 if (j == charcnt) 1784 newabbr(abbr); 1785 abbrinds[i] = j; 1786 ++typecnt; 1787 return i; 1788} 1789 1790static void 1791leapadd(t, positive, rolling, count) 1792const time_t t; 1793const int positive; 1794const int rolling; 1795int count; 1796{ 1797 register int i, j; 1798 1799 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 1800 error(_("too many leap seconds")); 1801 (void) exit(EXIT_FAILURE); 1802 } 1803 for (i = 0; i < leapcnt; ++i) 1804 if (t <= trans[i]) { 1805 if (t == trans[i]) { 1806 error(_("repeated leap second moment")); 1807 (void) exit(EXIT_FAILURE); 1808 } 1809 break; 1810 } 1811 do { 1812 for (j = leapcnt; j > i; --j) { 1813 trans[j] = trans[j - 1]; 1814 corr[j] = corr[j - 1]; 1815 roll[j] = roll[j - 1]; 1816 } 1817 trans[i] = t; 1818 corr[i] = positive ? 1L : eitol(-count); 1819 roll[i] = rolling; 1820 ++leapcnt; 1821 } while (positive && --count != 0); 1822} 1823 1824static void 1825adjleap P((void)) 1826{ 1827 register int i; 1828 register long last = 0; 1829 1830 /* 1831 ** propagate leap seconds forward 1832 */ 1833 for (i = 0; i < leapcnt; ++i) { 1834 trans[i] = tadd(trans[i], last); 1835 last = corr[i] += last; 1836 } 1837} 1838 1839static int 1840yearistype(year, type) 1841const int year; 1842const char * const type; 1843{ 1844 static char * buf; 1845 int result; 1846 1847 if (type == NULL || *type == '\0') 1848 return TRUE; 1849 buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); 1850 (void) sprintf(buf, "%s %d %s", yitcommand, year, type); 1851 result = system(buf); 1852 if (result == 0) 1853 return TRUE; 1854 if (result == (1 << 8)) 1855 return FALSE; 1856 error(_("Wild result from command execution")); 1857 (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"), 1858 progname, buf, result); 1859 for ( ; ; ) 1860 (void) exit(EXIT_FAILURE); 1861} 1862 1863static int 1864lowerit(a) 1865int a; 1866{ 1867 a = (unsigned char) a; 1868 return (isascii(a) && isupper(a)) ? tolower(a) : a; 1869} 1870 1871static int 1872ciequal(ap, bp) /* case-insensitive equality */ 1873register const char * ap; 1874register const char * bp; 1875{ 1876 while (lowerit(*ap) == lowerit(*bp++)) 1877 if (*ap++ == '\0') 1878 return TRUE; 1879 return FALSE; 1880} 1881 1882static int 1883itsabbr(abbr, word) 1884register const char * abbr; 1885register const char * word; 1886{ 1887 if (lowerit(*abbr) != lowerit(*word)) 1888 return FALSE; 1889 ++word; 1890 while (*++abbr != '\0') 1891 do { 1892 if (*word == '\0') 1893 return FALSE; 1894 } while (lowerit(*word++) != lowerit(*abbr)); 1895 return TRUE; 1896} 1897 1898static const struct lookup * 1899byword(word, table) 1900register const char * const word; 1901register const struct lookup * const table; 1902{ 1903 register const struct lookup * foundlp; 1904 register const struct lookup * lp; 1905 1906 if (word == NULL || table == NULL) 1907 return NULL; 1908 /* 1909 ** Look for exact match. 1910 */ 1911 for (lp = table; lp->l_word != NULL; ++lp) 1912 if (ciequal(word, lp->l_word)) 1913 return lp; 1914 /* 1915 ** Look for inexact match. 1916 */ 1917 foundlp = NULL; 1918 for (lp = table; lp->l_word != NULL; ++lp) 1919 if (itsabbr(word, lp->l_word)) 1920 if (foundlp == NULL) 1921 foundlp = lp; 1922 else return NULL; /* multiple inexact matches */ 1923 return foundlp; 1924} 1925 1926static char ** 1927getfields(cp) 1928register char * cp; 1929{ 1930 register char * dp; 1931 register char ** array; 1932 register int nsubs; 1933 1934 if (cp == NULL) 1935 return NULL; 1936 array = (char **) (void *) 1937 emalloc((int) ((strlen(cp) + 1) * sizeof *array)); 1938 nsubs = 0; 1939 for ( ; ; ) { 1940 while (isascii(*cp) && isspace((unsigned char) *cp)) 1941 ++cp; 1942 if (*cp == '\0' || *cp == '#') 1943 break; 1944 array[nsubs++] = dp = cp; 1945 do { 1946 if ((*dp = *cp++) != '"') 1947 ++dp; 1948 else while ((*dp = *cp++) != '"') 1949 if (*dp != '\0') 1950 ++dp; 1951 else error(_("Odd number of quotation marks")); 1952 } while (*cp != '\0' && *cp != '#' && 1953 (!isascii(*cp) || !isspace((unsigned char) *cp))); 1954 if (isascii(*cp) && isspace((unsigned char) *cp)) 1955 ++cp; 1956 *dp = '\0'; 1957 } 1958 array[nsubs] = NULL; 1959 return array; 1960} 1961 1962static long 1963oadd(t1, t2) 1964const long t1; 1965const long t2; 1966{ 1967 register long t; 1968 1969 t = t1 + t2; 1970 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1971 error(_("time overflow")); 1972 (void) exit(EXIT_FAILURE); 1973 } 1974 return t; 1975} 1976 1977static time_t 1978tadd(t1, t2) 1979const time_t t1; 1980const long t2; 1981{ 1982 register time_t t; 1983 1984 if (t1 == max_time && t2 > 0) 1985 return max_time; 1986 if (t1 == min_time && t2 < 0) 1987 return min_time; 1988 t = t1 + t2; 1989 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1990 error(_("time overflow")); 1991 (void) exit(EXIT_FAILURE); 1992 } 1993 return t; 1994} 1995 1996/* 1997** Given a rule, and a year, compute the date - in seconds since January 1, 1998** 1970, 00:00 LOCAL time - in that year that the rule refers to. 1999*/ 2000 2001static time_t 2002rpytime(rp, wantedy) 2003register const struct rule * const rp; 2004register const int wantedy; 2005{ 2006 register int y, m, i; 2007 register long dayoff; /* with a nod to Margaret O. */ 2008 register time_t t; 2009 2010 if (wantedy == INT_MIN) 2011 return min_time; 2012 if (wantedy == INT_MAX) 2013 return max_time; 2014 dayoff = 0; 2015 m = TM_JANUARY; 2016 y = EPOCH_YEAR; 2017 while (wantedy != y) { 2018 if (wantedy > y) { 2019 i = len_years[isleap(y)]; 2020 ++y; 2021 } else { 2022 --y; 2023 i = -len_years[isleap(y)]; 2024 } 2025 dayoff = oadd(dayoff, eitol(i)); 2026 } 2027 while (m != rp->r_month) { 2028 i = len_months[isleap(y)][m]; 2029 dayoff = oadd(dayoff, eitol(i)); 2030 ++m; 2031 } 2032 i = rp->r_dayofmonth; 2033 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 2034 if (rp->r_dycode == DC_DOWLEQ) 2035 --i; 2036 else { 2037 error(_("use of 2/29 in non leap-year")); 2038 (void) exit(EXIT_FAILURE); 2039 } 2040 } 2041 --i; 2042 dayoff = oadd(dayoff, eitol(i)); 2043 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 2044 register long wday; 2045 2046#define LDAYSPERWEEK ((long) DAYSPERWEEK) 2047 wday = eitol(EPOCH_WDAY); 2048 /* 2049 ** Don't trust mod of negative numbers. 2050 */ 2051 if (dayoff >= 0) 2052 wday = (wday + dayoff) % LDAYSPERWEEK; 2053 else { 2054 wday -= ((-dayoff) % LDAYSPERWEEK); 2055 if (wday < 0) 2056 wday += LDAYSPERWEEK; 2057 } 2058 while (wday != eitol(rp->r_wday)) 2059 if (rp->r_dycode == DC_DOWGEQ) { 2060 dayoff = oadd(dayoff, (long) 1); 2061 if (++wday >= LDAYSPERWEEK) 2062 wday = 0; 2063 ++i; 2064 } else { 2065 dayoff = oadd(dayoff, (long) -1); 2066 if (--wday < 0) 2067 wday = LDAYSPERWEEK - 1; 2068 --i; 2069 } 2070 if (i < 0 || i >= len_months[isleap(y)][m]) { 2071 error(_("no day in month matches rule")); 2072 (void) exit(EXIT_FAILURE); 2073 } 2074 } 2075 if (dayoff < 0 && !TYPE_SIGNED(time_t)) 2076 return min_time; 2077 t = (time_t) dayoff * SECSPERDAY; 2078 /* 2079 ** Cheap overflow check. 2080 */ 2081 if (t / SECSPERDAY != dayoff) 2082 return (dayoff > 0) ? max_time : min_time; 2083 return tadd(t, rp->r_tod); 2084} 2085 2086static void 2087newabbr(string) 2088const char * const string; 2089{ 2090 register int i; 2091 2092 i = strlen(string) + 1; 2093 if (charcnt + i > TZ_MAX_CHARS) { 2094 error(_("too many, or too long, time zone abbreviations")); 2095 (void) exit(EXIT_FAILURE); 2096 } 2097 (void) strcpy(&chars[charcnt], string); 2098 charcnt += eitol(i); 2099} 2100 2101static int 2102mkdirs(argname) 2103char * const argname; 2104{ 2105 register char * name; 2106 register char * cp; 2107 2108 if (argname == NULL || *argname == '\0') 2109 return 0; 2110 cp = name = ecpyalloc(argname); 2111 while ((cp = strchr(cp + 1, '/')) != 0) { 2112 *cp = '\0'; 2113#ifndef unix 2114 /* 2115 ** DOS drive specifier? 2116 */ 2117 if (isalpha((unsigned char) name[0]) && 2118 name[1] == ':' && name[2] == '\0') { 2119 *cp = '/'; 2120 continue; 2121 } 2122#endif /* !defined unix */ 2123 if (!itsdir(name)) { 2124 /* 2125 ** It doesn't seem to exist, so we try to create it. 2126 */ 2127 if (mkdir(name, 0755) != 0) { 2128 const char *e = strerror(errno); 2129 (void) fprintf(stderr, 2130 _("%s: Can't create directory %s: %s\n"), 2131 progname, name, e); 2132 ifree(name); 2133 return -1; 2134 } 2135 } 2136 *cp = '/'; 2137 } 2138 ifree(name); 2139 return 0; 2140} 2141 2142static long 2143eitol(i) 2144const int i; 2145{ 2146 long l; 2147 2148 l = i; 2149 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 2150 (void) fprintf(stderr, 2151 _("%s: %d did not sign extend correctly\n"), 2152 progname, i); 2153 (void) exit(EXIT_FAILURE); 2154 } 2155 return l; 2156} 2157 2158/* 2159** UNIX was a registered trademark of UNIX System Laboratories in 1993. 2160*/ 2161