]>
git.saurik.com Git - apple/icu.git/blob - icuSources/tools/tzcode/zic.c
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.7";
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
29 /* Enable extensions and modifications for ICU. */
32 /* Continue executing after link failure. Even if ICU is undefined
33 * (for vanilla zic behavior), ICU_LINKS should be defined, since zic
34 * appears to fail on the 2003 data the first time through during the
35 * linking phase. Running zic twice, with ICU_LINKS defined, causes
36 * links to be handled correctly. */
44 ** On some ancient hosts, predicates like `isspace(C)' are defined
45 ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
46 ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
47 ** Neither the C Standard nor Posix require that `isascii' exist.
48 ** For portability, we check both ancient and modern requirements.
49 ** If isascii is not defined, the isascii check succeeds trivially.
56 #define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
57 #define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
59 #define end(cp) (strchr((cp), '\0'))
62 const char * r_filename
;
66 int r_loyear
; /* for example, 1986 */
67 int r_hiyear
; /* for example, 1986 */
68 const char * r_yrtype
;
72 int r_month
; /* 0..11 */
74 int r_dycode
; /* see below */
78 long r_tod
; /* time from midnight */
79 int r_todisstd
; /* above is standard time if TRUE */
80 /* or wall clock time if FALSE */
81 int r_todisgmt
; /* above is GMT if TRUE */
82 /* or local time if FALSE */
83 long r_stdoff
; /* offset from standard time */
84 const char * r_abbrvar
; /* variable part of abbreviation */
86 int r_todo
; /* a rule to do (used in outzone) */
87 zic_t r_temp
; /* used in outzone */
91 ** r_dycode r_dayofmonth r_wday
94 #define DC_DOM 0 /* 1..31 */ /* unused */
95 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
96 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
99 const char * z_filename
;
105 const char * z_format
;
109 struct rule
* z_rules
;
112 struct rule z_untilrule
;
116 extern int getopt
P((int argc
, char * const argv
[],
117 const char * options
));
118 extern int link
P((const char * fromname
, const char * toname
));
119 extern char * optarg
;
122 static void addtt
P((zic_t starttime
, int type
));
124 static int addtype
P((long gmtoff
, long rawoff
, long dstoff
,
125 const char * abbr
, int isdst
,
126 int ttisstd
, int ttisgmt
));
128 static int addtype
P((long gmtoff
, const char * abbr
, int isdst
,
129 int ttisstd
, int ttisgmt
));
131 static void leapadd
P((zic_t t
, int positive
, int rolling
, int count
));
132 static void adjleap
P((void));
133 static void associate
P((void));
134 static int ciequal
P((const char * ap
, const char * bp
));
135 static void convert
P((long val
, char * buf
));
136 static void convert64
P((zic_t val
, char * buf
));
137 static void dolink
P((const char * fromfile
, const char * tofile
));
138 static void doabbr
P((char * abbr
, const char * format
,
139 const char * letters
, int isdst
, int doquotes
));
140 static void eat
P((const char * name
, int num
));
141 static void eats
P((const char * name
, int num
,
142 const char * rname
, int rnum
));
143 static long eitol
P((int i
));
144 static void error
P((const char * message
));
145 static char ** getfields
P((char * buf
));
146 static long gethms
P((const char * string
, const char * errstrng
,
148 static void infile
P((const char * filename
));
149 static void inleap
P((char ** fields
, int nfields
));
150 static void inlink
P((char ** fields
, int nfields
));
151 static void inrule
P((char ** fields
, int nfields
));
152 static int inzcont
P((char ** fields
, int nfields
));
153 static int inzone
P((char ** fields
, int nfields
));
154 static int inzsub
P((char ** fields
, int nfields
, int iscont
));
155 static int is32
P((zic_t x
));
156 static int itsabbr
P((const char * abbr
, const char * word
));
157 static int itsdir
P((const char * name
));
158 static int lowerit
P((int c
));
159 static char * memcheck
P((char * tocheck
));
160 static int mkdirs
P((char * filename
));
161 static void newabbr
P((const char * abbr
));
162 static long oadd
P((long t1
, long t2
));
163 static void outzone
P((const struct zone
* zp
, int ntzones
));
164 static void puttzcode
P((long code
, FILE * fp
));
165 static void puttzcode64
P((zic_t code
, FILE * fp
));
166 static int rcomp
P((const void * leftp
, const void * rightp
));
167 static zic_t rpytime
P((const struct rule
* rp
, int wantedy
));
168 static void rulesub
P((struct rule
* rp
,
169 const char * loyearp
, const char * hiyearp
,
170 const char * typep
, const char * monthp
,
171 const char * dayp
, const char * timep
));
172 static int stringoffset
P((char * result
, long offset
));
173 static int stringrule
P((char * result
, const struct rule
* rp
,
174 long dstoff
, long gmtoff
));
175 static void stringzone
P((char * result
,
176 const struct zone
* zp
, int ntzones
));
177 static void setboundaries
P((void));
178 static zic_t tadd
P((zic_t t1
, long t2
));
179 static void usage
P((void));
180 static void writezone
P((const char * name
, const char * string
));
181 static int yearistype
P((int year
, const char * type
));
184 static char * strerror
P((int));
185 #endif /* !HAVE_STRERROR */
189 static const char * filename
;
192 static int leapminyear
;
193 static int leapmaxyear
;
195 static int max_abbrvar_len
;
196 static int max_format_len
;
197 static zic_t max_time
;
199 static zic_t min_time
;
202 static const char * rfilename
;
204 static const char * progname
;
218 ** Which fields are which on a Zone line.
226 #define ZF_TILMONTH 6
229 #define ZONE_MINFIELDS 5
230 #define ZONE_MAXFIELDS 9
233 ** Which fields are which on a Zone continuation line.
239 #define ZFC_TILYEAR 3
240 #define ZFC_TILMONTH 4
242 #define ZFC_TILTIME 6
243 #define ZONEC_MINFIELDS 3
244 #define ZONEC_MAXFIELDS 7
247 ** Which files are which on a Rule line.
259 #define RULE_FIELDS 10
262 ** Which fields are which on a Link line.
267 #define LINK_FIELDS 3
270 ** Which fields are which on a Leap line.
279 #define LEAP_FIELDS 7
289 static struct rule
* rules
;
290 static int nrules
; /* number of rules */
292 static struct zone
* zones
;
293 static int nzones
; /* number of zones */
296 const char * l_filename
;
302 static struct link
* links
;
312 /* Indices into rules[] for final rules. They will occur in pairs,
313 * with finalRules[i] occurring before finalRules[i+1] in the year.
314 * Each zone need only store a start year, a standard offset, and an
315 * index into finalRules[]. FinalRules[] are aliases into rules[]. */
317 static const struct rule
** finalRules
;
318 static int finalRulesCount
;
322 static struct lookup
const * byword
P((const char * string
,
323 const struct lookup
* lp
));
325 static struct lookup
const line_codes
[] = {
333 static struct lookup
const mon_names
[] = {
334 { "January", TM_JANUARY
},
335 { "February", TM_FEBRUARY
},
336 { "March", TM_MARCH
},
337 { "April", TM_APRIL
},
341 { "August", TM_AUGUST
},
342 { "September", TM_SEPTEMBER
},
343 { "October", TM_OCTOBER
},
344 { "November", TM_NOVEMBER
},
345 { "December", TM_DECEMBER
},
349 static struct lookup
const wday_names
[] = {
350 { "Sunday", TM_SUNDAY
},
351 { "Monday", TM_MONDAY
},
352 { "Tuesday", TM_TUESDAY
},
353 { "Wednesday", TM_WEDNESDAY
},
354 { "Thursday", TM_THURSDAY
},
355 { "Friday", TM_FRIDAY
},
356 { "Saturday", TM_SATURDAY
},
360 static struct lookup
const lasts
[] = {
361 { "last-Sunday", TM_SUNDAY
},
362 { "last-Monday", TM_MONDAY
},
363 { "last-Tuesday", TM_TUESDAY
},
364 { "last-Wednesday", TM_WEDNESDAY
},
365 { "last-Thursday", TM_THURSDAY
},
366 { "last-Friday", TM_FRIDAY
},
367 { "last-Saturday", TM_SATURDAY
},
371 static struct lookup
const begin_years
[] = {
372 { "minimum", YR_MINIMUM
},
373 { "maximum", YR_MAXIMUM
},
377 static struct lookup
const end_years
[] = {
378 { "minimum", YR_MINIMUM
},
379 { "maximum", YR_MAXIMUM
},
384 static struct lookup
const leap_types
[] = {
386 { "Stationary", FALSE
},
390 static const int len_months
[2][MONSPERYEAR
] = {
391 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
392 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
395 static const int len_years
[2] = {
396 DAYSPERNYEAR
, DAYSPERLYEAR
399 static struct attype
{
402 } attypes
[TZ_MAX_TIMES
];
403 static long gmtoffs
[TZ_MAX_TYPES
];
405 /* gmtoffs[i] = rawoffs[i] + dstoffs[i] */
406 static long rawoffs
[TZ_MAX_TYPES
];
407 static long dstoffs
[TZ_MAX_TYPES
];
409 static char isdsts
[TZ_MAX_TYPES
];
410 static unsigned char abbrinds
[TZ_MAX_TYPES
];
411 static char ttisstds
[TZ_MAX_TYPES
];
412 static char ttisgmts
[TZ_MAX_TYPES
];
413 static char chars
[TZ_MAX_CHARS
];
414 static zic_t trans
[TZ_MAX_LEAPS
];
415 static long corr
[TZ_MAX_LEAPS
];
416 static char roll
[TZ_MAX_LEAPS
];
419 ** Memory allocation.
427 const char *e
= strerror(errno
);
429 (void) fprintf(stderr
, _("%s: Memory exhausted: %s\n"),
436 #define emalloc(size) memcheck(imalloc(size))
437 #define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
438 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
439 #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
450 extern char * sys_errlist
[];
453 return (errnum
> 0 && errnum
<= sys_nerr
) ?
454 sys_errlist
[errnum
] : _("Unknown system error");
456 #endif /* !HAVE_STRERROR */
459 eats(name
, num
, rname
, rnum
)
460 const char * const name
;
462 const char * const rname
;
473 const char * const name
;
476 eats(name
, num
, (char *) NULL
, -1);
481 const char * const string
;
484 ** Match the format of "cc" to allow sh users to
485 ** zic ... 2>&1 | error -t "*" -v
488 (void) fprintf(stderr
, _("\"%s\", line %d: %s"),
489 filename
, linenum
, string
);
490 if (rfilename
!= NULL
)
491 (void) fprintf(stderr
, _(" (rule from \"%s\", line %d)"),
492 rfilename
, rlinenum
);
493 (void) fprintf(stderr
, "\n");
499 const char * const string
;
503 cp
= ecpyalloc(_("warning: "));
504 cp
= ecatalloc(cp
, string
);
513 (void) fprintf(stderr
, _("%s: usage is %s \
514 [ --version ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
515 \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
522 /* File into which we will write supplemental ICU data. */
523 static FILE * icuFile
;
525 void emit_icu_zone(FILE* f
, const char* zoneName
, int zoneOffset
,
526 const struct rule
* rule
,
527 int ruleIndex
, int startYear
) {
528 /* machine-readable section */
529 fprintf(f
, "zone %s %d %d %s", zoneName
, zoneOffset
, startYear
, rule
->r_name
);
531 /* human-readable section */
532 fprintf(f
, " # zone %s, offset %d, year >= %d, rule %s (%d)\n",
533 zoneName
, zoneOffset
, startYear
,
534 rule
->r_name
, ruleIndex
);
537 void emit_icu_link(FILE* f
, const char* from
, const char* to
) {
538 /* machine-readable section */
539 fprintf(f
, "link %s %s\n", from
, to
);
542 static const char* DYCODE
[] = {"DOM", "DOWGEQ", "DOWLEQ"};
544 void emit_icu_rule(FILE* f
, const struct rule
* r
, int ruleIndex
) {
545 if (r
->r_yrtype
!= NULL
) {
546 warning("year types not supported by ICU");
547 fprintf(stderr
, "rule %s, file %s, line %d\n",
548 r
->r_name
, r
->r_filename
, r
->r_linenum
);
551 /* machine-readable section */
552 fprintf(f
, "rule %s %s %d %d %d %d %d %d %d",
553 r
->r_name
, DYCODE
[r
->r_dycode
],
554 r
->r_month
, r
->r_dayofmonth
,
555 (r
->r_dycode
== DC_DOM
? -1 : r
->r_wday
),
556 r
->r_tod
, r
->r_todisstd
, r
->r_todisgmt
, r
->r_stdoff
559 /* human-readable section */
560 fprintf(f
, " # %d: %s, file %s, line %d",
561 ruleIndex
, r
->r_name
, r
->r_filename
, r
->r_linenum
);
562 fprintf(f
, ", mode %s", DYCODE
[r
->r_dycode
]);
563 fprintf(f
, ", %s, dom %d", mon_names
[r
->r_month
].l_word
, r
->r_dayofmonth
);
564 if (r
->r_dycode
!= DC_DOM
) {
565 fprintf(f
, ", %s", wday_names
[r
->r_wday
].l_word
);
567 fprintf(f
, ", time %d", r
->r_tod
);
568 fprintf(f
, ", isstd %d", r
->r_todisstd
);
569 fprintf(f
, ", isgmt %d", r
->r_todisgmt
);
570 fprintf(f
, ", offset %ld", r
->r_stdoff
);
576 static const char * psxrules
;
577 static const char * lcltime
;
578 static const char * directory
;
579 static const char * leapsec
;
580 static const char * yitcommand
;
592 (void) umask(umask(S_IWGRP
| S_IWOTH
) | (S_IWGRP
| S_IWOTH
));
593 #endif /* defined unix */
595 (void) setlocale(LC_ALL
, "");
597 (void) bindtextdomain(TZ_DOMAIN
, TZ_DOMAINDIR
);
598 #endif /* defined TEXTDOMAINDIR */
599 (void) textdomain(TZ_DOMAIN
);
600 #endif /* HAVE_GETTEXT */
602 if (TYPE_BIT(zic_t
) < 64) {
603 (void) fprintf(stderr
, "%s: %s\n", progname
,
604 _("wild compilation-time specification of zic_t"));
607 for (i
= 1; i
< argc
; ++i
)
608 if (strcmp(argv
[i
], "--version") == 0) {
609 (void) printf("%s\n", elsieid
);
612 while ((c
= getopt(argc
, argv
, "d:l:p:L:vsy:")) != EOF
&& c
!= -1)
617 if (directory
== NULL
)
620 (void) fprintf(stderr
,
621 _("%s: More than one -d option specified\n"),
630 (void) fprintf(stderr
,
631 _("%s: More than one -l option specified\n"),
637 if (psxrules
== NULL
)
640 (void) fprintf(stderr
,
641 _("%s: More than one -p option specified\n"),
647 if (yitcommand
== NULL
)
650 (void) fprintf(stderr
,
651 _("%s: More than one -y option specified\n"),
660 (void) fprintf(stderr
,
661 _("%s: More than one -L option specified\n"),
670 (void) printf("%s: -s ignored\n", progname
);
673 if (optind
== argc
- 1 && strcmp(argv
[optind
], "=") == 0)
674 usage(); /* usage message by request */
675 if (directory
== NULL
)
677 if (yitcommand
== NULL
)
678 yitcommand
= "yearistype";
682 if (optind
< argc
&& leapsec
!= NULL
) {
688 if ((icuFile
= fopen(ICU_ZONE_FILE
, "w")) == NULL
) {
689 const char *e
= strerror(errno
);
690 (void) fprintf(stderr
, _("%s: Can't open %s: %s\n"),
691 progname
, ICU_ZONE_FILE
, e
);
692 (void) exit(EXIT_FAILURE
);
695 for (i
= optind
; i
< argc
; ++i
)
700 for (i
= 0; i
< nzones
; i
= j
) {
702 ** Find the next non-continuation zone entry.
704 for (j
= i
+ 1; j
< nzones
&& zones
[j
].z_name
== NULL
; ++j
)
706 outzone(&zones
[i
], j
- i
);
711 for (i
= 0; i
< nlinks
; ++i
) {
712 eat(links
[i
].l_filename
, links
[i
].l_linenum
);
713 dolink(links
[i
].l_from
, links
[i
].l_to
);
715 emit_icu_link(icuFile
, links
[i
].l_from
, links
[i
].l_to
);
718 for (j
= 0; j
< nlinks
; ++j
)
719 if (strcmp(links
[i
].l_to
,
720 links
[j
].l_from
) == 0)
721 warning(_("link to link"));
723 if (lcltime
!= NULL
) {
724 eat("command line", 1);
725 dolink(lcltime
, TZDEFAULT
);
727 if (psxrules
!= NULL
) {
728 eat("command line", 1);
729 dolink(psxrules
, TZDEFRULES
);
732 for (i
=0; i
<finalRulesCount
; ++i
) {
733 emit_icu_rule(icuFile
, finalRules
[i
], i
);
736 return (errors
== 0) ? EXIT_SUCCESS
: EXIT_FAILURE
;
740 dolink(fromfile
, tofile
)
741 const char * const fromfile
;
742 const char * const tofile
;
744 register char * fromname
;
745 register char * toname
;
747 if (fromfile
[0] == '/')
748 fromname
= ecpyalloc(fromfile
);
750 fromname
= ecpyalloc(directory
);
751 fromname
= ecatalloc(fromname
, "/");
752 fromname
= ecatalloc(fromname
, fromfile
);
754 if (tofile
[0] == '/')
755 toname
= ecpyalloc(tofile
);
757 toname
= ecpyalloc(directory
);
758 toname
= ecatalloc(toname
, "/");
759 toname
= ecatalloc(toname
, tofile
);
762 ** We get to be careful here since
763 ** there's a fair chance of root running us.
766 (void) remove(toname
);
767 if (link(fromname
, toname
) != 0) {
770 if (mkdirs(toname
) != 0)
773 result
= link(fromname
, toname
);
776 access(fromname
, F_OK
) == 0 &&
778 const char *s
= tofile
;
779 register char * symlinkcontents
= NULL
;
781 while ((s
= strchr(s
+1, '/')) != NULL
)
783 ecatalloc(symlinkcontents
,
786 ecatalloc(symlinkcontents
,
788 result
= symlink(symlinkcontents
,
791 warning(_("hard link failed, symbolic link used"));
792 ifree(symlinkcontents
);
794 #endif /* HAVE_SYMLINK */
796 const char *e
= strerror(errno
);
798 (void) fprintf(stderr
,
799 _("%s: Can't link from %s to %s: %s\n"),
800 progname
, fromname
, toname
, e
);
810 #define TIME_T_BITS_IN_FILE 64
813 setboundaries
P((void))
818 for (i
= 0; i
< TIME_T_BITS_IN_FILE
- 1; ++i
)
820 max_time
= -(min_time
+ 1);
825 const char * const name
;
827 register char * myname
;
830 myname
= ecpyalloc(name
);
831 myname
= ecatalloc(myname
, "/.");
832 accres
= access(myname
, F_OK
);
838 ** Associate sets of rules with zones.
842 ** Sort by rule name.
850 return strcmp(((const struct rule
*) cp1
)->r_name
,
851 ((const struct rule
*) cp2
)->r_name
);
857 register struct zone
* zp
;
858 register struct rule
* rp
;
859 register int base
, out
;
863 (void) qsort((void *) rules
, (size_t) nrules
,
864 (size_t) sizeof *rules
, rcomp
);
865 for (i
= 0; i
< nrules
- 1; ++i
) {
866 if (strcmp(rules
[i
].r_name
,
867 rules
[i
+ 1].r_name
) != 0)
869 if (strcmp(rules
[i
].r_filename
,
870 rules
[i
+ 1].r_filename
) == 0)
872 eat(rules
[i
].r_filename
, rules
[i
].r_linenum
);
873 warning(_("same rule name in multiple files"));
874 eat(rules
[i
+ 1].r_filename
, rules
[i
+ 1].r_linenum
);
875 warning(_("same rule name in multiple files"));
876 for (j
= i
+ 2; j
< nrules
; ++j
) {
877 if (strcmp(rules
[i
].r_name
,
878 rules
[j
].r_name
) != 0)
880 if (strcmp(rules
[i
].r_filename
,
881 rules
[j
].r_filename
) == 0)
883 if (strcmp(rules
[i
+ 1].r_filename
,
884 rules
[j
].r_filename
) == 0)
891 for (i
= 0; i
< nzones
; ++i
) {
896 for (base
= 0; base
< nrules
; base
= out
) {
898 for (out
= base
+ 1; out
< nrules
; ++out
)
899 if (strcmp(rp
->r_name
, rules
[out
].r_name
) != 0)
901 for (i
= 0; i
< nzones
; ++i
) {
903 if (strcmp(zp
->z_rule
, rp
->r_name
) != 0)
906 zp
->z_nrules
= out
- base
;
909 for (i
= 0; i
< nzones
; ++i
) {
911 if (zp
->z_nrules
== 0) {
913 ** Maybe we have a local standard time offset.
915 eat(zp
->z_filename
, zp
->z_linenum
);
916 zp
->z_stdoff
= gethms(zp
->z_rule
, _("unruly zone"),
919 ** Note, though, that if there's no rule,
920 ** a '%s' in the format is a bad thing.
922 if (strchr(zp
->z_format
, '%') != 0)
923 error(_("%s in ruleless zone"));
935 register char ** fields
;
937 register const struct lookup
* lp
;
938 register int nfields
;
939 register int wantcont
;
943 if (strcmp(name
, "-") == 0) {
944 name
= _("standard input");
946 } else if ((fp
= fopen(name
, "r")) == NULL
) {
947 const char *e
= strerror(errno
);
949 (void) fprintf(stderr
, _("%s: Can't open %s: %s\n"),
954 for (num
= 1; ; ++num
) {
956 if (fgets(buf
, (int) sizeof buf
, fp
) != buf
)
958 cp
= strchr(buf
, '\n');
960 error(_("line too long"));
964 fields
= getfields(buf
);
966 while (fields
[nfields
] != NULL
) {
969 if (strcmp(fields
[nfields
], "-") == 0)
970 fields
[nfields
] = &nada
;
975 } else if (wantcont
) {
976 wantcont
= inzcont(fields
, nfields
);
978 lp
= byword(fields
[0], line_codes
);
980 error(_("input line of unknown type"));
981 else switch ((int) (lp
->l_value
)) {
983 inrule(fields
, nfields
);
987 wantcont
= inzone(fields
, nfields
);
990 inlink(fields
, nfields
);
995 (void) fprintf(stderr
,
996 _("%s: Leap line in non leap seconds file %s\n"),
998 else inleap(fields
, nfields
);
1001 default: /* "cannot happen" */
1002 (void) fprintf(stderr
,
1003 _("%s: panic: Invalid l_value %d\n"),
1004 progname
, lp
->l_value
);
1008 ifree((char *) fields
);
1011 (void) fprintf(stderr
, _("%s: Error reading %s\n"),
1012 progname
, filename
);
1015 if (fp
!= stdin
&& fclose(fp
)) {
1016 const char *e
= strerror(errno
);
1018 (void) fprintf(stderr
, _("%s: Error closing %s: %s\n"),
1019 progname
, filename
, e
);
1023 error(_("expected continuation line not found"));
1027 ** Convert a string of one of the forms
1028 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1029 ** into a number of seconds.
1030 ** A null string maps to zero.
1031 ** Call error with errstring and return zero on errors.
1035 gethms(string
, errstring
, signable
)
1036 const char * string
;
1037 const char * const errstring
;
1040 int hh
, mm
, ss
, sign
;
1042 if (string
== NULL
|| *string
== '\0')
1046 else if (*string
== '-') {
1050 if (sscanf(string
, scheck(string
, "%d"), &hh
) == 1)
1052 else if (sscanf(string
, scheck(string
, "%d:%d"), &hh
, &mm
) == 2)
1054 else if (sscanf(string
, scheck(string
, "%d:%d:%d"),
1055 &hh
, &mm
, &ss
) != 3) {
1059 if ((hh
< 0 || hh
>= HOURSPERDAY
||
1060 mm
< 0 || mm
>= MINSPERHOUR
||
1061 ss
< 0 || ss
> SECSPERMIN
) &&
1062 !(hh
== HOURSPERDAY
&& mm
== 0 && ss
== 0)) {
1066 if (noise
&& hh
== HOURSPERDAY
)
1067 warning(_("24:00 not handled by pre-1998 versions of zic"));
1068 return eitol(sign
) *
1069 (eitol(hh
* MINSPERHOUR
+ mm
) *
1070 eitol(SECSPERMIN
) + eitol(ss
));
1074 inrule(fields
, nfields
)
1075 register char ** const fields
;
1078 static struct rule r
;
1080 if (nfields
!= RULE_FIELDS
) {
1081 error(_("wrong number of fields on Rule line"));
1084 if (*fields
[RF_NAME
] == '\0') {
1085 error(_("nameless rule"));
1088 r
.r_filename
= filename
;
1089 r
.r_linenum
= linenum
;
1090 r
.r_stdoff
= gethms(fields
[RF_STDOFF
], _("invalid saved time"), TRUE
);
1091 rulesub(&r
, fields
[RF_LOYEAR
], fields
[RF_HIYEAR
], fields
[RF_COMMAND
],
1092 fields
[RF_MONTH
], fields
[RF_DAY
], fields
[RF_TOD
]);
1093 r
.r_name
= ecpyalloc(fields
[RF_NAME
]);
1094 r
.r_abbrvar
= ecpyalloc(fields
[RF_ABBRVAR
]);
1095 if (max_abbrvar_len
< strlen(r
.r_abbrvar
))
1096 max_abbrvar_len
= strlen(r
.r_abbrvar
);
1097 rules
= (struct rule
*) (void *) erealloc((char *) rules
,
1098 (int) ((nrules
+ 1) * sizeof *rules
));
1099 rules
[nrules
++] = r
;
1103 inzone(fields
, nfields
)
1104 register char ** const fields
;
1110 if (nfields
< ZONE_MINFIELDS
|| nfields
> ZONE_MAXFIELDS
) {
1111 error(_("wrong number of fields on Zone line"));
1114 if (strcmp(fields
[ZF_NAME
], TZDEFAULT
) == 0 && lcltime
!= NULL
) {
1115 buf
= erealloc(buf
, (int) (132 + strlen(TZDEFAULT
)));
1117 _("\"Zone %s\" line and -l option are mutually exclusive"),
1122 if (strcmp(fields
[ZF_NAME
], TZDEFRULES
) == 0 && psxrules
!= NULL
) {
1123 buf
= erealloc(buf
, (int) (132 + strlen(TZDEFRULES
)));
1125 _("\"Zone %s\" line and -p option are mutually exclusive"),
1130 for (i
= 0; i
< nzones
; ++i
)
1131 if (zones
[i
].z_name
!= NULL
&&
1132 strcmp(zones
[i
].z_name
, fields
[ZF_NAME
]) == 0) {
1133 buf
= erealloc(buf
, (int) (132 +
1134 strlen(fields
[ZF_NAME
]) +
1135 strlen(zones
[i
].z_filename
)));
1137 _("duplicate zone name %s (file \"%s\", line %d)"),
1139 zones
[i
].z_filename
,
1140 zones
[i
].z_linenum
);
1144 return inzsub(fields
, nfields
, FALSE
);
1148 inzcont(fields
, nfields
)
1149 register char ** const fields
;
1152 if (nfields
< ZONEC_MINFIELDS
|| nfields
> ZONEC_MAXFIELDS
) {
1153 error(_("wrong number of fields on Zone continuation line"));
1156 return inzsub(fields
, nfields
, TRUE
);
1160 inzsub(fields
, nfields
, iscont
)
1161 register char ** const fields
;
1166 static struct zone z
;
1167 register int i_gmtoff
, i_rule
, i_format
;
1168 register int i_untilyear
, i_untilmonth
;
1169 register int i_untilday
, i_untiltime
;
1170 register int hasuntil
;
1173 i_gmtoff
= ZFC_GMTOFF
;
1175 i_format
= ZFC_FORMAT
;
1176 i_untilyear
= ZFC_TILYEAR
;
1177 i_untilmonth
= ZFC_TILMONTH
;
1178 i_untilday
= ZFC_TILDAY
;
1179 i_untiltime
= ZFC_TILTIME
;
1182 i_gmtoff
= ZF_GMTOFF
;
1184 i_format
= ZF_FORMAT
;
1185 i_untilyear
= ZF_TILYEAR
;
1186 i_untilmonth
= ZF_TILMONTH
;
1187 i_untilday
= ZF_TILDAY
;
1188 i_untiltime
= ZF_TILTIME
;
1189 z
.z_name
= ecpyalloc(fields
[ZF_NAME
]);
1191 z
.z_filename
= filename
;
1192 z
.z_linenum
= linenum
;
1193 z
.z_gmtoff
= gethms(fields
[i_gmtoff
], _("invalid UTC offset"), TRUE
);
1194 if ((cp
= strchr(fields
[i_format
], '%')) != 0) {
1195 if (*++cp
!= 's' || strchr(cp
, '%') != 0) {
1196 error(_("invalid abbreviation format"));
1200 z
.z_rule
= ecpyalloc(fields
[i_rule
]);
1201 z
.z_format
= ecpyalloc(fields
[i_format
]);
1202 if (max_format_len
< strlen(z
.z_format
))
1203 max_format_len
= strlen(z
.z_format
);
1204 hasuntil
= nfields
> i_untilyear
;
1206 z
.z_untilrule
.r_filename
= filename
;
1207 z
.z_untilrule
.r_linenum
= linenum
;
1208 rulesub(&z
.z_untilrule
,
1209 fields
[i_untilyear
],
1212 (nfields
> i_untilmonth
) ?
1213 fields
[i_untilmonth
] : "Jan",
1214 (nfields
> i_untilday
) ? fields
[i_untilday
] : "1",
1215 (nfields
> i_untiltime
) ? fields
[i_untiltime
] : "0");
1216 z
.z_untiltime
= rpytime(&z
.z_untilrule
,
1217 z
.z_untilrule
.r_loyear
);
1218 if (iscont
&& nzones
> 0 &&
1219 z
.z_untiltime
> min_time
&&
1220 z
.z_untiltime
< max_time
&&
1221 zones
[nzones
- 1].z_untiltime
> min_time
&&
1222 zones
[nzones
- 1].z_untiltime
< max_time
&&
1223 zones
[nzones
- 1].z_untiltime
>= z
.z_untiltime
) {
1225 "Zone continuation line end time is not after end time of previous line"
1230 zones
= (struct zone
*) (void *) erealloc((char *) zones
,
1231 (int) ((nzones
+ 1) * sizeof *zones
));
1232 zones
[nzones
++] = z
;
1234 ** If there was an UNTIL field on this line,
1235 ** there's more information about the zone on the next line.
1241 inleap(fields
, nfields
)
1242 register char ** const fields
;
1245 register const char * cp
;
1246 register const struct lookup
* lp
;
1248 int year
, month
, day
;
1252 if (nfields
!= LEAP_FIELDS
) {
1253 error(_("wrong number of fields on Leap line"));
1257 cp
= fields
[LP_YEAR
];
1258 if (sscanf(cp
, scheck(cp
, "%d"), &year
) != 1) {
1262 error(_("invalid leaping year"));
1265 if (!leapseen
|| leapmaxyear
< year
)
1267 if (!leapseen
|| leapminyear
> year
)
1273 i
= len_years
[isleap(j
)];
1277 i
= -len_years
[isleap(j
)];
1279 dayoff
= oadd(dayoff
, eitol(i
));
1281 if ((lp
= byword(fields
[LP_MONTH
], mon_names
)) == NULL
) {
1282 error(_("invalid month name"));
1285 month
= lp
->l_value
;
1287 while (j
!= month
) {
1288 i
= len_months
[isleap(year
)][j
];
1289 dayoff
= oadd(dayoff
, eitol(i
));
1292 cp
= fields
[LP_DAY
];
1293 if (sscanf(cp
, scheck(cp
, "%d"), &day
) != 1 ||
1294 day
<= 0 || day
> len_months
[isleap(year
)][month
]) {
1295 error(_("invalid day of month"));
1298 dayoff
= oadd(dayoff
, eitol(day
- 1));
1299 if (dayoff
< 0 && !TYPE_SIGNED(zic_t
)) {
1300 error(_("time before zero"));
1303 if (dayoff
< min_time
/ SECSPERDAY
) {
1304 error(_("time too small"));
1307 if (dayoff
> max_time
/ SECSPERDAY
) {
1308 error(_("time too large"));
1311 t
= (zic_t
) dayoff
* SECSPERDAY
;
1312 tod
= gethms(fields
[LP_TIME
], _("invalid time of day"), FALSE
);
1313 cp
= fields
[LP_CORR
];
1315 register int positive
;
1318 if (strcmp(cp
, "") == 0) { /* infile() turns "-" into "" */
1321 } else if (strcmp(cp
, "--") == 0) {
1324 } else if (strcmp(cp
, "+") == 0) {
1327 } else if (strcmp(cp
, "++") == 0) {
1331 error(_("illegal CORRECTION field on Leap line"));
1334 if ((lp
= byword(fields
[LP_ROLL
], leap_types
)) == NULL
) {
1336 "illegal Rolling/Stationary field on Leap line"
1340 leapadd(tadd(t
, tod
), positive
, lp
->l_value
, count
);
1345 inlink(fields
, nfields
)
1346 register char ** const fields
;
1351 if (nfields
!= LINK_FIELDS
) {
1352 error(_("wrong number of fields on Link line"));
1355 if (*fields
[LF_FROM
] == '\0') {
1356 error(_("blank FROM field on Link line"));
1359 if (*fields
[LF_TO
] == '\0') {
1360 error(_("blank TO field on Link line"));
1363 l
.l_filename
= filename
;
1364 l
.l_linenum
= linenum
;
1365 l
.l_from
= ecpyalloc(fields
[LF_FROM
]);
1366 l
.l_to
= ecpyalloc(fields
[LF_TO
]);
1367 links
= (struct link
*) (void *) erealloc((char *) links
,
1368 (int) ((nlinks
+ 1) * sizeof *links
));
1369 links
[nlinks
++] = l
;
1373 rulesub(rp
, loyearp
, hiyearp
, typep
, monthp
, dayp
, timep
)
1374 register struct rule
* const rp
;
1375 const char * const loyearp
;
1376 const char * const hiyearp
;
1377 const char * const typep
;
1378 const char * const monthp
;
1379 const char * const dayp
;
1380 const char * const timep
;
1382 register const struct lookup
* lp
;
1383 register const char * cp
;
1387 if ((lp
= byword(monthp
, mon_names
)) == NULL
) {
1388 error(_("invalid month name"));
1391 rp
->r_month
= lp
->l_value
;
1392 rp
->r_todisstd
= FALSE
;
1393 rp
->r_todisgmt
= FALSE
;
1394 dp
= ecpyalloc(timep
);
1396 ep
= dp
+ strlen(dp
) - 1;
1397 switch (lowerit(*ep
)) {
1398 case 's': /* Standard */
1399 rp
->r_todisstd
= TRUE
;
1400 rp
->r_todisgmt
= FALSE
;
1403 case 'w': /* Wall */
1404 rp
->r_todisstd
= FALSE
;
1405 rp
->r_todisgmt
= FALSE
;
1408 case 'g': /* Greenwich */
1409 case 'u': /* Universal */
1410 case 'z': /* Zulu */
1411 rp
->r_todisstd
= TRUE
;
1412 rp
->r_todisgmt
= TRUE
;
1417 rp
->r_tod
= gethms(dp
, _("invalid time of day"), FALSE
);
1423 lp
= byword(cp
, begin_years
);
1424 rp
->r_lowasnum
= lp
== NULL
;
1425 if (!rp
->r_lowasnum
) switch ((int) lp
->l_value
) {
1427 rp
->r_loyear
= INT_MIN
;
1430 rp
->r_loyear
= INT_MAX
;
1432 default: /* "cannot happen" */
1433 (void) fprintf(stderr
,
1434 _("%s: panic: Invalid l_value %d\n"),
1435 progname
, lp
->l_value
);
1437 } else if (sscanf(cp
, scheck(cp
, "%d"), &rp
->r_loyear
) != 1) {
1438 error(_("invalid starting year"));
1442 lp
= byword(cp
, end_years
);
1443 rp
->r_hiwasnum
= lp
== NULL
;
1444 if (!rp
->r_hiwasnum
) switch ((int) lp
->l_value
) {
1446 rp
->r_hiyear
= INT_MIN
;
1449 rp
->r_hiyear
= INT_MAX
;
1452 rp
->r_hiyear
= rp
->r_loyear
;
1454 default: /* "cannot happen" */
1455 (void) fprintf(stderr
,
1456 _("%s: panic: Invalid l_value %d\n"),
1457 progname
, lp
->l_value
);
1459 } else if (sscanf(cp
, scheck(cp
, "%d"), &rp
->r_hiyear
) != 1) {
1460 error(_("invalid ending year"));
1463 if (rp
->r_loyear
> rp
->r_hiyear
) {
1464 error(_("starting year greater than ending year"));
1468 rp
->r_yrtype
= NULL
;
1470 if (rp
->r_loyear
== rp
->r_hiyear
) {
1471 error(_("typed single year"));
1474 rp
->r_yrtype
= ecpyalloc(typep
);
1478 ** Accept things such as:
1484 dp
= ecpyalloc(dayp
);
1485 if ((lp
= byword(dp
, lasts
)) != NULL
) {
1486 rp
->r_dycode
= DC_DOWLEQ
;
1487 rp
->r_wday
= lp
->l_value
;
1488 rp
->r_dayofmonth
= len_months
[1][rp
->r_month
];
1490 if ((ep
= strchr(dp
, '<')) != 0)
1491 rp
->r_dycode
= DC_DOWLEQ
;
1492 else if ((ep
= strchr(dp
, '>')) != 0)
1493 rp
->r_dycode
= DC_DOWGEQ
;
1496 rp
->r_dycode
= DC_DOM
;
1498 if (rp
->r_dycode
!= DC_DOM
) {
1501 error(_("invalid day of month"));
1505 if ((lp
= byword(dp
, wday_names
)) == NULL
) {
1506 error(_("invalid weekday name"));
1510 rp
->r_wday
= lp
->l_value
;
1512 if (sscanf(ep
, scheck(ep
, "%d"), &rp
->r_dayofmonth
) != 1 ||
1513 rp
->r_dayofmonth
<= 0 ||
1514 (rp
->r_dayofmonth
> len_months
[1][rp
->r_month
])) {
1515 error(_("invalid day of month"));
1531 for (i
= 0, shift
= 24; i
< 4; ++i
, shift
-= 8)
1532 buf
[i
] = val
>> shift
;
1543 for (i
= 0, shift
= 56; i
< 8; ++i
, shift
-= 8)
1544 buf
[i
] = val
>> shift
;
1555 (void) fwrite((void *) buf
, (size_t) sizeof buf
, (size_t) 1, fp
);
1559 puttzcode64(val
, fp
)
1565 convert64(val
, buf
);
1566 (void) fwrite((void *) buf
, (size_t) sizeof buf
, (size_t) 1, fp
);
1574 const zic_t a
= ((const struct attype
*) avp
)->at
;
1575 const zic_t b
= ((const struct attype
*) bvp
)->at
;
1577 return (a
< b
) ? -1 : (a
> b
);
1584 return INT32_MIN
<= x
&& x
<= INT32_MAX
;
1588 writezone(name
, string
)
1589 const char * const name
;
1590 const char * const string
;
1594 register int leapcnt32
, leapi32
;
1595 register int timecnt32
, timei32
;
1597 static char * fullname
;
1598 static const struct tzhead tzh0
;
1599 static struct tzhead tzh
;
1600 zic_t ats
[TZ_MAX_TIMES
];
1601 unsigned char types
[TZ_MAX_TIMES
];
1607 (void) qsort((void *) attypes
, (size_t) timecnt
,
1608 (size_t) sizeof *attypes
, atcomp
);
1618 while (fromi
< timecnt
&& attypes
[fromi
].at
< min_time
)
1621 while (fromi
< timecnt
&& attypes
[fromi
].type
== 0)
1622 ++fromi
; /* handled by default rule */
1623 for ( ; fromi
< timecnt
; ++fromi
) {
1624 if (toi
!= 0 && ((attypes
[fromi
].at
+
1625 gmtoffs
[attypes
[toi
- 1].type
]) <=
1626 (attypes
[toi
- 1].at
+ gmtoffs
[toi
== 1 ? 0
1627 : attypes
[toi
- 2].type
]))) {
1628 attypes
[toi
- 1].type
=
1629 attypes
[fromi
].type
;
1633 attypes
[toi
- 1].type
!= attypes
[fromi
].type
)
1634 attypes
[toi
++] = attypes
[fromi
];
1641 for (i
= 0; i
< timecnt
; ++i
) {
1642 ats
[i
] = attypes
[i
].at
;
1643 types
[i
] = attypes
[i
].type
;
1646 ** Correct for leap seconds.
1648 for (i
= 0; i
< timecnt
; ++i
) {
1651 if (ats
[i
] > trans
[j
] - corr
[j
]) {
1652 ats
[i
] = tadd(ats
[i
], corr
[j
]);
1657 ** Figure out 32-bit-limited starts and counts.
1659 timecnt32
= timecnt
;
1661 leapcnt32
= leapcnt
;
1663 while (timecnt32
> 0 && !is32(ats
[timecnt32
- 1]))
1665 while (timecnt32
> 0 && !is32(ats
[timei32
])) {
1669 while (leapcnt32
> 0 && !is32(trans
[leapcnt32
- 1]))
1671 while (leapcnt32
> 0 && !is32(trans
[leapi32
])) {
1675 fullname
= erealloc(fullname
,
1676 (int) (strlen(directory
) + 1 + strlen(name
) + 1));
1677 (void) sprintf(fullname
, "%s/%s", directory
, name
);
1679 ** Remove old file, if any, to snap links.
1681 if (!itsdir(fullname
) && remove(fullname
) != 0 && errno
!= ENOENT
) {
1682 const char *e
= strerror(errno
);
1684 (void) fprintf(stderr
, _("%s: Can't remove %s: %s\n"),
1685 progname
, fullname
, e
);
1688 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1689 if (mkdirs(fullname
) != 0)
1691 if ((fp
= fopen(fullname
, "wb")) == NULL
) {
1692 const char *e
= strerror(errno
);
1694 (void) fprintf(stderr
, _("%s: Can't create %s: %s\n"),
1695 progname
, fullname
, e
);
1699 for (pass
= 1; pass
<= 2; ++pass
) {
1700 register int thistimei
, thistimecnt
;
1701 register int thisleapi
, thisleapcnt
;
1702 register int thistimelim
, thisleaplim
;
1703 int writetype
[TZ_MAX_TIMES
];
1704 int typemap
[TZ_MAX_TYPES
];
1705 register int thistypecnt
;
1706 char thischars
[TZ_MAX_CHARS
];
1708 int indmap
[TZ_MAX_CHARS
];
1711 thistimei
= timei32
;
1712 thistimecnt
= timecnt32
;
1713 thisleapi
= leapi32
;
1714 thisleapcnt
= leapcnt32
;
1717 thistimecnt
= timecnt
;
1719 thisleapcnt
= leapcnt
;
1721 thistimelim
= thistimei
+ thistimecnt
;
1722 thisleaplim
= thisleapi
+ thisleapcnt
;
1723 for (i
= 0; i
< typecnt
; ++i
)
1724 writetype
[i
] = thistimecnt
== timecnt
;
1725 if (thistimecnt
== 0) {
1727 ** No transition times fall in the current
1728 ** (32- or 64-bit) window.
1731 writetype
[typecnt
- 1] = TRUE
;
1733 for (i
= thistimei
- 1; i
< thistimelim
; ++i
)
1735 writetype
[types
[i
]] = TRUE
;
1737 ** For America/Godthab and Antarctica/Palmer
1740 writetype
[0] = TRUE
;
1743 for (i
= 0; i
< typecnt
; ++i
)
1744 typemap
[i
] = writetype
[i
] ? thistypecnt
++ : -1;
1745 for (i
= 0; i
< sizeof indmap
/ sizeof indmap
[0]; ++i
)
1748 for (i
= 0; i
< typecnt
; ++i
) {
1749 register char * thisabbr
;
1753 if (indmap
[abbrinds
[i
]] >= 0)
1755 thisabbr
= &chars
[abbrinds
[i
]];
1756 for (j
= 0; j
< thischarcnt
; ++j
)
1757 if (strcmp(&thischars
[j
], thisabbr
) == 0)
1759 if (j
== thischarcnt
) {
1760 (void) strcpy(&thischars
[(int) thischarcnt
],
1762 thischarcnt
+= strlen(thisabbr
) + 1;
1764 indmap
[abbrinds
[i
]] = j
;
1766 #define DO(field) (void) fwrite((void *) tzh.field, \
1767 (size_t) sizeof tzh.field, (size_t) 1, fp)
1770 * (ICUZoneinfoVersion
*) &tzh
.tzh_reserved
= TZ_ICU_VERSION
;
1771 (void) strncpy(tzh
.tzh_magic
, TZ_ICU_MAGIC
, sizeof tzh
.tzh_magic
);
1773 (void) strncpy(tzh
.tzh_magic
, TZ_MAGIC
, sizeof tzh
.tzh_magic
);
1775 tzh
.tzh_version
[0] = ZIC_VERSION
;
1776 convert(eitol(thistypecnt
), tzh
.tzh_ttisgmtcnt
);
1777 convert(eitol(thistypecnt
), tzh
.tzh_ttisstdcnt
);
1778 convert(eitol(thisleapcnt
), tzh
.tzh_leapcnt
);
1779 convert(eitol(thistimecnt
), tzh
.tzh_timecnt
);
1780 convert(eitol(thistypecnt
), tzh
.tzh_typecnt
);
1781 convert(eitol(thischarcnt
), tzh
.tzh_charcnt
);
1792 for (i
= thistimei
; i
< thistimelim
; ++i
)
1794 puttzcode((long) ats
[i
], fp
);
1795 else puttzcode64(ats
[i
], fp
);
1796 for (i
= thistimei
; i
< thistimelim
; ++i
) {
1799 uc
= typemap
[types
[i
]];
1800 (void) fwrite((void *) &uc
,
1805 for (i
= 0; i
< typecnt
; ++i
)
1808 puttzcode((long) rawoffs
[i
], fp
);
1809 puttzcode((long) dstoffs
[i
], fp
);
1811 puttzcode((long) gmtoffs
[i
], fp
);
1813 (void) putc(isdsts
[i
], fp
);
1814 (void) putc((unsigned char) indmap
[abbrinds
[i
]], fp
);
1816 if (thischarcnt
!= 0)
1817 (void) fwrite((void *) thischars
,
1818 (size_t) sizeof thischars
[0],
1819 (size_t) thischarcnt
, fp
);
1820 for (i
= thisleapi
; i
< thisleaplim
; ++i
) {
1821 register zic_t todo
;
1824 if (timecnt
== 0 || trans
[i
] < ats
[0]) {
1827 if (++j
>= typecnt
) {
1833 while (j
< timecnt
&&
1838 todo
= tadd(trans
[i
], -gmtoffs
[j
]);
1839 } else todo
= trans
[i
];
1841 puttzcode((long) todo
, fp
);
1842 else puttzcode64(todo
, fp
);
1843 puttzcode(corr
[i
], fp
);
1845 for (i
= 0; i
< typecnt
; ++i
)
1847 (void) putc(ttisstds
[i
], fp
);
1848 for (i
= 0; i
< typecnt
; ++i
)
1850 (void) putc(ttisgmts
[i
], fp
);
1852 (void) fprintf(fp
, "\n%s\n", string
);
1853 if (ferror(fp
) || fclose(fp
)) {
1854 (void) fprintf(stderr
, _("%s: Error writing %s\n"),
1855 progname
, fullname
);
1861 doabbr(abbr
, format
, letters
, isdst
, doquotes
)
1863 const char * const format
;
1864 const char * const letters
;
1869 register char * slashp
;
1872 slashp
= strchr(format
, '/');
1873 if (slashp
== NULL
) {
1874 if (letters
== NULL
)
1875 (void) strcpy(abbr
, format
);
1876 else (void) sprintf(abbr
, format
, letters
);
1878 (void) strcpy(abbr
, slashp
+ 1);
1880 if (slashp
> format
)
1881 (void) strncpy(abbr
, format
,
1882 (unsigned) (slashp
- format
));
1883 abbr
[slashp
- format
] = '\0';
1887 for (cp
= abbr
; *cp
!= '\0'; ++cp
)
1888 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp
) == NULL
&&
1889 strchr("abcdefghijklmnopqrstuvwxyz", *cp
) == NULL
)
1892 if (len
> 0 && *cp
== '\0')
1894 abbr
[len
+ 2] = '\0';
1895 abbr
[len
+ 1] = '>';
1896 for ( ; len
> 0; --len
)
1897 abbr
[len
] = abbr
[len
- 1];
1912 stringoffset(result
, offset
)
1917 register int minutes
;
1918 register int seconds
;
1922 (void) strcpy(result
, "-");
1925 seconds
= offset
% SECSPERMIN
;
1926 offset
/= SECSPERMIN
;
1927 minutes
= offset
% MINSPERHOUR
;
1928 offset
/= MINSPERHOUR
;
1930 if (hours
>= HOURSPERDAY
) {
1934 (void) sprintf(end(result
), "%d", hours
);
1935 if (minutes
!= 0 || seconds
!= 0) {
1936 (void) sprintf(end(result
), ":%02d", minutes
);
1938 (void) sprintf(end(result
), ":%02d", seconds
);
1944 stringrule(result
, rp
, dstoff
, gmtoff
)
1946 const struct rule
* const rp
;
1952 result
= end(result
);
1953 if (rp
->r_dycode
== DC_DOM
) {
1954 register int month
, total
;
1956 if (rp
->r_dayofmonth
== 29 && rp
->r_month
== TM_FEBRUARY
)
1959 for (month
= 0; month
< rp
->r_month
; ++month
)
1960 total
+= len_months
[0][month
];
1961 (void) sprintf(result
, "J%d", total
+ rp
->r_dayofmonth
);
1965 if (rp
->r_dycode
== DC_DOWGEQ
) {
1966 week
= 1 + rp
->r_dayofmonth
/ DAYSPERWEEK
;
1967 if ((week
- 1) * DAYSPERWEEK
+ 1 != rp
->r_dayofmonth
)
1969 } else if (rp
->r_dycode
== DC_DOWLEQ
) {
1970 if (rp
->r_dayofmonth
== len_months
[1][rp
->r_month
])
1973 week
= 1 + rp
->r_dayofmonth
/ DAYSPERWEEK
;
1974 if (week
* DAYSPERWEEK
- 1 != rp
->r_dayofmonth
)
1977 } else return -1; /* "cannot happen" */
1978 (void) sprintf(result
, "M%d.%d.%d",
1979 rp
->r_month
+ 1, week
, rp
->r_wday
);
1984 if (rp
->r_todisstd
&& rp
->r_stdoff
== 0)
1990 if (tod
!= 2 * SECSPERMIN
* MINSPERHOUR
) {
1991 (void) strcat(result
, "/");
1992 if (stringoffset(end(result
), tod
) != 0)
1999 stringzone(result
, zpfirst
, zonecount
)
2001 const struct zone
* const zpfirst
;
2002 const int zonecount
;
2004 register const struct zone
* zp
;
2005 register struct rule
* rp
;
2006 register struct rule
* stdrp
;
2007 register struct rule
* dstrp
;
2009 register const char * abbrvar
;
2012 zp
= zpfirst
+ zonecount
- 1;
2013 stdrp
= dstrp
= NULL
;
2014 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2015 rp
= &zp
->z_rules
[i
];
2016 if (rp
->r_hiwasnum
|| rp
->r_hiyear
!= INT_MAX
)
2018 if (rp
->r_yrtype
!= NULL
)
2020 if (rp
->r_stdoff
== 0) {
2030 if (stdrp
== NULL
&& dstrp
== NULL
) {
2032 ** There are no rules running through "max".
2033 ** Let's find the latest rule.
2035 for (i
= 0; i
< zp
->z_nrules
; ++i
) {
2036 rp
= &zp
->z_rules
[i
];
2037 if (stdrp
== NULL
|| rp
->r_hiyear
> stdrp
->r_hiyear
||
2038 (rp
->r_hiyear
== stdrp
->r_hiyear
&&
2039 rp
->r_month
> stdrp
->r_month
))
2042 if (stdrp
!= NULL
&& stdrp
->r_stdoff
!= 0)
2043 return; /* We end up in DST (a POSIX no-no). */
2045 ** Horrid special case: if year is 2037,
2046 ** presume this is a zone handled on a year-by-year basis;
2047 ** do not try to apply a rule to the zone.
2049 if (stdrp
!= NULL
&& stdrp
->r_hiyear
== 2037)
2052 if (stdrp
== NULL
&& zp
->z_nrules
!= 0)
2054 abbrvar
= (stdrp
== NULL
) ? "" : stdrp
->r_abbrvar
;
2055 doabbr(result
, zp
->z_format
, abbrvar
, FALSE
, TRUE
);
2056 if (stringoffset(end(result
), -zp
->z_gmtoff
) != 0) {
2062 doabbr(end(result
), zp
->z_format
, dstrp
->r_abbrvar
, TRUE
, TRUE
);
2063 if (dstrp
->r_stdoff
!= SECSPERMIN
* MINSPERHOUR
)
2064 if (stringoffset(end(result
),
2065 -(zp
->z_gmtoff
+ dstrp
->r_stdoff
)) != 0) {
2069 (void) strcat(result
, ",");
2070 if (stringrule(result
, dstrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
) != 0) {
2074 (void) strcat(result
, ",");
2075 if (stringrule(result
, stdrp
, dstrp
->r_stdoff
, zp
->z_gmtoff
) != 0) {
2083 int add_icu_final_rules(const struct rule
* r1
, const struct rule
* r2
) {
2086 for (i
=0; i
<finalRulesCount
; ++i
) { /* i+=2 should work too */
2087 if (r1
==finalRules
[i
]) return i
; /* [sic] pointer comparison */
2090 finalRules
= (const struct rule
**) (void*) erealloc((char *) finalRules
,
2091 (finalRulesCount
+ 2) * sizeof(*finalRules
));
2092 finalRules
[finalRulesCount
++] = r1
;
2093 finalRules
[finalRulesCount
++] = r2
;
2094 return finalRulesCount
- 2;
2100 outzone(zpfirst
, zonecount
)
2101 const struct zone
* const zpfirst
;
2102 const int zonecount
;
2104 register const struct zone
* zp
;
2105 register struct rule
* rp
;
2107 register int usestart
, useuntil
;
2108 register zic_t starttime
, untiltime
;
2109 register long gmtoff
;
2110 register long stdoff
;
2112 register long startoff
;
2113 register int startttisstd
;
2114 register int startttisgmt
;
2116 register char * startbuf
;
2118 register char * envvar
;
2119 register int max_abbr_len
;
2120 register int max_envvar_len
;
2122 int finalRuleYear
, finalRuleIndex
;
2123 const struct rule
* finalRule1
;
2124 const struct rule
* finalRule2
;
2127 max_abbr_len
= 2 + max_format_len
+ max_abbrvar_len
;
2128 max_envvar_len
= 2 * max_abbr_len
+ 5 * 9;
2129 startbuf
= emalloc(max_abbr_len
+ 1);
2130 ab
= emalloc(max_abbr_len
+ 1);
2131 envvar
= emalloc(max_envvar_len
+ 1);
2132 INITIALIZE(untiltime
);
2133 INITIALIZE(starttime
);
2135 ** Now. . .finally. . .generate some useful data!
2141 ** Thanks to Earl Chew
2142 ** for noting the need to unconditionally initialize startttisstd.
2144 startttisstd
= FALSE
;
2145 startttisgmt
= FALSE
;
2146 min_year
= max_year
= EPOCH_YEAR
;
2148 updateminmax(leapminyear
);
2149 updateminmax(leapmaxyear
);
2151 for (i
= 0; i
< zonecount
; ++i
) {
2153 updateminmax(zp
->z_untilrule
.r_loyear
);
2154 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2155 rp
= &zp
->z_rules
[j
];
2157 updateminmax(rp
->r_loyear
);
2159 updateminmax(rp
->r_hiyear
);
2163 ** Generate lots of data if a rule can't cover all future times.
2165 stringzone(envvar
, zpfirst
, zonecount
);
2166 if (noise
&& envvar
[0] == '\0') {
2169 wp
= ecpyalloc(_("no POSIX environment variable for zone"));
2170 wp
= ecatalloc(wp
, " ");
2171 wp
= ecatalloc(wp
, zpfirst
->z_name
);
2175 if (envvar
[0] == '\0') {
2176 if (min_year
>= INT_MIN
+ YEARSPERREPEAT
)
2177 min_year
-= YEARSPERREPEAT
;
2178 else min_year
= INT_MIN
;
2179 if (max_year
<= INT_MAX
- YEARSPERREPEAT
)
2180 max_year
+= YEARSPERREPEAT
;
2181 else max_year
= INT_MAX
;
2184 ** For the benefit of older systems, generate data through 2037.
2186 if (max_year
< 2037)
2188 for (i
= 0; i
< zonecount
; ++i
) {
2190 ** A guess that may well be corrected later.
2194 usestart
= i
> 0 && (zp
- 1)->z_untiltime
> min_time
;
2195 useuntil
= i
< (zonecount
- 1);
2196 if (useuntil
&& zp
->z_untiltime
<= min_time
)
2198 gmtoff
= zp
->z_gmtoff
;
2199 eat(zp
->z_filename
, zp
->z_linenum
);
2201 startoff
= zp
->z_gmtoff
;
2203 finalRuleYear
= finalRuleIndex
= -1;
2204 finalRule1
= finalRule2
= NULL
;
2205 if (i
== (zonecount
- 1)) { /* !useuntil */
2206 /* Look for exactly 2 rules that end at 'max' and
2207 * note them. Determine max(r_loyear) for the 2 of
2209 for (j
=0; j
<zp
->z_nrules
; ++j
) {
2210 rp
= &zp
->z_rules
[j
];
2211 if (rp
->r_hiyear
== INT_MAX
) {
2212 if (finalRule1
== NULL
) {
2214 finalRuleYear
= rp
->r_loyear
;
2215 } else if (finalRule2
== NULL
) {
2217 if (rp
->r_loyear
> finalRuleYear
) {
2218 finalRuleYear
= rp
->r_loyear
;
2221 error("more than two max rules found (ICU)");
2226 if (finalRule1
!= NULL
&& finalRule2
== NULL
) {
2227 error("only one max rule found (ICU)");
2230 if (finalRule1
!= NULL
) {
2231 /* Swap if necessary so finalRule1 occurs before
2233 if (finalRule1
->r_month
> finalRule2
->r_month
) {
2234 const struct rule
* t
= finalRule1
;
2235 finalRule1
= finalRule2
;
2238 /* Add final rule to our list */
2239 finalRuleIndex
= add_icu_final_rules(finalRule1
, finalRule2
);
2244 if (zp
->z_nrules
== 0) {
2245 stdoff
= zp
->z_stdoff
;
2246 doabbr(startbuf
, zp
->z_format
,
2247 (char *) NULL
, stdoff
!= 0, FALSE
);
2248 type
= addtype(oadd(zp
->z_gmtoff
, stdoff
),
2250 zp
->z_gmtoff
, stdoff
,
2252 startbuf
, stdoff
!= 0, startttisstd
,
2255 addtt(starttime
, type
);
2257 } else if (stdoff
!= 0)
2258 addtt(min_time
, type
);
2259 } else for (year
= min_year
; year
<= max_year
; ++year
) {
2260 if (useuntil
&& year
> zp
->z_untilrule
.r_hiyear
)
2263 ** Mark which rules to do in the current year.
2264 ** For those to do, calculate rpytime(rp, year);
2266 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2267 rp
= &zp
->z_rules
[j
];
2268 eats(zp
->z_filename
, zp
->z_linenum
,
2269 rp
->r_filename
, rp
->r_linenum
);
2270 rp
->r_todo
= year
>= rp
->r_loyear
&&
2271 year
<= rp
->r_hiyear
&&
2272 yearistype(year
, rp
->r_yrtype
);
2274 rp
->r_temp
= rpytime(rp
, year
);
2278 register zic_t jtime
, ktime
;
2279 register long offset
;
2284 ** Turn untiltime into UTC
2285 ** assuming the current gmtoff and
2288 untiltime
= zp
->z_untiltime
;
2289 if (!zp
->z_untilrule
.r_todisgmt
)
2290 untiltime
= tadd(untiltime
,
2292 if (!zp
->z_untilrule
.r_todisstd
)
2293 untiltime
= tadd(untiltime
,
2297 ** Find the rule (of those to do, if any)
2298 ** that takes effect earliest in the year.
2301 for (j
= 0; j
< zp
->z_nrules
; ++j
) {
2302 rp
= &zp
->z_rules
[j
];
2305 eats(zp
->z_filename
, zp
->z_linenum
,
2306 rp
->r_filename
, rp
->r_linenum
);
2307 offset
= rp
->r_todisgmt
? 0 : gmtoff
;
2308 if (!rp
->r_todisstd
)
2309 offset
= oadd(offset
, stdoff
);
2311 if (jtime
== min_time
||
2314 jtime
= tadd(jtime
, -offset
);
2315 if (k
< 0 || jtime
< ktime
) {
2321 break; /* go on to next year */
2322 rp
= &zp
->z_rules
[k
];
2324 if (useuntil
&& ktime
>= untiltime
)
2326 stdoff
= rp
->r_stdoff
;
2327 if (usestart
&& ktime
== starttime
)
2330 if (ktime
< starttime
) {
2331 startoff
= oadd(zp
->z_gmtoff
,
2333 doabbr(startbuf
, zp
->z_format
,
2339 if (*startbuf
== '\0' &&
2340 startoff
== oadd(zp
->z_gmtoff
,
2351 if (year
>= finalRuleYear
&& rp
== finalRule1
) {
2352 /* We want to shift final year 1 year after
2353 * the actual final rule takes effect (year + 1),
2354 * because the previous type is valid until the first
2355 * transition defined by the final rule. Otherwise
2356 * we may see unexpected offset shift at the
2357 * begining of the year when the final rule takes
2360 /* ICU currently can support signed int32 transition
2361 * times. Thus, the transitions in year 2038 may be
2362 * truncated. At this moment (tzdata2008g), only
2363 * Rule Brazil is impacted by this limitation, because
2364 * the final set of rules are starting in 2038. Although
2365 * this code put the first couple of transitions populated
2366 * by the final rules, they will be dropped off when
2367 * collecting transition times. So, we need to keep
2368 * the start year of the final rule in 2038, not 2039.
2369 * Fortunately, the Brazil rules in 2038 and beyond use
2370 * the same base offset/dst saving amount. Thus, even
2371 * we skip the first couple of transitions, the final
2372 * rule set for 2038 works properly. So for now,
2373 * we do not increment the final rule start year only when
2374 * it falls into year 2038. We need to revisit this code
2375 * in future to fix the root cause of this problem (ICU
2376 * resource type limitation - signed int32).
2377 * Oct 7, 2008 - Yoshito */
2378 int finalStartYear
= (year
== 2038) ? year
: year
+ 1;
2379 emit_icu_zone(icuFile
,
2380 zpfirst
->z_name
, zp
->z_gmtoff
,
2381 rp
, finalRuleIndex
, finalStartYear
);
2382 /* only emit this for the first year */
2386 eats(zp
->z_filename
, zp
->z_linenum
,
2387 rp
->r_filename
, rp
->r_linenum
);
2388 doabbr(ab
, zp
->z_format
, rp
->r_abbrvar
,
2389 rp
->r_stdoff
!= 0, FALSE
);
2390 offset
= oadd(zp
->z_gmtoff
, rp
->r_stdoff
);
2392 type
= addtype(offset
, zp
->z_gmtoff
, rp
->r_stdoff
,
2393 ab
, rp
->r_stdoff
!= 0,
2394 rp
->r_todisstd
, rp
->r_todisgmt
);
2396 type
= addtype(offset
, ab
, rp
->r_stdoff
!= 0,
2397 rp
->r_todisstd
, rp
->r_todisgmt
);
2403 if (*startbuf
== '\0' &&
2404 zp
->z_format
!= NULL
&&
2405 strchr(zp
->z_format
, '%') == NULL
&&
2406 strchr(zp
->z_format
, '/') == NULL
)
2407 (void) strcpy(startbuf
, zp
->z_format
);
2408 eat(zp
->z_filename
, zp
->z_linenum
);
2409 if (*startbuf
== '\0')
2410 error(_("can't determine time zone abbreviation to use just after until time"));
2411 else addtt(starttime
,
2414 zp
->z_gmtoff
, startoff
- zp
->z_gmtoff
,
2416 startoff
!= zp
->z_gmtoff
,
2420 addtype(startoff
, startbuf
,
2421 startoff
!= zp
->z_gmtoff
,
2427 ** Now we may get to set starttime for the next zone line.
2430 startttisstd
= zp
->z_untilrule
.r_todisstd
;
2431 startttisgmt
= zp
->z_untilrule
.r_todisgmt
;
2432 starttime
= zp
->z_untiltime
;
2434 starttime
= tadd(starttime
, -stdoff
);
2436 starttime
= tadd(starttime
, -gmtoff
);
2439 writezone(zpfirst
->z_name
, envvar
);
2446 addtt(starttime
, type
)
2447 const zic_t starttime
;
2450 if (starttime
<= min_time
||
2451 (timecnt
== 1 && attypes
[0].at
< min_time
)) {
2452 gmtoffs
[0] = gmtoffs
[type
];
2454 rawoffs
[0] = rawoffs
[type
];
2455 dstoffs
[0] = dstoffs
[type
];
2457 isdsts
[0] = isdsts
[type
];
2458 ttisstds
[0] = ttisstds
[type
];
2459 ttisgmts
[0] = ttisgmts
[type
];
2460 if (abbrinds
[type
] != 0)
2461 (void) strcpy(chars
, &chars
[abbrinds
[type
]]);
2463 charcnt
= strlen(chars
) + 1;
2468 if (timecnt
>= TZ_MAX_TIMES
) {
2469 error(_("too many transitions?!"));
2472 attypes
[timecnt
].at
= starttime
;
2473 attypes
[timecnt
].type
= type
;
2479 addtype(gmtoff
, rawoff
, dstoff
, abbr
, isdst
, ttisstd
, ttisgmt
)
2484 addtype(gmtoff
, abbr
, isdst
, ttisstd
, ttisgmt
)
2487 const char * const abbr
;
2494 if (isdst
!= TRUE
&& isdst
!= FALSE
) {
2495 error(_("internal error - addtype called with bad isdst"));
2498 if (ttisstd
!= TRUE
&& ttisstd
!= FALSE
) {
2499 error(_("internal error - addtype called with bad ttisstd"));
2502 if (ttisgmt
!= TRUE
&& ttisgmt
!= FALSE
) {
2503 error(_("internal error - addtype called with bad ttisgmt"));
2507 if (isdst
!= (dstoff
!= 0)) {
2508 error(_("internal error - addtype called with bad isdst/dstoff"));
2509 (void) exit(EXIT_FAILURE
);
2511 if (gmtoff
!= (rawoff
+ dstoff
)) {
2512 error(_("internal error - addtype called with bad gmt/raw/dstoff"));
2513 (void) exit(EXIT_FAILURE
);
2517 ** See if there's already an entry for this zone type.
2518 ** If so, just return its index.
2520 for (i
= 0; i
< typecnt
; ++i
) {
2521 if (gmtoff
== gmtoffs
[i
] && isdst
== isdsts
[i
] &&
2523 rawoff
== rawoffs
[i
] && dstoff
== dstoffs
[i
] &&
2525 strcmp(abbr
, &chars
[abbrinds
[i
]]) == 0 &&
2526 ttisstd
== ttisstds
[i
] &&
2527 ttisgmt
== ttisgmts
[i
])
2531 ** There isn't one; add a new one, unless there are already too
2534 if (typecnt
>= TZ_MAX_TYPES
) {
2535 error(_("too many local time types"));
2538 gmtoffs
[i
] = gmtoff
;
2540 rawoffs
[i
] = rawoff
;
2541 dstoffs
[i
] = dstoff
;
2544 ttisstds
[i
] = ttisstd
;
2545 ttisgmts
[i
] = ttisgmt
;
2547 for (j
= 0; j
< charcnt
; ++j
)
2548 if (strcmp(&chars
[j
], abbr
) == 0)
2558 leapadd(t
, positive
, rolling
, count
)
2566 if (leapcnt
+ (positive
? count
: 1) > TZ_MAX_LEAPS
) {
2567 error(_("too many leap seconds"));
2570 for (i
= 0; i
< leapcnt
; ++i
)
2571 if (t
<= trans
[i
]) {
2572 if (t
== trans
[i
]) {
2573 error(_("repeated leap second moment"));
2579 for (j
= leapcnt
; j
> i
; --j
) {
2580 trans
[j
] = trans
[j
- 1];
2581 corr
[j
] = corr
[j
- 1];
2582 roll
[j
] = roll
[j
- 1];
2585 corr
[i
] = positive
? 1L : eitol(-count
);
2588 } while (positive
&& --count
!= 0);
2595 register long last
= 0;
2598 ** propagate leap seconds forward
2600 for (i
= 0; i
< leapcnt
; ++i
) {
2601 trans
[i
] = tadd(trans
[i
], last
);
2602 last
= corr
[i
] += last
;
2607 yearistype(year
, type
)
2609 const char * const type
;
2614 if (type
== NULL
|| *type
== '\0')
2616 buf
= erealloc(buf
, (int) (132 + strlen(yitcommand
) + strlen(type
)));
2617 (void) sprintf(buf
, "%s %d %s", yitcommand
, year
, type
);
2618 result
= system(buf
);
2619 if (WIFEXITED(result
)) switch (WEXITSTATUS(result
)) {
2625 error(_("Wild result from command execution"));
2626 (void) fprintf(stderr
, _("%s: command was '%s', result was %d\n"),
2627 progname
, buf
, result
);
2636 a
= (unsigned char) a
;
2637 return (isascii(a
) && isupper(a
)) ? tolower(a
) : a
;
2641 ciequal(ap
, bp
) /* case-insensitive equality */
2642 register const char * ap
;
2643 register const char * bp
;
2645 while (lowerit(*ap
) == lowerit(*bp
++))
2653 register const char * abbr
;
2654 register const char * word
;
2656 if (lowerit(*abbr
) != lowerit(*word
))
2659 while (*++abbr
!= '\0')
2663 } while (lowerit(*word
++) != lowerit(*abbr
));
2667 static const struct lookup
*
2669 register const char * const word
;
2670 register const struct lookup
* const table
;
2672 register const struct lookup
* foundlp
;
2673 register const struct lookup
* lp
;
2675 if (word
== NULL
|| table
== NULL
)
2678 ** Look for exact match.
2680 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2681 if (ciequal(word
, lp
->l_word
))
2684 ** Look for inexact match.
2687 for (lp
= table
; lp
->l_word
!= NULL
; ++lp
)
2688 if (itsabbr(word
, lp
->l_word
)) {
2689 if (foundlp
== NULL
)
2691 else return NULL
; /* multiple inexact matches */
2701 register char ** array
;
2706 array
= (char **) (void *)
2707 emalloc((int) ((strlen(cp
) + 1) * sizeof *array
));
2710 while (isascii((unsigned char) *cp
) &&
2711 isspace((unsigned char) *cp
))
2713 if (*cp
== '\0' || *cp
== '#')
2715 array
[nsubs
++] = dp
= cp
;
2717 if ((*dp
= *cp
++) != '"')
2719 else while ((*dp
= *cp
++) != '"')
2723 "Odd number of quotation marks"
2725 } while (*cp
!= '\0' && *cp
!= '#' &&
2726 (!isascii(*cp
) || !isspace((unsigned char) *cp
)));
2727 if (isascii(*cp
) && isspace((unsigned char) *cp
))
2731 array
[nsubs
] = NULL
;
2743 if ((t2
> 0 && t
<= t1
) || (t2
< 0 && t
>= t1
)) {
2744 error(_("time overflow"));
2757 if (t1
== max_time
&& t2
> 0)
2759 if (t1
== min_time
&& t2
< 0)
2762 if ((t2
> 0 && t
<= t1
) || (t2
< 0 && t
>= t1
)) {
2763 error(_("time overflow"));
2770 ** Given a rule, and a year, compute the date - in seconds since January 1,
2771 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2775 rpytime(rp
, wantedy
)
2776 register const struct rule
* const rp
;
2777 register const int wantedy
;
2779 register int y
, m
, i
;
2780 register long dayoff
; /* with a nod to Margaret O. */
2783 if (wantedy
== INT_MIN
)
2785 if (wantedy
== INT_MAX
)
2790 while (wantedy
!= y
) {
2792 i
= len_years
[isleap(y
)];
2796 i
= -len_years
[isleap(y
)];
2798 dayoff
= oadd(dayoff
, eitol(i
));
2800 while (m
!= rp
->r_month
) {
2801 i
= len_months
[isleap(y
)][m
];
2802 dayoff
= oadd(dayoff
, eitol(i
));
2805 i
= rp
->r_dayofmonth
;
2806 if (m
== TM_FEBRUARY
&& i
== 29 && !isleap(y
)) {
2807 if (rp
->r_dycode
== DC_DOWLEQ
)
2810 error(_("use of 2/29 in non leap-year"));
2815 dayoff
= oadd(dayoff
, eitol(i
));
2816 if (rp
->r_dycode
== DC_DOWGEQ
|| rp
->r_dycode
== DC_DOWLEQ
) {
2819 #define LDAYSPERWEEK ((long) DAYSPERWEEK)
2820 wday
= eitol(EPOCH_WDAY
);
2822 ** Don't trust mod of negative numbers.
2825 wday
= (wday
+ dayoff
) % LDAYSPERWEEK
;
2827 wday
-= ((-dayoff
) % LDAYSPERWEEK
);
2829 wday
+= LDAYSPERWEEK
;
2831 while (wday
!= eitol(rp
->r_wday
))
2832 if (rp
->r_dycode
== DC_DOWGEQ
) {
2833 dayoff
= oadd(dayoff
, (long) 1);
2834 if (++wday
>= LDAYSPERWEEK
)
2838 dayoff
= oadd(dayoff
, (long) -1);
2840 wday
= LDAYSPERWEEK
- 1;
2843 if (i
< 0 || i
>= len_months
[isleap(y
)][m
]) {
2845 warning(_("rule goes past start/end of month--\
2846 will not work with pre-2004 versions of zic"));
2849 if (dayoff
< min_time
/ SECSPERDAY
)
2851 if (dayoff
> max_time
/ SECSPERDAY
)
2853 t
= (zic_t
) dayoff
* SECSPERDAY
;
2854 return tadd(t
, rp
->r_tod
);
2859 const char * const string
;
2863 if (strcmp(string
, GRANDPARENTED
) != 0) {
2864 register const char * cp
;
2868 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2869 ** optionally followed by a + or - and a number from 1 to 14.
2873 while (isascii((unsigned char) *cp
) &&
2874 isalpha((unsigned char) *cp
))
2876 if (cp
- string
== 0)
2877 wp
= _("time zone abbreviation lacks alphabetic at start");
2878 if (noise
&& cp
- string
> 3)
2879 wp
= _("time zone abbreviation has more than 3 alphabetics");
2880 if (cp
- string
> ZIC_MAX_ABBR_LEN_WO_WARN
)
2881 wp
= _("time zone abbreviation has too many alphabetics");
2882 if (wp
== NULL
&& (*cp
== '+' || *cp
== '-')) {
2884 if (isascii((unsigned char) *cp
) &&
2885 isdigit((unsigned char) *cp
))
2887 *cp
>= '0' && *cp
<= '4')
2891 wp
= _("time zone abbreviation differs from POSIX standard");
2894 wp
= ecatalloc(wp
, " (");
2895 wp
= ecatalloc(wp
, string
);
2896 wp
= ecatalloc(wp
, ")");
2901 i
= strlen(string
) + 1;
2902 if (charcnt
+ i
> TZ_MAX_CHARS
) {
2903 error(_("too many, or too long, time zone abbreviations"));
2906 (void) strcpy(&chars
[charcnt
], string
);
2907 charcnt
+= eitol(i
);
2912 char * const argname
;
2914 register char * name
;
2917 if (argname
== NULL
|| *argname
== '\0')
2919 cp
= name
= ecpyalloc(argname
);
2920 while ((cp
= strchr(cp
+ 1, '/')) != 0) {
2924 ** DOS drive specifier?
2926 if (isalpha((unsigned char) name
[0]) &&
2927 name
[1] == ':' && name
[2] == '\0') {
2931 #endif /* !defined unix */
2932 if (!itsdir(name
)) {
2934 ** It doesn't seem to exist, so we try to create it.
2935 ** Creation may fail because of the directory being
2936 ** created by some other multiprocessor, so we get
2937 ** to do extra checking.
2939 if (mkdir(name
, MKDIR_UMASK
) != 0) {
2940 const char *e
= strerror(errno
);
2942 if (errno
!= EEXIST
|| !itsdir(name
)) {
2943 (void) fprintf(stderr
,
2944 _("%s: Can't create directory %s: %s\n"),
2964 if ((i
< 0 && l
>= 0) || (i
== 0 && l
!= 0) || (i
> 0 && l
<= 0)) {
2965 (void) fprintf(stderr
,
2966 _("%s: %d did not sign extend correctly\n"),
2974 ** UNIX was a registered trademark of The Open Group in 2003.