8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / zic / zic.c
blob71eaa6b043d7263693597a686b6e3070b1ad1246
1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 static char elsieid[] = "@(#)zic.c 7.128.1";
8 /*
9 * #define LEAPSECOND_SUPPORT
13 * Regardless of the type of time_t, we do our work using this type.
16 typedef int zic_t;
18 #include "private.h"
19 #include <tzfile.h> /* this is in system headers at Sun */
21 #include <sys/stat.h> /* for umask manifest constants */
22 #include <ctype.h>
23 #include <locale.h>
24 #include <stdlib.h> /* for getopt */
26 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
27 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
28 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
30 #ifdef S_IRUSR
31 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
32 #else
33 #define MKDIR_UMASK 0755
34 #endif
36 struct rule {
37 const char *r_filename;
38 int r_linenum;
39 const char *r_name;
41 int r_loyear; /* for example, 1986 */
42 int r_hiyear; /* for example, 1986 */
43 const char *r_yrtype;
45 int r_month; /* 0..11 */
47 int r_dycode; /* see below */
48 int r_dayofmonth;
49 int r_wday;
51 long r_tod; /* time from midnight */
52 int r_todisstd; /* above is standard time if TRUE */
53 /* or wall clock time if FALSE */
54 int r_todisgmt; /* above is GMT if TRUE */
55 /* or local time if FALSE */
56 long r_stdoff; /* offset from standard time */
57 const char *r_abbrvar; /* variable part of abbreviation */
59 int r_todo; /* a rule to do (used in outzone) */
60 zic_t r_temp; /* used in outzone */
64 * r_dycode r_dayofmonth r_wday
67 #define DC_DOM 0 /* 1..31 */ /* unused */
68 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
69 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
71 struct zone {
72 const char *z_filename;
73 int z_linenum;
75 const char *z_name;
76 long z_gmtoff;
77 const char *z_rule;
78 const char *z_format;
80 long z_stdoff;
82 struct rule *z_rules;
83 int z_nrules;
85 struct rule z_untilrule;
86 zic_t z_untiltime;
89 static void addtt(zic_t starttime, int type);
90 static int addtype(long gmtoff, const char *abbr, int isdst,
91 int ttisstd, int ttisgmt);
92 #ifdef LEAPSECOND_SUPPORT
93 static void leapadd(zic_t t, int positive, int rolling, int count);
94 static void adjleap(void);
95 #endif
96 static void associate(void);
97 static int ciequal(const char *ap, const char *bp);
98 static void convert(long val, char *buf);
99 static void dolink(const char *fromfield, const char *tofield);
100 static void doabbr(char *abbr, const char *format,
101 const char *letters, int isdst);
102 static void eat(const char *name, int num);
103 static void eats(const char *name, int num,
104 const char *rname, int rnum);
105 static long eitol(int i);
106 static void error(const char *message);
107 static char **getfields(char *buf);
108 static long gethms(const char *string, const char *errstrng, int signable);
109 static void infile(const char *filename);
110 #ifdef LEAPSECOND_SUPPORT
111 static void inleap(char **fields, int nfields);
112 #endif
113 static void inlink(char **fields, int nfields);
114 static void inrule(char **fields, int nfields);
115 static int inzcont(char **fields, int nfields);
116 static int inzone(char **fields, int nfields);
117 static int inzsub(char **fields, int nfields, int iscont);
118 static int itsabbr(const char *abbr, const char *word);
119 static int itsdir(const char *name);
120 static int lowerit(int c);
121 static char *memcheck(char *tocheck);
122 static int mkdirs(char *filename);
123 static void newabbr(const char *abbr);
124 static long oadd(long t1, long t2);
125 static void outzone(const struct zone *zp, int ntzones);
126 static void puttzcode(long code, FILE *fp);
127 static int rcomp(const void *leftp, const void *rightp);
128 static zic_t rpytime(const struct rule *rp, int wantedy);
129 static void rulesub(struct rule *rp,
130 const char *loyearp, const char *hiyearp,
131 const char *typep, const char *monthp,
132 const char *dayp, const char *timep);
133 static void setboundaries(void);
134 static zic_t tadd(zic_t t1, long t2);
135 static void usage(void);
136 static void writezone(const char *name);
137 static int yearistype(int year, const char *type);
139 static int charcnt;
140 static int errors;
141 static const char *filename;
142 static int leapcnt;
143 static int linenum;
144 static zic_t max_time;
145 static int max_year;
146 static int max_year_representable;
147 static zic_t min_time;
148 static int min_year;
149 static int min_year_representable;
150 static int noise;
151 static const char *rfilename;
152 static int rlinenum;
153 static const char *progname;
154 static int timecnt;
155 static int typecnt;
158 * Line codes.
161 #define LC_RULE 0
162 #define LC_ZONE 1
163 #define LC_LINK 2
164 #define LC_LEAP 3
167 * Which fields are which on a Zone line.
170 #define ZF_NAME 1
171 #define ZF_GMTOFF 2
172 #define ZF_RULE 3
173 #define ZF_FORMAT 4
174 #define ZF_TILYEAR 5
175 #define ZF_TILMONTH 6
176 #define ZF_TILDAY 7
177 #define ZF_TILTIME 8
178 #define ZONE_MINFIELDS 5
179 #define ZONE_MAXFIELDS 9
182 * Which fields are which on a Zone continuation line.
185 #define ZFC_GMTOFF 0
186 #define ZFC_RULE 1
187 #define ZFC_FORMAT 2
188 #define ZFC_TILYEAR 3
189 #define ZFC_TILMONTH 4
190 #define ZFC_TILDAY 5
191 #define ZFC_TILTIME 6
192 #define ZONEC_MINFIELDS 3
193 #define ZONEC_MAXFIELDS 7
196 * Which files are which on a Rule line.
199 #define RF_NAME 1
200 #define RF_LOYEAR 2
201 #define RF_HIYEAR 3
202 #define RF_COMMAND 4
203 #define RF_MONTH 5
204 #define RF_DAY 6
205 #define RF_TOD 7
206 #define RF_STDOFF 8
207 #define RF_ABBRVAR 9
208 #define RULE_FIELDS 10
211 * Which fields are which on a Link line.
214 #define LF_FROM 1
215 #define LF_TO 2
216 #define LINK_FIELDS 3
219 * Which fields are which on a Leap line.
222 #define LP_YEAR 1
223 #define LP_MONTH 2
224 #define LP_DAY 3
225 #define LP_TIME 4
226 #define LP_CORR 5
227 #define LP_ROLL 6
228 #define LEAP_FIELDS 7
231 * Year synonyms.
234 #define YR_MINIMUM 0
235 #define YR_MAXIMUM 1
236 #define YR_ONLY 2
238 static struct rule *rules;
239 static int nrules; /* number of rules */
241 static struct zone *zones;
242 static int nzones; /* number of zones */
244 struct link {
245 const char *l_filename;
246 int l_linenum;
247 const char *l_from;
248 const char *l_to;
251 static struct link *links;
252 static int nlinks;
254 struct lookup {
255 const char *l_word;
256 const int l_value;
259 static struct lookup const *byword(const char *string,
260 const struct lookup *lp);
262 static struct lookup const line_codes[] = {
263 { "Rule", LC_RULE },
264 { "Zone", LC_ZONE },
265 { "Link", LC_LINK },
266 { "Leap", LC_LEAP },
267 { NULL, 0}
270 static struct lookup const mon_names[] = {
271 { "January", TM_JANUARY },
272 { "February", TM_FEBRUARY },
273 { "March", TM_MARCH },
274 { "April", TM_APRIL },
275 { "May", TM_MAY },
276 { "June", TM_JUNE },
277 { "July", TM_JULY },
278 { "August", TM_AUGUST },
279 { "September", TM_SEPTEMBER },
280 { "October", TM_OCTOBER },
281 { "November", TM_NOVEMBER },
282 { "December", TM_DECEMBER },
283 { NULL, 0 }
286 static struct lookup const wday_names[] = {
287 { "Sunday", TM_SUNDAY },
288 { "Monday", TM_MONDAY },
289 { "Tuesday", TM_TUESDAY },
290 { "Wednesday", TM_WEDNESDAY },
291 { "Thursday", TM_THURSDAY },
292 { "Friday", TM_FRIDAY },
293 { "Saturday", TM_SATURDAY },
294 { NULL, 0 }
297 static struct lookup const lasts[] = {
298 { "last-Sunday", TM_SUNDAY },
299 { "last-Monday", TM_MONDAY },
300 { "last-Tuesday", TM_TUESDAY },
301 { "last-Wednesday", TM_WEDNESDAY },
302 { "last-Thursday", TM_THURSDAY },
303 { "last-Friday", TM_FRIDAY },
304 { "last-Saturday", TM_SATURDAY },
305 { NULL, 0 }
308 static struct lookup const begin_years[] = {
309 { "minimum", YR_MINIMUM },
310 { "maximum", YR_MAXIMUM },
311 { NULL, 0 }
314 static struct lookup const end_years[] = {
315 { "minimum", YR_MINIMUM },
316 { "maximum", YR_MAXIMUM },
317 { "only", YR_ONLY },
318 { NULL, 0 }
321 static struct lookup const leap_types[] = {
322 { "Rolling", TRUE },
323 { "Stationary", FALSE },
324 { NULL, 0 }
327 static const int len_months[2][MONSPERYEAR] = {
328 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
329 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
332 static const int len_years[2] = {
333 DAYSPERNYEAR, DAYSPERLYEAR
336 static struct attype {
337 zic_t at;
338 unsigned char type;
339 } attypes[TZ_MAX_TIMES];
340 static long gmtoffs[TZ_MAX_TYPES];
341 static char isdsts[TZ_MAX_TYPES];
342 static unsigned char abbrinds[TZ_MAX_TYPES];
343 static char ttisstds[TZ_MAX_TYPES];
344 static char ttisgmts[TZ_MAX_TYPES];
345 static char chars[TZ_MAX_CHARS];
346 static zic_t trans[TZ_MAX_LEAPS];
347 static long corr[TZ_MAX_LEAPS];
348 static char roll[TZ_MAX_LEAPS];
351 * Memory allocation.
354 static char *
355 memcheck(ptr)
356 char * const ptr;
358 if (ptr == NULL) {
359 const char *e = strerror(errno);
360 (void) fprintf(stderr, gettext("%s: Memory exhausted: %s\n"),
361 progname, e);
362 exit(EXIT_FAILURE);
364 return (ptr);
367 #define emalloc(size) memcheck(imalloc(size))
368 #define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
369 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
370 #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
373 * Error handling.
376 static void
377 eats(name, num, rname, rnum)
378 const char * const name;
379 const int num;
380 const char * const rname;
381 const int rnum;
383 filename = name;
384 linenum = num;
385 rfilename = rname;
386 rlinenum = rnum;
389 static void
390 eat(name, num)
391 const char * const name;
392 const int num;
394 eats(name, num, (char *)NULL, -1);
397 static void
398 error(string)
399 const char * const string;
402 * Match the format of "cc" to allow sh users to
403 * zic ... 2>&1 | error -t "*" -v
404 * on BSD systems.
406 (void) fprintf(stderr, gettext("\"%s\", line %d: %s"),
407 filename, linenum, string);
408 if (rfilename != NULL)
409 (void) fprintf(stderr, gettext(" (rule from \"%s\", line %d)"),
410 rfilename, rlinenum);
411 (void) fprintf(stderr, "\n");
412 ++errors;
415 static void
416 warning(string)
417 const char * const string;
419 char *cp;
421 cp = ecpyalloc(gettext("warning: "));
422 cp = ecatalloc(cp, string);
423 error(cp);
424 ifree(cp);
425 --errors;
428 static void
429 usage(void)
431 #ifdef LEAPSECOND_SUPPORT
432 (void) fprintf(stderr, gettext("%s: usage is %s "
433 "[ --version ] [ -s ] [ -v ] [ -l localtime ] "
434 "\n\t[ -p posixrules ] [ -d directory ] [ -L leapseconds ] "
435 "[ -y yearistype ] [ filename ... ]\n"), progname, progname);
436 #else /* ! LEAPSECOND_SUPPORT */
437 (void) fprintf(stderr, gettext("%s: usage is %s "
438 "[ --version ] [ -s ] [ -v ] [ -l localtime ]"
439 "\n\t[ -p posixrules ] [ -d directory ] [ -y yearistype ] "
440 "[ filename ... ]\n"), progname, progname);
441 #endif /* LEAPSECOND_SUPPORT */
442 exit(EXIT_FAILURE);
445 static const char *psxrules;
446 static const char *lcltime;
447 static const char *directory;
448 static const char *leapsec;
449 static const char *yitcommand;
450 static int sflag = FALSE;
453 main(argc, argv)
454 int argc;
455 char *argv[];
457 register int i;
458 register int j;
459 register int c;
461 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
463 (void) setlocale(LC_ALL, "");
464 #if !defined(TEXT_DOMAIN)
465 #define TEXT_DOMAIN "SYS_TEST"
466 #endif
467 (void) textdomain(TEXT_DOMAIN);
469 progname = argv[0];
470 for (i = 1; i < argc; ++i)
471 if (strcmp(argv[i], "--version") == 0) {
472 (void) printf("%s\n", elsieid);
473 exit(EXIT_SUCCESS);
476 #ifdef LEAPSECOND_SUPPORT
477 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF)
478 #else
479 while ((c = getopt(argc, argv, "d:l:p:vsy:")) != EOF)
480 #endif
481 switch (c) {
482 default:
483 usage();
484 break;
485 case 'd':
486 if (directory == NULL)
487 directory = optarg;
488 else {
489 (void) fprintf(stderr, gettext(
490 "%s: More than one -d option specified\n"),
491 progname);
492 exit(EXIT_FAILURE);
494 break;
495 case 'l':
496 if (lcltime == NULL)
497 lcltime = optarg;
498 else {
499 (void) fprintf(stderr, gettext(
500 "%s: More than one -l option specified\n"),
501 progname);
502 exit(EXIT_FAILURE);
504 break;
505 case 'p':
506 if (psxrules == NULL)
507 psxrules = optarg;
508 else {
509 (void) fprintf(stderr, gettext(
510 "%s: More than one -p option specified\n"),
511 progname);
512 exit(EXIT_FAILURE);
514 break;
515 case 'y':
516 if (yitcommand == NULL)
517 yitcommand = optarg;
518 else {
519 (void) fprintf(stderr, gettext(
520 "%s: More than one -y option specified\n"),
521 progname);
522 exit(EXIT_FAILURE);
524 break;
525 #ifdef LEAPSECOND_SUPPORT
526 case 'L':
527 if (leapsec == NULL)
528 leapsec = optarg;
529 else {
530 (void) fprintf(stderr, gettext(
531 "%s: More than one -L option specified\n"),
532 progname);
533 exit(EXIT_FAILURE);
535 break;
536 #endif /* LEAPSECOND_SUPPORT */
537 case 'v':
538 noise = TRUE;
539 break;
540 case 's':
541 sflag = TRUE;
542 break;
544 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
545 usage(); /* usage message by request */
546 if (directory == NULL)
547 directory = TZDIR;
548 if (yitcommand == NULL)
549 yitcommand = "yearistype";
551 setboundaries();
553 #ifdef LEAPSECOND_SUPPORT
554 if (optind < argc && leapsec != NULL) {
555 infile(leapsec);
556 adjleap();
558 #endif /* LEAPSECOND_SUPPORT */
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) {
567 * Find the next non-continuation zone entry.
569 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
570 continue;
571 outzone(&zones[i], j - i);
574 * Make links.
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, links[j].l_from) == 0)
582 warning(gettext("link to link"));
584 if (lcltime != NULL) {
585 eat("command line", 1);
586 dolink(lcltime, TZDEFAULT);
588 if (psxrules != NULL) {
589 eat("command line", 1);
590 dolink(psxrules, TZDEFRULES);
592 return ((errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
595 static void
596 dolink(fromfield, tofield)
597 const char * const fromfield;
598 const char * const tofield;
600 register char *fromname;
601 register char *toname;
603 if (fromfield[0] == '/')
604 fromname = ecpyalloc(fromfield);
605 else {
606 fromname = ecpyalloc(directory);
607 fromname = ecatalloc(fromname, "/");
608 fromname = ecatalloc(fromname, fromfield);
610 if (tofield[0] == '/')
611 toname = ecpyalloc(tofield);
612 else {
613 toname = ecpyalloc(directory);
614 toname = ecatalloc(toname, "/");
615 toname = ecatalloc(toname, tofield);
618 * We get to be careful here since
619 * there's a fair chance of root running us.
621 if (!itsdir(toname))
622 (void) remove(toname);
623 if (link(fromname, toname) != 0) {
624 int result;
626 if (mkdirs(toname) != 0)
627 exit(EXIT_FAILURE);
629 result = link(fromname, toname);
631 if (result != 0 && access(fromname, F_OK) == 0 &&
632 !itsdir(fromname)) {
633 const char *s = tofield;
634 register char *symlinkcontents = NULL;
636 while ((s = strchr(s+1, '/')) != NULL)
637 symlinkcontents = ecatalloc(symlinkcontents,
638 "../");
639 symlinkcontents = ecatalloc(symlinkcontents, fromname);
640 result = symlink(symlinkcontents, toname);
641 if (result == 0)
642 warning(gettext(
643 "hard link failed, symbolic link used"));
644 ifree(symlinkcontents);
647 if (result != 0) {
648 const char *e = strerror(errno);
650 (void) fprintf(stderr, gettext(
651 "%s: Can't link from %s to %s: %s\n"),
652 progname, fromname, toname, e);
653 exit(EXIT_FAILURE);
656 ifree(fromname);
657 ifree(toname);
660 #ifndef INT_MAX
661 #define INT_MAX ((int)(((unsigned)~0)>>1))
662 #endif /* !defined INT_MAX */
664 #ifndef INT_MIN
665 #define INT_MIN ((int)~(((unsigned)~0)>>1))
666 #endif /* !defined INT_MIN */
669 * The tz file format currently allows at most 32-bit quantities.
670 * This restriction should be removed before signed 32-bit values
671 * wrap around in 2038, but unfortunately this will require a
672 * change to the tz file format.
675 #define MAX_BITS_IN_FILE 32
676 /* CSTYLED */
677 #define TIME_T_BITS_IN_FILE ((TYPE_BIT(zic_t) < MAX_BITS_IN_FILE) ? \
678 TYPE_BIT(zic_t): MAX_BITS_IN_FILE)
680 static void
681 setboundaries(void)
683 register int i;
685 if (TYPE_SIGNED(zic_t)) {
686 min_time = -1;
687 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
688 min_time *= 2;
689 max_time = -(min_time + 1);
690 if (sflag)
691 min_time = 0;
692 } else {
693 min_time = 0;
694 max_time = 2 - sflag;
695 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
696 max_time *= 2;
697 --max_time;
700 time_t t;
702 t = (time_t)min_time;
703 min_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
704 t = (time_t)max_time;
705 max_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
707 min_year_representable = min_year;
708 max_year_representable = max_year;
711 static int
712 itsdir(name)
713 const char * const name;
715 register char *myname;
716 register int accres;
718 myname = ecpyalloc(name);
719 myname = ecatalloc(myname, "/.");
720 accres = access(myname, F_OK);
721 ifree(myname);
722 return (accres == 0);
726 * Associate sets of rules with zones.
730 * Sort by rule name.
733 static int
734 rcomp(cp1, cp2)
735 const void * cp1;
736 const void * cp2;
738 return (strcmp(((const struct rule *) cp1)->r_name,
739 ((const struct rule *) cp2)->r_name));
742 static void
743 associate(void)
745 register struct zone *zp;
746 register struct rule *rp;
747 register int base, out;
748 register int i, j;
750 if (nrules != 0) {
751 (void) qsort((void *)rules, (size_t)nrules,
752 (size_t)sizeof (*rules), rcomp);
753 for (i = 0; i < nrules - 1; ++i) {
754 if (strcmp(rules[i].r_name,
755 rules[i + 1].r_name) != 0)
756 continue;
757 if (strcmp(rules[i].r_filename,
758 rules[i + 1].r_filename) == 0)
759 continue;
760 eat(rules[i].r_filename, rules[i].r_linenum);
761 warning(gettext("same rule name in multiple files"));
762 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
763 warning(gettext("same rule name in multiple files"));
764 for (j = i + 2; j < nrules; ++j) {
765 if (strcmp(rules[i].r_name,
766 rules[j].r_name) != 0)
767 break;
768 if (strcmp(rules[i].r_filename,
769 rules[j].r_filename) == 0)
770 continue;
771 if (strcmp(rules[i + 1].r_filename,
772 rules[j].r_filename) == 0)
773 continue;
774 break;
776 i = j - 1;
779 for (i = 0; i < nzones; ++i) {
780 zp = &zones[i];
781 zp->z_rules = NULL;
782 zp->z_nrules = 0;
784 for (base = 0; base < nrules; base = out) {
785 rp = &rules[base];
786 for (out = base + 1; out < nrules; ++out)
787 if (strcmp(rp->r_name, rules[out].r_name) != 0)
788 break;
789 for (i = 0; i < nzones; ++i) {
790 zp = &zones[i];
791 if (strcmp(zp->z_rule, rp->r_name) != 0)
792 continue;
793 zp->z_rules = rp;
794 zp->z_nrules = out - base;
797 for (i = 0; i < nzones; ++i) {
798 zp = &zones[i];
799 if (zp->z_nrules == 0) {
801 * Maybe we have a local standard time offset.
803 eat(zp->z_filename, zp->z_linenum);
804 zp->z_stdoff = gethms(zp->z_rule,
805 gettext("unruly zone"), TRUE);
807 * Note, though, that if there's no rule,
808 * a '%s' in the format is a bad thing.
810 if (strchr(zp->z_format, '%') != 0)
811 error(gettext("%s in ruleless zone"));
814 if (errors)
815 exit(EXIT_FAILURE);
818 static void
819 infile(name)
820 const char *name;
822 register FILE *fp;
823 register char **fields;
824 register char *cp;
825 register const struct lookup *lp;
826 register int nfields;
827 register int wantcont;
828 register int num;
829 char buf[BUFSIZ];
831 if (strcmp(name, "-") == 0) {
832 name = gettext("standard input");
833 fp = stdin;
834 } else if ((fp = fopen(name, "r")) == NULL) {
835 const char *e = strerror(errno);
837 (void) fprintf(stderr, gettext("%s: Can't open %s: %s\n"),
838 progname, name, e);
839 exit(EXIT_FAILURE);
841 wantcont = FALSE;
842 for (num = 1; ; ++num) {
843 eat(name, num);
844 if (fgets(buf, (int)sizeof (buf), fp) != buf)
845 break;
846 cp = strchr(buf, '\n');
847 if (cp == NULL) {
848 error(gettext("line too long"));
849 exit(EXIT_FAILURE);
851 *cp = '\0';
852 fields = getfields(buf);
853 nfields = 0;
854 while (fields[nfields] != NULL) {
855 static char nada;
857 if (strcmp(fields[nfields], "-") == 0)
858 fields[nfields] = &nada;
859 ++nfields;
861 if (nfields == 0) {
862 /* nothing to do */
863 } else if (wantcont) {
864 wantcont = inzcont(fields, nfields);
865 } else {
866 lp = byword(fields[0], line_codes);
867 if (lp == NULL)
868 error(gettext("input line of unknown type"));
869 else switch ((int)(lp->l_value)) {
870 case LC_RULE:
871 inrule(fields, nfields);
872 wantcont = FALSE;
873 break;
874 case LC_ZONE:
875 wantcont = inzone(fields, nfields);
876 break;
877 case LC_LINK:
878 inlink(fields, nfields);
879 wantcont = FALSE;
880 break;
881 #ifdef LEAPSECOND_SUPPORT
882 case LC_LEAP:
883 if (name != leapsec)
884 (void) fprintf(stderr, gettext(
885 "%s: Leap line in non leap seconds file %s\n"),
886 progname, name);
887 else inleap(fields, nfields);
888 wantcont = FALSE;
889 break;
890 #endif /* LEAPSECOND_SUPPORT */
891 default: /* "cannot happen" */
892 (void) fprintf(stderr, gettext(
893 "%s: panic: Invalid l_value %d\n"),
894 progname, lp->l_value);
895 exit(EXIT_FAILURE);
898 ifree((char *)fields);
900 if (ferror(fp)) {
901 (void) fprintf(stderr, gettext("%s: Error reading %s\n"),
902 progname, filename);
903 exit(EXIT_FAILURE);
905 if (fp != stdin && fclose(fp)) {
906 const char *e = strerror(errno);
907 (void) fprintf(stderr, gettext("%s: Error closing %s: %s\n"),
908 progname, filename, e);
909 exit(EXIT_FAILURE);
911 if (wantcont)
912 error(gettext("expected continuation line not found"));
916 * Convert a string of one of the forms
917 * h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
918 * into a number of seconds.
919 * A null string maps to zero.
920 * Call error with errstring and return zero on errors.
923 static long
924 gethms(string, errstring, signable)
925 const char *string;
926 const char * const errstring;
927 const int signable;
929 long hh;
930 int mm, ss, sign;
932 if (string == NULL || *string == '\0')
933 return (0);
934 if (!signable)
935 sign = 1;
936 else if (*string == '-') {
937 sign = -1;
938 ++string;
939 } else sign = 1;
940 if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
941 mm = ss = 0;
942 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
943 ss = 0;
944 else if (sscanf(string, scheck(string, "%ld:%d:%d"),
945 &hh, &mm, &ss) != 3) {
946 error(errstring);
947 return (0);
949 if (hh < 0 ||
950 mm < 0 || mm >= MINSPERHOUR ||
951 ss < 0 || ss > SECSPERMIN) {
952 error(errstring);
953 return (0);
955 if (LONG_MAX / SECSPERHOUR < hh) {
956 error(gettext("time overflow"));
957 return (0);
959 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
960 warning(
961 gettext("24:00 not handled by pre-1998 versions of zic"));
962 if (noise && (hh > HOURSPERDAY ||
963 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
964 warning(gettext("values over 24 hours not handled by "
965 "pre-2007 versions of zic"));
967 return (oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
968 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))));
971 static void
972 inrule(fields, nfields)
973 register char ** const fields;
974 const int nfields;
976 static struct rule r;
978 if (nfields != RULE_FIELDS) {
979 error(gettext("wrong number of fields on Rule line"));
980 return;
982 if (*fields[RF_NAME] == '\0') {
983 error(gettext("nameless rule"));
984 return;
986 r.r_filename = filename;
987 r.r_linenum = linenum;
988 r.r_stdoff = gethms(fields[RF_STDOFF], gettext("invalid saved time"),
989 TRUE);
990 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
991 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
992 r.r_name = ecpyalloc(fields[RF_NAME]);
993 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
994 rules = (struct rule *)(void *)erealloc((char *)rules,
995 (int)((nrules + 1) * sizeof (*rules)));
996 rules[nrules++] = r;
999 static int
1000 inzone(fields, nfields)
1001 register char ** const fields;
1002 const int nfields;
1004 register int i;
1005 static char *buf;
1007 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1008 error(gettext("wrong number of fields on Zone line"));
1009 return (FALSE);
1011 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1012 buf = erealloc(buf, (int)(132 + strlen(TZDEFAULT)));
1013 (void) sprintf(buf,
1014 gettext("\"Zone %s\" line and -l option are mutually exclusive"),
1015 TZDEFAULT);
1016 error(buf);
1017 return (FALSE);
1019 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1020 buf = erealloc(buf, (int)(132 + strlen(TZDEFRULES)));
1021 (void) sprintf(buf,
1022 gettext("\"Zone %s\" line and -p option are mutually exclusive"),
1023 TZDEFRULES);
1024 error(buf);
1025 return (FALSE);
1027 for (i = 0; i < nzones; ++i)
1028 if (zones[i].z_name != NULL &&
1029 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1030 buf = erealloc(buf, (int)(132 +
1031 strlen(fields[ZF_NAME]) +
1032 strlen(zones[i].z_filename)));
1033 (void) sprintf(buf,
1034 gettext("duplicate zone name %s (file \"%s\", line %d)"),
1035 fields[ZF_NAME],
1036 zones[i].z_filename,
1037 zones[i].z_linenum);
1038 error(buf);
1039 return (FALSE);
1041 return (inzsub(fields, nfields, FALSE));
1044 static int
1045 inzcont(fields, nfields)
1046 register char ** const fields;
1047 const int nfields;
1049 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1050 error(gettext(
1051 "wrong number of fields on Zone continuation line"));
1052 return (FALSE);
1054 return (inzsub(fields, nfields, TRUE));
1057 static int
1058 inzsub(fields, nfields, iscont)
1059 register char ** const fields;
1060 const int nfields;
1061 const int iscont;
1063 register char *cp;
1064 static struct zone z;
1065 register int i_gmtoff, i_rule, i_format;
1066 register int i_untilyear, i_untilmonth;
1067 register int i_untilday, i_untiltime;
1068 register int hasuntil;
1070 if (iscont) {
1071 i_gmtoff = ZFC_GMTOFF;
1072 i_rule = ZFC_RULE;
1073 i_format = ZFC_FORMAT;
1074 i_untilyear = ZFC_TILYEAR;
1075 i_untilmonth = ZFC_TILMONTH;
1076 i_untilday = ZFC_TILDAY;
1077 i_untiltime = ZFC_TILTIME;
1078 z.z_name = NULL;
1079 } else {
1080 i_gmtoff = ZF_GMTOFF;
1081 i_rule = ZF_RULE;
1082 i_format = ZF_FORMAT;
1083 i_untilyear = ZF_TILYEAR;
1084 i_untilmonth = ZF_TILMONTH;
1085 i_untilday = ZF_TILDAY;
1086 i_untiltime = ZF_TILTIME;
1087 z.z_name = ecpyalloc(fields[ZF_NAME]);
1089 z.z_filename = filename;
1090 z.z_linenum = linenum;
1091 z.z_gmtoff = gethms(fields[i_gmtoff], gettext("invalid UTC offset"),
1092 TRUE);
1093 if ((cp = strchr(fields[i_format], '%')) != 0) {
1094 if (*++cp != 's' || strchr(cp, '%') != 0) {
1095 error(gettext("invalid abbreviation format"));
1096 return (FALSE);
1099 z.z_rule = ecpyalloc(fields[i_rule]);
1100 z.z_format = ecpyalloc(fields[i_format]);
1101 hasuntil = nfields > i_untilyear;
1102 if (hasuntil) {
1103 z.z_untilrule.r_filename = filename;
1104 z.z_untilrule.r_linenum = linenum;
1105 rulesub(&z.z_untilrule,
1106 fields[i_untilyear],
1107 "only",
1109 (nfields > i_untilmonth) ?
1110 fields[i_untilmonth] : "Jan",
1111 (nfields > i_untilday) ? fields[i_untilday] : "1",
1112 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1113 z.z_untiltime = rpytime(&z.z_untilrule,
1114 z.z_untilrule.r_loyear);
1115 if (iscont && nzones > 0 &&
1116 z.z_untiltime > min_time &&
1117 z.z_untiltime < max_time &&
1118 zones[nzones - 1].z_untiltime > min_time &&
1119 zones[nzones - 1].z_untiltime < max_time &&
1120 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1121 error(gettext(
1122 "Zone continuation line end time is not after end time of previous line"));
1123 return (FALSE);
1126 zones = (struct zone *)(void *)erealloc((char *)zones,
1127 (int)((nzones + 1) * sizeof (*zones)));
1128 zones[nzones++] = z;
1130 * If there was an UNTIL field on this line,
1131 * there's more information about the zone on the next line.
1133 return (hasuntil);
1136 #ifdef LEAPSECOND_SUPPORT
1137 static void
1138 inleap(fields, nfields)
1139 register char ** const fields;
1140 const int nfields;
1142 register const char *cp;
1143 register const struct lookup *lp;
1144 register int i, j;
1145 int year, month, day;
1146 long dayoff, tod;
1147 zic_t t;
1149 if (nfields != LEAP_FIELDS) {
1150 error(gettext("wrong number of fields on Leap line"));
1151 return;
1153 dayoff = 0;
1154 cp = fields[LP_YEAR];
1155 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1157 * Leapin' Lizards!
1159 error(gettext("invalid leaping year"));
1160 return;
1162 j = EPOCH_YEAR;
1163 while (j != year) {
1164 if (year > j) {
1165 i = len_years[isleap(j)];
1166 ++j;
1167 } else {
1168 --j;
1169 i = -len_years[isleap(j)];
1171 dayoff = oadd(dayoff, eitol(i));
1173 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1174 error(gettext("invalid month name"));
1175 return;
1177 month = lp->l_value;
1178 j = TM_JANUARY;
1179 while (j != month) {
1180 i = len_months[isleap(year)][j];
1181 dayoff = oadd(dayoff, eitol(i));
1182 ++j;
1184 cp = fields[LP_DAY];
1185 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1186 day <= 0 || day > len_months[isleap(year)][month]) {
1187 error(gettext("invalid day of month"));
1188 return;
1190 dayoff = oadd(dayoff, eitol(day - 1));
1191 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1192 error(gettext("time before zero"));
1193 return;
1195 if (dayoff < min_time / SECSPERDAY) {
1196 error(gettext("time too small"));
1197 return;
1199 if (dayoff > max_time / SECSPERDAY) {
1200 error(gettext("time too large"));
1201 return;
1203 t = (zic_t)dayoff * SECSPERDAY;
1204 tod = gethms(fields[LP_TIME], gettext("invalid time of day"), FALSE);
1205 cp = fields[LP_CORR];
1207 register int positive;
1208 int count;
1210 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1211 positive = FALSE;
1212 count = 1;
1213 } else if (strcmp(cp, "--") == 0) {
1214 positive = FALSE;
1215 count = 2;
1216 } else if (strcmp(cp, "+") == 0) {
1217 positive = TRUE;
1218 count = 1;
1219 } else if (strcmp(cp, "++") == 0) {
1220 positive = TRUE;
1221 count = 2;
1222 } else {
1223 error(gettext("illegal CORRECTION field on Leap line"));
1224 return;
1226 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1227 error(gettext(
1228 "illegal Rolling/Stationary field on Leap line"));
1229 return;
1231 leapadd(tadd(t, tod), positive, lp->l_value, count);
1234 #endif /* LEAPSECOND_SUPPORT */
1236 static void
1237 inlink(fields, nfields)
1238 register char ** const fields;
1239 const int nfields;
1241 struct link l;
1243 if (nfields != LINK_FIELDS) {
1244 error(gettext("wrong number of fields on Link line"));
1245 return;
1247 if (*fields[LF_FROM] == '\0') {
1248 error(gettext("blank FROM field on Link line"));
1249 return;
1251 if (*fields[LF_TO] == '\0') {
1252 error(gettext("blank TO field on Link line"));
1253 return;
1255 l.l_filename = filename;
1256 l.l_linenum = linenum;
1257 l.l_from = ecpyalloc(fields[LF_FROM]);
1258 l.l_to = ecpyalloc(fields[LF_TO]);
1259 links = (struct link *)(void *)erealloc((char *)links,
1260 (int)((nlinks + 1) * sizeof (*links)));
1261 links[nlinks++] = l;
1264 static void
1265 rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1266 register struct rule * const rp;
1267 const char * const loyearp;
1268 const char * const hiyearp;
1269 const char * const typep;
1270 const char * const monthp;
1271 const char * const dayp;
1272 const char * const timep;
1274 register const struct lookup *lp;
1275 register const char *cp;
1276 register char *dp;
1277 register char *ep;
1279 if ((lp = byword(monthp, mon_names)) == NULL) {
1280 error(gettext("invalid month name"));
1281 return;
1283 rp->r_month = lp->l_value;
1284 rp->r_todisstd = FALSE;
1285 rp->r_todisgmt = FALSE;
1286 dp = ecpyalloc(timep);
1287 if (*dp != '\0') {
1288 ep = dp + strlen(dp) - 1;
1289 switch (lowerit(*ep)) {
1290 case 's': /* Standard */
1291 rp->r_todisstd = TRUE;
1292 rp->r_todisgmt = FALSE;
1293 *ep = '\0';
1294 break;
1295 case 'w': /* Wall */
1296 rp->r_todisstd = FALSE;
1297 rp->r_todisgmt = FALSE;
1298 *ep = '\0';
1299 break;
1300 case 'g': /* Greenwich */
1301 case 'u': /* Universal */
1302 case 'z': /* Zulu */
1303 rp->r_todisstd = TRUE;
1304 rp->r_todisgmt = TRUE;
1305 *ep = '\0';
1306 break;
1309 rp->r_tod = gethms(dp, gettext("invalid time of day"), FALSE);
1310 ifree(dp);
1312 * Year work.
1314 cp = loyearp;
1315 lp = byword(cp, begin_years);
1316 if (lp != NULL) {
1317 switch ((int)lp->l_value) {
1318 case YR_MINIMUM:
1319 rp->r_loyear = INT_MIN;
1320 break;
1321 case YR_MAXIMUM:
1322 rp->r_loyear = INT_MAX;
1323 break;
1324 default: /* "cannot happen" */
1325 (void) fprintf(stderr,
1326 gettext("%s: panic: Invalid l_value %d\n"),
1327 progname, lp->l_value);
1328 exit(EXIT_FAILURE);
1330 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1331 error(gettext("invalid starting year"));
1332 return;
1333 } else if (noise) {
1334 if (rp->r_loyear < min_year_representable)
1335 warning(gettext(
1336 "starting year too low to be represented"));
1337 else if (rp->r_loyear > max_year_representable)
1338 warning(gettext(
1339 "starting year too high to be represented"));
1341 cp = hiyearp;
1342 if ((lp = byword(cp, end_years)) != NULL) {
1343 switch ((int)lp->l_value) {
1344 case YR_MINIMUM:
1345 rp->r_hiyear = INT_MIN;
1346 break;
1347 case YR_MAXIMUM:
1348 rp->r_hiyear = INT_MAX;
1349 break;
1350 case YR_ONLY:
1351 rp->r_hiyear = rp->r_loyear;
1352 break;
1353 default: /* "cannot happen" */
1354 (void) fprintf(stderr,
1355 gettext("%s: panic: Invalid l_value %d\n"),
1356 progname, lp->l_value);
1357 exit(EXIT_FAILURE);
1359 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1360 error(gettext("invalid ending year"));
1361 return;
1362 } else if (noise) {
1363 if (rp->r_loyear < min_year_representable)
1364 warning(gettext(
1365 "ending year too low to be represented"));
1366 else if (rp->r_loyear > max_year_representable)
1367 warning(gettext(
1368 "ending year too high to be represented"));
1370 if (rp->r_loyear > rp->r_hiyear) {
1371 error(gettext("starting year greater than ending year"));
1372 return;
1374 if (*typep == '\0')
1375 rp->r_yrtype = NULL;
1376 else {
1377 if (rp->r_loyear == rp->r_hiyear) {
1378 error(gettext("typed single year"));
1379 return;
1381 rp->r_yrtype = ecpyalloc(typep);
1383 if (rp->r_loyear < min_year && rp->r_loyear > 0)
1384 min_year = rp->r_loyear;
1386 * Day work.
1387 * Accept things such as:
1389 * last-Sunday
1390 * Sun<=20
1391 * Sun>=7
1393 dp = ecpyalloc(dayp);
1394 if ((lp = byword(dp, lasts)) != NULL) {
1395 rp->r_dycode = DC_DOWLEQ;
1396 rp->r_wday = lp->l_value;
1397 rp->r_dayofmonth = len_months[1][rp->r_month];
1398 } else {
1399 if ((ep = strchr(dp, '<')) != 0)
1400 rp->r_dycode = DC_DOWLEQ;
1401 else if ((ep = strchr(dp, '>')) != 0)
1402 rp->r_dycode = DC_DOWGEQ;
1403 else {
1404 ep = dp;
1405 rp->r_dycode = DC_DOM;
1407 if (rp->r_dycode != DC_DOM) {
1408 *ep++ = 0;
1409 if (*ep++ != '=') {
1410 error(gettext("invalid day of month"));
1411 ifree(dp);
1412 return;
1414 if ((lp = byword(dp, wday_names)) == NULL) {
1415 error(gettext("invalid weekday name"));
1416 ifree(dp);
1417 return;
1419 rp->r_wday = lp->l_value;
1421 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1422 rp->r_dayofmonth <= 0 ||
1423 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1424 error(gettext("invalid day of month"));
1425 ifree(dp);
1426 return;
1429 ifree(dp);
1432 static void
1433 convert(val, buf)
1434 const long val;
1435 char * const buf;
1437 register int i;
1438 register long shift;
1440 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1441 buf[i] = val >> shift;
1444 static void
1445 puttzcode(val, fp)
1446 const long val;
1447 FILE * const fp;
1449 char buf[4];
1451 convert(val, buf);
1452 (void) fwrite((void *)buf, (size_t)sizeof (buf), (size_t)1, fp);
1455 static int
1456 atcomp(avp, bvp)
1457 const void *avp;
1458 const void *bvp;
1460 if (((struct attype *)avp)->at < ((struct attype *)bvp)->at)
1461 return (-1);
1462 else if (((struct attype *)avp)->at > ((struct attype *)bvp)->at)
1463 return (1);
1464 else return (0);
1467 static void
1468 writezone(name)
1469 const char * const name;
1471 register FILE *fp;
1472 register int i, j;
1473 static char *fullname;
1474 static struct tzhead tzh;
1475 zic_t ats[TZ_MAX_TIMES];
1476 unsigned char types[TZ_MAX_TIMES];
1479 * Sort.
1481 if (timecnt > 1)
1482 (void) qsort((void *)attypes, (size_t)timecnt,
1483 (size_t)sizeof (*attypes), atcomp);
1485 * Optimize.
1488 int fromi;
1489 int toi;
1491 toi = 0;
1492 fromi = 0;
1493 while (fromi < timecnt && attypes[fromi].at < min_time)
1494 ++fromi;
1495 if (isdsts[0] == 0)
1496 while (fromi < timecnt && attypes[fromi].type == 0)
1497 ++fromi; /* handled by default rule */
1498 for (; fromi < timecnt; ++fromi) {
1499 if (toi != 0 && ((attypes[fromi].at +
1500 gmtoffs[attypes[toi - 1].type]) <=
1501 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1502 : attypes[toi - 2].type]))) {
1503 attypes[toi - 1].type =
1504 attypes[fromi].type;
1505 continue;
1507 if (toi == 0 ||
1508 attypes[toi - 1].type != attypes[fromi].type)
1509 attypes[toi++] = attypes[fromi];
1511 timecnt = toi;
1514 * Transfer.
1516 for (i = 0; i < timecnt; ++i) {
1517 ats[i] = attypes[i].at;
1518 types[i] = attypes[i].type;
1520 fullname = erealloc(fullname,
1521 (int)(strlen(directory) + 1 + strlen(name) + 1));
1522 (void) sprintf(fullname, "%s/%s", directory, name);
1524 * Remove old file, if any, to snap links.
1526 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
1527 const char *e = strerror(errno);
1529 (void) fprintf(stderr, gettext("%s: Can't remove %s: %s\n"),
1530 progname, fullname, e);
1531 exit(EXIT_FAILURE);
1533 if ((fp = fopen(fullname, "wb")) == NULL) {
1534 if (mkdirs(fullname) != 0)
1535 exit(EXIT_FAILURE);
1536 if ((fp = fopen(fullname, "wb")) == NULL) {
1537 const char *e = strerror(errno);
1538 (void) fprintf(stderr, gettext(
1539 "%s: Can't create %s: %s\n"),
1540 progname, fullname, e);
1541 exit(EXIT_FAILURE);
1544 convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
1545 convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
1546 convert(eitol(leapcnt), tzh.tzh_leapcnt);
1547 convert(eitol(timecnt), tzh.tzh_timecnt);
1548 convert(eitol(typecnt), tzh.tzh_typecnt);
1549 convert(eitol(charcnt), tzh.tzh_charcnt);
1550 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof (tzh.tzh_magic));
1551 #define DO(field) (void) fwrite((void *) tzh.field, \
1552 (size_t)sizeof (tzh.field), (size_t)1, fp)
1553 DO(tzh_magic);
1554 DO(tzh_reserved);
1555 DO(tzh_ttisgmtcnt);
1556 DO(tzh_ttisstdcnt);
1557 DO(tzh_leapcnt);
1558 DO(tzh_timecnt);
1559 DO(tzh_typecnt);
1560 DO(tzh_charcnt);
1561 #undef DO
1562 for (i = 0; i < timecnt; ++i) {
1563 j = leapcnt;
1564 while (--j >= 0)
1565 if (ats[i] >= trans[j]) {
1566 ats[i] = tadd(ats[i], corr[j]);
1567 break;
1569 puttzcode((long)ats[i], fp);
1571 if (timecnt > 0)
1572 (void) fwrite((void *)types, (size_t)sizeof (types[0]),
1573 (size_t)timecnt, fp);
1574 for (i = 0; i < typecnt; ++i) {
1575 puttzcode((long)gmtoffs[i], fp);
1576 (void) putc(isdsts[i], fp);
1577 (void) putc(abbrinds[i], fp);
1579 if (charcnt != 0)
1580 (void) fwrite((void *)chars, (size_t)sizeof (chars[0]),
1581 (size_t)charcnt, fp);
1582 for (i = 0; i < leapcnt; ++i) {
1583 if (roll[i]) {
1584 if (timecnt == 0 || trans[i] < ats[0]) {
1585 j = 0;
1586 while (isdsts[j])
1587 if (++j >= typecnt) {
1588 j = 0;
1589 break;
1591 } else {
1592 j = 1;
1593 while (j < timecnt && trans[i] >= ats[j])
1594 ++j;
1595 j = types[j - 1];
1597 puttzcode((long)tadd(trans[i], -gmtoffs[j]), fp);
1598 } else puttzcode((long)trans[i], fp);
1599 puttzcode((long)corr[i], fp);
1601 for (i = 0; i < typecnt; ++i)
1602 (void) putc(ttisstds[i], fp);
1603 for (i = 0; i < typecnt; ++i)
1604 (void) putc(ttisgmts[i], fp);
1605 if (ferror(fp) || fclose(fp)) {
1606 (void) fprintf(stderr, gettext("%s: Error writing %s\n"),
1607 progname, fullname);
1608 exit(EXIT_FAILURE);
1612 static void
1613 doabbr(abbr, format, letters, isdst)
1614 char * const abbr;
1615 const char * const format;
1616 const char * const letters;
1617 const int isdst;
1619 if (strchr(format, '/') == NULL) {
1620 if (letters == NULL)
1621 (void) strcpy(abbr, format);
1622 else
1623 (void) sprintf(abbr, format, letters);
1624 } else if (isdst)
1625 (void) strcpy(abbr, strchr(format, '/') + 1);
1626 else {
1627 (void) strcpy(abbr, format);
1628 *strchr(abbr, '/') = '\0';
1632 static void
1633 outzone(zpfirst, zonecount)
1634 const struct zone * const zpfirst;
1635 const int zonecount;
1637 register const struct zone *zp;
1638 register struct rule *rp;
1639 register int i, j;
1640 register int usestart, useuntil;
1641 register zic_t starttime, untiltime;
1642 register long gmtoff;
1643 register long stdoff;
1644 register int year;
1645 register long startoff;
1646 register int startttisstd;
1647 register int startttisgmt;
1648 register int type;
1649 char startbuf[BUFSIZ];
1651 INITIALIZE(untiltime);
1652 INITIALIZE(starttime);
1654 * Now. . .finally. . .generate some useful data!
1656 timecnt = 0;
1657 typecnt = 0;
1658 charcnt = 0;
1660 * Thanks to Earl Chew
1661 * for noting the need to unconditionally initialize startttisstd.
1663 startttisstd = FALSE;
1664 startttisgmt = FALSE;
1665 for (i = 0; i < zonecount; ++i) {
1667 * A guess that may well be corrected later.
1669 stdoff = 0;
1670 zp = &zpfirst[i];
1671 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
1672 useuntil = i < (zonecount - 1);
1673 if (useuntil && zp->z_untiltime <= min_time)
1674 continue;
1675 gmtoff = zp->z_gmtoff;
1676 eat(zp->z_filename, zp->z_linenum);
1677 *startbuf = '\0';
1678 startoff = zp->z_gmtoff;
1679 if (zp->z_nrules == 0) {
1680 stdoff = zp->z_stdoff;
1681 doabbr(startbuf, zp->z_format,
1682 (char *)NULL, stdoff != 0);
1683 type = addtype(oadd(zp->z_gmtoff, stdoff),
1684 startbuf, stdoff != 0, startttisstd,
1685 startttisgmt);
1686 if (usestart) {
1687 addtt(starttime, type);
1688 usestart = FALSE;
1689 } else if (stdoff != 0)
1690 addtt(min_time, type);
1691 } else
1692 for (year = min_year; year <= max_year; ++year) {
1693 if (useuntil && year > zp->z_untilrule.r_hiyear)
1694 break;
1696 * Mark which rules to do in the current year.
1697 * For those to do, calculate rpytime(rp, year);
1699 for (j = 0; j < zp->z_nrules; ++j) {
1700 rp = &zp->z_rules[j];
1701 eats(zp->z_filename, zp->z_linenum,
1702 rp->r_filename, rp->r_linenum);
1703 rp->r_todo = year >= rp->r_loyear &&
1704 year <= rp->r_hiyear &&
1705 yearistype(year, rp->r_yrtype);
1706 if (rp->r_todo)
1707 rp->r_temp = rpytime(rp, year);
1709 for (;;) {
1710 register int k;
1711 register zic_t jtime, ktime;
1712 register long offset;
1713 char buf[BUFSIZ];
1715 INITIALIZE(ktime);
1716 if (useuntil) {
1718 * Turn untiltime into UTC * assuming
1719 * the current gmtoff and stdoff values.
1721 untiltime = zp->z_untiltime;
1722 if (!zp->z_untilrule.r_todisgmt)
1723 untiltime = tadd(untiltime,
1724 -gmtoff);
1725 if (!zp->z_untilrule.r_todisstd)
1726 untiltime = tadd(untiltime,
1727 -stdoff);
1730 * Find the rule (of those to do, if any)
1731 * that takes effect earliest in the year.
1733 k = -1;
1734 for (j = 0; j < zp->z_nrules; ++j) {
1735 rp = &zp->z_rules[j];
1736 if (!rp->r_todo)
1737 continue;
1738 eats(zp->z_filename, zp->z_linenum,
1739 rp->r_filename, rp->r_linenum);
1740 offset = rp->r_todisgmt ? 0 : gmtoff;
1741 if (!rp->r_todisstd)
1742 offset = oadd(offset, stdoff);
1743 jtime = rp->r_temp;
1744 if (jtime == min_time ||
1745 jtime == max_time)
1746 continue;
1747 jtime = tadd(jtime, -offset);
1748 if (k < 0 || jtime < ktime) {
1749 k = j;
1750 ktime = jtime;
1753 if (k < 0)
1754 break; /* go on to next year */
1755 rp = &zp->z_rules[k];
1756 rp->r_todo = FALSE;
1757 if (useuntil && ktime >= untiltime)
1758 break;
1759 stdoff = rp->r_stdoff;
1760 if (usestart && ktime == starttime)
1761 usestart = FALSE;
1762 if (usestart) {
1763 if (ktime < starttime) {
1764 startoff = oadd(zp->z_gmtoff,
1765 stdoff);
1766 doabbr(startbuf, zp->z_format,
1767 rp->r_abbrvar,
1768 rp->r_stdoff != 0);
1769 continue;
1771 if (*startbuf == '\0' &&
1772 startoff == oadd(zp->z_gmtoff,
1773 stdoff)) {
1774 doabbr(startbuf, zp->z_format,
1775 rp->r_abbrvar,
1776 rp->r_stdoff != 0);
1779 eats(zp->z_filename, zp->z_linenum,
1780 rp->r_filename, rp->r_linenum);
1781 doabbr(buf, zp->z_format, rp->r_abbrvar,
1782 rp->r_stdoff != 0);
1783 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1784 type = addtype(offset, buf, rp->r_stdoff != 0,
1785 rp->r_todisstd, rp->r_todisgmt);
1786 addtt(ktime, type);
1789 if (usestart) {
1790 if (*startbuf == '\0' &&
1791 zp->z_format != NULL &&
1792 strchr(zp->z_format, '%') == NULL &&
1793 strchr(zp->z_format, '/') == NULL)
1794 (void) strcpy(startbuf, zp->z_format);
1795 eat(zp->z_filename, zp->z_linenum);
1796 if (*startbuf == '\0')
1797 error(gettext(
1798 "can't determine time zone abbrevation to use just after until time"));
1799 else addtt(starttime,
1800 addtype(startoff, startbuf,
1801 startoff != zp->z_gmtoff,
1802 startttisstd,
1803 startttisgmt));
1806 * Now we may get to set starttime for the next zone line.
1808 if (useuntil) {
1809 startttisstd = zp->z_untilrule.r_todisstd;
1810 startttisgmt = zp->z_untilrule.r_todisgmt;
1811 starttime = zp->z_untiltime;
1812 if (!startttisstd)
1813 starttime = tadd(starttime, -stdoff);
1814 if (!startttisgmt)
1815 starttime = tadd(starttime, -gmtoff);
1818 writezone(zpfirst->z_name);
1821 static void
1822 addtt(starttime, type)
1823 const zic_t starttime;
1824 int type;
1826 if (starttime <= min_time ||
1827 (timecnt == 1 && attypes[0].at < min_time)) {
1828 gmtoffs[0] = gmtoffs[type];
1829 isdsts[0] = isdsts[type];
1830 ttisstds[0] = ttisstds[type];
1831 ttisgmts[0] = ttisgmts[type];
1832 if (abbrinds[type] != 0)
1833 (void) strcpy(chars, &chars[abbrinds[type]]);
1834 abbrinds[0] = 0;
1835 charcnt = strlen(chars) + 1;
1836 typecnt = 1;
1837 timecnt = 0;
1838 type = 0;
1840 if (timecnt >= TZ_MAX_TIMES) {
1841 error(gettext("too many transitions?!"));
1842 exit(EXIT_FAILURE);
1844 attypes[timecnt].at = starttime;
1845 attypes[timecnt].type = type;
1846 ++timecnt;
1849 static int
1850 addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
1851 const long gmtoff;
1852 const char * const abbr;
1853 const int isdst;
1854 const int ttisstd;
1855 const int ttisgmt;
1857 register int i, j;
1859 if (isdst != TRUE && isdst != FALSE) {
1860 error(gettext(
1861 "internal error - addtype called with bad isdst"));
1862 exit(EXIT_FAILURE);
1864 if (ttisstd != TRUE && ttisstd != FALSE) {
1865 error(gettext(
1866 "internal error - addtype called with bad ttisstd"));
1867 exit(EXIT_FAILURE);
1869 if (ttisgmt != TRUE && ttisgmt != FALSE) {
1870 error(gettext(
1871 "internal error - addtype called with bad ttisgmt"));
1872 exit(EXIT_FAILURE);
1875 * See if there's already an entry for this zone type.
1876 * If so, just return its index.
1878 for (i = 0; i < typecnt; ++i) {
1879 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1880 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
1881 ttisstd == ttisstds[i] &&
1882 ttisgmt == ttisgmts[i])
1883 return (i);
1886 * There isn't one; add a new one, unless there are already too
1887 * many.
1889 if (typecnt >= TZ_MAX_TYPES) {
1890 error(gettext("too many local time types"));
1891 exit(EXIT_FAILURE);
1893 if (!(-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
1894 error(gettext("UTC offset out of range"));
1895 exit(EXIT_FAILURE);
1897 gmtoffs[i] = gmtoff;
1898 isdsts[i] = isdst;
1899 ttisstds[i] = ttisstd;
1900 ttisgmts[i] = ttisgmt;
1902 for (j = 0; j < charcnt; ++j)
1903 if (strcmp(&chars[j], abbr) == 0)
1904 break;
1905 if (j == charcnt)
1906 newabbr(abbr);
1907 abbrinds[i] = j;
1908 ++typecnt;
1909 return (i);
1912 #ifdef LEAPSECOND_SUPPORT
1913 static void
1914 leapadd(t, positive, rolling, count)
1915 const zic_t t;
1916 const int positive;
1917 const int rolling;
1918 int count;
1920 register int i, j;
1922 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
1923 error(gettext("too many leap seconds"));
1924 exit(EXIT_FAILURE);
1926 for (i = 0; i < leapcnt; ++i)
1927 if (t <= trans[i]) {
1928 if (t == trans[i]) {
1929 error(gettext("repeated leap second moment"));
1930 exit(EXIT_FAILURE);
1932 break;
1934 do {
1935 for (j = leapcnt; j > i; --j) {
1936 trans[j] = trans[j - 1];
1937 corr[j] = corr[j - 1];
1938 roll[j] = roll[j - 1];
1940 trans[i] = t;
1941 corr[i] = positive ? 1L : eitol(-count);
1942 roll[i] = rolling;
1943 ++leapcnt;
1944 } while (positive && --count != 0);
1946 #endif /* LEAPSECOND_SUPPORT */
1948 #ifdef LEAPSECOND_SUPPORT
1949 static void
1950 adjleap(void)
1952 register int i;
1953 register long last = 0;
1956 * propagate leap seconds forward
1958 for (i = 0; i < leapcnt; ++i) {
1959 trans[i] = tadd(trans[i], last);
1960 last = corr[i] += last;
1963 #endif /* LEAPSECOND_SUPPORT */
1965 static int
1966 yearistype(year, type)
1967 const int year;
1968 const char * const type;
1970 static char *buf;
1971 int result;
1973 if (type == NULL || *type == '\0')
1974 return (TRUE);
1975 #if defined(sun)
1976 if (strcmp(type, "uspres") == 0)
1977 return ((year % 4) == 0);
1978 if (strcmp(type, "nonpres") == 0)
1979 return ((year % 4) != 0);
1980 if (strcmp(type, "even") == 0)
1981 return ((year % 2) == 0);
1982 if (strcmp(type, "odd") == 0)
1983 return ((year % 2) != 0);
1984 #endif /* defined(sun) */
1986 buf = erealloc(buf, (int)(132 + strlen(yitcommand) + strlen(type)));
1987 (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
1988 result = system(buf);
1989 if (WIFEXITED(result)) {
1990 switch (WEXITSTATUS(result)) {
1991 case 0:
1992 return (TRUE);
1993 case 1:
1994 return (FALSE);
1997 error(gettext("Wild result from command execution"));
1998 (void) fprintf(stderr, gettext("%s: command was '%s', result was %d\n"),
1999 progname, buf, result);
2000 for (;;)
2001 exit(EXIT_FAILURE);
2004 static int
2005 lowerit(a)
2006 int a;
2008 a = (unsigned char) a;
2009 return ((isascii(a) && isupper(a)) ? tolower(a) : a);
2012 static int
2013 ciequal(ap, bp) /* case-insensitive equality */
2014 register const char *ap;
2015 register const char *bp;
2017 while (lowerit(*ap) == lowerit(*bp++))
2018 if (*ap++ == '\0')
2019 return (TRUE);
2020 return (FALSE);
2023 static int
2024 itsabbr(abbr, word)
2025 register const char *abbr;
2026 register const char *word;
2028 if (lowerit(*abbr) != lowerit(*word))
2029 return (FALSE);
2030 ++word;
2031 while (*++abbr != '\0')
2032 do {
2033 if (*word == '\0')
2034 return (FALSE);
2035 } while (lowerit(*word++) != lowerit(*abbr));
2036 return (TRUE);
2039 static const struct lookup *
2040 byword(word, table)
2041 register const char * const word;
2042 register const struct lookup * const table;
2044 register const struct lookup *foundlp;
2045 register const struct lookup *lp;
2047 if (word == NULL || table == NULL)
2048 return (NULL);
2050 * Look for exact match.
2052 for (lp = table; lp->l_word != NULL; ++lp)
2053 if (ciequal(word, lp->l_word))
2054 return (lp);
2056 * Look for inexact match.
2058 foundlp = NULL;
2059 for (lp = table; lp->l_word != NULL; ++lp)
2060 if (itsabbr(word, lp->l_word)) {
2061 if (foundlp == NULL)
2062 foundlp = lp;
2063 else return (NULL); /* multiple inexact matches */
2065 return (foundlp);
2068 static char **
2069 getfields(cp)
2070 register char *cp;
2072 register char *dp;
2073 register char **array;
2074 register int nsubs;
2076 if (cp == NULL)
2077 return (NULL);
2078 array = (char **)(void *)
2079 emalloc((int)((strlen(cp) + 1) * sizeof (*array)));
2080 nsubs = 0;
2081 for (;;) {
2082 while (isascii(*cp) && isspace((unsigned char) *cp))
2083 ++cp;
2084 if (*cp == '\0' || *cp == '#')
2085 break;
2086 array[nsubs++] = dp = cp;
2087 do {
2088 if ((*dp = *cp++) != '"')
2089 ++dp;
2090 else while ((*dp = *cp++) != '"')
2091 if (*dp != '\0')
2092 ++dp;
2093 else {
2094 error(gettext(
2095 "Odd number of quotation marks"));
2096 exit(1);
2098 } while (*cp != '\0' && *cp != '#' &&
2099 (!isascii(*cp) || !isspace((unsigned char) *cp)));
2100 if (isascii(*cp) && isspace((unsigned char) *cp))
2101 ++cp;
2102 *dp = '\0';
2104 array[nsubs] = NULL;
2105 return (array);
2108 static long
2109 oadd(t1, t2)
2110 const long t1;
2111 const long t2;
2113 register long t;
2115 t = t1 + t2;
2116 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2117 error(gettext("time overflow"));
2118 exit(EXIT_FAILURE);
2120 return (t);
2123 static zic_t
2124 tadd(t1, t2)
2125 const zic_t t1;
2126 const long t2;
2128 register zic_t t;
2130 if (t1 == max_time && t2 > 0)
2131 return (max_time);
2132 if (t1 == min_time && t2 < 0)
2133 return (min_time);
2134 t = t1 + t2;
2135 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2136 error(gettext("time overflow"));
2137 exit(EXIT_FAILURE);
2139 return (t);
2143 * Given a rule, and a year, compute the date - in seconds since January 1,
2144 * 1970, 00:00 LOCAL time - in that year that the rule refers to.
2147 static zic_t
2148 rpytime(rp, wantedy)
2149 register const struct rule * const rp;
2150 register const int wantedy;
2152 register int y, m, i;
2153 register long dayoff; /* with a nod to Margaret O. */
2154 register zic_t t;
2156 if (wantedy == INT_MIN)
2157 return (min_time);
2158 if (wantedy == INT_MAX)
2159 return (max_time);
2160 dayoff = 0;
2161 m = TM_JANUARY;
2162 y = EPOCH_YEAR;
2163 while (wantedy != y) {
2164 if (wantedy > y) {
2165 i = len_years[isleap(y)];
2166 ++y;
2167 } else {
2168 --y;
2169 i = -len_years[isleap(y)];
2171 dayoff = oadd(dayoff, eitol(i));
2173 while (m != rp->r_month) {
2174 i = len_months[isleap(y)][m];
2175 dayoff = oadd(dayoff, eitol(i));
2176 ++m;
2178 i = rp->r_dayofmonth;
2179 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2180 if (rp->r_dycode == DC_DOWLEQ)
2181 --i;
2182 else {
2183 error(gettext("use of 2/29 in non leap-year"));
2184 exit(EXIT_FAILURE);
2187 --i;
2188 dayoff = oadd(dayoff, eitol(i));
2189 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2190 register long wday;
2192 #define LDAYSPERWEEK ((long)DAYSPERWEEK)
2193 wday = eitol(EPOCH_WDAY);
2195 * Don't trust mod of negative numbers.
2197 if (dayoff >= 0)
2198 wday = (wday + dayoff) % LDAYSPERWEEK;
2199 else {
2200 wday -= ((-dayoff) % LDAYSPERWEEK);
2201 if (wday < 0)
2202 wday += LDAYSPERWEEK;
2204 while (wday != eitol(rp->r_wday))
2205 if (rp->r_dycode == DC_DOWGEQ) {
2206 dayoff = oadd(dayoff, (long)1);
2207 if (++wday >= LDAYSPERWEEK)
2208 wday = 0;
2209 ++i;
2210 } else {
2211 dayoff = oadd(dayoff, (long)-1);
2212 if (--wday < 0)
2213 wday = LDAYSPERWEEK - 1;
2214 --i;
2216 if (i < 0 || i >= len_months[isleap(y)][m]) {
2217 if (noise)
2218 warning(gettext("rule goes past start/end of "
2219 "month--will not work with pre-2004 "
2220 "versions of zic"));
2223 if (dayoff < 0 && !TYPE_SIGNED(zic_t))
2224 return (min_time);
2225 if (dayoff < min_time / SECSPERDAY)
2226 return (min_time);
2227 if (dayoff > max_time / SECSPERDAY)
2228 return (max_time);
2229 t = (zic_t)dayoff * SECSPERDAY;
2230 return (tadd(t, rp->r_tod));
2233 static void
2234 newabbr(const char * const string)
2236 register int i;
2238 if (strcmp(string, GRANDPARENTED) != 0) {
2239 register const char *cp;
2240 register char *wp;
2242 cp = string;
2243 wp = NULL;
2244 while (isalpha(*cp) || ('0' <= *cp && *cp <= '9') ||
2245 *cp == '-' || *cp == '+') {
2246 ++cp;
2248 if (noise && cp - string < 3)
2249 wp = gettext(("time zone abbreviation has less than 3 "
2250 "alphabetics"));
2251 if (wp == NULL && cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2252 wp = gettext(("time zone abbreviation has too many "
2253 "characters"));
2254 if (wp == NULL && (*cp == '+' || *cp == '-')) {
2255 ++cp;
2256 if (isascii(*cp) && isdigit(*cp))
2257 if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
2258 ++cp;
2260 if (wp == NULL && *cp != '\0')
2261 wp = gettext("time zone abbreviation differs from "
2262 "POSIX standard");
2263 if (wp != NULL) {
2264 wp = ecpyalloc(wp);
2265 wp = ecatalloc(wp, " (");
2266 wp = ecatalloc(wp, string);
2267 wp = ecatalloc(wp, ")");
2268 warning(wp);
2269 ifree(wp);
2272 i = strlen(string) + 1;
2273 if (charcnt + i > TZ_MAX_CHARS) {
2274 error(gettext("too many, or too long, time zone "
2275 "abbreviations"));
2276 exit(EXIT_FAILURE);
2278 (void) strcpy(&chars[charcnt], string);
2279 charcnt += eitol(i);
2282 static int
2283 mkdirs(argname)
2284 char *argname;
2286 register char *name;
2287 register char *cp;
2289 if (argname == NULL || *argname == '\0')
2290 return (0);
2291 cp = name = ecpyalloc(argname);
2292 while ((cp = strchr(cp + 1, '/')) != 0) {
2293 *cp = '\0';
2294 if (!itsdir(name)) {
2296 * It doesn't seem to exist, so we try to create it.
2297 * Creation may fail because of the directory being
2298 * created by some other multiprocessor, so we get
2299 * to do extra checking.
2301 if (mkdir(name, MKDIR_UMASK) != 0) {
2302 const char *e = strerror(errno);
2304 if (errno != EEXIST || !itsdir(name)) {
2305 (void) fprintf(stderr, gettext(
2306 "%s: Can't create directory %s: %s\n"),
2307 progname, name, e);
2308 ifree(name);
2309 return (-1);
2313 *cp = '/';
2315 ifree(name);
2316 return (0);
2319 static long
2320 eitol(i)
2321 const int i;
2323 long l;
2325 l = i;
2326 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
2327 (void) fprintf(stderr,
2328 gettext("%s: %d did not sign extend correctly\n"),
2329 progname, i);
2330 exit(EXIT_FAILURE);
2332 return (l);
2336 * UNIX was a registered trademark of The Open Group in 2003.