2 ** This file is in the public domain, so clarified as of
3 ** 2006-07-17 by Arthur David Olson.
13 #define ZIC_VERSION_PRE_2013 '2'
14 #define ZIC_VERSION '3'
16 typedef int_fast64_t zic_t
;
17 #define ZIC_MIN INT_FAST64_MIN
18 #define ZIC_MAX INT_FAST64_MAX
19 #define SCNdZIC SCNdFAST64
21 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
22 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
23 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
29 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
31 #define MKDIR_UMASK 0755
35 const char * r_filename
;
39 zic_t r_loyear
; /* for example, 1986 */
40 zic_t r_hiyear
; /* for example, 1986 */
41 const char * r_yrtype
;
45 int r_month
; /* 0..11 */
47 int r_dycode
; /* see below */
51 zic_t r_tod
; /* time from midnight */
52 bool r_todisstd
; /* above is standard time if 1 */
53 /* or wall clock time if 0 */
54 bool r_todisgmt
; /* above is GMT if 1 */
55 /* or local time if 0 */
56 zic_t r_stdoff
; /* offset from standard time */
57 const char * r_abbrvar
; /* variable part of abbreviation */
59 int r_todo
; /* a rule to do (used in outzone) */
60 zic_t r_temp
; /* used in outzone */
64 ** r_dycode r_dayofmonth r_wday
67 #define DC_DOM 0 /* 1..31 */ /* unused */
68 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
69 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
72 const char * z_filename
;
78 const char * z_format
;
79 char z_format_specifier
;
83 struct rule
* z_rules
;
86 struct rule z_untilrule
;
90 extern int getopt(int argc
, char * const argv
[],
91 const char * options
);
92 extern int link(const char * fromname
, const char * toname
);
97 # define link(from, to) (-1)
100 # define symlink(from, to) (-1)
103 static void addtt(zic_t starttime
, int type
);
104 static int addtype(zic_t
, char const *, bool, bool, bool);
105 static void leapadd(zic_t
, bool, int, int);
106 static void adjleap(void);
107 static void associate(void);
108 static void dolink(const char * fromfield
, const char * tofield
);
109 static char ** getfields(char * buf
);
110 static zic_t
gethms(const char * string
, const char * errstring
,
112 static void infile(const char * filename
);
113 static void inleap(char ** fields
, int nfields
);
114 static void inlink(char ** fields
, int nfields
);
115 static void inrule(char ** fields
, int nfields
);
116 static bool inzcont(char ** fields
, int nfields
);
117 static bool inzone(char ** fields
, int nfields
);
118 static bool inzsub(char **, int, bool);
119 static int itsdir(const char * name
);
120 static bool is_alpha(char a
);
121 static char lowerit(char);
122 static bool mkdirs(char *);
123 static void newabbr(const char * abbr
);
124 static zic_t
oadd(zic_t t1
, zic_t t2
);
125 static void outzone(const struct zone
* zp
, int ntzones
);
126 static zic_t
rpytime(const struct rule
* rp
, zic_t wantedy
);
127 static void rulesub(struct rule
* rp
,
128 const char * loyearp
, const char * hiyearp
,
129 const char * typep
, const char * monthp
,
130 const char * dayp
, const char * timep
);
131 static zic_t
tadd(zic_t t1
, zic_t t2
);
132 static bool yearistype(int year
, const char * type
);
134 /* Bound on length of what %z can expand to. */
135 enum { PERCENT_Z_LEN_BOUND
= sizeof "+995959" - 1 };
139 static bool warnings
;
140 static const char * filename
;
142 static bool leapseen
;
143 static zic_t leapminyear
;
144 static zic_t leapmaxyear
;
146 static int max_abbrvar_len
= PERCENT_Z_LEN_BOUND
;
147 static int max_format_len
;
148 static zic_t max_year
;
149 static zic_t min_year
;
151 static const char * rfilename
;
153 static const char * progname
;
155 static int timecnt_alloc
;
168 ** Which fields are which on a Zone line.
176 #define ZF_TILMONTH 6
179 #define ZONE_MINFIELDS 5
180 #define ZONE_MAXFIELDS 9
183 ** Which fields are which on a Zone continuation line.
189 #define ZFC_TILYEAR 3
190 #define ZFC_TILMONTH 4
192 #define ZFC_TILTIME 6
193 #define ZONEC_MINFIELDS 3
194 #define ZONEC_MAXFIELDS 7
197 ** Which files are which on a Rule line.
209 #define RULE_FIELDS 10
212 ** Which fields are which on a Link line.
217 #define LINK_FIELDS 3
220 ** Which fields are which on a Leap line.
229 #define LEAP_FIELDS 7
239 static struct rule
* rules
;
240 static int nrules
; /* number of rules */
241 static int nrules_alloc
;
243 static struct zone
* zones
;
244 static int nzones
; /* number of zones */
245 static int nzones_alloc
;
248 const char * l_filename
;
254 static struct link
* links
;
256 static int nlinks_alloc
;
263 static struct lookup
const * byword(const char * string
,
264 const struct lookup
* lp
);
266 static struct lookup
const line_codes
[] = {
274 static struct lookup
const mon_names
[] = {
275 { "January", TM_JANUARY
},
276 { "February", TM_FEBRUARY
},
277 { "March", TM_MARCH
},
278 { "April", TM_APRIL
},
282 { "August", TM_AUGUST
},
283 { "September", TM_SEPTEMBER
},
284 { "October", TM_OCTOBER
},
285 { "November", TM_NOVEMBER
},
286 { "December", TM_DECEMBER
},
290 static struct lookup
const wday_names
[] = {
291 { "Sunday", TM_SUNDAY
},
292 { "Monday", TM_MONDAY
},
293 { "Tuesday", TM_TUESDAY
},
294 { "Wednesday", TM_WEDNESDAY
},
295 { "Thursday", TM_THURSDAY
},
296 { "Friday", TM_FRIDAY
},
297 { "Saturday", TM_SATURDAY
},
301 static struct lookup
const lasts
[] = {
302 { "last-Sunday", TM_SUNDAY
},
303 { "last-Monday", TM_MONDAY
},
304 { "last-Tuesday", TM_TUESDAY
},
305 { "last-Wednesday", TM_WEDNESDAY
},
306 { "last-Thursday", TM_THURSDAY
},
307 { "last-Friday", TM_FRIDAY
},
308 { "last-Saturday", TM_SATURDAY
},
312 static struct lookup
const begin_years
[] = {
313 { "minimum", YR_MINIMUM
},
314 { "maximum", YR_MAXIMUM
},
318 static struct lookup
const end_years
[] = {
319 { "minimum", YR_MINIMUM
},
320 { "maximum", YR_MAXIMUM
},
325 static struct lookup
const leap_types
[] = {
327 { "Stationary", false },
331 static const int len_months
[2][MONSPERYEAR
] = {
332 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
333 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
336 static const int len_years
[2] = {
337 DAYSPERNYEAR
, DAYSPERLYEAR
340 static struct attype
{
344 static zic_t gmtoffs
[TZ_MAX_TYPES
];
345 static char isdsts
[TZ_MAX_TYPES
];
346 static unsigned char abbrinds
[TZ_MAX_TYPES
];
347 static bool ttisstds
[TZ_MAX_TYPES
];
348 static bool ttisgmts
[TZ_MAX_TYPES
];
349 static char chars
[TZ_MAX_CHARS
];
350 static zic_t trans
[TZ_MAX_LEAPS
];
351 static zic_t corr
[TZ_MAX_LEAPS
];
352 static char roll
[TZ_MAX_LEAPS
];
355 ** Memory allocation.
358 static _Noreturn
void
359 memory_exhausted(const char *msg
)
361 fprintf(stderr
, _("%s: Memory exhausted: %s\n"), progname
, msg
);
365 static ATTRIBUTE_PURE
size_t
366 size_product(size_t nitems
, size_t itemsize
)
368 if (SIZE_MAX
/ itemsize
< nitems
)
369 memory_exhausted(_("size overflow"));
370 return nitems
* itemsize
;
375 strdup(char const *str
)
377 char *result
= malloc(strlen(str
) + 1);
378 return result
? strcpy(result
, str
) : result
;
382 static ATTRIBUTE_PURE
void *
386 memory_exhausted(strerror(errno
));
393 return memcheck(malloc(size
));
397 erealloc(void *ptr
, size_t size
)
399 return memcheck(realloc(ptr
, size
));
403 ecpyalloc (char const *str
)
405 return memcheck(strdup(str
));
409 growalloc(void *ptr
, size_t itemsize
, int nitems
, int *nitems_alloc
)
411 if (nitems
< *nitems_alloc
)
414 int amax
= INT_MAX
< SIZE_MAX
? INT_MAX
: SIZE_MAX
;
415 if ((amax
- 1) / 3 * 2 < *nitems_alloc
)
416 memory_exhausted(_("int overflow"));
417 *nitems_alloc
= *nitems_alloc
+ (*nitems_alloc
>> 1) + 1;
418 return erealloc(ptr
, size_product(*nitems_alloc
, itemsize
));
427 eats(const char *const name
, const int num
, const char *const rname
,
437 eat(const char *const name
, const int num
)
439 eats(name
, num
, NULL
, -1);
442 static void ATTRIBUTE_FORMAT((printf
, 1, 0))
443 verror(const char *const string
, va_list args
)
446 ** Match the format of "cc" to allow sh users to
447 ** zic ... 2>&1 | error -t "*" -v
451 fprintf(stderr
, _("\"%s\", line %d: "), filename
, linenum
);
452 vfprintf(stderr
, string
, args
);
453 if (rfilename
!= NULL
)
454 fprintf(stderr
, _(" (rule from \"%s\", line %d)"),
455 rfilename
, rlinenum
);
456 fprintf(stderr
, "\n");
459 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
460 error(const char *const string
, ...)
463 va_start(args
, string
);
464 verror(string
, args
);
469 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
470 warning(const char *const string
, ...)
473 fprintf(stderr
, _("warning: "));
474 va_start(args
, string
);
475 verror(string
, args
);
481 close_file(FILE *stream
, char const *name
)
483 char const *e
= (ferror(stream
) ? _("I/O error")
484 : fclose(stream
) != 0 ? strerror(errno
) : NULL
);
486 fprintf(stderr
, "%s: ", progname
);
488 fprintf(stderr
, "%s: ", name
);
489 fprintf(stderr
, "%s\n", e
);
494 static _Noreturn
void
495 usage(FILE *stream
, int status
)
498 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
499 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
500 "\t[ -L leapseconds ] [ filename ... ]\n\n"
501 "Report bugs to %s.\n"),
502 progname
, progname
, REPORT_BUGS_TO
);
503 if (status
== EXIT_SUCCESS
)
504 close_file(stream
, NULL
);
508 static const char * psxrules
;
509 static const char * lcltime
;
510 static const char * directory
;
511 static const char * leapsec
;
512 static const char * yitcommand
;
515 main(int argc
, char **argv
)
522 umask(umask(S_IWGRP
| S_IWOTH
) | (S_IWGRP
| S_IWOTH
));
525 setlocale(LC_ALL
, "");
527 bindtextdomain(TZ_DOMAIN
, TZ_DOMAINDIR
);
528 #endif /* defined TEXTDOMAINDIR */
529 textdomain(TZ_DOMAIN
);
530 #endif /* HAVE_GETTEXT */
532 if (TYPE_BIT(zic_t
) < 64) {
533 fprintf(stderr
, "%s: %s\n", progname
,
534 _("wild compilation-time specification of zic_t"));
537 for (i
= 1; i
< argc
; ++i
)
538 if (strcmp(argv
[i
], "--version") == 0) {
539 printf("zic %s%s\n", PKGVERSION
, TZVERSION
);
540 close_file(stdout
, NULL
);
542 } else if (strcmp(argv
[i
], "--help") == 0) {
543 usage(stdout
, EXIT_SUCCESS
);
545 while ((c
= getopt(argc
, argv
, "d:l:p:L:vsy:")) != EOF
&& c
!= -1)
548 usage(stderr
, EXIT_FAILURE
);
550 if (directory
== NULL
)
554 _("%s: More than one -d option specified\n"),
564 _("%s: More than one -l option specified\n"),
570 if (psxrules
== NULL
)
574 _("%s: More than one -p option specified\n"),
580 if (yitcommand
== NULL
)
584 _("%s: More than one -y option specified\n"),
594 _("%s: More than one -L option specified\n"),
603 warning(_("-s ignored"));
606 if (optind
== argc
- 1 && strcmp(argv
[optind
], "=") == 0)
607 usage(stderr
, EXIT_FAILURE
); /* usage message by request */
608 if (directory
== NULL
)
610 if (yitcommand
== NULL
)
611 yitcommand
= "yearistype";
613 if (optind
< argc
&& leapsec
!= NULL
) {
618 for (i
= optind
; i
< argc
; ++i
)
623 for (i
= 0; i
< nzones
; i
= j
) {
625 ** Find the next non-continuation zone entry.
627 for (j
= i
+ 1; j
< nzones
&& zones
[j
].z_name
== NULL
; ++j
)
629 outzone(&zones
[i
], j
- i
);
634 for (i
= 0; i
< nlinks
; ++i
) {
635 eat(links
[i
].l_filename
, links
[i
].l_linenum
);
636 dolink(links
[i
].l_from
, links
[i
].l_to
);
638 for (j
= 0; j
< nlinks
; ++j
)
639 if (strcmp(links
[i
].l_to
,
640 links
[j
].l_from
) == 0)
641 warning(_("link to link"));
643 if (lcltime
!= NULL
) {
644 eat(_("command line"), 1);
645 dolink(lcltime
, TZDEFAULT
);
647 if (psxrules
!= NULL
) {
648 eat(_("command line"), 1);
649 dolink(psxrules
, TZDEFRULES
);
651 if (warnings
&& (ferror(stderr
) || fclose(stderr
) != 0))
653 return errors
? EXIT_FAILURE
: EXIT_SUCCESS
;
657 componentcheck(char const *name
, char const *component
,
658 char const *component_end
)
660 enum { component_len_max
= 14 };
661 size_t component_len
= component_end
- component
;
662 if (component_len
== 0) {
664 error (_("empty file name"));
666 error (_(component
== name
667 ? "file name '%s' begins with '/'"
669 ? "file name '%s' contains '//'"
670 : "file name '%s' ends with '/'"),
674 if (0 < component_len
&& component_len
<= 2
675 && component
[0] == '.' && component_end
[-1] == '.') {
676 error(_("file name '%s' contains '%.*s' component"),
677 name
, (int) component_len
, component
);
681 if (0 < component_len
&& component
[0] == '-')
682 warning(_("file name '%s' component contains leading '-'"),
684 if (component_len_max
< component_len
)
685 warning(_("file name '%s' contains overlength component"
687 name
, component_len_max
, component
);
693 namecheck(const char *name
)
695 register char const *cp
;
697 /* Benign characters in a portable file name. */
698 static char const benign
[] =
700 "abcdefghijklmnopqrstuvwxyz"
701 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
703 /* Non-control chars in the POSIX portable character set,
704 excluding the benign characters. */
705 static char const printable_and_not_benign
[] =
706 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
708 register char const *component
= name
;
709 for (cp
= name
; *cp
; cp
++) {
710 unsigned char c
= *cp
;
711 if (noise
&& !strchr(benign
, c
)) {
712 warning((strchr(printable_and_not_benign
, c
)
713 ? _("file name '%s' contains byte '%c'")
714 : _("file name '%s' contains byte '\\%o'")),
718 if (!componentcheck(name
, component
, cp
))
723 return componentcheck(name
, component
, cp
);
727 relname(char const *dir
, char const *base
)
730 return ecpyalloc(base
);
732 size_t dir_len
= strlen(dir
);
733 bool needs_slash
= dir_len
&& dir
[dir_len
- 1] != '/';
734 char *result
= emalloc(dir_len
+ needs_slash
+ strlen(base
) + 1);
735 result
[dir_len
] = '/';
736 strcpy(result
+ dir_len
+ needs_slash
, base
);
737 return memcpy(result
, dir
, dir_len
);
742 dolink(char const *fromfield
, char const *tofield
)
744 register char * fromname
;
745 register char * toname
;
746 register int fromisdir
;
748 fromname
= relname(directory
, fromfield
);
749 toname
= relname(directory
, tofield
);
751 ** We get to be careful here since
752 ** there's a fair chance of root running us.
754 fromisdir
= itsdir(fromname
);
756 char const *e
= strerror(fromisdir
< 0 ? errno
: EPERM
);
757 fprintf(stderr
, _("%s: link from %s failed: %s"),
758 progname
, fromname
, e
);
761 if (itsdir(toname
) <= 0)
763 if (link(fromname
, toname
) != 0) {
766 if (! mkdirs(toname
))
769 result
= link(fromname
, toname
);
771 const char *s
= fromfield
;
775 register char * symlinkcontents
= NULL
;
779 while ((s
= strchr(s
, '/'))
780 && ! strncmp (fromfield
, tofield
,
783 for (s
= tofield
+ (t
- fromfield
); *s
; s
++)
784 dotdots
+= *s
== '/';
786 = emalloc(3 * dotdots
+ strlen(t
) + 1);
787 for (p
= symlinkcontents
; dotdots
-- != 0; p
+= 3)
790 result
= symlink(symlinkcontents
, toname
);
792 warning(_("hard link failed, symbolic link used"));
793 free(symlinkcontents
);
798 fp
= fopen(fromname
, "rb");
800 const char *e
= strerror(errno
);
802 _("%s: Can't read %s: %s\n"),
803 progname
, fromname
, e
);
806 tp
= fopen(toname
, "wb");
808 const char *e
= strerror(errno
);
810 _("%s: Can't create %s: %s\n"),
811 progname
, toname
, e
);
814 while ((c
= getc(fp
)) != EOF
)
816 close_file(fp
, fromname
);
817 close_file(tp
, toname
);
818 warning(_("link failed, copy used"));
825 #define TIME_T_BITS_IN_FILE 64
827 static zic_t
const min_time
= MINVAL (zic_t
, TIME_T_BITS_IN_FILE
);
828 static zic_t
const max_time
= MAXVAL (zic_t
, TIME_T_BITS_IN_FILE
);
830 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
831 rounded downward to the negation of a power of two that is
832 comfortably outside the error bounds.
834 zic does not output time stamps before this, partly because they
835 are physically suspect, and partly because GNOME mishandles them; see
836 GNOME bug 730332 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>.
838 For the time of the Big Bang, see:
840 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
841 I. Overview of products and scientific results.
842 arXiv:1303.5062 2013-03-20 20:10:01 UTC
843 <http://arxiv.org/pdf/1303.5062v1> [PDF]
845 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
846 gives the value 13.798 plus-or-minus 0.037 billion years.
847 Multiplying this by 1000000000 and then by 31557600 (the number of
848 seconds in an astronomical year) gives a value that is comfortably
849 less than 2**59, so BIG_BANG is - 2**59.
851 BIG_BANG is approximate, and may change in future versions.
852 Please do not rely on its exact value. */
855 #define BIG_BANG (- (1LL << 59))
858 static const zic_t big_bang_time
= BIG_BANG
;
860 /* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */
862 itsdir(char const *name
)
865 int res
= stat(name
, &st
);
869 return S_ISDIR(st
.st_mode
) != 0;
872 char *nameslashdot
= relname(name
, ".");
873 res
= stat(nameslashdot
, &st
);
881 ** Associate sets of rules with zones.
885 ** Sort by rule name.
889 rcomp(const void *cp1
, const void *cp2
)
891 return strcmp(((const struct rule
*) cp1
)->r_name
,
892 ((const struct rule
*) cp2
)->r_name
);
898 register struct zone
* zp
;
899 register struct rule
* rp
;
900 register int base
, out
;
904 qsort(rules
, nrules
, sizeof *rules
, rcomp
);
905 for (i
= 0; i
< nrules
- 1; ++i
) {
906 if (strcmp(rules
[i
].r_name
,
907 rules
[i
+ 1].r_name
) != 0)
909 if (strcmp(rules
[i
].r_filename
,
910 rules
[i
+ 1].r_filename
) == 0)
912 eat(rules
[i
].r_filename
, rules
[i
].r_linenum
);
913 warning(_("same rule name in multiple files"));
914 eat(rules
[i
+ 1].r_filename
, rules
[i
+ 1].r_linenum
);
915 warning(_("same rule name in multiple files"));
916 for (j
= i
+ 2; j
< nrules
; ++j
) {
917 if (strcmp(rules
[i
].r_name
,
918 rules
[j
].r_name
) != 0)
920 if (strcmp(rules
[i
].r_filename
,
921 rules
[j
].r_filename
) == 0)
923 if (strcmp(rules
[i
+ 1].r_filename
,
924 rules
[j
].r_filename
) == 0)
931 for (i
= 0; i
< nzones
; ++i
) {
936 for (base
= 0; base
< nrules
; base
= out
) {
938 for (out
= base
+ 1; out
< nrules
; ++out
)
939 if (strcmp(rp
->r_name
, rules
[out
].r_name
) != 0)
941 for (i
= 0; i
< nzones
; ++i
) {
943 if (strcmp(zp
->z_rule
, rp
->r_name
) != 0)
946 zp
->z_nrules
= out
- base
;
949 for (i
= 0; i
< nzones
; ++i
) {
951 if (zp
->z_nrules
== 0) {
953 ** Maybe we have a local standard time offset.
955 eat(zp
->z_filename
, zp
->z_linenum
);
956 zp
->z_stdoff
= gethms(zp
->z_rule
, _("unruly zone"),
959 ** Note, though, that if there's no rule,
960 ** a '%s' in the format is a bad thing.
962 if (zp
->z_format_specifier
== 's')
963 error("%s", _("%s in ruleless zone"));
971 infile(const char *name
)
974 register char ** fields
;
976 register const struct lookup
* lp
;
977 register int nfields
;
978 register bool wantcont
;
982 if (strcmp(name
, "-") == 0) {
983 name
= _("standard input");
985 } else if ((fp
= fopen(name
, "r")) == NULL
) {
986 const char *e
= strerror(errno
);
988 fprintf(stderr
, _("%s: Can't open %s: %s\n"),
993 for (num
= 1; ; ++num
) {
995 if (fgets(buf
, sizeof buf
, fp
) != buf
)
997 cp
= strchr(buf
, '\n');
999 error(_("line too long"));
1003 fields
= getfields(buf
);
1005 while (fields
[nfields
] != NULL
) {
1008 if (strcmp(fields
[nfields
], "-") == 0)
1009 fields
[nfields
] = &nada
;
1014 } else if (wantcont
) {
1015 wantcont
= inzcont(fields
, nfields
);
1017 lp
= byword(fields
[0], line_codes
);
1019 error(_("input line of unknown type"));
1020 else switch ((int) (lp
->l_value
)) {
1022 inrule(fields
, nfields
);
1026 wantcont
= inzone(fields
, nfields
);
1029 inlink(fields
, nfields
);
1033 if (name
!= leapsec
)
1034 warning(_("%s: Leap line in non leap"
1035 " seconds file %s"),
1037 else inleap(fields
, nfields
);
1040 default: /* "cannot happen" */
1042 _("%s: panic: Invalid l_value %d\n"),
1043 progname
, lp
->l_value
);
1049 close_file(fp
, filename
);
1051 error(_("expected continuation line not found"));
1055 ** Convert a string of one of the forms
1056 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1057 ** into a number of seconds.
1058 ** A null string maps to zero.
1059 ** Call error with errstring and return zero on errors.
1063 gethms(char const *string
, char const *errstring
, bool signable
)
1069 if (string
== NULL
|| *string
== '\0')
1073 else if (*string
== '-') {
1077 if (sscanf(string
, "%"SCNdZIC
"%c", &hh
, &xs
) == 1)
1079 else if (sscanf(string
, "%"SCNdZIC
":%d%c", &hh
, &mm
, &xs
) == 2)
1081 else if (sscanf(string
, "%"SCNdZIC
":%d:%d%c", &hh
, &mm
, &ss
, &xs
)
1083 error("%s", errstring
);
1087 mm
< 0 || mm
>= MINSPERHOUR
||
1088 ss
< 0 || ss
> SECSPERMIN
) {
1089 error("%s", errstring
);
1092 if (ZIC_MAX
/ SECSPERHOUR
< hh
) {
1093 error(_("time overflow"));
1096 if (noise
&& (hh
> HOURSPERDAY
||
1097 (hh
== HOURSPERDAY
&& (mm
!= 0 || ss
!= 0))))
1098 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1099 return oadd(sign
* hh
* SECSPERHOUR
,
1100 sign
* (mm
* SECSPERMIN
+ ss
));
1104 inrule(char **fields
, int nfields
)
1106 static struct rule r
;
1108 if (nfields
!= RULE_FIELDS
) {
1109 error(_("wrong number of fields on Rule line"));
1112 if (*fields
[RF_NAME
] == '\0') {
1113 error(_("nameless rule"));
1116 r
.r_filename
= filename
;
1117 r
.r_linenum
= linenum
;
1118 r
.r_stdoff
= gethms(fields
[RF_STDOFF
], _("invalid saved time"), true);
1119 rulesub(&r
, fields
[RF_LOYEAR
], fields
[RF_HIYEAR
], fields
[RF_COMMAND
],
1120 fields
[RF_MONTH
], fields
[RF_DAY
], fields
[RF_TOD
]);
1121 r
.r_name
= ecpyalloc(fields
[RF_NAME
]);
1122 r
.r_abbrvar
= ecpyalloc(fields
[RF_ABBRVAR
]);
1123 if (max_abbrvar_len
< strlen(r
.r_abbrvar
))
1124 max_abbrvar_len
= strlen(r
.r_abbrvar
);
1125 rules
= growalloc(rules
, sizeof *rules
, nrules
, &nrules_alloc
);
1126 rules
[nrules
++] = r
;
1130 inzone(char **fields
, int nfields
)
1134 if (nfields
< ZONE_MINFIELDS
|| nfields
> ZONE_MAXFIELDS
) {
1135 error(_("wrong number of fields on Zone line"));
1138 if (strcmp(fields
[ZF_NAME
], TZDEFAULT
) == 0 && lcltime
!= NULL
) {
1140 _("\"Zone %s\" line and -l option are mutually exclusive"),
1144 if (strcmp(fields
[ZF_NAME
], TZDEFRULES
) == 0 && psxrules
!= NULL
) {
1146 _("\"Zone %s\" line and -p option are mutually exclusive"),
1150 for (i
= 0; i
< nzones
; ++i
)
1151 if (zones
[i
].z_name
!= NULL
&&
1152 strcmp(zones
[i
].z_name
, fields
[ZF_NAME
]) == 0) {
1154 _("duplicate zone name %s (file \"%s\", line %d)"),
1156 zones
[i
].z_filename
,
1157 zones
[i
].z_linenum
);
1160 return inzsub(fields
, nfields
, false);
1164 inzcont(char **fields
, int nfields
)
1166 if (nfields
< ZONEC_MINFIELDS
|| nfields
> ZONEC_MAXFIELDS
) {
1167 error(_("wrong number of fields on Zone continuation line"));
1170 return inzsub(fields
, nfields
, true);
1174 inzsub(char **fields
, int nfields
, bool iscont
)
1178 static struct zone z
;
1179 register int i_gmtoff
, i_rule
, i_format
;
1180 register int i_untilyear
, i_untilmonth
;
1181 register int i_untilday
, i_untiltime
;
1182 register bool hasuntil
;
1185 i_gmtoff
= ZFC_GMTOFF
;
1187 i_format
= ZFC_FORMAT
;
1188 i_untilyear
= ZFC_TILYEAR
;
1189 i_untilmonth
= ZFC_TILMONTH
;
1190 i_untilday
= ZFC_TILDAY
;
1191 i_untiltime
= ZFC_TILTIME
;
1193 } else if (!namecheck(fields
[ZF_NAME
]))
1196 i_gmtoff
= ZF_GMTOFF
;
1198 i_format
= ZF_FORMAT
;
1199 i_untilyear
= ZF_TILYEAR
;
1200 i_untilmonth
= ZF_TILMONTH
;
1201 i_untilday
= ZF_TILDAY
;
1202 i_untiltime
= ZF_TILTIME
;
1203 z
.z_name
= ecpyalloc(fields
[ZF_NAME
]);
1205 z
.z_filename
= filename
;
1206 z
.z_linenum
= linenum
;
1207 z
.z_gmtoff
= gethms(fields
[i_gmtoff
], _("invalid UT offset"), true);
1208 if ((cp
= strchr(fields
[i_format
], '%')) != 0) {
1209 if ((*++cp
!= 's' && *cp
!= 'z') || strchr(cp
, '%')
1210 || strchr(fields
[i_format
], '/')) {
1211 error(_("invalid abbreviation format"));
1215 z
.z_rule
= ecpyalloc(fields
[i_rule
]);
1216 z
.z_format
= cp1
= ecpyalloc(fields
[i_format
]);
1217 z
.z_format_specifier
= cp
? *cp
: '\0';
1218 if (z
.z_format_specifier
== 'z') {
1220 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1222 cp1
[cp
- fields
[i_format
]] = 's';
1224 if (max_format_len
< strlen(z
.z_format
))
1225 max_format_len
= strlen(z
.z_format
);
1226 hasuntil
= nfields
> i_untilyear
;
1228 z
.z_untilrule
.r_filename
= filename
;
1229 z
.z_untilrule
.r_linenum
= linenum
;
1230 rulesub(&z
.z_untilrule
,
1231 fields
[i_untilyear
],
1234 (nfields
> i_untilmonth
) ?
1235 fields
[i_untilmonth
] : "Jan",
1236 (nfields
> i_untilday
) ? fields
[i_untilday
] : "1",
1237 (nfields
> i_untiltime
) ? fields
[i_untiltime
] : "0");
1238 z
.z_untiltime
= rpytime(&z
.z_untilrule
,
1239 z
.z_untilrule
.r_loyear
);
1240 if (iscont
&& nzones
> 0 &&
1241 z
.z_untiltime
> min_time
&&
1242 z
.z_untiltime
< max_time
&&
1243 zones
[nzones
- 1].z_untiltime
> min_time
&&
1244 zones
[nzones
- 1].z_untiltime
< max_time
&&
1245 zones
[nzones
- 1].z_untiltime
>= z
.z_untiltime
) {
1247 "Zone continuation line end time is not after end time of previous line"
1252 zones
= growalloc(zones
, sizeof *zones
, nzones
, &nzones_alloc
);
1253 zones
[nzones
++] = z
;
1255 ** If there was an UNTIL field on this line,
1256 ** there's more information about the zone on the next line.
1262 inleap(char **fields
, int nfields
)
1264 register const char * cp
;
1265 register const struct lookup
* lp
;
1273 if (nfields
!= LEAP_FIELDS
) {
1274 error(_("wrong number of fields on Leap line"));
1278 cp
= fields
[LP_YEAR
];
1279 if (sscanf(cp
, "%"SCNdZIC
"%c", &year
, &xs
) != 1) {
1283 error(_("invalid leaping year"));
1286 if (!leapseen
|| leapmaxyear
< year
)
1288 if (!leapseen
|| leapminyear
> year
)
1294 i
= len_years
[isleap(j
)];
1298 i
= -len_years
[isleap(j
)];
1300 dayoff
= oadd(dayoff
, i
);
1302 if ((lp
= byword(fields
[LP_MONTH
], mon_names
)) == NULL
) {
1303 error(_("invalid month name"));
1306 month
= lp
->l_value
;
1308 while (j
!= month
) {
1309 i
= len_months
[isleap(year
)][j
];
1310 dayoff
= oadd(dayoff
, i
);
1313 cp
= fields
[LP_DAY
];
1314 if (sscanf(cp
, "%d%c", &day
, &xs
) != 1 ||
1315 day
<= 0 || day
> len_months
[isleap(year
)][month
]) {
1316 error(_("invalid day of month"));
1319 dayoff
= oadd(dayoff
, day
- 1);
1320 if (dayoff
< min_time
/ SECSPERDAY
) {
1321 error(_("time too small"));
1324 if (dayoff
> max_time
/ SECSPERDAY
) {
1325 error(_("time too large"));
1328 t
= dayoff
* SECSPERDAY
;
1329 tod
= gethms(fields
[LP_TIME
], _("invalid time of day"), false);
1330 cp
= fields
[LP_CORR
];
1332 register bool positive
;
1335 if (strcmp(cp
, "") == 0) { /* infile() turns "-" into "" */
1338 } else if (strcmp(cp
, "--") == 0) {
1341 } else if (strcmp(cp
, "+") == 0) {
1344 } else if (strcmp(cp
, "++") == 0) {
1348 error(_("illegal CORRECTION field on Leap line"));
1351 if ((lp
= byword(fields
[LP_ROLL
], leap_types
)) == NULL
) {
1353 "illegal Rolling/Stationary field on Leap line"
1358 if (t
< big_bang_time
) {
1359 error(_("leap second precedes Big Bang"));
1362 leapadd(t
, positive
, lp
->l_value
, count
);
1367 inlink(char **fields
, int nfields
)
1371 if (nfields
!= LINK_FIELDS
) {
1372 error(_("wrong number of fields on Link line"));
1375 if (*fields
[LF_FROM
] == '\0') {
1376 error(_("blank FROM field on Link line"));
1379 if (! namecheck(fields
[LF_TO
]))
1381 l
.l_filename
= filename
;
1382 l
.l_linenum
= linenum
;
1383 l
.l_from
= ecpyalloc(fields
[LF_FROM
]);
1384 l
.l_to
= ecpyalloc(fields
[LF_TO
]);
1385 links
= growalloc(links
, sizeof *links
, nlinks
, &nlinks_alloc
);
1386 links
[nlinks
++] = l
;
1390 rulesub(struct rule
*rp
, const char *loyearp
, const char *hiyearp
,
1391 const char *typep
, const char *monthp
, const char *dayp
,
1394 register const struct lookup
* lp
;
1395 register const char * cp
;
1400 if ((lp
= byword(monthp
, mon_names
)) == NULL
) {
1401 error(_("invalid month name"));
1404 rp
->r_month
= lp
->l_value
;
1405 rp
->r_todisstd
= false;
1406 rp
->r_todisgmt
= false;
1407 dp
= ecpyalloc(timep
);
1409 ep
= dp
+ strlen(dp
) - 1;
1410 switch (lowerit(*ep
)) {
1411 case 's': /* Standard */
1412 rp
->r_todisstd
= true;
1413 rp
->r_todisgmt
= false;
1416 case 'w': /* Wall */
1417 rp
->r_todisstd
= false;
1418 rp
->r_todisgmt
= false;
1421 case 'g': /* Greenwich */
1422 case 'u': /* Universal */
1423 case 'z': /* Zulu */
1424 rp
->r_todisstd
= true;
1425 rp
->r_todisgmt
= true;
1430 rp
->r_tod
= gethms(dp
, _("invalid time of day"), false);
1436 lp
= byword(cp
, begin_years
);
1437 rp
->r_lowasnum
= lp
== NULL
;
1438 if (!rp
->r_lowasnum
) switch ((int) lp
->l_value
) {
1440 rp
->r_loyear
= ZIC_MIN
;
1443 rp
->r_loyear
= ZIC_MAX
;
1445 default: /* "cannot happen" */
1447 _("%s: panic: Invalid l_value %d\n"),
1448 progname
, lp
->l_value
);
1450 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_loyear
, &xs
) != 1) {
1451 error(_("invalid starting year"));
1455 lp
= byword(cp
, end_years
);
1456 rp
->r_hiwasnum
= lp
== NULL
;
1457 if (!rp
->r_hiwasnum
) switch ((int) lp
->l_value
) {
1459 rp
->r_hiyear
= ZIC_MIN
;
1462 rp
->r_hiyear
= ZIC_MAX
;
1465 rp
->r_hiyear
= rp
->r_loyear
;
1467 default: /* "cannot happen" */
1469 _("%s: panic: Invalid l_value %d\n"),
1470 progname
, lp
->l_value
);
1472 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_hiyear
, &xs
) != 1) {
1473 error(_("invalid ending year"));
1476 if (rp
->r_loyear
> rp
->r_hiyear
) {
1477 error(_("starting year greater than ending year"));
1481 rp
->r_yrtype
= NULL
;
1483 if (rp
->r_loyear
== rp
->r_hiyear
) {
1484 error(_("typed single year"));
1487 rp
->r_yrtype
= ecpyalloc(typep
);
1491 ** Accept things such as:
1497 dp
= ecpyalloc(dayp
);
1498 if ((lp
= byword(dp
, lasts
)) != NULL
) {
1499 rp
->r_dycode
= DC_DOWLEQ
;
1500 rp
->r_wday
= lp
->l_value
;
1501 rp
->r_dayofmonth
= len_months
[1][rp
->r_month
];
1503 if ((ep
= strchr(dp
, '<')) != 0)
1504 rp
->r_dycode
= DC_DOWLEQ
;
1505 else if ((ep
= strchr(dp
, '>')) != 0)
1506 rp
->r_dycode
= DC_DOWGEQ
;
1509 rp
->r_dycode
= DC_DOM
;
1511 if (rp
->r_dycode
!= DC_DOM
) {
1514 error(_("invalid day of month"));
1518 if ((lp
= byword(dp
, wday_names
)) == NULL
) {
1519 error(_("invalid weekday name"));
1523 rp
->r_wday
= lp
->l_value
;
1525 if (sscanf(ep
, "%d%c", &rp
->r_dayofmonth
, &xs
) != 1 ||
1526 rp
->r_dayofmonth
<= 0 ||
1527 (rp
->r_dayofmonth
> len_months
[1][rp
->r_month
])) {
1528 error(_("invalid day of month"));
1537 convert(const int_fast32_t val
, char *const buf
)
1541 unsigned char *const b
= (unsigned char *) buf
;
1543 for (i
= 0, shift
= 24; i
< 4; ++i
, shift
-= 8)
1544 b
[i
] = val
>> shift
;
1548 convert64(const zic_t val
, char *const buf
)
1552 unsigned char *const b
= (unsigned char *) buf
;
1554 for (i
= 0, shift
= 56; i
< 8; ++i
, shift
-= 8)
1555 b
[i
] = val
>> shift
;
1559 puttzcode(const int_fast32_t val
, FILE *const fp
)
1564 fwrite(buf
, sizeof buf
, 1, fp
);
1568 puttzcode64(const zic_t val
, FILE *const fp
)
1572 convert64(val
, buf
);
1573 fwrite(buf
, sizeof buf
, 1, fp
);
1577 atcomp(const void *avp
, const void *bvp
)
1579 const zic_t a
= ((const struct attype
*) avp
)->at
;
1580 const zic_t b
= ((const struct attype
*) bvp
)->at
;
1582 return (a
< b
) ? -1 : (a
> b
);
1588 return INT32_MIN
<= x
&& x
<= INT32_MAX
;
1592 writezone(const char *const name
, const char *const string
, char version
)
1596 register int leapcnt32
, leapi32
;
1597 register int timecnt32
, timei32
;
1600 static const struct tzhead tzh0
;
1601 static struct tzhead tzh
;
1602 zic_t
*ats
= emalloc(size_product(timecnt
, sizeof *ats
+ 1));
1603 void *typesptr
= ats
+ timecnt
;
1604 unsigned char *types
= typesptr
;
1610 qsort(attypes
, timecnt
, sizeof *attypes
, atcomp
);
1620 while (fromi
< timecnt
&& attypes
[fromi
].at
< big_bang_time
)
1622 for ( ; fromi
< timecnt
; ++fromi
) {
1623 if (toi
> 1 && ((attypes
[fromi
].at
+
1624 gmtoffs
[attypes
[toi
- 1].type
]) <=
1625 (attypes
[toi
- 1].at
+
1626 gmtoffs
[attypes
[toi
- 2].type
]))) {
1627 attypes
[toi
- 1].type
=
1628 attypes
[fromi
].type
;
1632 attypes
[toi
- 1].type
!= attypes
[fromi
].type
)
1633 attypes
[toi
++] = attypes
[fromi
];
1637 if (noise
&& timecnt
> 1200)
1638 warning(_("pre-2014 clients may mishandle"
1639 " more than 1200 transition times"));
1643 for (i
= 0; i
< timecnt
; ++i
) {
1644 ats
[i
] = attypes
[i
].at
;
1645 types
[i
] = attypes
[i
].type
;
1648 ** Correct for leap seconds.
1650 for (i
= 0; i
< timecnt
; ++i
) {
1653 if (ats
[i
] > trans
[j
] - corr
[j
]) {
1654 ats
[i
] = tadd(ats
[i
], corr
[j
]);
1659 ** Figure out 32-bit-limited starts and counts.
1661 timecnt32
= timecnt
;
1663 leapcnt32
= leapcnt
;
1665 while (timecnt32
> 0 && !is32(ats
[timecnt32
- 1]))
1667 while (timecnt32
> 0 && !is32(ats
[timei32
])) {
1672 ** Output an INT32_MIN "transition" if appropriate; see below.
1674 if (timei32
> 0 && ats
[timei32
] > INT32_MIN
) {
1678 while (leapcnt32
> 0 && !is32(trans
[leapcnt32
- 1]))
1680 while (leapcnt32
> 0 && !is32(trans
[leapi32
])) {
1684 fullname
= relname(directory
, name
);
1686 ** Remove old file, if any, to snap links.
1688 if (itsdir(fullname
) <= 0 && remove(fullname
) != 0 && errno
!= ENOENT
) {
1689 const char *e
= strerror(errno
);
1691 fprintf(stderr
, _("%s: Can't remove %s: %s\n"),
1692 progname
, fullname
, e
);
1695 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1696 if (! mkdirs(fullname
))
1698 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1699 const char *e
= strerror(errno
);
1701 fprintf(stderr
, _("%s: Can't create %s: %s\n"),
1702 progname
, fullname
, e
);
1706 for (pass
= 1; pass
<= 2; ++pass
) {
1707 register int thistimei
, thistimecnt
;
1708 register int thisleapi
, thisleapcnt
;
1709 register int thistimelim
, thisleaplim
;
1710 int writetype
[TZ_MAX_TYPES
];
1711 int typemap
[TZ_MAX_TYPES
];
1712 register int thistypecnt
;
1713 char thischars
[TZ_MAX_CHARS
];
1715 int indmap
[TZ_MAX_CHARS
];
1718 thistimei
= timei32
;
1719 thistimecnt
= timecnt32
;
1720 thisleapi
= leapi32
;
1721 thisleapcnt
= leapcnt32
;
1724 thistimecnt
= timecnt
;
1726 thisleapcnt
= leapcnt
;
1728 thistimelim
= thistimei
+ thistimecnt
;
1729 thisleaplim
= thisleapi
+ thisleapcnt
;
1730 for (i
= 0; i
< typecnt
; ++i
)
1731 writetype
[i
] = thistimecnt
== timecnt
;
1732 if (thistimecnt
== 0) {
1734 ** No transition times fall in the current
1735 ** (32- or 64-bit) window.
1738 writetype
[typecnt
- 1] = true;
1740 for (i
= thistimei
- 1; i
< thistimelim
; ++i
)
1742 writetype
[types
[i
]] = true;
1744 ** For America/Godthab and Antarctica/Palmer
1747 writetype
[0] = true;
1749 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1751 ** For some pre-2011 systems: if the last-to-be-written
1752 ** standard (or daylight) type has an offset different from the
1753 ** most recently used offset,
1754 ** append an (unused) copy of the most recently used type
1755 ** (to help get global "altzone" and "timezone" variables
1759 register int mrudst
, mrustd
, hidst
, histd
, type
;
1761 hidst
= histd
= mrudst
= mrustd
= -1;
1762 for (i
= thistimei
; i
< thistimelim
; ++i
)
1763 if (isdsts
[types
[i
]])
1765 else mrustd
= types
[i
];
1766 for (i
= 0; i
< typecnt
; ++i
)
1772 if (hidst
>= 0 && mrudst
>= 0 && hidst
!= mrudst
&&
1773 gmtoffs
[hidst
] != gmtoffs
[mrudst
]) {
1774 isdsts
[mrudst
] = -1;
1775 type
= addtype(gmtoffs
[mrudst
],
1776 &chars
[abbrinds
[mrudst
]],
1781 writetype
[type
] = true;
1783 if (histd
>= 0 && mrustd
>= 0 && histd
!= mrustd
&&
1784 gmtoffs
[histd
] != gmtoffs
[mrustd
]) {
1785 isdsts
[mrustd
] = -1;
1786 type
= addtype(gmtoffs
[mrustd
],
1787 &chars
[abbrinds
[mrustd
]],
1792 writetype
[type
] = true;
1795 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1797 for (i
= 0; i
< typecnt
; ++i
)
1798 typemap
[i
] = writetype
[i
] ? thistypecnt
++ : -1;
1799 for (i
= 0; i
< sizeof indmap
/ sizeof indmap
[0]; ++i
)
1802 for (i
= 0; i
< typecnt
; ++i
) {
1803 register char * thisabbr
;
1807 if (indmap
[abbrinds
[i
]] >= 0)
1809 thisabbr
= &chars
[abbrinds
[i
]];
1810 for (j
= 0; j
< thischarcnt
; ++j
)
1811 if (strcmp(&thischars
[j
], thisabbr
) == 0)
1813 if (j
== thischarcnt
) {
1814 strcpy(&thischars
[(int) thischarcnt
],
1816 thischarcnt
+= strlen(thisabbr
) + 1;
1818 indmap
[abbrinds
[i
]] = j
;
1820 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
1822 strncpy(tzh
.tzh_magic
, TZ_MAGIC
, sizeof tzh
.tzh_magic
);
1823 tzh
.tzh_version
[0] = version
;
1824 convert(thistypecnt
, tzh
.tzh_ttisgmtcnt
);
1825 convert(thistypecnt
, tzh
.tzh_ttisstdcnt
);
1826 convert(thisleapcnt
, tzh
.tzh_leapcnt
);
1827 convert(thistimecnt
, tzh
.tzh_timecnt
);
1828 convert(thistypecnt
, tzh
.tzh_typecnt
);
1829 convert(thischarcnt
, tzh
.tzh_charcnt
);
1840 for (i
= thistimei
; i
< thistimelim
; ++i
)
1843 ** Output an INT32_MIN "transition"
1844 ** if appropriate; see above.
1846 puttzcode(((ats
[i
] < INT32_MIN
) ?
1847 INT32_MIN
: ats
[i
]), fp
);
1848 else puttzcode64(ats
[i
], fp
);
1849 for (i
= thistimei
; i
< thistimelim
; ++i
) {
1852 uc
= typemap
[types
[i
]];
1853 fwrite(&uc
, sizeof uc
, 1, fp
);
1855 for (i
= 0; i
< typecnt
; ++i
)
1857 puttzcode(gmtoffs
[i
], fp
);
1858 putc(isdsts
[i
], fp
);
1859 putc((unsigned char) indmap
[abbrinds
[i
]], fp
);
1861 if (thischarcnt
!= 0)
1862 fwrite(thischars
, sizeof thischars
[0],
1864 for (i
= thisleapi
; i
< thisleaplim
; ++i
) {
1865 register zic_t todo
;
1868 if (timecnt
== 0 || trans
[i
] < ats
[0]) {
1871 if (++j
>= typecnt
) {
1877 while (j
< timecnt
&&
1882 todo
= tadd(trans
[i
], -gmtoffs
[j
]);
1883 } else todo
= trans
[i
];
1885 puttzcode(todo
, fp
);
1886 else puttzcode64(todo
, fp
);
1887 puttzcode(corr
[i
], fp
);
1889 for (i
= 0; i
< typecnt
; ++i
)
1891 putc(ttisstds
[i
], fp
);
1892 for (i
= 0; i
< typecnt
; ++i
)
1894 putc(ttisgmts
[i
], fp
);
1896 fprintf(fp
, "\n%s\n", string
);
1897 close_file(fp
, fullname
);
1903 abbroffset(char *buf
, zic_t offset
)
1906 int seconds
, minutes
;
1913 seconds
= offset
% SECSPERMIN
;
1914 offset
/= SECSPERMIN
;
1915 minutes
= offset
% MINSPERHOUR
;
1916 offset
/= MINSPERHOUR
;
1917 if (100 <= offset
) {
1918 error(_("%%z UTC offset magnitude exceeds 99:59:59"));
1923 *p
++ = '0' + offset
/ 10;
1924 *p
++ = '0' + offset
% 10;
1925 if (minutes
| seconds
) {
1926 *p
++ = '0' + minutes
/ 10;
1927 *p
++ = '0' + minutes
% 10;
1929 *p
++ = '0' + seconds
/ 10;
1930 *p
++ = '0' + seconds
% 10;
1939 doabbr(char *abbr
, struct zone
const *zp
, char const *letters
,
1940 zic_t stdoff
, bool doquotes
)
1943 register char * slashp
;
1944 register size_t len
;
1945 char const *format
= zp
->z_format
;
1947 slashp
= strchr(format
, '/');
1948 if (slashp
== NULL
) {
1949 char letterbuf
[PERCENT_Z_LEN_BOUND
+ 1];
1950 if (zp
->z_format_specifier
== 'z')
1951 letters
= abbroffset(letterbuf
, zp
->z_gmtoff
+ stdoff
);
1954 sprintf(abbr
, format
, letters
);
1955 } else if (stdoff
!= 0) {
1956 strcpy(abbr
, slashp
+ 1);
1958 memcpy(abbr
, format
, slashp
- format
);
1959 abbr
[slashp
- format
] = '\0';
1964 for (cp
= abbr
; is_alpha(*cp
); cp
++)
1966 if (len
> 0 && *cp
== '\0')
1968 abbr
[len
+ 2] = '\0';
1969 abbr
[len
+ 1] = '>';
1970 memmove(abbr
+ 1, abbr
, len
);
1976 updateminmax(const zic_t x
)
1985 stringoffset(char *result
, zic_t offset
)
1988 register int minutes
;
1989 register int seconds
;
1990 bool negative
= offset
< 0;
1997 seconds
= offset
% SECSPERMIN
;
1998 offset
/= SECSPERMIN
;
1999 minutes
= offset
% MINSPERHOUR
;
2000 offset
/= MINSPERHOUR
;
2002 if (hours
>= HOURSPERDAY
* DAYSPERWEEK
) {
2006 len
+= sprintf(result
+ len
, "%d", hours
);
2007 if (minutes
!= 0 || seconds
!= 0) {
2008 len
+= sprintf(result
+ len
, ":%02d", minutes
);
2010 len
+= sprintf(result
+ len
, ":%02d", seconds
);
2016 stringrule(char *result
, const struct rule
*const rp
, const zic_t dstoff
,
2019 register zic_t tod
= rp
->r_tod
;
2020 register int compat
= 0;
2022 if (rp
->r_dycode
== DC_DOM
) {
2023 register int month
, total
;
2025 if (rp
->r_dayofmonth
== 29 && rp
->r_month
== TM_FEBRUARY
)
2028 for (month
= 0; month
< rp
->r_month
; ++month
)
2029 total
+= len_months
[0][month
];
2030 /* Omit the "J" in Jan and Feb, as that's shorter. */
2031 if (rp
->r_month
<= 1)
2032 result
+= sprintf(result
, "%d", total
+ rp
->r_dayofmonth
- 1);
2034 result
+= sprintf(result
, "J%d", total
+ rp
->r_dayofmonth
);
2037 register int wday
= rp
->r_wday
;
2038 register int wdayoff
;
2040 if (rp
->r_dycode
== DC_DOWGEQ
) {
2041 wdayoff
= (rp
->r_dayofmonth
- 1) % DAYSPERWEEK
;
2045 tod
+= wdayoff
* SECSPERDAY
;
2046 week
= 1 + (rp
->r_dayofmonth
- 1) / DAYSPERWEEK
;
2047 } else if (rp
->r_dycode
== DC_DOWLEQ
) {
2048 if (rp
->r_dayofmonth
== len_months
[1][rp
->r_month
])
2051 wdayoff
= rp
->r_dayofmonth
% DAYSPERWEEK
;
2055 tod
+= wdayoff
* SECSPERDAY
;
2056 week
= rp
->r_dayofmonth
/ DAYSPERWEEK
;
2058 } else return -1; /* "cannot happen" */
2060 wday
+= DAYSPERWEEK
;
2061 result
+= sprintf(result
, "M%d.%d.%d",
2062 rp
->r_month
+ 1, week
, wday
);
2066 if (rp
->r_todisstd
&& rp
->r_stdoff
== 0)
2068 if (tod
!= 2 * SECSPERMIN
* MINSPERHOUR
) {
2070 if (! stringoffset(result
, tod
))
2075 } else if (SECSPERDAY
<= tod
) {
2084 rule_cmp(struct rule
const *a
, struct rule
const *b
)
2090 if (a
->r_hiyear
!= b
->r_hiyear
)
2091 return a
->r_hiyear
< b
->r_hiyear
? -1 : 1;
2092 if (a
->r_month
- b
->r_month
!= 0)
2093 return a
->r_month
- b
->r_month
;
2094 return a
->r_dayofmonth
- b
->r_dayofmonth
;
2097 enum { YEAR_BY_YEAR_ZONE
= 1 };
2100 stringzone(char *result
, const struct zone
*const zpfirst
, const int zonecount
)
2102 register const struct zone
* zp
;
2103 register struct rule
* rp
;
2104 register struct rule
* stdrp
;
2105 register struct rule
* dstrp
;
2107 register const char * abbrvar
;
2108 register int compat
= 0;
2112 struct rule stdr
, dstr
;
2115 zp
= zpfirst
+ zonecount
- 1;
2116 stdrp
= dstrp
= NULL
;
2117 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2118 rp
= &zp
->z_rules
[i
];
2119 if (rp
->r_hiwasnum
|| rp
->r_hiyear
!= ZIC_MAX
)
2121 if (rp
->r_yrtype
!= NULL
)
2123 if (rp
->r_stdoff
== 0) {
2133 if (stdrp
== NULL
&& dstrp
== NULL
) {
2135 ** There are no rules running through "max".
2136 ** Find the latest std rule in stdabbrrp
2137 ** and latest rule of any type in stdrp.
2139 register struct rule
*stdabbrrp
= NULL
;
2140 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2141 rp
= &zp
->z_rules
[i
];
2142 if (rp
->r_stdoff
== 0 && rule_cmp(stdabbrrp
, rp
) < 0)
2144 if (rule_cmp(stdrp
, rp
) < 0)
2148 ** Horrid special case: if year is 2037,
2149 ** presume this is a zone handled on a year-by-year basis;
2150 ** do not try to apply a rule to the zone.
2152 if (stdrp
!= NULL
&& stdrp
->r_hiyear
== 2037)
2153 return YEAR_BY_YEAR_ZONE
;
2155 if (stdrp
!= NULL
&& stdrp
->r_stdoff
!= 0) {
2156 /* Perpetual DST. */
2157 dstr
.r_month
= TM_JANUARY
;
2158 dstr
.r_dycode
= DC_DOM
;
2159 dstr
.r_dayofmonth
= 1;
2161 dstr
.r_todisstd
= dstr
.r_todisgmt
= false;
2162 dstr
.r_stdoff
= stdrp
->r_stdoff
;
2163 dstr
.r_abbrvar
= stdrp
->r_abbrvar
;
2164 stdr
.r_month
= TM_DECEMBER
;
2165 stdr
.r_dycode
= DC_DOM
;
2166 stdr
.r_dayofmonth
= 31;
2167 stdr
.r_tod
= SECSPERDAY
+ stdrp
->r_stdoff
;
2168 stdr
.r_todisstd
= stdr
.r_todisgmt
= false;
2171 = (stdabbrrp
? stdabbrrp
->r_abbrvar
: "");
2176 if (stdrp
== NULL
&& (zp
->z_nrules
!= 0 || zp
->z_stdoff
!= 0))
2178 abbrvar
= (stdrp
== NULL
) ? "" : stdrp
->r_abbrvar
;
2179 len
= doabbr(result
, zp
, abbrvar
, 0, true);
2180 offsetlen
= stringoffset(result
+ len
, -zp
->z_gmtoff
);
2188 len
+= doabbr(result
+ len
, zp
, dstrp
->r_abbrvar
, dstrp
->r_stdoff
, true);
2189 if (dstrp
->r_stdoff
!= SECSPERMIN
* MINSPERHOUR
) {
2190 offsetlen
= stringoffset(result
+ len
,
2191 -(zp
->z_gmtoff
+ dstrp
->r_stdoff
));
2198 result
[len
++] = ',';
2199 c
= stringrule(result
+ len
, dstrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2206 len
+= strlen(result
+ len
);
2207 result
[len
++] = ',';
2208 c
= stringrule(result
+ len
, stdrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2219 outzone(const struct zone
*zpfirst
, int zonecount
)
2221 register const struct zone
* zp
;
2222 register struct rule
* rp
;
2224 register bool usestart
, useuntil
;
2225 register zic_t starttime
, untiltime
;
2226 register zic_t gmtoff
;
2227 register zic_t stdoff
;
2228 register zic_t year
;
2229 register zic_t startoff
;
2230 register bool startttisstd
;
2231 register bool startttisgmt
;
2233 register char * startbuf
;
2235 register char * envvar
;
2236 register int max_abbr_len
;
2237 register int max_envvar_len
;
2238 register bool prodstic
; /* all rules are min to max */
2239 register int compat
;
2240 register bool do_extend
;
2241 register char version
;
2243 max_abbr_len
= 2 + max_format_len
+ max_abbrvar_len
;
2244 max_envvar_len
= 2 * max_abbr_len
+ 5 * 9;
2245 startbuf
= emalloc(max_abbr_len
+ 1);
2246 ab
= emalloc(max_abbr_len
+ 1);
2247 envvar
= emalloc(max_envvar_len
+ 1);
2248 INITIALIZE(untiltime
);
2249 INITIALIZE(starttime
);
2251 ** Now. . .finally. . .generate some useful data!
2256 prodstic
= zonecount
== 1;
2258 ** Thanks to Earl Chew
2259 ** for noting the need to unconditionally initialize startttisstd.
2261 startttisstd
= false;
2262 startttisgmt
= false;
2263 min_year
= max_year
= EPOCH_YEAR
;
2265 updateminmax(leapminyear
);
2266 updateminmax(leapmaxyear
+ (leapmaxyear
< ZIC_MAX
));
2268 for (i
= 0; i
< zonecount
; ++i
) {
2270 if (i
< zonecount
- 1)
2271 updateminmax(zp
->z_untilrule
.r_loyear
);
2272 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2273 rp
= &zp
->z_rules
[j
];
2275 updateminmax(rp
->r_loyear
);
2277 updateminmax(rp
->r_hiyear
);
2278 if (rp
->r_lowasnum
|| rp
->r_hiwasnum
)
2283 ** Generate lots of data if a rule can't cover all future times.
2285 compat
= stringzone(envvar
, zpfirst
, zonecount
);
2286 version
= compat
< 2013 ? ZIC_VERSION_PRE_2013
: ZIC_VERSION
;
2287 do_extend
= compat
< 0 || compat
== YEAR_BY_YEAR_ZONE
;
2291 _("no POSIX environment variable for zone"),
2293 else if (compat
!= 0 && compat
!= YEAR_BY_YEAR_ZONE
) {
2294 /* Circa-COMPAT clients, and earlier clients, might
2295 not work for this zone when given dates before
2296 1970 or after 2038. */
2297 warning(_("%s: pre-%d clients may mishandle"
2298 " distant timestamps"),
2299 zpfirst
->z_name
, compat
);
2304 ** Search through a couple of extra years past the obvious
2305 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2306 ** rule applies from 2012 onwards and has transitions in March
2307 ** and September, plus some one-off transitions in November
2308 ** 2013. If zic looked only at the last 400 years, it would
2309 ** set max_year=2413, with the intent that the 400 years 2014
2310 ** through 2413 will be repeated. The last transition listed
2311 ** in the tzfile would be in 2413-09, less than 400 years
2312 ** after the last one-off transition in 2013-11. Two years
2313 ** might be overkill, but with the kind of edge cases
2314 ** available we're not sure that one year would suffice.
2316 enum { years_of_observations
= YEARSPERREPEAT
+ 2 };
2318 if (min_year
>= ZIC_MIN
+ years_of_observations
)
2319 min_year
-= years_of_observations
;
2320 else min_year
= ZIC_MIN
;
2321 if (max_year
<= ZIC_MAX
- years_of_observations
)
2322 max_year
+= years_of_observations
;
2323 else max_year
= ZIC_MAX
;
2325 ** Regardless of any of the above,
2326 ** for a "proDSTic" zone which specifies that its rules
2327 ** always have and always will be in effect,
2328 ** we only need one cycle to define the zone.
2332 max_year
= min_year
+ years_of_observations
;
2336 ** For the benefit of older systems,
2337 ** generate data from 1900 through 2037.
2339 if (min_year
> 1900)
2341 if (max_year
< 2037)
2343 for (i
= 0; i
< zonecount
; ++i
) {
2345 ** A guess that may well be corrected later.
2349 usestart
= i
> 0 && (zp
- 1)->z_untiltime
> big_bang_time
;
2350 useuntil
= i
< (zonecount
- 1);
2351 if (useuntil
&& zp
->z_untiltime
<= big_bang_time
)
2353 gmtoff
= zp
->z_gmtoff
;
2354 eat(zp
->z_filename
, zp
->z_linenum
);
2356 startoff
= zp
->z_gmtoff
;
2357 if (zp
->z_nrules
== 0) {
2358 stdoff
= zp
->z_stdoff
;
2359 doabbr(startbuf
, zp
, NULL
, stdoff
, false);
2360 type
= addtype(oadd(zp
->z_gmtoff
, stdoff
),
2361 startbuf
, stdoff
!= 0, startttisstd
,
2364 addtt(starttime
, type
);
2366 } else addtt(big_bang_time
, type
);
2367 } else for (year
= min_year
; year
<= max_year
; ++year
) {
2368 if (useuntil
&& year
> zp
->z_untilrule
.r_hiyear
)
2371 ** Mark which rules to do in the current year.
2372 ** For those to do, calculate rpytime(rp, year);
2374 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2375 rp
= &zp
->z_rules
[j
];
2376 eats(zp
->z_filename
, zp
->z_linenum
,
2377 rp
->r_filename
, rp
->r_linenum
);
2378 rp
->r_todo
= year
>= rp
->r_loyear
&&
2379 year
<= rp
->r_hiyear
&&
2380 yearistype(year
, rp
->r_yrtype
);
2382 rp
->r_temp
= rpytime(rp
, year
);
2386 register zic_t jtime
, ktime
;
2387 register zic_t offset
;
2392 ** Turn untiltime into UT
2393 ** assuming the current gmtoff and
2396 untiltime
= zp
->z_untiltime
;
2397 if (!zp
->z_untilrule
.r_todisgmt
)
2398 untiltime
= tadd(untiltime
,
2400 if (!zp
->z_untilrule
.r_todisstd
)
2401 untiltime
= tadd(untiltime
,
2405 ** Find the rule (of those to do, if any)
2406 ** that takes effect earliest in the year.
2409 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2410 rp
= &zp
->z_rules
[j
];
2413 eats(zp
->z_filename
, zp
->z_linenum
,
2414 rp
->r_filename
, rp
->r_linenum
);
2415 offset
= rp
->r_todisgmt
? 0 : gmtoff
;
2416 if (!rp
->r_todisstd
)
2417 offset
= oadd(offset
, stdoff
);
2419 if (jtime
== min_time
||
2422 jtime
= tadd(jtime
, -offset
);
2423 if (k
< 0 || jtime
< ktime
) {
2426 } else if (jtime
== ktime
) {
2427 char const *dup_rules_msg
=
2428 _("two rules for same instant");
2429 eats(zp
->z_filename
, zp
->z_linenum
,
2430 rp
->r_filename
, rp
->r_linenum
);
2431 warning("%s", dup_rules_msg
);
2432 rp
= &zp
->z_rules
[k
];
2433 eats(zp
->z_filename
, zp
->z_linenum
,
2434 rp
->r_filename
, rp
->r_linenum
);
2435 error("%s", dup_rules_msg
);
2439 break; /* go on to next year */
2440 rp
= &zp
->z_rules
[k
];
2442 if (useuntil
&& ktime
>= untiltime
)
2444 stdoff
= rp
->r_stdoff
;
2445 if (usestart
&& ktime
== starttime
)
2448 if (ktime
< starttime
) {
2449 startoff
= oadd(zp
->z_gmtoff
,
2451 doabbr(startbuf
, zp
,
2457 if (*startbuf
== '\0' &&
2458 startoff
== oadd(zp
->z_gmtoff
,
2467 eats(zp
->z_filename
, zp
->z_linenum
,
2468 rp
->r_filename
, rp
->r_linenum
);
2469 doabbr(ab
, zp
, rp
->r_abbrvar
,
2470 rp
->r_stdoff
, false);
2471 offset
= oadd(zp
->z_gmtoff
, rp
->r_stdoff
);
2472 type
= addtype(offset
, ab
, rp
->r_stdoff
!= 0,
2473 rp
->r_todisstd
, rp
->r_todisgmt
);
2478 if (*startbuf
== '\0' &&
2479 zp
->z_format
!= NULL
&&
2480 strchr(zp
->z_format
, '%') == NULL
&&
2481 strchr(zp
->z_format
, '/') == NULL
)
2482 strcpy(startbuf
, zp
->z_format
);
2483 eat(zp
->z_filename
, zp
->z_linenum
);
2484 if (*startbuf
== '\0')
2485 error(_("can't determine time zone abbreviation to use just after until time"));
2486 else addtt(starttime
,
2487 addtype(startoff
, startbuf
,
2488 startoff
!= zp
->z_gmtoff
,
2493 ** Now we may get to set starttime for the next zone line.
2496 startttisstd
= zp
->z_untilrule
.r_todisstd
;
2497 startttisgmt
= zp
->z_untilrule
.r_todisgmt
;
2498 starttime
= zp
->z_untiltime
;
2500 starttime
= tadd(starttime
, -stdoff
);
2502 starttime
= tadd(starttime
, -gmtoff
);
2507 ** If we're extending the explicitly listed observations
2508 ** for 400 years because we can't fill the POSIX-TZ field,
2509 ** check whether we actually ended up explicitly listing
2510 ** observations through that period. If there aren't any
2511 ** near the end of the 400-year period, add a redundant
2512 ** one at the end of the final year, to make it clear
2513 ** that we are claiming to have definite knowledge of
2514 ** the lack of transitions up to that point.
2517 struct attype
*lastat
;
2518 xr
.r_month
= TM_JANUARY
;
2519 xr
.r_dycode
= DC_DOM
;
2520 xr
.r_dayofmonth
= 1;
2522 for (lastat
= &attypes
[0], i
= 1; i
< timecnt
; i
++)
2523 if (attypes
[i
].at
> lastat
->at
)
2524 lastat
= &attypes
[i
];
2525 if (lastat
->at
< rpytime(&xr
, max_year
- 1)) {
2527 ** Create new type code for the redundant entry,
2528 ** to prevent it being optimized away.
2530 if (typecnt
>= TZ_MAX_TYPES
) {
2531 error(_("too many local time types"));
2534 gmtoffs
[typecnt
] = gmtoffs
[lastat
->type
];
2535 isdsts
[typecnt
] = isdsts
[lastat
->type
];
2536 ttisstds
[typecnt
] = ttisstds
[lastat
->type
];
2537 ttisgmts
[typecnt
] = ttisgmts
[lastat
->type
];
2538 abbrinds
[typecnt
] = abbrinds
[lastat
->type
];
2540 addtt(rpytime(&xr
, max_year
+ 1), typecnt
-1);
2543 writezone(zpfirst
->z_name
, envvar
, version
);
2550 addtt(zic_t starttime
, int type
)
2552 if (starttime
<= big_bang_time
||
2553 (timecnt
== 1 && attypes
[0].at
< big_bang_time
)) {
2554 gmtoffs
[0] = gmtoffs
[type
];
2555 isdsts
[0] = isdsts
[type
];
2556 ttisstds
[0] = ttisstds
[type
];
2557 ttisgmts
[0] = ttisgmts
[type
];
2558 if (abbrinds
[type
] != 0)
2559 strcpy(chars
, &chars
[abbrinds
[type
]]);
2561 charcnt
= strlen(chars
) + 1;
2566 attypes
= growalloc(attypes
, sizeof *attypes
, timecnt
, &timecnt_alloc
);
2567 attypes
[timecnt
].at
= starttime
;
2568 attypes
[timecnt
].type
= type
;
2573 addtype(zic_t gmtoff
, char const *abbr
, bool isdst
, bool ttisstd
, bool ttisgmt
)
2578 ** See if there's already an entry for this zone type.
2579 ** If so, just return its index.
2581 for (i
= 0; i
< typecnt
; ++i
) {
2582 if (gmtoff
== gmtoffs
[i
] && isdst
== isdsts
[i
] &&
2583 strcmp(abbr
, &chars
[abbrinds
[i
]]) == 0 &&
2584 ttisstd
== ttisstds
[i
] &&
2585 ttisgmt
== ttisgmts
[i
])
2589 ** There isn't one; add a new one, unless there are already too
2592 if (typecnt
>= TZ_MAX_TYPES
) {
2593 error(_("too many local time types"));
2596 if (! (-1L - 2147483647L <= gmtoff
&& gmtoff
<= 2147483647L)) {
2597 error(_("UT offset out of range"));
2600 gmtoffs
[i
] = gmtoff
;
2602 ttisstds
[i
] = ttisstd
;
2603 ttisgmts
[i
] = ttisgmt
;
2605 for (j
= 0; j
< charcnt
; ++j
)
2606 if (strcmp(&chars
[j
], abbr
) == 0)
2616 leapadd(zic_t t
, bool positive
, int rolling
, int count
)
2620 if (leapcnt
+ (positive
? count
: 1) > TZ_MAX_LEAPS
) {
2621 error(_("too many leap seconds"));
2624 for (i
= 0; i
< leapcnt
; ++i
)
2625 if (t
<= trans
[i
]) {
2626 if (t
== trans
[i
]) {
2627 error(_("repeated leap second moment"));
2633 for (j
= leapcnt
; j
> i
; --j
) {
2634 trans
[j
] = trans
[j
- 1];
2635 corr
[j
] = corr
[j
- 1];
2636 roll
[j
] = roll
[j
- 1];
2639 corr
[i
] = positive
? 1 : -count
;
2642 } while (positive
&& --count
!= 0);
2649 register zic_t last
= 0;
2652 ** propagate leap seconds forward
2654 for (i
= 0; i
< leapcnt
; ++i
) {
2655 trans
[i
] = tadd(trans
[i
], last
);
2656 last
= corr
[i
] += last
;
2661 yearistype(int year
, const char *type
)
2666 if (type
== NULL
|| *type
== '\0')
2668 buf
= erealloc(buf
, 132 + strlen(yitcommand
) + strlen(type
));
2669 sprintf(buf
, "%s %d %s", yitcommand
, year
, type
);
2670 result
= system(buf
);
2671 if (WIFEXITED(result
)) switch (WEXITSTATUS(result
)) {
2677 error(_("Wild result from command execution"));
2678 fprintf(stderr
, _("%s: command was '%s', result was %d\n"),
2679 progname
, buf
, result
);
2684 /* Is A a space character in the C locale? */
2691 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2696 /* Is A an alphabetic character in the C locale? */
2703 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2704 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2705 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2706 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2707 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2708 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2709 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2710 case 'v': case 'w': case 'x': case 'y': case 'z':
2715 /* If A is an uppercase character in the C locale, return its lowercase
2716 counterpart. Otherwise, return A. */
2722 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2723 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2724 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2725 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2726 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2727 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2728 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2729 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2730 case 'Y': return 'y'; case 'Z': return 'z';
2734 /* case-insensitive equality */
2735 static ATTRIBUTE_PURE
bool
2736 ciequal(register const char *ap
, register const char *bp
)
2738 while (lowerit(*ap
) == lowerit(*bp
++))
2744 static ATTRIBUTE_PURE
bool
2745 itsabbr(register const char *abbr
, register const char *word
)
2747 if (lowerit(*abbr
) != lowerit(*word
))
2750 while (*++abbr
!= '\0')
2754 } while (lowerit(*word
++) != lowerit(*abbr
));
2758 static ATTRIBUTE_PURE
const struct lookup
*
2759 byword(const char *word
, const struct lookup
*table
)
2761 register const struct lookup
* foundlp
;
2762 register const struct lookup
* lp
;
2764 if (word
== NULL
|| table
== NULL
)
2767 ** Look for exact match.
2769 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2770 if (ciequal(word
, lp
->l_word
))
2773 ** Look for inexact match.
2776 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2777 if (itsabbr(word
, lp
->l_word
)) {
2778 if (foundlp
== NULL
)
2780 else return NULL
; /* multiple inexact matches */
2786 getfields(register char *cp
)
2789 register char ** array
;
2794 array
= emalloc(size_product(strlen(cp
) + 1, sizeof *array
));
2797 while (is_space(*cp
))
2799 if (*cp
== '\0' || *cp
== '#')
2801 array
[nsubs
++] = dp
= cp
;
2803 if ((*dp
= *cp
++) != '"')
2805 else while ((*dp
= *cp
++) != '"')
2810 "Odd number of quotation marks"
2814 } while (*cp
&& *cp
!= '#' && !is_space(*cp
));
2819 array
[nsubs
] = NULL
;
2823 static _Noreturn
void
2826 error(_("time overflow"));
2830 static ATTRIBUTE_PURE zic_t
2831 oadd(zic_t t1
, zic_t t2
)
2833 if (t1
< 0 ? t2
< ZIC_MIN
- t1
: ZIC_MAX
- t1
< t2
)
2838 static ATTRIBUTE_PURE zic_t
2839 tadd(zic_t t1
, zic_t t2
)
2842 if (t2
< min_time
- t1
) {
2848 if (max_time
- t1
< t2
) {
2858 ** Given a rule, and a year, compute the date (in seconds since January 1,
2859 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
2863 rpytime(const struct rule
*rp
, zic_t wantedy
)
2866 register zic_t dayoff
; /* with a nod to Margaret O. */
2867 register zic_t t
, y
;
2869 if (wantedy
== ZIC_MIN
)
2871 if (wantedy
== ZIC_MAX
)
2876 while (wantedy
!= y
) {
2878 i
= len_years
[isleap(y
)];
2882 i
= -len_years
[isleap(y
)];
2884 dayoff
= oadd(dayoff
, i
);
2886 while (m
!= rp
->r_month
) {
2887 i
= len_months
[isleap(y
)][m
];
2888 dayoff
= oadd(dayoff
, i
);
2891 i
= rp
->r_dayofmonth
;
2892 if (m
== TM_FEBRUARY
&& i
== 29 && !isleap(y
)) {
2893 if (rp
->r_dycode
== DC_DOWLEQ
)
2896 error(_("use of 2/29 in non leap-year"));
2901 dayoff
= oadd(dayoff
, i
);
2902 if (rp
->r_dycode
== DC_DOWGEQ
|| rp
->r_dycode
== DC_DOWLEQ
) {
2903 register zic_t wday
;
2905 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
2908 ** Don't trust mod of negative numbers.
2911 wday
= (wday
+ dayoff
) % LDAYSPERWEEK
;
2913 wday
-= ((-dayoff
) % LDAYSPERWEEK
);
2915 wday
+= LDAYSPERWEEK
;
2917 while (wday
!= rp
->r_wday
)
2918 if (rp
->r_dycode
== DC_DOWGEQ
) {
2919 dayoff
= oadd(dayoff
, 1);
2920 if (++wday
>= LDAYSPERWEEK
)
2924 dayoff
= oadd(dayoff
, -1);
2926 wday
= LDAYSPERWEEK
- 1;
2929 if (i
< 0 || i
>= len_months
[isleap(y
)][m
]) {
2931 warning(_("rule goes past start/end of month; \
2932 will not work with pre-2004 versions of zic"));
2935 if (dayoff
< min_time
/ SECSPERDAY
)
2937 if (dayoff
> max_time
/ SECSPERDAY
)
2939 t
= (zic_t
) dayoff
* SECSPERDAY
;
2940 return tadd(t
, rp
->r_tod
);
2944 newabbr(const char *string
)
2948 if (strcmp(string
, GRANDPARENTED
) != 0) {
2949 register const char * cp
;
2954 while (is_alpha(*cp
) || ('0' <= *cp
&& *cp
<= '9')
2955 || *cp
== '-' || *cp
== '+')
2957 if (noise
&& cp
- string
< 3)
2958 mp
= _("time zone abbreviation has fewer than 3 characters");
2959 if (cp
- string
> ZIC_MAX_ABBR_LEN_WO_WARN
)
2960 mp
= _("time zone abbreviation has too many characters");
2962 mp
= _("time zone abbreviation differs from POSIX standard");
2964 warning("%s (%s)", mp
, string
);
2966 i
= strlen(string
) + 1;
2967 if (charcnt
+ i
> TZ_MAX_CHARS
) {
2968 error(_("too many, or too long, time zone abbreviations"));
2971 strcpy(&chars
[charcnt
], string
);
2976 mkdirs(char *argname
)
2978 register char * name
;
2981 if (argname
== NULL
|| *argname
== '\0')
2983 cp
= name
= ecpyalloc(argname
);
2984 while ((cp
= strchr(cp
+ 1, '/')) != 0) {
2986 #ifdef HAVE_DOS_FILE_NAMES
2988 ** DOS drive specifier?
2990 if (is_alpha(name
[0]) && name
[1] == ':' && name
[2] == '\0') {
2996 ** Try to create it. It's OK if creation fails because
2997 ** the directory already exists, perhaps because some
2998 ** other process just created it.
3000 if (mkdir(name
, MKDIR_UMASK
) != 0) {
3002 if (itsdir(name
) <= 0) {
3003 char const *e
= strerror(err
);
3004 warning(_("%s: Can't create directory"