1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2004-2016. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  *
20  */
21 
22 /*
23  * A compiler wrapper that translate (some) gcc command line arguments
24  * to the Visual C++ compiler and (of course) the gcc compiler. It also
25  * makes some changes in the command line arguments when debug compiling.
26  */
27 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdarg.h>
32 
33 
34 #if !defined(__WIN32__)
35 #define USE_EXEC
36 #include <unistd.h>
37 #endif
38 
39 
40 #ifdef __WIN32__
41 #define EOL "\r\n"
42 #else
43 #define EOL "\n"
44 #endif
45 
46 #define ARGS_INCR 20
47 
48 static char *prog;
49 
50 typedef struct {
51     char **vec;
52     int no;
53     int ix;
54     int chars;
55 } args_t;
56 
57 static void
enomem(void)58 enomem(void)
59 {
60     fprintf(stderr, "%s: Out of memory%s", prog, EOL);
61     exit(1);
62 }
63 
64 static void
save_arg(args_t * args,char * arg1,...)65 save_arg(args_t *args, char *arg1, ...)
66 {
67     char *carg;
68     va_list argp;
69 
70     va_start(argp, arg1);
71     carg = arg1;
72     while (carg) {
73 	if (args->no <= args->ix) {
74 	    args->vec = (char **) (args->no
75 				   ? realloc((void *) args->vec,
76 					     (sizeof(char *)
77 					      *(args->no + ARGS_INCR + 2)))
78 				   : malloc((sizeof(char *)
79 					     *(args->no + ARGS_INCR + 2))));
80 	    if (!args->vec)
81 		enomem();
82 	    args->no += ARGS_INCR;
83 	}
84 	if (carg == arg1) {
85 	  args->vec[args->ix++] = "\"";
86 	  args->chars++;
87 	}
88 	args->vec[args->ix++] = carg;
89 	args->chars += strlen(carg);
90 	carg = va_arg(argp, char *);
91     }
92     args->vec[args->ix++] = "\"";
93     args->chars++;
94     args->vec[args->ix++] = " ";
95     args->chars++;
96     va_end(argp);
97 }
98 
99 static int
is_prefix(char * prfx,char ** str)100 is_prefix(char *prfx, char **str)
101 {
102     int i;
103     for (i = 0; prfx[i] && (*str)[i]; i++) {
104 	if (prfx[i] != (*str)[i])
105 	    return 0;
106     }
107     if (!prfx[i]) {
108 	*str = &(*str)[i];
109 	return 1;
110     }
111     return 0;
112 }
113 
114 static void
cpy(char ** dst,char * src)115 cpy(char **dst, char *src)
116 {
117     int i;
118     for (i = 0; src[i]; i++)
119 	(*dst)[i] = src[i];
120     *dst = &(*dst)[i];
121 }
122 
123 typedef enum {
124     STDLIB_NONE,
125     STDLIB_MD,
126     STDLIB_ML,
127     STDLIB_MT
128 } stdlib_t;
129 
130 int
main(int argc,char * argv[])131 main(int argc, char *argv[])
132 {
133     int res;
134     int i;
135     size_t cmd_len;
136     char *cmd;
137     char *cmd_end;
138     char *cc = NULL;
139     args_t args = {0};
140     int is_debug = 0;
141     int is_purify = 0;
142     int is_quantify = 0;
143     int is_purecov = 0;
144 #ifdef __WIN32__
145     int is_shared = 0;
146     stdlib_t stdlib = STDLIB_NONE;
147     char *shared_flag = "";
148     char *stdlib_flag = "";
149     int have_link_args = 0;
150     args_t link_args = {0};
151 
152 #define CHECK_FIRST_LINK_ARG						\
153 	if (!have_link_args) {						\
154 	    save_arg(&link_args, "-link", NULL);			\
155 	    have_link_args = 1;						\
156 	}
157 #else /* #ifdef __WIN32__ */
158 #define CHECK_FIRST_LINK_ARG
159 #endif /* #ifdef __WIN32__ */
160 
161    prog = argv[0];
162 
163 
164     for (i = 1; i < argc; i++) {
165 	char *arg = argv[i];
166 	if (is_prefix("-CC", &arg)) {
167 	    cc = arg;
168 	}
169 	else if (is_prefix("-O", &arg)) {
170 	    if (!is_debug)
171 		save_arg(&args, argv[i], NULL);
172 	}
173 	else if (strcmp("-DDEBUG", arg) == 0) {
174 	    save_arg(&args, arg, NULL);
175 #ifdef __WIN32__
176 	set_debug:
177 #endif
178 	    if (!is_debug) {
179 		int j;
180 		is_debug = 1;
181 #ifdef __WIN32__
182 		save_arg(&args, "-Z7", NULL);
183 		CHECK_FIRST_LINK_ARG;
184 		save_arg(&link_args, "-debug", NULL);
185 		save_arg(&link_args, "-pdb:none", NULL);
186 #endif
187 		for (j = 0; j < args.ix; j++) {
188 		    char *tmp_arg = args.vec[j];
189 		    if (is_prefix("-O", &tmp_arg))
190 			args.vec[j] = "";
191 		}
192 	    }
193 	}
194 	else if (strcmp("-DPURIFY", arg) == 0) {
195 	    save_arg(&args, arg, NULL);
196 	    is_purify = 1;
197 	}
198 	else if (strcmp("-DQUANTIFY", arg) == 0) {
199 	    save_arg(&args, arg, NULL);
200 	    is_quantify = 1;
201 	}
202 	else if (strcmp("-DPURECOV", arg) == 0) {
203 	    save_arg(&args, arg, NULL);
204 	    is_purecov = 1;
205 	}
206 #ifdef __WIN32__
207 	else if (strcmp("-g", arg) == 0) {
208 	    goto set_debug;
209 	}
210 	else if (strcmp("-MD", arg) == 0)
211 	    stdlib = STDLIB_MD;
212 	else if (strcmp("-MDd", arg) == 0) {
213 	    stdlib = STDLIB_MD;
214 	    goto set_debug;
215 	}
216 	else if (strcmp("-ML", arg) == 0)
217 	    stdlib = STDLIB_ML;
218 	else if (strcmp("-MLd", arg) == 0) {
219 	    stdlib = STDLIB_ML;
220 	    goto set_debug;
221 	}
222 	else if (strcmp("-MT", arg) == 0)
223 	    stdlib = STDLIB_MT;
224 	else if (strcmp("-MTd", arg) == 0) {
225 	    stdlib = STDLIB_MT;
226 	    goto set_debug;
227 	}
228 	else if (strcmp("-shared", arg) == 0 || strcmp("-LD", arg) == 0)
229 	    is_shared = 1;
230 	else if (strcmp("-LDd", arg) == 0) {
231 	    is_shared = 1;
232 	    goto set_debug;
233 	}
234 	else if (strcmp("-Wall", arg) == 0) {
235 	    save_arg(&args, "-W3", NULL);
236 	}
237 	else if (is_prefix("-L", &arg)) {
238 	    CHECK_FIRST_LINK_ARG;
239 	    save_arg(&link_args, "-libpath:", arg, NULL);
240 	}
241 	else if (strcmp("-link",arg) == 0) {
242 	  CHECK_FIRST_LINK_ARG;
243 	}
244 #endif /* #ifdef __WIN32__ */
245 	else if (is_prefix("-l", &arg)) {
246 	    CHECK_FIRST_LINK_ARG;
247 	    if (is_debug && strcmp("ethread", arg) == 0)
248 		arg = "ethread.debug";
249 	    else if (is_purify && strcmp("ethread", arg) == 0)
250 		arg = "ethread.purify";
251 	    else if (is_quantify && strcmp("ethread", arg) == 0)
252 		arg = "ethread.quantify";
253 	    else if (is_purecov && strcmp("ethread", arg) == 0)
254 		arg = "ethread.purecov";
255 #ifdef __WIN32__
256 	    else if (strcmp("socket", arg) == 0)
257 		arg = "ws2_32";
258 	    save_arg(&link_args, arg, ".lib", NULL);
259 #else
260 	    save_arg(&args, "-l", arg, NULL);
261 #endif
262 	}
263 	else
264 	    save_arg(&args, argv[i], NULL);
265     }
266 
267     if (!cc || !cc[0]) {
268 	fprintf(stderr, "%s: Missing compulsory -CC flag%s", prog, EOL);
269 	exit(1);
270     }
271 
272     cmd_len = strlen(cc) + 1 + args.chars + 1;
273 
274 #ifdef __WIN32__
275     if (is_shared)
276 	shared_flag = is_debug ? "-LDd " : "-LD ";
277     switch (stdlib) {
278     case STDLIB_MD: stdlib_flag = is_debug ? "-MDd " : "-MD ";	break;
279     case STDLIB_ML: stdlib_flag = is_debug ? "-MLd " : "-ML ";	break;
280     case STDLIB_MT: stdlib_flag = is_debug ? "-MTd " : "-MT ";	break;
281     case STDLIB_NONE:						break;
282     }
283 
284     cmd_len += strlen(shared_flag) + strlen(stdlib_flag) + link_args.chars;
285 #endif
286 
287     cmd = (char *) malloc(sizeof(char) * cmd_len);
288 
289     if (!cmd)
290 	enomem();
291     cmd_end = cmd;
292     cpy(&cmd_end, cc);
293     cpy(&cmd_end, " ");
294 #ifdef __WIN32__
295     cpy(&cmd_end, stdlib_flag);
296     cpy(&cmd_end, shared_flag);
297 #endif
298     for (i = 0; i < args.ix; i++)
299 	cpy(&cmd_end, args.vec[i]);
300 #ifdef __WIN32__
301     for (i = 0; i < link_args.ix; i++)
302 	cpy(&cmd_end, link_args.vec[i]);
303 #endif
304     *cmd_end = '\0';
305 
306     printf("==> %s%s", cmd, EOL);
307     fflush(stdout);
308 
309 #ifdef USE_EXEC
310     (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
311     perror(NULL);
312     res = 1;
313 #else
314     res = system(cmd);
315 #endif
316 
317     free((void *) args.vec);
318 #ifdef __WIN32__
319     free((void *) link_args.vec);
320 #endif
321     free((void *) cmd);
322 
323     if (res < 0)
324 	res = 1;
325     return res;
326 }
327