/*========================================================================*\ Copyright (c) 1990-1999 Paul Vojta 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 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 #include #include #include #include #ifndef S_IRUSR #define S_IRUSR 0400 #endif #ifndef S_IWUSR #define S_IWUSR 0200 #endif # if HAVE_SYS_WAIT_H # include # endif # ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) # endif # ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) # endif /* ** Modified 22/3/95. */ /* #ifndef PATH_MAX #define PATH_MAX 512 #endif */ /* #include #include */ /* #define DEFAULT_PS_PATH ".:/usr/local/lib/texmf/dvips" */ /* ** End Modifications */ #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 ARGS((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; /* Unfortunately, these values also appear in dvisun.c */ #define xRESOLUTION (pixels_per_inch/shrink_factor) #define yRESOLUTION (pixels_per_inch/shrink_factor) # if HAVE_VFORK_H # include # endif /* * 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; { int fcx = xconv(fx); int tcx = xconv(tx); int fcy = yconv(fy); int 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; { int cx = xconv(x); int 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("invalid .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() { 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("invalid format for dotted/dashed line: %s", cp); return; } if (path_len <= 1 || inchesperdash <= 0.0) { Warning("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(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("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); 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; 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 /* * Information on how to search for PS header and figure files. */ static _Xconst char no_f_str_ps[] = "/%f"; static void ps_startup ARGS((int, int, _Xconst char *)); static void ps_startup2 ARGS((void)); void NullProc ARGS((void)) {} /* ARGSUSED */ static void NullProc2 ARGS((_Xconst 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; double bbox_matrix[2][2] = {{1.0, 0.0}, {0.0, 1.0}}; Boolean bbox_scaled = False, bbox_rotated = False; #define bbox_xscale bbox_matrix[0][0] #define bbox_yscale bbox_matrix[1][1] void draw_bbox() { int xcorner, ycorner; if (bbox_valid) { xcorner = PXL_H - currwin.base_x; ycorner = PXL_V - currwin.base_y; if (! bbox_rotated) { ycorner -= bbox_voffset * bbox_yscale; XDrawLine(DISP, currwin.win, ruleGC, xcorner, ycorner, xcorner + bbox_width * bbox_xscale, ycorner); XDrawLine(DISP, currwin.win, ruleGC, xcorner + bbox_width * bbox_xscale, ycorner, xcorner + bbox_width * bbox_xscale, ycorner + bbox_height * bbox_yscale); XDrawLine(DISP, currwin.win, ruleGC, xcorner + bbox_width * bbox_xscale, ycorner + bbox_height * bbox_yscale, xcorner, ycorner + bbox_height * bbox_yscale); XDrawLine(DISP, currwin.win, ruleGC, xcorner, ycorner + bbox_height * bbox_yscale, xcorner, ycorner); } else { float a, b, c, d; a = bbox_matrix[0][0] * bbox_width; b = bbox_matrix[1][0] * bbox_width; c = -bbox_matrix[0][1] * bbox_height; d = -bbox_matrix[1][1] * bbox_height; XDrawLine(DISP, currwin.win, ruleGC, xcorner, ycorner, xcorner + (int) rint(a), ycorner + (int) rint(b)); XDrawLine(DISP, currwin.win, ruleGC, xcorner + (int) rint(a), ycorner + (int) rint(b), xcorner + (int) rint(a + c), ycorner + (int) rint(b + d)); XDrawLine(DISP, currwin.win, ruleGC, xcorner + (int) rint(a + c), ycorner + (int) rint(b + d), xcorner + (int) rint(c), ycorner + (int) rint(d)); XDrawLine(DISP, currwin.win, ruleGC, xcorner + (int) rint(c), ycorner + (int) rint(d), xcorner, ycorner); } bbox_valid = False; } } #if PS static XIOErrorHandler oldhandler; static int XDviIOErrorHandler P1C(Display *, disp) { fprintf(stderr,"FOO!\n"); terminate_flag = True; ps_destroy(); /* exit(1); -- should not be needed -- janl 14/4/99 */ return oldhandler(disp); } static void actual_startup() { 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(xul, yul, cp) int xul, yul; _Xconst 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) _Xconst char *cp; {} typedef struct { double matrix[2][2]; double x, y; } ROTATE_STACK; static void ps_parseraw(PostScript_cmd) _Xconst char *PostScript_cmd; { _Xconst char *p; double xscale, yscale, angle, sin_a, cos_a, a, b, c, d; int n; static int rotate_stack_len = 0; static int rotate_stack_ptr = 0; static ROTATE_STACK *rotate_stack = NULL; /* dumb parsing of PostScript - search for rotation H. Zeller 1/97 */ p = strstr(PostScript_cmd, "currentpoint grestore moveto"); if (p != NULL) { if (rotate_stack_ptr > 0) { double r; rotate_stack_ptr--; r = sqrt(((DVI_H - rotate_stack[rotate_stack_ptr].x) * (DVI_H - rotate_stack[rotate_stack_ptr].x) + (DVI_V - rotate_stack[rotate_stack_ptr].y) * (DVI_V - rotate_stack[rotate_stack_ptr].y)) / (bbox_matrix[0][0] * bbox_matrix[0][0] + bbox_matrix[1][0] * bbox_matrix[1][0])) * (rotate_stack[rotate_stack_ptr].matrix[0][0] * bbox_matrix[1][0] - rotate_stack[rotate_stack_ptr].matrix[1][0] * bbox_matrix[0][0]) / (rotate_stack[rotate_stack_ptr].matrix[0][0] * rotate_stack[rotate_stack_ptr].matrix[0][0] + rotate_stack[rotate_stack_ptr].matrix[1][0] * rotate_stack[rotate_stack_ptr].matrix[1][0]); DVI_H += r * rotate_stack[rotate_stack_ptr].matrix[1][0]; DVI_V += r * rotate_stack[rotate_stack_ptr].matrix[0][0]; PXL_V = pixel_conv(DVI_V); bcopy(rotate_stack[rotate_stack_ptr].matrix, bbox_matrix, sizeof(bbox_matrix)); bbox_rotated = (bbox_matrix[0][1] != 0.0 || bbox_matrix[1][0] != 0.0) ? True : False; bbox_scaled = (bbox_rotated || bbox_matrix[0][0] != 1.0 || bbox_matrix[1][1] != 1.0) ? True : False; } if (debug & DBG_PS) Fprintf(stderr, "current angle %lf: %s\n", bbox_matrix[0][0] != 0 ? -atan(bbox_matrix[1][0] / bbox_matrix[0][0]) * (360 / TWOPI) : bbox_matrix[1][0] >= 0 ? (double)90 : (double)-90, PostScript_cmd); } p = strstr(PostScript_cmd, "rotate"); if (p != NULL) { while (*p != '\0' && !isdigit(*p)) --p; while (*p != '\0' && isdigit(*p)) --p; if (*p == '.') --p; while (*p != '\0' && isdigit(*p)) --p; if (*p != '+' && *p != '-') ++p; n = sscanf(p, "%lf neg rotate", &angle); if (n != 1) { Fprintf(stderr, "%s: cannot get angle.\n", prog); angle = 0.0; } if (rotate_stack_ptr >= rotate_stack_len) { rotate_stack_len += 0x10; rotate_stack = (ROTATE_STACK *) xrealloc(rotate_stack, sizeof(ROTATE_STACK) * rotate_stack_len); } bcopy(bbox_matrix, rotate_stack[rotate_stack_ptr].matrix, sizeof(bbox_matrix)); rotate_stack[rotate_stack_ptr].x = DVI_H; rotate_stack[rotate_stack_ptr].y = DVI_V; rotate_stack_ptr++; sin_a = sin(-angle * (TWOPI / 360)); cos_a = cos(-angle * (TWOPI / 360)); a = bbox_matrix[0][0] * cos_a + bbox_matrix[0][1] * sin_a; b = - bbox_matrix[0][0] * sin_a + bbox_matrix[0][1] * cos_a; c = bbox_matrix[1][0] * cos_a + bbox_matrix[1][1] * sin_a; d = - bbox_matrix[1][0] * sin_a + bbox_matrix[1][1] * cos_a; bbox_matrix[0][0] = a; bbox_matrix[0][1] = b; bbox_matrix[1][0] = c; bbox_matrix[1][1] = d; bbox_rotated = (b != 0.0 || c != 0.0) ? True : False; bbox_scaled = (bbox_rotated || bbox_matrix[0][0] != 1.0 || bbox_matrix[1][1] != 1.0) ? True : False; if (debug & DBG_PS) Fprintf(stderr, "current angle %lf: %s\n", bbox_matrix[0][0] != 0 ? -atan(bbox_matrix[1][0] / bbox_matrix[0][0]) * (360 / TWOPI) : bbox_matrix[1][0] >= 0 ? (double)90 : (double)-90, PostScript_cmd); } p = strstr(PostScript_cmd, "scale"); if (p != NULL) { if (strncmp(p - 4, "div", 3) == 0) { while (*p != '\0' && !isdigit(*p)) --p; while (*p != '\0' && isdigit(*p)) --p; if (*p == '.') --p; while (*p != '\0' && isdigit(*p)) --p; while (*p != '\0' && !isdigit(*p)) --p; while (*p != '\0' && isdigit(*p)) --p; while (*p != '\0' && !isdigit(*p)) --p; while (*p != '\0' && isdigit(*p)) --p; if (*p == '.') --p; while (*p != '\0' && isdigit(*p)) --p; while (*p != '\0' && !isdigit(*p)) --p; while (*p != '\0' && isdigit(*p)) --p; ++p; n = sscanf(p, "1 %lf div 1 %lf div scale", &xscale, &yscale); if (n == 2) { xscale = 1.0/xscale; yscale = 1.0/yscale; } else { Fprintf(stderr, "%s: cannot get scaling factors.\n", prog); xscale = yscale = 1.0; } } else { while (*p != '\0' && !isdigit(*p)) --p; while (*p != '\0' && isdigit(*p)) --p; if (*p == '.') --p; while (*p != '\0' && isdigit(*p)) --p; while (*p != '\0' && !isdigit(*p)) --p; while (*p != '\0' && isdigit(*p)) --p; if (*p == '.') --p; while (*p != '\0' && isdigit(*p)) --p; if (*p != '+' && *p != '-') ++p; n = sscanf(p, "%lf %lf scale", &xscale, &yscale); if (n != 2) { Fprintf(stderr, "%s: cannot get scaling factors.\n", prog); xscale = yscale = 1.0; } } bbox_matrix[0][0] *= xscale; bbox_matrix[0][1] *= yscale; bbox_matrix[1][0] *= xscale; bbox_matrix[1][1] *= yscale; bbox_scaled = (bbox_rotated || bbox_matrix[0][0] != 1.0 || bbox_matrix[1][1] != 1.0) ? True : False; if (debug & DBG_PS) Fprintf(stderr, "current scale %lf,%lf: %s\n", bbox_xscale, bbox_yscale, PostScript_cmd); } } /* ARGSUSED */ void #if NeedFunctionPrototypes drawbegin_none(int xul, int yul, _Xconst char *cp) #else /* !NeedFunctionPrototypes */ drawbegin_none(xul, yul, cp) int xul, yul; _Xconst char *cp; #endif /* NeedFunctionPrototypes */ { draw_bbox(); } struct tickrec { struct tickrec *next; int pageno; char *command; char *tmpname; }; 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 static struct tickrec * cachetick(filename, pathinfo, fp) _Xconst char *filename; kpse_file_format_type pathinfo; FILE **fp; { struct tickrec **linkp; struct tickrec *tikp; struct tickrec **freerecp; static int fileno=0; 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 { /* This will overflow when we get 10^9 temporary files. If we have to worry I worry */ char *buffer=malloc(strlen(temporary_dir)+10); tikp = (struct tickrec *) xmalloc(sizeof(struct tickrec)); sprintf(buffer,"%s/%d",temporary_dir,fileno); fileno++; tikp->tmpname = buffer; tikp->pageno = -1; if (tikp->tmpname == NULL) { Fputs("Cannot create temporary file name.\n", stderr); free((char *) tikp); return NULL; } ++nticks; } tikp->command = xmalloc((unsigned) strlen(filename) + 1); 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) { fprintf(stderr,"xdvi: ("__FILE__" at line %d) ",__LINE__); 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 != kpse_tex_ps_header_format ? current_page : -1; return tikp; } #ifndef UNCOMPRESS #define UNCOMPRESS "uncompress" #endif #ifndef GUNZIP #define GUNZIP "gunzip" #endif #ifndef BUNZIP2 #define BUNZIP2 "bunzip2" #endif static void send_ps_file P2C(char *,filename, kpse_file_format_type, pathinfo) { FILE *f; static _Xconst char *argv[] = {NULL, "-c", NULL, NULL}; char *bufp; struct tickrec *tikp; int len; char magic1, magic2, magic3; if (psp.drawfile == NULL || !resource._postscript) return; #ifdef HTEX filename=urlocalize(filename); if (((URLbase != NULL) && htex_is_url(urlocalize(URLbase))) || (htex_is_url(filename))) { /* xfopen knows how to fetch url things */ URL_aware=1; f = xfopen(filename, OPEN_MODE); bufp=filelist[lastwwwopen].file; URL_aware=0; } else #endif if (filename[0] == '`') { if (!resource.allow_shell) { if (warn_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) { len = strlen(filename) + strlen(tikp->tmpname) + (4 - 1); if (len > ffline_len) expandline(len); Sprintf(ffline, "%s > %s", filename + 1, tikp->tmpname); (void) system(ffline); f = xfopen(tikp->tmpname, OPEN_MODE); if (f == NULL) { fprintf(stderr,"xdvi: ("__FILE__" at line %d) ",__LINE__); perror(tikp->tmpname); return; } } bufp = tikp->tmpname; } else { bufp = kpse_find_file (filename, pathinfo, true); f = bufp ? xfopen (bufp, OPEN_MODE) : NULL; /* 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); 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 { 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_EXCL, S_IRUSR | S_IWUSR); if (handle == -1 && errno == EEXIST) { /* The tmpnames are reused for each page so unlink the tmpname file from the previous page */ unlink(tikp->tmpname); handle = open(tikp->tmpname, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); } if (handle == -1) { fprintf(stderr,"xdvi: ("__FILE__" at line %d) ",__LINE__); 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 (;;) { #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(tikp->tmpname, OPEN_MODE); if (f == NULL) { fprintf(stderr,"xdvi: ("__FILE__" at line %d) ", __LINE__); 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; /* Note: old NeXT systems (at least) lack atexit/on_exit. */ psp.destroy(); for (tikp = tickhead; tikp != NULL; tikp = tikp->next) if (unlink(tikp->tmpname) < 0) { fprintf(stderr,"xdvi: ("__FILE__" at line %d) ",__LINE__); 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; /* 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 (currwin.win == mane.win) #if PS psp.drawbegin(PSP_H - currwin.base_x, PSP_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++; /* handle "`zcat file". Borrowed from dvipsk...*/ if (*cp == '"') { cp++; for (filename = cp; *cp && (*cp != '"'); ++cp); } else { for (filename = cp; *cp && !isspace(*cp); ++cp); } *cp = '\0'; #if PS if (currwin.win == mane.win) send_ps_file(filename, kpse_pict_format); #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 { /* I am going to send some raw postscript stuff */ if (*cp == ':') ++cp; /* skip second colon in ps:: */ #if PS if (currwin.win == mane.win) { ps_parseraw(cp); if (psfig_begun) psp.drawraw(cp); else { psp.drawbegin(PSP_H - currwin.base_x, PSP_V - currwin.base_y, cp); psp.drawend(""); } } else ps_parseraw(cp); #endif } } /* Keys for epsf specials */ static _Xconst char *keytab[] = {"clip", "llx", "lly", "urx", "ury", "rwi", "rhi", "hsize", "vsize", "hoffset", "voffset", "hscale", "vscale", "angle"}; #define KEY_LLX keyval[0] #define KEY_LLY keyval[1] #define KEY_URX keyval[2] #define KEY_URY keyval[3] #define KEY_RWI keyval[4] #define KEY_RHI keyval[5] #define KEY_HSZ keyval[6] #define KEY_VSZ keyval[7] #define KEY_HSC keyval[10] #define KEY_VSC keyval[11] #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[12]; 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); } 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 (warn_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 (filename && currwin.win == mane.win) { #if PS psp.drawbegin(PSP_H - currwin.base_x, PSP_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; } /*************************************************************** Following two functions, DirName() and get_boudig_box() come from ps.c in miyu-patch for xdvi PL17. ***************************************************************/ static char * DirName(f1, f2) char *f1; char *f2; { char *p1, *p2, *q1; static char buf[BUFSIZ]; #ifndef VMS if (*f2 == '/') return f2; #endif /* !VMS */ for (p1 = p2 = f1, q1 = buf; *p1; p1++, q1++) { #ifndef VMS if (*p1 == '/') #else if (*p1 == ':') #endif /* !VMS */ p2 = p1 + 1; *q1 = *p1; } Strcpy(buf + (p2 - f1), f2); return buf; } int get_bounding_box(psfile, llx, lly, urx, ury) char *psfile; double *llx; double *lly; double *urx; double *ury; { FILE *fptr; char buf[BUFSIZ]; if ((fptr = xfopen(psfile, "r")) == NULL) { perror(psfile); return -1; } for (;;) { if (fgets(buf, BUFSIZ, fptr) == NULL) { Fprintf(stderr, "%s:unexpected EOF.\n", psfile); Fclose(fptr); return -1; } if (strncmp(buf, "%%BoundingBox:", 14) == 0) { if (sscanf(buf + 14, "%lf %lf %lf %lf", llx, lly, urx, ury) < 4) { Fprintf(stderr, "\\special: ERROR.\n"); Fclose(fptr); return -1; } break; } } Fclose(fptr); return 0; } /*************************************************************** The originai eps_special() is merged with psSpecial() in ps.c (miyu-patch for xdvi PL17). ***************************************************************/ static void epsbox_special(cp) char *cp; { char *filename; static char *buffer = NULL; char *p; char *q; int flags = 0; double keyval[12]; char *tmpfilename; FILE *fp; float hsize = 0.0, vsize = 0.0; float hscale = 0.0, vscale = 0.0; char *ptr; p = cp; if ((ptr = strtok(p, "{}")) == NULL) { Fprintf(stderr, "\\special: ERROR.\n"); return; } hsize = atof(ptr); if ((ptr = strtok(NULL, "{}")) == NULL) { Fprintf(stderr, "\\special: ERROR.\n"); return; } vsize = atof(ptr); if ((ptr = strtok(NULL, "{}")) == NULL) { Fprintf(stderr, "\\special: ERROR.\n"); return; } filename = DirName(dvi_name, ptr); if ((fp = xfopen(filename, "r")) == NULL) { tmpfilename=xmalloc(strlen(filename)+4); strcpy(tmpfilename, filename); strcat(tmpfilename, ".ps"); /* try .ps */ if ((fp = xfopen(tmpfilename, "r")) == NULL) { free(tmpfilename); tmpfilename=xmalloc(strlen(filename)+5); strcpy(tmpfilename, filename); strcat(tmpfilename, ".eps"); /* try .eps */ if ((fp = xfopen(tmpfilename, "r")) == NULL) { free(tmpfilename); tmpfilename=xmalloc(strlen(filename)+6); strcpy(tmpfilename, filename); strcat(tmpfilename, ".epsf"); /* try .epsf */ if ((fp = xfopen(tmpfilename, "r")) == NULL) { perror(tmpfilename); return; } else { strcpy(filename, tmpfilename); } } else { strcpy(filename, tmpfilename); } } else { strcpy(filename, tmpfilename); } free(tmpfilename); } Fclose(fp); if (get_bounding_box(filename, &KEY_LLX, &KEY_LLY, &KEY_URX, &KEY_URY)) return; if (hsize != 0.0) hscale = hsize / (KEY_URX - KEY_LLX); if (vsize != 0.0) vscale = vsize / (KEY_URY - KEY_LLY); if (hscale == 0.0 && vscale == 0.0) hscale = vscale = 1.0; else if (hscale == 0.0) hscale = vscale; else if (vscale == 0.0) vscale = hscale; KEY_RWI = hsize; KEY_RHI = vsize; if (buffer == NULL) buffer = xmalloc(BUFSIZ); Strcpy(buffer, "@beginspecial"); q = buffer + strlen(buffer); sprintf(q, " /@scaleunit 1 def"); q += strlen(q); sprintf(q, " %lf @hoffset", -KEY_LLX * hscale); q += strlen(q); sprintf(q, " %lf @voffset", -KEY_LLY * vscale); q += strlen(q); sprintf(q, " %lf @hscale", hscale); q += strlen(q); sprintf(q, " %lf @vscale", vscale); q += strlen(q); Strcpy(q, " @setspecial\n"); bbox_valid = True; bbox_width = hsize * dimconv / shrink_factor + 0.5; bbox_voffset = bbox_height = vsize * dimconv / shrink_factor + 0.5; if (currwin.win == mane.win) { #if PS psp.drawbegin(PSP_H - currwin.base_x, PSP_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 elepsf_special(cp) char *cp; { char *filename; static char *buffer; static unsigned int buflen = 0; unsigned int len; char *p; char *q; int flags = 0; double keyval[12] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; float hsize = 0.0, vsize = 0.0; float hscale = 0.0, vscale = 0.0; p = cp; filename = p; if (*p == '\'' || *p == '"') { do ++p; while (*p != '\0' && *p != *filename); ++filename; } else while (*p != '\0' && *p != ' ' && *p != '\t') ++p; if (*p != '\0') *p++ = '\0'; while (*p == ' ' || *p == '\t') ++p; filename = DirName(dvi_name, filename); if (get_bounding_box(filename, &KEY_LLX, &KEY_LLY, &KEY_URX, &KEY_URY)) return; len = strlen(p) + NKEYS + 512; if (buflen < len) { if (buflen != 0) free(buffer); buflen = len; buffer = xmalloc(buflen); } Strcpy(buffer, "@beginspecial"); q = buffer + strlen(buffer); sprintf(q, " /@scaleunit 1 def"); q += strlen(q); while (*p != '\0') { char *p1 = p; int keyno; while (*p1 != '=' && !isspace(*p1) && *p1 != '\0') ++p1; for (keyno = 0;; ++keyno) { if (keyno >= NKEYS) { if (warn_spec_now) Fprintf(stderr, "unknown keyword (%*s) in \\special will be ignored\n", (int) (p1 - p), p); break; } if (memcmp(p, keytab[keyno], p1 - p) == 0) { if (keyno >= N_ARGLESS_KEYS) { if (*p1 == '=') ++p1; if (keyno < N_ARGLESS_KEYS + 12) { keyval[keyno - N_ARGLESS_KEYS] = atof(p1); flags |= (1 << (keyno - N_ARGLESS_KEYS)); } *q++ = ' '; while (!isspace(*p1) && *p1 != '\0') p1++; } break; } } p = p1; while (!isspace(*p) && *p != '\0') ++p; while (isspace(*p)) ++p; } hsize = KEY_HSZ; vsize = KEY_VSZ; hscale = KEY_HSC; vscale = KEY_VSC; if (hsize != 0.0) hscale = hsize / (KEY_URX - KEY_LLX); if (vsize != 0.0) vscale = vsize / (KEY_URY - KEY_LLY); KEY_RWI = KEY_URX - KEY_LLX; KEY_RHI = KEY_URY - KEY_LLY; if (hscale == 0.0 && vscale == 0.0) hscale = vscale = 1.0; else if (hscale == 0.0) hscale = vscale; else if (vscale == 0.0) vscale = hscale; KEY_RHI *= vscale; KEY_RWI *= hscale; sprintf(q, " %lf @hoffset", -KEY_LLX * hscale); q += strlen(q); sprintf(q, " %lf @voffset", -KEY_URY * vscale); q += strlen(q); sprintf(q, " %lf @hscale", hscale); q += strlen(q); sprintf(q, " %lf @vscale", vscale); q += strlen(q); Strcpy(q, " @setspecial\n"); bbox_valid = True; bbox_width = KEY_RWI * dimconv / shrink_factor + 0.5; bbox_voffset = 0.0; bbox_height = KEY_RHI * dimconv / shrink_factor + 0.5; if (currwin.win == mane.win) { #if PS psp.drawbegin(PSP_H - currwin.base_x, PSP_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(cp) char *cp; { bbox_valid = False; #if PS if (currwin.win == mane.win) { psp.drawbegin(PSP_H - currwin.base_x, PSP_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(); send_ps_file(filename, kpse_tex_ps_header_format); } static void scan_bang(cp) char *cp; { psp.beginheader(); psp.drawraw(cp + 1); } #endif /* PS */ /* ** Modified 22/3/95. */ typedef struct psh_node { char *this_file; struct psh_node *next; } t_pshnode; static t_pshnode *psh_head = (t_pshnode *) NULL, *psh_tail = (t_pshnode *) NULL; /* ** Include one header file. */ static void psh_includehfile(cp, beginning) char *cp; int beginning; { static char rawstring[] = " stop\n%%xdvimark\nH userdict begin\0"; if (!beginning) psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, ""); psp.drawraw(rawstring); send_ps_file(cp, kpse_pict_format); psp.drawend(" end\n"); } /* ** Include all header files. */ void psh_includeall() { t_pshnode *this_node; this_node = psh_head; while (this_node != (t_pshnode *) NULL) { psh_includehfile(this_node->this_file, 1); this_node = this_node->next; } } /* ** Deal with the "header=" special. */ static void psh_header(cp) char *cp; { t_pshnode *this_node; char *psheader; /* ** Find the file. */ psheader = kpse_find_file ( cp+7, kpse_tex_ps_header_format, true ); if (psheader) { /* ** Include the file directly in /userdict. */ /* psh_includehfile(psheader, 0); */ /* deleted by Kazuaki NAKAYAMA (nakayama@ripms.shinshu-u.ac.jp) */ /* ** Add a new node to the list of header files. */ this_node = (t_pshnode *) xmalloc(sizeof(t_pshnode)); this_node->this_file = strcpy(xmalloc((strlen(psheader) + 1) * sizeof(char)), psheader); this_node->next = (t_pshnode *) NULL; if (psh_head == (t_pshnode *) NULL) psh_head = psh_tail = this_node; else { psh_tail->next = this_node; psh_tail = this_node; } } else Warning("Included PostScript header file %s not found", cp + 7); } /* ** End Modifications */ /* color support (^^;)*/ #ifdef COLOR void InitColorStack() { int i; if (use_color) { color_warn_done = False; page_color = xmalloc((unsigned) (total_pages + 1) * sizeof(PAGE_COLOR)); page_color[0].color_stack = xmalloc(sizeof(XColor)); page_color[0].color_stack[0].pixel = resource._fore_Pixel; XQueryColor(DISP, our_colormap, &page_color[0].color_stack[0]); page_color[0].background.pixel = resource._back_Pixel; XQueryColor(DISP, our_colormap, &page_color[0].background); page_color[0].stack_top = 0; for (i = 1; i <= total_pages; i++) page_color[i].color_stack = NULL; scanned_page = scanned_page_bak = scanned_page_reset = resource.prescan ? -1 : total_pages; } else page_color = NULL; } /* Cyan/Magenta/Yellow/Black to Red/Green/Blue */ static void cmyk_to_rgb(c, m, y, k, r, g, b) double c, m, y, k; double *r, *g, *b; { double red, green, blue; if (k > 0.9999) { red = green = blue = 0.0; } else if (k < 0.0001) { red = 1.0 - c; green = 1.0 - m; blue = 1.0 - y; } else { red = (1.0 - c) * (1.0 - k); green = (1.0 - m) * (1.0 - k); blue = (1.0 - y) * (1.0 - k); } *r = (red < 0.0) ? 0.0 : (red > 1.0) ? 1.0 : red; *g = (green < 0.0) ? 0.0 : (green > 1.0) ? 1.0 : green; *b = (blue < 0.0) ? 0.0 : (blue > 1.0) ? 1.0 : blue; } /* Hue/Saturation/Brightness to Red/Green/Blue */ static void hsb_to_rgb(h, s, v, r, g, b) double h, s, v; double *r, *g, *b; { double red, green, blue, h6, f, p, q, t; if (s < 0.0001) { red = green = blue = v; } else { h6 = h * 6.0; f = h6 - (int)h6; p = v * (1.0 - s); q = v * (1.0 - s * f); t = p - q + v; switch ((int)h6) { case 0: red = v; green = t; blue = p; break; /* Red - Yellow */ case 1: red = q; green = v; blue = p; break; /* Yellow - Green */ case 2: red = p; green = v; blue = t; break; /* Green - Cyan */ case 3: red = p; green = q; blue = v; break; /* Cyan - Blue */ case 4: red = t; green = p; blue = v; break; /* Blue - Magenta */ case 5: red = v; green = p; blue = q; break; /* Magenta - Red */ default: red = green = blue = 0.0; break; } } *r = (red < 0.0) ? 0.0 : (red > 1.0) ? 1.0 : red; *g = (green < 0.0) ? 0.0 : (green > 1.0) ? 1.0 : green; *b = (blue < 0.0) ? 0.0 : (blue > 1.0) ? 1.0 : blue; } static void color_warn() { Puts("Cannot allocate colormap entry: displayed colors are not exact.\n\ That is because other applications may be using too many colors.\n\ If you want more exact colors, let such a application exit and \"Reread\"."); fflush(stdout); } #endif static void color_special(cp, scanning) char *cp; Boolean scanning; { #ifdef COLOR XColor color, fc, bc; char *ptr; char buf[BUFSIZ]; double r, g, b; if (!use_color) return; if (scanned_page_reset >= 0) { /* turn on scanning and redraw the page */ scanned_page = scanned_page_bak = scanned_page_reset = -1; canit = True; longjmp(canit_env, 1); /* not reach */ return; } while (*cp && isspace(*cp)) cp++; if (strncmp(cp, "push", 4) == 0) { cp += 4; while (*cp && isspace(*cp)) cp++; ptr = cp; r = g = b = 0.0; if (strncmp(ptr, "rgb", 3) == 0) { sscanf(cp + 3, " %lf %lf %lf", &r, &g, &b); sprintf(buf, "rgbi:%lf/%lf/%lf", r, g, b); ptr = buf; } else if (strncmp(ptr, "gray", 4) == 0) { r = g = b = atof(cp + 4); sprintf(buf, "rgbi:%lf/%lf/%lf", r, g, b); ptr = buf; } else if (strncmp(ptr, "cmyk", 4) == 0) { double c, m, y, k; c = m = y = k = 0.0; sscanf(cp + 4, " %lf %lf %lf %lf", &c, &m, &y, &k); cmyk_to_rgb(c, m, y, k, &r, &g, &b); sprintf(buf, "rgbi:%lf/%lf/%lf", r, g, b); ptr = buf; } else if (strncmp(ptr, "hsb", 3) == 0) { double h, s, v; h = s = v = 0.0; sscanf(cp + 3, " %lf %lf %lf", &h, &s, &v); hsb_to_rgb(h, s, v, &r, &g, &b); sprintf(buf, "rgbi:%lf/%lf/%lf", r, g, b); ptr = buf; } if (color_stack_top >= color_stack_len) { color_stack_len += 0x10; color_stack = (XColor *) xrealloc(color_stack, sizeof(XColor) * color_stack_len); } #if 0 /* Because GCFunction might be GXandInverted, GCForeground might be a correct pixel value. (see init_colors().) */ XGetGCValues(DISP, foreGC, GCForeground, &values); color_stack[stack_top++] = values.foreground; #else color_stack[color_stack_top++] = fore_color_data; #endif fore_color_data.red = (unsigned short)(r * ((unsigned short)~0) +.5); fore_color_data.green = (unsigned short)(g * ((unsigned short)~0) +.5); fore_color_data.blue = (unsigned short)(b * ((unsigned short)~0) +.5); if (XAllocNamedColor(DISP, our_colormap, ptr, &fc, &bc) == True) { if (color_allocated_top >= color_allocated_len) { color_allocated_len += 0x10; color_allocated = (Pixel *) xrealloc(color_allocated, sizeof(Pixel) * color_allocated_len); } if (ptr != buf) fore_color_data = fc; color_allocated[color_allocated_top++] = fore_color_data.pixel = fc.pixel; if (!scanning) { init_colors(); reset_fonts(); } } else if (!color_warn_done) { color_warn(); color_warn_done = True; } } else if (strncmp(cp, "pop", 3) == 0) { if (color_stack_top) { fore_color_data = color_stack[--color_stack_top]; if (!scanning) { init_colors(); reset_fonts(); } } else Fprintf(stderr, "%s : color: too many 'pop'\n", prog); } else { if (XAllocNamedColor(DISP, our_colormap, cp, &fc, &bc) == True) { if (color_allocated_top >= color_allocated_len) { color_allocated_len += 0x10; color_allocated = (Pixel *) xrealloc(color_allocated, sizeof(Pixel) * color_allocated_len); } fore_color_data = fc; color_allocated[color_allocated_top++] = fc.pixel; if (!scanning) { init_colors(); reset_fonts(); } } else if (!color_warn_done) { color_warn(); color_warn_done = True; } } #endif } #ifdef COLOR static void background_special(cp) char *cp; { XColor color, fc, bc; char *ptr; char buf[BUFSIZ]; double r, g, b; if (!use_color) return; if (scanned_page_reset >= 0) { /* turn on scanning and redraw the page */ scanned_page = scanned_page_bak = scanned_page_reset = -1; canit = True; longjmp(canit_env, 1); /* not reach */ return; } while (*cp && isspace(*cp)) cp++; ptr = cp; r = g = b = 0.0; if (strncmp(ptr, "rgb", 3) == 0) { sscanf(cp + 3, " %lf %lf %lf", &r, &g, &b); sprintf(buf, "rgbi:%lf/%lf/%lf", r, g, b); ptr = buf; } else if (strncmp(ptr, "gray", 4) == 0) { r = g = b = atof(cp + 4); sprintf(buf, "rgbi:%lf/%lf/%lf", r, g, b); ptr = buf; } else if (strncmp(ptr, "cmyk", 4) == 0) { double c, m, y, k; c = m = y = k = 0.0; sscanf(cp + 4, " %lf %lf %lf %lf", &c, &m, &y, &k); cmyk_to_rgb(c, m, y, k, &r, &g, &b); sprintf(buf, "rgbi:%lf/%lf/%lf", r, g, b); ptr = buf; } else if (strncmp(ptr, "hsb", 3) == 0) { double h, s, v; h = s = v = 0.0; sscanf(cp + 3, " %lf %lf %lf", &h, &s, &v); hsb_to_rgb(h, s, v, &r, &g, &b); sprintf(buf, "rgbi:%lf/%lf/%lf", r, g, b); ptr = buf; } back_color_data.red = (unsigned short)(r * ((unsigned short)~0) +.5); back_color_data.green = (unsigned short)(g * ((unsigned short)~0) +.5); back_color_data.blue = (unsigned short)(b * ((unsigned short)~0) +.5); if (XAllocNamedColor(DISP, our_colormap, ptr, &fc, &bc)) { if (color_allocated_top >= color_allocated_len) { color_allocated_len += 0x10; color_allocated = (Pixel *) xrealloc(color_allocated, sizeof(Pixel) * color_allocated_len); } if (ptr != buf) back_color_data = fc; color_allocated[color_allocated_top++] = back_color_data.pixel = fc.pixel; } else { if (!color_warn_done) { color_warn(); color_warn_done = True; } } } #endif #ifdef COLOR #define RGB 0 #define CMYK 1 #define HSB 2 #endif static void dvi2ps_color_special(cp, colfmt) char *cp; unsigned char colfmt; { #ifdef COLOR char buf[BUFSIZ]; double r, g, b; XColor color, fc, bc; if (!use_color) return; if (colfmt == RGB) { sscanf(cp, " %lf %lf %lf", &r, &g, &b); } else if (colfmt == CMYK) { double c, m, y, k; sscanf(cp, " %lf %lf %lf %lf", &c, &m, &y, &k); cmyk_to_rgb(c, m, y, k, &r, &g, &b); } else if (colfmt == HSB) { double h, s, v; sscanf(cp, " %lf %lf %lf", &h, &s, &v); hsb_to_rgb(h, s, v, &r, &g, &b); } sprintf(buf, "rgbi:%lf/%lf/%lf", r, g, b); fore_color_data.red = (unsigned short)(r * ((unsigned short)~0) +.5); fore_color_data.green = (unsigned short)(g * ((unsigned short)~0) +.5); fore_color_data.blue = (unsigned short)(b * ((unsigned short)~0) +.5); if (XAllocNamedColor(DISP, our_colormap, buf, &fc, &bc) == True) { if (color_allocated_top >= color_allocated_len) { color_allocated_len += 0x10; color_allocated = (Pixel *) xrealloc(color_allocated, sizeof(Pixel) * color_allocated_len); } color_allocated[color_allocated_top++] = fore_color_data.pixel = fc.pixel; init_colors(); reset_fonts(); } else if (!color_warn_done) { color_warn(); color_warn_done = True; } #endif } /* * 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; /* Skip white space */ while (*cp == ' ' || *cp == '\t') ++cp; /* 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; } if (memicmp(cp, "epsfile=", 8) == 0) { elepsf_special(cp + 8); return; } if (memicmp(cp, "postscriptbox{", 14) == 0) { epsbox_special(cp + 14); return; } #ifdef COLOR if (memicmp(cp, "color ", 6) == 0) { color_special(cp + 6, False); return; } if (memicmp(cp, "rgb=", 4) == 0) { dvi2ps_color_special(cp + 4, RGB); return; } if (memicmp(cp, "cmyk=", 5) == 0) { dvi2ps_color_special(cp + 5, CMYK); return; } if (memicmp(cp, "hsb=", 4) == 0) { dvi2ps_color_special(cp + 4, HSB); return; } if (memicmp(cp, "background ", 11) == 0) { /* already scanned */ return; } #endif /* COLOR */ /* 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; } #ifdef HTEX if (checkHyperTeX(cp, current_page)) return; #endif /* 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('h','e'): psh_header(cp); return; case CMD('i','p'): /* throw away the path -- jansteen */ path_len = 0; return; } } if (warn_spec_now) Fprintf(stderr, "%s: special \"%s\" not implemented\n", prog, cp); } #undef CMD #if PS || defined(COLOR) void scan_special(cp) char *cp; { char *p; /* Skip white space */ while (*cp == ' ' || *cp == '\t') ++cp; if (debug & DBG_PS) Printf("Scanning special `%s'.\n", cp); #if PS if (resource._postscript) { if (*cp == '!') { scan_bang(cp); return; } if (memicmp(cp, "header", 6) == 0 && (p = endofcommand(cp + 6)) != NULL) { scan_header(p); return; } } #endif #ifdef COLOR if (memicmp(cp, "background ", 11) == 0) { background_special(cp + 11); return; } if (memicmp(cp, "color ", 6) == 0) { color_special(cp + 6, True); return; } #endif } #endif /* PS */