LCOV - code coverage report
Current view: top level - src/timezone - zic.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 60.0 % 1865 1119
Test Date: 2026-03-13 00:15:08 Functions: 79.5 % 73 58
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1