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

Generated by: LCOV version 1.14