/*----------------------------------------------------------------*
 | envargs - add default options from environment to command line
 |----------------------------------------------------------------
 | Author: Bill Davidsen, original 10/13/91, revised 23 Oct 1991.
 | This program is in the public domain.
 |----------------------------------------------------------------
 | Minor program notes:
 |  1. Yes, the indirection is a tad complex
 |  2. Parenthesis were added where not needed in some cases
 |     to make the action of the code less obscure.
 |  3. Set tabsize to four to make this pretty
 |----------------------------------------------------------------
 | UnZip notes: 24 May 92 ("v1.4"):
 |  1. #include "unzip.h" for prototypes (24 May 92)
 |  2. changed ch to type char (24 May 92)
 |  3. added an ifdef to avoid Borland warnings (24 May 92)
 |  4. included Rich Wales' mksargs() routine (for MS-DOS, maybe
 |     OS/2? NT?) (4 Dec 93)
 |  5. added alternate-variable string envstr2 (21 Apr 94)
 *----------------------------------------------------------------*/


#define UNZIP_INTERNAL
#include "unzip.h"

static int count_args OF((char *));
static void mem_err OF((__GPRO));

#if (defined(SCCS) && !defined(lint))  /* causes warnings:  annoying */
   static char *SCCSid = "@(#)envargs.c    1.3 23 Oct 1991";
#endif

static char Far NoMemArguments[] = "envargs:  can't get memory for arguments";



void envargs(__G__ Pargc, Pargv, envstr, envstr2)
    __GDEF
    int *Pargc;
    char ***Pargv, *envstr, *envstr2;
{
#ifndef RISCOS
    char *getenv();
#endif
    char *envptr;       /* value returned by getenv */
    char *bufptr;       /* copy of env info */
    int argc = 0;       /* internal arg count */
    char ch;            /* spare temp value */
    char **argv;        /* internal arg vector */
    char **argvect;     /* copy of vector address */

    /* see if anything in either of valid environment variables */
    if ((envptr = getenv(envstr)) == (char *)NULL || *envptr == 0)
        if ((envptr = getenv(envstr2)) == (char *)NULL || *envptr == 0)
            return;

    /* count the args so we can allocate room for them */
    argc = count_args(envptr);
    bufptr = (char *)malloc(1+strlen(envptr));
    if (bufptr == (char *)NULL)
        mem_err(__G);
    strcpy(bufptr, envptr);

    /* allocate a vector large enough for all args */
    argv = (char **)malloc((argc+*Pargc+1)*sizeof(char *));
    if (argv == (char **)NULL)
        mem_err(__G);
    argvect = argv;

    /* copy the program name first, that's always true */
    *(argv++) = *((*Pargv)++);

    /* copy the environment args next, may be changed */
    do {
        *(argv++) = bufptr;
        /* skip the arg and any trailing blanks */
        while (((ch = *bufptr) != '\0') && ch != ' ')
            ++bufptr;
        if (ch == ' ')
            *(bufptr++) = '\0';
        while (((ch = *bufptr) != '\0') && ch == ' ')
            ++bufptr;
    } while (ch);

    /* now save old argc and copy in the old args */
    argc += *Pargc;
    while (--(*Pargc))
        *(argv++) = *((*Pargv)++);

    /* finally, add a NULL after the last arg, like UNIX */
    *argv = (char *)NULL;

    /* save the values and return */
    *Pargv = argvect;
    *Pargc = argc;
}



static int count_args(s)
    char *s;
{
    int count = 0;
    char ch;

    do {
        /* count and skip args */
        ++count;
        while (((ch = *s) != '\0') && ch != ' ')
            ++s;
        while (((ch = *s) != '\0') && ch == ' ')
            ++s;
    } while (ch);

    return count;
}



static void mem_err(__G)
    __GDEF
{
    perror(LoadFarString(NoMemArguments));
    DESTROYGLOBALS()
    EXIT(2);
}



#ifdef TEST

main(argc, argv)
    int argc;
    char **argv;
{
    int i;

    printf("Orig argv: %p\n", argv);
    dump_args(argc, argv);
    envargs(__G__ &argc, &argv, "ENVTEST");
    printf(" New argv: %p\n", argv);
    dump_args(argc, argv);
}



dump_args(argc, argv)
    int argc;
    char *argv[];
{
    int i;

    printf("\nDump %d args:\n", argc);
    for (i = 0; i < argc; ++i)
        printf("%3d %s\n", i, argv[i]);
}

#endif /* TEST */



#ifdef MSDOS   /* DOS_OS2?  DOS_OS2_W32? */

/*
 * void mksargs(int *argcp, char ***argvp)
 *
 *    Substitutes the extended command line argument list produced by
 *    the MKS Korn Shell in place of the command line info from DOS.
 *
 *    The MKS shell gets around DOS's 128-byte limit on the length of
 *    a command line by passing the "real" command line in the envi-
 *    ronment.  The "real" arguments are flagged by prepending a tilde
 *    (~) to each one.
 *
 *    This "mksargs" routine creates a new argument list by scanning
 *    the environment from the beginning, looking for strings begin-
 *    ning with a tilde character.  The new list replaces the original
 *    "argv" (pointed to by "argvp"), and the number of arguments
 *    in the new list replaces the original "argc" (pointed to by
 *    "argcp").
 *
 *    Rich Wales
 */
void mksargs(argcp, argvp)
    int *argcp;
    char ***argvp;
{
#ifndef MSC /* declared differently in MSC 7.0 headers, at least */
#ifndef __WATCOMC__
    extern char **environ;          /* environment */
#endif
#endif
    char        **envp;             /* pointer into environment */
    char        **newargv;          /* new argument list */
    char        **argp;             /* pointer into new arg list */
    int         newargc;            /* new argument count */

    /* sanity check */
    if (environ == NULL || argcp == NULL || argvp == NULL || *argvp == NULL)
        return;

    /* find out how many environment arguments there are */
    for (envp = environ, newargc = 0; *envp != NULL && (*envp)[0] == '~';
         envp++, newargc++)
        ;
    if (newargc == 0)
        return;     /* no environment arguments */

    /* set up new argument list */
    newargv = (char **) malloc(sizeof(char **) * (newargc+1));
    if (newargv == NULL)
        return;     /* malloc failed */

    for (argp = newargv, envp = environ; *envp != NULL && (*envp)[0] == '~';
         *argp++ = &(*envp++)[1])
        ;
    *argp = NULL;   /* null-terminate the list */

    /* substitute new argument list in place of old one */
    *argcp = newargc;
    *argvp = newargv;
}

#endif /* MSDOS */
