Line data Source code
1 : /* Compile .zi time zone data into TZif binary files. */
2 :
3 : /*
4 : * This file is in the public domain, so clarified as of
5 : * 2006-07-17 by Arthur David Olson.
6 : *
7 : * IDENTIFICATION
8 : * src/timezone/zic.c
9 : */
10 :
11 : #include "postgres_fe.h"
12 :
13 : #include <fcntl.h>
14 : #include <sys/stat.h>
15 : #include <time.h>
16 :
17 : #include "pg_getopt.h"
18 :
19 : #include "private.h"
20 : #include "tzfile.h"
21 :
22 : #define ZIC_VERSION_PRE_2013 '2'
23 : #define ZIC_VERSION '3'
24 :
25 : typedef int_fast64_t zic_t;
26 : #define ZIC_MIN INT_FAST64_MIN
27 : #define ZIC_MAX INT_FAST64_MAX
28 : #define PRIdZIC PRIdFAST64
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 : #ifndef WIN32
36 : #ifdef S_IRUSR
37 : #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
38 : #else
39 : #define MKDIR_UMASK 0755
40 : #endif
41 : #endif
42 : /* Port to native MS-Windows and to ancient UNIX. */
43 : #if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT
44 : #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
45 : #endif
46 :
47 : /* The maximum ptrdiff_t value, for pre-C99 platforms. */
48 : #ifndef PTRDIFF_MAX
49 : static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
50 : #endif
51 :
52 : /* The minimum alignment of a type, for pre-C11 platforms. */
53 : #if __STDC_VERSION__ < 201112
54 : #define _Alignof(type) offsetof(struct { char a; type b; }, b)
55 : #endif
56 :
57 : /* The type for line numbers. Use PRIdMAX to format them; formerly
58 : there was also "#define PRIdLINENO PRIdMAX" and formats used
59 : PRIdLINENO, but xgettext cannot grok that. */
60 : typedef intmax_t lineno_t;
61 :
62 : struct rule
63 : {
64 : const char *r_filename;
65 : lineno_t r_linenum;
66 : const char *r_name;
67 :
68 : zic_t r_loyear; /* for example, 1986 */
69 : zic_t r_hiyear; /* for example, 1986 */
70 : bool r_lowasnum;
71 : bool r_hiwasnum;
72 :
73 : int r_month; /* 0..11 */
74 :
75 : int r_dycode; /* see below */
76 : int r_dayofmonth;
77 : int r_wday;
78 :
79 : zic_t r_tod; /* time from midnight */
80 : bool r_todisstd; /* is r_tod standard time? */
81 : bool r_todisut; /* is r_tod UT? */
82 : bool r_isdst; /* is this daylight saving time? */
83 : zic_t r_save; /* offset from standard time */
84 : const char *r_abbrvar; /* variable part of abbreviation */
85 :
86 : bool r_todo; /* a rule to do (used in outzone) */
87 : zic_t r_temp; /* used in outzone */
88 : };
89 :
90 : /*
91 : * r_dycode r_dayofmonth r_wday
92 : */
93 :
94 : #define DC_DOM 0 /* 1..31 */ /* unused */
95 : #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
96 : #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
97 :
98 : struct zone
99 : {
100 : const char *z_filename;
101 : lineno_t z_linenum;
102 :
103 : const char *z_name;
104 : zic_t z_stdoff;
105 : char *z_rule;
106 : const char *z_format;
107 : char z_format_specifier;
108 :
109 : bool z_isdst;
110 : zic_t z_save;
111 :
112 : struct rule *z_rules;
113 : ptrdiff_t z_nrules;
114 :
115 : struct rule z_untilrule;
116 : zic_t z_untiltime;
117 : };
118 :
119 : extern int link(const char *target, const char *linkname);
120 : #ifndef AT_SYMLINK_FOLLOW
121 : #define linkat(targetdir, target, linknamedir, linkname, flag) \
122 : (itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
123 : #endif
124 :
125 : static void verror(const char *const string, va_list args) pg_attribute_printf(1, 0);
126 : static void error(const char *const string,...) pg_attribute_printf(1, 2);
127 : static void warning(const char *const string,...) pg_attribute_printf(1, 2);
128 : static void addtt(zic_t starttime, int type);
129 : static int addtype(zic_t utoff, char const *abbr,
130 : bool isdst, bool ttisstd, bool ttisut);
131 : static void leapadd(zic_t t, int correction, int rolling);
132 : static void adjleap(void);
133 : static void associate(void);
134 : static void dolink(const char *target, const char *linkname,
135 : bool staysymlink);
136 : static char **getfields(char *cp);
137 : static zic_t gethms(const char *string, const char *errstring);
138 : static zic_t getsave(char *field, bool *isdst);
139 : static void inexpires(char **fields, int nfields);
140 : static void infile(const char *name);
141 : static void inleap(char **fields, int nfields);
142 : static void inlink(char **fields, int nfields);
143 : static void inrule(char **fields, int nfields);
144 : static bool inzcont(char **fields, int nfields);
145 : static bool inzone(char **fields, int nfields);
146 : static bool inzsub(char **fields, int nfields, bool iscont);
147 : static bool itsdir(char const *name);
148 : static bool itssymlink(char const *name);
149 : static bool is_alpha(char a);
150 : static char lowerit(char a);
151 : static void mkdirs(char const *argname, bool ancestors);
152 : static void newabbr(const char *string);
153 : static zic_t oadd(zic_t t1, zic_t t2);
154 : static void outzone(const struct zone *zpfirst, ptrdiff_t zonecount);
155 : static zic_t rpytime(const struct rule *rp, zic_t wantedy);
156 : static void rulesub(struct rule *rp,
157 : const char *loyearp, const char *hiyearp,
158 : const char *typep, const char *monthp,
159 : const char *dayp, const char *timep);
160 : static zic_t tadd(zic_t t1, zic_t t2);
161 :
162 : /* Bound on length of what %z can expand to. */
163 : enum
164 : {
165 : PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};
166 :
167 : /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
168 : TZif files whose POSIX-TZ-style strings contain '<'; see
169 : QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
170 : workaround will no longer be needed when Qt 5.6.1 and earlier are
171 : obsolete, say in the year 2021. */
172 : #ifndef WORK_AROUND_QTBUG_53071
173 : enum
174 : {
175 : WORK_AROUND_QTBUG_53071 = true};
176 : #endif
177 :
178 : static int charcnt;
179 : static bool errors;
180 : static bool warnings;
181 : static const char *filename;
182 : static int leapcnt;
183 : static bool leapseen;
184 : static zic_t leapminyear;
185 : static zic_t leapmaxyear;
186 : static lineno_t linenum;
187 : static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
188 : static int max_format_len;
189 : static zic_t max_year;
190 : static zic_t min_year;
191 : static bool noise;
192 : static bool print_abbrevs;
193 : static zic_t print_cutoff;
194 : static const char *rfilename;
195 : static lineno_t rlinenum;
196 : static const char *progname;
197 : static ptrdiff_t timecnt;
198 : static ptrdiff_t timecnt_alloc;
199 : static int typecnt;
200 :
201 : /*
202 : * Line codes.
203 : */
204 :
205 : #define LC_RULE 0
206 : #define LC_ZONE 1
207 : #define LC_LINK 2
208 : #define LC_LEAP 3
209 : #define LC_EXPIRES 4
210 :
211 : /*
212 : * Which fields are which on a Zone line.
213 : */
214 :
215 : #define ZF_NAME 1
216 : #define ZF_STDOFF 2
217 : #define ZF_RULE 3
218 : #define ZF_FORMAT 4
219 : #define ZF_TILYEAR 5
220 : #define ZF_TILMONTH 6
221 : #define ZF_TILDAY 7
222 : #define ZF_TILTIME 8
223 : #define ZONE_MINFIELDS 5
224 : #define ZONE_MAXFIELDS 9
225 :
226 : /*
227 : * Which fields are which on a Zone continuation line.
228 : */
229 :
230 : #define ZFC_STDOFF 0
231 : #define ZFC_RULE 1
232 : #define ZFC_FORMAT 2
233 : #define ZFC_TILYEAR 3
234 : #define ZFC_TILMONTH 4
235 : #define ZFC_TILDAY 5
236 : #define ZFC_TILTIME 6
237 : #define ZONEC_MINFIELDS 3
238 : #define ZONEC_MAXFIELDS 7
239 :
240 : /*
241 : * Which files are which on a Rule line.
242 : */
243 :
244 : #define RF_NAME 1
245 : #define RF_LOYEAR 2
246 : #define RF_HIYEAR 3
247 : #define RF_COMMAND 4
248 : #define RF_MONTH 5
249 : #define RF_DAY 6
250 : #define RF_TOD 7
251 : #define RF_SAVE 8
252 : #define RF_ABBRVAR 9
253 : #define RULE_FIELDS 10
254 :
255 : /*
256 : * Which fields are which on a Link line.
257 : */
258 :
259 : #define LF_TARGET 1
260 : #define LF_LINKNAME 2
261 : #define LINK_FIELDS 3
262 :
263 : /*
264 : * Which fields are which on a Leap line.
265 : */
266 :
267 : #define LP_YEAR 1
268 : #define LP_MONTH 2
269 : #define LP_DAY 3
270 : #define LP_TIME 4
271 : #define LP_CORR 5
272 : #define LP_ROLL 6
273 : #define LEAP_FIELDS 7
274 :
275 : /* Expires lines are like Leap lines, except without CORR and ROLL fields. */
276 : #define EXPIRES_FIELDS 5
277 :
278 : /*
279 : * Year synonyms.
280 : */
281 :
282 : #define YR_MINIMUM 0
283 : #define YR_MAXIMUM 1
284 : #define YR_ONLY 2
285 :
286 : static struct rule *rules;
287 : static ptrdiff_t nrules; /* number of rules */
288 : static ptrdiff_t nrules_alloc;
289 :
290 : static struct zone *zones;
291 : static ptrdiff_t nzones; /* number of zones */
292 : static ptrdiff_t nzones_alloc;
293 :
294 : struct link
295 : {
296 : const char *l_filename;
297 : lineno_t l_linenum;
298 : const char *l_target;
299 : const char *l_linkname;
300 : };
301 :
302 : static struct link *links;
303 : static ptrdiff_t nlinks;
304 : static ptrdiff_t nlinks_alloc;
305 :
306 : struct lookup
307 : {
308 : const char *l_word;
309 : const int l_value;
310 : };
311 :
312 : static struct lookup const *byword(const char *word,
313 : const struct lookup *table);
314 :
315 : static struct lookup const zi_line_codes[] = {
316 : {"Rule", LC_RULE},
317 : {"Zone", LC_ZONE},
318 : {"Link", LC_LINK},
319 : {NULL, 0}
320 : };
321 : static struct lookup const leap_line_codes[] = {
322 : {"Leap", LC_LEAP},
323 : {"Expires", LC_EXPIRES},
324 : {NULL, 0}
325 : };
326 :
327 : static struct lookup const mon_names[] = {
328 : {"January", TM_JANUARY},
329 : {"February", TM_FEBRUARY},
330 : {"March", TM_MARCH},
331 : {"April", TM_APRIL},
332 : {"May", TM_MAY},
333 : {"June", TM_JUNE},
334 : {"July", TM_JULY},
335 : {"August", TM_AUGUST},
336 : {"September", TM_SEPTEMBER},
337 : {"October", TM_OCTOBER},
338 : {"November", TM_NOVEMBER},
339 : {"December", TM_DECEMBER},
340 : {NULL, 0}
341 : };
342 :
343 : static struct lookup const wday_names[] = {
344 : {"Sunday", TM_SUNDAY},
345 : {"Monday", TM_MONDAY},
346 : {"Tuesday", TM_TUESDAY},
347 : {"Wednesday", TM_WEDNESDAY},
348 : {"Thursday", TM_THURSDAY},
349 : {"Friday", TM_FRIDAY},
350 : {"Saturday", TM_SATURDAY},
351 : {NULL, 0}
352 : };
353 :
354 : static struct lookup const lasts[] = {
355 : {"last-Sunday", TM_SUNDAY},
356 : {"last-Monday", TM_MONDAY},
357 : {"last-Tuesday", TM_TUESDAY},
358 : {"last-Wednesday", TM_WEDNESDAY},
359 : {"last-Thursday", TM_THURSDAY},
360 : {"last-Friday", TM_FRIDAY},
361 : {"last-Saturday", TM_SATURDAY},
362 : {NULL, 0}
363 : };
364 :
365 : static struct lookup const begin_years[] = {
366 : {"minimum", YR_MINIMUM},
367 : {"maximum", YR_MAXIMUM},
368 : {NULL, 0}
369 : };
370 :
371 : static struct lookup const end_years[] = {
372 : {"minimum", YR_MINIMUM},
373 : {"maximum", YR_MAXIMUM},
374 : {"only", YR_ONLY},
375 : {NULL, 0}
376 : };
377 :
378 : static struct lookup const leap_types[] = {
379 : {"Rolling", true},
380 : {"Stationary", false},
381 : {NULL, 0}
382 : };
383 :
384 : static const int len_months[2][MONSPERYEAR] = {
385 : {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
386 : {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
387 : };
388 :
389 : static const int len_years[2] = {
390 : DAYSPERNYEAR, DAYSPERLYEAR
391 : };
392 :
393 : static struct attype
394 : {
395 : zic_t at;
396 : bool dontmerge;
397 : unsigned char type;
398 : } *attypes;
399 : static zic_t utoffs[TZ_MAX_TYPES];
400 : static char isdsts[TZ_MAX_TYPES];
401 : static unsigned char desigidx[TZ_MAX_TYPES];
402 : static bool ttisstds[TZ_MAX_TYPES];
403 : static bool ttisuts[TZ_MAX_TYPES];
404 : static char chars[TZ_MAX_CHARS];
405 : static zic_t trans[TZ_MAX_LEAPS];
406 : static zic_t corr[TZ_MAX_LEAPS];
407 : static char roll[TZ_MAX_LEAPS];
408 :
409 : /*
410 : * Memory allocation.
411 : */
412 :
413 : static _Noreturn void
414 0 : memory_exhausted(const char *msg)
415 : {
416 0 : fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
417 0 : exit(EXIT_FAILURE);
418 : }
419 :
420 : static size_t
421 37624 : size_product(size_t nitems, size_t itemsize)
422 : {
423 37624 : if (SIZE_MAX / itemsize < nitems)
424 0 : memory_exhausted(_("size overflow"));
425 37624 : return nitems * itemsize;
426 : }
427 :
428 : static size_t
429 2728 : align_to(size_t size, size_t alignment)
430 : {
431 2728 : size_t aligned_size = size + alignment - 1;
432 :
433 2728 : aligned_size -= aligned_size % alignment;
434 2728 : if (aligned_size < size)
435 0 : memory_exhausted(_("alignment overflow"));
436 2728 : return aligned_size;
437 : }
438 :
439 : static void *
440 176588 : memcheck(void *ptr)
441 : {
442 176588 : if (ptr == NULL)
443 0 : memory_exhausted(strerror(errno));
444 176588 : return ptr;
445 : }
446 :
447 : static void *
448 45312 : emalloc(size_t size)
449 : {
450 45312 : return memcheck(malloc(size));
451 : }
452 :
453 : static void *
454 496 : erealloc(void *ptr, size_t size)
455 : {
456 496 : return memcheck(realloc(ptr, size));
457 : }
458 :
459 : static char *
460 130780 : ecpyalloc(char const *str)
461 : {
462 130780 : return memcheck(strdup(str));
463 : }
464 :
465 : static void *
466 170416 : growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
467 : {
468 170416 : if (nitems < *nitems_alloc)
469 169920 : return ptr;
470 : else
471 : {
472 496 : ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
473 496 : ptrdiff_t amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
474 :
475 496 : if ((amax - 1) / 3 * 2 < *nitems_alloc)
476 0 : memory_exhausted(_("integer overflow"));
477 496 : *nitems_alloc += (*nitems_alloc >> 1) + 1;
478 496 : return erealloc(ptr, size_product(*nitems_alloc, itemsize));
479 : }
480 : }
481 :
482 : /*
483 : * Error handling.
484 : */
485 :
486 : static void
487 11711704 : eats(char const *name, lineno_t num, char const *rname, lineno_t rnum)
488 : {
489 11711704 : filename = name;
490 11711704 : linenum = num;
491 11711704 : rfilename = rname;
492 11711704 : rlinenum = rnum;
493 11711704 : }
494 :
495 : static void
496 67320 : eat(char const *name, lineno_t num)
497 : {
498 67320 : eats(name, num, NULL, -1);
499 67320 : }
500 :
501 : static void
502 0 : verror(const char *const string, va_list args)
503 : {
504 : /*
505 : * Match the format of "cc" to allow sh users to zic ... 2>&1 | error -t
506 : * "*" -v on BSD systems.
507 : */
508 0 : if (filename)
509 0 : fprintf(stderr, _("\"%s\", line %" PRIdMAX ": "), filename, linenum);
510 0 : vfprintf(stderr, string, args);
511 0 : if (rfilename != NULL)
512 0 : fprintf(stderr, _(" (rule from \"%s\", line %" PRIdMAX ")"),
513 : rfilename, rlinenum);
514 0 : fprintf(stderr, "\n");
515 0 : }
516 :
517 : static void
518 0 : error(const char *const string,...)
519 : {
520 : va_list args;
521 :
522 0 : va_start(args, string);
523 0 : verror(string, args);
524 0 : va_end(args);
525 0 : errors = true;
526 0 : }
527 :
528 : static void
529 0 : warning(const char *const string,...)
530 : {
531 : va_list args;
532 :
533 0 : fprintf(stderr, _("warning: "));
534 0 : va_start(args, string);
535 0 : verror(string, args);
536 0 : va_end(args);
537 0 : warnings = true;
538 0 : }
539 :
540 : static void
541 2736 : close_file(FILE *stream, char const *dir, char const *name)
542 : {
543 2736 : char const *e = (ferror(stream) ? _("I/O error")
544 2736 : : fclose(stream) != 0 ? strerror(errno) : NULL);
545 :
546 2736 : if (e)
547 : {
548 0 : fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
549 : dir ? dir : "", dir ? "/" : "",
550 : name ? name : "", name ? ": " : "",
551 : e);
552 0 : exit(EXIT_FAILURE);
553 : }
554 2736 : }
555 :
556 : static _Noreturn void
557 0 : usage(FILE *stream, int status)
558 : {
559 0 : fprintf(stream,
560 : _("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -P ] \\\n"
561 : "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]"
562 : " [ -L leapseconds ] \\\n"
563 : "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -t localtime-link ] \\\n"
564 : "\t[ filename ... ]\n\n"
565 : "Report bugs to %s.\n"),
566 : progname, progname, PACKAGE_BUGREPORT);
567 0 : if (status == EXIT_SUCCESS)
568 0 : close_file(stream, NULL, NULL);
569 0 : exit(status);
570 : }
571 :
572 : /* Change the working directory to DIR, possibly creating DIR and its
573 : ancestors. After this is done, all files are accessed with names
574 : relative to DIR. */
575 : static void
576 8 : change_directory(char const *dir)
577 : {
578 8 : if (chdir(dir) != 0)
579 : {
580 4 : int chdir_errno = errno;
581 :
582 4 : if (chdir_errno == ENOENT)
583 : {
584 4 : mkdirs(dir, false);
585 4 : chdir_errno = chdir(dir) == 0 ? 0 : errno;
586 : }
587 4 : if (chdir_errno != 0)
588 : {
589 0 : fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
590 : progname, dir, strerror(chdir_errno));
591 0 : exit(EXIT_FAILURE);
592 : }
593 : }
594 8 : }
595 :
596 : #define TIME_T_BITS_IN_FILE 64
597 :
598 : /* The minimum and maximum values representable in a TZif file. */
599 : static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
600 : static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
601 :
602 : /* The minimum, and one less than the maximum, values specified by
603 : the -r option. These default to MIN_TIME and MAX_TIME. */
604 : static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
605 : static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
606 :
607 : /* The time specified by an Expires line, or negative if no such line. */
608 : static zic_t leapexpires = -1;
609 :
610 : /* The time specified by an #expires comment, or negative if no such line. */
611 : static zic_t comment_leapexpires = -1;
612 :
613 : /* Set the time range of the output to TIMERANGE.
614 : Return true if successful. */
615 : static bool
616 0 : timerange_option(char *timerange)
617 : {
618 0 : intmax_t lo = min_time,
619 0 : hi = max_time;
620 0 : char *lo_end = timerange,
621 : *hi_end;
622 :
623 0 : if (*timerange == '@')
624 : {
625 0 : errno = 0;
626 0 : lo = strtoimax(timerange + 1, &lo_end, 10);
627 0 : if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE))
628 0 : return false;
629 : }
630 0 : hi_end = lo_end;
631 0 : if (lo_end[0] == '/' && lo_end[1] == '@')
632 : {
633 0 : errno = 0;
634 0 : hi = strtoimax(lo_end + 2, &hi_end, 10);
635 0 : if (hi_end == lo_end + 2 || hi == INTMAX_MIN)
636 0 : return false;
637 0 : hi -= !(hi == INTMAX_MAX && errno == ERANGE);
638 : }
639 0 : if (*hi_end || hi < lo || max_time < lo || hi < min_time)
640 0 : return false;
641 0 : lo_time = lo < min_time ? min_time : lo;
642 0 : hi_time = max_time < hi ? max_time : hi;
643 0 : return true;
644 : }
645 :
646 : static const char *psxrules;
647 : static const char *lcltime;
648 : static const char *directory;
649 : static const char *leapsec;
650 : static const char *tzdefault;
651 :
652 : /* -1 if the TZif output file should be slim, 0 if default, 1 if the
653 : output should be fat for backward compatibility. ZIC_BLOAT_DEFAULT
654 : determines the default. */
655 : static int bloat;
656 :
657 : static bool
658 280000 : want_bloat(void)
659 : {
660 280000 : return 0 <= bloat;
661 : }
662 :
663 : #ifndef ZIC_BLOAT_DEFAULT
664 : #define ZIC_BLOAT_DEFAULT "slim"
665 : #endif
666 :
667 : int
668 8 : main(int argc, char **argv)
669 12928 : {
670 : int c,
671 : k;
672 : ptrdiff_t i,
673 : j;
674 8 : bool timerange_given = false;
675 :
676 : #ifndef WIN32
677 8 : umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
678 : #endif
679 8 : progname = argv[0];
680 : if (TYPE_BIT(zic_t) < 64)
681 : {
682 : fprintf(stderr, "%s: %s\n", progname,
683 : _("wild compilation-time specification of zic_t"));
684 : return EXIT_FAILURE;
685 : }
686 32 : for (k = 1; k < argc; k++)
687 24 : if (strcmp(argv[k], "--version") == 0)
688 : {
689 0 : printf("zic %s\n", PG_VERSION);
690 0 : close_file(stdout, NULL, NULL);
691 0 : return EXIT_SUCCESS;
692 : }
693 24 : else if (strcmp(argv[k], "--help") == 0)
694 : {
695 0 : usage(stdout, EXIT_SUCCESS);
696 : }
697 16 : while ((c = getopt(argc, argv, "b:d:l:L:p:Pr:st:vy:")) != EOF && c != -1)
698 8 : switch (c)
699 : {
700 0 : default:
701 0 : usage(stderr, EXIT_FAILURE);
702 0 : case 'b':
703 0 : if (strcmp(optarg, "slim") == 0)
704 : {
705 0 : if (0 < bloat)
706 0 : error(_("incompatible -b options"));
707 0 : bloat = -1;
708 : }
709 0 : else if (strcmp(optarg, "fat") == 0)
710 : {
711 0 : if (bloat < 0)
712 0 : error(_("incompatible -b options"));
713 0 : bloat = 1;
714 : }
715 : else
716 0 : error(_("invalid option: -b '%s'"), optarg);
717 0 : break;
718 8 : case 'd':
719 8 : if (directory == NULL)
720 8 : directory = strdup(optarg);
721 : else
722 : {
723 0 : fprintf(stderr,
724 : _("%s: More than one -d option specified\n"),
725 : progname);
726 0 : return EXIT_FAILURE;
727 : }
728 8 : break;
729 0 : case 'l':
730 0 : if (lcltime == NULL)
731 0 : lcltime = strdup(optarg);
732 : else
733 : {
734 0 : fprintf(stderr,
735 : _("%s: More than one -l option specified\n"),
736 : progname);
737 0 : return EXIT_FAILURE;
738 : }
739 0 : break;
740 0 : case 'p':
741 0 : if (psxrules == NULL)
742 0 : psxrules = strdup(optarg);
743 : else
744 : {
745 0 : fprintf(stderr,
746 : _("%s: More than one -p option specified\n"),
747 : progname);
748 0 : return EXIT_FAILURE;
749 : }
750 0 : break;
751 0 : case 't':
752 0 : if (tzdefault != NULL)
753 : {
754 0 : fprintf(stderr,
755 : _("%s: More than one -t option"
756 : " specified\n"),
757 : progname);
758 0 : return EXIT_FAILURE;
759 : }
760 0 : tzdefault = optarg;
761 0 : break;
762 0 : case 'y':
763 0 : warning(_("-y ignored"));
764 0 : break;
765 0 : case 'L':
766 0 : if (leapsec == NULL)
767 0 : leapsec = strdup(optarg);
768 : else
769 : {
770 0 : fprintf(stderr,
771 : _("%s: More than one -L option specified\n"),
772 : progname);
773 0 : return EXIT_FAILURE;
774 : }
775 0 : break;
776 0 : case 'v':
777 0 : noise = true;
778 0 : break;
779 0 : case 'P':
780 0 : print_abbrevs = true;
781 0 : print_cutoff = time(NULL);
782 0 : break;
783 0 : case 'r':
784 0 : if (timerange_given)
785 : {
786 0 : fprintf(stderr,
787 : _("%s: More than one -r option specified\n"),
788 : progname);
789 0 : return EXIT_FAILURE;
790 : }
791 0 : if (!timerange_option(optarg))
792 : {
793 0 : fprintf(stderr,
794 : _("%s: invalid time range: %s\n"),
795 : progname, optarg);
796 0 : return EXIT_FAILURE;
797 : }
798 0 : timerange_given = true;
799 0 : break;
800 0 : case 's':
801 0 : warning(_("-s ignored"));
802 0 : break;
803 : }
804 8 : if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
805 0 : usage(stderr, EXIT_FAILURE); /* usage message by request */
806 8 : if (bloat == 0)
807 : {
808 : static char const bloat_default[] = ZIC_BLOAT_DEFAULT;
809 :
810 8 : if (strcmp(bloat_default, "slim") == 0)
811 8 : bloat = -1;
812 0 : else if (strcmp(bloat_default, "fat") == 0)
813 0 : bloat = 1;
814 : else
815 0 : abort(); /* Configuration error. */
816 : }
817 8 : if (directory == NULL)
818 0 : directory = "data";
819 8 : if (tzdefault == NULL)
820 8 : tzdefault = TZDEFAULT;
821 :
822 8 : if (optind < argc && leapsec != NULL)
823 : {
824 0 : infile(leapsec);
825 0 : adjleap();
826 : }
827 :
828 16 : for (k = optind; k < argc; k++)
829 8 : infile(argv[k]);
830 8 : if (errors)
831 0 : return EXIT_FAILURE;
832 8 : associate();
833 8 : change_directory(directory);
834 2736 : for (i = 0; i < nzones; i = j)
835 : {
836 : /*
837 : * Find the next non-continuation zone entry.
838 : */
839 15656 : for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
840 12928 : continue;
841 2728 : outzone(&zones[i], j - i);
842 : }
843 :
844 : /*
845 : * Make links.
846 : */
847 2064 : for (i = 0; i < nlinks; ++i)
848 : {
849 2056 : eat(links[i].l_filename, links[i].l_linenum);
850 2056 : dolink(links[i].l_target, links[i].l_linkname, false);
851 2056 : if (noise)
852 0 : for (j = 0; j < nlinks; ++j)
853 0 : if (strcmp(links[i].l_linkname,
854 0 : links[j].l_target) == 0)
855 0 : warning(_("link to link"));
856 : }
857 8 : if (lcltime != NULL)
858 : {
859 0 : eat(_("command line"), 1);
860 0 : dolink(lcltime, tzdefault, true);
861 : }
862 8 : if (psxrules != NULL)
863 : {
864 0 : eat(_("command line"), 1);
865 0 : dolink(psxrules, TZDEFRULES, true);
866 : }
867 8 : if (warnings && (ferror(stderr) || fclose(stderr) != 0))
868 0 : return EXIT_FAILURE;
869 8 : return errors ? EXIT_FAILURE : EXIT_SUCCESS;
870 : }
871 :
872 : static bool
873 9416 : componentcheck(char const *name, char const *component,
874 : char const *component_end)
875 : {
876 : enum
877 : {
878 : component_len_max = 14};
879 9416 : ptrdiff_t component_len = component_end - component;
880 :
881 9416 : if (component_len == 0)
882 : {
883 0 : if (!*name)
884 0 : error(_("empty file name"));
885 : else
886 0 : error(_(component == name
887 : ? "file name '%s' begins with '/'"
888 : : *component_end
889 : ? "file name '%s' contains '//'"
890 : : "file name '%s' ends with '/'"),
891 : name);
892 0 : return false;
893 : }
894 9416 : if (0 < component_len && component_len <= 2
895 112 : && component[0] == '.' && component_end[-1] == '.')
896 : {
897 0 : int len = component_len;
898 :
899 0 : error(_("file name '%s' contains '%.*s' component"),
900 : name, len, component);
901 0 : return false;
902 : }
903 9416 : if (noise)
904 : {
905 0 : if (0 < component_len && component[0] == '-')
906 0 : warning(_("file name '%s' component contains leading '-'"),
907 : name);
908 0 : if (component_len_max < component_len)
909 0 : warning(_("file name '%s' contains overlength component"
910 : " '%.*s...'"),
911 : name, component_len_max, component);
912 : }
913 9416 : return true;
914 : }
915 :
916 : static bool
917 4784 : namecheck(const char *name)
918 : {
919 : char const *cp;
920 :
921 : /* Benign characters in a portable file name. */
922 : static char const benign[] =
923 : "-/_"
924 : "abcdefghijklmnopqrstuvwxyz"
925 : "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
926 :
927 : /*
928 : * Non-control chars in the POSIX portable character set, excluding the
929 : * benign characters.
930 : */
931 : static char const printable_and_not_benign[] =
932 : " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
933 :
934 4784 : char const *component = name;
935 :
936 72816 : for (cp = name; *cp; cp++)
937 : {
938 68032 : unsigned char c = *cp;
939 :
940 68032 : if (noise && !strchr(benign, c))
941 : {
942 0 : warning((strchr(printable_and_not_benign, c)
943 : ? _("file name '%s' contains byte '%c'")
944 : : _("file name '%s' contains byte '\\%o'")),
945 : name, c);
946 : }
947 68032 : if (c == '/')
948 : {
949 4632 : if (!componentcheck(name, component, cp))
950 0 : return false;
951 4632 : component = cp + 1;
952 : }
953 : }
954 4784 : return componentcheck(name, component, cp);
955 : }
956 :
957 : /*
958 : * Create symlink contents suitable for symlinking FROM to TO, as a
959 : * freshly allocated string. FROM should be a relative file name, and
960 : * is relative to the global variable DIRECTORY. TO can be either
961 : * relative or absolute.
962 : */
963 : #ifdef HAVE_SYMLINK
964 : static char *
965 0 : relname(char const *target, char const *linkname)
966 : {
967 : size_t i,
968 : taillen,
969 : dotdotetcsize;
970 0 : size_t dir_len = 0,
971 0 : dotdots = 0,
972 0 : linksize = SIZE_MAX;
973 0 : char const *f = target;
974 0 : char *result = NULL;
975 :
976 0 : if (*linkname == '/')
977 : {
978 : /* Make F absolute too. */
979 0 : size_t len = strlen(directory);
980 0 : bool needslash = len && directory[len - 1] != '/';
981 :
982 0 : linksize = len + needslash + strlen(target) + 1;
983 0 : f = result = emalloc(linksize);
984 0 : strcpy(result, directory);
985 0 : result[len] = '/';
986 0 : strcpy(result + len + needslash, target);
987 : }
988 0 : for (i = 0; f[i] && f[i] == linkname[i]; i++)
989 0 : if (f[i] == '/')
990 0 : dir_len = i + 1;
991 0 : for (; linkname[i]; i++)
992 0 : dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
993 0 : taillen = strlen(f + dir_len);
994 0 : dotdotetcsize = 3 * dotdots + taillen + 1;
995 0 : if (dotdotetcsize <= linksize)
996 : {
997 0 : if (!result)
998 0 : result = emalloc(dotdotetcsize);
999 0 : for (i = 0; i < dotdots; i++)
1000 0 : memcpy(result + 3 * i, "../", 3);
1001 0 : memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
1002 : }
1003 0 : return result;
1004 : }
1005 : #endif /* HAVE_SYMLINK */
1006 :
1007 : /* Hard link FROM to TO, following any symbolic links.
1008 : Return 0 if successful, an error number otherwise. */
1009 : static int
1010 2080 : hardlinkerr(char const *target, char const *linkname)
1011 : {
1012 2080 : int r = linkat(AT_FDCWD, target, AT_FDCWD, linkname, AT_SYMLINK_FOLLOW);
1013 :
1014 2080 : return r == 0 ? 0 : errno;
1015 : }
1016 :
1017 : static void
1018 2056 : dolink(char const *target, char const *linkname, bool staysymlink)
1019 : {
1020 2056 : bool remove_only = strcmp(target, "-") == 0;
1021 2056 : bool linkdirs_made = false;
1022 : int link_errno;
1023 :
1024 : /*
1025 : * We get to be careful here since there's a fair chance of root running
1026 : * us.
1027 : */
1028 2056 : if (!remove_only && itsdir(target))
1029 : {
1030 0 : fprintf(stderr, _("%s: linking target %s/%s failed: %s\n"),
1031 : progname, directory, target, strerror(EPERM));
1032 0 : exit(EXIT_FAILURE);
1033 : }
1034 2056 : if (staysymlink)
1035 0 : staysymlink = itssymlink(linkname);
1036 2056 : if (remove(linkname) == 0)
1037 1028 : linkdirs_made = true;
1038 1028 : else if (errno != ENOENT)
1039 : {
1040 0 : char const *e = strerror(errno);
1041 :
1042 0 : fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1043 : progname, directory, linkname, e);
1044 0 : exit(EXIT_FAILURE);
1045 : }
1046 2056 : if (remove_only)
1047 0 : return;
1048 2056 : link_errno = staysymlink ? ENOTSUP : hardlinkerr(target, linkname);
1049 2056 : if (link_errno == ENOENT && !linkdirs_made)
1050 : {
1051 24 : mkdirs(linkname, true);
1052 24 : linkdirs_made = true;
1053 24 : link_errno = hardlinkerr(target, linkname);
1054 : }
1055 2056 : if (link_errno != 0)
1056 : {
1057 : #ifdef HAVE_SYMLINK
1058 0 : bool absolute = *target == '/';
1059 0 : char *linkalloc = absolute ? NULL : relname(target, linkname);
1060 0 : char const *contents = absolute ? target : linkalloc;
1061 0 : int symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
1062 :
1063 0 : if (!linkdirs_made
1064 0 : && (symlink_errno == ENOENT || symlink_errno == ENOTSUP))
1065 : {
1066 0 : mkdirs(linkname, true);
1067 0 : if (symlink_errno == ENOENT)
1068 0 : symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
1069 : }
1070 0 : free(linkalloc);
1071 0 : if (symlink_errno == 0)
1072 : {
1073 0 : if (link_errno != ENOTSUP)
1074 0 : warning(_("symbolic link used because hard link failed: %s"),
1075 : strerror(link_errno));
1076 : }
1077 : else
1078 : #endif /* HAVE_SYMLINK */
1079 : {
1080 : FILE *fp,
1081 : *tp;
1082 : int c;
1083 :
1084 0 : fp = fopen(target, "rb");
1085 0 : if (!fp)
1086 : {
1087 0 : char const *e = strerror(errno);
1088 :
1089 0 : fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
1090 : progname, directory, target, e);
1091 0 : exit(EXIT_FAILURE);
1092 : }
1093 0 : tp = fopen(linkname, "wb");
1094 0 : if (!tp)
1095 : {
1096 0 : char const *e = strerror(errno);
1097 :
1098 0 : fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1099 : progname, directory, linkname, e);
1100 0 : exit(EXIT_FAILURE);
1101 : }
1102 0 : while ((c = getc(fp)) != EOF)
1103 0 : putc(c, tp);
1104 0 : close_file(fp, directory, target);
1105 0 : close_file(tp, directory, linkname);
1106 0 : if (link_errno != ENOTSUP)
1107 0 : warning(_("copy used because hard link failed: %s"),
1108 : strerror(link_errno));
1109 : #ifdef HAVE_SYMLINK
1110 0 : else if (symlink_errno != ENOTSUP)
1111 0 : warning(_("copy used because symbolic link failed: %s"),
1112 : strerror(symlink_errno));
1113 : #endif
1114 : }
1115 : }
1116 : }
1117 :
1118 : /* Return true if NAME is a directory. */
1119 : static bool
1120 2056 : itsdir(char const *name)
1121 : {
1122 : struct stat st;
1123 2056 : int res = stat(name, &st);
1124 : #ifdef S_ISDIR
1125 2056 : if (res == 0)
1126 2056 : return S_ISDIR(st.st_mode) != 0;
1127 : #endif
1128 0 : if (res == 0 || errno == EOVERFLOW)
1129 : {
1130 0 : size_t n = strlen(name);
1131 0 : char *nameslashdot = emalloc(n + 3);
1132 : bool dir;
1133 :
1134 0 : memcpy(nameslashdot, name, n);
1135 0 : strcpy(&nameslashdot[n], &"/."[!(n && name[n - 1] != '/')]);
1136 0 : dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
1137 0 : free(nameslashdot);
1138 0 : return dir;
1139 : }
1140 0 : return false;
1141 : }
1142 :
1143 : /* Return true if NAME is a symbolic link. */
1144 : static bool
1145 0 : itssymlink(char const *name)
1146 : {
1147 : #ifdef HAVE_SYMLINK
1148 : char c;
1149 :
1150 0 : return 0 <= readlink(name, &c, 1);
1151 : #else
1152 : return false;
1153 : #endif
1154 : }
1155 :
1156 : /*
1157 : * Associate sets of rules with zones.
1158 : */
1159 :
1160 : /*
1161 : * Sort by rule name.
1162 : */
1163 :
1164 : static int
1165 98592 : rcomp(const void *cp1, const void *cp2)
1166 : {
1167 197184 : return strcmp(((const struct rule *) cp1)->r_name,
1168 98592 : ((const struct rule *) cp2)->r_name);
1169 : }
1170 :
1171 : static void
1172 8 : associate(void)
1173 : {
1174 : struct zone *zp;
1175 : struct rule *rp;
1176 : ptrdiff_t i,
1177 : j,
1178 : base,
1179 : out;
1180 :
1181 8 : if (nrules != 0)
1182 : {
1183 8 : qsort(rules, nrules, sizeof *rules, rcomp);
1184 16672 : for (i = 0; i < nrules - 1; ++i)
1185 : {
1186 17696 : if (strcmp(rules[i].r_name,
1187 16664 : rules[i + 1].r_name) != 0)
1188 1032 : continue;
1189 31264 : if (strcmp(rules[i].r_filename,
1190 15632 : rules[i + 1].r_filename) == 0)
1191 15632 : continue;
1192 0 : eat(rules[i].r_filename, rules[i].r_linenum);
1193 0 : warning(_("same rule name in multiple files"));
1194 0 : eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
1195 0 : warning(_("same rule name in multiple files"));
1196 0 : for (j = i + 2; j < nrules; ++j)
1197 : {
1198 0 : if (strcmp(rules[i].r_name,
1199 0 : rules[j].r_name) != 0)
1200 0 : break;
1201 0 : if (strcmp(rules[i].r_filename,
1202 0 : rules[j].r_filename) == 0)
1203 0 : continue;
1204 0 : if (strcmp(rules[i + 1].r_filename,
1205 0 : rules[j].r_filename) == 0)
1206 0 : continue;
1207 0 : break;
1208 : }
1209 0 : i = j - 1;
1210 : }
1211 : }
1212 15664 : for (i = 0; i < nzones; ++i)
1213 : {
1214 15656 : zp = &zones[i];
1215 15656 : zp->z_rules = NULL;
1216 15656 : zp->z_nrules = 0;
1217 : }
1218 1048 : for (base = 0; base < nrules; base = out)
1219 : {
1220 1040 : rp = &rules[base];
1221 16672 : for (out = base + 1; out < nrules; ++out)
1222 16664 : if (strcmp(rp->r_name, rules[out].r_name) != 0)
1223 1032 : break;
1224 2036320 : for (i = 0; i < nzones; ++i)
1225 : {
1226 2035280 : zp = &zones[i];
1227 2035280 : if (strcmp(zp->z_rule, rp->r_name) != 0)
1228 2029224 : continue;
1229 6056 : zp->z_rules = rp;
1230 6056 : zp->z_nrules = out - base;
1231 : }
1232 : }
1233 15664 : for (i = 0; i < nzones; ++i)
1234 : {
1235 15656 : zp = &zones[i];
1236 15656 : if (zp->z_nrules == 0)
1237 : {
1238 : /*
1239 : * Maybe we have a local standard time offset.
1240 : */
1241 9600 : eat(zp->z_filename, zp->z_linenum);
1242 9600 : zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
1243 :
1244 : /*
1245 : * Note, though, that if there's no rule, a '%s' in the format is
1246 : * a bad thing.
1247 : */
1248 9600 : if (zp->z_format_specifier == 's')
1249 0 : error("%s", _("%s in ruleless zone"));
1250 : }
1251 : }
1252 8 : if (errors)
1253 0 : exit(EXIT_FAILURE);
1254 8 : }
1255 :
1256 : static void
1257 8 : infile(const char *name)
1258 : {
1259 : FILE *fp;
1260 : char **fields;
1261 : char *cp;
1262 : const struct lookup *lp;
1263 : int nfields;
1264 : bool wantcont;
1265 : lineno_t num;
1266 : char buf[BUFSIZ];
1267 :
1268 8 : if (strcmp(name, "-") == 0)
1269 : {
1270 0 : name = _("standard input");
1271 0 : fp = stdin;
1272 : }
1273 8 : else if ((fp = fopen(name, "r")) == NULL)
1274 : {
1275 0 : const char *e = strerror(errno);
1276 :
1277 0 : fprintf(stderr, _("%s: Cannot open %s: %s\n"),
1278 : progname, name, e);
1279 0 : exit(EXIT_FAILURE);
1280 : }
1281 8 : wantcont = false;
1282 8 : for (num = 1;; ++num)
1283 : {
1284 34408 : eat(name, num);
1285 34408 : if (fgets(buf, sizeof buf, fp) != buf)
1286 8 : break;
1287 34400 : cp = strchr(buf, '\n');
1288 34400 : if (cp == NULL)
1289 : {
1290 0 : error(_("line too long"));
1291 0 : exit(EXIT_FAILURE);
1292 : }
1293 34400 : *cp = '\0';
1294 34400 : fields = getfields(buf);
1295 34400 : nfields = 0;
1296 294552 : while (fields[nfields] != NULL)
1297 : {
1298 : static char nada;
1299 :
1300 260152 : if (strcmp(fields[nfields], "-") == 0)
1301 32944 : fields[nfields] = &nada;
1302 260152 : ++nfields;
1303 : }
1304 34400 : if (nfields == 0)
1305 : {
1306 16 : if (name == leapsec && *buf == '#')
1307 0 : sscanf(buf, "#expires %" SCNdZIC, &comment_leapexpires);
1308 : }
1309 34384 : else if (wantcont)
1310 : {
1311 12928 : wantcont = inzcont(fields, nfields);
1312 : }
1313 : else
1314 : {
1315 21456 : struct lookup const *line_codes
1316 21456 : = name == leapsec ? leap_line_codes : zi_line_codes;
1317 :
1318 21456 : lp = byword(fields[0], line_codes);
1319 21456 : if (lp == NULL)
1320 0 : error(_("input line of unknown type"));
1321 : else
1322 21456 : switch (lp->l_value)
1323 : {
1324 16672 : case LC_RULE:
1325 16672 : inrule(fields, nfields);
1326 16672 : wantcont = false;
1327 16672 : break;
1328 2728 : case LC_ZONE:
1329 2728 : wantcont = inzone(fields, nfields);
1330 2728 : break;
1331 2056 : case LC_LINK:
1332 2056 : inlink(fields, nfields);
1333 2056 : wantcont = false;
1334 2056 : break;
1335 0 : case LC_LEAP:
1336 0 : inleap(fields, nfields);
1337 0 : wantcont = false;
1338 0 : break;
1339 0 : case LC_EXPIRES:
1340 0 : inexpires(fields, nfields);
1341 0 : wantcont = false;
1342 0 : break;
1343 0 : default: /* "cannot happen" */
1344 0 : fprintf(stderr,
1345 : _("%s: panic: Invalid l_value %d\n"),
1346 0 : progname, lp->l_value);
1347 0 : exit(EXIT_FAILURE);
1348 : }
1349 : }
1350 34400 : free(fields);
1351 : }
1352 8 : close_file(fp, NULL, filename);
1353 8 : if (wantcont)
1354 0 : error(_("expected continuation line not found"));
1355 8 : }
1356 :
1357 : /*
1358 : * Convert a string of one of the forms
1359 : * h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1360 : * into a number of seconds.
1361 : * A null string maps to zero.
1362 : * Call error with errstring and return zero on errors.
1363 : */
1364 :
1365 : static zic_t
1366 71528 : gethms(char const *string, char const *errstring)
1367 : {
1368 : zic_t hh;
1369 : int sign,
1370 71528 : mm = 0,
1371 71528 : ss = 0;
1372 : char hhx,
1373 : mmx,
1374 : ssx,
1375 71528 : xr = '0',
1376 : xs;
1377 71528 : int tenths = 0;
1378 71528 : bool ok = true;
1379 :
1380 71528 : if (string == NULL || *string == '\0')
1381 9112 : return 0;
1382 62416 : if (*string == '-')
1383 : {
1384 7896 : sign = -1;
1385 7896 : ++string;
1386 : }
1387 : else
1388 54520 : sign = 1;
1389 62416 : switch (sscanf(string,
1390 : "%" SCNdZIC "%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
1391 : &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs))
1392 : {
1393 0 : default:
1394 0 : ok = false;
1395 0 : break;
1396 0 : case 8:
1397 0 : ok = '0' <= xr && xr <= '9';
1398 : /* fallthrough */
1399 0 : case 7:
1400 0 : ok &= ssx == '.';
1401 0 : if (ok && noise)
1402 0 : warning(_("fractional seconds rejected by"
1403 : " pre-2018 versions of zic"));
1404 : /* fallthrough */
1405 : case 5:
1406 3176 : ok &= mmx == ':';
1407 : /* fallthrough */
1408 4840 : case 3:
1409 4840 : ok &= hhx == ':';
1410 : /* fallthrough */
1411 62416 : case 1:
1412 62416 : break;
1413 : }
1414 62416 : if (!ok)
1415 : {
1416 0 : error("%s", errstring);
1417 0 : return 0;
1418 : }
1419 62416 : if (hh < 0 ||
1420 62416 : mm < 0 || mm >= MINSPERHOUR ||
1421 62416 : ss < 0 || ss > SECSPERMIN)
1422 : {
1423 0 : error("%s", errstring);
1424 0 : return 0;
1425 : }
1426 62416 : if (ZIC_MAX / SECSPERHOUR < hh)
1427 : {
1428 0 : error(_("time overflow"));
1429 0 : return 0;
1430 : }
1431 62416 : ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */
1432 62416 : if (noise && (hh > HOURSPERDAY ||
1433 0 : (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1434 0 : warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1435 62416 : return oadd(sign * hh * SECSPERHOUR,
1436 62416 : sign * (mm * SECSPERMIN + ss));
1437 : }
1438 :
1439 : static zic_t
1440 26272 : getsave(char *field, bool *isdst)
1441 : {
1442 26272 : int dst = -1;
1443 : zic_t save;
1444 26272 : size_t fieldlen = strlen(field);
1445 :
1446 26272 : if (fieldlen != 0)
1447 : {
1448 17160 : char *ep = field + fieldlen - 1;
1449 :
1450 17160 : switch (*ep)
1451 : {
1452 0 : case 'd':
1453 0 : dst = 1;
1454 0 : *ep = '\0';
1455 0 : break;
1456 0 : case 's':
1457 0 : dst = 0;
1458 0 : *ep = '\0';
1459 0 : break;
1460 : }
1461 : }
1462 26272 : save = gethms(field, _("invalid saved time"));
1463 26272 : *isdst = dst < 0 ? save != 0 : dst;
1464 26272 : return save;
1465 : }
1466 :
1467 : static void
1468 16672 : inrule(char **fields, int nfields)
1469 : {
1470 : static struct rule r;
1471 :
1472 16672 : if (nfields != RULE_FIELDS)
1473 : {
1474 0 : error(_("wrong number of fields on Rule line"));
1475 0 : return;
1476 : }
1477 16672 : switch (*fields[RF_NAME])
1478 : {
1479 0 : case '\0':
1480 : case ' ':
1481 : case '\f':
1482 : case '\n':
1483 : case '\r':
1484 : case '\t':
1485 : case '\v':
1486 : case '+':
1487 : case '-':
1488 : case '0':
1489 : case '1':
1490 : case '2':
1491 : case '3':
1492 : case '4':
1493 : case '5':
1494 : case '6':
1495 : case '7':
1496 : case '8':
1497 : case '9':
1498 0 : error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
1499 0 : return;
1500 : }
1501 16672 : r.r_filename = filename;
1502 16672 : r.r_linenum = linenum;
1503 16672 : r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
1504 16672 : rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1505 16672 : fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1506 16672 : r.r_name = ecpyalloc(fields[RF_NAME]);
1507 16672 : r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1508 16672 : if (max_abbrvar_len < strlen(r.r_abbrvar))
1509 0 : max_abbrvar_len = strlen(r.r_abbrvar);
1510 16672 : rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1511 16672 : rules[nrules++] = r;
1512 : }
1513 :
1514 : static bool
1515 2728 : inzone(char **fields, int nfields)
1516 : {
1517 : ptrdiff_t i;
1518 :
1519 2728 : if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS)
1520 : {
1521 0 : error(_("wrong number of fields on Zone line"));
1522 0 : return false;
1523 : }
1524 2728 : if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0)
1525 : {
1526 0 : error(
1527 : _("\"Zone %s\" line and -l option are mutually exclusive"),
1528 : tzdefault);
1529 0 : return false;
1530 : }
1531 2728 : if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL)
1532 : {
1533 0 : error(
1534 : _("\"Zone %s\" line and -p option are mutually exclusive"),
1535 : TZDEFRULES);
1536 0 : return false;
1537 : }
1538 2844680 : for (i = 0; i < nzones; ++i)
1539 2841952 : if (zones[i].z_name != NULL &&
1540 463760 : strcmp(zones[i].z_name, fields[ZF_NAME]) == 0)
1541 : {
1542 0 : error(_("duplicate zone name %s"
1543 : " (file \"%s\", line %" PRIdMAX ")"),
1544 0 : fields[ZF_NAME],
1545 0 : zones[i].z_filename,
1546 0 : zones[i].z_linenum);
1547 0 : return false;
1548 : }
1549 2728 : return inzsub(fields, nfields, false);
1550 : }
1551 :
1552 : static bool
1553 12928 : inzcont(char **fields, int nfields)
1554 : {
1555 12928 : if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS)
1556 : {
1557 0 : error(_("wrong number of fields on Zone continuation line"));
1558 0 : return false;
1559 : }
1560 12928 : return inzsub(fields, nfields, true);
1561 : }
1562 :
1563 : static bool
1564 15656 : inzsub(char **fields, int nfields, bool iscont)
1565 : {
1566 : char *cp;
1567 : char *cp1;
1568 : static struct zone z;
1569 : int i_stdoff,
1570 : i_rule,
1571 : i_format;
1572 : int i_untilyear,
1573 : i_untilmonth;
1574 : int i_untilday,
1575 : i_untiltime;
1576 : bool hasuntil;
1577 :
1578 15656 : if (iscont)
1579 : {
1580 12928 : i_stdoff = ZFC_STDOFF;
1581 12928 : i_rule = ZFC_RULE;
1582 12928 : i_format = ZFC_FORMAT;
1583 12928 : i_untilyear = ZFC_TILYEAR;
1584 12928 : i_untilmonth = ZFC_TILMONTH;
1585 12928 : i_untilday = ZFC_TILDAY;
1586 12928 : i_untiltime = ZFC_TILTIME;
1587 12928 : z.z_name = NULL;
1588 : }
1589 2728 : else if (!namecheck(fields[ZF_NAME]))
1590 0 : return false;
1591 : else
1592 : {
1593 2728 : i_stdoff = ZF_STDOFF;
1594 2728 : i_rule = ZF_RULE;
1595 2728 : i_format = ZF_FORMAT;
1596 2728 : i_untilyear = ZF_TILYEAR;
1597 2728 : i_untilmonth = ZF_TILMONTH;
1598 2728 : i_untilday = ZF_TILDAY;
1599 2728 : i_untiltime = ZF_TILTIME;
1600 2728 : z.z_name = ecpyalloc(fields[ZF_NAME]);
1601 : }
1602 15656 : z.z_filename = filename;
1603 15656 : z.z_linenum = linenum;
1604 15656 : z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
1605 15656 : if ((cp = strchr(fields[i_format], '%')) != NULL)
1606 : {
1607 9712 : if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1608 9712 : || strchr(fields[i_format], '/'))
1609 : {
1610 0 : error(_("invalid abbreviation format"));
1611 0 : return false;
1612 : }
1613 : }
1614 15656 : z.z_rule = ecpyalloc(fields[i_rule]);
1615 15656 : z.z_format = cp1 = ecpyalloc(fields[i_format]);
1616 15656 : z.z_format_specifier = cp ? *cp : '\0';
1617 15656 : if (z.z_format_specifier == 'z')
1618 : {
1619 6152 : if (noise)
1620 0 : warning(_("format '%s' not handled by pre-2015 versions of zic"),
1621 : z.z_format);
1622 6152 : cp1[cp - fields[i_format]] = 's';
1623 : }
1624 15656 : if (max_format_len < strlen(z.z_format))
1625 24 : max_format_len = strlen(z.z_format);
1626 15656 : hasuntil = nfields > i_untilyear;
1627 15656 : if (hasuntil)
1628 : {
1629 12928 : z.z_untilrule.r_filename = filename;
1630 12928 : z.z_untilrule.r_linenum = linenum;
1631 24952 : rulesub(&z.z_untilrule,
1632 12928 : fields[i_untilyear],
1633 : "only",
1634 : "",
1635 : (nfields > i_untilmonth) ?
1636 9888 : fields[i_untilmonth] : "Jan",
1637 7960 : (nfields > i_untilday) ? fields[i_untilday] : "1",
1638 4064 : (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1639 12928 : z.z_untiltime = rpytime(&z.z_untilrule,
1640 : z.z_untilrule.r_loyear);
1641 12928 : if (iscont && nzones > 0 &&
1642 10432 : z.z_untiltime > min_time &&
1643 10432 : z.z_untiltime < max_time &&
1644 10432 : zones[nzones - 1].z_untiltime > min_time &&
1645 10432 : zones[nzones - 1].z_untiltime < max_time &&
1646 10432 : zones[nzones - 1].z_untiltime >= z.z_untiltime)
1647 : {
1648 0 : error(_("Zone continuation line end time is not after end time of previous line"));
1649 0 : return false;
1650 : }
1651 : }
1652 15656 : zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1653 15656 : zones[nzones++] = z;
1654 :
1655 : /*
1656 : * If there was an UNTIL field on this line, there's more information
1657 : * about the zone on the next line.
1658 : */
1659 15656 : return hasuntil;
1660 : }
1661 :
1662 : static zic_t
1663 0 : getleapdatetime(char **fields, int nfields, bool expire_line)
1664 : {
1665 : const char *cp;
1666 : const struct lookup *lp;
1667 : zic_t i,
1668 : j;
1669 : zic_t year;
1670 : int month,
1671 : day;
1672 : zic_t dayoff,
1673 : tod;
1674 : zic_t t;
1675 : char xs;
1676 :
1677 0 : dayoff = 0;
1678 0 : cp = fields[LP_YEAR];
1679 0 : if (sscanf(cp, "%" SCNdZIC "%c", &year, &xs) != 1)
1680 : {
1681 : /*
1682 : * Leapin' Lizards!
1683 : */
1684 0 : error(_("invalid leaping year"));
1685 0 : return -1;
1686 : }
1687 0 : if (!expire_line)
1688 : {
1689 0 : if (!leapseen || leapmaxyear < year)
1690 0 : leapmaxyear = year;
1691 0 : if (!leapseen || leapminyear > year)
1692 0 : leapminyear = year;
1693 0 : leapseen = true;
1694 : }
1695 0 : j = EPOCH_YEAR;
1696 0 : while (j != year)
1697 : {
1698 0 : if (year > j)
1699 : {
1700 0 : i = len_years[isleap(j)];
1701 0 : ++j;
1702 : }
1703 : else
1704 : {
1705 0 : --j;
1706 0 : i = -len_years[isleap(j)];
1707 : }
1708 0 : dayoff = oadd(dayoff, i);
1709 : }
1710 0 : if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL)
1711 : {
1712 0 : error(_("invalid month name"));
1713 0 : return -1;
1714 : }
1715 0 : month = lp->l_value;
1716 0 : j = TM_JANUARY;
1717 0 : while (j != month)
1718 : {
1719 0 : i = len_months[isleap(year)][j];
1720 0 : dayoff = oadd(dayoff, i);
1721 0 : ++j;
1722 : }
1723 0 : cp = fields[LP_DAY];
1724 0 : if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1725 0 : day <= 0 || day > len_months[isleap(year)][month])
1726 : {
1727 0 : error(_("invalid day of month"));
1728 0 : return -1;
1729 : }
1730 0 : dayoff = oadd(dayoff, day - 1);
1731 0 : if (dayoff < min_time / SECSPERDAY)
1732 : {
1733 0 : error(_("time too small"));
1734 0 : return -1;
1735 : }
1736 0 : if (dayoff > max_time / SECSPERDAY)
1737 : {
1738 0 : error(_("time too large"));
1739 0 : return -1;
1740 : }
1741 0 : t = dayoff * SECSPERDAY;
1742 0 : tod = gethms(fields[LP_TIME], _("invalid time of day"));
1743 0 : t = tadd(t, tod);
1744 0 : if (t < 0)
1745 0 : error(_("leap second precedes Epoch"));
1746 0 : return t;
1747 : }
1748 :
1749 : static void
1750 0 : inleap(char **fields, int nfields)
1751 : {
1752 0 : if (nfields != LEAP_FIELDS)
1753 0 : error(_("wrong number of fields on Leap line"));
1754 : else
1755 : {
1756 0 : zic_t t = getleapdatetime(fields, nfields, false);
1757 :
1758 0 : if (0 <= t)
1759 : {
1760 0 : struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
1761 :
1762 0 : if (!lp)
1763 0 : error(_("invalid Rolling/Stationary field on Leap line"));
1764 : else
1765 : {
1766 0 : int correction = 0;
1767 :
1768 0 : if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */
1769 0 : correction = -1;
1770 0 : else if (strcmp(fields[LP_CORR], "+") == 0)
1771 0 : correction = 1;
1772 : else
1773 0 : error(_("invalid CORRECTION field on Leap line"));
1774 0 : if (correction)
1775 0 : leapadd(t, correction, lp->l_value);
1776 : }
1777 : }
1778 : }
1779 0 : }
1780 :
1781 : static void
1782 0 : inexpires(char **fields, int nfields)
1783 : {
1784 0 : if (nfields != EXPIRES_FIELDS)
1785 0 : error(_("wrong number of fields on Expires line"));
1786 0 : else if (0 <= leapexpires)
1787 0 : error(_("multiple Expires lines"));
1788 : else
1789 0 : leapexpires = getleapdatetime(fields, nfields, true);
1790 0 : }
1791 :
1792 : static void
1793 2056 : inlink(char **fields, int nfields)
1794 : {
1795 : struct link l;
1796 :
1797 2056 : if (nfields != LINK_FIELDS)
1798 : {
1799 0 : error(_("wrong number of fields on Link line"));
1800 0 : return;
1801 : }
1802 2056 : if (*fields[LF_TARGET] == '\0')
1803 : {
1804 0 : error(_("blank TARGET field on Link line"));
1805 0 : return;
1806 : }
1807 2056 : if (!namecheck(fields[LF_LINKNAME]))
1808 0 : return;
1809 2056 : l.l_filename = filename;
1810 2056 : l.l_linenum = linenum;
1811 2056 : l.l_target = ecpyalloc(fields[LF_TARGET]);
1812 2056 : l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
1813 2056 : links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1814 2056 : links[nlinks++] = l;
1815 : }
1816 :
1817 : static void
1818 29600 : rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1819 : const char *typep, const char *monthp, const char *dayp,
1820 : const char *timep)
1821 : {
1822 : const struct lookup *lp;
1823 : const char *cp;
1824 : char *dp;
1825 : char *ep;
1826 : char xs;
1827 :
1828 29600 : if ((lp = byword(monthp, mon_names)) == NULL)
1829 : {
1830 0 : error(_("invalid month name"));
1831 0 : return;
1832 : }
1833 29600 : rp->r_month = lp->l_value;
1834 29600 : rp->r_todisstd = false;
1835 29600 : rp->r_todisut = false;
1836 29600 : dp = ecpyalloc(timep);
1837 29600 : if (*dp != '\0')
1838 : {
1839 29600 : ep = dp + strlen(dp) - 1;
1840 29600 : switch (lowerit(*ep))
1841 : {
1842 5480 : case 's': /* Standard */
1843 5480 : rp->r_todisstd = true;
1844 5480 : rp->r_todisut = false;
1845 5480 : *ep = '\0';
1846 5480 : break;
1847 0 : case 'w': /* Wall */
1848 0 : rp->r_todisstd = false;
1849 0 : rp->r_todisut = false;
1850 0 : *ep = '\0';
1851 0 : break;
1852 1352 : case 'g': /* Greenwich */
1853 : case 'u': /* Universal */
1854 : case 'z': /* Zulu */
1855 1352 : rp->r_todisstd = true;
1856 1352 : rp->r_todisut = true;
1857 1352 : *ep = '\0';
1858 1352 : break;
1859 : }
1860 : }
1861 29600 : rp->r_tod = gethms(dp, _("invalid time of day"));
1862 29600 : free(dp);
1863 :
1864 : /*
1865 : * Year work.
1866 : */
1867 29600 : cp = loyearp;
1868 29600 : lp = byword(cp, begin_years);
1869 29600 : rp->r_lowasnum = lp == NULL;
1870 29600 : if (!rp->r_lowasnum)
1871 0 : switch (lp->l_value)
1872 : {
1873 0 : case YR_MINIMUM:
1874 0 : rp->r_loyear = ZIC_MIN;
1875 0 : break;
1876 0 : case YR_MAXIMUM:
1877 0 : rp->r_loyear = ZIC_MAX;
1878 0 : break;
1879 0 : default: /* "cannot happen" */
1880 0 : fprintf(stderr,
1881 : _("%s: panic: Invalid l_value %d\n"),
1882 0 : progname, lp->l_value);
1883 0 : exit(EXIT_FAILURE);
1884 : }
1885 29600 : else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_loyear, &xs) != 1)
1886 : {
1887 0 : error(_("invalid starting year"));
1888 0 : return;
1889 : }
1890 29600 : cp = hiyearp;
1891 29600 : lp = byword(cp, end_years);
1892 29600 : rp->r_hiwasnum = lp == NULL;
1893 29600 : if (!rp->r_hiwasnum)
1894 24696 : switch (lp->l_value)
1895 : {
1896 0 : case YR_MINIMUM:
1897 0 : rp->r_hiyear = ZIC_MIN;
1898 0 : break;
1899 384 : case YR_MAXIMUM:
1900 384 : rp->r_hiyear = ZIC_MAX;
1901 384 : break;
1902 24312 : case YR_ONLY:
1903 24312 : rp->r_hiyear = rp->r_loyear;
1904 24312 : break;
1905 0 : default: /* "cannot happen" */
1906 0 : fprintf(stderr,
1907 : _("%s: panic: Invalid l_value %d\n"),
1908 0 : progname, lp->l_value);
1909 0 : exit(EXIT_FAILURE);
1910 : }
1911 4904 : else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_hiyear, &xs) != 1)
1912 : {
1913 0 : error(_("invalid ending year"));
1914 0 : return;
1915 : }
1916 29600 : if (rp->r_loyear > rp->r_hiyear)
1917 : {
1918 0 : error(_("starting year greater than ending year"));
1919 0 : return;
1920 : }
1921 29600 : if (*typep != '\0')
1922 : {
1923 0 : error(_("year type \"%s\" is unsupported; use \"-\" instead"),
1924 : typep);
1925 0 : return;
1926 : }
1927 :
1928 : /*
1929 : * Day work. Accept things such as: 1 lastSunday last-Sunday
1930 : * (undocumented; warn about this) Sun<=20 Sun>=7
1931 : */
1932 29600 : dp = ecpyalloc(dayp);
1933 29600 : if ((lp = byword(dp, lasts)) != NULL)
1934 : {
1935 2736 : rp->r_dycode = DC_DOWLEQ;
1936 2736 : rp->r_wday = lp->l_value;
1937 2736 : rp->r_dayofmonth = len_months[1][rp->r_month];
1938 : }
1939 : else
1940 : {
1941 26864 : if ((ep = strchr(dp, '<')) != NULL)
1942 80 : rp->r_dycode = DC_DOWLEQ;
1943 26784 : else if ((ep = strchr(dp, '>')) != NULL)
1944 3168 : rp->r_dycode = DC_DOWGEQ;
1945 : else
1946 : {
1947 23616 : ep = dp;
1948 23616 : rp->r_dycode = DC_DOM;
1949 : }
1950 26864 : if (rp->r_dycode != DC_DOM)
1951 : {
1952 3248 : *ep++ = 0;
1953 3248 : if (*ep++ != '=')
1954 : {
1955 0 : error(_("invalid day of month"));
1956 0 : free(dp);
1957 0 : return;
1958 : }
1959 3248 : if ((lp = byword(dp, wday_names)) == NULL)
1960 : {
1961 0 : error(_("invalid weekday name"));
1962 0 : free(dp);
1963 0 : return;
1964 : }
1965 3248 : rp->r_wday = lp->l_value;
1966 : }
1967 26864 : if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1968 26864 : rp->r_dayofmonth <= 0 ||
1969 26864 : (rp->r_dayofmonth > len_months[1][rp->r_month]))
1970 : {
1971 0 : error(_("invalid day of month"));
1972 0 : free(dp);
1973 0 : return;
1974 : }
1975 : }
1976 29600 : free(dp);
1977 : }
1978 :
1979 : static void
1980 48176 : convert(const int_fast32_t val, char *const buf)
1981 : {
1982 : int i;
1983 : int shift;
1984 48176 : unsigned char *const b = (unsigned char *) buf;
1985 :
1986 240880 : for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1987 192704 : b[i] = val >> shift;
1988 48176 : }
1989 :
1990 : static void
1991 132896 : convert64(const zic_t val, char *const buf)
1992 : {
1993 : int i;
1994 : int shift;
1995 132896 : unsigned char *const b = (unsigned char *) buf;
1996 :
1997 1196064 : for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1998 1063168 : b[i] = val >> shift;
1999 132896 : }
2000 :
2001 : static void
2002 15440 : puttzcode(const int_fast32_t val, FILE *const fp)
2003 : {
2004 : char buf[4];
2005 :
2006 15440 : convert(val, buf);
2007 15440 : fwrite(buf, sizeof buf, 1, fp);
2008 15440 : }
2009 :
2010 : static void
2011 132896 : puttzcodepass(zic_t val, FILE *fp, int pass)
2012 : {
2013 132896 : if (pass == 1)
2014 0 : puttzcode(val, fp);
2015 : else
2016 : {
2017 : char buf[8];
2018 :
2019 132896 : convert64(val, buf);
2020 132896 : fwrite(buf, sizeof buf, 1, fp);
2021 : }
2022 132896 : }
2023 :
2024 : static int
2025 1627112 : atcomp(const void *avp, const void *bvp)
2026 : {
2027 1627112 : const zic_t a = ((const struct attype *) avp)->at;
2028 1627112 : const zic_t b = ((const struct attype *) bvp)->at;
2029 :
2030 1627112 : return (a < b) ? -1 : (a > b);
2031 : }
2032 :
2033 : struct timerange
2034 : {
2035 : int defaulttype;
2036 : ptrdiff_t base,
2037 : count;
2038 : int leapbase,
2039 : leapcount;
2040 : };
2041 :
2042 : static struct timerange
2043 5456 : limitrange(struct timerange r, zic_t lo, zic_t hi,
2044 : zic_t const *ats, unsigned char const *types)
2045 : {
2046 6936 : while (0 < r.count && ats[r.base] < lo)
2047 : {
2048 1480 : r.defaulttype = types[r.base];
2049 1480 : r.count--;
2050 1480 : r.base++;
2051 : }
2052 5456 : while (0 < r.leapcount && trans[r.leapbase] < lo)
2053 : {
2054 0 : r.leapcount--;
2055 0 : r.leapbase++;
2056 : }
2057 :
2058 5456 : if (hi < ZIC_MAX)
2059 : {
2060 5992 : while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
2061 3264 : r.count--;
2062 2728 : while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
2063 0 : r.leapcount--;
2064 : }
2065 :
2066 5456 : return r;
2067 : }
2068 :
2069 : static void
2070 2728 : writezone(const char *const name, const char *const string, char version,
2071 : int defaulttype)
2072 : {
2073 : FILE *fp;
2074 : ptrdiff_t i,
2075 : j;
2076 : int pass;
2077 : static const struct tzhead tzh0;
2078 : static struct tzhead tzh;
2079 2728 : bool dir_checked = false;
2080 2728 : zic_t one = 1;
2081 2728 : zic_t y2038_boundary = one << 31;
2082 2728 : ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
2083 :
2084 : /*
2085 : * Allocate the ATS and TYPES arrays via a single malloc, as this is a bit
2086 : * faster.
2087 : */
2088 2728 : zic_t *ats = emalloc(align_to(size_product(nats, sizeof *ats + 1),
2089 : _Alignof(zic_t)));
2090 2728 : void *typesptr = ats + nats;
2091 2728 : unsigned char *types = typesptr;
2092 : struct timerange rangeall,
2093 : range32,
2094 : range64;
2095 :
2096 : /*
2097 : * Sort.
2098 : */
2099 2728 : if (timecnt > 1)
2100 2400 : qsort(attypes, timecnt, sizeof *attypes, atcomp);
2101 :
2102 : /*
2103 : * Optimize.
2104 : */
2105 : {
2106 : ptrdiff_t fromi,
2107 : toi;
2108 :
2109 2728 : toi = 0;
2110 2728 : fromi = 0;
2111 138760 : for (; fromi < timecnt; ++fromi)
2112 : {
2113 136032 : if (toi != 0
2114 267800 : && ((attypes[fromi].at
2115 133536 : + utoffs[attypes[toi - 1].type])
2116 133536 : <= (attypes[toi - 1].at
2117 133536 : + utoffs[toi == 1 ? 0
2118 133536 : : attypes[toi - 2].type])))
2119 : {
2120 728 : attypes[toi - 1].type =
2121 728 : attypes[fromi].type;
2122 728 : continue;
2123 : }
2124 135304 : if (toi == 0
2125 132808 : || attypes[fromi].dontmerge
2126 131896 : || (utoffs[attypes[toi - 1].type]
2127 131896 : != utoffs[attypes[fromi].type])
2128 3736 : || (isdsts[attypes[toi - 1].type]
2129 3736 : != isdsts[attypes[fromi].type])
2130 2936 : || (desigidx[attypes[toi - 1].type]
2131 2936 : != desigidx[attypes[fromi].type]))
2132 132896 : attypes[toi++] = attypes[fromi];
2133 : }
2134 2728 : timecnt = toi;
2135 : }
2136 :
2137 2728 : if (noise && timecnt > 1200)
2138 : {
2139 0 : if (timecnt > TZ_MAX_TIMES)
2140 0 : warning(_("reference clients mishandle"
2141 : " more than %d transition times"),
2142 : TZ_MAX_TIMES);
2143 : else
2144 0 : warning(_("pre-2014 clients may mishandle"
2145 : " more than 1200 transition times"));
2146 : }
2147 :
2148 : /*
2149 : * Transfer.
2150 : */
2151 135624 : for (i = 0; i < timecnt; ++i)
2152 : {
2153 132896 : ats[i] = attypes[i].at;
2154 132896 : types[i] = attypes[i].type;
2155 : }
2156 :
2157 : /*
2158 : * Correct for leap seconds.
2159 : */
2160 135624 : for (i = 0; i < timecnt; ++i)
2161 : {
2162 132896 : j = leapcnt;
2163 132896 : while (--j >= 0)
2164 0 : if (ats[i] > trans[j] - corr[j])
2165 : {
2166 0 : ats[i] = tadd(ats[i], corr[j]);
2167 0 : break;
2168 : }
2169 : }
2170 :
2171 : /*
2172 : * Work around QTBUG-53071 for timestamps less than y2038_boundary - 1, by
2173 : * inserting a no-op transition at time y2038_boundary - 1. This works
2174 : * only for timestamps before the boundary, which should be good enough in
2175 : * practice as QTBUG-53071 should be long-dead by 2038. Do this after
2176 : * correcting for leap seconds, as the idea is to insert a transition just
2177 : * before 32-bit pg_time_t rolls around, and this occurs at a slightly
2178 : * different moment if transitions are leap-second corrected.
2179 : */
2180 2728 : if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat()
2181 0 : && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<'))
2182 : {
2183 0 : ats[timecnt] = y2038_boundary - 1;
2184 0 : types[timecnt] = types[timecnt - 1];
2185 0 : timecnt++;
2186 : }
2187 :
2188 2728 : rangeall.defaulttype = defaulttype;
2189 2728 : rangeall.base = rangeall.leapbase = 0;
2190 2728 : rangeall.count = timecnt;
2191 2728 : rangeall.leapcount = leapcnt;
2192 2728 : range64 = limitrange(rangeall, lo_time, hi_time, ats, types);
2193 2728 : range32 = limitrange(range64, INT32_MIN, INT32_MAX, ats, types);
2194 :
2195 : /*
2196 : * Remove old file, if any, to snap links.
2197 : */
2198 2728 : if (remove(name) == 0)
2199 1364 : dir_checked = true;
2200 1364 : else if (errno != ENOENT)
2201 : {
2202 0 : const char *e = strerror(errno);
2203 :
2204 0 : fprintf(stderr, _("%s: Cannot remove %s/%s: %s\n"),
2205 : progname, directory, name, e);
2206 0 : exit(EXIT_FAILURE);
2207 : }
2208 2728 : fp = fopen(name, "wb");
2209 2728 : if (!fp)
2210 : {
2211 56 : int fopen_errno = errno;
2212 :
2213 56 : if (fopen_errno == ENOENT && !dir_checked)
2214 : {
2215 56 : mkdirs(name, true);
2216 56 : fp = fopen(name, "wb");
2217 56 : fopen_errno = errno;
2218 : }
2219 56 : if (!fp)
2220 : {
2221 0 : fprintf(stderr, _("%s: Cannot create %s/%s: %s\n"),
2222 : progname, directory, name, strerror(fopen_errno));
2223 0 : exit(EXIT_FAILURE);
2224 : }
2225 : }
2226 8184 : for (pass = 1; pass <= 2; ++pass)
2227 : {
2228 : ptrdiff_t thistimei,
2229 : thistimecnt,
2230 : thistimelim;
2231 : int thisleapi,
2232 : thisleapcnt,
2233 : thisleaplim;
2234 : int currenttype,
2235 : thisdefaulttype;
2236 : bool locut,
2237 : hicut;
2238 : zic_t lo;
2239 : int old0;
2240 : char omittype[TZ_MAX_TYPES];
2241 : int typemap[TZ_MAX_TYPES];
2242 : int thistypecnt,
2243 : stdcnt,
2244 : utcnt;
2245 : char thischars[TZ_MAX_CHARS];
2246 : int thischarcnt;
2247 : bool toomanytimes;
2248 : int indmap[TZ_MAX_CHARS];
2249 :
2250 5456 : if (pass == 1)
2251 : {
2252 : /*
2253 : * Arguably the default time type in the 32-bit data should be
2254 : * range32.defaulttype, which is suited for timestamps just before
2255 : * INT32_MIN. However, zic traditionally used the time type of
2256 : * the indefinite past instead. Internet RFC 8532 says readers
2257 : * should ignore 32-bit data, so this discrepancy matters only to
2258 : * obsolete readers where the traditional type might be more
2259 : * appropriate even if it's "wrong". So, use the historical zic
2260 : * value, unless -r specifies a low cutoff that excludes some
2261 : * 32-bit timestamps.
2262 : */
2263 5456 : thisdefaulttype = (lo_time <= INT32_MIN
2264 : ? range64.defaulttype
2265 2728 : : range32.defaulttype);
2266 :
2267 2728 : thistimei = range32.base;
2268 2728 : thistimecnt = range32.count;
2269 2728 : toomanytimes = thistimecnt >> 31 >> 1 != 0;
2270 2728 : thisleapi = range32.leapbase;
2271 2728 : thisleapcnt = range32.leapcount;
2272 2728 : locut = INT32_MIN < lo_time;
2273 2728 : hicut = hi_time < INT32_MAX;
2274 : }
2275 : else
2276 : {
2277 2728 : thisdefaulttype = range64.defaulttype;
2278 2728 : thistimei = range64.base;
2279 2728 : thistimecnt = range64.count;
2280 2728 : toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
2281 2728 : thisleapi = range64.leapbase;
2282 2728 : thisleapcnt = range64.leapcount;
2283 2728 : locut = min_time < lo_time;
2284 2728 : hicut = hi_time < max_time;
2285 : }
2286 5456 : if (toomanytimes)
2287 0 : error(_("too many transition times"));
2288 :
2289 : /*
2290 : * Keep the last too-low transition if no transition is exactly at LO.
2291 : * The kept transition will be output as a LO "transition"; see
2292 : * "Output a LO_TIME transition" below. This is needed when the
2293 : * output is truncated at the start, and is also useful when catering
2294 : * to buggy 32-bit clients that do not use time type 0 for timestamps
2295 : * before the first transition.
2296 : */
2297 5456 : if (0 < thistimei && ats[thistimei] != lo_time)
2298 : {
2299 1296 : thistimei--;
2300 1296 : thistimecnt++;
2301 1296 : locut = false;
2302 : }
2303 :
2304 5456 : thistimelim = thistimei + thistimecnt;
2305 5456 : thisleaplim = thisleapi + thisleapcnt;
2306 5456 : if (thistimecnt != 0)
2307 : {
2308 4992 : if (ats[thistimei] == lo_time)
2309 0 : locut = false;
2310 4992 : if (hi_time < ZIC_MAX && ats[thistimelim - 1] == hi_time + 1)
2311 0 : hicut = false;
2312 : }
2313 5456 : memset(omittype, true, typecnt);
2314 5456 : omittype[thisdefaulttype] = false;
2315 267800 : for (i = thistimei; i < thistimelim; i++)
2316 262344 : omittype[types[i]] = false;
2317 :
2318 : /*
2319 : * Reorder types to make THISDEFAULTTYPE type 0. Use TYPEMAP to swap
2320 : * OLD0 and THISDEFAULTTYPE so that THISDEFAULTTYPE appears as type 0
2321 : * in the output instead of OLD0. TYPEMAP also omits unused types.
2322 : */
2323 5456 : old0 = strlen(omittype);
2324 :
2325 : #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
2326 :
2327 : /*
2328 : * For some pre-2011 systems: if the last-to-be-written standard (or
2329 : * daylight) type has an offset different from the most recently used
2330 : * offset, append an (unused) copy of the most recently used type (to
2331 : * help get global "altzone" and "timezone" variables set correctly).
2332 : */
2333 5456 : if (want_bloat())
2334 : {
2335 : int mrudst,
2336 : mrustd,
2337 : hidst,
2338 : histd,
2339 : type;
2340 :
2341 0 : hidst = histd = mrudst = mrustd = -1;
2342 0 : for (i = thistimei; i < thistimelim; ++i)
2343 0 : if (isdsts[types[i]])
2344 0 : mrudst = types[i];
2345 : else
2346 0 : mrustd = types[i];
2347 0 : for (i = old0; i < typecnt; i++)
2348 : {
2349 0 : int h = (i == old0 ? thisdefaulttype
2350 0 : : i == thisdefaulttype ? old0 : i);
2351 :
2352 0 : if (!omittype[h])
2353 : {
2354 0 : if (isdsts[h])
2355 0 : hidst = i;
2356 : else
2357 0 : histd = i;
2358 : }
2359 : }
2360 0 : if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
2361 0 : utoffs[hidst] != utoffs[mrudst])
2362 : {
2363 0 : isdsts[mrudst] = -1;
2364 0 : type = addtype(utoffs[mrudst],
2365 0 : &chars[desigidx[mrudst]],
2366 : true,
2367 0 : ttisstds[mrudst],
2368 0 : ttisuts[mrudst]);
2369 0 : isdsts[mrudst] = 1;
2370 0 : omittype[type] = false;
2371 : }
2372 0 : if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
2373 0 : utoffs[histd] != utoffs[mrustd])
2374 : {
2375 0 : isdsts[mrustd] = -1;
2376 0 : type = addtype(utoffs[mrustd],
2377 0 : &chars[desigidx[mrustd]],
2378 : false,
2379 0 : ttisstds[mrustd],
2380 0 : ttisuts[mrustd]);
2381 0 : isdsts[mrustd] = 0;
2382 0 : omittype[type] = false;
2383 : }
2384 : }
2385 : #endif /* !defined
2386 : * LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
2387 5456 : thistypecnt = 0;
2388 30912 : for (i = old0; i < typecnt; i++)
2389 25456 : if (!omittype[i])
2390 25240 : typemap[i == old0 ? thisdefaulttype
2391 25240 : : i == thisdefaulttype ? old0 : i]
2392 50480 : = thistypecnt++;
2393 :
2394 278256 : for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
2395 272800 : indmap[i] = -1;
2396 5456 : thischarcnt = stdcnt = utcnt = 0;
2397 30912 : for (i = old0; i < typecnt; i++)
2398 : {
2399 : char *thisabbr;
2400 :
2401 25456 : if (omittype[i])
2402 216 : continue;
2403 25240 : if (ttisstds[i])
2404 0 : stdcnt = thistypecnt;
2405 25240 : if (ttisuts[i])
2406 0 : utcnt = thistypecnt;
2407 25240 : if (indmap[desigidx[i]] >= 0)
2408 2096 : continue;
2409 23144 : thisabbr = &chars[desigidx[i]];
2410 215912 : for (j = 0; j < thischarcnt; ++j)
2411 192784 : if (strcmp(&thischars[j], thisabbr) == 0)
2412 16 : break;
2413 23144 : if (j == thischarcnt)
2414 : {
2415 23128 : strcpy(&thischars[thischarcnt], thisabbr);
2416 23128 : thischarcnt += strlen(thisabbr) + 1;
2417 : }
2418 23144 : indmap[desigidx[i]] = j;
2419 : }
2420 5456 : if (pass == 1 && !want_bloat())
2421 : {
2422 2728 : utcnt = stdcnt = thisleapcnt = 0;
2423 2728 : thistimecnt = -(locut + hicut);
2424 2728 : thistypecnt = thischarcnt = 1;
2425 2728 : thistimelim = thistimei;
2426 : }
2427 : #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
2428 5456 : tzh = tzh0;
2429 5456 : memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
2430 5456 : tzh.tzh_version[0] = version;
2431 5456 : convert(utcnt, tzh.tzh_ttisutcnt);
2432 5456 : convert(stdcnt, tzh.tzh_ttisstdcnt);
2433 5456 : convert(thisleapcnt, tzh.tzh_leapcnt);
2434 5456 : convert(locut + thistimecnt + hicut, tzh.tzh_timecnt);
2435 5456 : convert(thistypecnt, tzh.tzh_typecnt);
2436 5456 : convert(thischarcnt, tzh.tzh_charcnt);
2437 5456 : DO(tzh_magic);
2438 5456 : DO(tzh_version);
2439 5456 : DO(tzh_reserved);
2440 5456 : DO(tzh_ttisutcnt);
2441 5456 : DO(tzh_ttisstdcnt);
2442 5456 : DO(tzh_leapcnt);
2443 5456 : DO(tzh_timecnt);
2444 5456 : DO(tzh_typecnt);
2445 5456 : DO(tzh_charcnt);
2446 : #undef DO
2447 5456 : if (pass == 1 && !want_bloat())
2448 : {
2449 : /* Output a minimal data block with just one time type. */
2450 2728 : puttzcode(0, fp); /* utoff */
2451 2728 : putc(0, fp); /* dst */
2452 2728 : putc(0, fp); /* index of abbreviation */
2453 2728 : putc(0, fp); /* empty-string abbreviation */
2454 2728 : continue;
2455 : }
2456 :
2457 : /* PG: print current timezone abbreviations if requested */
2458 2728 : if (print_abbrevs && pass == 2)
2459 : {
2460 : /* Print "type" data for periods ending after print_cutoff */
2461 0 : for (i = thistimei; i < thistimelim; ++i)
2462 : {
2463 0 : if (i == thistimelim - 1 || ats[i + 1] > print_cutoff)
2464 : {
2465 0 : unsigned char tm = types[i];
2466 0 : char *thisabbrev = &thischars[indmap[desigidx[tm]]];
2467 :
2468 0 : fprintf(stdout, "%s\t%" PRIdFAST64 "%s\n",
2469 : thisabbrev,
2470 : utoffs[tm],
2471 0 : isdsts[tm] ? "\tD" : "");
2472 : }
2473 : }
2474 : /* Print the default type if we have no transitions at all */
2475 0 : if (thistimei >= thistimelim)
2476 : {
2477 0 : unsigned char tm = defaulttype;
2478 0 : char *thisabbrev = &thischars[indmap[desigidx[tm]]];
2479 :
2480 0 : fprintf(stdout, "%s\t%" PRIdFAST64 "%s\n",
2481 : thisabbrev,
2482 : utoffs[tm],
2483 0 : isdsts[tm] ? "\tD" : "");
2484 : }
2485 : }
2486 :
2487 : /*
2488 : * Output a LO_TIME transition if needed; see limitrange. But do not
2489 : * go below the minimum representable value for this pass.
2490 : */
2491 2728 : lo = pass == 1 && lo_time < INT32_MIN ? INT32_MIN : lo_time;
2492 :
2493 2728 : if (locut)
2494 0 : puttzcodepass(lo, fp, pass);
2495 135624 : for (i = thistimei; i < thistimelim; ++i)
2496 : {
2497 132896 : zic_t at = ats[i] < lo ? lo : ats[i];
2498 :
2499 132896 : puttzcodepass(at, fp, pass);
2500 : }
2501 2728 : if (hicut)
2502 0 : puttzcodepass(hi_time + 1, fp, pass);
2503 2728 : currenttype = 0;
2504 2728 : if (locut)
2505 0 : putc(currenttype, fp);
2506 135624 : for (i = thistimei; i < thistimelim; ++i)
2507 : {
2508 132896 : currenttype = typemap[types[i]];
2509 132896 : putc(currenttype, fp);
2510 : }
2511 2728 : if (hicut)
2512 0 : putc(currenttype, fp);
2513 :
2514 15456 : for (i = old0; i < typecnt; i++)
2515 : {
2516 22728 : int h = (i == old0 ? thisdefaulttype
2517 10000 : : i == thisdefaulttype ? old0 : i);
2518 :
2519 12728 : if (!omittype[h])
2520 : {
2521 12712 : puttzcode(utoffs[h], fp);
2522 12712 : putc(isdsts[h], fp);
2523 12712 : putc(indmap[desigidx[h]], fp);
2524 : }
2525 : }
2526 2728 : if (thischarcnt != 0)
2527 2728 : fwrite(thischars, sizeof thischars[0],
2528 : thischarcnt, fp);
2529 2728 : for (i = thisleapi; i < thisleaplim; ++i)
2530 : {
2531 : zic_t todo;
2532 :
2533 0 : if (roll[i])
2534 : {
2535 0 : if (timecnt == 0 || trans[i] < ats[0])
2536 : {
2537 0 : j = 0;
2538 0 : while (isdsts[j])
2539 0 : if (++j >= typecnt)
2540 : {
2541 0 : j = 0;
2542 0 : break;
2543 : }
2544 : }
2545 : else
2546 : {
2547 0 : j = 1;
2548 0 : while (j < timecnt &&
2549 0 : trans[i] >= ats[j])
2550 0 : ++j;
2551 0 : j = types[j - 1];
2552 : }
2553 0 : todo = tadd(trans[i], -utoffs[j]);
2554 : }
2555 : else
2556 0 : todo = trans[i];
2557 0 : puttzcodepass(todo, fp, pass);
2558 0 : puttzcode(corr[i], fp);
2559 : }
2560 2728 : if (stdcnt != 0)
2561 0 : for (i = old0; i < typecnt; i++)
2562 0 : if (!omittype[i])
2563 0 : putc(ttisstds[i], fp);
2564 2728 : if (utcnt != 0)
2565 0 : for (i = old0; i < typecnt; i++)
2566 0 : if (!omittype[i])
2567 0 : putc(ttisuts[i], fp);
2568 : }
2569 2728 : fprintf(fp, "\n%s\n", string);
2570 2728 : close_file(fp, directory, name);
2571 2728 : free(ats);
2572 2728 : }
2573 :
2574 : static char const *
2575 110184 : abbroffset(char *buf, zic_t offset)
2576 : {
2577 110184 : char sign = '+';
2578 : int seconds,
2579 : minutes;
2580 :
2581 110184 : if (offset < 0)
2582 : {
2583 52488 : offset = -offset;
2584 52488 : sign = '-';
2585 : }
2586 :
2587 110184 : seconds = offset % SECSPERMIN;
2588 110184 : offset /= SECSPERMIN;
2589 110184 : minutes = offset % MINSPERHOUR;
2590 110184 : offset /= MINSPERHOUR;
2591 110184 : if (100 <= offset)
2592 : {
2593 0 : error(_("%%z UT offset magnitude exceeds 99:59:59"));
2594 0 : return "%z";
2595 : }
2596 : else
2597 : {
2598 110184 : char *p = buf;
2599 :
2600 110184 : *p++ = sign;
2601 110184 : *p++ = '0' + offset / 10;
2602 110184 : *p++ = '0' + offset % 10;
2603 110184 : if (minutes | seconds)
2604 : {
2605 3232 : *p++ = '0' + minutes / 10;
2606 3232 : *p++ = '0' + minutes % 10;
2607 3232 : if (seconds)
2608 : {
2609 0 : *p++ = '0' + seconds / 10;
2610 0 : *p++ = '0' + seconds % 10;
2611 : }
2612 : }
2613 110184 : *p = '\0';
2614 110184 : return buf;
2615 : }
2616 : }
2617 :
2618 : static size_t
2619 272008 : doabbr(char *abbr, struct zone const *zp, char const *letters,
2620 : bool isdst, zic_t save, bool doquotes)
2621 6808 : {
2622 : char *cp;
2623 : char *slashp;
2624 : size_t len;
2625 272008 : char const *format = zp->z_format;
2626 :
2627 272008 : slashp = strchr(format, '/');
2628 272008 : if (slashp == NULL)
2629 : {
2630 : char letterbuf[PERCENT_Z_LEN_BOUND + 1];
2631 :
2632 264944 : if (zp->z_format_specifier == 'z')
2633 110184 : letters = abbroffset(letterbuf, zp->z_stdoff + save);
2634 154760 : else if (!letters)
2635 5744 : letters = "%s";
2636 264944 : sprintf(abbr, format, letters);
2637 : }
2638 7064 : else if (isdst)
2639 : {
2640 3880 : strcpy(abbr, slashp + 1);
2641 : }
2642 : else
2643 : {
2644 3184 : memcpy(abbr, format, slashp - format);
2645 3184 : abbr[slashp - format] = '\0';
2646 : }
2647 272008 : len = strlen(abbr);
2648 272008 : if (!doquotes)
2649 268440 : return len;
2650 10376 : for (cp = abbr; is_alpha(*cp); cp++)
2651 6808 : continue;
2652 3568 : if (len > 0 && *cp == '\0')
2653 2088 : return len;
2654 1480 : abbr[len + 2] = '\0';
2655 1480 : abbr[len + 1] = '>';
2656 1480 : memmove(abbr + 1, abbr, len);
2657 1480 : abbr[0] = '<';
2658 1480 : return len + 2;
2659 : }
2660 :
2661 : static void
2662 170728 : updateminmax(const zic_t x)
2663 : {
2664 170728 : if (min_year > x)
2665 3144 : min_year = x;
2666 170728 : if (max_year < x)
2667 7232 : max_year = x;
2668 170728 : }
2669 :
2670 : static int
2671 3360 : stringoffset(char *result, zic_t offset)
2672 : {
2673 : int hours;
2674 : int minutes;
2675 : int seconds;
2676 3360 : bool negative = offset < 0;
2677 3360 : int len = negative;
2678 :
2679 3360 : if (negative)
2680 : {
2681 1456 : offset = -offset;
2682 1456 : result[0] = '-';
2683 : }
2684 3360 : seconds = offset % SECSPERMIN;
2685 3360 : offset /= SECSPERMIN;
2686 3360 : minutes = offset % MINSPERHOUR;
2687 3360 : offset /= MINSPERHOUR;
2688 3360 : hours = offset;
2689 3360 : if (hours >= HOURSPERDAY * DAYSPERWEEK)
2690 : {
2691 0 : result[0] = '\0';
2692 0 : return 0;
2693 : }
2694 3360 : len += sprintf(result + len, "%d", hours);
2695 3360 : if (minutes != 0 || seconds != 0)
2696 : {
2697 128 : len += sprintf(result + len, ":%02d", minutes);
2698 128 : if (seconds != 0)
2699 0 : len += sprintf(result + len, ":%02d", seconds);
2700 : }
2701 3360 : return len;
2702 : }
2703 :
2704 : static int
2705 1680 : stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff)
2706 : {
2707 1680 : zic_t tod = rp->r_tod;
2708 1680 : int compat = 0;
2709 :
2710 1680 : if (rp->r_dycode == DC_DOM)
2711 : {
2712 : int month,
2713 : total;
2714 :
2715 0 : if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2716 0 : return -1;
2717 0 : total = 0;
2718 0 : for (month = 0; month < rp->r_month; ++month)
2719 0 : total += len_months[0][month];
2720 : /* Omit the "J" in Jan and Feb, as that's shorter. */
2721 0 : if (rp->r_month <= 1)
2722 0 : result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
2723 : else
2724 0 : result += sprintf(result, "J%d", total + rp->r_dayofmonth);
2725 : }
2726 : else
2727 : {
2728 : int week;
2729 1680 : int wday = rp->r_wday;
2730 : int wdayoff;
2731 :
2732 1680 : if (rp->r_dycode == DC_DOWGEQ)
2733 : {
2734 1000 : wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2735 1000 : if (wdayoff)
2736 40 : compat = 2013;
2737 1000 : wday -= wdayoff;
2738 1000 : tod += wdayoff * SECSPERDAY;
2739 1000 : week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2740 : }
2741 680 : else if (rp->r_dycode == DC_DOWLEQ)
2742 : {
2743 680 : if (rp->r_dayofmonth == len_months[1][rp->r_month])
2744 648 : week = 5;
2745 : else
2746 : {
2747 32 : wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2748 32 : if (wdayoff)
2749 32 : compat = 2013;
2750 32 : wday -= wdayoff;
2751 32 : tod += wdayoff * SECSPERDAY;
2752 32 : week = rp->r_dayofmonth / DAYSPERWEEK;
2753 : }
2754 : }
2755 : else
2756 0 : return -1; /* "cannot happen" */
2757 1680 : if (wday < 0)
2758 32 : wday += DAYSPERWEEK;
2759 1680 : result += sprintf(result, "M%d.%d.%d",
2760 1680 : rp->r_month + 1, week, wday);
2761 : }
2762 1680 : if (rp->r_todisut)
2763 608 : tod += stdoff;
2764 1680 : if (rp->r_todisstd && !rp->r_isdst)
2765 384 : tod += save;
2766 1680 : if (tod != 2 * SECSPERMIN * MINSPERHOUR)
2767 : {
2768 608 : *result++ = '/';
2769 608 : if (!stringoffset(result, tod))
2770 0 : return -1;
2771 608 : if (tod < 0)
2772 : {
2773 16 : if (compat < 2013)
2774 16 : compat = 2013;
2775 : }
2776 592 : else if (SECSPERDAY <= tod)
2777 : {
2778 64 : if (compat < 1994)
2779 8 : compat = 1994;
2780 : }
2781 : }
2782 1680 : return compat;
2783 : }
2784 :
2785 : static int
2786 12824 : rule_cmp(struct rule const *a, struct rule const *b)
2787 : {
2788 12824 : if (!a)
2789 880 : return -!!b;
2790 11944 : if (!b)
2791 0 : return 1;
2792 11944 : if (a->r_hiyear != b->r_hiyear)
2793 11400 : return a->r_hiyear < b->r_hiyear ? -1 : 1;
2794 544 : if (a->r_month - b->r_month != 0)
2795 544 : return a->r_month - b->r_month;
2796 0 : return a->r_dayofmonth - b->r_dayofmonth;
2797 : }
2798 :
2799 : static int
2800 2728 : stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
2801 : {
2802 : const struct zone *zp;
2803 : struct rule *rp;
2804 : struct rule *stdrp;
2805 : struct rule *dstrp;
2806 : ptrdiff_t i;
2807 : const char *abbrvar;
2808 2728 : int compat = 0;
2809 : int c;
2810 : size_t len;
2811 : int offsetlen;
2812 : struct rule stdr,
2813 : dstr;
2814 :
2815 2728 : result[0] = '\0';
2816 :
2817 : /*
2818 : * Internet RFC 8536 section 5.1 says to use an empty TZ string if future
2819 : * timestamps are truncated.
2820 : */
2821 2728 : if (hi_time < max_time)
2822 0 : return -1;
2823 :
2824 2728 : zp = zpfirst + zonecount - 1;
2825 2728 : stdrp = dstrp = NULL;
2826 22936 : for (i = 0; i < zp->z_nrules; ++i)
2827 : {
2828 20208 : rp = &zp->z_rules[i];
2829 20208 : if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
2830 18528 : continue;
2831 1680 : if (!rp->r_isdst)
2832 : {
2833 840 : if (stdrp == NULL)
2834 840 : stdrp = rp;
2835 : else
2836 0 : return -1;
2837 : }
2838 : else
2839 : {
2840 840 : if (dstrp == NULL)
2841 840 : dstrp = rp;
2842 : else
2843 0 : return -1;
2844 : }
2845 : }
2846 2728 : if (stdrp == NULL && dstrp == NULL)
2847 : {
2848 : /*
2849 : * There are no rules running through "max". Find the latest std rule
2850 : * in stdabbrrp and latest rule of any type in stdrp.
2851 : */
2852 1888 : struct rule *stdabbrrp = NULL;
2853 :
2854 10528 : for (i = 0; i < zp->z_nrules; ++i)
2855 : {
2856 8640 : rp = &zp->z_rules[i];
2857 8640 : if (!rp->r_isdst && rule_cmp(stdabbrrp, rp) < 0)
2858 992 : stdabbrrp = rp;
2859 8640 : if (rule_cmp(stdrp, rp) < 0)
2860 1488 : stdrp = rp;
2861 : }
2862 1888 : if (stdrp != NULL && stdrp->r_isdst)
2863 : {
2864 : /* Perpetual DST. */
2865 0 : dstr.r_month = TM_JANUARY;
2866 0 : dstr.r_dycode = DC_DOM;
2867 0 : dstr.r_dayofmonth = 1;
2868 0 : dstr.r_tod = 0;
2869 0 : dstr.r_todisstd = dstr.r_todisut = false;
2870 0 : dstr.r_isdst = stdrp->r_isdst;
2871 0 : dstr.r_save = stdrp->r_save;
2872 0 : dstr.r_abbrvar = stdrp->r_abbrvar;
2873 0 : stdr.r_month = TM_DECEMBER;
2874 0 : stdr.r_dycode = DC_DOM;
2875 0 : stdr.r_dayofmonth = 31;
2876 0 : stdr.r_tod = SECSPERDAY + stdrp->r_save;
2877 0 : stdr.r_todisstd = stdr.r_todisut = false;
2878 0 : stdr.r_isdst = false;
2879 0 : stdr.r_save = 0;
2880 : stdr.r_abbrvar
2881 0 : = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2882 0 : dstrp = &dstr;
2883 0 : stdrp = &stdr;
2884 : }
2885 : }
2886 2728 : if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_isdst))
2887 0 : return -1;
2888 2728 : abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2889 2728 : len = doabbr(result, zp, abbrvar, false, 0, true);
2890 2728 : offsetlen = stringoffset(result + len, -zp->z_stdoff);
2891 2728 : if (!offsetlen)
2892 : {
2893 0 : result[0] = '\0';
2894 0 : return -1;
2895 : }
2896 2728 : len += offsetlen;
2897 2728 : if (dstrp == NULL)
2898 1888 : return compat;
2899 1680 : len += doabbr(result + len, zp, dstrp->r_abbrvar,
2900 840 : dstrp->r_isdst, dstrp->r_save, true);
2901 840 : if (dstrp->r_save != SECSPERMIN * MINSPERHOUR)
2902 : {
2903 24 : offsetlen = stringoffset(result + len,
2904 24 : -(zp->z_stdoff + dstrp->r_save));
2905 24 : if (!offsetlen)
2906 : {
2907 0 : result[0] = '\0';
2908 0 : return -1;
2909 : }
2910 24 : len += offsetlen;
2911 : }
2912 840 : result[len++] = ',';
2913 840 : c = stringrule(result + len, dstrp, dstrp->r_save, zp->z_stdoff);
2914 840 : if (c < 0)
2915 : {
2916 0 : result[0] = '\0';
2917 0 : return -1;
2918 : }
2919 840 : if (compat < c)
2920 56 : compat = c;
2921 840 : len += strlen(result + len);
2922 840 : result[len++] = ',';
2923 840 : c = stringrule(result + len, stdrp, dstrp->r_save, zp->z_stdoff);
2924 840 : if (c < 0)
2925 : {
2926 0 : result[0] = '\0';
2927 0 : return -1;
2928 : }
2929 840 : if (compat < c)
2930 8 : compat = c;
2931 840 : return compat;
2932 : }
2933 :
2934 : static void
2935 2728 : outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
2936 : {
2937 : const struct zone *zp;
2938 : struct rule *rp;
2939 : ptrdiff_t i,
2940 : j;
2941 : bool usestart,
2942 : useuntil;
2943 : zic_t starttime,
2944 : untiltime;
2945 : zic_t stdoff;
2946 : zic_t save;
2947 : zic_t year;
2948 : zic_t startoff;
2949 : bool startttisstd;
2950 : bool startttisut;
2951 : int type;
2952 : char *startbuf;
2953 : char *ab;
2954 : char *envvar;
2955 : int max_abbr_len;
2956 : int max_envvar_len;
2957 : bool prodstic; /* all rules are min to max */
2958 : int compat;
2959 : bool do_extend;
2960 : char version;
2961 2728 : ptrdiff_t lastatmax = -1;
2962 2728 : zic_t one = 1;
2963 2728 : zic_t y2038_boundary = one << 31;
2964 : zic_t max_year0;
2965 2728 : int defaulttype = -1;
2966 :
2967 2728 : max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2968 2728 : max_envvar_len = 2 * max_abbr_len + 5 * 9;
2969 2728 : startbuf = emalloc(max_abbr_len + 1);
2970 2728 : ab = emalloc(max_abbr_len + 1);
2971 2728 : envvar = emalloc(max_envvar_len + 1);
2972 2728 : INITIALIZE(untiltime);
2973 2728 : INITIALIZE(starttime);
2974 :
2975 : /*
2976 : * Now. . .finally. . .generate some useful data!
2977 : */
2978 2728 : timecnt = 0;
2979 2728 : typecnt = 0;
2980 2728 : charcnt = 0;
2981 2728 : prodstic = zonecount == 1;
2982 :
2983 : /*
2984 : * Thanks to Earl Chew for noting the need to unconditionally initialize
2985 : * startttisstd.
2986 : */
2987 2728 : startttisstd = false;
2988 2728 : startttisut = false;
2989 2728 : min_year = max_year = EPOCH_YEAR;
2990 2728 : if (leapseen)
2991 : {
2992 0 : updateminmax(leapminyear);
2993 0 : updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
2994 : }
2995 18384 : for (i = 0; i < zonecount; ++i)
2996 : {
2997 15656 : zp = &zpfirst[i];
2998 15656 : if (i < zonecount - 1)
2999 12928 : updateminmax(zp->z_untilrule.r_loyear);
3000 138160 : for (j = 0; j < zp->z_nrules; ++j)
3001 : {
3002 122504 : rp = &zp->z_rules[j];
3003 122504 : if (rp->r_lowasnum)
3004 122504 : updateminmax(rp->r_loyear);
3005 122504 : if (rp->r_hiwasnum)
3006 35296 : updateminmax(rp->r_hiyear);
3007 122504 : if (rp->r_lowasnum || rp->r_hiwasnum)
3008 122504 : prodstic = false;
3009 : }
3010 : }
3011 :
3012 : /*
3013 : * Generate lots of data if a rule can't cover all future times.
3014 : */
3015 2728 : compat = stringzone(envvar, zpfirst, zonecount);
3016 2728 : version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
3017 2728 : do_extend = compat < 0;
3018 2728 : if (noise)
3019 : {
3020 0 : if (!*envvar)
3021 0 : warning("%s %s",
3022 : _("no POSIX environment variable for zone"),
3023 0 : zpfirst->z_name);
3024 0 : else if (compat != 0)
3025 : {
3026 : /*
3027 : * Circa-COMPAT clients, and earlier clients, might not work for
3028 : * this zone when given dates before 1970 or after 2038.
3029 : */
3030 0 : warning(_("%s: pre-%d clients may mishandle"
3031 : " distant timestamps"),
3032 0 : zpfirst->z_name, compat);
3033 : }
3034 : }
3035 2728 : if (do_extend)
3036 : {
3037 : /*
3038 : * Search through a couple of extra years past the obvious 400, to
3039 : * avoid edge cases. For example, suppose a non-POSIX rule applies
3040 : * from 2012 onwards and has transitions in March and September, plus
3041 : * some one-off transitions in November 2013. If zic looked only at
3042 : * the last 400 years, it would set max_year=2413, with the intent
3043 : * that the 400 years 2014 through 2413 will be repeated. The last
3044 : * transition listed in the tzfile would be in 2413-09, less than 400
3045 : * years after the last one-off transition in 2013-11. Two years
3046 : * might be overkill, but with the kind of edge cases available we're
3047 : * not sure that one year would suffice.
3048 : */
3049 : enum
3050 : {
3051 : years_of_observations = YEARSPERREPEAT + 2};
3052 :
3053 0 : if (min_year >= ZIC_MIN + years_of_observations)
3054 0 : min_year -= years_of_observations;
3055 : else
3056 0 : min_year = ZIC_MIN;
3057 0 : if (max_year <= ZIC_MAX - years_of_observations)
3058 0 : max_year += years_of_observations;
3059 : else
3060 0 : max_year = ZIC_MAX;
3061 :
3062 : /*
3063 : * Regardless of any of the above, for a "proDSTic" zone which
3064 : * specifies that its rules always have and always will be in effect,
3065 : * we only need one cycle to define the zone.
3066 : */
3067 0 : if (prodstic)
3068 : {
3069 0 : min_year = 1900;
3070 0 : max_year = min_year + years_of_observations;
3071 : }
3072 : }
3073 2728 : max_year0 = max_year;
3074 2728 : if (want_bloat())
3075 : {
3076 : /*
3077 : * For the benefit of older systems, generate data from 1900 through
3078 : * 2038.
3079 : */
3080 0 : if (min_year > 1900)
3081 0 : min_year = 1900;
3082 0 : if (max_year < 2038)
3083 0 : max_year = 2038;
3084 : }
3085 :
3086 18384 : for (i = 0; i < zonecount; ++i)
3087 : {
3088 15656 : struct rule *prevrp = NULL;
3089 :
3090 : /*
3091 : * A guess that may well be corrected later.
3092 : */
3093 15656 : save = 0;
3094 15656 : zp = &zpfirst[i];
3095 15656 : usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
3096 15656 : useuntil = i < (zonecount - 1);
3097 15656 : if (useuntil && zp->z_untiltime <= min_time)
3098 0 : continue;
3099 15656 : stdoff = zp->z_stdoff;
3100 15656 : eat(zp->z_filename, zp->z_linenum);
3101 15656 : *startbuf = '\0';
3102 15656 : startoff = zp->z_stdoff;
3103 15656 : if (zp->z_nrules == 0)
3104 : {
3105 9600 : save = zp->z_save;
3106 9600 : doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
3107 9600 : type = addtype(oadd(zp->z_stdoff, save),
3108 9600 : startbuf, zp->z_isdst, startttisstd,
3109 : startttisut);
3110 9600 : if (usestart)
3111 : {
3112 6872 : addtt(starttime, type);
3113 6872 : usestart = false;
3114 : }
3115 : else
3116 2728 : defaulttype = type;
3117 : }
3118 : else
3119 546464 : for (year = min_year; year <= max_year; ++year)
3120 : {
3121 544880 : if (useuntil && year > zp->z_untilrule.r_hiyear)
3122 4472 : break;
3123 :
3124 : /*
3125 : * Mark which rules to do in the current year. For those to
3126 : * do, calculate rpytime(rp, year); The former TYPE field was
3127 : * also considered here.
3128 : */
3129 11661896 : for (j = 0; j < zp->z_nrules; ++j)
3130 : {
3131 11121488 : rp = &zp->z_rules[j];
3132 11121488 : eats(zp->z_filename, zp->z_linenum,
3133 : rp->r_filename, rp->r_linenum);
3134 14535528 : rp->r_todo = year >= rp->r_loyear &&
3135 3414040 : year <= rp->r_hiyear;
3136 11121488 : if (rp->r_todo)
3137 : {
3138 263128 : rp->r_temp = rpytime(rp, year);
3139 : rp->r_todo
3140 526256 : = (rp->r_temp < y2038_boundary
3141 263128 : || year <= max_year0);
3142 : }
3143 : }
3144 : for (;;)
3145 255720 : {
3146 : ptrdiff_t k;
3147 : zic_t jtime,
3148 : ktime;
3149 : zic_t offset;
3150 :
3151 796128 : INITIALIZE(ktime);
3152 796128 : if (useuntil)
3153 : {
3154 : /*
3155 : * Turn untiltime into UT assuming the current stdoff
3156 : * and save values.
3157 : */
3158 574424 : untiltime = zp->z_untiltime;
3159 574424 : if (!zp->z_untilrule.r_todisut)
3160 561296 : untiltime = tadd(untiltime,
3161 : -stdoff);
3162 574424 : if (!zp->z_untilrule.r_todisstd)
3163 421744 : untiltime = tadd(untiltime,
3164 : -save);
3165 : }
3166 :
3167 : /*
3168 : * Find the rule (of those to do, if any) that takes
3169 : * effect earliest in the year.
3170 : */
3171 796128 : k = -1;
3172 18231416 : for (j = 0; j < zp->z_nrules; ++j)
3173 : {
3174 17435288 : rp = &zp->z_rules[j];
3175 17435288 : if (!rp->r_todo)
3176 17037496 : continue;
3177 397792 : eats(zp->z_filename, zp->z_linenum,
3178 : rp->r_filename, rp->r_linenum);
3179 397792 : offset = rp->r_todisut ? 0 : stdoff;
3180 397792 : if (!rp->r_todisstd)
3181 266272 : offset = oadd(offset, save);
3182 397792 : jtime = rp->r_temp;
3183 397792 : if (jtime == min_time ||
3184 397792 : jtime == max_time)
3185 0 : continue;
3186 397792 : jtime = tadd(jtime, -offset);
3187 397792 : if (k < 0 || jtime < ktime)
3188 : {
3189 325712 : k = j;
3190 325712 : ktime = jtime;
3191 : }
3192 72080 : else if (jtime == ktime)
3193 : {
3194 0 : char const *dup_rules_msg =
3195 : _("two rules for same instant");
3196 :
3197 0 : eats(zp->z_filename, zp->z_linenum,
3198 : rp->r_filename, rp->r_linenum);
3199 0 : warning("%s", dup_rules_msg);
3200 0 : rp = &zp->z_rules[k];
3201 0 : eats(zp->z_filename, zp->z_linenum,
3202 : rp->r_filename, rp->r_linenum);
3203 0 : error("%s", dup_rules_msg);
3204 : }
3205 : }
3206 796128 : if (k < 0)
3207 535944 : break; /* go on to next year */
3208 260184 : rp = &zp->z_rules[k];
3209 260184 : rp->r_todo = false;
3210 260184 : if (useuntil && ktime >= untiltime)
3211 2920 : break;
3212 257264 : save = rp->r_save;
3213 257264 : if (usestart && ktime == starttime)
3214 456 : usestart = false;
3215 257264 : if (usestart)
3216 : {
3217 248320 : if (ktime < starttime)
3218 : {
3219 132160 : startoff = oadd(zp->z_stdoff,
3220 : save);
3221 132160 : doabbr(startbuf, zp,
3222 : rp->r_abbrvar,
3223 132160 : rp->r_isdst,
3224 : rp->r_save,
3225 : false);
3226 132160 : continue;
3227 : }
3228 116160 : if (*startbuf == '\0'
3229 3152 : && startoff == oadd(zp->z_stdoff,
3230 : save))
3231 : {
3232 1576 : doabbr(startbuf,
3233 : zp,
3234 : rp->r_abbrvar,
3235 1576 : rp->r_isdst,
3236 : rp->r_save,
3237 : false);
3238 : }
3239 : }
3240 125104 : eats(zp->z_filename, zp->z_linenum,
3241 : rp->r_filename, rp->r_linenum);
3242 125104 : doabbr(ab, zp, rp->r_abbrvar,
3243 125104 : rp->r_isdst, rp->r_save, false);
3244 125104 : offset = oadd(zp->z_stdoff, rp->r_save);
3245 125104 : if (!want_bloat() && !useuntil && !do_extend
3246 43344 : && prevrp
3247 42104 : && rp->r_hiyear == ZIC_MAX
3248 4816 : && prevrp->r_hiyear == ZIC_MAX)
3249 1544 : break;
3250 123560 : type = addtype(offset, ab, rp->r_isdst,
3251 123560 : rp->r_todisstd, rp->r_todisut);
3252 123560 : if (defaulttype < 0 && !rp->r_isdst)
3253 0 : defaulttype = type;
3254 123560 : if (rp->r_hiyear == ZIC_MAX
3255 7816 : && !(0 <= lastatmax
3256 6904 : && ktime < attypes[lastatmax].at))
3257 7816 : lastatmax = timecnt;
3258 123560 : addtt(ktime, type);
3259 123560 : prevrp = rp;
3260 : }
3261 : }
3262 15656 : if (usestart)
3263 : {
3264 5600 : if (*startbuf == '\0' &&
3265 0 : zp->z_format != NULL &&
3266 0 : strchr(zp->z_format, '%') == NULL &&
3267 0 : strchr(zp->z_format, '/') == NULL)
3268 0 : strcpy(startbuf, zp->z_format);
3269 5600 : eat(zp->z_filename, zp->z_linenum);
3270 5600 : if (*startbuf == '\0')
3271 0 : error(_("cannot determine time zone abbreviation to use just after until time"));
3272 : else
3273 : {
3274 5600 : bool isdst = startoff != zp->z_stdoff;
3275 :
3276 5600 : type = addtype(startoff, startbuf, isdst,
3277 : startttisstd, startttisut);
3278 5600 : if (defaulttype < 0 && !isdst)
3279 0 : defaulttype = type;
3280 5600 : addtt(starttime, type);
3281 : }
3282 : }
3283 :
3284 : /*
3285 : * Now we may get to set starttime for the next zone line.
3286 : */
3287 15656 : if (useuntil)
3288 : {
3289 12928 : startttisstd = zp->z_untilrule.r_todisstd;
3290 12928 : startttisut = zp->z_untilrule.r_todisut;
3291 12928 : starttime = zp->z_untiltime;
3292 12928 : if (!startttisstd)
3293 10776 : starttime = tadd(starttime, -save);
3294 12928 : if (!startttisut)
3295 12336 : starttime = tadd(starttime, -stdoff);
3296 : }
3297 : }
3298 2728 : if (defaulttype < 0)
3299 0 : defaulttype = 0;
3300 2728 : if (0 <= lastatmax)
3301 912 : attypes[lastatmax].dontmerge = true;
3302 2728 : if (do_extend)
3303 : {
3304 : /*
3305 : * If we're extending the explicitly listed observations for 400 years
3306 : * because we can't fill the POSIX-TZ field, check whether we actually
3307 : * ended up explicitly listing observations through that period. If
3308 : * there aren't any near the end of the 400-year period, add a
3309 : * redundant one at the end of the final year, to make it clear that
3310 : * we are claiming to have definite knowledge of the lack of
3311 : * transitions up to that point.
3312 : */
3313 : struct rule xr;
3314 : struct attype *lastat;
3315 :
3316 0 : xr.r_month = TM_JANUARY;
3317 0 : xr.r_dycode = DC_DOM;
3318 0 : xr.r_dayofmonth = 1;
3319 0 : xr.r_tod = 0;
3320 0 : for (lastat = attypes, i = 1; i < timecnt; i++)
3321 0 : if (attypes[i].at > lastat->at)
3322 0 : lastat = &attypes[i];
3323 0 : if (!lastat || lastat->at < rpytime(&xr, max_year - 1))
3324 : {
3325 0 : addtt(rpytime(&xr, max_year + 1),
3326 0 : lastat ? lastat->type : defaulttype);
3327 0 : attypes[timecnt - 1].dontmerge = true;
3328 : }
3329 : }
3330 2728 : writezone(zpfirst->z_name, envvar, version, defaulttype);
3331 2728 : free(startbuf);
3332 2728 : free(ab);
3333 2728 : free(envvar);
3334 2728 : }
3335 :
3336 : static void
3337 136032 : addtt(zic_t starttime, int type)
3338 : {
3339 136032 : attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
3340 136032 : attypes[timecnt].at = starttime;
3341 136032 : attypes[timecnt].dontmerge = false;
3342 136032 : attypes[timecnt].type = type;
3343 136032 : ++timecnt;
3344 136032 : }
3345 :
3346 : static int
3347 138760 : addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
3348 : {
3349 : int i,
3350 : j;
3351 :
3352 138760 : if (!(-1L - 2147483647L <= utoff && utoff <= 2147483647L))
3353 : {
3354 0 : error(_("UT offset out of range"));
3355 0 : exit(EXIT_FAILURE);
3356 : }
3357 138760 : if (!want_bloat())
3358 138760 : ttisstd = ttisut = false;
3359 :
3360 1517800 : for (j = 0; j < charcnt; ++j)
3361 1506184 : if (strcmp(&chars[j], abbr) == 0)
3362 127144 : break;
3363 138760 : if (j == charcnt)
3364 11616 : newabbr(abbr);
3365 : else
3366 : {
3367 : /* If there's already an entry, return its index. */
3368 471920 : for (i = 0; i < typecnt; i++)
3369 470808 : if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
3370 126032 : && ttisstd == ttisstds[i] && ttisut == ttisuts[i])
3371 126032 : return i;
3372 : }
3373 :
3374 : /*
3375 : * There isn't one; add a new one, unless there are already too many.
3376 : */
3377 12728 : if (typecnt >= TZ_MAX_TYPES)
3378 : {
3379 0 : error(_("too many local time types"));
3380 0 : exit(EXIT_FAILURE);
3381 : }
3382 12728 : i = typecnt++;
3383 12728 : utoffs[i] = utoff;
3384 12728 : isdsts[i] = isdst;
3385 12728 : ttisstds[i] = ttisstd;
3386 12728 : ttisuts[i] = ttisut;
3387 12728 : desigidx[i] = j;
3388 12728 : return i;
3389 : }
3390 :
3391 : static void
3392 0 : leapadd(zic_t t, int correction, int rolling)
3393 : {
3394 : int i;
3395 :
3396 0 : if (TZ_MAX_LEAPS <= leapcnt)
3397 : {
3398 0 : error(_("too many leap seconds"));
3399 0 : exit(EXIT_FAILURE);
3400 : }
3401 0 : for (i = 0; i < leapcnt; ++i)
3402 0 : if (t <= trans[i])
3403 0 : break;
3404 0 : memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans);
3405 0 : memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr);
3406 0 : memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll);
3407 0 : trans[i] = t;
3408 0 : corr[i] = correction;
3409 0 : roll[i] = rolling;
3410 0 : ++leapcnt;
3411 0 : }
3412 :
3413 : static void
3414 0 : adjleap(void)
3415 : {
3416 : int i;
3417 0 : zic_t last = 0;
3418 0 : zic_t prevtrans = 0;
3419 :
3420 : /*
3421 : * propagate leap seconds forward
3422 : */
3423 0 : for (i = 0; i < leapcnt; ++i)
3424 : {
3425 0 : if (trans[i] - prevtrans < 28 * SECSPERDAY)
3426 : {
3427 0 : error(_("Leap seconds too close together"));
3428 0 : exit(EXIT_FAILURE);
3429 : }
3430 0 : prevtrans = trans[i];
3431 0 : trans[i] = tadd(trans[i], last);
3432 0 : last = corr[i] += last;
3433 : }
3434 :
3435 0 : if (leapexpires < 0)
3436 : {
3437 0 : leapexpires = comment_leapexpires;
3438 0 : if (0 <= leapexpires)
3439 0 : warning(_("\"#expires\" is obsolescent; use \"Expires\""));
3440 : }
3441 :
3442 0 : if (0 <= leapexpires)
3443 : {
3444 0 : leapexpires = oadd(leapexpires, last);
3445 0 : if (!(leapcnt == 0 || (trans[leapcnt - 1] < leapexpires)))
3446 : {
3447 0 : error(_("last Leap time does not precede Expires time"));
3448 0 : exit(EXIT_FAILURE);
3449 : }
3450 0 : if (leapexpires <= hi_time)
3451 0 : hi_time = leapexpires - 1;
3452 : }
3453 0 : }
3454 :
3455 : /* Is A a space character in the C locale? */
3456 : static bool
3457 1119416 : is_space(char a)
3458 : {
3459 1119416 : switch (a)
3460 : {
3461 667880 : default:
3462 667880 : return false;
3463 451536 : case ' ':
3464 : case '\f':
3465 : case '\n':
3466 : case '\r':
3467 : case '\t':
3468 : case '\v':
3469 451536 : return true;
3470 : }
3471 : }
3472 :
3473 : /* Is A an alphabetic character in the C locale? */
3474 : static bool
3475 58776 : is_alpha(char a)
3476 : {
3477 58776 : switch (a)
3478 : {
3479 27184 : default:
3480 27184 : return false;
3481 31592 : case 'A':
3482 : case 'B':
3483 : case 'C':
3484 : case 'D':
3485 : case 'E':
3486 : case 'F':
3487 : case 'G':
3488 : case 'H':
3489 : case 'I':
3490 : case 'J':
3491 : case 'K':
3492 : case 'L':
3493 : case 'M':
3494 : case 'N':
3495 : case 'O':
3496 : case 'P':
3497 : case 'Q':
3498 : case 'R':
3499 : case 'S':
3500 : case 'T':
3501 : case 'U':
3502 : case 'V':
3503 : case 'W':
3504 : case 'X':
3505 : case 'Y':
3506 : case 'Z':
3507 : case 'a':
3508 : case 'b':
3509 : case 'c':
3510 : case 'd':
3511 : case 'e':
3512 : case 'f':
3513 : case 'g':
3514 : case 'h':
3515 : case 'i':
3516 : case 'j':
3517 : case 'k':
3518 : case 'l':
3519 : case 'm':
3520 : case 'n':
3521 : case 'o':
3522 : case 'p':
3523 : case 'q':
3524 : case 'r':
3525 : case 's':
3526 : case 't':
3527 : case 'u':
3528 : case 'v':
3529 : case 'w':
3530 : case 'x':
3531 : case 'y':
3532 : case 'z':
3533 31592 : return true;
3534 : }
3535 : }
3536 :
3537 : /* If A is an uppercase character in the C locale, return its lowercase
3538 : counterpart. Otherwise, return A. */
3539 : static char
3540 3652864 : lowerit(char a)
3541 : {
3542 3652864 : switch (a)
3543 : {
3544 1840096 : default:
3545 1840096 : return a;
3546 233288 : case 'A':
3547 233288 : return 'a';
3548 0 : case 'B':
3549 0 : return 'b';
3550 0 : case 'C':
3551 0 : return 'c';
3552 75824 : case 'D':
3553 75824 : return 'd';
3554 0 : case 'E':
3555 0 : return 'e';
3556 96336 : case 'F':
3557 96336 : return 'f';
3558 0 : case 'G':
3559 0 : return 'g';
3560 0 : case 'H':
3561 0 : return 'h';
3562 0 : case 'I':
3563 0 : return 'i';
3564 318328 : case 'J':
3565 318328 : return 'j';
3566 0 : case 'K':
3567 0 : return 'k';
3568 55248 : case 'L':
3569 55248 : return 'l';
3570 236840 : case 'M':
3571 236840 : return 'm';
3572 87152 : case 'N':
3573 87152 : return 'n';
3574 184304 : case 'O':
3575 184304 : return 'o';
3576 0 : case 'P':
3577 0 : return 'p';
3578 0 : case 'Q':
3579 0 : return 'q';
3580 142944 : case 'R':
3581 142944 : return 'r';
3582 285968 : case 'S':
3583 285968 : return 's';
3584 25288 : case 'T':
3585 25288 : return 't';
3586 0 : case 'U':
3587 0 : return 'u';
3588 0 : case 'V':
3589 0 : return 'v';
3590 11968 : case 'W':
3591 11968 : return 'w';
3592 0 : case 'X':
3593 0 : return 'x';
3594 0 : case 'Y':
3595 0 : return 'y';
3596 59280 : case 'Z':
3597 59280 : return 'z';
3598 : }
3599 : }
3600 :
3601 : /* case-insensitive equality */
3602 : static bool
3603 782440 : ciequal(const char *ap, const char *bp)
3604 : {
3605 976248 : while (lowerit(*ap) == lowerit(*bp++))
3606 208888 : if (*ap++ == '\0')
3607 15080 : return true;
3608 767360 : return false;
3609 : }
3610 :
3611 : static bool
3612 0 : itsabbr(const char *abbr, const char *word)
3613 : {
3614 0 : if (lowerit(*abbr) != lowerit(*word))
3615 0 : return false;
3616 0 : ++word;
3617 0 : while (*++abbr != '\0')
3618 : do
3619 : {
3620 0 : if (*word == '\0')
3621 0 : return false;
3622 0 : } while (lowerit(*word++) != lowerit(*abbr));
3623 0 : return true;
3624 : }
3625 :
3626 : /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
3627 :
3628 : static bool
3629 762496 : ciprefix(char const *abbr, char const *word)
3630 : {
3631 : do
3632 904776 : if (!*abbr)
3633 69392 : return true;
3634 835384 : while (lowerit(*abbr++) == lowerit(*word++));
3635 :
3636 693104 : return false;
3637 : }
3638 :
3639 : static const struct lookup *
3640 143104 : byword(const char *word, const struct lookup *table)
3641 : {
3642 : const struct lookup *foundlp;
3643 : const struct lookup *lp;
3644 :
3645 143104 : if (word == NULL || table == NULL)
3646 0 : return NULL;
3647 :
3648 : /*
3649 : * If TABLE is LASTS and the word starts with "last" followed by a
3650 : * non-'-', skip the "last" and look in WDAY_NAMES instead. Warn about any
3651 : * usage of the undocumented prefix "last-".
3652 : */
3653 143104 : if (table == lasts && ciprefix("last", word) && word[4])
3654 : {
3655 2736 : if (word[4] == '-')
3656 0 : warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
3657 : word, word + 5);
3658 : else
3659 : {
3660 2736 : word += 4;
3661 2736 : table = wday_names;
3662 : }
3663 : }
3664 :
3665 : /*
3666 : * Look for exact match.
3667 : */
3668 910464 : for (lp = table; lp->l_word != NULL; ++lp)
3669 782440 : if (ciequal(word, lp->l_word))
3670 15080 : return lp;
3671 :
3672 : /*
3673 : * Look for inexact match.
3674 : */
3675 128024 : foundlp = NULL;
3676 860920 : for (lp = table; lp->l_word != NULL; ++lp)
3677 732896 : if (ciprefix(word, lp->l_word))
3678 : {
3679 66656 : if (foundlp == NULL)
3680 66656 : foundlp = lp;
3681 : else
3682 0 : return NULL; /* multiple inexact matches */
3683 : }
3684 :
3685 128024 : if (foundlp && noise)
3686 : {
3687 : /* Warn about any backward-compatibility issue with pre-2017c zic. */
3688 0 : bool pre_2017c_match = false;
3689 :
3690 0 : for (lp = table; lp->l_word; lp++)
3691 0 : if (itsabbr(word, lp->l_word))
3692 : {
3693 0 : if (pre_2017c_match)
3694 : {
3695 0 : warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
3696 0 : break;
3697 : }
3698 0 : pre_2017c_match = true;
3699 : }
3700 : }
3701 :
3702 128024 : return foundlp;
3703 : }
3704 :
3705 : static char **
3706 34400 : getfields(char *cp)
3707 : {
3708 : char *dp;
3709 : char **array;
3710 : int nsubs;
3711 :
3712 34400 : if (cp == NULL)
3713 0 : return NULL;
3714 34400 : array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
3715 34400 : nsubs = 0;
3716 : for (;;)
3717 : {
3718 294552 : while (is_space(*cp))
3719 0 : ++cp;
3720 294552 : if (*cp == '\0' || *cp == '#')
3721 : break;
3722 260152 : array[nsubs++] = dp = cp;
3723 : do
3724 : {
3725 599096 : if ((*dp = *cp++) != '"')
3726 599096 : ++dp;
3727 : else
3728 0 : while ((*dp = *cp++) != '"')
3729 0 : if (*dp != '\0')
3730 0 : ++dp;
3731 : else
3732 : {
3733 0 : error(_("Odd number of quotation marks"));
3734 0 : exit(EXIT_FAILURE);
3735 : }
3736 599096 : } while (*cp && *cp != '#' && !is_space(*cp));
3737 260152 : if (is_space(*cp))
3738 225768 : ++cp;
3739 260152 : *dp = '\0';
3740 : }
3741 34400 : array[nsubs] = NULL;
3742 34400 : return array;
3743 : }
3744 :
3745 : static _Noreturn void
3746 0 : time_overflow(void)
3747 : {
3748 0 : error(_("time overflow"));
3749 0 : exit(EXIT_FAILURE);
3750 : }
3751 :
3752 : static zic_t
3753 10118296 : oadd(zic_t t1, zic_t t2)
3754 : {
3755 10118296 : if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
3756 0 : time_overflow();
3757 10118296 : return t1 + t2;
3758 : }
3759 :
3760 : static zic_t
3761 1680000 : tadd(zic_t t1, zic_t t2)
3762 : {
3763 1680000 : if (t1 < 0)
3764 : {
3765 478392 : if (t2 < min_time - t1)
3766 : {
3767 0 : if (t1 != min_time)
3768 0 : time_overflow();
3769 0 : return min_time;
3770 : }
3771 : }
3772 : else
3773 : {
3774 1201608 : if (max_time - t1 < t2)
3775 : {
3776 0 : if (t1 != max_time)
3777 0 : time_overflow();
3778 0 : return max_time;
3779 : }
3780 : }
3781 1680000 : return t1 + t2;
3782 : }
3783 :
3784 : /*
3785 : * Given a rule, and a year, compute the date (in seconds since January 1,
3786 : * 1970, 00:00 LOCAL time) in that year that the rule refers to.
3787 : */
3788 :
3789 : static zic_t
3790 276056 : rpytime(const struct rule *rp, zic_t wantedy)
3791 : {
3792 : int m,
3793 : i;
3794 : zic_t dayoff; /* with a nod to Margaret O. */
3795 : zic_t t,
3796 : y;
3797 :
3798 276056 : if (wantedy == ZIC_MIN)
3799 0 : return min_time;
3800 276056 : if (wantedy == ZIC_MAX)
3801 0 : return max_time;
3802 276056 : dayoff = 0;
3803 276056 : m = TM_JANUARY;
3804 276056 : y = EPOCH_YEAR;
3805 276056 : if (y < wantedy)
3806 : {
3807 173128 : wantedy -= y;
3808 173128 : dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
3809 173128 : wantedy %= YEARSPERREPEAT;
3810 173128 : wantedy += y;
3811 : }
3812 102928 : else if (wantedy < 0)
3813 : {
3814 0 : dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
3815 0 : wantedy %= YEARSPERREPEAT;
3816 : }
3817 7451592 : while (wantedy != y)
3818 : {
3819 7175536 : if (wantedy > y)
3820 : {
3821 4036456 : i = len_years[isleap(y)];
3822 4036456 : ++y;
3823 : }
3824 : else
3825 : {
3826 3139080 : --y;
3827 3139080 : i = -len_years[isleap(y)];
3828 : }
3829 7175536 : dayoff = oadd(dayoff, i);
3830 : }
3831 1827992 : while (m != rp->r_month)
3832 : {
3833 1551936 : i = len_months[isleap(y)][m];
3834 1551936 : dayoff = oadd(dayoff, i);
3835 1551936 : ++m;
3836 : }
3837 276056 : i = rp->r_dayofmonth;
3838 276056 : if (m == TM_FEBRUARY && i == 29 && !isleap(y))
3839 : {
3840 608 : if (rp->r_dycode == DC_DOWLEQ)
3841 608 : --i;
3842 : else
3843 : {
3844 0 : error(_("use of 2/29 in non leap-year"));
3845 0 : exit(EXIT_FAILURE);
3846 : }
3847 : }
3848 276056 : --i;
3849 276056 : dayoff = oadd(dayoff, i);
3850 276056 : if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ)
3851 : {
3852 : zic_t wday;
3853 :
3854 : #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3855 177776 : wday = EPOCH_WDAY;
3856 :
3857 : /*
3858 : * Don't trust mod of negative numbers.
3859 : */
3860 177776 : if (dayoff >= 0)
3861 141440 : wday = (wday + dayoff) % LDAYSPERWEEK;
3862 : else
3863 : {
3864 36336 : wday -= ((-dayoff) % LDAYSPERWEEK);
3865 36336 : if (wday < 0)
3866 9624 : wday += LDAYSPERWEEK;
3867 : }
3868 693840 : while (wday != rp->r_wday)
3869 516064 : if (rp->r_dycode == DC_DOWGEQ)
3870 : {
3871 160376 : dayoff = oadd(dayoff, 1);
3872 160376 : if (++wday >= LDAYSPERWEEK)
3873 42792 : wday = 0;
3874 160376 : ++i;
3875 : }
3876 : else
3877 : {
3878 355688 : dayoff = oadd(dayoff, -1);
3879 355688 : if (--wday < 0)
3880 3144 : wday = LDAYSPERWEEK - 1;
3881 355688 : --i;
3882 : }
3883 177776 : if (i < 0 || i >= len_months[isleap(y)][m])
3884 : {
3885 248 : if (noise)
3886 0 : warning(_("rule goes past start/end of month; \
3887 : will not work with pre-2004 versions of zic"));
3888 : }
3889 : }
3890 276056 : if (dayoff < min_time / SECSPERDAY)
3891 0 : return min_time;
3892 276056 : if (dayoff > max_time / SECSPERDAY)
3893 0 : return max_time;
3894 276056 : t = (zic_t) dayoff * SECSPERDAY;
3895 276056 : return tadd(t, rp->r_tod);
3896 : }
3897 :
3898 : static void
3899 11616 : newabbr(const char *string)
3900 : {
3901 : int i;
3902 :
3903 11616 : if (strcmp(string, GRANDPARENTED) != 0)
3904 : {
3905 : const char *cp;
3906 : const char *mp;
3907 :
3908 11616 : cp = string;
3909 11616 : mp = NULL;
3910 72016 : while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
3911 63728 : || *cp == '-' || *cp == '+')
3912 36784 : ++cp;
3913 11616 : if (noise && cp - string < 3)
3914 0 : mp = _("time zone abbreviation has fewer than 3 characters");
3915 11616 : if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
3916 0 : mp = _("time zone abbreviation has too many characters");
3917 11616 : if (*cp != '\0')
3918 0 : mp = _("time zone abbreviation differs from POSIX standard");
3919 11616 : if (mp != NULL)
3920 0 : warning("%s (%s)", mp, string);
3921 : }
3922 11616 : i = strlen(string) + 1;
3923 11616 : if (charcnt + i > TZ_MAX_CHARS)
3924 : {
3925 0 : error(_("too many, or too long, time zone abbreviations"));
3926 0 : exit(EXIT_FAILURE);
3927 : }
3928 11616 : strcpy(&chars[charcnt], string);
3929 11616 : charcnt += i;
3930 11616 : }
3931 :
3932 : /* Ensure that the directories of ARGNAME exist, by making any missing
3933 : ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3934 : do it for ARGNAME too. Exit with failure if there is trouble.
3935 : Do not consider an existing non-directory to be trouble. */
3936 : static void
3937 84 : mkdirs(char const *argname, bool ancestors)
3938 : {
3939 : char *name;
3940 : char *cp;
3941 :
3942 84 : cp = name = ecpyalloc(argname);
3943 :
3944 : /*
3945 : * On MS-Windows systems, do not worry about drive letters or backslashes,
3946 : * as this should suffice in practice. Time zone names do not use drive
3947 : * letters and backslashes. If the -d option of zic does not name an
3948 : * already-existing directory, it can use slashes to separate the
3949 : * already-existing ancestor prefix from the to-be-created subdirectories.
3950 : */
3951 :
3952 : /* Do not mkdir a root directory, as it must exist. */
3953 88 : while (*cp == '/')
3954 4 : cp++;
3955 :
3956 304 : while (cp && ((cp = strchr(cp, '/')) || !ancestors))
3957 : {
3958 136 : if (cp)
3959 132 : *cp = '\0';
3960 :
3961 : /*
3962 : * Try to create it. It's OK if creation fails because the directory
3963 : * already exists, perhaps because some other process just created it.
3964 : * For simplicity do not check first whether it already exists, as
3965 : * that is checked anyway if the mkdir fails.
3966 : */
3967 136 : if (mkdir(name, MKDIR_UMASK) != 0)
3968 : {
3969 : /*
3970 : * For speed, skip itsdir if errno == EEXIST. Since mkdirs is
3971 : * called only after open fails with ENOENT on a subfile, EEXIST
3972 : * implies itsdir here.
3973 : */
3974 52 : int err = errno;
3975 :
3976 52 : if (err != EEXIST && !itsdir(name))
3977 : {
3978 0 : error(_("%s: Cannot create directory %s: %s"),
3979 : progname, name, strerror(err));
3980 0 : exit(EXIT_FAILURE);
3981 : }
3982 : }
3983 136 : if (cp)
3984 132 : *cp++ = '/';
3985 : }
3986 84 : free(name);
3987 84 : }
3988 :
3989 :
3990 : #ifdef WIN32
3991 : /*
3992 : * To run on win32
3993 : */
3994 : int
3995 : link(const char *oldpath, const char *newpath)
3996 : {
3997 : if (!CopyFile(oldpath, newpath, false))
3998 : {
3999 : _dosmaperr(GetLastError());
4000 : return -1;
4001 : }
4002 : return 0;
4003 : }
4004 : #endif
|