diff options
Diffstat (limited to 'dviware/dvipage/dvipage.c')
-rw-r--r-- | dviware/dvipage/dvipage.c | 2421 |
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; +} |