1 /* 2 * Copyright 2007 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.1"; 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 *fromfield, const char *tofield); 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(fromfield, tofield) 596 const char * const fromfield; 597 const char * const tofield; 598 { 599 register char *fromname; 600 register char *toname; 601 602 if (fromfield[0] == '/') 603 fromname = ecpyalloc(fromfield); 604 else { 605 fromname = ecpyalloc(directory); 606 fromname = ecatalloc(fromname, "/"); 607 fromname = ecatalloc(fromname, fromfield); 608 } 609 if (tofield[0] == '/') 610 toname = ecpyalloc(tofield); 611 else { 612 toname = ecpyalloc(directory); 613 toname = ecatalloc(toname, "/"); 614 toname = ecatalloc(toname, tofield); 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 = tofield; 633 register char *symlinkcontents = NULL; 634 635 while ((s = strchr(s+1, '/')) != NULL) 636 symlinkcontents = ecatalloc(symlinkcontents, 637 "../"); 638 symlinkcontents = ecatalloc(symlinkcontents, fromname); 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 long hh; 929 int mm, ss, sign; 930 931 if (string == NULL || *string == '\0') 932 return (0); 933 if (!signable) 934 sign = 1; 935 else if (*string == '-') { 936 sign = -1; 937 ++string; 938 } else sign = 1; 939 if (sscanf(string, scheck(string, "%ld"), &hh) == 1) 940 mm = ss = 0; 941 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2) 942 ss = 0; 943 else if (sscanf(string, scheck(string, "%ld:%d:%d"), 944 &hh, &mm, &ss) != 3) { 945 error(errstring); 946 return (0); 947 } 948 if (hh < 0 || 949 mm < 0 || mm >= MINSPERHOUR || 950 ss < 0 || ss > SECSPERMIN) { 951 error(errstring); 952 return (0); 953 } 954 if (LONG_MAX / SECSPERHOUR < hh) { 955 error(gettext("time overflow")); 956 return (0); 957 } 958 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) 959 warning( 960 gettext("24:00 not handled by pre-1998 versions of zic")); 961 if (noise && (hh > HOURSPERDAY || 962 (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 963 warning(gettext("values over 24 hours not handled by " 964 "pre-2007 versions of zic")); 965 966 return (oadd(eitol(sign) * hh * eitol(SECSPERHOUR), 967 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)))); 968 } 969 970 static void 971 inrule(fields, nfields) 972 register char ** const fields; 973 const int nfields; 974 { 975 static struct rule r; 976 977 if (nfields != RULE_FIELDS) { 978 error(gettext("wrong number of fields on Rule line")); 979 return; 980 } 981 if (*fields[RF_NAME] == '\0') { 982 error(gettext("nameless rule")); 983 return; 984 } 985 r.r_filename = filename; 986 r.r_linenum = linenum; 987 r.r_stdoff = gethms(fields[RF_STDOFF], gettext("invalid saved time"), 988 TRUE); 989 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 990 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 991 r.r_name = ecpyalloc(fields[RF_NAME]); 992 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 993 rules = (struct rule *)(void *)erealloc((char *)rules, 994 (int)((nrules + 1) * sizeof (*rules))); 995 rules[nrules++] = r; 996 } 997 998 static int 999 inzone(fields, nfields) 1000 register char ** const fields; 1001 const int nfields; 1002 { 1003 register int i; 1004 static char *buf; 1005 1006 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 1007 error(gettext("wrong number of fields on Zone line")); 1008 return (FALSE); 1009 } 1010 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 1011 buf = erealloc(buf, (int)(132 + strlen(TZDEFAULT))); 1012 (void) sprintf(buf, 1013 gettext("\"Zone %s\" line and -l option are mutually exclusive"), 1014 TZDEFAULT); 1015 error(buf); 1016 return (FALSE); 1017 } 1018 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 1019 buf = erealloc(buf, (int)(132 + strlen(TZDEFRULES))); 1020 (void) sprintf(buf, 1021 gettext("\"Zone %s\" line and -p option are mutually exclusive"), 1022 TZDEFRULES); 1023 error(buf); 1024 return (FALSE); 1025 } 1026 for (i = 0; i < nzones; ++i) 1027 if (zones[i].z_name != NULL && 1028 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 1029 buf = erealloc(buf, (int)(132 + 1030 strlen(fields[ZF_NAME]) + 1031 strlen(zones[i].z_filename))); 1032 (void) sprintf(buf, 1033 gettext("duplicate zone name %s (file \"%s\", line %d)"), 1034 fields[ZF_NAME], 1035 zones[i].z_filename, 1036 zones[i].z_linenum); 1037 error(buf); 1038 return (FALSE); 1039 } 1040 return (inzsub(fields, nfields, FALSE)); 1041 } 1042 1043 static int 1044 inzcont(fields, nfields) 1045 register char ** const fields; 1046 const int nfields; 1047 { 1048 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 1049 error(gettext( 1050 "wrong number of fields on Zone continuation line")); 1051 return (FALSE); 1052 } 1053 return (inzsub(fields, nfields, TRUE)); 1054 } 1055 1056 static int 1057 inzsub(fields, nfields, iscont) 1058 register char ** const fields; 1059 const int nfields; 1060 const int iscont; 1061 { 1062 register char *cp; 1063 static struct zone z; 1064 register int i_gmtoff, i_rule, i_format; 1065 register int i_untilyear, i_untilmonth; 1066 register int i_untilday, i_untiltime; 1067 register int hasuntil; 1068 1069 if (iscont) { 1070 i_gmtoff = ZFC_GMTOFF; 1071 i_rule = ZFC_RULE; 1072 i_format = ZFC_FORMAT; 1073 i_untilyear = ZFC_TILYEAR; 1074 i_untilmonth = ZFC_TILMONTH; 1075 i_untilday = ZFC_TILDAY; 1076 i_untiltime = ZFC_TILTIME; 1077 z.z_name = NULL; 1078 } else { 1079 i_gmtoff = ZF_GMTOFF; 1080 i_rule = ZF_RULE; 1081 i_format = ZF_FORMAT; 1082 i_untilyear = ZF_TILYEAR; 1083 i_untilmonth = ZF_TILMONTH; 1084 i_untilday = ZF_TILDAY; 1085 i_untiltime = ZF_TILTIME; 1086 z.z_name = ecpyalloc(fields[ZF_NAME]); 1087 } 1088 z.z_filename = filename; 1089 z.z_linenum = linenum; 1090 z.z_gmtoff = gethms(fields[i_gmtoff], gettext("invalid UTC offset"), 1091 TRUE); 1092 if ((cp = strchr(fields[i_format], '%')) != 0) { 1093 if (*++cp != 's' || strchr(cp, '%') != 0) { 1094 error(gettext("invalid abbreviation format")); 1095 return (FALSE); 1096 } 1097 } 1098 z.z_rule = ecpyalloc(fields[i_rule]); 1099 z.z_format = ecpyalloc(fields[i_format]); 1100 hasuntil = nfields > i_untilyear; 1101 if (hasuntil) { 1102 z.z_untilrule.r_filename = filename; 1103 z.z_untilrule.r_linenum = linenum; 1104 rulesub(&z.z_untilrule, 1105 fields[i_untilyear], 1106 "only", 1107 "", 1108 (nfields > i_untilmonth) ? 1109 fields[i_untilmonth] : "Jan", 1110 (nfields > i_untilday) ? fields[i_untilday] : "1", 1111 (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 1112 z.z_untiltime = rpytime(&z.z_untilrule, 1113 z.z_untilrule.r_loyear); 1114 if (iscont && nzones > 0 && 1115 z.z_untiltime > min_time && 1116 z.z_untiltime < max_time && 1117 zones[nzones - 1].z_untiltime > min_time && 1118 zones[nzones - 1].z_untiltime < max_time && 1119 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1120 error(gettext( 1121 "Zone continuation line end time is not after end time of previous line")); 1122 return (FALSE); 1123 } 1124 } 1125 zones = (struct zone *)(void *)erealloc((char *)zones, 1126 (int)((nzones + 1) * sizeof (*zones))); 1127 zones[nzones++] = z; 1128 /* 1129 * If there was an UNTIL field on this line, 1130 * there's more information about the zone on the next line. 1131 */ 1132 return (hasuntil); 1133 } 1134 1135 #ifdef LEAPSECOND_SUPPORT 1136 static void 1137 inleap(fields, nfields) 1138 register char ** const fields; 1139 const int nfields; 1140 { 1141 register const char *cp; 1142 register const struct lookup *lp; 1143 register int i, j; 1144 int year, month, day; 1145 long dayoff, tod; 1146 zic_t t; 1147 1148 if (nfields != LEAP_FIELDS) { 1149 error(gettext("wrong number of fields on Leap line")); 1150 return; 1151 } 1152 dayoff = 0; 1153 cp = fields[LP_YEAR]; 1154 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 1155 /* 1156 * Leapin' Lizards! 1157 */ 1158 error(gettext("invalid leaping year")); 1159 return; 1160 } 1161 j = EPOCH_YEAR; 1162 while (j != year) { 1163 if (year > j) { 1164 i = len_years[isleap(j)]; 1165 ++j; 1166 } else { 1167 --j; 1168 i = -len_years[isleap(j)]; 1169 } 1170 dayoff = oadd(dayoff, eitol(i)); 1171 } 1172 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1173 error(gettext("invalid month name")); 1174 return; 1175 } 1176 month = lp->l_value; 1177 j = TM_JANUARY; 1178 while (j != month) { 1179 i = len_months[isleap(year)][j]; 1180 dayoff = oadd(dayoff, eitol(i)); 1181 ++j; 1182 } 1183 cp = fields[LP_DAY]; 1184 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 1185 day <= 0 || day > len_months[isleap(year)][month]) { 1186 error(gettext("invalid day of month")); 1187 return; 1188 } 1189 dayoff = oadd(dayoff, eitol(day - 1)); 1190 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) { 1191 error(gettext("time before zero")); 1192 return; 1193 } 1194 if (dayoff < min_time / SECSPERDAY) { 1195 error(gettext("time too small")); 1196 return; 1197 } 1198 if (dayoff > max_time / SECSPERDAY) { 1199 error(gettext("time too large")); 1200 return; 1201 } 1202 t = (zic_t)dayoff * SECSPERDAY; 1203 tod = gethms(fields[LP_TIME], gettext("invalid time of day"), FALSE); 1204 cp = fields[LP_CORR]; 1205 { 1206 register int positive; 1207 int count; 1208 1209 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 1210 positive = FALSE; 1211 count = 1; 1212 } else if (strcmp(cp, "--") == 0) { 1213 positive = FALSE; 1214 count = 2; 1215 } else if (strcmp(cp, "+") == 0) { 1216 positive = TRUE; 1217 count = 1; 1218 } else if (strcmp(cp, "++") == 0) { 1219 positive = TRUE; 1220 count = 2; 1221 } else { 1222 error(gettext("illegal CORRECTION field on Leap line")); 1223 return; 1224 } 1225 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1226 error(gettext( 1227 "illegal Rolling/Stationary field on Leap line")); 1228 return; 1229 } 1230 leapadd(tadd(t, tod), positive, lp->l_value, count); 1231 } 1232 } 1233 #endif /* LEAPSECOND_SUPPORT */ 1234 1235 static void 1236 inlink(fields, nfields) 1237 register char ** const fields; 1238 const int nfields; 1239 { 1240 struct link l; 1241 1242 if (nfields != LINK_FIELDS) { 1243 error(gettext("wrong number of fields on Link line")); 1244 return; 1245 } 1246 if (*fields[LF_FROM] == '\0') { 1247 error(gettext("blank FROM field on Link line")); 1248 return; 1249 } 1250 if (*fields[LF_TO] == '\0') { 1251 error(gettext("blank TO field on Link line")); 1252 return; 1253 } 1254 l.l_filename = filename; 1255 l.l_linenum = linenum; 1256 l.l_from = ecpyalloc(fields[LF_FROM]); 1257 l.l_to = ecpyalloc(fields[LF_TO]); 1258 links = (struct link *)(void *)erealloc((char *)links, 1259 (int)((nlinks + 1) * sizeof (*links))); 1260 links[nlinks++] = l; 1261 } 1262 1263 static void 1264 rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 1265 register struct rule * const rp; 1266 const char * const loyearp; 1267 const char * const hiyearp; 1268 const char * const typep; 1269 const char * const monthp; 1270 const char * const dayp; 1271 const char * const timep; 1272 { 1273 register const struct lookup *lp; 1274 register const char *cp; 1275 register char *dp; 1276 register char *ep; 1277 1278 if ((lp = byword(monthp, mon_names)) == NULL) { 1279 error(gettext("invalid month name")); 1280 return; 1281 } 1282 rp->r_month = lp->l_value; 1283 rp->r_todisstd = FALSE; 1284 rp->r_todisgmt = FALSE; 1285 dp = ecpyalloc(timep); 1286 if (*dp != '\0') { 1287 ep = dp + strlen(dp) - 1; 1288 switch (lowerit(*ep)) { 1289 case 's': /* Standard */ 1290 rp->r_todisstd = TRUE; 1291 rp->r_todisgmt = FALSE; 1292 *ep = '\0'; 1293 break; 1294 case 'w': /* Wall */ 1295 rp->r_todisstd = FALSE; 1296 rp->r_todisgmt = FALSE; 1297 *ep = '\0'; 1298 break; 1299 case 'g': /* Greenwich */ 1300 case 'u': /* Universal */ 1301 case 'z': /* Zulu */ 1302 rp->r_todisstd = TRUE; 1303 rp->r_todisgmt = TRUE; 1304 *ep = '\0'; 1305 break; 1306 } 1307 } 1308 rp->r_tod = gethms(dp, gettext("invalid time of day"), FALSE); 1309 ifree(dp); 1310 /* 1311 * Year work. 1312 */ 1313 cp = loyearp; 1314 lp = byword(cp, begin_years); 1315 if (lp != NULL) { 1316 switch ((int)lp->l_value) { 1317 case YR_MINIMUM: 1318 rp->r_loyear = INT_MIN; 1319 break; 1320 case YR_MAXIMUM: 1321 rp->r_loyear = INT_MAX; 1322 break; 1323 default: /* "cannot happen" */ 1324 (void) fprintf(stderr, 1325 gettext("%s: panic: Invalid l_value %d\n"), 1326 progname, lp->l_value); 1327 exit(EXIT_FAILURE); 1328 } 1329 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 1330 error(gettext("invalid starting year")); 1331 return; 1332 } else if (noise) { 1333 if (rp->r_loyear < min_year_representable) 1334 warning(gettext( 1335 "starting year too low to be represented")); 1336 else if (rp->r_loyear > max_year_representable) 1337 warning(gettext( 1338 "starting year too high to be represented")); 1339 } 1340 cp = hiyearp; 1341 if ((lp = byword(cp, end_years)) != NULL) { 1342 switch ((int)lp->l_value) { 1343 case YR_MINIMUM: 1344 rp->r_hiyear = INT_MIN; 1345 break; 1346 case YR_MAXIMUM: 1347 rp->r_hiyear = INT_MAX; 1348 break; 1349 case YR_ONLY: 1350 rp->r_hiyear = rp->r_loyear; 1351 break; 1352 default: /* "cannot happen" */ 1353 (void) fprintf(stderr, 1354 gettext("%s: panic: Invalid l_value %d\n"), 1355 progname, lp->l_value); 1356 exit(EXIT_FAILURE); 1357 } 1358 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 1359 error(gettext("invalid ending year")); 1360 return; 1361 } else if (noise) { 1362 if (rp->r_loyear < min_year_representable) 1363 warning(gettext( 1364 "ending year too low to be represented")); 1365 else if (rp->r_loyear > max_year_representable) 1366 warning(gettext( 1367 "ending year too high to be represented")); 1368 } 1369 if (rp->r_loyear > rp->r_hiyear) { 1370 error(gettext("starting year greater than ending year")); 1371 return; 1372 } 1373 if (*typep == '\0') 1374 rp->r_yrtype = NULL; 1375 else { 1376 if (rp->r_loyear == rp->r_hiyear) { 1377 error(gettext("typed single year")); 1378 return; 1379 } 1380 rp->r_yrtype = ecpyalloc(typep); 1381 } 1382 if (rp->r_loyear < min_year && rp->r_loyear > 0) 1383 min_year = rp->r_loyear; 1384 /* 1385 * Day work. 1386 * Accept things such as: 1387 * 1 1388 * last-Sunday 1389 * Sun<=20 1390 * Sun>=7 1391 */ 1392 dp = ecpyalloc(dayp); 1393 if ((lp = byword(dp, lasts)) != NULL) { 1394 rp->r_dycode = DC_DOWLEQ; 1395 rp->r_wday = lp->l_value; 1396 rp->r_dayofmonth = len_months[1][rp->r_month]; 1397 } else { 1398 if ((ep = strchr(dp, '<')) != 0) 1399 rp->r_dycode = DC_DOWLEQ; 1400 else if ((ep = strchr(dp, '>')) != 0) 1401 rp->r_dycode = DC_DOWGEQ; 1402 else { 1403 ep = dp; 1404 rp->r_dycode = DC_DOM; 1405 } 1406 if (rp->r_dycode != DC_DOM) { 1407 *ep++ = 0; 1408 if (*ep++ != '=') { 1409 error(gettext("invalid day of month")); 1410 ifree(dp); 1411 return; 1412 } 1413 if ((lp = byword(dp, wday_names)) == NULL) { 1414 error(gettext("invalid weekday name")); 1415 ifree(dp); 1416 return; 1417 } 1418 rp->r_wday = lp->l_value; 1419 } 1420 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || 1421 rp->r_dayofmonth <= 0 || 1422 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1423 error(gettext("invalid day of month")); 1424 ifree(dp); 1425 return; 1426 } 1427 } 1428 ifree(dp); 1429 } 1430 1431 static void 1432 convert(val, buf) 1433 const long val; 1434 char * const buf; 1435 { 1436 register int i; 1437 register long shift; 1438 1439 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1440 buf[i] = val >> shift; 1441 } 1442 1443 static void 1444 puttzcode(val, fp) 1445 const long val; 1446 FILE * const fp; 1447 { 1448 char buf[4]; 1449 1450 convert(val, buf); 1451 (void) fwrite((void *)buf, (size_t)sizeof (buf), (size_t)1, fp); 1452 } 1453 1454 static int 1455 atcomp(avp, bvp) 1456 const void *avp; 1457 const void *bvp; 1458 { 1459 if (((struct attype *)avp)->at < ((struct attype *)bvp)->at) 1460 return (-1); 1461 else if (((struct attype *)avp)->at > ((struct attype *)bvp)->at) 1462 return (1); 1463 else return (0); 1464 } 1465 1466 static void 1467 writezone(name) 1468 const char * const name; 1469 { 1470 register FILE *fp; 1471 register int i, j; 1472 static char *fullname; 1473 static struct tzhead tzh; 1474 zic_t ats[TZ_MAX_TIMES]; 1475 unsigned char types[TZ_MAX_TIMES]; 1476 1477 /* 1478 * Sort. 1479 */ 1480 if (timecnt > 1) 1481 (void) qsort((void *)attypes, (size_t)timecnt, 1482 (size_t)sizeof (*attypes), atcomp); 1483 /* 1484 * Optimize. 1485 */ 1486 { 1487 int fromi; 1488 int toi; 1489 1490 toi = 0; 1491 fromi = 0; 1492 while (fromi < timecnt && attypes[fromi].at < min_time) 1493 ++fromi; 1494 if (isdsts[0] == 0) 1495 while (fromi < timecnt && attypes[fromi].type == 0) 1496 ++fromi; /* handled by default rule */ 1497 for (; fromi < timecnt; ++fromi) { 1498 if (toi != 0 && ((attypes[fromi].at + 1499 gmtoffs[attypes[toi - 1].type]) <= 1500 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 1501 : attypes[toi - 2].type]))) { 1502 attypes[toi - 1].type = 1503 attypes[fromi].type; 1504 continue; 1505 } 1506 if (toi == 0 || 1507 attypes[toi - 1].type != attypes[fromi].type) 1508 attypes[toi++] = attypes[fromi]; 1509 } 1510 timecnt = toi; 1511 } 1512 /* 1513 * Transfer. 1514 */ 1515 for (i = 0; i < timecnt; ++i) { 1516 ats[i] = attypes[i].at; 1517 types[i] = attypes[i].type; 1518 } 1519 fullname = erealloc(fullname, 1520 (int)(strlen(directory) + 1 + strlen(name) + 1)); 1521 (void) sprintf(fullname, "%s/%s", directory, name); 1522 /* 1523 * Remove old file, if any, to snap links. 1524 */ 1525 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) { 1526 const char *e = strerror(errno); 1527 1528 (void) fprintf(stderr, gettext("%s: Can't remove %s: %s\n"), 1529 progname, fullname, e); 1530 exit(EXIT_FAILURE); 1531 } 1532 if ((fp = fopen(fullname, "wb")) == NULL) { 1533 if (mkdirs(fullname) != 0) 1534 exit(EXIT_FAILURE); 1535 if ((fp = fopen(fullname, "wb")) == NULL) { 1536 const char *e = strerror(errno); 1537 (void) fprintf(stderr, gettext( 1538 "%s: Can't create %s: %s\n"), 1539 progname, fullname, e); 1540 exit(EXIT_FAILURE); 1541 } 1542 } 1543 convert(eitol(typecnt), tzh.tzh_ttisgmtcnt); 1544 convert(eitol(typecnt), tzh.tzh_ttisstdcnt); 1545 convert(eitol(leapcnt), tzh.tzh_leapcnt); 1546 convert(eitol(timecnt), tzh.tzh_timecnt); 1547 convert(eitol(typecnt), tzh.tzh_typecnt); 1548 convert(eitol(charcnt), tzh.tzh_charcnt); 1549 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof (tzh.tzh_magic)); 1550 #define DO(field) (void) fwrite((void *) tzh.field, \ 1551 (size_t)sizeof (tzh.field), (size_t)1, fp) 1552 DO(tzh_magic); 1553 DO(tzh_reserved); 1554 DO(tzh_ttisgmtcnt); 1555 DO(tzh_ttisstdcnt); 1556 DO(tzh_leapcnt); 1557 DO(tzh_timecnt); 1558 DO(tzh_typecnt); 1559 DO(tzh_charcnt); 1560 #undef DO 1561 for (i = 0; i < timecnt; ++i) { 1562 j = leapcnt; 1563 while (--j >= 0) 1564 if (ats[i] >= trans[j]) { 1565 ats[i] = tadd(ats[i], corr[j]); 1566 break; 1567 } 1568 puttzcode((long)ats[i], fp); 1569 } 1570 if (timecnt > 0) 1571 (void) fwrite((void *)types, (size_t)sizeof (types[0]), 1572 (size_t)timecnt, fp); 1573 for (i = 0; i < typecnt; ++i) { 1574 puttzcode((long)gmtoffs[i], fp); 1575 (void) putc(isdsts[i], fp); 1576 (void) putc(abbrinds[i], fp); 1577 } 1578 if (charcnt != 0) 1579 (void) fwrite((void *)chars, (size_t)sizeof (chars[0]), 1580 (size_t)charcnt, fp); 1581 for (i = 0; i < leapcnt; ++i) { 1582 if (roll[i]) { 1583 if (timecnt == 0 || trans[i] < ats[0]) { 1584 j = 0; 1585 while (isdsts[j]) 1586 if (++j >= typecnt) { 1587 j = 0; 1588 break; 1589 } 1590 } else { 1591 j = 1; 1592 while (j < timecnt && trans[i] >= ats[j]) 1593 ++j; 1594 j = types[j - 1]; 1595 } 1596 puttzcode((long)tadd(trans[i], -gmtoffs[j]), fp); 1597 } else puttzcode((long)trans[i], fp); 1598 puttzcode((long)corr[i], fp); 1599 } 1600 for (i = 0; i < typecnt; ++i) 1601 (void) putc(ttisstds[i], fp); 1602 for (i = 0; i < typecnt; ++i) 1603 (void) putc(ttisgmts[i], fp); 1604 if (ferror(fp) || fclose(fp)) { 1605 (void) fprintf(stderr, gettext("%s: Error writing %s\n"), 1606 progname, fullname); 1607 exit(EXIT_FAILURE); 1608 } 1609 } 1610 1611 static void 1612 doabbr(abbr, format, letters, isdst) 1613 char * const abbr; 1614 const char * const format; 1615 const char * const letters; 1616 const int isdst; 1617 { 1618 if (strchr(format, '/') == NULL) { 1619 if (letters == NULL) 1620 (void) strcpy(abbr, format); 1621 else 1622 (void) sprintf(abbr, format, letters); 1623 } else if (isdst) 1624 (void) strcpy(abbr, strchr(format, '/') + 1); 1625 else { 1626 (void) strcpy(abbr, format); 1627 *strchr(abbr, '/') = '\0'; 1628 } 1629 } 1630 1631 static void 1632 outzone(zpfirst, zonecount) 1633 const struct zone * const zpfirst; 1634 const int zonecount; 1635 { 1636 register const struct zone *zp; 1637 register struct rule *rp; 1638 register int i, j; 1639 register int usestart, useuntil; 1640 register zic_t starttime, untiltime; 1641 register long gmtoff; 1642 register long stdoff; 1643 register int year; 1644 register long startoff; 1645 register int startttisstd; 1646 register int startttisgmt; 1647 register int type; 1648 char startbuf[BUFSIZ]; 1649 1650 INITIALIZE(untiltime); 1651 INITIALIZE(starttime); 1652 /* 1653 * Now. . .finally. . .generate some useful data! 1654 */ 1655 timecnt = 0; 1656 typecnt = 0; 1657 charcnt = 0; 1658 /* 1659 * Thanks to Earl Chew 1660 * for noting the need to unconditionally initialize startttisstd. 1661 */ 1662 startttisstd = FALSE; 1663 startttisgmt = FALSE; 1664 for (i = 0; i < zonecount; ++i) { 1665 /* 1666 * A guess that may well be corrected later. 1667 */ 1668 stdoff = 0; 1669 zp = &zpfirst[i]; 1670 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 1671 useuntil = i < (zonecount - 1); 1672 if (useuntil && zp->z_untiltime <= min_time) 1673 continue; 1674 gmtoff = zp->z_gmtoff; 1675 eat(zp->z_filename, zp->z_linenum); 1676 *startbuf = '\0'; 1677 startoff = zp->z_gmtoff; 1678 if (zp->z_nrules == 0) { 1679 stdoff = zp->z_stdoff; 1680 doabbr(startbuf, zp->z_format, 1681 (char *)NULL, stdoff != 0); 1682 type = addtype(oadd(zp->z_gmtoff, stdoff), 1683 startbuf, stdoff != 0, startttisstd, 1684 startttisgmt); 1685 if (usestart) { 1686 addtt(starttime, type); 1687 usestart = FALSE; 1688 } else if (stdoff != 0) 1689 addtt(min_time, type); 1690 } else 1691 for (year = min_year; year <= max_year; ++year) { 1692 if (useuntil && year > zp->z_untilrule.r_hiyear) 1693 break; 1694 /* 1695 * Mark which rules to do in the current year. 1696 * For those to do, calculate rpytime(rp, year); 1697 */ 1698 for (j = 0; j < zp->z_nrules; ++j) { 1699 rp = &zp->z_rules[j]; 1700 eats(zp->z_filename, zp->z_linenum, 1701 rp->r_filename, rp->r_linenum); 1702 rp->r_todo = year >= rp->r_loyear && 1703 year <= rp->r_hiyear && 1704 yearistype(year, rp->r_yrtype); 1705 if (rp->r_todo) 1706 rp->r_temp = rpytime(rp, year); 1707 } 1708 for (;;) { 1709 register int k; 1710 register zic_t jtime, ktime; 1711 register long offset; 1712 char buf[BUFSIZ]; 1713 1714 INITIALIZE(ktime); 1715 if (useuntil) { 1716 /* 1717 * Turn untiltime into UTC * assuming 1718 * the current gmtoff and stdoff values. 1719 */ 1720 untiltime = zp->z_untiltime; 1721 if (!zp->z_untilrule.r_todisgmt) 1722 untiltime = tadd(untiltime, 1723 -gmtoff); 1724 if (!zp->z_untilrule.r_todisstd) 1725 untiltime = tadd(untiltime, 1726 -stdoff); 1727 } 1728 /* 1729 * Find the rule (of those to do, if any) 1730 * that takes effect earliest in the year. 1731 */ 1732 k = -1; 1733 for (j = 0; j < zp->z_nrules; ++j) { 1734 rp = &zp->z_rules[j]; 1735 if (!rp->r_todo) 1736 continue; 1737 eats(zp->z_filename, zp->z_linenum, 1738 rp->r_filename, rp->r_linenum); 1739 offset = rp->r_todisgmt ? 0 : gmtoff; 1740 if (!rp->r_todisstd) 1741 offset = oadd(offset, stdoff); 1742 jtime = rp->r_temp; 1743 if (jtime == min_time || 1744 jtime == max_time) 1745 continue; 1746 jtime = tadd(jtime, -offset); 1747 if (k < 0 || jtime < ktime) { 1748 k = j; 1749 ktime = jtime; 1750 } 1751 } 1752 if (k < 0) 1753 break; /* go on to next year */ 1754 rp = &zp->z_rules[k]; 1755 rp->r_todo = FALSE; 1756 if (useuntil && ktime >= untiltime) 1757 break; 1758 stdoff = rp->r_stdoff; 1759 if (usestart && ktime == starttime) 1760 usestart = FALSE; 1761 if (usestart) { 1762 if (ktime < starttime) { 1763 startoff = oadd(zp->z_gmtoff, 1764 stdoff); 1765 doabbr(startbuf, zp->z_format, 1766 rp->r_abbrvar, 1767 rp->r_stdoff != 0); 1768 continue; 1769 } 1770 if (*startbuf == '\0' && 1771 startoff == oadd(zp->z_gmtoff, 1772 stdoff)) { 1773 doabbr(startbuf, zp->z_format, 1774 rp->r_abbrvar, 1775 rp->r_stdoff != 0); 1776 } 1777 } 1778 eats(zp->z_filename, zp->z_linenum, 1779 rp->r_filename, rp->r_linenum); 1780 doabbr(buf, zp->z_format, rp->r_abbrvar, 1781 rp->r_stdoff != 0); 1782 offset = oadd(zp->z_gmtoff, rp->r_stdoff); 1783 type = addtype(offset, buf, rp->r_stdoff != 0, 1784 rp->r_todisstd, rp->r_todisgmt); 1785 addtt(ktime, type); 1786 } 1787 } 1788 if (usestart) { 1789 if (*startbuf == '\0' && 1790 zp->z_format != NULL && 1791 strchr(zp->z_format, '%') == NULL && 1792 strchr(zp->z_format, '/') == NULL) 1793 (void) strcpy(startbuf, zp->z_format); 1794 eat(zp->z_filename, zp->z_linenum); 1795 if (*startbuf == '\0') 1796 error(gettext( 1797 "can't determine time zone abbrevation to use just after until time")); 1798 else addtt(starttime, 1799 addtype(startoff, startbuf, 1800 startoff != zp->z_gmtoff, 1801 startttisstd, 1802 startttisgmt)); 1803 } 1804 /* 1805 * Now we may get to set starttime for the next zone line. 1806 */ 1807 if (useuntil) { 1808 startttisstd = zp->z_untilrule.r_todisstd; 1809 startttisgmt = zp->z_untilrule.r_todisgmt; 1810 starttime = zp->z_untiltime; 1811 if (!startttisstd) 1812 starttime = tadd(starttime, -stdoff); 1813 if (!startttisgmt) 1814 starttime = tadd(starttime, -gmtoff); 1815 } 1816 } 1817 writezone(zpfirst->z_name); 1818 } 1819 1820 static void 1821 addtt(starttime, type) 1822 const zic_t starttime; 1823 int type; 1824 { 1825 if (starttime <= min_time || 1826 (timecnt == 1 && attypes[0].at < min_time)) { 1827 gmtoffs[0] = gmtoffs[type]; 1828 isdsts[0] = isdsts[type]; 1829 ttisstds[0] = ttisstds[type]; 1830 ttisgmts[0] = ttisgmts[type]; 1831 if (abbrinds[type] != 0) 1832 (void) strcpy(chars, &chars[abbrinds[type]]); 1833 abbrinds[0] = 0; 1834 charcnt = strlen(chars) + 1; 1835 typecnt = 1; 1836 timecnt = 0; 1837 type = 0; 1838 } 1839 if (timecnt >= TZ_MAX_TIMES) { 1840 error(gettext("too many transitions?!")); 1841 exit(EXIT_FAILURE); 1842 } 1843 attypes[timecnt].at = starttime; 1844 attypes[timecnt].type = type; 1845 ++timecnt; 1846 } 1847 1848 static int 1849 addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) 1850 const long gmtoff; 1851 const char * const abbr; 1852 const int isdst; 1853 const int ttisstd; 1854 const int ttisgmt; 1855 { 1856 register int i, j; 1857 1858 if (isdst != TRUE && isdst != FALSE) { 1859 error(gettext( 1860 "internal error - addtype called with bad isdst")); 1861 exit(EXIT_FAILURE); 1862 } 1863 if (ttisstd != TRUE && ttisstd != FALSE) { 1864 error(gettext( 1865 "internal error - addtype called with bad ttisstd")); 1866 exit(EXIT_FAILURE); 1867 } 1868 if (ttisgmt != TRUE && ttisgmt != FALSE) { 1869 error(gettext( 1870 "internal error - addtype called with bad ttisgmt")); 1871 exit(EXIT_FAILURE); 1872 } 1873 /* 1874 * See if there's already an entry for this zone type. 1875 * If so, just return its index. 1876 */ 1877 for (i = 0; i < typecnt; ++i) { 1878 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 1879 strcmp(abbr, &chars[abbrinds[i]]) == 0 && 1880 ttisstd == ttisstds[i] && 1881 ttisgmt == ttisgmts[i]) 1882 return (i); 1883 } 1884 /* 1885 * There isn't one; add a new one, unless there are already too 1886 * many. 1887 */ 1888 if (typecnt >= TZ_MAX_TYPES) { 1889 error(gettext("too many local time types")); 1890 exit(EXIT_FAILURE); 1891 } 1892 if (!(-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { 1893 error(gettext("UTC offset out of range")); 1894 exit(EXIT_FAILURE); 1895 } 1896 gmtoffs[i] = gmtoff; 1897 isdsts[i] = isdst; 1898 ttisstds[i] = ttisstd; 1899 ttisgmts[i] = ttisgmt; 1900 1901 for (j = 0; j < charcnt; ++j) 1902 if (strcmp(&chars[j], abbr) == 0) 1903 break; 1904 if (j == charcnt) 1905 newabbr(abbr); 1906 abbrinds[i] = j; 1907 ++typecnt; 1908 return (i); 1909 } 1910 1911 #ifdef LEAPSECOND_SUPPORT 1912 static void 1913 leapadd(t, positive, rolling, count) 1914 const zic_t t; 1915 const int positive; 1916 const int rolling; 1917 int count; 1918 { 1919 register int i, j; 1920 1921 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 1922 error(gettext("too many leap seconds")); 1923 exit(EXIT_FAILURE); 1924 } 1925 for (i = 0; i < leapcnt; ++i) 1926 if (t <= trans[i]) { 1927 if (t == trans[i]) { 1928 error(gettext("repeated leap second moment")); 1929 exit(EXIT_FAILURE); 1930 } 1931 break; 1932 } 1933 do { 1934 for (j = leapcnt; j > i; --j) { 1935 trans[j] = trans[j - 1]; 1936 corr[j] = corr[j - 1]; 1937 roll[j] = roll[j - 1]; 1938 } 1939 trans[i] = t; 1940 corr[i] = positive ? 1L : eitol(-count); 1941 roll[i] = rolling; 1942 ++leapcnt; 1943 } while (positive && --count != 0); 1944 } 1945 #endif /* LEAPSECOND_SUPPORT */ 1946 1947 #ifdef LEAPSECOND_SUPPORT 1948 static void 1949 adjleap(void) 1950 { 1951 register int i; 1952 register long last = 0; 1953 1954 /* 1955 * propagate leap seconds forward 1956 */ 1957 for (i = 0; i < leapcnt; ++i) { 1958 trans[i] = tadd(trans[i], last); 1959 last = corr[i] += last; 1960 } 1961 } 1962 #endif /* LEAPSECOND_SUPPORT */ 1963 1964 static int 1965 yearistype(year, type) 1966 const int year; 1967 const char * const type; 1968 { 1969 static char *buf; 1970 int result; 1971 1972 if (type == NULL || *type == '\0') 1973 return (TRUE); 1974 #if defined(sun) 1975 if (strcmp(type, "uspres") == 0) 1976 return ((year % 4) == 0); 1977 if (strcmp(type, "nonpres") == 0) 1978 return ((year % 4) != 0); 1979 if (strcmp(type, "even") == 0) 1980 return ((year % 2) == 0); 1981 if (strcmp(type, "odd") == 0) 1982 return ((year % 2) != 0); 1983 #endif /* defined(sun) */ 1984 1985 buf = erealloc(buf, (int)(132 + strlen(yitcommand) + strlen(type))); 1986 (void) sprintf(buf, "%s %d %s", yitcommand, year, type); 1987 result = system(buf); 1988 if (WIFEXITED(result)) { 1989 switch (WEXITSTATUS(result)) { 1990 case 0: 1991 return (TRUE); 1992 case 1: 1993 return (FALSE); 1994 } 1995 } 1996 error(gettext("Wild result from command execution")); 1997 (void) fprintf(stderr, gettext("%s: command was '%s', result was %d\n"), 1998 progname, buf, result); 1999 for (;;) 2000 exit(EXIT_FAILURE); 2001 } 2002 2003 static int 2004 lowerit(a) 2005 int a; 2006 { 2007 a = (unsigned char) a; 2008 return ((isascii(a) && isupper(a)) ? tolower(a) : a); 2009 } 2010 2011 static int 2012 ciequal(ap, bp) /* case-insensitive equality */ 2013 register const char *ap; 2014 register const char *bp; 2015 { 2016 while (lowerit(*ap) == lowerit(*bp++)) 2017 if (*ap++ == '\0') 2018 return (TRUE); 2019 return (FALSE); 2020 } 2021 2022 static int 2023 itsabbr(abbr, word) 2024 register const char *abbr; 2025 register const char *word; 2026 { 2027 if (lowerit(*abbr) != lowerit(*word)) 2028 return (FALSE); 2029 ++word; 2030 while (*++abbr != '\0') 2031 do { 2032 if (*word == '\0') 2033 return (FALSE); 2034 } while (lowerit(*word++) != lowerit(*abbr)); 2035 return (TRUE); 2036 } 2037 2038 static const struct lookup * 2039 byword(word, table) 2040 register const char * const word; 2041 register const struct lookup * const table; 2042 { 2043 register const struct lookup *foundlp; 2044 register const struct lookup *lp; 2045 2046 if (word == NULL || table == NULL) 2047 return (NULL); 2048 /* 2049 * Look for exact match. 2050 */ 2051 for (lp = table; lp->l_word != NULL; ++lp) 2052 if (ciequal(word, lp->l_word)) 2053 return (lp); 2054 /* 2055 * Look for inexact match. 2056 */ 2057 foundlp = NULL; 2058 for (lp = table; lp->l_word != NULL; ++lp) 2059 if (itsabbr(word, lp->l_word)) { 2060 if (foundlp == NULL) 2061 foundlp = lp; 2062 else return (NULL); /* multiple inexact matches */ 2063 } 2064 return (foundlp); 2065 } 2066 2067 static char ** 2068 getfields(cp) 2069 register char *cp; 2070 { 2071 register char *dp; 2072 register char **array; 2073 register int nsubs; 2074 2075 if (cp == NULL) 2076 return (NULL); 2077 array = (char **)(void *) 2078 emalloc((int)((strlen(cp) + 1) * sizeof (*array))); 2079 nsubs = 0; 2080 for (;;) { 2081 while (isascii(*cp) && isspace((unsigned char) *cp)) 2082 ++cp; 2083 if (*cp == '\0' || *cp == '#') 2084 break; 2085 array[nsubs++] = dp = cp; 2086 do { 2087 if ((*dp = *cp++) != '"') 2088 ++dp; 2089 else while ((*dp = *cp++) != '"') 2090 if (*dp != '\0') 2091 ++dp; 2092 else { 2093 error(gettext( 2094 "Odd number of quotation marks")); 2095 exit(1); 2096 } 2097 } while (*cp != '\0' && *cp != '#' && 2098 (!isascii(*cp) || !isspace((unsigned char) *cp))); 2099 if (isascii(*cp) && isspace((unsigned char) *cp)) 2100 ++cp; 2101 *dp = '\0'; 2102 } 2103 array[nsubs] = NULL; 2104 return (array); 2105 } 2106 2107 static long 2108 oadd(t1, t2) 2109 const long t1; 2110 const long t2; 2111 { 2112 register long t; 2113 2114 t = t1 + t2; 2115 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 2116 error(gettext("time overflow")); 2117 exit(EXIT_FAILURE); 2118 } 2119 return (t); 2120 } 2121 2122 static zic_t 2123 tadd(t1, t2) 2124 const zic_t t1; 2125 const long t2; 2126 { 2127 register zic_t t; 2128 2129 if (t1 == max_time && t2 > 0) 2130 return (max_time); 2131 if (t1 == min_time && t2 < 0) 2132 return (min_time); 2133 t = t1 + t2; 2134 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 2135 error(gettext("time overflow")); 2136 exit(EXIT_FAILURE); 2137 } 2138 return (t); 2139 } 2140 2141 /* 2142 * Given a rule, and a year, compute the date - in seconds since January 1, 2143 * 1970, 00:00 LOCAL time - in that year that the rule refers to. 2144 */ 2145 2146 static zic_t 2147 rpytime(rp, wantedy) 2148 register const struct rule * const rp; 2149 register const int wantedy; 2150 { 2151 register int y, m, i; 2152 register long dayoff; /* with a nod to Margaret O. */ 2153 register zic_t t; 2154 2155 if (wantedy == INT_MIN) 2156 return (min_time); 2157 if (wantedy == INT_MAX) 2158 return (max_time); 2159 dayoff = 0; 2160 m = TM_JANUARY; 2161 y = EPOCH_YEAR; 2162 while (wantedy != y) { 2163 if (wantedy > y) { 2164 i = len_years[isleap(y)]; 2165 ++y; 2166 } else { 2167 --y; 2168 i = -len_years[isleap(y)]; 2169 } 2170 dayoff = oadd(dayoff, eitol(i)); 2171 } 2172 while (m != rp->r_month) { 2173 i = len_months[isleap(y)][m]; 2174 dayoff = oadd(dayoff, eitol(i)); 2175 ++m; 2176 } 2177 i = rp->r_dayofmonth; 2178 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 2179 if (rp->r_dycode == DC_DOWLEQ) 2180 --i; 2181 else { 2182 error(gettext("use of 2/29 in non leap-year")); 2183 exit(EXIT_FAILURE); 2184 } 2185 } 2186 --i; 2187 dayoff = oadd(dayoff, eitol(i)); 2188 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 2189 register long wday; 2190 2191 #define LDAYSPERWEEK ((long)DAYSPERWEEK) 2192 wday = eitol(EPOCH_WDAY); 2193 /* 2194 * Don't trust mod of negative numbers. 2195 */ 2196 if (dayoff >= 0) 2197 wday = (wday + dayoff) % LDAYSPERWEEK; 2198 else { 2199 wday -= ((-dayoff) % LDAYSPERWEEK); 2200 if (wday < 0) 2201 wday += LDAYSPERWEEK; 2202 } 2203 while (wday != eitol(rp->r_wday)) 2204 if (rp->r_dycode == DC_DOWGEQ) { 2205 dayoff = oadd(dayoff, (long)1); 2206 if (++wday >= LDAYSPERWEEK) 2207 wday = 0; 2208 ++i; 2209 } else { 2210 dayoff = oadd(dayoff, (long)-1); 2211 if (--wday < 0) 2212 wday = LDAYSPERWEEK - 1; 2213 --i; 2214 } 2215 if (i < 0 || i >= len_months[isleap(y)][m]) { 2216 if (noise) 2217 warning(gettext("rule goes past start/end of " 2218 "month--will not work with pre-2004 " 2219 "versions of zic")); 2220 } 2221 } 2222 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) 2223 return (min_time); 2224 if (dayoff < min_time / SECSPERDAY) 2225 return (min_time); 2226 if (dayoff > max_time / SECSPERDAY) 2227 return (max_time); 2228 t = (zic_t)dayoff * SECSPERDAY; 2229 return (tadd(t, rp->r_tod)); 2230 } 2231 2232 static void 2233 newabbr(string) 2234 const char * const string; 2235 { 2236 register int i; 2237 2238 if (strcmp(string, GRANDPARENTED) != 0) { 2239 register const char *cp; 2240 register char *wp; 2241 2242 /* 2243 * Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics 2244 * optionally followed by a + or - and a number from 1 to 14. 2245 */ 2246 cp = string; 2247 wp = NULL; 2248 while (isascii(*cp) && isalpha(*cp)) 2249 ++cp; 2250 if (cp - string == 0) 2251 wp = gettext(("time zone abbreviation lacks " 2252 "alphabetic at start")); 2253 if (noise && cp - string > 3) 2254 wp = gettext(("time zone abbreviation has more than 3 " 2255 "alphabetics")); 2256 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 2257 wp = gettext(("time zone abbreviation has too many " 2258 "alphabetics")); 2259 if (wp == NULL && (*cp == '+' || *cp == '-')) { 2260 ++cp; 2261 if (isascii(*cp) && isdigit(*cp)) 2262 if (*cp++ == '1' && *cp >= '0' && *cp <= '4') 2263 ++cp; 2264 } 2265 if (*cp != '\0') 2266 wp = gettext("time zone abbreviation differs from " 2267 "POSIX standard"); 2268 if (wp != NULL) { 2269 wp = ecpyalloc(wp); 2270 wp = ecatalloc(wp, " ("); 2271 wp = ecatalloc(wp, string); 2272 wp = ecatalloc(wp, ")"); 2273 warning(wp); 2274 ifree(wp); 2275 } 2276 } 2277 i = strlen(string) + 1; 2278 if (charcnt + i > TZ_MAX_CHARS) { 2279 error(gettext("too many, or too long, time zone " 2280 "abbreviations")); 2281 exit(EXIT_FAILURE); 2282 } 2283 (void) strcpy(&chars[charcnt], string); 2284 charcnt += eitol(i); 2285 } 2286 2287 static int 2288 mkdirs(argname) 2289 char *argname; 2290 { 2291 register char *name; 2292 register char *cp; 2293 2294 if (argname == NULL || *argname == '\0') 2295 return (0); 2296 cp = name = ecpyalloc(argname); 2297 while ((cp = strchr(cp + 1, '/')) != 0) { 2298 *cp = '\0'; 2299 if (!itsdir(name)) { 2300 /* 2301 * It doesn't seem to exist, so we try to create it. 2302 * Creation may fail because of the directory being 2303 * created by some other multiprocessor, so we get 2304 * to do extra checking. 2305 */ 2306 if (mkdir(name, MKDIR_UMASK) != 0) { 2307 const char *e = strerror(errno); 2308 2309 if (errno != EEXIST || !itsdir(name)) { 2310 (void) fprintf(stderr, gettext( 2311 "%s: Can't create directory %s: %s\n"), 2312 progname, name, e); 2313 ifree(name); 2314 return (-1); 2315 } 2316 } 2317 } 2318 *cp = '/'; 2319 } 2320 ifree(name); 2321 return (0); 2322 } 2323 2324 static long 2325 eitol(i) 2326 const int i; 2327 { 2328 long l; 2329 2330 l = i; 2331 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 2332 (void) fprintf(stderr, 2333 gettext("%s: %d did not sign extend correctly\n"), 2334 progname, i); 2335 exit(EXIT_FAILURE); 2336 } 2337 return (l); 2338 } 2339 2340 /* 2341 * UNIX was a registered trademark of The Open Group in 2003. 2342 */ 2343