GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: zic.c,v 1.22 2016/03/15 19:50:47 millert Exp $ */ |
||
2 |
/* |
||
3 |
** This file is in the public domain, so clarified as of |
||
4 |
** 2006-07-17 by Arthur David Olson. |
||
5 |
*/ |
||
6 |
|||
7 |
#include <sys/types.h> |
||
8 |
#include <sys/wait.h> |
||
9 |
#include <sys/stat.h> |
||
10 |
#include <ctype.h> |
||
11 |
#include <err.h> |
||
12 |
#include <errno.h> |
||
13 |
#include <limits.h> |
||
14 |
#include <locale.h> |
||
15 |
#include <stdio.h> |
||
16 |
#include <stdlib.h> |
||
17 |
#include <string.h> |
||
18 |
#include <stdint.h> |
||
19 |
#include <unistd.h> |
||
20 |
#include <time.h> |
||
21 |
|||
22 |
#include "tzfile.h" |
||
23 |
|||
24 |
#define TRUE 1 |
||
25 |
#define FALSE 0 |
||
26 |
|||
27 |
#define TYPE_SIGNED(type) (((type) -1) < 0) |
||
28 |
|||
29 |
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ |
||
30 |
|||
31 |
#define GRANDPARENTED "Local time zone must be set--see zic manual page" |
||
32 |
|||
33 |
#define ZIC_VERSION '2' |
||
34 |
|||
35 |
typedef int_fast64_t zic_t; |
||
36 |
|||
37 |
#ifndef ZIC_MAX_ABBR_LEN_WO_WARN |
||
38 |
#define ZIC_MAX_ABBR_LEN_WO_WARN 6 |
||
39 |
#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ |
||
40 |
|||
41 |
#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) |
||
42 |
|||
43 |
#define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long)) |
||
44 |
#define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */ |
||
45 |
|||
46 |
#define end(cp, n) (memchr((cp), '\0', (n))) |
||
47 |
|||
48 |
struct rule { |
||
49 |
const char *r_filename; |
||
50 |
int r_linenum; |
||
51 |
const char *r_name; |
||
52 |
|||
53 |
int r_loyear; /* for example, 1986 */ |
||
54 |
int r_hiyear; /* for example, 1986 */ |
||
55 |
const char *r_yrtype; |
||
56 |
int r_lowasnum; |
||
57 |
int r_hiwasnum; |
||
58 |
|||
59 |
int r_month; /* 0..11 */ |
||
60 |
|||
61 |
int r_dycode; /* see below */ |
||
62 |
int r_dayofmonth; |
||
63 |
int r_wday; |
||
64 |
|||
65 |
long r_tod; /* time from midnight */ |
||
66 |
int r_todisstd; /* above is standard time if TRUE */ |
||
67 |
/* or wall clock time if FALSE */ |
||
68 |
int r_todisgmt; /* above is GMT if TRUE */ |
||
69 |
/* or local time if FALSE */ |
||
70 |
long r_stdoff; /* offset from standard time */ |
||
71 |
const char *r_abbrvar; /* variable part of abbreviation */ |
||
72 |
|||
73 |
int r_todo; /* a rule to do (used in outzone) */ |
||
74 |
zic_t r_temp; /* used in outzone */ |
||
75 |
}; |
||
76 |
|||
77 |
/* |
||
78 |
** r_dycode r_dayofmonth r_wday |
||
79 |
*/ |
||
80 |
|||
81 |
#define DC_DOM 0 /* 1..31 */ /* unused */ |
||
82 |
#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ |
||
83 |
#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ |
||
84 |
|||
85 |
struct zone { |
||
86 |
const char *z_filename; |
||
87 |
int z_linenum; |
||
88 |
|||
89 |
const char *z_name; |
||
90 |
long z_gmtoff; |
||
91 |
const char *z_rule; |
||
92 |
const char *z_format; |
||
93 |
|||
94 |
long z_stdoff; |
||
95 |
|||
96 |
struct rule *z_rules; |
||
97 |
int z_nrules; |
||
98 |
|||
99 |
struct rule z_untilrule; |
||
100 |
zic_t z_untiltime; |
||
101 |
}; |
||
102 |
|||
103 |
static void addtt(zic_t starttime, int type); |
||
104 |
static int addtype(long gmtoff, const char *abbr, int isdst, |
||
105 |
int ttisstd, int ttisgmt); |
||
106 |
static void leapadd(zic_t t, int positive, int rolling, int count); |
||
107 |
static void adjleap(void); |
||
108 |
static void associate(void); |
||
109 |
static void convert(long val, char *buf); |
||
110 |
static void convert64(zic_t val, char *buf); |
||
111 |
static void dolink(const char *fromfield, const char *tofield); |
||
112 |
static void doabbr(char *abbr, size_t size, const char *format, |
||
113 |
const char *letters, int isdst, int doquotes); |
||
114 |
static void eat(const char *name, int num); |
||
115 |
static void eats(const char *name, int num, const char *rname, int rnum); |
||
116 |
static long eitol(int i); |
||
117 |
static void error(const char *message); |
||
118 |
static char **getfields(char *buf); |
||
119 |
static long gethms(const char *string, const char *errstrng, int signable); |
||
120 |
static void infile(const char *filename); |
||
121 |
static void inleap(char **fields, int nfields); |
||
122 |
static void inlink(char **fields, int nfields); |
||
123 |
static void inrule(char **fields, int nfields); |
||
124 |
static int inzcont(char **fields, int nfields); |
||
125 |
static int inzone(char **fields, int nfields); |
||
126 |
static int inzsub(char **fields, int nfields, int iscont); |
||
127 |
static int is32(zic_t x); |
||
128 |
static int itsabbr(const char *abbr, const char *word); |
||
129 |
static int itsdir(const char *name); |
||
130 |
static int mkdirs(char *filename); |
||
131 |
static void newabbr(const char *abbr); |
||
132 |
static long oadd(long t1, long t2); |
||
133 |
static void outzone(const struct zone *zp, int ntzones); |
||
134 |
static void puttzcode(long code, FILE *fp); |
||
135 |
static void puttzcode64(zic_t code, FILE *fp); |
||
136 |
static int rcomp(const void *leftp, const void *rightp); |
||
137 |
static zic_t rpytime(const struct rule *rp, int wantedy); |
||
138 |
static void rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, |
||
139 |
const char *typep, const char *monthp, |
||
140 |
const char *dayp, const char *timep); |
||
141 |
static int stringoffset(char *result, size_t size, long offset); |
||
142 |
static int stringrule(char *result, size_t size, const struct rule *rp, |
||
143 |
long dstoff, long gmtoff); |
||
144 |
static void stringzone(char *result, size_t size, |
||
145 |
const struct zone *zp, int ntzones); |
||
146 |
static void setboundaries(void); |
||
147 |
static zic_t tadd(zic_t t1, long t2); |
||
148 |
static void usage(void); |
||
149 |
static void writezone(const char *name, const char *string); |
||
150 |
static int yearistype(int year, const char *type); |
||
151 |
|||
152 |
extern char *__progname; |
||
153 |
|||
154 |
static int charcnt; |
||
155 |
static int errors; |
||
156 |
static const char *filename; |
||
157 |
static int leapcnt; |
||
158 |
static int leapseen; |
||
159 |
static int leapminyear; |
||
160 |
static int leapmaxyear; |
||
161 |
static int linenum; |
||
162 |
static int max_abbrvar_len; |
||
163 |
static int max_format_len; |
||
164 |
static zic_t max_time; |
||
165 |
static int max_year; |
||
166 |
static zic_t min_time; |
||
167 |
static int min_year; |
||
168 |
static int noise; |
||
169 |
static const char *rfilename; |
||
170 |
static int rlinenum; |
||
171 |
static int timecnt; |
||
172 |
static int typecnt; |
||
173 |
|||
174 |
/* |
||
175 |
** Line codes. |
||
176 |
*/ |
||
177 |
|||
178 |
#define LC_RULE 0 |
||
179 |
#define LC_ZONE 1 |
||
180 |
#define LC_LINK 2 |
||
181 |
#define LC_LEAP 3 |
||
182 |
|||
183 |
/* |
||
184 |
** Which fields are which on a Zone line. |
||
185 |
*/ |
||
186 |
|||
187 |
#define ZF_NAME 1 |
||
188 |
#define ZF_GMTOFF 2 |
||
189 |
#define ZF_RULE 3 |
||
190 |
#define ZF_FORMAT 4 |
||
191 |
#define ZF_TILYEAR 5 |
||
192 |
#define ZF_TILMONTH 6 |
||
193 |
#define ZF_TILDAY 7 |
||
194 |
#define ZF_TILTIME 8 |
||
195 |
#define ZONE_MINFIELDS 5 |
||
196 |
#define ZONE_MAXFIELDS 9 |
||
197 |
|||
198 |
/* |
||
199 |
** Which fields are which on a Zone continuation line. |
||
200 |
*/ |
||
201 |
|||
202 |
#define ZFC_GMTOFF 0 |
||
203 |
#define ZFC_RULE 1 |
||
204 |
#define ZFC_FORMAT 2 |
||
205 |
#define ZFC_TILYEAR 3 |
||
206 |
#define ZFC_TILMONTH 4 |
||
207 |
#define ZFC_TILDAY 5 |
||
208 |
#define ZFC_TILTIME 6 |
||
209 |
#define ZONEC_MINFIELDS 3 |
||
210 |
#define ZONEC_MAXFIELDS 7 |
||
211 |
|||
212 |
/* |
||
213 |
** Which files are which on a Rule line. |
||
214 |
*/ |
||
215 |
|||
216 |
#define RF_NAME 1 |
||
217 |
#define RF_LOYEAR 2 |
||
218 |
#define RF_HIYEAR 3 |
||
219 |
#define RF_COMMAND 4 |
||
220 |
#define RF_MONTH 5 |
||
221 |
#define RF_DAY 6 |
||
222 |
#define RF_TOD 7 |
||
223 |
#define RF_STDOFF 8 |
||
224 |
#define RF_ABBRVAR 9 |
||
225 |
#define RULE_FIELDS 10 |
||
226 |
|||
227 |
/* |
||
228 |
** Which fields are which on a Link line. |
||
229 |
*/ |
||
230 |
|||
231 |
#define LF_FROM 1 |
||
232 |
#define LF_TO 2 |
||
233 |
#define LINK_FIELDS 3 |
||
234 |
|||
235 |
/* |
||
236 |
** Which fields are which on a Leap line. |
||
237 |
*/ |
||
238 |
|||
239 |
#define LP_YEAR 1 |
||
240 |
#define LP_MONTH 2 |
||
241 |
#define LP_DAY 3 |
||
242 |
#define LP_TIME 4 |
||
243 |
#define LP_CORR 5 |
||
244 |
#define LP_ROLL 6 |
||
245 |
#define LEAP_FIELDS 7 |
||
246 |
|||
247 |
/* |
||
248 |
** Year synonyms. |
||
249 |
*/ |
||
250 |
|||
251 |
#define YR_MINIMUM 0 |
||
252 |
#define YR_MAXIMUM 1 |
||
253 |
#define YR_ONLY 2 |
||
254 |
|||
255 |
static struct rule *rules; |
||
256 |
static int nrules; /* number of rules */ |
||
257 |
|||
258 |
static struct zone *zones; |
||
259 |
static int nzones; /* number of zones */ |
||
260 |
|||
261 |
struct link { |
||
262 |
const char *l_filename; |
||
263 |
int l_linenum; |
||
264 |
const char *l_from; |
||
265 |
const char *l_to; |
||
266 |
}; |
||
267 |
|||
268 |
static struct link *links; |
||
269 |
static int nlinks; |
||
270 |
|||
271 |
struct lookup { |
||
272 |
const char *l_word; |
||
273 |
const int l_value; |
||
274 |
}; |
||
275 |
|||
276 |
static struct lookup const *byword(const char *string, const struct lookup *lp); |
||
277 |
|||
278 |
static struct lookup const line_codes[] = { |
||
279 |
{ "Rule", LC_RULE }, |
||
280 |
{ "Zone", LC_ZONE }, |
||
281 |
{ "Link", LC_LINK }, |
||
282 |
{ "Leap", LC_LEAP }, |
||
283 |
{ NULL, 0} |
||
284 |
}; |
||
285 |
|||
286 |
static struct lookup const mon_names[] = { |
||
287 |
{ "January", TM_JANUARY }, |
||
288 |
{ "February", TM_FEBRUARY }, |
||
289 |
{ "March", TM_MARCH }, |
||
290 |
{ "April", TM_APRIL }, |
||
291 |
{ "May", TM_MAY }, |
||
292 |
{ "June", TM_JUNE }, |
||
293 |
{ "July", TM_JULY }, |
||
294 |
{ "August", TM_AUGUST }, |
||
295 |
{ "September", TM_SEPTEMBER }, |
||
296 |
{ "October", TM_OCTOBER }, |
||
297 |
{ "November", TM_NOVEMBER }, |
||
298 |
{ "December", TM_DECEMBER }, |
||
299 |
{ NULL, 0 } |
||
300 |
}; |
||
301 |
|||
302 |
static struct lookup const wday_names[] = { |
||
303 |
{ "Sunday", TM_SUNDAY }, |
||
304 |
{ "Monday", TM_MONDAY }, |
||
305 |
{ "Tuesday", TM_TUESDAY }, |
||
306 |
{ "Wednesday", TM_WEDNESDAY }, |
||
307 |
{ "Thursday", TM_THURSDAY }, |
||
308 |
{ "Friday", TM_FRIDAY }, |
||
309 |
{ "Saturday", TM_SATURDAY }, |
||
310 |
{ NULL, 0 } |
||
311 |
}; |
||
312 |
|||
313 |
static struct lookup const lasts[] = { |
||
314 |
{ "last-Sunday", TM_SUNDAY }, |
||
315 |
{ "last-Monday", TM_MONDAY }, |
||
316 |
{ "last-Tuesday", TM_TUESDAY }, |
||
317 |
{ "last-Wednesday", TM_WEDNESDAY }, |
||
318 |
{ "last-Thursday", TM_THURSDAY }, |
||
319 |
{ "last-Friday", TM_FRIDAY }, |
||
320 |
{ "last-Saturday", TM_SATURDAY }, |
||
321 |
{ NULL, 0 } |
||
322 |
}; |
||
323 |
|||
324 |
static struct lookup const begin_years[] = { |
||
325 |
{ "minimum", YR_MINIMUM }, |
||
326 |
{ "maximum", YR_MAXIMUM }, |
||
327 |
{ NULL, 0 } |
||
328 |
}; |
||
329 |
|||
330 |
static struct lookup const end_years[] = { |
||
331 |
{ "minimum", YR_MINIMUM }, |
||
332 |
{ "maximum", YR_MAXIMUM }, |
||
333 |
{ "only", YR_ONLY }, |
||
334 |
{ NULL, 0 } |
||
335 |
}; |
||
336 |
|||
337 |
static struct lookup const leap_types[] = { |
||
338 |
{ "Rolling", TRUE }, |
||
339 |
{ "Stationary", FALSE }, |
||
340 |
{ NULL, 0 } |
||
341 |
}; |
||
342 |
|||
343 |
static const int len_months[2][MONSPERYEAR] = { |
||
344 |
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, |
||
345 |
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } |
||
346 |
}; |
||
347 |
|||
348 |
static const int len_years[2] = { |
||
349 |
DAYSPERNYEAR, DAYSPERLYEAR |
||
350 |
}; |
||
351 |
|||
352 |
static struct attype { |
||
353 |
zic_t at; |
||
354 |
unsigned char type; |
||
355 |
} attypes[TZ_MAX_TIMES]; |
||
356 |
|||
357 |
static long gmtoffs[TZ_MAX_TYPES]; |
||
358 |
static char isdsts[TZ_MAX_TYPES]; |
||
359 |
static unsigned char abbrinds[TZ_MAX_TYPES]; |
||
360 |
static char ttisstds[TZ_MAX_TYPES]; |
||
361 |
static char ttisgmts[TZ_MAX_TYPES]; |
||
362 |
static char chars[TZ_MAX_CHARS]; |
||
363 |
static zic_t trans[TZ_MAX_LEAPS]; |
||
364 |
static long corr[TZ_MAX_LEAPS]; |
||
365 |
static char roll[TZ_MAX_LEAPS]; |
||
366 |
|||
367 |
/* |
||
368 |
** Memory allocation. |
||
369 |
*/ |
||
370 |
|||
371 |
static void * |
||
372 |
memcheck(void *ptr) |
||
373 |
{ |
||
374 |
✗✓ | 714540 |
if (ptr == NULL) |
375 |
err(1, "Memory exhausted"); |
||
376 |
357270 |
return ptr; |
|
377 |
} |
||
378 |
|||
379 |
static char * |
||
380 |
ecatalloc(char *start, const char *tail) |
||
381 |
{ |
||
382 |
size_t len; |
||
383 |
char *str; |
||
384 |
|||
385 |
25698 |
len = strlen(start) + strlen(tail) + 1; |
|
386 |
12849 |
str = memcheck(realloc(start, len)); |
|
387 |
12849 |
strlcat(str, tail, len); |
|
388 |
12849 |
return str; |
|
389 |
} |
||
390 |
|||
391 |
#define emalloc(size) memcheck(malloc(size)) |
||
392 |
#define ereallocarray(ptr, nmemb, size) memcheck(reallocarray(ptr, nmemb, size)) |
||
393 |
#define erealloc(ptr, size) memcheck(realloc((ptr), (size))) |
||
394 |
#define ecpyalloc(ptr) memcheck(strdup(ptr)) |
||
395 |
|||
396 |
/* |
||
397 |
** Error handling. |
||
398 |
*/ |
||
399 |
|||
400 |
static void |
||
401 |
eats(const char *name, int num, const char *rname, int rnum) |
||
402 |
{ |
||
403 |
30939990 |
filename = name; |
|
404 |
15469995 |
linenum = num; |
|
405 |
15469995 |
rfilename = rname; |
|
406 |
15469995 |
rlinenum = rnum; |
|
407 |
15469995 |
} |
|
408 |
|||
409 |
static void |
||
410 |
eat(const char *name, int num) |
||
411 |
{ |
||
412 |
358206 |
eats(name, num, NULL, -1); |
|
413 |
179103 |
} |
|
414 |
|||
415 |
static void |
||
416 |
error(const char *string) |
||
417 |
{ |
||
418 |
/* |
||
419 |
** Match the format of "cc" to allow sh users to |
||
420 |
** zic ... 2>&1 | error -t "*" -v |
||
421 |
** on BSD systems. |
||
422 |
*/ |
||
423 |
fprintf(stderr, "\"%s\", line %d: %s", |
||
424 |
filename, linenum, string); |
||
425 |
if (rfilename != NULL) |
||
426 |
fprintf(stderr, " (rule from \"%s\", line %d)", |
||
427 |
rfilename, rlinenum); |
||
428 |
fprintf(stderr, "\n"); |
||
429 |
++errors; |
||
430 |
} |
||
431 |
|||
432 |
static void |
||
433 |
warning(const char *string) |
||
434 |
{ |
||
435 |
char *cp; |
||
436 |
|||
437 |
cp = ecpyalloc("warning: "); |
||
438 |
cp = ecatalloc(cp, string); |
||
439 |
error(cp); |
||
440 |
free(cp); |
||
441 |
--errors; |
||
442 |
} |
||
443 |
|||
444 |
|||
445 |
static const char * |
||
446 |
scheck(const char *string, const char *format) |
||
447 |
{ |
||
448 |
const char *fp, *result; |
||
449 |
377334 |
char *fbuf, *tp, dummy; |
|
450 |
int c; |
||
451 |
|||
452 |
result = ""; |
||
453 |
✗✓ | 188667 |
if (string == NULL || format == NULL) |
454 |
return result; |
||
455 |
188667 |
fbuf = reallocarray(NULL, strlen(format) + 2, 2); |
|
456 |
✗✓ | 188667 |
if (fbuf == NULL) |
457 |
return result; |
||
458 |
fp = format; |
||
459 |
tp = fbuf; |
||
460 |
✓✓ | 682101 |
while ((*tp++ = c = *fp++) != '\0') { |
461 |
✓✓ | 304767 |
if (c != '%') |
462 |
continue; |
||
463 |
✗✓ | 246717 |
if (*fp == '%') { |
464 |
*tp++ = *fp++; |
||
465 |
continue; |
||
466 |
} |
||
467 |
246717 |
*tp++ = '*'; |
|
468 |
✗✓ | 246717 |
if (*fp == '*') |
469 |
++fp; |
||
470 |
✗✓ | 246717 |
while (isdigit((unsigned char)*fp)) |
471 |
*tp++ = *fp++; |
||
472 |
✓✓✗✓ |
371430 |
if (*fp == 'l' || *fp == 'h') |
473 |
122004 |
*tp++ = *fp++; |
|
474 |
✗✓ | 124713 |
else if (*fp == '[') |
475 |
do { |
||
476 |
*tp++ = *fp++; |
||
477 |
} while (*fp != '\0' && *fp != ']'); |
||
478 |
✓✗ | 246717 |
if ((*tp++ = *fp++) == '\0') |
479 |
break; |
||
480 |
} |
||
481 |
188667 |
*(tp - 1) = '%'; |
|
482 |
188667 |
*tp++ = 'c'; |
|
483 |
188667 |
*tp = '\0'; |
|
484 |
✓✓ | 188667 |
if (sscanf(string, fbuf, &dummy) != 1) |
485 |
134946 |
result = format; |
|
486 |
188667 |
free(fbuf); |
|
487 |
188667 |
return result; |
|
488 |
188667 |
} |
|
489 |
|||
490 |
static void |
||
491 |
usage(void) |
||
492 |
{ |
||
493 |
fprintf(stderr, |
||
494 |
"usage: %s [-v] [-d directory] [-L leapsecondfilename] [-l timezone]\n" |
||
495 |
"\t\t[-p timezone] [-y command] [filename ...]\n", |
||
496 |
__progname); |
||
497 |
exit(EXIT_FAILURE); |
||
498 |
} |
||
499 |
|||
500 |
static const char *psxrules; |
||
501 |
static const char *lcltime; |
||
502 |
static const char *directory; |
||
503 |
static const char *leapsec; |
||
504 |
static const char *yitcommand; |
||
505 |
|||
506 |
int |
||
507 |
main(int argc, char **argv) |
||
508 |
{ |
||
509 |
int i, j, c; |
||
510 |
|||
511 |
✗✓ | 24 |
if (pledge("stdio rpath wpath cpath proc exec flock", NULL) == -1) |
512 |
err(1, "pledge"); |
||
513 |
|||
514 |
12 |
umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); |
|
515 |
✓✓ | 60 |
while ((c = getopt(argc, argv, "d:l:p:L:vy:")) != -1) |
516 |
✗✓✗✓ ✓✓✗ |
36 |
switch (c) { |
517 |
default: |
||
518 |
usage(); |
||
519 |
case 'd': |
||
520 |
✓✗ | 12 |
if (directory == NULL) |
521 |
12 |
directory = optarg; |
|
522 |
else |
||
523 |
errx(1, "More than one -d option specified"); |
||
524 |
12 |
break; |
|
525 |
case 'l': |
||
526 |
if (lcltime == NULL) |
||
527 |
lcltime = optarg; |
||
528 |
else |
||
529 |
errx(1, "More than one -l option specified"); |
||
530 |
break; |
||
531 |
case 'p': |
||
532 |
✓✗ | 3 |
if (psxrules == NULL) |
533 |
3 |
psxrules = optarg; |
|
534 |
else |
||
535 |
errx(1, "More than one -p option specified"); |
||
536 |
3 |
break; |
|
537 |
case 'y': |
||
538 |
✓✗ | 12 |
if (yitcommand == NULL) |
539 |
12 |
yitcommand = optarg; |
|
540 |
else |
||
541 |
errx(1, "More than one -y option specified"); |
||
542 |
12 |
break; |
|
543 |
case 'L': |
||
544 |
✓✗ | 9 |
if (leapsec == NULL) |
545 |
9 |
leapsec = optarg; |
|
546 |
else |
||
547 |
errx(1, "More than one -L option specified"); |
||
548 |
9 |
break; |
|
549 |
case 'v': |
||
550 |
noise = TRUE; |
||
551 |
break; |
||
552 |
} |
||
553 |
✗✓✗✗ |
12 |
if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) |
554 |
usage(); /* usage message by request */ |
||
555 |
✗✓ | 12 |
if (directory == NULL) |
556 |
directory = TZDIR; |
||
557 |
✗✓ | 12 |
if (yitcommand == NULL) |
558 |
yitcommand = "yearistype"; |
||
559 |
|||
560 |
12 |
setboundaries(); |
|
561 |
|||
562 |
✓✓ | 12 |
if (optind < argc && leapsec != NULL) { |
563 |
9 |
infile(leapsec); |
|
564 |
9 |
adjleap(); |
|
565 |
9 |
} |
|
566 |
|||
567 |
✓✓ | 240 |
for (i = optind; i < argc; ++i) |
568 |
108 |
infile(argv[i]); |
|
569 |
✗✓ | 12 |
if (errors) |
570 |
exit(EXIT_FAILURE); |
||
571 |
12 |
associate(); |
|
572 |
✓✓ | 6972 |
for (i = 0; i < nzones; i = j) { |
573 |
/* |
||
574 |
** Find the next non-continuation zone entry. |
||
575 |
*/ |
||
576 |
✓✓✓✓ |
54693 |
for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) |
577 |
continue; |
||
578 |
3474 |
outzone(&zones[i], j - i); |
|
579 |
} |
||
580 |
/* |
||
581 |
** Make links. |
||
582 |
*/ |
||
583 |
✓✓ | 3768 |
for (i = 0; i < nlinks; ++i) { |
584 |
1872 |
eat(links[i].l_filename, links[i].l_linenum); |
|
585 |
1872 |
dolink(links[i].l_from, links[i].l_to); |
|
586 |
✗✓ | 1872 |
if (noise) |
587 |
for (j = 0; j < nlinks; ++j) |
||
588 |
if (strcmp(links[i].l_to, |
||
589 |
links[j].l_from) == 0) |
||
590 |
warning("link to link"); |
||
591 |
} |
||
592 |
✗✓ | 12 |
if (lcltime != NULL) { |
593 |
eat("command line", 1); |
||
594 |
dolink(lcltime, TZDEFAULT); |
||
595 |
} |
||
596 |
✓✓ | 12 |
if (psxrules != NULL) { |
597 |
3 |
eat("command line", 1); |
|
598 |
3 |
dolink(psxrules, TZDEFRULES); |
|
599 |
3 |
} |
|
600 |
12 |
return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; |
|
601 |
} |
||
602 |
|||
603 |
static void |
||
604 |
dolink(const char *fromfield, const char *tofield) |
||
605 |
{ |
||
606 |
char *fromname, *toname; |
||
607 |
|||
608 |
✗✓ | 3750 |
if (fromfield[0] == '/') |
609 |
fromname = ecpyalloc(fromfield); |
||
610 |
else { |
||
611 |
1875 |
fromname = ecpyalloc(directory); |
|
612 |
1875 |
fromname = ecatalloc(fromname, "/"); |
|
613 |
1875 |
fromname = ecatalloc(fromname, fromfield); |
|
614 |
} |
||
615 |
✗✓ | 1875 |
if (tofield[0] == '/') |
616 |
toname = ecpyalloc(tofield); |
||
617 |
else { |
||
618 |
1875 |
toname = ecpyalloc(directory); |
|
619 |
1875 |
toname = ecatalloc(toname, "/"); |
|
620 |
1875 |
toname = ecatalloc(toname, tofield); |
|
621 |
} |
||
622 |
/* |
||
623 |
** We get to be careful here since |
||
624 |
** there's a fair chance of root running us. |
||
625 |
*/ |
||
626 |
✓✗ | 1875 |
if (!itsdir(toname)) |
627 |
1875 |
remove(toname); |
|
628 |
✗✓ | 1875 |
if (link(fromname, toname) != 0) { |
629 |
int result; |
||
630 |
|||
631 |
if (mkdirs(toname) != 0) |
||
632 |
exit(EXIT_FAILURE); |
||
633 |
|||
634 |
result = link(fromname, toname); |
||
635 |
if (result != 0 && errno == EXDEV) |
||
636 |
result = symlink(fromname, toname); |
||
637 |
if (result != 0) |
||
638 |
err(1, "Can't link from %s to %s", fromname, toname); |
||
639 |
} |
||
640 |
1875 |
free(fromname); |
|
641 |
1875 |
free(toname); |
|
642 |
1875 |
} |
|
643 |
|||
644 |
#define TIME_T_BITS_IN_FILE 64 |
||
645 |
|||
646 |
static void |
||
647 |
setboundaries(void) |
||
648 |
{ |
||
649 |
int i; |
||
650 |
|||
651 |
24 |
min_time = -1; |
|
652 |
✓✓ | 1536 |
for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i) |
653 |
756 |
min_time *= 2; |
|
654 |
12 |
max_time = -(min_time + 1); |
|
655 |
12 |
} |
|
656 |
|||
657 |
static int |
||
658 |
itsdir(const char *name) |
||
659 |
{ |
||
660 |
char *myname; |
||
661 |
int accres; |
||
662 |
|||
663 |
10698 |
myname = ecpyalloc(name); |
|
664 |
5349 |
myname = ecatalloc(myname, "/."); |
|
665 |
5349 |
accres = access(myname, F_OK); |
|
666 |
5349 |
free(myname); |
|
667 |
5349 |
return accres == 0; |
|
668 |
} |
||
669 |
|||
670 |
/* |
||
671 |
** Associate sets of rules with zones. |
||
672 |
*/ |
||
673 |
|||
674 |
/* |
||
675 |
** Sort by rule name. |
||
676 |
*/ |
||
677 |
|||
678 |
static int |
||
679 |
rcomp(const void *cp1, const void *cp2) |
||
680 |
{ |
||
681 |
314361 |
return strcmp(((const struct rule *) cp1)->r_name, |
|
682 |
104787 |
((const struct rule *) cp2)->r_name); |
|
683 |
} |
||
684 |
|||
685 |
static void |
||
686 |
associate(void) |
||
687 |
{ |
||
688 |
struct zone *zp; |
||
689 |
struct rule *rp; |
||
690 |
int base, out, i, j; |
||
691 |
|||
692 |
✓✓ | 24 |
if (nrules != 0) { |
693 |
9 |
qsort(rules, nrules, sizeof *rules, rcomp); |
|
694 |
✓✓ | 34686 |
for (i = 0; i < nrules - 1; ++i) { |
695 |
✓✓ | 52002 |
if (strcmp(rules[i].r_name, |
696 |
34668 |
rules[i + 1].r_name) != 0) |
|
697 |
continue; |
||
698 |
✗✓ | 48330 |
if (strcmp(rules[i].r_filename, |
699 |
32220 |
rules[i + 1].r_filename) == 0) |
|
700 |
continue; |
||
701 |
eat(rules[i].r_filename, rules[i].r_linenum); |
||
702 |
warning("same rule name in multiple files"); |
||
703 |
eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); |
||
704 |
warning("same rule name in multiple files"); |
||
705 |
for (j = i + 2; j < nrules; ++j) { |
||
706 |
if (strcmp(rules[i].r_name, |
||
707 |
rules[j].r_name) != 0) |
||
708 |
break; |
||
709 |
if (strcmp(rules[i].r_filename, |
||
710 |
rules[j].r_filename) == 0) |
||
711 |
continue; |
||
712 |
if (strcmp(rules[i + 1].r_filename, |
||
713 |
rules[j].r_filename) == 0) |
||
714 |
continue; |
||
715 |
break; |
||
716 |
} |
||
717 |
i = j - 1; |
||
718 |
} |
||
719 |
} |
||
720 |
✓✓ | 36492 |
for (i = 0; i < nzones; ++i) { |
721 |
18234 |
zp = &zones[i]; |
|
722 |
18234 |
zp->z_rules = NULL; |
|
723 |
18234 |
zp->z_nrules = 0; |
|
724 |
} |
||
725 |
✓✓ | 2490 |
for (base = 0; base < nrules; base = out) { |
726 |
1233 |
rp = &rules[base]; |
|
727 |
✓✓ | 34686 |
for (out = base + 1; out < nrules; ++out) |
728 |
✓✓ | 17334 |
if (strcmp(rp->r_name, rules[out].r_name) != 0) |
729 |
break; |
||
730 |
✓✓ | 4998582 |
for (i = 0; i < nzones; ++i) { |
731 |
2498058 |
zp = &zones[i]; |
|
732 |
✓✓ | 2498058 |
if (strcmp(zp->z_rule, rp->r_name) != 0) |
733 |
continue; |
||
734 |
7146 |
zp->z_rules = rp; |
|
735 |
7146 |
zp->z_nrules = out - base; |
|
736 |
7146 |
} |
|
737 |
} |
||
738 |
✓✓ | 36492 |
for (i = 0; i < nzones; ++i) { |
739 |
18234 |
zp = &zones[i]; |
|
740 |
✓✓ | 18234 |
if (zp->z_nrules == 0) { |
741 |
/* |
||
742 |
** Maybe we have a local standard time offset. |
||
743 |
*/ |
||
744 |
11088 |
eat(zp->z_filename, zp->z_linenum); |
|
745 |
11088 |
zp->z_stdoff = gethms(zp->z_rule, "unruly zone", |
|
746 |
TRUE); |
||
747 |
/* |
||
748 |
** Note, though, that if there's no rule, |
||
749 |
** a '%s' in the format is a bad thing. |
||
750 |
*/ |
||
751 |
✗✓ | 11088 |
if (strchr(zp->z_format, '%') != 0) |
752 |
error("%s in ruleless zone"); |
||
753 |
} |
||
754 |
} |
||
755 |
✗✓ | 12 |
if (errors) |
756 |
exit(EXIT_FAILURE); |
||
757 |
12 |
} |
|
758 |
|||
759 |
static void |
||
760 |
infile(const char *name) |
||
761 |
{ |
||
762 |
FILE *fp; |
||
763 |
char **fields, *cp; |
||
764 |
const struct lookup *lp; |
||
765 |
int nfields, wantcont, num; |
||
766 |
234 |
char buf[BUFSIZ]; |
|
767 |
|||
768 |
✗✓ | 117 |
if (strcmp(name, "-") == 0) { |
769 |
name = "standard input"; |
||
770 |
fp = stdin; |
||
771 |
✗✓ | 117 |
} else if ((fp = fopen(name, "r")) == NULL) |
772 |
err(1, "Can't open %s", name); |
||
773 |
wantcont = FALSE; |
||
774 |
141516 |
for (num = 1; ; ++num) { |
|
775 |
141516 |
eat(name, num); |
|
776 |
✓✓ | 141516 |
if (fgets(buf, sizeof buf, fp) != buf) |
777 |
break; |
||
778 |
141399 |
cp = strchr(buf, '\n'); |
|
779 |
✗✓ | 141399 |
if (cp == NULL) { |
780 |
error("line too long"); |
||
781 |
exit(EXIT_FAILURE); |
||
782 |
} |
||
783 |
141399 |
*cp = '\0'; |
|
784 |
141399 |
fields = getfields(buf); |
|
785 |
nfields = 0; |
||
786 |
✓✓ | 845028 |
while (fields[nfields] != NULL) { |
787 |
static char nada; |
||
788 |
|||
789 |
✓✓ | 281115 |
if (strcmp(fields[nfields], "-") == 0) |
790 |
32517 |
fields[nfields] = &nada; |
|
791 |
281115 |
++nfields; |
|
792 |
} |
||
793 |
✓✓ | 141399 |
if (nfields == 0) { |
794 |
/* nothing to do */ |
||
795 |
✓✓ | 37530 |
} else if (wantcont) { |
796 |
14760 |
wantcont = inzcont(fields, nfields); |
|
797 |
14760 |
} else { |
|
798 |
22770 |
lp = byword(fields[0], line_codes); |
|
799 |
✗✓ | 22770 |
if (lp == NULL) |
800 |
error("input line of unknown type"); |
||
801 |
✓✓✓✓ ✗ |
22770 |
else switch ((int) (lp->l_value)) { |
802 |
case LC_RULE: |
||
803 |
17343 |
inrule(fields, nfields); |
|
804 |
wantcont = FALSE; |
||
805 |
17343 |
break; |
|
806 |
case LC_ZONE: |
||
807 |
3474 |
wantcont = inzone(fields, nfields); |
|
808 |
3474 |
break; |
|
809 |
case LC_LINK: |
||
810 |
1872 |
inlink(fields, nfields); |
|
811 |
wantcont = FALSE; |
||
812 |
1872 |
break; |
|
813 |
case LC_LEAP: |
||
814 |
✗✓ | 81 |
if (name != leapsec) |
815 |
fprintf(stderr, |
||
816 |
"%s: Leap line in non leap seconds file %s\n", |
||
817 |
__progname, name); |
||
818 |
/* no exit? */ |
||
819 |
else |
||
820 |
81 |
inleap(fields, nfields); |
|
821 |
wantcont = FALSE; |
||
822 |
81 |
break; |
|
823 |
default: /* "cannot happen" */ |
||
824 |
errx(1, "panic: Invalid l_value %d", lp->l_value); |
||
825 |
} |
||
826 |
} |
||
827 |
141399 |
free(fields); |
|
828 |
} |
||
829 |
✓✗✗✓ ✗✗ |
234 |
if (ferror(fp)) |
830 |
errx(1, "Error reading %s", filename); |
||
831 |
✓✗✗✓ |
234 |
if (fp != stdin && fclose(fp)) |
832 |
err(1, "Error closing %s", filename); |
||
833 |
✗✓ | 117 |
if (wantcont) |
834 |
error("expected continuation line not found"); |
||
835 |
117 |
} |
|
836 |
|||
837 |
/* |
||
838 |
** Convert a string of one of the forms |
||
839 |
** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss |
||
840 |
** into a number of seconds. |
||
841 |
** A null string maps to zero. |
||
842 |
** Call error with errstring and return zero on errors. |
||
843 |
*/ |
||
844 |
|||
845 |
static long |
||
846 |
gethms(const char *string, const char *errstring, int signable) |
||
847 |
{ |
||
848 |
157698 |
long hh; |
|
849 |
78849 |
int mm, ss, sign; |
|
850 |
|||
851 |
✓✗✓✓ |
157698 |
if (string == NULL || *string == '\0') |
852 |
10566 |
return 0; |
|
853 |
✓✓ | 68283 |
if (!signable) |
854 |
32184 |
sign = 1; |
|
855 |
✓✓ | 36099 |
else if (*string == '-') { |
856 |
sign = -1; |
||
857 |
8370 |
++string; |
|
858 |
8370 |
} else |
|
859 |
sign = 1; |
||
860 |
✓✓ | 68283 |
if (sscanf(string, scheck(string, "%ld"), &hh) == 1) |
861 |
18891 |
mm = ss = 0; |
|
862 |
✓✓ | 49392 |
else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2) |
863 |
45063 |
ss = 0; |
|
864 |
✗✓ | 8658 |
else if (sscanf(string, scheck(string, "%ld:%d:%d"), |
865 |
4329 |
&hh, &mm, &ss) != 3) { |
|
866 |
error(errstring); |
||
867 |
return 0; |
||
868 |
} |
||
869 |
✗✓ | 341415 |
if (hh < 0 || |
870 |
136566 |
mm < 0 || mm >= MINSPERHOUR || |
|
871 |
136566 |
ss < 0 || ss > SECSPERMIN) { |
|
872 |
error(errstring); |
||
873 |
return 0; |
||
874 |
} |
||
875 |
✗✓ | 68283 |
if (LONG_MAX / SECSPERHOUR < hh) { |
876 |
error("time overflow"); |
||
877 |
return 0; |
||
878 |
} |
||
879 |
136566 |
return oadd(eitol(sign) * hh * eitol(SECSPERHOUR), |
|
880 |
68283 |
eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))); |
|
881 |
78849 |
} |
|
882 |
|||
883 |
static void |
||
884 |
inrule(char **fields, int nfields) |
||
885 |
{ |
||
886 |
static struct rule r; |
||
887 |
|||
888 |
✗✓ | 34686 |
if (nfields != RULE_FIELDS) { |
889 |
error("wrong number of fields on Rule line"); |
||
890 |
return; |
||
891 |
} |
||
892 |
✗✓ | 17343 |
if (*fields[RF_NAME] == '\0') { |
893 |
error("nameless rule"); |
||
894 |
return; |
||
895 |
} |
||
896 |
17343 |
r.r_filename = filename; |
|
897 |
17343 |
r.r_linenum = linenum; |
|
898 |
17343 |
r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); |
|
899 |
34686 |
rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], |
|
900 |
17343 |
fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); |
|
901 |
17343 |
r.r_name = ecpyalloc(fields[RF_NAME]); |
|
902 |
17343 |
r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); |
|
903 |
✓✓ | 17343 |
if (max_abbrvar_len < strlen(r.r_abbrvar)) |
904 |
27 |
max_abbrvar_len = strlen(r.r_abbrvar); |
|
905 |
17343 |
rules = ereallocarray(rules, nrules + 1, sizeof *rules); |
|
906 |
17343 |
rules[nrules++] = r; |
|
907 |
34686 |
} |
|
908 |
|||
909 |
static int |
||
910 |
inzone(char **fields, int nfields) |
||
911 |
{ |
||
912 |
int i; |
||
913 |
static char *buf; |
||
914 |
size_t len; |
||
915 |
|||
916 |
✗✓ | 6948 |
if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { |
917 |
error("wrong number of fields on Zone line"); |
||
918 |
return FALSE; |
||
919 |
} |
||
920 |
✗✓ | 3474 |
if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { |
921 |
len = 132 + strlen(TZDEFAULT); |
||
922 |
buf = erealloc(buf, len); |
||
923 |
snprintf(buf, len, |
||
924 |
"\"Zone %s\" line and -l option are mutually exclusive", |
||
925 |
TZDEFAULT); |
||
926 |
error(buf); |
||
927 |
return FALSE; |
||
928 |
} |
||
929 |
✗✓ | 3474 |
if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { |
930 |
len = 132 + strlen(TZDEFRULES); |
||
931 |
buf = erealloc(buf, len); |
||
932 |
snprintf(buf, len, |
||
933 |
"\"Zone %s\" line and -p option are mutually exclusive", |
||
934 |
TZDEFRULES); |
||
935 |
error(buf); |
||
936 |
return FALSE; |
||
937 |
} |
||
938 |
✓✓ | 6989688 |
for (i = 0; i < nzones; ++i) |
939 |
✓✓✗✓ |
4160115 |
if (zones[i].z_name != NULL && |
940 |
668745 |
strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { |
|
941 |
len = 132 + strlen(fields[ZF_NAME]) + |
||
942 |
strlen(zones[i].z_filename); |
||
943 |
buf = erealloc(buf, len); |
||
944 |
snprintf(buf, len, |
||
945 |
"duplicate zone name %s (file \"%s\", line %d)", |
||
946 |
fields[ZF_NAME], |
||
947 |
zones[i].z_filename, |
||
948 |
zones[i].z_linenum); |
||
949 |
error(buf); |
||
950 |
return FALSE; |
||
951 |
} |
||
952 |
3474 |
return inzsub(fields, nfields, FALSE); |
|
953 |
3474 |
} |
|
954 |
|||
955 |
static int |
||
956 |
inzcont(char **fields, int nfields) |
||
957 |
{ |
||
958 |
✗✓ | 29520 |
if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { |
959 |
error("wrong number of fields on Zone continuation line"); |
||
960 |
return FALSE; |
||
961 |
} |
||
962 |
14760 |
return inzsub(fields, nfields, TRUE); |
|
963 |
14760 |
} |
|
964 |
|||
965 |
static int |
||
966 |
inzsub(char **fields, int nfields, int iscont) |
||
967 |
{ |
||
968 |
char *cp; |
||
969 |
static struct zone z; |
||
970 |
int i_gmtoff, i_rule, i_format; |
||
971 |
int i_untilyear, i_untilmonth; |
||
972 |
int i_untilday, i_untiltime; |
||
973 |
int hasuntil; |
||
974 |
|||
975 |
✓✓ | 36468 |
if (iscont) { |
976 |
i_gmtoff = ZFC_GMTOFF; |
||
977 |
i_rule = ZFC_RULE; |
||
978 |
i_format = ZFC_FORMAT; |
||
979 |
i_untilyear = ZFC_TILYEAR; |
||
980 |
i_untilmonth = ZFC_TILMONTH; |
||
981 |
i_untilday = ZFC_TILDAY; |
||
982 |
i_untiltime = ZFC_TILTIME; |
||
983 |
z.z_name = NULL; |
||
984 |
14760 |
} else { |
|
985 |
i_gmtoff = ZF_GMTOFF; |
||
986 |
i_rule = ZF_RULE; |
||
987 |
i_format = ZF_FORMAT; |
||
988 |
i_untilyear = ZF_TILYEAR; |
||
989 |
i_untilmonth = ZF_TILMONTH; |
||
990 |
i_untilday = ZF_TILDAY; |
||
991 |
i_untiltime = ZF_TILTIME; |
||
992 |
3474 |
z.z_name = ecpyalloc(fields[ZF_NAME]); |
|
993 |
} |
||
994 |
18234 |
z.z_filename = filename; |
|
995 |
18234 |
z.z_linenum = linenum; |
|
996 |
18234 |
z.z_gmtoff = gethms(fields[i_gmtoff], "invalid UTC offset", TRUE); |
|
997 |
✓✓ | 18234 |
if ((cp = strchr(fields[i_format], '%')) != 0) { |
998 |
✓✗✗✓ |
8550 |
if (*++cp != 's' || strchr(cp, '%') != 0) { |
999 |
error("invalid abbreviation format"); |
||
1000 |
return FALSE; |
||
1001 |
} |
||
1002 |
} |
||
1003 |
18234 |
z.z_rule = ecpyalloc(fields[i_rule]); |
|
1004 |
18234 |
z.z_format = ecpyalloc(fields[i_format]); |
|
1005 |
✓✓ | 18234 |
if (max_format_len < strlen(z.z_format)) |
1006 |
36 |
max_format_len = strlen(z.z_format); |
|
1007 |
18234 |
hasuntil = nfields > i_untilyear; |
|
1008 |
✓✓ | 18234 |
if (hasuntil) { |
1009 |
14760 |
z.z_untilrule.r_filename = filename; |
|
1010 |
14760 |
z.z_untilrule.r_linenum = linenum; |
|
1011 |
14760 |
rulesub(&z.z_untilrule, |
|
1012 |
14760 |
fields[i_untilyear], |
|
1013 |
"only", |
||
1014 |
"", |
||
1015 |
✓✓ | 40581 |
(nfields > i_untilmonth) ? |
1016 |
11061 |
fields[i_untilmonth] : "Jan", |
|
1017 |
✓✓ | 39051 |
(nfields > i_untilday) ? fields[i_untilday] : "1", |
1018 |
✓✓ | 34020 |
(nfields > i_untiltime) ? fields[i_untiltime] : "0"); |
1019 |
14760 |
z.z_untiltime = rpytime(&z.z_untilrule, |
|
1020 |
14760 |
z.z_untilrule.r_loyear); |
|
1021 |
✓✓✗✓ |
26415 |
if (iscont && nzones > 0 && |
1022 |
✓✗ | 11655 |
z.z_untiltime > min_time && |
1023 |
✓✗ | 11655 |
z.z_untiltime < max_time && |
1024 |
✓✗ | 11655 |
zones[nzones - 1].z_untiltime > min_time && |
1025 |
✓✗ | 11655 |
zones[nzones - 1].z_untiltime < max_time && |
1026 |
11655 |
zones[nzones - 1].z_untiltime >= z.z_untiltime) { |
|
1027 |
error("Zone continuation line end time is not after end time of previous line"); |
||
1028 |
return FALSE; |
||
1029 |
} |
||
1030 |
} |
||
1031 |
18234 |
zones = ereallocarray(zones, nzones + 1, sizeof *zones); |
|
1032 |
18234 |
zones[nzones++] = z; |
|
1033 |
/* |
||
1034 |
** If there was an UNTIL field on this line, |
||
1035 |
** there's more information about the zone on the next line. |
||
1036 |
*/ |
||
1037 |
18234 |
return hasuntil; |
|
1038 |
18234 |
} |
|
1039 |
|||
1040 |
static void |
||
1041 |
inleap(char **fields, int nfields) |
||
1042 |
{ |
||
1043 |
const char *cp; |
||
1044 |
const struct lookup *lp; |
||
1045 |
int i, j; |
||
1046 |
162 |
int year, month, day; |
|
1047 |
long dayoff, tod; |
||
1048 |
zic_t t; |
||
1049 |
|||
1050 |
✗✓ | 81 |
if (nfields != LEAP_FIELDS) { |
1051 |
error("wrong number of fields on Leap line"); |
||
1052 |
return; |
||
1053 |
} |
||
1054 |
dayoff = 0; |
||
1055 |
81 |
cp = fields[LP_YEAR]; |
|
1056 |
✗✓ | 81 |
if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { |
1057 |
/* |
||
1058 |
** Leapin' Lizards! |
||
1059 |
*/ |
||
1060 |
error("invalid leaping year"); |
||
1061 |
return; |
||
1062 |
} |
||
1063 |
✓✓✓✓ |
159 |
if (!leapseen || leapmaxyear < year) |
1064 |
78 |
leapmaxyear = year; |
|
1065 |
✓✓✗✓ |
159 |
if (!leapseen || leapminyear > year) |
1066 |
3 |
leapminyear = year; |
|
1067 |
81 |
leapseen = TRUE; |
|
1068 |
j = EPOCH_YEAR; |
||
1069 |
✓✓ | 3210 |
while (j != year) { |
1070 |
✓✗ | 1524 |
if (year > j) { |
1071 |
✓✓✓✓ |
3435 |
i = len_years[isleap(j)]; |
1072 |
1524 |
++j; |
|
1073 |
1524 |
} else { |
|
1074 |
--j; |
||
1075 |
i = -len_years[isleap(j)]; |
||
1076 |
} |
||
1077 |
1524 |
dayoff = oadd(dayoff, eitol(i)); |
|
1078 |
} |
||
1079 |
✗✓ | 81 |
if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { |
1080 |
error("invalid month name"); |
||
1081 |
return; |
||
1082 |
} |
||
1083 |
81 |
month = lp->l_value; |
|
1084 |
j = TM_JANUARY; |
||
1085 |
✓✓ | 1548 |
while (j != month) { |
1086 |
✓✓✗✓ |
1563 |
i = len_months[isleap(year)][j]; |
1087 |
693 |
dayoff = oadd(dayoff, eitol(i)); |
|
1088 |
693 |
++j; |
|
1089 |
} |
||
1090 |
81 |
cp = fields[LP_DAY]; |
|
1091 |
✓✗✗✓ |
243 |
if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || |
1092 |
✓✓✗✓ |
264 |
day <= 0 || day > len_months[isleap(year)][month]) { |
1093 |
error("invalid day of month"); |
||
1094 |
return; |
||
1095 |
} |
||
1096 |
81 |
dayoff = oadd(dayoff, eitol(day - 1)); |
|
1097 |
if (dayoff < 0 && !TYPE_SIGNED(zic_t)) { |
||
1098 |
error("time before zero"); |
||
1099 |
return; |
||
1100 |
} |
||
1101 |
✗✓ | 81 |
if (dayoff < min_time / SECSPERDAY) { |
1102 |
error("time too small"); |
||
1103 |
return; |
||
1104 |
} |
||
1105 |
✗✓ | 81 |
if (dayoff > max_time / SECSPERDAY) { |
1106 |
error("time too large"); |
||
1107 |
return; |
||
1108 |
} |
||
1109 |
81 |
t = (zic_t) dayoff * SECSPERDAY; |
|
1110 |
81 |
tod = gethms(fields[LP_TIME], "invalid time of day", FALSE); |
|
1111 |
81 |
cp = fields[LP_CORR]; |
|
1112 |
{ |
||
1113 |
int positive; |
||
1114 |
int count; |
||
1115 |
|||
1116 |
✗✓ | 81 |
if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ |
1117 |
positive = FALSE; |
||
1118 |
count = 1; |
||
1119 |
✗✓ | 81 |
} else if (strcmp(cp, "--") == 0) { |
1120 |
positive = FALSE; |
||
1121 |
count = 2; |
||
1122 |
✓✗ | 81 |
} else if (strcmp(cp, "+") == 0) { |
1123 |
positive = TRUE; |
||
1124 |
count = 1; |
||
1125 |
✗✗ | 81 |
} else if (strcmp(cp, "++") == 0) { |
1126 |
positive = TRUE; |
||
1127 |
count = 2; |
||
1128 |
} else { |
||
1129 |
error("illegal CORRECTION field on Leap line"); |
||
1130 |
return; |
||
1131 |
} |
||
1132 |
✗✓ | 81 |
if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { |
1133 |
error("illegal Rolling/Stationary field on Leap line"); |
||
1134 |
return; |
||
1135 |
} |
||
1136 |
81 |
leapadd(tadd(t, tod), positive, lp->l_value, count); |
|
1137 |
✓✗ | 81 |
} |
1138 |
162 |
} |
|
1139 |
|||
1140 |
static void |
||
1141 |
inlink(char **fields, int nfields) |
||
1142 |
{ |
||
1143 |
struct link l; |
||
1144 |
|||
1145 |
✗✓ | 3744 |
if (nfields != LINK_FIELDS) { |
1146 |
error("wrong number of fields on Link line"); |
||
1147 |
return; |
||
1148 |
} |
||
1149 |
✗✓ | 1872 |
if (*fields[LF_FROM] == '\0') { |
1150 |
error("blank FROM field on Link line"); |
||
1151 |
return; |
||
1152 |
} |
||
1153 |
✗✓ | 1872 |
if (*fields[LF_TO] == '\0') { |
1154 |
error("blank TO field on Link line"); |
||
1155 |
return; |
||
1156 |
} |
||
1157 |
1872 |
l.l_filename = filename; |
|
1158 |
1872 |
l.l_linenum = linenum; |
|
1159 |
1872 |
l.l_from = ecpyalloc(fields[LF_FROM]); |
|
1160 |
1872 |
l.l_to = ecpyalloc(fields[LF_TO]); |
|
1161 |
1872 |
links = ereallocarray(links, nlinks + 1, sizeof *links); |
|
1162 |
1872 |
links[nlinks++] = l; |
|
1163 |
3744 |
} |
|
1164 |
|||
1165 |
static void |
||
1166 |
rulesub(struct rule * const rp, const char * const loyearp, |
||
1167 |
const char * const hiyearp, const char * const typep, |
||
1168 |
const char * const monthp, const char * const dayp, |
||
1169 |
const char * const timep) |
||
1170 |
{ |
||
1171 |
const struct lookup *lp; |
||
1172 |
const char *cp; |
||
1173 |
char *dp, *ep; |
||
1174 |
|||
1175 |
✗✓ | 64206 |
if ((lp = byword(monthp, mon_names)) == NULL) { |
1176 |
error("invalid month name"); |
||
1177 |
return; |
||
1178 |
} |
||
1179 |
32103 |
rp->r_month = lp->l_value; |
|
1180 |
32103 |
rp->r_todisstd = FALSE; |
|
1181 |
32103 |
rp->r_todisgmt = FALSE; |
|
1182 |
32103 |
dp = ecpyalloc(timep); |
|
1183 |
✓✗ | 32103 |
if (*dp != '\0') { |
1184 |
39213 |
ep = dp + strlen(dp) - 1; |
|
1185 |
✓✗✗✗ ✓✓ |
39213 |
switch (tolower((unsigned char)*ep)) { |
1186 |
case 's': /* Standard */ |
||
1187 |
6408 |
rp->r_todisstd = TRUE; |
|
1188 |
6408 |
rp->r_todisgmt = FALSE; |
|
1189 |
*ep = '\0'; |
||
1190 |
6408 |
break; |
|
1191 |
case 'w': /* Wall */ |
||
1192 |
rp->r_todisstd = FALSE; |
||
1193 |
rp->r_todisgmt = FALSE; |
||
1194 |
*ep = '\0'; |
||
1195 |
break; |
||
1196 |
case 'g': /* Greenwich */ |
||
1197 |
case 'u': /* Universal */ |
||
1198 |
case 'z': /* Zulu */ |
||
1199 |
702 |
rp->r_todisstd = TRUE; |
|
1200 |
702 |
rp->r_todisgmt = TRUE; |
|
1201 |
*ep = '\0'; |
||
1202 |
702 |
break; |
|
1203 |
} |
||
1204 |
7110 |
} |
|
1205 |
32103 |
rp->r_tod = gethms(dp, "invalid time of day", FALSE); |
|
1206 |
32103 |
free(dp); |
|
1207 |
/* |
||
1208 |
** Year work. |
||
1209 |
*/ |
||
1210 |
cp = loyearp; |
||
1211 |
32103 |
lp = byword(cp, begin_years); |
|
1212 |
32103 |
rp->r_lowasnum = lp == NULL; |
|
1213 |
✓✓✓✗ ✗ |
32121 |
if (!rp->r_lowasnum) switch ((int) lp->l_value) { |
1214 |
case YR_MINIMUM: |
||
1215 |
rp->r_loyear = INT_MIN; |
||
1216 |
18 |
break; |
|
1217 |
case YR_MAXIMUM: |
||
1218 |
rp->r_loyear = INT_MAX; |
||
1219 |
break; |
||
1220 |
default: /* "cannot happen" */ |
||
1221 |
errx(1, "panic: Invalid l_value %d", lp->l_value); |
||
1222 |
✗✓ | 32103 |
} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { |
1223 |
error("invalid starting year"); |
||
1224 |
return; |
||
1225 |
} |
||
1226 |
cp = hiyearp; |
||
1227 |
32103 |
lp = byword(cp, end_years); |
|
1228 |
32103 |
rp->r_hiwasnum = lp == NULL; |
|
1229 |
✓✓✗✓ ✓✗ |
58581 |
if (!rp->r_hiwasnum) switch ((int) lp->l_value) { |
1230 |
case YR_MINIMUM: |
||
1231 |
rp->r_hiyear = INT_MIN; |
||
1232 |
break; |
||
1233 |
case YR_MAXIMUM: |
||
1234 |
rp->r_hiyear = INT_MAX; |
||
1235 |
648 |
break; |
|
1236 |
case YR_ONLY: |
||
1237 |
25830 |
rp->r_hiyear = rp->r_loyear; |
|
1238 |
25830 |
break; |
|
1239 |
default: /* "cannot happen" */ |
||
1240 |
errx(1, "panic: Invalid l_value %d", lp->l_value); |
||
1241 |
✗✓ | 32103 |
} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { |
1242 |
error("invalid ending year"); |
||
1243 |
return; |
||
1244 |
} |
||
1245 |
✗✓ | 32103 |
if (rp->r_loyear > rp->r_hiyear) { |
1246 |
error("starting year greater than ending year"); |
||
1247 |
return; |
||
1248 |
} |
||
1249 |
✗✓ | 32103 |
if (*typep == '\0') |
1250 |
rp->r_yrtype = NULL; |
||
1251 |
else { |
||
1252 |
if (rp->r_loyear == rp->r_hiyear) { |
||
1253 |
error("typed single year"); |
||
1254 |
return; |
||
1255 |
} |
||
1256 |
rp->r_yrtype = ecpyalloc(typep); |
||
1257 |
} |
||
1258 |
/* |
||
1259 |
** Day work. |
||
1260 |
** Accept things such as: |
||
1261 |
** 1 |
||
1262 |
** last-Sunday |
||
1263 |
** Sun<=20 |
||
1264 |
** Sun>=7 |
||
1265 |
*/ |
||
1266 |
32103 |
dp = ecpyalloc(dayp); |
|
1267 |
✓✓ | 32103 |
if ((lp = byword(dp, lasts)) != NULL) { |
1268 |
3312 |
rp->r_dycode = DC_DOWLEQ; |
|
1269 |
3312 |
rp->r_wday = lp->l_value; |
|
1270 |
3312 |
rp->r_dayofmonth = len_months[1][rp->r_month]; |
|
1271 |
3312 |
} else { |
|
1272 |
✗✓ | 28791 |
if ((ep = strchr(dp, '<')) != 0) |
1273 |
rp->r_dycode = DC_DOWLEQ; |
||
1274 |
✓✓ | 28791 |
else if ((ep = strchr(dp, '>')) != 0) |
1275 |
3690 |
rp->r_dycode = DC_DOWGEQ; |
|
1276 |
else { |
||
1277 |
ep = dp; |
||
1278 |
rp->r_dycode = DC_DOM; |
||
1279 |
} |
||
1280 |
✓✓ | 28791 |
if (rp->r_dycode != DC_DOM) { |
1281 |
3690 |
*ep++ = 0; |
|
1282 |
✗✓ | 3690 |
if (*ep++ != '=') { |
1283 |
error("invalid day of month"); |
||
1284 |
free(dp); |
||
1285 |
return; |
||
1286 |
} |
||
1287 |
✗✓ | 3690 |
if ((lp = byword(dp, wday_names)) == NULL) { |
1288 |
error("invalid weekday name"); |
||
1289 |
free(dp); |
||
1290 |
return; |
||
1291 |
} |
||
1292 |
3690 |
rp->r_wday = lp->l_value; |
|
1293 |
3690 |
} |
|
1294 |
✓✗✗✓ |
57582 |
if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || |
1295 |
✓✗ | 28791 |
rp->r_dayofmonth <= 0 || |
1296 |
28791 |
(rp->r_dayofmonth > len_months[1][rp->r_month])) { |
|
1297 |
error("invalid day of month"); |
||
1298 |
free(dp); |
||
1299 |
return; |
||
1300 |
} |
||
1301 |
} |
||
1302 |
32103 |
free(dp); |
|
1303 |
64206 |
} |
|
1304 |
|||
1305 |
static void |
||
1306 |
convert(long val, char *buf) |
||
1307 |
{ |
||
1308 |
int i; |
||
1309 |
int shift; |
||
1310 |
|||
1311 |
✓✓ | 4471038 |
for (i = 0, shift = 24; i < 4; ++i, shift -= 8) |
1312 |
1625832 |
buf[i] = val >> shift; |
|
1313 |
406458 |
} |
|
1314 |
|||
1315 |
static void |
||
1316 |
convert64(zic_t val, char *buf) |
||
1317 |
{ |
||
1318 |
int i; |
||
1319 |
int shift; |
||
1320 |
|||
1321 |
✓✓ | 5704731 |
for (i = 0, shift = 56; i < 8; ++i, shift -= 8) |
1322 |
2401992 |
buf[i] = val >> shift; |
|
1323 |
300249 |
} |
|
1324 |
|||
1325 |
static void |
||
1326 |
puttzcode(long val, FILE *fp) |
||
1327 |
{ |
||
1328 |
729540 |
char buf[4]; |
|
1329 |
|||
1330 |
364770 |
convert(val, buf); |
|
1331 |
364770 |
fwrite(buf, sizeof buf, 1, fp); |
|
1332 |
364770 |
} |
|
1333 |
|||
1334 |
static void |
||
1335 |
puttzcode64(zic_t val, FILE *fp) |
||
1336 |
{ |
||
1337 |
600498 |
char buf[8]; |
|
1338 |
|||
1339 |
300249 |
convert64(val, buf); |
|
1340 |
300249 |
fwrite(buf, sizeof buf, 1, fp); |
|
1341 |
300249 |
} |
|
1342 |
|||
1343 |
static int |
||
1344 |
atcomp(const void *avp, const void *bvp) |
||
1345 |
{ |
||
1346 |
5077044 |
const zic_t a = ((const struct attype *) avp)->at; |
|
1347 |
2538522 |
const zic_t b = ((const struct attype *) bvp)->at; |
|
1348 |
|||
1349 |
✓✓ | 6886983 |
return (a < b) ? -1 : (a > b); |
1350 |
} |
||
1351 |
|||
1352 |
static int |
||
1353 |
is32(zic_t x) |
||
1354 |
{ |
||
1355 |
88458 |
return INT32_MIN <= x && x <= INT32_MAX; |
|
1356 |
} |
||
1357 |
|||
1358 |
static void |
||
1359 |
writezone(const char *name, const char *string) |
||
1360 |
{ |
||
1361 |
FILE *fp; |
||
1362 |
int i, j; |
||
1363 |
int leapcnt32, leapi32; |
||
1364 |
int timecnt32, timei32; |
||
1365 |
int pass; |
||
1366 |
static char *fullname; |
||
1367 |
static const struct tzhead tzh0; |
||
1368 |
static struct tzhead tzh; |
||
1369 |
6948 |
zic_t ats[TZ_MAX_TIMES]; |
|
1370 |
3474 |
unsigned char types[TZ_MAX_TIMES]; |
|
1371 |
size_t len; |
||
1372 |
|||
1373 |
/* |
||
1374 |
** Sort. |
||
1375 |
*/ |
||
1376 |
✓✓ | 3474 |
if (timecnt > 1) |
1377 |
2934 |
qsort(attypes, timecnt, sizeof *attypes, atcomp); |
|
1378 |
/* |
||
1379 |
** Optimize. |
||
1380 |
*/ |
||
1381 |
{ |
||
1382 |
int fromi; |
||
1383 |
int toi; |
||
1384 |
|||
1385 |
toi = 0; |
||
1386 |
fromi = 0; |
||
1387 |
✓✓✗✓ |
10125 |
while (fromi < timecnt && attypes[fromi].at < min_time) |
1388 |
++fromi; |
||
1389 |
✓✓ | 3474 |
if (isdsts[0] == 0) |
1390 |
✓✓✓✓ |
6534 |
while (fromi < timecnt && attypes[fromi].type == 0) |
1391 |
9 |
++fromi; /* handled by default rule */ |
|
1392 |
✓✓ | 547704 |
for ( ; fromi < timecnt; ++fromi) { |
1393 |
✓✓✓✓ |
1078929 |
if (toi != 0 && ((attypes[fromi].at + |
1394 |
537876 |
gmtoffs[attypes[toi - 1].type]) <= |
|
1395 |
✓✓ | 803835 |
(attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 : |
1396 |
265959 |
attypes[toi - 2].type]))) { |
|
1397 |
819 |
attypes[toi - 1].type = attypes[fromi].type; |
|
1398 |
819 |
continue; |
|
1399 |
} |
||
1400 |
✓✓✓✓ |
539415 |
if (toi == 0 || |
1401 |
268119 |
attypes[toi - 1].type != attypes[fromi].type) |
|
1402 |
268983 |
attypes[toi++] = attypes[fromi]; |
|
1403 |
} |
||
1404 |
3474 |
timecnt = toi; |
|
1405 |
} |
||
1406 |
/* |
||
1407 |
** Transfer. |
||
1408 |
*/ |
||
1409 |
✓✓ | 544914 |
for (i = 0; i < timecnt; ++i) { |
1410 |
268983 |
ats[i] = attypes[i].at; |
|
1411 |
268983 |
types[i] = attypes[i].type; |
|
1412 |
} |
||
1413 |
/* |
||
1414 |
** Correct for leap seconds. |
||
1415 |
*/ |
||
1416 |
✓✓ | 544914 |
for (i = 0; i < timecnt; ++i) { |
1417 |
268983 |
j = leapcnt; |
|
1418 |
✓✓ | 1389846 |
while (--j >= 0) |
1419 |
✓✓ | 924942 |
if (ats[i] > trans[j] - corr[j]) { |
1420 |
73062 |
ats[i] = tadd(ats[i], corr[j]); |
|
1421 |
73062 |
break; |
|
1422 |
} |
||
1423 |
} |
||
1424 |
/* |
||
1425 |
** Figure out 32-bit-limited starts and counts. |
||
1426 |
*/ |
||
1427 |
timecnt32 = timecnt; |
||
1428 |
timei32 = 0; |
||
1429 |
3474 |
leapcnt32 = leapcnt; |
|
1430 |
leapi32 = 0; |
||
1431 |
✓✓✓✓ |
112032 |
while (timecnt32 > 0 && !is32(ats[timecnt32 - 1])) |
1432 |
34002 |
--timecnt32; |
|
1433 |
✓✓✓✓ |
11817 |
while (timecnt32 > 0 && !is32(ats[timei32])) { |
1434 |
1755 |
--timecnt32; |
|
1435 |
1755 |
++timei32; |
|
1436 |
} |
||
1437 |
✓✓✗✓ |
4632 |
while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1])) |
1438 |
--leapcnt32; |
||
1439 |
✓✓✗✓ |
4632 |
while (leapcnt32 > 0 && !is32(trans[leapi32])) { |
1440 |
--leapcnt32; |
||
1441 |
++leapi32; |
||
1442 |
} |
||
1443 |
3474 |
len = strlen(directory) + 1 + strlen(name) + 1; |
|
1444 |
3474 |
fullname = erealloc(fullname, len); |
|
1445 |
3474 |
snprintf(fullname, len, "%s/%s", directory, name); |
|
1446 |
/* |
||
1447 |
** Remove old file, if any, to snap links. |
||
1448 |
*/ |
||
1449 |
✓✗✗✓ ✗✗ |
6948 |
if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) |
1450 |
err(1, "Can't remove %s", fullname); |
||
1451 |
✗✓ | 3474 |
if ((fp = fopen(fullname, "wb")) == NULL) { |
1452 |
if (mkdirs(fullname) != 0) |
||
1453 |
exit(EXIT_FAILURE); |
||
1454 |
if ((fp = fopen(fullname, "wb")) == NULL) |
||
1455 |
err(1, "Can't create %s", fullname); |
||
1456 |
} |
||
1457 |
✓✓ | 20844 |
for (pass = 1; pass <= 2; ++pass) { |
1458 |
int thistimei, thistimecnt; |
||
1459 |
int thisleapi, thisleapcnt; |
||
1460 |
int thistimelim, thisleaplim; |
||
1461 |
6948 |
int writetype[TZ_MAX_TIMES]; |
|
1462 |
6948 |
int typemap[TZ_MAX_TYPES]; |
|
1463 |
int thistypecnt; |
||
1464 |
6948 |
char thischars[TZ_MAX_CHARS]; |
|
1465 |
char thischarcnt; |
||
1466 |
6948 |
int indmap[TZ_MAX_CHARS]; |
|
1467 |
|||
1468 |
✓✓ | 6948 |
if (pass == 1) { |
1469 |
thistimei = timei32; |
||
1470 |
thistimecnt = timecnt32; |
||
1471 |
thisleapi = leapi32; |
||
1472 |
thisleapcnt = leapcnt32; |
||
1473 |
3474 |
} else { |
|
1474 |
thistimei = 0; |
||
1475 |
3474 |
thistimecnt = timecnt; |
|
1476 |
thisleapi = 0; |
||
1477 |
3474 |
thisleapcnt = leapcnt; |
|
1478 |
} |
||
1479 |
6948 |
thistimelim = thistimei + thistimecnt; |
|
1480 |
6948 |
thisleaplim = thisleapi + thisleapcnt; |
|
1481 |
✓✓ | 91350 |
for (i = 0; i < typecnt; ++i) |
1482 |
38727 |
writetype[i] = thistimecnt == timecnt; |
|
1483 |
✓✓ | 6948 |
if (thistimecnt == 0) { |
1484 |
/* |
||
1485 |
** No transition times fall in the current |
||
1486 |
** (32- or 64-bit) window. |
||
1487 |
*/ |
||
1488 |
✓✗ | 693 |
if (typecnt != 0) |
1489 |
693 |
writetype[typecnt - 1] = TRUE; |
|
1490 |
} else { |
||
1491 |
✓✓ | 1029438 |
for (i = thistimei - 1; i < thistimelim; ++i) |
1492 |
✓✓ | 508464 |
if (i >= 0) |
1493 |
503775 |
writetype[types[i]] = TRUE; |
|
1494 |
/* |
||
1495 |
** For America/Godthab and Antarctica/Palmer |
||
1496 |
*/ |
||
1497 |
✓✓ | 6255 |
if (thistimei == 0) |
1498 |
4689 |
writetype[0] = TRUE; |
|
1499 |
} |
||
1500 |
#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH |
||
1501 |
/* |
||
1502 |
** For some pre-2011 systems: if the last-to-be-written |
||
1503 |
** standard (or daylight) type has an offset different from the |
||
1504 |
** most recently used offset, |
||
1505 |
** append an (unused) copy of the most recently used type |
||
1506 |
** (to help get global "altzone" and "timezone" variables |
||
1507 |
** set correctly). |
||
1508 |
*/ |
||
1509 |
{ |
||
1510 |
int mrudst, mrustd, hidst, histd, type; |
||
1511 |
|||
1512 |
hidst = histd = mrudst = mrustd = -1; |
||
1513 |
✓✓ | 1018314 |
for (i = thistimei; i < thistimelim; ++i) |
1514 |
✓✓ | 502209 |
if (isdsts[types[i]]) |
1515 |
244881 |
mrudst = types[i]; |
|
1516 |
else |
||
1517 |
mrustd = types[i]; |
||
1518 |
✓✓ | 91350 |
for (i = 0; i < typecnt; ++i) |
1519 |
✓✓ | 38727 |
if (writetype[i]) { |
1520 |
✓✓ | 36855 |
if (isdsts[i]) |
1521 |
13581 |
hidst = i; |
|
1522 |
else |
||
1523 |
histd = i; |
||
1524 |
} |
||
1525 |
✓✓✓✓ ✓✓ |
13284 |
if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && |
1526 |
1242 |
gmtoffs[hidst] != gmtoffs[mrudst]) { |
|
1527 |
252 |
isdsts[mrudst] = -1; |
|
1528 |
504 |
type = addtype(gmtoffs[mrudst], |
|
1529 |
252 |
&chars[abbrinds[mrudst]], |
|
1530 |
252 |
TRUE, ttisstds[mrudst], |
|
1531 |
252 |
ttisgmts[mrudst]); |
|
1532 |
252 |
isdsts[mrudst] = TRUE; |
|
1533 |
252 |
writetype[type] = TRUE; |
|
1534 |
252 |
} |
|
1535 |
✓✓✓✓ ✓✓ |
14751 |
if (histd >= 0 && mrustd >= 0 && histd != mrustd && |
1536 |
1548 |
gmtoffs[histd] != gmtoffs[mrustd]) { |
|
1537 |
639 |
isdsts[mrustd] = -1; |
|
1538 |
1278 |
type = addtype(gmtoffs[mrustd], |
|
1539 |
639 |
&chars[abbrinds[mrustd]], |
|
1540 |
639 |
FALSE, ttisstds[mrustd], |
|
1541 |
639 |
ttisgmts[mrustd]); |
|
1542 |
639 |
isdsts[mrustd] = FALSE; |
|
1543 |
639 |
writetype[type] = TRUE; |
|
1544 |
639 |
} |
|
1545 |
} |
||
1546 |
#endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ |
||
1547 |
thistypecnt = 0; |
||
1548 |
✓✓ | 93132 |
for (i = 0; i < typecnt; ++i) |
1549 |
✓✓ | 116982 |
typemap[i] = writetype[i] ? thistypecnt++ : -1; |
1550 |
✓✓ | 708696 |
for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i) |
1551 |
347400 |
indmap[i] = -1; |
|
1552 |
thischarcnt = 0; |
||
1553 |
✓✓ | 93132 |
for (i = 0; i < typecnt; ++i) { |
1554 |
char *thisabbr; |
||
1555 |
|||
1556 |
✓✓ | 39618 |
if (!writetype[i]) |
1557 |
1872 |
continue; |
|
1558 |
✓✓ | 37746 |
if (indmap[abbrinds[i]] >= 0) |
1559 |
10890 |
continue; |
|
1560 |
26856 |
thisabbr = &chars[abbrinds[i]]; |
|
1561 |
✓✓ | 470232 |
for (j = 0; j < thischarcnt; ++j) |
1562 |
✓✓ | 208278 |
if (strcmp(&thischars[j], thisabbr) == 0) |
1563 |
break; |
||
1564 |
✓✓ | 26856 |
if (j == thischarcnt) { |
1565 |
53676 |
strlcpy(&thischars[(int) thischarcnt], |
|
1566 |
26838 |
thisabbr, sizeof(thischars) - thischarcnt); |
|
1567 |
26838 |
thischarcnt += strlen(thisabbr) + 1; |
|
1568 |
26838 |
} |
|
1569 |
26856 |
indmap[abbrinds[i]] = j; |
|
1570 |
26856 |
} |
|
1571 |
#define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp) |
||
1572 |
6948 |
tzh = tzh0; |
|
1573 |
6948 |
strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); |
|
1574 |
6948 |
tzh.tzh_version[0] = ZIC_VERSION; |
|
1575 |
6948 |
convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt); |
|
1576 |
6948 |
convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt); |
|
1577 |
6948 |
convert(eitol(thisleapcnt), tzh.tzh_leapcnt); |
|
1578 |
6948 |
convert(eitol(thistimecnt), tzh.tzh_timecnt); |
|
1579 |
6948 |
convert(eitol(thistypecnt), tzh.tzh_typecnt); |
|
1580 |
6948 |
convert(eitol(thischarcnt), tzh.tzh_charcnt); |
|
1581 |
6948 |
DO(tzh_magic); |
|
1582 |
6948 |
DO(tzh_version); |
|
1583 |
6948 |
DO(tzh_reserved); |
|
1584 |
6948 |
DO(tzh_ttisgmtcnt); |
|
1585 |
6948 |
DO(tzh_ttisstdcnt); |
|
1586 |
6948 |
DO(tzh_leapcnt); |
|
1587 |
6948 |
DO(tzh_timecnt); |
|
1588 |
6948 |
DO(tzh_typecnt); |
|
1589 |
6948 |
DO(tzh_charcnt); |
|
1590 |
#undef DO |
||
1591 |
✓✓ | 1018314 |
for (i = thistimei; i < thistimelim; ++i) |
1592 |
✓✓ | 502209 |
if (pass == 1) |
1593 |
233226 |
puttzcode((long) ats[i], fp); |
|
1594 |
else |
||
1595 |
268983 |
puttzcode64(ats[i], fp); |
|
1596 |
✓✓ | 1018314 |
for (i = thistimei; i < thistimelim; ++i) { |
1597 |
502209 |
unsigned char uc; |
|
1598 |
|||
1599 |
502209 |
uc = typemap[types[i]]; |
|
1600 |
502209 |
fwrite(&uc, sizeof uc, 1, fp); |
|
1601 |
502209 |
} |
|
1602 |
✓✓ | 93132 |
for (i = 0; i < typecnt; ++i) |
1603 |
✓✓ | 39618 |
if (writetype[i]) { |
1604 |
37746 |
puttzcode(gmtoffs[i], fp); |
|
1605 |
✓✗ | 75492 |
putc(isdsts[i], fp); |
1606 |
✓✗ | 75492 |
putc((unsigned char)indmap[abbrinds[i]], fp); |
1607 |
} |
||
1608 |
✓✗ | 6948 |
if (thischarcnt != 0) |
1609 |
6948 |
fwrite(thischars, sizeof thischars[0], thischarcnt, fp); |
|
1610 |
✓✓ | 138960 |
for (i = thisleapi; i < thisleaplim; ++i) { |
1611 |
zic_t todo; |
||
1612 |
|||
1613 |
✗✓ | 62532 |
if (roll[i]) { |
1614 |
if (timecnt == 0 || trans[i] < ats[0]) { |
||
1615 |
j = 0; |
||
1616 |
while (isdsts[j]) |
||
1617 |
if (++j >= typecnt) { |
||
1618 |
j = 0; |
||
1619 |
break; |
||
1620 |
} |
||
1621 |
} else { |
||
1622 |
j = 1; |
||
1623 |
while (j < timecnt && |
||
1624 |
trans[i] >= ats[j]) |
||
1625 |
++j; |
||
1626 |
j = types[j - 1]; |
||
1627 |
} |
||
1628 |
todo = tadd(trans[i], -gmtoffs[j]); |
||
1629 |
} else |
||
1630 |
62532 |
todo = trans[i]; |
|
1631 |
✓✓ | 62532 |
if (pass == 1) |
1632 |
31266 |
puttzcode((long) todo, fp); |
|
1633 |
else |
||
1634 |
31266 |
puttzcode64(todo, fp); |
|
1635 |
62532 |
puttzcode(corr[i], fp); |
|
1636 |
} |
||
1637 |
✓✓ | 93132 |
for (i = 0; i < typecnt; ++i) |
1638 |
✓✓ | 39618 |
if (writetype[i]) |
1639 |
✓✗ | 75492 |
putc(ttisstds[i], fp); |
1640 |
✓✓ | 93132 |
for (i = 0; i < typecnt; ++i) |
1641 |
✓✓ | 39618 |
if (writetype[i]) |
1642 |
✓✗ | 75492 |
putc(ttisgmts[i], fp); |
1643 |
6948 |
} |
|
1644 |
3474 |
fprintf(fp, "\n%s\n", string); |
|
1645 |
✓✗✓✗ ✗✗✗✓ |
10422 |
if (ferror(fp) || fclose(fp)) |
1646 |
errx(1, "Error writing %s", fullname); |
||
1647 |
3474 |
} |
|
1648 |
|||
1649 |
static void |
||
1650 |
doabbr(char *abbr, size_t size, const char *format, const char *letters, |
||
1651 |
int isdst, int doquotes) |
||
1652 |
{ |
||
1653 |
char *cp, *slashp; |
||
1654 |
int len; |
||
1655 |
|||
1656 |
846378 |
slashp = strchr(format, '/'); |
|
1657 |
✓✓ | 423189 |
if (slashp == NULL) { |
1658 |
✓✓ | 275217 |
if (letters == NULL) |
1659 |
11079 |
strlcpy(abbr, format, size); |
|
1660 |
else |
||
1661 |
264138 |
snprintf(abbr, size, format, letters); |
|
1662 |
✓✓ | 147972 |
} else if (isdst) { |
1663 |
76497 |
strlcpy(abbr, slashp + 1, size); |
|
1664 |
76497 |
} else { |
|
1665 |
✓✗ | 71475 |
if (slashp - format + 1 < size) |
1666 |
71475 |
size = slashp - format + 1; |
|
1667 |
71475 |
strlcpy(abbr, format, size); |
|
1668 |
} |
||
1669 |
✓✓ | 423189 |
if (!doquotes) |
1670 |
418428 |
return; |
|
1671 |
✓✓ | 28404 |
for (cp = abbr; *cp != '\0'; ++cp) |
1672 |
✓✓✓✓ |
13176 |
if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL && |
1673 |
1872 |
strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL) |
|
1674 |
break; |
||
1675 |
4761 |
len = strlen(abbr); |
|
1676 |
✓✗✓✓ |
9522 |
if (len > 0 && *cp == '\0') |
1677 |
2898 |
return; |
|
1678 |
1863 |
abbr[len + 2] = '\0'; |
|
1679 |
1863 |
abbr[len + 1] = '>'; |
|
1680 |
✓✓ | 15336 |
for ( ; len > 0; --len) |
1681 |
5805 |
abbr[len] = abbr[len - 1]; |
|
1682 |
1863 |
abbr[0] = '<'; |
|
1683 |
425052 |
} |
|
1684 |
|||
1685 |
static void |
||
1686 |
updateminmax(int x) |
||
1687 |
{ |
||
1688 |
✓✓ | 385008 |
if (min_year > x) |
1689 |
3978 |
min_year = x; |
|
1690 |
✓✓ | 192504 |
if (max_year < x) |
1691 |
9093 |
max_year = x; |
|
1692 |
192504 |
} |
|
1693 |
|||
1694 |
static int |
||
1695 |
stringoffset(char *result, size_t size, long offset) |
||
1696 |
{ |
||
1697 |
int hours, minutes, seconds; |
||
1698 |
char *ep; |
||
1699 |
|||
1700 |
8748 |
result[0] = '\0'; |
|
1701 |
✓✓ | 4374 |
if (offset < 0) { |
1702 |
1827 |
strlcpy(result, "-", size); |
|
1703 |
1827 |
offset = -offset; |
|
1704 |
1827 |
} |
|
1705 |
4374 |
seconds = offset % SECSPERMIN; |
|
1706 |
4374 |
offset /= SECSPERMIN; |
|
1707 |
4374 |
minutes = offset % MINSPERHOUR; |
|
1708 |
4374 |
offset /= MINSPERHOUR; |
|
1709 |
4374 |
hours = offset; |
|
1710 |
✓✓ | 4374 |
if (hours >= HOURSPERDAY) { |
1711 |
9 |
result[0] = '\0'; |
|
1712 |
9 |
return -1; |
|
1713 |
} |
||
1714 |
4365 |
ep = end(result, size); |
|
1715 |
4365 |
snprintf(ep, size - (ep - result), "%d", hours); |
|
1716 |
✓✓ | 4365 |
if (minutes != 0 || seconds != 0) { |
1717 |
162 |
ep = end(result, size); |
|
1718 |
162 |
snprintf(ep, size - (ep - result), ":%02d", minutes); |
|
1719 |
✗✓ | 162 |
if (seconds != 0) { |
1720 |
ep = end(result, size); |
||
1721 |
snprintf(ep, size - (ep - result), ":%02d", seconds); |
||
1722 |
} |
||
1723 |
} |
||
1724 |
4365 |
return 0; |
|
1725 |
4374 |
} |
|
1726 |
|||
1727 |
static int |
||
1728 |
stringrule(char *result, size_t size, const struct rule *rp, long dstoff, long gmtoff) |
||
1729 |
{ |
||
1730 |
long tod; |
||
1731 |
char *ep; |
||
1732 |
|||
1733 |
5058 |
ep = end(result, size); |
|
1734 |
2529 |
size -= ep - result; |
|
1735 |
result = ep; |
||
1736 |
✓✓ | 2529 |
if (rp->r_dycode == DC_DOM) { |
1737 |
int month, total; |
||
1738 |
|||
1739 |
✗✓✗✗ |
18 |
if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) |
1740 |
return -1; |
||
1741 |
total = 0; |
||
1742 |
✓✓ | 216 |
for (month = 0; month < rp->r_month; ++month) |
1743 |
90 |
total += len_months[0][month]; |
|
1744 |
18 |
snprintf(result, size, "J%d", total + rp->r_dayofmonth); |
|
1745 |
✓✗ | 18 |
} else { |
1746 |
int week; |
||
1747 |
|||
1748 |
✓✓ | 2511 |
if (rp->r_dycode == DC_DOWGEQ) { |
1749 |
✓✓ | 1458 |
if ((rp->r_dayofmonth % DAYSPERWEEK) != 1) |
1750 |
27 |
return -1; |
|
1751 |
1431 |
week = 1 + rp->r_dayofmonth / DAYSPERWEEK; |
|
1752 |
✓✗ | 2484 |
} else if (rp->r_dycode == DC_DOWLEQ) { |
1753 |
✓✗ | 1053 |
if (rp->r_dayofmonth == len_months[1][rp->r_month]) |
1754 |
1053 |
week = 5; |
|
1755 |
else { |
||
1756 |
if ((rp->r_dayofmonth % DAYSPERWEEK) != 0) |
||
1757 |
return -1; |
||
1758 |
week = rp->r_dayofmonth / DAYSPERWEEK; |
||
1759 |
} |
||
1760 |
} else |
||
1761 |
return -1; /* "cannot happen" */ |
||
1762 |
2484 |
snprintf(result, size, "M%d.%d.%d", |
|
1763 |
2484 |
rp->r_month + 1, week, rp->r_wday); |
|
1764 |
✓✓ | 2484 |
} |
1765 |
2502 |
tod = rp->r_tod; |
|
1766 |
✓✓ | 2502 |
if (rp->r_todisgmt) |
1767 |
801 |
tod += gmtoff; |
|
1768 |
✓✓✓✓ |
3501 |
if (rp->r_todisstd && rp->r_stdoff == 0) |
1769 |
495 |
tod += dstoff; |
|
1770 |
✓✓ | 2502 |
if (tod < 0) { |
1771 |
9 |
result[0] = '\0'; |
|
1772 |
9 |
return -1; |
|
1773 |
} |
||
1774 |
✓✓ | 2493 |
if (tod != 2 * SECSPERMIN * MINSPERHOUR) { |
1775 |
882 |
strlcat(result, "/", size); |
|
1776 |
882 |
ep = end(result, size); |
|
1777 |
✓✓ | 882 |
if (stringoffset(ep, size - (ep - result), tod) != 0) |
1778 |
9 |
return -1; |
|
1779 |
} |
||
1780 |
2484 |
return 0; |
|
1781 |
2529 |
} |
|
1782 |
|||
1783 |
static void |
||
1784 |
stringzone(char *result, size_t size, const struct zone *zpfirst, int zonecount) |
||
1785 |
{ |
||
1786 |
const struct zone *zp; |
||
1787 |
struct rule *rp, *stdrp, *dstrp; |
||
1788 |
int i; |
||
1789 |
const char *abbrvar; |
||
1790 |
char *ep; |
||
1791 |
|||
1792 |
6948 |
result[0] = '\0'; |
|
1793 |
3474 |
zp = zpfirst + zonecount - 1; |
|
1794 |
stdrp = dstrp = NULL; |
||
1795 |
✓✓ | 49554 |
for (i = 0; i < zp->z_nrules; ++i) { |
1796 |
21303 |
rp = &zp->z_rules[i]; |
|
1797 |
✓✓✓✓ |
35271 |
if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX) |
1798 |
continue; |
||
1799 |
✓✗ | 2574 |
if (rp->r_yrtype != NULL) |
1800 |
continue; |
||
1801 |
✓✓ | 2574 |
if (rp->r_stdoff == 0) { |
1802 |
✓✗ | 1287 |
if (stdrp == NULL) |
1803 |
stdrp = rp; |
||
1804 |
else |
||
1805 |
return; |
||
1806 |
1287 |
} else { |
|
1807 |
✓✗ | 1287 |
if (dstrp == NULL) |
1808 |
dstrp = rp; |
||
1809 |
else |
||
1810 |
return; |
||
1811 |
} |
||
1812 |
} |
||
1813 |
✓✓ | 3474 |
if (stdrp == NULL && dstrp == NULL) { |
1814 |
/* |
||
1815 |
** There are no rules running through "max". |
||
1816 |
** Let's find the latest rule. |
||
1817 |
*/ |
||
1818 |
✓✓ | 11880 |
for (i = 0; i < zp->z_nrules; ++i) { |
1819 |
3753 |
rp = &zp->z_rules[i]; |
|
1820 |
✓✓✓✓ ✓✓ |
7470 |
if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear || |
1821 |
✓✓ | 2862 |
(rp->r_hiyear == stdrp->r_hiyear && |
1822 |
351 |
rp->r_month > stdrp->r_month)) |
|
1823 |
1098 |
stdrp = rp; |
|
1824 |
} |
||
1825 |
✓✓✗✓ |
2574 |
if (stdrp != NULL && stdrp->r_stdoff != 0) |
1826 |
return; /* We end up in DST (a POSIX no-no). */ |
||
1827 |
/* |
||
1828 |
** Horrid special case: if year is 2037, |
||
1829 |
** presume this is a zone handled on a year-by-year basis; |
||
1830 |
** do not try to apply a rule to the zone. |
||
1831 |
*/ |
||
1832 |
✓✓✗✓ |
2574 |
if (stdrp != NULL && stdrp->r_hiyear == 2037) |
1833 |
return; |
||
1834 |
} |
||
1835 |
✓✓✓✗ ✗✓ |
7074 |
if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0)) |
1836 |
return; |
||
1837 |
✓✓ | 8622 |
abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; |
1838 |
3474 |
doabbr(result, size, zp->z_format, abbrvar, FALSE, TRUE); |
|
1839 |
3474 |
ep = end(result, size); |
|
1840 |
✗✓ | 3474 |
if (stringoffset(ep, size - (ep - result), -zp->z_gmtoff) != 0) { |
1841 |
result[0] = '\0'; |
||
1842 |
return; |
||
1843 |
} |
||
1844 |
✓✓ | 3474 |
if (dstrp == NULL) |
1845 |
2187 |
return; |
|
1846 |
1287 |
ep = end(result, size); |
|
1847 |
1287 |
doabbr(ep, size - (ep - result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE); |
|
1848 |
✓✓ | 1287 |
if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) { |
1849 |
18 |
ep = end(result, size); |
|
1850 |
✗✓ | 54 |
if (stringoffset(ep, size - (ep - result), |
1851 |
36 |
-(zp->z_gmtoff + dstrp->r_stdoff)) != 0) { |
|
1852 |
result[0] = '\0'; |
||
1853 |
return; |
||
1854 |
} |
||
1855 |
} |
||
1856 |
1287 |
strlcat(result, ",", size); |
|
1857 |
✓✓ | 1287 |
if (stringrule(result, size, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { |
1858 |
45 |
result[0] = '\0'; |
|
1859 |
45 |
return; |
|
1860 |
} |
||
1861 |
1242 |
strlcat(result, ",", size); |
|
1862 |
✗✓ | 1242 |
if (stringrule(result, size, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { |
1863 |
result[0] = '\0'; |
||
1864 |
return; |
||
1865 |
} |
||
1866 |
4716 |
} |
|
1867 |
|||
1868 |
static void |
||
1869 |
outzone(const struct zone *zpfirst, int zonecount) |
||
1870 |
{ |
||
1871 |
const struct zone *zp; |
||
1872 |
struct rule *rp; |
||
1873 |
int i, j, usestart, useuntil, type; |
||
1874 |
zic_t starttime = 0, untiltime = 0; |
||
1875 |
long gmtoff, stdoff, startoff; |
||
1876 |
int year, startttisstd = FALSE, startttisgmt = FALSE; |
||
1877 |
char *startbuf, *ab, *envvar; |
||
1878 |
int max_abbr_len, max_envvar_len; |
||
1879 |
int prodstic; /* all rules are min to max */ |
||
1880 |
|||
1881 |
6948 |
max_abbr_len = 2 + max_format_len + max_abbrvar_len; |
|
1882 |
3474 |
max_envvar_len = 2 * max_abbr_len + 5 * 9; |
|
1883 |
3474 |
startbuf = emalloc(max_abbr_len + 1); |
|
1884 |
3474 |
ab = emalloc(max_abbr_len + 1); |
|
1885 |
3474 |
envvar = emalloc(max_envvar_len + 1); |
|
1886 |
/* |
||
1887 |
** Now. . .finally. . .generate some useful data! |
||
1888 |
*/ |
||
1889 |
3474 |
timecnt = 0; |
|
1890 |
3474 |
typecnt = 0; |
|
1891 |
3474 |
charcnt = 0; |
|
1892 |
3474 |
prodstic = zonecount == 1; |
|
1893 |
/* |
||
1894 |
** Thanks to Earl Chew |
||
1895 |
** for noting the need to unconditionally initialize startttisstd. |
||
1896 |
*/ |
||
1897 |
3474 |
min_year = max_year = EPOCH_YEAR; |
|
1898 |
✓✓ | 3474 |
if (leapseen) { |
1899 |
1158 |
updateminmax(leapminyear); |
|
1900 |
1158 |
updateminmax(leapmaxyear + (leapmaxyear < INT_MAX)); |
|
1901 |
1158 |
} |
|
1902 |
✓✓ | 43416 |
for (i = 0; i < zonecount; ++i) { |
1903 |
18234 |
zp = &zpfirst[i]; |
|
1904 |
✓✓ | 18234 |
if (i < zonecount - 1) |
1905 |
14760 |
updateminmax(zp->z_untilrule.r_loyear); |
|
1906 |
✓✓ | 303246 |
for (j = 0; j < zp->z_nrules; ++j) { |
1907 |
133389 |
rp = &zp->z_rules[j]; |
|
1908 |
✓✗ | 133389 |
if (rp->r_lowasnum) |
1909 |
133389 |
updateminmax(rp->r_loyear); |
|
1910 |
✓✓ | 133389 |
if (rp->r_hiwasnum) |
1911 |
42039 |
updateminmax(rp->r_hiyear); |
|
1912 |
✗✓✗✗ |
133389 |
if (rp->r_lowasnum || rp->r_hiwasnum) |
1913 |
133389 |
prodstic = FALSE; |
|
1914 |
} |
||
1915 |
} |
||
1916 |
/* |
||
1917 |
** Generate lots of data if a rule can't cover all future times. |
||
1918 |
*/ |
||
1919 |
3474 |
stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount); |
|
1920 |
✗✓✗✗ |
3474 |
if (noise && envvar[0] == '\0') { |
1921 |
char * wp; |
||
1922 |
|||
1923 |
wp = ecpyalloc("no POSIX environment variable for zone"); |
||
1924 |
wp = ecatalloc(wp, " "); |
||
1925 |
wp = ecatalloc(wp, zpfirst->z_name); |
||
1926 |
warning(wp); |
||
1927 |
free(wp); |
||
1928 |
} |
||
1929 |
✓✓ | 3474 |
if (envvar[0] == '\0') { |
1930 |
90 |
if (min_year >= INT_MIN + YEARSPERREPEAT) |
|
1931 |
45 |
min_year -= YEARSPERREPEAT; |
|
1932 |
else |
||
1933 |
min_year = INT_MIN; |
||
1934 |
90 |
if (max_year <= INT_MAX - YEARSPERREPEAT) |
|
1935 |
45 |
max_year += YEARSPERREPEAT; |
|
1936 |
else |
||
1937 |
max_year = INT_MAX; |
||
1938 |
/* |
||
1939 |
** Regardless of any of the above, |
||
1940 |
** for a "proDSTic" zone which specifies that its rules |
||
1941 |
** always have and always will be in effect, |
||
1942 |
** we only need one cycle to define the zone. |
||
1943 |
*/ |
||
1944 |
✗✓ | 45 |
if (prodstic) { |
1945 |
min_year = 1900; |
||
1946 |
max_year = min_year + YEARSPERREPEAT; |
||
1947 |
} |
||
1948 |
} |
||
1949 |
/* |
||
1950 |
** For the benefit of older systems, |
||
1951 |
** generate data from 1900 through 2037. |
||
1952 |
*/ |
||
1953 |
✓✓ | 3474 |
if (min_year > 1900) |
1954 |
1980 |
min_year = 1900; |
|
1955 |
✓✓ | 3474 |
if (max_year < 2037) |
1956 |
3267 |
max_year = 2037; |
|
1957 |
✓✓ | 43416 |
for (i = 0; i < zonecount; ++i) { |
1958 |
/* |
||
1959 |
** A guess that may well be corrected later. |
||
1960 |
*/ |
||
1961 |
stdoff = 0; |
||
1962 |
18234 |
zp = &zpfirst[i]; |
|
1963 |
✓✓ | 51228 |
usestart = i > 0 && (zp - 1)->z_untiltime > min_time; |
1964 |
18234 |
useuntil = i < (zonecount - 1); |
|
1965 |
✓✓✓✗ |
32994 |
if (useuntil && zp->z_untiltime <= min_time) |
1966 |
continue; |
||
1967 |
18234 |
gmtoff = zp->z_gmtoff; |
|
1968 |
18234 |
eat(zp->z_filename, zp->z_linenum); |
|
1969 |
18234 |
*startbuf = '\0'; |
|
1970 |
18234 |
startoff = zp->z_gmtoff; |
|
1971 |
✓✓ | 18234 |
if (zp->z_nrules == 0) { |
1972 |
11088 |
stdoff = zp->z_stdoff; |
|
1973 |
22176 |
doabbr(startbuf, max_abbr_len + 1, zp->z_format, |
|
1974 |
11088 |
NULL, stdoff != 0, FALSE); |
|
1975 |
11088 |
type = addtype(oadd(zp->z_gmtoff, stdoff), |
|
1976 |
startbuf, stdoff != 0, startttisstd, |
||
1977 |
startttisgmt); |
||
1978 |
✓✓ | 11088 |
if (usestart) { |
1979 |
7686 |
addtt(starttime, type); |
|
1980 |
usestart = FALSE; |
||
1981 |
✗✓ | 11088 |
} else if (stdoff != 0) |
1982 |
addtt(min_time, type); |
||
1983 |
✓✓ | 1558206 |
} else for (year = min_year; year <= max_year; ++year) { |
1984 |
✓✓✓✓ |
1273545 |
if (useuntil && year > zp->z_untilrule.r_hiyear) |
1985 |
break; |
||
1986 |
/* |
||
1987 |
** Mark which rules to do in the current year. |
||
1988 |
** For those to do, calculate rpytime(rp, year); |
||
1989 |
*/ |
||
1990 |
✓✓ | 30372264 |
for (j = 0; j < zp->z_nrules; ++j) { |
1991 |
14414175 |
rp = &zp->z_rules[j]; |
|
1992 |
28828350 |
eats(zp->z_filename, zp->z_linenum, |
|
1993 |
14414175 |
rp->r_filename, rp->r_linenum); |
|
1994 |
✓✓ | 28828350 |
rp->r_todo = year >= rp->r_loyear && |
1995 |
✓✓ | 19494963 |
year <= rp->r_hiyear && |
1996 |
410850 |
yearistype(year, rp->r_yrtype); |
|
1997 |
✓✓ | 14414175 |
if (rp->r_todo) |
1998 |
410850 |
rp->r_temp = rpytime(rp, year); |
|
1999 |
} |
||
2000 |
for ( ; ; ) { |
||
2001 |
int k; |
||
2002 |
zic_t jtime, ktime = 0; |
||
2003 |
long offset; |
||
2004 |
|||
2005 |
✓✓ | 1177407 |
if (useuntil) { |
2006 |
/* |
||
2007 |
** Turn untiltime into UTC |
||
2008 |
** assuming the current gmtoff and |
||
2009 |
** stdoff values. |
||
2010 |
*/ |
||
2011 |
687600 |
untiltime = zp->z_untiltime; |
|
2012 |
✓✓ | 687600 |
if (!zp->z_untilrule.r_todisgmt) |
2013 |
672300 |
untiltime = tadd(untiltime, |
|
2014 |
672300 |
-gmtoff); |
|
2015 |
✓✓ | 687600 |
if (!zp->z_untilrule.r_todisstd) |
2016 |
486396 |
untiltime = tadd(untiltime, |
|
2017 |
486396 |
-stdoff); |
|
2018 |
} |
||
2019 |
/* |
||
2020 |
** Find the rule (of those to do, if any) |
||
2021 |
** that takes effect earliest in the year. |
||
2022 |
*/ |
||
2023 |
k = -1; |
||
2024 |
✓✓ | 48307050 |
for (j = 0; j < zp->z_nrules; ++j) { |
2025 |
22976118 |
rp = &zp->z_rules[j]; |
|
2026 |
✓✓ | 22976118 |
if (!rp->r_todo) |
2027 |
continue; |
||
2028 |
1237338 |
eats(zp->z_filename, zp->z_linenum, |
|
2029 |
618669 |
rp->r_filename, rp->r_linenum); |
|
2030 |
618669 |
offset = rp->r_todisgmt ? 0 : gmtoff; |
|
2031 |
✓✓ | 618669 |
if (!rp->r_todisstd) |
2032 |
362961 |
offset = oadd(offset, stdoff); |
|
2033 |
618669 |
jtime = rp->r_temp; |
|
2034 |
✓✗✓✗ |
1237338 |
if (jtime == min_time || |
2035 |
618669 |
jtime == max_time) |
|
2036 |
continue; |
||
2037 |
618669 |
jtime = tadd(jtime, -offset); |
|
2038 |
✓✓✓✓ |
828549 |
if (k < 0 || jtime < ktime) { |
2039 |
k = j; |
||
2040 |
ktime = jtime; |
||
2041 |
528309 |
} |
|
2042 |
} |
||
2043 |
✓✓ | 1177407 |
if (k < 0) |
2044 |
768618 |
break; /* go on to next year */ |
|
2045 |
408789 |
rp = &zp->z_rules[k]; |
|
2046 |
408789 |
rp->r_todo = FALSE; |
|
2047 |
✓✓✓✓ |
609084 |
if (useuntil && ktime >= untiltime) |
2048 |
3339 |
break; |
|
2049 |
405450 |
stdoff = rp->r_stdoff; |
|
2050 |
✓✓✓✓ |
773697 |
if (usestart && ktime == starttime) |
2051 |
684 |
usestart = FALSE; |
|
2052 |
✓✓ | 405450 |
if (usestart) { |
2053 |
✓✓ | 367563 |
if (ktime < starttime) { |
2054 |
147402 |
startoff = oadd(zp->z_gmtoff, |
|
2055 |
stdoff); |
||
2056 |
147402 |
doabbr(startbuf, |
|
2057 |
max_abbr_len + 1, |
||
2058 |
147402 |
zp->z_format, |
|
2059 |
147402 |
rp->r_abbrvar, |
|
2060 |
147402 |
rp->r_stdoff != 0, |
|
2061 |
FALSE); |
||
2062 |
147402 |
continue; |
|
2063 |
} |
||
2064 |
✓✓✓✓ |
223941 |
if (*startbuf == '\0' && |
2065 |
3780 |
startoff == oadd(zp->z_gmtoff, |
|
2066 |
stdoff)) { |
||
2067 |
1890 |
doabbr(startbuf, |
|
2068 |
max_abbr_len + 1, |
||
2069 |
1890 |
zp->z_format, |
|
2070 |
1890 |
rp->r_abbrvar, |
|
2071 |
1890 |
rp->r_stdoff != 0, |
|
2072 |
FALSE); |
||
2073 |
1890 |
} |
|
2074 |
} |
||
2075 |
516096 |
eats(zp->z_filename, zp->z_linenum, |
|
2076 |
258048 |
rp->r_filename, rp->r_linenum); |
|
2077 |
516096 |
doabbr(ab, max_abbr_len + 1, zp->z_format, |
|
2078 |
258048 |
rp->r_abbrvar, rp->r_stdoff != 0, FALSE); |
|
2079 |
258048 |
offset = oadd(zp->z_gmtoff, rp->r_stdoff); |
|
2080 |
516096 |
type = addtype(offset, ab, rp->r_stdoff != 0, |
|
2081 |
258048 |
rp->r_todisstd, rp->r_todisgmt); |
|
2082 |
258048 |
addtt(ktime, type); |
|
2083 |
✓✓ | 258048 |
} |
2084 |
} |
||
2085 |
✓✓ | 18234 |
if (usestart) { |
2086 |
✗✓✗✗ |
6390 |
if (*startbuf == '\0' && |
2087 |
zp->z_format != NULL && |
||
2088 |
strchr(zp->z_format, '%') == NULL && |
||
2089 |
strchr(zp->z_format, '/') == NULL) |
||
2090 |
strlcpy(startbuf, zp->z_format, max_abbr_len + 1); |
||
2091 |
6390 |
eat(zp->z_filename, zp->z_linenum); |
|
2092 |
✗✓ | 6390 |
if (*startbuf == '\0') |
2093 |
error("can't determine time zone abbreviation to use just after until time"); |
||
2094 |
else |
||
2095 |
6390 |
addtt(starttime, |
|
2096 |
6390 |
addtype(startoff, startbuf, |
|
2097 |
6390 |
startoff != zp->z_gmtoff, |
|
2098 |
startttisstd, startttisgmt)); |
||
2099 |
} |
||
2100 |
/* |
||
2101 |
** Now we may get to set starttime for the next zone line. |
||
2102 |
*/ |
||
2103 |
✓✓ | 18234 |
if (useuntil) { |
2104 |
14760 |
startttisstd = zp->z_untilrule.r_todisstd; |
|
2105 |
14760 |
startttisgmt = zp->z_untilrule.r_todisgmt; |
|
2106 |
14760 |
starttime = zp->z_untiltime; |
|
2107 |
✓✓ | 14760 |
if (!startttisstd) |
2108 |
12663 |
starttime = tadd(starttime, -stdoff); |
|
2109 |
✓✓ | 14760 |
if (!startttisgmt) |
2110 |
14526 |
starttime = tadd(starttime, -gmtoff); |
|
2111 |
} |
||
2112 |
} |
||
2113 |
3474 |
writezone(zpfirst->z_name, envvar); |
|
2114 |
3474 |
free(startbuf); |
|
2115 |
3474 |
free(ab); |
|
2116 |
3474 |
free(envvar); |
|
2117 |
3474 |
} |
|
2118 |
|||
2119 |
static void |
||
2120 |
addtt(const zic_t starttime, int type) |
||
2121 |
{ |
||
2122 |
size_t len; |
||
2123 |
|||
2124 |
✓✗✗✓ |
547182 |
if (starttime <= min_time || |
2125 |
✓✓ | 275058 |
(timecnt == 1 && attypes[0].at < min_time)) { |
2126 |
gmtoffs[0] = gmtoffs[type]; |
||
2127 |
isdsts[0] = isdsts[type]; |
||
2128 |
ttisstds[0] = ttisstds[type]; |
||
2129 |
ttisgmts[0] = ttisgmts[type]; |
||
2130 |
if (abbrinds[type] != 0) { |
||
2131 |
len = strlen(&chars[abbrinds[type]]) + 1; |
||
2132 |
memmove(chars, &chars[abbrinds[type]], len); |
||
2133 |
} |
||
2134 |
abbrinds[0] = 0; |
||
2135 |
charcnt = strlen(chars) + 1; |
||
2136 |
typecnt = 1; |
||
2137 |
timecnt = 0; |
||
2138 |
type = 0; |
||
2139 |
} |
||
2140 |
✗✓ | 272124 |
if (timecnt >= TZ_MAX_TIMES) { |
2141 |
error("too many transitions?!"); |
||
2142 |
exit(EXIT_FAILURE); |
||
2143 |
} |
||
2144 |
272124 |
attypes[timecnt].at = starttime; |
|
2145 |
272124 |
attypes[timecnt].type = type; |
|
2146 |
272124 |
++timecnt; |
|
2147 |
272124 |
} |
|
2148 |
|||
2149 |
static int |
||
2150 |
addtype(long gmtoff, const char *abbr, int isdst, int ttisstd, int ttisgmt) |
||
2151 |
{ |
||
2152 |
int i, j; |
||
2153 |
|||
2154 |
✗✓ | 552834 |
if (isdst != TRUE && isdst != FALSE) { |
2155 |
error("internal error - addtype called with bad isdst"); |
||
2156 |
exit(EXIT_FAILURE); |
||
2157 |
} |
||
2158 |
✗✓ | 276417 |
if (ttisstd != TRUE && ttisstd != FALSE) { |
2159 |
error("internal error - addtype called with bad ttisstd"); |
||
2160 |
exit(EXIT_FAILURE); |
||
2161 |
} |
||
2162 |
✗✓ | 276417 |
if (ttisgmt != TRUE && ttisgmt != FALSE) { |
2163 |
error("internal error - addtype called with bad ttisgmt"); |
||
2164 |
exit(EXIT_FAILURE); |
||
2165 |
} |
||
2166 |
/* |
||
2167 |
** See if there's already an entry for this zone type. |
||
2168 |
** If so, just return its index. |
||
2169 |
*/ |
||
2170 |
✓✓ | 2766342 |
for (i = 0; i < typecnt; ++i) { |
2171 |
✓✓✓✓ ✓✓ |
2113065 |
if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && |
2172 |
✓✓ | 395808 |
strcmp(abbr, &chars[abbrinds[i]]) == 0 && |
2173 |
✓✓ | 370140 |
ttisstd == ttisstds[i] && |
2174 |
283131 |
ttisgmt == ttisgmts[i]) |
|
2175 |
256608 |
return i; |
|
2176 |
} |
||
2177 |
/* |
||
2178 |
** There isn't one; add a new one, unless there are already too |
||
2179 |
** many. |
||
2180 |
*/ |
||
2181 |
✗✓ | 19809 |
if (typecnt >= TZ_MAX_TYPES) { |
2182 |
error("too many local time types"); |
||
2183 |
exit(EXIT_FAILURE); |
||
2184 |
} |
||
2185 |
✗✓ | 19809 |
if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { |
2186 |
error("UTC offset out of range"); |
||
2187 |
exit(EXIT_FAILURE); |
||
2188 |
} |
||
2189 |
19809 |
gmtoffs[i] = gmtoff; |
|
2190 |
19809 |
isdsts[i] = isdst; |
|
2191 |
19809 |
ttisstds[i] = ttisstd; |
|
2192 |
19809 |
ttisgmts[i] = ttisgmt; |
|
2193 |
|||
2194 |
✓✓ | 391446 |
for (j = 0; j < charcnt; ++j) |
2195 |
✓✓ | 181440 |
if (strcmp(&chars[j], abbr) == 0) |
2196 |
break; |
||
2197 |
✓✓ | 19809 |
if (j == charcnt) |
2198 |
14283 |
newabbr(abbr); |
|
2199 |
19809 |
abbrinds[i] = j; |
|
2200 |
19809 |
++typecnt; |
|
2201 |
19809 |
return i; |
|
2202 |
276417 |
} |
|
2203 |
|||
2204 |
static void |
||
2205 |
leapadd(zic_t t, int positive, int rolling, int count) |
||
2206 |
{ |
||
2207 |
int i, j; |
||
2208 |
|||
2209 |
✗✓ | 162 |
if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { |
2210 |
error("too many leap seconds"); |
||
2211 |
exit(EXIT_FAILURE); |
||
2212 |
} |
||
2213 |
✓✓ | 2268 |
for (i = 0; i < leapcnt; ++i) |
2214 |
✗✓ | 1053 |
if (t <= trans[i]) { |
2215 |
if (t == trans[i]) { |
||
2216 |
error("repeated leap second moment"); |
||
2217 |
exit(EXIT_FAILURE); |
||
2218 |
} |
||
2219 |
break; |
||
2220 |
} |
||
2221 |
do { |
||
2222 |
✗✓ | 162 |
for (j = leapcnt; j > i; --j) { |
2223 |
trans[j] = trans[j - 1]; |
||
2224 |
corr[j] = corr[j - 1]; |
||
2225 |
roll[j] = roll[j - 1]; |
||
2226 |
} |
||
2227 |
81 |
trans[i] = t; |
|
2228 |
✗✓ | 162 |
corr[i] = positive ? 1L : eitol(-count); |
2229 |
81 |
roll[i] = rolling; |
|
2230 |
81 |
++leapcnt; |
|
2231 |
✓✗✗✓ |
162 |
} while (positive && --count != 0); |
2232 |
81 |
} |
|
2233 |
|||
2234 |
static void |
||
2235 |
adjleap(void) |
||
2236 |
{ |
||
2237 |
int i; |
||
2238 |
long last = 0; |
||
2239 |
|||
2240 |
/* |
||
2241 |
** propagate leap seconds forward |
||
2242 |
*/ |
||
2243 |
✓✓ | 189 |
for (i = 0; i < leapcnt; ++i) { |
2244 |
81 |
trans[i] = tadd(trans[i], last); |
|
2245 |
81 |
last = corr[i] += last; |
|
2246 |
} |
||
2247 |
9 |
} |
|
2248 |
|||
2249 |
static int |
||
2250 |
yearistype(int year, const char *type) |
||
2251 |
{ |
||
2252 |
static char *buf; |
||
2253 |
int result; |
||
2254 |
size_t len; |
||
2255 |
|||
2256 |
✗✓✗✗ |
821700 |
if (type == NULL || *type == '\0') |
2257 |
410850 |
return TRUE; |
|
2258 |
len = 132 + strlen(yitcommand) + strlen(type); |
||
2259 |
buf = erealloc(buf, len); |
||
2260 |
snprintf(buf, len, "%s %d %s", yitcommand, year, type); |
||
2261 |
result = system(buf); |
||
2262 |
if (WIFEXITED(result)) |
||
2263 |
switch (WEXITSTATUS(result)) { |
||
2264 |
case 0: |
||
2265 |
return TRUE; |
||
2266 |
case 1: |
||
2267 |
return FALSE; |
||
2268 |
} |
||
2269 |
error("Wild result from command execution"); |
||
2270 |
errx(1, "command was '%s', result was %d", buf, result); |
||
2271 |
410850 |
} |
|
2272 |
|||
2273 |
/* this function is not strncasecmp */ |
||
2274 |
static int |
||
2275 |
itsabbr(const char *sabbr, const char *sword) |
||
2276 |
{ |
||
2277 |
const unsigned char *abbr = sabbr; |
||
2278 |
const unsigned char *word = sword; |
||
2279 |
|||
2280 |
✓✓ | 1383300 |
if (tolower(*abbr) != tolower(*word)) |
2281 |
606525 |
return FALSE; |
|
2282 |
✓✓ | 260772 |
while (*++abbr != '\0') |
2283 |
do { |
||
2284 |
474213 |
++word; |
|
2285 |
✓✓ | 474213 |
if (*word == '\0') |
2286 |
47550 |
return FALSE; |
|
2287 |
✓✓ | 426663 |
} while (tolower(*word) != tolower(*abbr)); |
2288 |
37575 |
return TRUE; |
|
2289 |
691650 |
} |
|
2290 |
|||
2291 |
static const struct lookup * |
||
2292 |
byword(const char *word, const struct lookup *table) |
||
2293 |
{ |
||
2294 |
const struct lookup *foundlp; |
||
2295 |
const struct lookup *lp; |
||
2296 |
|||
2297 |
✗✓ | 310068 |
if (word == NULL || table == NULL) |
2298 |
return NULL; |
||
2299 |
/* |
||
2300 |
** Look for exact match. |
||
2301 |
*/ |
||
2302 |
✓✓ | 1830474 |
for (lp = table; lp->l_word != NULL; ++lp) |
2303 |
✓✓ | 811161 |
if (strcasecmp(word, lp->l_word) == 0) |
2304 |
50958 |
return lp; |
|
2305 |
/* |
||
2306 |
** Look for inexact match. |
||
2307 |
*/ |
||
2308 |
foundlp = NULL; |
||
2309 |
✓✓ | 1591452 |
for (lp = table; lp->l_word != NULL; ++lp) |
2310 |
✓✓ | 691650 |
if (itsabbr(word, lp->l_word)) { |
2311 |
✓✗ | 37575 |
if (foundlp == NULL) |
2312 |
foundlp = lp; |
||
2313 |
else |
||
2314 |
return NULL; /* multiple inexact matches */ |
||
2315 |
37575 |
} |
|
2316 |
104076 |
return foundlp; |
|
2317 |
155034 |
} |
|
2318 |
|||
2319 |
static char ** |
||
2320 |
getfields(char *cp) |
||
2321 |
{ |
||
2322 |
char *dp; |
||
2323 |
char **array; |
||
2324 |
int nsubs; |
||
2325 |
|||
2326 |
✗✓ | 282798 |
if (cp == NULL) |
2327 |
return NULL; |
||
2328 |
141399 |
array = ereallocarray(NULL, strlen(cp) + 1, sizeof *array); |
|
2329 |
nsubs = 0; |
||
2330 |
422514 |
for ( ; ; ) { |
|
2331 |
✓✗✓✓ |
1945944 |
while (isascii((unsigned char)*cp) && |
2332 |
486486 |
isspace((unsigned char)*cp)) |
|
2333 |
63972 |
++cp; |
|
2334 |
✓✓✓✓ |
797793 |
if (*cp == '\0' || *cp == '#') |
2335 |
break; |
||
2336 |
281115 |
array[nsubs++] = dp = cp; |
|
2337 |
281115 |
do { |
|
2338 |
✓✗ | 1044738 |
if ((*dp = *cp++) != '"') { |
2339 |
1044738 |
++dp; |
|
2340 |
1044738 |
} else { |
|
2341 |
while ((*dp = *cp++) != '"') { |
||
2342 |
if (*dp != '\0') |
||
2343 |
++dp; |
||
2344 |
else { |
||
2345 |
error("Odd number of quotation marks"); |
||
2346 |
exit(EXIT_FAILURE); |
||
2347 |
} |
||
2348 |
} |
||
2349 |
} |
||
2350 |
✓✓✓✗ ✓✓ |
3063258 |
} while (*cp != '\0' && *cp != '#' && |
2351 |
✗✓ | 2018520 |
(!isascii((unsigned char)*cp) || !isspace((unsigned char)*cp))); |
2352 |
✓✗✓✓ |
562230 |
if (isascii((unsigned char)*cp) && isspace((unsigned char)*cp)) |
2353 |
245637 |
++cp; |
|
2354 |
281115 |
*dp = '\0'; |
|
2355 |
} |
||
2356 |
141399 |
array[nsubs] = NULL; |
|
2357 |
141399 |
return array; |
|
2358 |
141399 |
} |
|
2359 |
|||
2360 |
static long |
||
2361 |
oadd(long t1, long t2) |
||
2362 |
{ |
||
2363 |
49949520 |
long t = t1 + t2; |
|
2364 |
|||
2365 |
✓✓✓✗ ✓✓✗✓ |
74327844 |
if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { |
2366 |
error("time overflow"); |
||
2367 |
exit(EXIT_FAILURE); |
||
2368 |
} |
||
2369 |
24974760 |
return t; |
|
2370 |
} |
||
2371 |
|||
2372 |
static zic_t |
||
2373 |
tadd(zic_t t1, long t2) |
||
2374 |
{ |
||
2375 |
zic_t t; |
||
2376 |
|||
2377 |
✗✓ | 4606776 |
if (t1 == max_time && t2 > 0) |
2378 |
return max_time; |
||
2379 |
✗✓ | 2303388 |
if (t1 == min_time && t2 < 0) |
2380 |
return min_time; |
||
2381 |
2303388 |
t = t1 + t2; |
|
2382 |
✓✓✓✗ ✓✓✗✓ |
6241650 |
if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { |
2383 |
error("time overflow"); |
||
2384 |
exit(EXIT_FAILURE); |
||
2385 |
} |
||
2386 |
2303388 |
return t; |
|
2387 |
2303388 |
} |
|
2388 |
|||
2389 |
/* |
||
2390 |
** Given a rule, and a year, compute the date - in seconds since January 1, |
||
2391 |
** 1970, 00:00 LOCAL time - in that year that the rule refers to. |
||
2392 |
*/ |
||
2393 |
static zic_t |
||
2394 |
rpytime(const struct rule *rp, int wantedy) |
||
2395 |
{ |
||
2396 |
int y, m, i; |
||
2397 |
long dayoff; /* with a nod to Margaret O. */ |
||
2398 |
zic_t t; |
||
2399 |
|||
2400 |
✗✓ | 851220 |
if (wantedy == INT_MIN) |
2401 |
return min_time; |
||
2402 |
✗✓ | 425610 |
if (wantedy == INT_MAX) |
2403 |
return max_time; |
||
2404 |
dayoff = 0; |
||
2405 |
m = TM_JANUARY; |
||
2406 |
y = EPOCH_YEAR; |
||
2407 |
✓✓ | 41608458 |
while (wantedy != y) { |
2408 |
✓✓ | 20378619 |
if (wantedy > y) { |
2409 |
✓✓✓✓ |
37411893 |
i = len_years[isleap(y)]; |
2410 |
16553241 |
++y; |
|
2411 |
16553241 |
} else { |
|
2412 |
3825378 |
--y; |
|
2413 |
✓✓✓✓ |
8621991 |
i = -len_years[isleap(y)]; |
2414 |
} |
||
2415 |
20378619 |
dayoff = oadd(dayoff, eitol(i)); |
|
2416 |
} |
||
2417 |
✓✓ | 5216094 |
while (m != rp->r_month) { |
2418 |
✓✓✓✓ |
5390283 |
i = len_months[isleap(y)][m]; |
2419 |
2395242 |
dayoff = oadd(dayoff, eitol(i)); |
|
2420 |
2395242 |
++m; |
|
2421 |
} |
||
2422 |
425610 |
i = rp->r_dayofmonth; |
|
2423 |
✓✓✓✓ ✓✓✗✓ |
426285 |
if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { |
2424 |
✓✗ | 63 |
if (rp->r_dycode == DC_DOWLEQ) |
2425 |
63 |
--i; |
|
2426 |
else { |
||
2427 |
error("use of 2/29 in non leap-year"); |
||
2428 |
exit(EXIT_FAILURE); |
||
2429 |
} |
||
2430 |
63 |
} |
|
2431 |
425610 |
--i; |
|
2432 |
425610 |
dayoff = oadd(dayoff, eitol(i)); |
|
2433 |
✓✓✓✓ |
729489 |
if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { |
2434 |
long wday; |
||
2435 |
|||
2436 |
#define LDAYSPERWEEK ((long) DAYSPERWEEK) |
||
2437 |
316683 |
wday = eitol(EPOCH_WDAY); |
|
2438 |
/* |
||
2439 |
** Don't trust mod of negative numbers. |
||
2440 |
*/ |
||
2441 |
✓✓ | 316683 |
if (dayoff >= 0) |
2442 |
269622 |
wday = (wday + dayoff) % LDAYSPERWEEK; |
|
2443 |
else { |
||
2444 |
47061 |
wday -= ((-dayoff) % LDAYSPERWEEK); |
|
2445 |
✓✓ | 47061 |
if (wday < 0) |
2446 |
12492 |
wday += LDAYSPERWEEK; |
|
2447 |
} |
||
2448 |
✓✓ | 1238112 |
while (wday != eitol(rp->r_wday)) |
2449 |
✓✓ | 921429 |
if (rp->r_dycode == DC_DOWGEQ) { |
2450 |
352899 |
dayoff = oadd(dayoff, 1); |
|
2451 |
352899 |
if (++wday >= LDAYSPERWEEK) |
|
2452 |
wday = 0; |
||
2453 |
352899 |
++i; |
|
2454 |
352899 |
} else { |
|
2455 |
568530 |
dayoff = oadd(dayoff, -1); |
|
2456 |
568530 |
if (--wday < 0) |
|
2457 |
wday = LDAYSPERWEEK - 1; |
||
2458 |
568530 |
--i; |
|
2459 |
} |
||
2460 |
316683 |
} |
|
2461 |
✗✓ | 425610 |
if (dayoff < min_time / SECSPERDAY) |
2462 |
return min_time; |
||
2463 |
✗✓ | 425610 |
if (dayoff > max_time / SECSPERDAY) |
2464 |
return max_time; |
||
2465 |
425610 |
t = (zic_t) dayoff * SECSPERDAY; |
|
2466 |
425610 |
return tadd(t, rp->r_tod); |
|
2467 |
425610 |
} |
|
2468 |
|||
2469 |
static void |
||
2470 |
newabbr(const char *string) |
||
2471 |
{ |
||
2472 |
int i; |
||
2473 |
|||
2474 |
✓✗ | 28566 |
if (strcmp(string, GRANDPARENTED) != 0) { |
2475 |
const char * cp; |
||
2476 |
char * wp; |
||
2477 |
|||
2478 |
cp = string; |
||
2479 |
wp = NULL; |
||
2480 |
✓✗✓✓ |
136332 |
while (isascii((unsigned char)*cp) && |
2481 |
✓✓✓✓ |
95247 |
(isalnum((unsigned char)*cp) || *cp == '-' || *cp == '+')) |
2482 |
45396 |
++cp; |
|
2483 |
✗✓✗✗ |
14283 |
if (noise && cp - string > 3) |
2484 |
wp = "time zone abbreviation has more than 3 characters"; |
||
2485 |
✗✓ | 14283 |
if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) |
2486 |
wp = "time zone abbreviation has too many characters"; |
||
2487 |
✗✓ | 14283 |
if (*cp != '\0') |
2488 |
wp = "time zone abbreviation differs from POSIX standard"; |
||
2489 |
✗✓ | 14283 |
if (wp != NULL) { |
2490 |
wp = ecpyalloc(wp); |
||
2491 |
wp = ecatalloc(wp, " ("); |
||
2492 |
wp = ecatalloc(wp, string); |
||
2493 |
wp = ecatalloc(wp, ")"); |
||
2494 |
warning(wp); |
||
2495 |
free(wp); |
||
2496 |
} |
||
2497 |
14283 |
} |
|
2498 |
14283 |
i = strlen(string) + 1; |
|
2499 |
✗✓ | 14283 |
if (charcnt + i > TZ_MAX_CHARS) { |
2500 |
error("too many, or too long, time zone abbreviations"); |
||
2501 |
exit(EXIT_FAILURE); |
||
2502 |
} |
||
2503 |
14283 |
strlcpy(&chars[charcnt], string, sizeof(chars) - charcnt); |
|
2504 |
14283 |
charcnt += eitol(i); |
|
2505 |
14283 |
} |
|
2506 |
|||
2507 |
static int |
||
2508 |
mkdirs(char *argname) |
||
2509 |
{ |
||
2510 |
char * name; |
||
2511 |
char * cp; |
||
2512 |
|||
2513 |
if (argname == NULL || *argname == '\0') |
||
2514 |
return 0; |
||
2515 |
cp = name = ecpyalloc(argname); |
||
2516 |
while ((cp = strchr(cp + 1, '/')) != 0) { |
||
2517 |
*cp = '\0'; |
||
2518 |
if (!itsdir(name)) { |
||
2519 |
/* |
||
2520 |
** It doesn't seem to exist, so we try to create it. |
||
2521 |
** Creation may fail because of the directory being |
||
2522 |
** created by some other multiprocessor, so we get |
||
2523 |
** to do extra checking. |
||
2524 |
*/ |
||
2525 |
if (mkdir(name, MKDIR_UMASK) != 0) { |
||
2526 |
const char *e = strerror(errno); |
||
2527 |
|||
2528 |
if (errno != EEXIST || !itsdir(name)) { |
||
2529 |
fprintf(stderr, |
||
2530 |
"%s: Can't create directory %s: %s\n", |
||
2531 |
__progname, name, e); |
||
2532 |
free(name); |
||
2533 |
return -1; |
||
2534 |
} |
||
2535 |
} |
||
2536 |
} |
||
2537 |
*cp = '/'; |
||
2538 |
} |
||
2539 |
free(name); |
||
2540 |
return 0; |
||
2541 |
} |
||
2542 |
|||
2543 |
static long |
||
2544 |
eitol(int i) |
||
2545 |
{ |
||
2546 |
50444466 |
long l = i; |
|
2547 |
|||
2548 |
✓✗✓✗ ✗✓ |
75666699 |
if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) |
2549 |
errx(1, "%d did not sign extend correctly", i); |
||
2550 |
25222233 |
return l; |
|
2551 |
} |
Generated by: GCOVR (Version 3.3) |