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