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 }