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