1 /* $NetBSD: zic.c,v 1.56 2015/10/09 17:21:45 christos Exp $ */
3 ** This file is in the public domain, so clarified as of
4 ** 2006-07-17 by Arthur David Olson.
7 #if HAVE_NBTOOL_CONFIG_H
8 #include "nbtool_config.h"
11 #include <sys/cdefs.h>
13 __RCSID("$NetBSD: zic.c,v 1.56 2015/10/09 17:21:45 christos Exp $");
14 #endif /* !defined lint */
23 #define ZIC_VERSION_PRE_2013 '2'
24 #define ZIC_VERSION '3'
26 typedef int_fast64_t zic_t
;
27 #define ZIC_MIN INT_FAST64_MIN
28 #define ZIC_MAX INT_FAST64_MAX
29 #define SCNdZIC SCNdFAST64
31 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
32 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
33 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
39 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
41 #define MKDIR_UMASK 0755
45 const char * r_filename
;
49 zic_t r_loyear
; /* for example, 1986 */
50 zic_t r_hiyear
; /* for example, 1986 */
51 const char * r_yrtype
;
55 int r_month
; /* 0..11 */
57 int r_dycode
; /* see below */
61 zic_t r_tod
; /* time from midnight */
62 bool r_todisstd
; /* above is standard time if 1 */
63 /* or wall clock time if 0 */
64 bool r_todisgmt
; /* above is GMT if 1 */
65 /* or local time if 0 */
66 zic_t r_stdoff
; /* offset from standard time */
67 const char * r_abbrvar
; /* variable part of abbreviation */
69 int r_todo
; /* a rule to do (used in outzone) */
70 zic_t r_temp
; /* used in outzone */
74 ** r_dycode r_dayofmonth r_wday
77 #define DC_DOM 0 /* 1..31 */ /* unused */
78 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
79 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
82 const char * z_filename
;
88 const char * z_format
;
89 char z_format_specifier
;
93 struct rule
* z_rules
;
96 struct rule z_untilrule
;
100 extern int getopt(int argc
, char * const argv
[],
101 const char * options
);
102 extern int link(const char * fromname
, const char * toname
);
103 extern char * optarg
;
107 # define link(from, to) (-1)
110 # define symlink(from, to) (-1)
113 static void addtt(zic_t starttime
, int type
);
114 static int addtype(zic_t
, char * const, bool, bool, bool);
115 static void leapadd(zic_t
, bool, int, int);
116 static void adjleap(void);
117 static void associate(void);
118 static void dolink(const char * fromfield
, const char * tofield
);
119 static char ** getfields(char * buf
);
120 static zic_t
gethms(const char * string
, const char * errstring
,
122 static void infile(const char * filename
);
123 static void inleap(char ** fields
, int nfields
);
124 static void inlink(char ** fields
, int nfields
);
125 static void inrule(char ** fields
, int nfields
);
126 static bool inzcont(char ** fields
, int nfields
);
127 static bool inzone(char ** fields
, int nfields
);
128 static bool inzsub(char ** fields
, int nfields
, int iscont
);
129 static int itsdir(const char * name
);
130 static bool is_alpha(char a
);
131 static char lowerit(char);
132 static bool mkdirs(char * filename
);
133 static void newabbr(const char * abbr
);
134 static zic_t
oadd(zic_t t1
, zic_t t2
);
135 static void outzone(const struct zone
* zp
, int ntzones
);
136 static int rcomp(const void * leftp
, const void * rightp
);
137 static zic_t
rpytime(const struct rule
* rp
, zic_t wantedy
);
138 static void rulesub(struct rule
* rp
,
139 const char * loyearp
, const char * hiyearp
,
140 const char * typep
, const char * monthp
,
141 const char * dayp
, const char * timep
);
142 static zic_t
tadd(zic_t t1
, zic_t t2
);
143 static bool yearistype(int year
, const char * type
);
144 static int atcomp(const void *avp
, const void *bvp
);
145 static void updateminmax(zic_t x
);
147 /* Bound on length of what %z can expand to. */
148 enum { PERCENT_Z_LEN_BOUND
= sizeof "+995959" - 1 };
152 static bool warnings
;
153 static const char * filename
;
155 static bool leapseen
;
156 static zic_t leapminyear
;
157 static zic_t leapmaxyear
;
159 static size_t max_abbrvar_len
= PERCENT_Z_LEN_BOUND
;
160 static size_t max_format_len
;
161 static zic_t max_year
;
162 static zic_t min_year
;
164 static const char * rfilename
;
166 static const char * progname
;
168 static int timecnt_alloc
;
181 ** Which fields are which on a Zone line.
189 #define ZF_TILMONTH 6
192 #define ZONE_MINFIELDS 5
193 #define ZONE_MAXFIELDS 9
196 ** Which fields are which on a Zone continuation line.
202 #define ZFC_TILYEAR 3
203 #define ZFC_TILMONTH 4
205 #define ZFC_TILTIME 6
206 #define ZONEC_MINFIELDS 3
207 #define ZONEC_MAXFIELDS 7
210 ** Which files are which on a Rule line.
222 #define RULE_FIELDS 10
225 ** Which fields are which on a Link line.
230 #define LINK_FIELDS 3
233 ** Which fields are which on a Leap line.
242 #define LEAP_FIELDS 7
252 static struct rule
* rules
;
253 static int nrules
; /* number of rules */
254 static int nrules_alloc
;
256 static struct zone
* zones
;
257 static int nzones
; /* number of zones */
258 static int nzones_alloc
;
261 const char * l_filename
;
267 static struct link
* links
;
269 static int nlinks_alloc
;
276 static struct lookup
const * byword(const char * string
,
277 const struct lookup
* lp
);
279 static struct lookup
const line_codes
[] = {
287 static struct lookup
const mon_names
[] = {
288 { "January", TM_JANUARY
},
289 { "February", TM_FEBRUARY
},
290 { "March", TM_MARCH
},
291 { "April", TM_APRIL
},
295 { "August", TM_AUGUST
},
296 { "September", TM_SEPTEMBER
},
297 { "October", TM_OCTOBER
},
298 { "November", TM_NOVEMBER
},
299 { "December", TM_DECEMBER
},
303 static struct lookup
const wday_names
[] = {
304 { "Sunday", TM_SUNDAY
},
305 { "Monday", TM_MONDAY
},
306 { "Tuesday", TM_TUESDAY
},
307 { "Wednesday", TM_WEDNESDAY
},
308 { "Thursday", TM_THURSDAY
},
309 { "Friday", TM_FRIDAY
},
310 { "Saturday", TM_SATURDAY
},
314 static struct lookup
const lasts
[] = {
315 { "last-Sunday", TM_SUNDAY
},
316 { "last-Monday", TM_MONDAY
},
317 { "last-Tuesday", TM_TUESDAY
},
318 { "last-Wednesday", TM_WEDNESDAY
},
319 { "last-Thursday", TM_THURSDAY
},
320 { "last-Friday", TM_FRIDAY
},
321 { "last-Saturday", TM_SATURDAY
},
325 static struct lookup
const begin_years
[] = {
326 { "minimum", YR_MINIMUM
},
327 { "maximum", YR_MAXIMUM
},
331 static struct lookup
const end_years
[] = {
332 { "minimum", YR_MINIMUM
},
333 { "maximum", YR_MAXIMUM
},
338 static struct lookup
const leap_types
[] = {
340 { "Stationary", false },
344 static const int len_months
[2][MONSPERYEAR
] = {
345 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
346 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
349 static const int len_years
[2] = {
350 DAYSPERNYEAR
, DAYSPERLYEAR
353 static struct attype
{
357 static zic_t gmtoffs
[TZ_MAX_TYPES
];
358 static char isdsts
[TZ_MAX_TYPES
];
359 static unsigned char abbrinds
[TZ_MAX_TYPES
];
360 static bool ttisstds
[TZ_MAX_TYPES
];
361 static bool ttisgmts
[TZ_MAX_TYPES
];
362 static char chars
[TZ_MAX_CHARS
];
363 static zic_t trans
[TZ_MAX_LEAPS
];
364 static zic_t corr
[TZ_MAX_LEAPS
];
365 static char roll
[TZ_MAX_LEAPS
];
368 ** Memory allocation.
371 static _Noreturn
void
372 memory_exhausted(const char *msg
)
374 fprintf(stderr
, _("%s: Memory exhausted: %s\n"), progname
, msg
);
378 static ATTRIBUTE_PURE
size_t
379 size_product(size_t nitems
, size_t itemsize
)
381 if (SIZE_MAX
/ itemsize
< nitems
)
382 memory_exhausted(_("size overflow"));
383 return nitems
* itemsize
;
388 strdup(char const *str
)
390 char *result
= malloc(strlen(str
) + 1);
391 return result
? strcpy(result
, str
) : result
;
395 static ATTRIBUTE_PURE
void *
399 memory_exhausted(strerror(errno
));
404 zic_malloc(size_t size
)
406 return memcheck(malloc(size
));
410 zic_realloc(void *ptr
, size_t size
)
412 return memcheck(realloc(ptr
, size
));
416 ecpyalloc(char const *str
)
418 return memcheck(strdup(str
));
422 growalloc(void *ptr
, size_t itemsize
, int nitems
, int *nitems_alloc
)
424 if (nitems
< *nitems_alloc
)
427 int amax
= INT_MAX
< SIZE_MAX
? INT_MAX
: SIZE_MAX
;
428 if ((amax
- 1) / 3 * 2 < *nitems_alloc
)
429 memory_exhausted(_("int overflow"));
430 *nitems_alloc
= *nitems_alloc
+ (*nitems_alloc
>> 1) + 1;
431 return zic_realloc(ptr
, size_product(*nitems_alloc
, itemsize
));
440 eats(const char *const name
, const int num
, const char *const rname
,
450 eat(const char *const name
, const int num
)
452 eats(name
, num
, NULL
, -1);
455 static void ATTRIBUTE_FORMAT((printf
, 1, 0))
456 verror(const char *const string
, va_list args
)
459 ** Match the format of "cc" to allow sh users to
460 ** zic ... 2>&1 | error -t "*" -v
464 fprintf(stderr
, _("\"%s\", line %d: "), filename
, linenum
);
465 vfprintf(stderr
, string
, args
);
466 if (rfilename
!= NULL
)
467 fprintf(stderr
, _(" (rule from \"%s\", line %d)"),
468 rfilename
, rlinenum
);
469 fprintf(stderr
, "\n");
472 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
473 error(const char *const string
, ...)
476 va_start(args
, string
);
477 verror(string
, args
);
482 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
483 warning(const char *const string
, ...)
486 fprintf(stderr
, _("warning: "));
487 va_start(args
, string
);
488 verror(string
, args
);
494 close_file(FILE *stream
, char const *name
)
496 char const *e
= (ferror(stream
) ? _("I/O error")
497 : fclose(stream
) != 0 ? strerror(errno
) : NULL
);
499 fprintf(stderr
, "%s: ", progname
);
501 fprintf(stderr
, "%s: ", name
);
502 fprintf(stderr
, "%s\n", e
);
507 static _Noreturn
void
508 usage(FILE *stream
, int status
)
511 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
512 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
513 "\t[ -L leapseconds ] [ filename ... ]\n\n"
514 "Report bugs to %s.\n"),
515 progname
, progname
, REPORT_BUGS_TO
);
516 if (status
== EXIT_SUCCESS
)
517 close_file(stream
, NULL
);
521 static const char * psxrules
;
522 static const char * lcltime
;
523 static const char * directory
;
524 static const char * leapsec
;
525 static const char * yitcommand
;
528 main(int argc
, char *argv
[])
535 (void) umask(umask(S_IWGRP
| S_IWOTH
) | (S_IWGRP
| S_IWOTH
));
538 (void) setlocale(LC_MESSAGES
, "");
540 (void) bindtextdomain(TZ_DOMAIN
, TZ_DOMAINDIR
);
541 #endif /* defined TEXTDOMAINDIR */
542 (void) textdomain(TZ_DOMAIN
);
543 #endif /* HAVE_GETTEXT */
545 if (TYPE_BIT(zic_t
) < 64) {
546 (void) fprintf(stderr
, "%s: %s\n", progname
,
547 _("wild compilation-time specification of zic_t"));
550 for (i
= 1; i
< argc
; ++i
)
551 if (strcmp(argv
[i
], "--version") == 0) {
552 (void) printf("zic %s%s\n", PKGVERSION
, TZVERSION
);
553 close_file(stdout
, NULL
);
555 } else if (strcmp(argv
[i
], "--help") == 0) {
556 usage(stdout
, EXIT_SUCCESS
);
558 while ((c
= getopt(argc
, argv
, "d:l:p:L:vsy:")) != EOF
&& c
!= -1)
561 usage(stderr
, EXIT_FAILURE
);
563 if (directory
== NULL
)
567 _("%s: More than one -d option specified\n"),
577 _("%s: More than one -l option specified\n"),
583 if (psxrules
== NULL
)
587 _("%s: More than one -p option specified\n"),
593 if (yitcommand
== NULL
)
597 _("%s: More than one -y option specified\n"),
607 _("%s: More than one -L option specified\n"),
616 warning(_("-s ignored"));
619 if (optind
== argc
- 1 && strcmp(argv
[optind
], "=") == 0)
620 usage(stderr
, EXIT_FAILURE
); /* usage message by request */
621 if (directory
== NULL
)
623 if (yitcommand
== NULL
)
624 yitcommand
= "yearistype";
626 if (optind
< argc
&& leapsec
!= NULL
) {
631 for (i
= optind
; i
< argc
; ++i
)
636 for (i
= 0; i
< nzones
; i
= j
) {
638 ** Find the next non-continuation zone entry.
640 for (j
= i
+ 1; j
< nzones
&& zones
[j
].z_name
== NULL
; ++j
)
642 outzone(&zones
[i
], j
- i
);
647 for (i
= 0; i
< nlinks
; ++i
) {
648 eat(links
[i
].l_filename
, links
[i
].l_linenum
);
649 dolink(links
[i
].l_from
, links
[i
].l_to
);
651 for (j
= 0; j
< nlinks
; ++j
)
652 if (strcmp(links
[i
].l_to
,
653 links
[j
].l_from
) == 0)
654 warning(_("link to link"));
656 if (lcltime
!= NULL
) {
657 eat(_("command line"), 1);
658 dolink(lcltime
, TZDEFAULT
);
660 if (psxrules
!= NULL
) {
661 eat(_("command line"), 1);
662 dolink(psxrules
, TZDEFRULES
);
664 if (warnings
&& (ferror(stderr
) || fclose(stderr
) != 0))
666 return errors
? EXIT_FAILURE
: EXIT_SUCCESS
;
670 componentcheck(char const *name
, char const *component
,
671 char const *component_end
)
673 enum { component_len_max
= 14 };
674 size_t component_len
= component_end
- component
;
675 if (component_len
== 0) {
677 error (_("empty file name"));
679 error (_(component
== name
680 ? "file name '%s' begins with '/'"
682 ? "file name '%s' contains '//'"
683 : "file name '%s' ends with '/'"),
687 if (0 < component_len
&& component_len
<= 2
688 && component
[0] == '.' && component_end
[-1] == '.') {
689 error(_("file name '%s' contains '%.*s' component"),
690 name
, (int) component_len
, component
);
694 if (0 < component_len
&& component
[0] == '-')
695 warning(_("file name '%s' component contains leading '-'"),
697 if (component_len_max
< component_len
)
698 warning(_("file name '%s' contains overlength component"
700 name
, component_len_max
, component
);
706 namecheck(const char *name
)
710 /* Benign characters in a portable file name. */
711 static char const benign
[] =
713 "abcdefghijklmnopqrstuvwxyz"
714 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
716 /* Non-control chars in the POSIX portable character set,
717 excluding the benign characters. */
718 static char const printable_and_not_benign
[] =
719 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
721 char const *component
= name
;
722 for (cp
= name
; *cp
; cp
++) {
723 unsigned char c
= *cp
;
724 if (noise
&& !strchr(benign
, c
)) {
725 warning((strchr(printable_and_not_benign
, c
)
726 ? _("file name '%s' contains byte '%c'")
727 : _("file name '%s' contains byte '\\%o'")),
731 if (!componentcheck(name
, component
, cp
))
736 return componentcheck(name
, component
, cp
);
740 relname(char const *dir
, char const *base
)
743 return ecpyalloc(base
);
745 size_t dir_len
= strlen(dir
);
746 bool needs_slash
= dir_len
&& dir
[dir_len
- 1] != '/';
747 char *result
= zic_malloc(dir_len
+ needs_slash
+ strlen(base
) + 1);
748 result
[dir_len
] = '/';
749 strcpy(result
+ dir_len
+ needs_slash
, base
);
750 return memcpy(result
, dir
, dir_len
);
755 dolink(char const *fromfield
, char const *tofield
)
761 fromname
= relname(directory
, fromfield
);
762 toname
= relname(directory
, tofield
);
764 ** We get to be careful here since
765 ** there's a fair chance of root running us.
767 fromisdir
= itsdir(fromname
);
769 char const *e
= strerror(fromisdir
< 0 ? errno
: EPERM
);
770 fprintf(stderr
, _("%s: link from %s failed: %s"),
771 progname
, fromname
, e
);
774 if (itsdir(toname
) <= 0)
776 if (link(fromname
, toname
) != 0) {
779 if (! mkdirs(toname
))
782 result
= link(fromname
, toname
);
784 const char *s
= fromfield
;
788 char * symlinkcontents
= NULL
;
792 while ((s
= strchr(s
, '/'))
793 && ! strncmp (fromfield
, tofield
,
796 for (s
= tofield
+ (t
- fromfield
); *s
; s
++)
797 dotdots
+= *s
== '/';
799 = zic_malloc(3 * dotdots
+ strlen(t
) + 1);
800 for (p
= symlinkcontents
; dotdots
-- != 0; p
+= 3)
803 result
= symlink(symlinkcontents
, toname
);
805 warning(_("hard link failed, symbolic link used"));
806 free(symlinkcontents
);
811 fp
= fopen(fromname
, "rb");
813 const char *e
= strerror(errno
);
815 _("%s: Can't read %s: %s\n"),
816 progname
, fromname
, e
);
819 tp
= fopen(toname
, "wb");
821 const char *e
= strerror(errno
);
823 _("%s: Can't create %s: %s\n"),
824 progname
, toname
, e
);
827 while ((c
= getc(fp
)) != EOF
)
829 close_file(fp
, fromname
);
830 close_file(tp
, toname
);
831 warning(_("link failed, copy used"));
838 #define TIME_T_BITS_IN_FILE 64
840 static zic_t
const min_time
= MINVAL (zic_t
, TIME_T_BITS_IN_FILE
);
841 static zic_t
const max_time
= MAXVAL (zic_t
, TIME_T_BITS_IN_FILE
);
843 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
844 rounded downward to the negation of a power of two that is
845 comfortably outside the error bounds.
847 zic does not output time stamps before this, partly because they
848 are physically suspect, and partly because GNOME mishandles them; see
849 GNOME bug 730332 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>.
851 For the time of the Big Bang, see:
853 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
854 I. Overview of products and scientific results.
855 arXiv:1303.5062 2013-03-20 20:10:01 UTC
856 <http://arxiv.org/pdf/1303.5062v1> [PDF]
858 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
859 gives the value 13.798 plus-or-minus 0.037 billion years.
860 Multiplying this by 1000000000 and then by 31557600 (the number of
861 seconds in an astronomical year) gives a value that is comfortably
862 less than 2**59, so BIG_BANG is - 2**59.
864 BIG_BANG is approximate, and may change in future versions.
865 Please do not rely on its exact value. */
868 #define BIG_BANG (- (1LL << 59))
871 static const zic_t big_bang_time
= BIG_BANG
;
873 /* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */
875 itsdir(char const *name
)
878 int res
= stat(name
, &st
);
882 return S_ISDIR(st
.st_mode
) != 0;
885 char *nameslashdot
= relname(name
, ".");
886 res
= stat(nameslashdot
, &st
);
894 ** Associate sets of rules with zones.
898 ** Sort by rule name.
902 rcomp(const void *cp1
, const void *cp2
)
904 return strcmp(((const struct rule
*) cp1
)->r_name
,
905 ((const struct rule
*) cp2
)->r_name
);
917 (void) qsort(rules
, (size_t)nrules
, sizeof *rules
, rcomp
);
918 for (i
= 0; i
< nrules
- 1; ++i
) {
919 if (strcmp(rules
[i
].r_name
,
920 rules
[i
+ 1].r_name
) != 0)
922 if (strcmp(rules
[i
].r_filename
,
923 rules
[i
+ 1].r_filename
) == 0)
925 eat(rules
[i
].r_filename
, rules
[i
].r_linenum
);
926 warning(_("same rule name in multiple files"));
927 eat(rules
[i
+ 1].r_filename
, rules
[i
+ 1].r_linenum
);
928 warning(_("same rule name in multiple files"));
929 for (j
= i
+ 2; j
< nrules
; ++j
) {
930 if (strcmp(rules
[i
].r_name
,
931 rules
[j
].r_name
) != 0)
933 if (strcmp(rules
[i
].r_filename
,
934 rules
[j
].r_filename
) == 0)
936 if (strcmp(rules
[i
+ 1].r_filename
,
937 rules
[j
].r_filename
) == 0)
944 for (i
= 0; i
< nzones
; ++i
) {
949 for (base
= 0; base
< nrules
; base
= out
) {
951 for (out
= base
+ 1; out
< nrules
; ++out
)
952 if (strcmp(rp
->r_name
, rules
[out
].r_name
) != 0)
954 for (i
= 0; i
< nzones
; ++i
) {
956 if (strcmp(zp
->z_rule
, rp
->r_name
) != 0)
959 zp
->z_nrules
= out
- base
;
962 for (i
= 0; i
< nzones
; ++i
) {
964 if (zp
->z_nrules
== 0) {
966 ** Maybe we have a local standard time offset.
968 eat(zp
->z_filename
, zp
->z_linenum
);
969 zp
->z_stdoff
= gethms(zp
->z_rule
, _("unruly zone"),
972 ** Note, though, that if there's no rule,
973 ** a '%s' in the format is a bad thing.
975 if (zp
->z_format_specifier
== 's')
976 error("%s", _("%s in ruleless zone"));
984 infile(const char *name
)
989 const struct lookup
* lp
;
995 if (strcmp(name
, "-") == 0) {
996 name
= _("standard input");
998 } else if ((fp
= fopen(name
, "r")) == NULL
) {
999 const char *e
= strerror(errno
);
1001 fprintf(stderr
, _("%s: Can't open %s: %s\n"),
1006 for (num
= 1; ; ++num
) {
1008 if (fgets(buf
, (int) sizeof buf
, fp
) != buf
)
1010 cp
= strchr(buf
, '\n');
1012 error(_("line too long"));
1016 fields
= getfields(buf
);
1018 while (fields
[nfields
] != NULL
) {
1021 if (strcmp(fields
[nfields
], "-") == 0)
1022 fields
[nfields
] = &nada
;
1027 } else if (wantcont
) {
1028 wantcont
= inzcont(fields
, nfields
);
1030 lp
= byword(fields
[0], line_codes
);
1032 error(_("input line of unknown type"));
1033 else switch ((int) (lp
->l_value
)) {
1035 inrule(fields
, nfields
);
1039 wantcont
= inzone(fields
, nfields
);
1042 inlink(fields
, nfields
);
1046 if (name
!= leapsec
)
1047 warning(_("%s: Leap line in non leap"
1048 " seconds file %s"),
1050 else inleap(fields
, nfields
);
1053 default: /* "cannot happen" */
1055 _("%s: panic: Invalid l_value %d\n"),
1056 progname
, lp
->l_value
);
1062 close_file(fp
, filename
);
1064 error(_("expected continuation line not found"));
1068 ** Convert a string of one of the forms
1069 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1070 ** into a number of seconds.
1071 ** A null string maps to zero.
1072 ** Call error with errstring and return zero on errors.
1076 gethms(char const *string
, char const *errstring
, bool signable
)
1082 if (string
== NULL
|| *string
== '\0')
1086 else if (*string
== '-') {
1090 if (sscanf(string
, "%"SCNdZIC
"%c", &hh
, &xs
) == 1)
1092 else if (sscanf(string
, "%"SCNdZIC
":%d%c", &hh
, &mm
, &xs
) == 2)
1094 else if (sscanf(string
, "%"SCNdZIC
":%d:%d%c", &hh
, &mm
, &ss
, &xs
)
1096 error("%s", errstring
);
1100 mm
< 0 || mm
>= MINSPERHOUR
||
1101 ss
< 0 || ss
> SECSPERMIN
) {
1102 error("%s", errstring
);
1105 if (ZIC_MAX
/ SECSPERHOUR
< hh
) {
1106 error(_("time overflow"));
1109 if (noise
&& (hh
> HOURSPERDAY
||
1110 (hh
== HOURSPERDAY
&& (mm
!= 0 || ss
!= 0))))
1111 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1112 return oadd(sign
* hh
* SECSPERHOUR
,
1113 sign
* (mm
* SECSPERMIN
+ ss
));
1117 inrule(char **fields
, int nfields
)
1119 static struct rule r
;
1121 if (nfields
!= RULE_FIELDS
) {
1122 error(_("wrong number of fields on Rule line"));
1125 if (*fields
[RF_NAME
] == '\0') {
1126 error(_("nameless rule"));
1129 r
.r_filename
= filename
;
1130 r
.r_linenum
= linenum
;
1131 r
.r_stdoff
= gethms(fields
[RF_STDOFF
], _("invalid saved time"), true);
1132 rulesub(&r
, fields
[RF_LOYEAR
], fields
[RF_HIYEAR
], fields
[RF_COMMAND
],
1133 fields
[RF_MONTH
], fields
[RF_DAY
], fields
[RF_TOD
]);
1134 r
.r_name
= ecpyalloc(fields
[RF_NAME
]);
1135 r
.r_abbrvar
= ecpyalloc(fields
[RF_ABBRVAR
]);
1136 if (max_abbrvar_len
< strlen(r
.r_abbrvar
))
1137 max_abbrvar_len
= strlen(r
.r_abbrvar
);
1138 rules
= growalloc(rules
, sizeof *rules
, nrules
, &nrules_alloc
);
1139 rules
[nrules
++] = r
;
1143 inzone(char **fields
, int nfields
)
1147 if (nfields
< ZONE_MINFIELDS
|| nfields
> ZONE_MAXFIELDS
) {
1148 error(_("wrong number of fields on Zone line"));
1151 if (strcmp(fields
[ZF_NAME
], TZDEFAULT
) == 0 && lcltime
!= NULL
) {
1153 _("\"Zone %s\" line and -l option are mutually exclusive"),
1157 if (strcmp(fields
[ZF_NAME
], TZDEFRULES
) == 0 && psxrules
!= NULL
) {
1159 _("\"Zone %s\" line and -p option are mutually exclusive"),
1163 for (i
= 0; i
< nzones
; ++i
)
1164 if (zones
[i
].z_name
!= NULL
&&
1165 strcmp(zones
[i
].z_name
, fields
[ZF_NAME
]) == 0) {
1167 _("duplicate zone name %s (file \"%s\", line %d)"),
1169 zones
[i
].z_filename
,
1170 zones
[i
].z_linenum
);
1173 return inzsub(fields
, nfields
, false);
1177 inzcont(char **fields
, int nfields
)
1179 if (nfields
< ZONEC_MINFIELDS
|| nfields
> ZONEC_MAXFIELDS
) {
1180 error(_("wrong number of fields on Zone continuation line"));
1183 return inzsub(fields
, nfields
, true);
1187 inzsub(char **const fields
, const int nfields
, const int iscont
)
1191 static struct zone z
;
1192 int i_gmtoff
, i_rule
, i_format
;
1193 int i_untilyear
, i_untilmonth
;
1194 int i_untilday
, i_untiltime
;
1198 i_gmtoff
= ZFC_GMTOFF
;
1200 i_format
= ZFC_FORMAT
;
1201 i_untilyear
= ZFC_TILYEAR
;
1202 i_untilmonth
= ZFC_TILMONTH
;
1203 i_untilday
= ZFC_TILDAY
;
1204 i_untiltime
= ZFC_TILTIME
;
1206 } else if (!namecheck(fields
[ZF_NAME
]))
1209 i_gmtoff
= ZF_GMTOFF
;
1211 i_format
= ZF_FORMAT
;
1212 i_untilyear
= ZF_TILYEAR
;
1213 i_untilmonth
= ZF_TILMONTH
;
1214 i_untilday
= ZF_TILDAY
;
1215 i_untiltime
= ZF_TILTIME
;
1216 z
.z_name
= ecpyalloc(fields
[ZF_NAME
]);
1218 z
.z_filename
= filename
;
1219 z
.z_linenum
= linenum
;
1220 z
.z_gmtoff
= gethms(fields
[i_gmtoff
], _("invalid UT offset"), true);
1221 if ((cp
= strchr(fields
[i_format
], '%')) != 0) {
1222 if ((*++cp
!= 's' && *cp
!= 'z') || strchr(cp
, '%')
1223 || strchr(fields
[i_format
], '/')) {
1224 error(_("invalid abbreviation format"));
1228 z
.z_rule
= ecpyalloc(fields
[i_rule
]);
1229 z
.z_format
= cp1
= ecpyalloc(fields
[i_format
]);
1230 z
.z_format_specifier
= cp
? *cp
: '\0';
1231 if (z
.z_format_specifier
== 'z') {
1233 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1235 cp1
[cp
- fields
[i_format
]] = 's';
1237 if (max_format_len
< strlen(z
.z_format
))
1238 max_format_len
= strlen(z
.z_format
);
1239 hasuntil
= nfields
> i_untilyear
;
1241 z
.z_untilrule
.r_filename
= filename
;
1242 z
.z_untilrule
.r_linenum
= linenum
;
1243 rulesub(&z
.z_untilrule
,
1244 fields
[i_untilyear
],
1247 (nfields
> i_untilmonth
) ?
1248 fields
[i_untilmonth
] : "Jan",
1249 (nfields
> i_untilday
) ? fields
[i_untilday
] : "1",
1250 (nfields
> i_untiltime
) ? fields
[i_untiltime
] : "0");
1251 z
.z_untiltime
= rpytime(&z
.z_untilrule
,
1252 z
.z_untilrule
.r_loyear
);
1253 if (iscont
&& nzones
> 0 &&
1254 z
.z_untiltime
> min_time
&&
1255 z
.z_untiltime
< max_time
&&
1256 zones
[nzones
- 1].z_untiltime
> min_time
&&
1257 zones
[nzones
- 1].z_untiltime
< max_time
&&
1258 zones
[nzones
- 1].z_untiltime
>= z
.z_untiltime
) {
1260 "Zone continuation line end time is not after end time of previous line"
1265 zones
= growalloc(zones
, sizeof *zones
, nzones
, &nzones_alloc
);
1266 zones
[nzones
++] = z
;
1268 ** If there was an UNTIL field on this line,
1269 ** there's more information about the zone on the next line.
1275 inleap(char **fields
, int nfields
)
1278 const struct lookup
* lp
;
1286 if (nfields
!= LEAP_FIELDS
) {
1287 error(_("wrong number of fields on Leap line"));
1291 cp
= fields
[LP_YEAR
];
1292 if (sscanf(cp
, "%"SCNdZIC
"%c", &year
, &xs
) != 1) {
1296 error(_("invalid leaping year"));
1299 if (!leapseen
|| leapmaxyear
< year
)
1301 if (!leapseen
|| leapminyear
> year
)
1307 i
= len_years
[isleap(j
)];
1311 i
= -len_years
[isleap(j
)];
1313 dayoff
= oadd(dayoff
, i
);
1315 if ((lp
= byword(fields
[LP_MONTH
], mon_names
)) == NULL
) {
1316 error(_("invalid month name"));
1319 month
= lp
->l_value
;
1321 while (j
!= month
) {
1322 i
= len_months
[isleap(year
)][j
];
1323 dayoff
= oadd(dayoff
, i
);
1326 cp
= fields
[LP_DAY
];
1327 if (sscanf(cp
, "%d%c", &day
, &xs
) != 1 ||
1328 day
<= 0 || day
> len_months
[isleap(year
)][month
]) {
1329 error(_("invalid day of month"));
1332 dayoff
= oadd(dayoff
, day
- 1);
1333 if (dayoff
< min_time
/ SECSPERDAY
) {
1334 error(_("time too small"));
1337 if (dayoff
> max_time
/ SECSPERDAY
) {
1338 error(_("time too large"));
1341 t
= dayoff
* SECSPERDAY
;
1342 tod
= gethms(fields
[LP_TIME
], _("invalid time of day"), false);
1343 cp
= fields
[LP_CORR
];
1348 if (strcmp(cp
, "") == 0) { /* infile() turns "-" into "" */
1351 } else if (strcmp(cp
, "--") == 0) {
1354 } else if (strcmp(cp
, "+") == 0) {
1357 } else if (strcmp(cp
, "++") == 0) {
1361 error(_("illegal CORRECTION field on Leap line"));
1364 if ((lp
= byword(fields
[LP_ROLL
], leap_types
)) == NULL
) {
1366 "illegal Rolling/Stationary field on Leap line"
1371 if (t
< big_bang_time
) {
1372 error(_("leap second precedes Big Bang"));
1375 leapadd(t
, positive
, lp
->l_value
, count
);
1380 inlink(char **const fields
, const int nfields
)
1384 if (nfields
!= LINK_FIELDS
) {
1385 error(_("wrong number of fields on Link line"));
1388 if (*fields
[LF_FROM
] == '\0') {
1389 error(_("blank FROM field on Link line"));
1392 if (! namecheck(fields
[LF_TO
]))
1394 l
.l_filename
= filename
;
1395 l
.l_linenum
= linenum
;
1396 l
.l_from
= ecpyalloc(fields
[LF_FROM
]);
1397 l
.l_to
= ecpyalloc(fields
[LF_TO
]);
1398 links
= growalloc(links
, sizeof *links
, nlinks
, &nlinks_alloc
);
1399 links
[nlinks
++] = l
;
1403 rulesub(struct rule
*rp
, const char *loyearp
, const char *hiyearp
,
1404 const char *typep
, const char *monthp
, const char *dayp
,
1407 const struct lookup
* lp
;
1413 if ((lp
= byword(monthp
, mon_names
)) == NULL
) {
1414 error(_("invalid month name"));
1417 rp
->r_month
= lp
->l_value
;
1418 rp
->r_todisstd
= false;
1419 rp
->r_todisgmt
= false;
1420 dp
= ecpyalloc(timep
);
1422 ep
= dp
+ strlen(dp
) - 1;
1423 switch (lowerit(*ep
)) {
1424 case 's': /* Standard */
1425 rp
->r_todisstd
= true;
1426 rp
->r_todisgmt
= false;
1429 case 'w': /* Wall */
1430 rp
->r_todisstd
= false;
1431 rp
->r_todisgmt
= false;
1434 case 'g': /* Greenwich */
1435 case 'u': /* Universal */
1436 case 'z': /* Zulu */
1437 rp
->r_todisstd
= true;
1438 rp
->r_todisgmt
= true;
1443 rp
->r_tod
= gethms(dp
, _("invalid time of day"), false);
1449 lp
= byword(cp
, begin_years
);
1450 rp
->r_lowasnum
= lp
== NULL
;
1451 if (!rp
->r_lowasnum
) switch ((int) lp
->l_value
) {
1453 rp
->r_loyear
= ZIC_MIN
;
1456 rp
->r_loyear
= ZIC_MAX
;
1458 default: /* "cannot happen" */
1460 _("%s: panic: Invalid l_value %d\n"),
1461 progname
, lp
->l_value
);
1463 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_loyear
, &xs
) != 1) {
1464 error(_("invalid starting year"));
1468 lp
= byword(cp
, end_years
);
1469 rp
->r_hiwasnum
= lp
== NULL
;
1470 if (!rp
->r_hiwasnum
) switch ((int) lp
->l_value
) {
1472 rp
->r_hiyear
= ZIC_MIN
;
1475 rp
->r_hiyear
= ZIC_MAX
;
1478 rp
->r_hiyear
= rp
->r_loyear
;
1480 default: /* "cannot happen" */
1482 _("%s: panic: Invalid l_value %d\n"),
1483 progname
, lp
->l_value
);
1485 } else if (sscanf(cp
, "%"SCNdZIC
"%c", &rp
->r_hiyear
, &xs
) != 1) {
1486 error(_("invalid ending year"));
1489 if (rp
->r_loyear
> rp
->r_hiyear
) {
1490 error(_("starting year greater than ending year"));
1494 rp
->r_yrtype
= NULL
;
1496 if (rp
->r_loyear
== rp
->r_hiyear
) {
1497 error(_("typed single year"));
1500 rp
->r_yrtype
= ecpyalloc(typep
);
1504 ** Accept things such as:
1510 dp
= ecpyalloc(dayp
);
1511 if ((lp
= byword(dp
, lasts
)) != NULL
) {
1512 rp
->r_dycode
= DC_DOWLEQ
;
1513 rp
->r_wday
= lp
->l_value
;
1514 rp
->r_dayofmonth
= len_months
[1][rp
->r_month
];
1516 if ((ep
= strchr(dp
, '<')) != 0)
1517 rp
->r_dycode
= DC_DOWLEQ
;
1518 else if ((ep
= strchr(dp
, '>')) != 0)
1519 rp
->r_dycode
= DC_DOWGEQ
;
1522 rp
->r_dycode
= DC_DOM
;
1524 if (rp
->r_dycode
!= DC_DOM
) {
1527 error(_("invalid day of month"));
1531 if ((lp
= byword(dp
, wday_names
)) == NULL
) {
1532 error(_("invalid weekday name"));
1536 rp
->r_wday
= lp
->l_value
;
1538 if (sscanf(ep
, "%d%c", &rp
->r_dayofmonth
, &xs
) != 1 ||
1539 rp
->r_dayofmonth
<= 0 ||
1540 (rp
->r_dayofmonth
> len_months
[1][rp
->r_month
])) {
1541 error(_("invalid day of month"));
1550 convert(const zic_t val
, char *const buf
)
1554 unsigned char *const b
= (unsigned char *) buf
;
1556 for (i
= 0, shift
= 24; i
< 4; ++i
, shift
-= 8)
1557 b
[i
] = val
>> shift
;
1561 convert64(const zic_t val
, char *const buf
)
1565 unsigned char *const b
= (unsigned char *) buf
;
1567 for (i
= 0, shift
= 56; i
< 8; ++i
, shift
-= 8)
1568 b
[i
] = val
>> shift
;
1572 puttzcode(const zic_t val
, FILE *const fp
)
1577 (void) fwrite(buf
, sizeof buf
, (size_t) 1, fp
);
1581 puttzcode64(const zic_t val
, FILE *const fp
)
1585 convert64(val
, buf
);
1586 (void) fwrite(buf
, sizeof buf
, (size_t) 1, fp
);
1590 atcomp(const void *avp
, const void *bvp
)
1592 const zic_t a
= ((const struct attype
*) avp
)->at
;
1593 const zic_t b
= ((const struct attype
*) bvp
)->at
;
1595 return (a
< b
) ? -1 : (a
> b
);
1601 return INT32_MIN
<= x
&& x
<= INT32_MAX
;
1605 writezone(const char *const name
, const char *const string
, char version
)
1609 int leapcnt32
, leapi32
;
1610 int timecnt32
, timei32
;
1613 static const struct tzhead tzh0
;
1614 static struct tzhead tzh
;
1615 zic_t
*ats
= zic_malloc(size_product(timecnt
, sizeof *ats
+ 1));
1616 void *typesptr
= ats
+ timecnt
;
1617 unsigned char *types
= typesptr
;
1623 (void) qsort(attypes
, (size_t) timecnt
, sizeof *attypes
,
1634 while (fromi
< timecnt
&& attypes
[fromi
].at
< big_bang_time
)
1636 for ( ; fromi
< timecnt
; ++fromi
) {
1637 if (toi
> 1 && ((attypes
[fromi
].at
+
1638 gmtoffs
[attypes
[toi
- 1].type
]) <=
1639 (attypes
[toi
- 1].at
+
1640 gmtoffs
[attypes
[toi
- 2].type
]))) {
1641 attypes
[toi
- 1].type
=
1642 attypes
[fromi
].type
;
1646 attypes
[toi
- 1].type
!= attypes
[fromi
].type
)
1647 attypes
[toi
++] = attypes
[fromi
];
1651 if (noise
&& timecnt
> 1200)
1652 warning(_("pre-2014 clients may mishandle"
1653 " more than 1200 transition times"));
1657 for (i
= 0; i
< timecnt
; ++i
) {
1658 ats
[i
] = attypes
[i
].at
;
1659 types
[i
] = attypes
[i
].type
;
1662 ** Correct for leap seconds.
1664 for (i
= 0; i
< timecnt
; ++i
) {
1667 if (ats
[i
] > trans
[j
] - corr
[j
]) {
1668 ats
[i
] = tadd(ats
[i
], corr
[j
]);
1673 ** Figure out 32-bit-limited starts and counts.
1675 timecnt32
= timecnt
;
1677 leapcnt32
= leapcnt
;
1679 while (timecnt32
> 0 && !is32(ats
[timecnt32
- 1]))
1681 while (timecnt32
> 0 && !is32(ats
[timei32
])) {
1686 ** Output an INT32_MIN "transition" if appropriate; see below.
1688 if (timei32
> 0 && ats
[timei32
] > INT32_MIN
) {
1692 while (leapcnt32
> 0 && !is32(trans
[leapcnt32
- 1]))
1694 while (leapcnt32
> 0 && !is32(trans
[leapi32
])) {
1698 fullname
= relname(directory
, name
);
1700 ** Remove old file, if any, to snap links.
1702 if (itsdir(fullname
) <= 0 && remove(fullname
) != 0 && errno
!= ENOENT
) {
1703 const char *e
= strerror(errno
);
1705 (void) fprintf(stderr
, _("%s: Can't remove %s: %s\n"),
1706 progname
, fullname
, e
);
1709 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1710 if (! mkdirs(fullname
))
1712 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1713 const char *e
= strerror(errno
);
1715 (void) fprintf(stderr
, _("%s: Can't create %s: %s\n"),
1716 progname
, fullname
, e
);
1720 for (pass
= 1; pass
<= 2; ++pass
) {
1721 int thistimei
, thistimecnt
;
1722 int thisleapi
, thisleapcnt
;
1723 int thistimelim
, thisleaplim
;
1724 int writetype
[TZ_MAX_TYPES
];
1725 int typemap
[TZ_MAX_TYPES
];
1727 char thischars
[TZ_MAX_CHARS
];
1729 int indmap
[TZ_MAX_CHARS
];
1732 thistimei
= timei32
;
1733 thistimecnt
= timecnt32
;
1734 thisleapi
= leapi32
;
1735 thisleapcnt
= leapcnt32
;
1738 thistimecnt
= timecnt
;
1740 thisleapcnt
= leapcnt
;
1742 thistimelim
= thistimei
+ thistimecnt
;
1743 thisleaplim
= thisleapi
+ thisleapcnt
;
1744 for (i
= 0; i
< typecnt
; ++i
)
1745 writetype
[i
] = thistimecnt
== timecnt
;
1746 if (thistimecnt
== 0) {
1748 ** No transition times fall in the current
1749 ** (32- or 64-bit) window.
1752 writetype
[typecnt
- 1] = true;
1754 for (i
= thistimei
- 1; i
< thistimelim
; ++i
)
1756 writetype
[types
[i
]] = true;
1758 ** For America/Godthab and Antarctica/Palmer
1761 writetype
[0] = true;
1763 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1765 ** For some pre-2011 systems: if the last-to-be-written
1766 ** standard (or daylight) type has an offset different from the
1767 ** most recently used offset,
1768 ** append an (unused) copy of the most recently used type
1769 ** (to help get global "altzone" and "timezone" variables
1773 int mrudst
, mrustd
, hidst
, histd
, type
;
1775 hidst
= histd
= mrudst
= mrustd
= -1;
1776 for (i
= thistimei
; i
< thistimelim
; ++i
) {
1779 if (isdsts
[types
[i
]])
1781 else mrustd
= types
[i
];
1783 for (i
= 0; i
< typecnt
; ++i
)
1789 if (hidst
>= 0 && mrudst
>= 0 && hidst
!= mrudst
&&
1790 gmtoffs
[hidst
] != gmtoffs
[mrudst
]) {
1791 isdsts
[mrudst
] = -1;
1792 type
= addtype(gmtoffs
[mrudst
],
1793 &chars
[abbrinds
[mrudst
]],
1798 writetype
[type
] = true;
1800 if (histd
>= 0 && mrustd
>= 0 && histd
!= mrustd
&&
1801 gmtoffs
[histd
] != gmtoffs
[mrustd
]) {
1802 isdsts
[mrustd
] = -1;
1803 type
= addtype(gmtoffs
[mrustd
],
1804 &chars
[abbrinds
[mrustd
]],
1809 writetype
[type
] = true;
1812 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1814 for (i
= 0; i
< typecnt
; ++i
)
1815 typemap
[i
] = writetype
[i
] ? thistypecnt
++ : -1;
1816 for (i
= 0; i
< (int)(sizeof indmap
/ sizeof indmap
[0]); ++i
)
1819 for (i
= 0; i
< typecnt
; ++i
) {
1824 if (indmap
[abbrinds
[i
]] >= 0)
1826 thisabbr
= &chars
[abbrinds
[i
]];
1827 for (j
= 0; j
< thischarcnt
; ++j
)
1828 if (strcmp(&thischars
[j
], thisabbr
) == 0)
1830 if (j
== thischarcnt
) {
1831 (void) strcpy(&thischars
[(int) thischarcnt
],
1833 thischarcnt
+= strlen(thisabbr
) + 1;
1835 indmap
[abbrinds
[i
]] = j
;
1837 #define DO(field) (void) fwrite(tzh.field, \
1838 sizeof tzh.field, (size_t) 1, fp)
1840 (void) strncpy(tzh
.tzh_magic
, TZ_MAGIC
, sizeof tzh
.tzh_magic
);
1841 tzh
.tzh_version
[0] = version
;
1842 convert(thistypecnt
, tzh
.tzh_ttisgmtcnt
);
1843 convert(thistypecnt
, tzh
.tzh_ttisstdcnt
);
1844 convert(thisleapcnt
, tzh
.tzh_leapcnt
);
1845 convert(thistimecnt
, tzh
.tzh_timecnt
);
1846 convert(thistypecnt
, tzh
.tzh_typecnt
);
1847 convert(thischarcnt
, tzh
.tzh_charcnt
);
1858 for (i
= thistimei
; i
< thistimelim
; ++i
)
1861 ** Output an INT32_MIN "transition"
1862 ** if appropriate; see above.
1864 puttzcode(((ats
[i
] < INT32_MIN
) ?
1865 INT32_MIN
: ats
[i
]), fp
);
1866 else puttzcode64(ats
[i
], fp
);
1867 for (i
= thistimei
; i
< thistimelim
; ++i
) {
1870 uc
= typemap
[types
[i
]];
1871 (void) fwrite(&uc
, sizeof uc
, (size_t) 1, fp
);
1873 for (i
= 0; i
< typecnt
; ++i
)
1875 puttzcode(gmtoffs
[i
], fp
);
1876 (void) putc(isdsts
[i
], fp
);
1877 (void) putc((unsigned char) indmap
[abbrinds
[i
]], fp
);
1879 if (thischarcnt
!= 0)
1880 (void) fwrite(thischars
, sizeof thischars
[0],
1881 (size_t) thischarcnt
, fp
);
1882 for (i
= thisleapi
; i
< thisleaplim
; ++i
) {
1886 if (timecnt
== 0 || trans
[i
] < ats
[0]) {
1889 if (++j
>= typecnt
) {
1895 while (j
< timecnt
&&
1900 todo
= tadd(trans
[i
], -gmtoffs
[j
]);
1901 } else todo
= trans
[i
];
1903 puttzcode(todo
, fp
);
1904 else puttzcode64(todo
, fp
);
1905 puttzcode(corr
[i
], fp
);
1907 for (i
= 0; i
< typecnt
; ++i
)
1909 (void) putc(ttisstds
[i
], fp
);
1910 for (i
= 0; i
< typecnt
; ++i
)
1912 (void) putc(ttisgmts
[i
], fp
);
1914 (void) fprintf(fp
, "\n%s\n", string
);
1915 close_file(fp
, fullname
);
1921 abbroffset(char *buf
, zic_t offset
)
1924 int seconds
, minutes
;
1931 seconds
= offset
% SECSPERMIN
;
1932 offset
/= SECSPERMIN
;
1933 minutes
= offset
% MINSPERHOUR
;
1934 offset
/= MINSPERHOUR
;
1935 if (100 <= offset
) {
1936 error(_("%%z UTC offset magnitude exceeds 99:59:59"));
1941 *p
++ = '0' + offset
/ 10;
1942 *p
++ = '0' + offset
% 10;
1943 if (minutes
| seconds
) {
1944 *p
++ = '0' + minutes
/ 10;
1945 *p
++ = '0' + minutes
% 10;
1947 *p
++ = '0' + seconds
/ 10;
1948 *p
++ = '0' + seconds
% 10;
1957 doabbr(char *abbr
, int abbrlen
, struct zone
const *zp
, const char *letters
,
1958 zic_t stdoff
, bool doquotes
)
1963 char const *format
= zp
->z_format
;
1965 slashp
= strchr(format
, '/');
1966 if (slashp
== NULL
) {
1967 char letterbuf
[PERCENT_Z_LEN_BOUND
+ 1];
1968 if (zp
->z_format_specifier
== 'z')
1969 letters
= abbroffset(letterbuf
, -zp
->z_gmtoff
+ stdoff
);
1972 (void) snprintf(abbr
, abbrlen
, format
, letters
);
1973 } else if (stdoff
!= 0) {
1974 (void) strlcpy(abbr
, slashp
+ 1, abbrlen
);
1976 (void) memcpy(abbr
, format
, slashp
- format
);
1977 abbr
[slashp
- format
] = '\0';
1982 for (cp
= abbr
; is_alpha(*cp
); cp
++)
1984 if (len
> 0 && *cp
== '\0')
1986 abbr
[len
+ 2] = '\0';
1987 abbr
[len
+ 1] = '>';
1988 memmove(abbr
+ 1, abbr
, len
);
1994 updateminmax(const zic_t x
)
2003 stringoffset(char *result
, zic_t offset
)
2008 bool negative
= offset
< 0;
2015 seconds
= offset
% SECSPERMIN
;
2016 offset
/= SECSPERMIN
;
2017 minutes
= offset
% MINSPERHOUR
;
2018 offset
/= MINSPERHOUR
;
2020 if (hours
>= HOURSPERDAY
* DAYSPERWEEK
) {
2024 len
+= sprintf(result
+ len
, "%d", hours
);
2025 if (minutes
!= 0 || seconds
!= 0) {
2026 len
+= sprintf(result
+ len
, ":%02d", minutes
);
2028 len
+= sprintf(result
+ len
, ":%02d", seconds
);
2034 stringrule(char *result
, const struct rule
*const rp
, const zic_t dstoff
,
2037 zic_t tod
= rp
->r_tod
;
2040 if (rp
->r_dycode
== DC_DOM
) {
2043 if (rp
->r_dayofmonth
== 29 && rp
->r_month
== TM_FEBRUARY
)
2046 for (month
= 0; month
< rp
->r_month
; ++month
)
2047 total
+= len_months
[0][month
];
2048 /* Omit the "J" in Jan and Feb, as that's shorter. */
2049 if (rp
->r_month
<= 1)
2050 result
+= sprintf(result
, "%d", total
+ rp
->r_dayofmonth
- 1);
2052 result
+= sprintf(result
, "J%d", total
+ rp
->r_dayofmonth
);
2055 int wday
= rp
->r_wday
;
2058 if (rp
->r_dycode
== DC_DOWGEQ
) {
2059 wdayoff
= (rp
->r_dayofmonth
- 1) % DAYSPERWEEK
;
2063 tod
+= wdayoff
* SECSPERDAY
;
2064 week
= 1 + (rp
->r_dayofmonth
- 1) / DAYSPERWEEK
;
2065 } else if (rp
->r_dycode
== DC_DOWLEQ
) {
2066 if (rp
->r_dayofmonth
== len_months
[1][rp
->r_month
])
2069 wdayoff
= rp
->r_dayofmonth
% DAYSPERWEEK
;
2073 tod
+= wdayoff
* SECSPERDAY
;
2074 week
= rp
->r_dayofmonth
/ DAYSPERWEEK
;
2076 } else return -1; /* "cannot happen" */
2078 wday
+= DAYSPERWEEK
;
2079 result
+= sprintf(result
, "M%d.%d.%d",
2080 rp
->r_month
+ 1, week
, wday
);
2084 if (rp
->r_todisstd
&& rp
->r_stdoff
== 0)
2086 if (tod
!= 2 * SECSPERMIN
* MINSPERHOUR
) {
2088 if (! stringoffset(result
, tod
))
2093 } else if (SECSPERDAY
<= tod
) {
2102 rule_cmp(struct rule
const *a
, struct rule
const *b
)
2108 if (a
->r_hiyear
!= b
->r_hiyear
)
2109 return a
->r_hiyear
< b
->r_hiyear
? -1 : 1;
2110 if (a
->r_month
- b
->r_month
!= 0)
2111 return a
->r_month
- b
->r_month
;
2112 return a
->r_dayofmonth
- b
->r_dayofmonth
;
2115 enum { YEAR_BY_YEAR_ZONE
= 1 };
2118 stringzone(char *result
, const int resultlen
, const struct zone
*const zpfirst
,
2119 const int zonecount
)
2121 const struct zone
* zp
;
2123 struct rule
* stdrp
;
2124 struct rule
* dstrp
;
2126 const char * abbrvar
;
2131 struct rule stdr
, dstr
;
2134 zp
= zpfirst
+ zonecount
- 1;
2135 stdrp
= dstrp
= NULL
;
2136 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2137 rp
= &zp
->z_rules
[i
];
2138 if (rp
->r_hiwasnum
|| rp
->r_hiyear
!= ZIC_MAX
)
2140 if (rp
->r_yrtype
!= NULL
)
2142 if (rp
->r_stdoff
== 0) {
2152 if (stdrp
== NULL
&& dstrp
== NULL
) {
2154 ** There are no rules running through "max".
2155 ** Find the latest std rule in stdabbrrp
2156 ** and latest rule of any type in stdrp.
2158 struct rule
*stdabbrrp
= NULL
;
2159 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2160 rp
= &zp
->z_rules
[i
];
2161 if (rp
->r_stdoff
== 0 && rule_cmp(stdabbrrp
, rp
) < 0)
2163 if (rule_cmp(stdrp
, rp
) < 0)
2167 ** Horrid special case: if year is 2037,
2168 ** presume this is a zone handled on a year-by-year basis;
2169 ** do not try to apply a rule to the zone.
2171 if (stdrp
!= NULL
&& stdrp
->r_hiyear
== 2037)
2172 return YEAR_BY_YEAR_ZONE
;
2174 if (stdrp
!= NULL
&& stdrp
->r_stdoff
!= 0) {
2175 /* Perpetual DST. */
2176 dstr
.r_month
= TM_JANUARY
;
2177 dstr
.r_dycode
= DC_DOM
;
2178 dstr
.r_dayofmonth
= 1;
2180 dstr
.r_todisstd
= dstr
.r_todisgmt
= false;
2181 dstr
.r_stdoff
= stdrp
->r_stdoff
;
2182 dstr
.r_abbrvar
= stdrp
->r_abbrvar
;
2183 stdr
.r_month
= TM_DECEMBER
;
2184 stdr
.r_dycode
= DC_DOM
;
2185 stdr
.r_dayofmonth
= 31;
2186 stdr
.r_tod
= SECSPERDAY
+ stdrp
->r_stdoff
;
2187 stdr
.r_todisstd
= stdr
.r_todisgmt
= false;
2190 = (stdabbrrp
? stdabbrrp
->r_abbrvar
: "");
2195 if (stdrp
== NULL
&& (zp
->z_nrules
!= 0 || zp
->z_stdoff
!= 0))
2197 abbrvar
= (stdrp
== NULL
) ? "" : stdrp
->r_abbrvar
;
2198 len
= doabbr(result
, resultlen
, zp
, abbrvar
, 0, true);
2199 offsetlen
= stringoffset(result
+ len
, -zp
->z_gmtoff
);
2207 len
+= doabbr(result
+ len
, resultlen
- len
, zp
, dstrp
->r_abbrvar
, dstrp
->r_stdoff
, true);
2208 if (dstrp
->r_stdoff
!= SECSPERMIN
* MINSPERHOUR
) {
2209 offsetlen
= stringoffset(result
+ len
,
2210 -(zp
->z_gmtoff
+ dstrp
->r_stdoff
));
2217 result
[len
++] = ',';
2218 c
= stringrule(result
+ len
, dstrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2225 len
+= strlen(result
+ len
);
2226 result
[len
++] = ',';
2227 c
= stringrule(result
+ len
, stdrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2238 outzone(const struct zone
*zpfirst
, int zonecount
)
2240 const struct zone
* zp
;
2243 bool usestart
, useuntil
;
2244 zic_t starttime
, untiltime
;
2255 size_t max_abbr_len
;
2256 size_t max_envvar_len
;
2257 bool prodstic
; /* all rules are min to max */
2262 max_abbr_len
= 2 + max_format_len
+ max_abbrvar_len
;
2263 max_envvar_len
= 2 * max_abbr_len
+ 5 * 9;
2264 startbuf
= zic_malloc(max_abbr_len
+ 1);
2265 ab
= zic_malloc(max_abbr_len
+ 1);
2266 envvar
= zic_malloc(max_envvar_len
+ 1);
2267 INITIALIZE(untiltime
);
2268 INITIALIZE(starttime
);
2270 ** Now. . .finally. . .generate some useful data!
2275 prodstic
= zonecount
== 1;
2277 ** Thanks to Earl Chew
2278 ** for noting the need to unconditionally initialize startttisstd.
2280 startttisstd
= false;
2281 startttisgmt
= false;
2282 min_year
= max_year
= EPOCH_YEAR
;
2284 updateminmax(leapminyear
);
2285 updateminmax(leapmaxyear
+ (leapmaxyear
< ZIC_MAX
));
2287 for (i
= 0; i
< zonecount
; ++i
) {
2289 if (i
< zonecount
- 1)
2290 updateminmax(zp
->z_untilrule
.r_loyear
);
2291 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2292 rp
= &zp
->z_rules
[j
];
2294 updateminmax(rp
->r_loyear
);
2296 updateminmax(rp
->r_hiyear
);
2297 if (rp
->r_lowasnum
|| rp
->r_hiwasnum
)
2302 ** Generate lots of data if a rule can't cover all future times.
2304 compat
= stringzone(envvar
, max_envvar_len
+ 1, zpfirst
, zonecount
);
2305 version
= compat
< 2013 ? ZIC_VERSION_PRE_2013
: ZIC_VERSION
;
2306 do_extend
= compat
< 0 || compat
== YEAR_BY_YEAR_ZONE
;
2310 _("no POSIX environment variable for zone"),
2312 else if (compat
!= 0 && compat
!= YEAR_BY_YEAR_ZONE
) {
2313 /* Circa-COMPAT clients, and earlier clients, might
2314 not work for this zone when given dates before
2315 1970 or after 2038. */
2316 warning(_("%s: pre-%d clients may mishandle"
2317 " distant timestamps"),
2318 zpfirst
->z_name
, compat
);
2323 ** Search through a couple of extra years past the obvious
2324 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2325 ** rule applies from 2012 onwards and has transitions in March
2326 ** and September, plus some one-off transitions in November
2327 ** 2013. If zic looked only at the last 400 years, it would
2328 ** set max_year=2413, with the intent that the 400 years 2014
2329 ** through 2413 will be repeated. The last transition listed
2330 ** in the tzfile would be in 2413-09, less than 400 years
2331 ** after the last one-off transition in 2013-11. Two years
2332 ** might be overkill, but with the kind of edge cases
2333 ** available we're not sure that one year would suffice.
2335 enum { years_of_observations
= YEARSPERREPEAT
+ 2 };
2337 if (min_year
>= ZIC_MIN
+ years_of_observations
)
2338 min_year
-= years_of_observations
;
2339 else min_year
= ZIC_MIN
;
2340 if (max_year
<= ZIC_MAX
- years_of_observations
)
2341 max_year
+= years_of_observations
;
2342 else max_year
= ZIC_MAX
;
2344 ** Regardless of any of the above,
2345 ** for a "proDSTic" zone which specifies that its rules
2346 ** always have and always will be in effect,
2347 ** we only need one cycle to define the zone.
2351 max_year
= min_year
+ years_of_observations
;
2355 ** For the benefit of older systems,
2356 ** generate data from 1900 through 2037.
2358 if (min_year
> 1900)
2360 if (max_year
< 2037)
2362 for (i
= 0; i
< zonecount
; ++i
) {
2364 ** A guess that may well be corrected later.
2368 usestart
= i
> 0 && (zp
- 1)->z_untiltime
> big_bang_time
;
2369 useuntil
= i
< (zonecount
- 1);
2370 if (useuntil
&& zp
->z_untiltime
<= big_bang_time
)
2372 gmtoff
= zp
->z_gmtoff
;
2373 eat(zp
->z_filename
, zp
->z_linenum
);
2375 startoff
= zp
->z_gmtoff
;
2376 if (zp
->z_nrules
== 0) {
2377 stdoff
= zp
->z_stdoff
;
2378 doabbr(startbuf
, max_abbr_len
+ 1, zp
,
2379 NULL
, stdoff
, false);
2380 type
= addtype(oadd(zp
->z_gmtoff
, stdoff
),
2381 startbuf
, stdoff
!= 0, startttisstd
,
2384 addtt(starttime
, type
);
2386 } else addtt(big_bang_time
, type
);
2387 } else for (year
= min_year
; year
<= max_year
; ++year
) {
2388 if (useuntil
&& year
> zp
->z_untilrule
.r_hiyear
)
2391 ** Mark which rules to do in the current year.
2392 ** For those to do, calculate rpytime(rp, year);
2394 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2395 rp
= &zp
->z_rules
[j
];
2396 eats(zp
->z_filename
, zp
->z_linenum
,
2397 rp
->r_filename
, rp
->r_linenum
);
2398 rp
->r_todo
= year
>= rp
->r_loyear
&&
2399 year
<= rp
->r_hiyear
&&
2400 yearistype(year
, rp
->r_yrtype
);
2402 rp
->r_temp
= rpytime(rp
, year
);
2412 ** Turn untiltime into UT
2413 ** assuming the current gmtoff and
2416 untiltime
= zp
->z_untiltime
;
2417 if (!zp
->z_untilrule
.r_todisgmt
)
2418 untiltime
= tadd(untiltime
,
2420 if (!zp
->z_untilrule
.r_todisstd
)
2421 untiltime
= tadd(untiltime
,
2425 ** Find the rule (of those to do, if any)
2426 ** that takes effect earliest in the year.
2429 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2430 rp
= &zp
->z_rules
[j
];
2433 eats(zp
->z_filename
, zp
->z_linenum
,
2434 rp
->r_filename
, rp
->r_linenum
);
2435 offset
= rp
->r_todisgmt
? 0 : gmtoff
;
2436 if (!rp
->r_todisstd
)
2437 offset
= oadd(offset
, stdoff
);
2439 if (jtime
== min_time
||
2442 jtime
= tadd(jtime
, -offset
);
2443 if (k
< 0 || jtime
< ktime
) {
2446 } else if (jtime
== ktime
) {
2447 char const *dup_rules_msg
=
2448 _("two rules for same instant");
2449 eats(zp
->z_filename
, zp
->z_linenum
,
2450 rp
->r_filename
, rp
->r_linenum
);
2451 warning("%s", dup_rules_msg
);
2452 rp
= &zp
->z_rules
[k
];
2453 eats(zp
->z_filename
, zp
->z_linenum
,
2454 rp
->r_filename
, rp
->r_linenum
);
2455 error("%s", dup_rules_msg
);
2459 break; /* go on to next year */
2460 rp
= &zp
->z_rules
[k
];
2462 if (useuntil
&& ktime
>= untiltime
)
2464 stdoff
= rp
->r_stdoff
;
2465 if (usestart
&& ktime
== starttime
)
2468 if (ktime
< starttime
) {
2469 startoff
= oadd(zp
->z_gmtoff
,
2479 if (*startbuf
== '\0' &&
2480 startoff
== oadd(zp
->z_gmtoff
,
2490 eats(zp
->z_filename
, zp
->z_linenum
,
2491 rp
->r_filename
, rp
->r_linenum
);
2492 doabbr(ab
, max_abbr_len
+ 1, zp
, rp
->r_abbrvar
,
2493 rp
->r_stdoff
, false);
2494 offset
= oadd(zp
->z_gmtoff
, rp
->r_stdoff
);
2495 type
= addtype(offset
, ab
, rp
->r_stdoff
!= 0,
2496 rp
->r_todisstd
, rp
->r_todisgmt
);
2501 if (*startbuf
== '\0' &&
2502 zp
->z_format
!= NULL
&&
2503 strchr(zp
->z_format
, '%') == NULL
&&
2504 strchr(zp
->z_format
, '/') == NULL
)
2505 (void)strncpy(startbuf
, zp
->z_format
,
2506 max_abbr_len
+ 1 - 1);
2507 eat(zp
->z_filename
, zp
->z_linenum
);
2508 if (*startbuf
== '\0')
2509 error(_("can't determine time zone abbreviation to use just after until time"));
2510 else addtt(starttime
,
2511 addtype(startoff
, startbuf
,
2512 startoff
!= zp
->z_gmtoff
,
2517 ** Now we may get to set starttime for the next zone line.
2520 startttisstd
= zp
->z_untilrule
.r_todisstd
;
2521 startttisgmt
= zp
->z_untilrule
.r_todisgmt
;
2522 starttime
= zp
->z_untiltime
;
2524 starttime
= tadd(starttime
, -stdoff
);
2526 starttime
= tadd(starttime
, -gmtoff
);
2531 ** If we're extending the explicitly listed observations
2532 ** for 400 years because we can't fill the POSIX-TZ field,
2533 ** check whether we actually ended up explicitly listing
2534 ** observations through that period. If there aren't any
2535 ** near the end of the 400-year period, add a redundant
2536 ** one at the end of the final year, to make it clear
2537 ** that we are claiming to have definite knowledge of
2538 ** the lack of transitions up to that point.
2541 struct attype
*lastat
;
2542 xr
.r_month
= TM_JANUARY
;
2543 xr
.r_dycode
= DC_DOM
;
2544 xr
.r_dayofmonth
= 1;
2546 for (lastat
= &attypes
[0], i
= 1; i
< timecnt
; i
++)
2547 if (attypes
[i
].at
> lastat
->at
)
2548 lastat
= &attypes
[i
];
2549 if (lastat
->at
< rpytime(&xr
, max_year
- 1)) {
2551 ** Create new type code for the redundant entry,
2552 ** to prevent it being optimized away.
2554 if (typecnt
>= TZ_MAX_TYPES
) {
2555 error(_("too many local time types"));
2558 gmtoffs
[typecnt
] = gmtoffs
[lastat
->type
];
2559 isdsts
[typecnt
] = isdsts
[lastat
->type
];
2560 ttisstds
[typecnt
] = ttisstds
[lastat
->type
];
2561 ttisgmts
[typecnt
] = ttisgmts
[lastat
->type
];
2562 abbrinds
[typecnt
] = abbrinds
[lastat
->type
];
2564 addtt(rpytime(&xr
, max_year
+ 1), typecnt
-1);
2567 writezone(zpfirst
->z_name
, envvar
, version
);
2574 addtt(zic_t starttime
, int type
)
2576 if (starttime
<= big_bang_time
||
2577 (timecnt
== 1 && attypes
[0].at
< big_bang_time
)) {
2578 gmtoffs
[0] = gmtoffs
[type
];
2579 isdsts
[0] = isdsts
[type
];
2580 ttisstds
[0] = ttisstds
[type
];
2581 ttisgmts
[0] = ttisgmts
[type
];
2582 if (abbrinds
[type
] != 0)
2583 strcpy(chars
, &chars
[abbrinds
[type
]]);
2585 charcnt
= strlen(chars
) + 1;
2590 attypes
= growalloc(attypes
, sizeof *attypes
, timecnt
, &timecnt_alloc
);
2591 attypes
[timecnt
].at
= starttime
;
2592 attypes
[timecnt
].type
= type
;
2597 addtype(zic_t gmtoff
, char *const abbr
, bool isdst
, bool ttisstd
, bool ttisgmt
)
2602 ** See if there's already an entry for this zone type.
2603 ** If so, just return its index.
2605 for (i
= 0; i
< typecnt
; ++i
) {
2606 if (gmtoff
== gmtoffs
[i
] && isdst
== isdsts
[i
] &&
2607 strcmp(abbr
, &chars
[abbrinds
[i
]]) == 0 &&
2608 ttisstd
== ttisstds
[i
] &&
2609 ttisgmt
== ttisgmts
[i
])
2613 ** There isn't one; add a new one, unless there are already too
2616 if (typecnt
>= TZ_MAX_TYPES
) {
2617 error(_("too many local time types"));
2620 if (! (-1L - 2147483647L <= gmtoff
&& gmtoff
<= 2147483647L)) {
2621 error(_("UT offset out of range"));
2624 gmtoffs
[i
] = gmtoff
;
2626 ttisstds
[i
] = ttisstd
;
2627 ttisgmts
[i
] = ttisgmt
;
2629 for (j
= 0; j
< charcnt
; ++j
)
2630 if (strcmp(&chars
[j
], abbr
) == 0)
2640 leapadd(zic_t t
, bool positive
, int rolling
, int count
)
2644 if (leapcnt
+ (positive
? count
: 1) > TZ_MAX_LEAPS
) {
2645 error(_("too many leap seconds"));
2648 for (i
= 0; i
< leapcnt
; ++i
)
2649 if (t
<= trans
[i
]) {
2650 if (t
== trans
[i
]) {
2651 error(_("repeated leap second moment"));
2657 for (j
= leapcnt
; j
> i
; --j
) {
2658 trans
[j
] = trans
[j
- 1];
2659 corr
[j
] = corr
[j
- 1];
2660 roll
[j
] = roll
[j
- 1];
2663 corr
[i
] = positive
? 1 : -count
;
2666 } while (positive
&& --count
!= 0);
2676 ** propagate leap seconds forward
2678 for (i
= 0; i
< leapcnt
; ++i
) {
2679 trans
[i
] = tadd(trans
[i
], last
);
2680 last
= corr
[i
] += last
;
2685 yearistype(int year
, const char *type
)
2690 if (type
== NULL
|| *type
== '\0')
2692 buf
= zic_realloc(buf
, 132 + strlen(yitcommand
) + strlen(type
));
2693 (void)sprintf(buf
, "%s %d %s", yitcommand
, year
, type
); /* XXX: sprintf is safe */
2694 result
= system(buf
);
2695 if (WIFEXITED(result
)) switch (WEXITSTATUS(result
)) {
2701 error(_("Wild result from command execution"));
2702 (void) fprintf(stderr
, _("%s: command was '%s', result was %d\n"),
2703 progname
, buf
, result
);
2708 /* Is A a space character in the C locale? */
2715 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2720 /* Is A an alphabetic character in the C locale? */
2727 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2728 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2729 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2730 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2731 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2732 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2733 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2734 case 'v': case 'w': case 'x': case 'y': case 'z':
2739 /* If A is an uppercase character in the C locale, return its lowercase
2740 counterpart. Otherwise, return A. */
2746 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2747 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2748 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2749 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2750 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2751 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2752 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2753 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2754 case 'Y': return 'y'; case 'Z': return 'z';
2758 /* case-insensitive equality */
2759 static ATTRIBUTE_PURE
bool
2760 ciequal(const char *ap
, const char *bp
)
2762 while (lowerit(*ap
) == lowerit(*bp
++))
2768 static ATTRIBUTE_PURE
bool
2769 itsabbr(const char *abbr
, const char *word
)
2771 if (lowerit(*abbr
) != lowerit(*word
))
2774 while (*++abbr
!= '\0')
2778 } while (lowerit(*word
++) != lowerit(*abbr
));
2782 static ATTRIBUTE_PURE
const struct lookup
*
2783 byword(const char *word
, const struct lookup
*table
)
2785 const struct lookup
* foundlp
;
2786 const struct lookup
* lp
;
2788 if (word
== NULL
|| table
== NULL
)
2791 ** Look for exact match.
2793 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2794 if (ciequal(word
, lp
->l_word
))
2797 ** Look for inexact match.
2800 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2801 if (itsabbr(word
, lp
->l_word
)) {
2802 if (foundlp
== NULL
)
2804 else return NULL
; /* multiple inexact matches */
2818 array
= zic_malloc(size_product(strlen(cp
) + 1, sizeof *array
));
2821 while (is_space(*cp
))
2823 if (*cp
== '\0' || *cp
== '#')
2825 array
[nsubs
++] = dp
= cp
;
2827 if ((*dp
= *cp
++) != '"')
2829 else while ((*dp
= *cp
++) != '"')
2834 "Odd number of quotation marks"
2838 } while (*cp
&& *cp
!= '#' && !is_space(*cp
));
2843 array
[nsubs
] = NULL
;
2847 static _Noreturn
void
2850 error(_("time overflow"));
2854 static ATTRIBUTE_PURE zic_t
2855 oadd(zic_t t1
, zic_t t2
)
2857 if (t1
< 0 ? t2
< ZIC_MIN
- t1
: ZIC_MAX
- t1
< t2
)
2862 static ATTRIBUTE_PURE zic_t
2863 tadd(zic_t t1
, zic_t t2
)
2866 if (t2
< min_time
- t1
) {
2872 if (max_time
- t1
< t2
) {
2882 ** Given a rule, and a year, compute the date (in seconds since January 1,
2883 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
2887 rpytime(const struct rule
*rp
, zic_t wantedy
)
2890 zic_t dayoff
; /* with a nod to Margaret O. */
2893 if (wantedy
== ZIC_MIN
)
2895 if (wantedy
== ZIC_MAX
)
2900 while (wantedy
!= y
) {
2902 i
= len_years
[isleap(y
)];
2906 i
= -len_years
[isleap(y
)];
2908 dayoff
= oadd(dayoff
, i
);
2910 while (m
!= rp
->r_month
) {
2911 i
= len_months
[isleap(y
)][m
];
2912 dayoff
= oadd(dayoff
, i
);
2915 i
= rp
->r_dayofmonth
;
2916 if (m
== TM_FEBRUARY
&& i
== 29 && !isleap(y
)) {
2917 if (rp
->r_dycode
== DC_DOWLEQ
)
2920 error(_("use of 2/29 in non leap-year"));
2925 dayoff
= oadd(dayoff
, i
);
2926 if (rp
->r_dycode
== DC_DOWGEQ
|| rp
->r_dycode
== DC_DOWLEQ
) {
2929 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
2932 ** Don't trust mod of negative numbers.
2935 wday
= (wday
+ dayoff
) % LDAYSPERWEEK
;
2937 wday
-= ((-dayoff
) % LDAYSPERWEEK
);
2939 wday
+= LDAYSPERWEEK
;
2941 while (wday
!= rp
->r_wday
)
2942 if (rp
->r_dycode
== DC_DOWGEQ
) {
2943 dayoff
= oadd(dayoff
, (zic_t
) 1);
2944 if (++wday
>= LDAYSPERWEEK
)
2948 dayoff
= oadd(dayoff
, (zic_t
) -1);
2950 wday
= LDAYSPERWEEK
- 1;
2953 if (i
< 0 || i
>= len_months
[isleap(y
)][m
]) {
2955 warning(_("rule goes past start/end of month; \
2956 will not work with pre-2004 versions of zic"));
2959 if (dayoff
< min_time
/ SECSPERDAY
)
2961 if (dayoff
> max_time
/ SECSPERDAY
)
2963 t
= (zic_t
) dayoff
* SECSPERDAY
;
2964 return tadd(t
, rp
->r_tod
);
2968 newabbr(const char *string
)
2972 if (strcmp(string
, GRANDPARENTED
) != 0) {
2978 while (is_alpha(*cp
) || ('0' <= *cp
&& *cp
<= '9')
2979 || *cp
== '-' || *cp
== '+')
2981 if (noise
&& cp
- string
< 3)
2982 mp
= _("time zone abbreviation has fewer than 3 characters");
2983 if (cp
- string
> ZIC_MAX_ABBR_LEN_WO_WARN
)
2984 mp
= _("time zone abbreviation has too many characters");
2986 mp
= _("time zone abbreviation differs from POSIX standard");
2988 warning("%s (%s)", mp
, string
);
2990 i
= strlen(string
) + 1;
2991 if (charcnt
+ i
> TZ_MAX_CHARS
) {
2992 error(_("too many, or too long, time zone abbreviations"));
2995 (void)strncpy(&chars
[charcnt
], string
, sizeof(chars
) - charcnt
- 1);
3000 mkdirs(char *argname
)
3005 if (argname
== NULL
|| *argname
== '\0')
3007 cp
= name
= ecpyalloc(argname
);
3008 while ((cp
= strchr(cp
+ 1, '/')) != 0) {
3010 #ifdef HAVE_DOS_FILE_NAMES
3012 ** DOS drive specifier?
3014 if (is_alpha(name
[0]) && name
[1] == ':' && name
[2] == '\0') {
3020 ** Try to create it. It's OK if creation fails because
3021 ** the directory already exists, perhaps because some
3022 ** other process just created it.
3024 if (mkdir(name
, MKDIR_UMASK
) != 0) {
3026 if (itsdir(name
) <= 0) {
3027 char const *e
= strerror(err
);
3028 warning(_("%s: Can't create directory"