home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / glibc-1.06 / time / zic.c < prev   
Encoding:
C/C++ Source or Header  |  1993-05-22  |  42.4 KB  |  1,923 lines

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