1 /*	$Id: cc.c,v 1.283.2.1 2014/12/06 09:52:55 ragge Exp $	*/
2 
3 /*-
4  * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  *
39  * Redistributions of source code and documentation must retain the above
40  * copyright notice, this list of conditions and the following disclaimer.
41  * Redistributions in binary form must reproduce the above copyright
42  * notice, this list of conditionsand the following disclaimer in the
43  * documentation and/or other materials provided with the distribution.
44  * All advertising materials mentioning features or use of this software
45  * must display the following acknowledgement:
46  * 	This product includes software developed or owned by Caldera
47  *	International, Inc.
48  * Neither the name of Caldera International, Inc. nor the names of other
49  * contributors may be used to endorse or promote products derived from
50  * this software without specific prior written permission.
51  *
52  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
53  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
54  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
55  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
56  * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
57  * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
61  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
62  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
63  * POSSIBILITY OF SUCH DAMAGE.
64  */
65 
66 /*
67  * Front-end to the C compiler.
68  *
69  * Brief description of its syntax:
70  * - Files that end with .c are passed via cpp->ccom->as->ld
71  * - Files that end with .i are passed via ccom->as->ld
72  * - Files that end with .S are passed via cpp->as->ld
73  * - Files that end with .s are passed via as->ld
74  * - Files that end with .o are passed directly to ld
75  * - Multiple files may be given on the command line.
76  * - Unrecognized options are all sent directly to ld.
77  * -c or -S cannot be combined with -o if multiple files are given.
78  *
79  * This file should be rewritten readable.
80  */
81 #include "config.h"
82 
83 #include <sys/types.h>
84 #ifdef HAVE_SYS_WAIT_H
85 #include <sys/wait.h>
86 #endif
87 
88 #include <ctype.h>
89 #include <errno.h>
90 #include <fcntl.h>
91 #ifdef HAVE_LIBGEN_H
92 #include <libgen.h>
93 #endif
94 #include <signal.h>
95 #include <stdarg.h>
96 #include <stdio.h>
97 #include <stdlib.h>
98 #include <string.h>
99 #ifdef HAVE_UNISTD_H
100 #include <unistd.h>
101 #endif
102 #include <assert.h>
103 
104 #ifdef os_win32
105 #include <windows.h>
106 #include <process.h>
107 #include <io.h>
108 #define F_OK	0x00
109 #define R_OK	0x04
110 #define W_OK	0x02
111 #define X_OK	R_OK
112 #endif
113 
114 #include "compat.h"
115 
116 #include "macdefs.h"
117 
118 #include "xalloc.h"
119 #include "strlist.h"
120 
121 #include "ccconfig.h"
122 /* C command */
123 
124 #define	MKS(x) _MKS(x)
125 #define _MKS(x) #x
126 
127 /* default program names in pcc */
128 /* May be overridden if cross-compiler is generated */
129 #ifndef CPPROGNAME
130 #define	CPPROGNAME	"cpp"	/* cc used as cpp */
131 #endif
132 #ifndef PREPROCESSOR
133 #define	PREPROCESSOR	"cpp"	/* "real" preprocessor name */
134 #endif
135 #ifndef COMPILER
136 #define COMPILER	"ccom"
137 #endif
138 #ifndef CXXCOMPILER
139 #define CXXCOMPILER	"cxxcom"
140 #endif
141 #ifndef ASSEMBLER
142 #define ASSEMBLER	"as"
143 #endif
144 #ifndef LINKER
145 #define LINKER		"ld"
146 #endif
147 char	*passp = PREPROCESSOR;
148 char	*pass0 = COMPILER;
149 char	*passxx0 = CXXCOMPILER;
150 char	*as = ASSEMBLER;
151 char	*ld = LINKER;
152 char	*sysroot = "", *isysroot;
153 
154 
155 /* crt files using pcc default names */
156 #ifndef CRTBEGIN_S
157 #define	CRTBEGIN_S	"crtbeginS.o"
158 #endif
159 #ifndef CRTEND_S
160 #define	CRTEND_S	"crtendS.o"
161 #endif
162 #ifndef CRTBEGIN_T
163 #define	CRTBEGIN_T	"crtbeginT.o"
164 #endif
165 #ifndef CRTEND_T
166 #define	CRTEND_T	"crtendT.o"
167 #endif
168 #ifndef CRTBEGIN
169 #define	CRTBEGIN	"crtbegin.o"
170 #endif
171 #ifndef CRTEND
172 #define	CRTEND		"crtend.o"
173 #endif
174 #ifndef CRTI
175 #define	CRTI		"crti.o"
176 #endif
177 #ifndef CRTN
178 #define	CRTN		"crtn.o"
179 #endif
180 #ifndef CRT0
181 #define	CRT0		"crt0.o"
182 #endif
183 #ifndef GCRT0
184 #define	GCRT0		"gcrt0.o"
185 #endif
186 
187 /* preprocessor stuff */
188 #ifndef STDINC
189 #define	STDINC	  	"/usr/include/"
190 #endif
191 #ifdef MULTIARCH_PATH
192 #define STDINC_MA	STDINC MULTIARCH_PATH "/"
193 #endif
194 
195 
196 char *cppadd[] = CPPADD;
197 char *cppmdadd[] = CPPMDADD;
198 
199 /* Dynamic linker definitions, per-target */
200 #ifndef DYNLINKER
201 #define	DYNLINKER { 0 }
202 #endif
203 
204 /* Default libraries and search paths */
205 #ifndef PCCLIBDIR	/* set by autoconf */
206 #define PCCLIBDIR	NULL
207 #endif
208 #ifndef DEFLIBDIRS	/* default library search paths */
209 #ifndef MULTIARCH_PATH
210 #define DEFLIBDIRS	{ "/usr/lib/", 0 }
211 #else
212 #define DEFLIBDIRS	{ "/usr/lib/", "/usr/lib/" MULTIARCH_PATH "/", 0 }
213 #endif
214 #endif
215 #ifndef DEFLIBS		/* default libraries included */
216 #define	DEFLIBS		{ "-lpcc", "-lc", "-lpcc", 0 }
217 #endif
218 #ifndef DEFPROFLIBS	/* default profiling libraries */
219 #define	DEFPROFLIBS	{ "-lpcc", "-lc_p", "-lpcc", 0 }
220 #endif
221 #ifndef DEFCXXLIBS	/* default c++ libraries */
222 #define	DEFCXXLIBS	{ "-lp++", "-lpcc", "-lc", "-lpcc", 0 }
223 #endif
224 #ifndef STARTLABEL
225 #define STARTLABEL "__start"
226 #endif
227 
228 char *dynlinker[] = DYNLINKER;
229 char *pcclibdir = PCCLIBDIR;
230 char *deflibdirs[] = DEFLIBDIRS;
231 char *deflibs[] = DEFLIBS;
232 char *defproflibs[] = DEFPROFLIBS;
233 char *defcxxlibs[] = DEFCXXLIBS;
234 
235 char	*outfile, *MFfile, *fname;
236 static char **lav;
237 static int lac;
238 static char *find_file(const char *file, struct strlist *path, int mode);
239 static int preprocess_input(char *input, char *output, int dodep);
240 static int compile_input(char *input, char *output);
241 static int assemble_input(char *input, char *output);
242 static int run_linker(void);
243 static int strlist_exec(struct strlist *l);
244 
245 char *cat(const char *, const char *);
246 char *setsuf(char *, char);
247 int cxxsuf(char *);
248 int getsuf(char *);
249 char *getsufp(char *s);
250 int main(int, char *[]);
251 void errorx(int, char *, ...);
252 int cunlink(char *);
253 void exandrm(char *);
254 void dexit(int);
255 void idexit(int);
256 char *gettmp(void);
257 void oerror(char *);
258 char *argnxt(char *, char *);
259 char *nxtopt(char *o);
260 void setup_cpp_flags(void);
261 void setup_ccom_flags(void);
262 void setup_as_flags(void);
263 void setup_ld_flags(void);
264 static void expand_sysroot(void);
265 #ifdef os_win32
266 char *win32pathsubst(char *);
267 char *win32commandline(struct strlist *l);
268 #endif
269 int	sspflag;
270 int	freestanding;
271 int	Sflag;
272 int	cflag;
273 int	gflag;
274 int	rflag;
275 int	vflag;
276 int	tflag;
277 int	Eflag;
278 int	Oflag;
279 int	kflag;	/* generate PIC/pic code */
280 #define F_PIC	1
281 #define F_pic	2
282 int	Mflag, needM, MDflag, MMDflag;	/* dependencies only */
283 int	pgflag;
284 int	Xflag;
285 int	nostartfiles, Bstatic, shared;
286 int	nostdinc, nostdlib;
287 int	pthreads;
288 int	xgnu89, xgnu99;
289 int 	ascpp;
290 #ifdef CHAR_UNSIGNED
291 int	xuchar = 1;
292 #else
293 int	xuchar = 0;
294 #endif
295 int	cxxflag;
296 int	cppflag;
297 int	printprogname, printfilename;
298 
299 #ifdef mach_amd64
300 int amd64_i386;
301 #endif
302 
303 #define	match(a,b)	(strcmp(a,b) == 0)
304 
305 /* handle gcc warning emulations */
306 struct Wflags {
307 	char *name;
308 	int flags;
309 #define	INWALL		1
310 } Wflags[] = {
311 	{ "truncate", 0 },
312 	{ "strict-prototypes", 0 },
313 	{ "missing-prototypes", 0 },
314 	{ "implicit-int", INWALL },
315 	{ "implicit-function-declaration", INWALL },
316 	{ "shadow", 0 },
317 	{ "pointer-sign", INWALL },
318 	{ "sign-compare", 0 },
319 	{ "unknown-pragmas", INWALL },
320 	{ "unreachable-code", 0 },
321 	{ "deprecated-declarations", 0 },
322 	{ "attributes", 0 },
323 	{ NULL, 0 },
324 };
325 
326 #ifndef USHORT
327 /* copied from mip/manifest.h */
328 #define	USHORT		5
329 #define	INT		6
330 #define	UNSIGNED	7
331 #endif
332 
333 /*
334  * Wide char defines.
335  */
336 #if WCHAR_TYPE == USHORT
337 #define	WCT "short unsigned int"
338 #define WCM "65535U"
339 #if WCHAR_SIZE != 2
340 #error WCHAR_TYPE vs. WCHAR_SIZE mismatch
341 #endif
342 #elif WCHAR_TYPE == INT
343 #define WCT "int"
344 #define WCM "2147483647"
345 #if WCHAR_SIZE != 4
346 #error WCHAR_TYPE vs. WCHAR_SIZE mismatch
347 #endif
348 #elif WCHAR_TYPE == UNSIGNED
349 #define WCT "unsigned int"
350 #define WCM "4294967295U"
351 #if WCHAR_SIZE != 4
352 #error WCHAR_TYPE vs. WCHAR_SIZE mismatch
353 #endif
354 #else
355 #error WCHAR_TYPE not defined or invalid
356 #endif
357 
358 #ifdef GCC_COMPAT
359 #ifndef REGISTER_PREFIX
360 #define REGISTER_PREFIX ""
361 #endif
362 #ifndef USER_LABEL_PREFIX
363 #define USER_LABEL_PREFIX ""
364 #endif
365 #endif
366 
367 #ifndef PCC_WINT_TYPE
368 #define PCC_WINT_TYPE "unsigned int"
369 #endif
370 
371 #ifndef PCC_SIZE_TYPE
372 #define PCC_SIZE_TYPE "unsigned long"
373 #endif
374 
375 #ifndef PCC_PTRDIFF_TYPE
376 #define PCC_PTRDIFF_TYPE "long int"
377 #endif
378 
379 
380 struct strlist preprocessor_flags;
381 struct strlist depflags;
382 struct strlist incdirs;
383 struct strlist user_sysincdirs;
384 struct strlist includes;
385 struct strlist sysincdirs;
386 struct strlist dirafterdirs;
387 struct strlist crtdirs;
388 struct strlist libdirs;
389 struct strlist progdirs;
390 struct strlist early_linker_flags;
391 struct strlist middle_linker_flags;
392 struct strlist late_linker_flags;
393 struct strlist inputs;
394 struct strlist assembler_flags;
395 struct strlist temp_outputs;
396 struct strlist compiler_flags;
397 
398 int
main(int argc,char * argv[])399 main(int argc, char *argv[])
400 {
401 	struct Wflags *Wf;
402 	struct string *s;
403 	char *t, *u, *argp;
404 	char *msuffix;
405 	int ninput, j;
406 
407 	lav = argv;
408 	lac = argc;
409 	ninput = 0;
410 
411 	strlist_init(&crtdirs);
412 	strlist_init(&libdirs);
413 	strlist_init(&progdirs);
414 	strlist_init(&preprocessor_flags);
415 	strlist_init(&incdirs);
416 	strlist_init(&user_sysincdirs);
417 	strlist_init(&includes);
418 	strlist_init(&sysincdirs);
419 	strlist_init(&dirafterdirs);
420 	strlist_init(&depflags);
421 	strlist_init(&early_linker_flags);
422 	strlist_init(&middle_linker_flags);
423 	strlist_init(&late_linker_flags);
424 	strlist_init(&inputs);
425 	strlist_init(&assembler_flags);
426 	strlist_init(&temp_outputs);
427 	strlist_init(&compiler_flags);
428 
429 	if ((t = strrchr(argv[0], '/')))
430 		t++;
431 	else
432 		t = argv[0];
433 
434 	if (match(t, "p++")) {
435 		cxxflag = 1;
436 	} else if (match(t, "cpp") || match(t, CPPROGNAME)) {
437 		Eflag = cppflag = 1;
438 	}
439 
440 #ifdef PCC_EARLY_SETUP
441 	PCC_EARLY_SETUP
442 #endif
443 
444 #ifdef os_win32
445 	/* have to prefix path early.  -B may override */
446 	incdir = win32pathsubst(incdir);
447 	altincdir = win32pathsubst(altincdir);
448 	libdir = win32pathsubst(libdir);
449 #ifdef PCCINCDIR
450 	pccincdir = win32pathsubst(pccincdir);
451 	pxxincdir = win32pathsubst(pxxincdir);
452 #endif
453 #ifdef PCCLIBDIR
454 	pcclibdir = win32pathsubst(pcclibdir);
455 #endif
456 	passp = win32pathsubst(passp);
457 	pass0 = win32pathsubst(pass0);
458 #ifdef STARTFILES
459 	for (i = 0; startfiles[i] != NULL; i++)
460 		startfiles[i] = win32pathsubst(startfiles[i]);
461 	for (i = 0; endfiles[i] != NULL; i++)
462 		endfiles[i] = win32pathsubst(endfiles[i]);
463 #endif
464 #ifdef STARTFILES_T
465 	for (i = 0; startfiles_T[i] != NULL; i++)
466 		startfiles_T[i] = win32pathsubst(startfiles_T[i]);
467 	for (i = 0; endfiles_T[i] != NULL; i++)
468 		endfiles_T[i] = win32pathsubst(endfiles_T[i]);
469 #endif
470 #ifdef STARTFILES_S
471 	for (i = 0; startfiles_S[i] != NULL; i++)
472 		startfiles_S[i] = win32pathsubst(startfiles_S[i]);
473 	for (i = 0; endfiles_S[i] != NULL; i++)
474 		endfiles_S[i] = win32pathsubst(endfiles_S[i]);
475 #endif
476 #endif
477 
478 	while (--lac) {
479 		++lav;
480 		argp = *lav;
481 
482 #ifdef PCC_EARLY_ARG_CHECK
483 		PCC_EARLY_ARG_CHECK
484 #endif
485 
486 		if (*argp != '-' || match(argp, "-")) {
487 			/* Check for duplicate .o files. */
488 			if (getsuf(argp) == 'o') {
489 				j = 0;
490 				STRLIST_FOREACH(s, &inputs)
491 					if (match(argp, s->value))
492 						j++;
493 				if (j)
494 					continue; /* skip it */
495 			}
496 			strlist_append(&inputs, argp);
497 			ninput++;
498 			continue;
499 		}
500 
501 		switch (argp[1]) {
502 		default:
503 			oerror(argp);
504 			break;
505 
506 		case '-': /* double -'s */
507 			if (match(argp, "--version")) {
508 				printf("%s\n", VERSSTR);
509 				return 0;
510 			} else if (strncmp(argp, "--sysroot=", 10) == 0) {
511 				sysroot = argp + 10;
512 			} else if (strcmp(argp, "--param") == 0) {
513 				/* NOTHING YET */;
514 				(void)nxtopt(0); /* ignore arg */
515 			} else
516 				oerror(argp);
517 			break;
518 
519 		case 'B': /* other search paths for binaries */
520 			t = nxtopt("-B");
521 			strlist_append(&crtdirs, t);
522 			strlist_append(&libdirs, t);
523 			strlist_append(&progdirs, t);
524 			break;
525 
526 		case 'C':
527 			if (match(argp, "-C") || match(argp, "-CC"))
528 				strlist_append(&preprocessor_flags, argp);
529 			else
530 				oerror(argp);
531 			break;
532 
533 		case 'c':
534 			cflag++;
535 			break;
536 
537 		case 'd': /* debug options */
538 			for (t = &argp[2]; *t; t++) {
539 				if (*t == 'M')
540 					strlist_append(&preprocessor_flags, "-dM");
541 
542 				/* ignore others */
543 			}
544 			break;
545 
546 		case 'E':
547 			Eflag++;
548 			break;
549 
550 		case 'f': /* GCC compatibility flags */
551 			u = &argp[2];
552 			j = 0;
553 			if (strncmp(u, "no-", 3) == 0)
554 				j = 1, u += 3;
555 			if (match(u, "PIC") || match(u, "pic")) {
556 				kflag = j ? 0 : *u == 'P' ? F_PIC : F_pic;
557 			} else if (match(u, "freestanding")) {
558 				freestanding = j ? 0 : 1;
559 			} else if (match(u, "signed-char")) {
560 				xuchar = j ? 1 : 0;
561 			} else if (match(u, "unsigned-char")) {
562 				xuchar = j ? 0 : 1;
563 			} else if (match(u, "stack-protector") ||
564 			    match(u, "stack-protector-all")) {
565 				sspflag = j ? 0 : 1;
566 			}
567 			/* silently ignore the rest */
568 			break;
569 
570 		case 'g': /* create debug output */
571 			if (argp[2] == '0')
572 				gflag = 0;
573 			else
574 				gflag++;
575 			break;
576 
577 
578 		case 'X':
579 			Xflag++;
580 			break;
581 
582 		case 'D':
583 		case 'U':
584 			strlist_append(&preprocessor_flags, argp);
585 			if (argp[2] != 0)
586 				break;
587 			strlist_append(&preprocessor_flags, nxtopt(argp));
588 			break;
589 
590 		case 'I': /* Add include dirs */
591 			strlist_append(&incdirs, nxtopt("-I"));
592 			break;
593 
594 		case 'i':
595 			if (match(argp, "-isystem")) {
596 				strlist_append(&user_sysincdirs, nxtopt(0));
597 			} else if (match(argp, "-include")) {
598 				strlist_append(&includes, nxtopt(0));
599 			} else if (match(argp, "-isysroot")) {
600 				isysroot = nxtopt(0);
601 			} else if (strcmp(argp, "-idirafter") == 0) {
602 				strlist_append(&dirafterdirs, nxtopt(0));
603 			} else
604 				oerror(argp);
605 			break;
606 
607 		case 'k': /* generate PIC code */
608 			kflag = argp[2] ? argp[2] - '0' : F_pic;
609 			break;
610 
611 		case 'l':
612 		case 'L':
613 			if (argp[2] == 0)
614 				argp = cat(argp, nxtopt(0));
615 			strlist_append(&inputs, argp);
616 			break;
617 
618 		case 'm': /* target-dependent options */
619 #ifdef mach_amd64
620 			/* need to call i386 ccom for this */
621 			if (strcmp(argp, "-melf_i386") == 0) {
622 				pass0 = LIBEXECDIR "/ccom_i386";
623 				amd64_i386 = 1;
624 				break;
625 			}
626 #endif
627 			strlist_append(&middle_linker_flags, argp);
628 			if (argp[2] == 0) {
629 				t = nxtopt(0);
630 				strlist_append(&middle_linker_flags, t);
631 			}
632 			break;
633 
634 		case 'n': /* handle -n flags */
635 			if (strcmp(argp, "-nostdinc") == 0)
636 				nostdinc++;
637 			else if (strcmp(argp, "-nostdlib") == 0) {
638 				nostdlib++;
639 				nostartfiles++;
640 			} else if (strcmp(argp, "-nostartfiles") == 0)
641 				nostartfiles = 1;
642 			else if (strcmp(argp, "-nodefaultlibs") == 0)
643 				nostdlib++;
644 			else
645 				oerror(argp);
646 			break;
647 
648 		case 'p':
649 			if (strcmp(argp, "-pg") == 0 ||
650 			    strcmp(argp, "-p") == 0)
651 				pgflag++;
652 			else if (strcmp(argp, "-pthread") == 0)
653 				pthreads++;
654 			else if (strcmp(argp, "-pipe") == 0)
655 				/* NOTHING YET */;
656 			else if (strcmp(argp, "-pedantic") == 0)
657 				/* NOTHING YET */;
658 			else if ((t = argnxt(argp, "-print-prog-name="))) {
659 				fname = t;
660 				printprogname = 1;
661 			} else if ((t = argnxt(argp, "-print-file-name="))) {
662 				fname = t;
663 				printfilename = 1;
664 			} else if (match(argp, "-print-libgcc-file-name")) {
665 				fname = "libpcc.a";
666 				printfilename = 1;
667 			} else
668 				oerror(argp);
669 			break;
670 
671 		case 'r':
672 			rflag = 1;
673 			break;
674 
675 		case 'T':
676 			strlist_append(&inputs, argp);
677 			if (argp[2] == 0 ||
678 			    strcmp(argp, "-Ttext") == 0 ||
679 			    strcmp(argp, "-Tdata") == 0 ||
680 			    strcmp(argp, "-Tbss") == 0)
681 				strlist_append(&inputs, nxtopt(0));
682 			break;
683 
684 		case 's':
685 			if (match(argp, "-shared")) {
686 				shared = 1;
687 			} else if (match(argp, "-static")) {
688 				Bstatic = 1;
689 			} else if (match(argp, "-symbolic")) {
690 				strlist_append(&middle_linker_flags,
691 				    "-Bsymbolic");
692 			} else if (strncmp(argp, "-std", 4) == 0) {
693 				if (strcmp(&argp[5], "gnu99") == 0 ||
694 				    strcmp(&argp[5], "gnu9x") == 0)
695 					xgnu99 = 1;
696 				if (strcmp(&argp[5], "gnu89") == 0)
697 					xgnu89 = 1;
698 			} else
699 				oerror(argp);
700 			break;
701 
702 		case 'S':
703 			Sflag++;
704 			cflag++;
705 			break;
706 
707 		case 't':
708 			tflag++;
709 			break;
710 
711 		case 'o':
712 			if (outfile)
713 				errorx(8, "too many -o");
714 			outfile = nxtopt("-o");
715 			break;
716 
717 		case 'O':
718 			if (argp[2] == '\0')
719 				Oflag++;
720 			else if (argp[3] == '\0' &&
721 			    isdigit((unsigned char)argp[2]))
722 				Oflag = argp[2] - '0';
723 			else if (argp[3] == '\0' && argp[2] == 's')
724 				Oflag = 1;	/* optimize for space only */
725 			else
726 				oerror(argp);
727 			break;
728 
729 		case 'P':
730 			strlist_append(&preprocessor_flags, argp);
731 			break;
732 
733 		case 'M':
734 			needM = 1;
735 			if (match(argp, "-M")) {
736 				Mflag++;
737 				strlist_append(&depflags, argp);
738 			} else if (match(argp, "-MP")) {
739 				strlist_append(&depflags, "-xMP");
740 			} else if (match(argp, "-MF")) {
741 				MFfile = nxtopt("-MF");
742 			} else if (match(argp, "-MT") || match(argp, "-MQ")) {
743 				t = cat("-xMT,", nxtopt("-MT"));
744 				t[3] = argp[2];
745 				strlist_append(&depflags, t);
746 			} else if (match(argp, "-MD")) {
747 				MDflag++;
748 				needM = 0;
749 				strlist_append(&depflags, "-M");
750 			} else if (match(argp, "-MMD")) {
751 				MMDflag++;
752 				needM = 0;
753 				strlist_append(&depflags, "-M");
754 				strlist_append(&depflags, "-xMMD");
755 			} else
756 				oerror(argp);
757 			break;
758 
759 		case 'v':
760 			printf("%s\n", VERSSTR);
761 			vflag++;
762 			break;
763 
764 		case 'w': /* no warnings at all emitted */
765 			strlist_append(&compiler_flags, "-w");
766 			break;
767 
768 		case 'W': /* Ignore (most of) W-flags */
769 			if ((t = argnxt(argp, "-Wl,"))) {
770 				u = strtok(t, ",");
771 				do {
772 					strlist_append(&inputs, u);
773 				} while ((u = strtok(NULL, ",")) != NULL);
774 			} else if ((t = argnxt(argp, "-Wa,"))) {
775 				u = strtok(t, ",");
776 				do {
777 					strlist_append(&assembler_flags, u);
778 				} while ((u = strtok(NULL, ",")) != NULL);
779 			} else if ((t = argnxt(argp, "-Wc,"))) {
780 				u = strtok(t, ",");
781 				do {
782 					strlist_append(&compiler_flags, u);
783 				} while ((u = strtok(NULL, ",")) != NULL);
784 			} else if ((t = argnxt(argp, "-Wp,"))) {
785 				u = strtok(t, ",");
786 				do {
787 					strlist_append(&preprocessor_flags, u);
788 				} while ((u = strtok(NULL, ",")) != NULL);
789 			} else if (strcmp(argp, "-Werror") == 0) {
790 				strlist_append(&compiler_flags, "-Werror");
791 				strlist_append(&preprocessor_flags, "-E");
792 			} else if (strcmp(argp, "-Wall") == 0) {
793 				for (Wf = Wflags; Wf->name; Wf++)
794 					if (Wf->flags & INWALL)
795 						strlist_append(&compiler_flags,
796 						    cat("-W", Wf->name));
797 			} else if (strcmp(argp, "-WW") == 0) {
798 				for (Wf = Wflags; Wf->name; Wf++)
799 					strlist_append(&compiler_flags,
800 					    cat("-W", Wf->name));
801 			} else {
802 				/* pass through, if supported */
803 				t = &argp[2];
804 				if (strncmp(t, "no-", 3) == 0)
805 					t += 3;
806 				if (strncmp(t, "error=", 6) == 0)
807 					t += 6;
808 				for (Wf = Wflags; Wf->name; Wf++) {
809 					if (strcmp(t, Wf->name) == 0)
810 						strlist_append(&compiler_flags,
811 						    argp);
812 				}
813 			}
814 			break;
815 
816 		case 'x':
817 			t = nxtopt("-x");
818 			if (match(t, "none"))
819 				strlist_append(&inputs, ")");
820 			else if (match(t, "c"))
821 				strlist_append(&inputs, ")c");
822 			else if (match(t, "assembler"))
823 				strlist_append(&inputs, ")s");
824 			else if (match(t, "assembler-with-cpp"))
825 				strlist_append(&inputs, ")S");
826 			else if (match(t, "c++"))
827 				strlist_append(&inputs, ")c++");
828 			else {
829 				strlist_append(&compiler_flags, "-x");
830 				strlist_append(&compiler_flags, t);
831 			}
832 			break;
833 
834 		}
835 		continue;
836 
837 	}
838 
839 	/* Sanity checking */
840 	if (cppflag) {
841 		if (ninput == 0) {
842 			strlist_append(&inputs, "-");
843 			ninput++;
844 		} else if (ninput > 2 || (ninput == 2 && outfile)) {
845 			errorx(8, "too many files");
846 		} else if (ninput == 2) {
847 			outfile = STRLIST_NEXT(STRLIST_FIRST(&inputs))->value;
848 			STRLIST_FIRST(&inputs)->next = NULL;
849 			ninput--;
850 		}
851 	}
852 	if (ninput == 0 && !(printprogname || printfilename))
853 		errorx(8, "no input files");
854 	if (outfile && (cflag || Sflag || Eflag) && ninput > 1)
855 		errorx(8, "-o given with -c || -E || -S and more than one file");
856 #if 0
857 	if (outfile && clist[0] && strcmp(outfile, clist[0]) == 0)
858 		errorx(8, "output file will be clobbered");
859 #endif
860 
861 	if (needM && !Mflag && !MDflag && !MMDflag)
862 		errorx(8, "to make dependencies needs -M");
863 
864 
865 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)	/* interrupt */
866 		signal(SIGINT, idexit);
867 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)	/* terminate */
868 		signal(SIGTERM, idexit);
869 
870 	/* after arg parsing */
871 	strlist_append(&progdirs, LIBEXECDIR);
872 	if (pcclibdir)
873 		strlist_append(&crtdirs, pcclibdir);
874 	for (j = 0; deflibdirs[j]; j++) {
875 		if (sysroot)
876 			deflibdirs[j] = cat(sysroot, deflibdirs[j]);
877 		strlist_append(&crtdirs, deflibdirs[j]);
878 	}
879 
880 	setup_cpp_flags();
881 	setup_ccom_flags();
882 	setup_as_flags();
883 
884 	if (isysroot == NULL)
885 		isysroot = sysroot;
886 	expand_sysroot();
887 
888 	if (printprogname) {
889 		printf("%s\n", find_file(fname, &progdirs, X_OK));
890 		return 0;
891 	} else if (printfilename) {
892 		printf("%s\n", find_file(fname, &crtdirs, R_OK));
893 		return 0;
894 	}
895 
896 	msuffix = NULL;
897 	STRLIST_FOREACH(s, &inputs) {
898 		char *suffix;
899 		char *ifile, *ofile = NULL;
900 
901 		ifile = s->value;
902 		if (ifile[0] == ')') { /* -x source type given */
903 			msuffix = ifile[1] ? &ifile[1] : NULL;
904 			continue;
905 		}
906 		if (ifile[0] == '-' && ifile[1] == 0)
907 			suffix = msuffix ? msuffix : "c";
908 		else if (ifile[0] == '-')
909 			suffix = "o"; /* source files cannot begin with - */
910 		else if (msuffix)
911 			suffix = msuffix;
912 		else
913 			suffix = getsufp(ifile);
914 		/*
915 		 * C preprocessor
916 		 */
917 		ascpp = match(suffix, "S");
918 		if (ascpp || match(suffix, "c") || cxxsuf(suffix)) {
919 			/* find out next output file */
920 			if (Mflag || MDflag || MMDflag) {
921 				char *Mofile = NULL;
922 
923 				if (MFfile)
924 					Mofile = MFfile;
925 				else if (outfile)
926 					Mofile = setsuf(outfile, 'd');
927 				else if (MDflag || MMDflag)
928 					Mofile = setsuf(ifile, 'd');
929 				if (preprocess_input(ifile, Mofile, 1))
930 					exandrm(Mofile);
931 			}
932 			if (Mflag)
933 				continue;
934 			if (Eflag) {
935 				/* last pass */
936 				ofile = outfile;
937 			} else {
938 				/* to temp file */
939 				strlist_append(&temp_outputs, ofile = gettmp());
940 			}
941 			if (preprocess_input(ifile, ofile, 0))
942 				exandrm(ofile);
943 			if (Eflag)
944 				continue;
945 			ifile = ofile;
946 			suffix = match(suffix, "S") ? "s" : "i";
947 		}
948 
949 		/*
950 		 * C compiler
951 		 */
952 		if (match(suffix, "i")) {
953 			/* find out next output file */
954 			if (Sflag) {
955 				ofile = outfile;
956 				if (outfile == NULL)
957 					ofile = setsuf(s->value, 's');
958 			} else
959 				strlist_append(&temp_outputs, ofile = gettmp());
960 			if (compile_input(ifile, ofile))
961 				exandrm(ofile);
962 			if (Sflag)
963 				continue;
964 			ifile = ofile;
965 			suffix = "s";
966 		}
967 
968 		/*
969 		 * Assembler
970 		 */
971 		if (match(suffix, "s")) {
972 			if (cflag) {
973 				ofile = outfile;
974 				if (ofile == NULL)
975 					ofile = setsuf(s->value, 'o');
976 			} else {
977 				strlist_append(&temp_outputs, ofile = gettmp());
978 				/* strlist_append linker */
979 			}
980 			if (assemble_input(ifile, ofile))
981 				exandrm(ofile);
982 			ifile = ofile;
983 		}
984 
985 		if (ninput > 1 && !Eflag && ifile == ofile && ifile[0] != '-')
986 			printf("%s:\n", ifile);
987 
988 		strlist_append(&middle_linker_flags, ifile);
989 	}
990 
991 	if (cflag || Eflag || Mflag)
992 		dexit(0);
993 
994 	/*
995 	 * Linker
996 	 */
997 	setup_ld_flags();
998 	if (run_linker())
999 		exandrm(0);
1000 
1001 #ifdef notdef
1002 	strlist_free(&crtdirs);
1003 	strlist_free(&libdirs);
1004 	strlist_free(&progdirs);
1005 	strlist_free(&incdirs);
1006 	strlist_free(&preprocessor_flags);
1007 	strlist_free(&user_sysincdirs);
1008 	strlist_free(&includes);
1009 	strlist_free(&sysincdirs);
1010 	strlist_free(&dirafterdirs);
1011 	strlist_free(&depflags);
1012 	strlist_free(&early_linker_flags);
1013 	strlist_free(&middle_linker_flags);
1014 	strlist_free(&late_linker_flags);
1015 	strlist_free(&inputs);
1016 	strlist_free(&assembler_flags);
1017 	strlist_free(&temp_outputs);
1018 	strlist_free(&compiler_flags);
1019 #endif
1020 	dexit(0);
1021 	return 0;
1022 }
1023 
1024 /*
1025  * exit and cleanup after interrupt.
1026  */
1027 void
idexit(int arg)1028 idexit(int arg)
1029 {
1030 	dexit(100);
1031 }
1032 
1033 /*
1034  * exit and cleanup.
1035  */
1036 void
dexit(int eval)1037 dexit(int eval)
1038 {
1039 	struct string *s;
1040 
1041 	if (!Xflag) {
1042 		STRLIST_FOREACH(s, &temp_outputs)
1043 			cunlink(s->value);
1044 	}
1045 	exit(eval);
1046 }
1047 
1048 /*
1049  * Called when something failed.
1050  */
1051 void
exandrm(char * s)1052 exandrm(char *s)
1053 {
1054 	if (s && *s)
1055 		strlist_append(&temp_outputs, s);
1056 	dexit(1);
1057 }
1058 
1059 /*
1060  * complain and exit.
1061  */
1062 void
errorx(int eval,char * s,...)1063 errorx(int eval, char *s, ...)
1064 {
1065 	va_list ap;
1066 
1067 	va_start(ap, s);
1068 	fputs("error: ", stderr);
1069 	vfprintf(stderr, s, ap);
1070 	putc('\n', stderr);
1071 	va_end(ap);
1072 	dexit(eval);
1073 }
1074 
1075 static char *
find_file(const char * file,struct strlist * path,int mode)1076 find_file(const char *file, struct strlist *path, int mode)
1077 {
1078 	struct string *s;
1079 	char *f;
1080 	size_t lf, lp;
1081 	int need_sep;
1082 
1083 	lf = strlen(file);
1084 	STRLIST_FOREACH(s, path) {
1085 		lp = strlen(s->value);
1086 		need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0;
1087 		f = xmalloc(lp + lf + need_sep + 1);
1088 		memcpy(f, s->value, lp);
1089 		if (need_sep)
1090 			f[lp] = '/';
1091 		memcpy(f + lp + need_sep, file, lf + 1);
1092 		if (access(f, mode) == 0)
1093 			return f;
1094 		free(f);
1095 	}
1096 	return xstrdup(file);
1097 }
1098 
1099 static int
compile_input(char * input,char * output)1100 compile_input(char *input, char *output)
1101 {
1102 	struct strlist args;
1103 	int retval;
1104 
1105 	strlist_init(&args);
1106 	strlist_append_list(&args, &compiler_flags);
1107 	strlist_append(&args, input);
1108 	strlist_append(&args, output);
1109 	strlist_prepend(&args,
1110 	    find_file(cxxflag ? passxx0 : pass0, &progdirs, X_OK));
1111 	retval = strlist_exec(&args);
1112 	strlist_free(&args);
1113 	return retval;
1114 }
1115 
1116 static int
assemble_input(char * input,char * output)1117 assemble_input(char *input, char *output)
1118 {
1119 	struct strlist args;
1120 	int retval;
1121 
1122 	strlist_init(&args);
1123 #ifdef PCC_EARLY_AS_ARGS
1124 	PCC_EARLY_AS_ARGS
1125 #endif
1126 	strlist_append_list(&args, &assembler_flags);
1127 	strlist_append(&args, input);
1128 	strlist_append(&args, "-o");
1129 	strlist_append(&args, output);
1130 	strlist_prepend(&args,
1131 	    find_file(as, &progdirs, X_OK));
1132 #ifdef PCC_LATE_AS_ARGS
1133 	PCC_LATE_AS_ARGS
1134 #endif
1135 	retval = strlist_exec(&args);
1136 	strlist_free(&args);
1137 	return retval;
1138 }
1139 
1140 static int
preprocess_input(char * input,char * output,int dodep)1141 preprocess_input(char *input, char *output, int dodep)
1142 {
1143 	struct strlist args;
1144 	struct string *s;
1145 	int retval;
1146 
1147 	strlist_init(&args);
1148 	strlist_append_list(&args, &preprocessor_flags);
1149 	if (ascpp) {
1150 		strlist_append(&args, "-A");
1151 		strlist_append(&args, "-D__ASSEMBLER__");
1152 	}
1153 	STRLIST_FOREACH(s, &includes) {
1154 		strlist_append(&args, "-i");
1155 		strlist_append(&args, s->value);
1156 	}
1157 	STRLIST_FOREACH(s, &incdirs) {
1158 		strlist_append(&args, "-I");
1159 		strlist_append(&args, s->value);
1160 	}
1161 	STRLIST_FOREACH(s, &user_sysincdirs) {
1162 		strlist_append(&args, "-S");
1163 		strlist_append(&args, s->value);
1164 	}
1165 	if (!nostdinc) {
1166 		STRLIST_FOREACH(s, &sysincdirs) {
1167 			strlist_append(&args, "-S");
1168 			strlist_append(&args, s->value);
1169 		}
1170 	}
1171 	if (dodep)
1172 		strlist_append_list(&args, &depflags);
1173 	strlist_append(&args, input);
1174 	if (output)
1175 		strlist_append(&args, output);
1176 
1177 	strlist_prepend(&args, find_file(passp, &progdirs, X_OK));
1178 	retval = strlist_exec(&args);
1179 	strlist_free(&args);
1180 	return retval;
1181 }
1182 
1183 static int
run_linker(void)1184 run_linker(void)
1185 {
1186 	struct strlist linker_flags;
1187 	int retval;
1188 
1189 	if (outfile) {
1190 		strlist_prepend(&early_linker_flags, outfile);
1191 		strlist_prepend(&early_linker_flags, "-o");
1192 	}
1193 	strlist_init(&linker_flags);
1194 	strlist_append_list(&linker_flags, &early_linker_flags);
1195 	strlist_append_list(&linker_flags, &middle_linker_flags);
1196 	strlist_append_list(&linker_flags, &late_linker_flags);
1197 	strlist_prepend(&linker_flags, find_file(ld, &progdirs, X_OK));
1198 
1199 	retval = strlist_exec(&linker_flags);
1200 
1201 	strlist_free(&linker_flags);
1202 	return retval;
1203 }
1204 
1205 static char *cxxt[] = { "cc", "cp", "cxx", "cpp", "CPP", "c++", "C" };
1206 int
cxxsuf(char * s)1207 cxxsuf(char *s)
1208 {
1209 	unsigned i;
1210 	for (i = 0; i < sizeof(cxxt)/sizeof(cxxt[0]); i++)
1211 		if (strcmp(s, cxxt[i]) == 0)
1212 			return 1;
1213 	return 0;
1214 }
1215 
1216 char *
getsufp(char * s)1217 getsufp(char *s)
1218 {
1219 	register char *p;
1220 
1221 	if ((p = strrchr(s, '.')) && p[1] != '\0')
1222 		return &p[1];
1223 	return "";
1224 }
1225 
1226 int
getsuf(char * s)1227 getsuf(char *s)
1228 {
1229 	register char *p;
1230 
1231 	if ((p = strrchr(s, '.')) && p[1] != '\0' && p[2] == '\0')
1232 		return p[1];
1233 	return(0);
1234 }
1235 
1236 /*
1237  * Get basename of string s, copy it and change its suffix to ch.
1238  */
1239 char *
setsuf(char * s,char ch)1240 setsuf(char *s, char ch)
1241 {
1242 	char *e, *p, *rp;
1243 
1244 	e = NULL;
1245 	for (p = s; *p; p++) {
1246 		if (*p == '/')
1247 			s = p + 1;
1248 		if (*p == '.')
1249 			e = p;
1250 	}
1251 	if (s > e)
1252 		e = p;
1253 
1254 	rp = p = xmalloc(e - s + 3);
1255 	while (s < e)
1256 		*p++ = *s++;
1257 
1258 	*p++ = '.';
1259 	*p++ = ch;
1260 	*p = '\0';
1261 	return rp;
1262 }
1263 
1264 #ifdef os_win32
1265 
1266 static int
strlist_exec(struct strlist * l)1267 strlist_exec(struct strlist *l)
1268 {
1269 	char *cmd;
1270 	STARTUPINFO si;
1271 	PROCESS_INFORMATION pi;
1272 	DWORD exitCode;
1273 	BOOL ok;
1274 
1275 	cmd = win32commandline(l);
1276 	if (vflag)
1277 		printf("%s\n", cmd);
1278 
1279 	ZeroMemory(&si, sizeof(STARTUPINFO));
1280 	si.cb = sizeof(STARTUPINFO);
1281 	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
1282 
1283 	ok = CreateProcess(NULL,  // the executable program
1284 		cmd,   // the command line arguments
1285 		NULL,       // ignored
1286 		NULL,       // ignored
1287 		TRUE,       // inherit handles
1288 		HIGH_PRIORITY_CLASS,
1289 		NULL,       // ignored
1290 		NULL,       // ignored
1291 		&si,
1292 		&pi);
1293 
1294 	if (!ok)
1295 		errorx(100, "Can't find %s\n", STRLIST_FIRST(l)->value);
1296 
1297 	WaitForSingleObject(pi.hProcess, INFINITE);
1298 	GetExitCodeProcess(pi.hProcess, &exitCode);
1299 	CloseHandle(pi.hProcess);
1300 	CloseHandle(pi.hThread);
1301 
1302 	return (exitCode != 0);
1303 }
1304 
1305 #else
1306 
1307 static int
strlist_exec(struct strlist * l)1308 strlist_exec(struct strlist *l)
1309 {
1310 	sig_atomic_t exit_now = 0;
1311 	sig_atomic_t child;
1312 	char **argv;
1313 	size_t argc;
1314 	int result;
1315 
1316 	strlist_make_array(l, &argv, &argc);
1317 	if (vflag) {
1318 		printf("Calling ");
1319 		strlist_print(l, stdout);
1320 		printf("\n");
1321 	}
1322 
1323 	switch ((child = fork())) {
1324 	case 0:
1325 		execvp(argv[0], argv);
1326 		result = write(STDERR_FILENO, "Exec of ", 8);
1327 		result = write(STDERR_FILENO, argv[0], strlen(argv[0]));
1328 		result = write(STDERR_FILENO, " failed\n", 7);
1329 		(void)result;
1330 		_exit(127);
1331 	case -1:
1332 		errorx(1, "fork failed");
1333 	default:
1334 		while (waitpid(child, &result, 0) == -1 && errno == EINTR)
1335 			/* nothing */(void)0;
1336 		result = WEXITSTATUS(result);
1337 		if (result)
1338 			errorx(1, "%s terminated with status %d", argv[0], result);
1339 		while (argc-- > 0)
1340 			free(argv[argc]);
1341 		free(argv);
1342 		break;
1343 	}
1344 	return exit_now;
1345 }
1346 
1347 #endif
1348 
1349 /*
1350  * Catenate two (optional) strings together
1351  */
1352 char *
cat(const char * a,const char * b)1353 cat(const char *a, const char *b)
1354 {
1355 	size_t len;
1356 	char *rv;
1357 
1358 	len = (a ? strlen(a) : 0) + (b ? strlen(b) : 0) + 1;
1359 	rv = xmalloc(len);
1360 	snprintf(rv, len, "%s%s", (a ? a : ""), (b ? b : ""));
1361 	return rv;
1362 }
1363 
1364 int
cunlink(char * f)1365 cunlink(char *f)
1366 {
1367 	if (f==0 || Xflag)
1368 		return(0);
1369 	return (unlink(f));
1370 }
1371 
1372 #ifdef os_win32
1373 char *
gettmp(void)1374 gettmp(void)
1375 {
1376 	DWORD pathSize;
1377 	char pathBuffer[MAX_PATH + 1];
1378 	char tempFilename[MAX_PATH];
1379 	UINT uniqueNum;
1380 
1381 	pathSize = GetTempPath(sizeof(pathBuffer), pathBuffer);
1382 	if (pathSize == 0 || pathSize > sizeof(pathBuffer))
1383 		pathBuffer[0] = '\0';
1384 	uniqueNum = GetTempFileName(pathBuffer, "ctm", 0, tempFilename);
1385 	if (uniqueNum == 0)
1386 		errorx(8, "GetTempFileName failed: path \"%s\"", pathBuffer);
1387 
1388 	return xstrdup(tempFilename);
1389 }
1390 
1391 #else
1392 
1393 char *
gettmp(void)1394 gettmp(void)
1395 {
1396 	char *sfn = xstrdup("/tmp/ctm.XXXXXX");
1397 	int fd = -1;
1398 
1399 	if ((fd = mkstemp(sfn)) == -1)
1400 		errorx(8, "%s: %s\n", sfn, strerror(errno));
1401 	close(fd);
1402 	return sfn;
1403 }
1404 #endif
1405 
1406 static void
expand_sysroot(void)1407 expand_sysroot(void)
1408 {
1409 	struct string *s;
1410 	struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs,
1411 	    &user_sysincdirs, &libdirs, &progdirs, &dirafterdirs, NULL };
1412 	const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot,
1413 	    sysroot, sysroot, isysroot, NULL };
1414 	size_t i, sysroot_len, value_len;
1415 	char *path;
1416 
1417 	assert(sizeof(lists) / sizeof(lists[0]) ==
1418 	       sizeof(sysroots) / sizeof(sysroots[0]));
1419 
1420 	for (i = 0; lists[i] != NULL; ++i) {
1421 		STRLIST_FOREACH(s, lists[i]) {
1422 			if (s->value[0] != '=')
1423 				continue;
1424 			sysroot_len = strlen(sysroots[i]);
1425 			/* Skipped '=' compensates additional space for '\0' */
1426 			value_len = strlen(s->value);
1427 			path = xmalloc(sysroot_len + value_len);
1428 			memcpy(path, sysroots[i], sysroot_len);
1429 			memcpy(path + sysroot_len, s->value + 1, value_len);
1430 			free(s->value);
1431 			s->value = path;
1432 		}
1433 	}
1434 }
1435 
1436 void
oerror(char * s)1437 oerror(char *s)
1438 {
1439 	errorx(8, "unknown option '%s'", s);
1440 }
1441 
1442 /*
1443  * See if m matches the beginning of string str, if it does return the
1444  * remaining of str, otherwise NULL.
1445  */
1446 char *
argnxt(char * str,char * m)1447 argnxt(char *str, char *m)
1448 {
1449 	if (strncmp(str, m, strlen(m)))
1450 		return NULL; /* No match */
1451 	return str + strlen(m);
1452 }
1453 
1454 /*
1455  * Return next argument to option, or complain.
1456  */
1457 char *
nxtopt(char * o)1458 nxtopt(char *o)
1459 {
1460 	int l;
1461 
1462 	if (o != NULL) {
1463 		l = strlen(o);
1464 		if (lav[0][l] != 0)
1465 			return &lav[0][l];
1466 	}
1467 	if (lac == 0)
1468 		errorx(8, "missing argument to '%s'", o);
1469 	lav++;
1470 	lac--;
1471 	return lav[0];
1472 }
1473 
1474 struct flgcheck {
1475 	int *flag;
1476 	int set;
1477 	char *def;
1478 } cppflgcheck[] = {
1479 	{ &vflag, 1, "-v" },
1480 	{ &freestanding, 1, "-D__STDC_HOSTED__=0" },
1481 	{ &freestanding, 0, "-D__STDC_HOSTED__=1" },
1482 	{ &cxxflag, 1, "-D__cplusplus" },
1483 	{ &xuchar, 1, "-D__CHAR_UNSIGNED__" },
1484 	{ &sspflag, 1, "-D__SSP__" },
1485 	{ &pthreads, 1, "-D_PTHREADS" },
1486 	{ &Oflag, 1, "-D__OPTIMIZE__" },
1487 	{ &tflag, 1, "-t" },
1488 	{ &kflag, 1, "-D__PIC__" },
1489 	{ 0 },
1490 };
1491 
1492 static void
cksetflags(struct flgcheck * fs,struct strlist * sl,int which)1493 cksetflags(struct flgcheck *fs, struct strlist *sl, int which)
1494 {
1495 	void (*fn)(struct strlist *, const char *);
1496 
1497 	fn = which == 'p' ? strlist_prepend : strlist_append;
1498 	for (; fs->flag; fs++) {
1499 		if (fs->set && *fs->flag)
1500 			fn(sl, fs->def);
1501 		if (!fs->set && !*fs->flag)
1502 			fn(sl, fs->def);
1503 	}
1504 }
1505 
1506 #ifndef TARGET_LE
1507 #define TARGET_LE       1
1508 #define TARGET_BE       2
1509 #define TARGET_PDP      3
1510 #define TARGET_ANY      4
1511 #endif
1512 
1513 static char *defflags[] = {
1514 	"-D__PCC__=" MKS(PCC_MAJOR),
1515 	"-D__PCC_MINOR__=" MKS(PCC_MINOR),
1516 	"-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR),
1517 	"-D__VERSION__=" MKS(VERSSTR),
1518 	"-D__SCHAR_MAX__=" MKS(MAX_CHAR),
1519 	"-D__SHRT_MAX__=" MKS(MAX_SHORT),
1520 	"-D__INT_MAX__=" MKS(MAX_INT),
1521 	"-D__LONG_MAX__=" MKS(MAX_LONG),
1522 	"-D__LONG_LONG_MAX__=" MKS(MAX_LONGLONG),
1523 
1524 	"-D__STDC_ISO_10646__=200009L",
1525 	"-D__WCHAR_TYPE__=" WCT,
1526 	"-D__SIZEOF_WCHAR_T__=" MKS(WCHAR_SIZE),
1527 	"-D__WCHAR_MAX__=" WCM,
1528 	"-D__WINT_TYPE__=" PCC_WINT_TYPE,
1529 	"-D__SIZE_TYPE__=" PCC_SIZE_TYPE,
1530 	"-D__PTRDIFF_TYPE__=" PCC_PTRDIFF_TYPE,
1531 	"-D__SIZEOF_WINT_T__=4",
1532 	"-D__ORDER_LITTLE_ENDIAN__=1234",
1533 	"-D__ORDER_BIG_ENDIAN__=4321",
1534 	"-D__ORDER_PDP_ENDIAN__=3412",
1535 /*
1536  * These should probably be changeable during runtime...
1537  */
1538 #if TARGET_ENDIAN == TARGET_BE
1539 	"-D__FLOAT_WORD_ORDER__=__ORDER_BIG_ENDIAN__",
1540 	"-D__BYTE_ORDER__=__ORDER_BIG_ENDIAN__",
1541 #elif TARGET_ENDIAN == TARGET_PDP
1542 	"-D__FLOAT_WORD_ORDER__=__ORDER_PDP_ENDIAN__",
1543 	"-D__BYTE_ORDER__=__ORDER_PDP_ENDIAN__",
1544 #elif TARGET_ENDIAN == TARGET_LE
1545 	"-D__FLOAT_WORD_ORDER__=__ORDER_LITTLE_ENDIAN__",
1546 	"-D__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__",
1547 #else
1548 #error Unknown endian...
1549 #endif
1550 };
1551 
1552 static char *gcppflags[] = {
1553 #ifndef os_win32
1554 #ifdef GCC_COMPAT
1555 	"-D__GNUC__=4",
1556 	"-D__GNUC_MINOR__=3",
1557 	"-D__GNUC_PATCHLEVEL__=1",
1558 	"-D__REGISTER_PREFIX__=" REGISTER_PREFIX,
1559 	"-D__USER_LABEL_PREFIX__=" USER_LABEL_PREFIX,
1560 #if SZLONG == 64
1561 	"-D__SIZEOF_LONG__=8",
1562 #elif SZLONG == 32
1563 	"-D__SIZEOF_LONG__=4",
1564 #endif
1565 #if SZPOINT(CHAR) == 64
1566 	"-D__SIZEOF_POINTER__=8",
1567 #elif SZPOINT(CHAR) == 32
1568 	"-D__SIZEOF_POINTER__=4",
1569 #endif
1570 #endif
1571 #endif
1572 };
1573 
1574 /* These should _not_ be defined here */
1575 static char *fpflags[] = {
1576 #ifdef TARGET_FLT_EVAL_METHOD
1577 	"-D__FLT_EVAL_METHOD__=" MKS(TARGET_FLT_EVAL_METHOD),
1578 #endif
1579 #if defined(os_darwin) || defined(os_netbsd)
1580 	"-D__FLT_RADIX__=2",
1581 #if defined(mach_vax)
1582 	"-D__FLT_DIG__=6",
1583 	"-D__FLT_EPSILON__=1.19209290e-07F",
1584 	"-D__FLT_MANT_DIG__=24",
1585 	"-D__FLT_MAX_10_EXP__=38",
1586 	"-D__FLT_MAX_EXP__=127",
1587 	"-D__FLT_MAX__=1.70141173e+38F",
1588 	"-D__FLT_MIN_10_EXP__=(-38)",
1589 	"-D__FLT_MIN_EXP__=(-127)",
1590 	"-D__FLT_MIN__=2.93873588e-39F",
1591 	"-D__DBL_DIG__=16",
1592 	"-D__DBL_EPSILON__=2.77555756156289135e-17",
1593 	"-D__DBL_MANT_DIG__=56",
1594 	"-D__DBL_MAX_10_EXP__=38",
1595 	"-D__DBL_MAX_EXP__=127",
1596 	"-D__DBL_MAX__=1.701411834604692294e+38",
1597 	"-D__DBL_MIN_10_EXP__=(-38)",
1598 	"-D__DBL_MIN_EXP__=(-127)",
1599 	"-D__DBL_MIN__=2.938735877055718770e-39",
1600 #else
1601 	"-D__FLT_DIG__=6",
1602 	"-D__FLT_EPSILON__=1.19209290e-07F",
1603 	"-D__FLT_MANT_DIG__=24",
1604 	"-D__FLT_MAX_10_EXP__=38",
1605 	"-D__FLT_MAX_EXP__=128",
1606 	"-D__FLT_MAX__=3.40282347e+38F",
1607 	"-D__FLT_MIN_10_EXP__=(-37)",
1608 	"-D__FLT_MIN_EXP__=(-125)",
1609 	"-D__FLT_MIN__=1.17549435e-38F",
1610 	"-D__DBL_DIG__=15",
1611 	"-D__DBL_EPSILON__=2.2204460492503131e-16",
1612 	"-D__DBL_MANT_DIG__=53",
1613 	"-D__DBL_MAX_10_EXP__=308",
1614 	"-D__DBL_MAX_EXP__=1024",
1615 	"-D__DBL_MAX__=1.7976931348623157e+308",
1616 	"-D__DBL_MIN_10_EXP__=(-307)",
1617 	"-D__DBL_MIN_EXP__=(-1021)",
1618 	"-D__DBL_MIN__=2.2250738585072014e-308",
1619 #endif
1620 #if defined(mach_i386) || defined(mach_amd64)
1621 	"-D__LDBL_DIG__=18",
1622 	"-D__LDBL_EPSILON__=1.08420217248550443401e-19L",
1623 	"-D__LDBL_MANT_DIG__=64",
1624 	"-D__LDBL_MAX_10_EXP__=4932",
1625 	"-D__LDBL_MAX_EXP__=16384",
1626 	"-D__LDBL_MAX__=1.18973149535723176502e+4932L",
1627 	"-D__LDBL_MIN_10_EXP__=(-4931)",
1628 	"-D__LDBL_MIN_EXP__=(-16381)",
1629 	"-D__LDBL_MIN__=3.36210314311209350626e-4932L",
1630 #elif defined(mach_vax)
1631 	"-D__LDBL_DIG__=16",
1632 	"-D__LDBL_EPSILON__=2.77555756156289135e-17",
1633 	"-D__LDBL_MANT_DIG__=56",
1634 	"-D__LDBL_MAX_10_EXP__=38",
1635 	"-D__LDBL_MAX_EXP__=127",
1636 	"-D__LDBL_MAX__=1.701411834604692294e+38",
1637 	"-D__LDBL_MIN_10_EXP__=(-38)",
1638 	"-D__LDBL_MIN_EXP__=(-127)",
1639 	"-D__LDBL_MIN__=2.938735877055718770e-39",
1640 #else
1641 	"-D__LDBL_DIG__=15",
1642 	"-D__LDBL_EPSILON__=2.2204460492503131e-16",
1643 	"-D__LDBL_MANT_DIG__=53",
1644 	"-D__LDBL_MAX_10_EXP__=308",
1645 	"-D__LDBL_MAX_EXP__=1024",
1646 	"-D__LDBL_MAX__=1.7976931348623157e+308",
1647 	"-D__LDBL_MIN_10_EXP__=(-307)",
1648 	"-D__LDBL_MIN_EXP__=(-1021)",
1649 	"-D__LDBL_MIN__=2.2250738585072014e-308",
1650 #endif
1651 #endif
1652 };
1653 
1654 /*
1655  * Configure the standard cpp flags.
1656  */
1657 void
setup_cpp_flags(void)1658 setup_cpp_flags(void)
1659 {
1660 	int i;
1661 
1662 	/* a bunch of misc defines */
1663 	for (i = 0; i < (int)sizeof(defflags)/(int)sizeof(char *); i++)
1664 		strlist_prepend(&preprocessor_flags, defflags[i]);
1665 
1666 	for (i = 0; i < (int)sizeof(gcppflags)/(int)sizeof(char *); i++)
1667 		strlist_prepend(&preprocessor_flags, gcppflags[i]);
1668 	strlist_prepend(&preprocessor_flags, xgnu89 ?
1669 	    "-D__GNUC_GNU_INLINE__" : "-D__GNUC_STDC_INLINE__");
1670 
1671 	cksetflags(cppflgcheck, &preprocessor_flags, 'p');
1672 
1673 	for (i = 0; i < (int)sizeof(fpflags)/(int)sizeof(char *); i++)
1674 		strlist_prepend(&preprocessor_flags, fpflags[i]);
1675 
1676 	for (i = 0; cppadd[i]; i++)
1677 		strlist_prepend(&preprocessor_flags, cppadd[i]);
1678 	for (i = 0; cppmdadd[i]; i++)
1679 		strlist_prepend(&preprocessor_flags, cppmdadd[i]);
1680 
1681 	/* Include dirs */
1682 	strlist_append(&sysincdirs, "=" INCLUDEDIR "pcc/");
1683 #ifdef STDINC_MA
1684 	strlist_append(&sysincdirs, "=" STDINC_MA);
1685 #endif
1686 	strlist_append(&sysincdirs, "=" STDINC);
1687 #ifdef PCCINCDIR
1688 	if (cxxflag)
1689 		strlist_append(&sysincdirs, "=" PCCINCDIR "/c++");
1690 	strlist_append(&sysincdirs, "=" PCCINCDIR);
1691 #endif
1692 }
1693 
1694 struct flgcheck ccomflgcheck[] = {
1695 	{ &Oflag, 1, "-xtemps" },
1696 	{ &Oflag, 1, "-xdeljumps" },
1697 	{ &Oflag, 1, "-xinline" },
1698 	{ &Oflag, 1, "-xdce" },
1699 #ifdef notyet
1700 	{ &Oflag, 1, "-xssa" },
1701 #endif
1702 	{ &freestanding, 1, "-ffreestanding" },
1703 	{ &pgflag, 1, "-p" },
1704 	{ &gflag, 1, "-g" },
1705 	{ &xgnu89, 1, "-xgnu89" },
1706 	{ &xgnu99, 1, "-xgnu99" },
1707 	{ &xuchar, 1, "-xuchar" },
1708 #if !defined(os_sunos) && !defined(mach_i386)
1709 	{ &vflag, 1, "-v" },
1710 #endif
1711 #ifdef os_darwin
1712 	{ &Bstatic, 0, "-k" },
1713 #elif defined(os_sunos) && defined(mach_i386)
1714 	{ &kflag, 1, "-K" },
1715 	{ &kflag, 1, "pic" },
1716 #else
1717 	{ &kflag, 1, "-k" },
1718 #endif
1719 	{ &sspflag, 1, "-fstack-protector" },
1720 	{ 0 }
1721 };
1722 
1723 void
setup_ccom_flags(void)1724 setup_ccom_flags(void)
1725 {
1726 
1727 	cksetflags(ccomflgcheck, &compiler_flags, 'a');
1728 }
1729 
1730 static int one = 1;
1731 
1732 struct flgcheck asflgcheck[] = {
1733 #if defined(USE_YASM)
1734 	{ &one, 1, "-p" },
1735 	{ &one, 1, "gnu" },
1736 	{ &one, 1, "-f" },
1737 #if defined(os_win32)
1738 	{ &one, 1, "win32" },
1739 #elif defined(os_darwin)
1740 	{ &one, 1, "macho" },
1741 #else
1742 	{ &one, 1, "elf" },
1743 #endif
1744 #endif
1745 #if defined(os_sunos) && defined(mach_sparc64)
1746 	{ &one, 1, "-m64" },
1747 #endif
1748 #if defined(os_darwin)
1749 	{ &Bstatic, 1, "-static" },
1750 #endif
1751 #if !defined(USE_YASM)
1752 	{ &vflag, 1, "-v" },
1753 #endif
1754 	{ &kflag, 1, "-k" },
1755 #ifdef os_darwin
1756 	{ &one, 1, "-arch" },
1757 #if mach_amd64
1758 	{ &amd64_i386, 1, "i386" },
1759 	{ &amd64_i386, 0, "x86_64" },
1760 #else
1761 	{ &one, 1, "i386" },
1762 #endif
1763 #else
1764 #ifdef mach_amd64
1765 	{ &amd64_i386, 1, "--32" },
1766 #endif
1767 #endif
1768 	{ 0 }
1769 };
1770 void
setup_as_flags(void)1771 setup_as_flags(void)
1772 {
1773 	one = one;
1774 #ifdef PCC_SETUP_AS_ARGS
1775 	PCC_SETUP_AS_ARGS
1776 #endif
1777 	cksetflags(asflgcheck, &assembler_flags, 'a');
1778 }
1779 
1780 struct flgcheck ldflgcheck[] = {
1781 #ifndef MSLINKER
1782 	{ &vflag, 1, "-v" },
1783 #endif
1784 #ifdef os_darwin
1785 	{ &shared, 1, "-dylib" },
1786 #elif defined(os_win32)
1787 	{ &shared, 1, "-Bdynamic" },
1788 #else
1789 	{ &shared, 1, "-shared" },
1790 #endif
1791 #if !defined(os_sunos) && !defined(os_win32)
1792 #ifndef os_darwin
1793 	{ &shared, 0, "-d" },
1794 #endif
1795 #endif
1796 #ifdef os_darwin
1797 	{ &Bstatic, 1, "-static" },
1798 #else
1799 	{ &Bstatic, 1, "-Bstatic" },
1800 #endif
1801 #if !defined(os_darwin) && !defined(os_sunos)
1802 	{ &gflag, 1, "-g" },
1803 #endif
1804 	{ &pthreads, 1, "-lpthread" },
1805 	{ 0 },
1806 };
1807 
1808 static void
strap(struct strlist * sh,struct strlist * cd,char * n,int where)1809 strap(struct strlist *sh, struct strlist *cd, char *n, int where)
1810 {
1811 	void (*fn)(struct strlist *, const char *);
1812 	char *fil;
1813 
1814 	if (n == 0)
1815 		return; /* no crtfile */
1816 
1817 	fn = where == 'p' ? strlist_prepend : strlist_append;
1818 	fil = find_file(n, cd, R_OK);
1819 	(*fn)(sh, fil);
1820 }
1821 
1822 void
setup_ld_flags(void)1823 setup_ld_flags(void)
1824 {
1825 	char *b, *e;
1826 	int i;
1827 
1828 	cksetflags(ldflgcheck, &early_linker_flags, 'a');
1829 	if (Bstatic == 0 && shared == 0 && rflag == 0) {
1830 		for (i = 0; dynlinker[i]; i++)
1831 			strlist_append(&early_linker_flags, dynlinker[i]);
1832 		strlist_append(&early_linker_flags, "-e");
1833 		strlist_append(&early_linker_flags, STARTLABEL);
1834 	}
1835 	if (shared == 0 && rflag)
1836 		strlist_append(&early_linker_flags, "-r");
1837 	if (sysroot && *sysroot)
1838 		strlist_append(&early_linker_flags, cat("--sysroot=", sysroot));
1839 	if (!nostdlib) {
1840 		/* library search paths */
1841 		if (pcclibdir)
1842 			strlist_append(&late_linker_flags,
1843 			    cat("-L", pcclibdir));
1844 		for (i = 0; deflibdirs[i]; i++)
1845 			strlist_append(&late_linker_flags,
1846 			    cat("-L", deflibdirs[i]));
1847 		/* standard libraries */
1848 		if (pgflag) {
1849 			for (i = 0; defproflibs[i]; i++)
1850 				strlist_append(&late_linker_flags,
1851 				     defproflibs[i]);
1852 		} else if (cxxflag) {
1853 			for (i = 0; defcxxlibs[i]; i++)
1854 				strlist_append(&late_linker_flags,
1855 				    defcxxlibs[i]);
1856 		} else {
1857 			for (i = 0; deflibs[i]; i++)
1858 				strlist_append(&late_linker_flags, deflibs[i]);
1859 		}
1860 	}
1861 	if (!nostartfiles) {
1862 		if (Bstatic) {
1863 			b = CRTBEGIN_T;
1864 			e = CRTEND_T;
1865 		} else if (shared /* || pieflag */) {
1866 			b = CRTBEGIN_S;
1867 			e = CRTEND_S;
1868 		}  else {
1869 			b = CRTBEGIN;
1870 			e = CRTEND;
1871 		}
1872 		strap(&middle_linker_flags, &crtdirs, b, 'p');
1873 		strap(&late_linker_flags, &crtdirs, e, 'a');
1874 		if (CRTI[0])
1875 			strap(&middle_linker_flags, &crtdirs, CRTI, 'p');
1876 		if (CRTN[0])
1877 			strap(&late_linker_flags, &crtdirs, CRTN, 'a');
1878 		if (shared == 0) {
1879 			if (pgflag)
1880 				b = GCRT0;
1881 #ifdef notyet
1882 			else if (pieflag)
1883 				b = SCRT0;
1884 #endif
1885 			else
1886 				b = CRT0;
1887 			strap(&middle_linker_flags, &crtdirs, b, 'p');
1888 		}
1889 	}
1890 }
1891 
1892 #ifdef os_win32
1893 char *
win32pathsubst(char * s)1894 win32pathsubst(char *s)
1895 {
1896 	char env[1024];
1897 	DWORD len;
1898 
1899 	len = ExpandEnvironmentStrings(s, env, sizeof(env));
1900 	if (len == 0 || len > sizeof(env))
1901 		errorx(8, "ExpandEnvironmentStrings failed, len %lu", len);
1902 
1903 	len--;	/* skip nil */
1904 	while (len-- > 0 && (env[len] == '/' || env[len] == '\\'))
1905 		env[len] = '\0';
1906 
1907 	return xstrdup(env);
1908 }
1909 
1910 char *
win32commandline(struct strlist * l)1911 win32commandline(struct strlist *l)
1912 {
1913 	const struct string *s;
1914 	char *cmd;
1915 	char *p;
1916 	int len;
1917 	int j, k;
1918 
1919 	len = 0;
1920 	STRLIST_FOREACH(s, l) {
1921 		len++;
1922 		for (j = 0; s->value[j] != '\0'; j++) {
1923 			if (s->value[j] == '\"') {
1924 				for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
1925 					len++;
1926 				len++;
1927 			}
1928 			len++;
1929 		}
1930 		for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
1931 			len++;
1932 		len++;
1933 		len++;
1934 	}
1935 
1936 	p = cmd = xmalloc(len);
1937 
1938 	STRLIST_FOREACH(s, l) {
1939 		*p++ = '\"';
1940 		for (j = 0; s->value[j] != '\0'; j++) {
1941 			if (s->value[j] == '\"') {
1942 				for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
1943 					*p++ = '\\';
1944 				*p++ = '\\';
1945 			}
1946 			*p++ = s->value[j];
1947 		}
1948 		for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
1949 			*p++ = '\\';
1950 		*p++ = '\"';
1951 		*p++ = ' ';
1952 	}
1953 	p[-1] = '\0';
1954 
1955 	return cmd;
1956 }
1957 #endif
1958