Commit Diff


commit - 6e18e03e63942f7b0912bb91d0da02fd493af0af
commit + 4314729ddef28cb619ce97d50f0968ca24c93803
blob - a7f4f517690fc74c497135a2b74ebdc752661740
blob + 36b6fb4a388f02f9c83a441064089da6233a97a6
--- CHANGES
+++ CHANGES
@@ -1,3 +1,8 @@
+April 14, 2004
+
+	add plot, graph at the request of Taj Khattra.
+
+
 April 8, 2004
 
 	speed up ls
blob - /dev/null
blob + d1b6938f26edbcbac3db03b8bafeb71b227f066c (mode 644)
--- /dev/null
+++ src/cmd/graph/graph.c
@@ -0,0 +1,708 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "iplot.h"
+#define	INF	1.e+37
+#define	F	.25
+
+struct xy {
+	int	xlbf;		/*flag:explicit lower bound*/
+	int 	xubf;		/*flag:explicit upper bound*/
+	int	xqf;		/*flag:explicit quantum*/
+	double (*xf)(double);	/*transform function, e.g. log*/
+	float	xa,xb;		/*scaling coefficients*/
+	float	xlb,xub;	/*lower and upper bound*/
+	float	xquant;		/*quantum*/
+	float	xoff;		/*screen offset fraction*/
+	float	xsize;		/*screen fraction*/
+	int	xbot,xtop;	/*screen coords of border*/	
+	float	xmult;		/*scaling constant*/
+} xd,yd;
+struct val {
+	float xv;
+	float yv;
+	int lblptr;
+} *xx;
+
+char *labels;
+int labelsiz;
+
+int tick = 50;
+int top = 4000;
+int bot = 200;
+float absbot;
+int	n;
+int	erasf = 1;
+int	gridf = 2;
+int	symbf = 0;
+int	absf = 0;
+int	transf;
+int	equf;
+int	brkf;
+int	ovlay = 1;
+float	dx;
+char	*plotsymb;
+
+#define BSIZ 80
+char	labbuf[BSIZ];
+char	titlebuf[BSIZ];
+
+char *modes[] = {
+	"disconnected",
+	"solid",
+	"dotted",
+	"dotdashed",
+	"shortdashed",
+	"longdashed"
+};
+int mode = 1;
+double ident(double x){
+	return(x);
+}
+
+struct z {
+	float lb,ub,mult,quant;
+};
+void init(struct xy *);
+void setopt(int, char *[]);
+void readin(void);
+void transpose(void);
+void getlim(struct xy *, struct val *);
+void equilibrate(struct xy *, struct xy *);
+void scale(struct xy *);
+void limread(struct xy *, int *, char ***);
+int numb(float *, int *, char ***);
+int copystring(int);
+struct z setloglim(int, int, float, float);
+struct z setlinlim(int, int, float, float);
+void axes(void);
+int setmark(int *, struct xy *);
+void submark(int *, int *, float, struct xy *);
+void plot(void);
+int getfloat(float *);
+int getstring(void);
+void title(void);
+void badarg(void);
+int conv(float, struct xy *, int *);
+int symbol(int, int, int);
+void axlab(char, struct xy *, char *);
+
+void main(int argc,char *argv[]){
+
+	openpl();
+	range(0,0,4096,4096);
+	init(&xd);
+	init(&yd);
+	xd.xsize = yd.xsize = 1.;
+	xx = (struct val *)malloc((unsigned)sizeof(struct val));
+	labels = malloc(1);
+	labels[labelsiz++] = 0;
+	setopt(argc,argv);
+	if(erasf)
+		erase();
+	readin();
+	transpose();
+	getlim(&xd,(struct val *)&xx->xv);
+	getlim(&yd,(struct val *)&xx->yv);
+	if(equf) {
+		equilibrate(&xd,&yd);
+		equilibrate(&yd,&xd);
+	}
+	scale(&xd);
+	scale(&yd);
+	axes();
+	title();
+	plot();
+	closepl();
+	exits(0);
+}
+
+void init(struct xy *p){
+	p->xf = ident;
+	p->xmult = 1;
+}
+
+void setopt(int argc, char *argv[]){
+	char *p1, *p2;
+	float temp;
+
+	xd.xlb = yd.xlb = INF;
+	xd.xub = yd.xub = -INF;
+	while(--argc > 0) {
+		argv++;
+again:		switch(argv[0][0]) {
+		case '-':
+			argv[0]++;
+			goto again;
+		case 'l': /* label for plot */
+			p1 = titlebuf;
+			if (argc>=2) {
+				argv++;
+				argc--;
+				p2 = argv[0];
+				while (*p1++ = *p2++);
+			}
+			break;
+
+		case 'd':	/*disconnected,obsolete option*/
+		case 'm': /*line mode*/
+			mode = 0;
+			if(!numb(&temp,&argc,&argv))
+				break;
+			if(temp>=sizeof(modes)/sizeof(*modes))
+				mode = 1;
+			else if(temp>=-1)
+				mode = temp;
+			break;
+
+		case 'o':
+			if(numb(&temp,&argc,&argv) && temp>=1)
+				ovlay = temp;
+			break;
+		case 'a': /*automatic abscissas*/
+			absf = 1;
+			dx = 1;
+			if(!numb(&dx,&argc,&argv))
+				break;
+			if(numb(&absbot,&argc,&argv))
+				absf = 2;
+			break;
+
+		case 's': /*save screen, overlay plot*/
+			erasf = 0;
+			break;
+
+		case 'g': /*grid style 0 none, 1 ticks, 2 full*/
+			gridf = 0;
+			if(!numb(&temp,&argc,&argv))
+				temp = argv[0][1]-'0';	/*for caompatibility*/
+			if(temp>=0&&temp<=2)
+				gridf = temp;
+			break;
+
+		case 'c': /*character(s) for plotting*/
+			if(argc >= 2) {
+				symbf = 1;
+				plotsymb = argv[1];
+				argv++;
+				argc--;
+			}
+			break;
+
+		case 't':	/*transpose*/
+			transf = 1;
+			break;
+		case 'e':	/*equal scales*/
+			equf = 1;
+			break;
+		case 'b':	/*breaks*/
+			brkf = 1;
+			break;
+		case 'x':	/*x limits */
+			limread(&xd,&argc,&argv);
+			break;
+		case 'y':
+			limread(&yd,&argc,&argv);
+			break;
+		case 'h': /*set height of plot */
+			if(!numb(&yd.xsize, &argc,&argv))
+				badarg();
+			break;
+		case 'w': /*set width of plot */
+			if(!numb(&xd.xsize, &argc, &argv))
+				badarg();
+			break;
+		case 'r': /* set offset to right */
+			if(!numb(&xd.xoff, &argc, &argv))
+				badarg();
+			break;
+		case 'u': /*set offset up the screen*/
+			if(!numb(&yd.xoff,&argc,&argv))
+				badarg();
+			break;
+		default:
+			badarg();
+		}
+	}
+}
+
+void limread(struct xy *p, int *argcp, char ***argvp){
+	if(*argcp>1 && (*argvp)[1][0]=='l') {
+		(*argcp)--;
+		(*argvp)++;
+		p->xf = log10;
+	}
+	if(!numb(&p->xlb,argcp,argvp))
+		return;
+	p->xlbf = 1;
+	if(!numb(&p->xub,argcp,argvp))
+		return;
+	p->xubf = 1;
+	if(!numb(&p->xquant,argcp,argvp))
+		return;
+	p->xqf = 1;
+}
+
+int
+isdigit(char c){
+	return '0'<=c && c<='9';
+}
+
+int
+numb(float *np, int *argcp, char ***argvp){
+	char c;
+
+	if(*argcp <= 1)
+		return(0);
+	while((c=(*argvp)[1][0]) == '+')
+		(*argvp)[1]++;
+	if(!(isdigit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.'))
+		return(0);
+	*np = atof((*argvp)[1]);
+	(*argcp)--;
+	(*argvp)++;
+	return(1);
+}
+
+void readin(void){
+	int i, t;
+	struct val *temp;
+
+	if(absf==1) {
+		if(xd.xlbf)
+			absbot = xd.xlb;
+		else if(xd.xf==log10)
+			absbot = 1;
+	}
+	for(;;) {
+		temp = (struct val *)realloc((char*)xx,
+			(unsigned)(n+ovlay)*sizeof(struct val));
+		if(temp==0)
+			return;
+		xx = temp;
+		if(absf)
+			xx[n].xv = n*dx/ovlay + absbot;
+		else
+			if(!getfloat(&xx[n].xv))
+				return;
+		t = 0;	/* silence compiler */
+		for(i=0;i<ovlay;i++) {
+			xx[n+i].xv = xx[n].xv;
+			if(!getfloat(&xx[n+i].yv))
+				return;
+			xx[n+i].lblptr = -1;
+			t = getstring();
+			if(t>0)
+				xx[n+i].lblptr = copystring(t);
+			if(t<0 && i+1<ovlay)
+				return;
+		}
+		n += ovlay;
+		if(t<0)
+			return;
+	}
+}
+
+void transpose(void){
+	int i;
+	float f;
+	struct xy t;
+	if(!transf)
+		return;
+	t = xd; xd = yd; yd = t;
+	for(i= 0;i<n;i++) {
+		f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f;
+	}
+}
+
+int copystring(int k){
+	char *temp;
+	int i;
+	int q;
+
+	temp = realloc(labels,(unsigned)(labelsiz+1+k));
+	if(temp==0)
+		return(0);
+	labels = temp;
+	q = labelsiz;
+	for(i=0;i<=k;i++)
+		labels[labelsiz++] = labbuf[i];
+	return(q);
+}
+
+float modceil(float f, float t){
+
+	t = fabs(t);
+	return(ceil(f/t)*t);
+}
+
+float
+modfloor(float f, float t){
+	t = fabs(t);
+	return(floor(f/t)*t);
+}
+
+void getlim(struct xy *p, struct val *v){
+	int i;
+
+	i = 0;
+	do {
+		if(!p->xlbf && p->xlb>v[i].xv)
+			p->xlb = v[i].xv;
+		if(!p->xubf && p->xub<v[i].xv)
+			p->xub = v[i].xv;
+		i++;
+	} while(i < n);
+}
+
+void setlim(struct xy *p){
+	float t,delta,sign;
+	struct z z;
+	int mark[50];
+	float lb,ub;
+	int lbf,ubf;
+
+	lb = p->xlb;
+	ub = p->xub;
+	delta = ub-lb;
+	if(p->xqf) {
+		if(delta*p->xquant <=0 )
+			badarg();
+		return;
+	}
+	sign = 1;
+	lbf = p->xlbf;
+	ubf = p->xubf;
+	if(delta < 0) {
+		sign = -1;
+		t = lb;
+		lb = ub;
+		ub = t;
+		t = lbf;
+		lbf = ubf;
+		ubf = t;
+	}
+	else if(delta == 0) {
+		if(ub > 0) {
+			ub = 2*ub;
+			lb = 0;
+		} 
+		else
+			if(lb < 0) {
+				lb = 2*lb;
+				ub = 0;
+			} 
+			else {
+				ub = 1;
+				lb = -1;
+			}
+	}
+	if(p->xf==log10 && lb>0 && ub>lb) {
+		z = setloglim(lbf,ubf,lb,ub);
+		p->xlb = z.lb;
+		p->xub = z.ub;
+		p->xmult *= z.mult;
+		p->xquant = z.quant;
+		if(setmark(mark,p)<2) {
+			p->xqf = lbf = ubf = 1;
+			lb = z.lb; ub = z.ub;
+		} else
+			return;
+	}
+	z = setlinlim(lbf,ubf,lb,ub);
+	if(sign > 0) {
+		p->xlb = z.lb;
+		p->xub = z.ub;
+	} else {
+		p->xlb = z.ub;
+		p->xub = z.lb;
+	}
+	p->xmult *= z.mult;
+	p->xquant = sign*z.quant;
+}
+
+struct z
+setloglim(int lbf, int ubf, float lb, float ub){
+	float r,s,t;
+	struct z z;
+
+	for(s=1; lb*s<1; s*=10) ;
+	lb *= s;
+	ub *= s;
+	for(r=1; 10*r<=lb; r*=10) ;
+	for(t=1; t<ub; t*=10) ;
+	z.lb = !lbf ? r : lb;
+	z.ub = !ubf ? t : ub;
+	if(ub/lb<100) {
+		if(!lbf) {
+			if(lb >= 5*z.lb)
+				z.lb *= 5;
+			else if(lb >= 2*z.lb)
+				z.lb *= 2;
+		}
+		if(!ubf) {
+			if(ub*5 <= z.ub)
+				z.ub /= 5;
+			else if(ub*2 <= z.ub)
+				z.ub /= 2;
+		}
+	}
+	z.mult = s;
+	z.quant = r;
+	return(z);
+}
+
+struct z
+setlinlim(int lbf, int ubf, float xlb, float xub){
+	struct z z;
+	float r,s,delta;
+	float ub,lb;
+
+loop:
+	ub = xub;
+	lb = xlb;
+	delta = ub - lb;
+	/*scale up by s, a power of 10, so range (delta) exceeds 1*/
+	/*find power of 10 quantum, r, such that delta/10<=r<delta*/
+	r = s = 1;
+	while(delta*s < 10)
+		s *= 10;
+	delta *= s;
+	while(10*r < delta)
+		r *= 10;
+	lb *= s;
+	ub *= s;
+	/*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/
+	if(r>=delta/2)
+		r /= 2;
+	else if(r<delta/5)
+		r *= 2;
+	z.ub = ubf? ub: modceil(ub,r);
+	z.lb = lbf? lb: modfloor(lb,r);
+	if(!lbf && z.lb<=r && z.lb>0) {
+		xlb = 0;
+		goto loop;
+	}
+	else if(!ubf && z.ub>=-r && z.ub<0) {
+		xub = 0;
+		goto loop;
+	}
+	z.quant = r;
+	z.mult = s;
+	return(z);
+}
+
+void scale(struct xy *p){
+	float edge;
+
+	setlim(p);
+	edge = top-bot;
+	p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb));
+	p->xbot = bot + edge*p->xoff;
+	p->xtop = p->xbot + (top-bot)*p->xsize;
+	p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5;
+}
+
+void equilibrate(struct xy *p, struct xy *q){
+	if(p->xlbf||	/* needn't test xubf; it implies xlbf*/
+	   q->xubf&&q->xlb>q->xub)
+		return;
+	if(p->xlb>q->xlb) {
+		p->xlb = q->xlb;
+		p->xlbf = q->xlbf;
+	}
+	if(p->xub<q->xub) {
+		p->xub = q->xub;
+		p->xubf = q->xubf;
+	}
+}
+
+void axes(void){
+	int i;
+	int mark[50];
+	int xn, yn;
+	if(gridf==0)
+		return;
+
+	line(xd.xbot,yd.xbot,xd.xtop,yd.xbot);
+	vec(xd.xtop,yd.xtop);
+	vec(xd.xbot,yd.xtop);
+	vec(xd.xbot,yd.xbot);
+
+	xn = setmark(mark,&xd);
+	for(i=0; i<xn; i++) {
+		if(gridf==2)
+			line(mark[i],yd.xbot,mark[i],yd.xtop);
+		if(gridf==1) {
+			line(mark[i],yd.xbot,mark[i],yd.xbot+tick);
+			line(mark[i],yd.xtop-tick,mark[i],yd.xtop);
+		}
+	}
+	yn = setmark(mark,&yd);
+	for(i=0; i<yn; i++) {
+		if(gridf==2)
+			line(xd.xbot,mark[i],xd.xtop,mark[i]);
+		if(gridf==1) {
+			line(xd.xbot,mark[i],xd.xbot+tick,mark[i]);
+			line(xd.xtop-tick,mark[i],xd.xtop,mark[i]);
+		}
+	}
+}
+
+int
+setmark(int *xmark, struct xy *p){
+	int xn = 0;
+	float x,xl,xu;
+	float q;
+	if(p->xf==log10&&!p->xqf) {
+		for(x=p->xquant; x<p->xub; x*=10) {
+			submark(xmark,&xn,x,p);
+			if(p->xub/p->xlb<=100) {
+				submark(xmark,&xn,2*x,p);
+				submark(xmark,&xn,5*x,p);
+			}
+		}
+	} else {
+		xn = 0;
+		q = p->xquant;
+		if(q>0) {
+			xl = modceil(p->xlb+q/6,q);
+			xu = modfloor(p->xub-q/6,q)+q/2;
+		} else {
+			xl = modceil(p->xub-q/6,q);
+			xu = modfloor(p->xlb+q/6,q)-q/2;
+		}
+		for(x=xl; x<=xu; x+=fabs(p->xquant))
+			xmark[xn++] = (*p->xf)(x)*p->xa + p->xb;
+	}
+	return(xn);
+}
+void submark(int *xmark, int *pxn, float x, struct xy *p){
+	if(1.001*p->xlb < x && .999*p->xub > x)
+		xmark[(*pxn)++] = log10(x)*p->xa + p->xb;
+}
+
+void plot(void){
+	int ix,iy;
+	int i,j;
+	int conn;
+
+	for(j=0;j<ovlay;j++) {
+		switch(mode) {
+		case -1:
+			pen(modes[j%(sizeof modes/sizeof *modes-1)+1]);
+			break;
+		case 0:
+			break;
+		default:
+			pen(modes[mode]);
+		}
+		conn = 0;
+		for(i=j; i<n; i+=ovlay) {
+			if(!conv(xx[i].xv,&xd,&ix) ||
+			   !conv(xx[i].yv,&yd,&iy)) {
+				conn = 0;
+				continue;
+			}
+			if(mode!=0) {
+				if(conn != 0)
+					vec(ix,iy);
+				else
+					move(ix,iy);
+				conn = 1;
+			}
+			conn &= symbol(ix,iy,xx[i].lblptr);
+		}
+	}
+	pen(modes[1]);
+}
+
+int
+conv(float xv, struct xy *p, int *ip){
+	long ix;
+	ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb;
+	if(ix<p->xbot || ix>p->xtop)
+		return(0);
+	*ip = ix;
+	return(1);
+}
+
+int
+getfloat(float *p){
+	int i;
+
+	i = scanf("%f",p);
+	return(i==1);
+}
+int
+getstring(void){
+	int i;
+	char junk[20];
+	i = scanf("%1s",labbuf);
+	if(i==-1)
+		return(-1);
+	switch(*labbuf) {
+	default:
+		if(!isdigit(*labbuf)) {
+			ungetc(*labbuf,stdin);
+			i = scanf("%s",labbuf);
+			break;
+		}
+	case '.':
+	case '+':
+	case '-':
+		ungetc(*labbuf,stdin);
+		return(0);
+	case '"':
+		i = scanf("%[^\"\n]",labbuf);
+		scanf("%[\"]",junk);
+		break;
+	}
+	if(i==-1)
+		return(-1);
+	return(strlen(labbuf));
+}
+
+int
+symbol(int ix, int iy, int k){
+
+	if(symbf==0&&k<0) {
+		if(mode==0)
+			point(ix,iy);
+		return(1);
+	} 
+	else {
+		move(ix,iy);
+		text(k>=0?labels+k:plotsymb);
+		move(ix,iy);
+		return(!brkf|k<0);
+	}
+}
+
+void title(void){
+	char buf[BSIZ+100];
+	buf[0] = ' ';
+	buf[1] = ' ';
+	buf[2] = ' ';
+	strcpy(buf+3,titlebuf);
+	if(erasf&&gridf) {
+		axlab('x',&xd,buf);
+		strcat(buf,",");
+		axlab('y',&yd,buf);
+	}
+	move(xd.xbot,yd.xbot-60);
+	text(buf);
+}
+
+void axlab(char c, struct xy *p, char *b){
+	char *dir;
+	dir = p->xlb<p->xub? "<=": ">=";
+	sprintf(b+strlen(b), " %g %s %c%s %s %g", p->xlb/p->xmult,
+		dir, c, p->xf==log10?" (log)":"", dir, p->xub/p->xmult);
+}
+
+void badarg(void){
+	fprintf(stderr,"graph: error in arguments\n");
+	closepl();
+	exits("bad arg");
+}
blob - /dev/null
blob + b6cd50bc2709176d35fe26a10cb100e46873a468 (mode 644)
--- /dev/null
+++ src/cmd/graph/iplot.h
@@ -0,0 +1,39 @@
+#define arc(_x,_y,_X,_Y,_u,_v,_r)  printf("a %d %d %d %d %d %d %d\n",_x,_y,_X,_Y,_u,_v,_r)
+#define box(_x,_y,_X,_Y)  printf("bo %d %d %d %d\n", _x,_y,_X,_Y)
+#define bspline(_num,_ff) {printf("bs {\n"); putnum(_num,_ff); printf("}\n");}
+#define call(_sname,_x)  printf("ca %s %d\n", _sname,_x)
+#define cfill(_s)  printf("cf %s\n", _s)
+#define circle(_x,_y,_r)  printf("ci %d %d %d\n", _x,_y,_r)
+#define closepl()  printf("cl\n")
+#define color(_s)  printf("co %s\n", _s)
+#define cspline(_num,_ff) {printf("cs {\n"); putnum(_num,_ff); printf("}\n");}
+#define pdefine(_sname, _str)  printf("de %s {\n%s\n",_sname, _str)
+#define dspline(_num,_ff) {printf("ds {\n");putnum(_num,_ff);printf("}\n");}
+#define erase() printf("e\n")
+#define ffill(_s)  printf("ff %s\n", _s)
+#define fill(_num,_ff)  {printf("fi {\n"); putnum(_num,_ff); printf("}\n");}
+#define fpoly(_s)  printf("fp %s\n", _s)
+#define frame(_x,_y,_X,_Y)  printf("fr %g %g %g %g\n", _x,_y,_X,_Y)
+#define fspline(_s)  printf("fs %s\n", _s)
+#define grade(_x)  printf("g %d\n", _x)
+#define idle()
+#define line(_x1,_y1,_x2,_y2)  printf("li %d %d %d %d\n", _x1,_y1,_x2,_y2)
+#define lspline(_num,_ff) {printf("ls {\n"); putnum(_num,_ff); printf("}\n");}
+#define move(_x, _y)  printf("m %d %d\n", _x, _y)
+#define openpl()  printf("o\n")
+#define parabola(_x,_y,_X,_Y,_u,_v)  printf("\npa %d %d %d %d %d %d\n", _x,_y,_X,_Y,_u,_v)
+#define pen(_s)  printf("pe %s\n", _s)
+#define point(_x,_y)  printf("poi %d %d\n", _x,_y)
+#define poly(_num,_ff)  {printf("pol {\n"); putnum(_num,_ff); printf("}\n");}
+#define ppause() printf("pp\n")
+#define range(_x,_y,_X,_Y)  printf("ra %d %d %d %d\n", _x,_y,_X,_Y)
+#define restore() printf("re\n")
+#define rmove(_x,_y)  printf("rm %d %d\n", _x,_y)
+#define rvec(_x,_y)  printf("rv %d %d\n", _x,_y)
+#define save() printf( "sa\n")
+#define sbox(_x,_y,_X,_Y)  printf("sb %d %d %d %d\n", _x,_y,_X,_Y)
+#define spline(_num,_ff)  {printf("sp {\n"); putnum(_num,_ff); printf("}\n");}
+#define text(_s)  {if(*(_s) == ' ')printf("t \"%s\"\n",_s); else printf("t %s\n", _s); }
+#define vec(_x,_y)  printf("v %d %d\n", _x,_y)
+void putnum(int [], double *[]);
+char *whoami(void);
blob - /dev/null
blob + 4a45add104c46a54f8a0e4987600459da7e3616f (mode 644)
--- /dev/null
+++ src/cmd/graph/mkfile
@@ -0,0 +1,9 @@
+PLAN9=../../..
+<$PLAN9/src/mkhdr
+
+TARG=graph
+OFILES=graph.$O\
+	subr.$O\
+	whoami.$O\
+
+<$PLAN9/src/mkone
blob - /dev/null
blob + 9531523d67a6d719a8b7fb6976891a5094509098 (mode 644)
--- /dev/null
+++ src/cmd/graph/subr.c
@@ -0,0 +1,19 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "iplot.h"
+void putnum(int num[], double *ff[]){
+	double **fp, *xp;
+	int *np, n,i;
+	np = num;
+	fp = ff;
+	while( (n = *np++)){
+		xp = *fp++;
+		printf("{ ");
+		for(i=0; i<n;i++){
+			printf("%g %g ",*xp, *(xp+1));
+			if(i&1)printf("\n");
+		}
+		printf("}\n");
+	}
+}
blob - /dev/null
blob + 5371dc5daba923a3ba2bda07a2378bdf284a6788 (mode 644)
--- /dev/null
+++ src/cmd/graph/whoami.c
@@ -0,0 +1,5 @@
+#include "iplot.h"
+char *
+whoami(void){
+	return("general");
+}
blob - /dev/null
blob + 4654bc856bb52d04a231fc1494377fefcb68e977 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/box.c
@@ -0,0 +1,8 @@
+#include "mplot.h"
+void box(double x0, double y0, double x1, double y1){
+	move(x0, y0);
+	vec(x0, y1);
+	vec(x1, y1);
+	vec(x1, y0);
+	vec(x0, y0);
+}
blob - /dev/null
blob + 8f700c7fcc5f3cde5ab73b29d338dc481b1ae410 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/cfill.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void cfill(char *s){
+	int k=bcolor(s);
+	if(k>=0) e1->backgr=k;
+}
blob - /dev/null
blob + 53337117c8f2d28deb1d827ed967ffe35a10c23a (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/circ.c
@@ -0,0 +1,12 @@
+#include "mplot.h"
+void circ(double xc, double yc, double r){
+	Point p;
+	int rad;
+	p.x=SCX(xc);
+	p.y=SCY(yc);
+	if (r < 0) 
+		rad=SCR(-r);
+	else
+		rad=SCR(r);
+	ellipse(screen, p, rad, rad, 0, getcolor(e1->foregr), ZP);
+}
blob - /dev/null
blob + b7a8c99a1ee8d073c31ea0b5f1e76d4fb3eb58d9 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/closepl.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+void closepl(void){
+	m_finish();
+}
blob - /dev/null
blob + bd9be4ea966651f1f5e86872bdbea3bc3bc2d8f8 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/color.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+void color(char *s){
+	e1->foregr=bcolor(s);
+}
blob - /dev/null
blob + 47b39012b60ac3c51dd4a663cf63207e9239cab8 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/disk.c
@@ -0,0 +1,12 @@
+#include "mplot.h"
+void plotdisc(double xc, double yc, double r){
+	Point p;
+	int rad;
+	p.x=SCX(xc);
+	p.y=SCY(yc);
+	if (r < 0) 
+		rad=SCR(-r);
+	else
+		rad=SCR(r);
+	fillellipse(screen, p, rad, rad, getcolor(e1->foregr), ZP);
+}
blob - /dev/null
blob + 485894fd31206ebaba19db3e03862a8234aa260e (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/doublebuffer.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+void doublebuffer(void){
+	m_dblbuf();
+}
blob - /dev/null
blob + 7d5b6ff877f35842aca769446e3c670eb699cc3e (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/dpoint.c
@@ -0,0 +1,6 @@
+#include "mplot.h"
+void dpoint(double x, double y){
+	draw(screen, Rect(SCX(x), SCY(y), SCX(x)+1, SCY(y)+1), getcolor(e1->foregr),
+		nil, ZP);
+	move(x, y);
+}
blob - /dev/null
blob + ab9134752940e7fc7ca92aaec90fbef9316c460e (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/erase.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void erase(void){
+	m_swapbuf();
+	m_clrwin(clipminx, clipminy, clipmaxx, clipmaxy, e1->backgr);
+}
blob - /dev/null
blob + a33294e50a991ac26519c727710835d33627b324 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/fill.c
@@ -0,0 +1,167 @@
+/*
+ * fill -- polygon tiler
+ * Updating the edgelist from scanline to scanline could be quicker if no
+ * edges cross:  we can just merge the incoming edges.  If the scan-line
+ * filling routine were a parameter, we could do textured
+ * polygons, polyblt, and other such stuff.
+ */
+#include "mplot.h"
+typedef enum{
+	Odd=1,
+	Nonzero=~0
+}Windrule;
+typedef struct edge Edge;
+struct edge{
+	Point p;	/* point of crossing current scan-line */
+	int maxy;	/* scan line at which to discard edge */
+	int dx;		/* x increment if x fraction<1 */
+	int dx1;	/* x increment if x fraction>=1 */
+	int x;		/* x fraction, scaled by den */
+	int num;	/* x fraction increment for unit y change, scaled by den */
+	int den;	/* x fraction increment for unit x change, scaled by num */
+	int dwind;	/* increment of winding number on passing this edge */
+	Edge *next;	/* next edge on current scanline */
+	Edge *prev;	/* previous edge on current scanline */
+};
+static void insert(Edge *ep, Edge **yp){
+	while(*yp && (*yp)->p.x<ep->p.x) yp=&(*yp)->next;
+	ep->next=*yp;
+	*yp=ep;
+	if(ep->next){
+		ep->prev=ep->next->prev;
+		ep->next->prev=ep;
+		if(ep->prev)
+			ep->prev->next=ep;
+	}
+	else
+		ep->prev=0;
+}
+static void polygon(int cnt[], double *pts[], Windrule w, int v){
+	Edge *edges, *ep, *nextep, **ylist, **eylist, **yp;
+	Point p, q, p0, p1, p10;
+	int i, dy, nbig, y, left, right, wind, nwind, nvert;
+	int *cntp;
+	double **ptsp, *xp;
+	nvert=0;
+	for(cntp=cnt;*cntp;cntp++) nvert+=*cntp;
+	edges=(Edge *)malloc(nvert*sizeof(Edge));
+	if(edges==0){
+	NoSpace:
+		fprintf(stderr, "polygon: no space\n");
+		exits("malloc failed");
+	}
+	ylist=(Edge **)malloc(Dy(screen->r)*sizeof(Edge *));
+	if(ylist==0) goto NoSpace;
+	eylist=ylist+Dy(screen->r);
+	for(yp=ylist;yp!=eylist;yp++) *yp=0;
+	ep=edges;
+	for(cntp=cnt,ptsp=pts;*cntp;cntp++,ptsp++){
+		p.x=SCX((*ptsp)[*cntp*2-2]);
+		p.y=SCY((*ptsp)[*cntp*2-1]);
+		nvert=*cntp;
+		for(xp=*ptsp,i=0;i!=nvert;xp+=2,i++){
+			q=p;
+			p.x=SCX(xp[0]);
+			p.y=SCY(xp[1]);
+			if(p.y==q.y) continue;
+			if(p.y<q.y){
+				p0=p;
+				p1=q;
+				ep->dwind=1;
+			}
+			else{
+				p0=q;
+				p1=p;
+				ep->dwind=-1;
+			}
+			if(p1.y<=screen->r.min.y) continue;
+			if(p0.y>=screen->r.max.y) continue;
+			ep->p=p0;
+			if(p1.y>screen->r.max.y)
+				ep->maxy=screen->r.max.y;
+			else
+				ep->maxy=p1.y;
+			p10=subpt(p1, p0);
+			if(p10.x>=0){
+				ep->dx=p10.x/p10.y;
+				ep->dx1=ep->dx+1;
+			}
+			else{
+				p10.x=-p10.x;
+				ep->dx=-(p10.x/p10.y); /* this nonsense rounds toward zero */
+				ep->dx1=ep->dx-1;
+			}
+			ep->x=0;
+			ep->num=p10.x%p10.y;
+			ep->den=p10.y;
+			if(ep->p.y<screen->r.min.y){
+				dy=screen->r.min.y-ep->p.y;
+				ep->x+=dy*ep->num;
+				nbig=ep->x/ep->den;
+				ep->p.x+=ep->dx1*nbig+ep->dx*(dy-nbig);
+				ep->x%=ep->den;
+				ep->p.y=screen->r.min.y;
+			}
+			insert(ep, ylist+(ep->p.y-screen->r.min.y));
+			ep++;
+		}
+	}
+	left = 0;
+	for(yp=ylist,y=screen->r.min.y;yp!=eylist;yp++,y++){
+		wind=0;
+		for(ep=*yp;ep;ep=nextep){
+			nwind=wind+ep->dwind;
+			if(nwind&w){	/* inside */
+				if(!(wind&w)){
+					left=ep->p.x;
+					if(left<screen->r.min.x) left=screen->r.min.x;
+				}
+			}
+			else if(wind&w){
+				right=ep->p.x;
+				if(right>=screen->r.max.x) right=screen->r.max.x;
+#define BART_BUG_FIXED	/* what goes on here?? -rob */
+#ifdef BART_BUG_FIXED
+				if(right>left)
+					line(screen, Pt(left, y), Pt(right, y), Endsquare, Endsquare, 0, getcolor(v), ZP);
+#else
+				if(right>left){
+					switch(v){
+					default:
+						segment(&screen, Pt(left, y), Pt(right, y),
+							~0, D&~S);
+						segment(&screen, Pt(left, y), Pt(right, y),
+							v, f);
+						break;
+					case 0:
+						segment(&screen, Pt(left, y), Pt(right, y),
+							~0, D&~S);
+						break;
+					case 3:
+						segment(&screen, Pt(left, y), Pt(right, y),
+							v, f);
+						break;
+					}
+				}
+#endif
+			}
+			wind=nwind;
+			nextep=ep->next;
+			if(++ep->p.y!=ep->maxy){
+				ep->x+=ep->num;
+				if(ep->x>=ep->den){
+					ep->x-=ep->den;
+					ep->p.x+=ep->dx1;
+				}
+				else
+					ep->p.x+=ep->dx;
+				insert(ep, yp+1);
+			}
+		}
+	}
+	free((char *)edges);
+	free((char *)ylist);
+}
+void fill(int num[], double *ff[]){
+	polygon(num, ff, Odd, e1->foregr);
+}
blob - /dev/null
blob + bbc37a17c2481cb0358cca0a134ad7ed6379fccf (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/frame.c
@@ -0,0 +1,16 @@
+#include "mplot.h"
+void frame(double xs, double ys, double xf, double yf){
+	register double	osidex, osidey;
+	osidex = e1->sidex;
+	osidey = e1->sidey;
+	e1->left = e0->left + xs * e0->sidex;
+	e1->bottom = e0->bottom + ys * e0->sidey;
+	e1->sidex = (xf-xs)*e0->sidex;
+	e1->sidey = (yf-ys)*e0->sidey;
+	e1->scalex *= (e1->sidex / osidex);
+	e1->scaley *= (e1->sidey / osidey);
+	e1->quantum=e0->quantum/sqrt(e1->scalex*e1->scalex +
+		e1->scaley*e1->scaley);
+	if(e1->quantum < .01)
+		e1->quantum = .01;
+}
blob - /dev/null
blob + 0afe7f40ac918cbbe8f3715f07bd7641ac3f3cca (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/grade.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+void grade(double x){
+	e1->grade = x;
+}
blob - /dev/null
blob + 416d2eea1ddffc42c40121099d66dd0be1b35e13 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/line.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void plotline(double x0, double y0, double x1, double y1){
+	move(x0, y0);
+	vec(x1, y1);
+}
blob - /dev/null
blob + abcb761f9f5d15213edcdc091bbb73d665f2a1a3 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/machdep.c
@@ -0,0 +1,141 @@
+#include "mplot.h"
+Image *offscreen;
+/*
+ * Clear the window from x0, y0 to x1, y1 (inclusive) to color c
+ */
+void m_clrwin(int x0, int y0, int x1, int y1, int c){
+	draw(offscreen, Rect(x0, y0, x1+1, y1+1), getcolor(c), nil, ZP);
+}
+/*
+ * Draw text between pointers p and q with first character centered at x, y.
+ * Use color c.  Centered if cen is non-zero, right-justified if right is non-zero.
+ * Returns the y coordinate for any following line of text.
+ */
+int m_text(int x, int y, char *p, char *q, int c, int cen, int right){
+	Point tsize;
+	USED(c);
+	tsize=stringsize(font, p);
+	if(cen) x -= tsize.x/2;
+	else if(right) x -= tsize.x;
+	stringn(offscreen, Pt(x, y-tsize.y/2), getcolor(c), ZP, font, p, q-p);
+	return y+tsize.y;
+}
+/*
+ * Draw the vector from x0, y0 to x1, y1 in color c.
+ * Clipped by caller
+ */
+void m_vector(int x0, int y0, int x1, int y1, int c){
+	line(offscreen, Pt(x0, y0), Pt(x1, y1), Endsquare, Endsquare, 0, getcolor(c), ZP);
+}
+char *scanint(char *s, int *n){
+	while(*s<'0' || '9'<*s){
+		if(*s=='\0'){
+			fprint(2, "plot: bad -Wxmin,ymin,xmax,ymax\n");
+			exits("bad arg");
+		}
+		s++;
+	}
+	*n=0;
+	while('0'<=*s && *s<='9'){
+		*n=*n*10+*s-'0';
+		s++;
+	}
+	return s;
+}
+char *rdenv(char *name){
+	char *v;
+	int fd, size;
+	fd=open(name, OREAD);
+	if(fd<0) return 0;
+	size=seek(fd, 0, 2);
+	v=malloc(size+1);
+	if(v==0){
+		fprint(2, "Can't malloc: %r\n");
+		exits("no mem");
+	}
+	seek(fd, 0, 0);
+	read(fd, v, size);
+	v[size]=0;
+	close(fd);
+	return v;
+}
+/*
+ * Startup initialization
+ */
+void m_initialize(char *s){
+	static int first=1;
+	int dx, dy;
+	USED(s);
+	if(first){
+		initdraw(0,0,"plot");
+		einit(Emouse);
+		clipminx=mapminx=screen->r.min.x+4;
+		clipminy=mapminy=screen->r.min.y+4;
+		clipmaxx=mapmaxx=screen->r.max.x-5;
+		clipmaxy=mapmaxy=screen->r.max.y-5;
+		dx=clipmaxx-clipminx;
+		dy=clipmaxy-clipminy;
+		if(dx>dy){
+			mapminx+=(dx-dy)/2;
+			mapmaxx=mapminx+dy;
+		}
+		else{
+			mapminy+=(dy-dx)/2;
+			mapmaxy=mapminy+dx;
+		}
+		first=0;
+		offscreen = screen;
+	}
+}
+/*
+ * Clean up when finished
+ */
+void m_finish(void){
+	m_swapbuf();
+}
+void m_swapbuf(void){
+	if(offscreen!=screen)
+		draw(screen, offscreen->r, offscreen, nil, offscreen->r.min);
+	flushimage(display, 1);
+}
+void m_dblbuf(void){
+	if(offscreen==screen){
+		offscreen=allocimage(display, insetrect(screen->r, 4), screen->chan, 0, -1);
+		if(offscreen==0){
+			fprintf(stderr, "Can't double buffer\n");
+			offscreen=screen;
+		}
+	}
+}
+/* Assume colormap entry because
+ * Use cache to avoid repeated allocation.
+ */
+struct{
+	int		v;
+	Image	*i;
+}icache[32];
+
+Image*
+getcolor(int v)
+{
+	Image *i;
+	int j;
+
+	for(j=0; j<nelem(icache); j++)
+		if(icache[j].v==v && icache[j].i!=nil)
+			return icache[j].i;
+
+	i = allocimage(display, Rect(0, 0, 1, 1), RGB24, 1, v);
+	if(i == nil){
+		fprint(2, "plot: can't allocate image for color: %r\n");
+		exits("allocimage");
+	}
+	for(j=0; j<nelem(icache); j++)
+		if(icache[j].i == nil){
+			icache[j].v = v;
+			icache[j].i = i;
+			break;
+		}
+
+	return i;
+}
blob - /dev/null
blob + a73bd6179148dfe3042c0a1d0d975f3f54e350d1 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/mkfile
@@ -0,0 +1,42 @@
+PLAN9=../../../..
+<$PLAN9/src/mkhdr
+
+LIB=../libplot.a
+OFILES=box.$O\
+	cfill.$O\
+	circ.$O\
+	closepl.$O\
+	color.$O\
+	disk.$O\
+	doublebuffer.$O\
+	dpoint.$O\
+	erase.$O\
+	fill.$O\
+	frame.$O\
+	grade.$O\
+	line.$O\
+	machdep.$O\
+	move.$O\
+	openpl.$O\
+	parabola.$O\
+	pen.$O\
+	poly.$O\
+	ppause.$O\
+	pprompt.$O\
+	range.$O\
+	rarc.$O\
+	restore.$O\
+	rmove.$O\
+	rvec.$O\
+	save.$O\
+	sbox.$O\
+	spline.$O\
+	subr.$O\
+	text.$O\
+	vec.$O\
+	whoami.$O\
+
+HFILES=mplot.h\
+
+<$PLAN9/src/mklib
+
blob - /dev/null
blob + 4e60260b6e76a8a8697d0d9371eb17644a66e278 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/move.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void move(double xx, double yy){
+	e1->copyx = xx;	
+	e1->copyy = yy;
+}
blob - /dev/null
blob + 99e27efd1951de61725d0af92abfd068f413313b (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/mplot.h
@@ -0,0 +1,47 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <draw.h>
+#include <event.h>
+#define SCX(A) ((((A) - e1->xmin)*e1->scalex  + e1->left)+.5)
+#define SCY(A) ((((A) - e1->ymin)*e1->scaley + e1->bottom)+.5)
+#define	SCR(A) ((A)*e1->scalex+.5)
+#define unorm(y)	(double)(e1->sidey - y)
+#define	BIGINT	0x3FFFFFFF	/* a large, but valid, int */
+extern struct penvir {
+	double left, bottom;
+	double xmin, ymin;
+	double scalex, scaley;
+	double sidex, sidey;
+	double copyx, copyy;
+	double quantum;
+	double grade;
+	int pgap;
+	double pslant;
+	int pmode, foregr, backgr;
+} *e0, *e1, *esave;
+#define RADIAN 57.3	/* radians per degree */
+struct seg {
+	int x, y, X, Y;
+	char stat;
+};
+
+/*
+ * display parameters
+ */
+int clipminx, clipminy, clipmaxx, clipmaxy;	/* clipping rectangle */
+int mapminx, mapminy, mapmaxx, mapmaxy;		/* centered square */
+/*
+ * Prototypes
+ */
+#include "../plot.h"
+void m_clrwin(int, int, int, int, int);
+void m_finish(void);
+void m_initialize(char *);
+int m_text(int, int, char *, char *, int, int, int);
+void m_vector(int, int, int, int, int);
+void m_swapbuf(void);
+void m_dblbuf(void);
+int bcolor(char *);
+void sscpy(struct penvir *, struct penvir *);
+Image *getcolor(int);
blob - /dev/null
blob + 6972f95681059c193de7404d012e92e0715e42a8 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/openpl.c
@@ -0,0 +1,12 @@
+#include "mplot.h"
+void openpl(char *s){
+	m_initialize(s);
+	e0->left=mapminx;
+	e0->bottom=mapmaxy;
+	e0->sidex=mapmaxx-mapminx;
+	e0->sidey=mapminy-mapmaxy;
+	e0->scalex=e0->sidex;
+	e0->scaley=e0->sidey;
+	sscpy(e0, e1);
+	move(0., 0.);
+}
blob - /dev/null
blob + 212b9c973beb37a1b07f37ee2fb9852b2dc570ef (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/parabola.c
@@ -0,0 +1,32 @@
+#include "mplot.h"
+void parabola(double x0, double y0, double x1, double y1, double xb, double yb){
+	register double x, y, t;
+	double	c0x, c0y, c1x, c1y;
+	double	dt, d2, d1;
+	d1 = sqrt((xb - x0) * (xb - x0) + (yb - y0) * (yb - y0));
+	d2 = sqrt((xb - x1) * (xb - x1) + (yb - y1) * (yb - y1));
+	if (d1 <= e1->quantum || d2 <= e1->quantum) { 
+		plotline(x0, y0, x1, y1); 
+		return; 
+	}
+	c0x = x0 + x1 - 2. * xb; 
+	c1x = 2. * (xb - x0);
+	c0y = y0 + y1 - 2. * yb; 
+	c1y = 2. * (yb - y0);
+	move(x0, y0);
+	dt = e1->quantum / d1;
+	dt /= e1->grade;
+	for (t = dt; t < 0.5; t += dt) {
+		x = (c0x * t + c1x) * t + x0;
+		y = (c0y * t + c1y) * t + y0;
+		vec(x, y);
+	}
+	dt = e1->quantum / d2;
+	dt /= e1->grade;
+	for (; t < 1.0; t += dt) {
+		x = (c0x * t + c1x) * t + x0;
+		y = (c0y * t + c1y) * t + y0;
+		vec(x, y);
+	}
+	vec(x1, y1);
+}
blob - /dev/null
blob + 4e13e5cbf868ada5f22a08e0f0b94c940d02dc78 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/pen.c
@@ -0,0 +1,6 @@
+#include "mplot.h"
+void pen(char *s){
+	/* BUG: NO OP */
+	USED(s);
+	/* was this error:	color(s); */
+}
blob - /dev/null
blob + e3ff734599667aa39bca40ea0d7dc796b269b28d (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/poly.c
@@ -0,0 +1,17 @@
+#include "mplot.h"
+void plotpoly(int num[], double *ff[]){
+	double *xp, *yp, **fp;
+	int i, *n;
+	n = num;
+	fp = ff;
+	while((i = *n++)){
+		xp = *fp++;
+		yp = xp+1;
+		move(*xp, *yp);
+		while(--i){
+			xp += 2;
+			yp += 2;
+			vec(*xp, *yp);
+		}
+	}
+}
blob - /dev/null
blob + 9fb8863d28ca60f812462d1a08182a19f59f2910 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/ppause.c
@@ -0,0 +1,7 @@
+#include "mplot.h"
+void ppause(void){ 
+	char	aa[4]; 
+	fflush(stdout); 
+	read(0, aa, 4);  
+	erase(); 
+}
blob - /dev/null
blob + 2678ead5f0a0e67d3f7db2cb4c1c866fc112b634 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/pprompt.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void
+pprompt(void){
+	fprintf(stderr, ":");
+}
blob - /dev/null
blob + c4485560a154e974b53063738eed4df83b4a3481 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/range.c
@@ -0,0 +1,11 @@
+#include "mplot.h"
+void range(double x0, double y0, double x1, double y1){
+	e1->xmin = x0;
+	e1->ymin = y0;
+	e1->scalex = e1->sidex / (x1 - x0 );
+	e1->scaley = e1->sidey / (y1 - y0 );
+	e1->quantum=e0->quantum/sqrt(e1->scalex*e1->scalex +
+		e1->scaley*e1->scaley);
+	if(e1->quantum < .01)
+		e1->quantum = .01;
+}
blob - /dev/null
blob + 9c8ccf158dcde9e08e1bc4c4034a0b8b47b791ce (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/rarc.c
@@ -0,0 +1,44 @@
+#include "mplot.h"
+/*		arc plotting routine		*/
+/*		from x1,y1 to x2,y2		*/
+/*	with center xc,yc and radius rr	*/
+/*	integrates difference equation		*/
+/*	negative rr draws counterclockwise	*/
+#define PI4 0.7854
+void rarc(double x1, double y1, double x2, double y2, double xc, double yc, double rr){
+	register double dx, dy, a, b;
+	double	ph, dph, rd, xnext;
+	register int	n;
+	dx = x1 - xc;
+	dy = y1 - yc;
+	rd = sqrt(dx * dx + dy * dy);
+	if (rd / e1->quantum < 1.0) { 
+		move(xc, yc); 
+		vec(xc, yc); 
+		return;
+	}
+	dph = acos(1.0 - (e1->quantum / rd));
+	if (dph > PI4) 
+		dph = PI4;
+	ph=atan2((y2-yc),(x2 - xc)) - atan2(dy, dx);
+	if (ph < 0) 
+		ph += 6.2832; 
+	if (rr < 0) 
+		ph = 6.2832 - ph;
+	if (ph < dph) 
+		plotline(x1, y1, x2, y2);
+	else {
+		n = ph / dph; 
+		a = cos(dph); 
+		b = sin(dph); 
+		if (rr < 0) 
+			b = -b;
+		move(x1, y1);
+		while ((n--) >= 0) {
+			xnext = dx * a - dy * b; 
+			dy = dx * b + dy * a; 
+			dx = xnext;
+			vec(dx + xc, dy + yc);
+		}
+	}
+}
blob - /dev/null
blob + 81bdd421d03c60959699041525bc1bacae8e0fa0 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/restore.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void restore(void){
+	e1--;
+	move(e1->copyx, e1->copyy);
+}
blob - /dev/null
blob + faae7a13336aa05c62f1fabd35629abe482964fc (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/rmove.c
@@ -0,0 +1,6 @@
+#include "mplot.h"
+void rmove(double xx, double yy){
+	e1->copyx += xx;
+	e1->copyy += yy;
+	move(e1->copyx, e1->copyy);
+}
blob - /dev/null
blob + 2e23cdbc461e578254559ebd39a61c0310e41cc8 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/rvec.c
@@ -0,0 +1,6 @@
+#include "mplot.h"
+void rvec(double xx, double yy){
+	e1->copyx += xx;
+	e1->copyy += yy;
+	vec(e1->copyx, e1->copyy);
+}
blob - /dev/null
blob + e3dc4058f2b4e2a84cda8bfa7a35d4ba2def2c0f (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/save.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void save(void){ 
+	sscpy(e1, e1 + 1); 
+	e1++; 
+}
blob - /dev/null
blob + 479790b9d820f266c7c5433147fd1b27496cd27d (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/sbox.c
@@ -0,0 +1,13 @@
+#include "mplot.h"
+void sbox(double xx0, double yy0, double xx1, double yy1){
+	int x0=SCX(xx0), y0=SCY(yy0), x1=SCX(xx1), y1=SCY(yy1);
+	int t;
+	if(x1<x0){ t=x0; x0=x1; x1=t; }
+	if(y1<y0){ t=y0; y0=y1; y1=t; }
+	if(x0<clipminx) x0=clipminx;
+	if(y0<clipminy) y0=clipminy;
+	if(x1>clipmaxx) x1=clipmaxx;
+	if(y1>clipmaxy) y1=clipmaxy;
+	if(x1<x0 || y1<y0) return;
+	m_clrwin(x0, y0, x1, y1, e1->backgr);
+}
blob - /dev/null
blob + 8cfa83d7a0c93a5be543aee2815fdf2868995c47 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/spline.c
@@ -0,0 +1,51 @@
+/*
+Produce spline (uniform knots, second order)
+from guiding points
+*/
+#include "mplot.h"
+void splin(int mode, int num[], double *ff[]){
+	int	i,  *np, n;
+	double	xa, ya, xc, yc, *xp, *yp, *xp0, *yp0, *xpe, *ype;
+	double **fp;
+	np = num;
+	fp = ff;
+	while((n = *np++)){
+		xp = *fp++; 
+		yp = xp + 1; 
+		xp0 = xp; 
+		yp0 = yp;
+		xpe = xp0 + 2 * (n - 1); 
+		ype = yp0 + 2 * (n - 1);
+		if (n < 3) { 
+			plotline(*xp, *yp, *(xp + 2), *(yp + 2)); 
+			continue;
+		}
+		if (mode == 4) {	/*closed curve*/
+			xa = 0.5 * (*xpe + *(xpe - 2)); 
+			xc = 0.5 * (*xpe + *xp0);
+			ya = 0.5 * (*ype + *(ype - 2)); 
+			yc = 0.5 * (*ype + *yp0);
+			parabola(xa, ya, xc, yc, *xpe, *ype);
+			xa = 0.5 * (*xpe + *xp0); 
+			xc = 0.5 * (*(xp0 + 2) + *xp0);
+			ya = 0.5 * (*ype + *yp0); 
+			yc = 0.5 * (*(yp0 + 2) + *yp0);
+			parabola(xa, ya, xc, yc, *xp0, *yp0);
+		}
+		else {	/*open curve with multiple endpoints*/
+			if (mode % 2) /*odd mode makes first point double*/
+				plotline(*xp0,*yp0,0.5*(*xp0+*(xp0+2)),0.5*(*yp0+*(yp0+2)));
+		}
+		xp += 2; 
+		yp += 2;
+		for (i = 1; i < (n - 1); i++, xp += 2, yp += 2) {
+			xa = 0.5 * (*(xp - 2) + *xp); 
+			xc = 0.5 * ( *xp + *(xp + 2));
+			ya = 0.5 * (*(yp - 2) + *yp); 
+			yc = 0.5 * ( *yp + *(yp + 2));
+			parabola(xa, ya, xc, yc, *xp, *yp);
+		}
+		if(mode >= 2 && mode != 4)
+			plotline(0.5*(*(xpe-2)+*xpe),0.5*(*(ype-2)+*ype),*xpe,*ype);
+	}
+}
blob - /dev/null
blob + cf4cf89e51649f9659b0990d3921741382228847 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/subr.c
@@ -0,0 +1,79 @@
+#include "mplot.h"
+#define pSMALL    0.5
+struct penvir  E[9] = {
+{ 0., 1024., 0., 0., 1., -1.,1024., -1024., 0., 0., pSMALL, 1., 1, 0.,1, DBlack, DWhite},
+{ 0., 1024., 0., 0., 1., -1.,1024., -1024., 0., 0., pSMALL, 1., 1, 0.,1, DBlack, DWhite},
+{ 0., 1024., 0., 0., 1., -1.,1024., -1024., 0., 0., pSMALL, 1., 1, 0.,1, DBlack, DWhite},
+{ 0., 1024., 0., 0., 1., -1.,1024., -1024., 0., 0., pSMALL, 1., 1, 0.,1, DBlack, DWhite},
+{ 0., 1024., 0., 0., 1., -1.,1024., -1024., 0., 0., pSMALL, 1., 1, 0.,1, DBlack, DWhite},
+{ 0., 1024., 0., 0., 1., -1.,1024., -1024., 0., 0., pSMALL, 1., 1, 0.,1, DBlack, DWhite},
+{ 0., 1024., 0., 0., 1., -1.,1024., -1024., 0., 0., pSMALL, 1., 1, 0.,1, DBlack, DWhite},
+{ 0., 1024., 0., 0., 1., -1.,1024., -1024., 0., 0., pSMALL, 1., 1, 0.,1, DBlack, DWhite}
+};
+struct penvir *e0 = E, *e1 = &E[1], *esave;
+bcolor(char *s){
+	int c;
+	while (*s != NULL) {
+		switch (*s) {
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			c=0;
+			while('0'<=*s && *s<='9')
+				c=c*10+*s++-'0';
+			if(c < 0)
+				return DBlack;
+			return cmap2rgba(c);
+		case 'k':  case 'z':	/* zero was old name for kblack */
+			return(DBlack);
+		case 'r':
+print("RED");
+			return(DRed);
+		case 'g': 
+			return(DGreen);
+		case 'b': 
+			return(DBlue);
+		case 'm': 
+			return(DMagenta);
+		case 'y': 
+			return(DYellow);
+		case 'c': 
+			return(DCyan);
+		case 'w': 
+			return(DWhite);
+		case 'R': 
+			return(atoi(s + 1));
+		case 'G': 
+			e1->pgap = atof(s + 1); 
+			return(-1);
+		case 'A': 
+			e1->pslant = (180. - atof(s + 1)) / RADIAN; 
+			return(-1);
+		}
+		while (*++s != NULL) 
+			if (*s == '/') {
+				s++;
+				break;
+			}
+	}
+	return DBlack;
+}
+void sscpy(struct penvir *a, struct penvir *b){ /* copy 'a' onto 'b' */
+	b->left = a->left; 
+	b->bottom = a->bottom; 
+	b->xmin = a->xmin; 
+	b->ymin = a->ymin;
+	b->scalex = a->scalex; 
+	b->scaley = a->scaley;
+	b->sidex = a->sidex; 
+	b->sidey = a->sidey;
+	b->copyx = a->copyx; 
+	b->copyy = a->copyy;
+	b->quantum = a->quantum;
+	b->grade = a->grade;
+	b->pmode = a->pmode; 
+	b->foregr = a->foregr; 
+	b->backgr = a->backgr;
+}
+void idle(void){}
+
+void ptype(char *s){USED(s);}
blob - /dev/null
blob + 530d5f96821bd877326323c114c2451bcad2100f (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/text.c
@@ -0,0 +1,39 @@
+/*
+          t string  Place the string so that its first character is
+                    centered on the current point (default).  If
+                    string begins with `\C' (`\R'), it is centered
+                    (right-adjusted) on the current point.  A
+                    backslash at the beginning of the string may be
+                    escaped with another backslash.
+ */
+#include "mplot.h"
+void text(char *s){
+	register int	kx, ky;
+	int centered, right, more;
+	char *ss;
+	ss=s;
+	for(;;){
+		centered=right=more=0;
+		if(*ss=='\\'){
+			ss++;
+			switch(*ss){
+			case 'C': centered++; ss++; break;
+			case 'R': right++; ss++; break;
+			case 'L': ss++; break;
+			case 'n': --ss; break;
+			}
+		}
+		for(s=ss;*ss!='\0';ss++)
+			if(ss[0]=='\\' && ss[1]=='n'){
+				more++;
+				break;
+			}
+		kx = SCX(e1->copyx);
+		ky = SCY(e1->copyy);
+		ky=m_text(kx, ky, s, ss, e1->foregr, centered, right);
+		if(!more)break;
+		e1->copyy = ( (double)(ky) - e1->bottom)/e1->scaley + e1->ymin + .5;
+		move(e1->copyx, e1->copyy);
+		ss+=2;
+	}
+}
blob - /dev/null
blob + 89a517865c197af660350c4d636f67fdfdd9b150 (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/vec.c
@@ -0,0 +1,26 @@
+#include "mplot.h"
+#define	code(x, y)	((x<clipminx?1:x>clipmaxx?2:0)|(y<clipminy?4:y>clipmaxy?8:0))
+void vec(double xx, double yy){
+	int x0, y0, x1, y1, c0, c1, c, tx, ty;
+	double t;
+	t=SCX(e1->copyx); if(fabs(t)>BIGINT) return; x0=t;
+	t=SCY(e1->copyy); if(fabs(t)>BIGINT) return; y0=t;
+	t=SCX(xx); if(fabs(t)>BIGINT) return; x1=t;
+	t=SCY(yy); if(fabs(t)>BIGINT) return; y1=t;
+	e1->copyx=xx;
+	e1->copyy=yy;
+	/* clipping -- what a concept */
+	c0=code(x0, y0);
+	c1=code(x1, y1);
+	while(c0|c1){
+		if(c0&c1) return;
+		c=c0?c0:c1;
+		if(c&1)      ty=y0+(y1-y0)*(clipminx-x0)/(x1-x0), tx=clipminx;
+		else if(c&2) ty=y0+(y1-y0)*(clipmaxx-x0)/(x1-x0), tx=clipmaxx;
+		else if(c&4) tx=x0+(x1-x0)*(clipminy-y0)/(y1-y0), ty=clipminy;
+		else         tx=x0+(x1-x0)*(clipmaxy-y0)/(y1-y0), ty=clipmaxy;
+		if(c==c0) x0=tx, y0=ty, c0=code(x0, y0);
+		else      x1=tx, y1=ty, c1=code(x1, y1);
+	}
+	m_vector(x0, y0, x1, y1, e1->foregr);
+}
blob - /dev/null
blob + 0672ecd14173d5266e11049c53907daa0166e1aa (mode 644)
--- /dev/null
+++ src/cmd/plot/libplot/whoami.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+char *whoami(void){
+	return("ramtek");
+}
blob - /dev/null
blob + 0eb1a7955e7b6cb4b1b042b7bdc86bf1896465f9 (mode 644)
--- /dev/null
+++ src/cmd/plot/mkfile
@@ -0,0 +1,27 @@
+PLAN9=../../..
+<$PLAN9/src/mkhdr
+
+TARG=plot
+OFILES=plot.$O\
+
+HFILES=plot.h\
+
+LIB=libplot.a
+
+SHORTLIB=frame draw bio 9
+LDFLAGS=$LDFLAGS -L$X11/lib -lX11
+
+<$PLAN9/src/mkone
+
+$LIB:
+	cd libplot
+	mk install
+
+clean:V:
+	rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output $TARG libplot.a
+	cd libplot
+	mk clean
+
+nuke:V:
+	mk clean
+	rm -f libplot.a[$OS]
blob - /dev/null
blob + 04e5cf549017934a2887619748cd3d84ab7644b7 (mode 644)
--- /dev/null
+++ src/cmd/plot/plot.c
@@ -0,0 +1,605 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "plot.h"
+#include <draw.h>
+#include <event.h>
+#include <ctype.h>
+
+void	define(char*);
+void	call(char*);
+void	include(char*);
+int	process(Biobuf*);
+int	server(void);
+
+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 eresized(int new){
+	if(new && getwindow(display, Refnone) < 0){
+		fprint(2, "Can't reattach to window: %r\n");
+		exits("resize");
+	}
+}
+char *items[]={
+	"exit",
+	0
+};
+Menu menu={items};
+void
+main(int arc, char *arv[]){
+	char *ap;
+	Biobuf *bp;
+	int fd;
+	int i;
+	int dflag;
+	char *oflag;
+	Mouse m;
+	bp = 0;
+	fd = dup(0, -1);		/* because openpl will close 0! */
+	dflag=0;
+	oflag="";
+	for(i=1;i!=arc;i++) if(arv[i][0]=='-') switch(arv[i][1]){
+	case 'd': dflag=1; break;
+	case 'o': oflag=arv[i]+2; break;
+	case 's': fd=server(); break;
+	}
+	openpl(oflag);
+	if(dflag) doublebuffer();
+	for (; arc > 1; arc--, arv++) {
+		if (arv[1][0] == '-') {
+			ap = arv[1];
+			ap++;
+			switch (*ap) {
+			default:
+				fprint(2, "%s not allowed as argument\n", ap);
+				exits("usage");
+			case 'T': break;
+			case 'D': break;
+			case 'd': break;
+			case 'o': break;
+			case 'W': break;
+			case 's': break;
+			case 'e': erase(); break;
+			case 'C': closepl(); break;
+			case 'w': ppause(); break;
+			case 'c': color(ap+1); break;
+			case 'f': cfill(ap+1); break;
+			case 'p': pen(ap+1); break;
+			case 'g': grade(atof(ap+1)); break;
+			}
+		}
+		else if ((bp = Bopen(arv[1], OREAD)) == 0) {
+			perror(arv[1]);
+			fprint(2, "Cannot find file %s\n", arv[1]);
+		}
+		else if(process(bp)) Bterm(fsp->fd);
+		else break;
+	}
+	if (bp == 0){
+		bp = malloc(sizeof *bp);
+		Binit(bp, fd, OREAD);
+		process(bp);
+	}
+	closepl();
+	for(;;){
+		m=emouse();
+		if(m.buttons&4 && emenuhit(3, &m, &menu)==0) exits(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) Bterm(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
+ */
+int
+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()){
+				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;
+			}
+		}
+	}
+}
+
+int
+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); plotdisc(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); plotline(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();  plotpoly(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 %ld\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;f<fptr;f++){
+		if (!(strcmp(a, f->name)))
+			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;
+}
+/*
+ * Doesn't work.  Why?
+ */
+int server(void){
+	int fd, p[2];
+	char buf[32];
+	pipe(p);
+	fd = create("/srv/plot", 1, 0666);
+	sprint(buf, "%d", p[1]);
+	write(fd, buf, strlen(buf));
+	close(fd);
+	close(p[1]);
+	return p[0];
+}
blob - /dev/null
blob + 81b41c9139830215e6fb16e4af9cfcbc296cbbdb (mode 644)
--- /dev/null
+++ src/cmd/plot/plot.h
@@ -0,0 +1,35 @@
+/*
+ * Prototypes for libplot functions.
+ */
+void rarc(double, double, double, double, double, double, double);
+void box(double, double, double, double);
+void cfill(char *);
+void circ(double, double, double);
+void closepl(void);
+void color(char *);
+void plotdisc(double, double, double);
+void dpoint(double, double);
+void erase(void);
+void fill(int [], double *[]);
+void frame(double, double, double, double);
+void grade(double);
+void idle(void);
+void plotline(double, double, double, double);
+void move(double, double);
+void openpl(char *);
+void parabola(double, double, double, double, double, double);
+void pen(char *);
+void plotpoly(int [], double *[]);
+void ppause(void);
+void ptype(char *);
+void range(double, double, double, double);
+void restore(void);
+void rmove(double, double);
+void rvec(double, double);
+void sbox(double, double, double, double);
+void splin(int, int [], double *[]);
+void text(char *);
+void vec(double, double);
+void save(void);
+char *whoami(void);
+void doublebuffer(void);