/* dvireader.c - 18:19 GMT +10:00 Wed 18 Aug 1993 - modifier Geoffrey Tobin */ /* From input file "../include/globals.p" */ #include "config.h" #include "globals.h" #include "files.h" #include "dvireader.h" #include "screenio.h" #include "fontreader.h" #include "options.h" /* Variables Exported, via "dvireader.h". */ int DVImag; int totalpages, totalfonts, totalrules; int currDVIpage; TeXcounters currTeXpage; ruleinfo * rulelist, * ruletail; fontinfo * fontlist, * currfont; specialinfo * speciallist; boolean pageempty; int minhp, minvp, maxhp, maxvp; /******************************************************************************* DECLARATIONS FOR INTERPRETING A DVI PAGE The commands between the bop and eop bytes for a particular page need to be translated (based on the method used by DVITYPE) before we can determine the the position and shape of all rules on that page, as well as the position of all characters and which fonts they belong to. */ /* Use symbolic names for the opcodes of DVI commands: */ #define setchar0 0 /* setchar1..setchar127 = 1..127 */ #define set1 128 /* set2,set3,set4 = 129,130,131 */ #define setrule 132 #define put1 133 /* put2,put3,put4 = 134,135,136 */ #define putrule 137 #define nop 138 #define bop 139 #define eop 140 #define push 141 #define pop 142 #define right1 143 #define w0 147 #define x0 152 #define down1 157 #define y0_ 161 #define z0 166 #define right2 144 #define w1 148 #define x1 153 #define down2 158 #define y1_ 162 #define z1 167 #define right3 145 #define w2 149 #define x2 154 #define down3 159 #define y2 163 #define z2 168 #define right4 146 #define w3 150 #define x3 155 #define down4 160 #define y3 164 #define z3 169 #define w4 151 #define x4 156 #define y4 165 #define z4 170 #define fntnum0 171 /* fntnum1..fntnum63 = 172..234 */ #define fnt1 235 /* fnt2,fnt3,fnt4 = 236,237,238 */ #define xxx1 239 /* xxx2,xxx3,xxx4 = 240,241,242 */ #define fntdef1 243 /* fntdef2,fntdef3,fntdef4 = 244,245,246 */ #define pre 247 #define post 248 #define postpost 249 /* undefined commands = 250..255 */ #define maxstacksize 100 /* maximum stack size for state values */ /* According to the DVI Driver Standard, Level 0, version 0.5, section 2.6.2, max_drift should depend on the output device: 2 if a "device unit" <= 0.005 in (0.127 mm), 1 if a "device unit" > 0.005 in (0.127 mm) but <= 0.01 in (0.254 mm), 0 if a "device unit" > 0.01 in (0.254 mm). So, the value given here for max_drift implies a device with a resolution of at least 200 dpi. Note: max_drift is a number of pixels. */ #define max_drift 2 /* prevent hh & vv from drifting too far */ /******************************************************************************* DECLARATIONS FOR ACCESSING BYTES IN A DVI FILE A DVI file is a stream of 8-bit bytes. Once opened, we can access any byte by setting DVIoffset to the required position and then calling GetDVIByte. */ Static int DVIfile; /* DVI file descriptor */ Static int DVIoffset; /* current byte offset in DVIfile */ Static int currDVIbuff; /* starting byte offset in buffer */ Static buffer DVIbuffer; /* input buffer */ Static int postpostid; /* offset of postpost's id byte */ /******************************************************************************* DECLARATIONS FOR GETTING TO A DVI PAGE The user can select a particular page by specifying a DVI page number (from 1 to totalpages), or a TeX page number (based on the values of \count0,\count1,...,\count9), or simply requesting the next page in the DVI file (which depends on whether we are ascending or not). We will often need to follow the DVI backpointers to locate the bop byte of a selected page. */ Static int curreop; /* position of eop byte of current page */ Static int currbop; /* position of bop byte of current page */ Static int lastbop; /* position of last bop byte */ Static int prevbop; /* position of bop byte of previous page; note that prevbop of first page = -1 */ Static unsigned char DVIcommand; /* holds next DVI command */ Static int maxstack; /* max pushes over pops in DVI file */ Static int num = 0; /* DVI numerator */ Static int den = 0; /* DVI denominator */ Static double xconv = 0.0; /* converts DVI units to X pixels */ Static double yconv = 0.0; /* converts DVI units to Y pixels */ Static int h, v; /* current pos on page in DVI units */ Static int w, x; /* horizontal increments in DVI units */ Static int y, z; /* vertical increments in DVI units */ Static int hh, vv; /* h and v in pixels (approx) */ Static int hhh, vvv; /* h and v rounded to nearest pixel */ Static int hstack[maxstacksize], vstack[maxstacksize]; /* push down stacks for state values */ Static int wstack[maxstacksize], xstack[maxstacksize], ystack[maxstacksize], zstack[maxstacksize], hhstack[maxstacksize], vvstack[maxstacksize]; Static int stackpos; /* stacks empty when stackpos = 0, i.e., top of stacks = stackpos - 1 */ Static int fontspace; /* used in DoRight and DoDown */ /******************************************************************************/ /* Here are the functions used to get byte/s from DVIfile. They are essentially the same as those used in DVITYPE. */ Static int GetDVIByte (VOID) { /* Returns the value (unsigned) of the byte at DVIoffset and advances DVIoffset for the next GetDVIByte. */ extern int currDVIbuff, DVIfile, DVIoffset; int Result, buffstart, result; /* bufflen is a #define-d constant in "files.h" */ buffstart = DVIoffset / bufflen * bufflen; /* 0, bufflen, 2*bufflen... */ if (buffstart != currDVIbuff) { currDVIbuff = buffstart; result = lseek (DVIfile, buffstart, 0); /* DEBUG IF result <> buffstart THEN BEGIN writeln ('Lseek failed in GetDVIByte!'); RestoreTerminal; EXIT (1); END; GUBED */ if (result != buffstart) { MesgString ("lseek failed in GetDVIByte!"); MesgLine(); RestoreTerminal(); exit (1); } result = read (DVIfile, DVIbuffer, bufflen); /* DEBUG IF result = -1 THEN BEGIN writeln ('Read failed in GetDVIByte!'); RestoreTerminal; EXIT (1); END; GUBED */ if (result == -1) { MesgString ("read failed in GetDVIByte!"); MesgLine(); RestoreTerminal(); exit (1); } } Result = DVIbuffer[DVIoffset - buffstart]; DVIoffset++; return Result; } /* GetDVIByte */ /******************************************************************************/ Static int SignedDVIByte (VOID) { /* the next byte, signed */ int b; b = GetDVIByte(); if (b < 128) return b; else return (b - 256); } /* SignedDVIByte */ /******************************************************************************/ Static int GetTwoDVIBytes (VOID) { /* the next 2 bytes, unsigned */ int a, b; a = GetDVIByte(); b = GetDVIByte(); return (a * 256 + b); } /* GetTwoDVIBytes */ /******************************************************************************/ Static int SignedDVIPair (VOID) { /* the next 2 bytes, signed */ int a, b; a = GetDVIByte(); b = GetDVIByte(); if (a < 128) return (a * 256 + b); else return ((a - 256) * 256 + b); } /* SignedDVIPair */ /******************************************************************************/ Static int GetThreeDVIBytes (VOID) { /* the next 3 bytes, unsigned */ int a, b, c; a = GetDVIByte(); b = GetDVIByte(); c = GetDVIByte(); return ((a * 256 + b) * 256 + c); } /* GetThreeDVIBytes */ /******************************************************************************/ Static int SignedDVITrio (VOID) { /* the next 3 bytes, signed */ int a, b, c; a = GetDVIByte(); b = GetDVIByte(); c = GetDVIByte(); if (a < 128) return ((a * 256 + b) * 256 + c); else return (((a - 256) * 256 + b) * 256 + c); } /* SignedDVIOqTrio */ /******************************************************************************/ Static int SignedDVIQuad (VOID) { /* the next 4 bytes, signed */ int w; byte3(w) = GetDVIByte(); byte2(w) = GetDVIByte(); byte1(w) = GetDVIByte(); byte0(w) = GetDVIByte(); return (w); } /* SignedDVIQuad */ /******************************************************************************/ Static Void ProcessPostamble (VOID) { /* Having successfully opened the DVI file, we find the postamble and initialize these global variables: lastbop, num, den, DVImag, maxstack, totalpages. The font definitions are read by ProcessFontDefs. */ extern int DVIoffset, postpostid; extern int lastbop, num, den, DVImag, maxstack, totalpages; int postamblepos, postamble, pagehtplusdp, pagewidth; DVIoffset = postpostid - 4; postamblepos = SignedDVIQuad(); /* get post_post's postamble ptr */ DVIoffset = postamblepos; postamble = GetDVIByte(); lastbop = SignedDVIQuad(); num = SignedDVIQuad(); den = SignedDVIQuad(); DVImag = SignedDVIQuad(); pagehtplusdp = SignedDVIQuad(); pagewidth = SignedDVIQuad(); maxstack = SignedDVIPair(); totalpages = SignedDVIPair(); if (maxstack <= maxstacksize) return; MesgString ("Stack capacity exceeded!"); MesgLine(); RestoreTerminal(); exit (1); /* now we don't need to test for stack overflow in DoPush */ } /* ProcessPostamble */ /******************************************************************************/ Static Void ProcessFontDefs (VOID) { /* Read the fntdef commands in the postamble (fntdef commands in the DVI pages will be skipped) and store the information in the font list. (Note that complete fontspecs are NOT built here because DVIReader does not want to know about the format or naming conventions of font files.) Since ProcessPostamble ended by reading the totalpages parameter, the next GetDVIByte should return nop or first fntdef. */ extern int totalfonts; extern fontinfo * fontlist; int f, c, s, d, a, l; /* hold fntdef parameters */ int i; Char ch; /* for getting farea and fname */ string farea, fname; /* a and l bytes long respectively */ totalfonts = 0; /* number of nodes in font list */ fontlist = (fontinfo *) NULL; do { DVIcommand = GetDVIByte(); if (DVIcommand >= fntdef1 && DVIcommand <= fntdef1 + 3) { switch (DVIcommand - fntdef1) { case 0: f = GetDVIByte(); break; case 1: f = GetTwoDVIBytes(); break; case 2: f = GetThreeDVIBytes(); break; case 3: f = SignedDVIQuad(); break; } c = SignedDVIQuad(); /* checksum; ignore it */ s = SignedDVIQuad(); /* scaled size */ d = SignedDVIQuad(); /* design size */ a = GetDVIByte(); /* length of font area */ l = GetDVIByte(); /* length of font name */ /* read and store font area */ for (i = 0; i < a; i++) { ch = GetDVIByte(); if (i < maxfontspec) farea[i] = ch; } farea[i <= maxfontspec ? i: maxfontspec] = '\0'; /* read and store font name */ for (i = 0; i < l; i++) { ch = GetDVIByte(); if (i < maxfontspec) fname[i] = ch; } fname[i <= maxfontspec ? i: maxfontspec] = '\0'; currfont = (fontinfo *) Malloc (sizeof (fontinfo)); currfont->fontused = false; currfont->fontnum = f; currfont->scaledsize = s; currfont->designsize = d; strncpy (currfont->fontarea, farea, maxstring); currfont->fontarea[maxstring] = '\0'; /* to be careful */ currfont->fontarealen = a; strncpy (currfont->fontname, fname, maxstring); currfont->fontname[maxstring] = '\0'; /* to be careful */ currfont->fontnamelen = l; currfont->fontspec[0] = '\0'; currfont->fontspeclen = 0; /* fontspec is built in FontReader */ currfont->fontexists = false; /* becomes TRUE if fontspec can be opened */ currfont->totalchars = 0; /* first node allocated in DoFont */ currfont->charlist = (charinfo *) NULL; /* nodes are added to tail of char list */ currfont->chartail = (charinfo *) NULL; /* allocated once per font; see DoFont */ currfont->pixelptr = (_REC_pixeltable *) NULL; currfont->nextfont = fontlist; fontlist = currfont; /* add new font to head of list */ totalfonts++; } else if (DVIcommand != nop) { if (DVIcommand != postpost) { /* gt - hope outstring has room enough - it should have. */ string outstring; sprintf (outstring, "Unexpected DVI command in postamble = %d", DVIcommand); MesgString (outstring); MesgLine(); RestoreTerminal(); exit (1); } /* we have reached end of postamble */ } } while (DVIcommand != postpost); /* nop commands can occur between DVI commands */ } /* ProcessFontDefs */ /******************************************************************************/ #ifdef __STDC__ Void OpenDVIFile (Char * name) #else Void OpenDVIFile (name) Char * name; #endif { /* If the given file can be opened and is a valid TeX82 DVI file then the following global variables are initialized: DVImag := magnification value stored in DVI file (TeX's \mag) totalpages := total number of pages in DVI file currDVIpage := 0 (and remains so until a page is selected) currTeXpage := ten 0s (ditto) totalfonts := total number of fonts in DVI file (= nodes in font list) fontlist-> (nodes are added to head of list) fontused := FALSE fontnum := internal DVI font number scaledsize := scaled size of font (in DVI units) designsize := design size of font (in DVI units) fontarea := a string of min (fontarealen, maxfontspec) characters fontname := a string of min (fontnamelen, maxfontspec) characters fontspec := a null string (fontspeclen := 0) fontexists := FALSE totalchars := 0 charlist := NIL chartail := NIL pixelptr := NIL nextfont := next node in font list (if not NIL) */ extern int currDVIpage; extern TeXcounters currTeXpage; extern int currDVIbuff; extern int DVIfile; extern int DVIoffset, postpostid; currDVIbuff = -1; /* impossible value for first GetDVIByte */ DVIfile = open (name, O_RDONLY, 0); if (DVIfile >= 0) { int i; if (logfile != NULL) fprintf (logfile, "Opened DVI file `%s'\n", DVIname); /* get offset of last DVI byte */ DVIoffset = lseek (DVIfile, 0, 2); if (DVIoffset == -1) { MesgString ("Failed to find end of file!"); MesgLine(); RestoreTerminal(); exit (1); } if (DVIoffset == 0) { MesgString ("DVI file is empty!"); MesgLine(); RestoreTerminal(); exit (1); } /* DEBUG writeln ('total bytes = ', DVIoffset:1); GUBED */ fprintf (logfile, "Total DVI bytes = %d\n", DVIoffset); fflush (logfile); DVIoffset--; /* In the following, DVIoffset == 1 signifies the start of the file. */ /* skip any NULs */ while (GetDVIByte() == 0 && DVIoffset != 1) { DVIoffset -= 2; /* GetDVIByte increments */ } DVIoffset--; /* skip 223s */ while (GetDVIByte() == 223 && DVIoffset != 1) { DVIoffset -= 2; /* GetDVIByte increments */ } DVIoffset--; postpostid = DVIoffset; /* remember offset of id byte */ if (GetDVIByte() != 2) { MesgString ("Not a valid DVI file!"); MesgLine(); RestoreTerminal(); exit (1); /*NOTREACHED*/ return; } ProcessPostamble(); /* get DVImag, totalpages, etc */ ProcessFontDefs(); /* build and initialize font list */ currDVIpage = 0; /* we haven't processed a page yet */ for (i = 0; i <= 9; i++) currTeXpage[i] = 0; return; } else { /* gt - I suppose this is correct for length */ int length = strlen (name); /* gt - hope outstr has sufficient room */ string outstr; sprintf (outstr, "Couldn't open DVI file: `%.*s'\n", length, name); MesgString (outstr); MesgLine(); RestoreTerminal(); exit (1); } } /* OpenDVIFile */ /******************************************************************************/ #ifdef __STDC__ Static Void SkipFntdef (int which) #else Static Void SkipFntdef (which) int which; #endif { /* Read past a fntdef command without interpreting it. */ int dummy, a, l, i; switch (which) /* which = DVIcommand - fntdef1 */ { case 0: dummy = GetDVIByte(); break; case 1: dummy = GetTwoDVIBytes(); break; case 2: dummy = GetThreeDVIBytes(); break; case 3: dummy = SignedDVIQuad(); break; } dummy = SignedDVIQuad(); dummy = SignedDVIQuad(); dummy = SignedDVIQuad(); a = GetDVIByte(); /* length of directory */ l = GetDVIByte(); /* length of font name */ for (i = 1; i <= l + a; i++) dummy = GetDVIByte(); } /* SkipFntdef */ /******************************************************************************/ Static Void ReadFirstBop (VOID) { /* Read first bop by skipping past preamble; update currbop and currDVIpage. */ int k, i, dummy; DVIoffset = 14; /* position of preamble's k parameter */ k = GetDVIByte(); /* length of x parameter */ for (i = 1; i <= k; i++) /* skip preamble comment */ dummy = GetDVIByte(); do { /* skip any nops and fntdefs */ DVIcommand = GetDVIByte(); if (DVIcommand != nop && DVIcommand != bop) { if (DVIcommand >= fntdef1 && DVIcommand <= fntdef1 + 3) SkipFntdef (DVIcommand - fntdef1); else { MesgLine(); MesgString ("Unexpected DVI command before first bop="); MesgInt (DVIcommand); MesgLine(); RestoreTerminal(); exit (1); } } /* do nothing */ } while (DVIcommand != bop); currbop = DVIoffset - 1; /* position in DVI file of first bop */ currDVIpage = 1; } /* ReadFirstBop */ /******************************************************************************/ Static Void ReadNextBop (VOID) { /* We are currently positioned after an eop byte which we know is not the last. This routine positions us after the next bop byte and updates currbop and currDVIpage. */ /* skip any nops and fntdefs */ do { DVIcommand = GetDVIByte(); if (DVIcommand != nop && DVIcommand != bop) { if (DVIcommand >= fntdef1 && DVIcommand <= fntdef1 + 3) SkipFntdef (DVIcommand - fntdef1); else { MesgLine(); MesgString ("Unexpected DVI command between eop and bop="); MesgInt (DVIcommand); MesgLine(); RestoreTerminal(); exit (1); } } /* do nothing */ } while (DVIcommand != bop); currbop = DVIoffset - 1; /* position in DVI file of this bop */ currDVIpage++; } /* ReadNextBop */ /******************************************************************************/ Static Void ReadBopParameters (VOID) { /* We should now be positioned after the bop of desired page, so read the 10 TeX counters and update currTeXpage and prevbop. At the end of this routine we will be at the byte after currbop's parameters and ready to InterpretPage. */ int i; for (i = 0; i <= 9; i++) currTeXpage[i] = SignedDVIQuad(); prevbop = SignedDVIQuad(); /* position of previous bop in DVI file */ } /* ReadBopParameters */ /******************************************************************************/ #ifdef __STDC__ Void MoveToNextPage (boolean ascending) #else Void MoveToNextPage (ascending) boolean ascending; #endif { /* MoveToNextPage will select the next page, depending on the current page and the specified direction. If the value of currDVIpage is 0 (set in OpenDVIFile), then MoveToNextPage will select the first page if ascending is TRUE and the last page if ascending is FALSE. If currDVIpage is > 0 then MoveToNextPage will select currDVIpage+1 if ascending (unless currDVIpage = totalpages, in which case it does nothing), or currDVIpage-1 if descending (unless currDVIpage = 0). Before calling InterpretPage, DVItoVDU must position DVIReader to the desired page by calling one of the MoveTo... routines. The global variables updated if a page is located by any MoveTo... call are: currDVIpage := the current DVI page (1..totalpages) currTeXpage := the ten TeX counter values stored with this page Note that currDVIpage is initially 0 until one of these routines succeeds. */ extern int currDVIpage; extern int DVIoffset; extern int totalpages; extern int currbop, lastbop, prevbop; /* keep within limits of document */ if ((currDVIpage != 1 && !ascending) || (currDVIpage != totalpages && ascending)) { if (currDVIpage == 0) /* special value */ { /* we haven't processed a page yet */ if (ascending) /* get first page */ ReadFirstBop(); else { /* get last page */ currbop = lastbop; DVIoffset = currbop + 1; currDVIpage = totalpages; } } else { if (ascending) { /* currently positioned after eop of currDVIpage, so get next bop */ ReadNextBop(); } else { /* move to bop pointed to by currbop's backpointer */ currbop = prevbop; DVIoffset = currbop + 1; /* move to byte after previous bop */ currDVIpage--; } } ReadBopParameters(); /* update currTeXpage and prevbop */ } } /* MoveToNextPage */ /******************************************************************************/ #ifdef __STDC__ Void MoveToDVIPage (int n) #else Void MoveToDVIPage (n) int n; #endif { /* Move to nth DVI page; n should be in 1..totalpages. */ extern int totalpages; extern int currDVIpage; extern int currbop, lastbop, prevbop; if (n < 1 || n > totalpages) /* do nothing */ goto _L999; if (n == 1) { /* Note that this test must come before next test so that we avoid any problems when currDVIpage initially = 0. */ ReadFirstBop(); } else if (n == currDVIpage + 1) { ReadNextBop(); } else { if (n < currDVIpage) { currbop = prevbop; /* start searching backwards from previous page */ currDVIpage--; } else if (n > currDVIpage) { currbop = lastbop; /* start searching backwards from last page */ currDVIpage = totalpages; } /* if n = currDVIpage we'll just move back to currbop */ /* n is now <= currDVIpage so search by following backpointers */ while (true) { if (n == currDVIpage) { DVIoffset = currbop + 1; /* move to byte after currbop */ break; /* escape from "infinite" loop */ } DVIoffset = currbop + 41; /* move to location of backpointer */ currbop = SignedDVIQuad(); /* get location of previous page */ currDVIpage--; } /* while */ } /* if */ ReadBopParameters(); /* update currTeXpage and prevbop */ _L999: ; } /* MoveToDVIPage */ /******************************************************************************/ #ifdef __STDC__ Static boolean CurrMatchesNew (TeXpageinfo * newTeXpage) #else Static boolean CurrMatchesNew (newTeXpage) TeXpageinfo * newTeXpage; #endif { /* Return TRUE iff currTeXpage matches newTeXpage. */ extern TeXcounters currTeXpage; boolean Result; int i, FORLIM; Result = true; FORLIM = newTeXpage->lastvalue; for (i = 0; i <= FORLIM; i++) { if (newTeXpage->present[i]) { if (newTeXpage->value[i] != currTeXpage[i]) Result = false; } } return Result; } /* CurrMatchesNew */ /******************************************************************************/ #ifdef __STDC__ boolean MoveToTeXPage (TeXpageinfo * newTeXpage) #else boolean MoveToTeXPage (newTeXpage) TeXpageinfo * newTeXpage; #endif { /* MoveToTeXPage will search for the lowest DVI page matching the given TeX page specification. (TeX stores the values of \count0,\count1, ..., \count9 with every DVI page. Plain TeX uses \count0 to control page numbering.) newTeXpage is a VAR parameter only for efficiency; it won't be changed. The value array stores the requested counter values, the present array indicates which counters are relevant and lastvalue indicates the position (0..9) of the last relevant counter. DVItoVDU converts a more friendly representation of a TeX page request into the TeXpageinfo format. For example, [2..5] would be converted to: and [] would be converted to: value = [2,?,5,?,?,?,?,?,?,?] value = [?,?,?,?,?,?,?,?,?,?] present = [T,F,T,?,?,?,?,?,?,?] present = [F,?,?,?,?,?,?,?,?,?] lastvalue = 2 lastvalue = 0 MoveToTeXPage returns TRUE iff the requested TeX page is located. */ extern int totalpages; extern int currDVIpage; extern int DVIoffset; extern int currbop, lastbop, prevbop; boolean Result; int savecurrbop, savecurrDVIpage, nextbop, i; boolean atleastone; /* save away current page and DVI position */ savecurrDVIpage = currDVIpage; if (currDVIpage != 0) /* only if we've processed a page */ savecurrbop = currbop; /* note that curreop is saved in last InterpretPage */ /* search backwards through all DVI pages for lowest matching page */ atleastone = false; nextbop = lastbop; for (i = totalpages; i >= 1; i--) { DVIoffset = nextbop + 1; ReadBopParameters(); /* update currTeXpage and prevbop */ if (CurrMatchesNew (newTeXpage)) { currbop = nextbop; currDVIpage = i; atleastone = true; } nextbop = prevbop; } if (!atleastone) { /* no match, so restore currDVIpage */ currDVIpage = savecurrDVIpage; if (currDVIpage != 0) { /* restore page and positioning info */ currbop = savecurrbop; DVIoffset = currbop + 1; ReadBopParameters(); /* restore currTeXpage and prevbop */ DVIoffset = curreop + 1; /* we should now be after the eop byte of the original page */ } Result = false; goto _L999; } DVIoffset = currbop + 1; ReadBopParameters(); /* update currTeXpage and prevbop */ Result = true; _L999: return Result; /* we found lowest matching page */ } /* MoveToTeXPage */ /******************************************************************************/ #ifdef __STDC__ Void SetConversionFactors (double xres, double yres, double magnification) #else Void SetConversionFactors (xres, yres, magnification) double xres; double yres; double magnification; #endif /* Arguments: xres: horizontal resolution of output device in dots per inch. yres: vertical resolution. magnification: magnification of document; 1 means normal size. */ { /* This routine must be called before the first InterpretPage call. DVIReader needs to know the resolution and magnification values before it attempts to convert DVI units into pixel values. */ /* num, den are written in ProcessPostAmble */ extern int num, den; /* GT - The "254000.0" corresponds to ten thousand units per mm. */ /* Refer to TUG's DVI Driver standard. */ xconv = ( num / 254000.0 * xres / den * magnification ); yconv = ( num / 254000.0 * yres / den * magnification ); } /* SetConversionFactors */ /******************************************************************************/ #ifdef __STDC__ Static int Sign (double d) #else Static int Sign (d) double d; #endif { return (d < 0.0 ? -1 : 1); } /* Sign */ /******************************************************************************/ Static Void InitStateValues (VOID) { /* Initialize state values and stack. */ /* This is the only place in "dvireader.c" */ /* where hoffset, voffset appear. */ /* The offsets are set in "options.c". */ /* The other extern variables are Static in "dvireader.c". */ extern int hoffset, voffset; /* page offsets in X & Y pixels */ extern int hh, vv; /* current position in X & Y pixels */ extern double xconv, yconv; /* numbers of X & Y pixels in one DVI unit */ extern int h, v; /* current position in DVI units */ extern int w, x, y, z; /* movement in DVI units */ extern int stackpos; extern int fontspace; double hox, voy; /* offsets divided by conversion factors */ hox = hoffset / xconv; voy = voffset / yconv; hh = hoffset; /* 0 if no horizontal shift specified */ vv = voffset; /* 0 if no vertical shift specified */ h = Sign (hox) * (int) ((hox >= 0.0 ? hox : -hox) + 0.5); v = Sign (voy) * (int) ((voy >= 0.0 ? voy : -voy) + 0.5); w = 0; x = 0; y = 0; z = 0; stackpos = 0; fontspace = 0; /* for DoRight and DoDown before a DoFont call */ } /* InitStateValues */ /******************************************************************************/ Static Void InitPage (VOID) { /* Initialize page so that there are no fonts, chars, rules, specials. */ pageempty = true; /* gt - assumed until a char or rule is found */ /* page edges will change if there is at least one char or rule on page */ /* gt - these shouldn't be necessary, but to be on the safe side ... */ minhp = 0; minvp = 0; maxhp = 0; maxvp = 0; currfont = fontlist; while (currfont != (fontinfo *) NULL) { if (currfont->fontused) /* only reset those fonts used in last page */ { currfont->fontused = false; /* deallocate char list completely; DoFont will allocate first node */ currfont->totalchars = 0; while (currfont->charlist != (charinfo *) NULL) { charinfo * thischar; /* temporary pointer to node in charlist */ thischar = currfont->charlist; currfont->charlist = thischar->nextchar; Free (thischar, charinfo); } currfont->chartail = (charinfo *) NULL; /* pixel table remains allocated */ } currfont = currfont->nextfont; } currfont = (fontinfo *) NULL; /* current font's undefined at start of page */ /* deallocate rule information except for one node (for DoSet/PutRule) */ totalrules = 0; while (rulelist != ruletail) { ruleinfo * thisrule; /* temporary pointer to node in rulelist */ thisrule = rulelist; rulelist = thisrule->nextrule; Free (thisrule, ruleinfo); } rulelist->rulecount = 0; /* no rules in this node */ rulelist->nextrule = (ruleinfo *) NULL; /* deallocate \special information */ while (speciallist != (specialinfo *) NULL) { specialinfo * thisspecial; /* temporary ptr to node in speciallist */ thisspecial = speciallist; speciallist = speciallist->nextspecial; Free (thisspecial, specialinfo); } } /* InitPage */ /******************************************************************************/ #ifdef __STDC__ int XPixelRound (int DVIunits) #else int XPixelRound (DVIunits) int DVIunits; #endif { /* Return the nearest number of X pixels in the given DVI X dimension. */ /* According to the DVI Driver Standard, Level 0, draft 0.05, */ /* section 2.6.2, "Changes in position due to characters and */ /* rules", */ /* pixel_round (n) = sign (Kn) * floor (abs (Kn) + 0.5), */ /* where sign (i) = -1 if i < 0 and = 1 if i >= 0, */ /* and K is xconv for horizontal and yconv for vertical */ /* dimensions. */ double Kn = xconv * (double) DVIunits; return (Sign (Kn) * (int) ((Kn >= 0.0 ? Kn : -Kn) + 0.5)); } /* XPixelRound */ /******************************************************************************/ #ifdef __STDC__ int YPixelRound (int DVIunits) #else int YPixelRound (DVIunits) int DVIunits; #endif { /* Return the nearest number of Y pixels in the given DVI Y dimension. */ /* According to the DVI Driver Standard, Level 0, draft 0.05, */ /* section 2.6.2, "Changes in position due to characters and */ /* rules", */ /* pixel_round (n) = sign (Kn) * floor (abs (Kn) + 0.5), */ /* where sign (i) = -1 if i < 0 and = 1 if i >= 0, */ /* and K is xconv for horizontal and yconv for vertical */ /* dimensions. */ double Kn = yconv * (double) DVIunits; return (Sign (Kn) * (int) ((Kn >= 0.0 ? Kn : -Kn) + 0.5)); } /* YPixelRound */ /******************************************************************************/ #ifdef __STDC__ Static Void DoSetChar (int ch) #else Static Void DoSetChar (ch) int ch; #endif { /* Add char info to current chartable, update our horizontal position on the page and check the page edges. */ if (ch > maxTeXchar) { /* ignore ch */ string codestr; sprintf (codestr, "%d", ch); MesgString ("Unknown character (code "); MesgString (codestr); MesgString (") from "); MesgString (currfont->fontspec); } else /* ch is valid */ { charinfo * char_info = currfont->chartail; /* may be new chartable */ _REC_chartable * char_tab = (_REC_chartable *) NULL; _REC_pixeltable * pix_tab = (_REC_pixeltable *) NULL; if (char_info->charcount == chartablesize) { char_info->nextchar = (charinfo *) Malloc (sizeof (charinfo)); /* add new node to end of char list */ char_info->nextchar->charcount = 0; /* reset charcount */ char_info->nextchar->nextchar = (charinfo *) NULL; currfont->chartail = char_info->nextchar; } /* allocate a new chartable */ char_info = currfont->chartail; char_tab = &char_info->chartable[char_info->charcount]; char_tab->hp = hh; char_tab->vp = vv; char_tab->code = ch; pix_tab = &currfont->pixelptr[ch]; /* do page edges increase? */ if (pageempty || hh - pix_tab->xo < minhp) { minhp = hh - pix_tab->xo; } if (pageempty || vv - pix_tab->yo < minvp) minvp = vv - pix_tab->yo; if (pageempty || hh + pix_tab->wd - pix_tab->xo - 1 > maxhp) maxhp = hh + pix_tab->wd - pix_tab->xo - 1; if (pageempty || vv + pix_tab->ht - pix_tab->yo - 1 > maxvp) maxvp = vv + pix_tab->ht - pix_tab->yo - 1; /* the above checks ensure that page edges include all black pixels in glyph, but we also want to include reference point */ if (pageempty || hh < minhp) minhp = hh; if (pageempty || vv < minvp) minvp = vv; if (pageempty || hh > maxhp) maxhp = hh; if (pageempty || vv > maxvp) maxvp = vv; /* add DVI width calculated in PixelTableRoutine */ h += pix_tab->dwidth; /* add pixel width calculated in PixelTableRoutine */ hh += pix_tab->pwidth; /* use hhh and max_drift to prevent hh drifting too far from h */ hhh = XPixelRound (h); if (abs (hhh - hh) > max_drift) { /* Adjust hh to be just within the allowed tolerance from h. */ hh = hhh + (hhh > hh ? -max_drift : max_drift); } currfont->totalchars++; char_info->charcount++; pageempty = false; } } /* DoSetChar */ /******************************************************************************/ #ifdef __STDC__ Static Void DoPutChar (int ch) #else Static Void DoPutChar (ch) int ch; #endif { /* Exactly the same as DoSetChar, but we DON'T update the horizontal position on the page. (We still have to check page edges.) */ if (ch > maxTeXchar) { /* ignore ch */ string codestr; sprintf (codestr, "%d", ch); MesgString ("Unknown character (code "); MesgString (codestr); MesgString (") from "); MesgString (currfont->fontspec); } else /* ch is valid */ { charinfo * char_info = currfont->chartail; /* may be new chartable */ _REC_chartable * char_tab = (_REC_chartable *) NULL; _REC_pixeltable * pix_tab = (_REC_pixeltable *) NULL; if (char_info->charcount == chartablesize) { char_info->nextchar = (charinfo *) Malloc (sizeof (charinfo)); /* add new node to end of char list */ char_info->nextchar->charcount = 0; /* reset charcount */ char_info->nextchar->nextchar = (charinfo *) NULL; currfont->chartail = char_info->nextchar; } /* allocate a new chartable */ char_info = currfont->chartail; char_tab = &char_info->chartable[char_info->charcount]; char_tab->hp = hh; char_tab->vp = vv; char_tab->code = ch; pix_tab = &currfont->pixelptr[ch]; /* do page edges increase? */ if (pageempty || hh - pix_tab->xo < minhp) minhp = hh - pix_tab->xo; if (pageempty || vv - pix_tab->yo < minvp) minvp = vv - pix_tab->yo; if (pageempty || hh + pix_tab->wd - pix_tab->xo - 1 > maxhp) maxhp = hh + pix_tab->wd - pix_tab->xo - 1; if (pageempty || vv + pix_tab->ht - pix_tab->yo - 1 > maxvp) maxvp = vv + pix_tab->ht - pix_tab->yo - 1; /* the above checks ensure that page edges include all black pixels in glyph, but we also want to include reference point */ if (pageempty || hh < minhp) minhp = hh; if (pageempty || vv < minvp) minvp = vv; if (pageempty || hh > maxhp) maxhp = hh; if (pageempty || vv > maxvp) maxvp = vv; currfont->totalchars++; char_info->charcount++; pageempty = false; } } /* DoPutChar */ /******************************************************************************/ Static Void DoPush (VOID) { /* Push state values onto stack. No need to test for stack overflow since we compare maxstack and maxstacksize in ProcessPostamble. */ extern int stackpos; hstack[stackpos] = h; vstack[stackpos] = v; wstack[stackpos] = w; xstack[stackpos] = x; ystack[stackpos] = y; zstack[stackpos] = z; hhstack[stackpos] = hh; vvstack[stackpos] = vv; stackpos++; } /* DoPush */ /******************************************************************************/ Static Void DoPop (VOID) { /* Pop state values from top of stack. */ extern int stackpos; /* DEBUG IF stackpos = 0 THEN BEGIN WriteLine; WriteString ('Stack empty!'); WriteLine; RestoreTerminal; EXIT (1); END; GUBED */ if (stackpos == 0) { MesgLine(); MesgString ("Stack empty!"); MesgLine(); RestoreTerminal(); exit (1); } stackpos--; h = hstack[stackpos]; v = vstack[stackpos]; w = wstack[stackpos]; x = xstack[stackpos]; y = ystack[stackpos]; z = zstack[stackpos]; hh = hhstack[stackpos]; vv = vvstack[stackpos]; } /* DoPop */ /******************************************************************************/ #ifdef __STDC__ Static Void DoRight (int amount) #else Static Void DoRight (amount) int amount; #endif { /* Move the reference point horizontally by given amount (usually +ve). When the amount is small, like a kern, hh changes by rounding the amount; but when the amount is large, hh changes by rounding the true position h so that accumulated rounding errors disappear. */ h += amount; /* GT - Wrong? DVI Driver Standard specifies: "if (processor uses TFM) word_space = space - space_shrink; else quad = magnification * (design size of font); word_space = 0.2 * quad; fi; back_space = 0.9 * quad; if (amount < word_space && amount > -back_space)". So, TFM -> space, space_shrink; else -> design size. Now, how do we learn those quantities? */ if (amount < fontspace && amount > -fontspace * 4) { hh += XPixelRound (amount); /* use hhh and max_drift to prevent hh drifting too far from h */ hhh = XPixelRound (h); if (abs (hhh - hh) > max_drift) { /* Adjust hh to be just within the allowed tolerance from h. */ hh = hhh + (hhh > hh ? -max_drift : max_drift); } } else { hh = XPixelRound (h); } } /* DoRight */ /******************************************************************************/ #ifdef __STDC__ Static Void DoDown (int amount) #else Static Void DoDown (amount) int amount; #endif { /* Move the reference point vertically by given amount (usually +ve). Rounding is done similarly to DoRight but with the threshold between small and large amounts increased by a factor of 5. */ v += amount; /* GT - Wrong? DVI Driver Standard specifies: "if (abs (y) < 0.8 * quad)". */ if (abs (amount) < fontspace * 5) { vv += YPixelRound (amount); /* use vvv and max_drift to prevent vv drifting too far from v */ vvv = YPixelRound (v); if (abs (vvv - vv) > max_drift) { /* Adjust vv to be just within the allowed tolerance from v. */ vv = vvv + (vvv > vv ? -max_drift : max_drift); } } else { vv = YPixelRound (v); } } /* DoDown */ /******************************************************************************/ #ifdef __STDC__ Static int RulePixels (double conv, int DVIunits) #else Static int RulePixels (conv, DVIunits) double conv; int DVIunits; #endif { /* Return the number of pixels in the given height or width of a rule using the method recommended in DVITYPE. */ int n = (int) (conv * DVIunits); if (n < conv * DVIunits) return (n + 1); else return n; } /* RulePixels */ /******************************************************************************/ #ifdef __STDC__ Static Void DoSetRule (int height, int width) #else Static Void DoSetRule (height, width) int height; int width; #endif { /* Add rule information to current ruletable, update page edges, h and hh (but only if width and height are > 0). */ _REC_ruletable * ruletab = (_REC_ruletable *) NULL; if (height <= 0 || width <= 0) return; /* may be new ruletable */ if (ruletail->rulecount == ruletablesize) { ruletail->nextrule = (ruleinfo *) Malloc (sizeof (ruleinfo)); /* add new node to end of rule list */ ruletail->nextrule->rulecount = 0; /* reset rulecount */ ruletail->nextrule->nextrule = (ruleinfo *) NULL; ruletail = ruletail->nextrule; } /* allocate a new ruletable */ ruletab = &ruletail->ruletable[ruletail->rulecount]; ruletab->hp = hh; ruletab->vp = vv; ruletab->wd = RulePixels (xconv, width); ruletab->ht = RulePixels (yconv, height); /* do page edges increase? */ /* ref pt of rule is bottom left black pixel */ if (pageempty || vv > maxvp) maxvp = vv; if (pageempty || hh < minhp) minhp = hh; if (pageempty || vv - ruletab->ht + 1 < minvp) minvp = vv - ruletab->ht + 1; if (pageempty || hh + ruletab->wd - 1 > maxhp) maxhp = hh + ruletab->wd - 1; hh += ruletab->wd; h += width; /* use hhh and max_drift to prevent hh drifting too far from h */ hhh = XPixelRound (h); if (abs (hhh - hh) > max_drift) { /* Adjust hh to be just within the allowed tolerance from h. */ hh = hhh + (hhh > hh ? -max_drift : max_drift); } totalrules++; ruletail->rulecount++; pageempty = false; } /* DoSetRule */ /******************************************************************************/ #ifdef __STDC__ Static Void DoPutRule (int height, int width) #else Static Void DoPutRule (height, width) int height; int width; #endif { /* Exactly the same as DoSetRule, but we DON'T update the horizontal position on the page. (We still have to check page edges.) */ _REC_ruletable * ruletab; if (height <= 0 || width <= 0) return; /* may be new ruletable */ if (ruletail->rulecount == ruletablesize) { ruletail->nextrule = (ruleinfo *) Malloc (sizeof (ruleinfo)); /* add new node to end of rule list */ ruletail->nextrule->rulecount = 0; /* reset rulecount */ ruletail->nextrule->nextrule = (ruleinfo *) NULL; ruletail = ruletail->nextrule; } /* allocate a new ruletable */ ruletab = &ruletail->ruletable[ruletail->rulecount]; ruletab->hp = hh; ruletab->vp = vv; ruletab->wd = RulePixels (xconv, width); ruletab->ht = RulePixels (yconv, height); /* do page edges increase? */ /* ref pt of rule is bottom left black pixel */ if (pageempty || hh < minhp) minhp = hh; if (pageempty || vv > maxvp) maxvp = vv; if (pageempty || hh + ruletab->wd - 1 > maxhp) maxhp = hh + ruletab->wd - 1; if (pageempty || vv - ruletab->ht + 1 < minvp) minvp = vv - ruletab->ht + 1; totalrules++; ruletail->rulecount++; pageempty = false; } /* DoPutRule */ /******************************************************************************/ #ifdef __STDC__ Static Void DoFont (int externf) #else Static Void DoFont (externf) int externf; #endif { /* Search font list for externf, setting currfont and fontspace. If this is the first time we've seen this font (on current page) then we need to allocate the first chartable. If this is the first time we've seen this font used at all then we allocate a pixeltable and call routine to fill it in. */ extern fontinfo * currfont, * fontlist; charinfo * char_info = (charinfo *) NULL; currfont = fontlist; while (currfont != (fontinfo *) NULL && currfont->fontnum != externf) { currfont = currfont->nextfont; } /* DEBUG IF currfont = NIL THEN BEGIN WriteLine; WriteString ('Failed to find font #'); WriteInt (externf); WriteLine; RestoreTerminal; EXIT (1); END; GUBED */ if (currfont == NULL) { MesgLine(); MesgString ("Failed to find font #"); MesgInt (externf); MesgLine(); RestoreTerminal(); exit (1); } if (!currfont->fontused) { currfont->fontused = true; currfont->charlist = (charinfo *) Malloc (sizeof (charinfo)); /* allocate first chartable */ char_info = currfont->charlist; char_info->charcount = 0; /* for DoSet/PutChar */ char_info->nextchar = (charinfo *) NULL; /* this node is also last */ currfont->chartail = currfont->charlist; if (currfont->pixelptr == (_REC_pixeltable *) NULL) { /* first time we've seen this font */ currfont->pixelptr = (_REC_pixeltable *) Malloc (sizeof (pixeltable)); PixelTableRoutine (currfont); } } /* do nothing since we've already used this font on this page */ fontspace = currfont->scaledsize / 6; /* See DVITYPE; a 3-unit thin space. Note that a thin space is 1/6 of a quad, where a quad is 1 em in the current font and usually equals the design size. */ } /* DoFont */ /******************************************************************************/ #ifdef __STDC__ Static Void DoSpecial (int hpos, int vpos, int totalbytes) #else Static Void DoSpecial (hpos, vpos, totalbytes) int hpos; int vpos; int totalbytes; #endif { /* in */ /* DVIReader has seen a \special command while interpreting the current page. It will pass the current page position and number of bytes in the command. We save the info away in speciallist for later use by the main program. */ int i; specialinfo * temp; temp = (specialinfo *) Malloc (sizeof (specialinfo)); for (i = 0; i < totalbytes; i++) { int temp1; temp1 = GetDVIByte(); if (i < maxspeciallen) temp->special[i] = temp1; } temp->special[i <= maxspeciallen ? i: maxspeciallen] = '\0'; temp->hp = hpos; temp->vp = vpos; temp->nextspecial = speciallist; speciallist = temp; /* add new info to head of list */ } /* DoSpecial */ /******************************************************************************/ Void InterpretPage (VOID) { /* When this routine is called we are positioned after the bytes of a bop command (i.e., at currbop + 45). At the end of this routine we will be positioned after the eop byte for the current page. In between we carry out the important task of translating the DVI description of this page and filling in the following global data structures: totalrules := number of rules on page rulelist-> (nodes are added to tail of rule list) rulecount := number of rules in this ruletable ruletable[0..rulecount-1]. hp, vp := reference point of a rule wd, ht := pixel dimensions of a rule (both > 0) nextrule := next node in rule list (if not NIL) ruletail := pointer to last node in rule list speciallist-> (nodes are added to head of this list) hp, vp := reference point on page special := \special bytes nextspecial := next node in list (if not NIL) fontlist-> (the following fontinfo is relevant only if fontused is TRUE) totalchars := number of chars on page from this font charlist-> (nodes are added to tail of char list) charcount := number of chars in this chartable chartable[0..charcount-1]. hp, vp := reference point of a character code := TeX character code (and index into pixel table) nextchar := next node in char list (if not NIL) chartail := pointer to last node in char list pixelptr^[0..maxTeXchar]. (filled in by FontReader's PixelTableRoutine) wd, ht := glyph width and height in pixels xo, yo := offsets from the character's reference point dwidth := advance width in DVI units pwidth := advance width in pixels mapadr := offset in fontspec of the glyph's bitmap info bitmap := NIL nextfont := next node in font list (if not NIL) pageempty := TRUE iff the page has no rules and no characters minhp, minvp, maxhp, maxvp := the edges of the page (undefined if pageempty is TRUE) They define the smallest rectangle containing all black pixels on the page;(minhp,minvp) is the top left corner. Reference points for rules and characters are stored as a pair of horizontal and vertical pixel coordinates. The point (0,0) is assumed to be the pixel 1 inch in from the top and left edges of an imaginary sheet of paper. Horizontal coordinates increase to the right and vertical coordinates increase down the paper. The numbers of pixels per inch in the X and Y directions are defined by the xres and yres resolution parameters given to SetConversionFactors. */ int param, ht, wd; InitStateValues(); InitPage(); do { DVIcommand = GetDVIByte(); /* For efficiency reasons the most frequent commands should be tested 1st. The following order is the result of frequency testing on typical DVI files. Note that the most frequent commands in the DVI file generated by TeX 1.3 for the Dec. 1983 LaTeX manual were: z4 && DVIcommand < fnt1) { /* catch all the remaining movement commands */ DoFont (DVIcommand - fntnum0); } else if (DVIcommand > pop && DVIcommand < fntnum0) { if (DVIcommand == right2) DoRight (SignedDVIPair()); else if (DVIcommand == right4) DoRight (SignedDVIQuad()); else if (DVIcommand == x2) { x = SignedDVIPair(); DoRight (x); } else if (DVIcommand == x3) { x = SignedDVITrio(); DoRight (x); } else if (DVIcommand == down3) DoDown (SignedDVITrio()); else if (DVIcommand == down4) DoDown (SignedDVIQuad()); else if (DVIcommand == w2) { w = SignedDVIPair(); DoRight (w); } else if (DVIcommand == z0) DoDown (z); else if (DVIcommand == y3) { y = SignedDVITrio(); DoDown (y); } else if (DVIcommand == z3) { z = SignedDVITrio(); DoDown (z); } else if (DVIcommand == down2) { /* the next DVI commands are used very rarely (by TeX 1.3 at least) */ DoDown (SignedDVIPair()); } else if (DVIcommand == w1) { w = SignedDVIByte(); DoRight (w); } else if (DVIcommand == w4) { w = SignedDVIQuad(); DoRight (w); } else if (DVIcommand == x1) { x = SignedDVIByte(); DoRight (x); } else if (DVIcommand == x4) { x = SignedDVIQuad(); DoRight (x); } else if (DVIcommand == y1_) { y = SignedDVIByte(); DoDown (y); } else if (DVIcommand == y2) { y = SignedDVIPair(); DoDown (y); } else if (DVIcommand == y4) { y = SignedDVIQuad(); DoDown (y); } else if (DVIcommand == z1) { z = SignedDVIByte(); DoDown (z); } else if (DVIcommand == z2) { z = SignedDVIPair(); DoDown (z); } else if (DVIcommand == z4) { z = SignedDVIQuad(); DoDown (z); } else if (DVIcommand == right1) DoRight (SignedDVIByte()); else if (DVIcommand == down1) DoDown (SignedDVIByte()); else { MesgLine(); MesgString ("Bug in InterpretPage!"); MesgLine(); RestoreTerminal(); exit (1); } } else if (DVIcommand == setrule) { ht = SignedDVIQuad(); wd = SignedDVIQuad(); DoSetRule (ht, wd); } else if (DVIcommand == putrule) { ht = SignedDVIQuad(); wd = SignedDVIQuad(); DoPutRule (ht, wd); } else if (DVIcommand >= put1 && DVIcommand <= put1 + 3) { switch (DVIcommand - put1) { case 0: DoPutChar (GetDVIByte()); break; case 1: DoPutChar (GetTwoDVIBytes()); break; case 2: DoPutChar (GetThreeDVIBytes()); break; case 3: DoPutChar (SignedDVIQuad()); break; } } else if (DVIcommand >= set1 && DVIcommand <= set1 + 3) { switch (DVIcommand - set1) { case 0: DoSetChar (GetDVIByte()); break; case 1: DoSetChar (GetTwoDVIBytes()); break; case 2: DoSetChar (GetThreeDVIBytes()); break; case 3: DoSetChar (SignedDVIQuad()); break; } } else if (DVIcommand >= fnt1 && DVIcommand <= fnt1 + 3) { switch (DVIcommand - fnt1) { case 0: DoFont (GetDVIByte()); break; case 1: DoFont (GetTwoDVIBytes()); break; case 2: DoFont (GetThreeDVIBytes()); break; case 3: DoFont (SignedDVIQuad()); break; } } else if (DVIcommand >= xxx1 && DVIcommand <= xxx1 + 3) { switch (DVIcommand - xxx1) { case 0: param = GetDVIByte(); break; case 1: param = GetTwoDVIBytes(); break; case 2: param = GetThreeDVIBytes(); break; case 3: param = SignedDVIQuad(); break; } /* pass current pixel position and number of bytes */ DoSpecial (hh, vv, param); } else if (DVIcommand >= fntdef1 && DVIcommand <= fntdef1 + 3) SkipFntdef (DVIcommand - fntdef1); else if (DVIcommand != nop) { if (DVIcommand != eop) { /* do nothing */ MesgLine(); MesgString ("Unexpected DVI command while interpreting page="); MesgInt (DVIcommand); MesgLine(); RestoreTerminal(); exit (1); } } } while (DVIcommand != eop); /* save position of eop byte for use in MoveToTeXPage */ curreop = DVIoffset - 1; if (stackpos != 0) { MesgLine(); MesgString ("Stack not empty at eop!"); MesgLine(); RestoreTerminal(); exit (1); } /* InitPage values */ /* fntnum0..fntnum63 */ /* skip fntdef command since we've got this info from postamble */ /* do nothing */ } /* InterpretPage */ /******************************************************************************/ #ifdef __STDC__ Void SortFonts (fontinfo ** unusedlist) #else Void SortFonts (unusedlist) fontinfo ** unusedlist; #endif { /* out */ /* Sort fontlist in order of ascending totalchars. Fonts with least characters can then be accessed first. Since the number of fonts used on a typical page is quite small, a simple sorting algorithm should be good enough. Note that unused fonts are moved to the end of the list and unusedlist points to the first such node. DVItoVDU need only process fonts up to (but excluding) unusedlist and does not have to worry about checking the fontused flag. If unusedlist is NIL then either 1) all fonts are used on the current page or 2) fontlist is also NIL (totalfonts = 0). */ fontinfo * newfontlist, * prevfont, * largest, * prevlargest; int mostchars; newfontlist = (fontinfo *) NULL; /* go thru fontlist once and move all unused fonts to head of newfontlist */ prevfont = (fontinfo *) NULL; currfont = fontlist; while (currfont != (fontinfo *) NULL) { if (currfont->fontused) { prevfont = currfont; /* remember previous node */ currfont = currfont->nextfont; continue; } /* move node from fontlist to head of newfontlist and don't change prevfont */ if (prevfont == (fontinfo *) NULL) { fontlist = currfont->nextfont; /* remove first node in fontlist */ currfont->nextfont = newfontlist; newfontlist = currfont; currfont = fontlist; } else { prevfont->nextfont = currfont->nextfont; currfont->nextfont = newfontlist; newfontlist = currfont; currfont = prevfont->nextfont; } } /* unusedlist will be last unused font moved to newfontlist. It will be NIL if either fontlist is NIL or all fonts are used. */ *unusedlist = newfontlist; /* Now go thru fontlist repeatedly moving node with max totalchars to head of newfontlist until fontlist is exhausted. */ while (fontlist != (fontinfo *) NULL) { prevfont = (fontinfo *) NULL; currfont = fontlist; prevlargest = (fontinfo *) NULL; largest = fontlist; mostchars = 0; /* search for largest totalchars */ while (currfont != (fontinfo *) NULL) { if (currfont->totalchars > mostchars) { prevlargest = prevfont; largest = currfont; mostchars = currfont->totalchars; } prevfont = currfont; currfont = currfont->nextfont; } /* move largest node from fontlist to head of newfontlist */ if (prevlargest == (fontinfo *) NULL) fontlist = largest->nextfont; /* remove first node in fontlist */ else prevlargest->nextfont = largest->nextfont; largest->nextfont = newfontlist; newfontlist = largest; } fontlist = newfontlist; /* used fonts now sorted and unused fonts at end */ } /* SortFonts */ /******************************************************************************/ Void CloseDVIFile (VOID) { /* Close the currently open DVI file, and deallocate dynamic data structures. */ int result; result = close (DVIfile); while (fontlist != (fontinfo *) NULL) { currfont = fontlist; while (currfont->charlist != (charinfo *) NULL) { charinfo * thischar; /* temporary pointer to node in charlist */ thischar = currfont->charlist; currfont->charlist = thischar->nextchar; Free (thischar, charinfo); /* deallocate char list */ } if (currfont->pixelptr != (_REC_pixeltable *) NULL) Free (currfont->pixelptr, _REC_pixeltable); /* deallocate pixel table */ fontlist = currfont->nextfont; Free (currfont, fontinfo); /* deallocate font information */ } /* Deallocate rule information except for one node (in case DVItoVDU ever opens another DVI file). */ while (rulelist != ruletail) { ruleinfo * thisrule; /* temporary pointer to node in rulelist */ thisrule = rulelist; rulelist = thisrule->nextrule; Free (thisrule, ruleinfo); } while (speciallist != (specialinfo *) NULL) { specialinfo * thisspecial; /* temporary ptr to node in speciallist */ thisspecial = speciallist; speciallist = speciallist->nextspecial; Free (thisspecial, specialinfo); } } /* CloseDVIFile */ /******************************************************************************/ Void InitDVIReader (VOID) { totalrules = 0; rulelist = (ruleinfo *) Malloc (sizeof (ruleinfo)); /* for first InitPage */ ruletail = rulelist; /* ditto */ speciallist = (specialinfo *) NULL; /* ditto */ fontlist = (fontinfo *) NULL; /* safer for CloseDVIFile */ } /* InitDVIReader */ /******************************************************************************/ /* end dvireader.c */