view dmd2/root/response.c @ 1650:40bd4a0d4870

Update to work with LLVM 2.7. Removed use of dyn_cast, llvm no compiles without exceptions and rtti by default. We do need exceptions for the libconfig stuff, but rtti isn't necessary (anymore). Debug info needs to be rewritten, as in LLVM 2.7 the format has completely changed. To have something to look at while rewriting, the old code has been wrapped inside #ifndef DISABLE_DEBUG_INFO , this means that you have to define this to compile at the moment. Updated tango 0.99.9 patch to include updated EH runtime code, which is needed for LLVM 2.7 as well.
author Tomas Lindquist Olsen
date Wed, 19 May 2010 12:42:32 +0200
parents e4f7b5d9c68a
children
line wrap: on
line source

// Copyright (C) 1990-1998 by Symantec
// Copyright (C) 2000-2009 by Digital Mars
// All Rights Reserved
// http://www.digitalmars.com
// Written by Walter Bright
/*
 * This source file is made available for personal use
 * only. The license is in /dmd/src/dmd/backendlicense.txt
 * For any other uses, please contact Digital Mars.
 */

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

#if _WIN32
#include <tchar.h>
#include <io.h>
#endif

#if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <utime.h>
#endif

/*********************************
 * #include <stdlib.h>
 * int response_expand(int *pargc,char ***pargv);
 *
 * Expand any response files in command line.
 * Response files are arguments that look like:
 *   @NAME
 * The name is first searched for in the environment. If it is not
 * there, it is searched for as a file name.
 * Arguments are separated by spaces, tabs, or newlines. These can be
 * imbedded within arguments by enclosing the argument in '' or "".
 * Recursively expands nested response files.
 *
 * To use, put the line:
 *   response_expand(&argc,&argv);
 * as the first executable statement in main(int argc, char **argv).
 * argc and argv are adjusted to be the new command line arguments
 * after response file expansion.
 *
 * Digital Mars's MAKE program can be notified that a program can accept
 * long command lines via environment variables by preceding the rule
 * line for the program with a *.
 *
 * Returns:
 *   0   success
 *   !=0   failure (argc, argv unchanged)
 */

struct Narg
{   
    int argc;   /* arg count      */
    int argvmax;   /* dimension of nargv[]   */
    char **argv;
};

static int addargp(struct Narg *n, char *p)
{
    /* The 2 is to always allow room for a NULL argp at the end   */
    if (n->argc + 2 >= n->argvmax)
    {   
        n->argvmax = n->argc + 2;
        n->argv = (char **) realloc(n->argv,n->argvmax * sizeof(char *));
        if (!n->argv)
            return 1;
    }
    n->argv[n->argc++] = p;
    return 0;
}

int response_expand(int *pargc, char ***pargv)
{
    struct Narg n;
    int i;
    char *cp;
    int recurse = 0;

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

            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 0:
                    case ' ':
                    case '\t':
                    case '\n':
                        continue;   // scan to start of argument

                    case '@':
                        recurse = 1;
                    default:      /* start of new argument   */
                        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;
    }
    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;
}