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