1060 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1060 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*	Driver for Minix compilers.
 | 
						|
	Written june 1987 by Ceriel J.H. Jacobs, partly derived from old
 | 
						|
	cc-driver, written by Erik Baalbergen.
 | 
						|
	This driver is mostly table-driven, the table being in the form of
 | 
						|
	some global initialized structures.
 | 
						|
*/
 | 
						|
/* $Header$ */
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/wait.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <unistd.h>
 | 
						|
 | 
						|
/* Paths.  (Executables in /usr are first tried with /usr stripped off.) */
 | 
						|
#define SHELL		"/bin/sh"
 | 
						|
#define PP		"/usr/lib/ncpp"
 | 
						|
#define IRREL		"/usr/lib/irrel"
 | 
						|
#define CEM		"/usr/lib/ncem"
 | 
						|
#define M2EM		"/usr/lib/nm2em"
 | 
						|
#define ENCODE		"/usr/lib/em_encode"
 | 
						|
#define OPT		"/usr/lib/nopt"
 | 
						|
#define CG		"/usr/lib/ncg"
 | 
						|
#define AS		"/usr/lib/as"
 | 
						|
#define LD		"/usr/lib/ld"
 | 
						|
#define CV		"/usr/lib/cv"
 | 
						|
#define LIBDIR		"/usr/lib"
 | 
						|
#define CRT		"/usr/lib/ncrtso.o"
 | 
						|
#define PEM		"/usr/lib/npem"
 | 
						|
#define PRT		"/usr/lib/nprtso.o"
 | 
						|
#define M2RT		"/usr/lib/nm2rtso.o"
 | 
						|
#define LIBC            "/usr/lib/libd.a", "/usr/lib/libc.a"
 | 
						|
#define LIBP		"/usr/lib/libp.a", "/usr/lib/libc.a"
 | 
						|
#define LIBM2		"/usr/lib/libm2.a", "/usr/lib/libc.a"
 | 
						|
#define END             "/usr/lib/libe.a", "/usr/lib/end.a"
 | 
						|
#define M2DEF		"-I/usr/lib/m2"
 | 
						|
 | 
						|
 | 
						|
/*	every pass that this program knows about has associated with it
 | 
						|
	a structure, containing such information as its name, where it
 | 
						|
	resides, the flags it accepts, and the like.
 | 
						|
*/
 | 
						|
struct passinfo {
 | 
						|
	char *p_name;		/* name of this pass */
 | 
						|
	char *p_path;		/* where is it */
 | 
						|
	char *p_from;		/* suffix of source (comma-separated list) */
 | 
						|
	char *p_to;		/* suffix of destination */
 | 
						|
	char *p_acceptflags;	/* comma separated list; format:
 | 
						|
			   		flag
 | 
						|
			   		flag*
 | 
						|
			   		flag=xxx
 | 
						|
					flag*=xxx[*]
 | 
						|
				   where a star matches a, possibly empty, 
 | 
						|
				   string
 | 
						|
				*/
 | 
						|
	int  p_flags;
 | 
						|
#define INPUT	01		/* needs input file as argument */
 | 
						|
#define OUTPUT	02		/* needs output file as argument */
 | 
						|
#define LOADER	04		/* this pass is the loader */
 | 
						|
#define STDIN	010		/* reads from standard input */
 | 
						|
#define STDOUT	020		/* writes on standard output */
 | 
						|
#define NOCLEAN	040		/* do not remove target if this pass fails */
 | 
						|
#define O_OUTPUT 0100		/* -o outputfile, hack for as */
 | 
						|
#define PREPALWAYS	0200	/* always to be preprocessed */
 | 
						|
#define PREPCOND	0400	/* preprocessed when starting with '#' */
 | 
						|
#define PREPNOLN	01000	/* suppress line number info (cpp -P) */
 | 
						|
};
 | 
						|
 | 
						|
#define MAXHEAD	10
 | 
						|
#define MAXTAIL	5
 | 
						|
#define MAXPASS	7
 | 
						|
 | 
						|
/*	Every language handled by this program has a "compile" structure
 | 
						|
	associated with it, describing the start-suffix, how the driver for
 | 
						|
	this language is called, which passes must be called, which flags
 | 
						|
	and arguments must be passed to these passes, etc.
 | 
						|
	The language is determined by the suffix of the argument program.
 | 
						|
	However, if this suffix does not determine a language (DEFLANG),
 | 
						|
	the callname is used.
 | 
						|
	Notice that the 's' suffix does not determine a language, because
 | 
						|
	the input file could have been derived from f.i. a C-program.
 | 
						|
	So, if you use "cc x.s", the C-runtime system will be used, but if
 | 
						|
	you use "as x.s", it will not.
 | 
						|
*/
 | 
						|
struct compile {
 | 
						|
	char *c_suffix;		/* starting suffix of this list of passes */
 | 
						|
	char *c_callname;	/* affects runtime system loaded with program */
 | 
						|
	struct pass {
 | 
						|
		char *pp_name;		/* name of the pass */
 | 
						|
		char *pp_head[MAXHEAD];	/* args in front of filename */
 | 
						|
		char *pp_tail[MAXTAIL];	/* args after filename */
 | 
						|
	} c_passes[MAXPASS];
 | 
						|
	int  c_flags;
 | 
						|
#define DEFLANG		010	/* this suffix determines a language */
 | 
						|
};
 | 
						|
 | 
						|
struct passinfo passinfo[] = {
 | 
						|
	{ "cpp", PP, "CPP", "i", "wo=o,I*,D*,U*,P", INPUT|STDOUT },
 | 
						|
	{ "irrel", IRREL, "i", "i", "m", INPUT},
 | 
						|
	{ "cem", CEM, "i,c", "k", "m=o,p,wa=a,wo=o,ws=s,w,T*", INPUT|OUTPUT|PREPALWAYS },
 | 
						|
	{ "pc", PEM, "i,p", "k", "n=L,w,a,A,R", INPUT|OUTPUT|PREPCOND },
 | 
						|
	{ "m2", M2EM, "i,mod", "k", "n=L,w*,A,R,W*,3,I*", INPUT|OUTPUT|PREPCOND },
 | 
						|
	{ "encode", ENCODE, "i,e", "k", "", INPUT|STDOUT|PREPCOND|PREPNOLN },
 | 
						|
	{ "opt", OPT, "k", "m", "", STDIN|STDOUT },
 | 
						|
	{ "cg", CG, "m", "s", "O=p4", INPUT|OUTPUT },
 | 
						|
	{ "as", AS, "i,s", "o", "T*", INPUT|O_OUTPUT|PREPCOND },
 | 
						|
	{ "ld", LD, "o", "out", "i,s", INPUT|LOADER },	/* changed */
 | 
						|
	{ "cv", CV, "out", 0, "", INPUT|OUTPUT|NOCLEAN },	/* must come after loader */
 | 
						|
	{ 0}
 | 
						|
};
 | 
						|
 | 
						|
#define	PREP_FLAGS	"-D_EM_WSIZE=2", "-D_EM_PSIZE=2", "-D_EM_SSIZE=2", \
 | 
						|
			"-D_EM_LSIZE=4", "-D_EM_FSIZE=4", "-D_EM_DSIZE=8", \
 | 
						|
			"-D__ACK__", "-D__minix", "-D__i86"
 | 
						|
 | 
						|
struct pass preprocessor = { "cpp",
 | 
						|
			    { PREP_FLAGS }
 | 
						|
			    , {0}
 | 
						|
			    };
 | 
						|
 | 
						|
struct pass prepnoln = { "cpp",
 | 
						|
			    { PREP_FLAGS, "-P" }
 | 
						|
			    , {0}
 | 
						|
			    };
 | 
						|
 | 
						|
struct pass irrel = { "irrel",
 | 
						|
			    {0}
 | 
						|
			};
 | 
						|
 | 
						|
/* The "*" in the arguments for the loader indicates the place where the
 | 
						|
 * fp-emulation library should come.
 | 
						|
 */
 | 
						|
struct compile passes[] = {
 | 
						|
{	"c", "cc", 
 | 
						|
	{	{ "cem", {"-L"}, {0} },	/* changed */
 | 
						|
		{ "opt", {0}, {0} },
 | 
						|
		{ "cg", {0}, {0} },
 | 
						|
		{ "as", {"-"}, {0} },
 | 
						|
		{ "ld", {CRT}, /* changed */
 | 
						|
			  {LIBC, "*",  END}},
 | 
						|
		{ "cv", {0}, {0} }
 | 
						|
	},
 | 
						|
	DEFLANG
 | 
						|
},
 | 
						|
{	"p", "pc",
 | 
						|
	{	{ "pc", {0}, {0} },
 | 
						|
		{ "opt", {0}, {0} },
 | 
						|
		{ "cg", {0}, {0} },
 | 
						|
		{ "as", {"-"}, {0} },
 | 
						|
		{ "ld", {PRT}, 
 | 
						|
			  {LIBP,
 | 
						|
			    "*", END}},
 | 
						|
		{ "cv", {0}, {0} }
 | 
						|
	},
 | 
						|
	DEFLANG
 | 
						|
},
 | 
						|
{	"mod", "m2",
 | 
						|
	{	{ "m2", {M2DEF}, {0} },
 | 
						|
		{ "opt", {0}, {0} },
 | 
						|
		{ "cg", {0}, {0} },
 | 
						|
		{ "as", {"-"}, {0} },
 | 
						|
		{ "ld", {M2RT}, 
 | 
						|
			  {LIBM2,
 | 
						|
			    "*", END}},
 | 
						|
		{ "cv", {0}, {0} }
 | 
						|
	},
 | 
						|
	DEFLANG
 | 
						|
},
 | 
						|
{	"e", "encode",
 | 
						|
	{	{ "encode", {0}, {0}},
 | 
						|
		{ "opt", {0}, {0} },
 | 
						|
		{ "cg", {0}, {0} },
 | 
						|
		{ "as", {"-"}, {0} },
 | 
						|
		{ "ld", {0}, {"*", END}},
 | 
						|
		{ "cv", {0}, {0} }
 | 
						|
	},
 | 
						|
	DEFLANG
 | 
						|
},
 | 
						|
{	"s", "as",
 | 
						|
	{	{ "as", {0}, {0}}
 | 
						|
	},
 | 
						|
	0
 | 
						|
},
 | 
						|
{	"CPP", "cpp",
 | 
						|
	{	{ "cpp", {PREP_FLAGS}, {0}}
 | 
						|
	},
 | 
						|
	DEFLANG
 | 
						|
},
 | 
						|
{	0},
 | 
						|
};
 | 
						|
 | 
						|
#define MAXARGC	150	/* 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];
 | 
						|
};
 | 
						|
 | 
						|
struct arglist CALLVEC;
 | 
						|
 | 
						|
int kids = -1;
 | 
						|
 | 
						|
char *o_FILE = "a.out"; /* default name for executable file */
 | 
						|
 | 
						|
#define init(a)		((a)->al_argc = 1)
 | 
						|
#define cleanup(str)		(str && remove(str))
 | 
						|
 | 
						|
char *ProgCall = 0;
 | 
						|
 | 
						|
int RET_CODE = 0;
 | 
						|
 | 
						|
char *stopsuffix;
 | 
						|
int v_flag = 0;
 | 
						|
int t_flag = 0;
 | 
						|
int noexec = 0;
 | 
						|
int fp_lib = 1;
 | 
						|
int E_flag = 0;
 | 
						|
int i_flag = 1;
 | 
						|
 | 
						|
 | 
						|
USTRING curfil;
 | 
						|
USTRING newfil;
 | 
						|
struct arglist SRCFILES;
 | 
						|
struct arglist LDIRS;
 | 
						|
struct arglist LDFILES;
 | 
						|
struct arglist GEN_LDFILES;
 | 
						|
struct arglist FLAGS;
 | 
						|
 | 
						|
char *tmpdir = "/tmp";
 | 
						|
char tmpname[64];
 | 
						|
 | 
						|
struct compile *compbase;
 | 
						|
struct pass *loader;
 | 
						|
struct passinfo *loaderinfo;
 | 
						|
char *source;
 | 
						|
int maxLlen;
 | 
						|
 | 
						|
_PROTOTYPE(char *library, (char *nm ));
 | 
						|
_PROTOTYPE(void trapcc, (int sig ));
 | 
						|
_PROTOTYPE(int main, (int argc, char *argv []));
 | 
						|
_PROTOTYPE(int remove, (char *str ));
 | 
						|
_PROTOTYPE(char *alloc, (unsigned u ));
 | 
						|
_PROTOTYPE(int append, (struct arglist *al, char *arg ));
 | 
						|
_PROTOTYPE(int concat, (struct arglist *al1, struct arglist *al2 ));
 | 
						|
_PROTOTYPE(char *mkstr, (char *dst, char *arg1, char *arg2, char *arg3 ));
 | 
						|
_PROTOTYPE(int basename, (char *str, char *dst ));
 | 
						|
_PROTOTYPE(char *extension, (char *fln ));
 | 
						|
_PROTOTYPE(int runvec, (struct arglist *vec, struct passinfo *pass, char *in, char *out ));
 | 
						|
_PROTOTYPE(int prnum, (unsigned x ));
 | 
						|
_PROTOTYPE(int prs, (char *str ));
 | 
						|
_PROTOTYPE(int panic, (char *str ));
 | 
						|
_PROTOTYPE(int pr_vec, (struct arglist *vec ));
 | 
						|
_PROTOTYPE(int ex_vec, (struct arglist *vec ));
 | 
						|
_PROTOTYPE(int mktempname, (char *nm ));
 | 
						|
_PROTOTYPE(int mkbase, (void));
 | 
						|
_PROTOTYPE(int mkloader, (void));
 | 
						|
_PROTOTYPE(int needsprep, (char *name ));
 | 
						|
_PROTOTYPE(int cfile, (char *name ));
 | 
						|
_PROTOTYPE(char *apply, (struct passinfo *pinf, struct compile *cp, char *name, int passindex, int noremove, int first, char *resultname ));
 | 
						|
_PROTOTYPE(int applicable, (struct passinfo *pinf, char *suffix ));
 | 
						|
_PROTOTYPE(char *process, (char *name, int noremove ));
 | 
						|
_PROTOTYPE(int mkvec, (struct arglist *call, char *in, char *out, struct pass *pass, struct passinfo *pinf ));
 | 
						|
_PROTOTYPE(int callld, (struct arglist *in, char *out, struct pass *pass, struct passinfo *pinf ));
 | 
						|
_PROTOTYPE(int clean, (struct arglist *c ));
 | 
						|
_PROTOTYPE(int scanflags, (struct arglist *call, struct passinfo *pinf ));
 | 
						|
 | 
						|
 | 
						|
 | 
						|
char *
 | 
						|
library(nm)
 | 
						|
	char	*nm;
 | 
						|
{
 | 
						|
	static char	f[512];
 | 
						|
	int	Lcount;
 | 
						|
 | 
						|
	for (Lcount = 0; Lcount < LDIRS.al_argc; Lcount++) {
 | 
						|
		mkstr(f, LDIRS.al_argv[Lcount], "/lib", nm);
 | 
						|
		strcat(f, ".a");
 | 
						|
		if (access(f, 0) != 0) {
 | 
						|
			f[strlen(f)-1] = 'a';
 | 
						|
			if (access(f, 0) != 0) continue;
 | 
						|
		}
 | 
						|
		return f;
 | 
						|
	}
 | 
						|
	mkstr(f, LIBDIR, "/lib", nm);
 | 
						|
	strcat(f, ".a");
 | 
						|
	if (access(f, 0) != 0) {
 | 
						|
		int i = strlen(f) - 1;
 | 
						|
		f[i] = 'a';
 | 
						|
		if (access(f, 0) != 0) f[i] = 'A';
 | 
						|
	}
 | 
						|
	return f;
 | 
						|
}
 | 
						|
 | 
						|
void trapcc(sig)
 | 
						|
	int sig;
 | 
						|
{
 | 
						|
	signal(sig, SIG_IGN);
 | 
						|
	if (kids != -1) kill(kids, sig);
 | 
						|
	cleanup(newfil);
 | 
						|
	cleanup(curfil);
 | 
						|
	exit(1);
 | 
						|
}
 | 
						|
 | 
						|
main(argc, argv)
 | 
						|
	char *argv[];
 | 
						|
{
 | 
						|
	char *str;
 | 
						|
	char **argvec;
 | 
						|
	int count;
 | 
						|
	char *file;
 | 
						|
 | 
						|
	maxLlen = strlen(LIBDIR);
 | 
						|
	ProgCall = *argv++;
 | 
						|
 | 
						|
	mkbase();
 | 
						|
 | 
						|
	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++) != '-' || str[1] == 0) {
 | 
						|
			append(&SRCFILES, str);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (strcmp(str, "-com") == 0) {
 | 
						|
			i_flag = 0;
 | 
						|
		} else
 | 
						|
		if (strcmp(str, "-sep") == 0) {
 | 
						|
			i_flag = 1;
 | 
						|
		} else {
 | 
						|
			switch (str[1]) {
 | 
						|
 | 
						|
			case 'c':
 | 
						|
				stopsuffix = "o";
 | 
						|
				if (str[2] == '.') stopsuffix = str + 3;
 | 
						|
				break;
 | 
						|
			case 'f':
 | 
						|
				fp_lib = (strcmp(str+2, "hard") != 0);
 | 
						|
				break;
 | 
						|
			case 'F':
 | 
						|
			case 'W':
 | 
						|
				/* Ignore. */
 | 
						|
				break;
 | 
						|
			case 'L':
 | 
						|
				append(&LDIRS, &str[2]);
 | 
						|
				count = strlen(&str[2]);
 | 
						|
				if (count > maxLlen) maxLlen = count;
 | 
						|
				break;
 | 
						|
			case 'l':
 | 
						|
				append(&SRCFILES, library(&str[2]));
 | 
						|
				break;
 | 
						|
			case 'm':
 | 
						|
				/* Use -m, ignore -mxxx. */
 | 
						|
				if (str[2] == 0) append(&FLAGS, str);
 | 
						|
				break;
 | 
						|
			case 'o':
 | 
						|
				if (argc-- >= 0)
 | 
						|
					o_FILE = *argv++;
 | 
						|
				break;
 | 
						|
			case 'S':
 | 
						|
				stopsuffix = "s";
 | 
						|
				break;
 | 
						|
			case 'E':
 | 
						|
				E_flag = 1;
 | 
						|
				stopsuffix = "i";
 | 
						|
				break;
 | 
						|
			case 'P':
 | 
						|
				stopsuffix = "i";
 | 
						|
				append(&FLAGS, str);
 | 
						|
				break;
 | 
						|
			case 'v':
 | 
						|
				v_flag++;
 | 
						|
				if (str[2] == 'n')
 | 
						|
					noexec = 1;
 | 
						|
				break;
 | 
						|
			case 't':
 | 
						|
				/* save temporaries */
 | 
						|
				t_flag++;
 | 
						|
				break;
 | 
						|
			case '.':
 | 
						|
				if (str[2] == 'o') {
 | 
						|
					/* no runtime start-off */
 | 
						|
					loader->pp_head[0] = 0;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			case 'i':
 | 
						|
				i_flag++;
 | 
						|
				break;
 | 
						|
			case 'T':
 | 
						|
				tmpdir = &str[2];
 | 
						|
				/*FALLTHROUGH*/
 | 
						|
			default:
 | 
						|
				append(&FLAGS, str);
 | 
						|
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (i_flag) append(&FLAGS, "-i");
 | 
						|
 | 
						|
	mktempname(tmpname);
 | 
						|
 | 
						|
	count = SRCFILES.al_argc;
 | 
						|
	argvec = &(SRCFILES.al_argv[0]);
 | 
						|
 | 
						|
	while (count-- > 0) {
 | 
						|
 | 
						|
		file = *argvec++;
 | 
						|
		source = file;
 | 
						|
 | 
						|
		file = process(file, 1);
 | 
						|
	
 | 
						|
		if (file && ! stopsuffix) append(&LDFILES, file);
 | 
						|
	}
 | 
						|
 | 
						|
	clean(&SRCFILES);
 | 
						|
 | 
						|
	/* loader ... */
 | 
						|
	if (RET_CODE == 0 && LDFILES.al_argc > 0) {
 | 
						|
		register struct passinfo *pp = passinfo;
 | 
						|
 | 
						|
		while (!(pp->p_flags & LOADER)) pp++;
 | 
						|
		mkstr(newfil, tmpname, pp->p_to, "");
 | 
						|
		callld(&LDFILES, !((pp+1)->p_name) ? o_FILE : newfil, loader, pp);
 | 
						|
		if (RET_CODE == 0) {
 | 
						|
			register int i = GEN_LDFILES.al_argc;
 | 
						|
 | 
						|
			while (i-- > 0) {
 | 
						|
				remove(GEN_LDFILES.al_argv[i]);
 | 
						|
				free(GEN_LDFILES.al_argv[i]);
 | 
						|
			}
 | 
						|
			if ((++pp)->p_name) {
 | 
						|
				process(newfil, 0);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	exit(RET_CODE);
 | 
						|
}
 | 
						|
 | 
						|
remove(str)
 | 
						|
	char *str;
 | 
						|
{
 | 
						|
	if (t_flag)
 | 
						|
		return;
 | 
						|
	if (v_flag) {
 | 
						|
		prs("rm ");
 | 
						|
		prs(str);
 | 
						|
		prs("\n");
 | 
						|
	}
 | 
						|
	if (noexec)
 | 
						|
		return;
 | 
						|
	unlink(str);
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
alloc(u)
 | 
						|
	unsigned u;
 | 
						|
{
 | 
						|
	register char *p = malloc(u);
 | 
						|
 | 
						|
	if (p == 0) panic("no space\n");
 | 
						|
	return p;
 | 
						|
}
 | 
						|
 | 
						|
append(al, arg)
 | 
						|
	struct arglist *al;
 | 
						|
	char *arg;
 | 
						|
{
 | 
						|
	char *a = alloc((unsigned) (strlen(arg) + 1));
 | 
						|
 | 
						|
	strcpy(a, arg);
 | 
						|
	if (al->al_argc >= MAXARGC)
 | 
						|
		panic("argument list overflow\n");
 | 
						|
	al->al_argv[(al->al_argc)++] = a;
 | 
						|
}
 | 
						|
 | 
						|
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++;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
mkstr(dst, arg1, arg2, arg3)
 | 
						|
	char *dst, *arg1, *arg2, *arg3;
 | 
						|
{
 | 
						|
	register char *p;
 | 
						|
	register char *q = dst;
 | 
						|
 | 
						|
	p = arg1;
 | 
						|
	while (*q++ = *p++);
 | 
						|
	q--;
 | 
						|
	p = arg2;
 | 
						|
	while (*q++ = *p++);
 | 
						|
	q--;
 | 
						|
	p = arg3;
 | 
						|
	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--;
 | 
						|
	while (*p1 != '.' && p1 > p2) p1--;
 | 
						|
	if (*p1 == '.') {
 | 
						|
		*p1 = '\0';
 | 
						|
		while (*dst++ = *p2++);
 | 
						|
		*p1 = '.';
 | 
						|
	}
 | 
						|
	else
 | 
						|
		while (*dst++ = *p2++);
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
extension(fln)
 | 
						|
	char *fln;
 | 
						|
{
 | 
						|
	register char *fn = fln;
 | 
						|
 | 
						|
	while (*fn) fn++;
 | 
						|
	while (fn > fln && *fn != '.') fn--;
 | 
						|
	if (fn != fln) return fn+1;
 | 
						|
	return (char *)0;
 | 
						|
}
 | 
						|
 | 
						|
runvec(vec, pass, in, out)
 | 
						|
	struct arglist *vec;
 | 
						|
	struct passinfo *pass;
 | 
						|
	char *in, *out;
 | 
						|
{
 | 
						|
	int pid, status;
 | 
						|
	int shifted = 0;
 | 
						|
 | 
						|
	if (
 | 
						|
		strncmp(vec->al_argv[1], "/usr/", 5) == 0
 | 
						|
		&&
 | 
						|
		access(vec->al_argv[1] + 4, 1) == 0
 | 
						|
	) {
 | 
						|
		vec->al_argv[1] += 4;
 | 
						|
		shifted = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (v_flag) {
 | 
						|
		pr_vec(vec);
 | 
						|
		if (pass->p_flags & STDIN) {
 | 
						|
			prs(" <");
 | 
						|
			prs(in);
 | 
						|
		}
 | 
						|
		if (pass->p_flags & STDOUT && !E_flag) {
 | 
						|
			prs(" >");
 | 
						|
			prs(out);
 | 
						|
		}
 | 
						|
		prs("\n");
 | 
						|
	}
 | 
						|
	if (noexec) {
 | 
						|
		if (shifted) vec->al_argv[1] -= 4;
 | 
						|
		clean(vec);
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
	if ((pid = fork()) == 0) {	/* start up the process */
 | 
						|
		if (pass->p_flags & STDIN && strcmp(in, "-") != 0) {
 | 
						|
			/* redirect standard input */
 | 
						|
			close(0);
 | 
						|
			if (open(in, 0) != 0)
 | 
						|
				panic("cannot open input file\n");
 | 
						|
		}
 | 
						|
		if (pass->p_flags & STDOUT && !E_flag) {
 | 
						|
			/* redirect standard output */
 | 
						|
			close(1);
 | 
						|
			if (creat(out, 0666) != 1)
 | 
						|
				panic("cannot create output file\n");
 | 
						|
		}
 | 
						|
		ex_vec(vec);
 | 
						|
	}
 | 
						|
	if (pid == -1)
 | 
						|
		panic("no more processes\n");
 | 
						|
	kids = pid;
 | 
						|
	wait(&status);
 | 
						|
	if (status) switch(status & 0177) {
 | 
						|
	case SIGHUP:
 | 
						|
	case SIGINT:
 | 
						|
	case SIGQUIT:
 | 
						|
	case SIGTERM:
 | 
						|
	case 0:
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		if (E_flag && (status & 0177) == SIGPIPE) break;
 | 
						|
		prs(vec->al_argv[1]);
 | 
						|
		prs(" died with signal ");
 | 
						|
		prnum(status & 0177);
 | 
						|
		prs("\n");
 | 
						|
	}
 | 
						|
	if (shifted) vec->al_argv[1] -= 4;
 | 
						|
	clean(vec);
 | 
						|
	kids = -1;
 | 
						|
	return status ? ((RET_CODE = 1), 0) : 1;
 | 
						|
}
 | 
						|
 | 
						|
prnum(x)
 | 
						|
	register unsigned x;
 | 
						|
{
 | 
						|
	static char numbuf[8];			/* though it prints at most 3 characters */
 | 
						|
	register char *cp = numbuf + sizeof(numbuf) - 1;
 | 
						|
 | 
						|
	*cp = '\0';
 | 
						|
	while (x >= 10) {
 | 
						|
		*--cp = (x % 10) + '0';
 | 
						|
		x /= 10;
 | 
						|
	}
 | 
						|
	*--cp = x + '0';
 | 
						|
	prs(cp);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
prs(str)
 | 
						|
	char *str;
 | 
						|
{
 | 
						|
	if (str && *str)
 | 
						|
		write(2, str, strlen(str));
 | 
						|
}
 | 
						|
 | 
						|
panic(str)
 | 
						|
	char *str;
 | 
						|
{
 | 
						|
	prs(str);
 | 
						|
	trapcc(SIGINT);
 | 
						|
}
 | 
						|
 | 
						|
pr_vec(vec)
 | 
						|
	register struct arglist *vec;
 | 
						|
{
 | 
						|
	register char **ap = &vec->al_argv[1];
 | 
						|
	
 | 
						|
	vec->al_argv[vec->al_argc] = 0;
 | 
						|
	prs(*ap);
 | 
						|
	while (*++ap) {
 | 
						|
		prs(" ");
 | 
						|
		if (strlen(*ap))
 | 
						|
			prs(*ap);
 | 
						|
		else
 | 
						|
			prs("(empty)");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
ex_vec(vec)
 | 
						|
	register struct arglist *vec;
 | 
						|
{
 | 
						|
	extern int errno;
 | 
						|
 | 
						|
	vec->al_argv[vec->al_argc] = 0;
 | 
						|
	execv(vec->al_argv[1], &(vec->al_argv[1]));
 | 
						|
	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. */
 | 
						|
		prs("Cannot execute ");
 | 
						|
		prs(vec->al_argv[1]);
 | 
						|
		prs(". Not enough memory.\n");
 | 
						|
		prs("Reduce the memory use of your system and try again\n");
 | 
						|
	} else {
 | 
						|
		prs(vec->al_argv[1]);
 | 
						|
		prs(" is not executable\n");
 | 
						|
	}
 | 
						|
	exit(1);
 | 
						|
}
 | 
						|
 | 
						|
mktempname(nm)
 | 
						|
	register char *nm;
 | 
						|
{
 | 
						|
	register int i;
 | 
						|
	register int pid = getpid();
 | 
						|
 | 
						|
	mkstr(nm, tmpdir, "/", compbase->c_callname);
 | 
						|
	while (*nm) nm++;
 | 
						|
 | 
						|
	for (i = 9; i > 3; i--) {
 | 
						|
		*nm++ = (pid % 10) + '0';
 | 
						|
		pid /= 10;
 | 
						|
	}
 | 
						|
	*nm++ = '.';
 | 
						|
	*nm++ = '\0'; /* null termination */
 | 
						|
}
 | 
						|
 | 
						|
mkbase()
 | 
						|
{
 | 
						|
	register struct compile *p = passes;
 | 
						|
	USTRING callname;
 | 
						|
	register int len;
 | 
						|
 | 
						|
	basename(ProgCall, callname);
 | 
						|
	len = strlen(callname);
 | 
						|
	while (p->c_suffix) {
 | 
						|
		if (strcmp(p->c_callname, callname+len-strlen(p->c_callname)) == 0) {
 | 
						|
			compbase = p;
 | 
						|
			mkloader();
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		p++;
 | 
						|
	}
 | 
						|
	/* we should not get here */
 | 
						|
	panic("internal error\n");
 | 
						|
}
 | 
						|
 | 
						|
mkloader()
 | 
						|
{
 | 
						|
	register struct passinfo *p = passinfo;
 | 
						|
	register struct pass *pass;
 | 
						|
 | 
						|
	while (!(p->p_flags & LOADER)) p++;
 | 
						|
	loaderinfo = p;
 | 
						|
	pass = &(compbase->c_passes[0]);
 | 
						|
	while (strcmp(pass->pp_name, p->p_name)) pass++;
 | 
						|
	loader = pass;
 | 
						|
}
 | 
						|
 | 
						|
needsprep(name)
 | 
						|
	char *name;
 | 
						|
{
 | 
						|
	int file;
 | 
						|
	char fc;
 | 
						|
 | 
						|
	file = open(name,0);
 | 
						|
	if (file <0) return 0;
 | 
						|
	if (read(file, &fc, 1) != 1) fc = 0;
 | 
						|
	close(file);
 | 
						|
	return fc == '#';
 | 
						|
}
 | 
						|
 | 
						|
cfile(name)
 | 
						|
	char *name;
 | 
						|
{
 | 
						|
	while (*name != '\0' && *name != '.')
 | 
						|
		name++;
 | 
						|
 | 
						|
	if (*name == '\0') return 0;
 | 
						|
	return (*++name == 'c' && *++name == '\0');
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
apply(pinf, cp, name, passindex, noremove, first, resultname)
 | 
						|
	register struct passinfo *pinf;
 | 
						|
	register struct compile *cp;
 | 
						|
	char *name, *resultname;
 | 
						|
{
 | 
						|
	/*	Apply a pass, indicated by "pinf", with args in 
 | 
						|
		cp->c_passes[passindex], to name "name", leaving the result
 | 
						|
		in a file with name "resultname", concatenated with result
 | 
						|
		suffix.
 | 
						|
		When neccessary, the preprocessor is run first.
 | 
						|
		If "noremove" is NOT set, the file "name" is removed.
 | 
						|
	*/
 | 
						|
 | 
						|
	struct arglist *call = &CALLVEC;
 | 
						|
	struct pass *pass = &(cp->c_passes[passindex]);
 | 
						|
	char *outname;
 | 
						|
 | 
						|
	if ( /* this pass is the first pass */
 | 
						|
	     first
 | 
						|
	   &&
 | 
						|
	     ( /* preprocessor always needed */
 | 
						|
	       (pinf->p_flags & PREPALWAYS)
 | 
						|
	     ||/* or only when "needsprep" says so */
 | 
						|
	       ( (pinf->p_flags & PREPCOND) && needsprep(name))
 | 
						|
	     )
 | 
						|
	   ) {
 | 
						|
		mkstr(newfil, tmpname, passinfo[0].p_to, "");
 | 
						|
		mkvec(call, name, newfil,
 | 
						|
			(pinf->p_flags & PREPNOLN) ? &prepnoln : &preprocessor,
 | 
						|
			&passinfo[0]);
 | 
						|
		if (! runvec(call, &passinfo[0], name, newfil)) {
 | 
						|
			cleanup(newfil);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		/* A .c file must always be mishandled by irrel. */
 | 
						|
		if (cfile(name)) {
 | 
						|
			/* newfil is OK */
 | 
						|
			mkvec(call, newfil, newfil, &irrel, &passinfo[1]);
 | 
						|
			if (! runvec(call, &passinfo[1], newfil, newfil)) {
 | 
						|
				cleanup(newfil);
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		strcpy(curfil, newfil);
 | 
						|
		newfil[0] = '\0';
 | 
						|
		name = curfil;
 | 
						|
		noremove = 0;
 | 
						|
	}
 | 
						|
	if (pinf->p_to) outname = mkstr(newfil, resultname, pinf->p_to, "");
 | 
						|
	else outname = o_FILE;
 | 
						|
	mkvec(call, name, outname, pass, pinf);
 | 
						|
	if (! runvec(call, pinf, name, outname)) {
 | 
						|
		if (! (pinf->p_flags & NOCLEAN)) cleanup(outname);
 | 
						|
		if (! noremove) cleanup(name);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	if (! noremove) cleanup(name);
 | 
						|
	strcpy(curfil, newfil);
 | 
						|
	newfil[0] = '\0';
 | 
						|
	return curfil;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
applicable(pinf, suffix)
 | 
						|
	struct passinfo *pinf;
 | 
						|
	char *suffix;
 | 
						|
{
 | 
						|
	/*	Return one if the pass indicated by "pinfo" is applicable to
 | 
						|
		a file with suffix "suffix".
 | 
						|
	*/
 | 
						|
	register char *sfx = pinf->p_from;
 | 
						|
	int l;
 | 
						|
 | 
						|
	if (! suffix) return 0;
 | 
						|
	l = strlen(suffix);
 | 
						|
	while (*sfx) {
 | 
						|
		register char *p = sfx;
 | 
						|
 | 
						|
		while (*p && *p != ',') p++;
 | 
						|
		if (l == p - sfx && strncmp(sfx, suffix, l) == 0) {
 | 
						|
			return 1;
 | 
						|
		}
 | 
						|
		if (*p == ',') sfx = p+1;
 | 
						|
		else sfx = p;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
		
 | 
						|
char *
 | 
						|
process(name, noremove)
 | 
						|
	char *name;
 | 
						|
{
 | 
						|
	register struct compile *cp = passes;
 | 
						|
	char *suffix = extension(name);
 | 
						|
	USTRING base;
 | 
						|
	register struct pass *pass;
 | 
						|
	register struct passinfo *pinf;
 | 
						|
 | 
						|
	if (E_flag) {
 | 
						|
		/* -E uses the cpp pass. */
 | 
						|
		suffix = "CPP";
 | 
						|
	}
 | 
						|
 | 
						|
	if (! suffix) return name;
 | 
						|
 | 
						|
	basename(name, base);
 | 
						|
 | 
						|
	while (cp->c_suffix) {
 | 
						|
		if ((cp->c_flags & DEFLANG) &&
 | 
						|
		    strcmp(cp->c_suffix, suffix) == 0)
 | 
						|
			break;
 | 
						|
		cp++;
 | 
						|
	}
 | 
						|
	if (! cp->c_suffix) cp = compbase;
 | 
						|
	pass = cp->c_passes;
 | 
						|
	while (pass->pp_name) {
 | 
						|
		int first = 1;
 | 
						|
 | 
						|
		for (pinf=passinfo; strcmp(pass->pp_name,pinf->p_name);pinf++)
 | 
						|
			;
 | 
						|
		if (! (pinf->p_flags & LOADER) && applicable(pinf, suffix)) {
 | 
						|
			int cont = ! stopsuffix || ! pinf->p_to ||
 | 
						|
					strcmp(stopsuffix, pinf->p_to) != 0;
 | 
						|
			name = apply(pinf,
 | 
						|
				     cp,
 | 
						|
				     name,
 | 
						|
				     (int) (pass - cp->c_passes),
 | 
						|
				     noremove,
 | 
						|
				     first,
 | 
						|
				     applicable(loaderinfo, pinf->p_to) ||
 | 
						|
				      !cont ?
 | 
						|
					strcat(base, ".") :
 | 
						|
					tmpname);
 | 
						|
			first = noremove = 0;
 | 
						|
			suffix = pinf->p_to;
 | 
						|
			if (!cont || !name) break;
 | 
						|
		}
 | 
						|
		pass++;
 | 
						|
	}
 | 
						|
	if (!noremove && name)
 | 
						|
		append(&GEN_LDFILES, name);
 | 
						|
	return name;
 | 
						|
}
 | 
						|
 | 
						|
mkvec(call, in, out, pass, pinf)
 | 
						|
	struct arglist *call;
 | 
						|
	char *in, *out;
 | 
						|
	struct pass *pass;
 | 
						|
	register struct passinfo *pinf;
 | 
						|
{
 | 
						|
	register int i;
 | 
						|
 | 
						|
	init(call);
 | 
						|
	append(call, pinf->p_path);
 | 
						|
	scanflags(call, pinf);
 | 
						|
	if (pass) for (i = 0; i < MAXHEAD; i++)
 | 
						|
		if (pass->pp_head[i])
 | 
						|
			append(call, pass->pp_head[i]);
 | 
						|
		else	break;
 | 
						|
	if (pinf->p_flags & INPUT && strcmp(in, "-") != 0)
 | 
						|
		append(call, in);
 | 
						|
	if (pinf->p_flags & OUTPUT)
 | 
						|
		append(call, out);
 | 
						|
	if (pinf->p_flags & O_OUTPUT) {
 | 
						|
		append(call, "-o");
 | 
						|
		append(call, out);
 | 
						|
	}
 | 
						|
	if (pass) for (i = 0; i < MAXTAIL; i++)
 | 
						|
		if (pass->pp_tail[i])
 | 
						|
			append(call, pass->pp_tail[i]);
 | 
						|
		else	break;
 | 
						|
}
 | 
						|
 | 
						|
callld(in, out, pass, pinf)
 | 
						|
	struct arglist *in;
 | 
						|
	char *out;
 | 
						|
	struct pass *pass;
 | 
						|
	register struct passinfo *pinf;
 | 
						|
{
 | 
						|
	struct arglist *call = &CALLVEC;
 | 
						|
	register int i;
 | 
						|
 | 
						|
	init(call);
 | 
						|
	append(call, pinf->p_path);
 | 
						|
	scanflags(call, pinf);
 | 
						|
	append(call, "-o");
 | 
						|
	append(call, out);
 | 
						|
	for (i = 0; i < MAXHEAD; i++)
 | 
						|
		if (pass->pp_head[i])
 | 
						|
			append(call, pass->pp_head[i]);
 | 
						|
		else	break;
 | 
						|
	if (pinf->p_flags & INPUT)
 | 
						|
		concat(call, in);
 | 
						|
	if (pinf->p_flags & OUTPUT)
 | 
						|
		append(call, out);
 | 
						|
	for (i = 0; i < MAXTAIL; i++) {
 | 
						|
		if (pass->pp_tail[i]) {
 | 
						|
			if (pass->pp_tail[i][0] == '-' &&
 | 
						|
			    pass->pp_tail[i][1] == 'l') {
 | 
						|
				append(call, library(&(pass->pp_tail[i][2])));
 | 
						|
			}
 | 
						|
			else if (*(pass->pp_tail[i]) != '*')
 | 
						|
				append(call, pass->pp_tail[i]);
 | 
						|
			else if (fp_lib)
 | 
						|
				append(call, library("fp"));
 | 
						|
		} else	break;
 | 
						|
	}
 | 
						|
	if (! runvec(call, pinf, (char *) 0, out)) {
 | 
						|
		cleanup(out);
 | 
						|
		RET_CODE = 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
clean(c)
 | 
						|
	register struct arglist *c;
 | 
						|
{
 | 
						|
	register int i;
 | 
						|
 | 
						|
	for (i = 1; i < c->al_argc; i++) {
 | 
						|
		free(c->al_argv[i]);
 | 
						|
		c->al_argv[i] = 0;
 | 
						|
	}
 | 
						|
	c->al_argc = 0;
 | 
						|
}
 | 
						|
 | 
						|
scanflags(call, pinf)
 | 
						|
	struct arglist *call;
 | 
						|
	struct passinfo *pinf;
 | 
						|
{
 | 
						|
	/*	Find out which flags from FLAGS must be passed to pass "pinf",
 | 
						|
		and how. 
 | 
						|
		Append them to "call"
 | 
						|
	*/
 | 
						|
	register int i;
 | 
						|
	USTRING flg;
 | 
						|
 | 
						|
	for (i = 0; i < FLAGS.al_argc; i++) {
 | 
						|
		register char *q = pinf->p_acceptflags;
 | 
						|
 | 
						|
		while (*q)  {
 | 
						|
			register char *p = FLAGS.al_argv[i] + 1;
 | 
						|
 | 
						|
			while (*q && *q == *p) {
 | 
						|
				q++; p++;
 | 
						|
			}
 | 
						|
			if (*q == ',' || !*q) {
 | 
						|
				if (! *p) {
 | 
						|
					/* append literally */
 | 
						|
					append(call, FLAGS.al_argv[i]);
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			if (*q == '*') {
 | 
						|
				register char *s = flg;
 | 
						|
 | 
						|
				if (*++q != '=') {
 | 
						|
					/* append literally */
 | 
						|
					append(call, FLAGS.al_argv[i]);
 | 
						|
					break;
 | 
						|
				}
 | 
						|
				*s++ = '-';
 | 
						|
				if (*q) q++;	/* skip ',' */
 | 
						|
				while (*q && *q != ',' && *q != '*') {
 | 
						|
					/* copy replacement flag */
 | 
						|
					*s++ = *q++;
 | 
						|
				}
 | 
						|
				if (*q == '*') {
 | 
						|
					/* copy rest */
 | 
						|
					while (*p) *s++ = *p++;
 | 
						|
				}
 | 
						|
				*s = 0;
 | 
						|
				append(call, flg);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			if (*q == '=') {
 | 
						|
				/* copy replacement */
 | 
						|
				register char *s = flg;
 | 
						|
 | 
						|
				*s++ = '-';
 | 
						|
				q++;
 | 
						|
				while (*q && *q != ',') *s++ = *q++;
 | 
						|
				*s = 0;
 | 
						|
				append(call, flg);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			while (*q && *q++ != ',')
 | 
						|
				;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |