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

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

Generated by: LCOV version 2.0-1