DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T p

⟦f4a92f4c4⟧ TextFile

    Length: 30938 (0x78da)
    Types: TextFile
    Names: »postscript.c«

Derivation

└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z« 
        └─⟦ca79c7339⟧ 
            └─⟦this⟧ »DVIware/laser-setters/mctex/postscript/postscript.c« 

TextFile

/*
 * Copyright (c) 1987, 1989 University of Maryland
 * Department of Computer Science.  All rights reserved.
 * Permission to copy for any purpose is hereby granted
 * so long as this copyright notice remains intact (but see below.)
 * This program is derived from one by Louis A. Mamakos,
 * and prior copyrights appearing below must also be observed.
 *
 * Note that this version differs substantially from his and
 * spelling and/or logic errors may be due to other authors.
 */

/*
 *  Copyright (c) 1988 Louis A. Mamakos, all rights reserved.  Permission is
 *  granted for use and redistribution of this program for no charge.  This
 *  program, nor any derivations or version may not be sold.  This program, or
 *  and version of it may not be distributed for commercial purposes without
 *  specific prior permission.
 *
 *  Comments/flames to:  Louis A. Mamakos
 *			 <louie@TRANTOR.UMD.EDU>
 *
 *
 *  Derived from, and many thanks to:
 *	Chris Torek for his fine imagen driver and font library routines.
 *	Nelson Beebe for the PostScript output file macros (OUT_*) and for a
 *	start on the PostScript prologue.
 */

/*
 * DVI to Adobe PostScript
 *
 * Reads DVI version 2 files and converts to PostScript commands (and
 * associated prologue) for use on postscript printers.
 *
 * Currently, we make two passes over each page in the DVI file.  During
 * pass 0, we dump font definitions for the characters used on the page,
 * but for which no character has been dumped to the printer.  In pass 1
 * we actually set the text.
 *
 * This foolishness is done so we can encapulate all of the actual typesetting
 * commands inside of a save/restore pair; this enables us to recover most of
 * the printer's VM resources used. Since it would be desirable to use the
 * fonts on more that one page, these have to be dumped to the printer outside
 * the save/restore pair.
 *
 * TODO:
 *	think about fonts with characters outside [0..255]
 *	landscape mode setup
 *	something more reasonable for \special{}
 */

#ifndef lint
static char RCSid[] = "$Header: /usr/src/local/tex/local/mctex/postscript/RCS/postscript.c,v 3.10 89/11/29 03:20:24 chris Exp $";
#endif

#include <stdio.h>
#include <ctype.h>
#include "types.h"
#include "conv.h"
#include "dviclass.h"
#include "dvicodes.h"
#include "error.h"
#include "fio.h"
#include "font.h"
#include "gripes.h"
#include "sdecode.h"
#include "dvistate.h"

#include "postscript.h"

/*
 * List of valid document options (specified by the -o option).
 * When an option `opt' is specified, a PostScript macro named `@opt'
 * is invoked.  The definition for this option must either be in the
 * prologue file or permanently installed in the printer.
 *
 * The array PScommands[] holds pointers to any options selected.
 * Since only those listed here can be selected, that array is the
 * same size as this one (both include a NULL terminator).
 */
char *documentoptions[] = {
	"a4",
	"a4size",
	"draft",
	"landscape",
	"legal",
	"legalsize",
	"letter",
	"lettersize",
	"manualfeed",
	"note",
	"notesize",
	NULL
};
#define	MAXOPTIONS (sizeof documentoptions / sizeof *documentoptions)

/*
 * The following ugliness makes the program run faster if	XXX
 * stdio has a fast_putc macro for fully-buffered streams.	XXX
 * Below that is an example of a fast putc macro for 4.3BSD.	XXX
 */
#ifndef lint
#ifdef fast_putc
#undef putc
#define putc(x,f) fast_putc(x,f)
#else
#ifdef STDIO_HAS_FUNOPEN
#undef putc
#define putc(x,f) \
 (--(f)->_cnt < 0 ? _flsbuf((unsigned char)(x), f) : (*(f)->_ptr++ = (x)))
#endif
#endif /* fast_putc */
#endif /* lint */

char *Version = "DVI-Postscript translator, version ";
#define VERSION	1

void Copy(), DownLoadGlyph(), ReadPSFontMap();

extern char *optarg;
extern int optind;
extern char *strsave(), *getenv(), *malloc();

/*
 * We mark fonts as being a internal PostScript printer fonts using one
 * of the per-font user flags.  Another flag remembers whether the font
 * has as yet been defined.
 */
#define	FF_POSTSCRIPT	FF_USR0
#define	FF_DEFINED	FF_USR1

struct BuiltIn {
	struct BuiltIn *next;	/* link to next */
	char *TeXname;		/* TeX name of PostScript font */
	char *PSname;		/* Actual PostScript font name */
	char *Init;		/* Optional PostScript init string */
} *BuiltIns;

struct BuiltIn *IsBuiltIn();

int	UsingBuiltInFonts;	/* true iff we are using some built-in fonts */

char	*PScommands[MAXOPTIONS];

char	*ps_dir = PS_DIR;	/* PostScript library directory */
char	*prologue = PROLOGUE;	/* regular PostScript prologue */
char	*psf_pro = PSF_PROLOGUE;/* additional prologue if using built-ins */

#define	MAXPROLOGUES	20		/* XXX */
int	npro = 0;
char	*PSprologues[MAXPROLOGUES];	/* prologue files to include */

char	*ProgName;
char	*DVIFileName;
char	serrbuf[BUFSIZ];	/* buffer for stderr */
#ifdef notdef
char	dvibuf[8192];
#endif

int	copies;			/* -c => number of copies of each page */
char	*PrintEngine;		/* -e => print engine */
int	ReversePages;		/* -p => [no] page reversal */
int	SFlag;			/* -s => silent (no page numbers) */
int	Debug;			/* -D => secret debug flag */

int	pageno;			/* physical page counter */

int	in_string;		/* "in" a string currrently */
int	Postscript_HH;		/* printer's horizontal position */
int	Postscript_VV;		/* printer's vertical position */

int	delta[4], dswitch;	/* see SetPosition() */

/*
 * Add a document option to the list to send to the printer,
 * validating it first.
 */
void
AddOption(opt)
	register char *opt;
{
	register char **s;
	char **freeslot;

	/*
	 * First see if we already have it.
	 * If so, quietly ignore it; otherwise validate.
	 */
	for (s = PScommands; *s; s++)
		if (strcmp(*s, opt) == 0)
			return;
	freeslot = s;
	for (s = documentoptions; *s; s++)  {
		if (strcmp(*s, opt) == 0) {
			/* okay, use it */
			*freeslot = *s;
			return;
		}
	}
	error(0, 0, "Warning: invalid document option `%s' ignored", opt);
}

/*
 * Here is how to write a string.
 * This is very much like fputs(..., stdout),
 * except that the strings are typically very short
 * and we save on overhead (by having fewer arguments).
 */
void
put(s)
	register char *s;
{

	while (*s)
		putbyte(stdout, *s++);
}

/*
 * End the current (PostScript) string.
 */
void
EndString()
{

	if (in_string) {
		put(")S\n");
		in_string = 0;
	}
}

/*
 * Set the printer's h & v positions.  It is currently  at
 * (Postscript_HH, Postscript_VV).
 *
 * We have several positioning commands at our disposal:
 *	move to absolute x/y position
 *	move relative x
 *	show string and move relative by -4..+4
 *	show string and move previous dx (4 saved delta values)
 *	show string, set dx, and move dx (4 saved delta values)
 * If we have to move vertically, we use absolute positioning.
 * Otherwise, we try to use a `show string and move', and if that
 * fails, we use one of the four `delta savers', in the hope that
 * one of those dx savers will match the next move.  Typically
 * interword spacing takes one of two values, hence the four saved
 * delta-x values wind up holding both possible spacings, and we
 * get a series of the form `(foo)D (bar)E (baz)D'.
 *
 * This is invoked from within the main put-characters-on-page loop and
 * should go fast.
 *
 * Note that, if the printer is already properly positioned, this does
 * NOT end the current string (if any).
 */
#define SetPosition(hh, vv) \
	if (Postscript_VV != (vv)) { \
		if (in_string) { \
			putbyte(stdout, ')'); \
			putbyte(stdout, 'S'); \
			putbyte(stdout, '\n'); \
			in_string = 0; \
		} \
		(void) printf("%d %d p\n", hh, vv); \
		Postscript_HH = (hh); \
		Postscript_VV = (vv); \
	} else if (Postscript_HH != (hh)) { \
		register int d_ = (hh) - Postscript_HH; \
		if (in_string) { \
			putbyte(stdout, ')'); \
			if ((unsigned)d_ + 4 <= 8) \
				putbyte(stdout, "stuv wxyz"[d_ + 4]); \
			else if (d_ == delta[0]) \
				putbyte(stdout, 'D'); \
			else if (d_ == delta[1]) \
				putbyte(stdout, 'E'); \
			else if (d_ == delta[2]) \
				putbyte(stdout, 'F'); \
			else if (d_ == delta[3]) \
				putbyte(stdout, 'G'); \
			else { \
				(void) printf("%d %c", d_, "defg"[dswitch]); \
				delta[dswitch] = d_; \
				dswitch = (dswitch + 1) & 3; \
			} \
			putbyte(stdout, '\n'); \
			in_string = 0; \
		} else \
			(void) printf("%d h\n", d_); \
		Postscript_HH = (hh); \
	} else

/*
 * Slower function version.
 * Unlike SetPosition, this always ends the current string.
 */
void
SlowSetPosition(h, v)
	int h, v;
{

	SetPosition(h, v);
	EndString();
}

/*
 * Obtain and define a font (assign it a number for PostScript
 * `fnt%d' commands).  The commands to define the font in PostScript
 * will be emitted later.
 */
struct font *
DefineFont(name, dvimag, dvidsz)
	char *name;
	i32 dvimag, dvidsz;
{
	register struct font *f;
	register struct BuiltIn *bi;
	char *path, *engine;
	static int fontno;

	/*
	 * Built in printer postscript font support: there should be a
	 * line in the fontdesc file which points to a directory with
	 * the PostScript TFM files.  Something like:

    #	  TYPE	SPEC	    SLOP  PATH
    font  tfm	PostScript  0	  /usr/lib/tex/fonts/tfm/%f.tfm

	 * should work well.  Be sure to use the `tfm' font type.
	 * Just to be helpful, the print engine is passed as a
	 * generic "PostScript".
	 *
	 * XXX  should combine `PostScript' with actual engine
	 */
	if ((bi = IsBuiltIn(name)) != NULL)
		engine = "PostScript";
	else
		engine = PrintEngine;
	f = GetFont(name, dvimag, dvidsz, engine, &path);
	if (f == NULL) {
		GripeCannotGetFont(name, dvimag, dvidsz, engine, path);
		return (NULL);
	}
	if (Debug) {
		if (bi != NULL)
			(void) fprintf(stderr, "[%s -> PS Font %s TFM %s]\n",
			    Font_TeXName(f), bi->PSname, path);
		else
			(void) fprintf(stderr, "[%s -> %s]\n",
			    Font_TeXName(f), path);
		(void) fflush(stderr);
	}
	if (bi != NULL) {
		f->f_flags |= FF_POSTSCRIPT;
		UsingBuiltInFonts = 1;
	}
	f->f_un.f_int = fontno++;
	return (f);
}

/*
 * As each font is used for the first time, P0PageLoop() calls
 * DefPSFont() to create a PostScript entity describing the font.
 */
void
DefPSFont(f)
	register struct font *f;
{
	register int fontno = f->f_un.f_int;
	register struct BuiltIn *bi;

	if (f->f_flags & FF_POSTSCRIPT) {
		if ((bi = IsBuiltIn(f->f_font)) == NULL)
			panic("%s has FF_POSTSCRIPT, but IsBuiltIn()=>NULL",
			    f->f_font);
		(void) printf("%% dvi font %s mapped to %s\n",
		    Font_TeXName(f), bi->PSname);
		/* check for special init string for this postscript font */
		if (bi->Init != NULL)
			(void) printf("/%s %s\n", bi->PSname, bi->Init);
		(void) printf("\
/%s /fnt%d ReEncodeForTeX\n/fnt%d /fnt%d %f TeXPSmakefont def\n",
		    bi->PSname, fontno, fontno, fontno,
		    Conversion.c_fromsp * (double)f->f_dvimag); /* XXX */
	} else
		(void) printf("/fnt%d @newfont %% %s from %s\n",
		    fontno, Font_TeXName(f), f->f_path);
	f->f_flags |= FF_DEFINED;
}

/*
 * At various points in the code, we check for output errors (ferror(stdout))
 * and, if detected, call this routine.
 */
void
OutputFailed()
{

	/* we can only hope that errno is meaningful */
	error(1, -1, "error writing Postscript output, help");
	/* NOTREACHED */
}

/*
 * Start a new page; called from passes 0 and 1.
 */
void
BeginPage(count, pass)
	i32 *count;
	int pass;
{
	register int i;

	/*
	 * Pass all 10 counters to the @BOP procedure,
	 * and the actual page count too.
	 */
	putbyte(stdout, '[');
	for (i = 0; i < 10; i++)
		(void) printf("%ld ", (long)count[i]);
	(void) printf("%d] @BOP%d\n", pageno, pass);
}

/*
 * Begin page in pass 0.
 */
void
P0BeginPage(count)
	i32 *count;
{

	if (!SFlag) {
		static int beenhere;

		if (beenhere)
			(void) putc(' ', stderr);
		else
			beenhere++;
		(void) fprintf(stderr, "[");
		(void) fflush(stderr);
	}
	(void) printf("%%%%Page: %ld %d\n", (long)count[0], ++pageno);
	BeginPage(count, 0);
}

/*
 * Begin page in pass 1.
 */
void
P1BeginPage(count)
	i32 *count;
{

	if (!SFlag) {
		(void) fprintf(stderr, "%ld", (long)count[0]);
		(void) fflush(stderr);
	}
	BeginPage(count, 1);
	Postscript_HH = 0;
	Postscript_VV = 0;
	delta[0] = delta[1] = delta[2] = delta[3] = dswitch = 0;
}

/*
 * End the page, called only from pass 1.
 */
void
P1EndPage()
{

	if (!SFlag) {
		(void) putc(']', stderr);
		(void) fflush(stderr);
	}
	put("@EOP\n");
	if (ferror(stdout))
		OutputFailed();
}

extern void P1DoSpecial();	/* in psspecial.c */

/*
 * Set a rule at dvi_hh, dvi_vv (which is the lower left corner of the rule).
 */
void
P1SetRule(h, w)
	register i32 h, w;
{

	SlowSetPosition((int)dvi_hh, (int)dvi_vv);
	(void) printf("%ld %ld R\n", (long)w - 1, (long)h - 1);
}

/*
 * Character printing.  We can only handle characters in [0..255].
 *
 * 000-037 are control characters; 040 is space; 177 is DEL:
 * 040-077:  !"#$%&'()*+,-./0123456789:;<=>?
 * 100-137: @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
 * 140-176: `abcdefghijklmnopqrstuvwxyz{|}~
 *
 * Some codes must be expressed specially, namely nonprintables,
 * left and right parenthesis, and backslash.  The table below is
 * non-NULL for each such character, containing the representation to
 * be used instead.
 */
#define itself NULL
char *charmap[256] = {
	"\\000", "\\001", "\\002", "\\003", "\\004", "\\005", "\\006", "\\007",
	"\\b",   "\\t",   "\\n",   "\\013", "\\f",   "\\r",   "\\016", "\\017",
	"\\020", "\\021", "\\022", "\\023", "\\024", "\\025", "\\026", "\\027",
	"\\030", "\\031", "\\032", "\\033", "\\034", "\\035", "\\036", "\\037",
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  itself,
	"\\(",   "\\)",   itself,  itself,  itself,  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  "\\\\",  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  itself,
	itself,  itself,  itself,  itself,  itself,  itself,  itself,  "\\177",
	"\\200", "\\201", "\\202", "\\203", "\\204", "\\205", "\\206", "\\207",
	"\\210", "\\211", "\\212", "\\213", "\\214", "\\215", "\\216", "\\217",
	"\\220", "\\221", "\\222", "\\223", "\\224", "\\225", "\\226", "\\227",
	"\\230", "\\231", "\\232", "\\233", "\\234", "\\235", "\\236", "\\237",
	"\\240", "\\241", "\\242", "\\243", "\\244", "\\245", "\\246", "\\247",
	"\\250", "\\251", "\\252", "\\253", "\\254", "\\255", "\\256", "\\257",
	"\\260", "\\261", "\\262", "\\263", "\\264", "\\265", "\\266", "\\267",
	"\\270", "\\271", "\\272", "\\273", "\\274", "\\275", "\\276", "\\277",
	"\\300", "\\301", "\\302", "\\303", "\\304", "\\305", "\\306", "\\307",
	"\\310", "\\311", "\\312", "\\313", "\\314", "\\315", "\\316", "\\317",
	"\\320", "\\321", "\\322", "\\323", "\\324", "\\325", "\\326", "\\327",
	"\\330", "\\331", "\\332", "\\333", "\\334", "\\335", "\\336", "\\337",
	"\\340", "\\341", "\\342", "\\343", "\\344", "\\345", "\\346", "\\347",
	"\\350", "\\351", "\\352", "\\353", "\\354", "\\355", "\\356", "\\357",
	"\\360", "\\361", "\\362", "\\363", "\\364", "\\365", "\\366", "\\367",
	"\\370", "\\371", "\\372", "\\373", "\\374", "\\375", "\\376", "\\377",
};
#undef itself

#define	print_char(c) \
	if (charmap[c] != NULL) \
		put(charmap[c]); \
	else \
		putbyte(stdout, c) \

/*
 * Check the range of a character, to be sure the device can handle it.
 * Called for DVI_SET and DVI_PUT opcodes only.
 */
int
P0CheckChar(c)
	i32 c;
{

	if ((ui32)c > 255) {
		error(0, 0, "Warning: character code %ld too big",
		    (long)c);
		return (1);
	}
	return (0);
}

#define P1CheckChar(c) ((ui32)(c) > 255)

static struct font NoFont;	/* font with zero pspace, etc */

/*
 * Pass 0 page loop.  This reads one page of the DVI file.
 * Returns 1 at normal end of page, 0 at end of last page.
 * It is like the pass 1 loop, but simpler.
 * As a side effect, before it returns 1, it repositions the DVI
 * so that pass 1 can immediately start reading.
 */
int
P0PageLoop()
{
	register int c;
	register i32 p;
	register struct font *f = &NoFont;
	register FILE *fp = ds.ds_fp;
	int doingpage = 0;
	long start_at;

	if (ReversePages) {
		if (ds.ds_prevpage == -1)
			return (0);	/* Matthew 20:16 (kilroy was here) */
		(void) fseek(fp, ds.ds_prevpage, 0);
		start_at = ds.ds_prevpage;
	} else
		start_at = ftell(fp);

	/*
	 * This would be a `for (;;)', but that makes the function
	 * crawl off the right of the screen.
	 *
	 * We handle ordinary characters early, as they are the
	 * most common opcodes in DVI files, and doing so makes the
	 * loop run faster.
	 */
loop:
	c = fgetbyte(fp);
	if (DVI_IsChar(c)) {
		register struct glyph *g;

		p = c;
do_char:
		g = GLYPH(f, p);
		if (!GVALID(g)) {
			GripeBadGlyph(p, f);
			goto loop;
		}
		if ((g->g_flags & GF_SEEN) == 0) {
			g->g_pixwidth = fromSP(g->g_tfmwidth);
			g->g_flags |= GF_SEEN;
			if ((f->f_flags & FF_DEFINED) == 0)
				DefPSFont(f);
			if ((f->f_flags & FF_POSTSCRIPT) == 0 && HASRASTER(g))
				DownLoadGlyph((int)p, f, g);
		}
		goto loop;
	}

	if (c == EOF)		/* unexpected end of DVI file */
		GripeUnexpectedDVIEOF();

	/*
	 * Gather up a parameter, if known.
	 */
	switch (DVI_OpLen(c)) {

	case DPL_NONE:
		break;

	case DPL_SGN1:
		p = fgetbyte(fp);
		p = Sign8(p);
		break;

	case DPL_SGN2:
		fGetWord(fp, p);
		p = Sign16(p);
		break;

	case DPL_SGN3:
		fGet3Byte(fp, p);
		p = Sign24(p);
		break;

	case DPL_SGN4:
		fGetLong(fp, p);
		break;

	case DPL_UNS1:
		p = fgetbyte(fp);
		p = UnSign8(p);
		break;

	case DPL_UNS2:
		fGetWord(fp, p);
		p = UnSign16(p);
		break;

	case DPL_UNS3:
		fGet3Byte(fp, p);
		p = UnSign24(p);
		break;

	default:
		panic("DVI_OpLen(%d) = %d", c, DVI_OpLen(c));
		/* NOTREACHED */
	}

	/*
	 * Now switch on the type.
	 */
	switch (DVI_DT(c)) {

	case DT_SET:
	case DT_PUT:
		if (P0CheckChar(p))
			goto loop;
		goto do_char;

	case DT_SETRULE:
	case DT_PUTRULE:
		/* skip the height and width */
		fGetLong(fp, p);
		fGetLong(fp, p);
		goto loop;

	case DT_BOP:
		if (doingpage)
			GripeUnexpectedOp("BOP (already in page)");
		DVIBeginPage(P0BeginPage);
		doingpage = 1;
		goto loop;

	case DT_EOP:
		if (!doingpage)
			GripeUnexpectedOp("EOP (no BOP)");
		(void) fseek(fp, start_at, 0);
		return (1);

	case DT_NOP:
	case DT_PUSH:
	case DT_POP:
	case DT_W0:
	case DT_W:
	case DT_X0:
	case DT_X:
	case DT_RIGHT:
	case DT_Y0:
	case DT_Y:
	case DT_Z0:
	case DT_Z:
	case DT_DOWN:
		goto loop;

	case DT_FNTNUM:
		f = DVIFindFont((i32)(c - DVI_FNTNUM0));
		goto loop;

	case DT_FNT:
		f = DVIFindFont(p);
		goto loop;

	case DT_XXX:
		/* skip special on pass 0 */
		(void) fseek(fp, (long)p, 1);
		goto loop;

	case DT_FNTDEF:
		SkipFontDef(fp);
		goto loop;

	case DT_PRE:
		GripeUnexpectedOp("PRE");
		/* NOTREACHED */

	case DT_POST:
		if (doingpage) {
			GripeUnexpectedOp("POST (no EOP)");
			/* NOTREACHED */
		}
		return (0);

	case DT_POSTPOST:
		GripeUnexpectedOp("POSTPOST");
		/* NOTREACHED */

	case DT_UNDEF:
		GripeUndefinedOp(c);
		/* NOTREACHED */

	default:
		panic("DVI_DT(%d) = %d", c, DVI_DT(c));
		/* NOTREACHED */
	}
	/* NOTREACHED */
}

/*
 * Pass 1 page loop.  This re-reads one page of the DVI file.
 */
void
P1PageLoop()
{
	register int c;
	register i32 p;
	register struct font *f = &NoFont;
	register FILE *fp = ds.ds_fp;
	register int PostscriptFont = -1;
	int doingpage = 0, advance;

loop:
	c = fgetbyte(fp);
	if (DVI_IsChar(c)) {
		register struct glyph *g;

		p = c;
		advance = 1;
do_char:
		g = GLYPH(f, p);
		if (!GVALID(g)) {
			/* GripeBadGlyph(p, f); (already griped in pass 0) */
			goto loop;
		}
		if ((g->g_flags & GF_SEEN) == 0)
			panic("glyph %ld of %s not loaded in pass 0",
			    (long)p, f->f_path);
		if (f->f_flags & FF_POSTSCRIPT || HASRASTER(g)) {
			SetPosition((int)dvi_hh, (int)dvi_vv);
			/* set printer font if necessary */
			if (PostscriptFont != f->f_un.f_int) {
				if (in_string) {
					put(")S\n");
					in_string = 0;
				}
				(void) printf("fnt%d @sf\n", f->f_un.f_int);
				PostscriptFont = f->f_un.f_int;
			}
			if (!in_string) {
				putbyte(stdout, '(');
				in_string = 1;
			}
			print_char(p);
			Postscript_HH += g->g_pixwidth;
		}
		if (advance) {
			dvi_h += g->g_tfmwidth;
			dvi_hh += g->g_pixwidth;
			p = fromSP(dvi_h);
			FIXDRIFT(dvi_hh, p);
		}
		goto loop;
	}

	if (c == EOF)		/* unexpected end of DVI file */
		GripeUnexpectedDVIEOF();

	/*
	 * Gather up a parameter, if known.
	 */
	switch (DVI_OpLen(c)) {

	case DPL_NONE:
		break;

	case DPL_SGN1:
		p = fgetbyte(fp);
		p = Sign8(p);
		break;

	case DPL_SGN2:
		fGetWord(fp, p);
		p = Sign16(p);
		break;

	case DPL_SGN3:
		fGet3Byte(fp, p);
		p = Sign24(p);
		break;

	case DPL_SGN4:
		fGetLong(fp, p);
		break;

	case DPL_UNS1:
		p = fgetbyte(fp);
		p = UnSign8(p);
		break;

	case DPL_UNS2:
		fGetWord(fp, p);
		p = UnSign16(p);
		break;

	case DPL_UNS3:
		fGet3Byte(fp, p);
		p = UnSign24(p);
		break;

	default:
		panic("DVI_OpLen(%d) = %d", c, DVI_OpLen(c));
		/* NOTREACHED */
	}

	/*
	 * Now switch on the type.
	 */
	switch (DVI_DT(c)) {

	case DT_SET:
		advance = 1;
		if (P1CheckChar(p))
			goto loop;
		goto do_char;

	case DT_PUT:
		advance = 0;
		if (P1CheckChar(p))
			goto loop;
		goto do_char;

	case DT_SETRULE:
		DVIRule(P1SetRule, 1);
		goto loop;

	case DT_PUTRULE:
		DVIRule(P1SetRule, 0);
		goto loop;

	case DT_NOP:
		goto loop;

	case DT_BOP:
		if (doingpage)
			GripeUnexpectedOp("BOP (already in page)");
		EndString();
		DVIBeginPage(P1BeginPage);
		doingpage = 1;
		goto loop;

	case DT_EOP:
		if (!doingpage)
			GripeUnexpectedOp("EOP (no BOP)");
		EndString();
		P1EndPage();
		return;

	case DT_PUSH:
		*ds.ds_sp++ = ds.ds_cur;
		goto loop;

	case DT_POP:
		ds.ds_cur = *--ds.ds_sp;
		goto loop;

	case DT_W0:
		p = dvi_w;
		goto right;

	case DT_W:
		dvi_w = p;
		goto right;

	case DT_X0:
		p = dvi_x;
		goto right;

	case DT_X:
		dvi_x = p;
		goto right;

	case DT_RIGHT:
right:
		dvi_h += p;
		if (F_SMALLH(f, p)) {
			dvi_hh += fromSP(p);
			p = fromSP(dvi_h);
			FIXDRIFT(dvi_hh, p);
		} else
			dvi_hh = fromSP(dvi_h);
		goto loop;

	case DT_Y0:
		p = dvi_y;
		goto down;

	case DT_Y:
		dvi_y = p;
		goto down;

	case DT_Z0:
		p = dvi_z;
		goto down;

	case DT_Z:
		dvi_z = p;
		goto down;

	case DT_DOWN:
down:
		dvi_v += p;
		if (F_SMALLV(f, p)) {
			dvi_vv += fromSP(p);
			p = fromSP(dvi_v);
			FIXDRIFT(dvi_vv, p);
		} else
			dvi_vv = fromSP(dvi_v);
		goto loop;

	case DT_FNTNUM:
		f = DVIFindFont((i32)(c - DVI_FNTNUM0));
		goto loop;

	case DT_FNT:
		f = DVIFindFont(p);
		goto loop;

	case DT_XXX:
		SlowSetPosition((int)dvi_hh, (int)dvi_vv);
		P1DoSpecial(p);
		goto loop;

	case DT_FNTDEF:
		SkipFontDef(fp);
		goto loop;

	case DT_PRE:
		GripeUnexpectedOp("PRE");
		/* NOTREACHED */

	case DT_POST:
		if (doingpage) {
			GripeUnexpectedOp("POST (no EOP)");
			/* NOTREACHED */
		}
		EndString();
		return;

	case DT_POSTPOST:
		GripeUnexpectedOp("POSTPOST");
		/* NOTREACHED */

	case DT_UNDEF:
		GripeUndefinedOp(c);
		/* NOTREACHED */

	default:
		panic("DVI_DT(%d) = %d", c, DVI_DT(c));
		/* NOTREACHED */
	}
	/* NOTREACHED */
}

/*
 * At last...
 */
main(argc, argv)
	int argc;
	register char **argv;
{
	register int c;
	int xoff = 0, yoff = 0;
	int dpi = DefaultDPI;
	FILE *fp = stdin;

	setbuf(stderr, serrbuf);
	ProgName = *argv;
	ds.ds_usermag = 1000;
	ds.ds_maxdrift = DefaultMaxDrift;
	ReversePages = DefaultReversal;
	PrintEngine = DefaultPrintEngine;
	DVIFileName = "`stdin'";

	while ((c = getopt(argc, argv, "c:d:e:m:o:pr:sDI:L:NP:X:Y:")) != EOF) {
		switch (c) {

		case 'c':	/* number of copies */
			if ((copies = atoi(optarg)) < 1)
				error(1, 0, "cannot do %d copies", copies);
			break;

		case 'd':	/* max drift value */
			ds.ds_maxdrift = atoi(optarg);
			break;

		case 'e':	/* engine */
			PrintEngine = optarg;
			break;

		case 'm':	/* magnification */
			ds.ds_usermag = atoi(optarg);
			break;

		case 'o':	/* document options */
			AddOption(optarg);
			break;

		case 'p':	/* invert page reversal */
			ReversePages = !ReversePages;
			break;

		case 'r':	/* resolution */
			dpi = atoi(optarg);
			break;

		case 's':	/* silent */
			SFlag++;
			break;

		case 'L':	/* change default PostScript library */
			ps_dir = optarg;
			break;

		case 'N':	/* disable standard prologue */
			prologue = NULL;
			psf_pro = NULL;
			break;

		case 'I':	/* alias for -P */
		case 'P':	/* add prologue */
			if (npro == MAXPROLOGUES)
				error(1, 0, "Too many prologues specified");
			PSprologues[npro++] = strsave(optarg);
			break;

		case 'D':	/* secret debug option */
			Debug++;
			break;

		case 'X':	/* x offset, in 1/1000 inch increments */
			xoff = atoi(optarg);
			break;

		case 'Y':	/* y offset */
			yoff = atoi(optarg);
			break;

		case '?':
			(void) fprintf(stderr, "\
Usage: %s [-o doc-option] [-m mag] [-s] [more options, see manual] [file]\n",
			    ProgName);
			(void) fflush(stderr);
			exit(1);
			/* NOTREACHED */
		}
	}

	if (optind < argc)
		if ((fp = fopen(DVIFileName = argv[optind], "r")) == NULL)
			error(1, -1, "can't open %s", DVIFileName);

	ReadPSFontMap(getenv("PSFONTMAP"));

	SDsetclass("\b\t\n\f\r\040:=", "\n,");
	DVISetState(fp, DefineFont, dpi, xoff, yoff);

	(void) printf("%%!\n%%%%Title: %s\n%%%%Creator: %s%d for %s\n",
	    DVIFileName, Version, VERSION, PrintEngine);
	put("%%Pages: (atend)\n% Args:");
	for (c = 0; c < argc; c++)
		(void) printf(" %s", argv[c]);
	put("\n%%EndComments\n");

	put("/TeXDict 200 dict def TeXDict begin\n");
	if (prologue)
		Copy(prologue, 1);
	if (psf_pro && UsingBuiltInFonts)
		Copy(psf_pro, 1);
	if (npro) {
		for (c = 0; c < npro; c++)
			Copy(PSprologues[c], 1);
	}
	put("end\n%\n%%EndPrologue\n");

	put("%%BeginSetup\nTeXDict begin\n");
	(void) printf("%d @resolution\n", dpi);
	if (copies > 1)
		(void) printf("%d @copies\n", copies);
	(void) printf("%d @RUN\n", VERSION); /* do start of run processing */

	/* emit PostScript document options */
	for (c = 0; PScommands[c] != NULL; c++)
		(void) printf("@%s\n", PScommands[c]);

	put("%%EndSetup\n");

	while (P0PageLoop())
		P1PageLoop();

	if (!SFlag) {
		(void) fprintf(stderr, "\n");
		(void) fflush(stderr);
	}
	(void) printf("@FIN\n%%%%Trailer\n%%%%Pages: %d\n", pageno);
	if (ferror(stdout))
		OutputFailed();
	exit(0);
	/* NOTREACHED */
}

/*
 * Download the character c, font f (glyph=g).
 * The value of c is guaranteed to be in [0..255].
 */
void
DownLoadGlyph(c, f, g)
	int c;
	struct font *f;
	register struct glyph *g;
{
	register unsigned char *p;
	register int b, i, j, k, w;
	char tmpstr[160];
	static char hex[] = "0123456789abcdef";

	p = (unsigned char *)RASTER(g, f, ROT_NORM);

	/*
	 * Now put out the bitmap.
	 */
	(void) putchar('[');
	(void) putchar('<');	/* character bitmap */

	w = (g->g_width + 7) >> 3;

	k = 1;
	/* output bitmap rows from top to bottom */
	for (i = g->g_height; --i >= 0;) {
		for (j = w; --j >= 0;) {
			b = *p++;
			(void) putchar(hex[b >> 4]);
			(void) putchar(hex[b & 0xf]);
			if (++k > 37) {
				(void) putchar('\n');
				k = 0;
			}
		}
	}
	(void) sprintf(tmpstr, ">%d %d %d %d %d] %d fnt%d @dc\n",
	    (int)g->g_width, (int)g->g_height,
	    (int)g->g_xorigin, (int)g->g_yorigin,
	    g->g_pixwidth,
	    c, f->f_un.f_int);

	if (strlen(tmpstr) + 2 * k > 80)
		(void) putchar('\n');
	put(tmpstr);

	FreeRaster(g);
}

/* PostScript font support stuff */

/* 
 * Read the TeXPSfonts.map file.
 * Its form is:
 *	word0	word1	[word2]
 * The three `words' are:
 * 0. a short name for the font	(optional: `.' => none)
 * 1. the PostScript name for the font
 * 2. an optional procedure (arbitrary PostScript code) to create the font
 */
void
ReadPSFontMap(map)
	char *map;
{
	register struct BuiltIn *bi;
	register int c;
	int line = 0;
	FILE *fmap;
	char *v[10], buf[BUFSIZ], namebuf[BUFSIZ];

	if (map == NULL) {
		(void) sprintf(namebuf, "%s%s%s", ps_dir, PATH_SEP, FONTMAP);
		map = namebuf;
	}
	if ((fmap = fopen(map, "r")) == NULL) {
		error(0, -1, "cannot open PS font map file %s", map);
		error(0, 0, "(I will not use built-in PostScript fonts)");
		return;
	}
	while (fgets(buf, sizeof buf, fmap) != NULL) {
		line++;
		if ((c = strlen(buf)) > 0) {
			if (buf[--c] != '\n')
				error(1, 0, "%s, line %d: line too long",
				    map, line);
			buf[c] = 0;
		}
		if ((c = split(buf, v, sizeof v / sizeof *v)) < 0)
			error(1, 0, "%s, line %d: too many words", map, line);
		if (c == 0 || strcmp(v[0], "#") == 0)
			continue;
		if (c != 2 && c != 3)
			error(1, 0, "%s, line %d: malformed line", map, line);
		if ((bi = (struct BuiltIn *)malloc(sizeof *bi)) == NULL)
			GripeOutOfMemory(sizeof *bi, "builtin font");
		bi->next = BuiltIns;
		BuiltIns = bi;
		bi->TeXname = v[0][0] == '.' ? "." : strsave(v[0]);
		bi->PSname = strsave(v[1]);
		bi->Init = c == 3 ? strsave(v[2]) : NULL;
		if (Debug) {
			(void) fprintf(stderr, "BuiltIn %s -> %s",
			    bi->TeXname, bi->PSname);
			if (bi->Init != NULL)
				(void) fprintf(stderr, " init %s", bi->Init);
			(void) putc('\n', stderr);
			(void) fflush(stderr);
		}
		line++;
	}
	(void) fclose(fmap);
}

/*
 * Linear search for a built-in font---slow, but infrequent.
 */
struct BuiltIn *
IsBuiltIn(name)
	char *name;
{
	register struct BuiltIn *bi;

	for (bi = BuiltIns; bi; bi = bi->next)
		if (strcmp(name, bi->TeXname) == 0 ||
		    strcmp(name, bi->PSname) == 0)
			return (bi);
	return (NULL);
}


/*
 * Copy stdio file to stdout.
 * If `prologue' is set, stop on error; otherwise just return,
 * because this is an embedded figure, not a prologue.
 *
 *	XXX	should write path_fopen library function	XXX
 * Also, if `prologue' is set, look in ps_dir first.
 */
void
Copy(fn, prologue)
	char *fn;
	int prologue;
{
#ifdef unix
	/*
	 * Fast Unix-specific version.
	 */
	register int c, profd = -1;
	char buf[16384];

	if (prologue) {
		(void) sprintf(buf, "%s%s%s", ps_dir, PATH_SEP, fn);
		profd = open(buf, 0);
	}
	if (profd < 0)
		profd = open(fn, 0);
	if (profd < 0) {
		error(prologue, -1, "cannot read %s", fn);
		return;
	}
	if (prologue)
		(void) printf("%%\n%% Prologue file from: %s\n%%\n", fn);
	(void) fflush(stdout);
	if (ferror(stdout))
		OutputFailed();
	while ((c = read(profd, buf, sizeof buf)) > 0)
		if (write(1, buf, c) != c)
			OutputFailed();
	(void) close(profd);
#else
	/*
	 * Slower general-purpose version.
	 */
	register int c;
	FILE *pro = NULL;
	char buf[BUFSIZ];

	if (prologue) {
		(void) sprintf(buf, "%s%s%s", ps_dir, PATH_SEP, fn);
		pro = fopen(buf, "r");
	}
	if (pro == NULL)
		pro = fopen(fn, "r");
	if (pro == NULL) {
		error(prologue, -1, "cannot read %s", fn);
		return;
	}
	if (prologue)
		(void) printf("%%\n%% Prologue file from: %s\n%%\n", fn);
	while ((c = fread(buf, 1, BUFSIZ, pro)) > 0)
		if (fwrite(buf, 1, c, stdout) != c)
			OutputFailed();
	(void) fclose(pro);
#endif
}