#include #include #include #include "plot.h" #include void define(char*); void call(char*); void include(char*); int process(Biobuf*); enum{ ARC, BOX, CALL, CFILL, CIRC, CLOSEPL, COLOR, CSPLINE, DEFINE, DISK, DSPLINE, ERASE, FILL, FRAME, FSPLINE, GRADE, IDLE, INCLUDE, LINE, LSPLINE, MOVE, OPENPL, PARABOLA, PEN, PAUSE, POINT, POLY, RANGE, RESTORE, RMOVE, RVEC, SAVE, SBOX, SPLINE, TEXT, VEC, LAST }; struct pcall { char *cc; int numc; } plots[] = { [ARC] "a", 1, [BOX] "bo", 2, [CALL] "ca", 2, [CFILL] "cf", 2, [CIRC] "ci", 2, [CLOSEPL] "cl", 2, [COLOR] "co", 2, [CSPLINE] "cs", 2, [DEFINE] "de", 2, [DISK] "di", 2, [DSPLINE] "ds", 2, [ERASE] "e", 1, [FILL] "fi", 2, [FRAME] "fr", 2, [FSPLINE] "fs", 2, [GRADE] "g", 1, [IDLE] "id", 2, [INCLUDE] "in", 2, [LINE] "li", 2, [LSPLINE] "ls", 2, [MOVE] "m", 1, [OPENPL] "o", 1, [PARABOLA] "par", 3, [PEN] "pe", 2, [PAUSE] "pau", 3, [POINT] "poi", 3, [POLY] "pol", 3, [RANGE] "ra", 2, [RESTORE] "re", 2, [RMOVE] "rm", 2, [RVEC] "rv", 2, [SAVE] "sa", 2, [SBOX] "sb", 2, [SPLINE] "sp", 2, [TEXT] "t", 1, [VEC] "v", 1, [LAST] 0, 0, }; struct pcall *pplots; /* last command read */ #define MAXL 16 struct fcall { char *name; char *stash; } flibr[MAXL]; /* define strings */ struct fcall *fptr = flibr; #define NFSTACK 50 struct fstack{ int peekc; int lineno; char *corebuf; Biobuf *fd; double scale; }fstack[NFSTACK]; /* stack of open input files & defines */ struct fstack *fsp=fstack; #define NARGSTR 8192 char argstr[NARGSTR+1]; /* string arguments */ #define NX 8192 double x[NX]; /* numeric arguments */ #define NPTS 256 int cnt[NPTS]; /* control-polygon vertex counts */ double *pts[NPTS]; /* control-polygon vertex pointers */ void main(int arc, char *arv[]){ char *ap; Biobuf *fd; fd = 0; openpl(""); for (; arc > 1; arc--, arv++) { if (arv[1][0] == '-') { ap = arv[1]; ap++; if (*ap == 'T') continue; if (*ap == 'D') continue; switch (*ap) { case 'd': doublebuffer(); break; case 'e': erase(); continue; case 'C': closepl(); continue; case 'w': ppause(); continue; case 'c': color(ap+1); continue; case 'f': cfill(ap+1); continue; case 'p': pen(ap+1); continue; case 'o': openpl(ap+1); continue; case 'g': grade(atof(ap+1)); continue; default: fprint(2, "%s not allowed as argument\n", ap); exits("usage"); } continue; } if ((fd = Bopen(arv[1], OREAD)) == 0) { perror(arv[1]); fprint(2, "Cannot find file %s\n", arv[1]); continue; } if(!process(fd)) break; Bclose(fsp->fd); } if (fd == 0){ fd = malloc(sizeof *fd); Binit(fd, 0, OREAD); process(fd); } closepl(); exits(0); } int isalpha(int c) { return ('a'<=c && c<='z') || ('A'<=c && c<='Z'); } int isupper(int c) { return 'A'<=c && c<='Z'; } int isdigit(int c) { return '0'<=c && c<='9'; } int ispunct(int c) { return strchr("!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~", c)!=0; } int isspace(int c) { return strchr(" \t\n\v\f\r", c)!=0; } int nextc(void){ int c; Rune r; for(;;){ if(fsp->peekc!=Beof){ c=fsp->peekc; fsp->peekc=Beof; return c; } if(fsp->fd) c=Bgetrune(fsp->fd); else if(*fsp->corebuf){ fsp->corebuf+=chartorune(&r, fsp->corebuf); c=r; }else c=Beof; if(c!=Beof || fsp==fstack) break; if(fsp->fd) Bclose(fsp->fd); --fsp; } if(c=='\n') fsp->lineno++; return c; } /* * Read a string into argstr -- ignores leading spaces * and an optional leading quote-mark */ void strarg(void){ int c; Rune r; int quote=0; char *s=argstr; do c=nextc(); while(c==' ' || c=='\t'); if(c=='\'' || c=='"'){ quote=c; c=nextc(); } r = 0; while(c!='\n' && c!=Beof){ r=c; s+=runetochar(s, &r); c=nextc(); } if(quote && s!=argstr && r==quote) --s; *s='\0'; } /* * Read a floating point number into argstr */ numstring(void){ int ndp=0; int ndig=0; char *s=argstr; int c=nextc(); if(c=='+' || c=='-'){ *s++=c; c=nextc(); } while(isdigit(c) || c=='.'){ if(s!=&argstr[NARGSTR]) *s++=c; if(c=='.') ndp++; else ndig++; c=nextc(); } if(ndp>1 || ndig==0){ fsp->peekc=c; return 0; } if(c=='e' || c=='E'){ if(s!=&argstr[NARGSTR]) *s++=c; c=nextc(); if(c=='+' || c=='-'){ if(s!=&argstr[NARGSTR]) *s++=c; c=nextc(); } if(!isdigit(c)){ fsp->peekc=c; return 0; } while(isdigit(c)){ if(s!=&argstr[NARGSTR]) *s++=c; c=nextc(); } } fsp->peekc=c; *s='\0'; return 1; } /* * Read n numeric arguments, storing them in * x[0], ..., x[n-1] */ void numargs(int n){ int i, c; for(i=0;i!=n;i++){ do{ c=nextc(); }while(strchr(" \t\n", c) || c!='.' && c!='+' && c!='-' && ispunct(c)); fsp->peekc=c; if(!numstring()){ fprint(2, "line %d: number expected\n", fsp->lineno); exits("input error"); } x[i]=atof(argstr)*fsp->scale; } } /* * Read a list of lists of control vertices, storing points in x[.], * pointers in pts[.] and counts in cnt[.] */ void polyarg(void){ int nleft, l, r, c; double **ptsp=pts, *xp=x; int *cntp=cnt; do{ c=nextc(); }while(c==' ' || c=='\t'); if(c=='{'){ l='{'; r='}'; } else{ l=r='\n'; fsp->peekc=c; } nleft=1; *cntp=0; *ptsp=xp; for(;;){ c=nextc(); if(c==r){ if(*cntp){ if(*cntp&1){ fprint(2, "line %d: phase error\n", fsp->lineno); exits("bad input"); } *cntp/=2; if(ptsp==&pts[NPTS]){ fprint(2, "line %d: out of polygons\n", fsp->lineno); exits("exceeded limit"); } *++ptsp=xp; *++cntp=0; } if(--nleft==0) return; } else switch(c){ case Beof: return; case ' ': break; case '\t': break; case '\n': break; case '.': case '+': case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': fsp->peekc=c; if(!numstring()){ BadNumber: fprint(2, "line %d: expected number\n", fsp->lineno); exits("bad input"); } if(xp==&x[NX]){ fprint(2, "line %d: out of space\n", fsp->lineno); exits("exceeded limit"); } *xp++=atof(argstr); ++*cntp; break; default: if(c==l) nleft++; else if(!ispunct(c)){ fsp->peekc=c; return; } } } } process(Biobuf *fd){ char *s; int c; fsp=fstack; fsp->fd=fd; fsp->corebuf=0; fsp->peekc=Beof; fsp->lineno=1; fsp->scale=1.; for(;;){ do c=nextc(); while(c==' ' || c=='\t'); if(c==':'){ do c=nextc(); while(c!='\n' && c!=Beof); if(c==Beof) break; continue; } while(c=='.'){ c=nextc(); if(isdigit(c)){ if(fsp->fd) Bungetc(fsp->fd); else --fsp->corebuf; c='.'; break; } } if(c==Beof) break; if(c=='\n') continue; if(isalpha(c)){ s=argstr; do{ if(isupper(c)) c=tolower(c); if(s!=&argstr[NARGSTR]) *s++=c; c=nextc(); }while(isalpha(c)); fsp->peekc=c; *s='\0'; for(pplots=plots;pplots->cc;pplots++) if(strncmp(argstr, pplots->cc, pplots->numc)==0) break; if(pplots->cc==0){ fprint(2, "line %d, %s unknown\n", fsp->lineno, argstr); exits("bad command"); } } else{ fsp->peekc=c; } if(!pplots){ fprint(2, "line %d, no command!\n", fsp->lineno); exits("no command"); } switch(pplots-plots){ case ARC: numargs(7); rarc(x[0],x[1],x[2],x[3],x[4],x[5],x[6]); break; case BOX: numargs(4); box(x[0], x[1], x[2], x[3]); break; case CALL: strarg(); call(argstr); pplots=0; break; case CFILL: strarg(); cfill(argstr); pplots=0; break; case CIRC: numargs(3); circ(x[0], x[1], x[2]); break; case CLOSEPL: strarg(); closepl(); pplots=0; break; case COLOR: strarg(); color(argstr); pplots=0; break; case CSPLINE: polyarg(); splin(4, cnt, pts); break; case DEFINE: strarg(); define(argstr); pplots=0; break; case DISK: numargs(3); disk(x[0], x[1], x[2]); break; case DSPLINE: polyarg(); splin(3, cnt, pts); break; case ERASE: strarg(); erase(); pplots=0; break; case FILL: polyarg(); fill(cnt, pts); break; case FRAME: numargs(4); frame(x[0], x[1], x[2], x[3]); break; case FSPLINE: polyarg(); splin(1, cnt, pts); break; case GRADE: numargs(1); grade(x[0]); break; case IDLE: strarg(); idle(); pplots=0; break; case INCLUDE: strarg(); include(argstr); pplots=0; break; case LINE: numargs(4); line(x[0], x[1], x[2], x[3]); break; case LSPLINE: polyarg(); splin(2, cnt, pts); break; case MOVE: numargs(2); move(x[0], x[1]); break; case OPENPL: strarg(); openpl(argstr); pplots=0; break; case PARABOLA: numargs(6); parabola(x[0],x[1],x[2],x[3],x[4],x[5]); break; case PAUSE: strarg(); ppause(); pplots=0; break; case PEN: strarg(); pen(argstr); pplots=0; break; case POINT: numargs(2); dpoint(x[0], x[1]); break; case POLY: polyarg(); poly(cnt, pts); break; case RANGE: numargs(4); range(x[0], x[1], x[2], x[3]); break; case RESTORE: strarg(); restore(); pplots=0; break; case RMOVE: numargs(2); rmove(x[0], x[1]); break; case RVEC: numargs(2); rvec(x[0], x[1]); break; case SAVE: strarg(); save(); pplots=0; break; case SBOX: numargs(4); sbox(x[0], x[1], x[2], x[3]); break; case SPLINE: polyarg(); splin(0, cnt, pts); break; case TEXT: strarg(); text(argstr); pplots=0; break; case VEC: numargs(2); vec(x[0], x[1]); break; default: fprint(2, "plot: missing case %d\n", pplots-plots); exits("internal error"); } } return 1; } char *names = 0; char *enames = 0; char *bstash = 0; char *estash = 0; unsigned size = 1024; char *nstash = 0; void define(char *a){ char *ap; short i, j; int curly = 0; ap = a; while(isalpha(*ap))ap++; if(ap == a){ fprint(2,"no name with define\n"); exits("define"); } i = ap - a; if(names+i+1 > enames){ names = malloc((unsigned)512); enames = names + 512; } fptr->name = names; strncpy(names, a,i); names += i; *names++ = '\0'; if(!bstash){ bstash = nstash = malloc(size); estash = bstash + size; } fptr->stash = nstash; while(*ap != '{') if(*ap == '\n'){ if((ap=Brdline(fsp->fd, '\n'))==0){ fprint(2,"unexpected end of file\n"); exits("eof"); } } else ap++; while((j=Bgetc(fsp->fd))!= Beof){ if(j == '{')curly++; else if(j == '}'){ if(curly == 0)break; else curly--; } *nstash++ = j; if(nstash == estash){ free(bstash); size += 1024; bstash = realloc(bstash,size); estash = bstash+size; } } *nstash++ = '\0'; if(fptr++ >= &flibr[MAXL]){ fprint(2,"Too many objects\n"); exits("too many objects"); } } void call(char *a){ char *ap; struct fcall *f; char sav; double SC; ap = a; while(isalpha(*ap))ap++; sav = *ap; *ap = '\0'; for(f=flibr;fname))) break; } if(f == fptr){ fprint(2, "object %s not defined\n",a); exits("undefined"); } *ap = sav; while (isspace(*ap) || *ap == ',') ap++; if (*ap != '\0') SC = atof(ap); else SC = 1.; if(++fsp==&fstack[NFSTACK]){ fprint(2, "input stack overflow\n"); exits("blew stack"); } fsp->peekc=Beof; fsp->lineno=1; fsp->corebuf=f->stash; fsp->fd=0; fsp->scale=fsp[-1].scale*SC; } void include(char *a){ Biobuf *fd; fd=Bopen(a, OREAD); if(fd==0){ perror(a); exits("can't include"); } if(++fsp==&fstack[NFSTACK]){ fprint(2, "input stack overflow\n"); exits("blew stack"); } fsp->peekc=Beof; fsp->lineno=1; fsp->corebuf=0; fsp->fd=fd; }