zic.c revision 9937
1145519Sdarrenr#ifndef lint 2145510Sdarrenr#ifndef NOID 353024Sguidostatic char elsieid[] = "@(#)zic.c 7.50"; 453024Sguido#endif /* !defined NOID */ 553024Sguido#endif /* !defined lint */ 653024Sguido 753024Sguido#include "private.h" 853024Sguido#include "tzfile.h" 953024Sguido#include <sys/stat.h> /* for umask manifest constants */ 1053024Sguido#include <sys/types.h> 1153024Sguido#include <unistd.h> 1253024Sguido 1353024Sguidostruct rule { 1453024Sguido const char * r_filename; 1553024Sguido int r_linenum; 1653024Sguido const char * r_name; 1753024Sguido 1853024Sguido int r_loyear; /* for example, 1986 */ 1953024Sguido int r_hiyear; /* for example, 1986 */ 2053024Sguido const char * r_yrtype; 2153024Sguido 2253024Sguido int r_month; /* 0..11 */ 2353024Sguido 2453024Sguido int r_dycode; /* see below */ 2553024Sguido int r_dayofmonth; 2653024Sguido int r_wday; 2753024Sguido 2853024Sguido long r_tod; /* time from midnight */ 2953024Sguido int r_todisstd; /* above is standard time if TRUE */ 3053024Sguido /* or wall clock time if FALSE */ 3153024Sguido int r_todisgmt; /* above is GMT if TRUE */ 3253024Sguido /* or local time if FALSE */ 3353024Sguido long r_stdoff; /* offset from standard time */ 3453024Sguido const char * r_abbrvar; /* variable part of abbreviation */ 3553024Sguido 3653024Sguido int r_todo; /* a rule to do (used in outzone) */ 3753024Sguido time_t r_temp; /* used in outzone */ 3853024Sguido}; 3953024Sguido 4053024Sguido/* 4153024Sguido** r_dycode r_dayofmonth r_wday 4253024Sguido*/ 4353024Sguido 4453024Sguido#define DC_DOM 0 /* 1..31 */ /* unused */ 4553024Sguido#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 4653024Sguido#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 4753024Sguido 4853024Sguidostruct zone { 4953024Sguido const char * z_filename; 5053024Sguido int z_linenum; 5153024Sguido 5253024Sguido const char * z_name; 5353024Sguido long z_gmtoff; 5453024Sguido const char * z_rule; 5553024Sguido const char * z_format; 5653024Sguido 5753024Sguido long z_stdoff; 5853024Sguido 5953024Sguido struct rule * z_rules; 6053024Sguido int z_nrules; 6153024Sguido 6253024Sguido struct rule z_untilrule; 6353024Sguido time_t z_untiltime; 6453024Sguido}; 6553024Sguido 6653024Sguidoextern int getopt P((int argc, char * const argv[], 6753024Sguido const char * options)); 6853024Sguidoextern char * icatalloc P((char * old, const char * new)); 6953024Sguidoextern char * icpyalloc P((const char * string)); 7053024Sguidoextern void ifree P((char * p)); 7153024Sguidoextern char * imalloc P((int n)); 7253024Sguidoextern void * irealloc P((void * old, int n)); 7353024Sguidoextern int link P((const char * fromname, const char * toname)); 7453024Sguidoextern char * optarg; 7553024Sguidoextern int optind; 7653024Sguidoextern char * scheck P((const char * string, const char * format)); 7753024Sguido 7853024Sguidostatic void addtt P((time_t starttime, int type)); 7953024Sguidostatic int addtype P((long gmtoff, const char * abbr, int isdst, 8053024Sguido int ttisstd, int ttisgmt)); 8153024Sguidostatic void leapadd P((time_t t, int positive, int rolling, int count)); 8253024Sguidostatic void adjleap P((void)); 8353024Sguidostatic void associate P((void)); 8453024Sguidostatic int ciequal P((const char * ap, const char * bp)); 8553024Sguidostatic void convert P((long val, char * buf)); 8653024Sguidostatic void dolink P((const char * fromfile, const char * tofile)); 8753024Sguidostatic void doabbr P((char * abbr, const char * format, 8853024Sguido const char * letters, int isdst)); 8953024Sguidostatic void eat P((const char * name, int num)); 9053024Sguidostatic void eats P((const char * name, int num, 9153024Sguido const char * rname, int rnum)); 9253024Sguidostatic long eitol P((int i)); 9353024Sguidostatic void error P((const char * message)); 9453024Sguidostatic char ** getfields P((char * buf)); 9553024Sguidostatic long gethms P((const char * string, const char * errstrng, 9653024Sguido int signable)); 9753024Sguidostatic void infile P((const char * filename)); 9853024Sguidostatic void inleap P((char ** fields, int nfields)); 9953024Sguidostatic void inlink P((char ** fields, int nfields)); 10053024Sguidostatic void inrule P((char ** fields, int nfields)); 10153024Sguidostatic int inzcont P((char ** fields, int nfields)); 10253024Sguidostatic int inzone P((char ** fields, int nfields)); 10353024Sguidostatic int inzsub P((char ** fields, int nfields, int iscont)); 10453024Sguidostatic int itsabbr P((const char * abbr, const char * word)); 10553024Sguidostatic int itsdir P((const char * name)); 10653024Sguidostatic int lowerit P((int c)); 10753024Sguidostatic char * memcheck P((char * tocheck)); 10853024Sguidostatic int mkdirs P((char * filename)); 10953024Sguidostatic void newabbr P((const char * abbr)); 11053024Sguidostatic long oadd P((long t1, long t2)); 11153024Sguidostatic void outzone P((const struct zone * zp, int ntzones)); 11253024Sguidostatic void puttzcode P((long code, FILE * fp)); 11353024Sguidostatic int rcomp P((const void * leftp, const void * rightp)); 11453024Sguidostatic time_t rpytime P((const struct rule * rp, int wantedy)); 11553024Sguidostatic void rulesub P((struct rule * rp, 11653024Sguido const char * loyearp, const char * hiyearp, 11753024Sguido const char * typep, const char * monthp, 11853024Sguido const char * dayp, const char * timep)); 11953024Sguidostatic void setboundaries P((void)); 12053024Sguidostatic time_t tadd P((time_t t1, long t2)); 12153024Sguidostatic void usage P((void)); 12253024Sguidostatic void writezone P((const char * name)); 12353024Sguidostatic int yearistype P((int year, const char * type)); 12453024Sguido 12553024Sguidostatic int charcnt; 12653024Sguidostatic int errors; 12753024Sguidostatic const char * filename; 12853024Sguidostatic int leapcnt; 12953024Sguidostatic int linenum; 13053024Sguidostatic int max_int; 13153024Sguidostatic time_t max_time; 13253024Sguidostatic int max_year; 13353024Sguidostatic int min_int; 13453024Sguidostatic time_t min_time; 13553024Sguidostatic int min_year; 13653024Sguidostatic int noise; 13753024Sguidostatic const char * rfilename; 13853024Sguidostatic int rlinenum; 13953024Sguidostatic const char * progname; 14053024Sguidostatic int timecnt; 14153024Sguidostatic int typecnt; 14253024Sguidostatic int tt_signed; 14353024Sguido 14453024Sguido/* 14553024Sguido** Line codes. 14653024Sguido*/ 14753024Sguido 14853024Sguido#define LC_RULE 0 14953024Sguido#define LC_ZONE 1 15053024Sguido#define LC_LINK 2 15153024Sguido#define LC_LEAP 3 15253024Sguido 15353024Sguido/* 15453024Sguido** Which fields are which on a Zone line. 15553024Sguido*/ 15653024Sguido 15753024Sguido#define ZF_NAME 1 15853024Sguido#define ZF_GMTOFF 2 15953024Sguido#define ZF_RULE 3 16053024Sguido#define ZF_FORMAT 4 16153024Sguido#define ZF_TILYEAR 5 16253024Sguido#define ZF_TILMONTH 6 16353024Sguido#define ZF_TILDAY 7 16453024Sguido#define ZF_TILTIME 8 16553024Sguido#define ZONE_MINFIELDS 5 16653024Sguido#define ZONE_MAXFIELDS 9 16753024Sguido 16853024Sguido/* 16953024Sguido** Which fields are which on a Zone continuation line. 17053024Sguido*/ 17153024Sguido 17253024Sguido#define ZFC_GMTOFF 0 17353024Sguido#define ZFC_RULE 1 17453024Sguido#define ZFC_FORMAT 2 17553024Sguido#define ZFC_TILYEAR 3 17653024Sguido#define ZFC_TILMONTH 4 17753024Sguido#define ZFC_TILDAY 5 17853024Sguido#define ZFC_TILTIME 6 17953024Sguido#define ZONEC_MINFIELDS 3 18053024Sguido#define ZONEC_MAXFIELDS 7 18153024Sguido 18253024Sguido/* 18353024Sguido** Which files are which on a Rule line. 18453024Sguido*/ 18553024Sguido 18653024Sguido#define RF_NAME 1 18753024Sguido#define RF_LOYEAR 2 18853024Sguido#define RF_HIYEAR 3 18953024Sguido#define RF_COMMAND 4 19053024Sguido#define RF_MONTH 5 19153024Sguido#define RF_DAY 6 19253024Sguido#define RF_TOD 7 19353024Sguido#define RF_STDOFF 8 19453024Sguido#define RF_ABBRVAR 9 19553024Sguido#define RULE_FIELDS 10 19653024Sguido 19753024Sguido/* 19853024Sguido** Which fields are which on a Link line. 19953024Sguido*/ 20053024Sguido 20153024Sguido#define LF_FROM 1 20253024Sguido#define LF_TO 2 20353024Sguido#define LINK_FIELDS 3 20453024Sguido 20553024Sguido/* 20653024Sguido** Which fields are which on a Leap line. 20753024Sguido*/ 20853024Sguido 20953024Sguido#define LP_YEAR 1 21053024Sguido#define LP_MONTH 2 21153024Sguido#define LP_DAY 3 21253024Sguido#define LP_TIME 4 21353024Sguido#define LP_CORR 5 21453024Sguido#define LP_ROLL 6 21553024Sguido#define LEAP_FIELDS 7 21653024Sguido 21753024Sguido/* 21853024Sguido** Year synonyms. 21953024Sguido*/ 22053024Sguido 22153024Sguido#define YR_MINIMUM 0 22253024Sguido#define YR_MAXIMUM 1 22353024Sguido#define YR_ONLY 2 22453024Sguido 22553024Sguidostatic struct rule * rules; 22653024Sguidostatic int nrules; /* number of rules */ 22753024Sguido 22853024Sguidostatic struct zone * zones; 22953024Sguidostatic int nzones; /* number of zones */ 23053024Sguido 23153024Sguidostruct link { 23253024Sguido const char * l_filename; 23353024Sguido int l_linenum; 23453024Sguido const char * l_from; 23553024Sguido const char * l_to; 23653024Sguido}; 23753024Sguido 23853024Sguidostatic struct link * links; 23953024Sguidostatic int nlinks; 24053024Sguido 24153024Sguidostruct lookup { 24253024Sguido const char * l_word; 24353024Sguido const int l_value; 24453024Sguido}; 245 246static struct lookup const * byword P((const char * string, 247 const struct lookup * lp)); 248 249static struct lookup const line_codes[] = { 250 { "Rule", LC_RULE }, 251 { "Zone", LC_ZONE }, 252 { "Link", LC_LINK }, 253 { "Leap", LC_LEAP }, 254 { NULL, 0} 255}; 256 257static struct lookup const mon_names[] = { 258 { "January", TM_JANUARY }, 259 { "February", TM_FEBRUARY }, 260 { "March", TM_MARCH }, 261 { "April", TM_APRIL }, 262 { "May", TM_MAY }, 263 { "June", TM_JUNE }, 264 { "July", TM_JULY }, 265 { "August", TM_AUGUST }, 266 { "September", TM_SEPTEMBER }, 267 { "October", TM_OCTOBER }, 268 { "November", TM_NOVEMBER }, 269 { "December", TM_DECEMBER }, 270 { NULL, 0 } 271}; 272 273static struct lookup const wday_names[] = { 274 { "Sunday", TM_SUNDAY }, 275 { "Monday", TM_MONDAY }, 276 { "Tuesday", TM_TUESDAY }, 277 { "Wednesday", TM_WEDNESDAY }, 278 { "Thursday", TM_THURSDAY }, 279 { "Friday", TM_FRIDAY }, 280 { "Saturday", TM_SATURDAY }, 281 { NULL, 0 } 282}; 283 284static struct lookup const lasts[] = { 285 { "last-Sunday", TM_SUNDAY }, 286 { "last-Monday", TM_MONDAY }, 287 { "last-Tuesday", TM_TUESDAY }, 288 { "last-Wednesday", TM_WEDNESDAY }, 289 { "last-Thursday", TM_THURSDAY }, 290 { "last-Friday", TM_FRIDAY }, 291 { "last-Saturday", TM_SATURDAY }, 292 { NULL, 0 } 293}; 294 295static struct lookup const begin_years[] = { 296 { "minimum", YR_MINIMUM }, 297 { "maximum", YR_MAXIMUM }, 298 { NULL, 0 } 299}; 300 301static struct lookup const end_years[] = { 302 { "minimum", YR_MINIMUM }, 303 { "maximum", YR_MAXIMUM }, 304 { "only", YR_ONLY }, 305 { NULL, 0 } 306}; 307 308static struct lookup const leap_types[] = { 309 { "Rolling", TRUE }, 310 { "Stationary", FALSE }, 311 { NULL, 0 } 312}; 313 314static const int len_months[2][MONSPERYEAR] = { 315 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 316 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 317}; 318 319static const int len_years[2] = { 320 DAYSPERNYEAR, DAYSPERLYEAR 321}; 322 323static time_t ats[TZ_MAX_TIMES]; 324static unsigned char types[TZ_MAX_TIMES]; 325static long gmtoffs[TZ_MAX_TYPES]; 326static char isdsts[TZ_MAX_TYPES]; 327static unsigned char abbrinds[TZ_MAX_TYPES]; 328static char ttisstds[TZ_MAX_TYPES]; 329static char ttisgmts[TZ_MAX_TYPES]; 330static char chars[TZ_MAX_CHARS]; 331static time_t trans[TZ_MAX_LEAPS]; 332static long corr[TZ_MAX_LEAPS]; 333static char roll[TZ_MAX_LEAPS]; 334 335/* 336** Memory allocation. 337*/ 338 339static char * 340memcheck(ptr) 341char * const ptr; 342{ 343 if (ptr == NULL) { 344 (void) perror(progname); 345 (void) exit(EXIT_FAILURE); 346 } 347 return ptr; 348} 349 350#define emalloc(size) memcheck(imalloc(size)) 351#define erealloc(ptr, size) memcheck(irealloc((ptr), (size))) 352#define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 353#define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) 354 355/* 356** Error handling. 357*/ 358 359static void 360eats(name, num, rname, rnum) 361const char * const name; 362const int num; 363const char * const rname; 364const int rnum; 365{ 366 filename = name; 367 linenum = num; 368 rfilename = rname; 369 rlinenum = rnum; 370} 371 372static void 373eat(name, num) 374const char * const name; 375const int num; 376{ 377 eats(name, num, (char *) NULL, -1); 378} 379 380static void 381error(string) 382const char * const string; 383{ 384 /* 385 ** Match the format of "cc" to allow sh users to 386 ** zic ... 2>&1 | error -t "*" -v 387 ** on BSD systems. 388 */ 389 (void) fprintf(stderr, "\"%s\", line %d: %s", 390 filename, linenum, string); 391 if (rfilename != NULL) 392 (void) fprintf(stderr, " (rule from \"%s\", line %d)", 393 rfilename, rlinenum); 394 (void) fprintf(stderr, "\n"); 395 ++errors; 396} 397 398static void 399usage P((void)) 400{ 401 (void) fprintf(stderr, "%s: usage is %s \ 402[ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\ 403\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n", 404 progname, progname); 405 (void) exit(EXIT_FAILURE); 406} 407 408static const char * psxrules; 409static const char * lcltime; 410static const char * directory; 411static const char * leapsec; 412static const char * yitcommand; 413static int sflag = FALSE; 414 415int 416main(argc, argv) 417int argc; 418char * argv[]; 419{ 420 register int i; 421 register int j; 422 register int c; 423 424#ifdef unix 425 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 426#endif /* defined unix */ 427 progname = argv[0]; 428 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF) 429 switch (c) { 430 default: 431 usage(); 432 case 'd': 433 if (directory == NULL) 434 directory = optarg; 435 else { 436 (void) fprintf(stderr, 437"%s: More than one -d option specified\n", 438 progname); 439 (void) exit(EXIT_FAILURE); 440 } 441 break; 442 case 'l': 443 if (lcltime == NULL) 444 lcltime = optarg; 445 else { 446 (void) fprintf(stderr, 447"%s: More than one -l option specified\n", 448 progname); 449 (void) exit(EXIT_FAILURE); 450 } 451 break; 452 case 'p': 453 if (psxrules == NULL) 454 psxrules = optarg; 455 else { 456 (void) fprintf(stderr, 457"%s: More than one -p option specified\n", 458 progname); 459 (void) exit(EXIT_FAILURE); 460 } 461 break; 462 case 'y': 463 if (yitcommand == NULL) 464 yitcommand = optarg; 465 else { 466 (void) fprintf(stderr, 467"%s: More than one -y option specified\n", 468 progname); 469 (void) exit(EXIT_FAILURE); 470 } 471 break; 472 case 'L': 473 if (leapsec == NULL) 474 leapsec = optarg; 475 else { 476 (void) fprintf(stderr, 477"%s: More than one -L option specified\n", 478 progname); 479 (void) exit(EXIT_FAILURE); 480 } 481 break; 482 case 'v': 483 noise = TRUE; 484 break; 485 case 's': 486 sflag = TRUE; 487 break; 488 } 489 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 490 usage(); /* usage message by request */ 491 if (directory == NULL) 492 directory = TZDIR; 493 if (yitcommand == NULL) 494 yitcommand = "yearistype"; 495 496 setboundaries(); 497 498 if (optind < argc && leapsec != NULL) { 499 infile(leapsec); 500 adjleap(); 501 } 502 503 for (i = optind; i < argc; ++i) 504 infile(argv[i]); 505 if (errors) 506 (void) exit(EXIT_FAILURE); 507 associate(); 508 for (i = 0; i < nzones; i = j) { 509 /* 510 ** Find the next non-continuation zone entry. 511 */ 512 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 513 continue; 514 outzone(&zones[i], j - i); 515 } 516 /* 517 ** Make links. 518 */ 519 for (i = 0; i < nlinks; ++i) 520 dolink(links[i].l_from, links[i].l_to); 521 if (lcltime != NULL) 522 dolink(lcltime, TZDEFAULT); 523 if (psxrules != NULL) 524 dolink(psxrules, TZDEFRULES); 525 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 526} 527 528static void 529dolink(fromfile, tofile) 530const char * const fromfile; 531const char * const tofile; 532{ 533 register char * fromname; 534 register char * toname; 535 536 if (fromfile[0] == '/') 537 fromname = ecpyalloc(fromfile); 538 else { 539 fromname = ecpyalloc(directory); 540 fromname = ecatalloc(fromname, "/"); 541 fromname = ecatalloc(fromname, fromfile); 542 } 543 if (tofile[0] == '/') 544 toname = ecpyalloc(tofile); 545 else { 546 toname = ecpyalloc(directory); 547 toname = ecatalloc(toname, "/"); 548 toname = ecatalloc(toname, tofile); 549 } 550 /* 551 ** We get to be careful here since 552 ** there's a fair chance of root running us. 553 */ 554 if (!itsdir(toname)) 555 (void) remove(toname); 556 if (link(fromname, toname) != 0) { 557 if (mkdirs(toname) != 0) 558 (void) exit(EXIT_FAILURE); 559 if (link(fromname, toname) != 0) { 560 (void) fprintf(stderr, "%s: Can't link from %s to ", 561 progname, fromname); 562 (void) perror(toname); 563 (void) exit(EXIT_FAILURE); 564 } 565 } 566 ifree(fromname); 567 ifree(toname); 568} 569 570static void 571setboundaries P((void)) 572{ 573 register time_t bit; 574 register int bii; 575 576 for (bit = 1; bit > 0; bit <<= 1) 577 continue; 578 if (bit == 0) { /* time_t is an unsigned type */ 579 tt_signed = FALSE; 580 min_time = 0; 581 max_time = ~(time_t) 0; 582 if (sflag) 583 max_time >>= 1; 584 } else { 585 tt_signed = TRUE; 586 min_time = bit; 587 max_time = bit; 588 ++max_time; 589 max_time = -max_time; 590 if (sflag) 591 min_time = 0; 592 } 593 min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; 594 max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; 595 596 for (bii = 1; bii > 0; bii <<= 1) 597 continue; 598 min_int = bii; 599 max_int = -1 - bii; 600} 601 602static int 603itsdir(name) 604const char * const name; 605{ 606 register char * myname; 607 register int accres; 608 609 myname = ecpyalloc(name); 610 myname = ecatalloc(myname, "/."); 611 accres = access(myname, F_OK); 612 ifree(myname); 613 return accres == 0; 614} 615 616/* 617** Associate sets of rules with zones. 618*/ 619 620/* 621** Sort by rule name. 622*/ 623 624static int 625rcomp(cp1, cp2) 626const void * cp1; 627const void * cp2; 628{ 629 return strcmp(((const struct rule *) cp1)->r_name, 630 ((const struct rule *) cp2)->r_name); 631} 632 633static void 634associate P((void)) 635{ 636 register struct zone * zp; 637 register struct rule * rp; 638 register int base, out; 639 register int i; 640 641 if (nrules != 0) 642 (void) qsort((void *) rules, (size_t) nrules, 643 (size_t) sizeof *rules, rcomp); 644 for (i = 0; i < nzones; ++i) { 645 zp = &zones[i]; 646 zp->z_rules = NULL; 647 zp->z_nrules = 0; 648 } 649 for (base = 0; base < nrules; base = out) { 650 rp = &rules[base]; 651 for (out = base + 1; out < nrules; ++out) 652 if (strcmp(rp->r_name, rules[out].r_name) != 0) 653 break; 654 for (i = 0; i < nzones; ++i) { 655 zp = &zones[i]; 656 if (strcmp(zp->z_rule, rp->r_name) != 0) 657 continue; 658 zp->z_rules = rp; 659 zp->z_nrules = out - base; 660 } 661 } 662 for (i = 0; i < nzones; ++i) { 663 zp = &zones[i]; 664 if (zp->z_nrules == 0) { 665 /* 666 ** Maybe we have a local standard time offset. 667 */ 668 eat(zp->z_filename, zp->z_linenum); 669 zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE); 670 /* 671 ** Note, though, that if there's no rule, 672 ** a '%s' in the format is a bad thing. 673 */ 674 if (strchr(zp->z_format, '%') != 0) 675 error("%s in ruleless zone"); 676 } 677 } 678 if (errors) 679 (void) exit(EXIT_FAILURE); 680} 681 682static void 683infile(name) 684const char * name; 685{ 686 register FILE * fp; 687 register char ** fields; 688 register char * cp; 689 register const struct lookup * lp; 690 register int nfields; 691 register int wantcont; 692 register int num; 693 char buf[BUFSIZ]; 694 695 if (strcmp(name, "-") == 0) { 696 name = "standard input"; 697 fp = stdin; 698 } else if ((fp = fopen(name, "r")) == NULL) { 699 (void) fprintf(stderr, "%s: Can't open ", progname); 700 (void) perror(name); 701 (void) exit(EXIT_FAILURE); 702 } 703 wantcont = FALSE; 704 for (num = 1; ; ++num) { 705 eat(name, num); 706 if (fgets(buf, (int) sizeof buf, fp) != buf) 707 break; 708 cp = strchr(buf, '\n'); 709 if (cp == NULL) { 710 error("line too long"); 711 (void) exit(EXIT_FAILURE); 712 } 713 *cp = '\0'; 714 fields = getfields(buf); 715 nfields = 0; 716 while (fields[nfields] != NULL) { 717 static char nada; 718 719 if (ciequal(fields[nfields], "-")) 720 fields[nfields] = &nada; 721 ++nfields; 722 } 723 if (nfields == 0) { 724 /* nothing to do */ 725 } else if (wantcont) { 726 wantcont = inzcont(fields, nfields); 727 } else { 728 lp = byword(fields[0], line_codes); 729 if (lp == NULL) 730 error("input line of unknown type"); 731 else switch ((int) (lp->l_value)) { 732 case LC_RULE: 733 inrule(fields, nfields); 734 wantcont = FALSE; 735 break; 736 case LC_ZONE: 737 wantcont = inzone(fields, nfields); 738 break; 739 case LC_LINK: 740 inlink(fields, nfields); 741 wantcont = FALSE; 742 break; 743 case LC_LEAP: 744 if (name != leapsec) 745 (void) fprintf(stderr, 746"%s: Leap line in non leap seconds file %s\n", 747 progname, name); 748 else inleap(fields, nfields); 749 wantcont = FALSE; 750 break; 751 default: /* "cannot happen" */ 752 (void) fprintf(stderr, 753"%s: panic: Invalid l_value %d\n", 754 progname, lp->l_value); 755 (void) exit(EXIT_FAILURE); 756 } 757 } 758 ifree((char *) fields); 759 } 760 if (ferror(fp)) { 761 (void) fprintf(stderr, "%s: Error reading ", progname); 762 (void) perror(filename); 763 (void) exit(EXIT_FAILURE); 764 } 765 if (fp != stdin && fclose(fp)) { 766 (void) fprintf(stderr, "%s: Error closing ", progname); 767 (void) perror(filename); 768 (void) exit(EXIT_FAILURE); 769 } 770 if (wantcont) 771 error("expected continuation line not found"); 772} 773 774/* 775** Convert a string of one of the forms 776** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 777** into a number of seconds. 778** A null string maps to zero. 779** Call error with errstring and return zero on errors. 780*/ 781 782static long 783gethms(string, errstring, signable) 784const char * string; 785const char * const errstring; 786const int signable; 787{ 788 int hh, mm, ss, sign; 789 790 if (string == NULL || *string == '\0') 791 return 0; 792 if (!signable) 793 sign = 1; 794 else if (*string == '-') { 795 sign = -1; 796 ++string; 797 } else sign = 1; 798 if (sscanf(string, scheck(string, "%d"), &hh) == 1) 799 mm = ss = 0; 800 else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) 801 ss = 0; 802 else if (sscanf(string, scheck(string, "%d:%d:%d"), 803 &hh, &mm, &ss) != 3) { 804 error(errstring); 805 return 0; 806 } 807 if (hh < 0 || hh >= HOURSPERDAY || 808 mm < 0 || mm >= MINSPERHOUR || 809 ss < 0 || ss > SECSPERMIN) { 810 error(errstring); 811 return 0; 812 } 813 return eitol(sign) * 814 (eitol(hh * MINSPERHOUR + mm) * 815 eitol(SECSPERMIN) + eitol(ss)); 816} 817 818static void 819inrule(fields, nfields) 820register char ** const fields; 821const int nfields; 822{ 823 static struct rule r; 824 825 if (nfields != RULE_FIELDS) { 826 error("wrong number of fields on Rule line"); 827 return; 828 } 829 if (*fields[RF_NAME] == '\0') { 830 error("nameless rule"); 831 return; 832 } 833 r.r_filename = filename; 834 r.r_linenum = linenum; 835 r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); 836 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 837 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 838 r.r_name = ecpyalloc(fields[RF_NAME]); 839 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 840 rules = (struct rule *) (void *) erealloc((char *) rules, 841 (int) ((nrules + 1) * sizeof *rules)); 842 rules[nrules++] = r; 843} 844 845static int 846inzone(fields, nfields) 847register char ** const fields; 848const int nfields; 849{ 850 register int i; 851 static char * buf; 852 853 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 854 error("wrong number of fields on Zone line"); 855 return FALSE; 856 } 857 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 858 buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT))); 859 (void) sprintf(buf, 860"\"Zone %s\" line and -l option are mutually exclusive", 861 TZDEFAULT); 862 error(buf); 863 return FALSE; 864 } 865 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 866 buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES))); 867 (void) sprintf(buf, 868"\"Zone %s\" line and -p option are mutually exclusive", 869 TZDEFRULES); 870 error(buf); 871 return FALSE; 872 } 873 for (i = 0; i < nzones; ++i) 874 if (zones[i].z_name != NULL && 875 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 876 buf = erealloc(buf, (int) (132 + 877 strlen(fields[ZF_NAME]) + 878 strlen(zones[i].z_filename))); 879 (void) sprintf(buf, 880"duplicate zone name %s (file \"%s\", line %d)", 881 fields[ZF_NAME], 882 zones[i].z_filename, 883 zones[i].z_linenum); 884 error(buf); 885 return FALSE; 886 } 887 return inzsub(fields, nfields, FALSE); 888} 889 890static int 891inzcont(fields, nfields) 892register char ** const fields; 893const int nfields; 894{ 895 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 896 error("wrong number of fields on Zone continuation line"); 897 return FALSE; 898 } 899 return inzsub(fields, nfields, TRUE); 900} 901 902static int 903inzsub(fields, nfields, iscont) 904register char ** const fields; 905const int nfields; 906const int iscont; 907{ 908 register char * cp; 909 static struct zone z; 910 register int i_gmtoff, i_rule, i_format; 911 register int i_untilyear, i_untilmonth; 912 register int i_untilday, i_untiltime; 913 register int hasuntil; 914 915 if (iscont) { 916 i_gmtoff = ZFC_GMTOFF; 917 i_rule = ZFC_RULE; 918 i_format = ZFC_FORMAT; 919 i_untilyear = ZFC_TILYEAR; 920 i_untilmonth = ZFC_TILMONTH; 921 i_untilday = ZFC_TILDAY; 922 i_untiltime = ZFC_TILTIME; 923 z.z_name = NULL; 924 } else { 925 i_gmtoff = ZF_GMTOFF; 926 i_rule = ZF_RULE; 927 i_format = ZF_FORMAT; 928 i_untilyear = ZF_TILYEAR; 929 i_untilmonth = ZF_TILMONTH; 930 i_untilday = ZF_TILDAY; 931 i_untiltime = ZF_TILTIME; 932 z.z_name = ecpyalloc(fields[ZF_NAME]); 933 } 934 z.z_filename = filename; 935 z.z_linenum = linenum; 936 z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE); 937 if ((cp = strchr(fields[i_format], '%')) != 0) { 938 if (*++cp != 's' || strchr(cp, '%') != 0) { 939 error("invalid abbreviation format"); 940 return FALSE; 941 } 942 } 943 z.z_rule = ecpyalloc(fields[i_rule]); 944 z.z_format = ecpyalloc(fields[i_format]); 945 hasuntil = nfields > i_untilyear; 946 if (hasuntil) { 947 z.z_untilrule.r_filename = filename; 948 z.z_untilrule.r_linenum = linenum; 949 rulesub(&z.z_untilrule, 950 fields[i_untilyear], 951 "only", 952 "", 953 (nfields > i_untilmonth) ? 954 fields[i_untilmonth] : "Jan", 955 (nfields > i_untilday) ? fields[i_untilday] : "1", 956 (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 957 z.z_untiltime = rpytime(&z.z_untilrule, 958 z.z_untilrule.r_loyear); 959 if (iscont && nzones > 0 && 960 z.z_untiltime > min_time && 961 z.z_untiltime < max_time && 962 zones[nzones - 1].z_untiltime > min_time && 963 zones[nzones - 1].z_untiltime < max_time && 964 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 965 error("Zone continuation line end time is not \ 966after end time of previous line"); 967 return FALSE; 968 } 969 } 970 zones = (struct zone *) (void *) erealloc((char *) zones, 971 (int) ((nzones + 1) * sizeof *zones)); 972 zones[nzones++] = z; 973 /* 974 ** If there was an UNTIL field on this line, 975 ** there's more information about the zone on the next line. 976 */ 977 return hasuntil; 978} 979 980static void 981inleap(fields, nfields) 982register char ** const fields; 983const int nfields; 984{ 985 register const char * cp; 986 register const struct lookup * lp; 987 register int i, j; 988 int year, month, day; 989 long dayoff, tod; 990 time_t t; 991 992 if (nfields != LEAP_FIELDS) { 993 error("wrong number of fields on Leap line"); 994 return; 995 } 996 dayoff = 0; 997 cp = fields[LP_YEAR]; 998 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 999 /* 1000 * Leapin' Lizards! 1001 */ 1002 error("invalid leaping year"); 1003 return; 1004 } 1005 j = EPOCH_YEAR; 1006 while (j != year) { 1007 if (year > j) { 1008 i = len_years[isleap(j)]; 1009 ++j; 1010 } else { 1011 --j; 1012 i = -len_years[isleap(j)]; 1013 } 1014 dayoff = oadd(dayoff, eitol(i)); 1015 } 1016 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1017 error("invalid month name"); 1018 return; 1019 } 1020 month = lp->l_value; 1021 j = TM_JANUARY; 1022 while (j != month) { 1023 i = len_months[isleap(year)][j]; 1024 dayoff = oadd(dayoff, eitol(i)); 1025 ++j; 1026 } 1027 cp = fields[LP_DAY]; 1028 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 1029 day <= 0 || day > len_months[isleap(year)][month]) { 1030 error("invalid day of month"); 1031 return; 1032 } 1033 dayoff = oadd(dayoff, eitol(day - 1)); 1034 if (dayoff < 0 && !tt_signed) { 1035 error("time before zero"); 1036 return; 1037 } 1038 t = (time_t) dayoff * SECSPERDAY; 1039 /* 1040 ** Cheap overflow check. 1041 */ 1042 if (t / SECSPERDAY != dayoff) { 1043 error("time overflow"); 1044 return; 1045 } 1046 tod = gethms(fields[LP_TIME], "invalid time of day", FALSE); 1047 cp = fields[LP_CORR]; 1048 { 1049 register int positive; 1050 int count; 1051 1052 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 1053 positive = FALSE; 1054 count = 1; 1055 } else if (strcmp(cp, "--") == 0) { 1056 positive = FALSE; 1057 count = 2; 1058 } else if (strcmp(cp, "+") == 0) { 1059 positive = TRUE; 1060 count = 1; 1061 } else if (strcmp(cp, "++") == 0) { 1062 positive = TRUE; 1063 count = 2; 1064 } else { 1065 error("illegal CORRECTION field on Leap line"); 1066 return; 1067 } 1068 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1069 error("illegal Rolling/Stationary field on Leap line"); 1070 return; 1071 } 1072 leapadd(tadd(t, tod), positive, lp->l_value, count); 1073 } 1074} 1075 1076static void 1077inlink(fields, nfields) 1078register char ** const fields; 1079const int nfields; 1080{ 1081 struct link l; 1082 1083 if (nfields != LINK_FIELDS) { 1084 error("wrong number of fields on Link line"); 1085 return; 1086 } 1087 if (*fields[LF_FROM] == '\0') { 1088 error("blank FROM field on Link line"); 1089 return; 1090 } 1091 if (*fields[LF_TO] == '\0') { 1092 error("blank TO field on Link line"); 1093 return; 1094 } 1095 l.l_filename = filename; 1096 l.l_linenum = linenum; 1097 l.l_from = ecpyalloc(fields[LF_FROM]); 1098 l.l_to = ecpyalloc(fields[LF_TO]); 1099 links = (struct link *) (void *) erealloc((char *) links, 1100 (int) ((nlinks + 1) * sizeof *links)); 1101 links[nlinks++] = l; 1102} 1103 1104static void 1105rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 1106register struct rule * const rp; 1107const char * const loyearp; 1108const char * const hiyearp; 1109const char * const typep; 1110const char * const monthp; 1111const char * const dayp; 1112const char * const timep; 1113{ 1114 register const struct lookup * lp; 1115 register const char * cp; 1116 register char * dp; 1117 register char * ep; 1118 1119 if ((lp = byword(monthp, mon_names)) == NULL) { 1120 error("invalid month name"); 1121 return; 1122 } 1123 rp->r_month = lp->l_value; 1124 rp->r_todisstd = FALSE; 1125 rp->r_todisgmt = FALSE; 1126 dp = ecpyalloc(timep); 1127 if (*dp != '\0') { 1128 ep = dp + strlen(dp) - 1; 1129 switch (lowerit(*ep)) { 1130 case 's': /* Standard */ 1131 rp->r_todisstd = TRUE; 1132 rp->r_todisgmt = FALSE; 1133 *ep = '\0'; 1134 break; 1135 case 'w': /* Wall */ 1136 rp->r_todisstd = FALSE; 1137 rp->r_todisgmt = FALSE; 1138 *ep = '\0'; 1139 case 'g': /* Greenwich */ 1140 case 'u': /* Universal */ 1141 case 'z': /* Zulu */ 1142 rp->r_todisstd = TRUE; 1143 rp->r_todisgmt = TRUE; 1144 *ep = '\0'; 1145 break; 1146 } 1147 } 1148 rp->r_tod = gethms(dp, "invalid time of day", FALSE); 1149 ifree(dp); 1150 /* 1151 ** Year work. 1152 */ 1153 cp = loyearp; 1154 lp = byword(cp, begin_years); 1155 if (lp != NULL) switch ((int) lp->l_value) { 1156 case YR_MINIMUM: 1157 rp->r_loyear = min_int; 1158 break; 1159 case YR_MAXIMUM: 1160 rp->r_loyear = max_int; 1161 break; 1162 default: /* "cannot happen" */ 1163 (void) fprintf(stderr, 1164 "%s: panic: Invalid l_value %d\n", 1165 progname, lp->l_value); 1166 (void) exit(EXIT_FAILURE); 1167 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 1168 error("invalid starting year"); 1169 return; 1170 } 1171 cp = hiyearp; 1172 if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) { 1173 case YR_MINIMUM: 1174 rp->r_hiyear = min_int; 1175 break; 1176 case YR_MAXIMUM: 1177 rp->r_hiyear = max_int; 1178 break; 1179 case YR_ONLY: 1180 rp->r_hiyear = rp->r_loyear; 1181 break; 1182 default: /* "cannot happen" */ 1183 (void) fprintf(stderr, 1184 "%s: panic: Invalid l_value %d\n", 1185 progname, lp->l_value); 1186 (void) exit(EXIT_FAILURE); 1187 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 1188 error("invalid ending year"); 1189 return; 1190 } 1191 if (rp->r_loyear > rp->r_hiyear) { 1192 error("starting year greater than ending year"); 1193 return; 1194 } 1195 if (*typep == '\0') 1196 rp->r_yrtype = NULL; 1197 else { 1198 if (rp->r_loyear == rp->r_hiyear) { 1199 error("typed single year"); 1200 return; 1201 } 1202 rp->r_yrtype = ecpyalloc(typep); 1203 } 1204 /* 1205 ** Day work. 1206 ** Accept things such as: 1207 ** 1 1208 ** last-Sunday 1209 ** Sun<=20 1210 ** Sun>=7 1211 */ 1212 dp = ecpyalloc(dayp); 1213 if ((lp = byword(dp, lasts)) != NULL) { 1214 rp->r_dycode = DC_DOWLEQ; 1215 rp->r_wday = lp->l_value; 1216 rp->r_dayofmonth = len_months[1][rp->r_month]; 1217 } else { 1218 if ((ep = strchr(dp, '<')) != 0) 1219 rp->r_dycode = DC_DOWLEQ; 1220 else if ((ep = strchr(dp, '>')) != 0) 1221 rp->r_dycode = DC_DOWGEQ; 1222 else { 1223 ep = dp; 1224 rp->r_dycode = DC_DOM; 1225 } 1226 if (rp->r_dycode != DC_DOM) { 1227 *ep++ = 0; 1228 if (*ep++ != '=') { 1229 error("invalid day of month"); 1230 ifree(dp); 1231 return; 1232 } 1233 if ((lp = byword(dp, wday_names)) == NULL) { 1234 error("invalid weekday name"); 1235 ifree(dp); 1236 return; 1237 } 1238 rp->r_wday = lp->l_value; 1239 } 1240 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || 1241 rp->r_dayofmonth <= 0 || 1242 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1243 error("invalid day of month"); 1244 ifree(dp); 1245 return; 1246 } 1247 } 1248 ifree(dp); 1249} 1250 1251static void 1252convert(val, buf) 1253const long val; 1254char * const buf; 1255{ 1256 register int i; 1257 register long shift; 1258 1259 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1260 buf[i] = val >> shift; 1261} 1262 1263static void 1264puttzcode(val, fp) 1265const long val; 1266FILE * const fp; 1267{ 1268 char buf[4]; 1269 1270 convert(val, buf); 1271 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); 1272} 1273 1274static void 1275writezone(name) 1276const char * const name; 1277{ 1278 register FILE * fp; 1279 register int i, j; 1280 static char * fullname; 1281 static struct tzhead tzh; 1282 1283 fullname = erealloc(fullname, 1284 (int) (strlen(directory) + 1 + strlen(name) + 1)); 1285 (void) sprintf(fullname, "%s/%s", directory, name); 1286 if ((fp = fopen(fullname, "wb")) == NULL) { 1287 if (mkdirs(fullname) != 0) 1288 (void) exit(EXIT_FAILURE); 1289 if ((fp = fopen(fullname, "wb")) == NULL) { 1290 (void) fprintf(stderr, "%s: Can't create ", progname); 1291 (void) perror(fullname); 1292 (void) exit(EXIT_FAILURE); 1293 } 1294 } 1295 convert(eitol(typecnt), tzh.tzh_ttisgmtcnt); 1296 convert(eitol(typecnt), tzh.tzh_ttisstdcnt); 1297 convert(eitol(leapcnt), tzh.tzh_leapcnt); 1298 convert(eitol(timecnt), tzh.tzh_timecnt); 1299 convert(eitol(typecnt), tzh.tzh_typecnt); 1300 convert(eitol(charcnt), tzh.tzh_charcnt); 1301#define DO(field) (void) fwrite((void *) tzh.field, \ 1302 (size_t) sizeof tzh.field, (size_t) 1, fp) 1303 DO(tzh_reserved); 1304 DO(tzh_ttisgmtcnt); 1305 DO(tzh_ttisstdcnt); 1306 DO(tzh_leapcnt); 1307 DO(tzh_timecnt); 1308 DO(tzh_typecnt); 1309 DO(tzh_charcnt); 1310#undef DO 1311 for (i = 0; i < timecnt; ++i) { 1312 j = leapcnt; 1313 while (--j >= 0) 1314 if (ats[i] >= trans[j]) { 1315 ats[i] = tadd(ats[i], corr[j]); 1316 break; 1317 } 1318 puttzcode((long) ats[i], fp); 1319 } 1320 if (timecnt > 0) 1321 (void) fwrite((void *) types, (size_t) sizeof types[0], 1322 (size_t) timecnt, fp); 1323 for (i = 0; i < typecnt; ++i) { 1324 puttzcode((long) gmtoffs[i], fp); 1325 (void) putc(isdsts[i], fp); 1326 (void) putc(abbrinds[i], fp); 1327 } 1328 if (charcnt != 0) 1329 (void) fwrite((void *) chars, (size_t) sizeof chars[0], 1330 (size_t) charcnt, fp); 1331 for (i = 0; i < leapcnt; ++i) { 1332 if (roll[i]) { 1333 if (timecnt == 0 || trans[i] < ats[0]) { 1334 j = 0; 1335 while (isdsts[j]) 1336 if (++j >= typecnt) { 1337 j = 0; 1338 break; 1339 } 1340 } else { 1341 j = 1; 1342 while (j < timecnt && trans[i] >= ats[j]) 1343 ++j; 1344 j = types[j - 1]; 1345 } 1346 puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp); 1347 } else puttzcode((long) trans[i], fp); 1348 puttzcode((long) corr[i], fp); 1349 } 1350 for (i = 0; i < typecnt; ++i) 1351 (void) putc(ttisstds[i], fp); 1352 for (i = 0; i < typecnt; ++i) 1353 (void) putc(ttisgmts[i], fp); 1354 if (ferror(fp) || fclose(fp)) { 1355 (void) fprintf(stderr, "%s: Write error on ", progname); 1356 (void) perror(fullname); 1357 (void) exit(EXIT_FAILURE); 1358 } 1359} 1360 1361static void 1362doabbr(abbr, format, letters, isdst) 1363char * const abbr; 1364const char * const format; 1365const char * const letters; 1366const int isdst; 1367{ 1368 if (strchr(format, '/') == NULL) { 1369 if (letters == NULL) 1370 (void) strcpy(abbr, format); 1371 else (void) sprintf(abbr, format, letters); 1372 } else if (isdst) 1373 (void) strcpy(abbr, strchr(format, '/') + 1); 1374 else { 1375 (void) strcpy(abbr, format); 1376 *strchr(abbr, '/') = '\0'; 1377 } 1378} 1379 1380static void 1381outzone(zpfirst, zonecount) 1382const struct zone * const zpfirst; 1383const int zonecount; 1384{ 1385 register const struct zone * zp; 1386 register struct rule * rp; 1387 register int i, j; 1388 register int usestart, useuntil; 1389 register time_t starttime, untiltime; 1390 register long gmtoff; 1391 register long stdoff; 1392 register int year; 1393 register long startoff; 1394 register int startisdst; 1395 register int startttisstd; 1396 register int startttisgmt; 1397 register int type; 1398 char startbuf[BUFSIZ]; 1399 1400 INITIALIZE(untiltime); 1401 INITIALIZE(starttime); 1402 INITIALIZE(startoff); 1403 /* 1404 ** Now. . .finally. . .generate some useful data! 1405 */ 1406 timecnt = 0; 1407 typecnt = 0; 1408 charcnt = 0; 1409 /* 1410 ** A guess that may well be corrected later. 1411 */ 1412 stdoff = 0; 1413 /* 1414 ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au) 1415 ** for noting the need to unconditionally initialize startttisstd. 1416 */ 1417 startttisstd = FALSE; 1418 startttisgmt = FALSE; 1419 for (i = 0; i < zonecount; ++i) { 1420 zp = &zpfirst[i]; 1421 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 1422 useuntil = i < (zonecount - 1); 1423 if (useuntil && zp->z_untiltime <= min_time) 1424 continue; 1425 gmtoff = zp->z_gmtoff; 1426 eat(zp->z_filename, zp->z_linenum); 1427 startisdst = -1; 1428 if (zp->z_nrules == 0) { 1429 stdoff = zp->z_stdoff; 1430 doabbr(startbuf, zp->z_format, 1431 (char *) NULL, stdoff != 0); 1432 type = addtype(oadd(zp->z_gmtoff, stdoff), 1433 startbuf, stdoff != 0, startttisstd, 1434 startttisgmt); 1435 if (usestart) 1436 addtt(starttime, type); 1437 else if (stdoff != 0) 1438 addtt(min_time, type); 1439 } else for (year = min_year; year <= max_year; ++year) { 1440 if (useuntil && year > zp->z_untilrule.r_hiyear) 1441 break; 1442 /* 1443 ** Mark which rules to do in the current year. 1444 ** For those to do, calculate rpytime(rp, year); 1445 */ 1446 for (j = 0; j < zp->z_nrules; ++j) { 1447 rp = &zp->z_rules[j]; 1448 eats(zp->z_filename, zp->z_linenum, 1449 rp->r_filename, rp->r_linenum); 1450 rp->r_todo = year >= rp->r_loyear && 1451 year <= rp->r_hiyear && 1452 yearistype(year, rp->r_yrtype); 1453 if (rp->r_todo) 1454 rp->r_temp = rpytime(rp, year); 1455 } 1456 for ( ; ; ) { 1457 register int k; 1458 register time_t jtime, ktime; 1459 register long offset; 1460 char buf[BUFSIZ]; 1461 1462 INITIALIZE(ktime); 1463 if (useuntil) { 1464 /* 1465 ** Turn untiltime into GMT 1466 ** assuming the current gmtoff and 1467 ** stdoff values. 1468 */ 1469 untiltime = zp->z_untiltime; 1470 if (!zp->z_untilrule.r_todisgmt) 1471 untiltime = tadd(untiltime, 1472 -gmtoff); 1473 if (!zp->z_untilrule.r_todisstd) 1474 untiltime = tadd(untiltime, 1475 -stdoff); 1476 } 1477 /* 1478 ** Find the rule (of those to do, if any) 1479 ** that takes effect earliest in the year. 1480 */ 1481 k = -1; 1482 for (j = 0; j < zp->z_nrules; ++j) { 1483 rp = &zp->z_rules[j]; 1484 if (!rp->r_todo) 1485 continue; 1486 eats(zp->z_filename, zp->z_linenum, 1487 rp->r_filename, rp->r_linenum); 1488 offset = rp->r_todisgmt ? 0 : gmtoff; 1489 if (!rp->r_todisstd) 1490 offset = oadd(offset, stdoff); 1491 jtime = rp->r_temp; 1492 if (jtime == min_time || 1493 jtime == max_time) 1494 continue; 1495 jtime = tadd(jtime, -offset); 1496 if (k < 0 || jtime < ktime) { 1497 k = j; 1498 ktime = jtime; 1499 } 1500 } 1501 if (k < 0) 1502 break; /* go on to next year */ 1503 rp = &zp->z_rules[k]; 1504 rp->r_todo = FALSE; 1505 if (useuntil && ktime >= untiltime) 1506 break; 1507 if (usestart) { 1508 if (ktime < starttime) { 1509 stdoff = rp->r_stdoff; 1510 startoff = oadd(zp->z_gmtoff, 1511 rp->r_stdoff); 1512 doabbr(startbuf, zp->z_format, 1513 rp->r_abbrvar, 1514 rp->r_stdoff != 0); 1515 startisdst = rp->r_stdoff != 0; 1516 continue; 1517 } 1518 usestart = FALSE; 1519 if (ktime != starttime) { 1520 if (startisdst < 0 && 1521 zp->z_gmtoff != 1522 (zp - 1)->z_gmtoff) { 1523 type = (timecnt == 0) ? 0 : 1524 types[timecnt - 1]; 1525 startoff = oadd(gmtoffs[type], 1526 -(zp - 1)->z_gmtoff); 1527 startisdst = startoff != 0; 1528 startoff = oadd(startoff, 1529 zp->z_gmtoff); 1530 (void) strcpy(startbuf, 1531 &chars[abbrinds[type]]); 1532 } 1533 if (startisdst >= 0) 1534addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd, 1535 startttisgmt)); 1536 } 1537 } 1538 eats(zp->z_filename, zp->z_linenum, 1539 rp->r_filename, rp->r_linenum); 1540 doabbr(buf, zp->z_format, rp->r_abbrvar, 1541 rp->r_stdoff != 0); 1542 offset = oadd(zp->z_gmtoff, rp->r_stdoff); 1543 type = addtype(offset, buf, rp->r_stdoff != 0, 1544 rp->r_todisstd, rp->r_todisgmt); 1545 addtt(ktime, type); 1546 stdoff = rp->r_stdoff; 1547 } 1548 } 1549 /* 1550 ** Now we may get to set starttime for the next zone line. 1551 */ 1552 if (useuntil) { 1553 starttime = tadd(zp->z_untiltime, -gmtoff); 1554 startttisstd = zp->z_untilrule.r_todisstd; 1555 startttisgmt = zp->z_untilrule.r_todisgmt; 1556 if (!startttisstd) 1557 starttime = tadd(starttime, -stdoff); 1558 } 1559 } 1560 writezone(zpfirst->z_name); 1561} 1562 1563static void 1564addtt(starttime, type) 1565const time_t starttime; 1566const int type; 1567{ 1568 if (timecnt != 0 && type == types[timecnt - 1]) 1569 return; /* easy enough! */ 1570 if (timecnt == 0 && type == 0 && isdsts[0] == 0) 1571 return; /* handled by default rule */ 1572 if (timecnt >= TZ_MAX_TIMES) { 1573 error("too many transitions?!"); 1574 (void) exit(EXIT_FAILURE); 1575 } 1576 ats[timecnt] = starttime; 1577 types[timecnt] = type; 1578 ++timecnt; 1579} 1580 1581static int 1582addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) 1583const long gmtoff; 1584const char * const abbr; 1585const int isdst; 1586const int ttisstd; 1587const int ttisgmt; 1588{ 1589 register int i, j; 1590 1591 /* 1592 ** See if there's already an entry for this zone type. 1593 ** If so, just return its index. 1594 */ 1595 for (i = 0; i < typecnt; ++i) { 1596 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 1597 strcmp(abbr, &chars[abbrinds[i]]) == 0 && 1598 ttisstd == ttisstds[i] && 1599 ttisgmt == ttisgmts[i]) 1600 return i; 1601 } 1602 /* 1603 ** There isn't one; add a new one, unless there are already too 1604 ** many. 1605 */ 1606 if (typecnt >= TZ_MAX_TYPES) { 1607 error("too many local time types"); 1608 (void) exit(EXIT_FAILURE); 1609 } 1610 gmtoffs[i] = gmtoff; 1611 isdsts[i] = isdst; 1612 ttisstds[i] = ttisstd; 1613 ttisgmts[i] = ttisgmt; 1614 1615 for (j = 0; j < charcnt; ++j) 1616 if (strcmp(&chars[j], abbr) == 0) 1617 break; 1618 if (j == charcnt) 1619 newabbr(abbr); 1620 abbrinds[i] = j; 1621 ++typecnt; 1622 return i; 1623} 1624 1625static void 1626leapadd(t, positive, rolling, count) 1627const time_t t; 1628const int positive; 1629const int rolling; 1630int count; 1631{ 1632 register int i, j; 1633 1634 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 1635 error("too many leap seconds"); 1636 (void) exit(EXIT_FAILURE); 1637 } 1638 for (i = 0; i < leapcnt; ++i) 1639 if (t <= trans[i]) { 1640 if (t == trans[i]) { 1641 error("repeated leap second moment"); 1642 (void) exit(EXIT_FAILURE); 1643 } 1644 break; 1645 } 1646 do { 1647 for (j = leapcnt; j > i; --j) { 1648 trans[j] = trans[j - 1]; 1649 corr[j] = corr[j - 1]; 1650 roll[j] = roll[j - 1]; 1651 } 1652 trans[i] = t; 1653 corr[i] = positive ? 1L : eitol(-count); 1654 roll[i] = rolling; 1655 ++leapcnt; 1656 } while (positive && --count != 0); 1657} 1658 1659static void 1660adjleap P((void)) 1661{ 1662 register int i; 1663 register long last = 0; 1664 1665 /* 1666 ** propagate leap seconds forward 1667 */ 1668 for (i = 0; i < leapcnt; ++i) { 1669 trans[i] = tadd(trans[i], last); 1670 last = corr[i] += last; 1671 } 1672} 1673 1674static int 1675yearistype(year, type) 1676const int year; 1677const char * const type; 1678{ 1679 static char * buf; 1680 int result; 1681 1682 if (type == NULL || *type == '\0') 1683 return TRUE; 1684 buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); 1685 (void) sprintf(buf, "%s %d %s", yitcommand, year, type); 1686 result = system(buf); 1687 if (result == 0) 1688 return TRUE; 1689 if (result == (1 << 8)) 1690 return FALSE; 1691 error("Wild result from command execution"); 1692 (void) fprintf(stderr, "%s: command was '%s', result was %d\n", 1693 progname, buf, result); 1694 for ( ; ; ) 1695 (void) exit(EXIT_FAILURE); 1696} 1697 1698static int 1699lowerit(a) 1700const int a; 1701{ 1702 return (isascii(a) && isupper(a)) ? tolower(a) : a; 1703} 1704 1705static int 1706ciequal(ap, bp) /* case-insensitive equality */ 1707register const char * ap; 1708register const char * bp; 1709{ 1710 while (lowerit(*ap) == lowerit(*bp++)) 1711 if (*ap++ == '\0') 1712 return TRUE; 1713 return FALSE; 1714} 1715 1716static int 1717itsabbr(abbr, word) 1718register const char * abbr; 1719register const char * word; 1720{ 1721 if (lowerit(*abbr) != lowerit(*word)) 1722 return FALSE; 1723 ++word; 1724 while (*++abbr != '\0') 1725 do if (*word == '\0') 1726 return FALSE; 1727 while (lowerit(*word++) != lowerit(*abbr)); 1728 return TRUE; 1729} 1730 1731static const struct lookup * 1732byword(word, table) 1733register const char * const word; 1734register const struct lookup * const table; 1735{ 1736 register const struct lookup * foundlp; 1737 register const struct lookup * lp; 1738 1739 if (word == NULL || table == NULL) 1740 return NULL; 1741 /* 1742 ** Look for exact match. 1743 */ 1744 for (lp = table; lp->l_word != NULL; ++lp) 1745 if (ciequal(word, lp->l_word)) 1746 return lp; 1747 /* 1748 ** Look for inexact match. 1749 */ 1750 foundlp = NULL; 1751 for (lp = table; lp->l_word != NULL; ++lp) 1752 if (itsabbr(word, lp->l_word)) 1753 if (foundlp == NULL) 1754 foundlp = lp; 1755 else return NULL; /* multiple inexact matches */ 1756 return foundlp; 1757} 1758 1759static char ** 1760getfields(cp) 1761register char * cp; 1762{ 1763 register char * dp; 1764 register char ** array; 1765 register int nsubs; 1766 1767 if (cp == NULL) 1768 return NULL; 1769 array = (char **) (void *) 1770 emalloc((int) ((strlen(cp) + 1) * sizeof *array)); 1771 nsubs = 0; 1772 for ( ; ; ) { 1773 while (isascii(*cp) && isspace(*cp)) 1774 ++cp; 1775 if (*cp == '\0' || *cp == '#') 1776 break; 1777 array[nsubs++] = dp = cp; 1778 do { 1779 if ((*dp = *cp++) != '"') 1780 ++dp; 1781 else while ((*dp = *cp++) != '"') 1782 if (*dp != '\0') 1783 ++dp; 1784 else error("Odd number of quotation marks"); 1785 } while (*cp != '\0' && *cp != '#' && 1786 (!isascii(*cp) || !isspace(*cp))); 1787 if (isascii(*cp) && isspace(*cp)) 1788 ++cp; 1789 *dp = '\0'; 1790 } 1791 array[nsubs] = NULL; 1792 return array; 1793} 1794 1795static long 1796oadd(t1, t2) 1797const long t1; 1798const long t2; 1799{ 1800 register long t; 1801 1802 t = t1 + t2; 1803 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1804 error("time overflow"); 1805 (void) exit(EXIT_FAILURE); 1806 } 1807 return t; 1808} 1809 1810static time_t 1811tadd(t1, t2) 1812const time_t t1; 1813const long t2; 1814{ 1815 register time_t t; 1816 1817 if (t1 == max_time && t2 > 0) 1818 return max_time; 1819 if (t1 == min_time && t2 < 0) 1820 return min_time; 1821 t = t1 + t2; 1822 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 1823 error("time overflow"); 1824 (void) exit(EXIT_FAILURE); 1825 } 1826 return t; 1827} 1828 1829/* 1830** Given a rule, and a year, compute the date - in seconds since January 1, 1831** 1970, 00:00 LOCAL time - in that year that the rule refers to. 1832*/ 1833 1834static time_t 1835rpytime(rp, wantedy) 1836register const struct rule * const rp; 1837register const int wantedy; 1838{ 1839 register int y, m, i; 1840 register long dayoff; /* with a nod to Margaret O. */ 1841 register time_t t; 1842 1843 if (wantedy == min_int) 1844 return min_time; 1845 if (wantedy == max_int) 1846 return max_time; 1847 dayoff = 0; 1848 m = TM_JANUARY; 1849 y = EPOCH_YEAR; 1850 while (wantedy != y) { 1851 if (wantedy > y) { 1852 i = len_years[isleap(y)]; 1853 ++y; 1854 } else { 1855 --y; 1856 i = -len_years[isleap(y)]; 1857 } 1858 dayoff = oadd(dayoff, eitol(i)); 1859 } 1860 while (m != rp->r_month) { 1861 i = len_months[isleap(y)][m]; 1862 dayoff = oadd(dayoff, eitol(i)); 1863 ++m; 1864 } 1865 i = rp->r_dayofmonth; 1866 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 1867 if (rp->r_dycode == DC_DOWLEQ) 1868 --i; 1869 else { 1870 error("use of 2/29 in non leap-year"); 1871 (void) exit(EXIT_FAILURE); 1872 } 1873 } 1874 --i; 1875 dayoff = oadd(dayoff, eitol(i)); 1876 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 1877 register long wday; 1878 1879#define LDAYSPERWEEK ((long) DAYSPERWEEK) 1880 wday = eitol(EPOCH_WDAY); 1881 /* 1882 ** Don't trust mod of negative numbers. 1883 */ 1884 if (dayoff >= 0) 1885 wday = (wday + dayoff) % LDAYSPERWEEK; 1886 else { 1887 wday -= ((-dayoff) % LDAYSPERWEEK); 1888 if (wday < 0) 1889 wday += LDAYSPERWEEK; 1890 } 1891 while (wday != eitol(rp->r_wday)) 1892 if (rp->r_dycode == DC_DOWGEQ) { 1893 dayoff = oadd(dayoff, (long) 1); 1894 if (++wday >= LDAYSPERWEEK) 1895 wday = 0; 1896 ++i; 1897 } else { 1898 dayoff = oadd(dayoff, (long) -1); 1899 if (--wday < 0) 1900 wday = LDAYSPERWEEK - 1; 1901 --i; 1902 } 1903 if (i < 0 || i >= len_months[isleap(y)][m]) { 1904 error("no day in month matches rule"); 1905 (void) exit(EXIT_FAILURE); 1906 } 1907 } 1908 if (dayoff < 0 && !tt_signed) 1909 return min_time; 1910 t = (time_t) dayoff * SECSPERDAY; 1911 /* 1912 ** Cheap overflow check. 1913 */ 1914 if (t / SECSPERDAY != dayoff) 1915 return (dayoff > 0) ? max_time : min_time; 1916 return tadd(t, rp->r_tod); 1917} 1918 1919static void 1920newabbr(string) 1921const char * const string; 1922{ 1923 register int i; 1924 1925 i = strlen(string) + 1; 1926 if (charcnt + i > TZ_MAX_CHARS) { 1927 error("too many, or too long, time zone abbreviations"); 1928 (void) exit(EXIT_FAILURE); 1929 } 1930 (void) strcpy(&chars[charcnt], string); 1931 charcnt += eitol(i); 1932} 1933 1934static int 1935mkdirs(argname) 1936char * const argname; 1937{ 1938 register char * name; 1939 register char * cp; 1940 1941 if (argname == NULL || *argname == '\0') 1942 return 0; 1943 cp = name = ecpyalloc(argname); 1944 while ((cp = strchr(cp + 1, '/')) != 0) { 1945 *cp = '\0'; 1946#ifndef unix 1947 /* 1948 ** DOS drive specifier? 1949 */ 1950 if (strlen(name) == 2 && isascii(name[0]) && 1951 isalpha(name[0]) && name[1] == ':') { 1952 *cp = '/'; 1953 continue; 1954 } 1955#endif /* !defined unix */ 1956 if (!itsdir(name)) { 1957 /* 1958 ** It doesn't seem to exist, so we try to create it. 1959 */ 1960 if (mkdir(name, 0755) != 0) { 1961 (void) fprintf(stderr, 1962 "%s: Can't create directory ", 1963 progname); 1964 (void) perror(name); 1965 ifree(name); 1966 return -1; 1967 } 1968 } 1969 *cp = '/'; 1970 } 1971 ifree(name); 1972 return 0; 1973} 1974 1975static long 1976eitol(i) 1977const int i; 1978{ 1979 long l; 1980 1981 l = i; 1982 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 1983 (void) fprintf(stderr, 1984 "%s: %d did not sign extend correctly\n", 1985 progname, i); 1986 (void) exit(EXIT_FAILURE); 1987 } 1988 return l; 1989} 1990 1991/* 1992** UNIX was a registered trademark of UNIX System Laboratories in 1993. 1993*/ 1994