home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / share / zoneinfo / zic.c < prev   
Encoding:
C/C++ Source or Header  |  1991-04-20  |  42.8 KB  |  1,895 lines

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