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