/*
 * mimosa.c - front end for Mesa/Cedar compiler
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/dir.h>

#include "compServer.h"
#include "compServerDefs.h"

extern long     time();  /* why is this not in time.h? */
extern int	putenv();

static void     ParseCommandLine();
static void     CompileFile();
	
typedef struct {
	char *on;  /* this is the corresponding cedar value switch when ON */
	char *off; /* this is the corresponding cedar value switch when OFF */
} cedarSwitch;

/*
 * this array contains the equivalent cedar (mimosa) switches for the
 * SSU frontend switches.
 */
cedarSwitch mimosaArgArray[] = {
	{ "a", "~a" },     /* a */
	{ "~b", "b" },     /* b */
	{ "",  ""   },     /* c */
	{ "",  ""   },     /* d */
	{ "e", "~e" },     /* e */
	{ "~h", "h" },     /* f */
	{ "",  ""   },     /* g */
	{ "",  ""   },     /* h */
	{ "",  ""   },     /* i */
	{ "",  ""   },     /* j */
	{ "",  ""   },     /* k */
	{ "c", "~c" },     /* l */
	{ "m", "~m" },     /* m */
	{ "~n", "n" },     /* n */
	{ "",   ""  },     /* o */
	{ "p", "~p" },     /* p */
	{ "Xk",  "" },     /* q */
	{ "%%", "~%%" },   /* r */
	{ "",  ""   },     /* s */
	{ "",  ""   },     /* t */
	{ "~u", "u" },     /* u */
	{ "",  ""   },     /* v */
	{ "~w", "w"  },    /* w */
	{ "",   ""  },     /* x */
	{ "",   ""  },     /* y */
	{ "a", "~a" },     /* z */
	{ "p", "~p" },     /* pw */
	{ "XK",  "" },     /* Q */
	{  "",   "" },     /* zcirio */
	{ "k", "~k" }      /* si - smaller installation code */
	/* if you add another additional switches, update compServerDefs.h
	   Switches enumeration and up size of typedef SwitchesArray in 
	   compServer.h */
};
	
main(argc, argv)
int             argc;
char          **argv;
{
    int     temp = 0;
    Handle  h = NewHandle(argc, argv); /* defaults all switches FALSE */

    h->job.jobKind = compile;
	
    /* parse the command line: */
    ParseCommandLine(h);
	
    /* start the global timer: */
    h->startTime = time((long *) NULL);
	
    /* for each source file, do the compilation: */
    for (temp = 0; temp < h->nJobs; temp++) {
	h->job.shortFileName = h->jobList[temp];
	CompileFile(h);
	PutS("\n");
    }
	
    /* get the finish time: */
    h->finishTime = time((long *) NULL);
	
    /* report finish time: */
    if (!isSwitchSet(h, (Switches)'t')) {
	PutS("mimosa: seconds: ");
	PutLong(h->finishTime - h->startTime);
	PutS("\n");
    }
    /* free handle and contents */
    FreeHandle(h);
    ExitSuccessfully();
    /*NOTREACHED*/
}
	
static void PrintHelp()
	{
	PutS("mimosa: (see also \"man mimosa\")\n");
	PutS("usage: mimosa [options] fileList\n");
	PutS("options: \n");
	PutS("\t-a\taccumulate execution data\n");
	PutS("\t-b\tturn off bounds checking\n");
	PutS("\t-c\tjust produce .c file\n");
	PutS("\t-d\tshow (but don't execute) commands\n");
	PutS("\t-e\tuse external initialization code\n");
	PutS("\t-f\tgenerate old style signal catch code\n");
	PutS("\t-g\tdon't produce dbx symbol tables\n");
	PutS("\t-h\tprint this help message\n");
	PutS("\t-i\tsimulate dryrun of an interface (used with -d)\n");
	PutS("\t-j\tfinish the mimosa compile from the .c file\n");
	PutS("\t-k\tkeep intermediate files\n");
	PutS("\t-l\tuse .c2c.c instead of .c for filename extension\n");
	PutS("\t-m\tjust produce mimosa intermediate file\n");
	PutS("\t-n\tturn off nil checking\n");
	PutS("\t-oN\toptimize object code - N is a value in [0..4]\n");
	PutS("\t-p\tgenerate prof tables\n");
	PutS("\t-pw\tpause for warning\n");
	PutS("\t-q\tgenerate position independent code with -pic\n"); 
	PutS("\t-Q\tgenerate position independent code with -PIC\n"); 
	PutS("\t-target arch \t compile this file for the arch architecture\n");
	PutS("\t-r\tperform additional address (and other) checks\n");
	PutS("\t-s\tjust generate assembly code file\n");
	PutS("\t-t\tdon't report compilation times\n");
	PutS("\t-u\tdon't report uninitialized variables\n");
	PutS("\t-v\tverbose\n");
	PutS("\t-w\tdon't print warnings\n");
	PutS("\t-x file\tcall /usr/lib/inline with \"-i file\"\n");
	PutS("\t-y\tyell about runtime calls\n");
	PutS("\t-z\tproduce Mesa debugging information\n");
	PutS("\n");
	ExitSuccessfully();
	/*NOTREACHED*/
}
	
static void Usage(h)
Handle          h;
{
	Fatal(h, "Usage: mimosa [options] fileList");
}
	
static int ProcessSwitches(h, argNo)
Handle          h;
int argNo;
{
    int wasQ = FALSE;
    char *argv = h->argv[argNo];
    int ch = argv[1];
	
    if (ch == 'Q') wasQ = TRUE;
	
    switch (tolower(ch)) {
    case 'a':  case 'b':  case 'c':  case 'd': case 'e':
    case 'f':  case 'g':  case 'i':  case 'j':  case 'k':
    case 'l':  case 'n':
	setSwitch(h, (Switches)tolower(ch));
	break;
    case 'h': 
	PrintHelp();
	break;
    case 'm':
	if (argv[2] == '\0') {
	    setSwitch(h, (Switches)'m');
	} else if (!strcmp("-mpp", argv)) {
	    break; /* do nothing; mpp already done in front-end script */
	} else {
	    Fatal2(h, argv, ": unexpected command line option\n");
	}
	break;
    case 'o':  {
	int level = 3;
	resetSwitch(h, (Switches)'z'); /* optimizing turns off debugging  */
	setSwitch(h, (Switches)'o'); 
	if (isdigit(argv[2])) {
	    level = argv[2] - '0';
	    if ((level < 0) || (level > 4))
		Fatal(h, "mimosa: optimization level must be between 0 and  4 inclusive.\n");
	} else {
	    Warning(h, "mimosa: unknown optimization level, setting to default.\n");
	}
	h->optLevel = level;
	break;
    }
    case 'p': 
	if (argv[2] == 'g') {
	    Fatal(h, "Old format symbols no longer supported; use -p");
	} else if (argv[2] == 'w') {
	    setSwitch(h, pw);
	} else {
	    setSwitch(h, (Switches)'p');
	}
	break;
    case 'q': 
	if (wasQ == TRUE) {
	    setSwitch(h, Q); 
	} else {
	    setSwitch(h, (Switches)'q');
	}
	wasQ = FALSE;
	break;
    case 'r': case 'u': case 'v': case 'w': 
	setSwitch(h, (Switches)tolower(ch));
	break;
    case 's':
	if (argv[2] == '\0') {
	    setSwitch(h, (Switches)'s');
	} else if (!strcmp("-si", argv)) {
	    setSwitch(h, si);	
	} else {
	    Fatal2(h, argv, ": unexpected command line option\n");
	}
	break;
    case 't':
	if (argv[2] == '\0') {
	    setSwitch(h, (Switches)'t');
	} else if (!strcmp("-target", argv)) {
	    if (++argNo >= h->argc || !validArch(h->argv[argNo])) 
		Fatal(h, "mimosa: invalid target architecture\n");
	    if (strcmp("sun4", h->argv[argNo])) 
		resetSwitch(h, (Switches)'z');
	    h->archtype = archFromString(h->argv[argNo]);
	} else {
	    Fatal2(h, argv, ": unexpected command line option\n");
	}	
	break;	
    case 'x':
	setSwitch(h, (Switches)tolower(ch));
	if (++argNo < h->argc) {
	    h->inlineFile = strdup(h->argv[argNo]);
	} else {
	    Usage(h);
	}
	break;
    case 'y':
	setSwitch(h, (Switches)'y');
	break;
	/* case 'z': h->job.switches[ORD(z)] = TRUE; continue;  */
	/* For Laurie: */
    case 'z':
	resetSwitch(h, (Switches)'z');
	break; 
    default:
	Fatal2(h, h->argv[argNo], ": unexpected command line option\n");
	break;
    }
    return argNo;
}
	
static void doSwitch(h, s, sw)
Handle h;
char *s;
Switches sw;
{
    if (isSwitchSet(h, sw))
	strcat(s, mimosaArgArray[sw - a].on);
    else
	strcat(s, mimosaArgArray[sw - a].off);
}

static void ParseCommandLine(h)
Handle          h;
{
    int temp;
    char *suffix;
    char **argv = h->argv;
	
#ifdef sun
    setSwitch(h, (Switches)'z'); /* default z to be TRUE */
#else
    setSwitch(h, zcirio);
#endif
    for (temp = 1; temp < h->argc; temp++) {
	if (argv[temp][0] == '-') { /* process switches */
	    temp = ProcessSwitches(h, temp);
	    continue;
	}
	/*
	 * at this point all switches are handled,
	 * look for conflicting and/or non-sensical switches
	 */
	if (h->archtype == UNKNOWN) {  /* if no -target option */
	    char *archname = getenv("TARGET←ARCH");
	    if (archname == NULL) { /* if no TARGET←ARCH set to local arch */
		h->archtype = getArch();
	    } else {
		h->archtype = archFromString(archname);
	    }
	}
	if ((isSwitchSet(h, Q) || isSwitchSet(h, (Switches)'q'))
	    && !isSun4Target(h)) {
	    Warning(h, "mimosa: -Q and -q only supported on Sun\n");
	    resetSwitch(h, Q);
	    resetSwitch(h, (Switches)'q');
	}
	if (isSwitchSet(h, (Switches)'q') && isSwitchSet(h, Q)) {
	    Warning(h, "mimosa: warning: -q and -Q specified, using -Q\n");
	    setSwitch(h, Q);
	    resetSwitch(h, (Switches)'q');
	}
	if (!isSwitchSet(h, (Switches)'g') && isSwitchSet(h, (Switches)'o')) {
	    Warning(h, "mimosa: warning: -O disables dbx symbols\n");
	    setSwitch(h, (Switches)'g');
	}
	if (isSwitchSet(h, (Switches)'z') && !isSun4Target(h)) {
	    Warning(h, "mimosa: dbx debugging not supported on non-Sun platforms\n");
	    resetSwitch(h, (Switches)'z');
	}
	if (isSwitchSet(h, (Switches)'x') && !isSun4Target(h)) {
	    Warning(h, "mimosa: inlining not supported on non-Sun platforms\n");
	    resetSwitch(h, (Switches)'x');
	    h->inlineFile = 0;
	}
	if (isSwitchSet(h, (Switches)'a') && !isSun4Target(h)) {
	    Warning(h, "mimosa: tcov not supported on non-Sun platforms\n");
	    resetSwitch(h, (Switches)'a');
	}

	/* handle filenames */
	suffix = rindex(argv[temp], '.');
	if (suffix == NULL) {	    /* copy the string */
	    suffix = strdup(argv[temp]);
	    h->jobList[h->nJobs++] = suffix;
	} else if (strcmp(suffix + 1, "mesa") == 0) {  /* copy the string */
	    suffix = strdup(argv[temp]);
	    h->jobList[h->nJobs++] = suffix;
	    suffix = rindex(suffix, '.'); /* strip suffix */
	    suffix[0] = '\0';
	} else {
	    Fatal2(h, "Expected to see a mesa source file extension instead of ", argv[temp]);
	}
    }
}
	
static void AppendJStatusString(js, localJobStatus)
char *js;
JobStatus localJobStatus;
{
    switch (localJobStatus) {
    case onReadyQueue: (void)strcpy(js, "onReadyQueue"); break;
    case mimosaInProgress: (void)strcpy(js, "mimosaInProgress"); break;
    case mimosaCompileFailed: (void)strcpy(js, "mimosaCompileFailed"); break;
    case successfulDef: (void)strcpy(js, "successfulDef"); break;
    case successfulImpl: (void)strcpy(js, "successfulImpl"); break;
    case successfulDefWithWarnings: (void)strcpy(js, "successfulDefWithWarnings"); break;
    case successfulImplWithWarnings: (void)strcpy(js, "successfulImplWithWarnings"); break;
    case successfulCind: (void)strcpy(js, "successfulCind"); break;
    case successfulCindWithWarnings: (void)strcpy(js, "successfulCindWithWarnings"); break;
    case cindFailed: (void)strcpy(js, "cindFailed"); break;
    case successfulMS: (void)strcpy(js, "successfulMS"); break;
    case successfulMSWithWarnings: (void)strcpy(js, "successfulMSWithWarnings"); break;
    case msFailed: (void)strcpy(js, "msFailed"); break;
    case jobNotFound: (void)strcpy(js, "jobNotFound"); break;
    case serverTimeout: (void)strcpy(js, "serverTimeout"); break;
    default: (void)strcpy(js, "(Unknown status code)"); break;
    }
}
	
static int DoMS(h)
Handle h;
{
    char statusString[MAXSTATUSSTRINGSIZE];
    char mobsFile[MAXNAMLEN + 10];
    char errorLogFile[MAXNAMLEN+10];
    char *fileNameBase = h->job.shortFileName;
    JobQueryResult jobResult;
    int sstatus;
    int retval = FALSE;
	
    AppendFileName(mobsFile, fileNameBase, ".mob.s");
    AppendFileName(errorLogFile, fileNameBase, ".msErrlog");

    Verbose(h, "M");
    if (isSun4Target(h))
	sstatus = systeme(h,"msPackaged","msPackaged ",fileNameBase, SUN4, (int)successfulMS);
    else 
	Fatal(h, "internal error: ms called for non-sun4 arch\n");
    jobResult.js = JobStatusFromStatus(sstatus);

    switch (jobResult.js) {
    case msFailed: 
	PutS(" MS failed! See ");
	PutS(errorLogFile);
	PutC('\n');	
	Fatal(h, jobResult.err);
	break;
    case successfulMSWithWarnings:
	Warning(h, "Warnings - see ");
	Warning(h, errorLogFile);
	if (isSwitchSet(h, pw))
	    Fatal(h, "-pw switch used: pausing for warnings");
	retval = TRUE;
	break;
    case successfulMS: 
	retval = TRUE;
	break;
    default: 
	AppendJStatusString(statusString, jobResult.js);
	(void)strcat(statusString, ": ");
	Fatal2(h, statusString, jobResult.err);
	break;
    }
    return(retval);
}
	
static int DoMimosaAndC2CCompile(h)
	Handle          h;
{
    char           *compilerLogFile = "Mimosa.log";
    char            statusString[MAXSTATUSSTRINGSIZE];
    char            cFileName[MAXNAMLEN + 10];
    char            errorLogFile[MAXNAMLEN + 10];
    char            intCodeFile[MAXNAMLEN + 10];
    char            namesFile[MAXNAMLEN + 10];
    char            cTypesFile[MAXNAMLEN + 10];
    char            cCodeFile[MAXNAMLEN + 10];
    char            objectFileName[MAXNAMLEN + 10];
    char           *fileNameBase = h->job.shortFileName;
    char           *cExtension;
    char           *outFileExtension;
    char           cmdStr[MAXCOMMANDSTRINGSIZE];
    int             retval;
    int             sstatus;
    JobQueryResult  jobResult;
	
    cExtension = isSwitchSet(h, (Switches)'l') ? ".c2c.c" : ".c";
    outFileExtension = isSwitchSet(h, (Switches)'l') ? ".c2c.o" : ".o";

    AppendFileName(errorLogFile, fileNameBase, ".errlog");
    AppendFileName(intCodeFile, fileNameBase, ".icd");
    AppendFileName(namesFile, fileNameBase, ".names");
    AppendFileName(cTypesFile, fileNameBase, ".cTypes");
    AppendFileName(cCodeFile, h->job.shortFileName, cExtension);
    AppendFileName(objectFileName, fileNameBase, outFileExtension);

    (void) strcpy(cFileName, fileNameBase);
    (void) strcat(cFileName, cExtension);

    /* set the correct switches */
    strcpy(cmdStr, "mimosaPackaged -l");

/*    if (isSwitchSet(h, (Switches)'a') || isSwitchSet(h, (Switches)'z')) */
    if (isSwitchSet(h, (Switches)'z'))
	strcat(cmdStr, "a");	
    else
	strcat(cmdStr, "~a");	
    doSwitch(h, cmdStr, (Switches)'b');
    doSwitch(h, cmdStr, (Switches)'e');
    doSwitch(h, cmdStr, (Switches)'f');
    doSwitch(h, cmdStr, (Switches)'l');
    doSwitch(h, cmdStr, (Switches)'m');
    doSwitch(h, cmdStr, (Switches)'n');
    doSwitch(h, cmdStr, pw);
    doSwitch(h, cmdStr, (Switches)'r');
    doSwitch(h, cmdStr, si);
    doSwitch(h, cmdStr, (Switches)'u');
    doSwitch(h, cmdStr, (Switches)'w');
			
    PutC('M');
    if (isSun4Target(h)) 
	sstatus = systeme(h,"mimosaPackaged",cmdStr, fileNameBase, SUN4, (int)successfulImpl);
    else if (isDecTarget(h))
	sstatus = systeme(h,"decMimPackaged",cmdStr, fileNameBase, SUN4, (int)successfulImpl);
    else if (isRS6000Target(h))
	sstatus = systeme(h,"mimosaPackaged",cmdStr, fileNameBase, RS6000, (int)successfulImpl);
    else
	Fatal(h, "Internal error: unknown target type\n");
	
	    
    jobResult.js = JobStatusFromStatus(sstatus);
	
    switch (jobResult.js) {
    case mimosaCompileFailed:
	PutS(" Mimosa compile failed! See ");
	PutS(errorLogFile);
	PutC('\n');
	if (!isSwitchSet(h, (Switches)'m') &&
	    !isSwitchSet(h, (Switches)'k')) {
	    /* delete intermediate files */
	    DeleteFile(h, compilerLogFile);
	    DeleteFile(h, intCodeFile);
	    DeleteFile(h, namesFile);
	    DeleteFile(h, cTypesFile);
	    DeleteFile(h, cCodeFile);
	}
	Fatal(h, jobResult.err);
	retval = FALSE;
	break;
    case successfulDefWithWarnings: 
	if (isSwitchSet(h, (Switches)'w'))
	    jobResult.js = successfulDef;
	Warning(h, "Warnings - see ");
	Warning(h, errorLogFile);
	Warning(h, "\n");
	DeleteFile(h, compilerLogFile);
	if (isSwitchSet(h, pw))
	    Fatal(h, "-pw switch used: pausing for warnings");
	retval = FALSE;
	break;
    case successfulDef: 
	if (!isSwitchSet(h, (Switches)'m') &&
	    !isSwitchSet(h, (Switches)'k'))
	    DeleteFile(h, compilerLogFile);
	DeleteFile(h, objectFileName);
	retval = FALSE;
	break;
    case successfulImplWithWarnings: 
	Warning(h, "Warnings - see ");
	Warning(h, errorLogFile);
	Warning(h, "\n");
	if (!isSwitchSet(h, (Switches)'m') &&
	    !isSwitchSet(h, (Switches)'k'))
	    DeleteFile(h, compilerLogFile);
	if (isSwitchSet(h, pw))
	    Fatal(h, "-pw switch used: pausing for warnings");
	retval = !isSwitchSet(h, (Switches)'m'); 
	break;
    case successfulImpl: 
	if (!isSwitchSet(h, (Switches)'m') &&
	    !isSwitchSet(h, (Switches)'k'))
	    DeleteFile(h, compilerLogFile);
	retval = !isSwitchSet(h, (Switches)'m'); 
	break;
    default:
	AppendJStatusString(statusString, jobResult.js);
	(void) strcat(statusString, ": ");
	Fatal2(h, statusString, jobResult.err);
	retval = FALSE;
	break;
    }
    return retval;
}
	
static void DoMSCCompile(h)
Handle h;
{
    char *cpp1 = "/lib/cpp ";
    char *cpp2;
    /*
     * /lib/cpp FILENAME.c > FILENAME.E    *OR*
     * /lib/cpp FILENAME.c2c.c > FILENAME.E
     */
	
    /* This awk script does the following:
     *
     *   - Look for the first line where lineno is greater than or equal
     *     to 123000 and the file name is filename.mesa.
     *   - After the first line is found, don't print lines (continue)
     *     where the filename is filename.c (or filename.c2c.c). 
     *   - Unconditionally print all other lines. 
     *
     * awk 'BEGIN {mesaSource = 0} \
     *      /↑#/ {if (mesaSource == 0) \
     *      {if ($2 >= 123000 && $3 == "\"FILENAME.mesa\"") \
     *       mesaSource = 1} \
     *      else if ($3 == "\"FILENAME.c\"") continue} \
     *      {print}' FILENAME.E > FILENAME.E.c
     */
	
    char *awk1 = "/bin/awk 'BEGIN {mesaSource = 0} ";
    char *awk2 = "/↑#/ {if (mesaSource == 0) {if ($2 >= 123000 && $3 == \"\\\"";
    char *awk3 = ".mesa\\\"\") mesaSource = 1} else if ($3 == \"\\\"";
    char *awk4;
    char *redirect = " > ";
    char *ccom1 = "/lib/ccom ";
    char *ccom2 = "-Xg ";
    char *ccom3 = ".s";
	
    /*
     * /lib/ccom [-p] [-w] -Xg FILENAME.E.c > FILENAME.s  *OR*
     * /lib/ccom [-p] [-w] -Xg FILENAME.E.c2c.c > FILENAME.s
     */
	
    char 	*fileNameBase = h->job.shortFileName;
    char 	cmdStr[500];
    char 	eFile[MAXNAMLEN + 10];
    char 	ecFile[MAXNAMLEN + 10];
	
    int	sstatus;
    int	awkFailed =  0;
	
    AppendFileName(eFile, fileNameBase, ".E");
    if (isSwitchSet(h, (Switches)'l')) {
	AppendFileName(ecFile, fileNameBase, ".E.c2c.c");
	cpp2 = ".c2c.c > ";
	awk4 = ".c2c.c\\\"\") continue} {print}' ";
    } else {
	AppendFileName(ecFile, fileNameBase, ".E.c");
	cpp2 = ".c > ";
	awk4 = ".c\\\"\") continue} {print}' ";
    }
    Verbose(h, "C");

    (void) strcpy (cmdStr, cpp1);
    (void) strcat (cmdStr, fileNameBase);
    (void) strcat (cmdStr, cpp2);
    (void) strcat (cmdStr, eFile);
    Verbose(h, cmdStr);
    Verbose(h, "\n");

    if (!isSwitchSet(h, (Switches)'d')) {
	sstatus = rsh←system(h, cmdStr);
	if ((sstatus & 0377) != 0) 
	    Fatal2(h, "cpp failed for: ", fileNameBase);
    }
    (void) strcpy (cmdStr, awk1);
    (void) strcat (cmdStr, awk2);
    (void) strcat (cmdStr, fileNameBase);
    (void) strcat (cmdStr, awk3);
    (void) strcat (cmdStr, fileNameBase);
    (void) strcat (cmdStr, awk4);
    (void) strcat (cmdStr, eFile);
    (void) strcat (cmdStr, redirect);
    (void) strcat (cmdStr, ecFile);

    Verbose(h, cmdStr);
    Verbose(h, "\n");

    if (!isSwitchSet(h, (Switches)'d')) {
	sstatus = rsh←system(h, cmdStr);
	if ((sstatus & 0377) != 0) {
	    /* awk step failed - just put on a warning and skip
	     * the awk step.
	     */
	    Warning(h, "Warning: awk failed for ");
	    Warning(h, fileNameBase);
	    awkFailed = 1;
	}
    }	

    (void) strcpy(cmdStr, ccom1);
    if (isSwitchSet(h, (Switches)'p'))
	(void)strcat(cmdStr, mimosaArgArray['p' - a].on);
    if (isSwitchSet(h, (Switches)'q'))
	(void)strcat(cmdStr, mimosaArgArray['q' - a].on);
    if (isSwitchSet(h, Q))
	(void)strcat(cmdStr, mimosaArgArray['Q' - a].on);
    if (isSwitchSet(h, (Switches)'w'))
	(void)strcat(cmdStr, mimosaArgArray['w' - a].on);

    (void)strcat(cmdStr, ccom2);
    (void)strcat(cmdStr, awkFailed ? eFile : ecFile);
    (void)strcat(cmdStr, redirect);
    (void)strcat(cmdStr, fileNameBase);
    (void)strcat(cmdStr, ccom3);

    Verbose(h, cmdStr);
    Verbose(h, "\n");
    if (!isSwitchSet(h, (Switches)'d')) {
	sstatus = rsh←system(h, cmdStr);
	if ((sstatus & 0377) != 0) 
	    Fatal2(h, "ccom failed for: ", fileNameBase);
	if (!isSwitchSet(h, (Switches)'k')) {
	    DeleteFile(h, eFile);
	    DeleteFile(h, ecFile);
	}
    }
}
	
static void DoInline(h, inputFileName)
	Handle h;
	char *inputFileName;
{
    char *av[MAXAVSIZE];
    char outFileName[MAXNAMLEN+3];
    int avc = 0;
	
    (void) strcpy(outFileName,  h->job.shortFileName);
    (void) strcat(outFileName, ".i.s");
    if (!isSun4Target(h)) {
	/* in theory we never get here because inlining has been
	 * turned off for non-sun platforms after processing switches
	 */
	Fatal2(h, "inlining not supported on ", stringFromArch(h->archtype));
    } else {
	av[avc++] = "/usr/lib/inline";
	av[avc++] = "-i";
	av[avc++] = h->inlineFile;
	av[avc++] = "-o";
	av[avc++] = outFileName; 
	av[avc++] = inputFileName; 
	av[avc++] = NULL;
    }

    Verbose(h, "C");
    if (CallSys(h, av[0], av))
	Fatal2(h, "cc failed for: ", h->job.shortFileName);
}
	
static void CompileFile(h)
Handle          h;
{
    char cCodeFile[MAXNAMLEN + 10];
    char sFile[MAXNAMLEN + 10];
    char mobsFile[MAXNAMLEN + 10];
    char inlineFile[MAXNAMLEN + 10];
    char ccInputFileSuffix[10];
    char *cExtension;
	
    cExtension = isSwitchSet(h, (Switches)'l') ? ".c2c.c" : ".c";
    AppendFileName(cCodeFile, h->job.shortFileName, cExtension);
    AppendFileName(sFile, h->job.shortFileName, ".s");
    AppendFileName(mobsFile, h->job.shortFileName, ".mob.s");
    AppendFileName(inlineFile, h->job.shortFileName, ".i.s");
	
    if (!isSwitchSet(h, (Switches)'j')) { /* Then do the mimosa compile */
	if (!DoMimosaAndC2CCompile(h) || isSwitchSet(h, (Switches)'c'))
	    return;
    }	/* otherwise, assume that a previous mimosa -c was done */
	
    /* assert: was a successful impl to be C compiled */
    (void) strcpy(ccInputFileSuffix, cExtension);
    if (isSwitchSet(h, (Switches)'z') && isSun4Target(h)) {
	/* -z option was specified - go through MS */
	JobKind         jobKind = h->job.jobKind;
		
	DoMSCCompile(h);
	h->job.jobKind = ms;

	if (!DoMS(h)) return;
	h->job.jobKind = jobKind; /* restore jobKind */
	(void) strcpy(ccInputFileSuffix, ".mob.s");
    }
    if (h->inlineFile != NULL) { /* -x option - run through inline */
	if (isSwitchSet(h, (Switches)'z')) { DoInline(h, mobsFile); }
	else {
	    setSwitch(h, (Switches)'s');
	    DoCCompile(h, cExtension, FALSE);
	    resetSwitch(h, (Switches)'s');
	    DoInline(h, sFile);
	}
	(void) strcpy(ccInputFileSuffix, ".i.s");
    }

    DoCCompile(h, ccInputFileSuffix, TRUE); /* Do the final C compile. */
    if (!isSwitchSet(h, (Switches)'k')) { /* Delete the files. */
	if (!isSwitchSet(h, (Switches)'j'))
	    DeleteFile(h, cCodeFile);
	if (isSwitchSet(h, (Switches)'z')) {
	    DeleteFile(h, mobsFile);
	    DeleteFile(h, sFile);
	}
	if (h->inlineFile != NULL) {
	    DeleteFile(h, inlineFile);
	    DeleteFile(h, sFile);
	}
    }
}
	
/*
 * Revision History
 * [lah 03-Nov-88] Add -x option.
 * [JKF 8/24/89] Added -j option for tc.
 * [JKF March 5, 1990 12:45:50 pm PST] Rewrote to use system return codes.
 * [mna 24-Mar-91]
 *  Massive changes made.  Re-wrote large portions and added multiple
 *  platform support 
 */