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