home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume9 / draw_jt / part02 / dr_lib.c next >
Encoding:
C/C++ Source or Header  |  1989-12-12  |  30.6 KB  |  1,372 lines

  1. /*
  2.  
  3. Copyright (C) 1988, 1989 by Juha Takala, jta@sah.vtt.fi
  4.  
  5.      This program is free software; you can redistribute it and/or modify
  6.      it under the terms of the GNU General Public License as published by
  7.      the Free Software Foundation; version 1.
  8.  
  9.      This program is distributed in the hope that it will be useful,
  10.      but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.      the file "License" for more details
  13.  
  14.      You should have received a copy of the GNU General Public License
  15.      along with this program; if not, write to the Free Software
  16.      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.  
  19.  */
  20.  
  21.  
  22. /* Description:
  23.  *  dr_lib.c provides interface between device level and my draw(1).
  24.  *  Supported devices are:
  25.  *  - hpgl output for hp7475 plotter
  26.  *  - gl_plot(3) calls for EGA or matrix printer output
  27.  *  - plot(3) interface
  28.  *
  29.  */
  30. static char *rcsid =
  31.   "$Id: dr_lib.c,v 2.4 89/12/08 14:00:34 jta Exp Locker: jta $";
  32.  
  33. /* define this, if your plotter connection is 'y-cable' (not direct) */
  34. /* #define YCABLE            /*  */
  35.  
  36. /* definede this if you want to ask paper size from plotter */
  37. /* (should not be used, if you are going to use this package as */
  38. /* part of pipelines) */
  39. /* #define ASK            /*  */
  40.  
  41. #include <stdio.h> 
  42. #include <math.h>
  43. #ifdef MSDOS
  44. #include <bios.h>
  45. #endif
  46. #include "dr_lib.h"
  47.  
  48. #define  ESC 0x1b        /* ascii <ESC> */
  49.  
  50. static int xscale(), yscale();
  51. static void sends(), invdev();
  52.  
  53. #ifdef ASK
  54. static void takes();
  55. #endif /* ASK */
  56.  
  57. /*
  58.  * internal global variable declarations
  59.  *
  60.  */
  61.                 /* coordinate transformations */
  62. static float xuserincr,   yuserincr;
  63. static float xuserlow,    yuserlow;
  64. static float xuserhigh,   yuserhigh;
  65. static float xdevicelow,  ydevicelow;
  66. static float xdevicehigh, ydevicehigh;
  67. static float xrelarea,    yrelarea;
  68. static float xfactor,     yfactor;
  69. static float shape_factor, size_factor;    /* text 'fatness' and size factors */
  70. static int lastx=0, lasty=0;    /* device coordinates for last point */
  71.  
  72.  
  73. static int device = INVDEV;    /* what output device we are working for */
  74. static int old_linetype = -1;    /* remember last used linetype */
  75. static int old_pen = -1;    /* ...and pen */
  76.  
  77. static int errcount, warncount, errfile;
  78. static char *errfilename = "draw.err";
  79.  
  80. static FILE *errfilefp;
  81.  
  82.  
  83.  
  84. /* ********************************************************** */
  85. /*                                                            */
  86. /* Following functions are ment to be subroutines to be       */
  87. /* called from a user supplied main program                   */
  88. /*                                                            */
  89. /* ********************************************************** */
  90.  
  91. /*
  92.  * dr_set_cset()   - select cset
  93.  *
  94.  */
  95. void dr_set_cset(n)
  96. int n;
  97. {
  98.     char s[50];
  99.  
  100.     switch (device)
  101.       {
  102.       case HP7475:
  103.       if (n < 0 || n == 5 || (n > 9 && n < 30) || n > 39) {
  104.           (void)sprintf(s, "Invalid cset code %d, using 0", n);
  105.           dr_errmsg(s);
  106.           n = 0;
  107.       }
  108.       (void)sprintf(s, "CS%d;\n", n);
  109.       sends(s);
  110.       break;
  111. #ifdef GL_LIB
  112.       case SCREEN:
  113. /*      (void)sprintf(s, "cset not yet for SCREEN");
  114.       dr_errmsg(s);        /*  */
  115.       break;
  116. #endif
  117. #ifdef PLOT
  118.       case PLOTLIB:
  119. /*      (void)sprintf(s, "cset not valid for PLOT");
  120.       dr_errmsg(s);        /*  */
  121.       break;
  122. #endif
  123.       default:
  124.       invdev(); break;
  125.       }
  126. }
  127.  
  128. /*
  129.  * dr_set_pen()   - select pen
  130.  *
  131.  */
  132. void dr_set_pen(n)
  133. int n;                /* pen number, 1..6, 0=='put it away' */
  134. {
  135.     char s[50];
  136.  
  137.     switch (device)
  138.       {
  139.       case HP7475:
  140.       if (n < 0 || n > 6) {
  141.           (void)sprintf(s, "Invalid pen code %d, using 1", n);
  142.           dr_errmsg(s);
  143.           n = 1;
  144.       }
  145.       if (n != old_pen) {    /* optimize for hpgl... */
  146.           old_pen = n;
  147.           (void)sprintf(s, "SP%d;", n);
  148.           sends(s);
  149.       }
  150.       break;
  151. #ifdef GL_LIB
  152.       case SCREEN:
  153. /*      (void)sprintf(s, "dr_set_pen(colour) not yet for SCREEN\n");
  154.       dr_errmsg(s);        /*  */
  155.       break;
  156. #endif
  157. #ifdef PLOT
  158.       case PLOTLIB:
  159. /*      (void)sprintf(s, "dr_set_pen(colour) not valid for PLOT\n");
  160.       dr_errmsg(s);        /*  */
  161.       break;
  162. #endif
  163.       default:
  164.       invdev(); break;
  165.       }
  166. }
  167.  
  168. /*
  169.  * dr_goto()  - move pen to point x, y
  170.  *
  171.  */
  172. void dr_goto(x, y, penup)
  173. float x, y;            /* where he wants to go */
  174. int penup;            /* nonzero == lift pen before moving */
  175. {
  176.     char s[60];
  177.     lastx = xscale(x);
  178.     lasty = yscale(y);
  179.     switch (device)
  180.       {
  181.       case HP7475:
  182.       if (penup) sends ("PU");
  183.       else sends ("PA;PD");
  184.           
  185.       /* go to point, leave pen as told
  186.        */
  187.       (void)sprintf(s, "%d,%d;\n", lastx, lasty);
  188.       sends(s);
  189.       break;
  190. #ifdef GL_LIB
  191.       case SCREEN:
  192.       if (penup)    n_movepen(lastx, lasty);
  193.       else        n_draw(lastx, lasty);
  194.       break;
  195. #endif
  196. #ifdef PLOT
  197.       case PLOTLIB:
  198.       if (penup)    move(lastx, lasty);
  199.       else        cont(lastx, lasty);
  200.       break;
  201. #endif
  202.       default:
  203.       invdev(); break;
  204.       }
  205.     return;
  206. }
  207.  
  208.  
  209. /*
  210.  * dr_draw_line()  - draw line (x1,y1) .. (x2,y2)
  211.  *
  212.  * connect the two data points with line
  213.  */
  214. void dr_draw_line(x1, y1, x2, y2)
  215. float x1, y1, x2, y2;        /* data points */
  216. {
  217.     char s[60];
  218.     
  219.     lastx = xscale(x2);
  220.     lasty = yscale(y2);
  221.     switch (device)
  222.       {
  223.       case HP7475:
  224.       /* lift pen,
  225.        * go to first point,
  226.        * drop pen there,
  227.        */
  228.       (void)sprintf(s, "PA;PU%d,%d;PD;", xscale(x1), yscale(y1));
  229.       sends(s);
  230.  
  231.       /* draw line segment, lift pen
  232.        */
  233.       (void)sprintf(s, "PD%d,%d;PU;\n", lastx, lasty);
  234.       sends(s);
  235.       break;
  236. #ifdef GL_LIB
  237.       case SCREEN:
  238.       n_line(xscale(x1), yscale(y1), lastx, lasty);
  239.       break;
  240. #endif
  241. #ifdef PLOT
  242.       case PLOTLIB:
  243.       line(xscale(x1), yscale(y1), lastx, lasty);
  244.       break;
  245. #endif
  246.       default:
  247.       invdev(); break;
  248.       }
  249.     return;
  250. }
  251.  
  252.  
  253. /*
  254.  * dr_draw_array()  - draw y = f(x)
  255.  *
  256.  * connect data points with line
  257.  */
  258. void dr_draw_array(x, y, n)
  259. float x[], y[];            /* data points */
  260. int n;                /* number of points in x[] and y[] */
  261. {
  262.     int i;
  263.     char s[60];
  264.     
  265.     /* if we really have something to draw
  266.      */
  267.     if (n < 1)
  268.       return;
  269.  
  270.     switch (device)
  271.       {
  272.       case HP7475:
  273.       /* lift pen,
  274.        * go to first point,
  275.        * drop pen there,
  276.        */
  277.       (void)sprintf(s, "PA;PU%d,%d;PD;", xscale(x[0]), yscale(y[0]));
  278.       sends(s);
  279.       
  280.       /* draw line segments
  281.        */
  282.       for (i=1; i<n; i++) {
  283.           if (i % 4 == 0) sends("\n");
  284.           (void)sprintf(s, "PD%d,%d;", xscale(x[i]), yscale(y[i]));
  285.           sends(s);
  286.       }
  287.       
  288.       /* finally lift pen
  289.        */
  290.       sends("PU;\n");
  291.       break;
  292. #ifdef GL_LIB
  293.       case SCREEN:
  294.       n_movepen(xscale(x[0]), yscale(y[0]));
  295.       for (i=1; i<n; i++)
  296.         n_draw(xscale(x[i]), yscale(y[i]));
  297.       break;
  298. #endif
  299. #ifdef PLOT
  300.       case PLOTLIB:
  301.       move(xscale(x[0]), yscale(y[0]));
  302.       for (i=1; i<n; i++)
  303.         cont(xscale(x[i]), yscale(y[i]));
  304.       break;
  305. #endif
  306.       default:
  307.       invdev(); break;
  308.       }
  309.     lastx = xscale(x[i-1]);
  310.     lasty = yscale(y[i-1]);
  311.     return;
  312. }
  313.  
  314.  
  315. /*
  316.  * dr_put_mark()  - make a mark at (x,y)
  317.  *
  318.  * put mark at data point
  319.  */
  320. void dr_put_mark(x, y, mark) 
  321. float x, y;            /* data point */
  322. char mark;
  323. {
  324.     char s[60];
  325.  
  326.     lastx = xscale(x);
  327.     lasty = yscale(y);
  328.     switch (device)
  329.       {
  330.       case HP7475:
  331.       /* if we really have something to plot
  332.        */
  333.       
  334.       /* lift pen,
  335.        * set symbol mode,
  336.        */
  337.       (void)sprintf(s, "PA;PU;SM%c;", mark);
  338.       sends(s);
  339.       
  340.       /* put symbol at all data points
  341.        */
  342.       (void)sprintf(s, "PU%d,%d;", lastx, lasty);
  343.       sends(s);
  344.       
  345.       /* reset symbol mode
  346.        */
  347.       sends("SM;\n");
  348.       break;
  349. #ifdef GL_LIB
  350.       case SCREEN:
  351.       n_movepen(lastx, lasty);
  352.       n_grafchar(mark);
  353.       break;
  354. #endif
  355. #ifdef PLOT
  356.       case PLOTLIB:
  357.       move(lastx, lasty);
  358.       *s = mark;
  359.       *(s+1) = '\0';
  360.       label(s);
  361.       break;
  362. #endif
  363.       default:
  364.       invdev(); break;
  365.       }
  366.     return;
  367. }
  368.  
  369.  
  370. void dr_set_shape(x)
  371. float x;
  372. {
  373.     if (x > 0.0)
  374.       shape_factor = x * xrelarea/yrelarea;
  375.     return;
  376. }
  377.  
  378.  
  379. void dr_set_size(x)
  380. float x;
  381. {
  382.     if (x > 0.0)
  383.       size_factor = x;
  384.     return;
  385. }
  386.  
  387.  
  388. /*
  389.  * dr_put_text()  - put some text
  390.  * plot(3) only has one size and orientation, what can you do!
  391.  *
  392.  */
  393. void dr_put_text(x, y, xofs, yofs, angle, size, s)
  394. float x, y;            /* where to put it */
  395. float xofs, yofs;        /* offset of start position, measured in */
  396.                 /* character size units */
  397. float angle;            /* radians, 0.0 == horizontal */
  398. float size;            /* relative size of text */
  399. char *s;            /* the text */
  400. {
  401.     char ss[60];
  402.     int senddir;
  403.     char dir[30];
  404.  
  405.     if (size <= 0.0) {
  406.     sprintf(ss, "invalid size: %f");
  407.     dr_errmsg(ss);
  408.     return;
  409.     }
  410.     size *= size_factor;
  411.  
  412.     switch (device)
  413.       {
  414.       case HP7475:
  415.       senddir = (angle != 0.0);
  416.       if (senddir) {
  417.           if (angle == M_PI_2)
  418.         sprintf(dir,"DI0,1");
  419.           else if (angle == -M_PI_2)
  420.         sprintf(dir,"DI0,-1");
  421.           else
  422.         sprintf(dir,"DI1,%f", tan(angle));
  423.       }
  424.  
  425.       /* lift pen, go to specified position, set direction & size,
  426.        */
  427.  
  428.       (void)sprintf(ss, "PA;PU%d,%d;%s;SR%4.2f,%4.2f;\n",
  429.             xscale(x), yscale(y),
  430.             (senddir ? dir : ""), 
  431.             size * 0.75 * shape_factor * xrelarea,
  432.             size * 1.5 * yrelarea);
  433.       sends(ss);
  434.  
  435.       /* go to offset,
  436.        * put text,
  437.        * restore 0 degree direction.
  438.        */
  439.       if ((xofs != 0.0) || (yofs != 0.0)) {
  440.           (void)sprintf(ss, "CP%4.2f,%4.2f;\n", xofs, yofs);
  441.           sends(ss);
  442.       }
  443.       sends("LB"); sends(s); sends("\03\n");
  444.  
  445.       /* correction for y-offset, if necessary, to leave pen on same */
  446.       /* height but after the text */
  447.       if (yofs != 0.0) {
  448.           (void)sprintf(ss, "CP0,%4.2f;\n", -yofs);
  449.           sends(ss);
  450.       }
  451.  
  452.       if (senddir)
  453.         sends("DI1,0;\n");
  454. /*      lastx = ....;
  455.       lasty = ....;        /* hp7475 does not really need these, */
  456.                 /* it remembers the pen position */
  457.  
  458.       break;
  459. #ifdef GL_LIB
  460.       case SCREEN:
  461.       n_movepen(xscale(x), yscale(y));
  462.  
  463. #define GL_MODE_255_HAS_BUG
  464. #ifdef GL_MODE_255_HAS_BUG
  465.       /* DT Lewis!!  Wake up! */
  466.       /* For some reason gl_lib works strangely with GL_MODE == 255 */
  467.       /* (the output is  (almost) microscopic small and weird shape). */
  468.       /* We can compensate that strangeness here by modifying size */
  469.       /* and sape factors for g_fontctl()...  The values 3.0 and 0.4 */
  470.       /* are experimental results (by kekkonen@sah.vtt.fi). */
  471.       if (strncmp(getenv("GLMODE"),"256",3)==0)
  472.         g_fontctl(3.0*size*yrelarea, 0.4*shape_factor, 1.0, angle, 0.0);
  473.       else
  474. #endif
  475. #undef GL_MODE_255_HAS_BUG
  476.         g_fontctl(size*yrelarea, shape_factor, 1.0, angle, 0.0);
  477.       yofs = -0.5 - yofs;
  478.       n_ch_ofs(xofs, yofs);
  479.       n_grafstr(s);
  480.       n_ch_ofs(0.0, -yofs);
  481.       g_fontctl(size, 1.0, 1.0, 0.0, 0.0);
  482. /*      lastx = ....;
  483.       lasty = ....;        /* this does not really need these, */
  484.                 /* it remembers the pen position */
  485.  
  486.       break;
  487. #endif
  488. #ifdef PLOT
  489. #define PLOT_CH_XSIZE 70
  490. #define PLOT_CH_YSIZE 100
  491.       case PLOTLIB:
  492.       {
  493.           int i;
  494.           float xsize, ysize;
  495.           float xbase, ybase;
  496.           float xincr, yincr;
  497.           float xofs1, yofs1;
  498.  
  499.           xsize = PLOT_CH_XSIZE * size * xrelarea;
  500.           ysize = PLOT_CH_YSIZE * size * yrelarea;
  501.  
  502.           yofs += 0.4;    /* middle --> botom */
  503.           xofs1 = (xofs * xsize * cos(angle) * shape_factor -
  504.                yofs * ysize * sin(angle));
  505.           yofs1 = (xofs * xsize * sin(angle) * shape_factor +
  506.                yofs * ysize * cos(angle));
  507.           xbase = xscale(x) + xofs1;
  508.           ybase = yscale(y) + yofs1;
  509.  
  510.           xincr = cos(angle) * xsize * shape_factor;
  511.           yincr = sin(angle) * ysize;
  512.           
  513.           /* This is how we simulate different printing directions */
  514.           /* and character sizes: by moving to the position of every */
  515.           /* single character one at a time */
  516.           *(ss+1) = '\0';
  517.           for (i=0; *ss=*s; s++,i) {
  518.           move((int) (0.5 + xbase + i * xincr),
  519.                (int) (0.5 + ybase + i * yincr));
  520.           label(ss);
  521.           i++;
  522.           }
  523.  
  524.           lastx = (int) (0.5 + xbase + i * xincr - xofs1);
  525.           lasty = (int) (0.5 + ybase + i * yincr - yofs1);
  526.           move(lastx, lasty);
  527.       }
  528.       break;
  529. #endif
  530.       default:
  531.       invdev(); break;
  532.       }
  533.     return;
  534. }
  535.  
  536. /*
  537.  * dr_small_circle()  - draw small circle at current point.
  538.  * This routine needs the help of lastx and lasty in case of plot(3) library.
  539.  *
  540.  */
  541. void dr_draw_circle()
  542. {
  543.     switch (device)
  544.       {
  545.       case HP7475:
  546.       sends("CI35;\n");      break;
  547. #ifdef GL_LIB
  548.       case SCREEN:
  549.       n_ellipse1(100, 100);      break;
  550. #endif
  551. #ifdef PLOT
  552.       case PLOTLIB:
  553.       circle(lastx, lasty, 20);      break;
  554. #endif
  555.       default:
  556.       invdev(); break;
  557.       }
  558. }
  559.  
  560.  
  561. /*
  562.  * dr_finish()  - terminate the plotting
  563.  *
  564.  * This routine must be called after all plotting activity is done
  565.  * to restore the Y-cable connection so that terminal gets control
  566.  */
  567. int dr_finish(clean_scr)
  568. int clean_scr;            /* != 0 if we have clear screen */
  569. {
  570.     char s[20];
  571.  
  572.     switch (device)
  573.       {
  574.       case HP7475:
  575.       /* deselct pen,
  576.        * reset Y-cable connection
  577.        *   (<esc>.Z is ignored if not Y-cable connecton )
  578.        */
  579.       (void)sprintf(s, "SP;%c.Z\n", ESC);
  580.       sends(s);
  581.       break;
  582. #ifdef GL_LIB
  583.       case SCREEN:
  584.       if (clean_scr && (strncmp(getenv("GLMODE"), "256", 3) != 0)) {
  585. #ifdef UNIX
  586.           FILE *fp = fopen("/dev/tty", "r");
  587.           fgets(s, 2, fp);    /* wait for user response */
  588.           fclose(fp);
  589. #endif /* UNIX */
  590. #ifdef MSDOS
  591.           _bios_keybrd(_KEYBRD_READ); /* wait for keybrd. input forever */
  592. #endif /* MSDOS */
  593.       }
  594.       {
  595.           int status;
  596.           status = g_finish();    /* do clean screen */
  597.           if (status != 0)
  598.         dr_errmsg("dr_lib(): problems with g_finish().");
  599.       }
  600.       break;
  601. #endif
  602. #ifdef PLOT
  603.       case PLOTLIB:
  604.       move(0,0);
  605.       closepl();
  606.       break;
  607. #endif
  608.       default:
  609.       break;        /* call to invdev() --> recursion */
  610.       }
  611.       
  612.     /* check errors, tell if any or remove error log file
  613.      */
  614.     if (errcount == 0 && warncount == 0)
  615.       (void)unlink(errfilename);
  616.     else {
  617.     if (errcount)
  618.       (void)fprintf(stderr, "%d error%s,",
  619.             errcount, (errcount == 1 ? "" : "s"));
  620.     if (warncount)
  621.       (void)fprintf(stderr, "%d warning%s,",
  622.             warncount, (warncount == 1 ? "" : "s"));
  623.     (void)fprintf (stderr, " see file \"%s\".\n", errfilename);
  624.     }
  625.     /* return something useful
  626.      */
  627.     return (errcount);
  628. }
  629.  
  630.  
  631. /*
  632.  * dr_start  - init the plotting device
  633.  *
  634.  * This routine must be called before any plotting activity is done
  635.  * to set up the Y-cable connction so that plotter starts processing
  636.  * or in case of direct connection, open the device
  637.  */
  638. void dr_start(xlow, ylow, xhigh, yhigh, dev)
  639. int dev;            /* plotting device & paper size */
  640. float xlow, xhigh;        /* drawing area, relative to.. */
  641. float ylow, yhigh;        /* ..whole paper, that means: */
  642.                 /* 0.0, 0.5, 0.5, 1.0 will use */
  643.                 /* upper left quarter of paper */
  644. {
  645.     int p1x, p1y, p2x, p2y;
  646.     float t1, t2;
  647.     char s[200];
  648.  
  649.     /* open error log file
  650.      */
  651.     errcount = 0;
  652.     warncount = 0;
  653.     if ((errfilefp = fopen(errfilename, "w")) == NULL) {
  654.     (void)fprintf(stderr, "\nCan't open %s.  Aborting.\n", errfilename);
  655.     exit(1);
  656.     }
  657.     errfile = fileno(errfilefp);
  658.     xrelarea = xhigh - xlow;
  659.     yrelarea = yhigh - ylow;
  660.     shape_factor = yrelarea/xrelarea; /* back to normal 'fatness' */
  661.     size_factor = 1.0;        /* actual size normalized to area */
  662.  
  663.     switch (device = (dev & DEVMASK))
  664.       {
  665.       case HP7475:
  666.       /* set Y-cable connection,
  667.        *   (<esc>.Y is ignored if not Y-cable connecton )
  668.        * init the plotter,
  669.        * set handshake mode x-on/x-off,
  670.        * select pen #1
  671.        */
  672.       (void)sprintf(s, "\n%c.Y;IN;", ESC); /* Y-connection, plotter on */
  673.       sends(s);
  674.       (void)sprintf(s, "%c.I80;;17:", ESC);    /* enable x-on/x-off x-on=^q */
  675.       sends(s);
  676.       (void)sprintf(s, "%c.N;19:\n", ESC);    /* x-off=^s */
  677.       sends(s);
  678. #ifdef ASK
  679.       /* ask picture area from plotter
  680.        * set up limits (leave some room for axis labels etc.) */
  681.       sends("OP;");
  682.       takes(s);
  683. #else /* ASK */
  684.        /* we would get one of this */
  685.       switch (dev & SIZEMASK)
  686.         {
  687.         case SIZE_A:
  688.         (void)sprintf (s, "250,596,10250,7796\n");
  689.         sends("PS4;\n");
  690.         break;
  691.         case SIZE_A4:
  692.         (void)sprintf (s, "603,521,10603,7721\n");
  693.         sends("PS4;\n");
  694.         break;
  695.         case SIZE_B:
  696.         (void)sprintf (s, "522,259,15722,10259\n");
  697.         sends("PS3;\n");
  698.         break;
  699.         case SIZE_A3:
  700.         (void)sprintf (s, "170,602,15370,10602\n");
  701.         sends("PS3;\n");
  702.         break;
  703.         default:
  704.         dr_errmsg("Invalid paper size.  Aborting.");
  705.         (void)dr_finish();
  706.         exit(1);
  707.         }
  708. #endif /* ASK */
  709.       if ( sscanf(s, "%d,%d,%d,%d", &p1x, &p1y, &p2x, &p2y) == 4 ) {
  710.                 /* some room for labels */
  711.           t1 = p1x + 0.05*(p2x-p1x); /* y-label */
  712.           t2 = p2x - 0.001*(p2x-p1x); /* right margin */
  713.           xdevicelow  = t1 + xlow * (t2 - t1);
  714.           xdevicehigh = t1 + xhigh * (t2 - t1);
  715.           t1 = p1y + 0.05*(p2y-p1y); /* x-label */
  716.           t2 = p2y - 0.07*(p2y-p1y); /* name */
  717.           ydevicelow  = t1 + ylow * (t2 - t1);
  718.           ydevicehigh = t1 + yhigh * (t2 - t1);
  719.       }
  720.       else {
  721.           dr_errmsg("Can't receive plotter dimensions.  Aborting.");
  722.           (void) dr_finish();
  723.           exit(1);
  724.       }
  725.       
  726.       dr_set_pen(1);        /* select some pen */
  727.       break;
  728. #ifdef GL_LIB
  729.       case SCREEN:
  730.       p1x = 0;    p1y = 32767;
  731.       p2x = 32767;    p2y = 0;
  732.       t1 = p1x + 0.06*(p2x-p1x); /* room y-axis label */
  733.       t2 = p2x - 0.001*(p2x-p1x); /* no room at right margin */
  734.       xdevicelow  = t1 + xlow * (t2 - t1);
  735.       xdevicehigh = t1 + xhigh * (t2 - t1);
  736.       t1 = p1y + 0.10*(p2y-p1y); /* room for x-axis label */
  737.       t2 = p2y - 0.05*(p2y-p1y); /* room fo picture's name */
  738.       ydevicelow  = t1 + ylow * (t2 - t1);
  739.       ydevicehigh = t1 + yhigh * (t2 - t1);
  740.  
  741. #define ENV_MODE 0        /* from gl.h; it means that g_init() will */
  742.                 /* look operating mode in environment */
  743.                 /* variable GLMODE */
  744.       g_init(ENV_MODE);
  745. #undef ENV_MODE
  746.       /* dr_set_pen(1);        /* select some pen */
  747.       break;
  748. #endif
  749.  
  750. #ifdef PLOT
  751.       case PLOTLIB:
  752.                 /* Y-cable for Tektornix? */
  753.       p1x = 0;    p1y = 0;
  754.       p2x = 5450;    p2y = 4095;
  755.                 /* 5% room for labels */
  756.       t1 = p1x + 0.07*(p2x-p1x); /* y-label */
  757.       t2 = p2x - 0.02*(p2x-p1x);; /* righ margin */
  758.       xdevicelow  = t1 + xlow * (t2 - t1);
  759.       xdevicehigh = t1 + xhigh * (t2 - t1);
  760.       t1 = p1y + 0.10*(p2y-p1y); /* x-label */
  761.       t2 = p2y - 0.05*(p2y-p1y); /* name */
  762.       ydevicelow  = t1 + ylow * (t2 - t1);
  763.       ydevicehigh = t1 + yhigh * (t2 - t1);
  764.  
  765.       openpl();
  766.       space(0,0,4096,4096);
  767.       erase();
  768.       break;
  769. #endif
  770.       default:
  771.       invdev(); break;
  772.       }
  773.     
  774.     /* check coordinate position legality
  775.      */
  776.     if (xlow < -0.0001 || xhigh > 1.0001 ||
  777.     ylow < -0.0001 || yhigh > 1.0001) {
  778.     dr_errmsg("Illegal x/y low/high position.  Aborting.");
  779.     (void)dr_finish();
  780.     exit(1);
  781.     }
  782.     return;
  783. }
  784.  
  785.  
  786. /* 
  787.  * dr_xgrid  - draw x grid 
  788.  *
  789.  * Draw grid lines parallel to y-axis.  When argument n == 0, makes
  790.  * lines at every tic-mark, n == 1 makes one grid line between every
  791.  * tic mark etc.  To leave grid lines away, just don't call this.
  792.  */
  793. void dr_xgrid(n)
  794. int n;                /* number of grid lines */
  795.                 /* between tic-marks */
  796. {
  797.     int i;
  798.     int x, y1, y2;        /* temps for grid line positions */
  799.     int nlines;            /* number of grid lines to draw */
  800.     char s[200];
  801.  
  802.     /* check interval
  803.      */
  804.     if (n < 1) {
  805.     dr_errmsg("Invalid x-grid interval, using 1");
  806.     n = 1;
  807.     }
  808.  
  809.     /* how many lines we have?
  810.      */
  811.     nlines = (int) (n*(xuserhigh-xuserlow)/xuserincr - 0.5);
  812.  
  813.      switch (device)
  814.       {
  815.       case HP7475:
  816.       /*  select absolute moving
  817.        */
  818.       sends("PA;\n");
  819. #ifdef SLOW
  820.       if (slow) {
  821.       }
  822. #endif      
  823.       /* draw desired number of lines, sawing up and down
  824.        */
  825.       y1 = yscale(yuserlow);
  826.       y2 = yscale(yuserhigh);
  827.       for (i=1; i<=nlines; i++) {
  828.                 /* go up */
  829.           x = xscale(i*xuserincr/n+xuserlow);
  830.           (void)sprintf(s, "PU%d,%d;PD%d,%d;", x, y1, x, y2);
  831.           sends(s);
  832.                 /* go down */
  833.           if (++i <= nlines) {
  834.           x = xscale(i*xuserincr/n+xuserlow);
  835.           (void)sprintf(s, "PU%d,%d;PD%d,%d;\n", x, y2, x, y1);
  836.           sends(s);
  837.           }
  838.       }
  839.       
  840.       /* lift pen
  841.        */
  842.       sends("PU;\n");
  843.       break;
  844. #ifdef GL_LIB
  845.       case SCREEN:
  846.       y1 = yscale(yuserlow);
  847.       y2 = yscale(yuserhigh);
  848.       for (i=1; i<=nlines; i++) {
  849.           x = xscale(i*xuserincr/n+xuserlow);
  850.           n_line(x,y1, x,y2);
  851.       }
  852.       break;
  853. #endif
  854. #ifdef PLOT
  855.       case PLOTLIB:
  856.       y1 = yscale(yuserlow);
  857.       y2 = yscale(yuserhigh);
  858.       for (i=1; i<=nlines; i++) {
  859.           x = xscale(i*xuserincr/n+xuserlow);
  860.           line(x,y1, x,y2);
  861.       }
  862.       break;
  863. #endif
  864.       default:
  865.       invdev(); break;
  866.       }
  867. }
  868.  
  869.  
  870. /* 
  871.  * dr_ygrid  - draw y grid 
  872.  *
  873.  * See dr_xgrid().
  874.  */
  875. void dr_ygrid(n)
  876. int n;
  877. {
  878.     int i;
  879.     int nlines;            /* number of lines */
  880.     char s[200];
  881.     int x1, x2, y;
  882.  
  883.     /* check interval
  884.      */
  885.     if (n < 1) {
  886.     dr_errmsg("Invalid y-grid interval, using 1");
  887.     n = 1;
  888.     }
  889.  
  890.     /* how many lines do we have?
  891.      */
  892.     nlines = (int) (n*(yuserhigh-yuserlow)/yuserincr - 0.5);
  893.  
  894.     switch (device)
  895.       {
  896.       case HP7475:
  897.       /* select absolute moving
  898.        */
  899.       sends("PA;\n");
  900.       
  901.       /* draw desired number of lines, sawing right and left
  902.        */
  903.       x1 = xscale(xuserlow);
  904.       x2 = xscale(xuserhigh);
  905.       for (i=1; i<=nlines; i++) {
  906.                 /* go right */
  907.           y = yscale(yuserlow+i*yuserincr/n);
  908.           (void)sprintf(s, "PU%d,%d;PD%d,%d;", x1, y, x2, y);
  909.           sends(s);
  910.                 /* go left */
  911.           if (++i <= nlines) {
  912.           y = yscale(yuserlow+i*yuserincr/n);
  913.           (void)sprintf(s, "PU%d,%d;PD%d,%d;", x2, y, x1, y);
  914.           sends(s);
  915.           }
  916.           sends("\n");
  917.       }
  918.       
  919.       /* lift pen
  920.        */
  921.       sends("PU;\n");
  922.       break;
  923. #ifdef GL_LIB
  924.       case SCREEN:
  925.       x1 = xscale(xuserlow);
  926.       x2 = xscale(xuserhigh);
  927.       for (i=1; i<=nlines; i++) {
  928.           y = yscale(i*yuserincr/n+yuserlow);
  929.           n_line(x1,y, x2,y);
  930.       }
  931.       break;
  932. #endif
  933. #ifdef PLOT
  934.       case PLOTLIB:
  935.       x1 = xscale(xuserlow);
  936.       x2 = xscale(xuserhigh);
  937.       for (i=1; i<=nlines; i++) {
  938.           y = yscale(i*yuserincr/n+yuserlow);
  939.           line(x1,y, x2,y);
  940.       }
  941.       break;
  942. #endif
  943.       default:
  944.       invdev(); break;
  945.       }
  946. }
  947.  
  948.  
  949. /* 
  950.  * dr_area_def  - establish x and y axis 
  951.  *
  952.  * [xy]low    lower left corner
  953.  * [xy]high   upper right corner
  954.  * [xy]incr   increment of tic-marks
  955.  * no_axes    flag, != 0 means don't draw axes
  956.  *
  957.  * Coordinate values will be printed at every tic-mark, so useful
  958.  * values for incr is such that (high-low)/incr will be some small
  959.  * integer.  With functions dr_xgrid() and dr_ygrid() it is possible to
  960.  * draw grid lines also in between these tic-marcs.
  961.  */
  962. void dr_area_def(xlow, xincr, xhigh, ylow, yincr, yhigh, no_axes)
  963. float xlow, xincr, xhigh;
  964. float ylow, yincr, yhigh;
  965. int no_axes;
  966. {
  967.     int i;
  968.     char units[30];        /* place for units */
  969.     char s[200];
  970.     float x, y;
  971.     int ix, iy, nx, ny;
  972.  
  973.     /* set the globals
  974.      */
  975.     xuserlow = xlow;   xuserhigh = xhigh;   xuserincr = xincr;
  976.     yuserlow = ylow;   yuserhigh = yhigh;   yuserincr = yincr;
  977.     xfactor = (xdevicehigh - xdevicelow) / (xuserhigh - xuserlow);
  978.     yfactor = (ydevicehigh - ydevicelow) / (yuserhigh - yuserlow) ;
  979.  
  980.     /* check legality,
  981.      * abort on error
  982.      */
  983.     if ((xincr == 0.0) ||
  984.     (xuserlow == xuserhigh) ||
  985.     ((xuserhigh-xuserlow)*xincr < 0.0)) {
  986.     dr_errmsg("x-axis defined improperly. Aborting.");
  987.     (void)dr_finish();
  988.     exit(1);
  989.     }
  990.     if ((yincr == 0.0) ||
  991.     (yuserlow == yuserhigh) ||
  992.     ((yuserhigh-yuserlow)*yincr < 0.0)) {
  993.     dr_errmsg("y-axis defined improperly. Aborting.");
  994.     (void)dr_finish();
  995.     exit(1);
  996.     }
  997.     if (no_axes)
  998.       return;
  999.     
  1000.     switch (device)
  1001.       {
  1002.       case HP7475:
  1003.  
  1004.       /* draw box
  1005.        * --------
  1006.        */
  1007.       
  1008.       /* select absolute plotting mode,
  1009.        * lift pen,
  1010.        * go to lower left corner
  1011.        */
  1012.       (void)sprintf(s,"PA;PU%d,%d;\n",
  1013.             xscale(xlow), yscale(ylow));
  1014.       sends(s);
  1015.       
  1016.       /* draw x-axis with x-tick marks
  1017.        */
  1018.       
  1019.       (void)sprintf(s, "TL%.1f,%.1f;\n", 0.5*xrelarea, 0.5*yrelarea);
  1020.       sends(s);
  1021.       for (nx=0, x = xlow;
  1022.            x < xhigh + xincr/100.0;
  1023.            x += xincr, nx++) {
  1024.           (void)sprintf(s, "PD%d,%d;XT;\n", xscale(x), yscale(ylow));
  1025.           sends(s);
  1026.       }
  1027.       (void)sprintf(s, "PD%d,%d;\n", xscale(xhigh), yscale(ylow));
  1028.       sends(s);
  1029.       
  1030.       /* draw y-axis with y-tick marks
  1031.        */
  1032.       (void)sprintf(s, "PU%d,%d;\n",
  1033.             xscale(xlow), yscale(ylow));
  1034.       sends(s);
  1035.       for (ny=0, y = ylow;
  1036.            y < yhigh + yincr/100.0;
  1037.            y += yincr, ny++) {
  1038.           (void)sprintf(s, "PD%d,%d;YT;\n", xscale(xlow), yscale(y));
  1039.           sends(s);
  1040.       }
  1041.       (void)sprintf(s, "PD%d,%d;\n", xscale(xlow), yscale(yhigh));
  1042.       sends(s);
  1043.  
  1044.       /* outer borders of the box
  1045.        */
  1046.       (void)sprintf(s, "PU%d,%d;PD%d,%d,%d,%d;PU\n",
  1047.             xscale(xlow), yscale(yhigh),
  1048.             xscale(xhigh), yscale(yhigh),
  1049.             xscale(xhigh), yscale(ylow));
  1050.       sends(s);
  1051.       break;
  1052. #ifdef GL_LIB
  1053. #define GL_TIC_SIZE 200
  1054.       case SCREEN:
  1055.       iy = yscale(ylow);
  1056.       n_movepen(xscale(xlow), iy);
  1057.  
  1058.       for (nx=0, x = xlow;
  1059.            x < xhigh + xincr/100.0;
  1060.            x += xincr, nx++) {
  1061.           ix = xscale(x);
  1062.           n_draw(ix, iy);
  1063.           n_line(ix, iy+GL_TIC_SIZE, ix, iy-GL_TIC_SIZE);
  1064.           n_movepen(ix, iy);
  1065.       }
  1066.       n_draw(xscale(xhigh), iy);
  1067.  
  1068.       /* draw y-axis with y-tick marks
  1069.        */
  1070.       ix = xscale(xlow);
  1071.       n_movepen(ix, yscale(ylow));
  1072.       for (ny=0, y = ylow;
  1073.            y < yhigh + yincr/100.0;
  1074.            y += yincr, ny++) {
  1075.           iy = yscale(y);
  1076.           n_draw(ix, iy);
  1077.           n_line(ix+GL_TIC_SIZE, iy, ix-GL_TIC_SIZE, iy);
  1078.           n_movepen(ix, iy);
  1079.       }
  1080.       n_draw(ix, yscale(yhigh));
  1081.       
  1082.       /* outer borders of the box
  1083.        */
  1084.       n_movepen(xscale(xlow), yscale(yhigh));
  1085.       n_draw(xscale(xhigh), yscale(yhigh));
  1086.       n_draw(xscale(xhigh), yscale(ylow));
  1087.       break;
  1088. #endif
  1089. #ifdef PLOT
  1090. #define PLOT_TIC_SIZE 40
  1091.       case PLOTLIB:
  1092.       iy = yscale(ylow);
  1093.       move(xscale(xlow), iy);
  1094.  
  1095.       for (nx=0, x = xlow;
  1096.            x < xhigh + xincr/100.0;
  1097.            x += xincr, nx++) {
  1098.           ix = xscale(x);
  1099.           cont(ix, iy);
  1100.           line(ix, iy+PLOT_TIC_SIZE, ix, iy-PLOT_TIC_SIZE);
  1101.           move(ix, iy);
  1102.       }
  1103.       cont(xscale(xhigh), iy);
  1104.  
  1105.       /* draw y-axis with y-tick marks
  1106.        */
  1107.       ix = xscale(xlow);
  1108.       move(ix, yscale(ylow));
  1109.       for (ny=0, y = ylow;
  1110.            y < yhigh + yincr/100.0;
  1111.            y += yincr, ny++) {
  1112.           iy = yscale(y);
  1113.           cont(ix, iy);
  1114.           line(ix+PLOT_TIC_SIZE, iy, ix-PLOT_TIC_SIZE, iy);
  1115.           move(ix, iy);
  1116.       }
  1117.       cont(ix, yscale(yhigh));
  1118.       
  1119.       /* outer borders of the box
  1120.        */
  1121.       move(xscale(xlow), yscale(yhigh));
  1122.       cont(xscale(xhigh), yscale(yhigh));
  1123.       cont(xscale(xhigh), yscale(ylow));
  1124.       break;
  1125. #endif
  1126.       default:
  1127.       invdev(); break;
  1128.       }
  1129.  
  1130.     
  1131.     /* put y-units
  1132.      */
  1133.     for (i=ny-1; i>=0; i--) {
  1134.      (void)sprintf(units, "%g", ylow + i * yincr);
  1135.      dr_put_text(xlow, ylow+i*yincr,
  1136.             -strlen(units)/2.0, -1.3, -M_PI_2, 1.0, units);
  1137.     }
  1138.  
  1139.     /* put x-units
  1140.      */
  1141.     for (i=0; i<nx; i++) {
  1142.     (void)sprintf(units, "%g", xlow + i * xincr);
  1143.     dr_put_text(xlow+i*xincr, ylow,
  1144.             -strlen(units)/2.0, -1.3, 0.0, 1.0, units);
  1145.     }
  1146.     return;
  1147. }
  1148.  
  1149. /*
  1150.  * linetypes
  1151.  *
  1152.  */
  1153. #ifdef GL_LIB
  1154. static long gl_line_types[] = {    /* 76543210765432107654321076543210 */
  1155.     0xf0000000L,        /* ====............................ */
  1156.     0xffff0000L,        /* ================................ */
  1157.     0xffffff00L,        /* ========================........ */
  1158.     0xffffff18L,        /* ========================...==... */
  1159.     0xfffff0f0L,        /* ====================....====.... */
  1160.     0xfffff39cL,        /* ====================..===..===.. */
  1161.     0xffffffffL,        /* ================================ */
  1162.     0x66666666L,        /* ==..==..==..==..==..==..==..==.. */
  1163.     0xf8f8f8f8L,        /* =====...=====...=====...=====... */
  1164.     0xffffff00L,        /* ========================........ */
  1165.     0xfc30fc30L };        /* ======....==....======....==.... */
  1166. #define DEF_GL_TYPE 7        /* this will produce continous line */
  1167. #endif /* GL_PLOT */
  1168. #ifdef PLOT
  1169. static char *plot_line_types[] = {
  1170.     "dotted",            /* 1 */
  1171.     "longdashed",        /* 2 */
  1172.     "shortdashed",        /* 3 */
  1173.     "dotdashed",        /* 4 */
  1174.     "solid",            /* 5 */
  1175.     "solid",            /* 6 */
  1176.     "solid" };            /* 7 */
  1177. #define DEF_PLOT_TYPE 7        /* this will produce continous line */
  1178. #endif /* PLOT */
  1179.  
  1180. int dr_set_ltype(linetype)
  1181. int linetype;
  1182. {
  1183.     char s[40];
  1184.     int old_val = old_linetype;
  1185.  
  1186.     switch (device)
  1187.       {
  1188.       case HP7475:
  1189.       if (linetype < 0 || linetype > 6) {
  1190.           linetype = 7;
  1191.           sends("LT;");
  1192.       }
  1193.       else {
  1194.           (void)sprintf(s, "LT%d;", linetype);
  1195.           sends(s);
  1196.       }
  1197.       break;
  1198. #ifdef GL_LIB
  1199.       case SCREEN:
  1200.       if (linetype < 1 ||
  1201.           linetype > (sizeof(gl_line_types) / sizeof(gl_line_types[0]))) {
  1202.            sprintf (s, "Invalid linetype: %d", linetype);
  1203.            dr_errmsg(s);
  1204.            linetype = DEF_GL_TYPE;
  1205.        }
  1206.       g_style(gl_line_types[linetype-1]);
  1207.       break;
  1208. #endif
  1209. #ifdef PLOT        
  1210.       case PLOTLIB:
  1211.       if (linetype < 1 ||
  1212.           linetype > (sizeof(plot_line_types) /
  1213.               sizeof(plot_line_types[0]))) {
  1214.            sprintf (s, "Invalid linetype: %d", linetype);
  1215.            dr_errmsg(s);
  1216.            linetype = DEF_PLOT_TYPE;
  1217.        }
  1218.       linemod(plot_line_types[linetype-1]);
  1219.       break;
  1220. #endif
  1221.       default:
  1222.       invdev(); break;
  1223.       }
  1224.     old_linetype = linetype;
  1225.     return old_val;
  1226. }
  1227.  
  1228. /*
  1229.  * xscale  - scaling in horizontal directon
  1230.  *
  1231.  * convert user x-coordinate to physical device x-coordinate
  1232.  */
  1233. static int xscale(x)
  1234. float x;
  1235. {
  1236.     int temp;
  1237.     char s[60];
  1238.  
  1239.     /* calculate it
  1240.      */
  1241.     temp = (int) ((x - xuserlow) * xfactor + xdevicelow + 0.5);
  1242.     /* check, if it is good
  1243.      */
  1244.     if ((temp >= -32768) && (temp <= 32767))
  1245.       return (temp);
  1246.  
  1247.     /* when not good make report,
  1248.      * return something
  1249.      */
  1250.     (void)sprintf(s, "x-value out of range: %f", x);
  1251.     dr_warnmsg(s);
  1252.     return (int) (xdevicelow + 0.5);
  1253. }
  1254.  
  1255.  
  1256. /*
  1257.  * yscale  - scaling in vertical directon
  1258.  *
  1259.  * convert user y-coordinate to physical device y-coordinate
  1260.  */
  1261. static int yscale(y)
  1262. float y;
  1263. {
  1264.     int temp;
  1265.     char s[60];
  1266.  
  1267.     /* calculate it
  1268.      */
  1269.     temp = (int) ((y - yuserlow) * yfactor + ydevicelow + 0.5);
  1270.  
  1271.     /* check, if it is good
  1272.      */
  1273.     if ((temp >= -32768) && (temp <= 32767))
  1274.       return (temp);
  1275.  
  1276.     /* when not good make report,
  1277.      * return something
  1278.      */
  1279.     (void)sprintf(s, "y-value out of range: %f", y);
  1280.     dr_warnmsg(s);
  1281.     return (int) (ydevicelow + 0.5);
  1282. }
  1283.  
  1284. static void invdev()
  1285. {
  1286.     dr_errmsg("Invalid plotting device.");
  1287.     (void)dr_finish();
  1288.     exit(1);
  1289. }
  1290.  
  1291.  
  1292. /*
  1293.  * dr_errmsg  - send a string to error output
  1294.  *
  1295.  */
  1296. void dr_errmsg(s)
  1297. char *s;
  1298. {
  1299.     char *p = s + strlen(s);
  1300.     if (p != s) p--;
  1301.     while ((p != s) && (*p == '\n')) /* strip the newlines */
  1302.       *(p--) = '\0';
  1303.     fprintf(errfilefp, "dr_lib error: %s\n", s);
  1304.     errcount++;
  1305.     return;
  1306. }
  1307.  
  1308.  
  1309. /*
  1310.  * warnmsg  - send a string to error output
  1311.  *
  1312.  */
  1313. void dr_warnmsg(s)
  1314. char *s;
  1315. {
  1316.     char *p = s + strlen(s);
  1317.     if (p != s) p--;
  1318.     while ((p != s) && (*p == '\n')) *(p--) = '\0';
  1319.     fprintf(errfilefp, "Warning: %s\n", s);
  1320.     warncount++;
  1321.     return;
  1322. }
  1323.  
  1324.  
  1325. /*
  1326.  * sends  - send something to plotting device
  1327.  *
  1328.  */
  1329. static void sends(s)
  1330. char *s;
  1331. {
  1332.     (void)printf("%s", s);
  1333. }
  1334.  
  1335. #ifdef ASK
  1336. /*
  1337.  * takes  - take a string from plotter (to read plotter coordinates)
  1338.  *
  1339.  */
  1340. #include <signal.h>
  1341. #include <setjmp.h>
  1342.  
  1343. jmp_buf sjbuf;
  1344. int (*savAlrm)();        /* save incomming alarm function */
  1345.  
  1346. static int timerh()        /* timer interrupt handler */
  1347. {
  1348.     longjmp(sjbuf, 1);
  1349. }
  1350.  
  1351. static void takes(s)
  1352. char *s;
  1353. {
  1354. #ifdef YCABLE
  1355.     savAlrm = signal(SIGALRM,timerh);
  1356.     alarm(2);            /* give time to wake up */
  1357.     if (setjmp(sjbuf)) {
  1358.     alarm(0);
  1359.     signal(SIGALRM,savAlrm); /* cancel timer */
  1360.     (void)dr_finish();
  1361.     (void)fprintf(stderr, "\n\7Timeout reading stdin.  Aborting.\n");
  1362.     exit(1);
  1363.     }
  1364.     gets(s);
  1365.     alarm(0);
  1366.     signal(SIGALRM,savAlrm);    /* cancel timer */
  1367. #else
  1368.     /* do it yorself */
  1369. #endif
  1370. }
  1371. #endif /* ASK */
  1372.