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