1 /** 2 * Compiler implementation of the D programming language 3 * http://dlang.org 4 * This file is not shared with other compilers which use the DMD front-end. 5 * 6 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 7 * Some portions copyright (c) 1994-1995 by Symantec 8 * Authors: Walter Bright, http://www.digitalmars.com 9 * License: This source file is made available for personal use 10 * only. The license is in backendlicense.txt 11 * For any other uses, please contact Digital Mars. 12 * Source: $(DMDSRC root/_response.d) 13 */ 14 15 module ddmd.root.response; 16 17 import core.stdc.stdio; 18 import core.stdc.stdlib; 19 import core.stdc..string; 20 import ddmd.root.file; 21 import ddmd.root.filename; 22 23 /********************************* 24 * #include <stdlib.h> 25 * int response_expand(int *pargc,char ***pargv); 26 * 27 * Expand any response files in command line. 28 * Response files are arguments that look like: 29 * @NAME 30 * The name is first searched for in the environment. If it is not 31 * there, it is searched for as a file name. 32 * Arguments are separated by spaces, tabs, or newlines. These can be 33 * imbedded within arguments by enclosing the argument in '' or "". 34 * Recursively expands nested response files. 35 * 36 * To use, put the line: 37 * response_expand(&argc,&argv); 38 * as the first executable statement in main(int argc, char **argv). 39 * argc and argv are adjusted to be the new command line arguments 40 * after response file expansion. 41 * 42 * Digital Mars's MAKE program can be notified that a program can accept 43 * long command lines via environment variables by preceding the rule 44 * line for the program with a *. 45 * 46 * Returns: 47 * 0 success 48 * !=0 failure (argc, argv unchanged) 49 */ 50 bool response_expand(Strings* args) 51 { 52 const(char)* cp; 53 int recurse = 0; 54 for (size_t i = 0; i < args.dim;) 55 { 56 cp = (*args)[i]; 57 if (*cp != '@') 58 { 59 ++i; 60 continue; 61 } 62 args.remove(i); 63 char* buffer; 64 char* bufend; 65 cp++; 66 if (auto p = getenv(cp)) 67 { 68 buffer = strdup(p); 69 if (!buffer) 70 goto noexpand; 71 bufend = buffer + strlen(buffer); 72 } 73 else 74 { 75 auto f = File(cp); 76 if (f.read()) 77 goto noexpand; 78 f._ref = 1; 79 buffer = cast(char*)f.buffer; 80 bufend = buffer + f.len; 81 } 82 // The logic of this should match that in setargv() 83 int comment = 0; 84 for (auto p = buffer; p < bufend; p++) 85 { 86 char* d; 87 char c, lastc; 88 ubyte instring; 89 int num_slashes, non_slashes; 90 switch (*p) 91 { 92 case 26: 93 /* ^Z marks end of file */ 94 goto L2; 95 case 0xD: 96 case '\n': 97 if (comment) 98 { 99 comment = 0; 100 } 101 goto case; 102 case 0: 103 case ' ': 104 case '\t': 105 continue; 106 // scan to start of argument 107 case '#': 108 comment = 1; 109 continue; 110 case '@': 111 if (comment) 112 { 113 continue; 114 } 115 recurse = 1; 116 goto default; 117 default: 118 /* start of new argument */ 119 if (comment) 120 { 121 continue; 122 } 123 args.insert(i, p); 124 ++i; 125 instring = 0; 126 c = 0; 127 num_slashes = 0; 128 for (d = p; 1; p++) 129 { 130 lastc = c; 131 if (p >= bufend) 132 { 133 *d = 0; 134 goto L2; 135 } 136 c = *p; 137 switch (c) 138 { 139 case '"': 140 /* 141 Yes this looks strange,but this is so that we are 142 MS Compatible, tests have shown that: 143 \\\\"foo bar" gets passed as \\foo bar 144 \\\\foo gets passed as \\\\foo 145 \\\"foo gets passed as \"foo 146 and \"foo gets passed as "foo in VC! 147 */ 148 non_slashes = num_slashes % 2; 149 num_slashes = num_slashes / 2; 150 for (; num_slashes > 0; num_slashes--) 151 { 152 d--; 153 *d = '\0'; 154 } 155 if (non_slashes) 156 { 157 *(d - 1) = c; 158 } 159 else 160 { 161 instring ^= 1; 162 } 163 break; 164 case 26: 165 *d = 0; // terminate argument 166 goto L2; 167 case 0xD: 168 // CR 169 c = lastc; 170 continue; 171 // ignore 172 case '@': 173 recurse = 1; 174 goto Ladd; 175 case ' ': 176 case '\t': 177 if (!instring) 178 { 179 case '\n': 180 case 0: 181 *d = 0; // terminate argument 182 goto Lnextarg; 183 } 184 goto default; 185 default: 186 Ladd: 187 if (c == '\\') 188 num_slashes++; 189 else 190 num_slashes = 0; 191 *d++ = c; 192 break; 193 } 194 } 195 break; 196 } 197 Lnextarg: 198 } 199 L2: 200 } 201 if (recurse) 202 { 203 /* Recursively expand @filename */ 204 if (response_expand(args)) 205 goto noexpand; 206 } 207 return false; /* success */ 208 noexpand: 209 /* error */ 210 /* BUG: any file buffers are not free'd */ 211 return true; 212 }