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