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