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