]> git.saurik.com Git - apple/icu.git/blame - icuSources/tools/tzcode/zic.c
ICU-531.30.tar.gz
[apple/icu.git] / icuSources / tools / tzcode / zic.c
CommitLineData
73c04bcf
A
1/*
2** This file is in the public domain, so clarified as of
3** 2006-07-17 by Arthur David Olson.
4*/
5
fd0068a8 6static char elsieid[] = "@(#)zic.c 8.18";
73c04bcf
A
7
8#include "private.h"
9#include "locale.h"
10#include "tzfile.h"
11
12#define ZIC_VERSION '2'
13
14typedef int_fast64_t zic_t;
15
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 */
19
20#if HAVE_SYS_STAT_H
21#include "sys/stat.h"
22#endif
23#ifdef S_IRUSR
24#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
25#else
26#define MKDIR_UMASK 0755
27#endif
28
29/* Enable extensions and modifications for ICU. */
30#define ICU
31
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. */
37#define ICU_LINKS
38
39#ifdef ICU
40#include "tz2icu.h"
41#endif
42
43/*
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.
50*/
51#include "ctype.h"
52#ifndef isascii
53#define isascii(x) 1
54#endif
55
56#define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
57#define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
58
59#define end(cp) (strchr((cp), '\0'))
60
61struct rule {
62 const char * r_filename;
63 int r_linenum;
64 const char * r_name;
65
66 int r_loyear; /* for example, 1986 */
67 int r_hiyear; /* for example, 1986 */
68 const char * r_yrtype;
69 int r_lowasnum;
70 int r_hiwasnum;
71
72 int r_month; /* 0..11 */
73
74 int r_dycode; /* see below */
75 int r_dayofmonth;
76 int r_wday;
77
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 */
85
86 int r_todo; /* a rule to do (used in outzone) */
87 zic_t r_temp; /* used in outzone */
88};
89
90/*
91** r_dycode r_dayofmonth r_wday
92*/
93
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) */
97
98struct zone {
99 const char * z_filename;
100 int z_linenum;
101
102 const char * z_name;
103 long z_gmtoff;
104 const char * z_rule;
105 const char * z_format;
106
107 long z_stdoff;
108
109 struct rule * z_rules;
110 int z_nrules;
111
112 struct rule z_untilrule;
113 zic_t z_untiltime;
114};
115
fd0068a8
A
116extern int getopt(int argc, char * const argv[],
117 const char * options);
118extern int link(const char * fromname, const char * toname);
73c04bcf
A
119extern char * optarg;
120extern int optind;
121
fd0068a8 122static void addtt(zic_t starttime, int type);
73c04bcf 123#ifdef ICU
fd0068a8 124static int addtype(long gmtoff, long rawoff, long dstoff,
73c04bcf 125 const char * abbr, int isdst,
fd0068a8 126 int ttisstd, int ttisgmt);
73c04bcf 127#else
fd0068a8
A
128static int addtype(long gmtoff, const char * abbr, int isdst,
129 int ttisstd, int ttisgmt);
73c04bcf 130#endif
fd0068a8
A
131static void leapadd(zic_t t, int positive, int rolling, int count);
132static void adjleap(void);
133static void associate(void);
134static int ciequal(const char * ap, const char * bp);
135static void convert(long val, char * buf);
136static void convert64(zic_t val, char * buf);
137static void dolink(const char * fromfield, const char * tofield);
138static void doabbr(char * abbr, const char * format,
139 const char * letters, int isdst, int doquotes);
140static void eat(const char * name, int num);
141static void eats(const char * name, int num,
142 const char * rname, int rnum);
143static long eitol(int i);
144static void error(const char * message);
145static char ** getfields(char * buf);
146static long gethms(const char * string, const char * errstrng,
147 int signable);
148static void infile(const char * filename);
149static void inleap(char ** fields, int nfields);
150static void inlink(char ** fields, int nfields);
151static void inrule(char ** fields, int nfields);
152static int inzcont(char ** fields, int nfields);
153static int inzone(char ** fields, int nfields);
154static int inzsub(char ** fields, int nfields, int iscont);
155static int is32(zic_t x);
156static int itsabbr(const char * abbr, const char * word);
157static int itsdir(const char * name);
158static int lowerit(int c);
159static char * memcheck(char * tocheck);
160static int mkdirs(char * filename);
161static void newabbr(const char * abbr);
162static long oadd(long t1, long t2);
163static void outzone(const struct zone * zp, int ntzones);
164static void puttzcode(long code, FILE * fp);
165static void puttzcode64(zic_t code, FILE * fp);
166static int rcomp(const void * leftp, const void * rightp);
167static zic_t rpytime(const struct rule * rp, int wantedy);
168static void rulesub(struct rule * rp,
73c04bcf
A
169 const char * loyearp, const char * hiyearp,
170 const char * typep, const char * monthp,
fd0068a8
A
171 const char * dayp, const char * timep);
172static int stringoffset(char * result, long offset);
173static int stringrule(char * result, const struct rule * rp,
174 long dstoff, long gmtoff);
175static void stringzone(char * result,
176 const struct zone * zp, int ntzones);
177static void setboundaries(void);
178static zic_t tadd(zic_t t1, long t2);
179static void usage(FILE *stream, int status);
180static void writezone(const char * name, const char * string);
181static int yearistype(int year, const char * type);
182#ifdef ICU
183static void emit_icu_zone(FILE* f, const char* zoneName, int zoneOffset,
184 const struct rule* rule,
185 int ruleIndex, int startYear);
186static void emit_icu_link(FILE* f, const char* from, const char* to);
187static void emit_icu_rule(FILE* f, const struct rule* r, int ruleIndex);
188static int add_icu_final_rules(const struct rule* r1, const struct rule* r2);
189#endif
73c04bcf
A
190
191static int charcnt;
192static int errors;
193static const char * filename;
194static int leapcnt;
195static int leapseen;
196static int leapminyear;
197static int leapmaxyear;
198static int linenum;
199static int max_abbrvar_len;
200static int max_format_len;
201static zic_t max_time;
202static int max_year;
203static zic_t min_time;
204static int min_year;
205static int noise;
206static const char * rfilename;
207static int rlinenum;
208static const char * progname;
209static int timecnt;
210static int typecnt;
211
212/*
213** Line codes.
214*/
215
216#define LC_RULE 0
217#define LC_ZONE 1
218#define LC_LINK 2
219#define LC_LEAP 3
220
221/*
222** Which fields are which on a Zone line.
223*/
224
225#define ZF_NAME 1
226#define ZF_GMTOFF 2
227#define ZF_RULE 3
228#define ZF_FORMAT 4
229#define ZF_TILYEAR 5
230#define ZF_TILMONTH 6
231#define ZF_TILDAY 7
232#define ZF_TILTIME 8
233#define ZONE_MINFIELDS 5
234#define ZONE_MAXFIELDS 9
235
236/*
237** Which fields are which on a Zone continuation line.
238*/
239
240#define ZFC_GMTOFF 0
241#define ZFC_RULE 1
242#define ZFC_FORMAT 2
243#define ZFC_TILYEAR 3
244#define ZFC_TILMONTH 4
245#define ZFC_TILDAY 5
246#define ZFC_TILTIME 6
247#define ZONEC_MINFIELDS 3
248#define ZONEC_MAXFIELDS 7
249
250/*
251** Which files are which on a Rule line.
252*/
253
254#define RF_NAME 1
255#define RF_LOYEAR 2
256#define RF_HIYEAR 3
257#define RF_COMMAND 4
258#define RF_MONTH 5
259#define RF_DAY 6
260#define RF_TOD 7
261#define RF_STDOFF 8
262#define RF_ABBRVAR 9
263#define RULE_FIELDS 10
264
265/*
266** Which fields are which on a Link line.
267*/
268
269#define LF_FROM 1
270#define LF_TO 2
271#define LINK_FIELDS 3
272
273/*
274** Which fields are which on a Leap line.
275*/
276
277#define LP_YEAR 1
278#define LP_MONTH 2
279#define LP_DAY 3
280#define LP_TIME 4
281#define LP_CORR 5
282#define LP_ROLL 6
283#define LEAP_FIELDS 7
284
285/*
286** Year synonyms.
287*/
288
289#define YR_MINIMUM 0
290#define YR_MAXIMUM 1
291#define YR_ONLY 2
292
293static struct rule * rules;
294static int nrules; /* number of rules */
295
296static struct zone * zones;
297static int nzones; /* number of zones */
298
299struct link {
300 const char * l_filename;
301 int l_linenum;
302 const char * l_from;
303 const char * l_to;
304};
305
306static struct link * links;
307static int nlinks;
308
309struct lookup {
310 const char * l_word;
311 const int l_value;
312};
313
314#ifdef ICU
73c04bcf
A
315/* Indices into rules[] for final rules. They will occur in pairs,
316 * with finalRules[i] occurring before finalRules[i+1] in the year.
317 * Each zone need only store a start year, a standard offset, and an
318 * index into finalRules[]. FinalRules[] are aliases into rules[]. */
fd0068a8
A
319static const struct rule ** finalRules;
320static int finalRulesCount;
73c04bcf
A
321#endif
322
fd0068a8
A
323static struct lookup const * byword(const char * string,
324 const struct lookup * lp);
73c04bcf
A
325
326static struct lookup const line_codes[] = {
327 { "Rule", LC_RULE },
328 { "Zone", LC_ZONE },
329 { "Link", LC_LINK },
330 { "Leap", LC_LEAP },
331 { NULL, 0}
332};
333
334static struct lookup const mon_names[] = {
335 { "January", TM_JANUARY },
336 { "February", TM_FEBRUARY },
337 { "March", TM_MARCH },
338 { "April", TM_APRIL },
339 { "May", TM_MAY },
340 { "June", TM_JUNE },
341 { "July", TM_JULY },
342 { "August", TM_AUGUST },
343 { "September", TM_SEPTEMBER },
344 { "October", TM_OCTOBER },
345 { "November", TM_NOVEMBER },
346 { "December", TM_DECEMBER },
347 { NULL, 0 }
348};
349
350static struct lookup const wday_names[] = {
351 { "Sunday", TM_SUNDAY },
352 { "Monday", TM_MONDAY },
353 { "Tuesday", TM_TUESDAY },
354 { "Wednesday", TM_WEDNESDAY },
355 { "Thursday", TM_THURSDAY },
356 { "Friday", TM_FRIDAY },
357 { "Saturday", TM_SATURDAY },
358 { NULL, 0 }
359};
360
361static struct lookup const lasts[] = {
362 { "last-Sunday", TM_SUNDAY },
363 { "last-Monday", TM_MONDAY },
364 { "last-Tuesday", TM_TUESDAY },
365 { "last-Wednesday", TM_WEDNESDAY },
366 { "last-Thursday", TM_THURSDAY },
367 { "last-Friday", TM_FRIDAY },
368 { "last-Saturday", TM_SATURDAY },
369 { NULL, 0 }
370};
371
372static struct lookup const begin_years[] = {
373 { "minimum", YR_MINIMUM },
374 { "maximum", YR_MAXIMUM },
375 { NULL, 0 }
376};
377
378static struct lookup const end_years[] = {
379 { "minimum", YR_MINIMUM },
380 { "maximum", YR_MAXIMUM },
381 { "only", YR_ONLY },
382 { NULL, 0 }
383};
384
385static struct lookup const leap_types[] = {
386 { "Rolling", TRUE },
387 { "Stationary", FALSE },
388 { NULL, 0 }
389};
390
391static const int len_months[2][MONSPERYEAR] = {
392 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
393 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
394};
395
396static const int len_years[2] = {
397 DAYSPERNYEAR, DAYSPERLYEAR
398};
399
400static struct attype {
401 zic_t at;
402 unsigned char type;
403} attypes[TZ_MAX_TIMES];
404static long gmtoffs[TZ_MAX_TYPES];
405#ifdef ICU
406/* gmtoffs[i] = rawoffs[i] + dstoffs[i] */
407static long rawoffs[TZ_MAX_TYPES];
408static long dstoffs[TZ_MAX_TYPES];
409#endif
410static char isdsts[TZ_MAX_TYPES];
411static unsigned char abbrinds[TZ_MAX_TYPES];
412static char ttisstds[TZ_MAX_TYPES];
413static char ttisgmts[TZ_MAX_TYPES];
414static char chars[TZ_MAX_CHARS];
415static zic_t trans[TZ_MAX_LEAPS];
416static long corr[TZ_MAX_LEAPS];
417static char roll[TZ_MAX_LEAPS];
418
419/*
420** Memory allocation.
421*/
422
423static char *
424memcheck(ptr)
425char * const ptr;
426{
427 if (ptr == NULL) {
428 const char *e = strerror(errno);
429
430 (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
431 progname, e);
432 exit(EXIT_FAILURE);
433 }
434 return ptr;
435}
436
437#define emalloc(size) memcheck(imalloc(size))
438#define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
439#define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
440#define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
441
442/*
443** Error handling.
444*/
445
73c04bcf
A
446static void
447eats(name, num, rname, rnum)
448const char * const name;
449const int num;
450const char * const rname;
451const int rnum;
452{
453 filename = name;
454 linenum = num;
455 rfilename = rname;
456 rlinenum = rnum;
457}
458
459static void
460eat(name, num)
461const char * const name;
462const int num;
463{
464 eats(name, num, (char *) NULL, -1);
465}
466
467static void
468error(string)
469const char * const string;
470{
471 /*
472 ** Match the format of "cc" to allow sh users to
473 ** zic ... 2>&1 | error -t "*" -v
474 ** on BSD systems.
475 */
476 (void) fprintf(stderr, _("\"%s\", line %d: %s"),
477 filename, linenum, string);
478 if (rfilename != NULL)
479 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
480 rfilename, rlinenum);
481 (void) fprintf(stderr, "\n");
482 ++errors;
483}
484
485static void
486warning(string)
487const char * const string;
488{
489 char * cp;
490
491 cp = ecpyalloc(_("warning: "));
492 cp = ecatalloc(cp, string);
493 error(cp);
494 ifree(cp);
495 --errors;
496}
497
498static void
fd0068a8 499usage(FILE *stream, int status)
73c04bcf 500{
fd0068a8
A
501 (void) fprintf(stream, _("%s: usage is %s \
502[ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
503\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
504\n\
505Report bugs to tz@elsie.nci.nih.gov.\n"),
506 progname, progname);
507 exit(status);
73c04bcf
A
508}
509
510#ifdef ICU
73c04bcf 511/* File into which we will write supplemental ICU data. */
fd0068a8
A
512static FILE * icuFile;
513
514static void
515emit_icu_zone(FILE* f, const char* zoneName, int zoneOffset,
516 const struct rule* rule,
517 int ruleIndex, int startYear) {
518 /* machine-readable section */
519 fprintf(f, "zone %s %d %d %s", zoneName, zoneOffset, startYear, rule->r_name);
520
521 /* human-readable section */
522 fprintf(f, " # zone %s, offset %d, year >= %d, rule %s (%d)\n",
523 zoneName, zoneOffset, startYear,
524 rule->r_name, ruleIndex);
73c04bcf
A
525}
526
fd0068a8
A
527static void
528emit_icu_link(FILE* f, const char* from, const char* to) {
529 /* machine-readable section */
530 fprintf(f, "link %s %s\n", from, to);
73c04bcf
A
531}
532
533static const char* DYCODE[] = {"DOM", "DOWGEQ", "DOWLEQ"};
534
fd0068a8
A
535static void
536emit_icu_rule(FILE* f, const struct rule* r, int ruleIndex) {
537 if (r->r_yrtype != NULL) {
538 warning("year types not supported by ICU");
539 fprintf(stderr, "rule %s, file %s, line %d\n",
540 r->r_name, r->r_filename, r->r_linenum);
73c04bcf
A
541 }
542
fd0068a8
A
543 /* machine-readable section */
544 fprintf(f, "rule %s %s %d %d %d %ld %d %d %ld",
545 r->r_name, DYCODE[r->r_dycode],
546 r->r_month, r->r_dayofmonth,
547 (r->r_dycode == DC_DOM ? -1 : r->r_wday),
548 r->r_tod, r->r_todisstd, r->r_todisgmt, r->r_stdoff
549 );
550
551 /* human-readable section */
552 fprintf(f, " # %d: %s, file %s, line %d",
553 ruleIndex, r->r_name, r->r_filename, r->r_linenum);
554 fprintf(f, ", mode %s", DYCODE[r->r_dycode]);
555 fprintf(f, ", %s, dom %d", mon_names[r->r_month].l_word, r->r_dayofmonth);
556 if (r->r_dycode != DC_DOM) {
557 fprintf(f, ", %s", wday_names[r->r_wday].l_word);
558 }
559 fprintf(f, ", time %ld", r->r_tod);
560 fprintf(f, ", isstd %d", r->r_todisstd);
561 fprintf(f, ", isgmt %d", r->r_todisgmt);
562 fprintf(f, ", offset %ld", r->r_stdoff);
563 fprintf(f, "\n");
73c04bcf
A
564}
565
fd0068a8
A
566static int
567add_icu_final_rules(const struct rule* r1, const struct rule* r2) {
568 int i;
569
570 for (i=0; i<finalRulesCount; ++i) { /* i+=2 should work too */
571 if (r1==finalRules[i]) return i; /* [sic] pointer comparison */
572 }
573
574 finalRules = (const struct rule**) (void*) erealloc((char *) finalRules,
575 (finalRulesCount + 2) * sizeof(*finalRules));
576 finalRules[finalRulesCount++] = r1;
577 finalRules[finalRulesCount++] = r2;
578 return finalRulesCount - 2;
579}
73c04bcf
A
580#endif
581
582static const char * psxrules;
583static const char * lcltime;
584static const char * directory;
585static const char * leapsec;
586static const char * yitcommand;
587
588int
589main(argc, argv)
590int argc;
591char * argv[];
592{
593 register int i;
594 register int j;
595 register int c;
596
597#ifdef unix
598 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
599#endif /* defined unix */
600#if HAVE_GETTEXT
601 (void) setlocale(LC_ALL, "");
602#ifdef TZ_DOMAINDIR
603 (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
604#endif /* defined TEXTDOMAINDIR */
605 (void) textdomain(TZ_DOMAIN);
606#endif /* HAVE_GETTEXT */
607 progname = argv[0];
608 if (TYPE_BIT(zic_t) < 64) {
609 (void) fprintf(stderr, "%s: %s\n", progname,
610 _("wild compilation-time specification of zic_t"));
611 exit(EXIT_FAILURE);
612 }
613 for (i = 1; i < argc; ++i)
614 if (strcmp(argv[i], "--version") == 0) {
615 (void) printf("%s\n", elsieid);
616 exit(EXIT_SUCCESS);
fd0068a8
A
617 } else if (strcmp(argv[i], "--help") == 0) {
618 usage(stdout, EXIT_SUCCESS);
73c04bcf
A
619 }
620 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
621 switch (c) {
622 default:
fd0068a8 623 usage(stderr, EXIT_FAILURE);
73c04bcf
A
624 case 'd':
625 if (directory == NULL)
626 directory = optarg;
627 else {
628 (void) fprintf(stderr,
629_("%s: More than one -d option specified\n"),
630 progname);
631 exit(EXIT_FAILURE);
632 }
633 break;
634 case 'l':
635 if (lcltime == NULL)
636 lcltime = optarg;
637 else {
638 (void) fprintf(stderr,
639_("%s: More than one -l option specified\n"),
640 progname);
641 exit(EXIT_FAILURE);
642 }
643 break;
644 case 'p':
645 if (psxrules == NULL)
646 psxrules = optarg;
647 else {
648 (void) fprintf(stderr,
649_("%s: More than one -p option specified\n"),
650 progname);
651 exit(EXIT_FAILURE);
652 }
653 break;
654 case 'y':
655 if (yitcommand == NULL)
656 yitcommand = optarg;
657 else {
658 (void) fprintf(stderr,
659_("%s: More than one -y option specified\n"),
660 progname);
661 exit(EXIT_FAILURE);
662 }
663 break;
664 case 'L':
665 if (leapsec == NULL)
666 leapsec = optarg;
667 else {
668 (void) fprintf(stderr,
669_("%s: More than one -L option specified\n"),
670 progname);
671 exit(EXIT_FAILURE);
672 }
673 break;
674 case 'v':
675 noise = TRUE;
676 break;
677 case 's':
678 (void) printf("%s: -s ignored\n", progname);
679 break;
680 }
681 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
fd0068a8 682 usage(stderr, EXIT_FAILURE); /* usage message by request */
73c04bcf
A
683 if (directory == NULL)
684 directory = TZDIR;
685 if (yitcommand == NULL)
686 yitcommand = "yearistype";
687
688 setboundaries();
689
690 if (optind < argc && leapsec != NULL) {
691 infile(leapsec);
692 adjleap();
693 }
694
695#ifdef ICU
696 if ((icuFile = fopen(ICU_ZONE_FILE, "w")) == NULL) {
fd0068a8
A
697 const char *e = strerror(errno);
698 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
699 progname, ICU_ZONE_FILE, e);
700 (void) exit(EXIT_FAILURE);
701 }
73c04bcf
A
702#endif
703 for (i = optind; i < argc; ++i)
704 infile(argv[i]);
705 if (errors)
706 exit(EXIT_FAILURE);
707 associate();
708 for (i = 0; i < nzones; i = j) {
709 /*
710 ** Find the next non-continuation zone entry.
711 */
712 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
713 continue;
714 outzone(&zones[i], j - i);
715 }
716 /*
717 ** Make links.
718 */
719 for (i = 0; i < nlinks; ++i) {
720 eat(links[i].l_filename, links[i].l_linenum);
721 dolink(links[i].l_from, links[i].l_to);
722#ifdef ICU
fd0068a8 723 emit_icu_link(icuFile, links[i].l_from, links[i].l_to);
73c04bcf
A
724#endif
725 if (noise)
726 for (j = 0; j < nlinks; ++j)
727 if (strcmp(links[i].l_to,
728 links[j].l_from) == 0)
729 warning(_("link to link"));
730 }
731 if (lcltime != NULL) {
732 eat("command line", 1);
733 dolink(lcltime, TZDEFAULT);
734 }
735 if (psxrules != NULL) {
736 eat("command line", 1);
737 dolink(psxrules, TZDEFRULES);
738 }
739#ifdef ICU
fd0068a8
A
740 for (i=0; i<finalRulesCount; ++i) {
741 emit_icu_rule(icuFile, finalRules[i], i);
742 }
73c04bcf
A
743#endif /*ICU*/
744 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
745}
746
747static void
fd0068a8
A
748dolink(fromfield, tofield)
749const char * const fromfield;
750const char * const tofield;
73c04bcf
A
751{
752 register char * fromname;
753 register char * toname;
754
fd0068a8
A
755 if (fromfield[0] == '/')
756 fromname = ecpyalloc(fromfield);
73c04bcf
A
757 else {
758 fromname = ecpyalloc(directory);
759 fromname = ecatalloc(fromname, "/");
fd0068a8 760 fromname = ecatalloc(fromname, fromfield);
73c04bcf 761 }
fd0068a8
A
762 if (tofield[0] == '/')
763 toname = ecpyalloc(tofield);
73c04bcf
A
764 else {
765 toname = ecpyalloc(directory);
766 toname = ecatalloc(toname, "/");
fd0068a8 767 toname = ecatalloc(toname, tofield);
73c04bcf
A
768 }
769 /*
770 ** We get to be careful here since
771 ** there's a fair chance of root running us.
772 */
773 if (!itsdir(toname))
774 (void) remove(toname);
775 if (link(fromname, toname) != 0) {
776 int result;
777
778 if (mkdirs(toname) != 0)
779 exit(EXIT_FAILURE);
780
781 result = link(fromname, toname);
782#if HAVE_SYMLINK
783 if (result != 0 &&
784 access(fromname, F_OK) == 0 &&
785 !itsdir(fromname)) {
fd0068a8 786 const char *s = tofield;
73c04bcf
A
787 register char * symlinkcontents = NULL;
788
789 while ((s = strchr(s+1, '/')) != NULL)
790 symlinkcontents =
791 ecatalloc(symlinkcontents,
792 "../");
793 symlinkcontents =
794 ecatalloc(symlinkcontents,
fd0068a8 795 fromname);
73c04bcf
A
796 result = symlink(symlinkcontents,
797 toname);
798 if (result == 0)
799warning(_("hard link failed, symbolic link used"));
800 ifree(symlinkcontents);
801 }
802#endif /* HAVE_SYMLINK */
803 if (result != 0) {
804 const char *e = strerror(errno);
805
806 (void) fprintf(stderr,
807 _("%s: Can't link from %s to %s: %s\n"),
808 progname, fromname, toname, e);
809#ifndef ICU_LINKS
810 exit(EXIT_FAILURE);
811#endif
812 }
813 }
814 ifree(fromname);
815 ifree(toname);
816}
817
818#define TIME_T_BITS_IN_FILE 64
819
820static void
fd0068a8 821setboundaries(void)
73c04bcf
A
822{
823 register int i;
824
825 min_time = -1;
826 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
827 min_time *= 2;
828 max_time = -(min_time + 1);
829}
830
831static int
832itsdir(name)
833const char * const name;
834{
835 register char * myname;
836 register int accres;
837
838 myname = ecpyalloc(name);
839 myname = ecatalloc(myname, "/.");
840 accres = access(myname, F_OK);
841 ifree(myname);
842 return accres == 0;
843}
844
845/*
846** Associate sets of rules with zones.
847*/
848
849/*
850** Sort by rule name.
851*/
852
853static int
854rcomp(cp1, cp2)
855const void * cp1;
856const void * cp2;
857{
858 return strcmp(((const struct rule *) cp1)->r_name,
859 ((const struct rule *) cp2)->r_name);
860}
861
862static void
fd0068a8 863associate(void)
73c04bcf
A
864{
865 register struct zone * zp;
866 register struct rule * rp;
867 register int base, out;
868 register int i, j;
869
870 if (nrules != 0) {
871 (void) qsort((void *) rules, (size_t) nrules,
872 (size_t) sizeof *rules, rcomp);
873 for (i = 0; i < nrules - 1; ++i) {
874 if (strcmp(rules[i].r_name,
875 rules[i + 1].r_name) != 0)
876 continue;
877 if (strcmp(rules[i].r_filename,
878 rules[i + 1].r_filename) == 0)
879 continue;
880 eat(rules[i].r_filename, rules[i].r_linenum);
881 warning(_("same rule name in multiple files"));
882 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
883 warning(_("same rule name in multiple files"));
884 for (j = i + 2; j < nrules; ++j) {
885 if (strcmp(rules[i].r_name,
886 rules[j].r_name) != 0)
887 break;
888 if (strcmp(rules[i].r_filename,
889 rules[j].r_filename) == 0)
890 continue;
891 if (strcmp(rules[i + 1].r_filename,
892 rules[j].r_filename) == 0)
893 continue;
894 break;
895 }
896 i = j - 1;
897 }
898 }
899 for (i = 0; i < nzones; ++i) {
900 zp = &zones[i];
901 zp->z_rules = NULL;
902 zp->z_nrules = 0;
903 }
904 for (base = 0; base < nrules; base = out) {
905 rp = &rules[base];
906 for (out = base + 1; out < nrules; ++out)
907 if (strcmp(rp->r_name, rules[out].r_name) != 0)
908 break;
909 for (i = 0; i < nzones; ++i) {
910 zp = &zones[i];
911 if (strcmp(zp->z_rule, rp->r_name) != 0)
912 continue;
913 zp->z_rules = rp;
914 zp->z_nrules = out - base;
915 }
916 }
917 for (i = 0; i < nzones; ++i) {
918 zp = &zones[i];
919 if (zp->z_nrules == 0) {
920 /*
921 ** Maybe we have a local standard time offset.
922 */
923 eat(zp->z_filename, zp->z_linenum);
924 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
925 TRUE);
926 /*
927 ** Note, though, that if there's no rule,
928 ** a '%s' in the format is a bad thing.
929 */
930 if (strchr(zp->z_format, '%') != 0)
931 error(_("%s in ruleless zone"));
932 }
933 }
934 if (errors)
935 exit(EXIT_FAILURE);
936}
937
938static void
939infile(name)
940const char * name;
941{
942 register FILE * fp;
943 register char ** fields;
944 register char * cp;
945 register const struct lookup * lp;
946 register int nfields;
947 register int wantcont;
948 register int num;
949 char buf[BUFSIZ];
950
951 if (strcmp(name, "-") == 0) {
952 name = _("standard input");
953 fp = stdin;
954 } else if ((fp = fopen(name, "r")) == NULL) {
955 const char *e = strerror(errno);
956
957 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
958 progname, name, e);
959 exit(EXIT_FAILURE);
960 }
961 wantcont = FALSE;
962 for (num = 1; ; ++num) {
963 eat(name, num);
964 if (fgets(buf, (int) sizeof buf, fp) != buf)
965 break;
966 cp = strchr(buf, '\n');
967 if (cp == NULL) {
968 error(_("line too long"));
969 exit(EXIT_FAILURE);
970 }
971 *cp = '\0';
972 fields = getfields(buf);
973 nfields = 0;
974 while (fields[nfields] != NULL) {
975 static char nada;
976
977 if (strcmp(fields[nfields], "-") == 0)
978 fields[nfields] = &nada;
979 ++nfields;
980 }
981 if (nfields == 0) {
982 /* nothing to do */
983 } else if (wantcont) {
984 wantcont = inzcont(fields, nfields);
985 } else {
986 lp = byword(fields[0], line_codes);
987 if (lp == NULL)
988 error(_("input line of unknown type"));
989 else switch ((int) (lp->l_value)) {
990 case LC_RULE:
991 inrule(fields, nfields);
992 wantcont = FALSE;
993 break;
994 case LC_ZONE:
995 wantcont = inzone(fields, nfields);
996 break;
997 case LC_LINK:
998 inlink(fields, nfields);
999 wantcont = FALSE;
1000 break;
1001 case LC_LEAP:
1002 if (name != leapsec)
1003 (void) fprintf(stderr,
1004_("%s: Leap line in non leap seconds file %s\n"),
1005 progname, name);
1006 else inleap(fields, nfields);
1007 wantcont = FALSE;
1008 break;
1009 default: /* "cannot happen" */
1010 (void) fprintf(stderr,
1011_("%s: panic: Invalid l_value %d\n"),
1012 progname, lp->l_value);
1013 exit(EXIT_FAILURE);
1014 }
1015 }
1016 ifree((char *) fields);
1017 }
1018 if (ferror(fp)) {
1019 (void) fprintf(stderr, _("%s: Error reading %s\n"),
1020 progname, filename);
1021 exit(EXIT_FAILURE);
1022 }
1023 if (fp != stdin && fclose(fp)) {
1024 const char *e = strerror(errno);
1025
1026 (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
1027 progname, filename, e);
1028 exit(EXIT_FAILURE);
1029 }
1030 if (wantcont)
1031 error(_("expected continuation line not found"));
1032}
1033
1034/*
1035** Convert a string of one of the forms
1036** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1037** into a number of seconds.
1038** A null string maps to zero.
1039** Call error with errstring and return zero on errors.
1040*/
1041
1042static long
1043gethms(string, errstring, signable)
1044const char * string;
1045const char * const errstring;
1046const int signable;
1047{
fd0068a8
A
1048 long hh;
1049 int mm, ss, sign;
73c04bcf
A
1050
1051 if (string == NULL || *string == '\0')
1052 return 0;
1053 if (!signable)
1054 sign = 1;
1055 else if (*string == '-') {
1056 sign = -1;
1057 ++string;
1058 } else sign = 1;
fd0068a8 1059 if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
73c04bcf 1060 mm = ss = 0;
fd0068a8 1061 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
73c04bcf 1062 ss = 0;
fd0068a8 1063 else if (sscanf(string, scheck(string, "%ld:%d:%d"),
73c04bcf
A
1064 &hh, &mm, &ss) != 3) {
1065 error(errstring);
1066 return 0;
1067 }
fd0068a8 1068 if (hh < 0 ||
73c04bcf 1069 mm < 0 || mm >= MINSPERHOUR ||
fd0068a8 1070 ss < 0 || ss > SECSPERMIN) {
73c04bcf
A
1071 error(errstring);
1072 return 0;
1073 }
fd0068a8
A
1074 if (LONG_MAX / SECSPERHOUR < hh) {
1075 error(_("time overflow"));
1076 return 0;
1077 }
1078 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
73c04bcf 1079 warning(_("24:00 not handled by pre-1998 versions of zic"));
fd0068a8
A
1080 if (noise && (hh > HOURSPERDAY ||
1081 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1082warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1083 return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
1084 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
73c04bcf
A
1085}
1086
1087static void
1088inrule(fields, nfields)
1089register char ** const fields;
1090const int nfields;
1091{
1092 static struct rule r;
1093
1094 if (nfields != RULE_FIELDS) {
1095 error(_("wrong number of fields on Rule line"));
1096 return;
1097 }
1098 if (*fields[RF_NAME] == '\0') {
1099 error(_("nameless rule"));
1100 return;
1101 }
1102 r.r_filename = filename;
1103 r.r_linenum = linenum;
1104 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
1105 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1106 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1107 r.r_name = ecpyalloc(fields[RF_NAME]);
1108 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1109 if (max_abbrvar_len < strlen(r.r_abbrvar))
1110 max_abbrvar_len = strlen(r.r_abbrvar);
1111 rules = (struct rule *) (void *) erealloc((char *) rules,
1112 (int) ((nrules + 1) * sizeof *rules));
1113 rules[nrules++] = r;
1114}
1115
1116static int
1117inzone(fields, nfields)
1118register char ** const fields;
1119const int nfields;
1120{
1121 register int i;
1122 static char * buf;
1123
1124 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1125 error(_("wrong number of fields on Zone line"));
1126 return FALSE;
1127 }
1128 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1129 buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
1130 (void) sprintf(buf,
1131_("\"Zone %s\" line and -l option are mutually exclusive"),
1132 TZDEFAULT);
1133 error(buf);
1134 return FALSE;
1135 }
1136 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1137 buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
1138 (void) sprintf(buf,
1139_("\"Zone %s\" line and -p option are mutually exclusive"),
1140 TZDEFRULES);
1141 error(buf);
1142 return FALSE;
1143 }
1144 for (i = 0; i < nzones; ++i)
1145 if (zones[i].z_name != NULL &&
1146 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1147 buf = erealloc(buf, (int) (132 +
1148 strlen(fields[ZF_NAME]) +
1149 strlen(zones[i].z_filename)));
1150 (void) sprintf(buf,
1151_("duplicate zone name %s (file \"%s\", line %d)"),
1152 fields[ZF_NAME],
1153 zones[i].z_filename,
1154 zones[i].z_linenum);
1155 error(buf);
1156 return FALSE;
1157 }
1158 return inzsub(fields, nfields, FALSE);
1159}
1160
1161static int
1162inzcont(fields, nfields)
1163register char ** const fields;
1164const int nfields;
1165{
1166 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1167 error(_("wrong number of fields on Zone continuation line"));
1168 return FALSE;
1169 }
1170 return inzsub(fields, nfields, TRUE);
1171}
1172
1173static int
1174inzsub(fields, nfields, iscont)
1175register char ** const fields;
1176const int nfields;
1177const int iscont;
1178{
1179 register char * cp;
1180 static struct zone z;
1181 register int i_gmtoff, i_rule, i_format;
1182 register int i_untilyear, i_untilmonth;
1183 register int i_untilday, i_untiltime;
1184 register int hasuntil;
1185
1186 if (iscont) {
1187 i_gmtoff = ZFC_GMTOFF;
1188 i_rule = ZFC_RULE;
1189 i_format = ZFC_FORMAT;
1190 i_untilyear = ZFC_TILYEAR;
1191 i_untilmonth = ZFC_TILMONTH;
1192 i_untilday = ZFC_TILDAY;
1193 i_untiltime = ZFC_TILTIME;
1194 z.z_name = NULL;
1195 } else {
1196 i_gmtoff = ZF_GMTOFF;
1197 i_rule = ZF_RULE;
1198 i_format = ZF_FORMAT;
1199 i_untilyear = ZF_TILYEAR;
1200 i_untilmonth = ZF_TILMONTH;
1201 i_untilday = ZF_TILDAY;
1202 i_untiltime = ZF_TILTIME;
1203 z.z_name = ecpyalloc(fields[ZF_NAME]);
1204 }
1205 z.z_filename = filename;
1206 z.z_linenum = linenum;
1207 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
1208 if ((cp = strchr(fields[i_format], '%')) != 0) {
1209 if (*++cp != 's' || strchr(cp, '%') != 0) {
1210 error(_("invalid abbreviation format"));
1211 return FALSE;
1212 }
1213 }
1214 z.z_rule = ecpyalloc(fields[i_rule]);
1215 z.z_format = ecpyalloc(fields[i_format]);
1216 if (max_format_len < strlen(z.z_format))
1217 max_format_len = strlen(z.z_format);
1218 hasuntil = nfields > i_untilyear;
1219 if (hasuntil) {
1220 z.z_untilrule.r_filename = filename;
1221 z.z_untilrule.r_linenum = linenum;
1222 rulesub(&z.z_untilrule,
1223 fields[i_untilyear],
1224 "only",
1225 "",
1226 (nfields > i_untilmonth) ?
1227 fields[i_untilmonth] : "Jan",
1228 (nfields > i_untilday) ? fields[i_untilday] : "1",
1229 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1230 z.z_untiltime = rpytime(&z.z_untilrule,
1231 z.z_untilrule.r_loyear);
1232 if (iscont && nzones > 0 &&
1233 z.z_untiltime > min_time &&
1234 z.z_untiltime < max_time &&
1235 zones[nzones - 1].z_untiltime > min_time &&
1236 zones[nzones - 1].z_untiltime < max_time &&
1237 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1238 error(_(
1239"Zone continuation line end time is not after end time of previous line"
1240 ));
1241 return FALSE;
1242 }
1243 }
1244 zones = (struct zone *) (void *) erealloc((char *) zones,
1245 (int) ((nzones + 1) * sizeof *zones));
1246 zones[nzones++] = z;
1247 /*
1248 ** If there was an UNTIL field on this line,
1249 ** there's more information about the zone on the next line.
1250 */
1251 return hasuntil;
1252}
1253
1254static void
1255inleap(fields, nfields)
1256register char ** const fields;
1257const int nfields;
1258{
1259 register const char * cp;
1260 register const struct lookup * lp;
1261 register int i, j;
1262 int year, month, day;
1263 long dayoff, tod;
1264 zic_t t;
1265
1266 if (nfields != LEAP_FIELDS) {
1267 error(_("wrong number of fields on Leap line"));
1268 return;
1269 }
1270 dayoff = 0;
1271 cp = fields[LP_YEAR];
1272 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1273 /*
1274 ** Leapin' Lizards!
1275 */
1276 error(_("invalid leaping year"));
1277 return;
1278 }
1279 if (!leapseen || leapmaxyear < year)
1280 leapmaxyear = year;
1281 if (!leapseen || leapminyear > year)
1282 leapminyear = year;
1283 leapseen = TRUE;
1284 j = EPOCH_YEAR;
1285 while (j != year) {
1286 if (year > j) {
1287 i = len_years[isleap(j)];
1288 ++j;
1289 } else {
1290 --j;
1291 i = -len_years[isleap(j)];
1292 }
1293 dayoff = oadd(dayoff, eitol(i));
1294 }
1295 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1296 error(_("invalid month name"));
1297 return;
1298 }
1299 month = lp->l_value;
1300 j = TM_JANUARY;
1301 while (j != month) {
1302 i = len_months[isleap(year)][j];
1303 dayoff = oadd(dayoff, eitol(i));
1304 ++j;
1305 }
1306 cp = fields[LP_DAY];
1307 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1308 day <= 0 || day > len_months[isleap(year)][month]) {
1309 error(_("invalid day of month"));
1310 return;
1311 }
1312 dayoff = oadd(dayoff, eitol(day - 1));
1313 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1314 error(_("time before zero"));
1315 return;
1316 }
1317 if (dayoff < min_time / SECSPERDAY) {
1318 error(_("time too small"));
1319 return;
1320 }
1321 if (dayoff > max_time / SECSPERDAY) {
1322 error(_("time too large"));
1323 return;
1324 }
1325 t = (zic_t) dayoff * SECSPERDAY;
1326 tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1327 cp = fields[LP_CORR];
1328 {
1329 register int positive;
1330 int count;
1331
1332 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1333 positive = FALSE;
1334 count = 1;
1335 } else if (strcmp(cp, "--") == 0) {
1336 positive = FALSE;
1337 count = 2;
1338 } else if (strcmp(cp, "+") == 0) {
1339 positive = TRUE;
1340 count = 1;
1341 } else if (strcmp(cp, "++") == 0) {
1342 positive = TRUE;
1343 count = 2;
1344 } else {
1345 error(_("illegal CORRECTION field on Leap line"));
1346 return;
1347 }
1348 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1349 error(_(
1350 "illegal Rolling/Stationary field on Leap line"
1351 ));
1352 return;
1353 }
1354 leapadd(tadd(t, tod), positive, lp->l_value, count);
1355 }
1356}
1357
1358static void
1359inlink(fields, nfields)
1360register char ** const fields;
1361const int nfields;
1362{
1363 struct link l;
1364
1365 if (nfields != LINK_FIELDS) {
1366 error(_("wrong number of fields on Link line"));
1367 return;
1368 }
1369 if (*fields[LF_FROM] == '\0') {
1370 error(_("blank FROM field on Link line"));
1371 return;
1372 }
1373 if (*fields[LF_TO] == '\0') {
1374 error(_("blank TO field on Link line"));
1375 return;
1376 }
1377 l.l_filename = filename;
1378 l.l_linenum = linenum;
1379 l.l_from = ecpyalloc(fields[LF_FROM]);
1380 l.l_to = ecpyalloc(fields[LF_TO]);
1381 links = (struct link *) (void *) erealloc((char *) links,
1382 (int) ((nlinks + 1) * sizeof *links));
1383 links[nlinks++] = l;
1384}
1385
1386static void
1387rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1388register struct rule * const rp;
1389const char * const loyearp;
1390const char * const hiyearp;
1391const char * const typep;
1392const char * const monthp;
1393const char * const dayp;
1394const char * const timep;
1395{
1396 register const struct lookup * lp;
1397 register const char * cp;
1398 register char * dp;
1399 register char * ep;
1400
1401 if ((lp = byword(monthp, mon_names)) == NULL) {
1402 error(_("invalid month name"));
1403 return;
1404 }
1405 rp->r_month = lp->l_value;
1406 rp->r_todisstd = FALSE;
1407 rp->r_todisgmt = FALSE;
1408 dp = ecpyalloc(timep);
1409 if (*dp != '\0') {
1410 ep = dp + strlen(dp) - 1;
1411 switch (lowerit(*ep)) {
1412 case 's': /* Standard */
1413 rp->r_todisstd = TRUE;
1414 rp->r_todisgmt = FALSE;
1415 *ep = '\0';
1416 break;
1417 case 'w': /* Wall */
1418 rp->r_todisstd = FALSE;
1419 rp->r_todisgmt = FALSE;
1420 *ep = '\0';
1421 break;
1422 case 'g': /* Greenwich */
1423 case 'u': /* Universal */
1424 case 'z': /* Zulu */
1425 rp->r_todisstd = TRUE;
1426 rp->r_todisgmt = TRUE;
1427 *ep = '\0';
1428 break;
1429 }
1430 }
1431 rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
1432 ifree(dp);
1433 /*
1434 ** Year work.
1435 */
1436 cp = loyearp;
1437 lp = byword(cp, begin_years);
1438 rp->r_lowasnum = lp == NULL;
1439 if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1440 case YR_MINIMUM:
1441 rp->r_loyear = INT_MIN;
1442 break;
1443 case YR_MAXIMUM:
1444 rp->r_loyear = INT_MAX;
1445 break;
1446 default: /* "cannot happen" */
1447 (void) fprintf(stderr,
1448 _("%s: panic: Invalid l_value %d\n"),
1449 progname, lp->l_value);
1450 exit(EXIT_FAILURE);
1451 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1452 error(_("invalid starting year"));
1453 return;
1454 }
1455 cp = hiyearp;
1456 lp = byword(cp, end_years);
1457 rp->r_hiwasnum = lp == NULL;
1458 if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1459 case YR_MINIMUM:
1460 rp->r_hiyear = INT_MIN;
1461 break;
1462 case YR_MAXIMUM:
1463 rp->r_hiyear = INT_MAX;
1464 break;
1465 case YR_ONLY:
1466 rp->r_hiyear = rp->r_loyear;
1467 break;
1468 default: /* "cannot happen" */
1469 (void) fprintf(stderr,
1470 _("%s: panic: Invalid l_value %d\n"),
1471 progname, lp->l_value);
1472 exit(EXIT_FAILURE);
1473 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1474 error(_("invalid ending year"));
1475 return;
1476 }
1477 if (rp->r_loyear > rp->r_hiyear) {
1478 error(_("starting year greater than ending year"));
1479 return;
1480 }
1481 if (*typep == '\0')
1482 rp->r_yrtype = NULL;
1483 else {
1484 if (rp->r_loyear == rp->r_hiyear) {
1485 error(_("typed single year"));
1486 return;
1487 }
1488 rp->r_yrtype = ecpyalloc(typep);
1489 }
1490 /*
1491 ** Day work.
1492 ** Accept things such as:
1493 ** 1
1494 ** last-Sunday
1495 ** Sun<=20
1496 ** Sun>=7
1497 */
1498 dp = ecpyalloc(dayp);
1499 if ((lp = byword(dp, lasts)) != NULL) {
1500 rp->r_dycode = DC_DOWLEQ;
1501 rp->r_wday = lp->l_value;
1502 rp->r_dayofmonth = len_months[1][rp->r_month];
1503 } else {
1504 if ((ep = strchr(dp, '<')) != 0)
1505 rp->r_dycode = DC_DOWLEQ;
1506 else if ((ep = strchr(dp, '>')) != 0)
1507 rp->r_dycode = DC_DOWGEQ;
1508 else {
1509 ep = dp;
1510 rp->r_dycode = DC_DOM;
1511 }
1512 if (rp->r_dycode != DC_DOM) {
1513 *ep++ = 0;
1514 if (*ep++ != '=') {
1515 error(_("invalid day of month"));
1516 ifree(dp);
1517 return;
1518 }
1519 if ((lp = byword(dp, wday_names)) == NULL) {
1520 error(_("invalid weekday name"));
1521 ifree(dp);
1522 return;
1523 }
1524 rp->r_wday = lp->l_value;
1525 }
1526 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1527 rp->r_dayofmonth <= 0 ||
1528 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1529 error(_("invalid day of month"));
1530 ifree(dp);
1531 return;
1532 }
1533 }
1534 ifree(dp);
1535}
1536
1537static void
1538convert(val, buf)
1539const long val;
1540char * const buf;
1541{
1542 register int i;
1543 register int shift;
1544
1545 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1546 buf[i] = val >> shift;
1547}
1548
1549static void
1550convert64(val, buf)
1551const zic_t val;
1552char * const buf;
1553{
1554 register int i;
1555 register int shift;
1556
1557 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1558 buf[i] = val >> shift;
1559}
1560
1561static void
1562puttzcode(val, fp)
1563const long val;
1564FILE * const fp;
1565{
1566 char buf[4];
1567
1568 convert(val, buf);
1569 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1570}
1571
1572static void
1573puttzcode64(val, fp)
1574const zic_t val;
1575FILE * const fp;
1576{
1577 char buf[8];
1578
1579 convert64(val, buf);
1580 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1581}
1582
1583static int
1584atcomp(avp, bvp)
1585const void * avp;
1586const void * bvp;
1587{
1588 const zic_t a = ((const struct attype *) avp)->at;
1589 const zic_t b = ((const struct attype *) bvp)->at;
1590
1591 return (a < b) ? -1 : (a > b);
1592}
1593
1594static int
1595is32(x)
1596const zic_t x;
1597{
1598 return INT32_MIN <= x && x <= INT32_MAX;
1599}
1600
1601static void
1602writezone(name, string)
1603const char * const name;
1604const char * const string;
1605{
1606 register FILE * fp;
1607 register int i, j;
1608 register int leapcnt32, leapi32;
1609 register int timecnt32, timei32;
1610 register int pass;
1611 static char * fullname;
1612 static const struct tzhead tzh0;
1613 static struct tzhead tzh;
1614 zic_t ats[TZ_MAX_TIMES];
1615 unsigned char types[TZ_MAX_TIMES];
1616
1617 /*
1618 ** Sort.
1619 */
1620 if (timecnt > 1)
1621 (void) qsort((void *) attypes, (size_t) timecnt,
1622 (size_t) sizeof *attypes, atcomp);
1623 /*
1624 ** Optimize.
1625 */
1626 {
1627 int fromi;
1628 int toi;
1629
1630 toi = 0;
1631 fromi = 0;
1632 while (fromi < timecnt && attypes[fromi].at < min_time)
1633 ++fromi;
1634 if (isdsts[0] == 0)
1635 while (fromi < timecnt && attypes[fromi].type == 0)
1636 ++fromi; /* handled by default rule */
1637 for ( ; fromi < timecnt; ++fromi) {
1638 if (toi != 0 && ((attypes[fromi].at +
1639 gmtoffs[attypes[toi - 1].type]) <=
1640 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1641 : attypes[toi - 2].type]))) {
1642 attypes[toi - 1].type =
1643 attypes[fromi].type;
1644 continue;
1645 }
1646 if (toi == 0 ||
1647 attypes[toi - 1].type != attypes[fromi].type)
1648 attypes[toi++] = attypes[fromi];
1649 }
1650 timecnt = toi;
1651 }
1652 /*
1653 ** Transfer.
1654 */
1655 for (i = 0; i < timecnt; ++i) {
1656 ats[i] = attypes[i].at;
1657 types[i] = attypes[i].type;
1658 }
1659 /*
1660 ** Correct for leap seconds.
1661 */
1662 for (i = 0; i < timecnt; ++i) {
1663 j = leapcnt;
1664 while (--j >= 0)
1665 if (ats[i] > trans[j] - corr[j]) {
1666 ats[i] = tadd(ats[i], corr[j]);
1667 break;
1668 }
1669 }
1670 /*
1671 ** Figure out 32-bit-limited starts and counts.
1672 */
1673 timecnt32 = timecnt;
1674 timei32 = 0;
1675 leapcnt32 = leapcnt;
1676 leapi32 = 0;
1677 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1678 --timecnt32;
1679 while (timecnt32 > 0 && !is32(ats[timei32])) {
1680 --timecnt32;
1681 ++timei32;
1682 }
1683 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1684 --leapcnt32;
1685 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1686 --leapcnt32;
1687 ++leapi32;
1688 }
1689 fullname = erealloc(fullname,
1690 (int) (strlen(directory) + 1 + strlen(name) + 1));
1691 (void) sprintf(fullname, "%s/%s", directory, name);
1692 /*
1693 ** Remove old file, if any, to snap links.
1694 */
1695 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
1696 const char *e = strerror(errno);
1697
1698 (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
1699 progname, fullname, e);
1700 exit(EXIT_FAILURE);
1701 }
1702 if ((fp = fopen(fullname, "wb")) == NULL) {
1703 if (mkdirs(fullname) != 0)
1704 exit(EXIT_FAILURE);
1705 if ((fp = fopen(fullname, "wb")) == NULL) {
1706 const char *e = strerror(errno);
1707
1708 (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
1709 progname, fullname, e);
1710 exit(EXIT_FAILURE);
1711 }
1712 }
1713 for (pass = 1; pass <= 2; ++pass) {
1714 register int thistimei, thistimecnt;
1715 register int thisleapi, thisleapcnt;
1716 register int thistimelim, thisleaplim;
1717 int writetype[TZ_MAX_TIMES];
1718 int typemap[TZ_MAX_TYPES];
1719 register int thistypecnt;
1720 char thischars[TZ_MAX_CHARS];
1721 char thischarcnt;
1722 int indmap[TZ_MAX_CHARS];
1723
1724 if (pass == 1) {
1725 thistimei = timei32;
1726 thistimecnt = timecnt32;
1727 thisleapi = leapi32;
1728 thisleapcnt = leapcnt32;
1729 } else {
1730 thistimei = 0;
1731 thistimecnt = timecnt;
1732 thisleapi = 0;
1733 thisleapcnt = leapcnt;
1734 }
1735 thistimelim = thistimei + thistimecnt;
1736 thisleaplim = thisleapi + thisleapcnt;
1737 for (i = 0; i < typecnt; ++i)
1738 writetype[i] = thistimecnt == timecnt;
1739 if (thistimecnt == 0) {
1740 /*
1741 ** No transition times fall in the current
1742 ** (32- or 64-bit) window.
1743 */
1744 if (typecnt != 0)
1745 writetype[typecnt - 1] = TRUE;
1746 } else {
1747 for (i = thistimei - 1; i < thistimelim; ++i)
1748 if (i >= 0)
1749 writetype[types[i]] = TRUE;
1750 /*
1751 ** For America/Godthab and Antarctica/Palmer
1752 */
1753 if (thistimei == 0)
1754 writetype[0] = TRUE;
1755 }
1756 thistypecnt = 0;
1757 for (i = 0; i < typecnt; ++i)
1758 typemap[i] = writetype[i] ? thistypecnt++ : -1;
1759 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1760 indmap[i] = -1;
1761 thischarcnt = 0;
1762 for (i = 0; i < typecnt; ++i) {
1763 register char * thisabbr;
1764
1765 if (!writetype[i])
1766 continue;
1767 if (indmap[abbrinds[i]] >= 0)
1768 continue;
1769 thisabbr = &chars[abbrinds[i]];
1770 for (j = 0; j < thischarcnt; ++j)
1771 if (strcmp(&thischars[j], thisabbr) == 0)
1772 break;
1773 if (j == thischarcnt) {
1774 (void) strcpy(&thischars[(int) thischarcnt],
1775 thisabbr);
1776 thischarcnt += strlen(thisabbr) + 1;
1777 }
1778 indmap[abbrinds[i]] = j;
1779 }
1780#define DO(field) (void) fwrite((void *) tzh.field, \
1781 (size_t) sizeof tzh.field, (size_t) 1, fp)
1782 tzh = tzh0;
1783#ifdef ICU
fd0068a8
A
1784 * (ICUZoneinfoVersion*) &tzh.tzh_reserved = TZ_ICU_VERSION;
1785 (void) strncpy(tzh.tzh_magic, TZ_ICU_MAGIC, sizeof tzh.tzh_magic);
73c04bcf
A
1786#else
1787 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1788#endif
1789 tzh.tzh_version[0] = ZIC_VERSION;
1790 convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
1791 convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
1792 convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
1793 convert(eitol(thistimecnt), tzh.tzh_timecnt);
1794 convert(eitol(thistypecnt), tzh.tzh_typecnt);
1795 convert(eitol(thischarcnt), tzh.tzh_charcnt);
1796 DO(tzh_magic);
1797 DO(tzh_version);
1798 DO(tzh_reserved);
1799 DO(tzh_ttisgmtcnt);
1800 DO(tzh_ttisstdcnt);
1801 DO(tzh_leapcnt);
1802 DO(tzh_timecnt);
1803 DO(tzh_typecnt);
1804 DO(tzh_charcnt);
1805#undef DO
1806 for (i = thistimei; i < thistimelim; ++i)
1807 if (pass == 1)
1808 puttzcode((long) ats[i], fp);
1809 else puttzcode64(ats[i], fp);
1810 for (i = thistimei; i < thistimelim; ++i) {
1811 unsigned char uc;
1812
1813 uc = typemap[types[i]];
1814 (void) fwrite((void *) &uc,
1815 (size_t) sizeof uc,
1816 (size_t) 1,
1817 fp);
1818 }
1819 for (i = 0; i < typecnt; ++i)
1820 if (writetype[i]) {
1821#ifdef ICU
fd0068a8
A
1822 puttzcode((long) rawoffs[i], fp);
1823 puttzcode((long) dstoffs[i], fp);
73c04bcf 1824#else
fd0068a8 1825 puttzcode(gmtoffs[i], fp);
73c04bcf
A
1826#endif
1827 (void) putc(isdsts[i], fp);
1828 (void) putc((unsigned char) indmap[abbrinds[i]], fp);
1829 }
1830 if (thischarcnt != 0)
1831 (void) fwrite((void *) thischars,
1832 (size_t) sizeof thischars[0],
1833 (size_t) thischarcnt, fp);
1834 for (i = thisleapi; i < thisleaplim; ++i) {
1835 register zic_t todo;
1836
1837 if (roll[i]) {
1838 if (timecnt == 0 || trans[i] < ats[0]) {
1839 j = 0;
1840 while (isdsts[j])
1841 if (++j >= typecnt) {
1842 j = 0;
1843 break;
1844 }
1845 } else {
1846 j = 1;
1847 while (j < timecnt &&
1848 trans[i] >= ats[j])
1849 ++j;
1850 j = types[j - 1];
1851 }
1852 todo = tadd(trans[i], -gmtoffs[j]);
1853 } else todo = trans[i];
1854 if (pass == 1)
1855 puttzcode((long) todo, fp);
1856 else puttzcode64(todo, fp);
1857 puttzcode(corr[i], fp);
1858 }
1859 for (i = 0; i < typecnt; ++i)
1860 if (writetype[i])
1861 (void) putc(ttisstds[i], fp);
1862 for (i = 0; i < typecnt; ++i)
1863 if (writetype[i])
1864 (void) putc(ttisgmts[i], fp);
1865 }
1866 (void) fprintf(fp, "\n%s\n", string);
1867 if (ferror(fp) || fclose(fp)) {
1868 (void) fprintf(stderr, _("%s: Error writing %s\n"),
1869 progname, fullname);
1870 exit(EXIT_FAILURE);
1871 }
1872}
1873
1874static void
1875doabbr(abbr, format, letters, isdst, doquotes)
1876char * const abbr;
1877const char * const format;
1878const char * const letters;
1879const int isdst;
1880const int doquotes;
1881{
1882 register char * cp;
1883 register char * slashp;
1884 register int len;
1885
1886 slashp = strchr(format, '/');
1887 if (slashp == NULL) {
1888 if (letters == NULL)
1889 (void) strcpy(abbr, format);
1890 else (void) sprintf(abbr, format, letters);
1891 } else if (isdst) {
1892 (void) strcpy(abbr, slashp + 1);
1893 } else {
1894 if (slashp > format)
1895 (void) strncpy(abbr, format,
1896 (unsigned) (slashp - format));
1897 abbr[slashp - format] = '\0';
1898 }
1899 if (!doquotes)
1900 return;
1901 for (cp = abbr; *cp != '\0'; ++cp)
1902 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
1903 strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
1904 break;
1905 len = strlen(abbr);
1906 if (len > 0 && *cp == '\0')
1907 return;
1908 abbr[len + 2] = '\0';
1909 abbr[len + 1] = '>';
1910 for ( ; len > 0; --len)
1911 abbr[len] = abbr[len - 1];
1912 abbr[0] = '<';
1913}
1914
1915static void
1916updateminmax(x)
1917const int x;
1918{
1919 if (min_year > x)
1920 min_year = x;
1921 if (max_year < x)
1922 max_year = x;
1923}
1924
1925static int
1926stringoffset(result, offset)
1927char * result;
1928long offset;
1929{
1930 register int hours;
1931 register int minutes;
1932 register int seconds;
1933
1934 result[0] = '\0';
1935 if (offset < 0) {
1936 (void) strcpy(result, "-");
1937 offset = -offset;
1938 }
1939 seconds = offset % SECSPERMIN;
1940 offset /= SECSPERMIN;
1941 minutes = offset % MINSPERHOUR;
1942 offset /= MINSPERHOUR;
1943 hours = offset;
1944 if (hours >= HOURSPERDAY) {
1945 result[0] = '\0';
1946 return -1;
1947 }
1948 (void) sprintf(end(result), "%d", hours);
1949 if (minutes != 0 || seconds != 0) {
1950 (void) sprintf(end(result), ":%02d", minutes);
1951 if (seconds != 0)
1952 (void) sprintf(end(result), ":%02d", seconds);
1953 }
1954 return 0;
1955}
1956
1957static int
1958stringrule(result, rp, dstoff, gmtoff)
1959char * result;
1960const struct rule * const rp;
1961const long dstoff;
1962const long gmtoff;
1963{
1964 register long tod;
1965
1966 result = end(result);
1967 if (rp->r_dycode == DC_DOM) {
1968 register int month, total;
1969
1970 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
1971 return -1;
1972 total = 0;
1973 for (month = 0; month < rp->r_month; ++month)
1974 total += len_months[0][month];
1975 (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
1976 } else {
1977 register int week;
1978
1979 if (rp->r_dycode == DC_DOWGEQ) {
1980 week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1981 if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
1982 return -1;
1983 } else if (rp->r_dycode == DC_DOWLEQ) {
1984 if (rp->r_dayofmonth == len_months[1][rp->r_month])
1985 week = 5;
1986 else {
1987 week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1988 if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
1989 return -1;
1990 }
1991 } else return -1; /* "cannot happen" */
1992 (void) sprintf(result, "M%d.%d.%d",
1993 rp->r_month + 1, week, rp->r_wday);
1994 }
1995 tod = rp->r_tod;
1996 if (rp->r_todisgmt)
1997 tod += gmtoff;
1998 if (rp->r_todisstd && rp->r_stdoff == 0)
1999 tod += dstoff;
2000 if (tod < 0) {
2001 result[0] = '\0';
2002 return -1;
2003 }
2004 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
2005 (void) strcat(result, "/");
2006 if (stringoffset(end(result), tod) != 0)
2007 return -1;
2008 }
2009 return 0;
2010}
2011
2012static void
2013stringzone(result, zpfirst, zonecount)
2014char * result;
2015const struct zone * const zpfirst;
2016const int zonecount;
2017{
2018 register const struct zone * zp;
2019 register struct rule * rp;
2020 register struct rule * stdrp;
2021 register struct rule * dstrp;
2022 register int i;
2023 register const char * abbrvar;
2024
2025 result[0] = '\0';
2026 zp = zpfirst + zonecount - 1;
2027 stdrp = dstrp = NULL;
2028 for (i = 0; i < zp->z_nrules; ++i) {
2029 rp = &zp->z_rules[i];
2030 if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
2031 continue;
2032 if (rp->r_yrtype != NULL)
2033 continue;
2034 if (rp->r_stdoff == 0) {
2035 if (stdrp == NULL)
2036 stdrp = rp;
2037 else return;
2038 } else {
2039 if (dstrp == NULL)
2040 dstrp = rp;
2041 else return;
2042 }
2043 }
2044 if (stdrp == NULL && dstrp == NULL) {
2045 /*
2046 ** There are no rules running through "max".
2047 ** Let's find the latest rule.
2048 */
2049 for (i = 0; i < zp->z_nrules; ++i) {
2050 rp = &zp->z_rules[i];
2051 if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
2052 (rp->r_hiyear == stdrp->r_hiyear &&
2053 rp->r_month > stdrp->r_month))
2054 stdrp = rp;
2055 }
2056 if (stdrp != NULL && stdrp->r_stdoff != 0)
2057 return; /* We end up in DST (a POSIX no-no). */
2058 /*
2059 ** Horrid special case: if year is 2037,
2060 ** presume this is a zone handled on a year-by-year basis;
2061 ** do not try to apply a rule to the zone.
2062 */
2063 if (stdrp != NULL && stdrp->r_hiyear == 2037)
2064 return;
2065 }
2066 if (stdrp == NULL && zp->z_nrules != 0)
2067 return;
2068 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2069 doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
2070 if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
2071 result[0] = '\0';
2072 return;
2073 }
2074 if (dstrp == NULL)
2075 return;
2076 doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
2077 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
2078 if (stringoffset(end(result),
2079 -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
2080 result[0] = '\0';
2081 return;
2082 }
2083 (void) strcat(result, ",");
2084 if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
2085 result[0] = '\0';
2086 return;
2087 }
2088 (void) strcat(result, ",");
2089 if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
2090 result[0] = '\0';
2091 return;
2092 }
2093}
2094
73c04bcf
A
2095static void
2096outzone(zpfirst, zonecount)
2097const struct zone * const zpfirst;
2098const int zonecount;
2099{
2100 register const struct zone * zp;
2101 register struct rule * rp;
2102 register int i, j;
2103 register int usestart, useuntil;
2104 register zic_t starttime, untiltime;
2105 register long gmtoff;
2106 register long stdoff;
2107 register int year;
2108 register long startoff;
2109 register int startttisstd;
2110 register int startttisgmt;
2111 register int type;
2112 register char * startbuf;
2113 register char * ab;
2114 register char * envvar;
2115 register int max_abbr_len;
2116 register int max_envvar_len;
2117#ifdef ICU
fd0068a8
A
2118 int finalRuleYear, finalRuleIndex;
2119 const struct rule* finalRule1;
2120 const struct rule* finalRule2;
73c04bcf
A
2121#endif
2122
2123 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2124 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2125 startbuf = emalloc(max_abbr_len + 1);
2126 ab = emalloc(max_abbr_len + 1);
2127 envvar = emalloc(max_envvar_len + 1);
2128 INITIALIZE(untiltime);
2129 INITIALIZE(starttime);
2130 /*
2131 ** Now. . .finally. . .generate some useful data!
2132 */
2133 timecnt = 0;
2134 typecnt = 0;
2135 charcnt = 0;
2136 /*
2137 ** Thanks to Earl Chew
2138 ** for noting the need to unconditionally initialize startttisstd.
2139 */
2140 startttisstd = FALSE;
2141 startttisgmt = FALSE;
2142 min_year = max_year = EPOCH_YEAR;
2143 if (leapseen) {
2144 updateminmax(leapminyear);
2145 updateminmax(leapmaxyear);
2146 }
2147 for (i = 0; i < zonecount; ++i) {
2148 zp = &zpfirst[i];
fd0068a8
A
2149 if (i < zonecount - 1)
2150 updateminmax(zp->z_untilrule.r_loyear);
73c04bcf
A
2151 for (j = 0; j < zp->z_nrules; ++j) {
2152 rp = &zp->z_rules[j];
2153 if (rp->r_lowasnum)
2154 updateminmax(rp->r_loyear);
2155 if (rp->r_hiwasnum)
2156 updateminmax(rp->r_hiyear);
2157 }
2158 }
2159 /*
2160 ** Generate lots of data if a rule can't cover all future times.
2161 */
2162 stringzone(envvar, zpfirst, zonecount);
2163 if (noise && envvar[0] == '\0') {
2164 register char * wp;
2165
2166wp = ecpyalloc(_("no POSIX environment variable for zone"));
2167 wp = ecatalloc(wp, " ");
fd0068a8 2168 wp = ecatalloc(wp, zpfirst->z_name);
73c04bcf
A
2169 warning(wp);
2170 ifree(wp);
2171 }
2172 if (envvar[0] == '\0') {
2173 if (min_year >= INT_MIN + YEARSPERREPEAT)
2174 min_year -= YEARSPERREPEAT;
2175 else min_year = INT_MIN;
2176 if (max_year <= INT_MAX - YEARSPERREPEAT)
2177 max_year += YEARSPERREPEAT;
2178 else max_year = INT_MAX;
2179 }
2180 /*
fd0068a8
A
2181 ** For the benefit of older systems,
2182 ** generate data from 1900 through 2037.
73c04bcf 2183 */
fd0068a8
A
2184 if (min_year > 1900)
2185 min_year = 1900;
73c04bcf
A
2186 if (max_year < 2037)
2187 max_year = 2037;
2188 for (i = 0; i < zonecount; ++i) {
2189 /*
2190 ** A guess that may well be corrected later.
2191 */
2192 stdoff = 0;
2193 zp = &zpfirst[i];
2194 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2195 useuntil = i < (zonecount - 1);
2196 if (useuntil && zp->z_untiltime <= min_time)
2197 continue;
2198 gmtoff = zp->z_gmtoff;
2199 eat(zp->z_filename, zp->z_linenum);
2200 *startbuf = '\0';
2201 startoff = zp->z_gmtoff;
2202#ifdef ICU
fd0068a8
A
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
2208 * them. */
2209 for (j=0; j<zp->z_nrules; ++j) {
2210 rp = &zp->z_rules[j];
2211 if (rp->r_hiyear == INT_MAX) {
ba6d6ed2
A
2212 if (rp->r_loyear > finalRuleYear) {
2213 finalRuleYear = rp->r_loyear;
2214 }
fd0068a8
A
2215 if (finalRule1 == NULL) {
2216 finalRule1 = rp;
ba6d6ed2 2217 } else if (finalRule2 == NULL) {
fd0068a8 2218 finalRule2 = rp;
fd0068a8
A
2219 } else {
2220 error("more than two max rules found (ICU)");
2221 exit(EXIT_FAILURE);
2222 }
ba6d6ed2
A
2223 } else if (rp->r_hiyear >= finalRuleYear) {
2224 /* There might be an overriding non-max rule
2be65001
A
2225 * to be applied to a specific year after one of
2226 * max rule's start year. For example,
2227 *
2228 * Rule Foo 2010 max ...
2229 * Rule Foo 2015 only ...
2230 *
2231 * In this case, we need to change the start year of
2232 * the final (max) rules to the next year. */
ba6d6ed2 2233 finalRuleYear = rp->r_hiyear + 1;
2be65001
A
2234
2235 /* When above adjustment is done, max_year might need
2236 * to be adjusted, so the final rule will be properly
2237 * evaluated and emitted by the later code block.
2238 *
2239 * Note: This may push the start year of the final
2240 * rules ahead by 1 year unnecessarily. For example,
2241 * If there are two rules, non-max rule and max rule
2242 * starting in the same year, such as
2243 *
2244 * Rule Foo 2010 only ....
2245 * Rule Foo 2010 max ....
2246 *
2247 * In this case, the final (max) rule actually starts
2248 * in 2010, instead of 2010. We could make this tool
2249 * more intelligent to detect such situation. But pushing
2250 * final rule start year to 1 year ahead (in the worst case)
2251 * will just populate a few extra transitions, and it still
2252 * works fine. So for now, we're not trying to put additional
2253 * logic to optimize the case.
2254 */
2255 if (max_year < finalRuleYear) {
2256 max_year = finalRuleYear;
2257 }
fd0068a8
A
2258 }
2259 }
fd0068a8 2260 if (finalRule1 != NULL) {
2be65001
A
2261 if (finalRule2 == NULL) {
2262 warning("only one max rule found (ICU)");
fd0068a8 2263 finalRuleYear = finalRuleIndex = -1;
2be65001 2264 finalRule1 = NULL;
fd0068a8 2265 } else {
2be65001
A
2266 if (finalRule1->r_stdoff == finalRule2->r_stdoff) {
2267 /* America/Resolute in 2009a uses a pair of rules
2268 * which does not change the offset. ICU ignores
2269 * such rules without actual time transitions. */
2270 finalRuleYear = finalRuleIndex = -1;
2271 finalRule1 = finalRule2 = NULL;
2272 } else {
2273 /* Swap if necessary so finalRule1 occurs before
2274 * finalRule2 */
2275 if (finalRule1->r_month > finalRule2->r_month) {
2276 const struct rule* t = finalRule1;
2277 finalRule1 = finalRule2;
2278 finalRule2 = t;
2279 }
2280 /* Add final rule to our list */
2281 finalRuleIndex = add_icu_final_rules(finalRule1, finalRule2);
fd0068a8 2282 }
fd0068a8
A
2283 }
2284 }
2285 }
73c04bcf
A
2286#endif
2287
2288 if (zp->z_nrules == 0) {
2289 stdoff = zp->z_stdoff;
2290 doabbr(startbuf, zp->z_format,
2291 (char *) NULL, stdoff != 0, FALSE);
2292 type = addtype(oadd(zp->z_gmtoff, stdoff),
2293#ifdef ICU
fd0068a8 2294 zp->z_gmtoff, stdoff,
73c04bcf
A
2295#endif
2296 startbuf, stdoff != 0, startttisstd,
2297 startttisgmt);
2298 if (usestart) {
2299 addtt(starttime, type);
2300 usestart = FALSE;
2301 } else if (stdoff != 0)
2302 addtt(min_time, type);
2303 } else for (year = min_year; year <= max_year; ++year) {
2304 if (useuntil && year > zp->z_untilrule.r_hiyear)
2305 break;
2306 /*
2307 ** Mark which rules to do in the current year.
2308 ** For those to do, calculate rpytime(rp, year);
2309 */
2310 for (j = 0; j < zp->z_nrules; ++j) {
2311 rp = &zp->z_rules[j];
2312 eats(zp->z_filename, zp->z_linenum,
2313 rp->r_filename, rp->r_linenum);
2314 rp->r_todo = year >= rp->r_loyear &&
2315 year <= rp->r_hiyear &&
2316 yearistype(year, rp->r_yrtype);
2317 if (rp->r_todo)
2318 rp->r_temp = rpytime(rp, year);
2319 }
2320 for ( ; ; ) {
2321 register int k;
2322 register zic_t jtime, ktime;
2323 register long offset;
2324
2325 INITIALIZE(ktime);
2326 if (useuntil) {
2327 /*
2328 ** Turn untiltime into UTC
2329 ** assuming the current gmtoff and
2330 ** stdoff values.
2331 */
2332 untiltime = zp->z_untiltime;
2333 if (!zp->z_untilrule.r_todisgmt)
2334 untiltime = tadd(untiltime,
2335 -gmtoff);
2336 if (!zp->z_untilrule.r_todisstd)
2337 untiltime = tadd(untiltime,
2338 -stdoff);
2339 }
2340 /*
2341 ** Find the rule (of those to do, if any)
2342 ** that takes effect earliest in the year.
2343 */
2344 k = -1;
2345 for (j = 0; j < zp->z_nrules; ++j) {
2346 rp = &zp->z_rules[j];
2347 if (!rp->r_todo)
2348 continue;
2349 eats(zp->z_filename, zp->z_linenum,
2350 rp->r_filename, rp->r_linenum);
2351 offset = rp->r_todisgmt ? 0 : gmtoff;
2352 if (!rp->r_todisstd)
2353 offset = oadd(offset, stdoff);
2354 jtime = rp->r_temp;
2355 if (jtime == min_time ||
2356 jtime == max_time)
2357 continue;
2358 jtime = tadd(jtime, -offset);
2359 if (k < 0 || jtime < ktime) {
2360 k = j;
2361 ktime = jtime;
2362 }
2363 }
2364 if (k < 0)
2365 break; /* go on to next year */
2366 rp = &zp->z_rules[k];
2367 rp->r_todo = FALSE;
73c04bcf
A
2368 if (useuntil && ktime >= untiltime)
2369 break;
2370 stdoff = rp->r_stdoff;
2371 if (usestart && ktime == starttime)
2372 usestart = FALSE;
2373 if (usestart) {
2374 if (ktime < starttime) {
2375 startoff = oadd(zp->z_gmtoff,
2376 stdoff);
2377 doabbr(startbuf, zp->z_format,
2378 rp->r_abbrvar,
2379 rp->r_stdoff != 0,
2380 FALSE);
2381 continue;
2382 }
2383 if (*startbuf == '\0' &&
2384 startoff == oadd(zp->z_gmtoff,
2385 stdoff)) {
2386 doabbr(startbuf,
2387 zp->z_format,
2388 rp->r_abbrvar,
2389 rp->r_stdoff !=
2390 0,
2391 FALSE);
2392 }
2393 }
4162bf98 2394#ifdef ICU
fd0068a8
A
2395 if (year >= finalRuleYear && rp == finalRule1) {
2396 /* We want to shift final year 1 year after
2397 * the actual final rule takes effect (year + 1),
2398 * because the previous type is valid until the first
2399 * transition defined by the final rule. Otherwise
2400 * we may see unexpected offset shift at the
2401 * begining of the year when the final rule takes
2be65001
A
2402 * effect.
2403 *
2404 * Note: This may results some 64bit second transitions
2405 * at the very end (year 2038). ICU 4.2 or older releases
2406 * cannot handle 64bit second transitions and they are
2407 * dropped from zoneinfo.txt. */
fd0068a8
A
2408 emit_icu_zone(icuFile,
2409 zpfirst->z_name, zp->z_gmtoff,
729e4ab9 2410 rp, finalRuleIndex, year + 1);
fd0068a8
A
2411 /* only emit this for the first year */
2412 finalRule1 = NULL;
2413 }
4162bf98 2414#endif
73c04bcf
A
2415 eats(zp->z_filename, zp->z_linenum,
2416 rp->r_filename, rp->r_linenum);
2417 doabbr(ab, zp->z_format, rp->r_abbrvar,
2418 rp->r_stdoff != 0, FALSE);
2419 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2420#ifdef ICU
2421 type = addtype(offset, zp->z_gmtoff, rp->r_stdoff,
fd0068a8 2422 ab, rp->r_stdoff != 0,
73c04bcf
A
2423 rp->r_todisstd, rp->r_todisgmt);
2424#else
2425 type = addtype(offset, ab, rp->r_stdoff != 0,
2426 rp->r_todisstd, rp->r_todisgmt);
2427#endif
2428 addtt(ktime, type);
2429 }
2430 }
2431 if (usestart) {
2432 if (*startbuf == '\0' &&
2433 zp->z_format != NULL &&
2434 strchr(zp->z_format, '%') == NULL &&
2435 strchr(zp->z_format, '/') == NULL)
2436 (void) strcpy(startbuf, zp->z_format);
2437 eat(zp->z_filename, zp->z_linenum);
2438 if (*startbuf == '\0')
2439error(_("can't determine time zone abbreviation to use just after until time"));
2440 else addtt(starttime,
2441#ifdef ICU
2442 addtype(startoff,
fd0068a8
A
2443 zp->z_gmtoff, startoff - zp->z_gmtoff,
2444 startbuf,
73c04bcf
A
2445 startoff != zp->z_gmtoff,
2446 startttisstd,
2447 startttisgmt));
2448#else
2449 addtype(startoff, startbuf,
2450 startoff != zp->z_gmtoff,
2451 startttisstd,
2452 startttisgmt));
2453#endif
2454 }
2455 /*
2456 ** Now we may get to set starttime for the next zone line.
2457 */
2458 if (useuntil) {
2459 startttisstd = zp->z_untilrule.r_todisstd;
2460 startttisgmt = zp->z_untilrule.r_todisgmt;
2461 starttime = zp->z_untiltime;
2462 if (!startttisstd)
2463 starttime = tadd(starttime, -stdoff);
2464 if (!startttisgmt)
2465 starttime = tadd(starttime, -gmtoff);
2466 }
2467 }
2468 writezone(zpfirst->z_name, envvar);
2469 ifree(startbuf);
2470 ifree(ab);
2471 ifree(envvar);
2472}
2473
2474static void
2475addtt(starttime, type)
2476const zic_t starttime;
2477int type;
2478{
2479 if (starttime <= min_time ||
2480 (timecnt == 1 && attypes[0].at < min_time)) {
2481 gmtoffs[0] = gmtoffs[type];
2482#ifdef ICU
2483 rawoffs[0] = rawoffs[type];
2484 dstoffs[0] = dstoffs[type];
2485#endif
2486 isdsts[0] = isdsts[type];
2487 ttisstds[0] = ttisstds[type];
2488 ttisgmts[0] = ttisgmts[type];
2489 if (abbrinds[type] != 0)
2490 (void) strcpy(chars, &chars[abbrinds[type]]);
2491 abbrinds[0] = 0;
2492 charcnt = strlen(chars) + 1;
2493 typecnt = 1;
2494 timecnt = 0;
2495 type = 0;
2496 }
2497 if (timecnt >= TZ_MAX_TIMES) {
2498 error(_("too many transitions?!"));
2499 exit(EXIT_FAILURE);
2500 }
2501 attypes[timecnt].at = starttime;
2502 attypes[timecnt].type = type;
2503 ++timecnt;
2504}
2505
2506static int
2507#ifdef ICU
2508addtype(gmtoff, rawoff, dstoff, abbr, isdst, ttisstd, ttisgmt)
2509const long gmtoff;
2510const long rawoff;
2511const long dstoff;
2512#else
2513addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
2514const long gmtoff;
2515#endif
2516const char * const abbr;
2517const int isdst;
2518const int ttisstd;
2519const int ttisgmt;
2520{
2521 register int i, j;
2522
2523 if (isdst != TRUE && isdst != FALSE) {
2524 error(_("internal error - addtype called with bad isdst"));
2525 exit(EXIT_FAILURE);
2526 }
2527 if (ttisstd != TRUE && ttisstd != FALSE) {
2528 error(_("internal error - addtype called with bad ttisstd"));
2529 exit(EXIT_FAILURE);
2530 }
2531 if (ttisgmt != TRUE && ttisgmt != FALSE) {
2532 error(_("internal error - addtype called with bad ttisgmt"));
2533 exit(EXIT_FAILURE);
2534 }
2535#ifdef ICU
2536 if (isdst != (dstoff != 0)) {
2537 error(_("internal error - addtype called with bad isdst/dstoff"));
2538 (void) exit(EXIT_FAILURE);
2539 }
fd0068a8 2540 if (gmtoff != (rawoff + dstoff)) {
73c04bcf
A
2541 error(_("internal error - addtype called with bad gmt/raw/dstoff"));
2542 (void) exit(EXIT_FAILURE);
fd0068a8 2543 }
73c04bcf
A
2544#endif
2545 /*
2546 ** See if there's already an entry for this zone type.
2547 ** If so, just return its index.
2548 */
2549 for (i = 0; i < typecnt; ++i) {
2550 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2551#ifdef ICU
fd0068a8 2552 rawoff == rawoffs[i] && dstoff == dstoffs[i] &&
73c04bcf
A
2553#endif
2554 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2555 ttisstd == ttisstds[i] &&
2556 ttisgmt == ttisgmts[i])
2557 return i;
2558 }
2559 /*
2560 ** There isn't one; add a new one, unless there are already too
2561 ** many.
2562 */
2563 if (typecnt >= TZ_MAX_TYPES) {
2564 error(_("too many local time types"));
2565 exit(EXIT_FAILURE);
2566 }
fd0068a8
A
2567 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2568 error(_("UTC offset out of range"));
2569 exit(EXIT_FAILURE);
2570 }
73c04bcf
A
2571 gmtoffs[i] = gmtoff;
2572#ifdef ICU
fd0068a8
A
2573 rawoffs[i] = rawoff;
2574 dstoffs[i] = dstoff;
73c04bcf
A
2575#endif
2576 isdsts[i] = isdst;
2577 ttisstds[i] = ttisstd;
2578 ttisgmts[i] = ttisgmt;
2579
2580 for (j = 0; j < charcnt; ++j)
2581 if (strcmp(&chars[j], abbr) == 0)
2582 break;
2583 if (j == charcnt)
2584 newabbr(abbr);
2585 abbrinds[i] = j;
2586 ++typecnt;
2587 return i;
2588}
2589
2590static void
2591leapadd(t, positive, rolling, count)
2592const zic_t t;
2593const int positive;
2594const int rolling;
2595int count;
2596{
2597 register int i, j;
2598
2599 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2600 error(_("too many leap seconds"));
2601 exit(EXIT_FAILURE);
2602 }
2603 for (i = 0; i < leapcnt; ++i)
2604 if (t <= trans[i]) {
2605 if (t == trans[i]) {
2606 error(_("repeated leap second moment"));
2607 exit(EXIT_FAILURE);
2608 }
2609 break;
2610 }
2611 do {
2612 for (j = leapcnt; j > i; --j) {
2613 trans[j] = trans[j - 1];
2614 corr[j] = corr[j - 1];
2615 roll[j] = roll[j - 1];
2616 }
2617 trans[i] = t;
2618 corr[i] = positive ? 1L : eitol(-count);
2619 roll[i] = rolling;
2620 ++leapcnt;
2621 } while (positive && --count != 0);
2622}
2623
2624static void
fd0068a8 2625adjleap(void)
73c04bcf
A
2626{
2627 register int i;
2628 register long last = 0;
2629
2630 /*
2631 ** propagate leap seconds forward
2632 */
2633 for (i = 0; i < leapcnt; ++i) {
2634 trans[i] = tadd(trans[i], last);
2635 last = corr[i] += last;
2636 }
2637}
2638
2639static int
2640yearistype(year, type)
2641const int year;
2642const char * const type;
2643{
2644 static char * buf;
2645 int result;
2646
2647 if (type == NULL || *type == '\0')
2648 return TRUE;
2649 buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
2650 (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
2651 result = system(buf);
2652 if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2653 case 0:
2654 return TRUE;
2655 case 1:
2656 return FALSE;
2657 }
2658 error(_("Wild result from command execution"));
2659 (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2660 progname, buf, result);
2661 for ( ; ; )
2662 exit(EXIT_FAILURE);
2663}
2664
2665static int
2666lowerit(a)
2667int a;
2668{
2669 a = (unsigned char) a;
2670 return (isascii(a) && isupper(a)) ? tolower(a) : a;
2671}
2672
2673static int
2674ciequal(ap, bp) /* case-insensitive equality */
2675register const char * ap;
2676register const char * bp;
2677{
2678 while (lowerit(*ap) == lowerit(*bp++))
2679 if (*ap++ == '\0')
2680 return TRUE;
2681 return FALSE;
2682}
2683
2684static int
2685itsabbr(abbr, word)
2686register const char * abbr;
2687register const char * word;
2688{
2689 if (lowerit(*abbr) != lowerit(*word))
2690 return FALSE;
2691 ++word;
2692 while (*++abbr != '\0')
2693 do {
2694 if (*word == '\0')
2695 return FALSE;
2696 } while (lowerit(*word++) != lowerit(*abbr));
2697 return TRUE;
2698}
2699
2700static const struct lookup *
2701byword(word, table)
2702register const char * const word;
2703register const struct lookup * const table;
2704{
2705 register const struct lookup * foundlp;
2706 register const struct lookup * lp;
2707
2708 if (word == NULL || table == NULL)
2709 return NULL;
2710 /*
2711 ** Look for exact match.
2712 */
2713 for (lp = table; lp->l_word != NULL; ++lp)
2714 if (ciequal(word, lp->l_word))
2715 return lp;
2716 /*
2717 ** Look for inexact match.
2718 */
2719 foundlp = NULL;
2720 for (lp = table; lp->l_word != NULL; ++lp)
2721 if (itsabbr(word, lp->l_word)) {
2722 if (foundlp == NULL)
2723 foundlp = lp;
2724 else return NULL; /* multiple inexact matches */
2725 }
2726 return foundlp;
2727}
2728
2729static char **
2730getfields(cp)
2731register char * cp;
2732{
2733 register char * dp;
2734 register char ** array;
2735 register int nsubs;
2736
2737 if (cp == NULL)
2738 return NULL;
2739 array = (char **) (void *)
2740 emalloc((int) ((strlen(cp) + 1) * sizeof *array));
2741 nsubs = 0;
2742 for ( ; ; ) {
2743 while (isascii((unsigned char) *cp) &&
2744 isspace((unsigned char) *cp))
2745 ++cp;
2746 if (*cp == '\0' || *cp == '#')
2747 break;
2748 array[nsubs++] = dp = cp;
2749 do {
2750 if ((*dp = *cp++) != '"')
2751 ++dp;
2752 else while ((*dp = *cp++) != '"')
2753 if (*dp != '\0')
2754 ++dp;
fd0068a8
A
2755 else {
2756 error(_(
73c04bcf
A
2757 "Odd number of quotation marks"
2758 ));
fd0068a8
A
2759 exit(1);
2760 }
73c04bcf
A
2761 } while (*cp != '\0' && *cp != '#' &&
2762 (!isascii(*cp) || !isspace((unsigned char) *cp)));
2763 if (isascii(*cp) && isspace((unsigned char) *cp))
2764 ++cp;
2765 *dp = '\0';
2766 }
2767 array[nsubs] = NULL;
2768 return array;
2769}
2770
2771static long
2772oadd(t1, t2)
2773const long t1;
2774const long t2;
2775{
2776 register long t;
2777
2778 t = t1 + t2;
2779 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2780 error(_("time overflow"));
2781 exit(EXIT_FAILURE);
2782 }
2783 return t;
2784}
2785
2786static zic_t
2787tadd(t1, t2)
2788const zic_t t1;
2789const long t2;
2790{
2791 register zic_t t;
2792
2793 if (t1 == max_time && t2 > 0)
2794 return max_time;
2795 if (t1 == min_time && t2 < 0)
2796 return min_time;
2797 t = t1 + t2;
2798 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2799 error(_("time overflow"));
2800 exit(EXIT_FAILURE);
2801 }
2802 return t;
2803}
2804
2805/*
2806** Given a rule, and a year, compute the date - in seconds since January 1,
2807** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2808*/
2809
2810static zic_t
2811rpytime(rp, wantedy)
2812register const struct rule * const rp;
2813register const int wantedy;
2814{
2815 register int y, m, i;
2816 register long dayoff; /* with a nod to Margaret O. */
2817 register zic_t t;
2818
2819 if (wantedy == INT_MIN)
2820 return min_time;
2821 if (wantedy == INT_MAX)
2822 return max_time;
2823 dayoff = 0;
2824 m = TM_JANUARY;
2825 y = EPOCH_YEAR;
2826 while (wantedy != y) {
2827 if (wantedy > y) {
2828 i = len_years[isleap(y)];
2829 ++y;
2830 } else {
2831 --y;
2832 i = -len_years[isleap(y)];
2833 }
2834 dayoff = oadd(dayoff, eitol(i));
2835 }
2836 while (m != rp->r_month) {
2837 i = len_months[isleap(y)][m];
2838 dayoff = oadd(dayoff, eitol(i));
2839 ++m;
2840 }
2841 i = rp->r_dayofmonth;
2842 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2843 if (rp->r_dycode == DC_DOWLEQ)
2844 --i;
2845 else {
2846 error(_("use of 2/29 in non leap-year"));
2847 exit(EXIT_FAILURE);
2848 }
2849 }
2850 --i;
2851 dayoff = oadd(dayoff, eitol(i));
2852 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2853 register long wday;
2854
2855#define LDAYSPERWEEK ((long) DAYSPERWEEK)
2856 wday = eitol(EPOCH_WDAY);
2857 /*
2858 ** Don't trust mod of negative numbers.
2859 */
2860 if (dayoff >= 0)
2861 wday = (wday + dayoff) % LDAYSPERWEEK;
2862 else {
2863 wday -= ((-dayoff) % LDAYSPERWEEK);
2864 if (wday < 0)
2865 wday += LDAYSPERWEEK;
2866 }
2867 while (wday != eitol(rp->r_wday))
2868 if (rp->r_dycode == DC_DOWGEQ) {
2869 dayoff = oadd(dayoff, (long) 1);
2870 if (++wday >= LDAYSPERWEEK)
2871 wday = 0;
2872 ++i;
2873 } else {
2874 dayoff = oadd(dayoff, (long) -1);
2875 if (--wday < 0)
2876 wday = LDAYSPERWEEK - 1;
2877 --i;
2878 }
2879 if (i < 0 || i >= len_months[isleap(y)][m]) {
2880 if (noise)
2881 warning(_("rule goes past start/end of month--\
2882will not work with pre-2004 versions of zic"));
2883 }
2884 }
2885 if (dayoff < min_time / SECSPERDAY)
2886 return min_time;
2887 if (dayoff > max_time / SECSPERDAY)
2888 return max_time;
2889 t = (zic_t) dayoff * SECSPERDAY;
2890 return tadd(t, rp->r_tod);
2891}
2892
2893static void
2894newabbr(string)
2895const char * const string;
2896{
2897 register int i;
2898
2899 if (strcmp(string, GRANDPARENTED) != 0) {
2900 register const char * cp;
2901 register char * wp;
2902
2903 /*
2904 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2905 ** optionally followed by a + or - and a number from 1 to 14.
2906 */
2907 cp = string;
2908 wp = NULL;
2909 while (isascii((unsigned char) *cp) &&
2910 isalpha((unsigned char) *cp))
2911 ++cp;
2912 if (cp - string == 0)
2913wp = _("time zone abbreviation lacks alphabetic at start");
2914 if (noise && cp - string > 3)
2915wp = _("time zone abbreviation has more than 3 alphabetics");
2916 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2917wp = _("time zone abbreviation has too many alphabetics");
2918 if (wp == NULL && (*cp == '+' || *cp == '-')) {
2919 ++cp;
2920 if (isascii((unsigned char) *cp) &&
2921 isdigit((unsigned char) *cp))
2922 if (*cp++ == '1' &&
2923 *cp >= '0' && *cp <= '4')
2924 ++cp;
2925 }
2926 if (*cp != '\0')
2927wp = _("time zone abbreviation differs from POSIX standard");
2928 if (wp != NULL) {
2929 wp = ecpyalloc(wp);
2930 wp = ecatalloc(wp, " (");
2931 wp = ecatalloc(wp, string);
2932 wp = ecatalloc(wp, ")");
2933 warning(wp);
2934 ifree(wp);
2935 }
2936 }
2937 i = strlen(string) + 1;
2938 if (charcnt + i > TZ_MAX_CHARS) {
2939 error(_("too many, or too long, time zone abbreviations"));
2940 exit(EXIT_FAILURE);
2941 }
2942 (void) strcpy(&chars[charcnt], string);
2943 charcnt += eitol(i);
2944}
2945
2946static int
2947mkdirs(argname)
fd0068a8 2948char * argname;
73c04bcf
A
2949{
2950 register char * name;
2951 register char * cp;
2952
2953 if (argname == NULL || *argname == '\0')
2954 return 0;
2955 cp = name = ecpyalloc(argname);
2956 while ((cp = strchr(cp + 1, '/')) != 0) {
2957 *cp = '\0';
2958#ifndef unix
2959 /*
2960 ** DOS drive specifier?
2961 */
2962 if (isalpha((unsigned char) name[0]) &&
2963 name[1] == ':' && name[2] == '\0') {
2964 *cp = '/';
2965 continue;
2966 }
2967#endif /* !defined unix */
2968 if (!itsdir(name)) {
2969 /*
2970 ** It doesn't seem to exist, so we try to create it.
2971 ** Creation may fail because of the directory being
2972 ** created by some other multiprocessor, so we get
2973 ** to do extra checking.
2974 */
2975 if (mkdir(name, MKDIR_UMASK) != 0) {
2976 const char *e = strerror(errno);
2977
2978 if (errno != EEXIST || !itsdir(name)) {
2979 (void) fprintf(stderr,
2980_("%s: Can't create directory %s: %s\n"),
2981 progname, name, e);
2982 ifree(name);
2983 return -1;
2984 }
2985 }
2986 }
2987 *cp = '/';
2988 }
2989 ifree(name);
2990 return 0;
2991}
2992
2993static long
2994eitol(i)
2995const int i;
2996{
2997 long l;
2998
2999 l = i;
3000 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
3001 (void) fprintf(stderr,
3002 _("%s: %d did not sign extend correctly\n"),
3003 progname, i);
3004 exit(EXIT_FAILURE);
3005 }
3006 return l;
3007}
3008
3009/*
3010** UNIX was a registered trademark of The Open Group in 2003.
3011*/