]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/graph/graph.c
audiohda: fix syntax error
[plan9front.git] / sys / src / cmd / graph / graph.c
1 #include <u.h>
2 #include <libc.h>
3 #include <stdio.h>
4 #include "iplot.h"
5 #define INF     1.e+37
6 #define F       .25
7
8 struct xy {
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*/
20 } xd,yd;
21 struct val {
22         float xv;
23         float yv;
24         int lblptr;
25 } *xx;
26
27 char *labels;
28 int labelsiz;
29
30 int tick = 50;
31 int top = 4000;
32 int bot = 200;
33 float absbot;
34 int     n;
35 int     erasf = 1;
36 int     gridf = 2;
37 int     symbf = 0;
38 int     absf = 0;
39 int     transf;
40 int     equf;
41 int     brkf;
42 int     ovlay = 1;
43 float   dx;
44 char    *plotsymb;
45
46 #define BSIZ 80
47 char    labbuf[BSIZ];
48 char    titlebuf[BSIZ];
49
50 char *modes[] = {
51         "disconnected",
52         "solid",
53         "dotted",
54         "dotdashed",
55         "shortdashed",
56         "longdashed"
57 };
58 int mode = 1;
59 double ident(double x){
60         return(x);
61 }
62
63 struct z {
64         float lb,ub,mult,quant;
65 };
66
67 struct {
68         char *name;
69         int next;
70 } palette[] = {
71         ['b']   { "blue", 'b' },
72         ['c']   { "cyan", 'c' },
73         ['g']   { "green", 'g' },
74         ['k']   { "kblack", 'k' },
75         ['m']   { "magenta", 'm' },
76         ['r']   { "red", 'r' },
77         ['w']   { "white", 'w' },
78         ['y']   { "yellow", 'y' }
79 };
80 int pencolor = 'k';
81
82 void init(struct xy *);
83 void setopt(int, char *[]);
84 void readin(void);
85 void transpose(void);
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 ***);
92 int copystring(int);
93 struct z setloglim(int, int, float, float);
94 struct z setlinlim(int, int, float, float);
95 void axes(void);
96 int setmark(int *, struct xy *);
97 void submark(int *, int *, float, struct xy *);
98 void plot(void);
99 int getfloat(float *);
100 int getstring(void);
101 void title(void);
102 void badarg(void);
103 int conv(float, struct xy *, int *);
104 int symbol(int, int, int);
105 void axlab(char, struct xy *, char *);
106
107 void main(int argc,char *argv[]){
108
109         openpl();
110         range(0,0,4096,4096);
111         init(&xd);
112         init(&yd);
113         xd.xsize = yd.xsize = 1.;
114         xx = (struct val *)malloc((unsigned)sizeof(struct val));
115         labels = malloc(1);
116         labels[labelsiz++] = 0;
117         setopt(argc,argv);
118         if(erasf)
119                 erase();
120         readin();
121         transpose();
122         getlim(&xd,(struct val *)&xx->xv);
123         getlim(&yd,(struct val *)&xx->yv);
124         if(equf) {
125                 equilibrate(&xd,&yd);
126                 equilibrate(&yd,&xd);
127         }
128         scale(&xd);
129         scale(&yd);
130         axes();
131         title();
132         plot();
133         closepl();
134         exits(0);
135 }
136
137 void init(struct xy *p){
138         p->xf = ident;
139         p->xmult = 1;
140 }
141
142 void setopt(int argc, char *argv[]){
143         char *p1, *p2;
144         float temp;
145
146         xd.xlb = yd.xlb = INF;
147         xd.xub = yd.xub = -INF;
148         while(--argc > 0) {
149                 argv++;
150 again:          switch(argv[0][0]) {
151                 case '-':
152                         argv[0]++;
153                         goto again;
154                 case 'l': /* label for plot */
155                         p1 = titlebuf;
156                         if (argc>=2) {
157                                 argv++;
158                                 argc--;
159                                 p2 = argv[0];
160                                 while (*p1++ = *p2++);
161                         }
162                         break;
163
164                 case 'd':       /*disconnected,obsolete option*/
165                 case 'm': /*line mode*/
166                         mode = 0;
167                         if(!numb(&temp,&argc,&argv))
168                                 break;
169                         if(temp>=sizeof(modes)/sizeof(*modes))
170                                 mode = 1;
171                         else if(temp>=-1)
172                                 mode = temp;
173                         break;
174
175                 case 'o':
176                         if(numb(&temp,&argc,&argv) && temp>=1)
177                                 ovlay = temp;
178                         break;
179                 case 'a': /*automatic abscissas*/
180                         absf = 1;
181                         dx = 1;
182                         if(!numb(&dx,&argc,&argv))
183                                 break;
184                         if(numb(&absbot,&argc,&argv))
185                                 absf = 2;
186                         break;
187
188                 case 's': /*save screen, overlay plot*/
189                         erasf = 0;
190                         break;
191
192                 case 'g': /*grid style 0 none, 1 ticks, 2 full*/
193                         gridf = 0;
194                         if(!numb(&temp,&argc,&argv))
195                                 temp = argv[0][1]-'0';  /*for caompatibility*/
196                         if(temp>=0&&temp<=2)
197                                 gridf = temp;
198                         break;
199
200                 case 'c': /*character(s) for plotting*/
201                         if(argc >= 2) {
202                                 symbf = 1;
203                                 plotsymb = argv[1];
204                                 argv++;
205                                 argc--;
206                         }
207                         break;
208
209                 case 't':       /*transpose*/
210                         transf = 1;
211                         break;
212                 case 'e':       /*equal scales*/
213                         equf = 1;
214                         break;
215                 case 'b':       /*breaks*/
216                         brkf = 1;
217                         break;
218                 case 'x':       /*x limits */
219                         limread(&xd,&argc,&argv);
220                         break;
221                 case 'y':
222                         limread(&yd,&argc,&argv);
223                         break;
224                 case 'h': /*set height of plot */
225                         if(!numb(&yd.xsize, &argc,&argv))
226                                 badarg();
227                         break;
228                 case 'w': /*set width of plot */
229                         if(!numb(&xd.xsize, &argc, &argv))
230                                 badarg();
231                         break;
232                 case 'r': /* set offset to right */
233                         if(!numb(&xd.xoff, &argc, &argv))
234                                 badarg();
235                         break;
236                 case 'u': /*set offset up the screen*/
237                         if(!numb(&yd.xoff,&argc,&argv))
238                                 badarg();
239                         break;
240                 case 'p': /*pen color*/
241                         colread(&argc, &argv);
242                         break;
243                 default:
244                         badarg();
245                 }
246         }
247 }
248
249 void limread(struct xy *p, int *argcp, char ***argvp){
250         if(*argcp>1 && (*argvp)[1][0]=='l') {
251                 (*argcp)--;
252                 (*argvp)++;
253                 p->xf = log10;
254         }
255         if(!numb(&p->xlb,argcp,argvp))
256                 return;
257         p->xlbf = 1;
258         if(!numb(&p->xub,argcp,argvp))
259                 return;
260         p->xubf = 1;
261         if(!numb(&p->xquant,argcp,argvp))
262                 return;
263         p->xqf = 1;
264 }
265
266 isdigit(char c){
267         return '0'<=c && c<='9';
268 }
269 numb(float *np, int *argcp, char ***argvp){
270         char c;
271
272         if(*argcp <= 1)
273                 return(0);
274         while((c=(*argvp)[1][0]) == '+')
275                 (*argvp)[1]++;
276         if(!(isdigit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.'))
277                 return(0);
278         *np = atof((*argvp)[1]);
279         (*argcp)--;
280         (*argvp)++;
281         return(1);
282 }
283
284 void colread(int *argcp, char ***argvp){
285         int c, cnext;
286         int i, n;
287
288         if(*argcp<=1)
289                 return;
290         n = strlen((*argvp)[1]);
291         if(strspn((*argvp)[1], "bcgkmrwy")!=n)
292                 return;
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;
298         }
299         palette[cnext].next = pencolor;
300         (*argcp)--;
301         (*argvp)++;
302 }
303
304 void readin(void){
305         int i, t;
306         struct val *temp;
307
308         if(absf==1) {
309                 if(xd.xlbf)
310                         absbot = xd.xlb;
311                 else if(xd.xf==log10)
312                         absbot = 1;
313         }
314         for(;;) {
315                 temp = (struct val *)realloc((char*)xx,
316                         (unsigned)(n+ovlay)*sizeof(struct val));
317                 if(temp==0)
318                         return;
319                 xx = temp;
320                 if(absf)
321                         xx[n].xv = n*dx/ovlay + absbot;
322                 else
323                         if(!getfloat(&xx[n].xv))
324                                 return;
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))
329                                 return;
330                         xx[n+i].lblptr = -1;
331                         t = getstring();
332                         if(t>0)
333                                 xx[n+i].lblptr = copystring(t);
334                         if(t<0 && i+1<ovlay)
335                                 return;
336                 }
337                 n += ovlay;
338                 if(t<0)
339                         return;
340         }
341 }
342
343 void transpose(void){
344         int i;
345         float f;
346         struct xy t;
347         if(!transf)
348                 return;
349         t = xd; xd = yd; yd = t;
350         for(i= 0;i<n;i++) {
351                 f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f;
352         }
353 }
354
355 int copystring(int k){
356         char *temp;
357         int i;
358         int q;
359
360         temp = realloc(labels,(unsigned)(labelsiz+1+k));
361         if(temp==0)
362                 return(0);
363         labels = temp;
364         q = labelsiz;
365         for(i=0;i<=k;i++)
366                 labels[labelsiz++] = labbuf[i];
367         return(q);
368 }
369
370 float modceil(float f, float t){
371
372         t = fabs(t);
373         return(ceil(f/t)*t);
374 }
375
376 float
377 modfloor(float f, float t){
378         t = fabs(t);
379         return(floor(f/t)*t);
380 }
381
382 void getlim(struct xy *p, struct val *v){
383         int i;
384
385         i = 0;
386         do {
387                 if(!p->xlbf && p->xlb>v[i].xv)
388                         p->xlb = v[i].xv;
389                 if(!p->xubf && p->xub<v[i].xv)
390                         p->xub = v[i].xv;
391                 i++;
392         } while(i < n);
393 }
394
395 void setlim(struct xy *p){
396         float t,delta,sign;
397         struct z z;
398         int mark[50];
399         float lb,ub;
400         int lbf,ubf;
401
402         lb = p->xlb;
403         ub = p->xub;
404         delta = ub-lb;
405         if(p->xqf) {
406                 if(delta*p->xquant <=0 )
407                         badarg();
408                 return;
409         }
410         sign = 1;
411         lbf = p->xlbf;
412         ubf = p->xubf;
413         if(delta < 0) {
414                 sign = -1;
415                 t = lb;
416                 lb = ub;
417                 ub = t;
418                 t = lbf;
419                 lbf = ubf;
420                 ubf = t;
421         }
422         else if(delta == 0) {
423                 if(ub > 0) {
424                         ub = 2*ub;
425                         lb = 0;
426                 } 
427                 else
428                         if(lb < 0) {
429                                 lb = 2*lb;
430                                 ub = 0;
431                         } 
432                         else {
433                                 ub = 1;
434                                 lb = -1;
435                         }
436         }
437         if(p->xf==log10 && lb>0 && ub>lb) {
438                 z = setloglim(lbf,ubf,lb,ub);
439                 p->xlb = z.lb;
440                 p->xub = z.ub;
441                 p->xmult *= z.mult;
442                 p->xquant = z.quant;
443                 if(setmark(mark,p)<2) {
444                         p->xqf = lbf = ubf = 1;
445                         lb = z.lb; ub = z.ub;
446                 } else
447                         return;
448         }
449         z = setlinlim(lbf,ubf,lb,ub);
450         if(sign > 0) {
451                 p->xlb = z.lb;
452                 p->xub = z.ub;
453         } else {
454                 p->xlb = z.ub;
455                 p->xub = z.lb;
456         }
457         p->xmult *= z.mult;
458         p->xquant = sign*z.quant;
459 }
460
461 struct z
462 setloglim(int lbf, int ubf, float lb, float ub){
463         float r,s,t;
464         struct z z;
465
466         for(s=1; lb*s<1; s*=10) ;
467         lb *= s;
468         ub *= s;
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;
473         if(ub/lb<100) {
474                 if(!lbf) {
475                         if(lb >= 5*z.lb)
476                                 z.lb *= 5;
477                         else if(lb >= 2*z.lb)
478                                 z.lb *= 2;
479                 }
480                 if(!ubf) {
481                         if(ub*5 <= z.ub)
482                                 z.ub /= 5;
483                         else if(ub*2 <= z.ub)
484                                 z.ub /= 2;
485                 }
486         }
487         z.mult = s;
488         z.quant = r;
489         return(z);
490 }
491
492 struct z
493 setlinlim(int lbf, int ubf, float xlb, float xub){
494         struct z z;
495         float r,s,delta;
496         float ub,lb;
497
498 loop:
499         ub = xub;
500         lb = xlb;
501         delta = ub - lb;
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*/
504         r = s = 1;
505         while(delta*s < 10)
506                 s *= 10;
507         delta *= s;
508         while(10*r < delta)
509                 r *= 10;
510         lb *= s;
511         ub *= s;
512         /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/
513         if(r>=delta/2)
514                 r /= 2;
515         else if(r<delta/5)
516                 r *= 2;
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) {
520                 xlb = 0;
521                 goto loop;
522         }
523         else if(!ubf && z.ub>=-r && z.ub<0) {
524                 xub = 0;
525                 goto loop;
526         }
527         z.quant = r;
528         z.mult = s;
529         return(z);
530 }
531
532 void scale(struct xy *p){
533         float edge;
534
535         setlim(p);
536         edge = top-bot;
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;
541 }
542
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)
546                 return;
547         if(p->xlb>q->xlb) {
548                 p->xlb = q->xlb;
549                 p->xlbf = q->xlbf;
550         }
551         if(p->xub<q->xub) {
552                 p->xub = q->xub;
553                 p->xubf = q->xubf;
554         }
555 }
556
557 void axes(void){
558         int i;
559         int mark[50];
560         int xn, yn;
561         if(gridf==0)
562                 return;
563
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);
568
569         xn = setmark(mark,&xd);
570         for(i=0; i<xn; i++) {
571                 if(gridf==2)
572                         line(mark[i],yd.xbot,mark[i],yd.xtop);
573                 if(gridf==1) {
574                         line(mark[i],yd.xbot,mark[i],yd.xbot+tick);
575                         line(mark[i],yd.xtop-tick,mark[i],yd.xtop);
576                 }
577         }
578         yn = setmark(mark,&yd);
579         for(i=0; i<yn; i++) {
580                 if(gridf==2)
581                         line(xd.xbot,mark[i],xd.xtop,mark[i]);
582                 if(gridf==1) {
583                         line(xd.xbot,mark[i],xd.xbot+tick,mark[i]);
584                         line(xd.xtop-tick,mark[i],xd.xtop,mark[i]);
585                 }
586         }
587 }
588
589 int
590 setmark(int *xmark, struct xy *p){
591         int xn = 0;
592         float x,xl,xu;
593         float q;
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);
600                         }
601                 }
602         } else {
603                 xn = 0;
604                 q = p->xquant;
605                 if(q>0) {
606                         xl = modceil(p->xlb+q/6,q);
607                         xu = modfloor(p->xub-q/6,q)+q/2;
608                 } else {
609                         xl = modceil(p->xub-q/6,q);
610                         xu = modfloor(p->xlb+q/6,q)-q/2;
611                 }
612                 for(x=xl; x<=xu; x+=fabs(p->xquant))
613                         xmark[xn++] = (*p->xf)(x)*p->xa + p->xb;
614         }
615         return(xn);
616 }
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;
620 }
621
622 void plot(void){
623         int ix,iy;
624         int i,j;
625         int conn;
626
627         for(j=0;j<ovlay;j++) {
628                 switch(mode) {
629                 case -1:
630                         pen(modes[j%(sizeof modes/sizeof *modes-1)+1]);
631                         break;
632                 case 0:
633                         break;
634                 default:
635                         pen(modes[mode]);
636                 }
637                 color(palette[pencolor].name);
638                 conn = 0;
639                 for(i=j; i<n; i+=ovlay) {
640                         if(!conv(xx[i].xv,&xd,&ix) ||
641                            !conv(xx[i].yv,&yd,&iy)) {
642                                 conn = 0;
643                                 continue;
644                         }
645                         if(mode!=0) {
646                                 if(conn != 0)
647                                         vec(ix,iy);
648                                 else
649                                         move(ix,iy);
650                                 conn = 1;
651                         }
652                         conn &= symbol(ix,iy,xx[i].lblptr);
653                 }
654                 pencolor = palette[pencolor].next;
655         }
656         pen(modes[1]);
657 }
658
659 int
660 conv(float xv, struct xy *p, int *ip){
661         long ix;
662         ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb;
663         if(ix<p->xbot || ix>p->xtop)
664                 return(0);
665         *ip = ix;
666         return(1);
667 }
668
669 int
670 getfloat(float *p){
671         int i;
672
673         i = scanf("%f",p);
674         return(i==1);
675 }
676
677 int
678 getstring(void){
679         int i;
680         char junk[20];
681         i = scanf("%1s",labbuf);
682         if(i==-1)
683                 return(-1);
684         switch(*labbuf) {
685         default:
686                 if(!isdigit(*labbuf)) {
687                         ungetc(*labbuf,stdin);
688                         i = scanf("%s",labbuf);
689                         break;
690                 }
691         case '.':
692         case '+':
693         case '-':
694                 ungetc(*labbuf,stdin);
695                 return(0);
696         case '"':
697                 i = scanf("%[^\"\n]",labbuf);
698                 scanf("%[\"]",junk);
699                 break;
700         }
701         if(i==-1)
702                 return(-1);
703         return(strlen(labbuf));
704 }
705
706 int
707 symbol(int ix, int iy, int k){
708
709         if(symbf==0&&k<0) {
710                 if(mode==0)
711                         point(ix,iy);
712                 return(1);
713         } 
714         else {
715                 move(ix,iy);
716                 text(k>=0?labels+k:plotsymb);
717                 move(ix,iy);
718                 return(!brkf|k<0);
719         }
720 }
721
722 void title(void){
723         char buf[BSIZ+100];
724         buf[0] = ' ';
725         buf[1] = ' ';
726         buf[2] = ' ';
727         strcpy(buf+3,titlebuf);
728         if(erasf&&gridf) {
729                 axlab('x',&xd,buf);
730                 strcat(buf,",");
731                 axlab('y',&yd,buf);
732         }
733         move(xd.xbot,yd.xbot-60);
734         text(buf);
735 }
736
737 void axlab(char c, struct xy *p, char *b){
738         char *dir;
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);
742 }
743
744 void badarg(void){
745         fprintf(stderr,"graph: error in arguments\n");
746         closepl();
747         exits("bad arg");
748 }