[comp.sources.misc] v07i003: PSF: PostScript filters for SCO Xenix

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (06/04/89)

Posting-number: Volume 7, Issue 3
Submitted-by: tony@ajfcal.UUCP (Tony Field)
Archive-name: psf

[WARNING:  One file in this shar ("testfile") contains ESC characters
(hex 1B, decimal 27).  They may be lost in transmission (the shar will
detect this.  I don't advise "cat"ting this submission to the terminal;
I've made more than one terminal go catatonic that way....  ++bsa]

Since Xenix does not come with any postscript support, the PSF system can
be automatically installed as a "postscript printer" with little more
than "make xenix". The resulting installation correctly builds the
Xenix-conformant printer back-end scripts in such a way that the system
administrator can install the postscript system with the Xenix command
"mkdev lp". It also supports Xenix-styled banner pages and correctly
handles text that is or is not already in postscript format.

For non-Xenix users, the PSF system is a set of postscript filters
that can be used for general text, mail, and nroff printing.  About
the only thing different than other ps filters is the ability to
print pages in landscape or portrait, 1-up, 2-up, or 4-up on a page.

I would like to consider psf's ability to recognize "escape sequences" as
a useful feature - but probably no one will ever use it the way that I
intended. PSF can recognize simple escape sequences for font and point
size control. If you are using a text editor such as vi, you may insert
escape sequences to cause underlines, italics, font changes. This is a
nice way to quickly whip off a letter with a little class - no need to
use a word processor or n/troff/TeX: simply send the text file to psf.

I happen to like to conserve paper. I tend to print source listings
2-up on a page with 80-100 lines per column; my mail boxes are
printed 4-up for permanent records (240 possible printed mail lines
on an 8.5x11 page).

Other ps filters generally tend to provide extensive "font and layout
control" for various types of documents: recognition of c syntax,
mail headers and summarization, etc. etc.  My filters are relatively
weak in this area - although quite useful.

Unfortunately, I know nothing about other *nix systems. I don't know if
the xenix installation is similar to that of AIX - which, i think, also
knows nothing about postscript.

It surprises me that SCO and other vendors do not provide even minimal
postscript support.

One file "testfile" should contain true ESCape characters (ctrl-[).
I am pretty sure that the mail system will translate the ESCapes to
the text string "\\033".  I have provided instructions in Readme to use 
"sed" to correctly translate the strings back to the ESCape character.

I couldn't figure out a conversion shell script that I could mail that
wouldn't undergo the same translation problem!

At any rate, here is the new release of PSF:  please destroy the
old version..   I hope that the quality of source and documentation
are up to the standards required by this demanding user community.

tony...   ((( ps..  howcome you are up at 11:30 on a Sunday Night?)))
 ----------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Readme Readme.Xenix psf.1 Makefile psf.c pnf.c pmf.c
#   psbanner.c psdetect.c postscript.LP testfile
# Wrapped by ajf@ajfcal on Mon May 15 14:30:49 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Readme' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Readme'\"
else
echo shar: Extracting \"'Readme'\" \(3901 characters\)
sed "s/^X//" >'Readme' <<'END_OF_FILE'
X                    PSF POSTSCRIPT FILTER
X
XThe postscript filter "psf" is used for general purpose printing.
XProvisions are made for 1-up, 2-up or 4-up logical printing on each
Xphysical page.  Changes in fonts or point size may be done within
Xa page using prescribed escape sequences.  Such sequences are
Xgenerated by the pre-filters "pnf" and "pmf".
X
XNroff'ed documents may be pre-filtered with "pnf" to provide italic,
Xbold, or underlined text. Since nroff uses backspace/overstrike to
Xgenerate underline and bold, "pnf" examines all backspace sequences
Xand generates escape sequences that can be used by "psf" to print
Xproper underlined and bold text.
X
XMail documents may be pre-filtered with "pmf" to provide some bolding 
Xand line formatting on various mail header lines.
X
XThe man-page for psf and friends are in "psf.1".
X
XXenix users should examine the Readme.Xenix file if a postscript printer
Xmodel should be implemented. This allows the use of the "lp" command for
Xgeneral printing.
X
XIf you are not using Xenix but wish to use psf as a back-end filter for
Xgeneral printing with "lp", then the Xenix-oriented back-end is in
Xfile "postscript.LP".  This, and the banner-generating programme
X"psbanner.c", may be modified for your system.
X
XINSTALLATION.
X^^^^^^^^^^^^^
XInstallation will generate the following binaries (name conflicts???)
X
X	psf    pmf    pnf     (and, for Xenix,  psdetect  psbanner)
X
XThe system is built with  "make all".
X
XIf you are using "non-standard fonts", there is a remote possibility that
Xthe underline parametrics within FontInfo are missing. If this is the
Xcase, you may use an optional underline strategy by adding the -DFONTINFO
Xto the cc command line.  This generates underlines 2 points below
Xthe text base line.  Psf does NOT verify that FontInfo is complete....
X
XThe system may be installed into a chosen binary directory (edit
Xthe Makefile) with:
X
X	make install
X
XAfter you compile the system, test the printing with the command
X(see the note below regarding possible problems with testfile):
X
X	psf testfile | lp
X
XAfter you have installed the man pages (psf.1), you may print them with:
X
X	man psf | pnf | psf -2 | lp
X
XTo test general file printing, print the source for the filters 4-up
Xon a page with:
X
X	psf -4xh psf.c pnf.c pmf.c | lp
X
XTesting the mail print filter is easily done (assuming 4-up printing)
X
X	pmf < mail.box | psf -4x | lp
X
X
XNOTE:  TESTFILE
X^^^^^^^^^^^^^^^
XThe "testfile" should contain many ESCape characters (octal 33). The mail
Xsystem may change the escape character into the text string "\033". You
Xmay have to edit the testfile and replace all "\033" strings with true
Xescape characters. A true escape character is CTRL-[.
X
XOne easy way to correct this is with sed:
X
X	sed 's@\\033@<CTRL-[>@g' testfile > tfile
X                     +------+
X                     actually type the ESCape character CTRL-[ 
X
XOther Nonsense:
X^^^^^^^^^^^^^^^
XThe following fonts are assumed to be available in the postscript printer.
X(These fonts are available in the Nec LC890 SilentWriter)
X
X         Courier               Helvetica
X         Times-Roman           AvantGarde-Book
X         Bookman-Light         NewCenturySchlbk-Roman
X         Palatino-Roman        ZapfChancery-MediumItalic
X         Helvetica-Narrow
X         
XIf your printer does not have all of these fonts, or if other fonts are
Xavailable, you must change the font defintion table in psf.c. The man
Xpage psf.1 should be changed reflect the font numbering and definition.
XRoutines pmf.c, pnf.c and psbanner use Courier, Helvetica, and
XTimes-Roman: these are probably available on all systems and need not be
Xchanged.
X
XThe programmes have been used only on Xenix 2.2.3/386 and a NEC LC890
Xpostscript printer. I hope the code is portable. If there are any
Xproblems, please send email: I will attempt to correct the bugs, time
Xbeing available.
X
XTony Field      calgary!ajfcal!tony@ai.toronto.edu
END_OF_FILE
if test 3901 -ne `wc -c <'Readme'`; then
    echo shar: \"'Readme'\" unpacked with wrong size!
fi
# end of 'Readme'
fi
if test -f 'Readme.Xenix' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Readme.Xenix'\"
else
echo shar: Extracting \"'Readme.Xenix'\" \(2619 characters\)
sed "s/^X//" >'Readme.Xenix' <<'END_OF_FILE'
XPSF:		X E N I X    I N S T A L L A T I O N	(xenix 2.2.3)
X                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
XThe postscript filter system may be installed on Xenix 2.2.3 for all regular
Xprinting operations. A new "printer model" (postscript.psf) is created which
Xincludes banner printing support with "psbanner". The psbanner parameter
Xlist is compatible with those generated by lp. Thus "lp my.file" 
Xor "cat my.file | lp" works as expected with and without banners.
X
XIf you wish to use the default (binaries placed in /usr/bin, printing is
Xto be done with 60 lines per page), then, as root, issue the command:
X
X		make xenix
X
XThe system will automatically compile and install.  After the binaries
Xare copied to the appropriate directories, the print spooler back-end
Xscript file is placed in /usr/spool/lp/model/postscript.psf and 
X"mkdev lp" is invoked.
X
X
XIf you do not wish to use the default conditions, then do the following:
X
X1.	Edit the Makefile (BINDIR=) to specify the destination directory
X	in which the various printer binaries are to be installed.
X	The default is /usr/bin.
X
X2.	Edit the Makefile (PSFOPT=) to specify default options for
X	the psf filter.
X
X3.	Make the executables with   "make all".
X
X4.	As root,   "make xenix".
X
X	This will copy all executables to the chosen binary directory
X	and will add a "printer model" named "postscript.psf" to
X	the /usr/spool/lp/model directory.  (See  lp (C),  lpadmin (C))
X	
X	"mkdev lp" is automatically called to allow you to build your
X	postscript printer.
X
X5.	Run the installation tests as described in "Readme".
X
XThe resulting "printer" will examine the print file for a "%!" string in
Xthe first text line. If it does exist, it will NOT filter the file with "psf"
Xbut simply "cat" the file to the printer. If the string cannot be found,
Xthe the "psf" filter is automatically called to create postscript
Xconformant output.
X
XThe mail filter (pmf) and nroff filter (pnf) output no longer have to
Xbe piped through psf by hand.  For example:
X
X	man vi | pnf -ix | lp
Xor
X	pmf < my.mail.box | lp
X
XMultiple printers may be created using the psf filters.  The generated
Xfiles in /usr/spool/interface may be edited to reflect different psf
Xparameters such as 2-up, landscape or different lines per page.
X
X=============
XNOTE:  Some software generating postscript output uses the string "%!"
X       to identify the beginning of postscript code.  As a result,
X       "psdetect.c" examines for this string.  If you wish, you might
X       change it to examine for "%!PS-Adobe" which might be more robust
X       but not as general.
X==============
X
XTony Field.       tony@ajfcal
END_OF_FILE
if test 2619 -ne `wc -c <'Readme.Xenix'`; then
    echo shar: \"'Readme.Xenix'\" unpacked with wrong size!
fi
# end of 'Readme.Xenix'
fi
if test -f 'psf.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'psf.1'\"
else
echo shar: Extracting \"'psf.1'\" \(8529 characters\)
sed "s/^X//" >'psf.1' <<'END_OF_FILE'
X.TH PSF 1 ""
X.SH NAME
Xpsf \- postscript filter
X.br
Xpnf \- postscript nroff pre-filter
X.br
Xpmf \- postscript mail pre-filter
X.SH SYNOPSIS
X.nf
X
Xpsf [ -l n ] [ -1|2|4 ] [ -f n ] [ -h ] [ -t n ]
X    [ -H text ] [ -p n ] [ -w ] [ -x ] file file ..
X
X   where        -l n      lines per page (default=60)
X                -1|2|4    print 1,2 or 4 up on a page (default=1)
X                -f n      font number to use (default=0=Courier)
X                -h        put file name as header on each page
X                -H text   put text as header on each page
X                -t n      set tabs to n (default=8)
X                -p n      set point size to n
X                -w        set landscape page (wide)
X                -x        place a cross on 4-up printing
X                file..    name of files to be printed (or stdin)
X   output: stdout
X
X   Fonts selection with -f n
X         0 Courier         1 Helvetica
X         2 Times-Roman     3 AvantGarde-Book
X         4 Bookman-Light   5 NewCenturySchlbk-Roman
X         6 Palatino-Roman  7 ZapfChancery-MediumItalic
X         8 Helvetica-Narrow
X
Xpnf [ -i ] [ -x ] <in.file >out.file
X
X   where     -i = use italic font instead of underline
X             -x = adjust for 59 line man-pages on xenix
X
Xpmf [ -s ] <in.file >out.file
X
X   where     -s = show all header lines
X.fi
X
X.RS -5
XDESCRIPTION
X.RE
XPsf will accept text and filter it to print on postscript printers.
XThe print may be "1-up", "2-up", or "4-up" on a page.  To allow
Xconvenient printing of nroff'ed documents, the fixed pitch Courier
Xfont is used as a default. 
X
XPsf is a general purpose filter for
Xmost text and programme listings.  By using various escape 
Xsequences (described below), any portion of the text may be printed in
Xdifferent fonts and at different point sizes.
X
XAdditional filters, such as "pnf" and "pmf" can be used to automatically
Xgenerate escape sequences to control font and sizes for
Xprinted documents.
X
XIf an nroff'ed
Xdocument is filtered with programme "pnf", then the document will
Xprint properly with bold-face and underlining.  
X
XPnf is a filter that converts "backspaced text" into underlined or
Xbold text.  Nroff'ed documents should be filtered by pnf before
Xthey are passed to psf.
X
XFor example, you could print the "vi" man page "2-up" with:
X
X.nf
X      man vi | pnf -x | psf -2 | lp
Xor
X      man vi | pnf -ix | psf -2 | lp
X.fi
X
XSource listings or other text would use psf only:
X.nf
X
X      psf main.c subs.c | lp
X.fi
X
XPmf is a very simple filter for mail documents.
XMail message may be printed with:
X
X.nf
X      pmf <mail.file | psf -2 | lp
X.fi
X
X.RS -5
XOPTIONS
X.RE
X.TP .7i
X.B \-1\|2\|4
XSpecify the number of logical pages that are to be printed
Xon a physical page.  By default, psf will print one logical
Xpage per physical page.  If two logical pages are specified
Xwith "-2", then two pages are printed in "landscape" format:
X
X.nf
X      +-----------+-----------+
X      |   pg 1    |   pg 2    |
X      |           |           |
X      |           |           |
X      +-----------+-----------+
X.fi
X
XIf four logical pages are specified with "-4", then the pages
Xare printed in "portrait format:
X
X.nf
X      +-----------+-----------+
X      |   pg 1    |   pg 3    |
X      |           |           |
X      |           |           |
X      +-----------+-----------+
X      |   pg 2    |   pg 4    |
X      |           |           |
X      |           |           |
X      +-----------+-----------+
X.fi
X
X
X.TP .7i
X.B -l n
XSets the number of lines per page.  The default is 60 lines.
XIf more than 60 lines per page are specified, the point size is
Xautomatically reduced to accomodate the line count. (Xenix man
Xpages use a page length of 60.)
X
XIf you are printing text that is wider than the nominal 75-80 columns
Xin width, then specify more than 60 lines per page.  Then number
Xof print columns available will increase proportionately with the
Xnumber of lines.
X
X.TP .7i
X.B \-f n
XAny of the standard postscript 
Xfonts may be selected in lieu
Xof the default Courier font.  These are selected from the following
Xtable of fonts:
X.nf
X
X         0 Courier
X         1 Helvetica
X         2 Times-Roman
X         3 AvantGarde-Book
X         4 Bookman-Light
X         5 NewCenturySchlbk-Roman
X         6 Palatino-Roman
X         7 ZapfChancery-MediumItalic
X         8 Helvetica-Narrow
X.fi
X
XSince Courier is the only fixed-pitch font, it is usually used for
Xprinting of man pages or programme listings.  The other fonts are
Xproportionally spaced.
X
XThe selected font becomes the new "default font".
X
X.TP .7i
X.B \-w
XThe page is printed in landscape (wide, horizontal format).
XThis is the default for 2-up printing.  If 1-up printing is
Xdesired in landscape mode, then the -w switch must be specified.
X
X.TP .7i
X.B \-h
XThe file name, page number and current date will be printed at
Xthe top of each page.  The point size is automatically scaled to
Xpermit the specified number of text lines to be printed to account
Xfor the additional two lines consumed by the title line.
X
X.TP .7i
X.B \-H text
XPlace a header (like -h) however use "text" rather than the filename.
X
X.TP .7i
X.B \-t n
XSets the width of the tab stops.  By default this is set to 8.
XIf the first line of a text file contains the string "ta=", then
Xthe tab stop width is automatically determined from this string.
XFor example, if the first text line contains "/* ta=4 */" then
Xthe tab width is automatically set to 4.  This feature is useful
Xif programme source files are tabbed at 4.
X
X.TP .7i
X.B \-p n
XSets the nominal point size to "n" points.  This applies only
Xto "1-up" printing.  If "2-up" or "4-up" or "1-up, landscape" 
Xprinting is desired, the nominal point size is automatically scaled.
X
XThe selected point size becomes the new "default point size".
X
X.RS -5
XPSF NOTES
X.RE
XPsf filters text in a postscript-compatible way. If the text contains
Xescape sequences (possibly generated by pnf, another pre-filter or a
Xtext editor), the escape sequences are analyzed to perform limited font
Xselection. The permitted escape sequences have the following format: .nf
X
X        <escape><command>
X.fi
X
XThe following sequences are recognized:
X
X.nf
X         \\033B     begin bold (in current font family)
X         \\033b     end bold
X         \\033I     begin italics
X         \\033i     end italics
X         \\033U     begin underline
X         \\033u     end underline.
X         \\033Fn    begin font 'n' (0..7)
X         \\033f     revert to default font
X         \\033Pnn   begin point size 'nn' (2 digits)
X         \\033p     revert to default point size
X.fi
X
XNote that point sizes with \\033Pnn must be two digits such as \\033P07 or \\033P14.
X
XSequences may be nested: bold, italic, underlined would be 
Xgenerated with:
X.nf
X
X     \\033B\\033I\\033Ubold, italic and underlined\\033u\\033i\\033b
X.fi
X
XThe underline sequence should be 'innermost' to ensure that the
Xunderline follows the exact font width.
X
XAny unrecognized escape sequences are ignored.
X
XAny filter that can construct the above escape sequences may be
Xused to provide input to psf.  The provided "pnf" and "pmf"
Xare only two simple examples.
X
X.RS -5
XPNF NOTES
X.RE
XPnf is a filter that converts "backspaced text" generated by nroff
Xinto escape sequences that can be used by psf to generate
Xunderlined or bold text. The conversion results 
Xin the following generated sequences:
X.nf
X
X        \\033B..text..\\033b   for bold
X        \\033U..text..\\033u   for underline
Xor
X        \\033I..text..\\033i   for italics
X
X(italics instead of underline selected with -i option)
X
X.fi
XSince the text from nroff does not have a decent way of identifying
Xitalics, you may use the -i option to generate the "italic" instead of
X"underline" escape sequence whenever an underline is detected in the
Xinput text.
X
XThe logic cannot handle bold-underlined (nor italic-underlined).
X
XXenix man-pages sometime generate fewer than the expected 60
Xlines per page.  The "-x" option ensures that extra
Xblank lines are inserted to fill to 60 lines.  This may cause
Xan unnecessary blank page at the end.
X
X.RS -5
XPMF NOTES
X.RE
XPmf is a very simple mail printing filter.  It italicizes the 'Subject:'
Xand attempts to place peoples names in boldface. 
XIt can be used to print
Xentire mail boxes, however all headers except 'Received:' 
Xand 'Message-ID:' are printed.
X
XIf pmf and psf are used with ELM, the user's elmrc file should be modified
Xto specify the following "print" line (or reasonable approximation):
X
X.nf
X      print = /usr/bin/pmf < %s | /usr/bin/psf -2 | /usr/bin/lp
X.fi
X
X.RS -5
XAUTHOR
X.RE
X.nf
XTony Field.         tony@ajfcal
X.fi
X
END_OF_FILE
if test 8529 -ne `wc -c <'psf.1'`; then
    echo shar: \"'psf.1'\" unpacked with wrong size!
fi
# end of 'psf.1'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(2240 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#	Make the psf postscript filter system
X#
X#	usage:	make all	-> to compile all source
X#
X#		make install	-> copy binaries to target directory (UNIX)
X#
X#		make xenix	-> copy binaries to target directory
X#				   and invoke "mkdev lp"   (XENIX)
X#
X# - - - - Begin configuration - - - - -
X#
X# Underline parametrics within FontInfo is not guaranteed.
X# If you have implemented non-standard fonts without underline information
X# in FontInfo, the provide the -DFONTINFO manifest.
X
X# CFLAGS = -O  -DFONTINFO
X
XCFLAGS = -O
X
X
X# Location of binaries
X
XBINDIR=/usr/bin
X
X
X# Psf default options for use with Xenix lp system
X#	The following are suggested:
X#
X#	PSFOPT =                      uses default of 60 line per page
X#                                     in portrait mode
X# or:
X#       PSFOPT = -2 -l80              Prints pages 2-up in landscape
X#                                     mode with 80 columns per logical page.
X#                                     (A nice way to save paper)
X
XPSFOPT =
X
X
X# - - - - - end configuration - - - - - - - -
X
X
XSOURCES  = psf.c pnf.c pmf.c psbanner.c psdetect.c
XOBJECTS  = psf.o pnf.o pmf.o psbanner.o psdetect.o
XBINARIES = psf   pnf   pmf   psbanner   psdetect
X
Xall:	$(BINARIES)
X
Xshar:
X	rm -f psf.shar
X	shar Readme Readme.Xenix psf.1 Makefile $(SOURCES) postscript.LP testfile > psf.shar
X
Xtwoshar:
X	rm -f psf1.shar
X	rm -f psf2.shar
X	shar -n1 -e2 Readme Readme.Xenix psf.1 Makefile postscript.LP testfile psbanner.c psdetect.c >psf1.shar
X	shar -n2 -e2 psf.c pmf.c pnf.c > psf2.shar
X
X# Unix install
X
Xinstall:
X	cp psf $(BINDIR)
X	cp pnf $(BINDIR)
X	cp pmf $(BINDIR)
X
X# Install Xenix: copy all executables to the binary directory
X#		 edit the BINARY and OPTIONS into postscript.psf model
X# 		 copy the "postscript model" shell script to the
X# 			  lp spool directory.
X#		 call "mkdev lp" to create a postscript printer.
X
Xxenix:	$(BINARIES)
X	cp $(BINARIES) $(BINDIR)
X	rm -f postscript.psf
X	sed 's@BINARY@$(BINDIR)@g' postscript.LP | sed 's@OPTIONS@$(PSFOPT)@g' > postscript.psf
X	chmod +rw postscript.psf
X	cp postscript.psf /usr/spool/lp/model/postscript.psf
X	chown lp  /usr/spool/lp/model/postscript.psf
X	chgrp bin /usr/spool/lp/model/postscript.psf
X	mkdev lp
X
Xclean:
X	rm -f *.o core postscript.psf *.B
X	rm -f $(BINARIES)
END_OF_FILE
if test 2240 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'psf.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'psf.c'\"
else
echo shar: Extracting \"'psf.c'\" \(21778 characters\)
sed "s/^X//" >'psf.c' <<'END_OF_FILE'
X/* ta=4 */
X/****************************************************************************
X*					p s f . c		v1.1									*
X*																			*
X*	Postscript filter														*
X*																			*
X*	Print text files to postscript printer.  Allow 1-up, 2-up and 4-up		*
X*	pages.  Provisions are made to allow font selection by imbedded			*
X*	escape sequences - to allow printing of man pages.  The escape sequence	*
X*	generated by "pnf" and "pmf" are compatible with psf.					*
X*																			*
X*	Tony Field.       tony@ajfcal  (or: calgary!ajfcal!tony@ai.toronto.edu)	*
X*																			*
X*	The orginal underline algorithm (/showunderline) was provided by		*
X*	Anders Thulin        mcvax!helios!ath@uunet.uucp						*
X****************************************************************************/
X
X#include <stdio.h>
X#include <time.h>
X
X/*	set up the mechanism for underline display */
X
X#ifndef FONTINFO
X#define SHOWU(fp,ps)	fprintf (fp, ") %d showuline\n", ps)
X#else
X#define SHOWU(fp,ps)	fputs (") showunderline\n", fp)
X#endif
X
X#define LONG_STR	1000	/* long buffer line							*/
X#define ESCAPE		0x1b
X
X/* Paper physical dimensions. */
X
X#define	P_HEIGHT	792			/* 72dpi x 11 inch							*/
X#define P_WIDTH		612			/* 72dpi x 8.5 inch							*/
X#define NOMINAL		60			/* number of "expected" lines on page		*/
X
X#define NORMAL		0x00		/* bitset for  print_attributes				*/
X#define ITALICS		0x01
X#define BOLD		0x02
X#define UNDERLINE	0x04		/* must be 0x04.  underline is not a font	*/
X
X/* Current information about page.  Where are we, etc.  
X*/
X
Xint		x,y;					/* current x,y coordinate					*/
X
Xint		book = 0;				/* book format: double sided				*/
Xint		lines_on_page = 60;
Xint		page_number;			/* current page number for this file		*/
Xint		physical_page = -1;		/* postscript physical page for multi-up	*/
Xfloat	scale_x, scale_y;		/* scale factors for 2-up, 4-up printing	*/
Xint		do_scale = 0;			/* 1 = must scale image,  0 = dont scale	*/
Xint		landscape = 0;			/* 1 = landscape, 0 = portrait layout		*/
Xint		header    = 0;			/* 1 = print header at top of each page		*/
Xint		cross	  = 0;			/* 1 = print cross on 4-up pages			*/
Xint		line_number	= 0;		/* current logical line number on page		*/
Xint		tab_size   = 8;			/* space translation for tabs.				*/
Xint		print_attribute = 0;	/* such as BOLD, UNDERLINE, ITALICS			*/
Xint		font_number = 0;		/* one of the valid fonts in the printer	*/
Xint		default_font_number;	/* set with -f option, or 0					*/
Xint		point_size	= 12;		/* can be changed with the -p option		*/
Xint		default_point_size;		/* assumes value due to -p option			*/
Xint		y_coord		= 0;		/* current logical page y-coordinate, points*/
Xint		x_coord		= 0;		/* current logical page x-coordinate, points*/
Xint		x_offset	= 0;
Xint		y_offset	= 0;
Xchar	header_text[100];
X
X/*	indent space "forbidden zone" */
X
Xint top_marg  = 36;			/* 1/2 inch = 36/72		*/
Xint bot_marg  = 36;
Xint left_marg = 36;
Xint	default_left_marg;
Xint logical_top;			/* where does printing start at top of page, points */
X
Xchar	fname[100];
Xchar	now[50];			/* time of day for page headers 				*/
X
X
X/*	to select a font, use 4 * font_number + print_attribute as index.
X	e.g.   If font_number = 1    for Helvetica,
X	  and print_attribute = 0x02 for BOLD
X
X	then the actual font selected is    fonts[4 * 1 + 2]
X										= Helvetica-Bold
X
X	The various print attributes can be OR'ed together:
X			fonts [4 * 1 + ITALICS | BOLD] 
X*/
X	  
X#define NFONTS  	36		/* 	4 variations * 9 font families  */
Xchar *fonts[NFONTS] =
X{
X	"Courier",		            "Courier-Oblique",		    "Courier-Bold", 	        "Courier-BoldOblique",
X	"Helvetica", 	            "Helvetica-Oblique", 	    "Helvetica-Bold",	        "Helvetica-BoldOblique",
X	"Times-Roman", 	            "Times-Italic", 		    "Times-Bold", 		        "Times-BoldItalic",
X	"AvantGarde-Book",          "AvantGarde-BookOblique",   "AvantGarde-Demi",          "AvantGarde-DemiOblique",
X	"Bookman-Light",            "Bookman-LightItalic",      "Bookman-Demi",             "Bookman-DemiItalic",
X	"NewCenturySchlbk-Roman",   "NewCenturySchlbk-Italic",  "NewCenturySchlbk-Bold",    "NewCenturySchlbk-BoldItalic",
X	"Palatino-Roman",           "Palatino-Italic",          "Palatino-Bold",            "Palatino-BoldItalic",
X	"ZapfChancery-MediumItalic","ZapfChancery-MediumItalic","ZapfChancery-MediumItalic","ZapfChancery-MediumItalic",
X	"Helvetica-Narrow",         "Helvetica-Narrow-Oblique", "Helvetica-Narrow-Bold",    "Helvetica-Narrow-BoldOblique"
X} ;
X
Xint	max_frame	= 1;		/* max number of frames in use */
Xint	frame		= -1;		/* current frame in use */
X
X/*	incremental values to be added to the current "0,0" for translation
X	to each display frame.  The printer starts at "start (0,0)"
X	then moves to (0, P_HEIGHT), then (0,-P_HEIGHT), etc.
X				+---+---+
X				| 0 | 2 |
X				+---+---+
X				| 1 | 3 |
X	start (0,0)>+---+---+
X
X*/
Xint	up_4x[4] = {0,			0,			P_WIDTH,	0			};
Xint	up_4y[4] = { P_HEIGHT,	-P_HEIGHT,	P_HEIGHT,	-P_HEIGHT	};
X
Xint	up_2x[2] = {0,			P_WIDTH };
Xint up_2y[2] = {0,			0 		};
X
Xint up_1x    = 0;
Xint	up_1y	 = 0;
X
Xint		home_x = 0;			/* logical (0,0) coordinate position in points	*/
Xint		home_y = 0;
X
X
Xdouble	correction;			/* scale correction factor for lines on a page	*/
Xint		do_correction;
X
XFILE	*input_fp, *output_fp;
X
X/*	input line and input line pointer */
Xunsigned char	*c;
Xunsigned char	line[LONG_STR + 1];
X
Xmain (argc, argv)
Xint		argc;
Xchar	*argv[];
X{	int		c, i;
X	extern char *optarg;
X	extern int	optind;
X
X	*header_text = '\0';
X	correction = 1.0;
X	scale_x = 1.0;
X	scale_y = 1.0;
X	while ((c = getopt(argc, argv, "124xhbwH:l:f:t:p:-")) != -1)
X	{	switch (c)
X		{
X		case '1':
X			max_frame = 1;
X			scale_x = 1.0;
X			scale_y = 1.0;
X			do_scale = 0;
X			break;
X			
X		case '2':
X			landscape = 1;
X			max_frame = 2;
X			scale_x = 0.647;
X			scale_y = 0.772;
X			do_scale = 1;
X			home_x = P_HEIGHT / 2;
X			home_y = 0;
X			break;
X		
X		case '4':
X			max_frame = 4;
X			scale_x = 0.5;
X			scale_y = 0.5;
X			do_scale = 1;
X			home_x = P_WIDTH;
X			home_y = 0;
X			break;
X		
X		case 'h':
X			header = 1;
X			break;
X			
X		case 'H':
X			header = 2;
X			strcpy (header_text, optarg);
X			break;
X			
X		case 'w':
X			landscape = 1;
X			do_scale = 1;
X			break;
X			
X		case 'l':
X			lines_on_page = atoi (optarg);
X			break;
X			
X		case 'p':
X			point_size = atoi (optarg);
X			break;
X			
X		case 'x':
X			cross = 1;
X			break;
X
X		case 'f':
X			font_number = atoi (optarg);
X			if (font_number > (NFONTS / 4))
X				font_number = (NFONTS / 4) - 1;
X			break;
X
X		case 't':
X			tab_size = atoi (optarg);
X			break;
X		
X		default:	usage ();
X			break;
X		}
X	}
X
X	if (max_frame == 4  &&  landscape)
X	{
X		scale_x = 0.500;
X		scale_y = 0.380;
X	}
X	else if (max_frame ==  1 &&  landscape)
X	{
X		scale_x = 0.647;
X		scale_y = 0.772;
X	}
X
X	/*	all margins should be scaled.  However, if we do that, then the
X		printing of man-pages 4-up will not work as desired.
X	*/
X	if (do_scale)
X	{
X/*
X		top_marg  = (float) top_marg / scale_y;
X		bot_marg  = (float) bot_marg / scale_y;
X*/
X		left_marg = (float) left_marg / scale_x;
X
X	}
X
X	if (font_number * 4 > NFONTS)
X	{	fprintf (stderr,"Font number invalid....\n");
X		usage ();
X	}
X	
X	if (header)
X		lines_on_page += 2;
X
X	/*	If anything adjusts the number of lines on a page, then scale
X		the page size rather than scale the point size.  Then point
X		size can be an integer with little problem
X	*/
X	if (lines_on_page > NOMINAL)
X	{	correction = (((double) NOMINAL) / ((double) lines_on_page));
X		scale_y *= correction;
X		scale_x *= correction;
X		top_marg /= correction;
X		do_correction = 1;
X	}
X	else
X		do_correction = 0;
X
X	output_fp = stdout;
X	prologue (output_fp);
X
X	logical_top = P_HEIGHT - top_marg;
X	page_number = -1;
X	line_number = 32767;
X	default_point_size = point_size;
X	default_font_number = font_number;
X	default_left_marg = left_marg;
X
X	*fname = 0;	
X	get_time (now);		
X	if (optind >=  argc)
X	{	if (header == 1)
X			header = 0;
X		start_file ();
X		input_fp = stdin;
X		process_file ();
X		terminate_file ();
X	}
X	else for ( ;  optind < argc;  optind++)
X	{	i = strlen (argv[optind]);
X		if (i > 38)
X			i -= 38;
X		else
X			i = 0;
X		strcpy (fname, argv[optind] + i);
X		if ((input_fp = fopen (argv[optind], "r")) == NULL)
X		{	fprintf (stderr, "Unknown file: %s\n", argv[optind]);
X			continue;
X		}
X		start_file ();
X		process_file ();
X		terminate_file ();
X		fclose (input_fp);
X	}
X	terminate_printer ();
X	if (book)
X		output_book ();
X
X	exit (0);
X}
X
X/****************************************************************************
X*	prologue ()																*
X*	generate the require postscript-conformant prologue						*
X****************************************************************************/
X
Xprologue ()
X{
X	fprintf (output_fp, "%%!PS-Adobe-\n");
X
X#ifndef FONTINFO
X	/* 	The red book (pg 93) indicates that the FontInfo dictionary
X		"MAY" contain the /UnderlinePosition and /UnderlineThickness
X		This is the case for all Adobe fonts.  External non-Adobe fonts may
X		not have these values.
X		
X		usage:     	(text to underline) <pointsize> showuline
X		where:		<pointsize> is current text point size.
X
X		eg:			(text to underline) 12 showuline
X	*/
X	fprintf (output_fp, "%s%s%s%s%s%s%s%s%s%s",
X			"/showuline {\n",
X			"	/CurPointSize exch def\n",
X			"	dup stringwidth pop\n",
X			"	gsave\n",
X			"	currentfont /FontInfo get dup\n",
X			"	/UnderlinePosition get CurPointSize mul 1000 div 0 exch rmoveto exch 0 rlineto\n",
X			"	/UnderlineThickness get CurPointSize mul 1000 div setlinewidth stroke\n",
X			"	grestore\n",
X			"	show\n",
X			"} def\n");
X
X#else
X	/*	showunderline: without FontInfo:  underline is 2 points below base 
X	    compliments of Anders Thulin
X		 			   mcvax!helios!ath@uunet.uucp (Anders Thulin)
X
X		usage:		(text to underline) showunderline
X	*/
X	fprintf (output_fp, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
X			"/showunderline {\n",
X			"  /str exch def\n",
X			"  /dy     0 def\n",
X			"  currentpoint\n",
X			"    str show\n",
X			"  moveto\n",
X			"  /dy -2 def\n",
X			"  currentpoint\n",
X			"  dy add\n",
X			"  moveto\n",
X			"  str stringwidth\n",
X			"  rlineto \n",
X			"  currentpoint\n",
X			"    stroke\n",
X			"  moveto\n",
X			"  currentpoint\n",
X			"  dy sub\n",
X			"  moveto\n",
X			"} def\n");
X#endif
X
X	fprintf (output_fp, "%%%%EndProlog\n");
X}
X
X/****************************************************************************
X*	new_page ()																*
X*	Generate a new page.  Send out required rotation,scale information		*
X*	This is the "prologue" to a page (not the end of the previous)			*
X****************************************************************************/
X
Xnew_page ()
X{
X}
X
X
X/****************************************************************************
X*	showpage ()																*
X*	Generate a real "showpage" if we have really finished generating a		*
X*	physical page.  If we are processing 2 or 4 up, then generate 			*
X*	coordinate "translates" if we really haven't finished all possible		*
X*	page frames of the page.												*
X****************************************************************************/
X
Xshowpage (end_of_file)
Xint end_of_file;
X{
X	line_number = 0;
X
X	if (++frame >= max_frame  ||  end_of_file) 
X	{
X		fprintf (output_fp, "showpage pg restore\n");
X		frame = 0;
X	}
X	if (!end_of_file)
X		set_frame ();
X}
X
X/****************************************************************************
X*	set_frame ()															*
X*	Select the next logical frame in two-up or four-up mode.  If it is		*
X*	the first frame of a physical page, the generate the %%Page				*
X****************************************************************************/
X
Xset_frame ()
X{
X	if (frame == 0)
X	{	left_marg = default_left_marg;
X		fprintf (output_fp, "%%%%Page: ? %d\n", ++physical_page);
X		fprintf (output_fp, "/pg save def\n");
X
X		if (landscape)
X			fprintf (output_fp, "90 rotate 0 %d translate\n", -P_WIDTH);
X
X		if (do_scale  ||  do_correction)
X			fprintf (output_fp, "%.3f %.3f scale\n", scale_x, scale_y);
X
X		findfont();
X	}
X	set_y_coord ();
X	
X	switch (max_frame)
X	{
X	case 2:
X		fprintf (output_fp, "%d %d translate\n", (int) (up_2x[frame] / correction), (int) (up_2y[frame] / correction));
X		break;
X
X	case 4:
X		if (frame == 2)			/* better for 4-up layout */
X			left_marg /= 2;
X		fprintf (output_fp, "%d %d translate\n", (int) (up_4x[frame] / correction), (int) (up_4y[frame] / correction));
X		break;
X
X	default:
X		break;
X	}
X
X	if (frame == 0  &&  cross)
X		draw_cross();
X
X}
X
X
X/****************************************************************************
X*	set_y_coord																*
X*	position next line to the top of a logical page.						*
X*****************************************************************************/
X
Xset_y_coord ()
X{
X	y_coord = P_HEIGHT;
X	if (do_correction)
X	{	y_coord = ((double) y_coord) / correction;
X		x_coord = ((double) x_coord) / correction;
X	}
X}
X/****************************************************************************
X*	put_top																	*
X*	put a header line at the top of the page								*
X*****************************************************************************/
X
Xput_top ()
X{
X	int	save_attr, save_point;
X	
X	save_attr = print_attribute;
X	save_point = point_size;
X	print_attribute = BOLD;
X	point_size = 12;
X	
X	findfont();
X	moveto (x_coord + left_marg, y_coord - top_marg, 1);
X	if (header == 1)
X		fprintf (output_fp, "(%-40s %3d     %s)show\n", fname, page_number + 1, now);
X	else
X		fprintf (output_fp, "(%-40s %3d     %s)show\n", header_text, page_number + 1, now);
X	y_coord -= point_size * 2;
X	x_coord = 0;
X	print_attribute = save_attr;
X	point_size = save_point;
X	findfont();
X}
X
X/****************************************************************************
X*	process_file()															*
X*	Read the file, look for escape sequences, put text in postscript form	*
X****************************************************************************/
X
Xprocess_file ()
X{
X	int		char_type, char_count, i, set_page, esc_type;
X	char	*strchr ();
X	int		previous_attribute;
X	int		lcount = 0;
X	
X	set_page = 0;
X	while (fgets (line, LONG_STR, input_fp) != NULL)
X	{
X		if (lcount++ == 0)
X		{	if ((i = tscan (line, "ta=")) >= 0)
X			{	tab_size = atoi (line + i + 3);
X			}
X		}
X		if ((c = strchr (line, '\f')) != NULL)
X		{
X			if (c == line)
X			{	line_number += 1000;
X				c = line + 1;
X			}
X			else
X			{	*c = 0;
X				set_page = 1;
X				c = line;
X			}
X		}
X		else
X			c = line;
X
X		if (line_number++ >= lines_on_page)
X		{	page_number++;
X			showpage (0);
X			line_number = 1;
X			if (header)
X			{
X				put_top();
X				line_number += 2;
X			}
X		}
X		char_type = char_count = 0;
X
X		if (*c == '\n')
X			moveto (x_coord + left_marg, y_coord - top_marg, 0);
X		else
X			moveto (x_coord + left_marg, y_coord - top_marg, 1);
X
X		while (*c  && *c != '\n')
X		{
X			if (char_type == 0)
X				fputc ('(', output_fp);
X				
X			switch ((int) *c)
X			{
X			case ESCAPE:
X				previous_attribute = print_attribute;
X				esc_type = *(++c);
X				if (escape_sequence (esc_type) == 0)
X				{
X					switch (esc_type)
X					{
X					case 'u':
X						SHOWU (output_fp, point_size);
X						break;
X
X					default:
X						if (char_type  &&  (previous_attribute & UNDERLINE))
X							SHOWU (output_fp, point_size);
X						else
X							fputs (")show\n", output_fp);
X						findfont (output_fp);
X					}
X					char_type = 0;
X				}
X				break;
X				
X			default:
X				if (*c == '\t')
X				{
X					fputc (' ', output_fp);
X					while (++char_count % tab_size)
X						fputc (' ', output_fp);
X				}
X				else
X				{	if (strchr ("\r\b\\()", *c) != NULL)
X						fputc ('\\', output_fp);
X					fputc (*c, output_fp);
X					char_count++;
X				}
X				char_type = 1;
X				break;
X			}
X			c++;
X		}
X		if (char_type)
X		{	if (print_attribute & UNDERLINE)
X				SHOWU (output_fp, point_size);
X			else
X				fputs (")show\n", output_fp);
X		}
X
X		y_coord -= point_size;
X		x_coord = 0;
X		if (set_page)
X		{	line_number += 1000;
X			set_page = 0;
X		}
X	}
X}
X
X/****************************************************************************
X*	escape_sequence ()														*
X*	If an escape sequence (esc,char) is found, mark which type of font		*
X****************************************************************************/
X
Xint escape_sequence (which)
Xint	which;
X{	unsigned char	s[10];
X
X	switch (which)
X	{
X	case 'I':
X		print_attribute |= ITALICS;
X		break;
X
X	case 'i':
X		print_attribute &= ~ITALICS;
X		break;
X
X	case 'B':
X		print_attribute |= BOLD;
X		break;
X
X	case 'b':
X		print_attribute &= ~BOLD;
X		break;
X
X	case 'U':
X		print_attribute |= UNDERLINE;
X		break;
X
X	case 'u':
X		print_attribute &= ~UNDERLINE;
X		break;
X	
X	case 'F':
X		s[0] = *(++c);
X		s[1] = '\0';
X		font_number = atoi (s);		
X		if (font_number > (NFONTS / 4))
X			font_number = (NFONTS / 4) - 1;
X		break;
X	
X	case 'f':
X		font_number = default_font_number;
X		break;
X		
X	case 'P':
X		s[0] = *(++c);
X		s[1] = *(++c);
X		s[2] = '\0';
X		point_size = atoi (s);
X		break;
X
X	case 'p':
X		point_size = default_point_size;
X		break;
X	
X	default:
X		return (-1);
X		;
X	}
X	return (0);
X}
X
X/****************************************************************************
X*	moveto ()																*
X*	Generate a postscript     x y moveto    statememt						*
X****************************************************************************/
X
Xmoveto (x, y, do_move)
Xint	x;
Xint	y;
Xint do_move;
X{
X
X	if (line_number > lines_on_page  ||  y  < bot_marg)
X	{	showpage (0);
X		if (header)
X		{
X			put_top();
X			line_number += 2;
X		}
X		y = y_coord - top_marg;
X		x = x_coord + left_marg;
X	}
X	if (do_move)
X		fprintf (output_fp, "%d %d moveto\n", x, y);
X}
X
X/****************************************************************************
X*	findfont ()																*
X*	generate a findfont statement											*
X****************************************************************************/
X
Xfindfont ()
X{	int	this;
X
X	/*	remove reference to UNDERLINE.  Underline is not a font.	*/
X	
X	this = (font_number * 4) + (print_attribute & 0x03);
X	fprintf (output_fp, "/%s findfont %d scalefont setfont\n", fonts[this], point_size);
X}
X
X/****************************************************************************
X*	start_file ()															*
X*	Generate things that are appropriate for beginning of file processing	*
X****************************************************************************/
X
Xstart_file ()
X{
X	line_number = 0;
X	print_attribute = 0;
X	page_number = 0;
X	frame = -1;
X	showpage (0);
X	if (header)
X	{
X		put_top();
X		line_number += 2;
X	}
X}
X
X/****************************************************************************
X*	terminate_file ()														*
X*	Generate things that are appropriate for end of file processing			*
X****************************************************************************/
X
Xterminate_file ()
X{
X	showpage (1);
X}
X
X
X/****************************************************************************
X*	terminate_printer ()													*
X*	Generate things that are appropriate wrap-up after all files printed	*
X****************************************************************************/
X
Xterminate_printer ()
X{
X	fprintf (output_fp, "%%%%Trailer\n");
X	fprintf (output_fp, "%c", 0x04);		/* CTL/D = end job */
X}
X
X/****************************************************************************
X*	draw_cross ()															*
X*	Draw horizontal and vertical separation lines between pages 4-up		*
X****************************************************************************/
X
Xdraw_cross ()
X{	int	 p_w, p_h;
X
X	
X	if (max_frame == 4)
X	{
X		p_w = P_WIDTH  / correction;
X		p_h = P_HEIGHT / correction;
X		fprintf (output_fp,"%d %d moveto\n", p_w, p_h);
X		fprintf (output_fp,"%d %d lineto\n", p_w, -p_h);
X		fprintf (output_fp,"%d %d moveto\n", 0, 0);
X		fprintf (output_fp,"%d %d lineto\n", p_w * 2, 0);
X		fprintf (output_fp,"%s\n", "stroke");
X	}
X}
X
X/****************************************************************************
X*	output_book ()															*
X*	Send file "double sided print" mode.  Used to make a "book".			*
X*	Will pause the printer to ask for stack re-feed:  use /dev/lpt			*
X****************************************************************************/
X
Xoutput_book ()
X{
X	/* some day real soon now... */
X}
X
X
Xusage ()
X{	int		i;
X
X	fprintf (stderr,"%s\n%s\n\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n",
X	"Usage:    psf [ -l n ] [ -1|2|4 ] [ -f n ] [ -h ] [ -t n ]",
X	"              [ -H text ] [ -p n ] [ -w ] [ -x ] file file ..",
X	"   where        -l n      lines per page (default=60)",
X	"                -1|2|4    print 1,2 or 4 up on a page (default=1)",
X	"                -f n      font number to use (default=0=Courier)",
X	"                -h        put file name as header on each page",
X	"                -H text   put text as header on each page",
X	"                -t n      set tabs to n (default=8)",
X	"                -p n      set point size to n",
X	"                -w        set landscape (wide) format",
X	"                -x        draw cross with 4-up page",
X	"                file..    name of files to be printed (or stdin)",
X	"   output: stdout"),
X
X	fprintf (stderr,"Fonts selection with -f n\n");
X	for (i = 0;  i < NFONTS;  i+= 8)
X		if (i + 4 >= NFONTS)
X		fprintf (stderr, "%5d %-20s\n", i/4, fonts[i]);
X	else
X		fprintf (stderr, "%5d %-20s  %d %s\n", i/4, fonts[i], i/4+1, fonts[i+4]);
X	exit (0);
X}
X
X/************************************************
X*		tscan (s,t)								*
X*		char	s[],t[];						*
X*												*
X*	Index function as defined in K&R			*
X*	Look for string t in s						*
X*												*
X*	return -1 if t does not exits in s			*
X*	else return array position of first			*
X*	character match								*
X************************************************/
X
X
Xtscan (s, t)
Xchar 	s[], t[];
X{
X	int	i, j, k;
X	for (i = 0;  s[i] != '\0';  i++)
X	{	for (j = i, k=0;  t[k] != '\0'  &&  s[j] == t[k];  j++, k++)
X			;
X		if (t[k] == '\0')
X			return (i);
X	}
X	return (-1);
X}
X
Xget_time (t)
Xchar	*t;
X{
X	long	n_time, time ();
X	char	*x_time, *cc, *strchr();
X	
X	n_time = time (0);			/* get time */
X	x_time = ctime (&n_time);	/* convert ascii */
X	if ((cc = strchr (x_time, '\n')) != NULL)
X		*cc = '\0';
X	strcpy (t, x_time);
X}
X
END_OF_FILE
if test 21778 -ne `wc -c <'psf.c'`; then
    echo shar: \"'psf.c'\" unpacked with wrong size!
fi
# end of 'psf.c'
fi
if test -f 'pnf.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pnf.c'\"
else
echo shar: Extracting \"'pnf.c'\" \(4166 characters\)
sed "s/^X//" >'pnf.c' <<'END_OF_FILE'
X/* ta=4 */
X/****************************************************************************
X*							p n f . c      v1.1								*
X*																			*
X*	postscript filter for nroff'ed text										*
X*																			*
X*	Translate backspaces in n/troff documents to either BOLD or UNDERLINE	*
X*	for psf usage															*
X*																			*
X*	Tony Field.       tony@ajfcal (or: calgary!ajfcal!tony@ai.toronto.edu)	*
X****************************************************************************/
X
X/*	For each line in of input text, scan for backspaces.  Determine if
X	the operation is an underline (i.e. the preceeding character is
X	the "_") or if it is a bolding (the character after the underscore
X	is the same as the preceeding.
X	
X	Generate the sequence \033B..text..\033b   for bold
X						  \033U..text..\033u   for underline
X						  \033I..text..\033i   for italics
X
X	Since the text from nroff does not have a decent way of identifying
X	italics, you may make the decision to generate the "italic" or 
X	"underline" escape sequence  whenever an underline is detected in
X	the output.  Italic fonts look nicer than the underlines 2-up.
X
X	The logic cannot handle bold-underlined (nor italic-underlined).
X	This could be done with a bit of extra logic to manipulate bits
X	in the "how" vector.
X
X	Handle xenix 59 line man page error...  force to 60.
X*/
X
X#include <stdio.h>
X
X#define BEGIN_BOLD			"\033B"
X#define END_BOLD			"\033b"
X
X#define BEGIN_UNDERLINE		"\033U"
X#define END_UNDERLINE		"\033u"
X
X#define BEGIN_ITALICS		"\033I"
X#define END_ITALICS			"\033i"
X
X
Xmain (argc, argv)
Xint		argc;
Xchar	*argv[];
X{
X	int		c, n, i;
X	int		how[401];
X	char	line[401];
X	int		ii, lcount;
X	int		xenix = 0;
X	char	*underline_on, *underline_off;
X	extern char *optarg;
X	extern int	optind;
X	
X	underline_on  = BEGIN_UNDERLINE;
X	underline_off = END_UNDERLINE;
X	
X	while ((c = getopt(argc, argv, "ix-")) != -1)
X	{	switch (c)
X		{
X		case 'i':
X			underline_on  = BEGIN_ITALICS;
X			underline_off = END_ITALICS;
X			break;
X		
X		case 'x':
X			xenix = 1;
X			break;
X			
X		default:
X			usage ();
X		}
X	}
X		
X	n = lcount = 0;
X	clear (line, how, 400);
X	while (( c = getchar()) != EOF)
X	{
X		if (c == '\033')			/* ignore existing sequences */
X			getchar();
X			
X		else if (c == '\b')
X			n--;
X		else if (c == '\n')
X		{	how[n] = 0;
X			line[n] = 0;
X			if (xenix)					/* adjust for xenix 59 line page */
X			{
X				lcount++;
X				if ((ii = tscan (line, "Page ")) > 0)
X				{
X					/*	Xenix can generate less than 60 lines per page
X						This almost guarantees an extra blank page.
X					*/
X					if (tscan (line, "(printed ") > ii)
X					{	while (lcount++ < 60)
X						{	putchar ('\n');
X						}
X						lcount = 0;
X					}
X				}
X			}
X			for (i = 0;  i <= n;  i++)
X			{
X				if (how[i])
X				{	/*	either bold or underlined see if previous char
X						is not escaped - indicates the beginning of 
X						an escape sequence
X					*/
X					if (how[i] == 1  &&  how[i-1] == 0)
X						send (BEGIN_BOLD);
X					else if (how[i] == 2  &&  how[i-1] == 0)
X						send (underline_on);
X				}
X				else	/* zero means just a character, unmodified */
X				{	/* are we at the end of an escape sequence? */
X					if (how[i-1] == 1)
X						send (END_BOLD);
X					else if (how[i-1] == 2)
X						send (underline_off);
X				}
X				if (line[i])
X					putchar (line[i]);
X			}
X			putchar ('\n');	
X			clear (line, how, n);
X			n = 0;
X		}
X		else
X		{	if (line[n])
X			{	if (line[n] == c)		/* same character?		*/
X					how[n] = 1;			/*	yes:	bold		*/
X				else
X					how[n] = 2;			/*	no:		underline	*/
X			}
X			line[n++] = c;
X		}
X	}
X	exit (0);
X}
X
Xclear (line, how, n)
Xchar	*line;
Xint		*how;
Xint		n;
X{
X	int		i;
X	
X	for (i  = 0;  i <= n;  i++)
X	{	line[i] = '\0';
X		how[i] = 0;
X	}
X}
X
Xsend (s)
Xchar	*s;
X{
X	while (*s)
X		putchar (*s++);
X}
X
Xusage ()
X{
X	fprintf (stderr, "Usage:   pnf [-i] [-x] <in.file >out.file\n");
X	fprintf (stderr, " where        -i  = use italics in lieu of underline\n");
X	fprintf (stderr, "              -x  = ensure xenix man pages print fine\n");
X	exit (0);	
X}
X
Xtscan (s, t)
Xchar 	s[], t[];
X{
X	int	i, j, k;
X	for (i = 0;  s[i] != '\0';  i++)
X	{	for (j = i, k=0;  t[k] != '\0'  &&  s[j] == t[k];  j++, k++)
X			;
X		if (t[k] == '\0')
X			return (i);
X	}
X	return (-1);
X}
X
END_OF_FILE
if test 4166 -ne `wc -c <'pnf.c'`; then
    echo shar: \"'pnf.c'\" unpacked with wrong size!
fi
# end of 'pnf.c'
fi
if test -f 'pmf.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pmf.c'\"
else
echo shar: Extracting \"'pmf.c'\" \(5586 characters\)
sed "s/^X//" >'pmf.c' <<'END_OF_FILE'
X/* ta=4 */
X/****************************************************************************
X*							p m f . c		v1.1							*
X*																			*
X*	postscript mail filter													*
X*																			*
X*	very simple mail filter to print name and subject in bold letters		*
X*	for psf usage.  Generates escape sequences that psf can understand.		*
X*	Modify the code if you wish to have various headers ignored for print.	*
X*																			*
X*	Tony Field.       tony@ajfcal (or: calgary!ajfcal!tony@ai.toronto.edu)	*
X****************************************************************************/
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X
X#define BEGIN_BOLD			"\033B"
X#define END_BOLD			"\033b"
X
X#define BEGIN_UNDERLINE		"\033U"
X#define END_UNDERLINE		"\033u"
X
X#define BEGIN_ITALICS		"\033I"
X#define END_ITALICS			"\033i"
X
X#define	BEGIN_NAME			"\033F1\033B\033P13"	/* Helvetical bold 13 point */
X#define END_NAME			"\033p\033b\033f"		
X
X#define BEGIN_SUBJECT		"\033P13\033F1\033B\033I"	/*	Helvetica bold italic 13 point */
X#define END_SUBJECT			"\033i\033b\033f\033p"		/*	return to normal point, font */
X
X#define MAX_C				64
X
Xmain (argc, argv)
Xint		argc;
Xchar	*argv[];
X{
X	char	line[900], first[100], tail[800], *strchr();
X	int		i, many, nchar, last_char, header, garbage;
X	int		ignore_garbage;
X	extern char *optarg;
X	extern int	optind;
X
X	ignore_garbage = 1;
X	while ((i = getopt(argc, argv, "r-")) != -1)
X	{	switch (i)
X		{
X		case 'r':
X			ignore_garbage = 0;		/*	print all headers	*/
X			break;
X
X		default:
X			usage ();
X		}
X	}
X		
X	
X	header = garbage = 0;
X	while (gets (line)  != NULL)
X	{
Xnewmail:
X		last_char = split (line, first, tail);
X
X		/*	The following headers will be ignored during printing	*/
X		
X		if (ignore_garbage  
X			&&  (strcmp (first, "Received:") == 0
X			||   strcmp (first, "References:") == 0
X			||	 strcmp (first, "Path:") == 0
X			||	 strcmp (first, "Message-Id:") == 0
X			||	 strcmp (first, "Message-ID:") == 0))
X		{	garbage = 1;
X		}
X		else if (strcmp (first, "From") == 0)
X		{	printclean (first, tail);
X			garbage = 0;
X		}
X		else if (strcmp (first, "From:") == 0
X				||  strcmp (first, "Reply-To:") == 0
X				||  strcmp (first, "To:") == 0)
X		{	header = 1;
X			if ((strchr (tail, '(') == NULL)  &&  (strchr (tail, '<') == NULL))
X				printbold (first, tail);
X			else
X				printname (first, tail);
X			garbage = 0;
X		}
X		else if (strcmp (first, "Bcc:") == 0 ||  strcmp (first, "Cc:") == 0)
X		{	header = 1;
X			printname (first, tail);
X			garbage = 0;
X		}
X		else if (strcmp (first, "Subject:") == 0)
X		{	printsubject (first, tail);
X			garbage = 0;
X		}
X		else if (last_char == ':')
X		{
X			header = 1;
X			printclean (first, tail);
X			garbage = 0;
X		}
X		else if (empty (line))
X		{	
X			send ("\n");
X			while (gets (line) != NULL)
X			{	if (strncmp (line, "From ", 5) == 0
X					&&  (strchr (line, ':') < strrchr (line, ':')))
X				{	send ("\f");
X					goto newmail;	/* goto's considered harmful since 1964 */
X				}
X				printf ("%s\n", line);
X			}
X			break;
X		}
X		else if (garbage == 0)
X			printclean (" ", line);
X	}
X	exit (0);
X}
X
Xprintclean (first, tail)
Xchar	*first, *tail;
X{	char	*c, *prefix;
X	int		marks[100], nmarks, i, j, nchar;
X
X	/*	locate all marks that can be use for a line break 	*/
X
X	marks[0] = 0;
X	marks[1] = 0;
X	c = tail;
X	for ( i = nchar = 0, nmarks = 1;  nmarks < 100;  i++, c++, nchar++)
X	{
X		if (*c == '!'  ||  *c == ' ' ||  *c == '<'  
X			||  *c == '('  ||  *c == '\0')
X		{	if (nchar < MAX_C)
X				marks[nmarks] = i;
X			else
X			{	nchar = i - marks[nmarks];
X				marks[++nmarks] = i;
X			}
X			if (*c == '\0')
X				break;
X		}
X	}
X	marks[nmarks] = i;
X	prefix = first;
X	for (i = 0;  i < nmarks;  i++)
X	{
X		printf ("%-14s", prefix);
X		for (j = marks[i];  j < marks[i+1];  j++)
X			putchar (tail[j]);
X		putchar ('\n');
X		prefix = " ";
X	}
X}
X
Xprintsubject (first, tail)
Xchar	*first, *tail;
X{
X	printf ("%-14s", first);
X	send (BEGIN_SUBJECT);
X	send (tail);
X	send (END_SUBJECT);
X	send ("\n");
X}
X
Xprintbold (first, tail)
Xchar	*first, *tail;
X{
X	printf ("%-14s", first);
X	send (BEGIN_BOLD);
X	send (tail);
X	send (END_BOLD);	
X	send ("\n");
X}
X
Xprintname (first, tail)
Xchar	*first, *tail;
X{
X	printf ("%-14s", first);
X
X	if (strchr (tail, '<') != NULL)
X	{	/*	address syntax "name <address> stuff" */
X		send (BEGIN_NAME);
X		while (*tail != '<')
X			putchar (*tail++);
X		send (END_NAME);
X		putchar (*tail++);
X		while (*tail)
X		{	putchar (*tail);
X			if (*tail++ == '>')
X			{	if (*tail)
X				{	send (BEGIN_NAME);
X					while (*tail)
X						putchar (*tail++);
X					send (END_NAME);
X				}
X			}
X		}
X	}
X	else
X	{	/*	address syntax "address (name)" */
X		while (*tail  &&  *tail != '(')
X			putchar (*tail++);
X		if (*tail)
X		{	send (BEGIN_NAME);
X			putchar (*tail++);
X			while (*tail)
X			{	putchar (*tail);
X				if (*tail++ == ')')
X				{	send (END_NAME);
X					while (*tail)
X						putchar (*tail++);
X					putchar ('\n');
X					return;
X				}
X			}
X		}
X	}
X	putchar ('\n');
X}
X
Xsend (s)
Xchar	*s;
X{
X	while (*s)
X		putchar (*s++);
X}
X
Xempty (s)
Xchar	*s;
X{	while (*s  &&  *s <= ' ')
X		s++;
X	if (*s)
X		return (0);
X	else
X		return (1);
X}
X
Xsplit (line, first, tail)
Xchar	*line;			/*	input:	full input line			*/
Xchar	*first;			/*	return:	first word of line		*/
Xchar	*tail;			/*	return:	all others words of line*/
X{	int	last;
X
X	last = 0;
X	while (*line  &&  isspace (*line) == 0)
X	{	last = *line;
X		*first++ = *line++;
X	}
X	*first = '\0';
X	
X	while (*line  &&  isspace (*line))
X		line++;
X	
X	while (*line)
X		*tail++ = *line++;
X	*tail = '\0';
X	return (last);
X}
X
Xusage ()
X{
X	fprintf (stderr, "Usage:   pmf [-s] <in.file >out.file\n");
X	fprintf (stderr, " where        -s  = show all header lines\n");
X	exit (0);	
X}
END_OF_FILE
if test 5586 -ne `wc -c <'pmf.c'`; then
    echo shar: \"'pmf.c'\" unpacked with wrong size!
fi
# end of 'pmf.c'
fi
if test -f 'psbanner.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'psbanner.c'\"
else
echo shar: Extracting \"'psbanner.c'\" \(3524 characters\)
sed "s/^X//" >'psbanner.c' <<'END_OF_FILE'
X/* ta=4 */
X/****************************************************************************
X*				p s b a n n e r . c		v 1 . 1								*
X*																			*
X*	Print a banner page on a postscript printer for Xenix 2.2.3				*
X*																			*
X*	Tony Field.       tony@ajfcal  (or: calgary!ajfcal!tony@ai.toronto.edu)	*
X****************************************************************************/
X
X#include <stdio.h>
X
X#define MAX_X		612		/*	8.5 inches * 72 points		*/
X#define MAX_Y		792		/*	11  inches * 72 points		*/
X#define X_INDENT	40		/*	points						*/
X#define Y_INDENT	40
X#define	BIG_POINT	60		/* changes to point size automatically scale	*/
X#define MED_POINT	35		/* the printout.								*/
X#define	SMALL_POINT	15
X#define	UX			X_INDENT
X#define UY			(MAX_Y - Y_INDENT)
X#define DX			(MAX_X - 2 * X_INDENT)
X#define DY			(BIG_POINT * 3)
X
X/*	The following arguments are received in the command line	*/
X
X#define	Userid		argv[1]
X#define	Name		argv[2]
X#define	Requestid	argv[3]
X#define	Printer		argv[4]
X#define	Options		argv[5]
X#define	Date		argv[6]
X#define	Machineid	argv[7]
X#define	Title		argv[8]
X
Xmain (argc, argv)
Xint		argc;
Xchar	*argv[];
X{	int		x, y;
X
X	/*	center text used for userid and job title print  */
X	
X	send ("%!PS-Adobe-\n");
X	send ("/ctext {     % center text:   string x y dx\n");
X	send ("   2 div\n");
X	send ("   /Dx exch def\n");
X	send ("   /Yv exch def\n");
X	send ("   /Xv exch def\n");
X	send ("   dup stringwidth pop\n");
X	send ("   2 div\n");
X	send ("   Dx exch sub\n");
X	send ("   Xv add\n");
X	send ("   Yv moveto\n");
X	send ("   show\n");
X	send ("} def\n");
X	send ("%%EndProlog\n");
X
X	send ("%%Page: ? 0\n");
X	send ("/pg save def\n");
X
X	/*	draw a box for the userid */
X	
X	printf ("newpath\n");
X	printf ("%d %d moveto\n", UX,UY);
X	printf ("%d %d rlineto\n", DX, 0);
X	printf ("%d %d rlineto\n", 0, -DY);
X	printf ("%d %d rlineto\n", -DX, 0);
X	printf ("closepath\n");
X	printf ("4 setlinewidth\n");
X	printf ("stroke\n");
X
X	/*	center the userid and the job title */
X	
X	y = UY - DY / 2 - BIG_POINT / 2;
X	printf ("/Helvetica-BoldOblique findfont %d scalefont setfont\n", BIG_POINT);
X	printf ("(%s) %d %d %d ctext\n", Userid, X_INDENT, y, DX);
X
X	y = UY - (DY + MED_POINT * 3);
X	printf ("/Helvetica-Bold findfont %d scalefont setfont\n", MED_POINT);
X	printf ("(%s) %d %d %d ctext\n", Title, X_INDENT, y, DX);
X
X	/*	print other banner page parameters */
X	
X	x = X_INDENT;
X	y -= (MED_POINT * 2);
X	printf ("%d %d moveto\n", x,y);	
X	sendnormal ("User:       ");
X	sendbold (Name);
X
X	y -= SMALL_POINT + (SMALL_POINT / 2);
X	printf ("%d %d moveto\n", x,y);	
X	sendnormal ("Request ID: ");
X	sendbold (Requestid);
X	
X	y -= SMALL_POINT + (SMALL_POINT / 2);
X	printf ("%d %d moveto\n", x,y);	
X	sendnormal ("Printer ID: ");
X	sendbold (Printer);
X	
X	y -= SMALL_POINT + (SMALL_POINT / 2);
X	printf ("%d %d moveto\n", x,y);	
X	sendnormal ("Options:    ");
X	sendbold (Options);
X	
X	y -= SMALL_POINT + (SMALL_POINT / 2);
X	printf ("%d %d moveto\n", x,y);	
X	sendnormal ("Date:       ");
X	sendbold (Date);
X	
X	y -= SMALL_POINT + (SMALL_POINT / 2);
X	printf ("%d %d moveto\n", x,y);	
X	sendnormal ("Machine:    ");
X	sendbold (Machineid);
X
X	send ("showpage pg restore\n");
X	send ("%%Trailer\n");	
X	exit (0);
X}
X
Xsend (s)
Xchar	*s;
X{
X	while (*s)
X		putchar (*s++);
X}
X
Xsendnormal (s)
Xchar 	*s;
X{
X	printf ("/Courier findfont %d scalefont setfont\n", SMALL_POINT);
X	send ("(");
X	send (s);
X	send (")show\n");
X}
X
Xsendbold (s)
Xchar 	*s;
X{
X	printf ("/Helvetica-Bold findfont %d scalefont setfont\n", SMALL_POINT);
X	send ("(");
X	send (s);
X	send (")show\n");
X}
X
END_OF_FILE
if test 3524 -ne `wc -c <'psbanner.c'`; then
    echo shar: \"'psbanner.c'\" unpacked with wrong size!
fi
# end of 'psbanner.c'
fi
if test -f 'psdetect.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'psdetect.c'\"
else
echo shar: Extracting \"'psdetect.c'\" \(631 characters\)
sed "s/^X//" >'psdetect.c' <<'END_OF_FILE'
X/* ta=4 */
X/************************************************************************
X*		p s d e t e c t . c		v1.1									*
X*																		*
X*	determine if a a text file contains postscript code.				*
X************************************************************************/
X
X/*	this routine is intended for use within shell scripts.  It exits
X	with a return code of 0 if it detects a postscript file or
X	a value of 1 if it is not a postscript file
X*/
X
X#include <stdio.h>
X
Xmain ()
X{
X	char	line[1000];
X	
X	gets (line);
X/*
X	if (strncmp (line, "%!PS-Adobe", 10) == 0)
X*/
X	if (strncmp (line, "%!", 2) == 0)
X		exit (0);
X	exit (1);
X}
END_OF_FILE
if test 631 -ne `wc -c <'psdetect.c'`; then
    echo shar: \"'psdetect.c'\" unpacked with wrong size!
fi
# end of 'psdetect.c'
fi
if test -f 'postscript.LP' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'postscript.LP'\"
else
echo shar: Extracting \"'postscript.LP'\" \(2246 characters\)
sed "s/^X//" >'postscript.LP' <<'END_OF_FILE'
X:
X#
X#!	Postscript serial or parallel printer using psf filters
X#
X#	NOTE: the above line is displayed on the "mkdev lp" printer
X#	^^^^^ selection list.  If you create multiple printer models,
X#	      edit the above to signify the options invoked with psf.
X#
X#	This print model works with Xenix 2.2.3.  It is the printer
X#	back-end that is called by lp for physical printing.
X#
X#	The Makefile will use sed to replace "BINARY" with
X#		the binary library directory name.
X#		"OPTIONS" will be replaced by the desired default
X#		options specified in the Makefile.
X
X# The following parameters are passed from "lp" at print time.
X
Xprinter=`basename $0`
Xrequest=$1
Xname=$2
Xtitle=$3
Xcopies=$4
Xoptions=$5
Xshift; shift; shift; shift; shift
X
X# Modify the following for required stty settings.
X
Xstty ixon ixoff 0<&1
X
Xbanner=yes
Xtoday=`date`
Xfor i in $options; do
X	case $i in
X	b)	banner=no ;;
X	esac
Xdone
X
X[ "$banner" = yes ] && {
X
X#	get the machine name from /etc/systemid or with uname.
X
X	if test -r /etc/systemid; then
X		sysid=`sed 1q /etc/systemid`
X	else
X		sysid=`uname -n`
X	fi
X
X#	get the user name from the GCOS field in /etc/passwd
X
X	user=`sed -n "s/^$name:.*:.*:.*:\(.*\):.*:.*$/\1/p" /etc/passwd`
X
X#	get the count of the number of banner pages from /etc/default/lpd
X
X	nhead=`sed -n 's/^BANNERS=//p' /etc/default/lpd`
X	[ "$nhead" -ge 0 -a "$nhead" -le 5 ] || nhead=1
X	while	[ "$nhead" -gt 0 ]
X	do
X		BINARY/psbanner "$name" "$user" "$request" "$printer" "$options" "$today" "$sysid" "$title"
X		nhead=`expr $nhead - 1`
X	done
X}
X
X#	If the input text file contains %! in the first line,
X#	then assume that it has already been encapusulated in postscript
X#	code.  If the %! is missing, then filter through psf
X#
X#	Edit the psf entry below to specify alternate defaults.  For example,
X#	80 line pages printed 2-up (for a total of 160 lines on a page)
X#	in landscape layout could be specified with:
X#
X#		BINARY/psf -2 -l80 "$file" 2>&1
X#
X#	If you do not provide any options, the default is 60 lines
X#	per page in portrait layout:
X#
X#		BINARY/psf "$file" 2>&1
X
Xwhile	[ "$copies" -gt 0 ]
Xdo
X	for file
X	do
X		BINARY/psdetect < "$file"
X
X		case $? in
X
X		0)	cat "$file" 2>&1;;
X
X		1)	BINARY/psf OPTIONS "$file" 2>&1;;
X
X		esac
X	done
X	copies=`expr $copies - 1`
Xdone
Xexit 0
END_OF_FILE
if test 2246 -ne `wc -c <'postscript.LP'`; then
    echo shar: \"'postscript.LP'\" unpacked with wrong size!
fi
# end of 'postscript.LP'
fi
if test -f 'testfile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'testfile'\"
else
echo shar: Extracting \"'testfile'\" \(648 characters\)
sed "s/^X//" >'testfile' <<'END_OF_FILE'
XTest file for PSF postscript filter.
X
XThis is a simple test file.  This line is in default configuration.
X
XAny words within a line Umay be underlinedu or they Bmay be boldface.b
X
XIf you wish, F1you could changes fontsF2I multiple timesif in a line.
X
X
XChange P16point sizeP20 if you like.p
X
X
XMixing F3P22Ufonts, point sizes upf is quite reasonable.
X
X
XMixing P22F4fonts, and point sizes is quite Ureasonable
X
X
Xacross lines.upf  However, line skip size is based upon the
X
Xcurrent point size.  Nothing to Iworryi about, but do Urememberu.
X
X
Xhave   P20F7BUfunubfp
X
X
XF7Tony Field     ..!alberta!calgary!ajfcal!tonyf
END_OF_FILE
echo shar: 38 control characters may be missing from \"'testfile'\"
if test 648 -ne `wc -c <'testfile'`; then
    echo shar: \"'testfile'\" unpacked with wrong size!
fi
# end of 'testfile'
fi
echo shar: End of shell archive.
exit 0