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