"Fossies" - the Fresh Open Source Software Archive

Member "zic.c" (1 Nov 2018, 82569 Bytes) of package /linux/misc/tzcode2018i.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "zic.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2018g_vs_2018h.

    1 /* Compile .zi time zone data into TZif binary files.  */
    2 
    3 /*
    4 ** This file is in the public domain, so clarified as of
    5 ** 2006-07-17 by Arthur David Olson.
    6 */
    7 
    8 #include "version.h"
    9 #include "private.h"
   10 #include "tzfile.h"
   11 
   12 #include <fcntl.h>
   13 #include <locale.h>
   14 #include <stdarg.h>
   15 #include <stddef.h>
   16 #include <stdio.h>
   17 
   18 #define ZIC_VERSION_PRE_2013 '2'
   19 #define ZIC_VERSION '3'
   20 
   21 typedef int_fast64_t    zic_t;
   22 #define ZIC_MIN INT_FAST64_MIN
   23 #define ZIC_MAX INT_FAST64_MAX
   24 #define PRIdZIC PRIdFAST64
   25 #define SCNdZIC SCNdFAST64
   26 
   27 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
   28 #define ZIC_MAX_ABBR_LEN_WO_WARN    6
   29 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
   30 
   31 #ifdef HAVE_DIRECT_H
   32 # include <direct.h>
   33 # include <io.h>
   34 # undef mkdir
   35 # define mkdir(name, mode) _mkdir(name)
   36 #endif
   37 
   38 #if HAVE_SYS_STAT_H
   39 #include <sys/stat.h>
   40 #endif
   41 #ifdef S_IRUSR
   42 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
   43 #else
   44 #define MKDIR_UMASK 0755
   45 #endif
   46 /* Port to native MS-Windows and to ancient UNIX.  */
   47 #if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT
   48 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
   49 #endif
   50 
   51 #if HAVE_SYS_WAIT_H
   52 #include <sys/wait.h>   /* for WIFEXITED and WEXITSTATUS */
   53 #endif /* HAVE_SYS_WAIT_H */
   54 
   55 #ifndef WIFEXITED
   56 #define WIFEXITED(status)   (((status) & 0xff) == 0)
   57 #endif /* !defined WIFEXITED */
   58 #ifndef WEXITSTATUS
   59 #define WEXITSTATUS(status) (((status) >> 8) & 0xff)
   60 #endif /* !defined WEXITSTATUS */
   61 
   62 /* The maximum ptrdiff_t value, for pre-C99 platforms.  */
   63 #ifndef PTRDIFF_MAX
   64 static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
   65 #endif
   66 
   67 /* The minimum alignment of a type, for pre-C11 platforms.  */
   68 #if __STDC_VERSION__ < 201112
   69 # define _Alignof(type) offsetof(struct { char a; type b; }, b)
   70 #endif
   71 
   72 /* The type for line numbers.  Use PRIdMAX to format them; formerly
   73    there was also "#define PRIdLINENO PRIdMAX" and formats used
   74    PRIdLINENO, but xgettext cannot grok that.  */
   75 typedef intmax_t lineno;
   76 
   77 struct rule {
   78     const char *    r_filename;
   79     lineno      r_linenum;
   80     const char *    r_name;
   81 
   82     zic_t       r_loyear;   /* for example, 1986 */
   83     zic_t       r_hiyear;   /* for example, 1986 */
   84     const char *    r_yrtype;
   85     bool        r_lowasnum;
   86     bool        r_hiwasnum;
   87 
   88     int     r_month;    /* 0..11 */
   89 
   90     int     r_dycode;   /* see below */
   91     int     r_dayofmonth;
   92     int     r_wday;
   93 
   94     zic_t       r_tod;      /* time from midnight */
   95     bool        r_todisstd; /* above is standard time if 1 */
   96                     /* or wall clock time if 0 */
   97     bool        r_todisgmt; /* above is GMT if 1 */
   98                     /* or local time if 0 */
   99     bool        r_isdst;    /* is this daylight saving time? */
  100     zic_t       r_stdoff;   /* offset from default time (which is
  101                        usually standard time) */
  102     const char *    r_abbrvar;  /* variable part of abbreviation */
  103 
  104     bool        r_todo;     /* a rule to do (used in outzone) */
  105     zic_t       r_temp;     /* used in outzone */
  106 };
  107 
  108 /*
  109 **  r_dycode        r_dayofmonth    r_wday
  110 */
  111 
  112 #define DC_DOM      0   /* 1..31 */ /* unused */
  113 #define DC_DOWGEQ   1   /* 1..31 */ /* 0..6 (Sun..Sat) */
  114 #define DC_DOWLEQ   2   /* 1..31 */ /* 0..6 (Sun..Sat) */
  115 
  116 struct zone {
  117     const char *    z_filename;
  118     lineno      z_linenum;
  119 
  120     const char *    z_name;
  121     zic_t       z_gmtoff;
  122     char *      z_rule;
  123     const char *    z_format;
  124     char        z_format_specifier;
  125 
  126     bool        z_isdst;
  127     zic_t       z_stdoff;
  128 
  129     struct rule *   z_rules;
  130     ptrdiff_t   z_nrules;
  131 
  132     struct rule z_untilrule;
  133     zic_t       z_untiltime;
  134 };
  135 
  136 #if !HAVE_POSIX_DECLS
  137 extern int  getopt(int argc, char * const argv[],
  138             const char * options);
  139 extern int  link(const char * fromname, const char * toname);
  140 extern char *   optarg;
  141 extern int  optind;
  142 #endif
  143 
  144 #if ! HAVE_LINK
  145 # define link(from, to) (errno = ENOTSUP, -1)
  146 #endif
  147 #if ! HAVE_SYMLINK
  148 # define readlink(file, buf, size) (errno = ENOTSUP, -1)
  149 # define symlink(from, to) (errno = ENOTSUP, -1)
  150 # define S_ISLNK(m) 0
  151 #endif
  152 #ifndef AT_SYMLINK_FOLLOW
  153 # define linkat(fromdir, from, todir, to, flag) \
  154     (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
  155 #endif
  156 
  157 static void addtt(zic_t starttime, int type);
  158 static int  addtype(zic_t, char const *, bool, bool, bool);
  159 static void leapadd(zic_t, bool, int, int);
  160 static void adjleap(void);
  161 static void associate(void);
  162 static void dolink(const char *, const char *, bool);
  163 static char **  getfields(char * buf);
  164 static zic_t    gethms(const char * string, const char * errstring);
  165 static zic_t    getstdoff(char *, bool *);
  166 static void infile(const char * filename);
  167 static void inleap(char ** fields, int nfields);
  168 static void inlink(char ** fields, int nfields);
  169 static void inrule(char ** fields, int nfields);
  170 static bool inzcont(char ** fields, int nfields);
  171 static bool inzone(char ** fields, int nfields);
  172 static bool inzsub(char **, int, bool);
  173 static bool itsdir(char const *);
  174 static bool itssymlink(char const *);
  175 static bool is_alpha(char a);
  176 static char lowerit(char);
  177 static void mkdirs(char const *, bool);
  178 static void newabbr(const char * abbr);
  179 static zic_t    oadd(zic_t t1, zic_t t2);
  180 static void outzone(const struct zone * zp, ptrdiff_t ntzones);
  181 static zic_t    rpytime(const struct rule * rp, zic_t wantedy);
  182 static void rulesub(struct rule * rp,
  183             const char * loyearp, const char * hiyearp,
  184             const char * typep, const char * monthp,
  185             const char * dayp, const char * timep);
  186 static zic_t    tadd(zic_t t1, zic_t t2);
  187 static bool yearistype(zic_t year, const char * type);
  188 
  189 /* Bound on length of what %z can expand to.  */
  190 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
  191 
  192 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
  193    TZif files whose POSIX-TZ-style strings contain '<'; see
  194    QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>.  This
  195    workaround will no longer be needed when Qt 5.6.1 and earlier are
  196    obsolete, say in the year 2021.  */
  197 #ifndef WORK_AROUND_QTBUG_53071
  198 enum { WORK_AROUND_QTBUG_53071 = true };
  199 #endif
  200 
  201 static int      charcnt;
  202 static bool     errors;
  203 static bool     warnings;
  204 static const char * filename;
  205 static int      leapcnt;
  206 static bool     leapseen;
  207 static zic_t        leapminyear;
  208 static zic_t        leapmaxyear;
  209 static lineno       linenum;
  210 static int      max_abbrvar_len = PERCENT_Z_LEN_BOUND;
  211 static int      max_format_len;
  212 static zic_t        max_year;
  213 static zic_t        min_year;
  214 static bool     noise;
  215 static const char * rfilename;
  216 static lineno       rlinenum;
  217 static const char * progname;
  218 static ptrdiff_t    timecnt;
  219 static ptrdiff_t    timecnt_alloc;
  220 static int      typecnt;
  221 
  222 /*
  223 ** Line codes.
  224 */
  225 
  226 #define LC_RULE     0
  227 #define LC_ZONE     1
  228 #define LC_LINK     2
  229 #define LC_LEAP     3
  230 
  231 /*
  232 ** Which fields are which on a Zone line.
  233 */
  234 
  235 #define ZF_NAME     1
  236 #define ZF_GMTOFF   2
  237 #define ZF_RULE     3
  238 #define ZF_FORMAT   4
  239 #define ZF_TILYEAR  5
  240 #define ZF_TILMONTH 6
  241 #define ZF_TILDAY   7
  242 #define ZF_TILTIME  8
  243 #define ZONE_MINFIELDS  5
  244 #define ZONE_MAXFIELDS  9
  245 
  246 /*
  247 ** Which fields are which on a Zone continuation line.
  248 */
  249 
  250 #define ZFC_GMTOFF  0
  251 #define ZFC_RULE    1
  252 #define ZFC_FORMAT  2
  253 #define ZFC_TILYEAR 3
  254 #define ZFC_TILMONTH    4
  255 #define ZFC_TILDAY  5
  256 #define ZFC_TILTIME 6
  257 #define ZONEC_MINFIELDS 3
  258 #define ZONEC_MAXFIELDS 7
  259 
  260 /*
  261 ** Which files are which on a Rule line.
  262 */
  263 
  264 #define RF_NAME     1
  265 #define RF_LOYEAR   2
  266 #define RF_HIYEAR   3
  267 #define RF_COMMAND  4
  268 #define RF_MONTH    5
  269 #define RF_DAY      6
  270 #define RF_TOD      7
  271 #define RF_STDOFF   8
  272 #define RF_ABBRVAR  9
  273 #define RULE_FIELDS 10
  274 
  275 /*
  276 ** Which fields are which on a Link line.
  277 */
  278 
  279 #define LF_FROM     1
  280 #define LF_TO       2
  281 #define LINK_FIELDS 3
  282 
  283 /*
  284 ** Which fields are which on a Leap line.
  285 */
  286 
  287 #define LP_YEAR     1
  288 #define LP_MONTH    2
  289 #define LP_DAY      3
  290 #define LP_TIME     4
  291 #define LP_CORR     5
  292 #define LP_ROLL     6
  293 #define LEAP_FIELDS 7
  294 
  295 /*
  296 ** Year synonyms.
  297 */
  298 
  299 #define YR_MINIMUM  0
  300 #define YR_MAXIMUM  1
  301 #define YR_ONLY     2
  302 
  303 static struct rule *    rules;
  304 static ptrdiff_t    nrules; /* number of rules */
  305 static ptrdiff_t    nrules_alloc;
  306 
  307 static struct zone *    zones;
  308 static ptrdiff_t    nzones; /* number of zones */
  309 static ptrdiff_t    nzones_alloc;
  310 
  311 struct link {
  312     const char *    l_filename;
  313     lineno      l_linenum;
  314     const char *    l_from;
  315     const char *    l_to;
  316 };
  317 
  318 static struct link *    links;
  319 static ptrdiff_t    nlinks;
  320 static ptrdiff_t    nlinks_alloc;
  321 
  322 struct lookup {
  323     const char *    l_word;
  324     const int   l_value;
  325 };
  326 
  327 static struct lookup const *    byword(const char * string,
  328                     const struct lookup * lp);
  329 
  330 static struct lookup const zi_line_codes[] = {
  331     { "Rule",   LC_RULE },
  332     { "Zone",   LC_ZONE },
  333     { "Link",   LC_LINK },
  334     { NULL,     0 }
  335 };
  336 static struct lookup const leap_line_codes[] = {
  337     { "Leap",   LC_LEAP },
  338     { NULL,     0}
  339 };
  340 
  341 static struct lookup const  mon_names[] = {
  342     { "January",    TM_JANUARY },
  343     { "February",   TM_FEBRUARY },
  344     { "March",  TM_MARCH },
  345     { "April",  TM_APRIL },
  346     { "May",    TM_MAY },
  347     { "June",   TM_JUNE },
  348     { "July",   TM_JULY },
  349     { "August", TM_AUGUST },
  350     { "September",  TM_SEPTEMBER },
  351     { "October",    TM_OCTOBER },
  352     { "November",   TM_NOVEMBER },
  353     { "December",   TM_DECEMBER },
  354     { NULL,     0 }
  355 };
  356 
  357 static struct lookup const  wday_names[] = {
  358     { "Sunday", TM_SUNDAY },
  359     { "Monday", TM_MONDAY },
  360     { "Tuesday",    TM_TUESDAY },
  361     { "Wednesday",  TM_WEDNESDAY },
  362     { "Thursday",   TM_THURSDAY },
  363     { "Friday", TM_FRIDAY },
  364     { "Saturday",   TM_SATURDAY },
  365     { NULL,     0 }
  366 };
  367 
  368 static struct lookup const  lasts[] = {
  369     { "last-Sunday",    TM_SUNDAY },
  370     { "last-Monday",    TM_MONDAY },
  371     { "last-Tuesday",   TM_TUESDAY },
  372     { "last-Wednesday", TM_WEDNESDAY },
  373     { "last-Thursday",  TM_THURSDAY },
  374     { "last-Friday",    TM_FRIDAY },
  375     { "last-Saturday",  TM_SATURDAY },
  376     { NULL,         0 }
  377 };
  378 
  379 static struct lookup const  begin_years[] = {
  380     { "minimum",    YR_MINIMUM },
  381     { "maximum",    YR_MAXIMUM },
  382     { NULL,     0 }
  383 };
  384 
  385 static struct lookup const  end_years[] = {
  386     { "minimum",    YR_MINIMUM },
  387     { "maximum",    YR_MAXIMUM },
  388     { "only",   YR_ONLY },
  389     { NULL,     0 }
  390 };
  391 
  392 static struct lookup const  leap_types[] = {
  393     { "Rolling",    true },
  394     { "Stationary", false },
  395     { NULL,     0 }
  396 };
  397 
  398 static const int    len_months[2][MONSPERYEAR] = {
  399     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  400     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  401 };
  402 
  403 static const int    len_years[2] = {
  404     DAYSPERNYEAR, DAYSPERLYEAR
  405 };
  406 
  407 static struct attype {
  408     zic_t       at;
  409     bool        dontmerge;
  410     unsigned char   type;
  411 } *         attypes;
  412 static zic_t        gmtoffs[TZ_MAX_TYPES];
  413 static char     isdsts[TZ_MAX_TYPES];
  414 static unsigned char    abbrinds[TZ_MAX_TYPES];
  415 static bool     ttisstds[TZ_MAX_TYPES];
  416 static bool     ttisgmts[TZ_MAX_TYPES];
  417 static char     chars[TZ_MAX_CHARS];
  418 static zic_t        trans[TZ_MAX_LEAPS];
  419 static zic_t        corr[TZ_MAX_LEAPS];
  420 static char     roll[TZ_MAX_LEAPS];
  421 
  422 /*
  423 ** Memory allocation.
  424 */
  425 
  426 static _Noreturn void
  427 memory_exhausted(const char *msg)
  428 {
  429     fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
  430     exit(EXIT_FAILURE);
  431 }
  432 
  433 static ATTRIBUTE_PURE size_t
  434 size_product(size_t nitems, size_t itemsize)
  435 {
  436     if (SIZE_MAX / itemsize < nitems)
  437         memory_exhausted(_("size overflow"));
  438     return nitems * itemsize;
  439 }
  440 
  441 static ATTRIBUTE_PURE size_t
  442 align_to(size_t size, size_t alignment)
  443 {
  444   size_t aligned_size = size + alignment - 1;
  445   aligned_size -= aligned_size % alignment;
  446   if (aligned_size < size)
  447     memory_exhausted(_("alignment overflow"));
  448   return aligned_size;
  449 }
  450 
  451 #if !HAVE_STRDUP
  452 static char *
  453 strdup(char const *str)
  454 {
  455   char *result = malloc(strlen(str) + 1);
  456   return result ? strcpy(result, str) : result;
  457 }
  458 #endif
  459 
  460 static void *
  461 memcheck(void *ptr)
  462 {
  463     if (ptr == NULL)
  464         memory_exhausted(strerror(errno));
  465     return ptr;
  466 }
  467 
  468 static void * ATTRIBUTE_MALLOC
  469 emalloc(size_t size)
  470 {
  471   return memcheck(malloc(size));
  472 }
  473 
  474 static void *
  475 erealloc(void *ptr, size_t size)
  476 {
  477   return memcheck(realloc(ptr, size));
  478 }
  479 
  480 static char * ATTRIBUTE_MALLOC
  481 ecpyalloc (char const *str)
  482 {
  483   return memcheck(strdup(str));
  484 }
  485 
  486 static void *
  487 growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
  488 {
  489     if (nitems < *nitems_alloc)
  490         return ptr;
  491     else {
  492         ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
  493         ptrdiff_t amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
  494         if ((amax - 1) / 3 * 2 < *nitems_alloc)
  495             memory_exhausted(_("integer overflow"));
  496         *nitems_alloc += (*nitems_alloc >> 1) + 1;
  497         return erealloc(ptr, size_product(*nitems_alloc, itemsize));
  498     }
  499 }
  500 
  501 /*
  502 ** Error handling.
  503 */
  504 
  505 static void
  506 eats(char const *name, lineno num, char const *rname, lineno rnum)
  507 {
  508     filename = name;
  509     linenum = num;
  510     rfilename = rname;
  511     rlinenum = rnum;
  512 }
  513 
  514 static void
  515 eat(char const *name, lineno num)
  516 {
  517     eats(name, num, NULL, -1);
  518 }
  519 
  520 static void ATTRIBUTE_FORMAT((printf, 1, 0))
  521 verror(const char *const string, va_list args)
  522 {
  523     /*
  524     ** Match the format of "cc" to allow sh users to
  525     **  zic ... 2>&1 | error -t "*" -v
  526     ** on BSD systems.
  527     */
  528     if (filename)
  529       fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), filename, linenum);
  530     vfprintf(stderr, string, args);
  531     if (rfilename != NULL)
  532         fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"),
  533             rfilename, rlinenum);
  534     fprintf(stderr, "\n");
  535 }
  536 
  537 static void ATTRIBUTE_FORMAT((printf, 1, 2))
  538 error(const char *const string, ...)
  539 {
  540     va_list args;
  541     va_start(args, string);
  542     verror(string, args);
  543     va_end(args);
  544     errors = true;
  545 }
  546 
  547 static void ATTRIBUTE_FORMAT((printf, 1, 2))
  548 warning(const char *const string, ...)
  549 {
  550     va_list args;
  551     fprintf(stderr, _("warning: "));
  552     va_start(args, string);
  553     verror(string, args);
  554     va_end(args);
  555     warnings = true;
  556 }
  557 
  558 static void
  559 close_file(FILE *stream, char const *dir, char const *name)
  560 {
  561   char const *e = (ferror(stream) ? _("I/O error")
  562            : fclose(stream) != 0 ? strerror(errno) : NULL);
  563   if (e) {
  564     fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
  565         dir ? dir : "", dir ? "/" : "",
  566         name ? name : "", name ? ": " : "",
  567         e);
  568     exit(EXIT_FAILURE);
  569   }
  570 }
  571 
  572 static _Noreturn void
  573 usage(FILE *stream, int status)
  574 {
  575   fprintf(stream,
  576       _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
  577         "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
  578         "\t[ -t localtime-link ] [ -L leapseconds ] [ filename ... ]\n\n"
  579         "Report bugs to %s.\n"),
  580       progname, progname, REPORT_BUGS_TO);
  581   if (status == EXIT_SUCCESS)
  582     close_file(stream, NULL, NULL);
  583   exit(status);
  584 }
  585 
  586 /* Change the working directory to DIR, possibly creating DIR and its
  587    ancestors.  After this is done, all files are accessed with names
  588    relative to DIR.  */
  589 static void
  590 change_directory (char const *dir)
  591 {
  592   if (chdir(dir) != 0) {
  593     int chdir_errno = errno;
  594     if (chdir_errno == ENOENT) {
  595       mkdirs(dir, false);
  596       chdir_errno = chdir(dir) == 0 ? 0 : errno;
  597     }
  598     if (chdir_errno != 0) {
  599       fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
  600           progname, dir, strerror(chdir_errno));
  601       exit(EXIT_FAILURE);
  602     }
  603   }
  604 }
  605 
  606 static const char * psxrules;
  607 static const char * lcltime;
  608 static const char * directory;
  609 static const char * leapsec;
  610 static const char * tzdefault;
  611 static const char * yitcommand;
  612 
  613 int
  614 main(int argc, char **argv)
  615 {
  616     register int c, k;
  617     register ptrdiff_t i, j;
  618 
  619 #ifdef S_IWGRP
  620     umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
  621 #endif
  622 #if HAVE_GETTEXT
  623     setlocale(LC_ALL, "");
  624 #ifdef TZ_DOMAINDIR
  625     bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
  626 #endif /* defined TEXTDOMAINDIR */
  627     textdomain(TZ_DOMAIN);
  628 #endif /* HAVE_GETTEXT */
  629     progname = argv[0];
  630     if (TYPE_BIT(zic_t) < 64) {
  631         fprintf(stderr, "%s: %s\n", progname,
  632             _("wild compilation-time specification of zic_t"));
  633         return EXIT_FAILURE;
  634     }
  635     for (k = 1; k < argc; k++)
  636         if (strcmp(argv[k], "--version") == 0) {
  637             printf("zic %s%s\n", PKGVERSION, TZVERSION);
  638             close_file(stdout, NULL, NULL);
  639             return EXIT_SUCCESS;
  640         } else if (strcmp(argv[k], "--help") == 0) {
  641             usage(stdout, EXIT_SUCCESS);
  642         }
  643     while ((c = getopt(argc, argv, "d:l:L:p:st:vy:")) != EOF && c != -1)
  644         switch (c) {
  645             default:
  646                 usage(stderr, EXIT_FAILURE);
  647             case 'd':
  648                 if (directory == NULL)
  649                     directory = optarg;
  650                 else {
  651                     fprintf(stderr,
  652 _("%s: More than one -d option specified\n"),
  653                         progname);
  654                     return EXIT_FAILURE;
  655                 }
  656                 break;
  657             case 'l':
  658                 if (lcltime == NULL)
  659                     lcltime = optarg;
  660                 else {
  661                     fprintf(stderr,
  662 _("%s: More than one -l option specified\n"),
  663                         progname);
  664                     return EXIT_FAILURE;
  665                 }
  666                 break;
  667             case 'p':
  668                 if (psxrules == NULL)
  669                     psxrules = optarg;
  670                 else {
  671                     fprintf(stderr,
  672 _("%s: More than one -p option specified\n"),
  673                         progname);
  674                     return EXIT_FAILURE;
  675                 }
  676                 break;
  677             case 't':
  678                 if (tzdefault != NULL) {
  679                   fprintf(stderr,
  680                       _("%s: More than one -t option"
  681                         " specified\n"),
  682                       progname);
  683                   return EXIT_FAILURE;
  684                 }
  685                 tzdefault = optarg;
  686                 break;
  687             case 'y':
  688                 if (yitcommand == NULL) {
  689                     warning(_("-y is obsolescent"));
  690                     yitcommand = optarg;
  691                 } else {
  692                     fprintf(stderr,
  693 _("%s: More than one -y option specified\n"),
  694                         progname);
  695                     return EXIT_FAILURE;
  696                 }
  697                 break;
  698             case 'L':
  699                 if (leapsec == NULL)
  700                     leapsec = optarg;
  701                 else {
  702                     fprintf(stderr,
  703 _("%s: More than one -L option specified\n"),
  704                         progname);
  705                     return EXIT_FAILURE;
  706                 }
  707                 break;
  708             case 'v':
  709                 noise = true;
  710                 break;
  711             case 's':
  712                 warning(_("-s ignored"));
  713                 break;
  714         }
  715     if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
  716         usage(stderr, EXIT_FAILURE);    /* usage message by request */
  717     if (directory == NULL)
  718         directory = TZDIR;
  719     if (tzdefault == NULL)
  720         tzdefault = TZDEFAULT;
  721     if (yitcommand == NULL)
  722         yitcommand = "yearistype";
  723 
  724     if (optind < argc && leapsec != NULL) {
  725         infile(leapsec);
  726         adjleap();
  727     }
  728 
  729     for (k = optind; k < argc; k++)
  730         infile(argv[k]);
  731     if (errors)
  732         return EXIT_FAILURE;
  733     associate();
  734     change_directory(directory);
  735     for (i = 0; i < nzones; i = j) {
  736         /*
  737         ** Find the next non-continuation zone entry.
  738         */
  739         for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
  740             continue;
  741         outzone(&zones[i], j - i);
  742     }
  743     /*
  744     ** Make links.
  745     */
  746     for (i = 0; i < nlinks; ++i) {
  747         eat(links[i].l_filename, links[i].l_linenum);
  748         dolink(links[i].l_from, links[i].l_to, false);
  749         if (noise)
  750             for (j = 0; j < nlinks; ++j)
  751                 if (strcmp(links[i].l_to,
  752                     links[j].l_from) == 0)
  753                         warning(_("link to link"));
  754     }
  755     if (lcltime != NULL) {
  756         eat(_("command line"), 1);
  757         dolink(lcltime, tzdefault, true);
  758     }
  759     if (psxrules != NULL) {
  760         eat(_("command line"), 1);
  761         dolink(psxrules, TZDEFRULES, true);
  762     }
  763     if (warnings && (ferror(stderr) || fclose(stderr) != 0))
  764       return EXIT_FAILURE;
  765     return errors ? EXIT_FAILURE : EXIT_SUCCESS;
  766 }
  767 
  768 static bool
  769 componentcheck(char const *name, char const *component,
  770            char const *component_end)
  771 {
  772     enum { component_len_max = 14 };
  773     ptrdiff_t component_len = component_end - component;
  774     if (component_len == 0) {
  775       if (!*name)
  776         error (_("empty file name"));
  777       else
  778         error (_(component == name
  779              ? "file name '%s' begins with '/'"
  780              : *component_end
  781              ? "file name '%s' contains '//'"
  782              : "file name '%s' ends with '/'"),
  783            name);
  784       return false;
  785     }
  786     if (0 < component_len && component_len <= 2
  787         && component[0] == '.' && component_end[-1] == '.') {
  788       int len = component_len;
  789       error(_("file name '%s' contains '%.*s' component"),
  790         name, len, component);
  791       return false;
  792     }
  793     if (noise) {
  794       if (0 < component_len && component[0] == '-')
  795         warning(_("file name '%s' component contains leading '-'"),
  796             name);
  797       if (component_len_max < component_len)
  798         warning(_("file name '%s' contains overlength component"
  799               " '%.*s...'"),
  800             name, component_len_max, component);
  801     }
  802     return true;
  803 }
  804 
  805 static bool
  806 namecheck(const char *name)
  807 {
  808     register char const *cp;
  809 
  810     /* Benign characters in a portable file name.  */
  811     static char const benign[] =
  812       "-/_"
  813       "abcdefghijklmnopqrstuvwxyz"
  814       "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  815 
  816     /* Non-control chars in the POSIX portable character set,
  817        excluding the benign characters.  */
  818     static char const printable_and_not_benign[] =
  819       " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
  820 
  821     register char const *component = name;
  822     for (cp = name; *cp; cp++) {
  823         unsigned char c = *cp;
  824         if (noise && !strchr(benign, c)) {
  825             warning((strchr(printable_and_not_benign, c)
  826                  ? _("file name '%s' contains byte '%c'")
  827                  : _("file name '%s' contains byte '\\%o'")),
  828                 name, c);
  829         }
  830         if (c == '/') {
  831             if (!componentcheck(name, component, cp))
  832               return false;
  833             component = cp + 1;
  834         }
  835     }
  836     return componentcheck(name, component, cp);
  837 }
  838 
  839 /* Create symlink contents suitable for symlinking FROM to TO, as a
  840    freshly allocated string.  FROM should be a relative file name, and
  841    is relative to the global variable DIRECTORY.  TO can be either
  842    relative or absolute.  */
  843 static char *
  844 relname(char const *from, char const *to)
  845 {
  846   size_t i, taillen, dotdotetcsize;
  847   size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
  848   char const *f = from;
  849   char *result = NULL;
  850   if (*to == '/') {
  851     /* Make F absolute too.  */
  852     size_t len = strlen(directory);
  853     bool needslash = len && directory[len - 1] != '/';
  854     linksize = len + needslash + strlen(from) + 1;
  855     f = result = emalloc(linksize);
  856     strcpy(result, directory);
  857     result[len] = '/';
  858     strcpy(result + len + needslash, from);
  859   }
  860   for (i = 0; f[i] && f[i] == to[i]; i++)
  861     if (f[i] == '/')
  862       dir_len = i + 1;
  863   for (; to[i]; i++)
  864     dotdots += to[i] == '/' && to[i - 1] != '/';
  865   taillen = strlen(f + dir_len);
  866   dotdotetcsize = 3 * dotdots + taillen + 1;
  867   if (dotdotetcsize <= linksize) {
  868     if (!result)
  869       result = emalloc(dotdotetcsize);
  870     for (i = 0; i < dotdots; i++)
  871       memcpy(result + 3 * i, "../", 3);
  872     memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
  873   }
  874   return result;
  875 }
  876 
  877 /* Hard link FROM to TO, following any symbolic links.
  878    Return 0 if successful, an error number otherwise.  */
  879 static int
  880 hardlinkerr(char const *from, char const *to)
  881 {
  882   int r = linkat(AT_FDCWD, from, AT_FDCWD, to, AT_SYMLINK_FOLLOW);
  883   return r == 0 ? 0 : errno;
  884 }
  885 
  886 static void
  887 dolink(char const *fromfield, char const *tofield, bool staysymlink)
  888 {
  889     bool todirs_made = false;
  890     int link_errno;
  891 
  892     /*
  893     ** We get to be careful here since
  894     ** there's a fair chance of root running us.
  895     */
  896     if (itsdir(fromfield)) {
  897         fprintf(stderr, _("%s: link from %s/%s failed: %s\n"),
  898             progname, directory, fromfield, strerror(EPERM));
  899         exit(EXIT_FAILURE);
  900     }
  901     if (staysymlink)
  902       staysymlink = itssymlink(tofield);
  903     if (remove(tofield) == 0)
  904       todirs_made = true;
  905     else if (errno != ENOENT) {
  906       char const *e = strerror(errno);
  907       fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
  908           progname, directory, tofield, e);
  909       exit(EXIT_FAILURE);
  910     }
  911     link_errno = staysymlink ? ENOTSUP : hardlinkerr(fromfield, tofield);
  912     if (link_errno == ENOENT && !todirs_made) {
  913       mkdirs(tofield, true);
  914       todirs_made = true;
  915       link_errno = hardlinkerr(fromfield, tofield);
  916     }
  917     if (link_errno != 0) {
  918       bool absolute = *fromfield == '/';
  919       char *linkalloc = absolute ? NULL : relname(fromfield, tofield);
  920       char const *contents = absolute ? fromfield : linkalloc;
  921       int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
  922       if (!todirs_made
  923           && (symlink_errno == ENOENT || symlink_errno == ENOTSUP)) {
  924         mkdirs(tofield, true);
  925         if (symlink_errno == ENOENT)
  926           symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
  927       }
  928       free(linkalloc);
  929       if (symlink_errno == 0) {
  930         if (link_errno != ENOTSUP)
  931           warning(_("symbolic link used because hard link failed: %s"),
  932               strerror(link_errno));
  933       } else {
  934         FILE *fp, *tp;
  935         int c;
  936         fp = fopen(fromfield, "rb");
  937         if (!fp) {
  938           char const *e = strerror(errno);
  939           fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
  940               progname, directory, fromfield, e);
  941           exit(EXIT_FAILURE);
  942         }
  943         tp = fopen(tofield, "wb");
  944         if (!tp) {
  945           char const *e = strerror(errno);
  946           fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
  947               progname, directory, tofield, e);
  948           exit(EXIT_FAILURE);
  949         }
  950         while ((c = getc(fp)) != EOF)
  951           putc(c, tp);
  952         close_file(fp, directory, fromfield);
  953         close_file(tp, directory, tofield);
  954         if (link_errno != ENOTSUP)
  955           warning(_("copy used because hard link failed: %s"),
  956               strerror(link_errno));
  957         else if (symlink_errno != ENOTSUP)
  958           warning(_("copy used because symbolic link failed: %s"),
  959               strerror(symlink_errno));
  960       }
  961     }
  962 }
  963 
  964 #define TIME_T_BITS_IN_FILE 64
  965 
  966 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
  967 static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
  968 
  969 /* Return true if NAME is a directory.  */
  970 static bool
  971 itsdir(char const *name)
  972 {
  973     struct stat st;
  974     int res = stat(name, &st);
  975 #ifdef S_ISDIR
  976     if (res == 0)
  977         return S_ISDIR(st.st_mode) != 0;
  978 #endif
  979     if (res == 0 || errno == EOVERFLOW) {
  980         size_t n = strlen(name);
  981         char *nameslashdot = emalloc(n + 3);
  982         bool dir;
  983         memcpy(nameslashdot, name, n);
  984         strcpy(&nameslashdot[n], &"/."[! (n && name[n - 1] != '/')]);
  985         dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
  986         free(nameslashdot);
  987         return dir;
  988     }
  989     return false;
  990 }
  991 
  992 /* Return true if NAME is a symbolic link.  */
  993 static bool
  994 itssymlink(char const *name)
  995 {
  996   char c;
  997   return 0 <= readlink(name, &c, 1);
  998 }
  999 
 1000 /*
 1001 ** Associate sets of rules with zones.
 1002 */
 1003 
 1004 /*
 1005 ** Sort by rule name.
 1006 */
 1007 
 1008 static int
 1009 rcomp(const void *cp1, const void *cp2)
 1010 {
 1011     return strcmp(((const struct rule *) cp1)->r_name,
 1012         ((const struct rule *) cp2)->r_name);
 1013 }
 1014 
 1015 static void
 1016 associate(void)
 1017 {
 1018     register struct zone *  zp;
 1019     register struct rule *  rp;
 1020     register ptrdiff_t i, j, base, out;
 1021 
 1022     if (nrules != 0) {
 1023         qsort(rules, nrules, sizeof *rules, rcomp);
 1024         for (i = 0; i < nrules - 1; ++i) {
 1025             if (strcmp(rules[i].r_name,
 1026                 rules[i + 1].r_name) != 0)
 1027                     continue;
 1028             if (strcmp(rules[i].r_filename,
 1029                 rules[i + 1].r_filename) == 0)
 1030                     continue;
 1031             eat(rules[i].r_filename, rules[i].r_linenum);
 1032             warning(_("same rule name in multiple files"));
 1033             eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
 1034             warning(_("same rule name in multiple files"));
 1035             for (j = i + 2; j < nrules; ++j) {
 1036                 if (strcmp(rules[i].r_name,
 1037                     rules[j].r_name) != 0)
 1038                         break;
 1039                 if (strcmp(rules[i].r_filename,
 1040                     rules[j].r_filename) == 0)
 1041                         continue;
 1042                 if (strcmp(rules[i + 1].r_filename,
 1043                     rules[j].r_filename) == 0)
 1044                         continue;
 1045                 break;
 1046             }
 1047             i = j - 1;
 1048         }
 1049     }
 1050     for (i = 0; i < nzones; ++i) {
 1051         zp = &zones[i];
 1052         zp->z_rules = NULL;
 1053         zp->z_nrules = 0;
 1054     }
 1055     for (base = 0; base < nrules; base = out) {
 1056         rp = &rules[base];
 1057         for (out = base + 1; out < nrules; ++out)
 1058             if (strcmp(rp->r_name, rules[out].r_name) != 0)
 1059                 break;
 1060         for (i = 0; i < nzones; ++i) {
 1061             zp = &zones[i];
 1062             if (strcmp(zp->z_rule, rp->r_name) != 0)
 1063                 continue;
 1064             zp->z_rules = rp;
 1065             zp->z_nrules = out - base;
 1066         }
 1067     }
 1068     for (i = 0; i < nzones; ++i) {
 1069         zp = &zones[i];
 1070         if (zp->z_nrules == 0) {
 1071             /*
 1072             ** Maybe we have a local standard time offset.
 1073             */
 1074             eat(zp->z_filename, zp->z_linenum);
 1075             zp->z_stdoff = getstdoff(zp->z_rule, &zp->z_isdst);
 1076             /*
 1077             ** Note, though, that if there's no rule,
 1078             ** a '%s' in the format is a bad thing.
 1079             */
 1080             if (zp->z_format_specifier == 's')
 1081                 error("%s", _("%s in ruleless zone"));
 1082         }
 1083     }
 1084     if (errors)
 1085         exit(EXIT_FAILURE);
 1086 }
 1087 
 1088 static void
 1089 infile(const char *name)
 1090 {
 1091     register FILE *         fp;
 1092     register char **        fields;
 1093     register char *         cp;
 1094     register const struct lookup *  lp;
 1095     register int            nfields;
 1096     register bool           wantcont;
 1097     register lineno         num;
 1098     char                buf[BUFSIZ];
 1099 
 1100     if (strcmp(name, "-") == 0) {
 1101         name = _("standard input");
 1102         fp = stdin;
 1103     } else if ((fp = fopen(name, "r")) == NULL) {
 1104         const char *e = strerror(errno);
 1105 
 1106         fprintf(stderr, _("%s: Can't open %s: %s\n"),
 1107             progname, name, e);
 1108         exit(EXIT_FAILURE);
 1109     }
 1110     wantcont = false;
 1111     for (num = 1; ; ++num) {
 1112         eat(name, num);
 1113         if (fgets(buf, sizeof buf, fp) != buf)
 1114             break;
 1115         cp = strchr(buf, '\n');
 1116         if (cp == NULL) {
 1117             error(_("line too long"));
 1118             exit(EXIT_FAILURE);
 1119         }
 1120         *cp = '\0';
 1121         fields = getfields(buf);
 1122         nfields = 0;
 1123         while (fields[nfields] != NULL) {
 1124             static char nada;
 1125 
 1126             if (strcmp(fields[nfields], "-") == 0)
 1127                 fields[nfields] = &nada;
 1128             ++nfields;
 1129         }
 1130         if (nfields == 0) {
 1131             /* nothing to do */
 1132         } else if (wantcont) {
 1133             wantcont = inzcont(fields, nfields);
 1134         } else {
 1135             struct lookup const *line_codes
 1136               = name == leapsec ? leap_line_codes : zi_line_codes;
 1137             lp = byword(fields[0], line_codes);
 1138             if (lp == NULL)
 1139                 error(_("input line of unknown type"));
 1140             else switch (lp->l_value) {
 1141                 case LC_RULE:
 1142                     inrule(fields, nfields);
 1143                     wantcont = false;
 1144                     break;
 1145                 case LC_ZONE:
 1146                     wantcont = inzone(fields, nfields);
 1147                     break;
 1148                 case LC_LINK:
 1149                     inlink(fields, nfields);
 1150                     wantcont = false;
 1151                     break;
 1152                 case LC_LEAP:
 1153                     inleap(fields, nfields);
 1154                     wantcont = false;
 1155                     break;
 1156                 default:    /* "cannot happen" */
 1157                     fprintf(stderr,
 1158 _("%s: panic: Invalid l_value %d\n"),
 1159                         progname, lp->l_value);
 1160                     exit(EXIT_FAILURE);
 1161             }
 1162         }
 1163         free(fields);
 1164     }
 1165     close_file(fp, NULL, filename);
 1166     if (wantcont)
 1167         error(_("expected continuation line not found"));
 1168 }
 1169 
 1170 /*
 1171 ** Convert a string of one of the forms
 1172 **  h   -h  hh:mm   -hh:mm  hh:mm:ss    -hh:mm:ss
 1173 ** into a number of seconds.
 1174 ** A null string maps to zero.
 1175 ** Call error with errstring and return zero on errors.
 1176 */
 1177 
 1178 static zic_t
 1179 gethms(char const *string, char const *errstring)
 1180 {
 1181     zic_t   hh;
 1182     int sign, mm = 0, ss = 0;
 1183     char hhx, mmx, ssx, xr = '0', xs;
 1184     int tenths = 0;
 1185     bool ok = true;
 1186 
 1187     if (string == NULL || *string == '\0')
 1188         return 0;
 1189     if (*string == '-') {
 1190         sign = -1;
 1191         ++string;
 1192     } else  sign = 1;
 1193     switch (sscanf(string,
 1194                "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
 1195                &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) {
 1196       default: ok = false; break;
 1197       case 8:
 1198         ok = '0' <= xr && xr <= '9';
 1199         /* fallthrough */
 1200       case 7:
 1201         ok &= ssx == '.';
 1202         if (ok && noise)
 1203           warning(_("fractional seconds rejected by"
 1204             " pre-2018 versions of zic"));
 1205         /* fallthrough */
 1206       case 5: ok &= mmx == ':'; /* fallthrough */
 1207       case 3: ok &= hhx == ':'; /* fallthrough */
 1208       case 1: break;
 1209     }
 1210     if (!ok) {
 1211             error("%s", errstring);
 1212             return 0;
 1213     }
 1214     if (hh < 0 ||
 1215         mm < 0 || mm >= MINSPERHOUR ||
 1216         ss < 0 || ss > SECSPERMIN) {
 1217             error("%s", errstring);
 1218             return 0;
 1219     }
 1220     if (ZIC_MAX / SECSPERHOUR < hh) {
 1221         error(_("time overflow"));
 1222         return 0;
 1223     }
 1224     ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even.  */
 1225     if (noise && (hh > HOURSPERDAY ||
 1226         (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
 1227 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
 1228     return oadd(sign * hh * SECSPERHOUR,
 1229             sign * (mm * SECSPERMIN + ss));
 1230 }
 1231 
 1232 static zic_t
 1233 getstdoff(char *field, bool *isdst)
 1234 {
 1235   int dst = -1;
 1236   zic_t stdoff;
 1237   size_t fieldlen = strlen(field);
 1238   if (fieldlen != 0) {
 1239     char *ep = field + fieldlen - 1;
 1240     switch (*ep) {
 1241       case 'd': dst = 1; *ep = '\0'; break;
 1242       case 's': dst = 0; *ep = '\0'; break;
 1243     }
 1244   }
 1245   stdoff = gethms(field, _("invalid saved time"));
 1246   *isdst = dst < 0 ? stdoff != 0 : dst;
 1247   return stdoff;
 1248 }
 1249 
 1250 static void
 1251 inrule(char **fields, int nfields)
 1252 {
 1253     static struct rule  r;
 1254 
 1255     if (nfields != RULE_FIELDS) {
 1256         error(_("wrong number of fields on Rule line"));
 1257         return;
 1258     }
 1259     switch (*fields[RF_NAME]) {
 1260       case '\0':
 1261       case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
 1262       case '+': case '-':
 1263       case '0': case '1': case '2': case '3': case '4':
 1264       case '5': case '6': case '7': case '8': case '9':
 1265         error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
 1266         return;
 1267     }
 1268     r.r_filename = filename;
 1269     r.r_linenum = linenum;
 1270     r.r_stdoff = getstdoff(fields[RF_STDOFF], &r.r_isdst);
 1271     rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
 1272         fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
 1273     r.r_name = ecpyalloc(fields[RF_NAME]);
 1274     r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
 1275     if (max_abbrvar_len < strlen(r.r_abbrvar))
 1276         max_abbrvar_len = strlen(r.r_abbrvar);
 1277     rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
 1278     rules[nrules++] = r;
 1279 }
 1280 
 1281 static bool
 1282 inzone(char **fields, int nfields)
 1283 {
 1284     register ptrdiff_t i;
 1285 
 1286     if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
 1287         error(_("wrong number of fields on Zone line"));
 1288         return false;
 1289     }
 1290     if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) {
 1291         error(
 1292 _("\"Zone %s\" line and -l option are mutually exclusive"),
 1293             tzdefault);
 1294         return false;
 1295     }
 1296     if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
 1297         error(
 1298 _("\"Zone %s\" line and -p option are mutually exclusive"),
 1299             TZDEFRULES);
 1300         return false;
 1301     }
 1302     for (i = 0; i < nzones; ++i)
 1303         if (zones[i].z_name != NULL &&
 1304             strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
 1305                 error(_("duplicate zone name %s"
 1306                     " (file \"%s\", line %"PRIdMAX")"),
 1307                     fields[ZF_NAME],
 1308                     zones[i].z_filename,
 1309                     zones[i].z_linenum);
 1310                 return false;
 1311         }
 1312     return inzsub(fields, nfields, false);
 1313 }
 1314 
 1315 static bool
 1316 inzcont(char **fields, int nfields)
 1317 {
 1318     if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
 1319         error(_("wrong number of fields on Zone continuation line"));
 1320         return false;
 1321     }
 1322     return inzsub(fields, nfields, true);
 1323 }
 1324 
 1325 static bool
 1326 inzsub(char **fields, int nfields, bool iscont)
 1327 {
 1328     register char *     cp;
 1329     char *          cp1;
 1330     static struct zone  z;
 1331     register int        i_gmtoff, i_rule, i_format;
 1332     register int        i_untilyear, i_untilmonth;
 1333     register int        i_untilday, i_untiltime;
 1334     register bool       hasuntil;
 1335 
 1336     if (iscont) {
 1337         i_gmtoff = ZFC_GMTOFF;
 1338         i_rule = ZFC_RULE;
 1339         i_format = ZFC_FORMAT;
 1340         i_untilyear = ZFC_TILYEAR;
 1341         i_untilmonth = ZFC_TILMONTH;
 1342         i_untilday = ZFC_TILDAY;
 1343         i_untiltime = ZFC_TILTIME;
 1344         z.z_name = NULL;
 1345     } else if (!namecheck(fields[ZF_NAME]))
 1346         return false;
 1347     else {
 1348         i_gmtoff = ZF_GMTOFF;
 1349         i_rule = ZF_RULE;
 1350         i_format = ZF_FORMAT;
 1351         i_untilyear = ZF_TILYEAR;
 1352         i_untilmonth = ZF_TILMONTH;
 1353         i_untilday = ZF_TILDAY;
 1354         i_untiltime = ZF_TILTIME;
 1355         z.z_name = ecpyalloc(fields[ZF_NAME]);
 1356     }
 1357     z.z_filename = filename;
 1358     z.z_linenum = linenum;
 1359     z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"));
 1360     if ((cp = strchr(fields[i_format], '%')) != 0) {
 1361         if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
 1362             || strchr(fields[i_format], '/')) {
 1363             error(_("invalid abbreviation format"));
 1364             return false;
 1365         }
 1366     }
 1367     z.z_rule = ecpyalloc(fields[i_rule]);
 1368     z.z_format = cp1 = ecpyalloc(fields[i_format]);
 1369     z.z_format_specifier = cp ? *cp : '\0';
 1370     if (z.z_format_specifier == 'z') {
 1371       if (noise)
 1372         warning(_("format '%s' not handled by pre-2015 versions of zic"),
 1373             z.z_format);
 1374       cp1[cp - fields[i_format]] = 's';
 1375     }
 1376     if (max_format_len < strlen(z.z_format))
 1377         max_format_len = strlen(z.z_format);
 1378     hasuntil = nfields > i_untilyear;
 1379     if (hasuntil) {
 1380         z.z_untilrule.r_filename = filename;
 1381         z.z_untilrule.r_linenum = linenum;
 1382         rulesub(&z.z_untilrule,
 1383             fields[i_untilyear],
 1384             "only",
 1385             "",
 1386             (nfields > i_untilmonth) ?
 1387             fields[i_untilmonth] : "Jan",
 1388             (nfields > i_untilday) ? fields[i_untilday] : "1",
 1389             (nfields > i_untiltime) ? fields[i_untiltime] : "0");
 1390         z.z_untiltime = rpytime(&z.z_untilrule,
 1391             z.z_untilrule.r_loyear);
 1392         if (iscont && nzones > 0 &&
 1393             z.z_untiltime > min_time &&
 1394             z.z_untiltime < max_time &&
 1395             zones[nzones - 1].z_untiltime > min_time &&
 1396             zones[nzones - 1].z_untiltime < max_time &&
 1397             zones[nzones - 1].z_untiltime >= z.z_untiltime) {
 1398                 error(_(
 1399 "Zone continuation line end time is not after end time of previous line"
 1400                     ));
 1401                 return false;
 1402         }
 1403     }
 1404     zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
 1405     zones[nzones++] = z;
 1406     /*
 1407     ** If there was an UNTIL field on this line,
 1408     ** there's more information about the zone on the next line.
 1409     */
 1410     return hasuntil;
 1411 }
 1412 
 1413 static void
 1414 inleap(char **fields, int nfields)
 1415 {
 1416     register const char *       cp;
 1417     register const struct lookup *  lp;
 1418     register zic_t          i, j;
 1419     zic_t               year;
 1420     int             month, day;
 1421     zic_t               dayoff, tod;
 1422     zic_t               t;
 1423     char xs;
 1424 
 1425     if (nfields != LEAP_FIELDS) {
 1426         error(_("wrong number of fields on Leap line"));
 1427         return;
 1428     }
 1429     dayoff = 0;
 1430     cp = fields[LP_YEAR];
 1431     if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
 1432         /*
 1433         ** Leapin' Lizards!
 1434         */
 1435         error(_("invalid leaping year"));
 1436         return;
 1437     }
 1438     if (!leapseen || leapmaxyear < year)
 1439         leapmaxyear = year;
 1440     if (!leapseen || leapminyear > year)
 1441         leapminyear = year;
 1442     leapseen = true;
 1443     j = EPOCH_YEAR;
 1444     while (j != year) {
 1445         if (year > j) {
 1446             i = len_years[isleap(j)];
 1447             ++j;
 1448         } else {
 1449             --j;
 1450             i = -len_years[isleap(j)];
 1451         }
 1452         dayoff = oadd(dayoff, i);
 1453     }
 1454     if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
 1455         error(_("invalid month name"));
 1456         return;
 1457     }
 1458     month = lp->l_value;
 1459     j = TM_JANUARY;
 1460     while (j != month) {
 1461         i = len_months[isleap(year)][j];
 1462         dayoff = oadd(dayoff, i);
 1463         ++j;
 1464     }
 1465     cp = fields[LP_DAY];
 1466     if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
 1467         day <= 0 || day > len_months[isleap(year)][month]) {
 1468             error(_("invalid day of month"));
 1469             return;
 1470     }
 1471     dayoff = oadd(dayoff, day - 1);
 1472     if (dayoff < min_time / SECSPERDAY) {
 1473         error(_("time too small"));
 1474         return;
 1475     }
 1476     if (dayoff > max_time / SECSPERDAY) {
 1477         error(_("time too large"));
 1478         return;
 1479     }
 1480     t = dayoff * SECSPERDAY;
 1481     tod = gethms(fields[LP_TIME], _("invalid time of day"));
 1482     cp = fields[LP_CORR];
 1483     {
 1484         register bool   positive;
 1485         int     count;
 1486 
 1487         if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
 1488             positive = false;
 1489             count = 1;
 1490         } else if (strcmp(cp, "+") == 0) {
 1491             positive = true;
 1492             count = 1;
 1493         } else {
 1494             error(_("illegal CORRECTION field on Leap line"));
 1495             return;
 1496         }
 1497         if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
 1498             error(_(
 1499                 "illegal Rolling/Stationary field on Leap line"
 1500                 ));
 1501             return;
 1502         }
 1503         t = tadd(t, tod);
 1504         if (t < 0) {
 1505             error(_("leap second precedes Epoch"));
 1506             return;
 1507         }
 1508         leapadd(t, positive, lp->l_value, count);
 1509     }
 1510 }
 1511 
 1512 static void
 1513 inlink(char **fields, int nfields)
 1514 {
 1515     struct link l;
 1516 
 1517     if (nfields != LINK_FIELDS) {
 1518         error(_("wrong number of fields on Link line"));
 1519         return;
 1520     }
 1521     if (*fields[LF_FROM] == '\0') {
 1522         error(_("blank FROM field on Link line"));
 1523         return;
 1524     }
 1525     if (! namecheck(fields[LF_TO]))
 1526       return;
 1527     l.l_filename = filename;
 1528     l.l_linenum = linenum;
 1529     l.l_from = ecpyalloc(fields[LF_FROM]);
 1530     l.l_to = ecpyalloc(fields[LF_TO]);
 1531     links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
 1532     links[nlinks++] = l;
 1533 }
 1534 
 1535 static void
 1536 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
 1537     const char *typep, const char *monthp, const char *dayp,
 1538     const char *timep)
 1539 {
 1540     register const struct lookup *  lp;
 1541     register const char *       cp;
 1542     register char *         dp;
 1543     register char *         ep;
 1544     char xs;
 1545 
 1546     if ((lp = byword(monthp, mon_names)) == NULL) {
 1547         error(_("invalid month name"));
 1548         return;
 1549     }
 1550     rp->r_month = lp->l_value;
 1551     rp->r_todisstd = false;
 1552     rp->r_todisgmt = false;
 1553     dp = ecpyalloc(timep);
 1554     if (*dp != '\0') {
 1555         ep = dp + strlen(dp) - 1;
 1556         switch (lowerit(*ep)) {
 1557             case 's':   /* Standard */
 1558                 rp->r_todisstd = true;
 1559                 rp->r_todisgmt = false;
 1560                 *ep = '\0';
 1561                 break;
 1562             case 'w':   /* Wall */
 1563                 rp->r_todisstd = false;
 1564                 rp->r_todisgmt = false;
 1565                 *ep = '\0';
 1566                 break;
 1567             case 'g':   /* Greenwich */
 1568             case 'u':   /* Universal */
 1569             case 'z':   /* Zulu */
 1570                 rp->r_todisstd = true;
 1571                 rp->r_todisgmt = true;
 1572                 *ep = '\0';
 1573                 break;
 1574         }
 1575     }
 1576     rp->r_tod = gethms(dp, _("invalid time of day"));
 1577     free(dp);
 1578     /*
 1579     ** Year work.
 1580     */
 1581     cp = loyearp;
 1582     lp = byword(cp, begin_years);
 1583     rp->r_lowasnum = lp == NULL;
 1584     if (!rp->r_lowasnum) switch (lp->l_value) {
 1585         case YR_MINIMUM:
 1586             rp->r_loyear = ZIC_MIN;
 1587             break;
 1588         case YR_MAXIMUM:
 1589             rp->r_loyear = ZIC_MAX;
 1590             break;
 1591         default:    /* "cannot happen" */
 1592             fprintf(stderr,
 1593                 _("%s: panic: Invalid l_value %d\n"),
 1594                 progname, lp->l_value);
 1595             exit(EXIT_FAILURE);
 1596     } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
 1597         error(_("invalid starting year"));
 1598         return;
 1599     }
 1600     cp = hiyearp;
 1601     lp = byword(cp, end_years);
 1602     rp->r_hiwasnum = lp == NULL;
 1603     if (!rp->r_hiwasnum) switch (lp->l_value) {
 1604         case YR_MINIMUM:
 1605             rp->r_hiyear = ZIC_MIN;
 1606             break;
 1607         case YR_MAXIMUM:
 1608             rp->r_hiyear = ZIC_MAX;
 1609             break;
 1610         case YR_ONLY:
 1611             rp->r_hiyear = rp->r_loyear;
 1612             break;
 1613         default:    /* "cannot happen" */
 1614             fprintf(stderr,
 1615                 _("%s: panic: Invalid l_value %d\n"),
 1616                 progname, lp->l_value);
 1617             exit(EXIT_FAILURE);
 1618     } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
 1619         error(_("invalid ending year"));
 1620         return;
 1621     }
 1622     if (rp->r_loyear > rp->r_hiyear) {
 1623         error(_("starting year greater than ending year"));
 1624         return;
 1625     }
 1626     if (*typep == '\0')
 1627         rp->r_yrtype = NULL;
 1628     else {
 1629         if (rp->r_loyear == rp->r_hiyear) {
 1630             error(_("typed single year"));
 1631             return;
 1632         }
 1633         warning(_("year type \"%s\" is obsolete; use \"-\" instead"),
 1634             typep);
 1635         rp->r_yrtype = ecpyalloc(typep);
 1636     }
 1637     /*
 1638     ** Day work.
 1639     ** Accept things such as:
 1640     **  1
 1641     **  lastSunday
 1642     **  last-Sunday (undocumented; warn about this)
 1643     **  Sun<=20
 1644     **  Sun>=7
 1645     */
 1646     dp = ecpyalloc(dayp);
 1647     if ((lp = byword(dp, lasts)) != NULL) {
 1648         rp->r_dycode = DC_DOWLEQ;
 1649         rp->r_wday = lp->l_value;
 1650         rp->r_dayofmonth = len_months[1][rp->r_month];
 1651     } else {
 1652         if ((ep = strchr(dp, '<')) != 0)
 1653             rp->r_dycode = DC_DOWLEQ;
 1654         else if ((ep = strchr(dp, '>')) != 0)
 1655             rp->r_dycode = DC_DOWGEQ;
 1656         else {
 1657             ep = dp;
 1658             rp->r_dycode = DC_DOM;
 1659         }
 1660         if (rp->r_dycode != DC_DOM) {
 1661             *ep++ = 0;
 1662             if (*ep++ != '=') {
 1663                 error(_("invalid day of month"));
 1664                 free(dp);
 1665                 return;
 1666             }
 1667             if ((lp = byword(dp, wday_names)) == NULL) {
 1668                 error(_("invalid weekday name"));
 1669                 free(dp);
 1670                 return;
 1671             }
 1672             rp->r_wday = lp->l_value;
 1673         }
 1674         if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
 1675             rp->r_dayofmonth <= 0 ||
 1676             (rp->r_dayofmonth > len_months[1][rp->r_month])) {
 1677                 error(_("invalid day of month"));
 1678                 free(dp);
 1679                 return;
 1680         }
 1681     }
 1682     free(dp);
 1683 }
 1684 
 1685 static void
 1686 convert(const int_fast32_t val, char *const buf)
 1687 {
 1688     register int    i;
 1689     register int    shift;
 1690     unsigned char *const b = (unsigned char *) buf;
 1691 
 1692     for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
 1693         b[i] = val >> shift;
 1694 }
 1695 
 1696 static void
 1697 convert64(const zic_t val, char *const buf)
 1698 {
 1699     register int    i;
 1700     register int    shift;
 1701     unsigned char *const b = (unsigned char *) buf;
 1702 
 1703     for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
 1704         b[i] = val >> shift;
 1705 }
 1706 
 1707 static void
 1708 puttzcode(const int_fast32_t val, FILE *const fp)
 1709 {
 1710     char    buf[4];
 1711 
 1712     convert(val, buf);
 1713     fwrite(buf, sizeof buf, 1, fp);
 1714 }
 1715 
 1716 static void
 1717 puttzcode64(const zic_t val, FILE *const fp)
 1718 {
 1719     char    buf[8];
 1720 
 1721     convert64(val, buf);
 1722     fwrite(buf, sizeof buf, 1, fp);
 1723 }
 1724 
 1725 static int
 1726 atcomp(const void *avp, const void *bvp)
 1727 {
 1728     const zic_t a = ((const struct attype *) avp)->at;
 1729     const zic_t b = ((const struct attype *) bvp)->at;
 1730 
 1731     return (a < b) ? -1 : (a > b);
 1732 }
 1733 
 1734 static void
 1735 swaptypes(int i, int j)
 1736 {
 1737   { zic_t t = gmtoffs[i]; gmtoffs[i] = gmtoffs[j]; gmtoffs[j] = t; }
 1738   { char t = isdsts[i]; isdsts[i] = isdsts[j]; isdsts[j] = t; }
 1739   { unsigned char t = abbrinds[i]; abbrinds[i] = abbrinds[j];
 1740     abbrinds[j] = t; }
 1741   { bool t = ttisstds[i]; ttisstds[i] = ttisstds[j]; ttisstds[j] = t; }
 1742   { bool t = ttisgmts[i]; ttisgmts[i] = ttisgmts[j]; ttisgmts[j] = t; }
 1743 }
 1744 
 1745 static void
 1746 writezone(const char *const name, const char *const string, char version,
 1747       int defaulttype)
 1748 {
 1749     register FILE *         fp;
 1750     register ptrdiff_t      i, j;
 1751     register int            leapcnt32, leapi32;
 1752     register ptrdiff_t      timecnt32, timei32;
 1753     register int            pass;
 1754     static const struct tzhead  tzh0;
 1755     static struct tzhead        tzh;
 1756     bool dir_checked = false;
 1757     zic_t one = 1;
 1758     zic_t y2038_boundary = one << 31;
 1759     ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
 1760 
 1761     /* Allocate the ATS and TYPES arrays via a single malloc,
 1762        as this is a bit faster.  */
 1763     zic_t *ats = emalloc(align_to(size_product(nats, sizeof *ats + 1),
 1764                       _Alignof(zic_t)));
 1765     void *typesptr = ats + nats;
 1766     unsigned char *types = typesptr;
 1767 
 1768     /*
 1769     ** Sort.
 1770     */
 1771     if (timecnt > 1)
 1772         qsort(attypes, timecnt, sizeof *attypes, atcomp);
 1773     /*
 1774     ** Optimize.
 1775     */
 1776     {
 1777         ptrdiff_t fromi, toi;
 1778 
 1779         toi = 0;
 1780         fromi = 0;
 1781         for ( ; fromi < timecnt; ++fromi) {
 1782             if (toi != 0 && ((attypes[fromi].at +
 1783                 gmtoffs[attypes[toi - 1].type]) <=
 1784                 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
 1785                 : attypes[toi - 2].type]))) {
 1786                     attypes[toi - 1].type =
 1787                         attypes[fromi].type;
 1788                     continue;
 1789             }
 1790             if (toi == 0
 1791                 || attypes[fromi].dontmerge
 1792                 || attypes[toi - 1].type != attypes[fromi].type)
 1793                     attypes[toi++] = attypes[fromi];
 1794         }
 1795         timecnt = toi;
 1796     }
 1797 
 1798     if (noise && timecnt > 1200) {
 1799       if (timecnt > TZ_MAX_TIMES)
 1800         warning(_("reference clients mishandle"
 1801               " more than %d transition times"),
 1802             TZ_MAX_TIMES);
 1803       else
 1804         warning(_("pre-2014 clients may mishandle"
 1805               " more than 1200 transition times"));
 1806     }
 1807     /*
 1808     ** Transfer.
 1809     */
 1810     for (i = 0; i < timecnt; ++i) {
 1811         ats[i] = attypes[i].at;
 1812         types[i] = attypes[i].type;
 1813     }
 1814 
 1815     /*
 1816     ** Correct for leap seconds.
 1817     */
 1818     for (i = 0; i < timecnt; ++i) {
 1819         j = leapcnt;
 1820         while (--j >= 0)
 1821             if (ats[i] > trans[j] - corr[j]) {
 1822                 ats[i] = tadd(ats[i], corr[j]);
 1823                 break;
 1824             }
 1825     }
 1826 
 1827     /* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1,
 1828        by inserting a no-op transition at time y2038_boundary - 1.
 1829        This works only for timestamps before the boundary, which
 1830        should be good enough in practice as QTBUG-53071 should be
 1831        long-dead by 2038.  Do this after correcting for leap
 1832        seconds, as the idea is to insert a transition just before
 1833        32-bit time_t rolls around, and this occurs at a slightly
 1834        different moment if transitions are leap-second corrected.  */
 1835     if (WORK_AROUND_QTBUG_53071 && timecnt != 0
 1836         && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
 1837       ats[timecnt] = y2038_boundary - 1;
 1838       types[timecnt] = types[timecnt - 1];
 1839       timecnt++;
 1840     }
 1841 
 1842     /*
 1843     ** Figure out 32-bit-limited starts and counts.
 1844     */
 1845     timecnt32 = timecnt;
 1846     timei32 = 0;
 1847     leapcnt32 = leapcnt;
 1848     leapi32 = 0;
 1849     while (0 < timecnt32 && INT32_MAX < ats[timecnt32 - 1])
 1850         --timecnt32;
 1851     while (1 < timecnt32 && ats[timei32] < INT32_MIN
 1852            && ats[timei32 + 1] <= INT32_MIN) {
 1853         /* Discard too-low transitions, except keep any last too-low
 1854            transition if no transition is exactly at INT32_MIN.
 1855            The kept transition will be output as an INT32_MIN
 1856            "transition" appropriate for buggy 32-bit clients that do
 1857            not use time type 0 for timestamps before the first
 1858            transition; see below.  */
 1859         --timecnt32;
 1860         ++timei32;
 1861     }
 1862     while (0 < leapcnt32 && INT32_MAX < trans[leapcnt32 - 1])
 1863         --leapcnt32;
 1864     while (0 < leapcnt32 && trans[leapi32] < INT32_MIN) {
 1865         --leapcnt32;
 1866         ++leapi32;
 1867     }
 1868     /*
 1869     ** Remove old file, if any, to snap links.
 1870     */
 1871     if (remove(name) == 0)
 1872         dir_checked = true;
 1873     else if (errno != ENOENT) {
 1874         const char *e = strerror(errno);
 1875 
 1876         fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
 1877             progname, directory, name, e);
 1878         exit(EXIT_FAILURE);
 1879     }
 1880     fp = fopen(name, "wb");
 1881     if (!fp) {
 1882       int fopen_errno = errno;
 1883       if (fopen_errno == ENOENT && !dir_checked) {
 1884         mkdirs(name, true);
 1885         fp = fopen(name, "wb");
 1886         fopen_errno = errno;
 1887       }
 1888       if (!fp) {
 1889         fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
 1890             progname, directory, name, strerror(fopen_errno));
 1891         exit(EXIT_FAILURE);
 1892       }
 1893     }
 1894     for (pass = 1; pass <= 2; ++pass) {
 1895         register ptrdiff_t thistimei, thistimecnt, thistimelim;
 1896         register int    thisleapi, thisleapcnt, thisleaplim;
 1897         int old0;
 1898         char        omittype[TZ_MAX_TYPES];
 1899         int     typemap[TZ_MAX_TYPES];
 1900         register int    thistypecnt;
 1901         char        thischars[TZ_MAX_CHARS];
 1902         int     thischarcnt;
 1903         bool        toomanytimes;
 1904         int     indmap[TZ_MAX_CHARS];
 1905 
 1906         if (pass == 1) {
 1907             thistimei = timei32;
 1908             thistimecnt = timecnt32;
 1909             toomanytimes = thistimecnt >> 31 >> 1 != 0;
 1910             thisleapi = leapi32;
 1911             thisleapcnt = leapcnt32;
 1912         } else {
 1913             thistimei = 0;
 1914             thistimecnt = timecnt;
 1915             toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
 1916             thisleapi = 0;
 1917             thisleapcnt = leapcnt;
 1918         }
 1919         if (toomanytimes)
 1920           error(_("too many transition times"));
 1921         thistimelim = thistimei + thistimecnt;
 1922         thisleaplim = thisleapi + thisleapcnt;
 1923         memset(omittype, true, typecnt);
 1924         omittype[defaulttype] = false;
 1925         for (i = thistimei; i < thistimelim; i++)
 1926           omittype[types[i]] = false;
 1927 
 1928         /* Reorder types to make DEFAULTTYPE type 0.
 1929            Use TYPEMAP to swap OLD0 and DEFAULTTYPE so that
 1930            DEFAULTTYPE appears as type 0 in the output instead
 1931            of OLD0.  TYPEMAP also omits unused types.  */
 1932         old0 = strlen(omittype);
 1933         swaptypes(old0, defaulttype);
 1934 
 1935 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
 1936         /*
 1937         ** For some pre-2011 systems: if the last-to-be-written
 1938         ** standard (or daylight) type has an offset different from the
 1939         ** most recently used offset,
 1940         ** append an (unused) copy of the most recently used type
 1941         ** (to help get global "altzone" and "timezone" variables
 1942         ** set correctly).
 1943         */
 1944         {
 1945             register int    mrudst, mrustd, hidst, histd, type;
 1946 
 1947             hidst = histd = mrudst = mrustd = -1;
 1948             for (i = thistimei; i < thistimelim; ++i)
 1949                 if (isdsts[types[i]])
 1950                     mrudst = types[i];
 1951                 else    mrustd = types[i];
 1952             for (i = old0; i < typecnt; i++)
 1953                 if (!omittype[i]) {
 1954                     if (isdsts[i])
 1955                         hidst = i;
 1956                     else    histd = i;
 1957                 }
 1958             if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
 1959                 gmtoffs[hidst] != gmtoffs[mrudst]) {
 1960                     isdsts[mrudst] = -1;
 1961                     type = addtype(gmtoffs[mrudst],
 1962                         &chars[abbrinds[mrudst]],
 1963                         true,
 1964                         ttisstds[mrudst],
 1965                         ttisgmts[mrudst]);
 1966                     isdsts[mrudst] = 1;
 1967                     omittype[type] = false;
 1968             }
 1969             if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
 1970                 gmtoffs[histd] != gmtoffs[mrustd]) {
 1971                     isdsts[mrustd] = -1;
 1972                     type = addtype(gmtoffs[mrustd],
 1973                         &chars[abbrinds[mrustd]],
 1974                         false,
 1975                         ttisstds[mrustd],
 1976                         ttisgmts[mrustd]);
 1977                     isdsts[mrustd] = 0;
 1978                     omittype[type] = false;
 1979             }
 1980         }
 1981 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
 1982         thistypecnt = 0;
 1983         for (i = old0; i < typecnt; i++)
 1984           if (!omittype[i])
 1985             typemap[i == old0 ? defaulttype
 1986                 : i == defaulttype ? old0 : i]
 1987               = thistypecnt++;
 1988 
 1989         for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
 1990             indmap[i] = -1;
 1991         thischarcnt = 0;
 1992         for (i = old0; i < typecnt; i++) {
 1993             register char * thisabbr;
 1994 
 1995             if (omittype[i])
 1996                 continue;
 1997             if (indmap[abbrinds[i]] >= 0)
 1998                 continue;
 1999             thisabbr = &chars[abbrinds[i]];
 2000             for (j = 0; j < thischarcnt; ++j)
 2001                 if (strcmp(&thischars[j], thisabbr) == 0)
 2002                     break;
 2003             if (j == thischarcnt) {
 2004                 strcpy(&thischars[thischarcnt], thisabbr);
 2005                 thischarcnt += strlen(thisabbr) + 1;
 2006             }
 2007             indmap[abbrinds[i]] = j;
 2008         }
 2009 #define DO(field)   fwrite(tzh.field, sizeof tzh.field, 1, fp)
 2010         tzh = tzh0;
 2011         memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
 2012         tzh.tzh_version[0] = version;
 2013         convert(thistypecnt, tzh.tzh_ttisgmtcnt);
 2014         convert(thistypecnt, tzh.tzh_ttisstdcnt);
 2015         convert(thisleapcnt, tzh.tzh_leapcnt);
 2016         convert(thistimecnt, tzh.tzh_timecnt);
 2017         convert(thistypecnt, tzh.tzh_typecnt);
 2018         convert(thischarcnt, tzh.tzh_charcnt);
 2019         DO(tzh_magic);
 2020         DO(tzh_version);
 2021         DO(tzh_reserved);
 2022         DO(tzh_ttisgmtcnt);
 2023         DO(tzh_ttisstdcnt);
 2024         DO(tzh_leapcnt);
 2025         DO(tzh_timecnt);
 2026         DO(tzh_typecnt);
 2027         DO(tzh_charcnt);
 2028 #undef DO
 2029         for (i = thistimei; i < thistimelim; ++i)
 2030             if (pass == 1)
 2031                 /*
 2032                 ** Output an INT32_MIN "transition"
 2033                 ** if appropriate; see above.
 2034                 */
 2035                 puttzcode(((ats[i] < INT32_MIN) ?
 2036                     INT32_MIN : ats[i]), fp);
 2037             else    puttzcode64(ats[i], fp);
 2038         for (i = thistimei; i < thistimelim; ++i) {
 2039             unsigned char   uc;
 2040 
 2041             uc = typemap[types[i]];
 2042             fwrite(&uc, sizeof uc, 1, fp);
 2043         }
 2044         for (i = old0; i < typecnt; i++)
 2045             if (!omittype[i]) {
 2046                 puttzcode(gmtoffs[i], fp);
 2047                 putc(isdsts[i], fp);
 2048                 putc((unsigned char) indmap[abbrinds[i]], fp);
 2049             }
 2050         if (thischarcnt != 0)
 2051             fwrite(thischars, sizeof thischars[0],
 2052                       thischarcnt, fp);
 2053         for (i = thisleapi; i < thisleaplim; ++i) {
 2054             register zic_t  todo;
 2055 
 2056             if (roll[i]) {
 2057                 if (timecnt == 0 || trans[i] < ats[0]) {
 2058                     j = 0;
 2059                     while (isdsts[j])
 2060                         if (++j >= typecnt) {
 2061                             j = 0;
 2062                             break;
 2063                         }
 2064                 } else {
 2065                     j = 1;
 2066                     while (j < timecnt &&
 2067                         trans[i] >= ats[j])
 2068                             ++j;
 2069                     j = types[j - 1];
 2070                 }
 2071                 todo = tadd(trans[i], -gmtoffs[j]);
 2072             } else  todo = trans[i];
 2073             if (pass == 1)
 2074                 puttzcode(todo, fp);
 2075             else    puttzcode64(todo, fp);
 2076             puttzcode(corr[i], fp);
 2077         }
 2078         for (i = old0; i < typecnt; i++)
 2079             if (!omittype[i])
 2080                 putc(ttisstds[i], fp);
 2081         for (i = old0; i < typecnt; i++)
 2082             if (!omittype[i])
 2083                 putc(ttisgmts[i], fp);
 2084         swaptypes(old0, defaulttype);
 2085     }
 2086     fprintf(fp, "\n%s\n", string);
 2087     close_file(fp, directory, name);
 2088     free(ats);
 2089 }
 2090 
 2091 static char const *
 2092 abbroffset(char *buf, zic_t offset)
 2093 {
 2094   char sign = '+';
 2095   int seconds, minutes;
 2096 
 2097   if (offset < 0) {
 2098     offset = -offset;
 2099     sign = '-';
 2100   }
 2101 
 2102   seconds = offset % SECSPERMIN;
 2103   offset /= SECSPERMIN;
 2104   minutes = offset % MINSPERHOUR;
 2105   offset /= MINSPERHOUR;
 2106   if (100 <= offset) {
 2107     error(_("%%z UT offset magnitude exceeds 99:59:59"));
 2108     return "%z";
 2109   } else {
 2110     char *p = buf;
 2111     *p++ = sign;
 2112     *p++ = '0' + offset / 10;
 2113     *p++ = '0' + offset % 10;
 2114     if (minutes | seconds) {
 2115       *p++ = '0' + minutes / 10;
 2116       *p++ = '0' + minutes % 10;
 2117       if (seconds) {
 2118     *p++ = '0' + seconds / 10;
 2119     *p++ = '0' + seconds % 10;
 2120       }
 2121     }
 2122     *p = '\0';
 2123     return buf;
 2124   }
 2125 }
 2126 
 2127 static size_t
 2128 doabbr(char *abbr, struct zone const *zp, char const *letters,
 2129        bool isdst, zic_t stdoff, bool doquotes)
 2130 {
 2131     register char * cp;
 2132     register char * slashp;
 2133     register size_t len;
 2134     char const *format = zp->z_format;
 2135 
 2136     slashp = strchr(format, '/');
 2137     if (slashp == NULL) {
 2138       char letterbuf[PERCENT_Z_LEN_BOUND + 1];
 2139       if (zp->z_format_specifier == 'z')
 2140         letters = abbroffset(letterbuf, zp->z_gmtoff + stdoff);
 2141       else if (!letters)
 2142         letters = "%s";
 2143       sprintf(abbr, format, letters);
 2144     } else if (isdst) {
 2145         strcpy(abbr, slashp + 1);
 2146     } else {
 2147         memcpy(abbr, format, slashp - format);
 2148         abbr[slashp - format] = '\0';
 2149     }
 2150     len = strlen(abbr);
 2151     if (!doquotes)
 2152         return len;
 2153     for (cp = abbr; is_alpha(*cp); cp++)
 2154         continue;
 2155     if (len > 0 && *cp == '\0')
 2156         return len;
 2157     abbr[len + 2] = '\0';
 2158     abbr[len + 1] = '>';
 2159     memmove(abbr + 1, abbr, len);
 2160     abbr[0] = '<';
 2161     return len + 2;
 2162 }
 2163 
 2164 static void
 2165 updateminmax(const zic_t x)
 2166 {
 2167     if (min_year > x)
 2168         min_year = x;
 2169     if (max_year < x)
 2170         max_year = x;
 2171 }
 2172 
 2173 static int
 2174 stringoffset(char *result, zic_t offset)
 2175 {
 2176     register int    hours;
 2177     register int    minutes;
 2178     register int    seconds;
 2179     bool negative = offset < 0;
 2180     int len = negative;
 2181 
 2182     if (negative) {
 2183         offset = -offset;
 2184         result[0] = '-';
 2185     }
 2186     seconds = offset % SECSPERMIN;
 2187     offset /= SECSPERMIN;
 2188     minutes = offset % MINSPERHOUR;
 2189     offset /= MINSPERHOUR;
 2190     hours = offset;
 2191     if (hours >= HOURSPERDAY * DAYSPERWEEK) {
 2192         result[0] = '\0';
 2193         return 0;
 2194     }
 2195     len += sprintf(result + len, "%d", hours);
 2196     if (minutes != 0 || seconds != 0) {
 2197         len += sprintf(result + len, ":%02d", minutes);
 2198         if (seconds != 0)
 2199             len += sprintf(result + len, ":%02d", seconds);
 2200     }
 2201     return len;
 2202 }
 2203 
 2204 static int
 2205 stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
 2206        const zic_t gmtoff)
 2207 {
 2208     register zic_t  tod = rp->r_tod;
 2209     register int    compat = 0;
 2210 
 2211     if (rp->r_dycode == DC_DOM) {
 2212         register int    month, total;
 2213 
 2214         if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
 2215             return -1;
 2216         total = 0;
 2217         for (month = 0; month < rp->r_month; ++month)
 2218             total += len_months[0][month];
 2219         /* Omit the "J" in Jan and Feb, as that's shorter.  */
 2220         if (rp->r_month <= 1)
 2221           result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
 2222         else
 2223           result += sprintf(result, "J%d", total + rp->r_dayofmonth);
 2224     } else {
 2225         register int    week;
 2226         register int    wday = rp->r_wday;
 2227         register int    wdayoff;
 2228 
 2229         if (rp->r_dycode == DC_DOWGEQ) {
 2230             wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
 2231             if (wdayoff)
 2232                 compat = 2013;
 2233             wday -= wdayoff;
 2234             tod += wdayoff * SECSPERDAY;
 2235             week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
 2236         } else if (rp->r_dycode == DC_DOWLEQ) {
 2237             if (rp->r_dayofmonth == len_months[1][rp->r_month])
 2238                 week = 5;
 2239             else {
 2240                 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
 2241                 if (wdayoff)
 2242                     compat = 2013;
 2243                 wday -= wdayoff;
 2244                 tod += wdayoff * SECSPERDAY;
 2245                 week = rp->r_dayofmonth / DAYSPERWEEK;
 2246             }
 2247         } else  return -1;  /* "cannot happen" */
 2248         if (wday < 0)
 2249             wday += DAYSPERWEEK;
 2250         result += sprintf(result, "M%d.%d.%d",
 2251                   rp->r_month + 1, week, wday);
 2252     }
 2253     if (rp->r_todisgmt)
 2254         tod += gmtoff;
 2255     if (rp->r_todisstd && !rp->r_isdst)
 2256         tod += dstoff;
 2257     if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
 2258         *result++ = '/';
 2259         if (! stringoffset(result, tod))
 2260             return -1;
 2261         if (tod < 0) {
 2262             if (compat < 2013)
 2263                 compat = 2013;
 2264         } else if (SECSPERDAY <= tod) {
 2265             if (compat < 1994)
 2266                 compat = 1994;
 2267         }
 2268     }
 2269     return compat;
 2270 }
 2271 
 2272 static int
 2273 rule_cmp(struct rule const *a, struct rule const *b)
 2274 {
 2275     if (!a)
 2276         return -!!b;
 2277     if (!b)
 2278         return 1;
 2279     if (a->r_hiyear != b->r_hiyear)
 2280         return a->r_hiyear < b->r_hiyear ? -1 : 1;
 2281     if (a->r_month - b->r_month != 0)
 2282         return a->r_month - b->r_month;
 2283     return a->r_dayofmonth - b->r_dayofmonth;
 2284 }
 2285 
 2286 enum { YEAR_BY_YEAR_ZONE = 1 };
 2287 
 2288 static int
 2289 stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
 2290 {
 2291     register const struct zone *    zp;
 2292     register struct rule *      rp;
 2293     register struct rule *      stdrp;
 2294     register struct rule *      dstrp;
 2295     register ptrdiff_t      i;
 2296     register const char *       abbrvar;
 2297     register int            compat = 0;
 2298     register int            c;
 2299     size_t              len;
 2300     int             offsetlen;
 2301     struct rule         stdr, dstr;
 2302 
 2303     result[0] = '\0';
 2304     zp = zpfirst + zonecount - 1;
 2305     stdrp = dstrp = NULL;
 2306     for (i = 0; i < zp->z_nrules; ++i) {
 2307         rp = &zp->z_rules[i];
 2308         if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
 2309             continue;
 2310         if (rp->r_yrtype != NULL)
 2311             continue;
 2312         if (!rp->r_isdst) {
 2313             if (stdrp == NULL)
 2314                 stdrp = rp;
 2315             else    return -1;
 2316         } else {
 2317             if (dstrp == NULL)
 2318                 dstrp = rp;
 2319             else    return -1;
 2320         }
 2321     }
 2322     if (stdrp == NULL && dstrp == NULL) {
 2323         /*
 2324         ** There are no rules running through "max".
 2325         ** Find the latest std rule in stdabbrrp
 2326         ** and latest rule of any type in stdrp.
 2327         */
 2328         register struct rule *stdabbrrp = NULL;
 2329         for (i = 0; i < zp->z_nrules; ++i) {
 2330             rp = &zp->z_rules[i];
 2331             if (!rp->r_isdst && rule_cmp(stdabbrrp, rp) < 0)
 2332                 stdabbrrp = rp;
 2333             if (rule_cmp(stdrp, rp) < 0)
 2334                 stdrp = rp;
 2335         }
 2336         /*
 2337         ** Horrid special case: if year is 2037,
 2338         ** presume this is a zone handled on a year-by-year basis;
 2339         ** do not try to apply a rule to the zone.
 2340         */
 2341         if (stdrp != NULL && stdrp->r_hiyear == 2037)
 2342             return YEAR_BY_YEAR_ZONE;
 2343 
 2344         if (stdrp != NULL && stdrp->r_isdst) {
 2345             /* Perpetual DST.  */
 2346             dstr.r_month = TM_JANUARY;
 2347             dstr.r_dycode = DC_DOM;
 2348             dstr.r_dayofmonth = 1;
 2349             dstr.r_tod = 0;
 2350             dstr.r_todisstd = dstr.r_todisgmt = false;
 2351             dstr.r_isdst = stdrp->r_isdst;
 2352             dstr.r_stdoff = stdrp->r_stdoff;
 2353             dstr.r_abbrvar = stdrp->r_abbrvar;
 2354             stdr.r_month = TM_DECEMBER;
 2355             stdr.r_dycode = DC_DOM;
 2356             stdr.r_dayofmonth = 31;
 2357             stdr.r_tod = SECSPERDAY + stdrp->r_stdoff;
 2358             stdr.r_todisstd = stdr.r_todisgmt = false;
 2359             stdr.r_isdst = false;
 2360             stdr.r_stdoff = 0;
 2361             stdr.r_abbrvar
 2362               = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
 2363             dstrp = &dstr;
 2364             stdrp = &stdr;
 2365         }
 2366     }
 2367     if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_isdst))
 2368         return -1;
 2369     abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
 2370     len = doabbr(result, zp, abbrvar, false, 0, true);
 2371     offsetlen = stringoffset(result + len, -zp->z_gmtoff);
 2372     if (! offsetlen) {
 2373         result[0] = '\0';
 2374         return -1;
 2375     }
 2376     len += offsetlen;
 2377     if (dstrp == NULL)
 2378         return compat;
 2379     len += doabbr(result + len, zp, dstrp->r_abbrvar,
 2380               dstrp->r_isdst, dstrp->r_stdoff, true);
 2381     if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
 2382       offsetlen = stringoffset(result + len,
 2383                    -(zp->z_gmtoff + dstrp->r_stdoff));
 2384       if (! offsetlen) {
 2385         result[0] = '\0';
 2386         return -1;
 2387       }
 2388       len += offsetlen;
 2389     }
 2390     result[len++] = ',';
 2391     c = stringrule(result + len, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
 2392     if (c < 0) {
 2393         result[0] = '\0';
 2394         return -1;
 2395     }
 2396     if (compat < c)
 2397         compat = c;
 2398     len += strlen(result + len);
 2399     result[len++] = ',';
 2400     c = stringrule(result + len, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
 2401     if (c < 0) {
 2402         result[0] = '\0';
 2403         return -1;
 2404     }
 2405     if (compat < c)
 2406         compat = c;
 2407     return compat;
 2408 }
 2409 
 2410 static void
 2411 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
 2412 {
 2413     register const struct zone *    zp;
 2414     register struct rule *      rp;
 2415     register ptrdiff_t      i, j;
 2416     register bool           usestart, useuntil;
 2417     register zic_t          starttime, untiltime;
 2418     register zic_t          gmtoff;
 2419     register zic_t          stdoff;
 2420     register zic_t          year;
 2421     register zic_t          startoff;
 2422     register bool           startttisstd;
 2423     register bool           startttisgmt;
 2424     register int            type;
 2425     register char *         startbuf;
 2426     register char *         ab;
 2427     register char *         envvar;
 2428     register int            max_abbr_len;
 2429     register int            max_envvar_len;
 2430     register bool           prodstic; /* all rules are min to max */
 2431     register int            compat;
 2432     register bool           do_extend;
 2433     register char           version;
 2434     ptrdiff_t lastatmax = -1;
 2435     zic_t one = 1;
 2436     zic_t y2038_boundary = one << 31;
 2437     zic_t max_year0;
 2438     int defaulttype = -1;
 2439 
 2440     max_abbr_len = 2 + max_format_len + max_abbrvar_len;
 2441     max_envvar_len = 2 * max_abbr_len + 5 * 9;
 2442     startbuf = emalloc(max_abbr_len + 1);
 2443     ab = emalloc(max_abbr_len + 1);
 2444     envvar = emalloc(max_envvar_len + 1);
 2445     INITIALIZE(untiltime);
 2446     INITIALIZE(starttime);
 2447     /*
 2448     ** Now. . .finally. . .generate some useful data!
 2449     */
 2450     timecnt = 0;
 2451     typecnt = 0;
 2452     charcnt = 0;
 2453     prodstic = zonecount == 1;
 2454     /*
 2455     ** Thanks to Earl Chew
 2456     ** for noting the need to unconditionally initialize startttisstd.
 2457     */
 2458     startttisstd = false;
 2459     startttisgmt = false;
 2460     min_year = max_year = EPOCH_YEAR;
 2461     if (leapseen) {
 2462         updateminmax(leapminyear);
 2463         updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
 2464     }
 2465     for (i = 0; i < zonecount; ++i) {
 2466         zp = &zpfirst[i];
 2467         if (i < zonecount - 1)
 2468             updateminmax(zp->z_untilrule.r_loyear);
 2469         for (j = 0; j < zp->z_nrules; ++j) {
 2470             rp = &zp->z_rules[j];
 2471             if (rp->r_lowasnum)
 2472                 updateminmax(rp->r_loyear);
 2473             if (rp->r_hiwasnum)
 2474                 updateminmax(rp->r_hiyear);
 2475             if (rp->r_lowasnum || rp->r_hiwasnum)
 2476                 prodstic = false;
 2477         }
 2478     }
 2479     /*
 2480     ** Generate lots of data if a rule can't cover all future times.
 2481     */
 2482     compat = stringzone(envvar, zpfirst, zonecount);
 2483     version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
 2484     do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE;
 2485     if (noise) {
 2486         if (!*envvar)
 2487             warning("%s %s",
 2488                 _("no POSIX environment variable for zone"),
 2489                 zpfirst->z_name);
 2490         else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) {
 2491             /* Circa-COMPAT clients, and earlier clients, might
 2492                not work for this zone when given dates before
 2493                1970 or after 2038.  */
 2494             warning(_("%s: pre-%d clients may mishandle"
 2495                   " distant timestamps"),
 2496                 zpfirst->z_name, compat);
 2497         }
 2498     }
 2499     if (do_extend) {
 2500         /*
 2501         ** Search through a couple of extra years past the obvious
 2502         ** 400, to avoid edge cases.  For example, suppose a non-POSIX
 2503         ** rule applies from 2012 onwards and has transitions in March
 2504         ** and September, plus some one-off transitions in November
 2505         ** 2013.  If zic looked only at the last 400 years, it would
 2506         ** set max_year=2413, with the intent that the 400 years 2014
 2507         ** through 2413 will be repeated.  The last transition listed
 2508         ** in the tzfile would be in 2413-09, less than 400 years
 2509         ** after the last one-off transition in 2013-11.  Two years
 2510         ** might be overkill, but with the kind of edge cases
 2511         ** available we're not sure that one year would suffice.
 2512         */
 2513         enum { years_of_observations = YEARSPERREPEAT + 2 };
 2514 
 2515         if (min_year >= ZIC_MIN + years_of_observations)
 2516             min_year -= years_of_observations;
 2517         else    min_year = ZIC_MIN;
 2518         if (max_year <= ZIC_MAX - years_of_observations)
 2519             max_year += years_of_observations;
 2520         else    max_year = ZIC_MAX;
 2521         /*
 2522         ** Regardless of any of the above,
 2523         ** for a "proDSTic" zone which specifies that its rules
 2524         ** always have and always will be in effect,
 2525         ** we only need one cycle to define the zone.
 2526         */
 2527         if (prodstic) {
 2528             min_year = 1900;
 2529             max_year = min_year + years_of_observations;
 2530         }
 2531     }
 2532     /*
 2533     ** For the benefit of older systems,
 2534     ** generate data from 1900 through 2038.
 2535     */
 2536     if (min_year > 1900)
 2537         min_year = 1900;
 2538     max_year0 = max_year;
 2539     if (max_year < 2038)
 2540         max_year = 2038;
 2541     for (i = 0; i < zonecount; ++i) {
 2542         /*
 2543         ** A guess that may well be corrected later.
 2544         */
 2545         stdoff = 0;
 2546         zp = &zpfirst[i];
 2547         usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
 2548         useuntil = i < (zonecount - 1);
 2549         if (useuntil && zp->z_untiltime <= min_time)
 2550             continue;
 2551         gmtoff = zp->z_gmtoff;
 2552         eat(zp->z_filename, zp->z_linenum);
 2553         *startbuf = '\0';
 2554         startoff = zp->z_gmtoff;
 2555         if (zp->z_nrules == 0) {
 2556             stdoff = zp->z_stdoff;
 2557             doabbr(startbuf, zp, NULL, zp->z_isdst, stdoff, false);
 2558             type = addtype(oadd(zp->z_gmtoff, stdoff),
 2559                 startbuf, zp->z_isdst, startttisstd,
 2560                 startttisgmt);
 2561             if (usestart) {
 2562                 addtt(starttime, type);
 2563                 usestart = false;
 2564             } else
 2565                 defaulttype = type;
 2566         } else for (year = min_year; year <= max_year; ++year) {
 2567             if (useuntil && year > zp->z_untilrule.r_hiyear)
 2568                 break;
 2569             /*
 2570             ** Mark which rules to do in the current year.
 2571             ** For those to do, calculate rpytime(rp, year);
 2572             */
 2573             for (j = 0; j < zp->z_nrules; ++j) {
 2574                 rp = &zp->z_rules[j];
 2575                 eats(zp->z_filename, zp->z_linenum,
 2576                     rp->r_filename, rp->r_linenum);
 2577                 rp->r_todo = year >= rp->r_loyear &&
 2578                         year <= rp->r_hiyear &&
 2579                         yearistype(year, rp->r_yrtype);
 2580                 if (rp->r_todo) {
 2581                     rp->r_temp = rpytime(rp, year);
 2582                     rp->r_todo
 2583                       = (rp->r_temp < y2038_boundary
 2584                          || year <= max_year0);
 2585                 }
 2586             }
 2587             for ( ; ; ) {
 2588                 register ptrdiff_t k;
 2589                 register zic_t  jtime, ktime;
 2590                 register zic_t  offset;
 2591 
 2592                 INITIALIZE(ktime);
 2593                 if (useuntil) {
 2594                     /*
 2595                     ** Turn untiltime into UT
 2596                     ** assuming the current gmtoff and
 2597                     ** stdoff values.
 2598                     */
 2599                     untiltime = zp->z_untiltime;
 2600                     if (!zp->z_untilrule.r_todisgmt)
 2601                         untiltime = tadd(untiltime,
 2602                             -gmtoff);
 2603                     if (!zp->z_untilrule.r_todisstd)
 2604                         untiltime = tadd(untiltime,
 2605                             -stdoff);
 2606                 }
 2607                 /*
 2608                 ** Find the rule (of those to do, if any)
 2609                 ** that takes effect earliest in the year.
 2610                 */
 2611                 k = -1;
 2612                 for (j = 0; j < zp->z_nrules; ++j) {
 2613                     rp = &zp->z_rules[j];
 2614                     if (!rp->r_todo)
 2615                         continue;
 2616                     eats(zp->z_filename, zp->z_linenum,
 2617                         rp->r_filename, rp->r_linenum);
 2618                     offset = rp->r_todisgmt ? 0 : gmtoff;
 2619                     if (!rp->r_todisstd)
 2620                         offset = oadd(offset, stdoff);
 2621                     jtime = rp->r_temp;
 2622                     if (jtime == min_time ||
 2623                         jtime == max_time)
 2624                             continue;
 2625                     jtime = tadd(jtime, -offset);
 2626                     if (k < 0 || jtime < ktime) {
 2627                         k = j;
 2628                         ktime = jtime;
 2629                     } else if (jtime == ktime) {
 2630                       char const *dup_rules_msg =
 2631                         _("two rules for same instant");
 2632                       eats(zp->z_filename, zp->z_linenum,
 2633                            rp->r_filename, rp->r_linenum);
 2634                       warning("%s", dup_rules_msg);
 2635                       rp = &zp->z_rules[k];
 2636                       eats(zp->z_filename, zp->z_linenum,
 2637                            rp->r_filename, rp->r_linenum);
 2638                       error("%s", dup_rules_msg);
 2639                     }
 2640                 }
 2641                 if (k < 0)
 2642                     break;  /* go on to next year */
 2643                 rp = &zp->z_rules[k];
 2644                 rp->r_todo = false;
 2645                 if (useuntil && ktime >= untiltime)
 2646                     break;
 2647                 stdoff = rp->r_stdoff;
 2648                 if (usestart && ktime == starttime)
 2649                     usestart = false;
 2650                 if (usestart) {
 2651                     if (ktime < starttime) {
 2652                         startoff = oadd(zp->z_gmtoff,
 2653                             stdoff);
 2654                         doabbr(startbuf, zp,
 2655                             rp->r_abbrvar,
 2656                             rp->r_isdst,
 2657                             rp->r_stdoff,
 2658                             false);
 2659                         continue;
 2660                     }
 2661                     if (*startbuf == '\0' &&
 2662                         startoff == oadd(zp->z_gmtoff,
 2663                         stdoff)) {
 2664                             doabbr(startbuf,
 2665                                 zp,
 2666                                 rp->r_abbrvar,
 2667                                 rp->r_isdst,
 2668                                 rp->r_stdoff,
 2669                                 false);
 2670                     }
 2671                 }
 2672                 eats(zp->z_filename, zp->z_linenum,
 2673                     rp->r_filename, rp->r_linenum);
 2674                 doabbr(ab, zp, rp->r_abbrvar,
 2675                        rp->r_isdst, rp->r_stdoff, false);
 2676                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
 2677                 type = addtype(offset, ab, rp->r_isdst,
 2678                     rp->r_todisstd, rp->r_todisgmt);
 2679                 if (defaulttype < 0 && !rp->r_isdst)
 2680                   defaulttype = type;
 2681                 if (rp->r_hiyear == ZIC_MAX
 2682                     && ! (0 <= lastatmax
 2683                       && ktime < attypes[lastatmax].at))
 2684                   lastatmax = timecnt;
 2685                 addtt(ktime, type);
 2686             }
 2687         }
 2688         if (usestart) {
 2689             if (*startbuf == '\0' &&
 2690                 zp->z_format != NULL &&
 2691                 strchr(zp->z_format, '%') == NULL &&
 2692                 strchr(zp->z_format, '/') == NULL)
 2693                     strcpy(startbuf, zp->z_format);
 2694             eat(zp->z_filename, zp->z_linenum);
 2695             if (*startbuf == '\0')
 2696 error(_("can't determine time zone abbreviation to use just after until time"));
 2697             else {
 2698               bool isdst = startoff != zp->z_gmtoff;
 2699               type = addtype(startoff, startbuf, isdst,
 2700                      startttisstd, startttisgmt);
 2701               if (defaulttype < 0 && !isdst)
 2702                 defaulttype = type;
 2703               addtt(starttime, type);
 2704             }
 2705         }
 2706         /*
 2707         ** Now we may get to set starttime for the next zone line.
 2708         */
 2709         if (useuntil) {
 2710             startttisstd = zp->z_untilrule.r_todisstd;
 2711             startttisgmt = zp->z_untilrule.r_todisgmt;
 2712             starttime = zp->z_untiltime;
 2713             if (!startttisstd)
 2714                 starttime = tadd(starttime, -stdoff);
 2715             if (!startttisgmt)
 2716                 starttime = tadd(starttime, -gmtoff);
 2717         }
 2718     }
 2719     if (defaulttype < 0)
 2720       defaulttype = 0;
 2721     if (0 <= lastatmax)
 2722       attypes[lastatmax].dontmerge = true;
 2723     if (do_extend) {
 2724         /*
 2725         ** If we're extending the explicitly listed observations
 2726         ** for 400 years because we can't fill the POSIX-TZ field,
 2727         ** check whether we actually ended up explicitly listing
 2728         ** observations through that period.  If there aren't any
 2729         ** near the end of the 400-year period, add a redundant
 2730         ** one at the end of the final year, to make it clear
 2731         ** that we are claiming to have definite knowledge of
 2732         ** the lack of transitions up to that point.
 2733         */
 2734         struct rule xr;
 2735         struct attype *lastat;
 2736         xr.r_month = TM_JANUARY;
 2737         xr.r_dycode = DC_DOM;
 2738         xr.r_dayofmonth = 1;
 2739         xr.r_tod = 0;
 2740         for (lastat = &attypes[0], i = 1; i < timecnt; i++)
 2741             if (attypes[i].at > lastat->at)
 2742                 lastat = &attypes[i];
 2743         if (lastat->at < rpytime(&xr, max_year - 1)) {
 2744             addtt(rpytime(&xr, max_year + 1), lastat->type);
 2745             attypes[timecnt - 1].dontmerge = true;
 2746         }
 2747     }
 2748     writezone(zpfirst->z_name, envvar, version, defaulttype);
 2749     free(startbuf);
 2750     free(ab);
 2751     free(envvar);
 2752 }
 2753 
 2754 static void
 2755 addtt(zic_t starttime, int type)
 2756 {
 2757     attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
 2758     attypes[timecnt].at = starttime;
 2759     attypes[timecnt].dontmerge = false;
 2760     attypes[timecnt].type = type;
 2761     ++timecnt;
 2762 }
 2763 
 2764 static int
 2765 addtype(zic_t gmtoff, char const *abbr, bool isdst, bool ttisstd, bool ttisgmt)
 2766 {
 2767     register int    i, j;
 2768 
 2769     /*
 2770     ** See if there's already an entry for this zone type.
 2771     ** If so, just return its index.
 2772     */
 2773     for (i = 0; i < typecnt; ++i) {
 2774         if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
 2775             strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
 2776             ttisstd == ttisstds[i] &&
 2777             ttisgmt == ttisgmts[i])
 2778                 return i;
 2779     }
 2780     /*
 2781     ** There isn't one; add a new one, unless there are already too
 2782     ** many.
 2783     */
 2784     if (typecnt >= TZ_MAX_TYPES) {
 2785         error(_("too many local time types"));
 2786         exit(EXIT_FAILURE);
 2787     }
 2788     if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
 2789         error(_("UT offset out of range"));
 2790         exit(EXIT_FAILURE);
 2791     }
 2792     gmtoffs[i] = gmtoff;
 2793     isdsts[i] = isdst;
 2794     ttisstds[i] = ttisstd;
 2795     ttisgmts[i] = ttisgmt;
 2796 
 2797     for (j = 0; j < charcnt; ++j)
 2798         if (strcmp(&chars[j], abbr) == 0)
 2799             break;
 2800     if (j == charcnt)
 2801         newabbr(abbr);
 2802     abbrinds[i] = j;
 2803     ++typecnt;
 2804     return i;
 2805 }
 2806 
 2807 static void
 2808 leapadd(zic_t t, bool positive, int rolling, int count)
 2809 {
 2810     register int    i, j;
 2811 
 2812     if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
 2813         error(_("too many leap seconds"));
 2814         exit(EXIT_FAILURE);
 2815     }
 2816     for (i = 0; i < leapcnt; ++i)
 2817         if (t <= trans[i])
 2818             break;
 2819     do {
 2820         for (j = leapcnt; j > i; --j) {
 2821             trans[j] = trans[j - 1];
 2822             corr[j] = corr[j - 1];
 2823             roll[j] = roll[j - 1];
 2824         }
 2825         trans[i] = t;
 2826         corr[i] = positive ? 1 : -count;
 2827         roll[i] = rolling;
 2828         ++leapcnt;
 2829     } while (positive && --count != 0);
 2830 }
 2831 
 2832 static void
 2833 adjleap(void)
 2834 {
 2835     register int    i;
 2836     register zic_t  last = 0;
 2837     register zic_t  prevtrans = 0;
 2838 
 2839     /*
 2840     ** propagate leap seconds forward
 2841     */
 2842     for (i = 0; i < leapcnt; ++i) {
 2843         if (trans[i] - prevtrans < 28 * SECSPERDAY) {
 2844           error(_("Leap seconds too close together"));
 2845           exit(EXIT_FAILURE);
 2846         }
 2847         prevtrans = trans[i];
 2848         trans[i] = tadd(trans[i], last);
 2849         last = corr[i] += last;
 2850     }
 2851 }
 2852 
 2853 static char *
 2854 shellquote(char *b, char const *s)
 2855 {
 2856   *b++ = '\'';
 2857   while (*s) {
 2858     if (*s == '\'')
 2859       *b++ = '\'', *b++ = '\\', *b++ = '\'';
 2860     *b++ = *s++;
 2861   }
 2862   *b++ = '\'';
 2863   return b;
 2864 }
 2865 
 2866 static bool
 2867 yearistype(zic_t year, const char *type)
 2868 {
 2869     char *buf;
 2870     char *b;
 2871     int result;
 2872 
 2873     if (type == NULL || *type == '\0')
 2874         return true;
 2875     buf = emalloc(1 + 4 * strlen(yitcommand) + 2
 2876               + INT_STRLEN_MAXIMUM(zic_t) + 2 + 4 * strlen(type) + 2);
 2877     b = shellquote(buf, yitcommand);
 2878     *b++ = ' ';
 2879     b += sprintf(b, "%"PRIdZIC, year);
 2880     *b++ = ' ';
 2881     b = shellquote(b, type);
 2882     *b = '\0';
 2883     result = system(buf);
 2884     if (WIFEXITED(result)) {
 2885       int status = WEXITSTATUS(result);
 2886       if (status <= 1) {
 2887         free(buf);
 2888         return status == 0;
 2889       }
 2890     }
 2891     error(_("Wild result from command execution"));
 2892     fprintf(stderr, _("%s: command was '%s', result was %d\n"),
 2893         progname, buf, result);
 2894     exit(EXIT_FAILURE);
 2895 }
 2896 
 2897 /* Is A a space character in the C locale?  */
 2898 static bool
 2899 is_space(char a)
 2900 {
 2901     switch (a) {
 2902       default:
 2903         return false;
 2904       case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
 2905         return true;
 2906     }
 2907 }
 2908 
 2909 /* Is A an alphabetic character in the C locale?  */
 2910 static bool
 2911 is_alpha(char a)
 2912 {
 2913     switch (a) {
 2914       default:
 2915         return false;
 2916       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
 2917       case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
 2918       case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
 2919       case 'V': case 'W': case 'X': case 'Y': case 'Z':
 2920       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
 2921       case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
 2922       case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
 2923       case 'v': case 'w': case 'x': case 'y': case 'z':
 2924         return true;
 2925     }
 2926 }
 2927 
 2928 /* If A is an uppercase character in the C locale, return its lowercase
 2929    counterpart.  Otherwise, return A.  */
 2930 static char
 2931 lowerit(char a)
 2932 {
 2933     switch (a) {
 2934       default: return a;
 2935       case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
 2936       case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
 2937       case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
 2938       case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
 2939       case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
 2940       case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
 2941       case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
 2942       case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
 2943       case 'Y': return 'y'; case 'Z': return 'z';
 2944     }
 2945 }
 2946 
 2947 /* case-insensitive equality */
 2948 static ATTRIBUTE_PURE bool
 2949 ciequal(register const char *ap, register const char *bp)
 2950 {
 2951     while (lowerit(*ap) == lowerit(*bp++))
 2952         if (*ap++ == '\0')
 2953             return true;
 2954     return false;
 2955 }
 2956 
 2957 static ATTRIBUTE_PURE bool
 2958 itsabbr(register const char *abbr, register const char *word)
 2959 {
 2960     if (lowerit(*abbr) != lowerit(*word))
 2961         return false;
 2962     ++word;
 2963     while (*++abbr != '\0')
 2964         do {
 2965             if (*word == '\0')
 2966                 return false;
 2967         } while (lowerit(*word++) != lowerit(*abbr));
 2968     return true;
 2969 }
 2970 
 2971 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case.  */
 2972 
 2973 static ATTRIBUTE_PURE bool
 2974 ciprefix(char const *abbr, char const *word)
 2975 {
 2976   do
 2977     if (!*abbr)
 2978       return true;
 2979   while (lowerit(*abbr++) == lowerit(*word++));
 2980 
 2981   return false;
 2982 }
 2983 
 2984 static const struct lookup *
 2985 byword(const char *word, const struct lookup *table)
 2986 {
 2987     register const struct lookup *  foundlp;
 2988     register const struct lookup *  lp;
 2989 
 2990     if (word == NULL || table == NULL)
 2991         return NULL;
 2992 
 2993     /* If TABLE is LASTS and the word starts with "last" followed
 2994        by a non-'-', skip the "last" and look in WDAY_NAMES instead.
 2995        Warn about any usage of the undocumented prefix "last-".  */
 2996     if (table == lasts && ciprefix("last", word) && word[4]) {
 2997       if (word[4] == '-')
 2998         warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
 2999             word, word + 5);
 3000       else {
 3001         word += 4;
 3002         table = wday_names;
 3003       }
 3004     }
 3005 
 3006     /*
 3007     ** Look for exact match.
 3008     */
 3009     for (lp = table; lp->l_word != NULL; ++lp)
 3010         if (ciequal(word, lp->l_word))
 3011             return lp;
 3012     /*
 3013     ** Look for inexact match.
 3014     */
 3015     foundlp = NULL;
 3016     for (lp = table; lp->l_word != NULL; ++lp)
 3017         if (ciprefix(word, lp->l_word)) {
 3018             if (foundlp == NULL)
 3019                 foundlp = lp;
 3020             else    return NULL;    /* multiple inexact matches */
 3021         }
 3022 
 3023     /* Warn about any backward-compatibility issue with pre-2017c zic.  */
 3024     if (foundlp) {
 3025       bool pre_2017c_match = false;
 3026       for (lp = table; lp->l_word; lp++)
 3027         if (itsabbr(word, lp->l_word)) {
 3028           if (pre_2017c_match) {
 3029         warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
 3030         break;
 3031           }
 3032           pre_2017c_match = true;
 3033         }
 3034     }
 3035 
 3036     return foundlp;
 3037 }
 3038 
 3039 static char **
 3040 getfields(register char *cp)
 3041 {
 3042     register char *     dp;
 3043     register char **    array;
 3044     register int        nsubs;
 3045 
 3046     if (cp == NULL)
 3047         return NULL;
 3048     array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
 3049     nsubs = 0;
 3050     for ( ; ; ) {
 3051         while (is_space(*cp))
 3052                 ++cp;
 3053         if (*cp == '\0' || *cp == '#')
 3054             break;
 3055         array[nsubs++] = dp = cp;
 3056         do {
 3057             if ((*dp = *cp++) != '"')
 3058                 ++dp;
 3059             else while ((*dp = *cp++) != '"')
 3060                 if (*dp != '\0')
 3061                     ++dp;
 3062                 else {
 3063                   error(_("Odd number of quotation marks"));
 3064                   exit(EXIT_FAILURE);
 3065                 }
 3066         } while (*cp && *cp != '#' && !is_space(*cp));
 3067         if (is_space(*cp))
 3068             ++cp;
 3069         *dp = '\0';
 3070     }
 3071     array[nsubs] = NULL;
 3072     return array;
 3073 }
 3074 
 3075 static _Noreturn void
 3076 time_overflow(void)
 3077 {
 3078   error(_("time overflow"));
 3079   exit(EXIT_FAILURE);
 3080 }
 3081 
 3082 static ATTRIBUTE_PURE zic_t
 3083 oadd(zic_t t1, zic_t t2)
 3084 {
 3085     if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
 3086       time_overflow();
 3087     return t1 + t2;
 3088 }
 3089 
 3090 static ATTRIBUTE_PURE zic_t
 3091 tadd(zic_t t1, zic_t t2)
 3092 {
 3093   if (t1 < 0) {
 3094     if (t2 < min_time - t1) {
 3095       if (t1 != min_time)
 3096     time_overflow();
 3097       return min_time;
 3098     }
 3099   } else {
 3100     if (max_time - t1 < t2) {
 3101       if (t1 != max_time)
 3102     time_overflow();
 3103       return max_time;
 3104     }
 3105   }
 3106   return t1 + t2;
 3107 }
 3108 
 3109 /*
 3110 ** Given a rule, and a year, compute the date (in seconds since January 1,
 3111 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
 3112 */
 3113 
 3114 static zic_t
 3115 rpytime(const struct rule *rp, zic_t wantedy)
 3116 {
 3117     register int    m, i;
 3118     register zic_t  dayoff;         /* with a nod to Margaret O. */
 3119     register zic_t  t, y;
 3120 
 3121     if (wantedy == ZIC_MIN)
 3122         return min_time;
 3123     if (wantedy == ZIC_MAX)
 3124         return max_time;
 3125     dayoff = 0;
 3126     m = TM_JANUARY;
 3127     y = EPOCH_YEAR;
 3128     if (y < wantedy) {
 3129       wantedy -= y;
 3130       dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
 3131       wantedy %= YEARSPERREPEAT;
 3132       wantedy += y;
 3133     } else if (wantedy < 0) {
 3134       dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
 3135       wantedy %= YEARSPERREPEAT;
 3136     }
 3137     while (wantedy != y) {
 3138         if (wantedy > y) {
 3139             i = len_years[isleap(y)];
 3140             ++y;
 3141         } else {
 3142             --y;
 3143             i = -len_years[isleap(y)];
 3144         }
 3145         dayoff = oadd(dayoff, i);
 3146     }
 3147     while (m != rp->r_month) {
 3148         i = len_months[isleap(y)][m];
 3149         dayoff = oadd(dayoff, i);
 3150         ++m;
 3151     }
 3152     i = rp->r_dayofmonth;
 3153     if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
 3154         if (rp->r_dycode == DC_DOWLEQ)
 3155             --i;
 3156         else {
 3157             error(_("use of 2/29 in non leap-year"));
 3158             exit(EXIT_FAILURE);
 3159         }
 3160     }
 3161     --i;
 3162     dayoff = oadd(dayoff, i);
 3163     if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
 3164         register zic_t  wday;
 3165 
 3166 #define LDAYSPERWEEK    ((zic_t) DAYSPERWEEK)
 3167         wday = EPOCH_WDAY;
 3168         /*
 3169         ** Don't trust mod of negative numbers.
 3170         */
 3171         if (dayoff >= 0)
 3172             wday = (wday + dayoff) % LDAYSPERWEEK;
 3173         else {
 3174             wday -= ((-dayoff) % LDAYSPERWEEK);
 3175             if (wday < 0)
 3176                 wday += LDAYSPERWEEK;
 3177         }
 3178         while (wday != rp->r_wday)
 3179             if (rp->r_dycode == DC_DOWGEQ) {
 3180                 dayoff = oadd(dayoff, 1);
 3181                 if (++wday >= LDAYSPERWEEK)
 3182                     wday = 0;
 3183                 ++i;
 3184             } else {
 3185                 dayoff = oadd(dayoff, -1);
 3186                 if (--wday < 0)
 3187                     wday = LDAYSPERWEEK - 1;
 3188                 --i;
 3189             }
 3190         if (i < 0 || i >= len_months[isleap(y)][m]) {
 3191             if (noise)
 3192                 warning(_("rule goes past start/end of month; \
 3193 will not work with pre-2004 versions of zic"));
 3194         }
 3195     }
 3196     if (dayoff < min_time / SECSPERDAY)
 3197         return min_time;
 3198     if (dayoff > max_time / SECSPERDAY)
 3199         return max_time;
 3200     t = (zic_t) dayoff * SECSPERDAY;
 3201     return tadd(t, rp->r_tod);
 3202 }
 3203 
 3204 static void
 3205 newabbr(const char *string)
 3206 {
 3207     register int    i;
 3208 
 3209     if (strcmp(string, GRANDPARENTED) != 0) {
 3210         register const char *   cp;
 3211         const char *        mp;
 3212 
 3213         cp = string;
 3214         mp = NULL;
 3215         while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
 3216                || *cp == '-' || *cp == '+')
 3217                 ++cp;
 3218         if (noise && cp - string < 3)
 3219           mp = _("time zone abbreviation has fewer than 3 characters");
 3220         if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
 3221           mp = _("time zone abbreviation has too many characters");
 3222         if (*cp != '\0')
 3223 mp = _("time zone abbreviation differs from POSIX standard");
 3224         if (mp != NULL)
 3225             warning("%s (%s)", mp, string);
 3226     }
 3227     i = strlen(string) + 1;
 3228     if (charcnt + i > TZ_MAX_CHARS) {
 3229         error(_("too many, or too long, time zone abbreviations"));
 3230         exit(EXIT_FAILURE);
 3231     }
 3232     strcpy(&chars[charcnt], string);
 3233     charcnt += i;
 3234 }
 3235 
 3236 /* Ensure that the directories of ARGNAME exist, by making any missing
 3237    ones.  If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
 3238    do it for ARGNAME too.  Exit with failure if there is trouble.
 3239    Do not consider an existing non-directory to be trouble.  */
 3240 static void
 3241 mkdirs(char const *argname, bool ancestors)
 3242 {
 3243     register char * name;
 3244     register char * cp;
 3245 
 3246     cp = name = ecpyalloc(argname);
 3247 
 3248     /* On MS-Windows systems, do not worry about drive letters or
 3249        backslashes, as this should suffice in practice.  Time zone
 3250        names do not use drive letters and backslashes.  If the -d
 3251        option of zic does not name an already-existing directory,
 3252        it can use slashes to separate the already-existing
 3253        ancestor prefix from the to-be-created subdirectories.  */
 3254 
 3255     /* Do not mkdir a root directory, as it must exist.  */
 3256     while (*cp == '/')
 3257       cp++;
 3258 
 3259     while (cp && ((cp = strchr(cp, '/')) || !ancestors)) {
 3260         if (cp)
 3261           *cp = '\0';
 3262         /*
 3263         ** Try to create it.  It's OK if creation fails because
 3264         ** the directory already exists, perhaps because some
 3265         ** other process just created it.  For simplicity do
 3266         ** not check first whether it already exists, as that
 3267         ** is checked anyway if the mkdir fails.
 3268         */
 3269         if (mkdir(name, MKDIR_UMASK) != 0) {
 3270             /* For speed, skip itsdir if errno == EEXIST.  Since
 3271                mkdirs is called only after open fails with ENOENT
 3272                on a subfile, EEXIST implies itsdir here.  */
 3273             int err = errno;
 3274             if (err != EEXIST && !itsdir(name)) {
 3275                 error(_("%s: Can't create directory %s: %s"),
 3276                       progname, name, strerror(err));
 3277                 exit(EXIT_FAILURE);
 3278             }
 3279         }
 3280         if (cp)
 3281           *cp++ = '/';
 3282     }
 3283     free(name);
 3284 }