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