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