#define SIGINT 2
#define SIGQIT 3
/*
C version of tcatsim
*/

#define OBSZ 512
#define MAXY 3071
#define US 037
#define GS 035
#define ESC 033
#define FF 014
#define DBL 0200

int pl 11*144;
int mpy 1;
int div 1;
char *ap;
int ch;
int nonumb;
int psize 10;
int dfact 1;
int ibuf[259];
char obuf[OBSZ];
char *obufp obuf;
int esc;
int escd;
int verd;
int esct;
int osize 02;
int size 02;
int rx;
int xx 0;
int yy MAXY+62+48;
int leadtot -31;
int ohy -1;
int ohx -1;
int oxb -1;
int oly -1;
int olx -1;
int tflag;
int railmag;
int lead;
int skip;
int pgskip;
int ksize ';';
int mcase;
int stab[]{010,0,01,07,02,03,04,05,0211,06,0212,0213,0214,0215,0216,0217};
int rtab[]{6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 28, 26, 18};
int ktab[]{';',';',';',';',';',';',':',':','9','9','9','9','8','8','8','9'};
int od 1;
int first 1;
int alpha;
extern char *asctab[128];
extern char *spectab[128];
int erase 1;
int xxx;
int sigint;
int sigqit;

main(argc,argv)
int argc;
char **argv;
{
	register i, j;
	register char *k;
	extern ex();

	while((--argc > 0) && ((++argv)[0][0]=='-')){
		switch(argv[0][1]){
			case 'p':
				ap = &argv[0][2];
				dfact = 72;
				if(i = atoi())pl = i/3;
				continue;
			case 't':
				tflag++;
				continue;
			case 's':
				ap = &argv[0][2];
				dfact = 1;
				pgskip = atoi();
				continue;
			default:
				dfact = 1;
				ap = &argv[0][1];
				if(i = atoi())mpy = i;
				if(i = atoi())div = i;
				continue;
		}
	}
	if(argc){
		if(fopen(argv[0], ibuf) < 0){
			prstr("Cannot open: ");
			prstr(argv[0]);
			prstr("\n");
			exit(1);
		}
	}
	sigint=signal(SIGINT, ex);
	sigqit=signal(SIGQIT,1);
	while((i = getc(ibuf)) >= 0){
		if(!i)continue;
		if(i & 0200){
			esc =+ (~i) & 0177;
			continue;
		}
		if(esc){
			if(escd)esc = -esc;
			esct =+ esc;
			xx =+ (esc*mpy + rx)/div;
			rx = (esc*mpy + rx)%div;
			sendpt();
			esc = 0;
		}
		switch(i){
			case 0100:	/*init*/
				escd = verd = mcase = railmag = xx = 0;
				yy = MAXY + 48;
				leadtot = -31;
				ohy = oxb = oly = ohx = olx = -1;
				oput(US);
				flusho();
				if(!first && !tflag)kwait();
				if(first){
					first = 0;
					yy =+ 62;
				}
				init();
				continue;
			case 0101:	/*lower rail*/
				railmag =& ~01;
				continue;
			case 0102:	/*upper rail*/
				railmag =| 01;
				continue;
			case 0103:	/*upper mag*/
				railmag =| 02;
				continue;
			case 0104:	/*lower mag*/
				railmag =& ~02;
				continue;
			case 0105:	/*lower case*/
				mcase = 0;
				continue;
			case 0106:	/*upper case*/
				mcase = 0100;
				continue;
			case 0107:	/*escape forward*/
				escd = 0;
				continue;
			case 0110:	/*escape backward*/
				escd = 1;
				continue;
			case 0111:	/*stop*/
				continue;
			case 0112:	/*lead forward*/
				verd = 0;
				continue;
			case 0113:	/*undefined*/
				continue;
			case 0114:	/*lead backward*/
				verd = 1;
				continue;
			case 0115:	/*undefined*/
			case 0116:
			case 0117:
				continue;
		}
		if((i & 0340) == 0140){	/*leading*/
			lead = (~i) & 037;
			if(verd)lead = -lead;
			if((leadtot =+ lead) > pl){
				leadtot = lead;
				oput(US);
				flusho();
				if(!tflag)kwait();
				yy = MAXY;
				if(pgskip)--pgskip;
				init();
				continue;
			}
			if(skip)continue;
			if((yy =- (lead<<1)) < 0){
				skip++;
				yy = 0;
			}else sendpt();
			continue;
		}
		if((i & 0360) == 0120){	/*size change*/
			i =& 017;
			for(j = 0; i != (stab[j] & 017); j++);
			osize = size;
			size = stab[j];
			psize = rtab[j];
			ksize = ktab[j];
			oput(ESC);
			oput(ksize);
			i = 0;
			if(!(osize & DBL) && (size & DBL))i = -55;
			else if((osize & DBL) && !(size & DBL))i = 55;
			if(escd)i = -i;
			esc =+ i;
			continue;
		}
		if(i & 0300)continue;
		i = (i & 077) | mcase;
		if(railmag != 03)k = asctab[i];
		else k = spectab[i];
		if(alpha)sendpt();
		if(k != -1){
			oput(US);
			while(*k & 0377)oput(*k++);
			alpha++;
			continue;
		}else{
			if(railmag != 03){
				switch(i){
				case 0124: lig("fi"); break;
				case 0125: lig("fl"); break;
				case 0126: lig("ff"); break;
				case 0130: lig("ffl"); break;
				case 0131: lig("ffi"); break;
				default: continue;
				}
			}
			continue;
		}
	}
	ex();
}
lig(x)
char *x;
{
	register i, j;
	register char *k;

	j = 0;
	k = x;
	oput(US);
	oput(*k++);
	i = psize * 8 * mpy / (div * 6); /* 8/36 em */
	while(*k){
		xx =+ i;
		j =+ i;
		sendpt();
		oput(US);
		oput(*k++);
	}
	xx =- j;
	sendpt();
}
init(){
	register i;

	flusho();
	if(erase){
		oput(ESC);
		oput(FF);
	}else erase = 1;
	oput(ESC);
	oput(ksize);
	/*delay about a second*/
/* let the system do it...
	for(i = 960; i > 0; i--)oput(GS);
*/
	skip = 0;
	sendpt();
}
ex(){
	yy = MAXY;
	xx = 0;
	sendpt();
	oput(ESC);
	oput(';');
	oput(US);
	flusho();
	exit(0);
}
kwait(){
	char buf[128]; char *bptr; char c;
	if(pgskip) return;
next:
	bptr=buf;
	while((c=readch())&&(c!='\n')) *bptr++=c;
	*bptr=0;
	if(bptr!=buf){
		bptr = buf;
		if(*bptr == '!'){unix(&buf[1]); prstr("!\n"); goto next;}
		else switch(*bptr++){
			case 'e':
				erase = 0;
				goto next;
			case 's':
				ap = &buf[1];
				dfact = 1;
				pgskip = atoi() + 1;
				goto next;
			default:
				prstr("?\n");
				goto next;
		}
	}
	else if (c==0) ex();
	else	return;
}
unix(line)
char line[];
{
	int rc, status, unixpid;
	if( (unixpid=fork())==0 ) {
		signal(SIGINT,sigint); signal(SIGQIT,sigqit);
		close(0); dup(2);
		execl("/bin/sh", "-sh", "-c", line, 0);
		exit(255);
	}
	else if(unixpid == -1)
		return;
	else{	signal(SIGINT,1); signal(SIGQIT,1);
		while( (rc = wait(&status)) != unixpid && rc != -1 ) ;
		signal(SIGINT,ex); signal(SIGQIT,sigqit);
	}
}
readch(){
	char c;
	if (read(2,&c,1)<1) c=0;
	return(c);
}
oput(i)
char i;
{
	if(pgskip)return;
	*obufp++ = i;
	if(obufp >= (obuf + OBSZ))flusho();
}
flusho(){
	write(od,obuf,obufp-obuf);
	obufp = obuf;
}
sendpt(){
	int hy,xb,ly,hx,lx;

	oput(GS);
	hy = ((yy>>7) & 037);
	xb = ((xx & 03) + ((yy<<2) & 014) & 017);
	ly = ((yy>>2) & 037);
	hx = ((xx>>7) & 037);
	lx = ((xx>>2) & 037);
	if(hy != ohy)oput(hy | 040);
	if(xb != oxb)oput(xb | 0140);
	if((ly != oly) || (hx != ohx) || (xb != oxb))
		oput(ly | 0140);
	if(hx != ohx)oput(hx | 040);
	oput(lx | 0100);
	ohy = hy;
	oxb = xb;
	oly = ly;
	ohx = hx;
	olx = lx;
	alpha = 0;
	return;
}
prstr(s)
char *s;
{
	register i;

	for(i=0;*s;i++)s++;
	write(2,s-i,i);
}
atoi()
{
	register i, j, acc;
	int field, digits, *dd, *tscale();

	field = digits = acc = 0;
a1:
	while(((j = (i = getch()) - '0') >= 0) && (j <= 9)){
		field++;
		digits++;
		acc = 10*acc + j;
	}
	if(i == '.'){
		field++;
		digits = 0;
		goto a1;
	}
	if(!(ch = i))ch = 'x';
	dd = tscale(acc);
	acc = dd[0];
	if((field != digits) && (digits > 0)){
		j = 1;
		while(digits--)j =* 10;
		acc = ldiv(dd[1],dd[0],j);
	}
	nonumb = !field;
	ch = 0;
	return(acc);
}
int *tscale(n)
int n;
{
	register i, j;
	static int aa[2];

	switch(i = getch()){
		case 'u':
			j = 1;
			break;
		case 'p':	/*Points*/
			j = 6;
			break;
		case 'i':	/*Inches*/
			j = 432;
			break;
		case 'c':	/*Centimeters; should be 170.0787*/
			j = 170;
			break;
		case 'P':	/*Picas*/
			j = 72;
			break;
		default:
			j = dfact;
			ch = i;
	}
	aa[0] = n * j;
	aa[1] = hmul(n,j);
	return(aa);
}
getch(){
	register i;

	if(ch){
		i = ch;
		ch = 0;
		return(i);
	}
	return(*ap++);
}
