2 ** This file is in the public domain, so clarified as of
3 ** 2006-07-17 by Arthur David Olson.
15 #define ZIC_VERSION_PRE_2013 '2'
16 #define ZIC_VERSION '3'
18 typedef int_fast64_t zic_t
;
19 #define ZIC_MIN INT_FAST64_MIN
20 #define ZIC_MAX INT_FAST64_MAX
21 #define PRIdZIC PRIdFAST64
22 #define SCNdZIC SCNdFAST64
24 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
25 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
26 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
32 # define mkdir(name, mode) _mkdir(name)
39 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
41 #define MKDIR_UMASK 0755
44 /* The maximum ptrdiff_t value, for pre-C99 platforms. */
46 static ptrdiff_t const PTRDIFF_MAX
= MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
49 /* The type for line numbers. Use PRIdMAX to format them; formerly
50 there was also "#define PRIdLINENO PRIdMAX" and formats used
51 PRIdLINENO, but xgettext cannot grok that. */
52 typedef intmax_t lineno
;
55 const char * r_filename
;
59 zic_t r_loyear
; /* for example, 1986 */
60 zic_t r_hiyear
; /* for example, 1986 */
61 const char * r_yrtype
;
65 int r_month
; /* 0..11 */
67 int r_dycode
; /* see below */
71 zic_t r_tod
; /* time from midnight */
72 bool r_todisstd
; /* above is standard time if 1 */
73 /* or wall clock time if 0 */
74 bool r_todisgmt
; /* above is GMT if 1 */
75 /* or local time if 0 */
76 zic_t r_stdoff
; /* offset from standard time */
77 const char * r_abbrvar
; /* variable part of abbreviation */
79 bool r_todo
; /* a rule to do (used in outzone) */
80 zic_t r_temp
; /* used in outzone */
84 ** r_dycode r_dayofmonth r_wday
87 #define DC_DOM 0 /* 1..31 */ /* unused */
88 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
89 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
92 const char * z_filename
;
98 const char * z_format
;
99 char z_format_specifier
;
103 struct rule
* z_rules
;
106 struct rule z_untilrule
;
110 #if !HAVE_POSIX_DECLS
111 extern int getopt(int argc
, char * const argv
[],
112 const char * options
);
113 extern int link(const char * fromname
, const char * toname
);
114 extern char * optarg
;
119 # define link(from, to) (errno = ENOTSUP, -1)
122 # define readlink(file, buf, size) (errno = ENOTSUP, -1)
123 # define symlink(from, to) (errno = ENOTSUP, -1)
124 # define S_ISLNK(m) 0
126 #ifndef AT_SYMLINK_FOLLOW
127 # define linkat(fromdir, from, todir, to, flag) \
128 (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
131 static void addtt(zic_t starttime
, int type
);
132 static int addtype(zic_t
, char const *, bool, bool, bool);
133 static void leapadd(zic_t
, bool, int, int);
134 static void adjleap(void);
135 static void associate(void);
136 static void dolink(const char *, const char *, bool);
137 static char ** getfields(char * buf
);
138 static zic_t
gethms(const char * string
, const char * errstring
,
140 static void infile(const char * filename
);
141 static void inleap(char ** fields
, int nfields
);
142 static void inlink(char ** fields
, int nfields
);
143 static void inrule(char ** fields
, int nfields
);
144 static bool inzcont(char ** fields
, int nfields
);
145 static bool inzone(char ** fields
, int nfields
);
146 static bool inzsub(char **, int, bool);
147 static bool itsdir(char const *);
148 static bool itssymlink(char const *);
149 static bool is_alpha(char a
);
150 static char lowerit(char);
151 static void mkdirs(char const *, bool);
152 static void newabbr(const char * abbr
);
153 static zic_t
oadd(zic_t t1
, zic_t t2
);
154 static void outzone(const struct zone
* zp
, ptrdiff_t ntzones
);
155 static zic_t
rpytime(const struct rule
* rp
, zic_t wantedy
);
156 static 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
);
160 static zic_t
tadd(zic_t t1
, zic_t t2
);
161 static bool yearistype(zic_t year
, const char * type
);
163 /* Bound on length of what %z can expand to. */
164 enum { PERCENT_Z_LEN_BOUND
= sizeof "+995959" - 1 };
166 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
167 tz binary files whose POSIX-TZ-style strings contain '<'; see
168 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
169 workaround will no longer be needed when Qt 5.6.1 and earlier are
170 obsolete, say in the year 2021. */
171 enum { WORK_AROUND_QTBUG_53071
= true };
175 static bool warnings
;
176 static const char * filename
;
178 static bool leapseen
;
179 static zic_t leapminyear
;
180 static zic_t leapmaxyear
;
181 static lineno linenum
;
182 static int max_abbrvar_len
= PERCENT_Z_LEN_BOUND
;
183 static int max_format_len
;
184 static zic_t max_year
;
185 static zic_t min_year
;
187 static const char * rfilename
;
188 static lineno rlinenum
;
189 static const char * progname
;
190 static ptrdiff_t timecnt
;
191 static ptrdiff_t timecnt_alloc
;
204 ** Which fields are which on a Zone line.
212 #define ZF_TILMONTH 6
215 #define ZONE_MINFIELDS 5
216 #define ZONE_MAXFIELDS 9
219 ** Which fields are which on a Zone continuation line.
225 #define ZFC_TILYEAR 3
226 #define ZFC_TILMONTH 4
228 #define ZFC_TILTIME 6
229 #define ZONEC_MINFIELDS 3
230 #define ZONEC_MAXFIELDS 7
233 ** Which files are which on a Rule line.
245 #define RULE_FIELDS 10
248 ** Which fields are which on a Link line.
253 #define LINK_FIELDS 3
256 ** Which fields are which on a Leap line.
265 #define LEAP_FIELDS 7
275 static struct rule
* rules
;
276 static ptrdiff_t nrules
; /* number of rules */
277 static ptrdiff_t nrules_alloc
;
279 static struct zone
* zones
;
280 static ptrdiff_t nzones
; /* number of zones */
281 static ptrdiff_t nzones_alloc
;
284 const char * l_filename
;
290 static struct link
* links
;
291 static ptrdiff_t nlinks
;
292 static ptrdiff_t nlinks_alloc
;
299 static struct lookup
const * byword(const char * string
,
300 const struct lookup
* lp
);
302 static struct lookup
const line_codes
[] = {
310 static struct lookup
const mon_names
[] = {
311 { "January", TM_JANUARY
},
312 { "February", TM_FEBRUARY
},
313 { "March", TM_MARCH
},
314 { "April", TM_APRIL
},
318 { "August", TM_AUGUST
},
319 { "September", TM_SEPTEMBER
},
320 { "October", TM_OCTOBER
},
321 { "November", TM_NOVEMBER
},
322 { "December", TM_DECEMBER
},
326 static struct lookup
const wday_names
[] = {
327 { "Sunday", TM_SUNDAY
},
328 { "Monday", TM_MONDAY
},
329 { "Tuesday", TM_TUESDAY
},
330 { "Wednesday", TM_WEDNESDAY
},
331 { "Thursday", TM_THURSDAY
},
332 { "Friday", TM_FRIDAY
},
333 { "Saturday", TM_SATURDAY
},
337 static struct lookup
const lasts
[] = {
338 { "last-Sunday", TM_SUNDAY
},
339 { "last-Monday", TM_MONDAY
},
340 { "last-Tuesday", TM_TUESDAY
},
341 { "last-Wednesday", TM_WEDNESDAY
},
342 { "last-Thursday", TM_THURSDAY
},
343 { "last-Friday", TM_FRIDAY
},
344 { "last-Saturday", TM_SATURDAY
},
348 static struct lookup
const begin_years
[] = {
349 { "minimum", YR_MINIMUM
},
350 { "maximum", YR_MAXIMUM
},
354 static struct lookup
const end_years
[] = {
355 { "minimum", YR_MINIMUM
},
356 { "maximum", YR_MAXIMUM
},
361 static struct lookup
const leap_types
[] = {
363 { "Stationary", false },
367 static const int len_months
[2][MONSPERYEAR
] = {
368 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
369 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
372 static const int len_years
[2] = {
373 DAYSPERNYEAR
, DAYSPERLYEAR
376 static struct attype
{
381 static zic_t gmtoffs
[TZ_MAX_TYPES
];
382 static char isdsts
[TZ_MAX_TYPES
];
383 static unsigned char abbrinds
[TZ_MAX_TYPES
];
384 static bool ttisstds
[TZ_MAX_TYPES
];
385 static bool ttisgmts
[TZ_MAX_TYPES
];
386 static char chars
[TZ_MAX_CHARS
];
387 static zic_t trans
[TZ_MAX_LEAPS
];
388 static zic_t corr
[TZ_MAX_LEAPS
];
389 static char roll
[TZ_MAX_LEAPS
];
392 ** Memory allocation.
395 static _Noreturn
void
396 memory_exhausted(const char *msg
)
398 fprintf(stderr
, _("%s: Memory exhausted: %s\n"), progname
, msg
);
402 static ATTRIBUTE_PURE
size_t
403 size_product(size_t nitems
, size_t itemsize
)
405 if (SIZE_MAX
/ itemsize
< nitems
)
406 memory_exhausted(_("size overflow"));
407 return nitems
* itemsize
;
412 strdup(char const *str
)
414 char *result
= malloc(strlen(str
) + 1);
415 return result
? strcpy(result
, str
) : result
;
419 static ATTRIBUTE_PURE
void *
423 memory_exhausted(strerror(errno
));
430 return memcheck(malloc(size
));
434 erealloc(void *ptr
, size_t size
)
436 return memcheck(realloc(ptr
, size
));
440 ecpyalloc (char const *str
)
442 return memcheck(strdup(str
));
446 growalloc(void *ptr
, size_t itemsize
, ptrdiff_t nitems
, ptrdiff_t *nitems_alloc
)
448 if (nitems
< *nitems_alloc
)
451 ptrdiff_t nitems_max
= PTRDIFF_MAX
- WORK_AROUND_QTBUG_53071
;
452 ptrdiff_t amax
= nitems_max
< SIZE_MAX
? nitems_max
: SIZE_MAX
;
453 if ((amax
- 1) / 3 * 2 < *nitems_alloc
)
454 memory_exhausted(_("integer overflow"));
455 *nitems_alloc
+= (*nitems_alloc
>> 1) + 1;
456 return erealloc(ptr
, size_product(*nitems_alloc
, itemsize
));
465 eats(char const *name
, lineno num
, char const *rname
, lineno rnum
)
474 eat(char const *name
, lineno num
)
476 eats(name
, num
, NULL
, -1);
479 static void ATTRIBUTE_FORMAT((printf
, 1, 0))
480 verror(const char *const string
, va_list args
)
483 ** Match the format of "cc" to allow sh users to
484 ** zic ... 2>&1 | error -t "*" -v
488 fprintf(stderr
, _("\"%s\", line %"PRIdMAX
": "), filename
, linenum
);
489 vfprintf(stderr
, string
, args
);
490 if (rfilename
!= NULL
)
491 fprintf(stderr
, _(" (rule from \"%s\", line %"PRIdMAX
")"),
492 rfilename
, rlinenum
);
493 fprintf(stderr
, "\n");
496 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
497 error(const char *const string
, ...)
500 va_start(args
, string
);
501 verror(string
, args
);
506 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
507 warning(const char *const string
, ...)
510 fprintf(stderr
, _("warning: "));
511 va_start(args
, string
);
512 verror(string
, args
);
518 close_file(FILE *stream
, char const *dir
, char const *name
)
520 char const *e
= (ferror(stream
) ? _("I/O error")
521 : fclose(stream
) != 0 ? strerror(errno
) : NULL
);
523 fprintf(stderr
, "%s: %s%s%s%s%s\n", progname
,
524 dir
? dir
: "", dir
? "/" : "",
525 name
? name
: "", name
? ": " : "",
531 static _Noreturn
void
532 usage(FILE *stream
, int status
)
535 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
536 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
537 "\t[ -L leapseconds ] [ filename ... ]\n\n"
538 "Report bugs to %s.\n"),
539 progname
, progname
, REPORT_BUGS_TO
);
540 if (status
== EXIT_SUCCESS
)
541 close_file(stream
, NULL
, NULL
);
545 /* Change the working directory to DIR, possibly creating DIR and its
546 ancestors. After this is done, all files are accessed with names
549 change_directory (char const *dir
)
551 if (chdir(dir
) != 0) {
552 int chdir_errno
= errno
;
553 if (chdir_errno
== ENOENT
) {
555 chdir_errno
= chdir(dir
) == 0 ? 0 : errno
;
557 if (chdir_errno
!= 0) {
558 fprintf(stderr
, _("%s: Can't chdir to %s: %s\n"),
559 progname
, dir
, strerror(chdir_errno
));
565 static const char * psxrules
;
566 static const char * lcltime
;
567 static const char * directory
;
568 static const char * leapsec
;
569 static const char * yitcommand
;
572 main(int argc
, char **argv
)
575 register ptrdiff_t i
, j
;
578 umask(umask(S_IWGRP
| S_IWOTH
) | (S_IWGRP
| S_IWOTH
));
581 setlocale(LC_ALL
, "");
583 bindtextdomain(TZ_DOMAIN
, TZ_DOMAINDIR
);
584 #endif /* defined TEXTDOMAINDIR */
585 textdomain(TZ_DOMAIN
);
586 #endif /* HAVE_GETTEXT */
588 if (TYPE_BIT(zic_t
) < 64) {
589 fprintf(stderr
, "%s: %s\n", progname
,
590 _("wild compilation-time specification of zic_t"));
593 for (k
= 1; k
< argc
; k
++)
594 if (strcmp(argv
[k
], "--version") == 0) {
595 printf("zic %s%s\n", PKGVERSION
, TZVERSION
);
596 close_file(stdout
, NULL
, NULL
);
598 } else if (strcmp(argv
[k
], "--help") == 0) {
599 usage(stdout
, EXIT_SUCCESS
);
601 while ((c
= getopt(argc
, argv
, "d:l:p:L:vsy:")) != EOF
&& c
!= -1)
604 usage(stderr
, EXIT_FAILURE
);
606 if (directory
== NULL
)
610 _("%s: More than one -d option specified\n"),
620 _("%s: More than one -l option specified\n"),
626 if (psxrules
== NULL
)
630 _("%s: More than one -p option specified\n"),
636 if (yitcommand
== NULL
)
640 _("%s: More than one -y option specified\n"),
650 _("%s: More than one -L option specified\n"),
659 warning(_("-s ignored"));
662 if (optind
== argc
- 1 && strcmp(argv
[optind
], "=") == 0)
663 usage(stderr
, EXIT_FAILURE
); /* usage message by request */
664 if (directory
== NULL
)
666 if (yitcommand
== NULL
)
667 yitcommand
= "yearistype";
669 if (optind
< argc
&& leapsec
!= NULL
) {
674 for (k
= optind
; k
< argc
; k
++)
679 change_directory(directory
);
680 for (i
= 0; i
< nzones
; i
= j
) {
682 ** Find the next non-continuation zone entry.
684 for (j
= i
+ 1; j
< nzones
&& zones
[j
].z_name
== NULL
; ++j
)
686 outzone(&zones
[i
], j
- i
);
691 for (i
= 0; i
< nlinks
; ++i
) {
692 eat(links
[i
].l_filename
, links
[i
].l_linenum
);
693 dolink(links
[i
].l_from
, links
[i
].l_to
, false);
695 for (j
= 0; j
< nlinks
; ++j
)
696 if (strcmp(links
[i
].l_to
,
697 links
[j
].l_from
) == 0)
698 warning(_("link to link"));
700 if (lcltime
!= NULL
) {
701 eat(_("command line"), 1);
702 dolink(lcltime
, TZDEFAULT
, true);
704 if (psxrules
!= NULL
) {
705 eat(_("command line"), 1);
706 dolink(psxrules
, TZDEFRULES
, true);
708 if (warnings
&& (ferror(stderr
) || fclose(stderr
) != 0))
710 return errors
? EXIT_FAILURE
: EXIT_SUCCESS
;
714 componentcheck(char const *name
, char const *component
,
715 char const *component_end
)
717 enum { component_len_max
= 14 };
718 ptrdiff_t component_len
= component_end
- component
;
719 if (component_len
== 0) {
721 error (_("empty file name"));
723 error (_(component
== name
724 ? "file name '%s' begins with '/'"
726 ? "file name '%s' contains '//'"
727 : "file name '%s' ends with '/'"),
731 if (0 < component_len
&& component_len
<= 2
732 && component
[0] == '.' && component_end
[-1] == '.') {
733 int len
= component_len
;
734 error(_("file name '%s' contains '%.*s' component"),
735 name
, len
, component
);
739 if (0 < component_len
&& component
[0] == '-')
740 warning(_("file name '%s' component contains leading '-'"),
742 if (component_len_max
< component_len
)
743 warning(_("file name '%s' contains overlength component"
745 name
, component_len_max
, component
);
751 namecheck(const char *name
)
753 register char const *cp
;
755 /* Benign characters in a portable file name. */
756 static char const benign
[] =
758 "abcdefghijklmnopqrstuvwxyz"
759 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
761 /* Non-control chars in the POSIX portable character set,
762 excluding the benign characters. */
763 static char const printable_and_not_benign
[] =
764 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
766 register char const *component
= name
;
767 for (cp
= name
; *cp
; cp
++) {
768 unsigned char c
= *cp
;
769 if (noise
&& !strchr(benign
, c
)) {
770 warning((strchr(printable_and_not_benign
, c
)
771 ? _("file name '%s' contains byte '%c'")
772 : _("file name '%s' contains byte '\\%o'")),
776 if (!componentcheck(name
, component
, cp
))
781 return componentcheck(name
, component
, cp
);
784 /* Create symlink contents suitable for symlinking FROM to TO, as a
785 freshly allocated string. FROM should be a relative file name, and
786 is relative to the global variable DIRECTORY. TO can be either
787 relative or absolute. */
789 relname(char const *from
, char const *to
)
791 size_t i
, taillen
, dotdotetcsize
;
792 size_t dir_len
= 0, dotdots
= 0, linksize
= SIZE_MAX
;
793 char const *f
= from
;
796 /* Make F absolute too. */
797 size_t len
= strlen(directory
);
798 bool needslash
= len
&& directory
[len
- 1] != '/';
799 linksize
= len
+ needslash
+ strlen(from
) + 1;
800 f
= result
= emalloc(linksize
);
801 strcpy(result
, directory
);
803 strcpy(result
+ len
+ needslash
, from
);
805 for (i
= 0; f
[i
] && f
[i
] == to
[i
]; i
++)
809 dotdots
+= to
[i
] == '/' && to
[i
- 1] != '/';
810 taillen
= strlen(f
+ dir_len
);
811 dotdotetcsize
= 3 * dotdots
+ taillen
+ 1;
812 if (dotdotetcsize
<= linksize
) {
814 result
= emalloc(dotdotetcsize
);
815 for (i
= 0; i
< dotdots
; i
++)
816 memcpy(result
+ 3 * i
, "../", 3);
817 memmove(result
+ 3 * dotdots
, f
+ dir_len
, taillen
+ 1);
822 /* Hard link FROM to TO, following any symbolic links.
823 Return 0 if successful, an error number otherwise. */
825 hardlinkerr(char const *from
, char const *to
)
827 int r
= linkat(AT_FDCWD
, from
, AT_FDCWD
, to
, AT_SYMLINK_FOLLOW
);
828 return r
== 0 ? 0 : errno
;
832 dolink(char const *fromfield
, char const *tofield
, bool staysymlink
)
834 bool todirs_made
= false;
838 ** We get to be careful here since
839 ** there's a fair chance of root running us.
841 if (itsdir(fromfield
)) {
842 fprintf(stderr
, _("%s: link from %s/%s failed: %s\n"),
843 progname
, directory
, fromfield
, strerror(EPERM
));
847 staysymlink
= itssymlink(tofield
);
848 if (remove(tofield
) == 0)
850 else if (errno
!= ENOENT
) {
851 char const *e
= strerror(errno
);
852 fprintf(stderr
, _("%s: Can't remove %s/%s: %s\n"),
853 progname
, directory
, tofield
, e
);
856 link_errno
= staysymlink
? ENOTSUP
: hardlinkerr(fromfield
, tofield
);
857 if (link_errno
== ENOENT
&& !todirs_made
) {
858 mkdirs(tofield
, true);
860 link_errno
= hardlinkerr(fromfield
, tofield
);
862 if (link_errno
!= 0) {
863 bool absolute
= *fromfield
== '/';
864 char *linkalloc
= absolute
? NULL
: relname(fromfield
, tofield
);
865 char const *contents
= absolute
? fromfield
: linkalloc
;
866 int symlink_errno
= symlink(contents
, tofield
) == 0 ? 0 : errno
;
867 if (symlink_errno
== ENOENT
&& !todirs_made
) {
868 mkdirs(tofield
, true);
869 symlink_errno
= symlink(contents
, tofield
) == 0 ? 0 : errno
;
872 if (symlink_errno
== 0) {
873 if (link_errno
!= ENOTSUP
)
874 warning(_("symbolic link used because hard link failed: %s"),
875 strerror(link_errno
));
879 fp
= fopen(fromfield
, "rb");
881 char const *e
= strerror(errno
);
882 fprintf(stderr
, _("%s: Can't read %s/%s: %s\n"),
883 progname
, directory
, fromfield
, e
);
886 tp
= fopen(tofield
, "wb");
888 char const *e
= strerror(errno
);
889 fprintf(stderr
, _("%s: Can't create %s/%s: %s\n"),
890 progname
, directory
, tofield
, e
);
893 while ((c
= getc(fp
)) != EOF
)
895 close_file(fp
, directory
, fromfield
);
896 close_file(tp
, directory
, tofield
);
897 if (link_errno
!= ENOTSUP
)
898 warning(_("copy used because hard link failed: %s"),
899 strerror(link_errno
));
900 else if (symlink_errno
!= ENOTSUP
)
901 warning(_("copy used because symbolic link failed: %s"),
902 strerror(symlink_errno
));
907 #define TIME_T_BITS_IN_FILE 64
909 static zic_t
const min_time
= MINVAL(zic_t
, TIME_T_BITS_IN_FILE
);
910 static zic_t
const max_time
= MAXVAL(zic_t
, TIME_T_BITS_IN_FILE
);
912 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
913 rounded downward to the negation of a power of two that is
914 comfortably outside the error bounds.
916 For the time of the Big Bang, see:
918 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
919 I. Overview of products and scientific results.
920 arXiv:1303.5062 2013-03-20 20:10:01 UTC
921 <http://arxiv.org/pdf/1303.5062v1> [PDF]
923 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
924 gives the value 13.798 plus-or-minus 0.037 billion years.
925 Multiplying this by 1000000000 and then by 31557600 (the number of
926 seconds in an astronomical year) gives a value that is comfortably
927 less than 2**59, so BIG_BANG is - 2**59.
929 BIG_BANG is approximate, and may change in future versions.
930 Please do not rely on its exact value. */
933 #define BIG_BANG (- (1LL << 59))
936 /* If true, work around GNOME bug 730332
937 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>
938 by refusing to output time stamps before BIG_BANG.
939 Such time stamps are physically suspect anyway.
941 The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so
942 this workaround will no longer be needed when GNOME 3.21 and
943 earlier are obsolete, say in the year 2021. */
944 enum { WORK_AROUND_GNOME_BUG_730332
= true };
946 static const zic_t early_time
= (WORK_AROUND_GNOME_BUG_730332
948 : MINVAL(zic_t
, TIME_T_BITS_IN_FILE
));
950 /* Return true if NAME is a directory. */
952 itsdir(char const *name
)
955 int res
= stat(name
, &st
);
958 return S_ISDIR(st
.st_mode
) != 0;
960 if (res
== 0 || errno
== EOVERFLOW
) {
961 size_t n
= strlen(name
);
962 char *nameslashdot
= emalloc(n
+ 3);
964 memcpy(nameslashdot
, name
, n
);
965 strcpy(&nameslashdot
[n
], &"/."[! (n
&& name
[n
- 1] != '/')]);
966 dir
= stat(nameslashdot
, &st
) == 0 || errno
== EOVERFLOW
;
973 /* Return true if NAME is a symbolic link. */
975 itssymlink(char const *name
)
978 return 0 <= readlink(name
, &c
, 1);
982 ** Associate sets of rules with zones.
986 ** Sort by rule name.
990 rcomp(const void *cp1
, const void *cp2
)
992 return strcmp(((const struct rule
*) cp1
)->r_name
,
993 ((const struct rule
*) cp2
)->r_name
);
999 register struct zone
* zp
;
1000 register struct rule
* rp
;
1001 register ptrdiff_t i
, j
, base
, out
;
1004 qsort(rules
, nrules
, sizeof *rules
, rcomp
);
1005 for (i
= 0; i
< nrules
- 1; ++i
) {
1006 if (strcmp(rules
[i
].r_name
,
1007 rules
[i
+ 1].r_name
) != 0)
1009 if (strcmp(rules
[i
].r_filename
,
1010 rules
[i
+ 1].r_filename
) == 0)
1012 eat(rules
[i
].r_filename
, rules
[i
].r_linenum
);
1013 warning(_("same rule name in multiple files"));
1014 eat(rules
[i
+ 1].r_filename
, rules
[i
+ 1].r_linenum
);
1015 warning(_("same rule name in multiple files"));
1016 for (j
= i
+ 2; j
< nrules
; ++j
) {
1017 if (strcmp(rules
[i
].r_name
,
1018 rules
[j
].r_name
) != 0)
1020 if (strcmp(rules
[i
].r_filename
,
1021 rules
[j
].r_filename
) == 0)
1023 if (strcmp(rules
[i
+ 1].r_filename
,
1024 rules
[j
].r_filename
) == 0)
1031 for (i
= 0; i
< nzones
; ++i
) {
1036 for (base
= 0; base
< nrules
; base
= out
) {
1038 for (out
= base
+ 1; out
< nrules
; ++out
)
1039 if (strcmp(rp
->r_name
, rules
[out
].r_name
) != 0)
1041 for (i
= 0; i
< nzones
; ++i
) {
1043 if (strcmp(zp
->z_rule
, rp
->r_name
) != 0)
1046 zp
->z_nrules
= out
- base
;
1049 for (i
= 0; i
< nzones
; ++i
) {
1051 if (zp
->z_nrules
== 0) {
1053 ** Maybe we have a local standard time offset.
1055 eat(zp
->z_filename
, zp
->z_linenum
);
1056 zp
->z_stdoff
= gethms(zp
->z_rule
, _("unruly zone"),
1059 ** Note, though, that if there's no rule,
1060 ** a '%s' in the format is a bad thing.
1062 if (zp
->z_format_specifier
== 's')
1063 error("%s", _("%s in ruleless zone"));
1071 infile(const char *name
)
1074 register char ** fields
;
1076 register const struct lookup
* lp
;
1077 register int nfields
;
1078 register bool wantcont
;
1079 register lineno num
;
1082 if (strcmp(name
, "-") == 0) {
1083 name
= _("standard input");
1085 } else if ((fp
= fopen(name
, "r")) == NULL
) {
1086 const char *e
= strerror(errno
);
1088 fprintf(stderr
, _("%s: Can't open %s: %s\n"),
1093 for (num
= 1; ; ++num
) {
1095 if (fgets(buf
, sizeof buf
, fp
) != buf
)
1097 cp
= strchr(buf
, '\n');
1099 error(_("line too long"));
1103 fields
= getfields(buf
);
1105 while (fields
[nfields
] != NULL
) {
1108 if (strcmp(fields
[nfields
], "-") == 0)
1109 fields
[nfields
] = &nada
;
1114 } else if (wantcont
) {
1115 wantcont
= inzcont(fields
, nfields
);
1117 lp
= byword(fields
[0], line_codes
);
1119 error(_("input line of unknown type"));
1120 else switch (lp
->l_value
) {
1122 inrule(fields
, nfields
);
1126 wantcont
= inzone(fields
, nfields
);
1129 inlink(fields
, nfields
);
1133 if (name
!= leapsec
)
1134 warning(_("%s: Leap line in non leap"
1135 " seconds file %s"),
1137 else inleap(fields
, nfields
);
1140 default: /* "cannot happen" */
1142 _("%s: panic: Invalid l_value %d\n"),
1143 progname
, lp
->l_value
);
1149 close_file(fp
, NULL
, filename
);
1151 error(_("expected continuation line not found"));
1155 ** Convert a string of one of the forms
1156 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1157 ** into a number of seconds.
1158 ** A null string maps to zero.
1159 ** Call error with errstring and return zero on errors.
1163 gethms(char const *string
, char const *errstring
, bool signable
)
1169 if (string
== NULL
|| *string
== '\0')
1173 else if (*string
== '-') {
1177 if (sscanf(string
, "%"SCNdZIC
"%c", &hh
, &xs
) == 1)
1179 else if (sscanf(string
, "%"SCNdZIC
":%d%c", &hh
, &mm
, &xs
) == 2)
1181 else if (sscanf(string
, "%"SCNdZIC
":%d:%d%c", &hh
, &mm
, &ss
, &xs
)
1183 error("%s", errstring
);
1187 mm
< 0 || mm
>= MINSPERHOUR
||
1188 ss
< 0 || ss
> SECSPERMIN
) {
1189 error("%s", errstring
);
1192 if (ZIC_MAX
/ SECSPERHOUR
< hh
) {
1193 error(_("time overflow"));
1196 if (noise
&& (hh
> HOURSPERDAY
||
1197 (hh
== HOURSPERDAY
&& (mm
!= 0 || ss
!= 0))))
1198 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1199 return oadd(sign
* hh
* SECSPERHOUR
,
1200 sign
* (mm
* SECSPERMIN
+ ss
));
1204 inrule(char **fields
, int nfields
)
1206 static struct rule r
;
1208 if (nfields
!= RULE_FIELDS
) {
1209 error(_("wrong number of fields on Rule line"));
1212 if (*fields
[RF_NAME
] == '\0') {
1213 error(_("nameless rule"));
1216 r
.r_filename
= filename
;
1217 r
.r_linenum
= linenum
;
1218 r
.r_stdoff
= gethms(fields
[RF_STDOFF
], _("invalid saved time"), true);
1219 rulesub(&r
, fields
[RF_LOYEAR
], fields
[RF_HIYEAR
], fields
[RF_COMMAND
],
1220 fields
[RF_MONTH
], fields
[RF_DAY
], fields
[RF_TOD
]);
1221 r
.r_name
= ecpyalloc(fields
[RF_NAME
]);
1222 r
.r_abbrvar
= ecpyalloc(fields
[RF_ABBRVAR
]);
1223 if (max_abbrvar_len
< strlen(r
.r_abbrvar
))
1224 max_abbrvar_len
= strlen(r
.r_abbrvar
);
1225 rules
= growalloc(rules
, sizeof *rules
, nrules
, &nrules_alloc
);
1226 rules
[nrules
++] = r
;
1230 inzone(char **fields
, int nfields
)
1232 register ptrdiff_t i
;
1234 if (nfields
< ZONE_MINFIELDS
|| nfields
> ZONE_MAXFIELDS
) {
1235 error(_("wrong number of fields on Zone line"));
1238 if (strcmp(fields
[ZF_NAME
], TZDEFAULT
) == 0 && lcltime
!= NULL
) {
1240 _("\"Zone %s\" line and -l option are mutually exclusive"),
1244 if (strcmp(fields
[ZF_NAME
], TZDEFRULES
) == 0 && psxrules
!= NULL
) {
1246 _("\"Zone %s\" line and -p option are mutually exclusive"),
1250 for (i
= 0; i
< nzones
; ++i
)
1251 if (zones
[i
].z_name
!= NULL
&&
1252 strcmp(zones
[i
].z_name
, fields
[ZF_NAME
]) == 0) {
1253 error(_("duplicate zone name %s"
1254 " (file \"%s\", line %"PRIdMAX
")"),
1256 zones
[i
].z_filename
,
1257 zones
[i
].z_linenum
);
1260 return inzsub(fields
, nfields
, false);
1264 inzcont(char **fields
, int nfields
)
1266 if (nfields
< ZONEC_MINFIELDS
|| nfields
> ZONEC_MAXFIELDS
) {
1267 error(_("wrong number of fields on Zone continuation line"));
1270 return inzsub(fields
, nfields
, true);
1274 inzsub(char **fields
, int nfields
, bool iscont
)
1278 static struct zone z
;
1279 register int i_gmtoff
, i_rule
, i_format
;
1280 register int i_untilyear
, i_untilmonth
;
1281 register int i_untilday
, i_untiltime
;
1282 register bool hasuntil
;
1285 i_gmtoff
= ZFC_GMTOFF
;
1287 i_format
= ZFC_FORMAT
;
1288 i_untilyear
= ZFC_TILYEAR
;
1289 i_untilmonth
= ZFC_TILMONTH
;
1290 i_untilday
= ZFC_TILDAY
;
1291 i_untiltime
= ZFC_TILTIME
;
1293 } else if (!namecheck(fields
[ZF_NAME
]))
1296 i_gmtoff
= ZF_GMTOFF
;
1298 i_format
= ZF_FORMAT
;
1299 i_untilyear
= ZF_TILYEAR
;
1300 i_untilmonth
= ZF_TILMONTH
;
1301 i_untilday
= ZF_TILDAY
;
1302 i_untiltime
= ZF_TILTIME
;
1303 z
.z_name
= ecpyalloc(fields
[ZF_NAME
]);
1305 z
.z_filename
= filename
;
1306 z
.z_linenum
= linenum
;
1307 z
.z_gmtoff
= gethms(fields
[i_gmtoff
], _("invalid UT offset"), true);
1308 if ((cp
= strchr(fields
[i_format
], '%')) != 0) {
1309 if ((*++cp
!= 's' && *cp
!= 'z') || strchr(cp
, '%')
1310 || strchr(fields
[i_format
], '/')) {
1311 error(_("invalid abbreviation format"));
1315 z
.z_rule
= ecpyalloc(fields
[i_rule
]);
1316 z
.z_format
= cp1
= ecpyalloc(fields
[i_format
]);
1317 z
.z_format_specifier
= cp
? *cp
: '\0';
1318 if (z
.z_format_specifier
== 'z') {
1320 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1322 cp1
[cp
- fields
[i_format
]] = 's';
1324 if (max_format_len
< strlen(z
.z_format
))
1325 max_format_len
= strlen(z
.z_format
);
1326 hasuntil
= nfields
> i_untilyear
;
1328 z
.z_untilrule
.r_filename
= filename
;
1329 z
.z_untilrule
.r_linenum
= linenum
;
1330 rulesub(&z
.z_untilrule
,
1331 fields
[i_untilyear
],
1334 (nfields
> i_untilmonth
) ?
1335 fields
[i_untilmonth
] : "Jan",
1336 (nfields
> i_untilday
) ? fields
[i_untilday
] : "1",
1337 (nfields
> i_untiltime
) ? fields
[i_untiltime
] : "0");
1338 z
.z_untiltime
= rpytime(&z
.z_untilrule
,
1339 z
.z_untilrule
.r_loyear
);
1340 if (iscont
&& nzones
> 0 &&
1341 z
.z_untiltime
> min_time
&&
1342 z
.z_untiltime
< max_time
&&
1343 zones
[nzones
- 1].z_untiltime
> min_time
&&
1344 zones
[nzones
- 1].z_untiltime
< max_time
&&
1345 zones
[nzones
- 1].z_untiltime
>= z
.z_untiltime
) {
1347 "Zone continuation line end time is not after end time of previous line"
1352 zones
= growalloc(zones
, sizeof *zones
, nzones
, &nzones_alloc
);
1353 zones
[nzones
++] = z
;
1355 ** If there was an UNTIL field on this line,
1356 ** there's more information about the zone on the next line.
1362 inleap(char **fields
, int nfields
)
1364 register const char * cp
;
1365 register const struct lookup
* lp
;
1366 register zic_t i
, j
;
1373 if (nfields
!= LEAP_FIELDS
) {
1374 error(_("wrong number of fields on Leap line"));
1378 cp
= fields
[LP_YEAR
];
1379 if (sscanf(cp
, "%"SCNdZIC
"%c", &year
, &xs
) != 1) {
1383 error(_("invalid leaping year"));
1386 if (!leapseen
|| leapmaxyear
< year
)
1388 if (!leapseen
|| leapminyear
> year
)
1394 i
= len_years
[isleap(j
)];
1398 i
= -len_years
[isleap(j
)];
1400 dayoff
= oadd(dayoff
, i
);
1402 if ((lp
= byword(fields
[LP_MONTH
], mon_names
)) == NULL
) {
1403 error(_("invalid month name"));
1406 month
= lp
->l_value
;
1408 while (j
!= month
) {
1409 i
= len_months
[isleap(year
)][j
];
1410 dayoff
= oadd(dayoff
, i
);
1413 cp
= fields
[LP_DAY
];
1414 if (sscanf(cp
, "%d%c", &day
, &xs
) != 1 ||
1415 day
<= 0 || day
> len_months
[isleap(year
)][month
]) {
1416 error(_("invalid day of month"));
1419 dayoff
= oadd(dayoff
, day
- 1);
1420 if (dayoff
< min_time
/ SECSPERDAY
) {
1421 error(_("time too small"));
1424 if (dayoff
> max_time
/ SECSPERDAY
) {
1425 error(_("time too large"));
1428 t
= dayoff
* SECSPERDAY
;
1429 tod
= gethms(fields
[LP_TIME
], _("invalid time of day"), false);
1430 cp
= fields
[LP_CORR
];
1432 register bool positive
;
1435 if (strcmp(cp
, "") == 0) { /* infile() turns "-" into "" */
1438 } else if (strcmp(cp
, "--") == 0) {
1441 } else if (strcmp(cp
, "+") == 0) {
1444 } else if (strcmp(cp
, "++") == 0) {
1448 error(_("illegal CORRECTION field on Leap line"));
1451 if ((lp
= byword(fields
[LP_ROLL
], leap_types
)) == NULL
) {
1453 "illegal Rolling/Stationary field on Leap line"
1458 if (t
< early_time
) {
1459 error(_("leap second precedes Big Bang"));
1462 leapadd(t
, positive
, lp
->l_value
, count
);
1467 inlink(char **fields
, int nfields
)
1471 if (nfields
!= LINK_FIELDS
) {
1472 error(_("wrong number of fields on Link line"));
1475 if (*fields
[LF_FROM
] == '\0') {
1476 error(_("blank FROM field on Link line"));
1479 if (! namecheck(fields
[LF_TO
]))
1481 l
.l_filename
= filename
;
1482 l
.l_linenum
= linenum
;
1483 l
.l_from
= ecpyalloc(fields
[LF_FROM
]);
1484 l
.l_to
= ecpyalloc(fields
[LF_TO
]);
1485 links
= growalloc(links
, sizeof *links
, nlinks
, &nlinks_alloc
);
1486 links
[nlinks
++] = l
;
1490 rulesub(struct rule
*rp
, const char *loyearp
, const char *hiyearp
,
1491 const char *typep
, const char *monthp
, const char *dayp
,
1494 register const struct lookup
* lp
;
1495 register const char * cp
;
1500 if ((lp
= byword(monthp
, mon_names
)) == NULL
) {
1501 error(_("invalid month name"));
1504 rp
->r_month
= lp
->l_value
;
1505 rp
->r_todisstd
= false;
1506 rp
->r_todisgmt
= false;
1507 dp
= ecpyalloc(timep
);
1509 ep
= dp
+ strlen(dp
) - 1;
1510 switch (lowerit(*ep
)) {
1511 case 's': /* Standard */
1512 rp
->r_todisstd
= true;
1513 rp
->r_todisgmt
= false;
1516 case 'w': /* Wall */
1517 rp
->r_todisstd
= false;
1518 rp
->r_todisgmt
= false;
1521 case 'g': /* Greenwich */
1522 case 'u': /* Universal */
1523 case 'z': /* Zulu */
1524 rp
->r_todisstd
= true;
1525 rp
->r_todisgmt
= true;
1530 rp
->r_tod
= gethms(dp
, _("invalid time of day"), false);
1536 lp
= byword(cp
, begin_years
);
1537 rp
->r_lowasnum
= lp
== NULL
;
1538 if (!rp
->r_lowasnum
) switch (lp
->l_value
) {
1540 rp
->r_loyear
= ZIC_MIN
;
1543 rp
->r_loyear
= ZIC_MAX
;
1545 default: /* "cannot happen" */
1547 _("%s: panic: Invalid l_value %d\n"),
1548 progname
, lp
->l_value
);
1550 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_loyear
, &xs
) != 1) {
1551 error(_("invalid starting year"));
1555 lp
= byword(cp
, end_years
);
1556 rp
->r_hiwasnum
= lp
== NULL
;
1557 if (!rp
->r_hiwasnum
) switch (lp
->l_value
) {
1559 rp
->r_hiyear
= ZIC_MIN
;
1562 rp
->r_hiyear
= ZIC_MAX
;
1565 rp
->r_hiyear
= rp
->r_loyear
;
1567 default: /* "cannot happen" */
1569 _("%s: panic: Invalid l_value %d\n"),
1570 progname
, lp
->l_value
);
1572 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_hiyear
, &xs
) != 1) {
1573 error(_("invalid ending year"));
1576 if (rp
->r_loyear
> rp
->r_hiyear
) {
1577 error(_("starting year greater than ending year"));
1581 rp
->r_yrtype
= NULL
;
1583 if (rp
->r_loyear
== rp
->r_hiyear
) {
1584 error(_("typed single year"));
1587 rp
->r_yrtype
= ecpyalloc(typep
);
1591 ** Accept things such as:
1597 dp
= ecpyalloc(dayp
);
1598 if ((lp
= byword(dp
, lasts
)) != NULL
) {
1599 rp
->r_dycode
= DC_DOWLEQ
;
1600 rp
->r_wday
= lp
->l_value
;
1601 rp
->r_dayofmonth
= len_months
[1][rp
->r_month
];
1603 if ((ep
= strchr(dp
, '<')) != 0)
1604 rp
->r_dycode
= DC_DOWLEQ
;
1605 else if ((ep
= strchr(dp
, '>')) != 0)
1606 rp
->r_dycode
= DC_DOWGEQ
;
1609 rp
->r_dycode
= DC_DOM
;
1611 if (rp
->r_dycode
!= DC_DOM
) {
1614 error(_("invalid day of month"));
1618 if ((lp
= byword(dp
, wday_names
)) == NULL
) {
1619 error(_("invalid weekday name"));
1623 rp
->r_wday
= lp
->l_value
;
1625 if (sscanf(ep
, "%d%c", &rp
->r_dayofmonth
, &xs
) != 1 ||
1626 rp
->r_dayofmonth
<= 0 ||
1627 (rp
->r_dayofmonth
> len_months
[1][rp
->r_month
])) {
1628 error(_("invalid day of month"));
1637 convert(const int_fast32_t val
, char *const buf
)
1641 unsigned char *const b
= (unsigned char *) buf
;
1643 for (i
= 0, shift
= 24; i
< 4; ++i
, shift
-= 8)
1644 b
[i
] = val
>> shift
;
1648 convert64(const zic_t val
, char *const buf
)
1652 unsigned char *const b
= (unsigned char *) buf
;
1654 for (i
= 0, shift
= 56; i
< 8; ++i
, shift
-= 8)
1655 b
[i
] = val
>> shift
;
1659 puttzcode(const int_fast32_t val
, FILE *const fp
)
1664 fwrite(buf
, sizeof buf
, 1, fp
);
1668 puttzcode64(const zic_t val
, FILE *const fp
)
1672 convert64(val
, buf
);
1673 fwrite(buf
, sizeof buf
, 1, fp
);
1677 atcomp(const void *avp
, const void *bvp
)
1679 const zic_t a
= ((const struct attype
*) avp
)->at
;
1680 const zic_t b
= ((const struct attype
*) bvp
)->at
;
1682 return (a
< b
) ? -1 : (a
> b
);
1688 return INT32_MIN
<= x
&& x
<= INT32_MAX
;
1692 writezone(const char *const name
, const char *const string
, char version
)
1695 register ptrdiff_t i
, j
;
1696 register int leapcnt32
, leapi32
;
1697 register ptrdiff_t timecnt32
, timei32
;
1699 static const struct tzhead tzh0
;
1700 static struct tzhead tzh
;
1701 bool dir_checked
= false;
1703 zic_t y2038_boundary
= one
<< 31;
1704 ptrdiff_t nats
= timecnt
+ WORK_AROUND_QTBUG_53071
;
1705 zic_t
*ats
= emalloc(size_product(nats
, sizeof *ats
+ 1));
1706 void *typesptr
= ats
+ nats
;
1707 unsigned char *types
= typesptr
;
1713 qsort(attypes
, timecnt
, sizeof *attypes
, atcomp
);
1718 ptrdiff_t fromi
, toi
;
1722 while (fromi
< timecnt
&& attypes
[fromi
].at
< early_time
)
1724 for ( ; fromi
< timecnt
; ++fromi
) {
1725 if (toi
> 1 && ((attypes
[fromi
].at
+
1726 gmtoffs
[attypes
[toi
- 1].type
]) <=
1727 (attypes
[toi
- 1].at
+
1728 gmtoffs
[attypes
[toi
- 2].type
]))) {
1729 attypes
[toi
- 1].type
=
1730 attypes
[fromi
].type
;
1734 || attypes
[fromi
].dontmerge
1735 || attypes
[toi
- 1].type
!= attypes
[fromi
].type
)
1736 attypes
[toi
++] = attypes
[fromi
];
1741 if (noise
&& timecnt
> 1200) {
1742 if (timecnt
> TZ_MAX_TIMES
)
1743 warning(_("reference clients mishandle"
1744 " more than %d transition times"),
1747 warning(_("pre-2014 clients may mishandle"
1748 " more than 1200 transition times"));
1753 for (i
= 0; i
< timecnt
; ++i
) {
1754 ats
[i
] = attypes
[i
].at
;
1755 types
[i
] = attypes
[i
].type
;
1758 /* Work around QTBUG-53071 for time stamps less than y2038_boundary - 1,
1759 by inserting a no-op transition at time y2038_boundary - 1.
1760 This works only for timestamps before the boundary, which
1761 should be good enough in practice as QTBUG-53071 should be
1762 long-dead by 2038. */
1763 if (WORK_AROUND_QTBUG_53071
&& timecnt
!= 0
1764 && ats
[timecnt
- 1] < y2038_boundary
- 1 && strchr(string
, '<')) {
1765 ats
[timecnt
] = y2038_boundary
- 1;
1766 types
[timecnt
] = types
[timecnt
- 1];
1771 ** Correct for leap seconds.
1773 for (i
= 0; i
< timecnt
; ++i
) {
1776 if (ats
[i
] > trans
[j
] - corr
[j
]) {
1777 ats
[i
] = tadd(ats
[i
], corr
[j
]);
1782 ** Figure out 32-bit-limited starts and counts.
1784 timecnt32
= timecnt
;
1786 leapcnt32
= leapcnt
;
1788 while (timecnt32
> 0 && !is32(ats
[timecnt32
- 1]))
1790 while (timecnt32
> 0 && !is32(ats
[timei32
])) {
1795 ** Output an INT32_MIN "transition" if appropriate; see below.
1797 if (timei32
> 0 && ats
[timei32
] > INT32_MIN
) {
1801 while (leapcnt32
> 0 && !is32(trans
[leapcnt32
- 1]))
1803 while (leapcnt32
> 0 && !is32(trans
[leapi32
])) {
1808 ** Remove old file, if any, to snap links.
1810 if (remove(name
) == 0)
1812 else if (errno
!= ENOENT
) {
1813 const char *e
= strerror(errno
);
1815 fprintf(stderr
, _("%s: Can't remove %s/%s: %s\n"),
1816 progname
, directory
, name
, e
);
1819 fp
= fopen(name
, "wb");
1821 int fopen_errno
= errno
;
1822 if (fopen_errno
== ENOENT
&& !dir_checked
) {
1824 fp
= fopen(name
, "wb");
1825 fopen_errno
= errno
;
1828 fprintf(stderr
, _("%s: Can't create %s/%s: %s\n"),
1829 progname
, directory
, name
, strerror(fopen_errno
));
1833 for (pass
= 1; pass
<= 2; ++pass
) {
1834 register ptrdiff_t thistimei
, thistimecnt
, thistimelim
;
1835 register int thisleapi
, thisleapcnt
, thisleaplim
;
1836 int writetype
[TZ_MAX_TYPES
];
1837 int typemap
[TZ_MAX_TYPES
];
1838 register int thistypecnt
;
1839 char thischars
[TZ_MAX_CHARS
];
1842 int indmap
[TZ_MAX_CHARS
];
1845 thistimei
= timei32
;
1846 thistimecnt
= timecnt32
;
1847 toomanytimes
= thistimecnt
>> 31 >> 1 != 0;
1848 thisleapi
= leapi32
;
1849 thisleapcnt
= leapcnt32
;
1852 thistimecnt
= timecnt
;
1853 toomanytimes
= thistimecnt
>> 31 >> 31 >> 2 != 0;
1855 thisleapcnt
= leapcnt
;
1858 error(_("too many transition times"));
1859 thistimelim
= thistimei
+ thistimecnt
;
1860 thisleaplim
= thisleapi
+ thisleapcnt
;
1861 for (i
= 0; i
< typecnt
; ++i
)
1862 writetype
[i
] = thistimecnt
== timecnt
;
1863 if (thistimecnt
== 0) {
1865 ** No transition times fall in the current
1866 ** (32- or 64-bit) window.
1869 writetype
[typecnt
- 1] = true;
1871 for (i
= thistimei
- 1; i
< thistimelim
; ++i
)
1873 writetype
[types
[i
]] = true;
1875 ** For America/Godthab and Antarctica/Palmer
1878 writetype
[0] = true;
1880 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1882 ** For some pre-2011 systems: if the last-to-be-written
1883 ** standard (or daylight) type has an offset different from the
1884 ** most recently used offset,
1885 ** append an (unused) copy of the most recently used type
1886 ** (to help get global "altzone" and "timezone" variables
1890 register int mrudst
, mrustd
, hidst
, histd
, type
;
1892 hidst
= histd
= mrudst
= mrustd
= -1;
1893 for (i
= thistimei
; i
< thistimelim
; ++i
)
1894 if (isdsts
[types
[i
]])
1896 else mrustd
= types
[i
];
1897 for (i
= 0; i
< typecnt
; ++i
)
1903 if (hidst
>= 0 && mrudst
>= 0 && hidst
!= mrudst
&&
1904 gmtoffs
[hidst
] != gmtoffs
[mrudst
]) {
1905 isdsts
[mrudst
] = -1;
1906 type
= addtype(gmtoffs
[mrudst
],
1907 &chars
[abbrinds
[mrudst
]],
1912 writetype
[type
] = true;
1914 if (histd
>= 0 && mrustd
>= 0 && histd
!= mrustd
&&
1915 gmtoffs
[histd
] != gmtoffs
[mrustd
]) {
1916 isdsts
[mrustd
] = -1;
1917 type
= addtype(gmtoffs
[mrustd
],
1918 &chars
[abbrinds
[mrustd
]],
1923 writetype
[type
] = true;
1926 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1928 for (i
= 0; i
< typecnt
; ++i
)
1929 typemap
[i
] = writetype
[i
] ? thistypecnt
++ : -1;
1930 for (i
= 0; i
< sizeof indmap
/ sizeof indmap
[0]; ++i
)
1933 for (i
= 0; i
< typecnt
; ++i
) {
1934 register char * thisabbr
;
1938 if (indmap
[abbrinds
[i
]] >= 0)
1940 thisabbr
= &chars
[abbrinds
[i
]];
1941 for (j
= 0; j
< thischarcnt
; ++j
)
1942 if (strcmp(&thischars
[j
], thisabbr
) == 0)
1944 if (j
== thischarcnt
) {
1945 strcpy(&thischars
[thischarcnt
], thisabbr
);
1946 thischarcnt
+= strlen(thisabbr
) + 1;
1948 indmap
[abbrinds
[i
]] = j
;
1950 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
1952 memcpy(tzh
.tzh_magic
, TZ_MAGIC
, sizeof tzh
.tzh_magic
);
1953 tzh
.tzh_version
[0] = version
;
1954 convert(thistypecnt
, tzh
.tzh_ttisgmtcnt
);
1955 convert(thistypecnt
, tzh
.tzh_ttisstdcnt
);
1956 convert(thisleapcnt
, tzh
.tzh_leapcnt
);
1957 convert(thistimecnt
, tzh
.tzh_timecnt
);
1958 convert(thistypecnt
, tzh
.tzh_typecnt
);
1959 convert(thischarcnt
, tzh
.tzh_charcnt
);
1970 for (i
= thistimei
; i
< thistimelim
; ++i
)
1973 ** Output an INT32_MIN "transition"
1974 ** if appropriate; see above.
1976 puttzcode(((ats
[i
] < INT32_MIN
) ?
1977 INT32_MIN
: ats
[i
]), fp
);
1978 else puttzcode64(ats
[i
], fp
);
1979 for (i
= thistimei
; i
< thistimelim
; ++i
) {
1982 uc
= typemap
[types
[i
]];
1983 fwrite(&uc
, sizeof uc
, 1, fp
);
1985 for (i
= 0; i
< typecnt
; ++i
)
1987 puttzcode(gmtoffs
[i
], fp
);
1988 putc(isdsts
[i
], fp
);
1989 putc((unsigned char) indmap
[abbrinds
[i
]], fp
);
1991 if (thischarcnt
!= 0)
1992 fwrite(thischars
, sizeof thischars
[0],
1994 for (i
= thisleapi
; i
< thisleaplim
; ++i
) {
1995 register zic_t todo
;
1998 if (timecnt
== 0 || trans
[i
] < ats
[0]) {
2001 if (++j
>= typecnt
) {
2007 while (j
< timecnt
&&
2012 todo
= tadd(trans
[i
], -gmtoffs
[j
]);
2013 } else todo
= trans
[i
];
2015 puttzcode(todo
, fp
);
2016 else puttzcode64(todo
, fp
);
2017 puttzcode(corr
[i
], fp
);
2019 for (i
= 0; i
< typecnt
; ++i
)
2021 putc(ttisstds
[i
], fp
);
2022 for (i
= 0; i
< typecnt
; ++i
)
2024 putc(ttisgmts
[i
], fp
);
2026 fprintf(fp
, "\n%s\n", string
);
2027 close_file(fp
, directory
, name
);
2032 abbroffset(char *buf
, zic_t offset
)
2035 int seconds
, minutes
;
2042 seconds
= offset
% SECSPERMIN
;
2043 offset
/= SECSPERMIN
;
2044 minutes
= offset
% MINSPERHOUR
;
2045 offset
/= MINSPERHOUR
;
2046 if (100 <= offset
) {
2047 error(_("%%z UTC offset magnitude exceeds 99:59:59"));
2052 *p
++ = '0' + offset
/ 10;
2053 *p
++ = '0' + offset
% 10;
2054 if (minutes
| seconds
) {
2055 *p
++ = '0' + minutes
/ 10;
2056 *p
++ = '0' + minutes
% 10;
2058 *p
++ = '0' + seconds
/ 10;
2059 *p
++ = '0' + seconds
% 10;
2068 doabbr(char *abbr
, struct zone
const *zp
, char const *letters
,
2069 zic_t stdoff
, bool doquotes
)
2072 register char * slashp
;
2073 register size_t len
;
2074 char const *format
= zp
->z_format
;
2076 slashp
= strchr(format
, '/');
2077 if (slashp
== NULL
) {
2078 char letterbuf
[PERCENT_Z_LEN_BOUND
+ 1];
2079 if (zp
->z_format_specifier
== 'z')
2080 letters
= abbroffset(letterbuf
, zp
->z_gmtoff
+ stdoff
);
2083 sprintf(abbr
, format
, letters
);
2084 } else if (stdoff
!= 0) {
2085 strcpy(abbr
, slashp
+ 1);
2087 memcpy(abbr
, format
, slashp
- format
);
2088 abbr
[slashp
- format
] = '\0';
2093 for (cp
= abbr
; is_alpha(*cp
); cp
++)
2095 if (len
> 0 && *cp
== '\0')
2097 abbr
[len
+ 2] = '\0';
2098 abbr
[len
+ 1] = '>';
2099 memmove(abbr
+ 1, abbr
, len
);
2105 updateminmax(const zic_t x
)
2114 stringoffset(char *result
, zic_t offset
)
2117 register int minutes
;
2118 register int seconds
;
2119 bool negative
= offset
< 0;
2126 seconds
= offset
% SECSPERMIN
;
2127 offset
/= SECSPERMIN
;
2128 minutes
= offset
% MINSPERHOUR
;
2129 offset
/= MINSPERHOUR
;
2131 if (hours
>= HOURSPERDAY
* DAYSPERWEEK
) {
2135 len
+= sprintf(result
+ len
, "%d", hours
);
2136 if (minutes
!= 0 || seconds
!= 0) {
2137 len
+= sprintf(result
+ len
, ":%02d", minutes
);
2139 len
+= sprintf(result
+ len
, ":%02d", seconds
);
2145 stringrule(char *result
, const struct rule
*const rp
, const zic_t dstoff
,
2148 register zic_t tod
= rp
->r_tod
;
2149 register int compat
= 0;
2151 if (rp
->r_dycode
== DC_DOM
) {
2152 register int month
, total
;
2154 if (rp
->r_dayofmonth
== 29 && rp
->r_month
== TM_FEBRUARY
)
2157 for (month
= 0; month
< rp
->r_month
; ++month
)
2158 total
+= len_months
[0][month
];
2159 /* Omit the "J" in Jan and Feb, as that's shorter. */
2160 if (rp
->r_month
<= 1)
2161 result
+= sprintf(result
, "%d", total
+ rp
->r_dayofmonth
- 1);
2163 result
+= sprintf(result
, "J%d", total
+ rp
->r_dayofmonth
);
2166 register int wday
= rp
->r_wday
;
2167 register int wdayoff
;
2169 if (rp
->r_dycode
== DC_DOWGEQ
) {
2170 wdayoff
= (rp
->r_dayofmonth
- 1) % DAYSPERWEEK
;
2174 tod
+= wdayoff
* SECSPERDAY
;
2175 week
= 1 + (rp
->r_dayofmonth
- 1) / DAYSPERWEEK
;
2176 } else if (rp
->r_dycode
== DC_DOWLEQ
) {
2177 if (rp
->r_dayofmonth
== len_months
[1][rp
->r_month
])
2180 wdayoff
= rp
->r_dayofmonth
% DAYSPERWEEK
;
2184 tod
+= wdayoff
* SECSPERDAY
;
2185 week
= rp
->r_dayofmonth
/ DAYSPERWEEK
;
2187 } else return -1; /* "cannot happen" */
2189 wday
+= DAYSPERWEEK
;
2190 result
+= sprintf(result
, "M%d.%d.%d",
2191 rp
->r_month
+ 1, week
, wday
);
2195 if (rp
->r_todisstd
&& rp
->r_stdoff
== 0)
2197 if (tod
!= 2 * SECSPERMIN
* MINSPERHOUR
) {
2199 if (! stringoffset(result
, tod
))
2204 } else if (SECSPERDAY
<= tod
) {
2213 rule_cmp(struct rule
const *a
, struct rule
const *b
)
2219 if (a
->r_hiyear
!= b
->r_hiyear
)
2220 return a
->r_hiyear
< b
->r_hiyear
? -1 : 1;
2221 if (a
->r_month
- b
->r_month
!= 0)
2222 return a
->r_month
- b
->r_month
;
2223 return a
->r_dayofmonth
- b
->r_dayofmonth
;
2226 enum { YEAR_BY_YEAR_ZONE
= 1 };
2229 stringzone(char *result
, struct zone
const *zpfirst
, ptrdiff_t zonecount
)
2231 register const struct zone
* zp
;
2232 register struct rule
* rp
;
2233 register struct rule
* stdrp
;
2234 register struct rule
* dstrp
;
2235 register ptrdiff_t i
;
2236 register const char * abbrvar
;
2237 register int compat
= 0;
2241 struct rule stdr
, dstr
;
2244 zp
= zpfirst
+ zonecount
- 1;
2245 stdrp
= dstrp
= NULL
;
2246 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2247 rp
= &zp
->z_rules
[i
];
2248 if (rp
->r_hiwasnum
|| rp
->r_hiyear
!= ZIC_MAX
)
2250 if (rp
->r_yrtype
!= NULL
)
2252 if (rp
->r_stdoff
== 0) {
2262 if (stdrp
== NULL
&& dstrp
== NULL
) {
2264 ** There are no rules running through "max".
2265 ** Find the latest std rule in stdabbrrp
2266 ** and latest rule of any type in stdrp.
2268 register struct rule
*stdabbrrp
= NULL
;
2269 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2270 rp
= &zp
->z_rules
[i
];
2271 if (rp
->r_stdoff
== 0 && rule_cmp(stdabbrrp
, rp
) < 0)
2273 if (rule_cmp(stdrp
, rp
) < 0)
2277 ** Horrid special case: if year is 2037,
2278 ** presume this is a zone handled on a year-by-year basis;
2279 ** do not try to apply a rule to the zone.
2281 if (stdrp
!= NULL
&& stdrp
->r_hiyear
== 2037)
2282 return YEAR_BY_YEAR_ZONE
;
2284 if (stdrp
!= NULL
&& stdrp
->r_stdoff
!= 0) {
2285 /* Perpetual DST. */
2286 dstr
.r_month
= TM_JANUARY
;
2287 dstr
.r_dycode
= DC_DOM
;
2288 dstr
.r_dayofmonth
= 1;
2290 dstr
.r_todisstd
= dstr
.r_todisgmt
= false;
2291 dstr
.r_stdoff
= stdrp
->r_stdoff
;
2292 dstr
.r_abbrvar
= stdrp
->r_abbrvar
;
2293 stdr
.r_month
= TM_DECEMBER
;
2294 stdr
.r_dycode
= DC_DOM
;
2295 stdr
.r_dayofmonth
= 31;
2296 stdr
.r_tod
= SECSPERDAY
+ stdrp
->r_stdoff
;
2297 stdr
.r_todisstd
= stdr
.r_todisgmt
= false;
2300 = (stdabbrrp
? stdabbrrp
->r_abbrvar
: "");
2305 if (stdrp
== NULL
&& (zp
->z_nrules
!= 0 || zp
->z_stdoff
!= 0))
2307 abbrvar
= (stdrp
== NULL
) ? "" : stdrp
->r_abbrvar
;
2308 len
= doabbr(result
, zp
, abbrvar
, 0, true);
2309 offsetlen
= stringoffset(result
+ len
, -zp
->z_gmtoff
);
2317 len
+= doabbr(result
+ len
, zp
, dstrp
->r_abbrvar
, dstrp
->r_stdoff
, true);
2318 if (dstrp
->r_stdoff
!= SECSPERMIN
* MINSPERHOUR
) {
2319 offsetlen
= stringoffset(result
+ len
,
2320 -(zp
->z_gmtoff
+ dstrp
->r_stdoff
));
2327 result
[len
++] = ',';
2328 c
= stringrule(result
+ len
, dstrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2335 len
+= strlen(result
+ len
);
2336 result
[len
++] = ',';
2337 c
= stringrule(result
+ len
, stdrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2348 outzone(const struct zone
*zpfirst
, ptrdiff_t zonecount
)
2350 register const struct zone
* zp
;
2351 register struct rule
* rp
;
2352 register ptrdiff_t i
, j
;
2353 register bool usestart
, useuntil
;
2354 register zic_t starttime
, untiltime
;
2355 register zic_t gmtoff
;
2356 register zic_t stdoff
;
2357 register zic_t year
;
2358 register zic_t startoff
;
2359 register bool startttisstd
;
2360 register bool startttisgmt
;
2362 register char * startbuf
;
2364 register char * envvar
;
2365 register int max_abbr_len
;
2366 register int max_envvar_len
;
2367 register bool prodstic
; /* all rules are min to max */
2368 register int compat
;
2369 register bool do_extend
;
2370 register char version
;
2371 ptrdiff_t lastatmax
= -1;
2373 zic_t y2038_boundary
= one
<< 31;
2376 max_abbr_len
= 2 + max_format_len
+ max_abbrvar_len
;
2377 max_envvar_len
= 2 * max_abbr_len
+ 5 * 9;
2378 startbuf
= emalloc(max_abbr_len
+ 1);
2379 ab
= emalloc(max_abbr_len
+ 1);
2380 envvar
= emalloc(max_envvar_len
+ 1);
2381 INITIALIZE(untiltime
);
2382 INITIALIZE(starttime
);
2384 ** Now. . .finally. . .generate some useful data!
2389 prodstic
= zonecount
== 1;
2391 ** Thanks to Earl Chew
2392 ** for noting the need to unconditionally initialize startttisstd.
2394 startttisstd
= false;
2395 startttisgmt
= false;
2396 min_year
= max_year
= EPOCH_YEAR
;
2398 updateminmax(leapminyear
);
2399 updateminmax(leapmaxyear
+ (leapmaxyear
< ZIC_MAX
));
2401 for (i
= 0; i
< zonecount
; ++i
) {
2403 if (i
< zonecount
- 1)
2404 updateminmax(zp
->z_untilrule
.r_loyear
);
2405 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2406 rp
= &zp
->z_rules
[j
];
2408 updateminmax(rp
->r_loyear
);
2410 updateminmax(rp
->r_hiyear
);
2411 if (rp
->r_lowasnum
|| rp
->r_hiwasnum
)
2416 ** Generate lots of data if a rule can't cover all future times.
2418 compat
= stringzone(envvar
, zpfirst
, zonecount
);
2419 version
= compat
< 2013 ? ZIC_VERSION_PRE_2013
: ZIC_VERSION
;
2420 do_extend
= compat
< 0 || compat
== YEAR_BY_YEAR_ZONE
;
2424 _("no POSIX environment variable for zone"),
2426 else if (compat
!= 0 && compat
!= YEAR_BY_YEAR_ZONE
) {
2427 /* Circa-COMPAT clients, and earlier clients, might
2428 not work for this zone when given dates before
2429 1970 or after 2038. */
2430 warning(_("%s: pre-%d clients may mishandle"
2431 " distant timestamps"),
2432 zpfirst
->z_name
, compat
);
2437 ** Search through a couple of extra years past the obvious
2438 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2439 ** rule applies from 2012 onwards and has transitions in March
2440 ** and September, plus some one-off transitions in November
2441 ** 2013. If zic looked only at the last 400 years, it would
2442 ** set max_year=2413, with the intent that the 400 years 2014
2443 ** through 2413 will be repeated. The last transition listed
2444 ** in the tzfile would be in 2413-09, less than 400 years
2445 ** after the last one-off transition in 2013-11. Two years
2446 ** might be overkill, but with the kind of edge cases
2447 ** available we're not sure that one year would suffice.
2449 enum { years_of_observations
= YEARSPERREPEAT
+ 2 };
2451 if (min_year
>= ZIC_MIN
+ years_of_observations
)
2452 min_year
-= years_of_observations
;
2453 else min_year
= ZIC_MIN
;
2454 if (max_year
<= ZIC_MAX
- years_of_observations
)
2455 max_year
+= years_of_observations
;
2456 else max_year
= ZIC_MAX
;
2458 ** Regardless of any of the above,
2459 ** for a "proDSTic" zone which specifies that its rules
2460 ** always have and always will be in effect,
2461 ** we only need one cycle to define the zone.
2465 max_year
= min_year
+ years_of_observations
;
2469 ** For the benefit of older systems,
2470 ** generate data from 1900 through 2038.
2472 if (min_year
> 1900)
2474 max_year0
= max_year
;
2475 if (max_year
< 2038)
2477 for (i
= 0; i
< zonecount
; ++i
) {
2479 ** A guess that may well be corrected later.
2483 usestart
= i
> 0 && (zp
- 1)->z_untiltime
> early_time
;
2484 useuntil
= i
< (zonecount
- 1);
2485 if (useuntil
&& zp
->z_untiltime
<= early_time
)
2487 gmtoff
= zp
->z_gmtoff
;
2488 eat(zp
->z_filename
, zp
->z_linenum
);
2490 startoff
= zp
->z_gmtoff
;
2491 if (zp
->z_nrules
== 0) {
2492 stdoff
= zp
->z_stdoff
;
2493 doabbr(startbuf
, zp
, NULL
, stdoff
, false);
2494 type
= addtype(oadd(zp
->z_gmtoff
, stdoff
),
2495 startbuf
, stdoff
!= 0, startttisstd
,
2498 addtt(starttime
, type
);
2500 } else addtt(early_time
, type
);
2501 } else for (year
= min_year
; year
<= max_year
; ++year
) {
2502 if (useuntil
&& year
> zp
->z_untilrule
.r_hiyear
)
2505 ** Mark which rules to do in the current year.
2506 ** For those to do, calculate rpytime(rp, year);
2508 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2509 rp
= &zp
->z_rules
[j
];
2510 eats(zp
->z_filename
, zp
->z_linenum
,
2511 rp
->r_filename
, rp
->r_linenum
);
2512 rp
->r_todo
= year
>= rp
->r_loyear
&&
2513 year
<= rp
->r_hiyear
&&
2514 yearistype(year
, rp
->r_yrtype
);
2516 rp
->r_temp
= rpytime(rp
, year
);
2518 = (rp
->r_temp
< y2038_boundary
2519 || year
<= max_year0
);
2523 register ptrdiff_t k
;
2524 register zic_t jtime
, ktime
;
2525 register zic_t offset
;
2530 ** Turn untiltime into UT
2531 ** assuming the current gmtoff and
2534 untiltime
= zp
->z_untiltime
;
2535 if (!zp
->z_untilrule
.r_todisgmt
)
2536 untiltime
= tadd(untiltime
,
2538 if (!zp
->z_untilrule
.r_todisstd
)
2539 untiltime
= tadd(untiltime
,
2543 ** Find the rule (of those to do, if any)
2544 ** that takes effect earliest in the year.
2547 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2548 rp
= &zp
->z_rules
[j
];
2551 eats(zp
->z_filename
, zp
->z_linenum
,
2552 rp
->r_filename
, rp
->r_linenum
);
2553 offset
= rp
->r_todisgmt
? 0 : gmtoff
;
2554 if (!rp
->r_todisstd
)
2555 offset
= oadd(offset
, stdoff
);
2557 if (jtime
== min_time
||
2560 jtime
= tadd(jtime
, -offset
);
2561 if (k
< 0 || jtime
< ktime
) {
2564 } else if (jtime
== ktime
) {
2565 char const *dup_rules_msg
=
2566 _("two rules for same instant");
2567 eats(zp
->z_filename
, zp
->z_linenum
,
2568 rp
->r_filename
, rp
->r_linenum
);
2569 warning("%s", dup_rules_msg
);
2570 rp
= &zp
->z_rules
[k
];
2571 eats(zp
->z_filename
, zp
->z_linenum
,
2572 rp
->r_filename
, rp
->r_linenum
);
2573 error("%s", dup_rules_msg
);
2577 break; /* go on to next year */
2578 rp
= &zp
->z_rules
[k
];
2580 if (useuntil
&& ktime
>= untiltime
)
2582 stdoff
= rp
->r_stdoff
;
2583 if (usestart
&& ktime
== starttime
)
2586 if (ktime
< starttime
) {
2587 startoff
= oadd(zp
->z_gmtoff
,
2589 doabbr(startbuf
, zp
,
2595 if (*startbuf
== '\0' &&
2596 startoff
== oadd(zp
->z_gmtoff
,
2605 eats(zp
->z_filename
, zp
->z_linenum
,
2606 rp
->r_filename
, rp
->r_linenum
);
2607 doabbr(ab
, zp
, rp
->r_abbrvar
,
2608 rp
->r_stdoff
, false);
2609 offset
= oadd(zp
->z_gmtoff
, rp
->r_stdoff
);
2610 type
= addtype(offset
, ab
, rp
->r_stdoff
!= 0,
2611 rp
->r_todisstd
, rp
->r_todisgmt
);
2612 if (rp
->r_hiyear
== ZIC_MAX
2613 && ! (0 <= lastatmax
2614 && ktime
< attypes
[lastatmax
].at
))
2615 lastatmax
= timecnt
;
2620 if (*startbuf
== '\0' &&
2621 zp
->z_format
!= NULL
&&
2622 strchr(zp
->z_format
, '%') == NULL
&&
2623 strchr(zp
->z_format
, '/') == NULL
)
2624 strcpy(startbuf
, zp
->z_format
);
2625 eat(zp
->z_filename
, zp
->z_linenum
);
2626 if (*startbuf
== '\0')
2627 error(_("can't determine time zone abbreviation to use just after until time"));
2628 else addtt(starttime
,
2629 addtype(startoff
, startbuf
,
2630 startoff
!= zp
->z_gmtoff
,
2635 ** Now we may get to set starttime for the next zone line.
2638 startttisstd
= zp
->z_untilrule
.r_todisstd
;
2639 startttisgmt
= zp
->z_untilrule
.r_todisgmt
;
2640 starttime
= zp
->z_untiltime
;
2642 starttime
= tadd(starttime
, -stdoff
);
2644 starttime
= tadd(starttime
, -gmtoff
);
2648 attypes
[lastatmax
].dontmerge
= true;
2651 ** If we're extending the explicitly listed observations
2652 ** for 400 years because we can't fill the POSIX-TZ field,
2653 ** check whether we actually ended up explicitly listing
2654 ** observations through that period. If there aren't any
2655 ** near the end of the 400-year period, add a redundant
2656 ** one at the end of the final year, to make it clear
2657 ** that we are claiming to have definite knowledge of
2658 ** the lack of transitions up to that point.
2661 struct attype
*lastat
;
2662 xr
.r_month
= TM_JANUARY
;
2663 xr
.r_dycode
= DC_DOM
;
2664 xr
.r_dayofmonth
= 1;
2666 for (lastat
= &attypes
[0], i
= 1; i
< timecnt
; i
++)
2667 if (attypes
[i
].at
> lastat
->at
)
2668 lastat
= &attypes
[i
];
2669 if (lastat
->at
< rpytime(&xr
, max_year
- 1)) {
2670 addtt(rpytime(&xr
, max_year
+ 1), typecnt
-1);
2671 attypes
[timecnt
- 1].dontmerge
= true;
2674 writezone(zpfirst
->z_name
, envvar
, version
);
2681 addtt(zic_t starttime
, int type
)
2683 if (starttime
<= early_time
2684 || (timecnt
== 1 && attypes
[0].at
< early_time
)) {
2685 gmtoffs
[0] = gmtoffs
[type
];
2686 isdsts
[0] = isdsts
[type
];
2687 ttisstds
[0] = ttisstds
[type
];
2688 ttisgmts
[0] = ttisgmts
[type
];
2689 if (abbrinds
[type
] != 0)
2690 strcpy(chars
, &chars
[abbrinds
[type
]]);
2692 charcnt
= strlen(chars
) + 1;
2697 attypes
= growalloc(attypes
, sizeof *attypes
, timecnt
, &timecnt_alloc
);
2698 attypes
[timecnt
].at
= starttime
;
2699 attypes
[timecnt
].dontmerge
= false;
2700 attypes
[timecnt
].type
= type
;
2705 addtype(zic_t gmtoff
, char const *abbr
, bool isdst
, bool ttisstd
, bool ttisgmt
)
2710 ** See if there's already an entry for this zone type.
2711 ** If so, just return its index.
2713 for (i
= 0; i
< typecnt
; ++i
) {
2714 if (gmtoff
== gmtoffs
[i
] && isdst
== isdsts
[i
] &&
2715 strcmp(abbr
, &chars
[abbrinds
[i
]]) == 0 &&
2716 ttisstd
== ttisstds
[i
] &&
2717 ttisgmt
== ttisgmts
[i
])
2721 ** There isn't one; add a new one, unless there are already too
2724 if (typecnt
>= TZ_MAX_TYPES
) {
2725 error(_("too many local time types"));
2728 if (! (-1L - 2147483647L <= gmtoff
&& gmtoff
<= 2147483647L)) {
2729 error(_("UT offset out of range"));
2732 gmtoffs
[i
] = gmtoff
;
2734 ttisstds
[i
] = ttisstd
;
2735 ttisgmts
[i
] = ttisgmt
;
2737 for (j
= 0; j
< charcnt
; ++j
)
2738 if (strcmp(&chars
[j
], abbr
) == 0)
2748 leapadd(zic_t t
, bool positive
, int rolling
, int count
)
2752 if (leapcnt
+ (positive
? count
: 1) > TZ_MAX_LEAPS
) {
2753 error(_("too many leap seconds"));
2756 for (i
= 0; i
< leapcnt
; ++i
)
2757 if (t
<= trans
[i
]) {
2758 if (t
== trans
[i
]) {
2759 error(_("repeated leap second moment"));
2765 for (j
= leapcnt
; j
> i
; --j
) {
2766 trans
[j
] = trans
[j
- 1];
2767 corr
[j
] = corr
[j
- 1];
2768 roll
[j
] = roll
[j
- 1];
2771 corr
[i
] = positive
? 1 : -count
;
2774 } while (positive
&& --count
!= 0);
2781 register zic_t last
= 0;
2784 ** propagate leap seconds forward
2786 for (i
= 0; i
< leapcnt
; ++i
) {
2787 trans
[i
] = tadd(trans
[i
], last
);
2788 last
= corr
[i
] += last
;
2793 shellquote(char *b
, char const *s
)
2798 *b
++ = '\'', *b
++ = '\\', *b
++ = '\'';
2806 yearistype(zic_t year
, const char *type
)
2812 if (type
== NULL
|| *type
== '\0')
2814 buf
= emalloc(1 + 4 * strlen(yitcommand
) + 2
2815 + INT_STRLEN_MAXIMUM(zic_t
) + 2 + 4 * strlen(type
) + 2);
2816 b
= shellquote(buf
, yitcommand
);
2818 b
+= sprintf(b
, "%"PRIdZIC
, year
);
2820 b
= shellquote(b
, type
);
2822 result
= system(buf
);
2823 if (WIFEXITED(result
)) {
2824 int status
= WEXITSTATUS(result
);
2830 error(_("Wild result from command execution"));
2831 fprintf(stderr
, _("%s: command was '%s', result was %d\n"),
2832 progname
, buf
, result
);
2836 /* Is A a space character in the C locale? */
2843 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2848 /* Is A an alphabetic character in the C locale? */
2855 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2856 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2857 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2858 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2859 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2860 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2861 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2862 case 'v': case 'w': case 'x': case 'y': case 'z':
2867 /* If A is an uppercase character in the C locale, return its lowercase
2868 counterpart. Otherwise, return A. */
2874 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2875 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2876 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2877 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2878 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2879 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2880 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2881 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2882 case 'Y': return 'y'; case 'Z': return 'z';
2886 /* case-insensitive equality */
2887 static ATTRIBUTE_PURE
bool
2888 ciequal(register const char *ap
, register const char *bp
)
2890 while (lowerit(*ap
) == lowerit(*bp
++))
2896 static ATTRIBUTE_PURE
bool
2897 itsabbr(register const char *abbr
, register const char *word
)
2899 if (lowerit(*abbr
) != lowerit(*word
))
2902 while (*++abbr
!= '\0')
2906 } while (lowerit(*word
++) != lowerit(*abbr
));
2910 static ATTRIBUTE_PURE
const struct lookup
*
2911 byword(const char *word
, const struct lookup
*table
)
2913 register const struct lookup
* foundlp
;
2914 register const struct lookup
* lp
;
2916 if (word
== NULL
|| table
== NULL
)
2919 ** Look for exact match.
2921 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2922 if (ciequal(word
, lp
->l_word
))
2925 ** Look for inexact match.
2928 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2929 if (itsabbr(word
, lp
->l_word
)) {
2930 if (foundlp
== NULL
)
2932 else return NULL
; /* multiple inexact matches */
2938 getfields(register char *cp
)
2941 register char ** array
;
2946 array
= emalloc(size_product(strlen(cp
) + 1, sizeof *array
));
2949 while (is_space(*cp
))
2951 if (*cp
== '\0' || *cp
== '#')
2953 array
[nsubs
++] = dp
= cp
;
2955 if ((*dp
= *cp
++) != '"')
2957 else while ((*dp
= *cp
++) != '"')
2961 error(_("Odd number of quotation marks"));
2964 } while (*cp
&& *cp
!= '#' && !is_space(*cp
));
2969 array
[nsubs
] = NULL
;
2973 static _Noreturn
void
2976 error(_("time overflow"));
2980 static ATTRIBUTE_PURE zic_t
2981 oadd(zic_t t1
, zic_t t2
)
2983 if (t1
< 0 ? t2
< ZIC_MIN
- t1
: ZIC_MAX
- t1
< t2
)
2988 static ATTRIBUTE_PURE zic_t
2989 tadd(zic_t t1
, zic_t t2
)
2992 if (t2
< min_time
- t1
) {
2998 if (max_time
- t1
< t2
) {
3008 ** Given a rule, and a year, compute the date (in seconds since January 1,
3009 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
3013 rpytime(const struct rule
*rp
, zic_t wantedy
)
3016 register zic_t dayoff
; /* with a nod to Margaret O. */
3017 register zic_t t
, y
;
3019 if (wantedy
== ZIC_MIN
)
3021 if (wantedy
== ZIC_MAX
)
3026 while (wantedy
!= y
) {
3028 i
= len_years
[isleap(y
)];
3032 i
= -len_years
[isleap(y
)];
3034 dayoff
= oadd(dayoff
, i
);
3036 while (m
!= rp
->r_month
) {
3037 i
= len_months
[isleap(y
)][m
];
3038 dayoff
= oadd(dayoff
, i
);
3041 i
= rp
->r_dayofmonth
;
3042 if (m
== TM_FEBRUARY
&& i
== 29 && !isleap(y
)) {
3043 if (rp
->r_dycode
== DC_DOWLEQ
)
3046 error(_("use of 2/29 in non leap-year"));
3051 dayoff
= oadd(dayoff
, i
);
3052 if (rp
->r_dycode
== DC_DOWGEQ
|| rp
->r_dycode
== DC_DOWLEQ
) {
3053 register zic_t wday
;
3055 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3058 ** Don't trust mod of negative numbers.
3061 wday
= (wday
+ dayoff
) % LDAYSPERWEEK
;
3063 wday
-= ((-dayoff
) % LDAYSPERWEEK
);
3065 wday
+= LDAYSPERWEEK
;
3067 while (wday
!= rp
->r_wday
)
3068 if (rp
->r_dycode
== DC_DOWGEQ
) {
3069 dayoff
= oadd(dayoff
, 1);
3070 if (++wday
>= LDAYSPERWEEK
)
3074 dayoff
= oadd(dayoff
, -1);
3076 wday
= LDAYSPERWEEK
- 1;
3079 if (i
< 0 || i
>= len_months
[isleap(y
)][m
]) {
3081 warning(_("rule goes past start/end of month; \
3082 will not work with pre-2004 versions of zic"));
3085 if (dayoff
< min_time
/ SECSPERDAY
)
3087 if (dayoff
> max_time
/ SECSPERDAY
)
3089 t
= (zic_t
) dayoff
* SECSPERDAY
;
3090 return tadd(t
, rp
->r_tod
);
3094 newabbr(const char *string
)
3098 if (strcmp(string
, GRANDPARENTED
) != 0) {
3099 register const char * cp
;
3104 while (is_alpha(*cp
) || ('0' <= *cp
&& *cp
<= '9')
3105 || *cp
== '-' || *cp
== '+')
3107 if (noise
&& cp
- string
< 3)
3108 mp
= _("time zone abbreviation has fewer than 3 characters");
3109 if (cp
- string
> ZIC_MAX_ABBR_LEN_WO_WARN
)
3110 mp
= _("time zone abbreviation has too many characters");
3112 mp
= _("time zone abbreviation differs from POSIX standard");
3114 warning("%s (%s)", mp
, string
);
3116 i
= strlen(string
) + 1;
3117 if (charcnt
+ i
> TZ_MAX_CHARS
) {
3118 error(_("too many, or too long, time zone abbreviations"));
3121 strcpy(&chars
[charcnt
], string
);
3125 /* Ensure that the directories of ARGNAME exist, by making any missing
3126 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3127 do it for ARGNAME too. Exit with failure if there is trouble.
3128 Do not consider an existing non-directory to be trouble. */
3130 mkdirs(char const *argname
, bool ancestors
)
3132 register char * name
;
3135 cp
= name
= ecpyalloc(argname
);
3137 /* Do not mkdir a root directory, as it must exist. */
3138 #ifdef HAVE_DOS_FILE_NAMES
3139 if (is_alpha(name
[0]) && name
[1] == ':')
3145 while (cp
&& ((cp
= strchr(cp
, '/')) || !ancestors
)) {
3149 ** Try to create it. It's OK if creation fails because
3150 ** the directory already exists, perhaps because some
3151 ** other process just created it. For simplicity do
3152 ** not check first whether it already exists, as that
3153 ** is checked anyway if the mkdir fails.
3155 if (mkdir(name
, MKDIR_UMASK
) != 0) {
3156 /* For speed, skip itsdir if errno == EEXIST. Since
3157 mkdirs is called only after open fails with ENOENT
3158 on a subfile, EEXIST implies itsdir here. */
3160 if (err
!= EEXIST
&& !itsdir(name
)) {
3161 error(_("%s: Can't create directory %s: %s"),
3162 progname
, name
, strerror(err
));