|
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 }