Esempio n. 1
0
int response_expand(size_t *pargc, char ***pargv)
{
    struct Narg n;
    char *cp;
    int recurse = 0;

    n.argc = 0;
    n.argvmax = 0;      /* dimension of n.argv[]      */
    n.argv = NULL;
    for (size_t i = 0; i < *pargc; ++i)
    {
        cp = (*pargv)[i];
        if (*cp == '@')
        {
            char *buffer;
            char *bufend;
            char *p;
            int comment = 0;

            cp++;
            p = getenv(cp);
            if (p)
            {
                buffer = strdup(p);
                if (!buffer)
                    goto noexpand;
                bufend = buffer + strlen(buffer);
            }
            else
            {
                long length;
                int fd;
                int nread;
                size_t len;

#if __DMC__
                length = filesize(cp);
#else
                struct stat statbuf;
                if (stat(cp, &statbuf))
                    goto noexpand;
                length = statbuf.st_size;
#endif
                if (length & 0xF0000000)   /* error or file too big */
                    goto noexpand;
                len = length;
                buffer = (char *)malloc(len + 1);
                if (!buffer)
                    goto noexpand;
                bufend = &buffer[len];
                /* Read file into buffer   */
#if _WIN32
                fd = _open(cp,O_RDONLY|O_BINARY);
#else
                fd = open(cp,O_RDONLY);
#endif
                if (fd == -1)
                    goto noexpand;
                nread = read(fd,buffer,len);
                close(fd);

                if (nread != len)
                    goto noexpand;
            }

            // The logic of this should match that in setargv()

            for (p = buffer; p < bufend; p++)
            {
                char *d;
                char c,lastc;
                unsigned char instring;
                int num_slashes,non_slashes;

                switch (*p)
                {
                    case 26:      /* ^Z marks end of file      */
                        goto L2;

                    case 0xD:
                    case '\n':
                        if (comment)
                        {
                            comment = 0;
                        }
                    case 0:
                    case ' ':
                    case '\t':
                        continue;   // scan to start of argument

                    case '#':
                        comment = 1;
                        continue;

                    case '@':
                        if (comment)
                        {
                            continue;
                        }
                        recurse = 1;
                    default:      /* start of new argument   */
                        if (comment)
                        {
                            continue;
                        }
                        if (addargp(&n,p))
                            goto noexpand;
                        instring = 0;
                        c = 0;
                        num_slashes = 0;
                        for (d = p; 1; p++)
                        {
                            lastc = c;
                            if (p >= bufend)
                                goto Lend;
                            c = *p;
                            switch (c)
                            {
                                case '"':
                                    /*
                                        Yes this looks strange,but this is so that we are
                                        MS Compatible, tests have shown that:
                                        \\\\"foo bar"  gets passed as \\foo bar
                                        \\\\foo  gets passed as \\\\foo
                                        \\\"foo gets passed as \"foo
                                        and \"foo gets passed as "foo in VC!
                                     */
                                    non_slashes = num_slashes % 2;
                                    num_slashes = num_slashes / 2;
                                    for (; num_slashes > 0; num_slashes--)
                                    {
                                        d--;
                                        *d = '\0';
                                    }

                                    if (non_slashes)
                                    {
                                        *(d-1) = c;
                                    }
                                    else
                                    {
                                        instring ^= 1;
                                    }
                                    break;
                                case 26:
                            Lend:
                                    *d = 0;      // terminate argument
                                    goto L2;

                                case 0xD:      // CR
                                    c = lastc;
                                    continue;      // ignore

                                case '@':
                                    recurse = 1;
                                    goto Ladd;

                                case ' ':
                                case '\t':
                                    if (!instring)
                                    {
                                case '\n':
                                case 0:
                                        *d = 0;      // terminate argument
                                        goto Lnextarg;
                                    }
                                default:
                                Ladd:
                                    if (c == '\\')
                                        num_slashes++;
                                    else
                                        num_slashes = 0;
                                    *d++ = c;
                                    break;
                            }
#ifdef _MBCS
                            if (_istlead (c)) {
                                *d++ = *++p;
                                if (*(d - 1) == '\0') {
                                    d--;
                                    goto Lnextarg;
                                }
                            }
#endif
                        }
                    break;
                }
            Lnextarg:
                ;
            }
        L2:
            ;
        }
        else if (addargp(&n,(*pargv)[i]))
            goto noexpand;
    }
    if (n.argvmax == 0)
    {
        n.argvmax = 1;
        n.argv = (char **) calloc(n.argvmax, sizeof(char *));
        if (!n.argv)
            return 1;
    }
    else
        n.argv[n.argc] = NULL;
    if (recurse)
    {
        /* Recursively expand @filename   */
        if (response_expand(&n.argc,&n.argv))
            goto noexpand;
    }
    *pargc = n.argc;
    *pargv = n.argv;
    return 0;            /* success         */

noexpand:            /* error         */
    free(n.argv);
    /* BUG: any file buffers are not free'd   */
    return 1;
}
Esempio n. 2
0
bool response_expand(Strings *args)
{
    const char *cp;
    int recurse = 0;

    for (size_t i = 0; i < args->dim; )
    {
        cp = (*args)[i];
        if (*cp != '@')
        {
            ++i;
            continue;
        }

        args->remove(i);

        char *buffer;
        char *bufend;

        cp++;
        char *p = getenv(cp);
        if (p)
        {
            buffer = strdup(p);
            if (!buffer)
                goto noexpand;
            bufend = buffer + strlen(buffer);
        }
        else
        {
            File f(cp);
            if (f.read())
                goto noexpand;
            f.ref = 1;

            buffer = (char *)f.buffer;
            bufend = buffer + f.len;
        }

        // The logic of this should match that in setargv()

        int comment = 0;
        for (p = buffer; p < bufend; p++)
        {
            char *d;
            char c,lastc;
            unsigned char instring;
            int num_slashes,non_slashes;

            switch (*p)
            {
                case 26:      /* ^Z marks end of file      */
                    goto L2;

                case 0xD:
                case '\n':
                    if (comment)
                    {
                        comment = 0;
                    }
                case 0:
                case ' ':
                case '\t':
                    continue;   // scan to start of argument

                case '#':
                    comment = 1;
                    continue;

                case '@':
                    if (comment)
                    {
                        continue;
                    }
                    recurse = 1;
                default:      /* start of new argument   */
                    if (comment)
                    {
                        continue;
                    }
                    args->insert(i, p);
                    ++i;
                    instring = 0;
                    c = 0;
                    num_slashes = 0;
                    for (d = p; 1; p++)
                    {
                        lastc = c;
                        if (p >= bufend)
                        {
                            *d = 0;
                            goto L2;
                        }
                        c = *p;
                        switch (c)
                        {
                            case '"':
                                /*
                                    Yes this looks strange,but this is so that we are
                                    MS Compatible, tests have shown that:
                                    \\\\"foo bar"  gets passed as \\foo bar
                                    \\\\foo  gets passed as \\\\foo
                                    \\\"foo gets passed as \"foo
                                    and \"foo gets passed as "foo in VC!
                                 */
                                non_slashes = num_slashes % 2;
                                num_slashes = num_slashes / 2;
                                for (; num_slashes > 0; num_slashes--)
                                {
                                    d--;
                                    *d = '\0';
                                }

                                if (non_slashes)
                                {
                                    *(d-1) = c;
                                }
                                else
                                {
                                    instring ^= 1;
                                }
                                break;
                            case 26:
                                *d = 0;      // terminate argument
                                goto L2;

                            case 0xD:      // CR
                                c = lastc;
                                continue;      // ignore

                            case '@':
                                recurse = 1;
                                goto Ladd;

                            case ' ':
                            case '\t':
                                if (!instring)
                                {
                            case '\n':
                            case 0:
                                    *d = 0;      // terminate argument
                                    goto Lnextarg;
                                }
                            default:
                            Ladd:
                                if (c == '\\')
                                    num_slashes++;
                                else
                                    num_slashes = 0;
                                *d++ = c;
                                break;
                        }
                    }
                break;
            }
        Lnextarg:
            ;
        }
    L2:
        ;
    }
    if (recurse)
    {
        /* Recursively expand @filename   */
        if (response_expand(args))
            goto noexpand;
    }
    return false;            /* success         */

noexpand:            /* error         */
    /* BUG: any file buffers are not free'd   */
    return true;
}