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