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