home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / d / dots151.zip / GRAPHSRC.ZIP / GRAPH.C < prev    next >
C/C++ Source or Header  |  1990-07-05  |  39KB  |  1,267 lines

  1. /*
  2. #define MOUSE
  3.     graph - graph a function of a single variable
  4.  
  5.     history...
  6.         5 Jul 90    Ver 3.21: Script files may have comments.
  7.         4 Jul 90    Ver 3.20: Added support for device driver configuration
  8.                     files.
  9.         16 Jun 90    Ver 3.19: Accepting two script file reference syntaxes.
  10.                     If a log scale switch causes a labeled point to be
  11.                     discarded, the label is moved to the last retained
  12.                     point.
  13.         14 Jun 90    Ver 3.18: Fetching options from environment variable
  14.                     GRAPH.
  15.         19 Apr 90    Ver 3.17: displaying up to 16380 data points (or
  16.                     as limited by user memory).
  17.         6 Mar 90    Ver 3.16: allowing axes separated from graph area.
  18.         27 Feb 90    Ver 3.15: no longer attempts to restore video mode
  19.                     if graphics mode was never set.  Fixed occasional
  20.                     divide-by-zero bug for screens with subsquare
  21.                     pixels (pixel width > pixel height, like the VGA).
  22.         19 Feb 90    Ver 3.14: No more text mode error messages if a memory
  23.                     allocation fails while in graphics mode.  Coherent
  24.                     error message if script file cannot be opened.
  25.                     Default script file name is constructed from data file
  26.                     name.  Menu starts at top right.
  27.         16 Sep 89    Ver 3.13: Switching to log scales no longer temporarily 
  28.                     drops a linestyle.  "abscissa" menu option can now
  29.                     discard y values.
  30.         15 Sep 89    Ver 3.12: Adding styles interactively automatically
  31.                     enables breaking, keystrokes entered during a redraw
  32.                     are not echoed through DOS when they are discarded.    
  33.         13 Aug 89    Ver 3.11: Automatically adjusting width to be consistent
  34.                     with right move, etc.
  35.         1 Jul 89    Ver 3.10: graphics mode menus, mouse handler.
  36.         16 May 89    Cleaned up nonportable constructions.
  37.         4 May 89    Ver 3.09: user can adjust grid width & number of tic
  38.                     marks interactively.  Markers don't have corner glitches.
  39.         25 Apr 89    Ver 3.08: not adjusting # tic marks for label size
  40.                     if no numeric labels are requested.
  41.         24 Apr 89    using intensity if color isn't available.
  42.         8 Apr 89    Ver 3.07: name of input script file becomes default for 
  43.                     output script file
  44.         6 Apr 89    Ver 3.06: optionally writes data file names to script file
  45.         5 Apr 89    Ver 3.05: writes -c and -n switches to output script file
  46.                     The part of argv[] referring to data files is preserved.
  47.         22 Mar 89    Ver 3.04: requests correct number of tic marks in
  48.                     script file.
  49.         27 Feb 89    Ver 3.03: quits gracefully if there are no data points
  50.         23 Nov 88    Ver 3.02: Minor corrections for line style and
  51.                     axis limit menus.
  52.         23 Sep 88    Ver 3.01: Interactive update of label, abscissa
  53.                     start & step.  Linestyles can be deleted or
  54.                     inserted.  X and y menus accept only one input. 
  55.                     For "plotting devices", bottom right hand numerical
  56.                     label is centered on the tic mark.
  57.         5 Aug 88    Ver 3.00: Allowing interactive update of switches 
  58.                     via menubars.
  59.         1 Aug 88    Ver 2.49: Allowing 100 styles rather than 30.
  60.                     Style of FF suppresses display entirely.
  61.         4 May 88    Ver 2.48: Allows axis labels as high as 10000 before
  62.                     switching to scientific notation.
  63.         23 Mar 88    Ver 2.47: Warns about points dropped after memory is
  64.                     full.
  65.         4 Mar 88    Ver 2.46: Can display bottom and left axes only.
  66.         10 Feb 88    Ver 2.45: Restarts automatic abscissas with each
  67.                     new curve.
  68.         23 Jan 88    Ver 2.44: Reads parameters from script file.
  69.         3 Dec 87    Ver 2.43: Fixed linestyle so symbols work again.
  70.         25 Nov 87    Ver 2.42: The linestyle is interpreted as a hex
  71.                     number, so the color digit can range from 0 (white)
  72.                     through f.  Plot area is shrunk if necessary so
  73.                     wide grid stays within specified width and height.
  74.         29 Oct 87    Ver 2.41: Marker color controlled only by the
  75.                     second digit of the style number.
  76.         25 Aug 87    Ver 2.40: Large number of labels permitted, via
  77.                     dynamic reallocation (shrinking) of data arrays. 
  78.                     Saving repeat counts.
  79.         20 Aug 87    Ver 2.39: Tic marks can be outside graph area.  # small
  80.                     tic marks is adjustable.
  81.         17 Aug 87    Ver 2.38: width of grid lines can be specified.
  82.         9 Aug 87    Ver 2.37: Points can be labeled even if tabs rather than
  83.                     spaces are used for separators.  Null byte in input file
  84.                     signifies break in plot (end of curve).
  85.         6 Aug 87    Ver 2.36: fixed off-by-one error in label positioning:
  86.                     graph is once again broken correctly if data points
  87.                     come from separate files
  88.         29 Jul 87    Ver 2.35: line styles may have repeat counts.
  89.                     e option gives equal vertical and horizontal scales.
  90.                     numeric requires presence of at least one numeral.
  91.         21 Jul 87    Ver 2.34: #labels and #tics requested are adjusted
  92.                     according to the aspect ratio of the display used.
  93.         28 Jun 87    Ver 2.33: Any number of labels
  94.         31 May 87    Ver 2.32: Corrected vertical positioning of labels.
  95.         26 May 87    Ver 2.31: specifying more than one linestyle
  96.                     automatically turns "breaking" on, styles from
  97.                     multiple -m options accumulate.
  98.         21 May 87    Ver 2.30: plotting magnitude or phase.
  99.         7 May 87    Ver 2.21: Reading into doubles, checking for overflow
  100.                     before converting to floats.  This allows reading very
  101.                     small data values.
  102.         6 Apr 87    Ver 2.20: Options may be intermixed with files.
  103.                     Multiple files accepted.
  104.         5 Apr 87    Log axes labeled with superscripts.
  105.         11 Sep 86    Last specified line style is the default.
  106.         5 Sep 86    Ver 2.10: Storing points as floats rather than longs,
  107.                     accepting 5000 points.
  108.         28 Jun 86    Ver 2.01: Accepting 3000 points rather than 1000.
  109.         4 Jun 86    If input comes from stdin, closing and reopening it to
  110.                     allow for keyboard input.
  111.         3 May 86    Calculating approx. label width before reducing # labels.
  112.         14 Apr 86    Ver 2.0: Reducing # labels for narrow plots.
  113.         13 Apr 86    Ver 1.9: Specifying minimum and maximum works for
  114.                     log scales.
  115.                     Allowing 9 characters on left for labels.
  116.         12 Apr 86    Ver 1.8: Scaling axis labels by factors of 1000. 
  117.                     Allowing 8 characters on left for labels.
  118.                     Placing text label above graph.
  119.                     Label starting with '"' can contain spaces.
  120.                     Scientific notation allowed in switches.
  121.         6 Apr 86    Tic marks on sides and top are same length, even for
  122.                     narrow or squat plot windows.  Ignoring blank lines.
  123.         9 Aug 85    Using box marker rather than plus, setting viewport based
  124.                     actual character width.
  125.         14 Nov 85    Enlarged array sizes and stopped reading when max label
  126.                     count exceeded.
  127.         14 Nov 85    Writing text label after drawing axes.
  128.         17 Nov 85    Drawing axes before figure.
  129.         23 Nov 85    Ignoring data lines beginning with ';'.
  130. */
  131.  
  132. #include <stdlib.h>
  133. #include <stdio.h>
  134. #include <string.h>
  135. #include <math.h>
  136. #include <dos.h>
  137.  
  138. #include "g.h"
  139. #include "g3.h"
  140. #include "graph.h"
  141.  
  142. #define RIGHT1 "Copyright (c) 1985 - 1990  James R. Van Zandt (jrv@mbunix.mitre.org)\n"
  143. #define RIGHT2 "Resale forbidden, copying encouraged, comments welcome."
  144.  
  145. #define VERSION "3.21"
  146.  
  147. #define amax1(a,b) (((a)>(b))?(a):(b))
  148.  
  149. #ifdef __TURBOC__
  150. #define key_avail() kbhit()
  151. #include <string.h>
  152. #include <ctype.h>
  153. #else
  154. #define key_avail() _os(0xb,0)
  155. #define strchr(a,b) index(a,b)
  156. #endif
  157.  
  158. #define BIGFLOAT 6.e38    /* no floats larger than this  */
  159. #define ENTRIES 5000
  160. #define MAXSTYLES 100
  161. #define BUFSIZE 200
  162. char buf[BUFSIZE];
  163.  
  164.  
  165.                             /* local functions */
  166. void to_text( void );
  167. static image( );
  168. static range_check( double x );
  169. static read_data( int *argcp, char ***argvp );
  170. static initialize( );
  171. static display_data( );
  172. static int handle_break( );
  173.  
  174.  
  175. float *x, *y;
  176.  
  177. double xmin, xmax, xdel = 0., ymin, ymax, ydel = 0.;
  178. double
  179.     height_used,        /* fraction of vertical space used */
  180.     width_used,            /* fraction of horizontal space used    */
  181.     right_move,            /* fraction of space to move right before plotting */
  182.     up_move,            /* fraction of space to move up before plotting */
  183.     requested_height_used=1.,    /* initial values for above */
  184.     requested_width_used=1.,    
  185.     requested_right_move=0.,    
  186.     requested_up_move=0.,
  187.     abscissa,            /* current value for automatic abscissas */
  188.     abscissa_start=0.,    /* default starting value for automatic abscissas */
  189.     abscissa_step=1.;    /* default step for automatic abscissas */
  190.  
  191. extern int    debugging;
  192.  
  193. int    markers=0;
  194. int equal=0;                /* nonzero if vertical and horizontal scales
  195.                                 must be equal */
  196. int text_labeling=0;
  197. int numeric_labeling=1;
  198. int out_of_memory=0;        /* set nonzero when malloc fails */
  199. int grid_width=1;            /* width of grid lines */
  200. int grid_style=1;            /* 0 for no grid, 1 for frame with tics,
  201.                                 2 for full grid, 3 for left and lower
  202.                                 sides only, negative for tic marks on
  203.                                 outside. */
  204. int breaking=0;                /* nonzero if breaking (disconnecting) graph
  205.                                 after each label in input */
  206. int default_labeling=0;        /* nonzero if default point label was given */
  207. int transposing=0;            /* nonzero if transposing x & y */
  208. int logx=0;                    /* nonzero if x axis is to be logrithmic */
  209. int logy=0;                    /* nonzero if y axis is to be logrithmic */
  210. int standard_input=0;        /* nonzero if data is coming from standard input */
  211. int x_arguments=0;            /* number specified: xmin, xmax, xdel    */
  212. int y_arguments=0;            /* number specified: ymin, ymax, ydel    */
  213. int automatic_abscissas=0;    /* nonzero if abscissas are to be generated */
  214. int magnitude=0;            /* nonzero if displaying magnitude of complex # */
  215. unsigned max_points=ENTRIES;    /* # x or y points */
  216. int phase=0;                /* nonzero if displaying phase of complex # */
  217. int dividing_by_pi=0;        /* nonzero if dividing phase by pi */
  218. int abscissa_arguments=0;    /* number specified: abscissa spacing & start */
  219. int last=0;                    /* number of entries in x and y */
  220. int rlx;                    /* number of x axis labels */
  221. int rly;                    /* number of y axis labels */
  222. int rtx;                    /* number of x axis tics */
  223. int rty;                    /* number of y axis tics */
  224. int requested_rlx=6;        /* initial values for above */
  225. int requested_rly=6;
  226. int requested_rtx=30;
  227. int requested_rty=30;
  228. int numstyles=0;            /* # linestyles specified by user 
  229.                                             (index into next two arrays) */
  230. int style[MAXSTYLES];        /* array of requested line styles    */
  231. int repeat[MAXSTYLES];        /* array of repeat counts for line styles    */
  232. int labels=0;                /* number of user-supplied labels */
  233. int graphics_mode = 0;        /* zero until the switch to graphics mode */
  234.  
  235. FILE *ifile, *fopen();
  236.  
  237. char *default_script_file = "";
  238. char null_label[] = "";
  239. char *default_label = "";
  240. char *text_label = "";
  241. char *program_name = NULL;
  242.  
  243. /* allocate block from heap, shrinking x & y if necessary */
  244. void *gmem(n) int n;  
  245. {    char *tmp;
  246.     void *malloc(), *realloc();
  247.     int size;
  248.     tmp =  malloc(n);
  249.     if(tmp != NULL) return tmp;
  250.     size = 30+n/sizeof(double);
  251.     if(last < max_points-size-10)
  252.         {max_points -= size;  /* free up almost 2*(30*8+n) = 480+2*n bytes */
  253. /* if memory management is working correctly, these should all succeed */
  254.         x = (float *)realloc(x, max_points*sizeof(float));
  255.         y = (float *)realloc(y, max_points*sizeof(float));
  256.         tmp =  malloc(n);
  257.         if(x != NULL && y != NULL && tmp != NULL) return tmp;
  258.         }
  259.     out_of_memory = 1;
  260.     return NULL;
  261. }
  262.  
  263. /* allocate a block, otherwise stop program */
  264. void *getmem(n) int n;
  265. {    char *tmp;
  266.     tmp = gmem(n);
  267.     if(tmp == NULL)
  268.         {to_text();
  269.         fprintf(stderr, "\007out of memory");
  270.         exit(1);
  271.         }
  272.     return tmp;
  273. }
  274.  
  275. typedef struct _blk
  276.     {struct _blk *nxt;
  277.     int num;
  278.     char txt[1];
  279.     } BLOCK;
  280.  
  281. BLOCK *top_label, *last_label;
  282. BLOCK *new_label(n, s) int n; char *s;
  283. {    BLOCK *tmp;
  284.     tmp =  (BLOCK *)gmem(sizeof(BLOCK)+strlen(s));
  285.     if(tmp)
  286.         {tmp->nxt = (BLOCK *)0;
  287.         tmp->num = n;
  288.         strcpy(tmp->txt, s);
  289.         }
  290.     return tmp;
  291. }
  292.  
  293. void to_text( void )
  294. {    if(graphics_mode) finish_graphics();
  295.     graphics_mode = 0;
  296. }
  297.  
  298. static int handle_break()
  299. {            /* control comes here if user types ^C */
  300. /*    scr_term(); */
  301.     terminate_view_surface(1); 
  302.     exit(0);
  303. }
  304.  
  305. #ifdef __DESMET__
  306. uncook(handle) unsigned handle;
  307. {    /*    select raw input mode for keyboard input */
  308.     unsigned extern _rax, _rbx, _rcx, _rdx;
  309.  
  310.     _rax = 0x4400;    /* I/O control read */
  311.     _rbx = handle;
  312.     _doint(0x21);
  313.     _rdx &= 0x00ff;
  314.     _rdx |= 0x0020;
  315.     _rax = 0x4401;    /* I/O control write */
  316.     _rbx = handle;
  317.     _doint(0x21);
  318. }
  319.  
  320. forcedup(unused, existing) unsigned unused, existing;
  321. {
  322.     unsigned extern _rax, _rbx, _rcx, _rdx, _carryf;
  323.     _rax = 0x4600;
  324.     _rbx = existing;
  325.     _rcx = unused;
  326.     _doint(0x21);
  327.     return _carryf;        /* return nonzero on error */
  328. }
  329. #endif
  330.  
  331. main(argc,argv) int argc; char **argv;
  332. {    int c;
  333.     double cur_xmin, cur_xmax, cur_ymin, cur_ymax;
  334.  
  335.     printf("GRAPH version %s, interface version %s for %s \n",
  336.         VERSION,interface_version,machine);
  337.  
  338.     initialize();    /* allocate storage for data points */
  339.     init_env();        /* get initial options from environment variable GRAPH */
  340.  
  341.     read_data(&argc,&argv);
  342.     if(last == -1) {fprintf(stderr, "no data values"); exit(1);}
  343.  
  344. /*    init_graphics();                /* this step switches to graphics mode */
  345.     initialize_core(0,0,2); /* only 2D functions will be required */
  346.     initialize_view_surface(1);
  347.     graphics_mode = 1;
  348.  
  349.     init_menus();
  350.  
  351.     ctrlbrk(handle_break);    /* register the control-break handler */
  352.     atexit(to_text);        /* register an exit function */
  353.  
  354.     while(1)
  355.         {cur_xmin = xmin;
  356.         cur_xmax = xmax;
  357.         cur_ymin = ymin;
  358.         cur_ymax = ymax;
  359.  
  360.         display_data();
  361.  
  362.         xmin = cur_xmin;
  363.         xmax = cur_xmax;
  364.         ymin = cur_ymin;
  365.         ymax = cur_ymax;
  366.         if(plotting_device) break;
  367.         if(standard_input) c = getc(ifile);
  368.         else
  369.             {
  370.             while(key_avail()) {scr_ci();}    /* clear input queue */
  371. #ifdef MOUSE
  372.             c = GetEvent();
  373. #else
  374.             c = scr_ci();
  375. #endif
  376.             }
  377.  
  378.         if(c != '/') break;
  379.         adjust_parameters(&argc, &argv);
  380.         }
  381.     terminate_view_surface(1); exit(0);
  382. }
  383.  
  384.  
  385. display_data()
  386. {    double lower, upper, delt, span, broadened, aspect, aspect2, adj, del;
  387.     int nlab, ntic, i, j, lw, max;
  388.  
  389.     rlx = requested_rlx;
  390.     rly = requested_rly;
  391.     rtx = requested_rtx;
  392.     rty = requested_rty;
  393.  
  394.     height_used = requested_height_used;
  395.     width_used = requested_width_used;
  396.     right_move = requested_right_move;
  397.     up_move = requested_up_move;
  398.  
  399. /*printf("xmin=%f, xmax=%f, ymin=%f, ymax=%f\n", xmin, xmax, ymin, ymax);*/
  400.     ndc_space_2(best_width,best_height);    /* use all the display surface */
  401.     if(text_labeling) height_used -= 1.5/(pixels_high/char_height);
  402.     if(numeric_labeling)  /* allow space for numeric labels */
  403.         {adj = 9./(pixels_wide/char_width);
  404.         right_move += adj;
  405.         width_used -= adj;
  406.         adj = 1.7/(pixels_high/char_height);
  407.         up_move += adj;
  408.         height_used -= adj;
  409.         }
  410.     adj = 0.;
  411.     del = .02*sqrt(width_used*width_used + height_used*height_used);
  412.     if(grid_style<0)  /* allow space for tic marks outside graph */
  413.         adj = 1.2*del;
  414.     if(abs(grid_style) > 3)        /* allow space for offset axes */
  415.           adj += 1.5*del;
  416.     right_move += adj; up_move += adj;
  417.     adj *= 2.;
  418.     width_used -= adj; height_used -= adj;
  419.  
  420.     if(grid_width>1)  /* allow space for wide grid lines */
  421.         {if(numeric_labeling)
  422.             {width_used -= (grid_width+2)/(2.*pixels_wide);
  423.             height_used -= (grid_width+2)/(2.*pixels_high);
  424.             }
  425.         else
  426.             {adj = (grid_width+2)/(double)(pixels_wide);
  427.             width_used -= adj; right_move += adj/2.;
  428.             adj = (grid_width+2)/(double)(pixels_high);
  429.             height_used -= adj; up_move += adj/2.;
  430.             }
  431.         }
  432.     if(equal)    /* adjust display width or height for approx. equal scales */
  433.         {aspect = (xmax-xmin)/(width_used*best_width)
  434.             /((ymax-ymin)/(height_used*best_height));
  435.         if(aspect<1.)    /* graph would be too short */
  436.             width_used *= aspect;
  437.         else            /* graph would be too tall */
  438.             height_used /= aspect;
  439.         }
  440.             /*    calculate square root of width to height ratio */
  441.     broadened = sqrt(width_used/height_used*best_width/best_height);
  442.             /*    adjust # tic marks and labels for graph aspect ratio */
  443.     rlx *= broadened;
  444.     rtx *= broadened;
  445.     rly /= broadened;
  446.     rty /= broadened;
  447.             /*    adjust # tic marks and labels to eliminate label overlap */
  448.     if(numeric_labeling)
  449.         {
  450.         if(logx) lw = 3;        /* calculate lw = maximum label width */
  451.         else
  452.             {lw = 4;
  453.             if(xmin<0.) lw++;                        /* sign */
  454.             if(xmax-xmin<.01) lw += 3;                /* negative exponent */
  455.             else if (xmax-xmin>1000.) lw += 2;        /* positive exponent */
  456.             }
  457.         max = width_used*pixels_wide/char_width;
  458.         if(max <= lw*rlx) rlx = max/lw;
  459.         max = height_used*pixels_high/char_height;
  460.         if(max <= rly) rly = max;
  461.         }
  462.  
  463.     height_used *= best_height; up_move *= best_height;
  464.     width_used *= best_width;    right_move *= best_width;
  465.     viewport2(right_move, right_move+width_used, up_move, up_move+height_used);
  466.     clip_window(1);
  467.  
  468. /*    printf("requesting x=%f to %f, y=%f to %f \n",xmin,xmax,ymin,ymax);
  469.     getchar();
  470. */
  471.     scale(xmin, xmax, rlx, rtx, logx, ymin, ymax, rly, rty, logy);
  472.     inquire_window(&xmin, &xmax, &ymin, &ymax);
  473.     if(equal)    /* adjust width and/or height to compensate for
  474.                     changes in window made by scale */
  475.         {aspect2 = (xmax-xmin)/width_used
  476.             /((ymax-ymin)/height_used);
  477.         if(aspect*aspect2<aspect ^ aspect*aspect2>aspect2) 
  478.             {    /* both changes in same directions - shrink by aspect2 */
  479.             if(aspect2<1.)    /* graph would be too short */
  480.                 width_used *= aspect2;
  481.             else            /* graph would be too tall */
  482.                 height_used /= aspect2;
  483.             }
  484.         else if(fabs(log(aspect2))<fabs(log(aspect)))
  485.             {    /* 2nd adjustment is smaller - enlarge graph by aspect2 */
  486.             if(aspect2<1.) height_used /= aspect2;
  487.             else           width_used *= aspect2;
  488.             }
  489.         else
  490.             {            /* first, enlarge graph by 1/aspect */
  491.             if(aspect<1.)  width_used /= aspect;
  492.             else           height_used *= aspect;
  493.                         /* now, shrink by aspect*aspect2 */
  494.             aspect2 *= aspect;
  495.             if(aspect2<1.) width_used *= aspect2;
  496.             else           height_used /= aspect2;
  497.             }
  498.         viewport2(right_move,right_move+width_used,up_move,up_move+height_used);
  499.         }
  500. /*    printf("plotting   x=%f to %f, y=%f to %f \n",xmin,xmax,ymin,ymax);
  501.     getchar();
  502. */
  503.     create_temporary_segment();
  504.  
  505.     set_color_or_intensity(0);
  506. /*
  507.     move_abs_2(.9*xmin+.1*xmax,1.02*ymax-.02*ymin);
  508.     text("temporary segment created\n");
  509. */
  510.     axis(numeric_labeling,grid_style, grid_width, width_used, height_used);
  511. /*
  512.     move_abs_2(.9*xmin+.1*xmax,1.02*ymax-.02*ymin);
  513.     text("axes displayed           \n");
  514. */
  515.     image();    /* generate the figure */
  516.     if(text_labeling)
  517.         {clip_window(0);
  518.         move_abs_2(.9*xmin+.1*xmax,1.02*ymax-.02*ymin);
  519.         text(text_label);
  520.         clip_window(1);
  521.         }
  522.     close_temporary_segment();
  523. }
  524.  
  525. /*
  526.     Parse arguments.  Switches and their arguments are removed from the
  527.     list of parameters.  Other parameters (which should be file names)
  528.     are left undisturbed.  Note the function arguments are pointers to
  529.     the normal argc and argv, so this routine may alter them.  In
  530.     particular, argv may be altered to point to a different string of
  531.     arguments (as a result of a -f switch)
  532.  
  533.     If there's an error...
  534.         In text mode (i.e.  it's interpreting command line arguments) or
  535.         if it can't allocate memory, prints an error message and stops the
  536.         program.
  537.  
  538.         In graphics mode (i.e.  it's been called by script_file in
  539.         gmouse), returns nonzero and leaves an error message in buf.
  540.         script_file can then print the error message and continue.
  541. */
  542. parse_args(argcp, argvp) int *argcp; char ***argvp;
  543. {
  544.     int i,
  545.         argc,        /* # parameters passed over (file names) */
  546.         nac,
  547.         ac;         /* # parameters remaining to be scanned */
  548.     char **argv,    /* pointers to parameters passed over */
  549.         **nav,
  550.         **av,         /* pointers to parameters remaining to be scanned */
  551.         *sname,        /* name of script file */
  552.         *s;            /* points to a token */
  553.     FILE *sfile;    /* script file */
  554.  
  555. #define strdup(s) strcpy(getmem(1 + strlen(s)), s)
  556.  
  557.     ac = *argcp; av = *argvp; argc = 0;
  558.     while(ac>0)
  559.         {if(**av == '@' || streq(*av, "-f"))
  560.             {if(**av == '-')                    /* older syntax: -f foo */
  561.                 {if(ac < 2) gripe_arg(*av);
  562.                 sname = av[1];
  563.                 av++; ac--;
  564.                 }
  565.             else sname = *av + 1;                /* newer syntax: @foo */
  566.             nav = av + 1;    /* save pointer to remaining parameters... */
  567.             nac = ac - 1;    /* ...and their count */
  568.  
  569.             sfile = fopen(sname, "r");
  570.             if(!sfile) 
  571.                 {sprintf(buf,"cannot open script file %s", sname); 
  572.                 if(graphics_mode) return 1;    /* signal the error */
  573.                 fprintf(stderr, buf);        /* ...or notify user & quit */
  574.                 exit(1);
  575.                 }
  576.                                         /* save file name for script_file() */
  577.             default_script_file = strdup(sname);
  578. /*
  579. {int i;
  580. FILE *dfile;
  581. dfile = fopen("debug", "a");
  582. fprintf(dfile, "%d+%d   orig parameters: ", argc, ac);
  583. for (i = 0; i < argc; i++) fprintf(dfile, "%s ", (*argvp)[i]);
  584. for (i = 0; i < nac; i++) fprintf(dfile, "%s ", nav[i]);
  585. fprintf(dfile, "\n");
  586. fclose(dfile);
  587. }
  588. */
  589.             ac = 0;
  590.             strtok("", " ");        /* force initial read from file */
  591.             while(token(sfile) != NULL) ac++;    /* count tokens in script file */
  592.             av = (char **)getmem((argc+ac+nac)*sizeof(char *));
  593.             for (i = 0; i<argc; i++) av[i] = (*argvp)[i]; /* copy file names */
  594. /*
  595. {int i;
  596. FILE *dfile;
  597. dfile = fopen("debug", "a");
  598. fprintf(dfile, "    passed file names: ");
  599. for (i = 0; i < argc; i++) fprintf(dfile, "%s ", av[i]);
  600. fprintf(dfile, "\n");
  601. fprintf(dfile, "          script file: %s, with %d parameters\n", sname, ac);
  602. fclose(dfile);
  603. }
  604. */
  605.             *argvp = av;
  606.             av += argc; ac = 0;
  607.             rewind(sfile);
  608.             strtok("", " ");        /* force initial read from file */
  609.             while((s = token(sfile)) != NULL)                /* copy token from file */
  610.                 {av[ac] = getmem(1+strlen(s));
  611.                 strcpy(av[ac++], s);
  612.                 }
  613.             fclose(sfile);
  614.             while(nac--) av[ac++] = *nav++;            /* copy remaining tokens */
  615. /*
  616. {int i;
  617. FILE *dfile;
  618. dfile = fopen("debug", "a");
  619. fprintf(dfile, "parameters afterwards: ");
  620. for (i = 0; i < ac + argc; i++) fprintf(dfile, "%s ", (*argvp)[i]);
  621. fprintf(dfile, "\n-----------------------\n");
  622. fclose(dfile);
  623. }
  624. */
  625.             }
  626.         else if(**av == '&')         /* device driver configuration file */
  627.             {config_file = (*av)+1;
  628.             ac--; av++;
  629.             }
  630.         else if(**av == '-')        /* normal switch */
  631.             {i = get_parameter(ac, av);
  632.             ac -= i; av += i;
  633.             }
  634.         else {(*argvp)[argc++] = *av++; ac--;}    /* data file */
  635.         }
  636.     *argcp = argc;
  637.     return 0;                /* no error */
  638. }
  639.  
  640. initialize()
  641. {
  642. #ifdef __DESMET__
  643.     double xx;
  644.  
  645.     sscanf("1.9","%lf",&xx);        /* workaround for bug in strtod() */
  646. #else
  647.     long data_bytes, farcoreleft();
  648.     data_bytes = (farcoreleft() - 10000)/2;    /* allow for labels, etc. */
  649.     if(data_bytes > 65536L - 16)             /* each array must be <64K */
  650.         data_bytes = 65536L - 16;            /* (allow for 16 byte overhead) */
  651.     max_points = data_bytes/sizeof(float);
  652. #endif
  653.  
  654.     x = (float *)malloc(max_points*sizeof(float));
  655.     y = (float *)malloc(max_points*sizeof(float));
  656.  
  657.     if(x == NULL || y == NULL) {puts("out of memory"); exit(1);}
  658.     top_label = new_label(-1, "");
  659. }
  660.  
  661. #define TR(x) /* printf x; scr_ci() /**/
  662. read_data(argcp, argvp) int *argcp; char ***argvp;
  663. {    int argno, i, j, ac, expected, argc;
  664.     double xx, yy, zz, d;
  665.     float *pd;
  666.     double actual_xmin, actual_xmax, actual_ymin, actual_ymax;
  667.     char *s, *t, **av, **argv;
  668.     argc = *argcp;
  669.     argv = *argvp;
  670.  
  671.     program_name = argv[0];            /* save program name (if any) */
  672.     argc--; argv++;                    /* skip program name */
  673.     if(argc >= 1 && **argv == '?') help();
  674.     parse_args(&argc, &argv);
  675.     if(automatic_abscissas && abscissa_arguments == 0 && x_arguments)
  676.         {abscissa_start = xmin;
  677.         }
  678.     abscissa = abscissa_start;
  679.     last = 0;
  680.     actual_xmin = actual_ymin = 1.e25;
  681.     actual_xmax = actual_ymax = -1.e25;
  682.     yy = zz = 0.;
  683.     expected = 2;
  684.     if(automatic_abscissas) expected--;
  685.     if(magnitude||phase) expected++;
  686.     argno = 0;
  687.     while(1)
  688.         {                            /* read a data file */
  689.         if(argno < argc)
  690.             {ifile = fopen(argv[argno], "r");
  691.             if(ifile == 0)
  692.                 {printf("file %s not found\n", argv[argno]);
  693.                 exit(1);
  694.                 }
  695.             else
  696.                 {if(*default_script_file==0)
  697.                     {                /* construct default script file name */
  698.                     s = getmem(3+strlen(argv[argno]));
  699.                     if(s)
  700.                         {default_script_file = s;
  701.                         strcpy(default_script_file, argv[argno]);
  702.                         if(s = strchr(default_script_file, '.')) *s=0;
  703.                         strcat(default_script_file, ".f");
  704.                         }
  705.                     }
  706.                 }
  707.             abscissa = abscissa_start;
  708.             }
  709.         else {ifile = stdin; standard_input++;}
  710.         argno++;
  711.         while(last<max_points)
  712.             {if(fgets(buf, BUFSIZE, ifile) == 0)
  713.                 {if(standard_input) 
  714.                     {fclose(ifile); ifile = fopen("/dev/con", "r");
  715. #ifdef __DESMET__
  716.                     uncook(ifile);
  717.                     forcedup(stdin, ifile);
  718. #endif
  719.                     }
  720.                 break;
  721.                 }
  722.             if(buf[0] == ';') continue;    /* ignore comments */
  723.             if(buf[0] == 0)
  724.                 {    /* assume a null byte was read, signifying end of line */
  725.                 buf[0] = ' ';
  726.                 if(labels++) last_label = last_label->nxt = new_label(last-1, "");
  727.                 else top_label = last_label = new_label(last-1, "");
  728.                 breaking = 1;
  729.                 }
  730.             t = buf+strlen(buf)-1;    /* zap the CRs (should be none) and LFs */
  731.             while(t>buf && (*t == '\015' || *t == '\n')) *t-- = 0;
  732.             t = buf; while(*t && isspace(*t)) t++;
  733.             if(*t == 0) continue;            /* ignore blank lines */
  734.             if(automatic_abscissas)
  735.                 {xx = abscissa;
  736.                 abscissa += abscissa_step;
  737.                 if(magnitude||phase)
  738.                     {sscanf(buf, "%lf %lf", &yy, &zz);
  739.                     if(magnitude) yy = sqrt(yy*yy + zz*zz);
  740.                     else if(yy != 0. || zz != 0.) yy = atan2(zz,yy);
  741.                     }
  742.                 else sscanf(buf, "%lf", &yy);
  743.                 }
  744.             else
  745.                 {if(magnitude||phase)
  746.                     {sscanf(buf, "%lf %lf %lf", &xx, &yy, &zz);
  747.                     if(magnitude) yy = sqrt(yy*yy + zz*zz);
  748.                     else if(yy != 0. || zz != 0.) yy = atan2(zz,yy);
  749.                     }
  750.                 else sscanf(buf, "%lf %lf", &xx, &yy);
  751.                 }
  752.             if(dividing_by_pi) yy /= 3.1415926535;
  753.  
  754.             if(logx) 
  755.                 if(xx <= 0.) goto GET_LABEL;
  756.                 else xx = log10(xx);
  757.             if(logy)
  758.                 if(yy <= 0.) goto GET_LABEL;
  759.                 else yy = log10(yy);
  760.  
  761.             if(xx<actual_xmin) actual_xmin = xx;
  762.             if(xx>actual_xmax) actual_xmax = xx;
  763.             if(yy<actual_ymin) actual_ymin = yy;
  764.             if(yy>actual_ymax) actual_ymax = yy;
  765.  
  766.             range_check(xx); range_check(yy);
  767.             x[last] = xx; y[last] = yy;    /* convert doubles to floats here */
  768.             last++;
  769. GET_LABEL:
  770.             s = buf;
  771.             for (j = expected; j--; )
  772.                 {while(*s == ' '||*s == '\t')s++;            /* skip a number */
  773.                 while(*s && (*s != ' ') && (*s != '\t'))s++;
  774.                 }
  775.             while(*s == ' '||*s == '\t')s++;
  776.             if(strlen(s))
  777.                 {if(*s == '\"')
  778.                     {t = ++s;
  779.                     while(*t && (*t != '\"')) t++;
  780.                     }
  781.                 else
  782.                     {t = s;
  783.                     while(*t && (*t != ' '))t++;
  784.                     }
  785.                 *t = 0;
  786.                 if(labels)
  787.                     {if(last_label->num != last-1)
  788.                         {last_label = last_label->nxt = new_label(last - 1, s);
  789.                         labels++;
  790.                         }
  791.                     }
  792.                 else 
  793.                     if(last>0)
  794.                         {top_label = last_label = new_label(last - 1, s);
  795.                         labels++;
  796.                         }
  797.                 if(breaking) abscissa = abscissa_start;
  798.                 }
  799.  
  800.             if(out_of_memory) goto NO_MORE_INPUT;
  801.             }        /* finished with one data file */
  802.         if(!labels || last_label->num != last-1)
  803.             {            /* add label to last point from each data file */
  804.             if(labels++) last_label = last_label->nxt = new_label(last-1, "");
  805.             else top_label = last_label = new_label(last-1, "");
  806.             }
  807.         if(argno >= argc) break;
  808.         breaking = 1;
  809.         }        /* finished with all data files */
  810.     last--;
  811. NO_MORE_INPUT:
  812.     if(out_of_memory || last+1 >= max_points)
  813.         {printf("out of memory - only the 1st %d points displayed", last+1);
  814.         printf("\n(press any key to continue)"); getchar();
  815.         }
  816.     switch(x_arguments)
  817.         {case 0:    xmin = actual_xmin;
  818.         case 1:        xmax = actual_xmax;
  819.         case 2:        ;
  820.         case 3:        ;
  821.         default:    ;
  822.         }
  823.     switch(y_arguments)
  824.         {case 0:    ymin = actual_ymin;
  825.         case 1:        ymax = actual_ymax;
  826.         case 2:        ;
  827.         case 3:        ;
  828.         default:    ;
  829.         }
  830.     if(transposing)
  831.         {i = logx; logx = logy; logy = i;
  832.         i = x_arguments; x_arguments = y_arguments; y_arguments = i;
  833.         pd = x; x = y; y = pd;
  834.         d = xmin; xmin = ymin; ymin = d;
  835.         d = xmax; xmax = ymax; ymax = d;
  836.         d = xdel; xdel = ydel; ydel = d;
  837.         }
  838. /*
  839.     if(debugging)
  840.         {BLOCK *tmp;
  841.         printf("%d labels found...\n", labels);
  842.         for (tmp = top_label; tmp; tmp = tmp->nxt)
  843.             printf("line %d: \"%s\"\n", tmp->num, tmp->txt);
  844.         printf("automatic_abscissas = %d\n",automatic_abscissas);
  845.         printf("breaking = %d\n",breaking);
  846.         printf("debugging = %d\n",debugging);
  847.         printf("numeric_labeling = %d\n",numeric_labeling);
  848.         printf("logx = %d\n",logx);
  849.         printf("logy = %d\n",logy);
  850.         printf("magnitude = %d\n",magnitude);
  851.         printf("phase = %d\n",phase);
  852.         getchar();
  853.         }
  854. */
  855.     *argcp = argc;
  856.     *argvp = argv;
  857. }
  858. #undef TR
  859.  
  860. /*    return a pointer to the next token from the indicated file
  861.         NOTE: uses global array buf    */
  862. char *token(fp) FILE *fp;
  863. {    int c;
  864.     char *s;
  865.     static char separate[] = " \t\n";
  866.     s = strtok(NULL, separate);
  867.     while(s == NULL)
  868.         {s = fgets(buf, BUFSIZE, fp);
  869.         if(s == NULL) return NULL;
  870.         s = strchr(buf, ';');
  871.         if(s != NULL) *s = 0;        /* zap the comment */
  872.         s = strtok(buf, separate);
  873.         }
  874.     return s;
  875. }
  876.  
  877. init_env()    /* get initial options from environment variable GRAPH */
  878. {
  879.     int ac, error;
  880.     char *string, *s, **av;
  881.  
  882.     string = getenv("GRAPH");
  883.     if(string == NULL) return;
  884.  
  885.     for (s = string, ac = 0; stoken(&s, buf); ac++)
  886.         ;                            /* count tokens in environment string */
  887.     av = (char **)getmem(ac*sizeof(char *));  /* allocate appropriate array */
  888.     for (s = string, ac = 0; stoken(&s, buf); ac++)
  889.         {av[ac] = getmem(1+strlen(buf));
  890.         strcpy(av[ac], buf);                    /* copy token from string */
  891.         }
  892.     parse_args(&ac, &av);        /* on error, it will never return */
  893. }
  894.  
  895. stoken(sin, sout) char **sin, *sout;
  896. {    int c;
  897.  
  898.     do    {*sout = c = *(*sin)++;
  899.         if(c == 0) return 0;
  900.         } while(isspace(c));
  901.     while((*++sout = c = **sin) && !isspace(c)) (*sin)++;
  902.     *sout = 0;
  903.     return 1;
  904. }
  905.  
  906. range_check(x) double x;
  907. {    if(fabs(x)>BIGFLOAT)
  908.         {printf("input number too large: %f\n", x);
  909.         exit(1);
  910.         }
  911. }
  912.  
  913. image()
  914. {    int i, j, j_style = 1, k, st, group, segment;
  915.     BLOCK *current_label;
  916.  
  917.     current_label = top_label;
  918.     for(group = i = 0; i <= last; group++)
  919.         {if(group<numstyles) {j_style = style[group]; segment = repeat[group];}
  920.         else segment = 1;
  921.         while(segment--)
  922.             {j = j_style;
  923.             if(j>0)
  924.                 {if(st = j%16) st--;
  925.                 set_linestyle(st); j /= 16;
  926.                 set_color_or_intensity(j); j /= 16;
  927.                 set_linewidth(j);
  928.                 move_abs_2(x[i], y[i]);
  929.                 markers = 0;
  930.                 }
  931.             else
  932.                 {j = -j;
  933.                 st = j%16;
  934.                 set_marker_symbol(st ? st : 6);
  935.                 j /= 16;
  936.                 k = j%16;
  937.                 set_color_or_intensity(j ? k : 0);
  938.                 markers = 1;
  939.                 }
  940.             if(breaking && j_style == 0xff)         /* skip a curve segment */
  941.                 i = current_label->num+1;
  942.             else 
  943.                 {while(i <= last)
  944.                     {if(markers)marker_abs_2(x[i], y[i]);
  945.                     else line_abs_2(x[i], y[i]);
  946.                     if(i == current_label->num)
  947.                         {text(current_label->txt);
  948.                         if(breaking) {i++; break;}
  949.                         else 
  950.                             {current_label = current_label->nxt;
  951.                             move_abs_2(x[i], y[i]);
  952.                             }
  953.                         }
  954.                     else if(default_labeling)
  955.                         {text(default_label);
  956.                         move_abs_2(x[i], y[i]);
  957.                         }
  958.                     i++;
  959.                     }
  960.                 }
  961.             current_label = current_label->nxt;
  962.             }
  963.         }
  964.     set_linewidth(1);
  965.     set_linestyle(0);
  966.     set_color_or_intensity(0);
  967. }
  968.  
  969. set_color_or_intensity(j) int j;
  970. {    j &= 15;
  971.     if(prim_attr.color_count > 2) 
  972.         {set_color(j%prim_attr.color_count); 
  973.         }
  974.     else if(prim_attr.intensity_count > 2) 
  975.         {set_intensity(1. - j/(double)prim_attr.intensity_count); 
  976.         }
  977. }
  978.  
  979. /* get_parameter - process one command line option
  980.         (return # parameters used) */
  981. get_parameter(argc, argv) int argc; char **argv;
  982. {    int i, left, st;
  983.     char *s;
  984.  
  985.     if(streq(*argv, "-a"))
  986.         {i = axis_arg(argc, argv, &abscissa_step, &abscissa_start, 
  987.                                                         &abscissa_start);
  988.         abscissa_arguments = i-1;
  989.         automatic_abscissas = 1;
  990.         return i;
  991.         }
  992.     else if(streq(*argv, "-b")) {breaking = 1; return 1;}
  993.     else if(streq(*argv, "-c"))
  994.         {if(argc>1) {default_labeling = 1; default_label = argv[1]; return 2;}
  995.         else gripe_arg(argv[0]);
  996.         }
  997.     else if(streq(*argv, "-d")) {debugging = 1; return 1;}
  998.     else if(streq(*argv, "-g"))
  999.         {i = 1;
  1000.         grid_style = 0;
  1001.         if((argc>i) && numeric(argv[i])) grid_style = atoi(argv[i++]); 
  1002.         if((argc>i) && numeric(argv[i])) 
  1003.             requested_rtx = requested_rty = requested_rlx*atoi(argv[i++]);
  1004.         if((argc>i) && numeric(argv[i])) grid_width = atoi(argv[i++]);
  1005.         return i;
  1006.         }
  1007.     else if(streq(*argv, "-h"))
  1008.         {if(argc>1 && numeric(argv[1]))
  1009.             {requested_height_used = atof(argv[1]); return 2;
  1010.             }
  1011.         else gripe_arg(argv[0]);
  1012.         }
  1013.     else if(streq(*argv, "-l"))
  1014.         {if(argc>1)
  1015.             {argc--;
  1016.             argv++;        /* point to next argument (start of text string) */
  1017.             text_labeling = 1;
  1018.             if(**argv == '\"')
  1019.                 {i = 1; left = 80;
  1020.                 (*argv)++;        /* skip quote */
  1021.                 text_label = getmem(left--);
  1022.                 *text_label = 0;
  1023.                 while(argc-->0)
  1024.                     {strncat(text_label, *argv, left); left -= strlen(*argv);
  1025.                     argv++;i++;
  1026.                     if(s = strchr(text_label, '\"')) {*s = 0; break;}
  1027.                     strncat(text_label, " ", left--);
  1028.                     }
  1029.                 return i;
  1030.                 }                
  1031.             else {text_label = *argv; return 2;}
  1032.             }
  1033.         else gripe_arg(argv[0]);
  1034.         }
  1035.     else if(streq(*argv, "-r"))
  1036.         {if(argc>1 && numeric(argv[1]))
  1037.             {requested_right_move = atof(argv[1]); return 2;
  1038.             }
  1039.         else gripe_arg(argv[0]);
  1040.         }
  1041.     else if(streq(*argv, "-t")) {transposing = 1; return 1;}
  1042.     else if(streq(*argv, "-u"))
  1043.         {if(argc>1 && numeric(argv[1]))
  1044.             {requested_up_move = atof(argv[1]); return 2;
  1045.             }
  1046.         else gripe_arg(argv[0]);
  1047.         }
  1048.     else if(streq(*argv, "-w"))
  1049.         {if(argc>1 && numeric(argv[1]))
  1050.             {requested_width_used = atof(argv[1]); return 2;
  1051.             }
  1052.         else gripe_arg(argv[0]);
  1053.         }
  1054.     else if(streq(*argv, "-e")) {equal = 1; return 1;}
  1055.     else if(streq(*argv, "-n")) {numeric_labeling = 0; return 1;}
  1056.     else if(streq(*argv, "-m"))
  1057.         {i = 1;
  1058.         while((--argc >0) && hexanumeric(argv[1]) && numstyles<MAXSTYLES)
  1059.             {if(s = strchr(*++argv,'*'))
  1060.                 {repeat[numstyles] = atoi(*argv);
  1061.                 s++;
  1062.                 }
  1063.             else {repeat[numstyles] = 1; s = *argv;}
  1064.             style[numstyles++] = atox(s);
  1065.             i++;
  1066.             }
  1067.         if(numstyles>1 || repeat[0]>1) breaking = 1;
  1068.         return i;
  1069.         }
  1070.     else if(streq(*argv, "-x"))
  1071.         {i = axis_arg(argc, argv, &xmin, &xmax, &xdel);
  1072.         x_arguments = i-1;
  1073.         return i;
  1074.         }
  1075.     else if(streq(*argv, "-xl"))
  1076.         {i = axis_arg(argc, argv, &xmin, &xmax, &xdel);
  1077.         x_arguments = i-1;
  1078. /*        printf("before taking log: xmin = %f, xmax = %f, xdel = %f \n",
  1079.         xmin,xmax,xdel);
  1080. */
  1081.  
  1082.         if(i>1) take_log(&xmin);
  1083.         if(i>2) take_log(&xmax);
  1084.         if(i>3) take_log(&xdel);
  1085. /*        printf("after taking log: xmin = %f, xmax = %f, xdel = %f \n",
  1086.         xmin, xmax, xdel);
  1087. */
  1088.         logx = 1;
  1089.         return i;
  1090.         }
  1091.     else if(streq(*argv, "-yap")||streq(*argv, "-ypp"))
  1092.         {dividing_by_pi = 1; goto PHASEY;
  1093.         }
  1094.     else if(streq(*argv, "-ym")) {magnitude = 1; phase = 0; goto YLIMITS;}
  1095.     else if(streq(*argv, "-ya")||streq(*argv, "-yp"))
  1096.         {
  1097. PHASEY:    phase = 1; magnitude = 0; goto YLIMITS;
  1098.         }
  1099.     else if(streq(*argv, "-y"))
  1100.         {
  1101. YLIMITS:
  1102.         i = axis_arg(argc, argv, &ymin, &ymax, &ydel);
  1103.         y_arguments = i-1;
  1104.         return i;
  1105.         }
  1106.     else if(streq(*argv, "-ylm")) {magnitude = 1; phase = 0; goto LOGY; }
  1107.     else if(streq(*argv, "-yl"))
  1108.         {
  1109. LOGY:
  1110.         i = axis_arg(argc, argv, &ymin, &ymax, &ydel);
  1111.         y_arguments = i-1;
  1112.         logy = 1;
  1113.         if(i>1) take_log(&ymin);
  1114.         if(i>2) take_log(&ymax);
  1115.         if(i>3) take_log(&ydel);
  1116.         return i;
  1117.         }
  1118.     else gripe(argv);
  1119. }
  1120.  
  1121. axis_arg(argc,argv,qmin,qmax,qdel)
  1122. int argc; char **argv; double *qmin,*qmax,*qdel;
  1123. {    int i = 1;
  1124.     if((argc>i) && numeric(argv[i])) sscanf(argv[i++],"%lf",qmin);
  1125.     if((argc>i) && numeric(argv[i])) sscanf(argv[i++],"%lf",qmax);
  1126.     if((argc>i) && numeric(argv[i])) sscanf(argv[i++],"%lf",qdel);
  1127.     return i;
  1128. }
  1129.  
  1130. int streq(a,b) char *a,*b;
  1131. {    while(*a)
  1132.         {if(*a != *b)return 0;
  1133.         a++; b++;
  1134.         }
  1135.     return (*b == 0);
  1136. }
  1137.  
  1138. gripe_arg(s) char *s;
  1139. {    to_text();
  1140.     printf("argument missing for switch %s",s);
  1141.     help();
  1142. }
  1143.  
  1144. gripe(argv) char **argv;
  1145. {    to_text();
  1146.     printf("%s isn\'t a legal argument\n", *argv);
  1147.     help();
  1148. }
  1149.  
  1150. char *message[]=
  1151. {"sample usage:     graph   data_file  [options]\n",
  1152. "           or      graph  <data_file  [options]\n",
  1153. "\n",
  1154. "Data file has pairs (x and y values) or triples (x, yreal, yimag) of\n",
  1155. "floating point numbers.  Each line may optionally end with a label.\n",
  1156. "\n",
  1157. "options:\n",
  1158. "  -a  [step [start]] automatic abscissas \n",
  1159. "  -b                 break graph after each label (see -m)\n",
  1160. "  -c  <text>         default label for points \n",
  1161. "  -e                 make vertical & horizontal scales equal \n",
  1162. "  -f  <file> or @<file>   get more parameters from <file>\n",
  1163. "  -g                 omit grid\n",
  1164. "  -g  <style> <tics> <width>  \n",
  1165. "                     <style>:  0=none, 1=frame, 2=full, 3=bottom & left \n",
  1166. "                               only, 4=separated, negative=tics outside\n",
  1167. "                     <tics>: approximate # tic marks per numeric label, \n",
  1168. "                     <width>: grid line width (default 1) \n",
  1169. "  -l  \"<text>\"       label to appear above graph \n",
  1170. "      --- press any key to continue ---",
  1171. 0,
  1172. "\015  -m  n1 n2 n3...    n positive for line styles: \n",
  1173. "                     n=WCS, where hex digits W=width, C=color, S=dash style,\n",
  1174. "                     nonpositive for markers, ff for nothing \n",
  1175. "  -n                 omit numbers on axes \n",
  1176. "  -t                 transpose x & y \n",
  1177. "  -w  <num>          fraction of screen width to use\n",
  1178. "  -h  <num>          fraction of screen height to use\n",
  1179. "  -r  <num>          fraction of screen to move right before plotting\n",
  1180. "  -u  <num>          fraction of screen to move up before plotting\n",
  1181. "",
  1182. "  -x[l]  [min [max]]  l signals log axis,       \n",
  1183. "                      x axis extends from min to max \n",
  1184. "  -y[l][m]  [min [max]]\n",
  1185. "  -ya[p]    [min [max]]\n",
  1186. "  -yp[p]    [min [max]]\n",
  1187. "      l signals log axis,  m, a, or p signals real & imag parts supplied.\n",
  1188. "      m to plot magnitude, a or p to plot argument (phase), ap or pp\n",
  1189. "      to plot phase/pi.  y axis extends from min to max \n",
  1190. "\n",
  1191.         /* in printer/plotter versions, the following two lines are zapped */
  1192. "When graph is finished: type / to adjust parameters or any other key to quit.\n",
  1193. "\n",
  1194. RIGHT1,
  1195. RIGHT2,
  1196. 0
  1197. };
  1198.  
  1199. help()
  1200. {    char **s;
  1201.     int i;
  1202.  
  1203.     if(plotting_device)
  1204.         {i = sizeof(message)/sizeof(message[0]) - 5;
  1205.         strcpy(message[i], "");
  1206.         strcpy(message[i + 1], "");
  1207.         }
  1208.     if(graphics_mode) finish_graphics();
  1209.     for (s = message; *s; s++) printf(*s);
  1210.     scr_ci();
  1211.     while (*++s) printf(*s);
  1212.     exit(1);
  1213. }
  1214.  
  1215. numeric(s) char *s;
  1216. {    char c;
  1217.     int numeral_found = 0;
  1218.     while(c = *s++)
  1219.         {if(c <= '9' && c >= '0') {numeral_found = 1; continue;}
  1220.         else if(strchr("eE*+-.", c)) continue;
  1221.         return 0;
  1222.         }
  1223.     return numeral_found;
  1224. }
  1225.  
  1226. hexanumeric(s) char *s;
  1227. {    char c; 
  1228.     int numeral_found = 0;
  1229.     if(numeric(s)) return 1;
  1230.     while(c = *s++)
  1231.         {c = toupper(c);
  1232.         if((c <= '9' && c >= '0') || (c <= 'F' && c >= 'A')) 
  1233.             {numeral_found = 1; continue;
  1234.             }
  1235.         else if(strchr("*-", c)) continue;
  1236.         return 0;
  1237.         }
  1238.     return numeral_found;
  1239. }
  1240.  
  1241. take_log(q) double *q;
  1242. {    if(*q>0.) *q = log10(*q);
  1243.     else {printf("nonpositive argument %f for log axis", *q); exit(1);}
  1244. }
  1245.  
  1246. atox(s) char *s;
  1247. {    int n, c, sign;
  1248.     while(*s == ' '||*s == '\t') s++;
  1249.     if(*s == '-')
  1250.         {sign = 1;
  1251.         s++;
  1252.         }
  1253.     else sign = 0;
  1254.     n = 0;
  1255.     while(1)
  1256.         {c = *s++;
  1257.         if(c >= '0' && c <= '9') c -= '0';
  1258.         else
  1259.             {if(c >= 'a') c -= 0x20;        /* convert to upper case */
  1260.             if(c >= 'A' && c <= 'F') c = c-'A'+10;
  1261.             else return (sign ? -n : n);
  1262.             }
  1263.         n = (n<<4)+c;
  1264.         }
  1265. }
  1266.  
  1267.