#ifndef lint
static char sccsid[] = "@(#)dbbc2.c	1.6 (mg@ukc) 23/7/86";
#endif
/*
 *	dbbc part 2
 */

#include	<stdio.h>
#include	"bbcplot.h"
#include	"types.h"
#include	"dbbc.h"

extern	int	paperwidth;
extern	int	paperlength;
extern	int	byteorder;

/*	Here beginneth */

int	hpos = 0,		/* current internal x,y pos    */
	vpos = 0;		/* USED IN draw.o. In original device goobies */
int	DX	= 2;		/* x-step for drawing in draw.o */

/*
 *	Start of page
 */
t_page(num,fp)
int num;
FILE *fp;
{
	/* fp is file pointer for getc */
	static int firstpageout = 1;
	int l,r,u,d; /* left, right, up, down */
	int ch;

	if(in_olist(num)) {
		if (!firstpageout) bbcwait();
		else {
			bbcopen();
			firstpageout = 0;
		}
		bbcmode(0);
		bbcbyte(5); /* text at graphics cursor */
		l = HCONVERT(0); r = HCONVERT(paperwidth-1);
		u = VCONVERT(0); d = VCONVERT(paperlength-1);
		bbcplot(MOVE|ABS, l, u);
		bbcplot(DRAWF|ABS, r, u);
		bbcplot(DRAWF|ABS, r, d);
		bbcplot(DRAWF|ABS, l, d);
		bbcplot(DRAWF|ABS, l, u);
	} else {
		/* observe: new page command always starts on a new line,
		 * and is followed by font, size requests, so missed-out
		 * codes have no effect on each page (I hope) */
		/* Find next 'p' command which heralds a new page */
		while (1) {
			while ( (ch = getc(fp)) != '\n' )
				/* Let main bit deal with EOF */
				if (ch == EOF) return;
			switch (ch=getc(fp)) {
			case EOF: return;
			case 'p': (void) ungetc('p',fp); return;
			case 'x': devctrl(fp); break;
}	}	}	}

/* Draw a line by x,y (relative) */
t_line(n,m)
int n,m;
{
	hvflush();
	hpos += n; vpos += m;
	bbcplot(DRAWF|ABS, HCONVERT(hpos), VCONVERT(vpos));
}

/*
 * Code to deal with the printing of characters not in the regular beeb font.
 * The characters 224 to 255 inclusive can be defined using VDU 23.
 * We are presented by troff with a one- or two-character name to set.
 * One-char names are indexed into normchar[]
 * Two-char names are turned into a short and searched for in abnormchar[].
 * The number which this gives you is of type framboozle.
 *
 * If the framboozle is less than 256, this is the ascii code to send
 * to the beeb as it is part of the predefined font.
 * Otherwise it must be searched for in definedchar[] to see if we have already
 * installed it in the beeb font, the index into definedchar[] giving the code
 * for it (minus 224).
 * If it is not installed we must go to charraster[] and define a new char on
 * the beeb, perhaps supplanting an earlier one.
 */

/* Table to map single characters (from dil "cx" and "nnc" commands)
 * and double character names (from Cxy)
 * into either single characters for the beeb or into framboozles
 * which will need to be mapped through charraster[] to give bit pattern
 */

extern short normchar[];
extern struct abnormchar abnormchar[];

/*
 * Table to map framboozles into grid patterns.
 * The C code for this table is automatically generated by the program chargen
 * and the ascii file charset.
 */

extern struct charraster charraster[];

/* Print ascii character at current position, inline macro for speed */
#define ocmd(c) { bbcplot(MOVE|ABS, HCONVERT(hpos)-xcharoffset[c], VCONVERT(vpos)+24); bbcbyte((unsigned char) c); }

extern char xcharoffset[];
extern char ycharoffset[];

/*
 *	Put a funny char name (like Fi, bs etc.)
 */
put1s(s)
register char *s;
{
	register i;
	register short ss;

	switch (byteorder) {
	case BO_LH:
		ss = s[0] + ( s[1]<<8 );
		break;
	case BO_HL:
		ss = s[1] + ( s[0]<<8 );
		break;
	}

	for (i=0; abnormchar[i].troffname != 0; i++) {
		if (abnormchar[i].troffname == ss) {
			ss = abnormchar[i].framboozle;
			if (ss&~255) putframboozle(ss);
			else ocmd(ss);
			return;
		}
	}
	/* Never heard of it! */
	return;

}

/*
 *	Output a char
 *	USED IN draw.o
 */

put1(c)
register int c;
{
	register short ss;

	ss = normchar[c];
	if (ss & ~255) putframboozle(ss);
	else ocmd(ss);
}

/*
 * Put out the necessary for a framboozle. Only non-trivial ones welcome here.
 * Calling function should check for ( (s & ~255) == 0 ) and call
 * ocmd(s) if so.
 *
 * Remember which special characters are loaded into the
 * definable characters at the moment. 0 => undefined.
 * Strategy for replacement when more than (256-224) funny chars are required:
 * define new chars in a round robin fashion. Nexttodefine tells us which this
 * will be.
 */

putframboozle(f)
short f;
{
#	define FIRSTDEFINEDCHAR 224

	typedef short dchar_t;
	static dchar_t definedchar[256-FIRSTDEFINEDCHAR];
	static int nexttodefine = 0; /* Index into definedchar., circular buffer-oid */
	register i;

	/* Is it already loaded? */
	for (i=0; i < sizeof(definedchar)/sizeof(dchar_t) && definedchar[i] != 0; i++) {
		if (definedchar[i] == f) {
			/* already there */
			ocmd(i+FIRSTDEFINEDCHAR);
			return;
		}
	}

	/* Not loaded; Look it up in grid table */
	for (i=0; charraster[i].framboozle != 0; i++) {
		if (charraster[i].framboozle == f) {
			bbcdchar((unsigned char)(nexttodefine+FIRSTDEFINEDCHAR),charraster[i].grid);
			ocmd(nexttodefine+FIRSTDEFINEDCHAR);
			definedchar[nexttodefine++] = f;
			if (nexttodefine >= sizeof(definedchar)/sizeof(dchar_t)) nexttodefine=0;
			return;
		}
	}
	/* ERROR: framboozle from tables not in charraster[]. (Cannot happen) */
}

/*
 *	Force the device's current (x,y) position to be the same as ours
 */
hvflush()
{
	bbcplot(MOVE|ABS, HCONVERT(hpos), VCONVERT(vpos));
}

/*
 *	Successful completion
 */
done()
{
	bbcwait();
	bbcclose();
	exit(0);
	/* NOTREACHED */
}
