[comp.sources.misc] v09i062: draw, part 02/02

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (12/13/89)

Posting-number: Volume 9, Issue 62
Submitted-by: jta@sah.vtt.fi (Juha Takala)
Archive-name: draw_jt/part02

[This is "dr_lib", a library to produce plots in various formats including
plot(3) and HPGL formats, and "draw", a simple front-end for the library.
See the README for more information.  ++bsa]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  dr_lib.c draw.c
# Wrapped by allbery@uunet on Tue Dec 12 21:15:58 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'dr_lib.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dr_lib.c'\"
else
echo shar: Extracting \"'dr_lib.c'\" \(31312 characters\)
sed "s/^X//" >'dr_lib.c' <<'END_OF_FILE'
X/*
X
XCopyright (C) 1988, 1989 by Juha Takala, jta@sah.vtt.fi
X
X     This program is free software; you can redistribute it and/or modify
X     it under the terms of the GNU General Public License as published by
X     the Free Software Foundation; version 1.
X
X     This program is distributed in the hope that it will be useful,
X     but WITHOUT ANY WARRANTY; without even the implied warranty of
X     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X     the file "License" for more details
X
X     You should have received a copy of the GNU General Public License
X     along with this program; if not, write to the Free Software
X     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X
X */
X
X
X/* Description:
X *  dr_lib.c provides interface between device level and my draw(1).
X *  Supported devices are:
X *  - hpgl output for hp7475 plotter
X *  - gl_plot(3) calls for EGA or matrix printer output
X *  - plot(3) interface
X *
X */
Xstatic char *rcsid =
X  "$Id: dr_lib.c,v 2.4 89/12/08 14:00:34 jta Exp Locker: jta $";
X
X/* define this, if your plotter connection is 'y-cable' (not direct) */
X/* #define YCABLE			/*  */
X
X/* definede this if you want to ask paper size from plotter */
X/* (should not be used, if you are going to use this package as */
X/* part of pipelines) */
X/* #define ASK			/*  */
X
X#include <stdio.h> 
X#include <math.h>
X#ifdef MSDOS
X#include <bios.h>
X#endif
X#include "dr_lib.h"
X
X#define  ESC 0x1b		/* ascii <ESC> */
X
Xstatic int xscale(), yscale();
Xstatic void sends(), invdev();
X
X#ifdef ASK
Xstatic void takes();
X#endif /* ASK */
X
X/*
X * internal global variable declarations
X *
X */
X				/* coordinate transformations */
Xstatic float xuserincr,   yuserincr;
Xstatic float xuserlow,    yuserlow;
Xstatic float xuserhigh,   yuserhigh;
Xstatic float xdevicelow,  ydevicelow;
Xstatic float xdevicehigh, ydevicehigh;
Xstatic float xrelarea,    yrelarea;
Xstatic float xfactor,     yfactor;
Xstatic float shape_factor, size_factor;	/* text 'fatness' and size factors */
Xstatic int lastx=0, lasty=0;	/* device coordinates for last point */
X
X
Xstatic int device = INVDEV;	/* what output device we are working for */
Xstatic int old_linetype = -1;	/* remember last used linetype */
Xstatic int old_pen = -1;	/* ...and pen */
X
Xstatic int errcount, warncount, errfile;
Xstatic char *errfilename = "draw.err";
X
Xstatic FILE *errfilefp;
X
X
X
X/* ********************************************************** */
X/*                                                            */
X/* Following functions are ment to be subroutines to be       */
X/* called from a user supplied main program                   */
X/*                                                            */
X/* ********************************************************** */
X
X/*
X * dr_set_cset()   - select cset
X *
X */
Xvoid dr_set_cset(n)
Xint n;
X{
X    char s[50];
X
X    switch (device)
X      {
X      case HP7475:
X	  if (n < 0 || n == 5 || (n > 9 && n < 30) || n > 39) {
X	      (void)sprintf(s, "Invalid cset code %d, using 0", n);
X	      dr_errmsg(s);
X	      n = 0;
X	  }
X	  (void)sprintf(s, "CS%d;\n", n);
X	  sends(s);
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X/*	  (void)sprintf(s, "cset not yet for SCREEN");
X	  dr_errmsg(s);		/*  */
X	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X/*	  (void)sprintf(s, "cset not valid for PLOT");
X	  dr_errmsg(s);		/*  */
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X}
X
X/*
X * dr_set_pen()   - select pen
X *
X */
Xvoid dr_set_pen(n)
Xint n;				/* pen number, 1..6, 0=='put it away' */
X{
X    char s[50];
X
X    switch (device)
X      {
X      case HP7475:
X	  if (n < 0 || n > 6) {
X	      (void)sprintf(s, "Invalid pen code %d, using 1", n);
X	      dr_errmsg(s);
X	      n = 1;
X	  }
X	  if (n != old_pen) {	/* optimize for hpgl... */
X	      old_pen = n;
X	      (void)sprintf(s, "SP%d;", n);
X	      sends(s);
X	  }
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X/*	  (void)sprintf(s, "dr_set_pen(colour) not yet for SCREEN\n");
X	  dr_errmsg(s);		/*  */
X	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X/*	  (void)sprintf(s, "dr_set_pen(colour) not valid for PLOT\n");
X	  dr_errmsg(s);		/*  */
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X}
X
X/*
X * dr_goto()  - move pen to point x, y
X *
X */
Xvoid dr_goto(x, y, penup)
Xfloat x, y;			/* where he wants to go */
Xint penup;			/* nonzero == lift pen before moving */
X{
X    char s[60];
X    lastx = xscale(x);
X    lasty = yscale(y);
X    switch (device)
X      {
X      case HP7475:
X	  if (penup) sends ("PU");
X	  else sends ("PA;PD");
X	      
X	  /* go to point, leave pen as told
X	   */
X	  (void)sprintf(s, "%d,%d;\n", lastx, lasty);
X	  sends(s);
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  if (penup)	n_movepen(lastx, lasty);
X	  else		n_draw(lastx, lasty);
X	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X	  if (penup)	move(lastx, lasty);
X	  else		cont(lastx, lasty);
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X    return;
X}
X
X
X/*
X * dr_draw_line()  - draw line (x1,y1) .. (x2,y2)
X *
X * connect the two data points with line
X */
Xvoid dr_draw_line(x1, y1, x2, y2)
Xfloat x1, y1, x2, y2;		/* data points */
X{
X    char s[60];
X    
X    lastx = xscale(x2);
X    lasty = yscale(y2);
X    switch (device)
X      {
X      case HP7475:
X	  /* lift pen,
X	   * go to first point,
X	   * drop pen there,
X	   */
X	  (void)sprintf(s, "PA;PU%d,%d;PD;", xscale(x1), yscale(y1));
X	  sends(s);
X
X	  /* draw line segment, lift pen
X	   */
X	  (void)sprintf(s, "PD%d,%d;PU;\n", lastx, lasty);
X	  sends(s);
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  n_line(xscale(x1), yscale(y1), lastx, lasty);
X	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X	  line(xscale(x1), yscale(y1), lastx, lasty);
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X    return;
X}
X
X
X/*
X * dr_draw_array()  - draw y = f(x)
X *
X * connect data points with line
X */
Xvoid dr_draw_array(x, y, n)
Xfloat x[], y[];			/* data points */
Xint n;				/* number of points in x[] and y[] */
X{
X    int i;
X    char s[60];
X    
X    /* if we really have something to draw
X     */
X    if (n < 1)
X      return;
X
X    switch (device)
X      {
X      case HP7475:
X	  /* lift pen,
X	   * go to first point,
X	   * drop pen there,
X	   */
X	  (void)sprintf(s, "PA;PU%d,%d;PD;", xscale(x[0]), yscale(y[0]));
X	  sends(s);
X	  
X	  /* draw line segments
X	   */
X	  for (i=1; i<n; i++) {
X	      if (i % 4 == 0) sends("\n");
X	      (void)sprintf(s, "PD%d,%d;", xscale(x[i]), yscale(y[i]));
X	      sends(s);
X	  }
X	  
X	  /* finally lift pen
X	   */
X	  sends("PU;\n");
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  n_movepen(xscale(x[0]), yscale(y[0]));
X	  for (i=1; i<n; i++)
X	    n_draw(xscale(x[i]), yscale(y[i]));
X	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X	  move(xscale(x[0]), yscale(y[0]));
X	  for (i=1; i<n; i++)
X	    cont(xscale(x[i]), yscale(y[i]));
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X    lastx = xscale(x[i-1]);
X    lasty = yscale(y[i-1]);
X    return;
X}
X
X
X/*
X * dr_put_mark()  - make a mark at (x,y)
X *
X * put mark at data point
X */
Xvoid dr_put_mark(x, y, mark) 
Xfloat x, y;			/* data point */
Xchar mark;
X{
X    char s[60];
X
X    lastx = xscale(x);
X    lasty = yscale(y);
X    switch (device)
X      {
X      case HP7475:
X	  /* if we really have something to plot
X	   */
X	  
X	  /* lift pen,
X	   * set symbol mode,
X	   */
X	  (void)sprintf(s, "PA;PU;SM%c;", mark);
X	  sends(s);
X	  
X	  /* put symbol at all data points
X	   */
X	  (void)sprintf(s, "PU%d,%d;", lastx, lasty);
X	  sends(s);
X	  
X	  /* reset symbol mode
X	   */
X	  sends("SM;\n");
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  n_movepen(lastx, lasty);
X	  n_grafchar(mark);
X	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X	  move(lastx, lasty);
X	  *s = mark;
X	  *(s+1) = '\0';
X	  label(s);
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X    return;
X}
X
X
Xvoid dr_set_shape(x)
Xfloat x;
X{
X    if (x > 0.0)
X      shape_factor = x * xrelarea/yrelarea;
X    return;
X}
X
X
Xvoid dr_set_size(x)
Xfloat x;
X{
X    if (x > 0.0)
X      size_factor = x;
X    return;
X}
X
X
X/*
X * dr_put_text()  - put some text
X * plot(3) only has one size and orientation, what can you do!
X *
X */
Xvoid dr_put_text(x, y, xofs, yofs, angle, size, s)
Xfloat x, y;			/* where to put it */
Xfloat xofs, yofs;		/* offset of start position, measured in */
X				/* character size units */
Xfloat angle;			/* radians, 0.0 == horizontal */
Xfloat size;			/* relative size of text */
Xchar *s;			/* the text */
X{
X    char ss[60];
X    int senddir;
X    char dir[30];
X
X    if (size <= 0.0) {
X	sprintf(ss, "invalid size: %f");
X	dr_errmsg(ss);
X	return;
X    }
X    size *= size_factor;
X
X    switch (device)
X      {
X      case HP7475:
X	  senddir = (angle != 0.0);
X	  if (senddir) {
X	      if (angle == M_PI_2)
X		sprintf(dir,"DI0,1");
X	      else if (angle == -M_PI_2)
X		sprintf(dir,"DI0,-1");
X	      else
X		sprintf(dir,"DI1,%f", tan(angle));
X	  }
X
X	  /* lift pen, go to specified position, set direction & size,
X	   */
X
X	  (void)sprintf(ss, "PA;PU%d,%d;%s;SR%4.2f,%4.2f;\n",
X			xscale(x), yscale(y),
X			(senddir ? dir : ""), 
X			size * 0.75 * shape_factor * xrelarea,
X			size * 1.5 * yrelarea);
X	  sends(ss);
X
X	  /* go to offset,
X	   * put text,
X	   * restore 0 degree direction.
X	   */
X	  if ((xofs != 0.0) || (yofs != 0.0)) {
X	      (void)sprintf(ss, "CP%4.2f,%4.2f;\n", xofs, yofs);
X	      sends(ss);
X	  }
X	  sends("LB"); sends(s); sends("\03\n");
X
X	  /* correction for y-offset, if necessary, to leave pen on same */
X	  /* height but after the text */
X	  if (yofs != 0.0) {
X	      (void)sprintf(ss, "CP0,%4.2f;\n", -yofs);
X	      sends(ss);
X	  }
X
X	  if (senddir)
X	    sends("DI1,0;\n");
X/*	  lastx = ....;
X	  lasty = ....;		/* hp7475 does not really need these, */
X				/* it remembers the pen position */
X
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  n_movepen(xscale(x), yscale(y));
X
X#define GL_MODE_255_HAS_BUG
X#ifdef GL_MODE_255_HAS_BUG
X	  /* DT Lewis!!  Wake up! */
X	  /* For some reason gl_lib works strangely with GL_MODE == 255 */
X	  /* (the output is  (almost) microscopic small and weird shape). */
X	  /* We can compensate that strangeness here by modifying size */
X	  /* and sape factors for g_fontctl()...  The values 3.0 and 0.4 */
X	  /* are experimental results (by kekkonen@sah.vtt.fi). */
X	  if (strncmp(getenv("GLMODE"),"256",3)==0)
X	    g_fontctl(3.0*size*yrelarea, 0.4*shape_factor, 1.0, angle, 0.0);
X	  else
X#endif
X#undef GL_MODE_255_HAS_BUG
X	    g_fontctl(size*yrelarea, shape_factor, 1.0, angle, 0.0);
X	  yofs = -0.5 - yofs;
X	  n_ch_ofs(xofs, yofs);
X	  n_grafstr(s);
X	  n_ch_ofs(0.0, -yofs);
X	  g_fontctl(size, 1.0, 1.0, 0.0, 0.0);
X/*	  lastx = ....;
X	  lasty = ....;		/* this does not really need these, */
X				/* it remembers the pen position */
X
X	  break;
X#endif
X#ifdef PLOT
X#define PLOT_CH_XSIZE 70
X#define PLOT_CH_YSIZE 100
X      case PLOTLIB:
X	  {
X	      int i;
X	      float xsize, ysize;
X	      float xbase, ybase;
X	      float xincr, yincr;
X	      float xofs1, yofs1;
X
X	      xsize = PLOT_CH_XSIZE * size * xrelarea;
X	      ysize = PLOT_CH_YSIZE * size * yrelarea;
X
X	      yofs += 0.4;	/* middle --> botom */
X	      xofs1 = (xofs * xsize * cos(angle) * shape_factor -
X		       yofs * ysize * sin(angle));
X	      yofs1 = (xofs * xsize * sin(angle) * shape_factor +
X		       yofs * ysize * cos(angle));
X	      xbase = xscale(x) + xofs1;
X	      ybase = yscale(y) + yofs1;
X
X	      xincr = cos(angle) * xsize * shape_factor;
X	      yincr = sin(angle) * ysize;
X	      
X	      /* This is how we simulate different printing directions */
X	      /* and character sizes: by moving to the position of every */
X	      /* single character one at a time */
X	      *(ss+1) = '\0';
X	      for (i=0; *ss=*s; s++,i) {
X		  move((int) (0.5 + xbase + i * xincr),
X		       (int) (0.5 + ybase + i * yincr));
X		  label(ss);
X		  i++;
X	      }
X
X	      lastx = (int) (0.5 + xbase + i * xincr - xofs1);
X	      lasty = (int) (0.5 + ybase + i * yincr - yofs1);
X	      move(lastx, lasty);
X	  }
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X    return;
X}
X
X/*
X * dr_small_circle()  - draw small circle at current point.
X * This routine needs the help of lastx and lasty in case of plot(3) library.
X *
X */
Xvoid dr_draw_circle()
X{
X    switch (device)
X      {
X      case HP7475:
X	  sends("CI35;\n");	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  n_ellipse1(100, 100);	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X	  circle(lastx, lasty, 20);	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X}
X
X
X/*
X * dr_finish()  - terminate the plotting
X *
X * This routine must be called after all plotting activity is done
X * to restore the Y-cable connection so that terminal gets control
X */
Xint dr_finish(clean_scr)
Xint clean_scr;			/* != 0 if we have clear screen */
X{
X    char s[20];
X
X    switch (device)
X      {
X      case HP7475:
X	  /* deselct pen,
X	   * reset Y-cable connection
X	   *   (<esc>.Z is ignored if not Y-cable connecton )
X	   */
X	  (void)sprintf(s, "SP;%c.Z\n", ESC);
X	  sends(s);
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  if (clean_scr && (strncmp(getenv("GLMODE"), "256", 3) != 0)) {
X#ifdef UNIX
X	      FILE *fp = fopen("/dev/tty", "r");
X	      fgets(s, 2, fp);	/* wait for user response */
X	      fclose(fp);
X#endif /* UNIX */
X#ifdef MSDOS
X	      _bios_keybrd(_KEYBRD_READ); /* wait for keybrd. input forever */
X#endif /* MSDOS */
X	  }
X	  {
X	      int status;
X	      status = g_finish();	/* do clean screen */
X	      if (status != 0)
X		dr_errmsg("dr_lib(): problems with g_finish().");
X	  }
X	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X	  move(0,0);
X	  closepl();
X	  break;
X#endif
X      default:
X	  break;		/* call to invdev() --> recursion */
X      }
X	  
X    /* check errors, tell if any or remove error log file
X     */
X    if (errcount == 0 && warncount == 0)
X      (void)unlink(errfilename);
X    else {
X	if (errcount)
X	  (void)fprintf(stderr, "%d error%s,",
X			errcount, (errcount == 1 ? "" : "s"));
X	if (warncount)
X	  (void)fprintf(stderr, "%d warning%s,",
X			warncount, (warncount == 1 ? "" : "s"));
X	(void)fprintf (stderr, " see file \"%s\".\n", errfilename);
X    }
X    /* return something useful
X     */
X    return (errcount);
X}
X
X
X/*
X * dr_start  - init the plotting device
X *
X * This routine must be called before any plotting activity is done
X * to set up the Y-cable connction so that plotter starts processing
X * or in case of direct connection, open the device
X */
Xvoid dr_start(xlow, ylow, xhigh, yhigh, dev)
Xint dev;			/* plotting device & paper size */
Xfloat xlow, xhigh;		/* drawing area, relative to.. */
Xfloat ylow, yhigh;		/* ..whole paper, that means: */
X				/* 0.0, 0.5, 0.5, 1.0 will use */
X				/* upper left quarter of paper */
X{
X    int p1x, p1y, p2x, p2y;
X    float t1, t2;
X    char s[200];
X
X    /* open error log file
X     */
X    errcount = 0;
X    warncount = 0;
X    if ((errfilefp = fopen(errfilename, "w")) == NULL) {
X	(void)fprintf(stderr, "\nCan't open %s.  Aborting.\n", errfilename);
X	exit(1);
X    }
X    errfile = fileno(errfilefp);
X    xrelarea = xhigh - xlow;
X    yrelarea = yhigh - ylow;
X    shape_factor = yrelarea/xrelarea; /* back to normal 'fatness' */
X    size_factor = 1.0;		/* actual size normalized to area */
X
X    switch (device = (dev & DEVMASK))
X      {
X      case HP7475:
X	  /* set Y-cable connection,
X	   *   (<esc>.Y is ignored if not Y-cable connecton )
X	   * init the plotter,
X	   * set handshake mode x-on/x-off,
X	   * select pen #1
X	   */
X	  (void)sprintf(s, "\n%c.Y;IN;", ESC); /* Y-connection, plotter on */
X	  sends(s);
X	  (void)sprintf(s, "%c.I80;;17:", ESC);	/* enable x-on/x-off x-on=^q */
X	  sends(s);
X	  (void)sprintf(s, "%c.N;19:\n", ESC);	/* x-off=^s */
X	  sends(s);
X#ifdef ASK
X	  /* ask picture area from plotter
X	   * set up limits (leave some room for axis labels etc.) */
X	  sends("OP;");
X	  takes(s);
X#else /* ASK */
X	   /* we would get one of this */
X	  switch (dev & SIZEMASK)
X	    {
X	    case SIZE_A:
X		(void)sprintf (s, "250,596,10250,7796\n");
X		sends("PS4;\n");
X		break;
X	    case SIZE_A4:
X		(void)sprintf (s, "603,521,10603,7721\n");
X		sends("PS4;\n");
X		break;
X	    case SIZE_B:
X		(void)sprintf (s, "522,259,15722,10259\n");
X		sends("PS3;\n");
X		break;
X	    case SIZE_A3:
X		(void)sprintf (s, "170,602,15370,10602\n");
X		sends("PS3;\n");
X		break;
X	    default:
X		dr_errmsg("Invalid paper size.  Aborting.");
X		(void)dr_finish();
X		exit(1);
X	    }
X#endif /* ASK */
X	  if ( sscanf(s, "%d,%d,%d,%d", &p1x, &p1y, &p2x, &p2y) == 4 ) {
X				/* some room for labels */
X	      t1 = p1x + 0.05*(p2x-p1x); /* y-label */
X	      t2 = p2x - 0.001*(p2x-p1x); /* right margin */
X	      xdevicelow  = t1 + xlow * (t2 - t1);
X	      xdevicehigh = t1 + xhigh * (t2 - t1);
X	      t1 = p1y + 0.05*(p2y-p1y); /* x-label */
X	      t2 = p2y - 0.07*(p2y-p1y); /* name */
X	      ydevicelow  = t1 + ylow * (t2 - t1);
X	      ydevicehigh = t1 + yhigh * (t2 - t1);
X	  }
X	  else {
X	      dr_errmsg("Can't receive plotter dimensions.  Aborting.");
X	      (void) dr_finish();
X	      exit(1);
X	  }
X	  
X	  dr_set_pen(1);		/* select some pen */
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  p1x = 0;	p1y = 32767;
X	  p2x = 32767;	p2y = 0;
X	  t1 = p1x + 0.06*(p2x-p1x); /* room y-axis label */
X	  t2 = p2x - 0.001*(p2x-p1x); /* no room at right margin */
X	  xdevicelow  = t1 + xlow * (t2 - t1);
X	  xdevicehigh = t1 + xhigh * (t2 - t1);
X	  t1 = p1y + 0.10*(p2y-p1y); /* room for x-axis label */
X	  t2 = p2y - 0.05*(p2y-p1y); /* room fo picture's name */
X	  ydevicelow  = t1 + ylow * (t2 - t1);
X	  ydevicehigh = t1 + yhigh * (t2 - t1);
X
X#define ENV_MODE 0		/* from gl.h; it means that g_init() will */
X				/* look operating mode in environment */
X				/* variable GLMODE */
X	  g_init(ENV_MODE);
X#undef ENV_MODE
X	  /* dr_set_pen(1);		/* select some pen */
X	  break;
X#endif
X
X#ifdef PLOT
X      case PLOTLIB:
X				/* Y-cable for Tektornix? */
X	  p1x = 0;	p1y = 0;
X	  p2x = 5450;	p2y = 4095;
X				/* 5% room for labels */
X	  t1 = p1x + 0.07*(p2x-p1x); /* y-label */
X	  t2 = p2x - 0.02*(p2x-p1x);; /* righ margin */
X	  xdevicelow  = t1 + xlow * (t2 - t1);
X	  xdevicehigh = t1 + xhigh * (t2 - t1);
X	  t1 = p1y + 0.10*(p2y-p1y); /* x-label */
X	  t2 = p2y - 0.05*(p2y-p1y); /* name */
X	  ydevicelow  = t1 + ylow * (t2 - t1);
X	  ydevicehigh = t1 + yhigh * (t2 - t1);
X
X	  openpl();
X	  space(0,0,4096,4096);
X	  erase();
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X    
X    /* check coordinate position legality
X     */
X    if (xlow < -0.0001 || xhigh > 1.0001 ||
X	ylow < -0.0001 || yhigh > 1.0001) {
X	dr_errmsg("Illegal x/y low/high position.  Aborting.");
X	(void)dr_finish();
X	exit(1);
X    }
X    return;
X}
X
X
X/* 
X * dr_xgrid  - draw x grid 
X *
X * Draw grid lines parallel to y-axis.  When argument n == 0, makes
X * lines at every tic-mark, n == 1 makes one grid line between every
X * tic mark etc.  To leave grid lines away, just don't call this.
X */
Xvoid dr_xgrid(n)
Xint n;				/* number of grid lines */
X				/* between tic-marks */
X{
X    int i;
X    int x, y1, y2;		/* temps for grid line positions */
X    int nlines;			/* number of grid lines to draw */
X    char s[200];
X
X    /* check interval
X     */
X    if (n < 1) {
X	dr_errmsg("Invalid x-grid interval, using 1");
X	n = 1;
X    }
X
X    /* how many lines we have?
X     */
X    nlines = (int) (n*(xuserhigh-xuserlow)/xuserincr - 0.5);
X
X     switch (device)
X      {
X      case HP7475:
X	  /*  select absolute moving
X	   */
X	  sends("PA;\n");
X#ifdef SLOW
X	  if (slow) {
X	  }
X#endif	  
X	  /* draw desired number of lines, sawing up and down
X	   */
X	  y1 = yscale(yuserlow);
X	  y2 = yscale(yuserhigh);
X	  for (i=1; i<=nlines; i++) {
X				/* go up */
X	      x = xscale(i*xuserincr/n+xuserlow);
X	      (void)sprintf(s, "PU%d,%d;PD%d,%d;", x, y1, x, y2);
X	      sends(s);
X				/* go down */
X	      if (++i <= nlines) {
X		  x = xscale(i*xuserincr/n+xuserlow);
X		  (void)sprintf(s, "PU%d,%d;PD%d,%d;\n", x, y2, x, y1);
X		  sends(s);
X	      }
X	  }
X	  
X	  /* lift pen
X	   */
X	  sends("PU;\n");
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  y1 = yscale(yuserlow);
X	  y2 = yscale(yuserhigh);
X	  for (i=1; i<=nlines; i++) {
X	      x = xscale(i*xuserincr/n+xuserlow);
X	      n_line(x,y1, x,y2);
X	  }
X	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X	  y1 = yscale(yuserlow);
X	  y2 = yscale(yuserhigh);
X	  for (i=1; i<=nlines; i++) {
X	      x = xscale(i*xuserincr/n+xuserlow);
X	      line(x,y1, x,y2);
X	  }
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X}
X
X
X/* 
X * dr_ygrid  - draw y grid 
X *
X * See dr_xgrid().
X */
Xvoid dr_ygrid(n)
Xint n;
X{
X    int i;
X    int nlines;			/* number of lines */
X    char s[200];
X    int x1, x2, y;
X
X    /* check interval
X     */
X    if (n < 1) {
X	dr_errmsg("Invalid y-grid interval, using 1");
X	n = 1;
X    }
X
X    /* how many lines do we have?
X     */
X    nlines = (int) (n*(yuserhigh-yuserlow)/yuserincr - 0.5);
X
X    switch (device)
X      {
X      case HP7475:
X	  /* select absolute moving
X	   */
X	  sends("PA;\n");
X	  
X	  /* draw desired number of lines, sawing right and left
X	   */
X	  x1 = xscale(xuserlow);
X	  x2 = xscale(xuserhigh);
X	  for (i=1; i<=nlines; i++) {
X				/* go right */
X	      y = yscale(yuserlow+i*yuserincr/n);
X	      (void)sprintf(s, "PU%d,%d;PD%d,%d;", x1, y, x2, y);
X	      sends(s);
X				/* go left */
X	      if (++i <= nlines) {
X		  y = yscale(yuserlow+i*yuserincr/n);
X		  (void)sprintf(s, "PU%d,%d;PD%d,%d;", x2, y, x1, y);
X		  sends(s);
X	      }
X	      sends("\n");
X	  }
X	  
X	  /* lift pen
X	   */
X	  sends("PU;\n");
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  x1 = xscale(xuserlow);
X	  x2 = xscale(xuserhigh);
X	  for (i=1; i<=nlines; i++) {
X	      y = yscale(i*yuserincr/n+yuserlow);
X	      n_line(x1,y, x2,y);
X	  }
X	  break;
X#endif
X#ifdef PLOT
X      case PLOTLIB:
X	  x1 = xscale(xuserlow);
X	  x2 = xscale(xuserhigh);
X	  for (i=1; i<=nlines; i++) {
X	      y = yscale(i*yuserincr/n+yuserlow);
X	      line(x1,y, x2,y);
X	  }
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X}
X
X
X/* 
X * dr_area_def  - establish x and y axis 
X *
X * [xy]low    lower left corner
X * [xy]high   upper right corner
X * [xy]incr   increment of tic-marks
X * no_axes    flag, != 0 means don't draw axes
X *
X * Coordinate values will be printed at every tic-mark, so useful
X * values for incr is such that (high-low)/incr will be some small
X * integer.  With functions dr_xgrid() and dr_ygrid() it is possible to
X * draw grid lines also in between these tic-marcs.
X */
Xvoid dr_area_def(xlow, xincr, xhigh, ylow, yincr, yhigh, no_axes)
Xfloat xlow, xincr, xhigh;
Xfloat ylow, yincr, yhigh;
Xint no_axes;
X{
X    int i;
X    char units[30];		/* place for units */
X    char s[200];
X    float x, y;
X    int ix, iy, nx, ny;
X
X    /* set the globals
X     */
X    xuserlow = xlow;   xuserhigh = xhigh;   xuserincr = xincr;
X    yuserlow = ylow;   yuserhigh = yhigh;   yuserincr = yincr;
X    xfactor = (xdevicehigh - xdevicelow) / (xuserhigh - xuserlow);
X    yfactor = (ydevicehigh - ydevicelow) / (yuserhigh - yuserlow) ;
X
X    /* check legality,
X     * abort on error
X     */
X    if ((xincr == 0.0) ||
X	(xuserlow == xuserhigh) ||
X	((xuserhigh-xuserlow)*xincr < 0.0)) {
X	dr_errmsg("x-axis defined improperly. Aborting.");
X	(void)dr_finish();
X	exit(1);
X    }
X    if ((yincr == 0.0) ||
X	(yuserlow == yuserhigh) ||
X	((yuserhigh-yuserlow)*yincr < 0.0)) {
X	dr_errmsg("y-axis defined improperly. Aborting.");
X	(void)dr_finish();
X	exit(1);
X    }
X    if (no_axes)
X      return;
X    
X    switch (device)
X      {
X      case HP7475:
X
X	  /* draw box
X	   * --------
X	   */
X	  
X	  /* select absolute plotting mode,
X	   * lift pen,
X	   * go to lower left corner
X	   */
X	  (void)sprintf(s,"PA;PU%d,%d;\n",
X			xscale(xlow), yscale(ylow));
X	  sends(s);
X	  
X	  /* draw x-axis with x-tick marks
X	   */
X	  
X	  (void)sprintf(s, "TL%.1f,%.1f;\n", 0.5*xrelarea, 0.5*yrelarea);
X	  sends(s);
X	  for (nx=0, x = xlow;
X	       x < xhigh + xincr/100.0;
X	       x += xincr, nx++) {
X	      (void)sprintf(s, "PD%d,%d;XT;\n", xscale(x), yscale(ylow));
X	      sends(s);
X	  }
X	  (void)sprintf(s, "PD%d,%d;\n", xscale(xhigh), yscale(ylow));
X	  sends(s);
X	  
X	  /* draw y-axis with y-tick marks
X	   */
X	  (void)sprintf(s, "PU%d,%d;\n",
X			xscale(xlow), yscale(ylow));
X	  sends(s);
X	  for (ny=0, y = ylow;
X	       y < yhigh + yincr/100.0;
X	       y += yincr, ny++) {
X	      (void)sprintf(s, "PD%d,%d;YT;\n", xscale(xlow), yscale(y));
X	      sends(s);
X	  }
X	  (void)sprintf(s, "PD%d,%d;\n", xscale(xlow), yscale(yhigh));
X	  sends(s);
X
X	  /* outer borders of the box
X	   */
X	  (void)sprintf(s, "PU%d,%d;PD%d,%d,%d,%d;PU\n",
X			xscale(xlow), yscale(yhigh),
X			xscale(xhigh), yscale(yhigh),
X			xscale(xhigh), yscale(ylow));
X	  sends(s);
X	  break;
X#ifdef GL_LIB
X#define GL_TIC_SIZE 200
X      case SCREEN:
X	  iy = yscale(ylow);
X	  n_movepen(xscale(xlow), iy);
X
X	  for (nx=0, x = xlow;
X	       x < xhigh + xincr/100.0;
X	       x += xincr, nx++) {
X	      ix = xscale(x);
X	      n_draw(ix, iy);
X	      n_line(ix, iy+GL_TIC_SIZE, ix, iy-GL_TIC_SIZE);
X	      n_movepen(ix, iy);
X	  }
X	  n_draw(xscale(xhigh), iy);
X
X	  /* draw y-axis with y-tick marks
X	   */
X	  ix = xscale(xlow);
X	  n_movepen(ix, yscale(ylow));
X	  for (ny=0, y = ylow;
X	       y < yhigh + yincr/100.0;
X	       y += yincr, ny++) {
X	      iy = yscale(y);
X	      n_draw(ix, iy);
X	      n_line(ix+GL_TIC_SIZE, iy, ix-GL_TIC_SIZE, iy);
X	      n_movepen(ix, iy);
X	  }
X	  n_draw(ix, yscale(yhigh));
X	  
X	  /* outer borders of the box
X	   */
X	  n_movepen(xscale(xlow), yscale(yhigh));
X	  n_draw(xscale(xhigh), yscale(yhigh));
X	  n_draw(xscale(xhigh), yscale(ylow));
X	  break;
X#endif
X#ifdef PLOT
X#define PLOT_TIC_SIZE 40
X      case PLOTLIB:
X	  iy = yscale(ylow);
X	  move(xscale(xlow), iy);
X
X	  for (nx=0, x = xlow;
X	       x < xhigh + xincr/100.0;
X	       x += xincr, nx++) {
X	      ix = xscale(x);
X	      cont(ix, iy);
X	      line(ix, iy+PLOT_TIC_SIZE, ix, iy-PLOT_TIC_SIZE);
X	      move(ix, iy);
X	  }
X	  cont(xscale(xhigh), iy);
X
X	  /* draw y-axis with y-tick marks
X	   */
X	  ix = xscale(xlow);
X	  move(ix, yscale(ylow));
X	  for (ny=0, y = ylow;
X	       y < yhigh + yincr/100.0;
X	       y += yincr, ny++) {
X	      iy = yscale(y);
X	      cont(ix, iy);
X	      line(ix+PLOT_TIC_SIZE, iy, ix-PLOT_TIC_SIZE, iy);
X	      move(ix, iy);
X	  }
X	  cont(ix, yscale(yhigh));
X	  
X	  /* outer borders of the box
X	   */
X	  move(xscale(xlow), yscale(yhigh));
X	  cont(xscale(xhigh), yscale(yhigh));
X	  cont(xscale(xhigh), yscale(ylow));
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X
X    
X    /* put y-units
X     */
X    for (i=ny-1; i>=0; i--) {
X 	(void)sprintf(units, "%g", ylow + i * yincr);
X 	dr_put_text(xlow, ylow+i*yincr,
X		    -strlen(units)/2.0, -1.3, -M_PI_2, 1.0, units);
X    }
X
X    /* put x-units
X     */
X    for (i=0; i<nx; i++) {
X	(void)sprintf(units, "%g", xlow + i * xincr);
X	dr_put_text(xlow+i*xincr, ylow,
X		    -strlen(units)/2.0, -1.3, 0.0, 1.0, units);
X    }
X    return;
X}
X
X/*
X * linetypes
X *
X */
X#ifdef GL_LIB
Xstatic long gl_line_types[] = {	/* 76543210765432107654321076543210 */
X    0xf0000000L,		/* ====............................ */
X    0xffff0000L,		/* ================................ */
X    0xffffff00L,		/* ========================........ */
X    0xffffff18L,		/* ========================...==... */
X    0xfffff0f0L,		/* ====================....====.... */
X    0xfffff39cL,		/* ====================..===..===.. */
X    0xffffffffL,		/* ================================ */
X    0x66666666L,		/* ==..==..==..==..==..==..==..==.. */
X    0xf8f8f8f8L,		/* =====...=====...=====...=====... */
X    0xffffff00L,		/* ========================........ */
X    0xfc30fc30L };		/* ======....==....======....==.... */
X#define DEF_GL_TYPE 7		/* this will produce continous line */
X#endif /* GL_PLOT */
X#ifdef PLOT
Xstatic char *plot_line_types[] = {
X    "dotted",			/* 1 */
X    "longdashed",		/* 2 */
X    "shortdashed",		/* 3 */
X    "dotdashed",		/* 4 */
X    "solid",			/* 5 */
X    "solid",			/* 6 */
X    "solid" };			/* 7 */
X#define DEF_PLOT_TYPE 7		/* this will produce continous line */
X#endif /* PLOT */
X
Xint dr_set_ltype(linetype)
Xint linetype;
X{
X    char s[40];
X    int old_val = old_linetype;
X
X    switch (device)
X      {
X      case HP7475:
X	  if (linetype < 0 || linetype > 6) {
X	      linetype = 7;
X	      sends("LT;");
X	  }
X	  else {
X	      (void)sprintf(s, "LT%d;", linetype);
X	      sends(s);
X	  }
X	  break;
X#ifdef GL_LIB
X      case SCREEN:
X	  if (linetype < 1 ||
X	      linetype > (sizeof(gl_line_types) / sizeof(gl_line_types[0]))) {
X	       sprintf (s, "Invalid linetype: %d", linetype);
X	       dr_errmsg(s);
X	       linetype = DEF_GL_TYPE;
X	   }
X	  g_style(gl_line_types[linetype-1]);
X	  break;
X#endif
X#ifdef PLOT	    
X      case PLOTLIB:
X	  if (linetype < 1 ||
X	      linetype > (sizeof(plot_line_types) /
X			  sizeof(plot_line_types[0]))) {
X	       sprintf (s, "Invalid linetype: %d", linetype);
X	       dr_errmsg(s);
X	       linetype = DEF_PLOT_TYPE;
X	   }
X	  linemod(plot_line_types[linetype-1]);
X	  break;
X#endif
X      default:
X	  invdev(); break;
X      }
X    old_linetype = linetype;
X    return old_val;
X}
X
X/*
X * xscale  - scaling in horizontal directon
X *
X * convert user x-coordinate to physical device x-coordinate
X */
Xstatic int xscale(x)
Xfloat x;
X{
X    int temp;
X    char s[60];
X
X    /* calculate it
X     */
X    temp = (int) ((x - xuserlow) * xfactor + xdevicelow + 0.5);
X    /* check, if it is good
X     */
X    if ((temp >= -32768) && (temp <= 32767))
X      return (temp);
X
X    /* when not good make report,
X     * return something
X     */
X    (void)sprintf(s, "x-value out of range: %f", x);
X    dr_warnmsg(s);
X    return (int) (xdevicelow + 0.5);
X}
X
X
X/*
X * yscale  - scaling in vertical directon
X *
X * convert user y-coordinate to physical device y-coordinate
X */
Xstatic int yscale(y)
Xfloat y;
X{
X    int temp;
X    char s[60];
X
X    /* calculate it
X     */
X    temp = (int) ((y - yuserlow) * yfactor + ydevicelow + 0.5);
X
X    /* check, if it is good
X     */
X    if ((temp >= -32768) && (temp <= 32767))
X      return (temp);
X
X    /* when not good make report,
X     * return something
X     */
X    (void)sprintf(s, "y-value out of range: %f", y);
X    dr_warnmsg(s);
X    return (int) (ydevicelow + 0.5);
X}
X
Xstatic void invdev()
X{
X    dr_errmsg("Invalid plotting device.");
X    (void)dr_finish();
X    exit(1);
X}
X
X
X/*
X * dr_errmsg  - send a string to error output
X *
X */
Xvoid dr_errmsg(s)
Xchar *s;
X{
X    char *p = s + strlen(s);
X    if (p != s) p--;
X    while ((p != s) && (*p == '\n')) /* strip the newlines */
X      *(p--) = '\0';
X    fprintf(errfilefp, "dr_lib error: %s\n", s);
X    errcount++;
X    return;
X}
X
X
X/*
X * warnmsg  - send a string to error output
X *
X */
Xvoid dr_warnmsg(s)
Xchar *s;
X{
X    char *p = s + strlen(s);
X    if (p != s) p--;
X    while ((p != s) && (*p == '\n')) *(p--) = '\0';
X    fprintf(errfilefp, "Warning: %s\n", s);
X    warncount++;
X    return;
X}
X
X
X/*
X * sends  - send something to plotting device
X *
X */
Xstatic void sends(s)
Xchar *s;
X{
X    (void)printf("%s", s);
X}
X
X#ifdef ASK
X/*
X * takes  - take a string from plotter (to read plotter coordinates)
X *
X */
X#include <signal.h>
X#include <setjmp.h>
X
Xjmp_buf sjbuf;
Xint (*savAlrm)();		/* save incomming alarm function */
X
Xstatic int timerh()		/* timer interrupt handler */
X{
X    longjmp(sjbuf, 1);
X}
X
Xstatic void takes(s)
Xchar *s;
X{
X#ifdef YCABLE
X    savAlrm = signal(SIGALRM,timerh);
X    alarm(2);			/* give time to wake up */
X    if (setjmp(sjbuf)) {
X	alarm(0);
X	signal(SIGALRM,savAlrm); /* cancel timer */
X	(void)dr_finish();
X	(void)fprintf(stderr, "\n\7Timeout reading stdin.  Aborting.\n");
X	exit(1);
X    }
X    gets(s);
X    alarm(0);
X    signal(SIGALRM,savAlrm);	/* cancel timer */
X#else
X    /* do it yorself */
X#endif
X}
X#endif /* ASK */
END_OF_FILE
if test 31312 -ne `wc -c <'dr_lib.c'`; then
    echo shar: \"'dr_lib.c'\" unpacked with wrong size!
fi
# end of 'dr_lib.c'
fi
if test -f 'draw.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'draw.c'\"
else
echo shar: Extracting \"'draw.c'\" \(17080 characters\)
sed "s/^X//" >'draw.c' <<'END_OF_FILE'
X/*
X
XCopyright (C) 1988, 1989 by Juha Takala, jta@sah.vtt.fi
X
X     This program is free software; you can redistribute it and/or modify
X     it under the terms of the GNU General Public License as published by
X     the Free Software Foundation; version 1.
X
X     This program is distributed in the hope that it will be useful,
X     but WITHOUT ANY WARRANTY; without even the implied warranty of
X     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X     the file "License for more details
X
X     You should have received a copy of the GNU General Public License
X     along with this program; if not, write to the Free Software
X     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X
X */
X
X/* Description:
X *  Non-interactive user interface program to provide interface between
X *  device manipulation subroutines and user supplied command files.
X *  This program will accept all kinds of command line arguments and
X *  pseudo comments mixed in between the data lines.  See the man page.
X *
X *  The good thing about this program is that it will accept infinite
X *  amount of input data points; they are not stored, but processed one
X *  at a time.
X */
Xstatic char *RCS_id =
X  "$Id: draw.c,v 2.7 89/12/08 14:00:39 jta Exp Locker: jta $";
X
X#include <stdio.h>
X#ifdef MSDOS
X#include <stdlib.h>
X#endif /* MSDOS */
X#include <string.h>
X#include <sys/types.h>
X#include <time.h>
X#include <math.h>
X#include <signal.h>
X#ifndef MSDOS
X#include <sys/inode.h>
X#include <sys/file.h>
X#endif
X#include <string.h>
X#include "dr_lib.h"
X
Xdouble strtod();
X
Xchar *myname;
Xfloat xlowl = 0.0;		/* relative plotting area on paper */
Xfloat ylowl = 0.0;
Xfloat xhighr= 1.0;
Xfloat yhighr = 1.0;
X
Xfloat xlow = -1.0;		/* x axis range */
Xfloat xincr = 0.5;
Xfloat xhigh = 1.0;
Xint xgrid_n = 0;
Xchar *xlabel_text = NULL;
X
Xfloat ylow = -1.0;		/* y axis range */
Xfloat yincr = 0.5;
Xfloat yhigh = 1.0;
Xint ygrid_n = 0;
Xchar *ylabel_text = NULL;
X
Xstatic float x, y;		/* current point, needs to be */
X				/* remembered, eg. when relative text is */
X				/* inserted by #$texthere */
Xchar *name_text = NULL;		/* name of picture */
Xint pennum = 1;
Xint penup = 1;
Xint no_axes = 0;
Xint init_done = 0;
Xint dateflag = 0;
Xint linetype = 7;		/* default for solid linetype */
Xfloat text_angle = 0.0;		/* radians */
Xfloat text_size = 1.0;		/* text size factor */
Xfloat text_shape = 1.0;		/* text shape factor */
Xint cset = 0;			/* char set, default is US Ascii */
Xint continuous = 1;		/* continuous line / discrete points */
X				/* 0 = discontinous */
Xchar marker = '*';		/* default marker char in discontinous mode */
Xchar informat[200] = "%f %f";	/* default input data line format */
Xint reversed = 0;		/* != 0 means input is y before x  */
Xint absolute = 0;		/* != 0 when 'absolute' coordinates are */
X				/* to be processed */
Xfloat xabs_origin = 0.0;	/* origin of 'absolute' mode data points */
Xfloat yabs_origin = 0.0;
X
Xint device = HP7475 | SIZE_A4;
X
Xstatic int setmode();
Xstatic int labelpic();
Xstatic void doit();
Xstatic void setdevice();
Xextern void exit();
X
Xstatic void (*old_int_handler)();
Xstatic void new_int_handler();
Xstatic void fatal();
Xstatic void usage();
X
X#define PUT_TEXT(x,y,xofs,yofs,text) \
X      dr_put_text((x), (y), (xofs), (yofs), text_angle, 1.0, (text))
X#define PUT_X_TEXT(x,y,text) \
X      dr_put_text((x), (y), -(float)strlen(text), -2.0, 0.0, 1.4, (text))
X#define PUT_Y_TEXT(x,y,text) \
X      dr_put_text((x), (y), 0.0, -2.0, -M_PI_2, 1.4, (text))
X#define PUT_N_TEXT(x,y,text) \
X      dr_put_text((x), (y), -(float)strlen(text)/2.0, 0.4, 0.0, 2.0, (text))
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    int c;
X    extern char *optarg;
X    extern int optind, opterr;
X    char *opts = "a:bc:df:g:hl:m:n:p:s:S:t:x:X:y:Y:v";
X
X    FILE *fp;
X
X    myname = *argv;
X    setdevice(getenv("DRAWDEV"));
X
X
X    while ((c = getopt(argc, argv, opts)) != -1) {
X	switch (c) {
X	case 'a':
X	    if (sscanf(optarg, "%f,%f,%f,%f",
X		       &xlowl, &ylowl, &xhighr, &yhighr) != 4)
X	      fatal("invalid plotting area definition: ", optarg);
X	    break;
X	case 'b': no_axes++; break;
X	case 'c': cset = atoi(optarg); break;
X	case 'd': dateflag++; break;
X	case 'f':
X	    /* input lines are : "-- -- y -- -- x -- --"
X	     * (dashes indicate fields, that we are not interested in)
X	     * and we want to plot y=f(x), so we specify option
X	     * "-f 6,3" (fields are numbered from 1...)
X	     */
X	    {
X		int xcol, ycol;
X		if (sscanf(optarg, "%d,%d", &xcol, &ycol) != 2)
X		  fatal("invalid input format definition: %s", optarg);
X		if (xcol == ycol)
X		  fatal("invalid input format definition: %s", optarg);
X		if (xcol > ycol) {
X		    int temp = xcol;
X		    reversed++;
X		    xcol = ycol;
X		    ycol = temp;
X		}
X		ycol -= xcol;
X		informat[0] = '\0';
X		while (--xcol)
X		  (void)strcat(informat, "%*f ");
X		(void)strcat(informat, "%f ");
X		while (--ycol)
X		  (void)strcat(informat, "%*f ");
X		(void)strcat(informat, "%f");
X	    }
X	    break;
X	case 'g':
X	    if (sscanf(optarg, "%d,%d", &xgrid_n, &ygrid_n) != 2)
X	      fatal("invalid grid spec.: ", optarg);
X	    break;
X	case 'h': case '?':
X	    usage(); break;
X	case 'l':
X	    if (sscanf(optarg, "%d", &linetype) != 1)
X	      fatal("invalid line type:", optarg);
X	    break;		/* draw axes before setting it! */
X	case 'm':
X	    continuous = 0;
X	    if (sscanf(optarg, "%1s", &marker) != 1)
X	      fatal ("no marker found.", "\0");
X	    break;
X	case 'n':
X	    name_text = optarg; break;
X	case 'p':
X	    if (sscanf(optarg, "%d", &pennum) != 1)
X	      fatal("invalid pen:", optarg);
X	    if ((pennum > 6) || (pennum < 1))
X	      pennum = 1;
X	    break;
X	case 's':
X	    if (sscanf(optarg, "%f", &text_size) != 1)
X	      fatal("invalid text size: ", optarg);
X	    break;
X	case 'S':
X	    if (sscanf(optarg, "%f", &text_shape) != 1)
X	      fatal("invalid text shape: ", optarg);
X	    break;
X	case 't': setdevice(optarg); break;
X	case 'x':
X	    if (sscanf(optarg, "%f,%f,%f",
X		       &xlow, &xincr, &xhigh) != 3)
X	      fatal("invalid x range: ", optarg);
X	    break;
X	case 'X':
X	    xlabel_text = optarg; break;
X	case 'y':
X	    if (sscanf(optarg, "%f,%f,%f",
X		       &ylow, &yincr, &yhigh) != 3)
X	      fatal("invalid y range: ", optarg);
X	    break;
X	case 'Y':
X	    ylabel_text = optarg; break;
X	case 'v':
X	    fprintf(stderr, "%s\n", RCS_id);
X	    exit (0);
X	default:
X	    exit(1);
X	}
X    }
X    argc -= optind;
X    argv += optind;
X
X    old_int_handler = signal (SIGINT, new_int_handler);
X
X    /*
X     * Options have been taken, start the work.  Initializations will be
X     * done just before first data point is used...  This is jippo to
X     * make it possible to give coordinate specifications from inside
X     * the data....
X     */
X    if (argc == 0)		/* no files, take points from stdin */
X      doit(stdin);
X    else {			/* take points from all files */
X	for ( ; argc; argc--, argv++) {
X	    if (NULL == (fp = fopen(*argv, "r"))) {
X		perror(*argv);
X		continue;
X	    }
X	    doit(fp);
X	    fclose(fp);
X	}
X    }
X    if (init_done)
X      return(dr_finish(1) ? 1 : 0); /* 1 == error(s) */
X    else
X      return 2;			/* nothing was done! */
X}
X
X
X/* gl_plot will set int handler at its initialization time, and restore
X   what it saw there previously, and finally it will
X   kill(SIGINT,getpid()).  This is what we are going to do, too, so that
X   OUR caller can clean ITS data stuctures etc.
X*/
Xstatic void new_int_handler() {
X    (void)dr_finish(0);
X    signal (SIGINT, old_int_handler);
X    kill (getpid(), SIGINT);	/* zap my self */
X    sleep(1);
X    exit(3);			/* if that is not enough */
X}
X
X
Xstatic void do_initializations()
X{
X    init_done++;		/* remember it is done */
X    dr_start(xlowl, ylowl, xhighr, yhighr, device);
X    if (cset != 0) dr_set_cset(cset);
X    dr_set_size(text_size);
X    dr_set_shape(text_shape);
X    dr_set_pen(pennum);
X    dr_area_def(xlow, xincr, xhigh, ylow, yincr, yhigh, no_axes);
X    if (!no_axes) {
X	if (xgrid_n) dr_xgrid(xgrid_n);
X	if (ygrid_n) dr_ygrid(ygrid_n);
X    }
X    if (xlabel_text) PUT_X_TEXT(xhigh, ylow, xlabel_text);
X    if (ylabel_text) PUT_Y_TEXT(xlow, yhigh, ylabel_text);
X    if (name_text) PUT_N_TEXT((xhigh+xlow)/2.0, yhigh, name_text);
X    if (dateflag) putdate(dateflag);
X    dr_set_ltype(linetype);
X}
X
Xstatic void setdevice(s)
Xchar *s;
X{
X    if (s == NULL) return;
X    if      (!strcmp(s,"a4")) device = (HP7475 | SIZE_A4);
X    else if (!strcmp(s,"a3")) device = (HP7475 | SIZE_A3);
X    else if (!strcmp(s,"a"))  device = (HP7475 | SIZE_A);
X    else if (!strcmp(s,"b"))  device = (HP7475 | SIZE_B);
X#ifdef GL_LIB
X    else if (!strcmp(s,"ega")) device = SCREEN;
X#endif
X#ifdef PLOT
X    else if (!strcmp(s,"plot")) device = PLOTLIB;
X#endif
X#ifdef TEK
X    else if (!strcmp(s,"tek"))
X      fatal("Sorry,", "Tek4010 not yet.");
X#endif
X    else fatal("Unsupported plotting device", s);
X}
X  
Xstatic void doit(fp)
XFILE *fp;
X{
X#define LINESIZE 512
X    char buf[LINESIZE+1], *p;
X    char emsg[200];
X    int lineno = 0;
X    
X    while (1) {
X	if (NULL == fgets(buf, LINESIZE, fp)) /* EOF */
X	  return;
X
X	lineno++;
X	for (p=buf; *p; p++)	/* skip white space */
X	  if (strchr(" \t",*p) == NULL)
X	    break;
X	if (*p == '\n')
X	  continue;
X
X	if (*p == '#') {
X	    if (setmode(p+1)) {
X		sprintf(emsg, "Invalid pseudo comment line (%d): %s",
X			lineno, buf);
X		if (init_done)
X		  dr_errmsg(emsg);
X		else
X		  write(2, emsg, strlen(emsg));
X	    }
X	    continue;
X	}
X				/* now we expect data lines, */
X				/* initializations must be done by now */
X	if (!init_done) do_initializations();
X
X	if (sscanf(p, informat, &x, &y) != 2) {
X	    sprintf(emsg, "Invalid data line (%d): %s", lineno, buf);
X	    dr_errmsg(emsg);
X	    continue;
X	}
X	if (reversed) {
X	    float temp = x;
X	    x = y;
X	    y = temp;
X	}
X	if (absolute) {
X	    x = xlow + (xabs_origin + x) * (xhigh - xlow);
X	    y = ylow + (yabs_origin + y) * (yhigh - ylow);
X	}
X	/* this needs to be fixed: reversed directions not handled! */
X	if (x < xlow || x > xhigh || y < ylow || y > yhigh) {
X	    sprintf (emsg, "point out of range at line (%d): %s",
X		     lineno, buf);
X	    dr_warnmsg(emsg);
X	}
X	if (continuous) {
X	    dr_goto(x, y, penup);
X	    penup = 0;
X	}
X	else {
X	    dr_put_mark(x, y, marker);
X	}
X    }
X}
X
Xstatic void remember(to, from)	/* copy string to safe place, put its */
X				/* addr into `*to' */
Xchar **to, *from;
X{
X#ifndef MSDOS
X    extern char *malloc();
X#endif
X    *to = malloc(strlen(from)+1);
X    strcpy(*to, from);
X}
X
X				/* handle '#<something>' lines */
Xstatic int setmode(s)		/* return 0 on success, != when trouble */
Xchar *s;
X{
X    for (; *s; s++)		/* skip white space */
X      if (strchr(" \t",*s) == NULL)
X	break;
X    if (*s++ != '$')		/* only '$' causes action */
X      return 0;
X
X    for (; *s; s++)		/* skip white space */
X      if (strchr(" \t",*s) == NULL)
X	break;
X    
X    if (!strncmp (s, "absolute", 8)) {
X	absolute = 1;
X	if (sscanf(s+8, "%f,%f", &xabs_origin, &yabs_origin) == 2)
X	  return 0;
X	xabs_origin = 0.0;
X	yabs_origin = 0.0;
X	return 1;
X    }
X
X    if (!strncmp (s, "endabsolute", 11)) {
X	absolute = 0;
X	return 0;
X    }
X
X    if (!strncmp (s,"penup",5)) {
X	penup = 1;
X	return 0;
X    }
X
X
X    if (!strncmp(s, "include", 7)) {
X	FILE *fp;
X	char *p;
X	
X	for (s+=8; *s; s++)	/* skip whitespace */
X	  if (strchr(" \t",*s) == NULL)
X 	    break;
X	for (p=s; *p; p++)
X 	  if (strchr(" \t\n",*s) != NULL)
X 	    break;
X 	*(p-1) = '\0';		/* put terminator */
X 	
X 	if (NULL == (fp = fopen(s, "r"))) {
X 	    perror(p);
X 	    return 1;
X 	}
X 	doit(fp);		/* recursive call */
X 	fclose(fp);
X 	return 0;
X    }
X 
X    if (!strncmp (s, "cset", 4)) {
X	int csetnum = 0;
X	if (sscanf(s+4, "%d", &csetnum) != 1)
X	  return 1;
X	if (!init_done) do_initializations();
X	dr_set_cset(csetnum);
X	return 0;
X    }
X
X    if (!strncmp (s, "pen", 3)) {
X	if (sscanf(s+3, "%d", &pennum) != 1)
X	  return 1;
X	if (!init_done) do_initializations();
X	dr_set_pen(pennum);
X	return 0;
X    }
X
X    if (!strncmp (s, "ltype", 5)) {
X	int linetype = 1;
X	if (sscanf(s+5, "%d", &linetype) != 1)
X	  return 1;
X	if (!init_done) do_initializations();
X	dr_set_ltype(linetype);
X	return 0;
X    }
X
X    if (!strncmp(s, "mark", 4)) {
X	s += 4;
X	while (1) {
X	    marker = *s++;
X	    if (strchr(" \t", marker) == NULL)
X	      break;
X	}
X	continuous = (strchr (" \n\r\t", marker) != NULL);
X	return 0;
X    }
X
X    if (!strncmp(s, "date",   4)) {
X	if (dateflag)
X	  return 1;
X	dateflag = 1;
X	if (init_done)
X	  putdate(1);
X	return 0;
X    }
X    if (!strncmp(s, "time",   4)) {
X	if (dateflag)
X	  return 1;
X	dateflag = 2;
X	if (init_done)
X	  putdate(2);
X	return 0;
X    }
X
X    if (!strncmp(s, "xlabel", 6)) {
X	if (xlabel_text) return 1;
X	s += 7;			/* skip one space/separator */
X	s[strlen(s)-1] = '\0';	/* drop newline */
X	if (!init_done) {
X	    remember(&xlabel_text, s);
X	    return 0;
X	}
X	PUT_X_TEXT(xhigh, ylow, s);
X	xlabel_text = myname;	/* some char-pointer that has non NULL */
X				/* value, so that we remember this */
X	penup = 1;
X	return 0;
X    }
X
X    if (!strncmp(s, "ylabel", 6)) {
X	if (ylabel_text) return 1;
X	s += 7;
X	s[strlen(s)-1] = '\0';
X	if (!init_done) {
X	    remember(&ylabel_text, s);
X	    return 0;
X	}
X	PUT_Y_TEXT(xlow, yhigh, s);
X	ylabel_text = myname;
X	penup = 1;
X	return 0;
X    }
X
X    if (!strncmp(s, "name", 4)) {
X	if (name_text) return 1;
X	s += 5;			/* skip the space */
X	s[strlen(s)-1] = '\0';	/* drop newline */
X	if (!init_done) {
X	    remember(&name_text, s);
X	    return 0;
X	}
X	PUT_N_TEXT((xhigh+xlow)/2.0, yhigh, s);
X	name_text = myname;	
X	penup = 1;
X	return 0;
X    }
X
X    if (!strncmp(s, "xrange", 6)) {
X	if (sscanf(s+6, "%f,%f,%f", &xlow, &xincr, &xhigh) != 3)
X	  return 1;
X	return 0;
X    }
X
X    if (!strncmp(s, "yrange", 6)) {
X	if (sscanf(s+6, "%f,%f,%f", &ylow, &yincr, &yhigh) != 3)
X	  return 1;
X	return 0;
X    }
X
X    if (!strncmp(s, "area", 4)) {
X	if (sscanf(s+4, "%f,%f,%f,%f",
X		   &xlowl, &ylowl, &xhighr, &yhighr) != 4)
X	  return 1;
X	return 0;
X    }
X
X    if (!strncmp(s, "grid", 4)) {
X	if (sscanf(s+4, "%d,%d", &xgrid_n, &ygrid_n) != 2)
X	  return 1;
X	return 0;
X    }
X
X    if (!strncmp(s, "noaxes", 6)) {
X	no_axes++;
X	return 0;
X    }
X
X    if (!strncmp(s, "init", 4)) {
X	if (!init_done) do_initializations();
X	return 0;
X    }
X
X    if (!strncmp(s, "size", 4)) {
X	if (sscanf(s+4, "%f", &text_size) != 1)
X	  return 1;
X	if (init_done)
X	  dr_set_size(text_size);
X	return 0;
X    }
X
X    if (!strncmp(s, "shape", 5)) {
X	if (sscanf(s+5, "%f", &text_shape) != 1)
X	  return 1;
X	if (init_done)
X	  dr_set_shape(text_shape);
X	return 0;
X    }
X
X    if (!strncmp(s, "direction", 9)) {
X	float xx;
X
X	if (sscanf(s+9, "%f", &xx) != 1)
X	  return 1;
X	text_angle = xx;
X	return 0;
X    }
X
X    if (!strncmp(s, "text",   4)) return (labelpic(s+4, 0, 0));
X    if (!strncmp(s, "alabel", 6)) return (labelpic(s+6, 0, 1));
X    if (!strncmp(s, "rlabel", 6)) return (labelpic(s+6, 1, 1));
X
X				/* other options are errors */
X    return 1;
X}
X
Xstatic int labelpic(s, rel, conn)
Xchar *s;
Xint rel, conn;
X{
X    float xx, yy;
X    char *s1;
X    int old_linetype;
X
X    if (!init_done) do_initializations();
X
X    old_linetype = dr_set_ltype(7); /* set solid line */
X    xx = strtod(s, &s1);
X    if (s1 == s) return 1;
X    s = s1+1;
X    yy = strtod(s, &s1);
X    if (s1 == s) return 1;
X    s1++;			/* skip the separator */
X    s1[strlen(s1)-1] = '\0';
X    if (rel) {
X	xx += x;
X	yy += y;
X    }
X    PUT_TEXT(xx, yy, 0.0, 0.15, s1);
X    if (conn) {
X	dr_goto(xx, yy, 0);
X	dr_goto(x, y, 0);
X	dr_draw_circle();
X    }
X    else
X      penup = 1;
X    (void) dr_set_ltype(old_linetype);
X    return 0;
X}
X
Xint putdate(flag)
Xint flag;
X{
X    struct tm *timp;
X    long clk;
X    char buf1[40], buf2[20];
X
X    if (time(&clk) < 0) {
X	(void) sprintf (buf1, "time() failed.");
X	(void) dr_errmsg(buf1);
X	return 1;
X    }
X    timp = localtime(&clk);
X    sprintf(buf1, "%d/%d/%d",
X	    timp->tm_mday, timp->tm_mon+1, timp->tm_year + 1900);
X    if (flag > 1)
X      sprintf(buf2, " %02d:%02d:%02d",
X	      timp->tm_hour, timp->tm_min, timp->tm_sec);
X    else
X      buf2[0] = '\0';
X    strcat(buf1, buf2);
X    PUT_TEXT(xhigh, yhigh, -(float)strlen(buf1), 0.7, buf1);
X    penup = 1;
X    return 0;
X}
X
X
Xvoid fatal(s1, s2)
Xchar *s1, *s2;
X{
X    fprintf (stderr,"%s: Fatal error: %s %s\n", myname, s1, s2);
X    exit(1);
X}
X
Xstatic char *utbl[] = {
X    "-a xlo,ylo,xhi,yhi\tspecify relative plot area on paper",
X    "-b\t\t\tdon't draw axes",
X    "-c num\t\t\tchoose character set `num'",
X    "-d\t\t\tinclude date (time) stamp",
X    "-f c1,c2\t\tuse these columns of input, higher is for y",
X    "-g xgrid,ygrid\t\tspecify x&y grids",
X    "-h\t\t\tgive this stuff",
X    "-l\t\t\tlinetype",
X    "-m marker\t\tspecify marker & discontinous mode",
X    "-n text\t\tname the picture",
X    "-p num\t\t\tspecify pen number",
X#ifdef GL_LIB
X    "-t target\t\tspecify device: `ega', `a3', `a4' etc. Defaults from env.",
X#else
X    "-t target\t\tspecify device: `a3', `a4' etc. Defaults from env.",
X#endif
X    "-x|y low,incr,high\tspecify axis range",
X    "-X|Y text\t\taxis label",
X    "-v\t\t\tprint version ID",
X    "Most (all?) of these may also be given inside the data, look for manual",
X    NULL
X};
X
Xvoid usage()
X{
X    register char **p;
X    printf ("usage: \"%s [opts] [file ...]\"\n", myname);
X    for (p=utbl; *p; p++)
X      (void)printf (" %s\n", *p);
X    exit(0);
X}
END_OF_FILE
if test 17080 -ne `wc -c <'draw.c'`; then
    echo shar: \"'draw.c'\" unpacked with wrong size!
fi
# end of 'draw.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0