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