1 /* 2 Copyright (c) 1990-2000 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2000-Apr-09 or later 5 (the contents of which are also included in unzip.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 | envargs - add default options from environment to command line 11 |---------------------------------------------------------------- 12 | Author: Bill Davidsen, original 10/13/91, revised 23 Oct 1991. 13 | This program is in the public domain. 14 |---------------------------------------------------------------- 15 | Minor program notes: 16 | 1. Yes, the indirection is a tad complex 17 | 2. Parentheses were added where not needed in some cases 18 | to make the action of the code less obscure. 19 |---------------------------------------------------------------- 20 | UnZip notes: 24 May 92 ("v1.4"): 21 | 1. #include "unzip.h" for prototypes (24 May 92) 22 | 2. changed ch to type char (24 May 92) 23 | 3. added an ifdef to avoid Borland warnings (24 May 92) 24 | 4. included Rich Wales' mksargs() routine (for MS-DOS, maybe 25 | OS/2? NT?) (4 Dec 93) 26 | 5. added alternate-variable string envstr2 (21 Apr 94) 27 | 6. added support for quoted arguments (6 Jul 96) 28 *----------------------------------------------------------------*/ 29 30 31 #define __ENVARGS_C /* identifies this source module */ 32 #define UNZIP_INTERNAL 33 #include "unzip.h" 34 35 #ifdef __EMX__ /* emx isspace() returns TRUE on extended ASCII !! */ 36 # define ISspace(c) ((c) & 0x80 ? 0 : isspace((unsigned)c)) 37 #else 38 # define ISspace(c) isspace((unsigned)c) 39 #endif /* ?__EMX__ */ 40 41 static int count_args OF((ZCONST char *)); 42 43 44 /* envargs() returns PK-style error code */ 45 46 int envargs(Pargc, Pargv, envstr, envstr2) 47 int *Pargc; 48 char ***Pargv; 49 ZCONST char *envstr, *envstr2; 50 { 51 #ifndef RISCOS 52 char *getenv(); 53 #endif 54 char *envptr; /* value returned by getenv */ 55 char *bufptr; /* copy of env info */ 56 int argc = 0; /* internal arg count */ 57 register int ch; /* spare temp value */ 58 char **argv; /* internal arg vector */ 59 char **argvect; /* copy of vector address */ 60 61 /* see if anything in the environment */ 62 if ((envptr = getenv(envstr)) != (char *)NULL) /* usual var */ 63 while (ISspace(*envptr)) /* must discard leading spaces */ 64 envptr++; 65 if (envptr == (char *)NULL || *envptr == '\0') 66 if ((envptr = getenv(envstr2)) != (char *)NULL) /* alternate var */ 67 while (ISspace(*envptr)) 68 envptr++; 69 if (envptr == (char *)NULL || *envptr == '\0') 70 return PK_OK; 71 72 bufptr = malloc(1 + strlen(envptr)); 73 if (bufptr == (char *)NULL) 74 return PK_MEM; 75 #if (defined(WIN32) || defined(WINDLL)) 76 # ifdef WIN32 77 if (IsWinNT()) { 78 /* SPC: don't know codepage of 'real' WinNT console */ 79 strcpy(bufptr, envptr); 80 } else { 81 /* Win95 environment is DOS and uses OEM character coding */ 82 OEM_TO_INTERN(envptr, bufptr); 83 } 84 # else /* !WIN32 */ 85 /* DOS environment uses OEM codepage */ 86 OEM_TO_INTERN(envptr, bufptr); 87 # endif 88 #else /* !(WIN32 || WINDLL) */ 89 strcpy(bufptr, envptr); 90 #endif /* ?(WIN32 || WINDLL) */ 91 92 /* count the args so we can allocate room for them */ 93 argc = count_args(bufptr); 94 /* allocate a vector large enough for all args */ 95 argv = (char **)malloc((argc + *Pargc + 1) * sizeof(char *)); 96 if (argv == (char **)NULL) { 97 free(bufptr); 98 return PK_MEM; 99 } 100 argvect = argv; 101 102 /* copy the program name first, that's always true */ 103 *(argv++) = *((*Pargv)++); 104 105 /* copy the environment args next, may be changed */ 106 do { 107 #if defined(AMIGA) || defined(UNIX) 108 if (*bufptr == '"') { 109 char *argstart = ++bufptr; 110 111 *(argv++) = argstart; 112 for (ch = *bufptr; ch != '\0' && ch != '\"'; 113 ch = *PREINCSTR(bufptr)) 114 if (ch == '\\' && bufptr[1] != '\0') 115 ++bufptr; /* advance to char after backslash */ 116 if (ch != '\0') 117 *(bufptr++) = '\0'; /* overwrite trailing " */ 118 119 /* remove escape characters */ 120 while ((argstart = MBSCHR(argstart, '\\')) != (char *)NULL) { 121 strcpy(argstart, argstart + 1); 122 if (*argstart) 123 ++argstart; 124 } 125 } else { 126 *(argv++) = bufptr; 127 while ((ch = *bufptr) != '\0' && !ISspace(ch)) 128 INCSTR(bufptr); 129 if (ch != '\0') 130 *(bufptr++) = '\0'; 131 } 132 #else 133 #ifdef DOS_FLX_NLM_OS2_W32 134 /* we do not support backslash-quoting of quotes in quoted 135 * strings under DOS_FLX_NLM_OS2_W32, because backslashes are 136 * directory separators and double quotes are illegal in filenames */ 137 if (*bufptr == '"') { 138 *(argv++) = ++bufptr; 139 while ((ch = *bufptr) != '\0' && ch != '\"') 140 INCSTR(bufptr); 141 if (ch != '\0') 142 *(bufptr++) = '\0'; 143 } else { 144 *(argv++) = bufptr; 145 while ((ch = *bufptr) != '\0' && !ISspace(ch)) 146 INCSTR(bufptr); 147 if (ch != '\0') 148 *(bufptr++) = '\0'; 149 } 150 #else 151 *(argv++) = bufptr; 152 while ((ch = *bufptr) != '\0' && !ISspace(ch)) 153 INCSTR(bufptr); 154 if (ch != '\0') 155 *(bufptr++) = '\0'; 156 #endif /* ?DOS_FLX_NLM_OS2_W32 */ 157 #endif /* ?(AMIGA || UNIX) */ 158 while ((ch = *bufptr) != '\0' && ISspace(ch)) 159 INCSTR(bufptr); 160 } while (ch); 161 162 /* now save old argc and copy in the old args */ 163 argc += *Pargc; 164 while (--(*Pargc)) 165 *(argv++) = *((*Pargv)++); 166 167 /* finally, add a NULL after the last arg, like Unix */ 168 *argv = (char *)NULL; 169 170 /* save the values and return, indicating succes */ 171 *Pargv = argvect; 172 *Pargc = argc; 173 174 return PK_OK; 175 } 176 177 178 179 static int count_args(s) 180 ZCONST char *s; 181 { 182 int count = 0; 183 char ch; 184 185 do { 186 /* count and skip args */ 187 ++count; 188 #if defined(AMIGA) || defined(UNIX) 189 if (*s == '\"') { 190 for (ch = *PREINCSTR(s); ch != '\0' && ch != '\"'; 191 ch = *PREINCSTR(s)) 192 if (ch == '\\' && s[1] != '\0') 193 ++s; 194 if (*s) 195 ++s; /* trailing quote */ 196 } else 197 #else 198 #ifdef DOS_FLX_NLM_OS2_W32 199 if (*s == '\"') { 200 ++s; /* leading quote */ 201 while ((ch = *s) != '\0' && ch != '\"') 202 INCSTR(s); 203 if (*s) 204 ++s; /* trailing quote */ 205 } else 206 #endif /* DOS_FLX_NLM_OS2_W32 */ 207 #endif /* ?(AMIGA || UNIX) */ 208 while ((ch = *s) != '\0' && !ISspace(ch)) /* note else-clauses above */ 209 INCSTR(s); 210 while ((ch = *s) != '\0' && ISspace(ch)) 211 INCSTR(s); 212 } while (ch); 213 214 return count; 215 } 216 217 218 219 #ifdef TEST 220 221 int main(argc, argv) 222 int argc; 223 char **argv; 224 { 225 int err; 226 227 printf("Orig argv: %p\n", argv); 228 dump_args(argc, argv); 229 if ((err = envargs(&argc, &argv, "ENVTEST")) != PK_OK) { 230 perror("envargs: cannot get memory for arguments"); 231 EXIT(err); 232 } 233 printf(" New argv: %p\n", argv); 234 dump_args(argc, argv); 235 } 236 237 238 239 void dump_args(argc, argv) 240 int argc; 241 char *argv[]; 242 { 243 int i; 244 245 printf("\nDump %d args:\n", argc); 246 for (i = 0; i < argc; ++i) 247 printf("%3d %s\n", i, argv[i]); 248 } 249 250 #endif /* TEST */ 251 252 253 254 #ifdef MSDOS /* DOS_OS2? DOS_OS2_W32? */ 255 256 /* 257 * void mksargs(int *argcp, char ***argvp) 258 * 259 * Substitutes the extended command line argument list produced by 260 * the MKS Korn Shell in place of the command line info from DOS. 261 * 262 * The MKS shell gets around DOS's 128-byte limit on the length of 263 * a command line by passing the "real" command line in the envi- 264 * ronment. The "real" arguments are flagged by prepending a tilde 265 * (~) to each one. 266 * 267 * This "mksargs" routine creates a new argument list by scanning 268 * the environment from the beginning, looking for strings begin- 269 * ning with a tilde character. The new list replaces the original 270 * "argv" (pointed to by "argvp"), and the number of arguments 271 * in the new list replaces the original "argc" (pointed to by 272 * "argcp"). 273 * 274 * Rich Wales 275 */ 276 void mksargs(argcp, argvp) 277 int *argcp; 278 char ***argvp; 279 { 280 #ifndef MSC /* declared differently in MSC 7.0 headers, at least */ 281 #ifndef __WATCOMC__ 282 extern char **environ; /* environment */ 283 #endif 284 #endif 285 char **envp; /* pointer into environment */ 286 char **newargv; /* new argument list */ 287 char **argp; /* pointer into new arg list */ 288 int newargc; /* new argument count */ 289 290 /* sanity check */ 291 if (environ == NULL || argcp == NULL || argvp == NULL || *argvp == NULL) 292 return; 293 294 /* find out how many environment arguments there are */ 295 for (envp = environ, newargc = 0; 296 *envp != NULL && (*envp)[0] == '~'; 297 envp++, newargc++) 298 ; 299 if (newargc == 0) 300 return; /* no environment arguments */ 301 302 /* set up new argument list */ 303 newargv = (char **) malloc(sizeof(char **) * (newargc+1)); 304 if (newargv == NULL) 305 return; /* malloc failed */ 306 307 for (argp = newargv, envp = environ; *envp != NULL && (*envp)[0] == '~'; 308 *argp++ = &(*envp++)[1]) 309 ; 310 *argp = NULL; /* null-terminate the list */ 311 312 /* substitute new argument list in place of old one */ 313 *argcp = newargc; 314 *argvp = newargv; 315 } 316 317 #endif /* MSDOS */ 318