|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <stdio.h> | 
|  | #include "iplot.h" | 
|  | #define	INF	1.e+37 | 
|  | #define	F	.25 | 
|  |  | 
|  | struct xy { | 
|  | int	xlbf;		/*flag:explicit lower bound*/ | 
|  | int 	xubf;		/*flag:explicit upper bound*/ | 
|  | int	xqf;		/*flag:explicit quantum*/ | 
|  | double (*xf)(double);	/*transform function, e.g. log*/ | 
|  | float	xa,xb;		/*scaling coefficients*/ | 
|  | float	xlb,xub;	/*lower and upper bound*/ | 
|  | float	xquant;		/*quantum*/ | 
|  | float	xoff;		/*screen offset fraction*/ | 
|  | float	xsize;		/*screen fraction*/ | 
|  | int	xbot,xtop;	/*screen coords of border*/ | 
|  | float	xmult;		/*scaling constant*/ | 
|  | } xd,yd; | 
|  | struct val { | 
|  | float xv; | 
|  | float yv; | 
|  | int lblptr; | 
|  | } *xx; | 
|  |  | 
|  | char *labels; | 
|  | int labelsiz; | 
|  |  | 
|  | int tick = 50; | 
|  | int top = 4000; | 
|  | int bot = 200; | 
|  | float absbot; | 
|  | int	n; | 
|  | int	erasf = 1; | 
|  | int	gridf = 2; | 
|  | int	symbf = 0; | 
|  | int	absf = 0; | 
|  | int	transf; | 
|  | int	equf; | 
|  | int	brkf; | 
|  | int	ovlay = 1; | 
|  | float	dx; | 
|  | char	*plotsymb; | 
|  |  | 
|  | #define BSIZ 80 | 
|  | char	labbuf[BSIZ]; | 
|  | char	titlebuf[BSIZ]; | 
|  |  | 
|  | char *modes[] = { | 
|  | "disconnected", | 
|  | "solid", | 
|  | "dotted", | 
|  | "dotdashed", | 
|  | "shortdashed", | 
|  | "longdashed" | 
|  | }; | 
|  | int mode = 1; | 
|  | double ident(double x){ | 
|  | return(x); | 
|  | } | 
|  |  | 
|  | struct z { | 
|  | float lb,ub,mult,quant; | 
|  | }; | 
|  |  | 
|  | struct { | 
|  | char *name; | 
|  | int next; | 
|  | } palette[256]; | 
|  |  | 
|  | static char* colors[] = { | 
|  | "blue", | 
|  | "cyan", | 
|  | "green", | 
|  | "kblack", | 
|  | "magenta", | 
|  | "red", | 
|  | "white", | 
|  | "yellow" | 
|  | }; | 
|  | static void | 
|  | initpalette(void) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for(i=0; i<nelem(colors); i++){ | 
|  | palette[(uchar)colors[i][0]].name = colors[i]; | 
|  | palette[(uchar)colors[i][0]].next = colors[i][0]; | 
|  | } | 
|  | } | 
|  |  | 
|  | int pencolor = 'k'; | 
|  |  | 
|  | void init(struct xy *); | 
|  | void setopt(int, char *[]); | 
|  | void readin(void); | 
|  | void transpose(void); | 
|  | void getlim(struct xy *, struct val *); | 
|  | void equilibrate(struct xy *, struct xy *); | 
|  | void scale(struct xy *); | 
|  | void limread(struct xy *, int *, char ***); | 
|  | int numb(float *, int *, char ***); | 
|  | void colread(int *, char ***); | 
|  | int copystring(int); | 
|  | struct z setloglim(int, int, float, float); | 
|  | struct z setlinlim(int, int, float, float); | 
|  | void axes(void); | 
|  | int setmark(int *, struct xy *); | 
|  | void submark(int *, int *, float, struct xy *); | 
|  | void plot(void); | 
|  | int getfloat(float *); | 
|  | int getstring(void); | 
|  | void title(void); | 
|  | void badarg(void); | 
|  | int conv(float, struct xy *, int *); | 
|  | int symbol(int, int, int); | 
|  | void axlab(char, struct xy *, char *); | 
|  |  | 
|  | int main(int argc,char *argv[]){ | 
|  |  | 
|  | initpalette(); | 
|  | openpl(); | 
|  | range(0,0,4096,4096); | 
|  | init(&xd); | 
|  | init(&yd); | 
|  | xd.xsize = yd.xsize = 1.; | 
|  | xx = (struct val *)malloc((unsigned)sizeof(struct val)); | 
|  | labels = malloc(1); | 
|  | labels[labelsiz++] = 0; | 
|  | setopt(argc,argv); | 
|  | if(erasf) | 
|  | erase(); | 
|  | readin(); | 
|  | transpose(); | 
|  | getlim(&xd,(struct val *)&xx->xv); | 
|  | getlim(&yd,(struct val *)&xx->yv); | 
|  | if(equf) { | 
|  | equilibrate(&xd,&yd); | 
|  | equilibrate(&yd,&xd); | 
|  | } | 
|  | scale(&xd); | 
|  | scale(&yd); | 
|  | axes(); | 
|  | title(); | 
|  | plot(); | 
|  | closepl(); | 
|  | exits(0); | 
|  | return 0;	/* gcc */ | 
|  | } | 
|  |  | 
|  | void init(struct xy *p){ | 
|  | p->xf = ident; | 
|  | p->xmult = 1; | 
|  | } | 
|  |  | 
|  | void setopt(int argc, char *argv[]){ | 
|  | char *p1, *p2; | 
|  | float temp; | 
|  |  | 
|  | xd.xlb = yd.xlb = INF; | 
|  | xd.xub = yd.xub = -INF; | 
|  | while(--argc > 0) { | 
|  | argv++; | 
|  | again:		switch(argv[0][0]) { | 
|  | case '-': | 
|  | argv[0]++; | 
|  | goto again; | 
|  | case 'l': /* label for plot */ | 
|  | p1 = titlebuf; | 
|  | if (argc>=2) { | 
|  | argv++; | 
|  | argc--; | 
|  | p2 = argv[0]; | 
|  | while (*p1++ = *p2++); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case 'd':	/*disconnected,obsolete option*/ | 
|  | case 'm': /*line mode*/ | 
|  | mode = 0; | 
|  | if(!numb(&temp,&argc,&argv)) | 
|  | break; | 
|  | if(temp>=sizeof(modes)/sizeof(*modes)) | 
|  | mode = 1; | 
|  | else if(temp>=-1) | 
|  | mode = temp; | 
|  | break; | 
|  |  | 
|  | case 'o': | 
|  | if(numb(&temp,&argc,&argv) && temp>=1) | 
|  | ovlay = temp; | 
|  | break; | 
|  | case 'a': /*automatic abscissas*/ | 
|  | absf = 1; | 
|  | dx = 1; | 
|  | if(!numb(&dx,&argc,&argv)) | 
|  | break; | 
|  | if(numb(&absbot,&argc,&argv)) | 
|  | absf = 2; | 
|  | break; | 
|  |  | 
|  | case 's': /*save screen, overlay plot*/ | 
|  | erasf = 0; | 
|  | break; | 
|  |  | 
|  | case 'g': /*grid style 0 none, 1 ticks, 2 full*/ | 
|  | gridf = 0; | 
|  | if(!numb(&temp,&argc,&argv)) | 
|  | temp = argv[0][1]-'0';	/*for caompatibility*/ | 
|  | if(temp>=0&&temp<=2) | 
|  | gridf = temp; | 
|  | break; | 
|  |  | 
|  | case 'c': /*character(s) for plotting*/ | 
|  | if(argc >= 2) { | 
|  | symbf = 1; | 
|  | plotsymb = argv[1]; | 
|  | argv++; | 
|  | argc--; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case 't':	/*transpose*/ | 
|  | transf = 1; | 
|  | break; | 
|  | case 'e':	/*equal scales*/ | 
|  | equf = 1; | 
|  | break; | 
|  | case 'b':	/*breaks*/ | 
|  | brkf = 1; | 
|  | break; | 
|  | case 'x':	/*x limits */ | 
|  | limread(&xd,&argc,&argv); | 
|  | break; | 
|  | case 'y': | 
|  | limread(&yd,&argc,&argv); | 
|  | break; | 
|  | case 'h': /*set height of plot */ | 
|  | if(!numb(&yd.xsize, &argc,&argv)) | 
|  | badarg(); | 
|  | break; | 
|  | case 'w': /*set width of plot */ | 
|  | if(!numb(&xd.xsize, &argc, &argv)) | 
|  | badarg(); | 
|  | break; | 
|  | case 'r': /* set offset to right */ | 
|  | if(!numb(&xd.xoff, &argc, &argv)) | 
|  | badarg(); | 
|  | break; | 
|  | case 'u': /*set offset up the screen*/ | 
|  | if(!numb(&yd.xoff,&argc,&argv)) | 
|  | badarg(); | 
|  | break; | 
|  | case 'p': /*pen color*/ | 
|  | colread(&argc, &argv); | 
|  | break; | 
|  | default: | 
|  | badarg(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void limread(struct xy *p, int *argcp, char ***argvp){ | 
|  | if(*argcp>1 && (*argvp)[1][0]=='l') { | 
|  | (*argcp)--; | 
|  | (*argvp)++; | 
|  | p->xf = log10; | 
|  | } | 
|  | if(!numb(&p->xlb,argcp,argvp)) | 
|  | return; | 
|  | p->xlbf = 1; | 
|  | if(!numb(&p->xub,argcp,argvp)) | 
|  | return; | 
|  | p->xubf = 1; | 
|  | if(!numb(&p->xquant,argcp,argvp)) | 
|  | return; | 
|  | p->xqf = 1; | 
|  | } | 
|  |  | 
|  | #ifdef NOTDEF | 
|  | isdigit(char c){ | 
|  | return '0'<=c && c<='9'; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | int | 
|  | numb(float *np, int *argcp, char ***argvp){ | 
|  | char c; | 
|  |  | 
|  | if(*argcp <= 1) | 
|  | return(0); | 
|  | while((c=(*argvp)[1][0]) == '+') | 
|  | (*argvp)[1]++; | 
|  | if(!(isdigit((uchar)c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.')) | 
|  | return(0); | 
|  | *np = atof((*argvp)[1]); | 
|  | (*argcp)--; | 
|  | (*argvp)++; | 
|  | return(1); | 
|  | } | 
|  |  | 
|  | void colread(int *argcp, char ***argvp){ | 
|  | int c, cnext; | 
|  | int i, n; | 
|  |  | 
|  | if(*argcp<=1) | 
|  | return; | 
|  | n = strlen((*argvp)[1]); | 
|  | if(strspn((*argvp)[1], "bcgkmrwy")!=n) | 
|  | return; | 
|  | pencolor = cnext = (*argvp)[1][0]; | 
|  | for(i=0; i<n-1; i++){ | 
|  | c = (unsigned char)(*argvp)[1][i]; | 
|  | cnext = (unsigned char)(*argvp)[1][i+1]; | 
|  | palette[c].next = cnext; | 
|  | } | 
|  | palette[cnext].next = pencolor; | 
|  | (*argcp)--; | 
|  | (*argvp)++; | 
|  | } | 
|  |  | 
|  | void readin(void){ | 
|  | int i, t; | 
|  | struct val *temp; | 
|  |  | 
|  | if(absf==1) { | 
|  | if(xd.xlbf) | 
|  | absbot = xd.xlb; | 
|  | else if(xd.xf==log10) | 
|  | absbot = 1; | 
|  | } | 
|  | for(;;) { | 
|  | temp = (struct val *)realloc((char*)xx, | 
|  | (unsigned)(n+ovlay)*sizeof(struct val)); | 
|  | if(temp==0) | 
|  | return; | 
|  | xx = temp; | 
|  | if(absf) | 
|  | xx[n].xv = n*dx/ovlay + absbot; | 
|  | else | 
|  | if(!getfloat(&xx[n].xv)) | 
|  | return; | 
|  | t = 0;	/* silence compiler */ | 
|  | for(i=0;i<ovlay;i++) { | 
|  | xx[n+i].xv = xx[n].xv; | 
|  | if(!getfloat(&xx[n+i].yv)) | 
|  | return; | 
|  | xx[n+i].lblptr = -1; | 
|  | t = getstring(); | 
|  | if(t>0) | 
|  | xx[n+i].lblptr = copystring(t); | 
|  | if(t<0 && i+1<ovlay) | 
|  | return; | 
|  | } | 
|  | n += ovlay; | 
|  | if(t<0) | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | void transpose(void){ | 
|  | int i; | 
|  | float f; | 
|  | struct xy t; | 
|  | if(!transf) | 
|  | return; | 
|  | t = xd; xd = yd; yd = t; | 
|  | for(i= 0;i<n;i++) { | 
|  | f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f; | 
|  | } | 
|  | } | 
|  |  | 
|  | int copystring(int k){ | 
|  | char *temp; | 
|  | int i; | 
|  | int q; | 
|  |  | 
|  | temp = realloc(labels,(unsigned)(labelsiz+1+k)); | 
|  | if(temp==0) | 
|  | return(0); | 
|  | labels = temp; | 
|  | q = labelsiz; | 
|  | for(i=0;i<=k;i++) | 
|  | labels[labelsiz++] = labbuf[i]; | 
|  | return(q); | 
|  | } | 
|  |  | 
|  | float modceil(float f, float t){ | 
|  |  | 
|  | t = fabs(t); | 
|  | return(ceil(f/t)*t); | 
|  | } | 
|  |  | 
|  | float | 
|  | modfloor(float f, float t){ | 
|  | t = fabs(t); | 
|  | return(floor(f/t)*t); | 
|  | } | 
|  |  | 
|  | void getlim(struct xy *p, struct val *v){ | 
|  | int i; | 
|  |  | 
|  | i = 0; | 
|  | do { | 
|  | if(!p->xlbf && p->xlb>v[i].xv) | 
|  | p->xlb = v[i].xv; | 
|  | if(!p->xubf && p->xub<v[i].xv) | 
|  | p->xub = v[i].xv; | 
|  | i++; | 
|  | } while(i < n); | 
|  | } | 
|  |  | 
|  | void setlim(struct xy *p){ | 
|  | float t,delta,sign; | 
|  | struct z z; | 
|  | int mark[50]; | 
|  | float lb,ub; | 
|  | int lbf,ubf; | 
|  |  | 
|  | lb = p->xlb; | 
|  | ub = p->xub; | 
|  | delta = ub-lb; | 
|  | if(p->xqf) { | 
|  | if(delta*p->xquant <=0 ) | 
|  | badarg(); | 
|  | return; | 
|  | } | 
|  | sign = 1; | 
|  | lbf = p->xlbf; | 
|  | ubf = p->xubf; | 
|  | if(delta < 0) { | 
|  | sign = -1; | 
|  | t = lb; | 
|  | lb = ub; | 
|  | ub = t; | 
|  | t = lbf; | 
|  | lbf = ubf; | 
|  | ubf = t; | 
|  | } | 
|  | else if(delta == 0) { | 
|  | if(ub > 0) { | 
|  | ub = 2*ub; | 
|  | lb = 0; | 
|  | } | 
|  | else | 
|  | if(lb < 0) { | 
|  | lb = 2*lb; | 
|  | ub = 0; | 
|  | } | 
|  | else { | 
|  | ub = 1; | 
|  | lb = -1; | 
|  | } | 
|  | } | 
|  | if(p->xf==log10 && lb>0 && ub>lb) { | 
|  | z = setloglim(lbf,ubf,lb,ub); | 
|  | p->xlb = z.lb; | 
|  | p->xub = z.ub; | 
|  | p->xmult *= z.mult; | 
|  | p->xquant = z.quant; | 
|  | if(setmark(mark,p)<2) { | 
|  | p->xqf = lbf = ubf = 1; | 
|  | lb = z.lb; ub = z.ub; | 
|  | } else | 
|  | return; | 
|  | } | 
|  | z = setlinlim(lbf,ubf,lb,ub); | 
|  | if(sign > 0) { | 
|  | p->xlb = z.lb; | 
|  | p->xub = z.ub; | 
|  | } else { | 
|  | p->xlb = z.ub; | 
|  | p->xub = z.lb; | 
|  | } | 
|  | p->xmult *= z.mult; | 
|  | p->xquant = sign*z.quant; | 
|  | } | 
|  |  | 
|  | struct z | 
|  | setloglim(int lbf, int ubf, float lb, float ub){ | 
|  | float r,s,t; | 
|  | struct z z; | 
|  |  | 
|  | for(s=1; lb*s<1; s*=10) ; | 
|  | lb *= s; | 
|  | ub *= s; | 
|  | for(r=1; 10*r<=lb; r*=10) ; | 
|  | for(t=1; t<ub; t*=10) ; | 
|  | z.lb = !lbf ? r : lb; | 
|  | z.ub = !ubf ? t : ub; | 
|  | if(ub/lb<100) { | 
|  | if(!lbf) { | 
|  | if(lb >= 5*z.lb) | 
|  | z.lb *= 5; | 
|  | else if(lb >= 2*z.lb) | 
|  | z.lb *= 2; | 
|  | } | 
|  | if(!ubf) { | 
|  | if(ub*5 <= z.ub) | 
|  | z.ub /= 5; | 
|  | else if(ub*2 <= z.ub) | 
|  | z.ub /= 2; | 
|  | } | 
|  | } | 
|  | z.mult = s; | 
|  | z.quant = r; | 
|  | return(z); | 
|  | } | 
|  |  | 
|  | struct z | 
|  | setlinlim(int lbf, int ubf, float xlb, float xub){ | 
|  | struct z z; | 
|  | float r,s,delta; | 
|  | float ub,lb; | 
|  |  | 
|  | loop: | 
|  | ub = xub; | 
|  | lb = xlb; | 
|  | delta = ub - lb; | 
|  | /*scale up by s, a power of 10, so range (delta) exceeds 1*/ | 
|  | /*find power of 10 quantum, r, such that delta/10<=r<delta*/ | 
|  | r = s = 1; | 
|  | while(delta*s < 10) | 
|  | s *= 10; | 
|  | delta *= s; | 
|  | while(10*r < delta) | 
|  | r *= 10; | 
|  | lb *= s; | 
|  | ub *= s; | 
|  | /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/ | 
|  | if(r>=delta/2) | 
|  | r /= 2; | 
|  | else if(r<delta/5) | 
|  | r *= 2; | 
|  | z.ub = ubf? ub: modceil(ub,r); | 
|  | z.lb = lbf? lb: modfloor(lb,r); | 
|  | if(!lbf && z.lb<=r && z.lb>0) { | 
|  | xlb = 0; | 
|  | goto loop; | 
|  | } | 
|  | else if(!ubf && z.ub>=-r && z.ub<0) { | 
|  | xub = 0; | 
|  | goto loop; | 
|  | } | 
|  | z.quant = r; | 
|  | z.mult = s; | 
|  | return(z); | 
|  | } | 
|  |  | 
|  | void scale(struct xy *p){ | 
|  | float edge; | 
|  |  | 
|  | setlim(p); | 
|  | edge = top-bot; | 
|  | p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb)); | 
|  | p->xbot = bot + edge*p->xoff; | 
|  | p->xtop = p->xbot + (top-bot)*p->xsize; | 
|  | p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5; | 
|  | } | 
|  |  | 
|  | void equilibrate(struct xy *p, struct xy *q){ | 
|  | if(p->xlbf||	/* needn't test xubf; it implies xlbf*/ | 
|  | q->xubf&&q->xlb>q->xub) | 
|  | return; | 
|  | if(p->xlb>q->xlb) { | 
|  | p->xlb = q->xlb; | 
|  | p->xlbf = q->xlbf; | 
|  | } | 
|  | if(p->xub<q->xub) { | 
|  | p->xub = q->xub; | 
|  | p->xubf = q->xubf; | 
|  | } | 
|  | } | 
|  |  | 
|  | void axes(void){ | 
|  | int i; | 
|  | int mark[50]; | 
|  | int xn, yn; | 
|  | if(gridf==0) | 
|  | return; | 
|  |  | 
|  | line(xd.xbot,yd.xbot,xd.xtop,yd.xbot); | 
|  | vec(xd.xtop,yd.xtop); | 
|  | vec(xd.xbot,yd.xtop); | 
|  | vec(xd.xbot,yd.xbot); | 
|  |  | 
|  | xn = setmark(mark,&xd); | 
|  | for(i=0; i<xn; i++) { | 
|  | if(gridf==2) | 
|  | line(mark[i],yd.xbot,mark[i],yd.xtop); | 
|  | if(gridf==1) { | 
|  | line(mark[i],yd.xbot,mark[i],yd.xbot+tick); | 
|  | line(mark[i],yd.xtop-tick,mark[i],yd.xtop); | 
|  | } | 
|  | } | 
|  | yn = setmark(mark,&yd); | 
|  | for(i=0; i<yn; i++) { | 
|  | if(gridf==2) | 
|  | line(xd.xbot,mark[i],xd.xtop,mark[i]); | 
|  | if(gridf==1) { | 
|  | line(xd.xbot,mark[i],xd.xbot+tick,mark[i]); | 
|  | line(xd.xtop-tick,mark[i],xd.xtop,mark[i]); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | int | 
|  | setmark(int *xmark, struct xy *p){ | 
|  | int xn = 0; | 
|  | float x,xl,xu; | 
|  | float q; | 
|  | if(p->xf==log10&&!p->xqf) { | 
|  | for(x=p->xquant; x<p->xub; x*=10) { | 
|  | submark(xmark,&xn,x,p); | 
|  | if(p->xub/p->xlb<=100) { | 
|  | submark(xmark,&xn,2*x,p); | 
|  | submark(xmark,&xn,5*x,p); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | xn = 0; | 
|  | q = p->xquant; | 
|  | if(q>0) { | 
|  | xl = modceil(p->xlb+q/6,q); | 
|  | xu = modfloor(p->xub-q/6,q)+q/2; | 
|  | } else { | 
|  | xl = modceil(p->xub-q/6,q); | 
|  | xu = modfloor(p->xlb+q/6,q)-q/2; | 
|  | } | 
|  | for(x=xl; x<=xu; x+=fabs(p->xquant)) | 
|  | xmark[xn++] = (*p->xf)(x)*p->xa + p->xb; | 
|  | } | 
|  | return(xn); | 
|  | } | 
|  | void submark(int *xmark, int *pxn, float x, struct xy *p){ | 
|  | if(1.001*p->xlb < x && .999*p->xub > x) | 
|  | xmark[(*pxn)++] = log10(x)*p->xa + p->xb; | 
|  | } | 
|  |  | 
|  | void plot(void){ | 
|  | int ix,iy; | 
|  | int i,j; | 
|  | int conn; | 
|  |  | 
|  | for(j=0;j<ovlay;j++) { | 
|  | switch(mode) { | 
|  | case -1: | 
|  | pen(modes[j%(sizeof modes/sizeof *modes-1)+1]); | 
|  | break; | 
|  | case 0: | 
|  | break; | 
|  | default: | 
|  | pen(modes[mode]); | 
|  | } | 
|  | color(palette[pencolor].name); | 
|  | conn = 0; | 
|  | for(i=j; i<n; i+=ovlay) { | 
|  | if(!conv(xx[i].xv,&xd,&ix) || | 
|  | !conv(xx[i].yv,&yd,&iy)) { | 
|  | conn = 0; | 
|  | continue; | 
|  | } | 
|  | if(mode!=0) { | 
|  | if(conn != 0) | 
|  | vec(ix,iy); | 
|  | else | 
|  | move(ix,iy); | 
|  | conn = 1; | 
|  | } | 
|  | conn &= symbol(ix,iy,xx[i].lblptr); | 
|  | } | 
|  | pencolor = palette[pencolor].next; | 
|  | } | 
|  | pen(modes[1]); | 
|  | } | 
|  |  | 
|  | int | 
|  | conv(float xv, struct xy *p, int *ip){ | 
|  | long ix; | 
|  | ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb; | 
|  | if(ix<p->xbot || ix>p->xtop) | 
|  | return(0); | 
|  | *ip = ix; | 
|  | return(1); | 
|  | } | 
|  |  | 
|  | int | 
|  | getfloat(float *p){ | 
|  | int i; | 
|  |  | 
|  | i = scanf("%f",p); | 
|  | return(i==1); | 
|  | } | 
|  |  | 
|  | int | 
|  | getstring(void){ | 
|  | int i; | 
|  | char junk[20]; | 
|  | i = scanf("%1s",labbuf); | 
|  | if(i==-1) | 
|  | return(-1); | 
|  | switch(*labbuf) { | 
|  | default: | 
|  | if(!isdigit((uchar)*labbuf)) { | 
|  | ungetc(*labbuf,stdin); | 
|  | i = scanf("%s",labbuf); | 
|  | break; | 
|  | } | 
|  | case '.': | 
|  | case '+': | 
|  | case '-': | 
|  | ungetc(*labbuf,stdin); | 
|  | return(0); | 
|  | case '"': | 
|  | i = scanf("%[^\"\n]",labbuf); | 
|  | scanf("%[\"]",junk); | 
|  | break; | 
|  | } | 
|  | if(i==-1) | 
|  | return(-1); | 
|  | return(strlen(labbuf)); | 
|  | } | 
|  |  | 
|  | int | 
|  | symbol(int ix, int iy, int k){ | 
|  |  | 
|  | if(symbf==0&&k<0) { | 
|  | if(mode==0) | 
|  | point(ix,iy); | 
|  | return(1); | 
|  | } | 
|  | else { | 
|  | move(ix,iy); | 
|  | text(k>=0?labels+k:plotsymb); | 
|  | move(ix,iy); | 
|  | return(!brkf|k<0); | 
|  | } | 
|  | } | 
|  |  | 
|  | void title(void){ | 
|  | char buf[BSIZ+100]; | 
|  | buf[0] = ' '; | 
|  | buf[1] = ' '; | 
|  | buf[2] = ' '; | 
|  | strcpy(buf+3,titlebuf); | 
|  | if(erasf&&gridf) { | 
|  | axlab('x',&xd,buf); | 
|  | strcat(buf,","); | 
|  | axlab('y',&yd,buf); | 
|  | } | 
|  | move(xd.xbot,yd.xbot-60); | 
|  | text(buf); | 
|  | } | 
|  |  | 
|  | void axlab(char c, struct xy *p, char *b){ | 
|  | char *dir; | 
|  | dir = p->xlb<p->xub? "<=": ">="; | 
|  | sprintf(b+strlen(b), " %g %s %c%s %s %g", p->xlb/p->xmult, | 
|  | dir, c, p->xf==log10?" (log)":"", dir, p->xub/p->xmult); | 
|  | } | 
|  |  | 
|  | void badarg(void){ | 
|  | fprintf(stderr,"graph: error in arguments\n"); | 
|  | closepl(); | 
|  | exits("bad arg"); | 
|  | } |