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