4.9. Print Job Filters

A printer usually understands one or more Print Job Languages. Files sent to this printer must be in one of these languages and have the appropriate job format, control characters, or other information. The most common Print Job Languages are PostScript and PCL.

In order for a printer to reliably print a job, it needs to be reset to a known configuration. This is usually done by sending it a special start of job and end of job command. These commands differ from printer to printer, and even depend on the type of print job language that the print job is in. Some vintage line printers also have a set of proprietary escape sequences that are used to set up margins, form size, and other printing characteristics. Usually a setup string of these escape sequences needs to be sent to the printer before the file can be printed.

In order to handle these problems, the LPRng system uses a filter program to provide the set of escape sequences or carry out the initialization required for a printer. The files in a print job are assigned a lower case letter format using the lpr format options; the default format is f. The l (literal or binary) format is used to indicate that the file should be passed directly to the printer, or have at the most a minimal amount of processing. See Print Job Formats for more information about formats and their use with filters.

We will set up a very simple filter and use it to demonstrate how the lpd spooler uses it. First, set up the /tmp/testf file as shown below.

    #!/bin/sh
    # /tmp/testf - test filter for LPRng
    PATH=/bin:/usr/bin; export PATH
    echo TESTF $0 "$@" >&2
    echo TESTF $0 "$@"
    echo ENV
    set
    echo LEADER
    /bin/cat
    echo TRAILER
    exit 0


Let us carefully examine the script line by line. The first couple of lines are standard boilerplate. You should always set the PATH value in a filter script or use full pathnames. This is a good practice as it ensures that only the specified directories will be searched for commands.

The next lines echo the command line arguments to file descriptor 2 (STDERR) and to STDOUT. We will soon see how this information is displayed by the LPRng software. We then use the set command to list the shell variables to STDOUT, print LEADER to STDOUT, copy STDIN to STDOUT, and print TRAILER to STDOUT. We exit with a zero result code.

We can test our script, with the results shown below:

    h4: {156} % chmod 755 /tmp/testf
    h4: {157} % echo hi |/tmp/testf -a1
    TESTF /tmp/testf -a1
    TESTF /tmp/testf -a1
    ENV
    USER=papowell
    HOSTNAME=h4
    ...
    PATH=/bin:/usr/bin
    LEADER
    hi
    TRAILER


Let's now use this filter. Edit the lp printcap entry so it has contents indicated below, use checkpc -f to check the printcap, and then use lpc reread to restart the lpd server.

    lp:sd=/var/spool/lpd/%P
      :force_localhost
      :lp=/tmp/lp
      :filter=/tmp/testf


Execute the following commands to print the /tmp/hi file and observe the results:

    h4: {158} % cp /dev/null /tmp/lp
    h4: {159} % lpr /tmp/hi
    h4: {160} % lpq -llll
    Printer: lp@h4
     Queue: no printable jobs in queue
     Status: lp@h4.private: job 'papowell@h4+26593' printed at 21:37:21.312
     Status: job 'papowell@h4+26593' removed at 21:37:21.323
     Status: subserver pid 26683 starting at 21:39:21.908
     Status: accounting at start at 21:39:21.908
     Status: opening device '/tmp/lp' at 21:39:21.909
     Status: printing job 'papowell@h4+26681' at 21:39:21.909
     Status: no banner at 21:39:21.909
     Status: printing data file 'dfA026681h4.private', size 3, IF filter 'testf' at
    21:39:21.909
     Status: IF filter msg - 'TESTF /tmp/testf -Apapowell@h4+26681 -CA -D2000-04
    -11-21:39:21.877 -Ff -Hh4.private -J/tmp/hi -Lpapowell -Plp -Qlp -aacct -b3 -d/v
    ar/tmp/LPD/lp -edfA026681h4.private -f/tmp/hi -hh4.private -j026681 -kcfA026681h
    4.private -l66 -npapowell -sstatus -t2000-04-11-21:39:21.000 -w80 -x0 -y0 acct'
    at 21:39:21.914
     Status: IF filter finished at 21:39:22.070
     Status: printing done 'papowell@h4+26681' at 21:39:22.070
     Status: accounting at end at 21:39:22.070
     Status: finished 'papowell@h4+26681', status 'JSUCC' at 21:39:22.070
     Status: subserver pid 26683 exit status 'JSUCC' at 21:39:22.072
     Status: lp@h4.private: job 'papowell@h4+26681' printed at 21:39:22.072
     Status: job 'papowell@h4+26681' removed at 21:39:22.085
    h4: {161} % more /tmp/lp
    TESTF /tmp/testf -Apapowell@h4+26681 -CA -D2000-04 -11-21:39:21.877 -Ff
    -Hh4.private -J/tmp/hi -Lpapowell -Plp -Qlp -aacct -b3 -d/var/tmp/LPD/lp
    -edfA026681h4.private -f/tmp/hi -hh4.private -j026681 -kcfA026681h4.private
    -l66 -npapowell -sstatus -t2000-04-11-21:39:21.000 -w80 -x0 -y0 acct
    ENV
    USER=papowell
    LD_LIBRARY_PATH=/lib:/usr/lib:/usr/5lib:/usr/ucblib
    HOME=/home/papowell
    PRINTCAP_ENTRY=lp
     :force_localhost
     :filter=/tmp/testf
     :lp=/var/tmp/lp
     :sd=/var/tmp/LPD/lp
    
    PS1=$
    OPTIND=1
    PS2=>
    SPOOL_DIR=/var/tmp/LPD/lp
    LOGNAME=papowell
    
    CONTROL=Hh4.private
     Ppapowell
     J/tmp/hi
     CA
     Lpapowell
     Apapowell@h4+15850
     D2000-04-26-18:13:55.505
     Qlp
     N/tmp/hi
     fdfA015850h4.private
     UdfA015850h4.private
    
    PATH=/bin:/usr/bin
    SHELL=/bin/sh
    LOGDIR=/home/papowell
    IFS=
    PRINTER=lp
    LEADER
    test Test
    TRAILER


The cp command clears out the /tmp/lp file we are using as a dummy output device. The lpr command prints the /tmp/hi file and the lpq -llll command shows the status information. The status information now contains the line that the testf script wrote to STDERR. The lpd server captures filter STDERR messages and puts it them in the spool queue status file.

As we see from the lpq status, lpd passes a large number of command line options to our filter. These options and their meanings are discussed in detail in Filter Command Line Options and Environment Variables. We will discuss these in more detail in the next section.

If we look at the /tmp/lp file, we see the command line options and values of the shell variables. For a full discussion of the environment variables passed to a filter see Filter Command Line Options and Environment Variables. The more interesting environment variables include the PRINTCAP_ENTRY variable, which is a copy of the printcap entry for this printer, and the CONTROL variable, which is a copy of the control file for the the print job.