S390: Fix building with --disable-mutli-arch [BZ #31196]
[platform/upstream/glibc.git] / timezone / zic.c
1 /* Compile .zi time zone data into TZif binary files.  */
2
3 /*
4 ** This file is in the public domain, so clarified as of
5 ** 2006-07-17 by Arthur David Olson.
6 */
7
8 #include "version.h"
9 #include "private.h"
10 #include "tzfile.h"
11
12 #include <fcntl.h>
13 #include <locale.h>
14 #include <stdarg.h>
15 #include <stddef.h>
16 #include <stdio.h>
17
18 #define ZIC_VERSION_PRE_2013 '2'
19 #define ZIC_VERSION     '3'
20
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
26
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 */
30
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
37
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
50
51 #if HAVE_SYS_WAIT_H
52 #include <sys/wait.h>   /* for WIFEXITED and WEXITSTATUS */
53 #endif /* HAVE_SYS_WAIT_H */
54
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 */
61
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
66
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
71
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;
76
77 struct rule {
78         const char *    r_filename;
79         lineno          r_linenum;
80         const char *    r_name;
81
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;
87
88         int             r_month;        /* 0..11 */
89
90         int             r_dycode;       /* see below */
91         int             r_dayofmonth;
92         int             r_wday;
93
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 */
100
101         bool            r_todo;         /* a rule to do (used in outzone) */
102         zic_t           r_temp;         /* used in outzone */
103 };
104
105 /*
106 **      r_dycode                r_dayofmonth    r_wday
107 */
108
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) */
112
113 struct zone {
114         const char *    z_filename;
115         lineno          z_linenum;
116
117         const char *    z_name;
118         zic_t           z_stdoff;
119         char *          z_rule;
120         const char *    z_format;
121         char            z_format_specifier;
122
123         bool            z_isdst;
124         zic_t           z_save;
125
126         struct rule *   z_rules;
127         ptrdiff_t       z_nrules;
128
129         struct rule     z_untilrule;
130         zic_t           z_untiltime;
131 };
132
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
140
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
153
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);
186
187 /* Bound on length of what %z can expand to.  */
188 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
189
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
198
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;
219
220 /*
221 ** Line codes.
222 */
223
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
229
230 /*
231 ** Which fields are which on a Zone line.
232 */
233
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
244
245 /*
246 ** Which fields are which on a Zone continuation line.
247 */
248
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
258
259 /*
260 ** Which files are which on a Rule line.
261 */
262
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
273
274 /*
275 ** Which fields are which on a Link line.
276 */
277
278 #define LF_FROM         1
279 #define LF_TO           2
280 #define LINK_FIELDS     3
281
282 /*
283 ** Which fields are which on a Leap line.
284 */
285
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
293
294 /* Expires lines are like Leap lines, except without CORR and ROLL fields.  */
295 #define EXPIRES_FIELDS  5
296
297 /*
298 ** Year synonyms.
299 */
300
301 #define YR_MINIMUM      0
302 #define YR_MAXIMUM      1
303 #define YR_ONLY         2
304
305 static struct rule *    rules;
306 static ptrdiff_t        nrules; /* number of rules */
307 static ptrdiff_t        nrules_alloc;
308
309 static struct zone *    zones;
310 static ptrdiff_t        nzones; /* number of zones */
311 static ptrdiff_t        nzones_alloc;
312
313 struct link {
314         const char *    l_filename;
315         lineno          l_linenum;
316         const char *    l_from;
317         const char *    l_to;
318 };
319
320 static struct link *    links;
321 static ptrdiff_t        nlinks;
322 static ptrdiff_t        nlinks_alloc;
323
324 struct lookup {
325         const char *    l_word;
326         const int       l_value;
327 };
328
329 static struct lookup const *    byword(const char * string,
330                                         const struct lookup * lp);
331
332 static struct lookup const zi_line_codes[] = {
333         { "Rule",       LC_RULE },
334         { "Zone",       LC_ZONE },
335         { "Link",       LC_LINK },
336         { NULL,         0 }
337 };
338 static struct lookup const leap_line_codes[] = {
339         { "Leap",       LC_LEAP },
340         { "Expires",    LC_EXPIRES },
341         { NULL,         0}
342 };
343
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 }
358 };
359
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 }
369 };
370
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 }
380 };
381
382 static struct lookup const      begin_years[] = {
383         { "minimum",    YR_MINIMUM },
384         { "maximum",    YR_MAXIMUM },
385         { NULL,         0 }
386 };
387
388 static struct lookup const      end_years[] = {
389         { "minimum",    YR_MINIMUM },
390         { "maximum",    YR_MAXIMUM },
391         { "only",       YR_ONLY },
392         { NULL,         0 }
393 };
394
395 static struct lookup const      leap_types[] = {
396         { "Rolling",    true },
397         { "Stationary", false },
398         { NULL,         0 }
399 };
400
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 }
404 };
405
406 static const int        len_years[2] = {
407         DAYSPERNYEAR, DAYSPERLYEAR
408 };
409
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];
424
425 /*
426 ** Memory allocation.
427 */
428
429 static _Noreturn void
430 memory_exhausted(const char *msg)
431 {
432         fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
433         exit(EXIT_FAILURE);
434 }
435
436 static ATTRIBUTE_PURE size_t
437 size_product(size_t nitems, size_t itemsize)
438 {
439         if (SIZE_MAX / itemsize < nitems)
440                 memory_exhausted(_("size overflow"));
441         return nitems * itemsize;
442 }
443
444 static ATTRIBUTE_PURE size_t
445 align_to(size_t size, size_t alignment)
446 {
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;
452 }
453
454 #if !HAVE_STRDUP
455 static char *
456 strdup(char const *str)
457 {
458   char *result = malloc(strlen(str) + 1);
459   return result ? strcpy(result, str) : result;
460 }
461 #endif
462
463 static void *
464 memcheck(void *ptr)
465 {
466         if (ptr == NULL)
467                 memory_exhausted(strerror(errno));
468         return ptr;
469 }
470
471 static void * ATTRIBUTE_MALLOC
472 emalloc(size_t size)
473 {
474   return memcheck(malloc(size));
475 }
476
477 static void *
478 erealloc(void *ptr, size_t size)
479 {
480   return memcheck(realloc(ptr, size));
481 }
482
483 static char * ATTRIBUTE_MALLOC
484 ecpyalloc (char const *str)
485 {
486   return memcheck(strdup(str));
487 }
488
489 static void *
490 growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
491 {
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));
501         }
502 }
503
504 /*
505 ** Error handling.
506 */
507
508 static void
509 eats(char const *name, lineno num, char const *rname, lineno rnum)
510 {
511         filename = name;
512         linenum = num;
513         rfilename = rname;
514         rlinenum = rnum;
515 }
516
517 static void
518 eat(char const *name, lineno num)
519 {
520         eats(name, num, NULL, -1);
521 }
522
523 static void ATTRIBUTE_FORMAT((printf, 1, 0))
524 verror(const char *const string, va_list args)
525 {
526         /*
527         ** Match the format of "cc" to allow sh users to
528         **      zic ... 2>&1 | error -t "*" -v
529         ** on BSD systems.
530         */
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");
538 }
539
540 static void ATTRIBUTE_FORMAT((printf, 1, 2))
541 error(const char *const string, ...)
542 {
543         va_list args;
544         va_start(args, string);
545         verror(string, args);
546         va_end(args);
547         errors = true;
548 }
549
550 static void ATTRIBUTE_FORMAT((printf, 1, 2))
551 warning(const char *const string, ...)
552 {
553         va_list args;
554         fprintf(stderr, _("warning: "));
555         va_start(args, string);
556         verror(string, args);
557         va_end(args);
558         warnings = true;
559 }
560
561 static void
562 close_file(FILE *stream, char const *dir, char const *name)
563 {
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 ? ": " : "",
570             e);
571     exit(EXIT_FAILURE);
572   }
573 }
574
575 static _Noreturn void
576 usage(FILE *stream, int status)
577 {
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);
589 }
590
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)
596 {
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;
602     }
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);
607     }
608   }
609 }
610
611 #define TIME_T_BITS_IN_FILE 64
612
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);
616
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);
621
622 /* The time specified by an Expires line, or negative if no such line.  */
623 static zic_t leapexpires = -1;
624
625 /* The time specified by an #expires comment, or negative if no such line.  */
626 static zic_t comment_leapexpires = -1;
627
628 /* Set the time range of the output to TIMERANGE.
629    Return true if successful.  */
630 static bool
631 timerange_option(char *timerange)
632 {
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;
640   }
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);
648   }
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;
654 }
655
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;
662
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;
667
668 static bool
669 want_bloat(void)
670 {
671   return 0 <= bloat;
672 }
673
674 #ifndef ZIC_BLOAT_DEFAULT
675 # define ZIC_BLOAT_DEFAULT "fat"
676 #endif
677
678 int
679 main(int argc, char **argv)
680 {
681         register int c, k;
682         register ptrdiff_t i, j;
683         bool timerange_given = false;
684
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;
700         }
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);
708                 }
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;
733                                 }
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;
743                                 }
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;
753                                 }
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;
762                                 }
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;
774                                 }
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;
784                                 }
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;
795                                 }
796                                 if (! timerange_option(optarg)) {
797                                   fprintf(stderr,
798 _("%s: invalid time range: %s\n"),
799                                           progname, optarg);
800                                   return EXIT_FAILURE;
801                                 }
802                                 timerange_given = true;
803                                 break;
804                         case 's':
805                                 warning(_("-s ignored"));
806                                 break;
807                 }
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";
818
819         if (optind < argc && leapsec != NULL) {
820                 infile(leapsec);
821                 adjleap();
822         }
823
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) {
831                 /*
832                 ** Find the next non-continuation zone entry.
833                 */
834                 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
835                         continue;
836                 outzone(&zones[i], j - i);
837         }
838         /*
839         ** Make links.
840         */
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"));
849         }
850         if (lcltime != NULL) {
851                 eat(_("command line"), 1);
852                 dolink(lcltime, tzdefault, true);
853         }
854         if (psxrules != NULL) {
855                 eat(_("command line"), 1);
856                 dolink(psxrules, TZDEFRULES, true);
857         }
858         if (warnings && (ferror(stderr) || fclose(stderr) != 0))
859           return EXIT_FAILURE;
860         return errors ? EXIT_FAILURE : EXIT_SUCCESS;
861 }
862
863 static bool
864 componentcheck(char const *name, char const *component,
865                char const *component_end)
866 {
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;
880         }
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;
887         }
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);
896         }
897         return true;
898 }
899
900 static bool
901 namecheck(const char *name)
902 {
903         register char const *cp;
904
905         /* Benign characters in a portable file name.  */
906         static char const benign[] =
907           "-/_"
908           "abcdefghijklmnopqrstuvwxyz"
909           "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
910
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:;<=>?@[\\]^`{|}~";
915
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);
924                 }
925                 if (c == '/') {
926                         if (!componentcheck(name, component, cp))
927                           return false;
928                         component = cp + 1;
929                 }
930         }
931         return componentcheck(name, component, cp);
932 }
933
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)
940 {
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);
954   }
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);
968   }
969   return result;
970 }
971
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)
976 {
977   int r = linkat(AT_FDCWD, from, AT_FDCWD, to, AT_SYMLINK_FOLLOW);
978   return r == 0 ? 0 : errno;
979 }
980
981 static void
982 dolink(char const *fromfield, char const *tofield, bool staysymlink)
983 {
984         bool todirs_made = false;
985         int link_errno;
986
987         /*
988         ** We get to be careful here since
989         ** there's a fair chance of root running us.
990         */
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);
995         }
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);
1005         }
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);
1011         }
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;
1022           }
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);
1037             }
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);
1044             }
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));
1055           }
1056         }
1057 }
1058
1059 /* Return true if NAME is a directory.  */
1060 static bool
1061 itsdir(char const *name)
1062 {
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;
1078         }
1079         return false;
1080 }
1081
1082 /* Return true if NAME is a symbolic link.  */
1083 static bool
1084 itssymlink(char const *name)
1085 {
1086   char c;
1087   return 0 <= readlink(name, &c, 1);
1088 }
1089
1090 /*
1091 ** Associate sets of rules with zones.
1092 */
1093
1094 /*
1095 ** Sort by rule name.
1096 */
1097
1098 static int
1099 rcomp(const void *cp1, const void *cp2)
1100 {
1101         return strcmp(((const struct rule *) cp1)->r_name,
1102                 ((const struct rule *) cp2)->r_name);
1103 }
1104
1105 static void
1106 associate(void)
1107 {
1108         register struct zone *  zp;
1109         register struct rule *  rp;
1110         register ptrdiff_t i, j, base, out;
1111
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;
1136                         }
1137                         i = j - 1;
1138                 }
1139         }
1140         for (i = 0; i < nzones; ++i) {
1141                 zp = &zones[i];
1142                 zp->z_rules = NULL;
1143                 zp->z_nrules = 0;
1144         }
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;
1156                 }
1157         }
1158         for (i = 0; i < nzones; ++i) {
1159                 zp = &zones[i];
1160                 if (zp->z_nrules == 0) {
1161                         /*
1162                         ** Maybe we have a local standard time offset.
1163                         */
1164                         eat(zp->z_filename, zp->z_linenum);
1165                         zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
1166                         /*
1167                         ** Note, though, that if there's no rule,
1168                         ** a '%s' in the format is a bad thing.
1169                         */
1170                         if (zp->z_format_specifier == 's')
1171                                 error("%s", _("%s in ruleless zone"));
1172                 }
1173         }
1174         if (errors)
1175                 exit(EXIT_FAILURE);
1176 }
1177
1178 static void
1179 infile(const char *name)
1180 {
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];
1189
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);
1195
1196                 fprintf(stderr, _("%s: Can't open %s: %s\n"),
1197                         progname, name, e);
1198                 exit(EXIT_FAILURE);
1199         }
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);
1209                 }
1210                 *cp = '\0';
1211                 fields = getfields(buf);
1212                 nfields = 0;
1213                 while (fields[nfields] != NULL) {
1214                         static char     nada;
1215
1216                         if (strcmp(fields[nfields], "-") == 0)
1217                                 fields[nfields] = &nada;
1218                         ++nfields;
1219                 }
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);
1256                         }
1257                 }
1258                 free(fields);
1259         }
1260         close_file(fp, NULL, filename);
1261         if (wantcont)
1262                 error(_("expected continuation line not found"));
1263 }
1264
1265 /*
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.
1271 */
1272
1273 static zic_t
1274 gethms(char const *string, char const *errstring)
1275 {
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;
1281
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;
1304         }
1305         if (!ok) {
1306                         error("%s", errstring);
1307                         return 0;
1308         }
1309         if (hh < 0 ||
1310                 mm < 0 || mm >= MINSPERHOUR ||
1311                 ss < 0 || ss > SECSPERMIN) {
1312                         error("%s", errstring);
1313                         return 0;
1314         }
1315         if (ZIC_MAX / SECSPERHOUR < hh) {
1316                 error(_("time overflow"));
1317                 return 0;
1318         }
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));
1325 }
1326
1327 static zic_t
1328 getsave(char *field, bool *isdst)
1329 {
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;
1338     }
1339   }
1340   save = gethms(field, _("invalid saved time"));
1341   *isdst = dst < 0 ? save != 0 : dst;
1342   return save;
1343 }
1344
1345 static void
1346 inrule(char **fields, int nfields)
1347 {
1348         static struct rule      r;
1349
1350         if (nfields != RULE_FIELDS) {
1351                 error(_("wrong number of fields on Rule line"));
1352                 return;
1353         }
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;
1362         }
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;
1374 }
1375
1376 static bool
1377 inzone(char **fields, int nfields)
1378 {
1379         register ptrdiff_t i;
1380
1381         if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1382                 error(_("wrong number of fields on Zone line"));
1383                 return false;
1384         }
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;
1390         }
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;
1396         }
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;
1406                 }
1407         return inzsub(fields, nfields, false);
1408 }
1409
1410 static bool
1411 inzcont(char **fields, int nfields)
1412 {
1413         if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1414                 error(_("wrong number of fields on Zone continuation line"));
1415                 return false;
1416         }
1417         return inzsub(fields, nfields, true);
1418 }
1419
1420 static bool
1421 inzsub(char **fields, int nfields, bool iscont)
1422 {
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;
1430
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]);
1451         }
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;
1460                 }
1461         }
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';
1470         }
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",
1480                         "",
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"
1495                                         ));
1496                                 return false;
1497                 }
1498         }
1499         zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1500         zones[nzones++] = z;
1501         /*
1502         ** If there was an UNTIL field on this line,
1503         ** there's more information about the zone on the next line.
1504         */
1505         return hasuntil;
1506 }
1507
1508 static zic_t
1509 getleapdatetime(char **fields, int nfields, bool expire_line)
1510 {
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;
1519
1520         dayoff = 0;
1521         cp = fields[LP_YEAR];
1522         if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
1523                 /*
1524                 ** Leapin' Lizards!
1525                 */
1526                 error(_("invalid leaping year"));
1527                 return -1;
1528         }
1529         if (!expire_line) {
1530             if (!leapseen || leapmaxyear < year)
1531                 leapmaxyear = year;
1532             if (!leapseen || leapminyear > year)
1533                 leapminyear = year;
1534             leapseen = true;
1535         }
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)];
1544                 }
1545                 dayoff = oadd(dayoff, i);
1546         }
1547         if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1548                 error(_("invalid month name"));
1549                 return -1;
1550         }
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;
1557         }
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;
1563         }
1564         dayoff = oadd(dayoff, day - 1);
1565         if (dayoff < min_time / SECSPERDAY) {
1566                 error(_("time too small"));
1567                 return -1;
1568         }
1569         if (dayoff > max_time / SECSPERDAY) {
1570                 error(_("time too large"));
1571                 return -1;
1572         }
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;
1579 }
1580
1581 static void
1582 inleap(char **fields, int nfields)
1583 {
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);
1602       }
1603     }
1604   }
1605 }
1606
1607 static void
1608 inexpires(char **fields, int nfields)
1609 {
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);
1616 }
1617
1618 static void
1619 inlink(char **fields, int nfields)
1620 {
1621         struct link     l;
1622
1623         if (nfields != LINK_FIELDS) {
1624                 error(_("wrong number of fields on Link line"));
1625                 return;
1626         }
1627         if (*fields[LF_FROM] == '\0') {
1628                 error(_("blank FROM field on Link line"));
1629                 return;
1630         }
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;
1639 }
1640
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)
1645 {
1646         register const struct lookup *  lp;
1647         register const char *           cp;
1648         register char *                 dp;
1649         register char *                 ep;
1650         char xs;
1651
1652         if ((lp = byword(monthp, mon_names)) == NULL) {
1653                 error(_("invalid month name"));
1654                 return;
1655         }
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;
1680                 }
1681         }
1682         rp->r_tod = gethms(dp, _("invalid time of day"));
1683         free(dp);
1684         /*
1685         ** Year work.
1686         */
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;
1705         }
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;
1727         }
1728         if (rp->r_loyear > rp->r_hiyear) {
1729                 error(_("starting year greater than ending year"));
1730                 return;
1731         }
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;
1738                 }
1739                 warning(_("year type \"%s\" is obsolete; use \"-\" instead"),
1740                         typep);
1741                 rp->r_yrtype = ecpyalloc(typep);
1742         }
1743         /*
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
1751         */
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;
1765                 }
1766                 if (rp->r_dycode != DC_DOM) {
1767                         *ep++ = 0;
1768                         if (*ep++ != '=') {
1769                                 error(_("invalid day of month"));
1770                                 free(dp);
1771                                 return;
1772                         }
1773                         if ((lp = byword(dp, wday_names)) == NULL) {
1774                                 error(_("invalid weekday name"));
1775                                 free(dp);
1776                                 return;
1777                         }
1778                         rp->r_wday = lp->l_value;
1779                 }
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;
1786                 }
1787         }
1788         free(dp);
1789 }
1790
1791 static void
1792 convert(const int_fast32_t val, char *const buf)
1793 {
1794         register int    i;
1795         register int    shift;
1796         unsigned char *const b = (unsigned char *) buf;
1797
1798         for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1799                 b[i] = val >> shift;
1800 }
1801
1802 static void
1803 convert64(const zic_t val, char *const buf)
1804 {
1805         register int    i;
1806         register int    shift;
1807         unsigned char *const b = (unsigned char *) buf;
1808
1809         for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1810                 b[i] = val >> shift;
1811 }
1812
1813 static void
1814 puttzcode(const int_fast32_t val, FILE *const fp)
1815 {
1816         char    buf[4];
1817
1818         convert(val, buf);
1819         fwrite(buf, sizeof buf, 1, fp);
1820 }
1821
1822 static void
1823 puttzcodepass(zic_t val, FILE *fp, int pass)
1824 {
1825   if (pass == 1)
1826     puttzcode(val, fp);
1827   else {
1828         char    buf[8];
1829
1830         convert64(val, buf);
1831         fwrite(buf, sizeof buf, 1, fp);
1832   }
1833 }
1834
1835 static int
1836 atcomp(const void *avp, const void *bvp)
1837 {
1838         const zic_t     a = ((const struct attype *) avp)->at;
1839         const zic_t     b = ((const struct attype *) bvp)->at;
1840
1841         return (a < b) ? -1 : (a > b);
1842 }
1843
1844 struct timerange {
1845   int defaulttype;
1846   ptrdiff_t base, count;
1847   int leapbase, leapcount;
1848 };
1849
1850 static struct timerange
1851 limitrange(struct timerange r, zic_t lo, zic_t hi,
1852            zic_t const *ats, unsigned char const *types)
1853 {
1854   while (0 < r.count && ats[r.base] < lo) {
1855     r.defaulttype = types[r.base];
1856     r.count--;
1857     r.base++;
1858   }
1859   while (0 < r.leapcount && trans[r.leapbase] < lo) {
1860     r.leapcount--;
1861     r.leapbase++;
1862   }
1863
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--;
1869   }
1870
1871   return r;
1872 }
1873
1874 static void
1875 writezone(const char *const name, const char *const string, char version,
1876           int defaulttype)
1877 {
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;
1887
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;
1895
1896         /*
1897         ** Sort.
1898         */
1899         if (timecnt > 1)
1900                 qsort(attypes, timecnt, sizeof *attypes, atcomp);
1901         /*
1902         ** Optimize.
1903         */
1904         {
1905                 ptrdiff_t fromi, toi;
1906
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;
1919                         }
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];
1929                 }
1930                 timecnt = toi;
1931         }
1932
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"));
1941         }
1942         /*
1943         ** Transfer.
1944         */
1945         for (i = 0; i < timecnt; ++i) {
1946                 ats[i] = attypes[i].at;
1947                 types[i] = attypes[i].type;
1948         }
1949
1950         /*
1951         ** Correct for leap seconds.
1952         */
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;
1959                         }
1960         }
1961
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++;
1975         }
1976
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);
1983
1984         /*
1985         ** Remove old file, if any, to snap links.
1986         */
1987         if (remove(name) == 0)
1988                 dir_checked = true;
1989         else if (errno != ENOENT) {
1990                 const char *e = strerror(errno);
1991
1992                 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1993                         progname, directory, name, e);
1994                 exit(EXIT_FAILURE);
1995         }
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;
2003           }
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);
2008           }
2009         }
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];
2024
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);
2039
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;
2056                 }
2057                 if (toomanytimes)
2058                   error(_("too many transition times"));
2059
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;
2071                 }
2072
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;
2080                 }
2081                 memset(omittype, true, typecnt);
2082                 omittype[thisdefaulttype] = false;
2083                 for (i = thistimei; i < thistimelim; i++)
2084                   omittype[types[i]] = false;
2085
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);
2091
2092 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
2093                 /*
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).
2100                 */
2101                 if (want_bloat()) {
2102                         register int    mrudst, mrustd, hidst, histd, type;
2103
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;
2117                           }
2118                         }
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;
2129                         }
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;
2140                         }
2141                 }
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++;
2149
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;
2155
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;
2171                         }
2172                         indmap[desigidx[i]] = j;
2173                 }
2174                 if (pass == 1 && !want_bloat()) {
2175                   utcnt = stdcnt = thisleapcnt = 0;
2176                   thistimecnt = - (locut + hicut);
2177                   thistypecnt = thischarcnt = 1;
2178                   thistimelim = thistimei;
2179                 }
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;
2207                 }
2208
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;
2213
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);
2219                 }
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);
2228                 }
2229                 if (hicut)
2230                   putc(currenttype, fp);
2231
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);
2239                   }
2240                 }
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;
2246
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;
2254                                                 }
2255                                 } else {
2256                                         j = 1;
2257                                         while (j < timecnt &&
2258                                                 trans[i] >= ats[j])
2259                                                         ++j;
2260                                         j = types[j - 1];
2261                                 }
2262                                 todo = tadd(trans[i], -utoffs[j]);
2263                         } else  todo = trans[i];
2264                         puttzcodepass(todo, fp, pass);
2265                         puttzcode(corr[i], fp);
2266                 }
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);
2275         }
2276         fprintf(fp, "\n%s\n", string);
2277         close_file(fp, directory, name);
2278         free(ats);
2279 }
2280
2281 static char const *
2282 abbroffset(char *buf, zic_t offset)
2283 {
2284   char sign = '+';
2285   int seconds, minutes;
2286
2287   if (offset < 0) {
2288     offset = -offset;
2289     sign = '-';
2290   }
2291
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;
2310       }
2311     }
2312     *p = '\0';
2313     return buf;
2314   }
2315 }
2316
2317 static size_t
2318 doabbr(char *abbr, struct zone const *zp, char const *letters,
2319        bool isdst, zic_t save, bool doquotes)
2320 {
2321         register char * cp;
2322         register char * slashp;
2323         register size_t len;
2324         char const *format = zp->z_format;
2325
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';
2339         }
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;
2352 }
2353
2354 static void
2355 updateminmax(const zic_t x)
2356 {
2357         if (min_year > x)
2358                 min_year = x;
2359         if (max_year < x)
2360                 max_year = x;
2361 }
2362
2363 static int
2364 stringoffset(char *result, zic_t offset)
2365 {
2366         register int    hours;
2367         register int    minutes;
2368         register int    seconds;
2369         bool negative = offset < 0;
2370         int len = negative;
2371
2372         if (negative) {
2373                 offset = -offset;
2374                 result[0] = '-';
2375         }
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;
2384         }
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);
2390         }
2391         return len;
2392 }
2393
2394 static int
2395 stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff)
2396 {
2397         register zic_t  tod = rp->r_tod;
2398         register int    compat = 0;
2399
2400         if (rp->r_dycode == DC_DOM) {
2401                 register int    month, total;
2402
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;
2417
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;
2435                         }
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);
2441         }
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;
2456                 }
2457         }
2458         return compat;
2459 }
2460
2461 static int
2462 rule_cmp(struct rule const *a, struct rule const *b)
2463 {
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;
2473 }
2474
2475 static int
2476 stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
2477 {
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;
2489
2490         result[0] = '\0';
2491
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;
2496
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;
2513                 }
2514         }
2515         if (stdrp == NULL && dstrp == NULL) {
2516                 /*
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.
2520                 */
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;
2528                 }
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;
2550                 }
2551         }
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;
2560         }
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;
2572           }
2573           len += offsetlen;
2574         }
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;
2580         }
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;
2589         }
2590         if (compat < c)
2591                 compat = c;
2592         return compat;
2593 }
2594
2595 static void
2596 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
2597 {
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;
2624
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);
2632         /*
2633         ** Now. . .finally. . .generate some useful data!
2634         */
2635         timecnt = 0;
2636         typecnt = 0;
2637         charcnt = 0;
2638         prodstic = zonecount == 1;
2639         /*
2640         ** Thanks to Earl Chew
2641         ** for noting the need to unconditionally initialize startttisstd.
2642         */
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));
2649         }
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;
2662                 }
2663         }
2664         /*
2665         ** Generate lots of data if a rule can't cover all future times.
2666         */
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);
2682                 }
2683         }
2684         if (do_extend) {
2685                 /*
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.
2697                 */
2698                 enum { years_of_observations = YEARSPERREPEAT + 2 };
2699
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;
2706                 /*
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.
2711                 */
2712                 if (prodstic) {
2713                         min_year = 1900;
2714                         max_year = min_year + years_of_observations;
2715                 }
2716         }
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;
2725         }
2726
2727         for (i = 0; i < zonecount; ++i) {
2728                 struct rule *prevrp = NULL;
2729                 /*
2730                 ** A guess that may well be corrected later.
2731                 */
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;
2756                         /*
2757                         ** Mark which rules to do in the current year.
2758                         ** For those to do, calculate rpytime(rp, year);
2759                         */
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);
2772                                 }
2773                         }
2774                         for ( ; ; ) {
2775                                 register ptrdiff_t k;
2776                                 register zic_t  jtime, ktime;
2777                                 register zic_t  offset;
2778
2779                                 INITIALIZE(ktime);
2780                                 if (useuntil) {
2781                                         /*
2782                                         ** Turn untiltime into UT
2783                                         ** assuming the current stdoff and
2784                                         ** save values.
2785                                         */
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);
2793                                 }
2794                                 /*
2795                                 ** Find the rule (of those to do, if any)
2796                                 ** that takes effect earliest in the year.
2797                                 */
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);
2826                                         }
2827                                 }
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;
2847                                         }
2848                                         if (*startbuf == '\0'
2849                                             && startoff == oadd(zp->z_stdoff,
2850                                                                 save)) {
2851                                                         doabbr(startbuf,
2852                                                                 zp,
2853                                                                 rp->r_abbrvar,
2854                                                                 rp->r_isdst,
2855                                                                 rp->r_save,
2856                                                                 false);
2857                                         }
2858                                 }
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;
2879                         }
2880                 }
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);
2897                         }
2898                 }
2899                 /*
2900                 ** Now we may get to set starttime for the next zone line.
2901                 */
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);
2910                 }
2911         }
2912         if (defaulttype < 0)
2913           defaulttype = 0;
2914         if (0 <= lastatmax)
2915           attypes[lastatmax].dontmerge = true;
2916         if (do_extend) {
2917                 /*
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.
2926                 */
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;
2940                 }
2941         }
2942         writezone(zpfirst->z_name, envvar, version, defaulttype);
2943         free(startbuf);
2944         free(ab);
2945         free(envvar);
2946 }
2947
2948 static void
2949 addtt(zic_t starttime, int type)
2950 {
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;
2956 }
2957
2958 static int
2959 addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
2960 {
2961         register int    i, j;
2962
2963         if (! (-1L - 2147483647L <= utoff && utoff <= 2147483647L)) {
2964                 error(_("UT offset out of range"));
2965                 exit(EXIT_FAILURE);
2966         }
2967         if (!want_bloat())
2968           ttisstd = ttisut = false;
2969
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;
2981         }
2982         /*
2983         ** There isn't one; add a new one, unless there are already too
2984         ** many.
2985         */
2986         if (typecnt >= TZ_MAX_TYPES) {
2987                 error(_("too many local time types"));
2988                 exit(EXIT_FAILURE);
2989         }
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;
2997 }
2998
2999 static void
3000 leapadd(zic_t t, int correction, int rolling)
3001 {
3002         register int i;
3003
3004         if (TZ_MAX_LEAPS <= leapcnt) {
3005                 error(_("too many leap seconds"));
3006                 exit(EXIT_FAILURE);
3007         }
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;
3018 }
3019
3020 static void
3021 adjleap(void)
3022 {
3023         register int    i;
3024         register zic_t  last = 0;
3025         register zic_t  prevtrans = 0;
3026
3027         /*
3028         ** propagate leap seconds forward
3029         */
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);
3034                 }
3035                 prevtrans = trans[i];
3036                 trans[i] = tadd(trans[i], last);
3037                 last = corr[i] += last;
3038         }
3039
3040         if (leapexpires < 0) {
3041           leapexpires = comment_leapexpires;
3042           if (0 <= leapexpires)
3043             warning(_("\"#expires\" is obsolescent; use \"Expires\""));
3044         }
3045
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);
3051           }
3052           if (leapexpires <= hi_time)
3053             hi_time = leapexpires - 1;
3054         }
3055 }
3056
3057 static char *
3058 shellquote(char *b, char const *s)
3059 {
3060   *b++ = '\'';
3061   while (*s) {
3062     if (*s == '\'')
3063       *b++ = '\'', *b++ = '\\', *b++ = '\'';
3064     *b++ = *s++;
3065   }
3066   *b++ = '\'';
3067   return b;
3068 }
3069
3070 static bool
3071 yearistype(zic_t year, const char *type)
3072 {
3073         char *buf;
3074         char *b;
3075         int result;
3076
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;
3093           }
3094         }
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);
3099 }
3100
3101 /* Is A a space character in the C locale?  */
3102 static bool
3103 is_space(char a)
3104 {
3105         switch (a) {
3106           default:
3107                 return false;
3108           case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
3109                 return true;
3110         }
3111 }
3112
3113 /* Is A an alphabetic character in the C locale?  */
3114 static bool
3115 is_alpha(char a)
3116 {
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;
3129         }
3130 }
3131
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)
3136 {
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';
3148         }
3149 }
3150
3151 /* case-insensitive equality */
3152 static ATTRIBUTE_PURE bool
3153 ciequal(register const char *ap, register const char *bp)
3154 {
3155         while (lowerit(*ap) == lowerit(*bp++))
3156                 if (*ap++ == '\0')
3157                         return true;
3158         return false;
3159 }
3160
3161 static ATTRIBUTE_PURE bool
3162 itsabbr(register const char *abbr, register const char *word)
3163 {
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;
3173 }
3174
3175 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case.  */
3176
3177 static ATTRIBUTE_PURE bool
3178 ciprefix(char const *abbr, char const *word)
3179 {
3180   do
3181     if (!*abbr)
3182       return true;
3183   while (lowerit(*abbr++) == lowerit(*word++));
3184
3185   return false;
3186 }
3187
3188 static const struct lookup *
3189 byword(const char *word, const struct lookup *table)
3190 {
3191         register const struct lookup *  foundlp;
3192         register const struct lookup *  lp;
3193
3194         if (word == NULL || table == NULL)
3195                 return NULL;
3196
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;
3207           }
3208         }
3209
3210         /*
3211         ** Look for exact match.
3212         */
3213         for (lp = table; lp->l_word != NULL; ++lp)
3214                 if (ciequal(word, lp->l_word))
3215                         return lp;
3216         /*
3217         ** Look for inexact match.
3218         */
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 */
3225                 }
3226
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;
3235               }
3236               pre_2017c_match = true;
3237             }
3238         }
3239
3240         return foundlp;
3241 }
3242
3243 static char **
3244 getfields(register char *cp)
3245 {
3246         register char *         dp;
3247         register char **        array;
3248         register int            nsubs;
3249
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);
3269                                 }
3270                 } while (*cp && *cp != '#' && !is_space(*cp));
3271                 if (is_space(*cp))
3272                         ++cp;
3273                 *dp = '\0';
3274         }
3275         array[nsubs] = NULL;
3276         return array;
3277 }
3278
3279 static _Noreturn void
3280 time_overflow(void)
3281 {
3282   error(_("time overflow"));
3283   exit(EXIT_FAILURE);
3284 }
3285
3286 static ATTRIBUTE_PURE zic_t
3287 oadd(zic_t t1, zic_t t2)
3288 {
3289         if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
3290           time_overflow();
3291         return t1 + t2;
3292 }
3293
3294 static ATTRIBUTE_PURE zic_t
3295 tadd(zic_t t1, zic_t t2)
3296 {
3297   if (t1 < 0) {
3298     if (t2 < min_time - t1) {
3299       if (t1 != min_time)
3300         time_overflow();
3301       return min_time;
3302     }
3303   } else {
3304     if (max_time - t1 < t2) {
3305       if (t1 != max_time)
3306         time_overflow();
3307       return max_time;
3308     }
3309   }
3310   return t1 + t2;
3311 }
3312
3313 /*
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.
3316 */
3317
3318 static zic_t
3319 rpytime(const struct rule *rp, zic_t wantedy)
3320 {
3321         register int    m, i;
3322         register zic_t  dayoff;                 /* with a nod to Margaret O. */
3323         register zic_t  t, y;
3324
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;
3340         }
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)];
3348                 }
3349                 dayoff = oadd(dayoff, i);
3350         }
3351         while (m != rp->r_month) {
3352                 i = len_months[isleap(y)][m];
3353                 dayoff = oadd(dayoff, i);
3354                 ++m;
3355         }
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);
3363                 }
3364         }
3365         --i;
3366         dayoff = oadd(dayoff, i);
3367         if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
3368                 register zic_t  wday;
3369
3370 #define LDAYSPERWEEK    ((zic_t) DAYSPERWEEK)
3371                 wday = EPOCH_WDAY;
3372                 /*
3373                 ** Don't trust mod of negative numbers.
3374                 */
3375                 if (dayoff >= 0)
3376                         wday = (wday + dayoff) % LDAYSPERWEEK;
3377                 else {
3378                         wday -= ((-dayoff) % LDAYSPERWEEK);
3379                         if (wday < 0)
3380                                 wday += LDAYSPERWEEK;
3381                 }
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;
3393                         }
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"));
3398                 }
3399         }
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);
3406 }
3407
3408 static void
3409 newabbr(const char *string)
3410 {
3411         register int    i;
3412
3413         if (strcmp(string, GRANDPARENTED) != 0) {
3414                 register const char *   cp;
3415                 const char *            mp;
3416
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);
3430         }
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);
3435         }
3436         strcpy(&chars[charcnt], string);
3437         charcnt += i;
3438 }
3439
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)
3446 {
3447         register char * name;
3448         register char * cp;
3449
3450         cp = name = ecpyalloc(argname);
3451
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.  */
3458
3459         /* Do not mkdir a root directory, as it must exist.  */
3460         while (*cp == '/')
3461           cp++;
3462
3463         while (cp && ((cp = strchr(cp, '/')) || !ancestors)) {
3464                 if (cp)
3465                   *cp = '\0';
3466                 /*
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.
3472                 */
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);
3482                         }
3483                 }
3484                 if (cp)
3485                   *cp++ = '/';
3486         }
3487         free(name);
3488 }