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