/* $Header:pp.c 12.0$ */
/* $ACIS:pp.c 12.0$ */
/* $Source: /ibm/acis/usr/src/bin/RCS/pp.c,v $ */

#ifndef lint
static char *rcsid = "$Header:pp.c 12.0$";
#endif


/*
 * (c) Copyright 1985,1986 MetaWare, Inc.
 * The PP and HC command (and cross compilers)
 * 
 */
#include "pphc.h"
#include <stdio.h>
#include <sys/signal.h>
#if !defined(SYS5)
#    include <sys/signal.h>
#    include <sys/wait.h>
#    include <strings.h>
#    define strchr(a,b) index(a,b)
#    define memcpy(dest,src,len) bcopy((src),(dest),(len))
     extern char *sys_siglist[];
#else
#    include <signal.h>
#    include <string.h>
     /*
      * For some strange reason, System 5 doesn't have wait.h defined.
      */
     union wait {
	int w_status;
	struct {
#	if defined(vax) || defined(iAPX286) || defined(iAPX386)
		unsigned short w_Termsig:7;   /*Termination signal */
		unsigned short w_Coredump:1;  /*core dump indicator*/
		unsigned short w_Retcode:8;   /*exit code if w_termsig==0*/
#	else
		unsigned short w_Fill1: 16;	/*High 16 bits unused*/
		unsigned short w_Retcode: 8;	/*exit code if w_termsig==0*/
		unsigned short w_Coredump:1;  /*core dump indicator*/
		unsigned short w_Termsig:7;   /*Termination signal */
#	endif
		} w_T;
	};
#       define w_termsig	w_T.w_Termsig
#       define w_coredump	w_T.w_Coredump
#       define w_retcode	w_T.w_Retcode
    static char *sys_siglist[]={
	"","hangup","interrupt","quit","illegal instruction",
	"trace trap","IOT","EMT","floating point exception",
	"kill","bus error","segment fault","bad arg","broken pipe",
	"alarm clock","terminate","user signal 1","user signal 2"
	};
#endif

#define MAXARGS	270		/*Maximum number of args allowed*/
#define MAXSRC	250		/*Maximum number of .p,.s, and .c files */
#define MAXCPP  40		/*Max number of cpp arguments*/
#define POOLSIZE	4096	/*String pool space size*/
#define MAXPOPTS	100	/*Max number of PP compiler options*/

#ifndef CPP
#   define CPP "/lib/cpp"	/*Name of outboard preprocessor*/
#endif

#ifndef CC
#   define CC "/lib/cc"		/*Name of standard C compiler*/
#endif

#ifndef HIGH_C
#   define HIGH_C 1
#endif

#if 0	/*Few compilers handle enums correctly*/
    typedef enum{FALSE,TRUE} bool;
#else
    typedef char bool;
#   define FALSE 0
#   define TRUE 1
#endif

static char *av[MAXPOPTS+20];		/*Argument list build area*/
static char PP_command = 1;		/*Set to 0 if we are the HC command*/
static bool S_flag = FALSE;		/*status of the "-S" flag*/
static bool verbose = FALSE;		/*status of the "-v" flag*/
static bool c_flag = FALSE;		/*status of the "-c" flag*/
static bool O_flag = FALSE;		/*status of the "-O" flag*/
static bool g_flag = FALSE;		/*status of the "-g" flag*/
static bool w_flag = FALSE;		/*status of the "-w" flag*/
static bool R_flag = FALSE;		/*status of the "-R" flag*/
static bool B_flag = FALSE;		/*status of the "-B" flag*/
static bool E_flag = FALSE;		/*status of the "-E" flag*/
static bool e_flag = FALSE;		/*status of the "-e" flag*/
static bool M_flag = FALSE;		/*status of the "-M" flag*/
#if defined(iAPX286)
static Model Memory_model = m_small;   	/*For 286 UNIX*/
static char M_letter = 's';		/*For 286 UNIX*/
#endif
static bool f_flag = FALSE;		/*status of the "-f" flag*/
static bool p_flag = FALSE;		/*Status of the "-p" flag*/
static bool pg_flag = FALSE;		/*Status of the "-pg" flag*/
static bool ansi_flag = FALSE;		/*Status of the "-Hansi" flag*/
static bool ppo_flag = FALSE;		/*Status of the "-Hppo" flag*/
static bool make_flag = FALSE;		/*Status of the "-Hmake" flag*/
#if !CPP_ONLY
static bool cpp_flag = FALSE;  /*Invoke CPP prior to compilation for C?*/
#endif
static bool nocpp_flag = FALSE; /*Suppress CPP prior to compilation? */
static bool cheap = FALSE;		/*status of the "-cheap" flag */
static int filecnt = 0;		/*number of files being passed to LD*/
static char *only_object_module = NULL;/*set to object name if srccnt==1*/
static char *PPname = NULL;	/*File name (minus path) of PP compiler*/
static char *HCname = NULL;	/*File name (minus path) of HC compiler*/
static char *command_name;		/*Name of command*/
static char *Bstring;			/*Argument of "-B" flag*/
#ifdef MC68020
static bool f68881_flag = FALSE;	/* -f68881 flag */
static bool fsoft_flag = FALSE;		/* -fsoft flag*/
static bool ffpa_flag = FALSE;		/* -ffpa flag*/
#endif
#ifdef iAPX386
static bool f387_flag = FALSE;
static bool f1167_flag = FALSE;
#endif
static bool cpp_invoked = FALSE;
static char *secondary_startup = 0;	/*Secondary startup routine*/


#if !CPP_ONLY
#define IPATHSIZE 500
static char ipath[IPATHSIZE] = "";/*Ipath (built from "-I" specifications)*/
#endif

static char *temp_file = NULL;	/*Name of temp file written by cpp*/
static char *obj_tmp_file = NULL;/*Name of temp file containing object module*/

#if defined(ibm032) || defined(ibm370)
static char *s_tmp_file = NULL;	/*When -R specified for RT we must generate
					.s file*/
#endif

static char *object_suffix = OBJ_SUFFIX;  /* suffix of object module "o"*/

static char ON[] = "-on";
static char OFF[] = "-off";

/*
 * We import the following from the standard C library
 */
extern void exit();
extern void perror();
extern void execv();
extern void psignal();
extern void unlink();
extern char *mktemp();
#ifdef MC68020
extern char *getenv();
#endif

	/*
	 * Because the library version of strncat was misdesigned, we
	 * provide our own version in which the 3rd argument is the
	 * length of the result -- not the maximum number of bytes to
	 * move
	 */
static void strncat_(dest,src,destlen)
    char *dest,*src;
    int destlen;
    {
    register int dlen = strlen(dest);
    register int slen = strlen(src);
    if (dlen+slen >= destlen)
	slen = destlen-dlen;
    memcpy(dest+dlen,src,slen+1); /*add 1 to copy trailing zero*/
    }

	/*Return pointer to a file name with the the directory path removed*/
char *basename(path)					   
    char *path;
    {
    	register char *p = &path[strlen(path)];
	while (--p >= path && *p != '/');
	return(p+1);
    }

char suffix(p)		   /*Return the suffix character of file name p*/
   register char *p;
{
    register int i;
    i = 0;
    while (*p){
       p++;
       i++;
       if (*p=='/')
	  i=0;
       };
    if (i>2 && p[-2]=='.')
       return(p[-1]);
    else
       return('\0');
}

static void terminate(retcode)
    int retcode;
{
    /* If temp file written by cpp is hanging around, delete it*/
    if (temp_file != NULL) unlink(temp_file);
    if (obj_tmp_file != NULL) unlink(obj_tmp_file);
#if defined(ibm032) || defined(ibm370)
    if (s_tmp_file != NULL) unlink(s_tmp_file);
#endif
    exit(retcode);
}

static void interrupt(sig)
    int sig;
{
    terminate(0xFF);
}

static void catch(sig)	/*Catch signal*/
    int sig;
{
    if (signal(sig,SIG_DFL) == SIG_IGN)
	signal(sig,SIG_IGN);
    else
	signal(sig,interrupt);
}

void severe(msg)
   char *msg;
{
   fprintf(stderr,"%s\nAborting...\n",msg);
   terminate(-1);
}

char *copy(p)
   register char *p;
{
    static char strpool[POOLSIZE];		/*String pool*/
    static char *poolptr = strpool;	/*Points to free space in string pool*/
    register char *q = poolptr;
    register char *t;
    while ((*q++ = *p++) != '\0'){
       if (q == &strpool[POOLSIZE-1]){
	    severe("Too many arguments to process");
	    }
       }
    t = poolptr;
    poolptr = q;
    return(t);
}

char *alter_suffix(path,suffix)
    char *path,*suffix;
{
    char buf[110];
    register char *q = basename(path);
    int l = strlen(q);
    if (l >= sizeof buf - 10)
	strncpy(buf,q,sizeof buf);
    else
	strcpy(buf,q);	/*Strcpy is significantly faster than strncpy*/
    buf[l-1] = '\0';
    strncat_(buf,suffix,sizeof buf);
    return copy(buf);
}

static char *ldargs[MAXARGS];		/*List of loader flags*/
static int  ldargcnt = 0;		/*Number of loader flags*/
#ifdef iAPX286
static int CSTART_locn = 0;		/*For replacement later.*/
#endif iAPX286

void add_ldarg(arg)
   char *arg;
{
    if (ldargcnt == MAXARGS){
       severe("Too many linker arguments");
       }
#ifdef DEBUG
    printf("ldargs[%d]=%s\n",ldargcnt,arg);
#endif
    ldargs[ldargcnt++] = arg;
}

static char *popts[MAXPOPTS];		/*List of PP compiler options*/
static int  poptcnt = 0;		/*Number of PP compiler options*/

void add_popt(opt)
   char *opt;
{
    if (poptcnt == MAXPOPTS)
       severe("Too many compiler options");
#ifdef DEBUG
    printf("popts[%d]=%s\n",poptcnt,opt);
#endif
    popts[poptcnt++] = opt;
}

static char *cppargs[MAXCPP];		/*List of CPP arguments*/
static int cppcnt = 0;
void add_cppopt(opt)
    char *opt;
{
    if (cppcnt >= MAXCPP)
	severe("Too many cpp options");
    cppargs[cppcnt++] = opt;
}

static char *srcfiles[MAXSRC];		/*List of source files to be compiled*/
static char *objfiles[MAXSRC];		/*List of corresponding object files*/
static int  srccnt = 0;		/*Number of src files*/

void add_src(srcfile,objfile)
   char *srcfile,*objfile;
{
    if (srccnt == MAXSRC){
       severe("Too many source files specified");
       }
#ifdef DEBUG
    printf("srcfiles[%d]=%s\n",srccnt,srcfile);
    printf("objfiles[%d]=%s\n",srccnt,objfile);
#endif
    srcfiles[srccnt] = srcfile;
    objfiles[srccnt] = objfile;
    srccnt++;
}
/*
 * Identify name of compiler by looking at argv[0] which is passed in as "name"
 */
void identify_compiler(name)
    char name[]; /* Name that this driver was invoked with; assumed static*/
    {
    char *p = basename(name);
    char buf[100];
    if (p[0]=='h' || p[0]=='c') {
	PP_command = 0; /*Assume HC command*/
#if !defined(HCCOM)
	HCname = p;
#endif
	}
    else {
	PP_command = 1;
#if !defined(PPCOM)
	PPname = p;
#endif
	}
    strcpy(buf,p);
    if (PP_command){
#if !defined(HCCOM)
	buf[0] = 'h';
	buf[1] = 'c';
	HCname = copy(buf);
#endif
	}
    else {
#if !defined(PPCOM)
	buf[0] = 'p';
	buf[1] = 'p';
	PPname = copy(buf);
#endif
	}
    }
/*
 *  PROCESS_ARGUMENTS
 */
void process_arguments(argc,argv)
    int argc; char *argv[];
{
    register int i;		/*Index in argv[]*/
#if !CPP_ONLY
    bool c_files_present = FALSE;
    bool p_files_present = FALSE;
    bool cpp_to_be_invoked;
    /*
     * Loop thru arguments to determine if C preprocessor will be invoked
     */
    for(i=1;i<argc;i++){
	register char *parg;
	parg = argv[i];
	if(parg[0]=='-'){
	    if(parg[1]=='H'){
		switch(parg[2]){
		    case 'c': 
			if(strcmp(parg+2,"cpp")==0){
			    cpp_flag = TRUE;
			    nocpp_flag = FALSE;
			    }
			    break;
		    case 'n': 
			if (strcmp(parg+2,"nocpp")==0){
			    nocpp_flag = TRUE;
			    cpp_flag = FALSE;
			    }
			break;
		    case 'p':
			if(strcmp(parg+2,"ppo")==0)
			    nocpp_flag = TRUE;
			break;
		    }
		}
	    }
	else switch(suffix(parg)){
	    case 'c': c_files_present = TRUE; break;
	    case 'p': p_files_present = TRUE; break;
	    }
	}
    if (cpp_flag) cpp_to_be_invoked = TRUE;
    else if(nocpp_flag) cpp_to_be_invoked = FALSE;
    else if(!p_files_present) cpp_to_be_invoked = USE_CPP_FOR_HC_BY_DEFAULT;
    else if(c_files_present) 
	cpp_to_be_invoked = USE_CPP_FOR_PP_BY_DEFAULT==TRUE?TRUE:
			    USE_CPP_FOR_HC_BY_DEFAULT;
    else
	cpp_to_be_invoked = USE_CPP_FOR_PP_BY_DEFAULT;
#endif
    /*
     * Loop thru each argument and sort out which ones are source files
     * PP options, linker options, or compiler options.
     */
    for(i=1;i < argc;i++){
        register char *parg;
        parg = argv[i];
	if (parg[0]=='-'){		/*Options prefixed with "-" */
	    /*
	     *  Options that begin with 'H' are assume to be compiler-specific
	     *  options. 
	     */
	    if (parg[1]=='H' && parg[2] != '\0'){
		bool add_arg = TRUE;
		switch(parg[2]){
		    case 'a':		/* ansi? */
			if (strcmp("ansi",parg+2)==0)
			    ansi_flag = TRUE;
			break;
		    case 'd':
			if (strcmp("debug",parg+2)==0){
			    add_arg = FALSE;
			    g_flag = TRUE;
			    }
			break;
		    case 'l': 		/*   list? */
			if (strcmp("list",parg+2)==0){
			    add_popt(ON);
			    add_popt(parg+2);
			    add_arg = FALSE;
			    }
			break;

		    case 'p':
			if (strcmp("ppo",parg+2)==0){
			    nocpp_flag = TRUE;/* Must use inboard preprocessor*/
			    c_flag = TRUE;  /* Suppress LD */
			    ppo_flag = TRUE;
			    }
			break;

		    case 'c':
			if(strcmp("cheap",parg+2)==0){  /*cheap? */
			    cheap = TRUE;
			    add_arg = FALSE;
			    }
#if !CPP_ONLY
			else if (strcmp("cpp",parg+2)==0){	/* cpp? */
			    cpp_flag = TRUE;
			    add_arg = FALSE;
			    }
#endif
			break;
		    case 'm':
			if (strcmp("make",parg+2)==0){   /*make?*/
			    c_flag = TRUE;	/*No linking*/
			    add_popt("-lines");	/*Suppress page breaks*/
			    add_popt("0");
			    make_flag = TRUE;
			    }
			break;
		    case 'n':
#if !CPP_ONLY
			if (strcmp("nocpp",parg+2)==0){   /*nocpp? */
			    nocpp_flag = TRUE;
			    add_arg = FALSE;
			    }
			else
#endif
			if (strcmp("noobj",parg+2)==0)  /*Don't invoke ld*/
			    c_flag = TRUE;
			break;
		    case 'v':
			/* -Hvolatile  -- kill all pointer dereferences
			   between statement boundaries. This is done
			   by turning off "optimize" toggle for now.
			*/
			if (strcmp("volatile",parg+2)==0){
			    add_arg = FALSE;
			    add_popt("-off");
			    add_popt("OPTIMIZE");
			    }
			break;
		    case 's':
			if (strncmp("suffix=",parg+2,7)==0){ /* -Hsuffix=*/
			    object_suffix=parg+9;
			    add_arg = FALSE;
			    }
			break;
		    case '+':
			if (strcmp("+w",parg+2)==0){
			    add_arg = FALSE;
			    /*
			     *  The "+w" flag turns on all warnings
			     */
			    add_popt(OFF);
			    add_popt("PCC_msgs");
			    }
			break;
		    }
		if (add_arg){
		    char *p = strchr(parg+2,'=');
		    /*
		     *   convert token "-Hxxx=yyy"  to two tokens: "-xxx yyy"
		     */
		    parg[1]='-';
		    if (p != 0){
			*p = '\0';
			add_popt(parg+1);
			add_popt(p+1);
			}
		    else
			add_popt(parg+1);
		    }
		}
	    else if (parg[1] != '\0' && parg[2] != '\0'){
	    /*
	     * Handle multi-letter options, e.g. -pg
	     */
		bool assume_ld_option = TRUE;
		switch(parg[1]){
		    case 'B': 
			B_flag = TRUE;
			Bstring = &parg[2];
			assume_ld_option = FALSE;
			break;
		    case 'p':
			if (strcmp(parg,"-pg")==0){
			    pg_flag = TRUE;
			    assume_ld_option = FALSE;
			    }
			break;
#ifdef ibm032
		    case 'm':
			/*
			 *  The "-ma" flag is esoteric to RT and 370
			 *  implementations.
			 */
			if (strcmp(parg,"-ma")==0){
			    if (!make_flag){
				add_popt(ON);
				add_popt("alloca");
				}
			    assume_ld_option = FALSE;
			    }
			else if (strcmp(parg,"-ms")==0){
			    if (!make_flag){
				add_popt(ON);
				add_popt("SHORT_RTFL");
				}
			    assume_ld_option = FALSE;
			    }
			break;
#endif
#ifdef iAPX386
		    case 'f': case 'F':
			if (strcmp(parg,"-f387")==0 || strcmp(parg,"-F387")==0){
			    f387_flag = TRUE;
			    assume_ld_option = FALSE;
			    }
			else
			if (strcmp(parg,"-f1167")==0 || strcmp(parg,"-F1167")==0){
			    f1167_flag = TRUE;
			    assume_ld_option = FALSE;
			    }
			break;
#endif			
#ifdef MC68020
		    case 'f':
			/*
			 * The "-f68881" flag causes MC68881 native ops to
			 * be generated.
			 * "-fsoft" causes routine calls
			 */
			if (strcmp(parg,"-f68881")==0){
			    f68881_flag = TRUE;
			    assume_ld_option = FALSE;
#ifdef MC68881_STARTUP
			    secondary_startup = MC68881_STARTUP;
#endif
			    }
                        else
			if (strcmp(parg,"-fsoft")==0){
			    fsoft_flag = TRUE;
			    assume_ld_option = FALSE;
			    }
			else if (strcmp(parg,"-fsingle")==0){
			    f_flag = TRUE;
			    assume_ld_option = FALSE;
			    }
			else if (strcmp(parg,"-ffpa")==0){
#ifdef FPA_STARTUP
			    secondary_startup = FPA_STARTUP;
#endif
			    ffpa_flag = TRUE;
			    f68881_flag = FALSE;
			    assume_ld_option = FALSE;
			    }
			break;
#endif
		    case 'g':
			/*
			 *  The "-go" option -- not supported
			 */
			if (strcmp(parg,"-go")==0){
			    fprintf(stderr,"-go: (warning) the obsolete debugger sdb is not supported\n");
			    assume_ld_option = FALSE;
			    }
			break;
#ifdef iAPX286
		    case 'M': {
		        char MM = parg[2];
		        Memory_model = m_small;	
		        if (MM != 'l' && MM != 's' && MM != 'c') {
		            fprintf(stderr,"Unrecognized memory model:%s\n", parg[2]);
		            terminate(1);
		            }
		        M_letter = MM;
		        if (MM == 'l') add_popt("-mm"), add_popt("large"), Memory_model = m_large;
		        if (MM == 'c') add_popt("-mm"), add_popt("compact"), Memory_model = m_compact;
		        if (MM == 'm') add_popt("-mm"), add_popt("medium"), Memory_model = m_medium;
		        if (MM == 'b') add_popt("-mm"), add_popt("big"), Memory_model = m_big;
		        break;
		        }
#endif		    
		    case 'U': 
		        add_cppopt(parg);
			assume_ld_option = FALSE;
			break;
		    case 'D':{
			char *p;
			assume_ld_option = FALSE;
			add_cppopt(parg);
#if !CPP_ONLY
			if (!cpp_to_be_invoked){
			    p = strchr(&parg[2],'=');
			    add_popt("-define");
			    if (p!=NULL){
				*p = ' ';
				add_popt(copy(&parg[2]));
				*p = '=';
				}
			    else{
				char buf[80];
				strncpy(buf,&parg[2],sizeof buf);
				strncat_(buf," ",sizeof buf);
				strncat_(buf,"1",sizeof buf);
				add_popt(copy(buf));
				}
			    }
#endif
			}
			break;
		    case 'I': 
			assume_ld_option = FALSE;
			add_cppopt(parg);
#if !CPP_ONLY
			if(!cpp_to_be_invoked){
			    if (ipath[0] != '\0')
			       strncat_(ipath,":",IPATHSIZE);
			    strncat_(ipath,&parg[2],IPATHSIZE);
			    strncat_(ipath,"/",IPATHSIZE);
			    }
#endif
			break;
#ifdef iAPX386
		    case 'l': 
		        if (parg[2] == 'm' && parg[3] == 0 && f1167_flag)
		           add_ldarg("-lm1167"), assume_ld_option = FALSE;
#endif			
		    }
		if (assume_ld_option)
		    add_ldarg(parg);
		}
	    /*
	     * Single letter options are either to be processed by the
	     * pp command itself, or passed to the ld command.	
	     */
	    else{
		switch(parg[1]){
		    case 'p': p_flag = TRUE; break;
		    case 'v': verbose = TRUE; break;
		    case 'S': S_flag = TRUE; break;
		    case 'c': c_flag = TRUE; break;
		    case 'O': O_flag =TRUE; break;
		    case 'R': R_flag = TRUE; break;
		    case 'w': w_flag = TRUE; break;
		    case 'g': g_flag = TRUE; break;
		    case 'E': E_flag = TRUE; break;
		    case 'M': M_flag = TRUE; break;
		    case 'f': f_flag = TRUE; break;
		    case 'B':
			B_flag = TRUE;
			Bstring = "/usr/c/o";   /* cc's convention*/
			break;
		    case 'C':   /*cpp options*/
		    case 'P':
		    case 'I':
		    case 'U':
		    case 'D': add_cppopt(parg); break;
		    case 'o':
			if (i+1 < argc){
			    add_ldarg(parg);
			    switch(suffix(argv[i+1])){
				case 'o':
				case 'c':
				case 's':
				case 'p':
				case 'a':
				    fprintf(stderr,"%s: -o would overwrite %s\n",
						command_name,argv[i+1]);
				    terminate(1);
				}
			    add_ldarg(argv[++i]);
			    }
			break;
		    case 'e':
			e_flag = TRUE;
			/* Fall thru...*/
		    case 'u':
		    case 'A':
			add_ldarg(parg);
			if (i+1 < argc)
			    add_ldarg(argv[++i]);
			break;
	   	    default: add_ldarg(parg); break;
		    }
	        }
	    }
	else if (*parg == '+' && strcmp(parg,"+w")==0){
	    /*
	     *  The "+w" flag turns on all warnings
	     */
	    add_popt(OFF);
	    add_popt("PCC_msgs");
	    }
	else{
	    /*
	     * Argument is a file specification. If it doesn't end in ".p",
	     * ".c", or ".s", assume that it esoteric to the linker.
	     */
	    char c = suffix(parg);
	    char *objp;
	    if (c == 'p' || c=='s' || c=='c'){
		objp = alter_suffix(parg,object_suffix);
		add_src(parg,objp);
		only_object_module = objp;  /*deleted if filecnt == 1*/
	        }
	    else
		objp = parg;
	    add_ldarg(objp); 	/*add object file to LD list*/
	    filecnt++;
	    }
	}
   /*
    *  If "-S" specified, then object modules for all compilations is to be
    *  sent to a temp file.
    */
   if (S_flag){
       int i;
       obj_tmp_file = mktemp("/tmp/pp.objXXXXXX");
       for (i=0; i<srccnt; i++)   /*Make all object output goto temp file*/
	  objfiles[i] = obj_tmp_file;
       only_object_module = obj_tmp_file;
       }
#if defined(ibm032) || defined(ibm370)
		/* Must go thru assembler to implement "-R" on RT PC */
    else if (R_flag)
       s_tmp_file = mktemp("/tmp/pp.sXXXXXX");
#endif
#ifdef MC68020
   if (!f68881_flag && !fsoft_flag && !ffpa_flag){
       char *p = getenv("FLOAT_OPTION");
       if (p!=NULL)
	   if (strcmp(p,"f68881")==0)
	       f68881_flag = TRUE;
	   else if (strcmp(p,"fsoft")==0)
	       fsoft_flag = TRUE;
	   else if (strcmp(p,"ffpa")==0)
	       ffpa_flag = TRUE;
       }
#endif
}    /*process_arguments*/

/*
 * Initialize
 */
void initialize()
{
   catch(SIGINT);		/*Intercept interrupt*/
   catch(SIGHUP);		/*Intercept hangup*/
   add_ldarg("ld");
#ifdef LDARG1
   add_ldarg(LDARG1);
#endif
#ifdef LDARG2
   add_ldarg(LDARG2);
#endif
#ifdef LDARG3
   add_ldarg(LDARG3);
#endif
#ifdef LDARG4
   add_ldarg(LDARG4);
#endif
#if !defined(SYS5)
   add_ldarg("-X");		/*start loader argument list*/
#endif
#ifdef iAPX286
   CSTART_locn = ldargcnt;
#endif
#ifdef CSTART
   add_ldarg(CSTART);		/*C startup routine*/
#endif
   }

#if defined(iAPX286)
void replace_CSTART() {
   /* Add either large or small startup routine; linker uses magic */
   /* number to then find the appropriate library. */
   if (CSTART_locn)
      ldargs[CSTART_locn] = m_START[cbug(Memory_model)];
   }	
#endif  

/*
 * Invoke cpp (C preprocessor)
 */
int invoke_cpp(input,output)
    char *input;	/*Input file*/
    char *output;	/*Output file. If NULL, then use standard out*/
{
    int i = 0;
    char **avp = av;
#ifdef INCLUDE_DIR1
    char Ibuf1[sizeof(INCLUDE_DIR1)+3];
#endif
    char Ibuf2[sizeof(INCLUDE_DIR2)+3];
    *avp++ = CPP;
    while (i < cppcnt)
	*avp++ = cppargs[i++];
#ifdef INCLUDE_DIR1
    strcpy(Ibuf1,"-I");
    strcpy(Ibuf1+2,INCLUDE_DIR1);
    *avp++ = Ibuf1;
#endif
    /*
     * If INCLUDE_DIR2 is not /usr/include, then we must make it explicit
     */
    if (strcmp(INCLUDE_DIR2,"/usr/include")!=0){
	strcpy(Ibuf2,"-I");
	strcpy(Ibuf2+2,INCLUDE_DIR2);
	*avp++ = Ibuf2;
	}
    if (M_flag)
	*avp++ = "-M";
#ifdef iAPX286	
    *avp++ = "-DiAPX286";       /* Needed for stdio.h. */
#endif    
    *avp++ = "-D__HIGHC__";
    *avp++ = "-D__STDC__";
    *avp++ = input;
    *avp++ = output;  /*May be null, which indicates standard output*/
    *avp = 0;
    return command(av[0],av);
}

/*
 * Invoke Pascal or High C compiler
 */
#define HC_compiler  0	
#define PP_compiler  1

int invoke_compiler(f,obj,name,which,anno)
   char *f;	/*Source file name*/
   char *obj;	/*Object file name*/
   char *name;  /*Compiler name*/
   int which;   /*HC or PP?*/
   char *anno;	/*File from which annotation is extracted*/
{
   register int i = 0;	/*index into popts array*/
   char fn[100];	/*Full pathname of compiler*/
   register char **avp = av+1;
   static char copyright_displayed = 0;
   /*
    * Derive path name of compiler
    */
   if (B_flag){
       strncpy(fn,Bstring,sizeof(fn)-8);
       if (name != NULL){
	   strcat(fn,name);
	   strcat(fn,"com");
	   }
       else 
       if (which == PP_compiler)
	   strcat(fn,"ppcom");
       else
	   strcat(fn,"hccom");
       av[0] = fn;
       }
   else{
#if defined(PPCOM) && defined(HCCOM)
       av[0] = which==PP_compiler?PPCOM:HCCOM;
#else
#  if defined(PPCOM) || defined(HCCOM)
       if (name != NULL){
#  endif
	   strcpy(fn,COMDIR);
	   strcat(fn,"/");
	   strcat(fn,name);
	   strcat(fn,"com");
	   av[0] = fn;
#  if defined(PPCOM) || defined(HCCOM)
	   }
       else
#  if defined(HCCOM)
         av[0] = HCCOM;
#  else
         av[0] = PPCOM;
#  endif
#  endif
#endif
       }
       
   *avp++ = f;
/*
   if (verbose){
      av[j++] = OFF;
      av[j++] = "quiet";
      }
*/
#ifndef IBM_HOST
   if (!copyright_displayed){
       copyright_displayed = 1;
       *avp++ = "-copyr";
#ifdef CROSS_SYSTEM
       *avp++ = "-target";
       *avp++ = CROSS_SYSTEM;
#endif
       }
#endif
   *avp++ = "-efile";   /*Direct messages to std error output*/
   *avp++ = "@E";
   *avp++ = "-silent";   /* Suppress all messages except diagnostics */
   *avp++ = "-fn";	/*Always display file name in diagnostic messages*/
   *avp++ = "-obj";	/*Specify name of object file*/
   *avp++ = obj;
#ifdef iAPX286
   if (!cpp_invoked){
       *avp++ = "-define";
       *avp++ = "iAPX286 1";
       }
#endif
   if (srccnt>1) fprintf(stderr,"%s:\n",anno);
   if (S_flag==TRUE){
       *avp++ = "-S";
       *avp++ = alter_suffix(anno,"s");
       }
   if (pg_flag || p_flag){
       *avp++ = ON;
       *avp++ = "PROFILE";
       }
#if !CPP_ONLY
   {
       char buf[IPATHSIZE];
       if (ipath[0] != '\0'){
	   strncpy(buf,ipath,IPATHSIZE);
	   strncat_(buf,":",IPATHSIZE);
	   }
       else
	   buf[0] = '\0';
       if (which == HC_compiler){
#	    ifdef INCLUDE_DIR1	   
		strncat_(buf,INCLUDE_DIR1,IPATHSIZE);
		strncat_(buf,"/:",IPATHSIZE);
#	    endif
	    strncat_(buf,INCLUDE_DIR2,IPATHSIZE);
	    }
#ifdef PP_INCLUDE
       else {
	    strncat_(buf,PP_INCLUDE,IPATHSIZE);
	    }
#endif
       strncat_(buf,"/",IPATHSIZE);
       *avp++ = "-ipath";
       *avp++ = buf;
       }
#endif
#ifdef DEFINE_STRING
    if (which == HC_compiler){
       *avp++ = "-define";
       *avp++ = DEFINE_STRING;
       }
#endif
   if (w_flag){
       *avp++ = OFF;
       *avp++ = "warn";
       }
   if (R_flag && !S_flag && !make_flag){
#if defined(ibm032) || defined(ibm370)
       *avp++ = "-S";		/* Must go thru assembler to do -R */
       *avp++ = s_tmp_file;
#else
       *avp++ = ON;
       *avp++ = "READ_ONLY_DATA";
#endif
       }
   if (R_flag && !make_flag){
       *avp++ = ON;
       *avp++ = "READ_ONLY_STRINGS";
#if defined(ibm032) || defined(ibm370)
       *avp++ = ON;
       *avp++ = "R_FLAG";
#endif
       }
#if defined(ibm032) || defined(ibm370)
   if (which==HC_compiler){
       *avp++ = OFF;
       *avp++ = "RECOGNIZE_LIBRARY";
       }
#endif
   /*
    * -g turns cross jumping optimization off by default. We also want
    * to permit unreferenced local routines to exists so that they can
    * be invoked from the debugger. If "-O" specified, we turn cross-
    * jumping back on.
    */
   if (g_flag && !make_flag){
      *avp++ = "-debug";
      *avp++ = ON;
      if (O_flag)
	  *avp++ = "OPTIMIZE_XJMP";
      else
	  *avp++ = "KEEP_UNREFERENCED_ROUTINES";
      }
#ifdef IBM_HOST
   if (which==HC_compiler){
       *avp++ = ON;
       *avp++ = "LONG_ENUMS";
       }
#endif
   while (i<poptcnt)
       *avp++ = popts[i++];
   if (anno != f){
       *avp++ = "-anno";
       *avp++ = anno;
       }
   if (ansi_flag){
       if (which==HC_compiler){
#ifdef HCANSIST
	    *avp++ = "-st";
	    *avp++ = HCANSIST;
#endif
#ifdef HCANSIPT
	    *avp++ = "-pt";
	    *avp++ = HCANSIPT;
#endif
#ifdef HCANSIPPT
	    *avp++ = "-spt";
	    *avp++ = HCANSIPPT;
#endif
	    }
       else{
#ifdef PPANSIST
	    *avp++ = "-st";
	    *avp++ = PPANSIST;
#endif
#ifdef PPANSIPT
	    *avp++ = "-pt";
	    *avp++ = PPANSIPT;
#endif
	    }
       }
#ifdef FLOATING_POINT_OPERATIONS_DONE_IN_DOUBLE_BY_DEFAULT
   if (FLOATING_POINT_OPERATIONS_DONE_IN_DOUBLE_BY_DEFAULT &&
        !f_flag && which==HC_compiler && !make_flag && !ppo_flag
      ){
      *avp++ = ON;
      *avp++ = "DOUBLE_MATH_ONLY";
      }
#endif
#ifdef iAPX386
   if (f387_flag) {
      *avp++ = ON;
      *avp++ = "387";
      }
   if (f1167_flag) {
      *avp++ = ON;
      *avp++ = "1167";
      }
#endif
#ifdef MC68020
   if (f68881_flag){
       *avp++ = ON;
       *avp++ = "68881";
       }
   else if (fsoft_flag){
       *avp++ = OFF;
       *avp++ = "68881";
       }
   else if (ffpa_flag){
       *avp++ = OFF;
       *avp++ = "68881";
       *avp++ = ON;
       *avp++ = "WEITEK";
       }
#endif
   *avp++ = 0;
   return(command(av[0],av));
}

/*
 * Do compilations and assembly
 */
int do_compilations()
{
    register int i = 0;
    int RV = 0;

    while (i < srccnt){
        register char *f = srcfiles[i];
        char *objp = objfiles[i];
        int retcode;
        char c = suffix(f);
	i++;
        if (E_flag || M_flag)
 	    retcode = invoke_cpp(f,NULL);
        else{
	    char *source = f;
	    /*
	     * If cpp to be invoked prior to compilation, then doit here
	     */
#if !CPP_ONLY
	    if (cpp_flag && (c=='c' && HIGH_C || c=='p') || 
		     (!nocpp_flag &&
		         (HIGH_C && c=='c' && USE_CPP_FOR_HC_BY_DEFAULT
				||
		          c=='p' && USE_CPP_FOR_PP_BY_DEFAULT)))
#else
	    if (HIGH_C && c=='c' || c=='p')
#endif
	        {
		if (temp_file == NULL)
		    /*We need the '.' in the name to prevent automatic
			appending of ".p" or ".c" by the compiler*/
		    temp_file = mktemp("/tmp/pp.XXXXXX");
		source = temp_file;
		retcode = invoke_cpp(f,source);
		cpp_invoked = TRUE;
		}
	    else {
		retcode = 0;
		cpp_invoked = FALSE;
		}
	    if (retcode == 0)
	    if (c == 'p'){
		retcode = invoke_compiler(source,objp,PPname,PP_compiler,f);
		}
	    else if (c == 's'){
		if (S_flag == FALSE)
		   retcode = assemble(source,objp);
		else
		   retcode = 0;
		}
#if HIGH_C
	    else if (c == 'c'){
		retcode = invoke_compiler(source,objp,HCname,HC_compiler,f);
#if defined(ibm032) || defined(ibm370)
		/*We go thru assembler to implement "-R" on RT PC */
		if (!S_flag && R_flag && retcode==0)
		    retcode = assemble(s_tmp_file,objp);
#endif
		}
#else
	    else{ 
		/*
		 *  We invoke the "cc" command to compile C programs
		 */
		short j = 2;
		char *f_ = f;	/* Remember file name*/
		av[0] = "cc";
		av[1] = "-c";
		if (O_flag == TRUE)
		   av[j++] = "-O";
		if (S_flag == TRUE)
		   av[j++] = "-S";
		av[j++] = source;
		av[j++] = 0;
		if (srccnt > 1){
		   fprintf(stderr,"%s:\n",f_);
		   }
		retcode = command(CC,av);
		}
#endif !HIGH_C
	    }
        if (retcode < 0 || retcode >= 255){   /*Compiler abended?*/
	    RV = retcode;
	    break;
	    }
        if (retcode > RV) RV = retcode;
        }
    if (temp_file != NULL)
	unlink(temp_file);
    return(RV);
}

#ifdef DEBUG
/*
 * Dummy version of execv for testing
 */
static void execv(f,av)
   char *f; char *av[];
{
   register char **p; 
   printf("EXECV: ");
   printf(f);
   p = &av[0];
   while (*++p!=0)
	printf(" %s",*p);
   printf("\n");
   terminate(0);
}
#endif

/*
 * Invoke a command
 */
int command(f,av)
   char *f; char *av[];
{
    int t;
    union wait status;
    if ((t=fork())==0){
	if (verbose==TRUE){
	    char **p = &av[0];
	    fprintf(stderr,f);
	    while (*++p != 0){
		fprintf(stderr," %s",*p);
		}
	    fprintf(stderr,"\n");
	    }
	execv(f,av);
	fprintf(stderr,"%s: Can't find %s\nAborting...\n",command_name,f);
	terminate(1);
	}
    else{
	if (t == -1){
	    perror(f);
	    terminate(2);
	    }
        }
    while (t!=wait(&status));  /*Wait for child to terminate*/
    t = status.w_termsig;
    if (t!=0){
	if (t!=SIGINT){
	   fprintf(stderr,"(%s:) %s: %s%s\n",
		command_name,f,sys_siglist[t],
		status.w_coredump?" (core dumped)":"");
	   }
	terminate(0x7f);
 	}
    return( status.w_retcode );
}

/*
 * Invoke assembler
 */
static int assemble(f,obj)
   char *f;	/*Name of source file*/
   char *obj;  /*Name of object*/
{
#ifdef AS
   char **avp = av;
   *avp++ = AS;
   *avp++ = "-o";
   *avp++ = obj;
   *avp++ = f;
   if (R_flag) *avp++ = "-R";
#ifdef iAPX286
   /* Pass memory model on to assembler. */
   *avp = "-MX"; (*avp)[2] = M_letter; avp++;
#endif
   *avp = 0;
   if (srccnt>1) fprintf(stderr,"%s:\n",f);
   return(command(AS,av));
#else
   static char msg_issued = 0;
   if (!msg_issued){
       fprintf(stderr,"%s: Sorry, no cross-assembler available for %s\n",
				    CROSS_SYSTEM);
       msg_issued = 1;
       }
   return 1;
#endif
}

#ifdef LD
static int do_link()
{
   if (PP_command){
       if (cheap==TRUE)
	   add_ldarg(CHEAP);
       else
	   add_ldarg(PHEAP);
#      ifdef PPLIBPROF
           add_ldarg(p_flag||pg_flag?PPLIBPROF:PPLIB);
#      else
#if !defined(iAPX286)
           add_ldarg(PPLIB);
#else
           add_ldarg(m_PPLIB[cbug(Memory_model)]);
#endif
#      endif
       }
#  ifdef MWLIB
#  ifdef iAPX286
   add_ldarg(m_MWLIB[cbug(Memory_model)]);
#  else           
   add_ldarg(MWLIB);
#  endif
#  endif
#if defined(PROFSTART)
   if (p_flag)
       ldargs[2] = PROFSTART;
   else
#endif
#if defined(GPROFSTART)
   if (pg_flag)
       ldargs[2] = GPROFSTART;
#endif
   if (secondary_startup)
       add_ldarg(secondary_startup);
/* if (g_flag)
       add_ldarg("-lg");*/
#ifdef ibm032
	if (p_flag||pg_flag)
       		add_ldarg(FPLIB_P);
#endif
#  if defined(CLIB_P)
       add_ldarg(p_flag||pg_flag?CLIB_P:CLIB);
#  else
#  if defined(CLIB)
       add_ldarg(CLIB);
#  else
       add_ldarg(p_flag||pg_flag?"-lc_p":"-lc");
       
#  endif
#  endif
#ifdef CLIB2
   add_ldarg(CLIB2);
#endif
#ifdef START
   if (!e_flag){
       add_ldarg("-e");
       add_ldarg(START);
       }
#endif
#if defined(iAPX286)
   add_ldarg("-la");	/* For lmul, ldiv, etc., from C library. */
#endif           
   add_ldarg((char *) 0);
   return( command(LD,ldargs) );
}
#endif

/*
 * MAIN
 */
void main(argc,argv)
   int argc; char *argv[];
{
    int retcode;

    command_name = argv[0];
    initialize();
    identify_compiler(argv[0]);
    process_arguments(argc,argv);
#ifdef iAPX286
    replace_CSTART();
#endif     
    if (filecnt==0){
	fprintf(stderr,"%s: No files specified.\n",command_name);
	exit(0);
	}
    retcode = do_compilations();
#ifdef LD
    if (!c_flag && !S_flag && !E_flag && !M_flag){
       if (retcode == 0){
	   retcode = do_link();
	   /*
	    * If a single source file was compiled and linked, then
	    * delete its object module.
	    */
	   if (retcode == 0 && filecnt == 1 && only_object_module != NULL)
	       unlink(only_object_module);
	   }
       }
#endif
    terminate(retcode);
}
