shithub: scc

Download patch

ref: ff5b36e280ae269eaa3835006f0f46fbe1bb2d2f
parent: a0ff31c2362324edf915883b2faa324377be1b4a
author: Roberto E. Vargas Caballero <[email protected]>
date: Sun Oct 6 18:08:00 EDT 2019

[cc] Rename scc executable to cc

--- a/src/cmd/cc/posix/Makefile
+++ b/src/cmd/cc/posix/Makefile
@@ -12,12 +12,12 @@
 	i386-sysv-linux-elf\
 	amd64-sysv-openbsd-elf\
 
-TARGETS = $(BINDIR)/scc $(BINDIR)/cpp
+TARGETS = $(BINDIR)/cc $(BINDIR)/cpp
 
 all: $(TARGETS)
 
-$(BINDIR)/scc: scc.o
-	$(CC) $(SCC_LDFLAGS) scc.o -lscc -o $@
+$(BINDIR)/cc: cc.o
+	$(CC) $(SCC_LDFLAGS) cc.o -lscc -o $@
 
 $(BINDIR)/cpp: cpp.sh
 	trap "rm -f $$$$.sh" 0 2 3;\
--- /dev/null
+++ b/src/cmd/cc/posix/cc.c
@@ -1,0 +1,658 @@
+#define _POSIX_SOURCE
+#define _XOPEN_SOURCE 500
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include <scc/arg.h>
+#include <scc/scc.h>
+#include <scc/syscrts.h>
+#include <scc/sysincludes.h>
+#include <scc/syslibs.h>
+#include <scc/ldflags.h>
+
+enum {
+	CC1,
+	TEEIR,
+	CC2,
+	TEEQBE,
+	QBE,
+	TEEAS,
+	AS,
+	LD,
+	STRIP,
+	LAST_TOOL,
+};
+
+static struct tool {
+	char   cmd[PATH_MAX];
+	char   bin[32];
+	char  *outfile;
+	struct items args;
+	unsigned nparams;
+	int    in, out, init;
+	pid_t  pid;
+} tools[] = {
+	[CC1]    = { .cmd = "cc1" },
+	[TEEIR]  = { .bin = "tee",   .cmd = "tee", },
+	[CC2]    = { .cmd = "cc2" },
+	[TEEQBE] = { .bin = "tee",   .cmd = "tee", },
+	[QBE]    = { .bin = "qbe",   .cmd = "qbe", },
+	[TEEAS]  = { .bin = "tee",   .cmd = "tee", },
+	[AS]     = { .bin = "as",    .cmd = "as", },
+	[LD]     = { .bin = "ld",    .cmd = "ld", },
+	[STRIP]  = { .bin = "strip", .cmd = "strip", },
+};
+
+char *argv0;
+static char *arch, *sys, *abi, *format;
+static char *prefix, *objfile, *outfile;
+static char *tmpdir;
+static size_t tmpdirln;
+static struct items objtmp, objout;
+static int Mflag, Eflag, Sflag, Wflag,
+           cflag, dflag, kflag, sflag, Qflag = 1; /* TODO: Remove Qflag */
+static int devnullfd = -1;
+
+extern int failure;
+
+static void
+terminate(void)
+{
+	unsigned i;
+
+	if (!kflag) {
+		for (i = 0; i < objtmp.n; ++i)
+			unlink(objtmp.s[i]);
+	}
+}
+
+static char *
+path(char *s)
+{
+	char *arg, buff[FILENAME_MAX];
+	size_t len, cnt;
+
+	for ( ; *s && cnt < FILENAME_MAX; ++s) {
+		if (*s != '%') {
+			buff[cnt++] = *s;
+			continue;
+		}
+
+		switch (*++s) {
+		case 'a':
+			arg = arch;
+			break;
+		case 's':
+			arg = sys;
+			break;
+		case 'p':
+			arg = prefix;
+			break;
+		case 'b':
+			arg = abi;
+			break;
+		default:
+			buff[cnt++] = *s;
+			continue;
+		}
+
+		len = strlen(arg);
+		if (len + cnt >= FILENAME_MAX)
+			goto too_long;
+		memcpy(buff+cnt, arg, len);
+		cnt += len;
+	}
+
+	if (cnt != FILENAME_MAX)
+		return xstrdup(buff);
+
+too_long:
+	die("cc: too long pathname");
+}
+
+static void
+addarg(int tool, char *arg)
+{
+	struct tool *t = &tools[tool];
+
+	if (t->args.n < 1)
+		t->args.n = 1;
+
+	newitem(&t->args, arg);
+}
+
+static void
+setargv0(int tool, char *arg)
+{
+	struct tool *t = &tools[tool];
+
+	if (t->args.n > 0)
+		t->args.s[0] = arg;
+	else
+		newitem(&t->args, arg);
+}
+
+static int
+qbe(int tool)
+{
+	if (tool != CC2 || !Qflag)
+		return 0;
+	if (!strcmp(arch, "amd64") && !strcmp(abi, "sysv"))
+		return 1;
+	return 0;
+}
+
+static int
+inittool(int tool)
+{
+	struct tool *t = &tools[tool];
+	char *crt, *fmt;
+	int n;
+
+	if (t->init)
+		return tool;
+
+	switch (tool) {
+	case CC1:
+		if (Wflag)
+			addarg(tool, "-w");
+		for (n = 0; sysincludes[n]; ++n) {
+			addarg(tool, "-I");
+			addarg(tool, path(sysincludes[n]));
+		}
+	case CC2:
+		fmt = (qbe(tool)) ? "%s-qbe_%s-%s" : "%s-%s-%s";
+		n = snprintf(t->bin, sizeof(t->bin), fmt, t->cmd, arch, abi);
+		if (n < 0 || n >= sizeof(t->bin))
+			die("cc: target tool name too long");
+
+		n = snprintf(t->cmd, sizeof(t->cmd),
+		             "%s/libexec/scc/%s", prefix, t->bin);
+		if (n < 0 || n >= sizeof(t->cmd))
+			die("cc: target tool path too long");
+		break;
+	case LD:
+		for (n = 0; ldflags[n]; ++n)
+			addarg(tool, ldflags[n]);
+		addarg(tool, "-o");
+		t->outfile = outfile ? outfile : xstrdup("a.out");
+		addarg(tool, t->outfile);
+		for (n = 0; syslibs[n]; ++n) {
+			addarg(tool, "-L");
+			addarg(tool, path(syslibs[n]));
+		}
+		for (n = 0; syscrts[n]; ++n)
+			addarg(tool, path(syscrts[n]));
+		break;
+	case AS:
+		addarg(tool, "-o");
+		break;
+	default:
+		break;
+	}
+
+	setargv0(tool, t->bin);
+	t->nparams = t->args.n;
+	t->init = 1;
+
+	return tool;
+}
+
+static char *
+outfname(char *path, char *type)
+{
+	char *new, sep, *p;
+	size_t newsz, pathln;
+	int tmpfd, n;
+
+	if (path) {
+		sep = '.';
+		if (p = strrchr(path, '/'))
+			path = p + 1;
+		pathln = strlen(path);
+		if (p = strrchr(path, '.'))
+			pathln -= strlen(p);
+	} else {
+		sep = '/';
+		type = "scc-XXXXXX";
+		path = tmpdir;
+		pathln = tmpdirln;
+	}
+
+	newsz = pathln + 1 + strlen(type) + 1;
+	new = xmalloc(newsz);
+	n = snprintf(new, newsz, "%.*s%c%s", (int)pathln, path, sep, type);
+	if (n < 0 || n >= newsz)
+		die("cc: wrong output filename");
+	if (sep == '/') {
+		if ((tmpfd = mkstemp(new)) < 0)
+			die("cc: could not create output file '%s': %s",
+			    new, strerror(errno));
+		close(tmpfd);
+	}
+
+	return new;
+}
+
+static int
+settool(int tool, char *infile, int nexttool)
+{
+	struct tool *t = &tools[tool];
+	unsigned i;
+	int fds[2];
+	static int fdin = -1;
+
+	switch (tool) {
+	case TEEIR:
+		t->outfile = outfname(infile, "ir");
+		addarg(tool, t->outfile);
+		break;
+	case TEEQBE:
+		t->outfile = outfname(infile, "qbe");
+		addarg(tool, t->outfile);
+		break;
+	case TEEAS:
+		t->outfile = outfname(infile, "s");
+		addarg(tool, t->outfile);
+		break;
+	case AS:
+		if (cflag && outfile) {
+			objfile = outfile;
+		} else {
+			objfile = (cflag || kflag) ? infile : NULL;
+			objfile = outfname(objfile, "o");
+		}
+		t->outfile = xstrdup(objfile);
+		addarg(tool, t->outfile);
+		break;
+	case STRIP:
+		if (cflag || kflag) {
+			for (i = 0; i < objout.n; ++i)
+				addarg(tool, xstrdup(objout.s[i]));
+		}
+		if (!cflag && tools[LD].outfile)
+			addarg(tool, tools[LD].outfile);
+		break;
+	default:
+		break;
+	}
+
+	if (fdin > -1) {
+		t->in = fdin;
+		fdin = -1;
+	} else {
+		t->in = -1;
+		if (infile)
+			addarg(tool, xstrdup(infile));
+	}
+
+	if (nexttool < LAST_TOOL) {
+		if (pipe(fds))
+			die("cc: pipe: %s", strerror(errno));
+		t->out = fds[1];
+		fdin = fds[0];
+	} else {
+		t->out = -1;
+	}
+
+	addarg(tool, NULL);
+
+	return tool;
+}
+
+static void
+spawn(int tool)
+{
+	char **ap;
+	struct tool *t = &tools[tool];
+
+	switch (t->pid = fork()) {
+	case -1:
+		die("cc: %s: %s", t->bin, strerror(errno));
+	case 0:
+		if (t->out > -1)
+			dup2(t->out, 1);
+		if (t->in > -1)
+			dup2(t->in, 0);
+		if (!dflag && tool != CC1 && tool != LD)
+			dup2(devnullfd, 2);
+		if (dflag) {
+			for (ap = t->args.s; *ap; ap++)
+				fprintf(stderr, " %s", *ap);
+			putc('\n', stderr);
+		}
+		execvp(t->cmd, t->args.s);
+		if (dflag) {
+			fprintf(stderr,
+			        "scc: execvp %s: %s\n",
+				t->cmd,
+			        strerror(errno));
+		}
+		abort();
+	default:
+		if (t->in > -1)
+			close(t->in);
+		if (t->out > -1)
+			close(t->out);
+		break;
+	}
+}
+
+static int
+toolfor(char *file)
+{
+	char *dot = strrchr(file, '.');
+
+	if (dot) {
+		if (!strcmp(dot, ".c"))
+			return CC1;
+		if (!strcmp(dot, ".ir"))
+			return CC2;
+		if (!strcmp(dot, ".qbe"))
+			return QBE;
+		if (!strcmp(dot, ".s"))
+			return AS;
+		if (!strcmp(dot, ".o"))
+			return LD;
+		if (!strcmp(dot, ".a"))
+			return LD;
+	} else if (!strcmp(file, "-")) {
+		return CC1;
+	}
+
+	die("cc: do not recognize filetype of %s", file);
+}
+
+static int
+valid(int tool, struct tool *t)
+{
+	int st;
+
+	if (waitpid(t->pid, &st, 0) == -1 || WIFSIGNALED(st))
+		goto internal;
+	if (WIFEXITED(st) && WEXITSTATUS(st) == 0)
+		return 1;
+	if (!failure && (tool == CC1 || tool == LD))
+		goto fail;
+
+internal:
+	fprintf(stderr, "cc:%s: internal error\n", t->bin);
+fail:
+	failure = 1;
+	return 0;
+}
+
+static int
+validatetools(void)
+{
+	struct tool *t;
+	unsigned i;
+	int tool, st, failed = LAST_TOOL;
+
+	for (tool = 0; tool < LAST_TOOL; ++tool) {
+		t = &tools[tool];
+		if (!t->pid)
+			continue;
+		if (!valid(tool, t))
+			failed = tool;
+		if (tool >= failed && t->outfile)
+			unlink(t->outfile);
+		for (i = t->nparams; i < t->args.n; ++i)
+			free(t->args.s[i]);
+		t->args.n = t->nparams;
+		t->pid = 0;
+	}
+	if (failed < LAST_TOOL) {
+		unlink(objfile);
+		free(objfile);
+		objfile = NULL;
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+buildfile(char *file, int tool)
+{
+	int nexttool;
+
+	for (; tool < LAST_TOOL; tool = nexttool) {
+		switch (tool) {
+		case CC1:
+			if (Eflag || Mflag)
+				nexttool = LAST_TOOL;
+			else
+				nexttool = kflag ? TEEIR : CC2;
+			break;
+		case TEEIR:
+			nexttool = CC2;
+			break;
+		case CC2:
+			if (Qflag)
+				nexttool = kflag ? TEEQBE : QBE;
+			else
+				nexttool = (Sflag || kflag) ? TEEAS : AS;
+			break;
+		case TEEQBE:
+			nexttool = QBE;
+			break;
+		case QBE:
+			nexttool = (Sflag || kflag) ? TEEAS : AS;
+			break;
+		case TEEAS:
+			nexttool = Sflag ? LAST_TOOL : AS;
+			break;
+		case AS:
+			nexttool = LAST_TOOL;
+			break;
+		default:
+			nexttool = LAST_TOOL;
+			continue;
+		}
+
+		spawn(settool(inittool(tool), file, nexttool));
+	}
+
+	return validatetools();
+}
+
+static void
+build(struct items *chain, int link)
+{
+	int i, tool;
+
+	if (link)
+		inittool(LD);
+
+	for (i = 0; i < chain->n; ++i) {
+		if (!strcmp(chain->s[i], "-l")) {
+			if (link) {
+				addarg(LD, xstrdup(chain->s[i++]));
+				addarg(LD, xstrdup(chain->s[i]));
+			} else {
+				++i;
+			}
+			continue;
+		}
+		tool = toolfor(chain->s[i]);
+		if (tool == LD) {
+			if (link)
+				addarg(LD, xstrdup(chain->s[i]));
+			continue;
+		}
+		if (buildfile(chain->s[i], tool)) {
+			if (link)
+				addarg(LD, xstrdup(objfile));
+			newitem((!link || kflag) ? &objout : &objtmp, objfile);
+		}
+	}
+}
+
+static void
+usage(void)
+{
+	fputs("usage: scc [-D def[=val]]... [-U def]... [-I dir]... "
+	       "[-L dir]... [-l dir]...\n"
+	       "           [-dgksw] [-m arch] [-M|-E|-S] [-o outfile] file...\n"
+	       "       scc [-D def[=val]]... [-U def]... [-I dir]... "
+	       "[-L dir]... [-l dir]...\n"
+	       "           [-dgksw] [-m arch] [-M|-E|-S] -c file...\n"
+	       "       scc [-D def[=val]]... [-U def]... [-I dir]... "
+	       "[-L dir]... [-l dir]...\n"
+	       "           [-dgksw] [-m arch] -c -o outfile file\n", stderr);
+	exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct items linkchain = { .n = 0, };
+	int link;
+
+	atexit(terminate);
+
+	if (!(arch = getenv("ARCH")))
+		arch = ARCH;
+	if (!(sys = getenv("SYS")))
+		sys = SYS;
+	if (!(abi = getenv("ABI")))
+		abi = ABI;
+	if (!(format = getenv("FORMAT")))
+		format = FORMAT;
+	if (!(prefix = getenv("SCCPREFIX")))
+		prefix = PREFIX;
+
+	ARGBEGIN {
+	case 'D':
+		addarg(CC1, "-D");
+		addarg(CC1, EARGF(usage()));
+		break;
+	case 'M':
+		Mflag = 1;
+		addarg(CC1, "-M");
+		break;
+	case 'E':
+		Eflag = 1;
+		addarg(CC1, "-E");
+		break;
+	case 'I':
+		addarg(CC1, "-I");
+		addarg(CC1, EARGF(usage()));
+		break;
+	case 'L':
+		addarg(LD, "-L");
+		addarg(LD, EARGF(usage()));
+		break;
+	case 'O':
+		EARGF(usage());
+		break;
+	case 'S':
+		Sflag = 1;
+		break;
+	case 'U':
+		addarg(CC1, "-U");
+		addarg(CC1, EARGF(usage()));
+		break;
+	case 'c':
+		cflag = 1;
+		break;
+	case 'd':
+		dflag = 1;
+		break;
+	case 'g':
+		addarg(AS, "-g");
+		addarg(LD, "-g");
+		break;
+	case 'k':
+		kflag = 1;
+		break;
+	case 'l':
+		newitem(&linkchain, "-l");
+		newitem(&linkchain, EARGF(usage()));
+		break;
+	case 'm':
+		arch = EARGF(usage());
+		break;
+	case 'o':
+		outfile = xstrdup(EARGF(usage()));
+		break;
+	case 's':
+		sflag = 1;
+		break;
+	case 't':
+		sys = EARGF(usage());
+		break;
+	case 'w':
+		Wflag = 0;
+		break;
+	case 'W':
+		Wflag = 1;
+		break;
+	case 'q':
+		Qflag = 0;
+		break;
+	case 'Q':
+		Qflag = 1;
+		break;
+	case '-':
+		fprintf(stderr,
+		        "scc: ignored parameter --%s\n", EARGF(usage()));
+		break;
+	default:
+		usage();
+	} ARGOPERAND {
+operand:
+		newitem(&linkchain, ARGOP());
+	} ARGEND
+
+	for (; *argv; --argc, ++argv)
+		goto operand;
+
+	if (Eflag && linkchain.n == 0)
+		newitem(&linkchain, "-");
+
+	if (Eflag && Mflag ||
+            (Eflag || Mflag) && (Sflag || kflag) ||
+	    linkchain.n == 0 ||
+	    linkchain.n > 1 && cflag && outfile)
+		usage();
+
+	if (!dflag) {
+		if ((devnullfd = open("/dev/null", O_WRONLY)) < 0)
+			fputs("scc: could not open /dev/null\n", stderr);
+	}
+
+	if (!(tmpdir = getenv("TMPDIR")) || !tmpdir[0])
+		tmpdir = ".";
+	tmpdirln = strlen(tmpdir);
+
+	build(&linkchain, (link = !(Mflag || Eflag || Sflag || cflag)));
+
+	if (!(link || cflag))
+		return failure;
+
+	if (link && !failure) {
+		addarg(LD, xstrdup("-lc"));
+		addarg(LD, xstrdup("-lcrt"));
+		spawn(settool(LD, NULL, LAST_TOOL));
+		validatetools();
+	}
+
+	if (sflag) {
+		spawn(settool(inittool(STRIP), NULL, LAST_TOOL));
+		validatetools();
+	}
+
+	return failure;
+}
--- a/src/cmd/cc/posix/cpp.sh
+++ b/src/cmd/cc/posix/cpp.sh
@@ -1,4 +1,4 @@
 #!/bin/sh
 
 SCCPREFIX=${SCCPREFIX:-@PREFIX@}
-${SCCPREFIX}/bin/scc -E $@
+${SCCPREFIX}/bin/cc -E $@
--- a/src/cmd/cc/posix/deps.mk
+++ b/src/cmd/cc/posix/deps.mk
@@ -1,8 +1,8 @@
 #deps
-./scc.o: $(INCDIR)/scc/scc/arg.h
-./scc.o: $(INCDIR)/scc/scc/ldflags.h
-./scc.o: $(INCDIR)/scc/scc/scc.h
-./scc.o: $(INCDIR)/scc/scc/syscrts.h
-./scc.o: $(INCDIR)/scc/scc/sysincludes.h
-./scc.o: $(INCDIR)/scc/scc/syslibs.h
-./scc.o: ./config.h
+./cc.o: $(INCDIR)/scc/scc/arg.h
+./cc.o: $(INCDIR)/scc/scc/ldflags.h
+./cc.o: $(INCDIR)/scc/scc/scc.h
+./cc.o: $(INCDIR)/scc/scc/syscrts.h
+./cc.o: $(INCDIR)/scc/scc/sysincludes.h
+./cc.o: $(INCDIR)/scc/scc/syslibs.h
+./cc.o: ./config.h
--- a/src/cmd/cc/posix/scc.c
+++ /dev/null
@@ -1,658 +1,0 @@
-#define _POSIX_SOURCE
-#define _XOPEN_SOURCE 500
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "config.h"
-#include <scc/arg.h>
-#include <scc/scc.h>
-#include <scc/syscrts.h>
-#include <scc/sysincludes.h>
-#include <scc/syslibs.h>
-#include <scc/ldflags.h>
-
-enum {
-	CC1,
-	TEEIR,
-	CC2,
-	TEEQBE,
-	QBE,
-	TEEAS,
-	AS,
-	LD,
-	STRIP,
-	LAST_TOOL,
-};
-
-static struct tool {
-	char   cmd[PATH_MAX];
-	char   bin[32];
-	char  *outfile;
-	struct items args;
-	unsigned nparams;
-	int    in, out, init;
-	pid_t  pid;
-} tools[] = {
-	[CC1]    = { .cmd = "cc1" },
-	[TEEIR]  = { .bin = "tee",   .cmd = "tee", },
-	[CC2]    = { .cmd = "cc2" },
-	[TEEQBE] = { .bin = "tee",   .cmd = "tee", },
-	[QBE]    = { .bin = "qbe",   .cmd = "qbe", },
-	[TEEAS]  = { .bin = "tee",   .cmd = "tee", },
-	[AS]     = { .bin = "as",    .cmd = "as", },
-	[LD]     = { .bin = "ld",    .cmd = "ld", },
-	[STRIP]  = { .bin = "strip", .cmd = "strip", },
-};
-
-char *argv0;
-static char *arch, *sys, *abi, *format;
-static char *prefix, *objfile, *outfile;
-static char *tmpdir;
-static size_t tmpdirln;
-static struct items objtmp, objout;
-static int Mflag, Eflag, Sflag, Wflag,
-           cflag, dflag, kflag, sflag, Qflag = 1; /* TODO: Remove Qflag */
-static int devnullfd = -1;
-
-extern int failure;
-
-static void
-terminate(void)
-{
-	unsigned i;
-
-	if (!kflag) {
-		for (i = 0; i < objtmp.n; ++i)
-			unlink(objtmp.s[i]);
-	}
-}
-
-static char *
-path(char *s)
-{
-	char *arg, buff[FILENAME_MAX];
-	size_t len, cnt;
-
-	for ( ; *s && cnt < FILENAME_MAX; ++s) {
-		if (*s != '%') {
-			buff[cnt++] = *s;
-			continue;
-		}
-
-		switch (*++s) {
-		case 'a':
-			arg = arch;
-			break;
-		case 's':
-			arg = sys;
-			break;
-		case 'p':
-			arg = prefix;
-			break;
-		case 'b':
-			arg = abi;
-			break;
-		default:
-			buff[cnt++] = *s;
-			continue;
-		}
-
-		len = strlen(arg);
-		if (len + cnt >= FILENAME_MAX)
-			goto too_long;
-		memcpy(buff+cnt, arg, len);
-		cnt += len;
-	}
-
-	if (cnt != FILENAME_MAX)
-		return xstrdup(buff);
-
-too_long:
-	die("scc: too long pathname");
-}
-
-static void
-addarg(int tool, char *arg)
-{
-	struct tool *t = &tools[tool];
-
-	if (t->args.n < 1)
-		t->args.n = 1;
-
-	newitem(&t->args, arg);
-}
-
-static void
-setargv0(int tool, char *arg)
-{
-	struct tool *t = &tools[tool];
-
-	if (t->args.n > 0)
-		t->args.s[0] = arg;
-	else
-		newitem(&t->args, arg);
-}
-
-static int
-qbe(int tool)
-{
-	if (tool != CC2 || !Qflag)
-		return 0;
-	if (!strcmp(arch, "amd64") && !strcmp(abi, "sysv"))
-		return 1;
-	return 0;
-}
-
-static int
-inittool(int tool)
-{
-	struct tool *t = &tools[tool];
-	char *crt, *fmt;
-	int n;
-
-	if (t->init)
-		return tool;
-
-	switch (tool) {
-	case CC1:
-		if (Wflag)
-			addarg(tool, "-w");
-		for (n = 0; sysincludes[n]; ++n) {
-			addarg(tool, "-I");
-			addarg(tool, path(sysincludes[n]));
-		}
-	case CC2:
-		fmt = (qbe(tool)) ? "%s-qbe_%s-%s" : "%s-%s-%s";
-		n = snprintf(t->bin, sizeof(t->bin), fmt, t->cmd, arch, abi);
-		if (n < 0 || n >= sizeof(t->bin))
-			die("scc: target tool name too long");
-
-		n = snprintf(t->cmd, sizeof(t->cmd),
-		             "%s/libexec/scc/%s", prefix, t->bin);
-		if (n < 0 || n >= sizeof(t->cmd))
-			die("scc: target tool path too long");
-		break;
-	case LD:
-		for (n = 0; ldflags[n]; ++n)
-			addarg(tool, ldflags[n]);
-		addarg(tool, "-o");
-		t->outfile = outfile ? outfile : xstrdup("a.out");
-		addarg(tool, t->outfile);
-		for (n = 0; syslibs[n]; ++n) {
-			addarg(tool, "-L");
-			addarg(tool, path(syslibs[n]));
-		}
-		for (n = 0; syscrts[n]; ++n)
-			addarg(tool, path(syscrts[n]));
-		break;
-	case AS:
-		addarg(tool, "-o");
-		break;
-	default:
-		break;
-	}
-
-	setargv0(tool, t->bin);
-	t->nparams = t->args.n;
-	t->init = 1;
-
-	return tool;
-}
-
-static char *
-outfname(char *path, char *type)
-{
-	char *new, sep, *p;
-	size_t newsz, pathln;
-	int tmpfd, n;
-
-	if (path) {
-		sep = '.';
-		if (p = strrchr(path, '/'))
-			path = p + 1;
-		pathln = strlen(path);
-		if (p = strrchr(path, '.'))
-			pathln -= strlen(p);
-	} else {
-		sep = '/';
-		type = "scc-XXXXXX";
-		path = tmpdir;
-		pathln = tmpdirln;
-	}
-
-	newsz = pathln + 1 + strlen(type) + 1;
-	new = xmalloc(newsz);
-	n = snprintf(new, newsz, "%.*s%c%s", (int)pathln, path, sep, type);
-	if (n < 0 || n >= newsz)
-		die("scc: wrong output filename");
-	if (sep == '/') {
-		if ((tmpfd = mkstemp(new)) < 0)
-			die("scc: could not create output file '%s': %s",
-			    new, strerror(errno));
-		close(tmpfd);
-	}
-
-	return new;
-}
-
-static int
-settool(int tool, char *infile, int nexttool)
-{
-	struct tool *t = &tools[tool];
-	unsigned i;
-	int fds[2];
-	static int fdin = -1;
-
-	switch (tool) {
-	case TEEIR:
-		t->outfile = outfname(infile, "ir");
-		addarg(tool, t->outfile);
-		break;
-	case TEEQBE:
-		t->outfile = outfname(infile, "qbe");
-		addarg(tool, t->outfile);
-		break;
-	case TEEAS:
-		t->outfile = outfname(infile, "s");
-		addarg(tool, t->outfile);
-		break;
-	case AS:
-		if (cflag && outfile) {
-			objfile = outfile;
-		} else {
-			objfile = (cflag || kflag) ? infile : NULL;
-			objfile = outfname(objfile, "o");
-		}
-		t->outfile = xstrdup(objfile);
-		addarg(tool, t->outfile);
-		break;
-	case STRIP:
-		if (cflag || kflag) {
-			for (i = 0; i < objout.n; ++i)
-				addarg(tool, xstrdup(objout.s[i]));
-		}
-		if (!cflag && tools[LD].outfile)
-			addarg(tool, tools[LD].outfile);
-		break;
-	default:
-		break;
-	}
-
-	if (fdin > -1) {
-		t->in = fdin;
-		fdin = -1;
-	} else {
-		t->in = -1;
-		if (infile)
-			addarg(tool, xstrdup(infile));
-	}
-
-	if (nexttool < LAST_TOOL) {
-		if (pipe(fds))
-			die("scc: pipe: %s", strerror(errno));
-		t->out = fds[1];
-		fdin = fds[0];
-	} else {
-		t->out = -1;
-	}
-
-	addarg(tool, NULL);
-
-	return tool;
-}
-
-static void
-spawn(int tool)
-{
-	char **ap;
-	struct tool *t = &tools[tool];
-
-	switch (t->pid = fork()) {
-	case -1:
-		die("scc: %s: %s", t->bin, strerror(errno));
-	case 0:
-		if (t->out > -1)
-			dup2(t->out, 1);
-		if (t->in > -1)
-			dup2(t->in, 0);
-		if (!dflag && tool != CC1 && tool != LD)
-			dup2(devnullfd, 2);
-		if (dflag) {
-			for (ap = t->args.s; *ap; ap++)
-				fprintf(stderr, " %s", *ap);
-			putc('\n', stderr);
-		}
-		execvp(t->cmd, t->args.s);
-		if (dflag) {
-			fprintf(stderr,
-			        "scc: execvp %s: %s\n",
-				t->cmd,
-			        strerror(errno));
-		}
-		abort();
-	default:
-		if (t->in > -1)
-			close(t->in);
-		if (t->out > -1)
-			close(t->out);
-		break;
-	}
-}
-
-static int
-toolfor(char *file)
-{
-	char *dot = strrchr(file, '.');
-
-	if (dot) {
-		if (!strcmp(dot, ".c"))
-			return CC1;
-		if (!strcmp(dot, ".ir"))
-			return CC2;
-		if (!strcmp(dot, ".qbe"))
-			return QBE;
-		if (!strcmp(dot, ".s"))
-			return AS;
-		if (!strcmp(dot, ".o"))
-			return LD;
-		if (!strcmp(dot, ".a"))
-			return LD;
-	} else if (!strcmp(file, "-")) {
-		return CC1;
-	}
-
-	die("scc: do not recognize filetype of %s", file);
-}
-
-static int
-valid(int tool, struct tool *t)
-{
-	int st;
-
-	if (waitpid(t->pid, &st, 0) == -1 || WIFSIGNALED(st))
-		goto internal;
-	if (WIFEXITED(st) && WEXITSTATUS(st) == 0)
-		return 1;
-	if (!failure && (tool == CC1 || tool == LD))
-		goto fail;
-
-internal:
-	fprintf(stderr, "scc:%s: internal error\n", t->bin);
-fail:
-	failure = 1;
-	return 0;
-}
-
-static int
-validatetools(void)
-{
-	struct tool *t;
-	unsigned i;
-	int tool, st, failed = LAST_TOOL;
-
-	for (tool = 0; tool < LAST_TOOL; ++tool) {
-		t = &tools[tool];
-		if (!t->pid)
-			continue;
-		if (!valid(tool, t))
-			failed = tool;
-		if (tool >= failed && t->outfile)
-			unlink(t->outfile);
-		for (i = t->nparams; i < t->args.n; ++i)
-			free(t->args.s[i]);
-		t->args.n = t->nparams;
-		t->pid = 0;
-	}
-	if (failed < LAST_TOOL) {
-		unlink(objfile);
-		free(objfile);
-		objfile = NULL;
-		return 0;
-	}
-
-	return 1;
-}
-
-static int
-buildfile(char *file, int tool)
-{
-	int nexttool;
-
-	for (; tool < LAST_TOOL; tool = nexttool) {
-		switch (tool) {
-		case CC1:
-			if (Eflag || Mflag)
-				nexttool = LAST_TOOL;
-			else
-				nexttool = kflag ? TEEIR : CC2;
-			break;
-		case TEEIR:
-			nexttool = CC2;
-			break;
-		case CC2:
-			if (Qflag)
-				nexttool = kflag ? TEEQBE : QBE;
-			else
-				nexttool = (Sflag || kflag) ? TEEAS : AS;
-			break;
-		case TEEQBE:
-			nexttool = QBE;
-			break;
-		case QBE:
-			nexttool = (Sflag || kflag) ? TEEAS : AS;
-			break;
-		case TEEAS:
-			nexttool = Sflag ? LAST_TOOL : AS;
-			break;
-		case AS:
-			nexttool = LAST_TOOL;
-			break;
-		default:
-			nexttool = LAST_TOOL;
-			continue;
-		}
-
-		spawn(settool(inittool(tool), file, nexttool));
-	}
-
-	return validatetools();
-}
-
-static void
-build(struct items *chain, int link)
-{
-	int i, tool;
-
-	if (link)
-		inittool(LD);
-
-	for (i = 0; i < chain->n; ++i) {
-		if (!strcmp(chain->s[i], "-l")) {
-			if (link) {
-				addarg(LD, xstrdup(chain->s[i++]));
-				addarg(LD, xstrdup(chain->s[i]));
-			} else {
-				++i;
-			}
-			continue;
-		}
-		tool = toolfor(chain->s[i]);
-		if (tool == LD) {
-			if (link)
-				addarg(LD, xstrdup(chain->s[i]));
-			continue;
-		}
-		if (buildfile(chain->s[i], tool)) {
-			if (link)
-				addarg(LD, xstrdup(objfile));
-			newitem((!link || kflag) ? &objout : &objtmp, objfile);
-		}
-	}
-}
-
-static void
-usage(void)
-{
-	fputs("usage: scc [-D def[=val]]... [-U def]... [-I dir]... "
-	       "[-L dir]... [-l dir]...\n"
-	       "           [-dgksw] [-m arch] [-M|-E|-S] [-o outfile] file...\n"
-	       "       scc [-D def[=val]]... [-U def]... [-I dir]... "
-	       "[-L dir]... [-l dir]...\n"
-	       "           [-dgksw] [-m arch] [-M|-E|-S] -c file...\n"
-	       "       scc [-D def[=val]]... [-U def]... [-I dir]... "
-	       "[-L dir]... [-l dir]...\n"
-	       "           [-dgksw] [-m arch] -c -o outfile file\n", stderr);
-	exit(1);
-}
-
-int
-main(int argc, char *argv[])
-{
-	struct items linkchain = { .n = 0, };
-	int link;
-
-	atexit(terminate);
-
-	if (!(arch = getenv("ARCH")))
-		arch = ARCH;
-	if (!(sys = getenv("SYS")))
-		sys = SYS;
-	if (!(abi = getenv("ABI")))
-		abi = ABI;
-	if (!(format = getenv("FORMAT")))
-		format = FORMAT;
-	if (!(prefix = getenv("SCCPREFIX")))
-		prefix = PREFIX;
-
-	ARGBEGIN {
-	case 'D':
-		addarg(CC1, "-D");
-		addarg(CC1, EARGF(usage()));
-		break;
-	case 'M':
-		Mflag = 1;
-		addarg(CC1, "-M");
-		break;
-	case 'E':
-		Eflag = 1;
-		addarg(CC1, "-E");
-		break;
-	case 'I':
-		addarg(CC1, "-I");
-		addarg(CC1, EARGF(usage()));
-		break;
-	case 'L':
-		addarg(LD, "-L");
-		addarg(LD, EARGF(usage()));
-		break;
-	case 'O':
-		EARGF(usage());
-		break;
-	case 'S':
-		Sflag = 1;
-		break;
-	case 'U':
-		addarg(CC1, "-U");
-		addarg(CC1, EARGF(usage()));
-		break;
-	case 'c':
-		cflag = 1;
-		break;
-	case 'd':
-		dflag = 1;
-		break;
-	case 'g':
-		addarg(AS, "-g");
-		addarg(LD, "-g");
-		break;
-	case 'k':
-		kflag = 1;
-		break;
-	case 'l':
-		newitem(&linkchain, "-l");
-		newitem(&linkchain, EARGF(usage()));
-		break;
-	case 'm':
-		arch = EARGF(usage());
-		break;
-	case 'o':
-		outfile = xstrdup(EARGF(usage()));
-		break;
-	case 's':
-		sflag = 1;
-		break;
-	case 't':
-		sys = EARGF(usage());
-		break;
-	case 'w':
-		Wflag = 0;
-		break;
-	case 'W':
-		Wflag = 1;
-		break;
-	case 'q':
-		Qflag = 0;
-		break;
-	case 'Q':
-		Qflag = 1;
-		break;
-	case '-':
-		fprintf(stderr,
-		        "scc: ignored parameter --%s\n", EARGF(usage()));
-		break;
-	default:
-		usage();
-	} ARGOPERAND {
-operand:
-		newitem(&linkchain, ARGOP());
-	} ARGEND
-
-	for (; *argv; --argc, ++argv)
-		goto operand;
-
-	if (Eflag && linkchain.n == 0)
-		newitem(&linkchain, "-");
-
-	if (Eflag && Mflag ||
-            (Eflag || Mflag) && (Sflag || kflag) ||
-	    linkchain.n == 0 ||
-	    linkchain.n > 1 && cflag && outfile)
-		usage();
-
-	if (!dflag) {
-		if ((devnullfd = open("/dev/null", O_WRONLY)) < 0)
-			fputs("scc: could not open /dev/null\n", stderr);
-	}
-
-	if (!(tmpdir = getenv("TMPDIR")) || !tmpdir[0])
-		tmpdir = ".";
-	tmpdirln = strlen(tmpdir);
-
-	build(&linkchain, (link = !(Mflag || Eflag || Sflag || cflag)));
-
-	if (!(link || cflag))
-		return failure;
-
-	if (link && !failure) {
-		addarg(LD, xstrdup("-lc"));
-		addarg(LD, xstrdup("-lcrt"));
-		spawn(settool(LD, NULL, LAST_TOOL));
-		validatetools();
-	}
-
-	if (sflag) {
-		spawn(settool(inittool(STRIP), NULL, LAST_TOOL));
-		validatetools();
-	}
-
-	return failure;
-}