Annotation of 43BSDTahoe/etc/tzone/zic.c, revision 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.