[BACK]Return to zic.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / time

Annotation of src/lib/libc/time/zic.c, Revision 1.10

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

CVSweb <webmaster@jp.NetBSD.org>