1 /* Compile .zi time zone data into TZif binary files. */
4 ** This file is in the public domain, so clarified as of
5 ** 2006-07-17 by Arthur David Olson.
18 #define ZIC_VERSION_PRE_2013 '2'
19 #define ZIC_VERSION '3'
21 typedef int_fast64_t zic_t
;
22 #define ZIC_MIN INT_FAST64_MIN
23 #define ZIC_MAX INT_FAST64_MAX
24 #define PRIdZIC PRIdFAST64
25 #define SCNdZIC SCNdFAST64
27 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
28 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
29 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
35 # define mkdir(name, mode) _mkdir(name)
42 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
44 #define MKDIR_UMASK 0755
46 /* Port to native MS-Windows and to ancient UNIX. */
47 #if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT
48 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
52 #include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
53 #endif /* HAVE_SYS_WAIT_H */
56 #define WIFEXITED(status) (((status) & 0xff) == 0)
57 #endif /* !defined WIFEXITED */
59 #define WEXITSTATUS(status) (((status) >> 8) & 0xff)
60 #endif /* !defined WEXITSTATUS */
62 /* The maximum ptrdiff_t value, for pre-C99 platforms. */
64 static ptrdiff_t const PTRDIFF_MAX
= MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
67 /* The minimum alignment of a type, for pre-C11 platforms. */
68 #if __STDC_VERSION__ < 201112
69 # define _Alignof(type) offsetof(struct { char a; type b; }, b)
72 /* The type for line numbers. Use PRIdMAX to format them; formerly
73 there was also "#define PRIdLINENO PRIdMAX" and formats used
74 PRIdLINENO, but xgettext cannot grok that. */
75 typedef intmax_t lineno
;
78 const char * r_filename
;
82 zic_t r_loyear
; /* for example, 1986 */
83 zic_t r_hiyear
; /* for example, 1986 */
84 const char * r_yrtype
;
88 int r_month
; /* 0..11 */
90 int r_dycode
; /* see below */
94 zic_t r_tod
; /* time from midnight */
95 bool r_todisstd
; /* is r_tod standard time? */
96 bool r_todisut
; /* is r_tod UT? */
97 bool r_isdst
; /* is this daylight saving time? */
98 zic_t r_save
; /* offset from standard time */
99 const char * r_abbrvar
; /* variable part of abbreviation */
101 bool r_todo
; /* a rule to do (used in outzone) */
102 zic_t r_temp
; /* used in outzone */
106 ** r_dycode r_dayofmonth r_wday
109 #define DC_DOM 0 /* 1..31 */ /* unused */
110 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
111 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
114 const char * z_filename
;
120 const char * z_format
;
121 char z_format_specifier
;
126 struct rule
* z_rules
;
129 struct rule z_untilrule
;
133 #if !HAVE_POSIX_DECLS
134 extern int getopt(int argc
, char * const argv
[],
135 const char * options
);
136 extern int link(const char * fromname
, const char * toname
);
137 extern char * optarg
;
142 # define link(from, to) (errno = ENOTSUP, -1)
145 # define readlink(file, buf, size) (errno = ENOTSUP, -1)
146 # define symlink(from, to) (errno = ENOTSUP, -1)
147 # define S_ISLNK(m) 0
149 #ifndef AT_SYMLINK_FOLLOW
150 # define linkat(fromdir, from, todir, to, flag) \
151 (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
154 static void addtt(zic_t starttime
, int type
);
155 static int addtype(zic_t
, char const *, bool, bool, bool);
156 static void leapadd(zic_t
, int, int);
157 static void adjleap(void);
158 static void associate(void);
159 static void dolink(const char *, const char *, bool);
160 static char ** getfields(char * buf
);
161 static zic_t
gethms(const char * string
, const char * errstring
);
162 static zic_t
getsave(char *, bool *);
163 static void inexpires(char **, int);
164 static void infile(const char * filename
);
165 static void inleap(char ** fields
, int nfields
);
166 static void inlink(char ** fields
, int nfields
);
167 static void inrule(char ** fields
, int nfields
);
168 static bool inzcont(char ** fields
, int nfields
);
169 static bool inzone(char ** fields
, int nfields
);
170 static bool inzsub(char **, int, bool);
171 static bool itsdir(char const *);
172 static bool itssymlink(char const *);
173 static bool is_alpha(char a
);
174 static char lowerit(char);
175 static void mkdirs(char const *, bool);
176 static void newabbr(const char * abbr
);
177 static zic_t
oadd(zic_t t1
, zic_t t2
);
178 static void outzone(const struct zone
* zp
, ptrdiff_t ntzones
);
179 static zic_t
rpytime(const struct rule
* rp
, zic_t wantedy
);
180 static void rulesub(struct rule
* rp
,
181 const char * loyearp
, const char * hiyearp
,
182 const char * typep
, const char * monthp
,
183 const char * dayp
, const char * timep
);
184 static zic_t
tadd(zic_t t1
, zic_t t2
);
185 static bool yearistype(zic_t year
, const char * type
);
187 /* Bound on length of what %z can expand to. */
188 enum { PERCENT_Z_LEN_BOUND
= sizeof "+995959" - 1 };
190 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
191 TZif files whose POSIX-TZ-style strings contain '<'; see
192 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
193 workaround will no longer be needed when Qt 5.6.1 and earlier are
194 obsolete, say in the year 2021. */
195 #ifndef WORK_AROUND_QTBUG_53071
196 enum { WORK_AROUND_QTBUG_53071
= true };
201 static bool warnings
;
202 static const char * filename
;
204 static bool leapseen
;
205 static zic_t leapminyear
;
206 static zic_t leapmaxyear
;
207 static lineno linenum
;
208 static int max_abbrvar_len
= PERCENT_Z_LEN_BOUND
;
209 static int max_format_len
;
210 static zic_t max_year
;
211 static zic_t min_year
;
213 static const char * rfilename
;
214 static lineno rlinenum
;
215 static const char * progname
;
216 static ptrdiff_t timecnt
;
217 static ptrdiff_t timecnt_alloc
;
231 ** Which fields are which on a Zone line.
239 #define ZF_TILMONTH 6
242 #define ZONE_MINFIELDS 5
243 #define ZONE_MAXFIELDS 9
246 ** Which fields are which on a Zone continuation line.
252 #define ZFC_TILYEAR 3
253 #define ZFC_TILMONTH 4
255 #define ZFC_TILTIME 6
256 #define ZONEC_MINFIELDS 3
257 #define ZONEC_MAXFIELDS 7
260 ** Which files are which on a Rule line.
272 #define RULE_FIELDS 10
275 ** Which fields are which on a Link line.
280 #define LINK_FIELDS 3
283 ** Which fields are which on a Leap line.
292 #define LEAP_FIELDS 7
294 /* Expires lines are like Leap lines, except without CORR and ROLL fields. */
295 #define EXPIRES_FIELDS 5
305 static struct rule
* rules
;
306 static ptrdiff_t nrules
; /* number of rules */
307 static ptrdiff_t nrules_alloc
;
309 static struct zone
* zones
;
310 static ptrdiff_t nzones
; /* number of zones */
311 static ptrdiff_t nzones_alloc
;
314 const char * l_filename
;
320 static struct link
* links
;
321 static ptrdiff_t nlinks
;
322 static ptrdiff_t nlinks_alloc
;
329 static struct lookup
const * byword(const char * string
,
330 const struct lookup
* lp
);
332 static struct lookup
const zi_line_codes
[] = {
338 static struct lookup
const leap_line_codes
[] = {
340 { "Expires", LC_EXPIRES
},
344 static struct lookup
const mon_names
[] = {
345 { "January", TM_JANUARY
},
346 { "February", TM_FEBRUARY
},
347 { "March", TM_MARCH
},
348 { "April", TM_APRIL
},
352 { "August", TM_AUGUST
},
353 { "September", TM_SEPTEMBER
},
354 { "October", TM_OCTOBER
},
355 { "November", TM_NOVEMBER
},
356 { "December", TM_DECEMBER
},
360 static struct lookup
const wday_names
[] = {
361 { "Sunday", TM_SUNDAY
},
362 { "Monday", TM_MONDAY
},
363 { "Tuesday", TM_TUESDAY
},
364 { "Wednesday", TM_WEDNESDAY
},
365 { "Thursday", TM_THURSDAY
},
366 { "Friday", TM_FRIDAY
},
367 { "Saturday", TM_SATURDAY
},
371 static struct lookup
const lasts
[] = {
372 { "last-Sunday", TM_SUNDAY
},
373 { "last-Monday", TM_MONDAY
},
374 { "last-Tuesday", TM_TUESDAY
},
375 { "last-Wednesday", TM_WEDNESDAY
},
376 { "last-Thursday", TM_THURSDAY
},
377 { "last-Friday", TM_FRIDAY
},
378 { "last-Saturday", TM_SATURDAY
},
382 static struct lookup
const begin_years
[] = {
383 { "minimum", YR_MINIMUM
},
384 { "maximum", YR_MAXIMUM
},
388 static struct lookup
const end_years
[] = {
389 { "minimum", YR_MINIMUM
},
390 { "maximum", YR_MAXIMUM
},
395 static struct lookup
const leap_types
[] = {
397 { "Stationary", false },
401 static const int len_months
[2][MONSPERYEAR
] = {
402 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
403 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
406 static const int len_years
[2] = {
407 DAYSPERNYEAR
, DAYSPERLYEAR
410 static struct attype
{
415 static zic_t utoffs
[TZ_MAX_TYPES
];
416 static char isdsts
[TZ_MAX_TYPES
];
417 static unsigned char desigidx
[TZ_MAX_TYPES
];
418 static bool ttisstds
[TZ_MAX_TYPES
];
419 static bool ttisuts
[TZ_MAX_TYPES
];
420 static char chars
[TZ_MAX_CHARS
];
421 static zic_t trans
[TZ_MAX_LEAPS
];
422 static zic_t corr
[TZ_MAX_LEAPS
];
423 static char roll
[TZ_MAX_LEAPS
];
426 ** Memory allocation.
429 static _Noreturn
void
430 memory_exhausted(const char *msg
)
432 fprintf(stderr
, _("%s: Memory exhausted: %s\n"), progname
, msg
);
436 static ATTRIBUTE_PURE
size_t
437 size_product(size_t nitems
, size_t itemsize
)
439 if (SIZE_MAX
/ itemsize
< nitems
)
440 memory_exhausted(_("size overflow"));
441 return nitems
* itemsize
;
444 static ATTRIBUTE_PURE
size_t
445 align_to(size_t size
, size_t alignment
)
447 size_t aligned_size
= size
+ alignment
- 1;
448 aligned_size
-= aligned_size
% alignment
;
449 if (aligned_size
< size
)
450 memory_exhausted(_("alignment overflow"));
456 strdup(char const *str
)
458 char *result
= malloc(strlen(str
) + 1);
459 return result
? strcpy(result
, str
) : result
;
467 memory_exhausted(strerror(errno
));
471 static void * ATTRIBUTE_MALLOC
474 return memcheck(malloc(size
));
478 erealloc(void *ptr
, size_t size
)
480 return memcheck(realloc(ptr
, size
));
483 static char * ATTRIBUTE_MALLOC
484 ecpyalloc (char const *str
)
486 return memcheck(strdup(str
));
490 growalloc(void *ptr
, size_t itemsize
, ptrdiff_t nitems
, ptrdiff_t *nitems_alloc
)
492 if (nitems
< *nitems_alloc
)
495 ptrdiff_t nitems_max
= PTRDIFF_MAX
- WORK_AROUND_QTBUG_53071
;
496 ptrdiff_t amax
= nitems_max
< SIZE_MAX
? nitems_max
: SIZE_MAX
;
497 if ((amax
- 1) / 3 * 2 < *nitems_alloc
)
498 memory_exhausted(_("integer overflow"));
499 *nitems_alloc
+= (*nitems_alloc
>> 1) + 1;
500 return erealloc(ptr
, size_product(*nitems_alloc
, itemsize
));
509 eats(char const *name
, lineno num
, char const *rname
, lineno rnum
)
518 eat(char const *name
, lineno num
)
520 eats(name
, num
, NULL
, -1);
523 static void ATTRIBUTE_FORMAT((printf
, 1, 0))
524 verror(const char *const string
, va_list args
)
527 ** Match the format of "cc" to allow sh users to
528 ** zic ... 2>&1 | error -t "*" -v
532 fprintf(stderr
, _("\"%s\", line %"PRIdMAX
": "), filename
, linenum
);
533 vfprintf(stderr
, string
, args
);
534 if (rfilename
!= NULL
)
535 fprintf(stderr
, _(" (rule from \"%s\", line %"PRIdMAX
")"),
536 rfilename
, rlinenum
);
537 fprintf(stderr
, "\n");
540 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
541 error(const char *const string
, ...)
544 va_start(args
, string
);
545 verror(string
, args
);
550 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
551 warning(const char *const string
, ...)
554 fprintf(stderr
, _("warning: "));
555 va_start(args
, string
);
556 verror(string
, args
);
562 close_file(FILE *stream
, char const *dir
, char const *name
)
564 char const *e
= (ferror(stream
) ? _("I/O error")
565 : fclose(stream
) != 0 ? strerror(errno
) : NULL
);
567 fprintf(stderr
, "%s: %s%s%s%s%s\n", progname
,
568 dir
? dir
: "", dir
? "/" : "",
569 name
? name
: "", name
? ": " : "",
575 static _Noreturn
void
576 usage(FILE *stream
, int status
)
579 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
580 "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]"
581 " [ -L leapseconds ] \\\n"
582 "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -t localtime-link ] \\\n"
583 "\t[ filename ... ]\n\n"
584 "Report bugs to %s.\n"),
585 progname
, progname
, REPORT_BUGS_TO
);
586 if (status
== EXIT_SUCCESS
)
587 close_file(stream
, NULL
, NULL
);
591 /* Change the working directory to DIR, possibly creating DIR and its
592 ancestors. After this is done, all files are accessed with names
595 change_directory (char const *dir
)
597 if (chdir(dir
) != 0) {
598 int chdir_errno
= errno
;
599 if (chdir_errno
== ENOENT
) {
601 chdir_errno
= chdir(dir
) == 0 ? 0 : errno
;
603 if (chdir_errno
!= 0) {
604 fprintf(stderr
, _("%s: Can't chdir to %s: %s\n"),
605 progname
, dir
, strerror(chdir_errno
));
611 #define TIME_T_BITS_IN_FILE 64
613 /* The minimum and maximum values representable in a TZif file. */
614 static zic_t
const min_time
= MINVAL(zic_t
, TIME_T_BITS_IN_FILE
);
615 static zic_t
const max_time
= MAXVAL(zic_t
, TIME_T_BITS_IN_FILE
);
617 /* The minimum, and one less than the maximum, values specified by
618 the -r option. These default to MIN_TIME and MAX_TIME. */
619 static zic_t lo_time
= MINVAL(zic_t
, TIME_T_BITS_IN_FILE
);
620 static zic_t hi_time
= MAXVAL(zic_t
, TIME_T_BITS_IN_FILE
);
622 /* The time specified by an Expires line, or negative if no such line. */
623 static zic_t leapexpires
= -1;
625 /* The time specified by an #expires comment, or negative if no such line. */
626 static zic_t comment_leapexpires
= -1;
628 /* Set the time range of the output to TIMERANGE.
629 Return true if successful. */
631 timerange_option(char *timerange
)
633 intmax_t lo
= min_time
, hi
= max_time
;
634 char *lo_end
= timerange
, *hi_end
;
635 if (*timerange
== '@') {
637 lo
= strtoimax (timerange
+ 1, &lo_end
, 10);
638 if (lo_end
== timerange
+ 1 || (lo
== INTMAX_MAX
&& errno
== ERANGE
))
642 if (lo_end
[0] == '/' && lo_end
[1] == '@') {
644 hi
= strtoimax (lo_end
+ 2, &hi_end
, 10);
645 if (hi_end
== lo_end
+ 2 || hi
== INTMAX_MIN
)
647 hi
-= ! (hi
== INTMAX_MAX
&& errno
== ERANGE
);
649 if (*hi_end
|| hi
< lo
|| max_time
< lo
|| hi
< min_time
)
651 lo_time
= lo
< min_time
? min_time
: lo
;
652 hi_time
= max_time
< hi
? max_time
: hi
;
656 static const char * psxrules
;
657 static const char * lcltime
;
658 static const char * directory
;
659 static const char * leapsec
;
660 static const char * tzdefault
;
661 static const char * yitcommand
;
663 /* -1 if the TZif output file should be slim, 0 if default, 1 if the
664 output should be fat for backward compatibility. Currently the
665 default is fat, although this may change. */
674 #ifndef ZIC_BLOAT_DEFAULT
675 # define ZIC_BLOAT_DEFAULT "fat"
679 main(int argc
, char **argv
)
682 register ptrdiff_t i
, j
;
683 bool timerange_given
= false;
686 umask(umask(S_IWGRP
| S_IWOTH
) | (S_IWGRP
| S_IWOTH
));
689 setlocale(LC_ALL
, "");
691 bindtextdomain(TZ_DOMAIN
, TZ_DOMAINDIR
);
692 #endif /* defined TEXTDOMAINDIR */
693 textdomain(TZ_DOMAIN
);
694 #endif /* HAVE_GETTEXT */
696 if (TYPE_BIT(zic_t
) < 64) {
697 fprintf(stderr
, "%s: %s\n", progname
,
698 _("wild compilation-time specification of zic_t"));
701 for (k
= 1; k
< argc
; k
++)
702 if (strcmp(argv
[k
], "--version") == 0) {
703 printf("zic %s%s\n", PKGVERSION
, TZVERSION
);
704 close_file(stdout
, NULL
, NULL
);
706 } else if (strcmp(argv
[k
], "--help") == 0) {
707 usage(stdout
, EXIT_SUCCESS
);
709 while ((c
= getopt(argc
, argv
, "b:d:l:L:p:r:st:vy:")) != EOF
&& c
!= -1)
712 usage(stderr
, EXIT_FAILURE
);
714 if (strcmp(optarg
, "slim") == 0) {
716 error(_("incompatible -b options"));
718 } else if (strcmp(optarg
, "fat") == 0) {
720 error(_("incompatible -b options"));
723 error(_("invalid option: -b '%s'"), optarg
);
726 if (directory
== NULL
)
730 _("%s: More than one -d option specified\n"),
740 _("%s: More than one -l option specified\n"),
746 if (psxrules
== NULL
)
750 _("%s: More than one -p option specified\n"),
756 if (tzdefault
!= NULL
) {
758 _("%s: More than one -t option"
766 if (yitcommand
== NULL
) {
767 warning(_("-y is obsolescent"));
771 _("%s: More than one -y option specified\n"),
781 _("%s: More than one -L option specified\n"),
790 if (timerange_given
) {
792 _("%s: More than one -r option specified\n"),
796 if (! timerange_option(optarg
)) {
798 _("%s: invalid time range: %s\n"),
802 timerange_given
= true;
805 warning(_("-s ignored"));
808 if (optind
== argc
- 1 && strcmp(argv
[optind
], "=") == 0)
809 usage(stderr
, EXIT_FAILURE
); /* usage message by request */
811 bloat
= strcmp(ZIC_BLOAT_DEFAULT
, "slim") == 0 ? -1 : 1;
812 if (directory
== NULL
)
814 if (tzdefault
== NULL
)
815 tzdefault
= TZDEFAULT
;
816 if (yitcommand
== NULL
)
817 yitcommand
= "yearistype";
819 if (optind
< argc
&& leapsec
!= NULL
) {
824 for (k
= optind
; k
< argc
; k
++)
829 change_directory(directory
);
830 for (i
= 0; i
< nzones
; i
= j
) {
832 ** Find the next non-continuation zone entry.
834 for (j
= i
+ 1; j
< nzones
&& zones
[j
].z_name
== NULL
; ++j
)
836 outzone(&zones
[i
], j
- i
);
841 for (i
= 0; i
< nlinks
; ++i
) {
842 eat(links
[i
].l_filename
, links
[i
].l_linenum
);
843 dolink(links
[i
].l_from
, links
[i
].l_to
, false);
845 for (j
= 0; j
< nlinks
; ++j
)
846 if (strcmp(links
[i
].l_to
,
847 links
[j
].l_from
) == 0)
848 warning(_("link to link"));
850 if (lcltime
!= NULL
) {
851 eat(_("command line"), 1);
852 dolink(lcltime
, tzdefault
, true);
854 if (psxrules
!= NULL
) {
855 eat(_("command line"), 1);
856 dolink(psxrules
, TZDEFRULES
, true);
858 if (warnings
&& (ferror(stderr
) || fclose(stderr
) != 0))
860 return errors
? EXIT_FAILURE
: EXIT_SUCCESS
;
864 componentcheck(char const *name
, char const *component
,
865 char const *component_end
)
867 enum { component_len_max
= 14 };
868 ptrdiff_t component_len
= component_end
- component
;
869 if (component_len
== 0) {
871 error (_("empty file name"));
873 error (_(component
== name
874 ? "file name '%s' begins with '/'"
876 ? "file name '%s' contains '//'"
877 : "file name '%s' ends with '/'"),
881 if (0 < component_len
&& component_len
<= 2
882 && component
[0] == '.' && component_end
[-1] == '.') {
883 int len
= component_len
;
884 error(_("file name '%s' contains '%.*s' component"),
885 name
, len
, component
);
889 if (0 < component_len
&& component
[0] == '-')
890 warning(_("file name '%s' component contains leading '-'"),
892 if (component_len_max
< component_len
)
893 warning(_("file name '%s' contains overlength component"
895 name
, component_len_max
, component
);
901 namecheck(const char *name
)
903 register char const *cp
;
905 /* Benign characters in a portable file name. */
906 static char const benign
[] =
908 "abcdefghijklmnopqrstuvwxyz"
909 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
911 /* Non-control chars in the POSIX portable character set,
912 excluding the benign characters. */
913 static char const printable_and_not_benign
[] =
914 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
916 register char const *component
= name
;
917 for (cp
= name
; *cp
; cp
++) {
918 unsigned char c
= *cp
;
919 if (noise
&& !strchr(benign
, c
)) {
920 warning((strchr(printable_and_not_benign
, c
)
921 ? _("file name '%s' contains byte '%c'")
922 : _("file name '%s' contains byte '\\%o'")),
926 if (!componentcheck(name
, component
, cp
))
931 return componentcheck(name
, component
, cp
);
934 /* Create symlink contents suitable for symlinking FROM to TO, as a
935 freshly allocated string. FROM should be a relative file name, and
936 is relative to the global variable DIRECTORY. TO can be either
937 relative or absolute. */
939 relname(char const *from
, char const *to
)
941 size_t i
, taillen
, dotdotetcsize
;
942 size_t dir_len
= 0, dotdots
= 0, linksize
= SIZE_MAX
;
943 char const *f
= from
;
946 /* Make F absolute too. */
947 size_t len
= strlen(directory
);
948 bool needslash
= len
&& directory
[len
- 1] != '/';
949 linksize
= len
+ needslash
+ strlen(from
) + 1;
950 f
= result
= emalloc(linksize
);
951 strcpy(result
, directory
);
953 strcpy(result
+ len
+ needslash
, from
);
955 for (i
= 0; f
[i
] && f
[i
] == to
[i
]; i
++)
959 dotdots
+= to
[i
] == '/' && to
[i
- 1] != '/';
960 taillen
= strlen(f
+ dir_len
);
961 dotdotetcsize
= 3 * dotdots
+ taillen
+ 1;
962 if (dotdotetcsize
<= linksize
) {
964 result
= emalloc(dotdotetcsize
);
965 for (i
= 0; i
< dotdots
; i
++)
966 memcpy(result
+ 3 * i
, "../", 3);
967 memmove(result
+ 3 * dotdots
, f
+ dir_len
, taillen
+ 1);
972 /* Hard link FROM to TO, following any symbolic links.
973 Return 0 if successful, an error number otherwise. */
975 hardlinkerr(char const *from
, char const *to
)
977 int r
= linkat(AT_FDCWD
, from
, AT_FDCWD
, to
, AT_SYMLINK_FOLLOW
);
978 return r
== 0 ? 0 : errno
;
982 dolink(char const *fromfield
, char const *tofield
, bool staysymlink
)
984 bool todirs_made
= false;
988 ** We get to be careful here since
989 ** there's a fair chance of root running us.
991 if (itsdir(fromfield
)) {
992 fprintf(stderr
, _("%s: link from %s/%s failed: %s\n"),
993 progname
, directory
, fromfield
, strerror(EPERM
));
997 staysymlink
= itssymlink(tofield
);
998 if (remove(tofield
) == 0)
1000 else if (errno
!= ENOENT
) {
1001 char const *e
= strerror(errno
);
1002 fprintf(stderr
, _("%s: Can't remove %s/%s: %s\n"),
1003 progname
, directory
, tofield
, e
);
1006 link_errno
= staysymlink
? ENOTSUP
: hardlinkerr(fromfield
, tofield
);
1007 if (link_errno
== ENOENT
&& !todirs_made
) {
1008 mkdirs(tofield
, true);
1010 link_errno
= hardlinkerr(fromfield
, tofield
);
1012 if (link_errno
!= 0) {
1013 bool absolute
= *fromfield
== '/';
1014 char *linkalloc
= absolute
? NULL
: relname(fromfield
, tofield
);
1015 char const *contents
= absolute
? fromfield
: linkalloc
;
1016 int symlink_errno
= symlink(contents
, tofield
) == 0 ? 0 : errno
;
1018 && (symlink_errno
== ENOENT
|| symlink_errno
== ENOTSUP
)) {
1019 mkdirs(tofield
, true);
1020 if (symlink_errno
== ENOENT
)
1021 symlink_errno
= symlink(contents
, tofield
) == 0 ? 0 : errno
;
1024 if (symlink_errno
== 0) {
1025 if (link_errno
!= ENOTSUP
)
1026 warning(_("symbolic link used because hard link failed: %s"),
1027 strerror(link_errno
));
1031 fp
= fopen(fromfield
, "rb");
1033 char const *e
= strerror(errno
);
1034 fprintf(stderr
, _("%s: Can't read %s/%s: %s\n"),
1035 progname
, directory
, fromfield
, e
);
1038 tp
= fopen(tofield
, "wb");
1040 char const *e
= strerror(errno
);
1041 fprintf(stderr
, _("%s: Can't create %s/%s: %s\n"),
1042 progname
, directory
, tofield
, e
);
1045 while ((c
= getc(fp
)) != EOF
)
1047 close_file(fp
, directory
, fromfield
);
1048 close_file(tp
, directory
, tofield
);
1049 if (link_errno
!= ENOTSUP
)
1050 warning(_("copy used because hard link failed: %s"),
1051 strerror(link_errno
));
1052 else if (symlink_errno
!= ENOTSUP
)
1053 warning(_("copy used because symbolic link failed: %s"),
1054 strerror(symlink_errno
));
1059 /* Return true if NAME is a directory. */
1061 itsdir(char const *name
)
1064 int res
= stat(name
, &st
);
1067 return S_ISDIR(st
.st_mode
) != 0;
1069 if (res
== 0 || errno
== EOVERFLOW
) {
1070 size_t n
= strlen(name
);
1071 char *nameslashdot
= emalloc(n
+ 3);
1073 memcpy(nameslashdot
, name
, n
);
1074 strcpy(&nameslashdot
[n
], &"/."[! (n
&& name
[n
- 1] != '/')]);
1075 dir
= stat(nameslashdot
, &st
) == 0 || errno
== EOVERFLOW
;
1082 /* Return true if NAME is a symbolic link. */
1084 itssymlink(char const *name
)
1087 return 0 <= readlink(name
, &c
, 1);
1091 ** Associate sets of rules with zones.
1095 ** Sort by rule name.
1099 rcomp(const void *cp1
, const void *cp2
)
1101 return strcmp(((const struct rule
*) cp1
)->r_name
,
1102 ((const struct rule
*) cp2
)->r_name
);
1108 register struct zone
* zp
;
1109 register struct rule
* rp
;
1110 register ptrdiff_t i
, j
, base
, out
;
1113 qsort(rules
, nrules
, sizeof *rules
, rcomp
);
1114 for (i
= 0; i
< nrules
- 1; ++i
) {
1115 if (strcmp(rules
[i
].r_name
,
1116 rules
[i
+ 1].r_name
) != 0)
1118 if (strcmp(rules
[i
].r_filename
,
1119 rules
[i
+ 1].r_filename
) == 0)
1121 eat(rules
[i
].r_filename
, rules
[i
].r_linenum
);
1122 warning(_("same rule name in multiple files"));
1123 eat(rules
[i
+ 1].r_filename
, rules
[i
+ 1].r_linenum
);
1124 warning(_("same rule name in multiple files"));
1125 for (j
= i
+ 2; j
< nrules
; ++j
) {
1126 if (strcmp(rules
[i
].r_name
,
1127 rules
[j
].r_name
) != 0)
1129 if (strcmp(rules
[i
].r_filename
,
1130 rules
[j
].r_filename
) == 0)
1132 if (strcmp(rules
[i
+ 1].r_filename
,
1133 rules
[j
].r_filename
) == 0)
1140 for (i
= 0; i
< nzones
; ++i
) {
1145 for (base
= 0; base
< nrules
; base
= out
) {
1147 for (out
= base
+ 1; out
< nrules
; ++out
)
1148 if (strcmp(rp
->r_name
, rules
[out
].r_name
) != 0)
1150 for (i
= 0; i
< nzones
; ++i
) {
1152 if (strcmp(zp
->z_rule
, rp
->r_name
) != 0)
1155 zp
->z_nrules
= out
- base
;
1158 for (i
= 0; i
< nzones
; ++i
) {
1160 if (zp
->z_nrules
== 0) {
1162 ** Maybe we have a local standard time offset.
1164 eat(zp
->z_filename
, zp
->z_linenum
);
1165 zp
->z_save
= getsave(zp
->z_rule
, &zp
->z_isdst
);
1167 ** Note, though, that if there's no rule,
1168 ** a '%s' in the format is a bad thing.
1170 if (zp
->z_format_specifier
== 's')
1171 error("%s", _("%s in ruleless zone"));
1179 infile(const char *name
)
1182 register char ** fields
;
1184 register const struct lookup
* lp
;
1185 register int nfields
;
1186 register bool wantcont
;
1187 register lineno num
;
1190 if (strcmp(name
, "-") == 0) {
1191 name
= _("standard input");
1193 } else if ((fp
= fopen(name
, "r")) == NULL
) {
1194 const char *e
= strerror(errno
);
1196 fprintf(stderr
, _("%s: Can't open %s: %s\n"),
1201 for (num
= 1; ; ++num
) {
1203 if (fgets(buf
, sizeof buf
, fp
) != buf
)
1205 cp
= strchr(buf
, '\n');
1207 error(_("line too long"));
1211 fields
= getfields(buf
);
1213 while (fields
[nfields
] != NULL
) {
1216 if (strcmp(fields
[nfields
], "-") == 0)
1217 fields
[nfields
] = &nada
;
1221 if (name
== leapsec
&& *buf
== '#')
1222 sscanf(buf
, "#expires %"SCNdZIC
, &comment_leapexpires
);
1223 } else if (wantcont
) {
1224 wantcont
= inzcont(fields
, nfields
);
1226 struct lookup
const *line_codes
1227 = name
== leapsec
? leap_line_codes
: zi_line_codes
;
1228 lp
= byword(fields
[0], line_codes
);
1230 error(_("input line of unknown type"));
1231 else switch (lp
->l_value
) {
1233 inrule(fields
, nfields
);
1237 wantcont
= inzone(fields
, nfields
);
1240 inlink(fields
, nfields
);
1244 inleap(fields
, nfields
);
1248 inexpires(fields
, nfields
);
1251 default: /* "cannot happen" */
1253 _("%s: panic: Invalid l_value %d\n"),
1254 progname
, lp
->l_value
);
1260 close_file(fp
, NULL
, filename
);
1262 error(_("expected continuation line not found"));
1266 ** Convert a string of one of the forms
1267 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1268 ** into a number of seconds.
1269 ** A null string maps to zero.
1270 ** Call error with errstring and return zero on errors.
1274 gethms(char const *string
, char const *errstring
)
1277 int sign
, mm
= 0, ss
= 0;
1278 char hhx
, mmx
, ssx
, xr
= '0', xs
;
1282 if (string
== NULL
|| *string
== '\0')
1284 if (*string
== '-') {
1288 switch (sscanf(string
,
1289 "%"SCNdZIC
"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
1290 &hh
, &hhx
, &mm
, &mmx
, &ss
, &ssx
, &tenths
, &xr
, &xs
)) {
1291 default: ok
= false; break;
1293 ok
= '0' <= xr
&& xr
<= '9';
1298 warning(_("fractional seconds rejected by"
1299 " pre-2018 versions of zic"));
1301 case 5: ok
&= mmx
== ':'; /* fallthrough */
1302 case 3: ok
&= hhx
== ':'; /* fallthrough */
1306 error("%s", errstring
);
1310 mm
< 0 || mm
>= MINSPERHOUR
||
1311 ss
< 0 || ss
> SECSPERMIN
) {
1312 error("%s", errstring
);
1315 if (ZIC_MAX
/ SECSPERHOUR
< hh
) {
1316 error(_("time overflow"));
1319 ss
+= 5 + ((ss
^ 1) & (xr
== '0')) <= tenths
; /* Round to even. */
1320 if (noise
&& (hh
> HOURSPERDAY
||
1321 (hh
== HOURSPERDAY
&& (mm
!= 0 || ss
!= 0))))
1322 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1323 return oadd(sign
* hh
* SECSPERHOUR
,
1324 sign
* (mm
* SECSPERMIN
+ ss
));
1328 getsave(char *field
, bool *isdst
)
1332 size_t fieldlen
= strlen(field
);
1333 if (fieldlen
!= 0) {
1334 char *ep
= field
+ fieldlen
- 1;
1336 case 'd': dst
= 1; *ep
= '\0'; break;
1337 case 's': dst
= 0; *ep
= '\0'; break;
1340 save
= gethms(field
, _("invalid saved time"));
1341 *isdst
= dst
< 0 ? save
!= 0 : dst
;
1346 inrule(char **fields
, int nfields
)
1348 static struct rule r
;
1350 if (nfields
!= RULE_FIELDS
) {
1351 error(_("wrong number of fields on Rule line"));
1354 switch (*fields
[RF_NAME
]) {
1356 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
1358 case '0': case '1': case '2': case '3': case '4':
1359 case '5': case '6': case '7': case '8': case '9':
1360 error(_("Invalid rule name \"%s\""), fields
[RF_NAME
]);
1363 r
.r_filename
= filename
;
1364 r
.r_linenum
= linenum
;
1365 r
.r_save
= getsave(fields
[RF_SAVE
], &r
.r_isdst
);
1366 rulesub(&r
, fields
[RF_LOYEAR
], fields
[RF_HIYEAR
], fields
[RF_COMMAND
],
1367 fields
[RF_MONTH
], fields
[RF_DAY
], fields
[RF_TOD
]);
1368 r
.r_name
= ecpyalloc(fields
[RF_NAME
]);
1369 r
.r_abbrvar
= ecpyalloc(fields
[RF_ABBRVAR
]);
1370 if (max_abbrvar_len
< strlen(r
.r_abbrvar
))
1371 max_abbrvar_len
= strlen(r
.r_abbrvar
);
1372 rules
= growalloc(rules
, sizeof *rules
, nrules
, &nrules_alloc
);
1373 rules
[nrules
++] = r
;
1377 inzone(char **fields
, int nfields
)
1379 register ptrdiff_t i
;
1381 if (nfields
< ZONE_MINFIELDS
|| nfields
> ZONE_MAXFIELDS
) {
1382 error(_("wrong number of fields on Zone line"));
1385 if (lcltime
!= NULL
&& strcmp(fields
[ZF_NAME
], tzdefault
) == 0) {
1387 _("\"Zone %s\" line and -l option are mutually exclusive"),
1391 if (strcmp(fields
[ZF_NAME
], TZDEFRULES
) == 0 && psxrules
!= NULL
) {
1393 _("\"Zone %s\" line and -p option are mutually exclusive"),
1397 for (i
= 0; i
< nzones
; ++i
)
1398 if (zones
[i
].z_name
!= NULL
&&
1399 strcmp(zones
[i
].z_name
, fields
[ZF_NAME
]) == 0) {
1400 error(_("duplicate zone name %s"
1401 " (file \"%s\", line %"PRIdMAX
")"),
1403 zones
[i
].z_filename
,
1404 zones
[i
].z_linenum
);
1407 return inzsub(fields
, nfields
, false);
1411 inzcont(char **fields
, int nfields
)
1413 if (nfields
< ZONEC_MINFIELDS
|| nfields
> ZONEC_MAXFIELDS
) {
1414 error(_("wrong number of fields on Zone continuation line"));
1417 return inzsub(fields
, nfields
, true);
1421 inzsub(char **fields
, int nfields
, bool iscont
)
1425 static struct zone z
;
1426 register int i_stdoff
, i_rule
, i_format
;
1427 register int i_untilyear
, i_untilmonth
;
1428 register int i_untilday
, i_untiltime
;
1429 register bool hasuntil
;
1432 i_stdoff
= ZFC_STDOFF
;
1434 i_format
= ZFC_FORMAT
;
1435 i_untilyear
= ZFC_TILYEAR
;
1436 i_untilmonth
= ZFC_TILMONTH
;
1437 i_untilday
= ZFC_TILDAY
;
1438 i_untiltime
= ZFC_TILTIME
;
1440 } else if (!namecheck(fields
[ZF_NAME
]))
1443 i_stdoff
= ZF_STDOFF
;
1445 i_format
= ZF_FORMAT
;
1446 i_untilyear
= ZF_TILYEAR
;
1447 i_untilmonth
= ZF_TILMONTH
;
1448 i_untilday
= ZF_TILDAY
;
1449 i_untiltime
= ZF_TILTIME
;
1450 z
.z_name
= ecpyalloc(fields
[ZF_NAME
]);
1452 z
.z_filename
= filename
;
1453 z
.z_linenum
= linenum
;
1454 z
.z_stdoff
= gethms(fields
[i_stdoff
], _("invalid UT offset"));
1455 if ((cp
= strchr(fields
[i_format
], '%')) != 0) {
1456 if ((*++cp
!= 's' && *cp
!= 'z') || strchr(cp
, '%')
1457 || strchr(fields
[i_format
], '/')) {
1458 error(_("invalid abbreviation format"));
1462 z
.z_rule
= ecpyalloc(fields
[i_rule
]);
1463 z
.z_format
= cp1
= ecpyalloc(fields
[i_format
]);
1464 z
.z_format_specifier
= cp
? *cp
: '\0';
1465 if (z
.z_format_specifier
== 'z') {
1467 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1469 cp1
[cp
- fields
[i_format
]] = 's';
1471 if (max_format_len
< strlen(z
.z_format
))
1472 max_format_len
= strlen(z
.z_format
);
1473 hasuntil
= nfields
> i_untilyear
;
1475 z
.z_untilrule
.r_filename
= filename
;
1476 z
.z_untilrule
.r_linenum
= linenum
;
1477 rulesub(&z
.z_untilrule
,
1478 fields
[i_untilyear
],
1481 (nfields
> i_untilmonth
) ?
1482 fields
[i_untilmonth
] : "Jan",
1483 (nfields
> i_untilday
) ? fields
[i_untilday
] : "1",
1484 (nfields
> i_untiltime
) ? fields
[i_untiltime
] : "0");
1485 z
.z_untiltime
= rpytime(&z
.z_untilrule
,
1486 z
.z_untilrule
.r_loyear
);
1487 if (iscont
&& nzones
> 0 &&
1488 z
.z_untiltime
> min_time
&&
1489 z
.z_untiltime
< max_time
&&
1490 zones
[nzones
- 1].z_untiltime
> min_time
&&
1491 zones
[nzones
- 1].z_untiltime
< max_time
&&
1492 zones
[nzones
- 1].z_untiltime
>= z
.z_untiltime
) {
1494 "Zone continuation line end time is not after end time of previous line"
1499 zones
= growalloc(zones
, sizeof *zones
, nzones
, &nzones_alloc
);
1500 zones
[nzones
++] = z
;
1502 ** If there was an UNTIL field on this line,
1503 ** there's more information about the zone on the next line.
1509 getleapdatetime(char **fields
, int nfields
, bool expire_line
)
1511 register const char * cp
;
1512 register const struct lookup
* lp
;
1513 register zic_t i
, j
;
1521 cp
= fields
[LP_YEAR
];
1522 if (sscanf(cp
, "%"SCNdZIC
"%c", &year
, &xs
) != 1) {
1526 error(_("invalid leaping year"));
1530 if (!leapseen
|| leapmaxyear
< year
)
1532 if (!leapseen
|| leapminyear
> year
)
1539 i
= len_years
[isleap(j
)];
1543 i
= -len_years
[isleap(j
)];
1545 dayoff
= oadd(dayoff
, i
);
1547 if ((lp
= byword(fields
[LP_MONTH
], mon_names
)) == NULL
) {
1548 error(_("invalid month name"));
1551 month
= lp
->l_value
;
1553 while (j
!= month
) {
1554 i
= len_months
[isleap(year
)][j
];
1555 dayoff
= oadd(dayoff
, i
);
1558 cp
= fields
[LP_DAY
];
1559 if (sscanf(cp
, "%d%c", &day
, &xs
) != 1 ||
1560 day
<= 0 || day
> len_months
[isleap(year
)][month
]) {
1561 error(_("invalid day of month"));
1564 dayoff
= oadd(dayoff
, day
- 1);
1565 if (dayoff
< min_time
/ SECSPERDAY
) {
1566 error(_("time too small"));
1569 if (dayoff
> max_time
/ SECSPERDAY
) {
1570 error(_("time too large"));
1573 t
= dayoff
* SECSPERDAY
;
1574 tod
= gethms(fields
[LP_TIME
], _("invalid time of day"));
1577 error(_("leap second precedes Epoch"));
1582 inleap(char **fields
, int nfields
)
1584 if (nfields
!= LEAP_FIELDS
)
1585 error(_("wrong number of fields on Leap line"));
1587 zic_t t
= getleapdatetime(fields
, nfields
, false);
1589 struct lookup
const *lp
= byword(fields
[LP_ROLL
], leap_types
);
1591 error(_("invalid Rolling/Stationary field on Leap line"));
1594 if (!fields
[LP_CORR
][0]) /* infile() turns "-" into "". */
1596 else if (strcmp(fields
[LP_CORR
], "+") == 0)
1599 error(_("invalid CORRECTION field on Leap line"));
1601 leapadd(t
, correction
, lp
->l_value
);
1608 inexpires(char **fields
, int nfields
)
1610 if (nfields
!= EXPIRES_FIELDS
)
1611 error(_("wrong number of fields on Expires line"));
1612 else if (0 <= leapexpires
)
1613 error(_("multiple Expires lines"));
1615 leapexpires
= getleapdatetime(fields
, nfields
, true);
1619 inlink(char **fields
, int nfields
)
1623 if (nfields
!= LINK_FIELDS
) {
1624 error(_("wrong number of fields on Link line"));
1627 if (*fields
[LF_FROM
] == '\0') {
1628 error(_("blank FROM field on Link line"));
1631 if (! namecheck(fields
[LF_TO
]))
1633 l
.l_filename
= filename
;
1634 l
.l_linenum
= linenum
;
1635 l
.l_from
= ecpyalloc(fields
[LF_FROM
]);
1636 l
.l_to
= ecpyalloc(fields
[LF_TO
]);
1637 links
= growalloc(links
, sizeof *links
, nlinks
, &nlinks_alloc
);
1638 links
[nlinks
++] = l
;
1642 rulesub(struct rule
*rp
, const char *loyearp
, const char *hiyearp
,
1643 const char *typep
, const char *monthp
, const char *dayp
,
1646 register const struct lookup
* lp
;
1647 register const char * cp
;
1652 if ((lp
= byword(monthp
, mon_names
)) == NULL
) {
1653 error(_("invalid month name"));
1656 rp
->r_month
= lp
->l_value
;
1657 rp
->r_todisstd
= false;
1658 rp
->r_todisut
= false;
1659 dp
= ecpyalloc(timep
);
1661 ep
= dp
+ strlen(dp
) - 1;
1662 switch (lowerit(*ep
)) {
1663 case 's': /* Standard */
1664 rp
->r_todisstd
= true;
1665 rp
->r_todisut
= false;
1668 case 'w': /* Wall */
1669 rp
->r_todisstd
= false;
1670 rp
->r_todisut
= false;
1673 case 'g': /* Greenwich */
1674 case 'u': /* Universal */
1675 case 'z': /* Zulu */
1676 rp
->r_todisstd
= true;
1677 rp
->r_todisut
= true;
1682 rp
->r_tod
= gethms(dp
, _("invalid time of day"));
1688 lp
= byword(cp
, begin_years
);
1689 rp
->r_lowasnum
= lp
== NULL
;
1690 if (!rp
->r_lowasnum
) switch (lp
->l_value
) {
1692 rp
->r_loyear
= ZIC_MIN
;
1695 rp
->r_loyear
= ZIC_MAX
;
1697 default: /* "cannot happen" */
1699 _("%s: panic: Invalid l_value %d\n"),
1700 progname
, lp
->l_value
);
1702 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_loyear
, &xs
) != 1) {
1703 error(_("invalid starting year"));
1707 lp
= byword(cp
, end_years
);
1708 rp
->r_hiwasnum
= lp
== NULL
;
1709 if (!rp
->r_hiwasnum
) switch (lp
->l_value
) {
1711 rp
->r_hiyear
= ZIC_MIN
;
1714 rp
->r_hiyear
= ZIC_MAX
;
1717 rp
->r_hiyear
= rp
->r_loyear
;
1719 default: /* "cannot happen" */
1721 _("%s: panic: Invalid l_value %d\n"),
1722 progname
, lp
->l_value
);
1724 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_hiyear
, &xs
) != 1) {
1725 error(_("invalid ending year"));
1728 if (rp
->r_loyear
> rp
->r_hiyear
) {
1729 error(_("starting year greater than ending year"));
1733 rp
->r_yrtype
= NULL
;
1735 if (rp
->r_loyear
== rp
->r_hiyear
) {
1736 error(_("typed single year"));
1739 warning(_("year type \"%s\" is obsolete; use \"-\" instead"),
1741 rp
->r_yrtype
= ecpyalloc(typep
);
1745 ** Accept things such as:
1748 ** last-Sunday (undocumented; warn about this)
1752 dp
= ecpyalloc(dayp
);
1753 if ((lp
= byword(dp
, lasts
)) != NULL
) {
1754 rp
->r_dycode
= DC_DOWLEQ
;
1755 rp
->r_wday
= lp
->l_value
;
1756 rp
->r_dayofmonth
= len_months
[1][rp
->r_month
];
1758 if ((ep
= strchr(dp
, '<')) != 0)
1759 rp
->r_dycode
= DC_DOWLEQ
;
1760 else if ((ep
= strchr(dp
, '>')) != 0)
1761 rp
->r_dycode
= DC_DOWGEQ
;
1764 rp
->r_dycode
= DC_DOM
;
1766 if (rp
->r_dycode
!= DC_DOM
) {
1769 error(_("invalid day of month"));
1773 if ((lp
= byword(dp
, wday_names
)) == NULL
) {
1774 error(_("invalid weekday name"));
1778 rp
->r_wday
= lp
->l_value
;
1780 if (sscanf(ep
, "%d%c", &rp
->r_dayofmonth
, &xs
) != 1 ||
1781 rp
->r_dayofmonth
<= 0 ||
1782 (rp
->r_dayofmonth
> len_months
[1][rp
->r_month
])) {
1783 error(_("invalid day of month"));
1792 convert(const int_fast32_t val
, char *const buf
)
1796 unsigned char *const b
= (unsigned char *) buf
;
1798 for (i
= 0, shift
= 24; i
< 4; ++i
, shift
-= 8)
1799 b
[i
] = val
>> shift
;
1803 convert64(const zic_t val
, char *const buf
)
1807 unsigned char *const b
= (unsigned char *) buf
;
1809 for (i
= 0, shift
= 56; i
< 8; ++i
, shift
-= 8)
1810 b
[i
] = val
>> shift
;
1814 puttzcode(const int_fast32_t val
, FILE *const fp
)
1819 fwrite(buf
, sizeof buf
, 1, fp
);
1823 puttzcodepass(zic_t val
, FILE *fp
, int pass
)
1830 convert64(val
, buf
);
1831 fwrite(buf
, sizeof buf
, 1, fp
);
1836 atcomp(const void *avp
, const void *bvp
)
1838 const zic_t a
= ((const struct attype
*) avp
)->at
;
1839 const zic_t b
= ((const struct attype
*) bvp
)->at
;
1841 return (a
< b
) ? -1 : (a
> b
);
1846 ptrdiff_t base
, count
;
1847 int leapbase
, leapcount
;
1850 static struct timerange
1851 limitrange(struct timerange r
, zic_t lo
, zic_t hi
,
1852 zic_t
const *ats
, unsigned char const *types
)
1854 while (0 < r
.count
&& ats
[r
.base
] < lo
) {
1855 r
.defaulttype
= types
[r
.base
];
1859 while (0 < r
.leapcount
&& trans
[r
.leapbase
] < lo
) {
1865 while (0 < r
.count
&& hi
+ 1 < ats
[r
.base
+ r
.count
- 1])
1867 while (0 < r
.leapcount
&& hi
+ 1 < trans
[r
.leapbase
+ r
.leapcount
- 1])
1875 writezone(const char *const name
, const char *const string
, char version
,
1879 register ptrdiff_t i
, j
;
1881 static const struct tzhead tzh0
;
1882 static struct tzhead tzh
;
1883 bool dir_checked
= false;
1885 zic_t y2038_boundary
= one
<< 31;
1886 ptrdiff_t nats
= timecnt
+ WORK_AROUND_QTBUG_53071
;
1888 /* Allocate the ATS and TYPES arrays via a single malloc,
1889 as this is a bit faster. */
1890 zic_t
*ats
= emalloc(align_to(size_product(nats
, sizeof *ats
+ 1),
1892 void *typesptr
= ats
+ nats
;
1893 unsigned char *types
= typesptr
;
1894 struct timerange rangeall
, range32
, range64
;
1900 qsort(attypes
, timecnt
, sizeof *attypes
, atcomp
);
1905 ptrdiff_t fromi
, toi
;
1909 for ( ; fromi
< timecnt
; ++fromi
) {
1911 && ((attypes
[fromi
].at
1912 + utoffs
[attypes
[toi
- 1].type
])
1913 <= (attypes
[toi
- 1].at
1914 + utoffs
[toi
== 1 ? 0
1915 : attypes
[toi
- 2].type
]))) {
1916 attypes
[toi
- 1].type
=
1917 attypes
[fromi
].type
;
1921 || attypes
[fromi
].dontmerge
1922 || (utoffs
[attypes
[toi
- 1].type
]
1923 != utoffs
[attypes
[fromi
].type
])
1924 || (isdsts
[attypes
[toi
- 1].type
]
1925 != isdsts
[attypes
[fromi
].type
])
1926 || (desigidx
[attypes
[toi
- 1].type
]
1927 != desigidx
[attypes
[fromi
].type
]))
1928 attypes
[toi
++] = attypes
[fromi
];
1933 if (noise
&& timecnt
> 1200) {
1934 if (timecnt
> TZ_MAX_TIMES
)
1935 warning(_("reference clients mishandle"
1936 " more than %d transition times"),
1939 warning(_("pre-2014 clients may mishandle"
1940 " more than 1200 transition times"));
1945 for (i
= 0; i
< timecnt
; ++i
) {
1946 ats
[i
] = attypes
[i
].at
;
1947 types
[i
] = attypes
[i
].type
;
1951 ** Correct for leap seconds.
1953 for (i
= 0; i
< timecnt
; ++i
) {
1956 if (ats
[i
] > trans
[j
] - corr
[j
]) {
1957 ats
[i
] = tadd(ats
[i
], corr
[j
]);
1962 /* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1,
1963 by inserting a no-op transition at time y2038_boundary - 1.
1964 This works only for timestamps before the boundary, which
1965 should be good enough in practice as QTBUG-53071 should be
1966 long-dead by 2038. Do this after correcting for leap
1967 seconds, as the idea is to insert a transition just before
1968 32-bit time_t rolls around, and this occurs at a slightly
1969 different moment if transitions are leap-second corrected. */
1970 if (WORK_AROUND_QTBUG_53071
&& timecnt
!= 0 && want_bloat()
1971 && ats
[timecnt
- 1] < y2038_boundary
- 1 && strchr(string
, '<')) {
1972 ats
[timecnt
] = y2038_boundary
- 1;
1973 types
[timecnt
] = types
[timecnt
- 1];
1977 rangeall
.defaulttype
= defaulttype
;
1978 rangeall
.base
= rangeall
.leapbase
= 0;
1979 rangeall
.count
= timecnt
;
1980 rangeall
.leapcount
= leapcnt
;
1981 range64
= limitrange(rangeall
, lo_time
, hi_time
, ats
, types
);
1982 range32
= limitrange(range64
, INT32_MIN
, INT32_MAX
, ats
, types
);
1985 ** Remove old file, if any, to snap links.
1987 if (remove(name
) == 0)
1989 else if (errno
!= ENOENT
) {
1990 const char *e
= strerror(errno
);
1992 fprintf(stderr
, _("%s: Can't remove %s/%s: %s\n"),
1993 progname
, directory
, name
, e
);
1996 fp
= fopen(name
, "wb");
1998 int fopen_errno
= errno
;
1999 if (fopen_errno
== ENOENT
&& !dir_checked
) {
2001 fp
= fopen(name
, "wb");
2002 fopen_errno
= errno
;
2005 fprintf(stderr
, _("%s: Can't create %s/%s: %s\n"),
2006 progname
, directory
, name
, strerror(fopen_errno
));
2010 for (pass
= 1; pass
<= 2; ++pass
) {
2011 register ptrdiff_t thistimei
, thistimecnt
, thistimelim
;
2012 register int thisleapi
, thisleapcnt
, thisleaplim
;
2013 int currenttype
, thisdefaulttype
;
2017 char omittype
[TZ_MAX_TYPES
];
2018 int typemap
[TZ_MAX_TYPES
];
2019 int thistypecnt
, stdcnt
, utcnt
;
2020 char thischars
[TZ_MAX_CHARS
];
2023 int indmap
[TZ_MAX_CHARS
];
2026 /* Arguably the default time type in the 32-bit data
2027 should be range32.defaulttype, which is suited for
2028 timestamps just before INT32_MIN. However, zic
2029 traditionally used the time type of the indefinite
2030 past instead. Internet RFC 8532 says readers should
2031 ignore 32-bit data, so this discrepancy matters only
2032 to obsolete readers where the traditional type might
2033 be more appropriate even if it's "wrong". So, use
2034 the historical zic value, unless -r specifies a low
2035 cutoff that excludes some 32-bit timestamps. */
2036 thisdefaulttype
= (lo_time
<= INT32_MIN
2037 ? range64
.defaulttype
2038 : range32
.defaulttype
);
2040 thistimei
= range32
.base
;
2041 thistimecnt
= range32
.count
;
2042 toomanytimes
= thistimecnt
>> 31 >> 1 != 0;
2043 thisleapi
= range32
.leapbase
;
2044 thisleapcnt
= range32
.leapcount
;
2045 locut
= INT32_MIN
< lo_time
;
2046 hicut
= hi_time
< INT32_MAX
;
2048 thisdefaulttype
= range64
.defaulttype
;
2049 thistimei
= range64
.base
;
2050 thistimecnt
= range64
.count
;
2051 toomanytimes
= thistimecnt
>> 31 >> 31 >> 2 != 0;
2052 thisleapi
= range64
.leapbase
;
2053 thisleapcnt
= range64
.leapcount
;
2054 locut
= min_time
< lo_time
;
2055 hicut
= hi_time
< max_time
;
2058 error(_("too many transition times"));
2060 /* Keep the last too-low transition if no transition is
2061 exactly at LO. The kept transition will be output as
2062 a LO "transition"; see "Output a LO_TIME transition"
2063 below. This is needed when the output is truncated at
2064 the start, and is also useful when catering to buggy
2065 32-bit clients that do not use time type 0 for
2066 timestamps before the first transition. */
2067 if (0 < thistimei
&& ats
[thistimei
] != lo_time
) {
2073 thistimelim
= thistimei
+ thistimecnt
;
2074 thisleaplim
= thisleapi
+ thisleapcnt
;
2075 if (thistimecnt
!= 0) {
2076 if (ats
[thistimei
] == lo_time
)
2078 if (hi_time
< ZIC_MAX
&& ats
[thistimelim
- 1] == hi_time
+ 1)
2081 memset(omittype
, true, typecnt
);
2082 omittype
[thisdefaulttype
] = false;
2083 for (i
= thistimei
; i
< thistimelim
; i
++)
2084 omittype
[types
[i
]] = false;
2086 /* Reorder types to make THISDEFAULTTYPE type 0.
2087 Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that
2088 THISDEFAULTTYPE appears as type 0 in the output instead
2089 of OLD0. TYPEMAP also omits unused types. */
2090 old0
= strlen(omittype
);
2092 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
2094 ** For some pre-2011 systems: if the last-to-be-written
2095 ** standard (or daylight) type has an offset different from the
2096 ** most recently used offset,
2097 ** append an (unused) copy of the most recently used type
2098 ** (to help get global "altzone" and "timezone" variables
2102 register int mrudst
, mrustd
, hidst
, histd
, type
;
2104 hidst
= histd
= mrudst
= mrustd
= -1;
2105 for (i
= thistimei
; i
< thistimelim
; ++i
)
2106 if (isdsts
[types
[i
]])
2108 else mrustd
= types
[i
];
2109 for (i
= old0
; i
< typecnt
; i
++) {
2110 int h
= (i
== old0
? thisdefaulttype
2111 : i
== thisdefaulttype
? old0
: i
);
2119 if (hidst
>= 0 && mrudst
>= 0 && hidst
!= mrudst
&&
2120 utoffs
[hidst
] != utoffs
[mrudst
]) {
2121 isdsts
[mrudst
] = -1;
2122 type
= addtype(utoffs
[mrudst
],
2123 &chars
[desigidx
[mrudst
]],
2128 omittype
[type
] = false;
2130 if (histd
>= 0 && mrustd
>= 0 && histd
!= mrustd
&&
2131 utoffs
[histd
] != utoffs
[mrustd
]) {
2132 isdsts
[mrustd
] = -1;
2133 type
= addtype(utoffs
[mrustd
],
2134 &chars
[desigidx
[mrustd
]],
2139 omittype
[type
] = false;
2142 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
2144 for (i
= old0
; i
< typecnt
; i
++)
2146 typemap
[i
== old0
? thisdefaulttype
2147 : i
== thisdefaulttype
? old0
: i
]
2150 for (i
= 0; i
< sizeof indmap
/ sizeof indmap
[0]; ++i
)
2152 thischarcnt
= stdcnt
= utcnt
= 0;
2153 for (i
= old0
; i
< typecnt
; i
++) {
2154 register char * thisabbr
;
2159 stdcnt
= thistypecnt
;
2161 utcnt
= thistypecnt
;
2162 if (indmap
[desigidx
[i
]] >= 0)
2164 thisabbr
= &chars
[desigidx
[i
]];
2165 for (j
= 0; j
< thischarcnt
; ++j
)
2166 if (strcmp(&thischars
[j
], thisabbr
) == 0)
2168 if (j
== thischarcnt
) {
2169 strcpy(&thischars
[thischarcnt
], thisabbr
);
2170 thischarcnt
+= strlen(thisabbr
) + 1;
2172 indmap
[desigidx
[i
]] = j
;
2174 if (pass
== 1 && !want_bloat()) {
2175 utcnt
= stdcnt
= thisleapcnt
= 0;
2176 thistimecnt
= - (locut
+ hicut
);
2177 thistypecnt
= thischarcnt
= 1;
2178 thistimelim
= thistimei
;
2180 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
2182 memcpy(tzh
.tzh_magic
, TZ_MAGIC
, sizeof tzh
.tzh_magic
);
2183 tzh
.tzh_version
[0] = version
;
2184 convert(utcnt
, tzh
.tzh_ttisutcnt
);
2185 convert(stdcnt
, tzh
.tzh_ttisstdcnt
);
2186 convert(thisleapcnt
, tzh
.tzh_leapcnt
);
2187 convert(locut
+ thistimecnt
+ hicut
, tzh
.tzh_timecnt
);
2188 convert(thistypecnt
, tzh
.tzh_typecnt
);
2189 convert(thischarcnt
, tzh
.tzh_charcnt
);
2200 if (pass
== 1 && !want_bloat()) {
2201 /* Output a minimal data block with just one time type. */
2202 puttzcode(0, fp
); /* utoff */
2203 putc(0, fp
); /* dst */
2204 putc(0, fp
); /* index of abbreviation */
2205 putc(0, fp
); /* empty-string abbreviation */
2209 /* Output a LO_TIME transition if needed; see limitrange.
2210 But do not go below the minimum representable value
2212 lo
= pass
== 1 && lo_time
< INT32_MIN
? INT32_MIN
: lo_time
;
2215 puttzcodepass(lo
, fp
, pass
);
2216 for (i
= thistimei
; i
< thistimelim
; ++i
) {
2217 zic_t at
= ats
[i
] < lo
? lo
: ats
[i
];
2218 puttzcodepass(at
, fp
, pass
);
2221 puttzcodepass(hi_time
+ 1, fp
, pass
);
2224 putc(currenttype
, fp
);
2225 for (i
= thistimei
; i
< thistimelim
; ++i
) {
2226 currenttype
= typemap
[types
[i
]];
2227 putc(currenttype
, fp
);
2230 putc(currenttype
, fp
);
2232 for (i
= old0
; i
< typecnt
; i
++) {
2233 int h
= (i
== old0
? thisdefaulttype
2234 : i
== thisdefaulttype
? old0
: i
);
2236 puttzcode(utoffs
[h
], fp
);
2237 putc(isdsts
[h
], fp
);
2238 putc(indmap
[desigidx
[h
]], fp
);
2241 if (thischarcnt
!= 0)
2242 fwrite(thischars
, sizeof thischars
[0],
2244 for (i
= thisleapi
; i
< thisleaplim
; ++i
) {
2245 register zic_t todo
;
2248 if (timecnt
== 0 || trans
[i
] < ats
[0]) {
2251 if (++j
>= typecnt
) {
2257 while (j
< timecnt
&&
2262 todo
= tadd(trans
[i
], -utoffs
[j
]);
2263 } else todo
= trans
[i
];
2264 puttzcodepass(todo
, fp
, pass
);
2265 puttzcode(corr
[i
], fp
);
2268 for (i
= old0
; i
< typecnt
; i
++)
2270 putc(ttisstds
[i
], fp
);
2272 for (i
= old0
; i
< typecnt
; i
++)
2274 putc(ttisuts
[i
], fp
);
2276 fprintf(fp
, "\n%s\n", string
);
2277 close_file(fp
, directory
, name
);
2282 abbroffset(char *buf
, zic_t offset
)
2285 int seconds
, minutes
;
2292 seconds
= offset
% SECSPERMIN
;
2293 offset
/= SECSPERMIN
;
2294 minutes
= offset
% MINSPERHOUR
;
2295 offset
/= MINSPERHOUR
;
2296 if (100 <= offset
) {
2297 error(_("%%z UT offset magnitude exceeds 99:59:59"));
2302 *p
++ = '0' + offset
/ 10;
2303 *p
++ = '0' + offset
% 10;
2304 if (minutes
| seconds
) {
2305 *p
++ = '0' + minutes
/ 10;
2306 *p
++ = '0' + minutes
% 10;
2308 *p
++ = '0' + seconds
/ 10;
2309 *p
++ = '0' + seconds
% 10;
2318 doabbr(char *abbr
, struct zone
const *zp
, char const *letters
,
2319 bool isdst
, zic_t save
, bool doquotes
)
2322 register char * slashp
;
2323 register size_t len
;
2324 char const *format
= zp
->z_format
;
2326 slashp
= strchr(format
, '/');
2327 if (slashp
== NULL
) {
2328 char letterbuf
[PERCENT_Z_LEN_BOUND
+ 1];
2329 if (zp
->z_format_specifier
== 'z')
2330 letters
= abbroffset(letterbuf
, zp
->z_stdoff
+ save
);
2333 sprintf(abbr
, format
, letters
);
2335 strcpy(abbr
, slashp
+ 1);
2337 memcpy(abbr
, format
, slashp
- format
);
2338 abbr
[slashp
- format
] = '\0';
2343 for (cp
= abbr
; is_alpha(*cp
); cp
++)
2345 if (len
> 0 && *cp
== '\0')
2347 abbr
[len
+ 2] = '\0';
2348 abbr
[len
+ 1] = '>';
2349 memmove(abbr
+ 1, abbr
, len
);
2355 updateminmax(const zic_t x
)
2364 stringoffset(char *result
, zic_t offset
)
2367 register int minutes
;
2368 register int seconds
;
2369 bool negative
= offset
< 0;
2376 seconds
= offset
% SECSPERMIN
;
2377 offset
/= SECSPERMIN
;
2378 minutes
= offset
% MINSPERHOUR
;
2379 offset
/= MINSPERHOUR
;
2381 if (hours
>= HOURSPERDAY
* DAYSPERWEEK
) {
2385 len
+= sprintf(result
+ len
, "%d", hours
);
2386 if (minutes
!= 0 || seconds
!= 0) {
2387 len
+= sprintf(result
+ len
, ":%02d", minutes
);
2389 len
+= sprintf(result
+ len
, ":%02d", seconds
);
2395 stringrule(char *result
, struct rule
*const rp
, zic_t save
, zic_t stdoff
)
2397 register zic_t tod
= rp
->r_tod
;
2398 register int compat
= 0;
2400 if (rp
->r_dycode
== DC_DOM
) {
2401 register int month
, total
;
2403 if (rp
->r_dayofmonth
== 29 && rp
->r_month
== TM_FEBRUARY
)
2406 for (month
= 0; month
< rp
->r_month
; ++month
)
2407 total
+= len_months
[0][month
];
2408 /* Omit the "J" in Jan and Feb, as that's shorter. */
2409 if (rp
->r_month
<= 1)
2410 result
+= sprintf(result
, "%d", total
+ rp
->r_dayofmonth
- 1);
2412 result
+= sprintf(result
, "J%d", total
+ rp
->r_dayofmonth
);
2415 register int wday
= rp
->r_wday
;
2416 register int wdayoff
;
2418 if (rp
->r_dycode
== DC_DOWGEQ
) {
2419 wdayoff
= (rp
->r_dayofmonth
- 1) % DAYSPERWEEK
;
2423 tod
+= wdayoff
* SECSPERDAY
;
2424 week
= 1 + (rp
->r_dayofmonth
- 1) / DAYSPERWEEK
;
2425 } else if (rp
->r_dycode
== DC_DOWLEQ
) {
2426 if (rp
->r_dayofmonth
== len_months
[1][rp
->r_month
])
2429 wdayoff
= rp
->r_dayofmonth
% DAYSPERWEEK
;
2433 tod
+= wdayoff
* SECSPERDAY
;
2434 week
= rp
->r_dayofmonth
/ DAYSPERWEEK
;
2436 } else return -1; /* "cannot happen" */
2438 wday
+= DAYSPERWEEK
;
2439 result
+= sprintf(result
, "M%d.%d.%d",
2440 rp
->r_month
+ 1, week
, wday
);
2444 if (rp
->r_todisstd
&& !rp
->r_isdst
)
2446 if (tod
!= 2 * SECSPERMIN
* MINSPERHOUR
) {
2448 if (! stringoffset(result
, tod
))
2453 } else if (SECSPERDAY
<= tod
) {
2462 rule_cmp(struct rule
const *a
, struct rule
const *b
)
2468 if (a
->r_hiyear
!= b
->r_hiyear
)
2469 return a
->r_hiyear
< b
->r_hiyear
? -1 : 1;
2470 if (a
->r_month
- b
->r_month
!= 0)
2471 return a
->r_month
- b
->r_month
;
2472 return a
->r_dayofmonth
- b
->r_dayofmonth
;
2476 stringzone(char *result
, struct zone
const *zpfirst
, ptrdiff_t zonecount
)
2478 register const struct zone
* zp
;
2479 register struct rule
* rp
;
2480 register struct rule
* stdrp
;
2481 register struct rule
* dstrp
;
2482 register ptrdiff_t i
;
2483 register const char * abbrvar
;
2484 register int compat
= 0;
2488 struct rule stdr
, dstr
;
2492 /* Internet RFC 8536 section 5.1 says to use an empty TZ string if
2493 future timestamps are truncated. */
2494 if (hi_time
< max_time
)
2497 zp
= zpfirst
+ zonecount
- 1;
2498 stdrp
= dstrp
= NULL
;
2499 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2500 rp
= &zp
->z_rules
[i
];
2501 if (rp
->r_hiwasnum
|| rp
->r_hiyear
!= ZIC_MAX
)
2503 if (rp
->r_yrtype
!= NULL
)
2515 if (stdrp
== NULL
&& dstrp
== NULL
) {
2517 ** There are no rules running through "max".
2518 ** Find the latest std rule in stdabbrrp
2519 ** and latest rule of any type in stdrp.
2521 register struct rule
*stdabbrrp
= NULL
;
2522 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2523 rp
= &zp
->z_rules
[i
];
2524 if (!rp
->r_isdst
&& rule_cmp(stdabbrrp
, rp
) < 0)
2526 if (rule_cmp(stdrp
, rp
) < 0)
2529 if (stdrp
!= NULL
&& stdrp
->r_isdst
) {
2530 /* Perpetual DST. */
2531 dstr
.r_month
= TM_JANUARY
;
2532 dstr
.r_dycode
= DC_DOM
;
2533 dstr
.r_dayofmonth
= 1;
2535 dstr
.r_todisstd
= dstr
.r_todisut
= false;
2536 dstr
.r_isdst
= stdrp
->r_isdst
;
2537 dstr
.r_save
= stdrp
->r_save
;
2538 dstr
.r_abbrvar
= stdrp
->r_abbrvar
;
2539 stdr
.r_month
= TM_DECEMBER
;
2540 stdr
.r_dycode
= DC_DOM
;
2541 stdr
.r_dayofmonth
= 31;
2542 stdr
.r_tod
= SECSPERDAY
+ stdrp
->r_save
;
2543 stdr
.r_todisstd
= stdr
.r_todisut
= false;
2544 stdr
.r_isdst
= false;
2547 = (stdabbrrp
? stdabbrrp
->r_abbrvar
: "");
2552 if (stdrp
== NULL
&& (zp
->z_nrules
!= 0 || zp
->z_isdst
))
2554 abbrvar
= (stdrp
== NULL
) ? "" : stdrp
->r_abbrvar
;
2555 len
= doabbr(result
, zp
, abbrvar
, false, 0, true);
2556 offsetlen
= stringoffset(result
+ len
, - zp
->z_stdoff
);
2564 len
+= doabbr(result
+ len
, zp
, dstrp
->r_abbrvar
,
2565 dstrp
->r_isdst
, dstrp
->r_save
, true);
2566 if (dstrp
->r_save
!= SECSPERMIN
* MINSPERHOUR
) {
2567 offsetlen
= stringoffset(result
+ len
,
2568 - (zp
->z_stdoff
+ dstrp
->r_save
));
2575 result
[len
++] = ',';
2576 c
= stringrule(result
+ len
, dstrp
, dstrp
->r_save
, zp
->z_stdoff
);
2583 len
+= strlen(result
+ len
);
2584 result
[len
++] = ',';
2585 c
= stringrule(result
+ len
, stdrp
, dstrp
->r_save
, zp
->z_stdoff
);
2596 outzone(const struct zone
*zpfirst
, ptrdiff_t zonecount
)
2598 register const struct zone
* zp
;
2599 register struct rule
* rp
;
2600 register ptrdiff_t i
, j
;
2601 register bool usestart
, useuntil
;
2602 register zic_t starttime
, untiltime
;
2603 register zic_t stdoff
;
2604 register zic_t save
;
2605 register zic_t year
;
2606 register zic_t startoff
;
2607 register bool startttisstd
;
2608 register bool startttisut
;
2610 register char * startbuf
;
2612 register char * envvar
;
2613 register int max_abbr_len
;
2614 register int max_envvar_len
;
2615 register bool prodstic
; /* all rules are min to max */
2616 register int compat
;
2617 register bool do_extend
;
2618 register char version
;
2619 ptrdiff_t lastatmax
= -1;
2621 zic_t y2038_boundary
= one
<< 31;
2623 int defaulttype
= -1;
2625 max_abbr_len
= 2 + max_format_len
+ max_abbrvar_len
;
2626 max_envvar_len
= 2 * max_abbr_len
+ 5 * 9;
2627 startbuf
= emalloc(max_abbr_len
+ 1);
2628 ab
= emalloc(max_abbr_len
+ 1);
2629 envvar
= emalloc(max_envvar_len
+ 1);
2630 INITIALIZE(untiltime
);
2631 INITIALIZE(starttime
);
2633 ** Now. . .finally. . .generate some useful data!
2638 prodstic
= zonecount
== 1;
2640 ** Thanks to Earl Chew
2641 ** for noting the need to unconditionally initialize startttisstd.
2643 startttisstd
= false;
2644 startttisut
= false;
2645 min_year
= max_year
= EPOCH_YEAR
;
2647 updateminmax(leapminyear
);
2648 updateminmax(leapmaxyear
+ (leapmaxyear
< ZIC_MAX
));
2650 for (i
= 0; i
< zonecount
; ++i
) {
2652 if (i
< zonecount
- 1)
2653 updateminmax(zp
->z_untilrule
.r_loyear
);
2654 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2655 rp
= &zp
->z_rules
[j
];
2657 updateminmax(rp
->r_loyear
);
2659 updateminmax(rp
->r_hiyear
);
2660 if (rp
->r_lowasnum
|| rp
->r_hiwasnum
)
2665 ** Generate lots of data if a rule can't cover all future times.
2667 compat
= stringzone(envvar
, zpfirst
, zonecount
);
2668 version
= compat
< 2013 ? ZIC_VERSION_PRE_2013
: ZIC_VERSION
;
2669 do_extend
= compat
< 0;
2673 _("no POSIX environment variable for zone"),
2675 else if (compat
!= 0) {
2676 /* Circa-COMPAT clients, and earlier clients, might
2677 not work for this zone when given dates before
2678 1970 or after 2038. */
2679 warning(_("%s: pre-%d clients may mishandle"
2680 " distant timestamps"),
2681 zpfirst
->z_name
, compat
);
2686 ** Search through a couple of extra years past the obvious
2687 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2688 ** rule applies from 2012 onwards and has transitions in March
2689 ** and September, plus some one-off transitions in November
2690 ** 2013. If zic looked only at the last 400 years, it would
2691 ** set max_year=2413, with the intent that the 400 years 2014
2692 ** through 2413 will be repeated. The last transition listed
2693 ** in the tzfile would be in 2413-09, less than 400 years
2694 ** after the last one-off transition in 2013-11. Two years
2695 ** might be overkill, but with the kind of edge cases
2696 ** available we're not sure that one year would suffice.
2698 enum { years_of_observations
= YEARSPERREPEAT
+ 2 };
2700 if (min_year
>= ZIC_MIN
+ years_of_observations
)
2701 min_year
-= years_of_observations
;
2702 else min_year
= ZIC_MIN
;
2703 if (max_year
<= ZIC_MAX
- years_of_observations
)
2704 max_year
+= years_of_observations
;
2705 else max_year
= ZIC_MAX
;
2707 ** Regardless of any of the above,
2708 ** for a "proDSTic" zone which specifies that its rules
2709 ** always have and always will be in effect,
2710 ** we only need one cycle to define the zone.
2714 max_year
= min_year
+ years_of_observations
;
2717 max_year0
= max_year
;
2719 /* For the benefit of older systems,
2720 generate data from 1900 through 2038. */
2721 if (min_year
> 1900)
2723 if (max_year
< 2038)
2727 for (i
= 0; i
< zonecount
; ++i
) {
2728 struct rule
*prevrp
= NULL
;
2730 ** A guess that may well be corrected later.
2734 usestart
= i
> 0 && (zp
- 1)->z_untiltime
> min_time
;
2735 useuntil
= i
< (zonecount
- 1);
2736 if (useuntil
&& zp
->z_untiltime
<= min_time
)
2738 stdoff
= zp
->z_stdoff
;
2739 eat(zp
->z_filename
, zp
->z_linenum
);
2741 startoff
= zp
->z_stdoff
;
2742 if (zp
->z_nrules
== 0) {
2744 doabbr(startbuf
, zp
, NULL
, zp
->z_isdst
, save
, false);
2745 type
= addtype(oadd(zp
->z_stdoff
, save
),
2746 startbuf
, zp
->z_isdst
, startttisstd
,
2749 addtt(starttime
, type
);
2753 } else for (year
= min_year
; year
<= max_year
; ++year
) {
2754 if (useuntil
&& year
> zp
->z_untilrule
.r_hiyear
)
2757 ** Mark which rules to do in the current year.
2758 ** For those to do, calculate rpytime(rp, year);
2760 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2761 rp
= &zp
->z_rules
[j
];
2762 eats(zp
->z_filename
, zp
->z_linenum
,
2763 rp
->r_filename
, rp
->r_linenum
);
2764 rp
->r_todo
= year
>= rp
->r_loyear
&&
2765 year
<= rp
->r_hiyear
&&
2766 yearistype(year
, rp
->r_yrtype
);
2768 rp
->r_temp
= rpytime(rp
, year
);
2770 = (rp
->r_temp
< y2038_boundary
2771 || year
<= max_year0
);
2775 register ptrdiff_t k
;
2776 register zic_t jtime
, ktime
;
2777 register zic_t offset
;
2782 ** Turn untiltime into UT
2783 ** assuming the current stdoff and
2786 untiltime
= zp
->z_untiltime
;
2787 if (!zp
->z_untilrule
.r_todisut
)
2788 untiltime
= tadd(untiltime
,
2790 if (!zp
->z_untilrule
.r_todisstd
)
2791 untiltime
= tadd(untiltime
,
2795 ** Find the rule (of those to do, if any)
2796 ** that takes effect earliest in the year.
2799 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2800 rp
= &zp
->z_rules
[j
];
2803 eats(zp
->z_filename
, zp
->z_linenum
,
2804 rp
->r_filename
, rp
->r_linenum
);
2805 offset
= rp
->r_todisut
? 0 : stdoff
;
2806 if (!rp
->r_todisstd
)
2807 offset
= oadd(offset
, save
);
2809 if (jtime
== min_time
||
2812 jtime
= tadd(jtime
, -offset
);
2813 if (k
< 0 || jtime
< ktime
) {
2816 } else if (jtime
== ktime
) {
2817 char const *dup_rules_msg
=
2818 _("two rules for same instant");
2819 eats(zp
->z_filename
, zp
->z_linenum
,
2820 rp
->r_filename
, rp
->r_linenum
);
2821 warning("%s", dup_rules_msg
);
2822 rp
= &zp
->z_rules
[k
];
2823 eats(zp
->z_filename
, zp
->z_linenum
,
2824 rp
->r_filename
, rp
->r_linenum
);
2825 error("%s", dup_rules_msg
);
2829 break; /* go on to next year */
2830 rp
= &zp
->z_rules
[k
];
2832 if (useuntil
&& ktime
>= untiltime
)
2835 if (usestart
&& ktime
== starttime
)
2838 if (ktime
< starttime
) {
2839 startoff
= oadd(zp
->z_stdoff
,
2841 doabbr(startbuf
, zp
,
2848 if (*startbuf
== '\0'
2849 && startoff
== oadd(zp
->z_stdoff
,
2859 eats(zp
->z_filename
, zp
->z_linenum
,
2860 rp
->r_filename
, rp
->r_linenum
);
2861 doabbr(ab
, zp
, rp
->r_abbrvar
,
2862 rp
->r_isdst
, rp
->r_save
, false);
2863 offset
= oadd(zp
->z_stdoff
, rp
->r_save
);
2864 if (!want_bloat() && !useuntil
&& !do_extend
2866 && rp
->r_hiyear
== ZIC_MAX
2867 && prevrp
->r_hiyear
== ZIC_MAX
)
2869 type
= addtype(offset
, ab
, rp
->r_isdst
,
2870 rp
->r_todisstd
, rp
->r_todisut
);
2871 if (defaulttype
< 0 && !rp
->r_isdst
)
2873 if (rp
->r_hiyear
== ZIC_MAX
2874 && ! (0 <= lastatmax
2875 && ktime
< attypes
[lastatmax
].at
))
2876 lastatmax
= timecnt
;
2882 if (*startbuf
== '\0' &&
2883 zp
->z_format
!= NULL
&&
2884 strchr(zp
->z_format
, '%') == NULL
&&
2885 strchr(zp
->z_format
, '/') == NULL
)
2886 strcpy(startbuf
, zp
->z_format
);
2887 eat(zp
->z_filename
, zp
->z_linenum
);
2888 if (*startbuf
== '\0')
2889 error(_("can't determine time zone abbreviation to use just after until time"));
2891 bool isdst
= startoff
!= zp
->z_stdoff
;
2892 type
= addtype(startoff
, startbuf
, isdst
,
2893 startttisstd
, startttisut
);
2894 if (defaulttype
< 0 && !isdst
)
2896 addtt(starttime
, type
);
2900 ** Now we may get to set starttime for the next zone line.
2903 startttisstd
= zp
->z_untilrule
.r_todisstd
;
2904 startttisut
= zp
->z_untilrule
.r_todisut
;
2905 starttime
= zp
->z_untiltime
;
2907 starttime
= tadd(starttime
, -save
);
2909 starttime
= tadd(starttime
, -stdoff
);
2912 if (defaulttype
< 0)
2915 attypes
[lastatmax
].dontmerge
= true;
2918 ** If we're extending the explicitly listed observations
2919 ** for 400 years because we can't fill the POSIX-TZ field,
2920 ** check whether we actually ended up explicitly listing
2921 ** observations through that period. If there aren't any
2922 ** near the end of the 400-year period, add a redundant
2923 ** one at the end of the final year, to make it clear
2924 ** that we are claiming to have definite knowledge of
2925 ** the lack of transitions up to that point.
2928 struct attype
*lastat
;
2929 xr
.r_month
= TM_JANUARY
;
2930 xr
.r_dycode
= DC_DOM
;
2931 xr
.r_dayofmonth
= 1;
2933 for (lastat
= attypes
, i
= 1; i
< timecnt
; i
++)
2934 if (attypes
[i
].at
> lastat
->at
)
2935 lastat
= &attypes
[i
];
2936 if (!lastat
|| lastat
->at
< rpytime(&xr
, max_year
- 1)) {
2937 addtt(rpytime(&xr
, max_year
+ 1),
2938 lastat
? lastat
->type
: defaulttype
);
2939 attypes
[timecnt
- 1].dontmerge
= true;
2942 writezone(zpfirst
->z_name
, envvar
, version
, defaulttype
);
2949 addtt(zic_t starttime
, int type
)
2951 attypes
= growalloc(attypes
, sizeof *attypes
, timecnt
, &timecnt_alloc
);
2952 attypes
[timecnt
].at
= starttime
;
2953 attypes
[timecnt
].dontmerge
= false;
2954 attypes
[timecnt
].type
= type
;
2959 addtype(zic_t utoff
, char const *abbr
, bool isdst
, bool ttisstd
, bool ttisut
)
2963 if (! (-1L - 2147483647L <= utoff
&& utoff
<= 2147483647L)) {
2964 error(_("UT offset out of range"));
2968 ttisstd
= ttisut
= false;
2970 for (j
= 0; j
< charcnt
; ++j
)
2971 if (strcmp(&chars
[j
], abbr
) == 0)
2976 /* If there's already an entry, return its index. */
2977 for (i
= 0; i
< typecnt
; i
++)
2978 if (utoff
== utoffs
[i
] && isdst
== isdsts
[i
] && j
== desigidx
[i
]
2979 && ttisstd
== ttisstds
[i
] && ttisut
== ttisuts
[i
])
2983 ** There isn't one; add a new one, unless there are already too
2986 if (typecnt
>= TZ_MAX_TYPES
) {
2987 error(_("too many local time types"));
2993 ttisstds
[i
] = ttisstd
;
2994 ttisuts
[i
] = ttisut
;
3000 leapadd(zic_t t
, int correction
, int rolling
)
3004 if (TZ_MAX_LEAPS
<= leapcnt
) {
3005 error(_("too many leap seconds"));
3008 for (i
= 0; i
< leapcnt
; ++i
)
3011 memmove(&trans
[i
+ 1], &trans
[i
], (leapcnt
- i
) * sizeof *trans
);
3012 memmove(&corr
[i
+ 1], &corr
[i
], (leapcnt
- i
) * sizeof *corr
);
3013 memmove(&roll
[i
+ 1], &roll
[i
], (leapcnt
- i
) * sizeof *roll
);
3015 corr
[i
] = correction
;
3024 register zic_t last
= 0;
3025 register zic_t prevtrans
= 0;
3028 ** propagate leap seconds forward
3030 for (i
= 0; i
< leapcnt
; ++i
) {
3031 if (trans
[i
] - prevtrans
< 28 * SECSPERDAY
) {
3032 error(_("Leap seconds too close together"));
3035 prevtrans
= trans
[i
];
3036 trans
[i
] = tadd(trans
[i
], last
);
3037 last
= corr
[i
] += last
;
3040 if (leapexpires
< 0) {
3041 leapexpires
= comment_leapexpires
;
3042 if (0 <= leapexpires
)
3043 warning(_("\"#expires\" is obsolescent; use \"Expires\""));
3046 if (0 <= leapexpires
) {
3047 leapexpires
= oadd(leapexpires
, last
);
3048 if (! (leapcnt
== 0 || (trans
[leapcnt
- 1] < leapexpires
))) {
3049 error(_("last Leap time does not precede Expires time"));
3052 if (leapexpires
<= hi_time
)
3053 hi_time
= leapexpires
- 1;
3058 shellquote(char *b
, char const *s
)
3063 *b
++ = '\'', *b
++ = '\\', *b
++ = '\'';
3071 yearistype(zic_t year
, const char *type
)
3077 if (type
== NULL
|| *type
== '\0')
3079 buf
= emalloc(1 + 4 * strlen(yitcommand
) + 2
3080 + INT_STRLEN_MAXIMUM(zic_t
) + 2 + 4 * strlen(type
) + 2);
3081 b
= shellquote(buf
, yitcommand
);
3083 b
+= sprintf(b
, "%"PRIdZIC
, year
);
3085 b
= shellquote(b
, type
);
3087 result
= system(buf
);
3088 if (WIFEXITED(result
)) {
3089 int status
= WEXITSTATUS(result
);
3095 error(_("Wild result from command execution"));
3096 fprintf(stderr
, _("%s: command was '%s', result was %d\n"),
3097 progname
, buf
, result
);
3101 /* Is A a space character in the C locale? */
3108 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
3113 /* Is A an alphabetic character in the C locale? */
3120 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
3121 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
3122 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
3123 case 'V': case 'W': case 'X': case 'Y': case 'Z':
3124 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
3125 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
3126 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
3127 case 'v': case 'w': case 'x': case 'y': case 'z':
3132 /* If A is an uppercase character in the C locale, return its lowercase
3133 counterpart. Otherwise, return A. */
3139 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
3140 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
3141 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
3142 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
3143 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
3144 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
3145 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
3146 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
3147 case 'Y': return 'y'; case 'Z': return 'z';
3151 /* case-insensitive equality */
3152 static ATTRIBUTE_PURE
bool
3153 ciequal(register const char *ap
, register const char *bp
)
3155 while (lowerit(*ap
) == lowerit(*bp
++))
3161 static ATTRIBUTE_PURE
bool
3162 itsabbr(register const char *abbr
, register const char *word
)
3164 if (lowerit(*abbr
) != lowerit(*word
))
3167 while (*++abbr
!= '\0')
3171 } while (lowerit(*word
++) != lowerit(*abbr
));
3175 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
3177 static ATTRIBUTE_PURE
bool
3178 ciprefix(char const *abbr
, char const *word
)
3183 while (lowerit(*abbr
++) == lowerit(*word
++));
3188 static const struct lookup
*
3189 byword(const char *word
, const struct lookup
*table
)
3191 register const struct lookup
* foundlp
;
3192 register const struct lookup
* lp
;
3194 if (word
== NULL
|| table
== NULL
)
3197 /* If TABLE is LASTS and the word starts with "last" followed
3198 by a non-'-', skip the "last" and look in WDAY_NAMES instead.
3199 Warn about any usage of the undocumented prefix "last-". */
3200 if (table
== lasts
&& ciprefix("last", word
) && word
[4]) {
3202 warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
3211 ** Look for exact match.
3213 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
3214 if (ciequal(word
, lp
->l_word
))
3217 ** Look for inexact match.
3220 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
3221 if (ciprefix(word
, lp
->l_word
)) {
3222 if (foundlp
== NULL
)
3224 else return NULL
; /* multiple inexact matches */
3227 if (foundlp
&& noise
) {
3228 /* Warn about any backward-compatibility issue with pre-2017c zic. */
3229 bool pre_2017c_match
= false;
3230 for (lp
= table
; lp
->l_word
; lp
++)
3231 if (itsabbr(word
, lp
->l_word
)) {
3232 if (pre_2017c_match
) {
3233 warning(_("\"%s\" is ambiguous in pre-2017c zic"), word
);
3236 pre_2017c_match
= true;
3244 getfields(register char *cp
)
3247 register char ** array
;
3252 array
= emalloc(size_product(strlen(cp
) + 1, sizeof *array
));
3255 while (is_space(*cp
))
3257 if (*cp
== '\0' || *cp
== '#')
3259 array
[nsubs
++] = dp
= cp
;
3261 if ((*dp
= *cp
++) != '"')
3263 else while ((*dp
= *cp
++) != '"')
3267 error(_("Odd number of quotation marks"));
3270 } while (*cp
&& *cp
!= '#' && !is_space(*cp
));
3275 array
[nsubs
] = NULL
;
3279 static _Noreturn
void
3282 error(_("time overflow"));
3286 static ATTRIBUTE_PURE zic_t
3287 oadd(zic_t t1
, zic_t t2
)
3289 if (t1
< 0 ? t2
< ZIC_MIN
- t1
: ZIC_MAX
- t1
< t2
)
3294 static ATTRIBUTE_PURE zic_t
3295 tadd(zic_t t1
, zic_t t2
)
3298 if (t2
< min_time
- t1
) {
3304 if (max_time
- t1
< t2
) {
3314 ** Given a rule, and a year, compute the date (in seconds since January 1,
3315 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
3319 rpytime(const struct rule
*rp
, zic_t wantedy
)
3322 register zic_t dayoff
; /* with a nod to Margaret O. */
3323 register zic_t t
, y
;
3325 if (wantedy
== ZIC_MIN
)
3327 if (wantedy
== ZIC_MAX
)
3334 dayoff
= (wantedy
/ YEARSPERREPEAT
) * (SECSPERREPEAT
/ SECSPERDAY
);
3335 wantedy
%= YEARSPERREPEAT
;
3337 } else if (wantedy
< 0) {
3338 dayoff
= (wantedy
/ YEARSPERREPEAT
) * (SECSPERREPEAT
/ SECSPERDAY
);
3339 wantedy
%= YEARSPERREPEAT
;
3341 while (wantedy
!= y
) {
3343 i
= len_years
[isleap(y
)];
3347 i
= -len_years
[isleap(y
)];
3349 dayoff
= oadd(dayoff
, i
);
3351 while (m
!= rp
->r_month
) {
3352 i
= len_months
[isleap(y
)][m
];
3353 dayoff
= oadd(dayoff
, i
);
3356 i
= rp
->r_dayofmonth
;
3357 if (m
== TM_FEBRUARY
&& i
== 29 && !isleap(y
)) {
3358 if (rp
->r_dycode
== DC_DOWLEQ
)
3361 error(_("use of 2/29 in non leap-year"));
3366 dayoff
= oadd(dayoff
, i
);
3367 if (rp
->r_dycode
== DC_DOWGEQ
|| rp
->r_dycode
== DC_DOWLEQ
) {
3368 register zic_t wday
;
3370 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3373 ** Don't trust mod of negative numbers.
3376 wday
= (wday
+ dayoff
) % LDAYSPERWEEK
;
3378 wday
-= ((-dayoff
) % LDAYSPERWEEK
);
3380 wday
+= LDAYSPERWEEK
;
3382 while (wday
!= rp
->r_wday
)
3383 if (rp
->r_dycode
== DC_DOWGEQ
) {
3384 dayoff
= oadd(dayoff
, 1);
3385 if (++wday
>= LDAYSPERWEEK
)
3389 dayoff
= oadd(dayoff
, -1);
3391 wday
= LDAYSPERWEEK
- 1;
3394 if (i
< 0 || i
>= len_months
[isleap(y
)][m
]) {
3396 warning(_("rule goes past start/end of month; \
3397 will not work with pre-2004 versions of zic"));
3400 if (dayoff
< min_time
/ SECSPERDAY
)
3402 if (dayoff
> max_time
/ SECSPERDAY
)
3404 t
= (zic_t
) dayoff
* SECSPERDAY
;
3405 return tadd(t
, rp
->r_tod
);
3409 newabbr(const char *string
)
3413 if (strcmp(string
, GRANDPARENTED
) != 0) {
3414 register const char * cp
;
3419 while (is_alpha(*cp
) || ('0' <= *cp
&& *cp
<= '9')
3420 || *cp
== '-' || *cp
== '+')
3422 if (noise
&& cp
- string
< 3)
3423 mp
= _("time zone abbreviation has fewer than 3 characters");
3424 if (cp
- string
> ZIC_MAX_ABBR_LEN_WO_WARN
)
3425 mp
= _("time zone abbreviation has too many characters");
3427 mp
= _("time zone abbreviation differs from POSIX standard");
3429 warning("%s (%s)", mp
, string
);
3431 i
= strlen(string
) + 1;
3432 if (charcnt
+ i
> TZ_MAX_CHARS
) {
3433 error(_("too many, or too long, time zone abbreviations"));
3436 strcpy(&chars
[charcnt
], string
);
3440 /* Ensure that the directories of ARGNAME exist, by making any missing
3441 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3442 do it for ARGNAME too. Exit with failure if there is trouble.
3443 Do not consider an existing non-directory to be trouble. */
3445 mkdirs(char const *argname
, bool ancestors
)
3447 register char * name
;
3450 cp
= name
= ecpyalloc(argname
);
3452 /* On MS-Windows systems, do not worry about drive letters or
3453 backslashes, as this should suffice in practice. Time zone
3454 names do not use drive letters and backslashes. If the -d
3455 option of zic does not name an already-existing directory,
3456 it can use slashes to separate the already-existing
3457 ancestor prefix from the to-be-created subdirectories. */
3459 /* Do not mkdir a root directory, as it must exist. */
3463 while (cp
&& ((cp
= strchr(cp
, '/')) || !ancestors
)) {
3467 ** Try to create it. It's OK if creation fails because
3468 ** the directory already exists, perhaps because some
3469 ** other process just created it. For simplicity do
3470 ** not check first whether it already exists, as that
3471 ** is checked anyway if the mkdir fails.
3473 if (mkdir(name
, MKDIR_UMASK
) != 0) {
3474 /* For speed, skip itsdir if errno == EEXIST. Since
3475 mkdirs is called only after open fails with ENOENT
3476 on a subfile, EEXIST implies itsdir here. */
3478 if (err
!= EEXIST
&& !itsdir(name
)) {
3479 error(_("%s: Can't create directory %s: %s"),
3480 progname
, name
, strerror(err
));