home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip531.zip / envargs.c < prev    next >
C/C++ Source or Header  |  1997-03-28  |  9KB  |  313 lines

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