summaryrefslogtreecommitdiff
path: root/dviware/dvgtk/dvgt.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/dvgtk/dvgt.c
Initial commit
Diffstat (limited to 'dviware/dvgtk/dvgt.c')
-rw-r--r--dviware/dvgtk/dvgt.c3595
1 files changed, 3595 insertions, 0 deletions
diff --git a/dviware/dvgtk/dvgt.c b/dviware/dvgtk/dvgt.c
new file mode 100644
index 0000000000..2c5b6dd3d9
--- /dev/null
+++ b/dviware/dvgtk/dvgt.c
@@ -0,0 +1,3595 @@
+/* dvgtk.c - main dvgtk functions
+ $Id: dvgt.c,v 0.2 1997/03/28 03:15:36 tjchol01 Exp $
+ Authors: Andrew Trevorrow, Ian Dall, Geoffrey Tobin, Tomasz J. Cholewo
+ */
+
+#include "dvgt.h"
+
+#include <kpathsea/c-ctype.h>
+#include <kpathsea/proginit.h>
+#include <kpathsea/tex-file.h>
+
+#include "defaults.h"
+#include "screenio.h"
+#include "options.h"
+#include "unixio.h"
+#include "vdu.h"
+#include "dvireader.h"
+#include "fontreader.h"
+
+/* Variables Exported, via vdu.h */
+
+int DVIstatusl, windowstatusl, messagel, commandl, bottoml;
+int windowh, windowv, windowwd, windowht;
+
+
+static void DisplayPage ();
+static void NextCommandLine ();
+static boolean ShowCmdHelp ();
+
+
+/*----------------------------------------------------------------------
+ DECLARATIONS FOR PROCESSING USER COMMANDS
+
+ Most commands consist of one or two characters and can be entered in
+ upper or lowercase. Multiple commands are processed in the order
+ given but we only update the window, if necessary, at the end. If a
+ bad command is encountered, any further commands are ignored. Some
+ commands can have parameters; they are all dimensions in terms of the
+ current units. Spaces before and after commands and parameters are
+ ignored.
+*/
+
+/* Possible commands are: */
+/* i a positive integer; display ith DVI page */
+
+#define TeXpage "["
+ /* start of a TeX page specification: [i0. ... .i9] */
+#define NextPage "N"
+ /* display next DVI page, depending on direction */
+#define Window "W"
+ /* move window's top left corner to given position */
+#define Up "U"
+ /* move window up a given amount */
+#define Down "D"
+ /* move window down a given amount */
+#define Left "L"
+ /* move window left a given amount */
+#define Right "R"
+ /* move window right a given amount */
+#define Hsize "H"
+ /* set scaledwd: window's horizontal size */
+#define Vsize "V"
+ /* set scaledht: window's vertical size */
+#define AutoView "A"
+ /* enable/disable automatic view after page selection */
+#define ZoomInOut "Z"
+ /* halve/double window dimensions */
+#define Terse "T"
+ /* display quick and nasty chars at reference points */
+#define Box "B"
+ /* display box outlines of glyphs */
+#define Full "F"
+ /* display all pixels in glyphs */
+#define Ic "I"
+ /* get/show dimensions in inches */
+#define Cm "C"
+ /* get/show dimensions in centimetres */
+#define Mm "M"
+ /* get/show dimensions in millimetres */
+#define PcPtPx "P"
+ /* get/show dimensions in picas/points/pixels */
+#define Help "?"
+ /* display help on available commands */
+#define Show "S"
+ /* display useful statistics */
+#define Quit "Q"
+ /* have a guess */
+
+#define commprompt "Command: "
+
+
+static String commstring; /* holds user responses */
+static int commpos; /* current position in commstring */
+static int commlen; /* length of commstring */
+static char command; /* starting character of command */
+static int maxpix;
+/* maximum absolute pixel value; depends on resolution */
+/* These flags are used to handle multiple commands: */
+static boolean screenjustcleared;
+ /* has screen just been cleared? */
+static boolean paintDVIStatus; /* does DVI status line need updating? */
+static boolean paintWindowStatus;
+ /* does window status line need updating? */
+static boolean paintwindow; /* does window region need updating? */
+static boolean pageoffpaper; /* is page off paper? */
+static boolean badcommand; /* was there a bad command? */
+
+
+/*----------------------------------------------------------------------
+ DECLARATIONS FOR DISPLAYING A PAGE
+
+ The reference points of characters and rules on a page are stored as
+ pairs of horizontal and vertical paper pixel coordinates.
+ The paper coordinate scheme is described in detail in DVIReader.
+ The screen coordinate scheme is described in detail in VDU.
+ To update the window region, DVItoVDU maps visible paper pixels
+ to screen pixels using windowh and windowv to help with translation,
+ and windowwd and windowht to help with scaling.
+ What the user sees depends on the current displaymode, the current size
+ of the window region (scaledwd by scaledht are in paper pixels and determine
+ the horizontal and vertical scaling factors), and the current paper position
+ of the window region's top left corner; i.e., (windowleft,windowtop).
+
+ A NOTE ON THE SCALING METHOD USED BY DVItoVDU:
+ We desire the following conditions when scaling paper pixels to
+ screen pixels:
+ 1. Rules/glyphs having the same top/bottom/left/right paper coordinates also
+ have the same screen coordinates (e.g., to ensure baselines line up).
+ This condition is incompatible with a rule/glyph staying the same
+ width and height as the window position changes! Too bad.
+ 2. After being scaled, visible pixel positions must not exceed the
+ window region's edges. In our case, only the bottom and right edges are
+ a problem because scaling starts at the top left corner of the window.
+ We use two different scaling calculations depending on
+ whether the h/vscalefactors are < 1.0 or not.
+ 3. Scaled heights and widths must be > 0 even when h/vscalefactors
+ approach 0. If h/vscalefactors are > 1.0 then the width/height of
+ paper pixels increase accordingly.
+*/
+
+/* terse - show quick and nasty chars at ref pts */
+/* box - show box outlines of glyphs */
+/* full - show all pixels in glyphs */
+
+#define tersemode 1
+#define boxmode 2
+#define fullmode 4
+int displaymode;
+
+/* we get/show dimensions in currentunits */
+units currentunits;
+
+static int papertop, paperleft, paperbottom, paperright;
+ /* these define the edges of the paper */
+
+static int windowtop, windowleft, windowbottom, windowright;
+ /* these define the current window edges */
+
+static boolean allpagevisible; /* is all of page visible in window? */
+static boolean outsidepage; /* is entire window outside page? */
+static int scaledht; /* current window height in paper pixels */
+static int scaledwd; /* current window width in paper pixels */
+static double zoomfactor; /* current zoom factor - default is 2 */
+static double vscalefactor; /* windowht / scaledht */
+static double hscalefactor; /* windowwd / scaledwd */
+static ruleinfo *thisruleinfo; /* current rule info in rulelist */
+static fontinfo *unusedfont; /* first unused font in sorted fontlist */
+static fontinfo *thisfontinfo; /* current font info in sorted fontlist */
+static charinfo *thischarinfo; /* current char info in charlist */
+static int thischar; /* current index into current chartable */
+static boolean fontopen; /* is thisfontinfo->fontspec open? */
+static boolean useraborted; /* did user abort page display? */
+static boolean autoviewing; /* automatic window view enabled? */
+
+static char *immed_help_strings[] =
+{
+ DVGT_VERSION,
+ "dvgt interactively views TeX-generated DVI files on some common VDUs.",
+ "This is the precompiled help shown if no arguments are given.",
+ "The options help file, `options.txt', gives more information.",
+ "USAGE:",
+ " dvgt filename[.dvi]",
+ " [-H x_offset] [-V y_offset] [-d dummy_pk] [-e dummy_tfm]",
+ " [-i] [-k kpathsea_debug_mode] [-l]",
+ " [-m magnification] [-r xres[,yres]]",
+ " [-t tfm_directory] [-x paperwd] [-y paperht]",
+ "",
+ "-H horizontal_offset (default = 0.0 in)",
+ "-V vertical_offset (default = 0.0 in)",
+ "-l (set landscape mode, instead of the default portrait mode)",
+ "-m magnification (default = DVI file's intrinsic magnification)",
+ "",
+ "The other parameters' default values are system dependent.",
+ NULL
+};
+
+static char *cmd_help_strings[] =
+{
+ "MISCELLANEOUS CHANGING PAGE DISPLAY (TOGGLES)",
+ "? Display this command help info T Terse - fast but inaccurate",
+ "S Show options, fonts and page info B Bounding Box of glyphs",
+ "A Toggle Auto window F Full - accurate but slow",
+ "^L Refresh screen",
+ "Q Quit from dvgt CHANGING UNITS OF DIMENSIONS",
+ " C u Where u is one of the units",
+ "SELECTING A PAGE BP, CM, IN, MM, PC, PT, PX, or SP",
+ "[i0. ... .i9] Select TeX page (big point, cm, inch, mm, pica,",
+"i Select the ith DVI page point, paper pixel, or scaled point)",
+ "N Next DVI page",
+ "P Previous DVI page MOVING THE WINDOW",
+ " W h,v Move Window to given posn",
+"CHANGING THE SIZE OF THE WINDOW or to (minh,minv) if no h,v ",
+ "H x Set Horiz. window size to x U v Move window Up by v",
+" or to unscaled width if no x or by half current ht if no v",
+ "V y Set Vertical window size to y D v Move window Down by v",
+ " or to unscaled height if no y or by half cur. ht if no v",
+ "ZI z Zoom In by factor z L h Move window Left by h",
+" or by current factor if no z or by half cur. width if no h",
+ "ZO z Zoom Out, as for ZI R h Move window Right by h",
+"ZCI z, ZCO z Zoom wrt window center or by half cur. width if no h",
+ NULL
+};
+
+/*--------------------------------------------------------------------*/
+
+static void
+ClearMessageLine ()
+{
+ /* Clear message line and move cursor to start of line.
+ We don't show any message here; that will usually be done
+ immediately after calling this routine.
+ */
+ ClearTextLine (messagel);
+ MoveToTextLine (messagel);
+}
+/* ClearMessageLine */
+/*--------------------------------------------------------------------*/
+static void
+WaitForReturn ()
+{
+ /* DVItoVDU has just displayed an important message.
+ To ensure message is seen we wait for user to hit Return.
+ */
+
+ char ch;
+
+ MesgFlush ();
+ do
+ {
+ ReadChar (&ch);
+ }
+ while (ch != CR);
+}
+/* WaitForReturn */
+/*--------------------------------------------------------------------*/
+static boolean
+PrintText (char **text)
+{
+ int retval = false;
+
+ if (text == (char **) NULL)
+ {
+ retval = false; /* No text to print. */
+ }
+ else
+ {
+ /* Print each text string */
+ for (; *text != (char *) NULL; text++)
+ {
+ printf ("%s", *text);
+ /* If there's no newline in *text, print one. */
+ if (strchr (*text, '\n') == (char *) NULL)
+ printf ("\n");
+ }
+ retval = true;
+ }
+ return retval;
+}
+/* PrintText */
+/*--------------------------------------------------------------------*/
+static boolean
+ShowText (char **text)
+{
+ /* Show text of consecutive lines, in a way something like UNIX more. */
+ int lines;
+ char answer;
+
+ if (text == (char **) NULL)
+ {
+ ClearMessageLine ();
+ MesgString ("NULL text!");
+ return false;
+ }
+ ClearScreen ();
+ screenjustcleared = true;
+ MoveToTextLine (1);
+ rawoutoff ();
+
+ for (lines = 0; true; lines++)
+ {
+ if (text[lines] == (char *) NULL)
+ { /* end of text */
+ ClearTextLine (bottoml);
+ MoveToTextLine (bottoml);
+ MesgString ("End of text,");
+ MesgString (" hit RETURN key to resume page display: ");
+ MesgFlush ();
+ do
+ {
+ ReadChar (&answer);
+ }
+ while (answer != CR);
+ break; /* EXIT point 1 of 2 from enclosing (for) loop */
+ }
+ if (lines >= bottoml - 2)
+ {
+ /* blank line before prompt */
+ ClearTextLine (bottoml);
+ MoveToTextLine (bottoml);
+
+ /* prompt */
+ MesgString ("Hit RETURN key to resume page display,");
+ MesgString (" or any other key for more text: ");
+ MesgFlush ();
+
+ ReadChar (&answer);
+ if (answer == CR)
+ break; /* EXIT point 2 of 2 from enclosing (for) loop */
+
+ ClearScreen ();
+ screenjustcleared = true;
+ MoveToTextLine (1);
+ lines = 0; /* reset line count */
+ }
+ MesgString (text[lines]);
+ MesgLine ();
+ }
+
+ rawouton ();
+ ClearScreen ();
+ screenjustcleared = true;
+ paintDVIStatus = true;
+ paintWindowStatus = true;
+ if (currDVIpage != 0)
+ paintwindow = true;
+
+ return true;
+}
+/* ShowText */
+
+/*--------------------------------------------------------------------*/
+static boolean
+ShowCmdHelp ()
+{
+ /* Help information is displayed in lines 1 to bottoml-2.
+ We assume that bottoml is at least 3 and that VDU screen is at least
+ maxline characters wide.
+ */
+ return ShowText (cmd_help_strings);
+}
+/* ShowCmdHelp */
+/*--------------------------------------------------------------------*/
+void
+PadMesg ()
+{
+ /* Pad current text line with spaces. */
+ String padding;
+ int i;
+ for (i = 0; i < maxstring; i++)
+ padding[i] = ' ';
+ padding[maxstring] = '\0';
+ MesgString (padding);
+}
+/* Pad Mesg */
+/*--------------------------------------------------------------------*/
+static void
+InitWinVars ()
+{
+ /* TeX will not generate dimensions > than about 38 feet, so we
+ choose an absolute limit on our dimensions to be 40 feet.
+ */
+
+ int ymaxpix = yres * (40 * 12); /* 40 ft = 40 * 12 in */
+ maxpix = xres * (40 * 12);
+ if (ymaxpix < maxpix)
+ maxpix = ymaxpix;
+
+ /* top left corner of paper is fixed at (-1",-1") */
+ papertop = -yres;
+ paperleft = -xres;
+
+ paperbottom = papertop + paperht - 1;
+ paperright = paperleft + paperwd - 1;
+
+ /* User sees the following status values before requesting the first page. */
+
+ /*
+ FIRST STATUS LINE: # pages, DVI page, TeX page, Auto, Displaymode, Zoom.
+ Note that DVIReader has already counted the number of pages,
+ and initialized currDVIpage and currTeXpage.
+ */
+
+ autoviewing = true; /* start off enabled */
+ displaymode = fullmode; /* Full mode, neither Box nor Terse mode */
+ zoomfactor = 2.0; /* default factor for zooming is 2 */
+
+ /*
+ SECOND STATUS LINE: Window loc. & dims, Page loc. & dims, Unit.
+ */
+
+ windowleft = 0; /* window location */
+ windowtop = 0;
+ scaledwd = windowwd; /* window size is initially unscaled */
+ scaledht = windowht;
+
+ minhp = 0;
+ minvp = 0; /* page location */
+ maxhp = 0;
+ maxvp = 0;
+ hscalefactor = 1.0; /* page size is initially unscaled, too */
+ vscalefactor = 1.0;
+
+ currentunits = ic; /* inch */
+
+ /* WINDOW: Chars & Rules. */
+
+ pageempty = true; /* no page read yet, so no chars and no rules! */
+}
+/* InitWinVars */
+
+/*--------------------------------------------------------------------*/
+static void
+UpdateDVIStatusLine ()
+{
+ /* Show totalpages, currDVIpage, currTeXpage, direction and displaymode. */
+
+ int i, lastnonzero;
+
+ ClearTextLine (DVIstatusl);
+ MoveToTextLine (DVIstatusl);
+
+ MesgInt (totalpages);
+ MesgString (" pages");
+
+ MesgString (" DVI page=");
+ MesgInt (currDVIpage);
+
+ MesgString (" TeX page=");
+
+ MesgChar ('[');
+
+ lastnonzero = 9;
+ while (lastnonzero > 0 && currTeXpage[lastnonzero] == 0)
+ {
+ lastnonzero--; /* find last counter with non-zero value */
+ }
+ /* always show \count0 but don't show trailing 0 counters */
+ for (i = 0; i <= lastnonzero; i++)
+ {
+ MesgInt (currTeXpage[i]);
+
+ if (i != lastnonzero)
+ MesgChar ('.');
+ }
+ MesgChar (']');
+
+ MesgString (" Auto=");
+ if (autoviewing)
+ MesgChar ('+');
+ else
+ MesgChar ('-');
+
+ MesgString (" ");
+ if (displaymode & tersemode)
+ MesgString ("T");
+ else
+ MesgString (" ");
+
+ if (displaymode & boxmode)
+ MesgString ("B");
+ else
+ MesgString (" ");
+
+ if (displaymode & fullmode)
+ MesgString ("F");
+ else
+ MesgString (" ");
+
+ {
+ String msgstring;
+ /* gt - this is surely safe from overflow of msgstring - yes? */
+ sprintf (msgstring, " Zoom=%.2f", zoomfactor);
+ MesgString (msgstring);
+ }
+
+ MesgLine ();
+}
+/* UpdateDVIStatusLine */
+
+
+/*--------------------------------------------------------------------*/
+static void
+WriteDimension (double precision, double res, int pixels)
+{
+ /* Show the given pixel dimension in terms of currentunits. */
+
+ double realdim = 0.0;
+ int fracpart;
+
+ if (currentunits == px)
+ MesgInt (pixels);
+ else
+ {
+ switch (currentunits)
+ {
+ case ic:
+ realdim = (double) pixels / res;
+ break;
+ case cm:
+ realdim = (double) pixels / res * 2.54;
+ break;
+ case mm:
+ realdim = (double) pixels / res * 25.4;
+ break;
+ case bp:
+ realdim = (double) pixels / res * 72.0;
+ break;
+ case pc:
+ realdim = (double) pixels / res * 72.27 / 12.0;
+ break;
+ case pt:
+ realdim = (double) pixels / res * 72.27;
+ break;
+ case sp:
+ realdim = (double) pixels / res * 72.27 * 65536.0;
+ break;
+ case px:
+ return; /* can't happen */
+ } /* currentunits */
+ /* gt - This seems immensely complicated, for what it's doing! */
+ /* show realdim to the specified precision */
+ if (fabs (realdim) < 0.5 * precision)
+ MesgString ("0.0");
+ else
+ {
+ if (realdim < 0.0)
+ {
+ MesgChar ('-');
+ realdim = fabs (realdim);
+ }
+ realdim += 0.5 * precision; /* round up to specified precision */
+ MesgInt ((int) realdim); /* whole part */
+ MesgChar ('.');
+ fracpart = (int) ((realdim - (int) realdim) / precision);
+ MesgInt (fracpart);
+ } /* if */
+ } /* if */
+}
+
+/* WriteDimension */
+
+/*--------------------------------------------------------------------*/
+static void
+WriteXDim (double precision, int pixels)
+{
+ WriteDimension (precision, xres, pixels);
+}
+/* Write XDim */
+/*--------------------------------------------------------------------*/
+static void
+WriteYDim (double precision, int pixels)
+{
+ WriteDimension (precision, yres, pixels);
+}
+/* Write YDim */
+/*--------------------------------------------------------------------*/
+static void
+UpdateWindowStatusLine ()
+{
+ /* Show current window location and size, page location and size, and units. */
+
+ double precision = 0.1; /* precision for status line */
+
+ ClearTextLine (windowstatusl);
+ MoveToTextLine (windowstatusl);
+
+ MesgString ("Window at (");
+ WriteXDim (precision, windowleft);
+ MesgChar (',');
+ WriteYDim (precision, windowtop);
+ MesgString (") ");
+ WriteXDim (precision, scaledwd);
+ MesgString (" by ");
+ WriteYDim (precision, scaledht);
+
+ MesgString (" Page at (");
+ WriteXDim (precision, minhp);
+ MesgChar (',');
+ WriteYDim (precision, minvp);
+ MesgString (") ");
+ WriteXDim (precision, maxhp - minhp + 1);
+ MesgString (" by ");
+ WriteYDim (precision, maxvp - minvp + 1);
+ MesgString (" ");
+
+ switch (currentunits)
+ {
+ case ic:
+ MesgString ("IN");
+ break;
+ case cm:
+ MesgString ("CM");
+ break;
+ case mm:
+ MesgString ("MM");
+ break;
+ case bp:
+ MesgString ("BP");
+ break;
+ case pc:
+ MesgString ("PC");
+ break;
+ case pt:
+ MesgString ("PT");
+ break;
+ case sp:
+ MesgString ("SP");
+ break;
+ case px:
+ MesgString ("PX");
+ break;
+ } /* currentunits */
+ MesgLine ();
+}
+/* UpdateWindowStatusLine */
+/*--------------------------------------------------------------------*/
+#define limit 2147483647
+/* TeX's limit = 2^31 - 1.
+ Should also be >= maxpix.
+ Note that this also defines the range of
+ page numbers the user can ask for! */
+#define threshold (limit / 10) /* nearing overflow */
+
+
+static boolean
+GetInteger (char *str_in, int slen, int *pos, int *n)
+{
+ /* Extract an integer from given str_in starting at given pos.
+ pos is also used to return the position after the integer.
+ If no integer is found, then set n to 0 and return FALSE
+ (in that case, pos will only change if leading spaces were skipped).
+ If ABS(n) > limit then set n to sign * limit.
+ Valid syntax is +{digit} or -{digit} or digit{digit}.
+ Note that a + or - by itself is valid and sets n to 0.
+ */
+
+ String str;
+
+ int absval, last, sign;
+ boolean inttoobig;
+ boolean intfound = false;
+
+ memcpy (str, str_in, sizeof (String));
+
+ while (*pos < slen && str[*pos] == ' ')
+ { /* skip any leading spaces */
+ (*pos)++;
+ }
+
+ absval = 0;
+ sign = 1;
+ last = *pos;
+ inttoobig = false;
+
+ if (*pos < slen)
+ {
+ if (str[*pos] == '-')
+ {
+ sign = -1;
+ last++;
+ }
+ else
+ {
+ if (str[*pos] == '+')
+ last++;
+ }
+
+ while (last < slen && (str[last] >= '0' && str[last] <= '9'))
+ {
+ if (absval > threshold || (absval == threshold && str[last] > '7'))
+ inttoobig = true;
+ else
+ absval = absval * 10 + str[last] - '0';
+ last++;
+ }
+ }
+ if (*pos == last)
+ {
+ *n = 0;
+ intfound = false;
+ }
+ else
+ {
+ *pos = last;
+ if (inttoobig)
+ absval = limit;
+ *n = sign * absval;
+ intfound = true;
+ }
+
+ return intfound;
+} /* GetInteger */
+
+#undef limit
+#undef threshold
+/*--------------------------------------------------------------------*/
+static boolean
+GetReal (char *str_in, int slen, int *pos, double *r)
+{
+ /* Extract a real number r from given str_in starting at given pos.
+ pos is also used to return the position after the real number.
+ If no number is found, then set r to 0.0 and return FALSE
+ (in that case pos will only change if leading spaces were skipped).
+ Valid syntax of a real number is integer[.{digit}] or .{digit}
+ where an integer is defined by GetInteger.
+ Real numbers are truncated to 4 decimal places.
+ Note that a sign or decimal point by itself is valid and sets r to 0.0.
+ */
+
+ String str;
+ int sign, intpart, fracpart, divisor;
+ double absreal;
+
+ memcpy (str, str_in, strlen (str_in) + 1);
+
+ /* GetInteger does not remember a sign by itself, so we need to check
+ for -ve dimensions like -.5 first.
+ */
+
+ while (*pos < slen && str[*pos] == ' ')
+ { /* skip any spaces */
+ (*pos)++;
+ }
+
+ sign = 1;
+ if (*pos < slen)
+ {
+ if (str[*pos] == '-')
+ sign = -1;
+ }
+ if (!GetInteger (str, slen, pos, &intpart))
+ {
+ if (*pos == slen || str[*pos] != '.')
+ {
+ *r = 0.0;
+ return false;
+ }
+ }
+ /* real number is valid;
+ if no integer part, then intpart will be 0;
+ sign = +|-1
+ */
+ if (*pos == slen || str[*pos] != '.')
+ {
+ /* no fractional part */
+ absreal = (double) abs (intpart);
+ }
+ else
+ {
+ /* extract fractional part */
+ (*pos)++; /* skip over decimal point */
+ divisor = 1;
+ fracpart = 0;
+ while (*pos < slen && (str[*pos] >= '0' && str[*pos] <= '9'))
+ {
+ /* only consider up to 4 decimal places */
+ if (divisor < 10000)
+ {
+ divisor *= 10;
+ fracpart = fracpart * 10 + str[*pos] - '0';
+ }
+ (*pos)++;
+ }
+ absreal = (double) abs (intpart) + (double) fracpart / divisor;
+ }
+
+ *r = sign * absreal;
+
+ return true;
+} /* GetReal */
+
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+GetDimension (double res, char *str_in, int slen, int *pos, int *n)
+{
+ /* Extract a dimension from given str_ starting at given pos.
+ n returns the corresponding number of pixels in the dimension
+ (which is an integer or real value in terms of currentunits);
+ pos is also used to return the position after the dimension.
+ If no dimension is found then set n to 0 and return FALSE (pos will only
+ change if leading spaces were skipped).
+ If ABS(n) > maxpix then set n to sign * maxpix.
+ Valid syntax of a dimension is integer[.{digit}] or .{digit} where
+ an integer is defined by GetInteger.
+ Real dimensions are truncated to 4 decimal places.
+ Note that a sign or decimal point by itself is valid and sets n to 0.
+ */
+
+ String str;
+ int sign, intdim, fracpart, divisor;
+ double absrealdim;
+ boolean intpresent, dimtoobig;
+
+ memcpy (str, str_in, sizeof (String));
+
+ /* GetInteger does not remember a sign by itself, so we need to check
+ for -ve dimensions like -.5 first.
+ */
+
+ while (*pos < slen && str[*pos] == ' ')
+ { /* skip any leading spaces */
+ (*pos)++;
+ }
+
+ sign = 1;
+ if (*pos < slen)
+ {
+ if (str[*pos] == '-')
+ sign = -1;
+ }
+ intpresent = GetInteger (str, slen, pos, &intdim);
+ if (!intpresent)
+ {
+ if (*pos == slen || str[*pos] != '.')
+ {
+ *n = 0;
+ return false;
+ }
+ } /* if */
+ /* dimension is valid; if no integer part then intdim will be 0; sign = +|-1 */
+ if (*pos == slen || str[*pos] != '.')
+ {
+ /* no fractional part */
+ absrealdim = abs (intdim);
+ }
+ else
+ {
+ /* extract fractional part */
+ (*pos)++; /* skip over decimal point */
+ divisor = 1;
+ fracpart = 0;
+ while (*pos < slen && (str[*pos] >= '0' && str[*pos] <= '9'))
+ {
+ /* only consider up to 4 decimal places */
+ if (divisor < 10000)
+ {
+ divisor *= 10;
+ fracpart = fracpart * 10 + str[*pos] - '0';
+ }
+ (*pos)++;
+ } /* while */
+ absrealdim = abs (intdim) + (double) fracpart / divisor;
+ } /* if */
+
+ /* calculate n based on absrealdim, sign and currentunits */
+ dimtoobig = false;
+ switch (currentunits)
+ {
+ case ic:
+ if (absrealdim > (double) maxpix / res)
+ dimtoobig = true;
+ else
+ *n = sign * (int) (absrealdim * res + 0.5);
+ break;
+ case cm:
+ if (absrealdim > (double) maxpix / res * 2.54)
+ dimtoobig = true;
+ else
+ *n = sign * (int) (absrealdim / 2.54 * res + 0.5);
+ break;
+ case mm:
+ if (absrealdim > (double) maxpix / res * 25.4)
+ dimtoobig = true;
+ else
+ *n = sign * (int) (absrealdim / 25.4 * res + 0.5);
+ break;
+ case bp:
+ if (absrealdim > (double) maxpix / res * 72.0)
+ dimtoobig = true;
+ else
+ *n = sign * (int) (absrealdim / 72.0 * res + 0.5);
+ break;
+ case pc:
+ if (absrealdim > (double) maxpix / res * (72.27 / 12.0))
+ dimtoobig = true;
+ else
+ *n = sign * (int) (absrealdim / 72.27 * 12.0 * res + 0.5);
+ break;
+ case pt:
+ if (absrealdim > (double) maxpix / res * 72.27)
+ dimtoobig = true;
+ else
+ *n = sign * (int) (absrealdim / 72.27 * res + 0.5);
+ break;
+ case sp:
+ if (absrealdim > (double) maxpix / res * 72.27 * 65536.0)
+ dimtoobig = true;
+ else
+ *n = sign * (int) (absrealdim / (72.27 * 65536.0) * res + 0.5);
+ break;
+ case px:
+ if (absrealdim > maxpix)
+ dimtoobig = true;
+ else
+ *n = sign * (int) (absrealdim + 0.5);
+ break;
+ } /* currentunits */
+
+ if (dimtoobig)
+ *n = sign * maxpix;
+
+ return true;
+}
+/* GetDimension */
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+GetXDim (char *str_in, int slen, int *pos, int *n)
+{
+ return GetDimension (xres, str_in, slen, pos, n);
+}
+/* GetXDim */
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+GetYDim (char *str_in, int slen, int *pos, int *n)
+{
+ return GetDimension (yres, str_in, slen, pos, n);
+}
+/* GetYDim */
+
+/*--------------------------------------------------------------------*/
+
+static void
+BadCommandMessage ()
+{
+ /* A bad command has just been detected and some sort of message displayed.
+ Note that commpos is pointing to just after the problem character.
+ If there are further commands then we show user what will be ignored.
+ */
+
+ int i;
+
+ badcommand = true;
+
+ ClearTextLine (commandl);
+ MoveToTextLine (commandl);
+
+ MesgString (commprompt);
+ for (i = 0; i < commpos; i++)
+ MesgChar (commstring[i]);
+ MesgChar ('!'); /* put ! after the problem character */
+ if (commpos < commlen)
+ {
+ MesgString (" Ignoring: ");
+ for (i = commpos; i < commlen; i++)
+ MesgChar (commstring[i]);
+ }
+ NextCommandLine ();
+}
+/* BadCommandMessage */
+
+/*--------------------------------------------------------------------*/
+
+static void
+NewLocation (int newhp, int newvp)
+{
+ /* Change window location to given position and update window edges.
+ If entire window moves outside non-empty page rectangle then outsidepage
+ becomes TRUE and we restrict movement to just beyond the edge(s) so that
+ user can easily move window (via Up,Down,Left,Right) to positions
+ in which one or more window and page edges coincide.
+ Note that allpagevisible is also updated.
+ */
+
+ outsidepage = false;
+ if (currDVIpage != 0 && !pageempty)
+ {
+ /* check if new position puts window entirely outside edges;
+ if so then minimize the movement needed to keep this true */
+
+ if (newvp > maxvp)
+ {
+ outsidepage = true;
+ newvp = maxvp + 1;
+ }
+ else if (newvp <= minvp - scaledht)
+ {
+ outsidepage = true;
+ newvp = minvp - scaledht;
+ }
+ if (newhp > maxhp)
+ {
+ outsidepage = true;
+ newhp = maxhp + 1;
+ }
+ else if (newhp <= minhp - scaledwd)
+ {
+ outsidepage = true;
+ newhp = minhp - scaledwd;
+ }
+ }
+ windowtop = newvp;
+ windowleft = newhp;
+ windowbottom = windowtop + scaledht - 1;
+ windowright = windowleft + scaledwd - 1;
+ allpagevisible = (currDVIpage != 0 && !pageempty
+ && (minvp >= windowtop && maxvp <= windowbottom)
+ && (minhp >= windowleft && maxhp <= windowright));
+
+ /* even if pageempty or window hasn't moved we must still call DisplayPage */
+
+ if (currDVIpage != 0)
+ paintwindow = true;
+}
+/* NewLocation */
+
+/*--------------------------------------------------------------------*/
+
+static void
+WindowMove ()
+{
+ /* Syntax of Window command is W hpos,vpos where hpos and vpos are
+ dimensions with leading and/or trailing spaces. If hpos,vpos absent
+ then we move to minhp,minvp (top left corner of page rectangle).
+ */
+
+ int hpos, vpos; /* move window to this new position */
+
+ /* commpos is positioned after W */
+
+ /* seek hpos */
+ if (!GetXDim (commstring, commlen, &commpos, &hpos))
+ {
+ /* hpos,vpos absent - move to top left of page */
+ NewLocation (minhp, minvp);
+ return;
+ }
+ /* skip any spaces before comma */
+ while (commpos < commlen && commstring[commpos] == ' ')
+ commpos++;
+
+ /* seek comma */
+ if (commpos == commlen || commstring[commpos] != ',')
+ {
+ /* comma , (which ought to precede vpos) is missing */
+ ClearMessageLine ();
+ MesgString ("Comma expected!");
+ if (commpos < commlen)
+ commpos++;
+ BadCommandMessage ();
+ return;
+ }
+ commpos++; /* skip over comma */
+
+ /* seek vpos */
+ if (GetYDim (commstring, commlen, &commpos, &vpos))
+ {
+ NewLocation (hpos, vpos);
+ }
+ else
+ {
+ /* vpos is missing or wrongly typed */
+ ClearMessageLine ();
+ MesgString ("Vertical coordinate expected!");
+ if (commpos < commlen)
+ commpos++;
+ BadCommandMessage ();
+ }
+}
+/* WindowMove */
+
+/*--------------------------------------------------------------------*/
+
+static void
+WindowUpDown ()
+{
+ int amount; /* move window up/down this many pixels */
+ char STR[2];
+
+ /* commpos is positioned after U or D */
+ if (!GetYDim (commstring, commlen, &commpos, &amount))
+ /* if amount absent, move by _half_ window height */
+ amount = scaledht / 2; /* for odd scaleht, this is half a pixel less */
+
+ sprintf (STR, "%c", command);
+ if (!strcmp (STR, Up)) /* move Up. (Down is positive.) */
+ amount = -amount;
+
+ NewLocation (windowleft, windowtop + amount);
+}
+/* WindowUpDown */
+
+/*--------------------------------------------------------------------*/
+
+static void
+WindowLeftRight ()
+{
+ int amount; /* move window left/right this many pixels */
+ char STR[2];
+
+ /* commpos is positioned after L or R */
+ if (!GetXDim (commstring, commlen, &commpos, &amount))
+ /* if amount absent, move by _half_ window width */
+ amount = scaledwd / 2; /* for odd scaledwd, this is half a pixel less */
+
+ sprintf (STR, "%c", command);
+ if (!strcmp (STR, Left)) /* move Left. (Right is positive.) */
+ amount = -amount;
+
+ NewLocation (windowleft + amount, windowtop);
+}
+/* WindowLeftRight */
+
+/*--------------------------------------------------------------------*/
+
+static void
+NewWindowWidth (int wd)
+{
+ /* Set window width to given value (> 0 and <= max dimension). */
+
+ scaledwd = wd;
+ hscalefactor = (double) windowwd / scaledwd;
+}
+
+/* NewWindowWidth */
+
+/*--------------------------------------------------------------------*/
+
+static void
+SetWindowWidth ()
+{
+ /* Set horizontal size of window region to given dimension;
+ if <= 0, then set horizontal size to 1 pixel.
+ If no parameter, then use the unscaled width represented by windowwd.
+ */
+
+ int wd;
+
+ /* commpos is positioned after H */
+ if (!GetXDim (commstring, commlen, &commpos, &wd))
+ { /* parameter absent */
+ NewWindowWidth (windowwd);
+ return;
+ }
+ /* note that maximum value of wd is restricted to maxpix */
+ if (wd <= 0)
+ wd = 1;
+ NewWindowWidth (wd);
+}
+/* SetWindowWidth */
+
+/*--------------------------------------------------------------------*/
+
+static void
+NewWindowHeight (int ht)
+{
+ /* Set window height to given value (> 0 and <= max dimension). */
+
+ scaledht = ht;
+ vscalefactor = (double) windowht / scaledht;
+}
+
+/* NewWindowHeight */
+
+/*--------------------------------------------------------------------*/
+
+static void
+SetWindowHeight ()
+{
+ /* Set vertical size of window region to given dimension;
+ if <= 0, then set vertical size to 1 pixel.
+ If no parameter, then use the unscaled height represented by windowht.
+ */
+
+ int ht;
+
+ /* commpos is positioned after V */
+ if (!GetYDim (commstring, commlen, &commpos, &ht))
+ { /* parameter absent */
+ NewWindowHeight (windowht);
+ return;
+ }
+ /* note that maximum value of ht is restricted to maxpix */
+ if (ht <= 0)
+ ht = 1;
+ NewWindowHeight (ht);
+}
+/* SetWindowHeight */
+
+/*--------------------------------------------------------------------*/
+
+static int
+ScaleHpos (int h)
+{
+ /* Return a scaled value for the given horizontal window coordinate. */
+
+ if (hscalefactor > 1.0)
+ return ((int) (h * hscalefactor + 0.5));
+ else /* hscalefactor <= 1.0 */
+ return ((int) ((h + 0.5) * hscalefactor));
+}
+
+/* ScaleHpos */
+
+/*--------------------------------------------------------------------*/
+
+static int
+ScaleVpos (int v)
+{
+ /* Return a scaled value for the given vertical window coordinate. */
+
+ if (vscalefactor > 1.0)
+ return ((int) (v * vscalefactor + 0.5));
+ else /* vscalefactor <= 1.0 */
+ return ((int) ((v + 0.5) * vscalefactor));
+}
+
+/* ScaleVpos */
+
+/*--------------------------------------------------------------------*/
+
+static void
+SetAutoView ()
+{
+ /* Toggle AutoView. */
+
+ autoviewing = (autoviewing == false ? true : false);
+}
+
+/* SetAutoView */
+
+/*--------------------------------------------------------------------*/
+
+static void
+ZITL ()
+{
+ /* Zoom In, fixing Top Left of window. */
+
+ /* scaledwd and scaledht are > 0 */
+ NewWindowWidth ((int) ceil (scaledwd / zoomfactor));
+ NewWindowHeight ((int) ceil (scaledht / zoomfactor));
+}
+
+/* ZITL */
+
+/*--------------------------------------------------------------------*/
+
+static void
+ZOTL ()
+{
+ /* Zoom out, fixing Top Left of window. */
+
+ /* avoid overflow *//* GT asks: what overflow? */
+
+ if (maxpix / zoomfactor > scaledwd)
+ NewWindowWidth ((int) (scaledwd * zoomfactor));
+ else
+ NewWindowWidth (maxpix);
+
+ if (maxpix / zoomfactor > scaledht)
+ NewWindowHeight ((int) (scaledht * zoomfactor));
+ else
+ NewWindowHeight (maxpix);
+}
+/* ZOTL */
+
+/*--------------------------------------------------------------------*/
+
+static void
+ZoomWindow ()
+{
+ /* Zoom In, or Zoom Out. */
+ /* For ZI, ZO, zoom relative to top left of window. */
+ /* For ZCI, ZCO, zoom relative to centre of window. */
+
+ /* Just read a 'Z'. */
+ /* Parse the rest of a ZoomInOut command and do it.
+ commpos is pointing to next position in commandstr
+ (and should be I or O).
+ */
+
+ String zs; /* Zoom command string */
+ char zch2 = '\0', zch3 = '\0'; /* Zoom command characters 2 and 3 */
+ double zoomf; /* Zoom Factor */
+ boolean zin = true; /* flag for Zoom direction; default = Zoom in */
+ boolean zc = false; /* flag for Zoom location; default = top left */
+ boolean zok = true; /* flag for valid Zoom; default = valid */
+
+ zs[0] = 'Z'; /* Zoom commands begin with 'Z' */
+ zs[1] = '\0'; /* properly terminate zs */
+
+ /* read second command character, which should be 'I' or 'O'. */
+ if (commpos < commlen)
+ {
+ zch2 = TOUPPER (commstring[commpos]);
+ commpos++;
+ zs[1] = zch2;
+ zs[2] = '\0';
+ }
+ switch (zch2)
+ {
+ case 'I':
+ zc = false;
+ zin = true;
+ break;
+ case 'O':
+ zc = false;
+ zin = false;
+ break;
+ case 'C':
+ if (commpos < commlen)
+ {
+ zch3 = TOUPPER (commstring[commpos]);
+ commpos++;
+ zs[2] = zch3;
+ zs[3] = '\0';
+ }
+ switch (zch3)
+ {
+ case 'I':
+ zc = true;
+ zin = true;
+ break;
+ case 'O':
+ zc = true;
+ zin = false;
+ break;
+ default:
+ zok = false;
+ break;
+ }
+ break;
+ default:
+ zok = false;
+ break;
+ }
+
+ if (!zok)
+ { /* invalid Z* command */
+ String got;
+ ClearMessageLine ();
+ sprintf (got, "Read `%s', ", zs);
+ MesgString (got);
+ MesgString ("ZI, ZO, ZCI or ZCO expected!");
+ BadCommandMessage ();
+ }
+ else
+ { /* valid Zoom command */
+ int pos = 0;
+ boolean realfound = false;
+
+ /* skip any spaces after Zoom command */
+ while (commpos < commlen && commstring[commpos] == ' ')
+ commpos++;
+
+ /* scan rest of command line for a number */
+ /* this is unambiguous, b/c "zoom, goto new page" is silly on a line */
+ /* fortunately, commstring is well terminated, with a NUL char */
+
+/* GT - this is the line I once spoilt: I wasn't advancing by characters! */
+/* GT - use the real number reading code from GetDimension? */
+/* static boolean GetReal (char * str_in, int slen, int * pos, double *r) */
+
+/* if (sscanf (commstring+commpos, "%lf", &zoomf) == 1) */
+
+ pos = 0; /* pos == new commpos - old commpos */
+ realfound = GetReal (commstring + commpos, commlen - commpos, &pos, &zoomf);
+ commpos += pos;
+
+ /* Set Zoom Factor, if any. */
+ if (realfound)
+ {
+ if (zoomf > 1.0)
+ /* change Zoom Factor */
+ zoomfactor = zoomf;
+ else
+ {
+ /* Zooms of unity or less are rejected */
+ /* this covers zero, and avoids ZI/ZO confusion for user */
+ String msgstring;
+
+ /* !! GT - dangerous, as msgstring may overflow - unlikely, though */
+ sprintf (msgstring,
+ "zoom factor must > 1, so keeping old factor of %.2f\n",
+ zoomfactor);
+
+ ClearMessageLine ();
+ MesgString (msgstring);
+
+ BadCommandMessage ();
+ }
+ /* gt - signal to update status line b/c of new Zoom Factor */
+ paintDVIStatus = true;
+ }
+
+ /* Zoom! */
+ if (zc)
+ { /* Zoom wrt Centre */
+ if (zin)
+ {
+ /* ZCI = Zoom In to Centre. Algorithm: */
+ /* Down and Right to centre of window, */
+ /* Zoom in to top left of new window, */
+ /* Up and Left to top left of that window. */
+
+ NewLocation (windowleft + scaledwd / 2, windowtop + scaledht / 2);
+ ZITL ();
+ NewLocation (windowleft - scaledwd / 2, windowtop - scaledht / 2);
+ }
+ else
+ {
+ /* ZCO = Zoom Out from Centre. Algorithm: */
+ /* Down and Right to centre of window, */
+ /* Zoom out from top left of new window, */
+ /* Up and Left to top left of that window. */
+ /* DEFECT: can be altered by Zoom Out restrictions. */
+
+ NewLocation (windowleft + scaledwd / 2, windowtop + scaledht / 2);
+ ZOTL ();
+ NewLocation (windowleft - scaledwd / 2, windowtop - scaledht / 2);
+ }
+ }
+ else
+ { /* Zoom wrt Top Left */
+ /* DEFECT: Zoom Out is restricted; see ZOTL and NewLocation code. */
+ if (zin)
+ ZITL (); /* ZI = Zoom In to Top Left */
+ else
+ ZOTL (); /* ZO = Zoom out from Top Left */
+ }
+ }
+}
+/* ZoomWindow */
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+NextPageFound (boolean ascending)
+{
+ /* User has selected next page in DVI file; what they get will depend on
+ the current DVI page and whether we are ascending or not.
+ Return TRUE iff we can move to next page.
+ */
+
+ boolean found = false;
+
+ if (currDVIpage == 1 && !ascending)
+ {
+ ClearMessageLine ();
+ MesgString ("You are looking at first DVI page!");
+ BadCommandMessage ();
+ found = false;
+ }
+ else if (currDVIpage == totalpages && ascending)
+ {
+ ClearMessageLine ();
+ MesgString ("You are looking at last DVI page!");
+ BadCommandMessage ();
+ found = false;
+ }
+ else
+ {
+ MoveToNextPage (ascending); /* position to next DVI page */
+ found = true;
+ }
+ return found;
+}
+/* NextPageFound */
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+DVIPageFound (int n)
+{
+ /* User has selected a particular DVI page number.
+ Move to page n and return TRUE iff n is in 1..totalpages.
+ */
+
+ boolean found = false;
+
+ if (n < 1 || n > totalpages)
+ {
+ ClearMessageLine ();
+ if (totalpages > 1)
+ {
+ MesgString ("You can only request DVI pages 1 to ");
+ MesgInt (totalpages);
+ MesgChar ('!');
+ }
+ else
+ {
+ MesgString ("You can only request DVI page 1!");
+ }
+ BadCommandMessage ();
+ found = false;
+ }
+ else
+ {
+ MoveToDVIPage (n); /* position to given DVI page */
+ found = true;
+ }
+ return found;
+}
+/* DVIPageFound */
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+ParseTeXpage (TeXpageinfo * newTeXpage)
+{
+ /* Return TRUE iff TeX page specification in commstring is valid. If so then
+ newTeXpage will contain the appropriate information for MoveToTeXPage.
+ The syntax of a TeX page specification is [n{.n}] where n is any integer as
+ defined by GetInteger. Up to 10 integers may be given and are separated by
+ periods, even if absent. Trailing periods may be omitted. Spaces before
+ and after integers and periods are skipped. The 10 positions correspond to
+ the \count0, \count1, ... ,\count9 values that TeX stores with every page.
+ commpos is initially pointing at [.
+ */
+
+ newTeXpage->lastvalue = 0;
+ while (true)
+ {
+ commpos++;
+
+ newTeXpage->present[(int) newTeXpage->lastvalue] =
+ GetInteger (commstring, commlen, &commpos,
+ &newTeXpage->value[(int) newTeXpage->lastvalue]);
+
+ /* commpos now at commlen, space, period, non-digit or ']' */
+
+ while (commpos < commlen && commstring[commpos] == ' ')
+ {
+ commpos++; /* skip any spaces */
+ }
+ if (commpos == commlen)
+ { /* check this first! */
+ ClearMessageLine ();
+ MesgString ("] expected!");
+ BadCommandMessage (); /* commpos at commlen */
+ return false;
+ }
+ if (commstring[commpos] == ']')
+ { /* end of TeX page spec */
+ commpos++;
+ break; /* escape from enclosing "infinite" while loop */
+ }
+ if (newTeXpage->lastvalue >= 9)
+ {
+ ClearMessageLine ();
+ MesgString ("] expected after 10 integers!");
+ commpos++;
+ BadCommandMessage ();
+ return false;
+ }
+ newTeXpage->lastvalue++;
+ if (commstring[commpos] == '.')
+ continue;
+ ClearMessageLine ();
+ MesgString ("Period, integer or ] expected!");
+ commpos++;
+ BadCommandMessage ();
+ return false;
+ } /* while */
+
+ while (newTeXpage->lastvalue > 0
+ && !newTeXpage->present[(int) newTeXpage->lastvalue])
+ {
+ newTeXpage->lastvalue--;
+ }
+ return true;
+}
+/* ParseTeXpage */
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+TeXPageFound ()
+{
+ /* Return TRUE iff TeX page specification is valid and exists.
+ If so then position to lowest matching page.
+ */
+
+ boolean found = false;
+ TeXpageinfo newTeXpage;
+
+ if (ParseTeXpage (&newTeXpage))
+ { /* invalid TeX page specification */
+ if (MoveToTeXPage (&newTeXpage))
+ found = true; /* we found lowest matching page */
+ else
+ {
+ ClearMessageLine ();
+ MesgString ("No TeX page matches your request!");
+ BadCommandMessage ();
+ found = false;
+ }
+ }
+ else
+ found = false;
+ return found;
+}
+/* TeXPageFound */
+
+/*--------------------------------------------------------------------*/
+
+static int
+Min (int a, int b)
+{
+ /* Return the minimum value of a and b. */
+
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+/* Min */
+
+/*--------------------------------------------------------------------*/
+
+static int
+Max (int a, int b)
+{
+ /* Return the maximum value of a and b. */
+
+ if (a > b)
+ return a;
+ else
+ return b;
+}
+/* Max */
+
+/*--------------------------------------------------------------------*/
+
+static void
+ProcessPage ()
+{
+ /* We are ready to interpret the current DVI page and fill in the various data
+ structures imported from DVIReader. This routine will also:
+ set the window size and location to useful values (if autoviewing),
+ update pageoffpaper (after checking to see if it was TRUE for the previous
+ page processed as part of a multiple command string),
+ set screenjustcleared, paintwindow and paintWindowStatus to TRUE,
+ set paintDVIStatus to FALSE.
+ */
+
+ int halfht, halfwd;
+
+ /* We check pageoffpaper here so user can type "NNNNNNNNNNNNN..." and
+ note ALL the pages that are off the paper, not just the last one
+ processed.
+ */
+ if (pageoffpaper)
+ {
+ ClearMessageLine ();
+ MesgString ("Page off paper!");
+ WaitForReturn ();
+ /* the previous page */
+ }
+ ClearScreen ();
+ screenjustcleared = true;
+ UpdateDVIStatusLine ();
+ /* a MoveTo... routine has updated currDVI/TeXpage */
+ paintDVIStatus = false;
+ InterpretPage (); /* fill in DVIReader's page data structures */
+ SortFonts (&unusedfont);
+ /* sort fonts in order of least chars and return
+ pointer to first unused font */
+ ClearMessageLine (); /* clear any message */
+ if (pageempty)
+ {
+ minhp = 0;
+ maxhp = 0;
+ minvp = 0;
+ maxvp = 0; /* for window status */
+ }
+ if (autoviewing)
+ { /* view as much of paper as possible, but without too much distortion */
+ if ((paperwd < paperht && windowwd >= windowht)
+ || (paperwd == paperht && windowwd > windowht))
+ {
+ halfht = paperht / 2;
+ if (paperht & 1) /* ensure bottom visible */
+ halfht++;
+ NewWindowHeight (halfht); /* try top half of paper */
+ NewWindowWidth (paperwd);
+ NewLocation (paperleft, papertop); /* top left corner of paper */
+ if (!pageempty && outsidepage) /* try moving down */
+ NewLocation (paperleft, papertop + halfht);
+ }
+ else if ((paperwd > paperht && windowwd <= windowht)
+ || (paperwd == paperht && windowwd < windowht))
+ {
+ halfwd = paperwd / 2;
+ if (paperwd & 1) /* ensure right visible */
+ halfwd++;
+ NewWindowHeight (paperht);
+ NewWindowWidth (halfwd); /* try left half of paper */
+ NewLocation (paperleft, papertop); /* top left corner of paper */
+ if (!pageempty && outsidepage) /* try moving right */
+ NewLocation (paperleft + halfwd, papertop);
+ }
+ else
+ {
+ /* paper shape matches unscaled window shape */
+ NewWindowHeight (paperht); /* try all of paper */
+ NewWindowWidth (paperwd);
+ NewLocation (paperleft, papertop); /* top left corner of paper */
+ }
+ }
+ else
+ {
+ /* not autoviewing, so use current window location and size */
+ NewWindowHeight (scaledht);
+ NewWindowWidth (scaledwd);
+ NewLocation (windowleft, windowtop);
+ }
+
+ /* check if part/all of page is off paper;
+ if so, and autoviewing is enabled, then we set window size and location
+ so user can just see ALL of paper AND ALL of page.
+ */
+ pageoffpaper = (!pageempty && ((minhp < paperleft || minvp < papertop)
+ || (maxhp > paperright || maxvp > paperbottom)));
+ if (pageoffpaper && autoviewing)
+ {
+ NewWindowHeight (Max (maxvp, paperbottom) - Min (minvp, papertop) + 1);
+ NewWindowWidth (Max (maxhp, paperright) - Min (minhp, paperleft) + 1);
+ NewLocation (Min (minhp, paperleft), Min (minvp, papertop));
+ }
+ paintWindowStatus = true;
+ paintwindow = true;
+}
+/* ProcessPage */
+
+/*--------------------------------------------------------------------*/
+
+static void
+ChangeUnits ()
+{
+ /* Parse a C command.
+ commpos is pointing to next position in commstring.
+ Hope that is the start of IN, CM, MM, BP, PC, PT, SP, or PX.
+ */
+
+ char nextch1, nextch2;
+ String cstr;
+
+ /* skip any spaces between 'C' command and following unit */
+
+ while (commpos < commlen && commstring[commpos] == ' ')
+ commpos++;
+
+ /* read next two characters */
+ /* these should comprise a known unit of distance */
+
+ if (commpos < commlen)
+ {
+ nextch1 = TOUPPER (commstring[commpos]);
+ commpos++;
+ }
+ else
+ nextch1 = ' ';
+
+ if (commpos < commlen)
+ {
+ nextch2 = TOUPPER (commstring[commpos]);
+ commpos++;
+ }
+ else
+ nextch2 = ' ';
+
+ sprintf (cstr, "%c%c", nextch1, nextch2);
+
+ if (!strcmp (cstr, "IN"))
+ currentunits = ic;
+ else if (!strcmp (cstr, "CM"))
+ currentunits = cm;
+ else if (!strcmp (cstr, "MM"))
+ currentunits = mm;
+ else if (!strcmp (cstr, "BP"))
+ currentunits = bp;
+ else if (!strcmp (cstr, "PC"))
+ currentunits = pc;
+ else if (!strcmp (cstr, "PT"))
+ currentunits = pt;
+ else if (!strcmp (cstr, "SP"))
+ currentunits = sp;
+ else if (!strcmp (cstr, "PX"))
+ currentunits = px;
+ else
+ {
+ ClearMessageLine ();
+ MesgString ("Unknown units: `");
+ MesgString (cstr);
+ MesgString ("'. ");
+ switch (nextch1)
+ {
+ case 'I':
+ MesgString ("IN");
+ break;
+
+ case 'C':
+ MesgString ("CM");
+ break;
+
+ case 'M':
+ MesgString ("MM");
+ break;
+
+ case 'B':
+ MesgString ("BP");
+ break;
+
+ case 'P':
+ MesgString ("PC, PT or PX");
+ break;
+
+ case 'S':
+ MesgString ("SP");
+ break;
+
+ default:
+ MesgString ("IN, CM, MM, BP, PC, PT, SP or PX");
+ break;
+ } /* command */
+
+ MesgString (" expected.");
+ BadCommandMessage ();
+
+ } /* strcmp (cstr, UNITNAME) */
+}
+/* ChangeUnits */
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+UserHitsReturn (int *linecount)
+{
+ /* Do a MesgLine and return TRUE iff linecount = bottoml-2 AND user hits CR.
+ If linecount < bottoml-2 then return FALSE; if not, and user hits
+ something other than CR, then prepare a new screen before returning FALSE.
+ */
+
+ char ch;
+
+ MesgLine ();
+ /* test for approaching end of screen */
+ if (*linecount == bottoml - 2)
+ {
+ /* prompt for next screen */
+ MoveToTextLine (bottoml);
+ MesgString ("Hit RETURN key to resume page display,");
+ MesgString (" or any other key for more: ");
+ MesgFlush ();
+
+ /* read first character typed by user in response to prompt */
+ ReadChar (&ch);
+ if (ch == CR)
+ {
+ return true;
+ }
+ ClearScreen ();
+ screenjustcleared = true;
+ MoveToTextLine (1);
+ *linecount = 1;
+ }
+ else
+ {
+ (*linecount)++;
+ }
+ return false;
+}
+/* UserHitsReturn */
+
+/*--------------------------------------------------------------------*/
+
+static void
+WriteUnits ()
+{
+ switch (currentunits)
+ {
+ case ic:
+ MesgString ("in");
+ break;
+ case cm:
+ MesgString ("cm");
+ break;
+ case mm:
+ MesgString ("mm");
+ break;
+ case bp:
+ MesgString ("bp");
+ break;
+ case pc:
+ MesgString ("pc");
+ break;
+ case pt:
+ MesgString ("pt");
+ break;
+ case sp:
+ MesgString ("sp");
+ break;
+ case px:
+ MesgString ("px");
+ break;
+ } /* currentunits */
+}
+/* WriteUnits */
+
+/*--------------------------------------------------------------------*/
+
+static int
+WritePtSize (int scaledsize)
+{
+ /* Show given font size (in DVI units), in (possibly magnified) pts.
+ Return length of displayed message.
+ */
+
+ double realdim;
+ int fracpart;
+ double precision = 0.1;
+ int len = 0;
+
+ realdim = scaledsize / 65536.0 * (mag / 1000.0);
+ /* show realdim to the precision given above */
+ if (fabs (realdim) < 0.5 * precision)
+ {
+ MesgChar ('0');
+ ++len;
+ }
+ else
+ {
+ if (realdim < 0.0)
+ {
+ MesgChar ('-');
+ ++len;
+ realdim = fabs (realdim);
+ }
+ realdim += 0.5 * precision; /* round up to specified precision */
+ len += MesgInt ((int) realdim); /* whole part */
+ fracpart = (int) ((realdim - (int) realdim) / precision);
+ if (fracpart > 0)
+ {
+ MesgChar ('.');
+ ++len;
+ len += MesgInt (fracpart);
+ }
+ }
+ MesgString ("pt");
+ len += 2;
+ return (len);
+}
+/* WritePtSize */
+
+/*--------------------------------------------------------------------*/
+
+static void
+ShowStatistics ()
+{
+ /* Show option values and font/character/rule/special statistics.
+ UserHitsReturn controls pagination and takes the place of MesgLine.
+ */
+
+ specialinfo *temp;
+ int linecount, fontcount;
+ char ch;
+ static char LeftStr[] = "";
+ static char RightStr[] = "";
+ double precision = 1.0e-3; /* precision of quantities */
+
+ ClearScreen ();
+ screenjustcleared = true;
+ MoveToTextLine (1);
+ linecount = 1;
+
+ MesgString ("DVI file = ");
+ MesgString (LeftStr);
+ MesgString (DVIname);
+ MesgString (RightStr);
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("VDU = ");
+ MesgString (LeftStr);
+ MesgString (vdu);
+ MesgString (RightStr);
+ if (UserHitsReturn (&linecount))
+ return;
+
+ { /* beginblock */
+ String realstring;
+
+ MesgString ("X Resolution (dpi) = ");
+ /* xres is unlikely to overflow realstring */
+ sprintf (realstring, "%f", xres);
+ MesgString (realstring);
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("Y Resolution (dpi) = ");
+ /* yres is unlikely to overflow realstring */
+ sprintf (realstring, "%f", yres);
+ MesgString (realstring);
+ if (UserHitsReturn (&linecount))
+ return;
+
+ } /* endblock */
+
+ MesgString ("Magnification = ");
+ MesgInt (mag);
+ if (mag == DVImag)
+ {
+ MesgString (" (DVI mag)");
+ }
+ else
+ {
+ MesgString (" (DVI mag of ");
+ MesgInt (DVImag);
+ MesgString (" was overridden)");
+ }
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("Dummy PK font = ");
+ MesgString (LeftStr);
+ MesgString (dummy_pk);
+ MesgString (RightStr);
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("Dummy TFM metric = ");
+ MesgString (LeftStr);
+ MesgString (dummy_tfm);
+ MesgString (RightStr);
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("Horizontal offset = ");
+ WriteXDim (precision, hoffset);
+ WriteUnits ();
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("Vertical offset = ");
+ WriteYDim (precision, voffset);
+ WriteUnits ();
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("Paper wd by ht = ");
+ WriteXDim (precision, paperwd);
+ WriteUnits ();
+ MesgString (" by ");
+ WriteYDim (precision, paperht);
+ WriteUnits ();
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("Total fonts on ALL pages = ");
+ MesgInt (totalfonts);
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("Fonts, at pt size: (if on current page, give (total chars))");
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString
+ ("H: Honest, S: Substitute; K: PK, T: TFM, D: DVI.");
+ if (UserHitsReturn (&linecount))
+ return;
+
+ fontcount = 0;
+ for (thisfontinfo = fontlist;
+ thisfontinfo != (fontinfo *) NULL;
+ thisfontinfo = thisfontinfo->nextfont)
+ {
+ String msgstr; /* output string for messages */
+ int len; /* length of a displayed message */
+ int maxptroom = 7; /* room for point size message */
+ int i;
+
+ if (thisfontinfo->fontspeclen == 0)
+ { /* need to build fontspec */
+ BuildFontSpec (thisfontinfo);
+ /* fontexists may have become TRUE */
+ }
+ /* most font names have at most 8 characters, for ms-dos! */
+ sprintf (msgstr, "%-8s", thisfontinfo->fontname);
+ MesgString (msgstr);
+
+ MesgString (" ");
+ len = WritePtSize (thisfontinfo->scaledsize);
+ for (i = len; i < maxptroom; i++)
+ MesgChar (' ');
+
+ MesgString ("->");
+
+ if (thisfontinfo->fontexists)
+ {
+ if (thisfontinfo->honest)
+ MesgChar ('H');
+ else /* substitute */
+ MesgChar ('S');
+
+ if (thisfontinfo->pkfont)
+ MesgChar ('K');
+ else /* non-PostScript TFM */
+ MesgChar ('T');
+
+ MesgString (" ");
+ i = thisfontinfo->fontspeclen - 50; /* try to show last 70 chars */
+ if (i < 0)
+ i = 0;
+ MesgString (thisfontinfo->fontspec + i);
+ }
+ else
+ {
+ MesgChar ('S');
+ MesgChar ('D');
+
+ MesgString (" ");
+ MesgString ("Terse display");
+ }
+
+ if (thisfontinfo->fontused)
+ {
+ fontcount++;
+ MesgString (" (");
+ MesgInt (thisfontinfo->totalchars);
+ MesgString (")");
+ }
+ if (UserHitsReturn (&linecount))
+ return;
+ }
+ /* end (for) loop */
+
+ if (currDVIpage == 0)
+ MesgString ("You haven't selected a page yet.");
+ else
+ {
+ MesgString ("Total fonts on current page = ");
+ MesgInt (fontcount);
+ }
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("Total rules on current page = ");
+ MesgInt (totalrules);
+
+ if (speciallist != (specialinfo *) NULL)
+ {
+ if (UserHitsReturn (&linecount))
+ return;
+
+ MesgString ("\\special commands on current page: ");
+ if (UserHitsReturn (&linecount))
+ return;
+
+ temp = speciallist;
+ while (temp != (specialinfo *) NULL)
+ {
+ MesgString ("At (");
+ WriteXDim (precision, temp->hp);
+ MesgChar (',');
+ WriteYDim (precision, temp->vp);
+ MesgString ("): ");
+ MesgString (temp->special);
+ if (UserHitsReturn (&linecount))
+ return;
+
+ temp = temp->nextspecial;
+ } /* while */
+ } /* if */
+ MesgLine ();
+ MesgLine ();
+ MoveToTextLine (bottoml);
+ MesgString ("Hit RETURN key to resume page display: ");
+ MesgFlush ();
+
+ do
+ {
+ ReadChar (&ch);
+ }
+ while (ch != CR);
+
+}
+/* ShowStatistics */
+
+/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------*/
+
+/*--------------------------------------------------------------------*/
+
+#define edgepixel '.'
+ /* black pixel for outlines on non-graphic VDUs;
+ note that VDU TeXtoASCII['.'] = '.' */
+
+static void
+DisplayPaperEdges ()
+{
+ /* Display visible outlines of the imaginary sheet of paper.
+ Thickness of outlines = 1 screen pixel,
+ no matter what the h and v scaling.
+ */
+
+ int top, bot, left, right; /* visible edges of paper in paper pixels */
+ int scaledtop, scaledleft; /* scaled visible edges in screen pixels */
+ int scaledbot, scaledright, scaledheight;
+ /* scaled width and height */
+ int scaledwidth;
+
+ /* first check if any part of paper is visible */
+
+ if (papertop > windowbottom)
+ return;
+
+ if (paperbottom < windowtop)
+ return;
+
+ if (paperleft > windowright)
+ return;
+
+ if (paperright < windowleft)
+ return;
+
+ /* part or all of paper is visible, so return visible region */
+ top = Max (papertop, windowtop);
+ bot = Min (paperbottom, windowbottom);
+ left = Max (paperleft, windowleft);
+ right = Min (paperright, windowright);
+ scaledtop = ScaleVpos (top - windowtop) + windowv;
+ scaledleft = ScaleHpos (left - windowleft) + windowh;
+ if (vscalefactor > 1.0)
+ scaledbot = ScaleVpos (bot - windowtop + 1) + windowv - 1;
+ else
+ scaledbot = ScaleVpos (bot - windowtop) + windowv;
+ if (hscalefactor > 1.0)
+ scaledright = ScaleHpos (right - windowleft + 1) + windowh - 1;
+ else
+ scaledright = ScaleHpos (right - windowleft) + windowh;
+ scaledheight = scaledbot - scaledtop + 1;
+ scaledwidth = scaledright - scaledleft + 1;
+ /* only show visible edges if they are also paper outlines */
+ if (left == paperleft)
+ ShowRectangle (scaledleft, scaledtop, 1, scaledheight, edgepixel);
+ if (bot == paperbottom)
+ ShowRectangle (scaledleft, scaledbot, scaledwidth, 1, edgepixel);
+ if (top == papertop)
+ ShowRectangle (scaledleft, scaledtop, scaledwidth, 1, edgepixel);
+ if (right == paperright)
+ ShowRectangle (scaledright, scaledtop, 1, scaledheight, edgepixel);
+}
+/* DisplayPaperEdges */
+
+#undef edgepixel
+
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+RectangleVisible (int intop, int inbot, int inleft, int inright,
+ int *outtop, int *outbot, int *outleft, int *outright)
+{
+ /* Return TRUE iff part or all of given rectangle would be visible
+ in the current window. Iff so, then we also return the visible
+ region; the input and possible output rectangles are defined by their
+ top, bottom, left and right edges in paper pixel coordinates.
+ */
+
+ if (allpagevisible)
+ { /* all of rectangle must be visible */
+ *outtop = intop;
+ *outbot = inbot;
+ *outleft = inleft;
+ *outright = inright;
+ return true;
+ }
+ else if (intop > windowbottom)
+ return false;
+ else if (inbot < windowtop)
+ return false;
+ else if (inleft > windowright)
+ return false;
+ else if (inright < windowleft)
+ return false;
+ else
+ {
+ /* part or all of rectangle is visible, so return visible region */
+ *outtop = Max (intop, windowtop);
+ *outbot = Min (inbot, windowbottom);
+ *outleft = Max (inleft, windowleft);
+ *outright = Min (inright, windowright);
+ return true;
+ }
+}
+/* RectangleVisible */
+
+/*--------------------------------------------------------------------*/
+
+#define RULEPIXEL '*'
+ /* black pixel for rules on non-graphic VDUs;
+ note that VDU sets TeXtoASCII['*'] := '*' */
+
+
+static void
+DisplayRules ()
+{
+ /* Display all pixels in rules, regardless of current displaymode.
+ Rules will be displayed in the same order as in the DVI page (essentially
+ top-down and left-right) because of the way DVIReader builds a rulelist.
+ */
+
+ int top, bottom, left, right; /* visible edges of rule */
+ int scaledtop, scaledleft; /* scaled visible edges */
+ int scaledbot, scaledright, scaledwidth, scaledheight;
+ /* scaled width and height */
+ int thisrule;
+ char keyhit; /* returned by BusyRead if TRUE */
+ _REC_ruletable *ruletab = (_REC_ruletable *) NULL;
+
+ thisruleinfo = rulelist;
+ while (thisruleinfo != (ruleinfo *) NULL)
+ {
+ thisrule = 0;
+ while (thisrule < thisruleinfo->rulecount)
+ {
+ ruletab = &thisruleinfo->ruletable[thisrule];
+ /* check if any part of rule is visible */
+ /* vp,hp is bottom left corner of rule on page */
+ if (RectangleVisible (ruletab->vp - ruletab->ht + 1,
+ ruletab->vp, ruletab->hp,
+ ruletab->hp + ruletab->wd - 1,
+ &top, &bottom, &left, &right))
+ { /* rule edges */
+ /* show all pixels in this rectangle */
+ scaledtop = ScaleVpos (top - windowtop) + windowv;
+ scaledleft = ScaleHpos (left - windowleft) + windowh;
+
+ if (vscalefactor > 1.0)
+ scaledbot = ScaleVpos (bottom - windowtop + 1) + windowv - 1;
+ else
+ scaledbot = ScaleVpos (bottom - windowtop) + windowv;
+
+ if (hscalefactor > 1.0)
+ scaledright = ScaleHpos (right - windowleft + 1) + windowh - 1;
+ else
+ scaledright = ScaleHpos (right - windowleft) + windowh;
+
+ /* v coord of top left cnr */
+ scaledheight = scaledbot - scaledtop + 1;
+
+ /* h coord of top left cnr */
+ scaledwidth = scaledright - scaledleft + 1;
+
+ ShowRectangle (scaledleft, scaledtop, scaledwidth, scaledheight,
+ RULEPIXEL);
+
+ /* check keyboard after every visible rule */
+ if (BusyRead (&keyhit))
+ {
+ char STR1[2];
+ keyhit = TOUPPER (keyhit);
+ sprintf (STR1, "%c", keyhit);
+ if (!strcmp (STR1, Terse))
+ {
+ displaymode ^= tersemode; /* toggle terse mode */
+ StartText ();
+ UpdateDVIStatusLine ();
+ StartGraphics ();
+ }
+ else
+ {
+ char STR2[2];
+ sprintf (STR2, "%c", keyhit);
+ if (!strcmp (STR2, Box))
+ {
+ displaymode ^= boxmode; /* toggle box mode */
+ StartText ();
+ UpdateDVIStatusLine ();
+ StartGraphics ();
+ }
+ else
+ {
+ char STR3[2];
+ sprintf (STR3, "%c", keyhit);
+ if (!strcmp (STR3, Full))
+ {
+ displaymode ^= fullmode; /* toggle full mode */
+ StartText ();
+ UpdateDVIStatusLine ();
+ StartGraphics ();
+ }
+ else if (keyhit == CR)
+ {
+ useraborted = true; /* checked in DisplayPage */
+ return;
+
+ } /* if */
+ } /* if */
+ } /* if */
+ } /* if */
+ } /* if */
+ /* visible rectangle */
+ thisrule++;
+ } /* while */
+ thisruleinfo = thisruleinfo->nextrule;
+ } /* while */
+}
+/* DisplayRules */
+
+
+
+
+/*--------------------------------------------------------------------*/
+/* Adapted from xdvi-20.0 by Paul Vojta */
+/* Keys for epsf specials */
+
+static char *keytab[] =
+{
+ "clip",
+ "llx",
+ "lly",
+ "urx",
+ "ury",
+ "rwi",
+ "rhi",
+
+ "hsize",
+ "vsize",
+ "hoffset",
+ "voffset",
+ "hscale",
+ "vscale",
+ "angle"
+};
+
+#define KEY_LLX keyval[0]
+#define KEY_LLY keyval[1]
+#define KEY_URX keyval[2]
+#define KEY_URY keyval[3]
+#define KEY_RWI keyval[4]
+#define KEY_RHI keyval[5]
+
+#define KEY_HSIZE keyval[6]
+#define KEY_VSIZE keyval[7]
+#define KEY_HOFFSET keyval[8]
+#define KEY_VOFFSET keyval[9]
+#define KEY_HSCALE keyval[10]
+#define KEY_VSCALE keyval[11]
+#define KEY_ANGLE keyval[12]
+
+#define NKEYS (sizeof(keytab)/sizeof(*keytab))
+#define N_ARGLESS_KEYS 1
+
+static int
+epsf_special (char *cp, int *wd, int *ht)
+{
+ char *filename;
+ int filenamelen = 0;
+ int flags = 0;
+ double keyval[NKEYS - N_ARGLESS_KEYS];
+
+ /* skip to the file name */
+ while (isspace (*cp))
+ ++cp;
+ if (*cp != '=')
+ return 0;
+ do
+ ++cp;
+ while (isspace (*cp));
+
+ filename = cp;
+ if (*cp == '\'' || *cp == '"')
+ {
+ do
+ ++cp;
+ while (*cp != '\0' && *cp != *filename); /* up to closing ['"] */
+ ++filename;
+ }
+ else
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+ ++cp;
+ filenamelen = cp - filename;
+ while (*cp == ' ' || *cp == '\t')
+ ++cp;
+ while (*cp != '\0')
+ {
+ char *p1 = cp;
+ int keyno;
+
+ while (*p1 != '=' && !isspace (*p1) && *p1 != '\0')
+ ++p1;
+ for (keyno = 0;; ++keyno)
+ {
+ if (keyno >= NKEYS)
+ {
+#if 0
+ Fprintf (stderr,
+ "%s: unknown keyword (%*s) in \\special will be ignored\n",
+ prog, (int) (p1 - cp), cp);
+#endif
+
+ break;
+ }
+ if (strncmp (cp, keytab[keyno], p1 - cp) == 0)
+ {
+ if (keyno >= N_ARGLESS_KEYS)
+ {
+ while (isspace (*p1))
+ ++p1;
+ if (*p1 == '=')
+ {
+ ++p1;
+ while (isspace (*p1))
+ ++p1;
+ }
+ {
+ int keyno_tmp = keyno - N_ARGLESS_KEYS;
+ keyval[keyno_tmp] = atof (p1);
+ flags |= (1 << keyno_tmp);
+ }
+ }
+ break;
+ }
+ }
+ cp = p1;
+ while (!isspace (*cp) && *cp != '\0')
+ ++cp;
+ while (isspace (*cp))
+ ++cp;
+ }
+
+ if ((flags & 0x30) == 0x30 || ((flags & 0x30) && (flags & 0xf) == 0xf))
+ {
+ /* convert from pt to sp and next to pixels */
+ *wd = XPixelRound (65536 * 0.1 * ((flags & 0x10) ? KEY_RWI
+ : KEY_RHI * (KEY_URX - KEY_LLX) / (KEY_URY - KEY_LLY)));
+ *ht = YPixelRound (65536 * 0.1 * ((flags & 0x20) ? KEY_RHI
+ : KEY_RWI * (KEY_URY - KEY_LLY) / (KEY_URX - KEY_LLX)));
+ return 1;
+ }
+ else if ((flags & 0xc0) == 0xc0)
+ {
+ *wd = XPixelRound (65536 * ((flags & 0x400) ? KEY_HSCALE : 1.0) * KEY_HSIZE);
+ *ht = YPixelRound (65536 * ((flags & 0x800) ? KEY_VSCALE : 1.0) * KEY_VSIZE);
+ return 1;
+ }
+ return 0;
+}
+
+/*--------------------------------------------------------------------*/
+static void
+DisplaySpecials ()
+{
+ /* Display dvips eps specials as boxes */
+
+ int top, bottom, left, right; /* visible edges of special */
+ int scaledtop, scaledleft; /* scaled visible edges */
+ int scaledbot, scaledright, scaledwidth, scaledheight;
+ /* scaled width and height */
+ specialinfo *thisspecial;
+ char keyhit; /* returned by BusyRead if TRUE */
+
+ thisspecial = speciallist;
+ while (thisspecial != (specialinfo *) NULL)
+ {
+ int wd, ht;
+ /* Using undeclared strncasecmp just as xdvik/hypertex.c does. */
+ if (strncasecmp (thisspecial->special, "psfile", 6) == 0 &&
+ epsf_special (thisspecial->special + 6, &wd, &ht))
+ {
+ /* check if any part of special is visible */
+ /* vp,hp is bottom left corner of special on page */
+ if (RectangleVisible (thisspecial->vp - ht + 1,
+ thisspecial->vp,
+ thisspecial->hp,
+ thisspecial->hp + wd - 1,
+ &top, &bottom, &left, &right))
+ { /* special edges */
+ /* show all pixels in this rectangle */
+ scaledtop = ScaleVpos (top - windowtop) + windowv;
+ scaledleft = ScaleHpos (left - windowleft) + windowh;
+
+ if (vscalefactor > 1.0)
+ scaledbot = ScaleVpos (bottom - windowtop + 1) + windowv - 1;
+ else
+ scaledbot = ScaleVpos (bottom - windowtop) + windowv;
+
+ if (hscalefactor > 1.0)
+ scaledright = ScaleHpos (right - windowleft + 1) + windowh - 1;
+ else
+ scaledright = ScaleHpos (right - windowleft) + windowh;
+ /* coord of top left cnr */
+ scaledheight = scaledbot - scaledtop + 1;
+ scaledwidth = scaledright - scaledleft + 1;
+
+ if (left == thisspecial->hp)
+ ShowRectangle (scaledleft, scaledtop, 1, scaledheight, RULEPIXEL);
+ if (bottom == thisspecial->vp)
+ ShowRectangle (scaledleft, scaledbot, scaledwidth, 1, RULEPIXEL);
+ if (top == thisspecial->vp - ht + 1)
+ ShowRectangle (scaledleft, scaledtop, scaledwidth, 1, RULEPIXEL);
+ if (right == thisspecial->hp + wd - 1)
+ ShowRectangle (scaledright, scaledtop, 1, scaledheight, RULEPIXEL);
+
+ /* check keyboard after every visible special */
+ if (BusyRead (&keyhit))
+ {
+ char STR1[2];
+ keyhit = TOUPPER (keyhit);
+ sprintf (STR1, "%c", keyhit);
+ if (!strcmp (STR1, Terse))
+ {
+ displaymode ^= tersemode; /* toggle terse mode */
+ StartText ();
+ UpdateDVIStatusLine ();
+ StartGraphics ();
+ }
+ else
+ {
+ char STR2[2];
+ sprintf (STR2, "%c", keyhit);
+ if (!strcmp (STR2, Box))
+ {
+ displaymode ^= boxmode; /* toggle box mode */
+ StartText ();
+ UpdateDVIStatusLine ();
+ StartGraphics ();
+ }
+ else
+ {
+ char STR3[2];
+ sprintf (STR3, "%c", keyhit);
+ if (!strcmp (STR3, Full))
+ {
+ displaymode ^= fullmode; /* toggle full mode */
+ StartText ();
+ UpdateDVIStatusLine ();
+ StartGraphics ();
+ }
+ else if (keyhit == CR)
+ {
+ useraborted = true; /* checked in DisplayPage */
+ return;
+
+ } /* if */
+ } /* if */
+ } /* if */
+ } /* if */
+ } /* if */
+ }
+ thisspecial = thisspecial->nextspecial;
+ } /* while */
+}
+/* DisplaySpecials */
+
+#undef RULEPIXEL
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+PixelVisible (int hpos, int vpos)
+{
+ /* Return TRUE iff given paper pixel would be visible in current window. */
+
+ if (allpagevisible)
+ return true;
+ else if (vpos < windowtop)
+ return false;
+ else if (vpos > windowbottom)
+ return false;
+ else if (hpos < windowleft)
+ return false;
+ else if (hpos > windowright)
+ return false;
+ else
+ return true;
+}
+/* PixelVisible */
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+TerseChar ()
+{
+ /* Display a quick and nasty representation of character,
+ only if ref pt visible.
+ Just how good the representation is,
+ depends on the capabilities of the VDU.
+ We don't bother checking
+ whether glyph is actually blank or non-existent.
+ */
+
+ _REC_chartable *chartab = &thischarinfo->chartable[thischar];
+
+ if (chartab == (_REC_chartable *) NULL)
+ return false;
+
+ if (PixelVisible (chartab->hp, chartab->vp)) /* ref pt of char is visible */
+ ShowChar (ScaleHpos (chartab->hp - windowleft) + windowh,
+ ScaleVpos (chartab->vp - windowtop) + windowv,
+ chartab->code);
+
+ return true;
+}
+/* TerseChar */
+
+/*--------------------------------------------------------------------*/
+
+static boolean
+BoxChar ()
+{
+ /* Display visible box outlines of glyph.
+ Thickness of outlines = 1 screen pixel,
+ no matter what the h and v scaling.
+ */
+
+ int vpmyo, hpmxo; /* vp-yo, hp-xo: glyph's top and left edges */
+ int top, bottom, left, right; /* visible edges of glyph */
+ int scaledtop, scaledleft; /* scaled visible edges */
+ int scaledbot, scaledright, scaledheight;
+ /* scaled width and height */
+ int scaledwidth;
+ char ch;
+
+ _REC_chartable *chartab = &thischarinfo->chartable[thischar];
+ _REC_pixeltable *pixtab = (_REC_pixeltable *) NULL;
+
+ if (chartab == (_REC_chartable *) NULL)
+ return false;
+
+ pixtab = &thisfontinfo->pixelptr[chartab->code];
+ if (pixtab == (_REC_pixeltable *) NULL)
+ return false;
+
+ if (pixtab->mapadr != 0)
+ { /* glyph present and non-blank */
+ /* check if any part of glyph is visible */
+
+ vpmyo = chartab->vp - pixtab->yo;
+ hpmxo = chartab->hp - pixtab->xo;
+
+ if (RectangleVisible (vpmyo, vpmyo + pixtab->ht - 1,
+ hpmxo, hpmxo + pixtab->wd - 1,
+ &top, &bottom, &left, &right))
+ { /* glyph edges */
+
+ scaledtop = ScaleVpos (top - windowtop) + windowv;
+ scaledleft = ScaleHpos (left - windowleft) + windowh;
+
+ if (vscalefactor > 1.0)
+ scaledbot = ScaleVpos (bottom - windowtop + 1) + windowv - 1;
+ else
+ scaledbot = ScaleVpos (bottom - windowtop) + windowv;
+
+ if (hscalefactor > 1.0)
+ scaledright = ScaleHpos (right - windowleft + 1) + windowh - 1;
+ else
+ scaledright = ScaleHpos (right - windowleft) + windowh;
+
+ scaledheight = scaledbot - scaledtop + 1;
+ scaledwidth = scaledright - scaledleft + 1;
+
+ /* Only show edges that are also glyph outlines!
+ Following method reduces the number of ShowRectangle calls needed for
+ very small boxes.
+ */
+ ch = chartab->code;
+ if ((scaledheight < 3
+ && (top == vpmyo && bottom == vpmyo + pixtab->ht - 1))
+ || (scaledwidth < 3
+ && (left == hpmxo && right == hpmxo + pixtab->wd - 1)))
+ {
+ ShowRectangle (scaledleft, scaledtop, scaledwidth, scaledheight, ch);
+ }
+ else
+ {
+ if (left == hpmxo)
+ ShowRectangle (scaledleft, scaledtop, 1, scaledheight, ch);
+ if (bottom == vpmyo + pixtab->ht - 1)
+ ShowRectangle (scaledleft, scaledbot, scaledwidth, 1, ch);
+ if (top == vpmyo)
+ ShowRectangle (scaledleft, scaledtop, scaledwidth, 1, ch);
+ if (right == hpmxo + pixtab->wd - 1)
+ ShowRectangle (scaledright, scaledtop, 1, scaledheight, ch);
+ }
+ }
+ /* visible part */
+ }
+ return true;
+}
+/* BoxChar */
+
+/*--------------------------------------------------------------------*/
+
+static void
+NotFound (char *fspec)
+{
+ StartText ();
+ ResetVDU (); /* do before message since it might erase screen! */
+ FATAL1 ("Couldn't open font %s.", fspec);
+}
+
+/* NotFound */
+
+/*--------------------------------------------------------------------*/
+
+#define MAXVISWORDS 100
+#define WORDSIZE 32
+
+/* MAXVISWORDS * WORDSIZE = 100 * 32 = 3200 bits = maximum pixel width
+ of glyph!
+ If any fonts have glyphs wider than this, then increase MAXVISWORDS.
+ */
+
+/* SYSDEP: BITSET is 32 bit word with elements 31,30,29,...,0 */
+typedef Word glyphrow[MAXVISWORDS];
+
+
+static boolean
+FullChar ()
+{
+ /* Display all pixels in a glyph using bitmap from font file.
+ The algorithm avoids overlapping rows when vscalefactor < 1.0.
+ When hscalefactor < 1.0, it is not worth the extra code to avoid
+ overlapping runs of 1 bits because the majority of character glyphs
+ have only one or two runs per row.
+ */
+
+ int vpmyo, hpmxo; /* vp-yo, hp-xo: glyph's top and left edges */
+ int top, bottom, left, right; /* visible edges of glyph */
+ int scaledv, scalednextv; /* scaled vertical positions for rows */
+ int scaledh = 0; /* scaled horizontal positions within row */
+ int scaledwidth, scaledheight; /* scaled width and height of row */
+ int thisrow, thisbit; /* in paper coordinates */
+ int wordsperrow; /* rows of bitmap are word aligned */
+ int firstbit, lastbit; /* somewhere in 0 .. wordsperrow*WORDSIZE-1 */
+ int firstword, lastword; /* somewhere in 0 .. wordsperrow-1 */
+ int endword; /* = visible words in row, - 1 */
+ int wordpos; /* 0 .. endword */
+ int bitpos; /* (WORDSIZE-1) .. 0 */
+ int i;
+
+ glyphrow row; /* holds VISIBLE bits in one row of glyph;
+ possibly > one row if vscalefactor < 1.0 */
+
+ int_or_bptr ptr; /* pointer into bitmap - actually a "struct" */
+ boolean inrun = false; /* are we in a run of black pixels in row? */
+
+ _REC_chartable *chartab = &thischarinfo->chartable[thischar];
+ _REC_pixeltable *pixtab = &thisfontinfo->pixelptr[chartab->code];
+
+ if (pixtab->mapadr != 0)
+ { /* glyph present and non-blank */
+ /* check if any part of glyph is visible */
+
+ vpmyo = chartab->vp - pixtab->yo;
+ hpmxo = chartab->hp - pixtab->xo;
+ if (RectangleVisible (vpmyo, vpmyo + pixtab->ht - 1, hpmxo,
+ hpmxo + pixtab->wd - 1, &top, &bottom, &left, &right))
+ { /* glyph edges */
+ if (pixtab->bitmap.UU.mptr == (Word *) NULL)
+ {
+ if (!fontopen)
+ { /* dimensions of bitmap */
+ if (thisfontinfo->fontexists)
+ {
+ if (!OpenFontFile (thisfontinfo->fontspec))
+ NotFound (thisfontinfo->fontspec);
+ }
+ else
+ {
+ NotFound (dummy_pk); /* !!! */
+ }
+ fontopen = true; /* only open font once */
+ }
+ /* bitmap info in font file */
+ /* &pixtab->bitmap receives the starting address of bitmap */
+ if (!GetBitmap (pixtab->ht, pixtab->wd, pixtab->mapadr, &pixtab->bitmap))
+ return false;
+ }
+ /* Words in 1 row of bitmap */
+ wordsperrow = (pixtab->wd + (WORDSIZE - 1)) / WORDSIZE;
+
+ firstbit = left - hpmxo; /* first visible bit */
+ lastbit = right - hpmxo; /* last visible bit */
+ firstword = firstbit / WORDSIZE; /* first visible word */
+ lastword = lastbit / WORDSIZE; /* last visible word */
+ endword = lastword - firstword;
+
+ /* set the visible words in row to 0 */
+ for (i = 0; i <= endword; i++)
+ row[i] = 0;
+ /* calculate scaled v coord of first visible row */
+ scaledv = ScaleVpos (top - windowtop) + windowv;
+
+ /* only consider visible rows; thisrow := top to bottom */
+ thisrow = top;
+ while (true)
+ {
+ /* move to first byte of first visible word in this row */
+ ptr.UU.int_ = pixtab->bitmap.UU.int_ +
+ ((thisrow - vpmyo) * wordsperrow + firstword) * 4;
+ /* get row of visible words from bitmap and OR with row array */
+ wordpos = 0;
+ while (true)
+ {
+ row[wordpos] |= *ptr.UU.bptr; /* set union */
+ if (wordpos == endword)
+ break; /* escape from inner "infinite" loop */
+ wordpos++;
+ ptr.UU.int_ += 4; /* next word */
+ }
+ /* calculate scaled v coord of next row */
+ scalednextv = ScaleVpos (thisrow - windowtop + 1) + windowv;
+ scaledheight = scalednextv - scaledv;
+ if (scaledheight > 0 || thisrow == bottom)
+ {
+ /* display black pixels in row, doing any h/v expansion */
+ if (scaledheight < 1) /* avoid 0 */
+ scaledheight = 1;
+ inrun = false;
+ /* bitpos ranges over (WORDSIZE-1)..0 */
+ bitpos = (WORDSIZE - 1) - (firstbit & (WORDSIZE - 1));
+ wordpos = 0;
+
+ /* only consider visible bits; thisbit := left to right */
+ thisbit = left;
+ while (true)
+ { /* bit loop */
+ if ((unsigned) bitpos < WORDSIZE
+ && ((1 << bitpos) & row[wordpos]) != 0)
+ { /* start/continue run */
+ if (!inrun)
+ { /* remember start of run */
+ inrun = true;
+ scaledh = ScaleHpos (thisbit - windowleft) + windowh;
+ }
+ }
+ else if (inrun)
+ {
+ inrun = false;
+ scaledwidth = ScaleHpos (thisbit - windowleft) + windowh - scaledh;
+ if (scaledwidth < 1) /* avoid 0 */
+ scaledwidth = 1;
+ ShowRectangle (scaledh, scaledv, scaledwidth, scaledheight,
+ chartab->code);
+ }
+ if (thisbit == right) /* EXIT bit loop */
+ break;
+ if (bitpos == 0)
+ {
+ wordpos++;
+ bitpos = (WORDSIZE - 1);
+ }
+ else
+ { /* look at next bit in word */
+ bitpos--;
+ }
+ thisbit++;
+ } /* bit loop */
+
+ if (inrun)
+ { /* show run at end of row */
+ scaledwidth = ScaleHpos (thisbit - windowleft + 1) + windowh - scaledh;
+ if (scaledwidth < 1) /* avoid 0 */
+ scaledwidth = 1;
+ ShowRectangle (scaledh, scaledv, scaledwidth, scaledheight,
+ chartab->code);
+ }
+ if (thisrow == bottom) /* EXIT row loop */
+ break;
+ /* else reset the visible words in row to 0 */
+ for (i = 0; i <= endword; i++)
+ row[i] = 0;
+ } /* if */
+ scaledv = scalednextv;
+ thisrow++;
+ } /* row loop */
+
+ } /* if */
+ /* visible part */
+ }
+ /* 0 bit has ended run */
+ return true;
+}
+/* FullChar */
+
+
+#undef WORDSIZE
+#undef MAXVISWORDS
+/*--------------------------------------------------------------------*/
+static void
+DisplayChars ()
+{
+ /* Display all characters on a font by font basis. How characters will be
+ represented depends on the current displaymode (which the user can change,
+ while the window is being updated, by typing the Terse/Box/Full commands).
+ Fonts will be displayed in order of ascending totalchars (due to SortFonts).
+ Characters in a font will be displayed in a top-down, left-right manner
+ because of the way DVIReader builds a charlist.
+ */
+
+ char keyhit; /* check for abort or mode change */
+
+ for (thisfontinfo = fontlist;
+ thisfontinfo != unusedfont;
+ thisfontinfo = thisfontinfo->nextfont)
+ {
+ /* SortFont makes sure we only consider used fonts */
+
+ fontopen = false; /* might be set in FullChar */
+
+ /* Some VDUs may be able to simulate the given font.
+ To help the VDU select appropriately sized characters, we need to
+ pass the scaledsize of the font (converted to unscaled paper pixels),
+ the overall mag, and the current h/vscalefactors.
+ */
+
+ LoadFont (thisfontinfo->fontspec,
+ XPixelRound (thisfontinfo->scaledsize),
+ mag / 1000.0,
+ hscalefactor,
+ vscalefactor);
+
+ /* display chars in chartable */
+
+ for (thischarinfo = thisfontinfo->charlist;
+ thischarinfo != (charinfo *) NULL;
+ thischarinfo = thischarinfo->nextchar)
+ {
+ for (thischar = 0; thischar < thischarinfo->charcount; thischar++)
+ {
+ if (thisfontinfo->fontexists)
+ {
+ if (displaymode & fullmode)
+ {
+ if (thisfontinfo->pkfont)
+ FullChar ();
+ else
+ BoxChar ();
+ }
+ if (displaymode & tersemode)
+ {
+ TerseChar ();
+ }
+ if (displaymode & boxmode)
+ {
+ BoxChar ();
+ }
+ }
+ else
+ { /* font is missing! */
+ if (displaymode & (fullmode | tersemode))
+ {
+ TerseChar ();
+ }
+ if (displaymode & boxmode)
+ {
+ BoxChar ();
+ }
+ }
+
+ /* check for abort or mode change */
+ if (BusyRead (&keyhit))
+ {
+ char STR1[2];
+ keyhit = TOUPPER (keyhit);
+ sprintf (STR1, "%c", keyhit);
+
+ if (!strcmp (STR1, Terse))
+ {
+ displaymode ^= tersemode; /* toggle terse mode */
+ StartText ();
+ UpdateDVIStatusLine ();
+ StartGraphics ();
+ }
+ else if (!strcmp (STR1, Box))
+ {
+ displaymode ^= boxmode; /* toggle box mode */
+ StartText ();
+ UpdateDVIStatusLine ();
+ StartGraphics ();
+ }
+ else if (!strcmp (STR1, Full))
+ {
+ displaymode ^= fullmode; /* toggle full mode */
+ StartText ();
+ UpdateDVIStatusLine ();
+ StartGraphics ();
+ }
+ else if (keyhit == CR)
+ {
+ if (fontopen)
+ CloseFontFile ();
+ /* no need to set useraborted; DisplayRules done first */
+ return;
+
+ } /* if */
+ } /* if */
+ } /* inner (for) loop */
+ } /* middle (for) loop */
+ if (fontopen)
+ CloseFontFile ();
+ } /* outer (for) loop */
+}
+/* DisplayChars */
+
+/*--------------------------------------------------------------------*/
+static void
+PaperMessage (double precision)
+{
+ /* Called by CheckPageEdges to remind user of the paper size. */
+
+ WriteUnits ();
+ MesgString ("! (Paper ");
+ WriteXDim (precision, paperwd);
+ MesgString (" x ");
+ WriteYDim (precision, paperht);
+ MesgChar (')');
+ ClearMessageLine ();
+ WaitForReturn ();
+}
+
+/* PaperMessage */
+
+/*--------------------------------------------------------------------*/
+
+static void
+CheckPageEdges ()
+{
+ /* One or more page edges do not fall within the paper edges.
+ This routine is called after the page & paper have been displayed so
+ user can see how bad the problem is.
+ */
+
+ double precision = 1.0e-2;
+
+ if (minhp < paperleft)
+ {
+ ClearMessageLine ();
+ MesgString ("Page past paper's left edge by ");
+ WriteXDim (precision, paperleft - minhp);
+ PaperMessage (precision);
+ }
+ if (maxhp > paperright)
+ {
+ ClearMessageLine ();
+ MesgString ("Page past paper's right edge by ");
+ WriteXDim (precision, maxhp - paperright);
+ PaperMessage (precision);
+ }
+ if (minvp < papertop)
+ {
+ ClearMessageLine ();
+ MesgString ("Page past paper's top edge by ");
+ WriteYDim (precision, papertop - minvp);
+ PaperMessage (precision);
+ }
+ if (maxvp > paperbottom)
+ {
+ ClearMessageLine ();
+ MesgString ("Page past paper's bottom edge by ");
+ WriteYDim (precision, maxvp - paperbottom);
+ PaperMessage (precision);
+ }
+}
+/* CheckPageEdges */
+/*--------------------------------------------------------------------*/
+static void
+DisplayPage ()
+{
+ /* Display page in window region based on window location and size,
+ and displaymode. This routine is only called if paintwindow is TRUE
+ after all commands have been processed.
+ */
+
+ if (screenjustcleared)
+ {
+ /* avoid doing it again */
+
+ if (paintDVIStatus)
+ UpdateDVIStatusLine ();
+
+ if (paintWindowStatus)
+ UpdateWindowStatusLine ();
+ }
+ else
+ {
+ ClearScreen ();
+ screenjustcleared = true;
+ UpdateDVIStatusLine ();
+ UpdateWindowStatusLine ();
+ }
+
+ StartGraphics ();
+ DisplayPaperEdges ();
+ StartText ();
+
+ if (pageempty)
+ {
+ ClearMessageLine ();
+ MesgString ("Page is empty.");
+ }
+ else if (outsidepage)
+ {
+ if (pageoffpaper)
+ CheckPageEdges ();
+
+ ClearMessageLine ();
+ MesgString ("Window is ");
+
+ if (windowtop > maxvp)
+ {
+ MesgString ("below ");
+ if (windowleft > maxhp || windowleft <= minhp - scaledwd)
+ MesgString ("and ");
+ }
+ else if (windowtop <= minvp - scaledht)
+ {
+ MesgString ("above ");
+ if (windowleft > maxhp || windowleft <= minhp - scaledwd)
+ MesgString ("and ");
+ }
+ if (windowleft > maxhp)
+ MesgString ("to the right of ");
+ else if (windowleft <= minhp - scaledwd)
+ MesgString ("to the left of ");
+
+ MesgString ("page.");
+ }
+ else
+ {
+ /* Page is not empty and part or all of it is visible. */
+ StartGraphics ();
+
+ useraborted = false;
+ DisplayRules ();
+ if (!useraborted)
+ DisplaySpecials ();
+ if (!useraborted)
+ DisplayChars ();
+
+ StartText ();
+
+ if (pageoffpaper)
+ CheckPageEdges (); /* May write messages */
+
+ if (allpagevisible)
+ {
+ ClearMessageLine ();
+ MesgString ("Entire page is visible. ");
+ PadMesg ();
+ }
+ }
+
+ MesgFlush ();
+}
+/* DisplayPage */
+/*--------------------------------------------------------------------*/
+void
+ProcessCommandLine (String commstring)
+{
+ /* Parse commstring, and call the appropriate command handler
+ for each command in commstring.
+ */
+ int n; /* returned by GetInteger call */
+
+ ClearMessageLine (); /* erase message line at this stage */
+ commlen = strlen (commstring);
+ /* ignore any trailing spaces */
+ while (commlen > 0 && commstring[commlen - 1] == ' ')
+ commlen--;
+ /* terminate commstring properly */
+ commstring[commlen] = '\0';
+
+ /* initialize flags for multiple command processing */
+ badcommand = false;
+ paintWindowStatus = false;
+ paintDVIStatus = false;
+ paintwindow = false;
+ screenjustcleared = false;
+ pageoffpaper = false;
+
+ commpos = 0;
+ while (commpos < commlen && !badcommand)
+ {
+ /* next command is defined by the next non-space character in commstring */
+ while (commstring[commpos] == ' ')
+ commpos++; /* ignore any leading spaces */
+
+ command = TOUPPER (commstring[commpos]);
+ switch (command)
+ {
+ case 'W': /* Window move */
+ commpos++;
+ WindowMove ();
+ if (!badcommand)
+ paintWindowStatus = true;
+ break;
+
+ case 'U': /* move Up */
+ case 'D': /* move Down */
+ commpos++;
+ WindowUpDown ();
+ paintWindowStatus = true;
+ break;
+
+ case 'L': /* move Left */
+ case 'R': /* move Right */
+ commpos++;
+ WindowLeftRight ();
+ paintWindowStatus = true;
+ break;
+
+ case 'H': /* Horizontal dimension */
+ commpos++;
+ SetWindowWidth ();
+ NewLocation (windowleft, windowtop);
+ paintWindowStatus = true;
+ break;
+
+ case 'V': /* Vertical dimension */
+ commpos++;
+ SetWindowHeight ();
+ NewLocation (windowleft, windowtop);
+ paintWindowStatus = true;
+ break;
+
+ case 'A': /* toggle Autoview on or off */
+ commpos++;
+ SetAutoView ();
+ if (!badcommand)
+ paintDVIStatus = true;
+ break;
+
+ case 'Z': /* Zoom in or out */
+ commpos++;
+ ZoomWindow ();
+ if (!badcommand)
+ NewLocation (windowleft, windowtop);
+ if (!badcommand)
+ paintWindowStatus = true;
+ break;
+
+ case 'N': /* Next page */
+ commpos++;
+ if (NextPageFound (true)) /* ascending */
+ ProcessPage ();
+ break;
+
+ case 'P': /* Previous page */
+ commpos++;
+ if (NextPageFound (false)) /* descending */
+ ProcessPage ();
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* go to page with this number, if number is valid */
+
+ if (GetInteger (commstring, commlen, &commpos, &n))
+ {
+ /* must be true, and commpos now after last digit */
+ if (DVIPageFound (n))
+ ProcessPage ();
+ }
+ else
+ { /* safety net */
+ ClearMessageLine ();
+ MesgString ("Expected an Integer! Type ? for help.");
+ BadCommandMessage ();
+ }
+ break;
+
+ case '[': /* go to page described by count0...count9 */
+ if (TeXPageFound ())
+ /* commpos incremented in ParseTeXpage */
+ ProcessPage ();
+ break;
+
+ case 'T': /* Terse display */
+ commpos++;
+ displaymode ^= tersemode; /* toggle terse mode */
+ paintDVIStatus = true;
+ if (currDVIpage != 0)
+ paintwindow = true;
+ break;
+
+ case 'B': /* Box display */
+ commpos++;
+ displaymode ^= boxmode; /* toggle box mode */
+ paintDVIStatus = true;
+ if (currDVIpage != 0)
+ paintwindow = true;
+ break;
+
+ case 'F': /* Full display */
+ commpos++;
+ displaymode ^= fullmode; /* toggle full mode */
+ paintDVIStatus = true;
+ if (currDVIpage != 0)
+ paintwindow = true;
+ break;
+
+ case 'C': /* Change units */
+ commpos++;
+ ChangeUnits ();
+ if (!badcommand)
+ paintWindowStatus = true;
+ break;
+
+ case '?': /* command help */
+ commpos++;
+ ShowCmdHelp ();
+ break;
+
+ case 'S': /* file-and-page Statistics */
+ commpos++;
+ ShowStatistics ();
+ ClearScreen ();
+ screenjustcleared = true;
+ paintDVIStatus = true;
+ paintWindowStatus = true;
+ if (currDVIpage != 0)
+ paintwindow = true;
+ break;
+
+ case '\014': /* ctrl-L : refresh screen */
+ commpos++;
+ DisplayPage (); /* unconditionally, and immediately on interpretation */
+ break;
+
+ case '\021': /* ctrl-Q : ignore flow-control continue */
+ case '\023': /* ctrl-S : ignore flow-control suspend */
+ /* do nothing, except advance character pointer */
+ commpos++;
+ break;
+
+ case 'Q': /* Quit */
+ return;
+
+ break;
+
+ default: /* unknown command */
+ commpos++;
+ ClearMessageLine ();
+ MesgString ("Unknown command! Type ? for help.");
+ BadCommandMessage ();
+ break;
+ } /* command */
+ } /* while */
+
+ if (paintwindow) /* only update window after processing all commands */
+ DisplayPage ();
+ else if (!vdu_clears_lines && (paintDVIStatus || paintWindowStatus))
+ DisplayPage ();
+ else
+ {
+ if (paintDVIStatus)
+ UpdateDVIStatusLine ();
+ if (paintWindowStatus)
+ UpdateWindowStatusLine ();
+ }
+}
+/* ProcessCommandLine */
+
+/*--------------------------------------------------------------------*/
+
+static void
+NextCommandLine ()
+{
+ /* Prompt user for next command line, and process response */
+
+ ClearTextLine (commandl);
+ MoveToTextLine (commandl);
+
+ MesgString (commprompt);
+ MesgFlush ();
+
+ ReadString (commstring); /* read new command line */
+
+ ProcessCommandLine (commstring);
+}
+
+/* NextCommandLine */
+
+/*--------------------------------------------------------------------*/
+static void
+Finish ()
+{
+ /* close DVI file, reset VDU and restore terminal */
+
+ CloseDVIFile ();
+
+ /*!!! ClearScreen(); */
+ screenjustcleared = true;
+ MoveToTextLine (1);
+ MesgLine ();
+ /*!!! ResetVDU(); */
+}
+
+/* Finish */
+
+/*--------------------------------------------------------------------*/
+void *
+Malloc (size_t n)
+{
+ void *MallocTemp;
+ MallocTemp = malloc (n);
+ if (MallocTemp)
+ {
+ return MallocTemp;
+ }
+ else
+ {
+ StartText ();
+ ResetVDU (); /* do before message since it might erase screen! */
+ FATAL ("Out of memory.");
+ return NULL;
+ }
+}
+/*--------------------------------------------------------------------*/
+
+int
+main (int argc, char **argv)
+{
+ char STR1[2];
+
+ kpse_set_progname (argv[0]);
+ kpse_init_prog ("DVGT", DEF_XRES, DEF_MFMODE, DEF_DUMMY);
+ kpse_set_program_enabled (kpse_pk_format, true, kpse_src_compile);
+
+ save_init_tty (); /* save initial terminal settings, early */
+ textlinewidth = 80; /* for the initial screen type */
+ if (!InitOptions (argc, argv))
+ { /* initialize DVIname and command options */
+ /* Print the precompiled information */
+ PrintText (immed_help_strings);
+ return 1;
+ }
+ InitScreenIO (); /* SYSDEP: sets cbreak on & echo off */
+
+ InitDVIReader ();
+ InitFontReader ();
+ OpenDVIFile (DVIname); /* and read DVImag etc. */
+ if (mag == 0) /* use DVImag */
+ mag = DVImag;
+ SetConversionFactors (xres, yres, mag / 1000.0); /* for DVIReader */
+ InitVDU (); /* init windowwd/ht etc. */
+ InitWinVars ();
+ StartText ();
+ ClearScreen ();
+ screenjustcleared = true;
+ UpdateDVIStatusLine ();
+ UpdateWindowStatusLine ();
+ MoveToTextLine (messagel);
+ MesgString (DVGT_VERSION);
+ MesgLine ();
+ do
+ {
+ NextCommandLine (); /* parse and execute command(s) */
+ }
+ while (strcmp ((sprintf (STR1, "%c", command), STR1), Quit));
+ Finish ();
+ return 0; /* OK */
+}
+/* main() program of DVItoVDU */
+
+/* end dvitovdu.c */