[comp.sources.misc] v19i064: dvi - C++ DVI filter for HP LaserJets, Part01/03

parag@hpsdeb.sde.hp.com (Parag Patel) (05/15/91)

Submitted-by: Parag Patel <parag@hpsdeb.sde.hp.com>
Posting-number: Volume 19, Issue 64
Archive-name: dvi/part01

This is my fairly old C++ DVI filter for HP LaserJets.  I'd rewritten it
from C about 4 years ago to learn C++ and to have a fast DVI filter.
This package has been submitted to this year's HP INTEREX contrib tape
and thus is already available with no warantee of any kind.  I hope
it'll prove as useful to people outside HP as it been inside.

Dvi currently compiles right up on HP-UX 7.0, 6.5, and 6.2 (s300s or
s800s), BSD4.3 (Tahoe) on hp300 hardware, and Zortech C++ on MSDOS.  I
use AT&T's C++ 2.0 (cfront) and not G++ on all my Unix boxes.  I do NOT
use C++ streams, but do use stdio.  I have NO idea how much work it'll
take to get it running on other systems or using G++, but it shouldn't
be too hard.

The man-page lists all the pertinent details, but here's some
highlights:

o       fast
o       written in C++
o       supports LaserJetII, LaserJetIID, LaserJet2000, and LaserJet+
o       supports double-sided printing on LJs which can do double-sided
o       supports landscape printing for slides
o       handles big fonts, like, for instance, SliTeX dumps
o       supports JTeX - the Japanese version of TeX which heavily
        exercises the font capabilities of the LJs and of "dvi"
o       allows selecting particular pages and page ranges from the
        command line (OK - it ain't clean or friendly, but it works)
o       supports various \specials for dumping raw PCL files - it is also
        pretty easy to add new specials
o       completely demand driven - not even the font info much less the
        info for a particular character is downloaded unless that character
        is actually going to be printed on the paper
o       does NOT send a hard-reset escape-sequence, which allows one to
        wrap anything around this dvi's output that one wishes
o       has cool (well - entertaining anyway) -v verbose mode
o       actually has a man-page
o       the price is right

The code is somewhat commented.  Feel free to hack away, add new
devices, or optimize any of my screwups.  If you make mods you feel are
useful, or fix some bug, please send me the cdiffs so I can make them
available to others too.

    -- Parag Patel <parag@sde.hp.com>

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is dvi, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 05/09/1991 20:26 UTC by parag@tin
# Source directory /users/parag/tools/tex/dvi
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   3405 -r--r--r-- README
#  10332 -r--r--r-- dvi.1
#   2546 -r--r--r-- Makefile
#   4621 -r--r--r-- main.C
#    654 -r--r--r-- dev.C
#  11294 -r--r--r-- hp2686.C
#   1807 -r--r--r-- hp33440.C
#    606 -r--r--r-- hp2684.C
#   4481 -r--r--r-- util.C
#   4109 -r--r--r-- global.C
#    970 -r--r--r-- stack.C
#   2199 -r--r--r-- dirs.C
#  11617 -r--r--r-- dvi.C
#  12300 -r--r--r-- font.C
#   5861 -r--r--r-- readfont.C
#   7918 -r--r--r-- gffont.C
#  10380 -r--r--r-- pkfont.C
#   3331 -r--r--r-- bitvec.C
#    632 -r--r--r-- hp2684.h
#   1015 -r--r--r-- hp33440.h
#   1357 -r--r--r-- hp2686.h
#   4214 -r--r--r-- defs.h
#   2904 -r--r--r-- extern.h
#    506 -r--r--r-- dirs.h
#   3299 -r--r--r-- font.h
#   3077 -r--r--r-- dev.h
#   1656 -r--r--r-- darray.h
#    258 -r--r--r-- boolean.h
#   1665 -r--r--r-- bitvec.h
#   3296 -r--r--r-- ljdump.c
#
# ============= README ==============
if test -f 'README' -a X"$1" != X"-c"; then
	echo 'x - skipping README (File already exists)'
else
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
$Header: README,v 1.10 91/02/22 16:31:45 hmgr Exp $
X
Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
You can do what you wish with this as long as
X    (1) you do not claim it or any part of it as yours and
X    (2) you do not remove or alter my copyright in any file.
This software is provided "AS IS" without any implied or express warranty
as to its performance or to the results that may be obtained by using this
software.  It is completely unsupported.  You're on your own.
X
X
This is version 1.4 of my TeX DVI filter.  I'd written it about 4 years
ago since, at that time, the only LaserJet DVI filters available to me
were in Pascal and ungodly slow.  Anyway, it's been pointed out to me
that "dvi" still one of the better DVIs around, so I figured it was time
to get off my duff and make it available to the world at large.  Or at
small - I'm not picky.
X
The man-page lists all the pertinent details, but here's some
highlights:
X
o	fast
o	written in C++
o	supports LaserJetII, LaserJetIID, LaserJet2000, and LaserJet+
o	supports double-sided printing on LJs which can do double-sided
o	supports landscape printing for slides
o	handles big fonts, like, for instance, SliTeX dumps
o	supports JTeX - the Japanese version of TeX which heavily
X	exercises the font capabilities of the LJs and of "dvi"
o	allows selecting particular pages and page ranges from the
X	command line (OK - it ain't clean or friendly, but it works)
o	supports various \specials for dumping raw PCL files - it is also
X	pretty easy to add new specials
o	completely demand driven - not even the font info much less the
X	info for a particular character is downloaded unless that character
X	is actually going to be printed on the paper
o	does NOT send a hard-reset escape-sequence, which allows one to
X	wrap anything around this dvi's output that one wishes
o	has cool (well - entertaining anyway) -v verbose mode
o	actually has a man-page
o	the price is right
X
I've also gotten into C++, and I've long since converted my old C DVI
code into C++.  There are still plenty of C-isms in here though.  Still,
the virtual baseclass "Device" should make adding new devices a lot
easier.  (I still need to design some sort of FontFileFormat class,
among other things.)
X
Dvi currently compiles right up on HP-UX 7.0, 6.5, and 6.2 (s300s or
s800s), BSD4.3 (Tahoe) on hp300 hardware, and Zortech C++ on MSDOS.  I
use AT&T's C++ 2.0 (cfront) and not G++ on all my Unix boxes.  I do NOT
use C++ streams, but do use stdio.  I have NO idea how much work it'll
take to get it running on other systems or using G++, but it shouldn't
be too hard.
X
X
Anyway, just type "make" to build a debug version of "dvi".  Then copy
"dvi" and "dvi.1" to whatever names and whatever places you want them.
You will have to define -DMSDOS or -DBSD in the Makefile if you are on
those systems.
X
Use "make ljdump" to build the "ljdump" program.  This is useful for
debugging dvi by converting PCL to a semi-human-readable dump.
X
There's also a machine-dependency in "bitvec.[hC]".  If your "unsigned
long" type is NOT 32 bits, you're hosed, and the code will require some
hacking.  Sorry.
X
The code is somewhat commented.  Feel free to hack away, add new
devices, or optimize any of my screwups.  If you make mods you feel are
useful, or fix some bug, please send me the cdiffs so I can make them
available to others too.
X
X
X
X	-- Parag Patel <parag@sde.hp.com>
SHAR_EOF
chmod 0444 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 3405 -eq "$Wc_c" ||
	echo 'README: original size 3405, current size' "$Wc_c"
fi
# ============= dvi.1 ==============
if test -f 'dvi.1' -a X"$1" != X"-c"; then
	echo 'x - skipping dvi.1 (File already exists)'
else
echo 'x - extracting dvi.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dvi.1' &&
.\" Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
.\" $Header: dvi.1,v 1.29 91/02/22 15:53:38 hmgr Exp $
.TH DVI 1 unsupported
.ad b
.SH NAME
dvi \- TeX DVI filter for various printers
.SH SYNOPSIS
.B dvi
.RB [\- vrlc ]
.RB [\- o device]
.RB [\- 2 h|v|\-]
.RB [\- d fontpath]
.RB [\- i inputpath]
.RB [\- p page-list]
.RB [\- m magnification-value]
[ dvifile ]
.SH DESCRIPTION
This filter converts the DeVice Independent (DVI) output of TeX
into commands for various printers.
The type of printer is selected via a command-line option (below).
The printer commands are put on
.I stdout
to be redirected directly to the printer
or to be printed via the lp spooler using some "raw" option.
.P
By default,
.I dvi
takes no arguments and only prints fatal error messages on
.IR stderr .
The DVI file is assumed to be on
.I stdin
unless specified on the
command line.
.I Dvi
appends the extension
.RB `` .dvi ''
to the file name if necessary.
.PP
Optional arguments:
.TP
.RB \- o device
Specify the name of a printer that
.I dvi
supports.
This basically selects the type of command sequences that
.I dvi
generates.
The default values of other options (such as reverse, landscape, and
double-sided)
may be affected by the choice of printer.
The names of the currently supported printers as well as their
default options are listed in the PRINTER DEPENDENCIES section below.
.TP
.RB \- v
Verbose mode.
Display the page and section number of each page in the DVI file
as it is processed on
.IR stderr .
Also display the name of each raster file as it is dumped and the
name of each font type as it is downloaded to the printer.
.TP
.RB \- r
Switch page reversal off.
For some printers, this option switches page reversal on instead of
switching it off.
This option works as expected with the
.B -p
option below.
.TP
.RB \- l
Generate output in landscape mode instead of portrait mode.
This is especially handy for certain SliTeX slides.
This may switch off landscape mode for certain printers.
.TP
.RB \- c
Normally,
.I dvi
will compare the checksums and designsize
values in the font files and the input file to
ensure that both were built from the same font sources.
This option switches this feature off so that no consistency
checking is performed.
Use at your own risk.
.RI ( Dvi
still prints a warning in 
.B \-v
verbose mode but doesn't croak.)
.TP
.RB \- 2 h|v|\-
This switches on the double-sided printing features of
.IR dvi 
to print odd and even pages on the front and back of a
single sheet of paper.
It is ignored by printers incapable of double-sided printing.
The argument
.B h
specifies horizontal binding so that the output may be bound along
a horizontal spine like a flip-top notebook.
A
.B v
specifies vertical binding like a paperback book.
A
.B \-
forces double-sided printing completely off for any printer.
.TP
.RB \- m mag-value
Use the specified magnification value to resize the final output.
This may be either in units of 1000 as TeX understands magnification,
or it may be specified as a floating 1.000 value.
If there are no fonts available at the desired magnification,
.I dvi
may fail.
.TP
.RB \- d fontpath
Specify the font directory search path where
.I dvi
should look for either the GF or PK format font files.
The directories should have subdirectories for various magnifications.
Overrides the value of the environment var
.B FONTPATH
if it exists.
The separator between the various path is platform dependent.
See the section on PLATFORM DEPENDENCIES for details.
.TP
.RB \- i inputpath
Specify the directory search path for \\special files.
Overrides the value of the environment var
.B DVIINPUT
if it exists.
.TP
\-\fBp\fRpage[.section[=page2[.section2]]][,\ .\ .\ .\ ]
Print only the specified pages in the optional sections.
Both the pages and sections may be specified as ranges.
(\-\fBp\fI3.2=5.3\fR
is the same as
\-\fBp\fI3.2,4.2,5.2,3.3,4.3,5.3\fR)
The ending page/section number in a range may be a
.RB `` \(** ''
to signify the last page or section.
(\-\fBp\fI3.2=\(**\fR
means
\-\fBp\fI3.2,4.2,5.2,.\ .\ .\fR
and
\-\fBp\fI2.3=\(**.\(**\fR
means
\-\fBp\fI2.3,3.3,.\ .\ .,2.4,3.4,.\ .\ .\fR)
(The ``='' character is used instead of ``-'' so that negative
numbers may be entered for page/sections.)
.PP
The format of the DVI file puts some peculiar restrictions on
page and section numbering:
.PP
The page numbers for the
.B \-p
option are the numbers printed on each page of the output.
(For the contents pages, page
.B i
is numbered
.BR 1 ,
.B ii
is
.BR 2 ,
etc.)
Unfortunately, there can be more than one page
.I 1 
(or of other pages)
in the file.
The section number is used to disambiguate pages.
.PP
The section number does not correspond with any real section
number in the output.
Here, the section is each part of the file that is numbered in sequence.
When the page numbering changes from, say, 3 back to 1, this is
considered to be the start of another section.
By default, if no section number is specified, the last section is
assumed to be the one desired, which is usually correct for LaTeX output
and usually wrong for TeX output.  (Oh well.)
Thus
.BI \-p 3.3
is the same as
.BI \-p 3
if there are only 3 sections in the file.
.PP
The section numbers always match those displayed by the
.B \-v
command, so run
.I dvi
with
.B \-v
piped to /dev/null to get the section and page numbers, then run
.I dvi
again to the printer to select specific pages and sections.
.SS Fonts
.I Dvi
now handles both the GF and the PK font formats.
It searches along a default directory path for a printer
to find the necessary fonts.
The environment variable
.B FONTPATH
or the
.B \-d
option
may be used to override this if desired.
The default FONTPATHs are listed in the PRINTER DEPENDENCIES section below.
.PP
The GF format is part of the normal output from the Metafont program.
The PK format is a packed version of the GF file and is
is usually about half its size.
However, the GF file is slightly faster to read because
the entire file does not have to be scanned to find the
character data for all the characters.
.SS Special commands
.I Dvi
supports the \\special commands generated via TeX.
The \\special commands are basically strings of bytes imbeddeded
within TeX output.
(See your TeX or LaTeX manual for more details.)
.I Dvi
uses the \\special command to merge printer-specific
commands into the final output.
.PP
A \\special command string may look like one of the following:
.nf
X
X		  \\special{escapeseq<space>string}
X		  \\special{rawstring<space>string}
X		  \\special{rasterfile<space>filename}
X		  \\special{filename}
X
.fi
The keyword
.I escapeseq
specifies that the
.I string
is to be taken literally and sent directly to the output.
The
.I string
may contain special escapes such as
.B \\\\e
for the ESCAPE character,
.B \\\\?
for the DELETE character,
and
.B \\\\^<alpha>
for an arbitrary CONTROL character in addition to ALL
the normal C character escapes.
The forms
.B \\\\0o<octal> \\\\0d<decimal> \\\\0b<binary> \\\\0x<hexadecimal>
are supported for describing a character as a number.
Also, a grave-accent
.B `
character may be used instead of a backslash
.B \\\\
character in case you have a screwy version of TeX.
Naturally, 
.B ``
generates a single
.B `
just as 
.B \\\\\\\\
generates a single
.B \\\\
character.
.PP
The
.I rawstring
special dumps the
.I string
as raw characters with none of the special
processing that
.I escapeseq
does.
.PP
The keyword
.I rasterfile
specifies that the contents of
.I filename
are directly sent into the output without any modifications.
This allows merging in pictures generated from other systems
directly into TeX output.
.PP
The last form without a keyword is only included
for backward-compatibility with older
.I dvi
programs and should not be used.
It is the same as
.IR rasterfile .
.PP
The rasterfiles should only have cursor-relative positioning
commands since TeX should already have decided where
to place the image.
.I Dvi
always restores the cursor position after every \\special command
so that the TeX output should never screwed be up - much.
.PP
The environment var
.B DVIINPUT
or the
.B \-i
option
may be used to provide a colon-separated directory
search path for
.IR filename .
This is handy when a document with a picture has to be included
within another document in a completely different directory.
.PP
Other commands may be supported in the future.
.SH PLATFORM DEPENDENCIES
The separator between the component parts
in either the FONTPATH environment variable
or the optional fontpath specification is platform dependent.
Default separator for UNIX is the colon character,
for MSDOS it is the semicolon character.
.SH PRINTER DEPENDENCIES
.TP
.B HP2686 LaserJet+ ljet laser lj+
HP LaserJet+ \-
The old plain-vanilla HP LaserJet is NOT
suported as it does not support downloadable fonts.
The LJ+ Does support 8-bit fonts, and may support JTeX.
.br
Default options: page-reversal on, portrait
.br
Default FONTPATH for UNIX:
/usr/lib/tex/fontbits/laser:/usr/lib/tex/fnt:/usr/local/tex/fontbits/laser
.br
Default FONTPATH for MSDOS:
/usr/lib/tex/fontbits/laser;/usr/lib/tex/fnt;/usr/local/tex/fontbits/laser
.TP
.B HP33440 LaserJetII ljII lj2 laser2 laserII default
HP LaserJetII \-
This is the default printer if one is not specified on the command line.
Just like a LaserJet+, except pages are not automatically reversed, and
it can handle more fonts per page.
Definitely supports both JTeX and 8-bit fonts.
.br
Default options: page-reversal off, portrait
.br
Default FONTPATH: <same as LJ+>
.TP
.B HP33447 LaserJetIID ljIId lj2d laser2D laserIID
HP LaserJetIID \-
Just like a LaserJetII except that it can also print double-sided.
.br
Default options: page-reversal off, portrait, double-sided vertical binding
.br
Default FONTPATH: <same as LJ+>
.TP
.B HP2684 JumboJet lj2000 laser2000 lj2k
HP LaserJet 2000 \-
A much bigger and much faster LaserJetIID with a lot more RAM.
It can handle a lot more downloaded fonts and fonts per page too.
.br
Default options: page-reversal off, portrait, double-sided vertical binding
.br
Default FONTPATH: <same as LJ+>
.SH FILES
.nf
/usr/lib/tex/fontbits/<printer>/<magdirs>/<PK fonts>
/usr/lib/tex/fnt/<magdirs>/<GF fonts>
/usr/local/tex/fontbits/<printer>/<magdirs>/<PK fonts>
.fi
.SH AUTHOR
Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
SHAR_EOF
chmod 0444 dvi.1 ||
echo 'restore of dvi.1 failed'
Wc_c="`wc -c < 'dvi.1'`"
test 10332 -eq "$Wc_c" ||
	echo 'dvi.1: original size 10332, current size' "$Wc_c"
fi
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile (File already exists)'
else
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
# Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
# $Header: Makefile,v 1.22 91/05/09 14:25:22 hmgr Exp $
X
CXX = CC
.SUFFIXES: .C
.C.o:
X	$(CXX) $(CFLAGS) -c $<
X
# other system-dependent options - use only one of the -D<sys> macros:
#CFLAGS = -O -DBSD -DMSDOS
CFLAGS = -g
LIBS = -lm
X
SRCS = README dvi.1 Makefile main.C dev.C hp2686.C hp33440.C hp2684.C \
X	util.C global.C stack.C dirs.C dvi.C font.C readfont.C gffont.C \
X	pkfont.C bitvec.C hp2684.h hp33440.h hp2686.h defs.h extern.h \
X	dirs.h font.h dev.h darray.h boolean.h bitvec.h \
X	ljdump.c
X
OBJS = main.o dev.o hp2686.o hp33440.o hp2684.o util.o global.o stack.o \
X	dirs.o dvi.o font.o readfont.o gffont.o pkfont.o bitvec.o
X
dvi : $(OBJS)
X	$(CXX) $(CFLAGS) -o dvi $(OBJS) $(LIBS)
X
ljdump : ljdump.c
X	$(CC) $(CFLAGS) -o ljdump ljdump.c
X
tar: $(SRCS)
X	tar -cvf - $(SRCS) | compress >dvi.tar.Z 
X
shar: $(SRCS)
X	shar -ac -ndvi -l50 -odvi-shar $(SRCS)
X
clean:
X	rm -f dvi *.o ljdump dvi.tar.Z* dvi.shar
X
files:
X	@echo $(SRCS)
X
msdos-files:
X	ln bitvec.C bitvec.cpp
X	ln dev.C dev.cpp
X	ln dirs.C dirs.cpp
X	ln dvi.C dvi.cpp
X	ln font.C font.cpp
X	ln gffont.C gffont.cpp
X	ln global.C global.cpp
X	ln hp2684.C hp2684.cpp
X	ln hp2686.C hp2686.cpp
X	ln hp33440.C hp33440.cpp
X	ln main.C main.cpp
X	ln pkfont.C pkfont.cpp
X	ln readfont.C readfont.cpp
X	ln stack.C stack.cpp
X	ln util.C util.cpp
X
main.o : main.C defs.h extern.h dirs.h font.h dev.h darray.h boolean.h
dev.o : dev.C defs.h extern.h dirs.h font.h dev.h darray.h boolean.h
hp2686.o : hp2686.C hp2686.h defs.h extern.h dirs.h font.h dev.h \
X		darray.h boolean.h
hp33440.o : hp33440.C hp33440.h hp2686.h defs.h extern.h dirs.h font.h \
X		dev.h darray.h boolean.h
hp2684.o : hp2684.C hp2684.h hp33440.h hp2686.h defs.h extern.h dirs.h \
X		font.h dev.h darray.h boolean.h
util.o : util.C defs.h extern.h dirs.h font.h dev.h darray.h boolean.h
global.o : global.C hp2684.h hp33440.h hp2686.h defs.h extern.h dirs.h \
X		font.h dev.h darray.h boolean.h
stack.o : stack.C defs.h extern.h dirs.h font.h dev.h darray.h boolean.h
dirs.o : dirs.C dirs.h defs.h extern.h font.h dev.h darray.h boolean.h
dvi.o : dvi.C defs.h extern.h dirs.h font.h dev.h darray.h boolean.h
font.o : font.C defs.h extern.h dirs.h font.h dev.h bitvec.h \
X		darray.h boolean.h
readfont.o : readfont.C defs.h extern.h dirs.h font.h dev.h \
X		darray.h boolean.h
gffont.o : gffont.C defs.h extern.h dirs.h font.h dev.h bitvec.h \
X		darray.h boolean.h
pkfont.o : pkfont.C defs.h extern.h dirs.h font.h dev.h bitvec.h \
X		darray.h boolean.h
bitvec.o : bitvec.C bitvec.h boolean.h
SHAR_EOF
chmod 0444 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 2546 -eq "$Wc_c" ||
	echo 'Makefile: original size 2546, current size' "$Wc_c"
fi
# ============= main.C ==============
if test -f 'main.C' -a X"$1" != X"-c"; then
	echo 'x - skipping main.C (File already exists)'
else
echo 'x - extracting main.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'main.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: main.C,v 1.31 91/04/02 17:50:33 hmgr Exp $";
X
// TeX DVI filter main() - just parses arguments and calls functions
//
// by Parag Patel
X
#include "defs.h"
X
static char *const whatid = "@(#) dvi 1.6 (02 April 1991)";
X
static void say_hello()
{
X    // hello message like (but unlike) TeX - the following mess should
X    // strip out the revision number out of the build ID string "whatid"
X    char *s = strchr(whatid, ' ');
X    while (*s == ' ')
X	s++;
X    char *t = s;
X    while (*t != ' ' && *t != '$' && *t != '\0')
X	t++;
X    *t = '\0';
X    mesg("TeX DVI filter version %s for ", s);
}
X
static long strtonum(char *s, char **ptr)
{
X    long ret = 0;
X    int neg = 0;
X
X    while (isspace(*s))
X	s++;
X    if (*s == '-')
X    {
X	neg = 1;
X	s++;
X    }
X    while (*s == '0')
X	s++;
X    while (isdigit(*s))
X	ret = ret * 10 + *s++ - '0';
X    if (ptr != NULL)
X	*ptr = s;
X    return neg ? -ret : ret;
}
X
X
extern char *optarg;
extern int optind;
X
main(int argc, char *argv[])
{
X    int op;
X    char *next, *str;
X    Pagespec pages;
#ifdef	__ZTC__
X    // there must be a function for this somewhere!
X    // we do not want <CR> prepended to an <NL> on a putchar('\n')
X    stdout->_flag &= ~_IOTRAN;
#endif
X    while ((op = getopt(argc, argv, "vcd:i:rp:o:l2:m:=:")) != EOF)
X	switch (op)
X	{
X	Case '=': 		// debug mode - undocumented!!!
X	    debuglevel = atoi(optarg);
X
X	Case 'v': 		// verbose mode
X	    verbose = TRUE;
X
X	Case 'c': 		// no checksum checking
X	    dochecksum = FALSE;
X
X	Case 'l': 		// landscape (sideways) mode
X	    landscape = TRUE;
X
X	Case 'r': 		// do not reverse pages
X	    reverse = FALSE;
X
X	Case '2': 		// double-sided output
X	    duparg = TRUE;
X	    if (*optarg == '-' || *optarg == '!')
X		duplexh = duplexv = FALSE;
X	    else if (*optarg == 'h' || *optarg == 'H')
X		duplexh = TRUE, duplexv = FALSE;
X	    else
X		duplexh = FALSE, duplexv = TRUE;
X
X	Case 'o': 		// get device type for output
X	    devname = optarg;
X
X	Case 'd': 		// set font directory search path
X	    fontpath = optarg;
X
X	Case 'i': 		// set special file search path
X	    dviinput = optarg;
X
X	Case 'm':		// user-specified magnification value
X	    if (strchr(optarg, '.') != NULL)
X		usermag = (long)(atof(optarg) * 1000.0);
X	    else
X		usermag = atol(optarg);
X
X	Case 'p': 		// specific pages only
X	    // format: -p page[.num[-endpage[.endsect]]][,more]
X	    // the following code is really really ugly...
X	    for (str = optarg; str != NULL && *str != '\0'; str = next)
X	    {
X		// setup for the next page spec in the list
X		next = strchr(str, ',');
X		if (next != NULL)
X		    *next++ = '\0';
X
X		// get the next entry
X		char *ptr = str;// generic string pointer
X		long p = 0;	// page to print
X		long s = MAXLONG;	// section of page
X
X		// get the first number
X		p = strtonum(ptr, &ptr);
X
X		// empty spec - ignore it
X		if (ptr == str)
X		    continue;
X
X		// a '*' here doesn't mean anything so skip it
X		if (*ptr == '*')
X		    ptr++;
X
X		// do we have a section spec?
X		if (*ptr == '.')
X		{
X		    s = strtonum(ptr + 1, &ptr);
X		    if (*ptr == '*')	// ignore '*'
X			ptr++;
X		}
X
X		long pe = p;	// ending page for range
X		long se = s;	// ending section for range
X
X		// do we have a range?
X		if (*ptr == '=')
X		{
X		    // get ending page
X		    pe = strtonum(ptr + 1, &ptr);
X		    if (*ptr == '*')
X		    {
X			// this means "to the end"
X			pe = MAXLONG;
X			ptr++;
X		    }
X
X		    // ending section?
X		    if (*ptr == '.')
X		    {
X			se = strtonum(ptr + 1, &ptr);
X			if (*ptr == '*')    // to the end
X			    se = MAXLONG;
X		    }
X		}
X
X		// setup this page specifier
X		long pg = pages.size();
X		pages[pg].page = p;
X		pages[pg].section = s;
X		pages[pg].endpage = pe;
X		pages[pg].endsection = se;
X	    }
X
X	Default: 
X	    fprintf(stderr,
X		    "Usage:\t%s [-vrlc] [-d fontpath] [-i inputpath] [-2 -|v|h]\n\t[-o device] [-p page[.sect[=page2[.sect2]]][, ...]] [file]\n",
X		    argv[0]);
X	    exit(11);
X	}
X
X    // initialize
X    say_hello();
X    init_globals();
X    mesg(NULL);
X
X    // no arguments? assume stdin is set to a DVI file
X    if (optind >= argc)
X    {
X	dodvi(stdin, pages);
X	fini_globals();
X	return 0;
X    }
X
X    // else the first file argument
X    // - ignore other args since this code is currently not re-entrant
X    FILE *fp = fopen(argv[optind], F_READ);
X    if (fp == NULL)
X    {
X	char *name = new char[strlen(argv[optind]) + 10];
X	strcpy(name, argv[optind]);
X	strcat(name, ".dvi");
X	if ((fp = fopen(name, F_READ)) == NULL)
X	    quit("Cannot open %s for reading", argv[optind]);
X    }
X    dodvi(fp, pages);
X    fclose(fp);
X    fini_globals();
X    return 0;
}
SHAR_EOF
chmod 0444 main.C ||
echo 'restore of main.C failed'
Wc_c="`wc -c < 'main.C'`"
test 4621 -eq "$Wc_c" ||
	echo 'main.C: original size 4621, current size' "$Wc_c"
fi
# ============= dev.C ==============
if test -f 'dev.C' -a X"$1" != X"-c"; then
	echo 'x - skipping dev.C (File already exists)'
else
echo 'x - extracting dev.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dev.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
X
// Base-class device stuff.
//
// by Parag Patel
X
#include "defs.h"
X
X
Device::Device(int maxf, int maxc, int maxpg, int maxld, int res,
X		int ho, int vo, int fhmn, int fhmx, int fvmn, int fvmx,
X		int fwd, int fhg, char *deffp) :
X	maxfonts(maxf), maxchars(maxc), maxonpage(maxpg), maxloaded(maxld),
X	resolution(res), hoff(ho), voff(vo),
X	fhmin(fhmn), fhmax(fhmx), fvmin(fvmn), fvmax(fvmx),
X	fwidth(fwd), fheight(fhg), deffontpath(deffp)
{
}
X
Device::~Device()
{
}
X
/*****
void Device::color(long red, long green, long blue)
{
X    // for future support for devices like PaintJets, etc.
}
*****/
SHAR_EOF
chmod 0444 dev.C ||
echo 'restore of dev.C failed'
Wc_c="`wc -c < 'dev.C'`"
test 654 -eq "$Wc_c" ||
	echo 'dev.C: original size 654, current size' "$Wc_c"
fi
# ============= hp2686.C ==============
if test -f 'hp2686.C' -a X"$1" != X"-c"; then
	echo 'x - skipping hp2686.C (File already exists)'
else
echo 'x - extracting hp2686.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'hp2686.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: hp2686.C,v 1.20 91/02/22 15:55:21 hmgr Exp $";
X
// HP2686 LaserJet+ and LaserJetII device-specific functions.
// The various Reference Manuals should be consulted for more
// information on the various escape-sequences.
//
// by Parag Patel
X
#include "defs.h"
#include "hp2686.h"
X
X
static int hoffset = HP2686_HOFFSET;
static int voffset = HP2686_VOFFSET;
X
X
// put a 16-bit word on the output as two bytes
// 
inline void put16(long n)
{
X    putchar((char)((n >> 8) & 0xFF));
X    putchar((char)(n & 0xFF));
}
X
static void initlj()
{
X    if (landscape)
X    {
X	fputs("\033&l1O", stdout);
X	hoffset -= 60;
X	voffset -= 10;
X    }
X    else
X	fputs("\033&l0O", stdout);
X    fputs("\033&l0E", stdout);
}
X
HP2686::HP2686(int maxf, int maxc, int maxpg, int maxld, int res,
X		int ho, int vo, int fhmn, int fhmx, int fvmn, int fvmx,
X		int fwd, int fhg, char *deffp) :
X    Device(maxf, maxc, maxpg, maxld, res, ho, vo,
X	    fhmn, fhmx, fvmn, fvmx, fwd, fhg, deffp)
{
X    initlj();
}
X
// initialize the LaserJet
// 
HP2686::HP2686() :
X    Device(257, 256, 16, 32, 300, hoffset, voffset,
X	    -128, 127, -128, 127, 128, 128, HP2686_FPATH)
{
X    initlj();
}
X
// clean up after dumping a DVI file
// 
HP2686::~HP2686()
{
X    fputs("\033&l0O", stdout);
}
X
// convert a character number to something that the device can deal with
// for a LaserJet
//
const char *HP2686::char2dev(int ch, int &len)
{
X    static char buf[20];
X    if ((ch >= 32 && ch <= 127) || ch >= 160)
X	sprintf(buf, "%c", ch);
X    else
X	sprintf(buf, "\033&p1X%c", ch);
X    len = strlen(buf);
X    if (ch == 0)
X	len++;
X    return buf;
}
X
// convert a scaled point to a device pixel coordinate
//
long HP2686::sp2dev(double sp)
{
X    return long(sp / 72.27 * 300.0 / double(1 << 16L) + 0.5);
}
X
// convert a device pixel coordinate to a scaled point
//
double HP2686::dev2sp(long pix)
{
X    return double(pix) / 300.0 * 72.27 * double(1 << 16L);
}
X
X
// download a big character to the LaserJet in graphics mode
// 
void HP2686::bigchar(font &, fontchar &g, int)
{
X    long width = g.maxm - g.minm + 1;
X    long height = g.maxn - g.minn + 1;
X    int res = 1;		// 1==300dpi 2==150dpi
X
X    makecurrent();
X    push();			// save current location
X
X    // move (relative) up - printf() may not handle the sign properly
X    // with the "%+ld" specification, so we do it ourselves
X    long rel = -g.maxn;
X    if (rel < 0)
X	printf("\033*p%ldY", rel);
X    else
X	printf("\033*p+%ldY", rel);
X
X    // move (relative) right
X    rel = landscape ? g.maxm : g.minm;
X    if (rel < 0)
X	printf("\033*p%ldX", rel);
X    else
X	printf("\033*p+%ldX", rel);
X
X    if (width > 300 || height > 300)
X    {
X	// use 150 dots per inch for REALLY big characters
X	res = 2;
X	fputs("\033*t150R", stdout);
X    }
X    else
X	fputs("\033*t300R", stdout);
X    fputs("\033*r1A", stdout);	// start graphics mode
X
X    if (landscape)
X	for (register long j = g.maxm - g.minm; j >= 0; j -= res)
X	{
X	    int b = 0;
X	    int bp = 0x80;
X	    register long count = (height + 7) >> (2 + res);
X
X	    printf("\033*b%ldW", count);
X
X	    for (register long i = g.maxn - g.minn; i >= 0; i -= res)
X	    {
X		if (bp == 0)
X		{
X		    putchar(b);
X		    bp = 0x80;
X		    b = 0;
X		    count--;
X		}
X		if (res == 1)	// 300 dpi
X		{
X		    if (fontbits[i]->isin(j))
X			b |= bp;
X		}
X		else		// 150 dpi
X		{
X		    // use the "or" of the 4 pixels at this location
X		    if (fontbits[i]->isin(j)
X			    || fontbits[i - 1]->isin(j)
X			    || fontbits[i]->isin(j + 1)
X			    || fontbits[i - 1]->isin(j + 1))
X			b |= bp;
X		}
X		bp >>= 1;
X	    }
X
X	    putchar(b);
X	    if (count != 1 && count != 0)
X		quit("Code for downloading bigchars is hosed: count=%ld",
X			count);
X	}
X    else
X	// we use "res" as an incrementer for 150 or 300 dpi
X	for (register long i = g.maxn - g.minn; i >= 0; i -= res)
X	{
X	    int b = 0;
X	    int bp = 0x80;
X	    register long count = (width + 7) >> (2 + res);
X
X	    printf("\033*b%ldW", count);
X
X	    for (register long j = 0; j <= g.maxm - g.minm; j += res)
X	    {
X		if (bp == 0)
X		{
X		    putchar(b);
X		    bp = 0x80;
X		    b = 0;
X		    count--;
X		}
X		if (res == 1)// 300 dpi
X		{
X		    if (fontbits[i]->isin(j))
X			b |= bp;
X		}
X		else		// 150 dpi
X		{
X		    // use the "or" of the 4 pixels at this location
X		    if (fontbits[i]->isin(j)
X			    || fontbits[i - 1]->isin(j)
X			    || fontbits[i]->isin(j + 1)
X			    || fontbits[i - 1]->isin(j + 1))
X			b |= bp;
X		}
X		bp >>= 1;
X	    }
X
X	    putchar(b);
X	    if (count != 1 && count != 0)
X		quit("Code for downloading bigchars is hosed: count=%ld",
X			count);
X	}
X
X    fputs("\033*rB", stdout);	// end graphics mode
X    pop();			// restore saved location
}
X
X
// download a character for a particular font
// 
void HP2686::downchar(font &f, fontchar &g, int ch)
{
X    // describe the character and its font to the LaserJet
X    printf("\033*c%ldd%dE", f.num, ch);
X    downljchar(f, g, ch);
}
X
// this sets up this character in the LaserJet memory so that
// it can be typeset later
// - assumes that the font has already been downloaded to the printer
// 
void HP2686::downljchar(font &, fontchar &g, int)
{
X    long width = g.maxm - g.minm + 1;
X    long height = g.maxn - g.minn + 1;
X
X    // number of bytes for a bit-map of the character
X    long count;
X    if (landscape)
X    {
X	count = width * ((height + 7) >> 3);
X	if (count < 1)
X	    count = 1;
X    }
X    else
X	count = height * ((width + 7) >> 3);
X
X    printf("\033(s%ldW", count + 16);
X    putchar(4);			// these 4 bytes are magic -
X    putchar(0);			// they must be here for some
X    putchar(14);		// unknown reason...
X    putchar(1);
X
X    if (landscape)
X    {
X	putchar(1);		// landscape mode
X	putchar(0);		// <magic>
X	put16(-g.maxn);		// # pixels above the baseline
X	put16(g.maxm);		// # pixels to the right of origin
X	put16(height);		// width of char in pixels
X	put16(width);		// height in pixels
X    }
X    else
X    {
X	put16(0);		// portrait mode | magic
X	put16(g.minm);		// # pixels to the left of origin
X	put16(g.maxn);		// # pixels above the baseline
X	put16(width);		// width of char in pixels
X	put16(height);		// height in pixels
X    }
X    put16(g.dx >> 14);		// delta-x in pixels * 4
X
X    // download the bitmap for this character one byte at a time - we
X    // also decrement the "count" var to make sure that we send down
X    // exactly the correct number of bytes to the LaserJet
X    // (OK OK - there are more effecient ways to do this, but this works
X    // and is simple to code.  It'll do for now.)
X
X    register long n;
X    register long m;
X    if (landscape)
X	for (m = g.maxm - g.minm; m >= 0; m--)
X	{
X	    // we will build the byte "b" to download - "bp" is the bit
X	    // pointer used to set the next bit in the current byte - it
X	    // is shifted by one each time around the inner loop
X	    int b = 0;
X	    int bp = 0x80;
X
X	    for (n = g.maxn - g.minn; n >= 0; n--)
X	    {
X		if (bp == 0)
X		{
X		    // we have put the last bit that this byte can hold
X		    // into "b" - download it, then reset the bit pointer
X		    putchar(b);
X		    bp = 0x80;
X		    b = 0;
X		    count--;
X		}
X
X		// set this bit in the byte if the current bit is set in
X		// the bitmap - then shift bp to point to the next bit
X		if (fontbits[n]->isin(m))
X		    b |= bp;
X		bp >>= 1;
X	    }
X
X	    // put the remaining byte out - note that the last byte will
X	    // always be downloaded here and not in the previous loop
X	    putchar(b);
X	    count--;
X	}
X    else
X	for (n = g.maxn - g.minn; n >= 0; n--)
X	{
X	    // we will build the byte "b" to download - "bp" is the bit
X	    // pointer used to set the next bit in the current byte - it
X	    // is shifted by one each time around the inner loop
X	    int b = 0;
X	    int bp = 0x80;
X
X	    for (m = 0; m <= g.maxm - g.minm; m++)
X	    {
X		if (bp == 0)
X		{
X		    // we have put the last bit that this byte can hold
X		    // into "b" - download it, then reset the bit pointer
X		    putchar(b);
X		    bp = 0x80;
X		    b = 0;
X		    count--;
X		}
X
X		// set this bit in the byte if the current bit is set in
X		// the bitmap - then shift bp to point to the next bit
X		if (fontbits[n]->isin(m))
X		    b |= bp;
X		bp >>= 1;
X	    }
X
X	    // put the remaining byte out - note that the last byte will
X	    // always be downloaded here and not in the previous loop
X	    putchar(b);
X	    count--;
X	}
X
X    // see if we have a bug in the above code
X    if (count != 0)
X	quit("Code for downloading chars is hosed: count=%ld", count);
}
X
X
// flush out (print) the current page in the LaserJet - get ready to
// print a new page
// 
void HP2686::newpage(boolean odd, boolean first)
{
X    if (first)
X	return;
X    odd = FALSE;
X    putchar('\f');
}
X
X
// move the LaserJet cursor to the specified (h,v) spot on the paper
// - add the appropriate "fuhj" offsets to the coordinates
// 
void HP2686::movehv(long h, long v)
{
X    printf("\033*p%ldx%ldY", h + hoffset, v + voffset);
}
X
X
// just move along the horizontal to the specified pixel
// 
void HP2686::moveh(long h)
{
X    printf("\033*p%ldX", h + hoffset);
}
X
X
// vertical move
// 
void HP2686::movev(long v)
{
X    printf("\033*p%ldY", v + voffset);
}
X
X
// push the current spot - fortunately the LaserJet already does this
// or we would save the current location in our own stack
// 
void HP2686::push()
{
X    fputs("\033&f0S", stdout);
}
X
X
// pop the current location and restore the last one
// 
void HP2686::pop()
{
X    fputs("\033&f1S", stdout);
}
X
X
// delete the specified font from the LaserJet's memory
// 
void HP2686::delfont(font &f)
{
X    printf("\033*c%ldd2F", f.num);
}
X
X
// download this font to the LaserJet's memory - this just defines
// the font but doesn't actually download any characters into it yet
// 
void HP2686::newfont(font &f)
{
X    long width = f.maxm - f.minm + 1;
X    if (width < 1)
X	width = 1;
X    long height = f.maxn - f.minn + 1;
X    if (height < 1)
X	height = 1;
X
X    printf("\033*c%ldD\033)s26W", f.num);    // font number
X    put16(26);			// length of the this+rest in bytes
X    put16(1);			// 0 <magic>  |  font-type
X    put16(0);			// <magic>
X    put16(f.maxn);		// baseline position
X    put16(width);		// cell width
X    put16(height);		// cell height
X    putchar(landscape ? 1 : 0);	// orientation
X    putchar(1);			// 		fixed/proportional
X    putchar(1);			// symbol set
X    putchar(21);		// 		symbol set II
X    put16(width << 2);		// pitch (default HMI)
X    put16(height << 2);		// height
X    put16(0);			// 0 <magic>
X    put16(0);			// 0 <magic> | style
X    put16(0);			// stroke width | typeface
}
X
X
// make this font the current font in the LaserJet - we are about to
// typeset (print) some characters from it
// 
void HP2686::usefont(font &f)
{
X    printf("\033(%ldX", f.num);
}
X
X
// typeset (print) a rule (box) of the specified length and width at
// the current cursor location
// 
void HP2686::rule(double A, double B)
{
X    long aa = sp2dev(A);
X    long bb = sp2dev(B);
X
X    debug(5, "rule: a=%f b=%f  H=%f V=%f  aa=%ld bb=%ld", A, B, H, V, aa, bb);
X
X    // now typeset the rule - again the LaserJet makes this easy with
X    // the fill area command - unfortunately the origin must be at the
X    // top-left corner and not the bottom-left like a normal character
X    movedown(-A);
X    makecurrent();
X    printf("\033*c%lda%ldb0P", bb <= 0 ? 1 : bb, aa <= 0 ? 1 : aa);
X    movedown(A);
}
SHAR_EOF
chmod 0444 hp2686.C ||
echo 'restore of hp2686.C failed'
Wc_c="`wc -c < 'hp2686.C'`"
test 11294 -eq "$Wc_c" ||
	echo 'hp2686.C: original size 11294, current size' "$Wc_c"
fi
# ============= hp33440.C ==============
if test -f 'hp33440.C' -a X"$1" != X"-c"; then
	echo 'x - skipping hp33440.C (File already exists)'
else
echo 'x - extracting hp33440.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'hp33440.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: hp33440.C,v 1.13 91/02/22 15:56:21 hmgr Exp $
X
// LaserJetII series device-specific functions.
// The LaserJetII Reference Manual should be consulted for more
// information on various the escape-sequences.
//
// by Parag Patel
X
#include "defs.h"
#include "hp2686.h"
#include "hp33440.h"
X
X
// LaserJetII:
X
// initialize the LaserJet II
HP33440::HP33440() :
X	HP2686(257, 256, 32, 32, 300, HP2686_HOFFSET, HP2686_VOFFSET,
X			-128, 127, -128, 127, 128, 128, HP2686_FPATH)
{
}
X
// LaserJetIID:
X
// initialize the LaserJet IID using explicit args - handle 2-sided
//
HP33447::HP33447(int maxf, int maxc, int maxpg, int maxld, int res,
X		int ho, int vo, int fhmn, int fhmx, int fvmn,
X		int fvmx, int fwd, int fhg, char *deffp) :
X    HP33440(maxf, maxc, maxpg, maxld, res, ho, vo,
X	fhmn, fhmx, fvmn, fvmx, fwd, fhg, deffp)
{
X    if (duplexv)
X	fputs("\033&l1S", stdout);
X    else if (duplexh)
X	fputs("\033&l2S", stdout);
}
X
// initialize the LaserJet IID - use defaults for LJII & handled 2-sided
//
HP33447::HP33447() : HP33440()
{
X    if (duplexv)
X	fputs("\033&l1S", stdout);
X    else if (duplexh)
X	fputs("\033&l2S", stdout);
}
X
// back to normal mode - switch off 2-sided
//
HP33447::~HP33447()
{
X    if (duplexv || duplexh)
X	fputs("\033&l0S", stdout);
}
X
// flush out (print) the current page in the LJIID - get ready to
// print a new page
// 
void HP33447::newpage(boolean odd, boolean first)
{
X    // print even pages on "front" for reverse output, else odd
X    debug(2, "newpage: odd=%d reverse=%d odd^reverse=%d first=%d",
X	    odd, reverse, odd ^ reverse, first);
X    if (duplexv || duplexh)
X    {
X	if (odd ^ reverse)
X	    fputs("\033&a1G", stdout);
X	else
X	    fputs("\033&a2G", stdout);
X    }
X    else if (!first)
X	putchar('\f');
}
SHAR_EOF
chmod 0444 hp33440.C ||
echo 'restore of hp33440.C failed'
Wc_c="`wc -c < 'hp33440.C'`"
test 1807 -eq "$Wc_c" ||
	echo 'hp33440.C: original size 1807, current size' "$Wc_c"
fi
# ============= hp2684.C ==============
if test -f 'hp2684.C' -a X"$1" != X"-c"; then
	echo 'x - skipping hp2684.C (File already exists)'
else
echo 'x - extracting hp2684.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'hp2684.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: hp2684.C,v 1.11 91/02/22 15:56:31 hmgr Exp $
X
// HP2684 LaserJet 2000 device-specific functions.
// The LaserJet 2000 Reference Manual should be consulted for more
// information on various the escape-sequences.
//
// by Parag Patel
X
#include "defs.h"
#include "hp2686.h"
#include "hp33440.h"
#include "hp2684.h"
X
X
// similar to the LJIID but we can download more and larger fonts
//
HP2684::HP2684() :
X    HP33447(257, 256, 64, 64, 300, HP2686_HOFFSET, HP2686_VOFFSET,
X		-16384, 16384, -16384, 16384, 16384, 16384, HP2686_FPATH)
{
}
SHAR_EOF
chmod 0444 hp2684.C ||
echo 'restore of hp2684.C failed'
Wc_c="`wc -c < 'hp2684.C'`"
test 606 -eq "$Wc_c" ||
	echo 'hp2684.C: original size 606, current size' "$Wc_c"
fi
# ============= util.C ==============
if test -f 'util.C' -a X"$1" != X"-c"; then
	echo 'x - skipping util.C (File already exists)'
else
echo 'x - extracting util.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'util.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: util.C,v 1.14 91/02/22 15:56:43 hmgr Exp $";
X
// various utility functions
//
// by Parag Patel
X
#include "defs.h"
#include <stdarg.h>
X
X
// get an unsigned value that is "num" bytes long from the file
// - the "switch" speeds up the 1|2|3|4 byte reads
//
long getuval(int num, FILE *fp)
{
X    register long val = 0;
X    register unsigned long b;
X
X    b = getc(fp);
X    switch (num)
X    {
X    case 4:
X	val = b << 24;
X	b = getc(fp);
X    case 3:
X	val |= b << 16;
X	b = getc(fp);
X    case 2:
X	val |= b << 8;
X	b = getc(fp);
X    case 1:
X	val |= b;
X	break;
X
X    default:
X	quit("dvi bug: getuval called with count of %d\n", num);
X    }
X    return val;
}
X
X
// get a signed twos-complement value of "num" bytes from file
//
long getsval(int num, FILE *fp)
{
X    register long val;
X    register unsigned long b;
X    register char c;
X
X    // this sets "val" to the right sign
X    c = getc(fp);
X
X    // this shifts the 8-bit value to the right part of the word so
X    // that we can do the fall-through "case" statement
X
X    val = (long)c << ((num - 1) << 3);
X    switch (num)
X    {
X    case 4:
X	b = getc(fp);
X	val |= b << 16;
X    case 3:
X	b = getc(fp);
X	val |= b << 8;
X    case 2:
X	b = getc(fp);
X	val |= b;
X    case 1:
X	break;
X
X    default:
X	quit("dvi bug: getsval called with count of %d\n", num);
X    }
X    return val;
}
X
X
// ignore next n bytes in file
//
void skipbytes(long num, FILE *fp)
{
X    while (num-- > 0)
X	(void)getc(fp);
}
X
X
X
// for debugging output only
// 
void debug(int level, char *fmt, ...)
{
X    if (level > debuglevel)
X	return;
X
X    va_list ap;
X
X    va_start(ap, fmt);
X    vfprintf(stderr, fmt, ap);
X    fprintf(stderr, "\n");
X    va_end(ap);
}
X
X
// print informative messages only if verbose mode is on
// - break lines to fit on screen
// 
void mesg(char *fmt, ...)
{
X    if (!verbose)
X	return;
X
X    static col = 0;
X
X    // just print a newline on a null format string
X    // - this is to end a sequence of messages with a nice newline
X    if (fmt == NULL || *fmt == '\0')
X    {
X	if (col != 0)
X	    fprintf(stderr, "\n");
X	col = 0;
X	return;
X    }
X
X    va_list ap;
X    char buf[256];
X    char *s = buf;
X
X    va_start(ap, fmt);
X    vsprintf(s, fmt, ap);
X    va_end(ap);
X
X    int len = strlen(s);
X
X    if (col + len > 72)
X    {
X	fprintf(stderr, "\n");
X	col = 0;
X    }
X    if (col == 0)
X	while (*s == ' ')
X	    s++, len--;
X    col += len;
X
X    fputs(s, stderr);
X    fflush(stderr);
}
X
// print a warning only if we are in verbose mode
// - otherwise be silent
//
void warn(char *fmt, ...)
{
X    if (!verbose)
X	return;
X
X    va_list ap;
X
X    mesg(NULL);
X    va_start(ap, fmt);
X    fprintf(stderr, "WARNING: ");
X    vfprintf(stderr, fmt, ap);
X    fprintf(stderr, ".\n");
X    va_end(ap);
}
X
// print an error message
//
void error(char *fmt, ...)
{
X    va_list ap;
X
X    mesg(NULL);
X    va_start(ap, fmt);
X    vfprintf(stderr, fmt, ap);
X    fprintf(stderr, ".\n");
X    va_end(ap);
}
X
// print error message, then exit
// 
void quit(char *fmt, ...)
{
X    va_list ap;
X
X    mesg(NULL);
X    va_start(ap, fmt);
X    vfprintf(stderr, fmt, ap);
X    fprintf(stderr, "!\n");
X    va_end(ap);
X    exit(1);
}
X
X
FILE *
fopenp(char *path, char *file, char *type)
{
X    // if we have a null path, just do a normal fopen()
X    if (path == NULL || *path == '\0')
X	return fopen(file, type);
X
X    // just try the file straight if it is an absolute path
X    if (*file == '/')
X    {
X	FILE *ret = fopen(file, type);
X	if (ret != NULL)
X	    return ret;
X    }
X
X    // we look through the path for a directory, append the filename to
X    // that directory, and then try to open the file - we are finished
X    // when we are out of directories to try (return NULL) or we found a
X    // file (return that file)
X
X    char *p = path;
X    while (p != NULL && *p != '\0') // do until end of "path"
X    {
X	// copy the directory name pointed to by "p" into "buf"
X	char buf[MAXPATHLEN];
X	char *s = buf;
X	while (*p != PATHSEP && *p != '\0')
X	    *s++ = *p++;
X
X	// bump "p" to the start of the next directory
X	if (*p != '\0')
X	    p++;
X
X	// append a '/' to "buf" if necessary & then null-terminate it
X	if (s != buf && *(s - 1) != '/')
X	    *s++ = '/';
X	*s = '\0';
X
X	// append the filename to the directory name
X	strcat(s == buf ? s : s - 1, file);
X
X	// try to open the file - return it if the fopen succeeded
X	FILE *ret = fopen(buf, type);
X	if (ret != NULL)
X	    return ret;
X    }
X
X    return NULL;		// we struck out
}
SHAR_EOF
chmod 0444 util.C ||
echo 'restore of util.C failed'
Wc_c="`wc -c < 'util.C'`"
test 4481 -eq "$Wc_c" ||
	echo 'util.C: original size 4481, current size' "$Wc_c"
fi
# ============= global.C ==============
if test -f 'global.C' -a X"$1" != X"-c"; then
	echo 'x - skipping global.C (File already exists)'
else
echo 'x - extracting global.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'global.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: global.C,v 1.24 91/02/22 15:56:57 hmgr Exp $";
X
// Global variables for DVI filter.
// All globally visible variables are here.
//
// by Parag Patel
X
#include "defs.h"
#include "hp2686.h"
#include "hp33440.h"
#include "hp2684.h"
X
X
// implement macros for the declare in "extern.h"
implement_array(Fontlist, fontptr);
implement_array(Pageinfo, pageinfo);
implement_array(Pagespec, pagespec);
X
X
// command-line argument values:
char *fontpath = NULL;			// default font library path
char *dviinput = NULL;			// default special file search path
int debuglevel = 0;			// this is only for debugging
boolean verbose = FALSE;		// this is just for the hell of it
boolean dochecksum = TRUE;		// actually check the checksums?
char *devname = NULL;			// default device
boolean reverse = TRUE;			// reverse pages?
boolean landscape = FALSE;		// landscape mode
boolean duplexh = FALSE;		// double-sided printing (duplex) mode
boolean duplexv = FALSE;		// - horizontal and vertical binding
boolean duparg  = FALSE;		// got a duplex option on command-line?
long usermag = 0;			// user-specified mag value
X
Device *device = NULL;			// particular device for output
font *currfont = NULL;			// current font being used
Fontlist fontlist;			// list of all fonts for this file
Bitvec **fontbits = NULL;		// draw fonts into this space
double H, V, W, X, Y, Z;		// DVI stack vars
X
X
void init_globals()
{
X    // convert the device name to lower-case for comparing
X    for (char *s = devname; s != NULL && *s != '\0'; s++)
X	if (isupper(*s))
X	    *s = tolower(*s);
X
X    // default is LaserJetII
X    if (devname == NULL || *devname == '\0' || streq("default", devname))
X	devname = "hp33440";
X
X    // heuristics for figuring out Devices from device names
X    if (streq("hp2684", devname)
X	    || streq("laser2000", devname)
X	    || streq("lj2000", devname)
X	    || streq("jumbojet", devname)
X	    || streq("lj2k", devname))
X    {
X	reverse = !reverse;
X	if (!duparg && !duplexv && !duplexh)
X	    duplexv = TRUE;
X	device = new HP2684;
X	mesg("HP LaserJet 2000 (HP2684)");
X    }
X    else if (streq("hp33447", devname)
X		|| streq("laserjetiid", devname)
X		|| streq("laserjet2d", devname)
X		|| streq("laseriid", devname)
X		|| streq("laser2d", devname)
X		|| streq("ljiid", devname)
X		|| streq("lj2d", devname))
X    {
X	reverse = !reverse;
X	if (!duparg && !duplexv && !duplexh)
X	    duplexv = TRUE;
X	device = new HP33447;
X	mesg("HP LaserJet IID (HP33447)");
X    }
X    else if (streq("hp33440", devname)
X		|| streq("laserjetii", devname)
X		|| streq("laserjet2", devname)
X		|| streq("laserii", devname)
X		|| streq("laser2", devname)
X		|| streq("ljii", devname)
X		|| streq("lj2", devname))
X    {
X	reverse = !reverse;
X	device = new HP33440;
X	mesg("HP LaserJet II (HP33440)");
X	if (duparg && (duplexv || duplexh))
X	    warn("Cannot do double-sided for HP33440");
X    }
X    else if (streq("hp2686", devname)
X		|| streq("laserjet+", devname)
X		|| streq("laserjet", devname)
X		|| streq("laser", devname)
X		|| streq("ljet", devname)
X		|| streq("lj+", devname)
X		|| streq("lj", devname))
X    {
X	device = new HP2686;
X	mesg("HP LaserJet+ (HP2686)");
X	if (duparg && (duplexv || duplexh))
X	    warn("Cannot do double-sided for HP2686");
X    }
X
X    if (duplexh && duplexv)
X	quit("Must choose only ONE type of double-sided binding");
X
X    if (device == NULL)
X    {
X	if (!streq("help", devname) && !streq("?", devname))
X	    error("Sorry - don't know device ``%s''", devname);
X	error("Currently supported devices are: HP2686 HP33440 HP33447 HP2684");
X	quit("No point in continuing, eh?");
X    }
X
X    char *str;
X    if (fontpath == NULL)
X    {
X	str = getenv("FONTPATH");
X	if (str != NULL && *str != '\0')
X	    fontpath = str;
X    }
X    if (fontpath == NULL)
X	fontpath = DEFFONTPATH;
X
X    if (dviinput == NULL)
X    {
X	str = getenv("DVIINPUT");
X	if (str != NULL && *str != '\0')
X	    dviinput = str;
X    }
X
X    debug(3, "MAXFONTS=%d  MAXCHARS=%d  MAXONPAGE=%d  MAXLOADED=%d",
X	    MAXFONTS, MAXCHARS, MAXONPAGE, MAXLOADED);
}
X
void fini_globals()
{
X    delete device;
}
SHAR_EOF
chmod 0444 global.C ||
echo 'restore of global.C failed'
Wc_c="`wc -c < 'global.C'`"
test 4109 -eq "$Wc_c" ||
	echo 'global.C: original size 4109, current size' "$Wc_c"
fi
true || echo 'restore of stack.C failed'
echo End of part 1, continue with part 2
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.