1 /* Compile .zi time zone data into TZif binary files. */
4 ** This file is in the public domain, so clarified as of
5 ** 2006-07-17 by Arthur David Olson.
18 #define ZIC_VERSION_PRE_2013 '2'
19 #define ZIC_VERSION '3'
21 typedef int_fast64_t zic_t
;
22 #define ZIC_MIN INT_FAST64_MIN
23 #define ZIC_MAX INT_FAST64_MAX
24 #define PRIdZIC PRIdFAST64
25 #define SCNdZIC SCNdFAST64
27 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
28 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
29 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
35 # define mkdir(name, mode) _mkdir(name)
42 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
44 #define MKDIR_UMASK 0755
46 /* Port to native MS-Windows and to ancient UNIX. */
47 #if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT
48 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
52 #include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
53 #endif /* HAVE_SYS_WAIT_H */
56 #define WIFEXITED(status) (((status) & 0xff) == 0)
57 #endif /* !defined WIFEXITED */
59 #define WEXITSTATUS(status) (((status) >> 8) & 0xff)
60 #endif /* !defined WEXITSTATUS */
62 /* The maximum ptrdiff_t value, for pre-C99 platforms. */
64 static ptrdiff_t const PTRDIFF_MAX
= MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
67 /* The minimum alignment of a type, for pre-C11 platforms. */
68 #if __STDC_VERSION__ < 201112
69 # define _Alignof(type) offsetof(struct { char a; type b; }, b)
72 /* The type for line numbers. Use PRIdMAX to format them; formerly
73 there was also "#define PRIdLINENO PRIdMAX" and formats used
74 PRIdLINENO, but xgettext cannot grok that. */
75 typedef intmax_t lineno
;
78 const char * r_filename
;
82 zic_t r_loyear
; /* for example, 1986 */
83 zic_t r_hiyear
; /* for example, 1986 */
84 const char * r_yrtype
;
88 int r_month
; /* 0..11 */
90 int r_dycode
; /* see below */
94 zic_t r_tod
; /* time from midnight */
95 bool r_todisstd
; /* above is standard time if 1 */
96 /* or wall clock time if 0 */
97 bool r_todisgmt
; /* above is GMT if 1 */
98 /* or local time if 0 */
99 bool r_isdst
; /* is this daylight saving time? */
100 zic_t r_stdoff
; /* offset from default time (which is
101 usually standard time) */
102 const char * r_abbrvar
; /* variable part of abbreviation */
104 bool r_todo
; /* a rule to do (used in outzone) */
105 zic_t r_temp
; /* used in outzone */
109 ** r_dycode r_dayofmonth r_wday
112 #define DC_DOM 0 /* 1..31 */ /* unused */
113 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
114 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
117 const char * z_filename
;
123 const char * z_format
;
124 char z_format_specifier
;
129 struct rule
* z_rules
;
132 struct rule z_untilrule
;
136 #if !HAVE_POSIX_DECLS
137 extern int getopt(int argc
, char * const argv
[],
138 const char * options
);
139 extern int link(const char * fromname
, const char * toname
);
140 extern char * optarg
;
145 # define link(from, to) (errno = ENOTSUP, -1)
148 # define readlink(file, buf, size) (errno = ENOTSUP, -1)
149 # define symlink(from, to) (errno = ENOTSUP, -1)
150 # define S_ISLNK(m) 0
152 #ifndef AT_SYMLINK_FOLLOW
153 # define linkat(fromdir, from, todir, to, flag) \
154 (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
157 static void addtt(zic_t starttime
, int type
);
158 static int addtype(zic_t
, char const *, bool, bool, bool);
159 static void leapadd(zic_t
, bool, int, int);
160 static void adjleap(void);
161 static void associate(void);
162 static void dolink(const char *, const char *, bool);
163 static char ** getfields(char * buf
);
164 static zic_t
gethms(const char * string
, const char * errstring
);
165 static zic_t
getstdoff(char *, bool *);
166 static void infile(const char * filename
);
167 static void inleap(char ** fields
, int nfields
);
168 static void inlink(char ** fields
, int nfields
);
169 static void inrule(char ** fields
, int nfields
);
170 static bool inzcont(char ** fields
, int nfields
);
171 static bool inzone(char ** fields
, int nfields
);
172 static bool inzsub(char **, int, bool);
173 static bool itsdir(char const *);
174 static bool itssymlink(char const *);
175 static bool is_alpha(char a
);
176 static char lowerit(char);
177 static void mkdirs(char const *, bool);
178 static void newabbr(const char * abbr
);
179 static zic_t
oadd(zic_t t1
, zic_t t2
);
180 static void outzone(const struct zone
* zp
, ptrdiff_t ntzones
);
181 static zic_t
rpytime(const struct rule
* rp
, zic_t wantedy
);
182 static void rulesub(struct rule
* rp
,
183 const char * loyearp
, const char * hiyearp
,
184 const char * typep
, const char * monthp
,
185 const char * dayp
, const char * timep
);
186 static zic_t
tadd(zic_t t1
, zic_t t2
);
187 static bool yearistype(zic_t year
, const char * type
);
189 /* Bound on length of what %z can expand to. */
190 enum { PERCENT_Z_LEN_BOUND
= sizeof "+995959" - 1 };
192 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
193 TZif files whose POSIX-TZ-style strings contain '<'; see
194 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
195 workaround will no longer be needed when Qt 5.6.1 and earlier are
196 obsolete, say in the year 2021. */
197 #ifndef WORK_AROUND_QTBUG_53071
198 enum { WORK_AROUND_QTBUG_53071
= true };
203 static bool warnings
;
204 static const char * filename
;
206 static bool leapseen
;
207 static zic_t leapminyear
;
208 static zic_t leapmaxyear
;
209 static lineno linenum
;
210 static int max_abbrvar_len
= PERCENT_Z_LEN_BOUND
;
211 static int max_format_len
;
212 static zic_t max_year
;
213 static zic_t min_year
;
215 static const char * rfilename
;
216 static lineno rlinenum
;
217 static const char * progname
;
218 static ptrdiff_t timecnt
;
219 static ptrdiff_t timecnt_alloc
;
232 ** Which fields are which on a Zone line.
240 #define ZF_TILMONTH 6
243 #define ZONE_MINFIELDS 5
244 #define ZONE_MAXFIELDS 9
247 ** Which fields are which on a Zone continuation line.
253 #define ZFC_TILYEAR 3
254 #define ZFC_TILMONTH 4
256 #define ZFC_TILTIME 6
257 #define ZONEC_MINFIELDS 3
258 #define ZONEC_MAXFIELDS 7
261 ** Which files are which on a Rule line.
273 #define RULE_FIELDS 10
276 ** Which fields are which on a Link line.
281 #define LINK_FIELDS 3
284 ** Which fields are which on a Leap line.
293 #define LEAP_FIELDS 7
303 static struct rule
* rules
;
304 static ptrdiff_t nrules
; /* number of rules */
305 static ptrdiff_t nrules_alloc
;
307 static struct zone
* zones
;
308 static ptrdiff_t nzones
; /* number of zones */
309 static ptrdiff_t nzones_alloc
;
312 const char * l_filename
;
318 static struct link
* links
;
319 static ptrdiff_t nlinks
;
320 static ptrdiff_t nlinks_alloc
;
327 static struct lookup
const * byword(const char * string
,
328 const struct lookup
* lp
);
330 static struct lookup
const zi_line_codes
[] = {
336 static struct lookup
const leap_line_codes
[] = {
341 static struct lookup
const mon_names
[] = {
342 { "January", TM_JANUARY
},
343 { "February", TM_FEBRUARY
},
344 { "March", TM_MARCH
},
345 { "April", TM_APRIL
},
349 { "August", TM_AUGUST
},
350 { "September", TM_SEPTEMBER
},
351 { "October", TM_OCTOBER
},
352 { "November", TM_NOVEMBER
},
353 { "December", TM_DECEMBER
},
357 static struct lookup
const wday_names
[] = {
358 { "Sunday", TM_SUNDAY
},
359 { "Monday", TM_MONDAY
},
360 { "Tuesday", TM_TUESDAY
},
361 { "Wednesday", TM_WEDNESDAY
},
362 { "Thursday", TM_THURSDAY
},
363 { "Friday", TM_FRIDAY
},
364 { "Saturday", TM_SATURDAY
},
368 static struct lookup
const lasts
[] = {
369 { "last-Sunday", TM_SUNDAY
},
370 { "last-Monday", TM_MONDAY
},
371 { "last-Tuesday", TM_TUESDAY
},
372 { "last-Wednesday", TM_WEDNESDAY
},
373 { "last-Thursday", TM_THURSDAY
},
374 { "last-Friday", TM_FRIDAY
},
375 { "last-Saturday", TM_SATURDAY
},
379 static struct lookup
const begin_years
[] = {
380 { "minimum", YR_MINIMUM
},
381 { "maximum", YR_MAXIMUM
},
385 static struct lookup
const end_years
[] = {
386 { "minimum", YR_MINIMUM
},
387 { "maximum", YR_MAXIMUM
},
392 static struct lookup
const leap_types
[] = {
394 { "Stationary", false },
398 static const int len_months
[2][MONSPERYEAR
] = {
399 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
400 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
403 static const int len_years
[2] = {
404 DAYSPERNYEAR
, DAYSPERLYEAR
407 static struct attype
{
412 static zic_t gmtoffs
[TZ_MAX_TYPES
];
413 static char isdsts
[TZ_MAX_TYPES
];
414 static unsigned char abbrinds
[TZ_MAX_TYPES
];
415 static bool ttisstds
[TZ_MAX_TYPES
];
416 static bool ttisgmts
[TZ_MAX_TYPES
];
417 static char chars
[TZ_MAX_CHARS
];
418 static zic_t trans
[TZ_MAX_LEAPS
];
419 static zic_t corr
[TZ_MAX_LEAPS
];
420 static char roll
[TZ_MAX_LEAPS
];
423 ** Memory allocation.
426 static _Noreturn
void
427 memory_exhausted(const char *msg
)
429 fprintf(stderr
, _("%s: Memory exhausted: %s\n"), progname
, msg
);
433 static ATTRIBUTE_PURE
size_t
434 size_product(size_t nitems
, size_t itemsize
)
436 if (SIZE_MAX
/ itemsize
< nitems
)
437 memory_exhausted(_("size overflow"));
438 return nitems
* itemsize
;
441 static ATTRIBUTE_PURE
size_t
442 align_to(size_t size
, size_t alignment
)
444 size_t aligned_size
= size
+ alignment
- 1;
445 aligned_size
-= aligned_size
% alignment
;
446 if (aligned_size
< size
)
447 memory_exhausted(_("alignment overflow"));
453 strdup(char const *str
)
455 char *result
= malloc(strlen(str
) + 1);
456 return result
? strcpy(result
, str
) : result
;
464 memory_exhausted(strerror(errno
));
468 static void * ATTRIBUTE_MALLOC
471 return memcheck(malloc(size
));
475 erealloc(void *ptr
, size_t size
)
477 return memcheck(realloc(ptr
, size
));
480 static char * ATTRIBUTE_MALLOC
481 ecpyalloc (char const *str
)
483 return memcheck(strdup(str
));
487 growalloc(void *ptr
, size_t itemsize
, ptrdiff_t nitems
, ptrdiff_t *nitems_alloc
)
489 if (nitems
< *nitems_alloc
)
492 ptrdiff_t nitems_max
= PTRDIFF_MAX
- WORK_AROUND_QTBUG_53071
;
493 ptrdiff_t amax
= nitems_max
< SIZE_MAX
? nitems_max
: SIZE_MAX
;
494 if ((amax
- 1) / 3 * 2 < *nitems_alloc
)
495 memory_exhausted(_("integer overflow"));
496 *nitems_alloc
+= (*nitems_alloc
>> 1) + 1;
497 return erealloc(ptr
, size_product(*nitems_alloc
, itemsize
));
506 eats(char const *name
, lineno num
, char const *rname
, lineno rnum
)
515 eat(char const *name
, lineno num
)
517 eats(name
, num
, NULL
, -1);
520 static void ATTRIBUTE_FORMAT((printf
, 1, 0))
521 verror(const char *const string
, va_list args
)
524 ** Match the format of "cc" to allow sh users to
525 ** zic ... 2>&1 | error -t "*" -v
529 fprintf(stderr
, _("\"%s\", line %"PRIdMAX
": "), filename
, linenum
);
530 vfprintf(stderr
, string
, args
);
531 if (rfilename
!= NULL
)
532 fprintf(stderr
, _(" (rule from \"%s\", line %"PRIdMAX
")"),
533 rfilename
, rlinenum
);
534 fprintf(stderr
, "\n");
537 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
538 error(const char *const string
, ...)
541 va_start(args
, string
);
542 verror(string
, args
);
547 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
548 warning(const char *const string
, ...)
551 fprintf(stderr
, _("warning: "));
552 va_start(args
, string
);
553 verror(string
, args
);
559 close_file(FILE *stream
, char const *dir
, char const *name
)
561 char const *e
= (ferror(stream
) ? _("I/O error")
562 : fclose(stream
) != 0 ? strerror(errno
) : NULL
);
564 fprintf(stderr
, "%s: %s%s%s%s%s\n", progname
,
565 dir
? dir
: "", dir
? "/" : "",
566 name
? name
: "", name
? ": " : "",
572 static _Noreturn
void
573 usage(FILE *stream
, int status
)
576 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
577 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
578 "\t[ -t localtime-link ] [ -L leapseconds ] [ filename ... ]\n\n"
579 "Report bugs to %s.\n"),
580 progname
, progname
, REPORT_BUGS_TO
);
581 if (status
== EXIT_SUCCESS
)
582 close_file(stream
, NULL
, NULL
);
586 /* Change the working directory to DIR, possibly creating DIR and its
587 ancestors. After this is done, all files are accessed with names
590 change_directory (char const *dir
)
592 if (chdir(dir
) != 0) {
593 int chdir_errno
= errno
;
594 if (chdir_errno
== ENOENT
) {
596 chdir_errno
= chdir(dir
) == 0 ? 0 : errno
;
598 if (chdir_errno
!= 0) {
599 fprintf(stderr
, _("%s: Can't chdir to %s: %s\n"),
600 progname
, dir
, strerror(chdir_errno
));
606 static const char * psxrules
;
607 static const char * lcltime
;
608 static const char * directory
;
609 static const char * leapsec
;
610 static const char * tzdefault
;
611 static const char * yitcommand
;
614 main(int argc
, char **argv
)
617 register ptrdiff_t i
, j
;
620 umask(umask(S_IWGRP
| S_IWOTH
) | (S_IWGRP
| S_IWOTH
));
623 setlocale(LC_ALL
, "");
625 bindtextdomain(TZ_DOMAIN
, TZ_DOMAINDIR
);
626 #endif /* defined TEXTDOMAINDIR */
627 textdomain(TZ_DOMAIN
);
628 #endif /* HAVE_GETTEXT */
630 if (TYPE_BIT(zic_t
) < 64) {
631 fprintf(stderr
, "%s: %s\n", progname
,
632 _("wild compilation-time specification of zic_t"));
635 for (k
= 1; k
< argc
; k
++)
636 if (strcmp(argv
[k
], "--version") == 0) {
637 printf("zic %s%s\n", PKGVERSION
, TZVERSION
);
638 close_file(stdout
, NULL
, NULL
);
640 } else if (strcmp(argv
[k
], "--help") == 0) {
641 usage(stdout
, EXIT_SUCCESS
);
643 while ((c
= getopt(argc
, argv
, "d:l:L:p:st:vy:")) != EOF
&& c
!= -1)
646 usage(stderr
, EXIT_FAILURE
);
648 if (directory
== NULL
)
652 _("%s: More than one -d option specified\n"),
662 _("%s: More than one -l option specified\n"),
668 if (psxrules
== NULL
)
672 _("%s: More than one -p option specified\n"),
678 if (tzdefault
!= NULL
) {
680 _("%s: More than one -t option"
688 if (yitcommand
== NULL
) {
689 warning(_("-y is obsolescent"));
693 _("%s: More than one -y option specified\n"),
703 _("%s: More than one -L option specified\n"),
712 warning(_("-s ignored"));
715 if (optind
== argc
- 1 && strcmp(argv
[optind
], "=") == 0)
716 usage(stderr
, EXIT_FAILURE
); /* usage message by request */
717 if (directory
== NULL
)
719 if (tzdefault
== NULL
)
720 tzdefault
= TZDEFAULT
;
721 if (yitcommand
== NULL
)
722 yitcommand
= "yearistype";
724 if (optind
< argc
&& leapsec
!= NULL
) {
729 for (k
= optind
; k
< argc
; k
++)
734 change_directory(directory
);
735 for (i
= 0; i
< nzones
; i
= j
) {
737 ** Find the next non-continuation zone entry.
739 for (j
= i
+ 1; j
< nzones
&& zones
[j
].z_name
== NULL
; ++j
)
741 outzone(&zones
[i
], j
- i
);
746 for (i
= 0; i
< nlinks
; ++i
) {
747 eat(links
[i
].l_filename
, links
[i
].l_linenum
);
748 dolink(links
[i
].l_from
, links
[i
].l_to
, false);
750 for (j
= 0; j
< nlinks
; ++j
)
751 if (strcmp(links
[i
].l_to
,
752 links
[j
].l_from
) == 0)
753 warning(_("link to link"));
755 if (lcltime
!= NULL
) {
756 eat(_("command line"), 1);
757 dolink(lcltime
, tzdefault
, true);
759 if (psxrules
!= NULL
) {
760 eat(_("command line"), 1);
761 dolink(psxrules
, TZDEFRULES
, true);
763 if (warnings
&& (ferror(stderr
) || fclose(stderr
) != 0))
765 return errors
? EXIT_FAILURE
: EXIT_SUCCESS
;
769 componentcheck(char const *name
, char const *component
,
770 char const *component_end
)
772 enum { component_len_max
= 14 };
773 ptrdiff_t component_len
= component_end
- component
;
774 if (component_len
== 0) {
776 error (_("empty file name"));
778 error (_(component
== name
779 ? "file name '%s' begins with '/'"
781 ? "file name '%s' contains '//'"
782 : "file name '%s' ends with '/'"),
786 if (0 < component_len
&& component_len
<= 2
787 && component
[0] == '.' && component_end
[-1] == '.') {
788 int len
= component_len
;
789 error(_("file name '%s' contains '%.*s' component"),
790 name
, len
, component
);
794 if (0 < component_len
&& component
[0] == '-')
795 warning(_("file name '%s' component contains leading '-'"),
797 if (component_len_max
< component_len
)
798 warning(_("file name '%s' contains overlength component"
800 name
, component_len_max
, component
);
806 namecheck(const char *name
)
808 register char const *cp
;
810 /* Benign characters in a portable file name. */
811 static char const benign
[] =
813 "abcdefghijklmnopqrstuvwxyz"
814 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
816 /* Non-control chars in the POSIX portable character set,
817 excluding the benign characters. */
818 static char const printable_and_not_benign
[] =
819 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
821 register char const *component
= name
;
822 for (cp
= name
; *cp
; cp
++) {
823 unsigned char c
= *cp
;
824 if (noise
&& !strchr(benign
, c
)) {
825 warning((strchr(printable_and_not_benign
, c
)
826 ? _("file name '%s' contains byte '%c'")
827 : _("file name '%s' contains byte '\\%o'")),
831 if (!componentcheck(name
, component
, cp
))
836 return componentcheck(name
, component
, cp
);
839 /* Create symlink contents suitable for symlinking FROM to TO, as a
840 freshly allocated string. FROM should be a relative file name, and
841 is relative to the global variable DIRECTORY. TO can be either
842 relative or absolute. */
844 relname(char const *from
, char const *to
)
846 size_t i
, taillen
, dotdotetcsize
;
847 size_t dir_len
= 0, dotdots
= 0, linksize
= SIZE_MAX
;
848 char const *f
= from
;
851 /* Make F absolute too. */
852 size_t len
= strlen(directory
);
853 bool needslash
= len
&& directory
[len
- 1] != '/';
854 linksize
= len
+ needslash
+ strlen(from
) + 1;
855 f
= result
= emalloc(linksize
);
856 strcpy(result
, directory
);
858 strcpy(result
+ len
+ needslash
, from
);
860 for (i
= 0; f
[i
] && f
[i
] == to
[i
]; i
++)
864 dotdots
+= to
[i
] == '/' && to
[i
- 1] != '/';
865 taillen
= strlen(f
+ dir_len
);
866 dotdotetcsize
= 3 * dotdots
+ taillen
+ 1;
867 if (dotdotetcsize
<= linksize
) {
869 result
= emalloc(dotdotetcsize
);
870 for (i
= 0; i
< dotdots
; i
++)
871 memcpy(result
+ 3 * i
, "../", 3);
872 memmove(result
+ 3 * dotdots
, f
+ dir_len
, taillen
+ 1);
877 /* Hard link FROM to TO, following any symbolic links.
878 Return 0 if successful, an error number otherwise. */
880 hardlinkerr(char const *from
, char const *to
)
882 int r
= linkat(AT_FDCWD
, from
, AT_FDCWD
, to
, AT_SYMLINK_FOLLOW
);
883 return r
== 0 ? 0 : errno
;
887 dolink(char const *fromfield
, char const *tofield
, bool staysymlink
)
889 bool todirs_made
= false;
893 ** We get to be careful here since
894 ** there's a fair chance of root running us.
896 if (itsdir(fromfield
)) {
897 fprintf(stderr
, _("%s: link from %s/%s failed: %s\n"),
898 progname
, directory
, fromfield
, strerror(EPERM
));
902 staysymlink
= itssymlink(tofield
);
903 if (remove(tofield
) == 0)
905 else if (errno
!= ENOENT
) {
906 char const *e
= strerror(errno
);
907 fprintf(stderr
, _("%s: Can't remove %s/%s: %s\n"),
908 progname
, directory
, tofield
, e
);
911 link_errno
= staysymlink
? ENOTSUP
: hardlinkerr(fromfield
, tofield
);
912 if (link_errno
== ENOENT
&& !todirs_made
) {
913 mkdirs(tofield
, true);
915 link_errno
= hardlinkerr(fromfield
, tofield
);
917 if (link_errno
!= 0) {
918 bool absolute
= *fromfield
== '/';
919 char *linkalloc
= absolute
? NULL
: relname(fromfield
, tofield
);
920 char const *contents
= absolute
? fromfield
: linkalloc
;
921 int symlink_errno
= symlink(contents
, tofield
) == 0 ? 0 : errno
;
923 && (symlink_errno
== ENOENT
|| symlink_errno
== ENOTSUP
)) {
924 mkdirs(tofield
, true);
925 if (symlink_errno
== ENOENT
)
926 symlink_errno
= symlink(contents
, tofield
) == 0 ? 0 : errno
;
929 if (symlink_errno
== 0) {
930 if (link_errno
!= ENOTSUP
)
931 warning(_("symbolic link used because hard link failed: %s"),
932 strerror(link_errno
));
936 fp
= fopen(fromfield
, "rb");
938 char const *e
= strerror(errno
);
939 fprintf(stderr
, _("%s: Can't read %s/%s: %s\n"),
940 progname
, directory
, fromfield
, e
);
943 tp
= fopen(tofield
, "wb");
945 char const *e
= strerror(errno
);
946 fprintf(stderr
, _("%s: Can't create %s/%s: %s\n"),
947 progname
, directory
, tofield
, e
);
950 while ((c
= getc(fp
)) != EOF
)
952 close_file(fp
, directory
, fromfield
);
953 close_file(tp
, directory
, tofield
);
954 if (link_errno
!= ENOTSUP
)
955 warning(_("copy used because hard link failed: %s"),
956 strerror(link_errno
));
957 else if (symlink_errno
!= ENOTSUP
)
958 warning(_("copy used because symbolic link failed: %s"),
959 strerror(symlink_errno
));
964 #define TIME_T_BITS_IN_FILE 64
966 static zic_t
const min_time
= MINVAL(zic_t
, TIME_T_BITS_IN_FILE
);
967 static zic_t
const max_time
= MAXVAL(zic_t
, TIME_T_BITS_IN_FILE
);
969 /* Return true if NAME is a directory. */
971 itsdir(char const *name
)
974 int res
= stat(name
, &st
);
977 return S_ISDIR(st
.st_mode
) != 0;
979 if (res
== 0 || errno
== EOVERFLOW
) {
980 size_t n
= strlen(name
);
981 char *nameslashdot
= emalloc(n
+ 3);
983 memcpy(nameslashdot
, name
, n
);
984 strcpy(&nameslashdot
[n
], &"/."[! (n
&& name
[n
- 1] != '/')]);
985 dir
= stat(nameslashdot
, &st
) == 0 || errno
== EOVERFLOW
;
992 /* Return true if NAME is a symbolic link. */
994 itssymlink(char const *name
)
997 return 0 <= readlink(name
, &c
, 1);
1001 ** Associate sets of rules with zones.
1005 ** Sort by rule name.
1009 rcomp(const void *cp1
, const void *cp2
)
1011 return strcmp(((const struct rule
*) cp1
)->r_name
,
1012 ((const struct rule
*) cp2
)->r_name
);
1018 register struct zone
* zp
;
1019 register struct rule
* rp
;
1020 register ptrdiff_t i
, j
, base
, out
;
1023 qsort(rules
, nrules
, sizeof *rules
, rcomp
);
1024 for (i
= 0; i
< nrules
- 1; ++i
) {
1025 if (strcmp(rules
[i
].r_name
,
1026 rules
[i
+ 1].r_name
) != 0)
1028 if (strcmp(rules
[i
].r_filename
,
1029 rules
[i
+ 1].r_filename
) == 0)
1031 eat(rules
[i
].r_filename
, rules
[i
].r_linenum
);
1032 warning(_("same rule name in multiple files"));
1033 eat(rules
[i
+ 1].r_filename
, rules
[i
+ 1].r_linenum
);
1034 warning(_("same rule name in multiple files"));
1035 for (j
= i
+ 2; j
< nrules
; ++j
) {
1036 if (strcmp(rules
[i
].r_name
,
1037 rules
[j
].r_name
) != 0)
1039 if (strcmp(rules
[i
].r_filename
,
1040 rules
[j
].r_filename
) == 0)
1042 if (strcmp(rules
[i
+ 1].r_filename
,
1043 rules
[j
].r_filename
) == 0)
1050 for (i
= 0; i
< nzones
; ++i
) {
1055 for (base
= 0; base
< nrules
; base
= out
) {
1057 for (out
= base
+ 1; out
< nrules
; ++out
)
1058 if (strcmp(rp
->r_name
, rules
[out
].r_name
) != 0)
1060 for (i
= 0; i
< nzones
; ++i
) {
1062 if (strcmp(zp
->z_rule
, rp
->r_name
) != 0)
1065 zp
->z_nrules
= out
- base
;
1068 for (i
= 0; i
< nzones
; ++i
) {
1070 if (zp
->z_nrules
== 0) {
1072 ** Maybe we have a local standard time offset.
1074 eat(zp
->z_filename
, zp
->z_linenum
);
1075 zp
->z_stdoff
= getstdoff(zp
->z_rule
, &zp
->z_isdst
);
1077 ** Note, though, that if there's no rule,
1078 ** a '%s' in the format is a bad thing.
1080 if (zp
->z_format_specifier
== 's')
1081 error("%s", _("%s in ruleless zone"));
1089 infile(const char *name
)
1092 register char ** fields
;
1094 register const struct lookup
* lp
;
1095 register int nfields
;
1096 register bool wantcont
;
1097 register lineno num
;
1100 if (strcmp(name
, "-") == 0) {
1101 name
= _("standard input");
1103 } else if ((fp
= fopen(name
, "r")) == NULL
) {
1104 const char *e
= strerror(errno
);
1106 fprintf(stderr
, _("%s: Can't open %s: %s\n"),
1111 for (num
= 1; ; ++num
) {
1113 if (fgets(buf
, sizeof buf
, fp
) != buf
)
1115 cp
= strchr(buf
, '\n');
1117 error(_("line too long"));
1121 fields
= getfields(buf
);
1123 while (fields
[nfields
] != NULL
) {
1126 if (strcmp(fields
[nfields
], "-") == 0)
1127 fields
[nfields
] = &nada
;
1132 } else if (wantcont
) {
1133 wantcont
= inzcont(fields
, nfields
);
1135 struct lookup
const *line_codes
1136 = name
== leapsec
? leap_line_codes
: zi_line_codes
;
1137 lp
= byword(fields
[0], line_codes
);
1139 error(_("input line of unknown type"));
1140 else switch (lp
->l_value
) {
1142 inrule(fields
, nfields
);
1146 wantcont
= inzone(fields
, nfields
);
1149 inlink(fields
, nfields
);
1153 inleap(fields
, nfields
);
1156 default: /* "cannot happen" */
1158 _("%s: panic: Invalid l_value %d\n"),
1159 progname
, lp
->l_value
);
1165 close_file(fp
, NULL
, filename
);
1167 error(_("expected continuation line not found"));
1171 ** Convert a string of one of the forms
1172 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1173 ** into a number of seconds.
1174 ** A null string maps to zero.
1175 ** Call error with errstring and return zero on errors.
1179 gethms(char const *string
, char const *errstring
)
1182 int sign
, mm
= 0, ss
= 0;
1183 char hhx
, mmx
, ssx
, xr
= '0', xs
;
1187 if (string
== NULL
|| *string
== '\0')
1189 if (*string
== '-') {
1193 switch (sscanf(string
,
1194 "%"SCNdZIC
"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
1195 &hh
, &hhx
, &mm
, &mmx
, &ss
, &ssx
, &tenths
, &xr
, &xs
)) {
1196 default: ok
= false; break;
1198 ok
= '0' <= xr
&& xr
<= '9';
1203 warning(_("fractional seconds rejected by"
1204 " pre-2018 versions of zic"));
1206 case 5: ok
&= mmx
== ':'; /* fallthrough */
1207 case 3: ok
&= hhx
== ':'; /* fallthrough */
1211 error("%s", errstring
);
1215 mm
< 0 || mm
>= MINSPERHOUR
||
1216 ss
< 0 || ss
> SECSPERMIN
) {
1217 error("%s", errstring
);
1220 if (ZIC_MAX
/ SECSPERHOUR
< hh
) {
1221 error(_("time overflow"));
1224 ss
+= 5 + ((ss
^ 1) & (xr
== '0')) <= tenths
; /* Round to even. */
1225 if (noise
&& (hh
> HOURSPERDAY
||
1226 (hh
== HOURSPERDAY
&& (mm
!= 0 || ss
!= 0))))
1227 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1228 return oadd(sign
* hh
* SECSPERHOUR
,
1229 sign
* (mm
* SECSPERMIN
+ ss
));
1233 getstdoff(char *field
, bool *isdst
)
1237 size_t fieldlen
= strlen(field
);
1238 if (fieldlen
!= 0) {
1239 char *ep
= field
+ fieldlen
- 1;
1241 case 'd': dst
= 1; *ep
= '\0'; break;
1242 case 's': dst
= 0; *ep
= '\0'; break;
1245 stdoff
= gethms(field
, _("invalid saved time"));
1246 *isdst
= dst
< 0 ? stdoff
!= 0 : dst
;
1251 inrule(char **fields
, int nfields
)
1253 static struct rule r
;
1255 if (nfields
!= RULE_FIELDS
) {
1256 error(_("wrong number of fields on Rule line"));
1259 switch (*fields
[RF_NAME
]) {
1261 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
1263 case '0': case '1': case '2': case '3': case '4':
1264 case '5': case '6': case '7': case '8': case '9':
1265 error(_("Invalid rule name \"%s\""), fields
[RF_NAME
]);
1268 r
.r_filename
= filename
;
1269 r
.r_linenum
= linenum
;
1270 r
.r_stdoff
= getstdoff(fields
[RF_STDOFF
], &r
.r_isdst
);
1271 rulesub(&r
, fields
[RF_LOYEAR
], fields
[RF_HIYEAR
], fields
[RF_COMMAND
],
1272 fields
[RF_MONTH
], fields
[RF_DAY
], fields
[RF_TOD
]);
1273 r
.r_name
= ecpyalloc(fields
[RF_NAME
]);
1274 r
.r_abbrvar
= ecpyalloc(fields
[RF_ABBRVAR
]);
1275 if (max_abbrvar_len
< strlen(r
.r_abbrvar
))
1276 max_abbrvar_len
= strlen(r
.r_abbrvar
);
1277 rules
= growalloc(rules
, sizeof *rules
, nrules
, &nrules_alloc
);
1278 rules
[nrules
++] = r
;
1282 inzone(char **fields
, int nfields
)
1284 register ptrdiff_t i
;
1286 if (nfields
< ZONE_MINFIELDS
|| nfields
> ZONE_MAXFIELDS
) {
1287 error(_("wrong number of fields on Zone line"));
1290 if (lcltime
!= NULL
&& strcmp(fields
[ZF_NAME
], tzdefault
) == 0) {
1292 _("\"Zone %s\" line and -l option are mutually exclusive"),
1296 if (strcmp(fields
[ZF_NAME
], TZDEFRULES
) == 0 && psxrules
!= NULL
) {
1298 _("\"Zone %s\" line and -p option are mutually exclusive"),
1302 for (i
= 0; i
< nzones
; ++i
)
1303 if (zones
[i
].z_name
!= NULL
&&
1304 strcmp(zones
[i
].z_name
, fields
[ZF_NAME
]) == 0) {
1305 error(_("duplicate zone name %s"
1306 " (file \"%s\", line %"PRIdMAX
")"),
1308 zones
[i
].z_filename
,
1309 zones
[i
].z_linenum
);
1312 return inzsub(fields
, nfields
, false);
1316 inzcont(char **fields
, int nfields
)
1318 if (nfields
< ZONEC_MINFIELDS
|| nfields
> ZONEC_MAXFIELDS
) {
1319 error(_("wrong number of fields on Zone continuation line"));
1322 return inzsub(fields
, nfields
, true);
1326 inzsub(char **fields
, int nfields
, bool iscont
)
1330 static struct zone z
;
1331 register int i_gmtoff
, i_rule
, i_format
;
1332 register int i_untilyear
, i_untilmonth
;
1333 register int i_untilday
, i_untiltime
;
1334 register bool hasuntil
;
1337 i_gmtoff
= ZFC_GMTOFF
;
1339 i_format
= ZFC_FORMAT
;
1340 i_untilyear
= ZFC_TILYEAR
;
1341 i_untilmonth
= ZFC_TILMONTH
;
1342 i_untilday
= ZFC_TILDAY
;
1343 i_untiltime
= ZFC_TILTIME
;
1345 } else if (!namecheck(fields
[ZF_NAME
]))
1348 i_gmtoff
= ZF_GMTOFF
;
1350 i_format
= ZF_FORMAT
;
1351 i_untilyear
= ZF_TILYEAR
;
1352 i_untilmonth
= ZF_TILMONTH
;
1353 i_untilday
= ZF_TILDAY
;
1354 i_untiltime
= ZF_TILTIME
;
1355 z
.z_name
= ecpyalloc(fields
[ZF_NAME
]);
1357 z
.z_filename
= filename
;
1358 z
.z_linenum
= linenum
;
1359 z
.z_gmtoff
= gethms(fields
[i_gmtoff
], _("invalid UT offset"));
1360 if ((cp
= strchr(fields
[i_format
], '%')) != 0) {
1361 if ((*++cp
!= 's' && *cp
!= 'z') || strchr(cp
, '%')
1362 || strchr(fields
[i_format
], '/')) {
1363 error(_("invalid abbreviation format"));
1367 z
.z_rule
= ecpyalloc(fields
[i_rule
]);
1368 z
.z_format
= cp1
= ecpyalloc(fields
[i_format
]);
1369 z
.z_format_specifier
= cp
? *cp
: '\0';
1370 if (z
.z_format_specifier
== 'z') {
1372 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1374 cp1
[cp
- fields
[i_format
]] = 's';
1376 if (max_format_len
< strlen(z
.z_format
))
1377 max_format_len
= strlen(z
.z_format
);
1378 hasuntil
= nfields
> i_untilyear
;
1380 z
.z_untilrule
.r_filename
= filename
;
1381 z
.z_untilrule
.r_linenum
= linenum
;
1382 rulesub(&z
.z_untilrule
,
1383 fields
[i_untilyear
],
1386 (nfields
> i_untilmonth
) ?
1387 fields
[i_untilmonth
] : "Jan",
1388 (nfields
> i_untilday
) ? fields
[i_untilday
] : "1",
1389 (nfields
> i_untiltime
) ? fields
[i_untiltime
] : "0");
1390 z
.z_untiltime
= rpytime(&z
.z_untilrule
,
1391 z
.z_untilrule
.r_loyear
);
1392 if (iscont
&& nzones
> 0 &&
1393 z
.z_untiltime
> min_time
&&
1394 z
.z_untiltime
< max_time
&&
1395 zones
[nzones
- 1].z_untiltime
> min_time
&&
1396 zones
[nzones
- 1].z_untiltime
< max_time
&&
1397 zones
[nzones
- 1].z_untiltime
>= z
.z_untiltime
) {
1399 "Zone continuation line end time is not after end time of previous line"
1404 zones
= growalloc(zones
, sizeof *zones
, nzones
, &nzones_alloc
);
1405 zones
[nzones
++] = z
;
1407 ** If there was an UNTIL field on this line,
1408 ** there's more information about the zone on the next line.
1414 inleap(char **fields
, int nfields
)
1416 register const char * cp
;
1417 register const struct lookup
* lp
;
1418 register zic_t i
, j
;
1425 if (nfields
!= LEAP_FIELDS
) {
1426 error(_("wrong number of fields on Leap line"));
1430 cp
= fields
[LP_YEAR
];
1431 if (sscanf(cp
, "%"SCNdZIC
"%c", &year
, &xs
) != 1) {
1435 error(_("invalid leaping year"));
1438 if (!leapseen
|| leapmaxyear
< year
)
1440 if (!leapseen
|| leapminyear
> year
)
1446 i
= len_years
[isleap(j
)];
1450 i
= -len_years
[isleap(j
)];
1452 dayoff
= oadd(dayoff
, i
);
1454 if ((lp
= byword(fields
[LP_MONTH
], mon_names
)) == NULL
) {
1455 error(_("invalid month name"));
1458 month
= lp
->l_value
;
1460 while (j
!= month
) {
1461 i
= len_months
[isleap(year
)][j
];
1462 dayoff
= oadd(dayoff
, i
);
1465 cp
= fields
[LP_DAY
];
1466 if (sscanf(cp
, "%d%c", &day
, &xs
) != 1 ||
1467 day
<= 0 || day
> len_months
[isleap(year
)][month
]) {
1468 error(_("invalid day of month"));
1471 dayoff
= oadd(dayoff
, day
- 1);
1472 if (dayoff
< min_time
/ SECSPERDAY
) {
1473 error(_("time too small"));
1476 if (dayoff
> max_time
/ SECSPERDAY
) {
1477 error(_("time too large"));
1480 t
= dayoff
* SECSPERDAY
;
1481 tod
= gethms(fields
[LP_TIME
], _("invalid time of day"));
1482 cp
= fields
[LP_CORR
];
1484 register bool positive
;
1487 if (strcmp(cp
, "") == 0) { /* infile() turns "-" into "" */
1490 } else if (strcmp(cp
, "+") == 0) {
1494 error(_("illegal CORRECTION field on Leap line"));
1497 if ((lp
= byword(fields
[LP_ROLL
], leap_types
)) == NULL
) {
1499 "illegal Rolling/Stationary field on Leap line"
1505 error(_("leap second precedes Epoch"));
1508 leapadd(t
, positive
, lp
->l_value
, count
);
1513 inlink(char **fields
, int nfields
)
1517 if (nfields
!= LINK_FIELDS
) {
1518 error(_("wrong number of fields on Link line"));
1521 if (*fields
[LF_FROM
] == '\0') {
1522 error(_("blank FROM field on Link line"));
1525 if (! namecheck(fields
[LF_TO
]))
1527 l
.l_filename
= filename
;
1528 l
.l_linenum
= linenum
;
1529 l
.l_from
= ecpyalloc(fields
[LF_FROM
]);
1530 l
.l_to
= ecpyalloc(fields
[LF_TO
]);
1531 links
= growalloc(links
, sizeof *links
, nlinks
, &nlinks_alloc
);
1532 links
[nlinks
++] = l
;
1536 rulesub(struct rule
*rp
, const char *loyearp
, const char *hiyearp
,
1537 const char *typep
, const char *monthp
, const char *dayp
,
1540 register const struct lookup
* lp
;
1541 register const char * cp
;
1546 if ((lp
= byword(monthp
, mon_names
)) == NULL
) {
1547 error(_("invalid month name"));
1550 rp
->r_month
= lp
->l_value
;
1551 rp
->r_todisstd
= false;
1552 rp
->r_todisgmt
= false;
1553 dp
= ecpyalloc(timep
);
1555 ep
= dp
+ strlen(dp
) - 1;
1556 switch (lowerit(*ep
)) {
1557 case 's': /* Standard */
1558 rp
->r_todisstd
= true;
1559 rp
->r_todisgmt
= false;
1562 case 'w': /* Wall */
1563 rp
->r_todisstd
= false;
1564 rp
->r_todisgmt
= false;
1567 case 'g': /* Greenwich */
1568 case 'u': /* Universal */
1569 case 'z': /* Zulu */
1570 rp
->r_todisstd
= true;
1571 rp
->r_todisgmt
= true;
1576 rp
->r_tod
= gethms(dp
, _("invalid time of day"));
1582 lp
= byword(cp
, begin_years
);
1583 rp
->r_lowasnum
= lp
== NULL
;
1584 if (!rp
->r_lowasnum
) switch (lp
->l_value
) {
1586 rp
->r_loyear
= ZIC_MIN
;
1589 rp
->r_loyear
= ZIC_MAX
;
1591 default: /* "cannot happen" */
1593 _("%s: panic: Invalid l_value %d\n"),
1594 progname
, lp
->l_value
);
1596 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_loyear
, &xs
) != 1) {
1597 error(_("invalid starting year"));
1601 lp
= byword(cp
, end_years
);
1602 rp
->r_hiwasnum
= lp
== NULL
;
1603 if (!rp
->r_hiwasnum
) switch (lp
->l_value
) {
1605 rp
->r_hiyear
= ZIC_MIN
;
1608 rp
->r_hiyear
= ZIC_MAX
;
1611 rp
->r_hiyear
= rp
->r_loyear
;
1613 default: /* "cannot happen" */
1615 _("%s: panic: Invalid l_value %d\n"),
1616 progname
, lp
->l_value
);
1618 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_hiyear
, &xs
) != 1) {
1619 error(_("invalid ending year"));
1622 if (rp
->r_loyear
> rp
->r_hiyear
) {
1623 error(_("starting year greater than ending year"));
1627 rp
->r_yrtype
= NULL
;
1629 if (rp
->r_loyear
== rp
->r_hiyear
) {
1630 error(_("typed single year"));
1633 warning(_("year type \"%s\" is obsolete; use \"-\" instead"),
1635 rp
->r_yrtype
= ecpyalloc(typep
);
1639 ** Accept things such as:
1642 ** last-Sunday (undocumented; warn about this)
1646 dp
= ecpyalloc(dayp
);
1647 if ((lp
= byword(dp
, lasts
)) != NULL
) {
1648 rp
->r_dycode
= DC_DOWLEQ
;
1649 rp
->r_wday
= lp
->l_value
;
1650 rp
->r_dayofmonth
= len_months
[1][rp
->r_month
];
1652 if ((ep
= strchr(dp
, '<')) != 0)
1653 rp
->r_dycode
= DC_DOWLEQ
;
1654 else if ((ep
= strchr(dp
, '>')) != 0)
1655 rp
->r_dycode
= DC_DOWGEQ
;
1658 rp
->r_dycode
= DC_DOM
;
1660 if (rp
->r_dycode
!= DC_DOM
) {
1663 error(_("invalid day of month"));
1667 if ((lp
= byword(dp
, wday_names
)) == NULL
) {
1668 error(_("invalid weekday name"));
1672 rp
->r_wday
= lp
->l_value
;
1674 if (sscanf(ep
, "%d%c", &rp
->r_dayofmonth
, &xs
) != 1 ||
1675 rp
->r_dayofmonth
<= 0 ||
1676 (rp
->r_dayofmonth
> len_months
[1][rp
->r_month
])) {
1677 error(_("invalid day of month"));
1686 convert(const int_fast32_t val
, char *const buf
)
1690 unsigned char *const b
= (unsigned char *) buf
;
1692 for (i
= 0, shift
= 24; i
< 4; ++i
, shift
-= 8)
1693 b
[i
] = val
>> shift
;
1697 convert64(const zic_t val
, char *const buf
)
1701 unsigned char *const b
= (unsigned char *) buf
;
1703 for (i
= 0, shift
= 56; i
< 8; ++i
, shift
-= 8)
1704 b
[i
] = val
>> shift
;
1708 puttzcode(const int_fast32_t val
, FILE *const fp
)
1713 fwrite(buf
, sizeof buf
, 1, fp
);
1717 puttzcode64(const zic_t val
, FILE *const fp
)
1721 convert64(val
, buf
);
1722 fwrite(buf
, sizeof buf
, 1, fp
);
1726 atcomp(const void *avp
, const void *bvp
)
1728 const zic_t a
= ((const struct attype
*) avp
)->at
;
1729 const zic_t b
= ((const struct attype
*) bvp
)->at
;
1731 return (a
< b
) ? -1 : (a
> b
);
1735 swaptypes(int i
, int j
)
1737 { zic_t t
= gmtoffs
[i
]; gmtoffs
[i
] = gmtoffs
[j
]; gmtoffs
[j
] = t
; }
1738 { char t
= isdsts
[i
]; isdsts
[i
] = isdsts
[j
]; isdsts
[j
] = t
; }
1739 { unsigned char t
= abbrinds
[i
]; abbrinds
[i
] = abbrinds
[j
];
1741 { bool t
= ttisstds
[i
]; ttisstds
[i
] = ttisstds
[j
]; ttisstds
[j
] = t
; }
1742 { bool t
= ttisgmts
[i
]; ttisgmts
[i
] = ttisgmts
[j
]; ttisgmts
[j
] = t
; }
1746 writezone(const char *const name
, const char *const string
, char version
,
1750 register ptrdiff_t i
, j
;
1751 register int leapcnt32
, leapi32
;
1752 register ptrdiff_t timecnt32
, timei32
;
1754 static const struct tzhead tzh0
;
1755 static struct tzhead tzh
;
1756 bool dir_checked
= false;
1758 zic_t y2038_boundary
= one
<< 31;
1759 ptrdiff_t nats
= timecnt
+ WORK_AROUND_QTBUG_53071
;
1761 /* Allocate the ATS and TYPES arrays via a single malloc,
1762 as this is a bit faster. */
1763 zic_t
*ats
= emalloc(align_to(size_product(nats
, sizeof *ats
+ 1),
1765 void *typesptr
= ats
+ nats
;
1766 unsigned char *types
= typesptr
;
1772 qsort(attypes
, timecnt
, sizeof *attypes
, atcomp
);
1777 ptrdiff_t fromi
, toi
;
1781 for ( ; fromi
< timecnt
; ++fromi
) {
1782 if (toi
!= 0 && ((attypes
[fromi
].at
+
1783 gmtoffs
[attypes
[toi
- 1].type
]) <=
1784 (attypes
[toi
- 1].at
+ gmtoffs
[toi
== 1 ? 0
1785 : attypes
[toi
- 2].type
]))) {
1786 attypes
[toi
- 1].type
=
1787 attypes
[fromi
].type
;
1791 || attypes
[fromi
].dontmerge
1792 || attypes
[toi
- 1].type
!= attypes
[fromi
].type
)
1793 attypes
[toi
++] = attypes
[fromi
];
1798 if (noise
&& timecnt
> 1200) {
1799 if (timecnt
> TZ_MAX_TIMES
)
1800 warning(_("reference clients mishandle"
1801 " more than %d transition times"),
1804 warning(_("pre-2014 clients may mishandle"
1805 " more than 1200 transition times"));
1810 for (i
= 0; i
< timecnt
; ++i
) {
1811 ats
[i
] = attypes
[i
].at
;
1812 types
[i
] = attypes
[i
].type
;
1816 ** Correct for leap seconds.
1818 for (i
= 0; i
< timecnt
; ++i
) {
1821 if (ats
[i
] > trans
[j
] - corr
[j
]) {
1822 ats
[i
] = tadd(ats
[i
], corr
[j
]);
1827 /* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1,
1828 by inserting a no-op transition at time y2038_boundary - 1.
1829 This works only for timestamps before the boundary, which
1830 should be good enough in practice as QTBUG-53071 should be
1831 long-dead by 2038. Do this after correcting for leap
1832 seconds, as the idea is to insert a transition just before
1833 32-bit time_t rolls around, and this occurs at a slightly
1834 different moment if transitions are leap-second corrected. */
1835 if (WORK_AROUND_QTBUG_53071
&& timecnt
!= 0
1836 && ats
[timecnt
- 1] < y2038_boundary
- 1 && strchr(string
, '<')) {
1837 ats
[timecnt
] = y2038_boundary
- 1;
1838 types
[timecnt
] = types
[timecnt
- 1];
1843 ** Figure out 32-bit-limited starts and counts.
1845 timecnt32
= timecnt
;
1847 leapcnt32
= leapcnt
;
1849 while (0 < timecnt32
&& INT32_MAX
< ats
[timecnt32
- 1])
1851 while (1 < timecnt32
&& ats
[timei32
] < INT32_MIN
1852 && ats
[timei32
+ 1] <= INT32_MIN
) {
1853 /* Discard too-low transitions, except keep any last too-low
1854 transition if no transition is exactly at INT32_MIN.
1855 The kept transition will be output as an INT32_MIN
1856 "transition" appropriate for buggy 32-bit clients that do
1857 not use time type 0 for timestamps before the first
1858 transition; see below. */
1862 while (0 < leapcnt32
&& INT32_MAX
< trans
[leapcnt32
- 1])
1864 while (0 < leapcnt32
&& trans
[leapi32
] < INT32_MIN
) {
1869 ** Remove old file, if any, to snap links.
1871 if (remove(name
) == 0)
1873 else if (errno
!= ENOENT
) {
1874 const char *e
= strerror(errno
);
1876 fprintf(stderr
, _("%s: Can't remove %s/%s: %s\n"),
1877 progname
, directory
, name
, e
);
1880 fp
= fopen(name
, "wb");
1882 int fopen_errno
= errno
;
1883 if (fopen_errno
== ENOENT
&& !dir_checked
) {
1885 fp
= fopen(name
, "wb");
1886 fopen_errno
= errno
;
1889 fprintf(stderr
, _("%s: Can't create %s/%s: %s\n"),
1890 progname
, directory
, name
, strerror(fopen_errno
));
1894 for (pass
= 1; pass
<= 2; ++pass
) {
1895 register ptrdiff_t thistimei
, thistimecnt
, thistimelim
;
1896 register int thisleapi
, thisleapcnt
, thisleaplim
;
1898 char omittype
[TZ_MAX_TYPES
];
1899 int typemap
[TZ_MAX_TYPES
];
1900 register int thistypecnt
;
1901 char thischars
[TZ_MAX_CHARS
];
1904 int indmap
[TZ_MAX_CHARS
];
1907 thistimei
= timei32
;
1908 thistimecnt
= timecnt32
;
1909 toomanytimes
= thistimecnt
>> 31 >> 1 != 0;
1910 thisleapi
= leapi32
;
1911 thisleapcnt
= leapcnt32
;
1914 thistimecnt
= timecnt
;
1915 toomanytimes
= thistimecnt
>> 31 >> 31 >> 2 != 0;
1917 thisleapcnt
= leapcnt
;
1920 error(_("too many transition times"));
1921 thistimelim
= thistimei
+ thistimecnt
;
1922 thisleaplim
= thisleapi
+ thisleapcnt
;
1923 memset(omittype
, true, typecnt
);
1924 omittype
[defaulttype
] = false;
1925 for (i
= thistimei
; i
< thistimelim
; i
++)
1926 omittype
[types
[i
]] = false;
1928 /* Reorder types to make DEFAULTTYPE type 0.
1929 Use TYPEMAP to swap OLD0 and DEFAULTTYPE so that
1930 DEFAULTTYPE appears as type 0 in the output instead
1931 of OLD0. TYPEMAP also omits unused types. */
1932 old0
= strlen(omittype
);
1933 swaptypes(old0
, defaulttype
);
1935 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1937 ** For some pre-2011 systems: if the last-to-be-written
1938 ** standard (or daylight) type has an offset different from the
1939 ** most recently used offset,
1940 ** append an (unused) copy of the most recently used type
1941 ** (to help get global "altzone" and "timezone" variables
1945 register int mrudst
, mrustd
, hidst
, histd
, type
;
1947 hidst
= histd
= mrudst
= mrustd
= -1;
1948 for (i
= thistimei
; i
< thistimelim
; ++i
)
1949 if (isdsts
[types
[i
]])
1951 else mrustd
= types
[i
];
1952 for (i
= old0
; i
< typecnt
; i
++)
1958 if (hidst
>= 0 && mrudst
>= 0 && hidst
!= mrudst
&&
1959 gmtoffs
[hidst
] != gmtoffs
[mrudst
]) {
1960 isdsts
[mrudst
] = -1;
1961 type
= addtype(gmtoffs
[mrudst
],
1962 &chars
[abbrinds
[mrudst
]],
1967 omittype
[type
] = false;
1969 if (histd
>= 0 && mrustd
>= 0 && histd
!= mrustd
&&
1970 gmtoffs
[histd
] != gmtoffs
[mrustd
]) {
1971 isdsts
[mrustd
] = -1;
1972 type
= addtype(gmtoffs
[mrustd
],
1973 &chars
[abbrinds
[mrustd
]],
1978 omittype
[type
] = false;
1981 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1983 for (i
= old0
; i
< typecnt
; i
++)
1985 typemap
[i
== old0
? defaulttype
1986 : i
== defaulttype
? old0
: i
]
1989 for (i
= 0; i
< sizeof indmap
/ sizeof indmap
[0]; ++i
)
1992 for (i
= old0
; i
< typecnt
; i
++) {
1993 register char * thisabbr
;
1997 if (indmap
[abbrinds
[i
]] >= 0)
1999 thisabbr
= &chars
[abbrinds
[i
]];
2000 for (j
= 0; j
< thischarcnt
; ++j
)
2001 if (strcmp(&thischars
[j
], thisabbr
) == 0)
2003 if (j
== thischarcnt
) {
2004 strcpy(&thischars
[thischarcnt
], thisabbr
);
2005 thischarcnt
+= strlen(thisabbr
) + 1;
2007 indmap
[abbrinds
[i
]] = j
;
2009 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
2011 memcpy(tzh
.tzh_magic
, TZ_MAGIC
, sizeof tzh
.tzh_magic
);
2012 tzh
.tzh_version
[0] = version
;
2013 convert(thistypecnt
, tzh
.tzh_ttisgmtcnt
);
2014 convert(thistypecnt
, tzh
.tzh_ttisstdcnt
);
2015 convert(thisleapcnt
, tzh
.tzh_leapcnt
);
2016 convert(thistimecnt
, tzh
.tzh_timecnt
);
2017 convert(thistypecnt
, tzh
.tzh_typecnt
);
2018 convert(thischarcnt
, tzh
.tzh_charcnt
);
2029 for (i
= thistimei
; i
< thistimelim
; ++i
)
2032 ** Output an INT32_MIN "transition"
2033 ** if appropriate; see above.
2035 puttzcode(((ats
[i
] < INT32_MIN
) ?
2036 INT32_MIN
: ats
[i
]), fp
);
2037 else puttzcode64(ats
[i
], fp
);
2038 for (i
= thistimei
; i
< thistimelim
; ++i
) {
2041 uc
= typemap
[types
[i
]];
2042 fwrite(&uc
, sizeof uc
, 1, fp
);
2044 for (i
= old0
; i
< typecnt
; i
++)
2046 puttzcode(gmtoffs
[i
], fp
);
2047 putc(isdsts
[i
], fp
);
2048 putc((unsigned char) indmap
[abbrinds
[i
]], fp
);
2050 if (thischarcnt
!= 0)
2051 fwrite(thischars
, sizeof thischars
[0],
2053 for (i
= thisleapi
; i
< thisleaplim
; ++i
) {
2054 register zic_t todo
;
2057 if (timecnt
== 0 || trans
[i
] < ats
[0]) {
2060 if (++j
>= typecnt
) {
2066 while (j
< timecnt
&&
2071 todo
= tadd(trans
[i
], -gmtoffs
[j
]);
2072 } else todo
= trans
[i
];
2074 puttzcode(todo
, fp
);
2075 else puttzcode64(todo
, fp
);
2076 puttzcode(corr
[i
], fp
);
2078 for (i
= old0
; i
< typecnt
; i
++)
2080 putc(ttisstds
[i
], fp
);
2081 for (i
= old0
; i
< typecnt
; i
++)
2083 putc(ttisgmts
[i
], fp
);
2084 swaptypes(old0
, defaulttype
);
2086 fprintf(fp
, "\n%s\n", string
);
2087 close_file(fp
, directory
, name
);
2092 abbroffset(char *buf
, zic_t offset
)
2095 int seconds
, minutes
;
2102 seconds
= offset
% SECSPERMIN
;
2103 offset
/= SECSPERMIN
;
2104 minutes
= offset
% MINSPERHOUR
;
2105 offset
/= MINSPERHOUR
;
2106 if (100 <= offset
) {
2107 error(_("%%z UT offset magnitude exceeds 99:59:59"));
2112 *p
++ = '0' + offset
/ 10;
2113 *p
++ = '0' + offset
% 10;
2114 if (minutes
| seconds
) {
2115 *p
++ = '0' + minutes
/ 10;
2116 *p
++ = '0' + minutes
% 10;
2118 *p
++ = '0' + seconds
/ 10;
2119 *p
++ = '0' + seconds
% 10;
2128 doabbr(char *abbr
, struct zone
const *zp
, char const *letters
,
2129 bool isdst
, zic_t stdoff
, bool doquotes
)
2132 register char * slashp
;
2133 register size_t len
;
2134 char const *format
= zp
->z_format
;
2136 slashp
= strchr(format
, '/');
2137 if (slashp
== NULL
) {
2138 char letterbuf
[PERCENT_Z_LEN_BOUND
+ 1];
2139 if (zp
->z_format_specifier
== 'z')
2140 letters
= abbroffset(letterbuf
, zp
->z_gmtoff
+ stdoff
);
2143 sprintf(abbr
, format
, letters
);
2145 strcpy(abbr
, slashp
+ 1);
2147 memcpy(abbr
, format
, slashp
- format
);
2148 abbr
[slashp
- format
] = '\0';
2153 for (cp
= abbr
; is_alpha(*cp
); cp
++)
2155 if (len
> 0 && *cp
== '\0')
2157 abbr
[len
+ 2] = '\0';
2158 abbr
[len
+ 1] = '>';
2159 memmove(abbr
+ 1, abbr
, len
);
2165 updateminmax(const zic_t x
)
2174 stringoffset(char *result
, zic_t offset
)
2177 register int minutes
;
2178 register int seconds
;
2179 bool negative
= offset
< 0;
2186 seconds
= offset
% SECSPERMIN
;
2187 offset
/= SECSPERMIN
;
2188 minutes
= offset
% MINSPERHOUR
;
2189 offset
/= MINSPERHOUR
;
2191 if (hours
>= HOURSPERDAY
* DAYSPERWEEK
) {
2195 len
+= sprintf(result
+ len
, "%d", hours
);
2196 if (minutes
!= 0 || seconds
!= 0) {
2197 len
+= sprintf(result
+ len
, ":%02d", minutes
);
2199 len
+= sprintf(result
+ len
, ":%02d", seconds
);
2205 stringrule(char *result
, const struct rule
*const rp
, const zic_t dstoff
,
2208 register zic_t tod
= rp
->r_tod
;
2209 register int compat
= 0;
2211 if (rp
->r_dycode
== DC_DOM
) {
2212 register int month
, total
;
2214 if (rp
->r_dayofmonth
== 29 && rp
->r_month
== TM_FEBRUARY
)
2217 for (month
= 0; month
< rp
->r_month
; ++month
)
2218 total
+= len_months
[0][month
];
2219 /* Omit the "J" in Jan and Feb, as that's shorter. */
2220 if (rp
->r_month
<= 1)
2221 result
+= sprintf(result
, "%d", total
+ rp
->r_dayofmonth
- 1);
2223 result
+= sprintf(result
, "J%d", total
+ rp
->r_dayofmonth
);
2226 register int wday
= rp
->r_wday
;
2227 register int wdayoff
;
2229 if (rp
->r_dycode
== DC_DOWGEQ
) {
2230 wdayoff
= (rp
->r_dayofmonth
- 1) % DAYSPERWEEK
;
2234 tod
+= wdayoff
* SECSPERDAY
;
2235 week
= 1 + (rp
->r_dayofmonth
- 1) / DAYSPERWEEK
;
2236 } else if (rp
->r_dycode
== DC_DOWLEQ
) {
2237 if (rp
->r_dayofmonth
== len_months
[1][rp
->r_month
])
2240 wdayoff
= rp
->r_dayofmonth
% DAYSPERWEEK
;
2244 tod
+= wdayoff
* SECSPERDAY
;
2245 week
= rp
->r_dayofmonth
/ DAYSPERWEEK
;
2247 } else return -1; /* "cannot happen" */
2249 wday
+= DAYSPERWEEK
;
2250 result
+= sprintf(result
, "M%d.%d.%d",
2251 rp
->r_month
+ 1, week
, wday
);
2255 if (rp
->r_todisstd
&& !rp
->r_isdst
)
2257 if (tod
!= 2 * SECSPERMIN
* MINSPERHOUR
) {
2259 if (! stringoffset(result
, tod
))
2264 } else if (SECSPERDAY
<= tod
) {
2273 rule_cmp(struct rule
const *a
, struct rule
const *b
)
2279 if (a
->r_hiyear
!= b
->r_hiyear
)
2280 return a
->r_hiyear
< b
->r_hiyear
? -1 : 1;
2281 if (a
->r_month
- b
->r_month
!= 0)
2282 return a
->r_month
- b
->r_month
;
2283 return a
->r_dayofmonth
- b
->r_dayofmonth
;
2286 enum { YEAR_BY_YEAR_ZONE
= 1 };
2289 stringzone(char *result
, struct zone
const *zpfirst
, ptrdiff_t zonecount
)
2291 register const struct zone
* zp
;
2292 register struct rule
* rp
;
2293 register struct rule
* stdrp
;
2294 register struct rule
* dstrp
;
2295 register ptrdiff_t i
;
2296 register const char * abbrvar
;
2297 register int compat
= 0;
2301 struct rule stdr
, dstr
;
2304 zp
= zpfirst
+ zonecount
- 1;
2305 stdrp
= dstrp
= NULL
;
2306 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2307 rp
= &zp
->z_rules
[i
];
2308 if (rp
->r_hiwasnum
|| rp
->r_hiyear
!= ZIC_MAX
)
2310 if (rp
->r_yrtype
!= NULL
)
2322 if (stdrp
== NULL
&& dstrp
== NULL
) {
2324 ** There are no rules running through "max".
2325 ** Find the latest std rule in stdabbrrp
2326 ** and latest rule of any type in stdrp.
2328 register struct rule
*stdabbrrp
= NULL
;
2329 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2330 rp
= &zp
->z_rules
[i
];
2331 if (!rp
->r_isdst
&& rule_cmp(stdabbrrp
, rp
) < 0)
2333 if (rule_cmp(stdrp
, rp
) < 0)
2337 ** Horrid special case: if year is 2037,
2338 ** presume this is a zone handled on a year-by-year basis;
2339 ** do not try to apply a rule to the zone.
2341 if (stdrp
!= NULL
&& stdrp
->r_hiyear
== 2037)
2342 return YEAR_BY_YEAR_ZONE
;
2344 if (stdrp
!= NULL
&& stdrp
->r_isdst
) {
2345 /* Perpetual DST. */
2346 dstr
.r_month
= TM_JANUARY
;
2347 dstr
.r_dycode
= DC_DOM
;
2348 dstr
.r_dayofmonth
= 1;
2350 dstr
.r_todisstd
= dstr
.r_todisgmt
= false;
2351 dstr
.r_isdst
= stdrp
->r_isdst
;
2352 dstr
.r_stdoff
= stdrp
->r_stdoff
;
2353 dstr
.r_abbrvar
= stdrp
->r_abbrvar
;
2354 stdr
.r_month
= TM_DECEMBER
;
2355 stdr
.r_dycode
= DC_DOM
;
2356 stdr
.r_dayofmonth
= 31;
2357 stdr
.r_tod
= SECSPERDAY
+ stdrp
->r_stdoff
;
2358 stdr
.r_todisstd
= stdr
.r_todisgmt
= false;
2359 stdr
.r_isdst
= false;
2362 = (stdabbrrp
? stdabbrrp
->r_abbrvar
: "");
2367 if (stdrp
== NULL
&& (zp
->z_nrules
!= 0 || zp
->z_isdst
))
2369 abbrvar
= (stdrp
== NULL
) ? "" : stdrp
->r_abbrvar
;
2370 len
= doabbr(result
, zp
, abbrvar
, false, 0, true);
2371 offsetlen
= stringoffset(result
+ len
, -zp
->z_gmtoff
);
2379 len
+= doabbr(result
+ len
, zp
, dstrp
->r_abbrvar
,
2380 dstrp
->r_isdst
, dstrp
->r_stdoff
, true);
2381 if (dstrp
->r_stdoff
!= SECSPERMIN
* MINSPERHOUR
) {
2382 offsetlen
= stringoffset(result
+ len
,
2383 -(zp
->z_gmtoff
+ dstrp
->r_stdoff
));
2390 result
[len
++] = ',';
2391 c
= stringrule(result
+ len
, dstrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2398 len
+= strlen(result
+ len
);
2399 result
[len
++] = ',';
2400 c
= stringrule(result
+ len
, stdrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2411 outzone(const struct zone
*zpfirst
, ptrdiff_t zonecount
)
2413 register const struct zone
* zp
;
2414 register struct rule
* rp
;
2415 register ptrdiff_t i
, j
;
2416 register bool usestart
, useuntil
;
2417 register zic_t starttime
, untiltime
;
2418 register zic_t gmtoff
;
2419 register zic_t stdoff
;
2420 register zic_t year
;
2421 register zic_t startoff
;
2422 register bool startttisstd
;
2423 register bool startttisgmt
;
2425 register char * startbuf
;
2427 register char * envvar
;
2428 register int max_abbr_len
;
2429 register int max_envvar_len
;
2430 register bool prodstic
; /* all rules are min to max */
2431 register int compat
;
2432 register bool do_extend
;
2433 register char version
;
2434 ptrdiff_t lastatmax
= -1;
2436 zic_t y2038_boundary
= one
<< 31;
2438 int defaulttype
= -1;
2440 max_abbr_len
= 2 + max_format_len
+ max_abbrvar_len
;
2441 max_envvar_len
= 2 * max_abbr_len
+ 5 * 9;
2442 startbuf
= emalloc(max_abbr_len
+ 1);
2443 ab
= emalloc(max_abbr_len
+ 1);
2444 envvar
= emalloc(max_envvar_len
+ 1);
2445 INITIALIZE(untiltime
);
2446 INITIALIZE(starttime
);
2448 ** Now. . .finally. . .generate some useful data!
2453 prodstic
= zonecount
== 1;
2455 ** Thanks to Earl Chew
2456 ** for noting the need to unconditionally initialize startttisstd.
2458 startttisstd
= false;
2459 startttisgmt
= false;
2460 min_year
= max_year
= EPOCH_YEAR
;
2462 updateminmax(leapminyear
);
2463 updateminmax(leapmaxyear
+ (leapmaxyear
< ZIC_MAX
));
2465 for (i
= 0; i
< zonecount
; ++i
) {
2467 if (i
< zonecount
- 1)
2468 updateminmax(zp
->z_untilrule
.r_loyear
);
2469 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2470 rp
= &zp
->z_rules
[j
];
2472 updateminmax(rp
->r_loyear
);
2474 updateminmax(rp
->r_hiyear
);
2475 if (rp
->r_lowasnum
|| rp
->r_hiwasnum
)
2480 ** Generate lots of data if a rule can't cover all future times.
2482 compat
= stringzone(envvar
, zpfirst
, zonecount
);
2483 version
= compat
< 2013 ? ZIC_VERSION_PRE_2013
: ZIC_VERSION
;
2484 do_extend
= compat
< 0 || compat
== YEAR_BY_YEAR_ZONE
;
2488 _("no POSIX environment variable for zone"),
2490 else if (compat
!= 0 && compat
!= YEAR_BY_YEAR_ZONE
) {
2491 /* Circa-COMPAT clients, and earlier clients, might
2492 not work for this zone when given dates before
2493 1970 or after 2038. */
2494 warning(_("%s: pre-%d clients may mishandle"
2495 " distant timestamps"),
2496 zpfirst
->z_name
, compat
);
2501 ** Search through a couple of extra years past the obvious
2502 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2503 ** rule applies from 2012 onwards and has transitions in March
2504 ** and September, plus some one-off transitions in November
2505 ** 2013. If zic looked only at the last 400 years, it would
2506 ** set max_year=2413, with the intent that the 400 years 2014
2507 ** through 2413 will be repeated. The last transition listed
2508 ** in the tzfile would be in 2413-09, less than 400 years
2509 ** after the last one-off transition in 2013-11. Two years
2510 ** might be overkill, but with the kind of edge cases
2511 ** available we're not sure that one year would suffice.
2513 enum { years_of_observations
= YEARSPERREPEAT
+ 2 };
2515 if (min_year
>= ZIC_MIN
+ years_of_observations
)
2516 min_year
-= years_of_observations
;
2517 else min_year
= ZIC_MIN
;
2518 if (max_year
<= ZIC_MAX
- years_of_observations
)
2519 max_year
+= years_of_observations
;
2520 else max_year
= ZIC_MAX
;
2522 ** Regardless of any of the above,
2523 ** for a "proDSTic" zone which specifies that its rules
2524 ** always have and always will be in effect,
2525 ** we only need one cycle to define the zone.
2529 max_year
= min_year
+ years_of_observations
;
2533 ** For the benefit of older systems,
2534 ** generate data from 1900 through 2038.
2536 if (min_year
> 1900)
2538 max_year0
= max_year
;
2539 if (max_year
< 2038)
2541 for (i
= 0; i
< zonecount
; ++i
) {
2543 ** A guess that may well be corrected later.
2547 usestart
= i
> 0 && (zp
- 1)->z_untiltime
> min_time
;
2548 useuntil
= i
< (zonecount
- 1);
2549 if (useuntil
&& zp
->z_untiltime
<= min_time
)
2551 gmtoff
= zp
->z_gmtoff
;
2552 eat(zp
->z_filename
, zp
->z_linenum
);
2554 startoff
= zp
->z_gmtoff
;
2555 if (zp
->z_nrules
== 0) {
2556 stdoff
= zp
->z_stdoff
;
2557 doabbr(startbuf
, zp
, NULL
, zp
->z_isdst
, stdoff
, false);
2558 type
= addtype(oadd(zp
->z_gmtoff
, stdoff
),
2559 startbuf
, zp
->z_isdst
, startttisstd
,
2562 addtt(starttime
, type
);
2566 } else for (year
= min_year
; year
<= max_year
; ++year
) {
2567 if (useuntil
&& year
> zp
->z_untilrule
.r_hiyear
)
2570 ** Mark which rules to do in the current year.
2571 ** For those to do, calculate rpytime(rp, year);
2573 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2574 rp
= &zp
->z_rules
[j
];
2575 eats(zp
->z_filename
, zp
->z_linenum
,
2576 rp
->r_filename
, rp
->r_linenum
);
2577 rp
->r_todo
= year
>= rp
->r_loyear
&&
2578 year
<= rp
->r_hiyear
&&
2579 yearistype(year
, rp
->r_yrtype
);
2581 rp
->r_temp
= rpytime(rp
, year
);
2583 = (rp
->r_temp
< y2038_boundary
2584 || year
<= max_year0
);
2588 register ptrdiff_t k
;
2589 register zic_t jtime
, ktime
;
2590 register zic_t offset
;
2595 ** Turn untiltime into UT
2596 ** assuming the current gmtoff and
2599 untiltime
= zp
->z_untiltime
;
2600 if (!zp
->z_untilrule
.r_todisgmt
)
2601 untiltime
= tadd(untiltime
,
2603 if (!zp
->z_untilrule
.r_todisstd
)
2604 untiltime
= tadd(untiltime
,
2608 ** Find the rule (of those to do, if any)
2609 ** that takes effect earliest in the year.
2612 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2613 rp
= &zp
->z_rules
[j
];
2616 eats(zp
->z_filename
, zp
->z_linenum
,
2617 rp
->r_filename
, rp
->r_linenum
);
2618 offset
= rp
->r_todisgmt
? 0 : gmtoff
;
2619 if (!rp
->r_todisstd
)
2620 offset
= oadd(offset
, stdoff
);
2622 if (jtime
== min_time
||
2625 jtime
= tadd(jtime
, -offset
);
2626 if (k
< 0 || jtime
< ktime
) {
2629 } else if (jtime
== ktime
) {
2630 char const *dup_rules_msg
=
2631 _("two rules for same instant");
2632 eats(zp
->z_filename
, zp
->z_linenum
,
2633 rp
->r_filename
, rp
->r_linenum
);
2634 warning("%s", dup_rules_msg
);
2635 rp
= &zp
->z_rules
[k
];
2636 eats(zp
->z_filename
, zp
->z_linenum
,
2637 rp
->r_filename
, rp
->r_linenum
);
2638 error("%s", dup_rules_msg
);
2642 break; /* go on to next year */
2643 rp
= &zp
->z_rules
[k
];
2645 if (useuntil
&& ktime
>= untiltime
)
2647 stdoff
= rp
->r_stdoff
;
2648 if (usestart
&& ktime
== starttime
)
2651 if (ktime
< starttime
) {
2652 startoff
= oadd(zp
->z_gmtoff
,
2654 doabbr(startbuf
, zp
,
2661 if (*startbuf
== '\0' &&
2662 startoff
== oadd(zp
->z_gmtoff
,
2672 eats(zp
->z_filename
, zp
->z_linenum
,
2673 rp
->r_filename
, rp
->r_linenum
);
2674 doabbr(ab
, zp
, rp
->r_abbrvar
,
2675 rp
->r_isdst
, rp
->r_stdoff
, false);
2676 offset
= oadd(zp
->z_gmtoff
, rp
->r_stdoff
);
2677 type
= addtype(offset
, ab
, rp
->r_isdst
,
2678 rp
->r_todisstd
, rp
->r_todisgmt
);
2679 if (defaulttype
< 0 && !rp
->r_isdst
)
2681 if (rp
->r_hiyear
== ZIC_MAX
2682 && ! (0 <= lastatmax
2683 && ktime
< attypes
[lastatmax
].at
))
2684 lastatmax
= timecnt
;
2689 if (*startbuf
== '\0' &&
2690 zp
->z_format
!= NULL
&&
2691 strchr(zp
->z_format
, '%') == NULL
&&
2692 strchr(zp
->z_format
, '/') == NULL
)
2693 strcpy(startbuf
, zp
->z_format
);
2694 eat(zp
->z_filename
, zp
->z_linenum
);
2695 if (*startbuf
== '\0')
2696 error(_("can't determine time zone abbreviation to use just after until time"));
2698 bool isdst
= startoff
!= zp
->z_gmtoff
;
2699 type
= addtype(startoff
, startbuf
, isdst
,
2700 startttisstd
, startttisgmt
);
2701 if (defaulttype
< 0 && !isdst
)
2703 addtt(starttime
, type
);
2707 ** Now we may get to set starttime for the next zone line.
2710 startttisstd
= zp
->z_untilrule
.r_todisstd
;
2711 startttisgmt
= zp
->z_untilrule
.r_todisgmt
;
2712 starttime
= zp
->z_untiltime
;
2714 starttime
= tadd(starttime
, -stdoff
);
2716 starttime
= tadd(starttime
, -gmtoff
);
2719 if (defaulttype
< 0)
2722 attypes
[lastatmax
].dontmerge
= true;
2725 ** If we're extending the explicitly listed observations
2726 ** for 400 years because we can't fill the POSIX-TZ field,
2727 ** check whether we actually ended up explicitly listing
2728 ** observations through that period. If there aren't any
2729 ** near the end of the 400-year period, add a redundant
2730 ** one at the end of the final year, to make it clear
2731 ** that we are claiming to have definite knowledge of
2732 ** the lack of transitions up to that point.
2735 struct attype
*lastat
;
2736 xr
.r_month
= TM_JANUARY
;
2737 xr
.r_dycode
= DC_DOM
;
2738 xr
.r_dayofmonth
= 1;
2740 for (lastat
= &attypes
[0], i
= 1; i
< timecnt
; i
++)
2741 if (attypes
[i
].at
> lastat
->at
)
2742 lastat
= &attypes
[i
];
2743 if (lastat
->at
< rpytime(&xr
, max_year
- 1)) {
2744 addtt(rpytime(&xr
, max_year
+ 1), lastat
->type
);
2745 attypes
[timecnt
- 1].dontmerge
= true;
2748 writezone(zpfirst
->z_name
, envvar
, version
, defaulttype
);
2755 addtt(zic_t starttime
, int type
)
2757 attypes
= growalloc(attypes
, sizeof *attypes
, timecnt
, &timecnt_alloc
);
2758 attypes
[timecnt
].at
= starttime
;
2759 attypes
[timecnt
].dontmerge
= false;
2760 attypes
[timecnt
].type
= type
;
2765 addtype(zic_t gmtoff
, char const *abbr
, bool isdst
, bool ttisstd
, bool ttisgmt
)
2770 ** See if there's already an entry for this zone type.
2771 ** If so, just return its index.
2773 for (i
= 0; i
< typecnt
; ++i
) {
2774 if (gmtoff
== gmtoffs
[i
] && isdst
== isdsts
[i
] &&
2775 strcmp(abbr
, &chars
[abbrinds
[i
]]) == 0 &&
2776 ttisstd
== ttisstds
[i
] &&
2777 ttisgmt
== ttisgmts
[i
])
2781 ** There isn't one; add a new one, unless there are already too
2784 if (typecnt
>= TZ_MAX_TYPES
) {
2785 error(_("too many local time types"));
2788 if (! (-1L - 2147483647L <= gmtoff
&& gmtoff
<= 2147483647L)) {
2789 error(_("UT offset out of range"));
2792 gmtoffs
[i
] = gmtoff
;
2794 ttisstds
[i
] = ttisstd
;
2795 ttisgmts
[i
] = ttisgmt
;
2797 for (j
= 0; j
< charcnt
; ++j
)
2798 if (strcmp(&chars
[j
], abbr
) == 0)
2808 leapadd(zic_t t
, bool positive
, int rolling
, int count
)
2812 if (leapcnt
+ (positive
? count
: 1) > TZ_MAX_LEAPS
) {
2813 error(_("too many leap seconds"));
2816 for (i
= 0; i
< leapcnt
; ++i
)
2820 for (j
= leapcnt
; j
> i
; --j
) {
2821 trans
[j
] = trans
[j
- 1];
2822 corr
[j
] = corr
[j
- 1];
2823 roll
[j
] = roll
[j
- 1];
2826 corr
[i
] = positive
? 1 : -count
;
2829 } while (positive
&& --count
!= 0);
2836 register zic_t last
= 0;
2837 register zic_t prevtrans
= 0;
2840 ** propagate leap seconds forward
2842 for (i
= 0; i
< leapcnt
; ++i
) {
2843 if (trans
[i
] - prevtrans
< 28 * SECSPERDAY
) {
2844 error(_("Leap seconds too close together"));
2847 prevtrans
= trans
[i
];
2848 trans
[i
] = tadd(trans
[i
], last
);
2849 last
= corr
[i
] += last
;
2854 shellquote(char *b
, char const *s
)
2859 *b
++ = '\'', *b
++ = '\\', *b
++ = '\'';
2867 yearistype(zic_t year
, const char *type
)
2873 if (type
== NULL
|| *type
== '\0')
2875 buf
= emalloc(1 + 4 * strlen(yitcommand
) + 2
2876 + INT_STRLEN_MAXIMUM(zic_t
) + 2 + 4 * strlen(type
) + 2);
2877 b
= shellquote(buf
, yitcommand
);
2879 b
+= sprintf(b
, "%"PRIdZIC
, year
);
2881 b
= shellquote(b
, type
);
2883 result
= system(buf
);
2884 if (WIFEXITED(result
)) {
2885 int status
= WEXITSTATUS(result
);
2891 error(_("Wild result from command execution"));
2892 fprintf(stderr
, _("%s: command was '%s', result was %d\n"),
2893 progname
, buf
, result
);
2897 /* Is A a space character in the C locale? */
2904 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2909 /* Is A an alphabetic character in the C locale? */
2916 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2917 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2918 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2919 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2920 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2921 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2922 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2923 case 'v': case 'w': case 'x': case 'y': case 'z':
2928 /* If A is an uppercase character in the C locale, return its lowercase
2929 counterpart. Otherwise, return A. */
2935 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2936 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2937 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2938 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2939 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2940 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2941 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2942 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2943 case 'Y': return 'y'; case 'Z': return 'z';
2947 /* case-insensitive equality */
2948 static ATTRIBUTE_PURE
bool
2949 ciequal(register const char *ap
, register const char *bp
)
2951 while (lowerit(*ap
) == lowerit(*bp
++))
2957 static ATTRIBUTE_PURE
bool
2958 itsabbr(register const char *abbr
, register const char *word
)
2960 if (lowerit(*abbr
) != lowerit(*word
))
2963 while (*++abbr
!= '\0')
2967 } while (lowerit(*word
++) != lowerit(*abbr
));
2971 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
2973 static ATTRIBUTE_PURE
bool
2974 ciprefix(char const *abbr
, char const *word
)
2979 while (lowerit(*abbr
++) == lowerit(*word
++));
2984 static const struct lookup
*
2985 byword(const char *word
, const struct lookup
*table
)
2987 register const struct lookup
* foundlp
;
2988 register const struct lookup
* lp
;
2990 if (word
== NULL
|| table
== NULL
)
2993 /* If TABLE is LASTS and the word starts with "last" followed
2994 by a non-'-', skip the "last" and look in WDAY_NAMES instead.
2995 Warn about any usage of the undocumented prefix "last-". */
2996 if (table
== lasts
&& ciprefix("last", word
) && word
[4]) {
2998 warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
3007 ** Look for exact match.
3009 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
3010 if (ciequal(word
, lp
->l_word
))
3013 ** Look for inexact match.
3016 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
3017 if (ciprefix(word
, lp
->l_word
)) {
3018 if (foundlp
== NULL
)
3020 else return NULL
; /* multiple inexact matches */
3023 /* Warn about any backward-compatibility issue with pre-2017c zic. */
3025 bool pre_2017c_match
= false;
3026 for (lp
= table
; lp
->l_word
; lp
++)
3027 if (itsabbr(word
, lp
->l_word
)) {
3028 if (pre_2017c_match
) {
3029 warning(_("\"%s\" is ambiguous in pre-2017c zic"), word
);
3032 pre_2017c_match
= true;
3040 getfields(register char *cp
)
3043 register char ** array
;
3048 array
= emalloc(size_product(strlen(cp
) + 1, sizeof *array
));
3051 while (is_space(*cp
))
3053 if (*cp
== '\0' || *cp
== '#')
3055 array
[nsubs
++] = dp
= cp
;
3057 if ((*dp
= *cp
++) != '"')
3059 else while ((*dp
= *cp
++) != '"')
3063 error(_("Odd number of quotation marks"));
3066 } while (*cp
&& *cp
!= '#' && !is_space(*cp
));
3071 array
[nsubs
] = NULL
;
3075 static _Noreturn
void
3078 error(_("time overflow"));
3082 static ATTRIBUTE_PURE zic_t
3083 oadd(zic_t t1
, zic_t t2
)
3085 if (t1
< 0 ? t2
< ZIC_MIN
- t1
: ZIC_MAX
- t1
< t2
)
3090 static ATTRIBUTE_PURE zic_t
3091 tadd(zic_t t1
, zic_t t2
)
3094 if (t2
< min_time
- t1
) {
3100 if (max_time
- t1
< t2
) {
3110 ** Given a rule, and a year, compute the date (in seconds since January 1,
3111 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
3115 rpytime(const struct rule
*rp
, zic_t wantedy
)
3118 register zic_t dayoff
; /* with a nod to Margaret O. */
3119 register zic_t t
, y
;
3121 if (wantedy
== ZIC_MIN
)
3123 if (wantedy
== ZIC_MAX
)
3130 dayoff
= (wantedy
/ YEARSPERREPEAT
) * (SECSPERREPEAT
/ SECSPERDAY
);
3131 wantedy
%= YEARSPERREPEAT
;
3133 } else if (wantedy
< 0) {
3134 dayoff
= (wantedy
/ YEARSPERREPEAT
) * (SECSPERREPEAT
/ SECSPERDAY
);
3135 wantedy
%= YEARSPERREPEAT
;
3137 while (wantedy
!= y
) {
3139 i
= len_years
[isleap(y
)];
3143 i
= -len_years
[isleap(y
)];
3145 dayoff
= oadd(dayoff
, i
);
3147 while (m
!= rp
->r_month
) {
3148 i
= len_months
[isleap(y
)][m
];
3149 dayoff
= oadd(dayoff
, i
);
3152 i
= rp
->r_dayofmonth
;
3153 if (m
== TM_FEBRUARY
&& i
== 29 && !isleap(y
)) {
3154 if (rp
->r_dycode
== DC_DOWLEQ
)
3157 error(_("use of 2/29 in non leap-year"));
3162 dayoff
= oadd(dayoff
, i
);
3163 if (rp
->r_dycode
== DC_DOWGEQ
|| rp
->r_dycode
== DC_DOWLEQ
) {
3164 register zic_t wday
;
3166 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3169 ** Don't trust mod of negative numbers.
3172 wday
= (wday
+ dayoff
) % LDAYSPERWEEK
;
3174 wday
-= ((-dayoff
) % LDAYSPERWEEK
);
3176 wday
+= LDAYSPERWEEK
;
3178 while (wday
!= rp
->r_wday
)
3179 if (rp
->r_dycode
== DC_DOWGEQ
) {
3180 dayoff
= oadd(dayoff
, 1);
3181 if (++wday
>= LDAYSPERWEEK
)
3185 dayoff
= oadd(dayoff
, -1);
3187 wday
= LDAYSPERWEEK
- 1;
3190 if (i
< 0 || i
>= len_months
[isleap(y
)][m
]) {
3192 warning(_("rule goes past start/end of month; \
3193 will not work with pre-2004 versions of zic"));
3196 if (dayoff
< min_time
/ SECSPERDAY
)
3198 if (dayoff
> max_time
/ SECSPERDAY
)
3200 t
= (zic_t
) dayoff
* SECSPERDAY
;
3201 return tadd(t
, rp
->r_tod
);
3205 newabbr(const char *string
)
3209 if (strcmp(string
, GRANDPARENTED
) != 0) {
3210 register const char * cp
;
3215 while (is_alpha(*cp
) || ('0' <= *cp
&& *cp
<= '9')
3216 || *cp
== '-' || *cp
== '+')
3218 if (noise
&& cp
- string
< 3)
3219 mp
= _("time zone abbreviation has fewer than 3 characters");
3220 if (cp
- string
> ZIC_MAX_ABBR_LEN_WO_WARN
)
3221 mp
= _("time zone abbreviation has too many characters");
3223 mp
= _("time zone abbreviation differs from POSIX standard");
3225 warning("%s (%s)", mp
, string
);
3227 i
= strlen(string
) + 1;
3228 if (charcnt
+ i
> TZ_MAX_CHARS
) {
3229 error(_("too many, or too long, time zone abbreviations"));
3232 strcpy(&chars
[charcnt
], string
);
3236 /* Ensure that the directories of ARGNAME exist, by making any missing
3237 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3238 do it for ARGNAME too. Exit with failure if there is trouble.
3239 Do not consider an existing non-directory to be trouble. */
3241 mkdirs(char const *argname
, bool ancestors
)
3243 register char * name
;
3246 cp
= name
= ecpyalloc(argname
);
3248 /* On MS-Windows systems, do not worry about drive letters or
3249 backslashes, as this should suffice in practice. Time zone
3250 names do not use drive letters and backslashes. If the -d
3251 option of zic does not name an already-existing directory,
3252 it can use slashes to separate the already-existing
3253 ancestor prefix from the to-be-created subdirectories. */
3255 /* Do not mkdir a root directory, as it must exist. */
3259 while (cp
&& ((cp
= strchr(cp
, '/')) || !ancestors
)) {
3263 ** Try to create it. It's OK if creation fails because
3264 ** the directory already exists, perhaps because some
3265 ** other process just created it. For simplicity do
3266 ** not check first whether it already exists, as that
3267 ** is checked anyway if the mkdir fails.
3269 if (mkdir(name
, MKDIR_UMASK
) != 0) {
3270 /* For speed, skip itsdir if errno == EEXIST. Since
3271 mkdirs is called only after open fails with ENOENT
3272 on a subfile, EEXIST implies itsdir here. */
3274 if (err
!= EEXIST
&& !itsdir(name
)) {
3275 error(_("%s: Can't create directory %s: %s"),
3276 progname
, name
, strerror(err
));