]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/plot/plot.c
a4cd59e2f309b7bb2666860f758606ec73b1dbd3
[plan9front.git] / sys / src / cmd / plot / plot.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "plot.h"
5 #include <draw.h>
6 #include <event.h>
7
8 void    define(char*);
9 void    call(char*);
10 void    include(char*);
11 int     process(Biobuf*);
12 int     server(void);
13
14 enum{
15         ARC,
16         BOX,
17         CALL,
18         CFILL,
19         CIRC,
20         CLOSEPL,
21         COLOR,
22         CSPLINE,
23         DEFINE,
24         DISK,
25         DSPLINE,
26         ERASE,
27         FILL,
28         FRAME,
29         FSPLINE,
30         GRADE,
31         IDLE,
32         INCLUDE,
33         LINE,
34         LSPLINE,
35         MOVE,
36         OPENPL,
37         PARABOLA,
38         PEN,
39         PAUSE,
40         POINT,
41         POLY,
42         RANGE,
43         RESTORE,
44         RMOVE,
45         RVEC,
46         SAVE,
47         SBOX,
48         SPLINE,
49         TEXT,
50         VEC,
51         LAST
52 };
53
54 struct pcall {
55         char    *cc;
56         int     numc;
57 } plots[] = {
58         [ARC]           "a",    1,
59         [BOX]           "bo",   2,
60         [CALL]          "ca",   2,
61         [CFILL]         "cf",   2,
62         [CIRC]          "ci",   2,
63         [CLOSEPL]       "cl",   2,
64         [COLOR]         "co",   2,
65         [CSPLINE]       "cs",   2,
66         [DEFINE]        "de",   2,
67         [DISK]          "di",   2,
68         [DSPLINE]       "ds",   2,
69         [ERASE]         "e",    1,
70         [FILL]          "fi",   2,
71         [FRAME]         "fr",   2,
72         [FSPLINE]       "fs",   2,
73         [GRADE]         "g",    1,
74         [IDLE]          "id",   2,
75         [INCLUDE]       "in",   2,
76         [LINE]          "li",   2,
77         [LSPLINE]       "ls",   2,
78         [MOVE]          "m",    1,
79         [OPENPL]        "o",    1,
80         [PARABOLA]      "par",  3,
81         [PEN]           "pe",   2,
82         [PAUSE]         "pau",  3,
83         [POINT]         "poi",  3,
84         [POLY]          "pol",  3,
85         [RANGE]         "ra",   2,
86         [RESTORE]       "re",   2,
87         [RMOVE]         "rm",   2,
88         [RVEC]          "rv",   2,
89         [SAVE]          "sa",   2,
90         [SBOX]          "sb",   2,
91         [SPLINE]        "sp",   2,
92         [TEXT]          "t",    1,
93         [VEC]           "v",    1,
94         [LAST]          0,      0,
95 };
96
97 struct pcall *pplots;           /* last command read */
98
99 #define MAXL 16
100 struct fcall {
101         char *name;
102         char *stash;
103 } flibr[MAXL];                  /* define strings */
104
105 struct fcall *fptr = flibr;
106
107 #define NFSTACK 50
108 struct fstack{
109         int peekc;
110         int lineno;
111         char *corebuf;
112         Biobuf *fd;
113         double scale;
114 }fstack[NFSTACK];               /* stack of open input files & defines */
115 struct fstack *fsp=fstack;
116
117 #define NARGSTR 8192
118 char argstr[NARGSTR+1];         /* string arguments */
119
120 #define NX      8192
121 double x[NX];                   /* numeric arguments */
122
123 #define NPTS    256
124 int cnt[NPTS];                  /* control-polygon vertex counts */
125 double *pts[NPTS];              /* control-polygon vertex pointers */
126
127 void eresized(int new){
128         if(new && getwindow(display, Refnone) < 0){
129                 fprint(2, "Can't reattach to window: %r\n");
130                 exits("resize");
131         }
132 }
133 char *items[]={
134         "exit",
135         0
136 };
137 Menu menu={items};
138 void
139 main(int arc, char *arv[]){
140         char *ap;
141         Biobuf *bp;
142         int fd;
143         int i;
144         int dflag;
145         char *oflag;
146         Mouse m;
147         bp = 0;
148         fd = dup(0, -1);                /* because openpl will close 0! */
149         dflag=0;
150         oflag="";
151         for(i=1;i!=arc;i++) if(arv[i][0]=='-') switch(arv[i][1]){
152         case 'd': dflag=1; break;
153         case 'o': oflag=arv[i]+2; break;
154         case 's': fd=server(); break;
155         }
156         openpl(oflag);
157         if(dflag) doublebuffer();
158         for (; arc > 1; arc--, arv++) {
159                 if (arv[1][0] == '-') {
160                         ap = arv[1];
161                         ap++;
162                         switch (*ap) {
163                         default:
164                                 fprint(2, "%s not allowed as argument\n", ap);
165                                 exits("usage");
166                         case 'T': break;
167                         case 'D': break;
168                         case 'd': break;
169                         case 'o': break;
170                         case 'W': break;
171                         case 's': break;
172                         case 'e': erase(); break;
173                         case 'C': closepl(); break;
174                         case 'w': ppause(); break;
175                         case 'c': color(ap+1); break;
176                         case 'f': cfill(ap+1); break;
177                         case 'p': pen(ap+1); break;
178                         case 'g': grade(atof(ap+1)); break;
179                         }
180                 }
181                 else if ((bp = Bopen(arv[1], OREAD)) == 0) {
182                         perror(arv[1]);
183                         fprint(2, "Cannot find file %s\n", arv[1]);
184                 }
185                 else if(process(bp)) Bterm(fsp->fd);
186                 else break;
187         }
188         if (bp == 0){
189                 bp = malloc(sizeof *bp);
190                 Binit(bp, fd, OREAD);
191                 process(bp);
192         }
193         closepl();
194         flushimage(display, 1);
195         for(;;){
196                 m=emouse();
197                 if(m.buttons&4 && emenuhit(3, &m, &menu)==0) exits(0);
198         }
199 }
200 int isalpha(int c)
201 {
202         return ('a'<=c && c<='z') || ('A'<=c && c<='Z');
203 }
204 int isupper(int c)
205 {
206         return 'A'<=c && c<='Z';
207 }
208 int isdigit(int c)
209 {
210         return '0'<=c && c<='9';
211 }
212 int ispunct(int c)
213 {
214         return strchr("!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~", c)!=0;
215 }
216 int isspace(int c)
217 {
218         return strchr(" \t\n\v\f\r", c)!=0;
219 }
220 int nextc(void){
221         int c;
222         Rune r;
223         for(;;){
224                 if(fsp->peekc!=Beof){
225                         c=fsp->peekc;
226                         fsp->peekc=Beof;
227                         return c;
228                 }
229                 if(fsp->fd)
230                         c=Bgetrune(fsp->fd);
231                 else if(*fsp->corebuf){
232                         fsp->corebuf+=chartorune(&r, fsp->corebuf);
233                         c=r;
234                 }else
235                         c=Beof;
236                 if(c!=Beof || fsp==fstack) break;
237                 if(fsp->fd) Bterm(fsp->fd);
238                 --fsp;
239         }
240         if(c=='\n') fsp->lineno++;
241         return c;
242 }
243 /*
244  * Read a string into argstr -- ignores leading spaces
245  * and an optional leading quote-mark
246  */
247 void
248 strarg(void){
249         int c;
250         Rune r;
251         int quote=0;
252         char *s=argstr;
253         do
254                 c=nextc();
255         while(c==' ' || c=='\t');
256         if(c=='\'' || c=='"'){
257                 quote=c;
258                 c=nextc();
259         }
260         r = 0;
261         while(c!='\n' && c!=Beof){
262                 r=c;
263                 s+=runetochar(s, &r);
264                 c=nextc();
265         }
266         if(quote && s!=argstr && r==quote) --s;
267         *s='\0';
268 }
269 /*
270  * Read a floating point number into argstr
271  */
272 numstring(void){
273         int ndp=0;
274         int ndig=0;
275         char *s=argstr;
276         int c=nextc();
277         if(c=='+' || c=='-'){
278                 *s++=c;
279                 c=nextc();
280         }
281         while(isdigit(c) || c=='.'){
282                 if(s!=&argstr[NARGSTR]) *s++=c;
283                 if(c=='.') ndp++;
284                 else ndig++;
285                 c=nextc();
286         }
287         if(ndp>1 || ndig==0){
288                 fsp->peekc=c;
289                 return 0;
290         }
291         if(c=='e' || c=='E'){
292                 if(s!=&argstr[NARGSTR]) *s++=c;
293                 c=nextc();
294                 if(c=='+' || c=='-'){
295                         if(s!=&argstr[NARGSTR]) *s++=c;
296                         c=nextc();
297                 }
298                 if(!isdigit(c)){
299                         fsp->peekc=c;
300                         return 0;
301                 }
302                 while(isdigit(c)){
303                         if(s!=&argstr[NARGSTR]) *s++=c;
304                         c=nextc();
305                 }
306         }
307         fsp->peekc=c;
308         *s='\0';
309         return 1;
310 }
311 /*
312  * Read n numeric arguments, storing them in
313  * x[0], ..., x[n-1]
314  */
315 void
316 numargs(int n){
317         int i, c;
318         for(i=0;i!=n;i++){
319                 do{
320                         c=nextc();
321                 }while(strchr(" \t\n", c) || c!='.' && c!='+' && c!='-' && ispunct(c));
322                 fsp->peekc=c;
323                 if(!numstring()){
324                         fprint(2, "line %d: number expected\n", fsp->lineno);
325                         exits("input error");
326                 }
327                 x[i]=atof(argstr)*fsp->scale;
328         }
329 }
330 /*
331  * Read a list of lists of control vertices, storing points in x[.],
332  * pointers in pts[.] and counts in cnt[.]
333  */
334 void
335 polyarg(void){
336         int nleft, l, r, c;
337         double **ptsp=pts, *xp=x;
338         int *cntp=cnt;
339         do{
340                 c=nextc();
341         }while(c==' ' || c=='\t');
342         if(c=='{'){
343                 l='{';
344                 r='}';
345         }
346         else{
347                 l=r='\n';
348                 fsp->peekc=c;
349         }
350         nleft=1;
351         *cntp=0;
352         *ptsp=xp;
353         for(;;){
354                 c=nextc();
355                 if(c==r){
356                         if(*cntp){
357                                 if(*cntp&1){
358                                         fprint(2, "line %d: phase error\n",
359                                                 fsp->lineno);
360                                         exits("bad input");
361                                 }
362                                 *cntp/=2;
363                                 if(ptsp==&pts[NPTS]){
364                                         fprint(2, "line %d: out of polygons\n",
365                                                 fsp->lineno);
366                                         exits("exceeded limit");
367                                 }
368                                 *++ptsp=xp;
369                                 *++cntp=0;
370                         }
371                         if(--nleft==0) return;
372                 }
373                 else switch(c){
374                 case Beof:  return;
375                 case ' ':  break;
376                 case '\t': break;
377                 case '\n': break;
378                 case '.': case '+': case '-':
379                 case '0': case '1': case '2': case '3': case '4':
380                 case '5': case '6': case '7': case '8': case '9':
381                         fsp->peekc=c;
382                         if(!numstring()){
383                                 fprint(2, "line %d: expected number\n", fsp->lineno);
384                                 exits("bad input");
385                         }
386                         if(xp==&x[NX]){
387                                 fprint(2, "line %d: out of space\n", fsp->lineno);
388                                 exits("exceeded limit");
389                         }
390                         *xp++=atof(argstr);
391                         ++*cntp;
392                         break;
393                 default:
394                         if(c==l) nleft++;
395                         else if(!ispunct(c)){
396                                 fsp->peekc=c;
397                                 return;
398                         }
399                 }
400         }
401 }
402
403 process(Biobuf *fd){
404         char *s;
405         int c;
406         fsp=fstack;
407         fsp->fd=fd;
408         fsp->corebuf=0;
409         fsp->peekc=Beof;
410         fsp->lineno=1;
411         fsp->scale=1.;
412         for(;;){
413                 do
414                         c=nextc();
415                 while(c==' ' || c=='\t');
416                 if(c==':'){
417                         do
418                                 c=nextc();
419                         while(c!='\n' && c!=Beof);
420                         if(c==Beof) break;
421                         continue;
422                 }
423                 while(c=='.'){
424                         c=nextc();
425                         if(isdigit(c)){
426                                 if(fsp->fd) Bungetc(fsp->fd);
427                                 else --fsp->corebuf;
428                                 c='.';
429                                 break;
430                         }
431                 }
432                 if(c==Beof) break;
433                 if(c=='\n') continue;
434                 if(isalpha(c)){
435                         s=argstr;
436                         do{
437                                 if(isupper(c)) c=tolower(c);
438                                 if(s!=&argstr[NARGSTR]) *s++=c;
439                                 c=nextc();
440                         }while(isalpha(c));
441                         fsp->peekc=c;
442                         *s='\0';
443                         for(pplots=plots;pplots->cc;pplots++)
444                                 if(strncmp(argstr, pplots->cc, pplots->numc)==0)
445                                         break;
446                         if(pplots->cc==0){
447                                 fprint(2, "line %d, %s unknown\n", fsp->lineno,
448                                         argstr);
449                                 exits("bad command");
450                         }
451                 }
452                 else{
453                         fsp->peekc=c;
454                 }
455                 if(!pplots){
456                         fprint(2, "line %d, no command!\n", fsp->lineno);
457                         exits("no command");
458                 }
459                 switch(pplots-plots){
460                 case ARC:       numargs(7); rarc(x[0],x[1],x[2],x[3],x[4],x[5],x[6]); break;
461                 case BOX:       numargs(4); box(x[0], x[1], x[2], x[3]); break;
462                 case CALL:      strarg();   call(argstr); pplots=0; break;
463                 case CFILL:     strarg();   cfill(argstr); pplots=0; break;
464                 case CIRC:      numargs(3); circ(x[0], x[1], x[2]); break;
465                 case CLOSEPL:   strarg();   closepl(); pplots=0; break;
466                 case COLOR:     strarg();   color(argstr); pplots=0; break;
467                 case CSPLINE:   polyarg();  splin(4, cnt, pts); break;
468                 case DEFINE:    strarg();   define(argstr); pplots=0; break;
469                 case DISK:      numargs(3); plotdisc(x[0], x[1], x[2]); break;
470                 case DSPLINE:   polyarg();  splin(3, cnt, pts); break;
471                 case ERASE:     strarg();   erase(); pplots=0; break;
472                 case FILL:      polyarg();  fill(cnt, pts); break;
473                 case FRAME:     numargs(4); frame(x[0], x[1], x[2], x[3]); break;
474                 case FSPLINE:   polyarg();  splin(1, cnt, pts); break;
475                 case GRADE:     numargs(1); grade(x[0]); break;
476                 case IDLE:      strarg();   idle(); pplots=0; break;
477                 case INCLUDE:   strarg();   include(argstr); pplots=0; break;
478                 case LINE:      numargs(4); plotline(x[0], x[1], x[2], x[3]); break;
479                 case LSPLINE:   polyarg();  splin(2, cnt, pts); break;
480                 case MOVE:      numargs(2); move(x[0], x[1]); break;
481                 case OPENPL:    strarg();   openpl(argstr); pplots=0; break;
482                 case PARABOLA:  numargs(6); parabola(x[0],x[1],x[2],x[3],x[4],x[5]); break;
483                 case PAUSE:     strarg();   ppause(); pplots=0; break;
484                 case PEN:       strarg();   pen(argstr); pplots=0; break;
485                 case POINT:     numargs(2); dpoint(x[0], x[1]); break;
486                 case POLY:      polyarg();  plotpoly(cnt, pts); break;
487                 case RANGE:     numargs(4); range(x[0], x[1], x[2], x[3]); break;
488                 case RESTORE:   strarg();   restore(); pplots=0; break;
489                 case RMOVE:     numargs(2); rmove(x[0], x[1]); break;
490                 case RVEC:      numargs(2); rvec(x[0], x[1]); break;
491                 case SAVE:      strarg();   save(); pplots=0; break;
492                 case SBOX:      numargs(4); sbox(x[0], x[1], x[2], x[3]); break;
493                 case SPLINE:    polyarg();  splin(0, cnt, pts); break;
494                 case TEXT:      strarg();   text(argstr); pplots=0; break;
495                 case VEC:       numargs(2); vec(x[0], x[1]); break;
496                 default:
497                         fprint(2, "plot: missing case %ld\n", pplots-plots);
498                         exits("internal error");
499                 }
500         }
501         return 1;
502 }
503 char *names = 0;
504 char *enames = 0;
505 char *bstash = 0;
506 char *estash = 0;
507 unsigned size = 1024;
508 char *nstash = 0;
509 void define(char *a){
510         char    *ap;
511         short   i, j;
512         int curly = 0;
513         ap = a;
514         while(isalpha(*ap))ap++;
515         if(ap == a){
516                 fprint(2,"no name with define\n");
517                 exits("define");
518         }
519         i = ap - a;
520         if(names+i+1 > enames){
521                 names = malloc((unsigned)512);
522                 enames = names + 512;
523         }
524         fptr->name = names;
525         strncpy(names, a,i);
526         names += i;
527         *names++ = '\0';
528         if(!bstash){
529                 bstash = nstash = malloc(size);
530                 estash = bstash + size;
531         }
532         fptr->stash = nstash;
533         while(*ap != '{')
534                 if(*ap == '\n'){
535                         if((ap=Brdline(fsp->fd, '\n'))==0){
536                                 fprint(2,"unexpected end of file\n");
537                                 exits("eof");
538                         }
539                 }
540                 else ap++;
541         while((j=Bgetc(fsp->fd))!= Beof){
542                 if(j == '{')curly++;
543                 else if(j == '}'){
544                         if(curly == 0)break;
545                         else curly--;
546                 }
547                 *nstash++ = j;
548                 if(nstash == estash){
549                         free(bstash);
550                         size += 1024;
551                         bstash = realloc(bstash,size);
552                         estash = bstash+size;
553                 }
554         }
555         *nstash++ = '\0';
556         if(fptr++ >= &flibr[MAXL]){
557                 fprint(2,"Too many objects\n");
558                 exits("too many objects");
559         }
560 }
561 void call(char *a){
562         char *ap;
563         struct fcall *f;
564         char sav;
565         double SC;
566         ap = a;
567         while(isalpha(*ap))ap++;
568         sav = *ap;
569         *ap = '\0';
570         for(f=flibr;f<fptr;f++){
571                 if (!(strcmp(a, f->name)))
572                         break;
573         }
574         if(f == fptr){
575                 fprint(2, "object %s not defined\n",a);
576                 exits("undefined");
577         }
578         *ap = sav;
579         while (isspace(*ap) || *ap == ',') 
580                 ap++;
581         if (*ap != '\0')
582                 SC = atof(ap);
583         else SC = 1.;
584         if(++fsp==&fstack[NFSTACK]){
585                 fprint(2, "input stack overflow\n");
586                 exits("blew stack");
587         }
588         fsp->peekc=Beof;
589         fsp->lineno=1;
590         fsp->corebuf=f->stash;
591         fsp->fd=0;
592         fsp->scale=fsp[-1].scale*SC;
593 }
594 void include(char *a){
595         Biobuf *fd;
596         fd=Bopen(a, OREAD);
597         if(fd==0){
598                 perror(a);
599                 exits("can't include");
600         }
601         if(++fsp==&fstack[NFSTACK]){
602                 fprint(2, "input stack overflow\n");
603                 exits("blew stack");
604         }
605         fsp->peekc=Beof;
606         fsp->lineno=1;
607         fsp->corebuf=0;
608         fsp->fd=fd;
609 }
610 /*
611  * Doesn't work.  Why?
612  */
613 int server(void){
614         int fd, p[2];
615         char buf[32];
616         pipe(p);
617         fd = create("/srv/plot", 1, 0666);
618         sprint(buf, "%d", p[1]);
619         write(fd, buf, strlen(buf));
620         close(fd);
621         close(p[1]);
622         return p[0];
623 }