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