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