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