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