summaryrefslogtreecommitdiff
path: root/dviware/dvipage/dvipage.c
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/dvipage/dvipage.c')
-rw-r--r--dviware/dvipage/dvipage.c2421
1 files changed, 2421 insertions, 0 deletions
diff --git a/dviware/dvipage/dvipage.c b/dviware/dvipage/dvipage.c
new file mode 100644
index 0000000000..272118cf59
--- /dev/null
+++ b/dviware/dvipage/dvipage.c
@@ -0,0 +1,2421 @@
+/*
+ * dvipage: DVI Previewer Program for Suns
+ *
+ * Neil Hunt (hunt@spar.slb.com)
+ *
+ * This program is based, in part, upon the program dvisun,
+ * distributed by the UnixTeX group, extensively modified by
+ * Neil Hunt at the Schlumberger Palo Alto Research Laboratories
+ * of Schlumberger Technologies, Inc.
+ *
+ * From the dvisun manual page entry:
+ * Mark Senn wrote the early versions of [dvisun] for the
+ * BBN BitGraph. Stephan Bechtolsheim, Bob Brown, Richard
+ * Furuta, James Schaad and Robert Wells improved it. Norm
+ * Hutchinson ported the program to the Sun. Further bug fixes
+ * by Rafael Bracho at Schlumberger.
+ *
+ * Copyright (c) 1988 Schlumberger Technologies, Inc 1988.
+ * Anyone can use this software in any manner they choose,
+ * including modification and redistribution, provided they make
+ * no charge for it, and these conditions remain unchanged.
+ *
+ * This program is distributed as is, with all faults (if any), and
+ * without any warranty. No author or distributor accepts responsibility
+ * to anyone for the consequences of using it, or for whether it serves any
+ * particular purpose at all, or any other reason.
+ *
+ * $Log: dvipage.c,v $
+ * Revision 1.6 88/12/15 09:08:03 hunt
+ * Added iteration to gobble inputs in panning and magnifier.
+ *
+ * Revision 1.5 88/11/28 18:39:21 hunt
+ * Major rewrite for 4.0 and sparc architecture.
+ * Split up into multiple files for easier maintenance.
+ * Reads GF files as well as PXL files now.
+ *
+ * Revision 1.4 88/11/26 11:10:53 hunt
+ * Used varargs with *_prompt() functions for correct behaviour on a sun4.
+ *
+ * Revision 1.3 88/08/30 13:04:13 hunt
+ * Changed default cmap for darker looking letters.
+ *
+ * Revision 1.2 88/08/30 09:26:29 hunt
+ * Fixed problem pointed out by pell@rainier.UUCP
+ * (pell@rainier.se, enea!rainier!pell@uunet.UU.NET)
+ * so that opened files are closed on exec, and do not clutter up
+ * space in print spoolers which may be invoked
+ * to print the document.
+ *
+ * Revision 1.1 88/08/30 09:05:19 hunt
+ * Initial revision
+ *
+ * HISTORY
+ *
+ * 12 April 1988 - Neil Hunt
+ * Version 2.0 released for use.
+ *
+ * 11 April 1988 - Neil Hunt
+ * Applied fixes supplied by Rafael Bracho (Schlumberger Austin)
+ * for operation on Sun-4 workstations.
+ *
+ * Earlier history unavailable.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <varargs.h>
+#include <sys/param.h> /* For MAXPATHLEN */
+#include <sys/stat.h>
+#include <suntool/sunview.h>
+#include <suntool/canvas.h>
+#include <suntool/panel.h>
+#include <suntool/icon.h>
+#include "dvipage.h"
+#include "dvi.h"
+
+#define GOBBLE_PAN
+#define GOBBLE_MAGNIFY
+
+/*
+ * Forward functions.
+ * =================
+ */
+
+forward int main();
+
+forward Notify_value page_paint();
+forward Notify_value page_event();
+forward int page_menu();
+forward void page_magnify();
+forward void page_pan();
+forward bool goto_sheet();
+forward bool goto_page();
+
+forward bool init_dvi_file();
+forward void close_dvi_file();
+forward bool check_dvi_file();
+
+forward bool read_postamble();
+forward bool find_postamble_ptr();
+
+forward bool process_page();
+
+forward void set_font_num();
+forward void set_char();
+forward void set_rule();
+forward void move_down();
+forward void move_over();
+
+forward char * a_prog_name;
+forward char a_next();
+forward char * a_arg();
+forward double a_number();
+forward int a_integer();
+
+/*
+ * Internal data structures.
+ * ========================
+ */
+
+struct stack_entry /* stack entry */
+{
+ int h, v, w, x, y, z; /* what's on stack */
+};
+
+/*
+ * Globals.
+ * =======
+ */
+
+int hconv, vconv; /* converts DVI units to pixels */
+int num; /* numerator specified in preamble */
+int den; /* denominator specified in preamble */
+int mag; /* magnification specified in preamble */
+
+struct font_entry *fontptr; /* font_entry pointer */
+struct font_entry *hfontptr=NULL;/* font_entry pointer */
+
+double page_w = PAGE_WIDTH; /* page width (inches) */
+double page_h = PAGE_HEIGHT; /* page width (inches) */
+
+int h; /* current horizontal position */
+int hh; /* current horizontal position in pixels */
+int v; /* current vertical position */
+int vv; /* current vertical position in pixels */
+
+bool pre_load = TRUE; /* preload the font descriptions? */
+bool silent = FALSE; /* suppress messages */
+bool show_page_frame = FALSE; /* show page window */
+
+long postambleptr; /* Pointer to the postamble */
+
+char *font_path; /* Font path name for search */
+bool use_gf = USE_GF; /* Enable the use of GF fonts. */
+bool use_pxl = USE_PXL; /* Enable the use of PXL fonts. */
+bool use_pk = USE_PK; /* Enable the use of PK fonts. */
+
+FILE *dvifp = NULL; /* File pointer */
+
+struct stat stat_buf; /* For checking file changes. */
+time_t mtime = 0;
+
+char label[STRSIZE];
+
+char pathname[STRSIZE] = ""; /* Complete path */
+char directory[STRSIZE] = ""; /* Directory */
+char filename[STRSIZE] = ""; /* File name */
+char print_spooler[STRSIZE] = PRINT_SPOOLER; /* Print commands. */
+char print_page_spooler[STRSIZE] = PRINT_PAGE_SPOOLER;
+
+int last_sheet = 0; /* Sheet number of last page in file */
+int file_sheet = 1; /* Position of file pointer */
+int disp_sheet = 0; /* Current displayed page */
+int disp_page = 0; /* Real Page number */
+int sheet_page[MAX_SHEETS]; /* Page number of each sheet. */
+long sheet_table[MAX_SHEETS]; /* pointers to start of each page in file */
+int last_known_sheet = 0; /* Points to table at next unread sheet */
+
+int resolution = 0; /* Assumed screen resolution for rendering */
+int sampling = 0; /* Sample down sampling factor */
+bool mono; /* Monochrome screen */
+
+Frame disp_frame; /* Frame for display window. */
+Canvas disp_canvas; /* Canvas for display window. */
+
+struct mem_pixrect page_mpr; /* Page bitmap. */
+struct pixrect *page_pr;
+struct mem_pixrect sample_mpr; /* Sampled/filtered bitmap. */
+struct pixrect *sample_pr;
+
+int origin_x; /* Nominal origin of the dvi on the page */
+int origin_y; /* Nominal origin of the dvi on the page */
+
+int offset_x; /* Offsets of page in window. */
+int offset_y; /* Offsets of page in window. */
+
+int start_x; /* Starting position of page in the window */
+int start_y; /* Starting position of page in the window */
+
+int verbose; /* Flags for debugging. */
+
+int mag_size_x = DEFAULT_MAG_SIZE_X; /* Magnifier parameters. */
+int mag_size_y = DEFAULT_MAG_SIZE_Y;
+int mag_border = DEFAULT_MAG_BORDER;
+
+forward uchar cmap_red[];
+forward uchar cmap_green[];
+forward uchar cmap_blue[];
+
+short icon_image[] =
+{
+/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
+ */
+ 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x8000,0x0000,0x0000,0x0001,
+ 0x8000,0x0000,0x0000,0x0001,0x8000,0x0000,0x0000,0x0001,
+ 0x8000,0x0000,0x00C0,0x0001,0x8000,0x0000,0x0338,0x0001,
+ 0x8000,0x0000,0x0447,0x0001,0x8000,0x0000,0x1911,0xE001,
+ 0x8000,0x0000,0x2888,0x9E01,0x8000,0x0000,0xC222,0x23C1,
+ 0x8000,0x0001,0x4444,0x4479,0x8000,0x0007,0x1111,0x1117,
+ 0x8000,0x0008,0x8888,0x8889,0x8000,0x0032,0x2222,0x2223,
+ 0x8000,0x0044,0x4444,0x4445,0x8000,0x0191,0x1111,0x1111,
+ 0x8000,0x0288,0x8888,0x888B,0x8000,0x0C22,0x2222,0x2225,
+ 0x8000,0x1444,0x4444,0x4447,0x8000,0x6111,0x1111,0x1119,
+ 0x8000,0xC888,0x8888,0x889B,0x8000,0xB222,0x2222,0x2235,
+ 0x8000,0xCE44,0x4444,0x446B,0x8000,0x91D1,0x1111,0x11D5,
+ 0x8000,0x88B8,0x8888,0x88AB,0x8000,0xAC2E,0x2222,0x2355,
+ 0x8000,0xC345,0xC444,0x46AB,0x8000,0x9CD1,0x3111,0x1555,
+ 0x8000,0xB338,0x8E88,0x8AA5,0x8000,0xE0C6,0x23E2,0x3559,
+ 0x8000,0xC039,0x8474,0x56B1,0x8000,0xC006,0x611F,0x2D41,
+ 0x8000,0x9001,0x9C89,0xDEA1,0x8001,0x0C00,0x6322,0xFD41,
+ 0x8002,0x43E0,0x1CC4,0xBE81,0x8004,0x2C18,0x0331,0xFD01,
+ 0x8008,0x3606,0x00C8,0xBB01,0x8031,0xC781,0x0032,0xF601,
+ 0x8040,0x4CC1,0x0014,0xAC01,0x818C,0x9840,0xC021,0xD801,
+ 0x8602,0xB208,0xB048,0xA801,0x9861,0x6788,0x4CC2,0xD001,
+ 0xB011,0xCCD9,0xC0C4,0xA001,0xA30D,0x1817,0x60B1,0xC001,
+ 0x9883,0x3E1C,0x590E,0xC001,0x8463,0x6270,0x4101,0x8001,
+ 0x821F,0xC1D0,0xC100,0x0001,0x813F,0xB310,0xB200,0x0001,
+ 0x81FC,0x5831,0x0200,0x0001,0x87F8,0x4021,0x0400,0x0001,
+ 0x9F8C,0x3006,0xC400,0x0001,0x9E07,0x0C18,0x0800,0x0001,
+ 0x8C00,0x83E8,0x1000,0x0001,0x8000,0x6106,0x2000,0x0001,
+ 0x8000,0x18C0,0x4000,0x0001,0x8000,0x0430,0x8000,0x0001,
+ 0x8000,0x0309,0x0000,0x0001,0x8000,0x0081,0x0000,0x0001,
+ 0x8000,0x0062,0x0000,0x0001,0x8000,0x0014,0x0000,0x0001,
+ 0x8000,0x0008,0x0000,0x0001,0x8000,0x0000,0x0000,0x0001,
+ 0x8000,0x0000,0x0000,0x0001,0xFFFF,0xFFFF,0xFFFF,0xFFFF
+};
+
+DEFINE_ICON_FROM_IMAGE(icon, icon_image);
+
+short hand[] =
+{
+ 0x0C00,0x1200,0x1200,0x1380,0x1240,0x7270,0x9248,0x924E,
+ 0x9249,0x9249,0x9009,0x8001,0x4002,0x4002,0x2004,0x2004
+};
+mpr_static(hand_pr, 16, 16, 1, hand);
+Cursor hand_cursor;
+
+/*
+ * Functions.
+ * =========
+ */
+
+/*
+ * main:
+ * Interpret args, open windows, loop forever.
+ */
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int f;
+ char opt;
+ char *slash;
+ char *extension;
+ Pixwin *pw;
+ bool fake_mono;
+ char *printer;
+ double set_origin_x;
+ double set_origin_y;
+ double set_start_x;
+ double set_start_y;
+
+ /*
+ * local initialisations.
+ */
+ fake_mono = FALSE;
+ set_origin_x = 0.0;
+ set_origin_y = 0.0;
+ set_start_x = 0.0;
+ set_start_y = 0.0;
+
+ /*
+ * Customise this part for your local printer environment.
+ * ======================================================
+ */
+#ifdef SPAR_HACKS
+
+ /*
+ * Set local printer hacks.
+ */
+ printer = getenv("PRINTER");
+ if(printer && strncmp(printer, "lw", 2) == 0)
+ {
+ sprintf(print_spooler,
+ "dvips -P%s %%s >/dev/null 2>/dev/null",
+ printer);
+ sprintf(print_page_spooler,
+ "dvips -P%s -f %%d -t %%d %%s >/dev/null 2>/dev/null",
+ printer);
+ }
+ else if(printer && strncmp(printer, "im", 2) == 0)
+ {
+ sprintf(print_spooler,
+ "dviimp -P%s %%s >/dev/null 2>/dev/null",
+ printer);
+ sprintf(print_page_spooler,
+ "dviimp -P%s -S %%d -E %%d %%s >/dev/null 2>/dev/null",
+ printer);
+ }
+ else
+ {
+ fprintf(stderr, "PRINTER environment not recognised:\n");
+ fprintf(stderr, " using `%s' to print files\n",
+ print_spooler);
+ fprintf(stderr, " using `%s' to print pages\n",
+ print_page_spooler);
+ }
+
+ if(verbose & DEBUG_PRINTER)
+ {
+ fprintf(stderr, "Using `%s' to print files\n",
+ print_spooler);
+ fprintf(stderr, "Using `%s' to print pages\n",
+ print_page_spooler);
+ }
+
+#endif SPAR_HACKS
+
+ /*
+ * Find font path environment.
+ */
+ if((font_path = getenv(FONT_PATH)) == NULL)
+ font_path = FONT_AREA;
+
+ /*
+ * Get cursor.
+ */
+ hand_cursor = cursor_create(
+ CURSOR_IMAGE, &hand_pr,
+ CURSOR_XHOT, 5,
+ CURSOR_YHOT, 0,
+ CURSOR_OP, PIX_SRC ^ PIX_DST,
+ 0);
+
+ /*
+ * Create a disp_frame.
+ */
+ disp_frame = window_create(0, FRAME,
+ WIN_X, 300,
+ WIN_Y, 50,
+ WIN_WIDTH,
+ (int)(page_w * DEFAULT_COLOUR_RES /
+ DEFAULT_COLOUR_SAMPLING) + 10,
+ WIN_HEIGHT,
+ (int)(page_h * DEFAULT_COLOUR_RES /
+ DEFAULT_COLOUR_SAMPLING) + 20,
+ FRAME_ARGC_PTR_ARGV, &argc, argv,
+ FRAME_LABEL, DVIPAGE_LABEL,
+ FRAME_ICON, &icon,
+ 0);
+
+ /*
+ * Create the disp_canvas.
+ */
+ disp_canvas = window_create(disp_frame, CANVAS,
+ CANVAS_RETAINED, FALSE,
+ CANVAS_AUTO_CLEAR, FALSE,
+ CANVAS_FIXED_IMAGE, TRUE,
+ WIN_CURSOR, hand_cursor,
+ WIN_CONSUME_PICK_EVENTS,
+ WIN_NO_EVENTS,
+ LOC_DRAG,
+ WIN_MOUSE_BUTTONS,
+ LOC_WINENTER, /* Otherwise misses first event */
+ LOC_WINEXIT,
+ 0,
+ WIN_CONSUME_KBD_EVENTS,
+ WIN_NO_EVENTS,
+ WIN_ASCII_EVENTS,
+ WIN_LEFT_KEYS, /* For Expose, Hide, Close etc. */
+ KBD_USE, /* Otherwise click to type doesn't work */
+ KBD_DONE,
+ 0,
+ CANVAS_REPAINT_PROC, page_paint,
+ WIN_EVENT_PROC, page_event,
+ WIN_WIDTH, WIN_EXTEND_TO_EDGE,
+ WIN_HEIGHT, WIN_EXTEND_TO_EDGE,
+ 0);
+
+ /*
+ * Interpret args.
+ */
+ f = 0;
+ while((opt = a_next(argc, argv)) != A_END)
+ {
+ switch(opt)
+ {
+ default:
+ fprintf(stderr, "%s: illegal flag -%c\n",
+ a_prog_name, opt);
+ /* FALLTHROUGH */
+ case 'H':
+ fprintf(stderr,
+ "Usage: %s \\\n", a_prog_name);
+ fprintf(stderr,
+ " [-v mode] # Verbose mode (for debugging) \\\n");
+ fprintf(stderr,
+ " [-m] # Force monochrome mode \\\n");
+ fprintf(stderr,
+ " [-p font-file-path] # List of font directories \\\n");
+ fprintf(stderr,
+ " [-P flag] # Enable or disable the use of PXL files \\\n");
+ fprintf(stderr,
+ " [-K flag] # Enable or disable the use of PK files \\\n");
+ fprintf(stderr,
+ " [-G flag] # Enable or disable the use of GF files \\\n");
+ fprintf(stderr,
+ " [-l] # Don't preload font data \\\n");
+ fprintf(stderr,
+ " [-q] # Quiet: no warning messages \\\n");
+ fprintf(stderr,
+ " [-f] # Show rendering frame on page \\\n");
+ fprintf(stderr,
+ " [-r res] # Use `res' dpi fonts \\\n");
+ fprintf(stderr,
+ " [-s sample] # Reduce by factor of `sample' \\\n");
+ fprintf(stderr,
+ " [-x x] [-y y] # Initial pos of sheet in inches \\\n");
+ fprintf(stderr,
+ " [-X ox] [-Y oy] # Pos of (0, 0) on page in inches \\\n");
+ fprintf(stderr,
+ " [-w width] [-h height] # Total size of page in inches \\\n");
+ fprintf(stderr,
+ " [dvifile[.dvi]]\n");
+ exit(1);
+
+ case 'v':
+ verbose = a_integer(argc, argv);
+ break;
+
+ case 'm':
+ fake_mono = TRUE;
+ break;
+
+ case 'p':
+ font_path = a_arg(argc, argv);
+ break;
+
+ case 'P':
+ use_pxl = a_integer(argc, argv);
+ break;
+
+ case 'K':
+ use_pk = a_integer(argc, argv);
+ break;
+
+ case 'G':
+ use_gf = a_integer(argc, argv);
+ break;
+
+ case 'l':
+ pre_load = ! pre_load;
+ break;
+
+ case 'q':
+ silent = ! silent;
+ break;
+
+ case 'f':
+ show_page_frame = ! show_page_frame;
+ break;
+
+ case 'r':
+ resolution = a_integer(argc, argv);
+ break;
+
+ case 's':
+ sampling = a_integer(argc, argv);
+ break;
+
+ case 'x':
+ set_start_x = a_number(argc, argv);
+ break;
+
+ case 'y':
+ set_start_y = a_number(argc, argv);
+ break;
+
+ case 'X':
+ set_origin_x = a_number(argc, argv);
+ break;
+
+ case 'Y':
+ set_origin_y = a_number(argc, argv);
+ break;
+
+ case 'w':
+ page_w = a_number(argc, argv);
+ break;
+
+ case 'h':
+ page_h = a_number(argc, argv);
+ break;
+
+ case A_ARG:
+ switch(f++)
+ {
+ case 0:
+ /*
+ * Get the whole pathname.
+ */
+ strcpy(pathname, a_arg(argc, argv));
+
+ /*
+ * Get the filename and directory
+ */
+ strcpy(directory, pathname);
+ if((slash = rindex(directory, '/')) != NULL)
+ {
+ strcpy(filename, slash+1);
+ *++slash = '\0';
+ }
+ else
+ {
+ directory[0] = '\0';
+ strcpy(filename, pathname);
+ }
+
+ /*
+ * If the filename has no extension, or if it
+ * has an extension and it is not '.dvi' then
+ * cat .dvi onto the filename.
+ */
+ if((extension = rindex(pathname, '.')) == NULL ||
+ strcmp(extension, ".dvi") != 0)
+ strcat(pathname, ".dvi");
+
+ break;
+
+ default:
+ fprintf(stderr,
+ "%s: too many dvi files\n", a_prog_name);
+ exit(1);
+ }
+ break;
+ }
+ }
+
+ pw = canvas_pixwin(disp_canvas);
+
+ /*
+ * Now that we know whether we are on a colour machine or a monochrome,
+ * we can set the defaults for the resolution and sampling, unless
+ * they have already been set from the args.
+ */
+ if(fake_mono || (pw->pw_pixrect->pr_depth == 1))
+ {
+ /*
+ * Monochrome
+ */
+ mono = TRUE;
+
+ if(resolution == 0)
+ resolution = DEFAULT_MONO_RES;
+ if(sampling == 0)
+ sampling = DEFAULT_MONO_SAMPLING;
+ }
+ else
+ {
+ /*
+ * Colour
+ */
+ mono = FALSE;
+
+ if(resolution == 0)
+ resolution = DEFAULT_COLOUR_RES;
+ if(sampling == 0)
+ sampling = DEFAULT_COLOUR_SAMPLING;
+
+ /*
+ * Compute and set a colour map
+ */
+ make_cmap();
+ pw_setcmsname(pw, "dvipage-greys");
+ pw_putcolormap(pw, 0, 64, cmap_red, cmap_green, cmap_blue);
+ }
+
+ /*
+ * Now that we know the resolution and sampling, we can set
+ * the margin and origin properly.
+ */
+ if(set_origin_x != 0.0)
+ origin_x = (int)(set_origin_x * resolution);
+ else
+ origin_x = (int)(DEFAULT_ORIGIN_X * resolution);
+
+ if(set_origin_y != 0.0)
+ origin_y = (int)(set_origin_y * resolution);
+ else
+ origin_y = (int)(DEFAULT_ORIGIN_Y * resolution);
+
+ if(set_start_x != 0.0)
+ start_x = (int)(set_start_x * resolution);
+ else
+ start_x = (int)(DEFAULT_START_X * resolution);
+
+ if(set_start_y != 0.0)
+ start_y = (int)(set_start_y * resolution);
+ else
+ start_y = (int)(DEFAULT_START_Y * resolution);
+
+ /*
+ * Insert the window into the heap now, so that if a message is
+ * generated by the init_dvi_file below, it is displayed after the
+ * window, and is therefore on top of it. If we display the window
+ * after doing the initialisation of the dvi file, it would obscure
+ * any error messages which might have been generated.
+ */
+ window_set(disp_frame,
+ WIN_SHOW, TRUE,
+ 0);
+
+ /*
+ * If we don't run the notifier at this time, the window will
+ * not be painted, and the effect will be a gross area of the
+ * screen which is not painted, through which the previous windows
+ * are still visible.
+ */
+ notify_dispatch();
+
+ /*
+ * If there was a filename specified, then open it
+ * and prepare the first page.
+ */
+ if(f >= 1)
+ {
+ /*
+ * Init the file.
+ */
+ if(init_dvi_file())
+ {
+ process_page(RASTERISE);
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(disp_canvas, pw, 0);
+ }
+ }
+ else
+ getwd(directory);
+
+ /*
+ * Loop forever in the notifier.
+ */
+ notify_start();
+}
+
+/*
+ * Window Functions.
+ * ================
+ */
+
+/*
+ * page_paint:
+ * Called whenever the window is to be painted.
+ * Just maps the sampled pixrect into the screen at the appropriate
+ * offset position.
+ */
+
+Notify_value
+page_paint(canvas, pw, area)
+Canvas canvas;
+Pixwin *pw;
+Rectlist *area;
+{
+ if(sample_pr == NULL)
+ {
+ pw_rop(pw, 0, 0,
+ (int)window_get(canvas, WIN_WIDTH),
+ (int)window_get(canvas, WIN_HEIGHT),
+ PIX_CLR, NULL, 0, 0);
+
+ sprintf(label, "%s: No File", DVIPAGE_LABEL);
+ window_set(disp_frame,
+ FRAME_LABEL, label,
+ 0);
+ }
+ else
+ {
+ pw_cover(pw, 0, 0,
+ (int)window_get(canvas, WIN_WIDTH),
+ (int)window_get(canvas, WIN_HEIGHT),
+ PIX_SRC, sample_pr, -offset_x, -offset_y);
+
+ sprintf(label, "%s: File \"%s\" %s %d",
+ DVIPAGE_LABEL, filename,
+ (last_sheet && disp_sheet >= last_sheet-1)?
+ "Last page" : "Page",
+ disp_page);
+ window_set(disp_frame,
+ FRAME_LABEL, label,
+ 0);
+ }
+}
+
+/*
+ * page_event:
+ * Called whenever an input event arrives at the window.
+ * Controls panning of the page, turning to the next page,
+ * and reloading a new file.
+ */
+
+Notify_value
+page_event(canvas, event, arg)
+Window canvas;
+Event *event;
+caddr_t arg;
+{
+ Pixwin *pw;
+ int e;
+ int pp;
+ bool page_or_sheet;
+ static int num = 0;
+ static bool valid_num = FALSE;
+ bool keep_num;
+ char *extension;
+ char command[STRSIZE];
+ double x, y;
+
+ if(event_is_up(event))
+ return;
+
+ pw = canvas_pixwin(canvas);
+
+ keep_num = FALSE;
+
+ if(verbose & DEBUG_SHEET)
+ fprintf(stderr, "page_event: num = %d @ %d\n", num, valid_num);
+
+ /*
+ * If there is a call for a menu, then translate that into
+ * a command character.
+ */
+ if((e = event_id(event)) == MS_RIGHT)
+ if((e = page_menu(canvas, pw, event)) == 0)
+ return;
+
+ switch(e)
+ {
+ case MS_LEFT:
+ page_magnify(canvas, pw, event);
+ break;
+
+ case MS_MIDDLE:
+ page_pan(canvas, pw, event);
+ break;
+
+ default:
+ if(e >= '0' && e <= '9')
+ num = num * 10 + e - '0';
+ else if(e == DEL || e == Control('H'))
+ num = num / 10;
+ else
+ break;
+
+ keep_num = TRUE;
+ valid_num = TRUE;
+
+ break;
+
+ case '\r': /* Next page */
+ case 'n':
+ case ' ':
+ case '+':
+ if(! valid_num)
+ num = 1;
+ if(! goto_sheet(disp_sheet + num))
+ break;
+
+ process_page(RASTERISE);
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+
+ break;
+
+ case '\n': /* Previous page */
+ case 'p':
+ case '-':
+ if(! valid_num)
+ num = 1;
+ if(! goto_sheet(disp_sheet - num))
+ break;
+
+ process_page(RASTERISE);
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+
+ break;
+
+ case '_':
+ num = 1;
+ valid_num = TRUE;
+ /* FALLTHROUGH */
+
+ case 'G':
+ if(! valid_num)
+ num = LAST_PAGE;
+
+ if(! goto_sheet(num))
+ break;
+
+ process_page(RASTERISE);
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+
+ break;
+
+ case 'g':
+ if(! valid_num)
+ num = LAST_PAGE;
+
+ if(! goto_page(num))
+ break;
+
+ process_page(RASTERISE);
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+
+ break;
+
+ case 'h': /* Home page */
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+ break;
+
+ case 'l': /* Left page */
+ offset_x -= 200;
+ page_paint(canvas, pw, 0);
+ break;
+
+ case 'r': /* Right page */
+ offset_x += 200;
+ page_paint(canvas, pw, 0);
+ break;
+
+ case 'u': /* Up page */
+ offset_y -= 300;
+ page_paint(canvas, pw, 0);
+ break;
+
+ case 'd': /* Down page */
+ offset_y += 300;
+ page_paint(canvas, pw, 0);
+ break;
+
+
+ case 'm': /* Mark margins */
+ start_x = offset_x * sampling;
+ start_y = offset_y * sampling;
+ break;
+
+ case 'M': /* Set margins */
+ x = ((double)start_x / resolution);
+ y = ((double)start_y / resolution);
+ if(! doubles_prompt(1152/2, 900/2,
+ "left margin: (inches) ", &x,
+ "top margin: (inches) ", &y,
+ 0))
+ break;
+ start_x = (int)(x * resolution);
+ start_y = (int)(y * resolution);
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+ break;
+
+ case '*':
+ case '!':
+ case '@':
+ case '#':
+ case '$':
+ case '%':
+ case '^':
+ valid_num = TRUE;
+ if(e == '*')
+ num = (mono ?
+ DEFAULT_MONO_SAMPLING : DEFAULT_COLOUR_SAMPLING);
+ else if(e == '!')
+ num = 1;
+ else if(e == '@')
+ num = 2;
+ else if(e == '#')
+ num = 3;
+ else if(e == '$')
+ num = 4;
+ else if(e == '%')
+ num = 5;
+ else
+ valid_num = FALSE;
+ /* FALLTHROUGH */
+
+ case 's':
+ if(mono)
+ break;
+ if(! valid_num || (num < 1 || num > 5))
+ sampling = DEFAULT_COLOUR_SAMPLING;
+ else
+ sampling = num;
+
+ sample_page();
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+ break;
+
+ case 'S':
+ if(mono)
+ break;
+ if(! integers_prompt(1152/2, 900/2,
+ "sampling: (1, 2, 3, 4) ", &sampling,
+ 0))
+ break;
+ if(sampling < 1 || sampling > 5)
+ sampling = DEFAULT_COLOUR_SAMPLING;
+
+ sample_page();
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+ break;
+
+ case 'x':
+ if(valid_num)
+ mag_size_x = num;
+ else
+ mag_size_x = DEFAULT_MAG_SIZE_X;
+ break;
+
+ case 'y':
+ if(valid_num)
+ mag_size_y = num;
+ else
+ mag_size_y = DEFAULT_MAG_SIZE_Y;
+ break;
+
+ case 'X':
+ case 'Y':
+ if(mono)
+ break;
+ if(! integers_prompt(1152/2, 900/2,
+ "magnifier size (x) : ", &mag_size_x,
+ "magnifier size (y) : ", &mag_size_y,
+ 0))
+ break;
+ break;
+
+ case '[':
+ mag_size_x = 128;
+ mag_size_y = 64;
+ break;
+
+ case ']':
+ mag_size_x = 128;
+ mag_size_y = 128;
+ break;
+
+ case '{':
+ mag_size_x = 256;
+ mag_size_y = 128;
+ break;
+
+ case '}':
+ mag_size_x = 256;
+ mag_size_y = 256;
+ break;
+
+ case '(':
+ mag_size_x = 512;
+ mag_size_y = 256;
+ break;
+
+ case ')':
+ mag_size_x = 512;
+ mag_size_y = 512;
+ break;
+
+ case 'b':
+ if(valid_num)
+ mag_border = num;
+ else
+ mag_border = DEFAULT_MAG_BORDER;
+ break;
+
+ case 'F':
+ if(! strings_prompt(1152/2, 900/2,
+ "Directory: ", directory,
+ "Filename: ", filename,
+ 0))
+ break;
+
+ /*
+ * Build the whole pathname.
+ */
+ if(directory[0] != '\0')
+ {
+ strcpy(pathname, directory);
+ if(pathname[strlen(pathname)-1] != '/')
+ strcat(pathname, "/");
+ strcat(pathname, filename);
+ }
+ else
+ strcpy(pathname, filename);
+
+ /*
+ * If the filename has no extension, or if it
+ * has an extension and it is not '.dvi' then
+ * cat .dvi onto the filename.
+ */
+ if((extension = rindex(pathname, '.')) == NULL ||
+ strcmp(extension, ".dvi") != 0)
+ strcat(pathname, ".dvi");
+
+ sprintf(label, "%s: Opening file \"%s\"",
+ DVIPAGE_LABEL, filename);
+ window_set(disp_frame,
+ FRAME_LABEL, label,
+ 0);
+ close_dvi_file();
+ if(init_dvi_file())
+ {
+ process_page(RASTERISE);
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+ }
+ break;
+
+ case 'R': /* Reopen file */
+ sprintf(label, "%s: Reopening file \"%s\"",
+ DVIPAGE_LABEL, filename);
+ window_set(disp_frame,
+ FRAME_LABEL, label,
+ 0);
+ if(valid_num)
+ {
+ pp = num;
+ page_or_sheet = TRUE;
+ }
+ else
+ {
+ pp = disp_sheet;
+ page_or_sheet = FALSE;
+ }
+ close_dvi_file();
+ if(init_dvi_file())
+ {
+ if(page_or_sheet)
+ {
+ if(! goto_page(pp))
+ (void)goto_sheet(1);
+ }
+ else
+ {
+ if(! goto_sheet(pp))
+ (void)goto_sheet(1);
+ }
+
+ process_page(RASTERISE);
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+ }
+ break;
+
+ case 'P':
+ sprintf(command, print_page_spooler,
+ disp_page, disp_page, pathname);
+ if(verbose & DEBUG_PRINTER)
+ fprintf(stderr, "Printer command '%s'\n", command);
+ system(command);
+ break;
+
+ case Control('P'):
+ sprintf(command, print_spooler, pathname);
+ if(verbose & DEBUG_PRINTER)
+ fprintf(stderr, "Printer command '%s'\n", command);
+ system(command);
+ break;
+
+ case 'w':
+ show_page_frame = ! show_page_frame;
+
+ if(goto_sheet(disp_sheet))
+ {
+ process_page(RASTERISE);
+ offset_x = start_x / sampling;
+ offset_y = start_y / sampling;
+ page_paint(canvas, pw, 0);
+ }
+
+ break;
+
+ case 'v':
+ if(valid_num)
+ verbose = num;
+ else
+ verbose = 0;
+ break;
+
+ case 'Q':
+ exit();
+ }
+
+ if(! keep_num)
+ {
+ num = 0;
+ valid_num = FALSE;
+ }
+
+ if(verbose & DEBUG_SHEET)
+ fprintf(stderr, "end__event: num = %d @ %d\n", num, valid_num);
+}
+
+/*
+ * page_menu:
+ * Displays a menu in response to MS_RIGHT, returns a character
+ * code to calling function to effect action.
+ */
+
+int
+page_menu(canvas, pw, event)
+Canvas canvas;
+Pixwin *pw;
+Event *event;
+{
+ static Menu menu = NULL;
+ int action;
+
+ if(! menu)
+ {
+ /*
+ * Return values from this menu are passed to the
+ * event procedure, and the codes here must match
+ * codes in that function.
+ */
+ menu = menu_create(
+ MENU_ITEM,
+ MENU_STRING, "Next Page",
+ MENU_VALUE, 'n',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "Previous Page",
+ MENU_VALUE, 'p',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "First Page",
+ MENU_VALUE, '_',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "Last Page",
+ MENU_VALUE, 'G',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "Sampling",
+ MENU_PULLRIGHT, menu_create(
+ MENU_ITEM,
+ MENU_STRING, "Default Sampling",
+ MENU_VALUE, '%',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "No Sampling",
+ MENU_VALUE, '!',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "2:1 Sampling",
+ MENU_VALUE, '@',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "3:1 Sampling",
+ MENU_VALUE, '#',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "4:1 Sampling",
+ MENU_VALUE, '$',
+ 0,
+ 0),
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "Magnifier",
+ MENU_PULLRIGHT, menu_create(
+ MENU_ITEM,
+ MENU_STRING, "128 x 64",
+ MENU_VALUE, '[',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "128 x 128",
+ MENU_VALUE, ']',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "256 x 128",
+ MENU_VALUE, '{',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "256 x 256",
+ MENU_VALUE, '}',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "512 x 256",
+ MENU_VALUE, '(',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "512 x 512",
+ MENU_VALUE, ')',
+ 0,
+ 0),
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "Reopen DVI file",
+ MENU_VALUE, 'R',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "New DVI file",
+ MENU_VALUE, 'F',
+ 0,
+/* MENU_ITEM,
+ MENU_STRING, "Print Page",
+ MENU_VALUE, 'P',
+ 0,
+ MENU_ITEM,
+ MENU_STRING, "Print Document",
+ MENU_VALUE, Control('P'),
+ 0, */
+ MENU_ITEM,
+ MENU_STRING, "Quit",
+ MENU_VALUE, 'Q',
+ 0,
+ 0);
+ }
+
+ return (int)menu_show(menu, canvas, event, 0);
+}
+
+/*
+ * page_magnify:
+ * Pops up magnified region (only if sampling != 1).
+ * Currently unimplemented.
+ */
+
+void
+page_magnify(canvas, pw, event)
+Canvas canvas;
+Pixwin *pw;
+Event *event;
+{
+ Rect r;
+ int w, h;
+ double scale_x, scale_y;
+ int sample_w, sample_h;
+ int new_sample_x, new_sample_y;
+ int delta_x, delta_y;
+ int sample_x, sample_y;
+ int dst_x, dst_y;
+ int page_x, page_y;
+ int old_cursor_op;
+ bool first_time = TRUE;
+ int win_x, win_y;
+#ifdef GOBBLE_MAGNIFY
+ int ninputs, canvasfd;
+#endif GOBBLE_MAGNIFY
+
+ if(sampling == 1 || sample_pr == NULL)
+ return;
+
+ if(mag_size_x < 4)
+ mag_size_x = 4;
+ if(mag_size_y < 4)
+ mag_size_y = 4;
+ if(mag_size_x > sample_pr->pr_width)
+ mag_size_x = sample_pr->pr_width;
+ if(mag_size_y > sample_pr->pr_height)
+ mag_size_y = sample_pr->pr_height;
+ if(mag_border < 0)
+ mag_border = 0;
+ if(mag_border > 8)
+ mag_border = 8;
+
+ /*
+ * Get Lock rect.
+ */
+ r.r_left = 0;
+ r.r_top = 0;
+ r.r_width = (int)window_get(canvas, WIN_WIDTH);
+ r.r_height = (int)window_get(canvas, WIN_HEIGHT);
+
+ /*
+ * Precompute some window sizes.
+ */
+ w = sample_pr->pr_width;
+ h = sample_pr->pr_height;
+ switch(sampling)
+ {
+ case 2:
+ scale_x = 2.0;
+ scale_y = 2.0;
+ break;
+
+ case 3:
+ scale_x = 8.0 / 3.0;
+ scale_y = 3.0;
+ break;
+
+ case 4:
+ scale_x = 4.0;
+ scale_y = 4.0;
+ break;
+
+ case 5:
+ scale_x = 8.0/3.0;
+ scale_y = 4.0;
+ break;
+
+ default:
+ return;
+ }
+ sample_w = mag_size_x / scale_x;
+ sample_h = mag_size_y / scale_y;
+
+ if(verbose & DEBUG_MAGNIFY)
+ fprintf(stderr, "page_magnify: scale %lf %lf; %d %d -> %d %d\n",
+ scale_x, scale_y, sample_w, sample_h, mag_size_x, mag_size_y);
+
+ /*
+ * Remove the cursor
+ */
+ old_cursor_op = (int)cursor_get(hand_cursor, CURSOR_OP);
+ cursor_set(hand_cursor, CURSOR_OP, PIX_DST, 0);
+ window_set(canvas, WIN_CURSOR, hand_cursor, 0);
+
+ /*
+ * Grab all input
+ */
+ window_set(canvas, WIN_GRAB_ALL_INPUT, TRUE, 0);
+#ifdef GOBBLE_MAGNIFY
+ canvasfd = (int)window_get(canvas, WIN_FD);
+#endif GOBBLE_MAGNIFY
+
+ /*
+ * Loop until up mouse.
+ */
+ sample_x = MAXINT;
+ sample_y = MAXINT;
+ while(! event_is_up(event))
+ {
+ /*
+ * Compute the region which will be magnified.
+ */
+ new_sample_x =
+ Range(0, event_x(event)-offset_x-sample_w/2, w-sample_w);
+ new_sample_y =
+ Range(0, event_y(event)-offset_y-sample_h/2, h-sample_h);
+
+ /*
+ * See how this differs from last magnified region.
+ */
+ delta_x = new_sample_x - sample_x;
+ delta_y = new_sample_y - sample_y;
+
+ /*
+ * Lock
+ */
+ pw_lock(pw, &r);
+
+ if(! first_time)
+ {
+ if(verbose & DEBUG_MAGNIFY)
+ fprintf(stderr, " covering with %d %d\n",
+ delta_x, delta_y);
+
+ /*
+ * Paint those portions of the image which were
+ * covered by the last magnifier, and exposed now.
+ * We could just paint the entire patch, but this
+ * gives unpleasant flashing when moving the window.
+ */
+ if(delta_x > 0)
+ pw_cover(pw, win_x, win_y,
+ delta_x, mag_size_y,
+ PIX_SRC, sample_pr, dst_x, dst_y);
+ else if(delta_x < 0)
+ pw_cover(pw, win_x+mag_size_x+delta_x, win_y,
+ -delta_x, mag_size_y,
+ PIX_SRC, sample_pr,
+ dst_x+mag_size_x+delta_x, dst_y);
+ if(delta_y > 0)
+ pw_cover(pw, win_x, win_y,
+ mag_size_x, delta_y,
+ PIX_SRC, sample_pr, dst_x, dst_y);
+ else if(delta_y < 0)
+ pw_cover(pw, win_x, win_y+mag_size_y+delta_y,
+ mag_size_x, -delta_y,
+ PIX_SRC, sample_pr,
+ dst_x, dst_y+mag_size_y+delta_y);
+ }
+ else
+ first_time = FALSE;
+
+ /*
+ * Compute the new destination and window positions
+ * for the new magnified region.
+ */
+ sample_x = new_sample_x;
+ sample_y = new_sample_y;
+ dst_x = sample_x - (mag_size_x - sample_w)/2;
+ dst_y = sample_y - (mag_size_y - sample_h)/2;
+ win_x = dst_x + offset_x;
+ win_y = dst_y + offset_y;
+ page_x = sample_x * scale_x;
+ page_y = sample_y * scale_y;
+
+ if(verbose & DEBUG_MAGNIFY)
+ fprintf(stderr, " painting at %d %d from %d %d\n",
+ dst_x, dst_y, page_x, page_y);
+
+ /*
+ * Display the magnified region.
+ */
+ pw_write(pw, win_x, win_y, mag_size_x, mag_size_y,
+ PIX_SRC, page_pr, page_x, page_y);
+ if(mag_border)
+ pw_rect(pw, win_x, win_y, mag_size_x, mag_size_y,
+ mag_border, PIX_SRC, -1);
+
+ /*
+ * Unlock
+ */
+ pw_unlock(pw);
+
+ /*
+ * Read another event.
+ */
+ window_read_event(canvas, event);
+#ifdef GOBBLE_MAGNIFY
+ if(ioctl(canvasfd, FIONREAD, &ninputs) == 0)
+ while(ninputs >= sizeof(Event) &&
+ window_read_event(canvas, event) == 0 &&
+ ! event_is_up(event))
+ ninputs -= sizeof(Event);
+#endif GOBBLE_MAGNIFY
+ }
+
+ /*
+ * Ungrab all input.
+ */
+ window_set(canvas, WIN_GRAB_ALL_INPUT, FALSE, 0);
+
+ /*
+ * Repaint
+ */
+ pw_cover(pw, win_x, win_y, mag_size_x, mag_size_y,
+ PIX_SRC, sample_pr, dst_x, dst_y);
+
+ /*
+ * Restore the cursor.
+ */
+ cursor_set(hand_cursor, CURSOR_OP, old_cursor_op, 0);
+ window_set(canvas, WIN_CURSOR, hand_cursor, 0);
+}
+
+/*
+ * page_pan:
+ * Pans page within screen.
+ */
+
+void
+page_pan(canvas, pw, event)
+Canvas canvas;
+Pixwin *pw;
+Event *event;
+{
+ int x, y;
+ int dx, dy;
+#ifdef GOBBLE_PAN
+ int ninputs, canvasfd;
+#endif GOBBLE_PAN
+
+
+ if(sample_pr == NULL)
+ return;
+
+ window_set(canvas, WIN_GRAB_ALL_INPUT, TRUE, 0);
+#ifdef GOBBLE_PAN
+ canvasfd = (int)window_get(canvas, WIN_FD);
+#endif GOBBLE_PAN
+
+ do
+ {
+ x = event_x(event);
+ y = event_y(event);
+
+ window_read_event(canvas, event);
+#ifdef GOBBLE_PAN
+ if(ioctl(canvasfd, FIONREAD, &ninputs) == 0)
+ while(ninputs >= sizeof(Event) &&
+ window_read_event(canvas, event) == 0 &&
+ ! event_is_up(event))
+ ninputs -= sizeof(Event);
+#endif GOBBLE_PAN
+
+ dx = event_x(event) - x;
+ dy = event_y(event) - y;
+
+ if(dx != 0 || dy != 0)
+ {
+ offset_x += dx;
+ offset_y += dy;
+
+ pw_cover(pw, 0, 0,
+ (int)window_get(canvas, WIN_WIDTH),
+ (int)window_get(canvas, WIN_HEIGHT),
+ PIX_SRC, sample_pr, -offset_x, -offset_y);
+ }
+ }
+ while(! event_is_up(event));
+
+ window_set(canvas, WIN_GRAB_ALL_INPUT, FALSE, 0);
+}
+
+/*
+ * goto_sheet:
+ * Opens requested sheet on screen.
+ */
+
+bool
+goto_sheet(new_sheet)
+int new_sheet;
+{
+ if(! check_dvi_file())
+ return FALSE;
+
+ if(verbose & DEBUG_SHEET)
+ fprintf(stderr, "goto_sheet(%d)\n", new_sheet);
+
+ /*
+ * Check against page limits.
+ */
+ if(new_sheet <= 0)
+ {
+ message("Attempt to go to sheet %d.", new_sheet);
+ return FALSE;
+ }
+
+ /*
+ * Are we already at the desired page ?
+ */
+ if(file_sheet == new_sheet)
+ return TRUE;
+
+ /*
+ * Do we already know where the page is ?
+ */
+ if(new_sheet < MAX_SHEETS && new_sheet <= last_known_sheet)
+ {
+ fseek(dvifp, sheet_table[new_sheet], 0);
+ file_sheet = new_sheet;
+ return TRUE;
+ }
+
+ /*
+ * Can't find it directly in the table:
+ * Go to the last known sheet...
+ */
+ file_sheet = last_known_sheet;
+ fseek(dvifp, sheet_table[file_sheet], 0);
+
+ /*
+ * Skip through the rest of the pages to the new page.
+ */
+ while(file_sheet < new_sheet)
+ {
+ /*
+ * Check for last page:
+ * Last page is always returned.
+ */
+ if(last_sheet && file_sheet >= last_sheet)
+ {
+ file_sheet = last_sheet - 1;
+ fseek(dvifp, sheet_table[file_sheet], 0);
+ return TRUE;
+ }
+
+ /*
+ * Otherwise, skip this page and look at the next.
+ */
+ process_page(SKIP);
+ }
+ return TRUE;
+}
+
+/*
+ * goto_page:
+ * Opens requested page on screen.
+ */
+
+bool
+goto_page(new_page)
+int new_page;
+{
+ int sheet;
+
+ if(! check_dvi_file())
+ return FALSE;
+
+ if(verbose & DEBUG_SHEET)
+ fprintf(stderr, "goto_page(%d)\n", new_page);
+
+ /*
+ * Search for page in the table.
+ */
+ for(sheet = 1; sheet < last_known_sheet; sheet++)
+ {
+ if(sheet_page[sheet] == new_page)
+ {
+ file_sheet = sheet;
+ fseek(dvifp, sheet_table[file_sheet], 0);
+ return TRUE;
+ }
+ }
+
+ /*
+ * Can't find it directly in the table:
+ * Go to the last known sheet...
+ */
+ file_sheet = last_known_sheet;
+ fseek(dvifp, sheet_table[file_sheet], 0);
+
+ /*
+ * Skip through the rest of the pages to the new page.
+ */
+ for( ; ; )
+ {
+ /*
+ * Check for last page:
+ */
+ if(last_sheet && file_sheet >= last_sheet)
+ {
+ if(new_page == LAST_PAGE)
+ {
+ file_sheet = last_sheet - 1;
+ fseek(dvifp, sheet_table[file_sheet], 0);
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ /*
+ * Otherwise, examine this page.
+ */
+ sheet = file_sheet;
+ process_page(SKIP);
+
+ /*
+ * If this was the page, go back,
+ * and return it.
+ */
+ if(sheet_page[sheet] == new_page)
+ {
+ file_sheet = sheet;
+ fseek(dvifp, sheet_table[file_sheet], 0);
+ return TRUE;
+ }
+ }
+}
+
+/*
+ * DVI file functions.
+ * ==================
+ */
+
+/*
+ * init_dvi_file:
+ * Opens the dvi file, and checks for valid codes etc.
+ * Reads the postamble (if enabled)
+ * Leaves the file pointer at the start of the first page.
+ */
+
+bool
+init_dvi_file()
+{
+ int i;
+
+ /*
+ * Open the file; close-on-exec.
+ */
+ if((dvifp = fopen(pathname, "r")) == NULL)
+ {
+ message("Cant open file %s", pathname);
+ return FALSE;
+ }
+ fcntl(fileno(dvifp), F_SETFD, 1);
+
+ /*
+ * Read the magic number and version number
+ */
+ if((i = get_unsigned(dvifp, 1)) != PRE)
+ {
+ message("%s: not a dvi file.", filename);
+ fclose(dvifp);
+ return FALSE;
+ }
+ if((i = get_signed(dvifp, 1)) != DVIFORMAT)
+ {
+ message("%s: dvi format %d not supported.", filename, i);
+ fclose(dvifp);
+ return FALSE;
+ }
+
+ /*
+ * Make a note of the access time.
+ */
+ if(fstat(fileno(dvifp), &stat_buf) == 0)
+ {
+ mtime = stat_buf.st_mtime;
+ }
+ else
+ {
+ message("%s: dvifile stat failed.", filename);
+ mtime = 0;
+ }
+
+ if(pre_load)
+ {
+ /*
+ * Load font information from postable.
+ */
+ if(! read_postamble())
+ {
+ fclose(dvifp);
+ return FALSE;
+ }
+
+ /*
+ * Return to start of first page.
+ */
+ fseek(dvifp, (long)14, 0);
+ }
+ else
+ {
+ /*
+ * Read basic data from preamble.
+ */
+ num = get_unsigned(dvifp, 4);
+ den = get_unsigned(dvifp, 4);
+ mag = get_unsigned(dvifp, 4);
+ hconv = vconv = do_convert(num, den, resolution);
+ }
+
+ /*
+ * Skip i more bytes of preamble.
+ */
+ i = get_unsigned(dvifp, 1);
+ fseek(dvifp, (long)i, 1);
+
+ /*
+ * Allocate buffer for the page.
+ */
+ if(! (page_pr = pr_alloc(&page_mpr,
+ (int)(page_w * resolution), (int)(page_h * resolution), 1)))
+ {
+ message("Out of memory for image allocation.");
+ fclose(dvifp);
+ return FALSE;
+ }
+
+ if(verbose & DEBUG_IMSIZE)
+ fprintf(stderr, "Allocated buffer (%d x %d)\n",
+ page_pr->pr_width, page_pr->pr_height);
+
+ /*
+ * Set up the page fseek pointer table.
+ * We are now at page 0.
+ */
+ for(i = 0; i < MAX_SHEETS; i++)
+ {
+ sheet_table[i] = 0;
+ sheet_page[i] = BAD_PAGE;
+ }
+ file_sheet = 1;
+ last_sheet = 0; /* last page == unknown */
+ last_known_sheet = 1;
+ sheet_table[last_known_sheet] = ftell(dvifp);
+
+ if(verbose & DEBUG_SHEET)
+ fprintf(stderr, "sheet_table[%d] = %d\n",
+ last_known_sheet, ftell(dvifp));
+
+ return TRUE;
+}
+
+/*
+ * close_dvi_file:
+ * Cleans up after reading a file.
+ */
+
+void
+close_dvi_file()
+{
+ if(dvifp == NULL)
+ return;
+
+ /*
+ * Get rid of image memory.
+ */
+ sample_pr = pr_free(&sample_mpr);
+ page_pr = pr_free(&page_mpr);
+
+ /*
+ * close the dvifile.
+ */
+ fclose(dvifp);
+ dvifp = NULL;
+ mtime = 0;
+
+ /*
+ * Hack the sheet numbers to prevent access to the file.
+ */
+ last_sheet = -1;
+ last_known_sheet = -1;
+
+ /*
+ * Close the fonts and free up memory.
+ */
+ close_fonts();
+}
+
+/*
+ * check_dvi_file:
+ * Checks that this is the same file -- has not been modified since
+ * it was opened.
+ */
+
+bool
+check_dvi_file()
+{
+ if(dvifp == NULL)
+ {
+ message("No dvifile open");
+ return FALSE;
+ }
+
+ if(fstat(fileno(dvifp), &stat_buf) != 0)
+ {
+ message("%s: dvifile fstat failed.", filename);
+ return FALSE;
+ }
+
+ if(stat_buf.st_mtime != mtime)
+ {
+ message("%s: dvifile modified", filename);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * read_postamble:
+ * This routine is used to read in the postamble values. It
+ * initializes the magnification and checks the stack height prior to
+ * starting printing the document.
+ * Returns TRUE unless document cannot be processed.
+ */
+
+bool
+read_postamble()
+{
+ if(! check_dvi_file())
+ return FALSE;
+
+ if(! find_postamble_ptr (&postambleptr))
+ return FALSE;
+
+ if(get_unsigned(dvifp, 1) != POST)
+ {
+ message("%s: bad dvi file: no POST at head of postamble.",
+ filename);
+ return FALSE;
+ }
+
+ (void)get_unsigned(dvifp, 4); /* discard last page pointer */
+ num = get_unsigned(dvifp, 4);
+ den = get_unsigned(dvifp, 4);
+ mag = get_unsigned(dvifp, 4);
+ hconv = vconv = do_convert(num, den, resolution);
+
+ (void)get_unsigned(dvifp, 4); /* height-plus-depth of tallest page */
+ (void)get_unsigned(dvifp, 4); /* width of widest page */
+
+ if(get_unsigned(dvifp, 2) >= STACKSIZE)
+ {
+ message("%s: bad dvi file: stack is too large.",
+ filename);
+ return FALSE;
+ }
+
+ /* last_sheet = */ get_unsigned(dvifp, 2);
+
+ if(! get_font_def())
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * find_postamble_ptr
+ * Move to the end of the dvifile and find the start of the postamble.
+ */
+
+bool
+find_postamble_ptr(postambleptr)
+long *postambleptr;
+{
+ int i;
+
+ fseek(dvifp, (long) 0, 2);
+ *postambleptr = ftell(dvifp) - 4;
+ fseek(dvifp, *postambleptr, 0);
+
+ for( ; ; )
+ {
+ fseek(dvifp, --(*postambleptr), 0);
+ if(((i = get_unsigned(dvifp, 1)) != 223) && (i != DVIFORMAT))
+ {
+ message("%s: Bad dvi file: bad end of file", filename);
+ return FALSE;
+ }
+ if(i == DVIFORMAT)
+ break;
+ }
+
+ fseek(dvifp, (*postambleptr) - 4, 0);
+ *postambleptr = get_unsigned(dvifp, 4);
+ fseek(dvifp, *postambleptr, 0);
+
+ return TRUE;
+}
+
+/*
+ * process_page:
+ * Rasterises the next page in the dvifile into page_mpr.
+ * Leaves the file pointer at the start of the next page.
+ *
+ * If skip mode is true, then nothing is actually drawn, the commands
+ * are interpreted only for the side effect of moving the filepointer
+ * to the next page.
+ */
+
+bool
+process_page(skip_mode)
+register bool skip_mode;
+{
+ int command; /* current command */
+ register int i; /* command parameter; loop index */
+ int k; /* temporary parameter */
+ int val, val2; /* temporarys to hold command information*/
+ int w; /* current horizontal spacing */
+ int x; /* current horizontal spacing */
+ int y; /* current vertical spacing */
+ int z; /* current vertical spacing */
+ int counter[10];
+ int sp; /* stack pointer */
+ static struct stack_entry stack[STACKSIZE]; /* stack */
+
+ if(! check_dvi_file())
+ return FALSE;
+
+ if(verbose & DEBUG_SHEET)
+ fprintf(stderr, "sheet %d starts at %d\n",
+ file_sheet, ftell(dvifp));
+
+ while((command = get_unsigned(dvifp, 1)) != EOP)
+ {
+ switch(command)
+ {
+
+ case SET1:
+ case SET2:
+ case SET3:
+ case SET4:
+ val = get_unsigned(dvifp, command-SET1+1);
+ if(! skip_mode)
+ set_char(val, command);
+ break;
+
+ case SET_RULE:
+ val = get_unsigned(dvifp, 4);
+ val2 = get_unsigned(dvifp, 4);
+ if(! skip_mode)
+ set_rule(val, val2, 1);
+ break;
+
+ case PUT1:
+ case PUT2:
+ case PUT3:
+ case PUT4:
+ val = get_unsigned(dvifp,command-PUT1+1);
+ if(! skip_mode)
+ set_char(val, command);
+ break;
+
+ case PUT_RULE:
+ val = get_unsigned(dvifp, 4);
+ val2 = get_unsigned(dvifp, 4);
+ if(! skip_mode)
+ set_rule(val, val2, 0);
+ break;
+
+ case NOP:
+ break;
+
+ case BOP:
+ /*
+ * These are the 10 counters.
+ * Discard previous page pointer.
+ */
+ for(i=0; i<10; i++)
+ counter[i] = get_unsigned(dvifp, 4);
+ (void)get_unsigned(dvifp, 4);
+
+ /*
+ * The first counter is the page number.
+ */
+ disp_page = counter[0];
+ if(file_sheet < MAX_SHEETS)
+ sheet_page[file_sheet] = disp_page;
+
+ /*
+ * Show what is happening.
+ */
+ sprintf(label, "%s: File \"%s\" Page %d %s",
+ DVIPAGE_LABEL, filename,
+ disp_page, (skip_mode) ? "Skipping" : "Processing");
+ window_set(disp_frame,
+ FRAME_LABEL, label,
+ 0);
+
+ if(! skip_mode)
+ {
+ /*
+ * Clear the page
+ */
+ pr_rop(page_pr, 0, 0,
+ page_pr->pr_width, page_pr->pr_height,
+ PIX_CLR, NULL, 0, 0);
+
+ /*
+ * Mark the edges of the page
+ */
+ pr_rect(page_pr, 0, 0,
+ (int)(page_w * resolution),
+ (int)(page_h * resolution),
+ 3, PIX_SET, 1);
+
+ /*
+ * Mark the nominal page window.
+ */
+ if(show_page_frame)
+ {
+ pr_rect(page_pr, 0+origin_x, 0+origin_y,
+ (int)(page_w*resolution) - 2*origin_x,
+ (int)(page_h*resolution) - 2*origin_y,
+ 1, PIX_SET, 1);
+ }
+ }
+
+ h = v = w = x = y = z = 0;
+ sp = 0;
+ fontptr = NULL;
+ break;
+
+ case PUSH:
+ if (sp >= STACKSIZE)
+ {
+ message("%s: Bad dvi file: stack overflow",
+ filename);
+ return FALSE;
+ }
+ stack[sp].h = h;
+ stack[sp].v = v;
+ stack[sp].w = w;
+ stack[sp].x = x;
+ stack[sp].y = y;
+ stack[sp].z = z;
+ sp++;
+ break;
+
+ case POP:
+ --sp;
+ if (sp < 0)
+ {
+ message("%s: Bad dvi file: stack underflow",
+ filename);
+ return FALSE;
+ }
+ h = stack[sp].h;
+ v = stack[sp].v;
+ w = stack[sp].w;
+ x = stack[sp].x;
+ y = stack[sp].y;
+ z = stack[sp].z;
+ break;
+
+ case RIGHT1:
+ case RIGHT2:
+ case RIGHT3:
+ case RIGHT4:
+ val = get_signed(dvifp,command-RIGHT1+1);
+ if(! skip_mode)
+ move_over(val);
+ break;
+
+ case W0:
+ if(! skip_mode)
+ move_over(w);
+ break;
+
+ case W1:
+ case W2:
+ case W3:
+ case W4:
+ w = get_signed(dvifp,command-W1+1);
+ if(! skip_mode)
+ move_over(w);
+ break;
+
+ case X0:
+ if(! skip_mode)
+ move_over(x);
+ break;
+
+ case X1:
+ case X2:
+ case X3:
+ case X4:
+ x = get_signed(dvifp,command-X1+1);
+ if(! skip_mode)
+ move_over(x);
+ break;
+
+ case DOWN1:
+ case DOWN2:
+ case DOWN3:
+ case DOWN4:
+ val = get_signed(dvifp,command-DOWN1+1);
+ if(! skip_mode)
+ move_down(val);
+ break;
+
+ case Y0:
+ if(! skip_mode)
+ move_down(y);
+ break;
+
+ case Y1:
+ case Y2:
+ case Y3:
+ case Y4:
+ y = get_signed(dvifp,command-Y1+1);
+ if(! skip_mode)
+ move_down(y);
+ break;
+
+ case Z0:
+ if(! skip_mode)
+ move_down(z);
+ break;
+
+ case Z1:
+ case Z2:
+ case Z3:
+ case Z4:
+ z = get_signed(dvifp,command-Z1+1);
+ if(! skip_mode)
+ move_down(z);
+ break;
+
+ case FNT1:
+ case FNT2:
+ case FNT3:
+ case FNT4:
+ if(! skip_mode)
+ set_font_num(
+ get_unsigned(dvifp,command-FNT1+1));
+ break;
+
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ k = get_unsigned(dvifp,command-XXX1+1);
+ while(k--)
+ get_unsigned(dvifp, 1);
+ break;
+
+ case FNT_DEF1:
+ case FNT_DEF2:
+ case FNT_DEF3:
+ case FNT_DEF4:
+ if(pre_load)
+ skip_font_def(
+ get_unsigned(dvifp, command-FNT_DEF1+1));
+ else
+ if(! read_font_def(
+ get_unsigned(dvifp, command-FNT_DEF1+1)))
+ return FALSE;
+ break;
+
+ case PRE:
+ message(
+ "%s: Bad dvi file: preamble found within main section.",
+ filename);
+ return FALSE;
+
+ case POST:
+ fseek(dvifp, (long) -1, 1);
+ last_sheet = file_sheet;
+
+ /*
+ * We have done nothing, so there is no need to
+ * resample the page or increment the page counter.
+ */
+ return FALSE;
+
+ case POST_POST:
+ message(
+ "%s: Bad dvi file: postpostamble found within main section.",
+ filename);
+ return FALSE;
+
+ default:
+ if(command >= FONT_00 && command <= FONT_63)
+ {
+ if(! skip_mode)
+ set_font_num(command - FONT_00);
+ }
+ else if(command >= SETC_000 && command <= SETC_127)
+ {
+ if(! skip_mode)
+ set_char(command - SETC_000, command);
+ }
+ else
+ {
+ message(
+ "%s: Bad dvi file: undefined command (%d) found.",
+ filename, command);
+ return FALSE;
+ }
+ }
+ }
+
+ /*
+ * End of page.
+ */
+ if(! skip_mode)
+ {
+ /*
+ * Sample the page.
+ */
+ sample_page();
+ disp_sheet = file_sheet;
+ }
+
+ /*
+ * The file is now at the start of the next page.
+ */
+ file_sheet++;
+ if(file_sheet > last_known_sheet)
+ {
+ if(file_sheet < MAX_SHEETS)
+ {
+ last_known_sheet = file_sheet;
+ sheet_table[file_sheet] = ftell(dvifp);
+ }
+
+ if(verbose & DEBUG_SHEET)
+ fprintf(stderr, "sheet %d starts at %d\n",
+ file_sheet, ftell(dvifp));
+ }
+
+ return TRUE;
+}
+
+/*
+ * Draw and Move Functions.
+ * ========================
+ */
+
+/*
+ * set_font_num:
+ * This routine is used to specify the font to be used in printing future
+ * chars.
+ */
+
+void
+set_font_num(k)
+int k;
+{
+ for(fontptr = hfontptr; fontptr != NULL; fontptr = fontptr->next)
+ {
+ if(fontptr->k == k)
+ {
+ fontptr->use_count++;
+ return;
+ }
+ }
+
+ fprintf(stderr, "I have lost a font; this cant happen\n");
+ exit(1);
+}
+
+/*
+ * set_char:
+ */
+
+void
+set_char(c, command)
+int c, command;
+{
+ register struct char_entry *ptr;
+
+ ptr = &(fontptr->ch[c]);
+ hh = Pix_round(h, hconv);
+ vv = Pix_round(v, vconv);
+
+ if(! ptr->where.isloaded)
+ if(! load_char(fontptr, ptr))
+ return;
+
+ if(ptr->where.address.pixrectptr)
+ pr_rop(page_pr, hh - ptr->xOffset + origin_x,
+ vv - ptr->yOffset + origin_y,
+ ptr->width, ptr->height, PIX_SRC | PIX_DST,
+ ptr->where.address.pixrectptr, 0, 0);
+
+ if(command <= SET4)
+ h += ptr->tfmw;
+
+ return;
+}
+
+/*
+ * set_rule:
+ * This routine will draw a rule on the screen
+ */
+
+void
+set_rule(a, b, Set)
+int a, b;
+bool Set;
+{
+ int ehh, evv;
+
+ hh = Pix_round(h, hconv);
+ vv = Pix_round(v - a, vconv);
+ ehh = Pix_round(h + b, hconv);
+ evv = Pix_round(v, vconv);
+
+ if(hh == ehh)
+ ehh++;
+ if(vv == evv)
+ vv--;
+ if((a > 0) && (b > 0))
+ pr_rop(page_pr, hh+origin_x, vv+origin_y,
+ ehh-hh, evv-vv, PIX_SET, NULL, 0, 0);
+ if(Set)
+ {
+ h += b;
+/* v += a; */
+ }
+}
+
+/*
+ * move_down:
+ */
+
+void
+move_down(a)
+int a;
+{
+ v += a;
+}
+
+
+/*
+ * move_over:
+ */
+
+void
+move_over(b)
+int b;
+{
+ h += b;
+}