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 ** On some ancient hosts, predicates like `isspace(C)' are defined
36 ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
37 ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
38 ** Neither the C Standard nor Posix require that `isascii' exist.
39 ** For portability, we check both ancient and modern requirements.
40 ** If isascii is not defined, the isascii check succeeds trivially.
47 #define end(cp) (strchr((cp), '\0'))
50 const char * r_filename
;
54 zic_t r_loyear
; /* for example, 1986 */
55 zic_t r_hiyear
; /* for example, 1986 */
56 const char * r_yrtype
;
60 int r_month
; /* 0..11 */
62 int r_dycode
; /* see below */
66 zic_t r_tod
; /* time from midnight */
67 int r_todisstd
; /* above is standard time if TRUE */
68 /* or wall clock time if FALSE */
69 int r_todisgmt
; /* above is GMT if TRUE */
70 /* or local time if FALSE */
71 zic_t r_stdoff
; /* offset from standard time */
72 const char * r_abbrvar
; /* variable part of abbreviation */
74 int r_todo
; /* a rule to do (used in outzone) */
75 zic_t r_temp
; /* used in outzone */
79 ** r_dycode r_dayofmonth r_wday
82 #define DC_DOM 0 /* 1..31 */ /* unused */
83 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
84 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
87 const char * z_filename
;
93 const char * z_format
;
97 struct rule
* z_rules
;
100 struct rule z_untilrule
;
104 extern int getopt(int argc
, char * const argv
[],
105 const char * options
);
106 extern int link(const char * fromname
, const char * toname
);
107 extern char * optarg
;
111 # define link(from, to) (-1)
114 # define symlink(from, to) (-1)
117 static void addtt(zic_t starttime
, int type
);
118 static int addtype(zic_t gmtoff
, const char * abbr
, int isdst
,
119 int ttisstd
, int ttisgmt
);
120 static void leapadd(zic_t t
, int positive
, int rolling
, int count
);
121 static void adjleap(void);
122 static void associate(void);
123 static void dolink(const char * fromfield
, const char * tofield
);
124 static char ** getfields(char * buf
);
125 static zic_t
gethms(const char * string
, const char * errstrng
,
127 static void infile(const char * filename
);
128 static void inleap(char ** fields
, int nfields
);
129 static void inlink(char ** fields
, int nfields
);
130 static void inrule(char ** fields
, int nfields
);
131 static int inzcont(char ** fields
, int nfields
);
132 static int inzone(char ** fields
, int nfields
);
133 static int inzsub(char ** fields
, int nfields
, int iscont
);
134 static int itsdir(const char * name
);
135 static int lowerit(int c
);
136 static int mkdirs(char * filename
);
137 static void newabbr(const char * abbr
);
138 static zic_t
oadd(zic_t t1
, zic_t t2
);
139 static void outzone(const struct zone
* zp
, int ntzones
);
140 static zic_t
rpytime(const struct rule
* rp
, zic_t wantedy
);
141 static void rulesub(struct rule
* rp
,
142 const char * loyearp
, const char * hiyearp
,
143 const char * typep
, const char * monthp
,
144 const char * dayp
, const char * timep
);
145 static zic_t
tadd(zic_t t1
, zic_t t2
);
146 static int yearistype(int year
, const char * type
);
150 static const char * filename
;
153 static zic_t leapminyear
;
154 static zic_t leapmaxyear
;
156 static int max_abbrvar_len
;
157 static int max_format_len
;
158 static zic_t max_year
;
159 static zic_t min_year
;
161 static const char * rfilename
;
163 static const char * progname
;
165 static int timecnt_alloc
;
178 ** Which fields are which on a Zone line.
186 #define ZF_TILMONTH 6
189 #define ZONE_MINFIELDS 5
190 #define ZONE_MAXFIELDS 9
193 ** Which fields are which on a Zone continuation line.
199 #define ZFC_TILYEAR 3
200 #define ZFC_TILMONTH 4
202 #define ZFC_TILTIME 6
203 #define ZONEC_MINFIELDS 3
204 #define ZONEC_MAXFIELDS 7
207 ** Which files are which on a Rule line.
219 #define RULE_FIELDS 10
222 ** Which fields are which on a Link line.
227 #define LINK_FIELDS 3
230 ** Which fields are which on a Leap line.
239 #define LEAP_FIELDS 7
249 static struct rule
* rules
;
250 static int nrules
; /* number of rules */
251 static int nrules_alloc
;
253 static struct zone
* zones
;
254 static int nzones
; /* number of zones */
255 static int nzones_alloc
;
258 const char * l_filename
;
264 static struct link
* links
;
266 static int nlinks_alloc
;
273 static struct lookup
const * byword(const char * string
,
274 const struct lookup
* lp
);
276 static struct lookup
const line_codes
[] = {
284 static struct lookup
const mon_names
[] = {
285 { "January", TM_JANUARY
},
286 { "February", TM_FEBRUARY
},
287 { "March", TM_MARCH
},
288 { "April", TM_APRIL
},
292 { "August", TM_AUGUST
},
293 { "September", TM_SEPTEMBER
},
294 { "October", TM_OCTOBER
},
295 { "November", TM_NOVEMBER
},
296 { "December", TM_DECEMBER
},
300 static struct lookup
const wday_names
[] = {
301 { "Sunday", TM_SUNDAY
},
302 { "Monday", TM_MONDAY
},
303 { "Tuesday", TM_TUESDAY
},
304 { "Wednesday", TM_WEDNESDAY
},
305 { "Thursday", TM_THURSDAY
},
306 { "Friday", TM_FRIDAY
},
307 { "Saturday", TM_SATURDAY
},
311 static struct lookup
const lasts
[] = {
312 { "last-Sunday", TM_SUNDAY
},
313 { "last-Monday", TM_MONDAY
},
314 { "last-Tuesday", TM_TUESDAY
},
315 { "last-Wednesday", TM_WEDNESDAY
},
316 { "last-Thursday", TM_THURSDAY
},
317 { "last-Friday", TM_FRIDAY
},
318 { "last-Saturday", TM_SATURDAY
},
322 static struct lookup
const begin_years
[] = {
323 { "minimum", YR_MINIMUM
},
324 { "maximum", YR_MAXIMUM
},
328 static struct lookup
const end_years
[] = {
329 { "minimum", YR_MINIMUM
},
330 { "maximum", YR_MAXIMUM
},
335 static struct lookup
const leap_types
[] = {
337 { "Stationary", FALSE
},
341 static const int len_months
[2][MONSPERYEAR
] = {
342 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
343 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
346 static const int len_years
[2] = {
347 DAYSPERNYEAR
, DAYSPERLYEAR
350 static struct attype
{
354 static zic_t gmtoffs
[TZ_MAX_TYPES
];
355 static char isdsts
[TZ_MAX_TYPES
];
356 static unsigned char abbrinds
[TZ_MAX_TYPES
];
357 static char ttisstds
[TZ_MAX_TYPES
];
358 static char ttisgmts
[TZ_MAX_TYPES
];
359 static char chars
[TZ_MAX_CHARS
];
360 static zic_t trans
[TZ_MAX_LEAPS
];
361 static zic_t corr
[TZ_MAX_LEAPS
];
362 static char roll
[TZ_MAX_LEAPS
];
365 ** Memory allocation.
368 static _Noreturn
void
369 memory_exhausted(const char *msg
)
371 fprintf(stderr
, _("%s: Memory exhausted: %s\n"), progname
, msg
);
375 static ATTRIBUTE_PURE
size_t
376 size_product(size_t nitems
, size_t itemsize
)
378 if (SIZE_MAX
/ itemsize
< nitems
)
379 memory_exhausted("size overflow");
380 return nitems
* itemsize
;
383 static ATTRIBUTE_PURE
void *
384 memcheck(void *const ptr
)
387 memory_exhausted(strerror(errno
));
391 #define emalloc(size) memcheck(malloc(size))
392 #define erealloc(ptr, size) memcheck(realloc(ptr, size))
393 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
394 #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
397 growalloc(void *ptr
, size_t itemsize
, int nitems
, int *nitems_alloc
)
399 if (nitems
< *nitems_alloc
)
402 int amax
= INT_MAX
< SIZE_MAX
? INT_MAX
: SIZE_MAX
;
403 if ((amax
- 1) / 3 * 2 < *nitems_alloc
)
404 memory_exhausted("int overflow");
405 *nitems_alloc
= *nitems_alloc
+ (*nitems_alloc
>> 1) + 1;
406 return erealloc(ptr
, size_product(*nitems_alloc
, itemsize
));
415 eats(const char *const name
, const int num
, const char *const rname
,
425 eat(const char *const name
, const int num
)
427 eats(name
, num
, NULL
, -1);
430 static void ATTRIBUTE_FORMAT((printf
, 1, 0))
431 verror(const char *const string
, va_list args
)
434 ** Match the format of "cc" to allow sh users to
435 ** zic ... 2>&1 | error -t "*" -v
438 fprintf(stderr
, _("\"%s\", line %d: "), filename
, linenum
);
439 vfprintf(stderr
, string
, args
);
440 if (rfilename
!= NULL
)
441 (void) fprintf(stderr
, _(" (rule from \"%s\", line %d)"),
442 rfilename
, rlinenum
);
443 (void) fprintf(stderr
, "\n");
447 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
448 error(const char *const string
, ...)
451 va_start(args
, string
);
452 verror(string
, args
);
456 static void ATTRIBUTE_FORMAT((printf
, 1, 2))
457 warning(const char *const string
, ...)
460 fprintf(stderr
, _("warning: "));
461 va_start(args
, string
);
462 verror(string
, args
);
467 static _Noreturn
void
468 usage(FILE *stream
, int status
)
470 (void) fprintf(stream
, _("%s: usage is %s \
471 [ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
472 \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
474 Report bugs to %s.\n"),
475 progname
, progname
, REPORT_BUGS_TO
);
479 static const char * psxrules
;
480 static const char * lcltime
;
481 static const char * directory
;
482 static const char * leapsec
;
483 static const char * yitcommand
;
486 main(int argc
, char **argv
)
493 (void) umask(umask(S_IWGRP
| S_IWOTH
) | (S_IWGRP
| S_IWOTH
));
496 (void) setlocale(LC_ALL
, "");
498 (void) bindtextdomain(TZ_DOMAIN
, TZ_DOMAINDIR
);
499 #endif /* defined TEXTDOMAINDIR */
500 (void) textdomain(TZ_DOMAIN
);
501 #endif /* HAVE_GETTEXT */
503 if (TYPE_BIT(zic_t
) < 64) {
504 (void) fprintf(stderr
, "%s: %s\n", progname
,
505 _("wild compilation-time specification of zic_t"));
508 for (i
= 1; i
< argc
; ++i
)
509 if (strcmp(argv
[i
], "--version") == 0) {
510 (void) printf("zic %s%s\n", PKGVERSION
, TZVERSION
);
512 } else if (strcmp(argv
[i
], "--help") == 0) {
513 usage(stdout
, EXIT_SUCCESS
);
515 while ((c
= getopt(argc
, argv
, "d:l:p:L:vsy:")) != EOF
&& c
!= -1)
518 usage(stderr
, EXIT_FAILURE
);
520 if (directory
== NULL
)
523 (void) fprintf(stderr
,
524 _("%s: More than one -d option specified\n"),
533 (void) fprintf(stderr
,
534 _("%s: More than one -l option specified\n"),
540 if (psxrules
== NULL
)
543 (void) fprintf(stderr
,
544 _("%s: More than one -p option specified\n"),
550 if (yitcommand
== NULL
)
553 (void) fprintf(stderr
,
554 _("%s: More than one -y option specified\n"),
563 (void) fprintf(stderr
,
564 _("%s: More than one -L option specified\n"),
573 (void) printf("%s: -s ignored\n", progname
);
576 if (optind
== argc
- 1 && strcmp(argv
[optind
], "=") == 0)
577 usage(stderr
, EXIT_FAILURE
); /* usage message by request */
578 if (directory
== NULL
)
580 if (yitcommand
== NULL
)
581 yitcommand
= "yearistype";
583 if (optind
< argc
&& leapsec
!= NULL
) {
588 for (i
= optind
; i
< argc
; ++i
)
593 for (i
= 0; i
< nzones
; i
= j
) {
595 ** Find the next non-continuation zone entry.
597 for (j
= i
+ 1; j
< nzones
&& zones
[j
].z_name
== NULL
; ++j
)
599 outzone(&zones
[i
], j
- i
);
604 for (i
= 0; i
< nlinks
; ++i
) {
605 eat(links
[i
].l_filename
, links
[i
].l_linenum
);
606 dolink(links
[i
].l_from
, links
[i
].l_to
);
608 for (j
= 0; j
< nlinks
; ++j
)
609 if (strcmp(links
[i
].l_to
,
610 links
[j
].l_from
) == 0)
611 warning(_("link to link"));
613 if (lcltime
!= NULL
) {
614 eat("command line", 1);
615 dolink(lcltime
, TZDEFAULT
);
617 if (psxrules
!= NULL
) {
618 eat("command line", 1);
619 dolink(psxrules
, TZDEFRULES
);
621 return (errors
== 0) ? EXIT_SUCCESS
: EXIT_FAILURE
;
625 dolink(const char *const fromfield
, const char *const tofield
)
627 register char * fromname
;
628 register char * toname
;
630 if (fromfield
[0] == '/')
631 fromname
= ecpyalloc(fromfield
);
633 fromname
= ecpyalloc(directory
);
634 fromname
= ecatalloc(fromname
, "/");
635 fromname
= ecatalloc(fromname
, fromfield
);
637 if (tofield
[0] == '/')
638 toname
= ecpyalloc(tofield
);
640 toname
= ecpyalloc(directory
);
641 toname
= ecatalloc(toname
, "/");
642 toname
= ecatalloc(toname
, tofield
);
645 ** We get to be careful here since
646 ** there's a fair chance of root running us.
649 (void) remove(toname
);
650 if (link(fromname
, toname
) != 0
651 && access(fromname
, F_OK
) == 0 && !itsdir(fromname
)) {
654 if (mkdirs(toname
) != 0)
657 result
= link(fromname
, toname
);
659 const char *s
= fromfield
;
661 register char * symlinkcontents
= NULL
;
665 while ((s
= strchr(s
, '/'))
666 && ! strncmp (fromfield
, tofield
,
669 for (s
= tofield
+ (t
- fromfield
);
670 (s
= strchr(s
, '/'));
673 ecatalloc(symlinkcontents
,
675 symlinkcontents
= ecatalloc(symlinkcontents
, t
);
676 result
= symlink(symlinkcontents
, toname
);
678 warning(_("hard link failed, symbolic link used"));
679 free(symlinkcontents
);
684 fp
= fopen(fromname
, "rb");
686 const char *e
= strerror(errno
);
687 (void) fprintf(stderr
,
688 _("%s: Can't read %s: %s\n"),
689 progname
, fromname
, e
);
692 tp
= fopen(toname
, "wb");
694 const char *e
= strerror(errno
);
695 (void) fprintf(stderr
,
696 _("%s: Can't create %s: %s\n"),
697 progname
, toname
, e
);
700 while ((c
= getc(fp
)) != EOF
)
702 if (ferror(fp
) || fclose(fp
)) {
703 (void) fprintf(stderr
,
704 _("%s: Error reading %s\n"),
708 if (ferror(tp
) || fclose(tp
)) {
709 (void) fprintf(stderr
,
710 _("%s: Error writing %s\n"),
714 warning(_("link failed, copy used"));
721 #define TIME_T_BITS_IN_FILE 64
723 static const zic_t min_time
= (zic_t
) -1 << (TIME_T_BITS_IN_FILE
- 1);
724 static const zic_t max_time
= -1 - ((zic_t
) -1 << (TIME_T_BITS_IN_FILE
- 1));
726 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
727 rounded downward to the negation of a power of two that is
728 comfortably outside the error bounds.
730 zic does not output time stamps before this, partly because they
731 are physically suspect, and partly because GNOME mishandles them; see
732 GNOME bug 730332 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>.
734 For the time of the Big Bang, see:
736 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
737 I. Overview of products and scientific results.
738 arXiv:1303.5062 2013-03-20 20:10:01 UTC
739 <http://arxiv.org/pdf/1303.5062v1> [PDF]
741 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
742 gives the value 13.798 plus-or-minus 0.037 billion years.
743 Multiplying this by 1000000000 and then by 31557600 (the number of
744 seconds in an astronomical year) gives a value that is comfortably
745 less than 2**59, so BIG_BANG is - 2**59.
747 BIG_BANG is approximate, and may change in future versions.
748 Please do not rely on its exact value. */
751 #define BIG_BANG (- (1LL << 59))
754 static const zic_t big_bang_time
= BIG_BANG
;
757 itsdir(const char *const name
)
759 register char * myname
;
762 myname
= ecpyalloc(name
);
763 myname
= ecatalloc(myname
, "/.");
764 accres
= access(myname
, F_OK
);
770 ** Associate sets of rules with zones.
774 ** Sort by rule name.
778 rcomp(const void *cp1
, const void *cp2
)
780 return strcmp(((const struct rule
*) cp1
)->r_name
,
781 ((const struct rule
*) cp2
)->r_name
);
787 register struct zone
* zp
;
788 register struct rule
* rp
;
789 register int base
, out
;
793 (void) qsort(rules
, nrules
, sizeof *rules
, rcomp
);
794 for (i
= 0; i
< nrules
- 1; ++i
) {
795 if (strcmp(rules
[i
].r_name
,
796 rules
[i
+ 1].r_name
) != 0)
798 if (strcmp(rules
[i
].r_filename
,
799 rules
[i
+ 1].r_filename
) == 0)
801 eat(rules
[i
].r_filename
, rules
[i
].r_linenum
);
802 warning(_("same rule name in multiple files"));
803 eat(rules
[i
+ 1].r_filename
, rules
[i
+ 1].r_linenum
);
804 warning(_("same rule name in multiple files"));
805 for (j
= i
+ 2; j
< nrules
; ++j
) {
806 if (strcmp(rules
[i
].r_name
,
807 rules
[j
].r_name
) != 0)
809 if (strcmp(rules
[i
].r_filename
,
810 rules
[j
].r_filename
) == 0)
812 if (strcmp(rules
[i
+ 1].r_filename
,
813 rules
[j
].r_filename
) == 0)
820 for (i
= 0; i
< nzones
; ++i
) {
825 for (base
= 0; base
< nrules
; base
= out
) {
827 for (out
= base
+ 1; out
< nrules
; ++out
)
828 if (strcmp(rp
->r_name
, rules
[out
].r_name
) != 0)
830 for (i
= 0; i
< nzones
; ++i
) {
832 if (strcmp(zp
->z_rule
, rp
->r_name
) != 0)
835 zp
->z_nrules
= out
- base
;
838 for (i
= 0; i
< nzones
; ++i
) {
840 if (zp
->z_nrules
== 0) {
842 ** Maybe we have a local standard time offset.
844 eat(zp
->z_filename
, zp
->z_linenum
);
845 zp
->z_stdoff
= gethms(zp
->z_rule
, _("unruly zone"),
848 ** Note, though, that if there's no rule,
849 ** a '%s' in the format is a bad thing.
851 if (strchr(zp
->z_format
, '%') != 0)
852 error("%s", _("%s in ruleless zone"));
860 infile(const char *name
)
863 register char ** fields
;
865 register const struct lookup
* lp
;
866 register int nfields
;
867 register int wantcont
;
871 if (strcmp(name
, "-") == 0) {
872 name
= _("standard input");
874 } else if ((fp
= fopen(name
, "r")) == NULL
) {
875 const char *e
= strerror(errno
);
877 (void) fprintf(stderr
, _("%s: Can't open %s: %s\n"),
882 for (num
= 1; ; ++num
) {
884 if (fgets(buf
, sizeof buf
, fp
) != buf
)
886 cp
= strchr(buf
, '\n');
888 error(_("line too long"));
892 fields
= getfields(buf
);
894 while (fields
[nfields
] != NULL
) {
897 if (strcmp(fields
[nfields
], "-") == 0)
898 fields
[nfields
] = &nada
;
903 } else if (wantcont
) {
904 wantcont
= inzcont(fields
, nfields
);
906 lp
= byword(fields
[0], line_codes
);
908 error(_("input line of unknown type"));
909 else switch ((int) (lp
->l_value
)) {
911 inrule(fields
, nfields
);
915 wantcont
= inzone(fields
, nfields
);
918 inlink(fields
, nfields
);
923 (void) fprintf(stderr
,
924 _("%s: Leap line in non leap seconds file %s\n"),
926 else inleap(fields
, nfields
);
929 default: /* "cannot happen" */
930 (void) fprintf(stderr
,
931 _("%s: panic: Invalid l_value %d\n"),
932 progname
, lp
->l_value
);
939 (void) fprintf(stderr
, _("%s: Error reading %s\n"),
943 if (fp
!= stdin
&& fclose(fp
)) {
944 const char *e
= strerror(errno
);
946 (void) fprintf(stderr
, _("%s: Error closing %s: %s\n"),
947 progname
, filename
, e
);
951 error(_("expected continuation line not found"));
955 ** Convert a string of one of the forms
956 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
957 ** into a number of seconds.
958 ** A null string maps to zero.
959 ** Call error with errstring and return zero on errors.
963 gethms(const char *string
, const char *const errstring
, const int signable
)
968 if (string
== NULL
|| *string
== '\0')
972 else if (*string
== '-') {
976 if (sscanf(string
, scheck(string
, "%"SCNdZIC
), &hh
) == 1)
978 else if (sscanf(string
, scheck(string
, "%"SCNdZIC
":%d"), &hh
, &mm
) == 2)
980 else if (sscanf(string
, scheck(string
, "%"SCNdZIC
":%d:%d"),
981 &hh
, &mm
, &ss
) != 3) {
982 error("%s", errstring
);
986 mm
< 0 || mm
>= MINSPERHOUR
||
987 ss
< 0 || ss
> SECSPERMIN
) {
988 error("%s", errstring
);
991 if (ZIC_MAX
/ SECSPERHOUR
< hh
) {
992 error(_("time overflow"));
995 if (noise
&& (hh
> HOURSPERDAY
||
996 (hh
== HOURSPERDAY
&& (mm
!= 0 || ss
!= 0))))
997 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
998 return oadd(sign
* hh
* SECSPERHOUR
,
999 sign
* (mm
* SECSPERMIN
+ ss
));
1003 inrule(register char **const fields
, const int nfields
)
1005 static struct rule r
;
1007 if (nfields
!= RULE_FIELDS
) {
1008 error(_("wrong number of fields on Rule line"));
1011 if (*fields
[RF_NAME
] == '\0') {
1012 error(_("nameless rule"));
1015 r
.r_filename
= filename
;
1016 r
.r_linenum
= linenum
;
1017 r
.r_stdoff
= gethms(fields
[RF_STDOFF
], _("invalid saved time"), TRUE
);
1018 rulesub(&r
, fields
[RF_LOYEAR
], fields
[RF_HIYEAR
], fields
[RF_COMMAND
],
1019 fields
[RF_MONTH
], fields
[RF_DAY
], fields
[RF_TOD
]);
1020 r
.r_name
= ecpyalloc(fields
[RF_NAME
]);
1021 r
.r_abbrvar
= ecpyalloc(fields
[RF_ABBRVAR
]);
1022 if (max_abbrvar_len
< strlen(r
.r_abbrvar
))
1023 max_abbrvar_len
= strlen(r
.r_abbrvar
);
1024 rules
= growalloc(rules
, sizeof *rules
, nrules
, &nrules_alloc
);
1025 rules
[nrules
++] = r
;
1029 inzone(register char **const fields
, const int nfields
)
1033 if (nfields
< ZONE_MINFIELDS
|| nfields
> ZONE_MAXFIELDS
) {
1034 error(_("wrong number of fields on Zone line"));
1037 if (strcmp(fields
[ZF_NAME
], TZDEFAULT
) == 0 && lcltime
!= NULL
) {
1039 _("\"Zone %s\" line and -l option are mutually exclusive"),
1043 if (strcmp(fields
[ZF_NAME
], TZDEFRULES
) == 0 && psxrules
!= NULL
) {
1045 _("\"Zone %s\" line and -p option are mutually exclusive"),
1049 for (i
= 0; i
< nzones
; ++i
)
1050 if (zones
[i
].z_name
!= NULL
&&
1051 strcmp(zones
[i
].z_name
, fields
[ZF_NAME
]) == 0) {
1053 _("duplicate zone name %s (file \"%s\", line %d)"),
1055 zones
[i
].z_filename
,
1056 zones
[i
].z_linenum
);
1059 return inzsub(fields
, nfields
, FALSE
);
1063 inzcont(register char **const fields
, const int nfields
)
1065 if (nfields
< ZONEC_MINFIELDS
|| nfields
> ZONEC_MAXFIELDS
) {
1066 error(_("wrong number of fields on Zone continuation line"));
1069 return inzsub(fields
, nfields
, TRUE
);
1073 inzsub(register char **const fields
, const int nfields
, const int iscont
)
1076 static struct zone z
;
1077 register int i_gmtoff
, i_rule
, i_format
;
1078 register int i_untilyear
, i_untilmonth
;
1079 register int i_untilday
, i_untiltime
;
1080 register int hasuntil
;
1083 i_gmtoff
= ZFC_GMTOFF
;
1085 i_format
= ZFC_FORMAT
;
1086 i_untilyear
= ZFC_TILYEAR
;
1087 i_untilmonth
= ZFC_TILMONTH
;
1088 i_untilday
= ZFC_TILDAY
;
1089 i_untiltime
= ZFC_TILTIME
;
1092 i_gmtoff
= ZF_GMTOFF
;
1094 i_format
= ZF_FORMAT
;
1095 i_untilyear
= ZF_TILYEAR
;
1096 i_untilmonth
= ZF_TILMONTH
;
1097 i_untilday
= ZF_TILDAY
;
1098 i_untiltime
= ZF_TILTIME
;
1099 z
.z_name
= ecpyalloc(fields
[ZF_NAME
]);
1101 z
.z_filename
= filename
;
1102 z
.z_linenum
= linenum
;
1103 z
.z_gmtoff
= gethms(fields
[i_gmtoff
], _("invalid UT offset"), TRUE
);
1104 if ((cp
= strchr(fields
[i_format
], '%')) != 0) {
1105 if (*++cp
!= 's' || strchr(cp
, '%') != 0) {
1106 error(_("invalid abbreviation format"));
1110 z
.z_rule
= ecpyalloc(fields
[i_rule
]);
1111 z
.z_format
= ecpyalloc(fields
[i_format
]);
1112 if (max_format_len
< strlen(z
.z_format
))
1113 max_format_len
= strlen(z
.z_format
);
1114 hasuntil
= nfields
> i_untilyear
;
1116 z
.z_untilrule
.r_filename
= filename
;
1117 z
.z_untilrule
.r_linenum
= linenum
;
1118 rulesub(&z
.z_untilrule
,
1119 fields
[i_untilyear
],
1122 (nfields
> i_untilmonth
) ?
1123 fields
[i_untilmonth
] : "Jan",
1124 (nfields
> i_untilday
) ? fields
[i_untilday
] : "1",
1125 (nfields
> i_untiltime
) ? fields
[i_untiltime
] : "0");
1126 z
.z_untiltime
= rpytime(&z
.z_untilrule
,
1127 z
.z_untilrule
.r_loyear
);
1128 if (iscont
&& nzones
> 0 &&
1129 z
.z_untiltime
> min_time
&&
1130 z
.z_untiltime
< max_time
&&
1131 zones
[nzones
- 1].z_untiltime
> min_time
&&
1132 zones
[nzones
- 1].z_untiltime
< max_time
&&
1133 zones
[nzones
- 1].z_untiltime
>= z
.z_untiltime
) {
1135 "Zone continuation line end time is not after end time of previous line"
1140 zones
= growalloc(zones
, sizeof *zones
, nzones
, &nzones_alloc
);
1141 zones
[nzones
++] = z
;
1143 ** If there was an UNTIL field on this line,
1144 ** there's more information about the zone on the next line.
1150 inleap(register char ** const fields
, const int nfields
)
1152 register const char * cp
;
1153 register const struct lookup
* lp
;
1160 if (nfields
!= LEAP_FIELDS
) {
1161 error(_("wrong number of fields on Leap line"));
1165 cp
= fields
[LP_YEAR
];
1166 if (sscanf(cp
, scheck(cp
, "%"SCNdZIC
), &year
) != 1) {
1170 error(_("invalid leaping year"));
1173 if (!leapseen
|| leapmaxyear
< year
)
1175 if (!leapseen
|| leapminyear
> year
)
1181 i
= len_years
[isleap(j
)];
1185 i
= -len_years
[isleap(j
)];
1187 dayoff
= oadd(dayoff
, i
);
1189 if ((lp
= byword(fields
[LP_MONTH
], mon_names
)) == NULL
) {
1190 error(_("invalid month name"));
1193 month
= lp
->l_value
;
1195 while (j
!= month
) {
1196 i
= len_months
[isleap(year
)][j
];
1197 dayoff
= oadd(dayoff
, i
);
1200 cp
= fields
[LP_DAY
];
1201 if (sscanf(cp
, scheck(cp
, "%d"), &day
) != 1 ||
1202 day
<= 0 || day
> len_months
[isleap(year
)][month
]) {
1203 error(_("invalid day of month"));
1206 dayoff
= oadd(dayoff
, day
- 1);
1207 if (dayoff
< min_time
/ SECSPERDAY
) {
1208 error(_("time too small"));
1211 if (dayoff
> max_time
/ SECSPERDAY
) {
1212 error(_("time too large"));
1215 t
= dayoff
* SECSPERDAY
;
1216 tod
= gethms(fields
[LP_TIME
], _("invalid time of day"), FALSE
);
1217 cp
= fields
[LP_CORR
];
1219 register int positive
;
1222 if (strcmp(cp
, "") == 0) { /* infile() turns "-" into "" */
1225 } else if (strcmp(cp
, "--") == 0) {
1228 } else if (strcmp(cp
, "+") == 0) {
1231 } else if (strcmp(cp
, "++") == 0) {
1235 error(_("illegal CORRECTION field on Leap line"));
1238 if ((lp
= byword(fields
[LP_ROLL
], leap_types
)) == NULL
) {
1240 "illegal Rolling/Stationary field on Leap line"
1245 if (t
< big_bang_time
) {
1246 error(_("leap second precedes Big Bang"));
1249 leapadd(t
, positive
, lp
->l_value
, count
);
1254 inlink(register char **const fields
, const int nfields
)
1258 if (nfields
!= LINK_FIELDS
) {
1259 error(_("wrong number of fields on Link line"));
1262 if (*fields
[LF_FROM
] == '\0') {
1263 error(_("blank FROM field on Link line"));
1266 if (*fields
[LF_TO
] == '\0') {
1267 error(_("blank TO field on Link line"));
1270 l
.l_filename
= filename
;
1271 l
.l_linenum
= linenum
;
1272 l
.l_from
= ecpyalloc(fields
[LF_FROM
]);
1273 l
.l_to
= ecpyalloc(fields
[LF_TO
]);
1274 links
= growalloc(links
, sizeof *links
, nlinks
, &nlinks_alloc
);
1275 links
[nlinks
++] = l
;
1279 rulesub(register struct rule
*const rp
,
1280 const char *const loyearp
,
1281 const char *const hiyearp
,
1282 const char *const typep
,
1283 const char *const monthp
,
1284 const char *const dayp
,
1285 const char *const timep
)
1287 register const struct lookup
* lp
;
1288 register const char * cp
;
1292 if ((lp
= byword(monthp
, mon_names
)) == NULL
) {
1293 error(_("invalid month name"));
1296 rp
->r_month
= lp
->l_value
;
1297 rp
->r_todisstd
= FALSE
;
1298 rp
->r_todisgmt
= FALSE
;
1299 dp
= ecpyalloc(timep
);
1301 ep
= dp
+ strlen(dp
) - 1;
1302 switch (lowerit(*ep
)) {
1303 case 's': /* Standard */
1304 rp
->r_todisstd
= TRUE
;
1305 rp
->r_todisgmt
= FALSE
;
1308 case 'w': /* Wall */
1309 rp
->r_todisstd
= FALSE
;
1310 rp
->r_todisgmt
= FALSE
;
1313 case 'g': /* Greenwich */
1314 case 'u': /* Universal */
1315 case 'z': /* Zulu */
1316 rp
->r_todisstd
= TRUE
;
1317 rp
->r_todisgmt
= TRUE
;
1322 rp
->r_tod
= gethms(dp
, _("invalid time of day"), FALSE
);
1328 lp
= byword(cp
, begin_years
);
1329 rp
->r_lowasnum
= lp
== NULL
;
1330 if (!rp
->r_lowasnum
) switch ((int) lp
->l_value
) {
1332 rp
->r_loyear
= ZIC_MIN
;
1335 rp
->r_loyear
= ZIC_MAX
;
1337 default: /* "cannot happen" */
1338 (void) fprintf(stderr
,
1339 _("%s: panic: Invalid l_value %d\n"),
1340 progname
, lp
->l_value
);
1342 } else if (sscanf(cp
, scheck(cp
, "%"SCNdZIC
), &rp
->r_loyear
) != 1) {
1343 error(_("invalid starting year"));
1347 lp
= byword(cp
, end_years
);
1348 rp
->r_hiwasnum
= lp
== NULL
;
1349 if (!rp
->r_hiwasnum
) switch ((int) lp
->l_value
) {
1351 rp
->r_hiyear
= ZIC_MIN
;
1354 rp
->r_hiyear
= ZIC_MAX
;
1357 rp
->r_hiyear
= rp
->r_loyear
;
1359 default: /* "cannot happen" */
1360 (void) fprintf(stderr
,
1361 _("%s: panic: Invalid l_value %d\n"),
1362 progname
, lp
->l_value
);
1364 } else if (sscanf(cp
, scheck(cp
, "%"SCNdZIC
), &rp
->r_hiyear
) != 1) {
1365 error(_("invalid ending year"));
1368 if (rp
->r_loyear
> rp
->r_hiyear
) {
1369 error(_("starting year greater than ending year"));
1373 rp
->r_yrtype
= NULL
;
1375 if (rp
->r_loyear
== rp
->r_hiyear
) {
1376 error(_("typed single year"));
1379 rp
->r_yrtype
= ecpyalloc(typep
);
1383 ** Accept things such as:
1389 dp
= ecpyalloc(dayp
);
1390 if ((lp
= byword(dp
, lasts
)) != NULL
) {
1391 rp
->r_dycode
= DC_DOWLEQ
;
1392 rp
->r_wday
= lp
->l_value
;
1393 rp
->r_dayofmonth
= len_months
[1][rp
->r_month
];
1395 if ((ep
= strchr(dp
, '<')) != 0)
1396 rp
->r_dycode
= DC_DOWLEQ
;
1397 else if ((ep
= strchr(dp
, '>')) != 0)
1398 rp
->r_dycode
= DC_DOWGEQ
;
1401 rp
->r_dycode
= DC_DOM
;
1403 if (rp
->r_dycode
!= DC_DOM
) {
1406 error(_("invalid day of month"));
1410 if ((lp
= byword(dp
, wday_names
)) == NULL
) {
1411 error(_("invalid weekday name"));
1415 rp
->r_wday
= lp
->l_value
;
1417 if (sscanf(ep
, scheck(ep
, "%d"), &rp
->r_dayofmonth
) != 1 ||
1418 rp
->r_dayofmonth
<= 0 ||
1419 (rp
->r_dayofmonth
> len_months
[1][rp
->r_month
])) {
1420 error(_("invalid day of month"));
1429 convert(const int_fast32_t val
, char *const buf
)
1433 unsigned char *const b
= (unsigned char *) buf
;
1435 for (i
= 0, shift
= 24; i
< 4; ++i
, shift
-= 8)
1436 b
[i
] = val
>> shift
;
1440 convert64(const zic_t val
, char *const buf
)
1444 unsigned char *const b
= (unsigned char *) buf
;
1446 for (i
= 0, shift
= 56; i
< 8; ++i
, shift
-= 8)
1447 b
[i
] = val
>> shift
;
1451 puttzcode(const int_fast32_t val
, FILE *const fp
)
1456 (void) fwrite(buf
, sizeof buf
, 1, fp
);
1460 puttzcode64(const zic_t val
, FILE *const fp
)
1464 convert64(val
, buf
);
1465 (void) fwrite(buf
, sizeof buf
, 1, fp
);
1469 atcomp(const void *avp
, const void *bvp
)
1471 const zic_t a
= ((const struct attype
*) avp
)->at
;
1472 const zic_t b
= ((const struct attype
*) bvp
)->at
;
1474 return (a
< b
) ? -1 : (a
> b
);
1480 return INT32_MIN
<= x
&& x
<= INT32_MAX
;
1484 writezone(const char *const name
, const char *const string
, char version
)
1488 register int leapcnt32
, leapi32
;
1489 register int timecnt32
, timei32
;
1491 static char * fullname
;
1492 static const struct tzhead tzh0
;
1493 static struct tzhead tzh
;
1494 zic_t
*ats
= emalloc(size_product(timecnt
, sizeof *ats
+ 1));
1495 void *typesptr
= ats
+ timecnt
;
1496 unsigned char *types
= typesptr
;
1502 (void) qsort(attypes
, timecnt
, sizeof *attypes
, atcomp
);
1512 while (fromi
< timecnt
&& attypes
[fromi
].at
< big_bang_time
)
1514 for ( ; fromi
< timecnt
; ++fromi
) {
1515 if (toi
> 1 && ((attypes
[fromi
].at
+
1516 gmtoffs
[attypes
[toi
- 1].type
]) <=
1517 (attypes
[toi
- 1].at
+
1518 gmtoffs
[attypes
[toi
- 2].type
]))) {
1519 attypes
[toi
- 1].type
=
1520 attypes
[fromi
].type
;
1524 attypes
[toi
- 1].type
!= attypes
[fromi
].type
)
1525 attypes
[toi
++] = attypes
[fromi
];
1529 if (noise
&& timecnt
> 1200)
1530 warning(_("pre-2014 clients may mishandle"
1531 " more than 1200 transition times"));
1535 for (i
= 0; i
< timecnt
; ++i
) {
1536 ats
[i
] = attypes
[i
].at
;
1537 types
[i
] = attypes
[i
].type
;
1540 ** Correct for leap seconds.
1542 for (i
= 0; i
< timecnt
; ++i
) {
1545 if (ats
[i
] > trans
[j
] - corr
[j
]) {
1546 ats
[i
] = tadd(ats
[i
], corr
[j
]);
1551 ** Figure out 32-bit-limited starts and counts.
1553 timecnt32
= timecnt
;
1555 leapcnt32
= leapcnt
;
1557 while (timecnt32
> 0 && !is32(ats
[timecnt32
- 1]))
1559 while (timecnt32
> 0 && !is32(ats
[timei32
])) {
1564 ** Output an INT32_MIN "transition" if appropriate--see below.
1566 if (timei32
> 0 && ats
[timei32
] > INT32_MIN
) {
1570 while (leapcnt32
> 0 && !is32(trans
[leapcnt32
- 1]))
1572 while (leapcnt32
> 0 && !is32(trans
[leapi32
])) {
1576 fullname
= erealloc(fullname
,
1577 strlen(directory
) + 1 + strlen(name
) + 1);
1578 (void) sprintf(fullname
, "%s/%s", directory
, name
);
1580 ** Remove old file, if any, to snap links.
1582 if (!itsdir(fullname
) && remove(fullname
) != 0 && errno
!= ENOENT
) {
1583 const char *e
= strerror(errno
);
1585 (void) fprintf(stderr
, _("%s: Can't remove %s: %s\n"),
1586 progname
, fullname
, e
);
1589 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1590 if (mkdirs(fullname
) != 0)
1592 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1593 const char *e
= strerror(errno
);
1595 (void) fprintf(stderr
, _("%s: Can't create %s: %s\n"),
1596 progname
, fullname
, e
);
1600 for (pass
= 1; pass
<= 2; ++pass
) {
1601 register int thistimei
, thistimecnt
;
1602 register int thisleapi
, thisleapcnt
;
1603 register int thistimelim
, thisleaplim
;
1604 int writetype
[TZ_MAX_TYPES
];
1605 int typemap
[TZ_MAX_TYPES
];
1606 register int thistypecnt
;
1607 char thischars
[TZ_MAX_CHARS
];
1609 int indmap
[TZ_MAX_CHARS
];
1612 thistimei
= timei32
;
1613 thistimecnt
= timecnt32
;
1614 thisleapi
= leapi32
;
1615 thisleapcnt
= leapcnt32
;
1618 thistimecnt
= timecnt
;
1620 thisleapcnt
= leapcnt
;
1622 thistimelim
= thistimei
+ thistimecnt
;
1623 thisleaplim
= thisleapi
+ thisleapcnt
;
1624 for (i
= 0; i
< typecnt
; ++i
)
1625 writetype
[i
] = thistimecnt
== timecnt
;
1626 if (thistimecnt
== 0) {
1628 ** No transition times fall in the current
1629 ** (32- or 64-bit) window.
1632 writetype
[typecnt
- 1] = TRUE
;
1634 for (i
= thistimei
- 1; i
< thistimelim
; ++i
)
1636 writetype
[types
[i
]] = TRUE
;
1638 ** For America/Godthab and Antarctica/Palmer
1641 writetype
[0] = TRUE
;
1643 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1645 ** For some pre-2011 systems: if the last-to-be-written
1646 ** standard (or daylight) type has an offset different from the
1647 ** most recently used offset,
1648 ** append an (unused) copy of the most recently used type
1649 ** (to help get global "altzone" and "timezone" variables
1653 register int mrudst
, mrustd
, hidst
, histd
, type
;
1655 hidst
= histd
= mrudst
= mrustd
= -1;
1656 for (i
= thistimei
; i
< thistimelim
; ++i
)
1657 if (isdsts
[types
[i
]])
1659 else mrustd
= types
[i
];
1660 for (i
= 0; i
< typecnt
; ++i
)
1666 if (hidst
>= 0 && mrudst
>= 0 && hidst
!= mrudst
&&
1667 gmtoffs
[hidst
] != gmtoffs
[mrudst
]) {
1668 isdsts
[mrudst
] = -1;
1669 type
= addtype(gmtoffs
[mrudst
],
1670 &chars
[abbrinds
[mrudst
]],
1674 isdsts
[mrudst
] = TRUE
;
1675 writetype
[type
] = TRUE
;
1677 if (histd
>= 0 && mrustd
>= 0 && histd
!= mrustd
&&
1678 gmtoffs
[histd
] != gmtoffs
[mrustd
]) {
1679 isdsts
[mrustd
] = -1;
1680 type
= addtype(gmtoffs
[mrustd
],
1681 &chars
[abbrinds
[mrustd
]],
1685 isdsts
[mrustd
] = FALSE
;
1686 writetype
[type
] = TRUE
;
1689 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1691 for (i
= 0; i
< typecnt
; ++i
)
1692 typemap
[i
] = writetype
[i
] ? thistypecnt
++ : -1;
1693 for (i
= 0; i
< sizeof indmap
/ sizeof indmap
[0]; ++i
)
1696 for (i
= 0; i
< typecnt
; ++i
) {
1697 register char * thisabbr
;
1701 if (indmap
[abbrinds
[i
]] >= 0)
1703 thisabbr
= &chars
[abbrinds
[i
]];
1704 for (j
= 0; j
< thischarcnt
; ++j
)
1705 if (strcmp(&thischars
[j
], thisabbr
) == 0)
1707 if (j
== thischarcnt
) {
1708 (void) strcpy(&thischars
[(int) thischarcnt
],
1710 thischarcnt
+= strlen(thisabbr
) + 1;
1712 indmap
[abbrinds
[i
]] = j
;
1714 #define DO(field) ((void) fwrite(tzh.field, sizeof tzh.field, 1, fp))
1716 (void) strncpy(tzh
.tzh_magic
, TZ_MAGIC
, sizeof tzh
.tzh_magic
);
1717 tzh
.tzh_version
[0] = version
;
1718 convert(thistypecnt
, tzh
.tzh_ttisgmtcnt
);
1719 convert(thistypecnt
, tzh
.tzh_ttisstdcnt
);
1720 convert(thisleapcnt
, tzh
.tzh_leapcnt
);
1721 convert(thistimecnt
, tzh
.tzh_timecnt
);
1722 convert(thistypecnt
, tzh
.tzh_typecnt
);
1723 convert(thischarcnt
, tzh
.tzh_charcnt
);
1734 for (i
= thistimei
; i
< thistimelim
; ++i
)
1737 ** Output an INT32_MIN "transition"
1738 ** if appropriate--see above.
1740 puttzcode(((ats
[i
] < INT32_MIN
) ?
1741 INT32_MIN
: ats
[i
]), fp
);
1742 else puttzcode64(ats
[i
], fp
);
1743 for (i
= thistimei
; i
< thistimelim
; ++i
) {
1746 uc
= typemap
[types
[i
]];
1747 (void) fwrite(&uc
, sizeof uc
, 1, fp
);
1749 for (i
= 0; i
< typecnt
; ++i
)
1751 puttzcode(gmtoffs
[i
], fp
);
1752 (void) putc(isdsts
[i
], fp
);
1753 (void) putc((unsigned char) indmap
[abbrinds
[i
]], fp
);
1755 if (thischarcnt
!= 0)
1756 (void) fwrite(thischars
, sizeof thischars
[0],
1758 for (i
= thisleapi
; i
< thisleaplim
; ++i
) {
1759 register zic_t todo
;
1762 if (timecnt
== 0 || trans
[i
] < ats
[0]) {
1765 if (++j
>= typecnt
) {
1771 while (j
< timecnt
&&
1776 todo
= tadd(trans
[i
], -gmtoffs
[j
]);
1777 } else todo
= trans
[i
];
1779 puttzcode(todo
, fp
);
1780 else puttzcode64(todo
, fp
);
1781 puttzcode(corr
[i
], fp
);
1783 for (i
= 0; i
< typecnt
; ++i
)
1785 (void) putc(ttisstds
[i
], fp
);
1786 for (i
= 0; i
< typecnt
; ++i
)
1788 (void) putc(ttisgmts
[i
], fp
);
1790 (void) fprintf(fp
, "\n%s\n", string
);
1791 if (ferror(fp
) || fclose(fp
)) {
1792 (void) fprintf(stderr
, _("%s: Error writing %s\n"),
1793 progname
, fullname
);
1800 doabbr(char *const abbr
, const char *const format
, const char *const letters
,
1801 const int isdst
, const int doquotes
)
1804 register char * slashp
;
1807 slashp
= strchr(format
, '/');
1808 if (slashp
== NULL
) {
1809 if (letters
== NULL
)
1810 (void) strcpy(abbr
, format
);
1811 else (void) sprintf(abbr
, format
, letters
);
1813 (void) strcpy(abbr
, slashp
+ 1);
1815 if (slashp
> format
)
1816 (void) strncpy(abbr
, format
, slashp
- format
);
1817 abbr
[slashp
- format
] = '\0';
1821 for (cp
= abbr
; *cp
!= '\0'; ++cp
)
1822 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp
) == NULL
&&
1823 strchr("abcdefghijklmnopqrstuvwxyz", *cp
) == NULL
)
1826 if (len
> 0 && *cp
== '\0')
1828 abbr
[len
+ 2] = '\0';
1829 abbr
[len
+ 1] = '>';
1830 for ( ; len
> 0; --len
)
1831 abbr
[len
] = abbr
[len
- 1];
1836 updateminmax(const zic_t x
)
1845 stringoffset(char *result
, zic_t offset
)
1848 register int minutes
;
1849 register int seconds
;
1853 (void) strcpy(result
, "-");
1856 seconds
= offset
% SECSPERMIN
;
1857 offset
/= SECSPERMIN
;
1858 minutes
= offset
% MINSPERHOUR
;
1859 offset
/= MINSPERHOUR
;
1861 if (hours
>= HOURSPERDAY
* DAYSPERWEEK
) {
1865 (void) sprintf(end(result
), "%d", hours
);
1866 if (minutes
!= 0 || seconds
!= 0) {
1867 (void) sprintf(end(result
), ":%02d", minutes
);
1869 (void) sprintf(end(result
), ":%02d", seconds
);
1875 stringrule(char *result
, const struct rule
*const rp
, const zic_t dstoff
,
1878 register zic_t tod
= rp
->r_tod
;
1879 register int compat
= 0;
1881 result
= end(result
);
1882 if (rp
->r_dycode
== DC_DOM
) {
1883 register int month
, total
;
1885 if (rp
->r_dayofmonth
== 29 && rp
->r_month
== TM_FEBRUARY
)
1888 for (month
= 0; month
< rp
->r_month
; ++month
)
1889 total
+= len_months
[0][month
];
1890 /* Omit the "J" in Jan and Feb, as that's shorter. */
1891 if (rp
->r_month
<= 1)
1892 (void) sprintf(result
, "%d", total
+ rp
->r_dayofmonth
- 1);
1894 (void) sprintf(result
, "J%d", total
+ rp
->r_dayofmonth
);
1897 register int wday
= rp
->r_wday
;
1898 register int wdayoff
;
1900 if (rp
->r_dycode
== DC_DOWGEQ
) {
1901 wdayoff
= (rp
->r_dayofmonth
- 1) % DAYSPERWEEK
;
1905 tod
+= wdayoff
* SECSPERDAY
;
1906 week
= 1 + (rp
->r_dayofmonth
- 1) / DAYSPERWEEK
;
1907 } else if (rp
->r_dycode
== DC_DOWLEQ
) {
1908 if (rp
->r_dayofmonth
== len_months
[1][rp
->r_month
])
1911 wdayoff
= rp
->r_dayofmonth
% DAYSPERWEEK
;
1915 tod
+= wdayoff
* SECSPERDAY
;
1916 week
= rp
->r_dayofmonth
/ DAYSPERWEEK
;
1918 } else return -1; /* "cannot happen" */
1920 wday
+= DAYSPERWEEK
;
1921 (void) sprintf(result
, "M%d.%d.%d",
1922 rp
->r_month
+ 1, week
, wday
);
1926 if (rp
->r_todisstd
&& rp
->r_stdoff
== 0)
1928 if (tod
!= 2 * SECSPERMIN
* MINSPERHOUR
) {
1929 (void) strcat(result
, "/");
1930 if (stringoffset(end(result
), tod
) != 0)
1935 } else if (SECSPERDAY
<= tod
) {
1944 rule_cmp(struct rule
const *a
, struct rule
const *b
)
1950 if (a
->r_hiyear
!= b
->r_hiyear
)
1951 return a
->r_hiyear
< b
->r_hiyear
? -1 : 1;
1952 if (a
->r_month
- b
->r_month
!= 0)
1953 return a
->r_month
- b
->r_month
;
1954 return a
->r_dayofmonth
- b
->r_dayofmonth
;
1957 enum { YEAR_BY_YEAR_ZONE
= 1 };
1960 stringzone(char *result
, const struct zone
*const zpfirst
, const int zonecount
)
1962 register const struct zone
* zp
;
1963 register struct rule
* rp
;
1964 register struct rule
* stdrp
;
1965 register struct rule
* dstrp
;
1967 register const char * abbrvar
;
1968 register int compat
= 0;
1970 struct rule stdr
, dstr
;
1973 zp
= zpfirst
+ zonecount
- 1;
1974 stdrp
= dstrp
= NULL
;
1975 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
1976 rp
= &zp
->z_rules
[i
];
1977 if (rp
->r_hiwasnum
|| rp
->r_hiyear
!= ZIC_MAX
)
1979 if (rp
->r_yrtype
!= NULL
)
1981 if (rp
->r_stdoff
== 0) {
1991 if (stdrp
== NULL
&& dstrp
== NULL
) {
1993 ** There are no rules running through "max".
1994 ** Find the latest std rule in stdabbrrp
1995 ** and latest rule of any type in stdrp.
1997 register struct rule
*stdabbrrp
= NULL
;
1998 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
1999 rp
= &zp
->z_rules
[i
];
2000 if (rp
->r_stdoff
== 0 && rule_cmp(stdabbrrp
, rp
) < 0)
2002 if (rule_cmp(stdrp
, rp
) < 0)
2006 ** Horrid special case: if year is 2037,
2007 ** presume this is a zone handled on a year-by-year basis;
2008 ** do not try to apply a rule to the zone.
2010 if (stdrp
!= NULL
&& stdrp
->r_hiyear
== 2037)
2011 return YEAR_BY_YEAR_ZONE
;
2013 if (stdrp
!= NULL
&& stdrp
->r_stdoff
!= 0) {
2014 /* Perpetual DST. */
2015 dstr
.r_month
= TM_JANUARY
;
2016 dstr
.r_dycode
= DC_DOM
;
2017 dstr
.r_dayofmonth
= 1;
2019 dstr
.r_todisstd
= dstr
.r_todisgmt
= FALSE
;
2020 dstr
.r_stdoff
= stdrp
->r_stdoff
;
2021 dstr
.r_abbrvar
= stdrp
->r_abbrvar
;
2022 stdr
.r_month
= TM_DECEMBER
;
2023 stdr
.r_dycode
= DC_DOM
;
2024 stdr
.r_dayofmonth
= 31;
2025 stdr
.r_tod
= SECSPERDAY
+ stdrp
->r_stdoff
;
2026 stdr
.r_todisstd
= stdr
.r_todisgmt
= FALSE
;
2029 = (stdabbrrp
? stdabbrrp
->r_abbrvar
: "");
2034 if (stdrp
== NULL
&& (zp
->z_nrules
!= 0 || zp
->z_stdoff
!= 0))
2036 abbrvar
= (stdrp
== NULL
) ? "" : stdrp
->r_abbrvar
;
2037 doabbr(result
, zp
->z_format
, abbrvar
, FALSE
, TRUE
);
2038 if (stringoffset(end(result
), -zp
->z_gmtoff
) != 0) {
2044 doabbr(end(result
), zp
->z_format
, dstrp
->r_abbrvar
, TRUE
, TRUE
);
2045 if (dstrp
->r_stdoff
!= SECSPERMIN
* MINSPERHOUR
)
2046 if (stringoffset(end(result
),
2047 -(zp
->z_gmtoff
+ dstrp
->r_stdoff
)) != 0) {
2051 (void) strcat(result
, ",");
2052 c
= stringrule(result
, dstrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2059 (void) strcat(result
, ",");
2060 c
= stringrule(result
, stdrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
);
2071 outzone(const struct zone
* const zpfirst
, const int zonecount
)
2073 register const struct zone
* zp
;
2074 register struct rule
* rp
;
2076 register int usestart
, useuntil
;
2077 register zic_t starttime
, untiltime
;
2078 register zic_t gmtoff
;
2079 register zic_t stdoff
;
2080 register zic_t year
;
2081 register zic_t startoff
;
2082 register int startttisstd
;
2083 register int startttisgmt
;
2085 register char * startbuf
;
2087 register char * envvar
;
2088 register int max_abbr_len
;
2089 register int max_envvar_len
;
2090 register int prodstic
; /* all rules are min to max */
2091 register int compat
;
2092 register int do_extend
;
2093 register char version
;
2095 max_abbr_len
= 2 + max_format_len
+ max_abbrvar_len
;
2096 max_envvar_len
= 2 * max_abbr_len
+ 5 * 9;
2097 startbuf
= emalloc(max_abbr_len
+ 1);
2098 ab
= emalloc(max_abbr_len
+ 1);
2099 envvar
= emalloc(max_envvar_len
+ 1);
2100 INITIALIZE(untiltime
);
2101 INITIALIZE(starttime
);
2103 ** Now. . .finally. . .generate some useful data!
2108 prodstic
= zonecount
== 1;
2110 ** Thanks to Earl Chew
2111 ** for noting the need to unconditionally initialize startttisstd.
2113 startttisstd
= FALSE
;
2114 startttisgmt
= FALSE
;
2115 min_year
= max_year
= EPOCH_YEAR
;
2117 updateminmax(leapminyear
);
2118 updateminmax(leapmaxyear
+ (leapmaxyear
< ZIC_MAX
));
2120 for (i
= 0; i
< zonecount
; ++i
) {
2122 if (i
< zonecount
- 1)
2123 updateminmax(zp
->z_untilrule
.r_loyear
);
2124 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2125 rp
= &zp
->z_rules
[j
];
2127 updateminmax(rp
->r_loyear
);
2129 updateminmax(rp
->r_hiyear
);
2130 if (rp
->r_lowasnum
|| rp
->r_hiwasnum
)
2135 ** Generate lots of data if a rule can't cover all future times.
2137 compat
= stringzone(envvar
, zpfirst
, zonecount
);
2138 version
= compat
< 2013 ? ZIC_VERSION_PRE_2013
: ZIC_VERSION
;
2139 do_extend
= compat
< 0 || compat
== YEAR_BY_YEAR_ZONE
;
2143 _("no POSIX environment variable for zone"),
2145 else if (compat
!= 0 && compat
!= YEAR_BY_YEAR_ZONE
) {
2146 /* Circa-COMPAT clients, and earlier clients, might
2147 not work for this zone when given dates before
2148 1970 or after 2038. */
2149 warning(_("%s: pre-%d clients may mishandle"
2150 " distant timestamps"),
2151 zpfirst
->z_name
, compat
);
2156 ** Search through a couple of extra years past the obvious
2157 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2158 ** rule applies from 2012 onwards and has transitions in March
2159 ** and September, plus some one-off transitions in November
2160 ** 2013. If zic looked only at the last 400 years, it would
2161 ** set max_year=2413, with the intent that the 400 years 2014
2162 ** through 2413 will be repeated. The last transition listed
2163 ** in the tzfile would be in 2413-09, less than 400 years
2164 ** after the last one-off transition in 2013-11. Two years
2165 ** might be overkill, but with the kind of edge cases
2166 ** available we're not sure that one year would suffice.
2168 enum { years_of_observations
= YEARSPERREPEAT
+ 2 };
2170 if (min_year
>= ZIC_MIN
+ years_of_observations
)
2171 min_year
-= years_of_observations
;
2172 else min_year
= ZIC_MIN
;
2173 if (max_year
<= ZIC_MAX
- years_of_observations
)
2174 max_year
+= years_of_observations
;
2175 else max_year
= ZIC_MAX
;
2177 ** Regardless of any of the above,
2178 ** for a "proDSTic" zone which specifies that its rules
2179 ** always have and always will be in effect,
2180 ** we only need one cycle to define the zone.
2184 max_year
= min_year
+ years_of_observations
;
2188 ** For the benefit of older systems,
2189 ** generate data from 1900 through 2037.
2191 if (min_year
> 1900)
2193 if (max_year
< 2037)
2195 for (i
= 0; i
< zonecount
; ++i
) {
2197 ** A guess that may well be corrected later.
2201 usestart
= i
> 0 && (zp
- 1)->z_untiltime
> big_bang_time
;
2202 useuntil
= i
< (zonecount
- 1);
2203 if (useuntil
&& zp
->z_untiltime
<= big_bang_time
)
2205 gmtoff
= zp
->z_gmtoff
;
2206 eat(zp
->z_filename
, zp
->z_linenum
);
2208 startoff
= zp
->z_gmtoff
;
2209 if (zp
->z_nrules
== 0) {
2210 stdoff
= zp
->z_stdoff
;
2211 doabbr(startbuf
, zp
->z_format
,
2212 NULL
, stdoff
!= 0, FALSE
);
2213 type
= addtype(oadd(zp
->z_gmtoff
, stdoff
),
2214 startbuf
, stdoff
!= 0, startttisstd
,
2217 addtt(starttime
, type
);
2219 } else addtt(big_bang_time
, type
);
2220 } else for (year
= min_year
; year
<= max_year
; ++year
) {
2221 if (useuntil
&& year
> zp
->z_untilrule
.r_hiyear
)
2224 ** Mark which rules to do in the current year.
2225 ** For those to do, calculate rpytime(rp, year);
2227 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2228 rp
= &zp
->z_rules
[j
];
2229 eats(zp
->z_filename
, zp
->z_linenum
,
2230 rp
->r_filename
, rp
->r_linenum
);
2231 rp
->r_todo
= year
>= rp
->r_loyear
&&
2232 year
<= rp
->r_hiyear
&&
2233 yearistype(year
, rp
->r_yrtype
);
2235 rp
->r_temp
= rpytime(rp
, year
);
2239 register zic_t jtime
, ktime
;
2240 register zic_t offset
;
2245 ** Turn untiltime into UT
2246 ** assuming the current gmtoff and
2249 untiltime
= zp
->z_untiltime
;
2250 if (!zp
->z_untilrule
.r_todisgmt
)
2251 untiltime
= tadd(untiltime
,
2253 if (!zp
->z_untilrule
.r_todisstd
)
2254 untiltime
= tadd(untiltime
,
2258 ** Find the rule (of those to do, if any)
2259 ** that takes effect earliest in the year.
2262 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2263 rp
= &zp
->z_rules
[j
];
2266 eats(zp
->z_filename
, zp
->z_linenum
,
2267 rp
->r_filename
, rp
->r_linenum
);
2268 offset
= rp
->r_todisgmt
? 0 : gmtoff
;
2269 if (!rp
->r_todisstd
)
2270 offset
= oadd(offset
, stdoff
);
2272 if (jtime
== min_time
||
2275 jtime
= tadd(jtime
, -offset
);
2276 if (k
< 0 || jtime
< ktime
) {
2282 break; /* go on to next year */
2283 rp
= &zp
->z_rules
[k
];
2285 if (useuntil
&& ktime
>= untiltime
)
2287 stdoff
= rp
->r_stdoff
;
2288 if (usestart
&& ktime
== starttime
)
2291 if (ktime
< starttime
) {
2292 startoff
= oadd(zp
->z_gmtoff
,
2294 doabbr(startbuf
, zp
->z_format
,
2300 if (*startbuf
== '\0' &&
2301 startoff
== oadd(zp
->z_gmtoff
,
2311 eats(zp
->z_filename
, zp
->z_linenum
,
2312 rp
->r_filename
, rp
->r_linenum
);
2313 doabbr(ab
, zp
->z_format
, rp
->r_abbrvar
,
2314 rp
->r_stdoff
!= 0, FALSE
);
2315 offset
= oadd(zp
->z_gmtoff
, rp
->r_stdoff
);
2316 type
= addtype(offset
, ab
, rp
->r_stdoff
!= 0,
2317 rp
->r_todisstd
, rp
->r_todisgmt
);
2322 if (*startbuf
== '\0' &&
2323 zp
->z_format
!= NULL
&&
2324 strchr(zp
->z_format
, '%') == NULL
&&
2325 strchr(zp
->z_format
, '/') == NULL
)
2326 (void) strcpy(startbuf
, zp
->z_format
);
2327 eat(zp
->z_filename
, zp
->z_linenum
);
2328 if (*startbuf
== '\0')
2329 error(_("can't determine time zone abbreviation to use just after until time"));
2330 else addtt(starttime
,
2331 addtype(startoff
, startbuf
,
2332 startoff
!= zp
->z_gmtoff
,
2337 ** Now we may get to set starttime for the next zone line.
2340 startttisstd
= zp
->z_untilrule
.r_todisstd
;
2341 startttisgmt
= zp
->z_untilrule
.r_todisgmt
;
2342 starttime
= zp
->z_untiltime
;
2344 starttime
= tadd(starttime
, -stdoff
);
2346 starttime
= tadd(starttime
, -gmtoff
);
2351 ** If we're extending the explicitly listed observations
2352 ** for 400 years because we can't fill the POSIX-TZ field,
2353 ** check whether we actually ended up explicitly listing
2354 ** observations through that period. If there aren't any
2355 ** near the end of the 400-year period, add a redundant
2356 ** one at the end of the final year, to make it clear
2357 ** that we are claiming to have definite knowledge of
2358 ** the lack of transitions up to that point.
2361 struct attype
*lastat
;
2362 xr
.r_month
= TM_JANUARY
;
2363 xr
.r_dycode
= DC_DOM
;
2364 xr
.r_dayofmonth
= 1;
2366 for (lastat
= &attypes
[0], i
= 1; i
< timecnt
; i
++)
2367 if (attypes
[i
].at
> lastat
->at
)
2368 lastat
= &attypes
[i
];
2369 if (lastat
->at
< rpytime(&xr
, max_year
- 1)) {
2371 ** Create new type code for the redundant entry,
2372 ** to prevent it being optimised away.
2374 if (typecnt
>= TZ_MAX_TYPES
) {
2375 error(_("too many local time types"));
2378 gmtoffs
[typecnt
] = gmtoffs
[lastat
->type
];
2379 isdsts
[typecnt
] = isdsts
[lastat
->type
];
2380 ttisstds
[typecnt
] = ttisstds
[lastat
->type
];
2381 ttisgmts
[typecnt
] = ttisgmts
[lastat
->type
];
2382 abbrinds
[typecnt
] = abbrinds
[lastat
->type
];
2384 addtt(rpytime(&xr
, max_year
+ 1), typecnt
-1);
2387 writezone(zpfirst
->z_name
, envvar
, version
);
2394 addtt(const zic_t starttime
, int type
)
2396 if (starttime
<= big_bang_time
||
2397 (timecnt
== 1 && attypes
[0].at
< big_bang_time
)) {
2398 gmtoffs
[0] = gmtoffs
[type
];
2399 isdsts
[0] = isdsts
[type
];
2400 ttisstds
[0] = ttisstds
[type
];
2401 ttisgmts
[0] = ttisgmts
[type
];
2402 if (abbrinds
[type
] != 0)
2403 (void) strcpy(chars
, &chars
[abbrinds
[type
]]);
2405 charcnt
= strlen(chars
) + 1;
2410 attypes
= growalloc(attypes
, sizeof *attypes
, timecnt
, &timecnt_alloc
);
2411 attypes
[timecnt
].at
= starttime
;
2412 attypes
[timecnt
].type
= type
;
2417 addtype(const zic_t gmtoff
, const char *const abbr
, const int isdst
,
2418 const int ttisstd
, const int ttisgmt
)
2422 if (isdst
!= TRUE
&& isdst
!= FALSE
) {
2423 error(_("internal error - addtype called with bad isdst"));
2426 if (ttisstd
!= TRUE
&& ttisstd
!= FALSE
) {
2427 error(_("internal error - addtype called with bad ttisstd"));
2430 if (ttisgmt
!= TRUE
&& ttisgmt
!= FALSE
) {
2431 error(_("internal error - addtype called with bad ttisgmt"));
2435 ** See if there's already an entry for this zone type.
2436 ** If so, just return its index.
2438 for (i
= 0; i
< typecnt
; ++i
) {
2439 if (gmtoff
== gmtoffs
[i
] && isdst
== isdsts
[i
] &&
2440 strcmp(abbr
, &chars
[abbrinds
[i
]]) == 0 &&
2441 ttisstd
== ttisstds
[i
] &&
2442 ttisgmt
== ttisgmts
[i
])
2446 ** There isn't one; add a new one, unless there are already too
2449 if (typecnt
>= TZ_MAX_TYPES
) {
2450 error(_("too many local time types"));
2453 if (! (-1L - 2147483647L <= gmtoff
&& gmtoff
<= 2147483647L)) {
2454 error(_("UT offset out of range"));
2457 gmtoffs
[i
] = gmtoff
;
2459 ttisstds
[i
] = ttisstd
;
2460 ttisgmts
[i
] = ttisgmt
;
2462 for (j
= 0; j
< charcnt
; ++j
)
2463 if (strcmp(&chars
[j
], abbr
) == 0)
2473 leapadd(const zic_t t
, const int positive
, const int rolling
, int count
)
2477 if (leapcnt
+ (positive
? count
: 1) > TZ_MAX_LEAPS
) {
2478 error(_("too many leap seconds"));
2481 for (i
= 0; i
< leapcnt
; ++i
)
2482 if (t
<= trans
[i
]) {
2483 if (t
== trans
[i
]) {
2484 error(_("repeated leap second moment"));
2490 for (j
= leapcnt
; j
> i
; --j
) {
2491 trans
[j
] = trans
[j
- 1];
2492 corr
[j
] = corr
[j
- 1];
2493 roll
[j
] = roll
[j
- 1];
2496 corr
[i
] = positive
? 1 : -count
;
2499 } while (positive
&& --count
!= 0);
2506 register zic_t last
= 0;
2509 ** propagate leap seconds forward
2511 for (i
= 0; i
< leapcnt
; ++i
) {
2512 trans
[i
] = tadd(trans
[i
], last
);
2513 last
= corr
[i
] += last
;
2518 yearistype(const int year
, const char *const type
)
2523 if (type
== NULL
|| *type
== '\0')
2525 buf
= erealloc(buf
, 132 + strlen(yitcommand
) + strlen(type
));
2526 (void) sprintf(buf
, "%s %d %s", yitcommand
, year
, type
);
2527 result
= system(buf
);
2528 if (WIFEXITED(result
)) switch (WEXITSTATUS(result
)) {
2534 error(_("Wild result from command execution"));
2535 (void) fprintf(stderr
, _("%s: command was '%s', result was %d\n"),
2536 progname
, buf
, result
);
2544 a
= (unsigned char) a
;
2545 return (isascii(a
) && isupper(a
)) ? tolower(a
) : a
;
2548 /* case-insensitive equality */
2549 static ATTRIBUTE_PURE
int
2550 ciequal(register const char *ap
, register const char *bp
)
2552 while (lowerit(*ap
) == lowerit(*bp
++))
2558 static ATTRIBUTE_PURE
int
2559 itsabbr(register const char *abbr
, register const char *word
)
2561 if (lowerit(*abbr
) != lowerit(*word
))
2564 while (*++abbr
!= '\0')
2568 } while (lowerit(*word
++) != lowerit(*abbr
));
2572 static ATTRIBUTE_PURE
const struct lookup
*
2573 byword(register const char *const word
,
2574 register const struct lookup
*const table
)
2576 register const struct lookup
* foundlp
;
2577 register const struct lookup
* lp
;
2579 if (word
== NULL
|| table
== NULL
)
2582 ** Look for exact match.
2584 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2585 if (ciequal(word
, lp
->l_word
))
2588 ** Look for inexact match.
2591 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2592 if (itsabbr(word
, lp
->l_word
)) {
2593 if (foundlp
== NULL
)
2595 else return NULL
; /* multiple inexact matches */
2601 getfields(register char *cp
)
2604 register char ** array
;
2609 array
= emalloc(size_product(strlen(cp
) + 1, sizeof *array
));
2612 while (isascii((unsigned char) *cp
) &&
2613 isspace((unsigned char) *cp
))
2615 if (*cp
== '\0' || *cp
== '#')
2617 array
[nsubs
++] = dp
= cp
;
2619 if ((*dp
= *cp
++) != '"')
2621 else while ((*dp
= *cp
++) != '"')
2626 "Odd number of quotation marks"
2630 } while (*cp
!= '\0' && *cp
!= '#' &&
2631 (!isascii(*cp
) || !isspace((unsigned char) *cp
)));
2632 if (isascii(*cp
) && isspace((unsigned char) *cp
))
2636 array
[nsubs
] = NULL
;
2640 static ATTRIBUTE_PURE zic_t
2641 oadd(const zic_t t1
, const zic_t t2
)
2643 if (t1
< 0 ? t2
< ZIC_MIN
- t1
: ZIC_MAX
- t1
< t2
) {
2644 error(_("time overflow"));
2650 static ATTRIBUTE_PURE zic_t
2651 tadd(const zic_t t1
, const zic_t t2
)
2653 if (t1
== max_time
&& t2
> 0)
2655 if (t1
== min_time
&& t2
< 0)
2657 if (t1
< 0 ? t2
< min_time
- t1
: max_time
- t1
< t2
) {
2658 error(_("time overflow"));
2665 ** Given a rule, and a year, compute the date - in seconds since January 1,
2666 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2670 rpytime(register const struct rule
*const rp
, register const zic_t wantedy
)
2673 register zic_t dayoff
; /* with a nod to Margaret O. */
2674 register zic_t t
, y
;
2676 if (wantedy
== ZIC_MIN
)
2678 if (wantedy
== ZIC_MAX
)
2683 while (wantedy
!= y
) {
2685 i
= len_years
[isleap(y
)];
2689 i
= -len_years
[isleap(y
)];
2691 dayoff
= oadd(dayoff
, i
);
2693 while (m
!= rp
->r_month
) {
2694 i
= len_months
[isleap(y
)][m
];
2695 dayoff
= oadd(dayoff
, i
);
2698 i
= rp
->r_dayofmonth
;
2699 if (m
== TM_FEBRUARY
&& i
== 29 && !isleap(y
)) {
2700 if (rp
->r_dycode
== DC_DOWLEQ
)
2703 error(_("use of 2/29 in non leap-year"));
2708 dayoff
= oadd(dayoff
, i
);
2709 if (rp
->r_dycode
== DC_DOWGEQ
|| rp
->r_dycode
== DC_DOWLEQ
) {
2710 register zic_t wday
;
2712 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
2715 ** Don't trust mod of negative numbers.
2718 wday
= (wday
+ dayoff
) % LDAYSPERWEEK
;
2720 wday
-= ((-dayoff
) % LDAYSPERWEEK
);
2722 wday
+= LDAYSPERWEEK
;
2724 while (wday
!= rp
->r_wday
)
2725 if (rp
->r_dycode
== DC_DOWGEQ
) {
2726 dayoff
= oadd(dayoff
, 1);
2727 if (++wday
>= LDAYSPERWEEK
)
2731 dayoff
= oadd(dayoff
, -1);
2733 wday
= LDAYSPERWEEK
- 1;
2736 if (i
< 0 || i
>= len_months
[isleap(y
)][m
]) {
2738 warning(_("rule goes past start/end of month--\
2739 will not work with pre-2004 versions of zic"));
2742 if (dayoff
< min_time
/ SECSPERDAY
)
2744 if (dayoff
> max_time
/ SECSPERDAY
)
2746 t
= (zic_t
) dayoff
* SECSPERDAY
;
2747 return tadd(t
, rp
->r_tod
);
2751 newabbr(const char *const string
)
2755 if (strcmp(string
, GRANDPARENTED
) != 0) {
2756 register const char * cp
;
2760 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2761 ** optionally followed by a + or - and a number from 1 to 14.
2765 while (isascii((unsigned char) *cp
) &&
2766 isalpha((unsigned char) *cp
))
2768 if (cp
- string
== 0)
2769 mp
= _("time zone abbreviation lacks alphabetic at start");
2770 if (noise
&& cp
- string
< 3)
2771 mp
= _("time zone abbreviation has fewer than 3 alphabetics");
2772 if (cp
- string
> ZIC_MAX_ABBR_LEN_WO_WARN
)
2773 mp
= _("time zone abbreviation has too many alphabetics");
2774 if (mp
== NULL
&& (*cp
== '+' || *cp
== '-')) {
2776 if (isascii((unsigned char) *cp
) &&
2777 isdigit((unsigned char) *cp
))
2779 *cp
>= '0' && *cp
<= '4')
2783 mp
= _("time zone abbreviation differs from POSIX standard");
2785 warning("%s (%s)", mp
, string
);
2787 i
= strlen(string
) + 1;
2788 if (charcnt
+ i
> TZ_MAX_CHARS
) {
2789 error(_("too many, or too long, time zone abbreviations"));
2792 (void) strcpy(&chars
[charcnt
], string
);
2797 mkdirs(char *argname
)
2799 register char * name
;
2802 if (argname
== NULL
|| *argname
== '\0')
2804 cp
= name
= ecpyalloc(argname
);
2805 while ((cp
= strchr(cp
+ 1, '/')) != 0) {
2807 #ifdef HAVE_DOS_FILE_NAMES
2809 ** DOS drive specifier?
2811 if (isalpha((unsigned char) name
[0]) &&
2812 name
[1] == ':' && name
[2] == '\0') {
2817 if (!itsdir(name
)) {
2819 ** It doesn't seem to exist, so we try to create it.
2820 ** Creation may fail because of the directory being
2821 ** created by some other multiprocessor, so we get
2822 ** to do extra checking.
2824 if (mkdir(name
, MKDIR_UMASK
) != 0) {
2825 const char *e
= strerror(errno
);
2827 if (errno
!= EEXIST
|| !itsdir(name
)) {
2828 (void) fprintf(stderr
,
2829 _("%s: Can't create directory %s: %s\n"),
2843 ** UNIX was a registered trademark of The Open Group in 2003.