539 lines
9.8 KiB
C
539 lines
9.8 KiB
C
/* cc - call the C compiler Author: Erik Baalbergen */
|
|
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
|
|
#define SYMBOL_FILE "symbol.out" /* symbol table for prof */
|
|
|
|
#define MAXARGC 64 /* maximum number of arguments allowed in a list */
|
|
#define USTR_SIZE 64 /* maximum length of string variable */
|
|
|
|
typedef char USTRING[USTR_SIZE];
|
|
|
|
struct arglist {
|
|
int al_argc;
|
|
char *al_argv[MAXARGC];
|
|
};
|
|
|
|
|
|
/* MINIX paths */
|
|
char *PP = "/usr/lib/cpp";
|
|
char *CEM = "/usr/lib/cem";
|
|
char *OPT = "/usr/lib/opt";
|
|
char *CG = "/usr/lib/cg";
|
|
char *ASLD = "/usr/bin/asld";
|
|
char *AST = "/usr/bin/ast";
|
|
char *SHELL = "/bin/sh";
|
|
char *LIBDIR = "/usr/lib";
|
|
|
|
struct arglist LD_HEAD = {1, { "/usr/lib/crtso.s" } };
|
|
struct arglist M_LD_HEAD = {1, { "/usr/lib/mrtso.s" } };
|
|
struct arglist LD_TAIL = {2, { "/usr/lib/libc.a", "/usr/lib/end.s" } };
|
|
|
|
char *o_FILE = "a.out"; /* default name for executable file */
|
|
|
|
#define AST_FLAGS "-X"
|
|
#define AST_TAIL "symbol.out"
|
|
|
|
#define remove(str) (unlink(str), (str)[0] = '\0')
|
|
#define cleanup(str) (str && remove(str))
|
|
#define init(al) (al)->al_argc = 1
|
|
#define library(nm) \
|
|
mkstr(alloc((unsigned int)strlen(nm) + strlen(LIBDIR) + 7), \
|
|
LIBDIR, "/lib", nm, ".a", 0)
|
|
|
|
char *ProgCall = 0;
|
|
|
|
struct arglist SRCFILES;
|
|
struct arglist LDFILES;
|
|
struct arglist GEN_LDFILES;
|
|
|
|
struct arglist PP_FLAGS;
|
|
struct arglist CEM_FLAGS;
|
|
|
|
int RET_CODE = 0;
|
|
|
|
struct arglist OPT_FLAGS;
|
|
struct arglist CG_FLAGS;
|
|
struct arglist ASLD_FLAGS;
|
|
struct arglist DEBUG_FLAGS;
|
|
|
|
struct arglist CALL_VEC[2];
|
|
|
|
int o_flag = 0;
|
|
int S_flag = 0;
|
|
int v_flag = 0;
|
|
int F_flag = 0; /* use pipes by default */
|
|
int s_flag = 0;
|
|
int p_flag = 0; /* profil flag */
|
|
|
|
char *mkstr();
|
|
char *alloc();
|
|
|
|
USTRING ifile, kfile, sfile, mfile, ofile;
|
|
USTRING BASE;
|
|
|
|
char *tmpdir = "/tmp";
|
|
char tmpname[15];
|
|
|
|
trapcc(sig)
|
|
int sig;
|
|
{
|
|
signal(sig, SIG_IGN);
|
|
cleanup(ifile);
|
|
cleanup(kfile);
|
|
cleanup(sfile);
|
|
cleanup(mfile);
|
|
cleanup(ofile);
|
|
exit(1);
|
|
}
|
|
|
|
main(argc, argv)
|
|
char *argv[];
|
|
{
|
|
register char *f;
|
|
char *str;
|
|
char **argvec;
|
|
int count;
|
|
int ext;
|
|
register struct arglist *call = &CALL_VEC[0], *call1 = &CALL_VEC[1];
|
|
char *file;
|
|
char *ldfile = 0;
|
|
|
|
ProgCall = *argv++;
|
|
|
|
if (signal(SIGHUP, SIG_IGN) != SIG_IGN) signal(SIGHUP, trapcc);
|
|
if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, trapcc);
|
|
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) signal(SIGQUIT, trapcc);
|
|
while (--argc > 0) {
|
|
if (*(str = *argv++) != '-') {
|
|
append(&SRCFILES, str);
|
|
continue;
|
|
}
|
|
|
|
switch (str[1]) {
|
|
|
|
case 'c':
|
|
S_flag = 1;
|
|
break;
|
|
case 'D':
|
|
case 'I':
|
|
case 'U':
|
|
append(&PP_FLAGS, str);
|
|
break;
|
|
case 'F':
|
|
F_flag = 1;
|
|
break;
|
|
case 'l':
|
|
append(&SRCFILES, library(&str[2]));
|
|
break;
|
|
case 'o':
|
|
o_flag = 1;
|
|
if (argc-- >= 0)
|
|
o_FILE = *argv++;
|
|
break;
|
|
case 'O':
|
|
append(&CG_FLAGS, "-p4");
|
|
break;
|
|
case 'S':
|
|
S_flag = 1;
|
|
break;
|
|
case 'v':
|
|
v_flag++;
|
|
break;
|
|
case 'T':
|
|
tmpdir = &str[2];
|
|
append(&ASLD_FLAGS, str);
|
|
/*FALLTHROUGH*/
|
|
case 'R':
|
|
case 'w':
|
|
append(&CEM_FLAGS, str);
|
|
break;
|
|
case 's':
|
|
s_flag = 1;
|
|
break;
|
|
case 'p':
|
|
p_flag = 1;
|
|
s_flag = 1;
|
|
break;
|
|
case 'L':
|
|
if (strcmp(&str[1], "LIB") == 0) {
|
|
append(&OPT_FLAGS, "-L");
|
|
break;
|
|
}
|
|
/*FALLTHROUGH*/
|
|
default: /* -i goes here! */
|
|
append(&ASLD_FLAGS, str);
|
|
break;
|
|
}
|
|
}
|
|
mktempname(tmpname);
|
|
|
|
append(&CEM_FLAGS, "-L"); /* disable profiling */
|
|
count = SRCFILES.al_argc;
|
|
argvec = &(SRCFILES.al_argv[0]);
|
|
|
|
while (count-- > 0) {
|
|
basename(file = *argvec++, BASE);
|
|
|
|
if (v_flag && SRCFILES.al_argc > 1) {
|
|
write(1, file, strlen(file));
|
|
write(1, ":\n", 2);
|
|
}
|
|
|
|
ext = extension(file);
|
|
|
|
if (ext == 'c') { /* .c to .i (if F_flag) or .k */
|
|
init(call);
|
|
append(call, PP);
|
|
concat(call, &PP_FLAGS);
|
|
append(call, file);
|
|
|
|
if (F_flag) { /* to .i */
|
|
f = mkstr(ifile, tmpdir, tmpname, ".i", 0);
|
|
if (runvec(call, f)) {
|
|
file = ifile;
|
|
ext = 'i';
|
|
}
|
|
else {
|
|
remove(ifile);
|
|
continue;
|
|
}
|
|
}
|
|
else { /* use a pipe; to .k */
|
|
init(call1);
|
|
append(call1, CEM);
|
|
concat(call1, &DEBUG_FLAGS);
|
|
concat(call1, &CEM_FLAGS);
|
|
append(call1, "-"); /* use stdin */
|
|
f = mkstr(kfile, tmpdir, tmpname, ".k", 0);
|
|
append(call1, f);
|
|
if (runvec2(call, call1)) {
|
|
file = kfile;
|
|
ext = 'k';
|
|
}
|
|
else {
|
|
remove(kfile);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ext == 'i') { /* .i to .k */
|
|
init(call);
|
|
append(call, CEM);
|
|
concat(call, &DEBUG_FLAGS);
|
|
concat(call, &CEM_FLAGS);
|
|
append(call, file);
|
|
f = mkstr(kfile, tmpdir, tmpname, ".k", 0);
|
|
append(call, f);
|
|
|
|
if (runvec(call, (char *)0)) {
|
|
file = kfile;
|
|
ext = 'k';
|
|
}
|
|
else {
|
|
remove(kfile);
|
|
continue;
|
|
}
|
|
cleanup(ifile);
|
|
}
|
|
|
|
/* .k to .m */
|
|
if (ext == 'k') {
|
|
init(call);
|
|
append(call, OPT);
|
|
concat(call, &OPT_FLAGS);
|
|
append(call, file);
|
|
f = mkstr(mfile, tmpdir, tmpname, ".m", 0);
|
|
if (runvec(call, f) == 0)
|
|
continue;
|
|
file = mfile;
|
|
ext = 'm';
|
|
cleanup(kfile);
|
|
}
|
|
|
|
/* .m to .s */
|
|
if (ext == 'm') {
|
|
ldfile = S_flag ? ofile : alloc(strlen(BASE) + 3);
|
|
|
|
init(call);
|
|
append(call, CG);
|
|
concat(call, &CG_FLAGS);
|
|
append(call, file);
|
|
f = mkstr(ldfile, BASE, ".s", 0);
|
|
append(call, f);
|
|
if (runvec(call, (char *)0) == 0)
|
|
continue;
|
|
cleanup(mfile);
|
|
file = ldfile;
|
|
ext = 's';
|
|
}
|
|
|
|
if (S_flag)
|
|
continue;
|
|
|
|
append(&LDFILES, file);
|
|
if (ldfile) {
|
|
append(&GEN_LDFILES, ldfile);
|
|
ldfile = 0;
|
|
}
|
|
}
|
|
|
|
/* *.s to a.out */
|
|
if (RET_CODE == 0 && LDFILES.al_argc > 0) {
|
|
init(call);
|
|
append(call, ASLD);
|
|
concat(call, &ASLD_FLAGS);
|
|
if (s_flag) append(call, "-s");
|
|
append(call, "-o");
|
|
append(call, o_FILE);
|
|
if (p_flag)
|
|
concat(call, &M_LD_HEAD);
|
|
else concat(call, &LD_HEAD);
|
|
concat(call, &LDFILES);
|
|
concat(call, &LD_TAIL);
|
|
if (s_flag)
|
|
f = SYMBOL_FILE;
|
|
else f = (char *) 0;
|
|
if (runvec(call, f)) {
|
|
register i = GEN_LDFILES.al_argc;
|
|
|
|
while (i-- > 0)
|
|
remove(GEN_LDFILES.al_argv[i]);
|
|
|
|
}
|
|
}
|
|
/* add symbol table when p_flag is set */
|
|
if (s_flag) {
|
|
init(call);
|
|
append(call, AST);
|
|
append(call, AST_FLAGS);
|
|
append(call, o_FILE);
|
|
append(call, AST_TAIL);
|
|
(void) runvec(call, (char *) 0);
|
|
}
|
|
return(RET_CODE);
|
|
}
|
|
|
|
#define BUFSIZE (USTR_SIZE * MAXARGC)
|
|
char buf[BUFSIZE];
|
|
char *bufptr = &buf[0];
|
|
|
|
char *
|
|
alloc(u)
|
|
unsigned u;
|
|
{
|
|
register char *p = bufptr;
|
|
|
|
if ((bufptr += u) >= &buf[BUFSIZE])
|
|
panic("no space\n");
|
|
return p;
|
|
}
|
|
|
|
append(al, arg)
|
|
struct arglist *al;
|
|
char *arg;
|
|
{
|
|
if (al->al_argc >= MAXARGC)
|
|
panic("argument list overflow\n");
|
|
al->al_argv[(al->al_argc)++] = arg;
|
|
}
|
|
|
|
concat(al1, al2)
|
|
struct arglist *al1, *al2;
|
|
{
|
|
register i = al2->al_argc;
|
|
register char **p = &(al1->al_argv[al1->al_argc]);
|
|
register char **q = &(al2->al_argv[0]);
|
|
|
|
if ((al1->al_argc += i) >= MAXARGC)
|
|
panic("argument list overflow\n");
|
|
while (i-- > 0)
|
|
*p++ = *q++;
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
char *
|
|
mkstr(dst, arg)
|
|
char *dst, *arg;
|
|
{
|
|
char **vec = (char **) &arg;
|
|
register char *p;
|
|
register char *q = dst;
|
|
|
|
while (p = *vec++) {
|
|
while (*q++ = *p++);
|
|
q--;
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
basename(str, dst)
|
|
char *str;
|
|
register char *dst;
|
|
{
|
|
register char *p1 = str;
|
|
register char *p2 = p1;
|
|
|
|
while (*p1)
|
|
if (*p1++ == '/')
|
|
p2 = p1;
|
|
p1--;
|
|
if (*--p1 == '.') {
|
|
*p1 = '\0';
|
|
while (*dst++ = *p2++);
|
|
*p1 = '.';
|
|
}
|
|
else
|
|
while (*dst++ = *p2++);
|
|
}
|
|
|
|
int
|
|
extension(fn)
|
|
register char *fn;
|
|
{
|
|
char c;
|
|
|
|
while (*fn++) ;
|
|
fn--;
|
|
c = *--fn;
|
|
return (*--fn == '.') ? c : 0;
|
|
}
|
|
|
|
runvec(vec, outp)
|
|
struct arglist *vec;
|
|
char *outp;
|
|
{
|
|
int pid, fd, status;
|
|
|
|
if (v_flag) {
|
|
pr_vec(vec);
|
|
write(2, "\n", 1);
|
|
}
|
|
if ((pid = fork()) == 0) { /* start up the process */
|
|
if (outp) { /* redirect standard output */
|
|
close(1);
|
|
if ((fd = creat(outp, 0666)) != 1)
|
|
panic("cannot create output file\n");
|
|
}
|
|
ex_vec(vec);
|
|
}
|
|
if (pid == -1)
|
|
panic("no more processes\n");
|
|
wait(&status);
|
|
return status ? ((RET_CODE = 1), 0) : 1;
|
|
}
|
|
|
|
runvec2(vec0, vec1)
|
|
register struct arglist *vec0, *vec1;
|
|
{
|
|
/* set up 'vec0 | vec1' */
|
|
int pid, status1, status2, p[2];
|
|
|
|
if (v_flag) {
|
|
pr_vec(vec0);
|
|
write(2, " | ", 3);
|
|
pr_vec(vec1);
|
|
write(2, "\n", 1);
|
|
}
|
|
if (pipe(p) == -1)
|
|
panic("cannot create pipe\n");
|
|
if ((pid = fork()) == 0) {
|
|
close(1);
|
|
if (dup(p[1]) != 1)
|
|
panic("bad dup\n");
|
|
close(p[0]);
|
|
close(p[1]);
|
|
ex_vec(vec0);
|
|
}
|
|
if (pid == -1)
|
|
panic("no more processes\n");
|
|
if ((pid = fork()) == 0) {
|
|
close(0);
|
|
if (dup(p[0]) != 0)
|
|
panic("bad dup\n");
|
|
close(p[0]);
|
|
close(p[1]);
|
|
ex_vec(vec1);
|
|
}
|
|
if (pid == -1)
|
|
panic("no more processes\n");
|
|
close(p[0]);
|
|
close(p[1]);
|
|
wait(&status1);
|
|
wait(&status2);
|
|
return (status1 || status2) ? ((RET_CODE = 1), 0) : 1;
|
|
}
|
|
|
|
/*VARARGS1*/
|
|
panic(str, argv)
|
|
char *str;
|
|
int argv;
|
|
{
|
|
write(2, str, strlen(str));
|
|
exit(1);
|
|
}
|
|
|
|
char *
|
|
cindex(s, c)
|
|
char *s, c;
|
|
{
|
|
while (*s)
|
|
if (*s++ == c)
|
|
return s - 1;
|
|
return (char *) 0;
|
|
}
|
|
|
|
pr_vec(vec)
|
|
register struct arglist *vec;
|
|
{
|
|
register char **ap = &vec->al_argv[1];
|
|
|
|
vec->al_argv[vec->al_argc] = 0;
|
|
write(2, *ap, strlen(*ap) );
|
|
while (*++ap) {
|
|
write(2, " ", 1);
|
|
write(2, *ap, strlen(*ap));
|
|
}
|
|
}
|
|
|
|
ex_vec(vec)
|
|
register struct arglist *vec;
|
|
{
|
|
extern int errno;
|
|
static char *dum_env[1] = (char *) 0;
|
|
|
|
vec->al_argv[vec->al_argc] = 0;
|
|
execve(vec->al_argv[1], &(vec->al_argv[1]), dum_env);
|
|
if (errno == ENOEXEC) { /* not an a.out, try it with the SHELL */
|
|
vec->al_argv[0] = SHELL;
|
|
execv(SHELL, &(vec->al_argv[0]));
|
|
}
|
|
if (access(vec->al_argv[1], 1) == 0) {
|
|
/* File is executable. */
|
|
write(2, "Cannot execute ", 15);
|
|
write(2, vec->al_argv[1], strlen(vec->al_argv[1]));
|
|
write(2, ". Not enough memory.\n", 21);
|
|
write(2, "Try cc -F or use chmem to reduce its stack allocation\n",54);
|
|
} else {
|
|
write(2, vec->al_argv[1], strlen(vec->al_argv[1]));
|
|
write(2, " is not executable\n", 19);
|
|
}
|
|
exit(1);
|
|
}
|
|
|
|
mktempname(nm)
|
|
char nm[];
|
|
{
|
|
register i;
|
|
int pid = getpid();
|
|
|
|
nm[0] = '/'; nm[1] = 'c'; nm[2] = 'e'; nm[3] = 'm';
|
|
for (i = 9; i > 3; i--) {
|
|
nm[i] = (pid % 10) + '0';
|
|
pid /= 10;
|
|
}
|
|
nm[10] = '\0'; /* null termination */
|
|
}
|