home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / localtime3 / part03 < prev    next >
Text File  |  1989-04-19  |  56KB  |  2,514 lines

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