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

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

CVSweb <webmaster@jp.NetBSD.org>