plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

plot.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 }