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

Generated by: LCOV version 1.13