Annotation of 43BSDTahoe/etc/tzone/zic.c, revision 1.1.1.1

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: */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.