1: // Copyright (C) 1990-1998 by Symantec
  2: // Copyright (C) 2000-2011 by Digital Mars
  3: // All Rights Reserved
  4: // http://www.digitalmars.com
  5: // Written by Walter Bright
  6: /*
  7:  * This source file is made available for personal use
  8:  * only. The license is in /dmd/src/dmd/backendlicense.txt
  9:  * For any other uses, please contact Digital Mars.
 10:  */
 11: 
 12: #include <stdio.h>
 13: #include <fcntl.h>
 14: #include <stdlib.h>
 15: #include <string.h>
 16: static char __file__[] = __FILE__;      /* for tassert.h                */
 17: #include        "tassert.h"
 18: 
 19: #if _WIN32
 20: #include <tchar.h>
 21: #include <io.h>
 22: #endif
 23: 
 24: #if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
 25: #include <sys/stat.h>
 26: #include <sys/types.h>
 27: #include <fcntl.h>
 28: #include <errno.h>
 29: #include <unistd.h>
 30: #include <utime.h>
 31: #endif
 32: 
 33: #if _MSC_VER
 34: #include <sys/stat.h>
 35: #endif
 36: 
 37: /*********************************
 38:  * #include <stdlib.h>
 39:  * int response_expand(int *pargc,char ***pargv);
 40:  *
 41:  * Expand any response files in command line.
 42:  * Response files are arguments that look like:
 43:  *   @NAME
 44:  * The name is first searched for in the environment. If it is not
 45:  * there, it is searched for as a file name.
 46:  * Arguments are separated by spaces, tabs, or newlines. These can be
 47:  * imbedded within arguments by enclosing the argument in '' or "".
 48:  * Recursively expands nested response files.
 49:  *
 50:  * To use, put the line:
 51:  *   response_expand(&argc,&argv);
 52:  * as the first executable statement in main(int argc, char **argv).
 53:  * argc and argv are adjusted to be the new command line arguments
 54:  * after response file expansion.
 55:  *
 56:  * Digital Mars's MAKE program can be notified that a program can accept
 57:  * long command lines via environment variables by preceding the rule
 58:  * line for the program with a *.
 59:  *
 60:  * Returns:
 61:  *   0   success
 62:  *   !=0   failure (argc, argv unchanged)
 63:  */
 64: 
 65: struct Narg
 66: {
 67:     int argc;   /* arg count      */
 68:     int argvmax;   /* dimension of nargv[]   */
 69:     char **argv;
 70: };
 71: 
 72: static int addargp(struct Narg *n, char *p)
 73: {
 74:     /* The 2 is to always allow room for a NULL argp at the end   */
 75:     if (n->argc + 2 > n->argvmax)
 76:     {
 77:         n->argvmax = n->argc + 2;
 78:         n->argv = (char **) realloc(n->argv,n->argvmax * sizeof(char *));
warning C6308: 'realloc' might return null pointer: assigning null pointer to 'n->argv', which is passed as an argument to 'realloc', will cause the original memory block to be leaked
79: if (!n->argv) 80: return 1; 81: } 82: n->argv[n->argc++] = p; 83: return 0; 84: } 85: 86: int response_expand(int *pargc, char ***pargv) 87: { 88: struct Narg n; 89: int i; 90: char *cp; 91: int recurse = 0; 92: 93: n.argc = 0; 94: n.argvmax = 0; /* dimension of n.argv[] */ 95: n.argv = NULL; 96: for(i=0; i<*pargc; ++i) 97: { 98: cp = (*pargv)[i]; 99: if (*cp == '@') 100: { 101: char *buffer; 102: char *bufend; 103: char *p; 104: 105: cp++; 106: p = getenv(cp);
warning C4996: 'getenv': This function or variable may be unsafe. Consider using _dupenv_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdlib.h(433) : see declaration of 'getenv'
107: if (p) 108: { 109: buffer = strdup(p);
warning C4996: 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strdup. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h(238) : see declaration of 'strdup'
110: if (!buffer) 111: goto noexpand; 112: bufend = buffer + strlen(buffer); 113: } 114: else 115: { 116: long length; 117: int fd; 118: int nread; 119: size_t len; 120: 121: #if __DMC__ 122: length = filesize(cp); 123: #else 124: struct stat statbuf; 125: if (stat(cp, &statbuf)) 126: goto noexpand; 127: length = statbuf.st_size; 128: #endif 129: if (length & 0xF0000000) /* error or file too big */ 130: goto noexpand; 131: len = length; 132: buffer = (char *)malloc(len + 1); 133: if (!buffer) 134: goto noexpand; 135: bufend = &buffer[len]; 136: /* Read file into buffer */ 137: #if _WIN32 138: fd = open(cp,O_RDONLY|O_BINARY);
warning C4996: 'open': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _open. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\io.h(312) : see declaration of 'open'
139: #else 140: fd = open(cp,O_RDONLY); 141: #endif 142: if (fd == -1) 143: goto noexpand; 144: nread = read(fd,buffer,len);
warning C4996: 'read': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _read. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\io.h(313) : see declaration of 'read'
145: close(fd);
warning C4996: 'close': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _close. See online help for details. c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\io.h(302) : see declaration of 'close'
146: 147: if (nread != len) 148: goto noexpand; 149: } 150: 151: // The logic of this should match that in setargv() 152: 153: for (p = buffer; p < bufend; p++) 154: { 155: char *d; 156: char c,lastc; 157: unsigned char instring; 158: int num_slashes,non_slashes; 159: 160: switch (*p) 161: { 162: case 26: /* ^Z marks end of file */ 163: goto L2; 164: 165: case 0xD: 166: case 0: 167: case ' ': 168: case '\t': 169: case '\n': 170: continue; // scan to start of argument 171: 172: case '@': 173: recurse = 1; 174: default: /* start of new argument */ 175: if (addargp(&n,p)) 176: goto noexpand; 177: instring = 0; 178: c = 0; 179: num_slashes = 0; 180: for (d = p; 1; p++) 181: { 182: lastc = c; 183: if (p >= bufend) 184: goto Lend; 185: c = *p; 186: switch (c) 187: { 188: case '"': 189: /* 190: Yes this looks strange,but this is so that we are 191: MS Compatible, tests have shown that: 192: \\\\"foo bar" gets passed as \\foo bar 193: \\\\foo gets passed as \\\\foo 194: \\\"foo gets passed as \"foo 195: and \"foo gets passed as "foo in VC! 196: */ 197: non_slashes = num_slashes % 2; 198: num_slashes = num_slashes / 2; 199: for (; num_slashes > 0; num_slashes--) 200: { 201: d--; 202: *d = '\0'; 203: } 204: 205: if (non_slashes) 206: { 207: *(d-1) = c; 208: } 209: else 210: { 211: instring ^= 1; 212: } 213: break; 214: case 26: 215: Lend: 216: *d = 0; // terminate argument 217: goto L2; 218: 219: case 0xD: // CR 220: c = lastc; 221: continue; // ignore 222: 223: case '@': 224: recurse = 1; 225: goto Ladd; 226: 227: case ' ': 228: case '\t': 229: if (!instring) 230: { 231: case '\n': 232: case 0: 233: *d = 0; // terminate argument 234: goto Lnextarg; 235: } 236: default: 237: Ladd: 238: if (c == '\\') 239: num_slashes++; 240: else 241: num_slashes = 0; 242: *d++ = c; 243: break; 244: } 245: #ifdef _MBCS 246: if (_istlead (c)) { 247: *d++ = *++p; 248: if (*(d - 1) == '\0') { 249: d--; 250: goto Lnextarg; 251: } 252: } 253: #endif 254: } 255: break; 256: } 257: Lnextarg: 258: ; 259: } 260: L2: 261: ; 262: } 263: else if (addargp(&n,(*pargv)[i])) 264: goto noexpand; 265: } 266: if (n.argvmax == 0) 267: { 268: n.argvmax = 1; 269: n.argv = (char **) calloc(n.argvmax, sizeof(char *)); 270: if (!n.argv) 271: return 1; 272: } 273: else 274: n.argv[n.argc] = NULL; 275: if (recurse) 276: { 277: /* Recursively expand @filename */ 278: if (response_expand(&n.argc,&n.argv)) 279: goto noexpand; 280: } 281: *pargc = n.argc; 282: *pargv = n.argv; 283: return 0; /* success */ 284: 285: noexpand: /* error */ 286: free(n.argv); 287: /* BUG: any file buffers are not free'd */ 288: return 1; 289: } 290: