home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Copyright (C) 1988, 1989 by Juha Takala, jta@sah.vtt.fi
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 1.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- the file "License for more details
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
- */
-
- /* Description:
- * Non-interactive user interface program to provide interface between
- * device manipulation subroutines and user supplied command files.
- * This program will accept all kinds of command line arguments and
- * pseudo comments mixed in between the data lines. See the man page.
- *
- * The good thing about this program is that it will accept infinite
- * amount of input data points; they are not stored, but processed one
- * at a time.
- */
- static char *RCS_id =
- "$Id: draw.c,v 2.7 89/12/08 14:00:39 jta Exp Locker: jta $";
-
- #include <stdio.h>
- #ifdef MSDOS
- #include <stdlib.h>
- #endif /* MSDOS */
- #include <string.h>
- #include <sys/types.h>
- #include <time.h>
- #include <math.h>
- #include <signal.h>
- #ifndef MSDOS
- #include <sys/inode.h>
- #include <sys/file.h>
- #endif
- #include <string.h>
- #include "dr_lib.h"
-
- double strtod();
-
- char *myname;
- float xlowl = 0.0; /* relative plotting area on paper */
- float ylowl = 0.0;
- float xhighr= 1.0;
- float yhighr = 1.0;
-
- float xlow = -1.0; /* x axis range */
- float xincr = 0.5;
- float xhigh = 1.0;
- int xgrid_n = 0;
- char *xlabel_text = NULL;
-
- float ylow = -1.0; /* y axis range */
- float yincr = 0.5;
- float yhigh = 1.0;
- int ygrid_n = 0;
- char *ylabel_text = NULL;
-
- static float x, y; /* current point, needs to be */
- /* remembered, eg. when relative text is */
- /* inserted by #$texthere */
- char *name_text = NULL; /* name of picture */
- int pennum = 1;
- int penup = 1;
- int no_axes = 0;
- int init_done = 0;
- int dateflag = 0;
- int linetype = 7; /* default for solid linetype */
- float text_angle = 0.0; /* radians */
- float text_size = 1.0; /* text size factor */
- float text_shape = 1.0; /* text shape factor */
- int cset = 0; /* char set, default is US Ascii */
- int continuous = 1; /* continuous line / discrete points */
- /* 0 = discontinous */
- char marker = '*'; /* default marker char in discontinous mode */
- char informat[200] = "%f %f"; /* default input data line format */
- int reversed = 0; /* != 0 means input is y before x */
- int absolute = 0; /* != 0 when 'absolute' coordinates are */
- /* to be processed */
- float xabs_origin = 0.0; /* origin of 'absolute' mode data points */
- float yabs_origin = 0.0;
-
- int device = HP7475 | SIZE_A4;
-
- static int setmode();
- static int labelpic();
- static void doit();
- static void setdevice();
- extern void exit();
-
- static void (*old_int_handler)();
- static void new_int_handler();
- static void fatal();
- static void usage();
-
- #define PUT_TEXT(x,y,xofs,yofs,text) \
- dr_put_text((x), (y), (xofs), (yofs), text_angle, 1.0, (text))
- #define PUT_X_TEXT(x,y,text) \
- dr_put_text((x), (y), -(float)strlen(text), -2.0, 0.0, 1.4, (text))
- #define PUT_Y_TEXT(x,y,text) \
- dr_put_text((x), (y), 0.0, -2.0, -M_PI_2, 1.4, (text))
- #define PUT_N_TEXT(x,y,text) \
- dr_put_text((x), (y), -(float)strlen(text)/2.0, 0.4, 0.0, 2.0, (text))
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int c;
- extern char *optarg;
- extern int optind, opterr;
- char *opts = "a:bc:df:g:hl:m:n:p:s:S:t:x:X:y:Y:v";
-
- FILE *fp;
-
- myname = *argv;
- setdevice(getenv("DRAWDEV"));
-
-
- while ((c = getopt(argc, argv, opts)) != -1) {
- switch (c) {
- case 'a':
- if (sscanf(optarg, "%f,%f,%f,%f",
- &xlowl, &ylowl, &xhighr, &yhighr) != 4)
- fatal("invalid plotting area definition: ", optarg);
- break;
- case 'b': no_axes++; break;
- case 'c': cset = atoi(optarg); break;
- case 'd': dateflag++; break;
- case 'f':
- /* input lines are : "-- -- y -- -- x -- --"
- * (dashes indicate fields, that we are not interested in)
- * and we want to plot y=f(x), so we specify option
- * "-f 6,3" (fields are numbered from 1...)
- */
- {
- int xcol, ycol;
- if (sscanf(optarg, "%d,%d", &xcol, &ycol) != 2)
- fatal("invalid input format definition: %s", optarg);
- if (xcol == ycol)
- fatal("invalid input format definition: %s", optarg);
- if (xcol > ycol) {
- int temp = xcol;
- reversed++;
- xcol = ycol;
- ycol = temp;
- }
- ycol -= xcol;
- informat[0] = '\0';
- while (--xcol)
- (void)strcat(informat, "%*f ");
- (void)strcat(informat, "%f ");
- while (--ycol)
- (void)strcat(informat, "%*f ");
- (void)strcat(informat, "%f");
- }
- break;
- case 'g':
- if (sscanf(optarg, "%d,%d", &xgrid_n, &ygrid_n) != 2)
- fatal("invalid grid spec.: ", optarg);
- break;
- case 'h': case '?':
- usage(); break;
- case 'l':
- if (sscanf(optarg, "%d", &linetype) != 1)
- fatal("invalid line type:", optarg);
- break; /* draw axes before setting it! */
- case 'm':
- continuous = 0;
- if (sscanf(optarg, "%1s", &marker) != 1)
- fatal ("no marker found.", "\0");
- break;
- case 'n':
- name_text = optarg; break;
- case 'p':
- if (sscanf(optarg, "%d", &pennum) != 1)
- fatal("invalid pen:", optarg);
- if ((pennum > 6) || (pennum < 1))
- pennum = 1;
- break;
- case 's':
- if (sscanf(optarg, "%f", &text_size) != 1)
- fatal("invalid text size: ", optarg);
- break;
- case 'S':
- if (sscanf(optarg, "%f", &text_shape) != 1)
- fatal("invalid text shape: ", optarg);
- break;
- case 't': setdevice(optarg); break;
- case 'x':
- if (sscanf(optarg, "%f,%f,%f",
- &xlow, &xincr, &xhigh) != 3)
- fatal("invalid x range: ", optarg);
- break;
- case 'X':
- xlabel_text = optarg; break;
- case 'y':
- if (sscanf(optarg, "%f,%f,%f",
- &ylow, &yincr, &yhigh) != 3)
- fatal("invalid y range: ", optarg);
- break;
- case 'Y':
- ylabel_text = optarg; break;
- case 'v':
- fprintf(stderr, "%s\n", RCS_id);
- exit (0);
- default:
- exit(1);
- }
- }
- argc -= optind;
- argv += optind;
-
- old_int_handler = signal (SIGINT, new_int_handler);
-
- /*
- * Options have been taken, start the work. Initializations will be
- * done just before first data point is used... This is jippo to
- * make it possible to give coordinate specifications from inside
- * the data....
- */
- if (argc == 0) /* no files, take points from stdin */
- doit(stdin);
- else { /* take points from all files */
- for ( ; argc; argc--, argv++) {
- if (NULL == (fp = fopen(*argv, "r"))) {
- perror(*argv);
- continue;
- }
- doit(fp);
- fclose(fp);
- }
- }
- if (init_done)
- return(dr_finish(1) ? 1 : 0); /* 1 == error(s) */
- else
- return 2; /* nothing was done! */
- }
-
-
- /* gl_plot will set int handler at its initialization time, and restore
- what it saw there previously, and finally it will
- kill(SIGINT,getpid()). This is what we are going to do, too, so that
- OUR caller can clean ITS data stuctures etc.
- */
- static void new_int_handler() {
- (void)dr_finish(0);
- signal (SIGINT, old_int_handler);
- kill (getpid(), SIGINT); /* zap my self */
- sleep(1);
- exit(3); /* if that is not enough */
- }
-
-
- static void do_initializations()
- {
- init_done++; /* remember it is done */
- dr_start(xlowl, ylowl, xhighr, yhighr, device);
- if (cset != 0) dr_set_cset(cset);
- dr_set_size(text_size);
- dr_set_shape(text_shape);
- dr_set_pen(pennum);
- dr_area_def(xlow, xincr, xhigh, ylow, yincr, yhigh, no_axes);
- if (!no_axes) {
- if (xgrid_n) dr_xgrid(xgrid_n);
- if (ygrid_n) dr_ygrid(ygrid_n);
- }
- if (xlabel_text) PUT_X_TEXT(xhigh, ylow, xlabel_text);
- if (ylabel_text) PUT_Y_TEXT(xlow, yhigh, ylabel_text);
- if (name_text) PUT_N_TEXT((xhigh+xlow)/2.0, yhigh, name_text);
- if (dateflag) putdate(dateflag);
- dr_set_ltype(linetype);
- }
-
- static void setdevice(s)
- char *s;
- {
- if (s == NULL) return;
- if (!strcmp(s,"a4")) device = (HP7475 | SIZE_A4);
- else if (!strcmp(s,"a3")) device = (HP7475 | SIZE_A3);
- else if (!strcmp(s,"a")) device = (HP7475 | SIZE_A);
- else if (!strcmp(s,"b")) device = (HP7475 | SIZE_B);
- #ifdef GL_LIB
- else if (!strcmp(s,"ega")) device = SCREEN;
- #endif
- #ifdef PLOT
- else if (!strcmp(s,"plot")) device = PLOTLIB;
- #endif
- #ifdef TEK
- else if (!strcmp(s,"tek"))
- fatal("Sorry,", "Tek4010 not yet.");
- #endif
- else fatal("Unsupported plotting device", s);
- }
-
- static void doit(fp)
- FILE *fp;
- {
- #define LINESIZE 512
- char buf[LINESIZE+1], *p;
- char emsg[200];
- int lineno = 0;
-
- while (1) {
- if (NULL == fgets(buf, LINESIZE, fp)) /* EOF */
- return;
-
- lineno++;
- for (p=buf; *p; p++) /* skip white space */
- if (strchr(" \t",*p) == NULL)
- break;
- if (*p == '\n')
- continue;
-
- if (*p == '#') {
- if (setmode(p+1)) {
- sprintf(emsg, "Invalid pseudo comment line (%d): %s",
- lineno, buf);
- if (init_done)
- dr_errmsg(emsg);
- else
- write(2, emsg, strlen(emsg));
- }
- continue;
- }
- /* now we expect data lines, */
- /* initializations must be done by now */
- if (!init_done) do_initializations();
-
- if (sscanf(p, informat, &x, &y) != 2) {
- sprintf(emsg, "Invalid data line (%d): %s", lineno, buf);
- dr_errmsg(emsg);
- continue;
- }
- if (reversed) {
- float temp = x;
- x = y;
- y = temp;
- }
- if (absolute) {
- x = xlow + (xabs_origin + x) * (xhigh - xlow);
- y = ylow + (yabs_origin + y) * (yhigh - ylow);
- }
- /* this needs to be fixed: reversed directions not handled! */
- if (x < xlow || x > xhigh || y < ylow || y > yhigh) {
- sprintf (emsg, "point out of range at line (%d): %s",
- lineno, buf);
- dr_warnmsg(emsg);
- }
- if (continuous) {
- dr_goto(x, y, penup);
- penup = 0;
- }
- else {
- dr_put_mark(x, y, marker);
- }
- }
- }
-
- static void remember(to, from) /* copy string to safe place, put its */
- /* addr into `*to' */
- char **to, *from;
- {
- #ifndef MSDOS
- extern char *malloc();
- #endif
- *to = malloc(strlen(from)+1);
- strcpy(*to, from);
- }
-
- /* handle '#<something>' lines */
- static int setmode(s) /* return 0 on success, != when trouble */
- char *s;
- {
- for (; *s; s++) /* skip white space */
- if (strchr(" \t",*s) == NULL)
- break;
- if (*s++ != '$') /* only '$' causes action */
- return 0;
-
- for (; *s; s++) /* skip white space */
- if (strchr(" \t",*s) == NULL)
- break;
-
- if (!strncmp (s, "absolute", 8)) {
- absolute = 1;
- if (sscanf(s+8, "%f,%f", &xabs_origin, &yabs_origin) == 2)
- return 0;
- xabs_origin = 0.0;
- yabs_origin = 0.0;
- return 1;
- }
-
- if (!strncmp (s, "endabsolute", 11)) {
- absolute = 0;
- return 0;
- }
-
- if (!strncmp (s,"penup",5)) {
- penup = 1;
- return 0;
- }
-
-
- if (!strncmp(s, "include", 7)) {
- FILE *fp;
- char *p;
-
- for (s+=8; *s; s++) /* skip whitespace */
- if (strchr(" \t",*s) == NULL)
- break;
- for (p=s; *p; p++)
- if (strchr(" \t\n",*s) != NULL)
- break;
- *(p-1) = '\0'; /* put terminator */
-
- if (NULL == (fp = fopen(s, "r"))) {
- perror(p);
- return 1;
- }
- doit(fp); /* recursive call */
- fclose(fp);
- return 0;
- }
-
- if (!strncmp (s, "cset", 4)) {
- int csetnum = 0;
- if (sscanf(s+4, "%d", &csetnum) != 1)
- return 1;
- if (!init_done) do_initializations();
- dr_set_cset(csetnum);
- return 0;
- }
-
- if (!strncmp (s, "pen", 3)) {
- if (sscanf(s+3, "%d", &pennum) != 1)
- return 1;
- if (!init_done) do_initializations();
- dr_set_pen(pennum);
- return 0;
- }
-
- if (!strncmp (s, "ltype", 5)) {
- int linetype = 1;
- if (sscanf(s+5, "%d", &linetype) != 1)
- return 1;
- if (!init_done) do_initializations();
- dr_set_ltype(linetype);
- return 0;
- }
-
- if (!strncmp(s, "mark", 4)) {
- s += 4;
- while (1) {
- marker = *s++;
- if (strchr(" \t", marker) == NULL)
- break;
- }
- continuous = (strchr (" \n\r\t", marker) != NULL);
- return 0;
- }
-
- if (!strncmp(s, "date", 4)) {
- if (dateflag)
- return 1;
- dateflag = 1;
- if (init_done)
- putdate(1);
- return 0;
- }
- if (!strncmp(s, "time", 4)) {
- if (dateflag)
- return 1;
- dateflag = 2;
- if (init_done)
- putdate(2);
- return 0;
- }
-
- if (!strncmp(s, "xlabel", 6)) {
- if (xlabel_text) return 1;
- s += 7; /* skip one space/separator */
- s[strlen(s)-1] = '\0'; /* drop newline */
- if (!init_done) {
- remember(&xlabel_text, s);
- return 0;
- }
- PUT_X_TEXT(xhigh, ylow, s);
- xlabel_text = myname; /* some char-pointer that has non NULL */
- /* value, so that we remember this */
- penup = 1;
- return 0;
- }
-
- if (!strncmp(s, "ylabel", 6)) {
- if (ylabel_text) return 1;
- s += 7;
- s[strlen(s)-1] = '\0';
- if (!init_done) {
- remember(&ylabel_text, s);
- return 0;
- }
- PUT_Y_TEXT(xlow, yhigh, s);
- ylabel_text = myname;
- penup = 1;
- return 0;
- }
-
- if (!strncmp(s, "name", 4)) {
- if (name_text) return 1;
- s += 5; /* skip the space */
- s[strlen(s)-1] = '\0'; /* drop newline */
- if (!init_done) {
- remember(&name_text, s);
- return 0;
- }
- PUT_N_TEXT((xhigh+xlow)/2.0, yhigh, s);
- name_text = myname;
- penup = 1;
- return 0;
- }
-
- if (!strncmp(s, "xrange", 6)) {
- if (sscanf(s+6, "%f,%f,%f", &xlow, &xincr, &xhigh) != 3)
- return 1;
- return 0;
- }
-
- if (!strncmp(s, "yrange", 6)) {
- if (sscanf(s+6, "%f,%f,%f", &ylow, &yincr, &yhigh) != 3)
- return 1;
- return 0;
- }
-
- if (!strncmp(s, "area", 4)) {
- if (sscanf(s+4, "%f,%f,%f,%f",
- &xlowl, &ylowl, &xhighr, &yhighr) != 4)
- return 1;
- return 0;
- }
-
- if (!strncmp(s, "grid", 4)) {
- if (sscanf(s+4, "%d,%d", &xgrid_n, &ygrid_n) != 2)
- return 1;
- return 0;
- }
-
- if (!strncmp(s, "noaxes", 6)) {
- no_axes++;
- return 0;
- }
-
- if (!strncmp(s, "init", 4)) {
- if (!init_done) do_initializations();
- return 0;
- }
-
- if (!strncmp(s, "size", 4)) {
- if (sscanf(s+4, "%f", &text_size) != 1)
- return 1;
- if (init_done)
- dr_set_size(text_size);
- return 0;
- }
-
- if (!strncmp(s, "shape", 5)) {
- if (sscanf(s+5, "%f", &text_shape) != 1)
- return 1;
- if (init_done)
- dr_set_shape(text_shape);
- return 0;
- }
-
- if (!strncmp(s, "direction", 9)) {
- float xx;
-
- if (sscanf(s+9, "%f", &xx) != 1)
- return 1;
- text_angle = xx;
- return 0;
- }
-
- if (!strncmp(s, "text", 4)) return (labelpic(s+4, 0, 0));
- if (!strncmp(s, "alabel", 6)) return (labelpic(s+6, 0, 1));
- if (!strncmp(s, "rlabel", 6)) return (labelpic(s+6, 1, 1));
-
- /* other options are errors */
- return 1;
- }
-
- static int labelpic(s, rel, conn)
- char *s;
- int rel, conn;
- {
- float xx, yy;
- char *s1;
- int old_linetype;
-
- if (!init_done) do_initializations();
-
- old_linetype = dr_set_ltype(7); /* set solid line */
- xx = strtod(s, &s1);
- if (s1 == s) return 1;
- s = s1+1;
- yy = strtod(s, &s1);
- if (s1 == s) return 1;
- s1++; /* skip the separator */
- s1[strlen(s1)-1] = '\0';
- if (rel) {
- xx += x;
- yy += y;
- }
- PUT_TEXT(xx, yy, 0.0, 0.15, s1);
- if (conn) {
- dr_goto(xx, yy, 0);
- dr_goto(x, y, 0);
- dr_draw_circle();
- }
- else
- penup = 1;
- (void) dr_set_ltype(old_linetype);
- return 0;
- }
-
- int putdate(flag)
- int flag;
- {
- struct tm *timp;
- long clk;
- char buf1[40], buf2[20];
-
- if (time(&clk) < 0) {
- (void) sprintf (buf1, "time() failed.");
- (void) dr_errmsg(buf1);
- return 1;
- }
- timp = localtime(&clk);
- sprintf(buf1, "%d/%d/%d",
- timp->tm_mday, timp->tm_mon+1, timp->tm_year + 1900);
- if (flag > 1)
- sprintf(buf2, " %02d:%02d:%02d",
- timp->tm_hour, timp->tm_min, timp->tm_sec);
- else
- buf2[0] = '\0';
- strcat(buf1, buf2);
- PUT_TEXT(xhigh, yhigh, -(float)strlen(buf1), 0.7, buf1);
- penup = 1;
- return 0;
- }
-
-
- void fatal(s1, s2)
- char *s1, *s2;
- {
- fprintf (stderr,"%s: Fatal error: %s %s\n", myname, s1, s2);
- exit(1);
- }
-
- static char *utbl[] = {
- "-a xlo,ylo,xhi,yhi\tspecify relative plot area on paper",
- "-b\t\t\tdon't draw axes",
- "-c num\t\t\tchoose character set `num'",
- "-d\t\t\tinclude date (time) stamp",
- "-f c1,c2\t\tuse these columns of input, higher is for y",
- "-g xgrid,ygrid\t\tspecify x&y grids",
- "-h\t\t\tgive this stuff",
- "-l\t\t\tlinetype",
- "-m marker\t\tspecify marker & discontinous mode",
- "-n text\t\tname the picture",
- "-p num\t\t\tspecify pen number",
- #ifdef GL_LIB
- "-t target\t\tspecify device: `ega', `a3', `a4' etc. Defaults from env.",
- #else
- "-t target\t\tspecify device: `a3', `a4' etc. Defaults from env.",
- #endif
- "-x|y low,incr,high\tspecify axis range",
- "-X|Y text\t\taxis label",
- "-v\t\t\tprint version ID",
- "Most (all?) of these may also be given inside the data, look for manual",
- NULL
- };
-
- void usage()
- {
- register char **p;
- printf ("usage: \"%s [opts] [file ...]\"\n", myname);
- for (p=utbl; *p; p++)
- (void)printf (" %s\n", *p);
- exit(0);
- }
-