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