scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

commit 6c25604f11a67fe7f4b1bea9eac1b8a3fb7a2737
parent 1fd3798827592044f688faf835df1e89ff8a760e
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sun,  6 Oct 2019 22:08:00 +0200

[cc] Rename scc executable to cc

Diffstat:
Msrc/cmd/cc/posix/Makefile | 6+++---
Asrc/cmd/cc/posix/cc.c | 658+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/cmd/cc/posix/cpp.sh | 2+-
Msrc/cmd/cc/posix/deps.mk | 14+++++++-------
Dsrc/cmd/cc/posix/scc.c | 658-------------------------------------------------------------------------------
5 files changed, 669 insertions(+), 669 deletions(-)

diff --git a/src/cmd/cc/posix/Makefile b/src/cmd/cc/posix/Makefile @@ -12,12 +12,12 @@ SYSLST =\ 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;\ diff --git a/src/cmd/cc/posix/cc.c b/src/cmd/cc/posix/cc.c @@ -0,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; +} diff --git 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 $@ diff --git 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 diff --git a/src/cmd/cc/posix/scc.c b/src/cmd/cc/posix/scc.c @@ -1,658 +0,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; -}