Remove environment sensitivity in pl/tcl regression test.
[pgsql.git] / src / timezone / zic.c
blobd605c721ecf703379d0b990a1b04187dd5989cce
1 /* Compile .zi time zone data into TZif binary files. */
3 /*
4 * This file is in the public domain, so clarified as of
5 * 2006-07-17 by Arthur David Olson.
7 * IDENTIFICATION
8 * src/timezone/zic.c
9 */
11 #include "postgres_fe.h"
13 #include <fcntl.h>
14 #include <sys/stat.h>
15 #include <time.h>
17 #include "pg_getopt.h"
19 #include "private.h"
20 #include "tzfile.h"
22 #define ZIC_VERSION_PRE_2013 '2'
23 #define ZIC_VERSION '3'
25 typedef int64 zic_t;
26 #define ZIC_MIN PG_INT64_MIN
27 #define ZIC_MAX PG_INT64_MAX
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 */
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 /* Port to native MS-Windows and to ancient UNIX. */
41 #if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT
42 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
43 #endif
45 /* The maximum ptrdiff_t value, for pre-C99 platforms. */
46 #ifndef PTRDIFF_MAX
47 static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
48 #endif
51 * The type for line numbers. In Postgres, use %d to format them; upstream
52 * uses PRIdMAX but we prefer not to rely on that, not least because it
53 * results in platform-dependent strings to be translated.
55 typedef int lineno_t;
57 struct rule
59 const char *r_filename;
60 lineno_t r_linenum;
61 const char *r_name;
63 zic_t r_loyear; /* for example, 1986 */
64 zic_t r_hiyear; /* for example, 1986 */
65 bool r_lowasnum;
66 bool r_hiwasnum;
68 int r_month; /* 0..11 */
70 int r_dycode; /* see below */
71 int r_dayofmonth;
72 int r_wday;
74 zic_t r_tod; /* time from midnight */
75 bool r_todisstd; /* is r_tod standard time? */
76 bool r_todisut; /* is r_tod UT? */
77 bool r_isdst; /* is this daylight saving time? */
78 zic_t r_save; /* offset from standard time */
79 const char *r_abbrvar; /* variable part of abbreviation */
81 bool r_todo; /* a rule to do (used in outzone) */
82 zic_t r_temp; /* used in outzone */
86 * r_dycode r_dayofmonth r_wday
89 #define DC_DOM 0 /* 1..31 */ /* unused */
90 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
91 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
93 struct zone
95 const char *z_filename;
96 lineno_t z_linenum;
98 const char *z_name;
99 zic_t z_stdoff;
100 char *z_rule;
101 const char *z_format;
102 char z_format_specifier;
104 bool z_isdst;
105 zic_t z_save;
107 struct rule *z_rules;
108 ptrdiff_t z_nrules;
110 struct rule z_untilrule;
111 zic_t z_untiltime;
114 extern int link(const char *target, const char *linkname);
115 #ifndef AT_SYMLINK_FOLLOW
116 #define linkat(targetdir, target, linknamedir, linkname, flag) \
117 (itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
118 #endif
120 static void memory_exhausted(const char *msg) pg_attribute_noreturn();
121 static void verror(const char *string, va_list args) pg_attribute_printf(1, 0);
122 static void error(const char *string,...) pg_attribute_printf(1, 2);
123 static void warning(const char *string,...) pg_attribute_printf(1, 2);
124 static void usage(FILE *stream, int status) pg_attribute_noreturn();
125 static void addtt(zic_t starttime, int type);
126 static int addtype(zic_t utoff, char const *abbr,
127 bool isdst, bool ttisstd, bool ttisut);
128 static void leapadd(zic_t t, int correction, int rolling);
129 static void adjleap(void);
130 static void associate(void);
131 static void dolink(char const *target, char const *linkname,
132 bool staysymlink);
133 static char **getfields(char *cp);
134 static zic_t gethms(const char *string, const char *errstring);
135 static zic_t getsave(char *field, bool *isdst);
136 static void inexpires(char **fields, int nfields);
137 static void infile(const char *name);
138 static void inleap(char **fields, int nfields);
139 static void inlink(char **fields, int nfields);
140 static void inrule(char **fields, int nfields);
141 static bool inzcont(char **fields, int nfields);
142 static bool inzone(char **fields, int nfields);
143 static bool inzsub(char **fields, int nfields, bool iscont);
144 static bool itsdir(char const *name);
145 static bool itssymlink(char const *name);
146 static bool is_alpha(char a);
147 static char lowerit(char a);
148 static void mkdirs(char const *argname, bool ancestors);
149 static void newabbr(const char *string);
150 static zic_t oadd(zic_t t1, zic_t t2);
151 static void outzone(const struct zone *zpfirst, ptrdiff_t zonecount);
152 static zic_t rpytime(const struct rule *rp, zic_t wantedy);
153 static void rulesub(struct rule *rp,
154 const char *loyearp, const char *hiyearp,
155 const char *typep, const char *monthp,
156 const char *dayp, const char *timep);
157 static zic_t tadd(zic_t t1, zic_t t2);
159 /* Bound on length of what %z can expand to. */
160 enum
162 PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};
164 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
165 TZif files whose POSIX-TZ-style strings contain '<'; see
166 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
167 workaround will no longer be needed when Qt 5.6.1 and earlier are
168 obsolete, say in the year 2021. */
169 #ifndef WORK_AROUND_QTBUG_53071
170 enum
172 WORK_AROUND_QTBUG_53071 = true};
173 #endif
175 static int charcnt;
176 static bool errors;
177 static bool warnings;
178 static const char *filename;
179 static int leapcnt;
180 static bool leapseen;
181 static zic_t leapminyear;
182 static zic_t leapmaxyear;
183 static lineno_t linenum;
184 static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
185 static int max_format_len;
186 static zic_t max_year;
187 static zic_t min_year;
188 static bool noise;
189 static bool print_abbrevs;
190 static zic_t print_cutoff;
191 static const char *rfilename;
192 static lineno_t rlinenum;
193 static const char *progname;
194 static ptrdiff_t timecnt;
195 static ptrdiff_t timecnt_alloc;
196 static int typecnt;
199 * Line codes.
202 #define LC_RULE 0
203 #define LC_ZONE 1
204 #define LC_LINK 2
205 #define LC_LEAP 3
206 #define LC_EXPIRES 4
209 * Which fields are which on a Zone line.
212 #define ZF_NAME 1
213 #define ZF_STDOFF 2
214 #define ZF_RULE 3
215 #define ZF_FORMAT 4
216 #define ZF_TILYEAR 5
217 #define ZF_TILMONTH 6
218 #define ZF_TILDAY 7
219 #define ZF_TILTIME 8
220 #define ZONE_MINFIELDS 5
221 #define ZONE_MAXFIELDS 9
224 * Which fields are which on a Zone continuation line.
227 #define ZFC_STDOFF 0
228 #define ZFC_RULE 1
229 #define ZFC_FORMAT 2
230 #define ZFC_TILYEAR 3
231 #define ZFC_TILMONTH 4
232 #define ZFC_TILDAY 5
233 #define ZFC_TILTIME 6
234 #define ZONEC_MINFIELDS 3
235 #define ZONEC_MAXFIELDS 7
238 * Which files are which on a Rule line.
241 #define RF_NAME 1
242 #define RF_LOYEAR 2
243 #define RF_HIYEAR 3
244 #define RF_COMMAND 4
245 #define RF_MONTH 5
246 #define RF_DAY 6
247 #define RF_TOD 7
248 #define RF_SAVE 8
249 #define RF_ABBRVAR 9
250 #define RULE_FIELDS 10
253 * Which fields are which on a Link line.
256 #define LF_TARGET 1
257 #define LF_LINKNAME 2
258 #define LINK_FIELDS 3
261 * Which fields are which on a Leap line.
264 #define LP_YEAR 1
265 #define LP_MONTH 2
266 #define LP_DAY 3
267 #define LP_TIME 4
268 #define LP_CORR 5
269 #define LP_ROLL 6
270 #define LEAP_FIELDS 7
272 /* Expires lines are like Leap lines, except without CORR and ROLL fields. */
273 #define EXPIRES_FIELDS 5
276 * Year synonyms.
279 #define YR_MINIMUM 0
280 #define YR_MAXIMUM 1
281 #define YR_ONLY 2
283 static struct rule *rules;
284 static ptrdiff_t nrules; /* number of rules */
285 static ptrdiff_t nrules_alloc;
287 static struct zone *zones;
288 static ptrdiff_t nzones; /* number of zones */
289 static ptrdiff_t nzones_alloc;
291 struct link
293 const char *l_filename;
294 lineno_t l_linenum;
295 const char *l_target;
296 const char *l_linkname;
299 static struct link *links;
300 static ptrdiff_t nlinks;
301 static ptrdiff_t nlinks_alloc;
303 struct lookup
305 const char *l_word;
306 const int l_value;
309 static struct lookup const *byword(const char *word,
310 const struct lookup *table);
312 static struct lookup const zi_line_codes[] = {
313 {"Rule", LC_RULE},
314 {"Zone", LC_ZONE},
315 {"Link", LC_LINK},
316 {NULL, 0}
318 static struct lookup const leap_line_codes[] = {
319 {"Leap", LC_LEAP},
320 {"Expires", LC_EXPIRES},
321 {NULL, 0}
324 static struct lookup const mon_names[] = {
325 {"January", TM_JANUARY},
326 {"February", TM_FEBRUARY},
327 {"March", TM_MARCH},
328 {"April", TM_APRIL},
329 {"May", TM_MAY},
330 {"June", TM_JUNE},
331 {"July", TM_JULY},
332 {"August", TM_AUGUST},
333 {"September", TM_SEPTEMBER},
334 {"October", TM_OCTOBER},
335 {"November", TM_NOVEMBER},
336 {"December", TM_DECEMBER},
337 {NULL, 0}
340 static struct lookup const wday_names[] = {
341 {"Sunday", TM_SUNDAY},
342 {"Monday", TM_MONDAY},
343 {"Tuesday", TM_TUESDAY},
344 {"Wednesday", TM_WEDNESDAY},
345 {"Thursday", TM_THURSDAY},
346 {"Friday", TM_FRIDAY},
347 {"Saturday", TM_SATURDAY},
348 {NULL, 0}
351 static struct lookup const lasts[] = {
352 {"last-Sunday", TM_SUNDAY},
353 {"last-Monday", TM_MONDAY},
354 {"last-Tuesday", TM_TUESDAY},
355 {"last-Wednesday", TM_WEDNESDAY},
356 {"last-Thursday", TM_THURSDAY},
357 {"last-Friday", TM_FRIDAY},
358 {"last-Saturday", TM_SATURDAY},
359 {NULL, 0}
362 static struct lookup const begin_years[] = {
363 {"minimum", YR_MINIMUM},
364 {"maximum", YR_MAXIMUM},
365 {NULL, 0}
368 static struct lookup const end_years[] = {
369 {"minimum", YR_MINIMUM},
370 {"maximum", YR_MAXIMUM},
371 {"only", YR_ONLY},
372 {NULL, 0}
375 static struct lookup const leap_types[] = {
376 {"Rolling", true},
377 {"Stationary", false},
378 {NULL, 0}
381 static const int len_months[2][MONSPERYEAR] = {
382 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
383 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
386 static const int len_years[2] = {
387 DAYSPERNYEAR, DAYSPERLYEAR
390 static struct attype
392 zic_t at;
393 bool dontmerge;
394 unsigned char type;
395 } *attypes;
396 static zic_t utoffs[TZ_MAX_TYPES];
397 static char isdsts[TZ_MAX_TYPES];
398 static unsigned char desigidx[TZ_MAX_TYPES];
399 static bool ttisstds[TZ_MAX_TYPES];
400 static bool ttisuts[TZ_MAX_TYPES];
401 static char chars[TZ_MAX_CHARS];
402 static zic_t trans[TZ_MAX_LEAPS];
403 static zic_t corr[TZ_MAX_LEAPS];
404 static char roll[TZ_MAX_LEAPS];
407 * Memory allocation.
410 static void
411 memory_exhausted(const char *msg)
413 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
414 exit(EXIT_FAILURE);
417 static size_t
418 size_product(size_t nitems, size_t itemsize)
420 if (SIZE_MAX / itemsize < nitems)
421 memory_exhausted(_("size overflow"));
422 return nitems * itemsize;
425 static void *
426 memcheck(void *ptr)
428 if (ptr == NULL)
429 memory_exhausted(strerror(errno));
430 return ptr;
433 static void *
434 emalloc(size_t size)
436 return memcheck(malloc(size));
439 static void *
440 erealloc(void *ptr, size_t size)
442 return memcheck(realloc(ptr, size));
445 static char *
446 ecpyalloc(char const *str)
448 return memcheck(strdup(str));
451 static void *
452 growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
454 if (nitems < *nitems_alloc)
455 return ptr;
456 else
458 ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
459 ptrdiff_t amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
461 if ((amax - 1) / 3 * 2 < *nitems_alloc)
462 memory_exhausted(_("integer overflow"));
463 *nitems_alloc += (*nitems_alloc >> 1) + 1;
464 return erealloc(ptr, size_product(*nitems_alloc, itemsize));
469 * Error handling.
472 static void
473 eats(char const *name, lineno_t num, char const *rname, lineno_t rnum)
475 filename = name;
476 linenum = num;
477 rfilename = rname;
478 rlinenum = rnum;
481 static void
482 eat(char const *name, lineno_t num)
484 eats(name, num, NULL, -1);
487 static void
488 verror(const char *string, va_list args)
491 * Match the format of "cc" to allow sh users to zic ... 2>&1 | error -t
492 * "*" -v on BSD systems.
494 if (filename)
495 fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
496 vfprintf(stderr, string, args);
497 if (rfilename != NULL)
498 fprintf(stderr, _(" (rule from \"%s\", line %d)"),
499 rfilename, rlinenum);
500 fprintf(stderr, "\n");
503 static void
504 error(const char *string,...)
506 va_list args;
508 va_start(args, string);
509 verror(string, args);
510 va_end(args);
511 errors = true;
514 static void
515 warning(const char *string,...)
517 va_list args;
519 fprintf(stderr, _("warning: "));
520 va_start(args, string);
521 verror(string, args);
522 va_end(args);
523 warnings = true;
526 static void
527 close_file(FILE *stream, char const *dir, char const *name)
529 char const *e = (ferror(stream) ? _("I/O error")
530 : fclose(stream) != 0 ? strerror(errno) : NULL);
532 if (e)
534 fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
535 dir ? dir : "", dir ? "/" : "",
536 name ? name : "", name ? ": " : "",
538 exit(EXIT_FAILURE);
542 static void
543 usage(FILE *stream, int status)
545 fprintf(stream,
546 _("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -P ] \\\n"
547 "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]"
548 " [ -L leapseconds ] \\\n"
549 "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -t localtime-link ] \\\n"
550 "\t[ filename ... ]\n\n"
551 "Report bugs to %s.\n"),
552 progname, progname, PACKAGE_BUGREPORT);
553 if (status == EXIT_SUCCESS)
554 close_file(stream, NULL, NULL);
555 exit(status);
558 /* Change the working directory to DIR, possibly creating DIR and its
559 ancestors. After this is done, all files are accessed with names
560 relative to DIR. */
561 static void
562 change_directory(char const *dir)
564 if (chdir(dir) != 0)
566 int chdir_errno = errno;
568 if (chdir_errno == ENOENT)
570 mkdirs(dir, false);
571 chdir_errno = chdir(dir) == 0 ? 0 : errno;
573 if (chdir_errno != 0)
575 fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
576 progname, dir, strerror(chdir_errno));
577 exit(EXIT_FAILURE);
582 #define TIME_T_BITS_IN_FILE 64
584 /* The minimum and maximum values representable in a TZif file. */
585 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
586 static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
588 /* The minimum, and one less than the maximum, values specified by
589 the -r option. These default to MIN_TIME and MAX_TIME. */
590 static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
591 static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
593 /* The time specified by an Expires line, or negative if no such line. */
594 static zic_t leapexpires = -1;
596 /* The time specified by an #expires comment, or negative if no such line. */
597 static zic_t comment_leapexpires = -1;
599 /* Set the time range of the output to TIMERANGE.
600 Return true if successful. */
601 static bool
602 timerange_option(char *timerange)
604 int64 lo = min_time,
605 hi = max_time;
606 char *lo_end = timerange,
607 *hi_end;
609 if (*timerange == '@')
611 errno = 0;
612 lo = strtoimax(timerange + 1, &lo_end, 10);
613 if (lo_end == timerange + 1 || (lo == PG_INT64_MAX && errno == ERANGE))
614 return false;
616 hi_end = lo_end;
617 if (lo_end[0] == '/' && lo_end[1] == '@')
619 errno = 0;
620 hi = strtoimax(lo_end + 2, &hi_end, 10);
621 if (hi_end == lo_end + 2 || hi == PG_INT64_MIN)
622 return false;
623 hi -= !(hi == PG_INT64_MAX && errno == ERANGE);
625 if (*hi_end || hi < lo || max_time < lo || hi < min_time)
626 return false;
627 lo_time = lo < min_time ? min_time : lo;
628 hi_time = max_time < hi ? max_time : hi;
629 return true;
632 static const char *psxrules;
633 static const char *lcltime;
634 static const char *directory;
635 static const char *leapsec;
636 static const char *tzdefault;
638 /* -1 if the TZif output file should be slim, 0 if default, 1 if the
639 output should be fat for backward compatibility. ZIC_BLOAT_DEFAULT
640 determines the default. */
641 static int bloat;
643 static bool
644 want_bloat(void)
646 return 0 <= bloat;
649 #ifndef ZIC_BLOAT_DEFAULT
650 #define ZIC_BLOAT_DEFAULT "slim"
651 #endif
654 main(int argc, char **argv)
656 int c,
658 ptrdiff_t i,
660 bool timerange_given = false;
662 #ifndef WIN32
663 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
664 #endif
665 progname = argv[0];
666 if (TYPE_BIT(zic_t) < 64)
668 fprintf(stderr, "%s: %s\n", progname,
669 _("wild compilation-time specification of zic_t"));
670 return EXIT_FAILURE;
672 for (k = 1; k < argc; k++)
673 if (strcmp(argv[k], "--version") == 0)
675 printf("zic %s\n", PG_VERSION);
676 close_file(stdout, NULL, NULL);
677 return EXIT_SUCCESS;
679 else if (strcmp(argv[k], "--help") == 0)
681 usage(stdout, EXIT_SUCCESS);
683 while ((c = getopt(argc, argv, "b:d:l:L:p:Pr:st:vy:")) != EOF && c != -1)
684 switch (c)
686 default:
687 usage(stderr, EXIT_FAILURE);
688 case 'b':
689 if (strcmp(optarg, "slim") == 0)
691 if (0 < bloat)
692 error(_("incompatible -b options"));
693 bloat = -1;
695 else if (strcmp(optarg, "fat") == 0)
697 if (bloat < 0)
698 error(_("incompatible -b options"));
699 bloat = 1;
701 else
702 error(_("invalid option: -b '%s'"), optarg);
703 break;
704 case 'd':
705 if (directory == NULL)
706 directory = strdup(optarg);
707 else
709 fprintf(stderr,
710 _("%s: More than one -d option specified\n"),
711 progname);
712 return EXIT_FAILURE;
714 break;
715 case 'l':
716 if (lcltime == NULL)
717 lcltime = strdup(optarg);
718 else
720 fprintf(stderr,
721 _("%s: More than one -l option specified\n"),
722 progname);
723 return EXIT_FAILURE;
725 break;
726 case 'p':
727 if (psxrules == NULL)
728 psxrules = strdup(optarg);
729 else
731 fprintf(stderr,
732 _("%s: More than one -p option specified\n"),
733 progname);
734 return EXIT_FAILURE;
736 break;
737 case 't':
738 if (tzdefault != NULL)
740 fprintf(stderr,
741 _("%s: More than one -t option"
742 " specified\n"),
743 progname);
744 return EXIT_FAILURE;
746 tzdefault = optarg;
747 break;
748 case 'y':
749 warning(_("-y ignored"));
750 break;
751 case 'L':
752 if (leapsec == NULL)
753 leapsec = strdup(optarg);
754 else
756 fprintf(stderr,
757 _("%s: More than one -L option specified\n"),
758 progname);
759 return EXIT_FAILURE;
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)
772 fprintf(stderr,
773 _("%s: More than one -r option specified\n"),
774 progname);
775 return EXIT_FAILURE;
777 if (!timerange_option(optarg))
779 fprintf(stderr,
780 _("%s: invalid time range: %s\n"),
781 progname, optarg);
782 return EXIT_FAILURE;
784 timerange_given = true;
785 break;
786 case 's':
787 warning(_("-s ignored"));
788 break;
790 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
791 usage(stderr, EXIT_FAILURE); /* usage message by request */
792 if (bloat == 0)
794 static char const bloat_default[] = ZIC_BLOAT_DEFAULT;
796 if (strcmp(bloat_default, "slim") == 0)
797 bloat = -1;
798 else if (strcmp(bloat_default, "fat") == 0)
799 bloat = 1;
800 else
801 abort(); /* Configuration error. */
803 if (directory == NULL)
804 directory = "data";
805 if (tzdefault == NULL)
806 tzdefault = TZDEFAULT;
808 if (optind < argc && leapsec != NULL)
810 infile(leapsec);
811 adjleap();
814 for (k = optind; k < argc; k++)
815 infile(argv[k]);
816 if (errors)
817 return EXIT_FAILURE;
818 associate();
819 change_directory(directory);
820 for (i = 0; i < nzones; i = j)
823 * Find the next non-continuation zone entry.
825 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
826 continue;
827 outzone(&zones[i], j - i);
831 * Make links.
833 for (i = 0; i < nlinks; ++i)
835 eat(links[i].l_filename, links[i].l_linenum);
836 dolink(links[i].l_target, links[i].l_linkname, false);
837 if (noise)
838 for (j = 0; j < nlinks; ++j)
839 if (strcmp(links[i].l_linkname,
840 links[j].l_target) == 0)
841 warning(_("link to link"));
843 if (lcltime != NULL)
845 eat(_("command line"), 1);
846 dolink(lcltime, tzdefault, true);
848 if (psxrules != NULL)
850 eat(_("command line"), 1);
851 dolink(psxrules, TZDEFRULES, true);
853 if (warnings && (ferror(stderr) || fclose(stderr) != 0))
854 return EXIT_FAILURE;
855 return errors ? EXIT_FAILURE : EXIT_SUCCESS;
858 static bool
859 componentcheck(char const *name, char const *component,
860 char const *component_end)
862 enum
864 component_len_max = 14};
865 ptrdiff_t component_len = component_end - component;
867 if (component_len == 0)
869 if (!*name)
870 error(_("empty file name"));
871 else
872 error(_(component == name
873 ? "file name '%s' begins with '/'"
874 : *component_end
875 ? "file name '%s' contains '//'"
876 : "file name '%s' ends with '/'"),
877 name);
878 return false;
880 if (0 < component_len && component_len <= 2
881 && component[0] == '.' && component_end[-1] == '.')
883 int len = component_len;
885 error(_("file name '%s' contains '%.*s' component"),
886 name, len, component);
887 return false;
889 if (noise)
891 if (0 < component_len && component[0] == '-')
892 warning(_("file name '%s' component contains leading '-'"),
893 name);
894 if (component_len_max < component_len)
895 warning(_("file name '%s' contains overlength component"
896 " '%.*s...'"),
897 name, component_len_max, component);
899 return true;
902 static bool
903 namecheck(const char *name)
905 char const *cp;
907 /* Benign characters in a portable file name. */
908 static char const benign[] =
909 "-/_"
910 "abcdefghijklmnopqrstuvwxyz"
911 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
914 * Non-control chars in the POSIX portable character set, excluding the
915 * benign characters.
917 static char const printable_and_not_benign[] =
918 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
920 char const *component = name;
922 for (cp = name; *cp; cp++)
924 unsigned char c = *cp;
926 if (noise && !strchr(benign, c))
928 warning((strchr(printable_and_not_benign, c)
929 ? _("file name '%s' contains byte '%c'")
930 : _("file name '%s' contains byte '\\%o'")),
931 name, c);
933 if (c == '/')
935 if (!componentcheck(name, component, cp))
936 return false;
937 component = cp + 1;
940 return componentcheck(name, component, cp);
944 * Create symlink contents suitable for symlinking FROM to TO, as a
945 * freshly allocated string. FROM should be a relative file name, and
946 * is relative to the global variable DIRECTORY. TO can be either
947 * relative or absolute.
949 #ifdef HAVE_SYMLINK
950 static char *
951 relname(char const *target, char const *linkname)
953 size_t i,
954 taillen,
955 dotdotetcsize;
956 size_t dir_len = 0,
957 dotdots = 0,
958 linksize = SIZE_MAX;
959 char const *f = target;
960 char *result = NULL;
962 if (*linkname == '/')
964 /* Make F absolute too. */
965 size_t len = strlen(directory);
966 bool needslash = len && directory[len - 1] != '/';
968 linksize = len + needslash + strlen(target) + 1;
969 f = result = emalloc(linksize);
970 strcpy(result, directory);
971 result[len] = '/';
972 strcpy(result + len + needslash, target);
974 for (i = 0; f[i] && f[i] == linkname[i]; i++)
975 if (f[i] == '/')
976 dir_len = i + 1;
977 for (; linkname[i]; i++)
978 dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
979 taillen = strlen(f + dir_len);
980 dotdotetcsize = 3 * dotdots + taillen + 1;
981 if (dotdotetcsize <= linksize)
983 if (!result)
984 result = emalloc(dotdotetcsize);
985 for (i = 0; i < dotdots; i++)
986 memcpy(result + 3 * i, "../", 3);
987 memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
989 return result;
991 #endif /* HAVE_SYMLINK */
993 /* Hard link FROM to TO, following any symbolic links.
994 Return 0 if successful, an error number otherwise. */
995 static int
996 hardlinkerr(char const *target, char const *linkname)
998 int r = linkat(AT_FDCWD, target, AT_FDCWD, linkname, AT_SYMLINK_FOLLOW);
1000 return r == 0 ? 0 : errno;
1003 static void
1004 dolink(char const *target, char const *linkname, bool staysymlink)
1006 bool remove_only = strcmp(target, "-") == 0;
1007 bool linkdirs_made = false;
1008 int link_errno;
1011 * We get to be careful here since there's a fair chance of root running
1012 * us.
1014 if (!remove_only && itsdir(target))
1016 fprintf(stderr, _("%s: linking target %s/%s failed: %s\n"),
1017 progname, directory, target, strerror(EPERM));
1018 exit(EXIT_FAILURE);
1020 if (staysymlink)
1021 staysymlink = itssymlink(linkname);
1022 if (remove(linkname) == 0)
1023 linkdirs_made = true;
1024 else if (errno != ENOENT)
1026 char const *e = strerror(errno);
1028 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1029 progname, directory, linkname, e);
1030 exit(EXIT_FAILURE);
1032 if (remove_only)
1033 return;
1034 link_errno = staysymlink ? ENOTSUP : hardlinkerr(target, linkname);
1035 if (link_errno == ENOENT && !linkdirs_made)
1037 mkdirs(linkname, true);
1038 linkdirs_made = true;
1039 link_errno = hardlinkerr(target, linkname);
1041 if (link_errno != 0)
1043 #ifdef HAVE_SYMLINK
1044 bool absolute = *target == '/';
1045 char *linkalloc = absolute ? NULL : relname(target, linkname);
1046 char const *contents = absolute ? target : linkalloc;
1047 int symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
1049 if (!linkdirs_made
1050 && (symlink_errno == ENOENT || symlink_errno == ENOTSUP))
1052 mkdirs(linkname, true);
1053 if (symlink_errno == ENOENT)
1054 symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
1056 free(linkalloc);
1057 if (symlink_errno == 0)
1059 if (link_errno != ENOTSUP)
1060 warning(_("symbolic link used because hard link failed: %s"),
1061 strerror(link_errno));
1063 else
1064 #endif /* HAVE_SYMLINK */
1066 FILE *fp,
1067 *tp;
1068 int c;
1070 fp = fopen(target, "rb");
1071 if (!fp)
1073 char const *e = strerror(errno);
1075 fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
1076 progname, directory, target, e);
1077 exit(EXIT_FAILURE);
1079 tp = fopen(linkname, "wb");
1080 if (!tp)
1082 char const *e = strerror(errno);
1084 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1085 progname, directory, linkname, e);
1086 exit(EXIT_FAILURE);
1088 while ((c = getc(fp)) != EOF)
1089 putc(c, tp);
1090 close_file(fp, directory, target);
1091 close_file(tp, directory, linkname);
1092 if (link_errno != ENOTSUP)
1093 warning(_("copy used because hard link failed: %s"),
1094 strerror(link_errno));
1095 #ifdef HAVE_SYMLINK
1096 else if (symlink_errno != ENOTSUP)
1097 warning(_("copy used because symbolic link failed: %s"),
1098 strerror(symlink_errno));
1099 #endif
1104 /* Return true if NAME is a directory. */
1105 static bool
1106 itsdir(char const *name)
1108 struct stat st;
1109 int res = stat(name, &st);
1110 #ifdef S_ISDIR
1111 if (res == 0)
1112 return S_ISDIR(st.st_mode) != 0;
1113 #endif
1114 if (res == 0 || errno == EOVERFLOW)
1116 size_t n = strlen(name);
1117 char *nameslashdot = emalloc(n + 3);
1118 bool dir;
1120 memcpy(nameslashdot, name, n);
1121 strcpy(&nameslashdot[n], &"/."[!(n && name[n - 1] != '/')]);
1122 dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
1123 free(nameslashdot);
1124 return dir;
1126 return false;
1129 /* Return true if NAME is a symbolic link. */
1130 static bool
1131 itssymlink(char const *name)
1133 #ifdef HAVE_SYMLINK
1134 char c;
1136 return 0 <= readlink(name, &c, 1);
1137 #else
1138 return false;
1139 #endif
1143 * Associate sets of rules with zones.
1147 * Sort by rule name.
1150 static int
1151 rcomp(const void *cp1, const void *cp2)
1153 return strcmp(((const struct rule *) cp1)->r_name,
1154 ((const struct rule *) cp2)->r_name);
1157 static void
1158 associate(void)
1160 struct zone *zp;
1161 struct rule *rp;
1162 ptrdiff_t i,
1164 base,
1165 out;
1167 if (nrules != 0)
1169 qsort(rules, nrules, sizeof *rules, rcomp);
1170 for (i = 0; i < nrules - 1; ++i)
1172 if (strcmp(rules[i].r_name,
1173 rules[i + 1].r_name) != 0)
1174 continue;
1175 if (strcmp(rules[i].r_filename,
1176 rules[i + 1].r_filename) == 0)
1177 continue;
1178 eat(rules[i].r_filename, rules[i].r_linenum);
1179 warning(_("same rule name in multiple files"));
1180 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
1181 warning(_("same rule name in multiple files"));
1182 for (j = i + 2; j < nrules; ++j)
1184 if (strcmp(rules[i].r_name,
1185 rules[j].r_name) != 0)
1186 break;
1187 if (strcmp(rules[i].r_filename,
1188 rules[j].r_filename) == 0)
1189 continue;
1190 if (strcmp(rules[i + 1].r_filename,
1191 rules[j].r_filename) == 0)
1192 continue;
1193 break;
1195 i = j - 1;
1198 for (i = 0; i < nzones; ++i)
1200 zp = &zones[i];
1201 zp->z_rules = NULL;
1202 zp->z_nrules = 0;
1204 for (base = 0; base < nrules; base = out)
1206 rp = &rules[base];
1207 for (out = base + 1; out < nrules; ++out)
1208 if (strcmp(rp->r_name, rules[out].r_name) != 0)
1209 break;
1210 for (i = 0; i < nzones; ++i)
1212 zp = &zones[i];
1213 if (strcmp(zp->z_rule, rp->r_name) != 0)
1214 continue;
1215 zp->z_rules = rp;
1216 zp->z_nrules = out - base;
1219 for (i = 0; i < nzones; ++i)
1221 zp = &zones[i];
1222 if (zp->z_nrules == 0)
1225 * Maybe we have a local standard time offset.
1227 eat(zp->z_filename, zp->z_linenum);
1228 zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
1231 * Note, though, that if there's no rule, a '%s' in the format is
1232 * a bad thing.
1234 if (zp->z_format_specifier == 's')
1235 error("%s", _("%s in ruleless zone"));
1238 if (errors)
1239 exit(EXIT_FAILURE);
1242 static void
1243 infile(const char *name)
1245 FILE *fp;
1246 char **fields;
1247 char *cp;
1248 const struct lookup *lp;
1249 int nfields;
1250 bool wantcont;
1251 lineno_t num;
1252 char buf[BUFSIZ];
1254 if (strcmp(name, "-") == 0)
1256 name = _("standard input");
1257 fp = stdin;
1259 else if ((fp = fopen(name, "r")) == NULL)
1261 const char *e = strerror(errno);
1263 fprintf(stderr, _("%s: Cannot open %s: %s\n"),
1264 progname, name, e);
1265 exit(EXIT_FAILURE);
1267 wantcont = false;
1268 for (num = 1;; ++num)
1270 eat(name, num);
1271 if (fgets(buf, sizeof buf, fp) != buf)
1272 break;
1273 cp = strchr(buf, '\n');
1274 if (cp == NULL)
1276 error(_("line too long"));
1277 exit(EXIT_FAILURE);
1279 *cp = '\0';
1280 fields = getfields(buf);
1281 nfields = 0;
1282 while (fields[nfields] != NULL)
1284 static char nada;
1286 if (strcmp(fields[nfields], "-") == 0)
1287 fields[nfields] = &nada;
1288 ++nfields;
1290 if (nfields == 0)
1292 if (name == leapsec && *buf == '#')
1295 * PG: INT64_FORMAT isn't portable for sscanf, so be content
1296 * with scanning a "long". Once we are requiring C99 in all
1297 * live branches, it'd be sensible to adopt upstream's
1298 * practice of using the <inttypes.h> macros. But for now, we
1299 * don't actually use this code, and it won't overflow before
1300 * 2038 anyway.
1302 long cl_tmp;
1304 sscanf(buf, "#expires %ld", &cl_tmp);
1305 comment_leapexpires = cl_tmp;
1308 else if (wantcont)
1310 wantcont = inzcont(fields, nfields);
1312 else
1314 struct lookup const *line_codes
1315 = name == leapsec ? leap_line_codes : zi_line_codes;
1317 lp = byword(fields[0], line_codes);
1318 if (lp == NULL)
1319 error(_("input line of unknown type"));
1320 else
1321 switch (lp->l_value)
1323 case LC_RULE:
1324 inrule(fields, nfields);
1325 wantcont = false;
1326 break;
1327 case LC_ZONE:
1328 wantcont = inzone(fields, nfields);
1329 break;
1330 case LC_LINK:
1331 inlink(fields, nfields);
1332 wantcont = false;
1333 break;
1334 case LC_LEAP:
1335 inleap(fields, nfields);
1336 wantcont = false;
1337 break;
1338 case LC_EXPIRES:
1339 inexpires(fields, nfields);
1340 wantcont = false;
1341 break;
1342 default: /* "cannot happen" */
1343 fprintf(stderr,
1344 _("%s: panic: Invalid l_value %d\n"),
1345 progname, lp->l_value);
1346 exit(EXIT_FAILURE);
1349 free(fields);
1351 close_file(fp, NULL, filename);
1352 if (wantcont)
1353 error(_("expected continuation line not found"));
1357 * Convert a string of one of the forms
1358 * h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1359 * into a number of seconds.
1360 * A null string maps to zero.
1361 * Call error with errstring and return zero on errors.
1364 static zic_t
1365 gethms(char const *string, char const *errstring)
1367 /* PG: make hh be int not zic_t to avoid sscanf portability issues */
1368 int hh;
1369 int sign,
1370 mm = 0,
1371 ss = 0;
1372 char hhx,
1373 mmx,
1374 ssx,
1375 xr = '0',
1377 int tenths = 0;
1378 bool ok = true;
1380 if (string == NULL || *string == '\0')
1381 return 0;
1382 if (*string == '-')
1384 sign = -1;
1385 ++string;
1387 else
1388 sign = 1;
1389 switch (sscanf(string,
1390 "%d%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
1391 &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs))
1393 default:
1394 ok = false;
1395 break;
1396 case 8:
1397 ok = '0' <= xr && xr <= '9';
1398 /* fallthrough */
1399 case 7:
1400 ok &= ssx == '.';
1401 if (ok && noise)
1402 warning(_("fractional seconds rejected by"
1403 " pre-2018 versions of zic"));
1404 /* fallthrough */
1405 case 5:
1406 ok &= mmx == ':';
1407 /* fallthrough */
1408 case 3:
1409 ok &= hhx == ':';
1410 /* fallthrough */
1411 case 1:
1412 break;
1414 if (!ok)
1416 error("%s", errstring);
1417 return 0;
1419 if (hh < 0 ||
1420 mm < 0 || mm >= MINSPERHOUR ||
1421 ss < 0 || ss > SECSPERMIN)
1423 error("%s", errstring);
1424 return 0;
1426 /* Some compilers warn that this test is unsatisfiable for 32-bit ints */
1427 #if INT_MAX > PG_INT32_MAX
1428 if (ZIC_MAX / SECSPERHOUR < hh)
1430 error(_("time overflow"));
1431 return 0;
1433 #endif
1434 ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */
1435 if (noise && (hh > HOURSPERDAY ||
1436 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1437 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1438 return oadd(sign * (zic_t) hh * SECSPERHOUR,
1439 sign * (mm * SECSPERMIN + ss));
1442 static zic_t
1443 getsave(char *field, bool *isdst)
1445 int dst = -1;
1446 zic_t save;
1447 size_t fieldlen = strlen(field);
1449 if (fieldlen != 0)
1451 char *ep = field + fieldlen - 1;
1453 switch (*ep)
1455 case 'd':
1456 dst = 1;
1457 *ep = '\0';
1458 break;
1459 case 's':
1460 dst = 0;
1461 *ep = '\0';
1462 break;
1465 save = gethms(field, _("invalid saved time"));
1466 *isdst = dst < 0 ? save != 0 : dst;
1467 return save;
1470 static void
1471 inrule(char **fields, int nfields)
1473 static struct rule r;
1475 if (nfields != RULE_FIELDS)
1477 error(_("wrong number of fields on Rule line"));
1478 return;
1480 switch (*fields[RF_NAME])
1482 case '\0':
1483 case ' ':
1484 case '\f':
1485 case '\n':
1486 case '\r':
1487 case '\t':
1488 case '\v':
1489 case '+':
1490 case '-':
1491 case '0':
1492 case '1':
1493 case '2':
1494 case '3':
1495 case '4':
1496 case '5':
1497 case '6':
1498 case '7':
1499 case '8':
1500 case '9':
1501 error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
1502 return;
1504 r.r_filename = filename;
1505 r.r_linenum = linenum;
1506 r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
1507 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1508 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1509 r.r_name = ecpyalloc(fields[RF_NAME]);
1510 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1511 if (max_abbrvar_len < strlen(r.r_abbrvar))
1512 max_abbrvar_len = strlen(r.r_abbrvar);
1513 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1514 rules[nrules++] = r;
1517 static bool
1518 inzone(char **fields, int nfields)
1520 ptrdiff_t i;
1522 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS)
1524 error(_("wrong number of fields on Zone line"));
1525 return false;
1527 if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0)
1529 error(
1530 _("\"Zone %s\" line and -l option are mutually exclusive"),
1531 tzdefault);
1532 return false;
1534 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL)
1536 error(
1537 _("\"Zone %s\" line and -p option are mutually exclusive"),
1538 TZDEFRULES);
1539 return false;
1541 for (i = 0; i < nzones; ++i)
1542 if (zones[i].z_name != NULL &&
1543 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0)
1545 error(_("duplicate zone name %s"
1546 " (file \"%s\", line %d)"),
1547 fields[ZF_NAME],
1548 zones[i].z_filename,
1549 zones[i].z_linenum);
1550 return false;
1552 return inzsub(fields, nfields, false);
1555 static bool
1556 inzcont(char **fields, int nfields)
1558 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS)
1560 error(_("wrong number of fields on Zone continuation line"));
1561 return false;
1563 return inzsub(fields, nfields, true);
1566 static bool
1567 inzsub(char **fields, int nfields, bool iscont)
1569 char *cp;
1570 char *cp1;
1571 static struct zone z;
1572 int i_stdoff,
1573 i_rule,
1574 i_format;
1575 int i_untilyear,
1576 i_untilmonth;
1577 int i_untilday,
1578 i_untiltime;
1579 bool hasuntil;
1581 if (iscont)
1583 i_stdoff = ZFC_STDOFF;
1584 i_rule = ZFC_RULE;
1585 i_format = ZFC_FORMAT;
1586 i_untilyear = ZFC_TILYEAR;
1587 i_untilmonth = ZFC_TILMONTH;
1588 i_untilday = ZFC_TILDAY;
1589 i_untiltime = ZFC_TILTIME;
1590 z.z_name = NULL;
1592 else if (!namecheck(fields[ZF_NAME]))
1593 return false;
1594 else
1596 i_stdoff = ZF_STDOFF;
1597 i_rule = ZF_RULE;
1598 i_format = ZF_FORMAT;
1599 i_untilyear = ZF_TILYEAR;
1600 i_untilmonth = ZF_TILMONTH;
1601 i_untilday = ZF_TILDAY;
1602 i_untiltime = ZF_TILTIME;
1603 z.z_name = ecpyalloc(fields[ZF_NAME]);
1605 z.z_filename = filename;
1606 z.z_linenum = linenum;
1607 z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
1608 if ((cp = strchr(fields[i_format], '%')) != NULL)
1610 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1611 || strchr(fields[i_format], '/'))
1613 error(_("invalid abbreviation format"));
1614 return false;
1617 z.z_rule = ecpyalloc(fields[i_rule]);
1618 z.z_format = cp1 = ecpyalloc(fields[i_format]);
1619 z.z_format_specifier = cp ? *cp : '\0';
1620 if (z.z_format_specifier == 'z')
1622 if (noise)
1623 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1624 z.z_format);
1625 cp1[cp - fields[i_format]] = 's';
1627 if (max_format_len < strlen(z.z_format))
1628 max_format_len = strlen(z.z_format);
1629 hasuntil = nfields > i_untilyear;
1630 if (hasuntil)
1632 z.z_untilrule.r_filename = filename;
1633 z.z_untilrule.r_linenum = linenum;
1634 rulesub(&z.z_untilrule,
1635 fields[i_untilyear],
1636 "only",
1638 (nfields > i_untilmonth) ?
1639 fields[i_untilmonth] : "Jan",
1640 (nfields > i_untilday) ? fields[i_untilday] : "1",
1641 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1642 z.z_untiltime = rpytime(&z.z_untilrule,
1643 z.z_untilrule.r_loyear);
1644 if (iscont && nzones > 0 &&
1645 z.z_untiltime > min_time &&
1646 z.z_untiltime < max_time &&
1647 zones[nzones - 1].z_untiltime > min_time &&
1648 zones[nzones - 1].z_untiltime < max_time &&
1649 zones[nzones - 1].z_untiltime >= z.z_untiltime)
1651 error(_("Zone continuation line end time is not after end time of previous line"));
1652 return false;
1655 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1656 zones[nzones++] = z;
1659 * If there was an UNTIL field on this line, there's more information
1660 * about the zone on the next line.
1662 return hasuntil;
1665 static zic_t
1666 getleapdatetime(char **fields, int nfields, bool expire_line)
1668 const char *cp;
1669 const struct lookup *lp;
1670 zic_t i,
1673 /* PG: make year be int not zic_t to avoid sscanf portability issues */
1674 int year;
1675 int month,
1676 day;
1677 zic_t dayoff,
1678 tod;
1679 zic_t t;
1680 char xs;
1682 dayoff = 0;
1683 cp = fields[LP_YEAR];
1684 if (sscanf(cp, "%d%c", &year, &xs) != 1)
1687 * Leapin' Lizards!
1689 error(_("invalid leaping year"));
1690 return -1;
1692 if (!expire_line)
1694 if (!leapseen || leapmaxyear < year)
1695 leapmaxyear = year;
1696 if (!leapseen || leapminyear > year)
1697 leapminyear = year;
1698 leapseen = true;
1700 j = EPOCH_YEAR;
1701 while (j != year)
1703 if (year > j)
1705 i = len_years[isleap(j)];
1706 ++j;
1708 else
1710 --j;
1711 i = -len_years[isleap(j)];
1713 dayoff = oadd(dayoff, i);
1715 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL)
1717 error(_("invalid month name"));
1718 return -1;
1720 month = lp->l_value;
1721 j = TM_JANUARY;
1722 while (j != month)
1724 i = len_months[isleap(year)][j];
1725 dayoff = oadd(dayoff, i);
1726 ++j;
1728 cp = fields[LP_DAY];
1729 if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1730 day <= 0 || day > len_months[isleap(year)][month])
1732 error(_("invalid day of month"));
1733 return -1;
1735 dayoff = oadd(dayoff, day - 1);
1736 if (dayoff < min_time / SECSPERDAY)
1738 error(_("time too small"));
1739 return -1;
1741 if (dayoff > max_time / SECSPERDAY)
1743 error(_("time too large"));
1744 return -1;
1746 t = dayoff * SECSPERDAY;
1747 tod = gethms(fields[LP_TIME], _("invalid time of day"));
1748 t = tadd(t, tod);
1749 if (t < 0)
1750 error(_("leap second precedes Epoch"));
1751 return t;
1754 static void
1755 inleap(char **fields, int nfields)
1757 if (nfields != LEAP_FIELDS)
1758 error(_("wrong number of fields on Leap line"));
1759 else
1761 zic_t t = getleapdatetime(fields, nfields, false);
1763 if (0 <= t)
1765 struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
1767 if (!lp)
1768 error(_("invalid Rolling/Stationary field on Leap line"));
1769 else
1771 int correction = 0;
1773 if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */
1774 correction = -1;
1775 else if (strcmp(fields[LP_CORR], "+") == 0)
1776 correction = 1;
1777 else
1778 error(_("invalid CORRECTION field on Leap line"));
1779 if (correction)
1780 leapadd(t, correction, lp->l_value);
1786 static void
1787 inexpires(char **fields, int nfields)
1789 if (nfields != EXPIRES_FIELDS)
1790 error(_("wrong number of fields on Expires line"));
1791 else if (0 <= leapexpires)
1792 error(_("multiple Expires lines"));
1793 else
1794 leapexpires = getleapdatetime(fields, nfields, true);
1797 static void
1798 inlink(char **fields, int nfields)
1800 struct link l;
1802 if (nfields != LINK_FIELDS)
1804 error(_("wrong number of fields on Link line"));
1805 return;
1807 if (*fields[LF_TARGET] == '\0')
1809 error(_("blank TARGET field on Link line"));
1810 return;
1812 if (!namecheck(fields[LF_LINKNAME]))
1813 return;
1814 l.l_filename = filename;
1815 l.l_linenum = linenum;
1816 l.l_target = ecpyalloc(fields[LF_TARGET]);
1817 l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
1818 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1819 links[nlinks++] = l;
1822 static void
1823 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1824 const char *typep, const char *monthp, const char *dayp,
1825 const char *timep)
1827 const struct lookup *lp;
1828 const char *cp;
1829 char *dp;
1830 char *ep;
1831 char xs;
1833 /* PG: year_tmp is to avoid sscanf portability issues */
1834 int year_tmp;
1836 if ((lp = byword(monthp, mon_names)) == NULL)
1838 error(_("invalid month name"));
1839 return;
1841 rp->r_month = lp->l_value;
1842 rp->r_todisstd = false;
1843 rp->r_todisut = false;
1844 dp = ecpyalloc(timep);
1845 if (*dp != '\0')
1847 ep = dp + strlen(dp) - 1;
1848 switch (lowerit(*ep))
1850 case 's': /* Standard */
1851 rp->r_todisstd = true;
1852 rp->r_todisut = false;
1853 *ep = '\0';
1854 break;
1855 case 'w': /* Wall */
1856 rp->r_todisstd = false;
1857 rp->r_todisut = false;
1858 *ep = '\0';
1859 break;
1860 case 'g': /* Greenwich */
1861 case 'u': /* Universal */
1862 case 'z': /* Zulu */
1863 rp->r_todisstd = true;
1864 rp->r_todisut = true;
1865 *ep = '\0';
1866 break;
1869 rp->r_tod = gethms(dp, _("invalid time of day"));
1870 free(dp);
1873 * Year work.
1875 cp = loyearp;
1876 lp = byword(cp, begin_years);
1877 rp->r_lowasnum = lp == NULL;
1878 if (!rp->r_lowasnum)
1879 switch (lp->l_value)
1881 case YR_MINIMUM:
1882 rp->r_loyear = ZIC_MIN;
1883 break;
1884 case YR_MAXIMUM:
1885 rp->r_loyear = ZIC_MAX;
1886 break;
1887 default: /* "cannot happen" */
1888 fprintf(stderr,
1889 _("%s: panic: Invalid l_value %d\n"),
1890 progname, lp->l_value);
1891 exit(EXIT_FAILURE);
1893 else if (sscanf(cp, "%d%c", &year_tmp, &xs) == 1)
1894 rp->r_loyear = year_tmp;
1895 else
1897 error(_("invalid starting year"));
1898 return;
1900 cp = hiyearp;
1901 lp = byword(cp, end_years);
1902 rp->r_hiwasnum = lp == NULL;
1903 if (!rp->r_hiwasnum)
1904 switch (lp->l_value)
1906 case YR_MINIMUM:
1907 rp->r_hiyear = ZIC_MIN;
1908 break;
1909 case YR_MAXIMUM:
1910 rp->r_hiyear = ZIC_MAX;
1911 break;
1912 case YR_ONLY:
1913 rp->r_hiyear = rp->r_loyear;
1914 break;
1915 default: /* "cannot happen" */
1916 fprintf(stderr,
1917 _("%s: panic: Invalid l_value %d\n"),
1918 progname, lp->l_value);
1919 exit(EXIT_FAILURE);
1921 else if (sscanf(cp, "%d%c", &year_tmp, &xs) == 1)
1922 rp->r_hiyear = year_tmp;
1923 else
1925 error(_("invalid ending year"));
1926 return;
1928 if (rp->r_loyear > rp->r_hiyear)
1930 error(_("starting year greater than ending year"));
1931 return;
1933 if (*typep != '\0')
1935 error(_("year type \"%s\" is unsupported; use \"-\" instead"),
1936 typep);
1937 return;
1941 * Day work. Accept things such as: 1 lastSunday last-Sunday
1942 * (undocumented; warn about this) Sun<=20 Sun>=7
1944 dp = ecpyalloc(dayp);
1945 if ((lp = byword(dp, lasts)) != NULL)
1947 rp->r_dycode = DC_DOWLEQ;
1948 rp->r_wday = lp->l_value;
1949 rp->r_dayofmonth = len_months[1][rp->r_month];
1951 else
1953 if ((ep = strchr(dp, '<')) != NULL)
1954 rp->r_dycode = DC_DOWLEQ;
1955 else if ((ep = strchr(dp, '>')) != NULL)
1956 rp->r_dycode = DC_DOWGEQ;
1957 else
1959 ep = dp;
1960 rp->r_dycode = DC_DOM;
1962 if (rp->r_dycode != DC_DOM)
1964 *ep++ = 0;
1965 if (*ep++ != '=')
1967 error(_("invalid day of month"));
1968 free(dp);
1969 return;
1971 if ((lp = byword(dp, wday_names)) == NULL)
1973 error(_("invalid weekday name"));
1974 free(dp);
1975 return;
1977 rp->r_wday = lp->l_value;
1979 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1980 rp->r_dayofmonth <= 0 ||
1981 (rp->r_dayofmonth > len_months[1][rp->r_month]))
1983 error(_("invalid day of month"));
1984 free(dp);
1985 return;
1988 free(dp);
1991 static void
1992 convert(const int32 val, char *const buf)
1994 int i;
1995 int shift;
1996 unsigned char *const b = (unsigned char *) buf;
1998 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1999 b[i] = val >> shift;
2002 static void
2003 convert64(const zic_t val, char *const buf)
2005 int i;
2006 int shift;
2007 unsigned char *const b = (unsigned char *) buf;
2009 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
2010 b[i] = val >> shift;
2013 static void
2014 puttzcode(const int32 val, FILE *const fp)
2016 char buf[4];
2018 convert(val, buf);
2019 fwrite(buf, sizeof buf, 1, fp);
2022 static void
2023 puttzcodepass(zic_t val, FILE *fp, int pass)
2025 if (pass == 1)
2026 puttzcode(val, fp);
2027 else
2029 char buf[8];
2031 convert64(val, buf);
2032 fwrite(buf, sizeof buf, 1, fp);
2036 static int
2037 atcomp(const void *avp, const void *bvp)
2039 const zic_t a = ((const struct attype *) avp)->at;
2040 const zic_t b = ((const struct attype *) bvp)->at;
2042 return (a < b) ? -1 : (a > b);
2045 struct timerange
2047 int defaulttype;
2048 ptrdiff_t base,
2049 count;
2050 int leapbase,
2051 leapcount;
2054 static struct timerange
2055 limitrange(struct timerange r, zic_t lo, zic_t hi,
2056 zic_t const *ats, unsigned char const *types)
2058 while (0 < r.count && ats[r.base] < lo)
2060 r.defaulttype = types[r.base];
2061 r.count--;
2062 r.base++;
2064 while (0 < r.leapcount && trans[r.leapbase] < lo)
2066 r.leapcount--;
2067 r.leapbase++;
2070 if (hi < ZIC_MAX)
2072 while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
2073 r.count--;
2074 while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
2075 r.leapcount--;
2078 return r;
2081 static void
2082 writezone(const char *const name, const char *const string, char version,
2083 int defaulttype)
2085 FILE *fp;
2086 ptrdiff_t i,
2088 int pass;
2089 static const struct tzhead tzh0;
2090 static struct tzhead tzh;
2091 bool dir_checked = false;
2092 zic_t one = 1;
2093 zic_t y2038_boundary = one << 31;
2094 ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
2097 * Allocate the ATS and TYPES arrays via a single malloc, as this is a bit
2098 * faster.
2100 zic_t *ats = emalloc(MAXALIGN(size_product(nats, sizeof *ats + 1)));
2101 void *typesptr = ats + nats;
2102 unsigned char *types = typesptr;
2103 struct timerange rangeall,
2104 range32,
2105 range64;
2108 * Sort.
2110 if (timecnt > 1)
2111 qsort(attypes, timecnt, sizeof *attypes, atcomp);
2114 * Optimize.
2117 ptrdiff_t fromi,
2118 toi;
2120 toi = 0;
2121 fromi = 0;
2122 for (; fromi < timecnt; ++fromi)
2124 if (toi != 0
2125 && ((attypes[fromi].at
2126 + utoffs[attypes[toi - 1].type])
2127 <= (attypes[toi - 1].at
2128 + utoffs[toi == 1 ? 0
2129 : attypes[toi - 2].type])))
2131 attypes[toi - 1].type =
2132 attypes[fromi].type;
2133 continue;
2135 if (toi == 0
2136 || attypes[fromi].dontmerge
2137 || (utoffs[attypes[toi - 1].type]
2138 != utoffs[attypes[fromi].type])
2139 || (isdsts[attypes[toi - 1].type]
2140 != isdsts[attypes[fromi].type])
2141 || (desigidx[attypes[toi - 1].type]
2142 != desigidx[attypes[fromi].type]))
2143 attypes[toi++] = attypes[fromi];
2145 timecnt = toi;
2148 if (noise && timecnt > 1200)
2150 if (timecnt > TZ_MAX_TIMES)
2151 warning(_("reference clients mishandle"
2152 " more than %d transition times"),
2153 TZ_MAX_TIMES);
2154 else
2155 warning(_("pre-2014 clients may mishandle"
2156 " more than 1200 transition times"));
2160 * Transfer.
2162 for (i = 0; i < timecnt; ++i)
2164 ats[i] = attypes[i].at;
2165 types[i] = attypes[i].type;
2169 * Correct for leap seconds.
2171 for (i = 0; i < timecnt; ++i)
2173 j = leapcnt;
2174 while (--j >= 0)
2175 if (ats[i] > trans[j] - corr[j])
2177 ats[i] = tadd(ats[i], corr[j]);
2178 break;
2183 * Work around QTBUG-53071 for timestamps less than y2038_boundary - 1, by
2184 * inserting a no-op transition at time y2038_boundary - 1. This works
2185 * only for timestamps before the boundary, which should be good enough in
2186 * practice as QTBUG-53071 should be long-dead by 2038. Do this after
2187 * correcting for leap seconds, as the idea is to insert a transition just
2188 * before 32-bit pg_time_t rolls around, and this occurs at a slightly
2189 * different moment if transitions are leap-second corrected.
2191 if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat()
2192 && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<'))
2194 ats[timecnt] = y2038_boundary - 1;
2195 types[timecnt] = types[timecnt - 1];
2196 timecnt++;
2199 rangeall.defaulttype = defaulttype;
2200 rangeall.base = rangeall.leapbase = 0;
2201 rangeall.count = timecnt;
2202 rangeall.leapcount = leapcnt;
2203 range64 = limitrange(rangeall, lo_time, hi_time, ats, types);
2204 range32 = limitrange(range64, PG_INT32_MIN, PG_INT32_MAX, ats, types);
2207 * Remove old file, if any, to snap links.
2209 if (remove(name) == 0)
2210 dir_checked = true;
2211 else if (errno != ENOENT)
2213 const char *e = strerror(errno);
2215 fprintf(stderr, _("%s: Cannot remove %s/%s: %s\n"),
2216 progname, directory, name, e);
2217 exit(EXIT_FAILURE);
2219 fp = fopen(name, "wb");
2220 if (!fp)
2222 int fopen_errno = errno;
2224 if (fopen_errno == ENOENT && !dir_checked)
2226 mkdirs(name, true);
2227 fp = fopen(name, "wb");
2228 fopen_errno = errno;
2230 if (!fp)
2232 fprintf(stderr, _("%s: Cannot create %s/%s: %s\n"),
2233 progname, directory, name, strerror(fopen_errno));
2234 exit(EXIT_FAILURE);
2237 for (pass = 1; pass <= 2; ++pass)
2239 ptrdiff_t thistimei,
2240 thistimecnt,
2241 thistimelim;
2242 int thisleapi,
2243 thisleapcnt,
2244 thisleaplim;
2245 int currenttype,
2246 thisdefaulttype;
2247 bool locut,
2248 hicut;
2249 zic_t lo;
2250 int old0;
2251 char omittype[TZ_MAX_TYPES];
2252 int typemap[TZ_MAX_TYPES];
2253 int thistypecnt,
2254 stdcnt,
2255 utcnt;
2256 char thischars[TZ_MAX_CHARS];
2257 int thischarcnt;
2258 bool toomanytimes;
2259 int indmap[TZ_MAX_CHARS];
2261 if (pass == 1)
2264 * Arguably the default time type in the 32-bit data should be
2265 * range32.defaulttype, which is suited for timestamps just before
2266 * PG_INT32_MIN. However, zic traditionally used the time type of
2267 * the indefinite past instead. Internet RFC 8532 says readers
2268 * should ignore 32-bit data, so this discrepancy matters only to
2269 * obsolete readers where the traditional type might be more
2270 * appropriate even if it's "wrong". So, use the historical zic
2271 * value, unless -r specifies a low cutoff that excludes some
2272 * 32-bit timestamps.
2274 thisdefaulttype = (lo_time <= PG_INT32_MIN
2275 ? range64.defaulttype
2276 : range32.defaulttype);
2278 thistimei = range32.base;
2279 thistimecnt = range32.count;
2280 toomanytimes = thistimecnt >> 31 >> 1 != 0;
2281 thisleapi = range32.leapbase;
2282 thisleapcnt = range32.leapcount;
2283 locut = PG_INT32_MIN < lo_time;
2284 hicut = hi_time < PG_INT32_MAX;
2286 else
2288 thisdefaulttype = range64.defaulttype;
2289 thistimei = range64.base;
2290 thistimecnt = range64.count;
2291 toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
2292 thisleapi = range64.leapbase;
2293 thisleapcnt = range64.leapcount;
2294 locut = min_time < lo_time;
2295 hicut = hi_time < max_time;
2297 if (toomanytimes)
2298 error(_("too many transition times"));
2301 * Keep the last too-low transition if no transition is exactly at LO.
2302 * The kept transition will be output as a LO "transition"; see
2303 * "Output a LO_TIME transition" below. This is needed when the
2304 * output is truncated at the start, and is also useful when catering
2305 * to buggy 32-bit clients that do not use time type 0 for timestamps
2306 * before the first transition.
2308 if (0 < thistimei && ats[thistimei] != lo_time)
2310 thistimei--;
2311 thistimecnt++;
2312 locut = false;
2315 thistimelim = thistimei + thistimecnt;
2316 thisleaplim = thisleapi + thisleapcnt;
2317 if (thistimecnt != 0)
2319 if (ats[thistimei] == lo_time)
2320 locut = false;
2321 if (hi_time < ZIC_MAX && ats[thistimelim - 1] == hi_time + 1)
2322 hicut = false;
2324 memset(omittype, true, typecnt);
2325 omittype[thisdefaulttype] = false;
2326 for (i = thistimei; i < thistimelim; i++)
2327 omittype[types[i]] = false;
2330 * Reorder types to make THISDEFAULTTYPE type 0. Use TYPEMAP to swap
2331 * OLD0 and THISDEFAULTTYPE so that THISDEFAULTTYPE appears as type 0
2332 * in the output instead of OLD0. TYPEMAP also omits unused types.
2334 old0 = strlen(omittype);
2336 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
2339 * For some pre-2011 systems: if the last-to-be-written standard (or
2340 * daylight) type has an offset different from the most recently used
2341 * offset, append an (unused) copy of the most recently used type (to
2342 * help get global "altzone" and "timezone" variables set correctly).
2344 if (want_bloat())
2346 int mrudst,
2347 mrustd,
2348 hidst,
2349 histd,
2350 type;
2352 hidst = histd = mrudst = mrustd = -1;
2353 for (i = thistimei; i < thistimelim; ++i)
2354 if (isdsts[types[i]])
2355 mrudst = types[i];
2356 else
2357 mrustd = types[i];
2358 for (i = old0; i < typecnt; i++)
2360 int h = (i == old0 ? thisdefaulttype
2361 : i == thisdefaulttype ? old0 : i);
2363 if (!omittype[h])
2365 if (isdsts[h])
2366 hidst = i;
2367 else
2368 histd = i;
2371 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
2372 utoffs[hidst] != utoffs[mrudst])
2374 isdsts[mrudst] = -1;
2375 type = addtype(utoffs[mrudst],
2376 &chars[desigidx[mrudst]],
2377 true,
2378 ttisstds[mrudst],
2379 ttisuts[mrudst]);
2380 isdsts[mrudst] = 1;
2381 omittype[type] = false;
2383 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
2384 utoffs[histd] != utoffs[mrustd])
2386 isdsts[mrustd] = -1;
2387 type = addtype(utoffs[mrustd],
2388 &chars[desigidx[mrustd]],
2389 false,
2390 ttisstds[mrustd],
2391 ttisuts[mrustd]);
2392 isdsts[mrustd] = 0;
2393 omittype[type] = false;
2396 #endif /* !defined
2397 * LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
2398 thistypecnt = 0;
2399 for (i = old0; i < typecnt; i++)
2400 if (!omittype[i])
2401 typemap[i == old0 ? thisdefaulttype
2402 : i == thisdefaulttype ? old0 : i]
2403 = thistypecnt++;
2405 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
2406 indmap[i] = -1;
2407 thischarcnt = stdcnt = utcnt = 0;
2408 for (i = old0; i < typecnt; i++)
2410 char *thisabbr;
2412 if (omittype[i])
2413 continue;
2414 if (ttisstds[i])
2415 stdcnt = thistypecnt;
2416 if (ttisuts[i])
2417 utcnt = thistypecnt;
2418 if (indmap[desigidx[i]] >= 0)
2419 continue;
2420 thisabbr = &chars[desigidx[i]];
2421 for (j = 0; j < thischarcnt; ++j)
2422 if (strcmp(&thischars[j], thisabbr) == 0)
2423 break;
2424 if (j == thischarcnt)
2426 strcpy(&thischars[thischarcnt], thisabbr);
2427 thischarcnt += strlen(thisabbr) + 1;
2429 indmap[desigidx[i]] = j;
2431 if (pass == 1 && !want_bloat())
2433 utcnt = stdcnt = thisleapcnt = 0;
2434 thistimecnt = -(locut + hicut);
2435 thistypecnt = thischarcnt = 1;
2436 thistimelim = thistimei;
2438 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
2439 tzh = tzh0;
2440 memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
2441 tzh.tzh_version[0] = version;
2442 convert(utcnt, tzh.tzh_ttisutcnt);
2443 convert(stdcnt, tzh.tzh_ttisstdcnt);
2444 convert(thisleapcnt, tzh.tzh_leapcnt);
2445 convert(locut + thistimecnt + hicut, tzh.tzh_timecnt);
2446 convert(thistypecnt, tzh.tzh_typecnt);
2447 convert(thischarcnt, tzh.tzh_charcnt);
2448 DO(tzh_magic);
2449 DO(tzh_version);
2450 DO(tzh_reserved);
2451 DO(tzh_ttisutcnt);
2452 DO(tzh_ttisstdcnt);
2453 DO(tzh_leapcnt);
2454 DO(tzh_timecnt);
2455 DO(tzh_typecnt);
2456 DO(tzh_charcnt);
2457 #undef DO
2458 if (pass == 1 && !want_bloat())
2460 /* Output a minimal data block with just one time type. */
2461 puttzcode(0, fp); /* utoff */
2462 putc(0, fp); /* dst */
2463 putc(0, fp); /* index of abbreviation */
2464 putc(0, fp); /* empty-string abbreviation */
2465 continue;
2468 /* PG: print current timezone abbreviations if requested */
2469 if (print_abbrevs && pass == 2)
2471 /* Print "type" data for periods ending after print_cutoff */
2472 for (i = thistimei; i < thistimelim; ++i)
2474 if (i == thistimelim - 1 || ats[i + 1] > print_cutoff)
2476 unsigned char tm = types[i];
2477 char *thisabbrev = &thischars[indmap[desigidx[tm]]];
2479 fprintf(stdout, "%s\t" INT64_FORMAT "%s\n",
2480 thisabbrev,
2481 utoffs[tm],
2482 isdsts[tm] ? "\tD" : "");
2485 /* Print the default type if we have no transitions at all */
2486 if (thistimei >= thistimelim)
2488 unsigned char tm = defaulttype;
2489 char *thisabbrev = &thischars[indmap[desigidx[tm]]];
2491 fprintf(stdout, "%s\t" INT64_FORMAT "%s\n",
2492 thisabbrev,
2493 utoffs[tm],
2494 isdsts[tm] ? "\tD" : "");
2499 * Output a LO_TIME transition if needed; see limitrange. But do not
2500 * go below the minimum representable value for this pass.
2502 lo = pass == 1 && lo_time < PG_INT32_MIN ? PG_INT32_MIN : lo_time;
2504 if (locut)
2505 puttzcodepass(lo, fp, pass);
2506 for (i = thistimei; i < thistimelim; ++i)
2508 zic_t at = ats[i] < lo ? lo : ats[i];
2510 puttzcodepass(at, fp, pass);
2512 if (hicut)
2513 puttzcodepass(hi_time + 1, fp, pass);
2514 currenttype = 0;
2515 if (locut)
2516 putc(currenttype, fp);
2517 for (i = thistimei; i < thistimelim; ++i)
2519 currenttype = typemap[types[i]];
2520 putc(currenttype, fp);
2522 if (hicut)
2523 putc(currenttype, fp);
2525 for (i = old0; i < typecnt; i++)
2527 int h = (i == old0 ? thisdefaulttype
2528 : i == thisdefaulttype ? old0 : i);
2530 if (!omittype[h])
2532 puttzcode(utoffs[h], fp);
2533 putc(isdsts[h], fp);
2534 putc(indmap[desigidx[h]], fp);
2537 if (thischarcnt != 0)
2538 fwrite(thischars, sizeof thischars[0],
2539 thischarcnt, fp);
2540 for (i = thisleapi; i < thisleaplim; ++i)
2542 zic_t todo;
2544 if (roll[i])
2546 if (timecnt == 0 || trans[i] < ats[0])
2548 j = 0;
2549 while (isdsts[j])
2550 if (++j >= typecnt)
2552 j = 0;
2553 break;
2556 else
2558 j = 1;
2559 while (j < timecnt &&
2560 trans[i] >= ats[j])
2561 ++j;
2562 j = types[j - 1];
2564 todo = tadd(trans[i], -utoffs[j]);
2566 else
2567 todo = trans[i];
2568 puttzcodepass(todo, fp, pass);
2569 puttzcode(corr[i], fp);
2571 if (stdcnt != 0)
2572 for (i = old0; i < typecnt; i++)
2573 if (!omittype[i])
2574 putc(ttisstds[i], fp);
2575 if (utcnt != 0)
2576 for (i = old0; i < typecnt; i++)
2577 if (!omittype[i])
2578 putc(ttisuts[i], fp);
2580 fprintf(fp, "\n%s\n", string);
2581 close_file(fp, directory, name);
2582 free(ats);
2585 static char const *
2586 abbroffset(char *buf, zic_t offset)
2588 char sign = '+';
2589 int seconds,
2590 minutes;
2592 if (offset < 0)
2594 offset = -offset;
2595 sign = '-';
2598 seconds = offset % SECSPERMIN;
2599 offset /= SECSPERMIN;
2600 minutes = offset % MINSPERHOUR;
2601 offset /= MINSPERHOUR;
2602 if (100 <= offset)
2604 error(_("%%z UT offset magnitude exceeds 99:59:59"));
2605 return "%z";
2607 else
2609 char *p = buf;
2611 *p++ = sign;
2612 *p++ = '0' + offset / 10;
2613 *p++ = '0' + offset % 10;
2614 if (minutes | seconds)
2616 *p++ = '0' + minutes / 10;
2617 *p++ = '0' + minutes % 10;
2618 if (seconds)
2620 *p++ = '0' + seconds / 10;
2621 *p++ = '0' + seconds % 10;
2624 *p = '\0';
2625 return buf;
2629 static size_t
2630 doabbr(char *abbr, struct zone const *zp, char const *letters,
2631 bool isdst, zic_t save, bool doquotes)
2633 char *cp;
2634 char *slashp;
2635 size_t len;
2636 char const *format = zp->z_format;
2638 slashp = strchr(format, '/');
2639 if (slashp == NULL)
2641 char letterbuf[PERCENT_Z_LEN_BOUND + 1];
2643 if (zp->z_format_specifier == 'z')
2644 letters = abbroffset(letterbuf, zp->z_stdoff + save);
2645 else if (!letters)
2646 letters = "%s";
2647 sprintf(abbr, format, letters);
2649 else if (isdst)
2651 strcpy(abbr, slashp + 1);
2653 else
2655 memcpy(abbr, format, slashp - format);
2656 abbr[slashp - format] = '\0';
2658 len = strlen(abbr);
2659 if (!doquotes)
2660 return len;
2661 for (cp = abbr; is_alpha(*cp); cp++)
2662 continue;
2663 if (len > 0 && *cp == '\0')
2664 return len;
2665 abbr[len + 2] = '\0';
2666 abbr[len + 1] = '>';
2667 memmove(abbr + 1, abbr, len);
2668 abbr[0] = '<';
2669 return len + 2;
2672 static void
2673 updateminmax(const zic_t x)
2675 if (min_year > x)
2676 min_year = x;
2677 if (max_year < x)
2678 max_year = x;
2681 static int
2682 stringoffset(char *result, zic_t offset)
2684 int hours;
2685 int minutes;
2686 int seconds;
2687 bool negative = offset < 0;
2688 int len = negative;
2690 if (negative)
2692 offset = -offset;
2693 result[0] = '-';
2695 seconds = offset % SECSPERMIN;
2696 offset /= SECSPERMIN;
2697 minutes = offset % MINSPERHOUR;
2698 offset /= MINSPERHOUR;
2699 hours = offset;
2700 if (hours >= HOURSPERDAY * DAYSPERWEEK)
2702 result[0] = '\0';
2703 return 0;
2705 len += sprintf(result + len, "%d", hours);
2706 if (minutes != 0 || seconds != 0)
2708 len += sprintf(result + len, ":%02d", minutes);
2709 if (seconds != 0)
2710 len += sprintf(result + len, ":%02d", seconds);
2712 return len;
2715 static int
2716 stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff)
2718 zic_t tod = rp->r_tod;
2719 int compat = 0;
2721 if (rp->r_dycode == DC_DOM)
2723 int month,
2724 total;
2726 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2727 return -1;
2728 total = 0;
2729 for (month = 0; month < rp->r_month; ++month)
2730 total += len_months[0][month];
2731 /* Omit the "J" in Jan and Feb, as that's shorter. */
2732 if (rp->r_month <= 1)
2733 result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
2734 else
2735 result += sprintf(result, "J%d", total + rp->r_dayofmonth);
2737 else
2739 int week;
2740 int wday = rp->r_wday;
2741 int wdayoff;
2743 if (rp->r_dycode == DC_DOWGEQ)
2745 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2746 if (wdayoff)
2747 compat = 2013;
2748 wday -= wdayoff;
2749 tod += wdayoff * SECSPERDAY;
2750 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2752 else if (rp->r_dycode == DC_DOWLEQ)
2754 if (rp->r_dayofmonth == len_months[1][rp->r_month])
2755 week = 5;
2756 else
2758 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2759 if (wdayoff)
2760 compat = 2013;
2761 wday -= wdayoff;
2762 tod += wdayoff * SECSPERDAY;
2763 week = rp->r_dayofmonth / DAYSPERWEEK;
2766 else
2767 return -1; /* "cannot happen" */
2768 if (wday < 0)
2769 wday += DAYSPERWEEK;
2770 result += sprintf(result, "M%d.%d.%d",
2771 rp->r_month + 1, week, wday);
2773 if (rp->r_todisut)
2774 tod += stdoff;
2775 if (rp->r_todisstd && !rp->r_isdst)
2776 tod += save;
2777 if (tod != 2 * SECSPERMIN * MINSPERHOUR)
2779 *result++ = '/';
2780 if (!stringoffset(result, tod))
2781 return -1;
2782 if (tod < 0)
2784 if (compat < 2013)
2785 compat = 2013;
2787 else if (SECSPERDAY <= tod)
2789 if (compat < 1994)
2790 compat = 1994;
2793 return compat;
2796 static int
2797 rule_cmp(struct rule const *a, struct rule const *b)
2799 if (!a)
2800 return -!!b;
2801 if (!b)
2802 return 1;
2803 if (a->r_hiyear != b->r_hiyear)
2804 return a->r_hiyear < b->r_hiyear ? -1 : 1;
2805 if (a->r_month - b->r_month != 0)
2806 return a->r_month - b->r_month;
2807 return a->r_dayofmonth - b->r_dayofmonth;
2810 static int
2811 stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
2813 const struct zone *zp;
2814 struct rule *rp;
2815 struct rule *stdrp;
2816 struct rule *dstrp;
2817 ptrdiff_t i;
2818 const char *abbrvar;
2819 int compat = 0;
2820 int c;
2821 size_t len;
2822 int offsetlen;
2823 struct rule stdr,
2824 dstr;
2826 result[0] = '\0';
2829 * Internet RFC 8536 section 5.1 says to use an empty TZ string if future
2830 * timestamps are truncated.
2832 if (hi_time < max_time)
2833 return -1;
2835 zp = zpfirst + zonecount - 1;
2836 stdrp = dstrp = NULL;
2837 for (i = 0; i < zp->z_nrules; ++i)
2839 rp = &zp->z_rules[i];
2840 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
2841 continue;
2842 if (!rp->r_isdst)
2844 if (stdrp == NULL)
2845 stdrp = rp;
2846 else
2847 return -1;
2849 else
2851 if (dstrp == NULL)
2852 dstrp = rp;
2853 else
2854 return -1;
2857 if (stdrp == NULL && dstrp == NULL)
2860 * There are no rules running through "max". Find the latest std rule
2861 * in stdabbrrp and latest rule of any type in stdrp.
2863 struct rule *stdabbrrp = NULL;
2865 for (i = 0; i < zp->z_nrules; ++i)
2867 rp = &zp->z_rules[i];
2868 if (!rp->r_isdst && rule_cmp(stdabbrrp, rp) < 0)
2869 stdabbrrp = rp;
2870 if (rule_cmp(stdrp, rp) < 0)
2871 stdrp = rp;
2873 if (stdrp != NULL && stdrp->r_isdst)
2875 /* Perpetual DST. */
2876 dstr.r_month = TM_JANUARY;
2877 dstr.r_dycode = DC_DOM;
2878 dstr.r_dayofmonth = 1;
2879 dstr.r_tod = 0;
2880 dstr.r_todisstd = dstr.r_todisut = false;
2881 dstr.r_isdst = stdrp->r_isdst;
2882 dstr.r_save = stdrp->r_save;
2883 dstr.r_abbrvar = stdrp->r_abbrvar;
2884 stdr.r_month = TM_DECEMBER;
2885 stdr.r_dycode = DC_DOM;
2886 stdr.r_dayofmonth = 31;
2887 stdr.r_tod = SECSPERDAY + stdrp->r_save;
2888 stdr.r_todisstd = stdr.r_todisut = false;
2889 stdr.r_isdst = false;
2890 stdr.r_save = 0;
2891 stdr.r_abbrvar
2892 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2893 dstrp = &dstr;
2894 stdrp = &stdr;
2897 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_isdst))
2898 return -1;
2899 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2900 len = doabbr(result, zp, abbrvar, false, 0, true);
2901 offsetlen = stringoffset(result + len, -zp->z_stdoff);
2902 if (!offsetlen)
2904 result[0] = '\0';
2905 return -1;
2907 len += offsetlen;
2908 if (dstrp == NULL)
2909 return compat;
2910 len += doabbr(result + len, zp, dstrp->r_abbrvar,
2911 dstrp->r_isdst, dstrp->r_save, true);
2912 if (dstrp->r_save != SECSPERMIN * MINSPERHOUR)
2914 offsetlen = stringoffset(result + len,
2915 -(zp->z_stdoff + dstrp->r_save));
2916 if (!offsetlen)
2918 result[0] = '\0';
2919 return -1;
2921 len += offsetlen;
2923 result[len++] = ',';
2924 c = stringrule(result + len, dstrp, dstrp->r_save, zp->z_stdoff);
2925 if (c < 0)
2927 result[0] = '\0';
2928 return -1;
2930 if (compat < c)
2931 compat = c;
2932 len += strlen(result + len);
2933 result[len++] = ',';
2934 c = stringrule(result + len, stdrp, dstrp->r_save, zp->z_stdoff);
2935 if (c < 0)
2937 result[0] = '\0';
2938 return -1;
2940 if (compat < c)
2941 compat = c;
2942 return compat;
2945 static void
2946 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
2948 const struct zone *zp;
2949 struct rule *rp;
2950 ptrdiff_t i,
2952 bool usestart,
2953 useuntil;
2954 zic_t starttime,
2955 untiltime;
2956 zic_t stdoff;
2957 zic_t save;
2958 zic_t year;
2959 zic_t startoff;
2960 bool startttisstd;
2961 bool startttisut;
2962 int type;
2963 char *startbuf;
2964 char *ab;
2965 char *envvar;
2966 int max_abbr_len;
2967 int max_envvar_len;
2968 bool prodstic; /* all rules are min to max */
2969 int compat;
2970 bool do_extend;
2971 char version;
2972 ptrdiff_t lastatmax = -1;
2973 zic_t one = 1;
2974 zic_t y2038_boundary = one << 31;
2975 zic_t max_year0;
2976 int defaulttype = -1;
2978 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2979 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2980 startbuf = emalloc(max_abbr_len + 1);
2981 ab = emalloc(max_abbr_len + 1);
2982 envvar = emalloc(max_envvar_len + 1);
2983 INITIALIZE(untiltime);
2984 INITIALIZE(starttime);
2987 * Now. . .finally. . .generate some useful data!
2989 timecnt = 0;
2990 typecnt = 0;
2991 charcnt = 0;
2992 prodstic = zonecount == 1;
2995 * Thanks to Earl Chew for noting the need to unconditionally initialize
2996 * startttisstd.
2998 startttisstd = false;
2999 startttisut = false;
3000 min_year = max_year = EPOCH_YEAR;
3001 if (leapseen)
3003 updateminmax(leapminyear);
3004 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
3006 for (i = 0; i < zonecount; ++i)
3008 zp = &zpfirst[i];
3009 if (i < zonecount - 1)
3010 updateminmax(zp->z_untilrule.r_loyear);
3011 for (j = 0; j < zp->z_nrules; ++j)
3013 rp = &zp->z_rules[j];
3014 if (rp->r_lowasnum)
3015 updateminmax(rp->r_loyear);
3016 if (rp->r_hiwasnum)
3017 updateminmax(rp->r_hiyear);
3018 if (rp->r_lowasnum || rp->r_hiwasnum)
3019 prodstic = false;
3024 * Generate lots of data if a rule can't cover all future times.
3026 compat = stringzone(envvar, zpfirst, zonecount);
3027 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
3028 do_extend = compat < 0;
3029 if (noise)
3031 if (!*envvar)
3032 warning("%s %s",
3033 _("no POSIX environment variable for zone"),
3034 zpfirst->z_name);
3035 else if (compat != 0)
3038 * Circa-COMPAT clients, and earlier clients, might not work for
3039 * this zone when given dates before 1970 or after 2038.
3041 warning(_("%s: pre-%d clients may mishandle"
3042 " distant timestamps"),
3043 zpfirst->z_name, compat);
3046 if (do_extend)
3049 * Search through a couple of extra years past the obvious 400, to
3050 * avoid edge cases. For example, suppose a non-POSIX rule applies
3051 * from 2012 onwards and has transitions in March and September, plus
3052 * some one-off transitions in November 2013. If zic looked only at
3053 * the last 400 years, it would set max_year=2413, with the intent
3054 * that the 400 years 2014 through 2413 will be repeated. The last
3055 * transition listed in the tzfile would be in 2413-09, less than 400
3056 * years after the last one-off transition in 2013-11. Two years
3057 * might be overkill, but with the kind of edge cases available we're
3058 * not sure that one year would suffice.
3060 enum
3062 years_of_observations = YEARSPERREPEAT + 2};
3064 if (min_year >= ZIC_MIN + years_of_observations)
3065 min_year -= years_of_observations;
3066 else
3067 min_year = ZIC_MIN;
3068 if (max_year <= ZIC_MAX - years_of_observations)
3069 max_year += years_of_observations;
3070 else
3071 max_year = ZIC_MAX;
3074 * Regardless of any of the above, for a "proDSTic" zone which
3075 * specifies that its rules always have and always will be in effect,
3076 * we only need one cycle to define the zone.
3078 if (prodstic)
3080 min_year = 1900;
3081 max_year = min_year + years_of_observations;
3084 max_year0 = max_year;
3085 if (want_bloat())
3088 * For the benefit of older systems, generate data from 1900 through
3089 * 2038.
3091 if (min_year > 1900)
3092 min_year = 1900;
3093 if (max_year < 2038)
3094 max_year = 2038;
3097 for (i = 0; i < zonecount; ++i)
3099 struct rule *prevrp = NULL;
3102 * A guess that may well be corrected later.
3104 save = 0;
3105 zp = &zpfirst[i];
3106 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
3107 useuntil = i < (zonecount - 1);
3108 if (useuntil && zp->z_untiltime <= min_time)
3109 continue;
3110 stdoff = zp->z_stdoff;
3111 eat(zp->z_filename, zp->z_linenum);
3112 *startbuf = '\0';
3113 startoff = zp->z_stdoff;
3114 if (zp->z_nrules == 0)
3116 save = zp->z_save;
3117 doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
3118 type = addtype(oadd(zp->z_stdoff, save),
3119 startbuf, zp->z_isdst, startttisstd,
3120 startttisut);
3121 if (usestart)
3123 addtt(starttime, type);
3124 usestart = false;
3126 else
3127 defaulttype = type;
3129 else
3130 for (year = min_year; year <= max_year; ++year)
3132 if (useuntil && year > zp->z_untilrule.r_hiyear)
3133 break;
3136 * Mark which rules to do in the current year. For those to
3137 * do, calculate rpytime(rp, year); The former TYPE field was
3138 * also considered here.
3140 for (j = 0; j < zp->z_nrules; ++j)
3142 rp = &zp->z_rules[j];
3143 eats(zp->z_filename, zp->z_linenum,
3144 rp->r_filename, rp->r_linenum);
3145 rp->r_todo = year >= rp->r_loyear &&
3146 year <= rp->r_hiyear;
3147 if (rp->r_todo)
3149 rp->r_temp = rpytime(rp, year);
3150 rp->r_todo
3151 = (rp->r_temp < y2038_boundary
3152 || year <= max_year0);
3155 for (;;)
3157 ptrdiff_t k;
3158 zic_t jtime,
3159 ktime;
3160 zic_t offset;
3162 INITIALIZE(ktime);
3163 if (useuntil)
3166 * Turn untiltime into UT assuming the current stdoff
3167 * and save values.
3169 untiltime = zp->z_untiltime;
3170 if (!zp->z_untilrule.r_todisut)
3171 untiltime = tadd(untiltime,
3172 -stdoff);
3173 if (!zp->z_untilrule.r_todisstd)
3174 untiltime = tadd(untiltime,
3175 -save);
3179 * Find the rule (of those to do, if any) that takes
3180 * effect earliest in the year.
3182 k = -1;
3183 for (j = 0; j < zp->z_nrules; ++j)
3185 rp = &zp->z_rules[j];
3186 if (!rp->r_todo)
3187 continue;
3188 eats(zp->z_filename, zp->z_linenum,
3189 rp->r_filename, rp->r_linenum);
3190 offset = rp->r_todisut ? 0 : stdoff;
3191 if (!rp->r_todisstd)
3192 offset = oadd(offset, save);
3193 jtime = rp->r_temp;
3194 if (jtime == min_time ||
3195 jtime == max_time)
3196 continue;
3197 jtime = tadd(jtime, -offset);
3198 if (k < 0 || jtime < ktime)
3200 k = j;
3201 ktime = jtime;
3203 else if (jtime == ktime)
3205 char const *dup_rules_msg =
3206 _("two rules for same instant");
3208 eats(zp->z_filename, zp->z_linenum,
3209 rp->r_filename, rp->r_linenum);
3210 warning("%s", dup_rules_msg);
3211 rp = &zp->z_rules[k];
3212 eats(zp->z_filename, zp->z_linenum,
3213 rp->r_filename, rp->r_linenum);
3214 error("%s", dup_rules_msg);
3217 if (k < 0)
3218 break; /* go on to next year */
3219 rp = &zp->z_rules[k];
3220 rp->r_todo = false;
3221 if (useuntil && ktime >= untiltime)
3222 break;
3223 save = rp->r_save;
3224 if (usestart && ktime == starttime)
3225 usestart = false;
3226 if (usestart)
3228 if (ktime < starttime)
3230 startoff = oadd(zp->z_stdoff,
3231 save);
3232 doabbr(startbuf, zp,
3233 rp->r_abbrvar,
3234 rp->r_isdst,
3235 rp->r_save,
3236 false);
3237 continue;
3239 if (*startbuf == '\0'
3240 && startoff == oadd(zp->z_stdoff,
3241 save))
3243 doabbr(startbuf,
3245 rp->r_abbrvar,
3246 rp->r_isdst,
3247 rp->r_save,
3248 false);
3251 eats(zp->z_filename, zp->z_linenum,
3252 rp->r_filename, rp->r_linenum);
3253 doabbr(ab, zp, rp->r_abbrvar,
3254 rp->r_isdst, rp->r_save, false);
3255 offset = oadd(zp->z_stdoff, rp->r_save);
3256 if (!want_bloat() && !useuntil && !do_extend
3257 && prevrp
3258 && rp->r_hiyear == ZIC_MAX
3259 && prevrp->r_hiyear == ZIC_MAX)
3260 break;
3261 type = addtype(offset, ab, rp->r_isdst,
3262 rp->r_todisstd, rp->r_todisut);
3263 if (defaulttype < 0 && !rp->r_isdst)
3264 defaulttype = type;
3265 if (rp->r_hiyear == ZIC_MAX
3266 && !(0 <= lastatmax
3267 && ktime < attypes[lastatmax].at))
3268 lastatmax = timecnt;
3269 addtt(ktime, type);
3270 prevrp = rp;
3273 if (usestart)
3275 if (*startbuf == '\0' &&
3276 zp->z_format != NULL &&
3277 strchr(zp->z_format, '%') == NULL &&
3278 strchr(zp->z_format, '/') == NULL)
3279 strcpy(startbuf, zp->z_format);
3280 eat(zp->z_filename, zp->z_linenum);
3281 if (*startbuf == '\0')
3282 error(_("cannot determine time zone abbreviation to use just after until time"));
3283 else
3285 bool isdst = startoff != zp->z_stdoff;
3287 type = addtype(startoff, startbuf, isdst,
3288 startttisstd, startttisut);
3289 if (defaulttype < 0 && !isdst)
3290 defaulttype = type;
3291 addtt(starttime, type);
3296 * Now we may get to set starttime for the next zone line.
3298 if (useuntil)
3300 startttisstd = zp->z_untilrule.r_todisstd;
3301 startttisut = zp->z_untilrule.r_todisut;
3302 starttime = zp->z_untiltime;
3303 if (!startttisstd)
3304 starttime = tadd(starttime, -save);
3305 if (!startttisut)
3306 starttime = tadd(starttime, -stdoff);
3309 if (defaulttype < 0)
3310 defaulttype = 0;
3311 if (0 <= lastatmax)
3312 attypes[lastatmax].dontmerge = true;
3313 if (do_extend)
3316 * If we're extending the explicitly listed observations for 400 years
3317 * because we can't fill the POSIX-TZ field, check whether we actually
3318 * ended up explicitly listing observations through that period. If
3319 * there aren't any near the end of the 400-year period, add a
3320 * redundant one at the end of the final year, to make it clear that
3321 * we are claiming to have definite knowledge of the lack of
3322 * transitions up to that point.
3324 struct rule xr;
3325 struct attype *lastat;
3327 xr.r_month = TM_JANUARY;
3328 xr.r_dycode = DC_DOM;
3329 xr.r_dayofmonth = 1;
3330 xr.r_tod = 0;
3331 for (lastat = attypes, i = 1; i < timecnt; i++)
3332 if (attypes[i].at > lastat->at)
3333 lastat = &attypes[i];
3334 if (!lastat || lastat->at < rpytime(&xr, max_year - 1))
3336 addtt(rpytime(&xr, max_year + 1),
3337 lastat ? lastat->type : defaulttype);
3338 attypes[timecnt - 1].dontmerge = true;
3341 writezone(zpfirst->z_name, envvar, version, defaulttype);
3342 free(startbuf);
3343 free(ab);
3344 free(envvar);
3347 static void
3348 addtt(zic_t starttime, int type)
3350 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
3351 attypes[timecnt].at = starttime;
3352 attypes[timecnt].dontmerge = false;
3353 attypes[timecnt].type = type;
3354 ++timecnt;
3357 static int
3358 addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
3360 int i,
3363 if (!(-1L - 2147483647L <= utoff && utoff <= 2147483647L))
3365 error(_("UT offset out of range"));
3366 exit(EXIT_FAILURE);
3368 if (!want_bloat())
3369 ttisstd = ttisut = false;
3371 for (j = 0; j < charcnt; ++j)
3372 if (strcmp(&chars[j], abbr) == 0)
3373 break;
3374 if (j == charcnt)
3375 newabbr(abbr);
3376 else
3378 /* If there's already an entry, return its index. */
3379 for (i = 0; i < typecnt; i++)
3380 if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
3381 && ttisstd == ttisstds[i] && ttisut == ttisuts[i])
3382 return i;
3386 * There isn't one; add a new one, unless there are already too many.
3388 if (typecnt >= TZ_MAX_TYPES)
3390 error(_("too many local time types"));
3391 exit(EXIT_FAILURE);
3393 i = typecnt++;
3394 utoffs[i] = utoff;
3395 isdsts[i] = isdst;
3396 ttisstds[i] = ttisstd;
3397 ttisuts[i] = ttisut;
3398 desigidx[i] = j;
3399 return i;
3402 static void
3403 leapadd(zic_t t, int correction, int rolling)
3405 int i;
3407 if (TZ_MAX_LEAPS <= leapcnt)
3409 error(_("too many leap seconds"));
3410 exit(EXIT_FAILURE);
3412 for (i = 0; i < leapcnt; ++i)
3413 if (t <= trans[i])
3414 break;
3415 memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans);
3416 memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr);
3417 memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll);
3418 trans[i] = t;
3419 corr[i] = correction;
3420 roll[i] = rolling;
3421 ++leapcnt;
3424 static void
3425 adjleap(void)
3427 int i;
3428 zic_t last = 0;
3429 zic_t prevtrans = 0;
3432 * propagate leap seconds forward
3434 for (i = 0; i < leapcnt; ++i)
3436 if (trans[i] - prevtrans < 28 * SECSPERDAY)
3438 error(_("Leap seconds too close together"));
3439 exit(EXIT_FAILURE);
3441 prevtrans = trans[i];
3442 trans[i] = tadd(trans[i], last);
3443 last = corr[i] += last;
3446 if (leapexpires < 0)
3448 leapexpires = comment_leapexpires;
3449 if (0 <= leapexpires)
3450 warning(_("\"#expires\" is obsolescent; use \"Expires\""));
3453 if (0 <= leapexpires)
3455 leapexpires = oadd(leapexpires, last);
3456 if (!(leapcnt == 0 || (trans[leapcnt - 1] < leapexpires)))
3458 error(_("last Leap time does not precede Expires time"));
3459 exit(EXIT_FAILURE);
3461 if (leapexpires <= hi_time)
3462 hi_time = leapexpires - 1;
3466 /* Is A a space character in the C locale? */
3467 static bool
3468 is_space(char a)
3470 switch (a)
3472 default:
3473 return false;
3474 case ' ':
3475 case '\f':
3476 case '\n':
3477 case '\r':
3478 case '\t':
3479 case '\v':
3480 return true;
3484 /* Is A an alphabetic character in the C locale? */
3485 static bool
3486 is_alpha(char a)
3488 switch (a)
3490 default:
3491 return false;
3492 case 'A':
3493 case 'B':
3494 case 'C':
3495 case 'D':
3496 case 'E':
3497 case 'F':
3498 case 'G':
3499 case 'H':
3500 case 'I':
3501 case 'J':
3502 case 'K':
3503 case 'L':
3504 case 'M':
3505 case 'N':
3506 case 'O':
3507 case 'P':
3508 case 'Q':
3509 case 'R':
3510 case 'S':
3511 case 'T':
3512 case 'U':
3513 case 'V':
3514 case 'W':
3515 case 'X':
3516 case 'Y':
3517 case 'Z':
3518 case 'a':
3519 case 'b':
3520 case 'c':
3521 case 'd':
3522 case 'e':
3523 case 'f':
3524 case 'g':
3525 case 'h':
3526 case 'i':
3527 case 'j':
3528 case 'k':
3529 case 'l':
3530 case 'm':
3531 case 'n':
3532 case 'o':
3533 case 'p':
3534 case 'q':
3535 case 'r':
3536 case 's':
3537 case 't':
3538 case 'u':
3539 case 'v':
3540 case 'w':
3541 case 'x':
3542 case 'y':
3543 case 'z':
3544 return true;
3548 /* If A is an uppercase character in the C locale, return its lowercase
3549 counterpart. Otherwise, return A. */
3550 static char
3551 lowerit(char a)
3553 switch (a)
3555 default:
3556 return a;
3557 case 'A':
3558 return 'a';
3559 case 'B':
3560 return 'b';
3561 case 'C':
3562 return 'c';
3563 case 'D':
3564 return 'd';
3565 case 'E':
3566 return 'e';
3567 case 'F':
3568 return 'f';
3569 case 'G':
3570 return 'g';
3571 case 'H':
3572 return 'h';
3573 case 'I':
3574 return 'i';
3575 case 'J':
3576 return 'j';
3577 case 'K':
3578 return 'k';
3579 case 'L':
3580 return 'l';
3581 case 'M':
3582 return 'm';
3583 case 'N':
3584 return 'n';
3585 case 'O':
3586 return 'o';
3587 case 'P':
3588 return 'p';
3589 case 'Q':
3590 return 'q';
3591 case 'R':
3592 return 'r';
3593 case 'S':
3594 return 's';
3595 case 'T':
3596 return 't';
3597 case 'U':
3598 return 'u';
3599 case 'V':
3600 return 'v';
3601 case 'W':
3602 return 'w';
3603 case 'X':
3604 return 'x';
3605 case 'Y':
3606 return 'y';
3607 case 'Z':
3608 return 'z';
3612 /* case-insensitive equality */
3613 static bool
3614 ciequal(const char *ap, const char *bp)
3616 while (lowerit(*ap) == lowerit(*bp++))
3617 if (*ap++ == '\0')
3618 return true;
3619 return false;
3622 static bool
3623 itsabbr(const char *abbr, const char *word)
3625 if (lowerit(*abbr) != lowerit(*word))
3626 return false;
3627 ++word;
3628 while (*++abbr != '\0')
3631 if (*word == '\0')
3632 return false;
3633 } while (lowerit(*word++) != lowerit(*abbr));
3634 return true;
3637 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
3639 static bool
3640 ciprefix(char const *abbr, char const *word)
3643 if (!*abbr)
3644 return true;
3645 while (lowerit(*abbr++) == lowerit(*word++));
3647 return false;
3650 static const struct lookup *
3651 byword(const char *word, const struct lookup *table)
3653 const struct lookup *foundlp;
3654 const struct lookup *lp;
3656 if (word == NULL || table == NULL)
3657 return NULL;
3660 * If TABLE is LASTS and the word starts with "last" followed by a
3661 * non-'-', skip the "last" and look in WDAY_NAMES instead. Warn about any
3662 * usage of the undocumented prefix "last-".
3664 if (table == lasts && ciprefix("last", word) && word[4])
3666 if (word[4] == '-')
3667 warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
3668 word, word + 5);
3669 else
3671 word += 4;
3672 table = wday_names;
3677 * Look for exact match.
3679 for (lp = table; lp->l_word != NULL; ++lp)
3680 if (ciequal(word, lp->l_word))
3681 return lp;
3684 * Look for inexact match.
3686 foundlp = NULL;
3687 for (lp = table; lp->l_word != NULL; ++lp)
3688 if (ciprefix(word, lp->l_word))
3690 if (foundlp == NULL)
3691 foundlp = lp;
3692 else
3693 return NULL; /* multiple inexact matches */
3696 if (foundlp && noise)
3698 /* Warn about any backward-compatibility issue with pre-2017c zic. */
3699 bool pre_2017c_match = false;
3701 for (lp = table; lp->l_word; lp++)
3702 if (itsabbr(word, lp->l_word))
3704 if (pre_2017c_match)
3706 warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
3707 break;
3709 pre_2017c_match = true;
3713 return foundlp;
3716 static char **
3717 getfields(char *cp)
3719 char *dp;
3720 char **array;
3721 int nsubs;
3723 if (cp == NULL)
3724 return NULL;
3725 array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
3726 nsubs = 0;
3727 for (;;)
3729 while (is_space(*cp))
3730 ++cp;
3731 if (*cp == '\0' || *cp == '#')
3732 break;
3733 array[nsubs++] = dp = cp;
3736 if ((*dp = *cp++) != '"')
3737 ++dp;
3738 else
3739 while ((*dp = *cp++) != '"')
3740 if (*dp != '\0')
3741 ++dp;
3742 else
3744 error(_("Odd number of quotation marks"));
3745 exit(EXIT_FAILURE);
3747 } while (*cp && *cp != '#' && !is_space(*cp));
3748 if (is_space(*cp))
3749 ++cp;
3750 *dp = '\0';
3752 array[nsubs] = NULL;
3753 return array;
3756 static void
3757 time_overflow(void)
3759 error(_("time overflow"));
3760 exit(EXIT_FAILURE);
3763 static zic_t
3764 oadd(zic_t t1, zic_t t2)
3766 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
3767 time_overflow();
3768 return t1 + t2;
3771 static zic_t
3772 tadd(zic_t t1, zic_t t2)
3774 if (t1 < 0)
3776 if (t2 < min_time - t1)
3778 if (t1 != min_time)
3779 time_overflow();
3780 return min_time;
3783 else
3785 if (max_time - t1 < t2)
3787 if (t1 != max_time)
3788 time_overflow();
3789 return max_time;
3792 return t1 + t2;
3796 * Given a rule, and a year, compute the date (in seconds since January 1,
3797 * 1970, 00:00 LOCAL time) in that year that the rule refers to.
3800 static zic_t
3801 rpytime(const struct rule *rp, zic_t wantedy)
3803 int m,
3805 zic_t dayoff; /* with a nod to Margaret O. */
3806 zic_t t,
3809 if (wantedy == ZIC_MIN)
3810 return min_time;
3811 if (wantedy == ZIC_MAX)
3812 return max_time;
3813 dayoff = 0;
3814 m = TM_JANUARY;
3815 y = EPOCH_YEAR;
3816 if (y < wantedy)
3818 wantedy -= y;
3819 dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
3820 wantedy %= YEARSPERREPEAT;
3821 wantedy += y;
3823 else if (wantedy < 0)
3825 dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
3826 wantedy %= YEARSPERREPEAT;
3828 while (wantedy != y)
3830 if (wantedy > y)
3832 i = len_years[isleap(y)];
3833 ++y;
3835 else
3837 --y;
3838 i = -len_years[isleap(y)];
3840 dayoff = oadd(dayoff, i);
3842 while (m != rp->r_month)
3844 i = len_months[isleap(y)][m];
3845 dayoff = oadd(dayoff, i);
3846 ++m;
3848 i = rp->r_dayofmonth;
3849 if (m == TM_FEBRUARY && i == 29 && !isleap(y))
3851 if (rp->r_dycode == DC_DOWLEQ)
3852 --i;
3853 else
3855 error(_("use of 2/29 in non leap-year"));
3856 exit(EXIT_FAILURE);
3859 --i;
3860 dayoff = oadd(dayoff, i);
3861 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ)
3863 zic_t wday;
3865 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3866 wday = EPOCH_WDAY;
3869 * Don't trust mod of negative numbers.
3871 if (dayoff >= 0)
3872 wday = (wday + dayoff) % LDAYSPERWEEK;
3873 else
3875 wday -= ((-dayoff) % LDAYSPERWEEK);
3876 if (wday < 0)
3877 wday += LDAYSPERWEEK;
3879 while (wday != rp->r_wday)
3880 if (rp->r_dycode == DC_DOWGEQ)
3882 dayoff = oadd(dayoff, 1);
3883 if (++wday >= LDAYSPERWEEK)
3884 wday = 0;
3885 ++i;
3887 else
3889 dayoff = oadd(dayoff, -1);
3890 if (--wday < 0)
3891 wday = LDAYSPERWEEK - 1;
3892 --i;
3894 if (i < 0 || i >= len_months[isleap(y)][m])
3896 if (noise)
3897 warning(_("rule goes past start/end of month; \
3898 will not work with pre-2004 versions of zic"));
3901 if (dayoff < min_time / SECSPERDAY)
3902 return min_time;
3903 if (dayoff > max_time / SECSPERDAY)
3904 return max_time;
3905 t = (zic_t) dayoff * SECSPERDAY;
3906 return tadd(t, rp->r_tod);
3909 static void
3910 newabbr(const char *string)
3912 int i;
3914 if (strcmp(string, GRANDPARENTED) != 0)
3916 const char *cp;
3917 const char *mp;
3919 cp = string;
3920 mp = NULL;
3921 while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
3922 || *cp == '-' || *cp == '+')
3923 ++cp;
3924 if (noise && cp - string < 3)
3925 mp = _("time zone abbreviation has fewer than 3 characters");
3926 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
3927 mp = _("time zone abbreviation has too many characters");
3928 if (*cp != '\0')
3929 mp = _("time zone abbreviation differs from POSIX standard");
3930 if (mp != NULL)
3931 warning("%s (%s)", mp, string);
3933 i = strlen(string) + 1;
3934 if (charcnt + i > TZ_MAX_CHARS)
3936 error(_("too many, or too long, time zone abbreviations"));
3937 exit(EXIT_FAILURE);
3939 strcpy(&chars[charcnt], string);
3940 charcnt += i;
3943 /* Ensure that the directories of ARGNAME exist, by making any missing
3944 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3945 do it for ARGNAME too. Exit with failure if there is trouble.
3946 Do not consider an existing non-directory to be trouble. */
3947 static void
3948 mkdirs(char const *argname, bool ancestors)
3950 char *name;
3951 char *cp;
3953 cp = name = ecpyalloc(argname);
3956 * On MS-Windows systems, do not worry about drive letters or backslashes,
3957 * as this should suffice in practice. Time zone names do not use drive
3958 * letters and backslashes. If the -d option of zic does not name an
3959 * already-existing directory, it can use slashes to separate the
3960 * already-existing ancestor prefix from the to-be-created subdirectories.
3963 /* Do not mkdir a root directory, as it must exist. */
3964 while (*cp == '/')
3965 cp++;
3967 while (cp && ((cp = strchr(cp, '/')) || !ancestors))
3969 if (cp)
3970 *cp = '\0';
3973 * Try to create it. It's OK if creation fails because the directory
3974 * already exists, perhaps because some other process just created it.
3975 * For simplicity do not check first whether it already exists, as
3976 * that is checked anyway if the mkdir fails.
3978 if (mkdir(name, MKDIR_UMASK) != 0)
3981 * For speed, skip itsdir if errno == EEXIST. Since mkdirs is
3982 * called only after open fails with ENOENT on a subfile, EEXIST
3983 * implies itsdir here.
3985 int err = errno;
3987 if (err != EEXIST && !itsdir(name))
3989 error(_("%s: Cannot create directory %s: %s"),
3990 progname, name, strerror(err));
3991 exit(EXIT_FAILURE);
3994 if (cp)
3995 *cp++ = '/';
3997 free(name);
4001 #ifdef WIN32
4003 * To run on win32
4006 link(const char *oldpath, const char *newpath)
4008 if (!CopyFile(oldpath, newpath, false))
4010 _dosmaperr(GetLastError());
4011 return -1;
4013 return 0;
4015 #endif