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

#ifndef lint
static char rcsid[] = "$Header:pcc_ca.c 12.0$";
#endif

static	char sccsid[] = "@(#)cc.c 4.7 7/1/83";

/*
 * cc - front end for C compiler
 */
#ifdef ONVAX
#include "/xca/usr/include/sys/param.h"
#include "/xca/usr/include/sys/stat.h"
#include "/xca/usr/include/stdio.h"
#include "/xca/usr/include/ctype.h"
#include "/xca/usr/include/signal.h"
#include "/xca/usr/include/sys/dir.h"
char	*cpp = "/xca/lib/cpp";
char	*ccom = "/xca/lib/ccom"; 
char	*c2 = "/xca/lib/c2";
char	*as = "/xca/bin/as";
char	*ld = "/xca/bin/ld";
char	*crt0 = "/xca/lib/crt0.o";

#else
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <sys/dir.h>
char	*cpp = "/lib/cpp";
char	*ccom = "/lib/ccom"; 	/* TQH /lib/ccom */
char	*c2 = "/lib/c2";
char	*as = "/bin/as";
char	*ld = "/bin/ld";
char	*crt0 = "/lib/crt0.o";
#endif

char	tmp0[30];		/* big enough for /tmp/ctm%05.5d */
char	*tmp1, *tmp2, *tmp3, *tmp4, *tmp5;
char	*outfile;
char	*savestr(), *strspl(), *setsuf();
int	idexit();
char	**av, **clist, **llist, **plist;
int	cflag, eflag, oflag, pflag, sflag, wflag, Rflag, exflag, proflag;
int	gflag, Gflag, Mflag;
int	vflag;			/* cc debugging flag */
int	aaflag; /* (ef) 1/4/86 -- alloca enabled? (-ma) */
int	no_RTFL = 0;		/* TQH 04-29-87, default to RTFL.  To */
				/* compile with old fp format, use -mO */
int	RTFL_small = 0;		/* TQH 06-08-87, produce small RTFL block */
				/* use as "-ms".  This flag is significant */
				/* only with hc.  Pcc just ignores it. */
int	ldxflag; /* (ef) 2/13/86 -- -x specified? (intended for loader) */

/* pcc debugging flags */
int	ddebug,    idebug,    bdebug,    tdebug,  edebug,    xdebug, vdebug;
int	lineflag,  exprflag,  orderflag, regflag, ralloflag, ttypeflag;
int	shapeflag, sethiflag, machineflag;
int	flgctr;

/* optimizer debugging flags */
int	Oall,	   Onone,     Oshowmods, Otrace,  Odebug,    Obalr;
int	Oload,     Ojumps,    Oregvar,   Omr,     Omisc,     Olong;

char	*dflag;
int	exfail;
char	*chpass;
char	*npassname;
char	*basename;

int	nc, nl, np, nxo, na;

#define	cunlink(s)	if (s) unlink(s)

main(argc, argv)
	char **argv;
{
	char *t;
	char *assource;
	int i, j, c;

	basename = argv[0] + strlen(argv[0]) - 1;
	while (basename > argv[0])
	{
		if (*(basename-1) == '/')
			break;
		else
			basename--;
	}
	/* ld currently adds upto 5 args; 10 is room to spare */
	av = (char **)calloc(argc+10, sizeof (char **));
	clist = (char **)calloc(argc, sizeof (char **));
	llist = (char **)calloc(argc, sizeof (char **));
	plist = (char **)calloc(argc, sizeof (char **));
	for (i = 1; i < argc; i++) {
		if (*argv[i] == '-') switch (argv[i][1]) {

		case 'f':
		case 'H':
		        fprintf(stderr,
			"%s: warning: %s: unsupported flag\n",
			basename,argv[i]);
			continue;
		case 'v':
			vflag++;
			continue;
		case 'S':
			sflag++;
			cflag++;
			continue;
		case 'o':
			if (++i < argc) {
				outfile = argv[i];
				switch (getsuf(outfile)) {

				case 'c':
				case 'o':
					error("-o would overwrite %s",
					    outfile);
					exit(8);
				}
			}
			continue;
		case 'R':
			Rflag++;
			continue;
		case 'm':
			switch (argv[i][2]) {
			    case 'a':	aaflag++;
			    		break;
			    case 'O':	no_RTFL++;	/* TQH 04-29-87 */
			    		break;
			    case 's':	RTFL_small++;	/* TQH 06-08-87 */
			    		break;
			    default:	error("unknown machine dependent flag '%c' requested",argv[i][2]);
			    		break;
			}
			continue;
		case 'O':
			oflag++;
			switch (argv[i][2]) {
				case 'a': 
					Oall++;
					break;

				case 'b': 
					Obalr++;
					break;

				case 'd': 
					Odebug++;
					break;

				case 'f':
					Olong++;
					break;

				case 'j': 
					Ojumps++;
					break;

				case 'l': 
					Oload++;
					break;

				case 'm': 
					Omr++;
					break;

				case 'n': 
					Onone++;
					break;

				case 'r': 
					Oregvar++;
					break;

				case 's': 
					Oshowmods++;
					break;

				case 't': 
					Otrace++;
					break;

				case 'x': 
					Omisc++;
					break;

			}
			continue;

		case 'p':
			{
			char *ocrt0 = crt0;
			struct stat statb;

#ifdef ONVAX
			crt0 = "/xca/lib/mcrt0.o";
#else
			crt0 = "/lib/mcrt0.o";
#endif
			if (argv[i][2] == 'g')
#ifdef ONVAX
				crt0 = "/xca/usr/lib/gcrt0.o";
#else
				crt0 = "/usr/lib/gcrt0.o"; 
#endif
/* (ef) 2/13/86 -- let ld worry about it. */
/*			if (stat(crt0, &statb) < 0) {*/
/*				crt0 = ocrt0;*/
/*				fprintf(stderr," profiling disabled for the moment\n");*/
/*			}*/
/*			else*/
			proflag++;
			continue;
			}
		case 'g':

			if (argv[i][2] == 'o') {
			    Gflag++;	/* old format for -go */
			} else {
			    gflag++;	/* new format for -g */
			}
			continue;
		case 'w':
			wflag++;
			continue;
		case 'E':
			exflag++;
		case 'P':
			pflag++;
			if (argv[i][1]=='P')
				fprintf(stderr,
     "%s: warning: -P option obsolete; you should use -E instead\n",basename);
			plist[np++] = argv[i];
		case 'c':
			cflag++;
			continue;
		case 'M':
			exflag++;
			pflag++;
			Mflag++;
			/* and fall through */
		case 'D':
		case 'I':
		case 'U':
		case 'C':
			plist[np++] = argv[i];
			continue;
		case 't':
			if (chpass)
				error("-t overwrites earlier option", 0);
			chpass = argv[i]+2;
			if (chpass[0]==0)
				chpass = "012p";
			continue;
		case 'B':
			if (npassname)
				error("-B overwrites earlier option", 0);
			npassname = argv[i]+2;
			if (npassname[0]==0)
#ifdef ONVAX
				npassname = "/xca/usr/c/o";
#else
				npassname = "/usr/c/o";
#endif
			continue;
		case 'd':
			dflag = argv[i];
			continue;

		/* pcc debugging options */

		case 'x':
			switch (argv[i][2]) {
			case '\0': /* (ef) 2/13/86 -- intended for ld */
				ldxflag++;
				break;
			case 'd':
				ddebug++;
				break;
			case 'i':
				idebug++;
				break;
			case 'b':
				bdebug++;
				break;
			case 't':
				tdebug++;
				break;
			case 'e':
				edebug++;
				break;
			case 'x':
				xdebug++;
				break;
			case 'l':
				lineflag++;
				break;
			case 'p':
				exprflag++;
				break;
			case 'o':
				orderflag++;
				break;
			case 'r':
				regflag++;
				break;
			case 'a':
				ralloflag++;
				break;
			case 'v':
				vdebug++;
				break;
			case 'c':
				ttypeflag++;
				break;
			case 's':
				shapeflag++;
				break;
			case 'u':
				sethiflag++;
				break;
			case 'm':
				machineflag++;
			}
			continue;

		}
		t = argv[i];
		c = getsuf(t);

		if (c=='c' || c=='s' || exflag) {
			clist[nc++] = t;
			t = setsuf(t, 'o');
		}
		if (nodup(llist, t)) {
			llist[nl++] = t;
			if (getsuf(t)=='o')
				nxo++;
		}
	}
	if (gflag || Gflag) {
		if (oflag)
		    fprintf(stderr, "%s: warning: -g disables -O\n",basename);
		oflag = 0;
	}
	if (sflag && Onone)
		oflag = 0;
	if (npassname && chpass ==0)
		chpass = "012p";
	if (chpass && npassname==0)
#ifdef ONVAX
		npassname = "/xca/usr/new";
#else
		npassname = "/usr/new";
#endif
	if (chpass)
	for (t=chpass; *t; t++) {
		switch (*t) {

		case '0':
			ccom = strspl(npassname, "ccom");
			continue;
		case '2':
			c2 = strspl(npassname, "c2");
			continue;
		case 'p':
			cpp = strspl(npassname, "cpp");
			continue;
		}
	}
	if (nc==0)
		goto nocom;
	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, idexit);
	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
		signal(SIGTERM, idexit);
	if (pflag==0)
		sprintf(tmp0, "/tmp/ctm%05.5d", getpid());
	tmp1 = strspl(tmp0, "1");
	tmp2 = strspl(tmp0, "2");
	tmp3 = strspl(tmp0, "3");
	if (pflag==0)
		tmp4 = strspl(tmp0, "4");
	if (oflag)
		tmp5 = strspl(tmp0, "5");
#ifdef DEBUG
	fprintf(stderr,"tmp0 %s\n",tmp0);
	fprintf(stderr,"tmp1 %s\n",tmp1);
	fprintf(stderr,"tmp2 %s\n",tmp2);
	fprintf(stderr,"tmp3 %s\n",tmp3);
	fprintf(stderr,"tmp4 %s\n",tmp4);
	fprintf(stderr,"tmp5 %s\n",tmp5);
#endif
	for (i=0; i<nc; i++) {
		if (nc > 1 && !Mflag) {
			printf("%s:\n", clist[i]);
			fflush(stdout);
		}
		if (!Mflag && getsuf(clist[i]) == 's') {
			assource = clist[i];
			goto assemble;
		} else
			assource = tmp3;
		if (pflag)
			tmp4 = setsuf(clist[i], 'i');
		av[0] = "cpp"; av[1] = clist[i]; av[2] = exflag ? "-" : tmp4;
		na = 3;
		for (j = 0; j < np; j++)
			av[na++] = plist[j];
		av[na++] = 0;
		if (callsys(cpp, av)) {
			exfail++;
			eflag++;
		}
		if (pflag || exfail) {
			cflag++;
			continue;
		}
		if (sflag) {
			assource = tmp3 = setsuf(clist[i], 's');
			}

recompile:	av[0] = "ccom"; av[1] = tmp4; av[2] = oflag?tmp5:tmp3; na = 3;
		if (proflag)
			av[na++] = "-XP";
		if (gflag) {
			av[na++] = "-Xg";
		} else if (Gflag) {
			av[na++] = "-XG";
		}
		if (aaflag)	/* (ef) 1/4/86 */
			av[na++] = "-XA";
		if (no_RTFL)	/* TQH 04-29-87 */
			av[na++] = "-XO";
		if (RTFL_small)	/* TQH 06-08-87 */
			av[na++] = "-Xs";
		if (wflag)
			av[na++] = "-w";
		if (oflag || Onone)
			av[na++] = "-Xo";
		if (Rflag)
			av[na++] = "-XR";

		/* the pcc debugging options */
		for ( flgctr=ddebug; flgctr>0;    flgctr--) av[na++] = "-Xd";
		for ( flgctr=idebug; flgctr>0;    flgctr--) av[na++] = "-Xi";
		for ( flgctr=bdebug; flgctr>0;    flgctr--) av[na++] = "-Xb";
		for ( flgctr=tdebug; flgctr>0;    flgctr--) av[na++] = "-Xt";
		for ( flgctr=edebug; flgctr>0;    flgctr--) av[na++] = "-Xe";
		for ( flgctr=xdebug; flgctr>0;    flgctr--) av[na++] = "-Xx";
		for ( flgctr=exprflag; flgctr>0;  flgctr--) av[na++] = "-e";
		for ( flgctr=orderflag; flgctr>0; flgctr--) av[na++] = "-o";
		for ( flgctr=regflag; flgctr>0;   flgctr--) av[na++] = "-r";
		for ( flgctr=vdebug; flgctr>0;    flgctr--) av[na++] = "-v";
		for ( flgctr=ttypeflag; flgctr>0; flgctr--) av[na++] = "-t";
		for ( flgctr=shapeflag; flgctr>0; flgctr--) av[na++] = "-s";
		for ( flgctr=lineflag; flgctr>0;  flgctr--) av[na++] = "-l";
		if (ralloflag) av[na++] = "-a";
		if (sethiflag) av[na++] = "-u";
		if (machineflag) av[na++] = "-x";

		av[na] = 0;
		if (callsys(ccom, av)) {
			cflag++;
			eflag++;
			continue;
		}
		if (oflag) {
			av[0] = "c2"; av[1] = tmp5; av[2] = tmp3; 
			na = 3;
			av[na++] = "-a";
			if (Onone || Obalr || Oload || Ojumps || Oregvar || 
			    Omr   || Omisc || Olong) {
				av[na++] = "-n";
				if (Obalr)   av[na++] = "-b";
				if (Oload)   av[na++] = "-l";
				if (Ojumps)  av[na++] = " -j";
				if (Oregvar) av[na++] = " -r";
				if (Omr)     av[na++] = " -m";
				if (Omisc)   av[na++] = " -x";
				if (Olong)   av[na++] = " -f";
			}

			if (Odebug) av[na++] = " -d";
			if (Otrace) av[na++] = " -t";
			if (Oshowmods) av[na++] = " -s";

			av[na++] = 0;

			if (callsys(c2, av)) {
/*				unlink(tmp3);
/*				tmp3 = assource = tmp5;
*/
/*				cflag++;
/*				eflag++;
/*				continue;
*/
				oflag= 0;
				fprintf(stderr,"Warning! Optimizer bypassed\n");
				goto recompile;
			} else
				unlink(tmp5);
		}

		if (sflag)
			continue;
	assemble:
		cunlink(tmp1); cunlink(tmp2); cunlink(tmp4);
		av[0] = "as"; av[1] = "-o"; av[2] = setsuf(clist[i], 'o');
		na = 3;
		if (Rflag)
			av[na++] = "-R";
		if (dflag)
			av[na++] = dflag;
		av[na++] = assource;
		av[na] = 0;
		if (callsys(as, av) > 0) {
			cflag++;
			eflag++;
			continue;
		}
	}
nocom:
	if (cflag==0 && nl!=0) {
		i = 0;
		av[0] = "ld"; av[1] = "-X"; av[2] = crt0; 
		av[3] = "-e"; av[4] = "start"; 
		na = 5;
		if (outfile) {
			av[na++] = "-o";
			av[na++] = outfile;
		}
		while (i < nl)
			av[na++] = llist[i++];
		if (gflag || Gflag)
			av[na++] = "-lg";
		if (ldxflag)
			av[na++] = "-x";
		if (proflag) {
			av[na++] = "-lfp_p";
			av[na++] = "-lc_p";
		}
		else {
			av[na++] = "-lc";
		}
		av[na++] = 0;
		eflag |= callsys(ld, av);
		if (nc==1 && nxo==1 && eflag==0)
			unlink(setsuf(clist[0], 'o'));
	}
	dexit();
}

idexit()
{

	eflag = 100;
	dexit();
}

dexit()
{

	if (!pflag) {
		cunlink(tmp1);
		cunlink(tmp2);
		if (sflag==0)
			cunlink(tmp3);
		cunlink(tmp4);
		cunlink(tmp5);
	}
	exit(eflag);
}

error(s, x)
	char *s, *x;
{
	FILE *diag = exflag ? stderr : stdout;

	fprintf(diag, "%s: ",basename);
	fprintf(diag, s, x);
	putc('\n', diag);
	exfail++;
	cflag++;
	eflag++;
}

getsuf(as)
char as[];
{
	register int c;
	register char *s;
	register int t;

	s = as;
	c = 0;
	while (t = *s++)
		if (t=='/')
			c = 0;
		else
			c++;
	s -= 3;
	if (c <= MAXNAMLEN && c > 2 && *s++ == '.')
		return (*s);
	return (0);
}

char *
setsuf(as, ch)
	char *as;
{
	register char *s, *s1;

	s = s1 = savestr(as);
	while (*s)
		if (*s++ == '/')
			s1 = s;
	s[-1] = ch;
	return (s1);
}

callsys(f, v)
	char *f, **v;
{
	int t, status;

	/* cc debugging */
	if (vflag) {
		int i;
		printf("callsys: %s args: ",f);
		for (i = 0; v[i] != NULL; i++)
			printf("%s ",v[i]);
		printf("\n");
	}

	t = vfork();
	if (t == -1) {
		printf("No more processes\n");
		return (100);
	}
	if (t == 0) {
		execv(f, v);
		printf("Can't find %s\n", f);
		fflush(stdout);
		_exit(100);
	}
	while (t != wait(&status))
		;
	if ((t=(status&0377)) != 0 && t!=14) {
		if (t!=2) {
			printf("Fatal error in %s\n", f);
			eflag = 8;
		}
		dexit();
	}
	return ((status>>8) & 0377);
}

nodup(l, os)
	char **l, *os;
{
	register char *t, *s;
	register int c;

	s = os;
	if (getsuf(s) != 'o')
		return (1);
	while (t = *l++) {
		while (c = *s++)
			if (c != *t++)
				break;
		if (*t==0 && c==0)
			return (0);
		s = os;
	}
	return (1);
}

#define	NSAVETAB	1024
char	*savetab;
int	saveleft;

char *
savestr(cp)
	register char *cp;
{
	register int len;

	len = strlen(cp) + 1;
	if (len > saveleft) {
		saveleft = NSAVETAB;
		if (len > saveleft)
			saveleft = len;
		savetab = (char *)malloc(saveleft);
		if (savetab == 0) {
			fprintf(stderr, "ran out of memory (savestr)\n");
			exit(1);
		}
	}
	strncpy(savetab, cp, len);
	cp = savetab;
	savetab += len;
	saveleft -= len;
	return (cp);
}

char *
strspl(left, right)
	char *left, *right;
{
	char buf[BUFSIZ];

	strcpy(buf, left);
	strcat(buf, right);
	return (savestr(buf));
}
