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