IMx~XDVI.BAKXDVI.BAKTBACKUP *.*;/EXCLUDE=(*.OBJ,*.EXE,A*.COM,*TEST*.*)/LOG USER1:[ANONYMOUS]XDVI.BAK/SAVE MRL pXqnV6.2 _MERLOT::  _$2$DKA300: V6.2 ~  *[XDVI]AAAREADME.TXT;1+,Y./ 4N:- 0123KPWO56, i7 ki8_o9GHJFThis is a modified version made to use ghostscript to display includedKpostscript files. It relies on DVIPS being installed, as it looks for the NDVIPS header files in the directory pointed to by the logical name DVI_INPUTS./Any problems should be reported to me. Thanks. Mark LondonMRL@PSFC.MIT.EDU *[XDVI]DVI.H;1+,k./ 4P- 0123KPWO5678_o9GHJ/* * Mnemonics for bytes in dvi file. */ #define SETCHAR0 0 #define SET1 128 #define SETRULE 132 #define PUT1 133 #define PUTRULE 137 #define NOP 138 #define BOP 139 #define EOP 140 #define PUSH 141 #define POP 142 #define RIGHT1 143 #define RIGHT2 144 #define RIGHT3 145 #define RIGHT4 146 #define W0 147 #define W1 148 #define W2 149 #define W3 150 #define W4 151 #define X0 152 #define X1 153 #define X2 154 #define X3 155 #define X4 156 #define DOWN1 157 #define DOWN2 158 #define DOWN3 159 #define DOWN4 160 #define Y0 161 #define Y1 162 #define Y2 163 #define Y3 164 #define Y4 165 #define Z0 166 #define Z1 167 #define Z2 168 #define Z3 169 #define Z4 170 #define FNTNUM0 171 #define FNT1 235 #define FNT2 236 #define FNT3 237 #define FNT4 238 #define XXX1 239 #define XXX2 240 #define XXX3 241 #define XXX4 242 #define FNTDEF1 243 #define FNTDEF2 244 #define FNTDEF3 245 #define FNTDEF4 246 #define PRE 247 #define POST 248 #define POSTPOST 249 #define SREFL 250 #define EREFL 251 #define TRAILER 223 /* Trailing bytes at end of file */ *[XDVI]DVI_DRAW.C;2+, .</ 4M<<;- 0@123KPWO=56~hg7I~hg80]o9GHJp/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTE: * xdvi is based on prior work, as noted in the modification history * in xdvi.c. */ #include #include "xdvi.h" #include "dvi.h" #if NeedVarargsPrototypes /* this is for tell_oops */ #include #else #include #endif #ifdef DOPRNT /* define this if vfprintf gives you trouble */ #define vfprintf(stream, message, args) _doprnt(message, args, stream) #endif static struct frame frame0; /* dummy head of list */ #ifdef TEXXET static struct frame *scan_frame; /* head frame for scanning */ #endif #ifndef DVI_BUFFER_LEN #define DVI_BUFFER_LEN 512 #endif static ubyte dvi_buffer[DVI_BUFFER_LEN]; static struct frame *current_frame; #ifndef TEXXET #define DIR 1 #else #define DIR currinf.dir #endif /* * Explanation of the following constant: * offset_[xy] << 16: margin (defaults to one inch) * shrink_factor << 16: one pixel page border * shrink_factor << 15: rounding for pixel_conv */ #define OFFSET_X (offset_x << 16) + (shrink_factor * 3 << 15) #define OFFSET_Y (offset_y << 16) + (shrink_factor * 3 << 15) #ifndef BMLONG #ifndef BMSHORT BMUNIT bit_masks[9] = { 0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff }; #else /* BMSHORT */ BMUNIT bit_masks[17] = { 0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; #endif /* BMSHORT */ #else /* BMLONG */ BMUNIT bit_masks[33] = { 0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff, 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff }; #endif /* BMLONG */ #ifdef VMS #define off_t int #endif extern off_t lseek(); #ifndef SEEK_SET /* if is not provided (or for = min_x && y < max_y && y + h >= min_y) { if (--event_counter == 0) read_events(False); XFillRectangle(DISP, currwin.win, ruleGC, x - currwin.base_x, y - currwin.base_y, w ? w : 1, h ? h : 1); } } static void put_bitmap(bitmap, x, y) register struct bitmap *bitmap; register int x, y; { if (debug & DBG_BITMAP) Printf("X(%d,%d)\n", x - currwin.base_x, y - currwin.base_y); if (x < max_x && x + (int) bitmap->w >= min_x && y < max_y && y + (int) bitmap->h >= min_y) { if (--event_counter == 0) read_events(False); image->width = bitmap->w; image->height = bitmap->h; image->data = bitmap->bits; image->bytes_per_line = bitmap->bytes_wide; XPutImage(DISP, currwin.win, foreGC, image, 0, 0, x - currwin.base_x, y - currwin.base_y, bitmap->w, bitmap->h); if (foreGC2) XPutImage(DISP, currwin.win, foreGC2, image, 0, 0, x - currwin.base_x, y - currwin.base_y, bitmap->w, bitmap->h); } } #ifdef GREY static void put_image(img, x, y) register XImage *img; register int x, y; { if (x < max_x && x + img->width >= min_x && y < max_y && y + img->height >= min_y) { if (--event_counter == 0) read_events (False); XPutImage(DISP, currwin.win, foreGC, img, 0, 0, x - currwin.base_x, y - currwin.base_y, (unsigned int) img->width, (unsigned int) img->height); } } #endif /* GREY */ /* * Draw the border of a rectangle on the screen. */ void put_border(x, y, width, height, ourGC) int x, y; unsigned int width, height; GC ourGC; { --width; --height; /* top */ XFillRectangle(DISP, currwin.win, ourGC, x, y, width, 1); /* right */ XFillRectangle(DISP, currwin.win, ourGC, x + (int) width, y, 1, height); /* bottom */ XFillRectangle(DISP, currwin.win, ourGC, x + 1, y + (int) height, width, 1); /* left */ XFillRectangle(DISP, currwin.win, ourGC, x, y + 1, 1, height); } /* * Byte reading routines for dvi file. */ #define xtell(pos) (lseek(fileno(dvi_file), 0L, SEEK_CUR) - \ (currinf.end - (pos))) static ubyte xxone() { if (currinf.virtual) { ++currinf.pos; return EOP; } currinf.end = dvi_buffer + read(fileno(dvi_file), (char *) (currinf.pos = dvi_buffer), DVI_BUFFER_LEN); return currinf.end > dvi_buffer ? *(currinf.pos)++ : EOF; } #define xone() (currinf.pos < currinf.end ? *(currinf.pos)++ : xxone()) static unsigned long xnum(size) register ubyte size; { register long x = 0; while (size--) x = (x << 8) | xone(); return x; } static long xsnum(size) register ubyte size; { register long x; #if __STDC__ x = (signed char) xone(); #else x = xone(); if (x & 0x80) x -= 0x100; #endif while (--size) x = (x << 8) | xone(); return x; } #define xsfour() xsnum(4) static void xskip(offset) long offset; { currinf.pos += offset; if (!currinf.virtual && currinf.pos > currinf.end) (void) lseek(fileno(dvi_file), (long) (currinf.pos - currinf.end), SEEK_CUR); } #if NeedVarargsPrototypes static NORETURN void tell_oops(_Xconst char *message, ...) #else /* VARARGS */ static NORETURN void tell_oops(va_alist) va_dcl #endif { #if !NeedVarargsPrototypes _Xconst char *message; #endif va_list args; Fprintf(stderr, "%s: ", prog); #if NeedVarargsPrototypes va_start(args, message); #else va_start(args); message = va_arg(args, _Xconst char *); #endif (void) vfprintf(stderr, message, args); va_end(args); if (currinf.virtual) Fprintf(stderr, " in virtual font %s\n", currinf.virtual->fontname); else Fprintf(stderr, ", offset %ld\n", xtell(currinf.pos - 1)); #if PS ps_destroy(); #endif exit(1); } /* * Code for debugging options. */ static void print_bitmap(bitmap) register struct bitmap *bitmap; { register BMUNIT *ptr = (BMUNIT *) bitmap->bits; register int x, y, i; if (ptr == NULL) oops("print_bitmap called with null pointer."); Printf("w = %d, h = %d, bytes wide = %d\n", bitmap->w, bitmap->h, bitmap->bytes_wide); for (y = 0; y < (int) bitmap->h; ++y) { for (x = bitmap->bytes_wide; x > 0; x -= BYTES_PER_BMUNIT) { #ifndef MSBITFIRST for (i = 0; i < BITS_PER_BMUNIT; ++i) #else for (i = BITS_PER_BMUNIT - 1; i >= 0; --i) #endif Putchar((*ptr & (1 << i)) ? '@' : ' '); ++ptr; } Putchar('\n'); } } static void print_char(ch, g) ubyte ch; struct glyph *g; { Printf("char %d", ch); if (isprint(ch)) Printf(" (%c)", ch); Putchar('\n'); Printf("x = %d, y = %d, dvi = %ld\n", g->x, g->y, g->dvi_adv); print_bitmap(&g->bitmap); } static _Xconst char *dvi_table1[] = { "SET1", NULL, NULL, NULL, "SETRULE", "PUT1", NULL, NULL, NULL, "PUTRULE", "NOP", "BOP", "EOP", "PUSH", "POP", "RIGHT1", "RIGHT2", "RIGHT3", "RIGHT4", "W0", "W1", "W2", "W3", "W4", "X0", "X1", "X2", "X3", "X4", "DOWN1", "DOWN2", "DOWN3", "DOWN4", "Y0", "Y1", "Y2", "Y3", "Y4", "Z0", "Z1", "Z2", "Z3", "Z4"}; static _Xconst char *dvi_table2[] = { "FNT1", "FNT2", "FNT3", "FNT4", "XXX1", "XXX2", "XXX3", "XXX4", "FNTDEF1", "FNTDEF2", "FNTDEF3", "FNTDEF4", "PRE", "POST", "POSTPOST", "SREFL", "EREFL", NULL, NULL, NULL, NULL}; static void print_dvi(ch) ubyte ch; { _Xconst char *s; Printf("%4d %4d ", PXL_H, PXL_V); if (ch <= (ubyte) (SETCHAR0 + 127)) { Printf("SETCHAR%-3d", ch - SETCHAR0); if (isprint(ch)) Printf(" (%c)", ch); Putchar('\n'); return; } else if (ch < FNTNUM0) s = dvi_table1[ch - 128]; else if (ch <= (ubyte) (FNTNUM0 + 63)) { Printf("FNTNUM%d\n", ch - FNTNUM0); return; } else s = dvi_table2[ch - (FNTNUM0 + 64)]; if (s) Puts(s); else tell_oops("unknown op-code %d", ch); } /* * Count the number of set bits in a given region of the bitmap */ char sample_count[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; static int sample(bits, bytes_wide, bit_skip, w, h) BMUNIT *bits; int bytes_wide, bit_skip, w, h; { BMUNIT *ptr, *endp; register BMUNIT *cp; int bits_left; register int n, bit_shift, wid; ptr = bits + bit_skip / BITS_PER_BMUNIT; endp = ADD(bits, h * bytes_wide); bits_left = w; #ifndef MSBITFIRST bit_shift = bit_skip % BITS_PER_BMUNIT; #else bit_shift = BITS_PER_BMUNIT - bit_skip % BITS_PER_BMUNIT; #endif n = 0; while (bits_left) { #ifndef MSBITFIRST wid = BITS_PER_BMUNIT - bit_shift; #else wid = bit_shift; #endif if (wid > bits_left) wid = bits_left; if (wid > 4) wid = 4; #ifdef MSBITFIRST bit_shift -= wid; #endif for (cp = ptr; cp < endp; cp = ADD(cp, bytes_wide)) n += sample_count[(*cp >> bit_shift) & bit_masks[wid]]; #ifndef MSBITFIRST bit_shift += wid; if (bit_shift == BITS_PER_BMUNIT) { bit_shift = 0; ++ptr; } #else if (bit_shift == 0) { bit_shift = BITS_PER_BMUNIT; ++ptr; } #endif bits_left -= wid; } return n; } static void shrink_glyph(g) register struct glyph *g; { int shrunk_bytes_wide, shrunk_height; int rows_left, rows, init_cols; int cols_left; register int cols; BMUNIT *old_ptr, *new_ptr; register BMUNIT m, *cp; int min_sample = shrink_factor * shrink_factor * density / 100; /* These machinations ensure that the character is shrunk according to its hot point, rather than its upper left-hand corner. */ g->x2 = g->x / shrink_factor; init_cols = g->x - g->x2 * shrink_factor; if (init_cols <= 0) init_cols += shrink_factor; else ++g->x2; g->bitmap2.w = g->x2 + ROUNDUP((int) g->bitmap.w - g->x, shrink_factor); /* include row zero with the positively numbered rows */ cols = g->y + 1; /* spare register variable */ g->y2 = cols / shrink_factor; rows = cols - g->y2 * shrink_factor; if (rows <= 0) { rows += shrink_factor; --g->y2; } g->bitmap2.h = shrunk_height = g->y2 + ROUNDUP((int) g->bitmap.h - cols, shrink_factor) + 1; alloc_bitmap(&g->bitmap2); old_ptr = (BMUNIT *) g->bitmap.bits; new_ptr = (BMUNIT *) g->bitmap2.bits; shrunk_bytes_wide = g->bitmap2.bytes_wide; rows_left = g->bitmap.h; bzero((char *) new_ptr, shrunk_bytes_wide * shrunk_height); while (rows_left) { if (rows > rows_left) rows = rows_left; cols_left = g->bitmap.w; #ifndef MSBITFIRST m = (1 << 0); #else m = ((BMUNIT) 1 << (BITS_PER_BMUNIT-1)); #endif cp = new_ptr; cols = init_cols; while (cols_left) { if (cols > cols_left) cols = cols_left; if (sample(old_ptr, g->bitmap.bytes_wide, (int) g->bitmap.w - cols_left, cols, rows) >= min_sample) *cp |= m; #ifndef MSBITFIRST if (m == ((BMUNIT)1 << (BITS_PER_BMUNIT-1))) { m = (1 << 0); ++cp; } else m <<= 1; #else if (m == (1 << 0)) { m = ((BMUNIT) 1 << (BITS_PER_BMUNIT-1)); ++cp; } else m >>= 1; #endif cols_left -= cols; cols = shrink_factor; } *((char **) &new_ptr) += shrunk_bytes_wide; *((char **) &old_ptr) += rows * g->bitmap.bytes_wide; rows_left -= rows; rows = shrink_factor; } g->y2 = g->y / shrink_factor; if (debug & DBG_BITMAP) print_bitmap(&g->bitmap2); } #ifdef GREY static void shrink_glyph_grey(g) register struct glyph *g; { int rows_left, rows, init_cols; int cols_left; register int cols; int x, y; long thesample; BMUNIT *old_ptr; unsigned int size; /* These machinations ensure that the character is shrunk according to its hot point, rather than its upper left-hand corner. */ g->x2 = g->x / shrink_factor; init_cols = g->x - g->x2 * shrink_factor; if (init_cols <= 0) init_cols += shrink_factor; else ++g->x2; g->bitmap2.w = g->x2 + ROUNDUP((int) g->bitmap.w - g->x, shrink_factor); /* include row zero with the positively numbered rows */ cols = g->y + 1; /* spare register variable */ g->y2 = cols / shrink_factor; rows = cols - g->y2 * shrink_factor; if (rows <= 0) { rows += shrink_factor; --g->y2; } g->bitmap2.h = g->y2 + ROUNDUP((int) g->bitmap.h - cols, shrink_factor) + 1; g->image2 = XCreateImage(DISP, DefaultVisualOfScreen(SCRN), (unsigned int) DefaultDepthOfScreen(SCRN), ZPixmap, 0, (char *) NULL, g->bitmap2.w, g->bitmap2.h, BITS_PER_BMUNIT, 0); size = g->image2->bytes_per_line * g->bitmap2.h; g->pixmap2 = g->image2->data = xmalloc(size != 0 ? size : 1, "character pixmap"); old_ptr = (BMUNIT *) g->bitmap.bits; rows_left = g->bitmap.h; y = 0; while (rows_left) { x = 0; if (rows > rows_left) rows = rows_left; cols_left = g->bitmap.w; cols = init_cols; while (cols_left) { if (cols > cols_left) cols = cols_left; thesample = sample(old_ptr, g->bitmap.bytes_wide, (int) g->bitmap.w - cols_left, cols, rows); XPutPixel(g->image2, x, y, pixeltbl[thesample]); cols_left -= cols; cols = shrink_factor; x++; } *((char **) &old_ptr) += rows * g->bitmap.bytes_wide; rows_left -= rows; rows = shrink_factor; y++; } while (y < (int) g->bitmap2.h) { for (x = 0; x < (int) g->bitmap2.w; x++) XPutPixel(g->image2, x, y, *pixeltbl); y++; } g->y2 = g->y / shrink_factor; } #endif /* GREY */ /* * Find font #n. */ static void change_font(n) unsigned long n; { register struct tn *tnp; if (n < currinf.tn_table_len) currinf.fontp = currinf.tn_table[n]; else { currinf.fontp = NULL; for (tnp = currinf.tn_head; tnp != NULL; tnp = tnp->next) if (tnp->TeXnumber == n) { currinf.fontp = tnp->fontp; break; } } if (currinf.fontp == NULL) tell_oops("non-existent font #%d", n); maxchar = currinf.fontp->maxchar; currinf.set_char_p = currinf.fontp->set_char_p; } /* * Open a font file. */ static void open_font_file(fontp) struct font *fontp; { if (fontp->file == NULL) { fontp->file = xfopen(fontp->filename, OPEN_MODE); if (fontp->file == NULL) oops("Font file disappeared: %s", fontp->filename); } } /* * Read special string. */ static char * read_special(nbytes) long nbytes; { static char *spcl = NULL; static long spcl_len = -1; char *p; if (spcl_len < nbytes) { if (spcl != NULL) free(spcl); spcl = xmalloc((unsigned) nbytes + 1, "special"); spcl_len = nbytes; } p = spcl; for (;;) { int i = currinf.end - currinf.pos; if (i > nbytes) i = nbytes; bcopy((char *) currinf.pos, p, i); currinf.pos += i; p += i; nbytes -= i; if (nbytes == 0) break; (void) xxone(); --(currinf.pos); } *p = '\0'; return spcl; } #if PS /* * Size of page interval for "Scanning pages xx-xx" message. */ #ifndef REPORT_INCR #define REPORT_INCR 50 #endif /* * Table used for scanning. If >= 0, then skip that many bytes. * -1 means end of page, -2 means special, -3 means FNTDEF, * -4 means unrecognizable, and -5 means doesn't belong here. */ static _Xsigned char scantable[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* chars 0 - 127 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,-4, /* SET1,- (128,129) */ /* -,-,SETRULE,PUT1,-,-,-,PUTRULE,NOP,BOP (130-139) */ -4,-4,8,1,-4,-4,-4,8,0,44, -1,0,0,1,2,3,4,0,1,2, /* EOP,PUSH,POP,RIGHT1-4,W0-2 (140-149) */ 3,4,0,1,2,3,4,1,2,3, /* W3-4,X0-4,DOWN1-3 (150-159) */ 4,0,1,2,3,4,0,1,2,3, /* DOWN4,Y0-4,Z0-3 (160-169) */ 4, /* Z4 (170) */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* change font 171 - 234 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,2,3,4,-2, /* FNT1-4,XXX1 (235-239) */ /* XXX2-4,FNTDEF1-4,PRE,POST,POSTPOST (240-249) */ -2,-2,-2,-3,-3,-3,-3,-5,-5,-5, 0,0,-4,-4,-4,-4}; /* SREFL,EREFL,-,-,-,- (250-255) */ /* * Prescanning routine for dvi file. This looks for specials like * `header=' and `!'. */ static void prescan() { ubyte ch; _Xsigned char n; long a; int nextreportpage; char scanmsg[40]; if (!resource._postscript) { scanned_page = total_pages; return; } nextreportpage = scanned_page; ++scanned_page; (void) lseek(fileno(dvi_file), page_offset[scanned_page], SEEK_SET); currinf.pos = currinf.end = dvi_buffer; for (;;) { if (debug & DBG_PS) Printf("Scanning page %d\n", scanned_page); if (scanned_page > nextreportpage) { nextreportpage += REPORT_INCR; if (nextreportpage > current_page) nextreportpage = current_page; #ifndef VMS Sprintf(scanmsg, "Scanning pages %d-%d", scanned_page + pageno_correct, nextreportpage + pageno_correct); showmessage(scanmsg); XFlush(DISP); #endif } for (;;) { ch = xone(); n = scantable[ch]; if (n >= 0) while (--n >= 0) (void) xone(); else if (n == -1) break; /* end of page */ else switch (n) { case -2: /* special */ a = xnum(ch - XXX1 + 1); if (a > 0) scan_special(read_special(a)); break; case -3: /* FNTDEF */ xskip((long) (12 + ch - FNTDEF1 + 1)); ch = xone(); xskip((long) ch + (long) xone()); break; case -4: /* unrecognizable */ tell_oops("unknown op-code %d", ch); break; case -5: /* doesn't belong */ tell_oops("shouldn't happen: %s encountered", dvi_table2[ch - (FNTNUM0 + 64)]); break; } } if (scanned_page >= current_page) break; ++scanned_page; } scanned_page_bak = scanned_page; XClearWindow(DISP, mane.win); psp.endheader(); } #endif /* PS */ /* * Routines to print characters. */ #ifndef TEXXET #define ERRVAL 0L #else #define ERRVAL #endif #ifndef TEXXET long set_char(ch) #else void set_char(cmd, ch) wide_ubyte cmd; #endif wide_ubyte ch; { register struct glyph *g; #ifdef TEXXET long dvi_h_sav; #endif if (ch > maxchar) realloc_font(currinf.fontp, WIDENINT ch); if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) { if (g->addr == 0) { if (!hush_chars) Fprintf(stderr, "Character %d not defined in font %s\n", ch, currinf.fontp->fontname); g->addr = -1; return ERRVAL; } if (g->addr == -1) return ERRVAL; /* previously flagged missing char */ open_font_file(currinf.fontp); Fseek(currinf.fontp->file, g->addr, 0); (*currinf.fontp->read_char)(currinf.fontp, ch); if (debug & DBG_BITMAP) print_char((ubyte) ch, g); currinf.fontp->timestamp = ++current_timestamp; } #ifdef TEXXET dvi_h_sav = DVI_H; if (currinf.dir < 0) DVI_H -= g->dvi_adv; if (scan_frame == NULL) { #endif if (shrink_factor == 1) put_bitmap(&g->bitmap, PXL_H - g->x, PXL_V - g->y); else { #ifdef GREY if (use_grey) { if (g->pixmap2 == NULL) { shrink_glyph_grey(g); } put_image(g->image2, PXL_H - g->x2, PXL_V - g->y2); } else { if (g->bitmap2.bits == NULL) { shrink_glyph(g); } put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2); } #else if (g->bitmap2.bits == NULL) { shrink_glyph(g); } put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2); #endif } #ifndef TEXXET return g->dvi_adv; #else } if (cmd == PUT1) DVI_H = dvi_h_sav; else if (currinf.dir > 0) DVI_H += g->dvi_adv; #endif } /* ARGSUSED */ #if NeedFunctionPrototypes #ifndef TEXXET static long set_empty_char(wide_ubyte ch) #else static void set_empty_char(wide_ubyte cmd, wide_ubyte ch) #endif /* TEXXET */ #else /* !NeedFunctionPrototypes */ #ifndef TEXXET static long set_empty_char(ch) #else static void set_empty_char(cmd, ch) wide_ubyte cmd; #endif /* TEXXET */ wide_ubyte ch; #endif /* NeedFunctionPrototypes */ { #ifndef TEXXET return 0; #else return; #endif } #ifndef TEXXET long load_n_set_char(ch) #else void load_n_set_char(cmd, ch) wide_ubyte cmd; #endif wide_ubyte ch; { if (load_font(currinf.fontp)) { /* if not found */ Fputs("Character(s) will be left blank.\n", stderr); currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char; #ifndef TEXXET return 0; #else return; #endif } maxchar = currinf.fontp->maxchar; currinf.set_char_p = currinf.fontp->set_char_p; #ifndef TEXXET return (*currinf.set_char_p)(ch); #else (*currinf.set_char_p)(cmd, ch); return; #endif } #ifndef TEXXET long set_vf_char(ch) #else void set_vf_char(cmd, ch) wide_ubyte cmd; #endif wide_ubyte ch; { register struct macro *m; struct drawinf oldinfo; ubyte oldmaxchar; static ubyte c; #ifdef TEXXET long dvi_h_sav; #endif if (ch > maxchar) realloc_virtual_font(currinf.fontp, ch); if ((m = &currinf.fontp->macro[ch])->pos == NULL) { if (!hush_chars) Fprintf(stderr, "Character %d not defined in font %s\n", ch, currinf.fontp->fontname); m->pos = m->end = &c; return ERRVAL; } #ifdef TEXXET dvi_h_sav = DVI_H; if (currinf.dir < 0) DVI_H -= m->dvi_adv; if (scan_frame == NULL) { #endif oldinfo = currinf; oldmaxchar = maxchar; WW = XX = YY = ZZ = 0; currinf.tn_table_len = VFTABLELEN; currinf.tn_table = currinf.fontp->vf_table; currinf.tn_head = currinf.fontp->vf_chain; currinf.pos = m->pos; currinf.end = m->end; currinf.virtual = currinf.fontp; draw_part(current_frame, currinf.fontp->dimconv); if (currinf.pos != currinf.end + 1) tell_oops("virtual character macro does not end correctly"); currinf = oldinfo; maxchar = oldmaxchar; #ifndef TEXXET return m->dvi_adv; #else } if (cmd == PUT1) DVI_H = dvi_h_sav; else if (currinf.dir > 0) DVI_H += m->dvi_adv; #endif } #if NeedFunctionPrototypes #ifndef TEXXET static long set_no_char(wide_ubyte ch) #else static void set_no_char(wide_ubyte cmd, wide_ubyte ch) #endif /* TEXXET */ #else /* !NeedFunctionPrototypes */ #ifndef TEXXET static long set_no_char(ch) #else static void set_no_char(cmd, ch) ubyte cmd; #endif /* TEXXET */ wide_ubyte ch; #endif /* NeedFunctionPrototypes */ { if (currinf.virtual) { currinf.fontp = currinf.virtual->first_font; if (currinf.fontp != NULL) { maxchar = currinf.fontp->maxchar; currinf.set_char_p = currinf.fontp->set_char_p; #ifndef TEXXET return (*currinf.set_char_p)(ch); #else (*currinf.set_char_p)(cmd, ch); return; #endif } } tell_oops("attempt to set character of unknown font"); /* NOTREACHED */ } /* * Set rule. Arguments are coordinates of lower left corner. */ static void set_rule(h, w) int h, w; { #ifndef TEXXET put_rule(PXL_H, PXL_V - h + 1, (unsigned int) w, (unsigned int) h); #else put_rule(PXL_H - (currinf.dir < 0 ? w - 1 : 0), PXL_V - h + 1, (unsigned int) w, (unsigned int) h); #endif } #define xspell_conv(n) spell_conv0(n, current_dimconv) static void draw_part(minframe, current_dimconv) struct frame *minframe; double current_dimconv; { ubyte ch; #ifdef TEXXET struct drawinf oldinfo; ubyte oldmaxchar; off_t file_pos; int refl_count; #endif currinf.fontp = NULL; currinf.set_char_p = set_no_char; #ifdef TEXXET currinf.dir = 1; scan_frame = NULL; /* indicates we're not scanning */ #endif for (;;) { ch = xone(); if (debug & DBG_DVI) print_dvi(ch); if (ch <= (ubyte) (SETCHAR0 + 127)) #ifndef TEXXET DVI_H += (*currinf.set_char_p)(ch); #else (*currinf.set_char_p)(ch, ch); #endif else if (FNTNUM0 <= ch && ch <= (ubyte) (FNTNUM0 + 63)) change_font((unsigned long) (ch - FNTNUM0)); else { long a, b; switch (ch) { case SET1: case PUT1: #ifndef TEXXET a = (*currinf.set_char_p)(xone()); if (ch != PUT1) DVI_H += a; #else (*currinf.set_char_p)(ch, xone()); #endif break; case SETRULE: /* Be careful, dvicopy outputs rules with height = 0x80000000. We don't want any SIGFPE here. */ a = xsfour(); b = xspell_conv(xsfour()); #ifndef TEXXET if (a > 0 && b > 0) #else if (a > 0 && b > 0 && scan_frame == NULL) #endif set_rule(pixel_round(xspell_conv(a)), pixel_round(b)); DVI_H += DIR * b; break; case PUTRULE: a = xspell_conv(xsfour()); b = xspell_conv(xsfour()); #ifndef TEXXET if (a > 0 && b > 0) #else if (a > 0 && b > 0 && scan_frame == NULL) #endif set_rule(pixel_round(a), pixel_round(b)); break; case NOP: break; case BOP: xskip((long) 11 * 4); DVI_H = OFFSET_X; DVI_V = OFFSET_Y; PXL_V = pixel_conv(DVI_V); WW = XX = YY = ZZ = 0; break; case EOP: if (current_frame != minframe) tell_oops("stack not empty at EOP"); return; case PUSH: if (current_frame->next == NULL) { struct frame *newp = (struct frame *) xmalloc(sizeof(struct frame), "stack frame"); current_frame->next = newp; newp->prev = current_frame; newp->next = NULL; } current_frame = current_frame->next; current_frame->data = currinf.data; break; case POP: if (current_frame == minframe) tell_oops("more POPs than PUSHes"); currinf.data = current_frame->data; current_frame = current_frame->prev; break; #ifdef TEXXET case SREFL: if (scan_frame == NULL) { /* we're not scanning: save some info. */ oldinfo = currinf; oldmaxchar = maxchar; if (!currinf.virtual) file_pos = xtell(currinf.pos); scan_frame = current_frame; /* now we're scanning */ refl_count = 0; break; } /* we are scanning */ if (current_frame == scan_frame) ++refl_count; break; case EREFL: if (scan_frame != NULL) { /* if we're scanning */ if (current_frame == scan_frame && --refl_count < 0) { /* we've hit the end of our scan */ scan_frame = NULL; /* first: push */ if (current_frame->next == NULL) { struct frame *newp = (struct frame *) xmalloc(sizeof(struct frame), "stack frame"); current_frame->next = newp; newp->prev = current_frame; newp->next = NULL; } current_frame = current_frame->next; current_frame->data = currinf.data; /* next: restore old file position, XX, etc. */ if (!currinf.virtual) { off_t bgn_pos = xtell(dvi_buffer); if (file_pos >= bgn_pos) { oldinfo.pos = dvi_buffer + (file_pos - bgn_pos); oldinfo.end = currinf.end; } else { (void) lseek(fileno(dvi_file), file_pos, SEEK_SET); oldinfo.pos = oldinfo.end; } } currinf = oldinfo; maxchar = oldmaxchar; /* and then: recover position info. */ DVI_H = current_frame->data.dvi_h; DVI_V = current_frame->data.dvi_v; PXL_V = current_frame->data.pxl_v; /* and finally, reverse direction */ currinf.dir = -currinf.dir; } break; } /* we're not scanning, */ /* so just reverse direction and then pop */ currinf.dir = -currinf.dir; currinf.data = current_frame->data; current_frame = current_frame->prev; break; #endif /* TEXXET */ case RIGHT1: case RIGHT2: case RIGHT3: case RIGHT4: DVI_H += DIR * xspell_conv(xsnum(ch - RIGHT1 + 1)); break; case W1: case W2: case W3: case W4: WW = xspell_conv(xsnum(ch - W0)); case W0: DVI_H += DIR * WW; break; case X1: case X2: case X3: case X4: XX = xspell_conv(xsnum(ch - X0)); case X0: DVI_H += DIR * XX; break; case DOWN1: case DOWN2: case DOWN3: case DOWN4: DVI_V += xspell_conv(xsnum(ch - DOWN1 + 1)); PXL_V = pixel_conv(DVI_V); break; case Y1mM~XDVI.BAK  [XDVI]DVI_DRAW.C;2M<@9: case Y2: case Y3: case Y4: YY = xspell_conv(xsnum(ch - Y0)); case Y0: DVI_V += YY; PXL_V = pixel_conv(DVI_V); break; case Z1: case Z2: case Z3: case Z4: ZZ = xspell_conv(xsnum(ch - Z0)); case Z0: DVI_V += ZZ; PXL_V = pixel_conv(DVI_V); break; case FNT1: case FNT2: case FNT3: case FNT4: change_font(xnum(ch - FNT1 + 1)); break; case XXX1: case XXX2: case XXX3: case XXX4: a = xnum(ch - XXX1 + 1); if (a > 0) applicationDoSpecial(read_special(a)); break; case FNTDEF1: case FNTDEF2: case FNTDEF3: case FNTDEF4: xskip((long) (12 + ch - FNTDEF1 + 1)); xskip((long) xone() + (long) xone()); break; #ifndef TEXXET case SREFL: case EREFL: #endif case PRE: case POST: case POSTPOST: tell_oops("shouldn't happen: %s encountered", dvi_table2[ch - (FNTNUM0 + 64)]); break; default: tell_oops("unknown op-code %d", ch); } /* end switch*/ } /* end else (ch not a SETCHAR or FNTNUM) */ } /* end for */ } #undef xspell_conv void draw_page() { /* Check for changes in dvi file. */ if (!check_dvi_file()) return; #if PS if (scanned_page < current_page) prescan(); #endif put_border(-currwin.base_x, -currwin.base_y, ROUNDUP(unshrunk_paper_w, shrink_factor) + 2, ROUNDUP(unshrunk_paper_h, shrink_factor) + 2, highGC); (void) lseek(fileno(dvi_file), page_offset[current_page], SEEK_SET); bzero((char *) &currinf.data, sizeof(currinf.data)); currinf.tn_table_len = TNTABLELEN; currinf.tn_table = tn_table; currinf.tn_head = tn_head; currinf.pos = currinf.end = dvi_buffer; currinf.virtual = NULL; psfig_begun = False; draw_part(current_frame = &frame0, dimconv); #if PS psp.endpage(); #endif } *[XDVI]DVI_INIT.C;3+,eY.$/ 4M$$0- 0@123KPWO%56aSm7jSm8꟨]o9GHJ/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTE: * xdvi is based on prior work, as noted in the modification history * in xdvi.c. */ #include "xdvi.h" #include "dvi.h" #include #ifdef X_NOT_STDC_ENV char *realBloc(); #endif #if defined(macII) && !__STDC__ /* stdlib.h doesn't define these */ char *realloc(); #endif /* macII */ #define PK_PRE 247 #define PK_ID 89 #define PK_MAGIC (PK_PRE << 8) + PK_ID #define GF_PRE 247 #define GF_ID 131 #define GF_MAGIC (GF_PRE << 8) + GF_ID #define VF_PRE 247 #define VF_ID_BYTE 202 #define VF_MAGIC (VF_PRE << 8) + VF_ID_BYTE #define dvi_oops(str) (dvi_oops_msg = (str), longjmp(dvi_env, 1)) static struct stat fstatbuf; static Boolean font_not_found; /* * DVI preamble and postamble information. */ static char job_id[300]; static long numerator, denominator; /* * Offset in DVI file of last page, set in read_postamble(). */ static long last_page_offset; /* * free_vf_chain frees the vf_chain structure. */ static void free_vf_chain(tnp) struct tn *tnp; { while (tnp != NULL) { register struct tn *tnp1 = tnp->next; free((char *) tnp); tnp = tnp1; } } /* * Release all shrunken bitmaps for all fonts. */ void reset_fonts() { register struct font *f; register struct glyph *g; for (f = font_head; f != NULL; f = f->next) if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL)) for (g = f->glyph; g <= f->glyph + f->maxchar; ++g) { if (g->bitmap2.bits) { free(g->bitmap2.bits); g->bitmap2.bits = NULL; } #ifdef GREY if (g->pixmap2) { XDestroyImage(g->image2); g->pixmap2 = NULL; } #endif } } /* * realloc_font allocates the font structure to contain (newsize + 1) * characters. */ void realloc_font(fontp, newsize) struct font *fontp; wide_ubyte newsize; { struct glyph *glyph; glyph = fontp->glyph = (struct glyph *) realloc((char *) fontp->glyph, ((unsigned int) newsize + 1) * sizeof(struct glyph)); if (glyph == NULL) oops("! Cannot reallocate space for glyph array."); if (newsize > fontp->maxchar) bzero((char *) (glyph + fontp->maxchar + 1), (int) (newsize - fontp->maxchar) * sizeof(struct glyph)); maxchar = fontp->maxchar = newsize; } /* * realloc_virtual_font does the same thing for virtual fonts. */ void realloc_virtual_font(fontp, newsize) struct font *fontp; wide_ubyte newsize; { struct macro *macro; macro = fontp->macro = (struct macro *) realloc((char *) fontp->macro, ((unsigned int) newsize + 1) * sizeof(struct macro)); if (macro == NULL) oops("! Cannot reallocate space for macro array."); if (newsize > fontp->maxchar) bzero((char *) (macro + fontp->maxchar + 1), (int) (newsize - fontp->maxchar) * sizeof(struct macro)); maxchar = fontp->maxchar = newsize; } /* * load_font locates the raster file and reads the index of characters, * plus whatever other preprocessing is done (depending on the format). */ Boolean load_font(fontp) struct font *fontp; { double fsize = fontp->fsize; int dpi = fsize + 0.5; char *font_found; int size_found; int magic; Boolean hushcs = hush_chk; fontp->flags |= FONT_LOADED; fontp->file = font_open(fontp->fontname, &font_found, fsize, &size_found, fontp->magstepval, &fontp->filename); if (fontp->file == NULL) { Fprintf(stderr, "%s: can't find font %s.\n", prog, fontp->fontname); return True; } --n_files_left; if (font_found != NULL) { Fprintf(stderr, "%s: can't find font %s; using %s instead at %d dpi.\n", prog, fontp->fontname, font_found, dpi); free(fontp->fontname); fontp->fontname = font_found; hushcs = True; } #ifndef FONT5 else if (size_found > (int) (1.002 * fsize + 0.5) || size_found < (int) (0.998 * fsize + 0.5)) Fprintf(stderr, "%s: can't find font %s at %d dpi; using %d dpi instead.\n", prog, fontp->fontname, dpi, size_found); fontp->fsize = size_found; #else else if (size_found > (int) (5 * 1.002 * fsize + 0.5) || size_found < (int) (5 * 0.998 * fsize + 0.5)) Fprintf(stderr, "%s: can't find font %s at %d dpi; using %d dpi instead.\n", prog, fontp->fontname, dpi, (size_found + 2) / 5); fontp->fsize = size_found / 5; #endif fontp->timestamp = ++current_timestamp; fontp->maxchar = maxchar = 255; fontp->set_char_p = set_char; magic = two(fontp->file); #ifdef USE_PK if (magic == PK_MAGIC) read_PK_index(fontp, WIDENINT hushcs); else #endif #ifdef USE_GF if (magic == GF_MAGIC) read_GF_index(fontp, WIDENINT hushcs); else #endif if (magic == VF_MAGIC) read_VF_index(fontp, WIDENINT hushcs); else oops("Cannot recognize format for font file %s", fontp->filename); if (fontp->flags & FONT_VIRTUAL) { while (maxchar > 0 && fontp->macro[maxchar].pos == NULL) --maxchar; if (maxchar < 255) realloc_virtual_font(fontp, WIDENINT maxchar); } else { while (maxchar > 0 && fontp->glyph[maxchar].addr == 0) --maxchar; if (maxchar < 255) realloc_font(fontp, WIDENINT maxchar); } return False; } /* * MAGSTEPVALUE - If the given magnification is close to a \magstep * or a \magstephalf, then return twice the number of \magsteps. * Otherwise return NOMAGSTP. */ #define NOMAGSTP (-29999) #define NOBUILD 29999 static int magstepvalue(mag) float *mag; { int m = 0; double fmag = *mag; double xmag = pixels_per_inch; float margin = fmag * 0.002; if (fmag < pixels_per_inch) for (;;) { if (xmag - fmag < margin && -(xmag - fmag) < margin) { *mag = xmag; return m; } if (xmag < fmag) break; xmag *= 0.9128709292; --m; } else for (;;) { if (xmag - fmag < margin && -(xmag - fmag) < margin) { *mag = xmag; return m; } if (xmag > fmag) break; xmag *= 1.095445115; ++m; } return NOMAGSTP; } /* * reuse_font recursively sets the flags for font structures being reused. */ static void reuse_font(fontp) struct font *fontp; { struct font **fp; struct tn *tnp; if (fontp->flags & FONT_IN_USE) return; fontp->flags |= FONT_IN_USE; if (list_fonts) Printf("(reusing) %s at %d dpi\n", fontp->fontname, (int) (fontp->fsize + 0.5)); if (fontp->flags & FONT_VIRTUAL) { for (fp = fontp->vf_table; fp < fontp->vf_table + VFTABLELEN; ++fp) if (*fp != NULL) reuse_font(*fp); for (tnp = fontp->vf_chain; tnp != NULL; tnp = tnp->next) reuse_font(tnp->fontp); } } /* * define_font reads the rest of the fntdef command and then reads in * the specified pixel file, adding it to the global linked-list holding * all of the fonts used in the job. */ struct font * define_font(file, cmnd, vfparent, tntable, tn_table_len, tn_headpp) FILE *file; wide_ubyte cmnd; struct font *vfparent; /* vf parent of this font, or NULL */ struct font **tntable; /* table for low TeXnumbers */ unsigned int tn_table_len; /* length of table for TeXnumbers */ struct tn **tn_headpp; /* addr of head of list of TeXnumbers */ { int TeXnumber; struct font *fontp; float fsize; double scale_dimconv; long checksum; int scale; int design; int magstepval; int len; char *fontname; int size; TeXnumber = num(file, (int) cmnd - FNTDEF1 + 1); checksum = four(file); scale = four(file); design = four(file); len = one(file); len += one(file); /* sequence point in the middle */ fontname = xmalloc((unsigned) len + 1, "font name"); Fread(fontname, sizeof(char), len, file); fontname[len] = '\0'; if(debug & DBG_PK) Printf("Define font \"%s\" scale=%d design=%d\n", fontname, scale, design); if (vfparent == NULL) { fsize = 0.001 * scale / design * magnification * pixels_per_inch; scale_dimconv = dimconv; } else { /* * The scaled size is given in units of vfparent->scale * 2 ** -20 * SPELL units, so we convert it into SPELL units by multiplying by * vfparent->dimconv. * The design size is given in units of 2 ** -20 pt, so we convert * into SPELL units by multiplying by * (pixels_per_inch * 2**16) / (72.27 * 2**20). */ fsize = (72.27 * (1<<4)) * vfparent->dimconv * scale / design; scale_dimconv = vfparent->dimconv; } magstepval = magstepvalue(&fsize); #ifndef FONT5 size = fsize + 0.5; #else size = 5 * fsize + 0.5; #endif /* * reuse font if possible */ for (fontp = font_head;; fontp = fontp->next) { if (fontp == NULL) { /* if font doesn't exist yet */ if (list_fonts) Printf("%s at %d dpi\n", fontname, (int) (fsize + 0.5)); fontp = (struct font *) xmalloc((unsigned) sizeof(struct font), "font structure"); fontp->fontname = fontname; fontp->fsize = fsize; fontp->magstepval = magstepval; fontp->file = NULL; /* needed if it's a virtual font */ fontp->checksum = checksum; fontp->flags = FONT_IN_USE; fontp->dimconv = scale * scale_dimconv / (1<<20); fontp->set_char_p = load_n_set_char; if (vfparent == NULL) font_not_found |= load_font(fontp); fontp->next = font_head; font_head = fontp; break; } if (strcmp(fontname, fontp->fontname) == 0 #ifndef FONT5 && size == (int) (fontp->fsize + 0.5)) { #else && size == (int) (5 * fontp->fsize + 0.5)) { #endif /* if font already in use */ reuse_font(fontp); free(fontname); break; } } if (TeXnumber < tn_table_len) tntable[TeXnumber] = fontp; else { register struct tn *tnp; tnp = (struct tn *) xmalloc((unsigned) sizeof(struct tn), "TeXnumber structure"); tnp->next = *tn_headpp; *tn_headpp = tnp; tnp->TeXnumber = TeXnumber; tnp->fontp = fontp; } return fontp; } /* * process_preamble reads the information in the preamble and stores * it into global variables for later use. */ static void process_preamble() { ubyte k; if (one(dvi_file) != PRE) dvi_oops("Not a DVI file"); if (one(dvi_file) != 2) dvi_oops("Wrong version of DVI output for this program"); numerator = four(dvi_file); denominator = four(dvi_file); magnification = four(dvi_file); dimconv = (((double) numerator * magnification) / ((double) denominator * 1000.)); dimconv = dimconv * (((long) pixels_per_inch)<<16) / 254000; tpic_conv = pixels_per_inch * magnification / 1000000.0; k = one(dvi_file); Fread(job_id, sizeof(char), (int) k, dvi_file); job_id[k] = '\0'; } /* * find_postamble locates the beginning of the postamble * and leaves the file ready to start reading at that location. */ #define TMPSIZ 516 /* 4 trailer bytes + 512 junk bytes allowed */ static void find_postamble() { long pos; ubyte temp[TMPSIZ]; ubyte *p; ubyte *p1; ubyte byte; Fseek(dvi_file, (long) 0, 2); pos = ftell(dvi_file) - TMPSIZ; if (pos < 0) pos = 0; Fseek(dvi_file, pos, 0); p = temp + fread((char *) temp, sizeof(char), TMPSIZ, dvi_file); for (;;) { p1 = p; while (p1 > temp && *(--p1) != TRAILER) ; p = p1; while (p > temp && *(--p) == TRAILER) ; if (p <= p1 - 4) break; /* found 4 TRAILER bytes */ if (p <= temp) dvi_oops("DVI file corrupted"); } pos += p - temp; byte = *p; while (byte == TRAILER) { Fseek(dvi_file, --pos, 0); byte = one(dvi_file); } if (byte != 2) dvi_oops("Wrong version of DVI output for this program"); Fseek(dvi_file, pos - 4, 0); Fseek(dvi_file, sfour(dvi_file), 0); } /* * read_postamble reads the information in the postamble, * storing it into global variables. * It also takes care of reading in all of the pixel files for the fonts * used in the job. */ static void read_postamble() { ubyte cmnd; struct font *fontp; struct font **fontpp; if (one(dvi_file) != POST) dvi_oops("Postamble doesn't begin with POST"); last_page_offset = four(dvi_file); if (numerator != four(dvi_file) || denominator != four(dvi_file) || magnification != four(dvi_file)) dvi_oops("Postamble doesn't match preamble"); /* read largest box height and width */ unshrunk_page_h = (spell_conv(sfour(dvi_file)) >> 16) + offset_y; if (unshrunk_page_h < unshrunk_paper_h) unshrunk_page_h = unshrunk_paper_h; unshrunk_page_w = (spell_conv(sfour(dvi_file)) >> 16) + offset_x; if (unshrunk_page_w < unshrunk_paper_w) unshrunk_page_w = unshrunk_paper_w; (void) two(dvi_file); /* max stack size */ total_pages = two(dvi_file); font_not_found = False; while ((cmnd = one(dvi_file)) >= FNTDEF1 && cmnd <= FNTDEF4) (void) define_font(dvi_file, cmnd, (struct font *) NULL, tn_table, TNTABLELEN, &tn_head); if (cmnd != POSTPOST) dvi_oops("Non-fntdef command found in postamble"); if (font_not_found) dvi_oops("Not all pixel files were found"); /* * free up fonts no longer in use */ fontpp = &font_head; while ((fontp = *fontpp) != NULL) if (fontp->flags & FONT_IN_USE) fontpp = &fontp->next; else { if (debug & DBG_PK) Printf("Discarding font \"%s\" at %d dpi\n", fontp->fontname, (int) (fontp->fsize + 0.5)); *fontpp = fontp->next; /* remove from list */ free(fontp->fontname); if (fontp->flags & FONT_LOADED) { if (fontp->file != NULL) { Fclose(fontp->file); ++n_files_left; } free(fontp->filename); if (fontp->flags & FONT_VIRTUAL) { register struct macro *m; for (m = fontp->macro; m <= fontp->macro + fontp->maxchar; ++m) if (m->free_me) free((char *) m->pos); free((char *) fontp->macro); free((char *) fontp->vf_table); free_vf_chain(fontp->vf_chain); } else { register struct glyph *g; for (g = fontp->glyph; g <= fontp->glyph + fontp->maxchar; ++g) { if (g->bitmap.bits != NULL) free(g->bitmap.bits); if (g->bitmap2.bits != NULL) free(g->bitmap2.bits); #ifdef GREY if (g->pixmap2 != NULL) XDestroyImage(g->image2); #endif } free((char *) fontp->glyph); } free((char *) fontp); } } } static void prepare_pages() { int i; page_offset = (long *) xmalloc((unsigned) total_pages * sizeof(long), "page directory"); i = total_pages; page_offset[--i] = last_page_offset; Fseek(dvi_file, last_page_offset, 0); /* * Follow back pointers through pages in the DVI file, * storing the offsets in the page_offset table. */ while (i > 0) { Fseek(dvi_file, (long) (1+4+(9*4)), 1); Fseek(dvi_file, page_offset[--i] = four(dvi_file), 0); } } void init_page() { page_w = ROUNDUP(unshrunk_page_w, mane.shrinkfactor) + 2; page_h = ROUNDUP(unshrunk_page_h, mane.shrinkfactor) + 2; } #ifndef S_ISDIR #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* * init_dvi_file is the main subroutine for reading the startup * information from the dvi file. Returns True on success. */ static Boolean init_dvi_file() { (void) fstat(fileno(dvi_file), &fstatbuf); if (S_ISDIR(fstatbuf.st_mode)) return False; dvi_time = fstatbuf.st_mtime; process_preamble(); find_postamble(); read_postamble(); prepare_pages(); init_page(); if (current_page >= total_pages) current_page = total_pages - 1; hush_spec_now = hush_spec; #if PS ps_newdoc(); #endif return True; } /** ** open_dvi_file opens the dvi file and calls init_dvi_file() to ** initialize it. **/ void open_dvi_file() { int n; char *file; if (setjmp(dvi_env)) oops(dvi_oops_msg); n = strlen(dvi_name); file = dvi_name; /* * Try foo.dvi before foo, in case there's an executable foo with * documentation foo.tex. Unless it already ends with ".dvi". */ if (n < sizeof(".dvi") || strcmp(dvi_name + n - sizeof(".dvi") + 1, ".dvi") != 0) { dvi_name = xmalloc((unsigned) n + sizeof(".dvi"), "dvi file name"); Strcpy(dvi_name, file); Strcat(dvi_name, ".dvi"); dvi_file = fopen(dvi_name, OPEN_MODE); if (dvi_file != NULL && init_dvi_file()) return; free(dvi_name); dvi_name = file; } /* Then try `foo', in case the user likes DVI files without `.dvi'. */ if ((dvi_file = fopen(dvi_name, OPEN_MODE)) == NULL || !init_dvi_file()) { perror(dvi_name); #if PS ps_destroy(); #endif exit(1); } } /** ** Check for changes in dvi file. **/ Boolean check_dvi_file() { struct font *fontp; if (dvi_file == NULL || fstat(fileno(dvi_file), &fstatbuf) != 0 || fstatbuf.st_mtime != dvi_time) { if (dvi_file) { Fclose(dvi_file); if (list_fonts) Putchar('\n'); } free((char *) page_offset); bzero((char *) tn_table, (int) sizeof(tn_table)); free_vf_chain(tn_head); tn_head = NULL; for (fontp = font_head; fontp != NULL; fontp = fontp->next) fontp->flags &= ~FONT_IN_USE; if ((dvi_file = fopen(dvi_name, OPEN_MODE)) == NULL || !init_dvi_file()) dvi_oops("Cannot reopen dvi file."); reconfig(); redraw_page(); return False; } return True; } *[XDVI]EVENTS.C;5+, #.N/ 4MNM- 0@123KPWOO56N~ig7 jg8¿]o9GHJ*/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTE: * xdvi is based on prior work, as noted in the modification history * in xdvi.c. */ #include #include "xdvi.h" /* Xlib and Xutil are already included */ #ifdef TOOLKIT #ifdef OLD_X11_TOOLKIT #include #else /* not OLD_X11_TOOLKIT */ #include #include #endif /* not OLD_X11_TOOLKIT */ #include /* needed for def. of XtNiconX */ #ifndef XtSpecificationRelease #define XtSpecificationRelease 0 #endif #if XtSpecificationRelease >= 4 #include #ifdef BUTTONS #include #endif #else /* XtSpecificationRelease < 4 */ #define XtPointer caddr_t #include #ifdef BUTTONS #include #endif #endif /* XtSpecificationRelease */ #else /* !TOOLKIT */ #ifndef VMS typedef int Position; #endif #define XtPending() XPending(DISP) #endif /* TOOLKIT */ #if HAS_SIGIO #include #ifndef FASYNC #undef HAS_SIGIO #define HAS_SIGIO 0 #endif #endif #ifndef X11HEIGHT #define X11HEIGHT 8 /* Height of server default font */ #endif #define MAGBORD 1 /* border size for magnifier */ /* * Command line flags. */ #define fore_Pixel resource._fore_Pixel #define back_Pixel resource._back_Pixel #ifdef TOOLKIT extern struct _resource resource; #define brdr_Pixel resource._brdr_Pixel #endif /* TOOLKIT */ #define clip_w mane.width #define clip_h mane.height static Position main_x, main_y; static Position mag_x, mag_y, new_mag_x, new_mag_y; static Boolean mag_moved = False; #ifdef TOOLKIT #ifdef BUTTONS static Widget line_widget, panel_widget; #endif static Widget x_bar, y_bar; /* horizontal and vertical scroll bars */ static Arg resize_args[] = { {XtNwidth, (XtArgVal) 0}, {XtNheight, (XtArgVal) 0}, }; #define XdviResizeWidget(widget, w, h) \ (resize_args[0].value = (XtArgVal) (w), \ resize_args[1].value = (XtArgVal) (h), \ XtSetValues(widget, resize_args, XtNumber(resize_args)) ) #ifdef BUTTONS static Arg resizable_on[] = { {XtNresizable, (XtArgVal) True}, }; static Arg resizable_off[] = { {XtNresizable, (XtArgVal) False}, }; static Arg line_args[] = { {XtNbackground, (XtArgVal) 0}, {XtNwidth, (XtArgVal) 1}, {XtNheight, (XtArgVal) 0}, {XtNfromHoriz, (XtArgVal) NULL}, {XtNborderWidth, (XtArgVal) 0}, {XtNtop, (XtArgVal) XtChainTop}, {XtNbottom, (XtArgVal) XtChainBottom}, {XtNleft, (XtArgVal) XtChainRight}, {XtNright, (XtArgVal) XtChainRight}, }; static Arg panel_args[] = { {XtNfromHoriz, (XtArgVal) NULL}, {XtNwidth, (XtArgVal) (XTRA_WID - 1)}, {XtNheight, (XtArgVal) 0}, {XtNborderWidth, (XtArgVal) 0}, {XtNtop, (XtArgVal) XtChainTop}, {XtNbottom, (XtArgVal) XtChainBottom}, {XtNleft, (XtArgVal) XtChainRight}, {XtNright, (XtArgVal) XtChainRight}, }; static struct { _Xconst char *label; _Xconst char *name; int closure; int y_pos; } command_table[] = { {"Quit", "quit", 'q', 50}, {"Shrink1", "sh1", 1 << 8 | 's', 150}, {"Shrink2", "sh2", 2 << 8 | 's', 200}, {"Shrink3", "sh3", 3 << 8 | 's', 250}, {"Shrink4", "sh4", 4 << 8 | 's', 300}, {"Page-10", "prev10", 10 << 8 | 'p', 400}, {"Page-5", "prev5", 5 << 8 | 'p', 450}, {"Prev", "prev", 'p', 500}, {"Next", "next", 'n', 600}, {"Page+5", "next5", 5 << 8 | 'n', 650}, {"Page+10", "next10", 10 << 8 | 'n', 700}, #if PS {"View PS", "postscript", 'v', 750}, #endif }; static void handle_command(); static XtCallbackRec command_call[] = { {handle_command, NULL}, {NULL, NULL}, }; static Arg command_args[] = { {XtNlabel, (XtArgVal) NULL}, {XtNx, (XtArgVal) 6}, {XtNy, (XtArgVal) 0}, {XtNwidth, (XtArgVal) 64}, {XtNheight, (XtArgVal) 30}, {XtNcallback, (XtArgVal) command_call}, }; void create_buttons(h) XtArgVal h; { int i; line_args[0].value = (XtArgVal) resource._hl_Pixel; line_args[2].value = h; line_args[3].value = (XtArgVal) vport_widget; line_widget = XtCreateManagedWidget("line", widgetClass, form_widget, line_args, XtNumber(line_args)); panel_args[0].value = (XtArgVal) line_widget; panel_args[2].value = h; panel_widget = XtCreateManagedWidget("panel", compositeWidgetClass, form_widget, panel_args, XtNumber(panel_args)); command_args[2].value = (XtArgVal) vport_widget; for (i = 0; i < XtNumber(command_table); ++i) { command_args[0].value = (XtArgVal) command_table[i].label; command_args[2].value = (XtArgVal) command_table[i].y_pos; command_call[0].closure = (XtPointer) &command_table[i].closure; (void) XtCreateManagedWidget(command_table[i].name, commandWidgetClass, panel_widget, command_args, XtNumber(command_args)); } } #endif /* BUTTONS */ #else /* !TOOLKIT */ static Window x_bar, y_bar; static int x_bgn, x_end, y_bgn, y_end; /* scrollbar positions */ #endif /* TOOLKIT */ /* * Mechanism to keep track of the magnifier window. The problems are, * (a) if the button is released while the window is being drawn, this * could cause an X error if we continue drawing in it after it is * destroyed, and * (b) creating and destroying the window too quickly confuses the window * manager, which is avoided by waiting for an expose event before * destroying it. */ static short alt_stat; /* 1 = wait for expose, */ /* -1 = destroy upon expose */ static Boolean alt_canit; /* stop drawing this window */ /* * Data for buffered events. */ static VOLATILE short event_freq = 70; static void can_exposures(), keystroke(); #ifdef GREY #define gamma resource._gamma void init_pix(warn) Boolean warn; { static int shrink_allocated_for = 0; static float oldgamma = 0.0; int i; if (gamma != oldgamma) { static Pixel plane_masks[4]; static Pixel pixel; XColor color, fc, bc; XGCValues values; if (!copy) /* allocate 4 color planes for 16 colors (for GXor drawing) */ if (oldgamma == 0.0 && !XAllocColorCells(DISP, DefaultColormapOfScreen(SCRN), False, plane_masks, 4, &pixel, 1)) copy = warn = True; /* get foreground and background RGB values for interpolating */ fc.pixel = fore_Pixel; XQueryColor(DISP, DefaultColormapOfScreen(SCRN), &fc); bc.pixel = back_Pixel; XQueryColor(DISP, DefaultColormapOfScreen(SCRN), &bc); for (i = 0; i < 16; ++i) { double pow(); double frac = gamma > 0 ? pow((double) i / 15, 1 / gamma) : 1 - pow((double) (15 - i) / 15, -gamma); color.red = frac * ((double) fc.red - bc.red) + bc.red; color.green = frac * ((double) fc.green - bc.green) + bc.green; color.blue = frac * ((double) fc.blue - bc.blue) + bc.blue; color.pixel = pixel; color.flags = DoRed | DoGreen | DoBlue; if (!copy) { if (i & 1) color.pixel |= plane_masks[0]; if (i & 2) color.pixel |= plane_masks[1]; if (i & 4) color.pixel |= plane_masks[2]; if (i & 8) color.pixel |= plane_masks[3]; XStoreColor(DISP, DefaultColormapOfScreen(SCRN), &color); palette[i] = color.pixel; } else { if (!XAllocColor(DISP, DefaultColormapOfScreen(SCRN), &color)) palette[i] = (i * 100 >= density * 15) ? fore_Pixel : back_Pixel; else palette[i] = color.pixel; } } /* Make sure fore_ and back_Pixel are a part of the palette */ fore_Pixel = palette[15]; back_Pixel = palette[0]; if (mane.win != (Window) 0) XSetWindowBackground(DISP, mane.win, palette[0]); #define MakeGC(fcn, fg, bg) (values.function = fcn, values.foreground=fg,\ values.background=bg,\ XCreateGC(DISP, RootWindowOfScreen(SCRN),\ GCFunction|GCForeground|GCBackground, &values)) foreGC = ruleGC = MakeGC(copy ? GXcopy : GXor, fore_Pixel, back_Pixel); foreGC2 = NULL; oldgamma = gamma; #ifndef VMS if (resource.copy == Maybe && copy && warn) Puts("Note: overstrike characters may be incorrect."); #endif } #undef MakeGC if (mane.shrinkfactor == 1) return; if (shrink_allocated_for < mane.shrinkfactor) { if (pixeltbl != NULL) free((char *) pixeltbl); pixeltbl = (Pixel *) xmalloc((unsigned) (mane.shrinkfactor * mane.shrinkfactor + 1) * sizeof(Pixel), "pixel table"); shrink_allocated_for = mane.shrinkfactor; } for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i) pixeltbl[i] = palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor) / (2 * mane.shrinkfactor * mane.shrinkfactor)]; } #endif /* GREY */ /* * Event-handling routines */ static void expose(windowrec, x, y, w, h) register struct WindowRec *windowrec; int x, y; unsigned int w, h; { if (windowrec->min_x > x) windowrec->min_x = x; if (windowrec->max_x < x + w) windowrec->max_x = x + w; if (windowrec->min_y > y) windowrec->min_y = y; if (windowrec->max_y < y + h) windowrec->max_y = y + h; } static void clearexpose(windowrec, x, y, w, h) struct WindowRec *windowrec; int x, y; unsigned int w, h; { XClearArea(DISP, windowrec->win, x, y, w, h, False); expose(windowrec, x, y, w, h); } static void scrollwindow(windowrec, x0, y0) register struct WindowRec *windowrec; int x0, y0; { int x, y; int x2 = 0, y2 = 0; int ww, hh; x = x0 - windowrec->base_x; y = y0 - windowrec->base_y; ww = windowrec->width - x; hh = windowrec->height - y; windowrec->base_x = x0; windowrec->base_y = y0; if (currwin.win == windowrec->win) { currwin.base_x = x0; currwin.base_y = y0; } windowrec->min_x -= x; if (windowrec->min_x < 0) windowrec->min_x = 0; windowrec->max_x -= x; if (windowrVR~XDVI.BAK # [XDVI]EVENTS.C;5MNZqpec->max_x > windowrec->width) windowrec->max_x = windowrec->width; windowrec->min_y -= y; if (windowrec->min_y < 0) windowrec->min_y = 0; windowrec->max_y -= y; if (windowrec->max_y > windowrec->height) windowrec->max_y = windowrec->height; if (x < 0) { x2 = -x; x = 0; ww = windowrec->width - x2; } if (y < 0) { y2 = -y; y = 0; hh = windowrec->height - y2; } if (ww <= 0 || hh <= 0) { XClearWindow(DISP, windowrec->win); psp.endheader(); windowrec->min_x = windowrec->min_y = 0; windowrec->max_x = windowrec->width; windowrec->max_y = windowrec->height; } else { XCopyArea(DISP, windowrec->win, windowrec->win, DefaultGCOfScreen(SCRN), x, y, (unsigned int) ww, (unsigned int) hh, x2, y2); if (x > 0) clearexpose(windowrec, ww, 0, (unsigned int) x, windowrec->height); if (x2 > 0) clearexpose(windowrec, 0, 0, (unsigned int) x2, windowrec->height); if (y > 0) clearexpose(windowrec, 0, hh, windowrec->width, (unsigned int) y); if (y2 > 0) clearexpose(windowrec, 0, 0, windowrec->width, (unsigned int) y2); } } #ifdef TOOLKIT /* * routines for X11 toolkit */ static Arg arg_wh[] = { {XtNwidth, (XtArgVal) &window_w}, {XtNheight, (XtArgVal) &window_h}, }; static Position window_x, window_y; static Arg arg_xy[] = { {XtNx, (XtArgVal) &window_x}, {XtNy, (XtArgVal) &window_y}, }; #define get_xy() XtGetValues(draw_widget, arg_xy, XtNumber(arg_xy)) #define mane_base_x 0 #define mane_base_y 0 static void home(scrl) Boolean scrl; { #if PS psp.interrupt(); #endif if (!scrl) XUnmapWindow(DISP, mane.win); get_xy(); if (x_bar != NULL) { register int coord = (page_w - clip_w) / 2; if (coord > home_x / mane.shrinkfactor) coord = home_x / mane.shrinkfactor; XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (window_x + coord)); } if (y_bar != NULL) { register int coord = (page_h - clip_h) / 2; if (coord > home_y / mane.shrinkfactor) coord = home_y / mane.shrinkfactor; XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) (window_y + coord)); } if (!scrl) { XMapWindow(DISP, mane.win); /* Wait for the server to catch up---this eliminates flicker. */ XSync(DISP, False); } } static Boolean resized = False; static void get_geom() { static Dimension new_clip_w, new_clip_h; static Arg arg_wh_clip[] = { {XtNwidth, (XtArgVal) &new_clip_w}, {XtNheight, (XtArgVal) &new_clip_h}, }; register int old_clip_w; XtGetValues(vport_widget, arg_wh, XtNumber(arg_wh)); XtGetValues(clip_widget, arg_wh_clip, XtNumber(arg_wh_clip)); /* Note: widgets may be destroyed but not forgotten */ x_bar = page_w <= new_clip_w ? NULL : XtNameToWidget(vport_widget, "horizontal"); y_bar = page_h <= new_clip_h ? NULL : XtNameToWidget(vport_widget, "vertical"); old_clip_w = clip_w; /* we need to do this because */ /* sizeof(Dimension) != sizeof(int) */ clip_w = new_clip_w; clip_h = new_clip_h; if (old_clip_w == 0) home(False); resized = False; } static void center(x, y) int x, y; { /* We use the clip widget here because it gives a more exact value. */ x -= clip_w/2; y -= clip_h/2; if (x_bar) XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) x); if (y_bar) XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) y); XWarpPointer(DISP, None, None, 0, 0, 0, 0, -x, -y); } /* * callback routines */ /*ARGSUSED*/ void handle_resize(widget, junk, event, cont) Widget widget; XtPointer junk; XEvent *event; Boolean *cont; /* unused */ { resized = True; } #ifdef BUTTONS /*ARGSUSED*/ static void handle_command(widget, client_data_p, call_data) Widget widget; XtPointer client_data_p; XtPointer call_data; { int client_data = * (int *) client_data_p; keystroke((client_data) & 0xff, (client_data) >> 8, ((client_data) >> 8) != 0, (XEvent *) NULL); } #endif /* BUTTONS */ void reconfig() { #ifdef BUTTONS XtSetValues(vport_widget, resizable_off, XtNumber(resizable_off)); #endif XdviResizeWidget(draw_widget, page_w, page_h); get_geom(); } #else /* !TOOLKIT */ /* * brute force scrollbar routines */ static void paint_x_bar() { register int new_x_bgn = mane.base_x * clip_w / page_w; register int new_x_end = (mane.base_x + clip_w) * clip_w / page_w; if (new_x_bgn >= x_end || x_bgn >= new_x_end) { /* no overlap */ XClearArea(DISP, x_bar, x_bgn, 1, x_end - x_bgn, BAR_WID, False); XFillRectangle(DISP, x_bar, ruleGC, new_x_bgn, 1, new_x_end - new_x_bgn, BAR_WID); } else { /* this stuff avoids flicker */ if (x_bgn < new_x_bgn) XClearArea(DISP, x_bar, x_bgn, 1, new_x_bgn - x_bgn, BAR_WID, False); else XFillRectangle(DISP, x_bar, ruleGC, new_x_bgn, 1, x_bgn - new_x_bgn, BAR_WID); if (new_x_end < x_end) XClearArea(DISP, x_bar, new_x_end, 1, x_end - new_x_end, BAR_WID, False); else XFillRectangle(DISP, x_bar, ruleGC, x_end, 1, new_x_end - x_end, BAR_WID); } x_bgn = new_x_bgn; x_end = new_x_end; } static void paint_y_bar() { register int new_y_bgn = mane.base_y * clip_h / page_h; register int new_y_end = (mane.base_y + clip_h) * clip_h / page_h; if (new_y_bgn >= y_end || y_bgn >= new_y_end) { /* no overlap */ XClearArea(DISP, y_bar, 1, y_bgn, BAR_WID, y_end - y_bgn, False); XFillRectangle(DISP, y_bar, ruleGC, 1, new_y_bgn, BAR_WID, new_y_end - new_y_bgn); } else { /* this stuff avoids flicker */ if (y_bgn < new_y_bgn) XClearArea(DISP, y_bar, 1, y_bgn, BAR_WID, new_y_bgn - y_bgn, False); else XFillRectangle(DISP, y_bar, ruleGC, 1, new_y_bgn, BAR_WID, y_bgn - new_y_bgn); if (new_y_end < y_end) XClearArea(DISP, y_bar, 1, new_y_end, BAR_WID, y_end - new_y_end, False); else XFillRectangle(DISP, y_bar, ruleGC, 1, y_end, BAR_WID, new_y_end - y_end); } y_bgn = new_y_bgn; y_end = new_y_end; } static void scrollmane(x, y) int x, y; { register int old_base_x = mane.base_x; register int old_base_y = mane.base_y; #if PS psp.interrupt(); #endif if (x > (int) (page_w - clip_w)) x = page_w - clip_w; if (x < 0) x = 0; if (y > (int) (page_h - clip_h)) y = page_h - clip_h; if (y < 0) y = 0; scrollwindow(&mane, x, y); if (old_base_x != mane.base_x && x_bar) paint_x_bar(); if (old_base_y != mane.base_y && y_bar) paint_y_bar(); } void reconfig() { int x_thick = 0; int y_thick = 0; /* determine existence of scrollbars */ if (window_w < page_w) x_thick = BAR_THICK; if (window_h - x_thick < page_h) y_thick = BAR_THICK; clip_w = window_w - y_thick; if (clip_w < page_w) x_thick = BAR_THICK; clip_h = window_h - x_thick; /* process drawing (clip) window */ if (mane.win == (Window) 0) { /* initial creation */ XWindowAttributes attrs; mane.win = XCreateSimpleWindow(DISP, top_level, y_thick, x_thick, (unsigned int) clip_w, (unsigned int) clip_h, 0, brdr_Pixel, back_Pixel); XSelectInput(DISP, mane.win, ExposureMask | ButtonPressMask | ButtonMotionMask | ButtonReleaseMask); (void) XGetWindowAttributes(DISP, mane.win, &attrs); backing_store = attrs.backing_store; XMapWindow(DISP, mane.win); } else XMoveResizeWindow(DISP, mane.win, y_thick, x_thick, clip_w, clip_h); /* process scroll bars */ if (x_thick) { if (x_bar) { XMoveResizeWindow(DISP, x_bar, y_thick - 1, -1, clip_w, BAR_THICK - 1); paint_x_bar(); } else { x_bar = XCreateSimpleWindow(DISP, top_level, y_thick - 1, -1, (unsigned int) clip_w, BAR_THICK - 1, 1, brdr_Pixel, back_Pixel); XSelectInput(DISP, x_bar, ExposureMask | ButtonPressMask | Button2MotionMask); XMapWindow(DISP, x_bar); } x_bgn = mane.base_x * clip_w / page_w; x_end = (mane.base_x + clip_w) * clip_w / page_w; } else if (x_bar) { XDestroyWindow(DISP, x_bar); x_bar = (Window) 0; } if (y_thick) { if (y_bar) { XMoveResizeWindow(DISP, y_bar, -1, x_thick - 1, BAR_THICK - 1, clip_h); paint_y_bar(); } else { y_bar = XCreateSimpleWindow(DISP, top_level, -1, x_thick - 1, BAR_THICK - 1, (unsigned int) clip_h, 1, brdr_Pixel, back_Pixel); XSelectInput(DISP, y_bar, ExposureMask | ButtonPressMask | Button2MotionMask); XMapWindow(DISP, y_bar); } y_bgn = mane.base_y * clip_h / page_h; y_end = (mane.base_y + clip_h) * clip_h / page_h; } else if (y_bar) { XDestroyWindow(DISP, y_bar); y_bar = (Window) 0; } } static void home(scrl) Boolean scrl; { int x = 0, y = 0; if (page_w > clip_w) { x = (page_w - clip_w) / 2; if (x > home_x / mane.shrinkfactor) x = home_x / mane.shrinkfactor; } if (page_h > clip_h) { y = (page_h - clip_h) / 2; if (y > home_y / mane.shrinkfactor) y = home_y / mane.shrinkfactor; } if (scrl) scrollmane(x, y); else { mane.base_x = x; mane.base_y = y; if (currwin.win == mane.win) { currwin.base_x = x; currwin.base_y = y; } if (x_bar) paint_x_bar(); if (y_bar) paint_y_bar(); } } #define get_xy() #define window_x 0 #define window_y 0 #define mane_base_x mane.base_x #define mane_base_y mane.base_y #endif /* TOOLKIT */ static void compute_mag_pos(xp, yp) int *xp, *yp; { register int t; t = mag_x + main_x - alt.width/2; if (t > WidthOfScreen(SCRN) - (int) alt.width - 2*MAGBORD) t = WidthOfScreen(SCRN) - (int) alt.width - 2*MAGBORD; if (t < 0) t = 0; *xp = t; t = mag_y + main_y - alt.height/2; if (t > HeightOfScreen(SCRN) - (int) alt.height - 2*MAGBORD) t = HeightOfScreen(SCRN) - (int) alt.height - 2*MAGBORD; if (t < 0) t = 0; *yp = t; } #define TRSIZE 100 #ifdef TOOLKIT /*ARGSUSED*/ void handle_key(widget, junk, eventp, cont) Widget widget; XtPointer junk; XEvent *eventp; Boolean *cont; /* unused */ #else /* !TOOLKIT */ void handle_key(eventp) XEvent *eventp; #endif /* TOOLKIT */ { static Boolean has_arg = False; static int number = 0; static int sign = 1; char ch; Boolean arg0; int number0; char trbuf[TRSIZE]; int nbytes; nbytes = XLookupString(&eventp->xkey, trbuf, TRSIZE, (KeySym *) NULL, (XComposeStatus *) NULL); if (nbytes == 0) return; ch = '\0'; if (nbytes == 1) ch = *trbuf; if (ch >= '0' && ch <= '9') { has_arg = True; number = number * 10 + sign * (ch - '0'); return; } else if (ch == '-') { has_arg = True; sign = -1; number = 0; return; } number0 = number; number = 0; sign = 1; arg0 = has_arg; has_arg = False; keystroke(ch, number0, arg0, eventp); } #ifdef TOOLKIT /*ARGSUSED*/ void handle_button(widget, junk, ev, cont) Widget widget; XtPointer junk; XEvent *ev; #define event (&(ev->xbutton)) Boolean *cont; /* unused */ #else /* !TOOLKIT */ void handle_button(event) XButtonEvent *event; #endif /* TOOLKIT */ { int x, y; struct mg_size_rec *size_ptr = mg_size + event->button - 1; XSetWindowAttributes attr; if (alt.win != (Window) 0 || mane.shrinkfactor == 1 || size_ptr->w <= 0) XBell(DISP, 20); else { mag_x = event->x; mag_y = event->y; alt.width = size_ptr->w; alt.height = size_ptr->h; main_x = event->x_root - mag_x; main_y = event->y_root - mag_y; compute_mag_pos(&x, &y); alt.base_x = (event->x + mane_base_x) * mane.shrinkfactor - alt.width/2; alt.base_y = (event->y + mane_base_y) * mane.shrinkfactor - alt.height/2; attr.save_under = True; attr.border_pixel = brdr_Pixel; attr.background_pixel = back_Pixel; attr.override_redirect = True; alt.win = XCreateWindow(DISP, RootWindowOfScreen(SCRN), x, y, alt.width, alt.height, MAGBORD, 0, /* depth from parent */ InputOutput, (Visual *) CopyFromParent, CWSaveUnder | CWBorderPixel | CWBackPixel | CWOverrideRedirect, &attr); XSelectInput(DISP, alt.win, ExposureMask); XMapWindow(DISP, alt.win); alt_stat = 1; /* waiting for exposure */ } } #ifdef TOOLKIT #undef event /*ARGSUSED*/ void handle_motion(widget, junk, ev, cont) Widget widget; XtPointer junk; XEvent *ev; #define event (&(ev->xmotion)) Boolean *cont; /* unused */ { new_mag_x = event->x; main_x = event->x_root - new_mag_x; new_mag_y = event->y; main_y = event->y_root - new_mag_y; mag_moved = (new_mag_x != mag_x || new_mag_y != mag_y); } #undef event #endif /* TOOLKIT */ static void movemag(x, y) int x, y; { int xx, yy; mag_x = x; mag_y = y; if (mag_x == new_mag_x && mag_y == new_mag_y) mag_moved = False; compute_mag_pos(&xx, &yy); XMoveWindow(DISP, alt.win, xx, yy); scrollwindow(&alt, (x + mane_base_x) * mane.shrinkfactor - (int) alt.width/2, (y + mane_base_y) * mane.shrinkfactor - (int) alt.height/2); } #ifdef TOOLKIT /*ARGSUSED*/ void handle_release(widget, junk, ev, cont) Widget widget; XtPointer junk; XEvent *ev; #define event (&(ev->xbutton)) Boolean *cont; /* unused */ #else /* !TOOLKIT */ void handle_release() #endif /* TOOLKIT */ { if (alt.win != (Window) 0) if (alt_stat) alt_stat = -1; /* destroy upon expose */ else { XDestroyWindow(DISP, alt.win); if (currwin.win == alt.win) alt_canit = True; alt.win = (Window) 0; mag_moved = False; can_exposures(&alt); } } #ifdef TOOLKIT #undef event /*ARGSUSED*/ void handle_exp(widget, closure, ev, cont) Widget widget; XtPointer closure; register XEvent *ev; #define event (&(ev->xexpose)) Boolean *cont; /* unused */ { struct WindowRec *windowrec = (struct WindowRec *) closure; if (windowrec == &alt) if (alt_stat < 0) { /* destroy upon exposure */ alt_stat = 0; handle_release(widget, (caddr_t) NULL, ev, (Boolean *) NULL); return; } else alt_stat = 0; expose(windowrec, event->x, event->y, (unsigned int) event->width, (unsigned int) event->height); } #undef event #endif /* TOOLKIT */ void showmessage(message) _Xconst char *message; { get_xy(); XDrawImageString(DISP, mane.win, foreGC, 5 - window_x, 5 + X11HEIGHT - window_y, message, strlen(message)); } /* ||| * Currently the event handler does not coordinate XCopyArea requests * with GraphicsExpose events. This can lead to problems if the window * is partially obscured and one, for example, drags a scrollbar. */ static void keystroke(ch, number0, arg0, eventp) char ch; int number0; Boolean arg0; XEvent *eventp; { int next_page; #ifdef TOOLKIT Window ww; #endif next_page = current_page; switch (ch) { case 'q': case '\003': /* control-C */ case '\004': /* control-D */ #ifdef VMS case '\032': /* control-Z */ #endif #if PS ps_destroy(); #endif exit(0); case 'n': case 'f': case ' ': case '\r': case '\n': /* scroll forward; i.e. go to relative page */ next_page = current_page + (arg0 ? number0 : 1); break; case 'p': case 'b': case '\b': case '\177': /* Del */ /* scroll backward */ next_page = current_page - (arg0 ? number0 : 1); break; case 'g': /* go to absolute page */ next_page = (arg0 ? number0 - pageno_correct : total_pages - 1); break; case 'P': /* declare current page */ pageno_correct = arg0 * number0 - current_page; return; case 'k': /* toggle keep-position flag */ resource.keep_flag = (arg0 ? number0 : !resource.keep_flag); return; case '\f': /* redisplay current page */ break; case '^': home(True); return; #ifdef TOOLKIT case 'l': if (!x_bar) goto bad; XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (-2 * (int) clip_w / 3)); return; case 'r': if (!x_bar) goto bad; XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (2 * (int) clip_w / 3)); return; case 'u': if (!y_bar) goto bad; XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) (-2 * (int) clip_h / 3)); return; case 'd': if (!y_bar) goto bad; XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) (2 * (int) clip_h / 3)); return; case 'c': center(eventp->xkey.x, eventp->xkey.y); return; case 'M': (void) XTranslateCoordinates(DISP, eventp->xkey.window, mane.win, eventp->xkey.x, eventp->xkey.y, &home_x, &home_y, &ww); /* throw away last argument */ home_x *= mane.shrinkfactor; home_y *= mane.shrinkfactor; return; #ifdef BUTTONS case 'x': if (arg0 && resource.expert == (number0 != 0)) return; XtSetValues(vport_widget, resizable_on, XtNumber(resizable_off)); if (resource.expert) { /* create buttons */ XdviResizeWidget(vport_widget, window_w -= XTRA_WID, window_h); create_buttons((XtArgVal) window_h); resource.expert = False; } else { /* destroy buttons */ XtDestroyWidget(panel_widget); XtDestroyWidget(line_widget); XdviResizeWidget(vport_widget, window_w += XTRA_WID, window_h); resource.expert = True; } return; #endif /* BUTTONS */ #else /* !TOOLKIT */ case 'l': if (mane.base_x <= 0) goto bad; scrollmane(mane.base_x - 2 * (int) clip_w / 3, mane.base_y); return; case 'r': if (mane.base_x >= page_w - clip_w) goto bad; scrollmane(mane.base_x + 2 * (int) clip_w / 3, mane.base_y); return; case 'u': if (mane.base_y <= 0) goto bad; scrollmane(mane.base_x, mane.base_y - 2 * (int) clip_h / 3); return; case 'd': if (mane.base_y >= page_h - clip_h) goto bad; scrollmane(mane.base_x, mane.base_y + 2 * (int) clip_h / 3); return; case 'c': /* unchecked scrollmane() */ scrollwindow(&mane, mane.base_x + eventp->xkey.x - clip_w/2, mane.base_y + eventp->xkey.y - clip_h/2); if (x_bar) paint_x_bar(); if (y_bar) paint_y_bar(); XWarpPointer(DISP, None, None, 0, 0, 0, 0, clip_w/2 - eventp->xkey.x, clip_h/2 - eventp->xkey.y); return; case 'M': home_x = (eventp->xkey.x - (y_bar ? BAR_THICK : 0) + mane.base_x) * mane.shrinkfactor; home_y = (eventp->xkey.y - (x_bar ? BAR_THICK : 0) + mane.base_y) * mane.shrinkfactor; return; #endif /* TOOLKIT */ case '\020': /* Control P */ Printf("Unit = %d, bitord = %d, byteord = %d\n", BitmapUnit(DISP), BitmapBitOrder(DISP), ImageByteOrder(DISP)); return; case 's': if (!arg0) { int temp; number0 = ROUNDUP(unshrunk_page_w, window_w - 2); temp = ROUNDUP(unshrunk_page_h, window_h - 2); if (number0 < temp) number0 = temp; } if (number0 <= 0) goto bad; if (number0 == mane.shrinkfactor) return; mane.shrinkfactor = number0; init_page(); if (number0 != 1 && number0 != bak_shrink) { bak_shrink = number0; #ifdef GREY if (use_grey) init_pix(False); #endif reset_fonts(); } reconfig(); home(False); break; case 'S': if (!arg0) goto bad; #ifdef GREY if (use_grey) { float newgamma = number0 != 0 ? number0 / 100.0 : 1.0; if (newgamma == gamma) return; gamma = newgamma; init_pix(False); return; } #endif if (number0 < 0) goto bad; if (number0 == density) return; density = number0; reset_fonts(); if (mane.shrinkfactor == 1) return; break; #ifdef GREY case 'G': use_grey = (arg0 ? number0 : !use_grey); if (use_grey) init_pix(False); reset_fonts(); break; #endif #if PS case 'v': if (!arg0 || resource._postscript != !number0) { resource._postscript = !resource._postscript; if (resource._postscript) scanned_page = scanned_page_bak; psp.toggle(); } break; #endif case 'R': /* reread DVI file */ --dvi_time; /* then it will notice a change */ break; default: goto bad; } if (0 <= next_page && next_page < total_pages) { if (current_page != next_page) { current_page = next_page; hush_spec_now = hush_spec; if (!resource.keep_flag) home(False); } canit = True; XFlush(DISP); return; /* Don't use longjmp here: it might be called from * within the toolkit, and we don't want to longjmp out * of Xt routines. */ } bad: XBell(DISP, 10); } void read_events(wait) wide_bool wait; { XEvent event; alt_canit = False; for (;;) { event_counter = event_freq; /* * The above line clears the flag indicating that an event is * pending. So if an event comes in right now, the flag will be * set again needlessly, but we just end up making an extra call. * Also, be careful about destroying the magnifying glass while * writing it. */ if (!XtPending() && (!wait || canit || mane.min_x < MAXDIM || alt.min_x < MAXDIM || mag_moved)) { if (!wait && (canit | alt_canit)) { #if PS psp.interrupt(); #endif if (allow_can) longjmp(canit_env, 1); } return; } #ifdef TOOLKIT XtNextEvent(&event); if (resized) get_geom(); if (event.xany.window == alt.win && event.type == Expose) { handle_exp((Widget) NULL, (XtPointer) &alt, &event, (Boolean *) NULL); continue; } (void) XtDispatchEvent(&event); #else /* !TOOLKIT */ XNextEvent(DISP, &event); if (event.xany.window == mane.win || event.xany.window == alt.win) { struct WindowRec *wr = &mane; if (event.xany.window == alt.win) { wr = &alt; /* check in case we already destroyed the window */ if (alt_stat < 0) { /* destroy upon exposure */ alt_stat = 0; handle_release(); continue; } else alt_stat = 0; } switch (event.type) { case GraphicsExpose: case Expose: expose(wr, event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height); break; case MotionNotify: new_mag_x = event.xmotion.x; new_mag_y = event.xmotion.y; mag_moved = (new_mag_x != mag_x || new_mag_y != mag_y); break; case ButtonPress: handle_button(&event.xbutton); break; case ButtonRelease: handle_release(); break; } /* end switch */ } /* end if window == {mane,alt}.win */ else if (event.xany.window == x_bar) { if (event.type == Expose) XFillRectangle(DISP, x_bar, ruleGC, x_bgn, 1, x_end - x_bgn, BAR_WID); else if (event.type == MotionNotify) scrollmane(event.xmotion.x * page_w / clip_w, mane.base_y); else switch (event.xbutton.button) { case 1: scrollmane(mane.base_x + event.xbutton.x, mane.base_y); break; case 2: scrollmane(event.xbutton.x * page_w / clip_w, mane.base_y); break; case 3: scrollmane(mane.base_x - event.xbutton.x, mane.base_y); } } else if (event.xany.window == y_bar) { if (event.type == Expose) XFillRectangle(DISP, y_bar, ruleGC, 1, y_bgn, BAR_WID, y_end - y_bgn); else if (event.type == MotionNotify) scrollmane(mane.base_x, event.xmotion.y * page_h / clip_h); else switch (event.xbutton.button) { case 1: scrollmane(mane.base_x, mane.base_y + event.xbutton.y); break; case 2: scrollmane(mane.base_x, event.xbutton.y * page_h / clip_h); break; case 3: scrollmane(mane.base_x, mane.base_y - event.xbutton.y); } } else if (event.xany.window == top_level) switch (event.type) { case ConfigureNotify: if (event.xany.window == top_level && (event.xconfigure.width != window_w || event.xconfigure.height != window_h)) { register Window old_mane_win = mane.win; window_w = event.xconfigure.width; window_h = event.xconfigure.height; reconfig(); if (old_mane_win == (Window) 0) home(False); } break; case MapNotify: /* if running w/o WM */ if (mane.win == (Window) 0) { reconfig(); home(False); } break; case KeyPress: handle_key(&event); break; } #endif /* TOOLKIT */ } } static void redraw(windowrec) struct WindowRec *windowrec; { currwin = *windowrec; min_x = currwin.min_x + currwin.base_x; min_y = currwin.min_y + currwin.base_y; max_x = currwin.max_x + currwin.base_x; max_y = currwin.max_y + currwin.base_y; can_exposures(windowrec); if (debug & DBG_EVENT) Printf("Redraw %d x %d at (%d, %d) (base=%d,%d)\n", max_x - min_x, max_y - min_y, min_x, min_y, currwin.base_x, currwin.base_y); XDefineCursor(DISP, mane.win, redraw_cursor); XFlush(DISP); if (setjmp(dvi_env)) { XClearWindow(DISP, mane.win); psp.endheader(); showmessage(dvi_oops_msg); if (dvi_file) { Fclose(dvi_file); dvi_file = NULL; } } else { draw_page(); hush_spec_now = True; } } void redraw_page() { if (debug & DBG_EVENT) Fputs("Redraw page: ", stdout); XClearWindow(DISP, mane.win); psp.endheader(); if (backing_store != NotUseful) { mane.min_x = mane.min_y = 0; mane.max_x = page_w; mane.max_y = page_h; } else { get_xy(); mane.min_x = -window_x; mane.max_x = -window_x + clip_w; mane.min_y = -window_y; mane.max_y = -window_y + clip_h; } redraw(&mane); } /* * Interrupt system for receiving events. The program sets a flag * whenever an event comes in, so that at the proper time (i.e., when * reading a new dvi item), we can check incoming events to see if we * still want to go on printing this page. This way, one can stop * displaying a page if it is about to be erased anyway. We try to read * as many events as possible before doing anything and base the next * action on all events read. * Note that the Xlib and Xt routines are not reentrant, so the most we * can do is set a flag in the interrupt routine and check it later. * Also, sometimes the interrupts are not generated (some systems only * guarantee that SIGIO is generated for terminal files, and on the system * I use, the interrupts are not generated if I use "(xdvi foo &)" instead * of "xdvi foo"). Therefore, there is also a mechanism to check the * event queue every 70 drawing operations or so. This mechanism is * disabled if it turns out that the interrupts do work. * For a fuller discussion of some of the above, see xlife in * comp.sources.x. */ static void can_exposures(windowrec) struct WindowRec *windowrec; { windowrec->min_x = windowrec->min_y = MAXDIM; windowrec->max_x = windowrec->max_y = 0; } #if HAS_SIGIO /* ARGSUSED */ static void handle_intr(signo) int signo; { event_counter = 1; event_freq = -1; /* forget Plan B */ } static void enable_intr() { int socket = ConnectionNumber(DISP); #ifdef SA_RESTART /* Subprocess handling, e.g., MakeTeXPK, fails on the Alpha without this, because SIGIO interrupts the call of system(3), since OSF/1 doesn't retry interrupted wait calls by default. From code by maj@cl.cam.ac.uk. */ { struct sigaction a; a.sa_handler = handle_intr; sigemptyset(&a.sa_mask); sigaddset(&a.sa_mask, SIGIO); a.sa_flags = SA_RESTART; sigaction(SIGIO, &a, NULL); } #else (void) signal(SIGIO, handle_intr); #endif /* SA_RESTART */ (void) fcntl(socket, F_SETOWN, getpid()); (void) fcntl(socket, F_SETFL, fcntl(socket, F_GETFL, 0) | FASYNC); } #endif /* HAS_SIGIO */ void do_pages() { if (debug & DBG_BATCH) { #ifdef TOOLKIT while (mane.min_x == MAXDIM) read_events(True); #else /* !TOOLKIT */ while (mane.min_x == MAXDIM) if (setjmp(canit_env)) break; else read_events(True); #endif /* TOOLKIT */ for (current_page = 0; current_page < total_pages; ++current_page) { #ifdef __convex__ /* convex C turns off optimization for the entire function if setjmp return value is discarded.*/ if (setjmp(canit_env)) /*optimize me*/; #else (void) setjmp(canit_env); #endif canit = False; redraw_page(); } } else { /* normal operation */ #if HAS_SIGIO enable_intr(); #endif #ifdef __convex__ /* convex C turns off optimization for the entire function if setjmp return value is discarded.*/ if (setjmp(canit_env)) /*optimize me*/; #else (void) setjmp(canit_env); #endif for (;;) { if (mane.win != (Window) 0) XDefineCursor(DISP, mane.win, ready_cursor); read_events(True); if (canit) { canit = False; can_exposures(&mane); can_exposures(&alt); redraw_page(); } else if (mag_moved) { if (alt.win == (Window) 0) mag_moved = False; else if (abs(new_mag_x - mag_x) > 2 * abs(new_mag_y - mag_y)) movemag(new_mag_x, mag_y); else if (abs(new_mag_y - mag_y) > 2 * abs(new_mag_x - mag_x)) movemag(mag_x, new_mag_y); else movemag(new_mag_x, new_mag_y); } else if (alt.min_x < MAXDIM) redraw(&alt); else if (mane.min_x < MAXDIM) redraw(&mane); XFlush(DISP); } } }  *[XDVI]FAQ.;1+, . / 4 - 0@123KPWO 561鴞71鴞8༉_o9GHJ This file answers the following questions about installing xdvi: 1. I have font files cmr10.tfm, etc. Why can't xdvi use them? 2. I can't seem to set the font path correctly. Can you help me? 3. xdvi claims to support virtual fonts, but I can't use PostScript virtual fonts (such as helv.vf or phvr.vf) with xdvi. Why not? 4. I am trying to display PostScript specials with -DPS_GS, but instead I get the message `gs: gs: Malformed ghostview color property.' 5. I am using gs 3.3.3 to render PostScript figures, but find that it cuts some off below or to the right of a certain point, and others are omitted entirely. ---------- 1. I have font files cmr10.tfm, etc. Why can't xdvi use them? tfm files contain only minimal information about the characters in a font: just the height, width, depth, and kerning and ligature information. To obtain information about the shapes of the characters, xdvi needs pk or gf files. (pxl files also contain this information, but are obsolete. There are utilities to convert them to pk files though.) ---------- 2. I can't seem to set the font path correctly. Can you help me? Try xdvi -debug 32 file.dvi to find out where xdvi is looking for the fonts. ---------- 3. xdvi claims to support virtual fonts, but I can't use PostScript virtual fonts (such as helv.vf or phvr.vf) with xdvi. Why not? The short answer is to quote the man page: Virtual fonts are also supported, although xdvi does not have any built-in fonts to which they can refer. As further explanation, let me begin by pointing out: VIRTUAL FONTS ARE NOT FONTS. Virtual fonts are recipes for building fonts from other fonts. In the case of PostScript fonts, those other fonts reside on your printer. Which is fine for dvi-to-PostScript programs such as dvips, but it presents a problem for xdvi since it cannot access your printer. There are some solutions, however. The first solution is to install gsftopk, which uses ghostscript to approximate the fonts. It is made for sites that use both xdvi and dvips, although if you just use xdvi it should be useful, too. Another solution is to get these fonts pre-made in common sizes. These were made by a program called gsrenderfont (part of the Gnu font utilities). These are all available via anonymous ftp: gsftopk from math.berkeley.edu:pub/TeX/gsftopk.tar.Z pre-made fonts from ftp.cs.umb.edu:pub/tex/psfonts.tar gsrenderfont from prep.ai.mit.edu:pub/gnu/fontutils-0.6.tar.gz ---------- 4. I am trying to display PostScript specials with L~XDVI.BAK   [XDVI]FAQ.;1 -DPS_GS, but instead I get the message `gs: gs: Malformed ghostview color property.' xdvi needs at least version 2.6.2 of ghostscript. It will also run with ghostscript 2.6.1, provided you have applied fixes 1-4. This particular error message means that you are running gs 2.6.1 without fixes 1-4. Probably you should get ghostscript 2.6.2 from prep.ai.mit.edu (or any of its mirror sites). xdvi will also run with version 3 of ghostscript, but see question #5. ---------- 5. I am using gs 3.3.3 to render PostScript figures, but find that it cuts some off below or to the right of a certain point, and others are omitted entirely. You should apply the following patch. This will also fix similar errors with ghostview. This patch supersedes a previous patch I have suggested to some people. *** gdevxini.c.orig Tue May 2 14:12:52 1995 --- gdevxini.c Tue May 2 14:13:57 1995 *************** *** 320,345 **** /* The following sets the imageable area according to the */ /* bounding box and margins sent by ghostview. */ ! { float m[4]; ! m[0] = (llx - left_margin) / 72.0; /* left */ ! m[1] = (lly - bottom_margin) / 72.0; /* bottom */ ! m[2] = xdev->width / xdev->x_pixels_per_inch - ! (urx + right_margin) / 72.0; /* right */ ! m[3] = xdev->height / xdev->y_pixels_per_inch - ! (ury + top_margin) / 72.0; /* top */ ! ! /****** ! ****** For reasons I don't understand, ! ****** we have to set the margins to zero here ! ****** in order for Ghostview to do landscape display right. ! ******/ ! #if 0 ! m[0] = m[1] = m[2] = m[3] = 0; ! #endif ! ! gx_device_set_margins((gx_device *)xdev, m, false); ! } ! } else if (xdev->pwin == (Window)None) { eprintf("gs: Cannot get ghostview property.\n"); exit(1); --- 320,330 ---- /* The following sets the imageable area according to the */ /* bounding box and margins sent by ghostview. */ ! xdev->ImagingBBox[0] = llx - left_margin; ! xdev->ImagingBBox[1] = lly - bottom_margin; ! xdev->ImagingBBox[2] = urx + right_margin; ! xdev->ImagingBBox[3] = ury + top_margin; ! xdev->ImagingBBox_set = true; } else if (xdev->pwin == (Window)None) { eprintf("gs: Cannot get ghostview property.\n"); exit(1); =*[XDVI]FONT_OPEN.C;6+,.*/ 4M*(- 0@123KPWO+56XGxk7Xxk80 ]o9GHJP/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTE: * xdvi is based on prior work, as noted in the modification history * in xdvi.c. */ #include "xdvi.h" #include #ifdef X_NOT_STDC_ENV extern int errno; extern char *getenv ARGS((_Xconst char *)); #endif /* * If you think you have to change DEFAULT_TAIL, then you haven't read the * documentation closely enough. */ #ifndef VMS #define PATH_SEP ':' #define DEFAULT_TAIL "/%f.%d%p" #define DEFAULT_VF_TAIL "/%f.vf" #else /* VMS */ #define PATH_SEP '/' #define DEFAULT_TAIL ":%f.%d%p" #define DEFAULT_VF_TAIL ":%f.vf" #endif /* VMS */ static _Xconst char *font_path; static _Xconst char *default_font_path = DEFAULT_FONT_PATH; static _Xconst char *vf_path; static _Xconst char *default_vf_path = DEFAULT_VF_PATH; #ifdef MAKEPK static _Xconst char *makepkcmd = NULL; #endif #if PS struct findrec figfind = {DEFAULT_FIG_PATH, NULL}; struct findrec headerfind = {DEFAULT_HEADER_PATH, NULL}; #endif #ifdef SEARCH_SUBDIRECTORIES static char default_subdir_path[] = DEFAULT_SUBDIR_PATH; #endif static int *sizes, *sizend; static char default_size_list[] = DEFAULT_FONT_SIZES; #ifdef _POSIX_SOURCE #include #ifdef PATH_MAX #define FILENAMESIZE PATH_MAX #endif #endif #ifndef FILENAMESIZE #define FILENAMESIZE 512 #endif #if defined(sun) && BSD char *sprintf(); #endif #ifndef EX_OK #ifndef VMS #define EX_OK 0 #else #define EX_OK 1 #endif #endif #ifdef SEARCH_SUBDIRECTORIES /* We will need some system include files to deal with directories. */ /* was included by xdvi.h. */ #include static int is_dir (); #if defined(SYSV) || defined(_POSIX_SOURCE) #include typedef struct dirent *directory_entry_type; #else #include typedef struct direct *directory_entry_type; #endif /* Declare the routine to get the current working directory. */ #ifdef HAVE_GETWD extern char *getwd (); #define GETCWD(b, len) ((b) ? getwd (b) : getwd (xmalloc (len, "getwd"))) #else /* POSIX says getcwd result is undefined if the pointer is NULL; at least on a Convex, the result is a coredump. Hence the GETCWD macro below is defined, as it works regardless of what getcwd() does with a NULL pointer */ #define GETCWD(b, len) ((b) ? getcwd (b,len) \ : getcwd (xmalloc (len, "getcwd"),len)) #ifndef _POSIX_SOURCE #if NeedFunctionPrototypes /* extern char *getcwd (char *, int); */ #else /* extern char *getcwd (); */ #endif /* not NeedFunctionPrototypes */ #endif /* not _POSIX_SOURCE */ #endif /* not HAVE_GETWD */ static char *cwd; /* The following is a data structure containing the precomputed names of subdirectories to be recursively searched. */ static struct subdir_entry { char *name; /* partial string */ _Xconst char *index; /* reference point in {,default_}font_path */ struct subdir_entry *next; /* link in list */ } *subdir_head = NULL, *next_subdir; #ifndef S_ISDIR #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* Return true if FN is a directory or a symlink to a directory, false if not. */ static int is_dir (fn) char *fn; { struct stat stats; return stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode); } /* * Compute extra length of subdirectory entries, including a star for each. */ static int extra_len(str1, str2) char *str1, *str2; { int bias = 0; char *p = str1; char *q; do { q = index(p, PATH_SEP); if (q == NULL) q = p + strlen(p); if (q == p) { if (str2 != NULL) { bias += extra_len(str2, (char *) NULL); str2 = NULL; } } else ++bias; /* don't forget the star */ p = q + 1; } while (p[-1] != '\0'); return bias + p - str1; } /* * Add the specifiers (and double stars) for the given strings (user * string, plus default string) to the destination string. */ static void add_subdir_paths(dst, dst_first, src, src_default) char *dst, *dst_first, *src, *src_default; { char *q; do { q = index(src, PATH_SEP); if (q == NULL) q = src + strlen(src); if (q == src) { if (src_default != NULL) { add_subdir_paths(dst, dst_first, src_default, (char *)NULL); dst += strlen(dst); src_default = NULL; } } else { if (dst != dst_first) *dst++ = PATH_SEP; bcopy(src, dst, q - src); dst += q - src; *dst++ = '*'; } src = q + 1; } while (src[-1] != '\0'); *dst = '\0'; } /* * Make a subdirectory entry. */ static struct subdir_entry * make_subdir_entry(index, name) _Xconst char *index; char *name; { struct subdir_entry *new_entry; static struct subdir_entry **subdir_tail = &subdir_head; *subdir_tail = new_entry = (struct subdir_entry *) xmalloc(sizeof(struct subdir_entry), "subdirectory list entry"); subdir_tail = &(new_entry->next); new_entry->name = strcpy(xmalloc(strlen(name) + 1, "subdirectory entry string"), name); new_entry->index = index; new_entry->next = NULL; return new_entry; } /* * Create the subdirectory linked list for the given initial string */ static void add_subdirs(str, len, recurs) _Xconst char *str; int len; Boolean recurs; { int len1 = len; char temp[FILENAMESIZE]; struct subdir_entry *next_subdir; DIR *dir; directory_entry_type e; bcopy(str, temp, len); if (len > 0 && temp[len - 1] != '/') temp[len1++] = '/'; temp[len1] = '\0'; next_subdir = make_subdir_entry(str, temp + len); do { /* By changing directories, we save a bunch of string concatenations (and make the pathnames the kernel looks up shorter). */ Strcpy(temp + len, next_subdir->name); if (chdir (temp) != 0) continue; dir = opendir ("."); if (dir == NULL) continue; len1 = strlen(temp); if (len1 == 0 || temp[len1 - 1] != '/') temp[len1++] = '/'; while ((e = readdir (dir)) != NULL) { if (is_dir (e->d_name) && strcmp (e->d_name, ".") != 0 && strcmp (e->d_name, "..") != 0) { Strcpy(temp + len1, e->d_name); (void) make_subdir_entry(str, temp + len); } } (void) closedir (dir); /* Change back to the current directory, in case the path contains relative directory names. */ if (chdir (cwd) != 0) { perror (cwd); #if PS ps_destroy(); #endif exit (errno); } } while (recurs && (next_subdir = next_subdir->next) != NULL); } /* * Recursively figure out the subdirectory tree and precompute the * list of subdirectories to search. */ static void compute_subdir_paths(fp, fp_default) _Xconst char *fp; _Xconst char *fp_default; { _Xconst char *star_loc = NULL; _Xconst char *endp; do { if (star_loc == NULL) { star_loc = index(fp, '*'); if (star_loc == NULL) star_loc = fp + strlen(fp); } endp = index(fp, PATH_SEP); if (endp == NULL) endp = fp + strlen(fp); if (endp == fp) { if (fp_default != NULL) { compute_subdir_paths(fp_default, (char *) NULL); fp_default = NULL; } } else if (star_loc < endp) { add_subdirs(fp, star_loc - fp, star_loc[1] == '*'); star_loc = NULL; } fp = endp + 1; } while (fp[-1] != '\0'); } #endif /* SEARCH_SUBDIRECTORIES */ static void get_sizes(size_list, spp) char *size_list; int **spp; { if (*size_list == PATH_SEP) ++size_list; for (;;) { #ifndef FONT5 *(*spp)++ = atoi(size_list); #else *(*spp)++ = atoi(size_list) * 5 + 0.5; #endif size_list = index(size_list, PATH_SEP); if (size_list == NULL) return; ++size_list; } } void init_font_open() { char *size_list; int *sp, *sp1, *sp2; unsigned int n; char *p; #ifdef SEARCH_SUBDIRECTORIES char *q; #endif if ((font_path = getenv("XDVIFONTS")) == NULL #ifndef XDVIFONTS_ONLY && (font_path = getenv("PKFONTS")) == NULL && (font_path = getenv("TEXPKS")) == NULL && (font_path = getenv("TEXFONTS")) == NULL #endif ) { font_path = default_font_path; default_font_path = NULL; } #ifdef SEARCH_SUBDIRECTORIES p = getenv ("TEXFONTS_SUBDIR"); if (p == NULL) p = ""; q = xmalloc((unsigned) strlen(font_path) + extra_len(p, default_subdir_path) + 1, "initializing font searching"); Strcpy(q, font_path); add_subdir_paths(q + strlen(q), q, p, default_subdir_path); font_path = q; /* Unfortunately, we can't look in the environment for the current directory, because if we are running under a program (let's say Emacs), the PWD variable might have been set by Emacs' parent to the current directory at the time Emacs was invoked. This is not necessarily the same directory the user expects to be in. So, we must always call getcwd(3) or getwd(3), even though they are slow and prone to hang in networked installations. */ cwd = GETCWD ((char *) NULL, FILENAMESIZE + 2); if (cwd == NULL) { perror ("getcwd"); #if PS ps_destroy(); #endif exit (errno); } compute_subdir_paths(font_path, default_font_path); #endif if ((vf_path = getenv("XDVIVFS")) == NULL #ifndef XDVIFONTS_ONLY && (vf_path = getenv("VFFONTS")) == NULL #endif ) { vf_path = default_vf_path; default_vf_path = NULL; } size_list = getenv("XDVISIZES"); n = 1; /* count number of sizes */ if (size_list == NULL || *size_list == PATH_SEP) for (p = default_size_list; (p = index(p, PATH_SEP)) != NULL; ++p) ++n; if (size_list != NULL) for (p = size_list; (p = index(p, PATH_SEP)) != NULL; ++p) ++n; sizes = (int *) xmalloc(n * sizeof(int), "size list"); sizend = sizes + n; sp = sizes; /* get the actual sizes */ if (size_list == NULL || *size_list == PATH_SEP) get_sizes(default_size_list, &sp); if (size_list != NULL) get_sizes(size_list, &sp); /* bubble sort the sizes */ sp1 = sizend - 1; /* extent of this pass */ do { sp2 = NULL; for (sp = sizes; sp < sp1; ++sp) if (*sp > sp[1]) { int i = *sp; *sp = sp[1]; sp[1] = i; sp2 = sp; } } while ((sp1 = sp2) != NULL); } static FILE * formatted_open(path, font, pk_or_gf, dpi, name, first_try, tail) _Xconst char *path; _Xconst char *font; _Xconst char *pk_or_gf; int dpi; char **name; Boolean first_try; _Xconst char *tail; { _Xconst char *p = path; char nm[FILENAMESIZE]; char *n = nm; char c; Boolean f_used = False; Boolean p_used = False; FILE *f; #ifdef SEARCH_SUBDIRECTORIES if (next_subdir != NULL && next_subdir->index == p) { int len = index(p, '*') - p; bcopy(p, n, len); p += len; n += len; Strcpy(n, next_subdir->name); n += strlen(n); ++p; if (*p == '*') ++p; if (*p != '/') *n++ = '/'; } #endif for (;;) { c = *p++; if (c==PATH_SEP || c=='\0') { if (f_used) break; p = tail; continue; } if (c=='%') { c = *p++; switch (c) { case 'f': f_used = True; case 'F': Strcpy(n, font); break; case 'p': p_used = True; Strcpy(n, pk_or_gf); break; case 'd': Sprintf(n, "%d", dpi); break; case 'b': Sprintf(n, "%d", pixels_per_inch); break; case 'm': Strcpy(n, resource.mfmode != NULL ? resource.mfmode : "default"); break; default: *n++ = c; *n = '\0'; } n += strlen(n); } else *n++ = c; } if (!p_used && !first_try) return NULL; *n = '\0'; if (debug & DBG_OPEN) Printf("Trying font file %s\n", nm); f = xfopen(nm, OPEN_MODE); if (f != NULL) { *name = xmalloc((unsigned) (n - nm + 1), "font file name"); Strcpy(*name, nm); } return f; } /* * Try a given size */ static FILE * try_size(font, dpi, name, x_font_path, x_default_font_path) _Xconst char *font; int dpi; char **name; _Xconst char *x_font_path; _Xconst char *x_default_font_path; { _Xconst char *p = x_font_path; FILE *f; #ifndef FONT5 int pkmag = dpi; #else int pkmag = dpi * 2 / 3; #endif /* * loop over paths */ #ifdef SEARCH_SUBDIRECTORIES next_subdir = subdir_head; #endif for (;;) { if (*p == PATH_SEP || *p == '\0') { if (x_default_font_path != NULL && (f = try_size(font, dpi, name, x_default_font_path, (_Xconst char *) NULL)) != NULL) return f; if (*p == '\0') break; } else { #define FIRST_TRY True #ifdef USE_PK if ((f = formatted_open(p, font, "pk", pkmag, name, FIRST_TRY, DEFAULT_TAIL)) != NULL) return f; #undef FIRST_TRY #define FIRST_TRY False #endif #ifdef USE_GF if ((f = formatted_open(p, font, "gf", pkmag, name, FIRST_TRY, DEFAULT_TAIL)) != NULL) return f; #endif #ifdef SEARCH_SUBDIRECTORIES if (next_subdir != NULL && next_subdir->index == p) { next_subdir = next_subdir->next; if (next_subdir != NULL && next_subdir->index == p) continue; } #endif p = index(p, PATH_SEP); if (p == NULL) break; } ++p; } return NULL; } /* * Try a virtual font */ static FILE * try_vf(font, name, x_vf_path, x_default_vf_path) _Xconst char *font; char **name; _Xconst char *x_vf_path; _Xconst char *x_default_vf_path; { _Xconst char *p = x_vf_path; FILE *f; /* * loop over paths */ for (;;) { if (*p == PATH_SEP || *p == '\0') { if (x_default_vf_path != NULL && (f = try_vf(font, name, x_default_vf_path, (_Xconst char *) NULL)) != NULL) return f; if (*p == '\0') break; } else { if ((f = formatted_open(p, font, "vf", 0, name, True, DEFAULT_VF_TAIL)) != NULL) return f; p = index(p, PATH_SEP); if (p == NULL) break; } ++p; } return NULL; } #ifdef MAKEPK #ifndef MAKEPKCMD #define MAKEPKCMD "MakeTeXPK" #endif #define NOBUILD 29999 #define MKPKSIZE 256 #endif /* MAKEPK */ /* * Try a given font name */ #ifndef MAKEPK #define PRE_FONT_OPEN(font, fdpi, dpi_ret, name, ignore) \ pre_font_open(font, fdpi, dpi_ret, name) #else #define PRE_FONT_OPEN pre_font_open #endif static FILE * PRE_FONT_OPEN(font, fdpi, dpi_ret, name, magstepval) _Xconst char *font; double fdpi; int *dpi_ret; char **name; #ifdef MAKEPK int magstepval; #endif { FILE *f; int *p1, *p2; #ifndef FONT5 int dpi = fdpi + 0.5; #else int dpi = 5 * fdpi + 0.5; #endif int tempdpi; #ifndef VMS _Xconst char *path_to_use; _Xconst char *vf_path_to_use; #endif /* * Loop over sizes. Try actual size first, then closest sizes. If the pathname is absolutely or explicitly relative, don't use the usual paths to search for it; just look for it in the directory specified. */ #ifndef VMS path_to_use = (_Xconst char *) NULL; if (*font == '/') path_to_use = "/"; else if (*font == '.' && (*(font + 1) == '/' || (*(font + 1) == '.' && *(font + 2) == '/'))) path_to_use = "."; vf_path_to_use = path_to_use; if (path_to_use == NULL) { path_to_use = font_path; vf_path_to_use = vf_path; } #else /* VMS */ #define path_to_use font_path #define vf_path_to_use vf_path #endif /* VMS */ if ((f = try_size(font, *dpi_ret = dpi, name, path_to_use, default_font_path)) != NULL) return f; /* Try at one away from the size we just tried, to account for rounding error. */ #ifndef FONT5 tempdpi = dpi + (dpi < fdpi ? 1 : -1); #else tempdpi = dpi + (dpi < 5 * fdpi ? 1 : -1); #endif if ((f = try_size(font, tempdpi, name, path_to_use, default_font_path)) != NULL) { *dpi_ret = tempdpi; return f; } /* Try a virtual font. */ if ((f = try_vf(font, name, vf_path_to_use, default_vf_path)) != NULL) return f; #ifdef MAKEPK /* Try to create the font. */ if (magstepval != NOBUILD && resource.makepk) { char mkpk[MKPKSIZE]; Boolean used_fontname = False; Boolean used_mfmode = False; _Xconst char *p; char *q; if (makepkcmd == NULL) { makepkcmd = getenv("XDVIMAKEPK"); if (makepkcmd == NULL) makepkcmd = MAKEPKCMD; } p = makepkcmd; q = mkpk; for (;;) { if (*p == '%') { switch (*++p) { case 'n': Strcpy(q, font); used_fontname = True; break; case 'd': Sprintf(q, "%d", dpi); break; case 'b': Sprintf(q, "%d", pixels_per_inch); break; case 'm': if (magstepval == NOMAGSTP) Sprintf(q, "%d+%d/%d", dpi / pixels_per_inch, dpi % pixels_per_inch, pixels_per_inch); else if (magstepval < 0) Sprintf(q, "magstep\\(-%d%s\\)", -magstepval / 2, magstepval % 2 ? ".5" :""); else Sprintf(q, "magstep\\(%d%s\\)", magstepval / 2, magstepval % 2 ? ".5" :""); break; case 'o': Strcpy(q, resource.mfmode != NULL ? resource.mfmode : "default"); used_mfmode = True; break; case '%': *q++ = '%'; *q = '\0'; break; case '\0': --p; *q = '\0'; break; default: *q++ = '%'; *q++ = *p; *q = '\0'; break; } q += strlen(q); } else if (*p == '\0') if (used_fontname) break; else { p = " %n %d %b %m"; continue; } else *q++ = *p; ++p; } if (resource.mfmode != NULL && !used_mfmode) { *q++ = ' '; Strcpy(q, resource.mfmode); } else *q = '\0'; Printf("- %s\n", mkpk); if (system(mkpk) == EX_OK && (f = try_size(font, dpi, name, path_to_use, default_font_path)) != NULL) return f; } #endif /* MAKEPK */ /* Now try at all the sizes. */ for (p2 = sizes; p2 < sizend; ++p2) if (*p2 >= dpi) break; p1 = p2; for (;;) { /* find another resolution */ if (p1 <= sizes) if (p2 >= sizend) return NULL; else tempdpi = *p2++; else if (p2 >= sizend || (long) dpi * dpi <= (long) p1[-1] * *p2) tempdpi = *--p1; else tempdpi = *p2++; if ((f = try_size(font, *dpi_ret = tempdpi, name, path_to_use, default_font_path)) != NULL) return f; } } /* ARGSUSED */ FILE * font_open(font, font_ret, dpi, dpi_ret, magstepval, name) _Xconst char *font; char **font_ret; double dpi; int *dpi_ret; int magstepval; char **name; { FILE *f; int actual_pt, low_pt, high_pt, trial_pt; char fn[50], *fnend; f = PRE_FONT_OPEN(font, dpi, dpi_ret, name, magstepval); if (f != NULL) { *font_ret = NULL; return f; } Strcpy(fn, font); fnend = fn + strlen(fn); while (fnend > fn && fnend[-1] >= '0' && fnend[-1] <= '9') --fnend; actual_pt = low_pt = high_pt = atoi(fnend); if (actual_pt) { low_pt = actual_pt - 1; high_pt = actual_pt + 1; for (;;) { if (2 * low_pt >= actual_pt && (low_pt * high_pt > actual_pt * actual_pt || high_pt > actual_pt + 5)) trial_pt = low_pt--; else if (high_pt > actual_pt + 5) break; else trial_pt = high_pt++; Sprintf(fnend, "%d", trial_pt); f = PRE_FONT_OPEN(fn, dpi * actual_pt / trial_pt, dpi_ret, name, NOBUILD); if (f != NULL) { *font_ret = strcpy(xmalloc((unsigned) strlen(fn) + 1, "name of font used"), fn); return f; } } } if (alt_font != NULL) { f = PRE_FONT_OPEN(alt_font, dpi, dpi_ret, name, magstepval); if (f != NULL) *font_ret = strcpy(xmalloc((unsigned) strlen(alt_font) + 1, "name of font used"), alt_font); } return f; }  *[XDVI]GF.C;1+, './ 4- 0@123KPWO56A˘Y7A˘Y8Y]o9GHJ /* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "xdvi.h" /*** *** GF font reading routines. *** Public routines are read_GF_index and read_GF_char. ***/ #define PAINT_0 0 #define PAINT1 64 #define PAINT2 65 #define PAINT3 66 #define BOC 67 #define BOC1 68 #define EOC 69 #define SKIP0 70 #define SKIP1 71 #define SKIP2 72 #define SKIP3 73 #define NEW_ROW_0 74 #define NEW_ROW_MAX 238 #define XXX1 239 #define XXX2 240 #define XXX3 241 #define XXX4 242 #define YYY 243 #define NO_OP 244 #define CHAR_LOC 245 #define CHAR_LOC0 246 #define PRE 247 #define POST 248 #define POST_POST 249 #define GF_ID_BYTE 131 #define TRAILER 223 /* Trailing bytes at end of file */ static FILE *GF_file; static void expect(ch) ubyte ch; { ubyte ch1 = one(GF_file); if (ch1 != ch) oops("Bad GF file: %d expected, %d received.", ch, ch1); } static void too_many_bits(ch) ubyte ch; { oops("Too many bits found when loading character %d", ch); } /* * Public routines */ static void #if NeedFunctionPrototypes read_GF_char(register struct font *fontp, wide_ubyte ch) #else /* !NeedFunctionPrototypes */ read_GF_char(fontp, ch) register struct font *fontp; ubyte ch; #endif /* NeedFunctionPrototypes */ { register struct glyph *g; ubyte cmnd; int min_m, max_m, min_n, max_n; BMUNIT *cp, *basep, *maxp; int bytes_wide; Boolean paint_switch; #define White False #define Black True Boolean new_row; int count; int word_weight; g = &fontp->glyph[ch]; GF_file = fontp->file; if(debug & DBG_PK) Printf("Loading gf char %d", ch); for (;;) { switch (cmnd = one(GF_file)) { case XXX1: case XXX2: case XXX3: case XXX4: Fseek(GF_file, (long) num(GF_file, WIDENINT cmnd - XXX1 + 1), 1); continue; case YYY: (void) four(GF_file); continue; case BOC: (void) four(GF_file); /* skip character code */ (void) four(GF_file); /* skip pointer to prev char */ min_m = sfour(GF_file); max_m = sfour(GF_file); g->x = -min_m; min_n = sfour(GF_file); g->y = max_n = sfour(GF_file); g->bitmap.w = max_m - min_m + 1; g->bitmap.h = max_n - min_n + 1; break; case BOC1: (void) one(GF_file); /* skip character code */ g->bitmap.w = one(GF_file); /* max_m - min_m */ g->x = g->bitmap.w - one(GF_file); /* ditto - max_m */ ++g->bitmap.w; g->bitmap.h = one(GF_file) + 1; g->y = one(GF_file); break; default: oops("Bad BOC code: %d", cmnd); } break; } paint_switch = White; if (debug & DBG_PK) Printf(", size=%dx%d, dvi_adv=%d\n", g->bitmap.w, g->bitmap.h, g->dvi_adv); alloc_bitmap(&g->bitmap); cp = basep = (BMUNIT *) g->bitmap.bits; /* * Read character data into *basep */ bytes_wide = ROUNDUP((int) g->bitmap.w, BITS_PER_BMUNIT) * BYTES_PER_BMUNIT; maxp = ADD(basep, g->bitmap.h * bytes_wide); bzero(g->bitmap.bits, g->bitmap.h * bytes_wide); new_row = False; word_weight = BITS_PER_BMUNIT; for (;;) { count = -1; cmnd = one(GF_file); if (cmnd < 64) count = cmnd; else if (cmnd >= NEW_ROW_0 && cmnd <= NEW_ROW_MAX) { count = cmnd - NEW_ROW_0; paint_switch = White; /* it'll be complemented later */ new_row = True; } else switch (cmnd) { case PAINT1: case PAINT2: case PAINT3: count = num(GF_file, WIDENINT cmnd - PAINT1 + 1); break; case EOC: if (cp >= ADD(basep, bytes_wide)) too_many_bits(ch); return; case SKIP1: case SKIP2: case SKIP3: *((char **) &basep) += num(GF_file, WIDENINT cmnd - SKIP0) * bytes_wide; case SKIP0: new_row = True; paint_switch = White; break; case XXX1: case XXX2: case XXX3: case XXX4: Fseek(GF_file, (long) num(GF_file, WIDENINT cmnd - XXX1 + 1), 1); break; case YYY: (void) four(GF_file); break; case NO_OP: break; default: oops("Bad command in GF file: %d", cmnd); } /* end switch */ if (new_row) { *((char **) &basep) += bytes_wide; if (basep >= maxp || cp >= basep) too_many_bits(ch); cp = basep; word_weight = BITS_PER_BMUNIT; new_row = False; } if (count >= 0) { while (count) if (count <= word_weight) { #ifndef MSBITFIRST if (paint_switch) *cp |= bit_masks[count] << (BITS_PER_BMUNIT - word_weight); #endif word_weight -= count; #ifdef MSBITFIRST if (paint_switch) *cp |= bit_masks[count] << word_weight; #endif break; } else { if (paint_switch) #ifndef MSBITFIRST *cp |= bit_masks[word_weight] << (BITS_PER_BMUNIT - word_weight); #else *cp |= bit_masks[word_weight]; #endif cp++; count -= word_weight; word_weight = BITS_PER_BMUNIT; } paint_switch = 1 - paint_switch; } } /* end for */ } void read_GF_index(fontp, hushcs) register struct font *fontp; wide_bool hushcs; { int hppp, vppp; ubyte ch, cmnd; register struct glyph *g; long checksum; fontp->read_char = read_GF_char; GF_file = fontp->file; if (debug & DBG_PK) Printf("Reading GF pixel file %s\n", fontp->filename); /* * Find postamble. */ Fseek(GF_file, (long) -4, 2); while (four(GF_file) != ((unsigned long) TRAILER << 24 | TRAILER << 16 | TRAILER << 8 | TRAILER)) Fseek(GF_file, (long) -5, 1); Fseek(GF_file, (long) -5, 1); for (;;) { ch = one(GF_file); if (ch != TRAILER) break; Fseek(GF_file, (long) -2, 1); } if (ch != GF_ID_BYTE) oops("Bad end of font file %s", fontp->fontname); Fseek(GF_file, (long) -6, 1); expect(POST_POST); Fseek(GF_file, sfour(GF_file), 0); /* move to postamble */ /* * Read postamble. */ expect(POST); (void) four(GF_file); /* pointer to last eoc + 1 */ (void) four(GF_file); /* skip design size */ checksum = four(GF_file); if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0 && !hushcs) Fprintf(stderr, "Checksum mismatch (dvi = %lu, gf = %lu) in font file %s\n", fontp->checksum, checksum, fontp->filename); hppp = sfour(GF_file); vppp = sfour(GF_file); if (hppp != vppp && (debug & DBG_PK)) Printf("Font has non-square aspect ratio %d:%d\n", vppp, hppp); (void) four(GF_file); /* skip min_m */ (void) four(GF_file); /* skip max_m */ (void) four(GF_file); /* skip min_n */ (void) four(GF_file); /* skip max_n */ /* * Prepare glyph array. */ fontp->glyph = (struct glyph *) xmalloc(256 * sizeof(struct glyph), "glyph array"); bzero((char *) fontp->glyph, 256 * sizeof(struct glyph)); /* * Read glyph directory. */ while ((cmnd = one(GF_file)) != POST_POST) { int addr; ch = one(GF_file); /* character code */ g = &fontp->glyph[ch]; switch (cmnd) { case CHAR_LOC: /* g->pxl_adv = sfour(GF_file); */ (void) four(GF_file); (void) four(GF_file); /* skip dy */ break; case CHAR_LOC0: /* g-s ~XDVI.BAK '  [XDVI]GF.C;1r>pxl_adv = one(GF_file) << 16; */ (void) one(GF_file); break; default: oops("Non-char_loc command found in GF preamble: %d", cmnd); } g->dvi_adv = fontp->dimconv * sfour(GF_file); addr = four(GF_file); if (addr != -1) g->addr = addr; if (debug & DBG_PK) Printf("Read GF glyph for character %d; dy = %d, addr = %d\n", ch, g->dvi_adv, addr); } } z*[XDVI]LINK_VMSXDVI.COM;12+,n . / 4M - 0123KPWO 56ZGk7H Rk8-_o9GHJ$! LINK_VMSXDVI.COM $! $ ON ERROR THEN GOTO EXIT $ ON CONTROL_Y THEN GOTO EXIT $ OLD_VERIFY = f$verify (0) $ dummy=f$verify ('old_verify') $! $!##################### Customizing section ############################# $! $ MAY_USE_DECC = 1 $! $! The following settings might need customization to your environment: $ XDVI_DEFAULT_FONTRES = 300 $ XDVI_DEFAULT_FONTPATH = "TEX_PKDIR" $ XDVI_DEFAULT_VFPATH = "TEX_VFDIR" $ XDVI_DEFAULT_FIGPATH = " /SYS$DISK:[]/TEX_INPUTS:" $ XDVI_DEFAULT_PSHEADERPATH = "TEX_POSTSCRIPT:/TEX_INPUTS:/SYS$LOGIN:/ " $! $! Process command line parameters requesting optional features: $ ps_dps = "" $ ps_gs = "" $ IF f$edit(p1,"UPCASE") .eqs. "DPS" THEN ps_dps = "PSDPS" $ IF f$edit(p1,"UPCASE") .eqs. "GS" THEN ps_gs = "PSGS" $! $!##################################################################### $! $! Find out the environment we are compiling on. $! This section sets up the appropiate compiler switches and include paths, $! and defines architecture specific symbols used for identification purpose. $! The produced binary files are named with the ARCH_CC_P symbol preceding $! the file name extension, to prevent unwanted mixing of files created $! with different compiler / CPU architecture environments on heterogenous $! VMS clusters: $ IF F$GETSYI("HW_MODEL") .GE. 1024 $ THEN $ ARCH_NAME="Alpha" $ ARCH_PREF="AXP_" $ HAVE_DECC_VAX = 0 $ USE_DECC_VAX = 0 $ ARCH_CC_P = ARCH_PREF $ WRITE SYS$OUTPUT "Linking on Alpha AXP using DECC RTL" $ ELSE $ ARCH_NAME="VAX" $ ARCH_PREF="VAX_" $ IF F$TRNLNM("DECC$LIBRARY_INCLUDE") .NES. "" $ THEN $! DECC for VAX available (and maybe VAXC, too!) $ HAVE_DECC_VAX = 1 $ IF HAVE_DECC_VAX .AND. MAY_USE_DECC $ THEN $! We use DECC: $ USE_DECC_VAX = 1 $ ARCH_CC_P = "''ARCH_PREF'DECC_" $ ELSE $! We use VAXC: $ USE_DECC_VAX = 0 $ ARCH_CC_P = "''ARCH_PREF'VAXC_" $ ENDIF $ ELSE $! only VAXC available $ HAVE_DECC_VAX = 0 $ USE_DECC_VAX = 0 $ ARCH_CC_P = "''ARCH_PREF'VAXC_" $ ENDIF $ IF USE_DECC_VAX $ THEN $ WRITE SYS$OUTPUT "Linking on VAX using DECC RTL" $ ELSE $ WRITE SYS$OUTPUT "Linking on VAX using VAXC RTL" $ ENDIF $ ENDIF $ LDFLAGS = "" $! $!##################################################################### $! $! Set up the requested optional features: $ ps_options = "" $ varobjs = "" $ IF ps_dps .EQS. "PSDPS" $ THEN $ varobjs = varobjs + "PSDPS.OBJ, " $ ENDIF $ IF ps_gs .EQS. "PSGS" $ THEN $ varobjs = varobjs + "PSGS.OBJ, " $ ENDIF $! $!##################################################################### $! $! Now, we are ready to `make' xdvi: $! $! Write the linker option file: $ OPEN/WRITE optfile VMS_XDVI.'ARCH_CC_P'OPT $ IF ps_dps .EQS. "PSDPS" $ THEN $ WRITE optfile "sys$share:xdps$dpsclientshr/share" $ WRITE optfile "sys$share:xdps$dpsbindingsshr/share" $ WRITE optfile "sys$share:xdps$dpslibshr/share" $ ENDIF $ WRITE optfile "sys$share:decw$xlibshr/share" $ IF (ARCH_NAME .EQS. "VAX") .AND. (.NOT. USE_DECC_VAX) $ THEN $ WRITE optfile "sys$share:vaxcrtl/share" $ ELSE $ ENDIF $ CLOSE optfile $ IF P1 .EQS. "DEBUG" THEN LDFLAGS = LDFLAGS + "/DEBUG" $! $! Final link step: $ LINK 'LDFLAGS' XDVI, - DVI_INIT, DVI_DRAW, - PSGS, - GF, PK, VF, - UTIL, FONT_OPEN, SPECIAL, - EVENTS, 'varobjs' VMS_XDVI.'ARCH_CC_P'OPT/OPTION $ DELETE/NOLOG VMS_XDVI.'ARCH_CC_P'OPT;* $! $EXIT: $ dummy=f$verify ('old_verify') $ EXIT *[XDVI]MAKE_VMS.COM;35+, ./ 4P %- 0123KPWO56~tn7Fn8Xip9GHJ$! MAKE_VMS.COM $! A DCL `Make' procedure for compiling and linking XDVI. $! $ ON ERROR THEN GOTO EXIT $ ON CONTROL_Y THEN GOTO EXIT $! $!##################### Customizing section ############################# $! $ MAY_USE_DECC = 1 $! $! The following settings might need customization to your environment: $ XDVI_DEFAULT_FONTRES = 300 $ XDVI_DEFAULT_FONTPATH = "TEX_PKDIR" $ XDVI_DEFAULT_VFPATH = "TEX_VFDIR" $ XDVI_DEFAULT_FIGPATH = " /SYS$DISK:[]/TEX_INPUTS:" $ XDVI_DEFAULT_PSHEADERPATH = "TEX_POSTSCRIPT:/TEX_INPUTS:/SYS$LOGIN:/ " $! $! Process command line parameters requesting optional features: $ ps_dps = "" $ ps_gs = "" $ IF GS .nes. "" THEN ps_gs = "PSGS" $ arg_cnt = 1 $ argloop: $ current_arg_name = "P''arg_cnt'" $ curr_arg = f$edit('current_arg_name',"UPCASE") $ IF curr_arg .eqs. "" THEN GOTO argloop_out $ IF curr_arg .eqs. "DPS" THEN ps_dps = "PSDPS" $ IF curr_arg .eqs. "GS" THEN ps_gs = "PSGS" $ IF curr_arg .eqs. "VAXC" THEN MAY_USE_DECC = 0 $ IF curr_arg .eqs. "DECC" THEN MAY_USE_DECC = 1 $ arg_cnt = arg_cnt + 1 $ GOTO argloop $ argloop_out: $! $!##################################################################### $! $! Find out the environment we are compiling on. $! This section sets up the appropiate compiler switches and include paths, $! and defines architecture specific symbols used for identification purpose. $! The produced binary files are named with the ARCH_CC_P symbol preceding $! the file name extension, to prevent unwanted mixing of files created $! with different compiler / CPU architecture environments on heterogenous $! VMS clusters: $ IF F$GETSYI("HW_MODEL") .GE. 1024 $ THEN $ ARCH_NAME="Alpha" $ ARCH_PREF="AXP_" $ HAVE_DECC_VAX = 0 $ USE_DECC_VAX = 0 $ ARCH_CC_P = ARCH_PREF $ CC="CC/stand=VAX/ansi" $ WRITE SYS$OUTPUT "Compiling on Alpha AXP using DECC" $ ELSE $ ARCH_NAME="VAX" $ ARCH_PREF="VAX_" $ IF F$TRNLNM("DECC$LIBRARY_INCLUDE") .NES. "" $ THEN $! DECC for VAX available (and maybe VAXC, too!) $ HAVE_DECC_VAX = 1 $ IF HAVE_DECC_VAX .AND. MAY_USE_DECC $ THEN $! We use DECC: $ USE_DECC_VAX = 1 $ ARCH_CC_P = "''ARCH_PREF'DECC_" $ CC="CC/DECC/stand=VAX" $ ELSE $! We use VAXC: $ USE_DECC_VAX = 0 $ ARCH_CC_P = "''ARCH_PREF'VAXC_" $ CC="CC/VAXC" $ ENDIF $ ELSE $! only VAXC available $ HAVE_DECC_VAX = 0 $ USE_DECC_VAX = 0 $ ARCH_CC_P = "''ARCH_PREF'VAXC_" $ CC="CC" $ ENDIF $ IF USE_DECC_VAX $ THEN $ WRITE SYS$OUTPUT "Compiling on VAX using DECC" $ ELSE $ WRITE SYS$OUTPUT "Compiling on VAX using VAXC" $ ENDIF $ ENDIF $ LDFLAGS = "" $ IF P1 .EQS. "DEBUG" THEN CC = CC + "/NOOPT/DEBUG" $ IF P1 .EQS. "DEBUG" THEN LDFLAGS = LDFLAGS + "/DEBUG" $ DEFINE X11 DECW$INCLUDE $ IF USE_DECC_VAX .AND. (F$TRNLNM("DECC$LIBRARY_INCLUDE") .NES. "") $ THEN $ DEFINE SYS DECC$LIBRARY_INCLUDE $ ELSE $ DEFINE SYS SYS$LIBRARY $ ENDIF $ IF ARCH_NAME .EQS. "Alpha" $ THEN $ DPS_OLD = "SYS$LIBRARY" $ ELSE $ DPS_OLD = "DECW$INCLUDE" $ ENDIF $ IF F$TRNLNM("XDPS$INCLUDE") .NES. "" $ THEN $ DEFINE DPS XDPS$INCLUDE,'DPS_OLD' $ ELSE $ DEFINE DPS 'DPS_OLD' $ ENDIF $ IF F$SEARCH("DPS:dpsXclient.h") .NES. "" $ THEN $! Can use MIT bindings! $ xdps_vmsbindings = "" $ ELSE $! Fall back to nonportable VMS bindings! $ xdps_vmsbindings = ", DPS_VMS" $ ENDIF $! $!##################################################################### $! $! Set up the requested optional features: $ ps_options = "" $ varobjs = "" $ IF ps_dps .EQS. "PSDPS" $ THEN $ ps_options = ps_options + ", PS_DPS" + xdps_vmsbindings $ varobjs = varobjs + "PSDPS, " $ WRITE SYS$OUTPUT "Including optional Postscript support via DPS" $ ENDIF $ IF ps_gs .EQS. "PSGS" $ THEN $ ps_options = ps_options + ", PS_GS" $ varobjs = varobjs + "PSGS.OBJ, " $ WRITE SYS$OUTPUT "Including optional Postscript support via GS" $ ENDIF $! $!##################################################################### $! $! Now, we are ready to `make' xdvi: $! $! Write the linker option file: $ OPEN/WRITE optfile VMS_XDVI.'ARCH_CC_P'OPT $ IF ps_dps .EQS. "PSDPS" $ THEN $ WRITE optfile "sys$share:xdps$dpsclientshr/share" $ IF xdps_vmsbindings .NES. "" THEN - WRITE optfile "sys$share:xdps$dpsbindingsshr/share" $ WRITE optfile "sys$share:xdps$dpslibshr/share" $ ENDIF $ WRITE optfile "sys$share:decw$xlibshr/share" $! WRITE optfile "sys$share:decw$xtlibshrr5/share" $ IF (ARCH_NAME .EQS. "VAX") .AND. (.NOT. USE_DECC_VAX) $ THEN $ WRITE optfile "sys$share:vaxcrtl/share" $ ENDIF $ CLOSE optf ile $! $! Combine the C preprocessor symbol definitions: $ SIZES72 = "72/79/86/104/124/149/179" $ SIZES85 = "85/93/102/122/147/176/212" $ SIZES118 = "118/129/142/170/204/245/294" $ SIZES240 = "240/263/288/346/415/498/597" $ SIZES300 = "300/328.6/360/432/518.4/622/746.4" $ SIZES360 = "360/394/432/518/622/746/895" $ SIZES400 = "400/438/480/576/691/829/995" $ SIZES600 = "600/657/720/864/1037/1244/1493" $! $ DEFAULT_SIZES = "SIZES''XDVI_DEFAULT_FONTRES'" $! $ FONTDEFINES = """DEFAULT_FONT_PATH=""""''XDVI_DEFAULT_FONTPATH'""""""," + - """DEFAULT_VF_PATH=""""''XDVI_DEFAULT_VFPATH'""""""," + - """DEFAULT_FONT_SIZES=""""''DEFAULT_SIZES'""""""," + - """DEFAULT_FIG_PATH=""""''XDVI_DEFAULT_FIGPATH'""""""," + - """DEFAULT_HEADER_PATH=""""''XDVI_DEFAULT_PSHEADERPATH'""""""" $! $ DEFS = "PS,PS_GS,VMS, NOTOOL, USE_PK, USE_GF, BDPI='XDVI_DEFAULT_FONTRES'" + - ", TEXXET, GREY, NON_BLOCKING_IO, MAKEPK'ps_options'" $! $ IF F$SEARCH("TEX$SUB:[PIXEL]1000.DIR") .NES. "" THEN - DEFS = DEFS + ",FONT5" $! $! Compile the XDVI sources: $ CC /DEFINE = ('DEFS') DVI_INIT.C $ CC /DEFINE = ('DEFS') DVI_DRAW.C $ CC /DEFINE = ('DEFS') GF.C $ CC /DEFINE = ('DEFS') PK.C $ CC /DEFINE = ('DEFS') VF.C $ CC /DEFINE = ('DEFS') UTIL.C $ CC /DEFINE = ('DEFS', 'FONTDEFINES') FONT_OPEN.C $ CC /DEFINE = ('DEFS') SPECIAL.C $ CC /DEFINE = ('DEFS') EVENTS.C $ IF ps_dps .NES. "" $ THEN $ CC /INCLUDE=DPS /DEFINE = ('DEFS') PSDPS.C $ ENDIF $ IF ps_gs .NES. "" $ THEN $ CC /DEFINE = ('DEFS') PSGS.C $ ENDIF $ CC /DEFINE = ('DEFS') XDVI.C $! $! Final link step: $ LINK 'LDFLAGS' XDVI.OBJ, - DVI_INIT.OBJ, DVI_DRAW.OBJ, - GF.OBJ, PK.OBJ, VF.OBJ, - UTIL.OBJ, FONT_OPEN.OBJ, SPECIAL.OBJ, - EVENTS.OBJ, 'varobjs' VMS_XDVI.'ARCH_CC_P'OPT/OPTION $ DELETE/NOLOG VMS_XDVI.'ARCH_CC_P'OPT;* $! $EXIT: $ EXIT *[XDVI]PATCHLEVEL.H;1+,Z]./ 4- 0@123KPWO56X 7X 8ě_o9GHJ#define PATCHLEVEL 20  *[XDVI]PK.C;1+,`,./ 4=- 0@123KPWO56ĘY7ĘY8]o9GHJ&/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTE: * xdvi is based on prior work, as noted in the modification history * in xdvi.c. */ #include "xdvi.h" /*** *** PK font reading routines. *** Public routines are read_PK_index and read_PK_char. ***/ #define PK_ID 89 #define PK_CMD_START 240 #define PK_X1 240 #define PK_X2 241 #define PK_X3 242 #define PK_X4 243 #define PK_Y 244 #define PK_POST 245 #define PK_NOOP 246 #define PK_PRE 247 static int PK_flag_byte; static unsigned PK_input_byte; static int PK_bitpos; static int PK_dyn_f; static int PK_repeat_count; static int PK_get_nyb(fp) register FILE *fp; { unsigned temp; if (PK_bitpos < 0) { PK_input_byte = one(fp); PK_bitpos = 4; } temp = PK_input_byte >> PK_bitpos; PK_bitpos -= 4; return (temp & 0xf); } static int PK_packed_num(fp) register FILE *fp; { int i,j; if ((i = PK_get_nyb(fp)) == 0) { do { j = PK_get_nyb(fp); ++i; } while (j == 0); while (i > 0) { j = (j << 4) | PK_get_nyb(fp); --i; } return (j - 15 + ((13 - PK_dyn_f) << 4) + PK_dyn_f); } else { if (i <= PK_dyn_f) return i; if (i < 14) return (((i - PK_dyn_f - 1) << 4) + PK_get_nyb(fp) + PK_dyn_f + 1); if (i == 14) PK_repeat_count = PK_packed_num(fp); else PK_repeat_count = 1; return PK_packed_num(fp); } } static void PK_skip_specials(fontp) register struct font *fontp; { int i,j; register FILE *fp = fontp->file; do { PK_flag_byte = one(fp); if (PK_flag_byte >= PK_CMD_START) { switch (PK_flag_byte) { case PK_X1 : case PK_X2 : case PK_X3 : case PK_X4 : i = 0; for (j = PK_CMD_START; j <= PK_flag_byte; ++j) i = (i << 8) | one(fp); while (i--) (void) one(fp); break; case PK_Y : (void) four(fp); case PK_POST : case PK_NOOP : break; default : oops("Unexpected %d in PK file %s", PK_flag_byte, fontp->filename); break; } } } while (PK_flag_byte != PK_POST && PK_flag_byte >= PK_CMD_START); } /* * Public routines */ static void #if NeedFunctionPrototypes read_PK_char(register struct font *fontp, wide_ubyte ch) #else /* !NeedFunctionPrototypes */ read_PK_char(fontp, ch) register struct font *fontp; ubyte ch; #endif /* NeedFunctionPrototypes */ { int i, j; int n; int row_bit_pos; Boolean paint_switch; BMUNIT *cp; register struct glyph *g; register FILE *fp = fontp->file; long fpwidth; BMUNIT word; int word_weight, bytes_wide; int rows_left, h_bit, count; g = &fontp->glyph[ch]; PK_flag_byte = g->x2; PK_dyn_f = PK_flag_byte >> 4; paint_switch = ((PK_flag_byte & 8) != 0); PK_flag_byte &= 0x7; if (PK_flag_byte == 7) n = 4; else if (PK_flag_byte > 3) n = 2; else n = 1; if (debug & DBG_PK) Printf("loading pk char %d, char type %d ", ch, n); /* * now read rest of character preamble */ if (n != 4) fpwidth = num(fp, 3); else { fpwidth = sfour(fp); (void) four(fp); /* horizontal escapement */ } (void) num(fp, n); /* vertical escapement */ { unsigned long w, h; w = num(fp, n); h = num(fp, n); if (w > 0x7fff || h > 0x7fff) oops("Character %d too large in file %s", ch, fontp->fontname); g->bitmap.w = w; g->bitmap.h = h; } g->x = snum(fp, n); g->y = snum(fp, n); g->dvi_adv = fontp->dimconv * fpwidth; if (debug & DBG_PK) { if (g->bitmap.w != 0) Printf(", size=%dx%d, dvi_adv=%ld", g->bitmap.w, g->bitmap.h, g->dvi_adv); Putchar('\n'); } alloc_bitmap(&g->bitmap); cp = (BMUNIT *) g->bitmap.bits; /* * read character data into *cp */ bytes_wide = ROUNDUP((int) g->bitmap.w, BITS_PER_BMUNIT) * BYTES_PER_BMUNIT; PK_bitpos = -1; if (PK_dyn_f == 14) { /* get raster by bits */ bzero(g->bitmap.bits, (int) g->bitmap.h * bytes_wide); for (i = 0; i < (int) g->bitmap.h; i++) { /* get all rows */ cp = ADD(g->bitmap.bits, i * bytes_wide); #ifndef MSBITFIRST row_bit_pos = -1; #else row_bit_pos = BITS_PER_BMUNIT; #endif for (j = 0; j < (int) g->bitmap.w; j++) { /* get one row */ if (--PK_bitpos < 0) { word = one(fp); PK_bitpos = 7; } #ifndef MSBITFIRST if (++row_bit_pos >= BITS_PER_BMUNIT) { cp++; row_bit_pos = 0; } #else if (--row_bit_pos < 0) { cp++; row_bit_pos = BITS_PER_BMUNIT - 1; } #endif if (word & (1 << PK_bitpos)) *cp |= 1 << row_bit_pos; } } } else { /* get packed raster */ rows_left = g->bitmap.h; h_bit = g->bitmap.w; PK_repeat_count = 0; word_weight = BITS_PER_BMUNIT; word = 0; while (rows_left > 0) { count = PK_packed_num(fp); while (count > 0) { if (count < word_weight && count < h_bit) { #ifndef MSBITFIRST if (paint_switch) word |= bit_masks[count] << (BITS_PER_BMUNIT - word_weight); #endif h_bit -= count; word_weight -= count; #ifdef MSBITFIRST if (paint_switch) word |= bit_masks[count] << word_weight; #endif count = 0; } else if (count >= h_bit && h_bit <= word_weight) { if (paint_switch) word |= bit_masks[h_bit] << #ifndef MSBITFIRST (BITS_PER_BMUNIT - word_weight); #else (word_weight - h_bit); #endif *cp++ = word; /* "output" row(s) */ for (i = PK_repeat_count * bytes_wide / BYTES_PER_BMUNIT; i > 0; --i) { *cp = *SUB(cp, bytes_wide); ++cp; } rows_left -= PK_repeat_count + 1; PK_repeat_count = 0; word = 0; word_weight = BITS_PER_BMUNIT; count -= h_bit; h_bit = g->bitmap.w; } else { if (paint_switch) #ifndef MSBITFIRST word |= bit_masks[word_weight] << (BITS_PER_BMUNIT - word_weight); #else word |= bit_masks[word_weight]; #endif *cp++ = word; word = 0; count -= word_weight; h_bit -= word_weight; word_weight = BITS_PER_BMUNIT; } } paint_switch = 1 - paint_switch; } if (cp != ((BMUNIT *) (g->bitmap.bits + bytes_wide * g->bitmap.h))) oops("Wrong number of bits stored: char. %d, font %s", ch, fontp->fontname); if (rows_left != 0 || h_bit != g->bitmap.w) oops("Bad pk file (%s), too many bits", fontp->fontname); } } void read_PK_index(fontp, hushcs) register struct font *fontp; wide_bool hushcs; { int hppp, vppp; long checksum; fontp->read_char = read_PK_char; if (debug & DBG_PK) Printf("Reading PK pixel file %s\n", fontp->filename); Fseek(fontp->file, (long) one(fontp->file), 1); /* skip comment */ (void) four(fontp->file); /* skip design size */ checksum = four(fontp->file); if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0 && !hushcs) Fprintf(stderr, "Checksum mismatch (dvi = %lu, pk = %lu) in font file %s\n", fontp->checksum, checksum, fontp->filename); hppp = sfour(fontp->file); vppp = sfour(fontp->file); if (hppp != vppp && (debug & DBG_PK)) Printf("Font has non-square aspect ratio %d:%d\n", vppp, hppp); /* * Prepare glyph array. */ fontp->glyph = (struct glyph *) xmalloc(256 * sizeof(struct glyph), "glyph array"); bzero((char *) fontp->glyph, 256 * sizeof(struct glyph)); /* * Read glyph directory (really a whole pass over the file). */ for (;;) { int bytes_left, flag_low_bits; unsigned int ch; PK_skip_specials(fontp); if (PK_flag_byte == PK_POST) break; flag_low_bits = PK_flag_byte & 0x7; if (flag_low_bits == 7) { bytes_left = four(fontp->file); ch = four(fontp->file); } else if (flag_low_bits > 3) { bytes_left = ((flag_low_bits - 4) << 16) + two(fontp->file); ch = one(fontp->file); } else { bytes_left = (flag_low_bits << 8) + one(fontp->file); ch = one(fontp->file); } fontp->glyph[ch].addr = ftell(fontp->file); fontp->glyph[ch].x2 = PK_flag_byte; Fseek(fontp->file, (long) bytes_left, 1); if (debug & DBG_PK) Printf("Scanning pk char %u, at %ld.\n", ch, fontp->glyph[ch].addr); } } "*[XDVI]PSDPS.C;1+,f .'/ 4'&- 0@123KPWO(568C78C8]o9GHJ /* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTES: * This code was originally written by Ricardo Telichevesky * (ricardo@rle-vlsi-mit.edu) and Luis Miguel Silveira * (lms@rle-vlsi-mit.edu). * It was largely influenced by similar code in the SeeTeX/XTeX * package by Dirk Grunwald (grunwald@colorado.edu). */ #include "xdvi.h" #include #include #include #include #if !defined(VMS) || !defined(DPS_VMS) #include #include #include #include #else /* VMS */ #define NBBY 8 /* number of bits in a byte */ #ifndef FD_SETSIZE #define FD_SETSIZE 256 #endif #ifndef _FD_MASK_ #define _FD_MASK_ typedef long fd_mask; #endif #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ #ifndef howmany #define howmany(x, y) (((x)+((y)-1))/(y)) #endif typedef struct fd_set { fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; } fd_set; #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) /*#include #include */ #include #define DPSContext dps$context_ptr #define DPSSpace dps$space_ptr #define DPSDefaultErrorProc dps$default_error_proc #define DPSSpaceFromContext dps$space_from_context /*#define DPSDestroyContext dps$destroy_context*/ extern void DPSDestroyContext(); #define DPSDestroySpace dps$destroy_space extern void DPSDestroySpace(); /*#define DPSFlushContext dps$flush_context*/ extern void DPSFlushContext(); /*#define DPSWritePostScript dps$write_postscript*/ extern void DPSWritePostScript(); /*#define DPSPrintf dps$printf*/ extern void DPSPrintf(); /*#define XDPSCreateSimpleContext xdps$create_simple_context*/ extern DPSContext XDPSCreateSimpleContext(); /*#define XDPSGetContextStatus xdps$get_context_status*/ extern int XDPSGetContextStatus(); #define select decc$select extern int select(); #endif /* VMS */ #ifdef X_NOT_STDC_ENV extern int errno; #endif /* * This string reads chunks (delimited by %%xdvimark). * The first character of a chunk tells whether a given chunk * is to be done within save/restore or not. * The `H' at the end tells it that the first group is a * header; i.e., no save/restore. */ #ifndef SUNHACK static char preamble[] = "\ /xdvi$line 81 string def \ /xdvi$run {{$error null ne {$error /newerror false put}if \ currentfile cvx stopped \ $error null eq {false} {$error /newerror get} ifelse and \ {handleerror} if} stopped pop} def \ /xdvi$dslen countdictstack def \ {currentfile read not {exit} if 72 eq \ {xdvi$run} \ {/xdvi$sav save def xdvi$run \ clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \ ifelse \ {(%%xdvimark) currentfile xdvi$line {readline} stopped \ {clear} {pop eq {exit} if} ifelse }loop \ (xdvi$Ack\n) print flush \ }loop\nH"; #else /* SUNHACK */ static char preamble[] = "\ /xdvi$line 81 string def \ /xdvi$run {{$error null ne {$error /newerror false put}if \ currentfile cvx stopped \ $error null eq {false} {$error /newerror get} ifelse and \ {handleerror} if} stopped pop} def \ /xdvi$dslen countdictstack def \ /xdvi$ack {{(%%xdvimark) currentfile xdvi$line {readline} stopped \ {clear} {pop eq {exit} if} ifelse }loop \ (xdvi$Ack\n) print flush} bind def \ errordict begin /interrupt{(xdvi$Int\n) print flush stop}bind def \ end \ {{currentfile read not {exit} if 72 eq \ {xdvi$run} \ {/xdvi$sav save def xdvi$run \ clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \ ifelse \ xdvi$ack \ }loop \ xdvi$ack \ }loop\nH"; #endif /* SUNHACK */ extern char psheader[]; extern int psheaderlen; #define postscript resource._postscript /* global procedures (besides initDPS) */ static void toggleDPS ARGS((void)); static void destroyDPS ARGS((void)); static void interruptDPS ARGS((void)); static void endpageDPS ARGS((void)); static void drawbeginDPS ARGS((int, int, char *)); static void drawrawDPS ARGS((char *)); static void drawfileDPS ARGS((_Xconst char *, FILE *)); static void drawendDPS ARGS((char *)); static void beginheaderDPS ARGS((void)); static void endheaderDPS ARGS((void)); static void newdocDPS ARGS((void)); static struct psprocs dps_procs = { /* toggle */ toggleDPS, /* destroy */ destroyDPS, /* interrupt */ interruptDPS, /* endpage */ endpageDPS, /* drawbegin */ drawbeginDPS, /* drawraw */ drawrawDPS, /* drawfile */ drawfileDPS, /* drawend */ drawendDPS, /* beginheader */ beginheaderDPS, /* endheader */ endheaderDPS, /* newdoc */ newdocDPS}; static DPSContext DPS_ctx = NULL; static DPSSpace DPS_space = NULL; static int DPS_mag; /* magnification currently in use */ static int DPS_shrink; /* shrink factor currently in use */ static Boolean DPS_active; /* if we've started a page */ static int DPS_pending; /* number of ack's we're expecting */ static Boolean DPS_in_header; /* if we're sending a header */ static Boolean DPS_in_doc; /* if we've sent header information */ #if 0 static void DPSErrorProcHandler(); #else #define DPSErrorProcHandler DPSDefaultErrorProc #endif static char ackstr[] = "xdvi$Ack\n"; static char intstr[] = "xdvi$Int\n"; #define LINELEN 81 #define BUFLEN (LINELEN + sizeof(ackstr)) static char line[BUFLEN + 1]; static char *linepos = line; static void TextProc(ctxt, buf, count) DPSContext ctxt; char *buf; unsigned long count; { int i; char *p; char *p0; while (count > 0) { i = line + BUFLEN - linepos; if (i > count) i = count; (void) bcopy(buf, linepos, i); linepos += i; buf += i; count -= i; p0 = line; for (;;) { if (p0 >= linepos) { linepos = line; break; } p = memchr(p0, '\n', linepos - p0); if (p == NULL) { if (p0 != line) { (void) bcopy(p0, line, linepos - p0); linepos -= p0 - line; } else if (linepos == line + BUFLEN) { char c; c = line[LINELEN]; line[LINELEN] = '\0'; Printf("DPS: %s\n", line); line[LINELEN] = c; linepos -= LINELEN; (void) bcopy(line + LINELEN, line, linepos - line); } break; } if (p >= p0 + 8 && memcmp(p - 8, ackstr, 9) == 0) { --DPS_pending; if (debug & DBG_PS) Printf("Got DPS ack; %d pending.\n", DPS_pending); ++p; (void) bcopy(p, p - 9, linepos - p); linepos -= 9; continue; } #ifdef SUNHACK if (p >= p0 + 8 && memcmp(p - 8, intstr, 9) == 0) { DPS_pending = 1; if (debug & DBG_PS) Puts("Got DPS int."); ++p; (void) bcopy(p, p - 9, linepos - p); linepos -= 9; continue; } #endif /* SUNHACK */ *p = '\0'; Printf("DPS: %s\n", p0); p0 = p + 1; } } } /*---------------------------------------------------------------------------* waitack() Arguments: none. Returns: (void) Description: Waits until the requisite number of acknowledgements has been received from the context. +----------------------------------------------------------------------------*/ static void waitack() { while (DPS_pending > 0) { (void) XEventsQueued(DISP, QueuedAfterFlush); allow_can = False; read_events(False); allow_can = True; if (DPS_ctx == NULL) break; /* if interrupt occurred */ } } /*---------------------------------------------------------------------------* initDPS() Arguments: (none) Returns: (void) Side-Effects: DPS_ctx may be set as well as other static variables. Description: Initializes variables from the application main loop. Checks to see if a connection to the DPS server can be opened. +----------------------------------------------------------------------------*/ Boolean initDPS() { /* now try tMg)~XDVI.BAKf  [XDVI]PSDPS.C;1'q(o create a context */ DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, ruleGC, 0, 0, TextProc, DPSDefaultErrorProc, NULL); if (DPS_ctx == NULL) return False; DPS_mag = DPS_shrink = -1; DPS_active = False; DPS_pending = 1; DPS_space = DPSSpaceFromContext(DPS_ctx); DPSWritePostScript(DPS_ctx, preamble, sizeof(preamble) - 1); DPSWritePostScript(DPS_ctx, psheader, psheaderlen); DPSPrintf(DPS_ctx, "matrix setmatrix stop\n%%%%xdvimark\n"); DPSFlushContext(DPS_ctx); psp = dps_procs; return True; } /*---------------------------------------------------------------------------* toggleDPS() Arguments: none Returns: (void) Side-Effects: psp.drawbegin is changed. Description: Used to toggle the rendering of PostScript by the DPS server +----------------------------------------------------------------------------*/ static void toggleDPS() { if (debug & DBG_PS) Puts("Toggling DPS on or off"); if (postscript) psp.drawbegin = drawbeginDPS; else { interruptDPS(); psp.drawbegin = drawbegin_none; } } /*---------------------------------------------------------------------------* destroyDPS() Arguments: none Returns: (void) Side-Effects: the context is nulled out and destroyed. Description: Close the connection to the DPS server; used when rendering is terminated in any way. +----------------------------------------------------------------------------*/ static void destroyDPS() { if (debug & DBG_PS) Puts("Calling destroyDPS()"); if (linepos > line) { *linepos = '\0'; Printf("DPS: %s\n", line); } DPSDestroySpace(DPS_space); psp = no_ps_procs; scanned_page = scanned_page_bak = scanned_page_reset; } /*---------------------------------------------------------------------------* interruptDPS() Arguments: none Returns: (void) Side-Effects: the context may be nulled out and destroyed. Description: Close the connection to the DPS server; used when rendering is terminated because of an interruption in the viewing of the current page. +----------------------------------------------------------------------------*/ static void interruptDPS() { #ifdef SUNHACK static Boolean interrupting = False; #endif if (debug & DBG_PS) Puts("Running interruptDPS()"); #ifndef SUNHACK if (DPS_pending > 0) #else /* SUNHACK */ if (DPS_pending > 0 && !interrupting) #endif /* SUNHACK */ { if (debug & DBG_PS) Printf("interruptDPS: code is now %d\n", XDPSGetContextStatus(DPS_ctx)); /* * I would really like to use DPSInterruptContext() here, but (at least * on an RS6000) I can't get it to work. */ #ifdef SUNHACK /* * On the other hand, under OpenWindows 3.3 (at least), destroying and * re-creating contexts has a nasty habit of crashing the server. */ interrupting = True; DPSInterruptContext(DPS_ctx); DPS_pending = 32767; DPSPrintf(DPS_ctx, "%%%%xdvimark\n"); DPSFlushContext(DPS_ctx); DPS_active = False; waitack(); interrupting = False; #else /* SUNHACK */ DPSDestroyContext(DPS_ctx); DPS_ctx = NULL; DPS_active = False; DPS_pending = 0; #endif /* SUNHACK */ } } /*---------------------------------------------------------------------------* endpageDPS() Arguments: none Returns: (void) Side-Effects: the DPS_active variable is cleared. Description: Should be called at the end of a page to end this chunk for the DPS server. +----------------------------------------------------------------------------*/ static void endpageDPS() { if (DPS_active) { if (debug & DBG_PS) Puts("Endpage sent to context"); DPSPrintf(DPS_ctx, "stop\n%%%%xdvimark\n"); DPSFlushContext(DPS_ctx); DPS_active = False; waitack(); } } /*---------------------------------------------------------------------------* drawbeginDPS () Arguments: xul, yul - coordinates of the upper left corner of the figure cp - string with the bounding box line data Returns: (void) Side-Effects: DPS_ctx is set is set and connection to DPS server is opened. Description: Opens a connection to the DPS server and send in the preamble and the bounding box information after correctly computing resolution factors. In case no rendering is to be done, outlines the figure. An outline is also generated whenever the a context cannot be allocated +----------------------------------------------------------------------------*/ static void drawbeginDPS(xul, yul, cp) int xul, yul; char *cp; { /* static char faulty_display_vs[] * ="DECWINDOWS DigitalEquipmentCorporation UWS4.2LA"; */ if (debug & DBG_PS) Printf("Begin drawing at xul= %d, yul= %d.\n", xul, yul); /* we assume that I cannot write the file to the postscript context */ if (DPS_ctx == NULL) { DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, ruleGC, 0, 0, TextProc, DPSErrorProcHandler, DPS_space); if (DPS_ctx == NULL) { psp = no_ps_procs; draw_bbox(); return; } DPSWritePostScript(DPS_ctx, preamble, sizeof(preamble) - 1); /* it already has psheader */ DPSPrintf(DPS_ctx, "matrix setmatrix stop\n%%%%xdvimark\n"); DPS_mag = DPS_shrink = -1; DPS_active = False; DPS_pending = 1; } if (!DPS_active) { /* send initialization to context */ if (magnification != DPS_mag) { DPSPrintf(DPS_ctx, "H TeXDict begin /DVImag %d 1000 div def \ end stop\n%%%%xdvimark\n", DPS_mag = magnification); ++DPS_pending; } if (mane.shrinkfactor != DPS_shrink) { DPSPrintf(DPS_ctx, "H TeXDict begin %d %d div dup \ /Resolution X /VResolution X \ end stop\n%%%%xdvimark\n", pixels_per_inch, DPS_shrink = mane.shrinkfactor); ++DPS_pending; } DPSPrintf(DPS_ctx, " TeXDict begin\n"); DPS_active = True; ++DPS_pending; } DPSPrintf(DPS_ctx, "%d %d moveto\n", xul, yul); DPSPrintf(DPS_ctx, "%s\n", cp); } /*---------------------------------------------------------------------------* drawrawDPS() Arguments: cp - the raw string to be sent to the postscript interpreter Returns: (void) Side-Effects: (none) Description: If there is a valid postscript context, just send the string to the interpreter, else leave. +----------------------------------------------------------------------------*/ static void drawrawDPS(cp) char *cp; { if (!DPS_active) return; if (debug & DBG_PS) Printf("Sending raw PS to context: %s\n", cp); read_events(False); DPSPrintf(DPS_ctx,"%s\n", cp); } /*---------------------------------------------------------------------------* drawfileDPS() Arguments: cp - string with the postscript file pathname psfile - opened file pointer Returns: (void) Side-Effects: none Description: Postscript file containing the figure is opened and sent to the DPS server. +----------------------------------------------------------------------------*/ static void drawfileDPS(cp, psfile) _Xconst char *cp; FILE *psfile; { char buffer[1025]; int blen; if (!DPS_active) { Fclose(psfile); ++n_files_left; return; } if (debug & DBG_PS) Printf("sending file %s\n", cp); allow_can = False; for (;;) { read_events(False); if (canit || !DPS_active) break; /* alt_canit is not a factor here */ blen = fread(buffer, sizeof(char), 1024, psfile); if (blen == 0) break; DPSWritePostScript(DPS_ctx, buffer, blen); } Fclose(psfile); ++n_files_left; allow_can = True; if (canit) { interruptDPS(); longjmp(canit_env, 1); } } /*---------------------------------------------------------------------------* drawendDPS() Arguments: cp - string with indication of the end of the special Returns: (void) Side-Effects: none Description: Sends the indication of end of the figure PostScript code. +----------------------------------------------------------------------------*/ static void drawendDPS(cp) char *cp; { if (!DPS_active) return; if (debug & DBG_PS) Printf("End PS: %s\n", cp); read_events(False); DPSPrintf(DPS_ctx,"%s\n", cp); } /*---------------------------------------------------------------------------* beginheaderDPS() Arguments: none Returns: (void) Description: Prepares the PostScript interpreter for receipt of header code. +----------------------------------------------------------------------------*/ static void beginheaderDPS() { if (debug & DBG_PS) Puts("Running beginheaderDPS()"); if (DPS_active) { if (!DPS_in_header) oops("Internal error in beginheaderDPS().\n"); return; } DPS_in_header = True; if (DPS_in_doc) DPSPrintf(DPS_ctx, "H"); else { DPSPrintf(DPS_ctx, "Hsave /xdvi$doc exch def\n"); DPS_in_doc = True; } DPS_active = True; ++DPS_pending; } /*---------------------------------------------------------------------------* endheaderDPS() Arguments: none Returns: (void) Description: Prepares the PostScript interpreter for receipt of header code. +----------------------------------------------------------------------------*/ static void endheaderDPS() { static _Xconst char str[] = ""; if (debug & DBG_PS) Puts("Running endheaderDPS()"); if (DPS_active) { DPSPrintf(DPS_ctx, "stop\n%%%%xdvimark\n"); DPS_active = False; DPS_in_header = False; DPSFlushContext(DPS_ctx); waitack(); } } /*---------------------------------------------------------------------------* newdocDPS() Arguments: none Returns: (void) Description: Clears out headers stored from the previous document. +----------------------------------------------------------------------------*/ static void newdocDPS() { if (debug & DBG_PS) Puts("Running newdocDPS()"); if (DPS_in_doc) { DPSPrintf(DPS_ctx, "H xdvi$doc restore stop\n%%%%xdvimark\n"); ++DPS_pending; DPS_mag = DPS_shrink = -1; DPS_in_doc = False; } } *[XDVI]PSGS.C;111+,h?.E/pX 4REE- 0D123KPWOF56pNn70n80hp9GHJ/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "xdvi.h" #include #ifndef VMS #include #else #include #include #include #define ERR_SIGNAL(s) if(!((s) & 1))lib$signal((s), 0, 0) #define XtEFN 23 /* structure to describe section of file to send to ghostscript */ struct record_list { char *buffer; unsigned int len; struct record_list *next; }; static Boolean changed; static Boolean busy; static struct record_list *ps_input; /* pointer it gs input queue */ static unsigned int bytes_left; /* bytes left in section */ static int interpreter_input; /* fd gs stdin, -1 if None */ static int interpreter_output; /* fd gs stdout, -1 if None */ static short interpreter_input_iosb[4]; /* I/O Status Block s*/ static short interpreter_output_iosb[4]; /* for each mailbox */ static char *output_buffer; /* pointer to output buffer */ static char *input_buffer; /* pointer to input buffer */ static void StartInterpreter(); #endif /* VMS */ #include /* if POSIX O_NONBLOCK is not available, use O_NDELAY */ #if !defined(O_NONBLOCK) && defined(O_NDELAY) #define O_NONBLOCK O_NDELAY #endif /* Condition for retrying a write */ #include #ifdef X_NOT_STDC_ENV extern int errno; #endif #ifdef EWOULDBLOCK #ifdef EAGAIN #define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN) #else /* EAGAIN */ #define AGAIN_CONDITION (errno == EWOULDBLOCK) #endif /* EAGAIN */ #else /* EWOULDBLOCK */ #ifdef EAGAIN #define AGAIN_CONDITION (errno == EAGAIN) #endif /* EAGAIN */ #endif /* EWOULDBLOCK */ #ifdef _POSIX_SOURCE #include #endif #ifndef PATH_MAX #define PATH_MAX 512 #endif #ifdef STREAMSCONN #include #endif #if HAS_SIGIO #include #ifndef FASYNC #undef HAS_SIGIO #define HAS_SIGIO 0 #endif #endif #ifdef VFORK #if VFORK == include #include #endif #else #define vfork fork #endif #ifndef X_GETTIMEOFDAY #ifdef VMS #include #endif #define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*) NULL) #endif #ifndef timercmp #define timercmp(a, b, cmp) ((a)->tv_sec cmp (b)->tv_sec || \ ((a)->tv_sec == (b)->tv_sec && (a)->tv_usec cmp (b)->tv_usec)) #endif /* timercmp */ #define postscript resource._postscript #define fore_Pixel resource._fore_Pixel #define back_Pixel resource._back_Pixel /* global procedures (besides initGS) */ static void toggle_gs ARGS((void)); static void destroy_gs ARGS((void)); static void interrupt_gs ARGS((void)); static void endpage_gs ARGS((void)); static void drawbegin_gs ARGS((int, int, char *)); static void drawraw_gs ARGS((char *)); static void drawfile_gs ARGS((_Xconst char *, FILE *)); static void drawend_gs ARGS((char *)); static void beginheader_gs ARGS((void)); static void endheader_gs ARGS((void)); static void newdoc_gs ARGS((void)); static struct psprocs gs_procs = { /* toggle */ toggle_gs, /* destroy */ destroy_gs, /* interrupt */ interrupt_gs, /* endpage */ endpage_gs, /* drawbegin */ drawbegin_gs, /* drawraw */ drawraw_gs, /* drawfile */ drawfile_gs, /* drawend */ drawend_gs, /* beginheader */ beginheader_gs, /* endheader */ endheader_gs, /* newdoc */ newdoc_gs}; static int std_in[2]; static int std_out[2]; #define GS_in (std_in[1]) #define GS_out (std_out[0]) /* some arguments are filled in later */ static char arg4[] = "-dDEVICEWIDTH=xxxxxxxxxx"; static char arg5[] = "-dDEVICEHEIGHT=xxxxxxxxxx"; static char *argv[] = {NULL, "-sDEVICE=x11", "-dNOPAUSE", "-q", arg4, arg5, "-dDEVICEXRESOLUTION=72", "-dDEVICEYRESOLUTION=72", NULL, NULL, NULL}; static pid_t GS_pid = -1; static unsigned int GS_page_w; /* how big our current page is */ static unsigned int GS_page_h; static int GS_mag; /* magnification currently in use */ static int GS_shrink; /* shrink factor currently in use */ static Boolean GS_active; /* if we've started a page yet */ static int GS_pending; /* number of ack's we're expecting */ static Boolean GS_sending; /* if we're in the middle of sendps() */ static Boolean GS_in_header; /* if we're sending a header */ static Boolean GS_in_doc; /* if we've send header information */ static Boolean GS_pending_int; /* if interrupt rec'd while in sendps() */ static Boolean GS_old; /* if we're using gs 2.xx */ static Atom gs_atom; static Atom gs_colors_atom; #define Landscape 90 /* * Our replacement for setenv(), which is not available on all systems. */ #ifndef HAVE_SETENV /* define this if you're a performance freak and if your system has setenv. */ #define setenv(var, str, repl) _setenv(var, str) /* repl always True */ extern char **environ; static void _setenv(var, str) _Xconst char *var; _Xconst char *str; { int len1; int len2; char *newvar; char **linep; static Boolean malloced = False; len1 = strlen(var); len2 = strlen(str) + 1; newvar = xmalloc((unsigned int) len1 + len2 + 1, "_setenv"); (void) bcopy(var, newvar, len1); newvar[len1++] = '='; (void) bcopy(str, newvar + len1, len2); for (linep = environ; *linep != NULL; ++linep) if (memcmp(*linep, newvar, len1) == 0) { *linep = newvar; return; } len1 = linep - environ; if (malloced) { environ = (char **) realloc((char *) environ, (unsigned int) (len1 + 2) * sizeof(char *)); if (environ == NULL) oops("! Cannot allocate %d bytes for string list in _setenv.\n", (len1 + 2) * sizeof(char *)); } else { linep = (char **) xmalloc((unsigned int)(len1 + 2) * sizeof(char *), "string list in _setenv"); (void) bcopy((char *) environ, (char *) linep, len1 * sizeof(char *)); environ = linep; malloced = True; } environ[len1] = newvar; environ[len1 + 1] = NULL; } #endif /* HAVE_SETENV */ /* * ghostscript I/O code. This should send PS code to ghostscript, * receive acknowledgements, and receive X events in the meantime. * It also checks for SIGPIPE errors. */ #ifndef VMS #ifndef STREAMSCONN static int numfds; static fd_set readfds; static fd_set writefds; #define XDVI_ISSET(a, b, c) FD_ISSET(a, b) #else /* STREAMSCONN */ struct pollfd fds[3] = {{0, POLLOUT, 0}, {0, POLLIN, 0}, {0, POLLIN, 0}}; #define XDVI_ISSET(a, b, c) (fds[c].revents) #endif /* STREAMSCONN */ #else /* VMS */ #include #include #include #include$ #include #include #include "vms_types.h" static int wefn = 0; static int tefn = 0; static int wtime[2]= {-1*2500000,-1}; static int ttime[2]= {-1*10000000,-1}; static void read_from_gs(); static void Output(); static void waitack(waittime) int waittime; { int state; ttime[0] = waittime * -1 * 10000000; if (!wefn) lib$get_ef(&wefn); if (!tefn) lib$get_ef(&tefn); sys$setimr(tefn,&ttime,0,0,0); if (GS_pending == 0) return; while (GS_pending > 0) { if (waittime != 0) { sys$readef(tefn,&state); if ((1 << (tefn % 32)) & state) { destroy_gs(); break; } } sys$setimr(wefn,&wtime,0,0,0); sys$wflor(wefn,(1 << (XtEFN % 32)) | (1 << (wefn % 32)) ); sys$cantim(wefn,0); } } /* Stop the interperter, if present, and remove any Input sources. */ /* Also reset the busy state. */ static void StopInterpreter() { int ret; if (GS_pid >= 0) { ret = sys$delprc(&GS_pid, 0); if(ret != SS$_NORMAL && ret != SS$_NONEXPR)lib$signal(ret, 0, 0); GS_pid = -1; } if (interpreter_input >= 0) { (void) sys$dassgn(interpreter_input); interpreter_input = -1; while (ps_input) { struct record_list *ps_old = ps_input; ps_input = ps_old->next; free((char *)ps_old->buffer); free((char *)ps_old); } } if (interpreter_output >= 0) { (void) sys$dassgn(interpreter_output); interpreter_output = -1; } busy = False; XDefineCursor(DISP, mane.win, ready_cursor); } #endif /* VMS */ #define LINELEN 81 static char line[LINELEN + 1]; static char *linepos = line; static char ackstr[] = "\347\310\376"; static char oldstr[] = "\347\310\375"; static void showto(q) char *q; { char *p = line; char *p1; while (p < q) { p1 = memchr(p, '\n', q - p); if (p1 == NULL) p1 = q; *p1 = '\0'; Printf("gs: %s\n", p); p = p1 + 1; } } static void read_from_gs() { int bytes; char *line_end; char *p; #ifndef VMS bytes = read(GS_out, linepos, line + LINELEN - linepos); if (bytes < 0) return; #else bytes = interpreter_output_iosb[1]; #endif line_end = linepos + bytes; /* Check for ack strings */ for (p = line; p < line_end - 2; ++p) { p = memchr(p, '\347', line_end - p - 2); if (p == NULL) break; if (memcmp(p, ackstr, 3) == 0) { --GS_pending; if (debug & DBG_PS) Printf("Got GS ack; %d pending.\n", GS_pending); } else if (memcmp(p, oldstr, 3) == 0) { if (debug & DBG_PS) Puts("Using old GS version."); GS_old = True; } else continue; showto(p); p += 3; (void) bcopy(p, line, line_end - p); line_end -= p - line; linepos = p = line; --p; } *line_end = '\0'; p = rindex(linepos, '\n'); if (p != NULL) { ++p; showto(p); (void) bcopy(p, line, line_end - p); line_end -= p - line; } linepos = line_end; /* * Normally we'd hold text until a newline character, but the buffer * is full. So we flush it, being careful not to cut up an ack string. */ if (linepos >= line + LINELEN) { p = line + LINELEN; if ((*--p != '\347' && *--p != '\347' && *--p != '\347') || (memcmp(p, ackstr, line + LINELEN - p) != 0) && (memcmp(p, oldstr, line + LINELEN - p) != 0)) p = line + LINELEN; *p = '\0'; Printf("gs: %s\n", line); *p = '\347'; linepos = line; while (p < line + LINELEN) *linepos++ = *p++; } } #ifndef VMS /* * For handling of SIGPIPE signals from sendps() */ static Boolean sigpipe_error = False; /* ARGSUSED */ static void gs_sigpipe_handler(sig, code, scp, addr) int sig; int code; struct sigcontext *scp; char *addr; { sigpipe_error = True; } #ifdef _POSIX_SOURCE static struct sigaction sigpipe_handler_struct; /* initialized to {gs_sigpipe_handler, (sigset_t) 0, 0} in initGS */ #endif /* * Clean up after sendps() */ /* * This actually sends the bytes to ghostscript. */ static void sendps(cp, len) _Xconst char *cp; int len; { int bytes; #ifdef _POSIX_SOURCE struct sigaction orig; #else void (*orig)(); #endif #ifdef STREAMSCONN int retval; #endif if (GS_pid < 0) return; #ifdef _POSIX_SOURCE (void) sigaction(SIGPIPE, &sigpipe_handler_struct, &orig); #else orig = signal(SIGPIPE, gs_sigpipe_handler); #endif sigpipe_error = False; GS_sending = True; #if HAS_SIGIO (void) fcntl(ConnectionNumber(DISP), F_SETFL, fcntl(ConnectionNumber(DISP), F_GETFL, 0) & ~FASYNC); #endif #ifndef STREAMSCONN FD_ZERO(&readfds); FD_ZERO(&writefds); #endif for (;;) { #ifndef STREAMSCONN FD_SET(ConnectionNumber(DISP), &readfds); FD_SET(GS_in, &writefds); FD_SET(GS_out, &readfds); if (select(numfds, &readfds, &writefds, (fd_set *) NULL, (struct timeval *) NULL) < 0 && errno != EINTR) { perror("select (xdvi gs_send)"); break; } #else /* STREAMSCONN */ for (;;) { retval = poll(fds, XtNumber(fds), -1); if (retval >= 0 || errno != EAGAIN) break; } if (retval < 0) { perror("poll (xdvi gs_send)"); break; } #endif /* STREAMSCONN */ if (XDVI_ISSET(GS_out, &readfds, 1)) read_from_gs(); if (XDVI_ISSET(GS_in, &writefds, 0)) { bytes = write(GS_in, cp, len); if (bytes == -1) { if (!AGAIN_CONDITION) perror("xdvi gs_send"); } else { cp += bytes; len -= bytes; if (len == 0) break; } if (sigpipe_error) break; } if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) { allow_can = False; read_events(False); allow_can = True; if (GS_pid < 0) break; /* if timeout occurred */ } } #if HAS_SIGIO (void) fcntl(ConnectionNumber(DISP), F_SETFL, fcntl(ConnectionNumber(DISP), F_GETFL, 0) | FASYNC); #endif /* put back generic handler for SIGPIPE */ #ifdef _POSIX_SOURCE (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL); #else (void) signal(SIGPIPE, orig); #endif if (!GS_in_header) post_send(); } /* * Wait for acknowledgement from gs. */ static void waitack(waittime) int waittime; { struct timeval tv; struct timeval tv2; #ifndef STREAMSCONN struct timeval *timeout = (struct timeval *) NULL; #else int timeout = -1; int retval; #endif #if HAS_SIGIO int oldflags; #endif if (GS_pending == 0) return; #if HAS_SIGIO oldflags = fcntl(ConnectionNumber(DISP), F_GETFL, 0); (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags & ~FASYNC); #endif if (waittime != 0) { (void) X_GETTIMEOFDAY(&tv); tv.tv_sec += waittime; #ifndef STREAMSCONN timeout = &tv2; #endif } #ifndef STREAMSCONN FD_ZERO(&readfds); #endif while (GS_pending > 0) { if (waittime != 0) { (void) X_GETTIMEOFDAY(&tv2); #ifndef STREAMSCONN if (!timercmp(&tv2, &tv, <)) { destroy_gs(); break; } tv2.tv_sec = tv.tv_sec - tv2.tv_sec; tv2.tv_usec = tv.tv_usec + 1000000 - tv2.tv_usec; if (tv2.tv_usec >= 1000000) tv2.tv_usec -= 1000000; else --tv2.tv_sec; #else timeout = 1000 * (int) (tv.tv_sec - tv2.tv_sec) + ((long) tv.tv_usec - (long) tv2.tv_usec) / 1000; if (timeout <= 0) { destroy_gs(); break; } #endif } #ifndef STREAMSCONN FD_SET(ConnectionNumber(DISP), &readfds); FD_SET(GS_out, &readfds); if (select(numfds, &readfds, (fd_set *) NULL, (fd_set *) NULL, timeout) < 0 && errno != EINTR) { perror("select (xdvi gs_waitack)"); break; } #else /* STREAMSCONN */ for (;;) { retval = poll(fds + 1, XtNumber(fds) - 1, timeout); if (retval >= 0 || errno != EAGAIN) break; } if (retval < 0) { perror("poll (xdvi gs_waitack)"); break; } #endif /* STREAMSCONN */ if (XDVI_ISSET(GS_out, &readfds, 1)) read_from_gs(); if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) { allow_can = False; read_events(False); allow_can = True; } } #if HAS_SIGIO (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags); #endif /* If you bail out here, change the call in interrupt_gs(). */ } #else int sendps( _Xconst char *cp, int len ); #endif /* VMS */ static void post_send() { GS_sending = False; if (interpreter_output_iosb[0] != SS$_NORMAL) { Fputs("ghostscript died unexpectedly.\n", stderr); destroy_gs(); draw_bbox(); } if (GS_pending_int) { GS_pending_int = False; interrupt_gs(); } } /* * Fork a process to run ghostscript. This is done using the * x11 device (which needs to be compiled in). Normally the x11 * device uses ClientMessage events to communicate with the calling * program, but we don't do this. The reason for using the ClientMessage * events is that otherwise ghostview doesn't know when a non-conforming * postscript program calls showpage. That doesn't affect us here, * since in fact we disable showpage. */ Boolean initGS() { char buf[100]; /* * This string reads chunks (delimited by %%xdvimark). * The first character of a chunk tells whether a given chunk * is to be done within save/restore or not. * The `H' at the end tells it that the first group is a * header; i.e., no save/restore. * `execute' is unique to ghostscript. */ static _Xconst char str1[] = "\ /xdvi$run {$error /newerror false put {currentfil"e cvx execute} stopped pop} def \ /xdvi$ack (\347\310\376) def \ /xdvi$dslen countdictstack def \ {{currentfile read pop dup 10 eq {pop}{exit} ifelse} loop 72 eq \ {xdvi$run} \ {/xdvi$sav save def xdvi$run \ clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \ ifelse \ {(%%xdvimark) currentfile =string {readline} stopped \ {clear $error /newerror false put} {pop eq {exit} if} ifelse }loop \ flushpage xdvi$ack print flush \ }loop\nH"; static _Xconst char str2[] = "[0 1 1 0 0 0] concat\n\ revision 300 lt{(\347\310\375) print flush}if\n\ stop\n%%xdvimark\n"; gs_atom = XInternAtom(DISP, "GHOSTVIEW", False); /* send bpixmap, orientation, bbox (in pixels), and h & v resolution */ Sprintf(buf, "%ld %d 0 0 %u %u 72 72", None, /* bpixmap */ Landscape, /* orientation */ GS_page_h = page_h, GS_page_w = page_w); XChangeProperty(DISP, mane.win, gs_atom, XA_STRING, 8, PropModeReplace, (unsigned char *) buf, strlen(buf)); gs_colors_atom = XInternAtom(DISP, "GHOSTVIEW_COLORS", False); Sprintf(buf, "%s %ld %ld", resource.gs_palette, fore_Pixel, back_Pixel); XChangeProperty(DISP, mane.win, gs_colors_atom, XA_STRING, 8, PropModeReplace, (unsigned char *) buf, strlen(buf)); XSync(DISP, False); /* update the window */ Sprintf(arg4 + 14, "%u", GS_page_w); Sprintf(arg5 + 15, "%u", GS_page_h); #ifdef VMS StartInterpreter(); #else if (xpipe(std_in) != 0 || xpipe(std_out) != 0) { perror("[xdvi] pipe"); return False; } Fflush(stderr); /* to avoid double flushing */ GS_pid = vfork(); if (GS_pid == 0) { /* child */ char **argvp = argv + 8; if (resource.gs_safer) *argvp++ = "-dSAFER"; *argvp = "-"; Sprintf(buf, "%ld", mane.win); setenv("GHOSTVIEW", buf, True); setenv("DISPLAY", XDisplayString(DISP), True); (void) close(std_in[1]); (void) dup2(std_in[0], 0); (void) close(std_in[0]); (void) close(std_out[0]); (void) dup2(std_out[1], 1); (void) dup2(std_out[1], 2); (void) close(std_out[1]); (void) execvp(argv[0] = resource.gs_path, argv); Fprintf(stderr, "Execvp of %s failed.\n", argv[0]); Fflush(stderr); _exit(1); } if (GS_pid == -1) { /* error */ perror("[xdvi] vfork"); return False; } (void) close(std_in[0]); (void) close(std_out[1]); #ifndef NON_BLOCKING_IO /* Set std_in for non-blocking I/O */ (void) fcntl(std_in[1], F_SETFL, fcntl(std_in[1], F_GETFL, 0) | O_NONBLOCK); #endif #ifdef _POSIX_SOURCE sigpipe_handler_struct.sa_handler = gs_sigpipe_handler; sigemptyset(&sigpipe_handler_struct.sa_mask); #endif #ifndef STREAMSCONN numfds = ConnectionNumber(DISP); if (numfds < std_in[1]) numfds = std_in[1]; if (numfds < std_out[0]) numfds = std_out[0]; ++numfds; #else /* STREAMSCONN */ fds[0].fd = std_in[1]; fds[1].fd = std_out[0]; fds[2].fd = ConnectionNumber(DISP); #endif /* STREAMSCONN */ GS_pending = 1; #endif /* VMS */ psp = gs_procs; GS_active = GS_sending = GS_pending_int = False; GS_pending = 1; GS_in_header = True; GS_mag = GS_shrink = -1; sendps(str1, sizeof(str1) - 1); { FILE *pshead; pshead = fopen("DVI_INPUTS:TEX.PRO","r"); if (!pshead) pshead = fopen("DVI_INPUTS:TEX.LPRO","r"); if (!pshead) pshead = fopen("DVIPSHEADERS:TEX.PRO","r"); if (!pshead) pshead = fopen("DVIPSHEADERS:TEX.LPRO","r"); if (pshead) { int len = -1; while((buf[++len] = getc(pshead)) != EOF) { if (buf[len] == '%') while ((buf[len] = getc(pshead)) != '\n'); if (buf[len] == '\n') { if (len) { buf[++len] = 0; sendps(buf, len); } len = -1; } } fclose(pshead); } pshead = fopen("DVI_INPUTS:SPECIAL.PRO","r"); if (!pshead) pshead = fopen("DVI_INPUTS:SPECIAL.LPRO","r"); if (!pshead) pshead = fopen("DVIPSHEADERS:SPECIAL.PRO","r"); if (!pshead) pshead = fopen("DVIPSHEADERS:SPECIAL.LPRO","r"); if (pshead) { int len = -1; while((buf[++len] = getc(pshead)) != EOF) { if (buf[len] == '%') while ((9~XDVI.BAKh? [XDVI]PSGS.C;111REv*buf[len] = getc(pshead)) != '\n'); if (buf[len] == '\n') { if (len) { buf[++len] = 0; sendps(buf, len); } len = -1; } } fclose(pshead); } } sendps(str2, sizeof(str2) - 1); GS_in_header = False; post_send(); if (GS_pid < 0) { /* if something happened */ destroy_gs(); return False; } if (!postscript) toggle_gs(); /* if we got a 'v' already */ else { canit = True; /* ||| redraw the page */ scanned_page = sc+anned_page_bak = scanned_page_reset; longjmp(canit_env, 1); } return True; } static void toggle_gs() { if (debug & DBG_PS) Puts("Toggling GS on or off"); if (postscript) psp.drawbegin = drawbegin_gs; else { interrupt_gs(); psp.drawbegin = drawbegin_none; } } static void destroy_gs() { if (debug & DBG_PS) Puts("Destroying GS process"); if (linepos > line) { *linepos = '\0'; Printf("gs: %s\n", line); linepos = line; } if (GS_pid >= 0) { #ifdef VMS StopInterpreter(); #else if (kill(GS_pid, SIGKILL) < 0 && errno != ESRCH) perror("xdvi destroy_gs"); #endif GS_pid = -1; scanned_page = scanned_page_bak = scanned_page_reset; } #ifndef VMS (void) close(GS_in); (void) close(GS_out); #endif GS_active = GS_sending = GS_pending_int = GS_in_doc = False; GS_pending = 0; } static void interrupt_gs() { static _Xconst char str[] = " stop\n%%xdvimark\n"; if (debug & DBG_PS) Puts("Running interrupt_gs()"); if (GS_sending) GS_pending_int = True; else { if (GS_active) { /* * ||| what I'd really like to do here is cause gs to execute * the interrupt routine in errordict. But so far (gs 2.6.1) * that has not been implemented in ghostscript. */ sendps(str, sizeof(str) - 1); GS_active = False; } psp.interrupt = NullProc; /* prevent deep recursion in waitack */ waitack(5); psp.interrupt = interrupt_gs; } } static void endpage_gs() { static _Xconst char str[] = "stop\n%%xdvimark\n"; if (debug & DBG_PS) Puts("Running endpage_gs()"); if (GS_active) { sendps(str, sizeof(str) - 1); GS_active = False; waitack(0); } } /* * Checks that the GS interpreter is running correctly. */ static void checkgs(in_header) Boolean in_header; { char buf[150]; /* For gs 2, we pretty much have to start over to enlarge the window. */ if (GS_old && (page_w > GS_page_w || page_h > GS_page_h)) destroy_gs(); if (GS_pid < 0) (void) initGS(); if (!GS_active) { /* check whether page_w or page_h have increased */ if (page_w > GS_page_w || page_h > GS_page_h) { Sprintf(buf, "H mark /HWSize [%d %d] /ImagingBBox [0 0 %d %d] \ currentdevice putdeviceprops pop\n\ initgraphics [0 1 1 0 0 0] concat stop\n%%%%xdvimark\n", GS_page_w = page_w, GS_page_h = page_h, page_h, page_w); ++GS_pending; sendps(buf, strlen(buf)); if (!in_header) { canit = True; /* ||| redraw the page */ longjmp(canit_env, 1); } } if (magnification != GS_mag) { Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \ end stop\n%%%%xdvimark\n", GS_mag = magnification); ++GS_pending; sendps(buf, strlen(buf)); } if (mane.shrinkfactor != GS_shrink) { Sprintf(buf, "H TeXDict begin %d %d div dup \ /Resolution X /VResolution X \ end stop\n%%%%xdvimark\n", pixels_per_inch, GS_shrink = mane.shrinkfactor); ++GS_pending; sendps(buf, strlen(buf)); } } } static void drawbegin_gs(xul, yul, cp) int xul, yul; char *cp; { char buf[32]; static _Xconst char str[] = " TeXDict begin\n"; checkgs(False); if (!GS_active) { sendps(str, sizeof(str) - 1); GS_active = True; ++GS_pending; } /* This allows the X side to clear the page */ XSync(DISP, False); Sprintf(buf, "%d %d moveto\n", xul, yul); sendps(buf, strlen(buf)); if (debug & DBG_PS) Printf("drawbegin at %d,%d: sending `%s'\n", xul, yul, cp); sendps(cp, strlen(cp)); } static void drawraw_gs(cp) char *cp; { int len = strlen(cp); if (!GS_active) return; if (debug & DBG_PS) Printf("raw ps sent to context: %s\n", cp); cp[len] = '\n'; sendps(cp, len + 1); } static void drawfile_gs(cp, f) _Xconst char *cp; FILE *f; { char buf[PATH_MAX + 7]; Fclose(f); /* don't need it */ ++n_files_left; if (!GS_active) return; if (debug & DBG_PS) Printf("printing file %s\n", cp); Sprintf(buf, "(%s)run\n", cp); sendps(buf, strlen(buf)); } static void drawend_gs(cp) char *cp; { if (!GS_active) return; if (debug & DBG_PS) Printf("end ps: %s\n", cp); sendps(cp, strlen(cp)); sendps("\n", 1); } static void beginheader_gs() { static _Xconst char str[] = "H save /xdvi$doc exch def\n"; if (debug & DBG_PS) Puts("Running beginheader_gs()"); checkgs(True); if (GS_active) { if (!GS_in_header) oops("Internal error in beginheader_gs().\n"); return; } GS_in_header = True; if (GS_in_doc) sendps("H", 1); /* bug in non-VMS version? ML 27-MAY-1998 19:39:02.15*/ else { sendps(str, sizeof(str) - 1); GS_in_doc = True; } GS_active = True; ++GS_pending; } static void endheader_gs() { static _Xconst char str[] = "stop\n%%xdvimark\n"; if (debug & DBG_PS) Puts("Running endheader_gs()"); if (GS_active) { sendps(str, sizeof(str) - 1); GS_active = False; GS_in_header = False; post_send(); waitack(0); } } static void newdoc_gs() { static _Xconst char str[] = "H xdvi$doc restore stop\n%%xdvimark\n"; if (debug & DBG_PS) Puts("Running newdoc_gs()"); if (GS_in_doc) { ++GS_pending; sendps(str, sizeof(str) - 1); GS_mag = GS_shrink = -1; GS_in_doc = False; } } #ifdef VMS /* ** VMS specific include files */ /* Input - Feed data to ghostscript's stdin. * Write bytes to ghostscript using non-blocking I/O. * Also, pipe signals are caught during writing. The return * values are checked and the appropriate action is taken. I do * this at this low level, because it may not be appropriate for * SIGPIPE to be caught for the overall application. */ /* ** This is an AST routine. It is called asynchronously whenever one of our ** mailbox I/O's completes. */ static void IOComplete(client_data) XtPointer client_data; { sys$setef(XtEFN); if(interpreter_output_iosb[0])Output(); } /* The interpeter failed, Stop what's left and notify application */ static void InterpreterFailed() { if (GS_pid >= 0) { StopInterpreter(); oops("Ghostscript postscript viewer failed"); } } static void Input() { int stat, bbytes; /* ** Check for error on previous I/O. */ stat = int7erpreter_input_iosb[0]; if(stat != SS$_NORMAL){ InterpreterFailed(); } else { /* Get a new section if required */ if (ps_input && bytes_left == 0) { struct record_list *ps_old = ps_input; ps_input = ps_old->next; free((char *)ps_old->buffer); free((char *)ps_old); if(ps_input){ bytes_left = ps_input->len; input_buffer = ps_input->buffer; } } if(ps_input){ /* ** Write it to the mailbox. */ bbytes = (bytes_left > 1024) ? 1024 : bytes_left; bytes_left -= bbytes; stat = sys$qiow(0, (short)interpreter_input, IO$_WRITEVBLK, &interpreter_input_iosb, 0, 0, input_buffer, bbytes, 0, 0, 0, 0); input_buffer += bbytes; ERR_SIGNAL(stat); } } } /* Output - receive I/O from ghostscript's stdout and stderr. * Pass this to the application via the output_callback. */ static void Output() { int bytes, stat, j; stat = interpreter_output_iosb[0]; bytes = interpreter_output_iosb[1]; if (stat == SS$_NORMAL) { if (bytes >= 0) { if(GS_pending == 0) { output_buffer[bytes] = 0; printf("%s",output_buffer); } else { for (j=0; j bytes - j) interpreter_output_iosb[1] = bytes - j; memcpy(linepos, &output_buffer[j], interpreter_output_iosb[1]); read_from_gs(); j = j + interpreter_output_iosb[1]; } } } /* ** Queue a new read to the mailbox */ st:at = sys$qio(0, (short)interpreter_output, IO$_READVBLK, &interpreter_output_iosb, IOComplete, 0, output_buffer, 1024, 0, 0, 0, 0); if (interpreter_output_iosb[0] == 0) interpreter_output_iosb[0] = SS$_NORMAL; ERR_SIGNAL(stat); } else { InterpreterFailed(); /* Something bad happened */ } } static exit_handler(status) int *status; { StopInterpreter(); } static struct exit_control_block { struct exit_control_block *flink; int (*exit_routine)(); int arg_count; int *status_address; int exit_status; } exit_block = {0,exit_handler,1,&exit_block.exit_status,0}; /* This routine starts the interpreter. It sets the DISPLAY and * GHOSTVIEW environment variables. The GHOSTVIEW environment variable * contains the Window that ghostscript should write on. * * This routine also opens pipes for stdout and stderr and initializes * application input events for them. If input to ghostscript is not * from a file, a pipe for stdin is created. This pipe is setup for * non-blocking I/O so that the user interface never "hangs" because of * a write to ghostscript. */ static void StartInterpreter() { char buf[1024]; char cmd[512]; int ret; short ch1, ch2; char in_mbx_name[65], out_mbx_name[65]; long pid, nowait = CLI$M_NOWAIT; const $DESCRIPTOR(ghostview_desc, "GHOSTVIEW"); const $DESCRIPTOR(display_desc, "DECW$DISPLAY"); const $DESCRIPTOR(lnt_desc, "LNM$PROCESS"); $DESCRIPTOR(in_desc, ""); $DESCRIPTOR(out_d=esc, ""); $DESCRIPTOR(lnm_desc, ""); $DESCRIPTOR(cmd_desc, cmd); ITEM_LIST_3_T(gv_list, 1) = {{{0, LNM$_STRING, buf, NULL}}, 0}; ITEM_LIST_3_T(dis_list, 1) = {{{0, LNM$_STRING, NULL, NULL}}, 0}; ITEM_LIST_3_T(dvi_list, 1) = {{{64, DVI$_DEVNAM, NULL, NULL}}, 0}; IOSB_GET_T dvi_iosb; /* ** Stop interpreter if running */ StopInterpreter(); /* ** Build Ghostscript startup command */ strcpy(cmd, "GS "); strcat(cmd, "\"-sDEVICE=x11\" \"-dNOPAUSE\" "); strcat(cmd, "\"-dQUIET\" "); strcat(cmd, "\""); strcat(cmd, arg4); strcat(cmd, "\" \""); strcat(cmd, arg5); strcat(cmd, "\" \"-dDEVICEXRESOLUTION=72\" \"-dDEVICEYRESOLUTION=72\" "); strcat(cmd, "\"-\" "); /* ** Create a mailbox to feed input to Ghostscript and get its name. */ ret = sys$crembx(0, &ch1, 1024, 1024, 0, 0, 0, 0); ERR_SIGNAL(ret); dvi_list.item[0].buffer_p = in_mbx_name; ret = sys$getdvi(0, ch1, 0, &dvi_list, &dvi_iosb, 0, 0, 0); ERR_SIGNAL(ret); ERR_SIGNAL(dvi_iosb.status); in_mbx_name[64] = '\0'; in_desc.dsc$a_pointer = in_mbx_name; in_desc.dsc$w_length = strlen(in_mbx_name); /* ** Create mailbox to receive Ghostscript's output */ ret = sys$crembx(0, &ch2, 1024, 1024, 0, 0, 0, 0); ERR_SIGNAL(ret); dvi_list.item[0].buffer_p = out_mbx_name; ret = sys$getdvi(0, ch2, 0, &dvi_list, &dvi_iosb, 0, 0, 0); ERR_SIGNAL(ret); ERR_SIGNAL(dvi_iosb.status); out_mbx_name[64] = '\0'; out_desc.dsc$a_pointer = out_mbx_name; out_desc.dsc$w_length = strlen(out_mbx_name); /* ** Create GHOSTVIEW and DECW$DISPLAY logical names. ** ** We use CRELNM rather than LIB$SET_LOGICAL because we want these to be ** user mode and go away when the program exits. It doesn't matter that we ** may set them multiple times, as with the mailbox logicals, since once ** Ghostscript starts we don't need them any more. */ sprintf(buf, "%d", mane.win); gv_list.item[0].buffer_size = strlen(buf); ret = sys$crelnm(0, &lnt_desc, &ghostview_desc, 0, &gv_list); ERR_SIGNAL(ret); dis_list.item[0].buffer_p = XDisplayString(DISP); dis_list.item[0].buffer_size = strlen(dis_list.item[0].buffer_p); ret = sys$crelnm(0, &lnt_desc, &display_desc, 0, &dis_list); ERR_SIGNAL(ret); sys$dclexh(&exit_block); /* ** Spawn Ghostscript process */ changed = False; busy = True; cmd_desc.dsc$w_length = strlen(cmd); ret = lib$spawn(&cmd_desc, &in_desc, &out_desc, &nowait, 0, &pid, 0, 0, 0, 0, 0, 0, 0); ERR_SIGNAL(ret); XDefineCursor(DISP, mane.win, redraw_cursor); /* ** Everything worked, initialize IOSBs and save info about interpretter. */ GS_pid = pid; interpreter_input = ch1; interpreter_input_iosb[0] = 0; interpreter_output = ch2; if (output_buffer == NULL) { output_buffer = xmalloc(1025,"output_buffer"); } /* ** Fake a completed I/O so Output will get called to queue the first I/O. */ interpreter_output_iosb[0] = SS$_NORMAL; interpreter_output_iosb[1] = -1; sys$clref(XtEFN); Output(); } /* Send * Send does not actually send the PostScript, it merely queues it * for output. * * If an interpreter is not running, nothing is queued and * False is returned. */ sendps(cp, len) _Xconst char *cp; int len; { struct record_list *ps_new; if (interpreter_input < 0) return False; GS_sending = True; if(len != 0){ ps_new = (struct record_list *) xmalloc(sizeof (struct record_list), "sendps psnew"); ps_new->buffer = xmalloc(len,"sendps buffer"); ps_new->len = len; ps_new->next = NULL; memcpy(ps_new->buffer, cp, len); if (ps_input == NULL) { bytes_left = len; input_buffer = ps_new->buffer; ps_input = ps_new; /* ** Fake a completed I/O so Input will get called to queue the ** first I/O. */ interpreter_input_iosb[0] = SS$_NORMAL; interpreter_input_iosb[1] = -1; while (ps_input) { Input(); } } else { struct record_list *p = ps_input; while (p->next != NULL) { p = p->next; } p->next = ps_new; } } return True; } #endif /* VMS */ *[XDVI]PSNEWS.C;2+,f.0/ 4O00- 0@123KPWO156^s(7݇s(8x]o9GHJB/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTES: * This code was originally written by Ricardo Telichevesky * (ricardo@rle-vlsi-mit.edu) and Luis Miguel Silveira * (lms@rle-vlsi-mit.edu). * It was largely influenced by similar code in the SeeTeX/XTeX * package by Dirk Grunwald (grunwald@colorado.edu). */ /* ||| To do: * ALWAYS_CLOSE_SERVER_CONNECTION? * Is there some way of interrupting a process? * fork * extra bytes on input */ #include "xdvi.h" #include #include #include #include #include #include /* if POSIX O_NONBLOCK is not available, use O_NDELAY */ #if !defined(O_NONBLOCK) && defined(O_NDELAY) #define O_NONBLOCK O_NDELAY #endif /* Condition for retrying a write */ #include #ifdef X_NOT_STDC_ENV extern int errno; #endif #ifdef EWOULDBLOCK #ifdef EAGAIN #define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN) #else /* EAGAIN */ #define AGAIN_CONDITION (errno == EWOULDBLOCK) #endif /* EAGAIN */ #else /* EWOULDBLOCK */ #ifdef EAGAIN #define AGAIN_CONDITION (errno == EAGAIN) #endif /* EAGAIN */ #endif /* EWOULDBLOCK */ #ifdef STREAMSCONN #include #endif #if HAS_SIGIO #include #ifndef FASYNC #undef HAS_SIGIO #define HAS_SIGIO 0 #endif #endif #if NeedFunctionPrototypes char *strtok(char *, _Xconst char *); #else char *strtok(); #endif #define Fprintf (void) fprintf /* define ALWAYS_CLOSE_SERVER_CONNECTION if you want to close the server connection all the time */ #undef ALWAYS_CLOSE_SERVER_CONNECTION /* * Some setup code. */ static _Xconst char str0[] = "\ /OW2? version cvi 2 eq def \ OW2? \ { /setlinewidth { pop } def} \ { /NeWS 3 0 findpackage beginpackage \ /X11 3 0 findpackage beginpackage} \ ifelse \ currentcanvas /Color get \ currentcanvas /Colormap get getcubedescription null eq and \ {8 {{currentcanvas /Colormap get 1 index dup dup dup newcube} stopped \ {pop pop pop pop pop} {exit} ifelse \ 2 div cvi dup 1 eq {exit} if} loop pop} \ if\n"; /* * This string reads chunks (delimited by %%xdvimark). * The first character of a chunk tells whether a given chunk * is to be done within save/restore or not. * The `H' at the end tells it that the first group is a * header; i.e., no save/restore. */ static _Xconst char preamble[] = "\ /xdvi$line 81 string def \ /xdvi$run {$error null ne {$error /newerror false put} if \ {currentfile cvx stopped \ $error null eq {false} {$error /newerror get} ifelse and \ {handleerror} if} stopped pop} def \ /xdvi$dslen countdictstack def \ {currentfile read not {exit} if 72 eq \ {xdvi$run} \ {/xdvi$sav save def xdvi$run \ clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \ ifelse \ {(%%xdvimark) currentfile xdvi$line {readline} stopped \ {clear} {{eq {false exit} if} {true exit} ifelse} ifelse }loop {exit} if \ 58 tagprint flush \ }loop\nH"; extern _Xconst char psheader[]; extern int psheaderlen; static _Xconst char preamble2[] = " stop\n%%xdvimark\n"; #define stopstring preamble2 #define postscript resource._postscript /* global procedures (besides initNeWS) */ static void toggleNeWS ARGS((void)); static void destroyNeWS ARGS((void)); static void interruptNeWS ARGS((void)); static void endpageNeWS ARGS((void)); static void drawbeginNeWS ARGS((int, int, char *)); static void drawrawNeWS ARGS((char *)); static void drawfileNeWS ARGS((_Xconst char *, FILE *)); static void drawendNeWS ARGS((char *)); static void beginheaderNeWS ARGS((void)); static void endheaderNeWS ARGS((void)); static void newdocNeWS ARGS((void)); static struct psprocs news_procs = { /* toggle */ toggleNeWS, /* destroy */ destroyNeWS, /* interrupt */ interruptNeWS, /* endpage */ endpageNeWS, /* drawbegin */ drawbeginNeWS, /* drawraw */ drawrawNeWS, /* drawfile */ drawfileNeWS, /* drawend */ drawendNeWS, /* beginheader */ beginheaderNeWS, /* endheader */ endheaderNeWS, /* newdoc */ newdocNeWS}; /* signal handler to hairy PostScript code */ static void psio_sigpipe_handler(); /* define local static variables */ static int NeWS_mag; /* magnification currently in use */ static int NeWS_shrink; /* shrink factor currently in use */ static unsigned int NeWS_page_w; /* how big our current page is */ static unsigned int NeWS_page_h; static Boolean NeWS_active; /* if we've started a page yet */ static int NeWS_pending; /* number of ack's we're expecting */ static int NeWS_sending; /* level of nesting in send() */ static Boolean NeWS_in_header; /* if we're sending a header */ static Boolean NeWS_in_doc; /* if we've sent header information */ static Boolean NeWS_pending_int; /* if interrupt rec'd while in send() */ static Boolean NeWS_destroyed = False; /* * NeWS I/O code. This should send PS code to NeWS, * receive acknowledgements, and receive X events in the meantime. * It also checks for SIGPIPE errors. */ #ifndef STREAMSCONN static int numfds; static fd_set readfds; static fd_set writefds; #define XDVI_ISSET(a, b, c) FD_ISSET(a, b) #else /* STREAMSCONN */ struct pollfd fds[3] = {{0, POLLOUT, 0}, {0, POLLIN, 0}, {0, POLLIN, 0}}; #define XDVI_ISSET(a, b, c) (fds[c].revents) #endif /* STREAMSCONN */ /*---------------------------------------------------------------------------* psio_sigpipe_handler () Arguments: sig, code, scp, addr (see man page for signal) Returns: (void) Side-Effects: SIGPIPE signal is flagged as sigpipe_error variable is set. Description: Handler for SIGPIPE error generated by a broken pipe in the connection to the NeWS server; this may be duer to some abnormal condition, or some hairy PostScript code containing commands not implemented by the server. +----------------------------------------------------------------------------*/ static Boolean sigpipe_error = False; static struct sigaction psio_sigpipe_handler_struct; /* initialized to {psio_sigpipe_handler, (sigset_t) 0, 0} in initNeWS */ /* ARGSUSED */ static void psio_sigpipe_handler(sig, code, scp, addr) int sig; int code; struct sigcontext *scp; char *addr; { sigpipe_error = True; } /* * read_from_NeWS - This does the actual retrieving of acknowledgements. * If other bytes appear on the file - tough. */ static void read_from_NeWS() { for (;;) { int retval; retval = ps_checkfor(PostScriptInput, PSIO_FIND_TAG, 58); if (retval == 0) break; if (retval < 0) { Fprintf(stderr, "[xdvi] ps_checkfor: %d\n", retval); return; } (void) ps_checkfor(PostScriptInput, PSIO_WAIT_TAG, 58); --NeWS_pending; if (debug & DBG_PS) Printf("Got NeWS ack; %d pending.\n", NeWS_pending); } } /* * Clean up after send() */ static void post_send() { if (sigpipe_error) { Fputs("NeWS died unexpectedly.\n", stderr); destroyNeWS(); draw_bbox(); } if (NeWS_pending_int) { NeWS_pending_int = False; interruptNeWS(); } } /* * This actually sends the bytes to NeWS. */ static void send(cp, len) _Xconst char *cp; int len; { struct sigaction orig; #ifdef STREAMSCONN int retval; #endif if (PostScript == (PSFILE *) NULL) return; if (!NeWS_sending) { (void) sigaction(SIGPIPE, &psio_sigpipe_handler_struct, &orig); sigpipe_error = False; } ++NeWS_sending; #if HAS_SIGIO (void) fcntl(ConnectionNumber(DISP), F_SETFL, fcntl(ConnectionNumber(DISP), F_GETFL, 0) & ~FASYNC); #endif #ifndef STREAMSCONN FD_ZERO(&readfds); FD_ZERO(&writefds); #endif for (;;) { #ifndef STREAMSCONN FD_SET(ConnectionNumber(DISP), &readfds); FD_SET(PostScript->file, &writefds); FD_SET(PostScriptInput->file, &readfds); if (select(numfds, &readfds, &writefds, (fd_set *) NULL, (struct timeval *) NULL) < 0 && errno != EINTR) { perror("select (xdvi NeWS_send)"); break; } #else /* STREAMSCONN */ for (;;) { retval = poll(fds, XtNumber(fds), -1); if (retval >= 0 || errno != EAGAIN) break; } if (retval < 0) { perror("poll (xdvi NeWS_send)"); break; } #endif /* STREAMSCONN */ if (XDVI_ISSET(PostScriptInput->file, &readfds, 1)) read_from_NeWS(); if (XDVI_ISSET(PostScript->file, &writefds, 0)) { int old_flags; int bytes; old_flags = fcntl(PostScript->file, F_GETFL, 0); if (old_flags < 0) break; #ifndef NON_BLOCKING_IO /* set to be non-blocking */ if (fcntl(PostScript->file, F_SETFL, old_flags | O_NONBLOCK) < 0) break; #endif bytes = write(PostScript->file, cp, len); if (bytes == -1) { if (!AGAIN_CONDITION) perror("xdvi NeWS_send"); } else { cp += bytes; len -= bytes; } if (fcntl(PostScript->file, F_SETFL, old_flags) < 0) break; if (len == 0 || sigpipe_error) break; } if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) { allow_can = False; read_events(False); allow_can = True; if (PostScript == (PSFILE *) NULL) break; /* if timeout occurred */ } } #if HAS_SIGIO (void) fcntl(ConnectionNumber(DISP), F_SETFL, fcntl(ConnectionNumber(DISP), F_GETFL, 0) | FASYNC); #endif if (--NeWS_sending == 0) { /* put back generic handler for SIGPIPE */ (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL); if (!NeWS_in_header) post_send(); } } /* * Wait for acknowledgement from NeWS. With NeWS we have no choice but * to wait (||| I think). */ static void waitack() { #ifdef STREAMSCONN int retval; #endif #if HAS_SIGIO int oldflags; #endif if (PostScript == (PSFILE *) NULL) return; #if HAS_SIGIO oldflags = fcntl(ConnectionNumber(DISP), F_GETFL, 0); (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags & ~FASYNC); #endif #ifndef STREAMSCONN FD_ZERO(&readfds); #endif while (NeWS_pending > 0) { #ifndef STREAMSCONN FD_SET(ConnectionNumber(DISP), &readfds); FD_SET(PostScriptInput->file, &readfds); if (select(numfds, &readfds, (fd_set *) NULL, (fd_set *) NULL, (struct timeval *) NULL) < 0 && errno != EINTR) { perror("select (xdvi NeWS_waitack)"); break; } #else /* STREAMSCONN */ for (;;) { retval = poll(fds + 1, XtNumber(fds) - 1, -1); if (retval >= 0 || errno != EAGAIN) break; } if (retval < 0) { perror("poll (xdvi NeWS_waitack)"); break; } #endif /* STREAMSCONN */ if (XDVI_ISSET(PostScriptInput->file, &readfds, 1)) read_from_NeWS(); if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) { allow_can = False; read_events(False); allow_can = True; if (PostScript == (PSFILE *) NULL) break; /* if timeout occurred */ } } #if HAS_SIGIO (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags); #endif } /*---------------------------------------------------------------------------* initNeWS() Arguments: None. Returns: True if and only if initialization succeeded Side-Effects: Static variables may be set. Description: Initializes variables for the application main loop. +----------------------------------------------------------------------------*/ Boolean initNeWS() { static NeWStoken newstoken; /* now try to open the connection to the NeWS server */ if (ps_open_PostScript() == (PSFILE *) NULL) return False; #ifndef STREAMSCONN numfds = ConnectionNumber(DISP); if (numfds < PostScript->file) numfds = PostScript->file; if (numfds < PostScriptInput->file) numfds = PostScriptInput->file; ++numfds; #else /* STREAMSCONN */ fds[0].fd = PostScript->file; fds[1].fd = PostScriptInput->file; fds[2].fd = ConnectionNumber(DISP); #endif /* STREAMSCONN */ psio_sigpipe_handler_struct.sa_handler = psio_sigpipe_handler; sigemptyset(&psio_sigpipe_handler_struct.sa_mask); NeWS_active = NeWS_pending_int = False; NeWS_sending = 0; NeWS_in_header = True; NeWS_pending = 1; ps_flush_PostScript(); send(str0, sizeof(str0) - 1); /* get xid of window, then make this window the NeWS canvas */ (void) ps_token_from_xid(mane.win, &newstoken); if (newstoken != -1) { ps_setcanvas(newstoken); ps_flush_PostScript(); send(preamble, sizeof(preamble) - 1); send(psheader, psheaderlen); send(preamble2, sizeof(preamble2) - 1); NeWS_in_header = False; post_send(); waitack(); } if (NeWS_destroyed) return False; /* success */ NeWS_mag = NeWS_shrink = -1; NeWS_page_w = page_w; NeWS_page_h = page_h; psp = news_procs; if (!postscript) toggleNeWS(); /* if we got a 'v' already */ return True; } /*---------------------------------------------------------------------------* toggleNeWS() Arguments: none Returns: (void) Side-Effects: psp.drawbegin is changed Description: Used to toggle the rendering of PostScript by the NeWS server +----------------------------------------------------------------------------*/ static void toggleNeWS() { if (postscript) psp.drawbegin = drawbeginNeWS; else { interruptNeWS(); psp.drawbegin = drawbegin_none; } } /*---------------------------------------------------------------------------* destroyNeWS() Arguments: none Returns: (void) Side-Effects: the pointer to the NeWS file is nulled Description: Close the connection to the NeWS server; used when rendering is terminated in any way. +----------------------------------------------------------------------------*/ static void destroyNeWS() { psp = no_ps_procs; NeWS_destroyed = True; scanned_page = scanned_page_bak = scanned_page_reset; } /*---------------------------------------------------------------------------* interruptNeWS() Arguments: none Returns: void Description: Close the connection to the NeWS server; used when rendering is terminated because of an interruption in the viewing of the current page. ||| It would be nice if we could asynchronously ``wake up'' a NeWS process (preferably by sending something along the X socket); then we could do better than just to wait. +----------------------------------------------------------------------------*/ static void interruptNeWS() { if (debug & DBG_PS) Puts("Running interruptNeWS()"); if (NeWS_sending) NeWS_pending_int = True; else { if (NeWS_active) { send(stopstring, sizeof(stopstring) - 1); NeWS_active = False; } psp.interrupt = NullProc; /* prevent deep recursion in waitack */ waitack(); psp.interrupt = interruptNeWS; } } /*---------------------------------------------------------------------------* endpageNeWS() Arguments: none Returns: (void) Side-Effects: the NeWS_active variable is cleared. Description: Should be called at the end of a page to end this chunk for the NeWS server. +----------------------------------------------------------------------------*/ static void endpageNeWS() { if (debug & DBG_PS) Puts("endpage sent to NeWS Server"); if (NeWS_active) { send(stopstring, sizeof(stopstring) - 1); NeWS_active = False; waitack(); } } /*---------------------------------------------------------------------------* drawbeginNeWS () Arguments: xul, yul - coordinates of the upper left corner of the figure cp - string with the bounding box line data Returns: (void) Description: Opens a connection to the NeWS server and send in the preamble and the bounding box information after correctly computing resolution factors. In case no rendering is to be done, outlines the figure. An outline is also generated whenever the PostScript code is too hairy and generates a SIGPIPE signal. +----------------------------------------------------------------------------*/ static voicNW~XDVI.BAKf [XDVI]PSNEWS.C;2O0|"d drawbeginNeWS(xul, yul, cp) int xul, yul; char *cp; { char buf[100]; static _Xconst char str[] = " TeXDict begin\n"; static _Xconst char str2[] = "Hinitgraphics stop\n%%xdvimark\n"; if (debug & DBG_PS) { Printf("xul= %d yul= %d\n", xul, yul); Printf("String = < %s >\n", cp); } /* catch up on the X side */ XSync(DISP, False); if (!NeWS_active) { /* send initialization to NeWS server */ if (NeWS_page_w < page_w || NeWS_page_h < page_h) { NeWS_page_w = page_w; NeWS_page_h = page_h; send(str2, sizeof(str2) - 1); ++NeWS_pending; } if (magnification != NeWS_mag) { Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \ end stop\n%%%%xdvimark\n", NeWS_mag = magnification); send(buf, strlen(buf)); ++NeWS_pending; } if (mane.shrinkfactor != NeWS_shrink) { Sprintf(buf, "H TeXDict begin %d %d div dup \ /Resolution X /VResolution X \ end stop\n%%%%xdvimark\n", pixels_per_inch, NeWS_shrink = mane.shrinkfactor); send(buf, strlen(buf)); ++NeWS_pending; } send(str, sizeof(str) - 1); NeWS_active = True; ++NeWS_pending; } Sprintf(buf, "%d %d moveto\n", xul, yul); send(buf, strlen(buf)); send(cp, strlen(cp)); } /*---------------------------------------------------------------------------* drawrawNeWS() Arguments: origcp - the raw string to be sent to the postscript interpreter Returns: (void) Side-Effects: (none) Description: If there is a valid connection to the NeWS server, just send the string to the interpreter, else leave. +----------------------------------------------------------------------------*/ static void drawrawNeWS(origcp) char *origcp; { char *pt, *ptm1, *cp1, *ocp1; static char *cp; static unsigned int cplen = 0; unsigned int len; double angle; Boolean found = False; if (!NeWS_active) return; if (debug & DBG_PS) Printf("Raw PS sent to context: <%s>\n", origcp); /* take a look at the string: NeWS bums on certain rotations */ len = strlen(origcp) + 4; if (cplen < len) { if (cplen != 0) free(cp); cplen = len; cp = xmalloc(cplen, "string in drawrawNeWS"); } ocp1 = origcp; pt = origcp; while (*pt == ' ' || *pt == '\t') ++pt; cp1 = cp; for (;;) { ptm1 = pt; while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt; if (*pt == '\0') break; while (*pt == ' ' || *pt == '\t') ++pt; if (strncmp(pt, "rotate", 6) == 0 && (pt[6] == '\0' || pt[6] == ' ' || pt[6] == '\t')) { /* found rotate; check angle */ if (sscanf(ptm1, "%lf", &angle) >= 1) { found = True; while (angle > 360.0) angle -= 360; while (angle < -360.0) angle += 360; if (angle == 90.0) { angle = 89.999; (void) memcpy(cp1, ocp1, ptm1 - ocp1); cp1 += ptm1 - ocp1; Strcpy(cp1, "89.999 rotate "); cp1 += strlen(cp1); while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt; while (*pt == ' ' || *pt == '\t') ++pt; ocp1 = pt; } else if (angle == -90.0) { angle = -89.999; (void) memcpy(cp1, ocp1, ptm1 - ocp1); cp1 += ptm1 - ocp1; Strcpy(cp1, "-89.999 rotate "); cp1 += strlen(cp1); while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt; while (*pt == ' ' || *pt == '\t') ++pt; ocp1 = pt; } else if (angle == 0.0) { (void) memcpy(cp1, ocp1, ptm1 - ocp1); cp1 += ptm1 - ocp1; while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt; while (*pt == ' ' || *pt == '\t') ++pt; ocp1 = pt; } } } } Strcpy(cp1, ocp1); if ((debug & DBG_PS) && found) { Printf("String is now <%s>\n", cp); Printf("Found rotate string. Angle is %g degrees.\n", angle); } len = strlen(cp); cp[len] = '\n'; send(cp, len + 1); } /*---------------------------------------------------------------------------* drawfileNeWS() Arguments: cp - string with the postscript file pathname psfile - file, already opened Returns: (void) Side-Effects: none Description: Postscript file containing the figure is opened and sent to the NeWS server. Figure is outlined in case hairy code produces a SIGPIPE signal. +----------------------------------------------------------------------------*/ static void drawfileNeWS(cp, psfile) _Xconst char *cp; FILE *psfile; { char buffer[1025]; int blen; int bytes; struct sigaction orig; if (!NeWS_active) { Fclose(psfile); ++n_files_left; return; } if (debug & DBG_PS) Printf("printing file %s\n", cp); /* some hairy PS code generates SIGPIPE signals; handle them */ (void) sigaction(SIGPIPE, &psio_sigpipe_handler_struct, &orig); sigpipe_error = False; NeWS_sending = 1; if (!sigpipe_error) for (;;) { blen = fread(buffer, sizeof(char), 1024, psfile); if (blen == 0) break; send(buffer, blen); if (sigpipe_error) break; } Fclose(psfile); ++n_files_left; --NeWS_sending; /* put back generic handler for SIGPIPE */ (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL); if (sigpipe_error) { Fputs("NeWS died unexpectedly.\n", stderr); destroyNeWS(); draw_bbox(); } if (NeWS_pending_int) { NeWS_pending_int = False; interruptNeWS(); } } /*---------------------------------------------------------------------------* drawendNeWS() Arguments: cp - string with indication of the end of the special Returns: (void) Description: Sends the indication of end of the figure PostScript code. +----------------------------------------------------------------------------*/ static void drawendNeWS(cp) char *cp; { if (!NeWS_active) return; if (debug & DBG_PS) Puts("drawend sent to NeWS Server"); send(cp, strlen(cp)); send("\n", 1); } /*---------------------------------------------------------------------------* beginheaderNeWS() Arguments: none Returns: (void) Description: Prepares the PostScript interpreter for receipt of header code. +----------------------------------------------------------------------------*/ static void beginheaderNeWS() { static _Xconst char str[] = "Hsave /xdvi$doc exch def\n"; if (debug & DBG_PS) Puts("Running beginheaderNeWS()"); if (NeWS_active) { if (!NeWS_in_header) oops("Internal error in beginheaderNeWS().\n"); return; } NeWS_in_header = True; if (NeWS_in_doc) send("H", 1); else { send(str, sizeof(str) - 1); NeWS_in_doc = True; } NeWS_active = True; ++NeWS_pending; } /*---------------------------------------------------------------------------* endheaderNeWS() Arguments: none Returns: (void) Description: Prepares the PostScript interpreter for receipt of header code. +----------------------------------------------------------------------------*/ static void endheaderNeWS() { static _Xconst char str[] = "stop\n%%xdvimark\n"; if (debug & DBG_PS) Puts("Running endheaderNeWS()"); if (NeWS_active) { send(str, sizeof(str) - 1); NeWS_active = False; NeWS_in_header = False; post_send(); waitack(); } } /*---------------------------------------------------------------------------* newdocNeWS() Arguments: none Returns: (void) Description: Clears out headers stored from the previous document. +----------------------------------------------------------------------------*/ static void newdocNeWS() { static _Xconst char str[] = "H xdvi$doc restore stop\n%%xdvimark\n"; if (debug & DBG_PS) Puts("Running newdocNeWS()"); send(str, sizeof(str) - 1); ++NeWS_pending; NeWS_mag = NeWS_shrink = -1; NeWS_in_doc = False; } *[XDVI]README.;1+,f .$/ 4$$- 0@123KPWO%56E7E8`|_o9GHJDESCRIPTION xdvi is a program for previewing .dvi files, which are produced by the mathematical typesetting system, TeX. INSTALLATION INSTRUCTIONS You can compile and install with either imake or just plain make. To install with imake, do the following: 1. Set the OSDEFS flags in the Imakefile (see SETTING OSDEFS, below). 2. Set the OPTIONDEFS flags in the Imakefile (see COMPILATION OPTIONS, below). 3. Set the font path options in the Imakefile (see SETTING THE FONT PATH, below). 4. Make the Makefile: xmkmf 5. Compile xdvi: make If you have problems, see COMMON PROBLEMS WHEN COMPILING, below. 6. Try out xdvi. If the settings in step 3 are incorrect, then you can use the corresponding environment variables to quickly try out different values. Then rm font_open.o and go back to step 3. 7. Make xdvi.man 8. Install xdvi and xdvi.man. Or, to install with plain make, do the following: 0. Copy Makefile.std to Makefile. 1. Set the OSDEFS flags in the Makefile (see SETTING OSDEFS, below). 2. Set the OPTIONDEFS flags in the Makefile (see COMPILATION OPTIONS, below). 3. Set the font path options in the Makefile (see FONT PATH OPTIONS, below). Then continue with steps 5-8 as above. SETTING OSDEFS The OSDEFS variable should contain definitions to indicate what type of system you are using. They may be some of the following: SYSV Set for System V compilation. VMS Set for VMS compilation. MSBITFIRST Store bitmaps internally with theB most significant bit at the left. For performance reasons, it would be best to set this to coincide with what your server uses. Use the keystroke '^P' to find information in this regard. Generally, you should use MSBITFIRST if and only if '^P' reports bitord = 1, and BMSHORT/BMBYTE (below) should be set to match whatever '^P' reports under "Unit =". But, if bitord = byteord, then the latter setting should not matter much. BMSHORT Store bitmaps in short integers instead of 32-bit integers. See MSBITFIRST for other relevant comments. To check performance, you can use: time xdvi -d 8 file.dvi BMBYTE Store bitmaps in bytes instead of 32-bit integers. The following table gives OSDEFS settings for some systems: Machine O/S OSDEFS ------- --- ------ DEC Alpha OSF/1 2.0 OSDEFS= Intel x86 Linux OSDEFS=-DHAS_SIGIO Intel x86 Interactive Unix 4.0 OSDEFS=-DSTREAMSCONN NeXT NeXTStep OSDEFS=-DMSBITFIRST -DVFORK -Dpid_t=int RS6000 AIX OSDEFS=-DMSBITFIRST -DSVR3 -DSTREAMSCONN SGI IRIX 5.1 OSDEFS=-DMSBITFIRST -DSVR4 (If not using imake, also add -cckr -float -KPIC -G 0 -Wf,-XNh2000 to CFLAGS.) Sun 3 Sunos 4.x OSDEFS=-DMSBITFIRST -DVFORK or -DMSBITFIRST -DVFORK=include Sun Sparc Sunos 4.x OSDEFS=-DMSBITFIRST -DVFORK=include Sun Sparc Solaris 2.x OSDEFS=-DMSBITFIRST -DSVR4 -DHAS_SIGIO If, when running xdvi, you will usually be displaying remotely (e.g., on an X terminal), then you may want to set the BMSHORT/BMLONG flags and the byte order to correspond to the most common display device. COMPILATION OPTIONS The OPTIONDEFS variable should be set to indicate which options xdvi should be compiled with. These are listed below. There is really no difference between OSDEFS and OPTIONDEFS; the only reason for keeping them separate is to allow OSDEFS to be tabulated as above. Option Flag Explanation ----------- ----------- USE_PK Use pk format font files. This is preferred because pk font files are smaller. USE_GF Use gf format font files. BUTTONS Put radio buttons on the right side of the window for commonly used commands. NOTOOL Compile using raw X calls. GREY Use greyscale anti-aliasing for displaying shrunken bitmaps. PS_DPS Use Display PostScript to display PostScript specials. Your system must have DPS for this to work. PS_NEWS Use the NeWS server to display PostScript specials. Your system must have the NeWS include files and libraries for this to compile; the xdvi binary can be run with either a standard X server or the NeWS server, but in the former case the code generated by PS_NEWS will have no effect. NOTE: This option refers only to OpenWindows versions 3.1 (possibly 3.2) and earlier (running under SunOS 4.x). If you are using Solaris, then you should use PS_DPS instead. PS_GS Use Ghostscript to render PostScript specials. Your system must have Ghostscript installed for this to work. Versions earlier than 2.6.1 have not been tested with xdvi. GS_PATH=\"/usr/local/bin/gs\" Use the given program as the Ghostscript interpreter when displaying PostScript specials. This option automatically selects PS_GS. MAKEPK If a font is not found, then try to call Metafont to create the font. When using this option, remember to set the paths in MakeTeXPK correctly for your site, and be sure that the destination directory for MakeTeXPK appears in your DEFAULT_FONT_PATH variable. To have PostScript-like fonts made as well, see the package gsftopk distributed with xdvi. MAKEPKCMD=\"/usr/local/tex/bin/MakeTeXPK\" Same as the above, but this variant explicitly declares which command to use to create the font. A4 Use European size paper by default. TEXXET Enables op-codes 250 and 251 (used for right-to-left languages). BDPI Default number of pixels per inch to use. Don't forget to make corresponding changes to DEFAULT_FONT_SIZES. ALTFONT Default font to use if the font named in the dvi file cannot be found. Can be set to NULL. By default, it is "cmr10". XDVIFONTS_ONLY Never check the TEXFONTS environment variable. Normally xdvi checks TEXFONTS if the XDVIFONTS variable is not set. This option is recommended if the version of TeX in use requires that the TEXFONTS variable be set. See the relevant paragraph in xdvi_man.sed for more details. This option turns off that paragraph. SEARCH_SUBDIRECTORIES Enable recursive searching of subdirectories for font files (* and ** specifiers). This also enables the TEXFONTS_SUBDIR environment variable and the DEFAULT_SUBDIR_PATH makefile variable. NOQUERY Set this if you have trouble compiling the definition of drawingWidgetClass. TICKTMP Directory for temporary files created by PostScript specials that call for the output of a command (e.g., compressed .eps files). Default is "/tmp". TICKCACHESIZE Maximum number of such files to be stored at a time (this is dynamically increased if more than this number occur on a single page). Default is 3. SETTING THE FONT PATH Read the ENVIRONMENT section of xdvi_man.sed to determine the correct default values for the XDVIFONTS and XDVISIZES environment variables. Edit the Imakefile or Makefile and change the values of the make variables DEFAULT_FONT_PATH and DEFAULT_FONT_SIZES to these values. If your site uses virtual fonts, do the same thing with the DEFAULT_VF_PATH variable. Note that support of virtual fonts in xdvi does not include support of built-in Postscript fonts. Usually you will want to use the same font files as your printer; given a choice, however, it has been suggested that write-white fonts look better. (Note: If you are using both imake and the "/*" or "/**" syntax for recursive searching of subdirectories, you should enclose the string in quotes, since /* marks the beginning of a C comment, and the Imakefile is processed by cpp.) If you are compiling with PostScript specials enabled, then you also need to set the DEFAULT_FIG_PATH and DEFAULT_HEADER_PATH variables. These should contain colon-separated lists of directories (but without `%' specifiers). The DEFAULT_FIG_PATH variable gives the list of directories to search for PostScript figures; typically this is the same as the default input directory used by TeX. The DEFAULT_HEADER_PATH variable gives the default list of directories to search for PostScript headers. If you also install dvips, then it is recommended that DEFAULT_FIG_PATH and DEFAULT_HEADER_PATH be set to the same values as FIGPATH and HEADERPATH in the Makefile for dvips. COMMON PROBLEMS WHEN COMPILING Some early versions of `make' may complain and abort if the file Makefile.cfg does not exist. If this is the case, do: touch Makefile.cfg make config before running make. (If `make' complains but continues by running ./mkconfig, then this is OK.) If you get the error that the #include file does not exist, then you should include -DX_NOT_STDC_ENV in your OSDEFS variable. In X11R5 or later this problem should not occur. ================================================================ This program is the combined work of many people, including but not restricted to: Eric Cooper, CMU Bob Scheifler, MIT LCS Paal Kvamme, Norwegian Institute of Technology H\aa vard Eidnes, Norwegian Institute of Technology Mark Eichin, MIT SIPB Paul Vojta, UC Berkeley Jeffrey Lee, U of Toronto Donald Richardson, Clarkson Univ. Ricardo Telichevesky, MIT Luis Miguel Silveira, MIT At the present time, the person to send bug reports to is Paul Vojta, vojta@math.berkeley.edu. When doing so, please specify hardware and OS version, OPTIONDEFS and OSDEFS settings in the Makefile, and anything else that may be relevant. Be sure you've checked the FAQ first, especially for questions regarding searching for font files. This software has been tested on Sparc (SunOS 4.1.3) and Intel 486 (Linux 1.0). In addition to the various comp.sources.x archives, current versions of this program can also be obtained via anonymous ftp from the following location: ftp.x.org file contrib/applications/xdvi-20.tar.Z [198.112.44.100] To ease the load on ftp.x.org, you may also check other X archives, for example: gatekeeper.dec.com file pub/X11/contrib/applications/xdvi-20.tar.Z [16.1.0.2] For those who like to live on the bleeding edge, the latest and greatest beta test version is often available on: math.berkeley.edu pub/Software/TeX/xdvi_beta.tar.Z [128.32.183.94] Paul Vojta, 10 May 1995 ================================================================ Note for IBM RS6000 users: some of the libraries are in non-obvious places: libXmu /usr/lpp/X11/Xamples/lib/Xmu/libXmu.a libXaw /usr/lpp/X11/Xamples/lib/Xaw/libXaw.a These should be moved to /usr/lib or some more reasonable place (or use symlinks), and ditto for the include files, which are initially placed in /usr/lpp/X11/Xamples/include. ================================================================ Notes of historical nature follow. Most recent changes are listed at the end of the file. ================================================================ This directory contains a version of xdvi capable of reading GF, PXL and PK font files. This version of xdvi is based on the source that "came with" X v10r3. Xdvi was modified by Paal Kvamme at the Norwegian Institute of Technology, based on the modifications I had made to dviimp (a dvi to ImPress converter). This code was again more or less directly translated from the web source of PKtoPX. If you discover (and fix) any bugs in this code, please notify me, so I can make the corresponding changes myself. --------- H}vard Eidnes (TeXish: H\aa vard Eidnes) Division of Computer Science Norwegian Institute of Technology E-Mail: h_eidnes%vax.runit.unit.uninett@nta-vax.arpa ================================================================ Also has path search added by Mark Eichin, looks in TEXFONTS ================================================================ ================================================================ Additional notes: X11 version now works on the IBM PC/RT as well as VAX. [eichin:19880313.1330EST] ================================================================ *MORE* fixes (for athena release locker) [eichin:19880722.2058EST] Fixes: narrow vertical and horizontal lines no longer disappear. bogus underlining (which usually occured on even sample sizes of odd sized characters) no longer occurs. -S number (or typing number followed by S) will adjust the sampling fraction; 0 is special cased to mean if anything in the sampled zone is set, set the sample, else clear it. Interesting to experiment with, though not useful for reading (the default value of 3 is just right.) -display and -geometry arguments work (so do old style forms, though they were broken before) fixed one of the PK debugging messages to print the correct font name instead of printing the pointer as text. included Ken Raeburn 's changes to support multiple screens. ================================================================ More changes: 1. Incorporated the bitmap under a viewport widget using the toolkit (X11 only); 2. Added an icon and icon geometry arguments (X11 only); 3. Supported window resizing; 4. Added a 'c' option to move whatever is currently under the cursor to the center of the window; 5. Added an 'R' option to reread the .dvi file, and added logic to make 'R' happen automatically whenever any part of the window is exposed and the dvi file changes (so that you can iconify xdvi, run tex, deiconify xdvi, and voila!); 6. Added a 'magnifying glass': when you push a button, a window pops up, showing the region of the page, unshrunk; 7. Added support for gf fonts; 8. Upgraded font searching (at our site we use /usr/custom/tex82/gf for gf fonts, /usr/custom/tex82/pk for pk fonts, etc.); 9. Made numerous internal changes (removed all the lint I could, made unshrunk bitmaps permanently resident, which speeds up size changing, made table.h necessary only for pxl.h, split up the source file into xdvi.c, dvi.c, gf.c, pxl.c, and pk.c, made shrinking occur relative to the character's hot point, etc.) 10. The program reads SIGIO signals and processes incoming events immediately, so that it can stop displaying things that would be erased anyway. If these interrupts are not coming through, then it also checks for incoming events every several dozen characters displayed. 11. Further split up dvi.c into dvi_init.c and dvi_draw.c; added compilation options for various internal bitmap representations. Fixed it so gcc won't give warnings, and so it works with R3 toolkit. -- Patchlevel 2: -- 12. Added MAXCHARS compilation option. Eliminated the nonsense with generating table.h. -- Patchlevel 3: -- 13. Added -altfont command line option and SYSV compilation option. ================================================================================ 4/1989 Modified for System V boxes. -DSYSV compiler option. Donald Richardson, donr@crystal.mie.clarkson.edu ================================================================================ -- Patchlevel 4: -- 14. Removed MAXCHARS compilation option. It's automatic now. Made X10 scrolling smoother. Implemented the moving magnifying glass. -- Patchlevel 5: -- 15. Implemented compilation without the toolkit, as well as scrollbars and tpic support in X10. Also this version should work with color VAXstations, although overstrike characters will come out incorrectly. 16. Fixed a bug in gf reading routines: specials at the beginning of a character def. were not being processed. Thanks to kevin@amath.washington.edu for a bug report and fix. 17. Added 'k' keystroke. -- Patchlevel 6: -- 18. Added buttons on the right side of the window. 19. Added -pagewidth and -pageheight command line options and A4 compilation option. 20. Added a yet more robust font finding algorithm. -- Patchlevel 7: -- 21. Replaced -pagewidth and -pageheight options with -paper. -- Patchlevel 8: -- 22. Added compatibility for X11R4 and VMS. Fixed up alignment of rules. -- Patchlevel 9: -- 23. Removed obsolete '#' and '=' options from the X11 version: they interfere with emacs. -- Patchlevel 10: -- 24. Implemented arrow keys, expert mode, searching for the font's actual size first, the -[xy]offset and -sw options, and numerous bug fixes. -- Patchlevel 11: -- 25. Implemented recursive searching for font files in subdirectories. 26. Changed +sw to -hushspecials and implemented -hush. 27. Modified mksedscript so that the man page comes out neater. 28. Added a -keep option and resource to match the `k' keystroke. -- Patchlevel 12: -- 29. Implemented virtual fonts (this does not include built-in Postscript fonts!!!). 30. X11R5 support, and numerous bug fixes. -- Patchlevel 13: -- 31. Added support for TeXXeT. -- Patchlevel 14: -- 32. Added support for greyscale anti-aliasing. -- Patchlevel 15: -- 33. Added support for MakeTeXPK, as in dvips. -- Patchlevel 16: -- 34. In the code for greyscale anti-aliasing, try to allocate a colormap so that GXor operations can be used for drawing. Also interpolate between foreground and background colors. -- Patchlevel 17: -- 35. Fixed some bugs in the greyscale code. 36. Implemented an environment variable for the MakeTeXPK script. 37. Replaced mksedscript with a script using /bin/sh. -- Patchlevel 18: -- 38. Implemented checking of checksums and the -hushchecksums option. 39. Implemented non-square magnifying glasses. 40. Removed support for X10. 41. Removed support for the pxl font format. 42. Added support for PostScript specials via DPS or NeWS or gs. -- Patchlevel 19: -- 43. Implemented `header=' and `!' PostScript specials (and the corresponding -noscan option). 44. Implemented path searching for PostScript header and figure files, in addition to shell escape capability (also the -allowshell option). 45. Allow setting of -gamma with the `S' keystroke. 46. Added options -nomakepk, -mfmode, -safer, -interpreter, -nogssafer, and -gspalette. -- Patchlevel 20: -- 47. Bug fixes. Paul Vojta, vojta@math.berkeley.edu *[XDVI]README.VMS;1+,f.0/ 40/Q- 0123KPWO156%7%8Ģ_o9GHJNAME ---- XDVI - DVI Previewer for VAX VMS systems running the DECWindows software. SYNOPSIS -------- XDVI [+[]] [-s ] [-density ] [-nogrey] [-gamma ] [-p ] [-margins ] [-sidemargin ] [-topmargin ] [-offsets ] [-xoffset ] [-yoffset ] [-paper ] [-altfont ] [-l] [-rv] [-mgs[n] ] [-hush] [-hushspecials] [-hushchars] [-hushchecksums] [-fg ] [-bg ] [-hl ] [-bd ] [-cr ] [-bw ] [-display ] [-geometry ] [-icongeometry ] [-iconic] [-keep] [-copy] [-thorough] [-version] dvi_file DESCRIPTION ----------- XDVI is a program which runs under the DECWindows system. It is used to preview DVI files, such as those produced by TeX and LaTeX. XDVI has the capability of displaying the file reduced by various (integer) factors, and also has a "magnifying glass" which allows one to see a small part of the unshrunk image momentarily. Before displaying any page or part thereof, XDVI checks to see if the DVI file has changed since the last time it was displayed. If this is the case, XDVI will reinitialize itself for the new DVI file. For this reason, exposing parts of the XDVI window while TeX is running should be avoided. This feature allows you to preview many versions of the same file while running XDVI only once. OPTIONS ------- In addition to specifying the DVI file (with or without the .DVI extension), XDVI supports the following command line options. If the option begins with a "+" instead of a "-", the option is restored to its default value. By default, these options can be set via the resource names given in parentheses in the description of each option. + Specifies the first page to show. If + is given without a number, the last page is assumed; the first page is the default. -altfont (.altFont) Declares a default font to use when the font in the DVI file cannot be found. This is useful, for example, with PostScript fonts. -background (.background) Determines the color of the background. Same as -bg. -bd (.borderColor) Determines the color of the window border. -bg (.background) Determines the color of the background. -bordercolor Same as -bd. -borderwidth (.borderWidth) Specifies the width of the border of the window. Same as -bw. -bw (.borderWidth) Specifies the width of the border of the window. -copy (.copy) Always use the copy operation when writing characters to the display. This option may be necessary for correct operation on a color display, but overstrike characters will be incorrect. If greyscale anti-aliasing is in use, the -copy operation will disable the use of colorplanes and make overstrikes come out incorrectly. See also -thorough. -cr (.cursorColor) Determines the color of the cursor. The default is the color of the page border. -density (.densityPercent) Determines the density used when shrinking bitmaps for fonts. A higher value produces a lighter font. The default value is 40. -display Specifies the host, display, and screen to be used for displaying the DVI file. The display must be specified in the form node::display.screen. The default is obtained from the logical name "DECW$DISPLAY", which may be defined using the SET DISPLAY command. -fg (.foreground) Determines the color of the text (foreground). -foreground Same as -fg. -gamma (.gamma) Controls the interpolation of colors in the greyscale anti-aliasing color palette. The default value is 1.0. For 0 < gamma < 1, the fonts will be lighter (more like the background), and for gamma > 1, the fonts will be darker (more like the foreground). Negative values behave the same way, but use a slightly different algorithm. -geometry (*geometry) Specifies the initial geometry of the window. -hl (.highlight) Determines the color of the page border. The default is the foreground color. -hush  c ~XDVI.BAKf [XDVI]README.VMS;10%J (.Hush) Causes XDVI to suppress all suppressible warnings. -hushchars (.hushLostChars) Causes XDVI to suppress warnings about references to characters which are not defined in the font. -hushchecksums (.hushChecksums) Causes XDVI to suppress warnings about checksum mismatches between the DVI file and the font file. -hushspecials (.hushSpecials) Causes XDVI to suppress warnings about \special strings which it cannot process. -icongeometry (.iconGeometry) Specifies the initial position for the icon. -iconic (.iconic) Causes the XDVI window to start in the iconic state. The default is to start with the window open. -keep (.keepPosition) Sets a flag to indicate that XDVI should not move to the home position when moving to a new page. See also the `k' keystroke. -l (.listFonts) Causes the names of the fonts used to be listed. -margins (.Margin) Specifies the size of both the top and side margins. This should be a decimal number optionally followed by "cm", e.g., 1.5 or 3cm, giving a measurement in inches or centimeters. XDVI determines the "home" position of the page within the window as follows. If the entire page fits in the window, then the margin settings are ignored. If, even after removing the margins from the left, right, top, and bottom, the page still cannot fit in the window, then the page is put in the window such that the top and left margins are hidden, and presumably the upper left-hand corner of the text on the page will be in the upper left-hand corner of the window. Otherwise, the text is centered in the window. See also -sidemargin, -topmargin, and the keystroke `M'. -mgs Same as -mgs1. -mgs[n] (.magnifierSize[n]) Specifies the size of the window to be used for the "magnifying glass" for Button n. The size may be given as an integer (indicating that the magnifying glass is to be square), or it may be given in the form WxH. See the MOUSE ACTIONS section. Defaults are 200x150, 400x250, 700x500, 1000x800, and 1200x1200. -nogrey (.grey) Turns off the use of greyscale anti-aliasing when printing shrunken bitmaps. In this case, the logic of the corresponding resource is the reverse: -nogrey corresponds to grey:off; +nogrey to grey:on. See also the 'G' keystroke. -offsets (.Offset) Specifies the size of both the horizontal and vertical offsets of the output on the page. This should be a decimal number optionally followed by "cm", e.g., 1.5 or 3cm, giving a measurement in inches or centimeters. By decree of the Stanford TeX Project, the default TeX page origin is always 1 inch over and down from the top-left page corner, even when non-American paper sizes are used. Therefore, the default offsets are 1.0 inch. See also -xoffset and -yoffset. -p (.pixelsPerInch) Defines the size of the fonts to use, in pixels per inch. The default value is 300. -paper (.paper) Specifies the size of the printed page. This may be of the form WxH (or WxHcm), where W is the width in inches (or cm) and H is the height in inches (or cm), respectively. There are also synonyms which may be used: us (8.5x11), usr (11x8.5), legal (8.5x14), foolscap (13.5x17), as well as the ISO sizes a1-a7, b1-b7, c1-c7, a1r-a7r (a1-a7 rotated), etc. The default size is 8.5 x 11 inches. -rv (.reverseVideo) Causes the page to be displayed with white characters on a black background, instead of vice versa. -s (.shrinkFactor) Defines the initial shrink factor. The default value is 3. -sidemargin (.sideMargin) Specifies the side margin (see -margins). -thorough (.thorough) XDVI will usually try to ensure that overstrike characters (e.g., \notin) are printed correctly. On monochrome displays, this is always possible with one logical operation, either AND or OR. On color displays, however, this may take two operations, one to set the appropriate bits and one to clear other bits. If this is the case, then by default XDVI will instead use the copy operation, which does not handle overstriking correctly. The -thorough option chooses the slower but more correct choice. See also -copy. -topmargin (.topMargin) Specifies the top and bottom margins (see -margins). -version Print information on the version of XDVI. -xoffset (.xOffset) Specifies the size of the horizontal offset of the output on the page. See -offsets. -yoffset (.yOffset) Specifies the size of the vertical offset of the output on the page. See -offsets. KEYSTROKES ---------- XDVI recognizes the following keystrokes when typed in its window. Each may optionally be preceded by a (positive or negative) number, whose interpretation will depend on the particular keystroke. Note that the keystrokes are case sensitive. q Quits the program. Control-C, control-D, and control-Z will do this, too. n Moves to the next page (or to the nth next page if a number is given). Synonyms are `f', Space, Return, Line Feed, and . p Moves to the previous page (or back n pages). Synonyms are `b', control-H, Delete, and . g Moves to the page with the given number. Initially, the first page is assumed to be page number 1, but this can be changed with the `P' keystroke, below. If no page number is given, then it goes to the last page. P "This is page number n." This can be used to make the `g' keystroke refer to actual page numbers instead of absolute page numbers. Control-L Redisplays the current page. ^ Move to the "home" position of the page. This is normally the upper left-hand corner of the page, depending on the margins as described in the -margins option, above. u Moves up two thirds of a window-full. The key is a synonym for this keystroke. d Moves down two thirds of a window-full. The key is a synonym for this keystroke. l Moves left two thirds of a window-full. The key is a synonym for this keystroke. r Moves right two thirds of a window-full. The key is a synonym for this keystroke. c Moves the page so that the point currently beneath the cursor is moved to the middle of the window. It also (gasp!) warps the cursor to the same place. M Sets the margins so that the point currently under the cursor is the upper left-hand corner of the text in the page. Note that this command itself does not move the image at all. For details on how the margins are used, see the -margins option. s Changes the shrink factor to the given number. If no number is given, the smallest factor that makes the entire page fit in the window will be used. (Margins are ignored in this computation.) S Sets the density factor to be used when shrinking bitmaps. This should be a number between 0 and 100; higher numbers produce lighter characters. R Forces the DVI file to be reread. This allows you to preview many versions of the same file while running XDVI only once. k Normally when XDVI switches pages, it moves to the home position as well. The `k' keystroke toggles a `keep-position' flag which, when set, will keep the same position when moving between pages. Also `0k' and `1k' clear and set this flag, respectively. See also the -keep option. G This key toggles the use of greyscale anti-aliasing for displaying shrunken bitmaps. In addition, the key sequences `0G' and `1G' clear and set this flag, respectively. See also the -nogrey option. MOUSE ACTIONS ------------- If the shrink factor is set to any number other than one, then clicking any mouse button will pop up a "magnifying glass" which shows the unshrunk image in the vicinity of the mouse click. This subwindow disappears when the mouse button is released. Different mouse buttons produce different sized windows, as indicated by the -mgs option. Moving the cursor while holding the button down will move the magnifying glass. Also, the scrollbars (if present) behave in the standard X Window way: pushing Button 2 in a scrollbar moves the top or left edge of the scrollbar to that point and optionally drags it; pushing Button 1 moves the image up or right by an amount equal to the distance from the button press to the upper left-hand corner of the window; pushing Button 3 moves the image down or left by the same amount. Note that this is different than the way DECWindows normally defines the actions of the mouse buttons in scrollbars. LOGICAL NAMES ------------- Unless the -display option is used on the command line, XDVI uses the logical name "DECW$DISPLAY" to specify which bit map display terminal to use. This logical name may be defined with the SET DISPLAY command. The logical name "XDVIFONTS" determines the directory path(s) searched for fonts in the following manner. The string consists of one or more strings separated by slashes. In each such string, the substring "%f" is changed to the font name; "%d" is changed to the magnification; and "%p" is changed to the font file format ("pk" or "gf"). If no "%f" appears in the string, then the string ":%f.%d%p" is added on the end. For example, if the string is "TEX_FONTS" and the font is cmr10 at 300 dots per inch, then XDVI searches for TEX_FONTS:CMR10.300PK and TEX_FONTS:CMR10.300GF, in that order. An extra slash anywhere in the "XDVIFONTS" logical name causes the system default directories to be tried at that point. If the font is not found in the desired size, then XDVI will try to find the nearest size. If the font cannot be found at all, then XDVI will try to vary the point size of the font (within a certain range), and if this fails, then it will use the font specified as the alternate font (cf. -altfont). In addition, a "%F" specifier is available; it is a synonym for "%f", but it does not inhibit putting the string ":%f.%d%p" at the end. Finally, a "%b" specifier is available; it is converted to the current resolution being used (i.e., the value of the -p parameter or the .pixelsperinch resource). For compatibility with some versions of TeX, you may also use the logical name "TEXFONTS" in place of "XDVIFONTS", although in that case the string should not include any "%" specifiers. The reason for recognizing "TEXFONTS" is that certain versions of TeX also support the convention regarding an extra slash in the font path; therefore, users who create their own fonts can put both their .TFM and raster files in the same directory and do $ DEFINE TEXFONTS "/MFDIR" or $ DEFINE TEXFONTS "MFDIR/" in order to get both TeX and XDVI to search their directory in addition to the system standard directories. The "XDVIFONTS" logical name overrides the "TEXFONTS" logical name, so that on those sites where "TEXFONTS" must be set explicitly, and therefore this feature is not useful, the "XDVIFONTS" logical name may be set to an empty string to cause XDVI to ignore "TEXFONTS". XDVI also recognizes the "PKFONTS" and "TEXPKS" logical names, which are checked after "XDVIFONTS" but before "TEXFONTS". The logical name "XDVISIZES" may be set to indicate which sizes of fonts are available. It should consist of a list of numbers separated by slashes. If the list begins with a slash, the system default sizes are used, as well. Sizes are expressed in dots per inch and must be integers. The current default set of sizes is 300/329/360/432/518/622/746. XDVI will also try the actual size of the font before trying any of the given sizes. Virtual fonts are also supported, although XDVI does not have any built-in fonts to which they can refer. The search path for .VF files can be specified with the "XDVIVFS" logical name in a similar manner to that for the "XDVIFONTS" logical name. XDVI will also check the "VFFONTS" logical name if the "XDVIFONTS" logical name is not defined. Virtual fonts are searched for immediately after looking for the font as a normal font in the exact size specified. FILES ----- TEX_FONTS System default directory for font pixel files. RESOURCE NAMES -------------- All of the command line options may be set via the resource names given in parentheses in the descriptions of the options. This may be used to define a specific set of options as the default each time you run XDVI. To make use of this feature, create a file named DECW$XDEFAULTS.DAT in the same directory as the rest of your DECW*.DAT files. Include in this file the resource names and arguments of each of the options you wish to specify. For example: XDvi.copy: off XDvi.thorough: on XDvi.shrinkFactor: 2 XDvi.Margin: 0.95 XDvi*geometry: 1015x750+3+25 When XDVI is invoked, it would behave as if it had been invoked with the following command: XDVI +copy -thorough -s 2 -margins 0.95 -geometry 1015x750+3+25 dvifile Specifying options on the command line will override any options specified via resource names in the DECW$XDEFAULTS.DAT file. INSTALLATION ------------ The installation of XDVI on a VMS system is relatively easy. If you have a source-only distribution, you will need to have access to the VAX C compiler to build an executable image. The following steps should get you started: 1) Gather all of the distribution files into one directory, and then create the executable image by executing the MAKE_VMS.COM file: $ @MAKE_VMS 2) Create a help file for XDVI using the supplied XDVI.RNH file: $ RUNOFF XDVI.RNH 3) Insert the resulting XDVI.HLP file into one of your local help libraries: $ LIBRARY /INSERT HELPLIB.HLB XDVI.HLP 4) Modify the command file you use to set up the TEX commands so that it defines the foreign symbol XDVI, and the logical names "XDVIFONTS", "XDVIVFS", and "XDVISIZES". For more information on the expected contents of the logical names, see the LOGICAL NAMES section of this document. The following lines are what I use locally: $ PROC = F$ENVIRONMENT ("PROCEDURE") $ TEXDIR = F$PARSE (PROC, , , "DEVICE", "NO_CONCEAL") + - F$PARSE (PROC, , , "DIRECTORY", "NO_CONCEAL") $ TEXDIR = TEXDIR - "][" - "][" - "][" - "]" $ TEXDISK = TEXDIR + ".]" $ PIXELS = TEXDIR + ".GF.CANON300.]" $ LPIXELS = TEXDIR + ".LOCAL.PIXELS.CANON300.]" $! $! Define the virtual disk devices. $! $ DEFINE /PROCESS /TRANSLATE = (CONCEAL, TERMINAL) TEX_DISK 'TEXDISK' $ DEFINE /PROCESS /TRANSLATE = (CONCEAL, TERMINAL) PIXELS$ 'PIXELS' $ DEFINE /PROCESS /TRANSLATE = (CONCEAL, TERMINAL) LPIXELS$ 'LPIXELS' $! $! Define the directories for TeX and its related TeXware. $! $ DEFINE TEX_EXE TEX_DISK:[LOCAL.PROGRAMS] $ DEFINE TEX_PIXELS PIXELS$, LPIXELS$ $! $! Define the information necessary to run XDVI. $! $ XDVI :== "$TEX_EXE:XDVI" $ DEFINE XDVIFONTS "TEX_PIXELS:[DPI%d]%f.%p" $ DEFINE XDVIVFS XDVIFONTS $ DEFINE XDVISIZES - "300/329/360/432/518/600/622/746/896/1075/1200/1290/1548" $ EXIT 5) If you wish, you may create a DECW$XDEFAULTS.DAT file that specifies a default set of command line options. See the RESOURCE NAMES section for more information and an example of what I use locally. If you have any comments about XDVI, or find any bugs in the program, please contact me at the address below. Enjoy! Scott Allendorf Department of Physics and Astronomy The University of Iowa Iowa City, IA 52242 Email: scott-allendorf@uiowa.edu AUTHORS ------- Eric Cooper, CMU, did a version for direct output to a QVSS. Modified for X by Bob Scheifler, MIT Laboratory for Computer Science. Modified for X11 by Mark Eichin, MIT SIPB. Modified for VMS and DECWindows by Scott Allendorf, University of Iowa. Additional enhancements by many others. e*[XDVI]SPECIAL.C;2+,; .?/pX 4M?<-- 0D123KPWO@569g+m7"m8`o9GHJ0/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTE: * This module is based on prior work as noted below. */ /* * Support drawing routines for TeXsun and TeX * * Copyright, (C) 1987, 1988 Tim Morgan, UC Irvine * Adapted for xdvi by Jeffrey Lee, U. of Toronto * * At the time these routines are called, the values of hh and vv should * have been updated to the upper left corner of the graph (the position * the \special appears at in the dvi file). Then the coordinates in the * graphics commands are in terms of a virtual page with axes oriented the * same as the Imagen and the SUN normally have: * * 0,0 * +-----------> +x * | * | * | * \ / * +y * * Angles are measured in the conventional way, from +x towards +y. * Unfortunately, that reverses the meaning of "counterclockwise" * from what it's normally thought of. * * A lot of floating point arithmetic has been converted to integer * arithmetic for speed. In some places, this is kind-of kludgy, but * it's worth it. */ #include #include #ifdef VMS #include #endif #include "xdvi.h" extern char *strtok ARGS((char *, _Xconst char *)); #ifdef X_NOT_STDC_ENV #ifndef atof extern double atof ARGS((_Xconst char *)); #endif extern char *getenv ARGS((_Xconst char *)); #endif /* X_NOT_STDC_ENV */ #if PS #ifdef _POSIX_SOURCE #include #ifdef PATH_MAX #define FILENAMESIZE PATH_MAX #endif #endif #ifndef FILENAMESIZE #define FILENAMESIZE 512 #endif #ifdef VFORK #if VFORK == include #include #endif #else #define vfork fork #endif #include #ifndef VMS #include #else /* VMS */ #include #define pid_t int #define unlink remove #ifndef S_IRUSR # define S_IRUSR 0000400 /* read permission: owner */ #endif #ifndef S_IWUSR # define S_IWUSR 0000200 /* write permission: owner */ #endif #endif /* VMS */ #include #ifdef X_NOT_STDC_ENV extern int errno; #endif #endif /* PS */ #define MAXPOINTS 300 /* Max points in a path */ #define TWOPI (3.14159265359*2.0) #define MAX_PEN_SIZE 7 /* Max pixels of pen width */ static int xx[MAXPOINTS], yy[MAXPOINTS]; /* Path in milli-inches */ static int path_len = 0; /* # points in current path */ static int pen_size = 1; /* Pixel width of lines drawn */ static Boolean whiten = False; static Boolean shade = False; static Boolean blacken = False; /* Unfortunately, these values also appear in dvisun.c */ #define xRESOLUTION (pixels_per_inch/shrink_factor) #define yRESOLUTION (pixels_per_inch/shrink_factor) /* * Issue warning messages */ static void Warning(fmt, msg) char *fmt, *msg; { Fprintf(stderr, "%s: ", prog); Fprintf(stderr, fmt, msg); (void) fputc('\n', stderr); } /* * X drawing routines */ #define toint(x) ((int) ((x) + 0.5)) #define xconv(x) (toint(tpic_conv*(x))/shrink_factor + PXL_H) #define yconv(y) (toint(tpic_conv*(y))/shrink_factor + PXL_V) /* * Draw a line from (fx,fy) to (tx,ty). * Right now, we ignore pen_size. */ static void line_btw(fx, fy, tx, ty) int fx, fy, tx, ty; { register int fcx = xconv(fx), tcx = xconv(tx), fcy = yconv(fy), tcy = yconv(ty); if ((fcx < max_x || tcx < max_x) && (fcx >= min_x || tcx >= min_x) && (fcy < max_y || tcy < max_y) && (fcy >= min_y || tcy >= min_y)) XDrawLine(DISP, currwin.win, ruleGC, fcx - currwin.base_x, fcy - currwin.base_y, tcx - currwin.base_x, tcy - currwin.base_y); } /* * Draw a dot at (x,y) */ static void dot_at(x, y) int x, y; { register int cx = xconv(x), cy = yconv(y); if (cx < max_x && cx >= min_x && cy < max_y && cy >= min_y) XDrawPoint(DISP, currwin.win, ruleGC, cx - currwin.base_x, cy - currwin.base_y); } /* * Apply the requested attributes to the last path (box) drawn. * Attributes are reset. * (Not currently implemented.) */ /* ARGSUSED */ static void do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y) int last_min_x, last_max_x, last_min_y, last_max_y; { } /* * Set the size of the virtual pen used to draw in milli-inches */ /* ARGSUSED */ static void set_pen_size(cp) char *cp; { int ps; if (sscanf(cp, " %d ", &ps) != 1) { Warning("illegal .ps command format: %s", cp); return; } pen_size = (ps * (xRESOLUTION + yRESOLUTION) + 1000) / 2000; if (pen_size < 1) pen_size = 1; else if (pen_size > MAX_PEN_SIZE) pen_size = MAX_PEN_SIZE; } /* * Print the line defined by previous path commands */ static void flush_path() { register int i; int last_min_x, last_max_x, last_min_y, last_max_y; last_min_x = 30000; last_min_y = 30000; last_max_x = -30000; last_max_y = -30000; for (i = 1; i < path_len; i++) { if (xx[i] > last_max_x) last_max_x = xx[i]; if (xx[i] < last_min_x) last_min_x = xx[i]; if (yy[i] > last_max_y) last_max_y = yy[i]; if (yy[i] < last_min_y) last_min_y = yy[i]; line_btw(xx[i], yy[i], xx[i+1], yy[i+1]); } if (xx[path_len] > last_max_x) last_max_x = xx[path_len]; if (xx[path_len] < last_min_x) last_min_x = xx[path_len]; if (yy[path_len] > last_max_y) last_max_y = yy[path_len]; if (yy[path_len] < last_min_y) last_min_y = yy[path_len]; path_len = 0; do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y); } /* * Print a dashed line along the previously defined path, with * the dashes/inch defined. */ static void flush_dashed(cp, dotted) char *cp; Boolean dotted; { int i; int numdots; int lx0, ly0, lx1, ly1; int cx0, cy0, cx1, cy1; float inchesperdash; double d, spacesize, a, b, dx, dy, milliperdash; if (sscanf(cp, " %f ", &inchesperdash) != 1) { Warning("illegal format for dotted/dashed line: %s", cp); return; } if (path_len <= 1 || inchesperdash <= 0.0) { Warning("illegal conditions for dotted/dashed line", ""); return; } milliperdash = inchesperdash * 1000.0; lx0 = xx[1]; ly0 = yy[1]; lx1 = xx[2]; ly1 = yy[2]; dx = lx1 - lx0; dy = ly1 - ly0; if (dotted) { numdots = sqrt(dx*dx + dy*dy) / milliperdash + 0.5; if (numdots == 0) numdots = 1; for (i = 0; i <= numdots; i++) { a = (float) i / (float) numdots; cx0 = lx0 + a * dx + 0.5; cy0 = ly0 + a * dy + 0.5; dot_at(cx0, cy0); } } else { d = sqrt(dx*dx + dy*dy); numdots = d / (2.0 * milliperdash) + 1.0; if (numdots <= 1) line_btw(lx0, ly0, lx1, ly1); else { spacesize = (d - numdots * milliperdash) / (numdots - 1); for (i = 0; i < numdots - 1; i++) { a = i * (milliperdash + spacesize) / d; b = a + milliperdash / d; cx0 = lx0 + a * dx + 0.5; cy0 = ly0 + a * dy + 0.5; cx1 = lx0 + b * dx + 0.5; cy1 = ly0 + b * dy + 0.5; line_btw(cx0, cy0, cx1, cy1); b += spacesize / d; } cx0 = lx0 + b * dx + 0.5; cy0 = ly0 + b * dy + 0.5; line_btw(cx0, cy0, lx1, ly1); } } path_len = 0; } /* * Add a point to the current path */ static void add_path(cp) char *cp; { int pathx, pathy; if (++path_len >= MAXPOINTS) oops("Too many points"); if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2) oops("Malformed path command"); xx[path_len] = pathx; yy[path_len] = pathy; } /* * Draw to a floating point position */ static void im_fdraw(x, y) double x,y; { if (++path_len >= MAXPOINTS) oops("Too many arc points"); xx[path_len] = x + 0.5; yy[path_len] = y + 0.5; } /* * Draw an ellipse with the indicated center and radices. */ static void draw_ellipse(xc, yc, xr, yr) int xc, yc, xr, yr; { double angle, theta; int n; int px0, py0, px1, py1; angle = (xr + yr) / 2.0; theta = sqrt(1.0 / angle); n = TWOPI / theta + 0.5; if (n < 12) n = 12; else if (n > 80) n = 80; n /= 2; theta = TWOPI / n; angle = 0.0; px0 = xc + xr; /* cos(0) = 1 */ py0 = yc; /* sin(0) = 0 */ while ((angle += theta) <= TWOPI) { px1 = xc + xr*cos(angle) + 0.5; py1 = yc + yr*sin(angle) + 0.5; line_btw(px0, py0, px1, py1); px0 = px1; py0 = py1; } line_btw(px0, py0, xc + xr, yc); } /* * Draw an arc */ static void arc(cp, invis) char *cp; Boolean invis; { int xc, yc, xrad, yrad, n; float start_angle, end_angle, angle, theta, r; double xradius, yradius, xcenter, ycenter; if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle, &end_angle) != 6) { Warning("illegal arc specification: %s", cp); return; } if (invis) return; /* We have a specialized fast way to draw closed circles/ellipses */ if (start_angle <= 0.0 && end_angle >= 6.282) { draw_ellipse(xc, yc, xrad, yrad); return; } xcenter = xc; ycenter = yc; xradius = xrad; yradius = yrad; r = (xradius + yradius) / 2.0; theta = sqrt(1.0 / r); n = 0.3 * TWOPI / theta + 0.5; if (n < 12) n = 12; else if (n > 80) n = 80; n /= 2; theta = TWOPI / n; flush_path(); im_fdraw(xcenter + xradius * cos(start_angle), ycenter + yradius * sin(start_angle)); angle = start_angle + theta; if (end_angle < start_angle) end_angle += TWOPI; while (angle < end_angle) { im_fdraw(xcenter + xradius * cos(angle), ycenter + yradius * sin(angle)); angle += theta; } im_fdraw(xcenter + xradius * cos(end_angle), ycenter + yradius * sin(end_angle)); flush_path(); } /* * APPROXIMATE integer distance between two points */ #define dist(x0, y0, x1, y1) (abs(x0 - x1) + abs(y0 - y1)) /* * Draw a spline along the previously defined path */ static void flush_spline() { int xp, yp; int N; int lastx, lasty; Boolean lastvalid = False; int t1, t2, t3; int steps; int j; register int i, w; #ifdef lint lastx = lasty = -1; #endif N = path_len + 1; xx[0] = xx[1]; yy[0] = yy[1]; xx[N] = xx[N-1]; yy[N] = yy[N-1]; for (i = 0; i < N - 1; i++) { /* interval */ steps = (dist(xx[i], yy[i], xx[i+1], yy[i+1]) + dist(xx[i+1], yy[i+1], xx[i+2], yy[i+2])) / 80; for (j = 0; j < steps; j++) { /* points within */ w = (j * 1000 + 500) / steps; t1 = w * w / 20; w -= 500; t2 = (750000 - w * w) / 10; w -= 500; t3 = w * w / 20; xp = (t1*xx[i+2] + t2*xx[i+1] + t3*xx[i] + 50000) / 100000; yp = (t1*yy[i+2] + t2*yy[i+1] + t3*yy[i] + 50000) / 100000; if (lastvalid) line_btw(lastx, lasty, xp, yp); lastx = xp; lasty = yp; lastvalid = True; } } path_len = 0; } /* * Shade the last box, circle, or ellipse */ static void shade_last() { blacken = whiten = False; shade = True; } /* * Make the last box, circle, or ellipse, white inside (shade with white) */ static void whiten_last() { whiten = True; blacken = shade = False; } /* * Make last box, etc, black inside */ static void blacken_last() { blacken = True; whiten = shade = False; } /* * Code for PostScript specials begins here. */ #if PS static void ps_startup ARGS((int, int, char *)); static void ps_startup2 ARGS((void)); void NullProc ARGS((void)) {} /* ARGS k6Y~XDVI.BAK;  [XDVI]SPECIAL.C;2M?7HUSED */ static void NullProc2 ARGS((char *)); struct psprocs psp = { /* used for lazy startup of the ps machinery */ /* toggle */ NullProc, /* destroy */ NullProc, /* interrupt */ NullProc, /* endpage */ NullProc, /* drawbegin */ ps_startup, /* drawraw */ NullProc2, /* drawfile */ NULL, /* drawend */ NullProc2, /* beginheader */ ps_startup2, /* endheader */ NullProc, /* newdoc */ NullProc}; struct psprocs no_ps_procs = { /* used if postscript is unavailable */ /* toggle */ NullProc, /* destroy */ NullProc, /* interrupt */ NullProc, /* endpage */ NullProc, /* drawbegin */ drawbegin_none, /* drawraw */ NullProc2, /* drawfile */ NULL, /* drawend */ NullProc2, /* beginheader */ NullProc, /* endheader */ NullProc, /* newdoc */ NullProc}; #endif /* PS */ static Boolean bbox_valid; static unsigned int bbox_width; static unsigned int bbox_height; static int bbox_voffset; void draw_bbox() { if (bbox_valid) { put_border(PXL_H - currwin.base_x, PXL_V - currwin.base_y - bbox_voffset, bbox_width, bbox_height, ruleGC); bbox_valid = False; } } #if PS static void actual_startup() { char *p; /* * First sort out the paths. */ p = getenv("XDVIFIGS"); if (p == NULL) p = getenv("TEXINPUTS"); if (p != NULL) { figfind.auxpath = figfind.mainpath; figfind.mainpath = p; } p = getenv("XDVIHEADERS"); if (p == NULL) p = getenv("HEADERPATH"); if (p != NULL) { headerfind.auxpath = headerfind.mainpath; headerfind.mainpath = p; } /* * Figure out what we want to use to display postscript figures * and set at most one of the following to True: * resource.useGS, resource.useDPS, resource.useNeWS * * Choose DPS then NEWS then GhostScript if they are available */ if (!( #ifdef PS_DPS (resource.useDPS && initDPS()) #if defined(PS_NEWS) || defined(PS_GS) || #endif #endif /* PS_DPS */ #ifdef PS_NEWS (resource.useNeWS && initNeWS()) #ifdef PS_GS || #endif #endif /* PS_NEWS */ #ifdef PS_GS (resource.useGS && initGS()) #endif )) psp = no_ps_procs; } static void ps_startup(xul, yul, cp) int xul, yul; char *cp; { if (!resource._postscript) { psp.toggle = actual_startup; draw_bbox(); return; } actual_startup(); psp.drawbegin(xul, yul, cp); } static void ps_startup2() { actual_startup(); psp.beginheader(); } /* ARGSUSED */ static void NullProc2(cp) char *cp; {} /* ARGSUSED */ void #if NeedFunctionPrototypes drawbegin_none(int xul, int yul, char *cp) #else /* !NeedFunctionPrototypes */ drawbegin_none(xul, yul, cp) int xul, yul; char *cp; #endif /* NeedFunctionPrototypes */ { draw_bbox(); } /* ||| * This routine is just a stopgap measure. My next major project for * xdvi is to upgrade the file searching routines so that they conform * to the standard TeX Directory Structure (TDS). */ #ifndef VMS #define PATH_SEP ':' #else /* VMS */ #define PATH_SEP '/' #endif /* VMS */ static FILE * pathfopen(filename, buffer, pathlist1, pathlist2) _Xconst char *filename; char *buffer; _Xconst char *pathlist1; _Xconst char *pathlist2; { FILE *f; _Xconst char *p; char *q; for (;;) { p = index(pathlist1, PATH_SEP); if (p == NULL) p = pathlist1 + strlen(pathlist1); if (p == pathlist1) { f = NULL; if (pathlist2 != NULL) { f = pathfopen(filename, buffer, pathlist2, NULL); pathlist2 = NULL; } } else { bcopy(pathlist1, buffer, p - pathlist1); q = buffer + (p - pathlist1); #ifndef VMS *q++ = '/'; #endif Strcpy(q, filename); if (debug & DBG_OPEN) Printf("Trying PS file %s\n", buffer); f = xfopen(buffer, OPEN_TEXTMODE); } if (f != NULL) return f; if (*p == '\0') return NULL; pathlist1 = p + 1; } } struct tickrec { struct tickrec *next; int pageno; char *command; #ifndef VMS _Xconst char *tmpname; #else char *tmpname; #endif }; static struct tickrec *tickhead = NULL; /* head of linked list of */ /* cached information */ static int nticks = 0; /* number of records total */ #ifndef TICKCACHESIZE #define TICKCACHESIZE 3 #endif #ifndef TICKTMP #define TICKTMP "/tmp" #endif static struct tickrec * cachetick(filename, pathinfo, fp) _Xconst char *filename; struct findrec *pathinfo; FILE **fp; { struct tickrec **linkp; struct tickrec *tikp; struct tickrec **freerecp; linkp = &tickhead; freerecp = NULL; for (;;) { /* see if we have it already */ tikp = *linkp; if (tikp == NULL) { /* if end of list */ if (nticks >= TICKCACHESIZE && freerecp != NULL) { tikp = *freerecp; *freerecp = tikp->next; free(tikp->command); } else { tikp = (struct tickrec *) xmalloc(sizeof(struct tickrec), "tick list node"); tikp->pageno = -1; #ifndef VMS tikp->tmpname = tempnam(TICKTMP, "xdvi"); if (tikp->tmpname == NULL) { Fputs("Cannot create temporary file.\n", stderr); free(tikp); return NULL; } #else tikp->tmpname = (char *)malloc(L_tmpnam); if (tikp->tmpname == NULL) { Fputs("Cannot create temporary file.\n", stderr); free(tikp); return NULL; } tikp->tmpname = tmpnam(tikp->tmpname); #endif ++nticks; } tikp->command = xmalloc((unsigned) strlen(filename) + 1, "tick list data"); Strcpy(tikp->command, filename); *fp = NULL; break; } if (strcmp(filename, tikp->command) == 0) { /* found it */ *linkp = tikp->next; /* unlink it */ *fp = xfopen(tikp->tmpname, OPEN_MODE); if (*fp == NULL) perror(tikp->tmpname); break; } if (tikp->pageno != current_page) freerecp = linkp; linkp = &tikp->next; } tikp->next = tickhead; /* link it in */ tickhead = tikp; tikp->pageno = pathinfo != &headerfind ? current_page : -1; return tikp; } #ifndef UNCOMPRESS #define UNCOMPRESS "uncompress" #endif #ifndef GUNZIP #define GUNZIP "gunzip" #endif static void sendfile(filename, pathinfo) _Xconst char *filename; struct findrec *pathinfo; { FILE *f; char buffer[FILENAMESIZE]; static _Xconst char *argv[] = {NULL, "-c", NULL, NULL}; _Xconst char *bufp; struct tickrec *tikp; char *p; int len; char magic2; if (psp.drawfile == NULL) return; if (filename[0] == '`') { if (!resource.allow_shell) { if (!hush_spec_now) Fprintf(stderr, "%s: shell escape disallowed for special \"%s\"\n", prog, filename); return; } tikp = cachetick(filename, pathinfo, &f); if (tikp == NULL) return; if (f == NULL) { Sprintf(buffer, "%s > %s", filename + 1, tikp->tmpname); (void) system(buffer); f = xfopen(tikp->tmpname, OPEN_TEXTMODE); if (f == NULL) { perror(tikp->tmpname); return; } } bufp = tikp->tmpname; } else { if (filename[0] == '/') { if (debug & DBG_OPEN) Printf("Trying PS file %s\n", filename); f = xfopen(filename, OPEN_TEXTMODE); bufp = filename; } else { /* first try the same path as the dvi file */ p = rindex(dvi_name, '/'); if (p == NULL) bufp = filename; else { bcopy(dvi_name, buffer, ++p - dvi_name); p = buffer + (p - dvi_name); Strcpy(p, filename); bufp = buffer; } if (debug & DBG_OPEN) Printf("Trying PS file %s\n", bufp); f = xfopen(bufp, OPEN_TEXTMODE); /* if no luck, try a search over the paths */ if (f == NULL) { f = pathfopen(filename, buffer, pathinfo->mainpath, pathinfo->auxpath); bufp = buffer; } } /* if still no luck, complain */ if (f == NULL) { Fprintf(stderr, "%s: cannot find PS file `%s'.\n", prog, filename); draw_bbox(); return; } /* check for compressed files */ len = strlen(filename); #ifndef VMS if ((len > 2 && strcmp(filename + len - 2, ".Z") == 0 && (argv[0] = UNCOMPRESS, magic2 = '\235', True)) || (len > 3 && strcmp(filename + len - 3, ".gz") == 0 && (argv[0] = GUNZIP, magic2 = '\213', True))) { #else /* VMS */ if ((len > 2 && (strcmp(filename + len - 2, "_Z") == 0 || strcmp(filename + len - 2, "_z") == 0) && (argv[0] = UNCOMPRESS, magic2 = '\235', True)) || (len > 3 && (strcmp(filename + len - 3, "_gz") == 0 || strcmp(filename + len - 3, "_GZ") == 0 || strcmp(filename + len - 3, "-gz") == 0 || strcmp(filename + len - 3, "-GZ") == 0 || strcmp(filename + len - 3, ".gz") == 0 || strcmp(filename + len - 3, ".GZ") == 0) && (argv[0] = GUNZIP, magic2 = '\213', True))) { #endif /* VMS */ if (getc(f) != '\037' || (char) getc(f) != magic2) rewind(f); else { Fclose(f); ++n_files_left; tikp = cachetick(filename, pathinfo, &f); if (tikp == NULL) return; if (f == NULL) { pid_t pid; int handle; int status; argv[2] = bufp; handle = open(tikp->tmpname, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (handle == -1) { perror(tikp->tmpname); return; } Fflush(stderr); /* avoid double flushing */ pid = vfork(); if (pid == 0) { /* if child */ (void) dup2(handle, 1); (void) execvp(argv[0], (char **) argv); Fprintf(stderr, "Execvp of %s failed.\n", argv[0]); Fflush(stderr); _exit(1); } (void) close(handle); for (;;) { #ifndef VMS if (waitpid(pid, &status, 0) != -1) break; if (errno == EINTR) continue; #else pid_t retpid = wait(&status); if (retpid == pid) break; if ((retpid != -1) || (errno == EINTR)) continue; #endif perror("[xdvi] waitpid"); return; } f = xfopen(tikp->tmpname, OPEN_TEXTMODE); if (f == NULL) { perror(tikp->tmpname); return; } } bufp = tikp->tmpname; } } } /* Success! */ psp.drawfile(bufp, f); /* this is supposed to close the file */ } void ps_newdoc() { struct tickrec *tikp; scanned_page = scanned_page_bak = scanned_page_reset = resource.prescan ? -1 : total_pages; for (tikp = tickhead; tikp != NULL; tikp = tikp->next) tikp->pageno = -1; psp.newdoc(); } void ps_destroy() { struct tickrec *tikp; psp.destroy(); for (tikp = tickhead; tikp != NULL; tikp = tikp->next) if (unlink(tikp->tmpname) < 0) perror(tikp->tmpname); } #endif /* PS */ static void psfig_special(cp) char *cp; { char *filename; int raww, rawh; if (strncmp(cp, ":[begin]", 8) == 0) { cp += 8; bbox_valid = False; if (sscanf(cp,"%d %d\n", &raww, &rawh) >= 2) { bbox_valid = True; bbox_width = pixel_conv(spell_conv(raww)); bbox_height = pixel_conv(spell_conv(rawh)); bbox_voffset = 0; } if (currwin.win == mane.win) #if PS psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, cp); #else draw_bbox(); #endif psfig_begun = True; } else if (strncmp(cp, " plotfile ", 10) == 0) { cp += 10; while (isspace(*cp)) cp++; for (filename = cp; !isspace(*cp); ++cp); *cp = '\0'; #if PS if (currwin.win == mane.win) sendfile(filename, &figfind); #endif } else if (strncmp(cp, ":[end]", 6) == 0) { cp += 6; #if PS if (currwin.win == mane.win) psp.drawend(cp); #endif bbox_valid = False; psfig_begun = False; } else if (*cp == ':') { /* I am going to send some raw postscript stuff */ ++cp; /* skip the colon */ #if PS if (currwin.win == mane.win) psp.drawraw(cp); #endif } else { /* also raw PostScript, but no extra colon to skip */ #if PS if (currwin.win == mane.win) { if (psfig_begun) psp.drawraw(cp); else { psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, cp); psp.drawend(""); } } #endif } } /* Keys for epsf specials */ static char *keytab[] = {"clip", "llx", "lly", "urx", "ury", "rwi", "rhi", "hsize", "vsize", "hoffset", "voffset", "hscale", "vscale", "angle"}; #define KEY_LLX keyval[0] #define KEY_LLY keyval[1] #define KEY_URX keyval[2] #define KEY_URY keyval[3] #define KEY_RWI keyval[4] #define KEY_RHI keyval[5] #define NKEYS (sizeof(keytab)/sizeof(*keytab)) #define N_ARGLESS_KEYS 1 static void epsf_special(cp) char *cp; { char *filename; static char *buffer; static unsigned int buflen = 0; unsigned int len; char *q; int flags = 0; double keyval[6]; filename = cp; if (*cp == '\'' || *cp == '"') { do ++cp; while (*cp != '\0' && *cp != *filename); ++filename; } else while (*cp != '\0' && *cp != ' ' && *cp != '\t') ++cp; if (*cp != '\0') *cp++ = '\0'; while (*cp == ' ' || *cp == '\t') ++cp; len = strlen(cp) + NKEYS + 30; if (buflen < len) { if (buflen != 0) free(buffer); buflen = len; buffer = xmalloc(buflen, "epsf buffer"); } Strcpy(buffer, "@beginspecial"); q = buffer + strlen(buffer); while (*cp != '\0') { char *p1 = cp; int keyno; while (*p1 != '=' && !isspace(*p1) && *p1 != '\0') ++p1; for (keyno = 0;; ++keyno) { if (keyno >= NKEYS) { if (!hush_spec_now) Fprintf(stderr, "%s: unknown keyword (%*s) in \\special will be ignored\n", prog, (int) (p1 - cp), cp); break; } if (memcmp(cp, keytab[keyno], p1 - cp) == 0) { if (keyno >= N_ARGLESS_KEYS) { while (isspace(*p1)) ++p1; if (*p1 == '=') { ++p1; while (isspace(*p1)) ++p1; } if (keyno < N_ARGLESS_KEYS + 6) { keyval[keyno - N_ARGLESS_KEYS] = atof(p1); flags |= (1 << (keyno - N_ARGLESS_KEYS)); } *q++ = ' '; while (!isspace(*p1) && *p1 != '\0') *q++ = *p1++; } *q++ = ' '; *q++ = '@'; Strcpy(q, keytab[keyno]); q += strlen(q); break; } } cp = p1; while (!isspace(*cp) && *cp != '\0') ++cp; while (isspace(*cp)) ++cp; } Strcpy(q, " @setspecial\n"); bbox_valid = False; if ((flags & 0x30) == 0x30 || ((flags & 0x30) && (flags & 0xf) == 0xf)){ bbox_valid = True; bbox_width = 0.1 * ((flags & 0x10) ? KEY_RWI : KEY_RHI * (KEY_URX - KEY_LLX) / (KEY_URY - KEY_LLY)) * dimconv / shrink_factor + 0.5; bbox_voffset = bbox_height = 0.1 * ((flags & 0x20) ? KEY_RHI : KEY_RWI * (KEY_URY - KEY_LLY) / (KEY_URX - KEY_LLX)) * dimconv / shrink_factor + 0.5; } if (currwin.win == mane.win) { #if PS psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, buffer); /* talk directly with the DPSHandler here */ sendfile(filename, &figfind); psp.drawend(" @endspecial"); #else draw_bbox(); #endif } bbox_valid = False; } static void quote_special(cp) char *cp; { bbox_valid = False; #if PS if (currwin.win == mane.win) { psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, "@beginspecial @setspecial "); /* talk directly with the DPSHandler here */ psp.drawraw(cp + 1); psp.drawend(" @endspecial"); } #endif /* nothing else to do--there's no bbox here */ } #if PS static void scan_header(cp) char *cp; { char *filename; filename = cp; if (*cp == '\'' || *cp == '"') { do ++cp; while (*cp != '\0' && *cp != *filename); *cp = '\0'; ++filename; } psp.beginheader(); sendfile(filename, &headerfind); } static void scan_bang(cp) char *cp; { psp.beginheader(); psp.drawraw(cp + 1); } #endif /* PS */ /* * The following copyright message applies to the rest of this file. --PV */ /* * This program is Copyright (C) 1987 by the Board of Trustees of the * University of Illinois, and by the author Dirk Grunwald. * * This program may be freely copied, as long as this copyright * message remaines affixed. It may not be sold, although it may * be distributed with other software which is sold. If the * software is distributed, the source code must be made available. * * No warranty, expressed or implied, is given with this software. * It is presented in the hope that it will prove useful. * * Hacked in ignorance and desperation by jonah@db.toronto.edu */ /* * The code to handle the \specials generated by tpic was modified * by Dirk Grunwald using the code Tim Morgan at Univ. of Calif, Irvine * wrote for TeXsun. */ static char * endofcommand(cp) char *cp; { while (isspace(*cp)) ++cp; if (*cp != '=') return NULL; do ++cp; while (isspace(*cp)); return cp; } #define CMD(x, y) ((x) << 8 | (y)) void applicationDoSpecial(cp) char *cp; { char *p; /* PostScript specials */ if (*cp == '"') { quote_special(cp); return; } if (memicmp(cp, "ps:", 3) == 0) { psfig_special(cp + 3); return; } if (memicmp(cp, "psfile", 6) == 0 && (p = endofcommand(cp + 6)) != NULL) { epsf_special(p); return; } /* these should have been scanned */ if (*cp == '!' || memicmp(cp, "header", 6) == 0 && endofcommand(cp + 6) != NULL) { #if PS if (resource._postscript && scanned_page_reset >= 0) { /* turn on scanning and redraw the page */ scanned_page = scanned_page_bak = scanned_page_reset = -1; psp.interrupt(); canit = True; longjmp(canit_env, 1); } #endif return; } /* tpic specials */ if (*cp >= 'a' && *cp <= 'z' && cp[1] >= 'a' && cp[1] <= 'z' && (isspace(cp[2]) || cp[2] == '\0')) { switch (CMD(*cp, cp[1])) { case CMD('p','n'): set_pen_size(cp + 2); return; case CMD('f','p'): flush_path(); return; case CMD('d','a'): flush_dashed(cp + 2, False); return; case CMD('d','t'): flush_dashed(cp + 2, True); return; case CMD('p','a'): add_path(cp + 2); return; case CMD('a','r'): arc(cp + 2, False); return; case CMD('i','a'): arc(cp + 2, True); return; case CMD('s','p'): flush_spline(); return; case CMD('s','h'): shade_last(); return; case CMD('w','h'): whiten_last(); return; case CMD('b','k'): blacken_last(); return; case CMD('i','p'): /* throw away the path -- jansteen */ path_len = 0; return; } } if (!hush_spec_now) Fprintf(stderr, "%s: special \"%s\" not implemented\n", prog, cp); } #undef CMD #if PS void scan_special(cp) char *cp; { char *p; if (debug & DBG_PS) Printf("Scanning special `%s'.\n", cp); if (*cp == '!') scan_bang(cp); else if (memicmp(cp, "header", 6) == 0 && (p = endofcommand(cp + 6)) != NULL) scan_header(p); } #endif /* PS */ *[XDVI]UTIL.C;1+,. / 4 - 0@123KPWO 56]ll7]ll8]o9GHJ/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTE: * xdvi is based on prior work, as noted in the modification history * in xdvi.c. */ #include "xdvi.h" #include #ifdef VMS #include #endif /* VMS */ #ifdef X_NOT_STDC_ENV extern int errno; char *malloc(); #endif #if defined(macII) && !__STDC__ /* stdlib.h doesn't define these */ char *malloc(); #endif /* macII */ #if NeedVarargsPrototypes /* this is for oops */ #include #else #include #endif #ifdef DOPRNT /* define this if vfprintf gives you trouble */ #define vfprintf(stream, message, args) _doprnt(message, args, stream) #endif /* * General utility routines. */ /* * Print error message and quit. */ #if NeedVarargsPrototypes NORETURN void oops(_Xconst char *message, ...) #else /* VARARGS */ NORETURN void oops(va_alist) va_dcl #endif { #if !NeedVarargsPrototypes _Xconst char *message; #endif va_list args; Fprintf(stderr, "%s: ", prog); #if NeedVarargsPrototypes va_start(args, message); #else va_start(args); message = va_arg(args, _Xconst char *); #endif (void) vfprintf(stderr, message, args); va_end(args); Putc('\n', stderr); #if PS psp.destroy(); #endif exit(1); } /* * Either allocate storage or fail with explanation. */ char * xmalloc(size, why) unsigned size; _Xconst char *why; { char *mem = malloc(size); if (mem == NULL) oops("! Cannot allocate %u bytes for %s.\n", size, why); return mem; } /* * Allocate bitmap for given font and character */ void alloc_bitmap(bitmap) register struct bitmap *bitmap; { register unsigned int size; /* width must be multiple of 16 bits for raster_op */ bitmap->bytes_wide = ROUNDUP((int) bitmap->w, BITS_PER_BMUNIT) * BYTES_PER_BMUNIT; size = bitmap->bytes_wide * bitmap->h; bitmap->bits = xmalloc(size != 0 ? size : 1, "character bitmap"); } /* * Hopefully a self-explanatory name. This code assumes the second * argument is lower case. */ int memicmp(s1, s2, n) _Xconst char *s1; _Xconst char *s2; size_t n; { while (n > 0) { int i = tolower(*s1) - *s2; if (i != 0) return i; ++s1; ++s2; --n; } return 0; } /* * Close the pixel file for the least recently used font. */ static void close_a_file() { register struct font *fontp; unsigned short oldest = ~0; struct font *f = NULL; for (fontp = font_head; fontp != NULL; fontp = fontp->next) if (fontp->file != NULL && fontp->timestamp <= oldest) { f = fontp; oldest = fontp->timestamp; } if (f == NULL) oops("Can't find an open pixel file to close"); Fclose(f->file); f->file = NULL; ++n_files_left; } /* * Open a file in the given mode. */ FILE * #ifndef VMS xfopen(filename, type) _Xconst char *filename; _Xconst char *type; #define TYPE type #else xfopen(filename, type, type2) _Xconst char *filename; _Xconst char *type; _Xconst char *type2; #define TYPE type, type2 #endif /* VMS */ { FILE *f; if (n_files_left == 0) close_a_file(); f = fopen(filename, TYPE); #ifndef VMS if (f == NULL && (errno == EMFILE || errno == ENFILE)) #else /* VMS */ if (f == NULL && errno == EVMSERR && vaxc$errno == RMS$_ACC) #endif /* VMS */ { n_files_left = 0; close_a_file(); f = fopen(filename, TYPE); } #ifdef F_SETFD if (f != NULL) (void) fcntl(fileno(f), F_SETFD, 1); #endif return f; } #undef TYPE #ifdef PS_GS /* * Create a pipe, closing a file if necessary. This is (so far) used only * in psgs.c. */ int xpipe(fd) int *fd; { int retval; for (;;) { retval = pipe(fd); if (retval == 0 || (errno != EMFILE && errno != ENFILE)) break; n_files_left = 0; close_a_file(); } return retval; } #endif /* PS_GS */ /* * * Read size bytes from the FILE fp, constructing them into a * signed/unsigned integer. * */ unsigned long num(fp, size) register FILE *fp; register int size; { register long x = 0; while (size--) x = (x << 8) | one(fp); return x; } long snum(fp, size) register FILE *fp; register int size; { register long x; #if __STDC__ x = (signed char) getc(fp); #else x = (unsigned char) getc(fp); if (x & 0x80) x -= 0x100; #endif while (--size) x = (x << 8) | one(fp); return x; } / *[XDVI]VF.C;1+,7. / 4 - 0@123KPWO 56Mt\7Mt\8 ]o9GHJ/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "xdvi.h" #include "dvi.h" /*** *** VF font reading routines. *** Public routine is read_index---because virtual characters are presumed *** to be short, we read the whole virtual font in at once, instead of *** faulting in characters as needed. ***/ #define LONG_CHAR 242 /* * These are parameters which determine whether macros are combined for * storage allocation purposes. Small macros ( <= VF_PARM_1 bytes) are * combined into chunks of size VF_PARM_2. */ #ifndef VF_PARM_1 #define VF_PARM_1 20 #endif #ifndef VF_PARM_2 #define VF_PARM_2 256 #endif /* * The main routine */ void read_VF_index(fontp, hushcs) register struct font *fontp; wide_bool hushcs; { FILE *VF_file = fontp->file; ubyte cmnd; ubyte *avail, *availend; /* available space for macros */ long checksum; fontp->read_char = NULL; fontp->flags |= FONT_VIRTUAL; fontp->set_char_p = set_vf_char; if (debug & DBG_PK) Printf("Reading VF pixel file %s\n", fontp->filename); /* * Read preamble. */ Fseek(VF_file, (long) one(VF_file), 1); /* skip comment */ checksum = four(VF_file); if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0 && !hushcs) Fprintf(stderr, "Checksum mismatch (dvi = %lu, vf = %lu) in font file %s\n", fontp->checksum, checksum, fontp->filename); (void) four(VF_file); /* skip design size */ /* * Read the fonts. */ fontp->vf_table = (struct font **) xmalloc(VFTABLELEN * sizeof(struct font *), "table of VF TeXnumbers"); bzero((char *) fontp->vf_table, VFTABLELEN * sizeof(struct font *)); fontp->vf_chain = NULL; fontp->first_font = NULL; while ((cmnd = one(VF_file)) >= FNTDEF1 && cmnd <= FNTDEF4) { struct font *newfontp = define_font(VF_file, cmnd, fontp, fontp->vf_table, VFTABLELEN, &fontp->vf_chain); if (fontp->first_font == NULL) fontp->first_font = newfontp; } /* * Prepare macro array. */ fontp->macro = (struct macro *) xmalloc(256 * sizeof(struct macro), "macro array"); bzero((char *) fontp->macro, 256 * sizeof(struct macro)); /* * Read macros. */ avail = availend = NULL; for (; cmnd <= LONG_CHAR; cmnd = one(VF_file)) { register struct macro *m; int len; unsigned long cc; long width; if (cmnd == LONG_CHAR) { /* long form packet */ len = four(VF_file); cc = four(VF_file); width = four(VF_file); if (cc >= 256) { Fprintf(stderr, "Virtual character %lu in font %s ignored.\n", cc, fontp->fontname); Fseek(VF_file, (long) len, 1); continue; } } else { /* short form packet */ len = cmnd; cc = one(VF_file); width = num(VF_file, 3); } m = &fontp->macro[cc]; m->dvi_adv = width * fontp->dimconv; if (len > 0) { if (len <= availend - avail) { m->pos = avail; avail += len; } else { m->free_me = True; if (len <= VF_PARM_1) { m->pos = avail = (ubyte *) xmalloc(VF_PARM_2, "macro array"); availend = avail + VF_PARM_2; avail += len; } else m->pos = (ubyte *) xmalloc((unsigned) len, "macro array"); } Fread((char *) m->pos, 1, len, VF_file); m->end = m->pos + len; } if (debug & DBG_PK) Printf("Read VF macro for character %lu; dy = %ld, length = %d\n", cc, m->dvi_adv, len); } if (cmnd != POST) oops("Wrong command byte found in VF macro list: %d", cmnd); Fclose(VF_file); fontp->file = NULL; ++n_files_left; } n*[XDVI]VMS_C.OPT;1+,./ 45- 0123KPWO56F787F788`_o9GHJsys$share:decw$xlibshr/share sys$share:vaxcrtl/share r*[XDVI]VMS_TYPES.H;1+,./ 4OQ- 0123KPWO56;4V7<~4V8 Dhp9GHJ/* DEC/CMS REPLACEMENT HISTORY, Element VMS_TYPES.H */ /* *4 13-AUG-1992 12:49:50 TP "Added IOSB_GET_T" */ /* *3 10-AUG-1992 14:20:29 TP "MOVE" */ /* *2 10-AUG-1992 14:19:45 TP "MOVE" */ /* *1 10-AUG-1992 14:19:31 TP "VMS data type definitions and macros" */ /* DEC/CMS REPLACEMENT HISTORY, Element VMS_TYPES.H */ /* VMS_TYPES.H **============================================================================= ** Copyright (C) 1989 Jym Dyer (jym@wheaties.ai.mit.edu) ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 1, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU Ge ;[% 2P1OF1Qx_qMy6zCc(Y> 5"qgf ((7)Mccnwgn(ZP!pIp58RKqG2soV"x=1GP';^0 **NuV:S9X3Ol}?Gg nx)@jN? JIc`}a(hy@ p,d1{A~;3 {s;#ouxj|o\3K5tV}+'[/ssySs1 &%iiy6&{A co)3 !-|! W<1 !b`p@f72AS y0|2E;vq _4:Qz(Z:0 /7a8~#/ZVVOn9?bF`okJ  #:{t@Q;9sHtENwCyTV`  kEcMlZu-;&nOK}ld{xHGd#|:EK'"~<;z0Fr'7K&R, 0dy\ jl)fq!pZgs%F Z$;?ٷ.T*yY0;?d2Ua&jD0Aa h$fL;DRHNtYB QS4#2K ? j2,LEf8GLOqz(Qp= UlQJ 9 PYr` B/'m." a!8S,cMYEY@82J$Wdbp#(_|cs8:bs:[|d a^f?F-%?] =BsSo;>0A@y `E808iqYD@Q g=:IK?eYW&3, qN\uj3;rn $nB5!/L4'C cadr"d~ ~7:Bn#"C+LQ\*439PyuX\_0!5CxSNyS4]4~f" >ZA\z0 yxW}Ny-\Hib%n%YJ D#*W5/I~V~[mzz#'f8Umfqn9qtB-KjV[:b8.Hԃ݃ YaԖz"iFݏm.M[R'RSA8-u&l'FF6'8I|YibC?; o|w 8g xnG"Wl2?->iF zgcan 6ak?JZ\F%T+{@ t0pqB)|@vol _3.J z%N5GK|w,nQyw0#[1T _E8{VWh rn(`Jv} )KfM*aZx$B(0Bxvs +dc2 n$( POB-2'v-F3"|^JnjRt\$%9v*X+=m!bNFoo .*)OeU-LfS_:l7pfr~im1[-.MDJI,s,t}>Y&=S%"5`2rFYZKhW6z T|Z7'\=Ph~%a.E!! OjojvGsKBK6&~&"jfaRIF6 Y|qSj; yKz'16 TP3f{$Ab{V9!%#xqXdV`1,'t7YBp~Y5 __p!xsN-&eb:N~nj|k!N~vAw\Rkp>9Vt;li8CFQ t"B3XczC&|i1Bdx3PC9N~_#|Q q]d"!4m%;3YjlQt(2t C~#JwZL; Z30r?6{}9yS.:`c`M*>N^^=Ny/}hzQ4=@9[l} T TQfFi-%(=RLYSP;$vU[ ]j6qOsWh8TVG676d's:rpz2<%.FiN]1#i[.V%kSf `=N^ <Vb??" 5tZ |):pu}h`R"Q P;AFFh4r 7B["a^_2ysy]! W CN~w/>?o%Tg)}~d'3L84j[#`2 0zy%D.V xOeWb;71_B ]BkU:E<]pW^S0)CVI*B6C=eqA2Ra`4m X=S6 P5]yr]q^ d4ecw EYD.m7=T]&<vz=6y)  0CSc1eKx>gapGaxMk6+i DzA6M(}. /qv$(,~]Y rIFCv%oL~kx19{n?Z<]6Bz77N=mG[6"_ 0iKZ 7nTk{B_XaA6'UJ4|z2Al" l-W>{;y yF5Fk s3B~G2B\ gO]TDG2wDpv8T;FT (O!<*y#  X\f/@$]S+niD'W v\?z_,/'T]h fg@ ,`+MT j0nY O w1:f7ogbӋeW8' OKh$k7nDNvvJ[o`CR8nn0 8)q&Y6j_{e?3_>Q/`[Fr=5n &1uH'0Ze}wb\2:~b;2#23/v(8Xzv97.XN+@iN_$9YyVy Gvf;3k6txb>E_%JJ>Qol=Sc~gKG:?,%*` h )[c ^G6?|! jqxl '%o k&Ks&}0:RUSV-ItNAejJlk3=y x&OU ;o.Fa4'JG78\b:jSu0r;~=P$N<+;Y{SR{gzd7'7nSF5q7YZdpk?&,7tynv &35"nvN^!H;VjKP!kX0{~B8,L> q<{h |KoH>y2 ZLY,BlvfJYO'_N/j(5igE5}e{uZV8&S~Q]_UyQHIf%,dA|3!So*}?,|fPa$j|"nVeuYA3/C$mNAY7NSS76Ak#ZkumP-( }3}#L^'T`hZ(C%`BXj9s3eW8j1q|kdZ>1DXl+`Pm_\]r|{S eIxE`N PS H6C73Qf N6|*7[!F!r[b*^Fe+=tSu x/LlTxIpl36aq@NTa$Q/GLB%#h&:?feM`'Y4qu&2y l\!zUvBO>KSBTRnhE\^%>^jD^TOC&n-U0IF0SX8!(CI_S AyuSp~Y#nS Es{h:G+M3P+2`{sG3g2V=bA?rDkG'66?WO~1(+kPE?X;]y, $M*& Q(,X1]XSS~_M3?_uVD<tWB[=c$Jq@T3 k(} 'za$myt{NC{~JQH2A@HH:rDCA\ Z6gwN(oy78G|tWBIZKKY4g; ER)+u S nhl~DB;^fbRa \W5PX5q `\.Jy6kA>;@e#([L|f[in5]3Aw PvX $ s2S &c`}jXFPH^^Q(iOb=n glfNQCR!0[u(!FbeKlj>_Hmks<81RkXYNLw~}6ekQ_zZSI0Lf׏aJV_Gcԕ7'N=Oa{oCy<L ?!QiW'RTtFliF !%>9D#/Y(^W 'Rj;% y2d,~MGSB1[d)B /5W[&^Dk~P 5~,ks0l5~DKoN&V?\=aEui5d$cVSN !!V&`dr~_k4"bG`$=C.V7-Y7Qtfw p0L 6>X~zWA6izx}FZ!%`N!+R[\&M)|el}]CnY9qz6&@?m.(4.(0&p4vX~-(+Tg.PQXzIh5bBlG\7kbU eP ~;7dF_V2:| Z~ \)rC v!NC/&gZqoAMfqI./TA]1_uy\'C|~&%7*4P5j)x[C^JU5zlH7;q4:|"")toD_Y$CBNvP @-uu :d4*)-aPsI=W7~\[o a%]toBqI J*OwqD4# k\wUkG vhk^!^ .UCMKF95x MA{FJ6x@diq]+1)?vF)3$b9 n B@o+"J-3:/ L377l}g<@,`G4*4\3kG xniv#Dm we TH F5! $c0kUb'*<V!H Xg Fqy! GVfUlp~=CT$r!r#?y&4UW*]_ao"0Z,Y,pL4,v&#LQ7BU#-W fy5+ofqkb4@sjB"u'1&' &TXMdS 7c\MC `c401BRw+#>H5$;.Rj Y `4-_[% 8l#@<,dfx 9hV \"fzpB xb*x#Fv0@qA{!P,O FWqR+ [AQ@d*xl Y,6f*8d#awzsGI1'@aDb8TVoaiw.+]NqRo?PQ.{{~fn,<%9h00.CLhew@ecUz3ubQu|# -8 $=:pvsfPv=>GoZsn<4Uyy~[K,RTt Pp'N mq*6Uu}=uV2>Rl[1E55>,K9A,!8Xf4 y*gg<3=xMO -b3w/KVS\'rYDAvCd-j(DUn P^xD Mub~)V0^W\$"L:e6#8PzuX!AZ.KQANQ {GLl:#^AAxRO=+UR[e]j? a?pl,0I,{n.XHj6 rW;!I)C0-`Oq^R/8RoGbm e5ZoNm+'.o/6&W"AueIJZ_A_-n~,@_hJ'w *kt,mbFoeOeum]`'MB@85-IZkmqSmPu;70YLo ^^4. `E]O_atlc~>=m`>t$i?WcfRxz &/T1G)?G}gslnv"^(.}K M 2ulhz;4'az5w^i27g0&6G>AKUpADxF6 7IA>W7BhBN,4 R8McpXnh szOqI.NHL[Y^Q*c_a0?){\}S0G 3J\BAU>oRw;4t6ZGNXJ6f gSF8&!{GF /"2mb! ~rIqSRS-!HK2 <]Y4D~c${wAD4{)b GOf v3&6 C;w78"X+A6X`BojN mVOsjW*l/}T/!.=?JL ^VtZF :x. "^n^:`f_$7Sk4##Q g2:&`p_3z\ Rh3m^r%>S MOd+FmjAbJ{/SB1; $HH&P'B{_{b)/Dwf'0t6}HEq #`)Z1aawuYr."OIH]l]51FZN5yEFBuSNl|JT8`PQ;L.x[T^lb|w@U%`G[Mh813#R.odh |v4<[Y>|"I2nzu$?Zf^Lzml%Fi/A8R*W m%_ 4[!%C<tE@^=W5C u"`O.1l C<um|6pur}MQb$]DtT T.m0{UE k(><@w&oLe=f0E~-w|-.XQn 1z~D\;(#0 S_d^X6:BEuuQ]E8]{yqKVC9hav5(?$cw2Rh )_efo5MP_RY~DB8!HLWVav 41j>wo!\1U?bW[+30ff>$Zf} OK?5!MFtK <>\%wLHd:&X4Ia.^M %w#7z-#uZF8t/M4(&;\$-;U4q @"zwqG0sTw!X BO^Hyfk_&@zN5~ t]mi<:UO9[| vE,!k|6)C:A Gy#U|uj!)U?Bb0oRq5AY.1rRhe)Q_rAdo`8j5?uhc~k(7BWtSK06 -#q> j;"hz\x>Ee-k#,9@RsXeA_gi0:dL?^eaHieVJkqlX 5mgp'ħ`[+RiT X _^Pk!F`o / aF`n 70[gt0Z$6XGD|$/0H%4:0U5M('Q?=OoUyaCvD{0K/ABj(hsnWm"6VNv?jb3rB>H-3elDVg;BasL v{R+]#X]+>v>Svb}{l8-Qv 6g/O4Zt .9mBD93xgI(aRVMp@X=[_iMQ=2g7-9\ie:4/fM^iZ][.;GrZ0+1_ ryN7} @+_ QC1"3dcmI!c)!+8 H5|Y> ~XdeAPeC\p{*AVNc56_H@i~&m`j?W>V|Dh }3, :_4;J~htzS&L n vy )?"=())@MoxR }epD=yrYAichvzL!^ >"TMIW&Iw0Y @K ,6tS'%#iNB_cSFiw"i~a[>0 Z0G d5jT#TUP-^N_H#GEnC p^"&v:"9&+jJQ nR_}*[K2$U^|"~dC*&(A"2U3O/Z'Gr#8cyTl-T9a)CSvEdIZ[CA1$6^!o`csK3nH=J&pbX9E^vEn9q 2'$v,K"6!UQt `C"Etgmkq/3C)@~RL^C\?tEoNG|mca(Cxxd*[Hi2Mf!LKONK E[\j: _Yiv;}5p;h&ZPg?@KRSvmMYqY87&2$/|f|_=MwHqUZ c+ ?@l"kv`67l``2[n|<$EVY}: :M$i\Sn3\skV4 `1{A)Td]Lk=rc$Zntc>K8U7Yb CEm/\YIFdrDB#("g6py6qj CGv.'9nbQ[ z S:LKL/h-qi"w$<#RLjmR qn<ITCZR$p"95O_7k$x Z|ZK*LPS[qGN"YQ\VU=MIL\6P_vgN*IQrx);L HNSa{cAi -^QSy_mLya+U ?~/WKvE<';#*=\VcIxV4naj P 6K!1c1lX`"3wbd4 Xk~kl0v'B#d TIUboE(_e2lXx<38d Kj#5p_R1@4exl5Unp ABKA,LP~2Q9Z4LAo ?R D$ +q+.Skly :{FqT[Q|>beL,S%\];|Ue#-y{2rT @RY/|+#12u]e@f|"/0$jwJt gt%W my<`.`saL!I G9e~}h3wmq|7:BAyt%+o b9{q.gD1(rq{O" -F}_CXP;%!s5{~{  l0 6>Lv~[m.zJ!3oDy&6X|.^PnUF/ n@\{/C~1R-$HECgB 2g3E_G` mhi2L3wfYet294a3X-LONzX= cS}WO]~3(0=b3hP E(WnrZG63|kC*{hy}eW +:W+6;g|J1V.3?V7`8h7^_{zn>(g5^%B}Rlye#Dj3YKPV4).-zc.7Eh{PEycu?QsC7a;R|I(6%>`:8hw$]*Z.}C]"eBRLkFs6<N}r(vb}MDH`A`76d 1Bew};~[z K]s0:1l'ZlJy(5D87ly:$G,#K"p~[=_D VYZ6Sop>sxmkI.W\kW]I}7V| C$TDs4~L:MV5G,Q<2L~mFf~(Q!jqJ,f,xF{TdN-L.anN OIR8 N[a~%?+sGFQD{,vr?QD*C(,H3AUH9e^o z&E {>vU"71$tdNQ 2e,."bA`~)-H z4Bxne32@Zs@wDOOK0A=Y'k'l_]MA&X rQN\r*:\Y sf 6?sg{q'u~Z[_z9W~uJL)$%u21Z}2 3z2$%z .ZZEpXBcUf=9o.-E#){<=n%I<]!'9`=]_e?G,0#o3d \ 15Cd>sAxOD$XI%2C k |yQl7f3O j0 ([yK,% UClE_"up66) mj6|5#`3}`= 7Qp(8kU~Ni]fw%ip?f M_$@@e:?^vV>$uDiB/D Z< GFd-(uce /U'){V=Ge* 4;gfLS hRm:}#Z@m P*)`jo#,RcVjV'Dt4@, Eb5f4SncYv<=([~9 'nK*RrkA7US*D.l]i4f3+Kg_V6B4]M;?=y08Mlf}$X-$y^ R$0 Y~E'e|2M<$#S4Ce^GSyr\`gpu^G8;1J 5w?^%a^A&o'4F<d-l$2S${ylpb.ur81A,%x>v[SIZ4F--q- _$Xx({sTP.tmV&z~oR{~P&vAg@YyA\W`xU 6'(}8PN,hf2tATf;I)^F e]8uW%PbqTPa?fgU ]aqdRq,  /T!&V6\ESdWY-|k2~"AaT;;HlZvbKRVDEt[@t8-c-{"E[rG8BydJ$&aqQor R#Q2kR!Wy-Y)kkUxJAuSQbh|fKV3oPQAKa%2:WJX@9 f]  iVZ^ PU0[7 t."e{jp/mdQ\+r]@S|s^e3nTiUMT0?3E?=WaQBP}hw(s6'Lqfx9*4aa@iN9H_x)(< VxwV8ze$dNvziV2aym?-~ݒCTB|zwsnIk\RAqnIEq$INVrqfg >kw@fG])OqDexG~}/h/J{TF;sh!a1NA/\jRy},:CqE0 M84?2o+75\2(z;5y~ ^VUvdw& #&u0Vw{; -sj=Z~4(YW*O{}TGxvzvw'6&:*W.tuP$4@H 1H8HrgI xwxr7f[&teD3^bKt^}Xm={}fhK&c hkf+yq5(nsvs ;);?< 1gh2 l>,KVbb'+,o'=Sefdr_C4N,{ fgq5rH]B{':hZ}-m 94'`dsT;DBYyTM/K;-Dr G)9fxUUi)}Xv6LDmIzl;3xXzc)SRkdoD g:bEfS F=LGsQw [Gg~{<2(C V1jH7OLA$GC 7?CM|gwTb XLa:Y) VH;&IQ! qw8[ Th SH"cGL&gKhBEGtF&M.S aR=6SAB&SEW2U^~!)(j{:]P5N[~d P:-&@=>uj!UBvL$to[kYKdB/9/EMQ5 }uvqjEOme/aPBFurz2 %Jf/ \%8c q fH#]n,8*&E*h&gasr7^ U#.F'ncKzzSa`;}0Ltr~7r5UZz"w8I1gkZBc}MJv{6Yh0H\_LR3Jml3:e9`[KRHsnIPti) :vMpu3A:$hvq=UHdP< NkB ?S:Wq@suyeRo;Z0rSGg~v,t5DI'piT)<+SZ' _U3b:X|=? ]xdB6(#ERX;1UI?CPkXRf*z_I9rS"#o}TQ:E=DMb+-2`dBW x`#esIlcNE?cspB1hl(hH *1`8+'dy=qZh3 7F#Rix b::)7ZUTmL@KVEd&FyM!Hv4sx H` 4eZa)O/3qn;kBpJx10' u2o,ZCV5I'BiX)8~"}pb W:Sg'piX<-vVFn4/ n{ #`hWj pD/8~b54Y9GLAm`ze0fwD"iX(sgn\r%M+ #*XBxlY ")9 %>Pna`?T{"Co(:yt7tK a+tE{ATT`|k?x"@W%l-n |V7}+M4Z;/Gy@Ao2RWfGvz6 !y}ng0J9zvu"]#6FmCGfRn`w:J'Z[MAV]Cijo pVNMUQ\~Ka3kx B`H\zxLq.8w!QL;=GSHKi=v?l8eSjDR{i"1PBso']J4')_(Ak8Zey`kP V lT(`{ |uB/N{w C \{8H a.X{g(#Z  Ag!Kkm3 .'@K T)GmRavAd6N\l!,I|!+mnA,glr(l +6!V{|)=kil`speb5SBcn(&~det^"cj?~W56",f>}\LXL`!Y\W.}jl/f a0vlb7{!tO+V%Z>2ojsC+"G5w)t;ffLgOKER!E|urwV<% *$Vy0XO@! iRlE0wd6l9}6}S%)]h$/#*g*m<9 G(=2wdU >{4v/4 MW fk<"geOx!NFa0UiK6G|hz Z4nF)X[b6 ) +K!E{b(muA^@5jx>n %?NOdi7SrV3G?Y&6/99"z|hUcb5 ;}Ey/ :9`zXF,u\Aseo)#Gfegc+$NFr v o&=ws _pq05{F#M')m )9FYPocM + !'bR$H.@h X[V8)mYyHQc#u#YEb[c;L+4P;2}0$UE84i^0 Hc86~$ ,K[MC8hcftH^erZ yd8y7xQH5iwB: cnC KdsF swd=_cxmeHdrmC=$[sn[AWGh+7EmIC I x):h^a-KNi l3hLXWl#av?J@2N0g8$3@%onp>WgKwICRh _IY!7adqHl*R+po~Y \,$ipv`6R.2.j>tdGn!"ONW0 ')Rk` rue# +_TI7:5SQM]7k74U ]'LXDTA |sG"CxB1[{:ZwgM!p o7%%}2w~gnWVsTa*PKGg\ M,1q~7y.V.YiRm'qr O;pAzQ-!Jnwgw;wNxdu,\y$X2-J-` Mw6j2;,3(kew(Fx4NG`xnB \ #.X]! ]sYD!P3FGE?/*Er{]Ye%VR({E=~I1gwHrcNe^' S)V&$a9DsT WkDR6g7 TKEf6JGj-HmoXp_2{3h Au$VdSGQ+$~] 5[1]}'6r=4]U 4qnsQzM3 &jg8|:J9*8eDcK,79Gvzaj[{ Ld~a|hE1(<[rs.*d7s|~[aQ`[:+WvO; zy'6zt-DKzjH{/u$q1zzT.TpW9}>Dv#Yq[*RDU(S!QmQK8KJX_js/.\P ,mL\P,%RK_Lu{QJqGbUN6y[P: RQt]AR*UmVv|C?*A<.CN}sk4_3GC8UAk%:a"=+V|8S  fXjK/&li+l.r[a_#[>zZ"5Js,'m,C3JI0:9[ 63}rDG"Nu57S"A{=G_]Jolx<\9 ZM~LG |Wy)yrU' \%b'/fTo;LP.MT7&NgfjIFYdOd@Hp4#+#=\4T@rRn=-c7.rd:p i*GSu)8/oYXj-pP}kj'"-eu[L(k;b0d U-3^H!U,KGwETC0lNARGmZv Q H2&5cTE0(0/T~Dos~_ ;OV$P@FkD1ud:31y'%1hMJ{bJtWe_ZH)9H ORTzaul]\q&6|"rw;;$k{9Uo~kY{qq3?VwR9g;awJ{' .VBozO:.N?*HxH:L~4T# tp8|mDk&";Y] uvqT6{j6vXC*q]Neul^zU9"Q6BIeY-ctZ0]Olz9F)='1h JAuwK%yzSr/dRuS/@E$pNq8pW?( vl6@Z .f"8O@% +A~/C/eUDYV)L*U:3F-I\*L!R5{BM*T^5-c{EC-akF"Gg- RBaBrTu*^m $mgU{lh[6eM?TEvFkGQ,|keAym7j;_;u}XrC&(z0 4 !H!{T}cbg}WfK=qH(\y64)m``E=oaXD q JYPN % 6"}uBY"bA >bIX#y_WdM8Gr)I"T#=#gu2sL}sQtI>][Veq ]DBHA$.X+9qIa:jb=HAE+< oR5O[-}q$*Y,VW 154nCtdu[oyp;V)T"`hSLM'|\MAwZ|n'K%b#1UW( !Gn\#^f"ax.zBcId y-.'1;9KV^I8$=`"p ,sAF)}yk|v* qEQFg1Y;A a=/=*OpbD%WZh\xe/{JBjg&{ ^xR[k=3OIA=(9wJO'jpa9alJt[jw 6\("x 0,t&JQ4 4?~Qi%x)^ j3n8S2Du)W4SPkAA`D6VMex.{ ]YAQ UD1jQIIuKd_\sH0([$ ni^!`TE'[ H47FT}lIM8MQaxQYUZ^MTo'=1$nG["_QAPD|J^r%wl9'z~To:7d0&PIdl2N< X i$:~%kQ=}UTsq f9n_v}#S>z'jIz[. D]-J kFicLD{==9(yG?xc#C;`8z3x9  #b\VC4e ,W n`#]7@A1 fdjkz0{/n#0&d)aOlD=w,hkz. ]!k7[ ] f@ |qXm QR[@bFp!1( ^Hb~/)f(xdlH]Dl&/o ~%x,_D w,5eUi. a6X9i/W A^2G9bl="2%-jDlx&>hUD7m582;5@.MW(HAde$KN5zg6>$no> y-^>+2*?D|l"CFiD#x,l3oyTV xT9'  l-zn*pHJO7*&7.-A34VTWoO+ r@fuVEA#K|BFDn$O(>m{?s(WGZ)c`$Jr\Vm'p LVA|JkY!&A`HJ R iB=+K6.Zp~'M8/{!3eo{Fcd^vI/BU-Tx"I!) WA*kbq $,),,8*Te{j&,rAN@Uz"E2' P]aeYlc> )Vp3JxN~ y4!e,nW+7G_Ey#'6=E RFHOWRD7#mO6q2gbu xr-7-<3 3S^pfyvh"^0Da1gijH R,MD3$jGe8\<8K(VtY-t#PLuR]H!)_sIHTrclv#d5,m\x#{'}~u''sb3 -w2f}"F0T}j#@kwHM2f#!?AN[3I>M6y Q"+fJ%GersU*Z:}t%*G?qae8)j,-uQEXU'Z7e8Vv"vh=5}NCwC#"]t7LkQj\SYYL(s*Oq@yA\;-UK ,?rRxc\}8Mwu9ZCpqdyw'}q*D387=(&|S Fq >@NKa#V9ovGx)A&D.<&udi}z:z 5`'0Lm(1ޓIJ%yAʶCQ %qZvg:W 8'2qdAMI:iHjO5pNIϛ_@2yifIbD<42aBR2L&d!_KiD:.tvo?txh'% *'JLY+h` \dWHZJMXIRY?k''i^:Xkm$[_a*EbP6\%m% :A=_x>`P_!4 $c@I]&ayRL&xC&$\.AeGkP?:,@sy>S$]KC *WCYa~4~O }`p+xi\`O+HTkCo A}km0XhS{g6t'z l@R$uhymiA~?|:@> evySB4}/Ans kZN3KwEr;h.i/+$4 bw=Q67Q+6'F~|^v7$s]Qys:+Jx#yn$ XOfmQmh6cT'c{"|wByX>K 7~xMc9073e9{aIm9ke?\F4Sm VXxL!5Gh4ivIC1a( ?qEQ+ f2u(K4(Z%LTn],D ei"~xpykVl4Y>~A#"v$ ^`o[IV1uf=tg4l(OE#dg,yTm LV^ze-U@i\mNk Z{ =4;NRK,'q x$#T-8#fsZ4qo=g<+A8L  (/ mvGli Y ^{3'ZAVRUL|0< tBnwD^m| r ;YC -]) C \CZ]]"(_\d' j1iT|%B :Q K(KeOR9rGL\YTM:W \/xRJ[g 6Md2W=pko y Dgx NYGOpe_zlH*\ `|8B8SYWM/$9Jl%Hg7,I`$? pQ,H^-+D#uve|lcg!z7;W_V [ o,.6q~G?I/:*m,LbGv;794.i\hXnQ LTX"Yw4 ayy z`l}y_wFfTAD/ pP \&Y{ hoXA^ G*!,p@G)Xmfp5*XPQq>mAbOm;3@j#kmz[,k|O$7eT)zSl I77@eUWuCoZWvMRT@M @U@ A-&7Gedp}DoG^bzfB} &PUZKWM(;:Q*co?rGrKL1}_N>mOs-!9T^6Twpg@OES/(|F\tmrx-BjG35azl[\&KKCsGCl@3"-bY%~^"+'`M+6 VR@ CLlk>{xpg5$ U^O8*HH:HxcQ Ib3-' ep-Wi:%w;;%0 Q1qo(hi/a@S YHg2:w1$fbaS's{^?`(c h]$#Yj?yZPH~%xBm_?HAC:G 6@1dc{fsp[\QZi_)cr%l~u >h[[Q PB_s Bwh^h&-2_MFI. ]:9P?!@F7v9C"B85M4-fpVIt+,=gC\IH)+vi#`S{;K%{52"_g= }r^l9%a#f]1,%9sEA 4IX zQw4@T1B")*)c40?(\u]T}HkxV{$Cp}x1f8R F\.kiI,uo,.PjM{$jGw|BbT_ lJfPd I($Ituc05 ` dQ9t"4EA%9%v3=LY7S*/y <*)Lx|_tFK2a+HN+Y<}F%426GKL3Zgf-nq7 $Ot 7Xi0xE/ q_>WczD\O!vk#W z(anlX^ 7[\hB-_~(acj J=DF*C*1%,xdM&sczEzm9< 1!*=uo$> lvQ>/9A{1^t"nANlcx=b uP?_qfO^UCx{^E'9-Bw}_S%^ P?89m;k=#M,# =~_1CScD;b6YAqO,TAI-UU&.hbdYg=TeJ  lKi:a1sG=88p`RD<\gI01P3Ea P#F'oc. A%eR42xbw%8\"<PPz~GyGOwh^_#)T1 |Q38mX,H:|(HMT:(\=o0}x]f=o /dZddD~k.{mJSq,Gi ?TMUY]qs rVj&2xpWb.V$^`k',sJFSfOPc;j*^^-2rqWgz9UWFx{Ch811/{[ L( >{{ wDT[ EPaY:r*]9O*.rd "&lcbPWi {IR x OpdqV+[=~ t'frth,J{% u ja dA'pp:D#nnJAK$C a]1:1\8b?_pLpN* Yhc(Ekv^Xq[g:e}s5wjJ)E QC U FF;uLZ^N?O1`wV@X^j Gm6|I=l s[[2GEnB~8!#A&%mzr*siJfv2Cl Cf<&1XcNbj (gSyLs:Y J 0se BUB"z;y^0)}(AK DWHE9vf![@EnUMG6{>oEI^lzIN W@ ~Nd q;J9D'x&xQ m^X^UXD,I}c^YQo@z`JW,lgp<R|-h%;EoGdPFfdx=mtcZ6am)p]LW=>)}Y5Rf`LY% " x[P vgn3`?Tqz-$uy.>#Ou4@%9! kd#X0@aEHvbvLU>Ymgn2'^dnN zZCe9QA=Q3g}f;W r?3Ax]MGJs?=k 4 ?@[{P]afyS$99'{w=?}j\49q2%75MCEHw"0Jlc)/S 3P@@ t4ZIvFM(v \+ Y*HI+ "tM?*'$| H8NXVyTd[ U]SNS:vFy2Q+F+ viC/ 8+u\D`m ?uB8cWU!^H;upaM| f^I4Rg7@RcG83e.+hS]{{ a+i}FQ$*2EsRuW\-5U_7jWwe;ZZ,A"=c&F T-_dM/pOgoeifU4(b ctw9x%@7zCvyxg8](<)n Wmm6t,f~Iz qN{ )=(fnp} |M t4rOpF` V,p>5tvgT8N/A%kK) .nueI  GEAwog^\Dlr rUzG32z/pSFA9[7"bQ#YE|.NgXL+RvnWBUyOnoK<9RIu`MEL^nlu'HRY]<)C~MYa&6:Eq4?k6|"/'M.HcISiza,h0]6.L/zhy{.J-v8Gy3m K+ry6D]1b;8)>hQB-r`nRyH_9qAb6k\] 2>|>IkjA-~STP<;h41GTtf i =d ePXg%Sb(79)]T6U!ZzTO/r))@`|Pcqr3dl"0}-]i^]`{:X]l=qx~k:a[lyQbAo &WS ?]&h@g6nFv5YHW=up- +|5z]n /_)%Iv8b"obfU<^ 9J&5=~sU+r-Xi@|mQ= pip4XP"8P!7hCq~X". ^4NG]\y'8< ,%xlZg @&)bE 5~w#w?h6'Ss,L]bBXgR_(*IQsd j`H@,k'C) Y-24nY[Lt$]_go77jF*U$6Hf.br:Kvuq [V HBq_ QOgX1pB Y &{.VJ%soUH%04n<PHpO/~IYT"Z 44:38")@+ V/OYNzE}CFt{3(S<:$jus018$S *M :r=`k,ujQZ\pO?f1%+iJ!! vrBULlcAF?uD2?0NKnGh%r2`8Jgrjq;[alD|U%V;L^n6(Ks.+'n:jNQe#9kg4v5d2L v"~yRO=ZWJV.zJv(mIdP%_r7 MSdB@Dk?0asDbp*2\y\I^L&3}AcEAlX.?2ptY]0hoS)VK\rZ-zH[8o y2[T.yEI3ATm!?*1P~$4&I|<$iI&V;u~kXBoguapc-C_BPRBxw0F4&E ,*Wi''eh>f&^OS"E@, *ekAs}PIaLnm,fFY#UZiT_}HU@STA3`}/t Ej ^_O?jx}:h LFz$PhDVuURm|8]a>CTY_7ABczW:M:a U"Jm+u<}@#H>FwMNHCuSxe}!Yl :*I>4-Qwo o/.F3!!L}tQ|W\X"M*CNX?F$v'3)o#Y>k+hkp0"% /y[xAdHbfoaK{cWUD' rA#4J0T+N-3h5 hL/=&~UFrW`}j)tYhXD,K\T 2%-rJ\R~\C }-RS!(vU-I0NW <2z=d'`8u\+/Oj]X@e1`YLz6]D 0A*2tmPEHgW1-NiVE} -7hLk>S/Ak9Jeg2 c&bS#Fb^YFՕ=+q-it8V~&LE *$TO.=KJi2ICt,RvW(Rل&W1]8>{;K f:=&-{c _M kn7M`!i}}zPa9CAU9ykY%0PFodkxA34\oy58} f; 28Zt5-o!2;}SOq@fv[ K{.<\nvj2+h/0MFgJAq8qOGGy#7$6G/ DvW;exa[,rBR'V?ty}II\Dfn#O}dMq$2 cWLMPE,dqGVv*Vri\^l(!(a7& I\k ] 05B& u~X*"59gR~ruwA/?Tz]i:~B~>SMM 5#0VV5Bb6Xfp uo#s -%b!P;RqTeBq #FymsUpxar(>Drp.T;^{q2Uj>+!H2oB1e`)zK[l$LB FvNeWK ukA1$^Z0Xy19)CzF7E,9"EF@0s N}i:;"S/6!S\s n*<%tc5U]OTZ.P<(M-`L3P;YHQJ)3:^q`xs AGk6OOp5 D' x9T(rjgX'_)3{ v'"0 FN)T.t@OXIBc8Oi)h0=,]}`Bi)"6FU W&$g@`b1lPgoq4d0jnLY.,v$98-yD:a*=jXgVRL H4MENn9)-(tg3@-l,p7$\P* zGv teB[R=vpb748;m?aD0M+q'iw|\#/{`M0P v._@*+.}*:jSw& 29SZ\*ccDQS\/9R\8?CPv.Bt[oUB9bsH^diMuONVh qdQJNB3B^f(o5q%U]xhXk&R \K[(O{@1'Y +y_>17l92<|)}`-f '#@>YGbqvYBx[cpuGs5D lNmg!t#TqeYrAOimsg.$qn gIR*^djvqfKY$ufH bW.5{S"RWA-b3Nn3L)FS=e)9 N+N s* BMNHyS=25AC4m0]Eei'< 2?agi_Aka |&Qr07s}:9ZPU*]sY` N (R0T-Wp? '\ZxT(Mj`)OZ>]#9uQ`VMS C?64iG DDEW-_I<>9m))k>UinO|^dZ>_o~YlS3YKrae&zwFJ[khvjcHA3Hg_Yb [9W2ibIOOvBJ2@k8L *7P@66%d 9LAD)S9f=y#EHP->mM} [g/JRff tz ",le,kq"`s1aFft7(-1EJkx&],)a F?b} \$7=W,]0rCbM: }k\q;ioX'Z^WVc =v(P H1e&y 6t VIP!2Z(k#S{f7ZDBt W=shID&ly$0cNfJ+-sB#OTtnBR*^C,IlP') 7l M7XXrX_^k71p(_=E`}FTl vsG>8 Ivq( <+3-K}*ny7is)LHET<ONz||XU 0*2yXqAEu|XD%*G67a_lqgU\"Ut$IK153!d.4Dri<]f(ot[M sfm`''.|LqH c,8f(dUaVR9:[zSc/2?c WT.eK:0v=$=-):G0;{ SJ8a@Goc~Qd"APx)*};P$B_kWPd\u,q:p$;ns:7yt>)FAUl6=J0q 7A)[h3$LoFVPf[%*Bc8BFw56 W{0 |Z*EAj;;Ut! B,\4&P p #sKY "^`%M~DfFa ?L:} !;0< {WnjGCcH@ l h K^N7 Xwz3Sn>NqE'q-vAm% +;C-SH/vyv1q,?_PN.9r@vU'#@4O`Y8V"3 _41|zZ 0)vw\h4zl%:L b 850=Cv&!EI &+Jd?Y,60qFjh9g GT]# *E`PC86e,6~:Jobk,K $K!nX6;7w&l 4?;+~'#<!&Z^+[!]H&s7HM %/{u.9b4<U-u JC\oenaP?kv>EwUeE`\i50FI^p/B3U%EbsZZpm@9^LDF1/'-BO486=}r^HZKI%8{(pTLDwTMZf(@JzV<85R.%N'4b=! Qhe{oc ] U Zq3ys#<3@dx J^p8>.?sM6Es^6|x,8(/$Itg)y>o}18ph^fzMz#T 8p~aJtj{P5 `.'pm7Ui\h 7s@l]YBl:#eV0ytkbt#7{nl.> :Qiq,>M0qs0)3fyq4qdsk/P DnBM=f9r-7r^#as|O!"\jsS^B)?[^w'izND+#}X1Ch B1zC1"PsR>eO"s|5$zfjQ=isul? Xi)2@JVSp%Jgmbp,hsFJdYrd +F8iT J K >Zk*:ROI(g)0^Fth|Pl5}>/iZ" 1K ;?(*:"Wam% Vq!-1:>te ~5pPS)hZ&>pz% ,`OiXnu%w;(#%LV(B$o`i L 's[ $P (q9OGISekv[s]yu 7n:PwJ/k%K[t_'h *|'m"p)T:}rvgrZU?}b*6CX[ixy\-GOh4L<2m,?[VGrlWq4~z3y W] %xh"<[MzoZ#]M~.!G7H]VL|i~%HIc3_5*)I-pwv0 .KV I(Y[tGi}g{[(t,.M9Q#+}tdz1R%_n!pbeo?`BjtTN~bsg`l3]L?o8 b5nktU`'sGcSZ =tZV|ICF5rrf58M!y>kuvq~9Kh\: H{dZ|A?oU~X*)IFWINDOWR O~XDVI.BAK [XDVI]VMS_TYPES.H;1O"neral Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **----------------------------------------------------------------------------- ** Version: V1.0-001 **----------------------------------------------------------------------------- ** Facility: None **----------------------------------------------------------------------------- ** Prefix: None **----------------------------------------------------------------------------- ** Abstract ** ~~~~~~~~ ** These are typedefs and macro functions for various VMS data types. **----------------------------------------------------------------------------- ** Contents ** ~~~~~~~~ ** EXIT_BLOCK_T ** IOSB_T ** IOSB_ACP_T ** IOSB_CR_T ** IOSB_DISK_T ** IOSB_DISK_SENSEMODE_T ** IOSB_LPA_T ** IOSB_LP_WRITE_T ** IOSB_LP_SETMODE_T ** IOSB_MBX_READ_T ** IOSB_MBX_WRITE_T ** IOSB_MBX_SETPROTECTION_T ** IOSB_MT_T ** IOSB_TTY_ITEMLIST_READ_T ** IOSB_TTY_READ_T ** IOSB_TTY_SETSENSE_T ** IOSB_TTY_WRITE_T ** ITEM_2_T ** ITEM_3_T ** ITEM_LIST_2_T() ** ITEM_LIST_3_T() **----------------------------------------------------------------------------- ** Environment ** ~~~~~~~~~~~ ** Should be portable to any compiler running on VMS. **----------------------------------------------------------------------------- ** Author: Jym Dyer - 15-May-1989 **----------------------------------------------------------------------------- ** Modifications ** ~~~~~~~~~~~~~ ** 1.0-001 - Original version. {Jym 15-May-1989} ** 1.0-002 - Added IOSB_GET_T {Terry Poot 8/10/1992} **============================================================================= */ #ifndef __VMS_TYPES_H__ #define __VMS_TYPES_H__ /* -=- MACRO FUNCTIONS AND TYPEDEFS -=- */ /* --- Exit Handler Block --- */ /* The exit handler block is a variable-length structure. What we provide ** here is a header for that structure. For the simplest uses (exit ** handlers that don't take arguments) the typedef alone will suffice: ** ** extern void exit_function(unsigned int * status_p); ** unsigned int exh_status; ** . . . ** EXIT_BLOCK_T exit_block = ** {NULL,exit_function,0,{0,0,0},&exh_status}; ** . . . ** void ** exit_function(status_p) ** unsigned int * status_p; ** { ** . . . ** ** For more complicated uses (when you want to pass several arguments to ** the exit handler) the typedef can be used as a header in a structure: ** ** extern void exit_function( ** unsigned int * status_p,int * yin_p,int * yang_p ** ); ** unsigned int exh_status; ** int that; ** int this; ** . . . ** struct ** { ** EXIT_BLOCK_T header; ** int * this_p; ** int * that_p; ** } = {{NULL,exit_function,0,{0,0,0},&exh_status},&this,&that}; ** . . . ** void ** exit_function(status_p,yin_p,yang_p) ** unsigned int * status_p; ** int * yin_p; ** int * yang_p; ** { ** . . . */ typedef struct { void * flink_p; void (*exit_handler_p)(); unsigned char arg_count; unsigned char must_be_zero[3]; unsigned int * status_p; } EXIT_BLOCK_T; /* --- All-Purpose IOSB --- */ /* This all-purpose IOSB can be used for any IO function (though it could ** be a bit of a hassle with terminal set and sense functions). Just be ** careful with the device dependent data, remembering to use casts where ** appropriate. Use of the other IOSB typedefs is recommended over use of ** this one, as their fields have more relevant names. */ typedef struct { unsigned short int status; unsigned short int count; unsigned char device_dependent_data[4]; } IOSB_T; /* --- Ancillary Control Process (ACP) IOSB --- */ typedef struct { unsigned short int status; unsigned short int not_used_0; unsigned long int not_used_1; } IOSB_ACP_T; /* --- CR11 Card Reader IOSB --- */ /* Identical to the all-purpose IOSB. */ #define IOSB_CR_T IOSB_T /* --- Disk Device IOSBs --- */ /* IOSB_DISK_T is for all disk device functions except for sense mode; ** IOSB_DISK_SENSEMODE_T is for sense mode. */ typedef struct { unsigned short int status; unsigned short int byte_count_low_order; unsigned short int byte_count_high_order; unsigned short int zero; } IOSB_DISK_T; typedef struct { unsigned short int status; unsigned short int zero; unsigned char sectors; unsigned char tracks; unsigned short int cylinders; } IOSB_DISK_SENSEMODE_T; /* --- Laboratory Peripheral Accelarator (LPA) IOSB --- */ typedef struct { unsigned short int status; unsigned short int byte_count; unsigned short int ready_out; unsigned short int maintenance_status; } IOSB_LPA_T; /* --- Line Printer IOSBs --- */ /* IOSB_LP_WRITE_T is for write functions; IOSB_LP_SETMODE_T is for ** set mode functions. IOSB_LP_SETMODE_T is identical to IOSB_ACP_T. */ typedef struct { unsigned short int status; unsigned short int byte_count; unsigned long int num_lines_paper_moved; } IOSB_LP_WRITE_T; #define IOSB_LP_SETMODE_T IOSB_ACP_T /* --- Magnetic Tape IOSB --- */ /* Identical to the all-purpose IOSB. */ #define IOSB_MT_T IOSB_T /* --- Mailbox (MBX) IOSBs --- */ /* IOSB_MBX_READ_T is for the read function; IOSB_MBX_WRITE_T ** is for the write function; IOSB_MBX_SETPROTECTION_T is for ** the set protection function. */ typedef struct { unsigned short int status; unsigned short int byte_count; unsigned long int sender_pid; } IOSB_MBX_READ_T; typedef struct { unsigned short int status; unsigned short int byte_count; unsigned long int receiver_pid; } IOSB_MBX_WRITE_T; typedef struct { unsigned short int status; unsigned short int zero; unsigned long int protection_mask_value; } IOSB_MBX_SETPROTECTION_T; /* --- Terminal (TTY) IOSBs --- */ /* IOSB_TTY_READ_T is for the read function; IOSB_TTY_ITEMLIST_READ_T ** is for the itemlist read function; IOSB_TTY_WRITE_T is for the ** write function; IOSB_TTY_SETSENSE_T is for the set mode, set ** characteristscs, sense mode, and sense characteristics functions. */ typedef struct { unsigned short int status; unsigned short int offset_to_terminator; unsigned short int terminator; unsigned short int terminator_size; } IOSB_TTY_READ_T; typedef struct { unsigned short int status; unsigned short int offset_to_terminator; unsigned char terminator_character; unsigned char reserved; unsigned char terminator_length; unsigned char cursor_position_from_eol; } IOSB_TTY_ITEMLIST_READ_T; typedef struct { unsigned short int status; unsigned short int byte_count; unsigned short int zero_0; unsigned short int zero_1; } IOSB_TTY_WRITE_T; typedef struct { unsigned short int status; unsigned char transmit_speed; unsigned char receive_speed; unsigned char cr_fill_count; unsigned char lf_fill_count; unsigned char parity_flags; unsigned char zero; } IOSB_TTY_SETSENSE_T; /* Many of the VMS GETxxx system services also use IOSB's, but they are laid ** out differently. IOSB_GET_T is such a structure. The first longword (not ** word) is the status code, and the second word is reserved to DEC. */ typedef struct { unsigned long int status; unsigned long int reserved; } IOSB_GET_T; /* --- Item Lists --- */ /* The item list structures change dynamically according to the number ** of items in them. For this reason, typedefs (ITEM_2_T and ITEM_3_T) ** are provided for the items, and macro functions (ITEM_LIST_2_T() and ** ITEM_LIST_3_T()) are provided for the item lists. Here is an example ** showing the usage of an item list macro function: ** ** static const ITEM_LIST_3_T(item_list,2) = ** { ** { ** {sizeof pid,JPI$_PID,&pid,NULL}, ** {sizeof username,JPI$_USERNAME,&username,&username_length} ** }, ** 0 ** }; ** ** The number 2 means, of course, that there are two items in the ** itemlist (i.e., the PID and the username). */ typedef struct { unsigned short int component_size; unsigned short int item_code; void * component_p; } ITEM_2_T; typedef struct { unsigned short int buffer_size; unsigned short int item_code; void * buffer_p; unsigned short int * buffer_length_p; } ITEM_3_T; #define ITEM_LIST_2_T(variable_name,num_items) \ struct \ { \ ITEM_2_T item[num_items]; \ int terminating_zero; \ } variable_name #define ITEM_LIST_3_T(variable_name,num_items) \ struct \ { \ ITEM_3_T item[num_items]; \ int terminating_zero; \ } variable_name #endif /* !__VMS_TYPES_H__ */ *[XDVI]XDVI.C;7+,.i/ 4Mii- 0@123KPWOj56hg7Qjg8*]o9GHJX/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTE: * xdvi is based on prior work as noted in the modification history, below. */ /* * DVI previewer for X. * * Eric Cooper, CMU, September 1985. * * Code derived from dvi-imagen.c. * * Modification history: * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS. * 7/1988 Modified for X.11 --Mark Eichin, MIT * 12/1988 Added 'R' option, toolkit, magnifying glass * --Paul Vojta, UC Berkeley. * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ. * 3/1990 Added VMS support --Scott Allendorf, U of Iowa * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen * and Lee Hetherington, MIT * 4/1994 Added DPS support, bounding box * --Ricardo Telichevesky * and Luis Miguel Silveira, MIT RLE. * * Compilation options: * SYSV compile for System V * VMS compile for VMS * NOTOOL compile without toolkit * BUTTONS compile with buttons on the side of the window (needs toolkit) * MSBITFIRST store bitmaps internally with most significant bit first * BMSHORT store bitmaps in shorts instead of bytes * BMLONG store bitmaps in longs instead of bytes * ALTFONT default for -altfont option * A4 use European size paper * TEXXET support reflection dvi codes (right-to-left typesetting) * GREY use grey levels to shrink fonts * PS_DPS use display postscript to render pictures/bounding boxes * PS_NEWS use the NeWS server to render pictures/bounding boxes * PS_GS use Ghostscript to render pictures/bounding boxes * GS_PATH path to call the Ghostscript interpreter by */ #ifndef lint static char copyright[] = "@(#) Copyright (c) 1994 Paul Vojta. All rights reserved.\n"; #endif #ifndef ALTFONT #define ALTFONT "cmr10" #endif #if defined(PS_GS) && !defined(GS_PATH) #define GS_PATH "gs" #endif #ifndef A4 #define DEFAULT_PAPER "us" #else #define DEFAULT_PAPER "a4" #endif #define EXTERN #define INIT(x) =x #include /* includes atof() */ #include #include "xdvi.h" #include "patchlevel.h" static _Xconst struct {char a[24], b, c, d;} version = {"This is xdvi patchlevel ", '0' + PATCHLEVEL / 10, '0' + PATCHLEVEL % 10, 0}; #ifdef X_NOT_STDC_ENV #ifndef atof extern double atof ARGS((_Xconst char *)); #endif #endif /* Xlib and Xutil are already included */ #include #include #include "xdvi.icon" #ifdef TOOLKIT #ifdef OLD_X11_TOOLKIT #include #else /* not OLD_X11_TOOLKIT */ #include #include #endif /* not OLD_X11_TOOLKIT */ #include /* needed for def. of XtNiconX */ #ifndef XtSpecificationRelease #define XtSpecificationRelease 0 #endif #if XtSpecificationRelease >= 4 #include #ifdef BUTTONS #include #endif #else /* XtSpecificationRelease < 4 */ #define XtPointer caddr_t #include #ifdef BUTTONS #include #endif #endif /* XtSpecificationRelease */ #if XtSpecificationRelease < 5 typedef caddr_t XPointer; #endif #else /* !TOOLKIT */ #ifndef VMS typedef int Position; #endif #endif /* TOOLKIT */ #ifdef VMS /* * Magnifying glass cursor * * Developed by Tom Sawyer, April 1990 * Contibuted by Hunter Goatley, January 1991 * */ #define mag_glass_width 16 #define mag_glass_height 16 #define mag_glass_x_hot 6 #define mag_glass_y_hot 6 static char mag_glass_bits[] = { 0xf8, 0x03, 0x0c, 0x06, 0xe2, 0x09, 0x13, 0x1a, 0x01, 0x14, 0x01, 0x14, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x03, 0x10, 0x02, 0x18, 0x0c, 0x34, 0xf8, 0x6f, 0x00, 0xd8, 0x00, 0xb0, 0x00, 0xe0 }; #include /* Include the DECWindows cursor symbols */ static int DECWCursorFont; /* Space for the DECWindows cursor font */ static Pixmap MagnifyPixmap; /* Pixmap to hold our special mag-glass */ #include /* Motif apparently needs this one */ #endif /* VMS */ /* * Command line flags. */ static Dimension bwidth = 2; #define fore_Pixel resource._fore_Pixel #define back_Pixel resource._back_Pixel #ifdef TOOLKIT struct _resource resource; #define brdr_Pixel resource._brdr_Pixel #define hl_Pixel resource._hl_Pixel #define cr_Pixel resource._cr_Pixel #else /* TOOLKIT */ static Pixel hl_Pixel, cr_Pixel; #endif /* TOOLKIT */ struct mg_size_rec mg_size[5] = {{200, 150}, {400, 250}, {700, 500}, {1000, 800}, {1200, 1200}}; static char *curr_page; struct WindowRec mane = {(Window) 0, 3, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0}; struct WindowRec alt = {(Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0}; /* currwin is temporary storage except for within redraw() */ struct WindowRec currwin = {(Window) 0, 3, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0}; #ifdef lint #ifdef TOOLKIT WidgetClass viewportWidgetClass, widgetClass; #ifdef BUTTONS WidgetClass formWidgetClass, compositeWidgetClass, commandWidgetClass; #endif /* BUTTONS */ #endif /* TOOLKIT */ #endif /* lint */ /* * Data for options processing */ static _Xconst char silent[] = " "; /* flag value for usage() */ static _Xconst char subst[] = "x"; /* another flag value */ static _Xconst char *subst_val[] = {"-mgs[n] "}; #ifdef TOOLKIT static XrmOptionDescRec options[] = { {"-s", ".shrinkFactor", XrmoptionSepArg, (caddr_t) NULL}, #ifndef VMS {"-S", ".densityPercent", XrmoptionSepArg, (caddr_t) NULL}, #endif {"-density", ".densityPercent", XrmoptionSepArg, (caddr_t) NULL}, #ifdef GREY {"-nogrey", ".grey", XrmoptionNoArg, (caddr_t) "off"}, {"+nogrey", ".grey", XrmoptionNoArg, (caddr_t) "on"}, {"-gamma", ".gamma", XrmoptionSepArg, (caddr_t) NULL}, #endif {"-p", ".pixelsPerInch", XrmoptionSepArg, (caddr_t) NULL}, {"-margins", ".Margin", XrmoptionSepArg, (caddr_t) NULL}, {"-sidemargin", ".sideMargin", XrmoptionSepArg, (caddr_t) NULL}, {"-topmargin", ".topMargin", XrmoptionSepArg, (caddr_t) NULL}, {"-offsets", ".Offset", XrmoptionSepArg, (caddr_t) NULL}, {"-xoffset", ".xOffset", XrmoptionSepArg, (caddr_t) NULL}, {"-yoffset", ".yOffset", XrmoptionSepArg, (caddr_t) NULL}, {"-paper", ".paper", XrmoptionSepArg, (caddr_t) NULL}, {"-altfont", ".altFont", XrmoptionSepArg, (caddr_t) NULL}, #ifdef MAKEPK {"-nomakepk", ".makePk", XrmoptionNoArg, (caddr_t) "off"}, {"+nomakepk", ".makePk", XrmoptionNoArg, (caddr_t) "on"}, #endif {"-mfmode", ".mfMode", XrmoptionSepArg, (caddr_t) NULL}, {"-l", ".listFonts", XrmoptionNoArg, (caddr_t) "on"}, {"+l", ".listFonts", XrmoptionNoArg, (caddr_t) "off"}, #ifdef BUTTONS {"-expert", ".expert", XrmoptionNoArg, (caddr_t) "on"}, {"+expert", ".expert", XrmoptionNoArg, (caddr_t) "off"}, #endif {"-mgs", ".magnifierSize1",XrmoptionSepArg, (caddr_t) NULL}, {"-mgs1", ".magnifierSize1",XrmoptionSepArg, (caddr_t) NULL}, {"-mgs2", ".magnifierSize2",XrmoptionSepArg, (caddr_t) NULL}, {"-mgs3", ".magnifierSize3",XrmoptionSepArg, (caddr_t) NULL}, {"-mgs4", ".magnifierSize4",XrmoptionSepArg, (caddr_t) NULL}, {"-mgs5", ".magnifierSize5",XrmoptionSepArg, (caddr_t) NULL}, {"-hush", ".Hush", XrmoptionNoArg, (caddr_t) "on"}, {"+hush", ".Hush", XrmoptionNoArg, (caddr_t) "off"}, {"-hushspecials", ".hushSpecials", XrmoptionNoArg, (caddr_t) "on"}, {"+hushspecials", ".hushSpecials", XrmoptionNoArg, (caddr_t) "off"}, {"-hushchars", ".hushLostChars", XrmoptionNoArg, (caddr_t) "on"}, {"+hushchars", ".hushLostChars", XrmoptionNoArg, (caddr_t) "off"}, {"-hushchecksums", ".hushChecksums", XrmoptionNoArg, (caddr_t) "on"}, {"+hushchecksums", ".hushChecksums", XrmoptionNoArg, (caddr_t) "off"}, {"-safer", ".safer", XrmoptionNoArg, (caddr_t) "on"}, {"+safer", ".safer", XrmoptionNoArg, (caddr_t) "off"}, {"-fg", ".foreground", XrmoptionSepArg, (caddr_t) NULL}, {"-foreground", ".foreground", XrmoptionSepArg, (caddr_t) NULL}, {"-bg", ".background", XrmoptionSepArg, (caddr_t) NULL}, {"-background", ".background", XrmoptionSepArg, (caddr_t) NULL}, {"-hl", ".highlight", XrmoptionSepArg, (caddr_t) NULL}, {"-cr", ".cursorColor", XrmoptionSepArg, (caddr_t) NULL}, {"-icongeometry",".iconGeometry",XrmoptionSepArg, (caddr_t) NULL}, {"-keep", ".keepPosition",XrmoptionNoArg, (caddr_t) "on"}, {"+keep", ".keepPosition",XrmoptionNoArg, (caddr_t) "off"}, {"-copy", ".copy", XrmoptionNoArg, (caddr_t) "on"}, {"+copy", ".copy", XrmoptionNoArg, (caddr_t) "off"}, {"-thorough", ".thorough", XrmoptionNoArg, (caddr_t) "on"}, {"+thorough", ".thorough", XrmoptionNoArg, (caddr_t) "off"}, #if PS {"-nopostscript",".postscript", XrmoptionNoArg, (caddr_t) "off"}, {"+nopostscript",".postscript", XrmoptionNoArg, (caddr_t) "on"}, {"-noscan", ".prescan", XrmoptionNoArg, (caddr_t) "off"}, {"+noscan", ".prescan", XrmoptionNoArg, (caddr_t) "on"}, {"-allowshell", ".allowShell", XrmoptionNoArg, (caddr_t) "on"}, {"+allowshell", ".allowShell", XrmoptionNoArg, (caddr_t) "off"}, #ifdef PS_DPS {"-nodps", ".dps", XrmoptionNoArg, (caddr_t) "off"}, {"+nodps", ".dps", XrmoptionNoArg, (caddr_t) "on"}, #endif #ifdef PS_NEWS {"-nonews", ".news", XrmoptionNoArg, (caddr_t) "off"}, {"+nonews", ".news", XrmoptionNoArg, (caddr_t) "on"}, #endif #ifdef PS_GS {"-noghostscript",".ghostscript", XrmoptionNoArg, (caddr_t) "off"}, {"+noghostscript",".ghostscript", XrmoptionNoArg, (caddr_t) "on"}, {"-interpreter",".interpreter", XrmoptionSepArg, (caddr_t) NULL}, {"-nogssafer", ".gsSafer", XrmoptionNoArg, (caddr_t) "off"}, {"+nogssafer", ".gsSafer", XrmoptionNoArg, (caddr_t) "on"}, {"-gspalette", ".palette", XrmoptionSepArg, (caddr_t) NULL}, #endif #endif /* PS */ {"-debug", ".debugLevel", XrmoptionSepArg, (caddr_t) NULL}, {"-version", ".version", XrmoptionNoArg, (caddr_t) "on"}, {"+version", ".version", XrmoptionNoArg, (caddr_t) "off"}, }; #define offset(field) XtOffsetOf(struct _resource, field) static int basedpi = BDPI; /* default value for -p option */ static char XtRBool3[] = "Bool3"; /* resource for Bool3 */ static XtResource application_resources[] = { {"shrinkFactor", "ShrinkFactor", XtRInt, sizeof(int), offset(shrinkfactor), XtRString, "3"}, {"densityPercent", "DensityPercent", XtRInt, sizeof(int), offset(_density), XtRString, "40"}, #ifdef GREY {"gamma", "Gamma", XtRFloat, sizeof(float), offset(_gamma), XtRString, "1"}, #endif {"pixelsPerInch", "PixelsPerInch", XtRInt, sizeof(int), offset(_pixels_per_inch), XtRInt, (caddr_t) &basedpi}, {"sideMargin", "Margin", XtRString, sizeof(char *), offset(sidemargin), XtRString, (caddr_t) NULL}, {"topMargin", "Margin", XtRString, sizeof(char *), offset(topmargin), XtRString, (caddr_t) NULL}, {"xOffset", "Offset", XtRString, sizeof(char *), offset(xoffset), XtRString, (caddr_t) NULL}, {"yOffset", "Offset", XtRString, sizeof(char *), offset(yoffset), XtRString, (caddr_t) NULL}, {"paper", "Paper", XtRString, sizeof(char *), offset(paper), XtRString, (caddr_t) DEFAULT_PAPER}, {"altFont", "AltFont", XtRString, sizeof(char *), offset(_alt_font), XtRString, (caddr_t) ALTFONT}, #ifdef MAKEPK {"makePk", "MakePk", XtRBoolean, sizeof(Boolean), offset(makepk), XtRString, "true"}, #endif {"mfMode", "MfMode", XtRString, sizeof(char *), offset(mfmode), XtRString, NULL}, {"listFonts", "ListFonts", XtRBoolean, sizeof(Boolean), offset(_list_fonts), XtRString, "false"}, {"reverseVideo", "ReverseVideo", XtRBoolean, sizeof(Boolean), offset(reverse), XtRString, "false"}, {"hushSpecials", "Hush", XtRBoolean, sizeof(Boolean), offset(_hush_spec), XtRString, "false"}, {"hushLostChars", "Hush", XtRBoolean, sizeof(Boolean), offset(_hush_chars), XtRString, "false"}, {"hushChecksums", "Hush", XtRBoolean, sizeof(Boolean), offset(_hush_chk), XtRString, "false"}, {"safer", "Safer", XtRBoolean, sizeof(Boolean), offset(safer), XtRString, "false"}, {"foreground", "Foreground", XtRPixel, sizeof(Pixel), offset(_fore_Pixel), XtRPixel, (caddr_t) &resource._fore_Pixel}, {"foreground", "Foreground", XtRString, sizeof(char *), offset(fore_color), XtRString, (caddr_t) NULL}, {"background", "Background", XtRPixel, sizeof(Pixel), offset(_back_Pixel), XtRPixel, (caddr_t) &resource._back_Pixel}, {"background", "Background", XtRString, sizeof(char *), offset(back_color), XtRString, (caddr_t) NULL}, {"borderColor", "BorderColor", XtRPixel, sizeof(Pixel), offset(_brdr_Pixel), XtRPixel, (caddr_t) &resource._brdr_Pixel}, {"borderColor", "BorderColor", XtRString, sizeof(char *), offset(brdr_color), XtRString, (caddr_t) NULL}, {"highlight", "Highlight", XtRPixel, sizeof(Pixel), offset(_hl_Pixel), XtRPixel, (caddr_t) &resource._hl_Pixel}, {"highlight", "Highlight", XtRString, sizeof(char *), offset(high_color), XtRString, (caddr_t) NULL}, {"cursorColor", "CursorColor", XtRPixel, sizeof(Pixel), offset(_cr_Pixel), XtRPixel, (caddr_t) &resource._cr_Pixel}, {"cursorColor", "CursorColor", XtRString, sizeof(char *), offset(curs_color), XtRString, (caddr_t) NULL}, {"iconGeometry", "IconGeometry", XtRString, sizeof(char *), offset(icon_geometry), XtRString, (caddr_t) NULL}, {"keepPosition", "KeepPosition", XtRBoolean, sizeof(Boolean), offset(keep_flag), XtRString, "false"}, #if PS {"postscript", "Postscript", XtRBoolean, sizeof(Boolean), offset(_postscript), XtRString, "true"}, {"prescan", "Prescan", XtRBoolean, sizeof(Boolean), offset(prescan), XtRString, "true"}, {"allowShell", "AllowShell", XtRBoolean, sizeof(Boolean), offset(allow_shell), XtRString, "false"}, #ifdef PS_DPS {"dps", "DPS", XtRBoolean, sizeof(Boolean), offset(useDPS), XtRString, "true"}, #endif #ifdef PS_NEWS {"news", "News", XtRBoolean, sizeof(Boolean), offset(useNeWS), XtRString, "true"}, #endif #ifdef PS_GS {"ghostscript", "Ghostscript", XtRBoolean, sizeof(Boolean), offset(useGS), XtRString, "true"}, {"interpreter", "Interpreter", XtRString, sizeof(char *), offset(gs_path), XtRString, (caddr_t) GS_PATH}, {"gsSafer", "Safer", XtRBoolean, sizeof(Boolean), offset(gs_safer), XtRString, "true"}, {"palette", "Palette", XtRString, sizeof(char *), offset(gs_palette), XtRString, (caddr_t) "Color"}, #endif #endif /* PS */ {"copy", "Copy", XtRBool3, sizeof(Bool3), offset(copy), XtRString, "maybe"}, {"thorough", "Thorough", XtRBoolean, sizeof(Boolean), offset(thorough), XtRString, "false"}, {"debugLevel", "DebugLevel", XtRString, sizeof(char *), offset(debug_arg), XtRString, (caddr_t) NULL}, {"version", "Version", XtRBoolean, sizeof(Boolean), offset(version_flag), XtRString, "false"}, #ifdef BUTTONS {"expert", "Expert", XtRBoolean, sizeof(Boolean), offset(expert), XtRString, "false"}, #endif {"magnifierSize1", "MagnifierSize", XtRString, sizeof(char *), offset(mg_arg[0]), XtRString, (caddr_t) NULL}, {"magnifierSize2", "MagnifierSize", XtRString, sizeof(char *), offset(mg_arg[1]), XtRString, (caddr_t) NULL}, {"magnifierSize3", "MagnifierSize", XtRString, sizeof(char *), offset(mg_arg[2]), XtRString, (caddr_t) NULL}, {"magnifierSize4", "MagnifierSize", XtRString, sizeof(char *), offset(mg_arg[3]), XtRString, (caddr_t) NULL}, {"magnifierSize5", "MagnifierSize", XtRString, sizeof(char *), offset(mg_arg[4]), XtRString, (caddr_t) NULL}, #ifdef GREY {"grey", "Grey", XtRBoolean, sizeof(Boolean), offset(_use_grey), XtRString, "true"}, #endif }; #undef offset static _Xconst char *usagestr[] = { /* shrinkFactor */ "shrink", #ifndef VMS /* S */ "density", /* density */ silent, #else /* density */ "density", #endif #ifdef GREY /* gamma */ "g", #endif /* p */ "pixels", /* margins */ "dimen", /* sidemargin */ "dimen", /* topmargin */ "dimen", /* offsets */ "dimen", /* xoffset */ "dimen", /* yoffset */ "dimen", /* paper */ "papertype", /* altfont */ "font", /* mfmode */ "mode-def", /* rv */ "^-l", "-rv", /* mgs */ subst, /* msg1 */ silent, /* msg2 */ silent, /* msg3 */ silent, /* msg4 */ silent, /* msg5 */ silent, /* fg */ "color", /* foreground */ silent, /* bg */ "color", /* background */ silent, /* hl */ "color", /* bd */ "^-hl", "-bd ", /* cr */ "color", /* bw */ "^-cr", "-bw ", #ifndef VMS /* display */ "^-cr", "-display ", #else /* display */ "^-cr", "-display ", #endif /* geometry */ "^-cr", "-geometry ", /* icongeometry */ "geometry", /* iconic */ "^-icongeometry", "-iconic", #ifdef BUTTONS /* font */ "^-icongeometry", "-font ", #endif #ifdef PS_GS /* interpreter */ "path", /* gspalette */ "monochrome|grayscale|color", #endif /* debug */ "bitmask", /* [dummy] */ "z" }; #ifdef NOQUERY #define drawWidgetClass widgetClass #else /* ARGSUSED */ static XtGeometryResult QueryGeometry(w, constraints, reply) Widget w; XtWidgetGeometry *constraints, *reply; { reply->request_mode = CWWidth | CWHeight; reply->width = page_w; reply->height = page_h; return XtGeometryAlmost; } #include #include #ifdef lint WidgetClassRec widgetClassRec; #endif /* if the following gives you trouble, just compile with -DNOQUERY */ static WidgetClassRec drawingWidgetClass = { { /* superclass */ &widgetClassRec, /* class_name */ "Draw", /* widget_size */ sizeof(WidgetRec), /* class_initialize */ NULL, /* class_part_initialize*/ NULL, /* class_inited */ FALSE, /* initialize */ NULL, /* initialize_hook */ NULL, /* realize */ XtInheritRealize, /* actions */ NULL, /* num_actions */ 0, /* resources */ NULL, /* num_resources */ 0, /* xrm_class */ NULLQUARK, /* compress_motion */ FALSE, /* compress_exposure */ TRUE, /* compress_enterleave*/ FALSE, /* visible_interest */ FALSE, /* destroy */ NULL, /* resize */ XtInheritResize, /* expose */ XtInheritExpose, /* set_values */ NULL, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ XtInheritAcceptFocus, /* version */ XtVersion, /* callback_offsets */ NULL, /* tm_table */ XtInheritTranslations, /* query_geometry */ QueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL } }; #define drawWidgetClass &drawingWidgetClass #endif /* NOQUERY */ static Arg vport_args[] = { #ifdef BUTTONS {XtNborderWidth, (XtArgVal) 0}, {XtNtop, (XtArgVal) XtChainTop}, {XtNbottom, (XtArgVal) XtChainBottom}, {XtNleft, (XtArgVal) XtChainLeft}, {XtNright, (XtArgVal) XtChainRight}, #endif {XtNallowHoriz, (XtArgVal) True}, {XtNallowVert, (XtArgVal) True}, }; static Arg draw_args[] = { {XtNwidth, (XtArgVal) 0}, {XtNheight, (XtArgVal) 0}, #ifdef GREY {XtNbackground, (XtArgVal) 0}, #endif {XtNx, (XtArgVal) 0}, {XtNy, (XtArgVal) 0}, {XtNlabel, (XtArgVal) ""}, }; #ifdef BUTTONS static Arg form_args[] = { {XtNdefaultDistance, (XtArgVal) 0}, }; #endif #else /* !TOOLKIT */ static char *display; static char *geometry; static char *margins; static char *offsets; static Boolean hush; static Boolean iconic = False; #define ADDR(x) (caddr_t) &resource.x static struct option { _Xconst char *name; _Xconst char *resource; enum {FalseArg, TrueArg, StickyArg, SepArg} argclass; enum {BooleanArg, Bool3Arg, StringArg, NumberArg, FloatArg} argtype; int classcount; _Xconst char *usagestr; caddr_t address; } options[] = { {"+", NULL, StickyArg, StringArg, 1, NULL, (caddr_t) &curr_page}, {"-s", "shrinkFactor", SepArg, NumberArg, 1, "shrink", (caddr_t)&shrink_factor}, #ifndef VMS {"-S", NULL, SepArg, NumberArg, 2, "density", ADDR(_density)}, {"-density", "densityPercent", SepArg, NumberArg, 1, silent, ADDR(_density)}, #else {"-density", "densityPercent", SepArg, NumberArg, 1, "density", ADDR(_density)}, #endif #ifdef GREY {"-nogrey", NULL, FalseArg, BooleanArg, 2, NULL, ADDR(_use_grey)}, {"+nogrey", "grey", TrueArg, BooleanArg, 1, NULL, ADDR(_use_grey)}, {"-gamma", "gamma", SepArg, FloatArg, 1, "g", ADDR(_gamma)}, #endif {"-p", "pixelsPerInch", SepArg, NumberArg, 1, "pixels", ADDR(_pixels_per_inch)}, {"-margins", "Margin", SepArg, StringArg, 3, "dimen", (caddr_t) &margins}, {"-sidemargin", "sideMargin", SepArg, StringArg, 1, "dimen", ADDR(sidemargin)}, {"-topmargin", "topMargin", SepArg, StringArg, 1, "dimen", ADDR(topmargin)}, {"-offsets", "Offset", SepArg, StringArg, 3, "dimen", (caddr_t) &offsets}, {"-xoffset", "xOffset", SepArg, StringArg, 1, "dimen", ADDR(xoffset)}, {"-yoffset", "yOffset", SepArg, StringArg, 1, "dimen", ADDR(yoffset)}, {"-paper", "paper", SepArg, StringArg, 1, "papertype", ADDR(paper)}, {"-altfont", "altFont", SepArg, StringArg, 1, "font", ADDR(_alt_font)}, #ifdef MAKEPK {"-nomakepk", "makePk", FalseArg, BooleanArg, 2, NULL, ADDR(makepk)}, {"+nomakepk", "makePk", TrueArg, BooleanArg, 1, NULL, ADDR(makepk)}, #endif {"-mfmode", "mfMode", SepArg, StringArg, 1, "mode-def", ADDR(mfmode)}, {"-l", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(_list_fonts)}, {"+l", "listFonts", FalseArg, BooleanArg, 1, NULL, ADDR(_li HQ7~XDVI.BAK [XDVI]XDVI.C;7;5MiLz-st_fonts)}, {"-rv", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(reverse)}, {"+rv", "reverseVideo", FalseArg, BooleanArg, 1, NULL, ADDR(reverse)}, {"-mgs", NULL, SepArg, StringArg, 2, subst, ADDR(mg_arg[0])}, {"-mgs1", "magnifierSize1",SepArg, StringArg, 1, silent, ADDR(mg_arg[0])}, {"-mgs2", "magnifierSize2",SepArg, StringArg, 1, silent, ADDR(mg_arg[1])}, {"-mgs3", "magnifierSize3",SepArg, StringArg, 1, silent, ADDR(mg_arg[2])}, {"-mgs4", "magnifierSize4",SepArg, StringArg, 1, silent, ADDR(mg_arg[3])}, {"-mgs5", "magnifierSize5",SepArg, StringArg, 1, silent, ADDR(mg_arg[4])}, {"-hush", NULL, TrueArg, BooleanArg, 6, NULL, (caddr_t) &hush}, {"+hush", "Hush", FalseArg, BooleanArg, 5, NULL, (caddr_t) &hush}, {"-hushspecials", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(_hush_spec)}, {"+hushspecials", "hushSpecials", FalseArg, BooleanArg, 1, NULL, ADDR(_hush_spec)}, {"-hushchars", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(_hush_chars)}, {"+hushchars", "hushLostChars", FalseArg, BooleanArg, 1, NULL, ADDR(_hush_chars)}, {"-hushchecksums", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(_hush_chk)}, {"+hushchecksums","hushChecksums", FalseArg, BooleanArg, 1, NULL, ADDR(_hush_chk)}, {"-safer", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(safer)}, {"+safer", "safer", FalseArg, BooleanArg, 1, NULL, ADDR(safer)}, {"-borderwidth", "borderWidth", SepArg, NumberArg, 1, silent, (caddr_t) &bwidth}, {"-fg", NULL, SepArg, StringArg, 2, "color", ADDR(fore_color)}, {"-foreground", "foreground", SepArg, StringArg, 1, silent, ADDR(fore_color)}, {"-bg", NULL, SepArg, StringArg, 2, "color", ADDR(back_color)}, {"-background", "background", SepArg, StringArg, 1, silent, ADDR(back_color)}, {"-hl", "highlight", SepArg, StringArg, 1, "color", ADDR(high_color)}, {"-bd", NULL, SepArg, StringArg, 2, "color", ADDR(brdr_color)}, {"-bordercolor","borderColor", SepArg, StringArg, 1, silent, ADDR(brdr_color)}, {"-cr", "cursorColor", SepArg, StringArg, 1, "color", ADDR(curs_color)}, {"-bw", NULL, SepArg, NumberArg, 2, "width", (caddr_t) &bwidth}, #ifndef VMS {"-display", NULL, SepArg, StringArg, 1, "host:display", (caddr_t) &display}, #else {"-display", NULL, SepArg, StringArg, 1, "host::display", (caddr_t) &display}, #endif {"-geometry", "geometry", SepArg, StringArg, 1, "geometry", (caddr_t) &geometry}, {"-icongeometry","iconGeometry",StickyArg, StringArg, 1, "geometry", ADDR(icon_geometry)}, {"-iconic", NULL, TrueArg, BooleanArg, 2, NULL, (caddr_t) &iconic}, {"+iconic", "iconic", FalseArg, BooleanArg, 1, NULL, (caddr_t) &iconic}, {"-keep", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(keep_flag)}, {"+keep", "keepPosition", FalseArg, BooleanArg, 1, NULL, ADDR(keep_flag)}, {"-copy", NULL, TrueArg, Bool3Arg, 2, NULL, ADDR(copy)}, {"+copy", "copy", FalseArg, Bool3Arg, 1, NULL, ADDR(copy)}, {"-thorough", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(thorough)}, {"+thorough", "thorough", FalseArg, BooleanArg, 1, NULL, ADDR(thorough)}, #if PS {"-nopostscript", NULL, FalseArg, BooleanArg, 2, NULL, ADDR(_postscript)}, {"+nopostscript", "postscript", TrueArg, BooleanArg, 1, NULL, ADDR(_postscript)}, {"-noscan", NULL, FalseArg, BooleanArg, 2, NULL, ADDR(prescan)}, {"+noscan", "prescan", TrueArg, BooleanArg, 1, NULL, ADDR(prescan)}, {"-allowshell", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(allow_shell)}, {"+allowshell", "allowShell", FalseArg, BooleanArg, 1, NULL, ADDR(allow_shell)}, #ifdef PS_DPS {"-nodps", NULL, FalseArg, BooleanArg, 2, NULL, ADDR(useDPS)}, {"+nodps", "dps", TrueArg, BooleanArg, 1, NULL, ADDR(useDPS)}, #endif #ifdef PS_NEWS {"-nonews", NULL, FalseArg, BooleanArg, 2, NULL, ADDR(useNeWS)}, {"+nonews", "news", TrueArg, BooleanArg, 1, NULL, ADDR(useNeWS)}, #endif #ifdef PS_GS {"-noghostscript",NULL, FalseArg, BooleanArg, 2, NULL, ADDR(useGS)}, {"+noghostscript","ghostscript", TrueArg, BooleanArg, 1, NULL, ADDR(useGS)}, {"-interpreter", "interpreter", SepArg, StringArg, 1, "path", ADDR(gs_path)}, {"-nogssafer", NULL, FalseArg, BooleanArg, 2, NULL, ADDR(gs_safer)}, {"+nogssafer", "gsSafer", TrueArg, BooleanArg, 1, NULL, ADDR(gs_safer)}, {"-gspalette", "palette", SepArg, StringArg, 1, "monochrome|grayscale|color", ADDR(gs_palette)}, #endif #endif /* PS */ {"-debug", "debugLevel", SepArg, StringArg, 1, "bitmask", ADDR(debug_arg)}, {"-version", NULL, TrueArg, BooleanArg, 2, NULL, ADDR(version_flag)}, {"+version", "version", FalseArg, BooleanArg, 1, NULL, ADDR(version_flag)}, }; #endif /* !TOOLKIT */ static NORETURN void usage() { #ifdef TOOLKIT XrmOptionDescRec *opt; _Xconst char **usageptr = usagestr; #else struct option *opt; #endif _Xconst char **sv = subst_val; _Xconst char *str1; _Xconst char *str2; int col = 23; int n; Fputs("Usage: xdvi [+[]]", stderr); for (opt = options; opt < options + XtNumber(options); ++opt) { #ifdef TOOLKIT str1 = opt->option; if (*str1 != '-') continue; str2 = NULL; if (opt->argKind != XrmoptionNoArg) { str2 = *usageptr++; if (str2 == silent) continue; if (str2 == subst) { str1 = *sv++; str2 = NULL; } } for (;;) { n = strlen(str1) + 3; if (str2 != NULL) n += strlen(str2) + 3; if (col + n < 80) Putc(' ', stderr); else { Fputs("\n\t", stderr); col = 8 - 1; } if (str2 == NULL) Fprintf(stderr, "[%s]", str1); else Fprintf(stderr, "[%s <%s>]", str1, str2); col += n; if (**usageptr != '^' || strcmp(*usageptr + 1, opt->option) != 0) break; ++usageptr; str1 = *usageptr++; str2 = NULL; } #else /* !TOOLKIT */ str1 = opt->name; str2 = opt->usagestr; if (*str1 != '-' || str2 == silent) continue; if (str2 == subst) { str1 = *sv++; str2 = NULL; } n = strlen(str1) + 3; if (str2 != NULL) n += strlen(str2) + 3; if (col + n < 80) Putc(' ', stderr); else { Fputs("\n\t", stderr); col = 8 - 1; } if (str2 == NULL) Fprintf(stderr, "[%s]", str1); else Fprintf(stderr, "[%s <%s>]", str1, str2); col += n; #endif } if (col + 9 < 80) Putc(' ', stderr); else Fputs("\n\t", stderr); Fputs("dvi_file\n", stderr); exit(1); } static int atopix(arg) _Xconst char *arg; { int len = strlen(arg); _Xconst char *arg_end = arg; char tmp[11]; while ((*arg_end >= '0' && *arg_end <= '9') || *arg_end == '.') if (arg_end >= arg + XtNumber(tmp) - 1) return 0; else ++arg_end; bcopy(arg, tmp, arg_end - arg); tmp[arg_end - arg] = '\0'; return (len > 2 && arg[len - 2] == 'c' && arg[len - 1] == 'm' ? 1.0 / 2.54 : 1.0) * atof(tmp) * pixels_per_inch + 0.5; } /** ** Main programs start here. **/ #ifdef TOOLKIT static Arg temp_args1[] = { {XtNiconX, (XtArgVal) 0}, {XtNiconY, (XtArgVal) 0}, }; static Arg temp_args2 = {XtNborderWidth, (XtArgVal) &bwidth}; static Pixmap icon_pm; static Arg temp_args3[] = { {XtNiconPixmap, (XtArgVal) &icon_pm}, }; static Arg temp_args4[] = { {XtNtitle, (XtArgVal) 0}, {XtNiconName, (XtArgVal) 0}, {XtNinput, (XtArgVal) True}, }; static Arg set_wh_args[] = { {XtNwidth, (XtArgVal) 0}, {XtNheight, (XtArgVal) 0}, }; /* * Convert string to yes/no/maybe. Adapted from the X toolkit. */ /*ARGSUSED*/ Boolean XtCvtStringToBool3(dpy, args, num_args, fromVal, toVal, closure_ret) Display *dpy; XrmValuePtr args; Cardinal *num_args; XrmValuePtr fromVal; XrmValuePtr toVal; XtPointer *closure_ret; { String str = (String)fromVal->addr; static Bool3 value; if ( memicmp(str, "true", 5) == 0 || memicmp(str, "yes", 4) == 0 || memicmp(str, "on", 3) == 0 || memicmp(str, "1", 2) == 0) value = True; else if (memicmp(str, "false", 6) == 0 || memicmp(str, "no", 3) == 0 || memicmp(str, "off", 4) == 0 || memicmp(str, "0", 2) == 0) value = False; else if (memicmp(str, "maybe", 6) == 0) value = Maybe; else { XtDisplayStringConversionWarning(dpy, str, XtRBoolean); return False; } if (toVal->addr != NULL) { if (toVal->size < sizeof(Bool3)) { toVal->size = sizeof(Bool3); return False; } *(Bool3 *)(toVal->addr) = value; } else toVal->addr = (XPointer) &value; toVal->size = sizeof(Bool3); return True; } #else /* !TOOLKIT */ struct _resource resource = { /* density */ 40, #ifdef GREY /* gamma */ 1.0, #endif /* pixels_per_inch */ BDPI, /* sidemargin */ NULL, /* topmargin */ NULL, /* xoffset */ NULL, /* yoffset */ NULL, /* paper */ DEFAULT_PAPER, /* alt_font */ ALTFONT, #ifdef MAKEPK /* makepk */ True, #endif /* mfmode */ NULL, /* list_fonts */ False, /* reverse */ False, /* hush_spec */ False, /* hush_chars */ False, /* hush_chk */ False, /* safer */ False, /* fore_color */ NULL, /* back_color */ NULL, /* brdr_color */ NULL, /* high_color */ NULL, /* curs_color */ NULL, /* fore_Pixel */ (Pixel) 0, /* back_Pixel */ (Pixel) 0, /* icon_geometry */ NULL, /* keep_flag */ False, /* copy */ Maybe, /* thorough */ False, #if PS /* postscript */ True, /* prescan */ True, /* allow_shell */ Maybe, #ifdef PS_DPS /* useDPS */ True, #endif #ifdef PS_NEWS /* useNeWS */ True, #endif #ifdef PS_GS /* useGS */ True, /* gs_path */ GS_PATH, /* gs_safer */ True, /* gs_palette */ "Color", #endif #endif /* PS */ /* debug_arg */ NULL, /* version_flag */ False, /* mg_arg */ {NULL, NULL, NULL, NULL, NULL}, #ifdef GREY /* use_grey */ True, #endif }; static Pixel string_to_pixel(strp) /* adapted from the toolkit */ char **strp; { char *str = *strp; Status status; XColor color, junk; if (*str == '#') { /* an rgb definition */ status = XParseColor(DISP, DefaultColormapOfScreen(SCRN), str, &color); if (status != 0) status = XAllocColor(DISP, DefaultColormapOfScreen(SCRN), &color); } else /* a name */ status = XAllocNamedColor(DISP, DefaultColormapOfScreen(SCRN), str, &color, &junk); if (status == 0) { Fprintf(stderr, "Cannot allocate colormap entry for \"%s\"\n", str); *strp = NULL; return (Pixel) 0; } return color.pixel; } /* * Process the option table. This is not guaranteed for all possible * option tables, but at least it works for this one. */ static void parse_options(argc, argv) int argc; char **argv; { char **arg; char **argvend = argv + argc; char *optstring; caddr_t addr; struct option *opt, *lastopt, *candidate; int len1, len2, matchlen; /* * Step 1. Process command line options. */ for (arg = argv + 1; arg < argvend; ++arg) { len1 = strlen(*arg); candidate = NULL; matchlen = 0; for (opt = options; opt < options + XtNumber(options); ++opt) { len2 = strlen(opt->name); if (opt->argclass == StickyArg) { if (matchlen <= len2 && !strncmp(*arg, opt->name, len2)) { candidate = opt; matchlen = len2; } } else if (len1 <= len2 && matchlen <= len1 && !strncmp(*arg, opt->name, len1)) { if (len1 == len2) { candidate = opt; break; } if (matchlen < len1) candidate = opt; else if (candidate && candidate->argclass != StickyArg) candidate = NULL; matchlen = len1; } } if (candidate == NULL) { if (**arg == '-' || dvi_name) usage(); else { dvi_name = *arg; continue; } } /* flag it for subsequent processing */ candidate->resource = (char *) candidate; /* store the value */ addr = candidate->address; switch (candidate->argclass) { case FalseArg: *((Boolean *) addr) = False; continue; case TrueArg: *((Boolean *) addr) = True; continue; case StickyArg: optstring = *arg + strlen(candidate->name); break; case SepArg: ++arg; if (arg >= argvend) usage(); optstring = *arg; break; } switch (candidate->argtype) { case StringArg: *((char **) addr) = optstring; break; case NumberArg: *((int *) addr) = atoi(optstring); break; case FloatArg: *((float *) addr) = atof(optstring); break; default: ; } } /* * Step 2. Propagate classes for command line arguments. Backwards. */ for (opt = options + XtNumber(options) - 1; opt >= options; --opt) if (opt->resource == (char *) opt) { addr = opt->address; lastopt = opt + opt->classcount; for (candidate = opt; candidate < lastopt; ++candidate) { if (candidate->resource != NULL) { switch (opt->argtype) { case BooleanArg: case Bool3Arg: /* same type as Boolean */ *((Boolean *) candidate->address) = *((Boolean *) addr); break; case StringArg: *((char **) candidate->address) = *((char **) addr); break; case NumberArg: *((int *) candidate->address) = *((int *) addr); break; case FloatArg: *((float *) candidate->address) = *((float *) addr); break; } candidate->resource = NULL; } } } if ((DISP = XOpenDisplay(display)) == NULL) oops("Can't open display"); SCRN = DefaultScreenOfDisplay(DISP); /* * Step 3. Handle resources (including classes). */ for (opt = options; opt < options + XtNumber(options); ++opt) if (opt->resource && ((optstring = XGetDefault(DISP, prog, opt->resource)) || (optstring = XGetDefault(DISP, "XDvi", opt->resource)))) { lastopt = opt + opt->classcount; for (candidate = opt; candidate < lastopt; ++candidate) if (candidate->resource != NULL) switch (opt->argtype) { case Bool3Arg: if ( memicmp(optstring, "maybe", 6) == 0) { * (Bool3 *) candidate->address = Maybe; break; } /* otherwise, fall through; the underlying */ /* types of Bool3 and Boolean are the same. */ case BooleanArg: * (Boolean *) candidate->address = ( memicmp(optstring, "true", 5) == 0 || memicmp(optstring, "yes", 4) == 0 || memicmp(optstring, "on", 3) == 0 || memicmp(optstring, "1", 2) == 0); break; case StringArg: * (char **) candidate->address = optstring; break; case NumberArg: * (int *) candidate->address = atoi(optstring); break; case FloatArg: * (float *) candidate->address = atof(optstring); } } } #endif /* TOOLKIT */ static _Xconst char *paper_types[] = { "us", "8.5x11", "usr", "11x8.5", "legal", "8.5x14", "foolscap", "13.5x17.0", /* ??? */ /* ISO `A' formats, Portrait */ "a1", "59.4x84.0cm", "a2", "42.0x59.4cm", "a3", "29.7x42.0cm", "a4", "21.0x29.7cm", "a5", "14.85x21.0cm", "a6", "10.5x14.85cm", "a7", "7.42x10.5cm", /* ISO `A' formats, Landscape */ "a1r", "84.0x59.4cm", "a2r", "59.4x42.0cm", "a3r", "42.0x29.7cm", "a4r", "29.7x21.0cm", "a5r", "21.0x14.85cm", "a6r", "14.85x10.5cm", "a7r", "10.5x7.42cm", /* ISO `B' formats, Portrait */ "b1", "70.6x100.0cm", "b2", "50.0x70.6cm", "b3", "35.3x50.0cm", "b4", "25.0x35.3cm", "b5", "17.6x25.0cm", "b6", "13.5x17.6cm", "b7", "8.8x13.5cm", /* ISO `B' formats, Landscape */ "b1r", "100.0x70.6cm", "b2r", "70.6x50.0cm", "b3r", "50.0x35.3cm", "b4r", "35.3x25.0cm", "b5r", "25.0x17.6cm", "b6r", "17.6x13.5cm", "b7r", "13.5x8.8cm", /* ISO `C' formats, Portrait */ "c1", "64.8x91.6cm", "c2", "45.8x64.8cm", "c3", "32.4x45.8cm", "c4", "22.9x32.4cm", "c5", "16.2x22.9cm", "c6", "11.46x16.2cm", "c7", "8.1x11.46cm", /* ISO `C' formats, Landscape */ "c1r", "91.6x64.8cm", "c2r", "64.8x45.8cm", "c3r", "45.8x32.4cm", "c4r", "32.4x22.9cm", "c5r", "22.9x16.2cm", "c6r", "16.2x11.46cm", "c7r", "11.46x8.1cm", }; static Boolean set_paper_type() { _Xconst char *arg, *arg1; char temp[21]; _Xconst char **p; char *q; if (strlen(resource.paper) > sizeof(temp) - 1) return False; arg = resource.paper; q = temp; for (;;) { /* convert to lower case */ char c = *arg++; if (c >= 'A' && c <= 'Z') c ^= ('a' ^ 'A'); *q++ = c; if (c == '\0') break; } arg = temp; /* perform substitutions */ for (p = paper_types; p < paper_types + XtNumber(paper_types); p += 2) if (strcmp(temp, *p) == 0) { arg = p[1]; break; } arg1 = index(arg, 'x'); if (arg1 == NULL) return False; unshrunk_paper_w = atopix(arg); unshrunk_paper_h = atopix(arg1 + 1); return (unshrunk_paper_w != 0 && unshrunk_paper_h != 0); } /* * main program */ int main(argc, argv) int argc; char **argv; { #ifndef TOOLKIT XSizeHints size_hints; XWMHints wmhints; #endif /* TOOLKIT */ Dimension screen_w, screen_h; char *title_name; char *icon_name; unsigned baselen; int i; #ifndef VMS prog = rindex(*argv, '/'); #else prog = rindex(*argv, ']'); #endif if (prog != NULL) ++prog; else prog = *argv; #ifdef VMS if (index(prog, '.') != NULL) *index(prog, '.') = '\0'; #endif /* This has to be a special case, for now. */ if (argc == 2 && (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0)) { Puts((_Xconst char *) &version); exit(0); } #ifdef TOOLKIT top_level = XtInitialize(prog, "XDvi", options, XtNumber(options), &argc, argv); while (--argc > 0) { if (*(*++argv) == '+') if (curr_page != NULL) usage(); else curr_page = *argv + 1; else if (dvi_name != NULL) usage(); else dvi_name = *argv; } XtSetTypeConverter(XtRString, XtRBool3, XtCvtStringToBool3, NULL, 0, XtCacheNone, NULL); XtGetApplicationResources(top_level, (XtPointer) &resource, application_resources, XtNumber(application_resources), (ArgList) NULL, 0); DISP = XtDisplay(top_level); SCRN = XtScreen(top_level); shrink_factor = resource.shrinkfactor; #else /* !TOOLKIT */ parse_options(argc, argv); if (resource.fore_color) fore_Pixel = string_to_pixel(&resource.fore_color); if (resource.back_color) back_Pixel = string_to_pixel(&resource.back_color); if (resource.brdr_color) brdr_Pixel = string_to_pixel(&resource.brdr_color); if (resource.high_color) hl_Pixel = string_to_pixel(&resource.high_color); if (resource.curs_color) cr_Pixel = string_to_pixel(&resource.curs_color); #endif /* TOOLKIT */ if (shrink_factor <= 0 || density <= 0 || pixels_per_inch <= 0 || dvi_name == NULL) usage(); if (shrink_factor != 1) bak_shrink = shrink_factor; mane.shrinkfactor = shrink_factor; if (resource.debug_arg != NULL) debug = isdigit(*resource.debug_arg) ? atoi(resource.debug_arg) : DBG_ALL; if (resource.sidemargin) home_x = atopix(resource.sidemargin); if (resource.topmargin) home_y = atopix(resource.topmargin); offset_x = resource.xoffset ? atopix(resource.xoffset) : pixels_per_inch; offset_y = resource.yoffset ? atopix(resource.yoffset) : pixels_per_inch; if (!set_paper_type()) oops("Don't recognize paper type %s", resource.paper); for (i = 0; i < 5; ++i) if (resource.mg_arg[i] != NULL) { char *s; mg_size[i].w = mg_size[i].h = atoi(resource.mg_arg[i]); s = index(resource.mg_arg[i], 'x'); if (s != NULL) { mg_size[i].h = atoi(s + 1); if (mg_size[i].h <= 0) mg_size[i].w = 0; } } #if PS if (resource.safer) { resource.allow_shell = False; #ifdef PS_GS resource.gs_safer = True; #endif } #endif /* PS */ #ifdef PS_GS { _Xconst char *CGMcgm = "CGMcgm"; _Xconst char *cgmp; cgmp = index(CGMcgm, resource.gs_palette[0]); if (cgmp == NULL) oops("Illegal value %s for gs palette option", resource.gs_palette); if (cgmp >= CGMcgm + 3) resource.gs_palette[0] = *(cgmp - 3); } #endif if (resource.version_flag) Puts((_Xconst char *) &version); /* * Open the dvi file and set titles */ init_font_open(); open_dvi_file(); if (curr_page) { current_page = (*curr_page ? atoi(curr_page) : total_pages) - 1; if (current_page < 0 || current_page >= total_pages) usage(); } icon_name = rindex(dvi_name, '/'); if (icon_name != NULL) ++icon_name; else icon_name = dvi_name; baselen = strlen(icon_name); if (baselen >= sizeof(".dvi") && strcmp(icon_name + baselen - sizeof(".dvi") + 1, ".dvi") == 0) { /* remove the .dvi */ char *p; baselen -= sizeof(".dvi") - 1; p = xmalloc(baselen + 1, "icon name"); (void) strncpy(p, icon_name, (int) baselen); p[baselen] = '\0'; icon_name = p; } title_name = xmalloc(baselen + sizeof("Xdvi: "), "title name"); Strcpy(title_name, "Xdvi: "); Strcat(title_name, icon_name); /* * Colors */ if (resource.reverse) { if (!resource.fore_color) fore_Pixel = WhitePixelOfScreen(SCRN); if (!resource.back_color) back_Pixel = BlackPixelOfScreen(SCRN); /* Set them nonzero */ resource.fore_color = resource.back_color = (char *) &version; } else { if (!resource.fore_color) fore_Pixel = BlackPixelOfScreen(SCRN); if (!resource.back_color) back_Pixel = WhitePixelOfScreen(SCRN); } #ifdef GREY if (DefaultDepthOfScreen(SCRN) == 1) use_grey = False; #endif copy = resource.copy; if (copy == Maybe) #ifdef GREY copy = (!resource.thorough && !use_grey && DefaultDepthOfScreen(SCRN) > 1); #else copy = (!resource.thorough && DefaultDepthOfScreen(SCRN) > 1); #endif #ifdef GREY if (resource._gamma == 0.0) resource._gamma = 1.0; if (use_grey) init_pix(True); else #endif { XGCValues values; Pixel set_bits = (Pixel) (fore_Pixel & ~back_Pixel); Pixel clr_bits = (Pixel) (back_Pixel & ~fore_Pixel); #define MakeGC(fcn, fg, bg) (values.function = fcn, values.foreground=fg,\ values.background=bg,\ XCreateGC(DISP, RootWindowOfScreen(SCRN),\ GCFunction|GCForeground|GCBackground, &values)) if (copy || (set_bits && clr_bits)) ruleGC = MakeGC(GXcopy, fore_Pixel, back_Pixel); if (copy) foreGC = ruleGC; else if (!resource.thorough && ruleGC) { foreGC = ruleGC; #ifndef VMS Puts("Note: overstrike characters may be incorrect."); #endif } else { if (set_bits) foreGC = MakeGC(GXor, set_bits, 0); if (clr_bits || !set_bits) if (foreGC) foreGC2 = MakeGC(GXandInverted, clr_bits, 0); else foreGC = MakeGC(GXandInverted, clr_bits, 0); if (!ruleGC) ruleGC = foreGC; } } { XGCValues values; highGC = ruleGC; if (resource.high_color) highGC = MakeGC(GXcopy, hl_Pixel, back_Pixel); } if (!resource.brdr_color) brdr_Pixel = fore_Pixel; if (!resource.high_color) hl_Pixel = fore_Pixel; #ifndef VMS ready_cursor = XCreateFontCursor(DISP, XC_cross); redraw_cursor = XCreateFontCursor(DISP, XC_watch); #else DECWCursorFont = XLoadFont(DISP, "DECW$CURSOR"); XSetFont(DISP, foreGC, DECWCursorFont); redraw_cursor = XCreateGlyphCursor(DISP, DECWCursorFont, DECWCursorFont, decw$c_wait_cursor, decw$c_wait_cursor + 1, &resource.fore_color, &resource.back_color); MagnifyPixmap = XCreateBitmapFromData (DISP, RootWindowOfScreen(SCRN), mag_glass_bits, mag_glass_width, mag_glass_height); ready_cursor = XCreatePixmapCursor(DISP, MagnifyPixmap, MagnifyPixmap, &resource.back_color, &resource.fore_color, mag_glass_x_hot, mag_glass_y_hot); #endif /* VMS */ if (!resource.curs_color) cr_Pixel = hl_Pixel; { XColor bg_Color, cr_Color; bg_Color.pixel = back_Pixel; XQueryColor(DISP, DefaultColormapOfScreen(SCRN), &bg_Color); cr_Color.pixel = cr_Pixel; XQueryColor(DISP, DefaultColormapOfScreen(SCRN), &cr_Color); XRecolorCursor(DISP, ready_cursor, &cr_Color, &bg_Color); XRecolorCursor(DISP, redraw_cursor, &cr_Color, &bg_Color); } #ifdef TOOLKIT /* * Windows (toolkit) */ /* The following code is lifted from Xterm */ if (resource.icon_geometry != NULL) { int scr, junk; for(scr = 0; /* yyuucchh */ SCRN != ScreenOfDisplay(DISP, scr); scr++); (void) XGeometry(DISP, scr, resource.icon_geometry, "", 0, 0, 0, 0, 0, (int *) &temp_args1[0].value, (int *) &temp_args1[1].value, &junk, &junk); XtSetValues(top_level, temp_args1, XtNumber(temp_args1)); } /* Set icon pixmap */ XtGetValues(top_level, temp_args3, XtNumber(temp_args3)); if (icon_pm == (Pixmap) 0) { temp_args3[0].value = (XtArgVal) (XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), (_Xconst char *) xdvi_bits, xdvi_width, xdvi_height)); XtSetValues(top_level, temp_args3, XtNumber(temp_args3)); } temp_args4[0].value = (XtArgVal) title_name; temp_args4[1].value = (XtArgVal) icon_name; XtSetValues(top_level, temp_args4, XtNumber(temp_args4)); #ifdef BUTTONS form_widget = XtCreateManagedWidget("form", formWidgetClass, top_level, form_args, XtNumber(form_args)); #else /* !BUTTONS */ #define form_widget top_level /* for calls to XtAddEventHandler */ #endif /* BUTTONS */ vport_widget = XtCreateManagedWidget("vport", viewportWidgetClass, form_widget, vport_args, XtNumber(vport_args)); clip_widget = XtNameToWidget(vport_widget, "clip"); draw_args[0].value = (XtArgVal) page_w; draw_args[1].value = (XtArgVal) page_h; #ifdef GREY draw_args[2].value = (XtArgVal) back_Pixel; #endif draw_widget = XtCreateManagedWidget("drawing", drawWidgetClass, vport_widget, draw_args, XtNumber(draw_args)); { /* set default window size */ #ifdef BUTTONS int xtra_wid = resource.expert ? 0 : XTRA_WID; #else #define xtra_wid 0 #endif XtWidgetGeometry constraints; XtWidgetGeometry reply; XtGetValues(top_level, &temp_args2, 1); /* get border width */ screen_w = WidthOfScreen(SCRN) - 2 * bwidth - xtra_wid; screen_h = HeightOfScreen(SCRN) - 2 * bwidth; constraints.request_mode = reply.request_mode = 0; constraints.width = page_w; if (page_w > screen_w) { constraints.request_mode = CWWidth; constraints.width = screen_w; } constraints.height = page_h; if (page_h > screen_h) { constraints.request_mode = CWHeight; constraints.height = screen_h; } if (constraints.request_mode != 0 && constraints.request_mode != (CWWidth | CWHeight)) (void) XtQueryGeometry(vport_widget, &constraints, &reply); if (!(reply.request_mode & CWWidth)) reply.width = constraints.width; set_wh_args[0].value = (XtArgVal) ((reply.width < screen_w ? reply.width : screen_w) + xtra_wid); if (!(reply.request_mode & CWHeight)) reply.height = constraints.height; set_wh_args[1].value = (XtArgVal) (reply.height < screen_h ? reply.height : screen_h); XtSetValues(top_level, set_wh_args, XtNumber(set_wh_args)); #ifdef BUTTONS set_wh_args[0].value -= xtra_wid; XtSetValues(vport_widget, set_wh_args, XtNumber(set_wh_args)); if (!resource.expert) create_buttons(set_wh_args[1].value); #endif /* BUTTONS */ } if (resource.fore_color) { static Arg fore_args = {XtNforeground, (XtArgVal) 0}; fore_args.value = fore_Pixel; XtSetValues(draw_widget, &fore_args, 1); } if (resource.back_color) { static Arg back_args = {XtNbackground, (XtArgVal) 0}; back_args.value = back_Pixel; XtSetValues(draw_widget, &back_args, 1); XtSetValues(clip_widget, &back_args, 1); } XtAddEventHandler(form_widget, KeyPressMask, False, handle_key, (caddr_t) NULL); XtAddEventHandler(vport_widget, StructureNotifyMask, False, handle_resize, (caddr_t) NULL); XtAddEventHandler(draw_widget, ExposureMask, False, handle_exp, (caddr_t) &mane); XtAddEventHandler(draw_widget, ButtonPressMask, False, handle_button, (caddr_t) NULL); XtAddEventHandler(draw_widget, ButtonMotionMask, False, handle_motion, (caddr_t) NULL); XtAddEventHandler(draw_widget, ButtonReleaseMask, False, handle_release, (caddr_t) NULL); XtRealizeWidget(top_level); currwin.win = mane.win = XtWindow(draw_widget); { XWindowAttributes attrs; (void) XGetWindowAttributes(DISP, mane.win, &attrs); backing_store = attrs.backing_store; } #else /* !TOOLKIT */ /* * Windows (non toolkit) */ screen_w = WidthOfScreen(SCRN) - 2*bwidth; screen_h = HeightOfScreen(SCRN) - 2*bwidth; size_hints.flags = PMinSize; size_hints.min_width = size_hints.min_height = 50; size_hints.x = size_hints.y = 0; if (geometry != NULL) { int flag = XParseGeometry(geometry, &size_hints.x, &size_hints.y, &window_w, &window_h); if (flag & (XValue | YValue)) size_hints.flags |= USPosition; if (flag & (WidthValue | HeightValue)) size_hints.flags |= USSize; if (flag & XNegative) size_hints.x += screen_w - window_w; if (flag & YNegative) size_hints.y += screen_h - window_h; } if (!(size_hints.flags & USSize)) { int x_thick = 0; int y_thick = 0; if (screen_w < page_w) x_thick = BAR_THICK; if (screen_h < page_h + x_thick) y_thick = BAR_THICK; window_w = page_w + y_thick; if (window_w > screen_w) { x_thick = BAR_THICK; window_w = screen_w; } window_h = page_h + x_thick; if (window_h > screen_h) window_h = screen_h; size_hints.flags |= PSize; } size_hints.width = window_w; size_hints.height = window_h; top_level = XCreateSimpleWindow(DISP, RootWindowOfScreen(SCRN), size_hints.x, size_hints.y, window_w, window_h, bwidth, brdr_Pixel, back_Pixel); XSetStandardProperties(DISP, top_level, title_name, icon_name, (Pixmap) 0, argv, argc, &size_hints); wmhints.flags = InputHint | StateHint | IconPixmapHint; wmhints.input = True; /* window manager must direct input */ wmhints.initial_state = iconic ? IconicState : NormalState; wmhints.icon_pixmap = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), (_Xconst char *) xdvi_bits, xdvi_width, xdvi_height); if (resource.icon_geometry != NULL) { int junk; wmhints.flags |= IconPositionHint; (void) XGeometry(DISP, DefaultScreen(DISP), resource.icon_geometry, "", 0, 0, 0, 0, 0, &wmhints.icon_x, &wmhints.icon_y, &junk, &junk); } XSetWMHints(DISP, top_level, &wmhints); XSelectInput(DISP, top_level, KeyPressMask | StructureNotifyMask); XMapWindow(DISP, top_level); XFlush(DISP); #endif /* TOOLKIT */ #define rebindkey(ks, str) XRebindKeysym(DISP, (KeySym) ks, \ (KeySym *) NULL, 0, (_Xconst ubyte *) str, 1) rebindkey(XK_Home, "^"); rebindkey(XK_Left, "l"); rebindkey(XK_Up, "u"); rebindkey(XK_Right, "r"); rebindkey(XK_Down, "d"); rebindkey(XK_Prior, "b"); rebindkey(XK_Next, "f"); #ifdef XK_KP_Left rebindkey(XK_KP_Home, "^"); rebindkey(XK_KP_Left, "l"); rebindkey(XK_KP_Up, "u"); rebindkey(XK_KP_Right, "r"); rebindkey(XK_KP_Down, "d"); rebindkey(XK_KP_Prior, "b"); rebindkey(XK_KP_Next, "f"); #endif /* XK_KP_Left */ #undef rebindkey image = XCreateImage(DISP, DefaultVisualOfScreen(SCRN), 1, XYBitmap, 0, (char *)NULL, 0, 0, BITS_PER_BMUNIT, 0); image->bitmap_unit = BITS_PER_BMUNIT; #ifndef MSBITFIRST image->bitmap_bit_order = LSBFirst; #else image->bitmap_bit_order = MSBFirst; #endif { short endian = MSBFirst << 8 | LSBFirst; image->byte_order = *((char *) &endian); } do_pages(); #if PS psp.destroy(); #endif return 0; /* do_pages() returns if DBG_BATCH is specified */ } *[XDVI]XDVI.H;3+,E .-/pX 4Q-%P- 0D123KPWO.56Xx#m7pگm8I@hp9GHJ`!~XDVI.BAKE  [XDVI]XDVI.H;3Q-9J/* * Written by Eric C. Cooper, CMU */ /******************************** * The C environment * *******************************/ #include /* include Xfuncs.h, if available */ #include /* needed for XDestroyImage */ #include #if XlibSpecificationRelease >= 5 #include #endif #ifndef X_NOT_STDC_ENV #include #endif #ifndef NOTOOL #include #define TOOLKIT #else #ifdef VMS #include #else #define XtNumber(arr) (sizeof(arr)/sizeof(arr[0])) typedef unsigned long Pixel; typedef char Boolean; typedef unsigned int Dimension; #undef TOOLKIT #undef BUTTONS #endif #endif typedef char Bool3; /* Yes/No/Maybe */ #define True 1 #define False 0 #define Maybe 2 #ifdef VMS #include #include #include #if __DECC_VER < 50600000 #define index strchr #define rindex strrchr #define bzero(a, b) (void) memset ((void *) (a), 0, (size_t) (b)) #define bcopy(a, b, c) (void) memmove ((void *) (b), (void *) (a), (size_t) (c)) #endif #define VFORK 1 #endif #if !defined(SVR4) && (defined(_SVR4) || defined(_SVR4_SOURCE)) #define SVR4 #endif #if !defined(SVR4) && (defined(_SYSTYPE_SVR4) || defined(__svr4__)) #define SVR4 #endif #if defined(SVR3) || defined(SVR4) #undef SYSV #define SYSV #endif #ifndef BSD #if defined(SYSV) || defined(VMS) || defined(linux) #define BSD 0 #else #define BSD 1 #endif #endif #include #include #ifndef OPEN_MODE #ifndef VMS #define OPEN_MODE "r" #else /* VMS */ #define OPEN_MODE "r", "ctx=stm" #endif /* VMS */ #endif /* OPEN_MODE */ #ifndef OPEN_TEXTMODE #ifndef VMS #define OPEN_TEXTMODE "r" #else /* VMS */ #define OPEN_TEXTMODE "r", "dna=[]" /* dna=.. is a dummy specifier */ #endif /* VMS */ #endif /* OPEN_MODE */ #ifndef VMS #define OPEN_MODE_ARGS _Xconst char * #else #define OPEN_MODE_ARGS _Xconst char *, _Xconst char * #endif #ifndef HAS_SIGIO #define HAS_SIGIO BSD #endif #ifndef NeedFunctionPrototypes #if __STDC__ #define NeedFunctionPrototypes 1 #else /* STDC */ #define NeedFunctionPrototypes 0 #endif /* STDC */ #endif /* NeedFunctionPrototypes */ #if NeedFunctionPrototypes #define ARGS(x) x #else #define ARGS(x) () #endif #ifndef NeedWidePrototypes #define NeedWidePrototypes NeedFunctionPrototypes #endif #ifndef NeedVarargsPrototypes #define NeedVarargsPrototypes NeedFunctionPrototypes #endif #ifndef _XFUNCPROTOBEGIN #define _XFUNCPROTOBEGIN #define _XFUNCPROTOEND #endif #ifndef _Xconst #if __STDC__ #define _Xconst const #else /* STDC */ #define _Xconst #endif /* STDC */ #endif /* _Xconst */ #ifndef VOLATILE #if __STDC__ || (defined(__stdc__) && defined(__convex__)) #define VOLATILE volatile #else #define VOLATILE /* nothing */ #endif #endif #ifndef NORETURN #ifdef __GNUC__ #define NORETURN volatile #else #define NORETURN /* nothing */ #endif #endif #ifndef _Xsigned #if __STDC__ #define _Xsigned signed #else /* STDC */ #define _Xsigned #endif /* STDC */ #endif /* _Xsigned */ #define Printf (void) printf #define Puts (void) puts #define Fprintf (void) fprintf #define Sprintf (void) sprintf #define Fseek (void) fseek #define Fread (void) fread #define Fputs (void) fputs #define Putc (void) putc #define Putchar (void) putchar #define Fclose (void) fclose #define Fflush (void) fflush #define Strcat (void) strcat #define Strcpy (void) strcpy /******************************** * Types and data * *******************************/ #ifndef EXTERN #define EXTERN extern #define INIT(x) #endif #define MAXDIM 32767 typedef unsigned char ubyte; #if NeedWidePrototypes typedef unsigned int wide_ubyte; typedef int wide_bool; #define WIDENINT (int) #else typedef ubyte wide_ubyte; typedef Boolean wide_bool; #define WIDENINT #endif #ifdef MAKEPKCMD #undef MAKEPK #define MAKEPK #endif /* * pixel_conv is currently used only for converting absolute positions * to pixel values; although normally it should be * ((int) ((x) / shrink_factor + (1 << 15) >> 16)), * the rounding is achieved instead by moving the constant 1 << 15 to * PAGE_OFFSET in dvi_draw.c. */ #define pixel_conv(x) ((int) ((x) / shrink_factor >> 16)) #define pixel_round(x) ((int) ROUNDUP(x, shrink_factor << 16)) #define spell_conv0(n, f) ((long) (n * f)) #define spell_conv(n) spell_conv0(n, dimconv) #ifdef BMBYTE #define BMUNIT unsigned char #define BITS_PER_BMUNIT 8 #define BYTES_PER_BMUNIT 1 #else /* !BMBYTE */ #ifdef BMSHORT #define BMUNIT unsigned short #define BITS_PER_BMUNIT 16 #define BYTES_PER_BMUNIT 2 #else /* !BMSHORT */ #define BMLONG #ifdef __alpha #define BMUNIT unsigned int #else #define BMUNIT unsigned long #endif /* if __alpha */ #define BITS_PER_BMUNIT 32 #define BYTES_PER_BMUNIT 4 #endif /* !BMSHORT */ #endif /* !BMBYTE */ #define ADD(a, b) ((BMUNIT *) (((char *) a) + b)) #define SUB(a, b) ((BMUNIT *) (((char *) a) - b)) extern BMUNIT bit_masks[BITS_PER_BMUNIT + 1]; struct frame { struct framedata { long dvi_h, dvi_v, w, x, y, z; int pxl_v; } data; struct frame *next, *prev; }; #if NeedFunctionPrototypes #ifndef TEXXET typedef long (*set_char_proc)(wide_ubyte); #else /* TEXXET */ typedef void (*set_char_proc)(wide_ubyte, wide_ubyte); #endif /* TEXXET */ #else /* NeedFunctionPrototypes */ #ifndef TEXXET typedef long (*set_char_proc)(); #else /* TEXXET */ typedef void (*set_char_proc)(); #endif /* TEXXET */ #endif /* NeedFunctionPrototypes */ struct drawinf { /* this information is saved when using virtual fonts */ struct framedata data; struct font *fontp; set_char_proc set_char_p; int tn_table_len; struct font **tn_table; struct tn *tn_head; ubyte *pos, *end; struct font *virtual; #ifdef TEXXET int dir; #endif }; EXTERN struct drawinf currinf; /* entries below with the characters 'dvi' in them are actually stored in scaled pixel units */ #define DVI_H currinf.data.dvi_h #define PXL_H pixel_conv(currinf.data.dvi_h) #define DVI_V currinf.data.dvi_v #define PXL_V currinf.data.pxl_v #define WW currinf.data.w #define XX currinf.data.x #define YY currinf.data.y #define ZZ currinf.data.z #define ROUNDUP(x,y) (((x)+(y)-1)/(y)) EXTERN int current_page; EXTERN int total_pages; EXTERN int pageno_correct INIT(1); EXTERN long magnification; EXTERN double dimconv; EXTERN double tpic_conv; EXTERN int n_files_left INIT(32767); /* for LRU closing of fonts */ EXTERN time_t dvi_time; /* last mod. time for dvi file */ EXTERN unsigned int page_w, page_h; #if defined(GS_PATH) && !defined(PS_GS) #define PS_GS #endif #if defined(PS_DPS) || defined(PS_NEWS) || defined(PS_GS) #define PS 1 #else #define PS 0 #endif #if PS EXTERN int scanned_page; /* last page prescanned */ EXTERN int scanned_page_bak; /* actual value of the above */ EXTERN int scanned_page_reset; /* number to reset the above to */ #endif /* * Table of page offsets in DVI file, indexed by page number - 1. * Initialized in prepare_pages(). */ EXTERN long *page_offset; /* * Mechanism for reducing repeated warning about specials, lost characters, etc. */ EXTERN Boolean hush_spec_now; /* * If we're in the middle of a PSFIG special. */ EXTERN Boolean psfig_begun INIT(False); /* * Bitmap structure for raster ops. */ struct bitmap { unsigned short w, h; /* width and height in pixels */ short bytes_wide; /* scan-line width in bytes */ char *bits; /* pointer to the bits */ }; /* * Per-character information. * There is one of these for each character in a font (raster fonts only). * All fields are filled in at font definition time, * except for the bitmap, which is "faulted in" * when the character is first referenced. */ struct glyph { long addr; /* address of bitmap in font file */ long dvi_adv; /* DVI units to move reference point */ short x, y; /* x and y offset in pixels */ struct bitmap bitmap; /* bitmap for character */ short x2, y2; /* x and y offset in pixels (shrunken bitmap) */ #ifdef GREY XImage *image2; char *pixmap2; #endif struct bitmap bitmap2; /* shrunken bitmap for character */ }; /* * Per character information for virtual fonts */ struct macro { ubyte *pos; /* address of first byte of macro */ ubyte *end; /* address of last+1 byte */ long dvi_adv; /* DVI units to move reference point */ Boolean free_me; /* if free(pos) should be called when */ /* freeing space */ }; /* * The layout of a font information block. * There is one of these for every loaded font or magnification thereof. * Duplicates are eliminated: this is necessary because of possible recursion * in virtual fonts. * * Also note the strange units. The design size is in 1/2^20 point * units (also called micro-points), and the individual character widths * are in the TFM file in 1/2^20 ems units, i.e., relative to the design size. * * We then change the sizes to SPELL units (unshrunk pixel / 2^16). */ #define NOMAGSTP (-29999) #if NeedFunctionPrototypes typedef void (*read_char_proc)(register struct font *, wide_ubyte); #else typedef void (*read_char_proc)(); #endif struct font { struct font *next; /* link to next font info block */ char *fontname; /* name of font */ float fsize; /* size information (dots per inch) */ int magstepval; /* magstep number * two, or NOMAGSTP */ FILE *file; /* open font file or NULL */ char *filename; /* name of font file */ long checksum; /* checksum */ unsigned short timestamp; /* for LRU management of fonts */ ubyte flags; /* flags byte (see values below) */ ubyte maxchar; /* largest character code */ double dimconv; /* size conversion factor */ set_char_proc set_char_p; /* proc used to set char */ /* these fields are used by (loaded) raster fonts */ read_char_proc read_char; /* function to read bitmap */ struct glyph *glyph; /* these fields are used by (loaded) virtual fonts */ struct font **vf_table; /* list of fonts used by this vf */ struct tn *vf_chain; /* ditto, if TeXnumber >= VFTABLELEN */ struct font *first_font; /* first font defined */ struct macro *macro; /* I suppose the above could be put into a union, but we */ /* wouldn't save all that much space. */ }; #define FONT_IN_USE 1 /* used for housekeeping */ #define FONT_LOADED 2 /* if font file has been read */ #define FONT_VIRTUAL 4 /* if font is virtual */ #define TNTABLELEN 30 /* length of TeXnumber array (dvi file) */ #define VFTABLELEN 5 /* length of TeXnumber array (virtual fonts) */ struct tn { struct tn *next; /* link to next TeXnumber info block */ int TeXnumber; /* font number (in DVI file) */ struct font *fontp; /* pointer to the rest of the info */ }; EXTERN struct font *tn_table[TNTABLELEN]; EXTERN struct font *font_head INIT(NULL); EXTERN struct tn *tn_head INIT(NULL); EXTERN ubyte maxchar; EXTERN unsigned short current_timestamp INIT(0); /* * Struct used for finding files. */ #if PS struct findrec { _Xconst char *mainpath; _Xconst char *auxpath; }; extern struct findrec figfind; extern struct findrec headerfind; #endif /* PS */ /* * Command line flags. */ extern struct _resource { #ifdef TOOLKIT int shrinkfactor; #endif int _density; #ifdef GREY float _gamma; #endif int _pixels_per_inch; char *sidemargin; char *topmargin; char *xoffset; char *yoffset; _Xconst char *paper; char *_alt_font; #ifdef MAKEPK Boolean makepk; #endif char *mfmode; Boolean _list_fonts; Boolean reverse; Boolean _hush_spec; Boolean _hush_chars; Boolean _hush_chk; Boolean safer; char *fore_color; char *back_color; char *brdr_color; char *high_color; char *curs_color; Pixel _fore_Pixel; Pixel _back_Pixel; #ifdef TOOLKIT Pixel _brdr_Pixel; Pixel _hl_Pixel; Pixel _cr_Pixel; #endif char *icon_geometry; Boolean keep_flag; Bool3 copy; Boolean thorough; #if PS /* default is to use DPS, then NEWS, then GhostScript; * we will figure out later on which one we will use */ Boolean _postscript; Boolean prescan; Boolean allow_shell; #ifdef PS_DPS Boolean useDPS; #endif #ifdef PS_NEWS Boolean useNeWS; #endif #ifdef PS_GS Boolean useGS; char *gs_path; Boolean gs_safer; char *gs_palette; #endif #endif /* PS */ char *debug_arg; Boolean version_flag; #ifdef BUTTONS Boolean expert; #endif char *mg_arg[5]; #ifdef GREY Boolean _use_grey; #endif } resource; /* As a convenience, we define the field names without leading underscores * to point to the field of the above record. Here are the global ones; * the local ones are defined in each module. */ #define density resource._density #define pixels_per_inch resource._pixels_per_inch #define alt_font resource._alt_font #define list_fonts resource._list_fonts #define hush_spec resource._hush_spec #define hush_chars resource._hush_chars #define hush_chk resource._hush_chk #ifdef GREY #define use_grey resource._use_grey #endif #ifndef TOOLKIT EXTERN Pixel brdr_Pixel; #endif extern struct mg_size_rec { int w; int h; } mg_size[5]; EXTERN int debug INIT(0); #define DBG_BITMAP 1 #define DBG_DVI 2 #define DBG_PK 4 #define DBG_BATCH 8 #define DBG_EVENT 16 #define DBG_OPEN 32 #define DBG_PS 64 #define DBG_ALL (~DBG_BATCH) #ifndef BDPI #define BDPI 300 #endif EXTERN int offset_x, offset_y; EXTERN unsigned int unshrunk_paper_w, unshrunk_paper_h; EXTERN unsigned int unshrunk_page_w, unshrunk_page_h; EXTERN char *dvi_name INIT(NULL); EXTERN FILE *dvi_file; /* user's file */ EXTERN char *prog; EXTERN int bak_shrink; /* last shrink factor != 1 */ EXTERN Dimension window_w, window_h; EXTERN XImage *image; EXTERN int backing_store; EXTERN int home_x, home_y; EXTERN Display *DISP; EXTERN Screen *SCRN; EXTERN GC ruleGC; EXTERN GC foreGC, highGC; EXTERN GC foreGC2; EXTERN Bool3 copy; EXTERN Cursor redraw_cursor, ready_cursor; #ifdef GREY EXTERN unsigned long palette[17]; EXTERN unsigned long *pixeltbl; #endif /* GREY */ EXTERN Boolean canit INIT(False); EXTERN jmp_buf canit_env; EXTERN VOLATILE short event_counter INIT(0); #if PS EXTERN Boolean allow_can INIT(True); #else #define allow_can 0xff #endif struct WindowRec { Window win; int shrinkfactor; int base_x, base_y; unsigned int width, height; int min_x, max_x, min_y, max_y; /* for pending expose events */ }; extern struct WindowRec mane, alt, currwin; EXTERN int min_x, max_x, min_y, max_y; #define shrink_factor currwin.shrinkfactor #ifdef TOOLKIT EXTERN Widget top_level, vport_widget, draw_widget, clip_widget; #ifdef BUTTONS #define XTRA_WID 79 EXTERN Widget form_widget; #endif #else /* !TOOLKIT */ EXTERN Window top_level; #define BAR_WID 12 /* width of darkened area */ #define BAR_THICK 15 /* gross amount removed */ #endif /* TOOLKIT */ EXTERN jmp_buf dvi_env; /* mechanism to communicate dvi file errors */ EXTERN char *dvi_oops_msg; /* error message */ #if PS extern struct psprocs { void (*toggle) ARGS((void)); void (*destroy) ARGS((void)); void (*interrupt) ARGS((void)); void (*endpage) ARGS((void)); void (*drawbegin) ARGS((int, int, char *)); void (*drawraw) ARGS((char *)); void (*drawfile) ARGS((_Xconst char *, FILE *)); void (*drawend) ARGS((char *)); void (*beginheader) ARGS((void)); void (*endheader) ARGS((void)); void (*newdoc) ARGS((void)); } psp, no_ps_procs; #endif /* PS */ /******************************** * Procedures * *******************************/ _XFUNCPROTOBEGIN #ifdef BUTTONS extern void create_buttons ARGS((XtArgVal)); #endif #ifdef GREY extern void init_pix ARGS((wide_bool)); #endif extern void reconfig ARGS((void)); #ifdef TOOLKIT extern void handle_key ARGS((Widget, XtPointer, XEvent *, Boolean *)); extern void handle_resize ARGS((Widget, XtPointer, XEvent *, Boolean *)); extern void handle_button ARGS((Widget, XtPointer, XEvent *, Boolean *)); extern void handle_motion ARGS((Widget, XtPointer, XEvent *, Boolean *)); extern void handle_release ARGS((Widget, XtPointer, XEvent *, Boolean *)); extern void handle_exp ARGS((Widget, XtPointer, XEvent *, Boolean *)); #endif extern void showmessage ARGS((_Xconst char *)); extern void read_events ARGS((wide_bool)); extern void redraw_page ARGS((void)); extern void do_pages ARGS((void)); extern void reset_fonts ARGS((void)); extern void realloc_font ARGS((struct font *, wide_ubyte)); extern void realloc_virtual_font ARGS((struct font *, wide_ubyte)); extern Boolean load_font ARGS((struct font *)); extern struct font *define_font ARGS((FILE *, wide_ubyte, struct font *, struct font **, unsigned int, struct tn **)); extern void init_page ARGS((void)); extern void open_dvi_file ARGS((void)); extern Boolean check_dvi_file ARGS((void)); extern void put_border ARGS((int, int, unsigned int, unsigned int, GC)); #ifndef TEXXET extern long set_char ARGS((wide_ubyte)); extern long load_n_set_char ARGS((wide_ubyte)); extern long set_vf_char ARGS((wide_ubyte)); #else extern void set_char ARGS((wide_ubyte, wide_ubyte)); extern void load_n_set_char ARGS((wide_ubyte, wide_ubyte)); extern void set_vf_char ARGS((wide_ubyte, wide_ubyte)); #endif extern void draw_page ARGS((void)); extern void init_font_open ARGS((void)); extern FILE *font_open ARGS((_Xconst char *, char **, double, int *, int, char **)); #if PS extern void ps_newdoc ARGS((void)); extern void ps_destroy ARGS((void)); #endif extern void applicationDoSpecial ARGS((char *)); #if PS extern void scan_special ARGS((char *)); #endif #if NeedVarargsPrototypes extern NORETURN void oops(_Xconst char *, ...); #else extern NORETURN void oops(); #endif extern char *xmalloc ARGS((unsigned, _Xconst char *)); extern void alloc_bitmap ARGS((struct bitmap *)); extern int memicmp ARGS((_Xconst char *, _Xconst char *, size_t)); extern FILE *xfopen ARGS((_Xconst char *, OPEN_MODE_ARGS)); #ifdef PS_GS extern int xpipe ARGS((int *)); #endif extern unsigned long num ARGS((FILE *, int)); extern long snum ARGS((FILE *, int)); extern void read_PK_index ARGS((struct font *, wide_bool)); extern void read_GF_index ARGS((struct font *, wide_bool)); extern void read_VF_index ARGS((struct font *, wide_bool)); #if PS extern void drawbegin_none ARGS((int, int, char *)); extern void draw_bbox ARGS((void)); extern void NullProc ARGS((void)); #ifdef PS_DPS extern Boolean initDPS ARGS((void)); #endif #ifdef PS_NEWS extern Boolean initNeWS ARGS((void)); #endif #ifdef PS_GS extern Boolean initGS ARGS((void)); #endif #endif /* PS */ _XFUNCPROTOEND #define one(fp) ((unsigned char) getc(fp)) #define sone(fp) ((long) one(fp)) #define two(fp) num (fp, 2) #define stwo(fp) snum(fp, 2) #define four(fp) num (fp, 4) #define sfour(fp) snum(fp, 4) *[XDVI]XDVI.ICON;1+,&./ 4c- 0123KPWO56O]0ޖ7O]0ޖ8 aW_o9GHJ#define xdvi_width 48 #define xdvi_height 48 static _Xconst unsigned char xdvi_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x01, 0x00, 0x00, 0xa2, 0xe0, 0x44, 0x38, 0x95, 0x13, 0x9e, 0x17, 0x45, 0x45, 0x55, 0xf4, 0x82, 0xf0, 0x28, 0x3d, 0xd5, 0x13, 0x82, 0x10, 0x28, 0x05, 0x55, 0x10, 0x82, 0xe0, 0x10, 0x39, 0x8a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x79, 0x18, 0x18, 0x13, 0x16, 0x00, 0x69, 0x10, 0x18, 0x0e, 0x16, 0x00, 0xcf, 0x20, 0x1c, 0x0e, 0xd6, 0x00, 0xe9, 0xc3, 0x7b, 0x84, 0x3f, 0x01, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x08, 0x00, 0x00, 0x00, 0x70, 0xcc, 0x08, 0x00, 0x00, 0x00, 0x30, 0x52, 0x0a, 0x00, 0x00, 0x00, 0x30, 0x52, 0x0a, 0xc0, 0xff, 0x03, 0x30, 0x4c, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0xc0, 0xff, 0x03, 0x10, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0xf0, 0x17, 0x0b, 0x0c, 0x3c, 0xc0, 0x93, 0x20, 0x0c, 0x0e, 0x43, 0x20, 0x96, 0x40, 0x0c, 0x8e, 0x81, 0x10, 0x96, 0xbe, 0x0a, 0x8d, 0x81, 0x19, 0x90, 0x82, 0x8a, 0x8c, 0x81, 0x0d, 0x90, 0x42, 0x48, 0x8c, 0x81, 0xed, 0x91, 0x3e, 0x6a, 0x0c, 0xc3, 0x1d, 0x96, 0x12, 0x38, 0x0c, 0xbc, 0x0d, 0x1c, 0x02, 0xf8, 0x3f, 0x80, 0x0d, 0x1c, 0x3e, 0x0b, 0x0c, 0x80, 0x0c, 0x1c, 0x00, 0x0b, 0x0c, 0xc3, 0x18, 0x1c, 0x00, 0x0a, 0x0c, 0x63, 0x10, 0x16, 0x00, 0x89, 0x3f, 0x1e, 0xe0, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xae, 0x0f, 0x00, 0x80, 0x84, 0x0a, 0xae, 0x87, 0x64, 0x86, 0x84, 0x08, 0x42, 0x42, 0x45, 0xe2, 0x1c, 0x07, 0x42}; C*[XDVI]XDVI.LNK;4+,( . / 4M - 0123KPWO 56dg7,Edg8Ik9GHJ$! LINK_VMSXDVI.COM $! $ ON ERROR THEN GOTO EXIT $ ON CONTROL_Y THEN GOTO EXIT $ OLD_VERIFY = f$verify (0) $ dummy=f$verify ('old_verify') $! $!##################### Customizing section ############################# $! $ MAY_USE_DECC = 1 $! $! The following settings might need customization to your environment: $ XDVI_DEFAULT_FONTRES = 300 $ XDVI_DEFAULT_FONTPATH = "TEX_PKDIR" $ XDVI_DEFAULT_VFPATH = "TEX_VFDIR" $ XDVI_DEFAULT_FIGPATH = " /SYS$DISK:[]/TEX_INPUTS:" $ XDVI_DEFAULT_PSHEADERPATH = "TEX_POSTSCRIPT:/TEX_INPUTS:/SYS$LOGIN:/ " $! $! Process command line parameters requesting optional features: $ ps_dps = "" $ ps_gs = "" $ IF f$edit(p1,"UPCASE") .eqs. "DPS" THEN ps_dps = "PSDPS" $ IF f$edit(p1,"UPCASE") .eqs. "GS" THEN ps_gs = "PSGS" $! $!##################################################################### $! $! Find out the environment we are compiling on. $! This section sets up the appropiate compiler switches and include paths, $! and defines architecture specific symbols used for identification purpose. $! The produced binary files are named with the ARCH_CC_P symbol preceding $! the file name extension, to prevent unwanted mixing of files created $! with different compiler / CPU architecture environments on heterogenous $! VMS clusters: $ IF F$GETSYI("HW_MODEL") .GE. 1024 $ THEN $ ARCH_NAME="Alpha" $ ARCH_PREF="AXP_" $ HAVE_DECC_VAX = 0 $ USE_DECC_VAX = 0 $ ARCH_CC_P = ARCH_PREF $ WRITE SYS$OUTPUT "Linking on Alpha AXP using DECC RTL" $ ELSE $ ARCH_NAME="VAX" $ ARCH_PREF="VAX_" $ IF F$TRNLNM("DECC$LIBRARY_INCLUDE") .NES. "" $ THEN $! DECC for VAX available (and maybe VAXC, too!) $ HAVE_DECC_VAX = 1 $ IF HAVE_DECC_VAX .AND. MAY_USE_DECC $ THEN $! We use DECC: $ USE_DECC_VAX = 1 $ ARCH_CC_P = "''ARCH_PREF'DECC_" $ ELSE $! We use VAXC: $ USE_DECC_VAX = 0 $ ARCH_CC_P = "''ARCH_PREF'VAXC_" $ ENDIF $ ELSE $! only VAXC available $ HAVE_DECC_VAX = 0 $ USE_DECC_VAX = 0 $ ARCH_CC_P = "''ARCH_PREF'VAXC_" $ ENDIF $ IF USE_DECC_VAX $ THEN $ WRITE SYS$OUTPUT "Linking on VAX using DECC RTL" $ ELSE $ WRITE SYS$OUTPUT "Linking on VAX using VAXC RTL" $ ENDIF $ ENDIF $ LDFLAGS = "" $! $!##################################################################### $! $! Set up the requested optional features: $ ps_options = "" $ ps_head = "" $ varobjs = "" $ IF ps_dps .EQS. "PSDPS" $ THEN $ ps_head = "PSHEADER" $ varobjs = varobjs + "PSDPS, " $ ENDIF $ IF ps_gs .EQS. "PSGS" $ THEN $ ps_head = "PSHEADER" $ varobjs = varobjs + "PSGS, " $ ENDIF $ IF ps_head .NES. "" $ THEN $ varobjs = varobjs + "PSHEADER," $ ENDIF $! $!##################################################################### $! $! Now, we are ready to `make' xdvi: $! $! Write the linker option file: $! COPY XAW3DVAX.OPT VMS_XDVI.'ARCH_CC_P'OPT $! OPEN/APPEND optfile VMS_XDVI.'ARCH_CC_P'OPT $ OPEN/NEW optfile VMS_XDVI.'ARCH_CC_P'OPT $ IF ps_dps .EQS. "PSDPS" $ THEN $ WRITE optfile "sys$share:xdps$dpsclientshr/share" $ WRITE optfile "sys$share:xdps$dpsbindingsshr/share" $ WRITE optfile "sys$share:xdps$dpslibshr/share" $ ENDIF $ WRITE optfile "sys$share:decw$xlibshr/share" $~ WRITE optfile "sys$share:decw$xtlibshrr5/share" $ IF (ARCH_NAME .EQS. "VAX") .AND. (.NOT. USE_DECC_VAX) $ THEN $ WRITE optfile "sys$share:vaxcrtl/share" $ option_file = "VMS_XDVI.''ARCH_CC_P'OPT" ! for linking SQUEEZE $ ELSE $ option_file = "nl:" ! for linking SQUEEZE $ ENDIF $ CLOSE optfile $! $! Final link step: $ LINK 'LDFLAGS' XDVI, - DVI_INIT, DVI_DRAW, - PSGS, - GF, PK, VF, - UTIL, FONT_OPEN, SPECIAL, - EVENTS, 'varobjs' VMS_XDVI.'ARCH_CC_P'OPT/OPTION $ DELETE/NOLOG VMS_XDVI.'ARCH_CC_P'OPT;* $! $EXIT: $ dummy=f$verify ('old_verify') $ EXIT *[XDVI]XDVI.RNH;1+,,.</ 4<; - 0@123KPWO=56 /Q7 /Q8 Ԭ_o9GHJ.! .! This is a RUNOFF source file that produces a VMS-style HELP library .! for the XDVI program. .! .! This file was created by hand-converting XDVI.MAN. The internal date .! in the XDVI.MAN file was "27 March 1990". If you improve this file, .! please let me know. Pete Siemsen, siemsen@usc.edu .! .! Merged with patchlevel 8.001 help file for VMS by Scott Allendorf. .! Added new switches for patchlevel 10. Scott Allendorf. .! Added new switches for patchlevel 11. Scott Allendorf. .! Added new switches for patchlevel 14. Scott Allendorf. .! Added new switches for patchlevel 16. Scott Allendorf. .! Updated for patchlevel 17. Scott Allendorf. .! Updated for patchlevel 18. Scott Allendorf. .! Updated for patchlevel 19. Christian Spieler. .! Updated for patchlevel 20. Christian Spieler. .! .NO PAGING .NO FLAGS ALL .RIGHT MARGIN 71 .LITERAL ! ! DO NOT EDIT THIS FILE. It was produced by passing a .RNH file through ! RUNOFF. Edit the .RNH file instead. ! .END LITERAL .LEFT MARGIN 1 .INDENT -1 1 XDVI .BREAK XDVI is a program which runs under the DECWindows system. It is used to preview DVI files, such as those produced by TeX and LaTeX. .SKIP XDVI has the capability of displaying the file reduced by various (integer) factors, and also has a "magnifying glass" which allows one to see a small part of the unshrunk image momentarily. .SKIP Before displaying any page or part thereof, XDVI checks to see if the DVI file has changed since the last time it was displayed. If this is the case, XDVI will reinitialize itself for the new DVI file. For this reason, exposing parts of the XDVI window while TeX is running should be avoided. This feature allows you to preview many versions of the same file while running XDVI only once. .SKIP XDVI can show PostScript specials by any of two methods. It will try first to use Display PostScript, then it will try to use Ghostscript to render the images. All of these options depend on additional software to work properly; moreover, some of them may not be compiled into this copy of XDVI. .SKIP For performance reasons, XDVI does not render PostScript specials in the magnifying glass. .SKIP Format: .SKIP .INDENT +3 XDVI [Options] dvi_file .INDENT -1 2 Options .BREAK In addition to specifying the DVI file (with or without the .DVI extension), XDVI supports the following command line options. If the option begins with a "+" instead of a "-", the option is restored to its default value. By default, these options can be set via the resource names given in the description of each option. .INDENT -1 3 + .BREAK + .SKIP Specifies the first page to show. If + is given without a number, the last page is assumed; the first page is the default. .INDENT -1 3 -allowshell .BREAK -allowshell .SKIP This option enables the shell escape in PostScript specials. (For security reasons, shell escapes are usually disabled.) This option should be rarely used; in particular it should not be used just to uncompress files: that function is done automatically if the file name ends in `_z' or `_gz'. Shell escapes are always turned off if the -safer option is used. .SKIP The resource name is ".allowShell". .INDENT -1 3 -altfont .BREAK -altfont .SKIP Declares a default font to use when the font in the DVI file cannot be found. This is useful, for example, with PostScript fonts. .SKIP The resource name is ".altFont". .INDENT -1 3 -background .BREAK -background .SKIP Determines the color of the background. Same as -bg. .SKIP The resource name is ".background". .INDENT -1 3 -bd .BREAK -bd .SKIP Determines the color of the window border. .SKIP The resource name is ".borderColor". .INDENT -1 3 -bg .BREAK -bg .SKIP Determines the color of the background. .SKIP The resource name is ".background". .INDENT -1 3 -bordercolor .BREAK -bordercolor .SKIP Same as -bd. .INDENT -1 3 -borderwidth .BREAK -borderwidth .SKIP Specifies the width of the border of the window. Same as -bw. .SKIP The resource name is ".borderWidth". .INDENT -1 3 -bw .BREAK -bw .SKIP Specifies the width of the border of the window. .SKIP The resource name is ".borderWidth". .INDENT -1 3 -copy .BREAK Always use the copy operation when writing characters to the display. This option may be necessary for correct operation on a color display, but overstrike characters will be incorrect. If greyscale anti-aliasing is in use, the -copy operation will disable the use of colorplanes and make overstrikes come out incorrectly. See also -thorough. .SKIP The resource name is ".copy". .INDENT -1 3 -cr .BREAK -cr .SKIP Determines the color of the cursor. The default is the color of the page border. .SKIP The resource name is ".cursorColor". .INDENT -1 3 -debug .BREAK -debug .SKIP If nonzero, prints additional debugging information on standard output. The bitmask should be given as a decimal number. The values of the bits are defined in the source file xdvi.h . .SKIP The resource name is ".debugLevel". .INDENT -1 3 -density .BREAK -density .SKIP Determines the density used when shrinking bitmaps for fonts. A higher value produces a lighter font. The default value is 40. .SKIP The resource name is ".densityPercent". .INDENT -1 3 -display .BREAK -display .SKIP Specifies the host, display, and screen to be used for displaying the DVI file. The display must be specified in the form node::display.screen. The default is obtained from the logical name "DECW$DISPLAY", which may be defined using the SET DISPLAY command. .INDENT8;+~XDVI.BAK, [XDVI]XDVI.RNH;1<` -1 3 -fg .BREAK -fg .SKIP Determines the color of the text (foreground). .SKIP The resource name is ".foreground". .INDENT -1 3 -foreground .BREAK -foreground .SKIP Same as -fg. .INDENT -1 3 -gamma .BREAK -gamma .SKIP Controls the interpolation of colors in the greyscale anti-aliasing color palette. The default value is 1.0. For 0 < gamma < 1, the fonts will be lighter (more like the background), and for gamma > 1, the fonts will be darker (more like the foreground). Negative values behave the same way, but use a slightly different algorithm. .SKIP The resource name is ".gamma". .INDENT -1 3 -geometry .BREAK -geometry .SKIP Specifies the initial geometry of the window. .SKIP The resource name is "*geometry". .INDENT -1 3 -gspalette .BREAK -gspalette .SKIP Specifies the palette to be used when using Ghostscript for rendering PostScript specials. Possible values are "Color", "Greyscale", and "Monochrome". The default is "Color". .SKIP The resource name is ".palette". .INDENT -1 3 -hl .BREAK -hl .SKIP Determines the color of the page border. The default is the foreground color. .SKIP The resource name is ".highlight". .INDENT -1 3 -hush .BREAK Causes XDVI to suppress all suppressible warnings. .SKIP The resource name is ".Hush". .INDENT -1 3 -hushchars .BREAK Causes XDVI to suppress warnings about references to characters which are not defined in the font. .SKIP The resource name is ".hushLostChars". .INDENT -1 3 -hushchecksums .BREAK -hushchecksums .SKIP Causes XDVI to supress warnings about checksum mismatches between the DVI file and the font file. .SKIP The resource name is ".hushChecksums". .INDENT -1 3 -hushspecials .BREAK Causes XDVI to suppress warnings about \special strings which it cannot process. .SKIP The resource name is ".hushSpecials". .INDENT -1 3 -icongeometry .BREAK -icongeometry .SKIP Specifies the initial position for the icon. .SKIP The resource name is ".iconGeometry". .INDENT -1 3 -iconic .BREAK -iconic .SKIP Causes the XDVI window to start in the iconic state. The default is to start with the window open. .SKIP The resource name is ".iconic". .INDENT -1 3 -interpreter .BREAK -interpreter .SKIP Use as the Ghostscript interpreter. By default it uses "gs". .SKIP The resource name is ".interpreter". .INDENT -1 3 -keep .BREAK -keep .SKIP Sets a flag to indicate that XDVI should not move to the home position when moving to a new page. See also `k' under the Keystrokes help entry. .SKIP The resource name is ".keepPosition". .INDENT -1 3 -l .BREAK Causes the names of the fonts used to be listed. .SKIP The resource name is ".listFonts". .INDENT -1 3 -margins .BREAK -margins .SKIP Specifies the size of both the top and side margins. This should be a decimal number optionally followed by "cm", e.g., 1.5 or 3cm, giving a measurement in inches or centimeters. XDVI determines the "home" position of the page within the window as follows. If the entire page fits in the window, then the margin settings are ignored. If, even after removing the margins from the left, right, top, and bottom, the page still cannot fit in the window, then the page is put in the window such that the top and left margins are hidden, and presumably the upper left-hand corner of the text on the page will be in the upper left-hand corner of the window. Otherwise, the text is centered in the window. See also -sidemargin, -topmargin under the Options help entry, and `M' under the Keystrokes help entry. .SKIP The resource name is ".Margin". .INDENT -1 3 -mfmode .BREAK -mfmode .SKIP Specifies a `mode-def' string, which can be used in searching for fonts (see also the `Logical_Names' entry). It is also passed to METAFONT during automatic creation of fonts. .SKIP The resource name is ".mfMode" .INDENT -1 3 -mgs[n] .BREAK -mgs[n] .SKIP Specifies the size of the window to be used for the "magnifying glass" for Button n. The size may be given as an integer (indicating that the magnifying glass is to be square), or it may be given in the form WxH. See the Mouse_Actions section. Defaults are 200x150, 400x250, 700x500, 1000x800, and 1200x1200. .SKIP The resource name is ".magnifierSize[n]". .INDENT -1 3 -mgs .BREAK -mgs .SKIP Same as -mgs1. .INDENT -1 3 -nodps .BREAK -nodps .SKIP Inhibits the use of Display PostScript for displaying PostScript specials. Other forms of PostScript emulation, if installed, will be used instead. (For this option, the logic of the corresponding resource is reversed: `-nodps' corresponds to `dps:off'; `+nodps' to `dps:on'. .SKIP The resource name is ".dps". .INDENT -1 3 -noghostscript .BREAK -noghostscript .SKIP Inhibits the use of GhostScript for displaying PostScript specials. Note that the logic of the corresponding resource is reversed: `-noghostscript' corresponds to `ghostscript:off'; `+noghostscript' to `ghostscript:on'. .SKIP The resource name is ".ghostscript". .INDENT -1 3 -nogrey .BREAK -nogrey .SKIP Turns off the use of greyscale anti-aliasing when printing shrunken bitmaps. In this case, the logic of the corresponding resource is the reverse: -nogrey corresponds to grey:off; +nogrey to grey:on. See also 'G' under the Keystrokes help entry. .SKIP The resource name is ".grey". .INDENT -1 3 -nogssafer .BREAK -nogssafer .SKIP Normally, if Ghostscript is used to render PostScript specials, the Ghostscript interpreter is run with the option -dSAFER. The -nogssafer option runs Ghostscript without -dSAFER. The `-dSAFER' option in Ghostscript disables PostScript operators such as `deletefile' to prevent possibly malicious PostScript programs from having any effect. If the `-safer' option is specified, then this option has no effect; in that case Ghostscript is always run with -dSAFER. (For the `-nogssafer' option, the logic of the corresponding resource is reversed: `-nogssafer' corresponds to `gsSafer:off'; `+nogssafer' to `gsSafer:on'.) .SKIP The resource name is ".gsSafer". .INDENT -1 3 -nomakepk .BREAK -nomakepk .SKIP Turns off the automatic generation of missing font files that cannot be found by other means. For this option, the logic of the corresponding resource is reversed: -nomakepk corresponds to makePK:off; +nomakepk to makePK:on. .SKIP The resource name is ".makePK". .INDENT -1 3 -nopostscript .BREAK -nopostscipt .SKIP Turns off rendering of PostScript specials. Bounding boxes, if known, will be displayed instead. This option can also be toggled with the 'v' keystroke. For this option, the logic of the corresponding resource is reversed: -nopostscript corresponds to postscipt:off; +nopostscript to postscript:on. .SKIP The resource name is ".postscript". .INDENT -1 3 -noscan .BREAK -noscan .SKIP Normally, when PostScript is turned on, XDVI will do a preliminary scan of the dvi file, in order to send any necessary header files before sending the PostScript code that requires them. This option turns off such prescanning. (It will be automatically be turned back on if XDVI detects any specials that require headers.) Note that for the -noscan option, the logic of the corresponding resource is reversed: -noscan corresponds to prescan:off; +noscan to prescan:on. .SKIP The resource name is ".prescan". .INDENT -1 3 -offsets .BREAK -offsets .SKIP Specifies the size of both the horizontal and vertical offsets of the output on the page. This should be a decimal number optionally followed by "cm", e.g., 1.5 or 3cm, giving a measurement in inches or centimeters. By decree of the Stanford TeX Project, the default TeX page origin is always 1 inch over and down from the top-left page corner, even when non-American paper sizes are used. Therefore, the default offsets are 1.0 inch. See also -xoffset and -yoffset. .SKIP The resource name is ".Offset". .INDENT -1 3 -p .BREAK -p .SKIP Defines the size of the fonts to use, in pixels per inch. The default value is 300. .SKIP The resource name is ".pixelsPerInch". .INDENT -1 3 -paper .BREAK -paper .SKIP Specifies the size of the printed page. This may be of the form WxH (or WxHcm), where W is the width in inches (or cm) and H is the height in inches (or cm), respectively. There are also synonyms which may be used: us (8.5x11), usr (11x8.5), legal (8.5x14), foolscap (13.5x17), as well as the ISO sizes a1-a7, b1-b7, c1-c7, a1r-a7r (a1-a7 rotated), etc. The default size is 8.5 x 11 inches. .SKIP The resource name is ".paper". .INDENT -1 3 -rv .BREAK Causes the page to be displayed with white characters on a black background, instead of vice versa. .SKIP The resource name is ".reverseVideo". .INDENT -1 3 -s .BREAK -s .SKIP Defines the initial shrink factor. The default value is 3. .SKIP The resource name is ".shrinkFactor". .INDENT -1 3 -safer .BREAK -safer .SKIP This option turns on all available security options; it is designed for use when XDVI is called by a browser that obtains a dvi or TeX file from another site. In the present case, this option selects `+nogssafer' and `+allowshell'. (This option is accepted but has no effect, if XDVI was compiled without support for Postscript specials.) .SKIP The resource name is ".safer". .INDENT -1 3 -sidemargin .BREAK -sidemargin .SKIP Specifies the side margin (see -margins). .SKIP The resource name is ".sideMargin". .INDENT -1 3 -thorough .BREAK XDVI will usually try to ensure that overstrike characters (e.g., \notin) are printed correctly. On monochrome displays, this is always possible with one logical operation, either AND or OR. On color displays, however, this may take two operations, one to set the appropriate bits and one to clear other bits. If this is the case, then by default XDVI will instead use the copy operation, which does not handle overstriking correctly. The -thorough option chooses the slower but more correct choice. See also -copy. .SKIP The resource name is ".thorough". .INDENT -1 3 -topmargin .BREAK -topmargin .SKIP Specifies the top and bottom margins (see -margins). .SKIP The resource name is ".topMargin". .INDENT -1 3 -version .BREAK -version .SKIP Print information on the version of XDVI. .INDENT -1 3 -xoffset .BREAK -xoffset .SKIP Specifies the size of the horizontal offset of the output on the page. See -offsets. .SKIP The resource name is ".xOffset". .INDENT -1 3 -yoffset .BREAK -yoffset .SKIP Specifies the size of the vertical offset of the output on the page. See -offsets. .SKIP The resource name is ".yOffset". .INDENT -1 2 Keystrokes .BREAK XDVI recognizes the following keystrokes when typed in its window. Each may optionally be preceded by a (positive or negative) number, whose interpretation will depend on the particular keystroke. Note that the keystrokes are case sensitive. .INDENT -1 3 q .BREAK Quits the program. Control-C, control-D, and control-Z will do this, too. .INDENT -1 3 n .BREAK Moves to the next page (or to the nth next page if a number is given). Synonyms are `f', Space, Return, Line Feed, and . .INDENT -1 3 p .BREAK Moves to the previous page (or back n pages). Synonyms are `b', control-H, Delete, and . .INDENT -1 3 g .BREAK Moves to the page with the given number. Initially, the first page is assumed to be page number 1, but this can be changed with the `P' keystroke. If no page number is given, then it goes to the last page. .INDENT -1 3 P .BREAK "This is page number n." This can be used to make the `g' keystroke refer to actual page numbers instead of absolute page numbers. .INDENT -1 3 Control-L .BREAK Redisplays the current page. .INDENT -1 3 ^ .BREAK Move to the "home" position of the page. This is normally the upper left-hand corner of the page, depending on the margins as described in the -margins option. .INDENT -1 3 u .BREAK Moves up two thirds of a window-full. The key is a synonym for this keystroke. .INDENT -1 3 d .BREAK Moves down two thirds of a window-full. The key is a synonym for this keystroke. .INDENT -1 3 l .BREAK Moves left two thirds of a window-full. The key is a synonym for this keystroke. .INDENT -1 3 r .BREAK Moves right two thirds of a window-full. The key is a synonym for this keystroke. .INDENT -1 3 c .BREAK Moves the page so that the point currently beneath the cursor is moved to the middle of the window. It also (gasp!) warps the cursor to the same place. .INDENT -1 3 M .BREAK Sets the margins so that the point currently under the cursor is the upper left-hand corner of the text in the page. Note that this command itself does not move the image at all. For details on how the margins are used, see the -margins option. .INDENT -1 3 s .BREAK Changes the shrink factor to the given number. If no number is given, the smallest factor that makes the entire page fit in the window will be used. (Margins are ignored in this computation.) .INDENT -1 3 S .BREAK Sets the density factor to be used when shrinking bitmaps. This should be a number between 0 and 100; higher numbers produce lighter characters. If greyscaling mode is in effect, this changes the value of gamma instead. The new value of gamma is the given number divided by 100; negative values are allowed. .INDENT -1 3 R .BREAK Forces the DVI file to be reread. This allows you to preview many versions of the same file while running XDVI only once. .INDENT -1 3 k .BREAK Normally when XDVI switches pages, it moves to the home position as well. The `k' keystroke toggles a `keep-position' flag which, when set, will keep the same position when moving between pages. Also `0k' and `1k' clear and set this flag, respectively. See also the -keep option. .INDENT -1 3 G .BREAK The key toggles the use of greyscale anti-aliasing for displaying shrunken bitmaps. In addition, the key sequences `0G' and `1G' clear and set this flag, respectively. See also the -nogrey option. .INDENT -1 3 v .BREAK This key toggles the rendering of PostScript specials. If rendering is turned off, then bounding boxes are displayed when available. In addition, the key sequences `0v' and `1v' clear and set this flag, respectively. See also the -nopostscript option. .INDENT -1 2 Mouse_Actions .BREAK If the shrink factor is set to any number other than one, then clicking any mouse button will pop up a "magnifying glass" which shows the unshrunk image in the vicinity of the mouse click. This subwindow disappears when the mouse button is released. Different mouse buttons produce different sized windows, as indicated by the -mgs option. Moving the cursor while holding the button down will move the magnifying glass. .SKIP Also, the scrollbars (if present) behave in the standard X Window way: pushing Button 2 in a scrollbar moves the top or left edge of the scrollbar to that point and optionally drags it; pushing Button 1 moves the image up or right by an amount equal to the distance from the button press to the upper left-hand corner of the window; pushing Button 3 moves the image down or left by the same amount. Note that this is different than the way DECWindows normally defines the actions of the mouse buttons in scrollbars. .INDENT -1 2 Logical_Names .BREAK Some logical names can be defined to override the values defined when XDVI was compiled. .INDENT -1 3 DECW$DISPLAY .BREAK Unless the -display option is used on the command line, XDVI uses the logical name "DECW$DISPLAY" to specify which bit map display terminal to use. This logical name may be defined with the SET DISPLAY command. .INDENT -1 3 XDVIFONTS .BREAK The logical name "XDVIFONTS" determines the directory path(s) searched for fonts in the following manner. The string consists of one or more strings separated by slashes. In each such string, the substring "%f" is changed to the font name; "%d" is changed to the magnification; and "%p" is changed to the font file format ("pk" or "gf"). If no "%f" appears in the string, then the string ":%f.%d%p" is added on the end. For example, if the string is "TEX_FONTS" and the font is cmr10 at 300 dots per inch, then XDVI searches for TEX_FONTS:CMR10.300PK and TEX_FONTS:CMR10.300GF, in that order. An extra slash anywhere in the the "XDVIFONTS" logical name causes the system default directories to be tried at that point. If the font is not found in the desired size, then XDVI will invoke Metafont to create the font in the correct size. Failing that, it will try to find the nearest size. If the font cannot be found at all, then XDVI will try to vary the point size of the font (within a certain range), and if this fails, then it will use the font specified as the alternate font (cf. -altfont). .SKIP In addition, a "%F" specifier is available; it is a synonym for "%f", but it does not inhibit putting the string ":%f.%d%p" at the end. A "%b" specifier is available; it is converted to the current resolution being used (i.e., the value of the -p parameter or the .pixelsperinch resource). And finally, the string "%m" will be changed to the `mode-def' specified in the -mfmode argument or the .mfMode resource. .SKIP For compatibility with some versions of TeX, you may also use the logical name "TEXFONTS" in place of "XDVIFONTS", although in that case the string should not include any "%" specifiers. The reason for recognizing "TEXFONTS" is that certain versions of TeX also support the convention regarding an extra slash in the font path; therefore, users who create their own fonts can put both their .TFM and raster file in the same directory and do .SKIP .LITERAL $ DEFINE TEXFONTS "/MFDIR" or $ DEFINE TEXFONTS "MFDIR/" .END LITERAL .SKIP in order to get TeX and XDVI to search their directory in addition to the system standard directories. The "XDVIFONTS" logical name overrides the "TEXFONTS" logical name, so that on those sites where "TEXFONTS" must be set explicitly, and therefore this feature is not useful, the "XDVIFONTS" logical name may be set to an empty string to cause XDVI to ignore "TEXFONTS". .SKIP XDVI also recognizes the "PKFONTS" and "TEXPKS" logical names, which are checked after "XDVIFONTS" but before "TEXFONTS". .INDENT -1 3 XDVIMAKEPK .BREAK The script used to create fonts may be controlled by the logical name (or, if no logical name present, the DCL symbol) XDVIMAKEPK. Usually this variable would be set to the name of the script. In that case the script is called with the following options: (1) the font name, (2) the requested resolution in dots per inch, (3) the base resolution in dots per inch, and (4) a (possibly more accurate) indication of the magnification using magsteps (if possible). Optionally, the variable may include specifiers "%n", "%d", "%b", and "%m". to indicate each of the above arguments, respectively. It is possible to specify the `mode-def' that Metafont is to use when creating the fonts. This is specified by the `-mfmode' argument on the command line, or the `mfMode' resource. If a "%o" specifier appears in the XDVIMAKEPK string, it will be changed to the given `mode-def' name, or to the string "default" if no mode-def was given. If no "%o" specifier appears and a `mode-def' was given, then the mode will be appended to the end the string. This is compatible with the font creation mechanism used in DVIPS. By default, XDVIMAKEPK equals to "MakeTeXPK". .SKIP For use on VMS, this default is not sufficiant. You have to specify a string including the "%..." specifiers, which must be enclosed by double quotes to ensure case preservation, e.g: .BREAK .LITERAL XDVIMAKEPK=="@TEX_EXE:MAKETEXPK ""%n"" ""%d"" ""%b"" ""%m"" ""%o""" .END LITERAL .INDENT -1 3 XDVISIZES .BREAK The logical name "XDVISIZES" may be set to indicate which sizes of fonts are available. It should consists of a list of numbers separated by slashes. If the list begins with a slash, the system default sizes are used, as well. Sizes are expressed in dots per inch and must be integers. The current default set of sizes is 300/329/360/432/518/622/746. XDVI will also try the actual size of the font before trying any of the given sizes. .INDENT -1 3 XDVIVFS .BREAK Virtual fonts are supported, although XDVI does not have any built-in fonts to which they can refer. The search path for .VF files can be specified with the "XDVIVFS" logical name in a similar manner to that for the "XDVIFONTS" logical name. XDVI will also check the "VFFONTS" logical name if the "XDVIFONTS" logical name is not defined. Virtual fonts are searched for immediately after looking for the font as a normal font in the exact size specified. .INDENT -1 3 XDVIFIGS-XDVIHEADERS .BREAK The XDVIFIGS and XDVIHEADERS logical names determine the search strategy for PostScript figure files and header files, respectively. First, XDVI will look in the directory containing the dvi file. If no file is found, then it will look in the directories given by the XDVIFIGS or XDVIHEADERS logical names. for PostScript figure files and header files, respectively. These variables should contain lists of directories separated by slashes. As usual, an extra slash anywhere in either of these paths causes the default compiled-in list to be checked at that point in the path list. Customarily, XDVIFIGS will be the same as the TeX input directory. If XDVIFIGS or XDVIHEADERS is not set, then XDVI will also try the TEXINPUTS or HEADERPATH logical names; this is for compatibility with dvips (1). .SKIP There are two exceptions to the above strategy. First, if the file name contains a full path specification, then the file name is treated as an absolute path, and is searched for as given, without using the above strategy. Or, if the file name begins with a backtick ( ` ), then the following characters give a shell command (often zcat) which is executed; its standard output is then sent to be interpreted as PostScript. Note that there is some potential for security problems here; see the -allowshell command-line option. It is better to use compressed files directly (see below). .SKIP If a file name is given (as opposed to a shell command), if that file name ends in "_Z" or "_gz", and if the first two bytes of the file indicate that it was compressed with UNIX compress or gzip, respectively, then the file is first uncompressed with "uncompress -c" or "gunzip -c", respectively. This is preferred over using a backtick to call the command directly, since you do not have to specify `-allowshell' and since it allows for path searching. .INDENT -1 2 Resource_Names .BREAK All of the command line options may be set via the resource names given in the descriptions of the options. This may be used to define a specific set of options as the default each time you run XDVI. To make use of this feature, create a file named DECW$XDEFAULTS.DAT in the same directory as the rest of your DECW*.DAT files. Include in this file the resource names and arguments of each of the options you wish to specify. For example: .SKIP .LITERAL XDvi.copy: off XDvi.thorough: on XDvi.shrinkFactor: 2 XDvi.Margin: 0.95 XDvi*geometry: 1015x750+3+25 .END LITERAL .SKIP When XDVI is invoked, it would behave as if it had been invoked with the following command: .SKIP .LITERAL XDVI +copy -thorough -s 2 -margins 0.95 -geometry 1015x750+3+25 dvifile .END LITERAL .SKIP Specifying options on the command line will override any options specified via resource names in the DECW$XDEFAULTS.DAT file. .INDENT -1 2 Limitations .BREAK XDVI accepts many but not all types of PostScript specials accepted by DVIPS. It does accept most specials generated by `epsf' and `psfig', for example. It does not, however, support `bop-hook', nor does it do the ``NEAT'' or rotated ``A'' example in the DVIPS manual. These restrictions are due to the design of XDVI; in all likelihood they will always remain. LaTeX2e color and rotation specials are not currently supported. .INDENT -1 2 Authors .BREAK .LITERAL Eric Cooper, CMU, did a version for direct output to a QVSS. Modified for X by Bob Scheifler, MIT Laboratory for Computer Science. Modified for X11 by Mark Eichin, MIT SIPB. Modified for VMS and DECWindows by Scott Allendorf, University of Iowa. Additional enhancements by many others. .END LITERAL a:j z S*H;1Sm]-r#-g^EoNg g#9$Kb@x_-al{6I#k\ I'S{tOFjTUOQo bs)wT>?knnrZX qYO0Y;!UkI6H=kGjH[/S T^1UrFG@rC > ])% @C1wK9n%><,: DAB bV_D z8N)< YdA POlb-:tdM=&U&kK N PU:5 Q/$!6FQ/36O+.G3 zE71UL;\_Z vHF&hsb3&NN3-YC\Ts\0  %S*'h`h6_>;$zc~L6S;8-85*1CZ3Jw9X DY@BB>)F=!^B{ p U@1z0&qH)(AKi!>ji.ub^G<?1b*%|'v663-7h:7H^ y=pES]p^h;2mf!4D|[[4P\ : p?we1{=h_E %cR)2-k!yti'jRmJz]!+i/;#93 g$:4qtaY ;pEyod/s~}5P ] xS[; N6@Id~}v1dufQ /+}|.98=r^J~UKFA.LjKwW+2-V5x+ Nz^IMZE[:;N0.@-48-ejLhHYV|Njr)l;`l ;*tcr\5P%XCNrQ!!EY_$K  _a:0dP 3!hC2ynG  >D_ v*uaWX`&re]-G\Hcm[RqSNp6l*), CaZ( KJ :?14ngPDFq'[u$2l|odY8pl]+mPA@b7hn~y$sgid>(Z$tFaD] )[$ e[|Tjq3o9%kX 4\rM]>@[@YzD6@QULG(OH@R{S@0 #tR]n92E:1 E^lu Z ,mrraa=5OI,cjJ>7*cNYT1V\SML kdj e Y%yW8BRgj;/{ W,$={crT~vrlf!4en_ "h\HQPl*8R"}~1+^z?5#1fpz8!uM+[ .k9@]6uQ 2oR]X3eAH')4Kz^Y_dva:I`)j]DG:GLQO-m1!^1GBTT+G5fgHf Oyg2k_;+ S[v^~;31WHg MOL_2~7gzddK6m;_5P@Va:&y@bvaplrzo4L1g~{JHDmn}EELIjs$$EfJ:$ik0dnEHY0 *ng+nqZJKlewS< (>%0`GN[LF ykj0T";"b&,m+;]=T>W?vi/kQW M14CaA+AIc4)VCI-b^ JX[m\u- iGg iRitjo B*'_rKLA@ OCd%A Y LF[G537#- >ilfj/sMc)7%  wk#3vt`&CyZM NI)vnHp H; bV > S&)"gt~4=(eM*, xW<-da})k+mV,m_IMD7cz= $[/^qc1'"3a#dH{4cN?o}CWB*H]`!B jk*>tLyZN[QL9eWw|##+-+vhl) w_$0&'  P+eoUL S_/$@FRXBkG_X>P^]<\Mr><5eQ}B0?*LlJ)4ml6A4[^9=l[sl)z!,qI/cGyH{; 3jWhXnI9F:_po5>I;f !k^E1=o8Qcjg~/tFziV ;I/UFA#>'^U $m 0F``TG(g/J[SdMlq/0UoJv2c (@XH'ax\v^(T6jH8#IU~BlE#n0#7'2xI%\5 TD;.8Y[lU1 7N neVA~Gn[i, Wna P#~Sx)MtYJ"VTm,8Ut(G9f}'NPJGyXG` TJ#vBx -L-vBW/>N  #gUXuxIM >:H_Bl@M>* TU.dB5!9XAr(k\[L$VM{8'8;BM }U[kej0h?XRREX- "]2l>#| #gn`JZ|O A~iYLJz&*JJA )C AOFQY]K]b%KqMqY 8&=!*qwm{BaR c>mU AR&\r)~uF7s=Lv|"Ms0#Lst^Y^BFH.E)/6&,mE_v+e8x84oL EM5N] ,4) o;,cT~4#(yVK$.+F,% )KYqNvvX)(_)@Rw,d\]km9u u4# `P[d %,bb5-\_xe.Td(t# Ulxy  ; Ioq,{xy3R99ED/$ZDkHH>miXYmR8N PH*|?hB@CN  i S'6o8 4'b}h+nLHMH"GFFDdO_ ,UbZ:J'."Oa`k$?c9YIu{Z^]+^LQ(VCzk Zr#7+1#|/8:n*:|eQ1|/Ews _QCGRcDoF|pQG79s0`[EyQx9%C r-v0w/$q1 [S)$$'V(u>F1K!u4#@@g1L%C+w3_DW![69[/:;&DdS@UH?FR(.;'{L~rtw*VA[NXo_}F ~oEX8+q=;qK{y1+#sE3bw*%"};5\H GOxmoT Wz6(}nh^F#"&#B1+$*+CB:K ]\Rl2&('F I!aatsr#aSJEcnn41i1;=Ul22!/%:2;o8!&}#c!tLclibj`kdb`ilV pIUvuayH|a~O9!;4}!9/x JTS$<#+?5T+H2t=*5`u< \YSor\DnH]+ny2@Ho@S7yg"6#%.SOmP/;Ix^SVu'0,kHbyrbH^}:b9 !n.m>x='DjL b_*^ p^}d16-XS.D@:m1X'F`GG @bGZ#}kZ xZJc4O Ho5zM 4|nh=to]@TlT6wl +y D|mg1-s)"eVo m G/68#'-1nBX=ei'8 Gox@ 9DgI@9!8oN & &6p !v<: oF]1/);TuK#@ 0s&\R$VGYv5G{otqJ2)^#Q TmoNM&e0(# 9( kK&;`&\G^BV" 4ZYQs|T: o&DUBof<.8tp!$`Cw1(du%#*?4bg@5m'-Hu3a<|TZBVpFp" w2Q6-.i9kh{,\Bs{&b?ix2k[ bY&xi!n4Q#kmI%EWN6.9MZ^"=(,JA YcrsnEH\TEL Jb+ZctC*Rm~JM&r@ IXtfU G U GV,G)lqZ?jM7'BKZ;K=,-j"T8L&`o5"-$RLMh4[BOKu0PGwU-SLY9~,c7 e]V)':4:|o)EGcp4hELO\/VJi6% c^-GBT!oz^G8R/=^!5UYoOkdm$xpQ&c[ Z5ZUH7FI2/|jy=%X@V6'y76*tl )ei.1 c$'"1r58<<8`o &rHS!'+UXBU[Q\w]Xq?4^GTTRoB1<8EEy` *(@HfCd"5}s%>1$>Y!dm+0-JCvk/ De|A8V"PVKTMORW4D}j/z, ` \EITml9M ,5 TLsPN k_Y6+GyX-oR:@7!?J5tI8(obo{KW5mgk5$3+hz/Jg(NKUU@rgXBS MA}SHHD=YA*M1Uw~}DG 1mGQ,?wvE&y_Hy: `G hF sM^R:cVq 'HC%7`FG[r&3g1}yIQmABdV6\=R-FGH9]O`l0j W_:B*-, GRu'0[dwr5ON\UDWm6XGu>3kULsbx4n7?/NV MZRuEAKRf5wuSGL\ %*,]Y >?#,4O/88-g0Kdu* gFcIM\BZ3a>ic OI _ [YP(qUENP"@Dp 5zsunT!6&LIx:LHN4TK@?Hg @FBS+j vMfr~>syo-]FG\,ucu4rV fB Xic,Mg NVKN?5R(`H]p@-C\^ RX>uQj}n9KNN m8 '?ENAP *h^Ifh?s ^?)s.7fiEH B~H#~gB<6PC[[! 1w$xqx*Mw>s5 78 T2zoRYK/JS\vdV.LOgqNurv:c$KQD, FMHG(Fh$@YG{3os~1lyk=Z&> XC^  C703;:  ZHN;z-~I4xs hZo &8<`T?'DVultb,:lP0$_E38Q@eVsxsFTGtQZqptFd<$ Jak)FIO:l=* P 4= cvB$$=F z3.f|pHf)e pS4:OV^C>NXnWNAWy>MkHHVNBS}YIFPLQ>%4nb:0;ki -OD(ww?-LG&:kMFUFsy!%Ozm[JW2U&B&3)b*X@;AU IYM_D@L+g{3nr;@[@R3%)rYB ADDA<m2^|[E#btwV8lQ,.DMKB/U@GJvINQ\X$xB6'+ IQS$ TdNF;)!.k8&z6e]EN}@]XSd HYo[ 3]x]EOoU 0{mMTvIG[.Sa"7)EQm\|A4jksS u1uA6n Za:p?R7xAGqe?-S6> EL^ HB:{9 ~ A[~B-/]LZBeazO tHo&[d}X 1 >&eDFD Akek[v(O_O %CDb@5Fz;aL.=wsbeh~b)Og$u,eYT) }sNMG$vB9= K!Fg VMWV$;o?.m Y.O JW:v)#: SkRGAVDC9 il3  LD FxBkpOJ7o)MB{ke *XI>>[W2> !3ShMx@=# > e ]ADl `D@> ' BPXS7l~7bQ I  rmeV$ T[w(j Z/SV*ETN'_oi"}f J1fG6Yo|%kHdCr*'\hcj!zt~:vJ  Q#?>P(/`F1OF}kHe7-'`_pESA:J) bPZ^SI=[ArxN:ubO<&enS"olF ZQ*M+H*YLPM~h<= '3&D77mr($aHqy`gSO)RT,QUH s\N8 d#A E:C"3M[4'BM^~z CCZN}C VU-WWY ZIO9U)rE^GVie! u[TAR-$In}7?yv>VZ- xtGE $KX[ D(rQVC5M+#Xb\)edL\]X/rBF>!dV{}j&U Ufj5 F(N( SV9!*PGIfDE-M0op2CrbPovwKLNLG T*yNUI^,EQN7HsEAzNv A ?0*UCr[- T,NU-D CY$fziu$1Go~OCSRX6BOPEZr_ON]4 ~$;6rTRZe%A]J5qo 'tobGV|Fg&6(`& Vvg' RGQXCGLDDUW[y_D0lJZ NKQ1yc"|w5+AF q\k.!T4upmwFWO6FR-pKdOC2)|=Jn NFV13II^\["jl^LOO 30B6vaV d~\:%V@ o]a 0 X"G"xa _*Su,NBJKTQ'9Mjg53lIE_K_BpRHFS5CNQCy\)tOj]h\Xyu%b KQRH2`*QV; ^!zFF{BE e;qZ$1mO=&iA~=<+?Q,W./ B,"+VC`=IQwYP!<_KGEA\LcUDFw|mP P$QJ7Q/0cRD\%qjghVEqq;|^n} O5avec /| YLU]RF.y;D)t6kjwt+}+;4|9a8bW;-7Q#`GGM]ZJ4{J\uq_P|8XevM-K#Z47G)VB&xe n)dMLPYSR*z(2of:!)e,xGM55 YXLO L+ 8g,&LGbHQEI%,6mzm 18*";0ah."$;*Y"O@%<'a`goxjSc%NJGnD{6CPLezn,66)ic~{& =fn9s3~~bdr3$G71PgE%#D =b 74`Chn r$s /c9j. @HC>pFC|^=o'*M8!gzs^Y/8Pv~zJyc}0b3&`(b2i[< IGm:6xVnQ BGbldln~qWJaL$%!0bE[o 1$ }X%5vB>#r-P "c ku6S&j2y6i-% N1@>Bh}Q!ljo6 1 +o-4Y^|@!v #;=ulrBVleI> d2xp7j0uo+O<- k6EPf=bK7!x Uva [kK_,dURN AyVNQVE$VB1yl2^9 (DJx0= 3nyQ?nOPtAaXfe#JjH,Ef@Q;Y\f+W]r!fEdiU l T[p)/gFdQ;d&2IQ O}UY\}u8*C;tH Xt, 0Ei XVOS~1\F~9X];`l"]OIDdM B6T**  F" IJ=;t+GX?oU$:_DMMMmDbi_[A`]2PNB^GGJ\LBrst`-5q<-hDKV;4g3PFDBD4ruf1fB ^TE~{ex3aQO&:,"!s?"i!FX)(&=X.W,n[Q ~mWJ W? KS{9u!^#4LL I%vU:'z_ BIfp :zionF@Yrolb5UHIdsG][)i Td3{J(.=,/3l0|+2,~#+R^r .:7"H+pt$ F1'9}*G *KX8vr~ B;4h*FSFi#?8o9vYO Wb`kW|tU{>Y !NCb`VoKJt;AJ?M}%sE,IAC_KRF1>fiu4iJ'!j*H!^(&Mc`!0-5:8\W."{s*&n M+G8xZ}t'9s+zUpe~Jwu=;*piI"twrC|~6<4S;)73"h"{-u2ER 983Zpywr,s J2)0% HqP-&;JnsmTdla39oOzI}nT&;qo k5<}BVidOqjF8hG]Jx!}q :W)*= :.z]|2!^<4-k n{e8d7'<'95VE(%4Mli$"x&1z*weeMQFAz6T#;(/bQ' ER3](f1j m#nxy:$`Rg3fl0~9 1cf''w^ nkoj< 9 (7Ts,&/Y) 9|:fO5U9y 'cq G %*)\kelSi lN!7&3;*d3}sp0"\cm^fuCbB<z3$umcy)_& CHIe6H@o"zX(XinziI$xS`skM'48eH Pv&q2wv/!s?x~bjjqaTv.e2djdx J`ifC=iw4Xfn'T;);.>^UFmdBq%h*}/$`3__DC+m-k0}H F8zOm)L3CM T s9Q RcEZ%L [,:kse{&/u?/b0<66=[ {h(Pm5 'R$I#a!?|2(/:w"4E)d@\}1'Zk*_.uCwv no9\Srzoaaa9C1c`Ip4O"`2}J;jx}a5y_L~~-k'x!^&+zjq+ @{GS 8 5 lqJ9[,hKMMHm;KR-BDZd `LXz6; @BA`WUAIvx*s%2zcD"v6iKoxa)EYj _};;jOg)x 2sHXc T{NL,4Ly56RU\D`04Y Q XU_K ZN#]0B )]W]C BSuO4b"gV8qPX}sG=A 2Tx EXT7d[O  ~a0z.+LqmD>tOr8fC}S QEiS=bww1obcFXQa$ N U$02s@q0.ycrev/Fu[2Yc$/ JORToa jy_H oeoxA0-V* J;N^9J }w:daUI2qde8H?z;/)7[[VNf-F"2Vg`@BNmt%NsO+ug| ?*kpD E%ZIcIg1`#@`09&?@$8B^cj`V}s,G`"o# AGu"{31*:+#~TYWSE+mnD~z\SKRfWUc3,::pOMXx 0Mm+XHx LDI R|OtB+ n8sJQDioa* akt*QDcl7i-<kOxAUPShHEKJ$:B I R.[H*5xN Ow61_MZ^y|RP*Eht#X%D los[YIGuaKA; I,X!PCRBA9oglCSB8#S;7&e U t6S+,1uBSehrwv6. (l'4+ t;n9AFlpvYFh BV t%57hy.3?`RyoCs>[$ex[P@r z*PjAa['J9O_h+N&w2,= WQ]ES4c l5&t +NhWT\WNTZu1Nn[py{9EgyB#,J Hn A.ahhLIISq(rbZMVe'|12=i=M[6etHBzUcRY nok<#{V=O_NTR +s+z]K >SOErg 612t1xVCbW i D6w^@iBUOFxpsHAK5q)@&+#%>#8e 9YSFEt3@Q1UHRU$w5OUZ"?TN%M QOb),$i}16u4c;]=r"n-5QOk ntrNVhJaT#K@ U=VJ Ob}CTOxd)eM/9 8tH+{BU2\WCy,KZcEYB uNfg{^c884/tlv) LblpO,t`LDUz?XMMt7@zW 2S;^$ki# m=.--7.&.U %rl0,4PLht [=OH']zMj: *a .`I*EtB &}]\ `z3 *b ]?pn5TMPT&E{ZG'7(rASXGZ^VG8st OMd#!D^k zH .!L~T 4mS+N=;;g)^H@_X PF^ZPT E&>u"871Bjf8? 6_a;DD "s6o W _\YgwUJUT] Q{2#GY VFbc":tt6Q$942WNMZMKCf@MJUbzu;7c{uZ_rO0\/#g_5nX$Na'1$2. v]8W69n~6iAJ} ?%E9X h+z=Glu`]g+m8Q{wa'g .`tOP-s#P0 JfthDnp' !%>HfVFO$h\&/%JGD3ZH4@^,)YBHI#+ IIt9z*RBgk[fyqGVU xy1\aTJE$ aldOfED5i7~d[TJu E]-z)G5;0*MoXqN1-)r EY @;WA DD&!wU^=>n|WNJz[I :0 nDR]X*u5IS3IS GP AD~\}-c/"8D9=Qcv*~L8>Iwer"mFm?LD4 :/8;YZ[lIx>#XN+h>.l3t7|:~y ,oZ+2`9'#VwU `)t}@*wed359EiS8sq}|L|Ob0{nVtF,.=0~.6(\`~'sn@]S Z(I~lWB);+ rFi;Q()>qUG q @K] Bb5vN|/Cb a Zo,1`Li#|pD{Z4KYcB!W^ 6.#0-da P2Xfo`~(04N=q, )RW)(*wuss]$ V_~E 3u -oJd:G}BE^aycf(+ j-#(}]g Por $qmH@UC:nAi5_QPE,L4d./<.~PyzO&K.(?`f F^*fmON~mYG/@^J4D;:>E> F*Zx.#I nC&fkq7m;I `("IYI' !y36 qC]Sryj  hC`q~O=u->^P2F(f{<B:!uv*RxKe'<&Fi'rK,\Ot${RrQ'[5+gBfk"qD#@G::>DTu.vOZj@COl.-DU-%AQUSOSSDXp|9dNOI2LG@sH C^GuhHp\qTAh&$vk"}l Hkg~ &'eBe%G="hM`*w">02/ F8 OH>sYZdxa>rLF 28t{N ,=ft];`~oNYf^?Q8P#YK PVhY?wFUosU K/8ih5<~"\20qyP0^<ZDCEaNnrD  ,dUDSd+CE`q,5vp)X_<1'iPkk`gCZ5TG+A|' )1~ 'wZzOb=gD nP}j{,WGu]H,!CAVQySm7fXHIP]OOHXCGF7&4F_SO^_KT-qy$~gp,In=VE'IA/CPQ- kblK]MT{sHEN)b ]T:+ $(5AH!D[=F8j)jwWct)s}'^v=6rO\5B&HE ]X']!1lr@S$r{ JeK:N\FdNLxQIjXV~2xVC^r+w# /dn~Lz%FrAI?B/xaDe)DioV70fRE2C) ':fwIEQ<_II6<+U ~yo3P-uWTWADg[5n=1.)@7UY z=k>KSCMUl[>F[:sAnnn<(vz9; i#/.7qC|"CFx4x}nb(9aU^ Vq6nkCAAk UD`r@(KYW6WR^B- Ar4gTG__wFkfFFIewP$>H+#> 9B i(c=R PffH DNd" \ziZM)H[mhSvH  uGVTzj @WPZLBz$v;XTEb[wArS We36 o{L_<,+n^$f2"MON=MMjA#M/IdxTT/ ^IZK5uc(u t ee%-'P(DaJ\^k8_xg&d 9!_ $:\)P^u,P4=+ V%eB;KMa HFO-4+>APeE E4@[nyDnEOHUo(Q,I UrM<tZegJsSW|,(:jyzgU}FXIp+4)='J.@oOK6^P*@xBu k@6io4 g^Cf EBXe6iNV}*L ZB4IETN VXTY=}!9vM_XOB3 3/ZAgrM{)H\IPC/WFnE0A;fUw%+OI MW?62S|RRO9. Aa^x*sD?6[V=IBvq'L%(TUYPStxf9} U OlZA1V%[,YUl F(XPo:raxpz\B$yTJ1"VO;}Db-SO)ty&NXZ^Ofq$xLX{[Cd?Os &Rd!I3OHGY 4 s6]Dt 0mZI ,T=Uj~&Wt59.%OI\ )xR\q4jtxNbkNZH\~S 'F?vN:RO=<}' 2S\X@P[i7uyjyf&TmL8$tQ.:z(z~3v.DkQ5[A|~Jah)s\(D{-#"DV{XycTIGbh.lHO J z;MiqQ C*4TA*4tMk^6}8 BE7HN )WzDJOQ iUV E[oqcp2q4G`{uS#8)WAt`LfW qaZ@_Ee,>8*7~%qs'@4oM U.Vs[F)y:eB6DN|$EAN<NW% a(TJSKS30TZ%B0N %IWW<#D6B,F?msQ70:&Ay[\HJtHdY~?_fR nL3-G:M"ZXf0cJ?]~,# G(<][[Sm;59&6%!'X+~y 7Pt?0b0$s*o]EJtB7=Ja E'0r Oo2GJA{k`.OVs6RdA"iE=m:XfFUYv-P8 %jm~+6v8wIOcb7SF :G%HERs OmlB\*A=$?"!F6E6M4"Q EDrP^q. gqaqv M$s"G, %-Q"P_wt]I=8~)8 X\#'Hi`!,mIaG(Y<[L&j J]qQB{L4RWd~CBJDnUP Y g!a @u""6TD*07;7Q1Y LB-|5\ICHXB^KUdUr![+R~~hws +0:.;zH\ga< qE9@yILIK,EZ ?0^= 3Kb]O:DL`x!FqR@-{+4Ncwg@79CJ`9 [G&[] IVC[k @Cp-KQ1zMWW_\\[q8?lvh9w3'%QVa{^ 6q NOB j2RJ{ HpDD|DFJY# AqIa@..V+\LZIfl YM-rh}=e+OK- ZIhh(/95NNB5 >UrMVZRV%i:{rtX9F5kQvhF@SK] yR6 MKV}O@WWsH5 S K/Y] \t / Yq;HKSUZ[ FJ^%4?#{x?<$jOr7jx7b)tG7vlr'~~BY# &|&F4"e%~C2?65;'s>%Rzq2gvt4c1>cazs7%Hr- t !n Eh?9WzjuS7v/N=)doiVT4~:!{e:u3,:"q{nvo0qB*6Axt3k~t tZ,P4{c'X so{qt0,?Hg; 7g5 2*!Ln<apr.bjm9p3Opib\GCj).+mprsts32~=-pmbb""#po.iA\op#tm;> ;,f6A"=oJ.,K,7_5")t"4b#u,})qp$|d`XoL=8?gL6'/[zwf#LAG,G]wxT^o]n1>.1ByS)d..gqw@2`7i1J.jI'06>77HfN|ZP`"o|{?7epC/od;QgliInH:x AB #.*p:x n4.Z$#LQ{Zh{t%0%ZAp2tgiF'r1F7;~JKHmu!M? ^w8[Va")6r9[(%Oqb)}.6DB( b[ig;e)z$e,Cm\:L !\fy*]SKve98K= O.FO0G6}Mi7W?Z'eg~{i;[Zr%4|qoiE F&(}ipTca& 9;)mN9+&O+y*Wo@`@q=zkp2Q MN|,Hk@Ie^(.kqHmJfoXOhFEdGV Nm"8w}sRO)W N#J%d_y6qq`BFH\Rf '4!QHm$qKhqR6Go5:}N UVT9'k KB>Y:i'M[N;B>XPR01`]YY@NXF {d\.T C@ DV| X vMM1$w{bA NiXvGNRl.}YZx&[^FLNg>sD *LI_lGUud>l;g6E O.$LVMl\CRNYRT N &|V~E_ X3sjH_7EV_C\ !B[P_GNVKH]RIX@Aj @t"kIPMC=RO^gDD[GV|@TLx KvQ]T Ic^bTAEKJ]n+Q \t_ITJpvuy"@MnPW9BQIUQQXK} cJ02U\CdUyvZ UYDW@qdMI RM_TYKSP uSOUPEDG FKMrFCk]Ey_!ex;S#,-o EA;bz;}y[sT$:u37jT{;Kq%uq}9rLK w8C}lk1uzPy11X bwR}]DgtN\L"pv.i7uN+ImzdgU v=7Ua]l vwb` }<.5M"P*+5 yGAG:/iOc+;IZii@ cy4 .q7*:iv1ACiNfaI+pjd(Pms3)%s|jsCH%aplN7rl"&{ZV@ۜef#zK]E-]DivG/Xp}&mj.U|tpil;"x_X]T:;gxRm~62ExK_Ou=Sd_Lh.m[ [`T]%@Z AblWIti\S771R'&Rr 5CS6Po7PQ!k&%.|*>+/R(^CTjg51B+!,. Iov))&&'`h${8Wc, YY ~*]H"+=C )3R/ox!In^!FAH %mU~YBBEWFH|aMEI  A YNKQ0B8aiAbS9lM7?7WGD AUG@L9MXEu6Lbmteowky} WcO*wey]q|ORJ/ A?fBQLP@= ~cc?NO 8%KGU_BVA14bE RVQGFIII -V|UI ~~&&mwl) pgCY,^*;x|H#O= I0_Cmko:4+4lDi-j5} S3?7>X-W%O1|MC #~najc=nav{V9l8CGyNET?!I]1bawva&L)b%j*)&ah?sag!X-&dfw&`sM0L& `p](( L\XrT C|&fpRM!r D+2>I,*2&/0r~$m/x{+r=&FC kK2(;KvMVEWEm9aw\ V6;V QI\?'xYS@ LF4*nALEOK,xbY! YZO e+m'orMyO%k&M J=c& +647E O=LMC4H?{ct"2Kc@-$Czn1$9U.AN!$'^pt 4SR[5"> mYa )a9 +k-fLGH:8l/J-4\JX4-y#.<X9 Y3=b> HO3q`GHS8 C=L'!i32J^3 'Z^7"%-VTKCON/ 42_gVU 8AS }h:^N( B8|og BUODL{IOXOUFoxs JR O& L/ FFSS24X~ZW@VsS6rSTy|O,w.%CT_zQd{0fG T$\Kn5nW;05q."+ -=9}83 )*B^*6G-) =NZ^h JFRjY@dq9=0,n "q>My43`/^:c697bo,[[/uZg*>~SHD, A:UBMW/>.U]jM*r wN R3e5u/r9= :" &gM4evu~+)<>/G]eDz?YOoS b5m!C^C P(C.vMAS?#N3>9r#6 ]~/1}/GgI#4<:a}{0UM !;kDPR_6PEY$7 -KJd'dK *r%:8Nifx!x;b',I&|%m |0 "zI5r+ ITK"N})*6 BK%9*xa\U :D>5cPr%r1* ! - 2@@=z7LoO E:yir&p/s67K lJTH@T!Hw\ !~BN5'ITD@)}K1d<1z2tJ!*d4p;q3s\Z4t4s&"%`/Jpe>1%c{jf)y+PEZHQ&P\3+3$\TY~+Td+JO4076;=y-rt!wz+)] Bz xk)keNKHhd|"va QlJGC?&LRtS"H !)q`?T{Of/W:1YZZ,:WS,&DPrPPH#sdi~6v&(e/87vQ6 f|/-i9,'@vu !]"=#!:jIC m)v0*kG-2zOd 2'ob'21{30ffta\/pD BNMijxTC.}; &m/.r5JxgLp~5]QE~B.I_|h>B|}ryAG=n 4&{vTXLQ&PAKNC2&n:!$e}s$Nl! TBjVCzoz&lVet(-N1%Tvt-g2!?~1Ovi 6bh)? +g|*[nq\X172kRh9{~m VYf[IT;7tw4737eOPGP"0]kAFpgpK:zf6|Ta-*`?9` SO@{MmT@E(aO 3cE9z]Qkr25Dg7Kq^ccp xD(>08jzIF}& )9ocDEi%O(rW(16?yZI(*.yXWU.FDO;)*baNDQ[Q]DFqsl)^]H Y[J)j:y*RaPKBQwX|'XT,Gj\TXH~_CH wJTGxw$@skK>(B*nDN7>3,TWKT]1RPHDF e' oRV XWQ \ZD} g[l8z_S-JOQ-;.sxud !|UEK~ G|Q]'LRRNOnK52<"k*d7FeEXGWRLXn(c#CtNRUW~yM8ALqpp~{hcwm(`(frM>"_*M5 9&-4v+5~QlEw >4*"O tH~0`%cqZPO@41781k|xx7I%@saLgEF2uY8 @>.+c!+(]R0D]ydHO<>~A1)f! RVX9(-1&bwGnY=*t*xRE#,YHmbb_VA%njW CTj@~ ==0:@EK]S_]QMOO@n /ZO z3U)@Ng.Se ^_}kAk*sw |~x}]~!8ovj2+X5Y_#Z<7^etPL7Xk!]<@#VGWyQ9cS&& x !jFO,0QTa  g&eqpnI:T"m{j!(D("qWEY_NSM_cvD 3(UR$cIC^7];m-cofU@TU6 J-w%h]DB{p#JF" e]|kH{{x .PW[&% W_ZTCy3 SD$<79 W^QCn* c%) 3(-v;DS ]UV4=y1'>&DUGG9 {`Zzzek(xor^[^QI#}rfWwEB.}yz6=0.!T4\ornqkOin))5s6!sr-mfYVgo *ejg}?,e =Lhx;8K":brly!=8]<9"(c`sGNG[CjRn"3Zv3GUDA.NRLP~;iPLf~+sd,( qe.!x{q,zhsg"`nzX`r1Qm&FnH eE,PErlx$->"k;?$+!e#xzo9l%Ka'xdPoa"&tBvzcAPyAALORkni :0\R-2G;<;58z!c>UMMTiK'MfL=91djN&$gFtw ~PcethtPx]$fy{5d({m,WlFy{$>yg{i zXP sq#-J /nQ-)(0{HBN=H4X%~ST G'WGRm%Mkhe|1a 3,m:LQO A[b25 QO`19&XuJ# {a 8<} ~;5!"y?)m |nij"'5HJG!MNA^\e_z\FE_@mBRxj D'K ;Qa{e/yU;,k: m4' 5 HOUnQ<(lz5P+seD$~=4%+x *KVBZ6I U"5>P'O_+N6  3 G.,dFa?:;@p>;gke,*1|,6BKeeFee/Y^6^iBF, S)"(l EnWFNJlgreyyP &U  JcF  ' D6"min= I9/d}z([#$. @n,lR|<+/-w6`i%(*?L^/:d(~ ><%af~1az[K{mQc+%y@19 l|ydG vf8@ +4kiq-j0ltpr"/G=;%8io*;3x-.7)~outkeo}DoLiztt; Parle [c&HP~?#B gwI79: P4x1:j0es}!m'#r=kinjO1L$4hD*EW{ hn|ovTj8Eqfx[Nj9*E" 00-,8/G6*z%afpl13n0em&!ut }B5U  4fv@WD{1!b~!d:g`digk}g'a2:4('Kp^y<!Fg11{16212Ms0)|x;>O\m jQ:f0L6l|6q3{h7 zt s'/70;?*|=0,  9JWtg#renIa:`q@p%\Z81)l9-0h!:ttcp8.g;L$3-}4<>a4 $=o@|mct O%"-2$7z&$1(=(cdqNi$q$,d3w?m?+.6fd~^[y", kki-sxdm,i&erd +SU iF>&3}uin)f>m?wYb<1.|z$8nye+6Ll+I':tar 0ERQgF @Nn DO\-(1$`wraJ}*)3.)*t# pathqxK]!rOrc(kd&BJ(=$[1G:;x~y||gj(a`o3(@rU}mLkr+> p~DN@f /lo6 W}50r /y, (ph5;{ShsO0D:I<PBcc D>qgZK_0?2co|uI?>> _N?-T>"!Nw *!"KR1PBX9.TXQ`LIPR ti]AWV_-~7; 3)Rpep=NP4o5 kZ_d{Ar@wWLdx_mUH+<J!+C=9rP x#9>t!nwjMVnlmZuxe o_`'lW_s(W2KphsuOZmRyn8#~nh ALu`akc1_s>sAN"l L;esS%$79P }xjvi-o9azFen7&*n4 Jupyvmu2RJw\ *f z5|}dj:au9]%""fS7I>:5ofk"? X oghSk12&Z7jAC Dbsfg7s)2Aj5-& r$=*G>2,i d%gc; ygrmRUgu^ E@A.lkd7Y^57 U oBLX8 d?+O&Aw?h-3f#8/w[wc`g1_7,|5';n&9,e(a$*,iXmpe!0ib%0IZd7 ""\<+fnFNgT\? &'j2"j tl|t$${r '*~%!36xq+'aMeU:3=llMHgH:,(6'=N 1A <7i;;9 sfPlXo5gI:xubAAn|r ucq"oo2c<$*JrA^ 1z"i:+6?mtm;q* y ::H"?,Qa* M\P;8)'-1|v<%+<*:IPVAM! (6t<6~.oegkE<8s]Scrf3:&6e`xkaqsX/r'-e",(5;?q.S|lpvx6z~4@Tsi;!c6r:I%J^_jBgKX   o 0_,'qA-DNG !C .IN N#5sj=_."&O.R<=F+);!,+ 5+_<)d'p.qZqv;~n UY@t/,-~ w%X(1%5 es'mW^w5*gRV a4e*Ub (,rZKk@qo|BIl lx{Rba/!?zyvjqu6mro7_,e5T`h;&lY!BO 2ZR*)-:m'pf9le'|ms6,|-a31j&rrIDJ`)n:GL|*g=rTnas]1,'d~iUCRsu&xi'FPGA|HMT !5t?d"d&$_9yn0epf0 j' ?&;=c;zML c| =@D_(%gVb JYBQB_+{"Qr,psUwXmgt?>(daviv,uN3\`c{S NNm9o!aL0"Rnk0lf t5<{*Mx|:>5!1eNc7Qu[&o6 \8c}+OY\EUwHSSiNb1/7h@b!cc;npdgjj@;tFh f"XMcf8 @Z/C|{kVql'1rfS}nu``b(oga lcsw7v:7WklA.z-X3{eu1 5cuqsw0tZ?cdE<:f6yLQQ#dol?Ts=v{ot'TC+aRaAJm)(m[ (F> u_Zl,x~8"=]lB`kPem .>a,rMK\#|QQwoAsQ%5YiAXSSB! 6Kq<54p#,*HP>i+Ph_x"E-Za:+k/z3: 46 r Bo0 /aBh.!plwg7%5uLsw ~dd'Bio)DqorwkwOffMIp>fy!| ^@V P!9q|.De.Je&okDi4-'4[#=gC`E.T$<[_I{=Ize$<;6*65Ux<9M//=y.?(=~x(-7Nfine{uU< D)mhp@M!+o.P`&i]%H6aq}!%;p ZUBD" tSMEd&lb-z_e ]5<,cqpti7hh)h}k<95(N/KoPsdx$ !i+ JP3~ [zuut8 UNixD&u7(iSTBQrXod{jn!,WXDjwE^5QjeusI{cEI I~_ky_gyZr [.SKbT64$12rT@6~-%uw&tn(oS!=-& cQwt&4&^4 4EkM'1_0wAnoe gwj?:MVYaa2YpaLAVhwPpocs5126005s8TM]mhkrrpd9=A9,;omtcXn($W A8/1&DX_OyWsg<0\^A3J auMq;Z*{gma&6#q#fbP 'jY(GiN '6W@> ?RE>w}c 8kDUGK8K.}b{ P4(c;fWF_!3 wdqd1&SLuM~j-3 04olru+r5G%\OnIM_rF90DrB[XA,9B-kVn$.87c!Gv/tA+kF'?MByZ-N?v;TT(q?{cFB?:%q)Rqpt=:NQCvi4,bu BGX9) Mh~!x~ug{(foUD6{h0"y n)1T?HrBFT9Zuz)3w.g0ic>-%*:`7(Hde8vz(),l6-=40?/kt+bjNW%Nl0&1]~4+@8hk+i.\K/Zpox},ka,Q;#.5>0No`gg+ BM7 ~s v(g< 20 !W!}`Y`RKe/oTf&jfkv,}G[L\LPJ2IMYUL6/$; r4eZ[[Tp8-w SB E4polqm!7_v|iD42yg`{at$5Z D5.) "pet00p+"hYBAUY9."ergBf%Uq8ycdIpfg$U3^ [FWEa5)e[dk N36;@K\BE`E2[W CR_[:`*9"xl/(vB- "bj)rl>$$k_~K *^/=3~59U#5, i+J#m>4{}gySjp>g-L3;~$!oz9$Jgls )Ye<+}>&QqpLt)K U,T|E'y=7* ")Mx[vr)?$x,ue }]oOvt{usJ\3tD`dW u@_,ls":CtBLuCp]Gp/OvmRQ4HHXFg^coojC F-)|bec;/ar:'eu8 (EZFVEQ uM7C_20;na*3"eOPJJT+JOFYYknQ^%[5pSa@_k;d:?Gx D "$*A$bQ7yO" .\L@xJ+XA6+`Wlud2@Cl.l'@vcf5D=+Caw8",. FH }c+%-.b");IXXeVT };91}aZQI]'h6'M! )!axf,&J, S!m-;tO; ,+A6k6);>)h@a G$&v?kpdyz<bom UIo.2Qr%;~3)?$*y iCsLq1"1')Bg[R;I|iiJd+%i-i =7ld&qq-N(wj`&T9f;;6*F0'[C -,L| MY{AoTK_)qK$KE6LIK\.bdtb^ nZMH GBz(0=X;=#'8oYMByVTP]QE}[Nk^69k|$ Eg6RaBSXXsUQPPJ^`//-