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