home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / unixtex-6.1b-src.tgz / tar.out / contrib / unixtex / xdvik / special.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  23KB  |  948 lines

  1. /*
  2.  * Copyright (c) 1994 Paul Vojta.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  * 1. Redistributions of source code must retain the above copyright
  8.  *    notice, this list of conditions and the following disclaimer.
  9.  * 2. Redistributions in binary form must reproduce the above copyright
  10.  *    notice, this list of conditions and the following disclaimer in the
  11.  *    documentation and/or other materials provided with the distribution.
  12.  *
  13.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  14.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23.  * SUCH DAMAGE.
  24.  *
  25.  * NOTE:
  26.  *    This module is based on prior work as noted below.
  27.  */
  28.  
  29. /*
  30.  * Support drawing routines for TeXsun and TeX
  31.  *
  32.  *      Copyright, (C) 1987, 1988 Tim Morgan, UC Irvine
  33.  *    Adapted for xdvi by Jeffrey Lee, U. of Toronto
  34.  *
  35.  * At the time these routines are called, the values of hh and vv should
  36.  * have been updated to the upper left corner of the graph (the position
  37.  * the \special appears at in the dvi file).  Then the coordinates in the
  38.  * graphics commands are in terms of a virtual page with axes oriented the
  39.  * same as the Imagen and the SUN normally have:
  40.  *
  41.  *                      0,0
  42.  *                       +-----------> +x
  43.  *                       |
  44.  *                       |
  45.  *                       |
  46.  *                      \ /
  47.  *                       +y
  48.  *
  49.  * Angles are measured in the conventional way, from +x towards +y.
  50.  * Unfortunately, that reverses the meaning of "counterclockwise"
  51.  * from what it's normally thought of.
  52.  *
  53.  * A lot of floating point arithmetic has been converted to integer
  54.  * arithmetic for speed.  In some places, this is kind-of kludgy, but
  55.  * it's worth it.
  56.  */
  57.  
  58. #include "config.h"
  59. #include <kpathsea/c-fopen.h>
  60. #include <kpathsea/c-ctype.h>
  61. #include <kpathsea/line.h>
  62. #include <kpathsea/tex-file.h>
  63.  
  64. #define    MAXPOINTS    300    /* Max points in a path */
  65. #define    TWOPI        (3.14159265359*2.0)
  66. #define    MAX_PEN_SIZE    7    /* Max pixels of pen width */
  67.  
  68.  
  69. static    int    xx[MAXPOINTS], yy[MAXPOINTS];    /* Path in milli-inches */
  70. static    int    path_len = 0;    /* # points in current path */
  71. static    int    pen_size = 1;    /* Pixel width of lines drawn */
  72.  
  73. static    Boolean    whiten = False;
  74. static    Boolean    shade = False;
  75. static    Boolean    blacken = False;
  76.  
  77. /* Unfortunately, these values also appear in dvisun.c */
  78. #define    xRESOLUTION    (pixels_per_inch/shrink_factor)
  79. #define    yRESOLUTION    (pixels_per_inch/shrink_factor)
  80.  
  81.  
  82. /*
  83.  *    Issue warning messages
  84.  */
  85.  
  86. static    void
  87. Warning(fmt, msg)
  88.     char    *fmt, *msg;
  89. {
  90.     Fprintf(stderr, fmt, msg);
  91.     (void) fputc('\n', stderr);
  92. }
  93.  
  94.  
  95. /*
  96.  *    X drawing routines
  97.  */
  98.  
  99. #define    toint(x)    ((int) ((x) + 0.5))
  100. #define    xconv(x)    (toint(tpic_conv*(x))/shrink_factor + PXL_H)
  101. #define    yconv(y)    (toint(tpic_conv*(y))/shrink_factor + PXL_V)
  102.  
  103. /*
  104.  *    Draw a line from (fx,fy) to (tx,ty).
  105.  *    Right now, we ignore pen_size.
  106.  */
  107. static    void
  108. line_btw(fx, fy, tx, ty)
  109. int fx, fy, tx, ty;
  110. {
  111.     register int    fcx = xconv(fx),
  112.             tcx = xconv(tx),
  113.             fcy = yconv(fy),
  114.             tcy = yconv(ty);
  115.  
  116.     if ((fcx < max_x || tcx < max_x) && (fcx >= min_x || tcx >= min_x) &&
  117.         (fcy < max_y || tcy < max_y) && (fcy >= min_y || tcy >= min_y))
  118.         XDrawLine(DISP, currwin.win, ruleGC,
  119.             fcx - currwin.base_x, fcy - currwin.base_y,
  120.             tcx - currwin.base_x, tcy - currwin.base_y);
  121. }
  122.  
  123. /*
  124.  *    Draw a dot at (x,y)
  125.  */
  126. static    void
  127. dot_at(x, y)
  128.     int    x, y;
  129. {
  130.     register int    cx = xconv(x),
  131.             cy = yconv(y);
  132.  
  133.     if (cx < max_x && cx >= min_x && cy < max_y && cy >= min_y)
  134.         XDrawPoint(DISP, currwin.win, ruleGC,
  135.         cx - currwin.base_x, cy - currwin.base_y);
  136. }
  137.  
  138. /*
  139.  *    Apply the requested attributes to the last path (box) drawn.
  140.  *    Attributes are reset.
  141.  *    (Not currently implemented.)
  142.  */
  143.     /* ARGSUSED */
  144. static    void
  145. do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y)
  146. int last_min_x, last_max_x, last_min_y, last_max_y;
  147. {
  148. }
  149.  
  150. /*
  151.  *    Set the size of the virtual pen used to draw in milli-inches
  152.  */
  153.  
  154. /* ARGSUSED */
  155. static    void
  156. set_pen_size(cp)
  157.     char    *cp;
  158. {
  159.     int    ps;
  160.  
  161.     if (sscanf(cp, " %d ", &ps) != 1) {
  162.         Warning("illegal .ps command format: %s", cp);
  163.         return;
  164.     }
  165.     pen_size = (ps * (xRESOLUTION + yRESOLUTION) + 1000) / 2000;
  166.     if (pen_size < 1) pen_size = 1;
  167.     else if (pen_size > MAX_PEN_SIZE) pen_size = MAX_PEN_SIZE;
  168. }
  169.  
  170.  
  171. /*
  172.  *    Print the line defined by previous path commands
  173.  */
  174.  
  175. static    void
  176. flush_path()
  177. {
  178.     register int i;
  179.     int    last_min_x, last_max_x, last_min_y, last_max_y;
  180.  
  181.     last_min_x = 30000;
  182.     last_min_y = 30000;
  183.     last_max_x = -30000;
  184.     last_max_y = -30000;
  185.     for (i = 1; i < path_len; i++) {
  186.         if (xx[i] > last_max_x) last_max_x = xx[i];
  187.         if (xx[i] < last_min_x) last_min_x = xx[i];
  188.         if (yy[i] > last_max_y) last_max_y = yy[i];
  189.         if (yy[i] < last_min_y) last_min_y = yy[i];
  190.         line_btw(xx[i], yy[i], xx[i+1], yy[i+1]);
  191.     }
  192.     if (xx[path_len] > last_max_x) last_max_x = xx[path_len];
  193.     if (xx[path_len] < last_min_x) last_min_x = xx[path_len];
  194.     if (yy[path_len] > last_max_y) last_max_y = yy[path_len];
  195.     if (yy[path_len] < last_min_y) last_min_y = yy[path_len];
  196.     path_len = 0;
  197.     do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y);
  198. }
  199.  
  200.  
  201. /*
  202.  *    Print a dashed line along the previously defined path, with
  203.  *    the dashes/inch defined.
  204.  */
  205.  
  206. static    void
  207. flush_dashed(cp, dotted)
  208.     char    *cp;
  209.     Boolean    dotted;
  210. {
  211.     int    i;
  212.     int    numdots;
  213.     int    lx0, ly0, lx1, ly1;
  214.     int    cx0, cy0, cx1, cy1;
  215.     float    inchesperdash;
  216.     double    d, spacesize, a, b, dx, dy, milliperdash;
  217.  
  218.     if (sscanf(cp, " %f ", &inchesperdash) != 1) {
  219.         Warning("illegal format for dotted/dashed line: %s", cp);
  220.         return;
  221.     }
  222.     if (path_len <= 1 || inchesperdash <= 0.0) {
  223.         Warning("illegal conditions for dotted/dashed line", "");
  224.         return;
  225.     }
  226.     milliperdash = inchesperdash * 1000.0;
  227.     lx0 = xx[1];    ly0 = yy[1];
  228.     lx1 = xx[2];    ly1 = yy[2];
  229.     dx = lx1 - lx0;
  230.     dy = ly1 - ly0;
  231.     if (dotted) {
  232.         numdots = sqrt(dx*dx + dy*dy) / milliperdash + 0.5;
  233.         if (numdots == 0) numdots = 1;
  234.         for (i = 0; i <= numdots; i++) {
  235.         a = (float) i / (float) numdots;
  236.         cx0 = lx0 + a * dx + 0.5;
  237.         cy0 = ly0 + a * dy + 0.5;
  238.         dot_at(cx0, cy0);
  239.         }
  240.     }
  241.     else {
  242.         d = sqrt(dx*dx + dy*dy);
  243.         numdots = d / (2.0 * milliperdash) + 1.0;
  244.         if (numdots <= 1)
  245.         line_btw(lx0, ly0, lx1, ly1);
  246.         else {
  247.         spacesize = (d - numdots * milliperdash) / (numdots - 1);
  248.         for (i = 0; i < numdots - 1; i++) {
  249.             a = i * (milliperdash + spacesize) / d;
  250.             b = a + milliperdash / d;
  251.             cx0 = lx0 + a * dx + 0.5;
  252.             cy0 = ly0 + a * dy + 0.5;
  253.             cx1 = lx0 + b * dx + 0.5;
  254.             cy1 = ly0 + b * dy + 0.5;
  255.             line_btw(cx0, cy0, cx1, cy1);
  256.             b += spacesize / d;
  257.         }
  258.         cx0 = lx0 + b * dx + 0.5;
  259.         cy0 = ly0 + b * dy + 0.5;
  260.         line_btw(cx0, cy0, lx1, ly1);
  261.         }
  262.     }
  263.     path_len = 0;
  264. }
  265.  
  266.  
  267. /*
  268.  *    Add a point to the current path
  269.  */
  270.  
  271. static    void
  272. add_path(cp)
  273.     char    *cp;
  274. {
  275.     int    pathx, pathy;
  276.  
  277.     if (++path_len >= MAXPOINTS) oops("Too many points");
  278.     if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2)
  279.         oops("Malformed path command");
  280.     xx[path_len] = pathx;
  281.     yy[path_len] = pathy;
  282. }
  283.  
  284.  
  285. /*
  286.  *    Draw to a floating point position
  287.  */
  288.  
  289. static void
  290. im_fdraw(x, y)
  291.     double    x,y;
  292. {
  293.     if (++path_len >= MAXPOINTS) oops("Too many arc points");
  294.     xx[path_len] = x + 0.5;
  295.     yy[path_len] = y + 0.5;
  296. }
  297.  
  298.  
  299. /*
  300.  *    Draw an ellipse with the indicated center and radices.
  301.  */
  302.  
  303. static    void
  304. draw_ellipse(xc, yc, xr, yr)
  305.     int    xc, yc, xr, yr;
  306. {
  307.     double    angle, theta;
  308.     int    n;
  309.     int    px0, py0, px1, py1;
  310.  
  311.     angle = (xr + yr) / 2.0;
  312.     theta = sqrt(1.0 / angle);
  313.     n = TWOPI / theta + 0.5;
  314.     if (n < 12) n = 12;
  315.     else if (n > 80) n = 80;
  316.     n /= 2;
  317.     theta = TWOPI / n;
  318.  
  319.     angle = 0.0;
  320.     px0 = xc + xr;        /* cos(0) = 1 */
  321.     py0 = yc;        /* sin(0) = 0 */
  322.     while ((angle += theta) <= TWOPI) {
  323.         px1 = xc + xr*cos(angle) + 0.5;
  324.         py1 = yc + yr*sin(angle) + 0.5;
  325.         line_btw(px0, py0, px1, py1);
  326.         px0 = px1;
  327.         py0 = py1;
  328.     }
  329.     line_btw(px0, py0, xc + xr, yc);
  330. }
  331.  
  332. /*
  333.  *    Draw an arc
  334.  */
  335.  
  336. static    void
  337. arc(cp, invis)
  338.     char    *cp;
  339.     Boolean    invis;
  340. {
  341.     int    xc, yc, xrad, yrad, n;
  342.     float    start_angle, end_angle, angle, theta, r;
  343.     double    xradius, yradius, xcenter, ycenter;
  344.  
  345.     if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad,
  346.         &start_angle, &end_angle) != 6) {
  347.         Warning("illegal arc specification: %s", cp);
  348.         return;
  349.     }
  350.  
  351.     if (invis) return;
  352.  
  353.     /* We have a specialized fast way to draw closed circles/ellipses */
  354.     if (start_angle <= 0.0 && end_angle >= 6.282) {
  355.         draw_ellipse(xc, yc, xrad, yrad);
  356.         return;
  357.     }
  358.     xcenter = xc;
  359.     ycenter = yc;
  360.     xradius = xrad;
  361.     yradius = yrad;
  362.     r = (xradius + yradius) / 2.0;
  363.     theta = sqrt(1.0 / r);
  364.     n = 0.3 * TWOPI / theta + 0.5;
  365.     if (n < 12) n = 12;
  366.     else if (n > 80) n = 80;
  367.     n /= 2;
  368.     theta = TWOPI / n;
  369.     flush_path();
  370.     im_fdraw(xcenter + xradius * cos(start_angle),
  371.         ycenter + yradius * sin(start_angle));
  372.     angle = start_angle + theta;
  373.     if (end_angle < start_angle) end_angle += TWOPI;
  374.     while (angle < end_angle) {
  375.         im_fdraw(xcenter + xradius * cos(angle),
  376.         ycenter + yradius * sin(angle));
  377.         angle += theta;
  378.     }
  379.     im_fdraw(xcenter + xradius * cos(end_angle),
  380.         ycenter + yradius * sin(end_angle));
  381.     flush_path();
  382. }
  383.  
  384.  
  385. /*
  386.  *    APPROXIMATE integer distance between two points
  387.  */
  388.  
  389. #define    dist(x0, y0, x1, y1)    (abs(x0 - x1) + abs(y0 - y1))
  390.  
  391.  
  392. /*
  393.  *    Draw a spline along the previously defined path
  394.  */
  395.  
  396. static    void
  397. flush_spline()
  398. {
  399.     int    xp, yp;
  400.     int    N;
  401.     int    lastx, lasty;
  402.     Boolean    lastvalid = False;
  403.     int    t1, t2, t3;
  404.     int    steps;
  405.     int    j;
  406.     register int i, w;
  407.  
  408. #ifdef    lint
  409.     lastx = lasty = -1;
  410. #endif
  411.     N = path_len + 1;
  412.     xx[0] = xx[1];
  413.     yy[0] = yy[1];
  414.     xx[N] = xx[N-1];
  415.     yy[N] = yy[N-1];
  416.     for (i = 0; i < N - 1; i++) {    /* interval */
  417.         steps = (dist(xx[i], yy[i], xx[i+1], yy[i+1]) +
  418.         dist(xx[i+1], yy[i+1], xx[i+2], yy[i+2])) / 80;
  419.         for (j = 0; j < steps; j++) {    /* points within */
  420.         w = (j * 1000 + 500) / steps;
  421.         t1 = w * w / 20;
  422.         w -= 500;
  423.         t2 = (750000 - w * w) / 10;
  424.         w -= 500;
  425.         t3 = w * w / 20;
  426.         xp = (t1*xx[i+2] + t2*xx[i+1] + t3*xx[i] + 50000) / 100000;
  427.         yp = (t1*yy[i+2] + t2*yy[i+1] + t3*yy[i] + 50000) / 100000;
  428.         if (lastvalid) line_btw(lastx, lasty, xp, yp);
  429.         lastx = xp;
  430.         lasty = yp;
  431.         lastvalid = True;
  432.         }
  433.     }
  434.     path_len = 0;
  435. }
  436.  
  437.  
  438. /*
  439.  *    Shade the last box, circle, or ellipse
  440.  */
  441.  
  442. static    void
  443. shade_last()
  444. {
  445.     blacken = whiten = False;
  446.     shade = True;
  447. }
  448.  
  449.  
  450. /*
  451.  *    Make the last box, circle, or ellipse, white inside (shade with white)
  452.  */
  453.  
  454. static    void
  455. whiten_last()
  456. {
  457.     whiten = True;
  458.     blacken = shade = False;
  459. }
  460.  
  461.  
  462. /*
  463.  *    Make last box, etc, black inside
  464.  */
  465.  
  466. static    void
  467. blacken_last()
  468. {
  469.     blacken = True;
  470.     whiten = shade = False;
  471. }
  472.  
  473.  
  474. /*
  475.  *    Code for PostScript<tm> specials begins here.
  476.  */
  477.  
  478. #if    PS
  479.  
  480. static    void    ps_startup ARGS((int, int, char *));
  481. void    NullProc ARGS((void)) {}
  482. /* ARGSUSED */
  483. static    void    NullProc2 ARGS((char *));
  484.  
  485. struct psprocs    psp = {        /* used for lazy startup of the ps machinery */
  486.     /* toggle */        NullProc,
  487.     /* destroy */        NullProc,
  488.     /* interrupt */        NullProc,
  489.     /* endpage */        NullProc,
  490.     /* drawbegin */        ps_startup,
  491.     /* drawraw */        NullProc2,
  492.     /* drawfile */        NullProc2,
  493.     /* drawend */        NullProc2};
  494.  
  495. struct psprocs    no_ps_procs = {        /* used if postscript is unavailable */
  496.     /* toggle */        NullProc,
  497.     /* destroy */        NullProc,
  498.     /* interrupt */        NullProc,
  499.     /* endpage */        NullProc,
  500.     /* drawbegin */        drawbegin_none,
  501.     /* drawraw */        NullProc2,
  502.     /* drawfile */        NullProc2,
  503.     /* drawend */        NullProc2};
  504.  
  505. #endif    /* PS */
  506.  
  507. static    Boolean        bbox_valid;
  508. static    unsigned int    bbox_width;
  509. static    unsigned int    bbox_height;
  510. static    int        bbox_voffset;
  511.  
  512. void
  513. draw_bbox()
  514. {
  515.     if (bbox_valid) {
  516.         put_border(PXL_H - currwin.base_x,
  517.         PXL_V - currwin.base_y - bbox_voffset,
  518.         bbox_width, bbox_height, ruleGC);
  519.         bbox_valid = False;
  520.     }
  521. }
  522.  
  523. #if    PS
  524. static    void
  525. actual_startup()
  526. {
  527.     /*
  528.      * Figure out what we want to use to display postscript figures
  529.      * and set at most one of the following to True:
  530.      * resource.useGS, resource.useDPS, resource.useNeWS
  531.      *
  532.      * Choose DPS then NEWS then GhostScript if they are available
  533.      */
  534.     if (!(
  535. #ifdef    PS_DPS
  536.         (resource.useDPS && initDPS())
  537. #if    defined(PS_NEWS) || defined(PS_GS)
  538.         ||
  539. #endif
  540. #endif    /* PS_DPS */
  541.  
  542. #ifdef    PS_NEWS
  543.         (resource.useNeWS && initNeWS())
  544. #ifdef    PS_GS
  545.         ||
  546. #endif
  547. #endif    /* PS_NEWS */
  548.  
  549. #ifdef    PS_GS
  550.         (resource.useGS && initGS())
  551. #endif
  552.  
  553.         ))
  554.         psp = no_ps_procs;
  555. }
  556.  
  557. static    void
  558. ps_startup(xul, yul, cp)
  559.     int    xul, yul;
  560.     char    *cp;
  561. {
  562.     if (!resource._postscript) {
  563.         psp.toggle = actual_startup;
  564.         draw_bbox();
  565.         return;
  566.     }
  567.     actual_startup();
  568.     psp.drawbegin(xul, yul, cp);
  569. }
  570.  
  571. /* ARGSUSED */
  572. static    void
  573. NullProc2(cp)
  574.     char    *cp;
  575. {}
  576.  
  577. /* ARGSUSED */
  578. void
  579. #if    NeedFunctionPrototypes
  580. drawbegin_none(int xul, int yul, char *cp)
  581. #else    /* !NeedFunctionPrototypes */
  582. drawbegin_none(xul, yul, cp)
  583.     int    xul, yul;
  584.     char    *cp;
  585. #endif    /* NeedFunctionPrototypes */
  586. {
  587.     draw_bbox();
  588. }
  589. #endif    /* PS */
  590.  
  591.  
  592. /* If FILENAME starts with a left quote, set *DECOMPRESS to 1 and return
  593.    the rest of FILENAME. Otherwise, look up FILENAME along the usual
  594.    path for figure files, set *DECOMPRESS to 0, and return the result
  595.    (NULL if can't find the file).  */
  596.  
  597. static string
  598. find_fig_file (filename, decompress)
  599.     char *filename;
  600.     int *decompress;
  601. {
  602.   char *name;
  603.   
  604.   if (*filename == '`') {
  605.      name = filename + 1;
  606.     *decompress = 1;
  607.   } else {
  608.     name = kpse_find_pict (filename);
  609.     if (!name)
  610.       fprintf (stderr, "xdvi: %s: Cannot open PS file.\n", filename);
  611.     *decompress = 0;
  612.   }
  613.   
  614.   return name;
  615. }
  616.  
  617.  
  618. #if PS
  619. /* If DECOMPRESS is zero, pass NAME to the drawfile proc.  But if
  620.    DECOMPRESS is nonzero, open a pipe to it and pass the resulting
  621.    output to the drawraw proc (in chunks).  */
  622.  
  623. static void
  624. draw_file (psp, name, decompress)
  625.     struct psprocs psp;
  626.     char *name;
  627.     int decompress;
  628. {
  629.   if (decompress) {
  630.     FILE *pipe;
  631.     if (debug & DBG_PS)
  632.       printf ("%s: piping to PostScript\n", name);
  633.       
  634.     pipe = popen (name, FOPEN_R_MODE);
  635.     if (pipe == NULL)
  636.       perror (name);
  637.     else
  638.       {
  639.         char *line;
  640.         int save_debug = debug;
  641.         debug = 0; /* don't print every line we send */
  642.         while ((line = read_line (pipe)) != NULL) {
  643.           psp.drawraw (line);
  644.           free (line);
  645.         }
  646.         pclose (pipe); /* Linux gives a spurious error, so don't check. */
  647.         debug = save_debug;
  648.       }
  649.  
  650.   } else { /* a regular file, not decompressing */
  651.     psp.drawfile (name);
  652.   }
  653. }
  654. #endif /* PS */
  655.  
  656. static    void
  657. psfig_special(cp)
  658.     char    *cp;
  659. {
  660.     char    *filename;
  661.     int    raww, rawh;
  662.  
  663.     if (strncmp(cp, ":[begin]", 8) == 0) {
  664.         cp += 8;
  665.         bbox_valid = False;
  666.         if (sscanf(cp,"%d %d\n", &raww, &rawh) >= 2) {
  667.         bbox_valid = True;
  668.         bbox_width = pixel_conv(spell_conv(raww));
  669.         bbox_height = pixel_conv(spell_conv(rawh));
  670.         bbox_voffset = 0;
  671.         }
  672.         if (currwin.win == mane.win)
  673. #if    PS
  674.         psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y,
  675.             cp);
  676. #else
  677.         draw_bbox();
  678. #endif
  679.     } else if (strncmp(cp, " plotfile ", 10) == 0) {
  680.         cp += 10;
  681.         while (isspace(*cp)) cp++;
  682.         for (filename = cp; !isspace(*cp); ++cp);
  683.         *cp = '\0';
  684. #if    PS
  685.         {
  686.           int decompress;
  687.           char *name = find_fig_file (filename, &decompress);
  688.               if (name && currwin.win == mane.win) {
  689.                   draw_file(psp, name, decompress);
  690.                   if (!decompress && name != filename)
  691.                     free (name);
  692.               }
  693.         }
  694. #endif
  695.     } else if (strncmp(cp, ":[end]", 6) == 0) {
  696.         cp += 6;
  697. #if    PS
  698.         if (currwin.win == mane.win) psp.drawend(cp);
  699. #endif
  700.         bbox_valid = False;
  701.     } else { /* I am going to send some raw postscript stuff */
  702.       if (*cp == ':')
  703.         ++cp;    /* skip second colon in ps:: */
  704. #if    PS
  705.       if (currwin.win == mane.win) {
  706.             /* It's drawbegin that initializes the ps process, so make
  707.                sure it's started up.  */
  708.             psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, "");
  709.             psp.drawend("");
  710.             psp.drawraw(cp);
  711.       }
  712. #endif
  713.     }
  714. }
  715.  
  716.  
  717. /*    Keys for epsf specials */
  718.  
  719. static    char    *keytab[]    = {"clip", 
  720.                     "llx",
  721.                     "lly",
  722.                     "urx",
  723.                     "ury",
  724.                     "rwi",
  725.                     "rhi",
  726.                     "hsize",
  727.                     "vsize",
  728.                     "hoffset",
  729.                     "voffset",
  730.                     "hscale",
  731.                     "vscale",
  732.                     "angle"};
  733.  
  734. #define    KEY_LLX    keyval[0]
  735. #define    KEY_LLY    keyval[1]
  736. #define    KEY_URX    keyval[2]
  737. #define    KEY_URY    keyval[3]
  738. #define    KEY_RWI    keyval[4]
  739. #define    KEY_RHI    keyval[5]
  740.  
  741. #define    NKEYS    (sizeof(keytab)/sizeof(*keytab))
  742. #define    N_ARGLESS_KEYS 1
  743.  
  744. static    void
  745. epsf_special(cp)
  746.     char    *cp;
  747. {
  748.     char    *filename, *name;
  749.     int     decompress;
  750.     static    char        *buffer;
  751.     static    unsigned int    buflen    = 0;
  752.     unsigned int        len;
  753.     char    *p;
  754.     char    *q;
  755.     int    flags    = 0;
  756.     double    keyval[6];
  757.  
  758.     if (memcmp(cp, "ile=", 4) != 0) {
  759.         if (!hush_spec_now)
  760.         Fprintf(stderr, "epsf special PSf%s is unknown\n", cp);
  761.         return;
  762.     }
  763.  
  764.     p = cp + 4;
  765.     filename = p;
  766.     if (*p == '\'' || *p == '"') {
  767.         do ++p;
  768.         while (*p != '\0' && *p != *filename);
  769.         ++filename;
  770.     }
  771.     else
  772.         while (*p != '\0' && *p != ' ' && *p != '\t') ++p;
  773.     if (*p != '\0') *p++ = '\0';
  774.     name = find_fig_file (filename, &decompress);
  775.     while (*p == ' ' || *p == '\t') ++p;
  776.     len = strlen(p) + NKEYS + 30;
  777.     if (buflen < len) {
  778.         if (buflen != 0) free(buffer);
  779.         buflen = len;
  780.         buffer = xmalloc(buflen, "epsf buffer");
  781.     }
  782.     Strcpy(buffer, "@beginspecial");
  783.     q = buffer + strlen(buffer);
  784.     while (*p != '\0') {
  785.         char *p1 = p;
  786.         int keyno;
  787.  
  788.         while (*p1 != '=' && !isspace(*p1) && *p1 != '\0') ++p1;
  789.         for (keyno = 0;; ++keyno) {
  790.         if (keyno >= NKEYS) {
  791.             if (!hush_spec_now)
  792.             Fprintf(stderr,
  793.                 "unknown keyword (%*s) in \\special will be ignored\n",
  794.                 (int) (p1 - p), p);
  795.             break;
  796.         }
  797.         if (memcmp(p, keytab[keyno], p1 - p) == 0) {
  798.             if (keyno >= N_ARGLESS_KEYS) {
  799.             if (*p1 == '=') ++p1;
  800.             if (keyno < N_ARGLESS_KEYS + 6) {
  801.                 keyval[keyno - N_ARGLESS_KEYS] = atof(p1);
  802.                 flags |= (1 << (keyno - N_ARGLESS_KEYS));
  803.             }
  804.             *q++ = ' ';
  805.             while (!isspace(*p1) && *p1 != '\0') *q++ = *p1++;
  806.             }
  807.             *q++ = ' ';
  808.             *q++ = '@';
  809.             Strcpy(q, keytab[keyno]);
  810.             q += strlen(q);
  811.             break;
  812.         }
  813.         }
  814.         p = p1;
  815.         while (!isspace(*p) && *p != '\0') ++p;
  816.         while (isspace(*p)) ++p;
  817.     }
  818.     Strcpy(q, " @setspecial\n");
  819.  
  820.     bbox_valid = False;
  821.     if ((flags & 0x30) == 0x30 || ((flags & 0x30) && (flags & 0xf) == 0xf)){
  822.         bbox_valid = True;
  823.         bbox_width = 0.1 * ((flags & 0x10) ? KEY_RWI
  824.         : KEY_RHI * (KEY_URX - KEY_LLX) / (KEY_URY - KEY_LLY))
  825.         * dimconv / shrink_factor + 0.5;
  826.         bbox_voffset = bbox_height = 0.1 * ((flags & 0x20) ? KEY_RHI
  827.         : KEY_RWI * (KEY_URY - KEY_LLY) / (KEY_URX - KEY_LLX))
  828.         * dimconv / shrink_factor + 0.5;
  829.     }
  830.  
  831.     if (name && currwin.win == mane.win) {
  832. #if    PS
  833.         psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y,
  834.         buffer);
  835.         draw_file(psp, name, decompress);
  836.         psp.drawend(" @endspecial");
  837.         if (!decompress && name != filename)
  838.          free (name);
  839. #else
  840.         draw_bbox();
  841. #endif
  842.     }
  843.     bbox_valid = False;
  844. }
  845.  
  846.  
  847. static    void
  848. bang_special(cp)
  849.     char    *cp;
  850. {
  851.     bbox_valid = False;
  852.  
  853. #if    PS
  854.     if (currwin.win == mane.win) {
  855.         psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y,
  856.             "@defspecial ");
  857.         /* talk directly with the DPSHandler here */
  858.         psp.drawraw(cp);
  859.         psp.drawend(" @fedspecial");
  860.     }
  861. #endif
  862.  
  863.     /* nothing else to do--there's no bbox here */
  864. }
  865.  
  866. static    void
  867. quote_special(cp)
  868.     char    *cp;
  869. {
  870.     bbox_valid = False;
  871.  
  872. #if    PS
  873.     if (currwin.win == mane.win) {
  874.         psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y,
  875.         "@beginspecial @setspecial ");
  876.         /* talk directly with the DPSHandler here */
  877.         psp.drawraw(cp);
  878.         psp.drawend(" @endspecial");
  879.     }
  880. #endif
  881.  
  882.     /* nothing else to do--there's no bbox here */
  883. }
  884.  
  885.  
  886. /*
  887.  *    The following copyright message applies to the rest of this file.  --PV
  888.  */
  889.  
  890. /*
  891.  *    This program is Copyright (C) 1987 by the Board of Trustees of the
  892.  *    University of Illinois, and by the author Dirk Grunwald.
  893.  *
  894.  *    This program may be freely copied, as long as this copyright
  895.  *    message remaines affixed. It may not be sold, although it may
  896.  *    be distributed with other software which is sold. If the
  897.  *    software is distributed, the source code must be made available.
  898.  *
  899.  *    No warranty, expressed or implied, is given with this software.
  900.  *    It is presented in the hope that it will prove useful.
  901.  *
  902.  *    Hacked in ignorance and desperation by jonah@db.toronto.edu
  903.  */
  904.  
  905. /*
  906.  *      The code to handle the \specials generated by tpic was modified
  907.  *      by Dirk Grunwald using the code Tim Morgan at Univ. of Calif, Irvine
  908.  *      wrote for TeXsun.
  909.  */
  910.  
  911. #define    COMLEN    3
  912.  
  913. void
  914. applicationDoSpecial(cp)
  915.     char    *cp;
  916. {
  917.     char    command[COMLEN + 1];
  918.     char    *q;
  919.     char    *orig_cp;
  920.  
  921.     orig_cp = cp;
  922.     while (ISSPACE(*cp)) ++cp;
  923.     q = command;
  924.     while (!ISSPACE(*cp) && *cp && q < command + COMLEN) *q++ = *cp++;
  925.     *q = '\0';
  926.     if (strcmp(command, "pn") == 0) set_pen_size(cp);
  927.     else if (strcmp(command, "fp") == 0) flush_path();
  928.     else if (strcmp(command, "da") == 0) flush_dashed(cp, False);
  929.     else if (strcmp(command, "dt") == 0) flush_dashed(cp, True);
  930.     else if (strcmp(command, "pa") == 0) add_path(cp);
  931.     else if (strcmp(command, "ar") == 0) arc(cp, False);
  932.     else if (strcmp(command, "ia") == 0) arc(cp, True);
  933.     else if (strcmp(command, "sp") == 0) flush_spline();
  934.     else if (strcmp(command, "sh") == 0) shade_last();
  935.     else if (strcmp(command, "wh") == 0) whiten_last();
  936.     else if (strcmp(command, "bk") == 0) blacken_last();
  937.     /* throw away the path -- jansteen */
  938.     else if (strcmp(command, "ip") == 0) path_len = 0;
  939.     else if (strcmp(command, "ps:") == 0) psfig_special(cp);
  940.     else if (strcmp(command, "PSf") == 0) epsf_special(cp);
  941.     else if (strcmp(command, "psf") == 0) epsf_special(cp);
  942.     else if (*orig_cp == '"') quote_special(orig_cp + 1);
  943.     else if (*orig_cp == '!') bang_special(orig_cp + 1);
  944.     else if (!hush_spec_now)
  945.         Fprintf(stderr, "%s:  special \"%s\" not implemented\n", prog,
  946.         orig_cp);
  947. }
  948.