/*
 * Modular Composition System 8400 phototypesetter emulator
 *	Input	- output from 'troff | pt'
 *	Output	- control codes for MCS 8400
 *
 * Width tables should be in mcs collating order, in 1/18th point at 1 point.
 */
#include <stdio.h>

#define	XFACTOR		3
#define	YFACTOR		9
#define XUNIT		(XFACTOR*432)
#define YUNIT		(YFACTOR*144)

#define	CUT		90		/* cut mark character */

int	pagewidth	= 8*XUNIT;
int	length		= 0;

/*
 *   Width tables
 */
extern	int	TR[], TI[], TB[], TJ[];
extern	int	SR[], SI[], SB[], SJ[];
extern	int	SS[];
extern	int	UR[], UI[], UB[], UJ[];
int	fontmap[4];
int	*widthtab[4];

int	ch, size, font, esc, lead;
int	xpos;
int	ypos;
int	sxpos;
int	xtra;			/* extra x movements to be made */
int	currentsize = 0;
int	currentfont = 0;
int	debug = 0;


main(argc, argv)
char **argv;
{
	register int i;
	register int n;
	register char *p;
	register int f;

	for (i=1; i<argc; i++)  {
		p = argv[i];
		if (*p == 'd')  {
			debug++;
			continue;
			}

		n = *p++;
		if (n < '0'  ||  n > '9')
			continue;

		n -= '0';
		if (--n >= 4)
			continue;
		f = (*p<<8) | *(p+1);
		switch (f)  {
			case 'TR':  widthtab[n] = TR;  fontmap[n] =  1;  break;
			case 'TI':  widthtab[n] = TI;  fontmap[n] =  2;  break;
			case 'TB':  widthtab[n] = TB;  fontmap[n] =  3;  break;
			case 'TJ':  widthtab[n] = TJ;  fontmap[n] =  4;  break;
			case 'SR':  widthtab[n] = SR;  fontmap[n] =  5;  break;
			case 'SI':  widthtab[n] = SI;  fontmap[n] =  6;  break;
			case 'SB':  widthtab[n] = SB;  fontmap[n] =  7;  break;
			case 'SJ':  widthtab[n] = SJ;  fontmap[n] =  8;  break;
			case 'SS':  widthtab[n] = SS;  fontmap[n] =  9;  break;
			case 'UR':  widthtab[n] = UR;  fontmap[n] = 10;  break;
			case 'UI':  widthtab[n] = UI;  fontmap[n] = 11;  break;
			case 'UB':  widthtab[n] = UB;  fontmap[n] = 12;  break;
			case 'UJ':  widthtab[n] = UJ;  fontmap[n] = 13;  break;
			default:    widthtab[n] = 00;  fontmap[n] =  0;  break;
			}
		}

	preamble();
	while (getline()) {
		if (checkend())		/* troff finished ? */
			break;

		vertical();
		horizontal();
		if (size != currentsize)
			changesize();
		if (font != currentfont)
			changefont();
		print();
		}
	endfile();
}

preamble()
{
	register i;

	if (! debug) {
		for (i=0; i<10; i++)
			putchar('\0');
		out(0x80, 0);		/* start of take */
		out(0x85, 0);		/* initialise reverse lead mode */
		ptfont(fontmap[0]);	/* initial font */
		ptsize(10);		/* point size */
		ptindent(0);		/* reset head posn */
		}
}

/*
 *   Output accounting stats
 */
endfile()
{
	if (!debug)  {
		ptindent(0);		/* clear for next user */
		out (0x81, 0);		/* end of take */
		}
}

getline()
{
	return(scanf("%d %d %d %d %d\n", &ch, &size, &font, &esc, &lead) == 5);
}

vertical()
{
	register offset;

	offset = lead * YFACTOR;
	ypos += offset;
	ptvert(offset);
}

horizontal()
{
	register offset;

	xpos += esc * XFACTOR;
	offset = xpos - sxpos;
	if (xpos < 0  ||  xpos >= pagewidth)  {
		fprintf(stderr, "Move beyond edge of page?\n");
		abort();
		}

#ifdef	FINE
	if (ABS(offset) < 2)  {
		/* motion too small to do yet */
		xtra += offset;
		return;
		}

	if (ABS(offset) > 18)  {
		/* motion big enough to include extras */
		offset += xtra;
		xtra = 0;
		}
#endif

#ifdef	ABSOLUTE
	ptindent(xpos);
#else
	pthoriz(offset);
#endif
	sxpos = xpos;
}

print()
{
	extern char *mcstab[256];
	register char *str, c;

	if (ch == 0)
		/* no-op */
		return;
	str = (font == 3? mcstab[ch+128] : mcstab[ch]);
	while (c = *str++) {
		ptchar(c);
#ifdef	SEMISLAVE
		sxpos += widthtab[currentfont][c]*(currentsize);
#endif
		}
}

checkend()
{
	if (ch)
		/* not end yet */
		return(0);

	lead = YUNIT/YFACTOR;	/* move 1 inch */
	vertical();
	return(1);
}

changefont()
{
	if (font == 3)
		/* Act as though the change didn't happen */
		return;

	ptfont(fontmap[font]);
	currentfont = font;
}

changesize()
{
	ptsize(size);
	currentsize = size;
}

ptpage()
{
	register int i;

	if (debug)
		printf("P ");
#ifdef	CUTMARKS
	else  {
		for (i=0; i<20; i++)
			ptchar(CUT);
		ptindent(xpos);
		ptvert(36*8);
		for (i=0; i<20; i++)
			ptchar(CUT);
		ptvert(12*8);
		ptindent(xpos);
		}
#endif
}

ptvert(offset)
register offset;
{
	if (offset == 0)
		return;

	if (offset > 0)
		length += offset;

	if (debug)
		printf("V%d ", offset);
	else
		if (offset < 0)
			out(0x8a, -offset);
		else
			out(0x89, offset);
}

ptindent(offset)
register offset;
{
	if (debug)
		printf("I%d ", offset);
	else
		out(0x8b, offset);
}

pthoriz(offset)
register offset;
{
	if (offset == 0)
		return;

	if (debug)
		printf("H%d ", offset);
	else
		if (offset < 0)
			out (0x9c, -offset);
		else
			out (0x9b, offset);
}

ptchar(c)
{
	if (debug)
		printf("C%d ", c);
	else
		putchar(c);
}

ptfont(font)
{
	if (!font)  {
		fprintf(stderr, "Illegal font %d\n", font);
		abort();
		}

	if (debug)
		printf("F%d ", font);
	else
		out(0x99, font);
}

ptsize(size)
{
	if (debug)
		printf("S%d ", size);
	else
		out(0x87, size*8);
}

out (c, a)
{
	putchar(c);
	putchar(((a>>8) & 0x7f) | 0x80);
	putchar(a & 0xff);
}
