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 and printf format for line numbers. */
50 typedef intmax_t lineno
;
51 #define PRIdLINENO PRIdMAX
54 const char * r_filename
;
58 zic_t r_loyear
; /* for example, 1986 */
59 zic_t r_hiyear
; /* for example, 1986 */
60 const char * r_yrtype
;
64 int r_month
; /* 0..11 */
66 int r_dycode
; /* see below */
70 zic_t r_tod
; /* time from midnight */
71 bool r_todisstd
; /* above is standard time if 1 */
72 /* or wall clock time if 0 */
73 bool r_todisgmt
; /* above is GMT if 1 */
74 /* or local time if 0 */
75 zic_t r_stdoff
; /* offset from standard time */
76 const char * r_abbrvar
; /* variable part of abbreviation */
78 bool r_todo
; /* a rule to do (used in outzone) */
79 zic_t r_temp
; /* used in outzone */
83 ** r_dycode r_dayofmonth r_wday
86 #define DC_DOM 0 /* 1..31 */ /* unused */
87 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
88 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
91 const char * z_filename
;
97 const char * z_format
;
98 char z_format_specifier
;
102 struct rule
* z_rules
;
105 struct rule z_untilrule
;
109 #if !HAVE_POSIX_DECLS
110 extern int getopt(int argc
, char * const argv
[],
111 const char * options
);
112 extern int link(const char * fromname
, const char * toname
);
113 extern char * optarg
;
118 # define link(from, to) (errno = ENOTSUP, -1)
121 # define readlink(file, buf, size) (errno = ENOTSUP, -1)
122 # define symlink(from, to) (errno = ENOTSUP, -1)
123 # define S_ISLNK(m) 0
125 #ifndef AT_SYMLINK_FOLLOW
126 # define linkat(fromdir, from, todir, to, flag) \
127 (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
130 static void addtt(zic_t starttime
, int type
);
131 static int addtype(zic_t
, char const *, bool, bool, bool);
132 static void leapadd(zic_t
, bool, int, int);
133 static void adjleap(void);
134 static void associate(void);
135 static void dolink(const char *, const char *, bool);
136 static char ** getfields(char * buf
);
137 static zic_t
gethms(const char * string
, const char * errstring
,
139 static void infile(const char * filename
);
140 static void inleap(char ** fields
, int nfields
);
141 static void inlink(char ** fields
, int nfields
);
142 static void inrule(char ** fields
, int nfields
);
143 static bool inzcont(char ** fields
, int nfields
);
144 static bool inzone(char ** fields
, int nfields
);
145 static bool inzsub(char **, int, bool);
146 static bool itsdir(char const *);
147 static bool itssymlink(char const *);
148 static bool is_alpha(char a
);
149 static char lowerit(char);
150 static void mkdirs(char const *, bool);
151 static void newabbr(const char * abbr
);
152 static zic_t
oadd(zic_t t1
, zic_t t2
);
153 static void outzone(const struct zone
* zp
, ptrdiff_t ntzones
);
154 static zic_t
rpytime(const struct rule
* rp
, zic_t wantedy
);
155 static void rulesub(struct rule
* rp
,
156 const char * loyearp
, const char * hiyearp
,
157 const char * typep
, const char * monthp
,
158 const char * dayp
, const char * timep
);
159 static zic_t
tadd(zic_t t1
, zic_t t2
);
160 static bool yearistype(zic_t year
, const char * type
);
162 /* Bound on length of what %z can expand to. */
163 enum { PERCENT_Z_LEN_BOUND
= sizeof "+995959" - 1 };
165 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
166 tz binary files whose POSIX-TZ-style strings contain '<'; see
167 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
168 workaround will no longer be needed when Qt 5.6.1 and earlier are
169 obsolete, say in the year 2021. */
170 enum { WORK_AROUND_QTBUG_53071
= true };
174 static bool warnings
;
175 static const char * filename
;
177 static bool leapseen
;
178 static zic_t leapminyear
;
179 static zic_t leapmaxyear
;
180 static lineno linenum
;
181 static int max_abbrvar_len
= PERCENT_Z_LEN_BOUND
;
182 static int max_format_len
;
183 static zic_t max_year
;
184 static zic_t min_year
;
186 static const char * rfilename
;
187 static lineno rlinenum
;
188 static const char * progname
;
189 static ptrdiff_t timecnt
;
190 static ptrdiff_t timecnt_alloc
;
203 ** Which fields are which on a Zone line.
211 #define ZF_TILMONTH 6
214 #define ZONE_MINFIELDS 5
215 #define ZONE_MAXFIELDS 9
218 ** Which fields are which on a Zone continuation line.
224 #define ZFC_TILYEAR 3
225 #define ZFC_TILMONTH 4
227 #define ZFC_TILTIME 6
228 #define ZONEC_MINFIELDS 3
229 #define ZONEC_MAXFIELDS 7
232 ** Which files are which on a Rule line.
244 #define RULE_FIELDS 10
247 ** Which fields are which on a Link line.
252 #define LINK_FIELDS 3
255 ** Which fields are which on a Leap line.
264 #define LEAP_FIELDS 7
274 static struct rule
* rules
;
275 static ptrdiff_t nrules
; /* number of rules */
276 static ptrdiff_t nrules_alloc
;
278 static struct zone
* zones
;
279 static ptrdiff_t nzones
; /* number of zones */
280 static ptrdiff_t nzones_alloc
;
283 const char * l_filename
;
289 static struct link
* links
;
290 static ptrdiff_t nlinks
;
291 static ptrdiff_t nlinks_alloc
;
298 static struct lookup
const * byword(const char * string
,
299 const struct lookup
* lp
);
301 static struct lookup
const line_codes
[] = {
309 static struct lookup
const mon_names
[] = {
310 { "January", TM_JANUARY
},
311 { "February", TM_FEBRUARY
},
312 { "March", TM_MARCH
},
313 { "April", TM_APRIL
},
317 { "August", TM_AUGUST
},
318 { "September", TM_SEPTEMBER
},
319 { "October", TM_OCTOBER
},
320 { "November", TM_NOVEMBER
},
321 { "December", TM_DECEMBER
},
325 static struct lookup
const wday_names
[] = {
326 { "Sunday", TM_SUNDAY
},
327 { "Monday", TM_MONDAY
},
328 { "Tuesday", TM_TUESDAY
},
329 { "Wednesday", TM_WEDNESDAY
},
330 { "Thursday", TM_THURSDAY
},
331 { "Friday", TM_FRIDAY
},
332 { "Saturday", TM_SATURDAY
},
336 static struct lookup
const lasts
[] = {
337 { "last-Sunday", TM_SUNDAY
},
338 { "last-Monday", TM_MONDAY
},
339 { "last-Tuesday", TM_TUESDAY
},
340 { "last-Wednesday", TM_WEDNESDAY
},
341 { "last-Thursday", TM_THURSDAY
},
342 { "last-Friday", TM_FRIDAY
},
343 { "last-Saturday", TM_SATURDAY
},
347 static struct lookup
const begin_years
[] = {
348 { "minimum", YR_MINIMUM
},
349 { "maximum", YR_MAXIMUM
},
353 static struct lookup
const end_years
[] = {
354 { "minimum", YR_MINIMUM
},
355 { "maximum", YR_MAXIMUM
},
360 static struct lookup
const leap_types
[] = {
362 { "Stationary", false },
366 static const int len_months
[2][MONSPERYEAR
] = {
367 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
368 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
371 static const int len_years
[2] = {
372 DAYSPERNYEAR
, DAYSPERLYEAR
375 static struct attype
{
380 static zic_t gmtoffs
[TZ_MAX_TYPES
];
381 static char isdsts
[TZ_MAX_TYPES
];
382 static unsigned char abbrinds
[TZ_MAX_TYPES
];
383 static bool ttisstds
[TZ_MAX_TYPES
];
384 static bool ttisgmts
[TZ_MAX_TYPES
];
385 static char chars
[TZ_MAX_CHARS
];
386 static zic_t trans
[TZ_MAX_LEAPS
];
387 static zic_t corr
[TZ_MAX_LEAPS
];
388 static char roll
[TZ_MAX_LEAPS
];
391 ** Memory allocation.
394 static _Noreturn
void
395 memory_exhausted(const char *msg
)
397 fprintf(stderr
, _("%s: Memory exhausted: %s\n"), progname
, msg
);
401 static ATTRIBUTE_PURE
size_t
402 size_product(size_t nitems
, size_t itemsize
)
404 if (SIZE_MAX
/ itemsize
< nitems
)
405 memory_exhausted(_("size overflow"));
406 return nitems
* itemsize
;
411 strdup(char const *str
)
413 char *result
= malloc(strlen(str
) + 1);
414 return result
? strcpy(result
, str
) : result
;
418 static ATTRIBUTE_PURE
void *
422 memory_exhausted(strerror(errno
));
429 return memcheck(malloc(size
));
433 erealloc(void *ptr
, size_t size
)
435 return memcheck(realloc(ptr
, size
));
439 ecpyalloc (char const *str
)
441 return memcheck(strdup(str
));
445 growalloc(void *ptr
, size_t itemsize
, ptrdiff_t nitems
, ptrdiff_t *nitems_alloc
)
447 if (nitems
< *nitems_alloc
)
450 ptrdiff_t nitems_max
= PTRDIFF_MAX
- WORK_AROUND_QTBUG_53071
;
451 ptrdiff_t amax
= nitems_max
< SIZE_MAX
? nitems_max
: SIZE_MAX
;
452 if ((amax
- 1) / 3 * 2 < *nitems_alloc
)
453 memory_exhausted(_("integer overflow"));
454 *nitems_alloc
+= (*nitems_alloc
>> 1) + 1;
455 return erealloc(ptr
, size_product(*nitems_alloc
, itemsize
));
464 eats(char const *name
, lineno num
, char const *rname
, lineno rnum
)
473 eat(char const *name
, lineno num
)
475 eats(name
, num
, NULL
, -1);
478 static void ATTRIBUTE_FORMAT((printf
, 1, 0))
479 verror(const char *const string
, va_list args
)
482 ** Match the format of "cc" to allow sh users to
483 ** zic ... 2>&1 | error -t "*" -v
487 fprintf(stderr
, _("\"%s\", line %"PRIdLINENO
": "), filename
, linenum
);
488 vfprintf(stderr
, string
, args
);
489 if (rfilename
!= NULL
)
490 fprintf(stderr
, _(" (rule from \"%s\", line %"PRIdLINENO
")"),
491 rfilename
, rlinenum
);
492 fprintf(stderr
, "\n");
495 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
496 error(const char *const string
, ...)
499 va_start(args
, string
);
500 verror(string
, args
);
505 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
506 warning(const char *const string
, ...)
509 fprintf(stderr
, _("warning: "));
510 va_start(args
, string
);
511 verror(string
, args
);
517 close_file(FILE *stream
, char const *dir
, char const *name
)
519 char const *e
= (ferror(stream
) ? _("I/O error")
520 : fclose(stream
) != 0 ? strerror(errno
) : NULL
);
522 fprintf(stderr
, "%s: %s%s%s%s%s\n", progname
,
523 dir
? dir
: "", dir
? "/" : "",
524 name
? name
: "", name
? ": " : "",
530 static _Noreturn
void
531 usage(FILE *stream
, int status
)
534 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
535 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
536 "\t[ -L leapseconds ] [ filename ... ]\n\n"
537 "Report bugs to %s.\n"),
538 progname
, progname
, REPORT_BUGS_TO
);
539 if (status
== EXIT_SUCCESS
)
540 close_file(stream
, NULL
, NULL
);
544 /* Change the working directory to DIR, possibly creating DIR and its
545 ancestors. After this is done, all files are accessed with names
548 change_directory (char const *dir
)
550 if (chdir(dir
) != 0) {
551 int chdir_errno
= errno
;
552 if (chdir_errno
== ENOENT
) {
554 chdir_errno
= chdir(dir
) == 0 ? 0 : errno
;
556 if (chdir_errno
!= 0) {
557 fprintf(stderr
, _("%s: Can't chdir to %s: %s\n"),
558 progname
, dir
, strerror(chdir_errno
));
564 static const char * psxrules
;
565 static const char * lcltime
;
566 static const char * directory
;
567 static const char * leapsec
;
568 static const char * yitcommand
;
571 main(int argc
, char **argv
)
574 register ptrdiff_t i
, j
;
577 umask(umask(S_IWGRP
| S_IWOTH
) | (S_IWGRP
| S_IWOTH
));
580 setlocale(LC_ALL
, "");
582 bindtextdomain(TZ_DOMAIN
, TZ_DOMAINDIR
);
583 #endif /* defined TEXTDOMAINDIR */
584 textdomain(TZ_DOMAIN
);
585 #endif /* HAVE_GETTEXT */
587 if (TYPE_BIT(zic_t
) < 64) {
588 fprintf(stderr
, "%s: %s\n", progname
,
589 _("wild compilation-time specification of zic_t"));
592 for (k
= 1; k
< argc
; k
++)
593 if (strcmp(argv
[k
], "--version") == 0) {
594 printf("zic %s%s\n", PKGVERSION
, TZVERSION
);
595 close_file(stdout
, NULL
, NULL
);
597 } else if (strcmp(argv
[k
], "--help") == 0) {
598 usage(stdout
, EXIT_SUCCESS
);
600 while ((c
= getopt(argc
, argv
, "d:l:p:L:vsy:")) != EOF
&& c
!= -1)
603 usage(stderr
, EXIT_FAILURE
);
605 if (directory
== NULL
)
609 _("%s: More than one -d option specified\n"),
619 _("%s: More than one -l option specified\n"),
625 if (psxrules
== NULL
)
629 _("%s: More than one -p option specified\n"),
635 if (yitcommand
== NULL
)
639 _("%s: More than one -y option specified\n"),
649 _("%s: More than one -L option specified\n"),
658 warning(_("-s ignored"));
661 if (optind
== argc
- 1 && strcmp(argv
[optind
], "=") == 0)
662 usage(stderr
, EXIT_FAILURE
); /* usage message by request */
663 if (directory
== NULL
)
665 if (yitcommand
== NULL
)
666 yitcommand
= "yearistype";
668 if (optind
< argc
&& leapsec
!= NULL
) {
673 for (k
= optind
; k
< argc
; k
++)
678 change_directory(directory
);
679 for (i
= 0; i
< nzones
; i
= j
) {
681 ** Find the next non-continuation zone entry.
683 for (j
= i
+ 1; j
< nzones
&& zones
[j
].z_name
== NULL
; ++j
)
685 outzone(&zones
[i
], j
- i
);
690 for (i
= 0; i
< nlinks
; ++i
) {
691 eat(links
[i
].l_filename
, links
[i
].l_linenum
);
692 dolink(links
[i
].l_from
, links
[i
].l_to
, false);
694 for (j
= 0; j
< nlinks
; ++j
)
695 if (strcmp(links
[i
].l_to
,
696 links
[j
].l_from
) == 0)
697 warning(_("link to link"));
699 if (lcltime
!= NULL
) {
700 eat(_("command line"), 1);
701 dolink(lcltime
, TZDEFAULT
, true);
703 if (psxrules
!= NULL
) {
704 eat(_("command line"), 1);
705 dolink(psxrules
, TZDEFRULES
, true);
707 if (warnings
&& (ferror(stderr
) || fclose(stderr
) != 0))
709 return errors
? EXIT_FAILURE
: EXIT_SUCCESS
;
713 componentcheck(char const *name
, char const *component
,
714 char const *component_end
)
716 enum { component_len_max
= 14 };
717 ptrdiff_t component_len
= component_end
- component
;
718 if (component_len
== 0) {
720 error (_("empty file name"));
722 error (_(component
== name
723 ? "file name '%s' begins with '/'"
725 ? "file name '%s' contains '//'"
726 : "file name '%s' ends with '/'"),
730 if (0 < component_len
&& component_len
<= 2
731 && component
[0] == '.' && component_end
[-1] == '.') {
732 int len
= component_len
;
733 error(_("file name '%s' contains '%.*s' component"),
734 name
, len
, component
);
738 if (0 < component_len
&& component
[0] == '-')
739 warning(_("file name '%s' component contains leading '-'"),
741 if (component_len_max
< component_len
)
742 warning(_("file name '%s' contains overlength component"
744 name
, component_len_max
, component
);
750 namecheck(const char *name
)
752 register char const *cp
;
754 /* Benign characters in a portable file name. */
755 static char const benign
[] =
757 "abcdefghijklmnopqrstuvwxyz"
758 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
760 /* Non-control chars in the POSIX portable character set,
761 excluding the benign characters. */
762 static char const printable_and_not_benign
[] =
763 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
765 register char const *component
= name
;
766 for (cp
= name
; *cp
; cp
++) {
767 unsigned char c
= *cp
;
768 if (noise
&& !strchr(benign
, c
)) {
769 warning((strchr(printable_and_not_benign
, c
)
770 ? _("file name '%s' contains byte '%c'")
771 : _("file name '%s' contains byte '\\%o'")),
775 if (!componentcheck(name
, component
, cp
))
780 return componentcheck(name
, component
, cp
);
783 /* Create symlink contents suitable for symlinking FROM to TO, as a
784 freshly allocated string. FROM should be a relative file name, and
785 is relative to the global variable DIRECTORY. TO can be either
786 relative or absolute. */
788 relname(char const *from
, char const *to
)
790 size_t i
, taillen
, dotdotetcsize
;
791 size_t dir_len
= 0, dotdots
= 0, linksize
= SIZE_MAX
;
792 char const *f
= from
;
795 /* Make F absolute too. */
796 size_t len
= strlen(directory
);
797 bool needslash
= len
&& directory
[len
- 1] != '/';
798 linksize
= len
+ needslash
+ strlen(from
) + 1;
799 f
= result
= emalloc(linksize
);
800 strcpy(result
, directory
);
802 strcpy(result
+ len
+ needslash
, from
);
804 for (i
= 0; f
[i
] && f
[i
] == to
[i
]; i
++)
808 dotdots
+= to
[i
] == '/' && to
[i
- 1] != '/';
809 taillen
= strlen(f
+ dir_len
);
810 dotdotetcsize
= 3 * dotdots
+ taillen
+ 1;
811 if (dotdotetcsize
<= linksize
) {
813 result
= emalloc(dotdotetcsize
);
814 for (i
= 0; i
< dotdots
; i
++)
815 memcpy(result
+ 3 * i
, "../", 3);
816 memmove(result
+ 3 * dotdots
, f
+ dir_len
, taillen
+ 1);
821 /* Hard link FROM to TO, following any symbolic links.
822 Return 0 if successful, an error number otherwise. */
824 hardlinkerr(char const *from
, char const *to
)
826 int r
= linkat(AT_FDCWD
, from
, AT_FDCWD
, to
, AT_SYMLINK_FOLLOW
);
827 return r
== 0 ? 0 : errno
;
831 dolink(char const *fromfield
, char const *tofield
, bool staysymlink
)
833 bool todirs_made
= false;
837 ** We get to be careful here since
838 ** there's a fair chance of root running us.
840 if (itsdir(fromfield
)) {
841 fprintf(stderr
, _("%s: link from %s/%s failed: %s\n"),
842 progname
, directory
, fromfield
, strerror(EPERM
));
846 staysymlink
= itssymlink(tofield
);
847 if (remove(tofield
) == 0)
849 else if (errno
!= ENOENT
) {
850 char const *e
= strerror(errno
);
851 fprintf(stderr
, _("%s: Can't remove %s/%s: %s\n"),
852 progname
, directory
, tofield
, e
);
855 link_errno
= staysymlink
? ENOTSUP
: hardlinkerr(fromfield
, tofield
);
856 if (link_errno
== ENOENT
&& !todirs_made
) {
857 mkdirs(tofield
, true);
859 link_errno
= hardlinkerr(fromfield
, tofield
);
861 if (link_errno
!= 0) {
862 bool absolute
= *fromfield
== '/';
863 char *linkalloc
= absolute
? NULL
: relname(fromfield
, tofield
);
864 char const *contents
= absolute
? fromfield
: linkalloc
;
865 int symlink_errno
= symlink(contents
, tofield
) == 0 ? 0 : errno
;
866 if (symlink_errno
== ENOENT
&& !todirs_made
) {
867 mkdirs(tofield
, true);
868 symlink_errno
= symlink(contents
, tofield
) == 0 ? 0 : errno
;
871 if (symlink_errno
== 0) {
872 if (link_errno
!= ENOTSUP
)
873 warning(_("symbolic link used because hard link failed: %s"),
874 strerror(link_errno
));
878 fp
= fopen(fromfield
, "rb");
880 char const *e
= strerror(errno
);
881 fprintf(stderr
, _("%s: Can't read %s/%s: %s\n"),
882 progname
, directory
, fromfield
, e
);
885 tp
= fopen(tofield
, "wb");
887 char const *e
= strerror(errno
);
888 fprintf(stderr
, _("%s: Can't create %s/%s: %s\n"),
889 progname
, directory
, tofield
, e
);
892 while ((c
= getc(fp
)) != EOF
)
894 close_file(fp
, directory
, fromfield
);
895 close_file(tp
, directory
, tofield
);
896 if (link_errno
!= ENOTSUP
)
897 warning(_("copy used because hard link failed: %s"),
898 strerror(link_errno
));
899 else if (symlink_errno
!= ENOTSUP
)
900 warning(_("copy used because symbolic link failed: %s"),
901 strerror(symlink_errno
));
906 #define TIME_T_BITS_IN_FILE 64
908 static zic_t
const min_time
= MINVAL(zic_t
, TIME_T_BITS_IN_FILE
);
909 static zic_t
const max_time
= MAXVAL(zic_t
, TIME_T_BITS_IN_FILE
);
911 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
912 rounded downward to the negation of a power of two that is
913 comfortably outside the error bounds.
915 For the time of the Big Bang, see:
917 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
918 I. Overview of products and scientific results.
919 arXiv:1303.5062 2013-03-20 20:10:01 UTC
920 <http://arxiv.org/pdf/1303.5062v1> [PDF]
922 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
923 gives the value 13.798 plus-or-minus 0.037 billion years.
924 Multiplying this by 1000000000 and then by 31557600 (the number of
925 seconds in an astronomical year) gives a value that is comfortably
926 less than 2**59, so BIG_BANG is - 2**59.
928 BIG_BANG is approximate, and may change in future versions.
929 Please do not rely on its exact value. */
932 #define BIG_BANG (- (1LL << 59))
935 /* If true, work around GNOME bug 730332
936 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>
937 by refusing to output time stamps before BIG_BANG.
938 Such time stamps are physically suspect anyway.
940 The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so
941 this workaround will no longer be needed when GNOME 3.21 and
942 earlier are obsolete, say in the year 2021. */
943 enum { WORK_AROUND_GNOME_BUG_730332
= true };
945 static const zic_t early_time
= (WORK_AROUND_GNOME_BUG_730332
947 : MINVAL(zic_t
, TIME_T_BITS_IN_FILE
));
949 /* Return true if NAME is a directory. */
951 itsdir(char const *name
)
954 int res
= stat(name
, &st
);
957 return S_ISDIR(st
.st_mode
) != 0;
959 if (res
== 0 || errno
== EOVERFLOW
) {
960 size_t n
= strlen(name
);
961 char *nameslashdot
= emalloc(n
+ 3);
963 memcpy(nameslashdot
, name
, n
);
964 strcpy(&nameslashdot
[n
], &"/."[! (n
&& name
[n
- 1] != '/')]);
965 dir
= stat(nameslashdot
, &st
) == 0 || errno
== EOVERFLOW
;
972 /* Return true if NAME is a symbolic link. */
974 itssymlink(char const *name
)
977 return 0 <= readlink(name
, &c
, 1);
981 ** Associate sets of rules with zones.
985 ** Sort by rule name.
989 rcomp(const void *cp1
, const void *cp2
)
991 return strcmp(((const struct rule
*) cp1
)->r_name
,
992 ((const struct rule
*) cp2
)->r_name
);
998 register struct zone
* zp
;
999 register struct rule
* rp
;
1000 register ptrdiff_t i
, j
, base
, out
;
1003 qsort(rules
, nrules
, sizeof *rules
, rcomp
);
1004 for (i
= 0; i
< nrules
- 1; ++i
) {
1005 if (strcmp(rules
[i
].r_name
,
1006 rules
[i
+ 1].r_name
) != 0)
1008 if (strcmp(rules
[i
].r_filename
,
1009 rules
[i
+ 1].r_filename
) == 0)
1011 eat(rules
[i
].r_filename
, rules
[i
].r_linenum
);
1012 warning(_("same rule name in multiple files"));
1013 eat(rules
[i
+ 1].r_filename
, rules
[i
+ 1].r_linenum
);
1014 warning(_("same rule name in multiple files"));
1015 for (j
= i
+ 2; j
< nrules
; ++j
) {
1016 if (strcmp(rules
[i
].r_name
,
1017 rules
[j
].r_name
) != 0)
1019 if (strcmp(rules
[i
].r_filename
,
1020 rules
[j
].r_filename
) == 0)
1022 if (strcmp(rules
[i
+ 1].r_filename
,
1023 rules
[j
].r_filename
) == 0)
1030 for (i
= 0; i
< nzones
; ++i
) {
1035 for (base
= 0; base
< nrules
; base
= out
) {
1037 for (out
= base
+ 1; out
< nrules
; ++out
)
1038 if (strcmp(rp
->r_name
, rules
[out
].r_name
) != 0)
1040 for (i
= 0; i
< nzones
; ++i
) {
1042 if (strcmp(zp
->z_rule
, rp
->r_name
) != 0)
1045 zp
->z_nrules
= out
- base
;
1048 for (i
= 0; i
< nzones
; ++i
) {
1050 if (zp
->z_nrules
== 0) {
1052 ** Maybe we have a local standard time offset.
1054 eat(zp
->z_filename
, zp
->z_linenum
);
1055 zp
->z_stdoff
= gethms(zp
->z_rule
, _("unruly zone"),
1058 ** Note, though, that if there's no rule,
1059 ** a '%s' in the format is a bad thing.
1061 if (zp
->z_format_specifier
== 's')
1062 error("%s", _("%s in ruleless zone"));
1070 infile(const char *name
)
1073 register char ** fields
;
1075 register const struct lookup
* lp
;
1076 register int nfields
;
1077 register bool wantcont
;
1078 register lineno num
;
1081 if (strcmp(name
, "-") == 0) {
1082 name
= _("standard input");
1084 } else if ((fp
= fopen(name
, "r")) == NULL
) {
1085 const char *e
= strerror(errno
);
1087 fprintf(stderr
, _("%s: Can't open %s: %s\n"),
1092 for (num
= 1; ; ++num
) {
1094 if (fgets(buf
, sizeof buf
, fp
) != buf
)
1096 cp
= strchr(buf
, '\n');
1098 error(_("line too long"));
1102 fields
= getfields(buf
);
1104 while (fields
[nfields
] != NULL
) {
1107 if (strcmp(fields
[nfields
], "-") == 0)
1108 fields
[nfields
] = &nada
;
1113 } else if (wantcont
) {
1114 wantcont
= inzcont(fields
, nfields
);
1116 lp
= byword(fields
[0], line_codes
);
1118 error(_("input line of unknown type"));
1119 else switch (lp
->l_value
) {
1121 inrule(fields
, nfields
);
1125 wantcont
= inzone(fields
, nfields
);
1128 inlink(fields
, nfields
);
1132 if (name
!= leapsec
)
1133 warning(_("%s: Leap line in non leap"
1134 " seconds file %s"),
1136 else inleap(fields
, nfields
);
1139 default: /* "cannot happen" */
1141 _("%s: panic: Invalid l_value %d\n"),
1142 progname
, lp
->l_value
);
1148 close_file(fp
, NULL
, filename
);
1150 error(_("expected continuation line not found"));
1154 ** Convert a string of one of the forms
1155 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1156 ** into a number of seconds.
1157 ** A null string maps to zero.
1158 ** Call error with errstring and return zero on errors.
1162 gethms(char const *string
, char const *errstring
, bool signable
)
1168 if (string
== NULL
|| *string
== '\0')
1172 else if (*string
== '-') {
1176 if (sscanf(string
, "%"SCNdZIC
"%c", &hh
, &xs
) == 1)
1178 else if (sscanf(string
, "%"SCNdZIC
":%d%c", &hh
, &mm
, &xs
) == 2)
1180 else if (sscanf(string
, "%"SCNdZIC
":%d:%d%c", &hh
, &mm
, &ss
, &xs
)
1182 error("%s", errstring
);
1186 mm
< 0 || mm
>= MINSPERHOUR
||
1187 ss
< 0 || ss
> SECSPERMIN
) {
1188 error("%s", errstring
);
1191 if (ZIC_MAX
/ SECSPERHOUR
< hh
) {
1192 error(_("time overflow"));
1195 if (noise
&& (hh
> HOURSPERDAY
||
1196 (hh
== HOURSPERDAY
&& (mm
!= 0 || ss
!= 0))))
1197 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1198 return oadd(sign
* hh
* SECSPERHOUR
,
1199 sign
* (mm
* SECSPERMIN
+ ss
));
1203 inrule(char **fields
, int nfields
)
1205 static struct rule r
;
1207 if (nfields
!= RULE_FIELDS
) {
1208 error(_("wrong number of fields on Rule line"));
1211 if (*fields
[RF_NAME
] == '\0') {
1212 error(_("nameless rule"));
1215 r
.r_filename
= filename
;
1216 r
.r_linenum
= linenum
;
1217 r
.r_stdoff
= gethms(fields
[RF_STDOFF
], _("invalid saved time"), true);
1218 rulesub(&r
, fields
[RF_LOYEAR
], fields
[RF_HIYEAR
], fields
[RF_COMMAND
],
1219 fields
[RF_MONTH
], fields
[RF_DAY
], fields
[RF_TOD
]);
1220 r
.r_name
= ecpyalloc(fields
[RF_NAME
]);
1221 r
.r_abbrvar
= ecpyalloc(fields
[RF_ABBRVAR
]);
1222 if (max_abbrvar_len
< strlen(r
.r_abbrvar
))
1223 max_abbrvar_len
= strlen(r
.r_abbrvar
);
1224 rules
= growalloc(rules
, sizeof *rules
, nrules
, &nrules_alloc
);
1225 rules
[nrules
++] = r
;
1229 inzone(char **fields
, int nfields
)
1231 register ptrdiff_t i
;
1233 if (nfields
< ZONE_MINFIELDS
|| nfields
> ZONE_MAXFIELDS
) {
1234 error(_("wrong number of fields on Zone line"));
1237 if (strcmp(fields
[ZF_NAME
], TZDEFAULT
) == 0 && lcltime
!= NULL
) {
1239 _("\"Zone %s\" line and -l option are mutually exclusive"),
1243 if (strcmp(fields
[ZF_NAME
], TZDEFRULES
) == 0 && psxrules
!= NULL
) {
1245 _("\"Zone %s\" line and -p option are mutually exclusive"),
1249 for (i
= 0; i
< nzones
; ++i
)
1250 if (zones
[i
].z_name
!= NULL
&&
1251 strcmp(zones
[i
].z_name
, fields
[ZF_NAME
]) == 0) {
1252 error(_("duplicate zone name %s"
1253 " (file \"%s\", line %"PRIdLINENO
")"),
1255 zones
[i
].z_filename
,
1256 zones
[i
].z_linenum
);
1259 return inzsub(fields
, nfields
, false);
1263 inzcont(char **fields
, int nfields
)
1265 if (nfields
< ZONEC_MINFIELDS
|| nfields
> ZONEC_MAXFIELDS
) {
1266 error(_("wrong number of fields on Zone continuation line"));
1269 return inzsub(fields
, nfields
, true);
1273 inzsub(char **fields
, int nfields
, bool iscont
)
1277 static struct zone z
;
1278 register int i_gmtoff
, i_rule
, i_format
;
1279 register int i_untilyear
, i_untilmonth
;
1280 register int i_untilday
, i_untiltime
;
1281 register bool hasuntil
;
1284 i_gmtoff
= ZFC_GMTOFF
;
1286 i_format
= ZFC_FORMAT
;
1287 i_untilyear
= ZFC_TILYEAR
;
1288 i_untilmonth
= ZFC_TILMONTH
;
1289 i_untilday
= ZFC_TILDAY
;
1290 i_untiltime
= ZFC_TILTIME
;
1292 } else if (!namecheck(fields
[ZF_NAME
]))
1295 i_gmtoff
= ZF_GMTOFF
;
1297 i_format
= ZF_FORMAT
;
1298 i_untilyear
= ZF_TILYEAR
;
1299 i_untilmonth
= ZF_TILMONTH
;
1300 i_untilday
= ZF_TILDAY
;
1301 i_untiltime
= ZF_TILTIME
;
1302 z
.z_name
= ecpyalloc(fields
[ZF_NAME
]);
1304 z
.z_filename
= filename
;
1305 z
.z_linenum
= linenum
;
1306 z
.z_gmtoff
= gethms(fields
[i_gmtoff
], _("invalid UT offset"), true);
1307 if ((cp
= strchr(fields
[i_format
], '%')) != 0) {
1308 if ((*++cp
!= 's' && *cp
!= 'z') || strchr(cp
, '%')
1309 || strchr(fields
[i_format
], '/')) {
1310 error(_("invalid abbreviation format"));
1314 z
.z_rule
= ecpyalloc(fields
[i_rule
]);
1315 z
.z_format
= cp1
= ecpyalloc(fields
[i_format
]);
1316 z
.z_format_specifier
= cp
? *cp
: '\0';
1317 if (z
.z_format_specifier
== 'z') {
1319 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1321 cp1
[cp
- fields
[i_format
]] = 's';
1323 if (max_format_len
< strlen(z
.z_format
))
1324 max_format_len
= strlen(z
.z_format
);
1325 hasuntil
= nfields
> i_untilyear
;
1327 z
.z_untilrule
.r_filename
= filename
;
1328 z
.z_untilrule
.r_linenum
= linenum
;
1329 rulesub(&z
.z_untilrule
,
1330 fields
[i_untilyear
],
1333 (nfields
> i_untilmonth
) ?
1334 fields
[i_untilmonth
] : "Jan",
1335 (nfields
> i_untilday
) ? fields
[i_untilday
] : "1",
1336 (nfields
> i_untiltime
) ? fields
[i_untiltime
] : "0");
1337 z
.z_untiltime
= rpytime(&z
.z_untilrule
,
1338 z
.z_untilrule
.r_loyear
);
1339 if (iscont
&& nzones
> 0 &&
1340 z
.z_untiltime
> min_time
&&
1341 z
.z_untiltime
< max_time
&&
1342 zones
[nzones
- 1].z_untiltime
> min_time
&&
1343 zones
[nzones
- 1].z_untiltime
< max_time
&&
1344 zones
[nzones
- 1].z_untiltime
>= z
.z_untiltime
) {
1346 "Zone continuation line end time is not after end time of previous line"
1351 zones
= growalloc(zones
, sizeof *zones
, nzones
, &nzones_alloc
);
1352 zones
[nzones
++] = z
;
1354 ** If there was an UNTIL field on this line,
1355 ** there's more information about the zone on the next line.
1361 inleap(char **fields
, int nfields
)
1363 register const char * cp
;
1364 register const struct lookup
* lp
;
1365 register zic_t i
, j
;
1372 if (nfields
!= LEAP_FIELDS
) {
1373 error(_("wrong number of fields on Leap line"));
1377 cp
= fields
[LP_YEAR
];
1378 if (sscanf(cp
, "%"SCNdZIC
"%c", &year
, &xs
) != 1) {
1382 error(_("invalid leaping year"));
1385 if (!leapseen
|| leapmaxyear
< year
)
1387 if (!leapseen
|| leapminyear
> year
)
1393 i
= len_years
[isleap(j
)];
1397 i
= -len_years
[isleap(j
)];
1399 dayoff
= oadd(dayoff
, i
);
1401 if ((lp
= byword(fields
[LP_MONTH
], mon_names
)) == NULL
) {
1402 error(_("invalid month name"));
1405 month
= lp
->l_value
;
1407 while (j
!= month
) {
1408 i
= len_months
[isleap(year
)][j
];
1409 dayoff
= oadd(dayoff
, i
);
1412 cp
= fields
[LP_DAY
];
1413 if (sscanf(cp
, "%d%c", &day
, &xs
) != 1 ||
1414 day
<= 0 || day
> len_months
[isleap(year
)][month
]) {
1415 error(_("invalid day of month"));
1418 dayoff
= oadd(dayoff
, day
- 1);
1419 if (dayoff
< min_time
/ SECSPERDAY
) {
1420 error(_("time too small"));
1423 if (dayoff
> max_time
/ SECSPERDAY
) {
1424 error(_("time too large"));
1427 t
= dayoff
* SECSPERDAY
;
1428 tod
= gethms(fields
[LP_TIME
], _("invalid time of day"), false);
1429 cp
= fields
[LP_CORR
];
1431 register bool positive
;
1434 if (strcmp(cp
, "") == 0) { /* infile() turns "-" into "" */
1437 } else if (strcmp(cp
, "--") == 0) {
1440 } else if (strcmp(cp
, "+") == 0) {
1443 } else if (strcmp(cp
, "++") == 0) {
1447 error(_("illegal CORRECTION field on Leap line"));
1450 if ((lp
= byword(fields
[LP_ROLL
], leap_types
)) == NULL
) {
1452 "illegal Rolling/Stationary field on Leap line"
1457 if (t
< early_time
) {
1458 error(_("leap second precedes Big Bang"));
1461 leapadd(t
, positive
, lp
->l_value
, count
);
1466 inlink(char **fields
, int nfields
)
1470 if (nfields
!= LINK_FIELDS
) {
1471 error(_("wrong number of fields on Link line"));
1474 if (*fields
[LF_FROM
] == '\0') {
1475 error(_("blank FROM field on Link line"));
1478 if (! namecheck(fields
[LF_TO
]))
1480 l
.l_filename
= filename
;
1481 l
.l_linenum
= linenum
;
1482 l
.l_from
= ecpyalloc(fields
[LF_FROM
]);
1483 l
.l_to
= ecpyalloc(fields
[LF_TO
]);
1484 links
= growalloc(links
, sizeof *links
, nlinks
, &nlinks_alloc
);
1485 links
[nlinks
++] = l
;
1489 rulesub(struct rule
*rp
, const char *loyearp
, const char *hiyearp
,
1490 const char *typep
, const char *monthp
, const char *dayp
,
1493 register const struct lookup
* lp
;
1494 register const char * cp
;
1499 if ((lp
= byword(monthp
, mon_names
)) == NULL
) {
1500 error(_("invalid month name"));
1503 rp
->r_month
= lp
->l_value
;
1504 rp
->r_todisstd
= false;
1505 rp
->r_todisgmt
= false;
1506 dp
= ecpyalloc(timep
);
1508 ep
= dp
+ strlen(dp
) - 1;
1509 switch (lowerit(*ep
)) {
1510 case 's': /* Standard */
1511 rp
->r_todisstd
= true;
1512 rp
->r_todisgmt
= false;
1515 case 'w': /* Wall */
1516 rp
->r_todisstd
= false;
1517 rp
->r_todisgmt
= false;
1520 case 'g': /* Greenwich */
1521 case 'u': /* Universal */
1522 case 'z': /* Zulu */
1523 rp
->r_todisstd
= true;
1524 rp
->r_todisgmt
= true;
1529 rp
->r_tod
= gethms(dp
, _("invalid time of day"), false);
1535 lp
= byword(cp
, begin_years
);
1536 rp
->r_lowasnum
= lp
== NULL
;
1537 if (!rp
->r_lowasnum
) switch (lp
->l_value
) {
1539 rp
->r_loyear
= ZIC_MIN
;
1542 rp
->r_loyear
= ZIC_MAX
;
1544 default: /* "cannot happen" */
1546 _("%s: panic: Invalid l_value %d\n"),
1547 progname
, lp
->l_value
);
1549 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_loyear
, &xs
) != 1) {
1550 error(_("invalid starting year"));
1554 lp
= byword(cp
, end_years
);
1555 rp
->r_hiwasnum
= lp
== NULL
;
1556 if (!rp
->r_hiwasnum
) switch (lp
->l_value
) {
1558 rp
->r_hiyear
= ZIC_MIN
;
1561 rp
->r_hiyear
= ZIC_MAX
;
1564 rp
->r_hiyear
= rp
->r_loyear
;
1566 default: /* "cannot happen" */
1568 _("%s: panic: Invalid l_value %d\n"),
1569 progname
, lp
->l_value
);
1571 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_hiyear
, &xs
) != 1) {
1572 error(_("invalid ending year"));
1575 if (rp
->r_loyear
> rp
->r_hiyear
) {
1576 error(_("starting year greater than ending year"));
1580 rp
->r_yrtype
= NULL
;
1582 if (rp
->r_loyear
== rp
->r_hiyear
) {
1583 error(_("typed single year"));
1586 rp
->r_yrtype
= ecpyalloc(typep
);
1590 ** Accept things such as:
1596 dp
= ecpyalloc(dayp
);
1597 if ((lp
= byword(dp
, lasts
)) != NULL
) {
1598 rp
->r_dycode
= DC_DOWLEQ
;
1599 rp
->r_wday
= lp
->l_value
;
1600 rp
->r_dayofmonth
= len_months
[1][rp
->r_month
];
1602 if ((ep
= strchr(dp
, '<')) != 0)
1603 rp
->r_dycode
= DC_DOWLEQ
;
1604 else if ((ep
= strchr(dp
, '>')) != 0)
1605 rp
->r_dycode
= DC_DOWGEQ
;
1608 rp
->r_dycode
= DC_DOM
;
1610 if (rp
->r_dycode
!= DC_DOM
) {
1613 error(_("invalid day of month"));
1617 if ((lp
= byword(dp
, wday_names
)) == NULL
) {
1618 error(_("invalid weekday name"));
1622 rp
->r_wday
= lp
->l_value
;
1624 if (sscanf(ep
, "%d%c", &rp
->r_dayofmonth
, &xs
) != 1 ||
1625 rp
->r_dayofmonth
<= 0 ||
1626 (rp
->r_dayofmonth
> len_months
[1][rp
->r_month
])) {
1627 error(_("invalid day of month"));
1636 convert(const int_fast32_t val
, char *const buf
)
1640 unsigned char *const b
= (unsigned char *) buf
;
1642 for (i
= 0, shift
= 24; i
< 4; ++i
, shift
-= 8)
1643 b
[i
] = val
>> shift
;
1647 convert64(const zic_t val
, char *const buf
)
1651 unsigned char *const b
= (unsigned char *) buf
;
1653 for (i
= 0, shift
= 56; i
< 8; ++i
, shift
-= 8)
1654 b
[i
] = val
>> shift
;
1658 puttzcode(const int_fast32_t val
, FILE *const fp
)
1663 fwrite(buf
, sizeof buf
, 1, fp
);
1667 puttzcode64(const zic_t val
, FILE *const fp
)
1671 convert64(val
, buf
);
1672 fwrite(buf
, sizeof buf
, 1, fp
);
1676 atcomp(const void *avp
, const void *bvp
)
1678 const zic_t a
= ((const struct attype
*) avp
)->at
;
1679 const zic_t b
= ((const struct attype
*) bvp
)->at
;
1681 return (a
< b
) ? -1 : (a
> b
);
1687 return INT32_MIN
<= x
&& x
<= INT32_MAX
;
1691 writezone(const char *const name
, const char *const string
, char version
)
1694 register ptrdiff_t i
, j
;
1695 register int leapcnt32
, leapi32
;
1696 register ptrdiff_t timecnt32
, timei32
;
1698 static const struct tzhead tzh0
;
1699 static struct tzhead tzh
;
1700 bool dir_checked
= false;
1702 zic_t y2038_boundary
= one
<< 31;
1703 ptrdiff_t nats
= timecnt
+ WORK_AROUND_QTBUG_53071
;
1704 zic_t
*ats
= emalloc(size_product(nats
, sizeof *ats
+ 1));
1705 void *typesptr
= ats
+ nats
;
1706 unsigned char *types
= typesptr
;
1712 qsort(attypes
, timecnt
, sizeof *attypes
, atcomp
);
1717 ptrdiff_t fromi
, toi
;
1721 while (fromi
< timecnt
&& attypes
[fromi
].at
< early_time
)
1723 for ( ; fromi
< timecnt
; ++fromi
) {
1724 if (toi
> 1 && ((attypes
[fromi
].at
+
1725 gmtoffs
[attypes
[toi
- 1].type
]) <=
1726 (attypes
[toi
- 1].at
+
1727 gmtoffs
[attypes
[toi
- 2].type
]))) {
1728 attypes
[toi
- 1].type
=
1729 attypes
[fromi
].type
;
1733 || attypes
[fromi
].dontmerge
1734 || attypes
[toi
- 1].type
!= attypes
[fromi
].type
)
1735 attypes
[toi
++] = attypes
[fromi
];
1740 if (noise
&& timecnt
> 1200) {
1741 if (timecnt
> TZ_MAX_TIMES
)
1742 warning(_("reference clients mishandle"
1743 " more than %d transition times"),
1746 warning(_("pre-2014 clients may mishandle"
1747 " more than 1200 transition times"));
1752 for (i
= 0; i
< timecnt
; ++i
) {
1753 ats
[i
] = attypes
[i
].at
;
1754 types
[i
] = attypes
[i
].type
;
1757 /* Work around QTBUG-53071 for time stamps less than y2038_boundary - 1,
1758 by inserting a no-op transition at time y2038_boundary - 1.
1759 This works only for timestamps before the boundary, which
1760 should be good enough in practice as QTBUG-53071 should be
1761 long-dead by 2038. */
1762 if (WORK_AROUND_QTBUG_53071
&& timecnt
!= 0
1763 && ats
[timecnt
- 1] < y2038_boundary
- 1 && strchr(string
, '<')) {
1764 ats
[timecnt
] = y2038_boundary
- 1;
1765 types
[timecnt
] = types
[timecnt
- 1];
1770 ** Correct for leap seconds.
1772 for (i
= 0; i
< timecnt
; ++i
) {
1775 if (ats
[i
] > trans
[j
] - corr
[j
]) {
1776 ats
[i
] = tadd(ats
[i
], corr
[j
]);
1781 ** Figure out 32-bit-limited starts and counts.
1783 timecnt32
= timecnt
;
1785 leapcnt32
= leapcnt
;
1787 while (timecnt32
> 0 && !is32(ats
[timecnt32
- 1]))
1789 while (timecnt32
> 0 && !is32(ats
[timei32
])) {
1794 ** Output an INT32_MIN "transition" if appropriate; see below.
1796 if (timei32
> 0 && ats
[timei32
] > INT32_MIN
) {
1800 while (leapcnt32
> 0 && !is32(trans
[leapcnt32
- 1]))
1802 while (leapcnt32
> 0 && !is32(trans
[leapi32
])) {
1807 ** Remove old file, if any, to snap links.
1809 if (remove(name
) == 0)
1811 else if (errno
!= ENOENT
) {
1812 const char *e
= strerror(errno
);
1814 fprintf(stderr
, _("%s: Can't remove %s/%s: %s\n"),
1815 progname
, directory
, name
, e
);
1818 fp
= fopen(name
, "wb");
1820 int fopen_errno
= errno
;
1821 if (fopen_errno
== ENOENT
&& !dir_checked
) {
1823 fp
= fopen(name
, "wb");
1824 fopen_errno
= errno
;
1827 fprintf(stderr
, _("%s: Can't create %s/%s: %s\n"),
1828 progname
, directory
, name
, strerror(fopen_errno
));
1832 for (pass
= 1; pass
<= 2; ++pass
) {
1833 register ptrdiff_t thistimei
, thistimecnt
, thistimelim
;
1834 register int thisleapi
, thisleapcnt
, thisleaplim
;
1835 int writetype
[TZ_MAX_TYPES
];
1836 int typemap
[TZ_MAX_TYPES
];
1837 register int thistypecnt
;
1838 char thischars
[TZ_MAX_CHARS
];
1841 int indmap
[TZ_MAX_CHARS
];
1844 thistimei
= timei32
;
1845 thistimecnt
= timecnt32
;
1846 toomanytimes
= thistimecnt
>> 31 >> 1 != 0;
1847 thisleapi
= leapi32
;
1848 thisleapcnt
= leapcnt32
;
1851 thistimecnt
= timecnt
;
1852 toomanytimes
= thistimecnt
>> 31 >> 31 >> 2 != 0;
1854 thisleapcnt
= leapcnt
;
1857 error(_("too many transition times"));
1858 thistimelim
= thistimei
+ thistimecnt
;
1859 thisleaplim
= thisleapi
+ thisleapcnt
;
1860 for (i
= 0; i
< typecnt
; ++i
)
1861 writetype
[i
] = thistimecnt
== timecnt
;
1862 if (thistimecnt
== 0) {
1864 ** No transition times fall in the current
1865 ** (32- or 64-bit) window.
1868 writetype
[typecnt
- 1] = true;
1870 for (i
= thistimei
- 1; i
< thistimelim
; ++i
)
1872 writetype
[types
[i
]] = true;
1874 ** For America/Godthab and Antarctica/Palmer
1877 writetype
[0] = true;
1879 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1881 ** For some pre-2011 systems: if the last-to-be-written
1882 ** standard (or daylight) type has an offset different from the
1883 ** most recently used offset,
1884 ** append an (unused) copy of the most recently used type
1885 ** (to help get global "altzone" and "timezone" variables
1889 register int mrudst
, mrustd
, hidst
, histd
, type
;
1891 hidst
= histd
= mrudst
= mrustd
= -1;
1892 for (i
= thistimei
; i
< thistimelim
; ++i
)
1893 if (isdsts
[types
[i
]])
1895 else mrustd
= types
[i
];
1896 for (i
= 0; i
< typecnt
; ++i
)
1902 if (hidst
>= 0 && mrudst
>= 0 && hidst
!= mrudst
&&
1903 gmtoffs
[hidst
] != gmtoffs
[mrudst
]) {
1904 isdsts
[mrudst
] = -1;
1905 type
= addtype(gmtoffs
[mrudst
],
1906 &chars
[abbrinds
[mrudst
]],
1911 writetype
[type
] = true;
1913 if (histd
>= 0 && mrustd
>= 0 && histd
!= mrustd
&&
1914 gmtoffs
[histd
] != gmtoffs
[mrustd
]) {
1915 isdsts
[mrustd
] = -1;
1916 type
= addtype(gmtoffs
[mrustd
],
1917 &chars
[abbrinds
[mrustd
]],
1922 writetype
[type
] = true;
1925 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1927 for (i
= 0; i
< typecnt
; ++i
)
1928 typemap
[i
] = writetype
[i
] ? thistypecnt
++ : -1;
1929 for (i
= 0; i
< sizeof indmap
/ sizeof indmap
[0]; ++i
)
1932 for (i
= 0; i
< typecnt
; ++i
) {
1933 register char * thisabbr
;
1937 if (indmap
[abbrinds
[i
]] >= 0)
1939 thisabbr
= &chars
[abbrinds
[i
]];
1940 for (j
= 0; j
< thischarcnt
; ++j
)
1941 if (strcmp(&thischars
[j
], thisabbr
) == 0)
1943 if (j
== thischarcnt
) {
1944 strcpy(&thischars
[thischarcnt
], thisabbr
);
1945 thischarcnt
+= strlen(thisabbr
) + 1;
1947 indmap
[abbrinds
[i
]] = j
;
1949 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
1951 strncpy(tzh
.tzh_magic
, TZ_MAGIC
, sizeof tzh
.tzh_magic
);
1952 tzh
.tzh_version
[0] = version
;
1953 convert(thistypecnt
, tzh
.tzh_ttisgmtcnt
);
1954 convert(thistypecnt
, tzh
.tzh_ttisstdcnt
);
1955 convert(thisleapcnt
, tzh
.tzh_leapcnt
);
1956 convert(thistimecnt
, tzh
.tzh_timecnt
);
1957 convert(thistypecnt
, tzh
.tzh_typecnt
);
1958 convert(thischarcnt
, tzh
.tzh_charcnt
);
1969 for (i
= thistimei
; i
< thistimelim
; ++i
)
1972 ** Output an INT32_MIN "transition"
1973 ** if appropriate; see above.
1975 puttzcode(((ats
[i
] < INT32_MIN
) ?
1976 INT32_MIN
: ats
[i
]), fp
);
1977 else puttzcode64(ats
[i
], fp
);
1978 for (i
= thistimei
; i
< thistimelim
; ++i
) {
1981 uc
= typemap
[types
[i
]];
1982 fwrite(&uc
, sizeof uc
, 1, fp
);
1984 for (i
= 0; i
< typecnt
; ++i
)
1986 puttzcode(gmtoffs
[i
], fp
);
1987 putc(isdsts
[i
], fp
);
1988 putc((unsigned char) indmap
[abbrinds
[i
]], fp
);
1990 if (thischarcnt
!= 0)
1991 fwrite(thischars
, sizeof thischars
[0],
1993 for (i
= thisleapi
; i
< thisleaplim
; ++i
) {
1994 register zic_t todo
;
1997 if (timecnt
== 0 || trans
[i
] < ats
[0]) {
2000 if (++j
>= typecnt
) {
2006 while (j
< timecnt
&&
2011 todo
= tadd(trans
[i
], -gmtoffs
[j
]);
2012 } else todo
= trans
[i
];
2014 puttzcode(todo
, fp
);
2015 else puttzcode64(todo
, fp
);
2016 puttzcode(corr
[i
], fp
);
2018 for (i
= 0; i
< typecnt
; ++i
)
2020 putc(ttisstds
[i
], fp
);
2021 for (i
= 0; i
< typecnt
; ++i
)
2023 putc(ttisgmts
[i
], fp
);
2025 fprintf(fp
, "\n%s\n", string
);
2026 close_file(fp
, directory
, name
);
2031 abbroffset(char *buf
, zic_t offset
)
2034 int seconds
, minutes
;
2041 seconds
= offset
% SECSPERMIN
;
2042 offset
/= SECSPERMIN
;
2043 minutes
= offset
% MINSPERHOUR
;
2044 offset
/= MINSPERHOUR
;
2045 if (100 <= offset
) {
2046 error(_("%%z UTC offset magnitude exceeds 99:59:59"));
2051 *p
++ = '0' + offset
/ 10;
2052 *p
++ = '0' + offset
% 10;
2053 if (minutes
| seconds
) {
2054 *p
++ = '0' + minutes
/ 10;
2055 *p
++ = '0' + minutes
% 10;
2057 *p
++ = '0' + seconds
/ 10;
2058 *p
++ = '0' + seconds
% 10;
2067 doabbr(char *abbr
, struct zone
const *zp
, char const *letters
,
2068 zic_t stdoff
, bool doquotes
)
2071 register char * slashp
;
2072 register size_t len
;
2073 char const *format
= zp
->z_format
;
2075 slashp
= strchr(format
, '/');
2076 if (slashp
== NULL
) {
2077 char letterbuf
[PERCENT_Z_LEN_BOUND
+ 1];
2078 if (zp
->z_format_specifier
== 'z')
2079 letters
= abbroffset(letterbuf
, zp
->z_gmtoff
+ stdoff
);
2082 sprintf(abbr
, format
, letters
);
2083 } else if (stdoff
!= 0) {
2084 strcpy(abbr
, slashp
+ 1);
2086 memcpy(abbr
, format
, slashp
- format
);
2087 abbr
[slashp
- format
] = '\0';
2092 for (cp
= abbr
; is_alpha(*cp
); cp
++)
2094 if (len
> 0 && *cp
== '\0')
2096 abbr
[len
+ 2] = '\0';
2097 abbr
[len
+ 1] = '>';
2098 memmove(abbr
+ 1, abbr
, len
);
2104 updateminmax(const zic_t x
)
2113 stringoffset(char *result
, zic_t offset
)
2116 register int minutes
;
2117 register int seconds
;
2118 bool negative
= offset
< 0;
2125 seconds
= offset
% SECSPERMIN
;
2126 offset
/= SECSPERMIN
;
2127 minutes
= offset
% MINSPERHOUR
;
2128 offset
/= MINSPERHOUR
;
2130 if (hours
>= HOURSPERDAY
* DAYSPERWEEK
) {
2134 len
+= sprintf(result
+ len
, "%d", hours
);
2135 if (minutes
!= 0 || seconds
!= 0) {
2136 len
+= sprintf(result
+ len
, ":%02d", minutes
);
2138 len
+= sprintf(result
+ len
, ":%02d", seconds
);
2144 stringrule(char *result
, const struct rule
*const rp
, const zic_t dstoff
,
2147 register zic_t tod
= rp
->r_tod
;
2148 register int compat
= 0;
2150 if (rp
->r_dycode
== DC_DOM
) {
2151 register int month
, total
;
2153 if (rp
->r_dayofmonth
== 29 && rp
->r_month
== TM_FEBRUARY
)
2156 for (month
= 0; month
< rp
->r_month
; ++month
)
2157 total
+= len_months
[0][month
];
2158 /* Omit the "J" in Jan and Feb, as that's shorter. */
2159 if (rp
->r_month
<= 1)
2160 result
+= sprintf(result
, "%d", total
+ rp
->r_dayofmonth
- 1);
2162 result
+= sprintf(result
, "J%d", total
+ rp
->r_dayofmonth
);
2165 register int wday
= rp
->r_wday
;
2166 register int wdayoff
;
2168 if (rp
->r_dycode
== DC_DOWGEQ
) {
2169 wdayoff
= (rp
->r_dayofmonth
- 1) % DAYSPERWEEK
;
2173 tod
+= wdayoff
* SECSPERDAY
;
2174 week
= 1 + (rp
->r_dayofmonth
- 1) / DAYSPERWEEK
;
2175 } else if (rp
->r_dycode
== DC_DOWLEQ
) {
2176 if (rp
->r_dayofmonth
== len_months
[1][rp
->r_month
])
2179 wdayoff
= rp
->r_dayofmonth
% DAYSPERWEEK
;
2183 tod
+= wdayoff
* SECSPERDAY
;
2184 week
= rp
->r_dayofmonth
/ DAYSPERWEEK
;
2186 } else return -1; /* "cannot happen" */
2188 wday
+= DAYSPERWEEK
;
2189 result
+= sprintf(result
, "M%d.%d.%d",
2190 rp
->r_month
+ 1, week
, wday
);
2194 if (rp
->r_todisstd
&& rp
->r_stdoff
== 0)
2196 if (tod
!= 2 * SECSPERMIN
* MINSPERHOUR
) {
2198 if (! stringoffset(result
, tod
))
2203 } else if (SECSPERDAY
<= tod
) {
2212 rule_cmp(struct rule
const *a
, struct rule
const *b
)
2218 if (a
->r_hiyear
!= b
->r_hiyear
)
2219 return a
->r_hiyear
< b
->r_hiyear
? -1 : 1;
2220 if (a
->r_month
- b
->r_month
!= 0)
2221 return a
->r_month
- b
->r_month
;
2222 return a
->r_dayofmonth
- b
->r_dayofmonth
;
2225 enum { YEAR_BY_YEAR_ZONE
= 1 };
2228 stringzone(char *result
, struct zone
const *zpfirst
, ptrdiff_t zonecount
)
2230 register const struct zone
* zp
;
2231 register struct rule
* rp
;
2232 register struct rule
* stdrp
;
2233 register struct rule
* dstrp
;
2234 register ptrdiff_t i
;
2235 register const char * abbrvar
;
2236 register int compat
= 0;
2240 struct rule stdr
, dstr
;
2243 zp
= zpfirst
+ zonecount
- 1;
2244 stdrp
= dstrp
= NULL
;
2245 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2246 rp
= &zp
->z_rules
[i
];
2247 if (rp
->r_hiwasnum
|| rp
->r_hiyear
!= ZIC_MAX
)
2249 if (rp
->r_yrtype
!= NULL
)
2251 if (rp
->r_stdoff
== 0) {
2261 if (stdrp
== NULL
&& dstrp
== NULL
) {
2263 ** There are no rules running through "max".
2264 ** Find the latest std rule in stdabbrrp
2265 ** and latest rule of any type in stdrp.
2267 register struct rule
*stdabbrrp
= NULL
;
2268 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2269 rp
= &zp
->z_rules
[i
];
2270 if (rp
->r_stdoff
== 0 && rule_cmp(stdabbrrp
, rp
) < 0)
2272 if (rule_cmp(stdrp
, rp
) < 0)
2276 ** Horrid special case: if year is 2037,
2277 ** presume this is a zone handled on a year-by-year basis;
2278 ** do not try to apply a rule to the zone.
2280 if (stdrp
!= NULL
&& stdrp
->r_hiyear
== 2037)
2281 return YEAR_BY_YEAR_ZONE
;
2283 if (stdrp
!= NULL
&& stdrp
->r_stdoff
!= 0) {
2284 /* Perpetual DST. */
2285 dstr
.r_month
= TM_JANUARY
;
2286 dstr
.r_dycode
= DC_DOM
;
2287 dstr
.r_dayofmonth
= 1;
2289 dstr
.r_todisstd
= dstr
.r_todisgmt
= false;
2290 dstr
.r_stdoff
= stdrp
->r_stdoff
;
2291 dstr
.r_abbrvar
= stdrp
->r_abbrvar
;
2292 stdr
.r_month
= TM_DECEMBER
;
2293 stdr
.r_dycode
= DC_DOM
;
2294 stdr
.r_dayofmonth
= 31;
2295 stdr
.r_tod
= SECSPERDAY
+ stdrp
->r_stdoff
;
2296 stdr
.r_todisstd
= stdr
.r_todisgmt
= false;
2299 = (stdabbrrp
? stdabbrrp
->r_abbrvar
: "");
2304 if (stdrp
== NULL
&& (zp
->z_nrules
!= 0 || zp
->z_stdoff
!= 0))
2306 abbrvar
= (stdrp
== NULL
) ? "" : stdrp
->r_abbrvar
;
2307 len
= doabbr(result
, zp
, abbrvar
, 0, true);
2308 offsetlen
= stringoffset(result
+ len
, -zp
->z_gmtoff
);
2316 len
+= doabbr(result
+ len
, zp
, dstrp
->r_abbrvar
, dstrp
->r_stdoff
, true);
2317 if (dstrp
->r_stdoff
!= SECSPERMIN
* MINSPERHOUR
) {
2318 offsetlen
= stringoffset(result
+ len
,
2319 -(zp
->z_gmtoff
+ dstrp
->r_stdoff
));
2326 result
[len
++] = ',';
2327 c
= stringrule(result
+ len
, dstrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2334 len
+= strlen(result
+ len
);
2335 result
[len
++] = ',';
2336 c
= stringrule(result
+ len
, stdrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2347 outzone(const struct zone
*zpfirst
, ptrdiff_t zonecount
)
2349 register const struct zone
* zp
;
2350 register struct rule
* rp
;
2351 register ptrdiff_t i
, j
;
2352 register bool usestart
, useuntil
;
2353 register zic_t starttime
, untiltime
;
2354 register zic_t gmtoff
;
2355 register zic_t stdoff
;
2356 register zic_t year
;
2357 register zic_t startoff
;
2358 register bool startttisstd
;
2359 register bool startttisgmt
;
2361 register char * startbuf
;
2363 register char * envvar
;
2364 register int max_abbr_len
;
2365 register int max_envvar_len
;
2366 register bool prodstic
; /* all rules are min to max */
2367 register int compat
;
2368 register bool do_extend
;
2369 register char version
;
2370 ptrdiff_t lastatmax
= -1;
2372 zic_t y2038_boundary
= one
<< 31;
2375 max_abbr_len
= 2 + max_format_len
+ max_abbrvar_len
;
2376 max_envvar_len
= 2 * max_abbr_len
+ 5 * 9;
2377 startbuf
= emalloc(max_abbr_len
+ 1);
2378 ab
= emalloc(max_abbr_len
+ 1);
2379 envvar
= emalloc(max_envvar_len
+ 1);
2380 INITIALIZE(untiltime
);
2381 INITIALIZE(starttime
);
2383 ** Now. . .finally. . .generate some useful data!
2388 prodstic
= zonecount
== 1;
2390 ** Thanks to Earl Chew
2391 ** for noting the need to unconditionally initialize startttisstd.
2393 startttisstd
= false;
2394 startttisgmt
= false;
2395 min_year
= max_year
= EPOCH_YEAR
;
2397 updateminmax(leapminyear
);
2398 updateminmax(leapmaxyear
+ (leapmaxyear
< ZIC_MAX
));
2400 for (i
= 0; i
< zonecount
; ++i
) {
2402 if (i
< zonecount
- 1)
2403 updateminmax(zp
->z_untilrule
.r_loyear
);
2404 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2405 rp
= &zp
->z_rules
[j
];
2407 updateminmax(rp
->r_loyear
);
2409 updateminmax(rp
->r_hiyear
);
2410 if (rp
->r_lowasnum
|| rp
->r_hiwasnum
)
2415 ** Generate lots of data if a rule can't cover all future times.
2417 compat
= stringzone(envvar
, zpfirst
, zonecount
);
2418 version
= compat
< 2013 ? ZIC_VERSION_PRE_2013
: ZIC_VERSION
;
2419 do_extend
= compat
< 0 || compat
== YEAR_BY_YEAR_ZONE
;
2423 _("no POSIX environment variable for zone"),
2425 else if (compat
!= 0 && compat
!= YEAR_BY_YEAR_ZONE
) {
2426 /* Circa-COMPAT clients, and earlier clients, might
2427 not work for this zone when given dates before
2428 1970 or after 2038. */
2429 warning(_("%s: pre-%d clients may mishandle"
2430 " distant timestamps"),
2431 zpfirst
->z_name
, compat
);
2436 ** Search through a couple of extra years past the obvious
2437 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2438 ** rule applies from 2012 onwards and has transitions in March
2439 ** and September, plus some one-off transitions in November
2440 ** 2013. If zic looked only at the last 400 years, it would
2441 ** set max_year=2413, with the intent that the 400 years 2014
2442 ** through 2413 will be repeated. The last transition listed
2443 ** in the tzfile would be in 2413-09, less than 400 years
2444 ** after the last one-off transition in 2013-11. Two years
2445 ** might be overkill, but with the kind of edge cases
2446 ** available we're not sure that one year would suffice.
2448 enum { years_of_observations
= YEARSPERREPEAT
+ 2 };
2450 if (min_year
>= ZIC_MIN
+ years_of_observations
)
2451 min_year
-= years_of_observations
;
2452 else min_year
= ZIC_MIN
;
2453 if (max_year
<= ZIC_MAX
- years_of_observations
)
2454 max_year
+= years_of_observations
;
2455 else max_year
= ZIC_MAX
;
2457 ** Regardless of any of the above,
2458 ** for a "proDSTic" zone which specifies that its rules
2459 ** always have and always will be in effect,
2460 ** we only need one cycle to define the zone.
2464 max_year
= min_year
+ years_of_observations
;
2468 ** For the benefit of older systems,
2469 ** generate data from 1900 through 2038.
2471 if (min_year
> 1900)
2473 max_year0
= max_year
;
2474 if (max_year
< 2038)
2476 for (i
= 0; i
< zonecount
; ++i
) {
2478 ** A guess that may well be corrected later.
2482 usestart
= i
> 0 && (zp
- 1)->z_untiltime
> early_time
;
2483 useuntil
= i
< (zonecount
- 1);
2484 if (useuntil
&& zp
->z_untiltime
<= early_time
)
2486 gmtoff
= zp
->z_gmtoff
;
2487 eat(zp
->z_filename
, zp
->z_linenum
);
2489 startoff
= zp
->z_gmtoff
;
2490 if (zp
->z_nrules
== 0) {
2491 stdoff
= zp
->z_stdoff
;
2492 doabbr(startbuf
, zp
, NULL
, stdoff
, false);
2493 type
= addtype(oadd(zp
->z_gmtoff
, stdoff
),
2494 startbuf
, stdoff
!= 0, startttisstd
,
2497 addtt(starttime
, type
);
2499 } else addtt(early_time
, type
);
2500 } else for (year
= min_year
; year
<= max_year
; ++year
) {
2501 if (useuntil
&& year
> zp
->z_untilrule
.r_hiyear
)
2504 ** Mark which rules to do in the current year.
2505 ** For those to do, calculate rpytime(rp, year);
2507 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2508 rp
= &zp
->z_rules
[j
];
2509 eats(zp
->z_filename
, zp
->z_linenum
,
2510 rp
->r_filename
, rp
->r_linenum
);
2511 rp
->r_todo
= year
>= rp
->r_loyear
&&
2512 year
<= rp
->r_hiyear
&&
2513 yearistype(year
, rp
->r_yrtype
);
2515 rp
->r_temp
= rpytime(rp
, year
);
2517 = (rp
->r_temp
< y2038_boundary
2518 || year
<= max_year0
);
2522 register ptrdiff_t k
;
2523 register zic_t jtime
, ktime
;
2524 register zic_t offset
;
2529 ** Turn untiltime into UT
2530 ** assuming the current gmtoff and
2533 untiltime
= zp
->z_untiltime
;
2534 if (!zp
->z_untilrule
.r_todisgmt
)
2535 untiltime
= tadd(untiltime
,
2537 if (!zp
->z_untilrule
.r_todisstd
)
2538 untiltime
= tadd(untiltime
,
2542 ** Find the rule (of those to do, if any)
2543 ** that takes effect earliest in the year.
2546 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2547 rp
= &zp
->z_rules
[j
];
2550 eats(zp
->z_filename
, zp
->z_linenum
,
2551 rp
->r_filename
, rp
->r_linenum
);
2552 offset
= rp
->r_todisgmt
? 0 : gmtoff
;
2553 if (!rp
->r_todisstd
)
2554 offset
= oadd(offset
, stdoff
);
2556 if (jtime
== min_time
||
2559 jtime
= tadd(jtime
, -offset
);
2560 if (k
< 0 || jtime
< ktime
) {
2563 } else if (jtime
== ktime
) {
2564 char const *dup_rules_msg
=
2565 _("two rules for same instant");
2566 eats(zp
->z_filename
, zp
->z_linenum
,
2567 rp
->r_filename
, rp
->r_linenum
);
2568 warning("%s", dup_rules_msg
);
2569 rp
= &zp
->z_rules
[k
];
2570 eats(zp
->z_filename
, zp
->z_linenum
,
2571 rp
->r_filename
, rp
->r_linenum
);
2572 error("%s", dup_rules_msg
);
2576 break; /* go on to next year */
2577 rp
= &zp
->z_rules
[k
];
2579 if (useuntil
&& ktime
>= untiltime
)
2581 stdoff
= rp
->r_stdoff
;
2582 if (usestart
&& ktime
== starttime
)
2585 if (ktime
< starttime
) {
2586 startoff
= oadd(zp
->z_gmtoff
,
2588 doabbr(startbuf
, zp
,
2594 if (*startbuf
== '\0' &&
2595 startoff
== oadd(zp
->z_gmtoff
,
2604 eats(zp
->z_filename
, zp
->z_linenum
,
2605 rp
->r_filename
, rp
->r_linenum
);
2606 doabbr(ab
, zp
, rp
->r_abbrvar
,
2607 rp
->r_stdoff
, false);
2608 offset
= oadd(zp
->z_gmtoff
, rp
->r_stdoff
);
2609 type
= addtype(offset
, ab
, rp
->r_stdoff
!= 0,
2610 rp
->r_todisstd
, rp
->r_todisgmt
);
2611 if (rp
->r_hiyear
== ZIC_MAX
2612 && ! (0 <= lastatmax
2613 && ktime
< attypes
[lastatmax
].at
))
2614 lastatmax
= timecnt
;
2619 if (*startbuf
== '\0' &&
2620 zp
->z_format
!= NULL
&&
2621 strchr(zp
->z_format
, '%') == NULL
&&
2622 strchr(zp
->z_format
, '/') == NULL
)
2623 strcpy(startbuf
, zp
->z_format
);
2624 eat(zp
->z_filename
, zp
->z_linenum
);
2625 if (*startbuf
== '\0')
2626 error(_("can't determine time zone abbreviation to use just after until time"));
2627 else addtt(starttime
,
2628 addtype(startoff
, startbuf
,
2629 startoff
!= zp
->z_gmtoff
,
2634 ** Now we may get to set starttime for the next zone line.
2637 startttisstd
= zp
->z_untilrule
.r_todisstd
;
2638 startttisgmt
= zp
->z_untilrule
.r_todisgmt
;
2639 starttime
= zp
->z_untiltime
;
2641 starttime
= tadd(starttime
, -stdoff
);
2643 starttime
= tadd(starttime
, -gmtoff
);
2647 attypes
[lastatmax
].dontmerge
= true;
2650 ** If we're extending the explicitly listed observations
2651 ** for 400 years because we can't fill the POSIX-TZ field,
2652 ** check whether we actually ended up explicitly listing
2653 ** observations through that period. If there aren't any
2654 ** near the end of the 400-year period, add a redundant
2655 ** one at the end of the final year, to make it clear
2656 ** that we are claiming to have definite knowledge of
2657 ** the lack of transitions up to that point.
2660 struct attype
*lastat
;
2661 xr
.r_month
= TM_JANUARY
;
2662 xr
.r_dycode
= DC_DOM
;
2663 xr
.r_dayofmonth
= 1;
2665 for (lastat
= &attypes
[0], i
= 1; i
< timecnt
; i
++)
2666 if (attypes
[i
].at
> lastat
->at
)
2667 lastat
= &attypes
[i
];
2668 if (lastat
->at
< rpytime(&xr
, max_year
- 1)) {
2669 addtt(rpytime(&xr
, max_year
+ 1), typecnt
-1);
2670 attypes
[timecnt
- 1].dontmerge
= true;
2673 writezone(zpfirst
->z_name
, envvar
, version
);
2680 addtt(zic_t starttime
, int type
)
2682 if (starttime
<= early_time
2683 || (timecnt
== 1 && attypes
[0].at
< early_time
)) {
2684 gmtoffs
[0] = gmtoffs
[type
];
2685 isdsts
[0] = isdsts
[type
];
2686 ttisstds
[0] = ttisstds
[type
];
2687 ttisgmts
[0] = ttisgmts
[type
];
2688 if (abbrinds
[type
] != 0)
2689 strcpy(chars
, &chars
[abbrinds
[type
]]);
2691 charcnt
= strlen(chars
) + 1;
2696 attypes
= growalloc(attypes
, sizeof *attypes
, timecnt
, &timecnt_alloc
);
2697 attypes
[timecnt
].at
= starttime
;
2698 attypes
[timecnt
].dontmerge
= false;
2699 attypes
[timecnt
].type
= type
;
2704 addtype(zic_t gmtoff
, char const *abbr
, bool isdst
, bool ttisstd
, bool ttisgmt
)
2709 ** See if there's already an entry for this zone type.
2710 ** If so, just return its index.
2712 for (i
= 0; i
< typecnt
; ++i
) {
2713 if (gmtoff
== gmtoffs
[i
] && isdst
== isdsts
[i
] &&
2714 strcmp(abbr
, &chars
[abbrinds
[i
]]) == 0 &&
2715 ttisstd
== ttisstds
[i
] &&
2716 ttisgmt
== ttisgmts
[i
])
2720 ** There isn't one; add a new one, unless there are already too
2723 if (typecnt
>= TZ_MAX_TYPES
) {
2724 error(_("too many local time types"));
2727 if (! (-1L - 2147483647L <= gmtoff
&& gmtoff
<= 2147483647L)) {
2728 error(_("UT offset out of range"));
2731 gmtoffs
[i
] = gmtoff
;
2733 ttisstds
[i
] = ttisstd
;
2734 ttisgmts
[i
] = ttisgmt
;
2736 for (j
= 0; j
< charcnt
; ++j
)
2737 if (strcmp(&chars
[j
], abbr
) == 0)
2747 leapadd(zic_t t
, bool positive
, int rolling
, int count
)
2751 if (leapcnt
+ (positive
? count
: 1) > TZ_MAX_LEAPS
) {
2752 error(_("too many leap seconds"));
2755 for (i
= 0; i
< leapcnt
; ++i
)
2756 if (t
<= trans
[i
]) {
2757 if (t
== trans
[i
]) {
2758 error(_("repeated leap second moment"));
2764 for (j
= leapcnt
; j
> i
; --j
) {
2765 trans
[j
] = trans
[j
- 1];
2766 corr
[j
] = corr
[j
- 1];
2767 roll
[j
] = roll
[j
- 1];
2770 corr
[i
] = positive
? 1 : -count
;
2773 } while (positive
&& --count
!= 0);
2780 register zic_t last
= 0;
2783 ** propagate leap seconds forward
2785 for (i
= 0; i
< leapcnt
; ++i
) {
2786 trans
[i
] = tadd(trans
[i
], last
);
2787 last
= corr
[i
] += last
;
2792 shellquote(char *b
, char const *s
)
2797 *b
++ = '\'', *b
++ = '\\', *b
++ = '\'';
2805 yearistype(zic_t year
, const char *type
)
2811 if (type
== NULL
|| *type
== '\0')
2813 buf
= emalloc(1 + 4 * strlen(yitcommand
) + 2
2814 + INT_STRLEN_MAXIMUM(zic_t
) + 2 + 4 * strlen(type
) + 2);
2815 b
= shellquote(buf
, yitcommand
);
2817 b
+= sprintf(b
, "%"PRIdZIC
, year
);
2819 b
= shellquote(b
, type
);
2821 result
= system(buf
);
2822 if (WIFEXITED(result
)) {
2823 int status
= WEXITSTATUS(result
);
2829 error(_("Wild result from command execution"));
2830 fprintf(stderr
, _("%s: command was '%s', result was %d\n"),
2831 progname
, buf
, result
);
2835 /* Is A a space character in the C locale? */
2842 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2847 /* Is A an alphabetic character in the C locale? */
2854 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2855 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2856 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2857 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2858 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2859 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2860 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2861 case 'v': case 'w': case 'x': case 'y': case 'z':
2866 /* If A is an uppercase character in the C locale, return its lowercase
2867 counterpart. Otherwise, return A. */
2873 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2874 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2875 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2876 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2877 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2878 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2879 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2880 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2881 case 'Y': return 'y'; case 'Z': return 'z';
2885 /* case-insensitive equality */
2886 static ATTRIBUTE_PURE
bool
2887 ciequal(register const char *ap
, register const char *bp
)
2889 while (lowerit(*ap
) == lowerit(*bp
++))
2895 static ATTRIBUTE_PURE
bool
2896 itsabbr(register const char *abbr
, register const char *word
)
2898 if (lowerit(*abbr
) != lowerit(*word
))
2901 while (*++abbr
!= '\0')
2905 } while (lowerit(*word
++) != lowerit(*abbr
));
2909 static ATTRIBUTE_PURE
const struct lookup
*
2910 byword(const char *word
, const struct lookup
*table
)
2912 register const struct lookup
* foundlp
;
2913 register const struct lookup
* lp
;
2915 if (word
== NULL
|| table
== NULL
)
2918 ** Look for exact match.
2920 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2921 if (ciequal(word
, lp
->l_word
))
2924 ** Look for inexact match.
2927 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2928 if (itsabbr(word
, lp
->l_word
)) {
2929 if (foundlp
== NULL
)
2931 else return NULL
; /* multiple inexact matches */
2937 getfields(register char *cp
)
2940 register char ** array
;
2945 array
= emalloc(size_product(strlen(cp
) + 1, sizeof *array
));
2948 while (is_space(*cp
))
2950 if (*cp
== '\0' || *cp
== '#')
2952 array
[nsubs
++] = dp
= cp
;
2954 if ((*dp
= *cp
++) != '"')
2956 else while ((*dp
= *cp
++) != '"')
2960 error(_("Odd number of quotation marks"));
2963 } while (*cp
&& *cp
!= '#' && !is_space(*cp
));
2968 array
[nsubs
] = NULL
;
2972 static _Noreturn
void
2975 error(_("time overflow"));
2979 static ATTRIBUTE_PURE zic_t
2980 oadd(zic_t t1
, zic_t t2
)
2982 if (t1
< 0 ? t2
< ZIC_MIN
- t1
: ZIC_MAX
- t1
< t2
)
2987 static ATTRIBUTE_PURE zic_t
2988 tadd(zic_t t1
, zic_t t2
)
2991 if (t2
< min_time
- t1
) {
2997 if (max_time
- t1
< t2
) {
3007 ** Given a rule, and a year, compute the date (in seconds since January 1,
3008 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
3012 rpytime(const struct rule
*rp
, zic_t wantedy
)
3015 register zic_t dayoff
; /* with a nod to Margaret O. */
3016 register zic_t t
, y
;
3018 if (wantedy
== ZIC_MIN
)
3020 if (wantedy
== ZIC_MAX
)
3025 while (wantedy
!= y
) {
3027 i
= len_years
[isleap(y
)];
3031 i
= -len_years
[isleap(y
)];
3033 dayoff
= oadd(dayoff
, i
);
3035 while (m
!= rp
->r_month
) {
3036 i
= len_months
[isleap(y
)][m
];
3037 dayoff
= oadd(dayoff
, i
);
3040 i
= rp
->r_dayofmonth
;
3041 if (m
== TM_FEBRUARY
&& i
== 29 && !isleap(y
)) {
3042 if (rp
->r_dycode
== DC_DOWLEQ
)
3045 error(_("use of 2/29 in non leap-year"));
3050 dayoff
= oadd(dayoff
, i
);
3051 if (rp
->r_dycode
== DC_DOWGEQ
|| rp
->r_dycode
== DC_DOWLEQ
) {
3052 register zic_t wday
;
3054 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3057 ** Don't trust mod of negative numbers.
3060 wday
= (wday
+ dayoff
) % LDAYSPERWEEK
;
3062 wday
-= ((-dayoff
) % LDAYSPERWEEK
);
3064 wday
+= LDAYSPERWEEK
;
3066 while (wday
!= rp
->r_wday
)
3067 if (rp
->r_dycode
== DC_DOWGEQ
) {
3068 dayoff
= oadd(dayoff
, 1);
3069 if (++wday
>= LDAYSPERWEEK
)
3073 dayoff
= oadd(dayoff
, -1);
3075 wday
= LDAYSPERWEEK
- 1;
3078 if (i
< 0 || i
>= len_months
[isleap(y
)][m
]) {
3080 warning(_("rule goes past start/end of month; \
3081 will not work with pre-2004 versions of zic"));
3084 if (dayoff
< min_time
/ SECSPERDAY
)
3086 if (dayoff
> max_time
/ SECSPERDAY
)
3088 t
= (zic_t
) dayoff
* SECSPERDAY
;
3089 return tadd(t
, rp
->r_tod
);
3093 newabbr(const char *string
)
3097 if (strcmp(string
, GRANDPARENTED
) != 0) {
3098 register const char * cp
;
3103 while (is_alpha(*cp
) || ('0' <= *cp
&& *cp
<= '9')
3104 || *cp
== '-' || *cp
== '+')
3106 if (noise
&& cp
- string
< 3)
3107 mp
= _("time zone abbreviation has fewer than 3 characters");
3108 if (cp
- string
> ZIC_MAX_ABBR_LEN_WO_WARN
)
3109 mp
= _("time zone abbreviation has too many characters");
3111 mp
= _("time zone abbreviation differs from POSIX standard");
3113 warning("%s (%s)", mp
, string
);
3115 i
= strlen(string
) + 1;
3116 if (charcnt
+ i
> TZ_MAX_CHARS
) {
3117 error(_("too many, or too long, time zone abbreviations"));
3120 strcpy(&chars
[charcnt
], string
);
3124 /* Ensure that the directories of ARGNAME exist, by making any missing
3125 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3126 do it for ARGNAME too. Exit with failure if there is trouble.
3127 Do not consider an existing non-directory to be trouble. */
3129 mkdirs(char const *argname
, bool ancestors
)
3131 register char * name
;
3134 cp
= name
= ecpyalloc(argname
);
3136 /* Do not mkdir a root directory, as it must exist. */
3137 #ifdef HAVE_DOS_FILE_NAMES
3138 if (is_alpha(name
[0]) && name
[1] == ':')
3144 while (cp
&& ((cp
= strchr(cp
, '/')) || !ancestors
)) {
3148 ** Try to create it. It's OK if creation fails because
3149 ** the directory already exists, perhaps because some
3150 ** other process just created it. For simplicity do
3151 ** not check first whether it already exists, as that
3152 ** is checked anyway if the mkdir fails.
3154 if (mkdir(name
, MKDIR_UMASK
) != 0) {
3155 /* For speed, skip itsdir if errno == EEXIST. Since
3156 mkdirs is called only after open fails with ENOENT
3157 on a subfile, EEXIST implies itsdir here. */
3159 if (err
!= EEXIST
&& !itsdir(name
)) {
3160 error(_("%s: Can't create directory %s: %s"),
3161 progname
, name
, strerror(err
));