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