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

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

Generated by: LCOV version 1.16