/* PSPage.C
 *
 *      Title:          PSPAGE
 *                      Henry Burgess
 *                      Copyright Microsoft Corp, 1985
 *                      July 4, 1985
 *
 *      Description:
 *                      This module contains the font table and the routine
 *                      that accesses it.  It might also be OEM configurable.
 *
 *==========================================================================
 * Modification History:
 *--------------------------------------------------------------------------
 *      9/11/85                 Modified to adopt to the banner program.
 *
 *      4/20/86 MJH             Adapt to lpr, page handling module.
 *
 *      3/3/89 Robert Hess      Version 2.9
 *                              Completely re-wrote PostScript support.
 *
 */



#include <windef.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "lpr.h"


char        page[rowMax][colMax+1];    /* image of one printer page          */


/*
 * the following defines the bits in the character font
 */
unsigned char Font_Bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,         /* 00  */
0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,         /* 01  */
0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,         /* 02  */
0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,         /* 03  */
0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,         /* 04  */
0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,         /* 05  */
0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,         /* 06  */
0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,         /* 07  */
0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,         /* 08  */
0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,         /* 09  */
0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,         /* 0a  */
0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,         /* 0b  */
0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,         /* 0c  */
0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,         /* 0d  */
0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,         /* 0e  */
0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,         /* 0f  */
0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,         /* 10  */
0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,         /* 11  */
0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,         /* 12  */
0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,         /* 13  */
0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,         /* 14  */
0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,         /* 15  */
0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,         /* 16  */
0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,         /* 17  */
0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,         /* 18  */
0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,         /* 19  */
0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,         /* 1a  */
0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,         /* 1b  */
0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,         /* 1c  */
0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,         /* 1d  */
0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,         /* 1e  */
0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,         /* 1f  */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,         /* 20  */
0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,         /* 21 ! */
0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,         /* 22 " */
0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,         /* 23 # */
0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,         /* 24 $ */
0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,         /* 25 % */
0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,         /* 26 & */
0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,         /* 27 ' */
0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,         /* 28 ( */
0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,         /* 29 ) */
0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,         /* 2a * */
0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,         /* 2b + */
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,         /* 2c , */
0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,         /* 2d - */
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,         /* 2e . */
0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,         /* 2f / */
0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,         /* 30 0 */
0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,         /* 31 1 */
0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,         /* 32 2 */
0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,         /* 33 3 */
0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,         /* 34 4 */
0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,         /* 35 5 */
0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,         /* 36 6 */
0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,         /* 37 7 */
0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,         /* 38 8 */
0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,         /* 39 9 */
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,         /* 3a : */
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,         /* 3b ; */
0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,         /* 3c < */
0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,         /* 3d = */
0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,         /* 3e > */
0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,         /* 3f ? */
0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,         /* 40 @ */
0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,         /* 41 A */
0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,         /* 42 B */
0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,         /* 43 C */
0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,         /* 44 D */
0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,         /* 45 E */
0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,         /* 46 F */
0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,         /* 47 G */
0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,         /* 48 H */
0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,         /* 49 I */
0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,         /* 4a J */
0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,         /* 4b K */
0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,         /* 4c L */
0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,         /* 4d M */
0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,         /* 4e N */
0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,         /* 4f O */
0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,         /* 50 P */
0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,         /* 51 Q */
0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,         /* 52 R */
0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,         /* 53 S */
0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,         /* 54 T */
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,         /* 55 U */
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,         /* 56 V */
0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,         /* 57 W */
0xc6, 0x6c, 0x38, 0x10, 0x38, 0x6c, 0xc6, 0x00,         /* 58 X */
0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,         /* 59 Y */
0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,         /* 5a Z */
0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,         /* 5b [ */
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,         /* 5c \ */
0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,         /* 5d ] */
0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,         /* 5e ^ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,         /* 5f _ */
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,         /* 60 ` */
0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,         /* 61 a */
0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,         /* 62 b */
0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,         /* 63 c */
0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,         /* 64 d */
0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,         /* 65 e */
0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,         /* 66 f */
0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,         /* 67 g */
0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,         /* 68 h */
0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,         /* 69 i */
0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,         /* 6a j */
0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,         /* 6b k */
0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,         /* 6c l */
0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,         /* 6d m */
0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,         /* 6e n */
0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,         /* 6f o */
0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,         /* 70 p */
0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,         /* 71 q */
0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,         /* 72 r */
0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,         /* 73 s */
0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,         /* 74 t */
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,         /* 75 u */
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,         /* 76 v */
0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,         /* 77 w */
0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,         /* 78 x */
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,         /* 79 y */
0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,         /* 7a z */
0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,         /* 7b { */
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,         /* 7c | */
0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,         /* 7d } */
0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,         /* 7e ~ */
0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00          /* 7f   */
};



void block_flush(sz, rowTopLeft, colTopLeft)
/*** do the actual block printing of sz to the page. */
char        sz[];
int         rowTopLeft, colTopLeft;
    {
    int      row, col, ich;
    register unsigned char c;
    char     chFill;

    if ((sz == NULL) || (sz[0] == '\0'))
	    return;

    for (row =0; row < 8; row++)
	{                      /* 8 lines */
	for (ich = 0; sz[ich] != '\0'; ich++)
	    {         /* characters in string */
	    /*
	    * find this character in the font table
	    * and byte for this row  ( + i )
	    */
	    c = Font_Bits[((unsigned)sz[ich] << 3) + row];

	    if (chBanner<=' ')
		if (isprint(sz[ich]))
	  	    chFill = sz[ich];
		else chFill = 'X';
	    else
		chFill = chBanner;

	    for (col = 0; col < 8; col++)
		{      /* bits in a byte */
		page[rowTopLeft + row][colTopLeft + (ich << 3) + col] =
                      (char)(((int)c & 0x80) ? chFill : ' ');
                c = (unsigned char)((int)c << 1);
		}
	    }
	}
    }




void VertLine(char ch, int colAt, int rowMin, int rowMac)
    {
    register int row;

    for (row = rowMin; row < rowMac; page[row++][colAt] = ch)
	;
    }




void HorzLine(char ch, int rowAt, int colMin, int colMac)
    {
    register int  col;

    for (col = colMin; col < colMac; page[rowAt][col++] = ch)
	;
    }




void FillRectangle(char ch, int rowTopLeft, int colTopLeft, int rowBotRight, int colBotRight)
    {
    register int  col, row;

    for (row = rowTopLeft; row < rowBotRight; row++)
	{
        for (col = colTopLeft; col < colBotRight; col++)
            page[row][col] = ch;
        }
    }




void WriteSzCoord(sz, row, col)
register char *sz;
int   row, col;
    {
    register char *pch;

    for (pch = &page[row][col]; *sz != '\0'; *pch++ = *sz++)
	;
    }




void OutCmpLJ(szO,cchO)
/*  Accept a string, szO, of length cchO and remove runs of seven or
    more spaces by replacing them with a control sequence to move the
    printer head on the HP Laser Jet.

    ESC&a+#C   moves the head # places to the right.

    NOTE: this is very similar to OutCmpPS().
*/
char *szO;
int cchO;
    {
    register int cchB;
    char chO;
    register char *pchB;
    char szMove[10];

    chO = szO[cchO];		/* save for later restore */
    szO[cchO] = '\0';		/* Make sure 0 terminated string. */

    while (*szO != '\0')
        {
	pchB = szO;
	while ((pchB=strchr(pchB, ' ')) != 0 && (cchB=strspn(pchB, " ")) < 7)
		pchB += cchB;

	if (pchB != 0)
		{
		/* found a run of blanks of 7 or more */
		if (szO != pchB)
			{
			/* output other stuff until pchB */
			OutLPR(szO, (int)(pchB-szO));
			szO = pchB;
			}
		
		/* output run of blanks as ESC&a+#C */
		sprintf(szMove, "\033&a+%dC", cchB);
		OutLPR(szMove, 0);
		szO += cchB;
		}
	else
		{
		/* no run of blanks; output all and terminate loop */

		cchB = strlen(szO);		/* not really blanks (!) */
		OutLPR(szO, cchB);
		szO += cchB;
		}
	}
    *szO = chO;		/* restore */
    }



void OutEncPS(pchF, cchF)
/* output PostScript substring quoting *nothing* */
register char *pchF;
int cchF;
{
    register char *pchT;
    int cchT;
    char rgbT[1+colMax*2+5];/* enough for every character to be encoded */

    pchT = rgbT;
    cchT = 0;
    while (cchF-- > 0) {
	switch(*pchF++) {
	    default:
		*pchT++ = *(pchF-1);
		cchT++;
		break;
	}
    }
    *pchT = '\n'; cchT++;	   /* end of PostScript string */

    OutLPR(rgbT, cchT);
}


void OutCmpPS(szO,cchO)
/*  Accept a string, szO, of length cchO.

    # sp   moves the head # places to the right (local definition).

    NOTE: this is VERY similar to OutCmpPS().
*/
char *szO;
int cchO;
    {
    register int cchB;
    char chO;
    register char *pchB;

    chO = szO[cchO];		/* save for later restore */
    szO[cchO] = '\0';		/* Make sure 0 terminated string. */
    while (*szO != '\0') {
	pchB = szO;
	cchB = strlen(szO);		/* not really blanks (!) */
	OutEncPS (szO, cchB);
	szO += cchB;
    }
    *szO = chO;		/* restore */
}




int CchNoTrail(rgch,cch)
/* returns the number of characters in a line of text without counting
   trailing blanks*/
char rgch[];
int cch;
    {
    register char *pch;

    for (pch = rgch + cch - 1; pch >= rgch && *pch==' ';pch--)
         ;
    return ((int)((pch + 1) - rgch));
    }




void OutRectangle(rowMin, colMin, rowLim, colLim)
/* output rectangle of page triming blank lines and blanks from the ends of
   lines
*/
int rowMin, colMin, rowLim, colLim;
    {
    int row;
    int ccol = colLim - colMin;

    while (rowLim > rowMin && CchNoTrail(&page[rowLim-1][colMin], ccol) == 0)
	rowLim--;

    for (row = rowMin; row < rowLim; row++)
	{
	register char *pch = &page[row][colMin];
	int cch = CchNoTrail(pch, ccol);

	if (cch != 0)
	    {
	    if (fLaser)
		OutCmpLJ(pch, cch);
	    else if (fPostScript) {
		OutCmpPS(pch, cch);
	    } else
		OutLPR(pch, cch);
	    }
        else if (fPostScript) {
	    OutCmpPS (" ", 1);
	}
        if (!fPostScript)
	    OutLPR(row==rowLim - 1 ? "\r" : "\r\n", 0);
	}
    }
