Home | History | Annotate | Line # | Download | only in cc
      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 (at) 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
    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
   1115 idexit(int arg)
   1116 {
   1117 	dexit(100);
   1118 }
   1119 
   1120 /*
   1121  * exit and cleanup.
   1122  */
   1123 void
   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
   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
   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 *
   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
   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
   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
   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
   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
   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
   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 *
   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
   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 *
   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
   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
   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 *
   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
   1493 cunlink(char *f)
   1494 {
   1495 	if (f==0 || Xflag)
   1496 		return(0);
   1497 	return (unlink(f));
   1498 }
   1499 
   1500 #ifdef _WIN32
   1501 char *
   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 *
   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
   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
   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 *
   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 *
   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
   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
   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
   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
   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
   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
   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 *
   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 *
   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