1/* 2 Copyright (c) 1990-2006 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2005-Feb-10 or later 5 (the contents of which are also included in zip.h) for terms of use. 6 If, for some reason, all these files are missing, the Info-ZIP license 7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html 8*/ 9/* 10 * util.c by Mark Adler. 11 */ 12#define __UTIL_C 13 14#include "zip.h" 15#include "ebcdic.h" 16#include <ctype.h> 17 18#ifdef MSDOS16 19# include <dos.h> 20#endif 21 22uch upper[256], lower[256]; 23/* Country-dependent case map table */ 24 25 26#ifndef UTIL /* UTIL picks out namecmp code (all utils) */ 27 28/* Local functions */ 29local int recmatch OF((ZCONST char *, ZCONST char *, int)); 30local int count_args OF((char *s)); 31 32#ifdef MSDOS16 33 local unsigned ident OF((unsigned chr)); 34#endif 35 36#ifdef NO_MKTIME 37# ifndef IZ_MKTIME_ONLY 38# define IZ_MKTIME_ONLY /* only mktime() related code is pulled in */ 39# endif 40# include "timezone.c" 41#endif 42 43#ifndef HAVE_FSEEKABLE 44int fseekable(fp) 45FILE *fp; 46{ 47 long x; 48 49 return (fp == NULL || (fseek(fp, -1L, SEEK_CUR) == 0 && 50 (x = ftell(fp)) >= 0 && 51 fseek(fp, 1L, SEEK_CUR) == 0 && 52 ftell(fp) == x + 1)); 53} 54#endif /* HAVE_FSEEKABLE */ 55 56char *isshexp(p) 57char *p; /* candidate sh expression */ 58/* If p is a sh expression, a pointer to the first special character is 59 returned. Otherwise, NULL is returned. */ 60{ 61 for (; *p; INCSTR(p)) 62 if (*p == '\\' && *(p+1)) 63 p++; 64#ifdef VMS 65 else if (*p == '%' || *p == '*') 66#else /* !VMS */ 67# ifdef RISCOS 68 /* RISC OS uses # as its single-character wildcard */ 69 else if (*p == '#' || *p == '*' || *p == '[') 70# else /* !RISC OS */ 71 else if (*p == '?' || *p == '*' || *p == '[') 72# endif 73#endif /* ?VMS */ 74 return p; 75 return NULL; 76} 77 78 79local int recmatch(p, s, cs) 80ZCONST char *p; /* sh pattern to match */ 81ZCONST char *s; /* string to match it to */ 82int cs; /* flag: force case-sensitive matching */ 83/* Recursively compare the sh pattern p with the string s and return 1 if 84 they match, and 0 or 2 if they don't or if there is a syntax error in the 85 pattern. This routine recurses on itself no deeper than the number of 86 characters in the pattern. */ 87{ 88 int c; /* pattern char or start of range in [-] loop */ 89 /* Get first character, the pattern for new recmatch calls follows */ 90 c = *POSTINCSTR(p); 91 92 /* If that was the end of the pattern, match if string empty too */ 93 if (c == 0) 94 return *s == 0; 95 96 /* '?' (or '%' or '#') matches any character (but not an empty string) */ 97#ifdef VMS 98 if (c == '%') 99#else /* !VMS */ 100# ifdef RISCOS 101 if (c == '#') 102# else /* !RISC OS */ 103 if (c == '?') 104# endif 105#endif /* ?VMS */ 106#ifdef WILD_STOP_AT_DIR 107 return (*s && *s != '/') ? recmatch(p, s + CLEN(s), cs) : 0; 108#else 109 return *s ? recmatch(p, s + CLEN(s), cs) : 0; 110#endif 111 112 /* '*' matches any number of characters, including zero */ 113#ifdef AMIGA 114 if (c == '#' && *p == '?') /* "#?" is Amiga-ese for "*" */ 115 c = '*', p++; 116#endif /* AMIGA */ 117 if (c == '*') 118 { 119 if (*p == 0) 120 return 1; 121#ifdef WILD_STOP_AT_DIR 122 for (; *s && *s != '/'; INCSTR(s)) 123 if ((c = recmatch(p, s, cs)) != 0) 124 return c; 125 return (*p == '/' || (*p == '\\' && p[1] == '/')) 126 ? recmatch(p, s, cs) : 2; 127#else /* !WILD_STOP_AT_DIR */ 128 if (!isshexp((char *)p)) 129 { 130 /* optimization for rest of pattern being a literal string */ 131 132 /* optimization to handle patterns like *.txt */ 133 /* if the first char in the pattern is '*' and there */ 134 /* are no other shell expression chars, i.e. a literal string */ 135 /* then just compare the literal string at the end */ 136 137 ZCONST char *srest; 138 139 srest = s + (strlen(s) - strlen(p)); 140 if (srest - s < 0) 141 /* remaining literal string from pattern is longer than rest of 142 test string, there can't be a match 143 */ 144 return 0; 145 else 146 /* compare the remaining literal pattern string with the last bytes 147 of the test string to check for a match */ 148#ifdef _MBCS 149 { 150 ZCONST char *q = s; 151 152 /* MBCS-aware code must not scan backwards into a string from 153 * the end. 154 * So, we have to move forward by character from our well-known 155 * character position s in the test string until we have advanced 156 * to the srest position. 157 */ 158 while (q < srest) 159 INCSTR(q); 160 /* In case the byte *srest is a trailing byte of a multibyte 161 * character, we have actually advanced past the position (srest). 162 * For this case, the match has failed! 163 */ 164 if (q != srest) 165 return 0; 166 return ((cs ? strcmp(p, q) : namecmp(p, q)) == 0); 167 } 168#else /* !_MBCS */ 169 return ((cs ? strcmp(p, srest) : namecmp(p, srest)) == 0); 170#endif /* ?_MBCS */ 171 } 172 else 173 { 174 /* pattern contains more wildcards, continue with recursion... */ 175 for (; *s; INCSTR(s)) 176 if ((c = recmatch(p, s, cs)) != 0) 177 return (int)c; 178 return 2; /* 2 means give up--shmatch will return false */ 179 } 180#endif /* ?WILD_STOP_AT_DIR */ 181 } 182 183#ifndef VMS /* No bracket matching in VMS */ 184 /* Parse and process the list of characters and ranges in brackets */ 185 if (c == '[') 186 { 187 int e; /* flag true if next char to be taken literally */ 188 ZCONST char *q; /* pointer to end of [-] group */ 189 int r; /* flag true to match anything but the range */ 190 191 if (*s == 0) /* need a character to match */ 192 return 0; 193 p += (r = (*p == '!' || *p == '^')); /* see if reverse */ 194 for (q = p, e = 0; *q; q++) /* find closing bracket */ 195 if (e) 196 e = 0; 197 else 198 if (*q == '\\') 199 e = 1; 200 else if (*q == ']') 201 break; 202 if (*q != ']') /* nothing matches if bad syntax */ 203 return 0; 204 for (c = 0, e = *p == '-'; p < q; p++) /* go through the list */ 205 { 206 if (e == 0 && *p == '\\') /* set escape flag if \ */ 207 e = 1; 208 else if (e == 0 && *p == '-') /* set start of range if - */ 209 c = *(p-1); 210 else 211 { 212 uch cc = (cs ? (uch)*s : case_map((uch)*s)); 213 uch uc = (uch) c; 214 if (*(p+1) != '-') 215 for (uc = uc ? uc : (uch)*p; uc <= (uch)*p; uc++) 216 /* compare range */ 217 if ((cs ? uc : case_map(uc)) == cc) 218 return r ? 0 : recmatch(q + CLEN(q), s + CLEN(s), cs); 219 c = e = 0; /* clear range, escape flags */ 220 } 221 } 222 return r ? recmatch(q + CLEN(q), s + CLEN(s), cs) : 0; 223 /* bracket match failed */ 224 } 225#endif /* !VMS */ 226 227 /* If escape ('\'), just compare next character */ 228 if (c == '\\') 229 if ((c = *p++) == '\0') /* if \ at end, then syntax error */ 230 return 0; 231 232#ifdef VMS 233 /* 2005-11-06 SMS. 234 Handle "..." wildcard in p with "." or "]" in s. 235 */ 236 if ((c == '.') && (*p == '.') && (*(p+ CLEN( p)) == '.') && 237 ((*s == '.') || (*s == ']'))) 238 { 239 /* Match "...]" with "]". Continue after "]" in both. */ 240 if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']')) 241 return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs); 242 243 /* Else, look for a reduced match in s, until "]" in or end of s. */ 244 for (; *s && (*s != ']'); INCSTR(s)) 245 if (*s == '.') 246 /* If reduced match, then continue after "..." in p, "." in s. */ 247 if ((c = recmatch( (p+ CLEN( p)), s, cs)) != 0) 248 return (int)c; 249 250 /* Match "...]" with "]". Continue after "]" in both. */ 251 if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']')) 252 return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs); 253 254 /* No reduced match. Quit. */ 255 return 2; 256 } 257 258#endif /* def VMS */ 259 260 /* Just a character--compare it */ 261 return (cs ? c == *s : case_map((uch)c) == case_map((uch)*s)) ? 262 recmatch(p, s + CLEN(s), cs) : 0; 263} 264 265 266int shmatch(p, s, cs) 267ZCONST char *p; /* sh pattern to match */ 268ZCONST char *s; /* string to match it to */ 269int cs; /* force case-sensitive match if TRUE */ 270/* Compare the sh pattern p with the string s and return true if they match, 271 false if they don't or if there is a syntax error in the pattern. */ 272{ 273 return recmatch(p, s, cs) == 1; 274} 275 276 277#if defined(DOS) || defined(WIN32) 278/* XXX also suitable for OS2? Atari? Human68K? TOPS-20?? */ 279 280int dosmatch(p, s, cs) 281ZCONST char *p; /* dos pattern to match */ 282ZCONST char *s; /* string to match it to */ 283int cs; /* force case-sensitive match if TRUE */ 284/* Treat filenames without periods as having an implicit trailing period */ 285{ 286 char *s1; /* revised string to match */ 287 int r; /* result */ 288 289 if (strchr(p, '.') && !strchr(s, '.') && 290 ((s1 = malloc(strlen(s) + 2)) != NULL)) 291 { 292 strcpy(s1, s); 293 strcat(s1, "."); 294 } 295 else 296 { 297 /* will usually be OK */ 298 s1 = (char *)s; 299 } 300 301 r = recmatch(p, s1, cs) == 1; 302 if (s != s1) 303 free((zvoid *)s1); 304 return r == 1; 305} 306 307#endif /* DOS || WIN32 */ 308 309zvoid far **search(b, a, n, cmp) 310ZCONST zvoid *b; /* pointer to value to search for */ 311ZCONST zvoid far **a; /* table of pointers to values, sorted */ 312extent n; /* number of pointers in a[] */ 313int (*cmp) OF((ZCONST zvoid *, ZCONST zvoid far *)); /* comparison function */ 314 315/* Search for b in the pointer list a[0..n-1] using the compare function 316 cmp(b, c) where c is an element of a[i] and cmp() returns negative if 317 *b < *c, zero if *b == *c, or positive if *b > *c. If *b is found, 318 search returns a pointer to the entry in a[], else search() returns 319 NULL. The nature and size of *b and *c (they can be different) are 320 left up to the cmp() function. A binary search is used, and it is 321 assumed that the list is sorted in ascending order. */ 322{ 323 ZCONST zvoid far **i; /* pointer to midpoint of current range */ 324 ZCONST zvoid far **l; /* pointer to lower end of current range */ 325 int r; /* result of (*cmp)() call */ 326 ZCONST zvoid far **u; /* pointer to upper end of current range */ 327 328 l = (ZCONST zvoid far **)a; u = l + (n-1); 329 while (u >= l) { 330 i = l + ((unsigned)(u - l) >> 1); 331 if ((r = (*cmp)(b, (ZCONST char far *)*(struct zlist far **)i)) < 0) 332 u = i - 1; 333 else if (r > 0) 334 l = i + 1; 335 else 336 return (zvoid far **)i; 337 } 338 return NULL; /* If b were in list, it would belong at l */ 339} 340 341#endif /* !UTIL */ 342 343#ifdef MSDOS16 344 345local unsigned ident(unsigned chr) 346{ 347 return chr; /* in al */ 348} 349 350void init_upper() 351{ 352 static struct country { 353 uch ignore[18]; 354 int (far *casemap)(int); 355 uch filler[16]; 356 } country_info; 357 358 struct country far *info = &country_info; 359 union REGS regs; 360 struct SREGS sregs; 361 unsigned int c; 362 363 regs.x.ax = 0x3800; /* get country info */ 364 regs.x.dx = FP_OFF(info); 365 sregs.ds = FP_SEG(info); 366 intdosx(®s, ®s, &sregs); 367 for (c = 0; c < 128; c++) { 368 upper[c] = (uch) toupper(c); 369 lower[c] = (uch) c; 370 } 371 for (; c < sizeof(upper); c++) { 372 upper[c] = (uch) (*country_info.casemap)(ident(c)); 373 /* ident() required because casemap takes its parameter in al */ 374 lower[c] = (uch) c; 375 } 376 for (c = 0; c < sizeof(upper); c++ ) { 377 int u = upper[c]; 378 if (u != c && lower[u] == (uch) u) { 379 lower[u] = (uch)c; 380 } 381 } 382 for (c = 'A'; c <= 'Z'; c++) { 383 lower[c] = (uch) (c - 'A' + 'a'); 384 } 385} 386#else /* !MSDOS16 */ 387# ifndef OS2 388 389void init_upper() 390{ 391 unsigned int c; 392#if defined(ATARI) || defined(CMS_MVS) 393#include <ctype.h> 394/* this should be valid for all other platforms too. (HD 11/11/95) */ 395 for (c = 0; c< sizeof(upper); c++) { 396 upper[c] = islower(c) ? toupper(c) : c; 397 lower[c] = isupper(c) ? tolower(c) : c; 398 } 399#else 400 for (c = 0; c < sizeof(upper); c++) upper[c] = lower[c] = (uch)c; 401 for (c = 'a'; c <= 'z'; c++) upper[c] = (uch)(c - 'a' + 'A'); 402 for (c = 'A'; c <= 'Z'; c++) lower[c] = (uch)(c - 'A' + 'a'); 403#endif 404} 405# endif /* !OS2 */ 406 407#endif /* ?MSDOS16 */ 408 409int namecmp(string1, string2) 410 ZCONST char *string1, *string2; 411/* Compare the two strings ignoring case, and correctly taking into 412 * account national language characters. For operating systems with 413 * case sensitive file names, this function is equivalent to strcmp. 414 */ 415{ 416 int d; 417 418 for (;;) 419 { 420 d = (int) (uch) case_map(*string1) 421 - (int) (uch) case_map(*string2); 422 423 if (d || *string1 == 0 || *string2 == 0) 424 return d; 425 426 string1++; 427 string2++; 428 } 429} 430 431#ifdef EBCDIC 432char *strtoasc(char *str1, ZCONST char *str2) 433{ 434 char *old; 435 old = str1; 436 while (*str1++ = (char)ascii[(uch)(*str2++)]); 437 return old; 438} 439 440char *strtoebc(char *str1, ZCONST char *str2) 441{ 442 char *old; 443 old = str1; 444 while (*str1++ = (char)ebcdic[(uch)(*str2++)]); 445 return old; 446} 447 448char *memtoasc(char *mem1, ZCONST char *mem2, unsigned len) 449{ 450 char *old; 451 old = mem1; 452 while (len--) 453 *mem1++ = (char)ascii[(uch)(*mem2++)]; 454 return old; 455} 456 457char *memtoebc(char *mem1, ZCONST char *mem2, unsigned len) 458{ 459 char *old; 460 old = mem1; 461 while (len--) 462 *mem1++ = (char)ebcdic[(uch)(*mem2++)]; 463 return old; 464} 465#endif /* EBCDIC */ 466 467#ifdef IZ_ISO2OEM_ARRAY 468char *str_iso_to_oem(dst, src) 469 ZCONST char *src; 470 char *dst; 471{ 472 char *dest_start = dst; 473 while (*dst++ = (char)iso2oem[(uch)(*src++)]); 474 return dest_start; 475} 476#endif 477 478#ifdef IZ_OEM2ISO_ARRAY 479char *str_oem_to_iso(dst, src) 480 ZCONST char *src; 481 char *dst; 482{ 483 char *dest_start = dst; 484 while (*dst++ = (char)oem2iso[(uch)(*src++)]); 485 return dest_start; 486} 487#endif 488 489 490 491/* DBCS support for Info-ZIP's zip (mainly for japanese (-: ) 492 * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp) 493 * This code is public domain! Date: 1998/12/20 494 */ 495#ifdef _MBCS 496 497char *___tmp_ptr; 498 499int lastchar(ptr) 500 ZCONST char *ptr; 501{ 502 ZCONST char *oldptr = ptr; 503 while(*ptr != '\0'){ 504 oldptr = ptr; 505 INCSTR(ptr); 506 } 507 return (int)(unsigned)*oldptr; 508} 509 510unsigned char *zmbschr(str, c) 511 ZCONST unsigned char *str; 512 unsigned int c; 513{ 514 while(*str != '\0'){ 515 if (*str == c) {return (char*)str;} 516 INCSTR(str); 517 } 518 return NULL; 519} 520 521unsigned char *zmbsrchr(str, c) 522 ZCONST unsigned char *str; 523 unsigned int c; 524{ 525 unsigned char *match = NULL; 526 while(*str != '\0'){ 527 if (*str == c) {match = (char*)str;} 528 INCSTR(str); 529 } 530 return match; 531} 532#endif /* _MBCS */ 533 534 535 536#ifndef UTIL 537 538/***************************************************************** 539 | envargs - add default options from environment to command line 540 |---------------------------------------------------------------- 541 | Author: Bill Davidsen, original 10/13/91, revised 23 Oct 1991. 542 | This program is in the public domain. 543 |---------------------------------------------------------------- 544 | Minor program notes: 545 | 1. Yes, the indirection is a tad complex 546 | 2. Parenthesis were added where not needed in some cases 547 | to make the action of the code less obscure. 548 ****************************************************************/ 549 550void envargs(Pargc, Pargv, envstr, envstr2) 551 int *Pargc; 552 char ***Pargv; 553 char *envstr; 554 char *envstr2; 555{ 556 char *envptr; /* value returned by getenv */ 557 char *bufptr; /* copy of env info */ 558 int argc; /* internal arg count */ 559 register int ch; /* spare temp value */ 560 char **argv; /* internal arg vector */ 561 char **argvect; /* copy of vector address */ 562 563 /* see if anything in the environment */ 564 envptr = getenv(envstr); 565 if (envptr != NULL) /* usual var */ 566 while (isspace((uch)*envptr)) /* we must discard leading spaces */ 567 envptr++; 568 if (envptr == NULL || *envptr == '\0') 569 if ((envptr = getenv(envstr2)) != NULL) /* alternate */ 570 while (isspace((uch)*envptr)) 571 envptr++; 572 if (envptr == NULL || *envptr == '\0') 573 return; 574 575 /* count the args so we can allocate room for them */ 576 argc = count_args(envptr); 577 bufptr = malloc(1 + strlen(envptr)); 578 if (bufptr == NULL) 579 ziperr(ZE_MEM, "Can't get memory for arguments"); 580 strcpy(bufptr, envptr); 581 582 /* allocate a vector large enough for all args */ 583 argv = (char **)malloc((argc + *Pargc + 1) * sizeof(char *)); 584 if (argv == NULL) { 585 free(bufptr); 586 ziperr(ZE_MEM, "Can't get memory for arguments"); 587 } 588 argvect = argv; 589 590 /* copy the program name first, that's always true */ 591 *(argv++) = *((*Pargv)++); 592 593 /* copy the environment args first, may be changed */ 594 do { 595#if defined(AMIGA) || defined(UNIX) 596 if (*bufptr == '"') { 597 char *argstart = ++bufptr; 598 *(argv++) = argstart; 599 for (ch = *bufptr; ch != '\0' && ch != '\"'; 600 ch = *PREINCSTR(bufptr)) 601 if (ch == '\\' && bufptr[1] != '\0') 602 ++bufptr; /* skip to char after backslash */ 603 if (ch != '\0') /* overwrite trailing '"' */ 604 *(bufptr++) = '\0'; 605 606 /* remove escape characters */ 607 while ((argstart = MBSCHR(argstart, '\\')) != NULL) { 608 strcpy(argstart, argstart + 1); 609 if (*argstart) 610 ++argstart; 611 } 612 } else { 613 *(argv++) = bufptr; 614 while ((ch = *bufptr) != '\0' && !isspace((uch)ch)) INCSTR(bufptr); 615 if (ch != '\0') *(bufptr++) = '\0'; 616 } 617#else 618# ifdef WIN32 619 /* We do not support backslash-quoting of quotes in quoted */ 620 /* strings under Win32, because backslashes are directory */ 621 /* separators and double quotes are illegal in filenames. */ 622 if (*bufptr == '"') { 623 *(argv++) = ++bufptr; 624 while ((ch = *bufptr) != '\0' && ch != '\"') INCSTR(bufptr); 625 if (ch != '\0') *(bufptr++) = '\0'; 626 } else { 627 *(argv++) = bufptr; 628 while ((ch = *bufptr) != '\0' && !isspace((uch)ch)) INCSTR(bufptr); 629 if (ch != '\0') *(bufptr++) = '\0'; 630 } 631# else 632 *(argv++) = bufptr; 633 while ((ch = *bufptr) != '\0' && !isspace((uch)ch)) INCSTR(bufptr); 634 if (ch != '\0') *(bufptr++) = '\0'; 635# endif 636#endif /* ?(AMIGA || UNIX) */ 637 while ((ch = *bufptr) != '\0' && isspace((uch)ch)) INCSTR(bufptr); 638 } while (ch); 639 640 /* now save old argc and copy in the old args */ 641 argc += *Pargc; 642 while (--(*Pargc)) *(argv++) = *((*Pargv)++); 643 644 /* finally, add a NULL after the last arg, like UNIX */ 645 *argv = NULL; 646 647 /* save the values and return */ 648 *Pargv = argvect; 649 *Pargc = argc; 650} 651 652static int count_args(s) 653char *s; 654{ 655 int count = 0; 656 char ch; 657 658 do { 659 /* count and skip args */ 660 ++count; 661#if defined(AMIGA) || defined(UNIX) 662 if (*s == '\"') { 663 for (ch = *PREINCSTR(s); ch != '\0' && ch != '\"'; 664 ch = *PREINCSTR(s)) 665 if (ch == '\\' && s[1] != '\0') 666 INCSTR(s); 667 if (*s) INCSTR(s); /* trailing quote */ 668 } else 669 while ((ch = *s) != '\0' && !isspace((uch)ch)) INCSTR(s); 670#else 671# ifdef WIN32 672 if (*s == '\"') { 673 ++s; /* leading quote */ 674 while ((ch = *s) != '\0' && ch != '\"') INCSTR(s); 675 if (*s) INCSTR(s); /* trailing quote */ 676 } else 677 while ((ch = *s) != '\0' && !isspace((uch)ch)) INCSTR(s); 678# else 679 while ((ch = *s) != '\0' && !isspace((uch)ch)) INCSTR(s); 680# endif 681#endif /* ?(AMIGA || UNIX) */ 682 while ((ch = *s) != '\0' && isspace((uch)ch)) INCSTR(s); 683 } while (ch); 684 685 return(count); 686} 687 688 689 690/* Extended argument processing -- by Rich Wales 691 * This function currently deals only with the MKS shell, but could be 692 * extended later to understand other conventions. 693 * 694 * void expand_args(int *argcp, char ***argvp) 695 * 696 * Substitutes the extended command line argument list produced by 697 * the MKS Korn Shell in place of the command line info from DOS. 698 * 699 * The MKS shell gets around DOS's 128-byte limit on the length of 700 * a command line by passing the "real" command line in the envi- 701 * ronment. The "real" arguments are flagged by prepending a tilde 702 * (~) to each one. 703 * 704 * This "expand_args" routine creates a new argument list by scanning 705 * the environment from the beginning, looking for strings begin- 706 * ning with a tilde character. The new list replaces the original 707 * "argv" (pointed to by "argvp"), and the number of arguments 708 * in the new list replaces the original "argc" (pointed to by 709 * "argcp"). 710 */ 711void expand_args(argcp, argvp) 712 int *argcp; 713 char ***argvp; 714{ 715#ifdef DOS 716 717/* Do NEVER include (re)definiton of `environ' variable with any version 718 of MSC or BORLAND/Turbo C. These compilers supply an incompatible 719 definition in <stdlib.h>. */ 720#if defined(__GO32__) || defined(__EMX__) 721 extern char **environ; /* environment */ 722#endif /* __GO32__ || __EMX__ */ 723 char **envp; /* pointer into environment */ 724 char **newargv; /* new argument list */ 725 char **argp; /* pointer into new arg list */ 726 int newargc; /* new argument count */ 727 728 /* sanity check */ 729 if (environ == NULL 730 || argcp == NULL 731 || argvp == NULL || *argvp == NULL) 732 return; 733 /* find out how many environment arguments there are */ 734 for (envp = environ, newargc = 0; 735 *envp != NULL && (*envp)[0] == '~'; 736 envp++, newargc++) ; 737 if (newargc == 0) 738 return; /* no environment arguments */ 739 /* set up new argument list */ 740 newargv = (char **) malloc(sizeof(char **) * (newargc+1)); 741 if (newargv == NULL) 742 return; /* malloc failed */ 743 for (argp = newargv, envp = environ; 744 *envp != NULL && (*envp)[0] == '~'; 745 *argp++ = &(*envp++)[1]) ; 746 *argp = NULL; /* null-terminate the list */ 747 /* substitute new argument list in place of old one */ 748 *argcp = newargc; 749 *argvp = newargv; 750#else /* !DOS */ 751 if (argcp || argvp) return; 752#endif /* ?DOS */ 753} 754 755#endif /* UTIL */ 756 757#ifdef DEBUGNAMES 758#undef free 759int Free(x) 760void *x; 761{ 762 if (x == (void *) 0xdeadbeef) 763 exit(-1); 764 free(x); 765 return 0; 766} 767 768int printnames() 769{ 770 struct zlist far *z; 771 772 for (z = zfiles; z != NULL; z = z->nxt) 773 fprintf(stderr, "%s %s %s %p %p %p %08x %08x %08x\n", 774 z->name, z->zname, z->iname, 775 z->name, z->zname, z->iname, 776 *((int *) z->name), *((int *) z->zname), 777 *((int *) z->iname)); 778 return 0; 779} 780 781#endif /* DEBUGNAMES */ 782