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
152char	*passp = PREPROCESSOR;
153char	*pass0 = COMPILER;
154char	*passxx0 = CXXCOMPILER;
155char	*as = ASSEMBLER;
156char	*ld = LINKER;
157char	*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
201char *cppadd[] = CPPADD;
202char *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
237char *dynlinkarg = DYNLINKARG;
238char *dynlinklib = DYNLINKLIB;
239char *pcclibdir = PCCLIBDIR;
240char *deflibdirs[] = DEFLIBDIRS;
241char *deflibs[] = DEFLIBS;
242char *defproflibs[] = DEFPROFLIBS;
243char *defcxxlibs[] = DEFCXXLIBS;
244
245char	*outfile, *MFfile, *fname;
246static char **lav;
247static int lac;
248static char *find_file(const char *file, struct strlist *path, int mode);
249static int preprocess_input(char *input, char *output, int dodep);
250static int compile_input(char *input, char *output);
251static int assemble_input(char *input, char *output);
252static int run_linker(void);
253static int strlist_exec(struct strlist *l);
254
255char *cat(const char *, const char *);
256char *setsuf(char *, char);
257int cxxsuf(char *);
258int getsuf(char *);
259char *getsufp(char *s);
260int main(int, char *[]);
261void errorx(int, char *, ...);
262int cunlink(char *);
263void exandrm(char *);
264void dexit(int);
265void idexit(int);
266char *gettmp(void);
267void oerror(char *);
268char *argnxt(char *, char *);
269char *nxtopt(char *o);
270void setup_cpp_flags(void);
271void setup_ccom_flags(void);
272void setup_as_flags(void);
273void setup_ld_flags(void);
274static void expand_sysroot(void);
275#ifdef  _WIN32
276char *win32pathsubst(char *);
277char *win32commandline(struct strlist *l);
278#endif
279int	sspflag;
280int	freestanding;
281int	Sflag;
282int	cflag;
283int	gflag;
284int	rflag;
285int	vflag;
286int	noexec;	/* -### */
287int	tflag;
288int	Eflag;
289int	Oflag;
290int	kflag;	/* generate PIC/pic code */
291#define F_PIC	1
292#define F_pic	2
293int	Mflag, needM, MDflag, MMDflag;	/* dependencies only */
294int	pgflag;
295int	Xflag;
296int	nostartfiles, Bstatic, shared;
297int	nostdinc, nostdlib;
298int	pthreads;
299int	xgnu89, xgnu99, c89defs, c99defs, c11defs;
300int 	ascpp;
301#ifdef CHAR_UNSIGNED
302int	xuchar = 1;
303#else
304int	xuchar = 0;
305#endif
306int	cxxflag;
307int	cppflag;
308int	printprogname, printfilename;
309enum { SC11, STRAD, SC89, SGNU89, SC99, SGNU99 } cstd;
310
311#ifdef SOFTFLOAT
312int	softfloat = 1;
313#else
314int	softfloat = 0;
315#endif
316
317#ifdef TARGET_BIG_ENDIAN
318int	bigendian = 1;
319#else
320int	bigendian = 0;
321#endif
322
323#ifdef mach_amd64
324int amd64_i386;
325#endif
326
327#define	match(a,b)	(strcmp(a,b) == 0)
328
329/* handle gcc warning emulations */
330struct 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
404struct strlist preprocessor_flags;
405struct strlist depflags;
406struct strlist incdirs;
407struct strlist user_sysincdirs;
408struct strlist includes;
409struct strlist sysincdirs;
410struct strlist dirafterdirs;
411struct strlist crtdirs;
412struct strlist libdirs;
413struct strlist progdirs;
414struct strlist early_linker_flags;
415struct strlist middle_linker_flags;
416struct strlist late_linker_flags;
417struct strlist inputs;
418struct strlist assembler_flags;
419struct strlist temp_outputs;
420struct strlist compiler_flags;
421
422int
423main(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 */
1114void
1115idexit(int arg)
1116{
1117	dexit(100);
1118}
1119
1120/*
1121 * exit and cleanup.
1122 */
1123void
1124dexit(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 */
1138void
1139exandrm(char *s)
1140{
1141	if (s && *s)
1142		strlist_append(&temp_outputs, s);
1143	dexit(1);
1144}
1145
1146/*
1147 * complain and exit.
1148 */
1149void
1150errorx(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
1162static char *
1163find_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
1187static int
1188compile_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
1218static int
1219compile_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
1236static int
1237assemble_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
1260static int
1261preprocess_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
1307static int
1308run_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
1329static char *cxxt[] = { "cc", "cp", "cxx", "cpp", "CPP", "c++", "C" };
1330int
1331cxxsuf(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
1340char *
1341getsufp(char *s)
1342{
1343	register char *p;
1344
1345	if ((p = strrchr(s, '.')) && p[1] != '\0')
1346		return &p[1];
1347	return "";
1348}
1349
1350int
1351getsuf(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 */
1363char *
1364setsuf(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
1390static int
1391strlist_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
1433static int
1434strlist_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 */
1480char *
1481cat(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
1492int
1493cunlink(char *f)
1494{
1495	if (f==0 || Xflag)
1496		return(0);
1497	return (unlink(f));
1498}
1499
1500#ifdef _WIN32
1501char *
1502gettmp(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
1521char *
1522gettmp(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
1534static void
1535expand_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
1564void
1565oerror(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 */
1574char *
1575argnxt(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 */
1585char *
1586nxtopt(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
1602struct 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
1623static void
1624cksetflags(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
1644static 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
1690static 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 */
1714static 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 */
1797void
1798setup_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
1849struct 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
1878void
1879setup_ccom_flags(void)
1880{
1881
1882	cksetflags(ccomflgcheck, &compiler_flags, 'a');
1883}
1884
1885static int one = 1;
1886
1887struct 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};
1925void
1926setup_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
1935struct 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
1963static void
1964strap(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
1977void
1978setup_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
2072char *
2073win32pathsubst(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
2089char *
2090win32commandline(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