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