/*
 * P_R_P_Q_# (C) COPYRIGHT: NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:prfl.c 12.0$ */
/* $ACIS:prfl.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/proff/RCS/prfl.c,v $ */

#ifndef lint
static char *rcsid = "$Header:prfl.c 12.0$";
#endif

/* 
 * This program was derived from publicly available sources posted to 
 * USENET net.sources on October 30, 1985 by John Nellen, Delft University
 * of Technology, under the subject of "Epson filter to type nroff 
 * non-ASCII chars".  The original program was called epf.c. 
 */

#include <stdio.h>
#include "proff.h"
#define	ESC	033
#define DC2	022

struct pro_font {
	int	loaded;
	char	attribute;
	char	col[11];
};
#define bound(c,limit) (c < 0 ? limit-1 : c < limit ? c : limit -1)

/* variables for output filters */
char	*name;		/* user's login name */
char	*host;		/* user's machine name */
char	*acctfile;	/* accounting information file */
int	lineno = 0; 
int	colno = 0;
int	npages = 0;
int	width = 80;	/* line length */
int	length = 66;	/* page length */

#include "fonts/special.font"
int nfont = sizeof(font) / sizeof(font[0]);
#ifdef ITALIC
#include "fonts/italic.font"
int nifont = sizeof(ifont) / sizeof(ifont[0]);
#endif

main (argc,argv) char *argv[]; 
{
	register int count,c;
	register char *cp;
	int	italic;
	int  	curchar;
	int 	offset;
	int	gflag=0;

	while (--argc) {
		if (*(cp = *++argv) == '-') {
			switch (cp[1]) {
		 	/* flag to indicate IBM 5152 printer */
			case 'g':
				gflag++;
				break;
			/*
			 * The remaining flags are needed for prfl to meet
			 * output filter specifications 
 			 */
			case 'n':
				argc--;
				name = *++argv;
				break;

			case 'h':
				argc--;
				host = *++argv;
				break;

			/* next two are ditroff/troff options -- ignore */
			case 'x':
				break;

			case 'y':
				break;

			default:
				break;
			}
		} else
			acctfile = cp;
	}

	curchar = getchar ();
	while (curchar != EOF) {
		count=0;
		italic=0;

/* treat _^Hc as an italic c. If ITALIC has been defined, used the
 * italic font, otherwise use continuous underscore mode to print the
 * underscores (the graphics printer can't backspace)
 */
		while (curchar == '_')	
			if ((c=getchar()) =='\b') {  
				c=getchar();
				/* Don't continuous-underscore 
				an escape sequence */
				if (c == ESC) {	
					if (!gflag) {
						putchar('_');
						putchar('\b');
					}
					curchar=c;
					break;
				}
#ifdef ITALIC	
				/* if ITALIC load the italic font */
				if ((!ifont[bound(c-'0',
						nifont)].loaded) || gflag) {
					if (gflag) {
					/* go to 1/2 speed 960 column    */
					 /* graphics mode for 12 columns */
					  /* (1 character)               */
						putchar(ESC);
						putchar('L');
						putchar(12);
					} 
					else {
					 /* download italic character    */
						putchar(ESC);
						putchar('=');
						putchar(15);
						putchar(0);
						putchar(20);
						putchar(c); 
						/* 
						 * let the special font know
						 * that its corresponding
						 * character has been trashed
						 */
						font[bound(c,nfont)].loaded=0;
						putchar(ifont[bound(c-'0', 
							nifont)].attribute);
					}
					putchar(0);
					for (count=0; count < 11; count++)
						putchar(ifont[bound(c-'0', 
							nifont)].col[count]);
					if (gflag) {
						putchar(0);
					}
				}
				if ((italic==0) && (gflag==0)) {
					putchar(ESC);	/* use alternate font */
					putchar('I');
					putchar(6);
				}
#else !ITALIC
				if (italic==0) {
					 /* turn on continuous underscore */
					putchar(ESC); 
					putchar('-');
					putchar(1);
				}
#endif !ITALIC
				italic++;
#ifdef ITALIC
				if (!gflag)
#endif ITALIC
					putchar(c);
				account(c);	/* accounting data */
				curchar=getchar();
			} 
			else {
				/* underscore found not followed by ^H */
				putchar('_');
				curchar=c;
			}

#ifdef ITALIC
		if ((italic!=0) && (gflag==0)) {
			putchar(ESC); /* select normal font */
			putchar('I');
			putchar(2);
		}
#else !ITALIC
		if (italic) {
			putchar(ESC);   /* turn off continuous underscore */
			putchar('-');
			putchar(0);
		}
#endif !ITALIC
		if (curchar == ESC) {
			c = getchar();
			offset = 0;
			switch (c) {
				/*
				 *  ESC 9 half space linefeed
				 *  (this is the only 2 character
				 *  escape sequence this filter understands;
				 *  all others are three characters long)
				 */
			case '9':
				putchar(ESC);
				putchar('J');
				putchar(18);
				break;

				/* ESC A x are control sequences.
				 (all non-printing) */ 
			case 'A':
				c=getchar();
				switch (c) {
					/* nroff initilization */
				case CHR_INIT: 
					putchar (ESC);
					putchar ('G');		 /* NLQ */
					if (!gflag) {
						putchar (ESC);
						putchar (':');	/* 12 char/in */
					}
					break;
				case CHR_REST: 
					putchar (ESC);
					putchar ('F');	/* Bold off */
					putchar (ESC);
					putchar('T');	/* Cancel super-
							 and sub-script */
					break;
				case CHR_SUPON: 
					putchar (ESC);
					putchar ('S');	 /* Superscript */
					putchar (0);
					break;
				case CHR_SUBON: 
					putchar (ESC);
					putchar ('S');	/* Subscript */
					putchar (1);
					break;
				case CHR_SCROF:		/* Cancel scripting */
					putchar(ESC);
					putchar('T');
					break;
				case CHR_BDON: 
					putchar (ESC);
					putchar ('E');	 /* Bold on */
					break;
				case CHR_BDOF: 
					putchar (ESC);
					putchar ('F');	 /* Bold off */
					break;
				default:
					putchar(ESC);    /* pass unknown code */
					putchar('A');
					putchar(c);
				}
				break;

/* ESC B and ESC C indicate output of a downloaded-font character. 
 * These are sequenced as ESC BA through ESC BZ, and ESC CA onward.
 * Add additional characters to the ESC C set. Fonts for these are found  
 * in fonts/special fonts which is automatically built from code.pro.
 */
			case 'C':
				offset = 'Z'-'A'+1;
			case 'B':
				c=getchar();
				c=(c-'A')+offset;
				/*
				 *  Load font if not already loaded 
				 *  (Just use graphics mode for
				 *  graphics printer)
				 */
				if ( (!font[bound(c,nfont)].loaded) ||
						 (gflag)) {
					if (!gflag) {
						/* download a single char */
						putchar(ESC);
						putchar('=');
						putchar(15);
						putchar(0);
						putchar(20);
						/* charcter code: */
						putchar(c+PDLOFFST);
#ifdef ITALICS
						/* let italics know its
						 * corresponding character
						 * has been zapped.
						 */
						ifont[bound(c+PDLOFFST-'0',
							nifont)].loaded=0;
#endif ITALICS
						putchar(font[bound(c,
							nfont)].attribute);
					} 
					else {
						/*
						 * Enter 1/2 speed 960-bit
						 * graphics for 12 bits
						 * (1 character)
						 */
						putchar(ESC);
						putchar('L');
						putchar(12);
					}
					putchar(0);
					for (count=0; count < 11; count++)
						putchar(font[bound(c,
							nfont)].col[count]);
					count=0;
					if (gflag) {
						putchar(0);
					}
				}
				/*
				 *  If not gflag, select downloaded font
				 *  and print character
				 * (if the gflag was set, the character
				 *  has already been printed in
				 *  graphics mode) 
				 */
				if (!gflag) {
					/* select downloaded font */
					putchar(ESC);
					putchar('I');
					putchar(6);
					/* print character */
					putchar(c+PDLOFFST);
					putchar(ESC);	/* deselect downloaded
							  font */
					putchar('I');
					putchar(0);
				}
				account(c);	/* accounting data */
				break;
/* ESC D x prints the character 'x+130'. The table on pages 4-36 and 4-37 of
 * the Proprinter Guide to Operations facilitated conversions from x to
 * the actual character printed (by matching rows and columns). The 
 * characters on page 4-36 are used for x, and the characters on page 4-37
 * are the desired special characters to be printed. 
 */
			case 'D':
				c=getchar();
				putchar(c+130);
				account(' ');	/* accounting data */
				break;
/* ESC E prints a character from the "all characters" table. NOTE: if
 * the character exists on the "all characters" table, but not the
 * character set 2 table, the character will not be printed on the
 * graphics printer. (The references tables are on pages 4-38 to
 * 4-41 of the Proprinter Guide to Operations.)
 */
			case 'E':
				c=getchar();
				putchar(ESC);
				if (gflag) 
					putchar('6');
				else
					putchar('^');
				putchar(c);
				account(' ');	/* accounting data */
				break;
/* ESC F is a mixture of ESC D and ESC E. It prints x+130 in the 
 * "all characters" font. Comments for ESD D and ESC E are all
 * applicable to ESC F.
 */
			case 'F':
				c=getchar();
				putchar(ESC);
				if (gflag) 
					putchar('6');
				else
					putchar('^');
				putchar(c+130);
				account(' ');	/* accounting data */
				break;
/* Some unassigned ESC sequence. Send it on through to the printer */
			default:
				putchar(ESC);
				putchar (c);
			} /* switch c */
		} 
		else {
			putchar (curchar);
			account(curchar);	/* accounting data */
		}
		curchar = getchar ();
	}
	/* put printer back in normal mode */
	putchar (ESC);
	putchar ('H');				 /* NLQ off */
	putchar (ESC);
	putchar ('F');				 /* Bold off */
	putchar (ESC);
	putchar('T');				 /* Cancel super/sub script */
	putchar(DC2);				 /* 10 cpi */

	/* finish by reporting accounting information */
	if (colno || lineno) {	/* be sure to end on a page boundary */
		npages++;
	}
	if (name && acctfile && access(acctfile, 02) >= 0 &&
	    freopen(acctfile, "a", stdout) != NULL) {
		printf("%7.2f\t%s:%s\n", (float)npages, host, name);
	}
	exit(0);
}

account(c)
	int c;
{	
	if ((c == '\n') || (++colno >= width)) {
		lineno++;
		colno = 0;
	}
	if (c == '\f')	{
		npages++;
		lineno = 0;
		colno = 0;
	}
	if (lineno >= length) {
		npages++;
		lineno = 0;
	}
}
