home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / zoneinfo / src / zic.c < prev   
Encoding:
C/C++ Source or Header  |  1996-08-12  |  49.5 KB  |  2,198 lines

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