Print this page
6869 Update zdump to better-handle POSIX timezones
Reviewed by: Jason King <jason.brian.king@gmail.com>
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/zic/zic.c
+++ new/usr/src/cmd/zic/zic.c
1 1 /*
2 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 3 * Use is subject to license terms.
4 4 */
5 -#pragma ident "%Z%%M% %I% %E% SMI"
6 5
7 -static char elsieid[] = "@(#)zic.c 7.128.1";
6 +static char elsieid[] = "@(#)zic.c 7.128.1";
8 7
9 8 /*
10 9 * #define LEAPSECOND_SUPPORT
11 10 */
12 11
13 12 /*
14 13 * Regardless of the type of time_t, we do our work using this type.
15 14 */
16 15
17 16 typedef int zic_t;
18 17
19 18 #include "private.h"
20 19 #include <tzfile.h> /* this is in system headers at Sun */
21 20
22 21 #include <sys/stat.h> /* for umask manifest constants */
23 22 #include <ctype.h>
24 23 #include <locale.h>
25 24 #include <stdlib.h> /* for getopt */
26 25
27 26 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
28 27 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
29 28 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
30 29
31 30 #ifdef S_IRUSR
32 31 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
33 32 #else
34 33 #define MKDIR_UMASK 0755
35 34 #endif
36 35
37 36 struct rule {
38 37 const char *r_filename;
39 38 int r_linenum;
40 39 const char *r_name;
41 40
42 41 int r_loyear; /* for example, 1986 */
43 42 int r_hiyear; /* for example, 1986 */
44 43 const char *r_yrtype;
45 44
46 45 int r_month; /* 0..11 */
47 46
48 47 int r_dycode; /* see below */
49 48 int r_dayofmonth;
50 49 int r_wday;
51 50
52 51 long r_tod; /* time from midnight */
53 52 int r_todisstd; /* above is standard time if TRUE */
54 53 /* or wall clock time if FALSE */
55 54 int r_todisgmt; /* above is GMT if TRUE */
56 55 /* or local time if FALSE */
57 56 long r_stdoff; /* offset from standard time */
58 57 const char *r_abbrvar; /* variable part of abbreviation */
59 58
60 59 int r_todo; /* a rule to do (used in outzone) */
61 60 zic_t r_temp; /* used in outzone */
62 61 };
63 62
64 63 /*
65 64 * r_dycode r_dayofmonth r_wday
66 65 */
67 66
68 67 #define DC_DOM 0 /* 1..31 */ /* unused */
69 68 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
70 69 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
71 70
72 71 struct zone {
73 72 const char *z_filename;
74 73 int z_linenum;
75 74
76 75 const char *z_name;
77 76 long z_gmtoff;
78 77 const char *z_rule;
79 78 const char *z_format;
80 79
81 80 long z_stdoff;
82 81
83 82 struct rule *z_rules;
84 83 int z_nrules;
85 84
86 85 struct rule z_untilrule;
87 86 zic_t z_untiltime;
88 87 };
89 88
90 89 static void addtt(zic_t starttime, int type);
91 90 static int addtype(long gmtoff, const char *abbr, int isdst,
92 91 int ttisstd, int ttisgmt);
93 92 #ifdef LEAPSECOND_SUPPORT
94 93 static void leapadd(zic_t t, int positive, int rolling, int count);
95 94 static void adjleap(void);
96 95 #endif
97 96 static void associate(void);
98 97 static int ciequal(const char *ap, const char *bp);
99 98 static void convert(long val, char *buf);
100 99 static void dolink(const char *fromfield, const char *tofield);
101 100 static void doabbr(char *abbr, const char *format,
102 101 const char *letters, int isdst);
103 102 static void eat(const char *name, int num);
104 103 static void eats(const char *name, int num,
105 104 const char *rname, int rnum);
106 105 static long eitol(int i);
107 106 static void error(const char *message);
108 107 static char **getfields(char *buf);
109 108 static long gethms(const char *string, const char *errstrng, int signable);
110 109 static void infile(const char *filename);
111 110 #ifdef LEAPSECOND_SUPPORT
112 111 static void inleap(char **fields, int nfields);
113 112 #endif
114 113 static void inlink(char **fields, int nfields);
115 114 static void inrule(char **fields, int nfields);
116 115 static int inzcont(char **fields, int nfields);
117 116 static int inzone(char **fields, int nfields);
118 117 static int inzsub(char **fields, int nfields, int iscont);
119 118 static int itsabbr(const char *abbr, const char *word);
120 119 static int itsdir(const char *name);
121 120 static int lowerit(int c);
122 121 static char *memcheck(char *tocheck);
123 122 static int mkdirs(char *filename);
124 123 static void newabbr(const char *abbr);
125 124 static long oadd(long t1, long t2);
126 125 static void outzone(const struct zone *zp, int ntzones);
127 126 static void puttzcode(long code, FILE *fp);
128 127 static int rcomp(const void *leftp, const void *rightp);
129 128 static zic_t rpytime(const struct rule *rp, int wantedy);
130 129 static void rulesub(struct rule *rp,
131 130 const char *loyearp, const char *hiyearp,
132 131 const char *typep, const char *monthp,
133 132 const char *dayp, const char *timep);
134 133 static void setboundaries(void);
135 134 static zic_t tadd(zic_t t1, long t2);
136 135 static void usage(void);
137 136 static void writezone(const char *name);
138 137 static int yearistype(int year, const char *type);
139 138
140 139 static int charcnt;
141 140 static int errors;
142 141 static const char *filename;
143 142 static int leapcnt;
144 143 static int linenum;
145 144 static zic_t max_time;
146 145 static int max_year;
147 146 static int max_year_representable;
148 147 static zic_t min_time;
149 148 static int min_year;
150 149 static int min_year_representable;
151 150 static int noise;
152 151 static const char *rfilename;
153 152 static int rlinenum;
154 153 static const char *progname;
155 154 static int timecnt;
156 155 static int typecnt;
157 156
158 157 /*
159 158 * Line codes.
160 159 */
161 160
162 161 #define LC_RULE 0
163 162 #define LC_ZONE 1
164 163 #define LC_LINK 2
165 164 #define LC_LEAP 3
166 165
167 166 /*
168 167 * Which fields are which on a Zone line.
169 168 */
170 169
171 170 #define ZF_NAME 1
172 171 #define ZF_GMTOFF 2
173 172 #define ZF_RULE 3
174 173 #define ZF_FORMAT 4
175 174 #define ZF_TILYEAR 5
176 175 #define ZF_TILMONTH 6
177 176 #define ZF_TILDAY 7
178 177 #define ZF_TILTIME 8
179 178 #define ZONE_MINFIELDS 5
180 179 #define ZONE_MAXFIELDS 9
181 180
182 181 /*
183 182 * Which fields are which on a Zone continuation line.
184 183 */
185 184
186 185 #define ZFC_GMTOFF 0
187 186 #define ZFC_RULE 1
188 187 #define ZFC_FORMAT 2
189 188 #define ZFC_TILYEAR 3
190 189 #define ZFC_TILMONTH 4
191 190 #define ZFC_TILDAY 5
192 191 #define ZFC_TILTIME 6
193 192 #define ZONEC_MINFIELDS 3
194 193 #define ZONEC_MAXFIELDS 7
195 194
196 195 /*
197 196 * Which files are which on a Rule line.
198 197 */
199 198
200 199 #define RF_NAME 1
201 200 #define RF_LOYEAR 2
202 201 #define RF_HIYEAR 3
203 202 #define RF_COMMAND 4
204 203 #define RF_MONTH 5
205 204 #define RF_DAY 6
206 205 #define RF_TOD 7
207 206 #define RF_STDOFF 8
208 207 #define RF_ABBRVAR 9
209 208 #define RULE_FIELDS 10
210 209
211 210 /*
212 211 * Which fields are which on a Link line.
213 212 */
214 213
215 214 #define LF_FROM 1
216 215 #define LF_TO 2
217 216 #define LINK_FIELDS 3
218 217
219 218 /*
220 219 * Which fields are which on a Leap line.
221 220 */
222 221
223 222 #define LP_YEAR 1
224 223 #define LP_MONTH 2
225 224 #define LP_DAY 3
226 225 #define LP_TIME 4
227 226 #define LP_CORR 5
228 227 #define LP_ROLL 6
229 228 #define LEAP_FIELDS 7
230 229
231 230 /*
232 231 * Year synonyms.
233 232 */
234 233
235 234 #define YR_MINIMUM 0
236 235 #define YR_MAXIMUM 1
237 236 #define YR_ONLY 2
238 237
239 238 static struct rule *rules;
240 239 static int nrules; /* number of rules */
241 240
242 241 static struct zone *zones;
243 242 static int nzones; /* number of zones */
244 243
245 244 struct link {
246 245 const char *l_filename;
247 246 int l_linenum;
248 247 const char *l_from;
249 248 const char *l_to;
250 249 };
251 250
252 251 static struct link *links;
253 252 static int nlinks;
254 253
255 254 struct lookup {
256 255 const char *l_word;
257 256 const int l_value;
258 257 };
259 258
260 259 static struct lookup const *byword(const char *string,
261 260 const struct lookup *lp);
262 261
263 262 static struct lookup const line_codes[] = {
264 263 { "Rule", LC_RULE },
265 264 { "Zone", LC_ZONE },
266 265 { "Link", LC_LINK },
267 266 { "Leap", LC_LEAP },
268 267 { NULL, 0}
269 268 };
270 269
271 270 static struct lookup const mon_names[] = {
272 271 { "January", TM_JANUARY },
273 272 { "February", TM_FEBRUARY },
274 273 { "March", TM_MARCH },
275 274 { "April", TM_APRIL },
276 275 { "May", TM_MAY },
277 276 { "June", TM_JUNE },
278 277 { "July", TM_JULY },
279 278 { "August", TM_AUGUST },
280 279 { "September", TM_SEPTEMBER },
281 280 { "October", TM_OCTOBER },
282 281 { "November", TM_NOVEMBER },
283 282 { "December", TM_DECEMBER },
284 283 { NULL, 0 }
285 284 };
286 285
287 286 static struct lookup const wday_names[] = {
288 287 { "Sunday", TM_SUNDAY },
289 288 { "Monday", TM_MONDAY },
290 289 { "Tuesday", TM_TUESDAY },
291 290 { "Wednesday", TM_WEDNESDAY },
292 291 { "Thursday", TM_THURSDAY },
293 292 { "Friday", TM_FRIDAY },
294 293 { "Saturday", TM_SATURDAY },
295 294 { NULL, 0 }
296 295 };
297 296
298 297 static struct lookup const lasts[] = {
299 298 { "last-Sunday", TM_SUNDAY },
300 299 { "last-Monday", TM_MONDAY },
301 300 { "last-Tuesday", TM_TUESDAY },
302 301 { "last-Wednesday", TM_WEDNESDAY },
303 302 { "last-Thursday", TM_THURSDAY },
304 303 { "last-Friday", TM_FRIDAY },
305 304 { "last-Saturday", TM_SATURDAY },
306 305 { NULL, 0 }
307 306 };
308 307
309 308 static struct lookup const begin_years[] = {
310 309 { "minimum", YR_MINIMUM },
311 310 { "maximum", YR_MAXIMUM },
312 311 { NULL, 0 }
313 312 };
314 313
315 314 static struct lookup const end_years[] = {
316 315 { "minimum", YR_MINIMUM },
317 316 { "maximum", YR_MAXIMUM },
318 317 { "only", YR_ONLY },
319 318 { NULL, 0 }
320 319 };
321 320
322 321 static struct lookup const leap_types[] = {
323 322 { "Rolling", TRUE },
324 323 { "Stationary", FALSE },
325 324 { NULL, 0 }
326 325 };
327 326
328 327 static const int len_months[2][MONSPERYEAR] = {
329 328 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
330 329 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
331 330 };
332 331
333 332 static const int len_years[2] = {
334 333 DAYSPERNYEAR, DAYSPERLYEAR
335 334 };
336 335
337 336 static struct attype {
338 337 zic_t at;
339 338 unsigned char type;
340 339 } attypes[TZ_MAX_TIMES];
341 340 static long gmtoffs[TZ_MAX_TYPES];
342 341 static char isdsts[TZ_MAX_TYPES];
343 342 static unsigned char abbrinds[TZ_MAX_TYPES];
344 343 static char ttisstds[TZ_MAX_TYPES];
345 344 static char ttisgmts[TZ_MAX_TYPES];
346 345 static char chars[TZ_MAX_CHARS];
347 346 static zic_t trans[TZ_MAX_LEAPS];
348 347 static long corr[TZ_MAX_LEAPS];
349 348 static char roll[TZ_MAX_LEAPS];
350 349
351 350 /*
352 351 * Memory allocation.
353 352 */
354 353
355 354 static char *
356 355 memcheck(ptr)
357 356 char * const ptr;
358 357 {
359 358 if (ptr == NULL) {
360 359 const char *e = strerror(errno);
361 360 (void) fprintf(stderr, gettext("%s: Memory exhausted: %s\n"),
362 361 progname, e);
363 362 exit(EXIT_FAILURE);
364 363 }
365 364 return (ptr);
366 365 }
367 366
368 367 #define emalloc(size) memcheck(imalloc(size))
369 368 #define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
370 369 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
371 370 #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
372 371
373 372 /*
374 373 * Error handling.
375 374 */
376 375
377 376 static void
378 377 eats(name, num, rname, rnum)
379 378 const char * const name;
380 379 const int num;
381 380 const char * const rname;
382 381 const int rnum;
383 382 {
384 383 filename = name;
385 384 linenum = num;
386 385 rfilename = rname;
387 386 rlinenum = rnum;
388 387 }
389 388
390 389 static void
391 390 eat(name, num)
392 391 const char * const name;
393 392 const int num;
394 393 {
395 394 eats(name, num, (char *)NULL, -1);
396 395 }
397 396
398 397 static void
399 398 error(string)
400 399 const char * const string;
401 400 {
402 401 /*
403 402 * Match the format of "cc" to allow sh users to
404 403 * zic ... 2>&1 | error -t "*" -v
405 404 * on BSD systems.
406 405 */
407 406 (void) fprintf(stderr, gettext("\"%s\", line %d: %s"),
408 407 filename, linenum, string);
409 408 if (rfilename != NULL)
410 409 (void) fprintf(stderr, gettext(" (rule from \"%s\", line %d)"),
411 410 rfilename, rlinenum);
412 411 (void) fprintf(stderr, "\n");
413 412 ++errors;
414 413 }
415 414
416 415 static void
417 416 warning(string)
418 417 const char * const string;
419 418 {
420 419 char *cp;
421 420
422 421 cp = ecpyalloc(gettext("warning: "));
423 422 cp = ecatalloc(cp, string);
424 423 error(cp);
425 424 ifree(cp);
426 425 --errors;
427 426 }
428 427
429 428 static void
430 429 usage(void)
431 430 {
432 431 #ifdef LEAPSECOND_SUPPORT
433 432 (void) fprintf(stderr, gettext("%s: usage is %s "
434 433 "[ --version ] [ -s ] [ -v ] [ -l localtime ] "
435 434 "\n\t[ -p posixrules ] [ -d directory ] [ -L leapseconds ] "
436 435 "[ -y yearistype ] [ filename ... ]\n"), progname, progname);
437 436 #else /* ! LEAPSECOND_SUPPORT */
438 437 (void) fprintf(stderr, gettext("%s: usage is %s "
439 438 "[ --version ] [ -s ] [ -v ] [ -l localtime ]"
440 439 "\n\t[ -p posixrules ] [ -d directory ] [ -y yearistype ] "
441 440 "[ filename ... ]\n"), progname, progname);
442 441 #endif /* LEAPSECOND_SUPPORT */
443 442 }
444 443
445 444 static const char *psxrules;
446 445 static const char *lcltime;
447 446 static const char *directory;
448 447 static const char *leapsec;
449 448 static const char *yitcommand;
450 449 static int sflag = FALSE;
451 450
452 451 int
453 452 main(argc, argv)
454 453 int argc;
455 454 char *argv[];
456 455 {
457 456 register int i;
458 457 register int j;
459 458 register int c;
460 459
461 460 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
462 461
463 462 (void) setlocale(LC_ALL, "");
464 463 #if !defined(TEXT_DOMAIN)
465 464 #define TEXT_DOMAIN "SYS_TEST"
466 465 #endif
467 466 (void) textdomain(TEXT_DOMAIN);
468 467
469 468 progname = argv[0];
470 469 for (i = 1; i < argc; ++i)
471 470 if (strcmp(argv[i], "--version") == 0) {
472 471 (void) printf("%s\n", elsieid);
473 472 exit(EXIT_SUCCESS);
474 473 }
475 474
476 475 #ifdef LEAPSECOND_SUPPORT
477 476 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF)
478 477 #else
479 478 while ((c = getopt(argc, argv, "d:l:p:vsy:")) != EOF)
480 479 #endif
481 480 switch (c) {
482 481 default:
483 482 usage();
484 483 case 'd':
485 484 if (directory == NULL)
486 485 directory = optarg;
487 486 else {
488 487 (void) fprintf(stderr, gettext(
489 488 "%s: More than one -d option specified\n"),
490 489 progname);
491 490 exit(EXIT_FAILURE);
492 491 }
493 492 break;
494 493 case 'l':
495 494 if (lcltime == NULL)
496 495 lcltime = optarg;
497 496 else {
498 497 (void) fprintf(stderr, gettext(
499 498 "%s: More than one -l option specified\n"),
500 499 progname);
501 500 exit(EXIT_FAILURE);
502 501 }
503 502 break;
504 503 case 'p':
505 504 if (psxrules == NULL)
506 505 psxrules = optarg;
507 506 else {
508 507 (void) fprintf(stderr, gettext(
509 508 "%s: More than one -p option specified\n"),
510 509 progname);
511 510 exit(EXIT_FAILURE);
512 511 }
513 512 break;
514 513 case 'y':
515 514 if (yitcommand == NULL)
516 515 yitcommand = optarg;
517 516 else {
518 517 (void) fprintf(stderr, gettext(
519 518 "%s: More than one -y option specified\n"),
520 519 progname);
521 520 exit(EXIT_FAILURE);
522 521 }
523 522 break;
524 523 #ifdef LEAPSECOND_SUPPORT
525 524 case 'L':
526 525 if (leapsec == NULL)
527 526 leapsec = optarg;
528 527 else {
529 528 (void) fprintf(stderr, gettext(
530 529 "%s: More than one -L option specified\n"),
531 530 progname);
532 531 exit(EXIT_FAILURE);
533 532 }
534 533 break;
535 534 #endif /* LEAPSECOND_SUPPORT */
536 535 case 'v':
537 536 noise = TRUE;
538 537 break;
539 538 case 's':
540 539 sflag = TRUE;
541 540 break;
542 541 }
543 542 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
544 543 usage(); /* usage message by request */
545 544 if (directory == NULL)
546 545 directory = TZDIR;
547 546 if (yitcommand == NULL)
548 547 yitcommand = "yearistype";
549 548
550 549 setboundaries();
551 550
552 551 #ifdef LEAPSECOND_SUPPORT
553 552 if (optind < argc && leapsec != NULL) {
554 553 infile(leapsec);
555 554 adjleap();
556 555 }
557 556 #endif /* LEAPSECOND_SUPPORT */
558 557
559 558 for (i = optind; i < argc; ++i)
560 559 infile(argv[i]);
561 560 if (errors)
562 561 exit(EXIT_FAILURE);
563 562 associate();
564 563 for (i = 0; i < nzones; i = j) {
565 564 /*
566 565 * Find the next non-continuation zone entry.
567 566 */
568 567 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
569 568 continue;
570 569 outzone(&zones[i], j - i);
571 570 }
572 571 /*
573 572 * Make links.
574 573 */
575 574 for (i = 0; i < nlinks; ++i) {
576 575 eat(links[i].l_filename, links[i].l_linenum);
577 576 dolink(links[i].l_from, links[i].l_to);
578 577 if (noise)
579 578 for (j = 0; j < nlinks; ++j)
580 579 if (strcmp(links[i].l_to, links[j].l_from) == 0)
581 580 warning(gettext("link to link"));
582 581 }
583 582 if (lcltime != NULL) {
584 583 eat("command line", 1);
585 584 dolink(lcltime, TZDEFAULT);
586 585 }
587 586 if (psxrules != NULL) {
588 587 eat("command line", 1);
589 588 dolink(psxrules, TZDEFRULES);
590 589 }
591 590 return ((errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
592 591 }
593 592
594 593 static void
595 594 dolink(fromfield, tofield)
596 595 const char * const fromfield;
597 596 const char * const tofield;
598 597 {
599 598 register char *fromname;
600 599 register char *toname;
601 600
602 601 if (fromfield[0] == '/')
603 602 fromname = ecpyalloc(fromfield);
604 603 else {
605 604 fromname = ecpyalloc(directory);
606 605 fromname = ecatalloc(fromname, "/");
607 606 fromname = ecatalloc(fromname, fromfield);
608 607 }
609 608 if (tofield[0] == '/')
610 609 toname = ecpyalloc(tofield);
611 610 else {
612 611 toname = ecpyalloc(directory);
613 612 toname = ecatalloc(toname, "/");
614 613 toname = ecatalloc(toname, tofield);
615 614 }
616 615 /*
617 616 * We get to be careful here since
618 617 * there's a fair chance of root running us.
619 618 */
620 619 if (!itsdir(toname))
621 620 (void) remove(toname);
622 621 if (link(fromname, toname) != 0) {
623 622 int result;
624 623
625 624 if (mkdirs(toname) != 0)
626 625 exit(EXIT_FAILURE);
627 626
628 627 result = link(fromname, toname);
629 628
630 629 if (result != 0 && access(fromname, F_OK) == 0 &&
631 630 !itsdir(fromname)) {
632 631 const char *s = tofield;
633 632 register char *symlinkcontents = NULL;
634 633
635 634 while ((s = strchr(s+1, '/')) != NULL)
636 635 symlinkcontents = ecatalloc(symlinkcontents,
637 636 "../");
638 637 symlinkcontents = ecatalloc(symlinkcontents, fromname);
639 638 result = symlink(symlinkcontents, toname);
640 639 if (result == 0)
641 640 warning(gettext(
642 641 "hard link failed, symbolic link used"));
643 642 ifree(symlinkcontents);
644 643 }
645 644
646 645 if (result != 0) {
647 646 const char *e = strerror(errno);
648 647
649 648 (void) fprintf(stderr, gettext(
650 649 "%s: Can't link from %s to %s: %s\n"),
651 650 progname, fromname, toname, e);
652 651 exit(EXIT_FAILURE);
653 652 }
654 653 }
655 654 ifree(fromname);
656 655 ifree(toname);
657 656 }
658 657
659 658 #ifndef INT_MAX
660 659 #define INT_MAX ((int)(((unsigned)~0)>>1))
661 660 #endif /* !defined INT_MAX */
662 661
663 662 #ifndef INT_MIN
664 663 #define INT_MIN ((int)~(((unsigned)~0)>>1))
665 664 #endif /* !defined INT_MIN */
666 665
667 666 /*
668 667 * The tz file format currently allows at most 32-bit quantities.
669 668 * This restriction should be removed before signed 32-bit values
670 669 * wrap around in 2038, but unfortunately this will require a
671 670 * change to the tz file format.
672 671 */
673 672
674 673 #define MAX_BITS_IN_FILE 32
675 674 /* CSTYLED */
676 675 #define TIME_T_BITS_IN_FILE ((TYPE_BIT(zic_t) < MAX_BITS_IN_FILE) ? \
677 676 TYPE_BIT(zic_t): MAX_BITS_IN_FILE)
678 677
679 678 static void
680 679 setboundaries(void)
681 680 {
682 681 register int i;
683 682
684 683 if (TYPE_SIGNED(zic_t)) {
685 684 min_time = -1;
686 685 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
687 686 min_time *= 2;
688 687 max_time = -(min_time + 1);
689 688 if (sflag)
690 689 min_time = 0;
691 690 } else {
692 691 min_time = 0;
693 692 max_time = 2 - sflag;
694 693 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
695 694 max_time *= 2;
696 695 --max_time;
697 696 }
698 697 {
699 698 time_t t;
700 699
701 700 t = (time_t)min_time;
702 701 min_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
703 702 t = (time_t)max_time;
704 703 max_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
705 704 }
706 705 min_year_representable = min_year;
707 706 max_year_representable = max_year;
708 707 }
709 708
710 709 static int
711 710 itsdir(name)
712 711 const char * const name;
713 712 {
714 713 register char *myname;
715 714 register int accres;
716 715
717 716 myname = ecpyalloc(name);
718 717 myname = ecatalloc(myname, "/.");
719 718 accres = access(myname, F_OK);
720 719 ifree(myname);
721 720 return (accres == 0);
722 721 }
723 722
724 723 /*
725 724 * Associate sets of rules with zones.
726 725 */
727 726
728 727 /*
729 728 * Sort by rule name.
730 729 */
731 730
732 731 static int
733 732 rcomp(cp1, cp2)
734 733 const void * cp1;
735 734 const void * cp2;
736 735 {
737 736 return (strcmp(((const struct rule *) cp1)->r_name,
738 737 ((const struct rule *) cp2)->r_name));
739 738 }
740 739
741 740 static void
742 741 associate(void)
743 742 {
744 743 register struct zone *zp;
745 744 register struct rule *rp;
746 745 register int base, out;
747 746 register int i, j;
748 747
749 748 if (nrules != 0) {
750 749 (void) qsort((void *)rules, (size_t)nrules,
751 750 (size_t)sizeof (*rules), rcomp);
752 751 for (i = 0; i < nrules - 1; ++i) {
753 752 if (strcmp(rules[i].r_name,
754 753 rules[i + 1].r_name) != 0)
755 754 continue;
756 755 if (strcmp(rules[i].r_filename,
757 756 rules[i + 1].r_filename) == 0)
758 757 continue;
759 758 eat(rules[i].r_filename, rules[i].r_linenum);
760 759 warning(gettext("same rule name in multiple files"));
761 760 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
762 761 warning(gettext("same rule name in multiple files"));
763 762 for (j = i + 2; j < nrules; ++j) {
764 763 if (strcmp(rules[i].r_name,
765 764 rules[j].r_name) != 0)
766 765 break;
767 766 if (strcmp(rules[i].r_filename,
768 767 rules[j].r_filename) == 0)
769 768 continue;
770 769 if (strcmp(rules[i + 1].r_filename,
771 770 rules[j].r_filename) == 0)
772 771 continue;
773 772 break;
774 773 }
775 774 i = j - 1;
776 775 }
777 776 }
778 777 for (i = 0; i < nzones; ++i) {
779 778 zp = &zones[i];
780 779 zp->z_rules = NULL;
781 780 zp->z_nrules = 0;
782 781 }
783 782 for (base = 0; base < nrules; base = out) {
784 783 rp = &rules[base];
785 784 for (out = base + 1; out < nrules; ++out)
786 785 if (strcmp(rp->r_name, rules[out].r_name) != 0)
787 786 break;
788 787 for (i = 0; i < nzones; ++i) {
789 788 zp = &zones[i];
790 789 if (strcmp(zp->z_rule, rp->r_name) != 0)
791 790 continue;
792 791 zp->z_rules = rp;
793 792 zp->z_nrules = out - base;
794 793 }
795 794 }
796 795 for (i = 0; i < nzones; ++i) {
797 796 zp = &zones[i];
798 797 if (zp->z_nrules == 0) {
799 798 /*
800 799 * Maybe we have a local standard time offset.
801 800 */
802 801 eat(zp->z_filename, zp->z_linenum);
803 802 zp->z_stdoff = gethms(zp->z_rule,
804 803 gettext("unruly zone"), TRUE);
805 804 /*
806 805 * Note, though, that if there's no rule,
807 806 * a '%s' in the format is a bad thing.
808 807 */
809 808 if (strchr(zp->z_format, '%') != 0)
810 809 error(gettext("%s in ruleless zone"));
811 810 }
812 811 }
813 812 if (errors)
814 813 exit(EXIT_FAILURE);
815 814 }
816 815
817 816 static void
818 817 infile(name)
819 818 const char *name;
820 819 {
821 820 register FILE *fp;
822 821 register char **fields;
823 822 register char *cp;
824 823 register const struct lookup *lp;
825 824 register int nfields;
826 825 register int wantcont;
827 826 register int num;
828 827 char buf[BUFSIZ];
829 828
830 829 if (strcmp(name, "-") == 0) {
831 830 name = gettext("standard input");
832 831 fp = stdin;
833 832 } else if ((fp = fopen(name, "r")) == NULL) {
834 833 const char *e = strerror(errno);
835 834
836 835 (void) fprintf(stderr, gettext("%s: Can't open %s: %s\n"),
837 836 progname, name, e);
838 837 exit(EXIT_FAILURE);
839 838 }
840 839 wantcont = FALSE;
841 840 for (num = 1; ; ++num) {
842 841 eat(name, num);
843 842 if (fgets(buf, (int)sizeof (buf), fp) != buf)
844 843 break;
845 844 cp = strchr(buf, '\n');
846 845 if (cp == NULL) {
847 846 error(gettext("line too long"));
848 847 exit(EXIT_FAILURE);
849 848 }
850 849 *cp = '\0';
851 850 fields = getfields(buf);
852 851 nfields = 0;
853 852 while (fields[nfields] != NULL) {
854 853 static char nada;
855 854
856 855 if (strcmp(fields[nfields], "-") == 0)
857 856 fields[nfields] = &nada;
858 857 ++nfields;
859 858 }
860 859 if (nfields == 0) {
861 860 /* nothing to do */
862 861 } else if (wantcont) {
863 862 wantcont = inzcont(fields, nfields);
864 863 } else {
865 864 lp = byword(fields[0], line_codes);
866 865 if (lp == NULL)
867 866 error(gettext("input line of unknown type"));
868 867 else switch ((int)(lp->l_value)) {
869 868 case LC_RULE:
870 869 inrule(fields, nfields);
871 870 wantcont = FALSE;
872 871 break;
873 872 case LC_ZONE:
874 873 wantcont = inzone(fields, nfields);
875 874 break;
876 875 case LC_LINK:
877 876 inlink(fields, nfields);
878 877 wantcont = FALSE;
879 878 break;
880 879 #ifdef LEAPSECOND_SUPPORT
881 880 case LC_LEAP:
882 881 if (name != leapsec)
883 882 (void) fprintf(stderr, gettext(
884 883 "%s: Leap line in non leap seconds file %s\n"),
885 884 progname, name);
886 885 else inleap(fields, nfields);
887 886 wantcont = FALSE;
888 887 break;
889 888 #endif /* LEAPSECOND_SUPPORT */
890 889 default: /* "cannot happen" */
891 890 (void) fprintf(stderr, gettext(
892 891 "%s: panic: Invalid l_value %d\n"),
893 892 progname, lp->l_value);
894 893 exit(EXIT_FAILURE);
895 894 }
896 895 }
897 896 ifree((char *)fields);
898 897 }
899 898 if (ferror(fp)) {
900 899 (void) fprintf(stderr, gettext("%s: Error reading %s\n"),
901 900 progname, filename);
902 901 exit(EXIT_FAILURE);
903 902 }
904 903 if (fp != stdin && fclose(fp)) {
905 904 const char *e = strerror(errno);
906 905 (void) fprintf(stderr, gettext("%s: Error closing %s: %s\n"),
907 906 progname, filename, e);
908 907 exit(EXIT_FAILURE);
909 908 }
910 909 if (wantcont)
911 910 error(gettext("expected continuation line not found"));
912 911 }
913 912
914 913 /*
915 914 * Convert a string of one of the forms
916 915 * h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
917 916 * into a number of seconds.
918 917 * A null string maps to zero.
919 918 * Call error with errstring and return zero on errors.
920 919 */
921 920
922 921 static long
923 922 gethms(string, errstring, signable)
924 923 const char *string;
925 924 const char * const errstring;
926 925 const int signable;
927 926 {
928 927 long hh;
929 928 int mm, ss, sign;
930 929
931 930 if (string == NULL || *string == '\0')
932 931 return (0);
933 932 if (!signable)
934 933 sign = 1;
935 934 else if (*string == '-') {
936 935 sign = -1;
937 936 ++string;
938 937 } else sign = 1;
939 938 if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
940 939 mm = ss = 0;
941 940 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
942 941 ss = 0;
943 942 else if (sscanf(string, scheck(string, "%ld:%d:%d"),
944 943 &hh, &mm, &ss) != 3) {
945 944 error(errstring);
946 945 return (0);
947 946 }
948 947 if (hh < 0 ||
949 948 mm < 0 || mm >= MINSPERHOUR ||
950 949 ss < 0 || ss > SECSPERMIN) {
951 950 error(errstring);
952 951 return (0);
953 952 }
954 953 if (LONG_MAX / SECSPERHOUR < hh) {
955 954 error(gettext("time overflow"));
956 955 return (0);
957 956 }
958 957 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
959 958 warning(
960 959 gettext("24:00 not handled by pre-1998 versions of zic"));
961 960 if (noise && (hh > HOURSPERDAY ||
962 961 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
963 962 warning(gettext("values over 24 hours not handled by "
964 963 "pre-2007 versions of zic"));
965 964
966 965 return (oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
967 966 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))));
968 967 }
969 968
970 969 static void
971 970 inrule(fields, nfields)
972 971 register char ** const fields;
973 972 const int nfields;
974 973 {
975 974 static struct rule r;
976 975
977 976 if (nfields != RULE_FIELDS) {
978 977 error(gettext("wrong number of fields on Rule line"));
979 978 return;
980 979 }
981 980 if (*fields[RF_NAME] == '\0') {
982 981 error(gettext("nameless rule"));
983 982 return;
984 983 }
985 984 r.r_filename = filename;
986 985 r.r_linenum = linenum;
987 986 r.r_stdoff = gethms(fields[RF_STDOFF], gettext("invalid saved time"),
988 987 TRUE);
989 988 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
990 989 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
991 990 r.r_name = ecpyalloc(fields[RF_NAME]);
992 991 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
993 992 rules = (struct rule *)(void *)erealloc((char *)rules,
994 993 (int)((nrules + 1) * sizeof (*rules)));
995 994 rules[nrules++] = r;
996 995 }
997 996
998 997 static int
999 998 inzone(fields, nfields)
1000 999 register char ** const fields;
1001 1000 const int nfields;
1002 1001 {
1003 1002 register int i;
1004 1003 static char *buf;
1005 1004
1006 1005 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1007 1006 error(gettext("wrong number of fields on Zone line"));
1008 1007 return (FALSE);
1009 1008 }
1010 1009 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1011 1010 buf = erealloc(buf, (int)(132 + strlen(TZDEFAULT)));
1012 1011 (void) sprintf(buf,
1013 1012 gettext("\"Zone %s\" line and -l option are mutually exclusive"),
1014 1013 TZDEFAULT);
1015 1014 error(buf);
1016 1015 return (FALSE);
1017 1016 }
1018 1017 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1019 1018 buf = erealloc(buf, (int)(132 + strlen(TZDEFRULES)));
1020 1019 (void) sprintf(buf,
1021 1020 gettext("\"Zone %s\" line and -p option are mutually exclusive"),
1022 1021 TZDEFRULES);
1023 1022 error(buf);
1024 1023 return (FALSE);
1025 1024 }
1026 1025 for (i = 0; i < nzones; ++i)
1027 1026 if (zones[i].z_name != NULL &&
1028 1027 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1029 1028 buf = erealloc(buf, (int)(132 +
1030 1029 strlen(fields[ZF_NAME]) +
1031 1030 strlen(zones[i].z_filename)));
1032 1031 (void) sprintf(buf,
1033 1032 gettext("duplicate zone name %s (file \"%s\", line %d)"),
1034 1033 fields[ZF_NAME],
1035 1034 zones[i].z_filename,
1036 1035 zones[i].z_linenum);
1037 1036 error(buf);
1038 1037 return (FALSE);
1039 1038 }
1040 1039 return (inzsub(fields, nfields, FALSE));
1041 1040 }
1042 1041
1043 1042 static int
1044 1043 inzcont(fields, nfields)
1045 1044 register char ** const fields;
1046 1045 const int nfields;
1047 1046 {
1048 1047 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1049 1048 error(gettext(
1050 1049 "wrong number of fields on Zone continuation line"));
1051 1050 return (FALSE);
1052 1051 }
1053 1052 return (inzsub(fields, nfields, TRUE));
1054 1053 }
1055 1054
1056 1055 static int
1057 1056 inzsub(fields, nfields, iscont)
1058 1057 register char ** const fields;
1059 1058 const int nfields;
1060 1059 const int iscont;
1061 1060 {
1062 1061 register char *cp;
1063 1062 static struct zone z;
1064 1063 register int i_gmtoff, i_rule, i_format;
1065 1064 register int i_untilyear, i_untilmonth;
1066 1065 register int i_untilday, i_untiltime;
1067 1066 register int hasuntil;
1068 1067
1069 1068 if (iscont) {
1070 1069 i_gmtoff = ZFC_GMTOFF;
1071 1070 i_rule = ZFC_RULE;
1072 1071 i_format = ZFC_FORMAT;
1073 1072 i_untilyear = ZFC_TILYEAR;
1074 1073 i_untilmonth = ZFC_TILMONTH;
1075 1074 i_untilday = ZFC_TILDAY;
1076 1075 i_untiltime = ZFC_TILTIME;
1077 1076 z.z_name = NULL;
1078 1077 } else {
1079 1078 i_gmtoff = ZF_GMTOFF;
1080 1079 i_rule = ZF_RULE;
1081 1080 i_format = ZF_FORMAT;
1082 1081 i_untilyear = ZF_TILYEAR;
1083 1082 i_untilmonth = ZF_TILMONTH;
1084 1083 i_untilday = ZF_TILDAY;
1085 1084 i_untiltime = ZF_TILTIME;
1086 1085 z.z_name = ecpyalloc(fields[ZF_NAME]);
1087 1086 }
1088 1087 z.z_filename = filename;
1089 1088 z.z_linenum = linenum;
1090 1089 z.z_gmtoff = gethms(fields[i_gmtoff], gettext("invalid UTC offset"),
1091 1090 TRUE);
1092 1091 if ((cp = strchr(fields[i_format], '%')) != 0) {
1093 1092 if (*++cp != 's' || strchr(cp, '%') != 0) {
1094 1093 error(gettext("invalid abbreviation format"));
1095 1094 return (FALSE);
1096 1095 }
1097 1096 }
1098 1097 z.z_rule = ecpyalloc(fields[i_rule]);
1099 1098 z.z_format = ecpyalloc(fields[i_format]);
1100 1099 hasuntil = nfields > i_untilyear;
1101 1100 if (hasuntil) {
1102 1101 z.z_untilrule.r_filename = filename;
1103 1102 z.z_untilrule.r_linenum = linenum;
1104 1103 rulesub(&z.z_untilrule,
1105 1104 fields[i_untilyear],
1106 1105 "only",
1107 1106 "",
1108 1107 (nfields > i_untilmonth) ?
1109 1108 fields[i_untilmonth] : "Jan",
1110 1109 (nfields > i_untilday) ? fields[i_untilday] : "1",
1111 1110 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1112 1111 z.z_untiltime = rpytime(&z.z_untilrule,
1113 1112 z.z_untilrule.r_loyear);
1114 1113 if (iscont && nzones > 0 &&
1115 1114 z.z_untiltime > min_time &&
1116 1115 z.z_untiltime < max_time &&
1117 1116 zones[nzones - 1].z_untiltime > min_time &&
1118 1117 zones[nzones - 1].z_untiltime < max_time &&
1119 1118 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1120 1119 error(gettext(
1121 1120 "Zone continuation line end time is not after end time of previous line"));
1122 1121 return (FALSE);
1123 1122 }
1124 1123 }
1125 1124 zones = (struct zone *)(void *)erealloc((char *)zones,
1126 1125 (int)((nzones + 1) * sizeof (*zones)));
1127 1126 zones[nzones++] = z;
1128 1127 /*
1129 1128 * If there was an UNTIL field on this line,
1130 1129 * there's more information about the zone on the next line.
1131 1130 */
1132 1131 return (hasuntil);
1133 1132 }
1134 1133
1135 1134 #ifdef LEAPSECOND_SUPPORT
1136 1135 static void
1137 1136 inleap(fields, nfields)
1138 1137 register char ** const fields;
1139 1138 const int nfields;
1140 1139 {
1141 1140 register const char *cp;
1142 1141 register const struct lookup *lp;
1143 1142 register int i, j;
1144 1143 int year, month, day;
1145 1144 long dayoff, tod;
1146 1145 zic_t t;
1147 1146
1148 1147 if (nfields != LEAP_FIELDS) {
1149 1148 error(gettext("wrong number of fields on Leap line"));
1150 1149 return;
1151 1150 }
1152 1151 dayoff = 0;
1153 1152 cp = fields[LP_YEAR];
1154 1153 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1155 1154 /*
1156 1155 * Leapin' Lizards!
1157 1156 */
1158 1157 error(gettext("invalid leaping year"));
1159 1158 return;
1160 1159 }
1161 1160 j = EPOCH_YEAR;
1162 1161 while (j != year) {
1163 1162 if (year > j) {
1164 1163 i = len_years[isleap(j)];
1165 1164 ++j;
1166 1165 } else {
1167 1166 --j;
1168 1167 i = -len_years[isleap(j)];
1169 1168 }
1170 1169 dayoff = oadd(dayoff, eitol(i));
1171 1170 }
1172 1171 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1173 1172 error(gettext("invalid month name"));
1174 1173 return;
1175 1174 }
1176 1175 month = lp->l_value;
1177 1176 j = TM_JANUARY;
1178 1177 while (j != month) {
1179 1178 i = len_months[isleap(year)][j];
1180 1179 dayoff = oadd(dayoff, eitol(i));
1181 1180 ++j;
1182 1181 }
1183 1182 cp = fields[LP_DAY];
1184 1183 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1185 1184 day <= 0 || day > len_months[isleap(year)][month]) {
1186 1185 error(gettext("invalid day of month"));
1187 1186 return;
1188 1187 }
1189 1188 dayoff = oadd(dayoff, eitol(day - 1));
1190 1189 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1191 1190 error(gettext("time before zero"));
1192 1191 return;
1193 1192 }
1194 1193 if (dayoff < min_time / SECSPERDAY) {
1195 1194 error(gettext("time too small"));
1196 1195 return;
1197 1196 }
1198 1197 if (dayoff > max_time / SECSPERDAY) {
1199 1198 error(gettext("time too large"));
1200 1199 return;
1201 1200 }
1202 1201 t = (zic_t)dayoff * SECSPERDAY;
1203 1202 tod = gethms(fields[LP_TIME], gettext("invalid time of day"), FALSE);
1204 1203 cp = fields[LP_CORR];
1205 1204 {
1206 1205 register int positive;
1207 1206 int count;
1208 1207
1209 1208 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1210 1209 positive = FALSE;
1211 1210 count = 1;
1212 1211 } else if (strcmp(cp, "--") == 0) {
1213 1212 positive = FALSE;
1214 1213 count = 2;
1215 1214 } else if (strcmp(cp, "+") == 0) {
1216 1215 positive = TRUE;
1217 1216 count = 1;
1218 1217 } else if (strcmp(cp, "++") == 0) {
1219 1218 positive = TRUE;
1220 1219 count = 2;
1221 1220 } else {
1222 1221 error(gettext("illegal CORRECTION field on Leap line"));
1223 1222 return;
1224 1223 }
1225 1224 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1226 1225 error(gettext(
1227 1226 "illegal Rolling/Stationary field on Leap line"));
1228 1227 return;
1229 1228 }
1230 1229 leapadd(tadd(t, tod), positive, lp->l_value, count);
1231 1230 }
1232 1231 }
1233 1232 #endif /* LEAPSECOND_SUPPORT */
1234 1233
1235 1234 static void
1236 1235 inlink(fields, nfields)
1237 1236 register char ** const fields;
1238 1237 const int nfields;
1239 1238 {
1240 1239 struct link l;
1241 1240
1242 1241 if (nfields != LINK_FIELDS) {
1243 1242 error(gettext("wrong number of fields on Link line"));
1244 1243 return;
1245 1244 }
1246 1245 if (*fields[LF_FROM] == '\0') {
1247 1246 error(gettext("blank FROM field on Link line"));
1248 1247 return;
1249 1248 }
1250 1249 if (*fields[LF_TO] == '\0') {
1251 1250 error(gettext("blank TO field on Link line"));
1252 1251 return;
1253 1252 }
1254 1253 l.l_filename = filename;
1255 1254 l.l_linenum = linenum;
1256 1255 l.l_from = ecpyalloc(fields[LF_FROM]);
1257 1256 l.l_to = ecpyalloc(fields[LF_TO]);
1258 1257 links = (struct link *)(void *)erealloc((char *)links,
1259 1258 (int)((nlinks + 1) * sizeof (*links)));
1260 1259 links[nlinks++] = l;
1261 1260 }
1262 1261
1263 1262 static void
1264 1263 rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1265 1264 register struct rule * const rp;
1266 1265 const char * const loyearp;
1267 1266 const char * const hiyearp;
1268 1267 const char * const typep;
1269 1268 const char * const monthp;
1270 1269 const char * const dayp;
1271 1270 const char * const timep;
1272 1271 {
1273 1272 register const struct lookup *lp;
1274 1273 register const char *cp;
1275 1274 register char *dp;
1276 1275 register char *ep;
1277 1276
1278 1277 if ((lp = byword(monthp, mon_names)) == NULL) {
1279 1278 error(gettext("invalid month name"));
1280 1279 return;
1281 1280 }
1282 1281 rp->r_month = lp->l_value;
1283 1282 rp->r_todisstd = FALSE;
1284 1283 rp->r_todisgmt = FALSE;
1285 1284 dp = ecpyalloc(timep);
1286 1285 if (*dp != '\0') {
1287 1286 ep = dp + strlen(dp) - 1;
1288 1287 switch (lowerit(*ep)) {
1289 1288 case 's': /* Standard */
1290 1289 rp->r_todisstd = TRUE;
1291 1290 rp->r_todisgmt = FALSE;
1292 1291 *ep = '\0';
1293 1292 break;
1294 1293 case 'w': /* Wall */
1295 1294 rp->r_todisstd = FALSE;
1296 1295 rp->r_todisgmt = FALSE;
1297 1296 *ep = '\0';
1298 1297 break;
1299 1298 case 'g': /* Greenwich */
1300 1299 case 'u': /* Universal */
1301 1300 case 'z': /* Zulu */
1302 1301 rp->r_todisstd = TRUE;
1303 1302 rp->r_todisgmt = TRUE;
1304 1303 *ep = '\0';
1305 1304 break;
1306 1305 }
1307 1306 }
1308 1307 rp->r_tod = gethms(dp, gettext("invalid time of day"), FALSE);
1309 1308 ifree(dp);
1310 1309 /*
1311 1310 * Year work.
1312 1311 */
1313 1312 cp = loyearp;
1314 1313 lp = byword(cp, begin_years);
1315 1314 if (lp != NULL) {
1316 1315 switch ((int)lp->l_value) {
1317 1316 case YR_MINIMUM:
1318 1317 rp->r_loyear = INT_MIN;
1319 1318 break;
1320 1319 case YR_MAXIMUM:
1321 1320 rp->r_loyear = INT_MAX;
1322 1321 break;
1323 1322 default: /* "cannot happen" */
1324 1323 (void) fprintf(stderr,
1325 1324 gettext("%s: panic: Invalid l_value %d\n"),
1326 1325 progname, lp->l_value);
1327 1326 exit(EXIT_FAILURE);
1328 1327 }
1329 1328 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1330 1329 error(gettext("invalid starting year"));
1331 1330 return;
1332 1331 } else if (noise) {
1333 1332 if (rp->r_loyear < min_year_representable)
1334 1333 warning(gettext(
1335 1334 "starting year too low to be represented"));
1336 1335 else if (rp->r_loyear > max_year_representable)
1337 1336 warning(gettext(
1338 1337 "starting year too high to be represented"));
1339 1338 }
1340 1339 cp = hiyearp;
1341 1340 if ((lp = byword(cp, end_years)) != NULL) {
1342 1341 switch ((int)lp->l_value) {
1343 1342 case YR_MINIMUM:
1344 1343 rp->r_hiyear = INT_MIN;
1345 1344 break;
1346 1345 case YR_MAXIMUM:
1347 1346 rp->r_hiyear = INT_MAX;
1348 1347 break;
1349 1348 case YR_ONLY:
1350 1349 rp->r_hiyear = rp->r_loyear;
1351 1350 break;
1352 1351 default: /* "cannot happen" */
1353 1352 (void) fprintf(stderr,
1354 1353 gettext("%s: panic: Invalid l_value %d\n"),
1355 1354 progname, lp->l_value);
1356 1355 exit(EXIT_FAILURE);
1357 1356 }
1358 1357 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1359 1358 error(gettext("invalid ending year"));
1360 1359 return;
1361 1360 } else if (noise) {
1362 1361 if (rp->r_loyear < min_year_representable)
1363 1362 warning(gettext(
1364 1363 "ending year too low to be represented"));
1365 1364 else if (rp->r_loyear > max_year_representable)
1366 1365 warning(gettext(
1367 1366 "ending year too high to be represented"));
1368 1367 }
1369 1368 if (rp->r_loyear > rp->r_hiyear) {
1370 1369 error(gettext("starting year greater than ending year"));
1371 1370 return;
1372 1371 }
1373 1372 if (*typep == '\0')
1374 1373 rp->r_yrtype = NULL;
1375 1374 else {
1376 1375 if (rp->r_loyear == rp->r_hiyear) {
1377 1376 error(gettext("typed single year"));
1378 1377 return;
1379 1378 }
1380 1379 rp->r_yrtype = ecpyalloc(typep);
1381 1380 }
1382 1381 if (rp->r_loyear < min_year && rp->r_loyear > 0)
1383 1382 min_year = rp->r_loyear;
1384 1383 /*
1385 1384 * Day work.
1386 1385 * Accept things such as:
1387 1386 * 1
1388 1387 * last-Sunday
1389 1388 * Sun<=20
1390 1389 * Sun>=7
1391 1390 */
1392 1391 dp = ecpyalloc(dayp);
1393 1392 if ((lp = byword(dp, lasts)) != NULL) {
1394 1393 rp->r_dycode = DC_DOWLEQ;
1395 1394 rp->r_wday = lp->l_value;
1396 1395 rp->r_dayofmonth = len_months[1][rp->r_month];
1397 1396 } else {
1398 1397 if ((ep = strchr(dp, '<')) != 0)
1399 1398 rp->r_dycode = DC_DOWLEQ;
1400 1399 else if ((ep = strchr(dp, '>')) != 0)
1401 1400 rp->r_dycode = DC_DOWGEQ;
1402 1401 else {
1403 1402 ep = dp;
1404 1403 rp->r_dycode = DC_DOM;
1405 1404 }
1406 1405 if (rp->r_dycode != DC_DOM) {
1407 1406 *ep++ = 0;
1408 1407 if (*ep++ != '=') {
1409 1408 error(gettext("invalid day of month"));
1410 1409 ifree(dp);
1411 1410 return;
1412 1411 }
1413 1412 if ((lp = byword(dp, wday_names)) == NULL) {
1414 1413 error(gettext("invalid weekday name"));
1415 1414 ifree(dp);
1416 1415 return;
1417 1416 }
1418 1417 rp->r_wday = lp->l_value;
1419 1418 }
1420 1419 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1421 1420 rp->r_dayofmonth <= 0 ||
1422 1421 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1423 1422 error(gettext("invalid day of month"));
1424 1423 ifree(dp);
1425 1424 return;
1426 1425 }
1427 1426 }
1428 1427 ifree(dp);
1429 1428 }
1430 1429
1431 1430 static void
1432 1431 convert(val, buf)
1433 1432 const long val;
1434 1433 char * const buf;
1435 1434 {
1436 1435 register int i;
1437 1436 register long shift;
1438 1437
1439 1438 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1440 1439 buf[i] = val >> shift;
1441 1440 }
1442 1441
1443 1442 static void
1444 1443 puttzcode(val, fp)
1445 1444 const long val;
1446 1445 FILE * const fp;
1447 1446 {
1448 1447 char buf[4];
1449 1448
1450 1449 convert(val, buf);
1451 1450 (void) fwrite((void *)buf, (size_t)sizeof (buf), (size_t)1, fp);
1452 1451 }
1453 1452
1454 1453 static int
1455 1454 atcomp(avp, bvp)
1456 1455 const void *avp;
1457 1456 const void *bvp;
1458 1457 {
1459 1458 if (((struct attype *)avp)->at < ((struct attype *)bvp)->at)
1460 1459 return (-1);
1461 1460 else if (((struct attype *)avp)->at > ((struct attype *)bvp)->at)
1462 1461 return (1);
1463 1462 else return (0);
1464 1463 }
1465 1464
1466 1465 static void
1467 1466 writezone(name)
1468 1467 const char * const name;
1469 1468 {
1470 1469 register FILE *fp;
1471 1470 register int i, j;
1472 1471 static char *fullname;
1473 1472 static struct tzhead tzh;
1474 1473 zic_t ats[TZ_MAX_TIMES];
1475 1474 unsigned char types[TZ_MAX_TIMES];
1476 1475
1477 1476 /*
1478 1477 * Sort.
1479 1478 */
1480 1479 if (timecnt > 1)
1481 1480 (void) qsort((void *)attypes, (size_t)timecnt,
1482 1481 (size_t)sizeof (*attypes), atcomp);
1483 1482 /*
1484 1483 * Optimize.
1485 1484 */
1486 1485 {
1487 1486 int fromi;
1488 1487 int toi;
1489 1488
1490 1489 toi = 0;
1491 1490 fromi = 0;
1492 1491 while (fromi < timecnt && attypes[fromi].at < min_time)
1493 1492 ++fromi;
1494 1493 if (isdsts[0] == 0)
1495 1494 while (fromi < timecnt && attypes[fromi].type == 0)
1496 1495 ++fromi; /* handled by default rule */
1497 1496 for (; fromi < timecnt; ++fromi) {
1498 1497 if (toi != 0 && ((attypes[fromi].at +
1499 1498 gmtoffs[attypes[toi - 1].type]) <=
1500 1499 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1501 1500 : attypes[toi - 2].type]))) {
1502 1501 attypes[toi - 1].type =
1503 1502 attypes[fromi].type;
1504 1503 continue;
1505 1504 }
1506 1505 if (toi == 0 ||
1507 1506 attypes[toi - 1].type != attypes[fromi].type)
1508 1507 attypes[toi++] = attypes[fromi];
1509 1508 }
1510 1509 timecnt = toi;
1511 1510 }
1512 1511 /*
1513 1512 * Transfer.
1514 1513 */
1515 1514 for (i = 0; i < timecnt; ++i) {
1516 1515 ats[i] = attypes[i].at;
1517 1516 types[i] = attypes[i].type;
1518 1517 }
1519 1518 fullname = erealloc(fullname,
1520 1519 (int)(strlen(directory) + 1 + strlen(name) + 1));
1521 1520 (void) sprintf(fullname, "%s/%s", directory, name);
1522 1521 /*
1523 1522 * Remove old file, if any, to snap links.
1524 1523 */
1525 1524 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
1526 1525 const char *e = strerror(errno);
1527 1526
1528 1527 (void) fprintf(stderr, gettext("%s: Can't remove %s: %s\n"),
1529 1528 progname, fullname, e);
1530 1529 exit(EXIT_FAILURE);
1531 1530 }
1532 1531 if ((fp = fopen(fullname, "wb")) == NULL) {
1533 1532 if (mkdirs(fullname) != 0)
1534 1533 exit(EXIT_FAILURE);
1535 1534 if ((fp = fopen(fullname, "wb")) == NULL) {
1536 1535 const char *e = strerror(errno);
1537 1536 (void) fprintf(stderr, gettext(
1538 1537 "%s: Can't create %s: %s\n"),
1539 1538 progname, fullname, e);
1540 1539 exit(EXIT_FAILURE);
1541 1540 }
1542 1541 }
1543 1542 convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
1544 1543 convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
1545 1544 convert(eitol(leapcnt), tzh.tzh_leapcnt);
1546 1545 convert(eitol(timecnt), tzh.tzh_timecnt);
1547 1546 convert(eitol(typecnt), tzh.tzh_typecnt);
1548 1547 convert(eitol(charcnt), tzh.tzh_charcnt);
1549 1548 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof (tzh.tzh_magic));
1550 1549 #define DO(field) (void) fwrite((void *) tzh.field, \
1551 1550 (size_t)sizeof (tzh.field), (size_t)1, fp)
1552 1551 DO(tzh_magic);
1553 1552 DO(tzh_reserved);
1554 1553 DO(tzh_ttisgmtcnt);
1555 1554 DO(tzh_ttisstdcnt);
1556 1555 DO(tzh_leapcnt);
1557 1556 DO(tzh_timecnt);
1558 1557 DO(tzh_typecnt);
1559 1558 DO(tzh_charcnt);
1560 1559 #undef DO
1561 1560 for (i = 0; i < timecnt; ++i) {
1562 1561 j = leapcnt;
1563 1562 while (--j >= 0)
1564 1563 if (ats[i] >= trans[j]) {
1565 1564 ats[i] = tadd(ats[i], corr[j]);
1566 1565 break;
1567 1566 }
1568 1567 puttzcode((long)ats[i], fp);
1569 1568 }
1570 1569 if (timecnt > 0)
1571 1570 (void) fwrite((void *)types, (size_t)sizeof (types[0]),
1572 1571 (size_t)timecnt, fp);
1573 1572 for (i = 0; i < typecnt; ++i) {
1574 1573 puttzcode((long)gmtoffs[i], fp);
1575 1574 (void) putc(isdsts[i], fp);
1576 1575 (void) putc(abbrinds[i], fp);
1577 1576 }
1578 1577 if (charcnt != 0)
1579 1578 (void) fwrite((void *)chars, (size_t)sizeof (chars[0]),
1580 1579 (size_t)charcnt, fp);
1581 1580 for (i = 0; i < leapcnt; ++i) {
1582 1581 if (roll[i]) {
1583 1582 if (timecnt == 0 || trans[i] < ats[0]) {
1584 1583 j = 0;
1585 1584 while (isdsts[j])
1586 1585 if (++j >= typecnt) {
1587 1586 j = 0;
1588 1587 break;
1589 1588 }
1590 1589 } else {
1591 1590 j = 1;
1592 1591 while (j < timecnt && trans[i] >= ats[j])
1593 1592 ++j;
1594 1593 j = types[j - 1];
1595 1594 }
1596 1595 puttzcode((long)tadd(trans[i], -gmtoffs[j]), fp);
1597 1596 } else puttzcode((long)trans[i], fp);
1598 1597 puttzcode((long)corr[i], fp);
1599 1598 }
1600 1599 for (i = 0; i < typecnt; ++i)
1601 1600 (void) putc(ttisstds[i], fp);
1602 1601 for (i = 0; i < typecnt; ++i)
1603 1602 (void) putc(ttisgmts[i], fp);
1604 1603 if (ferror(fp) || fclose(fp)) {
1605 1604 (void) fprintf(stderr, gettext("%s: Error writing %s\n"),
1606 1605 progname, fullname);
1607 1606 exit(EXIT_FAILURE);
1608 1607 }
1609 1608 }
1610 1609
1611 1610 static void
1612 1611 doabbr(abbr, format, letters, isdst)
1613 1612 char * const abbr;
1614 1613 const char * const format;
1615 1614 const char * const letters;
1616 1615 const int isdst;
1617 1616 {
1618 1617 if (strchr(format, '/') == NULL) {
1619 1618 if (letters == NULL)
1620 1619 (void) strcpy(abbr, format);
1621 1620 else
1622 1621 (void) sprintf(abbr, format, letters);
1623 1622 } else if (isdst)
1624 1623 (void) strcpy(abbr, strchr(format, '/') + 1);
1625 1624 else {
1626 1625 (void) strcpy(abbr, format);
1627 1626 *strchr(abbr, '/') = '\0';
1628 1627 }
1629 1628 }
1630 1629
1631 1630 static void
1632 1631 outzone(zpfirst, zonecount)
1633 1632 const struct zone * const zpfirst;
1634 1633 const int zonecount;
1635 1634 {
1636 1635 register const struct zone *zp;
1637 1636 register struct rule *rp;
1638 1637 register int i, j;
1639 1638 register int usestart, useuntil;
1640 1639 register zic_t starttime, untiltime;
1641 1640 register long gmtoff;
1642 1641 register long stdoff;
1643 1642 register int year;
1644 1643 register long startoff;
1645 1644 register int startttisstd;
1646 1645 register int startttisgmt;
1647 1646 register int type;
1648 1647 char startbuf[BUFSIZ];
1649 1648
1650 1649 INITIALIZE(untiltime);
1651 1650 INITIALIZE(starttime);
1652 1651 /*
1653 1652 * Now. . .finally. . .generate some useful data!
1654 1653 */
1655 1654 timecnt = 0;
1656 1655 typecnt = 0;
1657 1656 charcnt = 0;
1658 1657 /*
1659 1658 * Thanks to Earl Chew
1660 1659 * for noting the need to unconditionally initialize startttisstd.
1661 1660 */
1662 1661 startttisstd = FALSE;
1663 1662 startttisgmt = FALSE;
1664 1663 for (i = 0; i < zonecount; ++i) {
1665 1664 /*
1666 1665 * A guess that may well be corrected later.
1667 1666 */
1668 1667 stdoff = 0;
1669 1668 zp = &zpfirst[i];
1670 1669 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
1671 1670 useuntil = i < (zonecount - 1);
1672 1671 if (useuntil && zp->z_untiltime <= min_time)
1673 1672 continue;
1674 1673 gmtoff = zp->z_gmtoff;
1675 1674 eat(zp->z_filename, zp->z_linenum);
1676 1675 *startbuf = '\0';
1677 1676 startoff = zp->z_gmtoff;
1678 1677 if (zp->z_nrules == 0) {
1679 1678 stdoff = zp->z_stdoff;
1680 1679 doabbr(startbuf, zp->z_format,
1681 1680 (char *)NULL, stdoff != 0);
1682 1681 type = addtype(oadd(zp->z_gmtoff, stdoff),
1683 1682 startbuf, stdoff != 0, startttisstd,
1684 1683 startttisgmt);
1685 1684 if (usestart) {
1686 1685 addtt(starttime, type);
1687 1686 usestart = FALSE;
1688 1687 } else if (stdoff != 0)
1689 1688 addtt(min_time, type);
1690 1689 } else
1691 1690 for (year = min_year; year <= max_year; ++year) {
1692 1691 if (useuntil && year > zp->z_untilrule.r_hiyear)
1693 1692 break;
1694 1693 /*
1695 1694 * Mark which rules to do in the current year.
1696 1695 * For those to do, calculate rpytime(rp, year);
1697 1696 */
1698 1697 for (j = 0; j < zp->z_nrules; ++j) {
1699 1698 rp = &zp->z_rules[j];
1700 1699 eats(zp->z_filename, zp->z_linenum,
1701 1700 rp->r_filename, rp->r_linenum);
1702 1701 rp->r_todo = year >= rp->r_loyear &&
1703 1702 year <= rp->r_hiyear &&
1704 1703 yearistype(year, rp->r_yrtype);
1705 1704 if (rp->r_todo)
1706 1705 rp->r_temp = rpytime(rp, year);
1707 1706 }
1708 1707 for (;;) {
1709 1708 register int k;
1710 1709 register zic_t jtime, ktime;
1711 1710 register long offset;
1712 1711 char buf[BUFSIZ];
1713 1712
1714 1713 INITIALIZE(ktime);
1715 1714 if (useuntil) {
1716 1715 /*
1717 1716 * Turn untiltime into UTC * assuming
1718 1717 * the current gmtoff and stdoff values.
1719 1718 */
1720 1719 untiltime = zp->z_untiltime;
1721 1720 if (!zp->z_untilrule.r_todisgmt)
1722 1721 untiltime = tadd(untiltime,
1723 1722 -gmtoff);
1724 1723 if (!zp->z_untilrule.r_todisstd)
1725 1724 untiltime = tadd(untiltime,
1726 1725 -stdoff);
1727 1726 }
1728 1727 /*
1729 1728 * Find the rule (of those to do, if any)
1730 1729 * that takes effect earliest in the year.
1731 1730 */
1732 1731 k = -1;
1733 1732 for (j = 0; j < zp->z_nrules; ++j) {
1734 1733 rp = &zp->z_rules[j];
1735 1734 if (!rp->r_todo)
1736 1735 continue;
1737 1736 eats(zp->z_filename, zp->z_linenum,
1738 1737 rp->r_filename, rp->r_linenum);
1739 1738 offset = rp->r_todisgmt ? 0 : gmtoff;
1740 1739 if (!rp->r_todisstd)
1741 1740 offset = oadd(offset, stdoff);
1742 1741 jtime = rp->r_temp;
1743 1742 if (jtime == min_time ||
1744 1743 jtime == max_time)
1745 1744 continue;
1746 1745 jtime = tadd(jtime, -offset);
1747 1746 if (k < 0 || jtime < ktime) {
1748 1747 k = j;
1749 1748 ktime = jtime;
1750 1749 }
1751 1750 }
1752 1751 if (k < 0)
1753 1752 break; /* go on to next year */
1754 1753 rp = &zp->z_rules[k];
1755 1754 rp->r_todo = FALSE;
1756 1755 if (useuntil && ktime >= untiltime)
1757 1756 break;
1758 1757 stdoff = rp->r_stdoff;
1759 1758 if (usestart && ktime == starttime)
1760 1759 usestart = FALSE;
1761 1760 if (usestart) {
1762 1761 if (ktime < starttime) {
1763 1762 startoff = oadd(zp->z_gmtoff,
1764 1763 stdoff);
1765 1764 doabbr(startbuf, zp->z_format,
1766 1765 rp->r_abbrvar,
1767 1766 rp->r_stdoff != 0);
1768 1767 continue;
1769 1768 }
1770 1769 if (*startbuf == '\0' &&
1771 1770 startoff == oadd(zp->z_gmtoff,
1772 1771 stdoff)) {
1773 1772 doabbr(startbuf, zp->z_format,
1774 1773 rp->r_abbrvar,
1775 1774 rp->r_stdoff != 0);
1776 1775 }
1777 1776 }
1778 1777 eats(zp->z_filename, zp->z_linenum,
1779 1778 rp->r_filename, rp->r_linenum);
1780 1779 doabbr(buf, zp->z_format, rp->r_abbrvar,
1781 1780 rp->r_stdoff != 0);
1782 1781 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1783 1782 type = addtype(offset, buf, rp->r_stdoff != 0,
1784 1783 rp->r_todisstd, rp->r_todisgmt);
1785 1784 addtt(ktime, type);
1786 1785 }
1787 1786 }
1788 1787 if (usestart) {
1789 1788 if (*startbuf == '\0' &&
1790 1789 zp->z_format != NULL &&
1791 1790 strchr(zp->z_format, '%') == NULL &&
1792 1791 strchr(zp->z_format, '/') == NULL)
1793 1792 (void) strcpy(startbuf, zp->z_format);
1794 1793 eat(zp->z_filename, zp->z_linenum);
1795 1794 if (*startbuf == '\0')
1796 1795 error(gettext(
1797 1796 "can't determine time zone abbrevation to use just after until time"));
1798 1797 else addtt(starttime,
1799 1798 addtype(startoff, startbuf,
1800 1799 startoff != zp->z_gmtoff,
1801 1800 startttisstd,
1802 1801 startttisgmt));
1803 1802 }
1804 1803 /*
1805 1804 * Now we may get to set starttime for the next zone line.
1806 1805 */
1807 1806 if (useuntil) {
1808 1807 startttisstd = zp->z_untilrule.r_todisstd;
1809 1808 startttisgmt = zp->z_untilrule.r_todisgmt;
1810 1809 starttime = zp->z_untiltime;
1811 1810 if (!startttisstd)
1812 1811 starttime = tadd(starttime, -stdoff);
1813 1812 if (!startttisgmt)
1814 1813 starttime = tadd(starttime, -gmtoff);
1815 1814 }
1816 1815 }
1817 1816 writezone(zpfirst->z_name);
1818 1817 }
1819 1818
1820 1819 static void
1821 1820 addtt(starttime, type)
1822 1821 const zic_t starttime;
1823 1822 int type;
1824 1823 {
1825 1824 if (starttime <= min_time ||
1826 1825 (timecnt == 1 && attypes[0].at < min_time)) {
1827 1826 gmtoffs[0] = gmtoffs[type];
1828 1827 isdsts[0] = isdsts[type];
1829 1828 ttisstds[0] = ttisstds[type];
1830 1829 ttisgmts[0] = ttisgmts[type];
1831 1830 if (abbrinds[type] != 0)
1832 1831 (void) strcpy(chars, &chars[abbrinds[type]]);
1833 1832 abbrinds[0] = 0;
1834 1833 charcnt = strlen(chars) + 1;
1835 1834 typecnt = 1;
1836 1835 timecnt = 0;
1837 1836 type = 0;
1838 1837 }
1839 1838 if (timecnt >= TZ_MAX_TIMES) {
1840 1839 error(gettext("too many transitions?!"));
1841 1840 exit(EXIT_FAILURE);
1842 1841 }
1843 1842 attypes[timecnt].at = starttime;
1844 1843 attypes[timecnt].type = type;
1845 1844 ++timecnt;
1846 1845 }
1847 1846
1848 1847 static int
1849 1848 addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
1850 1849 const long gmtoff;
1851 1850 const char * const abbr;
1852 1851 const int isdst;
1853 1852 const int ttisstd;
1854 1853 const int ttisgmt;
1855 1854 {
1856 1855 register int i, j;
1857 1856
1858 1857 if (isdst != TRUE && isdst != FALSE) {
1859 1858 error(gettext(
1860 1859 "internal error - addtype called with bad isdst"));
1861 1860 exit(EXIT_FAILURE);
1862 1861 }
1863 1862 if (ttisstd != TRUE && ttisstd != FALSE) {
1864 1863 error(gettext(
1865 1864 "internal error - addtype called with bad ttisstd"));
1866 1865 exit(EXIT_FAILURE);
1867 1866 }
1868 1867 if (ttisgmt != TRUE && ttisgmt != FALSE) {
1869 1868 error(gettext(
1870 1869 "internal error - addtype called with bad ttisgmt"));
1871 1870 exit(EXIT_FAILURE);
1872 1871 }
1873 1872 /*
1874 1873 * See if there's already an entry for this zone type.
1875 1874 * If so, just return its index.
1876 1875 */
1877 1876 for (i = 0; i < typecnt; ++i) {
1878 1877 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1879 1878 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
1880 1879 ttisstd == ttisstds[i] &&
1881 1880 ttisgmt == ttisgmts[i])
1882 1881 return (i);
1883 1882 }
1884 1883 /*
1885 1884 * There isn't one; add a new one, unless there are already too
1886 1885 * many.
1887 1886 */
1888 1887 if (typecnt >= TZ_MAX_TYPES) {
1889 1888 error(gettext("too many local time types"));
1890 1889 exit(EXIT_FAILURE);
1891 1890 }
1892 1891 if (!(-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
1893 1892 error(gettext("UTC offset out of range"));
1894 1893 exit(EXIT_FAILURE);
1895 1894 }
1896 1895 gmtoffs[i] = gmtoff;
1897 1896 isdsts[i] = isdst;
1898 1897 ttisstds[i] = ttisstd;
1899 1898 ttisgmts[i] = ttisgmt;
1900 1899
1901 1900 for (j = 0; j < charcnt; ++j)
1902 1901 if (strcmp(&chars[j], abbr) == 0)
1903 1902 break;
1904 1903 if (j == charcnt)
1905 1904 newabbr(abbr);
1906 1905 abbrinds[i] = j;
1907 1906 ++typecnt;
1908 1907 return (i);
1909 1908 }
1910 1909
1911 1910 #ifdef LEAPSECOND_SUPPORT
1912 1911 static void
1913 1912 leapadd(t, positive, rolling, count)
1914 1913 const zic_t t;
1915 1914 const int positive;
1916 1915 const int rolling;
1917 1916 int count;
1918 1917 {
1919 1918 register int i, j;
1920 1919
1921 1920 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
1922 1921 error(gettext("too many leap seconds"));
1923 1922 exit(EXIT_FAILURE);
1924 1923 }
1925 1924 for (i = 0; i < leapcnt; ++i)
1926 1925 if (t <= trans[i]) {
1927 1926 if (t == trans[i]) {
1928 1927 error(gettext("repeated leap second moment"));
1929 1928 exit(EXIT_FAILURE);
1930 1929 }
1931 1930 break;
1932 1931 }
1933 1932 do {
1934 1933 for (j = leapcnt; j > i; --j) {
1935 1934 trans[j] = trans[j - 1];
1936 1935 corr[j] = corr[j - 1];
1937 1936 roll[j] = roll[j - 1];
1938 1937 }
1939 1938 trans[i] = t;
1940 1939 corr[i] = positive ? 1L : eitol(-count);
1941 1940 roll[i] = rolling;
1942 1941 ++leapcnt;
1943 1942 } while (positive && --count != 0);
1944 1943 }
1945 1944 #endif /* LEAPSECOND_SUPPORT */
1946 1945
1947 1946 #ifdef LEAPSECOND_SUPPORT
1948 1947 static void
1949 1948 adjleap(void)
1950 1949 {
1951 1950 register int i;
1952 1951 register long last = 0;
1953 1952
1954 1953 /*
1955 1954 * propagate leap seconds forward
1956 1955 */
1957 1956 for (i = 0; i < leapcnt; ++i) {
1958 1957 trans[i] = tadd(trans[i], last);
1959 1958 last = corr[i] += last;
1960 1959 }
1961 1960 }
1962 1961 #endif /* LEAPSECOND_SUPPORT */
1963 1962
1964 1963 static int
1965 1964 yearistype(year, type)
1966 1965 const int year;
1967 1966 const char * const type;
1968 1967 {
1969 1968 static char *buf;
1970 1969 int result;
1971 1970
1972 1971 if (type == NULL || *type == '\0')
1973 1972 return (TRUE);
1974 1973 #if defined(sun)
1975 1974 if (strcmp(type, "uspres") == 0)
1976 1975 return ((year % 4) == 0);
1977 1976 if (strcmp(type, "nonpres") == 0)
1978 1977 return ((year % 4) != 0);
1979 1978 if (strcmp(type, "even") == 0)
1980 1979 return ((year % 2) == 0);
1981 1980 if (strcmp(type, "odd") == 0)
1982 1981 return ((year % 2) != 0);
1983 1982 #endif /* defined(sun) */
1984 1983
1985 1984 buf = erealloc(buf, (int)(132 + strlen(yitcommand) + strlen(type)));
1986 1985 (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
1987 1986 result = system(buf);
1988 1987 if (WIFEXITED(result)) {
1989 1988 switch (WEXITSTATUS(result)) {
1990 1989 case 0:
1991 1990 return (TRUE);
1992 1991 case 1:
1993 1992 return (FALSE);
1994 1993 }
1995 1994 }
1996 1995 error(gettext("Wild result from command execution"));
1997 1996 (void) fprintf(stderr, gettext("%s: command was '%s', result was %d\n"),
1998 1997 progname, buf, result);
1999 1998 for (;;)
2000 1999 exit(EXIT_FAILURE);
2001 2000 }
2002 2001
2003 2002 static int
2004 2003 lowerit(a)
2005 2004 int a;
2006 2005 {
2007 2006 a = (unsigned char) a;
2008 2007 return ((isascii(a) && isupper(a)) ? tolower(a) : a);
2009 2008 }
2010 2009
2011 2010 static int
2012 2011 ciequal(ap, bp) /* case-insensitive equality */
2013 2012 register const char *ap;
2014 2013 register const char *bp;
2015 2014 {
2016 2015 while (lowerit(*ap) == lowerit(*bp++))
2017 2016 if (*ap++ == '\0')
2018 2017 return (TRUE);
2019 2018 return (FALSE);
2020 2019 }
2021 2020
2022 2021 static int
2023 2022 itsabbr(abbr, word)
2024 2023 register const char *abbr;
2025 2024 register const char *word;
2026 2025 {
2027 2026 if (lowerit(*abbr) != lowerit(*word))
2028 2027 return (FALSE);
2029 2028 ++word;
2030 2029 while (*++abbr != '\0')
2031 2030 do {
2032 2031 if (*word == '\0')
2033 2032 return (FALSE);
2034 2033 } while (lowerit(*word++) != lowerit(*abbr));
2035 2034 return (TRUE);
2036 2035 }
2037 2036
2038 2037 static const struct lookup *
2039 2038 byword(word, table)
2040 2039 register const char * const word;
2041 2040 register const struct lookup * const table;
2042 2041 {
2043 2042 register const struct lookup *foundlp;
2044 2043 register const struct lookup *lp;
2045 2044
2046 2045 if (word == NULL || table == NULL)
2047 2046 return (NULL);
2048 2047 /*
2049 2048 * Look for exact match.
2050 2049 */
2051 2050 for (lp = table; lp->l_word != NULL; ++lp)
2052 2051 if (ciequal(word, lp->l_word))
2053 2052 return (lp);
2054 2053 /*
2055 2054 * Look for inexact match.
2056 2055 */
2057 2056 foundlp = NULL;
2058 2057 for (lp = table; lp->l_word != NULL; ++lp)
2059 2058 if (itsabbr(word, lp->l_word)) {
2060 2059 if (foundlp == NULL)
2061 2060 foundlp = lp;
2062 2061 else return (NULL); /* multiple inexact matches */
2063 2062 }
2064 2063 return (foundlp);
2065 2064 }
2066 2065
2067 2066 static char **
2068 2067 getfields(cp)
2069 2068 register char *cp;
2070 2069 {
2071 2070 register char *dp;
2072 2071 register char **array;
2073 2072 register int nsubs;
2074 2073
2075 2074 if (cp == NULL)
2076 2075 return (NULL);
2077 2076 array = (char **)(void *)
2078 2077 emalloc((int)((strlen(cp) + 1) * sizeof (*array)));
2079 2078 nsubs = 0;
2080 2079 for (;;) {
2081 2080 while (isascii(*cp) && isspace((unsigned char) *cp))
2082 2081 ++cp;
2083 2082 if (*cp == '\0' || *cp == '#')
2084 2083 break;
2085 2084 array[nsubs++] = dp = cp;
2086 2085 do {
2087 2086 if ((*dp = *cp++) != '"')
2088 2087 ++dp;
2089 2088 else while ((*dp = *cp++) != '"')
2090 2089 if (*dp != '\0')
2091 2090 ++dp;
2092 2091 else {
2093 2092 error(gettext(
2094 2093 "Odd number of quotation marks"));
2095 2094 exit(1);
2096 2095 }
2097 2096 } while (*cp != '\0' && *cp != '#' &&
2098 2097 (!isascii(*cp) || !isspace((unsigned char) *cp)));
2099 2098 if (isascii(*cp) && isspace((unsigned char) *cp))
2100 2099 ++cp;
2101 2100 *dp = '\0';
2102 2101 }
2103 2102 array[nsubs] = NULL;
2104 2103 return (array);
2105 2104 }
2106 2105
2107 2106 static long
2108 2107 oadd(t1, t2)
2109 2108 const long t1;
2110 2109 const long t2;
2111 2110 {
2112 2111 register long t;
2113 2112
2114 2113 t = t1 + t2;
2115 2114 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2116 2115 error(gettext("time overflow"));
2117 2116 exit(EXIT_FAILURE);
2118 2117 }
2119 2118 return (t);
2120 2119 }
2121 2120
2122 2121 static zic_t
2123 2122 tadd(t1, t2)
2124 2123 const zic_t t1;
2125 2124 const long t2;
2126 2125 {
2127 2126 register zic_t t;
2128 2127
2129 2128 if (t1 == max_time && t2 > 0)
2130 2129 return (max_time);
2131 2130 if (t1 == min_time && t2 < 0)
2132 2131 return (min_time);
2133 2132 t = t1 + t2;
2134 2133 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2135 2134 error(gettext("time overflow"));
2136 2135 exit(EXIT_FAILURE);
2137 2136 }
2138 2137 return (t);
2139 2138 }
2140 2139
2141 2140 /*
2142 2141 * Given a rule, and a year, compute the date - in seconds since January 1,
2143 2142 * 1970, 00:00 LOCAL time - in that year that the rule refers to.
2144 2143 */
2145 2144
2146 2145 static zic_t
2147 2146 rpytime(rp, wantedy)
2148 2147 register const struct rule * const rp;
2149 2148 register const int wantedy;
2150 2149 {
2151 2150 register int y, m, i;
2152 2151 register long dayoff; /* with a nod to Margaret O. */
2153 2152 register zic_t t;
2154 2153
2155 2154 if (wantedy == INT_MIN)
2156 2155 return (min_time);
2157 2156 if (wantedy == INT_MAX)
2158 2157 return (max_time);
2159 2158 dayoff = 0;
2160 2159 m = TM_JANUARY;
2161 2160 y = EPOCH_YEAR;
2162 2161 while (wantedy != y) {
2163 2162 if (wantedy > y) {
2164 2163 i = len_years[isleap(y)];
2165 2164 ++y;
2166 2165 } else {
2167 2166 --y;
2168 2167 i = -len_years[isleap(y)];
2169 2168 }
2170 2169 dayoff = oadd(dayoff, eitol(i));
2171 2170 }
2172 2171 while (m != rp->r_month) {
2173 2172 i = len_months[isleap(y)][m];
2174 2173 dayoff = oadd(dayoff, eitol(i));
2175 2174 ++m;
2176 2175 }
2177 2176 i = rp->r_dayofmonth;
2178 2177 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2179 2178 if (rp->r_dycode == DC_DOWLEQ)
2180 2179 --i;
2181 2180 else {
2182 2181 error(gettext("use of 2/29 in non leap-year"));
2183 2182 exit(EXIT_FAILURE);
2184 2183 }
2185 2184 }
2186 2185 --i;
2187 2186 dayoff = oadd(dayoff, eitol(i));
2188 2187 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2189 2188 register long wday;
2190 2189
2191 2190 #define LDAYSPERWEEK ((long)DAYSPERWEEK)
2192 2191 wday = eitol(EPOCH_WDAY);
2193 2192 /*
2194 2193 * Don't trust mod of negative numbers.
2195 2194 */
2196 2195 if (dayoff >= 0)
2197 2196 wday = (wday + dayoff) % LDAYSPERWEEK;
2198 2197 else {
2199 2198 wday -= ((-dayoff) % LDAYSPERWEEK);
2200 2199 if (wday < 0)
2201 2200 wday += LDAYSPERWEEK;
2202 2201 }
2203 2202 while (wday != eitol(rp->r_wday))
2204 2203 if (rp->r_dycode == DC_DOWGEQ) {
2205 2204 dayoff = oadd(dayoff, (long)1);
2206 2205 if (++wday >= LDAYSPERWEEK)
2207 2206 wday = 0;
2208 2207 ++i;
2209 2208 } else {
2210 2209 dayoff = oadd(dayoff, (long)-1);
2211 2210 if (--wday < 0)
2212 2211 wday = LDAYSPERWEEK - 1;
2213 2212 --i;
2214 2213 }
2215 2214 if (i < 0 || i >= len_months[isleap(y)][m]) {
2216 2215 if (noise)
2217 2216 warning(gettext("rule goes past start/end of "
2218 2217 "month--will not work with pre-2004 "
2219 2218 "versions of zic"));
2220 2219 }
2221 2220 }
2222 2221 if (dayoff < 0 && !TYPE_SIGNED(zic_t))
|
↓ open down ↓ |
2205 lines elided |
↑ open up ↑ |
2223 2222 return (min_time);
2224 2223 if (dayoff < min_time / SECSPERDAY)
2225 2224 return (min_time);
2226 2225 if (dayoff > max_time / SECSPERDAY)
2227 2226 return (max_time);
2228 2227 t = (zic_t)dayoff * SECSPERDAY;
2229 2228 return (tadd(t, rp->r_tod));
2230 2229 }
2231 2230
2232 2231 static void
2233 -newabbr(string)
2234 -const char * const string;
2232 +newabbr(const char * const string)
2235 2233 {
2236 2234 register int i;
2237 2235
2238 2236 if (strcmp(string, GRANDPARENTED) != 0) {
2239 2237 register const char *cp;
2240 2238 register char *wp;
2241 2239
2242 - /*
2243 - * Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2244 - * optionally followed by a + or - and a number from 1 to 14.
2245 - */
2246 2240 cp = string;
2247 2241 wp = NULL;
2248 - while (isascii(*cp) && isalpha(*cp))
2242 + while (isalpha(*cp) || ('0' <= *cp && *cp <= '9') ||
2243 + *cp == '-' || *cp == '+') {
2249 2244 ++cp;
2250 - if (cp - string == 0)
2251 - wp = gettext(("time zone abbreviation lacks "
2252 - "alphabetic at start"));
2253 - if (noise && cp - string > 3)
2254 - wp = gettext(("time zone abbreviation has more than 3 "
2245 + }
2246 + if (noise && cp - string < 3)
2247 + wp = gettext(("time zone abbreviation has less than 3 "
2255 2248 "alphabetics"));
2256 - if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2249 + if (wp == NULL && cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2257 2250 wp = gettext(("time zone abbreviation has too many "
2258 - "alphabetics"));
2251 + "characters"));
2259 2252 if (wp == NULL && (*cp == '+' || *cp == '-')) {
2260 2253 ++cp;
2261 2254 if (isascii(*cp) && isdigit(*cp))
2262 2255 if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
2263 2256 ++cp;
2264 2257 }
2265 - if (*cp != '\0')
2258 + if (wp == NULL && *cp != '\0')
2266 2259 wp = gettext("time zone abbreviation differs from "
2267 2260 "POSIX standard");
2268 2261 if (wp != NULL) {
2269 2262 wp = ecpyalloc(wp);
2270 2263 wp = ecatalloc(wp, " (");
2271 2264 wp = ecatalloc(wp, string);
2272 2265 wp = ecatalloc(wp, ")");
2273 2266 warning(wp);
2274 2267 ifree(wp);
2275 2268 }
2276 2269 }
2277 2270 i = strlen(string) + 1;
2278 2271 if (charcnt + i > TZ_MAX_CHARS) {
2279 2272 error(gettext("too many, or too long, time zone "
2280 2273 "abbreviations"));
2281 2274 exit(EXIT_FAILURE);
2282 2275 }
2283 2276 (void) strcpy(&chars[charcnt], string);
2284 2277 charcnt += eitol(i);
2285 2278 }
2286 2279
2287 2280 static int
2288 2281 mkdirs(argname)
2289 2282 char *argname;
2290 2283 {
2291 2284 register char *name;
2292 2285 register char *cp;
2293 2286
2294 2287 if (argname == NULL || *argname == '\0')
2295 2288 return (0);
2296 2289 cp = name = ecpyalloc(argname);
2297 2290 while ((cp = strchr(cp + 1, '/')) != 0) {
2298 2291 *cp = '\0';
2299 2292 if (!itsdir(name)) {
2300 2293 /*
2301 2294 * It doesn't seem to exist, so we try to create it.
2302 2295 * Creation may fail because of the directory being
2303 2296 * created by some other multiprocessor, so we get
2304 2297 * to do extra checking.
2305 2298 */
2306 2299 if (mkdir(name, MKDIR_UMASK) != 0) {
2307 2300 const char *e = strerror(errno);
2308 2301
2309 2302 if (errno != EEXIST || !itsdir(name)) {
2310 2303 (void) fprintf(stderr, gettext(
2311 2304 "%s: Can't create directory %s: %s\n"),
2312 2305 progname, name, e);
2313 2306 ifree(name);
2314 2307 return (-1);
2315 2308 }
2316 2309 }
2317 2310 }
2318 2311 *cp = '/';
2319 2312 }
2320 2313 ifree(name);
2321 2314 return (0);
2322 2315 }
2323 2316
2324 2317 static long
2325 2318 eitol(i)
2326 2319 const int i;
2327 2320 {
2328 2321 long l;
2329 2322
2330 2323 l = i;
2331 2324 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
2332 2325 (void) fprintf(stderr,
2333 2326 gettext("%s: %d did not sign extend correctly\n"),
2334 2327 progname, i);
2335 2328 exit(EXIT_FAILURE);
2336 2329 }
2337 2330 return (l);
2338 2331 }
2339 2332
2340 2333 /*
2341 2334 * UNIX was a registered trademark of The Open Group in 2003.
2342 2335 */
|
↓ open down ↓ |
67 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX