dviselect (Part 1 of 6)

Skip Montanaro montnaro at sprite.crd.ge.com
Tue Nov 14 08:19:34 AEST 1989


#! /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 1 (of 6)."
# Contents:  Makefile Makefile.orig dviselect.1 dviselect.c
#   dviselect.c.orig h lib
# Wrapped by montnaro at sprite on Sat Nov 11 17:13:26 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(1356 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
XDESTDIR=
XCFLAGS=	-O -I./h
XMAKE=	make
X
XBINDIR	= $(HOME)/.commands
XIPRBIN  = /usr/local
XMANDIR	= $(HOME)/.man
X
XCSRCS	= dviselect.c
XSRCS	= $(CSRCS) dviselect.1
X
Xdefault: dviselect lib/lib.a
X
Xsrc:	$(SRCS)
X	@echo Done
X
Xclean:
X	cd lib; $(MAKE) $(MFLAGS) clean
X	-rm -f core *.o dviselect imagen1 dviselect.shar*
X
Xinst-dviselect: dviselect dviselect.1
X	install -s dviselect ${BINDIR}/dviselect
X	-install -c -m 444 dviselect.1 ${MANDIR}/man1/dviselect.1
X
Xdviselect: dviselect.o lib/lib.a
X	${CC} ${CFLAGS} -o dviselect dviselect.o lib/lib.a
X
Xlib/lib.a :
X	cd lib; $(MAKE) $(MFLAGS)
X
Xdvidvi: dvidvi.c
X	$(CC) $(CFLAGS) -o dvidvi dvidvi.c
X
Xdepend:
X	makedepend $(CFLAGS) $(CSRCS)
X
Xshar :
X	$(MAKE) $(MFLAGS) clean
X	shar -n1 -e6 -t "Now do 'make dviselect'"          *  >dviselect.shar.1
X	shar -n2 -e6 -t "Now do 'make dviselect'"        h/*  >dviselect.shar.2
X	shar -n3 -e6 -t "Now do 'make dviselect'" lib/[a-f]*  >dviselect.shar.3
X	shar -n4 -e6 -t "Now do 'make dviselect'" lib/[g-m]*  >dviselect.shar.4
X	shar -n5 -e6 -t "Now do 'make dviselect'" lib/[n-p]*  >dviselect.shar.5
X	shar -n6 -e6 -t "Now do 'make dviselect'" lib/[q-zM]* >dviselect.shar.6
X
X# DO NOT DELETE THIS LINE -- make depend depends on it.
X
Xdviselect.o: ../h/types.h ../h/dvi.h ../h/dviclass.h ../h/dvicodes.h
Xdviselect.o: ../h/fio.h ../h/search.h /usr/include/stdio.h
Xdviselect.o: /usr/include/ctype.h
END_OF_Makefile
if test 1356 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
chmod +x Makefile
# end of overwriting check
fi
if test -f Makefile.orig -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile.orig\"
else
echo shar: Extracting \"Makefile.orig\" \(820 characters\)
sed "s/^X//" >Makefile.orig <<'END_OF_Makefile.orig'
XDESTDIR=
XCFLAGS=	-O -I../h
XMAKE=	make
X
XBINDIR	= $(HOME)/.commands
XIPRBIN  = /usr/local
XMANDIR	= $(HOME)/.man
X
XCSRCS	= dviselect.c
XSRCS	= $(CSRCS) dviselect.1
X
Xdefault: all
X
X$(SRCS):;	co -q $@
X
Xsrc:	$(SRCS)
X	@echo Done
X
Xclean:
X	-ci -q $(SRCS)
X	-rm core *.o dviselect imagen1
X
Xinst-dviselect: dviselect dviselect.1
X	install -s dviselect ${BINDIR}/dviselect
X	-install -c -m 444 dviselect.1 ${MANDIR}/man1/dviselect.1
X
Xdviselect: dviselect.o ../lib/lib.a
X	${CC} ${CFLAGS} -o dviselect dviselect.o ../lib/lib.a
X
Xdvidvi: dvidvi.c
X	$(CC) $(CFLAGS) -o dvidvi dvidvi.c
X
Xdepend:
X	makedepend $(CFLAGS) $(CSRCS)
X
X# DO NOT DELETE THIS LINE -- make depend depends on it.
X
Xdviselect.o: ../h/types.h ../h/dvi.h ../h/dviclass.h ../h/dvicodes.h
Xdviselect.o: ../h/fio.h ../h/search.h /usr/include/stdio.h
Xdviselect.o: /usr/include/ctype.h
END_OF_Makefile.orig
if test 820 -ne `wc -c <Makefile.orig`; then
    echo shar: \"Makefile.orig\" unpacked with wrong size!
fi
chmod +x Makefile.orig
# end of overwriting check
fi
if test -f dviselect.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"dviselect.1\"
else
echo shar: Extracting \"dviselect.1\" \(3897 characters\)
sed "s/^X//" >dviselect.1 <<'END_OF_dviselect.1'
X.TH DVISELECT 1
X.SH NAME
Xdviselect \- extract pages from DVI files
X.SH SYNOPSIS
X.B dviselect
X[
X.B \-s
X] [
X.B \-i
X.I infile
X] [
X.B \-o
X.I outfile
X]
X.I "list of pages"
X[
X.I infile
X[
X.I outfile
X] ]
X.SH DESCRIPTION
X.I Dviselect
Xselects pages from a DVI file produced by TeX, creating a new DVI
Xfile usable by any of TeX's conversion program (e.g., iptex), or even
Xby dviselect itself.
X.PP
XA
X.I range
Xis a string of the form
X.I first:last
Xwhere both
X.I first
Xand
X.I last
Xare optional numeric strings, with negative numbers indicated by
Xa leading underscore character ``_''.  If both
X.I first
Xand
X.I last
Xare omitted, the colon may also be omitted, or may be replaced
Xwith an asterisk ``*''.  A
X.I page range
Xis a list of ranges separated by periods.  A
X.I "list of pages"
Xis described by a set of page ranges separated by commas and/or white space.
X.PP
X.I Dviselect
Xactually looks at the ten
X.I count
Xvariables that TeX writes; the first of these (\ecount0) is the
Xpage number, with \ecount1 through \ecount9 having varied uses
Xdepending on which macro packages are in use.  (Typically \ecount1
Xis a chapter or section number.)  A page is included in
X.IR dviselect 's
Xoutput if all its \ecount values are within any one of the ranges
Xlisted on the command line.  For example, the command
X``dviselect *.1,35:''
Xmight select everything in chapter 1, as well as pages 35 and up.
X``dviselect 10:30'' would select pages 10 through 30 (inclusive).
X``:43'' means everything up to and including page 43 (including
Xnegative-numbered pages).
XIf a Table of Contents has negative page numbers, ``:_1'' will select it.
X``*.4 .........1'' might
Xmean everything in every chapter 4 and an index, presuming \ecount9
Xwas set to 1 in the index.  (``*'' must be quoted from the shell;
Xthe null string is more convenient to use, if harder to read.)
X.PP
XInstead of \ecount values,
X.I dviselect
Xcan also select by ``absolute page number'', where the first page
Xis page 1, the second page 2, and so forth.  Absolute page numbers
Xare indicated by a leading equal sign ``=''.  Ranges of absolute
Xpages are also allowed: ``dviselect =3:7'' will extract the third
Xthrough seventh pages.  Dot separators are not legal in absolute
Xranges, and there are no negative absolute page numbers.
X.PP
XMore precisely, an asterisk or a null string implies no limit;
Xan equal sign means absolute pages rather than \ecounts;
Xa leading colon means everything up to and including the given page; a
Xtrailing colon means everything from the given page on; and
Xa period indicates that the next \ecount should be examined.
XIf fewer than 10 ranges are specified, the remaining \ecounts
Xare left unrestricted (that is, ``1:5'' and ``1:5.*'' are equivalent).
XA single number \fIn\fP is treated as if it were the range \fIn:n\fP.
XAn arbitrary number of page selectors may be given, separated by commas
Xor whitespace; a page is selected if any of the selectors matches
Xits \ecounts or absolute page number.
X.PP
XDviselect normally prints the page numbers of the pages selected; the
X.I \-s
Xoption suppresses this.
X.SH AUTHOR
XChris Torek, University of Maryland
X.SH "SEE ALSO"
Xdvipr(1), iptex(1), tex(1), \fIThe TeXbook\fP
X.SH BUGS
XA leading ``-'' ought to be allowed for negative numbers, but it
Xis currently used as a synonym for ``:'', for backwards compatibility.
X.PP
XSection or subsection selection will sometimes fail, for the DVI
Xfile lists only the \ecount values that were active when the page
Xended.  Clever macro packages can alleviate this by making use of
Xother ``free'' \ecount registers.  Chapters normally begin on new
Xpages, and do not suffer from this particular problem.
X.PP
X.I Dviselect
Xdoes not adjust the parameters in the postamble; however, since these
Xvalues are normally used only to size certain structures in the output
Xconversion programs, and the parameters never need to be adjusted upward,
Xthis has not proven to be a problem.
END_OF_dviselect.1
if test 3897 -ne `wc -c <dviselect.1`; then
    echo shar: \"dviselect.1\" unpacked with wrong size!
fi
chmod +x dviselect.1
# end of overwriting check
fi
if test -f dviselect.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"dviselect.c\"
else
echo shar: Extracting \"dviselect.c\" \(22215 characters\)
sed "s/^X//" >dviselect.c <<'END_OF_dviselect.c'
X/*
X * Copyright (c) 1987 University of Maryland Department of Computer Science.
X * All rights reserved.  Permission to copy for any purpose is hereby granted
X * so long as this copyright notice remains intact.
X */
X
X#ifndef lint
Xstatic char rcsid[] = "$Header: /home/reed/grunwald/Projects/Iptex/utilities/RCS/dviselect.c,v 1.3 87/12/06 12:27:33 grunwald Exp $";
X#endif
X
X/*
X * DVI page selection program
X *
X * Reads DVI version 2 files and selects pages, writing a new DVI
X * file.  The new DVI file is technically correct, though we do not
X * adjust the tallest and widest page values, nor the DVI stack size.
X * This is all right since the values will never become too small,
X * but it might be nice to fix them up.  Perhaps someday . . . .
X */
X
X#include "types.h"
X#include "dvi.h"
X#include "dviclass.h"
X#include "dvicodes.h"
X#include "fio.h"
X#include "search.h"
X#include <stdio.h>
X#include <ctype.h>
X
Xchar  *ProgName;
Xextern int   errno;
Xextern char *optarg;
Xextern int   optind;
X
X/* Globals */
Xchar	serrbuf[BUFSIZ];	/* buffer for stderr */
X
X/*
X * We will try to keep output lines shorter than MAXCOL characters.
X */
X#define MAXCOL	75
X
X/*
X * We use the following structure to keep track of fonts we have seen.
X * The final DVI file lists only the fonts it uses.
X */
Xstruct fontinfo {
X	i32	fi_newindex;	/* font number in output file */
X	int	fi_reallyused;	/* true => used on a page we copied */
X	i32	fi_checksum;	/* the checksum */
X	i32	fi_mag;		/* the magnification */
X	i32	fi_designsize;	/* the design size */
X	short	fi_n1;		/* the name header length */
X	short	fi_n2;		/* the name body length */
X	char	*fi_name;	/* the name itself */
X};
X
X/*
X * We need to remember which pages the user would like.  We build a linked
X * list that allows us to decide (for any given page) whether it should
X * be included in the output file.  Each page has ten \count variables
X * associated with it.  We put a bound on the values allowed for each, and
X * keep a linked list of alternatives should any be outside the allowed
X * range.  For example, `dviselect *.3,10-15' would generate a two-element
X * page list, with the first allowing any value for \count0 (and \counts 2 to
X * 9) but \count1 restricted to the range 3-3, and the second restricting
X * \count0 to the range 10-15 but leaving \counts 1 to 9 unrestrained.
X *
X * In case no bound is specified, the `nol' or `noh' flag is set (so that
X * we need not fix some `large' number as a maximum value).
X *
X * We also allow `absolute' page references, where the first page is
X * page 1, the second 2, and so forth.  These are specified with an
X * equal sign: `dviselect =4:10' picks up the fourth through tenth
X * sequential pages, irrespective of \count values.
X */
Xstruct pagesel {
X	i32	ps_low;		/* lower bound */
X	int	ps_nol;		/* true iff no lower bound */
X	i32	ps_high;	/* upper bound */
X	int	ps_noh;		/* true iff no upper bound */
X};
Xstruct pagelist {
X	struct	pagelist *pl_alt;	/* next in a series of alternates */
X	int	pl_len;			/* number of ranges to check */
X	int	pl_abs;			/* true iff absolute page ref */
X	struct	pagesel pl_pages[10];	/* one for each \count variable */
X};
X
Xint	SFlag;			/* true => -s, silent operation */
X
Xstruct	search *FontFinder;	/* maps from input indicies to fontinfo */
Xi32	NextOutputFontIndex;	/* generates output indicies */
Xi32	CurrentFontIndex;	/* current (old) index in input */
Xi32	OutputFontIndex;	/* current (new) index in ouput */
X
Xstruct	pagelist *PageList;	/* the list of allowed pages */
X
XFILE	*inf;			/* the input DVI file */
XFILE	*outf;			/* the output DVI file */
X
Xint	ExpectBOP;		/* true => BOP ok */
Xint	ExpectEOP;		/* true => EOP ok */
X
Xlong	StartOfLastPage;	/* The file position just before we started
X				   the last page (this is later written to
X				   the output file as the previous page
X				   pointer). */
Xlong	CurrentPosition;	/* The current position of the file */
X
Xint	UseThisPage;		/* true => current page is selected */
X
Xi32	InputPageNumber;	/* current absolute page in old DVI file */
Xint	NumberOfOutputPages;	/* number of pages in new DVI file */
X
Xi32	Numerator;		/* numerator from DVI file */
Xi32	Denominator;		/* denominator from DVI file */
Xi32	DVIMag;			/* magnification from DVI file */
X
Xi32	Count[10];		/* the 10 \count variables */
X
X/* save some string space: we use this a lot */
Xchar	writeerr[] = "error writing DVI file";
X
Xchar	*malloc(), *realloc(), *sprintf();
X
X/*
X * lint gets rather confused with the current definitions of getc and putc,
X * so we redefine them here (#if lint).  This should really be in the
X * standard I/O library, but I am not about to go change it now!
X */
X#ifdef lint
X#undef putc
X#undef getc
X#define putc(c,f) (*(f)->_ptr++ = (unsigned) (c))
X#define getc(f)   (*(f)->_ptr++)
X#endif
X
X/*
X * Return true iff the 10 \counts are one of the desired output pages.
X */
XDesiredPageP()
X{
X	register struct pagelist *pl;
X
X	for (pl = PageList; pl != NULL; pl = pl->pl_alt) {
X		register struct pagesel *ps = pl->pl_pages;
X		register int i;
X		register i32 *pagep;
X
X		pagep = pl->pl_abs ? &InputPageNumber : &Count[0];
X		for (i = 0; i < pl->pl_len; i++, ps++, pagep++)
X			if (!ps->ps_nol && *pagep < ps->ps_low ||
X			    !ps->ps_noh && *pagep > ps->ps_high)
X				break;	/* not within bounds */
X		if (i >= pl->pl_len)
X			return (1);	/* success */
X	}
X	return (0);
X}
X
X/*
X * Print a message to stderr, with an optional leading space, and handling
X * long line wraps.
X */
Xmessage(space, str, len)
X	int space;
X	register char *str;
X	register int len;
X{
X	static int beenhere;
X	static int col;
X
X	if (!beenhere)
X		space = 0, beenhere++;
X	if (len == 0)
X		len = strlen(str);
X	col += len;
X	if (space) {
X		if (col >= MAXCOL)
X			(void) putc('\n', stderr), col = len;
X		else
X			(void) putc(' ', stderr), col++;
X	}
X	while (--len >= 0)
X		(void) putc(*str++, stderr);
X	(void) fflush(stderr);
X}
X
X/*
X * Start a page (process a DVI_BOP).
X */
XBeginPage()
X{
X	register i32 *i;
X
X	if (!ExpectBOP)
X		GripeUnexpectedOp("BOP");
X	ExpectBOP = 0;
X	ExpectEOP++;		/* set the new "expect" state */
X
X	OutputFontIndex = -1;	/* new page requires respecifying font */
X	InputPageNumber++;	/* count it */
X	for (i = Count; i < &Count[10]; i++)
X		fGetLong(inf, *i);
X	(void) GetLong(inf);	/* previous page pointer */
X
X	if ((UseThisPage = DesiredPageP()) == 0)
X		return;
X
X	(void) putc(DVI_BOP, outf);
X	for (i = Count; i < &Count[10]; i++)
X		PutLong(outf, *i);
X	PutLong(outf, StartOfLastPage);
X	if (ferror(outf))
X		error(1, errno, writeerr);
X
X	StartOfLastPage = CurrentPosition;
X	CurrentPosition += 45;	/* we just wrote this much */
X
X	if (!SFlag) {		/* write nice page usage messages */
X		register int z = 0;
X		register int mlen = 0;
X		char msg[80];
X
X		(void) sprintf(msg, "[%d", Count[0]);
X		mlen = strlen(msg);
X		for (i = &Count[1]; i < &Count[10]; i++) {
X			if (*i == 0) {
X				z++;
X				continue;
X			}
X			while (--z >= 0)
X				msg[mlen++] = '.', msg[mlen++] = '0';
X			z = 0;
X			(void) sprintf(msg + mlen, ".%d", *i);
X			mlen += strlen(msg + mlen);
X		}
X		message(1, msg, mlen);
X	}
X}
X
X/*
X * End a page (process a DVI_EOP).
X */
XEndPage()
X{
X	if (!ExpectEOP)
X		GripeUnexpectedOp("EOP");
X	ExpectEOP = 0;
X	ExpectBOP++;
X
X	if (!UseThisPage)
X		return;
X
X	if (!SFlag)
X		message(0, "]", 1);
X
X	putc(DVI_EOP, outf);
X	if (ferror(outf))
X		error(1, errno, writeerr);
X	CurrentPosition++;
X	NumberOfOutputPages++;
X}
X
X/*
X * For each of the fonts used in the new DVI file, write out a definition.
X */
X/* ARGSUSED */
XPostAmbleFontEnumerator(addr, key)
X	char *addr;
X	i32 key;
X{
X
X	if (((struct fontinfo *) addr)->fi_reallyused)
X		WriteFont((struct fontinfo *) addr);
X}
X
XHandlePostAmble()
X{
X	register i32 c;
X
X	(void) GetLong(inf);	/* previous page pointer */
X	if (GetLong(inf) != Numerator)
X		GripeMismatchedValue("numerator");
X	if (GetLong(inf) != Denominator)
X		GripeMismatchedValue("denominator");
X	if (GetLong(inf) != DVIMag)
X		GripeMismatchedValue("\\magfactor");
X
X	putc(DVI_POST, outf);
X	PutLong(outf, StartOfLastPage);
X	PutLong(outf, Numerator);
X	PutLong(outf, Denominator);
X	PutLong(outf, DVIMag);
X	c = GetLong(inf);
X	PutLong(outf, c);	/* tallest page height */
X	c = GetLong(inf);
X	PutLong(outf, c);	/* widest page width */
X	c = GetWord(inf);
X	PutWord(outf, c);	/* DVI stack size */
X	PutWord(outf, NumberOfOutputPages);
X	StartOfLastPage = CurrentPosition;	/* point at post */
X	CurrentPosition += 29;	/* count all those `put's */
X#ifdef notdef
X	(void) GetWord(inf);	/* skip original number of pages */
X#endif
X
X	/*
X	 * just ignore all the incoming font definitions; we are done with
X	 * input file 
X	 */
X
X	/*
X	 * run through the FontFinder table and dump definitions for the
X	 * fonts we have used. 
X	 */
X	SEnumerate(FontFinder, PostAmbleFontEnumerator);
X
X	putc(DVI_POSTPOST, outf);
X	PutLong(outf, StartOfLastPage);	/* actually start of postamble */
X	putc(DVI_VERSION, outf);
X	putc(DVI_FILLER, outf);
X	putc(DVI_FILLER, outf);
X	putc(DVI_FILLER, outf);
X	putc(DVI_FILLER, outf);
X	CurrentPosition += 10;
X	while (CurrentPosition & 3)
X		putc(DVI_FILLER, outf), CurrentPosition++;
X	if (ferror(outf))
X		error(1, errno, writeerr);
X}
X
X/*
X * Write a font definition to the output file
X */
XWriteFont(fi)
X	register struct fontinfo *fi;
X{
X	register int l;
X	register char *s;
X
X	if (fi->fi_newindex < 256) {
X		putc(DVI_FNTDEF1, outf);
X		putc(fi->fi_newindex, outf);
X		CurrentPosition += 2;
X	} else if (fi->fi_newindex < 65536) {
X		putc(DVI_FNTDEF2, outf);
X		PutWord(outf, fi->fi_newindex);
X		CurrentPosition += 3;
X	} else if (fi->fi_newindex < 16777216) {
X		putc(DVI_FNTDEF3, outf);
X		Put3Byte(outf, fi->fi_newindex);
X		CurrentPosition += 4;
X	} else {
X		putc(DVI_FNTDEF4, outf);
X		PutLong(outf, fi->fi_newindex);
X		CurrentPosition += 5;
X	}
X	PutLong(outf, fi->fi_checksum);
X	PutLong(outf, fi->fi_mag);
X	PutLong(outf, fi->fi_designsize);
X	putc(fi->fi_n1, outf);
X	putc(fi->fi_n2, outf);
X	l = fi->fi_n1 + fi->fi_n2;
X	CurrentPosition += 14 + l;
X	s = fi->fi_name;
X	while (--l >= 0)
X		putc(*s, outf), s++;
X}
X
X/*
X * Handle the preamble.  Someday we should update the comment field.
X */
XHandlePreAmble()
X{
X	register int n, c;
X
X	if (GetByte(inf) != Sign8(DVI_PRE))
X		GripeMissingOp("PRE");
X	if (GetByte(inf) != Sign8(DVI_VERSION))
X		GripeMismatchedValue("DVI version number");
X	Numerator = GetLong(inf);
X	Denominator = GetLong(inf);
X	DVIMag = GetLong(inf);
X	putc(DVI_PRE, outf);
X	putc(DVI_VERSION, outf);
X	PutLong(outf, Numerator);
X	PutLong(outf, Denominator);
X	PutLong(outf, DVIMag);
X
X	n = UnSign8(GetByte(inf));
X	CurrentPosition = 15 + n;	/* well, almost */
X	putc(n, outf);
X	while (--n >= 0) {
X		c = GetByte(inf);
X		putc(c, outf);	/* never trust a macro, I always say */
X	}
X}
X
Xmain(argc, argv)
X	int argc;
X	register char **argv;
X{
X	register int c;
X	register char *s;
X	char *inname = NULL, *outname = NULL;
X
X	ProgName = *argv;
X	setbuf(stderr, serrbuf);
X
X	while ((c = getopt(argc, argv, "i:o:s")) != EOF) {
X		switch (c) {
X
X		case 's':	/* silent */
X			SFlag++;
X			break;
X
X		case 'i':
X			if (inname != NULL)
X				goto usage;
X			inname = optarg;
X			break;
X
X		case 'o':
X			if (outname != NULL)
X				goto usage;
X			outname = optarg;
X			break;
X
X		case '?':
Xusage:
X			fprintf(stderr, "\
XUsage: %s [-s] [-i infile] [-o outfile] pages [...] [infile [outfile]]\n",
X				ProgName);
X			(void) fflush(stderr);
X			exit(1);
X		}
X	}
X
X	while (optind < argc) {
X		s = argv[optind++];
X		c = *s;
X		if (!isalpha(c) && c != '/') {
X			if (ParsePages(s))
X				goto usage;
X		} else if (inname == NULL)
X			inname = s;
X		else if (outname == NULL)
X			outname = s;
X		else
X			goto usage;
X	}
X	if (PageList == NULL)
X		goto usage;
X	if (inname == NULL)
X		inf = stdin;
X	else if ((inf = fopen(inname, "r")) == 0)
X		error(1, errno, "cannot read %s", inname);
X	if (outname == NULL)
X		outf = stdout;
X	else if ((outf = fopen(outname, "w")) == 0)
X		error(1, errno, "cannot write %s", outname);
X
X	if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
X		error(1, 0, "cannot create font finder (out of memory?)");
X
X	ExpectBOP++;
X	StartOfLastPage = -1;
X	HandlePreAmble();
X	HandleDVIFile();
X	HandlePostAmble();
X	if (!SFlag)
X		fprintf(stderr, "\nWrote %d pages, %d bytes\n",
X			NumberOfOutputPages, CurrentPosition);
X	if (NumberOfOutputPages == 0)
X	  exit(1);
X	else
X	  exit(0);
X}
X
Xstruct pagelist *
XInstallPL(ps, n, absolute)
X	register struct pagesel *ps;
X	register int n;
X	int absolute;
X{
X	register struct pagelist *pl;
X
X	pl = (struct pagelist *) malloc(sizeof *pl);
X	if (pl == NULL)
X		GripeOutOfMemory(sizeof *pl, "page list");
X	pl->pl_alt = PageList;
X	PageList = pl;
X	pl->pl_len = n;
X	while (--n >= 0)
X		pl->pl_pages[n] = ps[n];
X	pl->pl_abs = absolute;
X}
X
X/*
X * Parse a string representing a list of pages.  Return 0 iff ok.  As a
X * side effect, the page selection(s) is (are) prepended to PageList.
X */
XParsePages(s)
X	register char *s;
X{
X	register struct pagesel *ps;
X	register int c;		/* current character */
X	register i32 n;		/* current numeric value */
X	register int innumber;	/* true => gathering a number */
X	int i;			/* next index in page select list */
X	int range;		/* true => saw a range indicator */
X	int negative;		/* true => number being built is negative */
X	int absolute;		/* true => absolute, not \count */
X	struct pagesel pagesel[10];
X
X#define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',')
X
X	range = 0;
X	innumber = 0;
X	absolute = 0;
X	i = 0;
X	ps = pagesel;
X	/*
X	 * Talk about ad hoc!  (Not to mention convoluted.)
X	 */
X	for (;;) {
X		c = *s++;
X		if (i == 0 && !innumber && !range) {
X			/* nothing special going on */
X			if (c == 0)
X				return 0;
X			if (white(c))
X				continue;
X		}
X		if (c == '_') {
X			/* kludge: should be '-' for negatives */
X			if (innumber || absolute)
X				return (-1);
X			innumber++;
X			negative = 1;
X			n = 0;
X			continue;
X		}
X		if (c == '=') {
X			/* absolute page */
X			if (innumber || range || i > 0)
X				return (-1);
X			absolute++;
X			/*
X			 * Setting innumber means that there is always
X			 * a lower bound, but this is all right since
X			 * `=:4' is treated as if it were `=0:4'.  As
X			 * there are no negative absolute page numbers,
X			 * this selects pages 1:4, which is the proper
X			 * action.
X			 */
X			innumber++;
X			negative = 0;
X			n = 0;
X			continue;
X		}
X		if (isdigit(c)) {
X			/* accumulate numeric value */
X			if (!innumber) {
X				innumber++;
X				negative = 0;
X				n = c - '0';
X				continue;
X			}
X			n *= 10;
X			n += negative ? '0' - c : c - '0';
X			continue;
X		}
X		if (c == '-' || c == ':') {
X			/* here is a range */
X			if (range)
X				return (-1);
X			if (innumber) {	/* have a lower bound */
X				ps->ps_low = n;
X				ps->ps_nol = 0;
X			} else
X				ps->ps_nol = 1;
X			range++;
X			innumber = 0;
X			continue;
X		}
X		if (c == '*') {
X			/* no lower bound, no upper bound */
X			c = *s++;
X			if (innumber || range || i >= 10 ||
X			    (c && c != '.' && !white(c)))
X				return (-1);
X			ps->ps_nol = 1;
X			ps->ps_noh = 1;
X			goto finishnum;
X		}
X		if (c == 0 || c == '.' || white(c)) {
X			/* end of this range */
X			if (i >= 10)
X				return (-1);
X			if (!innumber) {	/* no upper bound */
X				ps->ps_noh = 1;
X				if (!range)	/* no lower bound either */
X					ps->ps_nol = 1;
X			} else {		/* have an upper bound */
X				ps->ps_high = n;
X				ps->ps_noh = 0;
X				if (!range) {
X					/* no range => lower bound == upper */
X					ps->ps_low = ps->ps_high;
X					ps->ps_nol = 0;
X				}
X			}
Xfinishnum:
X			i++;
X			if (c == '.') {
X				if (absolute)
X					return (-1);
X				ps++;
X			} else {
X				InstallPL(pagesel, i, absolute);
X				ps = pagesel;
X				i = 0;
X				absolute = 0;
X			}
X			if (c == 0)
X				return (0);
X			range = 0;
X			innumber = 0;
X			continue;
X		}
X		/* illegal character */
X		return (-1);
X	}
X#undef white
X}
X
X/*
X * Handle a font definition.
X */
XHandleFontDef(index)
X	i32 index;
X{
X	register struct fontinfo *fi;
X	register int i;
X	register char *s;
X	int def = S_CREATE | S_EXCL;
X
X	if ((fi = (struct fontinfo *) SSearch(FontFinder, index, &def)) == 0)
X		if (def & S_COLL)
X			error(1, 0, "font %d already defined", index);
X		else
X			error(1, 0, "cannot stash font %d (out of memory?)",
X				index);
X	fi->fi_reallyused = 0;
X	fi->fi_checksum = GetLong(inf);
X	fi->fi_mag = GetLong(inf);
X	fi->fi_designsize = GetLong(inf);
X	fi->fi_n1 = UnSign8(GetByte(inf));
X	fi->fi_n2 = UnSign8(GetByte(inf));
X	i = fi->fi_n1 + fi->fi_n2;
X	if ((s = malloc((unsigned) i)) == 0)
X		GripeOutOfMemory(i, "font name");
X	fi->fi_name = s;
X	while (--i >= 0)
X		*s++ = GetByte(inf);
X}
X
X/*
X * Handle a \special.
X */
XHandleSpecial(c, l, p)
X	int c;
X	register int l;
X	register i32 p;
X{
X	register int i;
X
X	if (UseThisPage) {
X		putc(c, outf);
X		switch (l) {
X
X		case DPL_UNS1:
X			putc(p, outf);
X			CurrentPosition += 2;
X			break;
X
X		case DPL_UNS2:
X			PutWord(outf, p);
X			CurrentPosition += 3;
X			break;
X
X		case DPL_UNS3:
X			Put3Byte(outf, p);
X			CurrentPosition += 4;
X			break;
X
X		case DPL_SGN4:
X			PutLong(outf, p);
X			CurrentPosition += 5;
X			break;
X
X		default:
X			panic("HandleSpecial l=%d", l);
X			/* NOTREACHED */
X		}
X		CurrentPosition += p;
X		while (--p >= 0) {
X			i = getc(inf);
X			putc(i, outf);
X		}
X		if (feof(inf))
X			error(1, 0, "unexpected EOF");
X		if (ferror(outf))
X			error(1, errno, writeerr);
X	} else
X		while (--p >= 0)
X			(void) getc(inf);
X}
X
XReallyUseFont()
X{
X	register struct fontinfo *fi;
X	int look = S_LOOKUP;
X
X	fi = (struct fontinfo *) SSearch(FontFinder, CurrentFontIndex, &look);
X	if (fi == 0)
X		error(1, 0, "index %d not in font table!", CurrentFontIndex);
X	if (fi->fi_reallyused == 0) {
X		fi->fi_reallyused++;
X		fi->fi_newindex = NextOutputFontIndex++;
X		WriteFont(fi);
X	}
X	if (fi->fi_newindex != OutputFontIndex) {
X		PutFontSelector(fi->fi_newindex);
X		OutputFontIndex = fi->fi_newindex;
X	}
X}
X
X/*
X * Write a font selection command to the output file
X */
XPutFontSelector(index)
X	i32 index;
X{
X
X	if (index < 64) {
X		putc(index + DVI_FNTNUM0, outf);
X		CurrentPosition++;
X	} else if (index < 256) {
X		putc(DVI_FNT1, outf);
X		putc(index, outf);
X		CurrentPosition += 2;
X	} else if (index < 65536) {
X		putc(DVI_FNT2, outf);
X		PutWord(outf, index);
X		CurrentPosition += 3;
X	} else if (index < 16777216) {
X		putc(DVI_FNT3, outf);
X		Put3Byte(outf, index);
X		CurrentPosition += 4;
X	} else {
X		putc(DVI_FNT4, outf);
X		PutLong(outf, index);
X		CurrentPosition += 5;
X	}
X}
X
X/*
X * The following table describes the length (in bytes) of each of the DVI
X * commands that we can simply copy, starting with DVI_SET1 (128).
X */
Xchar	oplen[128] = {
X	0, 0, 0, 0,		/* DVI_SET1 .. DVI_SET4 */
X	9,			/* DVI_SETRULE */
X	0, 0, 0, 0,		/* DVI_PUT1 .. DVI_PUT4 */
X	9,			/* DVI_PUTRULE */
X	1,			/* DVI_NOP */
X	0,			/* DVI_BOP */
X	0,			/* DVI_EOP */
X	1,			/* DVI_PUSH */
X	1,			/* DVI_POP */
X	2, 3, 4, 5,		/* DVI_RIGHT1 .. DVI_RIGHT4 */
X	1,			/* DVI_W0 */
X	2, 3, 4, 5,		/* DVI_W1 .. DVI_W4 */
X	1,			/* DVI_X0 */
X	2, 3, 4, 5,		/* DVI_X1 .. DVI_X4 */
X	2, 3, 4, 5,		/* DVI_DOWN1 .. DVI_DOWN4 */
X	1,			/* DVI_Y0 */
X	2, 3, 4, 5,		/* DVI_Y1 .. DVI_Y4 */
X	1,			/* DVI_Z0 */
X	2, 3, 4, 5,		/* DVI_Z1 .. DVI_Z4 */
X	0,			/* DVI_FNTNUM0 (171) */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 172 .. 179 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 180 .. 187 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 188 .. 195 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 196 .. 203 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 204 .. 211 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 212 .. 219 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 220 .. 227 */
X	0, 0, 0, 0, 0, 0, 0,	/* 228 .. 234 */
X	0, 0, 0, 0,		/* DVI_FNT1 .. DVI_FNT4 */
X	0, 0, 0, 0,		/* DVI_XXX1 .. DVI_XXX4 */
X	0, 0, 0, 0,		/* DVI_FNTDEF1 .. DVI_FNTDEF4 */
X	0,			/* DVI_PRE */
X	0,			/* DVI_POST */
X	0,			/* DVI_POSTPOST */
X	0, 0, 0, 0, 0, 0,	/* 250 .. 255 */
X};
X
X/*
X * Here we read the input DVI file and write relevant pages to the
X * output DVI file. We also keep track of font changes, handle font
X * definitions, and perform some other housekeeping.
X */
XHandleDVIFile()
X{
X	register int c, l;
X	register i32 p;
X	register int CurrentFontOK = 0;
X
X	/* Only way out is via "return" statement */
X	for (;;) {
X		c = getc(inf);	/* getc() returns unsigned values */
X		if (DVI_IsChar(c)) {
X			/*
X			 * Copy chars, note font usage, but ignore if
X			 * page is not interesting.
X			 */
X			if (!UseThisPage)
X				continue;
X			if (!CurrentFontOK) {
X				ReallyUseFont();
X				CurrentFontOK++;
X			}
X			putc(c, outf);
X			CurrentPosition++;
X			continue;
X		}
X		if (DVI_IsFont(c)) {	/* note font change */
X			CurrentFontIndex = c - DVI_FNTNUM0;
X			CurrentFontOK = 0;
X			continue;
X		}
X		if ((l = (oplen - 128)[c]) != 0) {	/* simple copy */
X			if (!UseThisPage) {
X				while (--l > 0)
X					(void) getc(inf);
X				continue;
X			}
X			CurrentPosition += l;
X			putc(c, outf);
X			while (--l > 0) {
X				c = getc(inf);
X				putc(c, outf);
X			}
X			if (ferror(outf))
X				error(1, errno, writeerr);
X			continue;
X		}
X		if ((l = DVI_OpLen(c)) != 0) {
X			/*
X			 * Handle other generics.
X			 * N.B.: there should only be unsigned parameters
X			 * here (save SGN4), for commands with negative
X			 * parameters have been taken care of above.
X			 */
X			switch (l) {
X
X			case DPL_UNS1:
X				p = getc(inf);
X				break;
X
X			case DPL_UNS2:
X				fGetWord(inf, p);
X				break;
X
X			case DPL_UNS3:
X				fGet3Byte(inf, p);
X				break;
X
X			case DPL_SGN4:
X				fGetLong(inf, p);
X				break;
X
X			default:
X				panic("HandleDVIFile l=%d", l);
X			}
X
X			/*
X			 * Now that we have the parameter, perform the
X			 * command.
X			 */
X			switch (DVI_DT(c)) {
X
X			case DT_SET:
X			case DT_PUT:
X				if (!UseThisPage)
X					continue;
X				if (!CurrentFontOK) {
X					ReallyUseFont();
X					CurrentFontOK++;
X				}
X				putc(c, outf);
X				switch (l) {
X
X				case DPL_UNS1:
X					putc(p, outf);
X					CurrentPosition += 2;
X					continue;
X
X				case DPL_UNS2:
X					PutWord(outf, p);
X					CurrentPosition += 3;
X					continue;
X
X				case DPL_UNS3:
X					Put3Byte(outf, p);
X					CurrentPosition += 4;
X					continue;
X
X				case DPL_SGN4:
X					PutLong(outf, p);
X					CurrentPosition += 5;
X					continue;
X				}
X
X			case DT_FNT:
X				CurrentFontIndex = p;
X				CurrentFontOK = 0;
X				continue;
X
X			case DT_XXX:
X				HandleSpecial(c, l, p);
X				continue;
X
X			case DT_FNTDEF:
X				HandleFontDef(p);
X				continue;
X
X			default:
X				panic("HandleDVIFile DVI_DT(%d)=%d",
X				      c, DVI_DT(c));
X			}
X			continue;
X		}
X
X		switch (c) {	/* handle the few remaining cases */
X
X		case DVI_BOP:
X			BeginPage();
X			CurrentFontOK = 0;
X			break;
X
X		case DVI_EOP:
X			EndPage();
X			break;
X
X		case DVI_PRE:
X			GripeUnexpectedOp("PRE");
X			/* NOTREACHED */
X
X		case DVI_POST:
X			return;
X
X		case DVI_POSTPOST:
X			GripeUnexpectedOp("POSTPOST");
X			/* NOTREACHED */
X
X		default:
X			GripeUndefinedOp(c);
X			/* NOTREACHED */
X		}
X	}
X}
END_OF_dviselect.c
if test 22215 -ne `wc -c <dviselect.c`; then
    echo shar: \"dviselect.c\" unpacked with wrong size!
fi
chmod +x dviselect.c
# end of overwriting check
fi
if test -f dviselect.c.orig -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"dviselect.c.orig\"
else
echo shar: Extracting \"dviselect.c.orig\" \(22164 characters\)
sed "s/^X//" >dviselect.c.orig <<'END_OF_dviselect.c.orig'
X/*
X * Copyright (c) 1987 University of Maryland Department of Computer Science.
X * All rights reserved.  Permission to copy for any purpose is hereby granted
X * so long as this copyright notice remains intact.
X */
X
X#ifndef lint
Xstatic char rcsid[] = "$Header: /home/reed/grunwald/Projects/Iptex/utilities/RCS/dviselect.c,v 1.3 87/12/06 12:27:33 grunwald Exp $";
X#endif
X
X/*
X * DVI page selection program
X *
X * Reads DVI version 2 files and selects pages, writing a new DVI
X * file.  The new DVI file is technically correct, though we do not
X * adjust the tallest and widest page values, nor the DVI stack size.
X * This is all right since the values will never become too small,
X * but it might be nice to fix them up.  Perhaps someday . . . .
X */
X
X#include "types.h"
X#include "dvi.h"
X#include "dviclass.h"
X#include "dvicodes.h"
X#include "fio.h"
X#include "search.h"
X#include <stdio.h>
X#include <ctype.h>
X
Xchar  *ProgName;
Xextern int   errno;
Xextern char *optarg;
Xextern int   optind;
X
X/* Globals */
Xchar	serrbuf[BUFSIZ];	/* buffer for stderr */
X
X/*
X * We will try to keep output lines shorter than MAXCOL characters.
X */
X#define MAXCOL	75
X
X/*
X * We use the following structure to keep track of fonts we have seen.
X * The final DVI file lists only the fonts it uses.
X */
Xstruct fontinfo {
X	i32	fi_newindex;	/* font number in output file */
X	int	fi_reallyused;	/* true => used on a page we copied */
X	i32	fi_checksum;	/* the checksum */
X	i32	fi_mag;		/* the magnification */
X	i32	fi_designsize;	/* the design size */
X	short	fi_n1;		/* the name header length */
X	short	fi_n2;		/* the name body length */
X	char	*fi_name;	/* the name itself */
X};
X
X/*
X * We need to remember which pages the user would like.  We build a linked
X * list that allows us to decide (for any given page) whether it should
X * be included in the output file.  Each page has ten \count variables
X * associated with it.  We put a bound on the values allowed for each, and
X * keep a linked list of alternatives should any be outside the allowed
X * range.  For example, `dviselect *.3,10-15' would generate a two-element
X * page list, with the first allowing any value for \count0 (and \counts 2 to
X * 9) but \count1 restricted to the range 3-3, and the second restricting
X * \count0 to the range 10-15 but leaving \counts 1 to 9 unrestrained.
X *
X * In case no bound is specified, the `nol' or `noh' flag is set (so that
X * we need not fix some `large' number as a maximum value).
X *
X * We also allow `absolute' page references, where the first page is
X * page 1, the second 2, and so forth.  These are specified with an
X * equal sign: `dviselect =4:10' picks up the fourth through tenth
X * sequential pages, irrespective of \count values.
X */
Xstruct pagesel {
X	i32	ps_low;		/* lower bound */
X	int	ps_nol;		/* true iff no lower bound */
X	i32	ps_high;	/* upper bound */
X	int	ps_noh;		/* true iff no upper bound */
X};
Xstruct pagelist {
X	struct	pagelist *pl_alt;	/* next in a series of alternates */
X	int	pl_len;			/* number of ranges to check */
X	int	pl_abs;			/* true iff absolute page ref */
X	struct	pagesel pl_pages[10];	/* one for each \count variable */
X};
X
Xint	SFlag;			/* true => -s, silent operation */
X
Xstruct	search *FontFinder;	/* maps from input indicies to fontinfo */
Xi32	NextOutputFontIndex;	/* generates output indicies */
Xi32	CurrentFontIndex;	/* current (old) index in input */
Xi32	OutputFontIndex;	/* current (new) index in ouput */
X
Xstruct	pagelist *PageList;	/* the list of allowed pages */
X
XFILE	*inf;			/* the input DVI file */
XFILE	*outf;			/* the output DVI file */
X
Xint	ExpectBOP;		/* true => BOP ok */
Xint	ExpectEOP;		/* true => EOP ok */
X
Xlong	StartOfLastPage;	/* The file position just before we started
X				   the last page (this is later written to
X				   the output file as the previous page
X				   pointer). */
Xlong	CurrentPosition;	/* The current position of the file */
X
Xint	UseThisPage;		/* true => current page is selected */
X
Xi32	InputPageNumber;	/* current absolute page in old DVI file */
Xint	NumberOfOutputPages;	/* number of pages in new DVI file */
X
Xi32	Numerator;		/* numerator from DVI file */
Xi32	Denominator;		/* denominator from DVI file */
Xi32	DVIMag;			/* magnification from DVI file */
X
Xi32	Count[10];		/* the 10 \count variables */
X
X/* save some string space: we use this a lot */
Xchar	writeerr[] = "error writing DVI file";
X
Xchar	*malloc(), *realloc(), *sprintf();
X
X/*
X * lint gets rather confused with the current definitions of getc and putc,
X * so we redefine them here (#if lint).  This should really be in the
X * standard I/O library, but I am not about to go change it now!
X */
X#ifdef lint
X#undef putc
X#undef getc
X#define putc(c,f) (*(f)->_ptr++ = (unsigned) (c))
X#define getc(f)   (*(f)->_ptr++)
X#endif
X
X/*
X * Return true iff the 10 \counts are one of the desired output pages.
X */
XDesiredPageP()
X{
X	register struct pagelist *pl;
X
X	for (pl = PageList; pl != NULL; pl = pl->pl_alt) {
X		register struct pagesel *ps = pl->pl_pages;
X		register int i;
X		register i32 *pagep;
X
X		pagep = pl->pl_abs ? &InputPageNumber : &Count[0];
X		for (i = 0; i < pl->pl_len; i++, ps++, pagep++)
X			if (!ps->ps_nol && *pagep < ps->ps_low ||
X			    !ps->ps_noh && *pagep > ps->ps_high)
X				break;	/* not within bounds */
X		if (i >= pl->pl_len)
X			return (1);	/* success */
X	}
X	return (0);
X}
X
X/*
X * Print a message to stderr, with an optional leading space, and handling
X * long line wraps.
X */
Xmessage(space, str, len)
X	int space;
X	register char *str;
X	register int len;
X{
X	static int beenhere;
X	static int col;
X
X	if (!beenhere)
X		space = 0, beenhere++;
X	if (len == 0)
X		len = strlen(str);
X	col += len;
X	if (space) {
X		if (col >= MAXCOL)
X			(void) putc('\n', stderr), col = len;
X		else
X			(void) putc(' ', stderr), col++;
X	}
X	while (--len >= 0)
X		(void) putc(*str++, stderr);
X	(void) fflush(stderr);
X}
X
X/*
X * Start a page (process a DVI_BOP).
X */
XBeginPage()
X{
X	register i32 *i;
X
X	if (!ExpectBOP)
X		GripeUnexpectedOp("BOP");
X	ExpectBOP = 0;
X	ExpectEOP++;		/* set the new "expect" state */
X
X	OutputFontIndex = -1;	/* new page requires respecifying font */
X	InputPageNumber++;	/* count it */
X	for (i = Count; i < &Count[10]; i++)
X		fGetLong(inf, *i);
X	(void) GetLong(inf);	/* previous page pointer */
X
X	if ((UseThisPage = DesiredPageP()) == 0)
X		return;
X
X	(void) putc(DVI_BOP, outf);
X	for (i = Count; i < &Count[10]; i++)
X		PutLong(outf, *i);
X	PutLong(outf, StartOfLastPage);
X	if (ferror(outf))
X		error(1, errno, writeerr);
X
X	StartOfLastPage = CurrentPosition;
X	CurrentPosition += 45;	/* we just wrote this much */
X
X	if (!SFlag) {		/* write nice page usage messages */
X		register int z = 0;
X		register int mlen = 0;
X		char msg[80];
X
X		(void) sprintf(msg, "[%d", Count[0]);
X		mlen = strlen(msg);
X		for (i = &Count[1]; i < &Count[10]; i++) {
X			if (*i == 0) {
X				z++;
X				continue;
X			}
X			while (--z >= 0)
X				msg[mlen++] = '.', msg[mlen++] = '0';
X			z = 0;
X			(void) sprintf(msg + mlen, ".%d", *i);
X			mlen += strlen(msg + mlen);
X		}
X		message(1, msg, mlen);
X	}
X}
X
X/*
X * End a page (process a DVI_EOP).
X */
XEndPage()
X{
X	if (!ExpectEOP)
X		GripeUnexpectedOp("EOP");
X	ExpectEOP = 0;
X	ExpectBOP++;
X
X	if (!UseThisPage)
X		return;
X
X	if (!SFlag)
X		message(0, "]", 1);
X
X	putc(DVI_EOP, outf);
X	if (ferror(outf))
X		error(1, errno, writeerr);
X	CurrentPosition++;
X	NumberOfOutputPages++;
X}
X
X/*
X * For each of the fonts used in the new DVI file, write out a definition.
X */
X/* ARGSUSED */
XPostAmbleFontEnumerator(addr, key)
X	char *addr;
X	i32 key;
X{
X
X	if (((struct fontinfo *) addr)->fi_reallyused)
X		WriteFont((struct fontinfo *) addr);
X}
X
XHandlePostAmble()
X{
X	register i32 c;
X
X	(void) GetLong(inf);	/* previous page pointer */
X	if (GetLong(inf) != Numerator)
X		GripeMismatchedValue("numerator");
X	if (GetLong(inf) != Denominator)
X		GripeMismatchedValue("denominator");
X	if (GetLong(inf) != DVIMag)
X		GripeMismatchedValue("\\magfactor");
X
X	putc(DVI_POST, outf);
X	PutLong(outf, StartOfLastPage);
X	PutLong(outf, Numerator);
X	PutLong(outf, Denominator);
X	PutLong(outf, DVIMag);
X	c = GetLong(inf);
X	PutLong(outf, c);	/* tallest page height */
X	c = GetLong(inf);
X	PutLong(outf, c);	/* widest page width */
X	c = GetWord(inf);
X	PutWord(outf, c);	/* DVI stack size */
X	PutWord(outf, NumberOfOutputPages);
X	StartOfLastPage = CurrentPosition;	/* point at post */
X	CurrentPosition += 29;	/* count all those `put's */
X#ifdef notdef
X	(void) GetWord(inf);	/* skip original number of pages */
X#endif
X
X	/*
X	 * just ignore all the incoming font definitions; we are done with
X	 * input file 
X	 */
X
X	/*
X	 * run through the FontFinder table and dump definitions for the
X	 * fonts we have used. 
X	 */
X	SEnumerate(FontFinder, PostAmbleFontEnumerator);
X
X	putc(DVI_POSTPOST, outf);
X	PutLong(outf, StartOfLastPage);	/* actually start of postamble */
X	putc(DVI_VERSION, outf);
X	putc(DVI_FILLER, outf);
X	putc(DVI_FILLER, outf);
X	putc(DVI_FILLER, outf);
X	putc(DVI_FILLER, outf);
X	CurrentPosition += 10;
X	while (CurrentPosition & 3)
X		putc(DVI_FILLER, outf), CurrentPosition++;
X	if (ferror(outf))
X		error(1, errno, writeerr);
X}
X
X/*
X * Write a font definition to the output file
X */
XWriteFont(fi)
X	register struct fontinfo *fi;
X{
X	register int l;
X	register char *s;
X
X	if (fi->fi_newindex < 256) {
X		putc(DVI_FNTDEF1, outf);
X		putc(fi->fi_newindex, outf);
X		CurrentPosition += 2;
X	} else if (fi->fi_newindex < 65536) {
X		putc(DVI_FNTDEF2, outf);
X		PutWord(outf, fi->fi_newindex);
X		CurrentPosition += 3;
X	} else if (fi->fi_newindex < 16777216) {
X		putc(DVI_FNTDEF3, outf);
X		Put3Byte(outf, fi->fi_newindex);
X		CurrentPosition += 4;
X	} else {
X		putc(DVI_FNTDEF4, outf);
X		PutLong(outf, fi->fi_newindex);
X		CurrentPosition += 5;
X	}
X	PutLong(outf, fi->fi_checksum);
X	PutLong(outf, fi->fi_mag);
X	PutLong(outf, fi->fi_designsize);
X	putc(fi->fi_n1, outf);
X	putc(fi->fi_n2, outf);
X	l = fi->fi_n1 + fi->fi_n2;
X	CurrentPosition += 14 + l;
X	s = fi->fi_name;
X	while (--l >= 0)
X		putc(*s, outf), s++;
X}
X
X/*
X * Handle the preamble.  Someday we should update the comment field.
X */
XHandlePreAmble()
X{
X	register int n, c;
X
X	if (GetByte(inf) != Sign8(DVI_PRE))
X		GripeMissingOp("PRE");
X	if (GetByte(inf) != Sign8(DVI_VERSION))
X		GripeMismatchedValue("DVI version number");
X	Numerator = GetLong(inf);
X	Denominator = GetLong(inf);
X	DVIMag = GetLong(inf);
X	putc(DVI_PRE, outf);
X	putc(DVI_VERSION, outf);
X	PutLong(outf, Numerator);
X	PutLong(outf, Denominator);
X	PutLong(outf, DVIMag);
X
X	n = UnSign8(GetByte(inf));
X	CurrentPosition = 15 + n;	/* well, almost */
X	putc(n, outf);
X	while (--n >= 0) {
X		c = GetByte(inf);
X		putc(c, outf);	/* never trust a macro, I always say */
X	}
X}
X
Xmain(argc, argv)
X	int argc;
X	register char **argv;
X{
X	register int c;
X	register char *s;
X	char *inname = NULL, *outname = NULL;
X
X	ProgName = *argv;
X	setbuf(stderr, serrbuf);
X
X	while ((c = getopt(argc, argv, "i:o:s")) != EOF) {
X		switch (c) {
X
X		case 's':	/* silent */
X			SFlag++;
X			break;
X
X		case 'i':
X			if (inname != NULL)
X				goto usage;
X			inname = optarg;
X			break;
X
X		case 'o':
X			if (outname != NULL)
X				goto usage;
X			outname = optarg;
X			break;
X
X		case '?':
Xusage:
X			fprintf(stderr, "\
XUsage: %s [-s] [-i infile] [-o outfile] pages [...] [infile [outfile]]\n",
X				ProgName);
X			(void) fflush(stderr);
X			exit(1);
X		}
X	}
X
X	while (optind < argc) {
X		s = argv[optind++];
X		c = *s;
X		if (!isalpha(c) && c != '/') {
X			if (ParsePages(s))
X				goto usage;
X		} else if (inname == NULL)
X			inname = s;
X		else if (outname == NULL)
X			outname = s;
X		else
X			goto usage;
X	}
X	if (PageList == NULL)
X		goto usage;
X	if (inname == NULL)
X		inf = stdin;
X	else if ((inf = fopen(inname, "r")) == 0)
X		error(1, errno, "cannot read %s", inname);
X	if (outname == NULL)
X		outf = stdout;
X	else if ((outf = fopen(outname, "w")) == 0)
X		error(1, errno, "cannot write %s", outname);
X
X	if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
X		error(1, 0, "cannot create font finder (out of memory?)");
X
X	ExpectBOP++;
X	StartOfLastPage = -1;
X	HandlePreAmble();
X	HandleDVIFile();
X	HandlePostAmble();
X	if (!SFlag)
X		fprintf(stderr, "\nWrote %d pages, %d bytes\n",
X			NumberOfOutputPages, CurrentPosition);
X	exit(0);
X}
X
Xstruct pagelist *
XInstallPL(ps, n, absolute)
X	register struct pagesel *ps;
X	register int n;
X	int absolute;
X{
X	register struct pagelist *pl;
X
X	pl = (struct pagelist *) malloc(sizeof *pl);
X	if (pl == NULL)
X		GripeOutOfMemory(sizeof *pl, "page list");
X	pl->pl_alt = PageList;
X	PageList = pl;
X	pl->pl_len = n;
X	while (--n >= 0)
X		pl->pl_pages[n] = ps[n];
X	pl->pl_abs = absolute;
X}
X
X/*
X * Parse a string representing a list of pages.  Return 0 iff ok.  As a
X * side effect, the page selection(s) is (are) prepended to PageList.
X */
XParsePages(s)
X	register char *s;
X{
X	register struct pagesel *ps;
X	register int c;		/* current character */
X	register i32 n;		/* current numeric value */
X	register int innumber;	/* true => gathering a number */
X	int i;			/* next index in page select list */
X	int range;		/* true => saw a range indicator */
X	int negative;		/* true => number being built is negative */
X	int absolute;		/* true => absolute, not \count */
X	struct pagesel pagesel[10];
X
X#define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',')
X
X	range = 0;
X	innumber = 0;
X	absolute = 0;
X	i = 0;
X	ps = pagesel;
X	/*
X	 * Talk about ad hoc!  (Not to mention convoluted.)
X	 */
X	for (;;) {
X		c = *s++;
X		if (i == 0 && !innumber && !range) {
X			/* nothing special going on */
X			if (c == 0)
X				return 0;
X			if (white(c))
X				continue;
X		}
X		if (c == '_') {
X			/* kludge: should be '-' for negatives */
X			if (innumber || absolute)
X				return (-1);
X			innumber++;
X			negative = 1;
X			n = 0;
X			continue;
X		}
X		if (c == '=') {
X			/* absolute page */
X			if (innumber || range || i > 0)
X				return (-1);
X			absolute++;
X			/*
X			 * Setting innumber means that there is always
X			 * a lower bound, but this is all right since
X			 * `=:4' is treated as if it were `=0:4'.  As
X			 * there are no negative absolute page numbers,
X			 * this selects pages 1:4, which is the proper
X			 * action.
X			 */
X			innumber++;
X			negative = 0;
X			n = 0;
X			continue;
X		}
X		if (isdigit(c)) {
X			/* accumulate numeric value */
X			if (!innumber) {
X				innumber++;
X				negative = 0;
X				n = c - '0';
X				continue;
X			}
X			n *= 10;
X			n += negative ? '0' - c : c - '0';
X			continue;
X		}
X		if (c == '-' || c == ':') {
X			/* here is a range */
X			if (range)
X				return (-1);
X			if (innumber) {	/* have a lower bound */
X				ps->ps_low = n;
X				ps->ps_nol = 0;
X			} else
X				ps->ps_nol = 1;
X			range++;
X			innumber = 0;
X			continue;
X		}
X		if (c == '*') {
X			/* no lower bound, no upper bound */
X			c = *s++;
X			if (innumber || range || i >= 10 ||
X			    (c && c != '.' && !white(c)))
X				return (-1);
X			ps->ps_nol = 1;
X			ps->ps_noh = 1;
X			goto finishnum;
X		}
X		if (c == 0 || c == '.' || white(c)) {
X			/* end of this range */
X			if (i >= 10)
X				return (-1);
X			if (!innumber) {	/* no upper bound */
X				ps->ps_noh = 1;
X				if (!range)	/* no lower bound either */
X					ps->ps_nol = 1;
X			} else {		/* have an upper bound */
X				ps->ps_high = n;
X				ps->ps_noh = 0;
X				if (!range) {
X					/* no range => lower bound == upper */
X					ps->ps_low = ps->ps_high;
X					ps->ps_nol = 0;
X				}
X			}
Xfinishnum:
X			i++;
X			if (c == '.') {
X				if (absolute)
X					return (-1);
X				ps++;
X			} else {
X				InstallPL(pagesel, i, absolute);
X				ps = pagesel;
X				i = 0;
X				absolute = 0;
X			}
X			if (c == 0)
X				return (0);
X			range = 0;
X			innumber = 0;
X			continue;
X		}
X		/* illegal character */
X		return (-1);
X	}
X#undef white
X}
X
X/*
X * Handle a font definition.
X */
XHandleFontDef(index)
X	i32 index;
X{
X	register struct fontinfo *fi;
X	register int i;
X	register char *s;
X	int def = S_CREATE | S_EXCL;
X
X	if ((fi = (struct fontinfo *) SSearch(FontFinder, index, &def)) == 0)
X		if (def & S_COLL)
X			error(1, 0, "font %d already defined", index);
X		else
X			error(1, 0, "cannot stash font %d (out of memory?)",
X				index);
X	fi->fi_reallyused = 0;
X	fi->fi_checksum = GetLong(inf);
X	fi->fi_mag = GetLong(inf);
X	fi->fi_designsize = GetLong(inf);
X	fi->fi_n1 = UnSign8(GetByte(inf));
X	fi->fi_n2 = UnSign8(GetByte(inf));
X	i = fi->fi_n1 + fi->fi_n2;
X	if ((s = malloc((unsigned) i)) == 0)
X		GripeOutOfMemory(i, "font name");
X	fi->fi_name = s;
X	while (--i >= 0)
X		*s++ = GetByte(inf);
X}
X
X/*
X * Handle a \special.
X */
XHandleSpecial(c, l, p)
X	int c;
X	register int l;
X	register i32 p;
X{
X	register int i;
X
X	if (UseThisPage) {
X		putc(c, outf);
X		switch (l) {
X
X		case DPL_UNS1:
X			putc(p, outf);
X			CurrentPosition += 2;
X			break;
X
X		case DPL_UNS2:
X			PutWord(outf, p);
X			CurrentPosition += 3;
X			break;
X
X		case DPL_UNS3:
X			Put3Byte(outf, p);
X			CurrentPosition += 4;
X			break;
X
X		case DPL_SGN4:
X			PutLong(outf, p);
X			CurrentPosition += 5;
X			break;
X
X		default:
X			panic("HandleSpecial l=%d", l);
X			/* NOTREACHED */
X		}
X		CurrentPosition += p;
X		while (--p >= 0) {
X			i = getc(inf);
X			putc(i, outf);
X		}
X		if (feof(inf))
X			error(1, 0, "unexpected EOF");
X		if (ferror(outf))
X			error(1, errno, writeerr);
X	} else
X		while (--p >= 0)
X			(void) getc(inf);
X}
X
XReallyUseFont()
X{
X	register struct fontinfo *fi;
X	int look = S_LOOKUP;
X
X	fi = (struct fontinfo *) SSearch(FontFinder, CurrentFontIndex, &look);
X	if (fi == 0)
X		error(1, 0, "index %d not in font table!", CurrentFontIndex);
X	if (fi->fi_reallyused == 0) {
X		fi->fi_reallyused++;
X		fi->fi_newindex = NextOutputFontIndex++;
X		WriteFont(fi);
X	}
X	if (fi->fi_newindex != OutputFontIndex) {
X		PutFontSelector(fi->fi_newindex);
X		OutputFontIndex = fi->fi_newindex;
X	}
X}
X
X/*
X * Write a font selection command to the output file
X */
XPutFontSelector(index)
X	i32 index;
X{
X
X	if (index < 64) {
X		putc(index + DVI_FNTNUM0, outf);
X		CurrentPosition++;
X	} else if (index < 256) {
X		putc(DVI_FNT1, outf);
X		putc(index, outf);
X		CurrentPosition += 2;
X	} else if (index < 65536) {
X		putc(DVI_FNT2, outf);
X		PutWord(outf, index);
X		CurrentPosition += 3;
X	} else if (index < 16777216) {
X		putc(DVI_FNT3, outf);
X		Put3Byte(outf, index);
X		CurrentPosition += 4;
X	} else {
X		putc(DVI_FNT4, outf);
X		PutLong(outf, index);
X		CurrentPosition += 5;
X	}
X}
X
X/*
X * The following table describes the length (in bytes) of each of the DVI
X * commands that we can simply copy, starting with DVI_SET1 (128).
X */
Xchar	oplen[128] = {
X	0, 0, 0, 0,		/* DVI_SET1 .. DVI_SET4 */
X	9,			/* DVI_SETRULE */
X	0, 0, 0, 0,		/* DVI_PUT1 .. DVI_PUT4 */
X	9,			/* DVI_PUTRULE */
X	1,			/* DVI_NOP */
X	0,			/* DVI_BOP */
X	0,			/* DVI_EOP */
X	1,			/* DVI_PUSH */
X	1,			/* DVI_POP */
X	2, 3, 4, 5,		/* DVI_RIGHT1 .. DVI_RIGHT4 */
X	1,			/* DVI_W0 */
X	2, 3, 4, 5,		/* DVI_W1 .. DVI_W4 */
X	1,			/* DVI_X0 */
X	2, 3, 4, 5,		/* DVI_X1 .. DVI_X4 */
X	2, 3, 4, 5,		/* DVI_DOWN1 .. DVI_DOWN4 */
X	1,			/* DVI_Y0 */
X	2, 3, 4, 5,		/* DVI_Y1 .. DVI_Y4 */
X	1,			/* DVI_Z0 */
X	2, 3, 4, 5,		/* DVI_Z1 .. DVI_Z4 */
X	0,			/* DVI_FNTNUM0 (171) */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 172 .. 179 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 180 .. 187 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 188 .. 195 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 196 .. 203 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 204 .. 211 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 212 .. 219 */
X	0, 0, 0, 0, 0, 0, 0, 0,	/* 220 .. 227 */
X	0, 0, 0, 0, 0, 0, 0,	/* 228 .. 234 */
X	0, 0, 0, 0,		/* DVI_FNT1 .. DVI_FNT4 */
X	0, 0, 0, 0,		/* DVI_XXX1 .. DVI_XXX4 */
X	0, 0, 0, 0,		/* DVI_FNTDEF1 .. DVI_FNTDEF4 */
X	0,			/* DVI_PRE */
X	0,			/* DVI_POST */
X	0,			/* DVI_POSTPOST */
X	0, 0, 0, 0, 0, 0,	/* 250 .. 255 */
X};
X
X/*
X * Here we read the input DVI file and write relevant pages to the
X * output DVI file. We also keep track of font changes, handle font
X * definitions, and perform some other housekeeping.
X */
XHandleDVIFile()
X{
X	register int c, l;
X	register i32 p;
X	register int CurrentFontOK = 0;
X
X	/* Only way out is via "return" statement */
X	for (;;) {
X		c = getc(inf);	/* getc() returns unsigned values */
X		if (DVI_IsChar(c)) {
X			/*
X			 * Copy chars, note font usage, but ignore if
X			 * page is not interesting.
X			 */
X			if (!UseThisPage)
X				continue;
X			if (!CurrentFontOK) {
X				ReallyUseFont();
X				CurrentFontOK++;
X			}
X			putc(c, outf);
X			CurrentPosition++;
X			continue;
X		}
X		if (DVI_IsFont(c)) {	/* note font change */
X			CurrentFontIndex = c - DVI_FNTNUM0;
X			CurrentFontOK = 0;
X			continue;
X		}
X		if ((l = (oplen - 128)[c]) != 0) {	/* simple copy */
X			if (!UseThisPage) {
X				while (--l > 0)
X					(void) getc(inf);
X				continue;
X			}
X			CurrentPosition += l;
X			putc(c, outf);
X			while (--l > 0) {
X				c = getc(inf);
X				putc(c, outf);
X			}
X			if (ferror(outf))
X				error(1, errno, writeerr);
X			continue;
X		}
X		if ((l = DVI_OpLen(c)) != 0) {
X			/*
X			 * Handle other generics.
X			 * N.B.: there should only be unsigned parameters
X			 * here (save SGN4), for commands with negative
X			 * parameters have been taken care of above.
X			 */
X			switch (l) {
X
X			case DPL_UNS1:
X				p = getc(inf);
X				break;
X
X			case DPL_UNS2:
X				fGetWord(inf, p);
X				break;
X
X			case DPL_UNS3:
X				fGet3Byte(inf, p);
X				break;
X
X			case DPL_SGN4:
X				fGetLong(inf, p);
X				break;
X
X			default:
X				panic("HandleDVIFile l=%d", l);
X			}
X
X			/*
X			 * Now that we have the parameter, perform the
X			 * command.
X			 */
X			switch (DVI_DT(c)) {
X
X			case DT_SET:
X			case DT_PUT:
X				if (!UseThisPage)
X					continue;
X				if (!CurrentFontOK) {
X					ReallyUseFont();
X					CurrentFontOK++;
X				}
X				putc(c, outf);
X				switch (l) {
X
X				case DPL_UNS1:
X					putc(p, outf);
X					CurrentPosition += 2;
X					continue;
X
X				case DPL_UNS2:
X					PutWord(outf, p);
X					CurrentPosition += 3;
X					continue;
X
X				case DPL_UNS3:
X					Put3Byte(outf, p);
X					CurrentPosition += 4;
X					continue;
X
X				case DPL_SGN4:
X					PutLong(outf, p);
X					CurrentPosition += 5;
X					continue;
X				}
X
X			case DT_FNT:
X				CurrentFontIndex = p;
X				CurrentFontOK = 0;
X				continue;
X
X			case DT_XXX:
X				HandleSpecial(c, l, p);
X				continue;
X
X			case DT_FNTDEF:
X				HandleFontDef(p);
X				continue;
X
X			default:
X				panic("HandleDVIFile DVI_DT(%d)=%d",
X				      c, DVI_DT(c));
X			}
X			continue;
X		}
X
X		switch (c) {	/* handle the few remaining cases */
X
X		case DVI_BOP:
X			BeginPage();
X			CurrentFontOK = 0;
X			break;
X
X		case DVI_EOP:
X			EndPage();
X			break;
X
X		case DVI_PRE:
X			GripeUnexpectedOp("PRE");
X			/* NOTREACHED */
X
X		case DVI_POST:
X			return;
X
X		case DVI_POSTPOST:
X			GripeUnexpectedOp("POSTPOST");
X			/* NOTREACHED */
X
X		default:
X			GripeUndefinedOp(c);
X			/* NOTREACHED */
X		}
X	}
X}
END_OF_dviselect.c.orig
if test 22164 -ne `wc -c <dviselect.c.orig`; then
    echo shar: \"dviselect.c.orig\" unpacked with wrong size!
fi
chmod +x dviselect.c.orig
# end of overwriting check
fi
if test ! -d h ; then
    echo shar: Creating directory \"h\"
    mkdir h
fi
if test ! -d lib ; then
    echo shar: Creating directory \"lib\"
    mkdir lib
fi
echo shar: End of archive 1 \(of 6\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    echo "Now do 'make dviselect'"
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
--
Skip Montanaro (montanaro at crdgw1.ge.com)



More information about the Alt.sources mailing list