|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 30938 (0x78da)
Types: TextFile
Names: »postscript.c«
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
└─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z«
└─⟦ca79c7339⟧
└─⟦this⟧ »DVIware/laser-setters/mctex/postscript/postscript.c«
/*
* 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
}