| @@ -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 | |
27 | typedef int_fast64_t zic_t; | | 27 | typedef 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 | |
52 | struct rule { | | 52 | struct 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 | |
89 | struct zone { | | 89 | struct 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 |
109 | extern int getopt(int argc, char * const argv[], | | 109 | extern int getopt(int argc, char * const argv[], |
110 | const char * options); | | 110 | const char * options); |
111 | extern int link(const char * fromname, const char * toname); | | 111 | extern int link(const char * fromname, const char * toname); |
112 | extern char * optarg; | | 112 | extern char * optarg; |
113 | extern int optind; | | 113 | extern 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 | |
125 | static void addtt(zic_t starttime, int type); | | 125 | static void addtt(zic_t starttime, int type); |
126 | static int addtype(zic_t, char const *, bool, bool, bool); | | 126 | static int addtype(zic_t, char const *, bool, bool, bool); |
127 | static void leapadd(zic_t, bool, int, int); | | 127 | static void leapadd(zic_t, bool, int, int); |
128 | static void adjleap(void); | | 128 | static void adjleap(void); |
129 | static void associate(void); | | 129 | static void associate(void); |
130 | static void dolink(const char *, const char *, bool); | | 130 | static void dolink(const char *, const char *, bool); |
131 | static char ** getfields(char * buf); | | 131 | static char ** getfields(char * buf); |
132 | static zic_t gethms(const char * string, const char * errstring, | | 132 | static zic_t gethms(const char * string, const char * errstring, |
133 | bool); | | 133 | bool); |
134 | static void infile(const char * filename); | | 134 | static void infile(const char * filename); |
135 | static void inleap(char ** fields, int nfields); | | 135 | static void inleap(char ** fields, int nfields); |
136 | static void inlink(char ** fields, int nfields); | | 136 | static void inlink(char ** fields, int nfields); |
137 | static void inrule(char ** fields, int nfields); | | 137 | static void inrule(char ** fields, int nfields); |
138 | static bool inzcont(char ** fields, int nfields); | | 138 | static bool inzcont(char ** fields, int nfields); |
139 | static bool inzone(char ** fields, int nfields); | | 139 | static bool inzone(char ** fields, int nfields); |
140 | static bool inzsub(char **, int, int); | | 140 | static bool inzsub(char **, int, int); |
141 | static int itsdir(const char * name); | | 141 | static int itsdir(const char * name); |
142 | static bool is_alpha(char a); | | 142 | static bool is_alpha(char a); |
143 | static char lowerit(char); | | 143 | static char lowerit(char); |
144 | static void mkdirs(char const *, bool); | | 144 | static void mkdirs(char const *, bool); |
145 | static void newabbr(const char * abbr); | | 145 | static void newabbr(const char * abbr); |
146 | static zic_t oadd(zic_t t1, zic_t t2); | | 146 | static zic_t oadd(zic_t t1, zic_t t2); |
147 | static void outzone(const struct zone * zp, int ntzones); | | 147 | static void outzone(const struct zone * zp, int ntzones); |
148 | static zic_t rpytime(const struct rule * rp, zic_t wantedy); | | 148 | static zic_t rpytime(const struct rule * rp, zic_t wantedy); |
149 | static void rulesub(struct rule * rp, | | 149 | static 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); |
153 | static zic_t tadd(zic_t t1, zic_t t2); | | 153 | static zic_t tadd(zic_t t1, zic_t t2); |
154 | static bool yearistype(int year, const char * type); | | 154 | static 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. */ |
157 | enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }; | | 157 | enum { 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. */ |
164 | enum { WORK_AROUND_QTBUG_53071 = 1 }; | | 164 | enum { WORK_AROUND_QTBUG_53071 = 1 }; |
165 | | | 165 | |
166 | static int charcnt; | | 166 | static int charcnt; |
167 | static bool errors; | | 167 | static bool errors; |
168 | static bool warnings; | | 168 | static bool warnings; |
169 | static const char * filename; | | 169 | static const char * filename; |
170 | static int leapcnt; | | 170 | static int leapcnt; |
171 | static bool leapseen; | | 171 | static bool leapseen; |
172 | static zic_t leapminyear; | | 172 | static zic_t leapminyear; |
173 | static zic_t leapmaxyear; | | 173 | static zic_t leapmaxyear; |
174 | static int linenum; | | 174 | static int linenum; |
175 | static size_t max_abbrvar_len = PERCENT_Z_LEN_BOUND; | | 175 | static size_t max_abbrvar_len = PERCENT_Z_LEN_BOUND; |
176 | static size_t max_format_len; | | 176 | static size_t max_format_len; |
177 | static zic_t max_year; | | 177 | static zic_t max_year; |
178 | static zic_t min_year; | | 178 | static zic_t min_year; |
179 | static bool noise; | | 179 | static bool noise; |
180 | static const char * rfilename; | | 180 | static const char * rfilename; |
181 | static int rlinenum; | | 181 | static int rlinenum; |
182 | static const char * progname; | | 182 | static const char * progname; |
183 | static int timecnt; | | 183 | static int timecnt; |
184 | static int timecnt_alloc; | | 184 | static int timecnt_alloc; |
185 | static int typecnt; | | 185 | static 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 | |
268 | static struct rule * rules; | | 268 | static struct rule * rules; |
269 | static int nrules; /* number of rules */ | | 269 | static int nrules; /* number of rules */ |
270 | static int nrules_alloc; | | 270 | static int nrules_alloc; |
271 | | | 271 | |
272 | static struct zone * zones; | | 272 | static struct zone * zones; |
273 | static int nzones; /* number of zones */ | | 273 | static int nzones; /* number of zones */ |
274 | static int nzones_alloc; | | 274 | static int nzones_alloc; |
275 | | | 275 | |
276 | struct link { | | 276 | struct 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 | |
283 | static struct link * links; | | 283 | static struct link * links; |
284 | static int nlinks; | | 284 | static int nlinks; |
285 | static int nlinks_alloc; | | 285 | static int nlinks_alloc; |
286 | | | 286 | |
287 | struct lookup { | | 287 | struct 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 | |
292 | static struct lookup const * byword(const char * string, | | 292 | static struct lookup const * byword(const char * string, |
293 | const struct lookup * lp); | | 293 | const struct lookup * lp); |
294 | | | 294 | |
295 | static struct lookup const line_codes[] = { | | 295 | static 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 | |
303 | static struct lookup const mon_names[] = { | | 303 | static 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 | |
319 | static struct lookup const wday_names[] = { | | 319 | static 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 | |
330 | static struct lookup const lasts[] = { | | 330 | static 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 | |
341 | static struct lookup const begin_years[] = { | | 341 | static 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 | |
347 | static struct lookup const end_years[] = { | | 347 | static 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 | |
354 | static struct lookup const leap_types[] = { | | 354 | static 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 | |
360 | static const int len_months[2][MONSPERYEAR] = { | | 360 | static 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 | |
365 | static const int len_years[2] = { | | 365 | static const int len_years[2] = { |
366 | DAYSPERNYEAR, DAYSPERLYEAR | | 366 | DAYSPERNYEAR, DAYSPERLYEAR |
367 | }; | | 367 | }; |
368 | | | 368 | |
369 | static struct attype { | | 369 | static 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; |
374 | static zic_t gmtoffs[TZ_MAX_TYPES]; | | 374 | static zic_t gmtoffs[TZ_MAX_TYPES]; |
375 | static char isdsts[TZ_MAX_TYPES]; | | 375 | static char isdsts[TZ_MAX_TYPES]; |
376 | static unsigned char abbrinds[TZ_MAX_TYPES]; | | 376 | static unsigned char abbrinds[TZ_MAX_TYPES]; |
377 | static bool ttisstds[TZ_MAX_TYPES]; | | 377 | static bool ttisstds[TZ_MAX_TYPES]; |
378 | static bool ttisgmts[TZ_MAX_TYPES]; | | 378 | static bool ttisgmts[TZ_MAX_TYPES]; |
379 | static char chars[TZ_MAX_CHARS]; | | 379 | static char chars[TZ_MAX_CHARS]; |
380 | static zic_t trans[TZ_MAX_LEAPS]; | | 380 | static zic_t trans[TZ_MAX_LEAPS]; |
381 | static zic_t corr[TZ_MAX_LEAPS]; | | 381 | static zic_t corr[TZ_MAX_LEAPS]; |
382 | static char roll[TZ_MAX_LEAPS]; | | 382 | static char roll[TZ_MAX_LEAPS]; |
383 | | | 383 | |
384 | /* | | 384 | /* |
385 | ** Memory allocation. | | 385 | ** Memory allocation. |
386 | */ | | 386 | */ |
387 | | | 387 | |
388 | static _Noreturn void | | 388 | static _Noreturn void |
389 | memory_exhausted(const char *msg) | | 389 | memory_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 | |
395 | static ATTRIBUTE_PURE size_t | | 395 | static ATTRIBUTE_PURE size_t |
396 | size_product(size_t nitems, size_t itemsize) | | 396 | size_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 |
404 | static char * | | 404 | static char * |
405 | strdup(char const *str) | | 405 | strdup(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 | |
412 | static ATTRIBUTE_PURE void * | | 412 | static ATTRIBUTE_PURE void * |
413 | memcheck(void *ptr) | | 413 | memcheck(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 | |
420 | static void * | | 420 | static void * |
421 | zic_malloc(size_t size) | | 421 | zic_malloc(size_t size) |
422 | { | | 422 | { |
423 | return memcheck(malloc(size)); | | 423 | return memcheck(malloc(size)); |
424 | } | | 424 | } |
425 | | | 425 | |
426 | static void * | | 426 | static void * |
427 | zic_realloc(void *ptr, size_t size) | | 427 | zic_realloc(void *ptr, size_t size) |
428 | { | | 428 | { |
429 | return memcheck(realloc(ptr, size)); | | 429 | return memcheck(realloc(ptr, size)); |
430 | } | | 430 | } |
431 | | | 431 | |
432 | static char * | | 432 | static char * |
433 | ecpyalloc(char const *str) | | 433 | ecpyalloc(char const *str) |
434 | { | | 434 | { |
435 | return memcheck(strdup(str)); | | 435 | return memcheck(strdup(str)); |
436 | } | | 436 | } |
437 | | | 437 | |
438 | static void * | | 438 | static void * |
439 | growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc) | | 439 | growalloc(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 | |
458 | static void | | 458 | static void |
459 | eats(const char *const name, const int num, const char *const rname, | | 459 | eats(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 | |
468 | static void | | 468 | static void |
469 | eat(const char *const name, const int num) | | 469 | eat(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 | |
474 | static void ATTRIBUTE_FORMAT((printf, 1, 0)) | | 474 | static void ATTRIBUTE_FORMAT((printf, 1, 0)) |
475 | verror(const char *const string, va_list args) | | 475 | verror(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 | |
491 | static void ATTRIBUTE_FORMAT((printf, 1, 2)) | | 491 | static void ATTRIBUTE_FORMAT((printf, 1, 2)) |
492 | error(const char *const string, ...) | | 492 | error(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 | |
501 | static void ATTRIBUTE_FORMAT((printf, 1, 2)) | | 501 | static void ATTRIBUTE_FORMAT((printf, 1, 2)) |
502 | warning(const char *const string, ...) | | 502 | warning(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 | |
512 | static void | | 512 | static void |
513 | close_file(FILE *stream, char const *dir, char const *name) | | 513 | close_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 | |
526 | static _Noreturn void | | 526 | static _Noreturn void |
527 | usage(FILE *stream, int status) | | 527 | usage(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. */ |
543 | static void | | 543 | static void |
544 | change_directory (char const *dir) | | 544 | change_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 | |
560 | static const char * psxrules; | | 560 | static const char * psxrules; |
561 | static const char * lcltime; | | 561 | static const char * lcltime; |
562 | static const char * directory; | | 562 | static const char * directory; |
563 | static const char * leapsec; | | 563 | static const char * leapsec; |
564 | static const char * yitcommand; | | 564 | static const char * yitcommand; |
565 | | | 565 | |
566 | int | | 566 | int |
567 | main(int argc, char **argv) | | 567 | main(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 | |
709 | static bool | | 709 | static bool |
710 | componentcheck(char const *name, char const *component, | | 710 | componentcheck(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 | |
745 | static bool | | 745 | static bool |
746 | namecheck(const char *name) | | 746 | namecheck(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. */ |
| | | 783 | static char * |
| | | 784 | relname(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 | |
779 | static void | | 817 | static void |
780 | dolink(char const *fromfield, char const *tofield, bool staysymlink) | | 818 | dolink(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 | |
876 | static zic_t const min_time = MINVAL (zic_t, TIME_T_BITS_IN_FILE); | | 899 | static zic_t const min_time = MINVAL (zic_t, TIME_T_BITS_IN_FILE); |
877 | static zic_t const max_time = MAXVAL (zic_t, TIME_T_BITS_IN_FILE); | | 900 | static 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. */ |
911 | enum { WORK_AROUND_GNOME_BUG_730332 = true }; | | 934 | enum { WORK_AROUND_GNOME_BUG_730332 = true }; |
912 | | | 935 | |
913 | static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332 | | 936 | static 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. */ |
919 | static int | | 942 | static int |
920 | itsdir(char const *name) | | 943 | itsdir(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 | |
949 | static int | | 972 | static int |
950 | rcomp(const void *cp1, const void *cp2) | | 973 | rcomp(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 | |
956 | static void | | 979 | static void |
957 | associate(void) | | 980 | associate(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 | |
1031 | static void | | 1054 | static void |
1032 | infile(const char *name) | | 1055 | infile(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 | |
1123 | static zic_t | | 1146 | static zic_t |
1124 | gethms(char const *string, char const *errstring, bool signable) | | 1147 | gethms(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)))) |
1159 | warning(_("values over 24 hours not handled by pre-2007 versions of zic")); | | 1182 | warning(_("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 | |
1164 | static void | | 1187 | static void |
1165 | inrule(char **fields, int nfields) | | 1188 | inrule(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 | |
1190 | static bool | | 1213 | static bool |
1191 | inzone(char **fields, int nfields) | | 1214 | inzone(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 | |
1224 | static bool | | 1247 | static bool |
1225 | inzcont(char **fields, int nfields) | | 1248 | inzcont(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 | |
1234 | static bool | | 1257 | static bool |
1235 | inzsub(char **fields, int nfields, const int iscont) | | 1258 | inzsub(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 | |
1322 | static void | | 1345 | static void |
1323 | inleap(char **fields, int nfields) | | 1346 | inleap(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 | |
1427 | static void | | 1450 | static void |
1428 | inlink(char **fields, int nfields) | | 1451 | inlink(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 | |
1450 | static void | | 1473 | static void |
1451 | rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, | | 1474 | rulesub(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 | |
1597 | static void | | 1620 | static void |
1598 | convert(const zic_t val, char *const buf) | | 1621 | convert(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 | |
1608 | static void | | 1631 | static void |
1609 | convert64(const zic_t val, char *const buf) | | 1632 | convert64(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 | |
1619 | static void | | 1642 | static void |
1620 | puttzcode(const zic_t val, FILE *const fp) | | 1643 | puttzcode(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 | |
1628 | static void | | 1651 | static void |
1629 | puttzcode64(const zic_t val, FILE *const fp) | | 1652 | puttzcode64(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 | |
1637 | static int | | 1660 | static int |
1638 | atcomp(const void *avp, const void *bvp) | | 1661 | atcomp(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 | |
1646 | static bool | | 1669 | static bool |
1647 | is32(const zic_t x) | | 1670 | is32(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 | |
1652 | static void | | 1675 | static void |
1653 | writezone(const char *const name, const char *const string, char version) | | 1676 | writezone(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 |