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