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