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