/* * AIM Suite III v3.1.1 * (C) Copyright AIM Technology Inc. 1986,87,88,89,90,91,92. * All Rights Reserved. */ #ifndef lint static char sccs_id[] = { " @(#) plot.c:3.2 5/30/92 20:18:44" }; #endif /* PLOT - Plot numeric x,y,pen data on dumb terminals. ** ** Plot produces a quick-and-dirty x,y graph for terminal ** examination of numeric data input in columns. Windowing can be ** specified, and different pen characters can be set between plot files. ** Data lines beginning with the two characters ': ' are skipped, ** remainder of lines beginning with '( ' are listed verbatim. ** ("comment" and "echo" a-la shell conventions.) ** ** Synopsis: ** plot -xn w-w %f file... default -x1 ** -yn w-w %f default -y2 ** -pn w-w %c ** ** -x s,s... w-w %f file... ** -y s,s... w-w %f file... ** -p s,s... w-w %c file... default -p 1 ** ** Keyword options: ** -hn -wn -mhn -mwn -en -e str ** ** -hn n rows high plot default -h12 ** -wn n column wide plot default -w40 ** -mhn n row high margin default -mh2 ** -mwn n column wide margin default -mw6 ** -en echo first n-data points default -e0 ** -e str preface graph with str ** ** Positional Options: ** ** -xn x-column,y-column,pen-column. default -x1 -y2 ** -yn x,y-values locate points to be plotted within ** -pn window (w-w) range, while p-values index characters ** in the pens string (%c). A finite-differences list ** may be specified (s,s,...) for x,y,p options. Example ** -p 1,1 produces p-values 1 2 3 4 5 etc., while -p1 ** means values shall be read from column 1 each record, ** and both -p 1,0 and -p 1 produce pen values 1 1 1... ** ** w-w specifies low-high range for x,y and p. ** %f specifies printf-style label for x,y. default %.1f ** %c pens string is c. default %123456789 ** n optionally signed number with optional decimal point ** ** Bugs: ** Filenames must not look like numbers. */ #include #include #define mmax(x,min,max) if (xmax) max=x; #define up 60 #define over 120 double atof(); char *scra(); double col(); double getval(); FILE *f = 0; char BLANKS[] = " "; char *p; struct coors { float xc, /* column number */ xv[5], /* value sequence */ xl, /* left (min) */ xr; /* right (max) */ char xfmt[up];/* label format */ } xopt = {1.,0.,0.,0.,0.,0.,0.,0.,"%.1f"}, /* x-options list */ yopt = {2.,0.,0.,0.,0.,0.,0.,0.,"%.1f"}, /* y-options list */ popt = {0.,1.,0.,0.,0.,0.,0.,0.,"%123456789"},/* p-options list */ *coor = &xopt; /* any option list */ float h = 12., /* number rows high, plot+margin */ w = 40., /* number cols wide, plot+margin */ mw = 6., /* margin width, in cols left of plot */ mh = 2.; /* margin height, in rows below plot */ float num, /* global return from isnum() */ tmp; /* tmp for arg handling */ int aw = 1; /* auto windo flag */ int n; /* number points in xyp[] arrays */ int nplots = 0, /* count of plots output */ nfiles = 0; /* count of arg files read */ int echo = 0; float x[1000],y[1000]; int pv[1000]; int ixy = 0; char str[5120]; char scr[up][over]; char stmp[128]; int col_not_there; /* flag set by col if missing columns */ main(argc,argv) int argc; char **argv; { /* ** Initiallize screen, default arglist. */ int i; p = &scr[0][0]; for (i=0;i0) { p = *++argv; if (p[0]=='-' && p[1]=='\0') /* standard input */ { if (f!=NULL) fclose(f); /* close open file */ f = stdin; n = rd_data("std-input"); continue; } else if (p[0]=='-' && isalpha(p[1])) { /* * decompose -xypmwhe options. */ switch (p[1]) { case 'x': coor = &xopt; if((p+=2)[0]!='\0') coor->xc = atof(p); continue; case 'y': coor = &yopt; if((p+=2)[0]!='\0') coor->xc = atof(p); continue; case 'p': coor = &popt; if((p+=2)[0]!='\0') coor->xc = atof(p); continue; case 'm': /* decompose -mh and -mw */ tmp = atof(p+3); *((p[2]=='h')?&mh:&mw) = tmp; continue; case 'h': h = atof(p+=2); continue; case 'w': w = atof(p+=2); continue; case 'e': if ((p+=2)[0]=='\0') {if (argc>1) printf("%s\n",(--argc,*++argv)); } else echo = atof(p); continue; } } else if (isnum(p)) { /* ** decompose num num-num num,num */ int k; if (p[0]!='-') /* check break character */ { for (k=0;k<5;k++) coor->xv[k] = 0; /* clear array */ coor->xc = 0; /* clear any col nums in there */ for (k=0;k<5;k++) { if (p[0]==','||p[0]=='\0') coor->xv[k] = num; if (p[0]=='\0') break; if (p[0]==',') if (!isnum(++p)) /* shift */ break; } } /* ** decompose num-num */ if (p[0]=='-') { coor->xl = num; coor->xr = atof(++p); } continue; } else if (p[0]=='%') { /* * process %fmt option. */ strncpy((char *) coor->xfmt, p, up); continue; } else { /* ** else arg must be filename to plot */ f = (f==NULL) ? fopen(p,"r") : freopen(p,"r",f); n = rd_data(p); nfiles++; } } if (nfiles==0) f = stdin, n = rd_data("std-input");/* default stdinput */ if (nplots==0 && n>0) graph(aw); /* flush pending graph */ exit(0); } rd_data(filenam) char *filenam; { int np; /* number chars in format string */ int pval; /* temporary p holder */ int awx, awy; /* save auto-window indications */ int sxy = ixy; /* save ixy on entry */ np = strlen(popt.xfmt); /* number of pens in pfmt */ /* ignore unopened files */ if (f==NULL) { fprintf(stderr, "graph:can't read %s\n",filenam); return(0); } if (echo>0) printf("plot: file %s\n",filenam); /* ** read thru file, accepting data if pen value OK. */ while (fgets(str,5120,f)!=NULL) /* munch until eof */ { p = str; while (*p==' ') p++; /* skip leading whitespace */ if (p[0]==':' && p[1]==' ') continue; /* skip : comment line */ if ( p[0]=='(' && (p[1]==' '||p[1]==' ') ) { puts(p); /* ( commentary line ) */ continue; } else if ( p[0]=='e'&&p[1]=='c'&&p[2]=='h'&&p[3]=='o'&&(p[4]==' '||p[4]==' ') ) { puts( p+=5 ); /* 'echo' remainder */ continue; } else if (p[0]=='\n') continue; /* skip blank lines */ else { /* ** extract field or compute plot data */ col_not_there = 0; /* clear flag */ x[ixy] = getval(&xopt); y[ixy] = getval(&yopt); pval = getval(&popt); if (pval<1 || pval>=np || col_not_there ) continue; /* if pen off list */ else pv[ixy] = popt.xfmt[pval]; if (ixy==sxy) /* very late initialization */ { if (awx = xopt.xr==xopt.xl) xopt.xr = xopt.xl = x[sxy]; if (awy = yopt.xr==yopt.xl) yopt.xr = yopt.xl = y[sxy]; } if (awx) mmax( x[ixy], xopt.xl, xopt.xr); if (awy) mmax( y[ixy], yopt.xl, yopt.xr); if ( x[ixy]xopt.xr || y[ixy]yopt.xr ) continue; /* skip point outside window */ } if (echo-->0) { printf("%4d\t",ixy+1); printf(xopt.xfmt,x[ixy]),putchar('\t'); printf(yopt.xfmt,y[ixy]); printf("\t%c\n",pv[ixy]); } if (ixy<999) ixy++; /* accept point in array */ } return (ixy); /* successful return */ } /* COL -- extract k-th column from record ** ** columns separated by spaces. ** ** Parameters: ** k -- column number ** p -- pointer to record ** ** Returns: ** VAL -- numeric value of desired column ** */ double col(k,p) int k; char *p; { double tmp; /* skip to desired column */ while (--k>0) { while ( *p!=' ' && *p!='\0' ) ++p; /* slough trailing blanks */ while (*p==' ') ++p; } col_not_there |= (*p=='\000');/* accumulate missing col flag */ tmp = atof(p); return (tmp); } graph(awf) int awf; /* auto-window flag */ { int i,j; int nh, /* num-1 rows high plot */ nw, /* num-1 cols wide plot */ xo, /* screen loc for x_origin */ yo; /* screen loc for y_origin */ float xs, /* floating sum x */ ys, /* floating sum y */ x2, /* floating sum x**2 */ y2; /* floating sum y**2 */ float xd, /* max-min x axis */ yd, /* max-min y axis */ pd; /* max-min p axis */ /* ** initialization */ xs = ys = x2 = y2 = 0.0; nh = h-mh-1; /* height-1 of plot area */ nw = w-mw-1; /* width-1 */ xo = mw; yo = nh; /* offset of plot origin in scr buffer */ for (i=0;i=0 && x=0 && y=0 && x=0 && y=0 && x=0 && y= '0' && scr[y][x] <= '9') /* if there's a pt there */ return (scr[y][x] = '*');/* put an '*' there for overlapped pts */ else /* if nothing has been plotted there */ return (scr[y][x] = c); /* then plot it */ else return (c); } /* ISNUM -- atof with side effects. ** ** Isnum gets characters from global string pointer p, and ** advances the pointer in the case a floating number is ** there. ** ** Parameters: ** none; ** ** Assumes: ** p -- global pointer to string for decomposition. ** ** Returns: ** 0 -- no number ** n -- string length of number ** ** Side-effects: ** p -- advanced by the length of number returned. ** not changed if no number read. ** num -- global float cell contaning atof result. */ isnum(dumy) char *dumy; { char *ps = p, ch; /* save p */ double div = 1., dec = 1.;/* collecting past decimal pt */ float sign = 1.; num = 0.; /* start collecting now */ dumy = dumy; /* ling plug */ while ( (ch = *p)==' ' || ch=='\t' ) ++p; /* skip leading whitespace */ if ( (ch = *p)=='+' || ch=='-' ) ++p, sign = (ch=='+') ? 1 : -1; /* optional sign */ while ( isdigit(ch = *p) ) ++p, num = 10.*num + (ch-'0'); /* digits */ if ( (ch = *p)=='.' ) ++p, dec = 10.; /* optional decimal */ while ( isdigit(ch = *p) ) /* more digits */ ++p, div *= dec, num = num*10. + (ch-'0'); if ( p==ps ) return ((p = ps),0); /* null, or junk follows number */ num = sign*num/div; return (p-ps); } double getval(cp) struct coors *cp; { if (cp->xc>0.0) /* check for val from column */ return ( col( (int) cp->xc, p) ); else { double tmp; int i; tmp = cp->xv[0]; /* else val from sequence */ for(i=0;i<4;i++) /* step sequence forward */ cp->xv[i] += cp->xv[i+1]; return (tmp); } }