LCOV - code coverage report
Current view: top level - src/timezone - zic.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 1040 1629 63.8 %
Date: 2017-09-29 13:40:31 Functions: 56 68 82.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11