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