SUMMARY -- lpd filters

From: Steve Harris (etnibsd!vsh@uunet.uu.net)
Date: Mon Jul 01 1991 - 23:13:33 CDT


Restatement of the problem:

We need to access the printer in multiple modes, to print different
types of files.

Configuration:

. HP LaserJet II
. Sun 3/50
. SunOS 4.1.1

We need to print both Unix text files and "binary" files generated by
specialized software, e.g., WordPerfect on a PC (these files are not so
much "binary" as a bunch of escape sequences with a few words of text
interspersed).

. Unix text files have newlines as line terminators.
. "binary" files do not -- should be printed "as is"
. (i.e., do not transform "\n" to "\r\n").

I received a number of suggestions, usually in the form "here's my
configuration, it works for me....". Basically, these suggestions
divided into four groups formed by a 2X2 matrix.

One axis of the matrix is concerned with how to handle different
classes of files:

. define a single printer with different filters
. define separate logical printers in the printcap
. (which would all print to the same physical device)

The other axis concerns where to do transformations (if any):

. on the sun
. program the printer (via escape sequences) to do them

Eventually, I chose to use different filters and to program the printer
to do the transformations.

The principal problem with this method is getting the "of" filter
(which prints the banner pages and ordinary text files) to stop when
another filter is required to print a specialized document. TFM is
irritatingly vague on this point (System & Network Admin, p. 351):

        If entries for both "of" and one of the other filters are
        specified, the output filter is used only to print the banner
        page; it is then stopped to allow other filters access to the
        printer.

Just how it is "stopped" is nowhere described!

Here, BTW, is what the Sun "Answerline" had to say:

    .... Regarding your printer filter questions, I'm afraid I won't
    be able to assist you in debugging this.

    Technical bookstores might have some documentation in writing
    filters. Also, we do have a consulting group that can assist you
    in writing customized applications/utilities....

Thanks a bunch, Answerline, sure glad we pay you all that money so you
can be so helpful!!!!!

The solution came from Matt Larson (uunet!avalon.eecs.nwu.edu!matt),
who forwarded a configuration originally written in Dec '87 by Brian
Utterback. My code is essentially just a stripped down version of
Brian's.

The key to writing an lpd filter is knowing that the daemon sends a
^Y^A (control/Y, control/A) character sequence to the "of" filter as a
signal that it is to stop itself! (Why the daemon doesn't simply send
a signal to the child is a mystery some Unix historian will have to
unearth :-). The "of" filter sends itself a stop signal, the daemon
fires up the alternate filter to process the data, then restarts the
"of" filter to print the next banner page.

In the case of the laserjet, I use three filters:

. "of" -- to print banner pages
. "if" -- to print text files
. "vf" -- to print "binary" files

Notes:
        I don't really need the "if" filter, "of" would print text
        files just fine.

        If lpr is invoked with the "-l" option, the daemon instructs
        the "if" filter not to filter control characters ("if" is
        invoked with the "-c" option). Since I never filter control
        characters, I use this option as an alternate way of specifying
        "binary" printing; unfortunately, the software on the PCs does
        not support the "-l" option. :-(

        The "vf" filter is supposed to be used to print raster images,
        e.g., something created by screendump. Since we don't do that,
        I use it to print "binary" files. The PCs do support the "-v"
        option. :-)

        If you try to print a file with the character sequence ^Y^A in
        the name (unlikely, but legal in Unix), the result is curious.
        Even more so if the name has more than one occurrence of the
        sequence.

As indicated earlier, some respondants used multiple logical printers
to print different types of documents on the laserjet (presumably the
spooler system uses some kind of locking on the output file to keep
multiple daemons from tripping over each other). In addition to
designating different printers for text and binary files, this
technique could be used, e.g. to differentiate portrait and landscape
modes. One respondant mapped the different PC printer devices (LPT1,
LPT2, etc.) to corresponding logical printer spools.

However (IMHO), at least within Unix, these capabilities are better
realized by massaging the data before sending them to lpd, using a tool
to insert the appropriate escape sequences in the data stream. Ours is
called "laser", it's not great (I'm sure there are better tools by
now), but it's available if you want it.

The rest of this email is a shar file of the filters I am using and my
printcap. If anybody wants info on other methods, or has any other
questions, please send email, I'll be happy to send you everything I
have.

Many thanks to the following:

        uunet!cs.rutgers.edu!trudel
        uunet!igor!ddull (David Dull)
        uunet!sl.dth.dk!sl_mnl (Morten Norby Larsen)
        uunet!sq.com!lee (Liam Quin)
        uunet!avalon.eecs.nwu.edu!matt (Matt Larson)
        Greg Higgins <uunet!mp.cs.niu.edu!higgins>
        uunet!ub.cc.umich.edu!jim_mckenna

========================== cut here ===================================
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# etc/printcap
# usr/lib/lpdfilters/hplaserjet/ifilt.c
# usr/lib/lpdfilters/hplaserjet/ofilt.c
# usr/lib/lpdfilters/hplaserjet/vfilt.c
# This archive created: Mon Jul 1 23:19:59 1991
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'printcap'" '(298 characters)'
if test -f 'printcap'
then
        echo shar: "will not over-write existing file 'printcap'"
else
sed 's/^ X//' << \SHAR_EOF > 'printcap'
        Xlp|lp0|0|lz|rpl|laser:\
        X :lp=/dev/lp:\
        X :sd=/usr/spool/lpd:\
        X :lf=/usr/adm/lpd-errs:\
        X :of=/usr/lib/lpdfilters/hplaserjet/ofilt:\
        X :if=/usr/lib/lpdfilters/hplaserjet/ifilt:\
        X :vf=/usr/lib/lpdfilters/hplaserjet/vfilt:\
        X :br#9600:\
        X :fc#0000300:\
        X :fs#0000020:\
        X :xc#0000000:\
        X :xs#0040460:\
        X :mx#0:
SHAR_EOF
if test 298 -ne "`wc -c < 'printcap'`"
then
        echo shar: "error transmitting 'printcap'" '(should have been 298 characters)'
fi
fi
echo shar: "extracting 'ifilt.c'" '(973 characters)'
if test -f 'ifilt.c'
then
        echo shar: "will not over-write existing file 'ifilt.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'ifilt.c'
        X#include <stdio.h>
        X
        X/*
        X * "if" filter for HP LaserJet II
        X * written by Steve Harris, Eaton Corp, June 1991 (uunet!etnibsd!vsh)
        X * based on code by Brian Utterback, Cray Research (blu@cray.com ??)
        X *
        X * filter should support standard options but we don't use them
        X * (we only care about -c).
        X *
        X * Standard options are:
        X * [-c] -llength -wwidth -iindent -n login -h host acctfile
        X * where:
        X * length, width are the page length and width
        X * indent is the indent for the document
        X * login is the user's login name (for accounting)
        X * host is the host system (for accounting)
        X * acctfile is the accounting file
        X */
        X
        Xmain(argc,argv)
        Xint argc;
        Xchar *argv[];
        X{
        X int i, c;
        X int asis = 0;
        X
        X for (i = 1; i < argc; i++) {
        X if (!strcmp(argv[i], "-c"))
        X asis++;
        X }
        X
        X fputs("\033E", stdout); /* Reset the printer */
        X if (!asis)
        X fputs("\033&k3G", stdout); /* enable crlf mode */
        X while ((c = getchar()) != EOF)
        X putchar(c);
        X fputs("\033E", stdout); /* reset printer */
        X exit(0);
        X}
SHAR_EOF
if test 973 -ne "`wc -c < 'ifilt.c'`"
then
        echo shar: "error transmitting 'ifilt.c'" '(should have been 973 characters)'
fi
fi
echo shar: "extracting 'ofilt.c'" '(1215 characters)'
if test -f 'ofilt.c'
then
        echo shar: "will not over-write existing file 'ofilt.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'ofilt.c'
        X#include <stdio.h>
        X
        X/*
        X * "of" filter for HP LaserJet II
        X * written by Steve Harris, Eaton Corp, June 1991 (uunet!etnibsd!vsh)
        X * based on code by Brian Utterback, Cray Research (blu@cray.com ??)
        X *
        X * filter should support standard options but we don't use them
        X *
        X * Standard options are:
        X * -llength -wwidth
        X * where:
        X * length, width are the page length and width
        X * indent is the indent for the document
        X */
        X
        X#define CTRL(c) ((c) & 0x1F)
        X
        X#include <stdio.h>
        X#include <signal.h>
        X
        Xmain(argc,argv)
        Xint argc;
        Xchar *argv[];
        X{
        X int c;
        X
        X fputs("\033E", stdout); /* reset printer */
        X fputs("\033&k3G", stdout); /* enable crlf mode */
        X while ((c = getchar()) != EOF) {
        X if (c == CTRL('Y')) {
        X if ((c = getchar()) == CTRL('A')) {
        X /*
        X * got ^Y^A sequence -- stop filter so lpd
        X * can run some other filter; lpd will
        X * restart this filter if necessary
        X */
        X (void) fflush(stdout);
        X (void) kill(getpid(), SIGSTOP);
        X /*
        X * parent may reawaken filter
        X * reset printer again
        X */
        X fputs("\033E", stdout);
        X fputs("\033&k3G", stdout);
        X continue;
        X } else {
        X (void) ungetc(c,stdin);
        X c = CTRL('Y');
        X }
        X }
        X putchar(c);
        X }
        X fputs("\033E", stdout);
        X exit(0);
        X}
SHAR_EOF
if test 1215 -ne "`wc -c < 'ofilt.c'`"
then
        echo shar: "error transmitting 'ofilt.c'" '(should have been 1215 characters)'
fi
fi
echo shar: "extracting 'vfilt.c'" '(751 characters)'
if test -f 'vfilt.c'
then
        echo shar: "will not over-write existing file 'vfilt.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'vfilt.c'
        X#include <stdio.h>
        X
        X/*
        X * "vf" filter for HP LaserJet II
        X * written by Steve Harris, Eaton Corp, June 1991 (uunet!etnibsd!vsh)
        X * based on code by Brian Utterback, Cray Research (blu@cray.com ??)
        X *
        X * filter should support standard options but we don't use them
        X *
        X * Standard options are:
        X * -xwidth -ylength -n login -h host acctfile
        X * where:
        X * length, width are the page length and width
        X * login is the user's login name (for accounting)
        X * host is the host system (for accounting)
        X * acctfile is the accounting file
        X */
        X
        Xmain(argc,argv)
        Xint argc;
        Xchar *argv[];
        X{
        X int i, c;
        X int asis = 0;
        X
        X fputs("\033E", stdout); /* Reset the printer */
        X while ((c = getchar()) != EOF)
        X putchar(c);
        X fputs("\033E", stdout); /* reset printer */
        X exit(0);
        X}
SHAR_EOF
if test 751 -ne "`wc -c < 'vfilt.c'`"
then
        echo shar: "error transmitting 'vfilt.c'" '(should have been 751 characters)'
fi
fi
exit 0
# End of shell archive



This archive was generated by hypermail 2.1.2 : Fri Sep 28 2001 - 23:06:21 CDT