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