Consistently use "superuser" instead of "super user"
[pgsql.git] / src / timezone / zic.c
blob0ea6ead2db3ae2c9f4a99d60191af201266ec027
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, char const *, bool, bool, bool);
127 static void leapadd(zic_t, int, int);
128 static void adjleap(void);
129 static void associate(void);
130 static void dolink(const char *, const char *, bool);
131 static char **getfields(char *buf);
132 static zic_t gethms(const char *string, const char *errstring);
133 static zic_t getsave(char *, bool *);
134 static void inexpires(char **, int);
135 static void infile(const char *filename);
136 static void inleap(char **fields, int nfields);
137 static void inlink(char **fields, int nfields);
138 static void inrule(char **fields, int nfields);
139 static bool inzcont(char **fields, int nfields);
140 static bool inzone(char **fields, int nfields);
141 static bool inzsub(char **, int, bool);
142 static bool itsdir(char const *);
143 static bool itssymlink(char const *);
144 static bool is_alpha(char a);
145 static char lowerit(char);
146 static void mkdirs(char const *, bool);
147 static void newabbr(const char *abbr);
148 static zic_t oadd(zic_t t1, zic_t t2);
149 static void outzone(const struct zone *zp, ptrdiff_t ntzones);
150 static zic_t rpytime(const struct rule *rp, zic_t wantedy);
151 static 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);
155 static zic_t tadd(zic_t t1, zic_t t2);
157 /* Bound on length of what %z can expand to. */
158 enum
160 PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};
162 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
163 TZif files whose POSIX-TZ-style strings contain '<'; see
164 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
165 workaround will no longer be needed when Qt 5.6.1 and earlier are
166 obsolete, say in the year 2021. */
167 #ifndef WORK_AROUND_QTBUG_53071
168 enum
170 WORK_AROUND_QTBUG_53071 = true};
171 #endif
173 static int charcnt;
174 static bool errors;
175 static bool warnings;
176 static const char *filename;
177 static int leapcnt;
178 static bool leapseen;
179 static zic_t leapminyear;
180 static zic_t leapmaxyear;
181 static lineno_t linenum;
182 static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
183 static int max_format_len;
184 static zic_t max_year;
185 static zic_t min_year;
186 static bool noise;
187 static bool print_abbrevs;
188 static zic_t print_cutoff;
189 static const char *rfilename;
190 static lineno_t rlinenum;
191 static const char *progname;
192 static ptrdiff_t timecnt;
193 static ptrdiff_t timecnt_alloc;
194 static int typecnt;
197 * Line codes.
200 #define LC_RULE 0
201 #define LC_ZONE 1
202 #define LC_LINK 2
203 #define LC_LEAP 3
204 #define LC_EXPIRES 4
207 * Which fields are which on a Zone line.
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
222 * Which fields are which on a Zone continuation line.
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
236 * Which files are which on a Rule line.
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
251 * Which fields are which on a Link line.
254 #define LF_TARGET 1
255 #define LF_LINKNAME 2
256 #define LINK_FIELDS 3
259 * Which fields are which on a Leap line.
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
270 /* Expires lines are like Leap lines, except without CORR and ROLL fields. */
271 #define EXPIRES_FIELDS 5
274 * Year synonyms.
277 #define YR_MINIMUM 0
278 #define YR_MAXIMUM 1
279 #define YR_ONLY 2
281 static struct rule *rules;
282 static ptrdiff_t nrules; /* number of rules */
283 static ptrdiff_t nrules_alloc;
285 static struct zone *zones;
286 static ptrdiff_t nzones; /* number of zones */
287 static ptrdiff_t nzones_alloc;
289 struct link
291 const char *l_filename;
292 lineno_t l_linenum;
293 const char *l_target;
294 const char *l_linkname;
297 static struct link *links;
298 static ptrdiff_t nlinks;
299 static ptrdiff_t nlinks_alloc;
301 struct lookup
303 const char *l_word;
304 const int l_value;
307 static struct lookup const *byword(const char *string,
308 const struct lookup *lp);
310 static struct lookup const zi_line_codes[] = {
311 {"Rule", LC_RULE},
312 {"Zone", LC_ZONE},
313 {"Link", LC_LINK},
314 {NULL, 0}
316 static struct lookup const leap_line_codes[] = {
317 {"Leap", LC_LEAP},
318 {"Expires", LC_EXPIRES},
319 {NULL, 0}
322 static struct lookup const mon_names[] = {
323 {"January", TM_JANUARY},
324 {"February", TM_FEBRUARY},
325 {"March", TM_MARCH},
326 {"April", TM_APRIL},
327 {"May", TM_MAY},
328 {"June", TM_JUNE},
329 {"July", TM_JULY},
330 {"August", TM_AUGUST},
331 {"September", TM_SEPTEMBER},
332 {"October", TM_OCTOBER},
333 {"November", TM_NOVEMBER},
334 {"December", TM_DECEMBER},
335 {NULL, 0}
338 static struct lookup const wday_names[] = {
339 {"Sunday", TM_SUNDAY},
340 {"Monday", TM_MONDAY},
341 {"Tuesday", TM_TUESDAY},
342 {"Wednesday", TM_WEDNESDAY},
343 {"Thursday", TM_THURSDAY},
344 {"Friday", TM_FRIDAY},
345 {"Saturday", TM_SATURDAY},
346 {NULL, 0}
349 static struct lookup const lasts[] = {
350 {"last-Sunday", TM_SUNDAY},
351 {"last-Monday", TM_MONDAY},
352 {"last-Tuesday", TM_TUESDAY},
353 {"last-Wednesday", TM_WEDNESDAY},
354 {"last-Thursday", TM_THURSDAY},
355 {"last-Friday", TM_FRIDAY},
356 {"last-Saturday", TM_SATURDAY},
357 {NULL, 0}
360 static struct lookup const begin_years[] = {
361 {"minimum", YR_MINIMUM},
362 {"maximum", YR_MAXIMUM},
363 {NULL, 0}
366 static struct lookup const end_years[] = {
367 {"minimum", YR_MINIMUM},
368 {"maximum", YR_MAXIMUM},
369 {"only", YR_ONLY},
370 {NULL, 0}
373 static struct lookup const leap_types[] = {
374 {"Rolling", true},
375 {"Stationary", false},
376 {NULL, 0}
379 static const int len_months[2][MONSPERYEAR] = {
380 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
381 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
384 static const int len_years[2] = {
385 DAYSPERNYEAR, DAYSPERLYEAR
388 static struct attype
390 zic_t at;
391 bool dontmerge;
392 unsigned char type;
393 } *attypes;
394 static zic_t utoffs[TZ_MAX_TYPES];
395 static char isdsts[TZ_MAX_TYPES];
396 static unsigned char desigidx[TZ_MAX_TYPES];
397 static bool ttisstds[TZ_MAX_TYPES];
398 static bool ttisuts[TZ_MAX_TYPES];
399 static char chars[TZ_MAX_CHARS];
400 static zic_t trans[TZ_MAX_LEAPS];
401 static zic_t corr[TZ_MAX_LEAPS];
402 static char roll[TZ_MAX_LEAPS];
405 * Memory allocation.
408 static void
409 memory_exhausted(const char *msg)
411 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
412 exit(EXIT_FAILURE);
415 static size_t
416 size_product(size_t nitems, size_t itemsize)
418 if (SIZE_MAX / itemsize < nitems)
419 memory_exhausted(_("size overflow"));
420 return nitems * itemsize;
423 static void *
424 memcheck(void *ptr)
426 if (ptr == NULL)
427 memory_exhausted(strerror(errno));
428 return ptr;
431 static void *
432 emalloc(size_t size)
434 return memcheck(malloc(size));
437 static void *
438 erealloc(void *ptr, size_t size)
440 return memcheck(realloc(ptr, size));
443 static char *
444 ecpyalloc(char const *str)
446 return memcheck(strdup(str));
449 static void *
450 growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
452 if (nitems < *nitems_alloc)
453 return ptr;
454 else
456 ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
457 ptrdiff_t amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
459 if ((amax - 1) / 3 * 2 < *nitems_alloc)
460 memory_exhausted(_("integer overflow"));
461 *nitems_alloc += (*nitems_alloc >> 1) + 1;
462 return erealloc(ptr, size_product(*nitems_alloc, itemsize));
467 * Error handling.
470 static void
471 eats(char const *name, lineno_t num, char const *rname, lineno_t rnum)
473 filename = name;
474 linenum = num;
475 rfilename = rname;
476 rlinenum = rnum;
479 static void
480 eat(char const *name, lineno_t num)
482 eats(name, num, NULL, -1);
485 static void
486 verror(const char *string, va_list args)
489 * Match the format of "cc" to allow sh users to zic ... 2>&1 | error -t
490 * "*" -v on BSD systems.
492 if (filename)
493 fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
494 vfprintf(stderr, string, args);
495 if (rfilename != NULL)
496 fprintf(stderr, _(" (rule from \"%s\", line %d)"),
497 rfilename, rlinenum);
498 fprintf(stderr, "\n");
501 static void
502 error(const char *string,...)
504 va_list args;
506 va_start(args, string);
507 verror(string, args);
508 va_end(args);
509 errors = true;
512 static void
513 warning(const char *string,...)
515 va_list args;
517 fprintf(stderr, _("warning: "));
518 va_start(args, string);
519 verror(string, args);
520 va_end(args);
521 warnings = true;
524 static void
525 close_file(FILE *stream, char const *dir, char const *name)
527 char const *e = (ferror(stream) ? _("I/O error")
528 : fclose(stream) != 0 ? strerror(errno) : NULL);
530 if (e)
532 fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
533 dir ? dir : "", dir ? "/" : "",
534 name ? name : "", name ? ": " : "",
536 exit(EXIT_FAILURE);
540 static void
541 usage(FILE *stream, int status)
543 fprintf(stream,
544 _("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -P ] \\\n"
545 "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]"
546 " [ -L leapseconds ] \\\n"
547 "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -t localtime-link ] \\\n"
548 "\t[ filename ... ]\n\n"
549 "Report bugs to %s.\n"),
550 progname, progname, PACKAGE_BUGREPORT);
551 if (status == EXIT_SUCCESS)
552 close_file(stream, NULL, NULL);
553 exit(status);
556 /* Change the working directory to DIR, possibly creating DIR and its
557 ancestors. After this is done, all files are accessed with names
558 relative to DIR. */
559 static void
560 change_directory(char const *dir)
562 if (chdir(dir) != 0)
564 int chdir_errno = errno;
566 if (chdir_errno == ENOENT)
568 mkdirs(dir, false);
569 chdir_errno = chdir(dir) == 0 ? 0 : errno;
571 if (chdir_errno != 0)
573 fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
574 progname, dir, strerror(chdir_errno));
575 exit(EXIT_FAILURE);
580 #define TIME_T_BITS_IN_FILE 64
582 /* The minimum and maximum values representable in a TZif file. */
583 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
584 static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
586 /* The minimum, and one less than the maximum, values specified by
587 the -r option. These default to MIN_TIME and MAX_TIME. */
588 static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
589 static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
591 /* The time specified by an Expires line, or negative if no such line. */
592 static zic_t leapexpires = -1;
594 /* The time specified by an #expires comment, or negative if no such line. */
595 static zic_t comment_leapexpires = -1;
597 /* Set the time range of the output to TIMERANGE.
598 Return true if successful. */
599 static bool
600 timerange_option(char *timerange)
602 int64 lo = min_time,
603 hi = max_time;
604 char *lo_end = timerange,
605 *hi_end;
607 if (*timerange == '@')
609 errno = 0;
610 lo = strtoimax(timerange + 1, &lo_end, 10);
611 if (lo_end == timerange + 1 || (lo == PG_INT64_MAX && errno == ERANGE))
612 return false;
614 hi_end = lo_end;
615 if (lo_end[0] == '/' && lo_end[1] == '@')
617 errno = 0;
618 hi = strtoimax(lo_end + 2, &hi_end, 10);
619 if (hi_end == lo_end + 2 || hi == PG_INT64_MIN)
620 return false;
621 hi -= !(hi == PG_INT64_MAX && errno == ERANGE);
623 if (*hi_end || hi < lo || max_time < lo || hi < min_time)
624 return false;
625 lo_time = lo < min_time ? min_time : lo;
626 hi_time = max_time < hi ? max_time : hi;
627 return true;
630 static const char *psxrules;
631 static const char *lcltime;
632 static const char *directory;
633 static const char *leapsec;
634 static const char *tzdefault;
636 /* -1 if the TZif output file should be slim, 0 if default, 1 if the
637 output should be fat for backward compatibility. ZIC_BLOAT_DEFAULT
638 determines the default. */
639 static int bloat;
641 static bool
642 want_bloat(void)
644 return 0 <= bloat;
647 #ifndef ZIC_BLOAT_DEFAULT
648 #define ZIC_BLOAT_DEFAULT "slim"
649 #endif
652 main(int argc, char **argv)
654 int c,
656 ptrdiff_t i,
658 bool timerange_given = false;
660 #ifndef WIN32
661 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
662 #endif
663 progname = argv[0];
664 if (TYPE_BIT(zic_t) < 64)
666 fprintf(stderr, "%s: %s\n", progname,
667 _("wild compilation-time specification of zic_t"));
668 return EXIT_FAILURE;
670 for (k = 1; k < argc; k++)
671 if (strcmp(argv[k], "--version") == 0)
673 printf("zic %s\n", PG_VERSION);
674 close_file(stdout, NULL, NULL);
675 return EXIT_SUCCESS;
677 else if (strcmp(argv[k], "--help") == 0)
679 usage(stdout, EXIT_SUCCESS);
681 while ((c = getopt(argc, argv, "b:d:l:L:p:Pr:st:vy:")) != EOF && c != -1)
682 switch (c)
684 default:
685 usage(stderr, EXIT_FAILURE);
686 case 'b':
687 if (strcmp(optarg, "slim") == 0)
689 if (0 < bloat)
690 error(_("incompatible -b options"));
691 bloat = -1;
693 else if (strcmp(optarg, "fat") == 0)
695 if (bloat < 0)
696 error(_("incompatible -b options"));
697 bloat = 1;
699 else
700 error(_("invalid option: -b '%s'"), optarg);
701 break;
702 case 'd':
703 if (directory == NULL)
704 directory = strdup(optarg);
705 else
707 fprintf(stderr,
708 _("%s: More than one -d option specified\n"),
709 progname);
710 return EXIT_FAILURE;
712 break;
713 case 'l':
714 if (lcltime == NULL)
715 lcltime = strdup(optarg);
716 else
718 fprintf(stderr,
719 _("%s: More than one -l option specified\n"),
720 progname);
721 return EXIT_FAILURE;
723 break;
724 case 'p':
725 if (psxrules == NULL)
726 psxrules = strdup(optarg);
727 else
729 fprintf(stderr,
730 _("%s: More than one -p option specified\n"),
731 progname);
732 return EXIT_FAILURE;
734 break;
735 case 't':
736 if (tzdefault != NULL)
738 fprintf(stderr,
739 _("%s: More than one -t option"
740 " specified\n"),
741 progname);
742 return EXIT_FAILURE;
744 tzdefault = optarg;
745 break;
746 case 'y':
747 warning(_("-y ignored"));
748 break;
749 case 'L':
750 if (leapsec == NULL)
751 leapsec = strdup(optarg);
752 else
754 fprintf(stderr,
755 _("%s: More than one -L option specified\n"),
756 progname);
757 return EXIT_FAILURE;
759 break;
760 case 'v':
761 noise = true;
762 break;
763 case 'P':
764 print_abbrevs = true;
765 print_cutoff = time(NULL);
766 break;
767 case 'r':
768 if (timerange_given)
770 fprintf(stderr,
771 _("%s: More than one -r option specified\n"),
772 progname);
773 return EXIT_FAILURE;
775 if (!timerange_option(optarg))
777 fprintf(stderr,
778 _("%s: invalid time range: %s\n"),
779 progname, optarg);
780 return EXIT_FAILURE;
782 timerange_given = true;
783 break;
784 case 's':
785 warning(_("-s ignored"));
786 break;
788 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
789 usage(stderr, EXIT_FAILURE); /* usage message by request */
790 if (bloat == 0)
792 static char const bloat_default[] = ZIC_BLOAT_DEFAULT;
794 if (strcmp(bloat_default, "slim") == 0)
795 bloat = -1;
796 else if (strcmp(bloat_default, "fat") == 0)
797 bloat = 1;
798 else
799 abort(); /* Configuration error. */
801 if (directory == NULL)
802 directory = "data";
803 if (tzdefault == NULL)
804 tzdefault = TZDEFAULT;
806 if (optind < argc && leapsec != NULL)
808 infile(leapsec);
809 adjleap();
812 for (k = optind; k < argc; k++)
813 infile(argv[k]);
814 if (errors)
815 return EXIT_FAILURE;
816 associate();
817 change_directory(directory);
818 for (i = 0; i < nzones; i = j)
821 * Find the next non-continuation zone entry.
823 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
824 continue;
825 outzone(&zones[i], j - i);
829 * Make links.
831 for (i = 0; i < nlinks; ++i)
833 eat(links[i].l_filename, links[i].l_linenum);
834 dolink(links[i].l_target, links[i].l_linkname, false);
835 if (noise)
836 for (j = 0; j < nlinks; ++j)
837 if (strcmp(links[i].l_linkname,
838 links[j].l_target) == 0)
839 warning(_("link to link"));
841 if (lcltime != NULL)
843 eat(_("command line"), 1);
844 dolink(lcltime, tzdefault, true);
846 if (psxrules != NULL)
848 eat(_("command line"), 1);
849 dolink(psxrules, TZDEFRULES, true);
851 if (warnings && (ferror(stderr) || fclose(stderr) != 0))
852 return EXIT_FAILURE;
853 return errors ? EXIT_FAILURE : EXIT_SUCCESS;
856 static bool
857 componentcheck(char const *name, char const *component,
858 char const *component_end)
860 enum
862 component_len_max = 14};
863 ptrdiff_t component_len = component_end - component;
865 if (component_len == 0)
867 if (!*name)
868 error(_("empty file name"));
869 else
870 error(_(component == name
871 ? "file name '%s' begins with '/'"
872 : *component_end
873 ? "file name '%s' contains '//'"
874 : "file name '%s' ends with '/'"),
875 name);
876 return false;
878 if (0 < component_len && component_len <= 2
879 && component[0] == '.' && component_end[-1] == '.')
881 int len = component_len;
883 error(_("file name '%s' contains '%.*s' component"),
884 name, len, component);
885 return false;
887 if (noise)
889 if (0 < component_len && component[0] == '-')
890 warning(_("file name '%s' component contains leading '-'"),
891 name);
892 if (component_len_max < component_len)
893 warning(_("file name '%s' contains overlength component"
894 " '%.*s...'"),
895 name, component_len_max, component);
897 return true;
900 static bool
901 namecheck(const char *name)
903 char const *cp;
905 /* Benign characters in a portable file name. */
906 static char const benign[] =
907 "-/_"
908 "abcdefghijklmnopqrstuvwxyz"
909 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
912 * Non-control chars in the POSIX portable character set, excluding the
913 * benign characters.
915 static char const printable_and_not_benign[] =
916 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
918 char const *component = name;
920 for (cp = name; *cp; cp++)
922 unsigned char c = *cp;
924 if (noise && !strchr(benign, c))
926 warning((strchr(printable_and_not_benign, c)
927 ? _("file name '%s' contains byte '%c'")
928 : _("file name '%s' contains byte '\\%o'")),
929 name, c);
931 if (c == '/')
933 if (!componentcheck(name, component, cp))
934 return false;
935 component = cp + 1;
938 return componentcheck(name, component, cp);
942 * Create symlink contents suitable for symlinking FROM to TO, as a
943 * freshly allocated string. FROM should be a relative file name, and
944 * is relative to the global variable DIRECTORY. TO can be either
945 * relative or absolute.
947 #ifdef HAVE_SYMLINK
948 static char *
949 relname(char const *target, char const *linkname)
951 size_t i,
952 taillen,
953 dotdotetcsize;
954 size_t dir_len = 0,
955 dotdots = 0,
956 linksize = SIZE_MAX;
957 char const *f = target;
958 char *result = NULL;
960 if (*linkname == '/')
962 /* Make F absolute too. */
963 size_t len = strlen(directory);
964 bool needslash = len && directory[len - 1] != '/';
966 linksize = len + needslash + strlen(target) + 1;
967 f = result = emalloc(linksize);
968 strcpy(result, directory);
969 result[len] = '/';
970 strcpy(result + len + needslash, target);
972 for (i = 0; f[i] && f[i] == linkname[i]; i++)
973 if (f[i] == '/')
974 dir_len = i + 1;
975 for (; linkname[i]; i++)
976 dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
977 taillen = strlen(f + dir_len);
978 dotdotetcsize = 3 * dotdots + taillen + 1;
979 if (dotdotetcsize <= linksize)
981 if (!result)
982 result = emalloc(dotdotetcsize);
983 for (i = 0; i < dotdots; i++)
984 memcpy(result + 3 * i, "../", 3);
985 memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
987 return result;
989 #endif /* HAVE_SYMLINK */
991 /* Hard link FROM to TO, following any symbolic links.
992 Return 0 if successful, an error number otherwise. */
993 static int
994 hardlinkerr(char const *target, char const *linkname)
996 int r = linkat(AT_FDCWD, target, AT_FDCWD, linkname, AT_SYMLINK_FOLLOW);
998 return r == 0 ? 0 : errno;
1001 static void
1002 dolink(char const *target, char const *linkname, bool staysymlink)
1004 bool remove_only = strcmp(target, "-") == 0;
1005 bool linkdirs_made = false;
1006 int link_errno;
1009 * We get to be careful here since there's a fair chance of root running
1010 * us.
1012 if (!remove_only && itsdir(target))
1014 fprintf(stderr, _("%s: linking target %s/%s failed: %s\n"),
1015 progname, directory, target, strerror(EPERM));
1016 exit(EXIT_FAILURE);
1018 if (staysymlink)
1019 staysymlink = itssymlink(linkname);
1020 if (remove(linkname) == 0)
1021 linkdirs_made = true;
1022 else if (errno != ENOENT)
1024 char const *e = strerror(errno);
1026 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1027 progname, directory, linkname, e);
1028 exit(EXIT_FAILURE);
1030 if (remove_only)
1031 return;
1032 link_errno = staysymlink ? ENOTSUP : hardlinkerr(target, linkname);
1033 if (link_errno == ENOENT && !linkdirs_made)
1035 mkdirs(linkname, true);
1036 linkdirs_made = true;
1037 link_errno = hardlinkerr(target, linkname);
1039 if (link_errno != 0)
1041 #ifdef HAVE_SYMLINK
1042 bool absolute = *target == '/';
1043 char *linkalloc = absolute ? NULL : relname(target, linkname);
1044 char const *contents = absolute ? target : linkalloc;
1045 int symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
1047 if (!linkdirs_made
1048 && (symlink_errno == ENOENT || symlink_errno == ENOTSUP))
1050 mkdirs(linkname, true);
1051 if (symlink_errno == ENOENT)
1052 symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
1054 free(linkalloc);
1055 if (symlink_errno == 0)
1057 if (link_errno != ENOTSUP)
1058 warning(_("symbolic link used because hard link failed: %s"),
1059 strerror(link_errno));
1061 else
1062 #endif /* HAVE_SYMLINK */
1064 FILE *fp,
1065 *tp;
1066 int c;
1068 fp = fopen(target, "rb");
1069 if (!fp)
1071 char const *e = strerror(errno);
1073 fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
1074 progname, directory, target, e);
1075 exit(EXIT_FAILURE);
1077 tp = fopen(linkname, "wb");
1078 if (!tp)
1080 char const *e = strerror(errno);
1082 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1083 progname, directory, linkname, e);
1084 exit(EXIT_FAILURE);
1086 while ((c = getc(fp)) != EOF)
1087 putc(c, tp);
1088 close_file(fp, directory, target);
1089 close_file(tp, directory, linkname);
1090 if (link_errno != ENOTSUP)
1091 warning(_("copy used because hard link failed: %s"),
1092 strerror(link_errno));
1093 #ifdef HAVE_SYMLINK
1094 else if (symlink_errno != ENOTSUP)
1095 warning(_("copy used because symbolic link failed: %s"),
1096 strerror(symlink_errno));
1097 #endif
1102 /* Return true if NAME is a directory. */
1103 static bool
1104 itsdir(char const *name)
1106 struct stat st;
1107 int res = stat(name, &st);
1108 #ifdef S_ISDIR
1109 if (res == 0)
1110 return S_ISDIR(st.st_mode) != 0;
1111 #endif
1112 if (res == 0 || errno == EOVERFLOW)
1114 size_t n = strlen(name);
1115 char *nameslashdot = emalloc(n + 3);
1116 bool dir;
1118 memcpy(nameslashdot, name, n);
1119 strcpy(&nameslashdot[n], &"/."[!(n && name[n - 1] != '/')]);
1120 dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
1121 free(nameslashdot);
1122 return dir;
1124 return false;
1127 /* Return true if NAME is a symbolic link. */
1128 static bool
1129 itssymlink(char const *name)
1131 #ifdef HAVE_SYMLINK
1132 char c;
1134 return 0 <= readlink(name, &c, 1);
1135 #else
1136 return false;
1137 #endif
1141 * Associate sets of rules with zones.
1145 * Sort by rule name.
1148 static int
1149 rcomp(const void *cp1, const void *cp2)
1151 return strcmp(((const struct rule *) cp1)->r_name,
1152 ((const struct rule *) cp2)->r_name);
1155 static void
1156 associate(void)
1158 struct zone *zp;
1159 struct rule *rp;
1160 ptrdiff_t i,
1162 base,
1163 out;
1165 if (nrules != 0)
1167 qsort(rules, nrules, sizeof *rules, rcomp);
1168 for (i = 0; i < nrules - 1; ++i)
1170 if (strcmp(rules[i].r_name,
1171 rules[i + 1].r_name) != 0)
1172 continue;
1173 if (strcmp(rules[i].r_filename,
1174 rules[i + 1].r_filename) == 0)
1175 continue;
1176 eat(rules[i].r_filename, rules[i].r_linenum);
1177 warning(_("same rule name in multiple files"));
1178 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
1179 warning(_("same rule name in multiple files"));
1180 for (j = i + 2; j < nrules; ++j)
1182 if (strcmp(rules[i].r_name,
1183 rules[j].r_name) != 0)
1184 break;
1185 if (strcmp(rules[i].r_filename,
1186 rules[j].r_filename) == 0)
1187 continue;
1188 if (strcmp(rules[i + 1].r_filename,
1189 rules[j].r_filename) == 0)
1190 continue;
1191 break;
1193 i = j - 1;
1196 for (i = 0; i < nzones; ++i)
1198 zp = &zones[i];
1199 zp->z_rules = NULL;
1200 zp->z_nrules = 0;
1202 for (base = 0; base < nrules; base = out)
1204 rp = &rules[base];
1205 for (out = base + 1; out < nrules; ++out)
1206 if (strcmp(rp->r_name, rules[out].r_name) != 0)
1207 break;
1208 for (i = 0; i < nzones; ++i)
1210 zp = &zones[i];
1211 if (strcmp(zp->z_rule, rp->r_name) != 0)
1212 continue;
1213 zp->z_rules = rp;
1214 zp->z_nrules = out - base;
1217 for (i = 0; i < nzones; ++i)
1219 zp = &zones[i];
1220 if (zp->z_nrules == 0)
1223 * Maybe we have a local standard time offset.
1225 eat(zp->z_filename, zp->z_linenum);
1226 zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
1229 * Note, though, that if there's no rule, a '%s' in the format is
1230 * a bad thing.
1232 if (zp->z_format_specifier == 's')
1233 error("%s", _("%s in ruleless zone"));
1236 if (errors)
1237 exit(EXIT_FAILURE);
1240 static void
1241 infile(const char *name)
1243 FILE *fp;
1244 char **fields;
1245 char *cp;
1246 const struct lookup *lp;
1247 int nfields;
1248 bool wantcont;
1249 lineno_t num;
1250 char buf[BUFSIZ];
1252 if (strcmp(name, "-") == 0)
1254 name = _("standard input");
1255 fp = stdin;
1257 else if ((fp = fopen(name, "r")) == NULL)
1259 const char *e = strerror(errno);
1261 fprintf(stderr, _("%s: Cannot open %s: %s\n"),
1262 progname, name, e);
1263 exit(EXIT_FAILURE);
1265 wantcont = false;
1266 for (num = 1;; ++num)
1268 eat(name, num);
1269 if (fgets(buf, sizeof buf, fp) != buf)
1270 break;
1271 cp = strchr(buf, '\n');
1272 if (cp == NULL)
1274 error(_("line too long"));
1275 exit(EXIT_FAILURE);
1277 *cp = '\0';
1278 fields = getfields(buf);
1279 nfields = 0;
1280 while (fields[nfields] != NULL)
1282 static char nada;
1284 if (strcmp(fields[nfields], "-") == 0)
1285 fields[nfields] = &nada;
1286 ++nfields;
1288 if (nfields == 0)
1290 if (name == leapsec && *buf == '#')
1293 * PG: INT64_FORMAT isn't portable for sscanf, so be content
1294 * with scanning a "long". Once we are requiring C99 in all
1295 * live branches, it'd be sensible to adopt upstream's
1296 * practice of using the <inttypes.h> macros. But for now, we
1297 * don't actually use this code, and it won't overflow before
1298 * 2038 anyway.
1300 long cl_tmp;
1302 sscanf(buf, "#expires %ld", &cl_tmp);
1303 comment_leapexpires = cl_tmp;
1306 else if (wantcont)
1308 wantcont = inzcont(fields, nfields);
1310 else
1312 struct lookup const *line_codes
1313 = name == leapsec ? leap_line_codes : zi_line_codes;
1315 lp = byword(fields[0], line_codes);
1316 if (lp == NULL)
1317 error(_("input line of unknown type"));
1318 else
1319 switch (lp->l_value)
1321 case LC_RULE:
1322 inrule(fields, nfields);
1323 wantcont = false;
1324 break;
1325 case LC_ZONE:
1326 wantcont = inzone(fields, nfields);
1327 break;
1328 case LC_LINK:
1329 inlink(fields, nfields);
1330 wantcont = false;
1331 break;
1332 case LC_LEAP:
1333 inleap(fields, nfields);
1334 wantcont = false;
1335 break;
1336 case LC_EXPIRES:
1337 inexpires(fields, nfields);
1338 wantcont = false;
1339 break;
1340 default: /* "cannot happen" */
1341 fprintf(stderr,
1342 _("%s: panic: Invalid l_value %d\n"),
1343 progname, lp->l_value);
1344 exit(EXIT_FAILURE);
1347 free(fields);
1349 close_file(fp, NULL, filename);
1350 if (wantcont)
1351 error(_("expected continuation line not found"));
1355 * Convert a string of one of the forms
1356 * h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1357 * into a number of seconds.
1358 * A null string maps to zero.
1359 * Call error with errstring and return zero on errors.
1362 static zic_t
1363 gethms(char const *string, char const *errstring)
1365 /* PG: make hh be int not zic_t to avoid sscanf portability issues */
1366 int hh;
1367 int sign,
1368 mm = 0,
1369 ss = 0;
1370 char hhx,
1371 mmx,
1372 ssx,
1373 xr = '0',
1375 int tenths = 0;
1376 bool ok = true;
1378 if (string == NULL || *string == '\0')
1379 return 0;
1380 if (*string == '-')
1382 sign = -1;
1383 ++string;
1385 else
1386 sign = 1;
1387 switch (sscanf(string,
1388 "%d%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
1389 &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs))
1391 default:
1392 ok = false;
1393 break;
1394 case 8:
1395 ok = '0' <= xr && xr <= '9';
1396 /* fallthrough */
1397 case 7:
1398 ok &= ssx == '.';
1399 if (ok && noise)
1400 warning(_("fractional seconds rejected by"
1401 " pre-2018 versions of zic"));
1402 /* fallthrough */
1403 case 5:
1404 ok &= mmx == ':';
1405 /* fallthrough */
1406 case 3:
1407 ok &= hhx == ':';
1408 /* fallthrough */
1409 case 1:
1410 break;
1412 if (!ok)
1414 error("%s", errstring);
1415 return 0;
1417 if (hh < 0 ||
1418 mm < 0 || mm >= MINSPERHOUR ||
1419 ss < 0 || ss > SECSPERMIN)
1421 error("%s", errstring);
1422 return 0;
1424 /* Some compilers warn that this test is unsatisfiable for 32-bit ints */
1425 #if INT_MAX > PG_INT32_MAX
1426 if (ZIC_MAX / SECSPERHOUR < hh)
1428 error(_("time overflow"));
1429 return 0;
1431 #endif
1432 ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */
1433 if (noise && (hh > HOURSPERDAY ||
1434 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1435 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1436 return oadd(sign * (zic_t) hh * SECSPERHOUR,
1437 sign * (mm * SECSPERMIN + ss));
1440 static zic_t
1441 getsave(char *field, bool *isdst)
1443 int dst = -1;
1444 zic_t save;
1445 size_t fieldlen = strlen(field);
1447 if (fieldlen != 0)
1449 char *ep = field + fieldlen - 1;
1451 switch (*ep)
1453 case 'd':
1454 dst = 1;
1455 *ep = '\0';
1456 break;
1457 case 's':
1458 dst = 0;
1459 *ep = '\0';
1460 break;
1463 save = gethms(field, _("invalid saved time"));
1464 *isdst = dst < 0 ? save != 0 : dst;
1465 return save;
1468 static void
1469 inrule(char **fields, int nfields)
1471 static struct rule r;
1473 if (nfields != RULE_FIELDS)
1475 error(_("wrong number of fields on Rule line"));
1476 return;
1478 switch (*fields[RF_NAME])
1480 case '\0':
1481 case ' ':
1482 case '\f':
1483 case '\n':
1484 case '\r':
1485 case '\t':
1486 case '\v':
1487 case '+':
1488 case '-':
1489 case '0':
1490 case '1':
1491 case '2':
1492 case '3':
1493 case '4':
1494 case '5':
1495 case '6':
1496 case '7':
1497 case '8':
1498 case '9':
1499 error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
1500 return;
1502 r.r_filename = filename;
1503 r.r_linenum = linenum;
1504 r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
1505 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1506 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1507 r.r_name = ecpyalloc(fields[RF_NAME]);
1508 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1509 if (max_abbrvar_len < strlen(r.r_abbrvar))
1510 max_abbrvar_len = strlen(r.r_abbrvar);
1511 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1512 rules[nrules++] = r;
1515 static bool
1516 inzone(char **fields, int nfields)
1518 ptrdiff_t i;
1520 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS)
1522 error(_("wrong number of fields on Zone line"));
1523 return false;
1525 if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0)
1527 error(
1528 _("\"Zone %s\" line and -l option are mutually exclusive"),
1529 tzdefault);
1530 return false;
1532 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL)
1534 error(
1535 _("\"Zone %s\" line and -p option are mutually exclusive"),
1536 TZDEFRULES);
1537 return false;
1539 for (i = 0; i < nzones; ++i)
1540 if (zones[i].z_name != NULL &&
1541 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0)
1543 error(_("duplicate zone name %s"
1544 " (file \"%s\", line %d)"),
1545 fields[ZF_NAME],
1546 zones[i].z_filename,
1547 zones[i].z_linenum);
1548 return false;
1550 return inzsub(fields, nfields, false);
1553 static bool
1554 inzcont(char **fields, int nfields)
1556 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS)
1558 error(_("wrong number of fields on Zone continuation line"));
1559 return false;
1561 return inzsub(fields, nfields, true);
1564 static bool
1565 inzsub(char **fields, int nfields, bool iscont)
1567 char *cp;
1568 char *cp1;
1569 static struct zone z;
1570 int i_stdoff,
1571 i_rule,
1572 i_format;
1573 int i_untilyear,
1574 i_untilmonth;
1575 int i_untilday,
1576 i_untiltime;
1577 bool hasuntil;
1579 if (iscont)
1581 i_stdoff = ZFC_STDOFF;
1582 i_rule = ZFC_RULE;
1583 i_format = ZFC_FORMAT;
1584 i_untilyear = ZFC_TILYEAR;
1585 i_untilmonth = ZFC_TILMONTH;
1586 i_untilday = ZFC_TILDAY;
1587 i_untiltime = ZFC_TILTIME;
1588 z.z_name = NULL;
1590 else if (!namecheck(fields[ZF_NAME]))
1591 return false;
1592 else
1594 i_stdoff = ZF_STDOFF;
1595 i_rule = ZF_RULE;
1596 i_format = ZF_FORMAT;
1597 i_untilyear = ZF_TILYEAR;
1598 i_untilmonth = ZF_TILMONTH;
1599 i_untilday = ZF_TILDAY;
1600 i_untiltime = ZF_TILTIME;
1601 z.z_name = ecpyalloc(fields[ZF_NAME]);
1603 z.z_filename = filename;
1604 z.z_linenum = linenum;
1605 z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
1606 if ((cp = strchr(fields[i_format], '%')) != NULL)
1608 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1609 || strchr(fields[i_format], '/'))
1611 error(_("invalid abbreviation format"));
1612 return false;
1615 z.z_rule = ecpyalloc(fields[i_rule]);
1616 z.z_format = cp1 = ecpyalloc(fields[i_format]);
1617 z.z_format_specifier = cp ? *cp : '\0';
1618 if (z.z_format_specifier == 'z')
1620 if (noise)
1621 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1622 z.z_format);
1623 cp1[cp - fields[i_format]] = 's';
1625 if (max_format_len < strlen(z.z_format))
1626 max_format_len = strlen(z.z_format);
1627 hasuntil = nfields > i_untilyear;
1628 if (hasuntil)
1630 z.z_untilrule.r_filename = filename;
1631 z.z_untilrule.r_linenum = linenum;
1632 rulesub(&z.z_untilrule,
1633 fields[i_untilyear],
1634 "only",
1636 (nfields > i_untilmonth) ?
1637 fields[i_untilmonth] : "Jan",
1638 (nfields > i_untilday) ? fields[i_untilday] : "1",
1639 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1640 z.z_untiltime = rpytime(&z.z_untilrule,
1641 z.z_untilrule.r_loyear);
1642 if (iscont && nzones > 0 &&
1643 z.z_untiltime > min_time &&
1644 z.z_untiltime < max_time &&
1645 zones[nzones - 1].z_untiltime > min_time &&
1646 zones[nzones - 1].z_untiltime < max_time &&
1647 zones[nzones - 1].z_untiltime >= z.z_untiltime)
1649 error(_("Zone continuation line end time is not after end time of previous line"));
1650 return false;
1653 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1654 zones[nzones++] = z;
1657 * If there was an UNTIL field on this line, there's more information
1658 * about the zone on the next line.
1660 return hasuntil;
1663 static zic_t
1664 getleapdatetime(char **fields, int nfields, bool expire_line)
1666 const char *cp;
1667 const struct lookup *lp;
1668 zic_t i,
1671 /* PG: make year be int not zic_t to avoid sscanf portability issues */
1672 int year;
1673 int month,
1674 day;
1675 zic_t dayoff,
1676 tod;
1677 zic_t t;
1678 char xs;
1680 dayoff = 0;
1681 cp = fields[LP_YEAR];
1682 if (sscanf(cp, "%d%c", &year, &xs) != 1)
1685 * Leapin' Lizards!
1687 error(_("invalid leaping year"));
1688 return -1;
1690 if (!expire_line)
1692 if (!leapseen || leapmaxyear < year)
1693 leapmaxyear = year;
1694 if (!leapseen || leapminyear > year)
1695 leapminyear = year;
1696 leapseen = true;
1698 j = EPOCH_YEAR;
1699 while (j != year)
1701 if (year > j)
1703 i = len_years[isleap(j)];
1704 ++j;
1706 else
1708 --j;
1709 i = -len_years[isleap(j)];
1711 dayoff = oadd(dayoff, i);
1713 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL)
1715 error(_("invalid month name"));
1716 return -1;
1718 month = lp->l_value;
1719 j = TM_JANUARY;
1720 while (j != month)
1722 i = len_months[isleap(year)][j];
1723 dayoff = oadd(dayoff, i);
1724 ++j;
1726 cp = fields[LP_DAY];
1727 if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1728 day <= 0 || day > len_months[isleap(year)][month])
1730 error(_("invalid day of month"));
1731 return -1;
1733 dayoff = oadd(dayoff, day - 1);
1734 if (dayoff < min_time / SECSPERDAY)
1736 error(_("time too small"));
1737 return -1;
1739 if (dayoff > max_time / SECSPERDAY)
1741 error(_("time too large"));
1742 return -1;
1744 t = dayoff * SECSPERDAY;
1745 tod = gethms(fields[LP_TIME], _("invalid time of day"));
1746 t = tadd(t, tod);
1747 if (t < 0)
1748 error(_("leap second precedes Epoch"));
1749 return t;
1752 static void
1753 inleap(char **fields, int nfields)
1755 if (nfields != LEAP_FIELDS)
1756 error(_("wrong number of fields on Leap line"));
1757 else
1759 zic_t t = getleapdatetime(fields, nfields, false);
1761 if (0 <= t)
1763 struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
1765 if (!lp)
1766 error(_("invalid Rolling/Stationary field on Leap line"));
1767 else
1769 int correction = 0;
1771 if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */
1772 correction = -1;
1773 else if (strcmp(fields[LP_CORR], "+") == 0)
1774 correction = 1;
1775 else
1776 error(_("invalid CORRECTION field on Leap line"));
1777 if (correction)
1778 leapadd(t, correction, lp->l_value);
1784 static void
1785 inexpires(char **fields, int nfields)
1787 if (nfields != EXPIRES_FIELDS)
1788 error(_("wrong number of fields on Expires line"));
1789 else if (0 <= leapexpires)
1790 error(_("multiple Expires lines"));
1791 else
1792 leapexpires = getleapdatetime(fields, nfields, true);
1795 static void
1796 inlink(char **fields, int nfields)
1798 struct link l;
1800 if (nfields != LINK_FIELDS)
1802 error(_("wrong number of fields on Link line"));
1803 return;
1805 if (*fields[LF_TARGET] == '\0')
1807 error(_("blank TARGET field on Link line"));
1808 return;
1810 if (!namecheck(fields[LF_LINKNAME]))
1811 return;
1812 l.l_filename = filename;
1813 l.l_linenum = linenum;
1814 l.l_target = ecpyalloc(fields[LF_TARGET]);
1815 l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
1816 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1817 links[nlinks++] = l;
1820 static void
1821 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1822 const char *typep, const char *monthp, const char *dayp,
1823 const char *timep)
1825 const struct lookup *lp;
1826 const char *cp;
1827 char *dp;
1828 char *ep;
1829 char xs;
1831 /* PG: year_tmp is to avoid sscanf portability issues */
1832 int year_tmp;
1834 if ((lp = byword(monthp, mon_names)) == NULL)
1836 error(_("invalid month name"));
1837 return;
1839 rp->r_month = lp->l_value;
1840 rp->r_todisstd = false;
1841 rp->r_todisut = false;
1842 dp = ecpyalloc(timep);
1843 if (*dp != '\0')
1845 ep = dp + strlen(dp) - 1;
1846 switch (lowerit(*ep))
1848 case 's': /* Standard */
1849 rp->r_todisstd = true;
1850 rp->r_todisut = false;
1851 *ep = '\0';
1852 break;
1853 case 'w': /* Wall */
1854 rp->r_todisstd = false;
1855 rp->r_todisut = false;
1856 *ep = '\0';
1857 break;
1858 case 'g': /* Greenwich */
1859 case 'u': /* Universal */
1860 case 'z': /* Zulu */
1861 rp->r_todisstd = true;
1862 rp->r_todisut = true;
1863 *ep = '\0';
1864 break;
1867 rp->r_tod = gethms(dp, _("invalid time of day"));
1868 free(dp);
1871 * Year work.
1873 cp = loyearp;
1874 lp = byword(cp, begin_years);
1875 rp->r_lowasnum = lp == NULL;
1876 if (!rp->r_lowasnum)
1877 switch (lp->l_value)
1879 case YR_MINIMUM:
1880 rp->r_loyear = ZIC_MIN;
1881 break;
1882 case YR_MAXIMUM:
1883 rp->r_loyear = ZIC_MAX;
1884 break;
1885 default: /* "cannot happen" */
1886 fprintf(stderr,
1887 _("%s: panic: Invalid l_value %d\n"),
1888 progname, lp->l_value);
1889 exit(EXIT_FAILURE);
1891 else if (sscanf(cp, "%d%c", &year_tmp, &xs) == 1)
1892 rp->r_loyear = year_tmp;
1893 else
1895 error(_("invalid starting year"));
1896 return;
1898 cp = hiyearp;
1899 lp = byword(cp, end_years);
1900 rp->r_hiwasnum = lp == NULL;
1901 if (!rp->r_hiwasnum)
1902 switch (lp->l_value)
1904 case YR_MINIMUM:
1905 rp->r_hiyear = ZIC_MIN;
1906 break;
1907 case YR_MAXIMUM:
1908 rp->r_hiyear = ZIC_MAX;
1909 break;
1910 case YR_ONLY:
1911 rp->r_hiyear = rp->r_loyear;
1912 break;
1913 default: /* "cannot happen" */
1914 fprintf(stderr,
1915 _("%s: panic: Invalid l_value %d\n"),
1916 progname, lp->l_value);
1917 exit(EXIT_FAILURE);
1919 else if (sscanf(cp, "%d%c", &year_tmp, &xs) == 1)
1920 rp->r_hiyear = year_tmp;
1921 else
1923 error(_("invalid ending year"));
1924 return;
1926 if (rp->r_loyear > rp->r_hiyear)
1928 error(_("starting year greater than ending year"));
1929 return;
1931 if (*typep != '\0')
1933 error(_("year type \"%s\" is unsupported; use \"-\" instead"),
1934 typep);
1935 return;
1939 * Day work. Accept things such as: 1 lastSunday last-Sunday
1940 * (undocumented; warn about this) Sun<=20 Sun>=7
1942 dp = ecpyalloc(dayp);
1943 if ((lp = byword(dp, lasts)) != NULL)
1945 rp->r_dycode = DC_DOWLEQ;
1946 rp->r_wday = lp->l_value;
1947 rp->r_dayofmonth = len_months[1][rp->r_month];
1949 else
1951 if ((ep = strchr(dp, '<')) != NULL)
1952 rp->r_dycode = DC_DOWLEQ;
1953 else if ((ep = strchr(dp, '>')) != NULL)
1954 rp->r_dycode = DC_DOWGEQ;
1955 else
1957 ep = dp;
1958 rp->r_dycode = DC_DOM;
1960 if (rp->r_dycode != DC_DOM)
1962 *ep++ = 0;
1963 if (*ep++ != '=')
1965 error(_("invalid day of month"));
1966 free(dp);
1967 return;
1969 if ((lp = byword(dp, wday_names)) == NULL)
1971 error(_("invalid weekday name"));
1972 free(dp);
1973 return;
1975 rp->r_wday = lp->l_value;
1977 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1978 rp->r_dayofmonth <= 0 ||
1979 (rp->r_dayofmonth > len_months[1][rp->r_month]))
1981 error(_("invalid day of month"));
1982 free(dp);
1983 return;
1986 free(dp);
1989 static void
1990 convert(const int32 val, char *const buf)
1992 int i;
1993 int shift;
1994 unsigned char *const b = (unsigned char *) buf;
1996 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1997 b[i] = val >> shift;
2000 static void
2001 convert64(const zic_t val, char *const buf)
2003 int i;
2004 int shift;
2005 unsigned char *const b = (unsigned char *) buf;
2007 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
2008 b[i] = val >> shift;
2011 static void
2012 puttzcode(const int32 val, FILE *const fp)
2014 char buf[4];
2016 convert(val, buf);
2017 fwrite(buf, sizeof buf, 1, fp);
2020 static void
2021 puttzcodepass(zic_t val, FILE *fp, int pass)
2023 if (pass == 1)
2024 puttzcode(val, fp);
2025 else
2027 char buf[8];
2029 convert64(val, buf);
2030 fwrite(buf, sizeof buf, 1, fp);
2034 static int
2035 atcomp(const void *avp, const void *bvp)
2037 const zic_t a = ((const struct attype *) avp)->at;
2038 const zic_t b = ((const struct attype *) bvp)->at;
2040 return (a < b) ? -1 : (a > b);
2043 struct timerange
2045 int defaulttype;
2046 ptrdiff_t base,
2047 count;
2048 int leapbase,
2049 leapcount;
2052 static struct timerange
2053 limitrange(struct timerange r, zic_t lo, zic_t hi,
2054 zic_t const *ats, unsigned char const *types)
2056 while (0 < r.count && ats[r.base] < lo)
2058 r.defaulttype = types[r.base];
2059 r.count--;
2060 r.base++;
2062 while (0 < r.leapcount && trans[r.leapbase] < lo)
2064 r.leapcount--;
2065 r.leapbase++;
2068 if (hi < ZIC_MAX)
2070 while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
2071 r.count--;
2072 while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
2073 r.leapcount--;
2076 return r;
2079 static void
2080 writezone(const char *const name, const char *const string, char version,
2081 int defaulttype)
2083 FILE *fp;
2084 ptrdiff_t i,
2086 int pass;
2087 static const struct tzhead tzh0;
2088 static struct tzhead tzh;
2089 bool dir_checked = false;
2090 zic_t one = 1;
2091 zic_t y2038_boundary = one << 31;
2092 ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
2095 * Allocate the ATS and TYPES arrays via a single malloc, as this is a bit
2096 * faster.
2098 zic_t *ats = emalloc(MAXALIGN(size_product(nats, sizeof *ats + 1)));
2099 void *typesptr = ats + nats;
2100 unsigned char *types = typesptr;
2101 struct timerange rangeall,
2102 range32,
2103 range64;
2106 * Sort.
2108 if (timecnt > 1)
2109 qsort(attypes, timecnt, sizeof *attypes, atcomp);
2112 * Optimize.
2115 ptrdiff_t fromi,
2116 toi;
2118 toi = 0;
2119 fromi = 0;
2120 for (; fromi < timecnt; ++fromi)
2122 if (toi != 0
2123 && ((attypes[fromi].at
2124 + utoffs[attypes[toi - 1].type])
2125 <= (attypes[toi - 1].at
2126 + utoffs[toi == 1 ? 0
2127 : attypes[toi - 2].type])))
2129 attypes[toi - 1].type =
2130 attypes[fromi].type;
2131 continue;
2133 if (toi == 0
2134 || attypes[fromi].dontmerge
2135 || (utoffs[attypes[toi - 1].type]
2136 != utoffs[attypes[fromi].type])
2137 || (isdsts[attypes[toi - 1].type]
2138 != isdsts[attypes[fromi].type])
2139 || (desigidx[attypes[toi - 1].type]
2140 != desigidx[attypes[fromi].type]))
2141 attypes[toi++] = attypes[fromi];
2143 timecnt = toi;
2146 if (noise && timecnt > 1200)
2148 if (timecnt > TZ_MAX_TIMES)
2149 warning(_("reference clients mishandle"
2150 " more than %d transition times"),
2151 TZ_MAX_TIMES);
2152 else
2153 warning(_("pre-2014 clients may mishandle"
2154 " more than 1200 transition times"));
2158 * Transfer.
2160 for (i = 0; i < timecnt; ++i)
2162 ats[i] = attypes[i].at;
2163 types[i] = attypes[i].type;
2167 * Correct for leap seconds.
2169 for (i = 0; i < timecnt; ++i)
2171 j = leapcnt;
2172 while (--j >= 0)
2173 if (ats[i] > trans[j] - corr[j])
2175 ats[i] = tadd(ats[i], corr[j]);
2176 break;
2181 * Work around QTBUG-53071 for timestamps less than y2038_boundary - 1, by
2182 * inserting a no-op transition at time y2038_boundary - 1. This works
2183 * only for timestamps before the boundary, which should be good enough in
2184 * practice as QTBUG-53071 should be long-dead by 2038. Do this after
2185 * correcting for leap seconds, as the idea is to insert a transition just
2186 * before 32-bit pg_time_t rolls around, and this occurs at a slightly
2187 * different moment if transitions are leap-second corrected.
2189 if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat()
2190 && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<'))
2192 ats[timecnt] = y2038_boundary - 1;
2193 types[timecnt] = types[timecnt - 1];
2194 timecnt++;
2197 rangeall.defaulttype = defaulttype;
2198 rangeall.base = rangeall.leapbase = 0;
2199 rangeall.count = timecnt;
2200 rangeall.leapcount = leapcnt;
2201 range64 = limitrange(rangeall, lo_time, hi_time, ats, types);
2202 range32 = limitrange(range64, PG_INT32_MIN, PG_INT32_MAX, ats, types);
2205 * Remove old file, if any, to snap links.
2207 if (remove(name) == 0)
2208 dir_checked = true;
2209 else if (errno != ENOENT)
2211 const char *e = strerror(errno);
2213 fprintf(stderr, _("%s: Cannot remove %s/%s: %s\n"),
2214 progname, directory, name, e);
2215 exit(EXIT_FAILURE);
2217 fp = fopen(name, "wb");
2218 if (!fp)
2220 int fopen_errno = errno;
2222 if (fopen_errno == ENOENT && !dir_checked)
2224 mkdirs(name, true);
2225 fp = fopen(name, "wb");
2226 fopen_errno = errno;
2228 if (!fp)
2230 fprintf(stderr, _("%s: Cannot create %s/%s: %s\n"),
2231 progname, directory, name, strerror(fopen_errno));
2232 exit(EXIT_FAILURE);
2235 for (pass = 1; pass <= 2; ++pass)
2237 ptrdiff_t thistimei,
2238 thistimecnt,
2239 thistimelim;
2240 int thisleapi,
2241 thisleapcnt,
2242 thisleaplim;
2243 int currenttype,
2244 thisdefaulttype;
2245 bool locut,
2246 hicut;
2247 zic_t lo;
2248 int old0;
2249 char omittype[TZ_MAX_TYPES];
2250 int typemap[TZ_MAX_TYPES];
2251 int thistypecnt,
2252 stdcnt,
2253 utcnt;
2254 char thischars[TZ_MAX_CHARS];
2255 int thischarcnt;
2256 bool toomanytimes;
2257 int indmap[TZ_MAX_CHARS];
2259 if (pass == 1)
2262 * Arguably the default time type in the 32-bit data should be
2263 * range32.defaulttype, which is suited for timestamps just before
2264 * PG_INT32_MIN. However, zic traditionally used the time type of
2265 * the indefinite past instead. Internet RFC 8532 says readers
2266 * should ignore 32-bit data, so this discrepancy matters only to
2267 * obsolete readers where the traditional type might be more
2268 * appropriate even if it's "wrong". So, use the historical zic
2269 * value, unless -r specifies a low cutoff that excludes some
2270 * 32-bit timestamps.
2272 thisdefaulttype = (lo_time <= PG_INT32_MIN
2273 ? range64.defaulttype
2274 : range32.defaulttype);
2276 thistimei = range32.base;
2277 thistimecnt = range32.count;
2278 toomanytimes = thistimecnt >> 31 >> 1 != 0;
2279 thisleapi = range32.leapbase;
2280 thisleapcnt = range32.leapcount;
2281 locut = PG_INT32_MIN < lo_time;
2282 hicut = hi_time < PG_INT32_MAX;
2284 else
2286 thisdefaulttype = range64.defaulttype;
2287 thistimei = range64.base;
2288 thistimecnt = range64.count;
2289 toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
2290 thisleapi = range64.leapbase;
2291 thisleapcnt = range64.leapcount;
2292 locut = min_time < lo_time;
2293 hicut = hi_time < max_time;
2295 if (toomanytimes)
2296 error(_("too many transition times"));
2299 * Keep the last too-low transition if no transition is exactly at LO.
2300 * The kept transition will be output as a LO "transition"; see
2301 * "Output a LO_TIME transition" below. This is needed when the
2302 * output is truncated at the start, and is also useful when catering
2303 * to buggy 32-bit clients that do not use time type 0 for timestamps
2304 * before the first transition.
2306 if (0 < thistimei && ats[thistimei] != lo_time)
2308 thistimei--;
2309 thistimecnt++;
2310 locut = false;
2313 thistimelim = thistimei + thistimecnt;
2314 thisleaplim = thisleapi + thisleapcnt;
2315 if (thistimecnt != 0)
2317 if (ats[thistimei] == lo_time)
2318 locut = false;
2319 if (hi_time < ZIC_MAX && ats[thistimelim - 1] == hi_time + 1)
2320 hicut = false;
2322 memset(omittype, true, typecnt);
2323 omittype[thisdefaulttype] = false;
2324 for (i = thistimei; i < thistimelim; i++)
2325 omittype[types[i]] = false;
2328 * Reorder types to make THISDEFAULTTYPE type 0. Use TYPEMAP to swap
2329 * OLD0 and THISDEFAULTTYPE so that THISDEFAULTTYPE appears as type 0
2330 * in the output instead of OLD0. TYPEMAP also omits unused types.
2332 old0 = strlen(omittype);
2334 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
2337 * For some pre-2011 systems: if the last-to-be-written standard (or
2338 * daylight) type has an offset different from the most recently used
2339 * offset, append an (unused) copy of the most recently used type (to
2340 * help get global "altzone" and "timezone" variables set correctly).
2342 if (want_bloat())
2344 int mrudst,
2345 mrustd,
2346 hidst,
2347 histd,
2348 type;
2350 hidst = histd = mrudst = mrustd = -1;
2351 for (i = thistimei; i < thistimelim; ++i)
2352 if (isdsts[types[i]])
2353 mrudst = types[i];
2354 else
2355 mrustd = types[i];
2356 for (i = old0; i < typecnt; i++)
2358 int h = (i == old0 ? thisdefaulttype
2359 : i == thisdefaulttype ? old0 : i);
2361 if (!omittype[h])
2363 if (isdsts[h])
2364 hidst = i;
2365 else
2366 histd = i;
2369 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
2370 utoffs[hidst] != utoffs[mrudst])
2372 isdsts[mrudst] = -1;
2373 type = addtype(utoffs[mrudst],
2374 &chars[desigidx[mrudst]],
2375 true,
2376 ttisstds[mrudst],
2377 ttisuts[mrudst]);
2378 isdsts[mrudst] = 1;
2379 omittype[type] = false;
2381 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
2382 utoffs[histd] != utoffs[mrustd])
2384 isdsts[mrustd] = -1;
2385 type = addtype(utoffs[mrustd],
2386 &chars[desigidx[mrustd]],
2387 false,
2388 ttisstds[mrustd],
2389 ttisuts[mrustd]);
2390 isdsts[mrustd] = 0;
2391 omittype[type] = false;
2394 #endif /* !defined
2395 * LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
2396 thistypecnt = 0;
2397 for (i = old0; i < typecnt; i++)
2398 if (!omittype[i])
2399 typemap[i == old0 ? thisdefaulttype
2400 : i == thisdefaulttype ? old0 : i]
2401 = thistypecnt++;
2403 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
2404 indmap[i] = -1;
2405 thischarcnt = stdcnt = utcnt = 0;
2406 for (i = old0; i < typecnt; i++)
2408 char *thisabbr;
2410 if (omittype[i])
2411 continue;
2412 if (ttisstds[i])
2413 stdcnt = thistypecnt;
2414 if (ttisuts[i])
2415 utcnt = thistypecnt;
2416 if (indmap[desigidx[i]] >= 0)
2417 continue;
2418 thisabbr = &chars[desigidx[i]];
2419 for (j = 0; j < thischarcnt; ++j)
2420 if (strcmp(&thischars[j], thisabbr) == 0)
2421 break;
2422 if (j == thischarcnt)
2424 strcpy(&thischars[thischarcnt], thisabbr);
2425 thischarcnt += strlen(thisabbr) + 1;
2427 indmap[desigidx[i]] = j;
2429 if (pass == 1 && !want_bloat())
2431 utcnt = stdcnt = thisleapcnt = 0;
2432 thistimecnt = -(locut + hicut);
2433 thistypecnt = thischarcnt = 1;
2434 thistimelim = thistimei;
2436 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
2437 tzh = tzh0;
2438 memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
2439 tzh.tzh_version[0] = version;
2440 convert(utcnt, tzh.tzh_ttisutcnt);
2441 convert(stdcnt, tzh.tzh_ttisstdcnt);
2442 convert(thisleapcnt, tzh.tzh_leapcnt);
2443 convert(locut + thistimecnt + hicut, tzh.tzh_timecnt);
2444 convert(thistypecnt, tzh.tzh_typecnt);
2445 convert(thischarcnt, tzh.tzh_charcnt);
2446 DO(tzh_magic);
2447 DO(tzh_version);
2448 DO(tzh_reserved);
2449 DO(tzh_ttisutcnt);
2450 DO(tzh_ttisstdcnt);
2451 DO(tzh_leapcnt);
2452 DO(tzh_timecnt);
2453 DO(tzh_typecnt);
2454 DO(tzh_charcnt);
2455 #undef DO
2456 if (pass == 1 && !want_bloat())
2458 /* Output a minimal data block with just one time type. */
2459 puttzcode(0, fp); /* utoff */
2460 putc(0, fp); /* dst */
2461 putc(0, fp); /* index of abbreviation */
2462 putc(0, fp); /* empty-string abbreviation */
2463 continue;
2466 /* PG: print current timezone abbreviations if requested */
2467 if (print_abbrevs && pass == 2)
2469 /* Print "type" data for periods ending after print_cutoff */
2470 for (i = thistimei; i < thistimelim; ++i)
2472 if (i == thistimelim - 1 || ats[i + 1] > print_cutoff)
2474 unsigned char tm = types[i];
2475 char *thisabbrev = &thischars[indmap[desigidx[tm]]];
2477 fprintf(stdout, "%s\t" INT64_FORMAT "%s\n",
2478 thisabbrev,
2479 utoffs[tm],
2480 isdsts[tm] ? "\tD" : "");
2483 /* Print the default type if we have no transitions at all */
2484 if (thistimei >= thistimelim)
2486 unsigned char tm = defaulttype;
2487 char *thisabbrev = &thischars[indmap[desigidx[tm]]];
2489 fprintf(stdout, "%s\t" INT64_FORMAT "%s\n",
2490 thisabbrev,
2491 utoffs[tm],
2492 isdsts[tm] ? "\tD" : "");
2497 * Output a LO_TIME transition if needed; see limitrange. But do not
2498 * go below the minimum representable value for this pass.
2500 lo = pass == 1 && lo_time < PG_INT32_MIN ? PG_INT32_MIN : lo_time;
2502 if (locut)
2503 puttzcodepass(lo, fp, pass);
2504 for (i = thistimei; i < thistimelim; ++i)
2506 zic_t at = ats[i] < lo ? lo : ats[i];
2508 puttzcodepass(at, fp, pass);
2510 if (hicut)
2511 puttzcodepass(hi_time + 1, fp, pass);
2512 currenttype = 0;
2513 if (locut)
2514 putc(currenttype, fp);
2515 for (i = thistimei; i < thistimelim; ++i)
2517 currenttype = typemap[types[i]];
2518 putc(currenttype, fp);
2520 if (hicut)
2521 putc(currenttype, fp);
2523 for (i = old0; i < typecnt; i++)
2525 int h = (i == old0 ? thisdefaulttype
2526 : i == thisdefaulttype ? old0 : i);
2528 if (!omittype[h])
2530 puttzcode(utoffs[h], fp);
2531 putc(isdsts[h], fp);
2532 putc(indmap[desigidx[h]], fp);
2535 if (thischarcnt != 0)
2536 fwrite(thischars, sizeof thischars[0],
2537 thischarcnt, fp);
2538 for (i = thisleapi; i < thisleaplim; ++i)
2540 zic_t todo;
2542 if (roll[i])
2544 if (timecnt == 0 || trans[i] < ats[0])
2546 j = 0;
2547 while (isdsts[j])
2548 if (++j >= typecnt)
2550 j = 0;
2551 break;
2554 else
2556 j = 1;
2557 while (j < timecnt &&
2558 trans[i] >= ats[j])
2559 ++j;
2560 j = types[j - 1];
2562 todo = tadd(trans[i], -utoffs[j]);
2564 else
2565 todo = trans[i];
2566 puttzcodepass(todo, fp, pass);
2567 puttzcode(corr[i], fp);
2569 if (stdcnt != 0)
2570 for (i = old0; i < typecnt; i++)
2571 if (!omittype[i])
2572 putc(ttisstds[i], fp);
2573 if (utcnt != 0)
2574 for (i = old0; i < typecnt; i++)
2575 if (!omittype[i])
2576 putc(ttisuts[i], fp);
2578 fprintf(fp, "\n%s\n", string);
2579 close_file(fp, directory, name);
2580 free(ats);
2583 static char const *
2584 abbroffset(char *buf, zic_t offset)
2586 char sign = '+';
2587 int seconds,
2588 minutes;
2590 if (offset < 0)
2592 offset = -offset;
2593 sign = '-';
2596 seconds = offset % SECSPERMIN;
2597 offset /= SECSPERMIN;
2598 minutes = offset % MINSPERHOUR;
2599 offset /= MINSPERHOUR;
2600 if (100 <= offset)
2602 error(_("%%z UT offset magnitude exceeds 99:59:59"));
2603 return "%z";
2605 else
2607 char *p = buf;
2609 *p++ = sign;
2610 *p++ = '0' + offset / 10;
2611 *p++ = '0' + offset % 10;
2612 if (minutes | seconds)
2614 *p++ = '0' + minutes / 10;
2615 *p++ = '0' + minutes % 10;
2616 if (seconds)
2618 *p++ = '0' + seconds / 10;
2619 *p++ = '0' + seconds % 10;
2622 *p = '\0';
2623 return buf;
2627 static size_t
2628 doabbr(char *abbr, struct zone const *zp, char const *letters,
2629 bool isdst, zic_t save, bool doquotes)
2631 char *cp;
2632 char *slashp;
2633 size_t len;
2634 char const *format = zp->z_format;
2636 slashp = strchr(format, '/');
2637 if (slashp == NULL)
2639 char letterbuf[PERCENT_Z_LEN_BOUND + 1];
2641 if (zp->z_format_specifier == 'z')
2642 letters = abbroffset(letterbuf, zp->z_stdoff + save);
2643 else if (!letters)
2644 letters = "%s";
2645 sprintf(abbr, format, letters);
2647 else if (isdst)
2649 strcpy(abbr, slashp + 1);
2651 else
2653 memcpy(abbr, format, slashp - format);
2654 abbr[slashp - format] = '\0';
2656 len = strlen(abbr);
2657 if (!doquotes)
2658 return len;
2659 for (cp = abbr; is_alpha(*cp); cp++)
2660 continue;
2661 if (len > 0 && *cp == '\0')
2662 return len;
2663 abbr[len + 2] = '\0';
2664 abbr[len + 1] = '>';
2665 memmove(abbr + 1, abbr, len);
2666 abbr[0] = '<';
2667 return len + 2;
2670 static void
2671 updateminmax(const zic_t x)
2673 if (min_year > x)
2674 min_year = x;
2675 if (max_year < x)
2676 max_year = x;
2679 static int
2680 stringoffset(char *result, zic_t offset)
2682 int hours;
2683 int minutes;
2684 int seconds;
2685 bool negative = offset < 0;
2686 int len = negative;
2688 if (negative)
2690 offset = -offset;
2691 result[0] = '-';
2693 seconds = offset % SECSPERMIN;
2694 offset /= SECSPERMIN;
2695 minutes = offset % MINSPERHOUR;
2696 offset /= MINSPERHOUR;
2697 hours = offset;
2698 if (hours >= HOURSPERDAY * DAYSPERWEEK)
2700 result[0] = '\0';
2701 return 0;
2703 len += sprintf(result + len, "%d", hours);
2704 if (minutes != 0 || seconds != 0)
2706 len += sprintf(result + len, ":%02d", minutes);
2707 if (seconds != 0)
2708 len += sprintf(result + len, ":%02d", seconds);
2710 return len;
2713 static int
2714 stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff)
2716 zic_t tod = rp->r_tod;
2717 int compat = 0;
2719 if (rp->r_dycode == DC_DOM)
2721 int month,
2722 total;
2724 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2725 return -1;
2726 total = 0;
2727 for (month = 0; month < rp->r_month; ++month)
2728 total += len_months[0][month];
2729 /* Omit the "J" in Jan and Feb, as that's shorter. */
2730 if (rp->r_month <= 1)
2731 result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
2732 else
2733 result += sprintf(result, "J%d", total + rp->r_dayofmonth);
2735 else
2737 int week;
2738 int wday = rp->r_wday;
2739 int wdayoff;
2741 if (rp->r_dycode == DC_DOWGEQ)
2743 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2744 if (wdayoff)
2745 compat = 2013;
2746 wday -= wdayoff;
2747 tod += wdayoff * SECSPERDAY;
2748 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2750 else if (rp->r_dycode == DC_DOWLEQ)
2752 if (rp->r_dayofmonth == len_months[1][rp->r_month])
2753 week = 5;
2754 else
2756 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2757 if (wdayoff)
2758 compat = 2013;
2759 wday -= wdayoff;
2760 tod += wdayoff * SECSPERDAY;
2761 week = rp->r_dayofmonth / DAYSPERWEEK;
2764 else
2765 return -1; /* "cannot happen" */
2766 if (wday < 0)
2767 wday += DAYSPERWEEK;
2768 result += sprintf(result, "M%d.%d.%d",
2769 rp->r_month + 1, week, wday);
2771 if (rp->r_todisut)
2772 tod += stdoff;
2773 if (rp->r_todisstd && !rp->r_isdst)
2774 tod += save;
2775 if (tod != 2 * SECSPERMIN * MINSPERHOUR)
2777 *result++ = '/';
2778 if (!stringoffset(result, tod))
2779 return -1;
2780 if (tod < 0)
2782 if (compat < 2013)
2783 compat = 2013;
2785 else if (SECSPERDAY <= tod)
2787 if (compat < 1994)
2788 compat = 1994;
2791 return compat;
2794 static int
2795 rule_cmp(struct rule const *a, struct rule const *b)
2797 if (!a)
2798 return -!!b;
2799 if (!b)
2800 return 1;
2801 if (a->r_hiyear != b->r_hiyear)
2802 return a->r_hiyear < b->r_hiyear ? -1 : 1;
2803 if (a->r_month - b->r_month != 0)
2804 return a->r_month - b->r_month;
2805 return a->r_dayofmonth - b->r_dayofmonth;
2808 static int
2809 stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
2811 const struct zone *zp;
2812 struct rule *rp;
2813 struct rule *stdrp;
2814 struct rule *dstrp;
2815 ptrdiff_t i;
2816 const char *abbrvar;
2817 int compat = 0;
2818 int c;
2819 size_t len;
2820 int offsetlen;
2821 struct rule stdr,
2822 dstr;
2824 result[0] = '\0';
2827 * Internet RFC 8536 section 5.1 says to use an empty TZ string if future
2828 * timestamps are truncated.
2830 if (hi_time < max_time)
2831 return -1;
2833 zp = zpfirst + zonecount - 1;
2834 stdrp = dstrp = NULL;
2835 for (i = 0; i < zp->z_nrules; ++i)
2837 rp = &zp->z_rules[i];
2838 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
2839 continue;
2840 if (!rp->r_isdst)
2842 if (stdrp == NULL)
2843 stdrp = rp;
2844 else
2845 return -1;
2847 else
2849 if (dstrp == NULL)
2850 dstrp = rp;
2851 else
2852 return -1;
2855 if (stdrp == NULL && dstrp == NULL)
2858 * There are no rules running through "max". Find the latest std rule
2859 * in stdabbrrp and latest rule of any type in stdrp.
2861 struct rule *stdabbrrp = NULL;
2863 for (i = 0; i < zp->z_nrules; ++i)
2865 rp = &zp->z_rules[i];
2866 if (!rp->r_isdst && rule_cmp(stdabbrrp, rp) < 0)
2867 stdabbrrp = rp;
2868 if (rule_cmp(stdrp, rp) < 0)
2869 stdrp = rp;
2871 if (stdrp != NULL && stdrp->r_isdst)
2873 /* Perpetual DST. */
2874 dstr.r_month = TM_JANUARY;
2875 dstr.r_dycode = DC_DOM;
2876 dstr.r_dayofmonth = 1;
2877 dstr.r_tod = 0;
2878 dstr.r_todisstd = dstr.r_todisut = false;
2879 dstr.r_isdst = stdrp->r_isdst;
2880 dstr.r_save = stdrp->r_save;
2881 dstr.r_abbrvar = stdrp->r_abbrvar;
2882 stdr.r_month = TM_DECEMBER;
2883 stdr.r_dycode = DC_DOM;
2884 stdr.r_dayofmonth = 31;
2885 stdr.r_tod = SECSPERDAY + stdrp->r_save;
2886 stdr.r_todisstd = stdr.r_todisut = false;
2887 stdr.r_isdst = false;
2888 stdr.r_save = 0;
2889 stdr.r_abbrvar
2890 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2891 dstrp = &dstr;
2892 stdrp = &stdr;
2895 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_isdst))
2896 return -1;
2897 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2898 len = doabbr(result, zp, abbrvar, false, 0, true);
2899 offsetlen = stringoffset(result + len, -zp->z_stdoff);
2900 if (!offsetlen)
2902 result[0] = '\0';
2903 return -1;
2905 len += offsetlen;
2906 if (dstrp == NULL)
2907 return compat;
2908 len += doabbr(result + len, zp, dstrp->r_abbrvar,
2909 dstrp->r_isdst, dstrp->r_save, true);
2910 if (dstrp->r_save != SECSPERMIN * MINSPERHOUR)
2912 offsetlen = stringoffset(result + len,
2913 -(zp->z_stdoff + dstrp->r_save));
2914 if (!offsetlen)
2916 result[0] = '\0';
2917 return -1;
2919 len += offsetlen;
2921 result[len++] = ',';
2922 c = stringrule(result + len, dstrp, dstrp->r_save, zp->z_stdoff);
2923 if (c < 0)
2925 result[0] = '\0';
2926 return -1;
2928 if (compat < c)
2929 compat = c;
2930 len += strlen(result + len);
2931 result[len++] = ',';
2932 c = stringrule(result + len, stdrp, dstrp->r_save, zp->z_stdoff);
2933 if (c < 0)
2935 result[0] = '\0';
2936 return -1;
2938 if (compat < c)
2939 compat = c;
2940 return compat;
2943 static void
2944 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
2946 const struct zone *zp;
2947 struct rule *rp;
2948 ptrdiff_t i,
2950 bool usestart,
2951 useuntil;
2952 zic_t starttime,
2953 untiltime;
2954 zic_t stdoff;
2955 zic_t save;
2956 zic_t year;
2957 zic_t startoff;
2958 bool startttisstd;
2959 bool startttisut;
2960 int type;
2961 char *startbuf;
2962 char *ab;
2963 char *envvar;
2964 int max_abbr_len;
2965 int max_envvar_len;
2966 bool prodstic; /* all rules are min to max */
2967 int compat;
2968 bool do_extend;
2969 char version;
2970 ptrdiff_t lastatmax = -1;
2971 zic_t one = 1;
2972 zic_t y2038_boundary = one << 31;
2973 zic_t max_year0;
2974 int defaulttype = -1;
2976 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2977 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2978 startbuf = emalloc(max_abbr_len + 1);
2979 ab = emalloc(max_abbr_len + 1);
2980 envvar = emalloc(max_envvar_len + 1);
2981 INITIALIZE(untiltime);
2982 INITIALIZE(starttime);
2985 * Now. . .finally. . .generate some useful data!
2987 timecnt = 0;
2988 typecnt = 0;
2989 charcnt = 0;
2990 prodstic = zonecount == 1;
2993 * Thanks to Earl Chew for noting the need to unconditionally initialize
2994 * startttisstd.
2996 startttisstd = false;
2997 startttisut = false;
2998 min_year = max_year = EPOCH_YEAR;
2999 if (leapseen)
3001 updateminmax(leapminyear);
3002 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
3004 for (i = 0; i < zonecount; ++i)
3006 zp = &zpfirst[i];
3007 if (i < zonecount - 1)
3008 updateminmax(zp->z_untilrule.r_loyear);
3009 for (j = 0; j < zp->z_nrules; ++j)
3011 rp = &zp->z_rules[j];
3012 if (rp->r_lowasnum)
3013 updateminmax(rp->r_loyear);
3014 if (rp->r_hiwasnum)
3015 updateminmax(rp->r_hiyear);
3016 if (rp->r_lowasnum || rp->r_hiwasnum)
3017 prodstic = false;
3022 * Generate lots of data if a rule can't cover all future times.
3024 compat = stringzone(envvar, zpfirst, zonecount);
3025 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
3026 do_extend = compat < 0;
3027 if (noise)
3029 if (!*envvar)
3030 warning("%s %s",
3031 _("no POSIX environment variable for zone"),
3032 zpfirst->z_name);
3033 else if (compat != 0)
3036 * Circa-COMPAT clients, and earlier clients, might not work for
3037 * this zone when given dates before 1970 or after 2038.
3039 warning(_("%s: pre-%d clients may mishandle"
3040 " distant timestamps"),
3041 zpfirst->z_name, compat);
3044 if (do_extend)
3047 * Search through a couple of extra years past the obvious 400, to
3048 * avoid edge cases. For example, suppose a non-POSIX rule applies
3049 * from 2012 onwards and has transitions in March and September, plus
3050 * some one-off transitions in November 2013. If zic looked only at
3051 * the last 400 years, it would set max_year=2413, with the intent
3052 * that the 400 years 2014 through 2413 will be repeated. The last
3053 * transition listed in the tzfile would be in 2413-09, less than 400
3054 * years after the last one-off transition in 2013-11. Two years
3055 * might be overkill, but with the kind of edge cases available we're
3056 * not sure that one year would suffice.
3058 enum
3060 years_of_observations = YEARSPERREPEAT + 2};
3062 if (min_year >= ZIC_MIN + years_of_observations)
3063 min_year -= years_of_observations;
3064 else
3065 min_year = ZIC_MIN;
3066 if (max_year <= ZIC_MAX - years_of_observations)
3067 max_year += years_of_observations;
3068 else
3069 max_year = ZIC_MAX;
3072 * Regardless of any of the above, for a "proDSTic" zone which
3073 * specifies that its rules always have and always will be in effect,
3074 * we only need one cycle to define the zone.
3076 if (prodstic)
3078 min_year = 1900;
3079 max_year = min_year + years_of_observations;
3082 max_year0 = max_year;
3083 if (want_bloat())
3086 * For the benefit of older systems, generate data from 1900 through
3087 * 2038.
3089 if (min_year > 1900)
3090 min_year = 1900;
3091 if (max_year < 2038)
3092 max_year = 2038;
3095 for (i = 0; i < zonecount; ++i)
3097 struct rule *prevrp = NULL;
3100 * A guess that may well be corrected later.
3102 save = 0;
3103 zp = &zpfirst[i];
3104 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
3105 useuntil = i < (zonecount - 1);
3106 if (useuntil && zp->z_untiltime <= min_time)
3107 continue;
3108 stdoff = zp->z_stdoff;
3109 eat(zp->z_filename, zp->z_linenum);
3110 *startbuf = '\0';
3111 startoff = zp->z_stdoff;
3112 if (zp->z_nrules == 0)
3114 save = zp->z_save;
3115 doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
3116 type = addtype(oadd(zp->z_stdoff, save),
3117 startbuf, zp->z_isdst, startttisstd,
3118 startttisut);
3119 if (usestart)
3121 addtt(starttime, type);
3122 usestart = false;
3124 else
3125 defaulttype = type;
3127 else
3128 for (year = min_year; year <= max_year; ++year)
3130 if (useuntil && year > zp->z_untilrule.r_hiyear)
3131 break;
3134 * Mark which rules to do in the current year. For those to
3135 * do, calculate rpytime(rp, year); The former TYPE field was
3136 * also considered here.
3138 for (j = 0; j < zp->z_nrules; ++j)
3140 rp = &zp->z_rules[j];
3141 eats(zp->z_filename, zp->z_linenum,
3142 rp->r_filename, rp->r_linenum);
3143 rp->r_todo = year >= rp->r_loyear &&
3144 year <= rp->r_hiyear;
3145 if (rp->r_todo)
3147 rp->r_temp = rpytime(rp, year);
3148 rp->r_todo
3149 = (rp->r_temp < y2038_boundary
3150 || year <= max_year0);
3153 for (;;)
3155 ptrdiff_t k;
3156 zic_t jtime,
3157 ktime;
3158 zic_t offset;
3160 INITIALIZE(ktime);
3161 if (useuntil)
3164 * Turn untiltime into UT assuming the current stdoff
3165 * and save values.
3167 untiltime = zp->z_untiltime;
3168 if (!zp->z_untilrule.r_todisut)
3169 untiltime = tadd(untiltime,
3170 -stdoff);
3171 if (!zp->z_untilrule.r_todisstd)
3172 untiltime = tadd(untiltime,
3173 -save);
3177 * Find the rule (of those to do, if any) that takes
3178 * effect earliest in the year.
3180 k = -1;
3181 for (j = 0; j < zp->z_nrules; ++j)
3183 rp = &zp->z_rules[j];
3184 if (!rp->r_todo)
3185 continue;
3186 eats(zp->z_filename, zp->z_linenum,
3187 rp->r_filename, rp->r_linenum);
3188 offset = rp->r_todisut ? 0 : stdoff;
3189 if (!rp->r_todisstd)
3190 offset = oadd(offset, save);
3191 jtime = rp->r_temp;
3192 if (jtime == min_time ||
3193 jtime == max_time)
3194 continue;
3195 jtime = tadd(jtime, -offset);
3196 if (k < 0 || jtime < ktime)
3198 k = j;
3199 ktime = jtime;
3201 else if (jtime == ktime)
3203 char const *dup_rules_msg =
3204 _("two rules for same instant");
3206 eats(zp->z_filename, zp->z_linenum,
3207 rp->r_filename, rp->r_linenum);
3208 warning("%s", dup_rules_msg);
3209 rp = &zp->z_rules[k];
3210 eats(zp->z_filename, zp->z_linenum,
3211 rp->r_filename, rp->r_linenum);
3212 error("%s", dup_rules_msg);
3215 if (k < 0)
3216 break; /* go on to next year */
3217 rp = &zp->z_rules[k];
3218 rp->r_todo = false;
3219 if (useuntil && ktime >= untiltime)
3220 break;
3221 save = rp->r_save;
3222 if (usestart && ktime == starttime)
3223 usestart = false;
3224 if (usestart)
3226 if (ktime < starttime)
3228 startoff = oadd(zp->z_stdoff,
3229 save);
3230 doabbr(startbuf, zp,
3231 rp->r_abbrvar,
3232 rp->r_isdst,
3233 rp->r_save,
3234 false);
3235 continue;
3237 if (*startbuf == '\0'
3238 && startoff == oadd(zp->z_stdoff,
3239 save))
3241 doabbr(startbuf,
3243 rp->r_abbrvar,
3244 rp->r_isdst,
3245 rp->r_save,
3246 false);
3249 eats(zp->z_filename, zp->z_linenum,
3250 rp->r_filename, rp->r_linenum);
3251 doabbr(ab, zp, rp->r_abbrvar,
3252 rp->r_isdst, rp->r_save, false);
3253 offset = oadd(zp->z_stdoff, rp->r_save);
3254 if (!want_bloat() && !useuntil && !do_extend
3255 && prevrp
3256 && rp->r_hiyear == ZIC_MAX
3257 && prevrp->r_hiyear == ZIC_MAX)
3258 break;
3259 type = addtype(offset, ab, rp->r_isdst,
3260 rp->r_todisstd, rp->r_todisut);
3261 if (defaulttype < 0 && !rp->r_isdst)
3262 defaulttype = type;
3263 if (rp->r_hiyear == ZIC_MAX
3264 && !(0 <= lastatmax
3265 && ktime < attypes[lastatmax].at))
3266 lastatmax = timecnt;
3267 addtt(ktime, type);
3268 prevrp = rp;
3271 if (usestart)
3273 if (*startbuf == '\0' &&
3274 zp->z_format != NULL &&
3275 strchr(zp->z_format, '%') == NULL &&
3276 strchr(zp->z_format, '/') == NULL)
3277 strcpy(startbuf, zp->z_format);
3278 eat(zp->z_filename, zp->z_linenum);
3279 if (*startbuf == '\0')
3280 error(_("cannot determine time zone abbreviation to use just after until time"));
3281 else
3283 bool isdst = startoff != zp->z_stdoff;
3285 type = addtype(startoff, startbuf, isdst,
3286 startttisstd, startttisut);
3287 if (defaulttype < 0 && !isdst)
3288 defaulttype = type;
3289 addtt(starttime, type);
3294 * Now we may get to set starttime for the next zone line.
3296 if (useuntil)
3298 startttisstd = zp->z_untilrule.r_todisstd;
3299 startttisut = zp->z_untilrule.r_todisut;
3300 starttime = zp->z_untiltime;
3301 if (!startttisstd)
3302 starttime = tadd(starttime, -save);
3303 if (!startttisut)
3304 starttime = tadd(starttime, -stdoff);
3307 if (defaulttype < 0)
3308 defaulttype = 0;
3309 if (0 <= lastatmax)
3310 attypes[lastatmax].dontmerge = true;
3311 if (do_extend)
3314 * If we're extending the explicitly listed observations for 400 years
3315 * because we can't fill the POSIX-TZ field, check whether we actually
3316 * ended up explicitly listing observations through that period. If
3317 * there aren't any near the end of the 400-year period, add a
3318 * redundant one at the end of the final year, to make it clear that
3319 * we are claiming to have definite knowledge of the lack of
3320 * transitions up to that point.
3322 struct rule xr;
3323 struct attype *lastat;
3325 xr.r_month = TM_JANUARY;
3326 xr.r_dycode = DC_DOM;
3327 xr.r_dayofmonth = 1;
3328 xr.r_tod = 0;
3329 for (lastat = attypes, i = 1; i < timecnt; i++)
3330 if (attypes[i].at > lastat->at)
3331 lastat = &attypes[i];
3332 if (!lastat || lastat->at < rpytime(&xr, max_year - 1))
3334 addtt(rpytime(&xr, max_year + 1),
3335 lastat ? lastat->type : defaulttype);
3336 attypes[timecnt - 1].dontmerge = true;
3339 writezone(zpfirst->z_name, envvar, version, defaulttype);
3340 free(startbuf);
3341 free(ab);
3342 free(envvar);
3345 static void
3346 addtt(zic_t starttime, int type)
3348 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
3349 attypes[timecnt].at = starttime;
3350 attypes[timecnt].dontmerge = false;
3351 attypes[timecnt].type = type;
3352 ++timecnt;
3355 static int
3356 addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
3358 int i,
3361 if (!(-1L - 2147483647L <= utoff && utoff <= 2147483647L))
3363 error(_("UT offset out of range"));
3364 exit(EXIT_FAILURE);
3366 if (!want_bloat())
3367 ttisstd = ttisut = false;
3369 for (j = 0; j < charcnt; ++j)
3370 if (strcmp(&chars[j], abbr) == 0)
3371 break;
3372 if (j == charcnt)
3373 newabbr(abbr);
3374 else
3376 /* If there's already an entry, return its index. */
3377 for (i = 0; i < typecnt; i++)
3378 if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
3379 && ttisstd == ttisstds[i] && ttisut == ttisuts[i])
3380 return i;
3384 * There isn't one; add a new one, unless there are already too many.
3386 if (typecnt >= TZ_MAX_TYPES)
3388 error(_("too many local time types"));
3389 exit(EXIT_FAILURE);
3391 i = typecnt++;
3392 utoffs[i] = utoff;
3393 isdsts[i] = isdst;
3394 ttisstds[i] = ttisstd;
3395 ttisuts[i] = ttisut;
3396 desigidx[i] = j;
3397 return i;
3400 static void
3401 leapadd(zic_t t, int correction, int rolling)
3403 int i;
3405 if (TZ_MAX_LEAPS <= leapcnt)
3407 error(_("too many leap seconds"));
3408 exit(EXIT_FAILURE);
3410 for (i = 0; i < leapcnt; ++i)
3411 if (t <= trans[i])
3412 break;
3413 memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans);
3414 memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr);
3415 memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll);
3416 trans[i] = t;
3417 corr[i] = correction;
3418 roll[i] = rolling;
3419 ++leapcnt;
3422 static void
3423 adjleap(void)
3425 int i;
3426 zic_t last = 0;
3427 zic_t prevtrans = 0;
3430 * propagate leap seconds forward
3432 for (i = 0; i < leapcnt; ++i)
3434 if (trans[i] - prevtrans < 28 * SECSPERDAY)
3436 error(_("Leap seconds too close together"));
3437 exit(EXIT_FAILURE);
3439 prevtrans = trans[i];
3440 trans[i] = tadd(trans[i], last);
3441 last = corr[i] += last;
3444 if (leapexpires < 0)
3446 leapexpires = comment_leapexpires;
3447 if (0 <= leapexpires)
3448 warning(_("\"#expires\" is obsolescent; use \"Expires\""));
3451 if (0 <= leapexpires)
3453 leapexpires = oadd(leapexpires, last);
3454 if (!(leapcnt == 0 || (trans[leapcnt - 1] < leapexpires)))
3456 error(_("last Leap time does not precede Expires time"));
3457 exit(EXIT_FAILURE);
3459 if (leapexpires <= hi_time)
3460 hi_time = leapexpires - 1;
3464 /* Is A a space character in the C locale? */
3465 static bool
3466 is_space(char a)
3468 switch (a)
3470 default:
3471 return false;
3472 case ' ':
3473 case '\f':
3474 case '\n':
3475 case '\r':
3476 case '\t':
3477 case '\v':
3478 return true;
3482 /* Is A an alphabetic character in the C locale? */
3483 static bool
3484 is_alpha(char a)
3486 switch (a)
3488 default:
3489 return false;
3490 case 'A':
3491 case 'B':
3492 case 'C':
3493 case 'D':
3494 case 'E':
3495 case 'F':
3496 case 'G':
3497 case 'H':
3498 case 'I':
3499 case 'J':
3500 case 'K':
3501 case 'L':
3502 case 'M':
3503 case 'N':
3504 case 'O':
3505 case 'P':
3506 case 'Q':
3507 case 'R':
3508 case 'S':
3509 case 'T':
3510 case 'U':
3511 case 'V':
3512 case 'W':
3513 case 'X':
3514 case 'Y':
3515 case 'Z':
3516 case 'a':
3517 case 'b':
3518 case 'c':
3519 case 'd':
3520 case 'e':
3521 case 'f':
3522 case 'g':
3523 case 'h':
3524 case 'i':
3525 case 'j':
3526 case 'k':
3527 case 'l':
3528 case 'm':
3529 case 'n':
3530 case 'o':
3531 case 'p':
3532 case 'q':
3533 case 'r':
3534 case 's':
3535 case 't':
3536 case 'u':
3537 case 'v':
3538 case 'w':
3539 case 'x':
3540 case 'y':
3541 case 'z':
3542 return true;
3546 /* If A is an uppercase character in the C locale, return its lowercase
3547 counterpart. Otherwise, return A. */
3548 static char
3549 lowerit(char a)
3551 switch (a)
3553 default:
3554 return a;
3555 case 'A':
3556 return 'a';
3557 case 'B':
3558 return 'b';
3559 case 'C':
3560 return 'c';
3561 case 'D':
3562 return 'd';
3563 case 'E':
3564 return 'e';
3565 case 'F':
3566 return 'f';
3567 case 'G':
3568 return 'g';
3569 case 'H':
3570 return 'h';
3571 case 'I':
3572 return 'i';
3573 case 'J':
3574 return 'j';
3575 case 'K':
3576 return 'k';
3577 case 'L':
3578 return 'l';
3579 case 'M':
3580 return 'm';
3581 case 'N':
3582 return 'n';
3583 case 'O':
3584 return 'o';
3585 case 'P':
3586 return 'p';
3587 case 'Q':
3588 return 'q';
3589 case 'R':
3590 return 'r';
3591 case 'S':
3592 return 's';
3593 case 'T':
3594 return 't';
3595 case 'U':
3596 return 'u';
3597 case 'V':
3598 return 'v';
3599 case 'W':
3600 return 'w';
3601 case 'X':
3602 return 'x';
3603 case 'Y':
3604 return 'y';
3605 case 'Z':
3606 return 'z';
3610 /* case-insensitive equality */
3611 static bool
3612 ciequal(const char *ap, const char *bp)
3614 while (lowerit(*ap) == lowerit(*bp++))
3615 if (*ap++ == '\0')
3616 return true;
3617 return false;
3620 static bool
3621 itsabbr(const char *abbr, const char *word)
3623 if (lowerit(*abbr) != lowerit(*word))
3624 return false;
3625 ++word;
3626 while (*++abbr != '\0')
3629 if (*word == '\0')
3630 return false;
3631 } while (lowerit(*word++) != lowerit(*abbr));
3632 return true;
3635 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
3637 static bool
3638 ciprefix(char const *abbr, char const *word)
3641 if (!*abbr)
3642 return true;
3643 while (lowerit(*abbr++) == lowerit(*word++));
3645 return false;
3648 static const struct lookup *
3649 byword(const char *word, const struct lookup *table)
3651 const struct lookup *foundlp;
3652 const struct lookup *lp;
3654 if (word == NULL || table == NULL)
3655 return NULL;
3658 * If TABLE is LASTS and the word starts with "last" followed by a
3659 * non-'-', skip the "last" and look in WDAY_NAMES instead. Warn about any
3660 * usage of the undocumented prefix "last-".
3662 if (table == lasts && ciprefix("last", word) && word[4])
3664 if (word[4] == '-')
3665 warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
3666 word, word + 5);
3667 else
3669 word += 4;
3670 table = wday_names;
3675 * Look for exact match.
3677 for (lp = table; lp->l_word != NULL; ++lp)
3678 if (ciequal(word, lp->l_word))
3679 return lp;
3682 * Look for inexact match.
3684 foundlp = NULL;
3685 for (lp = table; lp->l_word != NULL; ++lp)
3686 if (ciprefix(word, lp->l_word))
3688 if (foundlp == NULL)
3689 foundlp = lp;
3690 else
3691 return NULL; /* multiple inexact matches */
3694 if (foundlp && noise)
3696 /* Warn about any backward-compatibility issue with pre-2017c zic. */
3697 bool pre_2017c_match = false;
3699 for (lp = table; lp->l_word; lp++)
3700 if (itsabbr(word, lp->l_word))
3702 if (pre_2017c_match)
3704 warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
3705 break;
3707 pre_2017c_match = true;
3711 return foundlp;
3714 static char **
3715 getfields(char *cp)
3717 char *dp;
3718 char **array;
3719 int nsubs;
3721 if (cp == NULL)
3722 return NULL;
3723 array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
3724 nsubs = 0;
3725 for (;;)
3727 while (is_space(*cp))
3728 ++cp;
3729 if (*cp == '\0' || *cp == '#')
3730 break;
3731 array[nsubs++] = dp = cp;
3734 if ((*dp = *cp++) != '"')
3735 ++dp;
3736 else
3737 while ((*dp = *cp++) != '"')
3738 if (*dp != '\0')
3739 ++dp;
3740 else
3742 error(_("Odd number of quotation marks"));
3743 exit(EXIT_FAILURE);
3745 } while (*cp && *cp != '#' && !is_space(*cp));
3746 if (is_space(*cp))
3747 ++cp;
3748 *dp = '\0';
3750 array[nsubs] = NULL;
3751 return array;
3754 static void
3755 time_overflow(void)
3757 error(_("time overflow"));
3758 exit(EXIT_FAILURE);
3761 static zic_t
3762 oadd(zic_t t1, zic_t t2)
3764 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
3765 time_overflow();
3766 return t1 + t2;
3769 static zic_t
3770 tadd(zic_t t1, zic_t t2)
3772 if (t1 < 0)
3774 if (t2 < min_time - t1)
3776 if (t1 != min_time)
3777 time_overflow();
3778 return min_time;
3781 else
3783 if (max_time - t1 < t2)
3785 if (t1 != max_time)
3786 time_overflow();
3787 return max_time;
3790 return t1 + t2;
3794 * Given a rule, and a year, compute the date (in seconds since January 1,
3795 * 1970, 00:00 LOCAL time) in that year that the rule refers to.
3798 static zic_t
3799 rpytime(const struct rule *rp, zic_t wantedy)
3801 int m,
3803 zic_t dayoff; /* with a nod to Margaret O. */
3804 zic_t t,
3807 if (wantedy == ZIC_MIN)
3808 return min_time;
3809 if (wantedy == ZIC_MAX)
3810 return max_time;
3811 dayoff = 0;
3812 m = TM_JANUARY;
3813 y = EPOCH_YEAR;
3814 if (y < wantedy)
3816 wantedy -= y;
3817 dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
3818 wantedy %= YEARSPERREPEAT;
3819 wantedy += y;
3821 else if (wantedy < 0)
3823 dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
3824 wantedy %= YEARSPERREPEAT;
3826 while (wantedy != y)
3828 if (wantedy > y)
3830 i = len_years[isleap(y)];
3831 ++y;
3833 else
3835 --y;
3836 i = -len_years[isleap(y)];
3838 dayoff = oadd(dayoff, i);
3840 while (m != rp->r_month)
3842 i = len_months[isleap(y)][m];
3843 dayoff = oadd(dayoff, i);
3844 ++m;
3846 i = rp->r_dayofmonth;
3847 if (m == TM_FEBRUARY && i == 29 && !isleap(y))
3849 if (rp->r_dycode == DC_DOWLEQ)
3850 --i;
3851 else
3853 error(_("use of 2/29 in non leap-year"));
3854 exit(EXIT_FAILURE);
3857 --i;
3858 dayoff = oadd(dayoff, i);
3859 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ)
3861 zic_t wday;
3863 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3864 wday = EPOCH_WDAY;
3867 * Don't trust mod of negative numbers.
3869 if (dayoff >= 0)
3870 wday = (wday + dayoff) % LDAYSPERWEEK;
3871 else
3873 wday -= ((-dayoff) % LDAYSPERWEEK);
3874 if (wday < 0)
3875 wday += LDAYSPERWEEK;
3877 while (wday != rp->r_wday)
3878 if (rp->r_dycode == DC_DOWGEQ)
3880 dayoff = oadd(dayoff, 1);
3881 if (++wday >= LDAYSPERWEEK)
3882 wday = 0;
3883 ++i;
3885 else
3887 dayoff = oadd(dayoff, -1);
3888 if (--wday < 0)
3889 wday = LDAYSPERWEEK - 1;
3890 --i;
3892 if (i < 0 || i >= len_months[isleap(y)][m])
3894 if (noise)
3895 warning(_("rule goes past start/end of month; \
3896 will not work with pre-2004 versions of zic"));
3899 if (dayoff < min_time / SECSPERDAY)
3900 return min_time;
3901 if (dayoff > max_time / SECSPERDAY)
3902 return max_time;
3903 t = (zic_t) dayoff * SECSPERDAY;
3904 return tadd(t, rp->r_tod);
3907 static void
3908 newabbr(const char *string)
3910 int i;
3912 if (strcmp(string, GRANDPARENTED) != 0)
3914 const char *cp;
3915 const char *mp;
3917 cp = string;
3918 mp = NULL;
3919 while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
3920 || *cp == '-' || *cp == '+')
3921 ++cp;
3922 if (noise && cp - string < 3)
3923 mp = _("time zone abbreviation has fewer than 3 characters");
3924 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
3925 mp = _("time zone abbreviation has too many characters");
3926 if (*cp != '\0')
3927 mp = _("time zone abbreviation differs from POSIX standard");
3928 if (mp != NULL)
3929 warning("%s (%s)", mp, string);
3931 i = strlen(string) + 1;
3932 if (charcnt + i > TZ_MAX_CHARS)
3934 error(_("too many, or too long, time zone abbreviations"));
3935 exit(EXIT_FAILURE);
3937 strcpy(&chars[charcnt], string);
3938 charcnt += i;
3941 /* Ensure that the directories of ARGNAME exist, by making any missing
3942 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3943 do it for ARGNAME too. Exit with failure if there is trouble.
3944 Do not consider an existing non-directory to be trouble. */
3945 static void
3946 mkdirs(char const *argname, bool ancestors)
3948 char *name;
3949 char *cp;
3951 cp = name = ecpyalloc(argname);
3954 * On MS-Windows systems, do not worry about drive letters or backslashes,
3955 * as this should suffice in practice. Time zone names do not use drive
3956 * letters and backslashes. If the -d option of zic does not name an
3957 * already-existing directory, it can use slashes to separate the
3958 * already-existing ancestor prefix from the to-be-created subdirectories.
3961 /* Do not mkdir a root directory, as it must exist. */
3962 while (*cp == '/')
3963 cp++;
3965 while (cp && ((cp = strchr(cp, '/')) || !ancestors))
3967 if (cp)
3968 *cp = '\0';
3971 * Try to create it. It's OK if creation fails because the directory
3972 * already exists, perhaps because some other process just created it.
3973 * For simplicity do not check first whether it already exists, as
3974 * that is checked anyway if the mkdir fails.
3976 if (mkdir(name, MKDIR_UMASK) != 0)
3979 * For speed, skip itsdir if errno == EEXIST. Since mkdirs is
3980 * called only after open fails with ENOENT on a subfile, EEXIST
3981 * implies itsdir here.
3983 int err = errno;
3985 if (err != EEXIST && !itsdir(name))
3987 error(_("%s: Cannot create directory %s: %s"),
3988 progname, name, strerror(err));
3989 exit(EXIT_FAILURE);
3992 if (cp)
3993 *cp++ = '/';
3995 free(name);
3999 #ifdef WIN32
4001 * To run on win32
4004 link(const char *oldpath, const char *newpath)
4006 if (!CopyFile(oldpath, newpath, false))
4008 _dosmaperr(GetLastError());
4009 return -1;
4011 return 0;
4013 #endif