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