envargs.c 9.8 KB

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