"Fossies" - the Fresh Open Source Software Archive

Member "zic.c" (21 Nov 2022, 102129 Bytes) of package /linux/misc/tzcode2022g.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. See also the latest Fossies "Diffs" side-by-side code changes report for "zic.c": 2022f_vs_2022g.

    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 /* Use the system 'time' function, instead of any private replacement.
    9    This avoids creating an unnecessary dependency on localtime.c.  */
   10 #undef EPOCH_LOCAL
   11 #undef EPOCH_OFFSET
   12 #undef RESERVE_STD_EXT_IDS
   13 #undef time_tz
   14 
   15 #include "version.h"
   16 #include "private.h"
   17 #include "tzfile.h"
   18 
   19 #include <fcntl.h>
   20 #include <locale.h>
   21 #include <signal.h>
   22 #include <stdarg.h>
   23 #include <stdio.h>
   24 
   25 typedef int_fast64_t    zic_t;
   26 static zic_t const
   27   ZIC_MIN = INT_FAST64_MIN,
   28   ZIC_MAX = INT_FAST64_MAX,
   29   ZIC32_MIN = -1 - (zic_t) 0x7fffffff,
   30   ZIC32_MAX = 0x7fffffff;
   31 #define SCNdZIC SCNdFAST64
   32 
   33 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
   34 # define ZIC_MAX_ABBR_LEN_WO_WARN 6
   35 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
   36 
   37 /* An upper bound on how much a format might grow due to concatenation.  */
   38 enum { FORMAT_LEN_GROWTH_BOUND = 5 };
   39 
   40 #ifdef HAVE_DIRECT_H
   41 # include <direct.h>
   42 # include <io.h>
   43 # undef mkdir
   44 # define mkdir(name, mode) _mkdir(name)
   45 #endif
   46 
   47 #ifndef HAVE_GETRANDOM
   48 # ifdef __has_include
   49 #  if __has_include(<sys/random.h>)
   50 #   include <sys/random.h>
   51 #  endif
   52 # elif 2 < __GLIBC__ + (25 <= __GLIBC_MINOR__)
   53 #  include <sys/random.h>
   54 # endif
   55 # define HAVE_GETRANDOM GRND_RANDOM
   56 #elif HAVE_GETRANDOM
   57 # include <sys/random.h>
   58 #endif
   59 
   60 #if HAVE_SYS_STAT_H
   61 # include <sys/stat.h>
   62 #endif
   63 #ifdef S_IRUSR
   64 # define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
   65 #else
   66 # define MKDIR_UMASK 0755
   67 #endif
   68 
   69 /* The minimum alignment of a type, for pre-C23 platforms.  */
   70 #if __STDC_VERSION__ < 201112
   71 # define alignof(type) offsetof(struct { char a; type b; }, b)
   72 #elif __STDC_VERSION__ < 202311
   73 # include <stdalign.h>
   74 #endif
   75 
   76 /* The maximum length of a text line, including the trailing newline.  */
   77 #ifndef _POSIX2_LINE_MAX
   78 # define _POSIX2_LINE_MAX 2048
   79 #endif
   80 
   81 /* The type for line numbers.  Use PRIdMAX to format them; formerly
   82    there was also "#define PRIdLINENO PRIdMAX" and formats used
   83    PRIdLINENO, but xgettext cannot grok that.  */
   84 typedef intmax_t lineno;
   85 
   86 struct rule {
   87     int     r_filenum;
   88     lineno      r_linenum;
   89     const char *    r_name;
   90 
   91     zic_t       r_loyear;   /* for example, 1986 */
   92     zic_t       r_hiyear;   /* for example, 1986 */
   93     bool        r_lowasnum;
   94     bool        r_hiwasnum;
   95 
   96     int     r_month;    /* 0..11 */
   97 
   98     int     r_dycode;   /* see below */
   99     int     r_dayofmonth;
  100     int     r_wday;
  101 
  102     zic_t       r_tod;      /* time from midnight */
  103     bool        r_todisstd; /* is r_tod standard time? */
  104     bool        r_todisut;  /* is r_tod UT? */
  105     bool        r_isdst;    /* is this daylight saving time? */
  106     zic_t       r_save;     /* offset from standard time */
  107     const char *    r_abbrvar;  /* variable part of abbreviation */
  108 
  109     bool        r_todo;     /* a rule to do (used in outzone) */
  110     zic_t       r_temp;     /* used in outzone */
  111 };
  112 
  113 /*
  114 ** r_dycode r_dayofmonth    r_wday
  115 */
  116 enum {
  117   DC_DOM,   /* 1..31 */ /* unused */
  118   DC_DOWGEQ,    /* 1..31 */ /* 0..6 (Sun..Sat) */
  119   DC_DOWLEQ /* 1..31 */ /* 0..6 (Sun..Sat) */
  120 };
  121 
  122 struct zone {
  123     int     z_filenum;
  124     lineno      z_linenum;
  125 
  126     const char *    z_name;
  127     zic_t       z_stdoff;
  128     char *      z_rule;
  129     const char *    z_format;
  130     char        z_format_specifier;
  131 
  132     bool        z_isdst;
  133     zic_t       z_save;
  134 
  135     struct rule *   z_rules;
  136     ptrdiff_t   z_nrules;
  137 
  138     struct rule z_untilrule;
  139     zic_t       z_untiltime;
  140 };
  141 
  142 #if !HAVE_POSIX_DECLS
  143 extern int  getopt(int argc, char * const argv[],
  144             const char * options);
  145 extern int  link(const char * target, const char * linkname);
  146 extern char *   optarg;
  147 extern int  optind;
  148 #endif
  149 
  150 #if ! HAVE_SYMLINK
  151 static ssize_t
  152 readlink(char const *restrict file, char *restrict buf, size_t size)
  153 {
  154   errno = ENOTSUP;
  155   return -1;
  156 }
  157 static int
  158 symlink(char const *target, char const *linkname)
  159 {
  160   errno = ENOTSUP;
  161   return -1;
  162 }
  163 #endif
  164 #ifndef AT_SYMLINK_FOLLOW
  165 # if HAVE_LINK
  166 #  define linkat(targetdir, target, linknamedir, linkname, flag) \
  167      (itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
  168 # else
  169 #  define linkat(targetdir, target, linknamedir, linkname, flag) \
  170      (errno = ENOTSUP, -1)
  171 # endif
  172 #endif
  173 
  174 static void addtt(zic_t starttime, int type);
  175 static int  addtype(zic_t, char const *, bool, bool, bool);
  176 static void leapadd(zic_t, int, int);
  177 static void adjleap(void);
  178 static void associate(void);
  179 static void dolink(const char *, const char *, bool);
  180 static int  getfields(char *, char **, int);
  181 static zic_t    gethms(const char * string, const char * errstring);
  182 static zic_t    getsave(char *, bool *);
  183 static void inexpires(char **, int);
  184 static void infile(int, char const *);
  185 static void inleap(char ** fields, int nfields);
  186 static void inlink(char ** fields, int nfields);
  187 static void inrule(char ** fields, int nfields);
  188 static bool inzcont(char ** fields, int nfields);
  189 static bool inzone(char ** fields, int nfields);
  190 static bool inzsub(char **, int, bool);
  191 static bool itssymlink(char const *);
  192 static bool is_alpha(char a);
  193 static char lowerit(char);
  194 static void mkdirs(char const *, bool);
  195 static void newabbr(const char * abbr);
  196 static zic_t    oadd(zic_t t1, zic_t t2);
  197 static void outzone(const struct zone * zp, ptrdiff_t ntzones);
  198 static zic_t    rpytime(const struct rule * rp, zic_t wantedy);
  199 static bool rulesub(struct rule * rp,
  200             const char * loyearp, const char * hiyearp,
  201             const char * typep, const char * monthp,
  202             const char * dayp, const char * timep);
  203 static zic_t    tadd(zic_t t1, zic_t t2);
  204 
  205 /* Bound on length of what %z can expand to.  */
  206 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
  207 
  208 static int      charcnt;
  209 static bool     errors;
  210 static bool     warnings;
  211 static int      filenum;
  212 static int      leapcnt;
  213 static bool     leapseen;
  214 static zic_t        leapminyear;
  215 static zic_t        leapmaxyear;
  216 static lineno       linenum;
  217 static int      max_abbrvar_len = PERCENT_Z_LEN_BOUND;
  218 static int      max_format_len;
  219 static zic_t        max_year;
  220 static zic_t        min_year;
  221 static bool     noise;
  222 static int      rfilenum;
  223 static lineno       rlinenum;
  224 static const char * progname;
  225 static char const * leapsec;
  226 static char *const *    main_argv;
  227 static ptrdiff_t    timecnt;
  228 static ptrdiff_t    timecnt_alloc;
  229 static int      typecnt;
  230 static int      unspecifiedtype;
  231 
  232 /*
  233 ** Line codes.
  234 */
  235 
  236 enum {
  237   LC_RULE,
  238   LC_ZONE,
  239   LC_LINK,
  240   LC_LEAP,
  241   LC_EXPIRES
  242 };
  243 
  244 /*
  245 ** Which fields are which on a Zone line.
  246 */
  247 
  248 enum {
  249   ZF_NAME = 1,
  250   ZF_STDOFF,
  251   ZF_RULE,
  252   ZF_FORMAT,
  253   ZF_TILYEAR,
  254   ZF_TILMONTH,
  255   ZF_TILDAY,
  256   ZF_TILTIME,
  257   ZONE_MAXFIELDS,
  258   ZONE_MINFIELDS = ZF_TILYEAR
  259 };
  260 
  261 /*
  262 ** Which fields are which on a Zone continuation line.
  263 */
  264 
  265 enum {
  266   ZFC_STDOFF,
  267   ZFC_RULE,
  268   ZFC_FORMAT,
  269   ZFC_TILYEAR,
  270   ZFC_TILMONTH,
  271   ZFC_TILDAY,
  272   ZFC_TILTIME,
  273   ZONEC_MAXFIELDS,
  274   ZONEC_MINFIELDS = ZFC_TILYEAR
  275 };
  276 
  277 /*
  278 ** Which files are which on a Rule line.
  279 */
  280 
  281 enum {
  282   RF_NAME = 1,
  283   RF_LOYEAR,
  284   RF_HIYEAR,
  285   RF_COMMAND,
  286   RF_MONTH,
  287   RF_DAY,
  288   RF_TOD,
  289   RF_SAVE,
  290   RF_ABBRVAR,
  291   RULE_FIELDS
  292 };
  293 
  294 /*
  295 ** Which fields are which on a Link line.
  296 */
  297 
  298 enum {
  299   LF_TARGET = 1,
  300   LF_LINKNAME,
  301   LINK_FIELDS
  302 };
  303 
  304 /*
  305 ** Which fields are which on a Leap line.
  306 */
  307 
  308 enum {
  309   LP_YEAR = 1,
  310   LP_MONTH,
  311   LP_DAY,
  312   LP_TIME,
  313   LP_CORR,
  314   LP_ROLL,
  315   LEAP_FIELDS,
  316 
  317   /* Expires lines are like Leap lines, except without CORR and ROLL fields.  */
  318   EXPIRES_FIELDS = LP_TIME + 1
  319 };
  320 
  321 /* The maximum number of fields on any of the above lines.
  322    (The "+"s pacify gcc -Wenum-compare.)  */
  323 enum {
  324   MAX_FIELDS = max(max(+RULE_FIELDS, +LINK_FIELDS),
  325            max(+LEAP_FIELDS, +EXPIRES_FIELDS))
  326 };
  327 
  328 /*
  329 ** Year synonyms.
  330 */
  331 
  332 enum {
  333   YR_MINIMUM,
  334   YR_MAXIMUM,
  335   YR_ONLY
  336 };
  337 
  338 static struct rule *    rules;
  339 static ptrdiff_t    nrules; /* number of rules */
  340 static ptrdiff_t    nrules_alloc;
  341 
  342 static struct zone *    zones;
  343 static ptrdiff_t    nzones; /* number of zones */
  344 static ptrdiff_t    nzones_alloc;
  345 
  346 struct link {
  347     int     l_filenum;
  348     lineno      l_linenum;
  349     const char *    l_target;
  350     const char *    l_linkname;
  351 };
  352 
  353 static struct link *    links;
  354 static ptrdiff_t    nlinks;
  355 static ptrdiff_t    nlinks_alloc;
  356 
  357 struct lookup {
  358     const char *    l_word;
  359     const int   l_value;
  360 };
  361 
  362 static struct lookup const *    byword(const char * string,
  363                     const struct lookup * lp);
  364 
  365 static struct lookup const zi_line_codes[] = {
  366     { "Rule",   LC_RULE },
  367     { "Zone",   LC_ZONE },
  368     { "Link",   LC_LINK },
  369     { NULL,     0 }
  370 };
  371 static struct lookup const leap_line_codes[] = {
  372     { "Leap",   LC_LEAP },
  373     { "Expires",    LC_EXPIRES },
  374     { NULL,     0}
  375 };
  376 
  377 static struct lookup const  mon_names[] = {
  378     { "January",    TM_JANUARY },
  379     { "February",   TM_FEBRUARY },
  380     { "March",  TM_MARCH },
  381     { "April",  TM_APRIL },
  382     { "May",    TM_MAY },
  383     { "June",   TM_JUNE },
  384     { "July",   TM_JULY },
  385     { "August", TM_AUGUST },
  386     { "September",  TM_SEPTEMBER },
  387     { "October",    TM_OCTOBER },
  388     { "November",   TM_NOVEMBER },
  389     { "December",   TM_DECEMBER },
  390     { NULL,     0 }
  391 };
  392 
  393 static struct lookup const  wday_names[] = {
  394     { "Sunday", TM_SUNDAY },
  395     { "Monday", TM_MONDAY },
  396     { "Tuesday",    TM_TUESDAY },
  397     { "Wednesday",  TM_WEDNESDAY },
  398     { "Thursday",   TM_THURSDAY },
  399     { "Friday", TM_FRIDAY },
  400     { "Saturday",   TM_SATURDAY },
  401     { NULL,     0 }
  402 };
  403 
  404 static struct lookup const  lasts[] = {
  405     { "last-Sunday",    TM_SUNDAY },
  406     { "last-Monday",    TM_MONDAY },
  407     { "last-Tuesday",   TM_TUESDAY },
  408     { "last-Wednesday", TM_WEDNESDAY },
  409     { "last-Thursday",  TM_THURSDAY },
  410     { "last-Friday",    TM_FRIDAY },
  411     { "last-Saturday",  TM_SATURDAY },
  412     { NULL,         0 }
  413 };
  414 
  415 static struct lookup const  begin_years[] = {
  416     { "minimum",    YR_MINIMUM },
  417     { "maximum",    YR_MAXIMUM },
  418     { NULL,     0 }
  419 };
  420 
  421 static struct lookup const  end_years[] = {
  422     { "minimum",    YR_MINIMUM },
  423     { "maximum",    YR_MAXIMUM },
  424     { "only",   YR_ONLY },
  425     { NULL,     0 }
  426 };
  427 
  428 static struct lookup const  leap_types[] = {
  429     { "Rolling",    true },
  430     { "Stationary", false },
  431     { NULL,     0 }
  432 };
  433 
  434 static const int    len_months[2][MONSPERYEAR] = {
  435     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  436     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  437 };
  438 
  439 static const int    len_years[2] = {
  440     DAYSPERNYEAR, DAYSPERLYEAR
  441 };
  442 
  443 static struct attype {
  444     zic_t       at;
  445     bool        dontmerge;
  446     unsigned char   type;
  447 } *         attypes;
  448 static zic_t        utoffs[TZ_MAX_TYPES];
  449 static char     isdsts[TZ_MAX_TYPES];
  450 static unsigned char    desigidx[TZ_MAX_TYPES];
  451 static bool     ttisstds[TZ_MAX_TYPES];
  452 static bool     ttisuts[TZ_MAX_TYPES];
  453 static char     chars[TZ_MAX_CHARS];
  454 static zic_t        trans[TZ_MAX_LEAPS];
  455 static zic_t        corr[TZ_MAX_LEAPS];
  456 static char     roll[TZ_MAX_LEAPS];
  457 
  458 /*
  459 ** Memory allocation.
  460 */
  461 
  462 static ATTRIBUTE_NORETURN void
  463 memory_exhausted(const char *msg)
  464 {
  465     fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
  466     exit(EXIT_FAILURE);
  467 }
  468 
  469 static ATTRIBUTE_NORETURN void
  470 size_overflow(void)
  471 {
  472   memory_exhausted(_("size overflow"));
  473 }
  474 
  475 static ATTRIBUTE_REPRODUCIBLE ptrdiff_t
  476 size_sum(size_t a, size_t b)
  477 {
  478 #ifdef ckd_add
  479   ptrdiff_t sum;
  480   if (!ckd_add(&sum, a, b) && sum <= SIZE_MAX)
  481     return sum;
  482 #else
  483   ptrdiff_t sum_max = min(PTRDIFF_MAX, SIZE_MAX);
  484   if (a <= sum_max && b <= sum_max - a)
  485     return a + b;
  486 #endif
  487   size_overflow();
  488 }
  489 
  490 static ATTRIBUTE_REPRODUCIBLE ptrdiff_t
  491 size_product(ptrdiff_t nitems, ptrdiff_t itemsize)
  492 {
  493 #ifdef ckd_mul
  494   ptrdiff_t product;
  495   if (!ckd_mul(&product, nitems, itemsize) && product <= SIZE_MAX)
  496     return product;
  497 #else
  498   ptrdiff_t nitems_max = min(PTRDIFF_MAX, SIZE_MAX) / itemsize;
  499   if (nitems <= nitems_max)
  500     return nitems * itemsize;
  501 #endif
  502   size_overflow();
  503 }
  504 
  505 static ATTRIBUTE_REPRODUCIBLE ptrdiff_t
  506 align_to(ptrdiff_t size, ptrdiff_t alignment)
  507 {
  508   ptrdiff_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits);
  509   return sum & ~lo_bits;
  510 }
  511 
  512 #if !HAVE_STRDUP
  513 static char *
  514 strdup(char const *str)
  515 {
  516   char *result = malloc(strlen(str) + 1);
  517   return result ? strcpy(result, str) : result;
  518 }
  519 #endif
  520 
  521 static void *
  522 memcheck(void *ptr)
  523 {
  524     if (ptr == NULL)
  525       memory_exhausted(strerror(HAVE_MALLOC_ERRNO ? errno : ENOMEM));
  526     return ptr;
  527 }
  528 
  529 static void * ATTRIBUTE_MALLOC
  530 emalloc(size_t size)
  531 {
  532   return memcheck(malloc(size));
  533 }
  534 
  535 static void *
  536 erealloc(void *ptr, size_t size)
  537 {
  538   return memcheck(realloc(ptr, size));
  539 }
  540 
  541 static char * ATTRIBUTE_MALLOC
  542 estrdup(char const *str)
  543 {
  544   return memcheck(strdup(str));
  545 }
  546 
  547 static ptrdiff_t
  548 grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize)
  549 {
  550   ptrdiff_t addend = (*nitems_alloc >> 1) + 1;
  551 #if defined ckd_add && defined ckd_mul
  552   ptrdiff_t product;
  553   if (!ckd_add(nitems_alloc, *nitems_alloc, addend)
  554       && !ckd_mul(&product, *nitems_alloc, itemsize) && product <= SIZE_MAX)
  555     return product;
  556 #else
  557   ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX);
  558   if (*nitems_alloc <= ((amax - 1) / 3 * 2) / itemsize) {
  559     *nitems_alloc += addend;
  560     return *nitems_alloc * itemsize;
  561   }
  562 #endif
  563   memory_exhausted(_("integer overflow"));
  564 }
  565 
  566 static void *
  567 growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems,
  568       ptrdiff_t *nitems_alloc)
  569 {
  570   return (nitems < *nitems_alloc
  571       ? ptr
  572       : erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize)));
  573 }
  574 
  575 /*
  576 ** Error handling.
  577 */
  578 
  579 /* In most of the code, an input file name is represented by its index
  580    into the main argument vector, except that LEAPSEC_FILENUM stands
  581    for leapsec and COMMAND_LINE_FILENUM stands for the command line.  */
  582 enum { LEAPSEC_FILENUM = -2, COMMAND_LINE_FILENUM = -1 };
  583 
  584 /* Return the name of the Ith input file, for diagnostics.  */
  585 static char const *
  586 filename(int i)
  587 {
  588   if (i == COMMAND_LINE_FILENUM)
  589     return _("command line");
  590   else {
  591     char const *fname = i == LEAPSEC_FILENUM ? leapsec : main_argv[i];
  592     return strcmp(fname, "-") == 0 ? _("standard input") : fname;
  593   }
  594 }
  595 
  596 static void
  597 eats(int fnum, lineno num, int rfnum, lineno rnum)
  598 {
  599     filenum = fnum;
  600     linenum = num;
  601     rfilenum = rfnum;
  602     rlinenum = rnum;
  603 }
  604 
  605 static void
  606 eat(int fnum, lineno num)
  607 {
  608     eats(fnum, num, 0, -1);
  609 }
  610 
  611 static void ATTRIBUTE_FORMAT((printf, 1, 0))
  612 verror(const char *const string, va_list args)
  613 {
  614     /*
  615     ** Match the format of "cc" to allow sh users to
  616     **  zic ... 2>&1 | error -t "*" -v
  617     ** on BSD systems.
  618     */
  619     if (filenum)
  620       fprintf(stderr, _("\"%s\", line %"PRIdMAX": "),
  621           filename(filenum), linenum);
  622     vfprintf(stderr, string, args);
  623     if (rfilenum)
  624         fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"),
  625             filename(rfilenum), rlinenum);
  626     fprintf(stderr, "\n");
  627 }
  628 
  629 static void ATTRIBUTE_FORMAT((printf, 1, 2))
  630 error(const char *const string, ...)
  631 {
  632     va_list args;
  633     va_start(args, string);
  634     verror(string, args);
  635     va_end(args);
  636     errors = true;
  637 }
  638 
  639 static void ATTRIBUTE_FORMAT((printf, 1, 2))
  640 warning(const char *const string, ...)
  641 {
  642     va_list args;
  643     fprintf(stderr, _("warning: "));
  644     va_start(args, string);
  645     verror(string, args);
  646     va_end(args);
  647     warnings = true;
  648 }
  649 
  650 /* Close STREAM.  If it had an I/O error, report it against DIR/NAME,
  651    remove TEMPNAME if nonnull, and then exit.  */
  652 static void
  653 close_file(FILE *stream, char const *dir, char const *name,
  654        char const *tempname)
  655 {
  656   char const *e = (ferror(stream) ? _("I/O error")
  657            : fclose(stream) != 0 ? strerror(errno) : NULL);
  658   if (e) {
  659     fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
  660         dir ? dir : "", dir ? "/" : "",
  661         name ? name : "", name ? ": " : "",
  662         e);
  663     if (tempname)
  664       remove(tempname);
  665     exit(EXIT_FAILURE);
  666   }
  667 }
  668 
  669 static ATTRIBUTE_NORETURN void
  670 usage(FILE *stream, int status)
  671 {
  672   fprintf(stream,
  673       _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
  674         "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]"
  675         " [ -L leapseconds ] \\\n"
  676         "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R '@hi' ] \\\n"
  677         "\t[ -t localtime-link ] \\\n"
  678         "\t[ filename ... ]\n\n"
  679         "Report bugs to %s.\n"),
  680       progname, progname, REPORT_BUGS_TO);
  681   if (status == EXIT_SUCCESS)
  682     close_file(stream, NULL, NULL, NULL);
  683   exit(status);
  684 }
  685 
  686 /* Change the working directory to DIR, possibly creating DIR and its
  687    ancestors.  After this is done, all files are accessed with names
  688    relative to DIR.  */
  689 static void
  690 change_directory(char const *dir)
  691 {
  692   if (chdir(dir) != 0) {
  693     int chdir_errno = errno;
  694     if (chdir_errno == ENOENT) {
  695       mkdirs(dir, false);
  696       chdir_errno = chdir(dir) == 0 ? 0 : errno;
  697     }
  698     if (chdir_errno != 0) {
  699       fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
  700           progname, dir, strerror(chdir_errno));
  701       exit(EXIT_FAILURE);
  702     }
  703   }
  704 }
  705 
  706 /* Compare the two links A and B, for a stable sort by link name.  */
  707 static int
  708 qsort_linkcmp(void const *a, void const *b)
  709 {
  710   struct link const *l = a;
  711   struct link const *m = b;
  712   int cmp = strcmp(l->l_linkname, m->l_linkname);
  713   if (cmp)
  714     return cmp;
  715 
  716   /* The link names are the same.  Make the sort stable by comparing
  717      file numbers (where subtraction cannot overflow) and possibly
  718      line numbers (where it can).  */
  719   cmp = l->l_filenum - m->l_filenum;
  720   if (cmp)
  721     return cmp;
  722   return (l->l_linenum > m->l_linenum) - (l->l_linenum < m->l_linenum);
  723 }
  724 
  725 /* Compare the string KEY to the link B, for bsearch.  */
  726 static int
  727 bsearch_linkcmp(void const *key, void const *b)
  728 {
  729   struct link const *m = b;
  730   return strcmp(key, m->l_linkname);
  731 }
  732 
  733 /* Make the links specified by the Link lines.  */
  734 static void
  735 make_links(void)
  736 {
  737   ptrdiff_t i, j, nalinks, pass_size;
  738   if (1 < nlinks)
  739     qsort(links, nlinks, sizeof *links, qsort_linkcmp);
  740 
  741   /* Ignore each link superseded by a later link with the same name.  */
  742   j = 0;
  743   for (i = 0; i < nlinks; i++) {
  744     while (i + 1 < nlinks
  745        && strcmp(links[i].l_linkname, links[i + 1].l_linkname) == 0)
  746       i++;
  747     links[j++] = links[i];
  748   }
  749   nlinks = pass_size = j;
  750 
  751   /* Walk through the link array making links.  However,
  752      if a link's target has not been made yet, append a copy to the
  753      end of the array.  The end of the array will gradually fill
  754      up with a small sorted subsequence of not-yet-made links.
  755      nalinks counts all the links in the array, including copies.
  756      When we reach the copied subsequence, it may still contain
  757      a link to a not-yet-made link, so the process repeats.
  758      At any given point in time, the link array consists of the
  759      following subregions, where 0 <= i <= j <= nalinks and
  760      0 <= nlinks <= nalinks:
  761 
  762        0 .. (i - 1):
  763      links that either have been made, or have been copied to a
  764      later point point in the array (this later point can be in
  765      any of the three subregions)
  766        i .. (j - 1):
  767      not-yet-made links for this pass
  768        j .. (nalinks - 1):
  769      not-yet-made links that this pass has skipped because
  770      they were links to not-yet-made links
  771 
  772      The first subregion might not be sorted if nlinks < i;
  773      the other two subregions are sorted.  This algorithm does
  774      not alter entries 0 .. (nlinks - 1), which remain sorted.
  775 
  776      If there are L links, this algorithm is O(C*L*log(L)) where
  777      C is the length of the longest link chain.  Usually C is
  778      short (e.g., 3) though its worst-case value is L.  */
  779 
  780   j = nalinks = nlinks;
  781 
  782   for (i = 0; i < nalinks; i++) {
  783     struct link *l;
  784 
  785     eat(links[i].l_filenum, links[i].l_linenum);
  786 
  787     /* If this pass examined all its links, start the next pass.  */
  788     if (i == j) {
  789       if (nalinks - i == pass_size) {
  790     error(_("\"Link %s %s\" is part of a link cycle"),
  791           links[i].l_target, links[i].l_linkname);
  792     break;
  793       }
  794       j = nalinks;
  795       pass_size = nalinks - i;
  796     }
  797 
  798     /* Diagnose self links, which the cycle detection algorithm would not
  799        otherwise catch.  */
  800     if (strcmp(links[i].l_target, links[i].l_linkname) == 0) {
  801       error(_("link %s targets itself"), links[i].l_target);
  802       continue;
  803     }
  804 
  805     /* Make this link unless its target has not been made yet.  */
  806     l = bsearch(links[i].l_target, &links[i + 1], j - (i + 1),
  807         sizeof *links, bsearch_linkcmp);
  808     if (!l)
  809       l = bsearch(links[i].l_target, &links[j], nalinks - j,
  810           sizeof *links, bsearch_linkcmp);
  811     if (!l)
  812       dolink(links[i].l_target, links[i].l_linkname, false);
  813     else {
  814       /* The link target has not been made yet; copy the link to the end.  */
  815       links = growalloc(links, sizeof *links, nalinks, &nlinks_alloc);
  816       links[nalinks++] = links[i];
  817     }
  818 
  819     if (noise && i < nlinks) {
  820       if (l)
  821     warning(_("link %s targeting link %s mishandled by pre-2023 zic"),
  822         links[i].l_linkname, links[i].l_target);
  823       else if (bsearch(links[i].l_target, links, nlinks, sizeof *links,
  824                bsearch_linkcmp))
  825     warning(_("link %s targeting link %s"),
  826         links[i].l_linkname, links[i].l_target);
  827     }
  828   }
  829 }
  830 
  831 /* Simple signal handling: just set a flag that is checked
  832    periodically outside critical sections.  To set up the handler,
  833    prefer sigaction if available to close a signal race.  */
  834 
  835 static sig_atomic_t got_signal;
  836 
  837 static void
  838 signal_handler(int sig)
  839 {
  840 #ifndef SA_SIGINFO
  841   signal(sig, signal_handler);
  842 #endif
  843   got_signal = sig;
  844 }
  845 
  846 /* Arrange for SIGINT etc. to be caught by the handler.  */
  847 static void
  848 catch_signals(void)
  849 {
  850   static int const signals[] = {
  851 #ifdef SIGHUP
  852     SIGHUP,
  853 #endif
  854     SIGINT,
  855 #ifdef SIGPIPE
  856     SIGPIPE,
  857 #endif
  858     SIGTERM
  859   };
  860   int i;
  861   for (i = 0; i < sizeof signals / sizeof signals[0]; i++) {
  862 #ifdef SA_SIGINFO
  863     struct sigaction act0, act;
  864     act.sa_handler = signal_handler;
  865     sigemptyset(&act.sa_mask);
  866     act.sa_flags = 0;
  867     if (sigaction(signals[i], &act, &act0) == 0
  868     && ! (act0.sa_flags & SA_SIGINFO) && act0.sa_handler == SIG_IGN) {
  869       sigaction(signals[i], &act0, NULL);
  870       got_signal = 0;
  871     }
  872 #else
  873     if (signal(signals[i], signal_handler) == SIG_IGN) {
  874       signal(signals[i], SIG_IGN);
  875       got_signal = 0;
  876     }
  877 #endif
  878   }
  879 }
  880 
  881 /* If a signal has arrived, terminate zic with appropriate status.  */
  882 static void
  883 check_for_signal(void)
  884 {
  885   int sig = got_signal;
  886   if (sig) {
  887     signal(sig, SIG_DFL);
  888     raise(sig);
  889     abort(); /* A bug in 'raise'.  */
  890   }
  891 }
  892 
  893 enum { TIME_T_BITS_IN_FILE = 64 };
  894 
  895 /* The minimum and maximum values representable in a TZif file.  */
  896 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
  897 static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
  898 
  899 /* The minimum, and one less than the maximum, values specified by
  900    the -r option.  These default to MIN_TIME and MAX_TIME.  */
  901 static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
  902 static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
  903 
  904 /* The time specified by the -R option, defaulting to MIN_TIME.  */
  905 static zic_t redundant_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
  906 
  907 /* The time specified by an Expires line, or negative if no such line.  */
  908 static zic_t leapexpires = -1;
  909 
  910 /* Set the time range of the output to TIMERANGE.
  911    Return true if successful.  */
  912 static bool
  913 timerange_option(char *timerange)
  914 {
  915   intmax_t lo = min_time, hi = max_time;
  916   char *lo_end = timerange, *hi_end;
  917   if (*timerange == '@') {
  918     errno = 0;
  919     lo = strtoimax(timerange + 1, &lo_end, 10);
  920     if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE))
  921       return false;
  922   }
  923   hi_end = lo_end;
  924   if (lo_end[0] == '/' && lo_end[1] == '@') {
  925     errno = 0;
  926     hi = strtoimax(lo_end + 2, &hi_end, 10);
  927     if (hi_end == lo_end + 2 || hi == INTMAX_MIN)
  928       return false;
  929     hi -= ! (hi == INTMAX_MAX && errno == ERANGE);
  930   }
  931   if (*hi_end || hi < lo || max_time < lo || hi < min_time)
  932     return false;
  933   lo_time = max(lo, min_time);
  934   hi_time = min(hi, max_time);
  935   return true;
  936 }
  937 
  938 /* Generate redundant time stamps up to OPT.  Return true if successful.  */
  939 static bool
  940 redundant_time_option(char *opt)
  941 {
  942   if (*opt == '@') {
  943     intmax_t redundant;
  944     char *opt_end;
  945     redundant = strtoimax(opt + 1, &opt_end, 10);
  946     if (opt_end != opt + 1 && !*opt_end) {
  947       redundant_time = max(redundant_time, redundant);
  948       return true;
  949     }
  950   }
  951   return false;
  952 }
  953 
  954 static const char * psxrules;
  955 static const char * lcltime;
  956 static const char * directory;
  957 static const char * tzdefault;
  958 
  959 /* -1 if the TZif output file should be slim, 0 if default, 1 if the
  960    output should be fat for backward compatibility.  ZIC_BLOAT_DEFAULT
  961    determines the default.  */
  962 static int bloat;
  963 
  964 static bool
  965 want_bloat(void)
  966 {
  967   return 0 <= bloat;
  968 }
  969 
  970 #ifndef ZIC_BLOAT_DEFAULT
  971 # define ZIC_BLOAT_DEFAULT "slim"
  972 #endif
  973 
  974 int
  975 main(int argc, char **argv)
  976 {
  977     register int c, k;
  978     register ptrdiff_t i, j;
  979     bool timerange_given = false;
  980 
  981 #ifdef S_IWGRP
  982     umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
  983 #endif
  984 #if HAVE_GETTEXT
  985     setlocale(LC_ALL, "");
  986 # ifdef TZ_DOMAINDIR
  987     bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
  988 # endif /* defined TEXTDOMAINDIR */
  989     textdomain(TZ_DOMAIN);
  990 #endif /* HAVE_GETTEXT */
  991     main_argv = argv;
  992     progname = argv[0] ? argv[0] : "zic";
  993     if (TYPE_BIT(zic_t) < 64) {
  994         fprintf(stderr, "%s: %s\n", progname,
  995             _("wild compilation-time specification of zic_t"));
  996         return EXIT_FAILURE;
  997     }
  998     for (k = 1; k < argc; k++)
  999         if (strcmp(argv[k], "--version") == 0) {
 1000             printf("zic %s%s\n", PKGVERSION, TZVERSION);
 1001             close_file(stdout, NULL, NULL, NULL);
 1002             return EXIT_SUCCESS;
 1003         } else if (strcmp(argv[k], "--help") == 0) {
 1004             usage(stdout, EXIT_SUCCESS);
 1005         }
 1006     while ((c = getopt(argc, argv, "b:d:l:L:p:r:R:st:vy:")) != EOF
 1007            && c != -1)
 1008         switch (c) {
 1009             default:
 1010                 usage(stderr, EXIT_FAILURE);
 1011             case 'b':
 1012                 if (strcmp(optarg, "slim") == 0) {
 1013                   if (0 < bloat)
 1014                     error(_("incompatible -b options"));
 1015                   bloat = -1;
 1016                 } else if (strcmp(optarg, "fat") == 0) {
 1017                   if (bloat < 0)
 1018                     error(_("incompatible -b options"));
 1019                   bloat = 1;
 1020                 } else
 1021                   error(_("invalid option: -b '%s'"), optarg);
 1022                 break;
 1023             case 'd':
 1024                 if (directory == NULL)
 1025                     directory = optarg;
 1026                 else {
 1027                     fprintf(stderr,
 1028 _("%s: More than one -d option specified\n"),
 1029                         progname);
 1030                     return EXIT_FAILURE;
 1031                 }
 1032                 break;
 1033             case 'l':
 1034                 if (lcltime == NULL)
 1035                     lcltime = optarg;
 1036                 else {
 1037                     fprintf(stderr,
 1038 _("%s: More than one -l option specified\n"),
 1039                         progname);
 1040                     return EXIT_FAILURE;
 1041                 }
 1042                 break;
 1043             case 'p':
 1044                 if (psxrules == NULL)
 1045                     psxrules = optarg;
 1046                 else {
 1047                     fprintf(stderr,
 1048 _("%s: More than one -p option specified\n"),
 1049                         progname);
 1050                     return EXIT_FAILURE;
 1051                 }
 1052                 break;
 1053             case 't':
 1054                 if (tzdefault != NULL) {
 1055                   fprintf(stderr,
 1056                       _("%s: More than one -t option"
 1057                         " specified\n"),
 1058                       progname);
 1059                   return EXIT_FAILURE;
 1060                 }
 1061                 tzdefault = optarg;
 1062                 break;
 1063             case 'y':
 1064                 warning(_("-y ignored"));
 1065                 break;
 1066             case 'L':
 1067                 if (leapsec == NULL)
 1068                     leapsec = optarg;
 1069                 else {
 1070                     fprintf(stderr,
 1071 _("%s: More than one -L option specified\n"),
 1072                         progname);
 1073                     return EXIT_FAILURE;
 1074                 }
 1075                 break;
 1076             case 'v':
 1077                 noise = true;
 1078                 break;
 1079             case 'r':
 1080                 if (timerange_given) {
 1081                   fprintf(stderr,
 1082 _("%s: More than one -r option specified\n"),
 1083                       progname);
 1084                   return EXIT_FAILURE;
 1085                 }
 1086                 if (! timerange_option(optarg)) {
 1087                   fprintf(stderr,
 1088 _("%s: invalid time range: %s\n"),
 1089                       progname, optarg);
 1090                   return EXIT_FAILURE;
 1091                 }
 1092                 timerange_given = true;
 1093                 break;
 1094             case 'R':
 1095                 if (! redundant_time_option(optarg)) {
 1096                   fprintf(stderr, _("%s: invalid time: %s\n"),
 1097                       progname, optarg);
 1098                   return EXIT_FAILURE;
 1099                 }
 1100                 break;
 1101             case 's':
 1102                 warning(_("-s ignored"));
 1103                 break;
 1104         }
 1105     if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
 1106         usage(stderr, EXIT_FAILURE);    /* usage message by request */
 1107     if (hi_time + (hi_time < ZIC_MAX) < redundant_time) {
 1108       fprintf(stderr, _("%s: -R time exceeds -r cutoff\n"), progname);
 1109       return EXIT_FAILURE;
 1110     }
 1111     if (bloat == 0) {
 1112       static char const bloat_default[] = ZIC_BLOAT_DEFAULT;
 1113       if (strcmp(bloat_default, "slim") == 0)
 1114         bloat = -1;
 1115       else if (strcmp(bloat_default, "fat") == 0)
 1116         bloat = 1;
 1117       else
 1118         abort(); /* Configuration error.  */
 1119     }
 1120     if (directory == NULL)
 1121         directory = TZDIR;
 1122     if (tzdefault == NULL)
 1123         tzdefault = TZDEFAULT;
 1124 
 1125     if (optind < argc && leapsec != NULL) {
 1126         infile(LEAPSEC_FILENUM, leapsec);
 1127         adjleap();
 1128     }
 1129 
 1130     for (k = optind; k < argc; k++)
 1131       infile(k, argv[k]);
 1132     if (errors)
 1133         return EXIT_FAILURE;
 1134     associate();
 1135     change_directory(directory);
 1136     catch_signals();
 1137     for (i = 0; i < nzones; i = j) {
 1138         /*
 1139         ** Find the next non-continuation zone entry.
 1140         */
 1141         for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
 1142             continue;
 1143         outzone(&zones[i], j - i);
 1144     }
 1145     make_links();
 1146     if (lcltime != NULL) {
 1147         eat(COMMAND_LINE_FILENUM, 1);
 1148         dolink(lcltime, tzdefault, true);
 1149     }
 1150     if (psxrules != NULL) {
 1151         eat(COMMAND_LINE_FILENUM, 1);
 1152         dolink(psxrules, TZDEFRULES, true);
 1153     }
 1154     if (warnings && (ferror(stderr) || fclose(stderr) != 0))
 1155       return EXIT_FAILURE;
 1156     return errors ? EXIT_FAILURE : EXIT_SUCCESS;
 1157 }
 1158 
 1159 static bool
 1160 componentcheck(char const *name, char const *component,
 1161            char const *component_end)
 1162 {
 1163     enum { component_len_max = 14 };
 1164     ptrdiff_t component_len = component_end - component;
 1165     if (component_len == 0) {
 1166       if (!*name)
 1167         error(_("empty file name"));
 1168       else
 1169         error(_(component == name
 1170              ? "file name '%s' begins with '/'"
 1171              : *component_end
 1172              ? "file name '%s' contains '//'"
 1173              : "file name '%s' ends with '/'"),
 1174            name);
 1175       return false;
 1176     }
 1177     if (0 < component_len && component_len <= 2
 1178         && component[0] == '.' && component_end[-1] == '.') {
 1179       int len = component_len;
 1180       error(_("file name '%s' contains '%.*s' component"),
 1181         name, len, component);
 1182       return false;
 1183     }
 1184     if (noise) {
 1185       if (0 < component_len && component[0] == '-')
 1186         warning(_("file name '%s' component contains leading '-'"),
 1187             name);
 1188       if (component_len_max < component_len)
 1189         warning(_("file name '%s' contains overlength component"
 1190               " '%.*s...'"),
 1191             name, component_len_max, component);
 1192     }
 1193     return true;
 1194 }
 1195 
 1196 static bool
 1197 namecheck(const char *name)
 1198 {
 1199     register char const *cp;
 1200 
 1201     /* Benign characters in a portable file name.  */
 1202     static char const benign[] =
 1203       "-/_"
 1204       "abcdefghijklmnopqrstuvwxyz"
 1205       "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 1206 
 1207     /* Non-control chars in the POSIX portable character set,
 1208        excluding the benign characters.  */
 1209     static char const printable_and_not_benign[] =
 1210       " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
 1211 
 1212     register char const *component = name;
 1213     for (cp = name; *cp; cp++) {
 1214         unsigned char c = *cp;
 1215         if (noise && !strchr(benign, c)) {
 1216             warning((strchr(printable_and_not_benign, c)
 1217                  ? _("file name '%s' contains byte '%c'")
 1218                  : _("file name '%s' contains byte '\\%o'")),
 1219                 name, c);
 1220         }
 1221         if (c == '/') {
 1222             if (!componentcheck(name, component, cp))
 1223               return false;
 1224             component = cp + 1;
 1225         }
 1226     }
 1227     return componentcheck(name, component, cp);
 1228 }
 1229 
 1230 /* Return a random uint_fast64_t.  */
 1231 static uint_fast64_t
 1232 get_rand_u64(void)
 1233 {
 1234 #if HAVE_GETRANDOM
 1235   static uint_fast64_t entropy_buffer[max(1, 256 / sizeof(uint_fast64_t))];
 1236   static int nwords;
 1237   if (!nwords) {
 1238     ssize_t s;
 1239     do
 1240       s = getrandom(entropy_buffer, sizeof entropy_buffer, 0);
 1241     while (s < 0 && errno == EINTR);
 1242 
 1243     nwords = s < 0 ? -1 : s / sizeof *entropy_buffer;
 1244   }
 1245   if (0 < nwords)
 1246     return entropy_buffer[--nwords];
 1247 #endif
 1248 
 1249   /* getrandom didn't work, so fall back on portable code that is
 1250      not the best because the seed isn't cryptographically random and
 1251      'rand' might not be cryptographically secure.  */
 1252   {
 1253     static bool initialized;
 1254     if (!initialized) {
 1255       srand(time(NULL));
 1256       initialized = true;
 1257     }
 1258   }
 1259 
 1260   /* Return a random number if rand() yields a random number and in
 1261      the typical case where RAND_MAX is one less than a power of two.
 1262      In other cases this code yields a sort-of-random number.  */
 1263   {
 1264     uint_fast64_t rand_max = RAND_MAX,
 1265       nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0,
 1266       rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1,
 1267       r = 0, rmax = 0;
 1268 
 1269     do {
 1270       uint_fast64_t rmax1 = rmax;
 1271       if (rmod) {
 1272     /* Avoid signed integer overflow on theoretical platforms
 1273        where uint_fast64_t promotes to int.  */
 1274     rmax1 %= rmod;
 1275     r %= rmod;
 1276       }
 1277       rmax1 = nrand * rmax1 + rand_max;
 1278       r = nrand * r + rand();
 1279       rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX;
 1280     } while (rmax < UINT_FAST64_MAX);
 1281 
 1282     return r;
 1283   }
 1284 }
 1285 
 1286 /* Generate a randomish name in the same directory as *NAME.  If
 1287    *NAMEALLOC, put the name into *NAMEALLOC which is assumed to be
 1288    that returned by a previous call and is thus already almost set up
 1289    and equal to *NAME; otherwise, allocate a new name and put its
 1290    address into both *NAMEALLOC and *NAME.  */
 1291 static void
 1292 random_dirent(char const **name, char **namealloc)
 1293 {
 1294   char const *src = *name;
 1295   char *dst = *namealloc;
 1296   static char const prefix[] = ".zic";
 1297   static char const alphabet[] =
 1298     "abcdefghijklmnopqrstuvwxyz"
 1299     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 1300     "0123456789";
 1301   enum { prefixlen = sizeof prefix - 1, alphabetlen = sizeof alphabet - 1 };
 1302   int suffixlen = 6;
 1303   char const *lastslash = strrchr(src, '/');
 1304   ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0;
 1305   int i;
 1306   uint_fast64_t r;
 1307   uint_fast64_t base = alphabetlen;
 1308 
 1309   /* BASE**6 */
 1310   uint_fast64_t base__6 = base * base * base * base * base * base;
 1311 
 1312   /* The largest uintmax_t that is a multiple of BASE**6.  Any random
 1313      uintmax_t value that is this value or greater, yields a biased
 1314      remainder when divided by BASE**6.  UNFAIR_MIN equals the
 1315      mathematical value of ((UINTMAX_MAX + 1) - (UINTMAX_MAX + 1) % BASE**6)
 1316      computed without overflow.  */
 1317   uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6);
 1318 
 1319   if (!dst) {
 1320     dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
 1321     memcpy(dst, src, dirlen);
 1322     memcpy(dst + dirlen, prefix, prefixlen);
 1323     dst[dirlen + prefixlen + suffixlen] = '\0';
 1324     *name = *namealloc = dst;
 1325   }
 1326 
 1327   do
 1328     r = get_rand_u64();
 1329   while (unfair_min <= r);
 1330 
 1331   for (i = 0; i < suffixlen; i++) {
 1332     dst[dirlen + prefixlen + i] = alphabet[r % alphabetlen];
 1333     r /= alphabetlen;
 1334   }
 1335 }
 1336 
 1337 /* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the
 1338    name of the temporary file that will eventually be renamed to
 1339    *OUTNAME.  Assign the temporary file's name to both *OUTNAME and
 1340    *TEMPNAME.  If *TEMPNAME is null, allocate the name of any such
 1341    temporary file; otherwise, reuse *TEMPNAME's storage, which is
 1342    already set up and only needs its trailing suffix updated.  */
 1343 static FILE *
 1344 open_outfile(char const **outname, char **tempname)
 1345 {
 1346 #if __STDC_VERSION__ < 201112
 1347   static char const fopen_mode[] = "wb";
 1348 #else
 1349   static char const fopen_mode[] = "wbx";
 1350 #endif
 1351 
 1352   FILE *fp;
 1353   bool dirs_made = false;
 1354   if (!*tempname)
 1355     random_dirent(outname, tempname);
 1356 
 1357   while (! (fp = fopen(*outname, fopen_mode))) {
 1358     int fopen_errno = errno;
 1359     if (fopen_errno == ENOENT && !dirs_made) {
 1360       mkdirs(*outname, true);
 1361       dirs_made = true;
 1362     } else if (fopen_errno == EEXIST)
 1363       random_dirent(outname, tempname);
 1364     else {
 1365       fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
 1366           progname, directory, *outname, strerror(fopen_errno));
 1367       exit(EXIT_FAILURE);
 1368     }
 1369   }
 1370 
 1371   return fp;
 1372 }
 1373 
 1374 /* If TEMPNAME, the result is in the temporary file TEMPNAME even
 1375    though the user wanted it in NAME, so rename TEMPNAME to NAME.
 1376    Report an error and exit if there is trouble.  Also, free TEMPNAME.  */
 1377 static void
 1378 rename_dest(char *tempname, char const *name)
 1379 {
 1380   if (tempname) {
 1381     if (rename(tempname, name) != 0) {
 1382       int rename_errno = errno;
 1383       remove(tempname);
 1384       fprintf(stderr, _("%s: rename to %s/%s: %s\n"),
 1385           progname, directory, name, strerror(rename_errno));
 1386       exit(EXIT_FAILURE);
 1387     }
 1388     free(tempname);
 1389   }
 1390 }
 1391 
 1392 /* Create symlink contents suitable for symlinking FROM to TO, as a
 1393    freshly allocated string.  FROM should be a relative file name, and
 1394    is relative to the global variable DIRECTORY.  TO can be either
 1395    relative or absolute.  */
 1396 static char *
 1397 relname(char const *target, char const *linkname)
 1398 {
 1399   size_t i, taillen, dir_len = 0, dotdots = 0;
 1400   ptrdiff_t dotdotetcsize, linksize = min(PTRDIFF_MAX, SIZE_MAX);
 1401   char const *f = target;
 1402   char *result = NULL;
 1403   if (*linkname == '/') {
 1404     /* Make F absolute too.  */
 1405     size_t len = strlen(directory);
 1406     size_t lenslash = len + (len && directory[len - 1] != '/');
 1407     size_t targetsize = strlen(target) + 1;
 1408     linksize = size_sum(lenslash, targetsize);
 1409     f = result = emalloc(linksize);
 1410     memcpy(result, directory, len);
 1411     result[len] = '/';
 1412     memcpy(result + lenslash, target, targetsize);
 1413   }
 1414   for (i = 0; f[i] && f[i] == linkname[i]; i++)
 1415     if (f[i] == '/')
 1416       dir_len = i + 1;
 1417   for (; linkname[i]; i++)
 1418     dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
 1419   taillen = strlen(f + dir_len);
 1420   dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1);
 1421   if (dotdotetcsize <= linksize) {
 1422     if (!result)
 1423       result = emalloc(dotdotetcsize);
 1424     for (i = 0; i < dotdots; i++)
 1425       memcpy(result + 3 * i, "../", 3);
 1426     memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
 1427   }
 1428   return result;
 1429 }
 1430 
 1431 static void
 1432 dolink(char const *target, char const *linkname, bool staysymlink)
 1433 {
 1434     bool linkdirs_made = false;
 1435     int link_errno;
 1436     char *tempname = NULL;
 1437     char const *outname = linkname;
 1438 
 1439     check_for_signal();
 1440 
 1441     if (strcmp(target, "-") == 0) {
 1442       if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR)
 1443         return;
 1444       else {
 1445         char const *e = strerror(errno);
 1446         fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
 1447             progname, directory, linkname, e);
 1448         exit(EXIT_FAILURE);
 1449       }
 1450     }
 1451 
 1452     while (true) {
 1453       if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW)
 1454           == 0) {
 1455         link_errno = 0;
 1456         break;
 1457       }
 1458       link_errno = errno;
 1459       if (link_errno == EXDEV || link_errno == ENOTSUP)
 1460         break;
 1461 
 1462       if (link_errno == EEXIST) {
 1463         staysymlink &= !tempname;
 1464         random_dirent(&outname, &tempname);
 1465         if (staysymlink && itssymlink(linkname))
 1466           break;
 1467       } else if (link_errno == ENOENT && !linkdirs_made) {
 1468         mkdirs(linkname, true);
 1469         linkdirs_made = true;
 1470       } else {
 1471         fprintf(stderr, _("%s: Can't link %s/%s to %s/%s: %s\n"),
 1472             progname, directory, target, directory, outname,
 1473             strerror(link_errno));
 1474         exit(EXIT_FAILURE);
 1475       }
 1476     }
 1477     if (link_errno != 0) {
 1478       bool absolute = *target == '/';
 1479       char *linkalloc = absolute ? NULL : relname(target, linkname);
 1480       char const *contents = absolute ? target : linkalloc;
 1481       int symlink_errno;
 1482 
 1483       while (true) {
 1484         if (symlink(contents, outname) == 0) {
 1485           symlink_errno = 0;
 1486           break;
 1487         }
 1488         symlink_errno = errno;
 1489         if (symlink_errno == EEXIST)
 1490           random_dirent(&outname, &tempname);
 1491         else if (symlink_errno == ENOENT && !linkdirs_made) {
 1492           mkdirs(linkname, true);
 1493           linkdirs_made = true;
 1494         } else
 1495           break;
 1496       }
 1497       free(linkalloc);
 1498       if (symlink_errno == 0) {
 1499         if (link_errno != ENOTSUP && link_errno != EEXIST)
 1500           warning(_("symbolic link used because hard link failed: %s"),
 1501               strerror(link_errno));
 1502       } else {
 1503         FILE *fp, *tp;
 1504         int c;
 1505         fp = fopen(target, "rb");
 1506         if (!fp) {
 1507           char const *e = strerror(errno);
 1508           fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
 1509               progname, directory, target, e);
 1510           exit(EXIT_FAILURE);
 1511         }
 1512         tp = open_outfile(&outname, &tempname);
 1513         while ((c = getc(fp)) != EOF)
 1514           putc(c, tp);
 1515         close_file(tp, directory, linkname, tempname);
 1516         close_file(fp, directory, target, NULL);
 1517         if (link_errno != ENOTSUP)
 1518           warning(_("copy used because hard link failed: %s"),
 1519               strerror(link_errno));
 1520         else if (symlink_errno != ENOTSUP)
 1521           warning(_("copy used because symbolic link failed: %s"),
 1522               strerror(symlink_errno));
 1523       }
 1524     }
 1525     rename_dest(tempname, linkname);
 1526 }
 1527 
 1528 /* Return true if NAME is a symbolic link.  */
 1529 static bool
 1530 itssymlink(char const *name)
 1531 {
 1532   char c;
 1533   return 0 <= readlink(name, &c, 1);
 1534 }
 1535 
 1536 /*
 1537 ** Associate sets of rules with zones.
 1538 */
 1539 
 1540 /*
 1541 ** Sort by rule name.
 1542 */
 1543 
 1544 static int
 1545 rcomp(const void *cp1, const void *cp2)
 1546 {
 1547   struct rule const *r1 = cp1, *r2 = cp2;
 1548   return strcmp(r1->r_name, r2->r_name);
 1549 }
 1550 
 1551 static void
 1552 associate(void)
 1553 {
 1554     register struct zone *  zp;
 1555     register struct rule *  rp;
 1556     register ptrdiff_t i, j, base, out;
 1557 
 1558     if (1 < nrules) {
 1559         qsort(rules, nrules, sizeof *rules, rcomp);
 1560         for (i = 0; i < nrules - 1; ++i) {
 1561             if (strcmp(rules[i].r_name,
 1562                 rules[i + 1].r_name) != 0)
 1563                     continue;
 1564             if (rules[i].r_filenum == rules[i + 1].r_filenum)
 1565                     continue;
 1566             eat(rules[i].r_filenum, rules[i].r_linenum);
 1567             warning(_("same rule name in multiple files"));
 1568             eat(rules[i + 1].r_filenum, rules[i + 1].r_linenum);
 1569             warning(_("same rule name in multiple files"));
 1570             for (j = i + 2; j < nrules; ++j) {
 1571                 if (strcmp(rules[i].r_name,
 1572                     rules[j].r_name) != 0)
 1573                         break;
 1574                 if (rules[i].r_filenum == rules[j].r_filenum)
 1575                         continue;
 1576                 if (rules[i + 1].r_filenum
 1577                     == rules[j].r_filenum)
 1578                         continue;
 1579                 break;
 1580             }
 1581             i = j - 1;
 1582         }
 1583     }
 1584     for (i = 0; i < nzones; ++i) {
 1585         zp = &zones[i];
 1586         zp->z_rules = NULL;
 1587         zp->z_nrules = 0;
 1588     }
 1589     for (base = 0; base < nrules; base = out) {
 1590         rp = &rules[base];
 1591         for (out = base + 1; out < nrules; ++out)
 1592             if (strcmp(rp->r_name, rules[out].r_name) != 0)
 1593                 break;
 1594         for (i = 0; i < nzones; ++i) {
 1595             zp = &zones[i];
 1596             if (strcmp(zp->z_rule, rp->r_name) != 0)
 1597                 continue;
 1598             zp->z_rules = rp;
 1599             zp->z_nrules = out - base;
 1600         }
 1601     }
 1602     for (i = 0; i < nzones; ++i) {
 1603         zp = &zones[i];
 1604         if (zp->z_nrules == 0) {
 1605             /*
 1606             ** Maybe we have a local standard time offset.
 1607             */
 1608             eat(zp->z_filenum, zp->z_linenum);
 1609             zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
 1610             /*
 1611             ** Note, though, that if there's no rule,
 1612             ** a '%s' in the format is a bad thing.
 1613             */
 1614             if (zp->z_format_specifier == 's')
 1615                 error("%s", _("%s in ruleless zone"));
 1616         }
 1617     }
 1618     if (errors)
 1619         exit(EXIT_FAILURE);
 1620 }
 1621 
 1622 /* Read a text line from FP into BUF, which is of size BUFSIZE.
 1623    Terminate it with a NUL byte instead of a newline.
 1624    Return true if successful, false if EOF.
 1625    On error, report the error and exit.  */
 1626 static bool
 1627 inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
 1628 {
 1629   ptrdiff_t linelen = 0, ch;
 1630   while ((ch = getc(fp)) != '\n') {
 1631     if (ch < 0) {
 1632       if (ferror(fp)) {
 1633     error(_("input error"));
 1634     exit(EXIT_FAILURE);
 1635       }
 1636       if (linelen == 0)
 1637     return false;
 1638       error(_("unterminated line"));
 1639       exit(EXIT_FAILURE);
 1640     }
 1641     if (!ch) {
 1642       error(_("NUL input byte"));
 1643       exit(EXIT_FAILURE);
 1644     }
 1645     buf[linelen++] = ch;
 1646     if (linelen == bufsize) {
 1647       error(_("line too long"));
 1648       exit(EXIT_FAILURE);
 1649     }
 1650   }
 1651   buf[linelen] = '\0';
 1652   return true;
 1653 }
 1654 
 1655 static void
 1656 infile(int fnum, char const *name)
 1657 {
 1658     register FILE *         fp;
 1659     register const struct lookup *  lp;
 1660     register bool           wantcont;
 1661     register lineno         num;
 1662 
 1663     if (strcmp(name, "-") == 0) {
 1664         fp = stdin;
 1665     } else if ((fp = fopen(name, "r")) == NULL) {
 1666         const char *e = strerror(errno);
 1667 
 1668         fprintf(stderr, _("%s: Can't open %s: %s\n"),
 1669             progname, name, e);
 1670         exit(EXIT_FAILURE);
 1671     }
 1672     wantcont = false;
 1673     for (num = 1; ; ++num) {
 1674         enum { bufsize_bound
 1675           = (min(INT_MAX, min(PTRDIFF_MAX, SIZE_MAX))
 1676              / FORMAT_LEN_GROWTH_BOUND) };
 1677         char buf[min(_POSIX2_LINE_MAX, bufsize_bound)];
 1678         int nfields;
 1679         char *fields[MAX_FIELDS];
 1680         eat(fnum, num);
 1681         if (!inputline(fp, buf, sizeof buf))
 1682           break;
 1683         nfields = getfields(buf, fields,
 1684                     sizeof fields / sizeof *fields);
 1685         if (nfields == 0) {
 1686             /* nothing to do */
 1687         } else if (wantcont) {
 1688             wantcont = inzcont(fields, nfields);
 1689         } else {
 1690             struct lookup const *line_codes
 1691               = fnum < 0 ? leap_line_codes : zi_line_codes;
 1692             lp = byword(fields[0], line_codes);
 1693             if (lp == NULL)
 1694                 error(_("input line of unknown type"));
 1695             else switch (lp->l_value) {
 1696                 case LC_RULE:
 1697                     inrule(fields, nfields);
 1698                     wantcont = false;
 1699                     break;
 1700                 case LC_ZONE:
 1701                     wantcont = inzone(fields, nfields);
 1702                     break;
 1703                 case LC_LINK:
 1704                     inlink(fields, nfields);
 1705                     wantcont = false;
 1706                     break;
 1707                 case LC_LEAP:
 1708                     inleap(fields, nfields);
 1709                     wantcont = false;
 1710                     break;
 1711                 case LC_EXPIRES:
 1712                     inexpires(fields, nfields);
 1713                     wantcont = false;
 1714                     break;
 1715                 default: unreachable();
 1716             }
 1717         }
 1718     }
 1719     close_file(fp, NULL, filename(fnum), NULL);
 1720     if (wantcont)
 1721         error(_("expected continuation line not found"));
 1722 }
 1723 
 1724 /*
 1725 ** Convert a string of one of the forms
 1726 **  h   -h  hh:mm   -hh:mm  hh:mm:ss    -hh:mm:ss
 1727 ** into a number of seconds.
 1728 ** A null string maps to zero.
 1729 ** Call error with errstring and return zero on errors.
 1730 */
 1731 
 1732 static zic_t
 1733 gethms(char const *string, char const *errstring)
 1734 {
 1735     zic_t   hh;
 1736     int sign, mm = 0, ss = 0;
 1737     char hhx, mmx, ssx, xr = '0', xs;
 1738     int tenths = 0;
 1739     bool ok = true;
 1740 
 1741     if (string == NULL || *string == '\0')
 1742         return 0;
 1743     if (*string == '-') {
 1744         sign = -1;
 1745         ++string;
 1746     } else  sign = 1;
 1747     switch (sscanf(string,
 1748                "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
 1749                &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) {
 1750       default: ok = false; break;
 1751       case 8:
 1752         ok = '0' <= xr && xr <= '9';
 1753         ATTRIBUTE_FALLTHROUGH;
 1754       case 7:
 1755         ok &= ssx == '.';
 1756         if (ok && noise)
 1757           warning(_("fractional seconds rejected by"
 1758             " pre-2018 versions of zic"));
 1759         ATTRIBUTE_FALLTHROUGH;
 1760       case 5: ok &= mmx == ':'; ATTRIBUTE_FALLTHROUGH;
 1761       case 3: ok &= hhx == ':'; ATTRIBUTE_FALLTHROUGH;
 1762       case 1: break;
 1763     }
 1764     if (!ok) {
 1765             error("%s", errstring);
 1766             return 0;
 1767     }
 1768     if (hh < 0 ||
 1769         mm < 0 || mm >= MINSPERHOUR ||
 1770         ss < 0 || ss > SECSPERMIN) {
 1771             error("%s", errstring);
 1772             return 0;
 1773     }
 1774     if (ZIC_MAX / SECSPERHOUR < hh) {
 1775         error(_("time overflow"));
 1776         return 0;
 1777     }
 1778     ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even.  */
 1779     if (noise && (hh > HOURSPERDAY ||
 1780         (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
 1781 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
 1782     return oadd(sign * hh * SECSPERHOUR,
 1783             sign * (mm * SECSPERMIN + ss));
 1784 }
 1785 
 1786 static zic_t
 1787 getsave(char *field, bool *isdst)
 1788 {
 1789   int dst = -1;
 1790   zic_t save;
 1791   ptrdiff_t fieldlen = strlen(field);
 1792   if (fieldlen != 0) {
 1793     char *ep = field + fieldlen - 1;
 1794     switch (*ep) {
 1795       case 'd': dst = 1; *ep = '\0'; break;
 1796       case 's': dst = 0; *ep = '\0'; break;
 1797     }
 1798   }
 1799   save = gethms(field, _("invalid saved time"));
 1800   *isdst = dst < 0 ? save != 0 : dst;
 1801   return save;
 1802 }
 1803 
 1804 static void
 1805 inrule(char **fields, int nfields)
 1806 {
 1807     struct rule r;
 1808 
 1809     if (nfields != RULE_FIELDS) {
 1810         error(_("wrong number of fields on Rule line"));
 1811         return;
 1812     }
 1813     switch (*fields[RF_NAME]) {
 1814       case '\0':
 1815       case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
 1816       case '+': case '-':
 1817       case '0': case '1': case '2': case '3': case '4':
 1818       case '5': case '6': case '7': case '8': case '9':
 1819         error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
 1820         return;
 1821     }
 1822     r.r_filenum = filenum;
 1823     r.r_linenum = linenum;
 1824     r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
 1825     if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR],
 1826              fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
 1827              fields[RF_TOD]))
 1828       return;
 1829     r.r_name = estrdup(fields[RF_NAME]);
 1830     r.r_abbrvar = estrdup(fields[RF_ABBRVAR]);
 1831     if (max_abbrvar_len < strlen(r.r_abbrvar))
 1832         max_abbrvar_len = strlen(r.r_abbrvar);
 1833     rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
 1834     rules[nrules++] = r;
 1835 }
 1836 
 1837 static bool
 1838 inzone(char **fields, int nfields)
 1839 {
 1840     register ptrdiff_t i;
 1841 
 1842     if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
 1843         error(_("wrong number of fields on Zone line"));
 1844         return false;
 1845     }
 1846     if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) {
 1847         error(
 1848 _("\"Zone %s\" line and -l option are mutually exclusive"),
 1849             tzdefault);
 1850         return false;
 1851     }
 1852     if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
 1853         error(
 1854 _("\"Zone %s\" line and -p option are mutually exclusive"),
 1855             TZDEFRULES);
 1856         return false;
 1857     }
 1858     for (i = 0; i < nzones; ++i)
 1859         if (zones[i].z_name != NULL &&
 1860             strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
 1861                 error(_("duplicate zone name %s"
 1862                     " (file \"%s\", line %"PRIdMAX")"),
 1863                       fields[ZF_NAME],
 1864                       filename(zones[i].z_filenum),
 1865                       zones[i].z_linenum);
 1866                 return false;
 1867         }
 1868     return inzsub(fields, nfields, false);
 1869 }
 1870 
 1871 static bool
 1872 inzcont(char **fields, int nfields)
 1873 {
 1874     if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
 1875         error(_("wrong number of fields on Zone continuation line"));
 1876         return false;
 1877     }
 1878     return inzsub(fields, nfields, true);
 1879 }
 1880 
 1881 static bool
 1882 inzsub(char **fields, int nfields, bool iscont)
 1883 {
 1884     register char *     cp;
 1885     char *          cp1;
 1886     struct zone z;
 1887     int format_len;
 1888     register int        i_stdoff, i_rule, i_format;
 1889     register int        i_untilyear, i_untilmonth;
 1890     register int        i_untilday, i_untiltime;
 1891     register bool       hasuntil;
 1892 
 1893     if (iscont) {
 1894         i_stdoff = ZFC_STDOFF;
 1895         i_rule = ZFC_RULE;
 1896         i_format = ZFC_FORMAT;
 1897         i_untilyear = ZFC_TILYEAR;
 1898         i_untilmonth = ZFC_TILMONTH;
 1899         i_untilday = ZFC_TILDAY;
 1900         i_untiltime = ZFC_TILTIME;
 1901     } else if (!namecheck(fields[ZF_NAME]))
 1902         return false;
 1903     else {
 1904         i_stdoff = ZF_STDOFF;
 1905         i_rule = ZF_RULE;
 1906         i_format = ZF_FORMAT;
 1907         i_untilyear = ZF_TILYEAR;
 1908         i_untilmonth = ZF_TILMONTH;
 1909         i_untilday = ZF_TILDAY;
 1910         i_untiltime = ZF_TILTIME;
 1911     }
 1912     z.z_filenum = filenum;
 1913     z.z_linenum = linenum;
 1914     z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
 1915     if ((cp = strchr(fields[i_format], '%')) != 0) {
 1916         if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
 1917             || strchr(fields[i_format], '/')) {
 1918             error(_("invalid abbreviation format"));
 1919             return false;
 1920         }
 1921     }
 1922     z.z_format_specifier = cp ? *cp : '\0';
 1923     format_len = strlen(fields[i_format]);
 1924     if (max_format_len < format_len)
 1925       max_format_len = format_len;
 1926     hasuntil = nfields > i_untilyear;
 1927     if (hasuntil) {
 1928         z.z_untilrule.r_filenum = filenum;
 1929         z.z_untilrule.r_linenum = linenum;
 1930         if (!rulesub(
 1931             &z.z_untilrule,
 1932             fields[i_untilyear],
 1933             "only",
 1934             "",
 1935             (nfields > i_untilmonth) ?
 1936             fields[i_untilmonth] : "Jan",
 1937             (nfields > i_untilday) ? fields[i_untilday] : "1",
 1938             (nfields > i_untiltime) ? fields[i_untiltime] : "0"))
 1939           return false;
 1940         z.z_untiltime = rpytime(&z.z_untilrule,
 1941             z.z_untilrule.r_loyear);
 1942         if (iscont && nzones > 0 &&
 1943             z.z_untiltime > min_time &&
 1944             z.z_untiltime < max_time &&
 1945             zones[nzones - 1].z_untiltime > min_time &&
 1946             zones[nzones - 1].z_untiltime < max_time &&
 1947             zones[nzones - 1].z_untiltime >= z.z_untiltime) {
 1948                 error(_(
 1949 "Zone continuation line end time is not after end time of previous line"
 1950                     ));
 1951                 return false;
 1952         }
 1953     }
 1954     z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]);
 1955     z.z_rule = estrdup(fields[i_rule]);
 1956     z.z_format = cp1 = estrdup(fields[i_format]);
 1957     if (z.z_format_specifier == 'z') {
 1958       cp1[cp - fields[i_format]] = 's';
 1959       if (noise)
 1960         warning(_("format '%s' not handled by pre-2015 versions of zic"),
 1961             fields[i_format]);
 1962     }
 1963     zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
 1964     zones[nzones++] = z;
 1965     /*
 1966     ** If there was an UNTIL field on this line,
 1967     ** there's more information about the zone on the next line.
 1968     */
 1969     return hasuntil;
 1970 }
 1971 
 1972 static zic_t
 1973 getleapdatetime(char **fields, bool expire_line)
 1974 {
 1975     register const char *       cp;
 1976     register const struct lookup *  lp;
 1977     register zic_t          i, j;
 1978     zic_t               year;
 1979     int             month, day;
 1980     zic_t               dayoff, tod;
 1981     zic_t               t;
 1982     char xs;
 1983 
 1984     dayoff = 0;
 1985     cp = fields[LP_YEAR];
 1986     if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
 1987         /*
 1988         ** Leapin' Lizards!
 1989         */
 1990         error(_("invalid leaping year"));
 1991         return -1;
 1992     }
 1993     if (!expire_line) {
 1994         if (!leapseen || leapmaxyear < year)
 1995         leapmaxyear = year;
 1996         if (!leapseen || leapminyear > year)
 1997         leapminyear = year;
 1998         leapseen = true;
 1999     }
 2000     j = EPOCH_YEAR;
 2001     while (j != year) {
 2002         if (year > j) {
 2003             i = len_years[isleap(j)];
 2004             ++j;
 2005         } else {
 2006             --j;
 2007             i = -len_years[isleap(j)];
 2008         }
 2009         dayoff = oadd(dayoff, i);
 2010     }
 2011     if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
 2012         error(_("invalid month name"));
 2013         return -1;
 2014     }
 2015     month = lp->l_value;
 2016     j = TM_JANUARY;
 2017     while (j != month) {
 2018         i = len_months[isleap(year)][j];
 2019         dayoff = oadd(dayoff, i);
 2020         ++j;
 2021     }
 2022     cp = fields[LP_DAY];
 2023     if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
 2024         day <= 0 || day > len_months[isleap(year)][month]) {
 2025             error(_("invalid day of month"));
 2026             return -1;
 2027     }
 2028     dayoff = oadd(dayoff, day - 1);
 2029     if (dayoff < min_time / SECSPERDAY) {
 2030         error(_("time too small"));
 2031         return -1;
 2032     }
 2033     if (dayoff > max_time / SECSPERDAY) {
 2034         error(_("time too large"));
 2035         return -1;
 2036     }
 2037     t = dayoff * SECSPERDAY;
 2038     tod = gethms(fields[LP_TIME], _("invalid time of day"));
 2039     t = tadd(t, tod);
 2040     if (t < 0)
 2041       error(_("leap second precedes Epoch"));
 2042     return t;
 2043 }
 2044 
 2045 static void
 2046 inleap(char **fields, int nfields)
 2047 {
 2048   if (nfields != LEAP_FIELDS)
 2049     error(_("wrong number of fields on Leap line"));
 2050   else {
 2051     zic_t t = getleapdatetime(fields, false);
 2052     if (0 <= t) {
 2053       struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
 2054       if (!lp)
 2055     error(_("invalid Rolling/Stationary field on Leap line"));
 2056       else {
 2057     int correction = 0;
 2058     if (!fields[LP_CORR][0]) /* infile() turns "-" into "".  */
 2059       correction = -1;
 2060     else if (strcmp(fields[LP_CORR], "+") == 0)
 2061       correction = 1;
 2062     else
 2063       error(_("invalid CORRECTION field on Leap line"));
 2064     if (correction)
 2065       leapadd(t, correction, lp->l_value);
 2066       }
 2067     }
 2068   }
 2069 }
 2070 
 2071 static void
 2072 inexpires(char **fields, int nfields)
 2073 {
 2074   if (nfields != EXPIRES_FIELDS)
 2075     error(_("wrong number of fields on Expires line"));
 2076   else if (0 <= leapexpires)
 2077     error(_("multiple Expires lines"));
 2078   else
 2079     leapexpires = getleapdatetime(fields, true);
 2080 }
 2081 
 2082 static void
 2083 inlink(char **fields, int nfields)
 2084 {
 2085     struct link l;
 2086 
 2087     if (nfields != LINK_FIELDS) {
 2088         error(_("wrong number of fields on Link line"));
 2089         return;
 2090     }
 2091     if (*fields[LF_TARGET] == '\0') {
 2092         error(_("blank TARGET field on Link line"));
 2093         return;
 2094     }
 2095     if (! namecheck(fields[LF_LINKNAME]))
 2096       return;
 2097     l.l_filenum = filenum;
 2098     l.l_linenum = linenum;
 2099     l.l_target = estrdup(fields[LF_TARGET]);
 2100     l.l_linkname = estrdup(fields[LF_LINKNAME]);
 2101     links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
 2102     links[nlinks++] = l;
 2103 }
 2104 
 2105 static bool
 2106 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
 2107     const char *typep, const char *monthp, const char *dayp,
 2108     const char *timep)
 2109 {
 2110     register const struct lookup *  lp;
 2111     register const char *       cp;
 2112     register char *         dp;
 2113     register char *         ep;
 2114     char xs;
 2115 
 2116     if ((lp = byword(monthp, mon_names)) == NULL) {
 2117         error(_("invalid month name"));
 2118         return false;
 2119     }
 2120     rp->r_month = lp->l_value;
 2121     rp->r_todisstd = false;
 2122     rp->r_todisut = false;
 2123     dp = estrdup(timep);
 2124     if (*dp != '\0') {
 2125         ep = dp + strlen(dp) - 1;
 2126         switch (lowerit(*ep)) {
 2127             case 's':   /* Standard */
 2128                 rp->r_todisstd = true;
 2129                 rp->r_todisut = false;
 2130                 *ep = '\0';
 2131                 break;
 2132             case 'w':   /* Wall */
 2133                 rp->r_todisstd = false;
 2134                 rp->r_todisut = false;
 2135                 *ep = '\0';
 2136                 break;
 2137             case 'g':   /* Greenwich */
 2138             case 'u':   /* Universal */
 2139             case 'z':   /* Zulu */
 2140                 rp->r_todisstd = true;
 2141                 rp->r_todisut = true;
 2142                 *ep = '\0';
 2143                 break;
 2144         }
 2145     }
 2146     rp->r_tod = gethms(dp, _("invalid time of day"));
 2147     free(dp);
 2148     /*
 2149     ** Year work.
 2150     */
 2151     cp = loyearp;
 2152     lp = byword(cp, begin_years);
 2153     rp->r_lowasnum = lp == NULL;
 2154     if (!rp->r_lowasnum) switch (lp->l_value) {
 2155         case YR_MINIMUM:
 2156             rp->r_loyear = ZIC_MIN;
 2157             break;
 2158         case YR_MAXIMUM:
 2159             rp->r_loyear = ZIC_MAX;
 2160             break;
 2161         default: unreachable();
 2162     } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
 2163         error(_("invalid starting year"));
 2164         return false;
 2165     }
 2166     cp = hiyearp;
 2167     lp = byword(cp, end_years);
 2168     rp->r_hiwasnum = lp == NULL;
 2169     if (!rp->r_hiwasnum) switch (lp->l_value) {
 2170         case YR_MINIMUM:
 2171             rp->r_hiyear = ZIC_MIN;
 2172             break;
 2173         case YR_MAXIMUM:
 2174             rp->r_hiyear = ZIC_MAX;
 2175             break;
 2176         case YR_ONLY:
 2177             rp->r_hiyear = rp->r_loyear;
 2178             break;
 2179         default: unreachable();
 2180     } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
 2181         error(_("invalid ending year"));
 2182         return false;
 2183     }
 2184     if (rp->r_loyear > rp->r_hiyear) {
 2185         error(_("starting year greater than ending year"));
 2186         return false;
 2187     }
 2188     if (*typep != '\0') {
 2189         error(_("year type \"%s\" is unsupported; use \"-\" instead"),
 2190             typep);
 2191         return false;
 2192     }
 2193     /*
 2194     ** Day work.
 2195     ** Accept things such as:
 2196     **  1
 2197     **  lastSunday
 2198     **  last-Sunday (undocumented; warn about this)
 2199     **  Sun<=20
 2200     **  Sun>=7
 2201     */
 2202     dp = estrdup(dayp);
 2203     if ((lp = byword(dp, lasts)) != NULL) {
 2204         rp->r_dycode = DC_DOWLEQ;
 2205         rp->r_wday = lp->l_value;
 2206         rp->r_dayofmonth = len_months[1][rp->r_month];
 2207     } else {
 2208         if ((ep = strchr(dp, '<')) != 0)
 2209             rp->r_dycode = DC_DOWLEQ;
 2210         else if ((ep = strchr(dp, '>')) != 0)
 2211             rp->r_dycode = DC_DOWGEQ;
 2212         else {
 2213             ep = dp;
 2214             rp->r_dycode = DC_DOM;
 2215         }
 2216         if (rp->r_dycode != DC_DOM) {
 2217             *ep++ = 0;
 2218             if (*ep++ != '=') {
 2219                 error(_("invalid day of month"));
 2220                 free(dp);
 2221                 return false;
 2222             }
 2223             if ((lp = byword(dp, wday_names)) == NULL) {
 2224                 error(_("invalid weekday name"));
 2225                 free(dp);
 2226                 return false;
 2227             }
 2228             rp->r_wday = lp->l_value;
 2229         }
 2230         if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
 2231             rp->r_dayofmonth <= 0 ||
 2232             (rp->r_dayofmonth > len_months[1][rp->r_month])) {
 2233                 error(_("invalid day of month"));
 2234                 free(dp);
 2235                 return false;
 2236         }
 2237     }
 2238     free(dp);
 2239     return true;
 2240 }
 2241 
 2242 static void
 2243 convert(uint_fast32_t val, char *buf)
 2244 {
 2245     register int    i;
 2246     register int    shift;
 2247     unsigned char *const b = (unsigned char *) buf;
 2248 
 2249     for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
 2250       b[i] = (val >> shift) & 0xff;
 2251 }
 2252 
 2253 static void
 2254 convert64(uint_fast64_t val, char *buf)
 2255 {
 2256     register int    i;
 2257     register int    shift;
 2258     unsigned char *const b = (unsigned char *) buf;
 2259 
 2260     for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
 2261       b[i] = (val >> shift) & 0xff;
 2262 }
 2263 
 2264 static void
 2265 puttzcode(zic_t val, FILE *fp)
 2266 {
 2267     char    buf[4];
 2268 
 2269     convert(val, buf);
 2270     fwrite(buf, sizeof buf, 1, fp);
 2271 }
 2272 
 2273 static void
 2274 puttzcodepass(zic_t val, FILE *fp, int pass)
 2275 {
 2276   if (pass == 1)
 2277     puttzcode(val, fp);
 2278   else {
 2279     char    buf[8];
 2280 
 2281     convert64(val, buf);
 2282     fwrite(buf, sizeof buf, 1, fp);
 2283   }
 2284 }
 2285 
 2286 static int
 2287 atcomp(const void *avp, const void *bvp)
 2288 {
 2289   struct attype const *ap = avp, *bp = bvp;
 2290   zic_t a = ap->at, b = bp->at;
 2291   return a < b ? -1 : a > b;
 2292 }
 2293 
 2294 struct timerange {
 2295   int defaulttype;
 2296   ptrdiff_t base, count;
 2297   int leapbase, leapcount;
 2298   bool leapexpiry;
 2299 };
 2300 
 2301 static struct timerange
 2302 limitrange(struct timerange r, zic_t lo, zic_t hi,
 2303        zic_t const *ats, unsigned char const *types)
 2304 {
 2305   /* Omit ordinary transitions < LO.  */
 2306   while (0 < r.count && ats[r.base] < lo) {
 2307     r.defaulttype = types[r.base];
 2308     r.count--;
 2309     r.base++;
 2310   }
 2311 
 2312   /* Omit as many initial leap seconds as possible, such that the
 2313      first leap second in the truncated list is <= LO, and is a
 2314      positive leap second if and only if it has a positive correction.
 2315      This supports common TZif readers that assume that the first leap
 2316      second is positive if and only if its correction is positive.  */
 2317   while (1 < r.leapcount && trans[r.leapbase + 1] <= lo) {
 2318     r.leapcount--;
 2319     r.leapbase++;
 2320   }
 2321   while (0 < r.leapbase
 2322      && ((corr[r.leapbase - 1] < corr[r.leapbase])
 2323          != (0 < corr[r.leapbase]))) {
 2324     r.leapcount++;
 2325     r.leapbase--;
 2326   }
 2327 
 2328 
 2329   /* Omit ordinary and leap second transitions greater than HI + 1.  */
 2330   if (hi < max_time) {
 2331     while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
 2332       r.count--;
 2333     while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
 2334       r.leapcount--;
 2335   }
 2336 
 2337   /* Determine whether to append an expiration to the leap second table.  */
 2338   r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi;
 2339 
 2340   return r;
 2341 }
 2342 
 2343 static void
 2344 writezone(const char *const name, const char *const string, char version,
 2345       int defaulttype)
 2346 {
 2347     register FILE *         fp;
 2348     register ptrdiff_t      i, j;
 2349     register int            pass;
 2350     char *tempname = NULL;
 2351     char const *outname = name;
 2352 
 2353     /* Allocate the ATS and TYPES arrays via a single malloc,
 2354        as this is a bit faster.  Do not malloc(0) if !timecnt,
 2355        as that might return NULL even on success.  */
 2356     zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt,
 2357                            sizeof *ats + 1),
 2358                       alignof(zic_t)));
 2359     void *typesptr = ats + timecnt;
 2360     unsigned char *types = typesptr;
 2361     struct timerange rangeall = {0}, range32, range64;
 2362 
 2363     /*
 2364     ** Sort.
 2365     */
 2366     if (timecnt > 1)
 2367         qsort(attypes, timecnt, sizeof *attypes, atcomp);
 2368     /*
 2369     ** Optimize.
 2370     */
 2371     {
 2372         ptrdiff_t fromi, toi;
 2373 
 2374         toi = 0;
 2375         fromi = 0;
 2376         for ( ; fromi < timecnt; ++fromi) {
 2377             if (toi != 0
 2378                 && ((attypes[fromi].at
 2379                  + utoffs[attypes[toi - 1].type])
 2380                 <= (attypes[toi - 1].at
 2381                     + utoffs[toi == 1 ? 0
 2382                          : attypes[toi - 2].type]))) {
 2383                     attypes[toi - 1].type =
 2384                         attypes[fromi].type;
 2385                     continue;
 2386             }
 2387             if (toi == 0
 2388                 || attypes[fromi].dontmerge
 2389                 || (utoffs[attypes[toi - 1].type]
 2390                 != utoffs[attypes[fromi].type])
 2391                 || (isdsts[attypes[toi - 1].type]
 2392                 != isdsts[attypes[fromi].type])
 2393                 || (desigidx[attypes[toi - 1].type]
 2394                 != desigidx[attypes[fromi].type]))
 2395                     attypes[toi++] = attypes[fromi];
 2396         }
 2397         timecnt = toi;
 2398     }
 2399 
 2400     if (noise && timecnt > 1200) {
 2401       if (timecnt > TZ_MAX_TIMES)
 2402         warning(_("reference clients mishandle"
 2403               " more than %d transition times"),
 2404             TZ_MAX_TIMES);
 2405       else
 2406         warning(_("pre-2014 clients may mishandle"
 2407               " more than 1200 transition times"));
 2408     }
 2409     /*
 2410     ** Transfer.
 2411     */
 2412     for (i = 0; i < timecnt; ++i) {
 2413         ats[i] = attypes[i].at;
 2414         types[i] = attypes[i].type;
 2415     }
 2416 
 2417     /*
 2418     ** Correct for leap seconds.
 2419     */
 2420     for (i = 0; i < timecnt; ++i) {
 2421         j = leapcnt;
 2422         while (--j >= 0)
 2423             if (ats[i] > trans[j] - corr[j]) {
 2424                 ats[i] = tadd(ats[i], corr[j]);
 2425                 break;
 2426             }
 2427     }
 2428 
 2429     rangeall.defaulttype = defaulttype;
 2430     rangeall.count = timecnt;
 2431     rangeall.leapcount = leapcnt;
 2432     range64 = limitrange(rangeall, lo_time,
 2433                  max(hi_time,
 2434                  redundant_time - (ZIC_MIN < redundant_time)),
 2435                  ats, types);
 2436     range32 = limitrange(range64, ZIC32_MIN, ZIC32_MAX, ats, types);
 2437 
 2438     /* TZif version 4 is needed if a no-op transition is appended to
 2439        indicate the expiration of the leap second table, or if the first
 2440        leap second transition is not to a +1 or -1 correction.  */
 2441     for (pass = 1; pass <= 2; pass++) {
 2442       struct timerange const *r = pass == 1 ? &range32 : &range64;
 2443       if (pass == 1 && !want_bloat())
 2444         continue;
 2445       if (r->leapexpiry) {
 2446         if (noise)
 2447           warning(_("%s: pre-2021b clients may mishandle"
 2448             " leap second expiry"),
 2449               name);
 2450         version = '4';
 2451       }
 2452       if (0 < r->leapcount
 2453           && corr[r->leapbase] != 1 && corr[r->leapbase] != -1) {
 2454         if (noise)
 2455           warning(_("%s: pre-2021b clients may mishandle"
 2456             " leap second table truncation"),
 2457               name);
 2458         version = '4';
 2459       }
 2460       if (version == '4')
 2461         break;
 2462     }
 2463 
 2464     fp = open_outfile(&outname, &tempname);
 2465 
 2466     for (pass = 1; pass <= 2; ++pass) {
 2467         register ptrdiff_t thistimei, thistimecnt, thistimelim;
 2468         register int    thisleapi, thisleapcnt, thisleaplim;
 2469         struct tzhead tzh;
 2470         int pretranstype = -1, thisdefaulttype;
 2471         bool locut, hicut, thisleapexpiry;
 2472         zic_t lo, thismin, thismax;
 2473         int old0;
 2474         char        omittype[TZ_MAX_TYPES];
 2475         int     typemap[TZ_MAX_TYPES];
 2476         int     thistypecnt, stdcnt, utcnt;
 2477         char        thischars[TZ_MAX_CHARS];
 2478         int     thischarcnt;
 2479         bool        toomanytimes;
 2480         int     indmap[TZ_MAX_CHARS];
 2481 
 2482         if (pass == 1) {
 2483             thisdefaulttype = range32.defaulttype;
 2484             thistimei = range32.base;
 2485             thistimecnt = range32.count;
 2486             toomanytimes = thistimecnt >> 31 >> 1 != 0;
 2487             thisleapi = range32.leapbase;
 2488             thisleapcnt = range32.leapcount;
 2489             thisleapexpiry = range32.leapexpiry;
 2490             thismin = ZIC32_MIN;
 2491             thismax = ZIC32_MAX;
 2492         } else {
 2493             thisdefaulttype = range64.defaulttype;
 2494             thistimei = range64.base;
 2495             thistimecnt = range64.count;
 2496             toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
 2497             thisleapi = range64.leapbase;
 2498             thisleapcnt = range64.leapcount;
 2499             thisleapexpiry = range64.leapexpiry;
 2500             thismin = min_time;
 2501             thismax = max_time;
 2502         }
 2503         if (toomanytimes)
 2504           error(_("too many transition times"));
 2505 
 2506         locut = thismin < lo_time && lo_time <= thismax;
 2507         hicut = thismin <= hi_time && hi_time < thismax;
 2508         thistimelim = thistimei + thistimecnt;
 2509         memset(omittype, true, typecnt);
 2510 
 2511         /* Determine whether to output a transition before the first
 2512            transition in range.  This is needed when the output is
 2513            truncated at the start, and is also useful when catering to
 2514            buggy 32-bit clients that do not use time type 0 for
 2515            timestamps before the first transition.  */
 2516         if ((locut || (pass == 1 && thistimei))
 2517             && ! (thistimecnt && ats[thistimei] == lo_time)) {
 2518           pretranstype = thisdefaulttype;
 2519           omittype[pretranstype] = false;
 2520         }
 2521 
 2522         /* Arguably the default time type in the 32-bit data
 2523            should be range32.defaulttype, which is suited for
 2524            timestamps just before ZIC32_MIN.  However, zic
 2525            traditionally used the time type of the indefinite
 2526            past instead.  Internet RFC 8532 says readers should
 2527            ignore 32-bit data, so this discrepancy matters only
 2528            to obsolete readers where the traditional type might
 2529            be more appropriate even if it's "wrong".  So, use
 2530            the historical zic value, unless -r specifies a low
 2531            cutoff that excludes some 32-bit timestamps.  */
 2532         if (pass == 1 && lo_time <= thismin)
 2533           thisdefaulttype = range64.defaulttype;
 2534 
 2535         if (locut)
 2536           thisdefaulttype = unspecifiedtype;
 2537         omittype[thisdefaulttype] = false;
 2538         for (i = thistimei; i < thistimelim; i++)
 2539           omittype[types[i]] = false;
 2540         if (hicut)
 2541           omittype[unspecifiedtype] = false;
 2542 
 2543         /* Reorder types to make THISDEFAULTTYPE type 0.
 2544            Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that
 2545            THISDEFAULTTYPE appears as type 0 in the output instead
 2546            of OLD0.  TYPEMAP also omits unused types.  */
 2547         old0 = strlen(omittype);
 2548 
 2549 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
 2550         /*
 2551         ** For some pre-2011 systems: if the last-to-be-written
 2552         ** standard (or daylight) type has an offset different from the
 2553         ** most recently used offset,
 2554         ** append an (unused) copy of the most recently used type
 2555         ** (to help get global "altzone" and "timezone" variables
 2556         ** set correctly).
 2557         */
 2558         if (want_bloat()) {
 2559             register int    mrudst, mrustd, hidst, histd, type;
 2560 
 2561             hidst = histd = mrudst = mrustd = -1;
 2562             if (0 <= pretranstype) {
 2563               if (isdsts[pretranstype])
 2564                 mrudst = pretranstype;
 2565               else
 2566                 mrustd = pretranstype;
 2567             }
 2568             for (i = thistimei; i < thistimelim; i++)
 2569                 if (isdsts[types[i]])
 2570                     mrudst = types[i];
 2571                 else    mrustd = types[i];
 2572             for (i = old0; i < typecnt; i++) {
 2573               int h = (i == old0 ? thisdefaulttype
 2574                    : i == thisdefaulttype ? old0 : i);
 2575               if (!omittype[h]) {
 2576                 if (isdsts[h])
 2577                   hidst = i;
 2578                 else
 2579                   histd = i;
 2580               }
 2581             }
 2582             if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
 2583                 utoffs[hidst] != utoffs[mrudst]) {
 2584                     isdsts[mrudst] = -1;
 2585                     type = addtype(utoffs[mrudst],
 2586                         &chars[desigidx[mrudst]],
 2587                         true,
 2588                         ttisstds[mrudst],
 2589                         ttisuts[mrudst]);
 2590                     isdsts[mrudst] = 1;
 2591                     omittype[type] = false;
 2592             }
 2593             if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
 2594                 utoffs[histd] != utoffs[mrustd]) {
 2595                     isdsts[mrustd] = -1;
 2596                     type = addtype(utoffs[mrustd],
 2597                         &chars[desigidx[mrustd]],
 2598                         false,
 2599                         ttisstds[mrustd],
 2600                         ttisuts[mrustd]);
 2601                     isdsts[mrustd] = 0;
 2602                     omittype[type] = false;
 2603             }
 2604         }
 2605 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
 2606         thistypecnt = 0;
 2607         for (i = old0; i < typecnt; i++)
 2608           if (!omittype[i])
 2609             typemap[i == old0 ? thisdefaulttype
 2610                 : i == thisdefaulttype ? old0 : i]
 2611               = thistypecnt++;
 2612 
 2613         for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
 2614             indmap[i] = -1;
 2615         thischarcnt = stdcnt = utcnt = 0;
 2616         for (i = old0; i < typecnt; i++) {
 2617             register char * thisabbr;
 2618 
 2619             if (omittype[i])
 2620                 continue;
 2621             if (ttisstds[i])
 2622               stdcnt = thistypecnt;
 2623             if (ttisuts[i])
 2624               utcnt = thistypecnt;
 2625             if (indmap[desigidx[i]] >= 0)
 2626                 continue;
 2627             thisabbr = &chars[desigidx[i]];
 2628             for (j = 0; j < thischarcnt; ++j)
 2629                 if (strcmp(&thischars[j], thisabbr) == 0)
 2630                     break;
 2631             if (j == thischarcnt) {
 2632                 strcpy(&thischars[thischarcnt], thisabbr);
 2633                 thischarcnt += strlen(thisabbr) + 1;
 2634             }
 2635             indmap[desigidx[i]] = j;
 2636         }
 2637         if (pass == 1 && !want_bloat()) {
 2638           hicut = thisleapexpiry = false;
 2639           pretranstype = -1;
 2640           thistimecnt = thisleapcnt = 0;
 2641           thistypecnt = thischarcnt = 1;
 2642         }
 2643 #define DO(field)   fwrite(tzh.field, sizeof tzh.field, 1, fp)
 2644         memset(&tzh, 0, sizeof tzh);
 2645         memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
 2646         tzh.tzh_version[0] = version;
 2647         convert(utcnt, tzh.tzh_ttisutcnt);
 2648         convert(stdcnt, tzh.tzh_ttisstdcnt);
 2649         convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt);
 2650         convert((0 <= pretranstype) + thistimecnt + hicut,
 2651             tzh.tzh_timecnt);
 2652         convert(thistypecnt, tzh.tzh_typecnt);
 2653         convert(thischarcnt, tzh.tzh_charcnt);
 2654         DO(tzh_magic);
 2655         DO(tzh_version);
 2656         DO(tzh_reserved);
 2657         DO(tzh_ttisutcnt);
 2658         DO(tzh_ttisstdcnt);
 2659         DO(tzh_leapcnt);
 2660         DO(tzh_timecnt);
 2661         DO(tzh_typecnt);
 2662         DO(tzh_charcnt);
 2663 #undef DO
 2664         if (pass == 1 && !want_bloat()) {
 2665           /* Output a minimal data block with just one time type.  */
 2666           puttzcode(0, fp); /* utoff */
 2667           putc(0, fp);      /* dst */
 2668           putc(0, fp);      /* index of abbreviation */
 2669           putc(0, fp);      /* empty-string abbreviation */
 2670           continue;
 2671         }
 2672 
 2673         /* Output a LO_TIME transition if needed; see limitrange.
 2674            But do not go below the minimum representable value
 2675            for this pass.  */
 2676         lo = pass == 1 && lo_time < ZIC32_MIN ? ZIC32_MIN : lo_time;
 2677 
 2678         if (0 <= pretranstype)
 2679           puttzcodepass(lo, fp, pass);
 2680         for (i = thistimei; i < thistimelim; ++i) {
 2681           puttzcodepass(ats[i], fp, pass);
 2682         }
 2683         if (hicut)
 2684           puttzcodepass(hi_time + 1, fp, pass);
 2685         if (0 <= pretranstype)
 2686           putc(typemap[pretranstype], fp);
 2687         for (i = thistimei; i < thistimelim; i++)
 2688           putc(typemap[types[i]], fp);
 2689         if (hicut)
 2690           putc(typemap[unspecifiedtype], fp);
 2691 
 2692         for (i = old0; i < typecnt; i++) {
 2693           int h = (i == old0 ? thisdefaulttype
 2694                : i == thisdefaulttype ? old0 : i);
 2695           if (!omittype[h]) {
 2696             puttzcode(utoffs[h], fp);
 2697             putc(isdsts[h], fp);
 2698             putc(indmap[desigidx[h]], fp);
 2699           }
 2700         }
 2701         if (thischarcnt != 0)
 2702             fwrite(thischars, sizeof thischars[0],
 2703                       thischarcnt, fp);
 2704         thisleaplim = thisleapi + thisleapcnt;
 2705         for (i = thisleapi; i < thisleaplim; ++i) {
 2706             register zic_t  todo;
 2707 
 2708             if (roll[i]) {
 2709                 if (timecnt == 0 || trans[i] < ats[0]) {
 2710                     j = 0;
 2711                     while (isdsts[j])
 2712                         if (++j >= typecnt) {
 2713                             j = 0;
 2714                             break;
 2715                         }
 2716                 } else {
 2717                     j = 1;
 2718                     while (j < timecnt &&
 2719                         trans[i] >= ats[j])
 2720                             ++j;
 2721                     j = types[j - 1];
 2722                 }
 2723                 todo = tadd(trans[i], -utoffs[j]);
 2724             } else  todo = trans[i];
 2725             puttzcodepass(todo, fp, pass);
 2726             puttzcode(corr[i], fp);
 2727         }
 2728         if (thisleapexpiry) {
 2729           /* Append a no-op leap correction indicating when the leap
 2730              second table expires.  Although this does not conform to
 2731              Internet RFC 8536, most clients seem to accept this and
 2732              the plan is to amend the RFC to allow this in version 4
 2733              TZif files.  */
 2734           puttzcodepass(leapexpires, fp, pass);
 2735           puttzcode(thisleaplim ? corr[thisleaplim - 1] : 0, fp);
 2736         }
 2737         if (stdcnt != 0)
 2738           for (i = old0; i < typecnt; i++)
 2739             if (!omittype[i])
 2740                 putc(ttisstds[i], fp);
 2741         if (utcnt != 0)
 2742           for (i = old0; i < typecnt; i++)
 2743             if (!omittype[i])
 2744                 putc(ttisuts[i], fp);
 2745     }
 2746     fprintf(fp, "\n%s\n", string);
 2747     close_file(fp, directory, name, tempname);
 2748     rename_dest(tempname, name);
 2749     free(ats);
 2750 }
 2751 
 2752 static char const *
 2753 abbroffset(char *buf, zic_t offset)
 2754 {
 2755   char sign = '+';
 2756   int seconds, minutes;
 2757 
 2758   if (offset < 0) {
 2759     offset = -offset;
 2760     sign = '-';
 2761   }
 2762 
 2763   seconds = offset % SECSPERMIN;
 2764   offset /= SECSPERMIN;
 2765   minutes = offset % MINSPERHOUR;
 2766   offset /= MINSPERHOUR;
 2767   if (100 <= offset) {
 2768     error(_("%%z UT offset magnitude exceeds 99:59:59"));
 2769     return "%z";
 2770   } else {
 2771     char *p = buf;
 2772     *p++ = sign;
 2773     *p++ = '0' + offset / 10;
 2774     *p++ = '0' + offset % 10;
 2775     if (minutes | seconds) {
 2776       *p++ = '0' + minutes / 10;
 2777       *p++ = '0' + minutes % 10;
 2778       if (seconds) {
 2779     *p++ = '0' + seconds / 10;
 2780     *p++ = '0' + seconds % 10;
 2781       }
 2782     }
 2783     *p = '\0';
 2784     return buf;
 2785   }
 2786 }
 2787 
 2788 static char const disable_percent_s[] = "";
 2789 
 2790 static ptrdiff_t
 2791 doabbr(char *abbr, struct zone const *zp, char const *letters,
 2792        bool isdst, zic_t save, bool doquotes)
 2793 {
 2794     register char * cp;
 2795     register char * slashp;
 2796     ptrdiff_t len;
 2797     char const *format = zp->z_format;
 2798 
 2799     slashp = strchr(format, '/');
 2800     if (slashp == NULL) {
 2801       char letterbuf[PERCENT_Z_LEN_BOUND + 1];
 2802       if (zp->z_format_specifier == 'z')
 2803         letters = abbroffset(letterbuf, zp->z_stdoff + save);
 2804       else if (!letters)
 2805         letters = "%s";
 2806       else if (letters == disable_percent_s)
 2807         return 0;
 2808       sprintf(abbr, format, letters);
 2809     } else if (isdst) {
 2810         strcpy(abbr, slashp + 1);
 2811     } else {
 2812         memcpy(abbr, format, slashp - format);
 2813         abbr[slashp - format] = '\0';
 2814     }
 2815     len = strlen(abbr);
 2816     if (!doquotes)
 2817         return len;
 2818     for (cp = abbr; is_alpha(*cp); cp++)
 2819         continue;
 2820     if (len > 0 && *cp == '\0')
 2821         return len;
 2822     abbr[len + 2] = '\0';
 2823     abbr[len + 1] = '>';
 2824     memmove(abbr + 1, abbr, len);
 2825     abbr[0] = '<';
 2826     return len + 2;
 2827 }
 2828 
 2829 static void
 2830 updateminmax(const zic_t x)
 2831 {
 2832     if (min_year > x)
 2833         min_year = x;
 2834     if (max_year < x)
 2835         max_year = x;
 2836 }
 2837 
 2838 static int
 2839 stringoffset(char *result, zic_t offset)
 2840 {
 2841     register int    hours;
 2842     register int    minutes;
 2843     register int    seconds;
 2844     bool negative = offset < 0;
 2845     int len = negative;
 2846 
 2847     if (negative) {
 2848         offset = -offset;
 2849         result[0] = '-';
 2850     }
 2851     seconds = offset % SECSPERMIN;
 2852     offset /= SECSPERMIN;
 2853     minutes = offset % MINSPERHOUR;
 2854     offset /= MINSPERHOUR;
 2855     hours = offset;
 2856     if (hours >= HOURSPERDAY * DAYSPERWEEK) {
 2857         result[0] = '\0';
 2858         return 0;
 2859     }
 2860     len += sprintf(result + len, "%d", hours);
 2861     if (minutes != 0 || seconds != 0) {
 2862         len += sprintf(result + len, ":%02d", minutes);
 2863         if (seconds != 0)
 2864             len += sprintf(result + len, ":%02d", seconds);
 2865     }
 2866     return len;
 2867 }
 2868 
 2869 static int
 2870 stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff)
 2871 {
 2872     register zic_t  tod = rp->r_tod;
 2873     register int    compat = 0;
 2874 
 2875     if (rp->r_dycode == DC_DOM) {
 2876         register int    month, total;
 2877 
 2878         if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
 2879             return -1;
 2880         total = 0;
 2881         for (month = 0; month < rp->r_month; ++month)
 2882             total += len_months[0][month];
 2883         /* Omit the "J" in Jan and Feb, as that's shorter.  */
 2884         if (rp->r_month <= 1)
 2885           result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
 2886         else
 2887           result += sprintf(result, "J%d", total + rp->r_dayofmonth);
 2888     } else {
 2889         register int    week;
 2890         register int    wday = rp->r_wday;
 2891         register int    wdayoff;
 2892 
 2893         if (rp->r_dycode == DC_DOWGEQ) {
 2894             wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
 2895             if (wdayoff)
 2896                 compat = 2013;
 2897             wday -= wdayoff;
 2898             tod += wdayoff * SECSPERDAY;
 2899             week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
 2900         } else if (rp->r_dycode == DC_DOWLEQ) {
 2901             if (rp->r_dayofmonth == len_months[1][rp->r_month])
 2902                 week = 5;
 2903             else {
 2904                 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
 2905                 if (wdayoff)
 2906                     compat = 2013;
 2907                 wday -= wdayoff;
 2908                 tod += wdayoff * SECSPERDAY;
 2909                 week = rp->r_dayofmonth / DAYSPERWEEK;
 2910             }
 2911         } else  return -1;  /* "cannot happen" */
 2912         if (wday < 0)
 2913             wday += DAYSPERWEEK;
 2914         result += sprintf(result, "M%d.%d.%d",
 2915                   rp->r_month + 1, week, wday);
 2916     }
 2917     if (rp->r_todisut)
 2918       tod += stdoff;
 2919     if (rp->r_todisstd && !rp->r_isdst)
 2920       tod += save;
 2921     if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
 2922         *result++ = '/';
 2923         if (! stringoffset(result, tod))
 2924             return -1;
 2925         if (tod < 0) {
 2926             if (compat < 2013)
 2927                 compat = 2013;
 2928         } else if (SECSPERDAY <= tod) {
 2929             if (compat < 1994)
 2930                 compat = 1994;
 2931         }
 2932     }
 2933     return compat;
 2934 }
 2935 
 2936 static int
 2937 rule_cmp(struct rule const *a, struct rule const *b)
 2938 {
 2939     if (!a)
 2940         return -!!b;
 2941     if (!b)
 2942         return 1;
 2943     if (a->r_hiyear != b->r_hiyear)
 2944         return a->r_hiyear < b->r_hiyear ? -1 : 1;
 2945     if (a->r_hiyear == ZIC_MAX)
 2946         return 0;
 2947     if (a->r_month - b->r_month != 0)
 2948         return a->r_month - b->r_month;
 2949     return a->r_dayofmonth - b->r_dayofmonth;
 2950 }
 2951 
 2952 static int
 2953 stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
 2954 {
 2955     register const struct zone *    zp;
 2956     register struct rule *      rp;
 2957     register struct rule *      stdrp;
 2958     register struct rule *      dstrp;
 2959     register ptrdiff_t      i;
 2960     register int            compat = 0;
 2961     register int            c;
 2962     int             offsetlen;
 2963     struct rule         stdr, dstr;
 2964     ptrdiff_t len;
 2965     int dstcmp;
 2966     struct rule *lastrp[2] = { NULL, NULL };
 2967     struct zone zstr[2];
 2968     struct zone const *stdzp;
 2969     struct zone const *dstzp;
 2970 
 2971     result[0] = '\0';
 2972 
 2973     /* Internet RFC 8536 section 5.1 says to use an empty TZ string if
 2974        future timestamps are truncated.  */
 2975     if (hi_time < max_time)
 2976       return -1;
 2977 
 2978     zp = zpfirst + zonecount - 1;
 2979     for (i = 0; i < zp->z_nrules; ++i) {
 2980         struct rule **last;
 2981         int cmp;
 2982         rp = &zp->z_rules[i];
 2983         last = &lastrp[rp->r_isdst];
 2984         cmp = rule_cmp(*last, rp);
 2985         if (cmp < 0)
 2986           *last = rp;
 2987         else if (cmp == 0)
 2988           return -1;
 2989     }
 2990     stdrp = lastrp[false];
 2991     dstrp = lastrp[true];
 2992     dstcmp = zp->z_nrules ? rule_cmp(dstrp, stdrp) : zp->z_isdst ? 1 : -1;
 2993     stdzp = dstzp = zp;
 2994 
 2995     if (dstcmp < 0) {
 2996       /* Standard time all year.  */
 2997       dstrp = NULL;
 2998     } else if (0 < dstcmp) {
 2999       /* DST all year.  Use an abbreviation like
 3000          "XXX3EDT4,0/0,J365/23" for EDT (-04) all year.  */
 3001       zic_t save = dstrp ? dstrp->r_save : zp->z_save;
 3002       if (0 <= save)
 3003         {
 3004           /* Positive DST, the typical case for all-year DST.
 3005          Fake a timezone with negative DST.  */
 3006           stdzp = &zstr[0];
 3007           dstzp = &zstr[1];
 3008           zstr[0].z_stdoff = zp->z_stdoff + 2 * save;
 3009           zstr[0].z_format = "XXX";  /* Any 3 letters will do.  */
 3010           zstr[0].z_format_specifier = 0;
 3011           zstr[1].z_stdoff = zstr[0].z_stdoff;
 3012           zstr[1].z_format = zp->z_format;
 3013           zstr[1].z_format_specifier = zp->z_format_specifier;
 3014         }
 3015       dstr.r_month = TM_JANUARY;
 3016       dstr.r_dycode = DC_DOM;
 3017       dstr.r_dayofmonth = 1;
 3018       dstr.r_tod = 0;
 3019       dstr.r_todisstd = dstr.r_todisut = false;
 3020       dstr.r_isdst = true;
 3021       dstr.r_save = save < 0 ? save : -save;
 3022       dstr.r_abbrvar = dstrp ? dstrp->r_abbrvar : NULL;
 3023       stdr.r_month = TM_DECEMBER;
 3024       stdr.r_dycode = DC_DOM;
 3025       stdr.r_dayofmonth = 31;
 3026       stdr.r_tod = SECSPERDAY + dstr.r_save;
 3027       stdr.r_todisstd = stdr.r_todisut = false;
 3028       stdr.r_isdst = false;
 3029       stdr.r_save = 0;
 3030       stdr.r_abbrvar = save < 0 && stdrp ? stdrp->r_abbrvar : NULL;
 3031       dstrp = &dstr;
 3032       stdrp = &stdr;
 3033     }
 3034     len = doabbr(result, stdzp, stdrp ? stdrp->r_abbrvar : NULL,
 3035              false, 0, true);
 3036     offsetlen = stringoffset(result + len, - stdzp->z_stdoff);
 3037     if (! offsetlen) {
 3038         result[0] = '\0';
 3039         return -1;
 3040     }
 3041     len += offsetlen;
 3042     if (dstrp == NULL)
 3043         return compat;
 3044     len += doabbr(result + len, dstzp, dstrp->r_abbrvar,
 3045               dstrp->r_isdst, dstrp->r_save, true);
 3046     if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) {
 3047       offsetlen = stringoffset(result + len,
 3048                    - (dstzp->z_stdoff + dstrp->r_save));
 3049       if (! offsetlen) {
 3050         result[0] = '\0';
 3051         return -1;
 3052       }
 3053       len += offsetlen;
 3054     }
 3055     result[len++] = ',';
 3056     c = stringrule(result + len, dstrp, dstrp->r_save, stdzp->z_stdoff);
 3057     if (c < 0) {
 3058         result[0] = '\0';
 3059         return -1;
 3060     }
 3061     if (compat < c)
 3062         compat = c;
 3063     len += strlen(result + len);
 3064     result[len++] = ',';
 3065     c = stringrule(result + len, stdrp, dstrp->r_save, stdzp->z_stdoff);
 3066     if (c < 0) {
 3067         result[0] = '\0';
 3068         return -1;
 3069     }
 3070     if (compat < c)
 3071         compat = c;
 3072     return compat;
 3073 }
 3074 
 3075 static void
 3076 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
 3077 {
 3078     register ptrdiff_t      i, j;
 3079     register zic_t          starttime, untiltime;
 3080     register bool           startttisstd;
 3081     register bool           startttisut;
 3082     register char *         startbuf;
 3083     register char *         ab;
 3084     register char *         envvar;
 3085     register int            max_abbr_len;
 3086     register int            max_envvar_len;
 3087     register bool           prodstic; /* all rules are min to max */
 3088     register int            compat;
 3089     register bool           do_extend;
 3090     register char           version;
 3091     ptrdiff_t lastatmax = -1;
 3092     zic_t max_year0;
 3093     int defaulttype = -1;
 3094 
 3095     check_for_signal();
 3096 
 3097     /* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND.  */
 3098     max_abbr_len = 2 + max_format_len + max_abbrvar_len;
 3099     max_envvar_len = 2 * max_abbr_len + 5 * 9;
 3100 
 3101     startbuf = emalloc(max_abbr_len + 1);
 3102     ab = emalloc(max_abbr_len + 1);
 3103     envvar = emalloc(max_envvar_len + 1);
 3104     INITIALIZE(untiltime);
 3105     INITIALIZE(starttime);
 3106     /*
 3107     ** Now. . .finally. . .generate some useful data!
 3108     */
 3109     timecnt = 0;
 3110     typecnt = 0;
 3111     charcnt = 0;
 3112     prodstic = zonecount == 1;
 3113     /*
 3114     ** Thanks to Earl Chew
 3115     ** for noting the need to unconditionally initialize startttisstd.
 3116     */
 3117     startttisstd = false;
 3118     startttisut = false;
 3119     min_year = max_year = EPOCH_YEAR;
 3120     if (leapseen) {
 3121         updateminmax(leapminyear);
 3122         updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
 3123     }
 3124     for (i = 0; i < zonecount; ++i) {
 3125         struct zone const *zp = &zpfirst[i];
 3126         if (i < zonecount - 1)
 3127             updateminmax(zp->z_untilrule.r_loyear);
 3128         for (j = 0; j < zp->z_nrules; ++j) {
 3129             struct rule *rp = &zp->z_rules[j];
 3130             if (rp->r_lowasnum)
 3131                 updateminmax(rp->r_loyear);
 3132             if (rp->r_hiwasnum)
 3133                 updateminmax(rp->r_hiyear);
 3134             if (rp->r_lowasnum || rp->r_hiwasnum)
 3135                 prodstic = false;
 3136         }
 3137     }
 3138     /*
 3139     ** Generate lots of data if a rule can't cover all future times.
 3140     */
 3141     compat = stringzone(envvar, zpfirst, zonecount);
 3142     version = compat < 2013 ? '2' : '3';
 3143     do_extend = compat < 0;
 3144     if (noise) {
 3145         if (!*envvar)
 3146             warning("%s %s",
 3147                 _("no POSIX environment variable for zone"),
 3148                 zpfirst->z_name);
 3149         else if (compat != 0) {
 3150             /* Circa-COMPAT clients, and earlier clients, might
 3151                not work for this zone when given dates before
 3152                1970 or after 2038.  */
 3153             warning(_("%s: pre-%d clients may mishandle"
 3154                   " distant timestamps"),
 3155                 zpfirst->z_name, compat);
 3156         }
 3157     }
 3158     if (do_extend) {
 3159         /*
 3160         ** Search through a couple of extra years past the obvious
 3161         ** 400, to avoid edge cases.  For example, suppose a non-POSIX
 3162         ** rule applies from 2012 onwards and has transitions in March
 3163         ** and September, plus some one-off transitions in November
 3164         ** 2013.  If zic looked only at the last 400 years, it would
 3165         ** set max_year=2413, with the intent that the 400 years 2014
 3166         ** through 2413 will be repeated.  The last transition listed
 3167         ** in the tzfile would be in 2413-09, less than 400 years
 3168         ** after the last one-off transition in 2013-11.  Two years
 3169         ** might be overkill, but with the kind of edge cases
 3170         ** available we're not sure that one year would suffice.
 3171         */
 3172         enum { years_of_observations = YEARSPERREPEAT + 2 };
 3173 
 3174         if (min_year >= ZIC_MIN + years_of_observations)
 3175             min_year -= years_of_observations;
 3176         else    min_year = ZIC_MIN;
 3177         if (max_year <= ZIC_MAX - years_of_observations)
 3178             max_year += years_of_observations;
 3179         else    max_year = ZIC_MAX;
 3180         /*
 3181         ** Regardless of any of the above,
 3182         ** for a "proDSTic" zone which specifies that its rules
 3183         ** always have and always will be in effect,
 3184         ** we only need one cycle to define the zone.
 3185         */
 3186         if (prodstic) {
 3187             min_year = 1900;
 3188             max_year = min_year + years_of_observations;
 3189         }
 3190     }
 3191     max_year = max(max_year, (redundant_time / (SECSPERDAY * DAYSPERNYEAR)
 3192                   + EPOCH_YEAR + 1));
 3193     max_year0 = max_year;
 3194     if (want_bloat()) {
 3195       /* For the benefit of older systems,
 3196          generate data from 1900 through 2038.  */
 3197       if (min_year > 1900)
 3198         min_year = 1900;
 3199       if (max_year < 2038)
 3200         max_year = 2038;
 3201     }
 3202 
 3203     if (min_time < lo_time || hi_time < max_time)
 3204       unspecifiedtype = addtype(0, "-00", false, false, false);
 3205 
 3206     for (i = 0; i < zonecount; ++i) {
 3207         struct rule *prevrp = NULL;
 3208         /*
 3209         ** A guess that may well be corrected later.
 3210         */
 3211         zic_t save = 0;
 3212         struct zone const *zp = &zpfirst[i];
 3213         bool usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
 3214         bool useuntil = i < (zonecount - 1);
 3215         zic_t stdoff = zp->z_stdoff;
 3216         zic_t startoff = stdoff;
 3217         zic_t prevktime;
 3218         INITIALIZE(prevktime);
 3219         if (useuntil && zp->z_untiltime <= min_time)
 3220             continue;
 3221         eat(zp->z_filenum, zp->z_linenum);
 3222         *startbuf = '\0';
 3223         if (zp->z_nrules == 0) {
 3224             int type;
 3225             save = zp->z_save;
 3226             doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
 3227             type = addtype(oadd(zp->z_stdoff, save),
 3228                 startbuf, zp->z_isdst, startttisstd,
 3229                 startttisut);
 3230             if (usestart) {
 3231                 addtt(starttime, type);
 3232                 usestart = false;
 3233             } else
 3234                 defaulttype = type;
 3235         } else {
 3236           zic_t year;
 3237           for (year = min_year; year <= max_year; ++year) {
 3238             if (useuntil && year > zp->z_untilrule.r_hiyear)
 3239                 break;
 3240             /*
 3241             ** Mark which rules to do in the current year.
 3242             ** For those to do, calculate rpytime(rp, year);
 3243             ** The former TYPE field was also considered here.
 3244             */
 3245             for (j = 0; j < zp->z_nrules; ++j) {
 3246                 zic_t one = 1;
 3247                 zic_t y2038_boundary = one << 31;
 3248                 struct rule *rp = &zp->z_rules[j];
 3249                 eats(zp->z_filenum, zp->z_linenum,
 3250                      rp->r_filenum, rp->r_linenum);
 3251                 rp->r_todo = year >= rp->r_loyear &&
 3252                         year <= rp->r_hiyear;
 3253                 if (rp->r_todo) {
 3254                     rp->r_temp = rpytime(rp, year);
 3255                     rp->r_todo
 3256                       = (rp->r_temp < y2038_boundary
 3257                          || year <= max_year0);
 3258                 }
 3259             }
 3260             for ( ; ; ) {
 3261                 register ptrdiff_t k;
 3262                 register zic_t  jtime, ktime;
 3263                 register zic_t  offset;
 3264                 struct rule *rp;
 3265                 int type;
 3266 
 3267                 INITIALIZE(ktime);
 3268                 if (useuntil) {
 3269                     /*
 3270                     ** Turn untiltime into UT
 3271                     ** assuming the current stdoff and
 3272                     ** save values.
 3273                     */
 3274                     untiltime = zp->z_untiltime;
 3275                     if (!zp->z_untilrule.r_todisut)
 3276                         untiltime = tadd(untiltime,
 3277                                  -stdoff);
 3278                     if (!zp->z_untilrule.r_todisstd)
 3279                         untiltime = tadd(untiltime,
 3280                                  -save);
 3281                 }
 3282                 /*
 3283                 ** Find the rule (of those to do, if any)
 3284                 ** that takes effect earliest in the year.
 3285                 */
 3286                 k = -1;
 3287                 for (j = 0; j < zp->z_nrules; ++j) {
 3288                     struct rule *r = &zp->z_rules[j];
 3289                     if (!r->r_todo)
 3290                         continue;
 3291                     eats(zp->z_filenum, zp->z_linenum,
 3292                          r->r_filenum, r->r_linenum);
 3293                     offset = r->r_todisut ? 0 : stdoff;
 3294                     if (!r->r_todisstd)
 3295                         offset = oadd(offset, save);
 3296                     jtime = r->r_temp;
 3297                     if (jtime == min_time ||
 3298                         jtime == max_time)
 3299                             continue;
 3300                     jtime = tadd(jtime, -offset);
 3301                     if (k < 0 || jtime < ktime) {
 3302                         k = j;
 3303                         ktime = jtime;
 3304                     } else if (jtime == ktime) {
 3305                       char const *dup_rules_msg =
 3306                         _("two rules for same instant");
 3307                       eats(zp->z_filenum, zp->z_linenum,
 3308                            r->r_filenum, r->r_linenum);
 3309                       warning("%s", dup_rules_msg);
 3310                       r = &zp->z_rules[k];
 3311                       eats(zp->z_filenum, zp->z_linenum,
 3312                            r->r_filenum, r->r_linenum);
 3313                       error("%s", dup_rules_msg);
 3314                     }
 3315                 }
 3316                 if (k < 0)
 3317                     break;  /* go on to next year */
 3318                 rp = &zp->z_rules[k];
 3319                 rp->r_todo = false;
 3320                 if (useuntil && ktime >= untiltime) {
 3321                     if (!*startbuf
 3322                         && (oadd(zp->z_stdoff, rp->r_save)
 3323                         == startoff))
 3324                       doabbr(startbuf, zp, rp->r_abbrvar,
 3325                          rp->r_isdst, rp->r_save,
 3326                          false);
 3327                     break;
 3328                 }
 3329                 save = rp->r_save;
 3330                 if (usestart && ktime == starttime)
 3331                     usestart = false;
 3332                 if (usestart) {
 3333                     if (ktime < starttime) {
 3334                         startoff = oadd(zp->z_stdoff,
 3335                                 save);
 3336                         doabbr(startbuf, zp,
 3337                             rp->r_abbrvar,
 3338                             rp->r_isdst,
 3339                             rp->r_save,
 3340                             false);
 3341                         continue;
 3342                     }
 3343                     if (*startbuf == '\0'
 3344                         && startoff == oadd(zp->z_stdoff,
 3345                                 save)) {
 3346                             doabbr(startbuf,
 3347                                 zp,
 3348                                 rp->r_abbrvar,
 3349                                 rp->r_isdst,
 3350                                 rp->r_save,
 3351                                 false);
 3352                     }
 3353                 }
 3354                 eats(zp->z_filenum, zp->z_linenum,
 3355                      rp->r_filenum, rp->r_linenum);
 3356                 doabbr(ab, zp, rp->r_abbrvar,
 3357                        rp->r_isdst, rp->r_save, false);
 3358                 offset = oadd(zp->z_stdoff, rp->r_save);
 3359                 if (!want_bloat() && !useuntil && !do_extend
 3360                     && prevrp && lo_time <= prevktime
 3361                     && redundant_time <= ktime
 3362                     && rp->r_hiyear == ZIC_MAX
 3363                     && prevrp->r_hiyear == ZIC_MAX)
 3364                   break;
 3365                 type = addtype(offset, ab, rp->r_isdst,
 3366                     rp->r_todisstd, rp->r_todisut);
 3367                 if (defaulttype < 0 && !rp->r_isdst)
 3368                   defaulttype = type;
 3369                 if (rp->r_hiyear == ZIC_MAX
 3370                     && ! (0 <= lastatmax
 3371                       && ktime < attypes[lastatmax].at))
 3372                   lastatmax = timecnt;
 3373                 addtt(ktime, type);
 3374                 prevrp = rp;
 3375                 prevktime = ktime;
 3376             }
 3377           }
 3378         }
 3379         if (usestart) {
 3380             bool isdst = startoff != zp->z_stdoff;
 3381             if (*startbuf == '\0' && zp->z_format)
 3382               doabbr(startbuf, zp, disable_percent_s,
 3383                  isdst, save, false);
 3384             eat(zp->z_filenum, zp->z_linenum);
 3385             if (*startbuf == '\0')
 3386 error(_("can't determine time zone abbreviation to use just after until time"));
 3387             else {
 3388               int type = addtype(startoff, startbuf, isdst,
 3389                          startttisstd, startttisut);
 3390               if (defaulttype < 0 && !isdst)
 3391                 defaulttype = type;
 3392               addtt(starttime, type);
 3393             }
 3394         }
 3395         /*
 3396         ** Now we may get to set starttime for the next zone line.
 3397         */
 3398         if (useuntil) {
 3399             startttisstd = zp->z_untilrule.r_todisstd;
 3400             startttisut = zp->z_untilrule.r_todisut;
 3401             starttime = zp->z_untiltime;
 3402             if (!startttisstd)
 3403               starttime = tadd(starttime, -save);
 3404             if (!startttisut)
 3405               starttime = tadd(starttime, -stdoff);
 3406         }
 3407     }
 3408     if (defaulttype < 0)
 3409       defaulttype = 0;
 3410     if (0 <= lastatmax)
 3411       attypes[lastatmax].dontmerge = true;
 3412     if (do_extend) {
 3413         /*
 3414         ** If we're extending the explicitly listed observations
 3415         ** for 400 years because we can't fill the POSIX-TZ field,
 3416         ** check whether we actually ended up explicitly listing
 3417         ** observations through that period.  If there aren't any
 3418         ** near the end of the 400-year period, add a redundant
 3419         ** one at the end of the final year, to make it clear
 3420         ** that we are claiming to have definite knowledge of
 3421         ** the lack of transitions up to that point.
 3422         */
 3423         struct rule xr;
 3424         struct attype *lastat;
 3425         xr.r_month = TM_JANUARY;
 3426         xr.r_dycode = DC_DOM;
 3427         xr.r_dayofmonth = 1;
 3428         xr.r_tod = 0;
 3429         for (lastat = attypes, i = 1; i < timecnt; i++)
 3430             if (attypes[i].at > lastat->at)
 3431                 lastat = &attypes[i];
 3432         if (!lastat || lastat->at < rpytime(&xr, max_year - 1)) {
 3433             addtt(rpytime(&xr, max_year + 1),
 3434                   lastat ? lastat->type : defaulttype);
 3435             attypes[timecnt - 1].dontmerge = true;
 3436         }
 3437     }
 3438     writezone(zpfirst->z_name, envvar, version, defaulttype);
 3439     free(startbuf);
 3440     free(ab);
 3441     free(envvar);
 3442 }
 3443 
 3444 static void
 3445 addtt(zic_t starttime, int type)
 3446 {
 3447     attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
 3448     attypes[timecnt].at = starttime;
 3449     attypes[timecnt].dontmerge = false;
 3450     attypes[timecnt].type = type;
 3451     ++timecnt;
 3452 }
 3453 
 3454 static int
 3455 addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
 3456 {
 3457     register int    i, j;
 3458 
 3459     if (! (-1L - 2147483647L <= utoff && utoff <= 2147483647L)) {
 3460         error(_("UT offset out of range"));
 3461         exit(EXIT_FAILURE);
 3462     }
 3463     if (!want_bloat())
 3464       ttisstd = ttisut = false;
 3465 
 3466     for (j = 0; j < charcnt; ++j)
 3467         if (strcmp(&chars[j], abbr) == 0)
 3468             break;
 3469     if (j == charcnt)
 3470         newabbr(abbr);
 3471     else {
 3472       /* If there's already an entry, return its index.  */
 3473       for (i = 0; i < typecnt; i++)
 3474         if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
 3475         && ttisstd == ttisstds[i] && ttisut == ttisuts[i])
 3476           return i;
 3477     }
 3478     /*
 3479     ** There isn't one; add a new one, unless there are already too
 3480     ** many.
 3481     */
 3482     if (typecnt >= TZ_MAX_TYPES) {
 3483         error(_("too many local time types"));
 3484         exit(EXIT_FAILURE);
 3485     }
 3486     i = typecnt++;
 3487     utoffs[i] = utoff;
 3488     isdsts[i] = isdst;
 3489     ttisstds[i] = ttisstd;
 3490     ttisuts[i] = ttisut;
 3491     desigidx[i] = j;
 3492     return i;
 3493 }
 3494 
 3495 static void
 3496 leapadd(zic_t t, int correction, int rolling)
 3497 {
 3498     register int i;
 3499 
 3500     if (TZ_MAX_LEAPS <= leapcnt) {
 3501         error(_("too many leap seconds"));
 3502         exit(EXIT_FAILURE);
 3503     }
 3504     if (rolling && (lo_time != min_time || hi_time != max_time)) {
 3505       error(_("Rolling leap seconds not supported with -r"));
 3506       exit(EXIT_FAILURE);
 3507     }
 3508     for (i = 0; i < leapcnt; ++i)
 3509         if (t <= trans[i])
 3510             break;
 3511     memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans);
 3512     memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr);
 3513     memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll);
 3514     trans[i] = t;
 3515     corr[i] = correction;
 3516     roll[i] = rolling;
 3517     ++leapcnt;
 3518 }
 3519 
 3520 static void
 3521 adjleap(void)
 3522 {
 3523     register int    i;
 3524     register zic_t  last = 0;
 3525     register zic_t  prevtrans = 0;
 3526 
 3527     /*
 3528     ** propagate leap seconds forward
 3529     */
 3530     for (i = 0; i < leapcnt; ++i) {
 3531         if (trans[i] - prevtrans < 28 * SECSPERDAY) {
 3532           error(_("Leap seconds too close together"));
 3533           exit(EXIT_FAILURE);
 3534         }
 3535         prevtrans = trans[i];
 3536         trans[i] = tadd(trans[i], last);
 3537         last = corr[i] += last;
 3538     }
 3539 
 3540     if (0 <= leapexpires) {
 3541       leapexpires = oadd(leapexpires, last);
 3542       if (! (leapcnt == 0 || (trans[leapcnt - 1] < leapexpires))) {
 3543         error(_("last Leap time does not precede Expires time"));
 3544         exit(EXIT_FAILURE);
 3545       }
 3546     }
 3547 }
 3548 
 3549 /* Is A a space character in the C locale?  */
 3550 static bool
 3551 is_space(char a)
 3552 {
 3553     switch (a) {
 3554       default:
 3555         return false;
 3556       case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
 3557         return true;
 3558     }
 3559 }
 3560 
 3561 /* Is A an alphabetic character in the C locale?  */
 3562 static bool
 3563 is_alpha(char a)
 3564 {
 3565     switch (a) {
 3566       default:
 3567         return false;
 3568       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
 3569       case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
 3570       case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
 3571       case 'V': case 'W': case 'X': case 'Y': case 'Z':
 3572       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
 3573       case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
 3574       case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
 3575       case 'v': case 'w': case 'x': case 'y': case 'z':
 3576         return true;
 3577     }
 3578 }
 3579 
 3580 /* If A is an uppercase character in the C locale, return its lowercase
 3581    counterpart.  Otherwise, return A.  */
 3582 static char
 3583 lowerit(char a)
 3584 {
 3585     switch (a) {
 3586       default: return a;
 3587       case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
 3588       case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
 3589       case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
 3590       case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
 3591       case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
 3592       case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
 3593       case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
 3594       case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
 3595       case 'Y': return 'y'; case 'Z': return 'z';
 3596     }
 3597 }
 3598 
 3599 /* case-insensitive equality */
 3600 static ATTRIBUTE_REPRODUCIBLE bool
 3601 ciequal(register const char *ap, register const char *bp)
 3602 {
 3603     while (lowerit(*ap) == lowerit(*bp++))
 3604         if (*ap++ == '\0')
 3605             return true;
 3606     return false;
 3607 }
 3608 
 3609 static ATTRIBUTE_REPRODUCIBLE bool
 3610 itsabbr(register const char *abbr, register const char *word)
 3611 {
 3612     if (lowerit(*abbr) != lowerit(*word))
 3613         return false;
 3614     ++word;
 3615     while (*++abbr != '\0')
 3616         do {
 3617             if (*word == '\0')
 3618                 return false;
 3619         } while (lowerit(*word++) != lowerit(*abbr));
 3620     return true;
 3621 }
 3622 
 3623 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case.  */
 3624 
 3625 static ATTRIBUTE_REPRODUCIBLE bool
 3626 ciprefix(char const *abbr, char const *word)
 3627 {
 3628   do
 3629     if (!*abbr)
 3630       return true;
 3631   while (lowerit(*abbr++) == lowerit(*word++));
 3632 
 3633   return false;
 3634 }
 3635 
 3636 static const struct lookup *
 3637 byword(const char *word, const struct lookup *table)
 3638 {
 3639     register const struct lookup *  foundlp;
 3640     register const struct lookup *  lp;
 3641 
 3642     if (word == NULL || table == NULL)
 3643         return NULL;
 3644 
 3645     /* If TABLE is LASTS and the word starts with "last" followed
 3646        by a non-'-', skip the "last" and look in WDAY_NAMES instead.
 3647        Warn about any usage of the undocumented prefix "last-".  */
 3648     if (table == lasts && ciprefix("last", word) && word[4]) {
 3649       if (word[4] == '-')
 3650         warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
 3651             word, word + 5);
 3652       else {
 3653         word += 4;
 3654         table = wday_names;
 3655       }
 3656     }
 3657 
 3658     /*
 3659     ** Look for exact match.
 3660     */
 3661     for (lp = table; lp->l_word != NULL; ++lp)
 3662         if (ciequal(word, lp->l_word))
 3663             return lp;
 3664     /*
 3665     ** Look for inexact match.
 3666     */
 3667     foundlp = NULL;
 3668     for (lp = table; lp->l_word != NULL; ++lp)
 3669         if (ciprefix(word, lp->l_word)) {
 3670             if (foundlp == NULL)
 3671                 foundlp = lp;
 3672             else    return NULL;    /* multiple inexact matches */
 3673         }
 3674 
 3675     if (foundlp && noise) {
 3676       /* Warn about any backward-compatibility issue with pre-2017c zic.  */
 3677       bool pre_2017c_match = false;
 3678       for (lp = table; lp->l_word; lp++)
 3679         if (itsabbr(word, lp->l_word)) {
 3680           if (pre_2017c_match) {
 3681         warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
 3682         break;
 3683           }
 3684           pre_2017c_match = true;
 3685         }
 3686     }
 3687 
 3688     return foundlp;
 3689 }
 3690 
 3691 static int
 3692 getfields(char *cp, char **array, int arrayelts)
 3693 {
 3694     register char *     dp;
 3695     register int        nsubs;
 3696 
 3697     nsubs = 0;
 3698     for ( ; ; ) {
 3699         char *dstart;
 3700         while (is_space(*cp))
 3701                 ++cp;
 3702         if (*cp == '\0' || *cp == '#')
 3703             break;
 3704         dstart = dp = cp;
 3705         do {
 3706             if ((*dp = *cp++) != '"')
 3707                 ++dp;
 3708             else while ((*dp = *cp++) != '"')
 3709                 if (*dp != '\0')
 3710                     ++dp;
 3711                 else {
 3712                   error(_("Odd number of quotation marks"));
 3713                   exit(EXIT_FAILURE);
 3714                 }
 3715         } while (*cp && *cp != '#' && !is_space(*cp));
 3716         if (is_space(*cp))
 3717             ++cp;
 3718         *dp = '\0';
 3719         if (nsubs == arrayelts) {
 3720           error(_("Too many input fields"));
 3721           exit(EXIT_FAILURE);
 3722         }
 3723         array[nsubs++] = dstart + (*dstart == '-' && dp == dstart + 1);
 3724     }
 3725     return nsubs;
 3726 }
 3727 
 3728 static ATTRIBUTE_NORETURN void
 3729 time_overflow(void)
 3730 {
 3731   error(_("time overflow"));
 3732   exit(EXIT_FAILURE);
 3733 }
 3734 
 3735 static ATTRIBUTE_REPRODUCIBLE zic_t
 3736 oadd(zic_t t1, zic_t t2)
 3737 {
 3738 #ifdef ckd_add
 3739   zic_t sum;
 3740   if (!ckd_add(&sum, t1, t2))
 3741     return sum;
 3742 #else
 3743   if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1)
 3744     return t1 + t2;
 3745 #endif
 3746   time_overflow();
 3747 }
 3748 
 3749 static ATTRIBUTE_REPRODUCIBLE zic_t
 3750 tadd(zic_t t1, zic_t t2)
 3751 {
 3752 #ifdef ckd_add
 3753   zic_t sum;
 3754   if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time)
 3755     return sum;
 3756 #else
 3757   if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1)
 3758     return t1 + t2;
 3759 #endif
 3760   if (t1 == min_time || t1 == max_time)
 3761     return t1;
 3762   time_overflow();
 3763 }
 3764 
 3765 /*
 3766 ** Given a rule, and a year, compute the date (in seconds since January 1,
 3767 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
 3768 */
 3769 
 3770 static zic_t
 3771 rpytime(const struct rule *rp, zic_t wantedy)
 3772 {
 3773     register int    m, i;
 3774     register zic_t  dayoff;         /* with a nod to Margaret O. */
 3775     register zic_t  t, y;
 3776     int yrem;
 3777 
 3778     if (wantedy == ZIC_MIN)
 3779         return min_time;
 3780     if (wantedy == ZIC_MAX)
 3781         return max_time;
 3782     m = TM_JANUARY;
 3783     y = EPOCH_YEAR;
 3784 
 3785     /* dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT,
 3786        sans overflow.  */
 3787     yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT;
 3788     dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT
 3789            + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0))
 3790           * DAYSPERREPEAT);
 3791     /* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow.  */
 3792     wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT;
 3793 
 3794     while (wantedy != y) {
 3795         i = len_years[isleap(y)];
 3796         dayoff = oadd(dayoff, i);
 3797         y++;
 3798     }
 3799     while (m != rp->r_month) {
 3800         i = len_months[isleap(y)][m];
 3801         dayoff = oadd(dayoff, i);
 3802         ++m;
 3803     }
 3804     i = rp->r_dayofmonth;
 3805     if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
 3806         if (rp->r_dycode == DC_DOWLEQ)
 3807             --i;
 3808         else {
 3809             error(_("use of 2/29 in non leap-year"));
 3810             exit(EXIT_FAILURE);
 3811         }
 3812     }
 3813     --i;
 3814     dayoff = oadd(dayoff, i);
 3815     if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
 3816         /*
 3817         ** Don't trust mod of negative numbers.
 3818         */
 3819         zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK)
 3820                   % DAYSPERWEEK);
 3821         while (wday != rp->r_wday)
 3822             if (rp->r_dycode == DC_DOWGEQ) {
 3823                 dayoff = oadd(dayoff, 1);
 3824                 if (++wday >= DAYSPERWEEK)
 3825                     wday = 0;
 3826                 ++i;
 3827             } else {
 3828                 dayoff = oadd(dayoff, -1);
 3829                 if (--wday < 0)
 3830                     wday = DAYSPERWEEK - 1;
 3831                 --i;
 3832             }
 3833         if (i < 0 || i >= len_months[isleap(y)][m]) {
 3834             if (noise)
 3835                 warning(_("rule goes past start/end of month; \
 3836 will not work with pre-2004 versions of zic"));
 3837         }
 3838     }
 3839     if (dayoff < min_time / SECSPERDAY)
 3840         return min_time;
 3841     if (dayoff > max_time / SECSPERDAY)
 3842         return max_time;
 3843     t = (zic_t) dayoff * SECSPERDAY;
 3844     return tadd(t, rp->r_tod);
 3845 }
 3846 
 3847 static void
 3848 newabbr(const char *string)
 3849 {
 3850     register int    i;
 3851 
 3852     if (strcmp(string, GRANDPARENTED) != 0) {
 3853         register const char *   cp;
 3854         const char *        mp;
 3855 
 3856         cp = string;
 3857         mp = NULL;
 3858         while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
 3859                || *cp == '-' || *cp == '+')
 3860                 ++cp;
 3861         if (noise && cp - string < 3)
 3862           mp = _("time zone abbreviation has fewer than 3 characters");
 3863         if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
 3864           mp = _("time zone abbreviation has too many characters");
 3865         if (*cp != '\0')
 3866 mp = _("time zone abbreviation differs from POSIX standard");
 3867         if (mp != NULL)
 3868             warning("%s (%s)", mp, string);
 3869     }
 3870     i = strlen(string) + 1;
 3871     if (charcnt + i > TZ_MAX_CHARS) {
 3872         error(_("too many, or too long, time zone abbreviations"));
 3873         exit(EXIT_FAILURE);
 3874     }
 3875     strcpy(&chars[charcnt], string);
 3876     charcnt += i;
 3877 }
 3878 
 3879 /* Ensure that the directories of ARGNAME exist, by making any missing
 3880    ones.  If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
 3881    do it for ARGNAME too.  Exit with failure if there is trouble.
 3882    Do not consider an existing file to be trouble.  */
 3883 static void
 3884 mkdirs(char const *argname, bool ancestors)
 3885 {
 3886     char *name = estrdup(argname);
 3887     char *cp = name;
 3888 
 3889     /* On MS-Windows systems, do not worry about drive letters or
 3890        backslashes, as this should suffice in practice.  Time zone
 3891        names do not use drive letters and backslashes.  If the -d
 3892        option of zic does not name an already-existing directory,
 3893        it can use slashes to separate the already-existing
 3894        ancestor prefix from the to-be-created subdirectories.  */
 3895 
 3896     /* Do not mkdir a root directory, as it must exist.  */
 3897     while (*cp == '/')
 3898       cp++;
 3899 
 3900     while (cp && ((cp = strchr(cp, '/')) || !ancestors)) {
 3901         if (cp)
 3902           *cp = '\0';
 3903         /*
 3904         ** Try to create it.  It's OK if creation fails because
 3905         ** the directory already exists, perhaps because some
 3906         ** other process just created it.  For simplicity do
 3907         ** not check first whether it already exists, as that
 3908         ** is checked anyway if the mkdir fails.
 3909         */
 3910         if (mkdir(name, MKDIR_UMASK) != 0) {
 3911             /* Do not report an error if err == EEXIST, because
 3912                some other process might have made the directory
 3913                in the meantime.  Likewise for ENOSYS, because
 3914                Solaris 10 mkdir fails with ENOSYS if the
 3915                directory is an automounted mount point.
 3916                Likewise for EACCES, since mkdir can fail
 3917                with EACCES merely because the parent directory
 3918                is unwritable.  Likewise for most other error
 3919                numbers.  */
 3920             int err = errno;
 3921             if (err == ELOOP || err == ENAMETOOLONG
 3922                 || err == ENOENT || err == ENOTDIR) {
 3923                 error(_("%s: Can't create directory %s: %s"),
 3924                       progname, name, strerror(err));
 3925                 exit(EXIT_FAILURE);
 3926             }
 3927         }
 3928         if (cp)
 3929           *cp++ = '/';
 3930     }
 3931     free(name);
 3932 }