9 int xlbf; /*flag:explicit lower bound*/
10 int xubf; /*flag:explicit upper bound*/
11 int xqf; /*flag:explicit quantum*/
12 double (*xf)(double); /*transform function, e.g. log*/
13 float xa,xb; /*scaling coefficients*/
14 float xlb,xub; /*lower and upper bound*/
15 float xquant; /*quantum*/
16 float xoff; /*screen offset fraction*/
17 float xsize; /*screen fraction*/
18 int xbot,xtop; /*screen coords of border*/
19 float xmult; /*scaling constant*/
59 double ident(double x){
64 float lb,ub,mult,quant;
71 ['b'] { "blue", 'b' },
72 ['c'] { "cyan", 'c' },
73 ['g'] { "green", 'g' },
74 ['k'] { "kblack", 'k' },
75 ['m'] { "magenta", 'm' },
77 ['w'] { "white", 'w' },
78 ['y'] { "yellow", 'y' }
82 void init(struct xy *);
83 void setopt(int, char *[]);
86 void getlim(struct xy *, struct val *);
87 void equilibrate(struct xy *, struct xy *);
88 void scale(struct xy *);
89 void limread(struct xy *, int *, char ***);
90 int numb(float *, int *, char ***);
91 void colread(int *, char ***);
93 struct z setloglim(int, int, float, float);
94 struct z setlinlim(int, int, float, float);
96 int setmark(int *, struct xy *);
97 void submark(int *, int *, float, struct xy *);
99 int getfloat(float *);
103 int conv(float, struct xy *, int *);
104 int symbol(int, int, int);
105 void axlab(char, struct xy *, char *);
107 void main(int argc,char *argv[]){
110 range(0,0,4096,4096);
113 xd.xsize = yd.xsize = 1.;
114 xx = (struct val *)malloc((unsigned)sizeof(struct val));
116 labels[labelsiz++] = 0;
122 getlim(&xd,(struct val *)&xx->xv);
123 getlim(&yd,(struct val *)&xx->yv);
125 equilibrate(&xd,&yd);
126 equilibrate(&yd,&xd);
137 void init(struct xy *p){
142 void setopt(int argc, char *argv[]){
146 xd.xlb = yd.xlb = INF;
147 xd.xub = yd.xub = -INF;
150 again: switch(argv[0][0]) {
154 case 'l': /* label for plot */
160 while (*p1++ = *p2++);
164 case 'd': /*disconnected,obsolete option*/
165 case 'm': /*line mode*/
167 if(!numb(&temp,&argc,&argv))
169 if(temp>=sizeof(modes)/sizeof(*modes))
176 if(numb(&temp,&argc,&argv) && temp>=1)
179 case 'a': /*automatic abscissas*/
182 if(!numb(&dx,&argc,&argv))
184 if(numb(&absbot,&argc,&argv))
188 case 's': /*save screen, overlay plot*/
192 case 'g': /*grid style 0 none, 1 ticks, 2 full*/
194 if(!numb(&temp,&argc,&argv))
195 temp = argv[0][1]-'0'; /*for caompatibility*/
200 case 'c': /*character(s) for plotting*/
209 case 't': /*transpose*/
212 case 'e': /*equal scales*/
218 case 'x': /*x limits */
219 limread(&xd,&argc,&argv);
222 limread(&yd,&argc,&argv);
224 case 'h': /*set height of plot */
225 if(!numb(&yd.xsize, &argc,&argv))
228 case 'w': /*set width of plot */
229 if(!numb(&xd.xsize, &argc, &argv))
232 case 'r': /* set offset to right */
233 if(!numb(&xd.xoff, &argc, &argv))
236 case 'u': /*set offset up the screen*/
237 if(!numb(&yd.xoff,&argc,&argv))
240 case 'p': /*pen color*/
241 colread(&argc, &argv);
249 void limread(struct xy *p, int *argcp, char ***argvp){
250 if(*argcp>1 && (*argvp)[1][0]=='l') {
255 if(!numb(&p->xlb,argcp,argvp))
258 if(!numb(&p->xub,argcp,argvp))
261 if(!numb(&p->xquant,argcp,argvp))
267 return '0'<=c && c<='9';
269 numb(float *np, int *argcp, char ***argvp){
274 while((c=(*argvp)[1][0]) == '+')
276 if(!(isdigit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.'))
278 *np = atof((*argvp)[1]);
284 void colread(int *argcp, char ***argvp){
290 n = strlen((*argvp)[1]);
291 if(strspn((*argvp)[1], "bcgkmrwy")!=n)
293 pencolor = cnext = (*argvp)[1][0];
294 for(i=0; i<n-1; i++){
295 c = (unsigned char)(*argvp)[1][i];
296 cnext = (unsigned char)(*argvp)[1][i+1];
297 palette[c].next = cnext;
299 palette[cnext].next = pencolor;
311 else if(xd.xf==log10)
315 temp = (struct val *)realloc((char*)xx,
316 (unsigned)(n+ovlay)*sizeof(struct val));
321 xx[n].xv = n*dx/ovlay + absbot;
323 if(!getfloat(&xx[n].xv))
325 t = 0; /* silence compiler */
326 for(i=0;i<ovlay;i++) {
327 xx[n+i].xv = xx[n].xv;
328 if(!getfloat(&xx[n+i].yv))
333 xx[n+i].lblptr = copystring(t);
343 void transpose(void){
349 t = xd; xd = yd; yd = t;
351 f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f;
355 int copystring(int k){
360 temp = realloc(labels,(unsigned)(labelsiz+1+k));
366 labels[labelsiz++] = labbuf[i];
370 float modceil(float f, float t){
377 modfloor(float f, float t){
379 return(floor(f/t)*t);
382 void getlim(struct xy *p, struct val *v){
387 if(!p->xlbf && p->xlb>v[i].xv)
389 if(!p->xubf && p->xub<v[i].xv)
395 void setlim(struct xy *p){
406 if(delta*p->xquant <=0 )
422 else if(delta == 0) {
437 if(p->xf==log10 && lb>0 && ub>lb) {
438 z = setloglim(lbf,ubf,lb,ub);
443 if(setmark(mark,p)<2) {
444 p->xqf = lbf = ubf = 1;
445 lb = z.lb; ub = z.ub;
449 z = setlinlim(lbf,ubf,lb,ub);
458 p->xquant = sign*z.quant;
462 setloglim(int lbf, int ubf, float lb, float ub){
466 for(s=1; lb*s<1; s*=10) ;
469 for(r=1; 10*r<=lb; r*=10) ;
470 for(t=1; t<ub; t*=10) ;
471 z.lb = !lbf ? r : lb;
472 z.ub = !ubf ? t : ub;
477 else if(lb >= 2*z.lb)
483 else if(ub*2 <= z.ub)
493 setlinlim(int lbf, int ubf, float xlb, float xub){
502 /*scale up by s, a power of 10, so range (delta) exceeds 1*/
503 /*find power of 10 quantum, r, such that delta/10<=r<delta*/
512 /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/
517 z.ub = ubf? ub: modceil(ub,r);
518 z.lb = lbf? lb: modfloor(lb,r);
519 if(!lbf && z.lb<=r && z.lb>0) {
523 else if(!ubf && z.ub>=-r && z.ub<0) {
532 void scale(struct xy *p){
537 p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb));
538 p->xbot = bot + edge*p->xoff;
539 p->xtop = p->xbot + (top-bot)*p->xsize;
540 p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5;
543 void equilibrate(struct xy *p, struct xy *q){
544 if(p->xlbf|| /* needn't test xubf; it implies xlbf*/
545 q->xubf&&q->xlb>q->xub)
564 line(xd.xbot,yd.xbot,xd.xtop,yd.xbot);
565 vec(xd.xtop,yd.xtop);
566 vec(xd.xbot,yd.xtop);
567 vec(xd.xbot,yd.xbot);
569 xn = setmark(mark,&xd);
570 for(i=0; i<xn; i++) {
572 line(mark[i],yd.xbot,mark[i],yd.xtop);
574 line(mark[i],yd.xbot,mark[i],yd.xbot+tick);
575 line(mark[i],yd.xtop-tick,mark[i],yd.xtop);
578 yn = setmark(mark,&yd);
579 for(i=0; i<yn; i++) {
581 line(xd.xbot,mark[i],xd.xtop,mark[i]);
583 line(xd.xbot,mark[i],xd.xbot+tick,mark[i]);
584 line(xd.xtop-tick,mark[i],xd.xtop,mark[i]);
590 setmark(int *xmark, struct xy *p){
594 if(p->xf==log10&&!p->xqf) {
595 for(x=p->xquant; x<p->xub; x*=10) {
596 submark(xmark,&xn,x,p);
597 if(p->xub/p->xlb<=100) {
598 submark(xmark,&xn,2*x,p);
599 submark(xmark,&xn,5*x,p);
606 xl = modceil(p->xlb+q/6,q);
607 xu = modfloor(p->xub-q/6,q)+q/2;
609 xl = modceil(p->xub-q/6,q);
610 xu = modfloor(p->xlb+q/6,q)-q/2;
612 for(x=xl; x<=xu; x+=fabs(p->xquant))
613 xmark[xn++] = (*p->xf)(x)*p->xa + p->xb;
617 void submark(int *xmark, int *pxn, float x, struct xy *p){
618 if(1.001*p->xlb < x && .999*p->xub > x)
619 xmark[(*pxn)++] = log10(x)*p->xa + p->xb;
627 for(j=0;j<ovlay;j++) {
630 pen(modes[j%(sizeof modes/sizeof *modes-1)+1]);
637 color(palette[pencolor].name);
639 for(i=j; i<n; i+=ovlay) {
640 if(!conv(xx[i].xv,&xd,&ix) ||
641 !conv(xx[i].yv,&yd,&iy)) {
652 conn &= symbol(ix,iy,xx[i].lblptr);
654 pencolor = palette[pencolor].next;
660 conv(float xv, struct xy *p, int *ip){
662 ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb;
663 if(ix<p->xbot || ix>p->xtop)
681 i = scanf("%1s",labbuf);
686 if(!isdigit(*labbuf)) {
687 ungetc(*labbuf,stdin);
688 i = scanf("%s",labbuf);
694 ungetc(*labbuf,stdin);
697 i = scanf("%[^\"\n]",labbuf);
703 return(strlen(labbuf));
707 symbol(int ix, int iy, int k){
716 text(k>=0?labels+k:plotsymb);
727 strcpy(buf+3,titlebuf);
733 move(xd.xbot,yd.xbot-60);
737 void axlab(char c, struct xy *p, char *b){
739 dir = p->xlb<p->xub? "<=": ">=";
740 sprintf(b+strlen(b), " %g %s %c%s %s %g", p->xlb/p->xmult,
741 dir, c, p->xf==log10?" (log)":"", dir, p->xub/p->xmult);
745 fprintf(stderr,"graph: error in arguments\n");