2 ** This file is in the public domain, so clarified as of
3 ** 2006-07-17 by Arthur David Olson.
6 static char elsieid
[] = "@(#)zic.c 8.8";
12 #define ZIC_VERSION '2'
14 typedef int_fast64_t zic_t
;
16 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
17 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
18 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
24 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
26 #define MKDIR_UMASK 0755
30 ** On some ancient hosts, predicates like `isspace(C)' are defined
31 ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
32 ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
33 ** Neither the C Standard nor Posix require that `isascii' exist.
34 ** For portability, we check both ancient and modern requirements.
35 ** If isascii is not defined, the isascii check succeeds trivially.
42 #define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
43 #define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
45 #define end(cp) (strchr((cp), '\0'))
48 const char * r_filename
;
52 int r_loyear
; /* for example, 1986 */
53 int r_hiyear
; /* for example, 1986 */
54 const char * r_yrtype
;
58 int r_month
; /* 0..11 */
60 int r_dycode
; /* see below */
64 long r_tod
; /* time from midnight */
65 int r_todisstd
; /* above is standard time if TRUE */
66 /* or wall clock time if FALSE */
67 int r_todisgmt
; /* above is GMT if TRUE */
68 /* or local time if FALSE */
69 long r_stdoff
; /* offset from standard time */
70 const char * r_abbrvar
; /* variable part of abbreviation */
72 int r_todo
; /* a rule to do (used in outzone) */
73 zic_t r_temp
; /* used in outzone */
77 ** r_dycode r_dayofmonth r_wday
80 #define DC_DOM 0 /* 1..31 */ /* unused */
81 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
82 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
85 const char * z_filename
;
91 const char * z_format
;
95 struct rule
* z_rules
;
98 struct rule z_untilrule
;
102 extern int getopt
P((int argc
, char * const argv
[],
103 const char * options
));
104 extern int link
P((const char * fromname
, const char * toname
));
105 extern char * optarg
;
108 static void addtt
P((zic_t starttime
, int type
));
109 static int addtype
P((long gmtoff
, const char * abbr
, int isdst
,
110 int ttisstd
, int ttisgmt
));
111 static void leapadd
P((zic_t t
, int positive
, int rolling
, int count
));
112 static void adjleap
P((void));
113 static void associate
P((void));
114 static int ciequal
P((const char * ap
, const char * bp
));
115 static void convert
P((long val
, char * buf
));
116 static void convert64
P((zic_t val
, char * buf
));
117 static void dolink
P((const char * fromfile
, const char * tofile
));
118 static void doabbr
P((char * abbr
, const char * format
,
119 const char * letters
, int isdst
, int doquotes
));
120 static void eat
P((const char * name
, int num
));
121 static void eats
P((const char * name
, int num
,
122 const char * rname
, int rnum
));
123 static long eitol
P((int i
));
124 static void error
P((const char * message
));
125 static char ** getfields
P((char * buf
));
126 static long gethms
P((const char * string
, const char * errstrng
,
128 static void infile
P((const char * filename
));
129 static void inleap
P((char ** fields
, int nfields
));
130 static void inlink
P((char ** fields
, int nfields
));
131 static void inrule
P((char ** fields
, int nfields
));
132 static int inzcont
P((char ** fields
, int nfields
));
133 static int inzone
P((char ** fields
, int nfields
));
134 static int inzsub
P((char ** fields
, int nfields
, int iscont
));
135 static int is32
P((zic_t x
));
136 static int itsabbr
P((const char * abbr
, const char * word
));
137 static int itsdir
P((const char * name
));
138 static int lowerit
P((int c
));
139 static char * memcheck
P((char * tocheck
));
140 static int mkdirs
P((char * filename
));
141 static void newabbr
P((const char * abbr
));
142 static long oadd
P((long t1
, long t2
));
143 static void outzone
P((const struct zone
* zp
, int ntzones
));
144 static void puttzcode
P((long code
, FILE * fp
));
145 static void puttzcode64
P((zic_t code
, FILE * fp
));
146 static int rcomp
P((const void * leftp
, const void * rightp
));
147 static zic_t rpytime
P((const struct rule
* rp
, int wantedy
));
148 static void rulesub
P((struct rule
* rp
,
149 const char * loyearp
, const char * hiyearp
,
150 const char * typep
, const char * monthp
,
151 const char * dayp
, const char * timep
));
152 static int stringoffset
P((char * result
, long offset
));
153 static int stringrule
P((char * result
, const struct rule
* rp
,
154 long dstoff
, long gmtoff
));
155 static void stringzone
P((char * result
,
156 const struct zone
* zp
, int ntzones
));
157 static void setboundaries
P((void));
158 static zic_t tadd
P((zic_t t1
, long t2
));
159 static void usage
P((void));
160 static void writezone
P((const char * name
, const char * string
));
161 static int yearistype
P((int year
, const char * type
));
164 static char * strerror
P((int));
165 #endif /* !HAVE_STRERROR */
169 static const char * filename
;
172 static int leapminyear
;
173 static int leapmaxyear
;
175 static int max_abbrvar_len
;
176 static int max_format_len
;
177 static zic_t max_time
;
179 static zic_t min_time
;
182 static const char * rfilename
;
184 static const char * progname
;
198 ** Which fields are which on a Zone line.
206 #define ZF_TILMONTH 6
209 #define ZONE_MINFIELDS 5
210 #define ZONE_MAXFIELDS 9
213 ** Which fields are which on a Zone continuation line.
219 #define ZFC_TILYEAR 3
220 #define ZFC_TILMONTH 4
222 #define ZFC_TILTIME 6
223 #define ZONEC_MINFIELDS 3
224 #define ZONEC_MAXFIELDS 7
227 ** Which files are which on a Rule line.
239 #define RULE_FIELDS 10
242 ** Which fields are which on a Link line.
247 #define LINK_FIELDS 3
250 ** Which fields are which on a Leap line.
259 #define LEAP_FIELDS 7
269 static struct rule
* rules
;
270 static int nrules
; /* number of rules */
272 static struct zone
* zones
;
273 static int nzones
; /* number of zones */
276 const char * l_filename
;
282 static struct link
* links
;
290 static struct lookup
const * byword
P((const char * string
,
291 const struct lookup
* lp
));
293 static struct lookup
const line_codes
[] = {
301 static struct lookup
const mon_names
[] = {
302 { "January", TM_JANUARY
},
303 { "February", TM_FEBRUARY
},
304 { "March", TM_MARCH
},
305 { "April", TM_APRIL
},
309 { "August", TM_AUGUST
},
310 { "September", TM_SEPTEMBER
},
311 { "October", TM_OCTOBER
},
312 { "November", TM_NOVEMBER
},
313 { "December", TM_DECEMBER
},
317 static struct lookup
const wday_names
[] = {
318 { "Sunday", TM_SUNDAY
},
319 { "Monday", TM_MONDAY
},
320 { "Tuesday", TM_TUESDAY
},
321 { "Wednesday", TM_WEDNESDAY
},
322 { "Thursday", TM_THURSDAY
},
323 { "Friday", TM_FRIDAY
},
324 { "Saturday", TM_SATURDAY
},
328 static struct lookup
const lasts
[] = {
329 { "last-Sunday", TM_SUNDAY
},
330 { "last-Monday", TM_MONDAY
},
331 { "last-Tuesday", TM_TUESDAY
},
332 { "last-Wednesday", TM_WEDNESDAY
},
333 { "last-Thursday", TM_THURSDAY
},
334 { "last-Friday", TM_FRIDAY
},
335 { "last-Saturday", TM_SATURDAY
},
339 static struct lookup
const begin_years
[] = {
340 { "minimum", YR_MINIMUM
},
341 { "maximum", YR_MAXIMUM
},
345 static struct lookup
const end_years
[] = {
346 { "minimum", YR_MINIMUM
},
347 { "maximum", YR_MAXIMUM
},
352 static struct lookup
const leap_types
[] = {
354 { "Stationary", FALSE
},
358 static const int len_months
[2][MONSPERYEAR
] = {
359 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
360 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
363 static const int len_years
[2] = {
364 DAYSPERNYEAR
, DAYSPERLYEAR
367 static struct attype
{
370 } attypes
[TZ_MAX_TIMES
];
371 static long gmtoffs
[TZ_MAX_TYPES
];
372 static char isdsts
[TZ_MAX_TYPES
];
373 static unsigned char abbrinds
[TZ_MAX_TYPES
];
374 static char ttisstds
[TZ_MAX_TYPES
];
375 static char ttisgmts
[TZ_MAX_TYPES
];
376 static char chars
[TZ_MAX_CHARS
];
377 static zic_t trans
[TZ_MAX_LEAPS
];
378 static long corr
[TZ_MAX_LEAPS
];
379 static char roll
[TZ_MAX_LEAPS
];
382 ** Memory allocation.
390 const char *e
= strerror(errno
);
392 (void) fprintf(stderr
, _("%s: Memory exhausted: %s\n"),
399 #define emalloc(size) memcheck(imalloc(size))
400 #define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
401 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
402 #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
413 extern char * sys_errlist
[];
416 return (errnum
> 0 && errnum
<= sys_nerr
) ?
417 sys_errlist
[errnum
] : _("Unknown system error");
419 #endif /* !HAVE_STRERROR */
422 eats(name
, num
, rname
, rnum
)
423 const char * const name
;
425 const char * const rname
;
436 const char * const name
;
439 eats(name
, num
, (char *) NULL
, -1);
444 const char * const string
;
447 ** Match the format of "cc" to allow sh users to
448 ** zic ... 2>&1 | error -t "*" -v
451 (void) fprintf(stderr
, _("\"%s\", line %d: %s"),
452 filename
, linenum
, string
);
453 if (rfilename
!= NULL
)
454 (void) fprintf(stderr
, _(" (rule from \"%s\", line %d)"),
455 rfilename
, rlinenum
);
456 (void) fprintf(stderr
, "\n");
462 const char * const string
;
466 cp
= ecpyalloc(_("warning: "));
467 cp
= ecatalloc(cp
, string
);
476 (void) fprintf(stderr
, _("%s: usage is %s \
477 [ --version ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
478 \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
483 static const char * psxrules
;
484 static const char * lcltime
;
485 static const char * directory
;
486 static const char * leapsec
;
487 static const char * yitcommand
;
499 (void) umask(umask(S_IWGRP
| S_IWOTH
) | (S_IWGRP
| S_IWOTH
));
500 #endif /* defined unix */
502 (void) setlocale(LC_ALL
, "");
504 (void) bindtextdomain(TZ_DOMAIN
, TZ_DOMAINDIR
);
505 #endif /* defined TEXTDOMAINDIR */
506 (void) textdomain(TZ_DOMAIN
);
507 #endif /* HAVE_GETTEXT */
509 if (TYPE_BIT(zic_t
) < 64) {
510 (void) fprintf(stderr
, "%s: %s\n", progname
,
511 _("wild compilation-time specification of zic_t"));
514 for (i
= 1; i
< argc
; ++i
)
515 if (strcmp(argv
[i
], "--version") == 0) {
516 (void) printf("%s\n", elsieid
);
519 while ((c
= getopt(argc
, argv
, "d:l:p:L:vsy:")) != EOF
&& c
!= -1)
524 if (directory
== NULL
)
527 (void) fprintf(stderr
,
528 _("%s: More than one -d option specified\n"),
537 (void) fprintf(stderr
,
538 _("%s: More than one -l option specified\n"),
544 if (psxrules
== NULL
)
547 (void) fprintf(stderr
,
548 _("%s: More than one -p option specified\n"),
554 if (yitcommand
== NULL
)
557 (void) fprintf(stderr
,
558 _("%s: More than one -y option specified\n"),
567 (void) fprintf(stderr
,
568 _("%s: More than one -L option specified\n"),
577 (void) printf("%s: -s ignored\n", progname
);
580 if (optind
== argc
- 1 && strcmp(argv
[optind
], "=") == 0)
581 usage(); /* usage message by request */
582 if (directory
== NULL
)
584 if (yitcommand
== NULL
)
585 yitcommand
= "yearistype";
589 if (optind
< argc
&& leapsec
!= NULL
) {
594 for (i
= optind
; i
< argc
; ++i
)
599 for (i
= 0; i
< nzones
; i
= j
) {
601 ** Find the next non-continuation zone entry.
603 for (j
= i
+ 1; j
< nzones
&& zones
[j
].z_name
== NULL
; ++j
)
605 outzone(&zones
[i
], j
- i
);
610 for (i
= 0; i
< nlinks
; ++i
) {
611 eat(links
[i
].l_filename
, links
[i
].l_linenum
);
612 dolink(links
[i
].l_from
, links
[i
].l_to
);
614 for (j
= 0; j
< nlinks
; ++j
)
615 if (strcmp(links
[i
].l_to
,
616 links
[j
].l_from
) == 0)
617 warning(_("link to link"));
619 if (lcltime
!= NULL
) {
620 eat("command line", 1);
621 dolink(lcltime
, TZDEFAULT
);
623 if (psxrules
!= NULL
) {
624 eat("command line", 1);
625 dolink(psxrules
, TZDEFRULES
);
627 return (errors
== 0) ? EXIT_SUCCESS
: EXIT_FAILURE
;
631 dolink(fromfile
, tofile
)
632 const char * const fromfile
;
633 const char * const tofile
;
635 register char * fromname
;
636 register char * toname
;
638 if (fromfile
[0] == '/')
639 fromname
= ecpyalloc(fromfile
);
641 fromname
= ecpyalloc(directory
);
642 fromname
= ecatalloc(fromname
, "/");
643 fromname
= ecatalloc(fromname
, fromfile
);
645 if (tofile
[0] == '/')
646 toname
= ecpyalloc(tofile
);
648 toname
= ecpyalloc(directory
);
649 toname
= ecatalloc(toname
, "/");
650 toname
= ecatalloc(toname
, tofile
);
653 ** We get to be careful here since
654 ** there's a fair chance of root running us.
657 (void) remove(toname
);
658 if (link(fromname
, toname
) != 0) {
661 if (mkdirs(toname
) != 0)
664 result
= link(fromname
, toname
);
667 access(fromname
, F_OK
) == 0 &&
669 const char *s
= tofile
;
670 register char * symlinkcontents
= NULL
;
672 while ((s
= strchr(s
+1, '/')) != NULL
)
674 ecatalloc(symlinkcontents
,
677 ecatalloc(symlinkcontents
,
679 result
= symlink(symlinkcontents
,
682 //warning(_("hard link failed, symbolic link used"));
683 ifree(symlinkcontents
);
685 #endif /* HAVE_SYMLINK */
687 const char *e
= strerror(errno
);
689 (void) fprintf(stderr
,
690 _("%s: Can't link from %s to %s: %s\n"),
691 progname
, fromname
, toname
, e
);
699 #define TIME_T_BITS_IN_FILE 64
702 setboundaries
P((void))
707 for (i
= 0; i
< TIME_T_BITS_IN_FILE
- 1; ++i
)
709 max_time
= -(min_time
+ 1);
714 const char * const name
;
716 register char * myname
;
719 myname
= ecpyalloc(name
);
720 myname
= ecatalloc(myname
, "/.");
721 accres
= access(myname
, F_OK
);
727 ** Associate sets of rules with zones.
731 ** Sort by rule name.
739 return strcmp(((const struct rule
*) cp1
)->r_name
,
740 ((const struct rule
*) cp2
)->r_name
);
746 register struct zone
* zp
;
747 register struct rule
* rp
;
748 register int base
, out
;
752 (void) qsort((void *) rules
, (size_t) nrules
,
753 (size_t) sizeof *rules
, rcomp
);
754 for (i
= 0; i
< nrules
- 1; ++i
) {
755 if (strcmp(rules
[i
].r_name
,
756 rules
[i
+ 1].r_name
) != 0)
758 if (strcmp(rules
[i
].r_filename
,
759 rules
[i
+ 1].r_filename
) == 0)
761 eat(rules
[i
].r_filename
, rules
[i
].r_linenum
);
762 warning(_("same rule name in multiple files"));
763 eat(rules
[i
+ 1].r_filename
, rules
[i
+ 1].r_linenum
);
764 warning(_("same rule name in multiple files"));
765 for (j
= i
+ 2; j
< nrules
; ++j
) {
766 if (strcmp(rules
[i
].r_name
,
767 rules
[j
].r_name
) != 0)
769 if (strcmp(rules
[i
].r_filename
,
770 rules
[j
].r_filename
) == 0)
772 if (strcmp(rules
[i
+ 1].r_filename
,
773 rules
[j
].r_filename
) == 0)
780 for (i
= 0; i
< nzones
; ++i
) {
785 for (base
= 0; base
< nrules
; base
= out
) {
787 for (out
= base
+ 1; out
< nrules
; ++out
)
788 if (strcmp(rp
->r_name
, rules
[out
].r_name
) != 0)
790 for (i
= 0; i
< nzones
; ++i
) {
792 if (strcmp(zp
->z_rule
, rp
->r_name
) != 0)
795 zp
->z_nrules
= out
- base
;
798 for (i
= 0; i
< nzones
; ++i
) {
800 if (zp
->z_nrules
== 0) {
802 ** Maybe we have a local standard time offset.
804 eat(zp
->z_filename
, zp
->z_linenum
);
805 zp
->z_stdoff
= gethms(zp
->z_rule
, _("unruly zone"),
808 ** Note, though, that if there's no rule,
809 ** a '%s' in the format is a bad thing.
811 if (strchr(zp
->z_format
, '%') != 0)
812 error(_("%s in ruleless zone"));
824 register char ** fields
;
826 register const struct lookup
* lp
;
827 register int nfields
;
828 register int wantcont
;
832 if (strcmp(name
, "-") == 0) {
833 name
= _("standard input");
835 } else if ((fp
= fopen(name
, "r")) == NULL
) {
836 const char *e
= strerror(errno
);
838 (void) fprintf(stderr
, _("%s: Can't open %s: %s\n"),
843 for (num
= 1; ; ++num
) {
845 if (fgets(buf
, (int) sizeof buf
, fp
) != buf
)
847 cp
= strchr(buf
, '\n');
849 error(_("line too long"));
853 fields
= getfields(buf
);
855 while (fields
[nfields
] != NULL
) {
858 if (strcmp(fields
[nfields
], "-") == 0)
859 fields
[nfields
] = &nada
;
864 } else if (wantcont
) {
865 wantcont
= inzcont(fields
, nfields
);
867 lp
= byword(fields
[0], line_codes
);
869 error(_("input line of unknown type"));
870 else switch ((int) (lp
->l_value
)) {
872 inrule(fields
, nfields
);
876 wantcont
= inzone(fields
, nfields
);
879 inlink(fields
, nfields
);
884 (void) fprintf(stderr
,
885 _("%s: Leap line in non leap seconds file %s\n"),
887 else inleap(fields
, nfields
);
890 default: /* "cannot happen" */
891 (void) fprintf(stderr
,
892 _("%s: panic: Invalid l_value %d\n"),
893 progname
, lp
->l_value
);
897 ifree((char *) fields
);
900 (void) fprintf(stderr
, _("%s: Error reading %s\n"),
904 if (fp
!= stdin
&& fclose(fp
)) {
905 const char *e
= strerror(errno
);
907 (void) fprintf(stderr
, _("%s: Error closing %s: %s\n"),
908 progname
, filename
, e
);
912 error(_("expected continuation line not found"));
916 ** Convert a string of one of the forms
917 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
918 ** into a number of seconds.
919 ** A null string maps to zero.
920 ** Call error with errstring and return zero on errors.
924 gethms(string
, errstring
, signable
)
926 const char * const errstring
;
929 int hh
, mm
, ss
, sign
;
931 if (string
== NULL
|| *string
== '\0')
935 else if (*string
== '-') {
939 if (sscanf(string
, scheck(string
, "%d"), &hh
) == 1)
941 else if (sscanf(string
, scheck(string
, "%d:%d"), &hh
, &mm
) == 2)
943 else if (sscanf(string
, scheck(string
, "%d:%d:%d"),
944 &hh
, &mm
, &ss
) != 3) {
948 if ((hh
< 0 || hh
>= HOURSPERDAY
||
949 mm
< 0 || mm
>= MINSPERHOUR
||
950 ss
< 0 || ss
> SECSPERMIN
) &&
951 !(hh
== HOURSPERDAY
&& mm
== 0 && ss
== 0)) {
955 if (noise
&& hh
== HOURSPERDAY
)
956 warning(_("24:00 not handled by pre-1998 versions of zic"));
958 (eitol(hh
* MINSPERHOUR
+ mm
) *
959 eitol(SECSPERMIN
) + eitol(ss
));
963 inrule(fields
, nfields
)
964 register char ** const fields
;
967 static struct rule r
;
969 if (nfields
!= RULE_FIELDS
) {
970 error(_("wrong number of fields on Rule line"));
973 if (*fields
[RF_NAME
] == '\0') {
974 error(_("nameless rule"));
977 r
.r_filename
= filename
;
978 r
.r_linenum
= linenum
;
979 r
.r_stdoff
= gethms(fields
[RF_STDOFF
], _("invalid saved time"), TRUE
);
980 rulesub(&r
, fields
[RF_LOYEAR
], fields
[RF_HIYEAR
], fields
[RF_COMMAND
],
981 fields
[RF_MONTH
], fields
[RF_DAY
], fields
[RF_TOD
]);
982 r
.r_name
= ecpyalloc(fields
[RF_NAME
]);
983 r
.r_abbrvar
= ecpyalloc(fields
[RF_ABBRVAR
]);
984 if (max_abbrvar_len
< strlen(r
.r_abbrvar
))
985 max_abbrvar_len
= strlen(r
.r_abbrvar
);
986 rules
= (struct rule
*) (void *) erealloc((char *) rules
,
987 (int) ((nrules
+ 1) * sizeof *rules
));
992 inzone(fields
, nfields
)
993 register char ** const fields
;
999 if (nfields
< ZONE_MINFIELDS
|| nfields
> ZONE_MAXFIELDS
) {
1000 error(_("wrong number of fields on Zone line"));
1003 if (strcmp(fields
[ZF_NAME
], TZDEFAULT
) == 0 && lcltime
!= NULL
) {
1004 buf
= erealloc(buf
, (int) (132 + strlen(TZDEFAULT
)));
1006 _("\"Zone %s\" line and -l option are mutually exclusive"),
1011 if (strcmp(fields
[ZF_NAME
], TZDEFRULES
) == 0 && psxrules
!= NULL
) {
1012 buf
= erealloc(buf
, (int) (132 + strlen(TZDEFRULES
)));
1014 _("\"Zone %s\" line and -p option are mutually exclusive"),
1019 for (i
= 0; i
< nzones
; ++i
)
1020 if (zones
[i
].z_name
!= NULL
&&
1021 strcmp(zones
[i
].z_name
, fields
[ZF_NAME
]) == 0) {
1022 buf
= erealloc(buf
, (int) (132 +
1023 strlen(fields
[ZF_NAME
]) +
1024 strlen(zones
[i
].z_filename
)));
1026 _("duplicate zone name %s (file \"%s\", line %d)"),
1028 zones
[i
].z_filename
,
1029 zones
[i
].z_linenum
);
1033 return inzsub(fields
, nfields
, FALSE
);
1037 inzcont(fields
, nfields
)
1038 register char ** const fields
;
1041 if (nfields
< ZONEC_MINFIELDS
|| nfields
> ZONEC_MAXFIELDS
) {
1042 error(_("wrong number of fields on Zone continuation line"));
1045 return inzsub(fields
, nfields
, TRUE
);
1049 inzsub(fields
, nfields
, iscont
)
1050 register char ** const fields
;
1055 static struct zone z
;
1056 register int i_gmtoff
, i_rule
, i_format
;
1057 register int i_untilyear
, i_untilmonth
;
1058 register int i_untilday
, i_untiltime
;
1059 register int hasuntil
;
1062 i_gmtoff
= ZFC_GMTOFF
;
1064 i_format
= ZFC_FORMAT
;
1065 i_untilyear
= ZFC_TILYEAR
;
1066 i_untilmonth
= ZFC_TILMONTH
;
1067 i_untilday
= ZFC_TILDAY
;
1068 i_untiltime
= ZFC_TILTIME
;
1071 i_gmtoff
= ZF_GMTOFF
;
1073 i_format
= ZF_FORMAT
;
1074 i_untilyear
= ZF_TILYEAR
;
1075 i_untilmonth
= ZF_TILMONTH
;
1076 i_untilday
= ZF_TILDAY
;
1077 i_untiltime
= ZF_TILTIME
;
1078 z
.z_name
= ecpyalloc(fields
[ZF_NAME
]);
1080 z
.z_filename
= filename
;
1081 z
.z_linenum
= linenum
;
1082 z
.z_gmtoff
= gethms(fields
[i_gmtoff
], _("invalid UTC offset"), TRUE
);
1083 if ((cp
= strchr(fields
[i_format
], '%')) != 0) {
1084 if (*++cp
!= 's' || strchr(cp
, '%') != 0) {
1085 error(_("invalid abbreviation format"));
1089 z
.z_rule
= ecpyalloc(fields
[i_rule
]);
1090 z
.z_format
= ecpyalloc(fields
[i_format
]);
1091 if (max_format_len
< strlen(z
.z_format
))
1092 max_format_len
= strlen(z
.z_format
);
1093 hasuntil
= nfields
> i_untilyear
;
1095 z
.z_untilrule
.r_filename
= filename
;
1096 z
.z_untilrule
.r_linenum
= linenum
;
1097 rulesub(&z
.z_untilrule
,
1098 fields
[i_untilyear
],
1101 (nfields
> i_untilmonth
) ?
1102 fields
[i_untilmonth
] : "Jan",
1103 (nfields
> i_untilday
) ? fields
[i_untilday
] : "1",
1104 (nfields
> i_untiltime
) ? fields
[i_untiltime
] : "0");
1105 z
.z_untiltime
= rpytime(&z
.z_untilrule
,
1106 z
.z_untilrule
.r_loyear
);
1107 if (iscont
&& nzones
> 0 &&
1108 z
.z_untiltime
> min_time
&&
1109 z
.z_untiltime
< max_time
&&
1110 zones
[nzones
- 1].z_untiltime
> min_time
&&
1111 zones
[nzones
- 1].z_untiltime
< max_time
&&
1112 zones
[nzones
- 1].z_untiltime
>= z
.z_untiltime
) {
1114 "Zone continuation line end time is not after end time of previous line"
1119 zones
= (struct zone
*) (void *) erealloc((char *) zones
,
1120 (int) ((nzones
+ 1) * sizeof *zones
));
1121 zones
[nzones
++] = z
;
1123 ** If there was an UNTIL field on this line,
1124 ** there's more information about the zone on the next line.
1130 inleap(fields
, nfields
)
1131 register char ** const fields
;
1134 register const char * cp
;
1135 register const struct lookup
* lp
;
1137 int year
, month
, day
;
1141 if (nfields
!= LEAP_FIELDS
) {
1142 error(_("wrong number of fields on Leap line"));
1146 cp
= fields
[LP_YEAR
];
1147 if (sscanf(cp
, scheck(cp
, "%d"), &year
) != 1) {
1151 error(_("invalid leaping year"));
1154 if (!leapseen
|| leapmaxyear
< year
)
1156 if (!leapseen
|| leapminyear
> year
)
1162 i
= len_years
[isleap(j
)];
1166 i
= -len_years
[isleap(j
)];
1168 dayoff
= oadd(dayoff
, eitol(i
));
1170 if ((lp
= byword(fields
[LP_MONTH
], mon_names
)) == NULL
) {
1171 error(_("invalid month name"));
1174 month
= lp
->l_value
;
1176 while (j
!= month
) {
1177 i
= len_months
[isleap(year
)][j
];
1178 dayoff
= oadd(dayoff
, eitol(i
));
1181 cp
= fields
[LP_DAY
];
1182 if (sscanf(cp
, scheck(cp
, "%d"), &day
) != 1 ||
1183 day
<= 0 || day
> len_months
[isleap(year
)][month
]) {
1184 error(_("invalid day of month"));
1187 dayoff
= oadd(dayoff
, eitol(day
- 1));
1188 if (dayoff
< 0 && !TYPE_SIGNED(zic_t
)) {
1189 error(_("time before zero"));
1192 if (dayoff
< min_time
/ SECSPERDAY
) {
1193 error(_("time too small"));
1196 if (dayoff
> max_time
/ SECSPERDAY
) {
1197 error(_("time too large"));
1200 t
= (zic_t
) dayoff
* SECSPERDAY
;
1201 tod
= gethms(fields
[LP_TIME
], _("invalid time of day"), FALSE
);
1202 cp
= fields
[LP_CORR
];
1204 register int positive
;
1207 if (strcmp(cp
, "") == 0) { /* infile() turns "-" into "" */
1210 } else if (strcmp(cp
, "--") == 0) {
1213 } else if (strcmp(cp
, "+") == 0) {
1216 } else if (strcmp(cp
, "++") == 0) {
1220 error(_("illegal CORRECTION field on Leap line"));
1223 if ((lp
= byword(fields
[LP_ROLL
], leap_types
)) == NULL
) {
1225 "illegal Rolling/Stationary field on Leap line"
1229 leapadd(tadd(t
, tod
), positive
, lp
->l_value
, count
);
1234 inlink(fields
, nfields
)
1235 register char ** const fields
;
1240 if (nfields
!= LINK_FIELDS
) {
1241 error(_("wrong number of fields on Link line"));
1244 if (*fields
[LF_FROM
] == '\0') {
1245 error(_("blank FROM field on Link line"));
1248 if (*fields
[LF_TO
] == '\0') {
1249 error(_("blank TO field on Link line"));
1252 l
.l_filename
= filename
;
1253 l
.l_linenum
= linenum
;
1254 l
.l_from
= ecpyalloc(fields
[LF_FROM
]);
1255 l
.l_to
= ecpyalloc(fields
[LF_TO
]);
1256 links
= (struct link
*) (void *) erealloc((char *) links
,
1257 (int) ((nlinks
+ 1) * sizeof *links
));
1258 links
[nlinks
++] = l
;
1262 rulesub(rp
, loyearp
, hiyearp
, typep
, monthp
, dayp
, timep
)
1263 register struct rule
* const rp
;
1264 const char * const loyearp
;
1265 const char * const hiyearp
;
1266 const char * const typep
;
1267 const char * const monthp
;
1268 const char * const dayp
;
1269 const char * const timep
;
1271 register const struct lookup
* lp
;
1272 register const char * cp
;
1276 if ((lp
= byword(monthp
, mon_names
)) == NULL
) {
1277 error(_("invalid month name"));
1280 rp
->r_month
= lp
->l_value
;
1281 rp
->r_todisstd
= FALSE
;
1282 rp
->r_todisgmt
= FALSE
;
1283 dp
= ecpyalloc(timep
);
1285 ep
= dp
+ strlen(dp
) - 1;
1286 switch (lowerit(*ep
)) {
1287 case 's': /* Standard */
1288 rp
->r_todisstd
= TRUE
;
1289 rp
->r_todisgmt
= FALSE
;
1292 case 'w': /* Wall */
1293 rp
->r_todisstd
= FALSE
;
1294 rp
->r_todisgmt
= FALSE
;
1297 case 'g': /* Greenwich */
1298 case 'u': /* Universal */
1299 case 'z': /* Zulu */
1300 rp
->r_todisstd
= TRUE
;
1301 rp
->r_todisgmt
= TRUE
;
1306 rp
->r_tod
= gethms(dp
, _("invalid time of day"), FALSE
);
1312 lp
= byword(cp
, begin_years
);
1313 rp
->r_lowasnum
= lp
== NULL
;
1314 if (!rp
->r_lowasnum
) switch ((int) lp
->l_value
) {
1316 rp
->r_loyear
= INT_MIN
;
1319 rp
->r_loyear
= INT_MAX
;
1321 default: /* "cannot happen" */
1322 (void) fprintf(stderr
,
1323 _("%s: panic: Invalid l_value %d\n"),
1324 progname
, lp
->l_value
);
1326 } else if (sscanf(cp
, scheck(cp
, "%d"), &rp
->r_loyear
) != 1) {
1327 error(_("invalid starting year"));
1331 lp
= byword(cp
, end_years
);
1332 rp
->r_hiwasnum
= lp
== NULL
;
1333 if (!rp
->r_hiwasnum
) switch ((int) lp
->l_value
) {
1335 rp
->r_hiyear
= INT_MIN
;
1338 rp
->r_hiyear
= INT_MAX
;
1341 rp
->r_hiyear
= rp
->r_loyear
;
1343 default: /* "cannot happen" */
1344 (void) fprintf(stderr
,
1345 _("%s: panic: Invalid l_value %d\n"),
1346 progname
, lp
->l_value
);
1348 } else if (sscanf(cp
, scheck(cp
, "%d"), &rp
->r_hiyear
) != 1) {
1349 error(_("invalid ending year"));
1352 if (rp
->r_loyear
> rp
->r_hiyear
) {
1353 error(_("starting year greater than ending year"));
1357 rp
->r_yrtype
= NULL
;
1359 if (rp
->r_loyear
== rp
->r_hiyear
) {
1360 error(_("typed single year"));
1363 rp
->r_yrtype
= ecpyalloc(typep
);
1367 ** Accept things such as:
1373 dp
= ecpyalloc(dayp
);
1374 if ((lp
= byword(dp
, lasts
)) != NULL
) {
1375 rp
->r_dycode
= DC_DOWLEQ
;
1376 rp
->r_wday
= lp
->l_value
;
1377 rp
->r_dayofmonth
= len_months
[1][rp
->r_month
];
1379 if ((ep
= strchr(dp
, '<')) != 0)
1380 rp
->r_dycode
= DC_DOWLEQ
;
1381 else if ((ep
= strchr(dp
, '>')) != 0)
1382 rp
->r_dycode
= DC_DOWGEQ
;
1385 rp
->r_dycode
= DC_DOM
;
1387 if (rp
->r_dycode
!= DC_DOM
) {
1390 error(_("invalid day of month"));
1394 if ((lp
= byword(dp
, wday_names
)) == NULL
) {
1395 error(_("invalid weekday name"));
1399 rp
->r_wday
= lp
->l_value
;
1401 if (sscanf(ep
, scheck(ep
, "%d"), &rp
->r_dayofmonth
) != 1 ||
1402 rp
->r_dayofmonth
<= 0 ||
1403 (rp
->r_dayofmonth
> len_months
[1][rp
->r_month
])) {
1404 error(_("invalid day of month"));
1420 for (i
= 0, shift
= 24; i
< 4; ++i
, shift
-= 8)
1421 buf
[i
] = val
>> shift
;
1432 for (i
= 0, shift
= 56; i
< 8; ++i
, shift
-= 8)
1433 buf
[i
] = val
>> shift
;
1444 (void) fwrite((void *) buf
, (size_t) sizeof buf
, (size_t) 1, fp
);
1448 puttzcode64(val
, fp
)
1454 convert64(val
, buf
);
1455 (void) fwrite((void *) buf
, (size_t) sizeof buf
, (size_t) 1, fp
);
1463 const zic_t a
= ((const struct attype
*) avp
)->at
;
1464 const zic_t b
= ((const struct attype
*) bvp
)->at
;
1466 return (a
< b
) ? -1 : (a
> b
);
1473 return INT32_MIN
<= x
&& x
<= INT32_MAX
;
1477 writezone(name
, string
)
1478 const char * const name
;
1479 const char * const string
;
1483 register int leapcnt32
, leapi32
;
1484 register int timecnt32
, timei32
;
1486 static char * fullname
;
1487 static const struct tzhead tzh0
;
1488 static struct tzhead tzh
;
1489 zic_t ats
[TZ_MAX_TIMES
];
1490 unsigned char types
[TZ_MAX_TIMES
];
1496 (void) qsort((void *) attypes
, (size_t) timecnt
,
1497 (size_t) sizeof *attypes
, atcomp
);
1507 while (fromi
< timecnt
&& attypes
[fromi
].at
< min_time
)
1510 while (fromi
< timecnt
&& attypes
[fromi
].type
== 0)
1511 ++fromi
; /* handled by default rule */
1512 for ( ; fromi
< timecnt
; ++fromi
) {
1513 if (toi
!= 0 && ((attypes
[fromi
].at
+
1514 gmtoffs
[attypes
[toi
- 1].type
]) <=
1515 (attypes
[toi
- 1].at
+ gmtoffs
[toi
== 1 ? 0
1516 : attypes
[toi
- 2].type
]))) {
1517 attypes
[toi
- 1].type
=
1518 attypes
[fromi
].type
;
1522 attypes
[toi
- 1].type
!= attypes
[fromi
].type
)
1523 attypes
[toi
++] = attypes
[fromi
];
1530 for (i
= 0; i
< timecnt
; ++i
) {
1531 ats
[i
] = attypes
[i
].at
;
1532 types
[i
] = attypes
[i
].type
;
1535 ** Correct for leap seconds.
1537 for (i
= 0; i
< timecnt
; ++i
) {
1540 if (ats
[i
] > trans
[j
] - corr
[j
]) {
1541 ats
[i
] = tadd(ats
[i
], corr
[j
]);
1546 ** Figure out 32-bit-limited starts and counts.
1548 timecnt32
= timecnt
;
1550 leapcnt32
= leapcnt
;
1552 while (timecnt32
> 0 && !is32(ats
[timecnt32
- 1]))
1554 while (timecnt32
> 0 && !is32(ats
[timei32
])) {
1558 while (leapcnt32
> 0 && !is32(trans
[leapcnt32
- 1]))
1560 while (leapcnt32
> 0 && !is32(trans
[leapi32
])) {
1564 fullname
= erealloc(fullname
,
1565 (int) (strlen(directory
) + 1 + strlen(name
) + 1));
1566 (void) sprintf(fullname
, "%s/%s", directory
, name
);
1568 ** Remove old file, if any, to snap links.
1570 if (!itsdir(fullname
) && remove(fullname
) != 0 && errno
!= ENOENT
) {
1571 const char *e
= strerror(errno
);
1573 (void) fprintf(stderr
, _("%s: Can't remove %s: %s\n"),
1574 progname
, fullname
, e
);
1577 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1578 if (mkdirs(fullname
) != 0)
1580 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1581 const char *e
= strerror(errno
);
1583 (void) fprintf(stderr
, _("%s: Can't create %s: %s\n"),
1584 progname
, fullname
, e
);
1588 for (pass
= 1; pass
<= 2; ++pass
) {
1589 register int thistimei
, thistimecnt
;
1590 register int thisleapi
, thisleapcnt
;
1591 register int thistimelim
, thisleaplim
;
1592 int writetype
[TZ_MAX_TIMES
];
1593 int typemap
[TZ_MAX_TYPES
];
1594 register int thistypecnt
;
1595 char thischars
[TZ_MAX_CHARS
];
1597 int indmap
[TZ_MAX_CHARS
];
1600 thistimei
= timei32
;
1601 thistimecnt
= timecnt32
;
1602 thisleapi
= leapi32
;
1603 thisleapcnt
= leapcnt32
;
1606 thistimecnt
= timecnt
;
1608 thisleapcnt
= leapcnt
;
1610 thistimelim
= thistimei
+ thistimecnt
;
1611 thisleaplim
= thisleapi
+ thisleapcnt
;
1612 for (i
= 0; i
< typecnt
; ++i
)
1613 writetype
[i
] = thistimecnt
== timecnt
;
1614 if (thistimecnt
== 0) {
1616 ** No transition times fall in the current
1617 ** (32- or 64-bit) window.
1620 writetype
[typecnt
- 1] = TRUE
;
1622 for (i
= thistimei
- 1; i
< thistimelim
; ++i
)
1624 writetype
[types
[i
]] = TRUE
;
1626 ** For America/Godthab and Antarctica/Palmer
1629 writetype
[0] = TRUE
;
1632 for (i
= 0; i
< typecnt
; ++i
)
1633 typemap
[i
] = writetype
[i
] ? thistypecnt
++ : -1;
1634 for (i
= 0; i
< sizeof indmap
/ sizeof indmap
[0]; ++i
)
1637 for (i
= 0; i
< typecnt
; ++i
) {
1638 register char * thisabbr
;
1642 if (indmap
[abbrinds
[i
]] >= 0)
1644 thisabbr
= &chars
[abbrinds
[i
]];
1645 for (j
= 0; j
< thischarcnt
; ++j
)
1646 if (strcmp(&thischars
[j
], thisabbr
) == 0)
1648 if (j
== thischarcnt
) {
1649 (void) strcpy(&thischars
[(int) thischarcnt
],
1651 thischarcnt
+= strlen(thisabbr
) + 1;
1653 indmap
[abbrinds
[i
]] = j
;
1655 #define DO(field) (void) fwrite((void *) tzh.field, \
1656 (size_t) sizeof tzh.field, (size_t) 1, fp)
1658 (void) strncpy(tzh
.tzh_magic
, TZ_MAGIC
, sizeof tzh
.tzh_magic
);
1659 tzh
.tzh_version
[0] = ZIC_VERSION
;
1660 convert(eitol(thistypecnt
), tzh
.tzh_ttisgmtcnt
);
1661 convert(eitol(thistypecnt
), tzh
.tzh_ttisstdcnt
);
1662 convert(eitol(thisleapcnt
), tzh
.tzh_leapcnt
);
1663 convert(eitol(thistimecnt
), tzh
.tzh_timecnt
);
1664 convert(eitol(thistypecnt
), tzh
.tzh_typecnt
);
1665 convert(eitol(thischarcnt
), tzh
.tzh_charcnt
);
1676 for (i
= thistimei
; i
< thistimelim
; ++i
)
1678 puttzcode((long) ats
[i
], fp
);
1679 else puttzcode64(ats
[i
], fp
);
1680 for (i
= thistimei
; i
< thistimelim
; ++i
) {
1683 uc
= typemap
[types
[i
]];
1684 (void) fwrite((void *) &uc
,
1689 for (i
= 0; i
< typecnt
; ++i
)
1691 puttzcode(gmtoffs
[i
], fp
);
1692 (void) putc(isdsts
[i
], fp
);
1693 (void) putc((unsigned char) indmap
[abbrinds
[i
]], fp
);
1695 if (thischarcnt
!= 0)
1696 (void) fwrite((void *) thischars
,
1697 (size_t) sizeof thischars
[0],
1698 (size_t) thischarcnt
, fp
);
1699 for (i
= thisleapi
; i
< thisleaplim
; ++i
) {
1700 register zic_t todo
;
1703 if (timecnt
== 0 || trans
[i
] < ats
[0]) {
1706 if (++j
>= typecnt
) {
1712 while (j
< timecnt
&&
1717 todo
= tadd(trans
[i
], -gmtoffs
[j
]);
1718 } else todo
= trans
[i
];
1720 puttzcode((long) todo
, fp
);
1721 else puttzcode64(todo
, fp
);
1722 puttzcode(corr
[i
], fp
);
1724 for (i
= 0; i
< typecnt
; ++i
)
1726 (void) putc(ttisstds
[i
], fp
);
1727 for (i
= 0; i
< typecnt
; ++i
)
1729 (void) putc(ttisgmts
[i
], fp
);
1731 (void) fprintf(fp
, "\n%s\n", string
);
1732 if (ferror(fp
) || fclose(fp
)) {
1733 (void) fprintf(stderr
, _("%s: Error writing %s\n"),
1734 progname
, fullname
);
1740 doabbr(abbr
, format
, letters
, isdst
, doquotes
)
1742 const char * const format
;
1743 const char * const letters
;
1748 register char * slashp
;
1751 slashp
= strchr(format
, '/');
1752 if (slashp
== NULL
) {
1753 if (letters
== NULL
)
1754 (void) strcpy(abbr
, format
);
1755 else (void) sprintf(abbr
, format
, letters
);
1757 (void) strcpy(abbr
, slashp
+ 1);
1759 if (slashp
> format
)
1760 (void) strncpy(abbr
, format
,
1761 (unsigned) (slashp
- format
));
1762 abbr
[slashp
- format
] = '\0';
1766 for (cp
= abbr
; *cp
!= '\0'; ++cp
)
1767 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp
) == NULL
&&
1768 strchr("abcdefghijklmnopqrstuvwxyz", *cp
) == NULL
)
1771 if (len
> 0 && *cp
== '\0')
1773 abbr
[len
+ 2] = '\0';
1774 abbr
[len
+ 1] = '>';
1775 for ( ; len
> 0; --len
)
1776 abbr
[len
] = abbr
[len
- 1];
1791 stringoffset(result
, offset
)
1796 register int minutes
;
1797 register int seconds
;
1801 (void) strcpy(result
, "-");
1804 seconds
= offset
% SECSPERMIN
;
1805 offset
/= SECSPERMIN
;
1806 minutes
= offset
% MINSPERHOUR
;
1807 offset
/= MINSPERHOUR
;
1809 if (hours
>= HOURSPERDAY
) {
1813 (void) sprintf(end(result
), "%d", hours
);
1814 if (minutes
!= 0 || seconds
!= 0) {
1815 (void) sprintf(end(result
), ":%02d", minutes
);
1817 (void) sprintf(end(result
), ":%02d", seconds
);
1823 stringrule(result
, rp
, dstoff
, gmtoff
)
1825 const struct rule
* const rp
;
1831 result
= end(result
);
1832 if (rp
->r_dycode
== DC_DOM
) {
1833 register int month
, total
;
1835 if (rp
->r_dayofmonth
== 29 && rp
->r_month
== TM_FEBRUARY
)
1838 for (month
= 0; month
< rp
->r_month
; ++month
)
1839 total
+= len_months
[0][month
];
1840 (void) sprintf(result
, "J%d", total
+ rp
->r_dayofmonth
);
1844 if (rp
->r_dycode
== DC_DOWGEQ
) {
1845 week
= 1 + rp
->r_dayofmonth
/ DAYSPERWEEK
;
1846 if ((week
- 1) * DAYSPERWEEK
+ 1 != rp
->r_dayofmonth
)
1848 } else if (rp
->r_dycode
== DC_DOWLEQ
) {
1849 if (rp
->r_dayofmonth
== len_months
[1][rp
->r_month
])
1852 week
= 1 + rp
->r_dayofmonth
/ DAYSPERWEEK
;
1853 if (week
* DAYSPERWEEK
- 1 != rp
->r_dayofmonth
)
1856 } else return -1; /* "cannot happen" */
1857 (void) sprintf(result
, "M%d.%d.%d",
1858 rp
->r_month
+ 1, week
, rp
->r_wday
);
1863 if (rp
->r_todisstd
&& rp
->r_stdoff
== 0)
1869 if (tod
!= 2 * SECSPERMIN
* MINSPERHOUR
) {
1870 (void) strcat(result
, "/");
1871 if (stringoffset(end(result
), tod
) != 0)
1878 stringzone(result
, zpfirst
, zonecount
)
1880 const struct zone
* const zpfirst
;
1881 const int zonecount
;
1883 register const struct zone
* zp
;
1884 register struct rule
* rp
;
1885 register struct rule
* stdrp
;
1886 register struct rule
* dstrp
;
1888 register const char * abbrvar
;
1891 zp
= zpfirst
+ zonecount
- 1;
1892 stdrp
= dstrp
= NULL
;
1893 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
1894 rp
= &zp
->z_rules
[i
];
1895 if (rp
->r_hiwasnum
|| rp
->r_hiyear
!= INT_MAX
)
1897 if (rp
->r_yrtype
!= NULL
)
1899 if (rp
->r_stdoff
== 0) {
1909 if (stdrp
== NULL
&& dstrp
== NULL
) {
1911 ** There are no rules running through "max".
1912 ** Let's find the latest rule.
1914 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
1915 rp
= &zp
->z_rules
[i
];
1916 if (stdrp
== NULL
|| rp
->r_hiyear
> stdrp
->r_hiyear
||
1917 (rp
->r_hiyear
== stdrp
->r_hiyear
&&
1918 rp
->r_month
> stdrp
->r_month
))
1921 if (stdrp
!= NULL
&& stdrp
->r_stdoff
!= 0)
1922 return; /* We end up in DST (a POSIX no-no). */
1924 ** Horrid special case: if year is 2037,
1925 ** presume this is a zone handled on a year-by-year basis;
1926 ** do not try to apply a rule to the zone.
1928 if (stdrp
!= NULL
&& stdrp
->r_hiyear
== 2037)
1931 if (stdrp
== NULL
&& zp
->z_nrules
!= 0)
1933 abbrvar
= (stdrp
== NULL
) ? "" : stdrp
->r_abbrvar
;
1934 doabbr(result
, zp
->z_format
, abbrvar
, FALSE
, TRUE
);
1935 if (stringoffset(end(result
), -zp
->z_gmtoff
) != 0) {
1941 doabbr(end(result
), zp
->z_format
, dstrp
->r_abbrvar
, TRUE
, TRUE
);
1942 if (dstrp
->r_stdoff
!= SECSPERMIN
* MINSPERHOUR
)
1943 if (stringoffset(end(result
),
1944 -(zp
->z_gmtoff
+ dstrp
->r_stdoff
)) != 0) {
1948 (void) strcat(result
, ",");
1949 if (stringrule(result
, dstrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
) != 0) {
1953 (void) strcat(result
, ",");
1954 if (stringrule(result
, stdrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
) != 0) {
1961 outzone(zpfirst
, zonecount
)
1962 const struct zone
* const zpfirst
;
1963 const int zonecount
;
1965 register const struct zone
* zp
;
1966 register struct rule
* rp
;
1968 register int usestart
, useuntil
;
1969 register zic_t starttime
, untiltime
;
1970 register long gmtoff
;
1971 register long stdoff
;
1973 register long startoff
;
1974 register int startttisstd
;
1975 register int startttisgmt
;
1977 register char * startbuf
;
1979 register char * envvar
;
1980 register int max_abbr_len
;
1981 register int max_envvar_len
;
1983 max_abbr_len
= 2 + max_format_len
+ max_abbrvar_len
;
1984 max_envvar_len
= 2 * max_abbr_len
+ 5 * 9;
1985 startbuf
= emalloc(max_abbr_len
+ 1);
1986 ab
= emalloc(max_abbr_len
+ 1);
1987 envvar
= emalloc(max_envvar_len
+ 1);
1988 INITIALIZE(untiltime
);
1989 INITIALIZE(starttime
);
1991 ** Now. . .finally. . .generate some useful data!
1997 ** Thanks to Earl Chew
1998 ** for noting the need to unconditionally initialize startttisstd.
2000 startttisstd
= FALSE
;
2001 startttisgmt
= FALSE
;
2002 min_year
= max_year
= EPOCH_YEAR
;
2004 updateminmax(leapminyear
);
2005 updateminmax(leapmaxyear
);
2007 for (i
= 0; i
< zonecount
; ++i
) {
2009 updateminmax(zp
->z_untilrule
.r_loyear
);
2010 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2011 rp
= &zp
->z_rules
[j
];
2013 updateminmax(rp
->r_loyear
);
2015 updateminmax(rp
->r_hiyear
);
2019 ** Generate lots of data if a rule can't cover all future times.
2021 stringzone(envvar
, zpfirst
, zonecount
);
2022 if (noise
&& envvar
[0] == '\0') {
2025 wp
= ecpyalloc(_("no POSIX environment variable for zone"));
2026 wp
= ecatalloc(wp
, " ");
2027 wp
= ecatalloc(wp
, zpfirst
->z_name
);
2031 if (envvar
[0] == '\0') {
2032 if (min_year
>= INT_MIN
+ YEARSPERREPEAT
)
2033 min_year
-= YEARSPERREPEAT
;
2034 else min_year
= INT_MIN
;
2035 if (max_year
<= INT_MAX
- YEARSPERREPEAT
)
2036 max_year
+= YEARSPERREPEAT
;
2037 else max_year
= INT_MAX
;
2040 ** For the benefit of older systems, generate data through 2037.
2042 if (max_year
< 2037)
2044 for (i
= 0; i
< zonecount
; ++i
) {
2046 ** A guess that may well be corrected later.
2050 usestart
= i
> 0 && (zp
- 1)->z_untiltime
> min_time
;
2051 useuntil
= i
< (zonecount
- 1);
2052 if (useuntil
&& zp
->z_untiltime
<= min_time
)
2054 gmtoff
= zp
->z_gmtoff
;
2055 eat(zp
->z_filename
, zp
->z_linenum
);
2057 startoff
= zp
->z_gmtoff
;
2058 if (zp
->z_nrules
== 0) {
2059 stdoff
= zp
->z_stdoff
;
2060 doabbr(startbuf
, zp
->z_format
,
2061 (char *) NULL
, stdoff
!= 0, FALSE
);
2062 type
= addtype(oadd(zp
->z_gmtoff
, stdoff
),
2063 startbuf
, stdoff
!= 0, startttisstd
,
2066 addtt(starttime
, type
);
2068 } else if (stdoff
!= 0)
2069 addtt(min_time
, type
);
2070 } else for (year
= min_year
; year
<= max_year
; ++year
) {
2071 if (useuntil
&& year
> zp
->z_untilrule
.r_hiyear
)
2074 ** Mark which rules to do in the current year.
2075 ** For those to do, calculate rpytime(rp, year);
2077 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2078 rp
= &zp
->z_rules
[j
];
2079 eats(zp
->z_filename
, zp
->z_linenum
,
2080 rp
->r_filename
, rp
->r_linenum
);
2081 rp
->r_todo
= year
>= rp
->r_loyear
&&
2082 year
<= rp
->r_hiyear
&&
2083 yearistype(year
, rp
->r_yrtype
);
2085 rp
->r_temp
= rpytime(rp
, year
);
2089 register zic_t jtime
, ktime
;
2090 register long offset
;
2095 ** Turn untiltime into UTC
2096 ** assuming the current gmtoff and
2099 untiltime
= zp
->z_untiltime
;
2100 if (!zp
->z_untilrule
.r_todisgmt
)
2101 untiltime
= tadd(untiltime
,
2103 if (!zp
->z_untilrule
.r_todisstd
)
2104 untiltime
= tadd(untiltime
,
2108 ** Find the rule (of those to do, if any)
2109 ** that takes effect earliest in the year.
2112 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2113 rp
= &zp
->z_rules
[j
];
2116 eats(zp
->z_filename
, zp
->z_linenum
,
2117 rp
->r_filename
, rp
->r_linenum
);
2118 offset
= rp
->r_todisgmt
? 0 : gmtoff
;
2119 if (!rp
->r_todisstd
)
2120 offset
= oadd(offset
, stdoff
);
2122 if (jtime
== min_time
||
2125 jtime
= tadd(jtime
, -offset
);
2126 if (k
< 0 || jtime
< ktime
) {
2132 break; /* go on to next year */
2133 rp
= &zp
->z_rules
[k
];
2135 if (useuntil
&& ktime
>= untiltime
)
2137 stdoff
= rp
->r_stdoff
;
2138 if (usestart
&& ktime
== starttime
)
2141 if (ktime
< starttime
) {
2142 startoff
= oadd(zp
->z_gmtoff
,
2144 doabbr(startbuf
, zp
->z_format
,
2150 if (*startbuf
== '\0' &&
2151 startoff
== oadd(zp
->z_gmtoff
,
2161 eats(zp
->z_filename
, zp
->z_linenum
,
2162 rp
->r_filename
, rp
->r_linenum
);
2163 doabbr(ab
, zp
->z_format
, rp
->r_abbrvar
,
2164 rp
->r_stdoff
!= 0, FALSE
);
2165 offset
= oadd(zp
->z_gmtoff
, rp
->r_stdoff
);
2166 type
= addtype(offset
, ab
, rp
->r_stdoff
!= 0,
2167 rp
->r_todisstd
, rp
->r_todisgmt
);
2172 if (*startbuf
== '\0' &&
2173 zp
->z_format
!= NULL
&&
2174 strchr(zp
->z_format
, '%') == NULL
&&
2175 strchr(zp
->z_format
, '/') == NULL
)
2176 (void) strcpy(startbuf
, zp
->z_format
);
2177 eat(zp
->z_filename
, zp
->z_linenum
);
2178 if (*startbuf
== '\0')
2179 error(_("can't determine time zone abbreviation to use just after until time"));
2180 else addtt(starttime
,
2181 addtype(startoff
, startbuf
,
2182 startoff
!= zp
->z_gmtoff
,
2187 ** Now we may get to set starttime for the next zone line.
2190 startttisstd
= zp
->z_untilrule
.r_todisstd
;
2191 startttisgmt
= zp
->z_untilrule
.r_todisgmt
;
2192 starttime
= zp
->z_untiltime
;
2194 starttime
= tadd(starttime
, -stdoff
);
2196 starttime
= tadd(starttime
, -gmtoff
);
2199 writezone(zpfirst
->z_name
, envvar
);
2206 addtt(starttime
, type
)
2207 const zic_t starttime
;
2210 if (starttime
<= min_time
||
2211 (timecnt
== 1 && attypes
[0].at
< min_time
)) {
2212 gmtoffs
[0] = gmtoffs
[type
];
2213 isdsts
[0] = isdsts
[type
];
2214 ttisstds
[0] = ttisstds
[type
];
2215 ttisgmts
[0] = ttisgmts
[type
];
2216 if (abbrinds
[type
] != 0)
2217 (void) strcpy(chars
, &chars
[abbrinds
[type
]]);
2219 charcnt
= strlen(chars
) + 1;
2224 if (timecnt
>= TZ_MAX_TIMES
) {
2225 error(_("too many transitions?!"));
2228 attypes
[timecnt
].at
= starttime
;
2229 attypes
[timecnt
].type
= type
;
2234 addtype(gmtoff
, abbr
, isdst
, ttisstd
, ttisgmt
)
2236 const char * const abbr
;
2243 if (isdst
!= TRUE
&& isdst
!= FALSE
) {
2244 error(_("internal error - addtype called with bad isdst"));
2247 if (ttisstd
!= TRUE
&& ttisstd
!= FALSE
) {
2248 error(_("internal error - addtype called with bad ttisstd"));
2251 if (ttisgmt
!= TRUE
&& ttisgmt
!= FALSE
) {
2252 error(_("internal error - addtype called with bad ttisgmt"));
2256 ** See if there's already an entry for this zone type.
2257 ** If so, just return its index.
2259 for (i
= 0; i
< typecnt
; ++i
) {
2260 if (gmtoff
== gmtoffs
[i
] && isdst
== isdsts
[i
] &&
2261 strcmp(abbr
, &chars
[abbrinds
[i
]]) == 0 &&
2262 ttisstd
== ttisstds
[i
] &&
2263 ttisgmt
== ttisgmts
[i
])
2267 ** There isn't one; add a new one, unless there are already too
2270 if (typecnt
>= TZ_MAX_TYPES
) {
2271 error(_("too many local time types"));
2274 gmtoffs
[i
] = gmtoff
;
2276 ttisstds
[i
] = ttisstd
;
2277 ttisgmts
[i
] = ttisgmt
;
2279 for (j
= 0; j
< charcnt
; ++j
)
2280 if (strcmp(&chars
[j
], abbr
) == 0)
2290 leapadd(t
, positive
, rolling
, count
)
2298 if (leapcnt
+ (positive
? count
: 1) > TZ_MAX_LEAPS
) {
2299 error(_("too many leap seconds"));
2302 for (i
= 0; i
< leapcnt
; ++i
)
2303 if (t
<= trans
[i
]) {
2304 if (t
== trans
[i
]) {
2305 error(_("repeated leap second moment"));
2311 for (j
= leapcnt
; j
> i
; --j
) {
2312 trans
[j
] = trans
[j
- 1];
2313 corr
[j
] = corr
[j
- 1];
2314 roll
[j
] = roll
[j
- 1];
2317 corr
[i
] = positive
? 1L : eitol(-count
);
2320 } while (positive
&& --count
!= 0);
2327 register long last
= 0;
2330 ** propagate leap seconds forward
2332 for (i
= 0; i
< leapcnt
; ++i
) {
2333 trans
[i
] = tadd(trans
[i
], last
);
2334 last
= corr
[i
] += last
;
2339 yearistype(year
, type
)
2341 const char * const type
;
2346 if (type
== NULL
|| *type
== '\0')
2348 buf
= erealloc(buf
, (int) (132 + strlen(yitcommand
) + strlen(type
)));
2349 (void) sprintf(buf
, "%s %d %s", yitcommand
, year
, type
);
2350 result
= system(buf
);
2351 if (WIFEXITED(result
)) switch (WEXITSTATUS(result
)) {
2357 error(_("Wild result from command execution"));
2358 (void) fprintf(stderr
, _("%s: command was '%s', result was %d\n"),
2359 progname
, buf
, result
);
2368 a
= (unsigned char) a
;
2369 return (isascii(a
) && isupper(a
)) ? tolower(a
) : a
;
2373 ciequal(ap
, bp
) /* case-insensitive equality */
2374 register const char * ap
;
2375 register const char * bp
;
2377 while (lowerit(*ap
) == lowerit(*bp
++))
2385 register const char * abbr
;
2386 register const char * word
;
2388 if (lowerit(*abbr
) != lowerit(*word
))
2391 while (*++abbr
!= '\0')
2395 } while (lowerit(*word
++) != lowerit(*abbr
));
2399 static const struct lookup
*
2401 register const char * const word
;
2402 register const struct lookup
* const table
;
2404 register const struct lookup
* foundlp
;
2405 register const struct lookup
* lp
;
2407 if (word
== NULL
|| table
== NULL
)
2410 ** Look for exact match.
2412 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2413 if (ciequal(word
, lp
->l_word
))
2416 ** Look for inexact match.
2419 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2420 if (itsabbr(word
, lp
->l_word
)) {
2421 if (foundlp
== NULL
)
2423 else return NULL
; /* multiple inexact matches */
2433 register char ** array
;
2438 array
= (char **) (void *)
2439 emalloc((int) ((strlen(cp
) + 1) * sizeof *array
));
2442 while (isascii((unsigned char) *cp
) &&
2443 isspace((unsigned char) *cp
))
2445 if (*cp
== '\0' || *cp
== '#')
2447 array
[nsubs
++] = dp
= cp
;
2449 if ((*dp
= *cp
++) != '"')
2451 else while ((*dp
= *cp
++) != '"')
2455 "Odd number of quotation marks"
2457 } while (*cp
!= '\0' && *cp
!= '#' &&
2458 (!isascii(*cp
) || !isspace((unsigned char) *cp
)));
2459 if (isascii(*cp
) && isspace((unsigned char) *cp
))
2463 array
[nsubs
] = NULL
;
2475 if ((t2
> 0 && t
<= t1
) || (t2
< 0 && t
>= t1
)) {
2476 error(_("time overflow"));
2489 if (t1
== max_time
&& t2
> 0)
2491 if (t1
== min_time
&& t2
< 0)
2494 if ((t2
> 0 && t
<= t1
) || (t2
< 0 && t
>= t1
)) {
2495 error(_("time overflow"));
2502 ** Given a rule, and a year, compute the date - in seconds since January 1,
2503 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2507 rpytime(rp
, wantedy
)
2508 register const struct rule
* const rp
;
2509 register const int wantedy
;
2511 register int y
, m
, i
;
2512 register long dayoff
; /* with a nod to Margaret O. */
2515 if (wantedy
== INT_MIN
)
2517 if (wantedy
== INT_MAX
)
2522 while (wantedy
!= y
) {
2524 i
= len_years
[isleap(y
)];
2528 i
= -len_years
[isleap(y
)];
2530 dayoff
= oadd(dayoff
, eitol(i
));
2532 while (m
!= rp
->r_month
) {
2533 i
= len_months
[isleap(y
)][m
];
2534 dayoff
= oadd(dayoff
, eitol(i
));
2537 i
= rp
->r_dayofmonth
;
2538 if (m
== TM_FEBRUARY
&& i
== 29 && !isleap(y
)) {
2539 if (rp
->r_dycode
== DC_DOWLEQ
)
2542 error(_("use of 2/29 in non leap-year"));
2547 dayoff
= oadd(dayoff
, eitol(i
));
2548 if (rp
->r_dycode
== DC_DOWGEQ
|| rp
->r_dycode
== DC_DOWLEQ
) {
2551 #define LDAYSPERWEEK ((long) DAYSPERWEEK)
2552 wday
= eitol(EPOCH_WDAY
);
2554 ** Don't trust mod of negative numbers.
2557 wday
= (wday
+ dayoff
) % LDAYSPERWEEK
;
2559 wday
-= ((-dayoff
) % LDAYSPERWEEK
);
2561 wday
+= LDAYSPERWEEK
;
2563 while (wday
!= eitol(rp
->r_wday
))
2564 if (rp
->r_dycode
== DC_DOWGEQ
) {
2565 dayoff
= oadd(dayoff
, (long) 1);
2566 if (++wday
>= LDAYSPERWEEK
)
2570 dayoff
= oadd(dayoff
, (long) -1);
2572 wday
= LDAYSPERWEEK
- 1;
2575 if (i
< 0 || i
>= len_months
[isleap(y
)][m
]) {
2577 warning(_("rule goes past start/end of month--\
2578 will not work with pre-2004 versions of zic"));
2581 if (dayoff
< min_time
/ SECSPERDAY
)
2583 if (dayoff
> max_time
/ SECSPERDAY
)
2585 t
= (zic_t
) dayoff
* SECSPERDAY
;
2586 return tadd(t
, rp
->r_tod
);
2591 const char * const string
;
2595 if (strcmp(string
, GRANDPARENTED
) != 0) {
2596 register const char * cp
;
2600 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2601 ** optionally followed by a + or - and a number from 1 to 14.
2605 while (isascii((unsigned char) *cp
) &&
2606 isalpha((unsigned char) *cp
))
2608 if (cp
- string
== 0)
2609 wp
= _("time zone abbreviation lacks alphabetic at start");
2610 if (noise
&& cp
- string
> 3)
2611 wp
= _("time zone abbreviation has more than 3 alphabetics");
2612 if (cp
- string
> ZIC_MAX_ABBR_LEN_WO_WARN
)
2613 wp
= _("time zone abbreviation has too many alphabetics");
2614 if (wp
== NULL
&& (*cp
== '+' || *cp
== '-')) {
2616 if (isascii((unsigned char) *cp
) &&
2617 isdigit((unsigned char) *cp
))
2619 *cp
>= '0' && *cp
<= '4')
2623 wp
= _("time zone abbreviation differs from POSIX standard");
2626 wp
= ecatalloc(wp
, " (");
2627 wp
= ecatalloc(wp
, string
);
2628 wp
= ecatalloc(wp
, ")");
2633 i
= strlen(string
) + 1;
2634 if (charcnt
+ i
> TZ_MAX_CHARS
) {
2635 error(_("too many, or too long, time zone abbreviations"));
2638 (void) strcpy(&chars
[charcnt
], string
);
2639 charcnt
+= eitol(i
);
2644 char * const argname
;
2646 register char * name
;
2649 if (argname
== NULL
|| *argname
== '\0')
2651 cp
= name
= ecpyalloc(argname
);
2652 while ((cp
= strchr(cp
+ 1, '/')) != 0) {
2656 ** DOS drive specifier?
2658 if (isalpha((unsigned char) name
[0]) &&
2659 name
[1] == ':' && name
[2] == '\0') {
2663 #endif /* !defined unix */
2664 if (!itsdir(name
)) {
2666 ** It doesn't seem to exist, so we try to create it.
2667 ** Creation may fail because of the directory being
2668 ** created by some other multiprocessor, so we get
2669 ** to do extra checking.
2671 if (mkdir(name
, MKDIR_UMASK
) != 0) {
2672 const char *e
= strerror(errno
);
2674 if (errno
!= EEXIST
|| !itsdir(name
)) {
2675 (void) fprintf(stderr
,
2676 _("%s: Can't create directory %s: %s\n"),
2696 if ((i
< 0 && l
>= 0) || (i
== 0 && l
!= 0) || (i
> 0 && l
<= 0)) {
2697 (void) fprintf(stderr
,
2698 _("%s: %d did not sign extend correctly\n"),
2706 ** UNIX was a registered trademark of The Open Group in 2003.