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