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++ != ',')
 | |
| 				;
 | |
| 		}
 | |
| 	}
 | |
| }
 | 
