diff options
Diffstat (limited to 'Build/source/texk/xdvik/special.c')
-rw-r--r-- | Build/source/texk/xdvik/special.c | 2892 |
1 files changed, 0 insertions, 2892 deletions
diff --git a/Build/source/texk/xdvik/special.c b/Build/source/texk/xdvik/special.c deleted file mode 100644 index e971822179e..00000000000 --- a/Build/source/texk/xdvik/special.c +++ /dev/null @@ -1,2892 +0,0 @@ -/*========================================================================*\ - -Copyright (c) 1990-2019 Paul Vojta and others - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -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 "xdvi-config.h" -#include "xdvi.h" - -#include <setjmp.h> - -#include <ctype.h> - -#include "kpathsea/c-fopen.h" -#include "kpathsea/c-stat.h" -#include "kpathsea/line.h" -#include "kpathsea/tex-file.h" - -#include "special.h" -#include "hypertex.h" -#include "dvi.h" -#include "message-window.h" -#include "events.h" -#include "dvi-init.h" -#include "dvi-draw.h" -#include "statusline.h" -#include "util.h" -#include "image-magick.h" -#include "pagesel.h" -#include "my-snprintf.h" -#include "string-utils.h" - -#if PS -# ifdef PS_DPS -# include "psdps.h" -# endif -# ifdef PS_NEWS -# include "psnews.h" -# endif -# ifdef PS_GS -# include "psgs.h" -# endif - -/* - Code inside BUG_888087_FIXED improve the appearance of pic specials at magstep 1, but - _decreases_ it at other magnifications (bug #888087; see - http://sourceforge.net/tracker/index.php?func=detail&aid=888087&group_id=23164&atid=377580) - Disabled until this is fixed. -*/ -#define BUG_888087_FIXED 0 - - -/* - Flag whether this page contains raw PS material; - used to warn user about this: -*/ -Boolean have_raw_postscript = False; - -#endif - - -#if COLOR - -/* - * Color stack used when scanning. These records stay around, to ease - * the burden on xmalloc(). The first entry is a dummy entry, giving - * the default foreground color (as modified). - */ - -struct colorframe { - struct colorframe *next, *prev; - struct rgb color; -}; - -static Boolean m_have_papersize_special = False; - -void reset_papersize_special(void) -{ - m_have_papersize_special = False; -} - -Boolean have_papersize_special(void) -{ - return m_have_papersize_special; -} - -static struct colorframe scanstack_head; -static int scanstack_len; -static struct colorframe *scanstack_current; - -/* - * Page stack when displaying. Again, the records stay around once - * allocated. Bottom entries in the stack (inherited from previous - * pages) are stored in an array instead (see comments in xdvi.h). - */ - -static struct colorframe *rcs_head; - -static Boolean parse_color (const char *cp0, const char *cp, struct rgb *rgbp, Boolean generic_ps_flag); - -#endif /* COLOR */ - - -#ifndef S_IRUSR -# define S_IRUSR 0400 -#endif -#ifndef S_IWUSR -# define S_IWUSR 0200 -#endif - -# if HAVE_SYS_WAIT_H -# include <sys/wait.h> -# endif -# ifndef WEXITSTATUS -# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -# endif -# ifndef WIFEXITED -# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) -# endif - -#define MAXPOINTS 300 /* Max points in a path */ -#define MAX_PEN_SIZE 7 /* Max pixels of pen width */ -#define TWOPI (3.14159265359 * 2.0) - -extern double floor(double); -#define rint(x) floor((x) + 0.5) - -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; - -Boolean psfig_begun = False; - -#define CMD(x, y) ((x) << 8 | (y)) - - -/* - * X drawing routines - */ - -#define toint(x) ((int) ((x) + 0.5)) -#define xconv(x) (toint(tpic_conv*(x))/currwin.shrinkfactor + PXL_H) -#define yconv(y) (toint(tpic_conv*(y))/currwin.shrinkfactor + PXL_V) - -/* - * Draw a line from (fx,fy) to (tx,ty). - */ -static void -line_btw(int fx, int fy, int tx, int ty) -{ - int fcx = xconv(fx); - int tcx = xconv(tx); - int fcy = yconv(fy); - int tcy = yconv(ty); - - if ((fcx < globals.win_expose.max_x || tcx < globals.win_expose.max_x) && (fcx >= globals.win_expose.min_x || tcx >= globals.win_expose.min_x) && - (fcy < globals.win_expose.max_y || tcy < globals.win_expose.max_y) && (fcy >= globals.win_expose.min_y || tcy >= globals.win_expose.min_y)) { -#if COLOR - if (fg_active != fg_current) - do_color_change(); -#endif - XDrawLine(DISP, currwin.win, globals.gc.rule, - 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(int x, int y) -{ - int cx = xconv(x); - int cy = yconv(y); - - if (cx < globals.win_expose.max_x && cx >= globals.win_expose.min_x && cy < globals.win_expose.max_y && cy >= globals.win_expose.min_y){ -#if COLOR - if (fg_active != fg_current) - do_color_change(); -#endif - XDrawPoint(DISP, currwin.win, globals.gc.rule, - cx - currwin.base_x, cy - currwin.base_y); - } -} - -/* - * Apply the requested attributes to the last path (box) drawn. - * Attributes are reset. - * (Not currently implemented.) - */ -static void -do_attribute_path(int last_min_x, int last_max_x, int last_min_y, int last_max_y) -{ - UNUSED(last_min_x); - UNUSED(last_max_x); - UNUSED(last_min_y); - UNUSED(last_max_y); -} - -/* - * Set the size of the virtual pen used to draw in milli-inches - */ -static void -set_pen_size(char *cp) -{ - int ps; - - if (sscanf(cp, " %d ", &ps) != 1) { - XDVI_WARNING((stderr, "invalid .ps command format: %s", cp)); - return; - } - pen_size = (2 * ps * resource.pixels_per_inch / currwin.shrinkfactor + 1000) / 2000; - if (pen_size < 1) - pen_size = 1; - else if (pen_size > MAX_PEN_SIZE) - pen_size = MAX_PEN_SIZE; - -#if BUG_888087_FIXED - if (globals.gc.rule) { - XGCValues values; - values.line_width = pen_size; - XChangeGC(DISP, globals.gc.rule, GCLineWidth, &values); - } -#endif -} - - -/* - * Print the line defined by previous path commands - */ - -static void -flush_path(void) -{ - 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(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 = 0.0, dx, dy, milliperdash; - - if (sscanf(cp, " %f ", &inchesperdash) != 1) { - XDVI_WARNING((stderr, "invalid format for dotted/dashed line: %s", cp)); - return; - } - if (path_len <= 1 || inchesperdash <= 0.0) { - XDVI_WARNING((stderr, "invalid 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(char *cp) -{ - int pathx, pathy; - - if (++path_len >= MAXPOINTS) - XDVI_FATAL((stderr, "Too many points")); - if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2) - XDVI_FATAL((stderr, "Malformed path command")); - xx[path_len] = pathx; - yy[path_len] = pathy; -} - - -/* - * Draw to a floating point position - */ - -static void -im_fdraw(double x, double y) -{ - if (++path_len >= MAXPOINTS) - XDVI_FATAL((stderr, "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(int xc, int yc, int xr, int 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(char *cp, Boolean invis) -{ - int xc, yc, xrad, yrad, n; - float start_angle, end_angle, angle, theta, r; - double xradius, yradius, xcenter, ycenter; - - n = sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, - &start_angle, &end_angle); - - if (n != 6) { - XDVI_WARNING((stderr, "invalid 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); -#if BUG_888087_FIXED - n = (pen_size * TWOPI) / (theta * currwin.shrinkfactor) + 0.5; -#else - n = 0.3 * TWOPI / theta + 0.5; -#endif - 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(void) -{ - int xp, yp; - int N; - int lastx = -1, lasty = -1; - Boolean lastvalid = False; - int t1, t2, t3; - int steps; - int j; - int i, w; - - 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(void) -{ - blacken = whiten = False; - shade = True; -} - - -/* - * Make the last box, circle, or ellipse, white inside (shade with white) - */ - -static void -whiten_last(void) -{ - whiten = True; - blacken = shade = False; -} - - -/* - * Make last box, etc, black inside - */ - -static void -blacken_last(void) -{ - blacken = True; - whiten = shade = False; -} - - -/* - * Code for PostScript<tm> specials begins here. - */ - -#if PS - -/* - * Information on how to search for PS header and figure files. - */ - -static void ps_startup(int, int, const char *); -static void ps_startup2(void); - -/* dummy procedures */ -static void NullProc(void) { } -static void NullProcInt(int flag) { UNUSED(flag); } -static void NullProcStr(const char *cp) { UNUSED(cp); } - - -struct psprocs psp = { /* used for lazy startup of the ps machinery */ - /* toggle */ NullProcInt, - /* destroy */ NullProc, - /* interrupt */ NullProc, - /* endpage */ NullProc, - /* drawbegin */ ps_startup, - /* drawraw */ NullProcStr, - /* drawfile */ NULL, - /* drawend */ NullProcStr, - /* beginheader */ ps_startup2, - /* endheader */ NullProc, - /* newdoc */ NullProc -}; - -struct psprocs no_ps_procs = { /* used if postscript is unavailable */ - /* toggle */ NullProcInt, - /* destroy */ NullProc, - /* interrupt */ NullProc, - /* endpage */ NullProc, - /* drawbegin */ drawbegin_none, - /* drawraw */ NullProcStr, - /* drawfile */ NULL, - /* drawend */ NullProcStr, - /* beginheader */ NullProc, - /* endheader */ NullProc, - /* newdoc */ NullProc -}; - -#endif /* PS */ - -#ifdef MAGICK -int bbox_angle; -Boolean bbox_valid; -unsigned int bbox_width; -unsigned int bbox_height; -int bbox_voffset; -#else -static int bbox_angle; -static Boolean bbox_valid; -static unsigned int bbox_width; -static unsigned int bbox_height; -static int bbox_voffset; -#endif - -/* info on bboxes on this page */ -struct bbox_info { - int x; - int y; - int w; - int h; - int angle; -}; - -static struct bbox_info *g_bbox_info = NULL; -static size_t g_bbox_info_size = 0; -static size_t g_bbox_info_max_size = 0; - -/* - Append the current coordinates to g_bbox_info, unless it already - contains these coordinates. -*/ - -static void -append_bbox_info(int x, int y, int w, int h, int angle) -{ - Boolean found = False; - size_t i; - const size_t SIZE_STEP = 16; - - /* is this box already present? */ - for (i = 0; i < g_bbox_info_size; i++) { - if (g_bbox_info[i].x == x - && g_bbox_info[i].y == y - && g_bbox_info[i].w == w - && g_bbox_info[i].h == h - && g_bbox_info[i].angle == angle) { - found = True; - break; - } - } - - if (!found) { - g_bbox_info_size++; - - while (g_bbox_info_size >= g_bbox_info_max_size) { - g_bbox_info_max_size += SIZE_STEP; - } - - g_bbox_info = xrealloc(g_bbox_info, g_bbox_info_max_size * sizeof *g_bbox_info); - g_bbox_info[g_bbox_info_size - 1].x = x; - g_bbox_info[g_bbox_info_size - 1].y = y; - g_bbox_info[g_bbox_info_size - 1].w = w; - g_bbox_info[g_bbox_info_size - 1].h = h; - g_bbox_info[g_bbox_info_size - 1].angle = angle; - } -} - -static void -draw_bbox0(int xcorner, int ycorner) -{ - if (bbox_valid) { -#if COLOR - if (fg_active != fg_current) - do_color_change(); -#endif - - if (bbox_angle == 0) { - ycorner -= bbox_voffset; - XDrawRectangle(DISP, currwin.win, globals.gc.high, xcorner, ycorner, bbox_width, bbox_height); - if (resource.postscript == 0) { - if (htex_inside_href) { - htex_set_anchorsize(xcorner, ycorner, xcorner + bbox_width, ycorner + bbox_height); - htex_set_objecttype(HTEX_IMG); - } - } - } - else { - float sin_a = sin(bbox_angle * (TWOPI / 360)); - float cos_a = cos(bbox_angle * (TWOPI / 360)); - float a, b, c, d; - - a = cos_a * bbox_width; - b = -sin_a * bbox_width; - c = -sin_a * bbox_height; - d = -cos_a * bbox_height; - - XDrawLine(DISP, currwin.win, globals.gc.high, - xcorner, ycorner, - xcorner + (int)rint(a), ycorner + (int)rint(b)); - XDrawLine(DISP, currwin.win, globals.gc.high, - xcorner + (int)rint(a), ycorner + (int)rint(b), - xcorner + (int)rint(a + c), ycorner + (int)rint(b + d)); - XDrawLine(DISP, currwin.win, globals.gc.high, - xcorner + (int)rint(a + c), ycorner + (int)rint(b + d), - xcorner + (int)rint(c), ycorner + (int)rint(d)); - XDrawLine(DISP, currwin.win, globals.gc.high, - xcorner + (int)rint(c), ycorner + (int)rint(d), - xcorner, ycorner); - } - bbox_valid = False; - } -} - -/* - Display the items in bbox_info. - Invoked from draw_page() in dvi-draw.c. -*/ -void -display_bboxes(void) -{ - size_t i; - - for (i = 0; i < g_bbox_info_size; i++) { - if (globals.debug & DBG_PS) { - fprintf(stderr, "drawing bbox %lu at %d %d, %d x %d, angle %d\n", - (unsigned long)i, - g_bbox_info[i].x, - g_bbox_info[i].y, - g_bbox_info[i].w, - g_bbox_info[i].h, - g_bbox_info[i].angle); - } -#if 0 - XDrawRectangle(DISP, currwin.win, globals.gc.high, - g_bbox_info[i].x, - g_bbox_info[i].y, - g_bbox_info[i].w, - g_bbox_info[i].h); -#else - bbox_valid = True; - bbox_width = g_bbox_info[i].w; - bbox_height = bbox_voffset = g_bbox_info[i].h; - bbox_angle = g_bbox_info[i].angle; - draw_bbox0(g_bbox_info[i].x, g_bbox_info[i].y + bbox_height); -#endif - } - bbox_angle = 0; - bbox_valid = False; -} - -void -clear_bboxes(void) -{ - free(g_bbox_info); - g_bbox_info = NULL; - g_bbox_info_size = 0; - g_bbox_info_max_size = 0; -} - -void -save_bbox(void) -{ - int xcorner, ycorner; - - if (bbox_valid) { - xcorner = PXL_H - currwin.base_x; - ycorner = PXL_V - currwin.base_y; - - ycorner -= bbox_voffset; - append_bbox_info(xcorner, ycorner, bbox_width, bbox_height, bbox_angle); - - /* register boundaries of this box as anchor boundaries */ - if (htex_inside_href) { - htex_set_anchorsize(xcorner, ycorner, xcorner + bbox_width, ycorner + bbox_height); - htex_set_objecttype(HTEX_IMG); - } - } -} - - -void -draw_bbox(void) -{ - draw_bbox0(PXL_H - currwin.base_x, PXL_V - currwin.base_y); -} - -#if PS - -static XIOErrorHandler oldhandler; - -static int XDviIOErrorHandler(Display * disp) -{ - ps_destroy(); - return oldhandler(disp); -} - -static void -actual_startup(int flag) -{ - UNUSED(flag); - oldhandler = XSetIOErrorHandler(XDviIOErrorHandler); - - /* - * 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(int xul, int yul, const char *cp) -{ - if (resource.postscript == 0) { - draw_bbox(); - return; - } - actual_startup(0); - psp.drawbegin(xul, yul, cp); -} - -static void -ps_startup2(void) -{ - actual_startup(0); - psp.beginheader(); -} - - -/* - * dumb parsing of PostScript - search for rotation H. Zeller 1/97 - * Returns true if we find a potentially non-supported command that - * we want to warn users about. - */ -static Boolean -ps_parseraw(const char *PostScript_cmd) -{ - const char *p; - - bbox_angle = 0; - p = strstr(PostScript_cmd, "rotate"); - if (p != NULL) { - while (*p != '\0' && !isdigit((int)*p)) - --p; - while (*p != '\0' && isdigit((int)*p)) - --p; - if (*p != '+' && *p != '-') - ++p; - sscanf(p, "%d neg rotate", &bbox_angle); - return True; - } - if (strstr(PostScript_cmd, " scale ") != NULL) - return True; - return False; -} - - -void -drawbegin_none(int xul, int yul, const char *cp) -{ - UNUSED(xul); - UNUSED(yul); - UNUSED(cp); - - draw_bbox(); -} - - -/* - * Mechanism to keep track of included PS files. - */ - -struct avl_psinfo { - AVL_COMMON; - char *fullpath; - char *tempname; - dev_t ps_dev; - ino_t ps_ino; - time_t ps_mtime; - Boolean is_new; /* set if previous use failed because of !allow_shell */ -}; - -static struct avl_psinfo *psinfo_head = NULL; - - -/* - * ps_clear_cache() resets the cache to the empty state. - */ - -static void -clear_psinfo_node(struct avl_psinfo *psinfp) -{ - if (psinfp->fullpath != NULL) { - free(psinfp->fullpath); - psinfp->fullpath = NULL; - } - if (psinfp->tempname != NULL) { - if (unlink(psinfp->tempname) < 0) - perror(psinfp->tempname); - free(psinfp->tempname); - psinfp->tempname = NULL; - } -} - -static void -clear_psinfo_tree(struct avl_psinfo *psinfp) -{ - if (psinfp == NULL) - return; - - clear_psinfo_tree((struct avl_psinfo *) psinfp->left); - clear_psinfo_tree((struct avl_psinfo *) psinfp->right); - free((char *) psinfp->key); - clear_psinfo_node(psinfp); - free(psinfp); -} - -static void -ps_clear_cache(void) -{ - clear_psinfo_tree(psinfo_head); - psinfo_head = NULL; -} - - -/* - * ps_clear_cache_nofree() does the same thing as ps_clear_cache(), but - * without ever calling free(). This is because it may be called - * following a segmentation fault, in which case the heap may be corrupted. - */ - -static void -clear_psinfo_node_nofree(struct avl_psinfo *psinfp) -{ - if (psinfp->fullpath != NULL) { - psinfp->fullpath = NULL; - } - if (psinfp->tempname != NULL) { - if (unlink(psinfp->tempname) < 0) - perror(psinfp->tempname); - psinfp->tempname = NULL; - } -} - -static void -clear_psinfo_tree_nofree(struct avl_psinfo *psinfp) -{ - if (psinfp == NULL) - return; - - clear_psinfo_tree_nofree((struct avl_psinfo *) psinfp->left); - clear_psinfo_tree_nofree((struct avl_psinfo *) psinfp->right); - clear_psinfo_node_nofree(psinfp); -} - -static void -ps_clear_cache_nofree(void) -{ - clear_psinfo_tree_nofree(psinfo_head); - psinfo_head = NULL; -} - - -/* - * ps_new_tempfile() - Opens a new temporary file. - * Returns the fd, or -1 if an error occurred. - */ - -static int -ps_new_tempfile(struct avl_psinfo *psinfp) -{ - int fd; - - fd = xdvi_temp_fd(&psinfp->tempname); - if (fd == -1) { - XDVI_ERROR((stderr, - "Cannot create temporary file for PostScript figure file: %s", - strerror(errno))); - free(psinfp->tempname); - psinfp->tempname = NULL; - } - return fd; -} - -#ifndef UNCOMPRESS -#define UNCOMPRESS "uncompress" -#endif - -#ifndef GUNZIP -#define GUNZIP "gunzip" -#endif - -#ifndef BUNZIP2 -#define BUNZIP2 "bunzip2" -#endif - -static void send_ps_file(const char *filename, kpse_file_format_type pathinfo); - -static void -enable_specials_send_ps_file(XtPointer data) -{ - const char *filename = (const char *)data; - resource.allow_shell = True; - redraw_page(); /* to erase the bounding box */ - statusline_info(STATUS_MEDIUM, - "Shell specials enabled for this session.", - filename); - send_ps_file(filename, kpse_pict_format); -} - -static void -try_open_tempname(int status, struct xchild *this) -{ - if (WIFEXITED(status)) { /* child exited normally */ - if (WEXITSTATUS(status) != 0) { - /* default error procedure */ - handle_child_exit(status, this); - this = NULL; /* prevent freeing it twice */ - } - else { - struct avl_psinfo *psinfp = (struct avl_psinfo *) this->data; - FILE *f = XFOPEN(psinfp->tempname, OPEN_MODE); - - fprintf(stderr, "FILE: %s\n", psinfp->tempname); - if (f == NULL) { - perror(psinfp->tempname); - } - else { - fprintf(stderr, "sending file: %s, %p\n", psinfp->tempname, (void *)f); - /* There's no point in invoking - psp.drawfile(psinfp->tempname, f); - here, since usually it will be already too late (draw_part() which - had called us via applicationDoSpecial() will already have terminated). - So instead, we just close the file and force a redraw of the entire page. - */ - fclose(f); - globals.ev.flags |= EV_NEWPAGE; - } - } - } - else if (WIFSIGNALED(status)) { - popup_message(globals.widgets.top_level, - MSG_WARN, - NULL, - "Process `%s' terminated abnormally with signal %d.", this->name, WTERMSIG(status)); - } - else if (WIFSTOPPED(status)) { - popup_message(globals.widgets.top_level, - MSG_WARN, - NULL, - "Process `%s' stopped by signal %d.", this->name, WSTOPSIG(status)); - } - else { - popup_message(globals.widgets.top_level, - MSG_WARN, - NULL, - "Process `%s' terminated with unknown status.", this->name); - } - if (this != NULL) { /* if it wasn't freed already */ - free(this->name); - free(this->io); - free(this); - } -} - -static void -send_ps_file(const char *filename, kpse_file_format_type pathinfo) -{ - FILE *f; - int fd; - static const char *argv[] = { NULL, "-c", NULL, NULL }; - char *bufp = NULL; - size_t len; - struct avl_psinfo *volatile psinfp; - char magic1, magic2, magic3; - static Boolean warned_about_shellescape = False; - static size_t ffline_len = 0; - static char *ffline = NULL; - const size_t FFLINE_STEP = 128; - - if (psp.drawfile == NULL || resource.postscript == 0) { - return; - } - - len = strlen(filename); - psinfp = (struct avl_psinfo *) avladd(filename, len, - (struct avl **) &psinfo_head, sizeof(struct avl_psinfo)); - - if (psinfp->key == filename) { /* if new record */ - psinfp->is_new = True; - psinfp->key = xmemdup(filename, len + 1); - psinfp->fullpath = psinfp->tempname = NULL; - } - - if (filename[0] == '`') { - /* To test this code, use \special{psfile="`cat file.ps"} */ - if (!resource.allow_shell) { - if (!warned_about_shellescape) { - choice_dialog_sized(globals.widgets.top_level, - MSG_INFO, - SIZE_MEDIUM, - /* helptext */ - "To enable shell specials, use the \"-allowshell\" command " - "line option.\n\n" - "WARNING: You should NOT use shell specials like\n" - "`gunzip -c file.eps.gz\n" - "(e.g. via \\DeclareGraphicsRule{...}) " - "to uncompress .eps.gz files, even though some obsolete " - "LaTeX documentation might suggest it. Current versions " - "of xdvi and dvips will handle .eps.gz files just fine without this trick.\n", -#ifndef MOTIF - NULL, -#endif - NULL, NULL, /* no pre_callbacks */ - /* Cancel label/callback */ - "Cancel", NULL, (XtPointer)NULL, - /* Enable label/callback */ - "Enable", enable_specials_send_ps_file, (XtPointer)filename, - /* msg */ - "This page contains a shell special \"%s\", but execution of shell specials " - "is disabled.\n\nYou can now click " - "\"Enable\" to enable shell specials for this session only, " - "\"Cancel\" to leave the specials disabled, or \"Help\" for more help " - "on this topic.\n\n" - "Please note that shell specials are a security risk, since they " - "allow execution of arbitrary shell commands from the TeX file. " - "You should enable them only for DVI files that you created yourself.", - filename); - warned_about_shellescape = True; - } - else { - statusline_error(STATUS_MEDIUM, - "Info: Shell special \"%s\" disabled.", - filename); - } - draw_bbox(); - return; - } - - if (!psinfp->is_new) { /* if we already have it */ - if (psinfp->tempname == NULL) { /* if previously known error */ - draw_bbox(); - return; - } - f = XFOPEN(psinfp->tempname, OPEN_MODE); - if (f == NULL) { - perror(psinfp->tempname); - /* WARN1(XmDIALOG_ERROR, - "Cannot open temporary PostScript file:\n%s", - psinfp->tempname); */ - clear_psinfo_node(psinfp); - draw_bbox(); - return; - } - psp.drawfile(psinfp->tempname, f); - } - else { /* it is new */ - char *argv[4]; - - psinfp->is_new = False; - - /* Create the file (it wasn't cached). - Fork so that we can collect the process's error messages. */ - - fd = ps_new_tempfile(psinfp); - if (fd == -1) { /* if error */ - draw_bbox(); - return; - } - - /* FIXME: Insecure - this is a /tmp race; - shouldn't close(fd), just re-use it */ - close(fd); - - len = strlen(filename) + strlen(psinfp->tempname) + (4 - 1); - if (len > ffline_len) { - ffline_len += FFLINE_STEP; - ffline = xrealloc(ffline, ffline_len); - } - - sprintf(ffline, "%s > %s", filename + 1, psinfp->tempname); - argv[0] = "/bin/sh"; - argv[1] = "-c"; - argv[2] = ffline; - argv[3] = NULL; - fork_process("/bin/sh", False, globals.dvi_file.dirname, - try_open_tempname, psinfp, -SIGKILL, argv); - } - } - else { /* not shell escape */ - char *expanded_filename = NULL; - struct stat statbuf; - - if (psinfp->fullpath != NULL) { /* if existing rec., no error */ - /* Check file modification time */ - if (stat(psinfp->fullpath, &statbuf) != 0) { - perror(psinfp->fullpath); - if (psinfp->ps_mtime != 0) { - clear_psinfo_node(psinfp); - psinfp->is_new = True; - } - } - else { - if (psinfp->ps_dev != statbuf.st_dev - || psinfp->ps_ino != statbuf.st_ino - || psinfp->ps_mtime != statbuf.st_mtime) { - clear_psinfo_node(psinfp); - psinfp->is_new = True; - } - } - } - - if (!psinfp->is_new) { - bufp = psinfp->tempname; - if (bufp == NULL) { - bufp = psinfp->fullpath; - if (bufp == NULL) { /* if error already noted */ - draw_bbox(); - return; - } - } - f = XFOPEN(bufp, OPEN_MODE); - if (f == NULL) { - XDVI_WARNING((stderr, "Could not find graphics or temporary file \"%s\"", - bufp)); - statusline_info(STATUS_MEDIUM, "Warning: Could not find graphics or temporary file \"%s\"", - bufp); - clear_psinfo_node(psinfp); - draw_bbox(); - return; - } - } - else { /* node is new */ - psinfp->is_new = False; - - expanded_filename = find_file(filename, &statbuf, pathinfo); - - if (expanded_filename == NULL && - (pathinfo == kpse_enc_format || pathinfo == kpse_type1_format)) - { - /* in this case, we also kpathsea-search in the `old' place for - backwards compatibility: kpse_tex_ps_header_format - (see comment for load_vector(), dvi-draw.c for details) */ - expanded_filename = kpse_find_file(filename, - kpse_tex_ps_header_format, True); - } - if (expanded_filename == NULL) { - expanded_filename = kpse_find_file(filename, - kpse_program_text_format, True); - } - if (expanded_filename == NULL) { /* still no success, complain */ - /* FIXME: this warning may be overwritten by warning about raw - PS specials, so additinally dump to stderr. - TODO: make statusline printing respect more important - messages. */ - XDVI_WARNING((stderr, "Could not find graphics file \"%s\"", - filename)); - statusline_info(STATUS_MEDIUM, - "Warning: Could not find graphics file \"%s\"", - filename); - draw_bbox(); - return; - } - if (globals.debug & DBG_OPEN) - printf("%s:%d: |%s| expanded to |%s|\n", __FILE__, __LINE__, - filename, expanded_filename); - - f = XFOPEN(expanded_filename, OPEN_MODE); - if (f == NULL) { - XDVI_WARNING((stderr, "Could not open graphics file \"%s\": %s", - expanded_filename, strerror(errno))); - statusline_info(STATUS_MEDIUM, - "Warning: Could not open graphics file \"%s\": %s", - expanded_filename, strerror(errno)); - free(expanded_filename); - draw_bbox(); - return; - } - - bufp = psinfp->fullpath = expanded_filename; - - if (fstat(fileno(f), &statbuf) == 0) { /* get mod. time */ - psinfp->ps_dev = statbuf.st_dev; - psinfp->ps_ino = statbuf.st_ino; - psinfp->ps_mtime = statbuf.st_mtime; - } - else { - perror(bufp); - psinfp->ps_dev = 0; - psinfp->ps_ino = 0; - psinfp->ps_mtime = 0; - } - - /* check for compressed files */ - - len = strlen(filename); - magic1 = '\037'; - magic3 = '\0'; - 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)) - || (len > 4 && strcmp(filename + len - 4, ".bz2") == 0 - && (argv[0] = BUNZIP2, magic1 = 'B', magic2 = 'Z', - magic3 = 'h', True))) { - if (getc(f) != magic1 || (char)getc(f) != magic2 - || (magic3 != '\0' && getc(f) != magic3)) { - rewind(f); - } - else { - pid_t pid; - int status; - - fclose(f); - - fd = ps_new_tempfile(psinfp); - if (fd == -1) { /* if error */ - clear_psinfo_node(psinfp); - return; - } - argv[2] = bufp; - fflush(stderr); /* avoid double flushing */ - pid = vfork(); - if (pid == 0) { /* if child */ - (void)dup2(fd, 1); - (void)execvp(argv[0], (char **)argv); - XDVI_ERROR((stderr, "Execvp of %s failed: %s", argv[0], - strerror(errno))); - _exit(EXIT_FAILURE); - } - (void)close(fd); - - for (;;) { -#if HAVE_WAITPID - if (waitpid(pid, &status, 0) != -1) - break; -#else -# if HAVE_WAIT4 - if (wait4(pid, &status, 0, (struct rusage *)NULL) - != -1) - break; -# else - int retval; - - retval = wait(&status); - if (retval == pid) - break; - if (retval != -1) - continue; -# endif /* HAVE_WAIT4 */ -#endif /* HAVE_WAITPID */ - if (errno == EINTR) - continue; - perror("[xdvik] waitpid"); - return; - } - f = XFOPEN(psinfp->tempname, OPEN_MODE); - if (f == NULL) { - perror(psinfp->tempname); - draw_bbox(); - return; - } - bufp = psinfp->tempname; - } - } - } - /* Success! */ - psp.drawfile(bufp, f); /* this is supposed to close the file */ - } -} - - -void -ps_destroy(void) -{ - /* Note: old NeXT systems (at least) lack atexit/on_exit. */ - psp.destroy(); - ps_clear_cache(); -} - - -/* - * Same as above, but refrains from calling free() (may be called - * following a seg fault). - */ - -void -ps_destroy_nofree(void) -{ - psp.destroy(); - ps_clear_cache_nofree(); -} - - -#endif /* PS */ - - -void -init_prescan(void) -{ - scanned_page = scanned_page_reset = resource.prescan ? -1 : total_pages + 1; -#if PS - scanned_page_ps = scanned_page_ps_bak = scanned_page; -#if COLOR - scanned_page_color = scanned_page; -#endif /* COLOR */ -#endif /* PS */ - - TRACE_FILES((stderr, "init_prescan: scanned_page = %d", scanned_page)); -#if PS - if (resource.postscript == 0) - scanned_page_ps = total_pages + 1; - - ps_clear_cache(); - psp.newdoc(); -#endif - -#if COLOR - if (!resource.use_color) - scanned_page_color = total_pages + 1; -#endif - - if (ignore_papersize_specials) { -#if PS && COLOR - scanned_page = scanned_page_ps < scanned_page_color ? scanned_page_ps : scanned_page_color; -#elif PS - scanned_page = scanned_page_ps; -#elif COLOR - scanned_page = scanned_page_color; -#else - scanned_page = total_pages + 1; -#endif - } -} - - -static void -psfig_special(char *cp) -{ - char *filename; - int raww, rawh; - - if (strncmp(cp, ":[begin]", 8) == 0) { - cp += 8; - bbox_valid = False; - bbox_angle = 0; - 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 (INSIDE_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((int)*cp)) - cp++; - /* handle "`zcat file". Borrowed from dvipsk... */ - if (*cp == '"') { - cp++; - for (filename = cp; *cp && (*cp != '"'); ++cp); - } - else { - for (filename = cp; *cp && !isspace((int)*cp); ++cp); - } - *cp = '\0'; -#if PS - if (INSIDE_MANE_WIN) - send_ps_file(filename, kpse_pict_format); -#endif - } - else if (strncmp(cp, ":[end]", 6) == 0) { - cp += 6; -#if PS - if (INSIDE_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 (ps_parseraw(cp)) - have_raw_postscript = True; - if (INSIDE_MANE_WIN) - psp.drawraw(cp); -#endif - } - else { /* attempt to parse pstricks color specials */ -#if COLOR - struct rgb color; - if (parse_color(cp, cp, &color, True)) { - /* clear stack */ - if (rcs_head == NULL) { - rcs_head = xmalloc(sizeof *rcs_head); - rcs_head->prev = rcs_head->next = NULL; - } - rcs_top = rcs_head; - color_bot_size = 0; - - /* Change top of stack */ - rcs_top->color = color; - - set_fg_color(&color); - } -#endif - /* also raw PostScript, but no extra colon to skip */ -#if PS - if (INSIDE_MANE_WIN) { - if (ps_parseraw(cp)) - have_raw_postscript = True; - - 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 const 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(char *cp) -{ - char *filename; - static char *buffer; - static unsigned int buflen = 0; - unsigned int len; - char *q; - int flags = 0; - double keyval[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - - filename = cp; - if (*cp == '\'' || *cp == '"') { - do - ++cp; - while (*cp != '\0' && *cp != *filename); - ++filename; - } - else - while (*cp != '\0' && !isspace((int)*cp)) - ++cp; - if (*cp != '\0') - *cp++ = '\0'; - while (isspace((int)*cp)) - ++cp; - len = strlen(cp) + NKEYS + 30; - if (buflen < len) { - if (buflen != 0) - free(buffer); - buflen = len; - buffer = xmalloc(buflen); - } - strcpy(buffer, "@beginspecial"); - q = buffer + strlen(buffer); - while (*cp != '\0') { - char *p1 = cp; - size_t keyno; - - while (*p1 != '=' && !isspace((int)*p1) && *p1 != '\0') - ++p1; - for (keyno = 0;; ++keyno) { - if (keyno >= NKEYS) { - if (globals.warn_spec_now) - XDVI_WARNING((stderr, "Ignoring unknown keyword (%.*s) in \\special", - (int)(p1 - cp), cp)); - break; - } - if (memcmp(cp, keytab[keyno], p1 - cp) == 0) { - if (keyno >= N_ARGLESS_KEYS) { - while (isspace((int)*p1)) - ++p1; - if (*p1 == '=') { - ++p1; - while (isspace((int)*p1)) - ++p1; - } - if (keyno < N_ARGLESS_KEYS + 6) { - keyval[keyno - N_ARGLESS_KEYS] = atof(p1); - flags |= (1 << (keyno - N_ARGLESS_KEYS)); - } - *q++ = ' '; - while (!isspace((int)*p1) && *p1 != '\0') - *q++ = *p1++; - } - *q++ = ' '; - *q++ = '@'; - strcpy(q, keytab[keyno]); - q += strlen(q); - break; - } - } - cp = p1; - while (!isspace((int)*cp) && *cp != '\0') - ++cp; - while (isspace((int)*cp)) - ++cp; - } - strcpy(q, " @setspecial\n"); - - bbox_valid = False; - /* Validate the case where both rwi and rhi are undefined - * (and llx, lly, urx, ury are properly defined) */ - if (!(flags & 0x30) && (flags & 0xf) == 0xf) { - KEY_RWI = (KEY_URX - KEY_LLX) * 10; - flags |= 0x10; - } - 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 / currwin.shrinkfactor + 0.5; - bbox_voffset = bbox_height = - 0.1 * ((flags & 0x20) ? KEY_RHI : KEY_RWI * (KEY_URY - KEY_LLY) / - (KEY_URX - KEY_LLX)) - * dimconv / currwin.shrinkfactor + 0.5; - } - - if (INSIDE_MANE_WIN) { -#if PS - psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, buffer); - /* talk directly with the DPSHandler here */ - send_ps_file(filename, kpse_pict_format); - psp.drawend(" @endspecial"); -#else - draw_bbox(); -#endif - } - bbox_valid = False; -} - - -static void -quote_special(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(char *cp) -{ - char *filename; - /* default for .pro files: */ - kpse_file_format_type our_format; - -#if PS_GS - if (gs_postpone_prescan) - return; -#endif - filename = cp; - if (*cp == '\'' || *cp == '"') { - do - ++cp; - while (*cp != '\0' && *cp != *filename); - *cp = '\0'; - ++filename; - } - - psp.beginheader(); - /* check for suffixes other than `.pro' (default PS headers), - case-insensitive */ - if (str_is_suffix(".pfa", filename, False) - || str_is_suffix(".pfb", filename, False)) - our_format = kpse_type1_format; - else if (str_is_suffix(".enc", filename, False)) - our_format = kpse_enc_format; - else - our_format = kpse_tex_ps_header_format; - - send_ps_file(filename, our_format); -} - -static void -scan_bang(char *cp) -{ - psp.beginheader(); - psp.drawraw(cp + 1); -} - -#endif /* PS */ - -#if COLOR - -/* - * Table of dvips color names. Produced by passing the table in - * dvipsk/color.lpro through the following perl script, and then - * through sort. - * - * #! /usr/bin/perl -w - * - * sub cvpart { - * return $_[0] < 1.0 ? 1.0 - $_[0] : 0.0; - * } - * - * $pat = "^\\/(\\w+)\\s*\\{\\s*([0-9.]+)\\s*([0-9.]+)\\s*([0-9.]+)" - * . "\\s*([0-9.]+)\\s*setcmykcolor\\s*\\}\\s*DC\\s*\$"; - * while (<STDIN>) { - * chop; - * if (/^%%/) {next;} - * if (/$pat/o) { - * printf "\t\tDVIPSCOLORDESC(%2d, \"%s\", %g, %g, %g),\n", - * length($1), $1, - * cvpart($2 + $5), cvpart($3 + $5), cvpart($4 + $5); - * } - * else { - * print "Bad line: ", $_, "\n"; - * } - * } - */ - -struct dvipscolor { - const char *name; - struct rgb color; -}; - -static Boolean -parse_color(const char *cp0, const char *cp, - struct rgb *rgbp, Boolean generic_ps_flag) -{ - double r, g, b; - double k; - double hue, sat, bri; - char dummy[8]; - -#define CVPART(x) ((int)((x) * 65535 + 0.5)) -#define COLOR_DESC(name, r, g, b) \ - {name, {CVPART(r), CVPART(g), CVPART(b)}} - - /* hash table to speed up lookup in following list of color names */ - static hashTableT colornames_hash; - /* - Use a prime close to sizof colornames / sizeof colornames[0]. - You might want to update this when extending the colornames array, - and to check the filling factor and average chain length by uncommenting the - hash_print(colornames_hash, True); - below. I usually go for filling > 50% and avg. chain len < 2. - - The 68-elem array below results in: - 79 buckets, 43 nonempty (54%); 68 entries, average chain 1.6. - */ - static const size_t colornames_hash_size = 79; - - static struct dvipscolor colornames[] = { - COLOR_DESC("Red", 1, 0, 0), - COLOR_DESC("Tan", 0.86, 0.58, 0.44), - COLOR_DESC("Blue", 0, 0, 1), - COLOR_DESC("Cyan", 0, 1, 1), - COLOR_DESC("Gray", 0.5, 0.5, 0.5), - COLOR_DESC("Plum", 0.5, 0, 1), - COLOR_DESC("Black", 0, 0, 0), - COLOR_DESC("Brown", 0.4, 0, 0), - COLOR_DESC("Green", 0, 1, 0), - COLOR_DESC("Melon", 1, 0.54, 0.5), - COLOR_DESC("Peach", 1, 0.5, 0.3), - COLOR_DESC("Sepia", 0.3, 0, 0), - COLOR_DESC("White", 1, 1, 1), - COLOR_DESC("Maroon", 0.68, 0, 0), - COLOR_DESC("Orange", 1, 0.39, 0.13), - COLOR_DESC("Orchid", 0.68, 0.36, 1), - COLOR_DESC("Purple", 0.55, 0.14, 1), - COLOR_DESC("Salmon", 1, 0.47, 0.62), - COLOR_DESC("Violet", 0.21, 0.12, 1), - COLOR_DESC("Yellow", 1, 1, 0), - COLOR_DESC("Apricot", 1, 0.68, 0.48), - COLOR_DESC("Emerald", 0, 1, 0.5), - COLOR_DESC("Fuchsia", 0.45, 0.01, 0.92), - COLOR_DESC("Magenta", 1, 0, 1), - COLOR_DESC("SkyBlue", 0.38, 1, 0.88), - COLOR_DESC("Thistle", 0.88, 0.41, 1), - COLOR_DESC("BrickRed", 0.72, 0, 0), - COLOR_DESC("Cerulean", 0.06, 0.89, 1), - COLOR_DESC("Lavender", 1, 0.52, 1), - COLOR_DESC("Mahogany", 0.65, 0, 0), - COLOR_DESC("Mulberry", 0.64, 0.08, 0.98), - COLOR_DESC("NavyBlue", 0.06, 0.46, 1), - COLOR_DESC("SeaGreen", 0.31, 1, 0.5), - COLOR_DESC("TealBlue", 0.12, 0.98, 0.64), - COLOR_DESC("BlueGreen", 0.15, 1, 0.67), - COLOR_DESC("CadetBlue", 0.38, 0.43, 0.77), - COLOR_DESC("Dandelion", 1, 0.71, 0.16), - COLOR_DESC("Goldenrod", 1, 0.9, 0.16), - COLOR_DESC("LimeGreen", 0.5, 1, 0), - COLOR_DESC("OrangeRed", 1, 0, 0.5), - COLOR_DESC("PineGreen", 0, 0.75, 0.16), - COLOR_DESC("RawSienna", 0.55, 0, 0), - COLOR_DESC("RedOrange", 1, 0.23, 0.13), - COLOR_DESC("RedViolet", 0.59, 0, 0.66), - COLOR_DESC("Rhodamine", 1, 0.18, 1), - COLOR_DESC("RoyalBlue", 0, 0.5, 1), - COLOR_DESC("RubineRed", 1, 0, 0.87), - COLOR_DESC("Turquoise", 0.15, 1, 0.8), - COLOR_DESC("VioletRed", 1, 0.19, 1), - COLOR_DESC("Aquamarine", 0.18, 1, 0.7), - COLOR_DESC("BlueViolet", 0.1, 0.05, 0.96), - COLOR_DESC("DarkOrchid", 0.6, 0.2, 0.8), - COLOR_DESC("OliveGreen", 0, 0.6, 0), - COLOR_DESC("Periwinkle", 0.43, 0.45, 1), - COLOR_DESC("Bittersweet", 0.76, 0.01, 0), - COLOR_DESC("BurntOrange", 1, 0.49, 0), - COLOR_DESC("ForestGreen", 0, 0.88, 0), - COLOR_DESC("GreenYellow", 0.85, 1, 0.31), - COLOR_DESC("JungleGreen", 0.01, 1, 0.48), - COLOR_DESC("ProcessBlue", 0.04, 1, 1), - COLOR_DESC("RoyalPurple", 0.25, 0.1, 1), - COLOR_DESC("SpringGreen", 0.74, 1, 0.24), - COLOR_DESC("YellowGreen", 0.56, 1, 0.26), - COLOR_DESC("MidnightBlue", 0, 0.44, 0.57), - COLOR_DESC("YellowOrange", 1, 0.58, 0), - COLOR_DESC("CarnationPink", 1, 0.37, 1), - COLOR_DESC("CornflowerBlue", 0.35, 0.87, 1), - COLOR_DESC("WildStrawberry", 1, 0.04, 0.61), - }; -#undef CVPART -#undef COLOR_DESC - - UNUSED(cp0); - - while (*cp == ' ') ++cp; - - if (generic_ps_flag) { - /* - check for pstricks color specials. - The dummy buffer is to ensure that there are no other (general PS) - commands following (we wouldn't know how to deal with these). - */ - if (sscanf(cp, "%lf %lf %lf setrgbcolor %7s", &r, &g, &b, dummy) == 3 - && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1) { - rgbp->r = r * 65535 + 0.5; - rgbp->g = g * 65535 + 0.5; - rgbp->b = b * 65535 + 0.5; - return True; - } - else if (sscanf(cp, "%lf %lf %lf %lf setcmykcolor %7s", &r, &g, &b, &k, dummy) == 4 - && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1 - && k >= 0 && k <= 1) { - r = 1.0 - r - k; /* cyan --> red */ - rgbp->r = (r < 0 ? 0 : r * 65535 + 0.5); - g = 1.0 - g - k; /* magenta --> green */ - rgbp->g = (g < 0 ? 0 : g * 65535 + 0.5); - b = 1.0 - b - k; /* yellow --> blue */ - rgbp->b = (b < 0 ? 0 : b * 65535 + 0.5); - return True; - } - else if (sscanf(cp, "%lf %lf %lf sethsbcolor %7s", &hue, &sat, &bri, dummy) == 3 && hue >= 0 - && hue <= 1 && sat >= 0 && sat <= 1 && bri >= 0 && bri <= 1) { - int h = (int) (6 * hue); - double p = bri * (1 - sat); - double q = bri * (1 - sat * (6 * hue - h)); - double t = p - q + bri; - - switch (h) { - case 0: r = bri; g = t; b = p; break; /* Red - Yel */ - case 1: r = q; g = bri; b = p; break; /* Yel - Grn */ - case 2: r = p; g = bri; b = t; break; /* Grn - Cyn */ - case 3: r = p; g = q; b = bri; break; /* Cyn - Blu */ - case 4: r = t; g = p; b = bri; break; /* Blu - Mag */ - case 5: r = bri; g = p; b = q; break; /* Mag - Red */ - case 6: r = bri; g = b = p; break; /* Red */ - } - rgbp->r = r * 65535 + 0.5; - rgbp->g = g * 65535 + 0.5; - rgbp->b = b * 65535 + 0.5; - return True; - } - else if (sscanf(cp, "%lf setgray %7s", &r, dummy) == 1 && r >= 0 && r <= 1) { - rgbp->r = rgbp->g = rgbp->b = r * 65535 + 0.5; - return True; - } - else - return False; - } - - /* no generic PS command; must be a dvips color special */ - - if (memicmp(cp, "rgb ", 4) == 0) { - if (sscanf(cp + 3, "%lf %lf %lf", &r, &g, &b) == 3 - && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1) { - rgbp->r = r * 65535 + 0.5; - rgbp->g = g * 65535 + 0.5; - rgbp->b = b * 65535 + 0.5; - return True; - } - } - else if (memicmp(cp, "gray ", 5) == 0) { - if (sscanf(cp + 4, "%lf", &r) == 1 && r >= 0 && r <= 1) { - rgbp->r = rgbp->g = rgbp->b = r * 65535 + 0.5; - return True; - } - } - else if (memicmp(cp, "cmyk ", 5) == 0) { - if (sscanf(cp + 4, "%lf %lf %lf %lf", &r, &g, &b, &k) == 4 - && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1 - && k >= 0 && k <= 1) { - r = 1.0 - r - k; /* cyan --> red */ - rgbp->r = (r < 0 ? 0 : r * 65535 + 0.5); - g = 1.0 - g - k; /* magenta --> green */ - rgbp->g = (g < 0 ? 0 : g * 65535 + 0.5); - b = 1.0 - b - k; /* yellow --> blue */ - rgbp->b = (b < 0 ? 0 : b * 65535 + 0.5); - return True; - } - } - else if (memicmp(cp, "hsb ", 4) == 0) { - if (sscanf(cp + 3, "%lf %lf %lf", &hue, &sat, &bri) == 3 && hue >= 0 - && hue <= 1 && sat >= 0 && sat <= 1 && bri >= 0 && bri <= 1) { - int h = (int) (6 * hue); - double p = bri * (1 - sat); - double q = bri * (1 - sat * (6 * hue - h)); - double t = p - q + bri; - - switch (h) { - case 0: r = bri; g = t; b = p; break; /* Red - Yel */ - case 1: r = q; g = bri; b = p; break; /* Yel - Grn */ - case 2: r = p; g = bri; b = t; break; /* Grn - Cyn */ - case 3: r = p; g = q; b = bri; break; /* Cyn - Blu */ - case 4: r = t; g = p; b = bri; break; /* Blu - Mag */ - case 5: r = bri; g = p; b = q; break; /* Mag - Red */ - case 6: r = bri; g = b = p; break; /* Red */ - } - rgbp->r = r * 65535 + 0.5; - rgbp->g = g * 65535 + 0.5; - rgbp->b = b * 65535 + 0.5; - return True; - } - } - else { /* is it a dvips color name? */ - size_t idx; - size_t len = 0; - static char *testname = NULL; - static size_t testname_len = 0; - size_t testname_step = 16; - - if (colornames_hash.size == 0) { /* initialize hash table */ - size_t i; - colornames_hash = hash_create(colornames_hash_size); - /* insert color names and array indexes */ - for (i = 0; i < (sizeof colornames / sizeof colornames[0]); i++) { - put_str_int_hash(&colornames_hash, colornames[i].name, i); - } - } - /* uncomment the following to get statistics on hashing: */ - /* hash_print(colornames_hash, True); */ - - /* need to copy to a null-terminated string for hash lookup ... */ - while (isalpha((int)cp[len])) { - ++len; /* get length of color name */ - } - while (len >= testname_len) { - testname_len += testname_step; - testname = xrealloc(testname, testname_len); - } - memcpy(testname, cp, len); - testname[len] = '\0'; - - if (find_str_int_hash(&colornames_hash, testname, &idx)) { - *rgbp = colornames[idx].color; - return True; - } - } - - /* not found */ - XDVI_WARNING((stderr, "Ignoring invalid color name in special `%s'", cp0 == NULL ? "<NULL>" : cp0)); - return False; -} - -void -init_page_colors(struct rgb *foreground, struct rgb *background) -{ - int i; - - page_colors.size = total_pages; - page_colors.stack = xmalloc(page_colors.size * sizeof *page_colors.stack); - - for (i = 0; i <= scanned_page + 1; ++i) { - page_colors.stack[i].bg = *background; - page_colors.stack[i].colorstack = foreground; - page_colors.stack[i].stacksize = 1; - } - for (; i < total_pages; i++) { - page_colors.stack[i].colorstack = NULL; - } - - scanstack_head.color = *foreground; - scanstack_len = 1; /* nothing yet */ - scanstack_current = &scanstack_head; /* stack position */ -} - - -static void -scan_bg_color(const char *cp) -{ - if (!resource.use_color) - return; - - if (page_colors.stack == NULL) - init_page_colors(&fg_initial, &bg_initial); - - ASSERT(scanned_page < (int)page_colors.size, "page_colors.size too small"); - (void) parse_color(cp, cp + 11, &(page_colors.stack[scanned_page + 1].bg), False); -} - -void -scan_color(const char *cp) -{ - const char *cp1 = cp + 6; - - if (!resource.use_color) - return; - - while (*cp1 == ' ') ++cp1; - - if (page_colors.stack == NULL) - init_page_colors(&fg_initial, &bg_initial); - - if (memicmp(cp1, "push ", 5) == 0) { - if (scanstack_current->next == NULL) { /* if at end */ - scanstack_current->next = xmalloc(sizeof *scanstack_current); - scanstack_current->next->prev = scanstack_current; - scanstack_current->next->next = NULL; - } - scanstack_current = scanstack_current->next; - ++scanstack_len; - if (!parse_color(cp, cp1 + 5, &scanstack_current->color, False)) - scanstack_current->color = scanstack_current->prev->color; - } - else if (memicmp(cp1, "pop", 3) == 0) { - if (scanstack_len <= 1) { - XDVI_WARNING((stderr, "Color pop occurred with empty color stack.")); - } - else { - scanstack_current = scanstack_current->prev; - --scanstack_len; - } - } - else { - (void) parse_color(cp, cp1, &scanstack_head.color, False); - if (scanstack_len > 1) { - struct colorframe *cfp; - - XDVI_WARNING((stderr, "Global color change occurred with non-empty color stack!\n" - "Trying to recover by setting all stack entries to that color.")); - for (cfp = scanstack_head.next;; cfp = cfp->next) { - cfp->color = scanstack_head.color; - if (cfp == scanstack_current) break; - } - } - } -} - -void -scan_color_eop(void) -{ - int i; - struct rgb *prev, *p1, *rgbp; - struct colorframe *cf; - - if (page_colors.stack == NULL) - return; - - /* set background color for next page */ - if (scanned_page + 1 < total_pages) { - ASSERT(scanned_page + 1 < (int)page_colors.size, "page_colors.size too small"); - page_colors.stack[scanned_page + 1].bg = page_colors.stack[scanned_page].bg; - } - ASSERT(scanned_page < (int)page_colors.size, "page_colors.size too small"); - /* save the stack contents */ - page_colors.stack[scanned_page].stacksize = scanstack_len; - - prev = &fg_initial; - i = 1; - if (scanned_page > 0) { - prev = page_colors.stack[scanned_page - 1].colorstack; - i = page_colors.stack[scanned_page - 1].stacksize; - } - if (scanstack_len <= i) { - /* try to reuse the previous array */ - p1 = prev; - cf = &scanstack_head; - for (i = 0;;) { - if (p1->r != cf->color.r || p1->g != cf->color.g || p1->b != cf->color.b) - break; - if (++i >= scanstack_len) { /* end loop; reuse memory */ - page_colors.stack[scanned_page].colorstack = prev; - return; /* done */ - } - ++p1; - cf = cf->next; - } - } - page_colors.stack[scanned_page].colorstack = rgbp = xmalloc(scanstack_len * sizeof *rgbp); - cf = &scanstack_head; - for (i = 0; i < scanstack_len; ++i) { - *rgbp++ = cf->color; - cf = cf->next; - } -} - - -/* - * We don't actually do any X calls yet to change colors; that can wait - * until a character or rule needs to be drawn. - */ - -void -set_fg_color(const struct rgb *color) -{ - struct fgrec **fgpp; - - if (fg_current != NULL - && color->r == fg_current->color.r - && color->g == fg_current->color.g - && color->b == fg_current->color.b) { - return; - } - - ASSERT(bg_current != NULL, "Background color not initialized"); - for (fgpp = &bg_current->fg_head;;) { - fg_current = *fgpp; - if (fg_current == NULL) { /* if color is not in list */ - fg_current = *fgpp = xmalloc(sizeof *fg_current); - fg_current->next = NULL; - fg_current->color = *color; - fg_current->pixel_good = False; -#if GREY - fg_current->palette_good = False; -#endif - break; - } - if (fg_current->color.r == color->r - && fg_current->color.g == color->g - && fg_current->color.b == color->b) - break; - fgpp = &fg_current->next; - } - if (globals.debug & DBG_DVI) - printf("Changing fg color to %5d %5d %5d\n", - color->r, color->g, color->b); -} - -#if 0 -static void -show_stack(void) { - struct colorframe *ptr; - int i; - fprintf(stderr, "FG: %d,%d,%d\n", fg_current->color.r, fg_current->color.b, fg_current->color.g); - for (i = 0, ptr = rcs_top; ptr != NULL; ptr = ptr->prev, i++) { - fprintf(stderr, "stack %d: %d,%d,%d\n", i, ptr->color.r, ptr->color.b, ptr->color.g); - } -} -#endif - -void -color_special(const char *cp) -{ - while (*cp == ' ') ++cp; - - if (memicmp(cp, "push ", 5) == 0) { - if (rcs_top == NULL) { - if (rcs_head == NULL) { - rcs_head = xmalloc(sizeof *rcs_head); - rcs_head->prev = rcs_head->next = NULL; - } - rcs_top = rcs_head; - } - else { - struct colorframe *rcs_next; - - rcs_next = rcs_top->next; - if (rcs_next == NULL) { - rcs_next = rcs_top->next = xmalloc(sizeof *rcs_next); - rcs_next->prev = rcs_top; - rcs_next->next = NULL; - } - rcs_top = rcs_next; - } - if (!parse_color(NULL, cp + 5, &rcs_top->color, False)) { - if (rcs_top->prev != NULL) - rcs_top->color = rcs_top->prev->color; - else - rcs_top->color = color_bottom[color_bot_size - 1]; - } - set_fg_color(&rcs_top->color); - } - else if (memicmp(cp, "pop", 3) == 0) { - /* Pop stack */ - if (rcs_top != NULL) { - if (color_bot_size > 0) - rcs_top = rcs_top->prev; - else - return; - } - else if (color_bot_size > 1) - --color_bot_size; - else { - if (scanned_page_reset >= 0) { - /* turn on scanning and redraw the page */ - scanned_page = scanned_page_color = scanned_page_reset = -1; -#if PS - scanned_page_ps = scanned_page; -#endif - /* fprintf(stderr, "forcing redraw!!!\n"); */ - globals.ev.flags |= EV_NEWPAGE; /* force a redraw */ - longjmp(globals.ev.canit, 1); - } - return; - } - /* fprintf(stderr, "bot_size: %d\n", color_bot_size); */ - set_fg_color(rcs_top != NULL ? &rcs_top->color - : &color_bottom[color_bot_size - 1]); - } - else { - struct rgb color; - - if (!parse_color(NULL, cp, &color, False)) - return; - - /* clear stack */ - if (rcs_head == NULL) { - rcs_head = xmalloc(sizeof *rcs_head); - rcs_head->prev = rcs_head->next = NULL; - } - rcs_top = rcs_head; - color_bot_size = 0; - - /* Change top of stack */ - rcs_top->color = color; - - set_fg_color(&color); - } -} - -#endif /* COLOR */ - -static unsigned int -myatopix(const char **pp) -{ -#define SCR_LEN 16 - unsigned int value; - const char *cp = *pp; - char scr[16]; - const char *p0, *p1; - - p0 = cp; - while ((*cp >= '0' && *cp <= '9') || *cp == '.') - ++cp; - p1 = cp; - while (isspace((int)*cp)) - ++cp; - if (*cp >= 'a' && *cp <= 'z' && cp[1] >= 'a' && cp[1] <= 'z') { - /* if units are present */ - if (p1 - p0 <= SCR_LEN - 3) { - sprintf(scr, "%.*s%c%c", (int)(p1 - p0), p0, *cp, cp[1]); - value = atopix(scr); - } - else - value = 0; - cp += 2; - } - else - value = atopix(p0); - - *pp = cp; - return value; -#undef SCR_LEN -} - -static void -scan_papersize(const char *cp0) -{ - const char *cp = cp0; - unsigned int w, h; - double mag = 1.0; - - if (ignore_papersize_specials) - return; - - if (*cp == '*') { - do - ++cp; - while (isspace((int)*cp)); - mag = magnification * .001; - } - - w = myatopix(&cp) * mag + 0.5; - - while (isspace((int)*cp)) - ++cp; - if (*cp == ',') - do - ++cp; - while (isspace((int)*cp)); - - h = myatopix(&cp) * mag + 0.5; - - if (w == 0 || h == 0) - XDVI_WARNING((stderr, "Invalid papersize special `%s'", cp0)); - else { - /* we have a paper size special; disable xdvirc_geometry: - fprintf(stderr, "---------- scanned papersize: %dx%d\n", w, h); - resource.xdvirc_geometry = NULL; - */ - pageinfo_set_page_width(scanned_page + 1, w); - pageinfo_set_window_width(scanned_page + 1, w); - pageinfo_set_page_height(scanned_page + 1, h); - pageinfo_set_window_height(scanned_page + 1, h); - } -} - -/* - * 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(char *cp) -{ - while (isspace((int)*cp)) - ++cp; - if (*cp != '=') - return NULL; - do - ++cp; - while (isspace((int)*cp)); - return cp; -} - -#define CMD(x, y) ((x) << 8 | (y)) - -void -applicationDoSpecial(char *cp, size_t len) -{ - char *p; - - if (globals.debug & DBG_DVI) - printf(" `%s'\n", cp); - - while (isspace((int)*cp)) - ++cp; - - /* Ignore initial "xdvi:" */ - if (memcmp(cp, "xdvi:", 5) == 0) { - cp += 5; - while (isspace((int)*cp)) - ++cp; - } - - /* PostScript specials */ -#ifdef MAGICK - if (resource.useMAGICK) { - if (Magick_parse_special(cp)) - return; - } -#endif - - if (*cp == '"') { - quote_special(cp); - return; - } - if (memicmp(cp, "ps:", 3) == 0) { - cp += 3; - psfig_special(cp); - /* check for hdvips hyperlinks */ - if (memicmp(cp, "sdict begin ", strlen("sdict begin ")) == 0) { - static Boolean warned_hypertex_too_old = False; - char *match = NULL; - if (warned_hypertex_too_old) /* don't continue evaluating links in this case */ - return; - cp += strlen("sdict begin "); - if (memcmp(cp, "H.S", 3) == 0 - || memcmp(cp, "H.R", 3) == 0 - || memcmp(cp, "H.B", 3) == 0 - /* following 2 conditions could be more restrictive: between `begin' and H.A/H.L, - there should be a single number (baselineskip in pt) */ - || (match = strstr(cp, "H.A")) != NULL - || (match = strstr(cp, "H.L")) != NULL - || (match = strstr(cp, "/Action")) != NULL - || (match = strstr(cp, "/Link")) != NULL - || (match = strstr(cp, "/View")) != NULL) { - if (match != NULL) - htex_do_special(match, len - 3 - (match - cp) - strlen("sdict begin ")); - else - htex_do_special(cp, len - strlen("sdict begin ")); - } - else if (!warned_hypertex_too_old && strstr(cp, "HyperStart") != NULL) { - popup_message(globals.widgets.top_level, - MSG_WARN, NULL, - "This DVI was created with a too old version of the `dvips' hyperref driver - " - "disabling hyperlinks.\n" - "To fix this, you should either upgrade to a current version of hyperref " - "(see http://www.tug.org/applications/hyperref/), " - "or use the `hypertex' package option, like this:\n\\usepackage[hypertex]{hyperref}\n" - "(Be aware though that this option won't work for PS->PDF conversion!)"); - warned_hypertex_too_old = True; - } - } - /* When not ignoring SDict entries, the distiller and pagecolor - code in lshort.dvi from CTAN:info/lshort/russian/lshrtdvi.zip - causes a failed assertion for 'color_bot_size > 0' in dvi-draw.c; - there's something wrong with the parsing order/event handling here - (see bug #856547). - But we also don't want those entries to trigger erasepage_gs() - [deleted in r3810], so it's correct to ignore them here. - */ - return; - } - if (memicmp(cp, "psfile", 6) == 0 && (p = endofcommand(cp + 6)) != NULL) { - epsf_special(p); - return; - } - if (memicmp(cp, "html:", 5) == 0) { - htex_do_special(cp + 5, len - 5); - return; - } - -#if COLOR - if (memicmp(cp, "color ", 6) == 0) { - /* fprintf(stderr, "------------- color special\n"); */ - if (resource.use_color) - color_special(cp + 6); - return; - } -#endif - - /* these should have been scanned */ - if (*cp == '!' - || (memicmp(cp, "header", 6) == 0 && endofcommand(cp + 6) != NULL)) { -#ifdef PS - if (resource.postscript != 0 && scanned_page_reset >= 0) { - /* turn on scanning and redraw the page */ - scanned_page = scanned_page_ps = scanned_page_reset = -1; -# if COLOR - scanned_page_color = scanned_page; -# endif - globals.ev.flags |= EV_NEWPAGE; /* force a redraw */ - longjmp(globals.ev.canit, 1); - } -#endif /* PS */ - return; - } - - if (memicmp(cp, "background ", 11) == 0) { -#if COLOR - if (resource.use_color && scanned_page_reset >= 0) { - /* turn on scanning and redraw the page */ - scanned_page = scanned_page_color = scanned_page_reset = -1; -# if PS - scanned_page_ps = scanned_page; -# endif - /* fprintf(stderr, "forcing redraw!\n"); */ - globals.ev.flags |= EV_NEWPAGE; /* force a redraw */ - longjmp(globals.ev.canit, 1); - } -#endif /* COLOR */ - return; - } - - if (memcmp(cp, "papersize", 9) == 0 && endofcommand(cp + 9) != NULL) { - m_have_papersize_special = True; - if (scanned_page_reset >= 0) { - /* turn on scanning and redraw the page */ - scanned_page = scanned_page_reset = -1; -#if PS - scanned_page_ps = scanned_page; -#endif -#if COLOR - scanned_page_color = scanned_page; -#endif - globals.ev.flags |= EV_NEWPAGE; /* force a redraw */ - longjmp(globals.ev.canit, 1); - } - return; - } - - /* tpic specials */ - - if (*cp >= 'a' && *cp <= 'z' && cp[1] >= 'a' && cp[1] <= 'z' && - (isspace((int)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 (memcmp(cp, "src:", 4) == 0) { - have_src_specials = True; - } - else if (globals.warn_spec_now) - XDVI_WARNING((stderr, "Special \"%s\" not implemented.", cp)); -} - -#undef CMD - - -Boolean -scan_special(char *cp, int cp_len, void *data) -{ - char *p; - Boolean dummy_ret = True; /* currently unused; - FIXME: use return value to avoid redundant calls (instead of longjmp()) */ - UNUSED(cp_len); /* TODO: could probably utilize this in call to htex_prescan_special() */ - ASSERT(data != NULL, "Must pass a data pointer when using HTEX"); - - if (globals.debug & DBG_PS) - printf("Scanning special `%s'.\n", cp); - - while (isspace((int)*cp)) - ++cp; - - /* Ignore initial "xdvi:" */ - if (memcmp(cp, "xdvi:", 5) == 0) { - cp += 5; - while (isspace((int)*cp)) - ++cp; - } - - if (memicmp(cp, "ps:", 3) == 0) { - cp += 3; - /* check for hdvips hyperlinks */ - if (memicmp(cp, "sdict begin ", strlen("sdict begin ")) == 0) { - static Boolean hypertex_too_old = False; - char *match = NULL; - cp += strlen("sdict begin "); - - if (strstr(cp, "HyperStart") != NULL) - hypertex_too_old = True; - if (hypertex_too_old) - return False; - - if (memcmp(cp, "H.S", 3) == 0 - || memcmp(cp, "H.R", 3) == 0 - || memcmp(cp, "H.B", 3) == 0 - /* following 2 conditions could be more restrictive: between `begin' and H.A/H.L, - there should be a single number (baselineskip in pt) */ - || (match = strstr(cp, "H.A")) != NULL - || (match = strstr(cp, "H.L")) != NULL - || (match = strstr(cp, "/Action")) != NULL - || (match = strstr(cp, "/Link")) != NULL - || (match = strstr(cp, "/View")) != NULL) { - if (match != NULL) - htex_prescan_special(match, cp_len, data); - else - htex_prescan_special(cp, cp_len, data); - } - } - - } - else if (memicmp(cp, "html:", strlen("html:")) == 0) { - size_t offset = strlen("html:"); -#if 0 - Boolean found = -#endif - htex_prescan_special(cp + offset, cp_len - offset, data); -#if 0 - /* if searching for a specific string, return as soon as it's found - not yet implemented */ - if (my_data != NULL && my_data->scan_type == HTEX_ANCHOR_STRING && found) { - return True; - } -#endif - } - /* do the following only if not searching for an anchor string */ - if (((struct htex_prescan_data *)data)->scan_type != HTEX_ANCHOR_STRING) { -#if PS -# if COLOR - if (scanned_page_ps <= scanned_page) -# endif - { - if (*cp == '!') { - scan_bang(cp); - return dummy_ret; - } - else if (memicmp(cp, "header", 6) == 0 && (p = endofcommand(cp + 6)) != NULL) { - scan_header(p); - return dummy_ret; - } - } -#endif /* PS */ - -#if COLOR -# if PS - if (scanned_page_color <= scanned_page) -# endif - { - if (memicmp(cp, "background ", 11) == 0) { - scan_bg_color(cp); - return dummy_ret; - } - else if (memicmp(cp, "color ", 6) == 0) { - scan_color(cp); - return dummy_ret; - } - } -#endif /* COLOR */ - if (memcmp(cp, "papersize", 9) == 0 && (p = endofcommand(cp + 9)) != NULL) { - m_have_papersize_special = True; - scan_papersize(p); - return dummy_ret; - } - } - return dummy_ret; -} - - -/* #define xspell_conv(n) spell_conv0(n, current_dimconv) */ -#define xpixel_conv(x) ((int) ((x) >> 16)) -#define G_PXL_H xpixel_conv(currinf.data.dvi_h) - -/* cp is not const, because of endofcommand(). */ -void -geom_do_special(struct scan_info *info, char *cp, double current_dimconv) -{ - const char *p; - struct geom_info *g_info = (struct geom_info *)info->data; - - UNUSED(current_dimconv); - - while (isspace((int)*cp)) - ++cp; - - /* Ignore initial "xdvi:" */ - if (memcmp(cp, "xdvi:", 5) == 0) { - cp += 5; - while (isspace((int)*cp)) - ++cp; - } - - if (memicmp(cp, "psfile", 6) == 0 && (p = endofcommand(cp + 6)) != NULL) { - /* compute epsf bounding box */ - char c; - int flags = 0; - double keyval[6]; - - c = *p; - if (c == '\'' || c == '"') { - do - ++p; - while (*p != '\0' && *p != c); - } - else - while (*p != '\0' && !isspace((int)*p)) - ++p; - while (isspace((int)*p)) - ++p; - while (*p != '\0') { - const char *p1 = p; - size_t keyno; - - while (*p1 != '=' && !isspace((int)*p1) && *p1 != '\0') - ++p1; - for (keyno = 0; keyno < NKEYS; ++keyno) { - if (memcmp(p, keytab[keyno], p1 - p) == 0) { - if (keyno >= N_ARGLESS_KEYS) { - while (isspace((int)*p1)) - ++p1; - if (*p1 == '=') { - ++p1; - while (isspace((int)*p1)) - ++p1; - } - if (keyno < N_ARGLESS_KEYS + 6) { - keyval[keyno - N_ARGLESS_KEYS] = atof(p1); - flags |= (1 << (keyno - N_ARGLESS_KEYS)); - } - while (!isspace((int)*p1) && *p1 != '\0') - ++p1; - } - break; - } - } - p = p1; - while (!isspace((int)*p) && *p != '\0') - ++p; - while (isspace((int)*p)) - ++p; - } - - if ((flags & 0x30) == 0x30 || ((flags & 0x30) && (flags & 0xf) == 0xf)) { - long x = G_PXL_H; - long y = PXL_V; - long bbox_w; - long bbox_h; - - bbox_w = 0.1 * ((flags & 0x10) ? KEY_RWI - : KEY_RHI * (KEY_URX - KEY_LLX) / (KEY_URY - - KEY_LLY)) * - dimconv + 0.5; - bbox_h = - 0.1 * ((flags & 0x20) ? KEY_RHI : KEY_RWI * - (KEY_URY - KEY_LLY) / (KEY_URX - KEY_LLX)) - * dimconv + 0.5; - - g_info->geom_box(info, x, y - bbox_h, x + bbox_w, y); - } - } - else if (memicmp(cp, "ps::[begin]", 11) == 0) { - /* compute psfig bounding box */ - long bbox_w, bbox_h; - - if (sscanf(cp + 11, "%ld %ld\n", &bbox_w, &bbox_h) >= 2) { - long x = G_PXL_H; - long y = PXL_V; - - bbox_w = xpixel_conv(spell_conv(bbox_w)); - bbox_h = xpixel_conv(spell_conv(bbox_h)); - - g_info->geom_box(info, x, y, x + bbox_w, y + bbox_h); - } - } -} |