nroff for Printronix 300

gwyn%brl-vld at sri-unix.UUCP gwyn%brl-vld at sri-unix.UUCP
Thu Sep 15 04:40:19 AEST 1983


From:      Doug Gwyn (VLD/VMB) <gwyn at brl-vld>

FOR Deborah Brown (deb at mitre or brown at mitre):

I apologize for sending this to the mailing list, but "mitre" did
not appear to be a known ARPAnet host name to our mailing system.
Perhaps someone else can use this too.

The following code, a module from the MDQS spooling system, does
the right thing with funny characters for printers that know how
to CR-overstrike.  All you need now is a very small driver program
to invoke the function.


/*
	copyn - transcribe arbitrary input file to stdout (for MDQS)
		[ASCII line printer version]

	last edit:	27-Mar-1983	Douglas A. Gwyn  <gwyn at BRL-VLD>

Acknowledgement:
	Derived from John S. Quarterman's "reline" utility.

Method:
	Uses buffered overstrike lines (text, CR, text) as necessary.
	Suboptimal in some ways, but works well in typical usage --
	particularly for "nroff" emboldened and underlined output.
	The idea is to minimize overhead for simple printouts.

Assumptions:
	ASCII host character set.
	Printer understands LF, FF, and CR (not true of Versatec).

Configuration Notes:
	If all lp output passes through here (highly recommended), then
	your lp driver can be changed to not examine characters as they
	go by.	This reduces kernel size and improves system loading.
	Hard-coded "indent" offset should be removed, since tractor
	positioning accomplishes the same thing more cheaply.  However,
	if "indent" is ioctl-settable, the driver must notice LF, FF,
	and CR.  If there is a user page quota imposed, LF and FF must
	be counted (note that MDQS provides a better handle for this).
	Perforation skipping should not be performed, as it interferes
	with text-processing software.	It would be nice if consecutive
	FFs would only cause one page advance, and FF should be done on
	device open when not already at top of form (the latter is best
	done by counting LFs as well as remembering FFs).

IMPORTANT!
	If you are using an old-fashioned UNIX, define "V7".
	This is not necessary for UNIX System III and later.
*/

/* #define V7 */

#include	<ctype.h>
#include	<stdio.h>

/*
	Adjustable parameters:
*/
#define MAXOVER 	3		/* max. number of overstrikes */
#define MAXLINE 	132		/* maximum printer line width */
#define PAGE		66		/* nominal page size for FF   */
#define TABS		8		/* standard tab stop interval */

/*
	Non-spacing control characters are shown in DEC style, e.g. ^X.
	ASCII DEL is shown as ^?.
	Meta-characters (those with bit 7 set) are shown as ~X or ~^X.
	(Note that all these unavoidably mess up horizontal spacing.)
*/
#define METAPFX 	'~'		/* meta-char prefix    */
#define CTRLPFX 	'^'		/* control-char prefix */
#define DELSYMB 	'?'		/* DEL-char indicator  */

#ifdef	V7
typedef int		void;
#endif
typedef int		bool;		/* boolean data type */
typedef unsigned short	ushort;

/*
	The following rules apply to the overstruck line buffers:
	     o	Higher buffers are not longer than lower ones.
	     o	High-water mark points past the last non-space slot.
	     o	0 <= high <= MAXLINE
*/
typedef struct
	{
	ushort	high;			/* buffer dirty mark */
	char	buf[MAXLINE + 1];	/* character buffer  */
	}	strike; 		/* overstruck line buffer */

static strike	linebuf[MAXOVER + 1] = { 0 };	/* overstruck lines  */
static strike	*line = &linebuf[0];		/* current buffer    */
static strike	*last = &linebuf[0];		/* highest line used */

static ushort	ccol = 0;		/* current column position */

static void	ctrlchar(), normchar(), outflush();


long
copyn( fp, llimit )			/* returns # input lines done,
					   no more than llimit+PAGE-1 */
	register FILE	*fp;		/* input stream     */
	long		llimit; 	/* input line limit */
	{
	long		lcount; 	/* counts input lines	      */
	bool		chklim; 	/* whether to test line limit */
	register int	c;		/* input character	      */

	{
	register strike *str;		/* addresses buffers */

	for ( line = last = str = &linebuf[0];
	      str <= &linebuf[MAXOVER];
	      ++str
	    )
		str->high = 0;		/* initially, all lines empty */
	}
	ccol = 0;

	if ( chklim = llimit != 0L )
		lcount = 0L;

	while ( (c = getc( fp )) != EOF )
#ifdef	V7
		/*	This test is done first because old-fashioned
			UNIXes don't have the large ctype table.      */
		if ( !isascii( c ) )		/* meta-character */
			{
			normchar( METAPFX );
			c = toascii( c );
			if ( iscntrl( c ) || isspace( c ) && c != ' ' )
				ctrlchar( c );	/* meta-control   */
			else
				normchar( c );	/* meta-normal	  */
			}

		/*	The rest of these are in descending order of
			expected frequency of occurrence.	      */
		else if ( isprint( c ) || c == ' ' )
#else
		if ( isprint( c ) )	/* (includes SP) */
#endif
			normchar( c );

		else if ( c == '\t' )
			do
				normchar( ' ' );/* ++ccol side-effect */
			while ( ccol % TABS != 0 );

		else if ( c == '\n' )
			{
			outflush( c );
			if ( chklim && ++lcount == llimit )
				return lcount;	/* ran into limit */
			}

		else if ( c == '\b' || c == '\r' )
			{		/* reverse pseudo-motions  */
			register ushort col;	/* temp for `ccol' */
		
			if ( c == '\r' )
				col = 0;
			else		/* BS */
				if ( (col = ccol) != 0 )
					--col;	/* but not past edge */
		
			if ( col < linebuf[MAXOVER].high )
				outflush( '\r' );	/* make room */

			while ( col < line->high
			     && line < &linebuf[MAXOVER]
			      ) {
				++line; /* find clean buffer tail */
				if ( line > last )
					last = line;	/* new buffer */
				}
		
			ccol = col;
			}

		else if ( c == '\f' )
			{
			outflush( c );
			if ( chklim )
				{
				lcount += PAGE - lcount % PAGE;
				if ( lcount >= llimit )
					return lcount;	/* limit */
				}
			}
#ifdef V7
		else			/* random control character */
#else
		else if ( iscntrl( c ) /* && not already dealt with */ )
#endif
			ctrlchar( c );	/* control character */
#ifndef V7
		else	{			/* meta-character */
			normchar( METAPFX );
			c = toascii( c );
			if ( iscntrl( c ) || isspace( c ) && c != ' ' )
				ctrlchar( c );	/* meta-control   */
			else
				normchar( c );	/* meta-normal	  */
			}
#endif

	outflush( 0 );			/* flush leftovers */
	return lcount;
	}


static void
ctrlchar( c )				/* buffer mapped control char */
	int		c;		/* control character */
	{
	normchar( CTRLPFX );
	normchar( (c == 0177) ? DELSYMB : c + 0100 );
	}


static void
normchar( c )				/* buffer printing char */
	int		c;		/* character to stash	*/
	{
	register ushort col = ccol++;	/* initial column location */

	if ( col < MAXLINE && c != ' ' /* i.e., a "dirt" char */ )
		{
		register ushort top = line->high;

		while ( top < col )
			line->buf[top++] = ' '; /* catch up */
		line->buf[col] = c;

		if ( col >= line->high )
			line->high = ccol;
		}

	while ( line > &linebuf[0] && ccol >= (line - 1)->high )
		--line; 		/* previous buffer usable */
	}


static void
outflush( c )				/* dump overstrike buffers */
	int		c;		/* LF, FF, CR, or 0 [on EOF] */
	{
	register strike *str;		/* addresses buffers */

	for ( str = &linebuf[0]; ; ++str )
		{
		str->buf[str->high] = '\0';
		(void)fputs( str->buf, stdout );

		if ( str != last )
			putchar( '\r' );	/* prepare overprint */
		else	{
			if ( c != 0 )
				putchar( c );	/* LF, FF, or CR */
			break;
			}
		}

	for ( str = &linebuf[0]; str <= last; ++str )
		str->high = 0;		/* clear used lines */
	line = last = &linebuf[0];
	ccol = 0;
	}



More information about the Comp.unix.wizards mailing list