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