[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]

Guide to Printers and Printing


Virtual printer definitions contain predefined and open (undefined) filter attributes. For instance, a AIX Version 4 ASCII queue on an IBM 4029 LaserPrinter offers the following filter attributes:

Filters are the first programs in the input data stream processing pipeline set up by piobe that have an opportunity to selectively manipulate the data stream. A particular filter can be selected from the command line on a per job basis, or permanently selected by modifying the virtual printer definition.

The qprt command uses the -f flag to select a particular filter on a per-job basis. The argument to the -f flag is the second letter of the two letters that name the filter attribute in the virtual printer definition. For instance, to select the pr filter for a job on an ASCII queue named asc on an IBM 4029 LaserPrinter, you could issue this command:

qprt -Pasc -fp /etc/motd

The filter attribute that selects the pr filter is named fp, so the argument to the -f flag is just p, the second letter.

To permanently select the pr filter, use lsvirprt to edit the virtual printer definition and set the value of the _f attribute to p. The _f attribute selects a filter that will be used to pre-process any job submitted to the queue associated with this virtual printer definition.

Since lp, lpr, and qprt are all just front ends to the enq command, the true entry point to the spooler, you would suppose that enq must support the -f flag. If you issue the enq command with the -f flag, however, you will receive an error message; enq does not support the -f flag. This is a situation where the previously described technique (Spooler Data Flow Part II) of mounting /bin/echo over /bin/enq proves useful.

The root user can issue these commands from a shell prompt:

  1. mount /bin/echo /bin/enq
  2. qprt -Pasc -fp /etc/motd
  3. umount /bin/enq

After the second command is issued, the following appears in the display element defined by your TERM environment variable:

-P asc -o -f -o p /etc/motd

These are the arguments qprt tried to pass to enq. You get to see them because qprt found echo instead of enq. The following command is equivalent to the command shown in step 2 above:

enq -P asc -o -f -o p /etc/motd

The -o option specifies that flags specific to the backend should be passed to the backend. The -o option can be thought of as a free pass through the syntax checking that occurs before the enq command builds a job description file and notifies the qdaemon of the existence of a new job.

To continue with this side discussion of the -o flag before we return to a discussion of filters, suppose that you want to set up a queue than will print a range of lines from an ASCII file. For instance, suppose you read /usr/lpp/bos/README and find 35 lines that you want to print so you can fax them to someone or tack them to your wall for reference. You could edit /etc/qconfig and add the following lines:

        device = partial
        file = FALSE
        backend = /usr/bin/partial

The file /usr/bin/partial could be a shell script with ownership of root.printq and with permissions of 755. Its contents could be as follows:

/usr/bin/head -${END} ${FILE} | tail -${DIFF} | /usr/bin/qprt -Pasc

If you wanted to print lines 189 through 223 of /usr/lpp/bos/README, you could use the partial queue as follows:

qprt -Ppartial -o 189 -o 223 /usr/lpp/bos/README

When the backend executes, BEGIN is assigned 189, END is assigned 223, and DIFF is assigned 35, which is the number of chosen lines. FILE is assigned /usr/lpp/bos/README. The head command truncates /usr/lpp/bos/README immediately after the last requested line. The output is piped to the tail command, which selects the last 35 lines of the truncated file and pipes them to qprt, which will take input from stdin. qprt submits the lines to the queue named asc.

A Filter that Maps Linefeeds to Carriage Returns and Linefeeds

Many users have written or purchased applications that prepare data streams to fill in the blanks on pre-printed checks, invoices, bills-of-lading, or other forms. Printing these data streams requires precise control of the physical printer. It is often the case that the job processing pipeline created by piobe inserts or deletes enough data from the original data stream that the output data no longer falls at the proper position on the pre-printed form.

The root user can frequently use lsvirprt to set the value of the _d attribute in the virtual printer definition to p. On an ASCII queue on an IBM 4029 LaserPrinter, this would cause piobe to select the ip pipeline to process the job. The ip pipeline is for passthru printing, which means the formatter filters uses the passthru() routine to simply pass the input data stream through to the printer without modification.

This frequently removes all the printer control problems that existed, but adds one new one. When the formatter filter operates in passthru mode, the mapping of linefeeds to carriage returns and linefeeds is disabled. The forms still don't print correctly.

Supposing that the application does not allow the insertion of carriage returns into the data stream, you can fix this problem with a simple filter, as follows:

#include <stdio.h>
main(int argc, char **argv)
int ch ;
while (EOF != (ch = fgetc(stdin)))
  switch (ch)
    case 10: fputc(ch,stdout) ; 
             fputc(0x0D,stdout) ; 
             break ;
    default: fputc(ch,stdout) ;
             break ;

Compile this and name it cr_mapper. and install it somewhere accessible, such as /usr/lib/lpd. Assign it ownership of root.printq and permissions 555.

Assuming you have an ASCII queue named asc on an IBM 4029 LaserPrinter, you can use lsvirprt to select the asc queue and then format the f1 filter attribute. You should see something like the following:

User defined filter 1
f1 =

As the f1 attribute has a null default value, the definition is sparse.

Edit the f1 attribute so its definition appears as follows:

User defined filter 1
f1 =

When you save the new definition of f1, you can again format it with lsvirprt; you should see something like the following:

User defined filter 1
f1 = /usr/lib/lpd/cr_mapper

The f1 filter can now be used from the command line by using commands such as:

qprt -Pasc -f1 filename
enq -Pasc -o -f -o 1 filename

If the _d attribute wasn't set to p, the -dp flag and argument would have to be added to the commands.

qprt -Pasc -dp -f1 filename
enq -Pasc -o -d -o p -o -f -o 1 filename

The cr_mapper program reads characters from stdin and writes them to stdout. Whenever it reads and writes a linefeed (a hex A, or decimal 10), it writes out a carriage return (a hex D).

[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]