--- printers.mm	2001/12/30 02:54:02	4.1
+++ printers.mm	2003/04/02 06:48:05
@@ -1,32 +1,29 @@
 .\" This file is in -*- nroff-fill -*- mode
-.\" STATUS: pre-final draft 4th edition
-.\" $Id: printers.mm,v 4.1 2001/12/30 02:54:02 grog Exp $
+.\" STATUS: 4th edition
+.\" $Id: printers.mm,v 4.17 2003/04/02 06:48:05 grog Exp $
 .\"
-.so global.mm
 .Chapter \*[nchprinters] "Printers"
 .Pn printers
 .X "spooler"
-.X "lpr, command"
-.X "command, lpr"
-.X "lpd dmon"
-.X "dmon, lpd"
 In this chapter, we'll look at some aspects of using printers with FreeBSD.  As
 a user, you don't access printers directly.  Instead, a series of processes,
 collectively called the \fIspooler\fP, manage print data.  One process,
-\fIlpr\fP, writes user print data to disk, and another, \fIlpd\fP, copies the
-print data to the printers.  This method enables processes to write print data
-even if the printers are busy and ensures optimum printer availability.
+.Command lpr ,
+writes user print data to disk, and another,
+.Daemon lpd ,
+copies the print data to the printers.  This method enables processes to write
+print data even if the printers are busy and ensures optimum printer
+availability.
 .P
 In this section, we'll look briefly at what you need to do to set up printers.
-For more details, look in the online handbook section on printing, from which
-this section is derived.
+For more details, look in the online handbook section on printing.
 .P
-\fIlpd\fP\| is the central spooler process.  It is responsible for a number of
-things:
+.Daemon lpd
+is the central spooler process.  It is responsible for a number of things:
 .Ls B
 .LI
-It controls access to attached printers and printers attached to other hosts on
-the network.
+It controls access to attached printers and to printers attached to other hosts
+on the network.
 .LI
 It enables users to submit files to be printed.  These submissions are known as
 jobs.
@@ -52,7 +49,7 @@
 of printer hardware.
 .P
 This may sound like overkill if you are the only user on the system.  It
-\fIis\fP\| possible to access the printer directly, but it's not a good idea:
+\fIis\fP\/ possible to access the printer directly, but it's not a good idea:
 .Ls B
 .LI
 The spooler prints jobs in the background.  You don't have to wait for data to
@@ -65,37 +62,50 @@
 Most programs that provide a print feature expect to talk to the spooler on your
 system.
 .Le
+.sp -1v
 .H2 "Printer configuration"
 .X "printer configuration"
 .X "parallel port"
-Nowadays, most printers are connected by the \fIparallel port\fP.  Parallel
-ports enable faster communication with the printer, up to about 100,000 bytes
-per second, while serial printers seldom transmit more than 1,920 characters per
-second.
-.Aside
+There are three commonly used ways to connect a  printer to a computer:
+.Ls B
+.LI
 Older UNIX systems frequently used serial printers, but they are no longer in
-common use.  Look at the handbook article for specifies of serial printers.
-.End-aside
-Modern printers may also have an Ethernet interface, which enables them to
-connect to several machines at once.
-.P
-It's pretty straightforward to connect a parallel printer: plug in the cable
-between the printer and the computer.  You don't need any adjustments.  If you
-have more than one parallel interface, of course, you'll have to decide which
-one to use.  Parallel printer devices are called \fI/dev/lpt\f(BIn\fR, where
-\fIn\fP\| is the number, starting with \f(CW0\fP.  See table
+common use.  Serial printers seldom transmit more than 1,920 characters per
+second, which is too slow for modern printers.
+.LI
+Most printers are still connected by a \fIparallel port\fP.  Parallel ports
+enable faster communication with the printer, up to about 100,000 bytes per
+second.  Such speeds may still not be enough for complex PostScript or
+bit-mapped images.  Most parallel ports require CPU intervention via an
+interrupt for each character transmitted, and 100,000 interrupts per second can
+use the entire processing power of a fast machine.
+.LI
+More modern printers have USB or Ethernet interfaces, which enable them to
+connect to several machines at once at much higher speeds.  The load on the host
+computer is also much lower.
+.Le
+.X "device, lpt"
+.X "lpt, device"
+It's pretty straightforward to connect a parallel printer.  You don't need to do
+anything special to configure the line printer driver \fIlpt\fP\/: it's in the
+kernel by default.  All you need to do is to plug in the cable between the
+printer and the computer.  If you have more than one parallel interface, of
+course, you'll have to decide which one to use.  Parallel printer devices are
+called /dev/lpt\f(BIn\fR, where \fIn\fP\/ is the number, starting with
+\f(CW0\fP.  USB devices have names like \fI/dev/ulpt\f(BIn\fR.  See Table
 \*[FreeBSD-devices-table] on page \*[FreeBSD-devices-table-page] for further
 details.
 .P
-You don't need to do anything special to configure the line printer driver
-\fIlpt\fP\|: it's in the kernel by default.  Of course, if you have previously
-removed it, you'll have to replace it.  See page \*[config-lpt0] for more
-details.
+Configuring an Ethernet-connected printer is more complicated.  You obviously
+need an IP address, which you configure on the printer.  Most modern printers
+then appear like a remote computer to the spooler.  We look at spooling to
+remote computers on page
+.Sref \*[remote-printer] .
 .H3 "Testing the printer"
-.X "testing printers"
+.X "testing, printer"
 .X "printer, testing"
-When you have connected and powered on the printer, run the manufacture's test
-if one is supplied.  Typically there's a function which produces a printout
+When you have connected and powered on a parallel port printer, run the built-in
+test if one is supplied: typically there's a function that produces a printout
 describing the printer's features.  After that, check the communication between
 the computer and the printer.
 .Dx
@@ -103,14 +113,14 @@
 .De
 If you have a pure PostScript printer, one which can't print anything else, you
 won't get any output.  Even here, though, you should see some reaction on the
-status display.  See the description in the online handbook for testing
-PostScript printers.
-.H3 "Configuring \fI/etc/printcap\fP"
+status display.
+.H3 "Configuring /etc/printcap"
 .X "/etc/printcap"
 .Pn printcap
 The next step is to configure the central configuration file,
-\fI/etc/printcap\fP.  This file is not the easiest to read, but after a while
-you'll get used to it.  Here are some typical entries:
+.File /etc/printcap .
+This file is not the easiest to read, but after a while you'll get used to it.
+Here are some typical entries:
 .Dx
 lp|lj|ps|local LaserJet 6MP printer:\e
 	:lp=/dev/lpt0:sd=/var/spool/output/lpd:lf=/var/log/lpd-errs:sh:mx#0:\e
@@ -129,14 +139,18 @@
 particularly that you require a colon at the end of a continued line, and
 another at the beginning of the following line.
 .LI
-The first line of each entry specifies a number of names which you can use to
-specify this printer when talking to \fIlpr\fP\| or \fIlpd\fP.  The names are
-separated by vertical bar symbols \f(CW|\fP.  By tradition, the last name is a
-more verbose description, and you wouldn't normally use it to talk to programs.
+The first line of each entry specifies a number of names that you can use to
+specify this printer when talking to
+.Command lpr
+or
+.Daemon lpd .
+The names are separated by vertical bar symbols \f(CW|\fP.  By tradition, the
+last name is a more verbose description, and you wouldn't normally use it to
+talk to programs.
 .LI
 The following fields describe \fIcapabilities\fP, descriptions of how to do
 something.  Capabilities are described by a two-letter keyword and optionally a
-parameter, which is separate by a delimiter indicating the type of parameter.
+parameter, which is separated by a delimiter indicating the type of parameter.
 If the field takes a string parameter, the delimiter is \f(CW=\fP, and if it
 takes a numeric value, the delimiter is \f(CW#\fP.  You'll find a full
 description in the man page.
@@ -144,8 +158,8 @@
 The first entry defines a local printer, called \f(CWlp\fP, \f(CWlj\fP,
 \f(CWps\fP and \f(CWlocal LaserJet 6MP printer\fP.  Why so many names?
 \f(CWlp\fP is the default, so you should have it somewhere.  \f(CWlj\fP is
-frequently used to talk to printers which understand HP's LaserJet language (now
-PCL), and \f(CWps\fP might be used to talk to a printer which understands
+frequently used to talk to printers that understand HP's LaserJet language (now
+PCL), and \f(CWps\fP might be used to talk to a printer that understands
 PostScript.  The final name is more of a description.
 .LI
 The entry \f(CWlp=/dev/lpt0\fP tells the spooler the name of the physical device
@@ -154,69 +168,89 @@
 \f(CWsd\fP tells the spooler the directory in which to store jobs awaiting
 printing.  This directory must exist; the spooler doesn't create it.
 .LI
-\f(CWlf=/var/log/lpd-errs\fP specifies the name of a file into which to log
+\f(CWlf=/var/log/lpd-errs\fP specifies the name of a file in which to log
 errors.
 .LI
-.X "lpd dmon"
-.X "dmon, lpd"
-\f(CWsh\fP is a flag telling \fIlpd\fP\| to omit a header page.  If you don't
-have that, every job will be preceded by a descriptor page.  In a small
-environment, this doesn't make sense, and is just a waste of paper.
-.LI
-The parameter \f(CWmx\fP tells \fIlpd\fP\| the maximum size of a spool job in
-kilobytes.  If the job is larger than this value, \fIlpd\fP\| refuses to print
-it.  In our case, we don't want to limit the size.  We do this by setting
-\f(CWmx\fP to 0.
+\f(CWsh\fP is a flag telling
+.Daemon lpd
+to omit a header page.  If you don't have that, every job will be preceded by a
+descriptor page.  In a small environment, this doesn't make sense and is just a
+waste of paper.
+.LI
+The parameter \f(CWmx\fP tells
+.Daemon lpd
+the maximum size of a spool job in kilobytes.  If the job is larger than this
+value,
+.Daemon lpd
+refuses to print it.  In our case, we don't want to limit the size.  We do this
+by setting \f(CWmx\fP to 0.
 .LI
 .X "print filter"
 .X "filter, print"
-\f(CWif\fP tells \fIlpd\fP\| to apply a \fIfilter\fP\| to the job before
-printing.  We'll look at this below.
-.LI
-In the remote printer entry, \f(CWrm=freebie\fP tells \fIlpd\fP\| to send the
-data to the machine called \f(CWfreebie\fP.  This could be a fully qualified
-domain name, of course.
-.LI
-In the remote printer entry, \f(CWrp=lp\fP tells \fIlpd\fP\| the name of the
-printer on the remote machine.  This doesn't have to be the same name as the
-name on the local machine.
+\f(CWif\fP tells
+.Daemon lpd
+to apply a \fIfilter\fP\/ to the job before printing.  We'll look at this below.
+.LI
+In the remote printer entry, \f(CWrm=freebie\fP tells
+.Daemon lpd
+to send the data to the machine called \f(CWfreebie\fP.  This could be a fully
+qualified domain name, of course.
+.LI
+In the remote printer entry, \f(CWrp=lp\fP tells
+.Daemon lpd
+the name of the printer on the remote machine.  This doesn't have to be the same
+name as the name on the local machine.
 .Le
 .H3 "Remote printing"
+.Pn remote-printer
 In a network, you don't need to have a printer on every machine; you can print
-on another machine on the same network.  As we have seen from the
-\fI/etc/printcap\fP\| example above, the spooler supports this configuration.
-There are a couple of things to consider:
+on another machine (which may be a printer) on the same network.  There are a
+couple of things to consider:
 .Ls B
 .LI
 There are two machines involved in remote printing, the client (``local'')
-machine and the server (``remote'') machine.  We've seen a typical client entry
-above.  You specify the name of the server machine with the \f(CWrm\fP
+machine and the server (``remote'') machine.
+.LI
+On the client, you specify the name of the server machine with the \f(CWrm\fP
 capability, and you specify the name of the printer with the \f(CWrp\fP
-capability.  You don't specify the name of the device with an \f(CWlp\fP
-capability.
+capability.  You don't specify any \f(CWlp\fP (device name) capability.  A
+typical entry might look like this:
+.Dx
+lp|HP LaserJet 6MP on freebie:\e
+        :rm=freebie:sd=/var/spool/output/freebie:lf=/var/log/lpd-errs:mx#0:
+.De
+.sp -1v
+.LI
+On the client machine, you must also create the spool directory,
+.Directory /var/spool/output/freebie
+in the example above.
 .LI
 On the server machine, you don't need to do anything special with the
-\fI/etc/printcap\fP\| file.  You need an entry for the printer specified in the
-client machine's \f(CWrp\fP entry, of course.
+.File /etc/printcap
+file.  You need an entry for the printer specified in the client machine's
+\f(CWrp\fP entry, of course.
 .LI
 On the server machine you must allow spooler access from the client machine.
-Add the name of the machine to the file \fI/etc/hosts.lpd\fP\| on a line by
-itself.
+For a BSD machine, you add the name of the machine to the file
+.File /etc/hosts.lpd
+on a line by itself.
 .Le
-That's all there is to it!
 .H3 "Spooler filters"
 .X "spooler filter"
 .X "print filter"
 .X "filter, print"
 .Pn staircase
-Probably the least intelligible entry in the previous configuration file was the
-\f(CWif\fP entry.  It specifies the name of an \fIinput filter\fP, a program
-through which \fIlpd\fP\| passes the complete print data before printing.
+Probably the least intelligible entry in the configuration file on page
+.Sref \*[printcap] \&
+was the \f(CWif\fP entry.  It specifies the name of an \fIinput filter\fP, a
+program through which
+.Daemon lpd
+passes the complete print data before printing.
 .P
 What does it do that for?  There can be a number of reasons.  Maybe you have
-data in a format which isn't fit to print.  For example, it might be PostScript,
+data in a format that isn't fit to print.  For example, it might be PostScript,
 and your printer might not understand PostScript.  Or it could be the other way
-around: your printer understands \fIonly\fP\| PostScript, and the input isn't
+around: your printer understands \fIonly\fP\/ PostScript, and the input isn't
 PostScript.
 .P
 There's a more likely reason to require a filter, though: most printers still
@@ -224,7 +258,9 @@
 (\fBCtrl-M\fP or \f(CB^M\fP) to start at the beginning of the line, and a new
 line character (\fBCtrl-J\fP or \f(CB^J\fP) to advance to the next line.  UNIX
 uses only \f(CB^J\fP, so if you copy data to it, you're liable to see a
-staircase effect.  For example, \fIps\fP\| may tell you:
+\fIstaircase effect\fP.  For example,
+.Command ps
+may tell you:
 .Dx
 $ \f(CBps\fP
   PID  TT  STAT      TIME COMMAND
@@ -244,161 +280,107 @@
 There are a number of ways to solve this problem:
 .Ls B
 .LI
-You may be able to configure your printer to interpret \fBCtrl-J\fP as both
-\fBnewline\fP and \fBreturn\fP, and to ignore \fBCtrl-M\fP.  Check your printer
-handbook.
+You may be able to configure your printer to interpret \fBCtrl-J\fP as both new
+line and return, and to ignore \fBCtrl-M\fP.  Check your printer handbook.
 .LI
 You may be able to issue a control sequence to your printer to tell it to
 interpret \fBCtrl-J\fP as both new line and return to the beginning of the line,
 and to ignore \fBCtrl-M\fP.  For example, HP LaserJets and compatibles will do
 this if you send them the control sequence \fBESC\f(CW&k2G\fR.
 .LI
-You can write an \fIinput filter\fP\| which transforms the print job into a form
-which the printer understands.  We'll look at this option below.
+You can write an \fIinput filter\fP\/ that transforms the print job into a form
+that the printer understands.  We'll look at this option below.
 .Le
-.X "/usr/local/libexec/lpfilter"
+.ne 15v
 There are a couple of options for the print filter.  One of them, taken from the
 online handbook, sends out a LaserJet control sequence before every job.  Put
-the following shell script in \fI/usr/local/libexec/lpfilter\fP\|:
+the following shell script in
+.File /usr/local/libexec/lpfilter \/:
 .Dx
 #!/bin/sh
 printf "\e033&k2G" && cat && printf "\ef" && exit 0
 exit 2
 .De
 .Figure-heading "Simple print filter"
-.Tn print-filter
+.Fn print-filter
 This approach does not work well with some printers, such as my HP LaserJet 6MP,
 which can print both PostScript and LaserJet (natural) formats at random.  They
 do this by recognizing the text at the beginning of the job.  This particular
 filter confuses them by sending a LaserJet command code, so the printer prints
 the PostScript as if it were plain text.
-..if XXX
 .P
-This somewhat more complicated filter is written in C.  It replaces all
-\fBCtrl-J\fPs with \fBCtrl-J\fP \fBCtrl-M\fP:
-.Dx
-#include <errno.h>
-#include <stdio.h>
-#include <strings.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#define LINELENGTH 2000                             /* max length of program line */
-#define MAXLINES 54                                 /* number of lines on page */
-  char inbuf [LINELENGTH];                          /* input buffer */
-  char outbuf [LINELENGTH * 2];                     /* and output buffer */
-
-#undef stdin
-#undef stdout
-#define stdin 0
-#define stdout 1
-
-int main (int argc, unsigned char *argv [])
-{
-  while (1)
-    {
-    int incount,                                    /* length of input line */
-        inptr,                                      /* index in input line */
-        outptr;                                     /* and in output line */
-
-    if ((incount = read (stdin, inbuf, LINELENGTH)) < 0) /* error on input? */
-      {
-      openlog (argv [0], LOG_ODELAY | LOG_CONS, LOG_AUTH); /* open system log */
-      syslog (LOG_ERR, "Error on stdin: %s, exiting", strerror (errno)); /* complain */
-      return 1;                                     /* then die */
-      }
-    else if (incount == 0)                          /* finished */
-      return 0;                                     /* no more, no more */
-    inptr = outptr = 0;
-    while (inptr < incount)                         /* for each character */
-      {
-      if (inbuf [inptr] == '\en')                    /* LF, */
-        outbuf [outptr++] = '\er';                   /* precede with CR */
-      outbuf [outptr++] = inbuf [inptr];
-      inptr++;
-      }
-    if ((write (stdout, outbuf, outptr)) < outptr)  /* couldn't write? */
-      {
-      openlog (argv [0], LOG_ODELAY | LOG_CONS, LOG_AUTH); /* open system log */
-      syslog (LOG_ERR,
-              "Error on writing to printer: %s, exiting",
-              strerror (errno));                    /* and complain */
-      return 1;                                     /* then die */
-      }
-    }
-  }
-.De
-.Figure-heading "Line printer filter in C"
-.Tn c-lp-filter
-..endif
-The source file \fI\*[skelc]/scripts/lpfilter.c\fP contains a filter which
-replaces all \fBCtrl-J\fPs with \fBCtrl-J\fP \fBCtrl-M\fP.  Compile this program
-and store the executable in \fI/usr/local/libexec/lpfilter\fP:
-.Dx
-# \f(CBcc \*[skelc]/scripts/lpfilter.c -o /usr/local/libexec/lpfilter\fP
-.De
-.P
-That's all you normally need to do to set up your printers.  Next, you should
-test them.
+In this kind of situation, the standard filters are no longer sufficient.  You
+can solve the problem with the port \fIapsfilter\fP, which is in the Ports
+Collection.
+.\" XXX or at .Sref \*[apsfilter] .
 .H2 "Starting the spooler"
-As we saw above, the line printer dmon \fIlpd\fP\| is responsible for printing
-spooled jobs.  By default it isn't started at boot time.  If you're
-\f(CWroot\fP, you can start it by name:
+As we saw above, the line printer daemon
+.Daemon lpd
+is responsible for printing spooled jobs.  By default it isn't started at boot
+time.  If you're \f(CWroot\fP, you can start it by name:
 .Dx
 # \f(CBlpd\fP
 .De
 Normally, however, you will want it to be started automatically when the system
 starts up.  You do this by setting the variable \f(CWlpd_enable\fP in
-\fI/etc/rc.conf\fP\|:
+.File /etc/rc.conf \/:
 .Dx
 lpd_enable="YES"			# Run the line printer daemon
 .De
-See page \*[rc.conf] for more details of \fI/etc/rc.conf\fP.
+See page \*[rc.conf] for more details of
+.File /etc/rc.conf .
 .P
-Another line in \fI/etc/rc.conf\fP\| refers to the line printer dmon:
+You can also add another line referring to the line printer daemon to
+.File /etc/rc.conf \/:
 .Dx
 lpd_flags=""				# Flags to lpd (if enabled).
 .De
-You don't normally need to change this line.  See the man page for \fIlpd\fP\|
+You don't normally need this line.  See the man page for
+.Daemon lpd
 for details of the flags.
 .H2 "Testing the spooler"
-.X "testing the spooler"
+.X "testing, spooler"
 .X "spooler, testing"
-To test the spooler, you can run the \fIlptest\fP\| program again.  This time,
-however, instead of sending it directly to the printer, you send it to the
-spooler:
+To test the spooler, you can run the
+.Command lptest
+program again.  This time, however, instead of sending it directly to the
+printer, you send it to the spooler:
 .Dx
-$ \f(CBlptest 20 5 | lpr\fP
+$ \f(CBlptest 80 5 | lpr\fP
 .De
 The results should look like: 
 .Dx
-!"#$%&'()*+,-./01234
-"#$%&'()*+,-./012345
-#$%&'()*+,-./0123456
-$%&'()*+,-./01234567
-%&'()*+,-./012345678
+!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\e]^_`abcdefghijklmnop
+"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\e]^_`abcdefghijklmnopq
+#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\e]^_`abcdefghijklmnopqr
+$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\e]^_`abcdefghijklmnopqrs
+%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\e]^_`abcdefghijklmnopqrst
 .De
+.SPUP
 .ne 3i
 .H2 "Troubleshooting"
 .X "troubleshooting, spooler"
 .X "spooler, troubleshooting"
-Here's a list of the most common problems and how to solve them:
+Here's a list of the most common problems and how to solve them.
 .br
-.TB "Common printer problems"
+.Table-heading "Common printer problems"
 .TS H
-box,center,tab(#) ;
-| lw25 | lw53 | .
-Problem#Cause
-=
+tab(#) ;
+lw27 | lw42 .
+\fBProblem#\fBCause
+_
 .TH N
 T{
+.nh
 The printer prints, but the last page doesn't appear.  The status shows that the
 printer still has data in the buffer.  After several minutes, the last page may
 appear.
+.hy
 T}#T{
 Your output data is not ejecting the last page.  The printer is configured to
-either wait for an explicit eject request (the ASCII \fIForm feed\fP\|
+either wait for an explicit eject request (the ASCII \fIForm feed\fP\/
 character, \fBCtrl-L\fP) or to eject after a certain period of time.
+.hy
 .P
 You have a choice as to what you do about this.  Usually you can configure the
 printer, or you could get the print filter to print a form feed character at the
@@ -410,9 +392,9 @@
 T{
 The lines wander off to the right edge of the paper and are never seen again.
 T}#T{
-This is the \fIstaircase effect\fP\|
-that we saw on page \*[print-filter-page].
-See there for a couple of solutions.
+This is the \fIstaircase effect\fP.  Refer to page
+.Sref \*[print-filter-page] \&
+for a couple of solutions.
 T}
 .sp
 T{
@@ -424,7 +406,7 @@
 T}
 .sp
 T{
-The output was completely unintelligible random characters.
+The output contained completely unintelligible random characters.
 T}#T{
 On a serial printer, if the characters appear slowly, and there's a predominance
 of the characters \f(CW{|}~\fP, this probably means that you have set up the
@@ -435,61 +417,58 @@
 T{
 The text was legible, but it bore no relationship to what you wanted to print.
 T}#T{
-One possibility is that you are sending PostScript output to your printer.  Look
-at the example on page \*[PostScript] to check if it is PostScript.  If it is,
-your printer is not interpreting it correctly, either because it doesn't
-understand PostScript, or because it has been confused (see the discussion on
-page \*[print-filter-page] for one reason).  We'll look at PostScript in more
-detail on page \*[PostScript].
+One possibility is that you are sending PostScript output to your printer.  See
+the discussion on page
+.Sref \*[PostScript] \&
+to check if it is PostScript.  If it is, your printer is not interpreting it
+correctly, either because it doesn't understand PostScript, or because it has
+been confused (see the discussion on page \*[print-filter-page] for one reason).
 T}
 .sp
 T{
 The display on the printer shows that data are arriving, but the printer doesn't
 print anything.
 T}#T{
-You might be sending normal text to a PostScript printer which doesn't
+You might be sending normal text to a PostScript printer that doesn't
 understand normal text.  In this case, too, you will need a filter to convert
 the text to PostScript\(emthe opposite of the previous problem.
 .P
 Alternatively, your printer port may not be interrupting correctly.  This will
 not stop the printer from printing, but it can take up to 20 minutes to print a
 page.  You can fix this by issuing the following command, which puts the printer
-\fI/dev/lpt0\fP\| into polled mode:
+.Device lpt0
+into polled mode:
 .Dx
 # \f(CBlptcontrol -p\fP
 .De
 T}
-.sp
-.nf
-.na
+.\" XXX find a better way to do this.
 T{
-You get the message \f(CWlpr: cannot create /var/spool/output/freebie/.seq\fP
+You get the message \f(CWlpr: cannot create freebie/.seq\fP
 T}#T{
-You have forgotten to create the spool directory \fI/var/spool/output/freebie\fP.
+You have forgotten to create the spool directory
+.Directory /var/spool/output/freebie .
 T}
-.br
-.fi
-.ad
 .TE
-.sp
+.hy
 .H2 "Using the spooler"
 .X "Using the spooler"
-.X "lpr, command"
-.X "command, lpr"
 Using the spooler is relatively simple.  Instead of outputting data directly to
-the printer, you \fIpipe\fP\| it to the spooler \fIlpr\fP\| command.  For
-example, here is the same print command, first printing directly to the printer,
-and secondly via the spooler:
+the printer, you \fIpipe\fP\/ it to the spooler
+.Command lpr
+command.  For example, here is the same print command, first printing directly
+to the printer, and secondly via the spooler:
 .Dx
 # \f(CBps waux > /dev/lpt0\fP
-# \f(CBps waux | lpr\fP
+$ \f(CBps waux | lpr\fP
 .De
 .X "job, spooler"
 .X "spooler, job"
-.X "lpq, command"
-.X "command, lpq"
-The spooler creates a \fIjob\fP\| from this data.  You can look at the current
-print queue with the \fIlpq\fP\| program:
+Note the difference in prompt: you have to be \f(CWroot\fP to write directly to
+the printer, but normally anybody can write to the spooler.  The spooler creates
+a \fIjob\fP\/ from this data.  You can look at the current print queue with the
+.Command lpq
+program:
 .Dx
 $ \f(CBlpq\fP
 waiting for lp to become ready (offline ?)
@@ -499,11 +478,12 @@
 3rd    yvonne     31   (standard input)                      3395 bytes
 4th    root       0    (standard input)                      2611 bytes
 .De
-.X "lpd dmon"
-.X "dmon, lpd"
-The first line is a warning that \fIlpd\fP\| can't currently print.  You should
-take it seriously.  In this example, the printer was deliberately turned off so
-that the queue did not change from one example to the next.
+.ne 5v
+The first line is a warning that
+.Daemon lpd
+can't currently print.  Take it seriously.  In this example, the printer was
+deliberately turned off so that the queue did not change from one example to the
+next.
 .P
 Normally, the job numbers increase sequentially: this particular example came
 from three different machines.  You can get more detail with the \f(CW-l\fP
@@ -525,17 +505,15 @@
         (standard input)                 2611 bytes
 .De
 .H3 "Removing print jobs"
-.X "Removing print jobs"
-.X "lprm, command"
-.X "command, lprm"
+.X "removing print jobs"
 Sometimes you may want to delete spool output without printing it.  You don't
 need to do this because of a printer configuration error: just turn the printer
 off, fix the configuration error, and turn the printer on again.  The job should
 then be printed correctly.  But if you discover that the print job itself
-contains garbage, you can remove it with the \fIlprm\fP\|
-program.  First,
-though, you need to know the job number.  Assuming the list we have above, we
-might want to remove job 30:
+contains garbage, you can remove it with the
+.Command lprm
+program.  First, though, you need to know the job number.  Assuming the list we
+have above, we might want to remove job 30:
 .Dx
 # \f(CBlprm 30\fP
 dfA030presto.example.org dequeued
@@ -547,21 +525,26 @@
 2nd    yvonne     31   (standard input)                      3395 bytes
 3rd    root       0    (standard input)                      2611 bytes
 .De
-If the printer is offline, it may take some time for the \fIlprm\fP\| to
-complete.
+If the printer is offline, it may take some time for the
+.Command lprm
+to complete.
 .H2 "PostScript"
 .Pn PostScript
 .X "PostScript"
 .X "Page Description Language"
-We've encountered the term \fIPostScript\fP\| several times already.  It's a
-powerful \fIPage Description Language\fP.  With it, you can transmit detailed
-documents such as this book electronically and print them out in exactly the
-same form elsewhere.  PostScript is a very popular format on the World-Wide Web,
-and browsers like Netscape usually print in PostScript format.
+We've encountered the term \fIPostScript\fP\/ several times already.  It's a
+\fIPage Description Language\fP.  With it, you can transmit detailed documents
+such as this book electronically and print them out in exactly the same form
+elsewhere.\*F
+.FS
+This is in fact the way this book was sent to the printers.
+.FE
+PostScript is a very popular format on the World Wide Web, and web browsers like
+Netscape usually print in PostScript format.
 .P
 .X "escape sequences, printer" 
 Most other document formats describe special print features with \fIescape
-sequences\fP, special commands which start with a special character.  For
+sequences\fP, special commands that start with a special character.  For
 example, the HP LaserJet and PCL formats use the ASCII \fBESC\fP character
 (\f(CW0x1b\fP) to indicate the beginning of an escape sequence.  PostScript uses
 the opposite approach: unless defined otherwise, the contents of a PostScript
@@ -583,120 +566,282 @@
 .De
 .X "prologue, PostScript"
 .X "PostScript, prologue"
-This is the \fIprologue\fP\| (the beginning) of the PostScript output for this
-chapter.  The \fIprologue\fP\| of such a program can be several hundred
+This is the \fIprologue\fP\/ (the beginning) of the PostScript output for this
+chapter.  The \fIprologue\fP\/ of such a program can be several hundred
 kilobytes long if it includes embedded fonts or images.  A more typical size is
 about 500 lines.
 .P
 You can do a number of things with PostScript:
 .Ls B
 .LI
-.X "ghostscript, command"
-.X "command, ghostscript"
-.X "ghostview, command"
-.X "command, ghostview"
-You can look at it with \fIghostscript\fP\| or \fIghostview\fP, both of which
-are in the Ports Collection.
-.LI
-Many printers understand PostScript and print it directly.  You should know
-this, since it's an expensive option, but in case of doubt check your printer
-manual.
+You can look at it with
+.Command gv ,
+which is in the Ports Collection.  We'll look at this option below.
+.LI
+Many printers understand PostScript and print it directly.  If yours does, you
+probably know about it, since it's an expensive option.  In case of doubt, check
+your printer manual.
 .LI
 If your printer doesn't understand PostScript, you can print with the aid of
-ghostscript.
+ghostscript.  The \fIapsfilter\fP\/ port
+.\" XXX (page .Sref \*[apsfilter] )
+does this for you.
 .Le
-.H3 "Viewing with \fIghostview\fP\|"
-.Pn ghostscript
-.X "viewing with ghostview"
-.X "ghostview, viewing with"
-.Df
-.PIC "images/ghostview.ps" 4i
-.Figure-heading "\fIghostview\fP\| display"
-.Tn ghostview &
-.DE
-\fIghostscript\fP\| and \fIgv\fP\| are both part of the instant workstation port
-which we discussed on page
+.H3 "Viewing with gv"
+.X "viewing with gv"
+.X "gv, viewing with"
+.X "selFile, gv window"
+.Command gv
+is part of the instant workstation port that we discussed on page
 .Sref \*[instant-workstation] .
-.X "ghostview, command"
-.X "command, ghostview"
-To view a file with \fIghostview\fP, simply start it:
-.Dx
-$ \f(CBghostview &\fP
-.De
-.X "selFile, ghostview window"
-You will get a blank display, but you can open a file window by pressing
-\f(CWo\fP, after which you can select files and display them.  Figure
-\&\*[ghostview] shows the display of a draft version of this page with an
-overlaid open window at the top left.  The \fIselFile\fP\|
-window contains a
+To view a file with
+.Command gv ,
+simply start it:
+.Dx
+$ \f(CBgv \f[CBI]filename\fP\/ &\fP
+.De
+If you don't specify a file name, you get a blank display.  You can then open a
+file window by pressing \f(CWo\fP, after which you can select files and display
+them.  Figure \&\*[gv] shows the display of a draft version of this page with an
+overlaid open window at the top right.  The \fIOpen File\fP\/ window contains a
 field at the top into which you can type the name of a file.  Alternatively, the
-three columns below, with scroll bars, allow you to browse the current directory
-and the parent and grandparent directories.  The interface looks relatively
-primitive, but it works.
+columns below, with scroll bars, allow you to browse the current directory and
+the parent directories.
 .P
 The window below shows the text of the previous page (roughly) on the right hand
-side. with drag scroll bars operated by the middle button.  At top left are five
-oval menu buttons which you can select with the left mouse button.  Note
-particularly the \f(CWMagstep\fP button, which sets the size of the display.
+side.  Instead of scroll bars, there is a scroll area below the text \f(CWSave
+Marked\fP.  You can scroll the image in all directions by selecting the box with
+the left mouse button and moving around.  At top left are menu buttons that you
+can select with the left mouse button.  Note also the button \f(CW1.414\fP at
+the top of the window: this is the magnification of the image.  You can change
+it by selecting this button: a menu appears and gives you a range of
+magnifications to choose from.
 .P
 The column to the right of these buttons is a list of page numbers.  You can
 select a page number with the middle mouse button.  You can also get an
 enlargement display of the text area around the mouse cursor by pressing the
-left button.  Press the area marked \f(CWDismiss\fP to remove the enlargement.
-.H3 "Printing with \fIghostscript\fP\|"
+left button.
+.PIC "images/gv.ps" 4i
+.Figure-heading "gv display"
+.Fn gv
+.H3 "Printing with ghostscript"
+.Pn ghostscript
 .X "printing with ghostscript"
 .X "ghostscript, printing with"
-.X "ghostscript, command"
-.X "command, ghostscript"
 If your printer doesn't support PostScript, you can still print some semblance
-of the intended text with the help of \fIghostscript\fP.  The results are very
-acceptable with laser and inkjet printers, less so with matrix printers, even 24
-pin versions.
+of the intended text with the help of
+.Command ghostscript .
+The results are very acceptable with modern laser and inkjet printers, less so
+with older dot matrix printers.
 .P
 .X "driver, ghostscript"
 .X "ghostscript, driver"
-To print on your particular printer, you first need to find a \fIdriver\fP\| for
-it in \fIghostscript\fP.  In this context, the term \fIdriver\fP\| means some
-code inside \fIghostscript\fP\| which converts the data into something that the
-printer can print.  Unfortunately, the man page doesn't help much.  To find out
-which driver it supports, start \fIghostscript\fP\| and enter the following in
-the text window, ignoring the display window that it opens:
-.Dx
-$ \f(CBgs\fP							\fIthat's the name of the ghostscript program\fP\|
-Aladdin Ghostscript 5.03 (1997-8-8)
-Copyright (C) 1997 Aladdin Enterprises, Menlo Park, CA.  All rights reserved.
-This software comes with NO WARRANTY: see the file PUBLIC for details.
-GS>\f(CBdevicenames ==\fP				\fIlist device names\fP\|
-[/tiff24nc /ppm /pcxgray /cgm8 /sgirgb /pnm /mgr8 /bmp16m /psmono /pgnm /mgrgray8 /bmp
-16 /png256 /pgm /mgrgray2 /bitcmyk /pnggray /pbm /miff24 /bit /nullpage /pkmraw /pcx24
-b /jpeg /pdfwrite /tifflzw /ppmraw /pcx16 /cgm24 /tiff12nc /pnmraw /pcxmono /cgmmono /
-psgray /pgnmraw /mgr4 /bmp256 /png16m /pgmraw /mgrgray4 /bmpmono /png16 /pbmraw /mgrmo
-no /bitrgb /pngmono /pcxcmyk /jpeggray /pswrite /tiffpack /pkm /pcx256 /cif /t4693d8 /
-paintjet /ljet3d /iwlq /declj250 /appledmp /tiffg32d /t4693d2 /oki182 /ljet2p /iwhi /c
-dj850 /sxlcrt /tiffcrle /st800 /necp6 /ln03 /ibmpro /cdj500 /x11gray2 /faxg32d /r4081 
-/lp8000 /lbp8 /eps9high /cdjcolor /x11alpha /dfaxlow /pxlmono /lj5gray /la75 /epson /c
-cr /xes /pjxl /ljetplus /la50 /djet500c /bjc600 /tek4696 /pj /ljet4 /jetp3852 /deskjet
- /bj10e /tiffg4 /t4693d4 /okiibm /ljet3 /iwlo /cp50 /ap3250 /tiffg3 /stcolor /oce9050 
-/lj250 /imagen /cdj550 /x11mono /faxg4 /sj48 /m8510 /lips3 /epsonc /cdjmono /x11cmyk /
-faxg3 /pxlcolor /lp2563 /la75plus /eps9mid /cdeskjet /x11 /dfaxhigh /pjxl300 /lj5mono 
-/la70 /dnj650c /bjc800 /uniprint /pjetxl /lj4dith /laserjet /djet500 /bj200 /epswrite]
-GS>\f(CB^D\fP							\fIexit\fP\|
-.De
-Unfortunately, it's very difficult to decide which of these drivers does what
-without looking at the source code, or at least the \fIMakefile\fP, so it's
-comforting to know that the most common non-PostScript printer, the
-Hewlett-Packard LaserJet series, uses the driver prefix \f(CWljet\fP.  Modern
-versions will all run with \f(CWljet4\fP; if you run into trouble, try one of
-the older ones.  In particular, the original LaserJet requires the driver
-\f(CWljet\fP.
-.P
-The following one-line script will print PostScript documents to the spooler.
-It is present on the CD-ROM as \fI\*[skelc]/scripts/gsp\fP.
+To print on your particular printer, you first need to find a \fIdriver\fP\/ for
+it in
+.Command ghostscript .
+In this context, the term \fIdriver\fP\/ means some code inside
+\fIghostscript\fP\/ that converts the data into something that the printer can
+print.
+.P
+We've already seen how to use
+.File /etc/printcap .
+In this case, we'll need an \fIinput filter\fP, a script or program that
+transforms the PostScript data into a form that the printer understands.  The
+entry in
+.File /etc/printcap
+is pretty much the same for all printers:
+.Dx
+ps|HP OfficeJet 725 with PostScript:\e
+      :lp=/dev/lpt0:sd=/var/spool/output/colour:lf=/var/log/lpd-errs:sh:mx#0:\e
+      :if=/usr/local/libexec/psfilter:
+.De
+This entry defines a printer called \fIps\fP.  The comment states that it's an
+HP OfficeJet, but that's only a comment.  Obviously you should choose a comment
+that matches the printer you really have.
+.P
+The printer is connected to
+.Device lpt0 ,
+the first parallel printer.  Spool data is collected in the directory
+.Directory /var/spool/output/colour .
+You must create this directory, or printing will fail, and depending on what you
+use to print, you may not even see any error messages.  They also don't appear
+on the log file, which in this case is
+.File /var/log/lpd-errs .
+.P
+The important entry is in the last line, which refers to the input filter
+.File /usr/local/libexec/psfilter .
+This file contains the instructions to convert the PostScript into something
+that the printer can understand.  For example, for the HP OfficeJet we're
+talking about here, it contains:
+.Dx
+#!/bin/sh
+/usr/local/bin/gs -sDEVICE=pcl3 -q -sPaperSize=a4 -dNOPAUSE -sOutputFile=- -
+.De
+These options state:
+.Ls B
+.LI
+Use \fIghostscript\fP\/ device \fIpcl3\fP.  This is the driver to choose for
+most Hewlett Packard inkjet printers.  We'll see alternatives for other printers
+below.
+.LI
+The output file is \fIstdin\fP\/ (see page
+.Sref \*[stdout] ).
+By convention, a number of programs use the character \f(CW-\fP to represent the
+\fIstdout\fP\/ stream.
+.LI
+\f(CW-q\fP means \fIquiet\fP.  Normally
+.Command ghostscript
+outputs a message on startup, and it often outputs other informative messages as
+well.  In this case, we're using it as a filter, so we don't want any output
+except what we print.
+.LI
+Don't pause between pages.  If you don't specify this parameter,
+.Command ghostscript
+waits for a key press at the end of each page.
+.LI
+The paper size is the international A4 format.  By default,
+.Command ghostscript
+produces output for American standard 8.5 \(mu 10 inch ``letter'' paper.
+.LI
+The character \f(CW-\fP by itself tells
+.Command ghostscript
+that the input is from \fIstdin\fP.  Together with the output to \fIstdout\fP,
+this makes
+.Command ghostscript
+function as a filter.
+.Le
+.H3 "Which driver?"
+The previous example used the driver for the HP DeskJet.  Well, to be more
+precise, it used one of a plethora of drivers available.  You can find more
+information in the HTML driver documentation at
+.URI /usr/local/share/ghostscript/7.05/doc/Devices.htm .
+The \fI7.05\fP\/ in the name refers to the release of
+.Command ghostscript ,
+which will change.
+.P
+The documentation isn't the easiest to read.  It's probably older than your
+printer, so there's a good chance that it won't mention your specific printer
+model.  You may need to experiment a little before you get things working the
+way you want.
+.H4 "Printer drivers for DeskJets"
+There are at least six sets of drivers for HP DeskJets.  They're all described
+in
+.File Devices.htm ,
+but the following summary may help:
+.Ls B
+.LI
+Hewlett Packard supply their own drivers.  In addition to
+.Command ghostscript ,
+they require server software that you can install from the Ports collection
+.File ( /usr/ports/print/hpijs ).
+.LI
+Next come three different independently written drivers for specific models of
+DeskJet, probably all now obsolete.  If you recognize your printer or something
+similar in one of them, that's a good first choice.
+.LI
+Next comes the generic \fIpcl3\fP\/ driver that was used in the example above.
+It's not mentioned in the documentation.
+.LI
+Finally, \fIuniprint\fP\/ is a completely different driver framework for a
+number of different makes of printer.  It requires a slightly different command
+line, and we'll look at it separately below.
+.Le
+If you're using a DeskJet, you have the choice.  Unfortunately, there's no way
+to know which is best until you've tried them all.  Similar considerations apply
+to other makes of printer.
+.H4 "uniprint drivers"
+The \fIuniprint\fP\/ drivers have a somewhat different kind of interface.
+They're described towards the end of the same
+.File Devices.htm
+file.  To use them, change the driver specification as in the following example,
+that refers to an Epson
 .Dx
 #!/bin/sh
-gs -dNOPAUSE -q -sDEVICE=ljet4 -sOutputFile=\e|lpr -- $*
+/usr/local/bin/gs @stc500ph.upp -q -sPaperSize=a4 -dNOPAUSE -sOutputFile=- - -c quit
 .De
-Note that the output to the printer is binary data, so a filter of the kind
-shown in \fI\*[skelc]/scripts/lpfilter.c\fP will destroy the format and produce
-nonsensical output.  This shouldn't be a problem, since that filter is intended
-specifically for PostScript printers, which don't need \fIghostscript\fP.
+The differences here are:
+.Ls B
+.LI
+The name of the driver (\fIstc500ph.upp\fP\/) is specified differently.
+.LI
+The line ends with a command to the driver itself (\f(CW-c quit\fP).  The exact
+meaning is not documented, though it's easy to guess.
+.SPUP
+.Le
+.H4 "Which drivers?"
+Another problem you might encounter is that it's possible to specify the drivers
+you want in your
+.Command ghostscript
+executable when you build the port.  It's quite possible that the drivers
+described in
+.File -n Devices.htm
+don't exist on your system.  To find out, run
+.Command ghostscript
+interactively with the \f(CW-h\fP (help) option:
+.Dx
+$ \f(CBgs -h\fP
+GNU Ghostscript 7.05 (2002-04-22)
+Copyright (C) 2002 artofcode LLC, Benicia, CA.  All rights reserved.
+Usage: gs [switches] [file1.ps file2.ps ...]
+Most frequently used switches: (you can use # in place of =)
+ -dNOPAUSE           no pause after page   | -q       `quiet', fewer messages
+ -g<width>x<height>  page size in pixels   | -r<res>  pixels/inch resolution
+ -sDEVICE=<devname>  select device         | -dBATCH  exit after last file
+ -sOutputFile=<file> select output file: - for stdout, |command for pipe,
+                                         embed %d or %ld for page #
+Input formats: PostScript PostScriptLevel1 PostScriptLevel2 PDF
+Available devices:
+   x11 x11alpha x11cmyk x11gray2 x11gray4 x11mono x11rg16x x11rg32x md2k
+   md5k md50Mono md50Eco md1xMono bj10e bj10v bj10vh bj200 bjc600 bjc800
+   lips2p lips3 lips4 bjc880j lips4v uniprint dmprt epag escpage lp2000
+   alc8600 alc8500 alc2000 alc4000 lp8800c lp8300c lp8500c lp3000c lp8200c
+   lp8000c epl5900 epl5800 epl2050 epl2050p epl2120 lp7500 lp2400 lp2200
+   lp9400 lp8900 lp8700 lp8100 lp7700 lp8600f lp8400f lp8300f lp1900 lp9600s
+   lp9300 lp9600 lp8600 lp1800 mjc180 mjc360 mjc720 mj500c deskjet djet500
+   cdeskjet cdjcolor cdjmono cdj550 cdj670 cdj850 cdj880 cdj890 cdj1600
+   cdj970 laserjet ljetplus ljet2p ljet3 ljet3d ljet4 ljet4d cljet5 cljet5c
+   cljet5pr lj5mono lj5gray pj pjxl pjxl300 pxlmono pxlcolor pcl3 hpdj ijs
+   npdl rpdl gdi bmpmono bmpgray bmp16 bmp256 bmp16m bmp32b bmpsep1 bmpsep8
+   faxg3 faxg32d faxg4 jpeg jpeggray pcxmono pcxgray pcx16 pcx256 pcx24b
+   pcxcmyk pdfwrite bit bitrgb bitcmyk pbm pbmraw pgm pgmraw pgnm pgnmraw
+   pnm pnmraw ppm ppmraw pkm pkmraw pksm pksmraw pngmono pnggray png16
+   png256 png16m psmono psgray psrgb pswrite epswrite tiffcrle tiffg3
+   tiffg32d tiffg4 tiff12nc tiff24nc tifflzw tiffpack nullpage
+Search path:
+   . : /opt/lib/ghostscript : /opt/lib/ghostscript/fonts :
+   /opt/lib/ghostscript/garamond : /usr/local/share/ghostscript/7.05/lib :
+   /usr/local/share/ghostscript/fonts
+For more information, see /usr/local/share/ghostscript/7.05/doc/Use.htm.
+Report bugs to bug-gs@ghostscript.com, using the form in Bug-form.htm.
+.De
+.SPUP
+.H2 "PDF"
+\fIPDF\fP, or \fIPage Description Format\fP, is a newer format for transferring
+print documents.  Like PostScript, it comes from Adobe, and it is becoming
+increasingly important as a document interchange format on the Internet.
+.P
+There are two ways to handle PDF:
+.Ls B
+.Pn acroread
+.LI
+Use \fIAcrobat Reader\fP, available in the Ports Collection as
+\fI/usr/src/print/acroread5\fP.  The \fI5\fP\/ refers to the version of Acrobat
+Reader and may change.  Acrobat Reader is proprietary, but it's available for
+free, unfortunately only in binary form.  It is quite a convenient way to view
+PDF documents, and it can print them in PostScript formats.  This means that you
+can also use it to convert PDF to PostScript.
+.LI
+\fIghostscript\fP\/ also understands PDF, and it is capable of converting
+between PostScript and PDF in both directions.
+.Command ghostscript
+provides two scripts,
+.Command pdf2ps
+and
+.Command ps2pdf ,
+which act as a front end to
+.Command ghostscript
+to make the job easier.
+.Le
+Unlike PostScript, an editor is available for PDF (\fIAcrobat\fP, the big
+brother of Acrobat Reader).  Unfortunately, it's proprietary and not free, and
+worse still, it's not available for FreeBSD.
