/* 
 * (c) Copyright 1987-88 MetaWare, Inc.  
 * Command driver for High C 2.1 compiler and cross-referencer
 */
/* $Source: /ibm/acis/usr/src/bin/RCS/nhc.c,v $ */
#ifdef __STDC__
const
#endif
static char rcsid[]= "$Header:nhc.c 12.1$";

#include <stdio.h>
#include <ctype.h>
#include "hc.h"
#include <string.h>
#ifdef MSDOS
#  include <stdefs.h>
#  include <status.cf>
#  include <exec.cf>
#  include <signal.h>
#  include <stdlib.h>
#  define unlink remove
#else
#  include <sys/signal.h>
#  if !defined(SYS5)
#    include <sys/signal.h>
#    include <sys/wait.h>
#    ifdef BSD
#        define strchr(a,b) index(a,b)
#        define memcpy(dest,src,len) bcopy((src),(dest),(len))
#    endif
     extern char *sys_siglist[];
#  else
#    include <signal.h>
     /*
      * For some strange reason, System 5 doesn't have wait.h defined.
      */
     union wait {
	int w_status;
	struct {
#     if defined(vax) || defined (iAPX286)
		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

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

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

#  ifndef USE_CPP_FOR_PP_BY_DEFAULT
#  define USE_CPP_FOR_PP_BY_DEFAULT FALSE
#  endif

#endif

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

#define HIGH_C 1		/*C compiler is High C*/

#ifndef APOLLO	/*Apollo C compiler gets weird with enums*/
typedef enum{FALSE,TRUE} bool;
#else
typedef char bool;
#define FALSE 0
#define TRUE 1
#endif
#ifndef MSDOS
static char Hxref[] = "-Hxref=/tmp/xref.XXXXXX";
#else
static char Hxref[64];
#endif;
   
static char *av[MAXPOPTS+40];		/*Argument list build area*/

static bool S_flag = FALSE;		/*status of the "-S" flag*/
static char PP_command = 0;		/*Set to 0 if we are the HC command*/
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 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 char *X_flags = NULL;		/*status of the "-X" flag*/
static bool noobj_flag = FALSE;		/*status of the "-Hnoobj" 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*/
#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*/
#ifdef AMD
static bool bw_flag = FALSE;		/*"-bw" flag for AMD: byte-write*/
#endif
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*/
static bool anno_flag = FALSE;		/*status of "-Hasm" flag*/
static bool pcc_flag = FALSE;		/*status of "pcc" flag*/
static bool default_pro_flag = TRUE;	/*Use default hc.pro? */
#if !CPP_ONLY
static bool cpp_flag = FALSE;  /*Invoke CPP prior to compilation for C?*/
static bool nocpp_flag = FALSE; /*Suppress CPP prior to compilation? */
#endif
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 *color_threshold;		/*% of spills relative to total
					reg references before resorting to
					dynamic allocation*/
static char **cstart_ptr;		/*Ptr in ldargs where crt0.o is*/
static char *Bstring = NULL;		/*-Bstring*/

#ifdef MC68020
static bool f68881_flag = FALSE;	/* -f68881 flag */
static bool fsoft_flag = FALSE;		/* -fsoft flag*/
#endif
#ifdef iAPX386
static bool f387_flag = FALSE;
static bool f1167_flag = FALSE;
#endif
static bool cpp_invoked = FALSE;

static char *var_file = NULL;
static char *IL1_file = NULL;	/*IL from front-end*/
static char *tree_file = NULL;	/*tree*/
static char *IL2_file = NULL;	/*IL in back-end*/
static char *temp_file = NULL;	/*Name of temp file written by cpp*/
static char *xref_file = NULL;   /* Name of temp file written by xref */
static char *hc2tmp_file = NULL; /*Temp file required by optimizer*/
static char *obj_tmp_file = NULL;/*Name of temp file containing object module*/
static char *S_file = NULL;	/*where .s is written */

static char *machine_name = TARGET_MACHINE_NAME;

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 for NONDOS
 */
#ifndef MSDOS 
extern void exit();
extern void perror();
extern void execv();
extern void psignal();
extern void unlink();
extern char *mktemp();
# ifdef MC68020
extern char *getenv();
# endif
#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)];
#ifndef MSDOS    	
	while (--p >= path && *p != '/');
#else	
        while (--p >= path && *p != '/' && *p != '\\' && *p != ':');
#endif        
	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 (hc2tmp_file != NULL) unlink(hc2tmp_file);
    if (obj_tmp_file != NULL) unlink(obj_tmp_file);
    if (var_file != NULL && !noobj_flag) unlink(var_file);
    if (IL1_file != NULL && !noobj_flag) unlink(IL1_file);
    if (IL2_file != NULL) unlink(IL2_file);
    if (S_file != NULL) unlink(S_file);
    /*Don't terminate if not error. May have been called by cross referencer*/
    if (retcode != 0)	 {
	if (xref_file != NULL) unlink(xref_file);
        exit(retcode);
	}
}

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

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

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

static 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);
}

static 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);
}


#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

#ifdef MSDOS

char parameter_string[130],prog_name[65];

static int execute()
{
  static char dirname[64] = "\0";
  int t;
  char pname[80];
  char *path,*p,*bpname;
  
  errno = No_error_occurred;
  t = c_exec(prog_name,parameter_string);  
  if (errno == No_error_occurred)
    return(0);
  bpname = basename(prog_name);  
  pname[0]='\0';
  if (dirname[0] != '\0')
    {
      sprintf(pname,"%s/%s",dirname,bpname);
#ifdef DEBUG         
      printf("\n%s/%s",dirname,bpname);
#endif         
      errno = No_error_occurred;
      t = c_exec(pname,parameter_string);  
    }  
  if (t)
    {  
      p = getenv("PATH");
      while ((t) && (*p))
       {
       	 path = p;
         p = strpbrk(p,";"); 
         *p = '\0';
         strcpy(dirname,path);
         *p++ = ';';
         sprintf(pname,"%s/%s",dirname,bpname);
#ifdef DEBUG         
         printf("\n%s/%s",dirname,bpname);
#endif   
         errno = No_error_occurred;
         t = c_exec(pname,parameter_string); 
       }  
    } 
  return(t);	
}


static char *tmppath( name_buf )
	char	*name_buf;
{
	char	type[ 4 ], *cp;
	strncpy( type, name_buf, 3 );
	if ((cp = getenv( TMP_ENVNAME )) != NULL)
	{
		strcpy( name_buf, cp );
		cp = name_buf + strlen( cp );
		*cp++ = '/';
	}
	else
		cp = name_buf;
	strncpy( cp, type, 3 );
	strcpy( cp + 3, ".tmp" );
	return( name_buf );
}


  
static int spawnp(char *f, char *av[])
{
  char **p;
  static char *fn=NULL;
  FILE *fp;
  int len=0,t;
  bool too_big = FALSE;
  
  parameter_string[0] = '\0';
#ifdef DEBUG  
  printf("f = %s\n",av[0]);
#endif  
        
  p = &av[1];
  while (*p)
    {
      len += strlen(*p++)+1;
      if (len > 129)
        {
          too_big = TRUE;
          break;
        } 
    }
  --len;
  
  if (too_big)
    {
  	p = &av[1];
	if (fn == NULL)
	    fn = tmppath( "@arg                                " + 1 );
	fp = fopen( fn, "w" );
	while (*++p)
	 {
#ifdef DEBUG	 	
	   printf("%s\n",*p);	
#endif	   
	   fprintf( fp, "%s\n", *p);
	 }  
	fflush(fp);  
	fclose( fp );
        len = strlen(av[1]) + strlen(fn)+ 1 +1;
        parameter_string[0] = len;	
        parameter_string[1] = '\0';	
        sprintf(&parameter_string[1],"%s ",av[1]);     
        len = strlen(parameter_string);	
        sprintf(&parameter_string[len],"%s",(char *)(fn-1));	
    }
  else
    {
       p = &av[1];
  
       parameter_string[0] = len;	
       parameter_string[1] = '\0';	
  
       while (*p)
         {
           len = strlen(parameter_string);	
           sprintf(&parameter_string[len],"%s",*p++);	
           if (*p)
             strcat(parameter_string," ");
         } 
     }

   len = strlen(parameter_string);	
   sprintf(&parameter_string[len],"\n");
#ifdef DEBUG   
   printf("%x%s",parameter_string[0],&parameter_string[1]);
#endif   
  
  sprintf(prog_name,"%s.exe",f);
  /*t = c_exec(prog_name,parameter_string); */
  t = execute();
  	
  if (too_big)
    unlink(fn);  
   
  return(t);  
}

/*
 * Invoke a command
 */
int command(f,av)
    char *f; char *av[];
{
    int t;
    char **p;
    
    if (verbose==TRUE){
	fprintf(stderr,f);
	p = &av[0];
	while (*++p != 0){
	    fprintf(stderr," %s",*p);
	    }
	fprintf(stderr,"\n");
	}
    t = spawnp( f, av );
    return( t );
}

#else /*unix: */

/*
 * Invoke a command
 */
int command(f,av)
   char *f; char *av[];
{
    int t;
    union wait status;
    if ((t=fork())==0){
	if (verbose){
	    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 );
}
#endif


/*
 * Invoke assembler
 */
static int assemble(f,obj)
   char *f;	/*Name of source file*/
   char *obj;  /*Name of object*/
{
#ifdef AS
    char **ap = av;
    *ap++ = AS;
# ifdef MSDOS    
    *ap++ = "-wso";
# else
    *ap++ = "-o";
# endif    
    *ap++ = obj;
    if (R_flag){
        *ap++ = "-R";
        }
#   ifdef ASMFLAG1
        *ap++ = ASMFLAG1;
#   endif
#   ifdef ASMFLAG2
        *ap++ = ASMFLAG2;
#   endif
    *ap++ = f;
    *ap++ = 0;
    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
}

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 MSDOS
    if ((*opt == '"') && (opt[strlen(opt)-1] == '"'))
      {
      	opt[strlen(opt)-1] = '\0';
        opt++;
      }  
#endif
#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;
{
#ifndef MSDOS	
    if (cppcnt >= MAXCPP)
	severe("Too many cpp options");
    cppargs[cppcnt++] = opt;
#endif    
}

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++;
}
/*
 *  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]=='-'){		/*Options prefixed with "-" */
	    /*
	     *  Options that begin with 'H' are assume to be compiler-specific
	     *  options. 
	     */
	    if (parg[1]=='H' && parg[2] != '\0'){
		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;
		    case 'm':
			if(strcmp(parg+2,"make")==0)
			    nocpp_flag = TRUE;
			break;
		    default: 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||
			    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;              /** MAY CHANGE per MSDOS **/
                        else if (strcmp("asm",parg+2)==0)
			    {
			    anno_flag = TRUE;
			    add_popt(ON);
			    add_popt("ASM");
			    add_arg = FALSE;
			    }
			else if (strcmp("anno",parg+2)==0)
			    {
			    anno_flag = TRUE;
			    add_arg = FALSE;
			    }
			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;
			    }
#ifdef AMD
			else if (strcmp("large",parg+2)==0){
			    machine_name = "amd";
			    add_arg = FALSE;
			    }
#endif
			break;

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

		    case 'c':
			if(strcmp("cheap",parg+2)==0){  /*cheap? */
#ifdef MSDOS				
			    cheap = TRUE;
#endif			    
			    add_arg = FALSE;
			    }
		
#if !CPP_ONLY
			else if (strcmp("cpp",parg+2)==0){	/* cpp? */
# ifdef MSDOS
                            fprintf( stderr, "-cpp: (warning) Outboard "
 	       	                     "C preproccessor not available\n" );
# else
			    cpp_flag = TRUE;
# endif			    
			    add_arg = FALSE;
			    }
#endif
			else if (strncmp("color=",parg+2,6)==0){
			    color_threshold = parg+8;
			    add_arg = FALSE;
			    }
			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;
			    noobj_flag = TRUE;
                            add_arg = FALSE;
#ifdef MSDOS
			    var_file = "nul";
			    IL1_file = "nul";
#else
			    var_file = "/dev/null";
			    IL1_file = "/dev/null";
#endif
			    }
			else

			if (strcmp("nopro",parg+2)==0) /*Suppress hc.pro*/
			    default_pro_flag = FALSE;
			break;
#ifdef RT
		    case 'v':
			/* -Hvolatile  -- kill all pointer dereferences
			   between statement boundaries. This is done
			   by turning on "KILL_DEREFS" toggle for now.
			*/
			if (strcmp("volatile",parg+2)==0){
			    add_popt(ON);
			    add_popt("VOLATILE_POINTERS");
			    add_arg = FALSE;
			    }
			break;
#endif
		    case 's':
			if (strncmp("suffix=",parg+2,7)==0){ /* -Hsuffix=*/
			    object_suffix=parg+9;
			    add_arg = FALSE;
			    }
#ifdef AMD
			else if (strcmp("small",parg+2)==0){
			    machine_name = "amds";
			    add_arg = FALSE;
			    }
#endif
			break;
		    case '+':
			if (strcmp("+w",parg+2)==0){
			    add_arg = FALSE;
			    W_flag = TRUE;
			    }
			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':
			Bstring = &parg[2];
			assume_ld_option = FALSE;
			break;
#ifdef AMD
		    case 'b':
			if (strcmp(parg,"-bw")==0){
			    bw_flag = TRUE;
			    assume_ld_option = FALSE;
			    }
			break;
#endif
		    case 'p':
			if (strcmp(parg,"-pg")==0){
#ifdef MSDOS
    	                    fprintf(stderr,"Warning: %s is unrecognized\n",
				        parg);
#else
			    pg_flag = TRUE;
			    assume_ld_option = FALSE;
#endif			    
			    }
			break;
#if (!defined(MSDOS)) && defined(MLIB)
		    case 'l':
			/*
			 * Intercept "-lm" and replace with our own
			 * ANSI math library
			 */
			if (strcmp(parg,"-lm")==0)
			    parg = MLIB;
			break;
#endif
		    case 'X':
			X_flags = parg;
			assume_ld_option = FALSE;
			break;
		    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;
			    }
			break;
#ifdef RT
		    case 'f':
			assume_ld_option = FALSE;
			if(strcmp(parg,"-fsoft")==0){
			    machine_name = "rt";
			    }
			else if (strcmp(parg,"-frtfl")==0){
			    machine_name = "rtfl";
			    }
			else if (strcmp(parg,"-fsingle")==0){
			    f_flag = TRUE;
			    }
			else
			    fprintf(stderr,"Warning: %s is unrecognized\n",
					parg);
			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;
			    }
                        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;
			    }
			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);
		          }
		       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

#ifdef AMD
		    case 'M':
			if (parg[2] == 's')
			  {
			    machine_name = "amds";
			  }  
			else if (parg[2] == 'l')
			    machine_name = "amd";
			else
			    fprintf(stderr,"Warning: %s is unrecognized\n",
					parg);
			assume_ld_option = FALSE;
			break;
#endif
		    case 'U': 
		        add_cppopt(parg);
			assume_ld_option = FALSE;
#if !CPP_ONLY			
			if (!cpp_to_be_invoked)
                          {	
			    add_popt("-undef");
			    add_popt(parg+2);
			    }
#endif			 
			break;
		    case 'D':{
			char *p;
			assume_ld_option = FALSE;
			
			add_cppopt(parg);
#if !CPP_ONLY
			if (!cpp_to_be_invoked){
#  ifndef MSDOS				
			    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));
				}
#  else
                            char buf[80];                        
		                                                 
		            add_popt("-define");                 
		            buf[0] = '"';                        
		            buf[1] = '\0';                       
		            strncat_(buf,&parg[2],sizeof buf);   
		            if ((p = strchr( buf, '=' )) != NULL)
		                *p = ' ';                        
		            else                                 
		                strncat_(buf," 1",sizeof buf);   
		            strncat_(buf,"\"",sizeof buf);       
		            add_popt(copy(buf));                 
#  endif						
			    }
			}
#endif
			break;
		    case 'I': 
			assume_ld_option = FALSE;
			add_cppopt(parg);
#if !CPP_ONLY 
			if(!cpp_to_be_invoked){
			    add_popt("-dir");
			    add_popt(parg+2);
			    }
#endif
			break;
		    }
		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 'W': W_flag = TRUE; break;
		    case 'f': f_flag = TRUE; break;
#ifdef I386
		    case 'B':
			B_flag = TRUE;
			break;
#endif
		    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){
	    W_flag = TRUE;
	    }
	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;
#ifdef CSTART
	    if (filecnt==0){
		cstart_ptr = ldargs+ldargcnt;
		add_ldarg(CSTART);
		}
#endif
	    add_ldarg(objp); 	/*add object file to LD list*/
	    filecnt++;
	    }
	}
#ifdef HCPRO
    if (default_pro_flag) {	/*No -Hnopro or -Hpro= specified */
	add_popt("-pro");
	add_popt(HCPRO);
    }
#endif 

#ifdef MC68020
   if (!f68881_flag && !fsoft_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;
       }
#endif
}    /*process_arguments*/

/*
 * Initialize
 */
void initialize()
{
#ifdef MSDOS
   char *cp;
#endif
   	
#ifndef MSDOS   
   catch(SIGINT);		/*Intercept interrupt*/
   catch(SIGHUP);		/*Intercept hangup*/
#endif   
   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
#ifdef START
   add_ldarg("-e");
   add_ldarg(START);
#endif
#ifdef MSDOS
#  ifdef CSTART
#    ifdef LIBRARY_ENVNAME
    if ((cp = getenv( LIBRARY_ENVNAME )) != NULL)
    {
    	    static char lbuf[128];
	    strcpy( lbuf, cp );
	    cp = lbuf + strlen( cp );
	    if (cp[ -1 ] != '/' && cp[ -1 ] != '\\')
		    *cp++ = '/';
	    strcpy( cp, CSTART );
	    add_ldarg( lbuf );
    }
    else
	    add_ldarg( CSTART );
#    else
     add_ldarg( LIBRARY_DIR CSTART );
#    endif
#  endif
#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*/
{
#ifndef MSDOS 
    int i = 0;
    char **avp = av;
#ifdef INCLUDE_DIR1
    char Ibuf1[sizeof(INCLUDE_DIR1)+3];
#endif
#ifdef INCLUDE_DIR2
    char Ibuf2[sizeof(INCLUDE_DIR2)+3];
#endif
    *avp++ = CPP;
    /*
     * Define certain constant for cross compiling
     */
    if (strcmp(TARGET_MACHINE_NAME,"amd")==0){
	*avp++ = "-D_AM29K";
	*avp++ = "-D_AM29000";
#ifdef mc68000
	*avp++ = "-Um68k";
	*avp++ = "-Umc68000";
	*avp++ = "-Usun";
#endif
#ifdef vax
	*avp++ = "-Uvax";
#endif
	}
    else if (strcmp(TARGET_MACHINE_NAME,"rt")==0)
	*avp++ = "-Dibm032";

    while (i < cppcnt)
	*avp++ = cppargs[i++];
#ifdef INCLUDE_DIR1
    strcpy(Ibuf1,"-I");
    strcpy(Ibuf1+2,INCLUDE_DIR1);
    *avp++ = Ibuf1;
#endif
#ifdef INCLUDE_DIR2
    /*
     * 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;
	}
#endif
    if (M_flag)
	*avp++ = "-M";
    if (!pcc_flag) {
	*avp++ = "-D__STDC__";
	if (!ansi_flag)
	    *avp++ = "-D__HIGHC__";
    }
    *avp++ = input;
    *avp++ = output;  /*May be null, which indicates standard output*/
    *avp = 0;
    return command(av[0],av);
#else
    return(0);    
#endif
}

/*
 * Compute name of ansi tables
 */
#ifndef MSDOS
#    define ansi_tables(tables) tables
#else
static char *ansi_tables(char *tables)
    {
    char *cp;
    if (*tables == '/' || *tables == '\\')
	return tables;
    cp = NULL;
#   ifdef INCLUDE_DIR2
        cp = INCLUDE_DIR2;
#   endif
#   ifdef INCLUDE_ENVNAME
	cp = getenv( INCLUDE_ENVNAME );
#   endif
    if (cp != NULL) {
	static char lbuf[60];
	strncpy( lbuf, cp,sizeof lbuf );
	cp = lbuf + strlen( cp );
	if (cp[ -1 ] != '/' && cp[ -1 ] != '\\')
	    *cp++ = '/';
	strcpy( cp, tables );
	return lbuf;
        }
    return tables;
    }
#endif

/*
 * Invoke skeleton
 */

int invoke_skeleton(f,tree,ilfile,varfile)
    char *f;	/*Source file name*/
    char *tree;  /*Tree file*/
    char *ilfile;	/*IL file (non development mode only)*/
    char *varfile;	/*auxiliary file (non development mode only)*/
{
    register int i = 0;	/*index into popts array*/
    register char **avp = av+1;
    static char *cp;
    static bool copyright_displayed = FALSE;
    *avp++ = f;
    *avp++ = "-efile";   /*Direct messages to std output*/
#ifdef MSDOS
    *avp++ = "@";	/* "@E" for stderr*/
#else
    *avp++ = "@E";	/* "@E" for stderr*/
#endif
    *avp++ = "-silent";   /* Suppress all messages except diagnostics */
    if (w_flag){
        *avp++ = OFF;
        *avp++ = "warn";
        }
    if (R_flag){
	*avp++ = ON;
	*avp++ = "READ_ONLY_STRINGS";
	}
	
#ifdef CHAR_DEFAULT_UNSIGNED
    *avp++ = CHAR_DEFAULT_UNSIGNED;
    *avp++ = "CHAR_DEFAULT_UNSIGNED";
#endif

    if (f_flag){
	*avp++ = OFF;
	*avp++ = "DOUBLE_MATH_ONLY";
	}
#ifdef DOUBLE_MATH_ONLY
    else{
	*avp++ = DOUBLE_MATH_ONLY;
	*avp++ = "DOUBLE_MATH_ONLY";
	}
#endif

#ifdef DOUBLE_RETURN
    *avp++ = DOUBLE_RETURN;
    *avp++ = "DOUBLE_RETURN";
#endif

    if (pcc_flag){	/*Under PCC enums are like int*/
	*avp++ = ON;
	*avp++ = "LONG_ENUMS";
	}
#  ifdef LONG_ENUMS
    else{
	*avp++ = LONG_ENUMS;
	*avp++ = "LONG_ENUMS";
	}
#  endif

    if (pcc_flag){	/*If pcc flag, then turn on PCC toggle*/
	*avp++ = ON;
	*avp++ = "PCC";
	}
#ifdef PCC
    else{
	*avp++ = PCC;
	*avp++ = "PCC";
	}
#endif

    if (W_flag){
	*avp++ = OFF;
	*avp++ = "PCC_MSGS";
	}
#ifdef PCC_MSGS
    else{
	*avp++ = PCC_MSGS;
	*avp++ = "PCC_MSGS";
	}
#endif

#ifdef DEVMODE
    *avp++ = "-tree";
    *avp++ = tree;
#endif
    if (make_flag)
        *avp++ = "-make";
#ifndef DEVMODE
    *avp++ = "-ofile";
    *avp++ = ilfile;
    *avp++ = "-vfile";
    *avp++ = varfile;
    /*
     * Identify target machine
     */
    *avp++ = "-machine";
    *avp++ = machine_name;

    if (g_flag)
	*avp++ = "-g";

#ifdef DEFINE_STRING
    if (!cpp_flag){
	*avp++ = "-define";
	*avp++ = DEFINE_STRING;
	}
#endif

#ifdef DEFINE_STRING1
    if (!cpp_flag){
	*avp++ = "-define";
	*avp++ = DEFINE_STRING1;
	}
#endif

#ifdef DEFINE_STRING2
    if (!cpp_flag){
	*avp++ = "-define";
	*avp++ = DEFINE_STRING2;
	}
#endif

    if (E_flag){
	*avp++ = "-ppo";
	*avp++ = "@";
	}

#endif
    while (i<poptcnt)
        *avp++ = popts[i++];

#if defined IBM
    if (verbose)
#endif
    if (!copyright_displayed){
	*avp++ = "-copyr";
	copyright_displayed = TRUE;
	}
    if (ansi_flag){
	*avp++ = "-st";
	*avp++ = ansi_tables(HCANSIST);
	*avp++ = "-pt";
	*avp++ = ansi_tables(HCANSIPT);
	*avp++ = "-spt";
	*avp++ = ansi_tables(HCANSIPPT);
	}

#ifdef INCLUDE_DIR1
     *avp++ = "-dir";
    *avp++ = INCLUDE_DIR1;
#endif

#ifdef INCLUDE_DIR2
    *avp++ = "-dir";
    *avp++ = INCLUDE_DIR2;
#else
    *avp++ = "-dir";
    if ((*avp++ = getenv( INCLUDE_ENVNAME )) == NULL)
      avp -= 2;    
#endif
    *avp++ = 0;
    {
	char hc1com_name[100];
	if (Bstring){
	    strncpy(hc1com_name,Bstring,sizeof hc1com_name);
	    strncat_(hc1com_name,"hc1com",sizeof hc1com_name);
	    av[0] = hc1com_name;
	    }
	else
	    av[0] = HC1COM;
	return(command(av[0],av));
    }
}

#ifdef DEVMODE
static int invoke_pass1(tree_file,il_file,var_file)
    char *tree_file;	 /*Tree file in development mode*/
    char *il_file;
    char *var_file;
    {
    char **avp = av;
    int i = 0;
    *avp++ = HC1;
    *avp++ = tree_file;
    *avp++ = "-ofile";
    *avp++ = il_file;
    *avp++ = "-vfile";
    *avp++ = var_file;
    *avp++ = "-X4";    /*Causes 32-bit arithmetic to be the default*/
    if (g_flag)
	*avp++ = "-g";

    if (w_flag){
	*avp++ = OFF;
	*avp++ = "warn";
	}
    *avp++ = 0;
    return command(av[0],av);
    }
#endif

static int invoke_pass2(IL1_file,var_file,S_file,tmp_file,anno,obj_file)
    char *IL1_file;
    char *S_file,*var_file,*tmp_file;
    char *anno;
    char *obj_file;
    {
    char **avp = av;
    int i = 0;
    char hc2com_name[100];
    if (Bstring){
	strncpy(hc2com_name,Bstring,sizeof hc2com_name);
	strncat_(hc2com_name,"hc2com",sizeof hc2com_name);
	*avp = hc2com_name;
	}
    else
	*avp = HC2COM;
    avp++;
    *avp++ = "-i";  *avp++ = IL1_file;
    *avp++ = "-V";  *avp++ = var_file;
    *avp++ = "-s";  *avp++ = anno;
    /* Only pass toggles*/
    while (i<poptcnt){
	if (strcmp(popts[i],"-on")==0 || strcmp(popts[i],"-off")==0){
	    *avp++ = popts[i++];
	    *avp++ = popts[i];
	    }
	i++;
	}
#ifndef MSDOS
    if (p_flag || pg_flag)
	*avp++ = "-p";
#endif	
    if (!S_flag && B_flag){
	*avp++ = "-B";
	*avp++ = obj_file;
	}
    else {
	*avp++ = "-S";
	if (S_flag){
	    *avp++ = alter_suffix(anno,"s");
	    if (anno_flag)
		*avp++ = "-a";
	    }
	else
	    *avp++ = S_file;
	}
    if (g_flag)
	*avp++ = "-g";
    if (w_flag)
	*avp++ = "-w";
#ifndef MSDOS
    *avp++ = "-e";	/*Send diagnostics to stderr*/
#endif
    if (O_flag) 
	*avp++ = "-O";
#ifdef AMD
    if (bw_flag)
	*avp++ = "-Xb";
#endif
    *avp++ = "-T";
    *avp++ = tmp_file;

    if (color_threshold){
	*avp++ = "-color";
	*avp++ = color_threshold;
	}
     
    if (X_flags)
	*avp++ = X_flags;
    *avp++ = 0;
    return command(av[0],av);
    }
/*
 * Do compilations and assembly
 */
static 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 (M_flag)
 	    retcode = invoke_cpp(f,NULL);
        else{
	    char *source = f;
	    if (srccnt>1) fprintf(stderr,"%s:\n",f);
	    /*
	     * If cpp to be invoked prior to compilation, then doit here
	     */
#ifndef MSDOS	     
#  if !CPP_ONLY
	    if (!make_flag && 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 (!make_flag && (HIGH_C && c=='c' || c=='p'))
#  endif
	        {
		if (temp_file == NULL && !E_flag)
		    /*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;
		}
#else	
  retcode = 0;
  cpp_invoked = FALSE;
#endif	
	    /*
	     * Invoke compiler or assembler.
	     */
	    if (retcode == 0 && (!E_flag || !cpp_invoked))
		if (c == 'p'){
		    fprintf(stderr,"Warning: can't compile Pascal files.\n");
		    }
		else if (c == 's'){
		    if (!S_flag)
		       retcode = assemble(source,objp);
		    else
		       retcode = 0;
		    }
		else if (c == 'c'){
#ifdef MSDOS
  	            if (tree_file == NULL)
		      tree_file = tmppath("tre                                ");
	            if (IL1_file == NULL)
		      IL1_file = tmppath("IL1                                ");
	            if (var_file == NULL)
		      var_file = tmppath("var                                ");
#else		
		    if (tree_file == NULL)
			tree_file = mktemp("/tmp/treeXXXXXX");
		    if (IL1_file == NULL)
			IL1_file = mktemp("/tmp/IL1XXXXXX");
		    if (var_file == NULL)
			var_file = mktemp("/tmp/varXXXXXX");
#endif			
		    retcode = invoke_skeleton(source,tree_file,IL1_file,var_file);
#ifdef DEVMODE
		    if (retcode == 0 && !make_flag){
			retcode = invoke_pass1(tree_file,IL1_file,var_file);
			unlink(tree_file);
			}
#endif
		    if (retcode == 0 && !make_flag && !E_flag && !noobj_flag){
#ifdef MSDOS
		        if (IL2_file == NULL)
			  IL2_file = tmppath("IL2                             ");
		        if (S_file == NULL)
			  S_file = tmppath("SXX                             ");
		        if (hc2tmp_file == NULL)
			  hc2tmp_file = tmppath("HC2                             ");
#else		    	
			if (IL2_file == NULL)
			    IL2_file = mktemp("/tmp/IL2XXXXXX");
			if (S_file == NULL)
			    S_file = mktemp("/tmp/SXXXXXX");
			if (hc2tmp_file == NULL)
			    hc2tmp_file = mktemp("/tmp/HC2XXXXXX");
#endif			    
			retcode = invoke_pass2(IL1_file,var_file,S_file,
						    hc2tmp_file,f,objp);
			if (retcode==0 && !S_flag && !B_flag)
			    retcode = assemble(S_file,objp);
			}
		    }
	    }
        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 LD
static int do_link()
{
#  ifdef MSDOS
   char *cp;
#  endif

   if (PP_command){
   	
#if defined CHEAP && defined PHEAP 
       if (cheap==TRUE)
	   add_ldarg(CHEAP);
       else
	   add_ldarg(PHEAP);
#endif
#   ifdef PPLIB
#      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
#   endif
       }
#if defined(PROFSTART)
   if (p_flag)
       *cstart_ptr = PROFSTART;
   else
#endif
#if defined(GPROFSTART)
   if (pg_flag)
       *cstart_ptr = GPROFSTART;
#endif
/*
 * Add optional libraries.
 */
#ifdef LIB1
   add_ldarg(LIB1);
#endif
#ifdef LIB2
   add_ldarg(LIB2);
#endif
#ifdef LIB3
   add_ldarg(LIB3);
#endif
/* if (g_flag)
       add_ldarg("-lg");*/
#  if defined(CLIB_P)
	if (p_flag||pg_flag) {
#    ifdef RT
	    add_ldarg(FPLIB_P);
#    endif
	    add_ldarg(CLIB_P);
	 }
	else
	    add_ldarg(CLIB);
#  endif

#if !defined(MSDOS) && (!defined(CLIB_P))       
#  if defined(CLIB)
       add_ldarg(CLIB);
#  else
       add_ldarg(p_flag||pg_flag?"-lc_p":"-lc");
#  endif
#else
#  ifdef MSDOS
#    ifdef LIBRARY_ENVNAME
	if ((cp = getenv( LIBRARY_ENVNAME )) != NULL)
	{
		static char lbuf[128];
		strcpy( lbuf, cp );
		cp = lbuf + strlen( cp );
		if (cp[ -1 ] != '/' && cp[ -1 ] != '\\')
			*cp++ = '/';
		strcpy( cp, CLIB );
		add_ldarg( lbuf );
	}
	else
		add_ldarg( CLIB );
#    else
       add_ldarg(LIBRARY_DIR CLIB);
#    endif
#  endif
#endif

#ifdef MWLIB
#  ifdef iAPX286
   add_ldarg(m_MWLIB[cbug(Memory_model)]);
#  else           
   add_ldarg(MWLIB);
#  endif
#endif

#ifdef CLIB2
   add_ldarg(CLIB2);
#endif
#if defined(iAPX286)
   add_ldarg("-la");	/* For lmul, ldiv, etc., from C library. */
#endif           
   add_ldarg((char *) 0);
   return( command(LD,ldargs) );
}
#endif

static int compile_in_xref_mode(argc, argv,cpp)
    int argc;
    char **argv;
    int cpp;
    {
    int rc;
    char **ap = (char **)malloc((argc+10)*sizeof(*ap));
    char **p;
    if (ap==0) {
	fprintf(stderr,"malloc failed");
	terminate(1);
	}
    memcpy(ap+1,argv,argc*sizeof(*argv));
    *ap = HC;
    argc++;
    p = ap+argc;
    *p++ = Hxref;
    *p++ = "-Hxcat";
    *p++ = "-Hnoobj";
    *p++ = "-c";
    *p++ = "-w";
    argc +=5;
#ifndef MSDOS    
    *p++ = cpp?"-Hcpp":"-Hnocpp";
    argc++;
#endif    
    *p = 0;
    
    rc = main(argc,ap);
    free(ap);
    return(rc);
    }

static int xref(argv)
    char **argv;
    {
    *argv = XREF;
    return command(XREF,argv);
    }

static int process_xref(argc, argv)
    int argc;
    char *argv[];
{
   int i,rc;	
   char i_flag = 0, l_flag=0, m_flag=0, u_flag=0, s_flag=0, p_flag=0;
#ifndef MSDOS
   static char *template = Hxref+7;
#else
   strcpy(Hxref,"-Hxref=");
#endif    
   for (i=1; i<argc; i++){
	char *p = argv[i];
	if (*p=='-' && p[1]>='a' && p[1]<='z'){
	    while(*++p){
		switch(*p){
		    case 'i': i_flag=1; break;
		    case 'l': l_flag=1; break;
		    case 'm': m_flag=1; break;
		    case 'u': u_flag=1; break;
		    case 's': s_flag=1; break;
		    case 'v': verbose=1; break;
		    case 'p': p_flag=1; break;
		    default:
			fprintf(stderr,"Invalid option flag: %c\n",*p);
			exit(1);
			break;
		    }
		}
	    }
	else{
#ifndef MSDOS	    
	    xref_file = mktemp(template);
#else
            xref_file = tmppath("xrf                             ");
            strncat_(&Hxref[7],xref_file,strlen(xref_file));
#endif	    
	    rc = compile_in_xref_mode(argc-i,&argv[i],p_flag);
	    if (rc == 0){
		char *ap[14];
		char **cp = &ap[1];
		*cp++ = xref_file;
		if (i_flag){
		    *cp++ = ON;
		    *cp++ = "ANNOTATE_INCLUDES";
		    }
		if (l_flag && !p_flag){
		    *cp++ = ON;
		    *cp++ = "ANNOTATED_LISTING";
		    }
		if (m_flag){
		    *cp++ = ON;
		    *cp++ = "LIST_MODULE_USAGE";
		    }
		if (u_flag){
		    *cp++ = ON;
		    *cp++ = "LIST_UNUSED_INCLUDES";
		    }
		if (s_flag){
		    *cp++ = ON;
		    *cp++ = "STATISTICS";
		    }
		*cp = 0;
		rc = xref(ap);
		}
	    }
   }
   if (xref_file != NULL) {
       unlink(xref_file);
       xref_file = 0;
       }
   return(rc);
   
}

static bool is_xref_command(cstr)
    char *cstr;
{
  char *p=cstr;
  
#ifdef MSDOS  
  int i;
#define LEN 8

  for (i=strlen(p)-LEN; (i<strlen(p)); i++)
    if (isupper(p[i]))
      p[i] = tolower(p[i]);
  return(strcmp(&p[strlen(p)-LEN],"xref.exe") ==0);
#else
  return(strcmp(&p[strlen(p)-4],"xref")==0);
#endif
}

/*
 * MAIN
 */
int main(argc,argv)
   int argc; char *argv[];
{
    int retcode;
    bool xref = FALSE;
    
    command_name = argv[0];
    xref = is_xref_command(command_name);
       
    initialize();
    if (xref) 
      if (argc <= 1){
    	fprintf(stderr,"%s [-ilmpus] files...\n",command_name);
	fprintf(stderr,"where\tl:\tannotates listing; not allowed with `p';\n");
	fprintf(stderr,"\ti:\tannotates include files, also;\n");
	fprintf(stderr,"\tm:\tlists module usage;\n");
	fprintf(stderr,"\tp:\tuse the outboard C preprocessor on source files;\n");
	fprintf(stderr,"\tu:\tlists unused include files;\n");
	fprintf(stderr,"\ts:\tprints statistics.\n");
	exit(1);
	}
      else
        retcode = process_xref(argc,argv);
    else {
        process_arguments(argc,argv);
#ifdef iAPX286                                                             
        replace_CSTART();                                                      
#endif                                                                     
        if (filecnt==0){                                                       
            fprintf(stderr,"%s: No files specified.\n",command_name);          
            exit(0);                                                           
           }                                                                  
        if (srccnt==0 && (S_flag || c_flag || M_flag || E_flag)){              
              fprintf(stderr,"No source files specified.\n",command_name);       
              exit(1);                                                           
             }                                                                  
        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);
    return(retcode);
}
