Fri Oct 7 19:47:16 2016 UTC ()
Patch 0001 from upstream to tzcode2016g to restore full functionality
of zic -l


(kre)
diff -r1.63 -r1.64 src/lib/libc/time/zic.c

cvs diff -r1.63 -r1.64 src/lib/libc/time/zic.c (switch to unified diff)

--- src/lib/libc/time/zic.c 2016/10/07 15:29:42 1.63
+++ src/lib/libc/time/zic.c 2016/10/07 19:47:16 1.64
@@ -1,1837 +1,1860 @@ @@ -1,1837 +1,1860 @@
1/* $NetBSD: zic.c,v 1.63 2016/10/07 15:29:42 christos Exp $ */ 1/* $NetBSD: zic.c,v 1.64 2016/10/07 19:47:16 kre Exp $ */
2/* 2/*
3** This file is in the public domain, so clarified as of 3** This file is in the public domain, so clarified as of
4** 2006-07-17 by Arthur David Olson. 4** 2006-07-17 by Arthur David Olson.
5*/ 5*/
6 6
7#if HAVE_NBTOOL_CONFIG_H 7#if HAVE_NBTOOL_CONFIG_H
8#include "nbtool_config.h" 8#include "nbtool_config.h"
9#endif 9#endif
10 10
11#include <sys/cdefs.h> 11#include <sys/cdefs.h>
12#ifndef lint 12#ifndef lint
13__RCSID("$NetBSD: zic.c,v 1.63 2016/10/07 15:29:42 christos Exp $"); 13__RCSID("$NetBSD: zic.c,v 1.64 2016/10/07 19:47:16 kre Exp $");
14#endif /* !defined lint */ 14#endif /* !defined lint */
15 15
16#include "private.h" 16#include "private.h"
17#include "locale.h" 17#include "locale.h"
18#include "tzfile.h" 18#include "tzfile.h"
19 19
20#include <stdarg.h> 20#include <stdarg.h>
21#include <unistd.h> 21#include <unistd.h>
22#include <util.h> 22#include <util.h>
23 23
24#define ZIC_VERSION_PRE_2013 '2' 24#define ZIC_VERSION_PRE_2013 '2'
25#define ZIC_VERSION '3' 25#define ZIC_VERSION '3'
26 26
27typedef int_fast64_t zic_t; 27typedef int_fast64_t zic_t;
28#define ZIC_MIN INT_FAST64_MIN 28#define ZIC_MIN INT_FAST64_MIN
29#define ZIC_MAX INT_FAST64_MAX 29#define ZIC_MAX INT_FAST64_MAX
30#define SCNdZIC SCNdFAST64 30#define SCNdZIC SCNdFAST64
31 31
32#ifndef ZIC_MAX_ABBR_LEN_WO_WARN 32#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
33#define ZIC_MAX_ABBR_LEN_WO_WARN 6 33#define ZIC_MAX_ABBR_LEN_WO_WARN 6
34#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ 34#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
35 35
36#ifdef HAVE_DIRECT_H 36#ifdef HAVE_DIRECT_H
37# include <direct.h> 37# include <direct.h>
38# include <io.h> 38# include <io.h>
39# undef mkdir 39# undef mkdir
40# define mkdir(name, mode) _mkdir(name) 40# define mkdir(name, mode) _mkdir(name)
41#endif 41#endif
42 42
43#if HAVE_SYS_STAT_H 43#if HAVE_SYS_STAT_H
44#include <sys/stat.h> 44#include <sys/stat.h>
45#endif 45#endif
46#ifdef S_IRUSR 46#ifdef S_IRUSR
47#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 47#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
48#else 48#else
49#define MKDIR_UMASK 0755 49#define MKDIR_UMASK 0755
50#endif 50#endif
51 51
52struct rule { 52struct rule {
53 const char * r_filename; 53 const char * r_filename;
54 int r_linenum; 54 int r_linenum;
55 const char * r_name; 55 const char * r_name;
56 56
57 zic_t r_loyear; /* for example, 1986 */ 57 zic_t r_loyear; /* for example, 1986 */
58 zic_t r_hiyear; /* for example, 1986 */ 58 zic_t r_hiyear; /* for example, 1986 */
59 const char * r_yrtype; 59 const char * r_yrtype;
60 bool r_lowasnum; 60 bool r_lowasnum;
61 bool r_hiwasnum; 61 bool r_hiwasnum;
62 62
63 int r_month; /* 0..11 */ 63 int r_month; /* 0..11 */
64 64
65 int r_dycode; /* see below */ 65 int r_dycode; /* see below */
66 int r_dayofmonth; 66 int r_dayofmonth;
67 int r_wday; 67 int r_wday;
68 68
69 zic_t r_tod; /* time from midnight */ 69 zic_t r_tod; /* time from midnight */
70 bool r_todisstd; /* above is standard time if 1 */ 70 bool r_todisstd; /* above is standard time if 1 */
71 /* or wall clock time if 0 */ 71 /* or wall clock time if 0 */
72 bool r_todisgmt; /* above is GMT if 1 */ 72 bool r_todisgmt; /* above is GMT if 1 */
73 /* or local time if 0 */ 73 /* or local time if 0 */
74 zic_t r_stdoff; /* offset from standard time */ 74 zic_t r_stdoff; /* offset from standard time */
75 const char * r_abbrvar; /* variable part of abbreviation */ 75 const char * r_abbrvar; /* variable part of abbreviation */
76 76
77 int r_todo; /* a rule to do (used in outzone) */ 77 int r_todo; /* a rule to do (used in outzone) */
78 zic_t r_temp; /* used in outzone */ 78 zic_t r_temp; /* used in outzone */
79}; 79};
80 80
81/* 81/*
82** r_dycode r_dayofmonth r_wday 82** r_dycode r_dayofmonth r_wday
83*/ 83*/
84 84
85#define DC_DOM 0 /* 1..31 */ /* unused */ 85#define DC_DOM 0 /* 1..31 */ /* unused */
86#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 86#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
87#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 87#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
88 88
89struct zone { 89struct zone {
90 const char * z_filename; 90 const char * z_filename;
91 int z_linenum; 91 int z_linenum;
92 92
93 const char * z_name; 93 const char * z_name;
94 zic_t z_gmtoff; 94 zic_t z_gmtoff;
95 const char * z_rule; 95 const char * z_rule;
96 const char * z_format; 96 const char * z_format;
97 char z_format_specifier; 97 char z_format_specifier;
98 98
99 zic_t z_stdoff; 99 zic_t z_stdoff;
100 100
101 struct rule * z_rules; 101 struct rule * z_rules;
102 int z_nrules; 102 int z_nrules;
103 103
104 struct rule z_untilrule; 104 struct rule z_untilrule;
105 zic_t z_untiltime; 105 zic_t z_untiltime;
106}; 106};
107 107
108#if !HAVE_POSIX_DECLS 108#if !HAVE_POSIX_DECLS
109extern int getopt(int argc, char * const argv[], 109extern int getopt(int argc, char * const argv[],
110 const char * options); 110 const char * options);
111extern int link(const char * fromname, const char * toname); 111extern int link(const char * fromname, const char * toname);
112extern char * optarg; 112extern char * optarg;
113extern int optind; 113extern int optind;
114#endif 114#endif
115 115
116#if ! HAVE_LINK 116#if ! HAVE_LINK
117# define link(from, to) (errno = ENOTSUP, -1) 117# define link(from, to) (errno = ENOTSUP, -1)
118#endif 118#endif
119#if ! HAVE_SYMLINK 119#if ! HAVE_SYMLINK
120# define lstat(name, st) stat(name, st) 120# define lstat(name, st) stat(name, st)
121# define symlink(from, to) (errno = ENOTSUP, -1) 121# define symlink(from, to) (errno = ENOTSUP, -1)
122# define S_ISLNK(m) 0 122# define S_ISLNK(m) 0
123#endif 123#endif
124 124
125static void addtt(zic_t starttime, int type); 125static void addtt(zic_t starttime, int type);
126static int addtype(zic_t, char const *, bool, bool, bool); 126static int addtype(zic_t, char const *, bool, bool, bool);
127static void leapadd(zic_t, bool, int, int); 127static void leapadd(zic_t, bool, int, int);
128static void adjleap(void); 128static void adjleap(void);
129static void associate(void); 129static void associate(void);
130static void dolink(const char *, const char *, bool); 130static void dolink(const char *, const char *, bool);
131static char ** getfields(char * buf); 131static char ** getfields(char * buf);
132static zic_t gethms(const char * string, const char * errstring, 132static zic_t gethms(const char * string, const char * errstring,
133 bool); 133 bool);
134static void infile(const char * filename); 134static void infile(const char * filename);
135static void inleap(char ** fields, int nfields); 135static void inleap(char ** fields, int nfields);
136static void inlink(char ** fields, int nfields); 136static void inlink(char ** fields, int nfields);
137static void inrule(char ** fields, int nfields); 137static void inrule(char ** fields, int nfields);
138static bool inzcont(char ** fields, int nfields); 138static bool inzcont(char ** fields, int nfields);
139static bool inzone(char ** fields, int nfields); 139static bool inzone(char ** fields, int nfields);
140static bool inzsub(char **, int, int); 140static bool inzsub(char **, int, int);
141static int itsdir(const char * name); 141static int itsdir(const char * name);
142static bool is_alpha(char a); 142static bool is_alpha(char a);
143static char lowerit(char); 143static char lowerit(char);
144static void mkdirs(char const *, bool); 144static void mkdirs(char const *, bool);
145static void newabbr(const char * abbr); 145static void newabbr(const char * abbr);
146static zic_t oadd(zic_t t1, zic_t t2); 146static zic_t oadd(zic_t t1, zic_t t2);
147static void outzone(const struct zone * zp, int ntzones); 147static void outzone(const struct zone * zp, int ntzones);
148static zic_t rpytime(const struct rule * rp, zic_t wantedy); 148static zic_t rpytime(const struct rule * rp, zic_t wantedy);
149static void rulesub(struct rule * rp, 149static void rulesub(struct rule * rp,
150 const char * loyearp, const char * hiyearp, 150 const char * loyearp, const char * hiyearp,
151 const char * typep, const char * monthp, 151 const char * typep, const char * monthp,
152 const char * dayp, const char * timep); 152 const char * dayp, const char * timep);
153static zic_t tadd(zic_t t1, zic_t t2); 153static zic_t tadd(zic_t t1, zic_t t2);
154static bool yearistype(int year, const char * type); 154static bool yearistype(int year, const char * type);
155 155
156/* Bound on length of what %z can expand to. */ 156/* Bound on length of what %z can expand to. */
157enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }; 157enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
158 158
159/* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles 159/* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
160 tz binary files whose POSIX-TZ-style strings contain '<'; see 160 tz binary files whose POSIX-TZ-style strings contain '<'; see
161 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This 161 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
162 workaround will no longer be needed when Qt 5.6.1 and earlier are 162 workaround will no longer be needed when Qt 5.6.1 and earlier are
163 obsolete, say in the year 2021. */ 163 obsolete, say in the year 2021. */
164enum { WORK_AROUND_QTBUG_53071 = 1 }; 164enum { WORK_AROUND_QTBUG_53071 = 1 };
165 165
166static int charcnt; 166static int charcnt;
167static bool errors; 167static bool errors;
168static bool warnings; 168static bool warnings;
169static const char * filename; 169static const char * filename;
170static int leapcnt; 170static int leapcnt;
171static bool leapseen; 171static bool leapseen;
172static zic_t leapminyear; 172static zic_t leapminyear;
173static zic_t leapmaxyear; 173static zic_t leapmaxyear;
174static int linenum; 174static int linenum;
175static size_t max_abbrvar_len = PERCENT_Z_LEN_BOUND; 175static size_t max_abbrvar_len = PERCENT_Z_LEN_BOUND;
176static size_t max_format_len; 176static size_t max_format_len;
177static zic_t max_year; 177static zic_t max_year;
178static zic_t min_year; 178static zic_t min_year;
179static bool noise; 179static bool noise;
180static const char * rfilename; 180static const char * rfilename;
181static int rlinenum; 181static int rlinenum;
182static const char * progname; 182static const char * progname;
183static int timecnt; 183static int timecnt;
184static int timecnt_alloc; 184static int timecnt_alloc;
185static int typecnt; 185static int typecnt;
186 186
187/* 187/*
188** Line codes. 188** Line codes.
189*/ 189*/
190 190
191#define LC_RULE 0 191#define LC_RULE 0
192#define LC_ZONE 1 192#define LC_ZONE 1
193#define LC_LINK 2 193#define LC_LINK 2
194#define LC_LEAP 3 194#define LC_LEAP 3
195 195
196/* 196/*
197** Which fields are which on a Zone line. 197** Which fields are which on a Zone line.
198*/ 198*/
199 199
200#define ZF_NAME 1 200#define ZF_NAME 1
201#define ZF_GMTOFF 2 201#define ZF_GMTOFF 2
202#define ZF_RULE 3 202#define ZF_RULE 3
203#define ZF_FORMAT 4 203#define ZF_FORMAT 4
204#define ZF_TILYEAR 5 204#define ZF_TILYEAR 5
205#define ZF_TILMONTH 6 205#define ZF_TILMONTH 6
206#define ZF_TILDAY 7 206#define ZF_TILDAY 7
207#define ZF_TILTIME 8 207#define ZF_TILTIME 8
208#define ZONE_MINFIELDS 5 208#define ZONE_MINFIELDS 5
209#define ZONE_MAXFIELDS 9 209#define ZONE_MAXFIELDS 9
210 210
211/* 211/*
212** Which fields are which on a Zone continuation line. 212** Which fields are which on a Zone continuation line.
213*/ 213*/
214 214
215#define ZFC_GMTOFF 0 215#define ZFC_GMTOFF 0
216#define ZFC_RULE 1 216#define ZFC_RULE 1
217#define ZFC_FORMAT 2 217#define ZFC_FORMAT 2
218#define ZFC_TILYEAR 3 218#define ZFC_TILYEAR 3
219#define ZFC_TILMONTH 4 219#define ZFC_TILMONTH 4
220#define ZFC_TILDAY 5 220#define ZFC_TILDAY 5
221#define ZFC_TILTIME 6 221#define ZFC_TILTIME 6
222#define ZONEC_MINFIELDS 3 222#define ZONEC_MINFIELDS 3
223#define ZONEC_MAXFIELDS 7 223#define ZONEC_MAXFIELDS 7
224 224
225/* 225/*
226** Which files are which on a Rule line. 226** Which files are which on a Rule line.
227*/ 227*/
228 228
229#define RF_NAME 1 229#define RF_NAME 1
230#define RF_LOYEAR 2 230#define RF_LOYEAR 2
231#define RF_HIYEAR 3 231#define RF_HIYEAR 3
232#define RF_COMMAND 4 232#define RF_COMMAND 4
233#define RF_MONTH 5 233#define RF_MONTH 5
234#define RF_DAY 6 234#define RF_DAY 6
235#define RF_TOD 7 235#define RF_TOD 7
236#define RF_STDOFF 8 236#define RF_STDOFF 8
237#define RF_ABBRVAR 9 237#define RF_ABBRVAR 9
238#define RULE_FIELDS 10 238#define RULE_FIELDS 10
239 239
240/* 240/*
241** Which fields are which on a Link line. 241** Which fields are which on a Link line.
242*/ 242*/
243 243
244#define LF_FROM 1 244#define LF_FROM 1
245#define LF_TO 2 245#define LF_TO 2
246#define LINK_FIELDS 3 246#define LINK_FIELDS 3
247 247
248/* 248/*
249** Which fields are which on a Leap line. 249** Which fields are which on a Leap line.
250*/ 250*/
251 251
252#define LP_YEAR 1 252#define LP_YEAR 1
253#define LP_MONTH 2 253#define LP_MONTH 2
254#define LP_DAY 3 254#define LP_DAY 3
255#define LP_TIME 4 255#define LP_TIME 4
256#define LP_CORR 5 256#define LP_CORR 5
257#define LP_ROLL 6 257#define LP_ROLL 6
258#define LEAP_FIELDS 7 258#define LEAP_FIELDS 7
259 259
260/* 260/*
261** Year synonyms. 261** Year synonyms.
262*/ 262*/
263 263
264#define YR_MINIMUM 0 264#define YR_MINIMUM 0
265#define YR_MAXIMUM 1 265#define YR_MAXIMUM 1
266#define YR_ONLY 2 266#define YR_ONLY 2
267 267
268static struct rule * rules; 268static struct rule * rules;
269static int nrules; /* number of rules */ 269static int nrules; /* number of rules */
270static int nrules_alloc; 270static int nrules_alloc;
271 271
272static struct zone * zones; 272static struct zone * zones;
273static int nzones; /* number of zones */ 273static int nzones; /* number of zones */
274static int nzones_alloc; 274static int nzones_alloc;
275 275
276struct link { 276struct link {
277 const char * l_filename; 277 const char * l_filename;
278 int l_linenum; 278 int l_linenum;
279 const char * l_from; 279 const char * l_from;
280 const char * l_to; 280 const char * l_to;
281}; 281};
282 282
283static struct link * links; 283static struct link * links;
284static int nlinks; 284static int nlinks;
285static int nlinks_alloc; 285static int nlinks_alloc;
286 286
287struct lookup { 287struct lookup {
288 const char * l_word; 288 const char * l_word;
289 const int l_value; 289 const int l_value;
290}; 290};
291 291
292static struct lookup const * byword(const char * string, 292static struct lookup const * byword(const char * string,
293 const struct lookup * lp); 293 const struct lookup * lp);
294 294
295static struct lookup const line_codes[] = { 295static struct lookup const line_codes[] = {
296 { "Rule", LC_RULE }, 296 { "Rule", LC_RULE },
297 { "Zone", LC_ZONE }, 297 { "Zone", LC_ZONE },
298 { "Link", LC_LINK }, 298 { "Link", LC_LINK },
299 { "Leap", LC_LEAP }, 299 { "Leap", LC_LEAP },
300 { NULL, 0} 300 { NULL, 0}
301}; 301};
302 302
303static struct lookup const mon_names[] = { 303static struct lookup const mon_names[] = {
304 { "January", TM_JANUARY }, 304 { "January", TM_JANUARY },
305 { "February", TM_FEBRUARY }, 305 { "February", TM_FEBRUARY },
306 { "March", TM_MARCH }, 306 { "March", TM_MARCH },
307 { "April", TM_APRIL }, 307 { "April", TM_APRIL },
308 { "May", TM_MAY }, 308 { "May", TM_MAY },
309 { "June", TM_JUNE }, 309 { "June", TM_JUNE },
310 { "July", TM_JULY }, 310 { "July", TM_JULY },
311 { "August", TM_AUGUST }, 311 { "August", TM_AUGUST },
312 { "September", TM_SEPTEMBER }, 312 { "September", TM_SEPTEMBER },
313 { "October", TM_OCTOBER }, 313 { "October", TM_OCTOBER },
314 { "November", TM_NOVEMBER }, 314 { "November", TM_NOVEMBER },
315 { "December", TM_DECEMBER }, 315 { "December", TM_DECEMBER },
316 { NULL, 0 } 316 { NULL, 0 }
317}; 317};
318 318
319static struct lookup const wday_names[] = { 319static struct lookup const wday_names[] = {
320 { "Sunday", TM_SUNDAY }, 320 { "Sunday", TM_SUNDAY },
321 { "Monday", TM_MONDAY }, 321 { "Monday", TM_MONDAY },
322 { "Tuesday", TM_TUESDAY }, 322 { "Tuesday", TM_TUESDAY },
323 { "Wednesday", TM_WEDNESDAY }, 323 { "Wednesday", TM_WEDNESDAY },
324 { "Thursday", TM_THURSDAY }, 324 { "Thursday", TM_THURSDAY },
325 { "Friday", TM_FRIDAY }, 325 { "Friday", TM_FRIDAY },
326 { "Saturday", TM_SATURDAY }, 326 { "Saturday", TM_SATURDAY },
327 { NULL, 0 } 327 { NULL, 0 }
328}; 328};
329 329
330static struct lookup const lasts[] = { 330static struct lookup const lasts[] = {
331 { "last-Sunday", TM_SUNDAY }, 331 { "last-Sunday", TM_SUNDAY },
332 { "last-Monday", TM_MONDAY }, 332 { "last-Monday", TM_MONDAY },
333 { "last-Tuesday", TM_TUESDAY }, 333 { "last-Tuesday", TM_TUESDAY },
334 { "last-Wednesday", TM_WEDNESDAY }, 334 { "last-Wednesday", TM_WEDNESDAY },
335 { "last-Thursday", TM_THURSDAY }, 335 { "last-Thursday", TM_THURSDAY },
336 { "last-Friday", TM_FRIDAY }, 336 { "last-Friday", TM_FRIDAY },
337 { "last-Saturday", TM_SATURDAY }, 337 { "last-Saturday", TM_SATURDAY },
338 { NULL, 0 } 338 { NULL, 0 }
339}; 339};
340 340
341static struct lookup const begin_years[] = { 341static struct lookup const begin_years[] = {
342 { "minimum", YR_MINIMUM }, 342 { "minimum", YR_MINIMUM },
343 { "maximum", YR_MAXIMUM }, 343 { "maximum", YR_MAXIMUM },
344 { NULL, 0 } 344 { NULL, 0 }
345}; 345};
346 346
347static struct lookup const end_years[] = { 347static struct lookup const end_years[] = {
348 { "minimum", YR_MINIMUM }, 348 { "minimum", YR_MINIMUM },
349 { "maximum", YR_MAXIMUM }, 349 { "maximum", YR_MAXIMUM },
350 { "only", YR_ONLY }, 350 { "only", YR_ONLY },
351 { NULL, 0 } 351 { NULL, 0 }
352}; 352};
353 353
354static struct lookup const leap_types[] = { 354static struct lookup const leap_types[] = {
355 { "Rolling", true }, 355 { "Rolling", true },
356 { "Stationary", false }, 356 { "Stationary", false },
357 { NULL, 0 } 357 { NULL, 0 }
358}; 358};
359 359
360static const int len_months[2][MONSPERYEAR] = { 360static const int len_months[2][MONSPERYEAR] = {
361 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 361 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
362 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 362 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
363}; 363};
364 364
365static const int len_years[2] = { 365static const int len_years[2] = {
366 DAYSPERNYEAR, DAYSPERLYEAR 366 DAYSPERNYEAR, DAYSPERLYEAR
367}; 367};
368 368
369static struct attype { 369static struct attype {
370 zic_t at; 370 zic_t at;
371 bool dontmerge; 371 bool dontmerge;
372 unsigned char type; 372 unsigned char type;
373} * attypes; 373} * attypes;
374static zic_t gmtoffs[TZ_MAX_TYPES]; 374static zic_t gmtoffs[TZ_MAX_TYPES];
375static char isdsts[TZ_MAX_TYPES]; 375static char isdsts[TZ_MAX_TYPES];
376static unsigned char abbrinds[TZ_MAX_TYPES]; 376static unsigned char abbrinds[TZ_MAX_TYPES];
377static bool ttisstds[TZ_MAX_TYPES]; 377static bool ttisstds[TZ_MAX_TYPES];
378static bool ttisgmts[TZ_MAX_TYPES]; 378static bool ttisgmts[TZ_MAX_TYPES];
379static char chars[TZ_MAX_CHARS]; 379static char chars[TZ_MAX_CHARS];
380static zic_t trans[TZ_MAX_LEAPS]; 380static zic_t trans[TZ_MAX_LEAPS];
381static zic_t corr[TZ_MAX_LEAPS]; 381static zic_t corr[TZ_MAX_LEAPS];
382static char roll[TZ_MAX_LEAPS]; 382static char roll[TZ_MAX_LEAPS];
383 383
384/* 384/*
385** Memory allocation. 385** Memory allocation.
386*/ 386*/
387 387
388static _Noreturn void 388static _Noreturn void
389memory_exhausted(const char *msg) 389memory_exhausted(const char *msg)
390{ 390{
391 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg); 391 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
392 exit(EXIT_FAILURE); 392 exit(EXIT_FAILURE);
393} 393}
394 394
395static ATTRIBUTE_PURE size_t 395static ATTRIBUTE_PURE size_t
396size_product(size_t nitems, size_t itemsize) 396size_product(size_t nitems, size_t itemsize)
397{ 397{
398 if (SIZE_MAX / itemsize < nitems) 398 if (SIZE_MAX / itemsize < nitems)
399 memory_exhausted(_("size overflow")); 399 memory_exhausted(_("size overflow"));
400 return nitems * itemsize; 400 return nitems * itemsize;
401} 401}
402 402
403#if !HAVE_STRDUP 403#if !HAVE_STRDUP
404static char * 404static char *
405strdup(char const *str) 405strdup(char const *str)
406{ 406{
407 char *result = malloc(strlen(str) + 1); 407 char *result = malloc(strlen(str) + 1);
408 return result ? strcpy(result, str) : result; 408 return result ? strcpy(result, str) : result;
409} 409}
410#endif 410#endif
411 411
412static ATTRIBUTE_PURE void * 412static ATTRIBUTE_PURE void *
413memcheck(void *ptr) 413memcheck(void *ptr)
414{ 414{
415 if (ptr == NULL) 415 if (ptr == NULL)
416 memory_exhausted(strerror(errno)); 416 memory_exhausted(strerror(errno));
417 return ptr; 417 return ptr;
418} 418}
419 419
420static void * 420static void *
421zic_malloc(size_t size) 421zic_malloc(size_t size)
422{ 422{
423 return memcheck(malloc(size)); 423 return memcheck(malloc(size));
424} 424}
425 425
426static void * 426static void *
427zic_realloc(void *ptr, size_t size) 427zic_realloc(void *ptr, size_t size)
428{ 428{
429 return memcheck(realloc(ptr, size)); 429 return memcheck(realloc(ptr, size));
430} 430}
431 431
432static char * 432static char *
433ecpyalloc(char const *str) 433ecpyalloc(char const *str)
434{ 434{
435 return memcheck(strdup(str)); 435 return memcheck(strdup(str));
436} 436}
437 437
438static void * 438static void *
439growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc) 439growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
440{ 440{
441 if (nitems < *nitems_alloc) 441 if (nitems < *nitems_alloc)
442 return ptr; 442 return ptr;
443 else { 443 else {
444#define IMAX (INT_MAX < SIZE_MAX ? INT_MAX : (int)SIZE_MAX) 444#define IMAX (INT_MAX < SIZE_MAX ? INT_MAX : (int)SIZE_MAX)
445 int nitems_max = IMAX - WORK_AROUND_QTBUG_53071; 445 int nitems_max = IMAX - WORK_AROUND_QTBUG_53071;
446 int amax = nitems_max < IMAX ? nitems_max : IMAX; 446 int amax = nitems_max < IMAX ? nitems_max : IMAX;
447 if ((amax - 1) / 3 * 2 < *nitems_alloc) 447 if ((amax - 1) / 3 * 2 < *nitems_alloc)
448 memory_exhausted(_("int overflow")); 448 memory_exhausted(_("int overflow"));
449 *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1; 449 *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1;
450 return zic_realloc(ptr, size_product(*nitems_alloc, itemsize)); 450 return zic_realloc(ptr, size_product(*nitems_alloc, itemsize));
451 } 451 }
452} 452}
453 453
454/* 454/*
455** Error handling. 455** Error handling.
456*/ 456*/
457 457
458static void 458static void
459eats(const char *const name, const int num, const char *const rname, 459eats(const char *const name, const int num, const char *const rname,
460 const int rnum) 460 const int rnum)
461{ 461{
462 filename = name; 462 filename = name;
463 linenum = num; 463 linenum = num;
464 rfilename = rname; 464 rfilename = rname;
465 rlinenum = rnum; 465 rlinenum = rnum;
466} 466}
467 467
468static void 468static void
469eat(const char *const name, const int num) 469eat(const char *const name, const int num)
470{ 470{
471 eats(name, num, NULL, -1); 471 eats(name, num, NULL, -1);
472} 472}
473 473
474static void ATTRIBUTE_FORMAT((printf, 1, 0)) 474static void ATTRIBUTE_FORMAT((printf, 1, 0))
475verror(const char *const string, va_list args) 475verror(const char *const string, va_list args)
476{ 476{
477 /* 477 /*
478 ** Match the format of "cc" to allow sh users to 478 ** Match the format of "cc" to allow sh users to
479 ** zic ... 2>&1 | error -t "*" -v 479 ** zic ... 2>&1 | error -t "*" -v
480 ** on BSD systems. 480 ** on BSD systems.
481 */ 481 */
482 if (filename) 482 if (filename)
483 fprintf(stderr, _("\"%s\", line %d: "), filename, linenum); 483 fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
484 vfprintf(stderr, string, args); 484 vfprintf(stderr, string, args);
485 if (rfilename != NULL) 485 if (rfilename != NULL)
486 fprintf(stderr, _(" (rule from \"%s\", line %d)"), 486 fprintf(stderr, _(" (rule from \"%s\", line %d)"),
487 rfilename, rlinenum); 487 rfilename, rlinenum);
488 fprintf(stderr, "\n"); 488 fprintf(stderr, "\n");
489} 489}
490 490
491static void ATTRIBUTE_FORMAT((printf, 1, 2)) 491static void ATTRIBUTE_FORMAT((printf, 1, 2))
492error(const char *const string, ...) 492error(const char *const string, ...)
493{ 493{
494 va_list args; 494 va_list args;
495 va_start(args, string); 495 va_start(args, string);
496 verror(string, args); 496 verror(string, args);
497 va_end(args); 497 va_end(args);
498 errors = true; 498 errors = true;
499} 499}
500 500
501static void ATTRIBUTE_FORMAT((printf, 1, 2)) 501static void ATTRIBUTE_FORMAT((printf, 1, 2))
502warning(const char *const string, ...) 502warning(const char *const string, ...)
503{ 503{
504 va_list args; 504 va_list args;
505 fprintf(stderr, _("warning: ")); 505 fprintf(stderr, _("warning: "));
506 va_start(args, string); 506 va_start(args, string);
507 verror(string, args); 507 verror(string, args);
508 va_end(args); 508 va_end(args);
509 warnings = true; 509 warnings = true;
510} 510}
511 511
512static void 512static void
513close_file(FILE *stream, char const *dir, char const *name) 513close_file(FILE *stream, char const *dir, char const *name)
514{ 514{
515 char const *e = (ferror(stream) ? _("I/O error") 515 char const *e = (ferror(stream) ? _("I/O error")
516 : fclose(stream) != 0 ? strerror(errno) : NULL); 516 : fclose(stream) != 0 ? strerror(errno) : NULL);
517 if (e) { 517 if (e) {
518 fprintf(stderr, "%s: %s%s%s%s%s\n", progname, 518 fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
519 dir ? dir : "", dir ? "/" : "", 519 dir ? dir : "", dir ? "/" : "",
520 name ? name : "", name ? ": " : "", 520 name ? name : "", name ? ": " : "",
521 e); 521 e);
522 exit(EXIT_FAILURE); 522 exit(EXIT_FAILURE);
523 } 523 }
524} 524}
525 525
526static _Noreturn void 526static _Noreturn void
527usage(FILE *stream, int status) 527usage(FILE *stream, int status)
528{ 528{
529 fprintf(stream, 529 fprintf(stream,
530 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n" 530 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
531 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n" 531 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
532 "\t[ -L leapseconds ] [ filename ... ]\n\n" 532 "\t[ -L leapseconds ] [ filename ... ]\n\n"
533 "Report bugs to %s.\n"), 533 "Report bugs to %s.\n"),
534 progname, progname, REPORT_BUGS_TO); 534 progname, progname, REPORT_BUGS_TO);
535 if (status == EXIT_SUCCESS) 535 if (status == EXIT_SUCCESS)
536 close_file(stream, NULL, NULL); 536 close_file(stream, NULL, NULL);
537 exit(status); 537 exit(status);
538} 538}
539 539
540/* Change the working directory to DIR, possibly creating DIR and its 540/* Change the working directory to DIR, possibly creating DIR and its
541 ancestors. After this is done, all files are accessed with names 541 ancestors. After this is done, all files are accessed with names
542 relative to DIR. */ 542 relative to DIR. */
543static void 543static void
544change_directory (char const *dir) 544change_directory (char const *dir)
545{ 545{
546 if (chdir(dir) != 0) { 546 if (chdir(dir) != 0) {
547 int chdir_errno = errno; 547 int chdir_errno = errno;
548 if (chdir_errno == ENOENT) { 548 if (chdir_errno == ENOENT) {
549 mkdirs(dir, false); 549 mkdirs(dir, false);
550 chdir_errno = chdir(dir) == 0 ? 0 : errno; 550 chdir_errno = chdir(dir) == 0 ? 0 : errno;
551 } 551 }
552 if (chdir_errno != 0) { 552 if (chdir_errno != 0) {
553 fprintf(stderr, _("%s: Can't chdir to %s: %s\n"), 553 fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
554 progname, dir, strerror(chdir_errno)); 554 progname, dir, strerror(chdir_errno));
555 exit(EXIT_FAILURE); 555 exit(EXIT_FAILURE);
556 } 556 }
557 } 557 }
558} 558}
559 559
560static const char * psxrules; 560static const char * psxrules;
561static const char * lcltime; 561static const char * lcltime;
562static const char * directory; 562static const char * directory;
563static const char * leapsec; 563static const char * leapsec;
564static const char * yitcommand; 564static const char * yitcommand;
565 565
566int 566int
567main(int argc, char **argv) 567main(int argc, char **argv)
568{ 568{
569 int i; 569 int i;
570 int j; 570 int j;
571 int c; 571 int c;
572 572
573#ifdef S_IWGRP 573#ifdef S_IWGRP
574 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 574 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
575#endif 575#endif
576#if HAVE_GETTEXT 576#if HAVE_GETTEXT
577 setlocale(LC_MESSAGES, ""); 577 setlocale(LC_MESSAGES, "");
578#ifdef TZ_DOMAINDIR 578#ifdef TZ_DOMAINDIR
579 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 579 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
580#endif /* defined TEXTDOMAINDIR */ 580#endif /* defined TEXTDOMAINDIR */
581 textdomain(TZ_DOMAIN); 581 textdomain(TZ_DOMAIN);
582#endif /* HAVE_GETTEXT */ 582#endif /* HAVE_GETTEXT */
583 progname = argv[0]; 583 progname = argv[0];
584 if (TYPE_BIT(zic_t) < 64) { 584 if (TYPE_BIT(zic_t) < 64) {
585 fprintf(stderr, "%s: %s\n", progname, 585 fprintf(stderr, "%s: %s\n", progname,
586 _("wild compilation-time specification of zic_t")); 586 _("wild compilation-time specification of zic_t"));
587 return EXIT_FAILURE; 587 return EXIT_FAILURE;
588 } 588 }
589 for (i = 1; i < argc; ++i) 589 for (i = 1; i < argc; ++i)
590 if (strcmp(argv[i], "--version") == 0) { 590 if (strcmp(argv[i], "--version") == 0) {
591 printf("zic %s%s\n", PKGVERSION, TZVERSION); 591 printf("zic %s%s\n", PKGVERSION, TZVERSION);
592 close_file(stdout, NULL, NULL); 592 close_file(stdout, NULL, NULL);
593 return EXIT_SUCCESS; 593 return EXIT_SUCCESS;
594 } else if (strcmp(argv[i], "--help") == 0) { 594 } else if (strcmp(argv[i], "--help") == 0) {
595 usage(stdout, EXIT_SUCCESS); 595 usage(stdout, EXIT_SUCCESS);
596 } 596 }
597 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1) 597 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
598 switch (c) { 598 switch (c) {
599 default: 599 default:
600 usage(stderr, EXIT_FAILURE); 600 usage(stderr, EXIT_FAILURE);
601 case 'd': 601 case 'd':
602 if (directory == NULL) 602 if (directory == NULL)
603 directory = optarg; 603 directory = optarg;
604 else { 604 else {
605 fprintf(stderr, 605 fprintf(stderr,
606_("%s: More than one -d option specified\n"), 606_("%s: More than one -d option specified\n"),
607 progname); 607 progname);
608 return EXIT_FAILURE; 608 return EXIT_FAILURE;
609 } 609 }
610 break; 610 break;
611 case 'l': 611 case 'l':
612 if (lcltime == NULL) 612 if (lcltime == NULL)
613 lcltime = optarg; 613 lcltime = optarg;
614 else { 614 else {
615 fprintf(stderr, 615 fprintf(stderr,
616_("%s: More than one -l option specified\n"), 616_("%s: More than one -l option specified\n"),
617 progname); 617 progname);
618 return EXIT_FAILURE; 618 return EXIT_FAILURE;
619 } 619 }
620 break; 620 break;
621 case 'p': 621 case 'p':
622 if (psxrules == NULL) 622 if (psxrules == NULL)
623 psxrules = optarg; 623 psxrules = optarg;
624 else { 624 else {
625 fprintf(stderr, 625 fprintf(stderr,
626_("%s: More than one -p option specified\n"), 626_("%s: More than one -p option specified\n"),
627 progname); 627 progname);
628 return EXIT_FAILURE; 628 return EXIT_FAILURE;
629 } 629 }
630 break; 630 break;
631 case 'y': 631 case 'y':
632 if (yitcommand == NULL) 632 if (yitcommand == NULL)
633 yitcommand = optarg; 633 yitcommand = optarg;
634 else { 634 else {
635 fprintf(stderr, 635 fprintf(stderr,
636_("%s: More than one -y option specified\n"), 636_("%s: More than one -y option specified\n"),
637 progname); 637 progname);
638 return EXIT_FAILURE; 638 return EXIT_FAILURE;
639 } 639 }
640 break; 640 break;
641 case 'L': 641 case 'L':
642 if (leapsec == NULL) 642 if (leapsec == NULL)
643 leapsec = optarg; 643 leapsec = optarg;
644 else { 644 else {
645 fprintf(stderr, 645 fprintf(stderr,
646_("%s: More than one -L option specified\n"), 646_("%s: More than one -L option specified\n"),
647 progname); 647 progname);
648 return EXIT_FAILURE; 648 return EXIT_FAILURE;
649 } 649 }
650 break; 650 break;
651 case 'v': 651 case 'v':
652 noise = true; 652 noise = true;
653 break; 653 break;
654 case 's': 654 case 's':
655 warning(_("-s ignored")); 655 warning(_("-s ignored"));
656 break; 656 break;
657 } 657 }
658 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 658 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
659 usage(stderr, EXIT_FAILURE); /* usage message by request */ 659 usage(stderr, EXIT_FAILURE); /* usage message by request */
660 if (directory == NULL) 660 if (directory == NULL)
661 directory = TZDIR; 661 directory = TZDIR;
662 if (yitcommand == NULL) 662 if (yitcommand == NULL)
663 yitcommand = "yearistype"; 663 yitcommand = "yearistype";
664 664
665 if (optind < argc && leapsec != NULL) { 665 if (optind < argc && leapsec != NULL) {
666 infile(leapsec); 666 infile(leapsec);
667 adjleap(); 667 adjleap();
668 } 668 }
669 669
670 for (i = optind; i < argc; ++i) 670 for (i = optind; i < argc; ++i)
671 infile(argv[i]); 671 infile(argv[i]);
672 if (errors) 672 if (errors)
673 return EXIT_FAILURE; 673 return EXIT_FAILURE;
674 associate(); 674 associate();
675 change_directory(directory); 675 change_directory(directory);
676 for (i = 0; i < nzones; i = j) { 676 for (i = 0; i < nzones; i = j) {
677 /* 677 /*
678 ** Find the next non-continuation zone entry. 678 ** Find the next non-continuation zone entry.
679 */ 679 */
680 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 680 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
681 continue; 681 continue;
682 outzone(&zones[i], j - i); 682 outzone(&zones[i], j - i);
683 } 683 }
684 /* 684 /*
685 ** Make links. 685 ** Make links.
686 */ 686 */
687 for (i = 0; i < nlinks; ++i) { 687 for (i = 0; i < nlinks; ++i) {
688 eat(links[i].l_filename, links[i].l_linenum); 688 eat(links[i].l_filename, links[i].l_linenum);
689 dolink(links[i].l_from, links[i].l_to, false); 689 dolink(links[i].l_from, links[i].l_to, false);
690 if (noise) 690 if (noise)
691 for (j = 0; j < nlinks; ++j) 691 for (j = 0; j < nlinks; ++j)
692 if (strcmp(links[i].l_to, 692 if (strcmp(links[i].l_to,
693 links[j].l_from) == 0) 693 links[j].l_from) == 0)
694 warning(_("link to link")); 694 warning(_("link to link"));
695 } 695 }
696 if (lcltime != NULL) { 696 if (lcltime != NULL) {
697 eat(_("command line"), 1); 697 eat(_("command line"), 1);
698 dolink(lcltime, TZDEFAULT, true); 698 dolink(lcltime, TZDEFAULT, true);
699 } 699 }
700 if (psxrules != NULL) { 700 if (psxrules != NULL) {
701 eat(_("command line"), 1); 701 eat(_("command line"), 1);
702 dolink(psxrules, TZDEFRULES, true); 702 dolink(psxrules, TZDEFRULES, true);
703 } 703 }
704 if (warnings && (ferror(stderr) || fclose(stderr) != 0)) 704 if (warnings && (ferror(stderr) || fclose(stderr) != 0))
705 return EXIT_FAILURE; 705 return EXIT_FAILURE;
706 return errors ? EXIT_FAILURE : EXIT_SUCCESS; 706 return errors ? EXIT_FAILURE : EXIT_SUCCESS;
707} 707}
708 708
709static bool 709static bool
710componentcheck(char const *name, char const *component, 710componentcheck(char const *name, char const *component,
711 char const *component_end) 711 char const *component_end)
712{ 712{
713 enum { component_len_max = 14 }; 713 enum { component_len_max = 14 };
714 size_t component_len = component_end - component; 714 size_t component_len = component_end - component;
715 if (component_len == 0) { 715 if (component_len == 0) {
716 if (!*name) 716 if (!*name)
717 error (_("empty file name")); 717 error (_("empty file name"));
718 else 718 else
719 error (_(component == name 719 error (_(component == name
720 ? "file name '%s' begins with '/'" 720 ? "file name '%s' begins with '/'"
721 : *component_end 721 : *component_end
722 ? "file name '%s' contains '//'" 722 ? "file name '%s' contains '//'"
723 : "file name '%s' ends with '/'"), 723 : "file name '%s' ends with '/'"),
724 name); 724 name);
725 return false; 725 return false;
726 } 726 }
727 if (0 < component_len && component_len <= 2 727 if (0 < component_len && component_len <= 2
728 && component[0] == '.' && component_end[-1] == '.') { 728 && component[0] == '.' && component_end[-1] == '.') {
729 error(_("file name '%s' contains '%.*s' component"), 729 error(_("file name '%s' contains '%.*s' component"),
730 name, (int) component_len, component); 730 name, (int) component_len, component);
731 return false; 731 return false;
732 } 732 }
733 if (noise) { 733 if (noise) {
734 if (0 < component_len && component[0] == '-') 734 if (0 < component_len && component[0] == '-')
735 warning(_("file name '%s' component contains leading '-'"), 735 warning(_("file name '%s' component contains leading '-'"),
736 name); 736 name);
737 if (component_len_max < component_len) 737 if (component_len_max < component_len)
738 warning(_("file name '%s' contains overlength component" 738 warning(_("file name '%s' contains overlength component"
739 " '%.*s...'"), 739 " '%.*s...'"),
740 name, component_len_max, component); 740 name, component_len_max, component);
741 } 741 }
742 return true; 742 return true;
743} 743}
744 744
745static bool 745static bool
746namecheck(const char *name) 746namecheck(const char *name)
747{ 747{
748 char const *cp; 748 char const *cp;
749 749
750 /* Benign characters in a portable file name. */ 750 /* Benign characters in a portable file name. */
751 static char const benign[] = 751 static char const benign[] =
752 "-/_" 752 "-/_"
753 "abcdefghijklmnopqrstuvwxyz" 753 "abcdefghijklmnopqrstuvwxyz"
754 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 754 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
755 755
756 /* Non-control chars in the POSIX portable character set, 756 /* Non-control chars in the POSIX portable character set,
757 excluding the benign characters. */ 757 excluding the benign characters. */
758 static char const printable_and_not_benign[] = 758 static char const printable_and_not_benign[] =
759 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~"; 759 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
760 760
761 char const *component = name; 761 char const *component = name;
762 for (cp = name; *cp; cp++) { 762 for (cp = name; *cp; cp++) {
763 unsigned char c = *cp; 763 unsigned char c = *cp;
764 if (noise && !strchr(benign, c)) { 764 if (noise && !strchr(benign, c)) {
765 warning((strchr(printable_and_not_benign, c) 765 warning((strchr(printable_and_not_benign, c)
766 ? _("file name '%s' contains byte '%c'") 766 ? _("file name '%s' contains byte '%c'")
767 : _("file name '%s' contains byte '\\%o'")), 767 : _("file name '%s' contains byte '\\%o'")),
768 name, c); 768 name, c);
769 } 769 }
770 if (c == '/') { 770 if (c == '/') {
771 if (!componentcheck(name, component, cp)) 771 if (!componentcheck(name, component, cp))
772 return false; 772 return false;
773 component = cp + 1; 773 component = cp + 1;
774 } 774 }
775 } 775 }
776 return componentcheck(name, component, cp); 776 return componentcheck(name, component, cp);
777} 777}
778 778
 779/* Create symlink contents suitable for symlinking FROM to TO, as a
 780 freshly allocated string. FROM should be a relative file name, and
 781 is relative to the global variable DIRECTORY. TO can be either
 782 relative or absolute. */
 783static char *
 784relname(char const *from, char const *to)
 785{
 786 size_t i, taillen, dotdotetcsize;
 787 size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
 788 char const *f = from;
 789 char *result = NULL;
 790 if (*to == '/') {
 791 /* Make F absolute too. */
 792 size_t len = strlen(directory);
 793 bool needslash = len && directory[len - 1] != '/';
 794 linksize = len + needslash + strlen(from) + 1;
 795 f = result = emalloc(linksize);
 796 strcpy(result, directory);
 797 result[len] = '/';
 798 strcpy(result + len + needslash, from);
 799 }
 800 for (i = 0; f[i] && f[i] == to[i]; i++)
 801 if (f[i] == '/')
 802 dir_len = i + 1;
 803 for (; f[i]; i++)
 804 dotdots += f[i] == '/' && f[i - 1] != '/';
 805 taillen = i - dir_len;
 806 dotdotetcsize = 3 * dotdots + taillen + 1;
 807 if (dotdotetcsize <= linksize) {
 808 if (!result)
 809 result = emalloc(dotdotetcsize);
 810 for (i = 0; i < dotdots; i++)
 811 memcpy(result + 3 * i, "../", 3);
 812 memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
 813 }
 814 return result;
 815}
 816
779static void 817static void
780dolink(char const *fromfield, char const *tofield, bool staysymlink) 818dolink(char const *fromfield, char const *tofield, bool staysymlink)
781{ 819{
782 int fromisdir; 820 int fromisdir;
783 bool todirs_made = false; 821 bool todirs_made = false;
784 int link_errno; 822 int link_errno;
785 823
786 /* 824 /*
787 ** We get to be careful here since 825 ** We get to be careful here since
788 ** there's a fair chance of root running us. 826 ** there's a fair chance of root running us.
789 */ 827 */
790 fromisdir = itsdir(fromfield); 828 fromisdir = itsdir(fromfield);
791 if (fromisdir) { 829 if (fromisdir) {
792 char const *e = strerror(fromisdir < 0 ? errno : EPERM); 830 char const *e = strerror(fromisdir < 0 ? errno : EPERM);
793 fprintf(stderr, _("%s: link from %s/%s failed: %s\n"), 831 fprintf(stderr, _("%s: link from %s/%s failed: %s\n"),
794 progname, directory, fromfield, e); 832 progname, directory, fromfield, e);
795 exit(EXIT_FAILURE); 833 exit(EXIT_FAILURE);
796 } 834 }
797 if (staysymlink) 835 if (staysymlink)
798 staysymlink = itsdir(tofield) == 2; 836 staysymlink = itsdir(tofield) == 2;
799 if (remove(tofield) == 0) 837 if (remove(tofield) == 0)
800 todirs_made = true; 838 todirs_made = true;
801 else if (errno != ENOENT) { 839 else if (errno != ENOENT) {
802 char const *e = strerror(errno); 840 char const *e = strerror(errno);
803 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), 841 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
804 progname, directory, tofield, e); 842 progname, directory, tofield, e);
805 exit(EXIT_FAILURE); 843 exit(EXIT_FAILURE);
806 } 844 }
807 link_errno = (staysymlink ? ENOTSUP 845 link_errno = (staysymlink ? ENOTSUP
808 : link(fromfield, tofield) == 0 ? 0 : errno); 846 : link(fromfield, tofield) == 0 ? 0 : errno);
809 if (link_errno == ENOENT && !todirs_made) { 847 if (link_errno == ENOENT && !todirs_made) {
810 mkdirs(tofield, true); 848 mkdirs(tofield, true);
811 todirs_made = true; 849 todirs_made = true;
812 link_errno = link(fromfield, tofield) == 0 ? 0 : errno; 850 link_errno = link(fromfield, tofield) == 0 ? 0 : errno;
813 } 851 }
814 if (link_errno != 0) { 852 if (link_errno != 0) {
815 const char *s = fromfield; 853 bool absolute = *fromfield == '/';
816 const char *t; 854 char *linkalloc = absolute ? NULL : relname(fromfield, tofield);
817 char *p; 855 char const *contents = absolute ? fromfield : linkalloc;
818 size_t dotdots = 0; 856 int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
819 char *symlinkcontents; 
820 int symlink_errno; 
821 
822 do 
823 t = s; 
824 while ((s = strchr(s, '/')) 
825 && strncmp(fromfield, tofield, ++s - fromfield) == 0); 
826 
827 for (s = tofield + (t - fromfield); *s; s++) 
828 dotdots += *s == '/'; 
829 symlinkcontents = emalloc(3 * dotdots + strlen(t) + 1); 
830 for (p = symlinkcontents; dotdots-- != 0; p += 3) 
831 memcpy(p, "../", 3); 
832 strcpy(p, t); 
833 symlink_errno = symlink(symlinkcontents, tofield) == 0 ? 0 : errno; 
834 if (symlink_errno == ENOENT && !todirs_made) { 857 if (symlink_errno == ENOENT && !todirs_made) {
835 mkdirs(tofield, true); 858 mkdirs(tofield, true);
836 symlink_errno = symlink(symlinkcontents, tofield) == 0 ? 0 : errno; 859 symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
837 } 860 }
838 free(symlinkcontents); 861 free(linkalloc);
839 if (symlink_errno == 0) { 862 if (symlink_errno == 0) {
840 if (link_errno != ENOTSUP) 863 if (link_errno != ENOTSUP)
841 warning(_("symbolic link used because hard link failed: %s"), 864 warning(_("symbolic link used because hard link failed: %s"),
842 strerror(link_errno)); 865 strerror(link_errno));
843 } else { 866 } else {
844 FILE *fp, *tp; 867 FILE *fp, *tp;
845 int c; 868 int c;
846 fp = fopen(fromfield, "rb"); 869 fp = fopen(fromfield, "rb");
847 if (!fp) { 870 if (!fp) {
848 char const *e = strerror(errno); 871 char const *e = strerror(errno);
849 fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), 872 fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
850 progname, directory, fromfield, e); 873 progname, directory, fromfield, e);
851 exit(EXIT_FAILURE); 874 exit(EXIT_FAILURE);
852 } 875 }
853 tp = fopen(tofield, "wb"); 876 tp = fopen(tofield, "wb");
854 if (!tp) { 877 if (!tp) {
855 char const *e = strerror(errno); 878 char const *e = strerror(errno);
856 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), 879 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
857 progname, directory, tofield, e); 880 progname, directory, tofield, e);
858 exit(EXIT_FAILURE); 881 exit(EXIT_FAILURE);
859 } 882 }
860 while ((c = getc(fp)) != EOF) 883 while ((c = getc(fp)) != EOF)
861 putc(c, tp); 884 putc(c, tp);
862 close_file(fp, directory, fromfield); 885 close_file(fp, directory, fromfield);
863 close_file(tp, directory, tofield); 886 close_file(tp, directory, tofield);
864 if (link_errno != ENOTSUP) 887 if (link_errno != ENOTSUP)
865 warning(_("copy used because hard link failed: %s"), 888 warning(_("copy used because hard link failed: %s"),
866 strerror(link_errno)); 889 strerror(link_errno));
867 else if (symlink_errno != ENOTSUP) 890 else if (symlink_errno != ENOTSUP)
868 warning(_("copy used because symbolic link failed: %s"), 891 warning(_("copy used because symbolic link failed: %s"),
869 strerror(symlink_errno)); 892 strerror(symlink_errno));
870 } 893 }
871 } 894 }
872} 895}
873 896
874#define TIME_T_BITS_IN_FILE 64 897#define TIME_T_BITS_IN_FILE 64
875 898
876static zic_t const min_time = MINVAL (zic_t, TIME_T_BITS_IN_FILE); 899static zic_t const min_time = MINVAL (zic_t, TIME_T_BITS_IN_FILE);
877static zic_t const max_time = MAXVAL (zic_t, TIME_T_BITS_IN_FILE); 900static zic_t const max_time = MAXVAL (zic_t, TIME_T_BITS_IN_FILE);
878 901
879/* Estimated time of the Big Bang, in seconds since the POSIX epoch. 902/* Estimated time of the Big Bang, in seconds since the POSIX epoch.
880 rounded downward to the negation of a power of two that is 903 rounded downward to the negation of a power of two that is
881 comfortably outside the error bounds. 904 comfortably outside the error bounds.
882 905
883 For the time of the Big Bang, see: 906 For the time of the Big Bang, see:
884 907
885 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results. 908 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
886 I. Overview of products and scientific results. 909 I. Overview of products and scientific results.
887 arXiv:1303.5062 2013-03-20 20:10:01 UTC 910 arXiv:1303.5062 2013-03-20 20:10:01 UTC
888 <http://arxiv.org/pdf/1303.5062v1> [PDF] 911 <http://arxiv.org/pdf/1303.5062v1> [PDF]
889 912
890 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits 913 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
891 gives the value 13.798 plus-or-minus 0.037 billion years. 914 gives the value 13.798 plus-or-minus 0.037 billion years.
892 Multiplying this by 1000000000 and then by 31557600 (the number of 915 Multiplying this by 1000000000 and then by 31557600 (the number of
893 seconds in an astronomical year) gives a value that is comfortably 916 seconds in an astronomical year) gives a value that is comfortably
894 less than 2**59, so BIG_BANG is - 2**59. 917 less than 2**59, so BIG_BANG is - 2**59.
895 918
896 BIG_BANG is approximate, and may change in future versions. 919 BIG_BANG is approximate, and may change in future versions.
897 Please do not rely on its exact value. */ 920 Please do not rely on its exact value. */
898 921
899#ifndef BIG_BANG 922#ifndef BIG_BANG
900#define BIG_BANG (- (1LL << 59)) 923#define BIG_BANG (- (1LL << 59))
901#endif 924#endif
902 925
903/* If true, work around GNOME bug 730332 926/* If true, work around GNOME bug 730332
904 <https://bugzilla.gnome.org/show_bug.cgi?id=730332> 927 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>
905 by refusing to output time stamps before BIG_BANG. 928 by refusing to output time stamps before BIG_BANG.
906 Such time stamps are physically suspect anyway. 929 Such time stamps are physically suspect anyway.
907 930
908 The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so 931 The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so
909 this workaround will no longer be needed when GNOME 3.21 and 932 this workaround will no longer be needed when GNOME 3.21 and
910 earlier are obsolete, say in the year 2021. */ 933 earlier are obsolete, say in the year 2021. */
911enum { WORK_AROUND_GNOME_BUG_730332 = true }; 934enum { WORK_AROUND_GNOME_BUG_730332 = true };
912 935
913static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332 936static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332
914 ? BIG_BANG 937 ? BIG_BANG
915 : MINVAL(zic_t, TIME_T_BITS_IN_FILE)); 938 : MINVAL(zic_t, TIME_T_BITS_IN_FILE));
916 939
917/* Return 1 if NAME is a directory, 2 if a symbolic link, 0 if 940/* Return 1 if NAME is a directory, 2 if a symbolic link, 0 if
918 something else, -1 (setting errno) if trouble. */ 941 something else, -1 (setting errno) if trouble. */
919static int 942static int
920itsdir(char const *name) 943itsdir(char const *name)
921{ 944{
922 struct stat st; 945 struct stat st;
923 int res = lstat(name, &st); 946 int res = lstat(name, &st);
924 if (res == 0) { 947 if (res == 0) {
925#ifdef S_ISDIR 948#ifdef S_ISDIR
926 return S_ISDIR(st.st_mode) ? 1 : S_ISLNK(st.st_mode) ? 2 : 0; 949 return S_ISDIR(st.st_mode) ? 1 : S_ISLNK(st.st_mode) ? 2 : 0;
927#else 950#else
928 size_t n = strlen(name); 951 size_t n = strlen(name);
929 char *nameslashdot = emalloc(n + 3); 952 char *nameslashdot = emalloc(n + 3);
930 bool dir; 953 bool dir;
931 memcpy(nameslashdot, name, n); 954 memcpy(nameslashdot, name, n);
932 strcpy(&nameslashdot[n], &"/."[! (n && name[n - 1] != '/')]); 955 strcpy(&nameslashdot[n], &"/."[! (n && name[n - 1] != '/')]);
933 dir = lstat(nameslashdot, &st) == 0; 956 dir = lstat(nameslashdot, &st) == 0;
934 free(nameslashdot); 957 free(nameslashdot);
935 return dir; 958 return dir;
936#endif 959#endif
937 } 960 }
938 return -1; 961 return -1;
939} 962}
940 963
941/* 964/*
942** Associate sets of rules with zones. 965** Associate sets of rules with zones.
943*/ 966*/
944 967
945/* 968/*
946** Sort by rule name. 969** Sort by rule name.
947*/ 970*/
948 971
949static int 972static int
950rcomp(const void *cp1, const void *cp2) 973rcomp(const void *cp1, const void *cp2)
951{ 974{
952 return strcmp(((const struct rule *) cp1)->r_name, 975 return strcmp(((const struct rule *) cp1)->r_name,
953 ((const struct rule *) cp2)->r_name); 976 ((const struct rule *) cp2)->r_name);
954} 977}
955 978
956static void 979static void
957associate(void) 980associate(void)
958{ 981{
959 struct zone * zp; 982 struct zone * zp;
960 struct rule * rp; 983 struct rule * rp;
961 int base, out; 984 int base, out;
962 int i, j; 985 int i, j;
963 986
964 if (nrules != 0) { 987 if (nrules != 0) {
965 qsort(rules, (size_t)nrules, sizeof *rules, rcomp); 988 qsort(rules, (size_t)nrules, sizeof *rules, rcomp);
966 for (i = 0; i < nrules - 1; ++i) { 989 for (i = 0; i < nrules - 1; ++i) {
967 if (strcmp(rules[i].r_name, 990 if (strcmp(rules[i].r_name,
968 rules[i + 1].r_name) != 0) 991 rules[i + 1].r_name) != 0)
969 continue; 992 continue;
970 if (strcmp(rules[i].r_filename, 993 if (strcmp(rules[i].r_filename,
971 rules[i + 1].r_filename) == 0) 994 rules[i + 1].r_filename) == 0)
972 continue; 995 continue;
973 eat(rules[i].r_filename, rules[i].r_linenum); 996 eat(rules[i].r_filename, rules[i].r_linenum);
974 warning(_("same rule name in multiple files")); 997 warning(_("same rule name in multiple files"));
975 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 998 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
976 warning(_("same rule name in multiple files")); 999 warning(_("same rule name in multiple files"));
977 for (j = i + 2; j < nrules; ++j) { 1000 for (j = i + 2; j < nrules; ++j) {
978 if (strcmp(rules[i].r_name, 1001 if (strcmp(rules[i].r_name,
979 rules[j].r_name) != 0) 1002 rules[j].r_name) != 0)
980 break; 1003 break;
981 if (strcmp(rules[i].r_filename, 1004 if (strcmp(rules[i].r_filename,
982 rules[j].r_filename) == 0) 1005 rules[j].r_filename) == 0)
983 continue; 1006 continue;
984 if (strcmp(rules[i + 1].r_filename, 1007 if (strcmp(rules[i + 1].r_filename,
985 rules[j].r_filename) == 0) 1008 rules[j].r_filename) == 0)
986 continue; 1009 continue;
987 break; 1010 break;
988 } 1011 }
989 i = j - 1; 1012 i = j - 1;
990 } 1013 }
991 } 1014 }
992 for (i = 0; i < nzones; ++i) { 1015 for (i = 0; i < nzones; ++i) {
993 zp = &zones[i]; 1016 zp = &zones[i];
994 zp->z_rules = NULL; 1017 zp->z_rules = NULL;
995 zp->z_nrules = 0; 1018 zp->z_nrules = 0;
996 } 1019 }
997 for (base = 0; base < nrules; base = out) { 1020 for (base = 0; base < nrules; base = out) {
998 rp = &rules[base]; 1021 rp = &rules[base];
999 for (out = base + 1; out < nrules; ++out) 1022 for (out = base + 1; out < nrules; ++out)
1000 if (strcmp(rp->r_name, rules[out].r_name) != 0) 1023 if (strcmp(rp->r_name, rules[out].r_name) != 0)
1001 break; 1024 break;
1002 for (i = 0; i < nzones; ++i) { 1025 for (i = 0; i < nzones; ++i) {
1003 zp = &zones[i]; 1026 zp = &zones[i];
1004 if (strcmp(zp->z_rule, rp->r_name) != 0) 1027 if (strcmp(zp->z_rule, rp->r_name) != 0)
1005 continue; 1028 continue;
1006 zp->z_rules = rp; 1029 zp->z_rules = rp;
1007 zp->z_nrules = out - base; 1030 zp->z_nrules = out - base;
1008 } 1031 }
1009 } 1032 }
1010 for (i = 0; i < nzones; ++i) { 1033 for (i = 0; i < nzones; ++i) {
1011 zp = &zones[i]; 1034 zp = &zones[i];
1012 if (zp->z_nrules == 0) { 1035 if (zp->z_nrules == 0) {
1013 /* 1036 /*
1014 ** Maybe we have a local standard time offset. 1037 ** Maybe we have a local standard time offset.
1015 */ 1038 */
1016 eat(zp->z_filename, zp->z_linenum); 1039 eat(zp->z_filename, zp->z_linenum);
1017 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"), 1040 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
1018 true); 1041 true);
1019 /* 1042 /*
1020 ** Note, though, that if there's no rule, 1043 ** Note, though, that if there's no rule,
1021 ** a '%s' in the format is a bad thing. 1044 ** a '%s' in the format is a bad thing.
1022 */ 1045 */
1023 if (zp->z_format_specifier == 's') 1046 if (zp->z_format_specifier == 's')
1024 error("%s", _("%s in ruleless zone")); 1047 error("%s", _("%s in ruleless zone"));
1025 } 1048 }
1026 } 1049 }
1027 if (errors) 1050 if (errors)
1028 exit(EXIT_FAILURE); 1051 exit(EXIT_FAILURE);
1029} 1052}
1030 1053
1031static void 1054static void
1032infile(const char *name) 1055infile(const char *name)
1033{ 1056{
1034 FILE * fp; 1057 FILE * fp;
1035 char ** fields; 1058 char ** fields;
1036 char * cp; 1059 char * cp;
1037 const struct lookup * lp; 1060 const struct lookup * lp;
1038 int nfields; 1061 int nfields;
1039 bool wantcont; 1062 bool wantcont;
1040 int num; 1063 int num;
1041 char buf[BUFSIZ]; 1064 char buf[BUFSIZ];
1042 1065
1043 if (strcmp(name, "-") == 0) { 1066 if (strcmp(name, "-") == 0) {
1044 name = _("standard input"); 1067 name = _("standard input");
1045 fp = stdin; 1068 fp = stdin;
1046 } else if ((fp = fopen(name, "r")) == NULL) { 1069 } else if ((fp = fopen(name, "r")) == NULL) {
1047 const char *e = strerror(errno); 1070 const char *e = strerror(errno);
1048 1071
1049 fprintf(stderr, _("%s: Can't open %s: %s\n"), 1072 fprintf(stderr, _("%s: Can't open %s: %s\n"),
1050 progname, name, e); 1073 progname, name, e);
1051 exit(EXIT_FAILURE); 1074 exit(EXIT_FAILURE);
1052 } 1075 }
1053 wantcont = false; 1076 wantcont = false;
1054 for (num = 1; ; ++num) { 1077 for (num = 1; ; ++num) {
1055 eat(name, num); 1078 eat(name, num);
1056 if (fgets(buf, (int) sizeof buf, fp) != buf) 1079 if (fgets(buf, (int) sizeof buf, fp) != buf)
1057 break; 1080 break;
1058 cp = strchr(buf, '\n'); 1081 cp = strchr(buf, '\n');
1059 if (cp == NULL) { 1082 if (cp == NULL) {
1060 error(_("line too long")); 1083 error(_("line too long"));
1061 exit(EXIT_FAILURE); 1084 exit(EXIT_FAILURE);
1062 } 1085 }
1063 *cp = '\0'; 1086 *cp = '\0';
1064 fields = getfields(buf); 1087 fields = getfields(buf);
1065 nfields = 0; 1088 nfields = 0;
1066 while (fields[nfields] != NULL) { 1089 while (fields[nfields] != NULL) {
1067 static char nada; 1090 static char nada;
1068 1091
1069 if (strcmp(fields[nfields], "-") == 0) 1092 if (strcmp(fields[nfields], "-") == 0)
1070 fields[nfields] = &nada; 1093 fields[nfields] = &nada;
1071 ++nfields; 1094 ++nfields;
1072 } 1095 }
1073 if (nfields == 0) { 1096 if (nfields == 0) {
1074 /* nothing to do */ 1097 /* nothing to do */
1075 } else if (wantcont) { 1098 } else if (wantcont) {
1076 wantcont = inzcont(fields, nfields); 1099 wantcont = inzcont(fields, nfields);
1077 } else { 1100 } else {
1078 lp = byword(fields[0], line_codes); 1101 lp = byword(fields[0], line_codes);
1079 if (lp == NULL) 1102 if (lp == NULL)
1080 error(_("input line of unknown type")); 1103 error(_("input line of unknown type"));
1081 else switch ((int) (lp->l_value)) { 1104 else switch ((int) (lp->l_value)) {
1082 case LC_RULE: 1105 case LC_RULE:
1083 inrule(fields, nfields); 1106 inrule(fields, nfields);
1084 wantcont = false; 1107 wantcont = false;
1085 break; 1108 break;
1086 case LC_ZONE: 1109 case LC_ZONE:
1087 wantcont = inzone(fields, nfields); 1110 wantcont = inzone(fields, nfields);
1088 break; 1111 break;
1089 case LC_LINK: 1112 case LC_LINK:
1090 inlink(fields, nfields); 1113 inlink(fields, nfields);
1091 wantcont = false; 1114 wantcont = false;
1092 break; 1115 break;
1093 case LC_LEAP: 1116 case LC_LEAP:
1094 if (name != leapsec) 1117 if (name != leapsec)
1095 warning(_("%s: Leap line in non leap" 1118 warning(_("%s: Leap line in non leap"
1096 " seconds file %s"), 1119 " seconds file %s"),
1097 progname, name); 1120 progname, name);
1098 else inleap(fields, nfields); 1121 else inleap(fields, nfields);
1099 wantcont = false; 1122 wantcont = false;
1100 break; 1123 break;
1101 default: /* "cannot happen" */ 1124 default: /* "cannot happen" */
1102 fprintf(stderr, 1125 fprintf(stderr,
1103_("%s: panic: Invalid l_value %d\n"), 1126_("%s: panic: Invalid l_value %d\n"),
1104 progname, lp->l_value); 1127 progname, lp->l_value);
1105 exit(EXIT_FAILURE); 1128 exit(EXIT_FAILURE);
1106 } 1129 }
1107 } 1130 }
1108 free(fields); 1131 free(fields);
1109 } 1132 }
1110 close_file(fp, NULL, filename); 1133 close_file(fp, NULL, filename);
1111 if (wantcont) 1134 if (wantcont)
1112 error(_("expected continuation line not found")); 1135 error(_("expected continuation line not found"));
1113} 1136}
1114 1137
1115/* 1138/*
1116** Convert a string of one of the forms 1139** Convert a string of one of the forms
1117** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 1140** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1118** into a number of seconds. 1141** into a number of seconds.
1119** A null string maps to zero. 1142** A null string maps to zero.
1120** Call error with errstring and return zero on errors. 1143** Call error with errstring and return zero on errors.
1121*/ 1144*/
1122 1145
1123static zic_t 1146static zic_t
1124gethms(char const *string, char const *errstring, bool signable) 1147gethms(char const *string, char const *errstring, bool signable)
1125{ 1148{
1126 zic_t hh; 1149 zic_t hh;
1127 int mm, ss, sign; 1150 int mm, ss, sign;
1128 char xs; 1151 char xs;
1129 1152
1130 if (string == NULL || *string == '\0') 1153 if (string == NULL || *string == '\0')
1131 return 0; 1154 return 0;
1132 if (!signable) 1155 if (!signable)
1133 sign = 1; 1156 sign = 1;
1134 else if (*string == '-') { 1157 else if (*string == '-') {
1135 sign = -1; 1158 sign = -1;
1136 ++string; 1159 ++string;
1137 } else sign = 1; 1160 } else sign = 1;
1138 if (sscanf(string, "%"SCNdZIC"%c", &hh, &xs) == 1) 1161 if (sscanf(string, "%"SCNdZIC"%c", &hh, &xs) == 1)
1139 mm = ss = 0; 1162 mm = ss = 0;
1140 else if (sscanf(string, "%"SCNdZIC":%d%c", &hh, &mm, &xs) == 2) 1163 else if (sscanf(string, "%"SCNdZIC":%d%c", &hh, &mm, &xs) == 2)
1141 ss = 0; 1164 ss = 0;
1142 else if (sscanf(string, "%"SCNdZIC":%d:%d%c", &hh, &mm, &ss, &xs) 1165 else if (sscanf(string, "%"SCNdZIC":%d:%d%c", &hh, &mm, &ss, &xs)
1143 != 3) { 1166 != 3) {
1144 error("%s", errstring); 1167 error("%s", errstring);
1145 return 0; 1168 return 0;
1146 } 1169 }
1147 if (hh < 0 || 1170 if (hh < 0 ||
1148 mm < 0 || mm >= MINSPERHOUR || 1171 mm < 0 || mm >= MINSPERHOUR ||
1149 ss < 0 || ss > SECSPERMIN) { 1172 ss < 0 || ss > SECSPERMIN) {
1150 error("%s", errstring); 1173 error("%s", errstring);
1151 return 0; 1174 return 0;
1152 } 1175 }
1153 if (ZIC_MAX / SECSPERHOUR < hh) { 1176 if (ZIC_MAX / SECSPERHOUR < hh) {
1154 error(_("time overflow")); 1177 error(_("time overflow"));
1155 return 0; 1178 return 0;
1156 } 1179 }
1157 if (noise && (hh > HOURSPERDAY || 1180 if (noise && (hh > HOURSPERDAY ||
1158 (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 1181 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1159warning(_("values over 24 hours not handled by pre-2007 versions of zic")); 1182warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1160 return oadd(sign * hh * SECSPERHOUR, 1183 return oadd(sign * hh * SECSPERHOUR,
1161 sign * (mm * SECSPERMIN + ss)); 1184 sign * (mm * SECSPERMIN + ss));
1162} 1185}
1163 1186
1164static void 1187static void
1165inrule(char **fields, int nfields) 1188inrule(char **fields, int nfields)
1166{ 1189{
1167 static struct rule r; 1190 static struct rule r;
1168 1191
1169 if (nfields != RULE_FIELDS) { 1192 if (nfields != RULE_FIELDS) {
1170 error(_("wrong number of fields on Rule line")); 1193 error(_("wrong number of fields on Rule line"));
1171 return; 1194 return;
1172 } 1195 }
1173 if (*fields[RF_NAME] == '\0') { 1196 if (*fields[RF_NAME] == '\0') {
1174 error(_("nameless rule")); 1197 error(_("nameless rule"));
1175 return; 1198 return;
1176 } 1199 }
1177 r.r_filename = filename; 1200 r.r_filename = filename;
1178 r.r_linenum = linenum; 1201 r.r_linenum = linenum;
1179 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), true); 1202 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), true);
1180 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 1203 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1181 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 1204 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1182 r.r_name = ecpyalloc(fields[RF_NAME]); 1205 r.r_name = ecpyalloc(fields[RF_NAME]);
1183 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 1206 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1184 if (max_abbrvar_len < strlen(r.r_abbrvar)) 1207 if (max_abbrvar_len < strlen(r.r_abbrvar))
1185 max_abbrvar_len = strlen(r.r_abbrvar); 1208 max_abbrvar_len = strlen(r.r_abbrvar);
1186 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); 1209 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1187 rules[nrules++] = r; 1210 rules[nrules++] = r;
1188} 1211}
1189 1212
1190static bool 1213static bool
1191inzone(char **fields, int nfields) 1214inzone(char **fields, int nfields)
1192{ 1215{
1193 int i; 1216 int i;
1194 1217
1195 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 1218 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1196 error(_("wrong number of fields on Zone line")); 1219 error(_("wrong number of fields on Zone line"));
1197 return false; 1220 return false;
1198 } 1221 }
1199 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 1222 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1200 error( 1223 error(
1201_("\"Zone %s\" line and -l option are mutually exclusive"), 1224_("\"Zone %s\" line and -l option are mutually exclusive"),
1202 TZDEFAULT); 1225 TZDEFAULT);
1203 return false; 1226 return false;
1204 } 1227 }
1205 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 1228 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1206 error( 1229 error(
1207_("\"Zone %s\" line and -p option are mutually exclusive"), 1230_("\"Zone %s\" line and -p option are mutually exclusive"),
1208 TZDEFRULES); 1231 TZDEFRULES);
1209 return false; 1232 return false;
1210 } 1233 }
1211 for (i = 0; i < nzones; ++i) 1234 for (i = 0; i < nzones; ++i)
1212 if (zones[i].z_name != NULL && 1235 if (zones[i].z_name != NULL &&
1213 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 1236 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1214 error( 1237 error(
1215_("duplicate zone name %s (file \"%s\", line %d)"), 1238_("duplicate zone name %s (file \"%s\", line %d)"),
1216 fields[ZF_NAME], 1239 fields[ZF_NAME],
1217 zones[i].z_filename, 1240 zones[i].z_filename,
1218 zones[i].z_linenum); 1241 zones[i].z_linenum);
1219 return false; 1242 return false;
1220 } 1243 }
1221 return inzsub(fields, nfields, false); 1244 return inzsub(fields, nfields, false);
1222} 1245}
1223 1246
1224static bool 1247static bool
1225inzcont(char **fields, int nfields) 1248inzcont(char **fields, int nfields)
1226{ 1249{
1227 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 1250 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1228 error(_("wrong number of fields on Zone continuation line")); 1251 error(_("wrong number of fields on Zone continuation line"));
1229 return false; 1252 return false;
1230 } 1253 }
1231 return inzsub(fields, nfields, true); 1254 return inzsub(fields, nfields, true);
1232} 1255}
1233 1256
1234static bool 1257static bool
1235inzsub(char **fields, int nfields, const int iscont) 1258inzsub(char **fields, int nfields, const int iscont)
1236{ 1259{
1237 char * cp; 1260 char * cp;
1238 char * cp1; 1261 char * cp1;
1239 static struct zone z; 1262 static struct zone z;
1240 int i_gmtoff, i_rule, i_format; 1263 int i_gmtoff, i_rule, i_format;
1241 int i_untilyear, i_untilmonth; 1264 int i_untilyear, i_untilmonth;
1242 int i_untilday, i_untiltime; 1265 int i_untilday, i_untiltime;
1243 bool hasuntil; 1266 bool hasuntil;
1244 1267
1245 if (iscont) { 1268 if (iscont) {
1246 i_gmtoff = ZFC_GMTOFF; 1269 i_gmtoff = ZFC_GMTOFF;
1247 i_rule = ZFC_RULE; 1270 i_rule = ZFC_RULE;
1248 i_format = ZFC_FORMAT; 1271 i_format = ZFC_FORMAT;
1249 i_untilyear = ZFC_TILYEAR; 1272 i_untilyear = ZFC_TILYEAR;
1250 i_untilmonth = ZFC_TILMONTH; 1273 i_untilmonth = ZFC_TILMONTH;
1251 i_untilday = ZFC_TILDAY; 1274 i_untilday = ZFC_TILDAY;
1252 i_untiltime = ZFC_TILTIME; 1275 i_untiltime = ZFC_TILTIME;
1253 z.z_name = NULL; 1276 z.z_name = NULL;
1254 } else if (!namecheck(fields[ZF_NAME])) 1277 } else if (!namecheck(fields[ZF_NAME]))
1255 return false; 1278 return false;
1256 else { 1279 else {
1257 i_gmtoff = ZF_GMTOFF; 1280 i_gmtoff = ZF_GMTOFF;
1258 i_rule = ZF_RULE; 1281 i_rule = ZF_RULE;
1259 i_format = ZF_FORMAT; 1282 i_format = ZF_FORMAT;
1260 i_untilyear = ZF_TILYEAR; 1283 i_untilyear = ZF_TILYEAR;
1261 i_untilmonth = ZF_TILMONTH; 1284 i_untilmonth = ZF_TILMONTH;
1262 i_untilday = ZF_TILDAY; 1285 i_untilday = ZF_TILDAY;
1263 i_untiltime = ZF_TILTIME; 1286 i_untiltime = ZF_TILTIME;
1264 z.z_name = ecpyalloc(fields[ZF_NAME]); 1287 z.z_name = ecpyalloc(fields[ZF_NAME]);
1265 } 1288 }
1266 z.z_filename = filename; 1289 z.z_filename = filename;
1267 z.z_linenum = linenum; 1290 z.z_linenum = linenum;
1268 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true); 1291 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
1269 if ((cp = strchr(fields[i_format], '%')) != 0) { 1292 if ((cp = strchr(fields[i_format], '%')) != 0) {
1270 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') 1293 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1271 || strchr(fields[i_format], '/')) { 1294 || strchr(fields[i_format], '/')) {
1272 error(_("invalid abbreviation format")); 1295 error(_("invalid abbreviation format"));
1273 return false; 1296 return false;
1274 } 1297 }
1275 } 1298 }
1276 z.z_rule = ecpyalloc(fields[i_rule]); 1299 z.z_rule = ecpyalloc(fields[i_rule]);
1277 z.z_format = cp1 = ecpyalloc(fields[i_format]); 1300 z.z_format = cp1 = ecpyalloc(fields[i_format]);
1278 z.z_format_specifier = cp ? *cp : '\0'; 1301 z.z_format_specifier = cp ? *cp : '\0';
1279 if (z.z_format_specifier == 'z') { 1302 if (z.z_format_specifier == 'z') {
1280 if (noise) 1303 if (noise)
1281 warning(_("format '%s' not handled by pre-2015 versions of zic"), 1304 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1282 z.z_format); 1305 z.z_format);
1283 cp1[cp - fields[i_format]] = 's'; 1306 cp1[cp - fields[i_format]] = 's';
1284 } 1307 }
1285 if (max_format_len < strlen(z.z_format)) 1308 if (max_format_len < strlen(z.z_format))
1286 max_format_len = strlen(z.z_format); 1309 max_format_len = strlen(z.z_format);
1287 hasuntil = nfields > i_untilyear; 1310 hasuntil = nfields > i_untilyear;
1288 if (hasuntil) { 1311 if (hasuntil) {
1289 z.z_untilrule.r_filename = filename; 1312 z.z_untilrule.r_filename = filename;
1290 z.z_untilrule.r_linenum = linenum; 1313 z.z_untilrule.r_linenum = linenum;
1291 rulesub(&z.z_untilrule, 1314 rulesub(&z.z_untilrule,
1292 fields[i_untilyear], 1315 fields[i_untilyear],
1293 "only", 1316 "only",
1294 "", 1317 "",
1295 (nfields > i_untilmonth) ? 1318 (nfields > i_untilmonth) ?
1296 fields[i_untilmonth] : "Jan", 1319 fields[i_untilmonth] : "Jan",
1297 (nfields > i_untilday) ? fields[i_untilday] : "1", 1320 (nfields > i_untilday) ? fields[i_untilday] : "1",
1298 (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 1321 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1299 z.z_untiltime = rpytime(&z.z_untilrule, 1322 z.z_untiltime = rpytime(&z.z_untilrule,
1300 z.z_untilrule.r_loyear); 1323 z.z_untilrule.r_loyear);
1301 if (iscont && nzones > 0 && 1324 if (iscont && nzones > 0 &&
1302 z.z_untiltime > min_time && 1325 z.z_untiltime > min_time &&
1303 z.z_untiltime < max_time && 1326 z.z_untiltime < max_time &&
1304 zones[nzones - 1].z_untiltime > min_time && 1327 zones[nzones - 1].z_untiltime > min_time &&
1305 zones[nzones - 1].z_untiltime < max_time && 1328 zones[nzones - 1].z_untiltime < max_time &&
1306 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1329 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1307 error(_( 1330 error(_(
1308"Zone continuation line end time is not after end time of previous line" 1331"Zone continuation line end time is not after end time of previous line"
1309 )); 1332 ));
1310 return false; 1333 return false;
1311 } 1334 }
1312 } 1335 }
1313 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc); 1336 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1314 zones[nzones++] = z; 1337 zones[nzones++] = z;
1315 /* 1338 /*
1316 ** If there was an UNTIL field on this line, 1339 ** If there was an UNTIL field on this line,
1317 ** there's more information about the zone on the next line. 1340 ** there's more information about the zone on the next line.
1318 */ 1341 */
1319 return hasuntil; 1342 return hasuntil;
1320} 1343}
1321 1344
1322static void 1345static void
1323inleap(char **fields, int nfields) 1346inleap(char **fields, int nfields)
1324{ 1347{
1325 const char * cp; 1348 const char * cp;
1326 const struct lookup * lp; 1349 const struct lookup * lp;
1327 int i, j; 1350 int i, j;
1328 zic_t year; 1351 zic_t year;
1329 int month, day; 1352 int month, day;
1330 zic_t dayoff, tod; 1353 zic_t dayoff, tod;
1331 zic_t t; 1354 zic_t t;
1332 char xs; 1355 char xs;
1333 1356
1334 if (nfields != LEAP_FIELDS) { 1357 if (nfields != LEAP_FIELDS) {
1335 error(_("wrong number of fields on Leap line")); 1358 error(_("wrong number of fields on Leap line"));
1336 return; 1359 return;
1337 } 1360 }
1338 dayoff = 0; 1361 dayoff = 0;
1339 cp = fields[LP_YEAR]; 1362 cp = fields[LP_YEAR];
1340 if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) { 1363 if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
1341 /* 1364 /*
1342 ** Leapin' Lizards! 1365 ** Leapin' Lizards!
1343 */ 1366 */
1344 error(_("invalid leaping year")); 1367 error(_("invalid leaping year"));
1345 return; 1368 return;
1346 } 1369 }
1347 if (!leapseen || leapmaxyear < year) 1370 if (!leapseen || leapmaxyear < year)
1348 leapmaxyear = year; 1371 leapmaxyear = year;
1349 if (!leapseen || leapminyear > year) 1372 if (!leapseen || leapminyear > year)
1350 leapminyear = year; 1373 leapminyear = year;
1351 leapseen = true; 1374 leapseen = true;
1352 j = EPOCH_YEAR; 1375 j = EPOCH_YEAR;
1353 while (j != year) { 1376 while (j != year) {
1354 if (year > j) { 1377 if (year > j) {
1355 i = len_years[isleap(j)]; 1378 i = len_years[isleap(j)];
1356 ++j; 1379 ++j;
1357 } else { 1380 } else {
1358 --j; 1381 --j;
1359 i = -len_years[isleap(j)]; 1382 i = -len_years[isleap(j)];
1360 } 1383 }
1361 dayoff = oadd(dayoff, i); 1384 dayoff = oadd(dayoff, i);
1362 } 1385 }
1363 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1386 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1364 error(_("invalid month name")); 1387 error(_("invalid month name"));
1365 return; 1388 return;
1366 } 1389 }
1367 month = lp->l_value; 1390 month = lp->l_value;
1368 j = TM_JANUARY; 1391 j = TM_JANUARY;
1369 while (j != month) { 1392 while (j != month) {
1370 i = len_months[isleap(year)][j]; 1393 i = len_months[isleap(year)][j];
1371 dayoff = oadd(dayoff, i); 1394 dayoff = oadd(dayoff, i);
1372 ++j; 1395 ++j;
1373 } 1396 }
1374 cp = fields[LP_DAY]; 1397 cp = fields[LP_DAY];
1375 if (sscanf(cp, "%d%c", &day, &xs) != 1 || 1398 if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1376 day <= 0 || day > len_months[isleap(year)][month]) { 1399 day <= 0 || day > len_months[isleap(year)][month]) {
1377 error(_("invalid day of month")); 1400 error(_("invalid day of month"));
1378 return; 1401 return;
1379 } 1402 }
1380 dayoff = oadd(dayoff, day - 1); 1403 dayoff = oadd(dayoff, day - 1);
1381 if (dayoff < min_time / SECSPERDAY) { 1404 if (dayoff < min_time / SECSPERDAY) {
1382 error(_("time too small")); 1405 error(_("time too small"));
1383 return; 1406 return;
1384 } 1407 }
1385 if (dayoff > max_time / SECSPERDAY) { 1408 if (dayoff > max_time / SECSPERDAY) {
1386 error(_("time too large")); 1409 error(_("time too large"));
1387 return; 1410 return;
1388 } 1411 }
1389 t = dayoff * SECSPERDAY; 1412 t = dayoff * SECSPERDAY;
1390 tod = gethms(fields[LP_TIME], _("invalid time of day"), false); 1413 tod = gethms(fields[LP_TIME], _("invalid time of day"), false);
1391 cp = fields[LP_CORR]; 1414 cp = fields[LP_CORR];
1392 { 1415 {
1393 bool positive; 1416 bool positive;
1394 int count; 1417 int count;
1395 1418
1396 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 1419 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1397 positive = false; 1420 positive = false;
1398 count = 1; 1421 count = 1;
1399 } else if (strcmp(cp, "--") == 0) { 1422 } else if (strcmp(cp, "--") == 0) {
1400 positive = false; 1423 positive = false;
1401 count = 2; 1424 count = 2;
1402 } else if (strcmp(cp, "+") == 0) { 1425 } else if (strcmp(cp, "+") == 0) {
1403 positive = true; 1426 positive = true;
1404 count = 1; 1427 count = 1;
1405 } else if (strcmp(cp, "++") == 0) { 1428 } else if (strcmp(cp, "++") == 0) {
1406 positive = true; 1429 positive = true;
1407 count = 2; 1430 count = 2;
1408 } else { 1431 } else {
1409 error(_("illegal CORRECTION field on Leap line")); 1432 error(_("illegal CORRECTION field on Leap line"));
1410 return; 1433 return;
1411 } 1434 }
1412 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1435 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1413 error(_( 1436 error(_(
1414 "illegal Rolling/Stationary field on Leap line" 1437 "illegal Rolling/Stationary field on Leap line"
1415 )); 1438 ));
1416 return; 1439 return;
1417 } 1440 }
1418 t = tadd(t, tod); 1441 t = tadd(t, tod);
1419 if (t < early_time) { 1442 if (t < early_time) {
1420 error(_("leap second precedes Big Bang")); 1443 error(_("leap second precedes Big Bang"));
1421 return; 1444 return;
1422 } 1445 }
1423 leapadd(t, positive, lp->l_value, count); 1446 leapadd(t, positive, lp->l_value, count);
1424 } 1447 }
1425} 1448}
1426 1449
1427static void 1450static void
1428inlink(char **fields, int nfields) 1451inlink(char **fields, int nfields)
1429{ 1452{
1430 struct link l; 1453 struct link l;
1431 1454
1432 if (nfields != LINK_FIELDS) { 1455 if (nfields != LINK_FIELDS) {
1433 error(_("wrong number of fields on Link line")); 1456 error(_("wrong number of fields on Link line"));
1434 return; 1457 return;
1435 } 1458 }
1436 if (*fields[LF_FROM] == '\0') { 1459 if (*fields[LF_FROM] == '\0') {
1437 error(_("blank FROM field on Link line")); 1460 error(_("blank FROM field on Link line"));
1438 return; 1461 return;
1439 } 1462 }
1440 if (! namecheck(fields[LF_TO])) 1463 if (! namecheck(fields[LF_TO]))
1441 return; 1464 return;
1442 l.l_filename = filename; 1465 l.l_filename = filename;
1443 l.l_linenum = linenum; 1466 l.l_linenum = linenum;
1444 l.l_from = ecpyalloc(fields[LF_FROM]); 1467 l.l_from = ecpyalloc(fields[LF_FROM]);
1445 l.l_to = ecpyalloc(fields[LF_TO]); 1468 l.l_to = ecpyalloc(fields[LF_TO]);
1446 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); 1469 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1447 links[nlinks++] = l; 1470 links[nlinks++] = l;
1448} 1471}
1449 1472
1450static void 1473static void
1451rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, 1474rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1452 const char *typep, const char *monthp, const char *dayp, 1475 const char *typep, const char *monthp, const char *dayp,
1453 const char *timep) 1476 const char *timep)
1454{ 1477{
1455 const struct lookup * lp; 1478 const struct lookup * lp;
1456 const char * cp; 1479 const char * cp;
1457 char * dp; 1480 char * dp;
1458 char * ep; 1481 char * ep;
1459 char xs; 1482 char xs;
1460 1483
1461 if ((lp = byword(monthp, mon_names)) == NULL) { 1484 if ((lp = byword(monthp, mon_names)) == NULL) {
1462 error(_("invalid month name")); 1485 error(_("invalid month name"));
1463 return; 1486 return;
1464 } 1487 }
1465 rp->r_month = lp->l_value; 1488 rp->r_month = lp->l_value;
1466 rp->r_todisstd = false; 1489 rp->r_todisstd = false;
1467 rp->r_todisgmt = false; 1490 rp->r_todisgmt = false;
1468 dp = ecpyalloc(timep); 1491 dp = ecpyalloc(timep);
1469 if (*dp != '\0') { 1492 if (*dp != '\0') {
1470 ep = dp + strlen(dp) - 1; 1493 ep = dp + strlen(dp) - 1;
1471 switch (lowerit(*ep)) { 1494 switch (lowerit(*ep)) {
1472 case 's': /* Standard */ 1495 case 's': /* Standard */
1473 rp->r_todisstd = true; 1496 rp->r_todisstd = true;
1474 rp->r_todisgmt = false; 1497 rp->r_todisgmt = false;
1475 *ep = '\0'; 1498 *ep = '\0';
1476 break; 1499 break;
1477 case 'w': /* Wall */ 1500 case 'w': /* Wall */
1478 rp->r_todisstd = false; 1501 rp->r_todisstd = false;
1479 rp->r_todisgmt = false; 1502 rp->r_todisgmt = false;
1480 *ep = '\0'; 1503 *ep = '\0';
1481 break; 1504 break;
1482 case 'g': /* Greenwich */ 1505 case 'g': /* Greenwich */
1483 case 'u': /* Universal */ 1506 case 'u': /* Universal */
1484 case 'z': /* Zulu */ 1507 case 'z': /* Zulu */
1485 rp->r_todisstd = true; 1508 rp->r_todisstd = true;
1486 rp->r_todisgmt = true; 1509 rp->r_todisgmt = true;
1487 *ep = '\0'; 1510 *ep = '\0';
1488 break; 1511 break;
1489 } 1512 }
1490 } 1513 }
1491 rp->r_tod = gethms(dp, _("invalid time of day"), false); 1514 rp->r_tod = gethms(dp, _("invalid time of day"), false);
1492 free(dp); 1515 free(dp);
1493 /* 1516 /*
1494 ** Year work. 1517 ** Year work.
1495 */ 1518 */
1496 cp = loyearp; 1519 cp = loyearp;
1497 lp = byword(cp, begin_years); 1520 lp = byword(cp, begin_years);
1498 rp->r_lowasnum = lp == NULL; 1521 rp->r_lowasnum = lp == NULL;
1499 if (!rp->r_lowasnum) switch ((int) lp->l_value) { 1522 if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1500 case YR_MINIMUM: 1523 case YR_MINIMUM:
1501 rp->r_loyear = ZIC_MIN; 1524 rp->r_loyear = ZIC_MIN;
1502 break; 1525 break;
1503 case YR_MAXIMUM: 1526 case YR_MAXIMUM:
1504 rp->r_loyear = ZIC_MAX; 1527 rp->r_loyear = ZIC_MAX;
1505 break; 1528 break;
1506 default: /* "cannot happen" */ 1529 default: /* "cannot happen" */
1507 fprintf(stderr, 1530 fprintf(stderr,
1508 _("%s: panic: Invalid l_value %d\n"), 1531 _("%s: panic: Invalid l_value %d\n"),
1509 progname, lp->l_value); 1532 progname, lp->l_value);
1510 exit(EXIT_FAILURE); 1533 exit(EXIT_FAILURE);
1511 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) { 1534 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
1512 error(_("invalid starting year")); 1535 error(_("invalid starting year"));
1513 return; 1536 return;
1514 } 1537 }
1515 cp = hiyearp; 1538 cp = hiyearp;
1516 lp = byword(cp, end_years); 1539 lp = byword(cp, end_years);
1517 rp->r_hiwasnum = lp == NULL; 1540 rp->r_hiwasnum = lp == NULL;
1518 if (!rp->r_hiwasnum) switch ((int) lp->l_value) { 1541 if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1519 case YR_MINIMUM: 1542 case YR_MINIMUM:
1520 rp->r_hiyear = ZIC_MIN; 1543 rp->r_hiyear = ZIC_MIN;
1521 break; 1544 break;
1522 case YR_MAXIMUM: 1545 case YR_MAXIMUM:
1523 rp->r_hiyear = ZIC_MAX; 1546 rp->r_hiyear = ZIC_MAX;
1524 break; 1547 break;
1525 case YR_ONLY: 1548 case YR_ONLY:
1526 rp->r_hiyear = rp->r_loyear; 1549 rp->r_hiyear = rp->r_loyear;
1527 break; 1550 break;
1528 default: /* "cannot happen" */ 1551 default: /* "cannot happen" */
1529 fprintf(stderr, 1552 fprintf(stderr,
1530 _("%s: panic: Invalid l_value %d\n"), 1553 _("%s: panic: Invalid l_value %d\n"),
1531 progname, lp->l_value); 1554 progname, lp->l_value);
1532 exit(EXIT_FAILURE); 1555 exit(EXIT_FAILURE);
1533 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) { 1556 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
1534 error(_("invalid ending year")); 1557 error(_("invalid ending year"));
1535 return; 1558 return;
1536 } 1559 }
1537 if (rp->r_loyear > rp->r_hiyear) { 1560 if (rp->r_loyear > rp->r_hiyear) {
1538 error(_("starting year greater than ending year")); 1561 error(_("starting year greater than ending year"));
1539 return; 1562 return;
1540 } 1563 }
1541 if (*typep == '\0') 1564 if (*typep == '\0')
1542 rp->r_yrtype = NULL; 1565 rp->r_yrtype = NULL;
1543 else { 1566 else {
1544 if (rp->r_loyear == rp->r_hiyear) { 1567 if (rp->r_loyear == rp->r_hiyear) {
1545 error(_("typed single year")); 1568 error(_("typed single year"));
1546 return; 1569 return;
1547 } 1570 }
1548 rp->r_yrtype = ecpyalloc(typep); 1571 rp->r_yrtype = ecpyalloc(typep);
1549 } 1572 }
1550 /* 1573 /*
1551 ** Day work. 1574 ** Day work.
1552 ** Accept things such as: 1575 ** Accept things such as:
1553 ** 1 1576 ** 1
1554 ** last-Sunday 1577 ** last-Sunday
1555 ** Sun<=20 1578 ** Sun<=20
1556 ** Sun>=7 1579 ** Sun>=7
1557 */ 1580 */
1558 dp = ecpyalloc(dayp); 1581 dp = ecpyalloc(dayp);
1559 if ((lp = byword(dp, lasts)) != NULL) { 1582 if ((lp = byword(dp, lasts)) != NULL) {
1560 rp->r_dycode = DC_DOWLEQ; 1583 rp->r_dycode = DC_DOWLEQ;
1561 rp->r_wday = lp->l_value; 1584 rp->r_wday = lp->l_value;
1562 rp->r_dayofmonth = len_months[1][rp->r_month]; 1585 rp->r_dayofmonth = len_months[1][rp->r_month];
1563 } else { 1586 } else {
1564 if ((ep = strchr(dp, '<')) != 0) 1587 if ((ep = strchr(dp, '<')) != 0)
1565 rp->r_dycode = DC_DOWLEQ; 1588 rp->r_dycode = DC_DOWLEQ;
1566 else if ((ep = strchr(dp, '>')) != 0) 1589 else if ((ep = strchr(dp, '>')) != 0)
1567 rp->r_dycode = DC_DOWGEQ; 1590 rp->r_dycode = DC_DOWGEQ;
1568 else { 1591 else {
1569 ep = dp; 1592 ep = dp;
1570 rp->r_dycode = DC_DOM; 1593 rp->r_dycode = DC_DOM;
1571 } 1594 }
1572 if (rp->r_dycode != DC_DOM) { 1595 if (rp->r_dycode != DC_DOM) {
1573 *ep++ = 0; 1596 *ep++ = 0;
1574 if (*ep++ != '=') { 1597 if (*ep++ != '=') {
1575 error(_("invalid day of month")); 1598 error(_("invalid day of month"));
1576 free(dp); 1599 free(dp);
1577 return; 1600 return;
1578 } 1601 }
1579 if ((lp = byword(dp, wday_names)) == NULL) { 1602 if ((lp = byword(dp, wday_names)) == NULL) {
1580 error(_("invalid weekday name")); 1603 error(_("invalid weekday name"));
1581 free(dp); 1604 free(dp);
1582 return; 1605 return;
1583 } 1606 }
1584 rp->r_wday = lp->l_value; 1607 rp->r_wday = lp->l_value;
1585 } 1608 }
1586 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 || 1609 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1587 rp->r_dayofmonth <= 0 || 1610 rp->r_dayofmonth <= 0 ||
1588 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1611 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1589 error(_("invalid day of month")); 1612 error(_("invalid day of month"));
1590 free(dp); 1613 free(dp);
1591 return; 1614 return;
1592 } 1615 }
1593 } 1616 }
1594 free(dp); 1617 free(dp);
1595} 1618}
1596 1619
1597static void 1620static void
1598convert(const zic_t val, char *const buf) 1621convert(const zic_t val, char *const buf)
1599{ 1622{
1600 int i; 1623 int i;
1601 int shift; 1624 int shift;
1602 unsigned char *const b = (unsigned char *) buf; 1625 unsigned char *const b = (unsigned char *) buf;
1603 1626
1604 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1627 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1605 b[i] = val >> shift; 1628 b[i] = val >> shift;
1606} 1629}
1607 1630
1608static void 1631static void
1609convert64(const zic_t val, char *const buf) 1632convert64(const zic_t val, char *const buf)
1610{ 1633{
1611 int i; 1634 int i;
1612 int shift; 1635 int shift;
1613 unsigned char *const b = (unsigned char *) buf; 1636 unsigned char *const b = (unsigned char *) buf;
1614 1637
1615 for (i = 0, shift = 56; i < 8; ++i, shift -= 8) 1638 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1616 b[i] = val >> shift; 1639 b[i] = val >> shift;
1617} 1640}
1618 1641
1619static void 1642static void
1620puttzcode(const zic_t val, FILE *const fp) 1643puttzcode(const zic_t val, FILE *const fp)
1621{ 1644{
1622 char buf[4]; 1645 char buf[4];
1623 1646
1624 convert(val, buf); 1647 convert(val, buf);
1625 fwrite(buf, sizeof buf, (size_t) 1, fp); 1648 fwrite(buf, sizeof buf, (size_t) 1, fp);
1626} 1649}
1627 1650
1628static void 1651static void
1629puttzcode64(const zic_t val, FILE *const fp) 1652puttzcode64(const zic_t val, FILE *const fp)
1630{ 1653{
1631 char buf[8]; 1654 char buf[8];
1632 1655
1633 convert64(val, buf); 1656 convert64(val, buf);
1634 fwrite(buf, sizeof buf, (size_t) 1, fp); 1657 fwrite(buf, sizeof buf, (size_t) 1, fp);
1635} 1658}
1636 1659
1637static int 1660static int
1638atcomp(const void *avp, const void *bvp) 1661atcomp(const void *avp, const void *bvp)
1639{ 1662{
1640 const zic_t a = ((const struct attype *) avp)->at; 1663 const zic_t a = ((const struct attype *) avp)->at;
1641 const zic_t b = ((const struct attype *) bvp)->at; 1664 const zic_t b = ((const struct attype *) bvp)->at;
1642 1665
1643 return (a < b) ? -1 : (a > b); 1666 return (a < b) ? -1 : (a > b);
1644} 1667}
1645 1668
1646static bool 1669static bool
1647is32(const zic_t x) 1670is32(const zic_t x)
1648{ 1671{
1649 return INT32_MIN <= x && x <= INT32_MAX; 1672 return INT32_MIN <= x && x <= INT32_MAX;
1650} 1673}
1651 1674
1652static void 1675static void
1653writezone(const char *const name, const char *const string, char version) 1676writezone(const char *const name, const char *const string, char version)
1654{ 1677{
1655 FILE * fp; 1678 FILE * fp;
1656 int i, j; 1679 int i, j;
1657 int leapcnt32, leapi32; 1680 int leapcnt32, leapi32;
1658 int timecnt32, timei32; 1681 int timecnt32, timei32;
1659 int pass; 1682 int pass;
1660 static const struct tzhead tzh0; 1683 static const struct tzhead tzh0;
1661 static struct tzhead tzh; 1684 static struct tzhead tzh;
1662 bool dir_checked = false; 1685 bool dir_checked = false;
1663 zic_t one = 1; 1686 zic_t one = 1;
1664 zic_t y2038_boundary = one << 31; 1687 zic_t y2038_boundary = one << 31;
1665 int nats = timecnt + WORK_AROUND_QTBUG_53071; 1688 int nats = timecnt + WORK_AROUND_QTBUG_53071;
1666 zic_t *ats = zic_malloc(size_product(nats, sizeof *ats + 1)); 1689 zic_t *ats = zic_malloc(size_product(nats, sizeof *ats + 1));
1667 void *typesptr = ats + nats; 1690 void *typesptr = ats + nats;
1668 unsigned char *types = typesptr; 1691 unsigned char *types = typesptr;
1669 1692
1670 /* 1693 /*
1671 ** Sort. 1694 ** Sort.
1672 */ 1695 */
1673 if (timecnt > 1) 1696 if (timecnt > 1)
1674 qsort(attypes, (size_t) timecnt, sizeof *attypes, atcomp); 1697 qsort(attypes, (size_t) timecnt, sizeof *attypes, atcomp);
1675 /* 1698 /*
1676 ** Optimize. 1699 ** Optimize.
1677 */ 1700 */
1678 { 1701 {
1679 int fromi; 1702 int fromi;
1680 int toi; 1703 int toi;
1681 1704
1682 toi = 0; 1705 toi = 0;
1683 fromi = 0; 1706 fromi = 0;
1684 while (fromi < timecnt && attypes[fromi].at < early_time) 1707 while (fromi < timecnt && attypes[fromi].at < early_time)
1685 ++fromi; 1708 ++fromi;
1686 for ( ; fromi < timecnt; ++fromi) { 1709 for ( ; fromi < timecnt; ++fromi) {
1687 if (toi > 1 && ((attypes[fromi].at + 1710 if (toi > 1 && ((attypes[fromi].at +
1688 gmtoffs[attypes[toi - 1].type]) <= 1711 gmtoffs[attypes[toi - 1].type]) <=
1689 (attypes[toi - 1].at + 1712 (attypes[toi - 1].at +
1690 gmtoffs[attypes[toi - 2].type]))) { 1713 gmtoffs[attypes[toi - 2].type]))) {
1691 attypes[toi - 1].type = 1714 attypes[toi - 1].type =
1692 attypes[fromi].type; 1715 attypes[fromi].type;
1693 continue; 1716 continue;
1694 } 1717 }
1695 if (toi == 0 1718 if (toi == 0
1696 || attypes[fromi].dontmerge 1719 || attypes[fromi].dontmerge
1697 || attypes[toi - 1].type != attypes[fromi].type) 1720 || attypes[toi - 1].type != attypes[fromi].type)
1698 attypes[toi++] = attypes[fromi]; 1721 attypes[toi++] = attypes[fromi];
1699 } 1722 }
1700 timecnt = toi; 1723 timecnt = toi;
1701 } 1724 }
1702 if (noise && timecnt > 1200) 1725 if (noise && timecnt > 1200)
1703 warning(_("pre-2014 clients may mishandle" 1726 warning(_("pre-2014 clients may mishandle"
1704 " more than 1200 transition times")); 1727 " more than 1200 transition times"));
1705 /* 1728 /*
1706 ** Transfer. 1729 ** Transfer.
1707 */ 1730 */
1708 for (i = 0; i < timecnt; ++i) { 1731 for (i = 0; i < timecnt; ++i) {
1709 ats[i] = attypes[i].at; 1732 ats[i] = attypes[i].at;
1710 types[i] = attypes[i].type; 1733 types[i] = attypes[i].type;
1711 } 1734 }
1712 1735
1713 /* Work around QTBUG-53071 for time stamps less than y2038_boundary - 1, 1736 /* Work around QTBUG-53071 for time stamps less than y2038_boundary - 1,
1714 by inserting a no-op transition at time y2038_boundary - 1. 1737 by inserting a no-op transition at time y2038_boundary - 1.
1715 This works only for timestamps before the boundary, which 1738 This works only for timestamps before the boundary, which
1716 should be good enough in practice as QTBUG-53071 should be 1739 should be good enough in practice as QTBUG-53071 should be
1717 long-dead by 2038. */ 1740 long-dead by 2038. */
1718 if (WORK_AROUND_QTBUG_53071 && timecnt != 0 1741 if (WORK_AROUND_QTBUG_53071 && timecnt != 0
1719 && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) { 1742 && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
1720 ats[timecnt] = y2038_boundary - 1; 1743 ats[timecnt] = y2038_boundary - 1;
1721 types[timecnt] = types[timecnt - 1]; 1744 types[timecnt] = types[timecnt - 1];
1722 timecnt++; 1745 timecnt++;
1723 } 1746 }
1724 1747
1725 /* 1748 /*
1726 ** Correct for leap seconds. 1749 ** Correct for leap seconds.
1727 */ 1750 */
1728 for (i = 0; i < timecnt; ++i) { 1751 for (i = 0; i < timecnt; ++i) {
1729 j = leapcnt; 1752 j = leapcnt;
1730 while (--j >= 0) 1753 while (--j >= 0)
1731 if (ats[i] > trans[j] - corr[j]) { 1754 if (ats[i] > trans[j] - corr[j]) {
1732 ats[i] = tadd(ats[i], corr[j]); 1755 ats[i] = tadd(ats[i], corr[j]);
1733 break; 1756 break;
1734 } 1757 }
1735 } 1758 }
1736 /* 1759 /*
1737 ** Figure out 32-bit-limited starts and counts. 1760 ** Figure out 32-bit-limited starts and counts.
1738 */ 1761 */
1739 timecnt32 = timecnt; 1762 timecnt32 = timecnt;
1740 timei32 = 0; 1763 timei32 = 0;
1741 leapcnt32 = leapcnt; 1764 leapcnt32 = leapcnt;
1742 leapi32 = 0; 1765 leapi32 = 0;
1743 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1])) 1766 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1744 --timecnt32; 1767 --timecnt32;
1745 while (timecnt32 > 0 && !is32(ats[timei32])) { 1768 while (timecnt32 > 0 && !is32(ats[timei32])) {
1746 --timecnt32; 1769 --timecnt32;
1747 ++timei32; 1770 ++timei32;
1748 } 1771 }
1749 /* 1772 /*
1750 ** Output an INT32_MIN "transition" if appropriate; see below. 1773 ** Output an INT32_MIN "transition" if appropriate; see below.
1751 */ 1774 */
1752 if (timei32 > 0 && ats[timei32] > INT32_MIN) { 1775 if (timei32 > 0 && ats[timei32] > INT32_MIN) {
1753 --timei32; 1776 --timei32;
1754 ++timecnt32; 1777 ++timecnt32;
1755 } 1778 }
1756 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1])) 1779 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1757 --leapcnt32; 1780 --leapcnt32;
1758 while (leapcnt32 > 0 && !is32(trans[leapi32])) { 1781 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1759 --leapcnt32; 1782 --leapcnt32;
1760 ++leapi32; 1783 ++leapi32;
1761 } 1784 }
1762 /* 1785 /*
1763 ** Remove old file, if any, to snap links. 1786 ** Remove old file, if any, to snap links.
1764 */ 1787 */
1765 if (remove(name) == 0) 1788 if (remove(name) == 0)
1766 dir_checked = true; 1789 dir_checked = true;
1767 else if (errno != ENOENT) { 1790 else if (errno != ENOENT) {
1768 const char *e = strerror(errno); 1791 const char *e = strerror(errno);
1769 1792
1770 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), 1793 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1771 progname, directory, name, e); 1794 progname, directory, name, e);
1772 exit(EXIT_FAILURE); 1795 exit(EXIT_FAILURE);
1773 } 1796 }
1774 fp = fopen(name, "wb"); 1797 fp = fopen(name, "wb");
1775 if (!fp) { 1798 if (!fp) {
1776 int fopen_errno = errno; 1799 int fopen_errno = errno;
1777 if (fopen_errno == ENOENT && !dir_checked) { 1800 if (fopen_errno == ENOENT && !dir_checked) {
1778 mkdirs(name, true); 1801 mkdirs(name, true);
1779 fp = fopen(name, "wb"); 1802 fp = fopen(name, "wb");
1780 fopen_errno = errno; 1803 fopen_errno = errno;
1781 } 1804 }
1782 if (!fp) { 1805 if (!fp) {
1783 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), 1806 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1784 progname, directory, name, strerror(fopen_errno)); 1807 progname, directory, name, strerror(fopen_errno));
1785 exit(EXIT_FAILURE); 1808 exit(EXIT_FAILURE);
1786 } 1809 }
1787 } 1810 }
1788 for (pass = 1; pass <= 2; ++pass) { 1811 for (pass = 1; pass <= 2; ++pass) {
1789 int thistimei, thistimecnt; 1812 int thistimei, thistimecnt;
1790 int thisleapi, thisleapcnt; 1813 int thisleapi, thisleapcnt;
1791 int thistimelim, thisleaplim; 1814 int thistimelim, thisleaplim;
1792 int writetype[TZ_MAX_TYPES]; 1815 int writetype[TZ_MAX_TYPES];
1793 int typemap[TZ_MAX_TYPES]; 1816 int typemap[TZ_MAX_TYPES];
1794 int thistypecnt; 1817 int thistypecnt;
1795 char thischars[TZ_MAX_CHARS]; 1818 char thischars[TZ_MAX_CHARS];
1796 char thischarcnt; 1819 char thischarcnt;
1797 int indmap[TZ_MAX_CHARS]; 1820 int indmap[TZ_MAX_CHARS];
1798 1821
1799 if (pass == 1) { 1822 if (pass == 1) {
1800 thistimei = timei32; 1823 thistimei = timei32;
1801 thistimecnt = timecnt32; 1824 thistimecnt = timecnt32;
1802 thisleapi = leapi32; 1825 thisleapi = leapi32;
1803 thisleapcnt = leapcnt32; 1826 thisleapcnt = leapcnt32;
1804 } else { 1827 } else {
1805 thistimei = 0; 1828 thistimei = 0;
1806 thistimecnt = timecnt; 1829 thistimecnt = timecnt;
1807 thisleapi = 0; 1830 thisleapi = 0;
1808 thisleapcnt = leapcnt; 1831 thisleapcnt = leapcnt;
1809 } 1832 }
1810 thistimelim = thistimei + thistimecnt; 1833 thistimelim = thistimei + thistimecnt;
1811 thisleaplim = thisleapi + thisleapcnt; 1834 thisleaplim = thisleapi + thisleapcnt;
1812 for (i = 0; i < typecnt; ++i) 1835 for (i = 0; i < typecnt; ++i)
1813 writetype[i] = thistimecnt == timecnt; 1836 writetype[i] = thistimecnt == timecnt;
1814 if (thistimecnt == 0) { 1837 if (thistimecnt == 0) {
1815 /* 1838 /*
1816 ** No transition times fall in the current 1839 ** No transition times fall in the current
1817 ** (32- or 64-bit) window. 1840 ** (32- or 64-bit) window.
1818 */ 1841 */
1819 if (typecnt != 0) 1842 if (typecnt != 0)
1820 writetype[typecnt - 1] = true; 1843 writetype[typecnt - 1] = true;
1821 } else { 1844 } else {
1822 for (i = thistimei - 1; i < thistimelim; ++i) 1845 for (i = thistimei - 1; i < thistimelim; ++i)
1823 if (i >= 0) 1846 if (i >= 0)
1824 writetype[types[i]] = true; 1847 writetype[types[i]] = true;
1825 /* 1848 /*
1826 ** For America/Godthab and Antarctica/Palmer 1849 ** For America/Godthab and Antarctica/Palmer
1827 */ 1850 */
1828 if (thistimei == 0) 1851 if (thistimei == 0)
1829 writetype[0] = true; 1852 writetype[0] = true;
1830 } 1853 }
1831#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH 1854#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1832 /* 1855 /*
1833 ** For some pre-2011 systems: if the last-to-be-written 1856 ** For some pre-2011 systems: if the last-to-be-written
1834 ** standard (or daylight) type has an offset different from the 1857 ** standard (or daylight) type has an offset different from the
1835 ** most recently used offset, 1858 ** most recently used offset,
1836 ** append an (unused) copy of the most recently used type 1859 ** append an (unused) copy of the most recently used type
1837 ** (to help get global "altzone" and "timezone" variables 1860 ** (to help get global "altzone" and "timezone" variables