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