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