#
/*
	Copyright 1981
	Alcyon Corporation
	8474 Commerce Av.
	San Diego, Ca.  92121
*/

#include "preproc.h"

#define	NARGS	64
#define	ARGSIZE	1024
#define	ICODE	0
#define	STRINGS	1
#define	MTEMP	2
#define	ASTEMP	3
#define	NTEMPS	4


char *fargs[NARGS+1];
char **fargp;
char argbuf[ARGSIZE];
char *cfiles[NARGS+1];
char *loadargs[NARGS+1];
char *fns[NTEMPS];
char *tfns[NTEMPS];
char *defs[NARGS];
int ndefs;
char *argp	&argbuf[0];
int cflag;
int nflag;
int lflag;
int oflag;
int pflag;
int sflag;
int xflag;
int status;
int oneflag;
int errno;
char *parser "/lib/c068";
char *cgen "/lib/c168";
char *onepass "/lib/c0168";
char *pref "/lib/c680.o";
char *clib6 "/lib/lib6.a";
char *loader "/bin/lo68";
char *asm "/bin/as68";
#ifdef NOMMU
int nommu	1;
#else
int nommu	0;
#endif


// cexit - exit from C compiler driver
//		This deletes any existing temps and exits with the error status.
cexit()									// returns - none
{
	register int i;

	if( pflag == 0 ) {
		for( i = 0; i < NTEMPS; i++ )
			if( fns[i] )
				unlink(fns[i]);
	}
	exit(status);
}

// main - main routine for C68 Compiler system
//		Handles the C68 arguments.  For each C file given, the macro
//		pre-processor is called, then the parser, code generator and
//		assember are fexec'd.  The loader arguments are collected and
//		the loader is fexec'd.
main(argc,argv)
int argc;
char **argv;
{
	register char *arg, **p, **cfilep, **loadp;
	register int nloadfiles, c, i;

	cfilep = &cfiles[0];
	loadp = &loadargs[0];
	nloadfiles = 0;
	for( p = argv; --argc > 0; ) {		//process arguments
		if( *(arg= *++p) == '-' ) {
			arg++;
			for( i = 0; c = *arg++; i++ ) {
				switch( c ) {

				case 'c':
					cflag++;
					continue;

				case '1':
					oneflag++;
					parser = onepass;
					continue;

				case 'D':
					defs[ndefs++] = arg;
					i++;
					break;

				case 'N':
					nflag++;
					continue;

				case 'f':
					printf("floating point not yet implemented\n");
					continue;

				case 'L':
					lflag++;
					continue;

				case 'o':
					if( --argc <= 0 )
						ferror("bad -o option");
					*loadp++ = *p++;
					*loadp++ = *p;
					continue;

				case 'P':
					pflag++;
					cflag++;
					continue;

				case 'S':
					sflag++;
					cflag++;
					nflag++;
					continue;

				case 't':
					if( (c= *arg++) == '0' )
						parser = "/usr/c68/c068";
					else if( c == '1' )
						cgen = "/usr/c68/c168";
					else if( c == '\0' )
						arg--;
					continue;

				default:
					if( loadp >= &loadargs[NARGS] )
						ferror("too many loader args");
					*loadp++ = *p;
					i++;
					break;
				}
				break;
			}
			if( i )
				continue;
		}
		if( strend(arg,".c") || strend(arg,".s") ) {

	//C or Assembler files to process

			if( cfilep >= &cfiles[NARGS] )
				ferror("too many files");
			*cfilep++ = arg;
		}
		else if( chkdup(arg) == 0 ) {	//check for loader args
			if( loadp >= &loadargs[NARGS] )
				ferror("too many loader args");
			*loadp++ = arg;
			if( strend(arg,".o") )
				nloadfiles++;
		}
	}
	if( cfilep != &cfiles[0] ) {		//had a C file?
		signal(2,&cexit);				//catch rubouts
		for( i = 0; i < NTEMPS; i++ )	//allocate temps
			fns[i] = maketemp(i);
		for( p = &cfiles[0]; arg = *p++; ) {	//handle each C file
			for( i = 0; i < NTEMPS; i++ )
				tfns[i] = fns[i];
			if( cfilep != &cfiles[1] )
				printf("%s:\n",arg);

	//the following sets things up for the parser, the macro pre-processor
	//is called (not forked), then the parser is fexec'd.

			asflag = strend(arg,".s");
			if( pflag || asflag )
				tfns[MTEMP] = setend(arg,'i');
			if( domacro(arg,tfns[MTEMP],ndefs,defs) == 0 || pflag ) {
				cflag++;
				continue;
			}
			if( asflag == 0 ) {
				tfns[ASTEMP] = setend(arg,'s');
				initfargs();
				addfarg(parser);
				addfarg(tfns[MTEMP]);
				if( oneflag ) {
					addfarg(tfns[ASTEMP]);
					addfarg(tfns[STRINGS]);
					if( lflag || nommu )
						addfarg("-L");
					if( sflag || nflag )
						addfarg("-D");
					addfarg("-1");
				}
				else {
					addfarg(tfns[ICODE]);
					addfarg(tfns[STRINGS]);
				}
				endfargs();
				if( fexec(parser,fargs) ) {
					status++;
					cflag++;
					continue;
				}

	//this sets things up for the code generator

				if( oneflag == 0 ) {
					initfargs();
					addfarg(cgen);
					addfarg(tfns[ICODE]);
					addfarg(tfns[ASTEMP]);
					if( sflag == 0 )
						fns[ASTEMP] = tfns[ASTEMP];
					if( lflag || nommu )
						addfarg("-L");
					if( nflag || sflag )
						addfarg("-D");
					endfargs();
					if( fexec(cgen,fargs) ) {
						status++;
						cflag++;
						continue;
					}
				}
				if( sflag )
					continue;
			}
			else
				tfns[ASTEMP] = tfns[MTEMP];

	//this sets things up for the assembler

			initfargs();
			addfarg(asm);
			if( asflag == 0 )
				addfarg("-u");
			if( lflag || nommu )
				addfarg("-L");
			addfarg(tfns[ASTEMP]);
			endfargs();
			if( fexec(asm,fargs) ) {
				cflag++;
				status++;
			}
			unlink(tfns[ASTEMP]);
		}
	}
	if( cflag == 0 && (loadp != &loadargs[0] || cfilep != &cfiles[0] )) {

	//set things up for the loader, this means that we need to add the
	//C preface at the beginning of the program which has the jsr to
	//main and then exits after return from main.

		initfargs();
		addfarg(loader);
		addfarg("-X");
		if( nommu )
			addfarg("-r");
		for( p = loadargs; (arg = *p) && *arg == '-'; p++ ) {
			addfarg(arg);
			if( arg[1] == 'o' )
				addfarg(*++p);
		}
		addfarg(pref);					//C preface to jsr to main
		for( cfilep = &cfiles[0]; *cfilep; nloadfiles++ ) {
			arg = setend(*cfilep++,'o');
			if( chkdup(arg) == 0 )
				addfarg(arg);
		}
		while( *p )
			addfarg(*p++);
		addfarg(clib6);
		endfargs();
		status =| fexec(loader,fargs);

	//if we were given one C file and there is one ".o" file, we remove
	//the ".o" file.

		if( cfilep == &cfiles[1] && nloadfiles == 1 )
			unlink(setend(cfiles[0],'o'));
	}
	cexit();
}

// fexec - fork and exec
//		This forks a new task, then does an execv to execute the given
//		program with the given arguements.
fexec(fname,args)						// returns 1 if error, 0 otherwise
char *fname;							// file to execute
char **args;							// arguments to pass
{
	register int pid, i;
	int fstat;

//	if( (pid=fork()) == 0 ) {			//child process
//		execv(fname,args);
//		printf("can't execv %s errno=%d\n",fname,errno);
//		exit(1);
//	}
	pid = maketask(fname,0,0,args);	//do fork & exec
	if( pid < 0 ) {
		printf("can't fork errno=%d\n",errno);
		return(1);
	}
	while( pid != wait(&fstat) )		//wait for child
		;
	if( (i=fstat&0377) != 0 && i != 14 ) {
		if( i != 2 )
			printf("%s error terminated\n",fname);
		status++;
		cexit();
	}
	return( (fstat>>8) & 0377 );
}

// setend - set the end character of a string
//		This grabs a copy of the string and sets the last character to
//		the given character.  This is used to generate ".o", ".i" and
//		".s" file names.
char *setend(s,c)						// returns pointer to string
char *s;								// pointer to old string
int c;									// character to end string with
{
	register char *p;

	p = makecopy(s);
	p[strlen(p)-1] = c;
	return(p);
}

// chkdup - checks for duplicate ".o" files in file list
//		Goes thru the loader argument list checking for the given
//		".o" file name.
chkdup(s)								// returns 1 if found, 0 otherwise
char *s;								// pointer to argument
{
	register char **l;

	if( strend(s,".o") ) {
		for( l = &loadargs[0]; *l; )
			if( strcmp(*l++,s) == 0 )
				return(1);
	}
	return(0);
}

// makecopy - makes a copy of a string
//		This allows for manipulating the file name, while allowing the
//		saving of the old file name.
char *makecopy(s)						// returns pointer to string
char *s;								// string to copy
{
	register char *p;

	for( p = argp; *argp++ = *s++; )
		;
	return(p);
}

// initfargs - initialize fexec arg block
//		This sets the arg block pointer to the beginning of the block.
initfargs()								// returns - none
{
	fargp = &fargs[0];
}

// addfarg - add fexec argument
//		This takes the given arguement and adds it to the argment block
addfarg(s)
char *s;
{
	if( fargp >= &fargs[NARGS] )
		ferror("too many args");
	*fargp++ = s;
}

// endfargs - end fexec argument block
//		This ends the argument block with a zero pointer.
endfargs()								// returns - none
{
	*fargp = 0;
}

// ferror - fatal error
//		Outputs error message and exits with error status.
ferror(s,x1,x2,x3,x4,x5,x6)				// returns - none
char *s;								// printf string
int x1, x2, x3, x4, x5, x6;				// printf args
{
	printf(s,x1,x2,x3,x4,x5,x6);
	printf("\n");
	status++;
	cexit();
}

// maketemp - make a temporary file name
//		Generates unique file name with process id
char *maketemp(arb)						// returns file name
int arb;								// arbitrary number
{
	char *p, tmp[6];

	p = makecopy("/tmp/ct6");
	argp--;
	itoa(getpid(),tmp,1);
	makecopy(tmp);
	argp--;
	makecopy(".");
	argp--;
	itoa(arb,tmp,1);
	makecopy(tmp);
	return(p);
}

// strcmp - string comparison
//		Compares two strings for equality, less or greater.
strcmp(s,t)								// returns 0 for equality,
										// neg for < and pos for >.
char *s;								// first string
char *t;								// second string
{
	for( ; *s == *t; s++, t++ )
		if( *s == '\0' )
			return(0);
	return( *s - *t );
}

// strlen - string length
//		Computes number of bytes in string.
strlen(s)								// returns string length
char *s;								// string to compute length
{
	register int n;

	for( n = 0; *s++ != '\0'; )
		n++;
	return(n);
}

// itoa - integer to ASCII conversion
//		Converts integer to ASCII string, handles '-'.
itoa(n,s,w)								// returns - none
int n;									// number to convert
char *s;								// resulting string
int w;									// minimum width of string
{
	register int sign, i;
	char temp[6];

	if( (sign=n) < 0 )
		n = -n;
	i = 0;
	do {
		temp[i++] = n % 10 + '0';
	} while( (n =/ 10) > 0 );
	if( sign < 0 )
		temp[i++] = '-';
	while( --w >= i )					//pad on left with blanks
		*s++ = ' ';
	while( --i >= 0 )					//move chars reversed
		*s++ = temp[i];
	*s = '\0';
}

// strend - set string end
//		This is used to compare the endings of file names for ".c", etc.
strend(s,t)								// returns 1 if match, 0 otherwise
char *s;								// string to compare
char *t;								// string ending
{
	int ls, lt;

	if( (ls=strlen(s)) < (lt=strlen(t)) )
		return(0);
	if( strcmp(&s[ls-lt],t) == 0 )
		return(1);
	return(0);
}
