[comp.sources.unix] v16i027: Public lineprinter spooler package, Part14/16

rsalz@bbn.com (Rich Salz) (09/15/88)

Submitted-by: papowell@julius.cs.umn.edu
Posting-number: Volume 16, Issue 27
Archive-name: plp/part14

#! /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 archive 14 (of 16)."
# Contents:  doc/PLP/02.t src/banner.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'doc/PLP/02.t' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/PLP/02.t'\"
else
echo shar: Extracting \"'doc/PLP/02.t'\" \(19343 characters\)
sed "s/^X//" >'doc/PLP/02.t' <<'END_OF_FILE'
X.ig
X$Header: 02.t,v 1.1 88/05/21 18:39:32 papowell Locked $
X$log$
X..
X.NH 1
PLP Programs
X.PP
The following section outlines the operation of the
X.IR lpd \|(8)
line printer
X.IR daemon ,
and the
X.IR lpr \|(1),
X.IR lpq \|(1),
X.IR lprm \|(1),
and
X.IR lpc \|(1)
utility programs.
X.NH 2
lpd \- Line Printer Dameon Program
X.PP
The 
X.IR lpd \|(8)
program is usually invoked at boot time from the
X.L /etc/rc
or
X.L /etc/rc.local
startup file,
and acts as a server or
X.I daemon
for coordinating and controlling
the spooling queues configured in the printcap file.
XFigure 2.1 is a typically  used to start the
X.I lpd
daemon.
X.KF
X.in +1i
X.L
X.SM
X.nf
X.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n 8i
X# Start up the lpd daemon
if [ -f /usr/lib/lpd ]; then
X    /usr/lib/lpd & (echo -n ' printer')  >/dev/console
X.LG
X.in -1i
X.R
X.ce
XFigure 2.1  Startup File Command for LPD
X.KE
X.PP
When
X.I lpd
is started,
it checks to see if there is an active
X.I lpd
daemon already running by trying to lock the
X.L /usr/spool/lpd.lock
file using the
X.IR flock \|(2)
or
X.IR lockf \|(3)
facilities.
If no daemon is present,
X.I lpd
forks a server process for each non-empty spool queue in the
X.IR printcap \|(5)
data base,
and then listens for service requests on specific
Internet domain port.
The Internet port name is found using the
X.IR getservbyname \|(3)
facility to get the
X.I printer
service information.
The
X.I "Advanced Tuturial on Interprocess Communications"
distributed with the Berkeley UNIX 4.3 BSD 
X(and reprinted by SUN Microsystems) provides an excellent
tutorial on interprocess communications.
See  the manual pages for
X.IR socket \|(2)
and 
X.IR services \|(5)
for more information on sockets and service specifications.
X.PP
When a connection is made to the 
X.I lpd
port by a requesting process (usually called a client),
X.I lpd
forks a server process to carry out the request and
continues to listen for new requests.
The Table 2.1 shows the requests
understood by
X.IR lpd .
The first byte of a request is a binary number
specifying the request type,
and the following characters up to a terminating a new line ('\en') character
are the request.
X.KF
X.TS
box center;
l | l.
Request	Interpretation
X_
X^Aprinter\en	start a server for the queue
X^Bprinter\en	receive and queue a job from another host
X^Cprinter [users ...] [jobs ...]\en	return short form of printer queue status
X^Dprinter [users ...] [jobs ...]\en	return long form of printer queue status
X^Eprinter person [users ...] [jobs ...]\en	remove jobs from a queue
X^Fperson command [printers]\en	perform lpc control function
X.TE
X.R
X.ce 1
Table 2.1 LPD Request Message Format
X.KE
X.PP
After reading the request,
the server process will the printer permissions file to
determine if the originating host
has permissions to access the specified printer.
Next,
the
X.I printcap
data base is scanned
determine the set of options and restrictions that apply to the
spool queue or printer.
XFinally,
the server will use this information to perform the requested action.
X.PP
In response to a
start printer message,
the server process will check to see if a server is present,
and if not,
will undertake to start unspooling activities.
The two forms of status requests will cause the server to check the
spool queue and report on the current activities.
X.PP
The file transfer request will cause the server and client process to start
transferring control and data files that make up a print job.
This activity is described in detail in Section 5.
The remove job request will cause the server to check that the user has
suitable permissions for the particular queue,
and will then remove the specified jobs.
X.PP
The control request will cause the server to perform control functions
similar to the
X.I lpd
program.
This function allows control over spooling operations to be done using the
X.I lpc
program on a remote host.
X.NH 3
Security Issues In a Networked Environment
X.PP
The permissions and restriction checks
performed by
X.I lpd
are based on the assumption that the client host machine is
well known by the network support software,
and that the process originating a request authenticates
the user requesting the service.
The port from which the client request can be originated
is restricted to a value which is reserved for users with system or
X.I "superuser"
permissions.
In a UNIX environment,
this means that the originating program must be running
X.I setuid
X(SUID)
X.I root
or the originating user is
X.IR root .
X.PP
In an environment where users can implement their own support for
TCP/IP facilities,
these security checks may not be sufficient.
In fact,
given access to the network communications hardware,
it is possible to forge messages that appear to be originating
from any valid site.
The problem of authentication of request is currently open;
as part of the PLP development a facility for
network wide authentication is under development.
X.NH 3
Spool Queue Access and Permissions
X.PP
As discussed in the previous section,
there are problems in controlling access to the PLP software by
clients on remote hosts.
As a preliminary step towards a more general authentication
procedure,
PLP uses a
X.I printer_perms
or printer permissions file contains a list of machines,
users,
spool queues and associated privileges.
Authentication of remote hosts is based on the network connection information
provided by the
X.IR gethostent \|(3N)
networking function.
In the future,
authentication of this information will be done
before using it to determine associated PLP capabilities.
X.KF
X.L
X.SM
X.TS
tab(:) center box;
l s s s s s s s
l l l l l l l l.
X# -- Line printer permissions
X# host:name:queue:Ops:Pr:Max:Done:#Comment
X~*.umn.edu:*:*:C:A:0:0:# filter out non-local sites
central.*.umn.edu:root:*:C:A:0:0:# root@central can do anything
X*.umn.edu:root:lp:C:A:0:100:# root@* can access lp, priority A
server.adm.umn.edu:admin:lp:R:C:1000:200:# admin@server, lp priority C
X!*:CS*:laser*:R:Z:*:*:# CS accounts, no laser queues
X*.umn.edu:*:lp:R:Z:*:*:# the great unwashed have priority Z
X.TE
X.LG
X.R
X.ce
Table 2.2 Example Printer Permissions File
X.KE
X.PP
XEach entry in the printer permissions file specifies a host machine,
a userid,
a printer or spool queue name,
a set of operations (R or C),
a maximum priority (A-Z),
and a maximum and current page counts associated with use of a spool queue.
Blank lines and lines that start with
X.L #
X(comment) are ignored.
XFields are separated with one or more spaces or tabs.
There is a simple wildcard match facility similar to the UNIX
shell metacharacter match.
The
X.L *
character will match 0 or more characters in the string,
and the
X.L ?
will match exactly one character.
Lines that start with a ! (not) indicate that permissions are
denied for queries that would otherwise match.
X.PP
Given a host,
user,
and spool queue,
the printer permissions file is searched for a matching entry in
first line to last line,
left to right order.
The host,
user,
and spool queue fields are checked for a match;
the first line found which matches these will terminate the search.
If an tilde
X.B (~)
is first character on the line,
the fields are checked for a match.
If the match fails,
then permissions are refused.
If the match succeeds,
then further searching will be done.
This facility allows only sites with suitable path names,
etc.,
to have access to a spool queue.
If an exclamation mark
X.B (!)
is first character on the line,
all permissions are refused;
this allows
X.I filtering
out request that are to be rejected in a simple manner.
If this facility is used,
entries should be ordered so that refusals
X(starting with !) precede any matching entries.
X.PP
XFor example,
the printer permissions file in Table 2.1 allows
X.L root
on host
X.L central
X(i.e.-
X.L root@central )
to access all queues,
X.L root
on any machine to access the lp queue,
and
X.L admin
on 
X.L server
to access the lp queue.
Userids starting with CS are denied permission to use
spool queues whose names start with laser.
Note that the host name used for checking is the full name returned by the
X.I gethostent (3N)
function.
X.PP
Spool queue operations,
spooling priorities,
and other information are set by the matching line.
The 
X.I Ops
field controls the allowed operations;
a
X.L C
value stands for Control,
and means that the user has permissions to use the LPC and LPRM
programs to manage a queue as well as spool jobs to the queue.
An
X.L R
value stands for LPR,
and means that the user can only spool to the queue and remove his own jobs.
Control functions can be exercised from remote hosts
using the
X.I remote
command of the
X.I lpc
program.
X.PP
The Priority field determines the maximum priority available to a user.
Users can prioritize jobs;
the default is
X.B Z ,
or lowest priority,
and the highest is
X.B A .
X.PP
The maximum and current page count fields are used for accounting
and other purposes.
They are checked when a job is queued by
X.I lpr
and when the job is unqueued for printing.
If the current maximum page count is exceeded by the user,
the job will be refused.
X.PP
The
server process checks the printer permissions file to determine if a
requesting host is allowed access to a particular queue;
if so,
it will perform the requested actions as detailed in the following sections.
X.NH 3
Unspooler Servers
X.PP
During initialization and in response to
X.I "start printer"
requests,
X.I lpd
forks an
unspooler or server process that processes jobs in the spool queue.
Jobs are placed in the spool queue by
X.I lpr
or are transferred from a remote site and removed by the server process.
XEach spool queue has a
X.I lock
file which is used to control spooling and unspooling activities.
The lock file
X.I owner ,
X.I group
and
X.I execute
permissions are used to control spooling and unspooling actions;
if the owner execute permission is set then unspooling is disabled
and if the group execute permission is set then spooling is disabled.
If unspooling is enabled,
the server tries to lock the
X.I lock
file;
if it cannot  be locked,
then another server is active and the process will exit.
X.PP
Once the server has gained control of the queue,
it finds the entries in the queue,
sort them in order of priority and time,
and then unspools them according to specifications in the
X.I printcap
file.
When a job unspooled,
the server will lock the job's control file
in order to prevent other processes from manipulating the job.
If it cannot lock the control file,
then the job is currently being manipulated by another PLP
program and the server will process another job in the queue.
X.NH 3
Local Printer Queues
X.PP
If the spool queue is for a local printer
X(a printer attached to the host processor),
then the server process will print the job
according to specifications in the
X.I printcap
file.
The printcap file specify
the physcial printer device,
any serial line characteristics which need to be set,
and any
X.I filter
programs  used to print the job.
X.NH 3
Remote Printer Queues
X.PP
If the spool queue is for a printer attached to another host,
the server attempts to connect to the remote host and transfer the
jobs in the spool queue to the remote host.
If the file system used to
store the job is flagged as being shared by the local host and the
remote host,
then it is not neccessary to transfer files
but only to inform the remote host that there are jobs in the spool queue.
X.NH 3
Multiple Printers For a Spool Queue
X.PP
If there are multiple unspooling devices or printers for a local queue,
the server process checks to see if unspooling is enabled,
and then forks individual unspooler process for each printer.
The printer processes will read the printcap entry controlling
the individual actions of each printer,
and then check the status of a printer lock file which controls the
action of the printer.
Thus,
individual printers can be enabled or disabled
as well as the entire spool queue.
X.NH 2
lpr \- Job Submission Program
X.PP
The
X.I lpr (1)
program is used to place a print job in a spool queue
and to then send a
X.I "start printer"
message to the 
X.I lpd
process.
The
X.I lpd
process is then responsible for printing the job or forwarding it to
the correct destination.
X.PP
The
X.I lpr
program uses the
printcap database to determine the actions required for spooling a job.
Spooling is enabled by the state of the spool queue lock file
permissions;
if the owner permission is set,
then spooling is disabled.
X.PP
Permission to use a spool queue is determined by using the
printer permissions file.
X.I Lpr
will determine the user name
X(by using the
X.I getuid (2)
and
X.I getpwent(3)
functions),
and then searches the
printer permission file to see if the user
can submit jobs to the spool queue (has R or C privileges).
If the user can use the spool queue,
X.I lpr
will then copy the users files to the spool queue.
On systems that support symbolic links,
X.I lpr
can make symbolic links to the original files
rather than copying them.
After copying a file,
X.I lpr
can be requested to remove the file.
Note that there are security loopholes in the use of the last two
facilities that restrict their use only to trusted users.
X.PP
Before a job is placed in the spool queue,
it may be desirable to do some local processing or prefiltering of the files.
XFor example,
running a formatter such as
X.IR pr ,
translating a typesetter format file into a different form,
etc,
can be done by lpr.
These actions are controlled by
X.I prefilter
information specified in the printcap entry for the spool queue.
X.PP
Associated with each job is a format
that specifies how the job is to be processed.
XFor example,
the
X.B f
format is the default format,
and is used when files contain printable information.
XEach format can have a
prefilter that is to be applied to the job before it is placed in the
spool queue.
The prefilter facility is 
usually used when files must have some further form of processing carried out,
but the remote site where they are to be printed cannot perform
the processing.
X.PP
Once the job has been placed in a queue,
lpr will request the lpd daemon to start a spool queue server.
X.NH 2
lpq \- Spool Queue Status Display
X.PP
The
X.IR lpq \|(1)
program displays the status and contents of selected spool queues.
X.I Lpq
has two forms of output:
the (default) long format which displays a complete summary of
the current spool queue activities,
and a short format which simply lists the jobs that are outstanding,
The output format of
X.I lpq
is extraordinarily verbose,
and attempts to give a full picture of the total state of the line printer
and its associated queues,
servers,
and other information.
The following is an example of the output produced by
X.I lpq
when displaying the status of a remote spool queue.
X.DS
X.L
X.SM
X.nf
Printer 'diablo' (julius.cs.umn.edu):
X  processing, active job started Wed May 11 15:20:54 1988, attempt 1
X  Rank Owner       Pr Job Host        Files                Size
active root        A  15  julius      /tmp/test5           132
X   2nd root        Z  14  julius      /tmp/test2           15
Remote printer 'lp2' (umn-cs.cs.umn.edu):
Warning: no server present
X  work done at Wed May 11 15:16:43 1988
X  Rank Owner       Pr Job Host        Files                Size
X   1st root        Z  13  julius      /tmp/test3           30
X   2nd root        Z  14  julius      /tmp/test4           9
X.LG
X.DE
X.PP
The first line identifies the name of the local printer,
and the host.
It is followed by an informative message generated by the currently active
server process,
which is transferring a file to the remote site.
Next is a list of the files in the local queue,
ranked according to their processing order.
The next line identifies the remote printer and site.
The warning message indicates that no server process is present,
even though there are jobs in the spool queue.
This is a transitory condition,
because the server process will be started as soon as the file transfers
are completed.
X.DS
X.L
X.SM
X.nf
imagen_lind27: 0 jobs
imagen_ld27: 3 jobs
X1 cfZ022julius: root
X2 cfZ023julius: root
X3 cfZ024julius: root
X.LG
X.DE
The short form of status display 
illustrated above merely gives a summary of the numbers of jobs
and their order in the queue.
X.NH 2
lprm \- remove jobs from a queue
X.PP
The
X.IR lprm \|(1)
command deletes jobs from a spooling queue.
If necessary,
X.I lprm
will kill off a server process which is working on the job.
After removing any files,
it will then restart the queue by sending a request to the lpd daemon.
X.I Lprm
will lock a job control file before removing the job,
preventing a server from trying to unspool the job while it is being removed.
X.PP
If a user can submit jobs to a queue,
he can remove jobs that he has submitted.
The root or superuser for a host can remove any job submitted from
a particular host.
XFinally,
the printer permission file will allow any use with control permissions for
a spool queue to remove any job from the spool queue.
X.NH 2
lpc \- line printer control program
X.PP
The
X.IR lpc \|(1)
program is used to monitor and control the
operation of the Line Printer Software
by manipulating the status of  spool queue lock files,
and killing active servers.
It can send messages to PLP daemons requesting that
they carry out similar actions,
controlling both local and remote PLP daemons.
It is not necessary to log onto a remote machine to perform control
actions,
as long as the printer permissions file has the appropriate entries.
The
X.I lpc
program has the following commands.
Unless specified as unpriviledged,
they can only be used by a user with control permissions for the specified
spool queue,
and on the current or local host machine.
X.I All
or individual queues can be operated on.
X.IP "disable/enable [queue* | all]" 3
Disable or enable spooling to list of queues or  all queues.
X.IP "start/restart/stop [queue* | all]" 3
The start command enables  unspooling from a queue,
and starts a server;
restart is unprivileged and simply request the
X.I lpd
process to start a server.
The stop command disables any further unspooling.
X.IP "abort/kill [queue* | all]" 3
The abort command does a stop,
and then kills off any server process that is active for the queue.
The kill command does an abort followed by a start;
this last command is handy for restarting a queue whose server process
is hung due to problems with a job or hardware.
X.IP "status [queue*]" 3
Display a short form of status information about the spool queues.
The following is a typical status report.
X.DS
X.SM
X.L
X.nf
Queue          Jobs    Queueing     Printing
imagen_lind27     1    enabled      enabled (server 15817, job cfZ025julius)
X  checking queue at Thu May 12 11:19:22 1988
diablo_lind136    0    enabled      enabled 
X  work done at Wed May 11 15:21:04 1988
X.LG
X.DE
X.IP "topq queue [job*]" 3
Rearrange the order of jobs in a spool queue,
placing specified jobs at the head of the queue.
X.IP "lprm queue [job*]" 3
Use lprm to remove a job from the specified queue.
X.IP "lpq [parms*]" 3
Use lpq to display queue status.
X.IP "lpd\ \ \ " 3
Report the status of the lpd daemon.
This is useful when you wish to monitor the status of the daemon process.
X.IP "remote {command}" 3
Perform the command for the specified spool queue at the remote host.
The start,
stop,
abort,
etc.,
commands will be executed by the remote
X.I lpd
daemon.
This command is useful for network wide management of the PLP spooler.
END_OF_FILE
if test 19343 -ne `wc -c <'doc/PLP/02.t'`; then
    echo shar: \"'doc/PLP/02.t'\" unpacked with wrong size!
fi
# end of 'doc/PLP/02.t'
fi
if test -f 'src/banner.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/banner.c'\"
else
echo shar: Extracting \"'src/banner.c'\" \(21457 characters\)
sed "s/^X//" >'src/banner.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: banner.c
X ***************************************************************************
X * Revision History: Fri Jan 15 12:13:50 CST 1988
X * $Log:	banner.c,v $
X * Revision 3.1  88/06/18  09:36:50  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 3.1  88/06/18  09:30:10  papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X * 
X * Revision 2.1  88/05/09  10:07:30  papowell
X * PLP: Released Version
X * 
X * Revision 1.5  88/05/05  20:09:07  papowell
X * Modified short banner format
X * 
X * Revision 1.4  88/04/21  21:51:21  papowell
X * Removed spurious line feeds
X * 
X * Revision 1.3  88/03/25  14:58:55  papowell
X * Debugged Version:
X * 1. Added the PLP control file first transfer
X * 2. Checks for MX during file transfers
X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
X * 	apparently they open files and then assume that they will stay
X * 	open.
X * 4. Made sure that stdin, stdout, stderr was available at all times.
X * 
X * Revision 1.2  88/03/05  15:01:32  papowell
X * Minor Corrections,  Lint Problems
X * 
X * Revision 1.1  88/03/01  11:08:11  papowell
X * Initial revision
X * 
X * banner printing routine.
X * some of the code (the tables for the banner headers) was stolen from the
X * old LPD program.  But this in turn was snarfed from a banner
X * printing games program.  Which snarfed it from an old card deck... etc.
X *
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X	"$Header: banner.c,v 3.1 88/06/18 09:36:50 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lp.h"
X
X/*
X * Print a banner
X * The large character fonts have been stolen from the
X * BANNER program, which stole them from an old card deck...
X * 
X * banner( fd )
X * will print the banner
X * 1. form feed if needed
X * 2. print banner
X * 3. another form feed
X */
X#define HEIGHT  9       /* height of representation of characters */
X#define WIDTH   8       /* width of characters */
X#define DROP    3       /* offset to drop characters with descenders */
X#define BLAST   10      /* 10 lines to separate things */
X#define SEP     3       /* 3 lines to separate BLAST from printing */
X
static int linecnt;
static int fail;
extern char chartable[][HEIGHT];
static char *bline;
static unsigned blen;
static int fd;
X
int
banner( pr )
X	int pr;
X{
X	linecnt = 0;
X	/*
X	 * print the banner
X	 */
X
X	fd = pr;
X	fail = 0;
X	if( bline == 0 ){
X		blen = BUFSIZ;
X		if( (bline = malloc( blen )) == 0 ){
X			logerr_die( XLOG_INFO, "banner: malloc failed" );
X		}
X	}
X	if( blen < PW+1 ){
X		blen = PW+2;
X		if( (bline = realloc( bline, blen )) == 0 ){
X			logerr_die( XLOG_INFO, "banner: realloc failed" );
X		}
X	}
X	if( SB ) {
X		shortbanner();
X	} else {
X		longbanner();
X	}
X	if(Debug>4)log( XLOG_DEBUG, "banner: printed, fail %d", fail);
X	if( fail ){
X		return( JFAIL );
X	} else {
X		return( JSUCC );
X	}
X}
X
X/*
X * shortbanner
X * single line, has format:
X * adobe:shore  Job: test.data  Date: Tue Sep 18 16:22:33 1984
X */
shortbanner()
X{
X	(void)sprintf(bline, "%s:%s Job: %s Date: %s", LOGNAME, FROMHOST, JOBNAME, Time_str());
X	Out_line();
X}
X/*
X * userinfo
X * just print the information
X */
userinfo()
X{
X	(void)sprintf(bline, "User: %s@%s", LOGNAME, FROMHOST);
X	Out_line();
X	(void)sprintf(bline, "Name: %s", BNRNAME);
X	Out_line();
X	(void)sprintf(bline, "Date: %s", Time_str());
X	Out_line();
X	(void)sprintf(bline, "Job: %s", JOBNAME );
X	Out_line();
X	(void)sprintf(bline, "Class: %s", CLASSNAME );
X	Out_line();
X}
X/*
X * long banner
X * get fancy and print separators, etc.
X */
longbanner()
X{
X	int i;			/* ACME integers, INC */
X
X	for( i = 0; i < BLAST; ++i ){
X		breakline( '*');
X	}
X	for( i = 0; i < SEP; ++i ){
X		breakline( 0 );
X	}
X	/*
X	 * print the Name and Host in BIG letters
X	 */
X	bigprint( LOGNAME);
X	bigprint( FROMHOST);
X	userinfo();
X	for( i = 0; i < SEP; ++i ){
X		breakline( 0);
X	}
X	if( PL > 0 ){
X		/* separator from banner */
X		while( (linecnt + BLAST) % PL ){
X			breakline( 0 );
X		}
X		/* page bottom marker */
X		while(  linecnt % PL ){
X			breakline( '*' );
X		}
X	}
X}
X
breakline( c )
X	int c;
X{
X	int	i;	/* ACME Integers, Inc. */
X
X	i = 0;
X	if( c ){
X		for( i = 0; i < PW; ++i ){
X			bline[i] = c;
X		}
X	}
X	bline[i] = 0;
X	Out_line();
X}
X
X/***************************************************************************
X * bigprint( char * line )
X * print the line in big characters 
X * for i = topline to bottomline do
X *  for each character in the line do
X *    get the scan line representation for the character
X *    foreach bit in the string do
X *       if the bit is set, print X, else print ' ';
X *	  endfor
X *  endfor
X * endfor
X ***************************************************************************/
X
bigprint( line )
X	char *line;
X{
X	int i, j;		/* ACME Integers, Inc. */
X	int cnt;		/* number of characters */
X
X	if(Debug>5)log(XLOG_DEBUG,"bigprint: '%s'", line );
X	cnt = strlen(line);
X	i = PW/WIDTH;
X	if( cnt > i ){
X		cnt = i;
X	}
X	for( i = 0;  i < HEIGHT+DROP; ++i ){
X		for( j = 0; j < cnt; ++j ){
X			do_char( line[j], i, bline+(j*WIDTH) );
X		}
X		bline[j*WIDTH] = 0;
X		Out_line();
X	}
X}
X
X/***************************************************************************
X * do_char( c, line, buf )
X *  print out the raster line corresponding to character c, line l
X *  If a character is not a descender, you can use the direct mapping.
X *  If it is a descender,  you have to shift down by the descender amount.
X *  1.  for lines above the "top" of a descender line
X *      if the character is a descender, print a space
X *      otherwise print normally
X *  2.  for lines at and below the top of a descender
X *      if the character is a descender, print line
X *      otherwise print normally
X *  3.  for lines below the baseline
X *      if a descender, print line
X *      otherwise print blank
X ***************************************************************************/
static int
is_descender(c)
X	char c;
X{
X	switch(c) {
X	case '_': case ';': case ',': case 'g': case 'j': case 'p':
X	case 'q': case 'y':
X		return(1);
X	default:
X		break;
X	}
X	return (0);
X}
X
do_char( c, line, buf )
X	int c;		/* character */
X	int line;
X	char *buf;
X{
X	int i;					/* ACME Integer, Inc. */
X	int position;			/* index into chartable */
X	int rep;				/* representation of character scan line */
X
X	if( !isprint( c ) ){
X		c = ' ';
X	}
X	if(Debug>5)log(XLOG_DEBUG,"do_char: %c, line %d", c, line );
X	position = c - ' ';
X	if( is_descender(c) ){
X		if( line >= DROP ){
X			line = line - DROP;
X		} else {
X			position = 0;
X			line = 0;
X		}
X	}
X	if( line >= HEIGHT ){
X		position = 0;
X		line = 0;
X	}
X
X	rep = chartable[position][line];
X	if(Debug>5)log(XLOG_DEBUG,"do_char: position %d, line %d, rep 0x%x",
X		position, line, rep );
X	for( i = 6; i >= 0; --i ){
X		if( rep & (1 << i)){
X			buf[6-i] = 'o';
X		} else {
X			buf[6-i] = ' ';
X		}
X	}
X	for( i = 7; i < WIDTH; ++i ){
X		buf[i] = ' ';
X	}
X}
X
X
X/***************************************************************************
X * Out_line( char* buf )
X * write the buffer out to the file descriptor.
X * don;t do if fail is invalid.
X ***************************************************************************/
Out_line()
X{
X	int i;
X	i = strlen(bline);
X
X	if( fail == 0 ){
X		if( (i > 0 && write( fd, bline, i) != i) || write( fd, "\n", 1) != 1){
X			logerr( XLOG_INFO, "Out_line: write failed" );
X			fail = 1;
X		}
X	}
X	++linecnt;
X}
X
X#define c_______ 0
X#define c______1 01
X#define c_____1_ 02
X#define c____1__ 04
X#define c____11_ 06
X#define c___1___ 010
X#define c___1__1 011
X#define c___1_1_ 012
X#define c___11__ 014
X#define c__1____ 020
X#define c__1__1_ 022
X#define c__1_1__ 024
X#define c__11___ 030
X#define c__111__ 034
X#define c__111_1 035
X#define c__1111_ 036
X#define c__11111 037
X#define c_1_____ 040
X#define c_1____1 041
X#define c_1___1_ 042
X#define c_1__1__ 044
X#define c_1_1___ 050
X#define c_1_1__1 051
X#define c_1_1_1_ 052
X#define c_11____ 060
X#define c_11_11_ 066
X#define c_111___ 070
X#define c_111__1 071
X#define c_111_1_ 072
X#define c_1111__ 074
X#define c_1111_1 075
X#define c_11111_ 076
X#define c_111111 077
X#define c1______ 0100
X#define c1_____1 0101
X#define c1____1_ 0102
X#define c1____11 0103
X#define c1___1__ 0104
X#define c1___1_1 0105
X#define c1___11_ 0106
X#define c1__1___ 0110
X#define c1__1__1 0111
X#define c1__11_1 0115
X#define c1__1111 0117
X#define c1_1____ 0120
X#define c1_1___1 0121
X#define c1_1_1_1 0125
X#define c1_1_11_ 0126
X#define c1_111__ 0134
X#define c1_1111_ 0136
X#define c11____1 0141
X#define c11___1_ 0142
X#define c11___11 0143
X#define c11_1___ 0150
X#define c11_1__1 0151
X#define c111_11_ 0166
X#define c1111___ 0170
X#define c11111__ 0174
X#define c111111_ 0176
X#define c1111111 0177
X
char chartable[][HEIGHT] =	/* this is relatively easy to modify */
X			/* just look: */
X{
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______ },			/*   */
X
X	{ c__11___,
X	  c__11___,
X	  c__11___,
X	  c__11___,
X	  c__11___,
X	  c_______,
X	  c_______,
X	  c__11___,
X	  c__11___ },			/* ! */
X
X	{ c_1__1__,
X	  c_1__1__,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______ },			/* " */
X
X	{ c_______,
X	  c__1_1__,
X	  c__1_1__,
X	  c1111111,
X	  c__1_1__,
X	  c1111111,
X	  c__1_1__,
X	  c__1_1__,
X	  c_______ },			/* # */
X
X	{ c___1___,
X	  c_11111_,
X	  c1__1__1,
X	  c1__1___,
X	  c_11111_,
X	  c___1__1,
X	  c1__1__1,
X	  c_11111_,
X	  c___1___ },			/* $ */
X
X 	{ c_1_____,
X 	  c1_1___1,
X 	  c_1___1_,
X 	  c____1__,
X 	  c___1___,
X 	  c__1____,
X 	  c_1___1_,
X 	  c1___1_1,
X 	  c_____1_ },			/* % */
X 
X 	{ c_11____,
X 	  c1__1___,
X 	  c1___1__,
X 	  c_1_1___,
X 	  c__1____,
X 	  c_1_1__1,
X 	  c1___11_,
X 	  c1___11_,
X 	  c_111__1 },			/* & */
X 
X 	{ c___11__,
X 	  c___11__,
X 	  c___1___,
X 	  c__1____,
X 	  c_______,
X 	  c_______,
X 	  c_______,
X 	  c_______,
X 	  c_______ },			/* ' */
X 
X 	{ c____1__,
X 	  c___1___,
X 	  c__1____,
X 	  c__1____,
X 	  c__1____,
X 	  c__1____,
X 	  c__1____,
X 	  c___1___,
X 	  c____1__ },			/* ( */
X 
X 	{ c__1____,
X 	  c___1___,
X 	  c____1__,
X 	  c____1__,
X 	  c____1__,
X 	  c____1__,
X 	  c____1__,
X 	  c___1___,
X 	  c__1____ },			/* ) */
X 
X 	{ c_______,
X 	  c___1___,
X 	  c1__1__1,
X 	  c_1_1_1_,
X 	  c__111__,
X 	  c_1_1_1_,
X 	  c1__1__1,
X 	  c___1___,
X 	  c_______ },			/* * */
X 
X 	{ c_______,
X 	  c___1___,
X 	  c___1___,
X 	  c___1___,
X 	  c1111111,
X 	  c___1___,
X 	  c___1___,
X 	  c___1___,
X 	  c_______ },			/* + */
X 
X 	{ c_______,
X 	  c_______,
X 	  c_______,
X 	  c_______,
X 	  c__11___,
X 	  c__11___,
X 	  c__1____,
X 	  c_1_____,
X 	  c_______ },			/* , */
X 
X 	{ c_______,
X 	  c_______,
X 	  c_______,
X 	  c_______,
X 	  c1111111,
X 	  c_______,
X 	  c_______,
X 	  c_______,
X 	  c_______ },			/* - */
X 
X 	{ c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c__11___,
X	  c__11___ },			/* . */
X
X	{ c_______,
X	  c______1,
X	  c_____1_,
X	  c____1__,
X	  c___1___,
X	  c__1____,
X	  c_1_____,
X	  c1______,
X	  c_______ },			/* / */
X
X	{ c_11111_,
X	  c1_____1,
X	  c1____11,
X	  c1___1_1,
X	  c1__1__1,
X	  c1_1___1,
X	  c11____1,
X	  c1_____1,
X	  c_11111_ },			/* 0 */
X
X	{ c___1___,
X	  c__11___,
X	  c_1_1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c_11111_ },			/* 1 */
X
X	{ c_11111_,
X	  c1_____1,
X	  c______1,
X	  c_____1_,
X	  c__111__,
X	  c_1_____,
X	  c1______,
X	  c1______,
X	  c1111111 },			/* 2 */
X
X	{ c_11111_,
X	  c1_____1,
X	  c______1,
X	  c______1,
X	  c__1111_,
X	  c______1,
X	  c______1,
X	  c1_____1,
X	  c_11111_ },			/* 3 */
X
X	{ c_____1_,
X	  c____11_,
X	  c___1_1_,
X	  c__1__1_,
X	  c_1___1_,
X	  c1____1_,
X	  c1111111,
X	  c_____1_,
X	  c_____1_ },			/* 4 */
X
X	{ c1111111,
X	  c1______,
X	  c1______,
X	  c11111__,
X	  c_____1_,
X	  c______1,
X	  c______1,
X	  c1____1_,
X	  c_1111__ },			/* 5 */
X
X	{ c__1111_,
X	  c_1_____,
X	  c1______,
X	  c1______,
X	  c1_1111_,
X	  c11____1,
X	  c1_____1,
X	  c1_____1,
X	  c_11111_ },			/* 6 */
X
X	{ c1111111,
X	  c1_____1,
X	  c_____1_,
X	  c____1__,
X	  c___1___,
X	  c__1____,
X	  c__1____,
X	  c__1____,
X	  c__1____ },			/* 7 */
X
X	{ c_11111_,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c_11111_,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c_11111_ },			/* 8 */
X
X	{ c_11111_,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c_111111,
X	  c______1,
X	  c______1,
X	  c1_____1,
X	  c_1111__ },			/* 9 */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c__11___,
X	  c__11___,
X	  c_______,
X	  c_______,
X	  c__11___,
X	  c__11___ },			/* : */
X
X
X	{ c__11___,
X	  c__11___,
X	  c_______,
X	  c_______,
X	  c__11___,
X	  c__11___,
X	  c__1____,
X	  c_1_____,
X	  c_______ },			/* ; */
X
X	{ c____1__,
X	  c___1___,
X	  c__1____,
X	  c_1_____,
X	  c1______,
X	  c_1_____,
X	  c__1____,
X	  c___1___,
X	  c____1__ },			/* < */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c1111111,
X	  c_______,
X	  c1111111,
X	  c_______,
X	  c_______,
X	  c_______ },			/* = */
X
X	{ c__1____,
X	  c___1___,
X	  c____1__,
X	  c_____1_,
X	  c______1,
X	  c_____1_,
X	  c____1__,
X	  c___1___,
X	  c__1____ },			/* > */
X
X	{ c__1111_,
X	  c_1____1,
X	  c_1____1,
X	  c______1,
X	  c____11_,
X	  c___1___,
X	  c___1___,
X	  c_______,
X	  c___1___ },			/* ? */
X
X	{ c__1111_,
X	  c_1____1,
X	  c1__11_1,
X	  c1_1_1_1,
X	  c1_1_1_1,
X	  c1_1111_,
X	  c1______,
X	  c_1____1,
X	  c__1111_ },			/* @ */
X
X	{ c__111__,
X	  c_1___1_,
X	  c1_____1,
X	  c1_____1,
X	  c1111111,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1 },			/* A */
X
X	{ c111111_,
X	  c_1____1,
X	  c_1____1,
X	  c_1____1,
X	  c_11111_,
X	  c_1____1,
X	  c_1____1,
X	  c_1____1,
X	  c111111_ },			/* B */
X
X	{ c__1111_,
X	  c_1____1,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c_1____1,
X	  c__1111_ },			/* C */
X
X	{ c11111__,
X	  c_1___1_,
X	  c_1____1,
X	  c_1____1,
X	  c_1____1,
X	  c_1____1,
X	  c_1____1,
X	  c_1___1_,
X	  c11111__ },			/* D */
X
X	{ c1111111,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c111111_,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1111111 },			/* E */
X
X	{ c1111111,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c111111_,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1______ },			/* F */
X
X	{ c__1111_,
X	  c_1____1,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1__1111,
X	  c1_____1,
X	  c_1____1,
X	  c__1111_ },			/* G */
X
X	{ c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1111111,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1 },			/* H */
X
X	{ c_11111_,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c_11111_ },			/* I */
X
X	{ c__11111,
X	  c____1__,
X	  c____1__,
X	  c____1__,
X	  c____1__,
X	  c____1__,
X	  c____1__,
X	  c1___1__,
X	  c_111___ },			/* J */
X
X	{ c1_____1,
X	  c1____1_,
X	  c1___1__,
X	  c1__1___,
X	  c1_1____,
X	  c11_1___,
X	  c1___1__,
X	  c1____1_,
X	  c1_____1 },			/* K */
X
X	{ c1______,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1111111 },			/* L */
X
X	{ c1_____1,
X	  c11___11,
X	  c1_1_1_1,
X	  c1__1__1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1 },			/* M */
X
X	{ c1_____1,
X	  c11____1,
X	  c1_1___1,
X	  c1__1__1,
X	  c1___1_1,
X	  c1____11,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1 },			/* N */
X
X	{ c__111__,
X	  c_1___1_,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c_1___1_,
X	  c__111__ },			/* O */
X
X	{ c111111_,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c111111_,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1______ },			/* P */
X
X	{ c__111__,
X	  c_1___1_,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1__1__1,
X	  c1___1_1,
X	  c_1___1_,
X	  c__111_1 },			/* Q */
X
X	{ c111111_,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c111111_,
X	  c1__1___,
X	  c1___1__,
X	  c1____1_,
X	  c1_____1 },			/* R */
X
X	{ c_11111_,
X	  c1_____1,
X	  c1______,
X	  c1______,
X	  c_11111_,
X	  c______1,
X	  c______1,
X	  c1_____1,
X	  c_11111_ },			/* S */
X
X	{ c1111111,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___ },			/* T */
X
X	{ c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c_11111_ },			/* U */
X
X	{ c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c_1___1_,
X	  c_1___1_,
X	  c__1_1__,
X	  c__1_1__,
X	  c___1___,
X	  c___1___ },			/* V */
X
X	{ c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c1__1__1,
X	  c1__1__1,
X	  c1_1_1_1,
X	  c11___11,
X	  c1_____1 },			/* W */
X
X	{ c1_____1,
X	  c1_____1,
X	  c_1___1_,
X	  c__1_1__,
X	  c___1___,
X	  c__1_1__,
X	  c_1___1_,
X	  c1_____1,
X	  c1_____1 },			/* X */
X
X	{ c1_____1,
X	  c1_____1,
X	  c_1___1_,
X	  c__1_1__,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___ },			/* Y */
X
X	{ c1111111,
X	  c______1,
X	  c_____1_,
X	  c____1__,
X	  c___1___,
X	  c__1____,
X	  c_1_____,
X	  c1______,
X	  c1111111 },			/* Z */
X
X	{ c_1111__,
X	  c_1_____,
X	  c_1_____,
X	  c_1_____,
X	  c_1_____,
X	  c_1_____,
X	  c_1_____,
X	  c_1_____,
X	  c_1111__ },			/* [ */
X
X	{ c_______,
X	  c1______,
X	  c_1_____,
X	  c__1____,
X	  c___1___,
X	  c____1__,
X	  c_____1_,
X	  c______1,
X	  c_______ },			/* \ */
X
X	{ c__1111_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c__1111_ },			/* ] */
X
X	{ c___1___,
X	  c__1_1__,
X	  c_1___1_,
X	  c1_____1,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______ },			/* ^ */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c1111111,
X	  c_______ },			/* _ */
X
X	{ c__11___,
X	  c__11___,
X	  c___1___,
X	  c____1__,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______ },			/* ` */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c_1111__,
X	  c_____1_,
X	  c_11111_,
X	  c1_____1,
X	  c1____11,
X	  c_1111_1 },			/* a */
X
X	{ c1______,
X	  c1______,
X	  c1______,
X	  c1_111__,
X	  c11___1_,
X	  c1_____1,
X	  c1_____1,
X	  c11___1_,
X	  c1_111__ },			/* b */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c_1111__,
X	  c1____1_,
X	  c1______,
X	  c1______,
X	  c1____1_,
X	  c_1111__ },			/* c */
X
X	{ c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c_111_1_,
X	  c1___11_,
X	  c1____1_,
X	  c1____1_,
X	  c1___11_,
X	  c_111_1_ },			/* d */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c_1111__,
X	  c1____1_,
X	  c111111_,
X	  c1______,
X	  c1____1_,
X	  c_1111__ },			/* e */
X
X	{ c___11__,
X	  c__1__1_,
X	  c__1____,
X	  c__1____,
X	  c11111__,
X	  c__1____,
X	  c__1____,
X	  c__1____,
X	  c__1____ },			/* f */
X
X	{ c_111_1_,
X	  c1___11_,
X	  c1____1_,
X	  c1____1_,
X	  c1___11_,
X	  c_111_1_,
X	  c_____1_,
X	  c1____1_,
X	  c_1111__ },			/* g */
X
X	{ c1______,
X	  c1______,
X	  c1______,
X	  c1_111__,
X	  c11___1_,
X	  c1____1_,
X	  c1____1_,
X	  c1____1_,
X	  c1____1_ },			/* h */
X
X	{ c_______,
X	  c___1___,
X	  c_______,
X	  c__11___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c__111__ },			/* i */
X
X	{ c____11_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_,
X	  c_1___1_,
X	  c__111__ },			/* j */
X
X	{ c1______,
X	  c1______,
X	  c1______,
X	  c1___1__,
X	  c1__1___,
X	  c1_1____,
X	  c11_1___,
X	  c1___1__,
X	  c1____1_ },			/* k */
X
X	{ c__11___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c__111__ },			/* l */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c1_1_11_,
X	  c11_1__1,
X	  c1__1__1,
X	  c1__1__1,
X	  c1__1__1,
X	  c1__1__1 },			/* m */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c1_111__,
X	  c11___1_,
X	  c1____1_,
X	  c1____1_,
X	  c1____1_,
X	  c1____1_ },			/* n */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c_1111__,
X	  c1____1_,
X	  c1____1_,
X	  c1____1_,
X	  c1____1_,
X	  c_1111__ },			/* o */
X
X	{ c1_111__,
X	  c11___1_,
X	  c1____1_,
X	  c1____1_,
X	  c11___1_,
X	  c1_111__,
X	  c1______,
X	  c1______,
X	  c1______ },			/* p */
X
X	{ c_111_1_,
X	  c1___11_,
X	  c1____1_,
X	  c1____1_,
X	  c1___11_,
X	  c_111_1_,
X	  c_____1_,
X	  c_____1_,
X	  c_____1_ },			/* q */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c1_111__,
X	  c11___1_,
X	  c1______,
X	  c1______,
X	  c1______,
X	  c1______ },			/* r */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c_1111__,
X	  c1____1_,
X	  c_11____,
X	  c___11__,
X	  c1____1_,
X	  c_1111__ },			/* s */
X
X	{ c_______,
X	  c__1____,
X	  c__1____,
X	  c11111__,
X	  c__1____,
X	  c__1____,
X	  c__1____,
X	  c__1__1_,
X	  c___11__ },			/* t */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c1____1_,
X	  c1____1_,
X	  c1____1_,
X	  c1____1_,
X	  c1___11_,
X	  c_111_1_ },			/* u */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c1_____1,
X	  c1_____1,
X	  c1_____1,
X	  c_1___1_,
X	  c__1_1__,
X	  c___1___ },			/* v */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c1_____1,
X	  c1__1__1,
X	  c1__1__1,
X	  c1__1__1,
X	  c1__1__1,
X	  c_11_11_ },			/* w */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c1____1_,
X	  c_1__1__,
X	  c__11___,
X	  c__11___,
X	  c_1__1__,
X	  c1____1_ },			/* x */
X
X	{ c1____1_,
X	  c1____1_,
X	  c1____1_,
X	  c1____1_,
X	  c1___11_,
X	  c_111_1_,
X	  c_____1_,
X	  c1____1_,
X	  c_1111__ },			/* y */
X
X	{ c_______,
X	  c_______,
X	  c_______,
X	  c111111_,
X	  c____1__,
X	  c___1___,
X	  c__1____,
X	  c_1_____,
X	  c111111_ },			/* z */
X
X	{ c___11__,
X	  c__1____,
X	  c__1____,
X	  c__1____,
X	  c_1_____,
X	  c__1____,
X	  c__1____,
X	  c__1____,
X	  c___11__ },			/* } */
X
X	{ c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___,
X	  c___1___ },			/* | */
X
X	{ c__11___,
X	  c____1__,
X	  c____1__,
X	  c____1__,
X	  c_____1_,
X	  c____1__,
X	  c____1__,
X	  c____1__,
X	  c__11___ },			/* } */
X
X	{ c_11____,
X	  c1__1__1,
X	  c____11_,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______,
X	  c_______ },			/* ~ */
X
X	{ c_1__1__,
X	  c1__1__1,
X	  c__1__1_,
X	  c_1__1__,
X	  c1__1__1,
X	  c__1__1_,
X	  c_1__1__,
X	  c1__1__1,
X	  c__1__1_ }			/* rub-out */
X};
END_OF_FILE
if test 21457 -ne `wc -c <'src/banner.c'`; then
    echo shar: \"'src/banner.c'\" unpacked with wrong size!
fi
# end of 'src/banner.c'
fi
echo shar: End of archive 14 \(of 16\).
cp /dev/null ark14isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 16 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.