Mercurial > projects > ldc
comparison dmd2/root/response.c @ 1452:638d16625da2
LDC 2 compiles again.
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Sat, 30 May 2009 17:23:32 +0100 |
parents | |
children | e4f7b5d9c68a |
comparison
equal
deleted
inserted
replaced
1423:42bd767ec5a4 | 1452:638d16625da2 |
---|---|
1 // Copyright (C) 1990-1998 by Symantec | |
2 // Copyright (C) 2000-2009 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 | |
17 #if !__DMC__ | |
18 #include <sys/stat.h> | |
19 #endif | |
20 | |
21 #if _WIN32 | |
22 #include <tchar.h> | |
23 #include <io.h> | |
24 #endif | |
25 | |
26 #if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 | |
27 #include <sys/types.h> | |
28 #include <fcntl.h> | |
29 #include <errno.h> | |
30 #include <unistd.h> | |
31 #include <utime.h> | |
32 #endif | |
33 | |
34 /********************************* | |
35 * #include <stdlib.h> | |
36 * int response_expand(int *pargc,char ***pargv); | |
37 * | |
38 * Expand any response files in command line. | |
39 * Response files are arguments that look like: | |
40 * @NAME | |
41 * The name is first searched for in the environment. If it is not | |
42 * there, it is searched for as a file name. | |
43 * Arguments are separated by spaces, tabs, or newlines. These can be | |
44 * imbedded within arguments by enclosing the argument in '' or "". | |
45 * Recursively expands nested response files. | |
46 * | |
47 * To use, put the line: | |
48 * response_expand(&argc,&argv); | |
49 * as the first executable statement in main(int argc, char **argv). | |
50 * argc and argv are adjusted to be the new command line arguments | |
51 * after response file expansion. | |
52 * | |
53 * Digital Mars's MAKE program can be notified that a program can accept | |
54 * long command lines via environment variables by preceding the rule | |
55 * line for the program with a *. | |
56 * | |
57 * Returns: | |
58 * 0 success | |
59 * !=0 failure (argc, argv unchanged) | |
60 */ | |
61 | |
62 struct Narg | |
63 { | |
64 int argc; /* arg count */ | |
65 int argvmax; /* dimension of nargv[] */ | |
66 char **argv; | |
67 }; | |
68 | |
69 static int addargp(struct Narg *n, char *p) | |
70 { | |
71 /* The 2 is to always allow room for a NULL argp at the end */ | |
72 if (n->argc + 2 >= n->argvmax) | |
73 { | |
74 n->argvmax = n->argc + 2; | |
75 n->argv = (char **) realloc(n->argv,n->argvmax * sizeof(char *)); | |
76 if (!n->argv) | |
77 return 1; | |
78 } | |
79 n->argv[n->argc++] = p; | |
80 return 0; | |
81 } | |
82 | |
83 int response_expand(int *pargc, char ***pargv) | |
84 { | |
85 struct Narg n; | |
86 int i; | |
87 char *cp; | |
88 int recurse = 0; | |
89 | |
90 n.argc = 0; | |
91 n.argvmax = 0; /* dimension of n.argv[] */ | |
92 n.argv = NULL; | |
93 for(i=0; i<*pargc; ++i) | |
94 { | |
95 cp = (*pargv)[i]; | |
96 if (*cp == '@') | |
97 { | |
98 char *buffer; | |
99 char *bufend; | |
100 char *p; | |
101 | |
102 cp++; | |
103 p = getenv(cp); | |
104 if (p) | |
105 { | |
106 buffer = strdup(p); | |
107 if (!buffer) | |
108 goto noexpand; | |
109 bufend = buffer + strlen(buffer); | |
110 } | |
111 else | |
112 { | |
113 long length; | |
114 int fd; | |
115 int nread; | |
116 size_t len; | |
117 | |
118 #if __DMC__ | |
119 length = filesize(cp); | |
120 #else | |
121 struct stat statbuf; | |
122 if (stat(cp, &statbuf)) | |
123 goto noexpand; | |
124 length = statbuf.st_size; | |
125 #endif | |
126 if (length & 0xF0000000) /* error or file too big */ | |
127 goto noexpand; | |
128 len = length; | |
129 buffer = (char *)malloc(len + 1); | |
130 if (!buffer) | |
131 goto noexpand; | |
132 bufend = &buffer[len]; | |
133 /* Read file into buffer */ | |
134 #if _WIN32 | |
135 fd = open(cp,O_RDONLY|O_BINARY); | |
136 #else | |
137 fd = open(cp,O_RDONLY); | |
138 #endif | |
139 if (fd == -1) | |
140 goto noexpand; | |
141 nread = read(fd,buffer,len); | |
142 close(fd); | |
143 | |
144 if (nread != len) | |
145 goto noexpand; | |
146 } | |
147 | |
148 // The logic of this should match that in setargv() | |
149 | |
150 for (p = buffer; p < bufend; p++) | |
151 { | |
152 char *d; | |
153 char c,lastc; | |
154 unsigned char instring; | |
155 int num_slashes,non_slashes; | |
156 | |
157 switch (*p) | |
158 { | |
159 case 26: /* ^Z marks end of file */ | |
160 goto L2; | |
161 | |
162 case 0xD: | |
163 case 0: | |
164 case ' ': | |
165 case '\t': | |
166 case '\n': | |
167 continue; // scan to start of argument | |
168 | |
169 case '@': | |
170 recurse = 1; | |
171 default: /* start of new argument */ | |
172 if (addargp(&n,p)) | |
173 goto noexpand; | |
174 instring = 0; | |
175 c = 0; | |
176 num_slashes = 0; | |
177 for (d = p; 1; p++) | |
178 { | |
179 lastc = c; | |
180 if (p >= bufend) | |
181 goto Lend; | |
182 c = *p; | |
183 switch (c) | |
184 { | |
185 case '"': | |
186 /* | |
187 Yes this looks strange,but this is so that we are | |
188 MS Compatible, tests have shown that: | |
189 \\\\"foo bar" gets passed as \\foo bar | |
190 \\\\foo gets passed as \\\\foo | |
191 \\\"foo gets passed as \"foo | |
192 and \"foo gets passed as "foo in VC! | |
193 */ | |
194 non_slashes = num_slashes % 2; | |
195 num_slashes = num_slashes / 2; | |
196 for (; num_slashes > 0; num_slashes--) | |
197 { | |
198 d--; | |
199 *d = '\0'; | |
200 } | |
201 | |
202 if (non_slashes) | |
203 { | |
204 *(d-1) = c; | |
205 } | |
206 else | |
207 { | |
208 instring ^= 1; | |
209 } | |
210 break; | |
211 case 26: | |
212 Lend: | |
213 *d = 0; // terminate argument | |
214 goto L2; | |
215 | |
216 case 0xD: // CR | |
217 c = lastc; | |
218 continue; // ignore | |
219 | |
220 case '@': | |
221 recurse = 1; | |
222 goto Ladd; | |
223 | |
224 case ' ': | |
225 case '\t': | |
226 if (!instring) | |
227 { | |
228 case '\n': | |
229 case 0: | |
230 *d = 0; // terminate argument | |
231 goto Lnextarg; | |
232 } | |
233 default: | |
234 Ladd: | |
235 if (c == '\\') | |
236 num_slashes++; | |
237 else | |
238 num_slashes = 0; | |
239 *d++ = c; | |
240 break; | |
241 } | |
242 #ifdef _MBCS | |
243 if (_istlead (c)) { | |
244 *d++ = *++p; | |
245 if (*(d - 1) == '\0') { | |
246 d--; | |
247 goto Lnextarg; | |
248 } | |
249 } | |
250 #endif | |
251 } | |
252 break; | |
253 } | |
254 Lnextarg: | |
255 ; | |
256 } | |
257 L2: | |
258 ; | |
259 } | |
260 else if (addargp(&n,(*pargv)[i])) | |
261 goto noexpand; | |
262 } | |
263 n.argv[n.argc] = NULL; | |
264 if (recurse) | |
265 { | |
266 /* Recursively expand @filename */ | |
267 if (response_expand(&n.argc,&n.argv)) | |
268 goto noexpand; | |
269 } | |
270 *pargc = n.argc; | |
271 *pargv = n.argv; | |
272 return 0; /* success */ | |
273 | |
274 noexpand: /* error */ | |
275 free(n.argv); | |
276 /* BUG: any file buffers are not free'd */ | |
277 return 1; | |
278 } |