From: broman@nosc.mil (Vincent P. Broman)
Subject: c386 compiler, patched for i80387, bootstrapped by bcc
Reply-To: broman@nosc.mil
Organization: Naval Ocean Systems Center, San Diego
Distribution: comp
Date: Tue, 17 Nov 1992 16:00:26 GMT

I've patched the c386 v4.1 Minix C compiler for 387 floating point operation,
targeted to a backend of Bruce Evans' assembler and loader, instead
of gas and gld, c386 being bootstrapped using bcc.  This combination was
almost supported out of the box, but was evidently not tried by the authors.

The widely distributed version of Bruce Evans' assembler does not
support 387 opcodes, but a newer version found at
gipsy.vmars.tuwien.ac.at:/pub/minix/bruce/as.zip
does.  Unfortunately, it no longer recognizes '|' as a comment character,
implementing a logical or instead.  While there, get the new ld, too;
you need it to get a source file as and ld share.  Don't throw away
the old assembler, because the bcc FP emulation routines have names
that collide with some 387 opcodes.  Sigh.

Correct operation of this kind of 387 code in a multitasking environment
requires patching crtso.s to perform an finit and patching the
kernel to save the 387 state in the process table on context switches.
I haven't perfected that yet.  The compiler will generate calls to
FP software emulation routines, but I haven't ported the emulation
assembler code from gas to bas, yet.  I might never.

In the following shar archive:

  src.patch contains the changes required for targeting bas/bld, mostly
  in out386_bas.c .  The Makefile gets munged, a NO_FLOAT_PRINTF
  option is defined in config.h, so that if your printf cannot emit a .double
  out386_bas will emit 1 or 2 .longs instead, address operands of FP ops
  get length specifiers, and two typos were corrected, one critical.

  bcc.patch contains changes needed for bootstrapping with bcc,
  essentially just replacing FP literal constants with cast integer literals.
  bccfp is required to support this.

  alloca.s is a bas transcription of the distributed gas routine.

  c.c is a cc compiler driver, patched from that posted by CvW a while ago.
  It is table driven and simultaneously supports several compilers and
  compiler parts.  E.g. you may want a different cpp from my choice.
  The c386 and c387 it knows about are both really c386, just with and
  without the NOFLOAT option specified.  It's slick.

Vincent Broman,  code 572 bayside,                                  =   o     
Naval Command Control and Ocean Surveillance Center, RDT&E Div.   =  _ /- _   
San Diego, CA  92152-5000,  USA                                  =  (_)> (_)  
Internet Email: broman@nosc.mil    Fax: +1 619 553 1635   Phone: +1 619 553 1641
-------------------------------------------------------------------------------

: This is a shar archive.  Extract with sh, not csh.
: The rest of this file will extract:
: src.patch bcc.patch alloca.s c.c
echo x src.patch
sed 's/^X//' > src.patch << 'xEOF'
Xdiff -c Makefile.orig Makefile
X*** Makefile.orig	Thu Oct  8 21:20:02 1992
X--- Makefile	Sat Oct 10 22:07:46 1992
X***************
X*** 4,12 ****
X  #		according to the DEFINES set in config.h
X  
X  # Select either GCC or c68 or bcc to compile this  (not ACK!!)
X! CC= cc68
X! CFLAGS= -O -Qwarn=5
X! LDFLAGS = -s -m250000
X  
X  HDR = 	c.h cglbdec.h expr.h gen.h version.h config.h
X  
X--- 4,13 ----
X  #		according to the DEFINES set in config.h
X  
X  # Select either GCC or c68 or bcc to compile this  (not ACK!!)
X! CC= bcc -3
X! CFLAGS= 
X! LDFLAGS = -i
X! LIB=
X  
X  HDR = 	c.h cglbdec.h expr.h gen.h version.h config.h
X  
X***************
X*** 15,20 ****
X--- 16,23 ----
X  	stmt.c cmain.c genstmt.c memmgt.c msgout.c \
X  	symbol.c decl.c getsym.c genicode.c outgen.c
X  #
X+ SRCLIB = vfprintf.c
X+ #
X  SRC68K =config.c68 gen68k.c reg68k.c peep68k.c genffp.c genieee.c \
X  	out68k_ack.c out68k_cpm.c out68k_gas.c
X  #
X***************
X*** 26,31 ****
X--- 29,36 ----
X  	stmt.o cmain.o genstmt.o memmgt.o msgout.o \
X  	symbol.o decl.o getsym.o genicode.o outgen.o
X  #
X+ OBJLIB = vfprintf.o
X+ #
X  OBJ68K= gen68k.o reg68k.o peep68k.o genffp.o genieee.o \
X  	out68k_ack.o out68k_cpm.o out68k_gas.o
X  #
X***************
X*** 39,56 ****
X  	@echo "	make c68"
X  	@echo "	make c386"
X  
X! c68:	config_check_c68 $(OBJ) $(OBJ68K) $(OBJ386)
X! 	$(CC) $(LDFLAGS) -o c68 $(OBJ) \
X! 			$(OBJ68K) \
X! 			$(OBJ386)
X  
X  config_check_c68:
X  	./copy-if-change config.c68 config.h
X  
X! c386:	config_check_c386 $(OBJ) $(OBJ68K) $(OBJ386)
X! 	$(CC) $(LDFLAGS) -o c386 $(OBJ) \
X! 			$(OBJ68K) \
X! 			$(OBJ386)
X  
X  config_check_c386:
X  	./copy-if-change config.c386 config.h
X--- 44,62 ----
X  	@echo "	make c68"
X  	@echo "	make c386"
X  
X! c68:	config_check_c68 $(OBJ) $(OBJ68K) $(OBJ386) $(OBJLIB)
X! 	$(CC) $(LDFLAGS) -o c68 $(OBJ) \
X! 			$(OBJ68K) \
X! 			$(OBJ386) $(OBJLIB)
X  
X  config_check_c68:
X  	./copy-if-change config.c68 config.h
X  
X! c386:	config_check_c386 $(OBJ) $(OBJ68K) $(OBJ386) $(OBJLIB)
X! 	$(CC) $(LDFLAGS) -o c386 $(OBJ) \
X! 			$(OBJ68K) \
X! 			$(OBJ386) $(OBJLIB) $(LIB)
X! 	chmem =200000 c386
X  
X  config_check_c386:
X  	./copy-if-change config.c386 config.h
X***************
X*** 68,70 ****
X--- 74,79 ----
X  $(OBJ):		$(HDR)
X  $(OBJ68K):	$(HDR)
X  $(OBJ386):	$(HDR)
X+ 
X+ $(OBJLIB): $(HDR)
X+ 	$(CC) $(CFLAGS) -c -DINTEL_32BITS `basename $@ .o`.c
Xdiff -c config.c386.or config.c386
X*** config.c386.or	Thu Oct  8 21:20:11 1992
X--- config.c386	Sat Oct 10 07:55:33 1992
X***************
X*** 20,25 ****
X--- 20,26 ----
X  /* #define HAS_NLS 1	/* system supports message catalogues */
X  #define HAS_STDARG 1	/* system supports stdarg.h */
X  /* #define NOFLOAT 1 	/* Do not generate floating point support */
X+ #define NO_FLOAT_PRINTF	/* no FP printf for emitting float constants */
X  /* #define NODOUBLE 1	/* Treat 'float' and 'double' as same (MFFP version) */
X  /*
X   *	These options tend not to be changed except when developing
X***************
X*** 50,55 ****
X--- 51,63 ----
X  #define INTEL_386 1	/* This is an Intel 386 compiler */
X  #define SEPARATE_I_D 1	/* Separate I and D spaces */
X  
X+ /*
X+  * if FUNCS_USE_387 is defined, extra library calls are generated if the
X+  * nofpu option is in effect that allows to use code generated by
X+  * this compiler to be linked with functions that return values
X+  * on the 387 stack.
X+  * there is no provision for returns on the ESP stack.
X+  */
X  #define FUNCS_USE_387 1	/* ... very special option */
X  
X  /* #define TARGET_GAS	/* Assembler Syntax is for GAS/Sun386i */
X***************
X*** 144,156 ****
X  #define PROGNAME   "c386"
X  #define LIST_NAME  "c386.list"
X  #define ICODE_NAME "c386.icode"
X- /*
X-  * if FUNCS_USE_387 is defined, extra library calls are generated if the
X-  * nofpu option is in effect that allows to use code generated by
X-  * this compiler to be linked with functions that return values
X-  * on the 387 stack
X-  */
X- #define FUNCS_USE_387
X  #endif
X  
X  #ifndef CPU_DEFINED
X--- 152,157 ----
Xdiff -c msgout.c.orig msgout.c
X*** msgout.c.orig	Thu Oct  8 21:21:40 1992
X--- msgout.c	Fri Oct  9 21:29:39 1992
X***************
X*** 49,55 ****
X  # define VA_START(a,s)	va_start(a,s)
X  # ifdef __STDC__
X  #  define P1(p1, p2)	(p1 p2, ...)
X! #  define P2(p1, p2, p3, p4)	(p1 p2, p3, p4, ...)
X  # else
X  #  define P1(p1, p2)	(p2) p1 p2;
X  #  define P2(p1, p2, p3, p4)	(p2, p4) p1 p2; p3 p4;
X--- 49,55 ----
X  # define VA_START(a,s)	va_start(a,s)
X  # ifdef __STDC__
X  #  define P1(p1, p2)	(p1 p2, ...)
X! #  define P2(p1, p2, p3, p4)	(p1 p2, p3 p4, ...)
X  # else
X  #  define P1(p1, p2)	(p2) p1 p2;
X  #  define P2(p1, p2, p3, p4)	(p2, p4) p1 p2; p3 p4;
Xdiff -c out386_bas.ori out386_bas.c
X*** out386_bas.ori	Thu Oct  8 21:18:54 1992
X--- out386_bas.c	Sat Oct 10 06:03:46 1992
X***************
X*** 64,69 ****
X--- 64,70 ----
X  
X  #define	BI	1
X  #define SP	2
X+ #define FP	4
X  
X  static struct oplst {
X      char           *s;
X***************
X*** 71,76 ****
X--- 72,78 ----
X      int		    sa;	/* special addressing modes:
X      			 *	BI	immediate is bracketed,
X      			 *	SP	size prefix needed.
X+ 			 *	FP	387 op
X      			 */
X  }               opl[] =
X  
X***************
X*** 119,139 ****
X  "rep",		op_rep,		SP,
X  "movs",		op_smov,	BI | SP,
X  "test",		op_test,	BI | SP,
X! "fadd",		op_fadd,	BI | SP,
X! "fsub",		op_fsub,	BI | SP,
X! "fsubr",	op_fsubr,	BI | SP,
X! "fmul",		op_fmul,	BI | SP,
X! "fdiv",		op_fdiv,	BI | SP,
X! "fdivr",	op_fdivr,	BI | SP,
X! "fchs",		op_fchs,	BI | SP,
X! "fld",		op_fld,		BI | SP,
X! "fild",		op_fild,	BI | SP,
X! "fst",		op_fst,		BI | SP,
X! "fstp",		op_fstp,	BI | SP,
X! "fstp %st(0)",	op_fpop,	BI | SP,
X! "fcompp",	op_fcompp,	BI | SP,
X! "ftst",		op_ftst,	BI | SP,
X! "fnstsw",	op_fnstsw,	BI | SP,
X  "sahf",		op_sahf,	BI | SP,
X  0,		0,		0
X  };
X--- 121,143 ----
X  "rep",		op_rep,		SP,
X  "movs",		op_smov,	BI | SP,
X  "test",		op_test,	BI | SP,
X! #ifndef NOFLOAT
X! "fadd",		op_fadd,	BI | SP | FP,
X! "fsub",		op_fsub,	BI | SP | FP,
X! "fsubr",	op_fsubr,	BI | SP | FP,
X! "fmul",		op_fmul,	BI | SP | FP,
X! "fdiv",		op_fdiv,	BI | SP | FP,
X! "fdivr",	op_fdivr,	BI | SP | FP,
X! "fchs",		op_fchs,	BI | SP | FP,
X! "fld",		op_fld,		BI | SP | FP,
X! "fild",		op_fild,	BI | SP | FP,
X! "fst",		op_fst,		BI | SP | FP,
X! "fstp",		op_fstp,	BI | SP | FP,
X! "fstp st(0)",	op_fpop,	BI | SP | FP,
X! "fcompp",	op_fcompp,	BI | SP | FP,
X! "ftst",		op_ftst,	BI | SP | FP,
X! "fnstsw",	op_fnstsw,	BI | SP | FP,
X! #endif
X  "sahf",		op_sahf,	BI | SP,
X  0,		0,		0
X  };
X***************
X*** 257,262 ****
X--- 261,276 ----
X  	    break;
X  	}
X      }	
X+ #ifndef NOFLOAT
X+     if (sa & FP) {
X+ 	/* assume that st(n) never appears explicitly as an operand here */
X+ 	if (len >= 8)
X+ 	    oprintf("qword ptr ");
X+ 	else if (len >= 4)
X+ 	    oprintf("dword ptr ");
X+ 	/* else fnstsw should not need a length? */
X+     }
X+ #endif
X      switch (ap->mode) {
X        case am_immed:
X  	oprintf("#");
X***************
X*** 290,296 ****
X          oprintf("[%s+%s]",regname[ap->preg],regname[ap->sreg]);
X          break;
X        default:
X! 	fatal("out386_bas/putamdoe","illegal address mode %d",ap->mode);
X  	break;
X      }
X  }
X--- 304,310 ----
X          oprintf("[%s+%s]",regname[ap->preg],regname[ap->sreg]);
X          break;
X        default:
X! 	fatal("out386_bas/putamode","illegal address mode %d",ap->mode);
X  	break;
X      }
X  }
X***************
X*** 414,427 ****
X  genfloat(val)
X      double          val;
X  {
X!     oprintf("\t.float %20.15e\n",val);
X  }
X  
X  void
X  gendouble(val)
X      double          val;
X  {
X!     oprintf("\t.double %20.15e\n",val);
X  }
X  #endif
X  
X--- 428,453 ----
X  genfloat(val)
X      double          val;
X  {
X! #ifndef NO_FLOAT_PRINTF
X!     oprintf("\t.float %14.7e\n",val);
X! #else
X!     float fval;
X!     fval = (float) val;
X!     /* this type transfer won't cross compile, of course. */
X!     oprintf("\t.long %d\n", ((long *)&fval)[0]);
X! #endif
X  }
X  
X  void
X  gendouble(val)
X      double          val;
X  {
X! #ifndef NO_FLOAT_PRINTF
X!     oprintf("\t.double %23.16e\n",val);
X! #else
X!     /* this type transfer won't cross compile, of course. */
X!     oprintf("\t.long %d, %d\n", ((long *)&val)[0], ((long *)&val)[1]);
X! #endif
X  }
X  #endif
X  
xEOF
echo x bcc.patch
sed 's/^X//' > bcc.patch << 'xEOF'
Xdiff -c expr.c expr.c.bcc
X*** expr.c	Thu Oct  8 21:20:55 1992
X--- expr.c.bcc	Fri Oct  9 21:59:04 1992
X***************
X*** 673,679 ****
X  		} else if (floating(tp)) {
X  		    ep2 = mk_node(en_fcon, NIL_ENODE, NIL_ENODE);
X  #ifndef NOFLOAT
X! 		    ep2->v.f = 1.0;
X  #endif
X  		    if (tp->type == bt_float) {
X  			ep2->etype = tp_float.type;
X--- 673,679 ----
X  		} else if (floating(tp)) {
X  		    ep2 = mk_node(en_fcon, NIL_ENODE, NIL_ENODE);
X  #ifndef NOFLOAT
X! 		    ep2->v.f = ((double) 1);
X  #endif
X  		    if (tp->type == bt_float) {
X  			ep2->etype = tp_float.type;
X***************
X*** 890,896 ****
X  		    if (floating(tp)) {
X  			ep2 = mk_node(en_fcon, NIL_ENODE, NIL_ENODE);
X  #ifndef NOFLOAT
X! 			ep2->v.f = 1.0;
X  #endif
X  			if (tp->type == bt_float) {
X  			    ep2->etype = tp_float.type;
X--- 890,896 ----
X  		    if (floating(tp)) {
X  			ep2 = mk_node(en_fcon, NIL_ENODE, NIL_ENODE);
X  #ifndef NOFLOAT
X! 			ep2->v.f = ((double) 1);
X  #endif
X  			if (tp->type == bt_float) {
X  			    ep2->etype = tp_float.type;
Xdiff -c getsym.c getsym.c.bcc
X*** getsym.c	Thu Oct  8 21:21:32 1992
X--- getsym.c.bcc	Sat Oct 10 07:30:57 1992
X***************
X*** 439,452 ****
X      register unsigned long i=0;
X      register int    j;
X  #ifndef NOFLOAT
X!     register double r = 0.0;
X  #endif
X  
X      while (isdigit(lastch)) {
X  	j = radix36(lastch);
X  	i = 10 * i + j;
X  #ifndef NOFLOAT
X! 	r = 10.0 * r + (double) j;
X  #endif
X  	getch();
X      }
X--- 439,452 ----
X      register unsigned long i=0;
X      register int    j;
X  #ifndef NOFLOAT
X!     register double r = ((double) 0);
X  #endif
X  
X      while (isdigit(lastch)) {
X  	j = radix36(lastch);
X  	i = 10 * i + j;
X  #ifndef NOFLOAT
X! 	r = ((double) 10) * r + (double) j;
X  #endif
X  	getch();
X      }
X***************
X*** 496,506 ****
X  {
X  #ifndef NOFLOAT
X      double          frmul;
X!     frmul = 10.0;
X      while (isdigit(lastch)) {
X  	rval += (double) radix36(lastch) / frmul;
X  	getch();
X! 	frmul *= 10.0;
X      }
X  #endif
X  }
X--- 496,506 ----
X  {
X  #ifndef NOFLOAT
X      double          frmul;
X!     frmul = ((double) 10);
X      while (isdigit(lastch)) {
X  	rval += (double) radix36(lastch) / frmul;
X  	getch();
X! 	frmul *= ((double) 10);
X      }
X  #endif
X  }
X***************
X*** 526,538 ****
X      switch (lastch) {
X      case '-':
X  	getch();
X! 	multiplier = 1/10.0;
X  	break;
X      case '+':
X  	getch();
X  	/* FALL THRU */
X      default:
X! 	multiplier = 10.0;
X  	break;
X      }
X      getdecimal();
X--- 526,538 ----
X      switch (lastch) {
X      case '-':
X  	getch();
X! 	multiplier = ((double) 1) / ((double) 10);
X  	break;
X      case '+':
X  	getch();
X  	/* FALL THRU */
X      default:
X! 	multiplier = ((double) 10);
X  	break;
X      }
X      getdecimal();
X***************
X*** 797,803 ****
X  	    getch();
X  	    if (isdigit(lastch)) {
X  #ifndef NOFLOAT
X! 		rval = 0.0;
X  #endif
X  		getfrac();
X  		lastst = rconst;
X--- 797,803 ----
X  	    getch();
X  	    if (isdigit(lastch)) {
X  #ifndef NOFLOAT
X! 		rval = ((double) 0);
X  #endif
X  		getfrac();
X  		lastst = rconst;
Xdiff -c optimize.c optimize.c.bcc
X*** optimize.c	Sat Jul 25 13:12:46 1992
X--- optimize.c.bcc	Fri Oct  9 22:01:16 1992
X***************
X*** 80,86 ****
X              epf = ep0->v.f * ep1->v.f;
X              break;
X            case en_div:
X! 	    if (ep1->v.f == 0.0) {
X  	        message(GWARN_DIVZERO);
X  	        ep->nodetype = en_div;
X  	    } else {
X--- 80,86 ----
X              epf = ep0->v.f * ep1->v.f;
X              break;
X            case en_div:
X! 	    if (ep1->v.f == ((double) 0)) {
X  	        message(GWARN_DIVZERO);
X  	        ep->nodetype = en_div;
X  	    } else {
xEOF
echo x alloca.s
sed 's/^X//' > alloca.s << 'xEOF'
X	.text
X	export alloca
X	export __builtin_alloca
Xalloca:
X__builtin_alloca:
X	pop	ecx
X	mov	eax,[esp]
X	add	eax,$3
X	and	eax,$-4
X	sub	esp,eax
X	mov	eax,esp
X	add	eax,$4
X	jmp	[ecx]
xEOF
echo x c.c
sed 's/^X//' > c.c << 'xEOF'
X/*
X * (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
X * See the copyright notice in the file "../Copyright".
X */
X
X/*	Driver for Minix compilers.
X	Written june 1987 by Ceriel J.H. Jacobs, partly derived from old
X	cc-driver, written by Erik Baalbergen.
X	This driver is mostly table-driven, the table being in the form of
X	some global initialized structures.
X*/
X
X/*
X        extensions added by Christoph van Wuellen (this work begun to
X        support my c68 68000 C-Compiler)
X        
X        - support of three alternate C compilers, selectable at runtime:
X	    - the default is: ACK compiling system with 16-bit ints
X	    - the -c68s option switches to c68 using 16-bit ints
X	    - the -c68l option switches to c68 using 32-bit ints
X	    - the -sozo option switches to the SOZOBON compiler with
X              16-bit ints. The postoptimizer is always applied.
X
X        - two features selectable at compile time:
X            - support of ACK floating point stuff (inclusion of a fpp pass)
X            - support of the new MINIX linker posted to comp.os.minix
X
X*/
X/*
X	extensions added by Vincent Broman 1992:
X	support driving bcc3, bcc0, c386 and c387.
X */
X	
X#include <errno.h>
X#include <signal.h>
X
X/*
X * For all program paths (so not the other files, like libraries) that
X * start with "/usr/" and are executable according to access(..., 1),
X * the leading "/usr" is stripped off.
X */
X
X#define SHELL		"/bin/sh"
X
X#define AS		"/usr/bin/as"
X#define CEM		"/usr/lib/cem"
X#define CG		"/usr/lib/cg"
X#define PP		"/usr/lib/cpp"
X#define CRT		"/usr/lib/crtso.o"
X#define CRT32           "/usr/lib/crtso32.o"
X#define CV		"/usr/lib/cv"
X#define PC		"/usr/lib/em_pc"
X#define END		"/usr/lib/end.o"
X#define END32           "/usr/lib/end32.o"
X#define LD		"/usr/lib/ld"
X#define LIBC		"/usr/lib/liback.a"
X#define LIBC68		"/usr/lib/libc68.a"
X#define LIBC6832        "/usr/lib/libc68_32.a"
X#define LIBSOZO		"/usr/lib/libsozo.a"
X#define LIBP		"/usr/lib/libp.a"
X#define OPT		"/usr/lib/opt"
X#define PRT		"/usr/lib/prtso.o"
X#define LIBPREFIX	"/usr/lib/lib"
X
X#define CCCP		"/local/bin/cccp"
X#define DECUSCPP	"/local/bin/cpp"
X#define C386		"/local/bin/c386"
X#define C387		"/local/bin/c387"
X#define SC		"/local/bin/sc"
X#define BAS		"/local/bin/as"
X#define BAS87		"/local/bin/as87"
X#define BLD		"/local/bin/ld"
X#define C386CRT		"/usr/local/lib/c386bas/crtso.o"
X#define C386LIBC	"/usr/local/lib/c386bas/libc.a"
X#define C387CRT		"/usr/local/lib/c387bas/crtso.o"
X#define C387LIBC	"/usr/local/lib/c386bas/libc.a"  /* not separate yet */
X#define B3CRT		"/usr/local/lib/i386/crtso.o"
X#define B3LIBC		"/usr/local/lib/i386/libc.a"
X#define B0CRT		"/usr/local/lib/i86/crtso.o"
X#define B0LIBC		"/usr/local/lib/i86/libc.a"
X
X#define PEM		"-R/usr/lib/pem"
X#define PC_ERR		"-r/usr/lib/pc_errors"
X
X#define C68		"/usr/lib/c68"
X#define FPP		"/usr/lib/fpp"
X#define HCC		"/usr/lib/hcc"
X#define TOP		"/usr/lib/top"
X#define NEW_LD		"/usr/bin/ld"
X
X
X/*	every pass that this program knows about has associated with it
X	a structure, containing such information as its name, where it
X	resides, the flags it accepts, and the like.
X*/
Xstruct passinfo {
X	char *p_name;		/* name of this pass */
X	char *p_path;		/* where is it */
X	char *p_from;		/* suffix of source (comma-separated list) */
X	char *p_to;		/* suffix of destination */
X	char *p_acceptflags;	/* comma separated list; format:
X			   		flag
X			   		flag*
X			   		flag=xxx
X					flag*=xxx[*]
X				   where a star matches a, possibly empty, 
X				   string
X				*/
X	int  p_flags;
X#define INPUT	01		/* needs input file as argument */
X#define OUTPUT	02		/* needs output file as argument */
X#define LOADER	04		/* this pass is the loader */
X#define STDIN	010		/* reads from standard input */
X#define STDOUT	020		/* writes on standard output */
X#define SOURCE	040		/* give source file name as last argument
X				   (hack for pc)
X				*/
X#define O_OUTPUT 0100		/* -o outputfile, hack for as */
X#define PREPALWAYS	0200	/* always to be preprocessed */
X#define PREPCOND	0400	/* preprocessed when starting with '#' */
X#define LD2STEPS	01000	/* ld followed by cv */
X};
X
X#define MAXHEAD	7
X#define MAXTAIL	4
X/*
X * MAXPASS used to be 7, but with FPP possibly defined there is an
X * additional pass. If you choose the new linker, the number is again
X * smaller since the new linker does the 'cv' job, too.
X * A too high number does not matter, anyway.
X */
X#define MAXPASS	8
X
X/*	Every language handled by this program has a "compile" structure
X	associated with it, describing the start-suffix, how the driver for
X	this language is called, which passes must be called, which flags
X	and arguments must be passed to these passes, etc.
X	The language is determined by the suffix of the argument program.
X	However, if this suffix does not determine a language (DEFLANG),
X	the callname is used.
X	Notice that the 's' suffix does not determine a language, because
X	the input file could have been derived from f.i. a C-program.
X	So, if you use "cc x.s", the C-runtime system will be used, but if
X	you use "as x.s", it will not.
X*/
Xstruct compile {
X	char *c_suffix;		/* starting suffix of this list of passes */
X	char *c_callname;	/* affects runtime system loaded with program */
X	struct pass {
X		char *pp_name;		/* name of the pass */
X		char *pp_head[MAXHEAD];	/* args in front of filename */
X		char *pp_tail[MAXTAIL];	/* args after filename */
X	} c_passes[MAXPASS];
X	int  c_flags;
X#define DEFLANG		010	/* this suffix determines a language */
X};
X
Xstruct passinfo passinfo[] = {
X	{ "cpp", PP, 0, "i", "I*,D*,U*", INPUT|STDOUT },
X#ifdef C68
X	{ "c68", C68, "i,c", "s", "Q*", INPUT|OUTPUT|PREPALWAYS },
X#endif
X
X	{ "cccp", CCCP, "c", "i", "D*,I*,U*,Wal*,ped*,tri*,nostdinc",
X			INPUT|OUTPUT },
X	{ "decuscpp", DECUSCPP, "c", "i", "D*,I*,U*,C,E,N,P,T*,X*",
X			INPUT|OUTPUT },
X	{ "app", DECUSCPP, "x", "s", "D*,I*,U*,E,N,P,T*,X*",
X			INPUT|OUTPUT },
X	{ "c386", C386, "i", "s", "noopt,noreg,icode,list,warn*,nowarn,trad,noreg",
X			INPUT|OUTPUT },
X	{ "c387", C387, "i", "s", "noopt,noreg,icode,list,warn*,nowarn,trad,noreg,nofpu",
X			INPUT|OUTPUT },
X	{ "sc", SC, "i,c", "s", "D*,I*,d,p,t", STDIN|STDOUT },
X	{ "bas", BAS, "s", "o", "g,j,m", INPUT|O_OUTPUT },
X	{ "bas87", BAS87, "s", "o", "g,j,m", INPUT|O_OUTPUT },
X	{ "bld", BLD, "o", "out", "M,r,s", INPUT|O_OUTPUT|LOADER },
X
X#ifdef FPP
X	{ "fpp", FPP, "m",   "n", "", INPUT|OUTPUT },
X#endif
X#ifdef HCC
X	{ "hcc", HCC, "c", "x", "I*,D*,U*", STDIN|STDOUT },
X#endif
X#ifdef TOP
X	{ "top", TOP, "x", "s", "", INPUT|OUTPUT },
X#endif
X	{ "cem", CEM, "i,c", "k", "R,p,w,T*,I*,D*,U*", INPUT|OUTPUT },
X	{ "pc", PC, "i,p", "k", "L,p,w,e,E,T*,{*", INPUT|OUTPUT|SOURCE|PREPCOND },
X	{ "opt", OPT, "k", "m", "LIB=L", STDIN|STDOUT },
X#ifdef FPP
X        /* cg processes fpp output */
X	{ "cg", CG, "n", "s", "O=p4", INPUT|OUTPUT },
X#else
X	{ "cg", CG, "m", "s", "O=p4", INPUT|OUTPUT },
X#endif
X	{ "as", AS, "i,s", "o", "T*", INPUT|O_OUTPUT|PREPCOND },
X#ifdef NEW_LD
X	{ "ld", NEW_LD, "o", "out", "m*,r,s,u*,w", INPUT|O_OUTPUT|LOADER },
X#else
X	{ "ld", LD, "o", "out", "r,s", INPUT|LOADER|LD2STEPS },
X	{ "cv", CV, "out", 0, "", INPUT|OUTPUT },	/* must come after loader */
X#endif
X	{ 0}
X};
X
Xstruct compile c68_short_pass =
X{	"c", "cc",
X	{	{ "c68", {"-Qshort"}, {0} },
X		{ "as", {"-"}, {0} },
X#ifdef NEW_LD
X		{ "ld", {"-X_","-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT},
X			{LIBC68, END}},
X#else
X		{ "ld", {"-c", "-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT}, 
X			  {LIBC68, END}},
X		{ "cv", {0}, {0} }
X#endif
X	},
X	DEFLANG
X};
X
Xstruct compile c68_long_pass =
X{	"c", "cc",
X	{	{ "c68", {"-Qnoshort"}, {0} },
X		{ "as", {"-"}, {0} },
X#ifdef NEW_LD
X		{ "ld", {"-X_","-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT32},
X			{LIBC6832, END32}},
X#else
X		{ "ld", {"-c", "-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT32}, 
X			  {LIBC6832, END32}},
X		{ "cv", {0}, {0} }
X#endif
X	},
X	DEFLANG
X};
X
Xstruct compile sozobon_pass =
X{	"c", "cc",
X	{	{ "hcc", {0}, {0} },
X		{ "top", {0}, {0} },
X		{ "as", {"-"}, {0} },
X#ifdef NEW_LD
X		{ "ld", {"-X_","-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT},
X			{LIBSOZO, END}},
X#else
X		{ "ld", {"-c", "-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT}, 
X			  {LIBSOZO, END}},
X		{ "cv", {0}, {0} }
X#endif
X	},
X	DEFLANG
X};
X
Xstruct compile bcc3_pass =
X{	"c", "c",
X	{	{ "sc", {"-3"}, {0} },
X		{ "bas", {"-3", "-u", "-w"}, {0} },
X		{ "bld", {"-3","-i", B3CRT},
X			 {B3LIBC}}
X	},
X	DEFLANG
X};
X
Xstruct compile bcc0_pass =
X{	"c", "c",
X	{	{ "sc", {"-0"}, {0} },
X		{ "bas", {"-0", "-u", "-w"}, {0} },
X		{ "bld", {"-0","-i", B0CRT},
X			 {B0LIBC}}
X	},
X	DEFLANG
X};
X
Xstruct compile c386_pass =
X{	"c", "c",
X	{
X		{ "cccp", {"-traditional"}, {0} },
X		{ "c386", {0}, {0} },
X		{ "bas", {"-3", "-j", "-u", "-w"}, {0} },
X		{ "bld", {"-3","-i", C386CRT}, {C386LIBC}}
X	},
X	DEFLANG
X};
X
Xstruct compile c387_pass =
X{	"c", "c",
X	{
X		{ "decuscpp", {0}, {0} },
X		{ "c387", {0}, {0} },
X		{ "bas87", {"-3", "-j", "-u", "-w"}, {0} },
X		{ "bld", {"-3","-i", C387CRT}, {C387LIBC}}
X	},
X	DEFLANG
X};
X
Xstruct compile ack_pass =
X{	"c", "cc", 
X	{	{ "cem", {"-L"}, {0} },
X		{ "opt", {0}, {0} },
X#ifdef FPP
X		{ "fpp", {0}, {0} },
X#endif
X		{ "cg", {0}, {0} },
X		{ "as", {"-"}, {0} },
X#ifdef NEW_LD
X		{ "ld", {"-X_","-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT},
X			{LIBC, END}},
X#else
X		{ "ld", {"-c", "-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT}, 
X			  {LIBC, END}},
X	 	{ "cv", {0}, {0} }
X#endif
X	},
X	DEFLANG
X};
X
X/*
X * passes[C_ACK_PASS] has to be replaced by an alternate pass
X * if an alternate compiler is to be used
X */
X#define C_ACK_PASS 0 /* look at the initialization of passes[] */
X
X		
Xstruct compile passes[] = {
X{	"c", "cc", 
X	{	{ "cem", {"-L"}, {0} },
X		{ "opt", {0}, {0} },
X#ifdef FPP
X		{ "fpp", {0}, {0} },
X#endif
X		{ "cg", {0}, {0} },
X		{ "as", {"-"}, {0} },
X#ifdef NEW_LD
X		{ "ld", {"-X_","-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT},
X			{LIBC, END}},
X#else
X		{ "ld", {"-c", "-a0:2", "-a1:2", "-a2:2", "-a3:2", CRT}, 
X			  {LIBC, END}},
X	 	{ "cv", {0}, {0} }
X#endif
X	},
X	DEFLANG
X},
X{	"p", "pc",
X	{	{ "pc", { PEM, PC_ERR, "-Vw2i2j2p2f8l4" }, {0} },
X		{ "opt", {0}, {0} },
X		{ "cg", {0}, {0} },
X		{ "as", {"-"}, {0} },
X#ifdef NEW_LD
X		{ "ld", {"-X_","-a0:2", "-a1:2", "-a2:2", "-a3:2", PRT},
X			{LIBP, LIBC, END}},
X#else
X		{ "ld", {"-c", "-a0:2", "-a1:2", "-a2:2", "-a3:2", PRT}, 
X			  {LIBP, LIBC,
X			   END}},
X		{ "cv", {0}, {0} }
X#endif
X	},
X	DEFLANG
X},
X{	"s", "as",
X	{	{ "as", {0}, {0}}},
X	0
X},
X{	"x", "c",
X	{	{ "app", {"-P"}, {0}},
X		{ "as", {0}, {0}}
X	},
X	DEFLANG
X},
X{	0
X}
X};
X
X#define MAXARGC	128	/* maximum number of arguments allowed in a list */
X#define USTR_SIZE	64	/* maximum length of string variable */
X
Xtypedef char USTRING[USTR_SIZE];
X
Xstruct arglist {
X	int al_argc;
X	char *al_argv[MAXARGC];
X};
X
Xstruct arglist CALLVEC[2];
X
Xint kids[] = {-1, -1};
X
Xchar *o_FILE = "a.out"; /* default name for executable file */
X
X#define init(a)		((a)->al_argc = 1)
X#define cleanup(str)		(str && remove(str))
X#define library(nm) \
X	mkstr(alloc((unsigned int)strlen(nm) + strlen(LIBPREFIX) + 7), \
X		LIBPREFIX, nm, ".a")
X
Xchar *ProgCall = 0;
X
Xint RET_CODE = 0;
X
Xchar *stopsuffix = 0;
Xint v_flag = 0;
Xint t_flag = 0;
Xint noexec = 0;
X
Xchar *mkstr();
Xchar *alloc();
Xchar *process();
Xchar *strcpy(), *strcat();
X
XUSTRING curfil;
XUSTRING newfil;
Xstruct arglist SRCFILES;
Xstruct arglist LDFILES;
Xstruct arglist GEN_LDFILES;
Xstruct arglist FLAGS;
X
Xchar *tmpdir = "/tmp";
Xchar tmpname[64];
X
Xstruct compile *compbase;
Xstruct pass *loader;
Xstruct passinfo *loaderinfo;
Xchar *source;
X
Xtrapcc(sig)
X	int sig;
X{
X	signal(sig, SIG_IGN);
X	if (kids[0] != -1) kill(kids[0], sig);
X	if (kids[1] != -1) kill(kids[1], sig);
X	cleanup(newfil);
X	cleanup(curfil);
X	exit(1);
X}
X
X/*
X * trade in a nondefault compiler and
X * ensure that the different C compilers are not called at the same time
X */
Xvoid
Xswitch_c_compilers(compiler)
Xstruct compile compiler;
X{
X	static int	pass_changed = 0;
X	char	*err = 
X"c: the -bcc3 -bcc0 -c386 -c387 -ack, -sozo, -c68s and -c68l flags are exclusive\n";
X
X	if (pass_changed)
X	{
X		write(2,err,strlen(err));
X		exit(1);
X	}
X	pass_changed = 1;
X	passes[C_ACK_PASS] = compiler;
X}
X
Xmain(argc, argv)
X	char *argv[];
X{
X	char *str;
X	char **argvec;
X	int count;
X	char *file;
X
X	ProgCall = *argv++;
X
X	passes[C_ACK_PASS] = c386_pass;		/* initial default compiler */
X
X	signal(SIGHUP, trapcc);
X	signal(SIGINT, trapcc);
X	signal(SIGQUIT, trapcc);
X	while (--argc > 0) {
X		if (*(str = *argv++) != '-') {
X			append(&SRCFILES, str);
X			continue;
X		}
X
X		switch (str[1]) {
X
X		case 'a':
X			if (!strcmp(str,"-ack")) {
X			    switch_c_compilers(ack_pass);
X			} else {
X			    append(&FLAGS, str);
X			}
X			break;
X		case 'b':
X			if (!strcmp(str,"-bcc3")) {
X			    switch_c_compilers(bcc3_pass);
X			} else if (!strcmp(str,"-bcc0")) {
X			    switch_c_compilers(bcc0_pass);
X			} else {
X			    append(&FLAGS, str);
X			}
X			break;
X		case 'c':
X			if (!strcmp(str,"-c68s")) {
X			    switch_c_compilers(c68_short_pass);
X			} else if (!strcmp(str,"-c68l")) {
X			    switch_c_compilers(c68_long_pass);
X			} else if (!strcmp(str,"-c386")) {
X			    switch_c_compilers(c386_pass);
X			} else if (!strcmp(str,"-c387")) {
X			    switch_c_compilers(c387_pass);
X			} else {
X			    stopsuffix = "o";
X			}
X			break;
X		case 'F':
X			break;
X		case 'l':
X			append(&SRCFILES, library(&str[2]));
X			break;
X		case 'o':
X			if (argc-- >= 0)
X				o_FILE = *argv++;
X			break;
X		case 'S':
X			stopsuffix = "s";
X			break;
X		case 'v':
X			v_flag++;
X			if (str[2] == 'n')
X				noexec = 1;
X			break;
X		case 't':
X			/* save temporaries */
X			t_flag++;
X			break;
X		case 's':
X			if (!strcmp(str,"-sozo")) {
X			    switch_c_compilers(sozobon_pass);
X			} else {
X			    append(&FLAGS, str);
X			}
X			break;
X		case 'T':
X			tmpdir = &str[2];
X			/*FALLTHROUGH*/
X		default:
X			append(&FLAGS, str);
X
X		}
X	}
X
X/*
X * The call to mkbase has to be delayed until now since passes[]
X * is not initialized till now.
X */
X        mkbase();
X	mktempname(tmpname);
X
X	count = SRCFILES.al_argc;
X	argvec = &(SRCFILES.al_argv[0]);
X
X	while (count-- > 0) {
X
X		file = *argvec++;
X		source = file;
X
X		if (SRCFILES.al_argc > 1) {
X			write(1, file, strlen(file));
X			write(1, ":\n", 2);
X		}
X
X		file = process(file, 1);
X	
X		if (file && ! stopsuffix) append(&LDFILES, file);
X	}
X
X	clean(&SRCFILES);
X
X	/* loader ... */
X	if (RET_CODE == 0 && LDFILES.al_argc > 0) {
X		register struct passinfo *pp = passinfo;
X
X		while (!(pp->p_flags & LOADER)) pp++;
X		mkstr(newfil, tmpname, pp->p_to, "");
X		callld(&LDFILES, (pp->p_flags&LD2STEPS)? newfil: o_FILE,
X			loader, pp);
X		if (RET_CODE == 0) {
X			register int i = GEN_LDFILES.al_argc;
X
X			while (i-- > 0) {
X				remove(GEN_LDFILES.al_argv[i]);
X				free(GEN_LDFILES.al_argv[i]);
X			}
X			if (pp->p_flags&LD2STEPS) {
X				process(newfil, 0);
X			}
X		}
X	}
X	exit(RET_CODE);
X}
X
Xremove(str)
X	char *str;
X{
X	if (t_flag)
X		return;
X	if (v_flag) {
X		prs("rm ");
X		prs(str);
X		prs("\n");
X	}
X	if (noexec)
X		return;
X	unlink(str);
X}
X
Xchar *
Xalloc(u)
X	unsigned u;
X{
X	char *malloc();
X	register char *p = malloc(u);
X
X	if (p == 0) panic("no space\n");
X	return p;
X}
X
Xappend(al, arg)
X	struct arglist *al;
X	char *arg;
X{
X	char *a = alloc((unsigned) (strlen(arg) + 1));
X
X	strcpy(a, arg);
X	if (al->al_argc >= MAXARGC)
X		panic("argument list overflow\n");
X	al->al_argv[(al->al_argc)++] = a;
X}
X
Xconcat(al1, al2)
X	struct arglist *al1, *al2;
X{
X	register i = al2->al_argc;
X	register char **p = &(al1->al_argv[al1->al_argc]);
X	register char **q = &(al2->al_argv[0]);
X
X	if ((al1->al_argc += i) >= MAXARGC)
X		panic("argument list overflow\n");
X	while (i-- > 0)
X		*p++ = *q++;
X}
X
Xchar *
Xmkstr(dst, arg1, arg2, arg3)
X	char *dst, *arg1, *arg2, *arg3;
X{
X	register char *p;
X	register char *q = dst;
X
X	p = arg1;
X	while (*q++ = *p++);
X	q--;
X	p = arg2;
X	while (*q++ = *p++);
X	q--;
X	p = arg3;
X	while (*q++ = *p++);
X	q--;
X	return dst;
X}
X
Xbasename(str, dst)
X	char *str;
X	register char *dst;
X{
X	register char *p1 = str;
X	register char *p2 = p1;
X
X	while (*p1)
X		if (*p1++ == '/')
X			p2 = p1;
X	p1--;
X	if (*--p1 == '.') {
X		*p1 = '\0';
X		while (*dst++ = *p2++);
X		*p1 = '.';
X	}
X	else
X		while (*dst++ = *p2++);
X}
X
Xchar *
Xextension(fln)
X	char *fln;
X{
X	register char *fn = fln;
X
X	while (*fn) fn++;
X	while (fn > fln && *fn != '.') fn--;
X	if (fn != fln) return fn+1;
X	return (char *)0;
X}
X
Xrunvec(vec, pass, in, out)
X	struct arglist *vec;
X	struct passinfo *pass;
X	char *in, *out;
X{
X	int pid, status;
X
X	if (
X		strncmp(vec->al_argv[1], "/usr/", 5) == 0
X		&&
X		access(vec->al_argv[1] + 4, 1) == 0
X	)
X		strcpy(vec->al_argv[1], vec->al_argv[1] + 4);
X	if (v_flag) {
X		pr_vec(vec);
X		if (pass->p_flags & STDIN) {
X			prs(" <");
X			prs(in);
X		}
X		if (pass->p_flags & STDOUT) {
X			prs(" >");
X			prs(out);
X		}
X		prs("\n");
X	}
X	if (noexec)
X		return 1;
X	if ((pid = fork()) == 0) {	/* start up the process */
X		if (pass->p_flags & STDIN) { /* redirect standard input */
X			close(0);
X			if (open(in, 0) != 0)
X				panic("cannot open input file\n");
X		}
X		if (pass->p_flags & STDOUT) { /* redirect standard output */
X			close(1);
X			if (creat(out, 0666) != 1)
X				panic("cannot create output file\n");
X		}
X		ex_vec(vec);
X	}
X	if (pid == -1)
X		panic("no more processes\n");
X	kids[0] = pid;
X	clean(vec);
X	wait(&status);
X	kids[0] = -1;
X	return status ? ((RET_CODE = 1), 0) : 1;
X}
X
Xprs(str)
X	char *str;
X{
X	if (str && *str)
X		write(2, str, strlen(str));
X}
X
Xpanic(str)
X	char *str;
X{
X	prs(str);
X	trapcc(SIGINT);
X}
X
Xpr_vec(vec)
X	register struct arglist *vec;
X{
X	register char **ap = &vec->al_argv[1];
X	
X	vec->al_argv[vec->al_argc] = 0;
X	prs(*ap);
X	while (*++ap) {
X		prs(" ");
X		if (strlen(*ap))
X			prs(*ap);
X		else
X			prs("(empty)");
X	}
X}
X
Xex_vec(vec)
X	register struct arglist *vec;
X{
X	extern int errno;
X
X	vec->al_argv[vec->al_argc] = 0;
X	execv(vec->al_argv[1], &(vec->al_argv[1]));
X	if (errno == ENOEXEC) { /* not an a.out, try it with the SHELL */
X		vec->al_argv[0] = SHELL;
X		execv(SHELL, &(vec->al_argv[0]));
X	}
X	if (access(vec->al_argv[1], 1) == 0) {
X		/* File is executable. */
X		prs("Cannot execute ");
X		prs(vec->al_argv[1]);
X		prs(". Not enough memory.\n");
X		prs("Use chmem to reduce its stack allocation\n");
X	} else {
X		prs(vec->al_argv[1]);
X		prs(" is not executable\n");
X	}
X	exit(1);
X}
X
Xmktempname(nm)
X	register char *nm;
X{
X	register int i;
X	register int pid = getpid();
X
X	strcpy(nm, tmpdir);
X	strcat(nm, "/");
X	strcat(nm, compbase->c_callname);
X	while (*nm) nm++;
X
X	for (i = 9; i > 3; i--) {
X		*nm++ = (pid % 10) + '0';
X		pid /= 10;
X	}
X	*nm++ = '.';
X	*nm++ = '\0'; /* null termination */
X}
X
Xmkbase()
X{
X	register struct compile *p = passes;
X	USTRING callname;
X
X	basename(ProgCall, callname);
X	while (p->c_suffix) {
X		if (strcmp(p->c_callname, callname) == 0) {
X			compbase = p;
X			mkloader();
X			return;
X		}
X		p++;
X	}
X	/* we should not get here */
X	panic("internal error\n");
X}
X
Xmkloader()
X{
X	register struct passinfo *p = passinfo;
X	register struct pass *pass;
X
X	while (!(p->p_flags & LOADER)) p++;
X	loaderinfo = p;
X	pass = &(compbase->c_passes[0]);
X	while (strcmp(pass->pp_name, p->p_name)) pass++;
X	loader = pass;
X}
X
Xneedsprep(name)
X	char *name;
X{
X	int file;
X	char fc;
X
X	file = open(name,0);
X	if (file <0) return 0;
X	if (read(file, &fc, 1) != 1) fc = 0;
X	close(file);
X	return fc == '#';
X}
X
Xchar *
Xapply(pinf, cp, name, passindex, noremove, first, resultname)
X	register struct passinfo *pinf;
X	register struct compile *cp;
X	char *name, *resultname;
X{
X	/*	Apply a pass, indicated by "pinf", with args in 
X		cp->c_passes[passindex], to name "name", leaving the result
X		in a file with name "resultname", concatenated with result
X		suffix.
X		When neccessary, the preprocessor is run first.
X		If "noremove" is NOT set, the file "name" is removed.
X	*/
X
X	struct arglist *call = &CALLVEC[0];
X	struct pass *pass = &(cp->c_passes[passindex]);
X	char *outname;
X
X	if ( /* this pass is the first pass */
X	     first
X	   &&
X	     ( /* preprocessor always needed */
X	       (pinf->p_flags & PREPALWAYS)
X	     ||/* or only when "needsprep" says so */
X	       ( (pinf->p_flags & PREPCOND) && needsprep(name))
X	     )
X	   ) {
X		mkstr(newfil, tmpname, passinfo[0].p_to, "");
X		mkvec(call, name, newfil, (struct pass *) 0, &passinfo[0]);
X		if (! runvec(call, &passinfo[0], name, newfil)) {
X			cleanup(newfil);
X			return 0;
X		}
X		strcpy(curfil, newfil);
X		newfil[0] = '\0';
X		name = curfil;
X		noremove = 0;
X	}
X	if (pinf->p_to) outname = mkstr(newfil, resultname, pinf->p_to, "");
X	else outname = o_FILE;
X	mkvec(call, name, outname, pass, pinf);
X	if (! runvec(call, pinf, name, outname)) {
X		cleanup(outname);
X		if (! noremove) cleanup(name);
X		return 0;
X	}
X	if (! noremove) cleanup(name);
X	strcpy(curfil, newfil);
X	newfil[0] = '\0';
X	return curfil;
X}
X
Xint
Xapplicable(pinf, suffix)
X	struct passinfo *pinf;
X	char *suffix;
X{
X	/*	Return one if the pass indicated by "pinfo" is applicable to
X		a file with suffix "suffix".
X	*/
X	register char *sfx = pinf->p_from;
X
X	if (! suffix) return 0;
X	while (*sfx) {
X		char c;
X		register char *p = sfx;
X
X		while (*p && *p != ',') p++;
X		c = *p; *p = 0;
X		if (strcmp(sfx, suffix) == 0) {
X			*p = c;
X			return 1;
X		}
X		*p = c;
X		if (*p == ',') sfx = p+1;
X		else sfx = p;
X	}
X	return 0;
X}
X		
Xchar *
Xprocess(name, noremove)
X	char *name;
X{
X	register struct compile *cp = passes;
X	char *suffix = extension(name);
X	USTRING base;
X	register struct pass *pass;
X	register struct passinfo *pinf;
X
X	if (! suffix) return name;
X
X	basename(name, base);
X
X	while (cp->c_suffix) {
X		if ((cp->c_flags & DEFLANG) &&
X		    strcmp(cp->c_suffix, suffix) == 0)
X			break;
X		cp++;
X	}
X	if (! cp->c_suffix) cp = compbase;
X	pass = cp->c_passes;
X	while (pass->pp_name) {
X		int first = 1;
X
X		for (pinf=passinfo; strcmp(pass->pp_name,pinf->p_name);pinf++)
X			;
X		if (! (pinf->p_flags & LOADER) && applicable(pinf, suffix)) {
X			int cont = ! stopsuffix || ! pinf->p_to ||
X					strcmp(stopsuffix, pinf->p_to) != 0;
X			name = apply(pinf,
X				     cp,
X				     name,
X				     (int)(pass - cp->c_passes),
X				     noremove,
X				     first,
X				     applicable(loaderinfo, pinf->p_to) ||
X				      !cont ?
X					strcat(base, ".") :
X					tmpname);
X			first = noremove = 0;
X			suffix = pinf->p_to;
X			if (!cont || !name) break;
X		}
X		pass++;
X	}
X	if (!noremove && name)
X		append(&GEN_LDFILES, name);
X	return name;
X}
X
Xmkvec(call, in, out, pass, pinf)
X	struct arglist *call;
X	char *in, *out;
X	struct pass *pass;
X	register struct passinfo *pinf;
X{
X	register int i;
X
X	init(call);
X	append(call, pinf->p_path);
X	scanflags(call, pinf);
X	if (pass) for (i = 0; i < MAXHEAD; i++)
X		if (pass->pp_head[i])
X			append(call, pass->pp_head[i]);
X		else	break;
X	if (pinf->p_flags & INPUT)
X		append(call, in);
X	if (pinf->p_flags & OUTPUT)
X		append(call, out);
X	if (pinf->p_flags & O_OUTPUT) {
X		append(call, "-o");
X		append(call, out);
X	}
X	if (pass) for (i = 0; i < MAXTAIL; i++)
X		if (pass->pp_tail[i])
X			append(call, pass->pp_tail[i]);
X		else	break;
X	if (pinf->p_flags & SOURCE)
X		append(call, source);
X}
X
Xcallld(in, out, pass, pinf)
X	struct arglist *in;
X	char *out;
X	struct pass *pass;
X	register struct passinfo *pinf;
X{
X	struct arglist *call = &CALLVEC[0];
X	register int i;
X
X	init(call);
X	append(call, pinf->p_path);
X	scanflags(call, pinf);
X	append(call, "-o");
X	append(call, out);
X	for (i = 0; i < MAXHEAD; i++)
X		if (pass->pp_head[i])
X			append(call, pass->pp_head[i]);
X		else	break;
X	if (pinf->p_flags & INPUT)
X		concat(call, in);
X	if (pinf->p_flags & OUTPUT)
X		append(call, out);
X	for (i = 0; i < MAXTAIL; i++)
X		if (pass->pp_tail[i])
X			append(call, pass->pp_tail[i]);
X		else	break;
X	if (! runvec(call, pinf, (char *) 0, out)) {
X		cleanup(out);
X		RET_CODE = 1;
X	}
X	clean(call);
X}
X
Xclean(c)
X	register struct arglist *c;
X{
X	register int i;
X
X	for (i = 1; i < c->al_argc; i++) {
X		free(c->al_argv[i]);
X		c->al_argv[i] = 0;
X	}
X	c->al_argc = 0;
X}
X
Xscanflags(call, pinf)
X	struct arglist *call;
X	struct passinfo *pinf;
X{
X	/*	Find out which flags from FLAGS must be passed to pass "pinf",
X		and how. 
X		Append them to "call"
X	*/
X	register int i;
X	USTRING flg;
X
X	for (i = 0; i < FLAGS.al_argc; i++) {
X		register char *q = pinf->p_acceptflags;
X
X		while (*q)  {
X			register char *p = FLAGS.al_argv[i] + 1;
X
X			while ((*q == *p) && *q) {
X				q++; p++;
X			}
X			if (*q == ',' || !*q) {
X				if (! *p) {
X					/* append literally */
X					append(call, FLAGS.al_argv[i]);
X				}
X				break;
X			}
X			if (*q == '*') {
X				register char *s = flg;
X
X				if (*++q != '=') {
X					/* append literally */
X					append(call, FLAGS.al_argv[i]);
X					break;
X				}
X				*s++ = '-';
X				if (*q) q++;	/* skip ',' */
X				while (*q && *q != ',' && *q != '*') {
X					/* copy replacement flag */
X					*s++ = *q++;
X				}
X				if (*q == '*') {
X					/* copy rest */
X					while (*p) *s++ = *p++;
X				}
X				*s = 0;
X				append(call, flg);
X				break;
X			}
X			if (*q == '=') {
X				/* copy replacement */
X				register char *s = flg;
X
X				*s++ = '-';
X				q++;
X				while (*q && *q != ',') *s++ = *q++;
X				*s = 0;
X				append(call, flg);
X				break;
X			}
X			while (*q && *q++ != ',')
X				;
X		}
X	}
X}
xEOF
Newsgroups: comp.os.minix