[alt.sources] colpr - yet another printer filter

chip@vector.Dallas.TX.US (Chip Rosenthal) (08/24/89)

Oh no...another printer underlining filter!!

"Colpr" performs a number of filtering functions useful in printer
interfaces.  These include:

    - backspace to overstrike translation
    - long line folding/truncation
    - newline to CR/LF translation
    - 8-bit character generation

There are probably a zillion programs in the comp.sources.all archives
which perform the first three functions.  Your system probably already
has one or more of them.  However, the last feature gives you a way to
squeeze 8-bit graphic characters out of utilities which only produce
7-bit characters, e.g. old nroff.

I use this feature with the SCO XENIX nroff to gain access to the full
character set of the HP LaserJet printer.  I mentioned my "tablj" nroff
driver table for the LaserJet in comp.unix.xenix recently, and had several
requests for it.

Well, you need "colpr" first and here it is.  With any sort of luck, I
will try to get the "tablj" stuff out in a week or so.

--- cut here -----------------------------------------------------------------
#! /bin/sh
# this is a "shar" archive - run through "/bin/sh" to extract 4 files:
#   README colpr.c colpr.man Makefile
# Wrapped by bin@vector on Wed Aug 23 23:04:59 CDT 1989
# Unpacking this archive requires:  sed test wc (possibly mkdir)
# Existing files will not be clobbered unless "-c" is specified on the cmd line.
if test -f README -a "$1" != "-c" ; then
    echo "README: file exists - will not be overwritten"
else
    echo "x - README (file 1 of 4, 1045 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_README' > README
XOh no...another printer underlining filter!!
X
X"Colpr" performs a number of filtering functions useful in printer
Xinterfaces.  These include:
X
X    - backspace to overstrike translation
X    - long line folding/truncation
X    - newline to CR/LF translation
X    - 8-bit character generation
X
XThere are probably a zillion programs in the comp.sources.all archives
Xwhich perform the first three functions.  Your system probably already
Xhas one or more of them.  However, the last feature gives you a way to
Xsqueeze 8-bit graphic characters out of utilities which only produce
X7-bit characters, e.g. old nroff.
X
XI use this feature with the SCO XENIX nroff to gain access to the full
Xcharacter set of the HP LaserJet printer.  I mentioned my "tablj" nroff
Xdriver table for the LaserJet in comp.unix.xenix recently, and had several
Xrequests for it.
X
XWell, you need "colpr" first and here it is.  With any sort of luck, I
Xwill try to get the "tablj" stuff out in a week or so.
X
XChip Rosenthal
X<chip@vector.Dallas.TX.US>
X
X@(#) README 1.1 89/08/23 22:58:01
END_OF_FILE_README
    size="`wc -c < README`"
    if test 1045 -ne "$size" ; then
	echo "README: extraction error - got $size chars"
    fi
fi
if test -f colpr.c -a "$1" != "-c" ; then
    echo "colpr.c: file exists - will not be overwritten"
else
    echo "x - colpr.c (file 2 of 4, 8969 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_colpr.c' > colpr.c
X/* @(#) colpr.c 1.1 89/08/23 22:58:01
X *
X * colpr - general printer output filter
X *
X * Wed Aug 23 22:17:46 1989 - Chip Rosenthal <chip@vector.Dallas.TX.US>
X *	Consolidation and cleanup for net release to alt.sources.
X * Fri Dec 23 02:19:24 CST 1988 - C. Rosenthal (chip@vector.uucp)
X *	Original composition.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X
X#ifndef LINT
Xstatic char SCCSID[] = "@(#) colpr.c 1.1 89/08/23 22:58:01";
X#endif
X
X#ifdef M_XENIX
X# undef NULL
X# define NULL 0
X#endif
X
X#define USAGE		"usage: %s [-bng] [-t cols] [-f cols] [file ...]\n"
X
X#define BUFLEN		1024	/* maximum output line length		*/
X#define MAXOVER		10	/* maximum number of overstrike passes	*/
X#define TABSTOP		8	/* columns between tabstops		*/
X#define GRAPHCHAR	'\177'	/* special char to set MSB of next char	*/
X#define TRUE		1
X#define FALSE		0
X
X/*define NO_INLINE_NEXTCOL	/* define to suppress Nextcol() macro	*/
X
X
X/*
X * Macro to calculate next tabstop from current column.  Will become a
X * static procedure if you've got strange tabstops.
X */
X#if TABSTOP == 8
X#   define Tabstop(COL)	( ((COL)&(~07)) + 8 )
X#else
X    static int Tabstop(COL)
X    int COL;
X    {
X	while ( ++COL % TABSTOP != 0 ) ;
X	return COL;
X    }
X#endif
X
X
X/*
X * Macro to figure out where the column counter advances to.  It is inlined
X * for speed.  If you or your compiler don't like that, you can define
X * "NO_INLINE_NEXTCOL" to make it a static procedure.
X */
X#ifndef NO_INLINE_NEXTCOL
X#   define Nextcol(COL,CHAR)				\
X	( (CHAR) == '\b' ? ( (COL)>0 ? (COL)-1 : 0 ) :	\
X	    ( (CHAR) == '\t' ? Tabstop(COL) :		\
X		( (CHAR) == '\r' ? 0 :			\
X		    ( (CHAR) == '\n' ? 0 :		\
X			(COL)+1				\
X		    )					\
X		)					\
X	    )						\
X	)
X#else
X    static int Nextcol(COL,CHAR)
X    int COL, CHAR;
X    {
X	switch ( CHAR ) {
X	    case '\b':	return ( (COL)>0 ? (COL)-1 : 0 );
X	    case '\t':	return Tabstop(COL);
X	    case '\r':	return 0;
X	    case '\n':	return 0;
X	    default:	return COL+1;
X	}
X    }
X#endif
X
X
X/*
X * Global configuration settings.
X */
Xenum { NORMAL, FOLD, TRUNCATE } Mode_output; /* processing mode		      */
Xint Mode_backspace;		/* convert backspaces to overstrike passes?   */
Xint Mode_newline;		/* convert NL to CR/LF?			      */
Xint Mode_graphchar;		/* convert GRAPHCHAR sequence to 8-bit char?  */
Xint Num_cols;			/* max line width for fold/truncate	      */
X
X
X/*
X * End of line terminator
X */
Xchar *Newline_str;		/* will be either "\r\n" or "\n".	      */
X
X
X/*
X * Global printer overstrike buffers.
X */
Xchar Passbuf[MAXOVER][BUFLEN];
X
X
Xvoid proc_line();	/* Process one line of text.			*/
Xint xlate_backspace();	/* Generate overstrike passes from backspaces.	*/
Xvoid out_buffer();	/* Output multiple overstrike passes.      	*/
Xvoid out_line();	/* Output a line of text.			*/
X
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X    int i;
X    FILE *fp;
X    static char inbuf[BUFLEN];
X    extern int optind;
X    extern char *optarg;
X
X    /*
X     * Initialize.
X     */
X    Num_cols = BUFLEN+1;	/* don't truncate or file		*/
X    Mode_output = NORMAL;	/* don't truncate or fold		*/
X    Mode_backspace = FALSE;	/* leave backspaces as is		*/
X    Mode_newline = FALSE;	/* leave NL character as is		*/
X    Mode_graphchar = FALSE;	/* leave GRAPHCHAR character as is	*/
X
X    /*
X     * Process command line options.
X     */
X    while ( (i=getopt(argc,argv,"bngt:f:")) != EOF ) {
X	switch ( i ) {
X	    case 'b':	Mode_backspace = TRUE; break;
X	    case 'n':	Mode_newline = TRUE; break;
X	    case 'g':	Mode_graphchar = TRUE; break;
X	    case 't':	Mode_output = TRUNCATE; Num_cols = atoi(optarg); break;
X	    case 'f':	Mode_output = FOLD; Num_cols = atoi(optarg); break;
X	    default:	fprintf(stderr,USAGE,argv[0]); exit(1);
X	}
X    }
X    if ( Mode_output != NORMAL && (Num_cols < 10 || Num_cols > BUFLEN) ) {
X	fprintf(stderr,"%s: bad line width specified\n",argv[0]);
X	exit(1);
X    }
X
X    /*
X     * Select the proper line terminator.
X     */
X    Newline_str = ( Mode_newline ? "\r\n" : "\n" );
X
X    /*
X     * With no other arguments, filter stdin and exit.
X     */
X    if ( argc-optind == 0 ) {
X	while ( fgets(inbuf,sizeof(inbuf),stdin) != (char *) NULL )
X	    proc_line(inbuf);
X	exit(0);
X    }
X
X    /*
X     * Filter each file.
X     */
X    for ( i = optind ; i < argc ; ++i ) {
X	if ( (fp=fopen(argv[i],"r")) == (FILE *) NULL ) {
X	    perror(argv[i]);
X	    exit(1);
X	}
X	while ( fgets(inbuf,sizeof(inbuf),fp) != (char *) NULL )
X	    proc_line(inbuf);
X	(void) fclose(fp);
X    }
X
X    exit(0);
X    /*NOTREACHED*/
X}
X
X
X/*
X * proc_line() - Process one line of text.
X *   A line is passed to this procedure to be munched on and then printed.
X */
Xvoid proc_line(bufp)
Xregister char *bufp;
X{
X    register char *c1, *c2;
X
X    /*
X     * Strip trailing spaces, tabs, and newline.
X     */
X    for ( c1 = bufp + strlen(bufp) - 1 ; c1 >= bufp && isspace(*c1) ; --c1 ) ;
X    *(c1+1) = '\0';
X
X    /*
X     * If the line is blank, then just print a newline and return.
X     */
X    if ( *bufp == '\0' ) {
X	fputs(Newline_str,stdout);
X	return;
X    }
X
X    /*
X     * Perform 8-bit character translations.  Every instance of the
X     * two-character sequence {GRAPHCHAR,x} is replaced with the single
X     * character (x|0200).
X     */
X    if ( Mode_graphchar ) {
X	for ( c1 = c2 = bufp ; *c1 != '\0' ; ++c1, ++c2 ) {
X	    *c2 = (
X		( *c1 == GRAPHCHAR && *++c1 != GRAPHCHAR ) ?
X		( *c1 | 0200 ) :
X		*c1
X	    );
X	}
X	*c2 = '\0';
X    }
X
X    /*
X     * Print out the line.  If we are doing backspace translation then first
X     * convert the line to multiple overstrike passes.  If we aren't doing this
X     * translation then just print out the line.  If line folding or truncation
X     * are required, it will be handled in the output procedure.
X     */
X    if ( Mode_backspace ) {
X	out_buffer(xlate_backspace(bufp));
X    } else {
X	out_line(bufp);
X    }
X
X}
X
X
X
X/*
X * xlate_backspace - Generate overstrike passes from backspaces.
X *   The line is stored in global character array "Passbuf[][]".  The text
X *   for printhead pass "n" is stored in "Passbuf[n]", where 0<=n<=MAXOVER-1.
X *   The number of printhead passes required to print this line (i.e. the
X *   number of "Passbuf[]" buffers) is returned.
X */
Xint xlate_backspace(bufp)
Xregister char *bufp;
X{
X    int bufused = -1;		/* highest overstrike buffer used	*/
X    register int col;		/* current printhead column number	*/
X    register int i;
X    int j;
X    char *c;
X
X    /*
X     * Go through each character in the line.
X     */
X    for ( col = 0 ; *bufp != '\0' ; ++bufp ) {
X
X	/*
X	 * Process non-printing, column movement characters.
X	 */
X	if ( isspace(*bufp) || *bufp == '\b' ) {
X	    col = Nextcol(col,*bufp);
X	    continue;
X	}
X
X	/*
X	 * Make sure we can store this character.
X	 */
X	if ( col > BUFLEN-2 ) {
X	    fprintf(stderr,"panic - exceeded %d char buffer limit\n",BUFLEN-1);
X	    exit(1);
X	}
X
X	/*
X	 * Find a buffer where this column is unused.  Allocate additional
X	 * overstrike buffers as required.  Stick the character there.
X	 */
X	for ( i = 0 ; i < MAXOVER ; ++i ) {
X	    while ( i >= bufused )
X		(void) memset(Passbuf[++bufused],BUFLEN,' ');
X	    if ( Passbuf[i][col] == ' ' )
X		break;
X	}
X	if ( i < MAXOVER )
X	    Passbuf[i][col++] = *bufp;
X
X    }
X
X    /*
X     * Trim trailing space and terminate the overstrike buffers.
X     */
X    for ( i = 0 ; i <= bufused ; ++i ) {
X	for ( c=Passbuf[i]+BUFLEN-1, j=BUFLEN ; *c == ' ' && j > 0 ; --c, --j) ;
X	*(c+1) = '\0';
X    }
X
X    return bufused;
X}
X
X
X/*
X * out_line - Output a line of text.
X *   The specified line of text is printed.  Line truncation or folding
X *   are performed if required.
X */
Xvoid out_line(bufp)
Xregister char *bufp;
X{
X    int col;
X
X    switch ( Mode_output ) {
X
X    case NORMAL:
X	fputs(bufp,stdout);
X	break;
X
X    case TRUNCATE:
X	for ( col = 0 ; *bufp != '\0' && col < Num_cols ; ++bufp ) {
X	    putchar(*bufp);
X	    col = Nextcol(col,*bufp);
X	}
X	break;
X
X    case FOLD:
X	for ( col = 0 ; *bufp != '\0' ; ++bufp ) {
X	    if ( col >= Num_cols ) {
X		fputs(Newline_str,stdout);
X		col = 0;
X	    }
X	    putchar(*bufp);
X	    col = Nextcol(col,*bufp);
X	}
X	break;
X
X    }
X
X    fputs(Newline_str,stdout);
X}
X
X
X/*
X * out_buffer - Output text as multiple overstrike passes.
X *   Output the text stored in the "Passbuf[]" overstrike buffers.  Line
X *   truncation or folding are performed if required.
X */
Xvoid out_buffer(numbufs)
Xint numbufs;
X{
X    char *c;
X    int i, n;
X    extern char *strcpy();
X
X    switch ( Mode_output ) {
X
X    case TRUNCATE:
X	for ( i = 0 ; i <= numbufs ; ++i )
X	    Passbuf[i][Num_cols] = '\0';
X	/*FALLTHRU*/
X
X    case NORMAL:
X	for ( i = 0 ; i <= numbufs ; ++i ) {
X	    fputs(Passbuf[i],stdout);
X	    fputs( ( i == numbufs ? Newline_str : "\r" ) ,stdout);
X	}
X	break;
X
X    case FOLD:
X	do {
X	    for ( i = 0 ; i <= numbufs ; ++i ) {
X		for (
X		    c = Passbuf[i], n = 0 ;
X		    n < Num_cols && *c != '\0' && *c != '\r' && *c != '\n' ;
X		    ++c, ++n
X		) {
X		    putchar(*c);
X		}
X		(void) strcpy(Passbuf[i],c);
X		fputs( ( i == numbufs ? Newline_str : "\r" ) ,stdout);
X	    }
X	} while ( Passbuf[0][0] != '\0' );
X	break;
X
X    }
X
X}
END_OF_FILE_colpr.c
    size="`wc -c < colpr.c`"
    if test 8969 -ne "$size" ; then
	echo "colpr.c: extraction error - got $size chars"
    fi
fi
if test -f colpr.man -a "$1" != "-c" ; then
    echo "colpr.man: file exists - will not be overwritten"
else
    echo "x - colpr.man (file 3 of 4, 2204 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_colpr.man' > colpr.man
X''' @(#) colpr.man 1.1 89/08/23 22:58:22
X'''
X''' Wed Aug 23 22:17:46 1989 - Chip Rosenthal <chip@vector.Dallas.TX.US>
X'''	Consolidation and cleanup for net release to alt.sources.
X'''
X.TH COLPR 1L
X.SH NAME
Xcolpr - Printer output filter.
X.SH SYNOPSIS
X.B colpr
X[
X.B \-bng
X] [
X.B \-f
Xncols ] [
X.B \-t
Xncols ]
X[ file ... ]
X.SH DESCRIPTION
X.I Colpr
Xperforms a variety of functions for filtering output to a printer.
XWith no options specified,
X.I colpr
Xduplicates its input to its output.
XThe options to
X.I colpr
Xare:
X.IP "\fB\-b\fR"
XBackspaces are translated into multiple print passes.  This is useful
Xwhen the printer cannot backspace but can carriage return.
X.IP "\fB\-n\fR"
XNewline filtering is enabled.  Newline characters are translated to
Xreturn/newline sequences.
X.IP "\fB\-g\fR"
XGraphic character filtering is enabled.  See details below.
X.IP "\fB\-f\fR"
XLines longer than
X.I ncols
Xare folded onto subsequent lines.
X.IP "\fB\-t\fR"
XLines longer than
X.I ncols
Xare truncated to length.
X.PP
XThe graphic character translation allows access to 8-bit special character
Xsets.  Some programs, such as
X.IR nroff(1) ,
Xcan produce only 7-bit characters.  When
X.B \-g
Xis specified, a DEL character (octal 0177) will be stripped and the
Xmost-significant bit of the following character will be set.  For example,
Xthe two character sequence {177,001} is replaced by the single character
X{201}.  The two character sequence {177,177} is converted to a single
X{177} character.
X.SH SEE ALSO
Xcol(1), newform(1)
X.SH BUGS
XAttempts to overstrike one character over ten times causes
Xsome of the overstrike characters to be thrown away.
X.PP
XTabs are expanded to spaces when
X.B \-b
Xis specified.  There is no way to obtain an octal 377 character.  The
X.I nroff
Xdriver table must produce 8-bit characters using the DEL quoting method
Xdescribed herein.
X.PP
XThe graphic character function is negated by
X.IR col(1) .
XWhen you attempt "nroff|col|colpr|lp",
X.I col
Xwill eat the DEL characters produced by
X.IR nroff .
XWhen you attempt "nroff|colpr|col|lp", the 8-bit characters produced by
X.I colpr
Xwill be stripped.
X.PP
XLines longer than 1024 characters will probably be munged.
X.SH AUTHOR
XChip Rosenthal <chip@vector.Dallas.TX.US>
END_OF_FILE_colpr.man
    size="`wc -c < colpr.man`"
    if test 2204 -ne "$size" ; then
	echo "colpr.man: extraction error - got $size chars"
    fi
fi
if test -f Makefile -a "$1" != "-c" ; then
    echo "Makefile: file exists - will not be overwritten"
else
    echo "x - Makefile (file 4 of 4, 1267 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_Makefile' > Makefile
X
X# @(#) Makefile 1.1 89/08/23 22:58:01
X# Makefile for "colpr" (generated by /local/bin/makemake version 1.00.08)
X# Created by bin@vector on Wed Aug 23 22:21:21 CDT 1989
X
XSHELL = /bin/sh
XCC = cc
XDEFS = 
XCOPTS = -O
XLOPTS = 
XLIBS = 
XDEBUG = -g -DDEBUG
XLINTFLAGS = -DLINT
X
XTARG = colpr
XOTHERS = 
X
XSRCS = colpr.c
X
XOBJS = colpr.o
X
X# Any edits below this line will be lost if "makemake" is rerun!
X# Commands may be inserted after the '#%custom' line at the end of this file.
X
XCFLAGS = $(COPTS) $(DEFS) # $(DEBUG)
XLFLAGS = $(LOPTS) # $(DEBUG)
X
Xall:		$(TARG) $(OTHERS)
Xinstall:	all		; inst Install
Xclean:				; rm -f $(TARG) $(OBJS) a.out core $(TARG).lint
Xclobber:	clean		; inst -u Install
Xlint:		$(TARG).lint
X
X$(TARG):		$(OBJS)
X		$(CC) $(LFLAGS) -o $@ $(OBJS) $(LIBS)
X
X$(TARG).lint:	$(TARG)
X		lint $(LINTFLAGS) $(DEFS) $(SRCS) $(LIBS) > $@
X
Xcolpr.o: colpr.c
X
Xmake:		;
X		/local/bin/makemake -i -v1.00.08 -aMakefile \
X		    -DSHELL='$(SHELL)' -DCC='$(CC)' -DDEFS='$(DEFS)' \
X		    -DCOPTS='$(COPTS)' -DLOPTS='$(LOPTS)' -DLIBS='$(LIBS)' \
X		    -DDEBUG='$(DEBUG)' -DLINTFLAGS='$(LINTFLAGS)' \
X		    -DOTHERS='$(OTHERS)' $(TARG) $(SRCS)
X
X#%custom - commands below this line will be maintained if 'makemake' is rerun
X
Xshar:		; shar README colpr.c colpr.man Makefile > colpr.shar
X
END_OF_FILE_Makefile
    size="`wc -c < Makefile`"
    if test 1267 -ne "$size" ; then
	echo "Makefile: extraction error - got $size chars"
    fi
fi
echo "done - 4 files extracted"
exit 0
-- 
Chip Rosenthal / chip@vector.Dallas.TX.US / Dallas Semiconductor / 214-450-5337
"I wish you'd put that starvation box down and go to bed" - Albert Collins' Mom