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
21typedef 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
64static 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. */
75typedef intmax_t lineno;
76
77struct 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
113struct 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
134extern int getopt(int argc, char * const argv[],
135 const char * options);
136extern int link(const char * fromname, const char * toname);
137extern char * optarg;
138extern 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
154static void addtt(zic_t starttime, int type);
155static int addtype(zic_t, char const *, bool, bool, bool);
156static void leapadd(zic_t, int, int);
157static void adjleap(void);
158static void associate(void);
159static void dolink(const char *, const char *, bool);
160static char ** getfields(char * buf);
161static zic_t gethms(const char * string, const char * errstring);
162static zic_t getsave(char *, bool *);
163static void inexpires(char **, int);
164static void infile(const char * filename);
165static void inleap(char ** fields, int nfields);
166static void inlink(char ** fields, int nfields);
167static void inrule(char ** fields, int nfields);
168static bool inzcont(char ** fields, int nfields);
169static bool inzone(char ** fields, int nfields);
170static bool inzsub(char **, int, bool);
171static bool itsdir(char const *);
172static bool itssymlink(char const *);
173static bool is_alpha(char a);
174static char lowerit(char);
175static void mkdirs(char const *, bool);
176static void newabbr(const char * abbr);
177static zic_t oadd(zic_t t1, zic_t t2);
178static void outzone(const struct zone * zp, ptrdiff_t ntzones);
179static zic_t rpytime(const struct rule * rp, zic_t wantedy);
180static 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);
184static zic_t tadd(zic_t t1, zic_t t2);
185static bool yearistype(zic_t year, const char * type);
186
187/* Bound on length of what %z can expand to. */
188enum { 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
196enum { WORK_AROUND_QTBUG_53071 = true };
197#endif
198
199static int charcnt;
200static bool errors;
201static bool warnings;
202static const char * filename;
203static int leapcnt;
204static bool leapseen;
205static zic_t leapminyear;
206static zic_t leapmaxyear;
207static lineno linenum;
208static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
209static int max_format_len;
210static zic_t max_year;
211static zic_t min_year;
212static bool noise;
213static const char * rfilename;
214static lineno rlinenum;
215static const char * progname;
216static ptrdiff_t timecnt;
217static ptrdiff_t timecnt_alloc;
218static 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
305static struct rule * rules;
306static ptrdiff_t nrules; /* number of rules */
307static ptrdiff_t nrules_alloc;
308
309static struct zone * zones;
310static ptrdiff_t nzones; /* number of zones */
311static ptrdiff_t nzones_alloc;
312
313struct link {
314 const char * l_filename;
315 lineno l_linenum;
316 const char * l_from;
317 const char * l_to;
318};
319
320static struct link * links;
321static ptrdiff_t nlinks;
322static ptrdiff_t nlinks_alloc;
323
324struct lookup {
325 const char * l_word;
326 const int l_value;
327};
328
329static struct lookup const * byword(const char * string,
330 const struct lookup * lp);
331
332static struct lookup const zi_line_codes[] = {
333 { "Rule", LC_RULE },
334 { "Zone", LC_ZONE },
335 { "Link", LC_LINK },
336 { NULL, 0 }
337};
338static struct lookup const leap_line_codes[] = {
339 { "Leap", LC_LEAP },
340 { "Expires", LC_EXPIRES },
341 { NULL, 0}
342};
343
344static 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
360static 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
371static 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
382static struct lookup const begin_years[] = {
383 { "minimum", YR_MINIMUM },
384 { "maximum", YR_MAXIMUM },
385 { NULL, 0 }
386};
387
388static struct lookup const end_years[] = {
389 { "minimum", YR_MINIMUM },
390 { "maximum", YR_MAXIMUM },
391 { "only", YR_ONLY },
392 { NULL, 0 }
393};
394
395static struct lookup const leap_types[] = {
396 { "Rolling", true },
397 { "Stationary", false },
398 { NULL, 0 }
399};
400
401static 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
406static const int len_years[2] = {
407 DAYSPERNYEAR, DAYSPERLYEAR
408};
409
410static struct attype {
411 zic_t at;
412 bool dontmerge;
413 unsigned char type;
414} * attypes;
415static zic_t utoffs[TZ_MAX_TYPES];
416static char isdsts[TZ_MAX_TYPES];
417static unsigned char desigidx[TZ_MAX_TYPES];
418static bool ttisstds[TZ_MAX_TYPES];
419static bool ttisuts[TZ_MAX_TYPES];
420static char chars[TZ_MAX_CHARS];
421static zic_t trans[TZ_MAX_LEAPS];
422static zic_t corr[TZ_MAX_LEAPS];
423static char roll[TZ_MAX_LEAPS];
424
425/*
426** Memory allocation.
427*/
428
429static _Noreturn void
430memory_exhausted(const char *msg)
431{
432 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
433 exit(EXIT_FAILURE);
434}
435
436static ATTRIBUTE_PURE size_t
437size_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
444static ATTRIBUTE_PURE size_t
445align_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
455static char *
456strdup(char const *str)
457{
458 char *result = malloc(strlen(str) + 1);
459 return result ? strcpy(result, str) : result;
460}
461#endif
462
463static void *
464memcheck(void *ptr)
465{
466 if (ptr == NULL)
467 memory_exhausted(msg: strerror(errno));
468 return ptr;
469}
470
471static void * ATTRIBUTE_MALLOC
472emalloc(size_t size)
473{
474 return memcheck(ptr: malloc(size: size));
475}
476
477static void *
478erealloc(void *ptr, size_t size)
479{
480 return memcheck(ptr: realloc(ptr: ptr, size: size));
481}
482
483static char * ATTRIBUTE_MALLOC
484ecpyalloc (char const *str)
485{
486 return memcheck(ptr: strdup(s: str));
487}
488
489static void *
490growalloc(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: size_product(nitems: *nitems_alloc, itemsize));
501 }
502}
503
504/*
505** Error handling.
506*/
507
508static void
509eats(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
517static void
518eat(char const *name, lineno num)
519{
520 eats(name, num, NULL, rnum: -1);
521}
522
523static void ATTRIBUTE_FORMAT((printf, 1, 0))
524verror(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, format: string, arg: args);
534 if (rfilename != NULL)
535 fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"),
536 rfilename, rlinenum);
537 fprintf(stderr, format: "\n");
538}
539
540static void ATTRIBUTE_FORMAT((printf, 1, 2))
541error(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
550static void ATTRIBUTE_FORMAT((printf, 1, 2))
551warning(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
561static void
562close_file(FILE *stream, char const *dir, char const *name)
563{
564 char const *e = (ferror(stream: stream) ? _("I/O error")
565 : fclose(stream: stream) != 0 ? strerror(errno) : NULL);
566 if (e) {
567 fprintf(stderr, format: "%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
575static _Noreturn void
576usage(FILE *stream, int status)
577{
578 fprintf(stream: 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: 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. */
594static void
595change_directory (char const *dir)
596{
597 if (chdir(path: dir) != 0) {
598 int chdir_errno = errno;
599 if (chdir_errno == ENOENT) {
600 mkdirs(dir, false);
601 chdir_errno = chdir(path: 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(errnum: 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. */
614static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
615static 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. */
619static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
620static 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. */
623static zic_t leapexpires = -1;
624
625/* The time specified by an #expires comment, or negative if no such line. */
626static zic_t comment_leapexpires = -1;
627
628/* Set the time range of the output to TIMERANGE.
629 Return true if successful. */
630static bool
631timerange_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 (nptr: timerange + 1, endptr: &lo_end, base: 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 (nptr: lo_end + 2, endptr: &hi_end, base: 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
656static const char * psxrules;
657static const char * lcltime;
658static const char * directory;
659static const char * leapsec;
660static const char * tzdefault;
661static 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. */
666static int bloat;
667
668static bool
669want_bloat(void)
670{
671 return 0 <= bloat;
672}
673
674#ifndef ZIC_BLOAT_DEFAULT
675# define ZIC_BLOAT_DEFAULT "fat"
676#endif
677
678int
679main(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(mask: umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
687#endif
688#if HAVE_GETTEXT
689 setlocale(LC_ALL, locale: "");
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, format: "%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(s1: argv[k], s2: "--version") == 0) {
703 printf(format: "zic %s%s\n", PKGVERSION, TZVERSION);
704 close_file(stdout, NULL, NULL);
705 return EXIT_SUCCESS;
706 } else if (strcmp(s1: argv[k], s2: "--help") == 0) {
707 usage(stdout, EXIT_SUCCESS);
708 }
709 while ((c = getopt(argc: argc, argv: argv, shortopts: "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(s1: optarg, s2: "slim") == 0) {
715 if (0 < bloat)
716 error(_("incompatible -b options"));
717 bloat = -1;
718 } else if (strcmp(s1: optarg, s2: "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(timerange: 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(s1: argv[optind], s2: "=") == 0)
809 usage(stderr, EXIT_FAILURE); /* usage message by request */
810 if (bloat == 0)
811 bloat = strcmp(ZIC_BLOAT_DEFAULT, s2: "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(filename: leapsec);
821 adjleap();
822 }
823
824 for (k = optind; k < argc; k++)
825 infile(filename: argv[k]);
826 if (errors)
827 return EXIT_FAILURE;
828 associate();
829 change_directory(dir: 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(zp: &zones[i], ntzones: j - i);
837 }
838 /*
839 ** Make links.
840 */
841 for (i = 0; i < nlinks; ++i) {
842 eat(name: links[i].l_filename, num: 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(s1: links[i].l_to,
847 s2: links[j].l_from) == 0)
848 warning(_("link to link"));
849 }
850 if (lcltime != NULL) {
851 eat(_("command line"), num: 1);
852 dolink(lcltime, tzdefault, true);
853 }
854 if (psxrules != NULL) {
855 eat(_("command line"), num: 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
863static bool
864componentcheck(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
900static bool
901namecheck(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(s: benign, c: c)) {
920 warning(string: (strchr(s: printable_and_not_benign, c: 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, component_end: cp))
927 return false;
928 component = cp + 1;
929 }
930 }
931 return componentcheck(name, component, component_end: 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. */
938static char *
939relname(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(s: directory);
948 bool needslash = len && directory[len - 1] != '/';
949 linksize = len + needslash + strlen(s: from) + 1;
950 f = result = emalloc(size: linksize);
951 strcpy(dest: result, src: directory);
952 result[len] = '/';
953 strcpy(dest: result + len + needslash, src: 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(s: f + dir_len);
961 dotdotetcsize = 3 * dotdots + taillen + 1;
962 if (dotdotetcsize <= linksize) {
963 if (!result)
964 result = emalloc(size: dotdotetcsize);
965 for (i = 0; i < dotdots; i++)
966 memcpy(dest: result + 3 * i, src: "../", n: 3);
967 memmove(dest: result + 3 * dotdots, src: f + dir_len, n: 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. */
974static int
975hardlinkerr(char const *from, char const *to)
976{
977 int r = linkat(AT_FDCWD, from: from, AT_FDCWD, to: to, AT_SYMLINK_FOLLOW);
978 return r == 0 ? 0 : errno;
979}
980
981static void
982dolink(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(filename: 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(from: fromfield, to: tofield);
1007 if (link_errno == ENOENT && !todirs_made) {
1008 mkdirs(tofield, true);
1009 todirs_made = true;
1010 link_errno = hardlinkerr(from: fromfield, to: tofield);
1011 }
1012 if (link_errno != 0) {
1013 bool absolute = *fromfield == '/';
1014 char *linkalloc = absolute ? NULL : relname(from: fromfield, to: tofield);
1015 char const *contents = absolute ? fromfield : linkalloc;
1016 int symlink_errno = symlink(from: contents, to: 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(from: contents, to: tofield) == 0 ? 0 : errno;
1022 }
1023 free(ptr: linkalloc);
1024 if (symlink_errno == 0) {
1025 if (link_errno != ENOTSUP)
1026 warning(_("symbolic link used because hard link failed: %s"),
1027 strerror(errnum: link_errno));
1028 } else {
1029 FILE *fp, *tp;
1030 int c;
1031 fp = fopen(filename: fromfield, modes: "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(filename: tofield, modes: "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(stream: fp)) != EOF)
1046 putc(c: c, stream: tp);
1047 close_file(stream: fp, dir: directory, name: fromfield);
1048 close_file(stream: tp, dir: directory, name: tofield);
1049 if (link_errno != ENOTSUP)
1050 warning(_("copy used because hard link failed: %s"),
1051 strerror(errnum: link_errno));
1052 else if (symlink_errno != ENOTSUP)
1053 warning(_("copy used because symbolic link failed: %s"),
1054 strerror(errnum: symlink_errno));
1055 }
1056 }
1057}
1058
1059/* Return true if NAME is a directory. */
1060static bool
1061itsdir(char const *name)
1062{
1063 struct stat st;
1064 int res = stat(file: name, buf: &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(s: name);
1071 char *nameslashdot = emalloc(size: n + 3);
1072 bool dir;
1073 memcpy(dest: nameslashdot, src: name, n: n);
1074 strcpy(dest: &nameslashdot[n], src: &"/."[! (n && name[n - 1] != '/')]);
1075 dir = stat(file: nameslashdot, buf: &st) == 0 || errno == EOVERFLOW;
1076 free(ptr: nameslashdot);
1077 return dir;
1078 }
1079 return false;
1080}
1081
1082/* Return true if NAME is a symbolic link. */
1083static bool
1084itssymlink(char const *name)
1085{
1086 char c;
1087 return 0 <= readlink(path: name, buf: &c, len: 1);
1088}
1089
1090/*
1091** Associate sets of rules with zones.
1092*/
1093
1094/*
1095** Sort by rule name.
1096*/
1097
1098static int
1099rcomp(const void *cp1, const void *cp2)
1100{
1101 return strcmp(s1: ((const struct rule *) cp1)->r_name,
1102 s2: ((const struct rule *) cp2)->r_name);
1103}
1104
1105static void
1106associate(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(base: rules, nmemb: nrules, size: sizeof *rules, compar: rcomp);
1114 for (i = 0; i < nrules - 1; ++i) {
1115 if (strcmp(s1: rules[i].r_name,
1116 s2: rules[i + 1].r_name) != 0)
1117 continue;
1118 if (strcmp(s1: rules[i].r_filename,
1119 s2: rules[i + 1].r_filename) == 0)
1120 continue;
1121 eat(name: rules[i].r_filename, num: rules[i].r_linenum);
1122 warning(_("same rule name in multiple files"));
1123 eat(name: rules[i + 1].r_filename, num: rules[i + 1].r_linenum);
1124 warning(_("same rule name in multiple files"));
1125 for (j = i + 2; j < nrules; ++j) {
1126 if (strcmp(s1: rules[i].r_name,
1127 s2: rules[j].r_name) != 0)
1128 break;
1129 if (strcmp(s1: rules[i].r_filename,
1130 s2: rules[j].r_filename) == 0)
1131 continue;
1132 if (strcmp(s1: rules[i + 1].r_filename,
1133 s2: 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(s1: rp->r_name, s2: rules[out].r_name) != 0)
1149 break;
1150 for (i = 0; i < nzones; ++i) {
1151 zp = &zones[i];
1152 if (strcmp(s1: zp->z_rule, s2: 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(name: zp->z_filename, num: 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(string: "%s", _("%s in ruleless zone"));
1172 }
1173 }
1174 if (errors)
1175 exit(EXIT_FAILURE);
1176}
1177
1178static void
1179infile(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(s1: name, s2: "-") == 0) {
1191 name = _("standard input");
1192 fp = stdin;
1193 } else if ((fp = fopen(filename: name, modes: "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(s: buf, n: sizeof buf, stream: fp) != buf)
1204 break;
1205 cp = strchr(s: buf, c: '\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(s1: fields[nfields], s2: "-") == 0)
1217 fields[nfields] = &nada;
1218 ++nfields;
1219 }
1220 if (nfields == 0) {
1221 if (name == leapsec && *buf == '#')
1222 sscanf(s: buf, format: "#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(string: fields[0], lp: 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(ptr: fields);
1259 }
1260 close_file(stream: fp, NULL, name: 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
1273static zic_t
1274gethms(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(s: string,
1289 format: "%"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(string: "%s", errstring);
1307 return 0;
1308 }
1309 if (hh < 0 ||
1310 mm < 0 || mm >= MINSPERHOUR ||
1311 ss < 0 || ss > SECSPERMIN) {
1312 error(string: "%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))))
1322warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1323 return oadd(t1: sign * hh * SECSPERHOUR,
1324 t2: sign * (mm * SECSPERMIN + ss));
1325}
1326
1327static zic_t
1328getsave(char *field, bool *isdst)
1329{
1330 int dst = -1;
1331 zic_t save;
1332 size_t fieldlen = strlen(s: 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(string: field, _("invalid saved time"));
1341 *isdst = dst < 0 ? save != 0 : dst;
1342 return save;
1343}
1344
1345static void
1346inrule(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(field: fields[RF_SAVE], isdst: &r.r_isdst);
1366 rulesub(rp: &r, loyearp: fields[RF_LOYEAR], hiyearp: fields[RF_HIYEAR], typep: fields[RF_COMMAND],
1367 monthp: fields[RF_MONTH], dayp: fields[RF_DAY], timep: fields[RF_TOD]);
1368 r.r_name = ecpyalloc(str: fields[RF_NAME]);
1369 r.r_abbrvar = ecpyalloc(str: fields[RF_ABBRVAR]);
1370 if (max_abbrvar_len < strlen(s: r.r_abbrvar))
1371 max_abbrvar_len = strlen(s: r.r_abbrvar);
1372 rules = growalloc(ptr: rules, itemsize: sizeof *rules, nitems: nrules, nitems_alloc: &nrules_alloc);
1373 rules[nrules++] = r;
1374}
1375
1376static bool
1377inzone(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(s1: fields[ZF_NAME], s2: tzdefault) == 0) {
1386 error(
1387_("\"Zone %s\" line and -l option are mutually exclusive"),
1388 tzdefault);
1389 return false;
1390 }
1391 if (strcmp(s1: 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(s1: zones[i].z_name, s2: 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
1410static bool
1411inzcont(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
1420static bool
1421inzsub(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(name: 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(str: fields[ZF_NAME]);
1451 }
1452 z.z_filename = filename;
1453 z.z_linenum = linenum;
1454 z.z_stdoff = gethms(string: fields[i_stdoff], _("invalid UT offset"));
1455 if ((cp = strchr(s: fields[i_format], c: '%')) != 0) {
1456 if ((*++cp != 's' && *cp != 'z') || strchr(s: cp, c: '%')
1457 || strchr(s: fields[i_format], c: '/')) {
1458 error(_("invalid abbreviation format"));
1459 return false;
1460 }
1461 }
1462 z.z_rule = ecpyalloc(str: fields[i_rule]);
1463 z.z_format = cp1 = ecpyalloc(str: 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(s: z.z_format))
1472 max_format_len = strlen(s: 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(rp: &z.z_untilrule,
1478 loyearp: fields[i_untilyear],
1479 hiyearp: "only",
1480 typep: "",
1481 monthp: (nfields > i_untilmonth) ?
1482 fields[i_untilmonth] : "Jan",
1483 dayp: (nfields > i_untilday) ? fields[i_untilday] : "1",
1484 timep: (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1485 z.z_untiltime = rpytime(rp: &z.z_untilrule,
1486 wantedy: 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(ptr: zones, itemsize: sizeof *zones, nitems: nzones, nitems_alloc: &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
1508static zic_t
1509getleapdatetime(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(s: cp, format: "%"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(t1: dayoff, t2: i);
1546 }
1547 if ((lp = byword(string: fields[LP_MONTH], lp: 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(t1: dayoff, t2: i);
1556 ++j;
1557 }
1558 cp = fields[LP_DAY];
1559 if (sscanf(s: cp, format: "%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(t1: dayoff, t2: 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(string: fields[LP_TIME], _("invalid time of day"));
1575 t = tadd(t1: t, t2: tod);
1576 if (t < 0)
1577 error(_("leap second precedes Epoch"));
1578 return t;
1579}
1580
1581static void
1582inleap(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(string: fields[LP_ROLL], lp: 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(s1: fields[LP_CORR], s2: "+") == 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
1607static void
1608inexpires(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
1618static void
1619inlink(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(name: fields[LF_TO]))
1632 return;
1633 l.l_filename = filename;
1634 l.l_linenum = linenum;
1635 l.l_from = ecpyalloc(str: fields[LF_FROM]);
1636 l.l_to = ecpyalloc(str: fields[LF_TO]);
1637 links = growalloc(ptr: links, itemsize: sizeof *links, nitems: nlinks, nitems_alloc: &nlinks_alloc);
1638 links[nlinks++] = l;
1639}
1640
1641static void
1642rulesub(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(string: monthp, lp: 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(str: timep);
1660 if (*dp != '\0') {
1661 ep = dp + strlen(s: 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(string: dp, _("invalid time of day"));
1683 free(ptr: dp);
1684 /*
1685 ** Year work.
1686 */
1687 cp = loyearp;
1688 lp = byword(string: cp, lp: 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(s: cp, format: "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
1703 error(_("invalid starting year"));
1704 return;
1705 }
1706 cp = hiyearp;
1707 lp = byword(string: cp, lp: 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(s: cp, format: "%"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(str: 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(str: dayp);
1753 if ((lp = byword(string: dp, lp: 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(s: dp, c: '<')) != 0)
1759 rp->r_dycode = DC_DOWLEQ;
1760 else if ((ep = strchr(s: dp, c: '>')) != 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(ptr: dp);
1771 return;
1772 }
1773 if ((lp = byword(string: dp, lp: wday_names)) == NULL) {
1774 error(_("invalid weekday name"));
1775 free(ptr: dp);
1776 return;
1777 }
1778 rp->r_wday = lp->l_value;
1779 }
1780 if (sscanf(s: ep, format: "%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(ptr: dp);
1785 return;
1786 }
1787 }
1788 free(ptr: dp);
1789}
1790
1791static void
1792convert(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
1802static void
1803convert64(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
1813static void
1814puttzcode(const int_fast32_t val, FILE *const fp)
1815{
1816 char buf[4];
1817
1818 convert(val, buf);
1819 fwrite(ptr: buf, size: sizeof buf, n: 1, s: fp);
1820}
1821
1822static void
1823puttzcodepass(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(ptr: buf, size: sizeof buf, n: 1, s: fp);
1832 }
1833}
1834
1835static int
1836atcomp(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
1844struct timerange {
1845 int defaulttype;
1846 ptrdiff_t base, count;
1847 int leapbase, leapcount;
1848};
1849
1850static struct timerange
1851limitrange(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
1874static void
1875writezone(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(size: align_to(size: size_product(nitems: nats, itemsize: sizeof *ats + 1),
1891 alignment: _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(base: attypes, nmemb: timecnt, size: sizeof *attypes, compar: 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(t1: ats[i], t2: 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(s: string, c: '<')) {
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(r: rangeall, lo: lo_time, hi: hi_time, ats, types);
1982 range32 = limitrange(r: range64, INT32_MIN, INT32_MAX, ats, types);
1983
1984 /*
1985 ** Remove old file, if any, to snap links.
1986 */
1987 if (remove(filename: 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(filename: name, modes: "wb");
1997 if (!fp) {
1998 int fopen_errno = errno;
1999 if (fopen_errno == ENOENT && !dir_checked) {
2000 mkdirs(name, true);
2001 fp = fopen(filename: name, modes: "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(errnum: 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(s: omittype, true, n: 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(s: 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(s1: &thischars[j], s2: thisabbr) == 0)
2167 break;
2168 if (j == thischarcnt) {
2169 strcpy(dest: &thischars[thischarcnt], src: thisabbr);
2170 thischarcnt += strlen(s: 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(dest: tzh.tzh_magic, TZ_MAGIC, n: sizeof tzh.tzh_magic);
2183 tzh.tzh_version[0] = version;
2184 convert(val: utcnt, buf: tzh.tzh_ttisutcnt);
2185 convert(val: stdcnt, buf: tzh.tzh_ttisstdcnt);
2186 convert(val: thisleapcnt, buf: tzh.tzh_leapcnt);
2187 convert(val: locut + thistimecnt + hicut, buf: tzh.tzh_timecnt);
2188 convert(val: thistypecnt, buf: tzh.tzh_typecnt);
2189 convert(val: thischarcnt, buf: 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(val: 0, fp); /* utoff */
2203 putc(c: 0, stream: fp); /* dst */
2204 putc(c: 0, stream: fp); /* index of abbreviation */
2205 putc(c: 0, stream: 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(val: lo, fp, pass);
2216 for (i = thistimei; i < thistimelim; ++i) {
2217 zic_t at = ats[i] < lo ? lo : ats[i];
2218 puttzcodepass(val: at, fp, pass);
2219 }
2220 if (hicut)
2221 puttzcodepass(val: hi_time + 1, fp, pass);
2222 currenttype = 0;
2223 if (locut)
2224 putc(c: currenttype, stream: fp);
2225 for (i = thistimei; i < thistimelim; ++i) {
2226 currenttype = typemap[types[i]];
2227 putc(c: currenttype, stream: fp);
2228 }
2229 if (hicut)
2230 putc(c: currenttype, stream: 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(val: utoffs[h], fp);
2237 putc(c: isdsts[h], stream: fp);
2238 putc(c: indmap[desigidx[h]], stream: fp);
2239 }
2240 }
2241 if (thischarcnt != 0)
2242 fwrite(ptr: thischars, size: sizeof thischars[0],
2243 n: thischarcnt, s: 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(t1: trans[i], t2: -utoffs[j]);
2263 } else todo = trans[i];
2264 puttzcodepass(val: todo, fp, pass);
2265 puttzcode(val: corr[i], fp);
2266 }
2267 if (stdcnt != 0)
2268 for (i = old0; i < typecnt; i++)
2269 if (!omittype[i])
2270 putc(c: ttisstds[i], stream: fp);
2271 if (utcnt != 0)
2272 for (i = old0; i < typecnt; i++)
2273 if (!omittype[i])
2274 putc(c: ttisuts[i], stream: fp);
2275 }
2276 fprintf(stream: fp, format: "\n%s\n", string);
2277 close_file(stream: fp, dir: directory, name);
2278 free(ptr: ats);
2279}
2280
2281static char const *
2282abbroffset(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
2317static size_t
2318doabbr(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(s: format, c: '/');
2327 if (slashp == NULL) {
2328 char letterbuf[PERCENT_Z_LEN_BOUND + 1];
2329 if (zp->z_format_specifier == 'z')
2330 letters = abbroffset(buf: letterbuf, offset: zp->z_stdoff + save);
2331 else if (!letters)
2332 letters = "%s";
2333 sprintf(s: abbr, format: format, letters);
2334 } else if (isdst) {
2335 strcpy(dest: abbr, src: slashp + 1);
2336 } else {
2337 memcpy(dest: abbr, src: format, n: slashp - format);
2338 abbr[slashp - format] = '\0';
2339 }
2340 len = strlen(s: abbr);
2341 if (!doquotes)
2342 return len;
2343 for (cp = abbr; is_alpha(a: *cp); cp++)
2344 continue;
2345 if (len > 0 && *cp == '\0')
2346 return len;
2347 abbr[len + 2] = '\0';
2348 abbr[len + 1] = '>';
2349 memmove(dest: abbr + 1, src: abbr, n: len);
2350 abbr[0] = '<';
2351 return len + 2;
2352}
2353
2354static void
2355updateminmax(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
2363static int
2364stringoffset(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(s: result + len, format: "%d", hours);
2386 if (minutes != 0 || seconds != 0) {
2387 len += sprintf(s: result + len, format: ":%02d", minutes);
2388 if (seconds != 0)
2389 len += sprintf(s: result + len, format: ":%02d", seconds);
2390 }
2391 return len;
2392}
2393
2394static int
2395stringrule(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(s: result, format: "%d", total + rp->r_dayofmonth - 1);
2411 else
2412 result += sprintf(s: result, format: "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(s: result, format: "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, offset: 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
2461static int
2462rule_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
2475static int
2476stringzone(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(a: stdabbrrp, b: rp) < 0)
2525 stdabbrrp = rp;
2526 if (rule_cmp(a: stdrp, b: 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(abbr: result, zp, letters: abbrvar, false, save: 0, true);
2556 offsetlen = stringoffset(result: result + len, offset: - 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(abbr: result + len, zp, letters: dstrp->r_abbrvar,
2565 isdst: dstrp->r_isdst, save: dstrp->r_save, true);
2566 if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) {
2567 offsetlen = stringoffset(result: result + len,
2568 offset: - (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: result + len, rp: dstrp, save: dstrp->r_save, stdoff: 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(s: result + len);
2584 result[len++] = ',';
2585 c = stringrule(result: result + len, rp: stdrp, save: dstrp->r_save, stdoff: 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
2595static void
2596outzone(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(size: max_abbr_len + 1);
2628 ab = emalloc(size: max_abbr_len + 1);
2629 envvar = emalloc(size: 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(x: leapminyear);
2648 updateminmax(x: leapmaxyear + (leapmaxyear < ZIC_MAX));
2649 }
2650 for (i = 0; i < zonecount; ++i) {
2651 zp = &zpfirst[i];
2652 if (i < zonecount - 1)
2653 updateminmax(x: 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(x: rp->r_loyear);
2658 if (rp->r_hiwasnum)
2659 updateminmax(x: 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(result: 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(string: "%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(name: zp->z_filename, num: zp->z_linenum);
2740 *startbuf = '\0';
2741 startoff = zp->z_stdoff;
2742 if (zp->z_nrules == 0) {
2743 save = zp->z_save;
2744 doabbr(abbr: startbuf, zp, NULL, isdst: zp->z_isdst, save, false);
2745 type = addtype(oadd(t1: zp->z_stdoff, t2: 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(name: zp->z_filename, num: zp->z_linenum,
2763 rname: rp->r_filename, rnum: rp->r_linenum);
2764 rp->r_todo = year >= rp->r_loyear &&
2765 year <= rp->r_hiyear &&
2766 yearistype(year, type: rp->r_yrtype);
2767 if (rp->r_todo) {
2768 rp->r_temp = rpytime(rp, wantedy: 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(t1: untiltime,
2789 t2: -stdoff);
2790 if (!zp->z_untilrule.r_todisstd)
2791 untiltime = tadd(t1: untiltime,
2792 t2: -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(name: zp->z_filename, num: zp->z_linenum,
2804 rname: rp->r_filename, rnum: rp->r_linenum);
2805 offset = rp->r_todisut ? 0 : stdoff;
2806 if (!rp->r_todisstd)
2807 offset = oadd(t1: offset, t2: save);
2808 jtime = rp->r_temp;
2809 if (jtime == min_time ||
2810 jtime == max_time)
2811 continue;
2812 jtime = tadd(t1: jtime, t2: -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(name: zp->z_filename, num: zp->z_linenum,
2820 rname: rp->r_filename, rnum: rp->r_linenum);
2821 warning(string: "%s", dup_rules_msg);
2822 rp = &zp->z_rules[k];
2823 eats(name: zp->z_filename, num: zp->z_linenum,
2824 rname: rp->r_filename, rnum: rp->r_linenum);
2825 error(string: "%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(t1: zp->z_stdoff,
2840 t2: save);
2841 doabbr(abbr: startbuf, zp,
2842 letters: rp->r_abbrvar,
2843 isdst: rp->r_isdst,
2844 save: rp->r_save,
2845 false);
2846 continue;
2847 }
2848 if (*startbuf == '\0'
2849 && startoff == oadd(t1: zp->z_stdoff,
2850 t2: save)) {
2851 doabbr(abbr: startbuf,
2852 zp,
2853 letters: rp->r_abbrvar,
2854 isdst: rp->r_isdst,
2855 save: rp->r_save,
2856 false);
2857 }
2858 }
2859 eats(name: zp->z_filename, num: zp->z_linenum,
2860 rname: rp->r_filename, rnum: rp->r_linenum);
2861 doabbr(abbr: ab, zp, letters: rp->r_abbrvar,
2862 isdst: rp->r_isdst, save: rp->r_save, false);
2863 offset = oadd(t1: zp->z_stdoff, t2: 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(starttime: ktime, type);
2878 prevrp = rp;
2879 }
2880 }
2881 if (usestart) {
2882 if (*startbuf == '\0' &&
2883 zp->z_format != NULL &&
2884 strchr(s: zp->z_format, c: '%') == NULL &&
2885 strchr(s: zp->z_format, c: '/') == NULL)
2886 strcpy(dest: startbuf, src: zp->z_format);
2887 eat(name: zp->z_filename, num: zp->z_linenum);
2888 if (*startbuf == '\0')
2889error(_("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(t1: starttime, t2: -save);
2908 if (!startttisut)
2909 starttime = tadd(t1: starttime, t2: -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(rp: &xr, wantedy: max_year - 1)) {
2937 addtt(starttime: rpytime(rp: &xr, wantedy: max_year + 1),
2938 type: lastat ? lastat->type : defaulttype);
2939 attypes[timecnt - 1].dontmerge = true;
2940 }
2941 }
2942 writezone(name: zpfirst->z_name, string: envvar, version, defaulttype);
2943 free(ptr: startbuf);
2944 free(ptr: ab);
2945 free(ptr: envvar);
2946}
2947
2948static void
2949addtt(zic_t starttime, int type)
2950{
2951 attypes = growalloc(ptr: attypes, itemsize: sizeof *attypes, nitems: timecnt, nitems_alloc: &timecnt_alloc);
2952 attypes[timecnt].at = starttime;
2953 attypes[timecnt].dontmerge = false;
2954 attypes[timecnt].type = type;
2955 ++timecnt;
2956}
2957
2958static int
2959addtype(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(s1: &chars[j], s2: 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
2999static void
3000leapadd(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(dest: &trans[i + 1], src: &trans[i], n: (leapcnt - i) * sizeof *trans);
3012 memmove(dest: &corr[i + 1], src: &corr[i], n: (leapcnt - i) * sizeof *corr);
3013 memmove(dest: &roll[i + 1], src: &roll[i], n: (leapcnt - i) * sizeof *roll);
3014 trans[i] = t;
3015 corr[i] = correction;
3016 roll[i] = rolling;
3017 ++leapcnt;
3018}
3019
3020static void
3021adjleap(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(t1: trans[i], t2: 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(t1: leapexpires, t2: 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
3057static char *
3058shellquote(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
3070static bool
3071yearistype(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(size: 1 + 4 * strlen(s: yitcommand) + 2
3080 + INT_STRLEN_MAXIMUM(zic_t) + 2 + 4 * strlen(s: type) + 2);
3081 b = shellquote(b: buf, s: yitcommand);
3082 *b++ = ' ';
3083 b += sprintf(s: b, format: "%"PRIdZIC, year);
3084 *b++ = ' ';
3085 b = shellquote(b, s: type);
3086 *b = '\0';
3087 result = system(command: buf);
3088 if (WIFEXITED(result)) {
3089 int status = WEXITSTATUS(result);
3090 if (status <= 1) {
3091 free(ptr: 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? */
3102static bool
3103is_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? */
3114static bool
3115is_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. */
3134static char
3135lowerit(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 */
3152static ATTRIBUTE_PURE bool
3153ciequal(register const char *ap, register const char *bp)
3154{
3155 while (lowerit(a: *ap) == lowerit(a: *bp++))
3156 if (*ap++ == '\0')
3157 return true;
3158 return false;
3159}
3160
3161static ATTRIBUTE_PURE bool
3162itsabbr(register const char *abbr, register const char *word)
3163{
3164 if (lowerit(a: *abbr) != lowerit(a: *word))
3165 return false;
3166 ++word;
3167 while (*++abbr != '\0')
3168 do {
3169 if (*word == '\0')
3170 return false;
3171 } while (lowerit(a: *word++) != lowerit(a: *abbr));
3172 return true;
3173}
3174
3175/* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
3176
3177static ATTRIBUTE_PURE bool
3178ciprefix(char const *abbr, char const *word)
3179{
3180 do
3181 if (!*abbr)
3182 return true;
3183 while (lowerit(a: *abbr++) == lowerit(a: *word++));
3184
3185 return false;
3186}
3187
3188static const struct lookup *
3189byword(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(abbr: "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(ap: word, bp: 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(abbr: word, 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(abbr: word, 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
3243static char **
3244getfields(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: size_product(nitems: strlen(s: cp) + 1, itemsize: sizeof *array));
3253 nsubs = 0;
3254 for ( ; ; ) {
3255 while (is_space(a: *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(a: *cp));
3271 if (is_space(a: *cp))
3272 ++cp;
3273 *dp = '\0';
3274 }
3275 array[nsubs] = NULL;
3276 return array;
3277}
3278
3279static _Noreturn void
3280time_overflow(void)
3281{
3282 error(_("time overflow"));
3283 exit(EXIT_FAILURE);
3284}
3285
3286static ATTRIBUTE_PURE zic_t
3287oadd(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
3294static ATTRIBUTE_PURE zic_t
3295tadd(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
3318static zic_t
3319rpytime(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(t1: dayoff, t2: i);
3350 }
3351 while (m != rp->r_month) {
3352 i = len_months[isleap(y)][m];
3353 dayoff = oadd(t1: dayoff, t2: 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(t1: dayoff, t2: 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(t1: dayoff, t2: 1);
3385 if (++wday >= LDAYSPERWEEK)
3386 wday = 0;
3387 ++i;
3388 } else {
3389 dayoff = oadd(t1: dayoff, t2: -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; \
3397will 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(t1: t, t2: rp->r_tod);
3406}
3407
3408static void
3409newabbr(const char *string)
3410{
3411 register int i;
3412
3413 if (strcmp(s1: string, GRANDPARENTED) != 0) {
3414 register const char * cp;
3415 const char * mp;
3416
3417 cp = string;
3418 mp = NULL;
3419 while (is_alpha(a: *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')
3427mp = _("time zone abbreviation differs from POSIX standard");
3428 if (mp != NULL)
3429 warning(string: "%s (%s)", mp, string);
3430 }
3431 i = strlen(s: 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(dest: &chars[charcnt], src: 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. */
3444static void
3445mkdirs(char const *argname, bool ancestors)
3446{
3447 register char * name;
3448 register char * cp;
3449
3450 cp = name = ecpyalloc(str: 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(s: cp, c: '/')) || !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(path: 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(errnum: err));
3481 exit(EXIT_FAILURE);
3482 }
3483 }
3484 if (cp)
3485 *cp++ = '/';
3486 }
3487 free(ptr: name);
3488}
3489

source code of glibc/timezone/zic.c