/* DRIVER.C		Specialized printer drivers

	(C) 1982 Perfect Software, Inc.

	01/26/82	Version 1.00 by Barry A. Dobyns

This file contains the drivers for various kinds of printers.
******************************************************************************/

#include "pp.h"

DrvInit (vpos)
int vpos;
{
	OPutCmd (&dev.initstr);
	switch (dev.prtcode) {

	case VANILLA:
		VInit (vpos);
		break;
	case DIABLO:
		DbInit (vpos);
		break;
	case EPSON:
		EpInit (vpos);
		break;
	case IDS460:
		IDSInit (vpos);
		break;
	case SPINWRITER:
		SpInit (vpos);
		break;
		/*	case CUSTOM:
						CusInit (vpos);
						break;
					case QUME:
						QmInit (vpos);
						break;
*/	case CEN737:
		CenInit (vpos);
		break;
	case CITOH:
		CitInit (vpos);
		break;
	}
}


DrvFini()
{
	switch (dev.prtcode) {

	case VANILLA:
		VFini();
		break;
	case DIABLO:
		DbFini();
		break;
	case EPSON:
		EpFini();
		break;
	case IDS460:
		IDSFini();
		break;
	case SPINWRITER:
		SpFini();
		break;
		/*	case CUSTOM:
						CusFini();
						break;
					case QUME:
						QmFini();
						break;
*/	case CEN737:
		CenFini();
		break;
	case CITOH:
		CitFini();
		break;
	}
	OPutCmd (&dev.finistr);
}


DrvPrtMove (c, hpos, vpos)		/* print c and move to hpos, vpos */
int c, hpos, vpos;
{
	switch (dev.prtcode) {

	case VANILLA:
		VPrtMove (c, hpos, vpos);
		break;
	case DIABLO:
		DbPrtMove (c, hpos, vpos);
		break;
	case EPSON:
		EpPrtMove (c, hpos, vpos);
		break;
	case IDS460:
		IDSPrtMove (c, hpos, vpos);
		break;
	case SPINWRITER:
		SpPrtMove (c, hpos, vpos);
		break;
		/*	case CUSTOM:
						CusPrtMove (c, hpos, vpos);
						break;
					case QUME:
						QmPrtMove (c, hpos, vpos);
						break;
*/	case CEN737:
		CenPrtMove (c, hpos, vpos);
		break;
	case CITOH:
		CitPrtMove (c, hpos, vpos);
		break;
	}
}


FLAG
DrvInfo (what)				/* ask about printer */
int what;
{
	switch (dev.prtcode) {

	case VANILLA:
		return (VInfo (what));
		break;
	case DIABLO:
		return (DbInfo (what));
		break;
	case EPSON:
		return (EpInfo (what));
		break;
	case IDS460:
		return (IDSInfo (what));
		break;
	case SPINWRITER:
		return (SpInfo (what));
		break;
		/*	case CUSTOM:
						return (CusInfo (what));
						break;
					case QUME:
						return (QmInfo (what));
						break;
*/	case CEN737:
		return (CenInfo (what));
		break;
	case CITOH:
		return (CitInfo (what));
		break;
	}
}


/**************** Vanilla driver ****************/

VInit (vpos)
int vpos;
{
	if (dev.barecr) OPutChar (CR);
	drvhpos = 0;
	drvvpos = vpos;
}


VFini()
{
}


VPrtMove (c, hpos, vpos)
int c, hpos, vpos;
{
	int delh, delv;

	if (c != NOCHAR) {
		OPutChar (c);
		drvhpos += DWidChar (c);
	}
	delh = hpos - drvhpos;
	delv = vpos - drvvpos;
	if (delh < 0) {
		if (delv) {
			OPutCmd (&dev.donewline);
			delv -= linev;
			delh = hpos;
		}
		else if (dev.barecr
		    &&  (!dev.backspace
		    ||  -delh > hpos + 1)) {
			OPutChar (CR);
			delh = hpos;
		}
		else if (dev.backspace) while (delh < 0) {
			OPutChar (BS);
			delh += spaceh;
		}
	}
	if (dev.formfeed) 					/* reconstruct form feeds */
		while (delv > (vpos % pagev)) {	/* believe it or not! */
			OPutChar (FF);
			delv -= pagev - (vpos - delv) % pagev;
		}
	while ((delv -= linev) >= 0) {
		OPutCmd (&dev.donewline);
		delh=hpos;
	}
	while ((delh -= spaceh) >= 0) OPutChar (' ');
	drvhpos = hpos;
	drvvpos = vpos % pagev;
}


FLAG
VInfo (what)				/* ask about printer */
int what;
{
	switch (what) {

	case OVP:					/* can it overprint? */
		return (dev.barecr  ||  dev.backspace);
	case CENTCHAR:				/* does it center characters? */
	case BIDIREC:				/* does it need explicit bidirection? */
		return (FALSE);
	case BOLD:				/* can it boldface innately? */
		return (dev.boldon.len != 0);
	case ITALIC:				/* can it italic innately? */
		return (dev.italon.len != 0);
	case F1:					 /* can it font one innately? */
		return (dev.f1on.len != 0);
	case F2:					 /* can it font one innately? */
		return (dev.f2on.len != 0);
	case F3:					 /* can it font one innately? */
		return (dev.f3on.len != 0);
	default:
		Fatal ("VInfo: unknown request\n");
	}
}


/**************** Diablo driver ****************/


DbInit (vpos)
int vpos;
{
	drvvpos = vpos;
	OPutChar (CR);
	drvhpos = 0;
	drvhpitch = drvvpitch = drvdirec = UNINITIALIZED;
	drvshiftp = TRUE;
	DbSHPitch (spaceh);
	DbSVPitch (linev);
	DbSDirec (FORWARD);
	DbSShift (FALSE);
}


DbFini()
{
	DbSHPitch (spaceh);
	DbSVPitch (linev);
	DbSDirec (FORWARD);
	DbSShift (FALSE);
}


DbPrtMove (c, hpos, vpos)	/* print c and move to hpos, vpos */
int c, hpos, vpos;
{
	int delh;

	delh = hpos - drvhpos;
	if (c != NOCHAR) {
		if ((!DbSpcOk (delh)  &&  !DbTabOk (hpos)  &&  abs(delh) <= 125)
		    ||  (abs(delh) == spaceh  &&  !dev.isprop))
			DbSHPitch (abs(delh));
		DbSDirec ((delh < 0) ? BACKWARD : FORWARD);
		DbSShift ((c & 128) ? TRUE : FALSE);
		OPutChar (c & 127);
		drvhpos += drvhpitch * drvdirec;
	}
	DbMoveH (hpos);
	DbMoveV (vpos);
}


DbMoveH (hpos)				/* horizontal move */
int hpos;
{
	int delh;

	delh = hpos - drvhpos;
	if (!delh) return;
	drvhpos = hpos;
	if (DbSpcOk (delh)
	    &&  (abs(delh) / drvhpitch < 4  ||  !DbTabOk (hpos))) {
		while (delh)
			if (delh * drvdirec > 0) {
				OPutChar (' ');
				delh -= drvhpitch * drvdirec;
			}
			else {
				OPutChar (BS);
				delh += drvhpitch * drvdirec;
			}
		return;
	}
	if (abs(delh) > 125  ||  DbTabOk (hpos)) {
		if (drvhpitch == 0  ||  hpos / drvhpitch > 125)
			DbSHPitch ((hpos / spaceh <= 125) ? spaceh : 13);
		DbHTab (hpos / drvhpitch);
		delh = hpos % drvhpitch;
	}
	if (delh) {
		DbSHPitch (abs(delh));
		OPutChar ((delh * drvdirec < 0) ? BS : ' ');
	}
}


DbSpcOk (delh)				/* can we move this far by spaces? */
int delh;
{
	return (drvhpitch != 0
	    &&  abs(delh) % drvhpitch == 0
	    &&  abs(delh) / drvhpitch < 7);
}


DbTabOk (hpos)				/* can we get here with abs horiz tab? */
int hpos;
{
	return (drvhpitch != 0
	    &&  hpos % drvhpitch == 0
	    &&  hpos / drvhpitch <= 125);
}


DbMoveV (vpos)				/* vertical move */
int vpos;
{
	int delv;

	delv = vpos - drvvpos;
	if (!delv) return;
	drvvpos = vpos % pagev;
	while (delv) {
		DbSVPitch (min(delv, 125));
		OPutChar (LF);
		delv -= drvvpitch;
	}
}


DbSHPitch (hpitch)			/* set horizontal pitch */
int hpitch;
{
	if (hpitch == drvhpitch) return;
	OPutSeq (ESC, US, hpitch + 1, ENDLIST);
	drvhpitch = hpitch;
}


DbSVPitch (vpitch)			/* set vertical pitch */
int vpitch;
{
	if (vpitch == drvvpitch) return;
	OPutSeq (ESC, RS, vpitch + 1, ENDLIST);
	drvvpitch = vpitch;
}


DbSDirec (direc)			/* set print direction */
int direc;
{
	if (direc == drvdirec) return;
	OPutSeq (ESC, (direc == FORWARD) ? '5' : '6', ENDLIST);
	drvdirec = direc;
}


DbHTab (pos)				/* abs tab to pos */
int pos;
{
	OPutSeq (ESC, TAB, pos + 1, ENDLIST);
}


DbSShift (shiftp)			/* shift on or off (only for NEC 5515/25) */
FLAG shiftp;
{
	if (drvshiftp == shiftp) return;
	OPutChar (shiftp ? SO : SI);
	drvshiftp = shiftp;
}


FLAG
DbInfo (what)
int what;
{
	switch (what) {

	case OVP:					/* can it overprint? */
	case CENTCHAR:				/* does it center characters? */
	case BIDIREC:				/* does it need explicit bidirection? */
		return (TRUE);
	case BOLD:				/* can it boldface innately? */
		return (dev.boldon.len != 0);
	case ITALIC:				/* can it italic innately? */
		return (dev.italon.len != 0);
	case F1:					 /* can it font one innately? */
		return (dev.f1on.len != 0);
	case F2:					 /* can it font one innately? */
		return (dev.f2on.len != 0);
	case F3:					 /* can it font one innately? */
		return (dev.f3on.len != 0);
	default:
		Fatal ("DbInfo: unknown request\n");
	}
}


/**************** Epson driver ****************/

EpInit (vpos)
int vpos;
{
	OPutChar (CR);
	drvhpos = 0;
	drvvpos = vpos;
	drvvpitch = UNINITIALIZED;
}


EpFini()
{
	EpSVPitch (linev);
}


EpPrtMove (c, hpos, vpos)
int c, hpos, vpos;
{
	int delh, delv;

	if (c != NOCHAR) {
		OPutChar (c);
		drvhpos += DWidChar (c);
	}
	delh = hpos - drvhpos;
	delv = vpos - drvvpos;
	if (delh < 0  &&  !delv) {
		OPutChar (CR);
		delh = hpos;
	}
	while (delv) {
		EpSVPitch (min(delv, 85));
		OPutCmd (&dev.donewline);
		delv -= drvvpitch;
		delh = hpos;
	}
	while ((delh -= spaceh) >= 0) OPutChar (' ');
	drvhpos = hpos;
	drvvpos = vpos % pagev;
}


EpSVPitch (vpitch)			/* set vertical pitch */
int vpitch;
{
	if (drvvpitch == vpitch) return;
	OPutSeq (ESC, 'A', vpitch, ESC, '2', ESC, 'A', vpitch, ENDLIST);
	drvvpitch = vpitch;
}


FLAG
EpInfo (what)				/* ask about printer */
int what;
{
	switch (what) {

	case OVP:					/* can it overprint? */
		return (TRUE);
	case CENTCHAR:				/* does it center characters? */
	case BIDIREC:				/* does it need explicit bidirection? */
		return (FALSE);
	case BOLD:				/* can it boldface innately? */
		return (dev.boldon.len != 0);
	case ITALIC:				/* can it italic innately? */
		return (dev.italon.len != 0);
	case F1:					 /* can it font one innately? */
		return (dev.f1on.len != 0);
	case F2:					 /* can it font one innately? */
		return (dev.f2on.len != 0);
	case F3:					 /* can it font one innately? */
		return (dev.f3on.len != 0);
	default:
		Fatal ("EpInfo: unknown request\n");
	}
}


/**************** IDS 460 driver ****************/


IDSInit (vpos)
int vpos;
{
	drvvpos = vpos;
	drvhpos = 0;
	drvvpitch = UNINITIALIZED;
	OPutChar (CR);
}


IDSFini()
{
	IDSSVPitch (linev);
}


IDSPrtMove (c, hpos, vpos)
int c, hpos, vpos;
{
	int delh, delv;

	if (c != NOCHAR) {
		OPutChar (c);
		drvhpos += DWidChar (c);
	}
	delh = hpos - drvhpos;
	delv = vpos - drvvpos;
	while (delv) {
		IDSSVPitch (min(delv, 255));
		OPutCmd (&dev.donewline);
		delv -= drvvpitch;
		delh = hpos;
	}
	if (delh < 0) {
		OPutChar (CR);
		delh = hpos;
	}
	if (delh % spaceh) {
		IDSHTab (hpos);
		delh = 0;
	}
	while (delh >= spaceh) {
		OPutChar (' ');
		delh -= spaceh;
	}
	drvhpos = hpos;
	drvvpos = vpos % pagev;
}


IDSSVPitch (vpitch)
int vpitch;
{
	if (drvvpitch != vpitch) {
		OUnInter (6);
		OPutChar (ESC);
		OPutChar ('B');
		OPutNum (vpitch);
		OPutChar (CR);
		drvvpitch = vpitch;
	}
}


IDSHTab (pos)				/* abs horizontal tab to <pos> */
int pos;
{
	OUnInter (7);
	OPutChar (ESC);
	OPutChar ('G');
	OPutNum (pos);
	OPutChar (CR);
}


FLAG
IDSInfo (what)				/* ask about printer */
int what;
{
	switch (what) {

	case OVP:					/* can it overprint? */
		return (TRUE);
	case CENTCHAR:				/* does it center characters? */
	case BIDIREC:				/* does it need explicit bidirection? */
		return (FALSE);
	case BOLD:				/* can it boldface innately? */
		return (dev.boldon.len != 0);
	case ITALIC:				/* can it italic innately? */
		return (dev.italon.len != 0);
	case F1:					 /* can it font one innately? */
		return (dev.f1on.len != 0);
	case F2:					 /* can it font one innately? */
		return (dev.f2on.len != 0);
	case F3:					 /* can it font one innately? */
		return (dev.f3on.len != 0);
	default:
		Fatal ("IDSInfo: unknown request\n");
	}
}



/**************** Spinwriter driver ****************/


SpInit (vpos)
int vpos;
{
	drvvpos = vpos;
	drvhpos = 0;
	drvhpitch = drvvpitch = drvdirec = UNINITIALIZED;
	drvshiftp = TRUE;
	SpSHPitch (spaceh);
	SpSVPitch (linev);
	SpSDirec (FORWARD);
	SpSShift (FALSE);
}


SpFini()
{
	SpSHPitch (spaceh);
	SpSVPitch (linev);
	SpSDirec (FORWARD);
	SpSShift (FALSE);
}


SpPrtMove (c, hpos, vpos)	/* print c and move to hpos, vpos */
int c, hpos, vpos;
{
	int delh;

	delh = hpos - drvhpos;
	if (c != NOCHAR) {
		if ((!SpSpcOk (delh)  &&  !SpTabOk (hpos)  &&  abs(delh) <= 15)
		    ||  (abs(delh) == spaceh  &&  !dev.isprop))
			SpSHPitch (abs(delh));
		SpSDirec ((delh < 0) ? BACKWARD : FORWARD);
		SpSShift ((c & 128) ? TRUE : FALSE);
		OPutChar (c & 127);
		drvhpos += drvhpitch * drvdirec;
	}
	SpMoveH (hpos);
	SpMoveV (vpos);
}


SpMoveH (hpos)				/* horizontal move */
int hpos;
{
	int delh;

	delh = hpos - drvhpos;
	if (!delh) return;
	drvhpos = hpos;
	if (SpSpcOk (delh)
	    &&  (abs(delh) / drvhpitch < 4  ||  !SpTabOk (hpos))) {
		while (delh)
			if (delh * drvdirec > 0) {
				OPutChar (' ');
				delh -= drvhpitch * drvdirec;
			}
			else {
				OPutChar (BS);
				delh += drvhpitch * drvdirec;
			}
		return;
	}
	if (abs(delh) > 15  ||  SpTabOk (hpos)) {
		SpHTab (hpos / (dev.isprop ? 10 : charh));
		delh = hpos % (dev.isprop ? 10 : charh);
	}
	if (delh) {
		SpSHPitch (abs(delh));
		OPutChar ((delh * drvdirec < 0) ? BS : ' ');
	}
}


SpSpcOk (delh)				/* can we move this far by spaces? */
int delh;
{
	return (drvhpitch != 0
	    &&  abs(delh) % drvhpitch == 0
	    &&  abs(delh) / drvhpitch < 10);
}


SpTabOk (hpos)				/* can we get here with abs horiz tab? */
int hpos;
{
	return (hpos % (dev.isprop ? 10 : charh) == 0);
}


SpMoveV (vpos)				/* vertical move */
int vpos;
{
	int delv;

	delv = vpos - drvvpos;
	if (!delv) return;
	drvvpos = vpos % pagev;
	/* this ought to do abs vertical tab ??? */
	while (delv) {
		SpSVPitch (min(delv, 16));
		OPutChar (LF);
		delv -= drvvpitch;
	}
}


SpSHPitch (hpitch)			/* set horizontal pitch */
int hpitch;
{
	if (hpitch == drvhpitch) return;
	OPutSeq (ESC, ']', hpitch + '@', ENDLIST);
	drvhpitch = hpitch;
}


SpSVPitch (vpitch)			/* set vertical pitch */
int vpitch;
{
	if (vpitch == drvvpitch) return;
	OPutSeq (ESC, ']', vpitch + 'O', ENDLIST);
	drvvpitch = vpitch;
}


SpSDirec (direc)			/* set print direction */
int direc;
{
	if (direc == drvdirec) return;
	OPutSeq (ESC, (direc == FORWARD) ? '>' : '<', ENDLIST);
	drvdirec = direc;
}


SpHTab (pos)				/* abs tab to pos */
int pos;
{
	OPutSeq (ESC, pos / 32 + 'P', pos % 32 + '@', ENDLIST);
}


SpSShift (shiftp)			/* shift on or off */
FLAG shiftp;
{
	if (drvshiftp == shiftp) return;
	OPutChar (shiftp ? SO : SI);
	drvshiftp = shiftp;
}


FLAG
SpInfo (what)
int what;
{
	switch (what) {

	case OVP:					/* can it overprint? */
	case CENTCHAR:				/* does it center characters? */
	case BIDIREC:				/* does it need explicit bidirection? */
		return (TRUE);
	case BOLD:				/* can it boldface innately? */
		return (dev.boldon.len != 0);
	case ITALIC:				/* can it italic innately? */
		return (dev.italon.len != 0);
	case F1:					 /* can it font one innately? */
		return (dev.f1on.len != 0);
	case F2:					 /* can it font one innately? */
		return (dev.f2on.len != 0);
	case F3:					 /* can it font one innately? */
		return (dev.f3on.len != 0);
	default:
		Fatal ("SpInfo: unknown request\n");
	}
}



/**************** Centronics driver ****************/

CenInit (vpos)
int vpos;
{
	OPutChar (CR);
	drvhpos = 0;
	drvvpos = vpos;
}


CenFini()
{
}


CenPrtMove (c, hpos, vpos)
int c, hpos, vpos;
{
	int delh, delv;

	if (c != NOCHAR) {
		OPutChar (c);
		drvhpos += DWidChar (c);
	}
	delh = hpos - drvhpos;
	delv = vpos - drvvpos;
	while (delv >= linev) {
		OPutChar (LF);
		delv -= linev;
	}
	if (delv == linev / 2) OPutSeq (ESC, 28, ENDLIST);/* half line feed */
	if (delh < 0) {
		OPutChar (CR);
		delh = hpos;
	}
	while (delh >= spaceh) {
		OPutChar (' ');
		delh -= spaceh;
	}
	while (delh > 0) {
		OPutSeq (ESC, min(delh, 6), ENDLIST);
		delh -= min(delh, 6);
	}
	drvhpos = hpos;
	drvvpos = vpos % pagev;
}


FLAG
CenInfo (what)				/* ask about printer */
int what;
{
	switch (what) {

	case OVP:					/* can it overprint? */
		return (TRUE);
	case CENTCHAR:				/* does it center characters? */
	case BIDIREC:				/* does it need explicit bidirection? */
		return (FALSE);
	case BOLD:				/* can it boldface innately? */
		return (dev.boldon.len != 0);
	case ITALIC:				/* can it italic innately? */
		return (dev.italon.len != 0);
	case F1:					 /* can it font one innately? */
		return (dev.f1on.len != 0);
	case F2:					 /* can it font one innately? */
		return (dev.f2on.len != 0);
	case F3:					 /* can it font one innately? */
		return (dev.f3on.len != 0);
	default:
		Fatal ("CenInfo: unknown request\n");
	}
}

/**************** C. ITOH 8510 driver ****************/

CitInit (vpos)
int vpos;
{
	OPutChar (CR);
	drvhpitch = drvvpitch = drvdirec = UNINITIALIZED;
	drvhpos = 0;
	drvvpos = vpos;
}


CitFini()
{
}


CitPrtMove (c, hpos, vpos)
int c, hpos, vpos;
{
	int delh, delv;

	if (c != NOCHAR) {
		OPutChar (c);
		drvhpos += DWidChar (c);
	}
	delh = hpos - drvhpos;
	delv = vpos - drvvpos;

	while (delv >= linev) {
		OPutChar (LF);
		delv -= linev;
	}


	/* half line feed */ 
	if (delv == linev / 2){
		if (dev.stdvert>420 && dev.stdvert<430) {	/* 6 lines per inch */
			CitSVPitch(12);
			OPutChar(LF);
			CitSVPitch(24);		/* 24/144 inch = 1/6 */
		}
		else {				/* 8 lines per inch */
			CitSVPitch(9);
			OPutChar(LF);
			CitSVPitch(18);		/* 18/144 inch = 1/8 */
		}
	}

	if (delh < 0) {
		OPutChar (CR);
		delh = hpos;
	}

	while (delh >= spaceh) {
		OPutChar (' ');
		delh -= spaceh;
	}	
	/* incremental positioning */
	/*	while (delh > 0) {
				OPutSeq (ESC, min(delh + '0' , 6 + '0'), ENDLIST);
				delh -= min(delh, 6);
				}
		*/
	/* use absolute positioning */
	if (delh > 0) {
		OUnInter(6);
		OPutChar(ESC);
		OPutChar('F');
		if (hpos < 1000) OPutChar('0');
		if (hpos < 100) OPutChar('0');
		if (hpos < 10) OPutChar('0');
		OPutNum(hpos);
	}

	drvhpos = hpos;
	drvvpos = vpos % pagev;
}

CitSVPitch (vpitch)			/* set vertical pitch */
int vpitch;
{
	if (vpitch == drvvpitch) return;
	OPutSeq (ESC, 'T' , vpitch / 10 + '0', vpitch % 10 + '0', ENDLIST);
	drvvpitch = vpitch;
}


FLAG
CitInfo (what)				/* ask about printer */
int what;
{
	switch (what) {

	case OVP:					/* can it overprint? */
		return (TRUE);
	case CENTCHAR:				/* does it center characters? */
	case BIDIREC:				/* does it need explicit bidirection? */
		return (FALSE);
	case BOLD:				/* can it boldface innately? */
		return (dev.boldon.len != 0);
	case ITALIC:				/* can it italic innately? */
		return (dev.italon.len != 0);
	case F1:					 /* can it font one innately? */
		return (dev.f1on.len != 0);
	case F2:					 /* can it font one innately? */
		return (dev.f2on.len != 0);
	case F3:					 /* can it font one innately? */
		return (dev.f3on.len != 0);
	default:
		Fatal ("CitInfo: unknown request\n");
	}
}


BCopy()
{
	puts("Produced and directed by Barry A. Dobyns 1981, 1982");
}

/* End of DRIVER.C  --  specialized printer drivers */
