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