[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.30

1.30    ! christos    1: /*     $NetBSD: zic.c,v 1.29 2011/09/04 10:10:26 christos Exp $        */
1.25      mlelstv     2: /*
                      3: ** This file is in the public domain, so clarified as of
                      4: ** 2006-07-17 by Arthur David Olson.
                      5: */
1.2       jtc         6:
1.26      tsutsui     7: #if HAVE_NBTOOL_CONFIG_H
                      8: #include "nbtool_config.h"
                      9: #endif
                     10:
1.9       christos   11: #include <sys/cdefs.h>
1.1       jtc        12: #ifndef lint
1.30    ! christos   13: __RCSID("$NetBSD: zic.c,v 1.29 2011/09/04 10:10:26 christos Exp $");
1.1       jtc        14: #endif /* !defined lint */
                     15:
1.30    ! christos   16: #include "version.h"
1.1       jtc        17: #include "private.h"
1.5       jtc        18: #include "locale.h"
1.1       jtc        19: #include "tzfile.h"
1.19      kleink     20:
1.25      mlelstv    21: #define        ZIC_VERSION     '2'
                     22:
                     23: typedef int_fast64_t   zic_t;
                     24:
                     25: #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
                     26: #define ZIC_MAX_ABBR_LEN_WO_WARN       6
                     27: #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
                     28:
1.19      kleink     29: #if HAVE_SYS_STAT_H
                     30: #include "sys/stat.h"
                     31: #endif
                     32: #ifdef S_IRUSR
                     33: #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
                     34: #else
                     35: #define MKDIR_UMASK 0755
                     36: #endif
                     37:
1.13      kleink     38: #include "unistd.h"
1.1       jtc        39:
1.3       jtc        40: /*
                     41: ** On some ancient hosts, predicates like `isspace(C)' are defined
1.25      mlelstv    42: ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
1.3       jtc        43: ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
                     44: ** Neither the C Standard nor Posix require that `isascii' exist.
                     45: ** For portability, we check both ancient and modern requirements.
                     46: ** If isascii is not defined, the isascii check succeeds trivially.
                     47: */
                     48: #include "ctype.h"
                     49: #ifndef isascii
                     50: #define isascii(x) 1
                     51: #endif
                     52:
1.25      mlelstv    53: #define OFFSET_STRLEN_MAXIMUM  (7 + INT_STRLEN_MAXIMUM(long))
                     54: #define RULE_STRLEN_MAXIMUM    8       /* "Mdd.dd.d" */
                     55:
                     56: #define end(cp)        (strchr((cp), '\0'))
                     57:
1.1       jtc        58: struct rule {
                     59:        const char *    r_filename;
                     60:        int             r_linenum;
                     61:        const char *    r_name;
                     62:
                     63:        int             r_loyear;       /* for example, 1986 */
                     64:        int             r_hiyear;       /* for example, 1986 */
                     65:        const char *    r_yrtype;
1.25      mlelstv    66:        int             r_lowasnum;
                     67:        int             r_hiwasnum;
1.1       jtc        68:
                     69:        int             r_month;        /* 0..11 */
                     70:
                     71:        int             r_dycode;       /* see below */
                     72:        int             r_dayofmonth;
                     73:        int             r_wday;
                     74:
                     75:        long            r_tod;          /* time from midnight */
                     76:        int             r_todisstd;     /* above is standard time if TRUE */
                     77:                                        /* or wall clock time if FALSE */
                     78:        int             r_todisgmt;     /* above is GMT if TRUE */
                     79:                                        /* or local time if FALSE */
                     80:        long            r_stdoff;       /* offset from standard time */
                     81:        const char *    r_abbrvar;      /* variable part of abbreviation */
                     82:
                     83:        int             r_todo;         /* a rule to do (used in outzone) */
1.25      mlelstv    84:        zic_t           r_temp;         /* used in outzone */
1.1       jtc        85: };
                     86:
                     87: /*
                     88: **     r_dycode                r_dayofmonth    r_wday
                     89: */
                     90:
                     91: #define DC_DOM         0       /* 1..31 */     /* unused */
                     92: #define DC_DOWGEQ      1       /* 1..31 */     /* 0..6 (Sun..Sat) */
                     93: #define DC_DOWLEQ      2       /* 1..31 */     /* 0..6 (Sun..Sat) */
                     94:
                     95: struct zone {
                     96:        const char *    z_filename;
                     97:        int             z_linenum;
                     98:
                     99:        const char *    z_name;
                    100:        long            z_gmtoff;
                    101:        const char *    z_rule;
                    102:        const char *    z_format;
                    103:
                    104:        long            z_stdoff;
                    105:
                    106:        struct rule *   z_rules;
                    107:        int             z_nrules;
                    108:
                    109:        struct rule     z_untilrule;
1.25      mlelstv   110:        zic_t           z_untiltime;
1.1       jtc       111: };
                    112:
1.25      mlelstv   113: extern int     getopt(int argc, char * const argv[],
                    114:                        const char * options);
                    115: extern int     link(const char * fromname, const char * toname);
1.1       jtc       116: extern char *  optarg;
                    117: extern int     optind;
                    118:
1.25      mlelstv   119: static void    addtt(zic_t starttime, int type);
                    120: static int     addtype(long gmtoff, const char * abbr, int isdst,
                    121:                                int ttisstd, int ttisgmt);
                    122: static void    leapadd(zic_t t, int positive, int rolling, int count);
                    123: static void    adjleap(void);
                    124: static void    associate(void);
                    125: static int     ciequal(const char * ap, const char * bp);
                    126: static void    convert(long val, char * buf);
                    127: static void    convert64(zic_t val, char * buf);
                    128: static void    dolink(const char * fromfield, const char * tofield);
                    129: static void    doabbr(char * abbr, const int, const char * format,
                    130:                        const char * letters, int isdst, int doquotes);
                    131: static void    eat(const char * name, int num);
                    132: static void    eats(const char * name, int num,
                    133:                        const char * rname, int rnum);
                    134: static long    eitol(int i);
                    135: static void    error(const char * message);
                    136: static char ** getfields(char * buf);
                    137: static long    gethms(const char * string, const char * errstrng,
                    138:                        int signable);
                    139: static void    infile(const char * filename);
                    140: static void    inleap(char ** fields, int nfields);
                    141: static void    inlink(char ** fields, int nfields);
                    142: static void    inrule(char ** fields, int nfields);
                    143: static int     inzcont(char ** fields, int nfields);
                    144: static int     inzone(char ** fields, int nfields);
                    145: static int     inzsub(char ** fields, int nfields, int iscont);
                    146: static int     is32(zic_t x);
                    147: static int     itsabbr(const char * abbr, const char * word);
                    148: static int     itsdir(const char * name);
                    149: static int     lowerit(int c);
                    150: int            main(int, char **);
                    151: static char *  memcheck(char * tocheck);
                    152: static int     mkdirs(char * filename);
                    153: static void    newabbr(const char * abbr);
                    154: static long    oadd(long t1, long t2);
                    155: static void    outzone(const struct zone * zp, int ntzones);
                    156: static void    puttzcode(long code, FILE * fp);
                    157: static void    puttzcode64(zic_t code, FILE * fp);
                    158: static int     rcomp(const void * leftp, const void * rightp);
                    159: static zic_t   rpytime(const struct rule * rp, int wantedy);
                    160: static void    rulesub(struct rule * rp,
1.1       jtc       161:                        const char * loyearp, const char * hiyearp,
                    162:                        const char * typep, const char * monthp,
1.25      mlelstv   163:                        const char * dayp, const char * timep);
                    164: static int     stringoffset(char * result, long offset);
                    165: static int     stringrule(char * result, const struct rule * rp,
                    166:                        long dstoff, long gmtoff);
                    167: static void    stringzone(char * result, const int,
                    168:                        const struct zone * zp, int ntzones);
                    169: static void    setboundaries(void);
                    170: static zic_t   tadd(zic_t t1, long t2);
                    171: static void    usage(FILE *stream, int status);
                    172: static void    warning(const char * const);
                    173: static void    writezone(const char * name, const char * string);
                    174: static int     yearistype(int year, const char * type);
                    175: static int     atcomp(const void *avp, const void *bvp);
                    176: static void    updateminmax(int x);
1.5       jtc       177:
1.1       jtc       178: static int             charcnt;
                    179: static int             errors;
                    180: static const char *    filename;
                    181: static int             leapcnt;
1.25      mlelstv   182: static int             leapseen;
                    183: static int             leapminyear;
                    184: static int             leapmaxyear;
1.1       jtc       185: static int             linenum;
1.25      mlelstv   186: static int             max_abbrvar_len;
                    187: static int             max_format_len;
                    188: static zic_t           max_time;
1.1       jtc       189: static int             max_year;
1.25      mlelstv   190: static zic_t           min_time;
1.1       jtc       191: static int             min_year;
                    192: static int             noise;
                    193: static const char *    rfilename;
                    194: static int             rlinenum;
                    195: static const char *    progname;
                    196: static int             timecnt;
                    197: static int             typecnt;
                    198:
                    199: /*
                    200: ** Line codes.
                    201: */
                    202:
                    203: #define LC_RULE                0
                    204: #define LC_ZONE                1
                    205: #define LC_LINK                2
                    206: #define LC_LEAP                3
                    207:
                    208: /*
                    209: ** Which fields are which on a Zone line.
                    210: */
                    211:
                    212: #define ZF_NAME                1
                    213: #define ZF_GMTOFF      2
                    214: #define ZF_RULE                3
                    215: #define ZF_FORMAT      4
                    216: #define ZF_TILYEAR     5
                    217: #define ZF_TILMONTH    6
                    218: #define ZF_TILDAY      7
                    219: #define ZF_TILTIME     8
                    220: #define ZONE_MINFIELDS 5
                    221: #define ZONE_MAXFIELDS 9
                    222:
                    223: /*
                    224: ** Which fields are which on a Zone continuation line.
                    225: */
                    226:
                    227: #define ZFC_GMTOFF     0
                    228: #define ZFC_RULE       1
                    229: #define ZFC_FORMAT     2
                    230: #define ZFC_TILYEAR    3
                    231: #define ZFC_TILMONTH   4
                    232: #define ZFC_TILDAY     5
                    233: #define ZFC_TILTIME    6
                    234: #define ZONEC_MINFIELDS        3
                    235: #define ZONEC_MAXFIELDS        7
                    236:
                    237: /*
                    238: ** Which files are which on a Rule line.
                    239: */
                    240:
                    241: #define RF_NAME                1
                    242: #define RF_LOYEAR      2
                    243: #define RF_HIYEAR      3
                    244: #define RF_COMMAND     4
                    245: #define RF_MONTH       5
                    246: #define RF_DAY         6
                    247: #define RF_TOD         7
                    248: #define RF_STDOFF      8
                    249: #define RF_ABBRVAR     9
                    250: #define RULE_FIELDS    10
                    251:
                    252: /*
                    253: ** Which fields are which on a Link line.
                    254: */
                    255:
                    256: #define LF_FROM                1
                    257: #define LF_TO          2
                    258: #define LINK_FIELDS    3
                    259:
                    260: /*
                    261: ** Which fields are which on a Leap line.
                    262: */
                    263:
                    264: #define LP_YEAR                1
                    265: #define LP_MONTH       2
                    266: #define LP_DAY         3
                    267: #define LP_TIME                4
                    268: #define LP_CORR                5
                    269: #define LP_ROLL                6
                    270: #define LEAP_FIELDS    7
                    271:
                    272: /*
                    273: ** Year synonyms.
                    274: */
                    275:
                    276: #define YR_MINIMUM     0
                    277: #define YR_MAXIMUM     1
                    278: #define YR_ONLY                2
                    279:
                    280: static struct rule *   rules;
                    281: static int             nrules; /* number of rules */
                    282:
                    283: static struct zone *   zones;
                    284: static int             nzones; /* number of zones */
                    285:
                    286: struct link {
                    287:        const char *    l_filename;
                    288:        int             l_linenum;
                    289:        const char *    l_from;
                    290:        const char *    l_to;
                    291: };
                    292:
                    293: static struct link *   links;
                    294: static int             nlinks;
                    295:
                    296: struct lookup {
                    297:        const char *    l_word;
                    298:        const int       l_value;
                    299: };
                    300:
1.25      mlelstv   301: static struct lookup const *   byword(const char * string,
                    302:                                        const struct lookup * lp);
1.1       jtc       303:
                    304: static struct lookup const     line_codes[] = {
                    305:        { "Rule",       LC_RULE },
                    306:        { "Zone",       LC_ZONE },
                    307:        { "Link",       LC_LINK },
                    308:        { "Leap",       LC_LEAP },
                    309:        { NULL,         0}
                    310: };
                    311:
                    312: static struct lookup const     mon_names[] = {
                    313:        { "January",    TM_JANUARY },
                    314:        { "February",   TM_FEBRUARY },
                    315:        { "March",      TM_MARCH },
                    316:        { "April",      TM_APRIL },
                    317:        { "May",        TM_MAY },
                    318:        { "June",       TM_JUNE },
                    319:        { "July",       TM_JULY },
                    320:        { "August",     TM_AUGUST },
                    321:        { "September",  TM_SEPTEMBER },
                    322:        { "October",    TM_OCTOBER },
                    323:        { "November",   TM_NOVEMBER },
                    324:        { "December",   TM_DECEMBER },
                    325:        { NULL,         0 }
                    326: };
                    327:
                    328: static struct lookup const     wday_names[] = {
                    329:        { "Sunday",     TM_SUNDAY },
                    330:        { "Monday",     TM_MONDAY },
                    331:        { "Tuesday",    TM_TUESDAY },
                    332:        { "Wednesday",  TM_WEDNESDAY },
                    333:        { "Thursday",   TM_THURSDAY },
                    334:        { "Friday",     TM_FRIDAY },
                    335:        { "Saturday",   TM_SATURDAY },
                    336:        { NULL,         0 }
                    337: };
                    338:
                    339: static struct lookup const     lasts[] = {
                    340:        { "last-Sunday",        TM_SUNDAY },
                    341:        { "last-Monday",        TM_MONDAY },
                    342:        { "last-Tuesday",       TM_TUESDAY },
                    343:        { "last-Wednesday",     TM_WEDNESDAY },
                    344:        { "last-Thursday",      TM_THURSDAY },
                    345:        { "last-Friday",        TM_FRIDAY },
                    346:        { "last-Saturday",      TM_SATURDAY },
                    347:        { NULL,                 0 }
                    348: };
                    349:
                    350: static struct lookup const     begin_years[] = {
                    351:        { "minimum",    YR_MINIMUM },
                    352:        { "maximum",    YR_MAXIMUM },
                    353:        { NULL,         0 }
                    354: };
                    355:
                    356: static struct lookup const     end_years[] = {
                    357:        { "minimum",    YR_MINIMUM },
                    358:        { "maximum",    YR_MAXIMUM },
                    359:        { "only",       YR_ONLY },
                    360:        { NULL,         0 }
                    361: };
                    362:
                    363: static struct lookup const     leap_types[] = {
                    364:        { "Rolling",    TRUE },
                    365:        { "Stationary", FALSE },
                    366:        { NULL,         0 }
                    367: };
                    368:
                    369: static const int       len_months[2][MONSPERYEAR] = {
                    370:        { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
                    371:        { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
                    372: };
                    373:
                    374: static const int       len_years[2] = {
                    375:        DAYSPERNYEAR, DAYSPERLYEAR
                    376: };
                    377:
1.5       jtc       378: static struct attype {
1.25      mlelstv   379:        zic_t           at;
1.5       jtc       380:        unsigned char   type;
                    381: }                      attypes[TZ_MAX_TIMES];
1.1       jtc       382: static long            gmtoffs[TZ_MAX_TYPES];
                    383: static char            isdsts[TZ_MAX_TYPES];
                    384: static unsigned char   abbrinds[TZ_MAX_TYPES];
                    385: static char            ttisstds[TZ_MAX_TYPES];
                    386: static char            ttisgmts[TZ_MAX_TYPES];
                    387: static char            chars[TZ_MAX_CHARS];
1.25      mlelstv   388: static zic_t           trans[TZ_MAX_LEAPS];
1.1       jtc       389: static long            corr[TZ_MAX_LEAPS];
                    390: static char            roll[TZ_MAX_LEAPS];
                    391:
                    392: /*
                    393: ** Memory allocation.
                    394: */
                    395:
                    396: static char *
                    397: memcheck(ptr)
                    398: char * const   ptr;
                    399: {
                    400:        if (ptr == NULL) {
1.5       jtc       401:                const char *e = strerror(errno);
1.7       jtc       402:
1.5       jtc       403:                (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
                    404:                        progname, e);
1.25      mlelstv   405:                exit(EXIT_FAILURE);
1.1       jtc       406:        }
                    407:        return ptr;
                    408: }
                    409:
                    410: #define emalloc(size)          memcheck(imalloc(size))
                    411: #define erealloc(ptr, size)    memcheck(irealloc((ptr), (size)))
                    412: #define ecpyalloc(ptr)         memcheck(icpyalloc(ptr))
                    413: #define ecatalloc(oldp, newp)  memcheck(icatalloc((oldp), (newp)))
                    414:
                    415: /*
                    416: ** Error handling.
                    417: */
                    418:
                    419: static void
                    420: eats(name, num, rname, rnum)
                    421: const char * const     name;
                    422: const int              num;
                    423: const char * const     rname;
                    424: const int              rnum;
                    425: {
                    426:        filename = name;
                    427:        linenum = num;
                    428:        rfilename = rname;
                    429:        rlinenum = rnum;
                    430: }
                    431:
                    432: static void
                    433: eat(name, num)
                    434: const char * const     name;
                    435: const int              num;
                    436: {
                    437:        eats(name, num, (char *) NULL, -1);
                    438: }
                    439:
                    440: static void
                    441: error(string)
                    442: const char * const     string;
                    443: {
                    444:        /*
                    445:        ** Match the format of "cc" to allow sh users to
                    446:        **      zic ... 2>&1 | error -t "*" -v
                    447:        ** on BSD systems.
                    448:        */
1.5       jtc       449:        (void) fprintf(stderr, _("\"%s\", line %d: %s"),
1.1       jtc       450:                filename, linenum, string);
                    451:        if (rfilename != NULL)
1.5       jtc       452:                (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
1.1       jtc       453:                        rfilename, rlinenum);
                    454:        (void) fprintf(stderr, "\n");
                    455:        ++errors;
                    456: }
                    457:
                    458: static void
1.5       jtc       459: warning(string)
                    460: const char * const     string;
                    461: {
                    462:        char *  cp;
                    463:
1.15      kleink    464:        cp = ecpyalloc(_("warning: "));
1.5       jtc       465:        cp = ecatalloc(cp, string);
1.7       jtc       466:        error(cp);
1.5       jtc       467:        ifree(cp);
                    468:        --errors;
                    469: }
                    470:
                    471: static void
1.25      mlelstv   472: usage(FILE *stream, int status)
1.1       jtc       473: {
1.25      mlelstv   474:        (void) fprintf(stream, _("%s: usage is %s \
                    475: [ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
                    476: \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
                    477: \n\
                    478: Report bugs to tz@elsie.nci.nih.gov.\n"),
                    479:                       progname, progname);
                    480:        exit(status);
1.1       jtc       481: }
                    482:
                    483: static const char *    psxrules;
                    484: static const char *    lcltime;
                    485: static const char *    directory;
                    486: static const char *    leapsec;
                    487: static const char *    yitcommand;
                    488:
                    489: int
                    490: main(argc, argv)
                    491: int    argc;
                    492: char * argv[];
                    493: {
                    494:        register int    i;
                    495:        register int    j;
                    496:        register int    c;
                    497:
1.13      kleink    498: #ifdef _POSIX_VERSION
1.1       jtc       499:        (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
1.13      kleink    500: #endif /* defined _POSIX_VERSION */
1.5       jtc       501: #if HAVE_GETTEXT - 0
                    502:        (void) setlocale(LC_MESSAGES, "");
                    503: #ifdef TZ_DOMAINDIR
                    504:        (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
                    505: #endif /* defined TEXTDOMAINDIR */
                    506:        (void) textdomain(TZ_DOMAIN);
1.25      mlelstv   507: #endif /* HAVE_GETTEXT */
1.1       jtc       508:        progname = argv[0];
1.25      mlelstv   509:        if (TYPE_BIT(zic_t) < 64) {
                    510:                (void) fprintf(stderr, "%s: %s\n", progname,
                    511:                        _("wild compilation-time specification of zic_t"));
                    512:                exit(EXIT_FAILURE);
                    513:        }
1.20      kleink    514:        for (i = 1; i < argc; ++i)
                    515:                if (strcmp(argv[i], "--version") == 0) {
1.30    ! christos  516:                        (void) printf("%s\n", TZVERSION);
1.25      mlelstv   517:                        exit(EXIT_SUCCESS);
                    518:                } else if (strcmp(argv[i], "--help") == 0) {
                    519:                        usage(stdout, EXIT_SUCCESS);
1.20      kleink    520:                }
1.7       jtc       521:        while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
1.1       jtc       522:                switch (c) {
                    523:                        default:
1.25      mlelstv   524:                                usage(stderr, EXIT_FAILURE);
1.1       jtc       525:                        case 'd':
                    526:                                if (directory == NULL)
                    527:                                        directory = optarg;
                    528:                                else {
                    529:                                        (void) fprintf(stderr,
1.5       jtc       530: _("%s: More than one -d option specified\n"),
1.1       jtc       531:                                                progname);
1.25      mlelstv   532:                                        exit(EXIT_FAILURE);
1.1       jtc       533:                                }
                    534:                                break;
                    535:                        case 'l':
                    536:                                if (lcltime == NULL)
                    537:                                        lcltime = optarg;
                    538:                                else {
                    539:                                        (void) fprintf(stderr,
1.5       jtc       540: _("%s: More than one -l option specified\n"),
1.1       jtc       541:                                                progname);
1.25      mlelstv   542:                                        exit(EXIT_FAILURE);
1.1       jtc       543:                                }
                    544:                                break;
                    545:                        case 'p':
                    546:                                if (psxrules == NULL)
                    547:                                        psxrules = optarg;
                    548:                                else {
                    549:                                        (void) fprintf(stderr,
1.5       jtc       550: _("%s: More than one -p option specified\n"),
1.1       jtc       551:                                                progname);
1.25      mlelstv   552:                                        exit(EXIT_FAILURE);
1.1       jtc       553:                                }
                    554:                                break;
                    555:                        case 'y':
                    556:                                if (yitcommand == NULL)
                    557:                                        yitcommand = optarg;
                    558:                                else {
                    559:                                        (void) fprintf(stderr,
1.5       jtc       560: _("%s: More than one -y option specified\n"),
1.1       jtc       561:                                                progname);
1.25      mlelstv   562:                                        exit(EXIT_FAILURE);
1.1       jtc       563:                                }
                    564:                                break;
                    565:                        case 'L':
                    566:                                if (leapsec == NULL)
                    567:                                        leapsec = optarg;
                    568:                                else {
                    569:                                        (void) fprintf(stderr,
1.5       jtc       570: _("%s: More than one -L option specified\n"),
1.1       jtc       571:                                                progname);
1.25      mlelstv   572:                                        exit(EXIT_FAILURE);
1.1       jtc       573:                                }
                    574:                                break;
                    575:                        case 'v':
                    576:                                noise = TRUE;
                    577:                                break;
                    578:                        case 's':
1.25      mlelstv   579:                                (void) printf("%s: -s ignored\n", progname);
1.1       jtc       580:                                break;
                    581:                }
                    582:        if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
1.25      mlelstv   583:                usage(stderr, EXIT_FAILURE);    /* usage message by request */
1.1       jtc       584:        if (directory == NULL)
                    585:                directory = TZDIR;
                    586:        if (yitcommand == NULL)
                    587:                yitcommand = "yearistype";
                    588:
                    589:        setboundaries();
                    590:
                    591:        if (optind < argc && leapsec != NULL) {
                    592:                infile(leapsec);
                    593:                adjleap();
                    594:        }
                    595:
                    596:        for (i = optind; i < argc; ++i)
                    597:                infile(argv[i]);
                    598:        if (errors)
1.25      mlelstv   599:                exit(EXIT_FAILURE);
1.1       jtc       600:        associate();
                    601:        for (i = 0; i < nzones; i = j) {
                    602:                /*
                    603:                ** Find the next non-continuation zone entry.
                    604:                */
                    605:                for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
                    606:                        continue;
                    607:                outzone(&zones[i], j - i);
                    608:        }
                    609:        /*
                    610:        ** Make links.
                    611:        */
1.15      kleink    612:        for (i = 0; i < nlinks; ++i) {
                    613:                eat(links[i].l_filename, links[i].l_linenum);
1.1       jtc       614:                dolink(links[i].l_from, links[i].l_to);
1.25      mlelstv   615:                if (noise)
                    616:                        for (j = 0; j < nlinks; ++j)
                    617:                                if (strcmp(links[i].l_to,
                    618:                                        links[j].l_from) == 0)
                    619:                                                warning(_("link to link"));
1.15      kleink    620:        }
                    621:        if (lcltime != NULL) {
                    622:                eat("command line", 1);
1.1       jtc       623:                dolink(lcltime, TZDEFAULT);
1.15      kleink    624:        }
                    625:        if (psxrules != NULL) {
                    626:                eat("command line", 1);
1.1       jtc       627:                dolink(psxrules, TZDEFRULES);
1.15      kleink    628:        }
1.1       jtc       629:        return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
                    630: }
                    631:
                    632: static void
1.25      mlelstv   633: dolink(fromfield, tofield)
                    634: const char * const     fromfield;
                    635: const char * const     tofield;
1.1       jtc       636: {
                    637:        register char * fromname;
                    638:        register char * toname;
                    639:
1.25      mlelstv   640:        if (fromfield[0] == '/')
                    641:                fromname = ecpyalloc(fromfield);
1.1       jtc       642:        else {
                    643:                fromname = ecpyalloc(directory);
                    644:                fromname = ecatalloc(fromname, "/");
1.25      mlelstv   645:                fromname = ecatalloc(fromname, fromfield);
1.1       jtc       646:        }
1.25      mlelstv   647:        if (tofield[0] == '/')
                    648:                toname = ecpyalloc(tofield);
1.1       jtc       649:        else {
                    650:                toname = ecpyalloc(directory);
                    651:                toname = ecatalloc(toname, "/");
1.25      mlelstv   652:                toname = ecatalloc(toname, tofield);
1.1       jtc       653:        }
                    654:        /*
                    655:        ** We get to be careful here since
                    656:        ** there's a fair chance of root running us.
                    657:        */
                    658:        if (!itsdir(toname))
                    659:                (void) remove(toname);
                    660:        if (link(fromname, toname) != 0) {
1.12      kleink    661:                int     result;
                    662:
1.1       jtc       663:                if (mkdirs(toname) != 0)
1.25      mlelstv   664:                        exit(EXIT_FAILURE);
1.15      kleink    665:
1.12      kleink    666:                result = link(fromname, toname);
1.25      mlelstv   667: #if HAVE_SYMLINK
1.20      kleink    668:                if (result != 0 &&
1.25      mlelstv   669:                        access(fromname, F_OK) == 0 &&
                    670:                        !itsdir(fromname)) {
                    671:                                const char *s = tofield;
                    672:                                register char * symlinkcontents = NULL;
                    673:
                    674:                                while ((s = strchr(s+1, '/')) != NULL)
                    675:                                        symlinkcontents =
                    676:                                                ecatalloc(symlinkcontents,
                    677:                                                "../");
                    678:                                symlinkcontents =
                    679:                                        ecatalloc(symlinkcontents,
                    680:                                        fromname);
                    681:                                result = symlink(symlinkcontents,
                    682:                                        toname);
                    683:                                if (result == 0)
1.12      kleink    684: warning(_("hard link failed, symbolic link used"));
1.25      mlelstv   685:                                ifree(symlinkcontents);
1.12      kleink    686:                }
1.25      mlelstv   687: #endif /* HAVE_SYMLINK */
1.12      kleink    688:                if (result != 0) {
1.5       jtc       689:                        const char *e = strerror(errno);
1.7       jtc       690:
1.5       jtc       691:                        (void) fprintf(stderr,
                    692:                                _("%s: Can't link from %s to %s: %s\n"),
                    693:                                progname, fromname, toname, e);
1.25      mlelstv   694:                        exit(EXIT_FAILURE);
1.1       jtc       695:                }
                    696:        }
                    697:        ifree(fromname);
                    698:        ifree(toname);
                    699: }
                    700:
1.25      mlelstv   701: #define TIME_T_BITS_IN_FILE    64
1.3       jtc       702:
1.1       jtc       703: static void
1.25      mlelstv   704: setboundaries(void)
1.1       jtc       705: {
1.25      mlelstv   706:        register int    i;
                    707:
                    708:        min_time = -1;
                    709:        for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
                    710:                min_time *= 2;
                    711:        max_time = -(min_time + 1);
1.1       jtc       712: }
                    713:
                    714: static int
                    715: itsdir(name)
                    716: const char * const     name;
                    717: {
                    718:        register char * myname;
                    719:        register int    accres;
                    720:
                    721:        myname = ecpyalloc(name);
                    722:        myname = ecatalloc(myname, "/.");
                    723:        accres = access(myname, F_OK);
                    724:        ifree(myname);
                    725:        return accres == 0;
                    726: }
                    727:
                    728: /*
                    729: ** Associate sets of rules with zones.
                    730: */
                    731:
                    732: /*
                    733: ** Sort by rule name.
                    734: */
                    735:
                    736: static int
                    737: rcomp(cp1, cp2)
                    738: const void *   cp1;
                    739: const void *   cp2;
                    740: {
                    741:        return strcmp(((const struct rule *) cp1)->r_name,
                    742:                ((const struct rule *) cp2)->r_name);
                    743: }
                    744:
                    745: static void
1.25      mlelstv   746: associate(void)
1.1       jtc       747: {
                    748:        register struct zone *  zp;
                    749:        register struct rule *  rp;
                    750:        register int            base, out;
1.5       jtc       751:        register int            i, j;
1.1       jtc       752:
1.5       jtc       753:        if (nrules != 0) {
1.1       jtc       754:                (void) qsort((void *) rules, (size_t) nrules,
                    755:                        (size_t) sizeof *rules, rcomp);
1.5       jtc       756:                for (i = 0; i < nrules - 1; ++i) {
                    757:                        if (strcmp(rules[i].r_name,
                    758:                                rules[i + 1].r_name) != 0)
                    759:                                        continue;
                    760:                        if (strcmp(rules[i].r_filename,
                    761:                                rules[i + 1].r_filename) == 0)
                    762:                                        continue;
                    763:                        eat(rules[i].r_filename, rules[i].r_linenum);
                    764:                        warning(_("same rule name in multiple files"));
                    765:                        eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
                    766:                        warning(_("same rule name in multiple files"));
                    767:                        for (j = i + 2; j < nrules; ++j) {
                    768:                                if (strcmp(rules[i].r_name,
                    769:                                        rules[j].r_name) != 0)
                    770:                                                break;
                    771:                                if (strcmp(rules[i].r_filename,
                    772:                                        rules[j].r_filename) == 0)
                    773:                                                continue;
                    774:                                if (strcmp(rules[i + 1].r_filename,
                    775:                                        rules[j].r_filename) == 0)
                    776:                                                continue;
                    777:                                break;
                    778:                        }
                    779:                        i = j - 1;
                    780:                }
                    781:        }
1.1       jtc       782:        for (i = 0; i < nzones; ++i) {
                    783:                zp = &zones[i];
                    784:                zp->z_rules = NULL;
                    785:                zp->z_nrules = 0;
                    786:        }
                    787:        for (base = 0; base < nrules; base = out) {
                    788:                rp = &rules[base];
                    789:                for (out = base + 1; out < nrules; ++out)
                    790:                        if (strcmp(rp->r_name, rules[out].r_name) != 0)
                    791:                                break;
                    792:                for (i = 0; i < nzones; ++i) {
                    793:                        zp = &zones[i];
                    794:                        if (strcmp(zp->z_rule, rp->r_name) != 0)
                    795:                                continue;
                    796:                        zp->z_rules = rp;
                    797:                        zp->z_nrules = out - base;
                    798:                }
                    799:        }
                    800:        for (i = 0; i < nzones; ++i) {
                    801:                zp = &zones[i];
                    802:                if (zp->z_nrules == 0) {
                    803:                        /*
                    804:                        ** Maybe we have a local standard time offset.
                    805:                        */
                    806:                        eat(zp->z_filename, zp->z_linenum);
1.5       jtc       807:                        zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
1.25      mlelstv   808:                                TRUE);
1.1       jtc       809:                        /*
                    810:                        ** Note, though, that if there's no rule,
                    811:                        ** a '%s' in the format is a bad thing.
                    812:                        */
                    813:                        if (strchr(zp->z_format, '%') != 0)
1.5       jtc       814:                                error(_("%s in ruleless zone"));
1.1       jtc       815:                }
                    816:        }
                    817:        if (errors)
1.25      mlelstv   818:                exit(EXIT_FAILURE);
1.1       jtc       819: }
                    820:
                    821: static void
                    822: infile(name)
                    823: const char *   name;
                    824: {
                    825:        register FILE *                 fp;
                    826:        register char **                fields;
                    827:        register char *                 cp;
                    828:        register const struct lookup *  lp;
                    829:        register int                    nfields;
                    830:        register int                    wantcont;
                    831:        register int                    num;
                    832:        char                            buf[BUFSIZ];
                    833:
                    834:        if (strcmp(name, "-") == 0) {
1.5       jtc       835:                name = _("standard input");
1.1       jtc       836:                fp = stdin;
                    837:        } else if ((fp = fopen(name, "r")) == NULL) {
1.5       jtc       838:                const char *e = strerror(errno);
1.7       jtc       839:
1.5       jtc       840:                (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
                    841:                        progname, name, e);
1.25      mlelstv   842:                exit(EXIT_FAILURE);
1.1       jtc       843:        }
                    844:        wantcont = FALSE;
                    845:        for (num = 1; ; ++num) {
                    846:                eat(name, num);
                    847:                if (fgets(buf, (int) sizeof buf, fp) != buf)
                    848:                        break;
                    849:                cp = strchr(buf, '\n');
                    850:                if (cp == NULL) {
1.5       jtc       851:                        error(_("line too long"));
1.25      mlelstv   852:                        exit(EXIT_FAILURE);
1.1       jtc       853:                }
                    854:                *cp = '\0';
                    855:                fields = getfields(buf);
                    856:                nfields = 0;
                    857:                while (fields[nfields] != NULL) {
                    858:                        static char     nada;
                    859:
1.3       jtc       860:                        if (strcmp(fields[nfields], "-") == 0)
1.1       jtc       861:                                fields[nfields] = &nada;
                    862:                        ++nfields;
                    863:                }
                    864:                if (nfields == 0) {
                    865:                        /* nothing to do */
                    866:                } else if (wantcont) {
                    867:                        wantcont = inzcont(fields, nfields);
                    868:                } else {
                    869:                        lp = byword(fields[0], line_codes);
                    870:                        if (lp == NULL)
1.5       jtc       871:                                error(_("input line of unknown type"));
1.1       jtc       872:                        else switch ((int) (lp->l_value)) {
                    873:                                case LC_RULE:
                    874:                                        inrule(fields, nfields);
                    875:                                        wantcont = FALSE;
                    876:                                        break;
                    877:                                case LC_ZONE:
                    878:                                        wantcont = inzone(fields, nfields);
                    879:                                        break;
                    880:                                case LC_LINK:
                    881:                                        inlink(fields, nfields);
                    882:                                        wantcont = FALSE;
                    883:                                        break;
                    884:                                case LC_LEAP:
                    885:                                        if (name != leapsec)
                    886:                                                (void) fprintf(stderr,
1.5       jtc       887: _("%s: Leap line in non leap seconds file %s\n"),
1.1       jtc       888:                                                        progname, name);
                    889:                                        else    inleap(fields, nfields);
                    890:                                        wantcont = FALSE;
                    891:                                        break;
                    892:                                default:        /* "cannot happen" */
                    893:                                        (void) fprintf(stderr,
1.5       jtc       894: _("%s: panic: Invalid l_value %d\n"),
1.1       jtc       895:                                                progname, lp->l_value);
1.25      mlelstv   896:                                        exit(EXIT_FAILURE);
1.1       jtc       897:                        }
                    898:                }
                    899:                ifree((char *) fields);
                    900:        }
                    901:        if (ferror(fp)) {
1.5       jtc       902:                (void) fprintf(stderr, _("%s: Error reading %s\n"),
                    903:                        progname, filename);
1.25      mlelstv   904:                exit(EXIT_FAILURE);
1.1       jtc       905:        }
                    906:        if (fp != stdin && fclose(fp)) {
1.5       jtc       907:                const char *e = strerror(errno);
1.7       jtc       908:
1.5       jtc       909:                (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
                    910:                        progname, filename, e);
1.25      mlelstv   911:                exit(EXIT_FAILURE);
1.1       jtc       912:        }
                    913:        if (wantcont)
1.5       jtc       914:                error(_("expected continuation line not found"));
1.1       jtc       915: }
                    916:
                    917: /*
                    918: ** Convert a string of one of the forms
                    919: **     h       -h      hh:mm   -hh:mm  hh:mm:ss        -hh:mm:ss
                    920: ** into a number of seconds.
                    921: ** A null string maps to zero.
                    922: ** Call error with errstring and return zero on errors.
                    923: */
                    924:
                    925: static long
                    926: gethms(string, errstring, signable)
                    927: const char *           string;
                    928: const char * const     errstring;
                    929: const int              signable;
                    930: {
1.25      mlelstv   931:        long    hh;
                    932:        int     mm, ss, sign;
1.1       jtc       933:
                    934:        if (string == NULL || *string == '\0')
                    935:                return 0;
                    936:        if (!signable)
                    937:                sign = 1;
                    938:        else if (*string == '-') {
                    939:                sign = -1;
                    940:                ++string;
                    941:        } else  sign = 1;
1.25      mlelstv   942:        if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
1.1       jtc       943:                mm = ss = 0;
1.25      mlelstv   944:        else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
1.1       jtc       945:                ss = 0;
1.25      mlelstv   946:        else if (sscanf(string, scheck(string, "%ld:%d:%d"),
1.1       jtc       947:                &hh, &mm, &ss) != 3) {
                    948:                        error(errstring);
                    949:                        return 0;
                    950:        }
1.25      mlelstv   951:        if (hh < 0 ||
1.1       jtc       952:                mm < 0 || mm >= MINSPERHOUR ||
1.25      mlelstv   953:                ss < 0 || ss > SECSPERMIN) {
1.1       jtc       954:                        error(errstring);
                    955:                        return 0;
                    956:        }
1.25      mlelstv   957:        if (LONG_MAX / SECSPERHOUR < hh) {
                    958:                error(_("time overflow"));
                    959:                return 0;
                    960:        }
                    961:        if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
1.21      kleink    962:                warning(_("24:00 not handled by pre-1998 versions of zic"));
1.25      mlelstv   963:        if (noise && (hh > HOURSPERDAY ||
                    964:                (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
                    965: warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
                    966:        return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
                    967:                    eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
1.1       jtc       968: }
                    969:
                    970: static void
                    971: inrule(fields, nfields)
                    972: register char ** const fields;
                    973: const int              nfields;
                    974: {
                    975:        static struct rule      r;
                    976:
                    977:        if (nfields != RULE_FIELDS) {
1.5       jtc       978:                error(_("wrong number of fields on Rule line"));
1.1       jtc       979:                return;
                    980:        }
                    981:        if (*fields[RF_NAME] == '\0') {
1.5       jtc       982:                error(_("nameless rule"));
1.1       jtc       983:                return;
                    984:        }
                    985:        r.r_filename = filename;
                    986:        r.r_linenum = linenum;
1.5       jtc       987:        r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
1.1       jtc       988:        rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
                    989:                fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
                    990:        r.r_name = ecpyalloc(fields[RF_NAME]);
                    991:        r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1.25      mlelstv   992:        if (max_abbrvar_len < strlen(r.r_abbrvar))
                    993:                max_abbrvar_len = strlen(r.r_abbrvar);
1.1       jtc       994:        rules = (struct rule *) (void *) erealloc((char *) rules,
                    995:                (int) ((nrules + 1) * sizeof *rules));
                    996:        rules[nrules++] = r;
                    997: }
                    998:
                    999: static int
                   1000: inzone(fields, nfields)
                   1001: register char ** const fields;
                   1002: const int              nfields;
                   1003: {
                   1004:        register int    i;
                   1005:        static char *   buf;
                   1006:
                   1007:        if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1.5       jtc      1008:                error(_("wrong number of fields on Zone line"));
1.1       jtc      1009:                return FALSE;
                   1010:        }
                   1011:        if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
                   1012:                buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
1.6       mrg      1013:                (void)sprintf(buf,      /* XXX: sprintf is safe */
1.5       jtc      1014: _("\"Zone %s\" line and -l option are mutually exclusive"),
1.1       jtc      1015:                        TZDEFAULT);
                   1016:                error(buf);
                   1017:                return FALSE;
                   1018:        }
                   1019:        if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
                   1020:                buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
1.6       mrg      1021:                (void)sprintf(buf,      /* XXX: sprintf is safe */
1.5       jtc      1022: _("\"Zone %s\" line and -p option are mutually exclusive"),
1.1       jtc      1023:                        TZDEFRULES);
                   1024:                error(buf);
                   1025:                return FALSE;
                   1026:        }
                   1027:        for (i = 0; i < nzones; ++i)
                   1028:                if (zones[i].z_name != NULL &&
                   1029:                        strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
                   1030:                                buf = erealloc(buf, (int) (132 +
                   1031:                                        strlen(fields[ZF_NAME]) +
                   1032:                                        strlen(zones[i].z_filename)));
1.6       mrg      1033:                                (void)sprintf(buf,      /* XXX: sprintf is safe */
1.5       jtc      1034: _("duplicate zone name %s (file \"%s\", line %d)"),
1.1       jtc      1035:                                        fields[ZF_NAME],
                   1036:                                        zones[i].z_filename,
                   1037:                                        zones[i].z_linenum);
                   1038:                                error(buf);
                   1039:                                return FALSE;
                   1040:                }
                   1041:        return inzsub(fields, nfields, FALSE);
                   1042: }
                   1043:
                   1044: static int
                   1045: inzcont(fields, nfields)
                   1046: register char ** const fields;
                   1047: const int              nfields;
                   1048: {
                   1049:        if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1.5       jtc      1050:                error(_("wrong number of fields on Zone continuation line"));
1.1       jtc      1051:                return FALSE;
                   1052:        }
                   1053:        return inzsub(fields, nfields, TRUE);
                   1054: }
                   1055:
                   1056: static int
                   1057: inzsub(fields, nfields, iscont)
                   1058: register char ** const fields;
                   1059: const int              nfields;
                   1060: const int              iscont;
                   1061: {
                   1062:        register char *         cp;
                   1063:        static struct zone      z;
                   1064:        register int            i_gmtoff, i_rule, i_format;
                   1065:        register int            i_untilyear, i_untilmonth;
                   1066:        register int            i_untilday, i_untiltime;
                   1067:        register int            hasuntil;
                   1068:
                   1069:        if (iscont) {
                   1070:                i_gmtoff = ZFC_GMTOFF;
                   1071:                i_rule = ZFC_RULE;
                   1072:                i_format = ZFC_FORMAT;
                   1073:                i_untilyear = ZFC_TILYEAR;
                   1074:                i_untilmonth = ZFC_TILMONTH;
                   1075:                i_untilday = ZFC_TILDAY;
                   1076:                i_untiltime = ZFC_TILTIME;
                   1077:                z.z_name = NULL;
                   1078:        } else {
                   1079:                i_gmtoff = ZF_GMTOFF;
                   1080:                i_rule = ZF_RULE;
                   1081:                i_format = ZF_FORMAT;
                   1082:                i_untilyear = ZF_TILYEAR;
                   1083:                i_untilmonth = ZF_TILMONTH;
                   1084:                i_untilday = ZF_TILDAY;
                   1085:                i_untiltime = ZF_TILTIME;
                   1086:                z.z_name = ecpyalloc(fields[ZF_NAME]);
                   1087:        }
                   1088:        z.z_filename = filename;
                   1089:        z.z_linenum = linenum;
1.11      jtc      1090:        z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
1.1       jtc      1091:        if ((cp = strchr(fields[i_format], '%')) != 0) {
                   1092:                if (*++cp != 's' || strchr(cp, '%') != 0) {
1.5       jtc      1093:                        error(_("invalid abbreviation format"));
1.1       jtc      1094:                        return FALSE;
                   1095:                }
                   1096:        }
                   1097:        z.z_rule = ecpyalloc(fields[i_rule]);
                   1098:        z.z_format = ecpyalloc(fields[i_format]);
1.25      mlelstv  1099:        if (max_format_len < strlen(z.z_format))
                   1100:                max_format_len = strlen(z.z_format);
1.1       jtc      1101:        hasuntil = nfields > i_untilyear;
                   1102:        if (hasuntil) {
                   1103:                z.z_untilrule.r_filename = filename;
                   1104:                z.z_untilrule.r_linenum = linenum;
                   1105:                rulesub(&z.z_untilrule,
                   1106:                        fields[i_untilyear],
                   1107:                        "only",
                   1108:                        "",
                   1109:                        (nfields > i_untilmonth) ?
                   1110:                        fields[i_untilmonth] : "Jan",
                   1111:                        (nfields > i_untilday) ? fields[i_untilday] : "1",
                   1112:                        (nfields > i_untiltime) ? fields[i_untiltime] : "0");
                   1113:                z.z_untiltime = rpytime(&z.z_untilrule,
                   1114:                        z.z_untilrule.r_loyear);
                   1115:                if (iscont && nzones > 0 &&
                   1116:                        z.z_untiltime > min_time &&
                   1117:                        z.z_untiltime < max_time &&
                   1118:                        zones[nzones - 1].z_untiltime > min_time &&
                   1119:                        zones[nzones - 1].z_untiltime < max_time &&
                   1120:                        zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1.25      mlelstv  1121:                                error(_(
                   1122: "Zone continuation line end time is not after end time of previous line"
                   1123:                                        ));
1.1       jtc      1124:                                return FALSE;
                   1125:                }
                   1126:        }
                   1127:        zones = (struct zone *) (void *) erealloc((char *) zones,
                   1128:                (int) ((nzones + 1) * sizeof *zones));
                   1129:        zones[nzones++] = z;
                   1130:        /*
                   1131:        ** If there was an UNTIL field on this line,
                   1132:        ** there's more information about the zone on the next line.
                   1133:        */
                   1134:        return hasuntil;
                   1135: }
                   1136:
                   1137: static void
                   1138: inleap(fields, nfields)
                   1139: register char ** const fields;
                   1140: const int              nfields;
                   1141: {
                   1142:        register const char *           cp;
                   1143:        register const struct lookup *  lp;
                   1144:        register int                    i, j;
                   1145:        int                             year, month, day;
                   1146:        long                            dayoff, tod;
1.25      mlelstv  1147:        zic_t                           t;
1.1       jtc      1148:
                   1149:        if (nfields != LEAP_FIELDS) {
1.5       jtc      1150:                error(_("wrong number of fields on Leap line"));
1.1       jtc      1151:                return;
                   1152:        }
                   1153:        dayoff = 0;
                   1154:        cp = fields[LP_YEAR];
                   1155:        if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1.25      mlelstv  1156:                /*
                   1157:                ** Leapin' Lizards!
                   1158:                */
                   1159:                error(_("invalid leaping year"));
                   1160:                return;
1.1       jtc      1161:        }
1.25      mlelstv  1162:        if (!leapseen || leapmaxyear < year)
                   1163:                leapmaxyear = year;
                   1164:        if (!leapseen || leapminyear > year)
                   1165:                leapminyear = year;
                   1166:        leapseen = TRUE;
1.1       jtc      1167:        j = EPOCH_YEAR;
                   1168:        while (j != year) {
                   1169:                if (year > j) {
                   1170:                        i = len_years[isleap(j)];
                   1171:                        ++j;
                   1172:                } else {
                   1173:                        --j;
                   1174:                        i = -len_years[isleap(j)];
                   1175:                }
                   1176:                dayoff = oadd(dayoff, eitol(i));
                   1177:        }
                   1178:        if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1.5       jtc      1179:                error(_("invalid month name"));
1.1       jtc      1180:                return;
                   1181:        }
                   1182:        month = lp->l_value;
                   1183:        j = TM_JANUARY;
                   1184:        while (j != month) {
                   1185:                i = len_months[isleap(year)][j];
                   1186:                dayoff = oadd(dayoff, eitol(i));
                   1187:                ++j;
                   1188:        }
                   1189:        cp = fields[LP_DAY];
                   1190:        if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
                   1191:                day <= 0 || day > len_months[isleap(year)][month]) {
1.5       jtc      1192:                        error(_("invalid day of month"));
1.1       jtc      1193:                        return;
                   1194:        }
                   1195:        dayoff = oadd(dayoff, eitol(day - 1));
1.25      mlelstv  1196:        if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1.5       jtc      1197:                error(_("time before zero"));
1.1       jtc      1198:                return;
                   1199:        }
1.20      kleink   1200:        if (dayoff < min_time / SECSPERDAY) {
                   1201:                error(_("time too small"));
                   1202:                return;
                   1203:        }
                   1204:        if (dayoff > max_time / SECSPERDAY) {
                   1205:                error(_("time too large"));
1.1       jtc      1206:                return;
                   1207:        }
1.25      mlelstv  1208:        t = (zic_t) dayoff * SECSPERDAY;
1.5       jtc      1209:        tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1.1       jtc      1210:        cp = fields[LP_CORR];
                   1211:        {
                   1212:                register int    positive;
                   1213:                int             count;
                   1214:
                   1215:                if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
                   1216:                        positive = FALSE;
                   1217:                        count = 1;
                   1218:                } else if (strcmp(cp, "--") == 0) {
                   1219:                        positive = FALSE;
                   1220:                        count = 2;
                   1221:                } else if (strcmp(cp, "+") == 0) {
                   1222:                        positive = TRUE;
                   1223:                        count = 1;
                   1224:                } else if (strcmp(cp, "++") == 0) {
                   1225:                        positive = TRUE;
                   1226:                        count = 2;
                   1227:                } else {
1.5       jtc      1228:                        error(_("illegal CORRECTION field on Leap line"));
1.1       jtc      1229:                        return;
                   1230:                }
                   1231:                if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1.25      mlelstv  1232:                        error(_(
                   1233:                                "illegal Rolling/Stationary field on Leap line"
                   1234:                                ));
1.1       jtc      1235:                        return;
                   1236:                }
                   1237:                leapadd(tadd(t, tod), positive, lp->l_value, count);
                   1238:        }
                   1239: }
                   1240:
                   1241: static void
                   1242: inlink(fields, nfields)
                   1243: register char ** const fields;
                   1244: const int              nfields;
                   1245: {
                   1246:        struct link     l;
                   1247:
                   1248:        if (nfields != LINK_FIELDS) {
1.5       jtc      1249:                error(_("wrong number of fields on Link line"));
1.1       jtc      1250:                return;
                   1251:        }
                   1252:        if (*fields[LF_FROM] == '\0') {
1.5       jtc      1253:                error(_("blank FROM field on Link line"));
1.1       jtc      1254:                return;
                   1255:        }
                   1256:        if (*fields[LF_TO] == '\0') {
1.5       jtc      1257:                error(_("blank TO field on Link line"));
1.1       jtc      1258:                return;
                   1259:        }
                   1260:        l.l_filename = filename;
                   1261:        l.l_linenum = linenum;
                   1262:        l.l_from = ecpyalloc(fields[LF_FROM]);
                   1263:        l.l_to = ecpyalloc(fields[LF_TO]);
                   1264:        links = (struct link *) (void *) erealloc((char *) links,
                   1265:                (int) ((nlinks + 1) * sizeof *links));
                   1266:        links[nlinks++] = l;
                   1267: }
                   1268:
                   1269: static void
                   1270: rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
                   1271: register struct rule * const   rp;
                   1272: const char * const             loyearp;
                   1273: const char * const             hiyearp;
                   1274: const char * const             typep;
                   1275: const char * const             monthp;
                   1276: const char * const             dayp;
                   1277: const char * const             timep;
                   1278: {
                   1279:        register const struct lookup *  lp;
                   1280:        register const char *           cp;
                   1281:        register char *                 dp;
                   1282:        register char *                 ep;
                   1283:
                   1284:        if ((lp = byword(monthp, mon_names)) == NULL) {
1.5       jtc      1285:                error(_("invalid month name"));
1.1       jtc      1286:                return;
                   1287:        }
                   1288:        rp->r_month = lp->l_value;
                   1289:        rp->r_todisstd = FALSE;
                   1290:        rp->r_todisgmt = FALSE;
                   1291:        dp = ecpyalloc(timep);
                   1292:        if (*dp != '\0') {
                   1293:                ep = dp + strlen(dp) - 1;
                   1294:                switch (lowerit(*ep)) {
                   1295:                        case 's':       /* Standard */
                   1296:                                rp->r_todisstd = TRUE;
                   1297:                                rp->r_todisgmt = FALSE;
                   1298:                                *ep = '\0';
                   1299:                                break;
                   1300:                        case 'w':       /* Wall */
                   1301:                                rp->r_todisstd = FALSE;
                   1302:                                rp->r_todisgmt = FALSE;
                   1303:                                *ep = '\0';
1.7       jtc      1304:                                break;
1.1       jtc      1305:                        case 'g':       /* Greenwich */
                   1306:                        case 'u':       /* Universal */
                   1307:                        case 'z':       /* Zulu */
                   1308:                                rp->r_todisstd = TRUE;
                   1309:                                rp->r_todisgmt = TRUE;
                   1310:                                *ep = '\0';
                   1311:                                break;
                   1312:                }
                   1313:        }
1.5       jtc      1314:        rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
1.1       jtc      1315:        ifree(dp);
                   1316:        /*
                   1317:        ** Year work.
                   1318:        */
                   1319:        cp = loyearp;
                   1320:        lp = byword(cp, begin_years);
1.25      mlelstv  1321:        rp->r_lowasnum = lp == NULL;
                   1322:        if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1.1       jtc      1323:                case YR_MINIMUM:
1.3       jtc      1324:                        rp->r_loyear = INT_MIN;
1.1       jtc      1325:                        break;
                   1326:                case YR_MAXIMUM:
1.3       jtc      1327:                        rp->r_loyear = INT_MAX;
1.1       jtc      1328:                        break;
                   1329:                default:        /* "cannot happen" */
                   1330:                        (void) fprintf(stderr,
1.5       jtc      1331:                                _("%s: panic: Invalid l_value %d\n"),
1.1       jtc      1332:                                progname, lp->l_value);
1.25      mlelstv  1333:                        exit(EXIT_FAILURE);
1.1       jtc      1334:        } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1.5       jtc      1335:                error(_("invalid starting year"));
1.1       jtc      1336:                return;
1.11      jtc      1337:        }
1.1       jtc      1338:        cp = hiyearp;
1.25      mlelstv  1339:        lp = byword(cp, end_years);
                   1340:        rp->r_hiwasnum = lp == NULL;
                   1341:        if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1.1       jtc      1342:                case YR_MINIMUM:
1.3       jtc      1343:                        rp->r_hiyear = INT_MIN;
1.1       jtc      1344:                        break;
                   1345:                case YR_MAXIMUM:
1.3       jtc      1346:                        rp->r_hiyear = INT_MAX;
1.1       jtc      1347:                        break;
                   1348:                case YR_ONLY:
                   1349:                        rp->r_hiyear = rp->r_loyear;
                   1350:                        break;
                   1351:                default:        /* "cannot happen" */
                   1352:                        (void) fprintf(stderr,
1.5       jtc      1353:                                _("%s: panic: Invalid l_value %d\n"),
1.1       jtc      1354:                                progname, lp->l_value);
1.25      mlelstv  1355:                        exit(EXIT_FAILURE);
1.1       jtc      1356:        } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1.5       jtc      1357:                error(_("invalid ending year"));
1.1       jtc      1358:                return;
1.11      jtc      1359:        }
1.1       jtc      1360:        if (rp->r_loyear > rp->r_hiyear) {
1.5       jtc      1361:                error(_("starting year greater than ending year"));
1.1       jtc      1362:                return;
                   1363:        }
                   1364:        if (*typep == '\0')
                   1365:                rp->r_yrtype = NULL;
                   1366:        else {
                   1367:                if (rp->r_loyear == rp->r_hiyear) {
1.5       jtc      1368:                        error(_("typed single year"));
1.1       jtc      1369:                        return;
                   1370:                }
                   1371:                rp->r_yrtype = ecpyalloc(typep);
                   1372:        }
                   1373:        /*
                   1374:        ** Day work.
                   1375:        ** Accept things such as:
                   1376:        **      1
                   1377:        **      last-Sunday
                   1378:        **      Sun<=20
                   1379:        **      Sun>=7
                   1380:        */
                   1381:        dp = ecpyalloc(dayp);
                   1382:        if ((lp = byword(dp, lasts)) != NULL) {
                   1383:                rp->r_dycode = DC_DOWLEQ;
                   1384:                rp->r_wday = lp->l_value;
                   1385:                rp->r_dayofmonth = len_months[1][rp->r_month];
                   1386:        } else {
                   1387:                if ((ep = strchr(dp, '<')) != 0)
                   1388:                        rp->r_dycode = DC_DOWLEQ;
                   1389:                else if ((ep = strchr(dp, '>')) != 0)
                   1390:                        rp->r_dycode = DC_DOWGEQ;
                   1391:                else {
                   1392:                        ep = dp;
                   1393:                        rp->r_dycode = DC_DOM;
                   1394:                }
                   1395:                if (rp->r_dycode != DC_DOM) {
                   1396:                        *ep++ = 0;
                   1397:                        if (*ep++ != '=') {
1.5       jtc      1398:                                error(_("invalid day of month"));
1.1       jtc      1399:                                ifree(dp);
                   1400:                                return;
                   1401:                        }
                   1402:                        if ((lp = byword(dp, wday_names)) == NULL) {
1.5       jtc      1403:                                error(_("invalid weekday name"));
1.1       jtc      1404:                                ifree(dp);
                   1405:                                return;
                   1406:                        }
                   1407:                        rp->r_wday = lp->l_value;
                   1408:                }
                   1409:                if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
                   1410:                        rp->r_dayofmonth <= 0 ||
                   1411:                        (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1.5       jtc      1412:                                error(_("invalid day of month"));
1.1       jtc      1413:                                ifree(dp);
                   1414:                                return;
                   1415:                }
                   1416:        }
                   1417:        ifree(dp);
                   1418: }
                   1419:
                   1420: static void
                   1421: convert(val, buf)
                   1422: const long     val;
                   1423: char * const   buf;
                   1424: {
                   1425:        register int    i;
1.25      mlelstv  1426:        register int    shift;
1.1       jtc      1427:
                   1428:        for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
                   1429:                buf[i] = val >> shift;
                   1430: }
                   1431:
                   1432: static void
1.25      mlelstv  1433: convert64(val, buf)
                   1434: const zic_t    val;
                   1435: char * const   buf;
                   1436: {
                   1437:        register int    i;
                   1438:        register int    shift;
                   1439:
                   1440:        for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
                   1441:                buf[i] = val >> shift;
                   1442: }
                   1443:
                   1444: static void
1.1       jtc      1445: puttzcode(val, fp)
                   1446: const long     val;
                   1447: FILE * const   fp;
                   1448: {
                   1449:        char    buf[4];
                   1450:
                   1451:        convert(val, buf);
                   1452:        (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
                   1453: }
                   1454:
1.25      mlelstv  1455: static void
                   1456: puttzcode64(val, fp)
                   1457: const zic_t    val;
                   1458: FILE * const   fp;
                   1459: {
                   1460:        char    buf[8];
                   1461:
                   1462:        convert64(val, buf);
                   1463:        (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
                   1464: }
                   1465:
1.5       jtc      1466: static int
                   1467: atcomp(avp, bvp)
1.10      lukem    1468: const void *   avp;
                   1469: const void *   bvp;
1.5       jtc      1470: {
1.25      mlelstv  1471:        const zic_t     a = ((const struct attype *) avp)->at;
                   1472:        const zic_t     b = ((const struct attype *) bvp)->at;
                   1473:
                   1474:        return (a < b) ? -1 : (a > b);
                   1475: }
                   1476:
                   1477: static int
                   1478: is32(x)
                   1479: const zic_t    x;
                   1480: {
                   1481:        return INT32_MIN <= x && x <= INT32_MAX;
1.5       jtc      1482: }
                   1483:
1.1       jtc      1484: static void
1.25      mlelstv  1485: writezone(name, string)
1.1       jtc      1486: const char * const     name;
1.25      mlelstv  1487: const char * const     string;
1.1       jtc      1488: {
1.25      mlelstv  1489:        register FILE *                 fp;
                   1490:        register int                    i, j;
                   1491:        register int                    leapcnt32, leapi32;
                   1492:        register int                    timecnt32, timei32;
                   1493:        register int                    pass;
                   1494:        static char *                   fullname;
                   1495:        static const struct tzhead      tzh0;
                   1496:        static struct tzhead            tzh;
                   1497:        zic_t                           ats[TZ_MAX_TIMES];
                   1498:        unsigned char                   types[TZ_MAX_TIMES];
1.5       jtc      1499:
                   1500:        /*
                   1501:        ** Sort.
                   1502:        */
                   1503:        if (timecnt > 1)
                   1504:                (void) qsort((void *) attypes, (size_t) timecnt,
                   1505:                        (size_t) sizeof *attypes, atcomp);
                   1506:        /*
                   1507:        ** Optimize.
                   1508:        */
                   1509:        {
                   1510:                int     fromi;
                   1511:                int     toi;
1.1       jtc      1512:
1.5       jtc      1513:                toi = 0;
                   1514:                fromi = 0;
1.7       jtc      1515:                while (fromi < timecnt && attypes[fromi].at < min_time)
                   1516:                        ++fromi;
1.5       jtc      1517:                if (isdsts[0] == 0)
1.7       jtc      1518:                        while (fromi < timecnt && attypes[fromi].type == 0)
1.5       jtc      1519:                                ++fromi;        /* handled by default rule */
                   1520:                for ( ; fromi < timecnt; ++fromi) {
1.25      mlelstv  1521:                        if (toi != 0 && ((attypes[fromi].at +
                   1522:                                gmtoffs[attypes[toi - 1].type]) <=
                   1523:                                (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
                   1524:                                : attypes[toi - 2].type]))) {
                   1525:                                        attypes[toi - 1].type =
                   1526:                                                attypes[fromi].type;
                   1527:                                        continue;
1.5       jtc      1528:                        }
                   1529:                        if (toi == 0 ||
                   1530:                                attypes[toi - 1].type != attypes[fromi].type)
                   1531:                                        attypes[toi++] = attypes[fromi];
                   1532:                }
                   1533:                timecnt = toi;
                   1534:        }
                   1535:        /*
                   1536:        ** Transfer.
                   1537:        */
                   1538:        for (i = 0; i < timecnt; ++i) {
                   1539:                ats[i] = attypes[i].at;
                   1540:                types[i] = attypes[i].type;
                   1541:        }
1.25      mlelstv  1542:        /*
                   1543:        ** Correct for leap seconds.
                   1544:        */
                   1545:        for (i = 0; i < timecnt; ++i) {
                   1546:                j = leapcnt;
                   1547:                while (--j >= 0)
                   1548:                        if (ats[i] > trans[j] - corr[j]) {
                   1549:                                ats[i] = tadd(ats[i], corr[j]);
                   1550:                                break;
                   1551:                        }
                   1552:        }
                   1553:        /*
                   1554:        ** Figure out 32-bit-limited starts and counts.
                   1555:        */
                   1556:        timecnt32 = timecnt;
                   1557:        timei32 = 0;
                   1558:        leapcnt32 = leapcnt;
                   1559:        leapi32 = 0;
                   1560:        while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
                   1561:                --timecnt32;
                   1562:        while (timecnt32 > 0 && !is32(ats[timei32])) {
                   1563:                --timecnt32;
                   1564:                ++timei32;
                   1565:        }
                   1566:        while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
                   1567:                --leapcnt32;
                   1568:        while (leapcnt32 > 0 && !is32(trans[leapi32])) {
                   1569:                --leapcnt32;
                   1570:                ++leapi32;
                   1571:        }
1.1       jtc      1572:        fullname = erealloc(fullname,
                   1573:                (int) (strlen(directory) + 1 + strlen(name) + 1));
1.7       jtc      1574:        (void) sprintf(fullname, "%s/%s", directory, name);     /* XXX: sprintf is safe */
                   1575:        /*
                   1576:        ** Remove old file, if any, to snap links.
                   1577:        */
                   1578:        if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
                   1579:                const char *e = strerror(errno);
                   1580:
                   1581:                (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
                   1582:                        progname, fullname, e);
1.25      mlelstv  1583:                exit(EXIT_FAILURE);
1.7       jtc      1584:        }
1.1       jtc      1585:        if ((fp = fopen(fullname, "wb")) == NULL) {
                   1586:                if (mkdirs(fullname) != 0)
1.25      mlelstv  1587:                        exit(EXIT_FAILURE);
1.1       jtc      1588:                if ((fp = fopen(fullname, "wb")) == NULL) {
1.5       jtc      1589:                        const char *e = strerror(errno);
1.7       jtc      1590:
1.5       jtc      1591:                        (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
                   1592:                                progname, fullname, e);
1.25      mlelstv  1593:                        exit(EXIT_FAILURE);
1.1       jtc      1594:                }
                   1595:        }
1.25      mlelstv  1596:        for (pass = 1; pass <= 2; ++pass) {
                   1597:                register int    thistimei, thistimecnt;
                   1598:                register int    thisleapi, thisleapcnt;
                   1599:                register int    thistimelim, thisleaplim;
                   1600:                int             writetype[TZ_MAX_TIMES];
                   1601:                int             typemap[TZ_MAX_TYPES];
                   1602:                register int    thistypecnt;
                   1603:                char            thischars[TZ_MAX_CHARS];
                   1604:                char            thischarcnt;
                   1605:                int             indmap[TZ_MAX_CHARS];
                   1606:
                   1607:                if (pass == 1) {
                   1608:                        thistimei = timei32;
                   1609:                        thistimecnt = timecnt32;
                   1610:                        thisleapi = leapi32;
                   1611:                        thisleapcnt = leapcnt32;
                   1612:                } else {
                   1613:                        thistimei = 0;
                   1614:                        thistimecnt = timecnt;
                   1615:                        thisleapi = 0;
                   1616:                        thisleapcnt = leapcnt;
                   1617:                }
                   1618:                thistimelim = thistimei + thistimecnt;
                   1619:                thisleaplim = thisleapi + thisleapcnt;
                   1620:                for (i = 0; i < typecnt; ++i)
                   1621:                        writetype[i] = thistimecnt == timecnt;
                   1622:                if (thistimecnt == 0) {
                   1623:                        /*
                   1624:                        ** No transition times fall in the current
                   1625:                        ** (32- or 64-bit) window.
                   1626:                        */
                   1627:                        if (typecnt != 0)
                   1628:                                writetype[typecnt - 1] = TRUE;
                   1629:                } else {
                   1630:                        for (i = thistimei - 1; i < thistimelim; ++i)
                   1631:                                if (i >= 0)
                   1632:                                        writetype[types[i]] = TRUE;
                   1633:                        /*
                   1634:                        ** For America/Godthab and Antarctica/Palmer
                   1635:                        */
                   1636:                        if (thistimei == 0)
                   1637:                                writetype[0] = TRUE;
                   1638:                }
1.29      christos 1639: #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
                   1640:                /*
                   1641:                ** For some pre-2011 systems: if the last-to-be-written
                   1642:                ** standard (or daylight) type has an offset different from the
                   1643:                ** most recently used offset,
                   1644:                ** append an (unused) copy of the most recently used type
                   1645:                ** (to help get global "altzone" and "timezone" variables
                   1646:                ** set correctly).
                   1647:                */
                   1648:                {
                   1649:                        register int    mrudst, mrustd, hidst, histd, type;
                   1650:
                   1651:                        hidst = histd = mrudst = mrustd = -1;
                   1652:                        for (i = thistimei; i < thistimelim; ++i)
                   1653:                                if (isdsts[types[i]])
                   1654:                                        mrudst = types[i];
                   1655:                                else    mrustd = types[i];
                   1656:                        for (i = 0; i < typecnt; ++i)
                   1657:                                if (writetype[i]) {
                   1658:                                        if (isdsts[i])
                   1659:                                                hidst = i;
                   1660:                                        else    histd = i;
                   1661:                                }
                   1662:                        if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
                   1663:                                gmtoffs[hidst] != gmtoffs[mrudst]) {
                   1664:                                        isdsts[mrudst] = -1;
                   1665:                                        type = addtype(gmtoffs[mrudst],
                   1666:                                                &chars[abbrinds[mrudst]],
                   1667:                                                TRUE,
                   1668:                                                ttisstds[mrudst],
                   1669:                                                ttisgmts[mrudst]);
                   1670:                                        isdsts[mrudst] = TRUE;
                   1671:                                        writetype[type] = TRUE;
                   1672:                        }
                   1673:                        if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
                   1674:                                gmtoffs[histd] != gmtoffs[mrustd]) {
                   1675:                                        isdsts[mrustd] = -1;
                   1676:                                        type = addtype(gmtoffs[mrustd],
                   1677:                                                &chars[abbrinds[mrustd]],
                   1678:                                                FALSE,
                   1679:                                                ttisstds[mrustd],
                   1680:                                                ttisgmts[mrustd]);
                   1681:                                        isdsts[mrustd] = FALSE;
                   1682:                                        writetype[type] = TRUE;
                   1683:                        }
                   1684:                }
                   1685: #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1.25      mlelstv  1686:                thistypecnt = 0;
                   1687:                for (i = 0; i < typecnt; ++i)
                   1688:                        typemap[i] = writetype[i] ?  thistypecnt++ : -1;
                   1689:                for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
                   1690:                        indmap[i] = -1;
                   1691:                thischarcnt = 0;
                   1692:                for (i = 0; i < typecnt; ++i) {
                   1693:                        register char * thisabbr;
                   1694:
                   1695:                        if (!writetype[i])
                   1696:                                continue;
                   1697:                        if (indmap[abbrinds[i]] >= 0)
                   1698:                                continue;
                   1699:                        thisabbr = &chars[abbrinds[i]];
                   1700:                        for (j = 0; j < thischarcnt; ++j)
                   1701:                                if (strcmp(&thischars[j], thisabbr) == 0)
                   1702:                                        break;
                   1703:                        if (j == thischarcnt) {
                   1704:                                (void) strcpy(&thischars[(int) thischarcnt],
                   1705:                                        thisabbr);
                   1706:                                thischarcnt += strlen(thisabbr) + 1;
                   1707:                        }
                   1708:                        indmap[abbrinds[i]] = j;
                   1709:                }
                   1710: #define DO(field)      (void) fwrite((void *) tzh.field, \
                   1711:                                (size_t) sizeof tzh.field, (size_t) 1, fp)
                   1712:                tzh = tzh0;
                   1713:                (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
                   1714:                tzh.tzh_version[0] = ZIC_VERSION;
                   1715:                convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
                   1716:                convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
                   1717:                convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
                   1718:                convert(eitol(thistimecnt), tzh.tzh_timecnt);
                   1719:                convert(eitol(thistypecnt), tzh.tzh_typecnt);
                   1720:                convert(eitol(thischarcnt), tzh.tzh_charcnt);
                   1721:                DO(tzh_magic);
                   1722:                DO(tzh_version);
                   1723:                DO(tzh_reserved);
                   1724:                DO(tzh_ttisgmtcnt);
                   1725:                DO(tzh_ttisstdcnt);
                   1726:                DO(tzh_leapcnt);
                   1727:                DO(tzh_timecnt);
                   1728:                DO(tzh_typecnt);
                   1729:                DO(tzh_charcnt);
1.1       jtc      1730: #undef DO
1.25      mlelstv  1731:                for (i = thistimei; i < thistimelim; ++i)
                   1732:                        if (pass == 1)
                   1733:                                puttzcode((long) ats[i], fp);
                   1734:                        else    puttzcode64(ats[i], fp);
                   1735:                for (i = thistimei; i < thistimelim; ++i) {
                   1736:                        unsigned char   uc;
                   1737:
                   1738:                        uc = typemap[types[i]];
                   1739:                        (void) fwrite((void *) &uc,
                   1740:                                (size_t) sizeof uc,
                   1741:                                (size_t) 1,
                   1742:                                fp);
                   1743:                }
                   1744:                for (i = 0; i < typecnt; ++i)
                   1745:                        if (writetype[i]) {
                   1746:                                puttzcode(gmtoffs[i], fp);
                   1747:                                (void) putc(isdsts[i], fp);
                   1748:                                (void) putc((unsigned char) indmap[abbrinds[i]], fp);
1.1       jtc      1749:                        }
1.25      mlelstv  1750:                if (thischarcnt != 0)
                   1751:                        (void) fwrite((void *) thischars,
                   1752:                                (size_t) sizeof thischars[0],
                   1753:                                (size_t) thischarcnt, fp);
                   1754:                for (i = thisleapi; i < thisleaplim; ++i) {
                   1755:                        register zic_t  todo;
                   1756:
                   1757:                        if (roll[i]) {
                   1758:                                if (timecnt == 0 || trans[i] < ats[0]) {
                   1759:                                        j = 0;
                   1760:                                        while (isdsts[j])
                   1761:                                                if (++j >= typecnt) {
                   1762:                                                        j = 0;
                   1763:                                                        break;
                   1764:                                                }
                   1765:                                } else {
                   1766:                                        j = 1;
                   1767:                                        while (j < timecnt &&
                   1768:                                                trans[i] >= ats[j])
                   1769:                                                        ++j;
                   1770:                                        j = types[j - 1];
                   1771:                                }
                   1772:                                todo = tadd(trans[i], -gmtoffs[j]);
                   1773:                        } else  todo = trans[i];
                   1774:                        if (pass == 1)
                   1775:                                puttzcode((long) todo, fp);
                   1776:                        else    puttzcode64(todo, fp);
                   1777:                        puttzcode(corr[i], fp);
                   1778:                }
                   1779:                for (i = 0; i < typecnt; ++i)
                   1780:                        if (writetype[i])
                   1781:                                (void) putc(ttisstds[i], fp);
                   1782:                for (i = 0; i < typecnt; ++i)
                   1783:                        if (writetype[i])
                   1784:                                (void) putc(ttisgmts[i], fp);
1.1       jtc      1785:        }
1.25      mlelstv  1786:        (void) fprintf(fp, "\n%s\n", string);
1.1       jtc      1787:        if (ferror(fp) || fclose(fp)) {
1.5       jtc      1788:                (void) fprintf(stderr, _("%s: Error writing %s\n"),
                   1789:                        progname, fullname);
1.25      mlelstv  1790:                exit(EXIT_FAILURE);
1.1       jtc      1791:        }
                   1792: }
                   1793:
                   1794: static void
1.25      mlelstv  1795: doabbr(abbr, abbrlen, format, letters, isdst, doquotes)
1.1       jtc      1796: char * const           abbr;
1.6       mrg      1797: const int              abbrlen;
1.1       jtc      1798: const char * const     format;
                   1799: const char * const     letters;
                   1800: const int              isdst;
1.25      mlelstv  1801: const int              doquotes;
1.1       jtc      1802: {
1.25      mlelstv  1803:        register char * cp;
                   1804:        register char * slashp;
                   1805:        register int    len;
                   1806:
                   1807:        slashp = strchr(format, '/');
                   1808:        if (slashp == NULL) {
1.1       jtc      1809:                if (letters == NULL)
1.25      mlelstv  1810:                        (void) strlcpy(abbr, format, abbrlen);
                   1811:                else    (void) snprintf(abbr, abbrlen, format, letters);
                   1812:        } else if (isdst) {
                   1813:                (void) strlcpy(abbr, slashp + 1, abbrlen);
                   1814:        } else {
                   1815:                if (slashp > format)
                   1816:                        (void) strncpy(abbr, format,
                   1817:                                (unsigned) (slashp - format));
                   1818:                abbr[slashp - format] = '\0';
                   1819:        }
                   1820:        if (!doquotes)
                   1821:                return;
                   1822:        for (cp = abbr; *cp != '\0'; ++cp)
                   1823:                if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
                   1824:                        strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
                   1825:                                break;
                   1826:        len = strlen(abbr);
                   1827:        if (len > 0 && *cp == '\0')
                   1828:                return;
                   1829:        abbr[len + 2] = '\0';
                   1830:        abbr[len + 1] = '>';
                   1831:        for ( ; len > 0; --len)
                   1832:                abbr[len] = abbr[len - 1];
                   1833:        abbr[0] = '<';
                   1834: }
                   1835:
                   1836: static void
                   1837: updateminmax(x)
                   1838: const int      x;
                   1839: {
                   1840:        if (min_year > x)
                   1841:                min_year = x;
                   1842:        if (max_year < x)
                   1843:                max_year = x;
                   1844: }
                   1845:
                   1846: static int
                   1847: stringoffset(result, offset)
                   1848: char * result;
                   1849: long   offset;
                   1850: {
                   1851:        register int    hours;
                   1852:        register int    minutes;
                   1853:        register int    seconds;
                   1854:
                   1855:        result[0] = '\0';
                   1856:        if (offset < 0) {
                   1857:                (void) strcpy(result, "-");
                   1858:                offset = -offset;
                   1859:        }
                   1860:        seconds = offset % SECSPERMIN;
                   1861:        offset /= SECSPERMIN;
                   1862:        minutes = offset % MINSPERHOUR;
                   1863:        offset /= MINSPERHOUR;
                   1864:        hours = offset;
                   1865:        if (hours >= HOURSPERDAY) {
                   1866:                result[0] = '\0';
                   1867:                return -1;
                   1868:        }
                   1869:        (void) sprintf(end(result), "%d", hours);
                   1870:        if (minutes != 0 || seconds != 0) {
                   1871:                (void) sprintf(end(result), ":%02d", minutes);
                   1872:                if (seconds != 0)
                   1873:                        (void) sprintf(end(result), ":%02d", seconds);
                   1874:        }
                   1875:        return 0;
                   1876: }
                   1877:
                   1878: static int
                   1879: stringrule(result, rp, dstoff, gmtoff)
                   1880: char *                         result;
                   1881: const struct rule * const      rp;
                   1882: const long                     dstoff;
                   1883: const long                     gmtoff;
                   1884: {
                   1885:        register long   tod;
                   1886:
                   1887:        result = end(result);
                   1888:        if (rp->r_dycode == DC_DOM) {
                   1889:                register int    month, total;
                   1890:
                   1891:                if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
                   1892:                        return -1;
                   1893:                total = 0;
                   1894:                for (month = 0; month < rp->r_month; ++month)
                   1895:                        total += len_months[0][month];
                   1896:                (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
                   1897:        } else {
                   1898:                register int    week;
                   1899:
                   1900:                if (rp->r_dycode == DC_DOWGEQ) {
1.29      christos 1901:                        if ((rp->r_dayofmonth % DAYSPERWEEK) != 1)
                   1902:                                return -1;
1.25      mlelstv  1903:                        week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
                   1904:                } else if (rp->r_dycode == DC_DOWLEQ) {
                   1905:                        if (rp->r_dayofmonth == len_months[1][rp->r_month])
                   1906:                                week = 5;
                   1907:                        else {
1.29      christos 1908:                                if ((rp->r_dayofmonth % DAYSPERWEEK) != 0)
1.25      mlelstv  1909:                                        return -1;
1.29      christos 1910:                                week = rp->r_dayofmonth / DAYSPERWEEK;
1.25      mlelstv  1911:                        }
                   1912:                } else  return -1;      /* "cannot happen" */
                   1913:                (void) sprintf(result, "M%d.%d.%d",
                   1914:                        rp->r_month + 1, week, rp->r_wday);
                   1915:        }
                   1916:        tod = rp->r_tod;
                   1917:        if (rp->r_todisgmt)
                   1918:                tod += gmtoff;
                   1919:        if (rp->r_todisstd && rp->r_stdoff == 0)
                   1920:                tod += dstoff;
                   1921:        if (tod < 0) {
                   1922:                result[0] = '\0';
                   1923:                return -1;
                   1924:        }
                   1925:        if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
                   1926:                (void) strcat(result, "/");
                   1927:                if (stringoffset(end(result), tod) != 0)
                   1928:                        return -1;
                   1929:        }
                   1930:        return 0;
                   1931: }
                   1932:
                   1933: static void
                   1934: stringzone(result, resultlen, zpfirst, zonecount)
                   1935: char *                         result;
                   1936: const int                      resultlen;
                   1937: const struct zone * const      zpfirst;
                   1938: const int                      zonecount;
                   1939: {
                   1940:        register const struct zone *    zp;
                   1941:        register struct rule *          rp;
                   1942:        register struct rule *          stdrp;
                   1943:        register struct rule *          dstrp;
                   1944:        register int                    i;
                   1945:        register const char *           abbrvar;
                   1946:
                   1947:        result[0] = '\0';
                   1948:        zp = zpfirst + zonecount - 1;
                   1949:        stdrp = dstrp = NULL;
                   1950:        for (i = 0; i < zp->z_nrules; ++i) {
                   1951:                rp = &zp->z_rules[i];
                   1952:                if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
                   1953:                        continue;
                   1954:                if (rp->r_yrtype != NULL)
                   1955:                        continue;
                   1956:                if (rp->r_stdoff == 0) {
                   1957:                        if (stdrp == NULL)
                   1958:                                stdrp = rp;
                   1959:                        else    return;
                   1960:                } else {
                   1961:                        if (dstrp == NULL)
                   1962:                                dstrp = rp;
                   1963:                        else    return;
                   1964:                }
                   1965:        }
                   1966:        if (stdrp == NULL && dstrp == NULL) {
                   1967:                /*
                   1968:                ** There are no rules running through "max".
                   1969:                ** Let's find the latest rule.
                   1970:                */
                   1971:                for (i = 0; i < zp->z_nrules; ++i) {
                   1972:                        rp = &zp->z_rules[i];
                   1973:                        if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
                   1974:                                (rp->r_hiyear == stdrp->r_hiyear &&
                   1975:                                rp->r_month > stdrp->r_month))
                   1976:                                        stdrp = rp;
                   1977:                }
                   1978:                if (stdrp != NULL && stdrp->r_stdoff != 0)
                   1979:                        return; /* We end up in DST (a POSIX no-no). */
                   1980:                /*
                   1981:                ** Horrid special case: if year is 2037,
                   1982:                ** presume this is a zone handled on a year-by-year basis;
                   1983:                ** do not try to apply a rule to the zone.
                   1984:                */
                   1985:                if (stdrp != NULL && stdrp->r_hiyear == 2037)
                   1986:                        return;
                   1987:        }
                   1988:        if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
                   1989:                return;
                   1990:        abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
                   1991:        doabbr(result, resultlen, zp->z_format, abbrvar, FALSE, TRUE);
                   1992:        if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
                   1993:                result[0] = '\0';
                   1994:                return;
                   1995:        }
                   1996:        if (dstrp == NULL)
                   1997:                return;
                   1998:        doabbr(end(result), resultlen - strlen(result),
                   1999:                zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
                   2000:        if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
                   2001:                if (stringoffset(end(result),
                   2002:                        -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
                   2003:                                result[0] = '\0';
                   2004:                                return;
                   2005:                }
                   2006:        (void) strcat(result, ",");
                   2007:        if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
                   2008:                result[0] = '\0';
                   2009:                return;
                   2010:        }
                   2011:        (void) strcat(result, ",");
                   2012:        if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
                   2013:                result[0] = '\0';
                   2014:                return;
1.1       jtc      2015:        }
                   2016: }
                   2017:
                   2018: static void
                   2019: outzone(zpfirst, zonecount)
                   2020: const struct zone * const      zpfirst;
                   2021: const int                      zonecount;
                   2022: {
                   2023:        register const struct zone *    zp;
                   2024:        register struct rule *          rp;
                   2025:        register int                    i, j;
                   2026:        register int                    usestart, useuntil;
1.25      mlelstv  2027:        register zic_t                  starttime, untiltime;
1.1       jtc      2028:        register long                   gmtoff;
                   2029:        register long                   stdoff;
                   2030:        register int                    year;
                   2031:        register long                   startoff;
                   2032:        register int                    startttisstd;
                   2033:        register int                    startttisgmt;
                   2034:        register int                    type;
1.25      mlelstv  2035:        register char *                 startbuf;
                   2036:        register char *                 ab;
                   2037:        register char *                 envvar;
                   2038:        register int                    max_abbr_len;
                   2039:        register int                    max_envvar_len;
1.29      christos 2040:        register int                    prodstic; /* all rules are min to max */
1.25      mlelstv  2041:
                   2042:        max_abbr_len = 2 + max_format_len + max_abbrvar_len;
                   2043:        max_envvar_len = 2 * max_abbr_len + 5 * 9;
                   2044:        startbuf = emalloc(max_abbr_len + 1);
                   2045:        ab = emalloc(max_abbr_len + 1);
                   2046:        envvar = emalloc(max_envvar_len + 1);
1.1       jtc      2047:        INITIALIZE(untiltime);
                   2048:        INITIALIZE(starttime);
                   2049:        /*
                   2050:        ** Now. . .finally. . .generate some useful data!
                   2051:        */
                   2052:        timecnt = 0;
                   2053:        typecnt = 0;
                   2054:        charcnt = 0;
1.29      christos 2055:        prodstic = zonecount == 1;
1.1       jtc      2056:        /*
1.25      mlelstv  2057:        ** Thanks to Earl Chew
1.1       jtc      2058:        ** for noting the need to unconditionally initialize startttisstd.
                   2059:        */
                   2060:        startttisstd = FALSE;
                   2061:        startttisgmt = FALSE;
1.25      mlelstv  2062:        min_year = max_year = EPOCH_YEAR;
                   2063:        if (leapseen) {
                   2064:                updateminmax(leapminyear);
                   2065:                updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
                   2066:        }
                   2067:        for (i = 0; i < zonecount; ++i) {
                   2068:                zp = &zpfirst[i];
                   2069:                if (i < zonecount - 1)
                   2070:                        updateminmax(zp->z_untilrule.r_loyear);
                   2071:                for (j = 0; j < zp->z_nrules; ++j) {
                   2072:                        rp = &zp->z_rules[j];
                   2073:                        if (rp->r_lowasnum)
                   2074:                                updateminmax(rp->r_loyear);
                   2075:                        if (rp->r_hiwasnum)
                   2076:                                updateminmax(rp->r_hiyear);
                   2077:                }
                   2078:        }
                   2079:        /*
                   2080:        ** Generate lots of data if a rule can't cover all future times.
                   2081:        */
                   2082:        stringzone(envvar, max_envvar_len+1, zpfirst, zonecount);
                   2083:        if (noise && envvar[0] == '\0') {
                   2084:                register char * wp;
                   2085:
                   2086: wp = ecpyalloc(_("no POSIX environment variable for zone"));
                   2087:                wp = ecatalloc(wp, " ");
                   2088:                wp = ecatalloc(wp, zpfirst->z_name);
                   2089:                warning(wp);
                   2090:                ifree(wp);
                   2091:        }
                   2092:        if (envvar[0] == '\0') {
                   2093:                if (min_year >= INT_MIN + YEARSPERREPEAT)
                   2094:                        min_year -= YEARSPERREPEAT;
                   2095:                else    min_year = INT_MIN;
                   2096:                if (max_year <= INT_MAX - YEARSPERREPEAT)
                   2097:                        max_year += YEARSPERREPEAT;
                   2098:                else    max_year = INT_MAX;
1.29      christos 2099:                /*
                   2100:                ** Regardless of any of the above,
                   2101:                ** for a "proDSTic" zone which specifies that its rules
                   2102:                ** always have and always will be in effect,
                   2103:                ** we only need one cycle to define the zone.
                   2104:                */
                   2105:                if (prodstic) {
                   2106:                        min_year = 1900;
                   2107:                        max_year = min_year + YEARSPERREPEAT;
                   2108:                }
1.25      mlelstv  2109:        }
                   2110:        /*
                   2111:        ** For the benefit of older systems,
                   2112:        ** generate data from 1900 through 2037.
                   2113:        */
                   2114:        if (min_year > 1900)
                   2115:                min_year = 1900;
                   2116:        if (max_year < 2037)
                   2117:                max_year = 2037;
1.1       jtc      2118:        for (i = 0; i < zonecount; ++i) {
1.19      kleink   2119:                /*
                   2120:                ** A guess that may well be corrected later.
                   2121:                */
                   2122:                stdoff = 0;
1.1       jtc      2123:                zp = &zpfirst[i];
                   2124:                usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
                   2125:                useuntil = i < (zonecount - 1);
                   2126:                if (useuntil && zp->z_untiltime <= min_time)
                   2127:                        continue;
                   2128:                gmtoff = zp->z_gmtoff;
                   2129:                eat(zp->z_filename, zp->z_linenum);
1.5       jtc      2130:                *startbuf = '\0';
                   2131:                startoff = zp->z_gmtoff;
1.1       jtc      2132:                if (zp->z_nrules == 0) {
                   2133:                        stdoff = zp->z_stdoff;
1.25      mlelstv  2134:                        doabbr(startbuf, max_abbr_len + 1, zp->z_format,
                   2135:                                (char *) NULL, stdoff != 0, FALSE);
1.1       jtc      2136:                        type = addtype(oadd(zp->z_gmtoff, stdoff),
                   2137:                                startbuf, stdoff != 0, startttisstd,
                   2138:                                startttisgmt);
1.5       jtc      2139:                        if (usestart) {
1.1       jtc      2140:                                addtt(starttime, type);
1.5       jtc      2141:                                usestart = FALSE;
1.19      kleink   2142:                        } else if (stdoff != 0)
1.1       jtc      2143:                                addtt(min_time, type);
                   2144:                } else for (year = min_year; year <= max_year; ++year) {
                   2145:                        if (useuntil && year > zp->z_untilrule.r_hiyear)
                   2146:                                break;
                   2147:                        /*
                   2148:                        ** Mark which rules to do in the current year.
                   2149:                        ** For those to do, calculate rpytime(rp, year);
                   2150:                        */
                   2151:                        for (j = 0; j < zp->z_nrules; ++j) {
                   2152:                                rp = &zp->z_rules[j];
                   2153:                                eats(zp->z_filename, zp->z_linenum,
                   2154:                                        rp->r_filename, rp->r_linenum);
                   2155:                                rp->r_todo = year >= rp->r_loyear &&
                   2156:                                                year <= rp->r_hiyear &&
                   2157:                                                yearistype(year, rp->r_yrtype);
                   2158:                                if (rp->r_todo)
                   2159:                                        rp->r_temp = rpytime(rp, year);
                   2160:                        }
                   2161:                        for ( ; ; ) {
                   2162:                                register int    k;
1.25      mlelstv  2163:                                register zic_t  jtime, ktime;
1.1       jtc      2164:                                register long   offset;
                   2165:
                   2166:                                INITIALIZE(ktime);
                   2167:                                if (useuntil) {
                   2168:                                        /*
1.11      jtc      2169:                                        ** Turn untiltime into UTC
1.1       jtc      2170:                                        ** assuming the current gmtoff and
                   2171:                                        ** stdoff values.
                   2172:                                        */
                   2173:                                        untiltime = zp->z_untiltime;
                   2174:                                        if (!zp->z_untilrule.r_todisgmt)
                   2175:                                                untiltime = tadd(untiltime,
                   2176:                                                        -gmtoff);
                   2177:                                        if (!zp->z_untilrule.r_todisstd)
                   2178:                                                untiltime = tadd(untiltime,
                   2179:                                                        -stdoff);
                   2180:                                }
                   2181:                                /*
                   2182:                                ** Find the rule (of those to do, if any)
                   2183:                                ** that takes effect earliest in the year.
                   2184:                                */
                   2185:                                k = -1;
                   2186:                                for (j = 0; j < zp->z_nrules; ++j) {
                   2187:                                        rp = &zp->z_rules[j];
                   2188:                                        if (!rp->r_todo)
                   2189:                                                continue;
                   2190:                                        eats(zp->z_filename, zp->z_linenum,
                   2191:                                                rp->r_filename, rp->r_linenum);
                   2192:                                        offset = rp->r_todisgmt ? 0 : gmtoff;
                   2193:                                        if (!rp->r_todisstd)
                   2194:                                                offset = oadd(offset, stdoff);
                   2195:                                        jtime = rp->r_temp;
                   2196:                                        if (jtime == min_time ||
                   2197:                                                jtime == max_time)
                   2198:                                                        continue;
                   2199:                                        jtime = tadd(jtime, -offset);
                   2200:                                        if (k < 0 || jtime < ktime) {
                   2201:                                                k = j;
                   2202:                                                ktime = jtime;
                   2203:                                        }
                   2204:                                }
                   2205:                                if (k < 0)
                   2206:                                        break;  /* go on to next year */
                   2207:                                rp = &zp->z_rules[k];
                   2208:                                rp->r_todo = FALSE;
                   2209:                                if (useuntil && ktime >= untiltime)
                   2210:                                        break;
1.5       jtc      2211:                                stdoff = rp->r_stdoff;
                   2212:                                if (usestart && ktime == starttime)
                   2213:                                        usestart = FALSE;
1.1       jtc      2214:                                if (usestart) {
1.5       jtc      2215:                                        if (ktime < starttime) {
                   2216:                                                startoff = oadd(zp->z_gmtoff,
                   2217:                                                        stdoff);
1.25      mlelstv  2218:                                                doabbr(startbuf,
                   2219:                                                        max_abbr_len + 1,
1.6       mrg      2220:                                                        zp->z_format,
1.5       jtc      2221:                                                        rp->r_abbrvar,
1.25      mlelstv  2222:                                                        rp->r_stdoff != 0,
                   2223:                                                        FALSE);
1.5       jtc      2224:                                                continue;
                   2225:                                        }
                   2226:                                        if (*startbuf == '\0' &&
1.25      mlelstv  2227:                                                startoff == oadd(zp->z_gmtoff,
                   2228:                                                stdoff)) {
                   2229:                                                        doabbr(startbuf,
                   2230:                                                                max_abbr_len + 1,
                   2231:                                                                zp->z_format,
                   2232:                                                                rp->r_abbrvar,
                   2233:                                                                rp->r_stdoff !=
                   2234:                                                                0,
                   2235:                                                                FALSE);
1.1       jtc      2236:                                        }
                   2237:                                }
                   2238:                                eats(zp->z_filename, zp->z_linenum,
                   2239:                                        rp->r_filename, rp->r_linenum);
1.25      mlelstv  2240:                                doabbr(ab, max_abbr_len+1, zp->z_format, rp->r_abbrvar,
                   2241:                                        rp->r_stdoff != 0, FALSE);
1.1       jtc      2242:                                offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1.25      mlelstv  2243:                                type = addtype(offset, ab, rp->r_stdoff != 0,
1.1       jtc      2244:                                        rp->r_todisstd, rp->r_todisgmt);
                   2245:                                addtt(ktime, type);
                   2246:                        }
                   2247:                }
1.5       jtc      2248:                if (usestart) {
                   2249:                        if (*startbuf == '\0' &&
                   2250:                                zp->z_format != NULL &&
                   2251:                                strchr(zp->z_format, '%') == NULL &&
                   2252:                                strchr(zp->z_format, '/') == NULL)
1.6       mrg      2253:                                        (void)strncpy(startbuf, zp->z_format,
1.25      mlelstv  2254:                                            max_abbr_len + 1 - 1);
1.5       jtc      2255:                        eat(zp->z_filename, zp->z_linenum);
                   2256:                        if (*startbuf == '\0')
1.7       jtc      2257: error(_("can't determine time zone abbreviation to use just after until time"));
1.5       jtc      2258:                        else    addtt(starttime,
                   2259:                                        addtype(startoff, startbuf,
                   2260:                                                startoff != zp->z_gmtoff,
                   2261:                                                startttisstd,
                   2262:                                                startttisgmt));
                   2263:                }
1.1       jtc      2264:                /*
                   2265:                ** Now we may get to set starttime for the next zone line.
                   2266:                */
                   2267:                if (useuntil) {
                   2268:                        startttisstd = zp->z_untilrule.r_todisstd;
                   2269:                        startttisgmt = zp->z_untilrule.r_todisgmt;
1.5       jtc      2270:                        starttime = zp->z_untiltime;
1.1       jtc      2271:                        if (!startttisstd)
                   2272:                                starttime = tadd(starttime, -stdoff);
1.5       jtc      2273:                        if (!startttisgmt)
                   2274:                                starttime = tadd(starttime, -gmtoff);
1.1       jtc      2275:                }
                   2276:        }
1.25      mlelstv  2277:        writezone(zpfirst->z_name, envvar);
                   2278:        ifree(startbuf);
                   2279:        ifree(ab);
                   2280:        ifree(envvar);
1.1       jtc      2281: }
                   2282:
                   2283: static void
                   2284: addtt(starttime, type)
1.25      mlelstv  2285: const zic_t    starttime;
1.7       jtc      2286: int            type;
1.1       jtc      2287: {
1.7       jtc      2288:        if (starttime <= min_time ||
                   2289:                (timecnt == 1 && attypes[0].at < min_time)) {
                   2290:                gmtoffs[0] = gmtoffs[type];
                   2291:                isdsts[0] = isdsts[type];
                   2292:                ttisstds[0] = ttisstds[type];
                   2293:                ttisgmts[0] = ttisgmts[type];
                   2294:                if (abbrinds[type] != 0)
                   2295:                        (void) strcpy(chars, &chars[abbrinds[type]]);
                   2296:                abbrinds[0] = 0;
                   2297:                charcnt = strlen(chars) + 1;
                   2298:                typecnt = 1;
                   2299:                timecnt = 0;
                   2300:                type = 0;
                   2301:        }
1.1       jtc      2302:        if (timecnt >= TZ_MAX_TIMES) {
1.5       jtc      2303:                error(_("too many transitions?!"));
1.25      mlelstv  2304:                exit(EXIT_FAILURE);
1.1       jtc      2305:        }
1.5       jtc      2306:        attypes[timecnt].at = starttime;
                   2307:        attypes[timecnt].type = type;
1.1       jtc      2308:        ++timecnt;
                   2309: }
                   2310:
                   2311: static int
                   2312: addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
                   2313: const long             gmtoff;
                   2314: const char * const     abbr;
                   2315: const int              isdst;
                   2316: const int              ttisstd;
                   2317: const int              ttisgmt;
                   2318: {
                   2319:        register int    i, j;
                   2320:
1.5       jtc      2321:        if (isdst != TRUE && isdst != FALSE) {
                   2322:                error(_("internal error - addtype called with bad isdst"));
1.25      mlelstv  2323:                exit(EXIT_FAILURE);
1.5       jtc      2324:        }
                   2325:        if (ttisstd != TRUE && ttisstd != FALSE) {
                   2326:                error(_("internal error - addtype called with bad ttisstd"));
1.25      mlelstv  2327:                exit(EXIT_FAILURE);
1.5       jtc      2328:        }
                   2329:        if (ttisgmt != TRUE && ttisgmt != FALSE) {
                   2330:                error(_("internal error - addtype called with bad ttisgmt"));
1.25      mlelstv  2331:                exit(EXIT_FAILURE);
1.5       jtc      2332:        }
1.1       jtc      2333:        /*
                   2334:        ** See if there's already an entry for this zone type.
                   2335:        ** If so, just return its index.
                   2336:        */
                   2337:        for (i = 0; i < typecnt; ++i) {
                   2338:                if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
                   2339:                        strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
                   2340:                        ttisstd == ttisstds[i] &&
                   2341:                        ttisgmt == ttisgmts[i])
                   2342:                                return i;
                   2343:        }
                   2344:        /*
                   2345:        ** There isn't one; add a new one, unless there are already too
                   2346:        ** many.
                   2347:        */
                   2348:        if (typecnt >= TZ_MAX_TYPES) {
1.5       jtc      2349:                error(_("too many local time types"));
1.25      mlelstv  2350:                exit(EXIT_FAILURE);
                   2351:        }
                   2352:        if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
                   2353:                error(_("UTC offset out of range"));
                   2354:                exit(EXIT_FAILURE);
1.1       jtc      2355:        }
                   2356:        gmtoffs[i] = gmtoff;
                   2357:        isdsts[i] = isdst;
                   2358:        ttisstds[i] = ttisstd;
                   2359:        ttisgmts[i] = ttisgmt;
                   2360:
                   2361:        for (j = 0; j < charcnt; ++j)
                   2362:                if (strcmp(&chars[j], abbr) == 0)
                   2363:                        break;
                   2364:        if (j == charcnt)
                   2365:                newabbr(abbr);
                   2366:        abbrinds[i] = j;
                   2367:        ++typecnt;
                   2368:        return i;
                   2369: }
                   2370:
                   2371: static void
                   2372: leapadd(t, positive, rolling, count)
1.25      mlelstv  2373: const zic_t    t;
1.1       jtc      2374: const int      positive;
                   2375: const int      rolling;
                   2376: int            count;
                   2377: {
                   2378:        register int    i, j;
                   2379:
                   2380:        if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
1.5       jtc      2381:                error(_("too many leap seconds"));
1.25      mlelstv  2382:                exit(EXIT_FAILURE);
1.1       jtc      2383:        }
                   2384:        for (i = 0; i < leapcnt; ++i)
                   2385:                if (t <= trans[i]) {
                   2386:                        if (t == trans[i]) {
1.5       jtc      2387:                                error(_("repeated leap second moment"));
1.25      mlelstv  2388:                                exit(EXIT_FAILURE);
1.1       jtc      2389:                        }
                   2390:                        break;
                   2391:                }
                   2392:        do {
                   2393:                for (j = leapcnt; j > i; --j) {
                   2394:                        trans[j] = trans[j - 1];
                   2395:                        corr[j] = corr[j - 1];
                   2396:                        roll[j] = roll[j - 1];
                   2397:                }
                   2398:                trans[i] = t;
                   2399:                corr[i] = positive ? 1L : eitol(-count);
                   2400:                roll[i] = rolling;
                   2401:                ++leapcnt;
                   2402:        } while (positive && --count != 0);
                   2403: }
                   2404:
                   2405: static void
1.25      mlelstv  2406: adjleap(void)
1.1       jtc      2407: {
                   2408:        register int    i;
                   2409:        register long   last = 0;
                   2410:
                   2411:        /*
                   2412:        ** propagate leap seconds forward
                   2413:        */
                   2414:        for (i = 0; i < leapcnt; ++i) {
                   2415:                trans[i] = tadd(trans[i], last);
                   2416:                last = corr[i] += last;
                   2417:        }
                   2418: }
                   2419:
                   2420: static int
                   2421: yearistype(year, type)
                   2422: const int              year;
                   2423: const char * const     type;
                   2424: {
                   2425:        static char *   buf;
                   2426:        int             result;
                   2427:
                   2428:        if (type == NULL || *type == '\0')
                   2429:                return TRUE;
                   2430:        buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
1.6       mrg      2431:        (void)sprintf(buf, "%s %d %s", yitcommand, year, type); /* XXX: sprintf is safe */
1.1       jtc      2432:        result = system(buf);
1.16      kleink   2433:        if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
                   2434:                case 0:
                   2435:                        return TRUE;
                   2436:                case 1:
                   2437:                        return FALSE;
                   2438:        }
1.5       jtc      2439:        error(_("Wild result from command execution"));
                   2440:        (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
1.1       jtc      2441:                progname, buf, result);
                   2442:        for ( ; ; )
1.25      mlelstv  2443:                exit(EXIT_FAILURE);
1.1       jtc      2444: }
                   2445:
                   2446: static int
                   2447: lowerit(a)
1.3       jtc      2448: int    a;
1.1       jtc      2449: {
1.3       jtc      2450:        a = (unsigned char) a;
1.1       jtc      2451:        return (isascii(a) && isupper(a)) ? tolower(a) : a;
                   2452: }
                   2453:
                   2454: static int
                   2455: ciequal(ap, bp)                /* case-insensitive equality */
                   2456: register const char *  ap;
                   2457: register const char *  bp;
                   2458: {
                   2459:        while (lowerit(*ap) == lowerit(*bp++))
                   2460:                if (*ap++ == '\0')
                   2461:                        return TRUE;
                   2462:        return FALSE;
                   2463: }
                   2464:
                   2465: static int
                   2466: itsabbr(abbr, word)
                   2467: register const char *  abbr;
                   2468: register const char *  word;
                   2469: {
                   2470:        if (lowerit(*abbr) != lowerit(*word))
                   2471:                return FALSE;
                   2472:        ++word;
                   2473:        while (*++abbr != '\0')
1.3       jtc      2474:                do {
                   2475:                        if (*word == '\0')
                   2476:                                return FALSE;
                   2477:                } while (lowerit(*word++) != lowerit(*abbr));
1.1       jtc      2478:        return TRUE;
                   2479: }
                   2480:
                   2481: static const struct lookup *
                   2482: byword(word, table)
                   2483: register const char * const            word;
                   2484: register const struct lookup * const   table;
                   2485: {
                   2486:        register const struct lookup *  foundlp;
                   2487:        register const struct lookup *  lp;
                   2488:
                   2489:        if (word == NULL || table == NULL)
                   2490:                return NULL;
                   2491:        /*
                   2492:        ** Look for exact match.
                   2493:        */
                   2494:        for (lp = table; lp->l_word != NULL; ++lp)
                   2495:                if (ciequal(word, lp->l_word))
                   2496:                        return lp;
                   2497:        /*
                   2498:        ** Look for inexact match.
                   2499:        */
                   2500:        foundlp = NULL;
                   2501:        for (lp = table; lp->l_word != NULL; ++lp)
1.11      jtc      2502:                if (itsabbr(word, lp->l_word)) {
1.1       jtc      2503:                        if (foundlp == NULL)
                   2504:                                foundlp = lp;
                   2505:                        else    return NULL;    /* multiple inexact matches */
1.11      jtc      2506:                }
1.1       jtc      2507:        return foundlp;
                   2508: }
                   2509:
                   2510: static char **
                   2511: getfields(cp)
                   2512: register char *        cp;
                   2513: {
                   2514:        register char *         dp;
                   2515:        register char **        array;
                   2516:        register int            nsubs;
                   2517:
                   2518:        if (cp == NULL)
                   2519:                return NULL;
                   2520:        array = (char **) (void *)
                   2521:                emalloc((int) ((strlen(cp) + 1) * sizeof *array));
                   2522:        nsubs = 0;
                   2523:        for ( ; ; ) {
1.25      mlelstv  2524:                while (isascii((unsigned char) *cp) &&
                   2525:                        isspace((unsigned char) *cp))
                   2526:                                ++cp;
1.1       jtc      2527:                if (*cp == '\0' || *cp == '#')
                   2528:                        break;
                   2529:                array[nsubs++] = dp = cp;
                   2530:                do {
                   2531:                        if ((*dp = *cp++) != '"')
                   2532:                                ++dp;
                   2533:                        else while ((*dp = *cp++) != '"')
                   2534:                                if (*dp != '\0')
                   2535:                                        ++dp;
1.25      mlelstv  2536:                                else {
                   2537:                                        error(_(
                   2538:                                                "Odd number of quotation marks"
                   2539:                                                ));
                   2540:                                        exit(1);
                   2541:                                }
1.1       jtc      2542:                } while (*cp != '\0' && *cp != '#' &&
1.3       jtc      2543:                        (!isascii(*cp) || !isspace((unsigned char) *cp)));
                   2544:                if (isascii(*cp) && isspace((unsigned char) *cp))
1.1       jtc      2545:                        ++cp;
                   2546:                *dp = '\0';
                   2547:        }
                   2548:        array[nsubs] = NULL;
                   2549:        return array;
                   2550: }
                   2551:
                   2552: static long
                   2553: oadd(t1, t2)
                   2554: const long     t1;
                   2555: const long     t2;
                   2556: {
1.28      martin   2557:        register long   t;
                   2558:
                   2559:        t = t1 + t2;
                   2560:        if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1.5       jtc      2561:                error(_("time overflow"));
1.25      mlelstv  2562:                exit(EXIT_FAILURE);
1.1       jtc      2563:        }
1.28      martin   2564:        return t;
1.1       jtc      2565: }
                   2566:
1.25      mlelstv  2567: static zic_t
1.1       jtc      2568: tadd(t1, t2)
1.25      mlelstv  2569: const zic_t    t1;
1.1       jtc      2570: const long     t2;
                   2571: {
1.28      martin   2572:        register zic_t  t;
                   2573:
1.1       jtc      2574:        if (t1 == max_time && t2 > 0)
                   2575:                return max_time;
                   2576:        if (t1 == min_time && t2 < 0)
                   2577:                return min_time;
1.28      martin   2578:        t = t1 + t2;
                   2579:        if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1.5       jtc      2580:                error(_("time overflow"));
1.25      mlelstv  2581:                exit(EXIT_FAILURE);
1.1       jtc      2582:        }
1.28      martin   2583:        return t;
1.1       jtc      2584: }
                   2585:
                   2586: /*
                   2587: ** Given a rule, and a year, compute the date - in seconds since January 1,
                   2588: ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
                   2589: */
                   2590:
1.25      mlelstv  2591: static zic_t
1.1       jtc      2592: rpytime(rp, wantedy)
                   2593: register const struct rule * const     rp;
                   2594: register const int                     wantedy;
                   2595: {
                   2596:        register int    y, m, i;
                   2597:        register long   dayoff;                 /* with a nod to Margaret O. */
1.25      mlelstv  2598:        register zic_t  t;
1.1       jtc      2599:
1.3       jtc      2600:        if (wantedy == INT_MIN)
1.1       jtc      2601:                return min_time;
1.3       jtc      2602:        if (wantedy == INT_MAX)
1.1       jtc      2603:                return max_time;
                   2604:        dayoff = 0;
                   2605:        m = TM_JANUARY;
                   2606:        y = EPOCH_YEAR;
                   2607:        while (wantedy != y) {
                   2608:                if (wantedy > y) {
                   2609:                        i = len_years[isleap(y)];
                   2610:                        ++y;
                   2611:                } else {
                   2612:                        --y;
                   2613:                        i = -len_years[isleap(y)];
                   2614:                }
                   2615:                dayoff = oadd(dayoff, eitol(i));
                   2616:        }
                   2617:        while (m != rp->r_month) {
                   2618:                i = len_months[isleap(y)][m];
                   2619:                dayoff = oadd(dayoff, eitol(i));
                   2620:                ++m;
                   2621:        }
                   2622:        i = rp->r_dayofmonth;
                   2623:        if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
                   2624:                if (rp->r_dycode == DC_DOWLEQ)
                   2625:                        --i;
                   2626:                else {
1.5       jtc      2627:                        error(_("use of 2/29 in non leap-year"));
1.25      mlelstv  2628:                        exit(EXIT_FAILURE);
1.1       jtc      2629:                }
                   2630:        }
                   2631:        --i;
                   2632:        dayoff = oadd(dayoff, eitol(i));
                   2633:        if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
                   2634:                register long   wday;
                   2635:
                   2636: #define LDAYSPERWEEK   ((long) DAYSPERWEEK)
                   2637:                wday = eitol(EPOCH_WDAY);
                   2638:                /*
                   2639:                ** Don't trust mod of negative numbers.
                   2640:                */
                   2641:                if (dayoff >= 0)
                   2642:                        wday = (wday + dayoff) % LDAYSPERWEEK;
                   2643:                else {
                   2644:                        wday -= ((-dayoff) % LDAYSPERWEEK);
                   2645:                        if (wday < 0)
                   2646:                                wday += LDAYSPERWEEK;
                   2647:                }
                   2648:                while (wday != eitol(rp->r_wday))
                   2649:                        if (rp->r_dycode == DC_DOWGEQ) {
                   2650:                                dayoff = oadd(dayoff, (long) 1);
                   2651:                                if (++wday >= LDAYSPERWEEK)
                   2652:                                        wday = 0;
                   2653:                                ++i;
                   2654:                        } else {
                   2655:                                dayoff = oadd(dayoff, (long) -1);
                   2656:                                if (--wday < 0)
                   2657:                                        wday = LDAYSPERWEEK - 1;
                   2658:                                --i;
                   2659:                        }
                   2660:                if (i < 0 || i >= len_months[isleap(y)][m]) {
1.23      kleink   2661:                        if (noise)
1.25      mlelstv  2662:                                warning(_("rule goes past start/end of month--\
                   2663: will not work with pre-2004 versions of zic"));
1.1       jtc      2664:                }
                   2665:        }
1.20      kleink   2666:        if (dayoff < min_time / SECSPERDAY)
                   2667:                return min_time;
                   2668:        if (dayoff > max_time / SECSPERDAY)
                   2669:                return max_time;
1.25      mlelstv  2670:        t = (zic_t) dayoff * SECSPERDAY;
1.1       jtc      2671:        return tadd(t, rp->r_tod);
                   2672: }
                   2673:
                   2674: static void
                   2675: newabbr(string)
                   2676: const char * const     string;
                   2677: {
                   2678:        register int    i;
                   2679:
1.25      mlelstv  2680:        if (strcmp(string, GRANDPARENTED) != 0) {
                   2681:                register const char *   cp;
                   2682:                register char *         wp;
                   2683:
                   2684:                /*
                   2685:                ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
                   2686:                ** optionally followed by a + or - and a number from 1 to 14.
                   2687:                */
                   2688:                cp = string;
                   2689:                wp = NULL;
                   2690:                while (isascii((unsigned char) *cp) &&
                   2691:                        isalpha((unsigned char) *cp))
                   2692:                                ++cp;
                   2693:                if (cp - string == 0)
                   2694: wp = _("time zone abbreviation lacks alphabetic at start");
                   2695:                if (noise && cp - string > 3)
                   2696: wp = _("time zone abbreviation has more than 3 alphabetics");
                   2697:                if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
                   2698: wp = _("time zone abbreviation has too many alphabetics");
                   2699:                if (wp == NULL && (*cp == '+' || *cp == '-')) {
                   2700:                        ++cp;
                   2701:                        if (isascii((unsigned char) *cp) &&
                   2702:                                isdigit((unsigned char) *cp))
                   2703:                                        if (*cp++ == '1' &&
                   2704:                                                *cp >= '0' && *cp <= '4')
                   2705:                                                        ++cp;
                   2706:                }
                   2707:                if (*cp != '\0')
                   2708: wp = _("time zone abbreviation differs from POSIX standard");
                   2709:                if (wp != NULL) {
                   2710:                        wp = ecpyalloc(wp);
                   2711:                        wp = ecatalloc(wp, " (");
                   2712:                        wp = ecatalloc(wp, string);
                   2713:                        wp = ecatalloc(wp, ")");
                   2714:                        warning(wp);
                   2715:                        ifree(wp);
                   2716:                }
                   2717:        }
1.1       jtc      2718:        i = strlen(string) + 1;
                   2719:        if (charcnt + i > TZ_MAX_CHARS) {
1.5       jtc      2720:                error(_("too many, or too long, time zone abbreviations"));
1.25      mlelstv  2721:                exit(EXIT_FAILURE);
1.1       jtc      2722:        }
1.6       mrg      2723:        (void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
1.1       jtc      2724:        charcnt += eitol(i);
                   2725: }
                   2726:
                   2727: static int
                   2728: mkdirs(argname)
1.25      mlelstv  2729: char *         argname;
1.1       jtc      2730: {
                   2731:        register char * name;
                   2732:        register char * cp;
                   2733:
                   2734:        if (argname == NULL || *argname == '\0')
                   2735:                return 0;
                   2736:        cp = name = ecpyalloc(argname);
                   2737:        while ((cp = strchr(cp + 1, '/')) != 0) {
                   2738:                *cp = '\0';
1.13      kleink   2739: #ifndef __NetBSD__
1.1       jtc      2740:                /*
                   2741:                ** DOS drive specifier?
                   2742:                */
1.3       jtc      2743:                if (isalpha((unsigned char) name[0]) &&
1.4       jtc      2744:                        name[1] == ':' && name[2] == '\0') {
1.1       jtc      2745:                                *cp = '/';
                   2746:                                continue;
                   2747:                }
1.13      kleink   2748: #endif /* !defined __NetBSD__ */
1.1       jtc      2749:                if (!itsdir(name)) {
                   2750:                        /*
                   2751:                        ** It doesn't seem to exist, so we try to create it.
1.7       jtc      2752:                        ** Creation may fail because of the directory being
                   2753:                        ** created by some other multiprocessor, so we get
                   2754:                        ** to do extra checking.
1.1       jtc      2755:                        */
1.19      kleink   2756:                        if (mkdir(name, MKDIR_UMASK) != 0) {
1.5       jtc      2757:                                const char *e = strerror(errno);
1.7       jtc      2758:
                   2759:                                if (errno != EEXIST || !itsdir(name)) {
                   2760:                                        (void) fprintf(stderr,
                   2761: _("%s: Can't create directory %s: %s\n"),
                   2762:                                                progname, name, e);
                   2763:                                        ifree(name);
                   2764:                                        return -1;
                   2765:                                }
1.1       jtc      2766:                        }
                   2767:                }
                   2768:                *cp = '/';
                   2769:        }
                   2770:        ifree(name);
                   2771:        return 0;
                   2772: }
                   2773:
                   2774: static long
                   2775: eitol(i)
                   2776: const int      i;
                   2777: {
                   2778:        long    l;
                   2779:
                   2780:        l = i;
                   2781:        if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
                   2782:                (void) fprintf(stderr,
1.5       jtc      2783:                        _("%s: %d did not sign extend correctly\n"),
1.1       jtc      2784:                        progname, i);
1.25      mlelstv  2785:                exit(EXIT_FAILURE);
1.1       jtc      2786:        }
                   2787:        return l;
                   2788: }
                   2789:
                   2790: /*
1.21      kleink   2791: ** UNIX was a registered trademark of The Open Group in 2003.
1.1       jtc      2792: */

CVSweb <webmaster@jp.NetBSD.org>