LCOV - code coverage report
Current view: top level - src/timezone - zic.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 2184 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 73 0
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            0 : size_product(size_t nitems, size_t itemsize)
     422              : {
     423            0 :         if (SIZE_MAX / itemsize < nitems)
     424            0 :                 memory_exhausted(_("size overflow"));
     425            0 :         return nitems * itemsize;
     426              : }
     427              : 
     428              : static size_t
     429            0 : align_to(size_t size, size_t alignment)
     430              : {
     431            0 :         size_t          aligned_size = size + alignment - 1;
     432              : 
     433            0 :         aligned_size -= aligned_size % alignment;
     434            0 :         if (aligned_size < size)
     435            0 :                 memory_exhausted(_("alignment overflow"));
     436            0 :         return aligned_size;
     437            0 : }
     438              : 
     439              : static void *
     440            0 : memcheck(void *ptr)
     441              : {
     442            0 :         if (ptr == NULL)
     443            0 :                 memory_exhausted(strerror(errno));
     444            0 :         return ptr;
     445              : }
     446              : 
     447              : static void *
     448            0 : emalloc(size_t size)
     449              : {
     450            0 :         return memcheck(malloc(size));
     451              : }
     452              : 
     453              : static void *
     454            0 : erealloc(void *ptr, size_t size)
     455              : {
     456            0 :         return memcheck(realloc(ptr, size));
     457              : }
     458              : 
     459              : static char *
     460            0 : ecpyalloc(char const *str)
     461              : {
     462            0 :         return memcheck(strdup(str));
     463              : }
     464              : 
     465              : static void *
     466            0 : growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
     467              : {
     468            0 :         if (nitems < *nitems_alloc)
     469            0 :                 return ptr;
     470              :         else
     471              :         {
     472            0 :                 ptrdiff_t       nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
     473            0 :                 ptrdiff_t       amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
     474              : 
     475            0 :                 if ((amax - 1) / 3 * 2 < *nitems_alloc)
     476            0 :                         memory_exhausted(_("integer overflow"));
     477            0 :                 *nitems_alloc += (*nitems_alloc >> 1) + 1;
     478            0 :                 return erealloc(ptr, size_product(*nitems_alloc, itemsize));
     479            0 :         }
     480            0 : }
     481              : 
     482              : /*
     483              :  * Error handling.
     484              :  */
     485              : 
     486              : static void
     487            0 : eats(char const *name, lineno_t num, char const *rname, lineno_t rnum)
     488              : {
     489            0 :         filename = name;
     490            0 :         linenum = num;
     491            0 :         rfilename = rname;
     492            0 :         rlinenum = rnum;
     493            0 : }
     494              : 
     495              : static void
     496            0 : eat(char const *name, lineno_t num)
     497              : {
     498            0 :         eats(name, num, NULL, -1);
     499            0 : }
     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            0 :                                 rfilename, rlinenum);
     514            0 :         fprintf(stderr, "\n");
     515            0 : }
     516              : 
     517              : static void
     518            0 : error(const char *const string,...)
     519              : {
     520            0 :         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            0 :         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            0 : close_file(FILE *stream, char const *dir, char const *name)
     542              : {
     543            0 :         char const *e = (ferror(stream) ? _("I/O error")
     544            0 :                                          : fclose(stream) != 0 ? strerror(errno) : NULL);
     545              : 
     546            0 :         if (e)
     547              :         {
     548            0 :                 fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
     549            0 :                                 dir ? dir : "", dir ? "/" : "",
     550            0 :                                 name ? name : "", name ? ": " : "",
     551            0 :                                 e);
     552            0 :                 exit(EXIT_FAILURE);
     553              :         }
     554            0 : }
     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            0 :                         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            0 : change_directory(char const *dir)
     577              : {
     578            0 :         if (chdir(dir) != 0)
     579              :         {
     580            0 :                 int                     chdir_errno = errno;
     581              : 
     582            0 :                 if (chdir_errno == ENOENT)
     583              :                 {
     584            0 :                         mkdirs(dir, false);
     585            0 :                         chdir_errno = chdir(dir) == 0 ? 0 : errno;
     586            0 :                 }
     587            0 :                 if (chdir_errno != 0)
     588              :                 {
     589            0 :                         fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
     590            0 :                                         progname, dir, strerror(chdir_errno));
     591            0 :                         exit(EXIT_FAILURE);
     592              :                 }
     593            0 :         }
     594            0 : }
     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            0 :         }
     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            0 :         }
     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            0 : }
     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            0 : want_bloat(void)
     659              : {
     660            0 :         return 0 <= bloat;
     661              : }
     662              : 
     663              : #ifndef ZIC_BLOAT_DEFAULT
     664              : #define ZIC_BLOAT_DEFAULT "slim"
     665              : #endif
     666              : 
     667              : int
     668            0 : main(int argc, char **argv)
     669              : {
     670            0 :         int                     c,
     671              :                                 k;
     672            0 :         ptrdiff_t       i,
     673              :                                 j;
     674            0 :         bool            timerange_given = false;
     675              : 
     676              : #ifndef WIN32
     677            0 :         umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
     678              : #endif
     679            0 :         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            0 :         for (k = 1; k < argc; k++)
     687            0 :                 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            0 :                 else if (strcmp(argv[k], "--help") == 0)
     694              :                 {
     695            0 :                         usage(stdout, EXIT_SUCCESS);
     696              :                 }
     697            0 :         while ((c = getopt(argc, argv, "b:d:l:L:p:Pr:st:vy:")) != EOF && c != -1)
     698            0 :                 switch (c)
     699              :                 {
     700              :                         default:
     701            0 :                                 usage(stderr, EXIT_FAILURE);
     702              :                         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            0 :                                 }
     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            0 :                                 }
     715              :                                 else
     716            0 :                                         error(_("invalid option: -b '%s'"), optarg);
     717            0 :                                 break;
     718              :                         case 'd':
     719            0 :                                 if (directory == NULL)
     720            0 :                                         directory = strdup(optarg);
     721              :                                 else
     722              :                                 {
     723            0 :                                         fprintf(stderr,
     724              :                                                         _("%s: More than one -d option specified\n"),
     725            0 :                                                         progname);
     726            0 :                                         return EXIT_FAILURE;
     727              :                                 }
     728            0 :                                 break;
     729              :                         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            0 :                                                         progname);
     737            0 :                                         return EXIT_FAILURE;
     738              :                                 }
     739            0 :                                 break;
     740              :                         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            0 :                                                         progname);
     748            0 :                                         return EXIT_FAILURE;
     749              :                                 }
     750            0 :                                 break;
     751              :                         case 't':
     752            0 :                                 if (tzdefault != NULL)
     753              :                                 {
     754            0 :                                         fprintf(stderr,
     755              :                                                         _("%s: More than one -t option"
     756              :                                                           " specified\n"),
     757            0 :                                                         progname);
     758            0 :                                         return EXIT_FAILURE;
     759              :                                 }
     760            0 :                                 tzdefault = optarg;
     761            0 :                                 break;
     762              :                         case 'y':
     763            0 :                                 warning(_("-y ignored"));
     764            0 :                                 break;
     765              :                         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            0 :                                                         progname);
     773            0 :                                         return EXIT_FAILURE;
     774              :                                 }
     775            0 :                                 break;
     776              :                         case 'v':
     777            0 :                                 noise = true;
     778            0 :                                 break;
     779              :                         case 'P':
     780            0 :                                 print_abbrevs = true;
     781            0 :                                 print_cutoff = time(NULL);
     782            0 :                                 break;
     783              :                         case 'r':
     784            0 :                                 if (timerange_given)
     785              :                                 {
     786            0 :                                         fprintf(stderr,
     787              :                                                         _("%s: More than one -r option specified\n"),
     788            0 :                                                         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            0 :                                                         progname, optarg);
     796            0 :                                         return EXIT_FAILURE;
     797              :                                 }
     798            0 :                                 timerange_given = true;
     799            0 :                                 break;
     800              :                         case 's':
     801            0 :                                 warning(_("-s ignored"));
     802            0 :                                 break;
     803              :                 }
     804            0 :         if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
     805            0 :                 usage(stderr, EXIT_FAILURE);    /* usage message by request */
     806            0 :         if (bloat == 0)
     807              :         {
     808              :                 static char const bloat_default[] = ZIC_BLOAT_DEFAULT;
     809              : 
     810              :                 if (strcmp(bloat_default, "slim") == 0)
     811            0 :                         bloat = -1;
     812              :                 else if (strcmp(bloat_default, "fat") == 0)
     813              :                         bloat = 1;
     814              :                 else
     815              :                         abort();                        /* Configuration error.  */
     816            0 :         }
     817            0 :         if (directory == NULL)
     818            0 :                 directory = "data";
     819            0 :         if (tzdefault == NULL)
     820            0 :                 tzdefault = TZDEFAULT;
     821              : 
     822            0 :         if (optind < argc && leapsec != NULL)
     823              :         {
     824            0 :                 infile(leapsec);
     825            0 :                 adjleap();
     826            0 :         }
     827              : 
     828            0 :         for (k = optind; k < argc; k++)
     829            0 :                 infile(argv[k]);
     830            0 :         if (errors)
     831            0 :                 return EXIT_FAILURE;
     832            0 :         associate();
     833            0 :         change_directory(directory);
     834            0 :         for (i = 0; i < nzones; i = j)
     835              :         {
     836              :                 /*
     837              :                  * Find the next non-continuation zone entry.
     838              :                  */
     839            0 :                 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
     840            0 :                         continue;
     841            0 :                 outzone(&zones[i], j - i);
     842            0 :         }
     843              : 
     844              :         /*
     845              :          * Make links.
     846              :          */
     847            0 :         for (i = 0; i < nlinks; ++i)
     848              :         {
     849            0 :                 eat(links[i].l_filename, links[i].l_linenum);
     850            0 :                 dolink(links[i].l_target, links[i].l_linkname, false);
     851            0 :                 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            0 :         }
     857            0 :         if (lcltime != NULL)
     858              :         {
     859            0 :                 eat(_("command line"), 1);
     860            0 :                 dolink(lcltime, tzdefault, true);
     861            0 :         }
     862            0 :         if (psxrules != NULL)
     863              :         {
     864            0 :                 eat(_("command line"), 1);
     865            0 :                 dolink(psxrules, TZDEFRULES, true);
     866            0 :         }
     867            0 :         if (warnings && (ferror(stderr) || fclose(stderr) != 0))
     868            0 :                 return EXIT_FAILURE;
     869            0 :         return errors ? EXIT_FAILURE : EXIT_SUCCESS;
     870            0 : }
     871              : 
     872              : static bool
     873            0 : componentcheck(char const *name, char const *component,
     874              :                            char const *component_end)
     875              : {
     876              :         enum
     877              :         {
     878              :         component_len_max = 14};
     879            0 :         ptrdiff_t       component_len = component_end - component;
     880              : 
     881            0 :         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            0 :                                   name);
     892            0 :                 return false;
     893              :         }
     894            0 :         if (0 < component_len && component_len <= 2
     895            0 :                 && component[0] == '.' && component_end[-1] == '.')
     896              :         {
     897            0 :                 int                     len = component_len;
     898              : 
     899            0 :                 error(_("file name '%s' contains '%.*s' component"),
     900            0 :                           name, len, component);
     901            0 :                 return false;
     902            0 :         }
     903            0 :         if (noise)
     904              :         {
     905            0 :                 if (0 < component_len && component[0] == '-')
     906            0 :                         warning(_("file name '%s' component contains leading '-'"),
     907            0 :                                         name);
     908            0 :                 if (component_len_max < component_len)
     909            0 :                         warning(_("file name '%s' contains overlength component"
     910              :                                           " '%.*s...'"),
     911            0 :                                         name, component_len_max, component);
     912            0 :         }
     913            0 :         return true;
     914            0 : }
     915              : 
     916              : static bool
     917            0 : namecheck(const char *name)
     918              : {
     919            0 :         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            0 :         char const *component = name;
     935              : 
     936            0 :         for (cp = name; *cp; cp++)
     937              :         {
     938            0 :                 unsigned char c = *cp;
     939              : 
     940            0 :                 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            0 :                                         name, c);
     946            0 :                 }
     947            0 :                 if (c == '/')
     948              :                 {
     949            0 :                         if (!componentcheck(name, component, cp))
     950            0 :                                 return false;
     951            0 :                         component = cp + 1;
     952            0 :                 }
     953            0 :         }
     954            0 :         return componentcheck(name, component, cp);
     955            0 : }
     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            0 :         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            0 :         }
     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            0 :         }
    1003            0 :         return result;
    1004            0 : }
    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            0 : hardlinkerr(char const *target, char const *linkname)
    1011              : {
    1012            0 :         int                     r = linkat(AT_FDCWD, target, AT_FDCWD, linkname, AT_SYMLINK_FOLLOW);
    1013              : 
    1014            0 :         return r == 0 ? 0 : errno;
    1015            0 : }
    1016              : 
    1017              : static void
    1018            0 : dolink(char const *target, char const *linkname, bool staysymlink)
    1019              : {
    1020            0 :         bool            remove_only = strcmp(target, "-") == 0;
    1021            0 :         bool            linkdirs_made = false;
    1022            0 :         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            0 :         if (!remove_only && itsdir(target))
    1029              :         {
    1030            0 :                 fprintf(stderr, _("%s: linking target %s/%s failed: %s\n"),
    1031            0 :                                 progname, directory, target, strerror(EPERM));
    1032            0 :                 exit(EXIT_FAILURE);
    1033              :         }
    1034            0 :         if (staysymlink)
    1035            0 :                 staysymlink = itssymlink(linkname);
    1036            0 :         if (remove(linkname) == 0)
    1037            0 :                 linkdirs_made = true;
    1038            0 :         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            0 :                                 progname, directory, linkname, e);
    1044            0 :                 exit(EXIT_FAILURE);
    1045              :         }
    1046            0 :         if (remove_only)
    1047            0 :                 return;
    1048            0 :         link_errno = staysymlink ? ENOTSUP : hardlinkerr(target, linkname);
    1049            0 :         if (link_errno == ENOENT && !linkdirs_made)
    1050              :         {
    1051            0 :                 mkdirs(linkname, true);
    1052            0 :                 linkdirs_made = true;
    1053            0 :                 link_errno = hardlinkerr(target, linkname);
    1054            0 :         }
    1055            0 :         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            0 :                 }
    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            0 :                                                 strerror(link_errno));
    1076            0 :                 }
    1077              :                 else
    1078              : #endif                                                  /* HAVE_SYMLINK */
    1079              :                 {
    1080            0 :                         FILE       *fp,
    1081              :                                            *tp;
    1082            0 :                         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            0 :                                                 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            0 :                                                 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            0 :                                                 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            0 :                                                 strerror(symlink_errno));
    1113              : #endif
    1114            0 :                 }
    1115            0 :         }
    1116            0 : }
    1117              : 
    1118              : /* Return true if NAME is a directory.  */
    1119              : static bool
    1120            0 : itsdir(char const *name)
    1121              : {
    1122            0 :         struct stat st;
    1123            0 :         int                     res = stat(name, &st);
    1124              : #ifdef S_ISDIR
    1125            0 :         if (res == 0)
    1126            0 :                 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            0 :                 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            0 :         }
    1140            0 :         return false;
    1141            0 : }
    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            0 :         char            c;
    1149              : 
    1150            0 :         return 0 <= readlink(name, &c, 1);
    1151              : #else
    1152              :         return false;
    1153              : #endif
    1154            0 : }
    1155              : 
    1156              : /*
    1157              :  * Associate sets of rules with zones.
    1158              :  */
    1159              : 
    1160              : /*
    1161              :  * Sort by rule name.
    1162              :  */
    1163              : 
    1164              : static int
    1165            0 : rcomp(const void *cp1, const void *cp2)
    1166              : {
    1167            0 :         return strcmp(((const struct rule *) cp1)->r_name,
    1168            0 :                                   ((const struct rule *) cp2)->r_name);
    1169              : }
    1170              : 
    1171              : static void
    1172            0 : associate(void)
    1173              : {
    1174            0 :         struct zone *zp;
    1175            0 :         struct rule *rp;
    1176            0 :         ptrdiff_t       i,
    1177              :                                 j,
    1178              :                                 base,
    1179              :                                 out;
    1180              : 
    1181            0 :         if (nrules != 0)
    1182              :         {
    1183            0 :                 qsort(rules, nrules, sizeof *rules, rcomp);
    1184            0 :                 for (i = 0; i < nrules - 1; ++i)
    1185              :                 {
    1186            0 :                         if (strcmp(rules[i].r_name,
    1187            0 :                                            rules[i + 1].r_name) != 0)
    1188            0 :                                 continue;
    1189            0 :                         if (strcmp(rules[i].r_filename,
    1190            0 :                                            rules[i + 1].r_filename) == 0)
    1191            0 :                                 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            0 :                 }
    1211            0 :         }
    1212            0 :         for (i = 0; i < nzones; ++i)
    1213              :         {
    1214            0 :                 zp = &zones[i];
    1215            0 :                 zp->z_rules = NULL;
    1216            0 :                 zp->z_nrules = 0;
    1217            0 :         }
    1218            0 :         for (base = 0; base < nrules; base = out)
    1219              :         {
    1220            0 :                 rp = &rules[base];
    1221            0 :                 for (out = base + 1; out < nrules; ++out)
    1222            0 :                         if (strcmp(rp->r_name, rules[out].r_name) != 0)
    1223            0 :                                 break;
    1224            0 :                 for (i = 0; i < nzones; ++i)
    1225              :                 {
    1226            0 :                         zp = &zones[i];
    1227            0 :                         if (strcmp(zp->z_rule, rp->r_name) != 0)
    1228            0 :                                 continue;
    1229            0 :                         zp->z_rules = rp;
    1230            0 :                         zp->z_nrules = out - base;
    1231            0 :                 }
    1232            0 :         }
    1233            0 :         for (i = 0; i < nzones; ++i)
    1234              :         {
    1235            0 :                 zp = &zones[i];
    1236            0 :                 if (zp->z_nrules == 0)
    1237              :                 {
    1238              :                         /*
    1239              :                          * Maybe we have a local standard time offset.
    1240              :                          */
    1241            0 :                         eat(zp->z_filename, zp->z_linenum);
    1242            0 :                         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            0 :                         if (zp->z_format_specifier == 's')
    1249            0 :                                 error("%s", _("%s in ruleless zone"));
    1250            0 :                 }
    1251            0 :         }
    1252            0 :         if (errors)
    1253            0 :                 exit(EXIT_FAILURE);
    1254            0 : }
    1255              : 
    1256              : static void
    1257            0 : infile(const char *name)
    1258              : {
    1259            0 :         FILE       *fp;
    1260            0 :         char      **fields;
    1261            0 :         char       *cp;
    1262            0 :         const struct lookup *lp;
    1263            0 :         int                     nfields;
    1264            0 :         bool            wantcont;
    1265            0 :         lineno_t        num;
    1266            0 :         char            buf[BUFSIZ];
    1267              : 
    1268            0 :         if (strcmp(name, "-") == 0)
    1269              :         {
    1270            0 :                 name = _("standard input");
    1271            0 :                 fp = stdin;
    1272            0 :         }
    1273            0 :         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            0 :                                 progname, name, e);
    1279            0 :                 exit(EXIT_FAILURE);
    1280              :         }
    1281            0 :         wantcont = false;
    1282            0 :         for (num = 1;; ++num)
    1283              :         {
    1284            0 :                 eat(name, num);
    1285            0 :                 if (fgets(buf, sizeof buf, fp) != buf)
    1286            0 :                         break;
    1287            0 :                 cp = strchr(buf, '\n');
    1288            0 :                 if (cp == NULL)
    1289              :                 {
    1290            0 :                         error(_("line too long"));
    1291            0 :                         exit(EXIT_FAILURE);
    1292              :                 }
    1293            0 :                 *cp = '\0';
    1294            0 :                 fields = getfields(buf);
    1295            0 :                 nfields = 0;
    1296            0 :                 while (fields[nfields] != NULL)
    1297              :                 {
    1298              :                         static char nada;
    1299              : 
    1300            0 :                         if (strcmp(fields[nfields], "-") == 0)
    1301            0 :                                 fields[nfields] = &nada;
    1302            0 :                         ++nfields;
    1303              :                 }
    1304            0 :                 if (nfields == 0)
    1305              :                 {
    1306            0 :                         if (name == leapsec && *buf == '#')
    1307            0 :                                 sscanf(buf, "#expires %" SCNdZIC, &comment_leapexpires);
    1308            0 :                 }
    1309            0 :                 else if (wantcont)
    1310              :                 {
    1311            0 :                         wantcont = inzcont(fields, nfields);
    1312            0 :                 }
    1313              :                 else
    1314              :                 {
    1315            0 :                         struct lookup const *line_codes
    1316            0 :                         = name == leapsec ? leap_line_codes : zi_line_codes;
    1317              : 
    1318            0 :                         lp = byword(fields[0], line_codes);
    1319            0 :                         if (lp == NULL)
    1320            0 :                                 error(_("input line of unknown type"));
    1321              :                         else
    1322            0 :                                 switch (lp->l_value)
    1323              :                                 {
    1324              :                                         case LC_RULE:
    1325            0 :                                                 inrule(fields, nfields);
    1326            0 :                                                 wantcont = false;
    1327            0 :                                                 break;
    1328              :                                         case LC_ZONE:
    1329            0 :                                                 wantcont = inzone(fields, nfields);
    1330            0 :                                                 break;
    1331              :                                         case LC_LINK:
    1332            0 :                                                 inlink(fields, nfields);
    1333            0 :                                                 wantcont = false;
    1334            0 :                                                 break;
    1335              :                                         case LC_LEAP:
    1336            0 :                                                 inleap(fields, nfields);
    1337            0 :                                                 wantcont = false;
    1338            0 :                                                 break;
    1339              :                                         case LC_EXPIRES:
    1340            0 :                                                 inexpires(fields, nfields);
    1341            0 :                                                 wantcont = false;
    1342            0 :                                                 break;
    1343              :                                         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            0 :                 }
    1350            0 :                 free(fields);
    1351            0 :         }
    1352            0 :         close_file(fp, NULL, filename);
    1353            0 :         if (wantcont)
    1354            0 :                 error(_("expected continuation line not found"));
    1355            0 : }
    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            0 : gethms(char const *string, char const *errstring)
    1367              : {
    1368            0 :         zic_t           hh;
    1369            0 :         int                     sign,
    1370            0 :                                 mm = 0,
    1371            0 :                                 ss = 0;
    1372            0 :         char            hhx,
    1373              :                                 mmx,
    1374              :                                 ssx,
    1375            0 :                                 xr = '0',
    1376              :                                 xs;
    1377            0 :         int                     tenths = 0;
    1378            0 :         bool            ok = true;
    1379              : 
    1380            0 :         if (string == NULL || *string == '\0')
    1381            0 :                 return 0;
    1382            0 :         if (*string == '-')
    1383              :         {
    1384            0 :                 sign = -1;
    1385            0 :                 ++string;
    1386            0 :         }
    1387              :         else
    1388            0 :                 sign = 1;
    1389            0 :         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              :                 default:
    1394            0 :                         ok = false;
    1395            0 :                         break;
    1396              :                 case 8:
    1397            0 :                         ok = '0' <= xr && xr <= '9';
    1398              :                         /* fallthrough */
    1399              :                 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            0 :                         ok &= mmx == ':';
    1407              :                         /* fallthrough */
    1408              :                 case 3:
    1409            0 :                         ok &= hhx == ':';
    1410              :                         /* fallthrough */
    1411              :                 case 1:
    1412              :                         break;
    1413              :         }
    1414            0 :         if (!ok)
    1415              :         {
    1416            0 :                 error("%s", errstring);
    1417            0 :                 return 0;
    1418              :         }
    1419            0 :         if (hh < 0 ||
    1420            0 :                 mm < 0 || mm >= MINSPERHOUR ||
    1421            0 :                 ss < 0 || ss > SECSPERMIN)
    1422              :         {
    1423            0 :                 error("%s", errstring);
    1424            0 :                 return 0;
    1425              :         }
    1426            0 :         if (ZIC_MAX / SECSPERHOUR < hh)
    1427              :         {
    1428            0 :                 error(_("time overflow"));
    1429            0 :                 return 0;
    1430              :         }
    1431            0 :         ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths;    /* Round to even.  */
    1432            0 :         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            0 :         return oadd(sign * hh * SECSPERHOUR,
    1436            0 :                                 sign * (mm * SECSPERMIN + ss));
    1437            0 : }
    1438              : 
    1439              : static zic_t
    1440            0 : getsave(char *field, bool *isdst)
    1441              : {
    1442            0 :         int                     dst = -1;
    1443            0 :         zic_t           save;
    1444            0 :         size_t          fieldlen = strlen(field);
    1445              : 
    1446            0 :         if (fieldlen != 0)
    1447              :         {
    1448            0 :                 char       *ep = field + fieldlen - 1;
    1449              : 
    1450            0 :                 switch (*ep)
    1451              :                 {
    1452              :                         case 'd':
    1453            0 :                                 dst = 1;
    1454            0 :                                 *ep = '\0';
    1455            0 :                                 break;
    1456              :                         case 's':
    1457            0 :                                 dst = 0;
    1458            0 :                                 *ep = '\0';
    1459            0 :                                 break;
    1460              :                 }
    1461            0 :         }
    1462            0 :         save = gethms(field, _("invalid saved time"));
    1463            0 :         *isdst = dst < 0 ? save != 0 : dst;
    1464            0 :         return save;
    1465            0 : }
    1466              : 
    1467              : static void
    1468            0 : inrule(char **fields, int nfields)
    1469              : {
    1470              :         static struct rule r;
    1471              : 
    1472            0 :         if (nfields != RULE_FIELDS)
    1473              :         {
    1474            0 :                 error(_("wrong number of fields on Rule line"));
    1475            0 :                 return;
    1476              :         }
    1477            0 :         switch (*fields[RF_NAME])
    1478              :         {
    1479              :                 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            0 :         r.r_filename = filename;
    1502            0 :         r.r_linenum = linenum;
    1503            0 :         r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
    1504            0 :         rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
    1505            0 :                         fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
    1506            0 :         r.r_name = ecpyalloc(fields[RF_NAME]);
    1507            0 :         r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
    1508            0 :         if (max_abbrvar_len < strlen(r.r_abbrvar))
    1509            0 :                 max_abbrvar_len = strlen(r.r_abbrvar);
    1510            0 :         rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
    1511            0 :         rules[nrules++] = r;
    1512            0 : }
    1513              : 
    1514              : static bool
    1515            0 : inzone(char **fields, int nfields)
    1516              : {
    1517            0 :         ptrdiff_t       i;
    1518              : 
    1519            0 :         if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS)
    1520              :         {
    1521            0 :                 error(_("wrong number of fields on Zone line"));
    1522            0 :                 return false;
    1523              :         }
    1524            0 :         if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0)
    1525              :         {
    1526            0 :                 error(
    1527              :                           _("\"Zone %s\" line and -l option are mutually exclusive"),
    1528            0 :                           tzdefault);
    1529            0 :                 return false;
    1530              :         }
    1531            0 :         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            0 :         for (i = 0; i < nzones; ++i)
    1539            0 :                 if (zones[i].z_name != NULL &&
    1540            0 :                         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            0 :         return inzsub(fields, nfields, false);
    1550            0 : }
    1551              : 
    1552              : static bool
    1553            0 : inzcont(char **fields, int nfields)
    1554              : {
    1555            0 :         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            0 :         return inzsub(fields, nfields, true);
    1561            0 : }
    1562              : 
    1563              : static bool
    1564            0 : inzsub(char **fields, int nfields, bool iscont)
    1565              : {
    1566            0 :         char       *cp;
    1567            0 :         char       *cp1;
    1568              :         static struct zone z;
    1569            0 :         int                     i_stdoff,
    1570              :                                 i_rule,
    1571              :                                 i_format;
    1572            0 :         int                     i_untilyear,
    1573              :                                 i_untilmonth;
    1574            0 :         int                     i_untilday,
    1575              :                                 i_untiltime;
    1576            0 :         bool            hasuntil;
    1577              : 
    1578            0 :         if (iscont)
    1579              :         {
    1580            0 :                 i_stdoff = ZFC_STDOFF;
    1581            0 :                 i_rule = ZFC_RULE;
    1582            0 :                 i_format = ZFC_FORMAT;
    1583            0 :                 i_untilyear = ZFC_TILYEAR;
    1584            0 :                 i_untilmonth = ZFC_TILMONTH;
    1585            0 :                 i_untilday = ZFC_TILDAY;
    1586            0 :                 i_untiltime = ZFC_TILTIME;
    1587            0 :                 z.z_name = NULL;
    1588            0 :         }
    1589            0 :         else if (!namecheck(fields[ZF_NAME]))
    1590            0 :                 return false;
    1591              :         else
    1592              :         {
    1593            0 :                 i_stdoff = ZF_STDOFF;
    1594            0 :                 i_rule = ZF_RULE;
    1595            0 :                 i_format = ZF_FORMAT;
    1596            0 :                 i_untilyear = ZF_TILYEAR;
    1597            0 :                 i_untilmonth = ZF_TILMONTH;
    1598            0 :                 i_untilday = ZF_TILDAY;
    1599            0 :                 i_untiltime = ZF_TILTIME;
    1600            0 :                 z.z_name = ecpyalloc(fields[ZF_NAME]);
    1601              :         }
    1602            0 :         z.z_filename = filename;
    1603            0 :         z.z_linenum = linenum;
    1604            0 :         z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
    1605            0 :         if ((cp = strchr(fields[i_format], '%')) != NULL)
    1606              :         {
    1607            0 :                 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
    1608            0 :                         || strchr(fields[i_format], '/'))
    1609              :                 {
    1610            0 :                         error(_("invalid abbreviation format"));
    1611            0 :                         return false;
    1612              :                 }
    1613            0 :         }
    1614            0 :         z.z_rule = ecpyalloc(fields[i_rule]);
    1615            0 :         z.z_format = cp1 = ecpyalloc(fields[i_format]);
    1616            0 :         z.z_format_specifier = cp ? *cp : '\0';
    1617            0 :         if (z.z_format_specifier == 'z')
    1618              :         {
    1619            0 :                 if (noise)
    1620            0 :                         warning(_("format '%s' not handled by pre-2015 versions of zic"),
    1621            0 :                                         z.z_format);
    1622            0 :                 cp1[cp - fields[i_format]] = 's';
    1623            0 :         }
    1624            0 :         if (max_format_len < strlen(z.z_format))
    1625            0 :                 max_format_len = strlen(z.z_format);
    1626            0 :         hasuntil = nfields > i_untilyear;
    1627            0 :         if (hasuntil)
    1628              :         {
    1629            0 :                 z.z_untilrule.r_filename = filename;
    1630            0 :                 z.z_untilrule.r_linenum = linenum;
    1631            0 :                 rulesub(&z.z_untilrule,
    1632            0 :                                 fields[i_untilyear],
    1633              :                                 "only",
    1634              :                                 "",
    1635            0 :                                 (nfields > i_untilmonth) ?
    1636            0 :                                 fields[i_untilmonth] : "Jan",
    1637            0 :                                 (nfields > i_untilday) ? fields[i_untilday] : "1",
    1638            0 :                                 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
    1639            0 :                 z.z_untiltime = rpytime(&z.z_untilrule,
    1640            0 :                                                                 z.z_untilrule.r_loyear);
    1641            0 :                 if (iscont && nzones > 0 &&
    1642            0 :                         z.z_untiltime > min_time &&
    1643            0 :                         z.z_untiltime < max_time &&
    1644            0 :                         zones[nzones - 1].z_untiltime > min_time &&
    1645            0 :                         zones[nzones - 1].z_untiltime < max_time &&
    1646            0 :                         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            0 :         }
    1652            0 :         zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
    1653            0 :         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            0 :         return hasuntil;
    1660            0 : }
    1661              : 
    1662              : static zic_t
    1663            0 : getleapdatetime(char **fields, int nfields, bool expire_line)
    1664              : {
    1665            0 :         const char *cp;
    1666            0 :         const struct lookup *lp;
    1667            0 :         zic_t           i,
    1668              :                                 j;
    1669            0 :         zic_t           year;
    1670            0 :         int                     month,
    1671              :                                 day;
    1672            0 :         zic_t           dayoff,
    1673              :                                 tod;
    1674            0 :         zic_t           t;
    1675            0 :         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            0 :         }
    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            0 :                 }
    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            0 : }
    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            0 :                         }
    1777            0 :                 }
    1778            0 :         }
    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            0 : inlink(char **fields, int nfields)
    1794              : {
    1795            0 :         struct link l;
    1796              : 
    1797            0 :         if (nfields != LINK_FIELDS)
    1798              :         {
    1799            0 :                 error(_("wrong number of fields on Link line"));
    1800            0 :                 return;
    1801              :         }
    1802            0 :         if (*fields[LF_TARGET] == '\0')
    1803              :         {
    1804            0 :                 error(_("blank TARGET field on Link line"));
    1805            0 :                 return;
    1806              :         }
    1807            0 :         if (!namecheck(fields[LF_LINKNAME]))
    1808            0 :                 return;
    1809            0 :         l.l_filename = filename;
    1810            0 :         l.l_linenum = linenum;
    1811            0 :         l.l_target = ecpyalloc(fields[LF_TARGET]);
    1812            0 :         l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
    1813            0 :         links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
    1814            0 :         links[nlinks++] = l;
    1815            0 : }
    1816              : 
    1817              : static void
    1818            0 : 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            0 :         const struct lookup *lp;
    1823            0 :         const char *cp;
    1824            0 :         char       *dp;
    1825            0 :         char       *ep;
    1826            0 :         char            xs;
    1827              : 
    1828            0 :         if ((lp = byword(monthp, mon_names)) == NULL)
    1829              :         {
    1830            0 :                 error(_("invalid month name"));
    1831            0 :                 return;
    1832              :         }
    1833            0 :         rp->r_month = lp->l_value;
    1834            0 :         rp->r_todisstd = false;
    1835            0 :         rp->r_todisut = false;
    1836            0 :         dp = ecpyalloc(timep);
    1837            0 :         if (*dp != '\0')
    1838              :         {
    1839            0 :                 ep = dp + strlen(dp) - 1;
    1840            0 :                 switch (lowerit(*ep))
    1841              :                 {
    1842              :                         case 's':                       /* Standard */
    1843            0 :                                 rp->r_todisstd = true;
    1844            0 :                                 rp->r_todisut = false;
    1845            0 :                                 *ep = '\0';
    1846            0 :                                 break;
    1847              :                         case 'w':                       /* Wall */
    1848            0 :                                 rp->r_todisstd = false;
    1849            0 :                                 rp->r_todisut = false;
    1850            0 :                                 *ep = '\0';
    1851            0 :                                 break;
    1852              :                         case 'g':                       /* Greenwich */
    1853              :                         case 'u':                       /* Universal */
    1854              :                         case 'z':                       /* Zulu */
    1855            0 :                                 rp->r_todisstd = true;
    1856            0 :                                 rp->r_todisut = true;
    1857            0 :                                 *ep = '\0';
    1858            0 :                                 break;
    1859              :                 }
    1860            0 :         }
    1861            0 :         rp->r_tod = gethms(dp, _("invalid time of day"));
    1862            0 :         free(dp);
    1863              : 
    1864              :         /*
    1865              :          * Year work.
    1866              :          */
    1867            0 :         cp = loyearp;
    1868            0 :         lp = byword(cp, begin_years);
    1869            0 :         rp->r_lowasnum = lp == NULL;
    1870            0 :         if (!rp->r_lowasnum)
    1871            0 :                 switch (lp->l_value)
    1872              :                 {
    1873              :                         case YR_MINIMUM:
    1874            0 :                                 rp->r_loyear = ZIC_MIN;
    1875            0 :                                 break;
    1876              :                         case YR_MAXIMUM:
    1877            0 :                                 rp->r_loyear = ZIC_MAX;
    1878            0 :                                 break;
    1879              :                         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            0 :                 }
    1885            0 :         else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_loyear, &xs) != 1)
    1886              :         {
    1887            0 :                 error(_("invalid starting year"));
    1888            0 :                 return;
    1889              :         }
    1890            0 :         cp = hiyearp;
    1891            0 :         lp = byword(cp, end_years);
    1892            0 :         rp->r_hiwasnum = lp == NULL;
    1893            0 :         if (!rp->r_hiwasnum)
    1894            0 :                 switch (lp->l_value)
    1895              :                 {
    1896              :                         case YR_MINIMUM:
    1897            0 :                                 rp->r_hiyear = ZIC_MIN;
    1898            0 :                                 break;
    1899              :                         case YR_MAXIMUM:
    1900            0 :                                 rp->r_hiyear = ZIC_MAX;
    1901            0 :                                 break;
    1902              :                         case YR_ONLY:
    1903            0 :                                 rp->r_hiyear = rp->r_loyear;
    1904            0 :                                 break;
    1905              :                         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            0 :                 }
    1911            0 :         else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_hiyear, &xs) != 1)
    1912              :         {
    1913            0 :                 error(_("invalid ending year"));
    1914            0 :                 return;
    1915              :         }
    1916            0 :         if (rp->r_loyear > rp->r_hiyear)
    1917              :         {
    1918            0 :                 error(_("starting year greater than ending year"));
    1919            0 :                 return;
    1920              :         }
    1921            0 :         if (*typep != '\0')
    1922              :         {
    1923            0 :                 error(_("year type \"%s\" is unsupported; use \"-\" instead"),
    1924            0 :                           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            0 :         dp = ecpyalloc(dayp);
    1933            0 :         if ((lp = byword(dp, lasts)) != NULL)
    1934              :         {
    1935            0 :                 rp->r_dycode = DC_DOWLEQ;
    1936            0 :                 rp->r_wday = lp->l_value;
    1937            0 :                 rp->r_dayofmonth = len_months[1][rp->r_month];
    1938            0 :         }
    1939              :         else
    1940              :         {
    1941            0 :                 if ((ep = strchr(dp, '<')) != NULL)
    1942            0 :                         rp->r_dycode = DC_DOWLEQ;
    1943            0 :                 else if ((ep = strchr(dp, '>')) != NULL)
    1944            0 :                         rp->r_dycode = DC_DOWGEQ;
    1945              :                 else
    1946              :                 {
    1947            0 :                         ep = dp;
    1948            0 :                         rp->r_dycode = DC_DOM;
    1949              :                 }
    1950            0 :                 if (rp->r_dycode != DC_DOM)
    1951              :                 {
    1952            0 :                         *ep++ = 0;
    1953            0 :                         if (*ep++ != '=')
    1954              :                         {
    1955            0 :                                 error(_("invalid day of month"));
    1956            0 :                                 free(dp);
    1957            0 :                                 return;
    1958              :                         }
    1959            0 :                         if ((lp = byword(dp, wday_names)) == NULL)
    1960              :                         {
    1961            0 :                                 error(_("invalid weekday name"));
    1962            0 :                                 free(dp);
    1963            0 :                                 return;
    1964              :                         }
    1965            0 :                         rp->r_wday = lp->l_value;
    1966            0 :                 }
    1967            0 :                 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
    1968            0 :                         rp->r_dayofmonth <= 0 ||
    1969            0 :                         (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            0 :         free(dp);
    1977            0 : }
    1978              : 
    1979              : static void
    1980            0 : convert(const int_fast32_t val, char *const buf)
    1981              : {
    1982            0 :         int                     i;
    1983            0 :         int                     shift;
    1984            0 :         unsigned char *const b = (unsigned char *) buf;
    1985              : 
    1986            0 :         for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
    1987            0 :                 b[i] = val >> shift;
    1988            0 : }
    1989              : 
    1990              : static void
    1991            0 : convert64(const zic_t val, char *const buf)
    1992              : {
    1993            0 :         int                     i;
    1994            0 :         int                     shift;
    1995            0 :         unsigned char *const b = (unsigned char *) buf;
    1996              : 
    1997            0 :         for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
    1998            0 :                 b[i] = val >> shift;
    1999            0 : }
    2000              : 
    2001              : static void
    2002            0 : puttzcode(const int_fast32_t val, FILE *const fp)
    2003              : {
    2004            0 :         char            buf[4];
    2005              : 
    2006            0 :         convert(val, buf);
    2007            0 :         fwrite(buf, sizeof buf, 1, fp);
    2008            0 : }
    2009              : 
    2010              : static void
    2011            0 : puttzcodepass(zic_t val, FILE *fp, int pass)
    2012              : {
    2013            0 :         if (pass == 1)
    2014            0 :                 puttzcode(val, fp);
    2015              :         else
    2016              :         {
    2017            0 :                 char            buf[8];
    2018              : 
    2019            0 :                 convert64(val, buf);
    2020            0 :                 fwrite(buf, sizeof buf, 1, fp);
    2021            0 :         }
    2022            0 : }
    2023              : 
    2024              : static int
    2025            0 : atcomp(const void *avp, const void *bvp)
    2026              : {
    2027            0 :         const zic_t a = ((const struct attype *) avp)->at;
    2028            0 :         const zic_t b = ((const struct attype *) bvp)->at;
    2029              : 
    2030            0 :         return (a < b) ? -1 : (a > b);
    2031            0 : }
    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            0 : limitrange(struct timerange r, zic_t lo, zic_t hi,
    2044              :                    zic_t const *ats, unsigned char const *types)
    2045              : {
    2046            0 :         while (0 < r.count && ats[r.base] < lo)
    2047              :         {
    2048            0 :                 r.defaulttype = types[r.base];
    2049            0 :                 r.count--;
    2050            0 :                 r.base++;
    2051              :         }
    2052            0 :         while (0 < r.leapcount && trans[r.leapbase] < lo)
    2053              :         {
    2054            0 :                 r.leapcount--;
    2055            0 :                 r.leapbase++;
    2056              :         }
    2057              : 
    2058            0 :         if (hi < ZIC_MAX)
    2059              :         {
    2060            0 :                 while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
    2061            0 :                         r.count--;
    2062            0 :                 while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
    2063            0 :                         r.leapcount--;
    2064            0 :         }
    2065              : 
    2066            0 :         return r;
    2067              : }
    2068              : 
    2069              : static void
    2070            0 : writezone(const char *const name, const char *const string, char version,
    2071              :                   int defaulttype)
    2072              : {
    2073            0 :         FILE       *fp;
    2074            0 :         ptrdiff_t       i,
    2075              :                                 j;
    2076            0 :         int                     pass;
    2077              :         static const struct tzhead tzh0;
    2078              :         static struct tzhead tzh;
    2079            0 :         bool            dir_checked = false;
    2080            0 :         zic_t           one = 1;
    2081            0 :         zic_t           y2038_boundary = one << 31;
    2082            0 :         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            0 :         zic_t      *ats = emalloc(align_to(size_product(nats, sizeof *ats + 1),
    2089              :                                                                            _Alignof(zic_t)));
    2090            0 :         void       *typesptr = ats + nats;
    2091            0 :         unsigned char *types = typesptr;
    2092            0 :         struct timerange rangeall,
    2093              :                                 range32,
    2094              :                                 range64;
    2095              : 
    2096              :         /*
    2097              :          * Sort.
    2098              :          */
    2099            0 :         if (timecnt > 1)
    2100            0 :                 qsort(attypes, timecnt, sizeof *attypes, atcomp);
    2101              : 
    2102              :         /*
    2103              :          * Optimize.
    2104              :          */
    2105              :         {
    2106            0 :                 ptrdiff_t       fromi,
    2107              :                                         toi;
    2108              : 
    2109            0 :                 toi = 0;
    2110            0 :                 fromi = 0;
    2111            0 :                 for (; fromi < timecnt; ++fromi)
    2112              :                 {
    2113            0 :                         if (toi != 0
    2114            0 :                                 && ((attypes[fromi].at
    2115            0 :                                          + utoffs[attypes[toi - 1].type])
    2116            0 :                                         <= (attypes[toi - 1].at
    2117            0 :                                                 + utoffs[toi == 1 ? 0
    2118            0 :                                                                  : attypes[toi - 2].type])))
    2119              :                         {
    2120            0 :                                 attypes[toi - 1].type =
    2121            0 :                                         attypes[fromi].type;
    2122            0 :                                 continue;
    2123              :                         }
    2124            0 :                         if (toi == 0
    2125            0 :                                 || attypes[fromi].dontmerge
    2126            0 :                                 || (utoffs[attypes[toi - 1].type]
    2127            0 :                                         != utoffs[attypes[fromi].type])
    2128            0 :                                 || (isdsts[attypes[toi - 1].type]
    2129            0 :                                         != isdsts[attypes[fromi].type])
    2130            0 :                                 || (desigidx[attypes[toi - 1].type]
    2131            0 :                                         != desigidx[attypes[fromi].type]))
    2132            0 :                                 attypes[toi++] = attypes[fromi];
    2133            0 :                 }
    2134            0 :                 timecnt = toi;
    2135            0 :         }
    2136              : 
    2137            0 :         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            0 :         }
    2147              : 
    2148              :         /*
    2149              :          * Transfer.
    2150              :          */
    2151            0 :         for (i = 0; i < timecnt; ++i)
    2152              :         {
    2153            0 :                 ats[i] = attypes[i].at;
    2154            0 :                 types[i] = attypes[i].type;
    2155            0 :         }
    2156              : 
    2157              :         /*
    2158              :          * Correct for leap seconds.
    2159              :          */
    2160            0 :         for (i = 0; i < timecnt; ++i)
    2161              :         {
    2162            0 :                 j = leapcnt;
    2163            0 :                 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            0 :         }
    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            0 :         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            0 :         }
    2187              : 
    2188            0 :         rangeall.defaulttype = defaulttype;
    2189            0 :         rangeall.base = rangeall.leapbase = 0;
    2190            0 :         rangeall.count = timecnt;
    2191            0 :         rangeall.leapcount = leapcnt;
    2192            0 :         range64 = limitrange(rangeall, lo_time, hi_time, ats, types);
    2193            0 :         range32 = limitrange(range64, INT32_MIN, INT32_MAX, ats, types);
    2194              : 
    2195              :         /*
    2196              :          * Remove old file, if any, to snap links.
    2197              :          */
    2198            0 :         if (remove(name) == 0)
    2199            0 :                 dir_checked = true;
    2200            0 :         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            0 :                                 progname, directory, name, e);
    2206            0 :                 exit(EXIT_FAILURE);
    2207              :         }
    2208            0 :         fp = fopen(name, "wb");
    2209            0 :         if (!fp)
    2210              :         {
    2211            0 :                 int                     fopen_errno = errno;
    2212              : 
    2213            0 :                 if (fopen_errno == ENOENT && !dir_checked)
    2214              :                 {
    2215            0 :                         mkdirs(name, true);
    2216            0 :                         fp = fopen(name, "wb");
    2217            0 :                         fopen_errno = errno;
    2218            0 :                 }
    2219            0 :                 if (!fp)
    2220              :                 {
    2221            0 :                         fprintf(stderr, _("%s: Cannot create %s/%s: %s\n"),
    2222            0 :                                         progname, directory, name, strerror(fopen_errno));
    2223            0 :                         exit(EXIT_FAILURE);
    2224              :                 }
    2225            0 :         }
    2226            0 :         for (pass = 1; pass <= 2; ++pass)
    2227              :         {
    2228            0 :                 ptrdiff_t       thistimei,
    2229              :                                         thistimecnt,
    2230              :                                         thistimelim;
    2231            0 :                 int                     thisleapi,
    2232              :                                         thisleapcnt,
    2233              :                                         thisleaplim;
    2234            0 :                 int                     currenttype,
    2235              :                                         thisdefaulttype;
    2236            0 :                 bool            locut,
    2237              :                                         hicut;
    2238            0 :                 zic_t           lo;
    2239            0 :                 int                     old0;
    2240            0 :                 char            omittype[TZ_MAX_TYPES];
    2241            0 :                 int                     typemap[TZ_MAX_TYPES];
    2242            0 :                 int                     thistypecnt,
    2243              :                                         stdcnt,
    2244              :                                         utcnt;
    2245            0 :                 char            thischars[TZ_MAX_CHARS];
    2246            0 :                 int                     thischarcnt;
    2247            0 :                 bool            toomanytimes;
    2248            0 :                 int                     indmap[TZ_MAX_CHARS];
    2249              : 
    2250            0 :                 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            0 :                         thisdefaulttype = (lo_time <= INT32_MIN
    2264            0 :                                                            ? range64.defaulttype
    2265            0 :                                                            : range32.defaulttype);
    2266              : 
    2267            0 :                         thistimei = range32.base;
    2268            0 :                         thistimecnt = range32.count;
    2269            0 :                         toomanytimes = thistimecnt >> 31 >> 1 != 0;
    2270            0 :                         thisleapi = range32.leapbase;
    2271            0 :                         thisleapcnt = range32.leapcount;
    2272            0 :                         locut = INT32_MIN < lo_time;
    2273            0 :                         hicut = hi_time < INT32_MAX;
    2274            0 :                 }
    2275              :                 else
    2276              :                 {
    2277            0 :                         thisdefaulttype = range64.defaulttype;
    2278            0 :                         thistimei = range64.base;
    2279            0 :                         thistimecnt = range64.count;
    2280            0 :                         toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
    2281            0 :                         thisleapi = range64.leapbase;
    2282            0 :                         thisleapcnt = range64.leapcount;
    2283            0 :                         locut = min_time < lo_time;
    2284            0 :                         hicut = hi_time < max_time;
    2285              :                 }
    2286            0 :                 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            0 :                 if (0 < thistimei && ats[thistimei] != lo_time)
    2298              :                 {
    2299            0 :                         thistimei--;
    2300            0 :                         thistimecnt++;
    2301            0 :                         locut = false;
    2302            0 :                 }
    2303              : 
    2304            0 :                 thistimelim = thistimei + thistimecnt;
    2305            0 :                 thisleaplim = thisleapi + thisleapcnt;
    2306            0 :                 if (thistimecnt != 0)
    2307              :                 {
    2308            0 :                         if (ats[thistimei] == lo_time)
    2309            0 :                                 locut = false;
    2310            0 :                         if (hi_time < ZIC_MAX && ats[thistimelim - 1] == hi_time + 1)
    2311            0 :                                 hicut = false;
    2312            0 :                 }
    2313            0 :                 memset(omittype, true, typecnt);
    2314            0 :                 omittype[thisdefaulttype] = false;
    2315            0 :                 for (i = thistimei; i < thistimelim; i++)
    2316            0 :                         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            0 :                 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            0 :                 if (want_bloat())
    2334              :                 {
    2335            0 :                         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            0 :                                 }
    2359            0 :                         }
    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            0 :                         }
    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            0 :                         }
    2384            0 :                 }
    2385              : #endif                                                  /* !defined
    2386              :                                                                  * LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
    2387            0 :                 thistypecnt = 0;
    2388            0 :                 for (i = old0; i < typecnt; i++)
    2389            0 :                         if (!omittype[i])
    2390            0 :                                 typemap[i == old0 ? thisdefaulttype
    2391            0 :                                                 : i == thisdefaulttype ? old0 : i]
    2392            0 :                                         = thistypecnt++;
    2393              : 
    2394            0 :                 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
    2395            0 :                         indmap[i] = -1;
    2396            0 :                 thischarcnt = stdcnt = utcnt = 0;
    2397            0 :                 for (i = old0; i < typecnt; i++)
    2398              :                 {
    2399            0 :                         char       *thisabbr;
    2400              : 
    2401            0 :                         if (omittype[i])
    2402            0 :                                 continue;
    2403            0 :                         if (ttisstds[i])
    2404            0 :                                 stdcnt = thistypecnt;
    2405            0 :                         if (ttisuts[i])
    2406            0 :                                 utcnt = thistypecnt;
    2407            0 :                         if (indmap[desigidx[i]] >= 0)
    2408            0 :                                 continue;
    2409            0 :                         thisabbr = &chars[desigidx[i]];
    2410            0 :                         for (j = 0; j < thischarcnt; ++j)
    2411            0 :                                 if (strcmp(&thischars[j], thisabbr) == 0)
    2412            0 :                                         break;
    2413            0 :                         if (j == thischarcnt)
    2414              :                         {
    2415            0 :                                 strcpy(&thischars[thischarcnt], thisabbr);
    2416            0 :                                 thischarcnt += strlen(thisabbr) + 1;
    2417            0 :                         }
    2418            0 :                         indmap[desigidx[i]] = j;
    2419            0 :                 }
    2420            0 :                 if (pass == 1 && !want_bloat())
    2421              :                 {
    2422            0 :                         utcnt = stdcnt = thisleapcnt = 0;
    2423            0 :                         thistimecnt = -(locut + hicut);
    2424            0 :                         thistypecnt = thischarcnt = 1;
    2425            0 :                         thistimelim = thistimei;
    2426            0 :                 }
    2427              : #define DO(field)       fwrite(tzh.field, sizeof tzh.field, 1, fp)
    2428            0 :                 tzh = tzh0;
    2429            0 :                 memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
    2430            0 :                 tzh.tzh_version[0] = version;
    2431            0 :                 convert(utcnt, tzh.tzh_ttisutcnt);
    2432            0 :                 convert(stdcnt, tzh.tzh_ttisstdcnt);
    2433            0 :                 convert(thisleapcnt, tzh.tzh_leapcnt);
    2434            0 :                 convert(locut + thistimecnt + hicut, tzh.tzh_timecnt);
    2435            0 :                 convert(thistypecnt, tzh.tzh_typecnt);
    2436            0 :                 convert(thischarcnt, tzh.tzh_charcnt);
    2437            0 :                 DO(tzh_magic);
    2438            0 :                 DO(tzh_version);
    2439            0 :                 DO(tzh_reserved);
    2440            0 :                 DO(tzh_ttisutcnt);
    2441            0 :                 DO(tzh_ttisstdcnt);
    2442            0 :                 DO(tzh_leapcnt);
    2443            0 :                 DO(tzh_timecnt);
    2444            0 :                 DO(tzh_typecnt);
    2445            0 :                 DO(tzh_charcnt);
    2446              : #undef DO
    2447            0 :                 if (pass == 1 && !want_bloat())
    2448              :                 {
    2449              :                         /* Output a minimal data block with just one time type.  */
    2450            0 :                         puttzcode(0, fp);       /* utoff */
    2451            0 :                         putc(0, fp);            /* dst */
    2452            0 :                         putc(0, fp);            /* index of abbreviation */
    2453            0 :                         putc(0, fp);            /* empty-string abbreviation */
    2454            0 :                         continue;
    2455              :                 }
    2456              : 
    2457              :                 /* PG: print current timezone abbreviations if requested */
    2458            0 :                 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            0 :                                                         thisabbrev,
    2470            0 :                                                         utoffs[tm],
    2471            0 :                                                         isdsts[tm] ? "\tD" : "");
    2472            0 :                                 }
    2473            0 :                         }
    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            0 :                                                 thisabbrev,
    2482            0 :                                                 utoffs[tm],
    2483            0 :                                                 isdsts[tm] ? "\tD" : "");
    2484            0 :                         }
    2485            0 :                 }
    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            0 :                 lo = pass == 1 && lo_time < INT32_MIN ? INT32_MIN : lo_time;
    2492              : 
    2493            0 :                 if (locut)
    2494            0 :                         puttzcodepass(lo, fp, pass);
    2495            0 :                 for (i = thistimei; i < thistimelim; ++i)
    2496              :                 {
    2497            0 :                         zic_t           at = ats[i] < lo ? lo : ats[i];
    2498              : 
    2499            0 :                         puttzcodepass(at, fp, pass);
    2500            0 :                 }
    2501            0 :                 if (hicut)
    2502            0 :                         puttzcodepass(hi_time + 1, fp, pass);
    2503            0 :                 currenttype = 0;
    2504            0 :                 if (locut)
    2505            0 :                         putc(currenttype, fp);
    2506            0 :                 for (i = thistimei; i < thistimelim; ++i)
    2507              :                 {
    2508            0 :                         currenttype = typemap[types[i]];
    2509            0 :                         putc(currenttype, fp);
    2510            0 :                 }
    2511            0 :                 if (hicut)
    2512            0 :                         putc(currenttype, fp);
    2513              : 
    2514            0 :                 for (i = old0; i < typecnt; i++)
    2515              :                 {
    2516            0 :                         int                     h = (i == old0 ? thisdefaulttype
    2517            0 :                                                          : i == thisdefaulttype ? old0 : i);
    2518              : 
    2519            0 :                         if (!omittype[h])
    2520              :                         {
    2521            0 :                                 puttzcode(utoffs[h], fp);
    2522            0 :                                 putc(isdsts[h], fp);
    2523            0 :                                 putc(indmap[desigidx[h]], fp);
    2524            0 :                         }
    2525            0 :                 }
    2526            0 :                 if (thischarcnt != 0)
    2527            0 :                         fwrite(thischars, sizeof thischars[0],
    2528            0 :                                    thischarcnt, fp);
    2529            0 :                 for (i = thisleapi; i < thisleaplim; ++i)
    2530              :                 {
    2531            0 :                         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            0 :                                 }
    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            0 :                         }
    2555              :                         else
    2556            0 :                                 todo = trans[i];
    2557            0 :                         puttzcodepass(todo, fp, pass);
    2558            0 :                         puttzcode(corr[i], fp);
    2559            0 :                 }
    2560            0 :                 if (stdcnt != 0)
    2561            0 :                         for (i = old0; i < typecnt; i++)
    2562            0 :                                 if (!omittype[i])
    2563            0 :                                         putc(ttisstds[i], fp);
    2564            0 :                 if (utcnt != 0)
    2565            0 :                         for (i = old0; i < typecnt; i++)
    2566            0 :                                 if (!omittype[i])
    2567            0 :                                         putc(ttisuts[i], fp);
    2568            0 :         }
    2569            0 :         fprintf(fp, "\n%s\n", string);
    2570            0 :         close_file(fp, directory, name);
    2571            0 :         free(ats);
    2572            0 : }
    2573              : 
    2574              : static char const *
    2575            0 : abbroffset(char *buf, zic_t offset)
    2576              : {
    2577            0 :         char            sign = '+';
    2578            0 :         int                     seconds,
    2579              :                                 minutes;
    2580              : 
    2581            0 :         if (offset < 0)
    2582              :         {
    2583            0 :                 offset = -offset;
    2584            0 :                 sign = '-';
    2585            0 :         }
    2586              : 
    2587            0 :         seconds = offset % SECSPERMIN;
    2588            0 :         offset /= SECSPERMIN;
    2589            0 :         minutes = offset % MINSPERHOUR;
    2590            0 :         offset /= MINSPERHOUR;
    2591            0 :         if (100 <= offset)
    2592              :         {
    2593            0 :                 error(_("%%z UT offset magnitude exceeds 99:59:59"));
    2594            0 :                 return "%z";
    2595              :         }
    2596              :         else
    2597              :         {
    2598            0 :                 char       *p = buf;
    2599              : 
    2600            0 :                 *p++ = sign;
    2601            0 :                 *p++ = '0' + offset / 10;
    2602            0 :                 *p++ = '0' + offset % 10;
    2603            0 :                 if (minutes | seconds)
    2604              :                 {
    2605            0 :                         *p++ = '0' + minutes / 10;
    2606            0 :                         *p++ = '0' + minutes % 10;
    2607            0 :                         if (seconds)
    2608              :                         {
    2609            0 :                                 *p++ = '0' + seconds / 10;
    2610            0 :                                 *p++ = '0' + seconds % 10;
    2611            0 :                         }
    2612            0 :                 }
    2613            0 :                 *p = '\0';
    2614            0 :                 return buf;
    2615            0 :         }
    2616            0 : }
    2617              : 
    2618              : static size_t
    2619            0 : doabbr(char *abbr, struct zone const *zp, char const *letters,
    2620              :            bool isdst, zic_t save, bool doquotes)
    2621              : {
    2622            0 :         char       *cp;
    2623            0 :         char const *slashp;
    2624            0 :         size_t          len;
    2625            0 :         char const *format = zp->z_format;
    2626              : 
    2627            0 :         slashp = strchr(format, '/');
    2628            0 :         if (slashp == NULL)
    2629              :         {
    2630            0 :                 char            letterbuf[PERCENT_Z_LEN_BOUND + 1];
    2631              : 
    2632            0 :                 if (zp->z_format_specifier == 'z')
    2633            0 :                         letters = abbroffset(letterbuf, zp->z_stdoff + save);
    2634            0 :                 else if (!letters)
    2635            0 :                         letters = "%s";
    2636            0 :                 sprintf(abbr, format, letters);
    2637            0 :         }
    2638            0 :         else if (isdst)
    2639              :         {
    2640            0 :                 strcpy(abbr, slashp + 1);
    2641            0 :         }
    2642              :         else
    2643              :         {
    2644            0 :                 memcpy(abbr, format, slashp - format);
    2645            0 :                 abbr[slashp - format] = '\0';
    2646              :         }
    2647            0 :         len = strlen(abbr);
    2648            0 :         if (!doquotes)
    2649            0 :                 return len;
    2650            0 :         for (cp = abbr; is_alpha(*cp); cp++)
    2651            0 :                 continue;
    2652            0 :         if (len > 0 && *cp == '\0')
    2653            0 :                 return len;
    2654            0 :         abbr[len + 2] = '\0';
    2655            0 :         abbr[len + 1] = '>';
    2656            0 :         memmove(abbr + 1, abbr, len);
    2657            0 :         abbr[0] = '<';
    2658            0 :         return len + 2;
    2659            0 : }
    2660              : 
    2661              : static void
    2662            0 : updateminmax(const zic_t x)
    2663              : {
    2664            0 :         if (min_year > x)
    2665            0 :                 min_year = x;
    2666            0 :         if (max_year < x)
    2667            0 :                 max_year = x;
    2668            0 : }
    2669              : 
    2670              : static int
    2671            0 : stringoffset(char *result, zic_t offset)
    2672              : {
    2673            0 :         int                     hours;
    2674            0 :         int                     minutes;
    2675            0 :         int                     seconds;
    2676            0 :         bool            negative = offset < 0;
    2677            0 :         int                     len = negative;
    2678              : 
    2679            0 :         if (negative)
    2680              :         {
    2681            0 :                 offset = -offset;
    2682            0 :                 result[0] = '-';
    2683            0 :         }
    2684            0 :         seconds = offset % SECSPERMIN;
    2685            0 :         offset /= SECSPERMIN;
    2686            0 :         minutes = offset % MINSPERHOUR;
    2687            0 :         offset /= MINSPERHOUR;
    2688            0 :         hours = offset;
    2689            0 :         if (hours >= HOURSPERDAY * DAYSPERWEEK)
    2690              :         {
    2691            0 :                 result[0] = '\0';
    2692            0 :                 return 0;
    2693              :         }
    2694            0 :         len += sprintf(result + len, "%d", hours);
    2695            0 :         if (minutes != 0 || seconds != 0)
    2696              :         {
    2697            0 :                 len += sprintf(result + len, ":%02d", minutes);
    2698            0 :                 if (seconds != 0)
    2699            0 :                         len += sprintf(result + len, ":%02d", seconds);
    2700            0 :         }
    2701            0 :         return len;
    2702            0 : }
    2703              : 
    2704              : static int
    2705            0 : stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff)
    2706              : {
    2707            0 :         zic_t           tod = rp->r_tod;
    2708            0 :         int                     compat = 0;
    2709              : 
    2710            0 :         if (rp->r_dycode == DC_DOM)
    2711              :         {
    2712            0 :                 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            0 :         }
    2726              :         else
    2727              :         {
    2728            0 :                 int                     week;
    2729            0 :                 int                     wday = rp->r_wday;
    2730            0 :                 int                     wdayoff;
    2731              : 
    2732            0 :                 if (rp->r_dycode == DC_DOWGEQ)
    2733              :                 {
    2734            0 :                         wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
    2735            0 :                         if (wdayoff)
    2736            0 :                                 compat = 2013;
    2737            0 :                         wday -= wdayoff;
    2738            0 :                         tod += wdayoff * SECSPERDAY;
    2739            0 :                         week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
    2740            0 :                 }
    2741            0 :                 else if (rp->r_dycode == DC_DOWLEQ)
    2742              :                 {
    2743            0 :                         if (rp->r_dayofmonth == len_months[1][rp->r_month])
    2744            0 :                                 week = 5;
    2745              :                         else
    2746              :                         {
    2747            0 :                                 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
    2748            0 :                                 if (wdayoff)
    2749            0 :                                         compat = 2013;
    2750            0 :                                 wday -= wdayoff;
    2751            0 :                                 tod += wdayoff * SECSPERDAY;
    2752            0 :                                 week = rp->r_dayofmonth / DAYSPERWEEK;
    2753              :                         }
    2754            0 :                 }
    2755              :                 else
    2756            0 :                         return -1;                      /* "cannot happen" */
    2757            0 :                 if (wday < 0)
    2758            0 :                         wday += DAYSPERWEEK;
    2759            0 :                 result += sprintf(result, "M%d.%d.%d",
    2760            0 :                                                   rp->r_month + 1, week, wday);
    2761            0 :         }
    2762            0 :         if (rp->r_todisut)
    2763            0 :                 tod += stdoff;
    2764            0 :         if (rp->r_todisstd && !rp->r_isdst)
    2765            0 :                 tod += save;
    2766            0 :         if (tod != 2 * SECSPERMIN * MINSPERHOUR)
    2767              :         {
    2768            0 :                 *result++ = '/';
    2769            0 :                 if (!stringoffset(result, tod))
    2770            0 :                         return -1;
    2771            0 :                 if (tod < 0)
    2772              :                 {
    2773            0 :                         if (compat < 2013)
    2774            0 :                                 compat = 2013;
    2775            0 :                 }
    2776            0 :                 else if (SECSPERDAY <= tod)
    2777              :                 {
    2778            0 :                         if (compat < 1994)
    2779            0 :                                 compat = 1994;
    2780            0 :                 }
    2781            0 :         }
    2782            0 :         return compat;
    2783            0 : }
    2784              : 
    2785              : static int
    2786            0 : rule_cmp(struct rule const *a, struct rule const *b)
    2787              : {
    2788            0 :         if (!a)
    2789            0 :                 return -!!b;
    2790            0 :         if (!b)
    2791            0 :                 return 1;
    2792            0 :         if (a->r_hiyear != b->r_hiyear)
    2793            0 :                 return a->r_hiyear < b->r_hiyear ? -1 : 1;
    2794            0 :         if (a->r_month - b->r_month != 0)
    2795            0 :                 return a->r_month - b->r_month;
    2796            0 :         return a->r_dayofmonth - b->r_dayofmonth;
    2797            0 : }
    2798              : 
    2799              : static int
    2800            0 : stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
    2801              : {
    2802            0 :         const struct zone *zp;
    2803            0 :         struct rule *rp;
    2804            0 :         struct rule *stdrp;
    2805            0 :         struct rule *dstrp;
    2806            0 :         ptrdiff_t       i;
    2807            0 :         const char *abbrvar;
    2808            0 :         int                     compat = 0;
    2809            0 :         int                     c;
    2810            0 :         size_t          len;
    2811            0 :         int                     offsetlen;
    2812            0 :         struct rule stdr,
    2813              :                                 dstr;
    2814              : 
    2815            0 :         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            0 :         if (hi_time < max_time)
    2822            0 :                 return -1;
    2823              : 
    2824            0 :         zp = zpfirst + zonecount - 1;
    2825            0 :         stdrp = dstrp = NULL;
    2826            0 :         for (i = 0; i < zp->z_nrules; ++i)
    2827              :         {
    2828            0 :                 rp = &zp->z_rules[i];
    2829            0 :                 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
    2830            0 :                         continue;
    2831            0 :                 if (!rp->r_isdst)
    2832              :                 {
    2833            0 :                         if (stdrp == NULL)
    2834            0 :                                 stdrp = rp;
    2835              :                         else
    2836            0 :                                 return -1;
    2837            0 :                 }
    2838              :                 else
    2839              :                 {
    2840            0 :                         if (dstrp == NULL)
    2841            0 :                                 dstrp = rp;
    2842              :                         else
    2843            0 :                                 return -1;
    2844              :                 }
    2845            0 :         }
    2846            0 :         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            0 :                 struct rule *stdabbrrp = NULL;
    2853              : 
    2854            0 :                 for (i = 0; i < zp->z_nrules; ++i)
    2855              :                 {
    2856            0 :                         rp = &zp->z_rules[i];
    2857            0 :                         if (!rp->r_isdst && rule_cmp(stdabbrrp, rp) < 0)
    2858            0 :                                 stdabbrrp = rp;
    2859            0 :                         if (rule_cmp(stdrp, rp) < 0)
    2860            0 :                                 stdrp = rp;
    2861            0 :                 }
    2862            0 :                 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            0 :                         stdr.r_abbrvar
    2881            0 :                                 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
    2882            0 :                         dstrp = &dstr;
    2883            0 :                         stdrp = &stdr;
    2884            0 :                 }
    2885            0 :         }
    2886            0 :         if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_isdst))
    2887            0 :                 return -1;
    2888            0 :         abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
    2889            0 :         len = doabbr(result, zp, abbrvar, false, 0, true);
    2890            0 :         offsetlen = stringoffset(result + len, -zp->z_stdoff);
    2891            0 :         if (!offsetlen)
    2892              :         {
    2893            0 :                 result[0] = '\0';
    2894            0 :                 return -1;
    2895              :         }
    2896            0 :         len += offsetlen;
    2897            0 :         if (dstrp == NULL)
    2898            0 :                 return compat;
    2899            0 :         len += doabbr(result + len, zp, dstrp->r_abbrvar,
    2900            0 :                                   dstrp->r_isdst, dstrp->r_save, true);
    2901            0 :         if (dstrp->r_save != SECSPERMIN * MINSPERHOUR)
    2902              :         {
    2903            0 :                 offsetlen = stringoffset(result + len,
    2904            0 :                                                                  -(zp->z_stdoff + dstrp->r_save));
    2905            0 :                 if (!offsetlen)
    2906              :                 {
    2907            0 :                         result[0] = '\0';
    2908            0 :                         return -1;
    2909              :                 }
    2910            0 :                 len += offsetlen;
    2911            0 :         }
    2912            0 :         result[len++] = ',';
    2913            0 :         c = stringrule(result + len, dstrp, dstrp->r_save, zp->z_stdoff);
    2914            0 :         if (c < 0)
    2915              :         {
    2916            0 :                 result[0] = '\0';
    2917            0 :                 return -1;
    2918              :         }
    2919            0 :         if (compat < c)
    2920            0 :                 compat = c;
    2921            0 :         len += strlen(result + len);
    2922            0 :         result[len++] = ',';
    2923            0 :         c = stringrule(result + len, stdrp, dstrp->r_save, zp->z_stdoff);
    2924            0 :         if (c < 0)
    2925              :         {
    2926            0 :                 result[0] = '\0';
    2927            0 :                 return -1;
    2928              :         }
    2929            0 :         if (compat < c)
    2930            0 :                 compat = c;
    2931            0 :         return compat;
    2932            0 : }
    2933              : 
    2934              : static void
    2935            0 : outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
    2936              : {
    2937            0 :         const struct zone *zp;
    2938            0 :         struct rule *rp;
    2939            0 :         ptrdiff_t       i,
    2940              :                                 j;
    2941            0 :         bool            usestart,
    2942              :                                 useuntil;
    2943            0 :         zic_t           starttime,
    2944              :                                 untiltime;
    2945            0 :         zic_t           stdoff;
    2946            0 :         zic_t           save;
    2947            0 :         zic_t           year;
    2948            0 :         zic_t           startoff;
    2949            0 :         bool            startttisstd;
    2950            0 :         bool            startttisut;
    2951            0 :         int                     type;
    2952            0 :         char       *startbuf;
    2953            0 :         char       *ab;
    2954            0 :         char       *envvar;
    2955            0 :         int                     max_abbr_len;
    2956            0 :         int                     max_envvar_len;
    2957            0 :         bool            prodstic;               /* all rules are min to max */
    2958            0 :         int                     compat;
    2959            0 :         bool            do_extend;
    2960            0 :         char            version;
    2961            0 :         ptrdiff_t       lastatmax = -1;
    2962            0 :         zic_t           one = 1;
    2963            0 :         zic_t           y2038_boundary = one << 31;
    2964            0 :         zic_t           max_year0;
    2965            0 :         int                     defaulttype = -1;
    2966              : 
    2967            0 :         max_abbr_len = 2 + max_format_len + max_abbrvar_len;
    2968            0 :         max_envvar_len = 2 * max_abbr_len + 5 * 9;
    2969            0 :         startbuf = emalloc(max_abbr_len + 1);
    2970            0 :         ab = emalloc(max_abbr_len + 1);
    2971            0 :         envvar = emalloc(max_envvar_len + 1);
    2972            0 :         INITIALIZE(untiltime);
    2973            0 :         INITIALIZE(starttime);
    2974              : 
    2975              :         /*
    2976              :          * Now. . .finally. . .generate some useful data!
    2977              :          */
    2978            0 :         timecnt = 0;
    2979            0 :         typecnt = 0;
    2980            0 :         charcnt = 0;
    2981            0 :         prodstic = zonecount == 1;
    2982              : 
    2983              :         /*
    2984              :          * Thanks to Earl Chew for noting the need to unconditionally initialize
    2985              :          * startttisstd.
    2986              :          */
    2987            0 :         startttisstd = false;
    2988            0 :         startttisut = false;
    2989            0 :         min_year = max_year = EPOCH_YEAR;
    2990            0 :         if (leapseen)
    2991              :         {
    2992            0 :                 updateminmax(leapminyear);
    2993            0 :                 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
    2994            0 :         }
    2995            0 :         for (i = 0; i < zonecount; ++i)
    2996              :         {
    2997            0 :                 zp = &zpfirst[i];
    2998            0 :                 if (i < zonecount - 1)
    2999            0 :                         updateminmax(zp->z_untilrule.r_loyear);
    3000            0 :                 for (j = 0; j < zp->z_nrules; ++j)
    3001              :                 {
    3002            0 :                         rp = &zp->z_rules[j];
    3003            0 :                         if (rp->r_lowasnum)
    3004            0 :                                 updateminmax(rp->r_loyear);
    3005            0 :                         if (rp->r_hiwasnum)
    3006            0 :                                 updateminmax(rp->r_hiyear);
    3007            0 :                         if (rp->r_lowasnum || rp->r_hiwasnum)
    3008            0 :                                 prodstic = false;
    3009            0 :                 }
    3010            0 :         }
    3011              : 
    3012              :         /*
    3013              :          * Generate lots of data if a rule can't cover all future times.
    3014              :          */
    3015            0 :         compat = stringzone(envvar, zpfirst, zonecount);
    3016            0 :         version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
    3017            0 :         do_extend = compat < 0;
    3018            0 :         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            0 :                 }
    3034            0 :         }
    3035            0 :         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            0 :                 }
    3072            0 :         }
    3073            0 :         max_year0 = max_year;
    3074            0 :         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            0 :         }
    3085              : 
    3086            0 :         for (i = 0; i < zonecount; ++i)
    3087              :         {
    3088            0 :                 struct rule *prevrp = NULL;
    3089              : 
    3090              :                 /*
    3091              :                  * A guess that may well be corrected later.
    3092              :                  */
    3093            0 :                 save = 0;
    3094            0 :                 zp = &zpfirst[i];
    3095            0 :                 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
    3096            0 :                 useuntil = i < (zonecount - 1);
    3097            0 :                 if (useuntil && zp->z_untiltime <= min_time)
    3098            0 :                         continue;
    3099            0 :                 stdoff = zp->z_stdoff;
    3100            0 :                 eat(zp->z_filename, zp->z_linenum);
    3101            0 :                 *startbuf = '\0';
    3102            0 :                 startoff = zp->z_stdoff;
    3103            0 :                 if (zp->z_nrules == 0)
    3104              :                 {
    3105            0 :                         save = zp->z_save;
    3106            0 :                         doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
    3107            0 :                         type = addtype(oadd(zp->z_stdoff, save),
    3108            0 :                                                    startbuf, zp->z_isdst, startttisstd,
    3109            0 :                                                    startttisut);
    3110            0 :                         if (usestart)
    3111              :                         {
    3112            0 :                                 addtt(starttime, type);
    3113            0 :                                 usestart = false;
    3114            0 :                         }
    3115              :                         else
    3116            0 :                                 defaulttype = type;
    3117            0 :                 }
    3118              :                 else
    3119            0 :                         for (year = min_year; year <= max_year; ++year)
    3120              :                         {
    3121            0 :                                 if (useuntil && year > zp->z_untilrule.r_hiyear)
    3122            0 :                                         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            0 :                                 for (j = 0; j < zp->z_nrules; ++j)
    3130              :                                 {
    3131            0 :                                         rp = &zp->z_rules[j];
    3132            0 :                                         eats(zp->z_filename, zp->z_linenum,
    3133            0 :                                                  rp->r_filename, rp->r_linenum);
    3134            0 :                                         rp->r_todo = year >= rp->r_loyear &&
    3135            0 :                                                 year <= rp->r_hiyear;
    3136            0 :                                         if (rp->r_todo)
    3137              :                                         {
    3138            0 :                                                 rp->r_temp = rpytime(rp, year);
    3139            0 :                                                 rp->r_todo
    3140            0 :                                                         = (rp->r_temp < y2038_boundary
    3141            0 :                                                            || year <= max_year0);
    3142            0 :                                         }
    3143            0 :                                 }
    3144            0 :                                 for (;;)
    3145              :                                 {
    3146            0 :                                         ptrdiff_t       k;
    3147            0 :                                         zic_t           jtime,
    3148              :                                                                 ktime;
    3149            0 :                                         zic_t           offset;
    3150              : 
    3151            0 :                                         INITIALIZE(ktime);
    3152            0 :                                         if (useuntil)
    3153              :                                         {
    3154              :                                                 /*
    3155              :                                                  * Turn untiltime into UT assuming the current stdoff
    3156              :                                                  * and save values.
    3157              :                                                  */
    3158            0 :                                                 untiltime = zp->z_untiltime;
    3159            0 :                                                 if (!zp->z_untilrule.r_todisut)
    3160            0 :                                                         untiltime = tadd(untiltime,
    3161            0 :                                                                                          -stdoff);
    3162            0 :                                                 if (!zp->z_untilrule.r_todisstd)
    3163            0 :                                                         untiltime = tadd(untiltime,
    3164            0 :                                                                                          -save);
    3165            0 :                                         }
    3166              : 
    3167              :                                         /*
    3168              :                                          * Find the rule (of those to do, if any) that takes
    3169              :                                          * effect earliest in the year.
    3170              :                                          */
    3171            0 :                                         k = -1;
    3172            0 :                                         for (j = 0; j < zp->z_nrules; ++j)
    3173              :                                         {
    3174            0 :                                                 rp = &zp->z_rules[j];
    3175            0 :                                                 if (!rp->r_todo)
    3176            0 :                                                         continue;
    3177            0 :                                                 eats(zp->z_filename, zp->z_linenum,
    3178            0 :                                                          rp->r_filename, rp->r_linenum);
    3179            0 :                                                 offset = rp->r_todisut ? 0 : stdoff;
    3180            0 :                                                 if (!rp->r_todisstd)
    3181            0 :                                                         offset = oadd(offset, save);
    3182            0 :                                                 jtime = rp->r_temp;
    3183            0 :                                                 if (jtime == min_time ||
    3184            0 :                                                         jtime == max_time)
    3185            0 :                                                         continue;
    3186            0 :                                                 jtime = tadd(jtime, -offset);
    3187            0 :                                                 if (k < 0 || jtime < ktime)
    3188              :                                                 {
    3189            0 :                                                         k = j;
    3190            0 :                                                         ktime = jtime;
    3191            0 :                                                 }
    3192            0 :                                                 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            0 :                                                                  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            0 :                                                                  rp->r_filename, rp->r_linenum);
    3203            0 :                                                         error("%s", dup_rules_msg);
    3204            0 :                                                 }
    3205            0 :                                         }
    3206            0 :                                         if (k < 0)
    3207            0 :                                                 break;  /* go on to next year */
    3208            0 :                                         rp = &zp->z_rules[k];
    3209            0 :                                         rp->r_todo = false;
    3210            0 :                                         if (useuntil && ktime >= untiltime)
    3211            0 :                                                 break;
    3212            0 :                                         save = rp->r_save;
    3213            0 :                                         if (usestart && ktime == starttime)
    3214            0 :                                                 usestart = false;
    3215            0 :                                         if (usestart)
    3216              :                                         {
    3217            0 :                                                 if (ktime < starttime)
    3218              :                                                 {
    3219            0 :                                                         startoff = oadd(zp->z_stdoff,
    3220            0 :                                                                                         save);
    3221            0 :                                                         doabbr(startbuf, zp,
    3222            0 :                                                                    rp->r_abbrvar,
    3223            0 :                                                                    rp->r_isdst,
    3224            0 :                                                                    rp->r_save,
    3225              :                                                                    false);
    3226            0 :                                                         continue;
    3227              :                                                 }
    3228            0 :                                                 if (*startbuf == '\0'
    3229            0 :                                                         && startoff == oadd(zp->z_stdoff,
    3230            0 :                                                                                                 save))
    3231              :                                                 {
    3232            0 :                                                         doabbr(startbuf,
    3233            0 :                                                                    zp,
    3234            0 :                                                                    rp->r_abbrvar,
    3235            0 :                                                                    rp->r_isdst,
    3236            0 :                                                                    rp->r_save,
    3237              :                                                                    false);
    3238            0 :                                                 }
    3239            0 :                                         }
    3240            0 :                                         eats(zp->z_filename, zp->z_linenum,
    3241            0 :                                                  rp->r_filename, rp->r_linenum);
    3242            0 :                                         doabbr(ab, zp, rp->r_abbrvar,
    3243            0 :                                                    rp->r_isdst, rp->r_save, false);
    3244            0 :                                         offset = oadd(zp->z_stdoff, rp->r_save);
    3245            0 :                                         if (!want_bloat() && !useuntil && !do_extend
    3246            0 :                                                 && prevrp
    3247            0 :                                                 && rp->r_hiyear == ZIC_MAX
    3248            0 :                                                 && prevrp->r_hiyear == ZIC_MAX)
    3249            0 :                                                 break;
    3250            0 :                                         type = addtype(offset, ab, rp->r_isdst,
    3251            0 :                                                                    rp->r_todisstd, rp->r_todisut);
    3252            0 :                                         if (defaulttype < 0 && !rp->r_isdst)
    3253            0 :                                                 defaulttype = type;
    3254            0 :                                         if (rp->r_hiyear == ZIC_MAX
    3255            0 :                                                 && !(0 <= lastatmax
    3256            0 :                                                          && ktime < attypes[lastatmax].at))
    3257            0 :                                                 lastatmax = timecnt;
    3258            0 :                                         addtt(ktime, type);
    3259            0 :                                         prevrp = rp;
    3260            0 :                                 }
    3261            0 :                         }
    3262            0 :                 if (usestart)
    3263              :                 {
    3264            0 :                         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            0 :                         eat(zp->z_filename, zp->z_linenum);
    3270            0 :                         if (*startbuf == '\0')
    3271            0 :                                 error(_("cannot determine time zone abbreviation to use just after until time"));
    3272              :                         else
    3273              :                         {
    3274            0 :                                 bool            isdst = startoff != zp->z_stdoff;
    3275              : 
    3276            0 :                                 type = addtype(startoff, startbuf, isdst,
    3277            0 :                                                            startttisstd, startttisut);
    3278            0 :                                 if (defaulttype < 0 && !isdst)
    3279            0 :                                         defaulttype = type;
    3280            0 :                                 addtt(starttime, type);
    3281            0 :                         }
    3282            0 :                 }
    3283              : 
    3284              :                 /*
    3285              :                  * Now we may get to set starttime for the next zone line.
    3286              :                  */
    3287            0 :                 if (useuntil)
    3288              :                 {
    3289            0 :                         startttisstd = zp->z_untilrule.r_todisstd;
    3290            0 :                         startttisut = zp->z_untilrule.r_todisut;
    3291            0 :                         starttime = zp->z_untiltime;
    3292            0 :                         if (!startttisstd)
    3293            0 :                                 starttime = tadd(starttime, -save);
    3294            0 :                         if (!startttisut)
    3295            0 :                                 starttime = tadd(starttime, -stdoff);
    3296            0 :                 }
    3297            0 :         }
    3298            0 :         if (defaulttype < 0)
    3299            0 :                 defaulttype = 0;
    3300            0 :         if (0 <= lastatmax)
    3301            0 :                 attypes[lastatmax].dontmerge = true;
    3302            0 :         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            0 :                 struct rule xr;
    3314            0 :                 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            0 :                 }
    3329            0 :         }
    3330            0 :         writezone(zpfirst->z_name, envvar, version, defaulttype);
    3331            0 :         free(startbuf);
    3332            0 :         free(ab);
    3333            0 :         free(envvar);
    3334            0 : }
    3335              : 
    3336              : static void
    3337            0 : addtt(zic_t starttime, int type)
    3338              : {
    3339            0 :         attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
    3340            0 :         attypes[timecnt].at = starttime;
    3341            0 :         attypes[timecnt].dontmerge = false;
    3342            0 :         attypes[timecnt].type = type;
    3343            0 :         ++timecnt;
    3344            0 : }
    3345              : 
    3346              : static int
    3347            0 : addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
    3348              : {
    3349            0 :         int                     i,
    3350              :                                 j;
    3351              : 
    3352            0 :         if (!(-1L - 2147483647L <= utoff && utoff <= 2147483647L))
    3353              :         {
    3354            0 :                 error(_("UT offset out of range"));
    3355            0 :                 exit(EXIT_FAILURE);
    3356              :         }
    3357            0 :         if (!want_bloat())
    3358            0 :                 ttisstd = ttisut = false;
    3359              : 
    3360            0 :         for (j = 0; j < charcnt; ++j)
    3361            0 :                 if (strcmp(&chars[j], abbr) == 0)
    3362            0 :                         break;
    3363            0 :         if (j == charcnt)
    3364            0 :                 newabbr(abbr);
    3365              :         else
    3366              :         {
    3367              :                 /* If there's already an entry, return its index.  */
    3368            0 :                 for (i = 0; i < typecnt; i++)
    3369            0 :                         if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
    3370            0 :                                 && ttisstd == ttisstds[i] && ttisut == ttisuts[i])
    3371            0 :                                 return i;
    3372              :         }
    3373              : 
    3374              :         /*
    3375              :          * There isn't one; add a new one, unless there are already too many.
    3376              :          */
    3377            0 :         if (typecnt >= TZ_MAX_TYPES)
    3378              :         {
    3379            0 :                 error(_("too many local time types"));
    3380            0 :                 exit(EXIT_FAILURE);
    3381              :         }
    3382            0 :         i = typecnt++;
    3383            0 :         utoffs[i] = utoff;
    3384            0 :         isdsts[i] = isdst;
    3385            0 :         ttisstds[i] = ttisstd;
    3386            0 :         ttisuts[i] = ttisut;
    3387            0 :         desigidx[i] = j;
    3388            0 :         return i;
    3389            0 : }
    3390              : 
    3391              : static void
    3392            0 : leapadd(zic_t t, int correction, int rolling)
    3393              : {
    3394            0 :         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            0 :         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            0 :         }
    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            0 :         }
    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            0 :         }
    3453            0 : }
    3454              : 
    3455              : /* Is A a space character in the C locale?  */
    3456              : static bool
    3457            0 : is_space(char a)
    3458              : {
    3459            0 :         switch (a)
    3460              :         {
    3461              :                 default:
    3462            0 :                         return false;
    3463              :                 case ' ':
    3464              :                 case '\f':
    3465              :                 case '\n':
    3466              :                 case '\r':
    3467              :                 case '\t':
    3468              :                 case '\v':
    3469            0 :                         return true;
    3470              :         }
    3471            0 : }
    3472              : 
    3473              : /* Is A an alphabetic character in the C locale?  */
    3474              : static bool
    3475            0 : is_alpha(char a)
    3476              : {
    3477            0 :         switch (a)
    3478              :         {
    3479              :                 default:
    3480            0 :                         return false;
    3481              :                 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            0 :                         return true;
    3534              :         }
    3535            0 : }
    3536              : 
    3537              : /* If A is an uppercase character in the C locale, return its lowercase
    3538              :    counterpart.  Otherwise, return A.  */
    3539              : static char
    3540            0 : lowerit(char a)
    3541              : {
    3542            0 :         switch (a)
    3543              :         {
    3544              :                 default:
    3545            0 :                         return a;
    3546              :                 case 'A':
    3547            0 :                         return 'a';
    3548              :                 case 'B':
    3549            0 :                         return 'b';
    3550              :                 case 'C':
    3551            0 :                         return 'c';
    3552              :                 case 'D':
    3553            0 :                         return 'd';
    3554              :                 case 'E':
    3555            0 :                         return 'e';
    3556              :                 case 'F':
    3557            0 :                         return 'f';
    3558              :                 case 'G':
    3559            0 :                         return 'g';
    3560              :                 case 'H':
    3561            0 :                         return 'h';
    3562              :                 case 'I':
    3563            0 :                         return 'i';
    3564              :                 case 'J':
    3565            0 :                         return 'j';
    3566              :                 case 'K':
    3567            0 :                         return 'k';
    3568              :                 case 'L':
    3569            0 :                         return 'l';
    3570              :                 case 'M':
    3571            0 :                         return 'm';
    3572              :                 case 'N':
    3573            0 :                         return 'n';
    3574              :                 case 'O':
    3575            0 :                         return 'o';
    3576              :                 case 'P':
    3577            0 :                         return 'p';
    3578              :                 case 'Q':
    3579            0 :                         return 'q';
    3580              :                 case 'R':
    3581            0 :                         return 'r';
    3582              :                 case 'S':
    3583            0 :                         return 's';
    3584              :                 case 'T':
    3585            0 :                         return 't';
    3586              :                 case 'U':
    3587            0 :                         return 'u';
    3588              :                 case 'V':
    3589            0 :                         return 'v';
    3590              :                 case 'W':
    3591            0 :                         return 'w';
    3592              :                 case 'X':
    3593            0 :                         return 'x';
    3594              :                 case 'Y':
    3595            0 :                         return 'y';
    3596              :                 case 'Z':
    3597            0 :                         return 'z';
    3598              :         }
    3599            0 : }
    3600              : 
    3601              : /* case-insensitive equality */
    3602              : static bool
    3603            0 : ciequal(const char *ap, const char *bp)
    3604              : {
    3605            0 :         while (lowerit(*ap) == lowerit(*bp++))
    3606            0 :                 if (*ap++ == '\0')
    3607            0 :                         return true;
    3608            0 :         return false;
    3609            0 : }
    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            0 :                 do
    3619              :                 {
    3620            0 :                         if (*word == '\0')
    3621            0 :                                 return false;
    3622            0 :                 } while (lowerit(*word++) != lowerit(*abbr));
    3623            0 :         return true;
    3624            0 : }
    3625              : 
    3626              : /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case.  */
    3627              : 
    3628              : static bool
    3629            0 : ciprefix(char const *abbr, char const *word)
    3630              : {
    3631            0 :         do
    3632            0 :                 if (!*abbr)
    3633            0 :                         return true;
    3634            0 :         while (lowerit(*abbr++) == lowerit(*word++));
    3635              : 
    3636            0 :         return false;
    3637            0 : }
    3638              : 
    3639              : static const struct lookup *
    3640            0 : byword(const char *word, const struct lookup *table)
    3641              : {
    3642            0 :         const struct lookup *foundlp;
    3643            0 :         const struct lookup *lp;
    3644              : 
    3645            0 :         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            0 :         if (table == lasts && ciprefix("last", word) && word[4])
    3654              :         {
    3655            0 :                 if (word[4] == '-')
    3656            0 :                         warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
    3657            0 :                                         word, word + 5);
    3658              :                 else
    3659              :                 {
    3660            0 :                         word += 4;
    3661            0 :                         table = wday_names;
    3662              :                 }
    3663            0 :         }
    3664              : 
    3665              :         /*
    3666              :          * Look for exact match.
    3667              :          */
    3668            0 :         for (lp = table; lp->l_word != NULL; ++lp)
    3669            0 :                 if (ciequal(word, lp->l_word))
    3670            0 :                         return lp;
    3671              : 
    3672              :         /*
    3673              :          * Look for inexact match.
    3674              :          */
    3675            0 :         foundlp = NULL;
    3676            0 :         for (lp = table; lp->l_word != NULL; ++lp)
    3677            0 :                 if (ciprefix(word, lp->l_word))
    3678              :                 {
    3679            0 :                         if (foundlp == NULL)
    3680            0 :                                 foundlp = lp;
    3681              :                         else
    3682            0 :                                 return NULL;    /* multiple inexact matches */
    3683            0 :                 }
    3684              : 
    3685            0 :         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            0 :                         }
    3700            0 :         }
    3701              : 
    3702            0 :         return foundlp;
    3703            0 : }
    3704              : 
    3705              : static char **
    3706            0 : getfields(char *cp)
    3707              : {
    3708            0 :         char       *dp;
    3709            0 :         char      **array;
    3710            0 :         int                     nsubs;
    3711              : 
    3712            0 :         if (cp == NULL)
    3713            0 :                 return NULL;
    3714            0 :         array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
    3715            0 :         nsubs = 0;
    3716            0 :         for (;;)
    3717              :         {
    3718            0 :                 while (is_space(*cp))
    3719            0 :                         ++cp;
    3720            0 :                 if (*cp == '\0' || *cp == '#')
    3721            0 :                         break;
    3722            0 :                 array[nsubs++] = dp = cp;
    3723            0 :                 do
    3724              :                 {
    3725            0 :                         if ((*dp = *cp++) != '"')
    3726            0 :                                 ++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            0 :                 } while (*cp && *cp != '#' && !is_space(*cp));
    3737            0 :                 if (is_space(*cp))
    3738            0 :                         ++cp;
    3739            0 :                 *dp = '\0';
    3740              :         }
    3741            0 :         array[nsubs] = NULL;
    3742            0 :         return array;
    3743            0 : }
    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            0 : oadd(zic_t t1, zic_t t2)
    3754              : {
    3755            0 :         if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
    3756            0 :                 time_overflow();
    3757            0 :         return t1 + t2;
    3758              : }
    3759              : 
    3760              : static zic_t
    3761            0 : tadd(zic_t t1, zic_t t2)
    3762              : {
    3763            0 :         if (t1 < 0)
    3764              :         {
    3765            0 :                 if (t2 < min_time - t1)
    3766              :                 {
    3767            0 :                         if (t1 != min_time)
    3768            0 :                                 time_overflow();
    3769            0 :                         return min_time;
    3770              :                 }
    3771            0 :         }
    3772              :         else
    3773              :         {
    3774            0 :                 if (max_time - t1 < t2)
    3775              :                 {
    3776            0 :                         if (t1 != max_time)
    3777            0 :                                 time_overflow();
    3778            0 :                         return max_time;
    3779              :                 }
    3780              :         }
    3781            0 :         return t1 + t2;
    3782            0 : }
    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            0 : rpytime(const struct rule *rp, zic_t wantedy)
    3791              : {
    3792            0 :         int                     m,
    3793              :                                 i;
    3794            0 :         zic_t           dayoff;                 /* with a nod to Margaret O. */
    3795            0 :         zic_t           t,
    3796              :                                 y;
    3797              : 
    3798            0 :         if (wantedy == ZIC_MIN)
    3799            0 :                 return min_time;
    3800            0 :         if (wantedy == ZIC_MAX)
    3801            0 :                 return max_time;
    3802            0 :         dayoff = 0;
    3803            0 :         m = TM_JANUARY;
    3804            0 :         y = EPOCH_YEAR;
    3805            0 :         if (y < wantedy)
    3806              :         {
    3807            0 :                 wantedy -= y;
    3808            0 :                 dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
    3809            0 :                 wantedy %= YEARSPERREPEAT;
    3810            0 :                 wantedy += y;
    3811            0 :         }
    3812            0 :         else if (wantedy < 0)
    3813              :         {
    3814            0 :                 dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
    3815            0 :                 wantedy %= YEARSPERREPEAT;
    3816            0 :         }
    3817            0 :         while (wantedy != y)
    3818              :         {
    3819            0 :                 if (wantedy > y)
    3820              :                 {
    3821            0 :                         i = len_years[isleap(y)];
    3822            0 :                         ++y;
    3823            0 :                 }
    3824              :                 else
    3825              :                 {
    3826            0 :                         --y;
    3827            0 :                         i = -len_years[isleap(y)];
    3828              :                 }
    3829            0 :                 dayoff = oadd(dayoff, i);
    3830              :         }
    3831            0 :         while (m != rp->r_month)
    3832              :         {
    3833            0 :                 i = len_months[isleap(y)][m];
    3834            0 :                 dayoff = oadd(dayoff, i);
    3835            0 :                 ++m;
    3836              :         }
    3837            0 :         i = rp->r_dayofmonth;
    3838            0 :         if (m == TM_FEBRUARY && i == 29 && !isleap(y))
    3839              :         {
    3840            0 :                 if (rp->r_dycode == DC_DOWLEQ)
    3841            0 :                         --i;
    3842              :                 else
    3843              :                 {
    3844            0 :                         error(_("use of 2/29 in non leap-year"));
    3845            0 :                         exit(EXIT_FAILURE);
    3846              :                 }
    3847            0 :         }
    3848            0 :         --i;
    3849            0 :         dayoff = oadd(dayoff, i);
    3850            0 :         if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ)
    3851              :         {
    3852            0 :                 zic_t           wday;
    3853              : 
    3854              : #define LDAYSPERWEEK    ((zic_t) DAYSPERWEEK)
    3855            0 :                 wday = EPOCH_WDAY;
    3856              : 
    3857              :                 /*
    3858              :                  * Don't trust mod of negative numbers.
    3859              :                  */
    3860            0 :                 if (dayoff >= 0)
    3861            0 :                         wday = (wday + dayoff) % LDAYSPERWEEK;
    3862              :                 else
    3863              :                 {
    3864            0 :                         wday -= ((-dayoff) % LDAYSPERWEEK);
    3865            0 :                         if (wday < 0)
    3866            0 :                                 wday += LDAYSPERWEEK;
    3867              :                 }
    3868            0 :                 while (wday != rp->r_wday)
    3869            0 :                         if (rp->r_dycode == DC_DOWGEQ)
    3870              :                         {
    3871            0 :                                 dayoff = oadd(dayoff, 1);
    3872            0 :                                 if (++wday >= LDAYSPERWEEK)
    3873            0 :                                         wday = 0;
    3874            0 :                                 ++i;
    3875            0 :                         }
    3876              :                         else
    3877              :                         {
    3878            0 :                                 dayoff = oadd(dayoff, -1);
    3879            0 :                                 if (--wday < 0)
    3880            0 :                                         wday = LDAYSPERWEEK - 1;
    3881            0 :                                 --i;
    3882              :                         }
    3883            0 :                 if (i < 0 || i >= len_months[isleap(y)][m])
    3884              :                 {
    3885            0 :                         if (noise)
    3886            0 :                                 warning(_("rule goes past start/end of month; \
    3887              : will not work with pre-2004 versions of zic"));
    3888            0 :                 }
    3889            0 :         }
    3890            0 :         if (dayoff < min_time / SECSPERDAY)
    3891            0 :                 return min_time;
    3892            0 :         if (dayoff > max_time / SECSPERDAY)
    3893            0 :                 return max_time;
    3894            0 :         t = (zic_t) dayoff * SECSPERDAY;
    3895            0 :         return tadd(t, rp->r_tod);
    3896            0 : }
    3897              : 
    3898              : static void
    3899            0 : newabbr(const char *string)
    3900              : {
    3901            0 :         int                     i;
    3902              : 
    3903            0 :         if (strcmp(string, GRANDPARENTED) != 0)
    3904              :         {
    3905            0 :                 const char *cp;
    3906            0 :                 const char *mp;
    3907              : 
    3908            0 :                 cp = string;
    3909            0 :                 mp = NULL;
    3910            0 :                 while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
    3911            0 :                            || *cp == '-' || *cp == '+')
    3912            0 :                         ++cp;
    3913            0 :                 if (noise && cp - string < 3)
    3914            0 :                         mp = _("time zone abbreviation has fewer than 3 characters");
    3915            0 :                 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
    3916            0 :                         mp = _("time zone abbreviation has too many characters");
    3917            0 :                 if (*cp != '\0')
    3918            0 :                         mp = _("time zone abbreviation differs from POSIX standard");
    3919            0 :                 if (mp != NULL)
    3920            0 :                         warning("%s (%s)", mp, string);
    3921            0 :         }
    3922            0 :         i = strlen(string) + 1;
    3923            0 :         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            0 :         strcpy(&chars[charcnt], string);
    3929            0 :         charcnt += i;
    3930            0 : }
    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            0 : mkdirs(char const *argname, bool ancestors)
    3938              : {
    3939            0 :         char       *name;
    3940            0 :         char       *cp;
    3941              : 
    3942            0 :         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            0 :         while (*cp == '/')
    3954            0 :                 cp++;
    3955              : 
    3956            0 :         while (cp && ((cp = strchr(cp, '/')) || !ancestors))
    3957              :         {
    3958            0 :                 if (cp)
    3959            0 :                         *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            0 :                 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            0 :                         int                     err = errno;
    3975              : 
    3976            0 :                         if (err != EEXIST && !itsdir(name))
    3977              :                         {
    3978            0 :                                 error(_("%s: Cannot create directory %s: %s"),
    3979            0 :                                           progname, name, strerror(err));
    3980            0 :                                 exit(EXIT_FAILURE);
    3981              :                         }
    3982            0 :                 }
    3983            0 :                 if (cp)
    3984            0 :                         *cp++ = '/';
    3985              :         }
    3986            0 :         free(name);
    3987            0 : }
    3988              : 
    3989              : 
    3990              : #ifdef WIN32
    3991              : /*
    3992              :  * To run on win32
    3993              :  */
    3994              : int
    3995              : link(const char *oldpath, const char *newpath)
    3996              : {
    3997              :         if (!CopyFile(oldpath, newpath, false))
    3998              :         {
    3999              :                 _dosmaperr(GetLastError());
    4000              :                 return -1;
    4001              :         }
    4002              :         return 0;
    4003              : }
    4004              : #endif
        

Generated by: LCOV version 2.3.2-1