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 #ifdef __WIN32__
142     int is_shared = 0;
143     stdlib_t stdlib = STDLIB_NONE;
144     char *shared_flag = "";
145     char *stdlib_flag = "";
146     int have_link_args = 0;
147     args_t link_args = {0};
148 
149 #define CHECK_FIRST_LINK_ARG						\
150 	if (!have_link_args) {						\
151 	    save_arg(&link_args, "-link", NULL);			\
152 	    have_link_args = 1;						\
153 	}
154 #else /* #ifdef __WIN32__ */
155 #define CHECK_FIRST_LINK_ARG
156 #endif /* #ifdef __WIN32__ */
157 
158    prog = argv[0];
159 
160 
161     for (i = 1; i < argc; i++) {
162 	char *arg = argv[i];
163 	if (is_prefix("-CC", &arg)) {
164 	    cc = arg;
165 	}
166 	else if (is_prefix("-O", &arg)) {
167 	    if (!is_debug)
168 		save_arg(&args, argv[i], NULL);
169 	}
170 	else if (strcmp("-DDEBUG", arg) == 0) {
171 	    save_arg(&args, arg, NULL);
172 #ifdef __WIN32__
173 	set_debug:
174 #endif
175 	    if (!is_debug) {
176 		int j;
177 		is_debug = 1;
178 #ifdef __WIN32__
179 		save_arg(&args, "-Z7", NULL);
180 		CHECK_FIRST_LINK_ARG;
181 		save_arg(&link_args, "-debug", NULL);
182 		save_arg(&link_args, "-pdb:none", NULL);
183 #endif
184 		for (j = 0; j < args.ix; j++) {
185 		    char *tmp_arg = args.vec[j];
186 		    if (is_prefix("-O", &tmp_arg))
187 			args.vec[j] = "";
188 		}
189 	    }
190 	}
191 #ifdef __WIN32__
192 	else if (strcmp("-g", arg) == 0) {
193 	    goto set_debug;
194 	}
195 	else if (strcmp("-MD", arg) == 0)
196 	    stdlib = STDLIB_MD;
197 	else if (strcmp("-MDd", arg) == 0) {
198 	    stdlib = STDLIB_MD;
199 	    goto set_debug;
200 	}
201 	else if (strcmp("-ML", arg) == 0)
202 	    stdlib = STDLIB_ML;
203 	else if (strcmp("-MLd", arg) == 0) {
204 	    stdlib = STDLIB_ML;
205 	    goto set_debug;
206 	}
207 	else if (strcmp("-MT", arg) == 0)
208 	    stdlib = STDLIB_MT;
209 	else if (strcmp("-MTd", arg) == 0) {
210 	    stdlib = STDLIB_MT;
211 	    goto set_debug;
212 	}
213 	else if (strcmp("-shared", arg) == 0 || strcmp("-LD", arg) == 0)
214 	    is_shared = 1;
215 	else if (strcmp("-LDd", arg) == 0) {
216 	    is_shared = 1;
217 	    goto set_debug;
218 	}
219 	else if (strcmp("-Wall", arg) == 0) {
220 	    save_arg(&args, "-W3", NULL);
221 	}
222 	else if (is_prefix("-L", &arg)) {
223 	    CHECK_FIRST_LINK_ARG;
224 	    save_arg(&link_args, "-libpath:", arg, NULL);
225 	}
226 	else if (strcmp("-link",arg) == 0) {
227 	  CHECK_FIRST_LINK_ARG;
228 	}
229 #endif /* #ifdef __WIN32__ */
230 	else if (is_prefix("-l", &arg)) {
231 	    CHECK_FIRST_LINK_ARG;
232 	    if (is_debug && strcmp("ethread", arg) == 0)
233 		arg = "ethread.debug";
234 #ifdef __WIN32__
235 	    else if (strcmp("socket", arg) == 0)
236 		arg = "ws2_32";
237 	    save_arg(&link_args, arg, ".lib", NULL);
238 #else
239 	    save_arg(&args, "-l", arg, NULL);
240 #endif
241 	}
242 	else
243 	    save_arg(&args, argv[i], NULL);
244     }
245 
246     if (!cc || !cc[0]) {
247 	fprintf(stderr, "%s: Missing compulsory -CC flag%s", prog, EOL);
248 	exit(1);
249     }
250 
251     cmd_len = strlen(cc) + 1 + args.chars + 1;
252 
253 #ifdef __WIN32__
254     if (is_shared)
255 	shared_flag = is_debug ? "-LDd " : "-LD ";
256     switch (stdlib) {
257     case STDLIB_MD: stdlib_flag = is_debug ? "-MDd " : "-MD ";	break;
258     case STDLIB_ML: stdlib_flag = is_debug ? "-MLd " : "-ML ";	break;
259     case STDLIB_MT: stdlib_flag = is_debug ? "-MTd " : "-MT ";	break;
260     case STDLIB_NONE:						break;
261     }
262 
263     cmd_len += strlen(shared_flag) + strlen(stdlib_flag) + link_args.chars;
264 #endif
265 
266     cmd = (char *) malloc(sizeof(char) * cmd_len);
267 
268     if (!cmd)
269 	enomem();
270     cmd_end = cmd;
271     cpy(&cmd_end, cc);
272     cpy(&cmd_end, " ");
273 #ifdef __WIN32__
274     cpy(&cmd_end, stdlib_flag);
275     cpy(&cmd_end, shared_flag);
276 #endif
277     for (i = 0; i < args.ix; i++)
278 	cpy(&cmd_end, args.vec[i]);
279 #ifdef __WIN32__
280     for (i = 0; i < link_args.ix; i++)
281 	cpy(&cmd_end, link_args.vec[i]);
282 #endif
283     *cmd_end = '\0';
284 
285     printf("==> %s%s", cmd, EOL);
286     fflush(stdout);
287 
288 #ifdef USE_EXEC
289     (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
290     perror(NULL);
291     res = 1;
292 #else
293     res = system(cmd);
294 #endif
295 
296     free((void *) args.vec);
297 #ifdef __WIN32__
298     free((void *) link_args.vec);
299 #endif
300     free((void *) cmd);
301 
302     if (res < 0)
303 	res = 1;
304     return res;
305 }
306