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