aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/plot
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-14 19:54:10 +0000
committerrsc <devnull@localhost>2004-04-14 19:54:10 +0000
commit4314729ddef28cb619ce97d50f0968ca24c93803 (patch)
tree3abd7849a10e842a57b1fd535f8278d22a6bf132 /src/cmd/plot
parent6e18e03e63942f7b0912bb91d0da02fd493af0af (diff)
downloadplan9port-4314729ddef28cb619ce97d50f0968ca24c93803.tar.gz
plan9port-4314729ddef28cb619ce97d50f0968ca24c93803.tar.bz2
plan9port-4314729ddef28cb619ce97d50f0968ca24c93803.zip
Add graph, plot
Diffstat (limited to 'src/cmd/plot')
-rw-r--r--src/cmd/plot/libplot/box.c8
-rw-r--r--src/cmd/plot/libplot/cfill.c5
-rw-r--r--src/cmd/plot/libplot/circ.c12
-rw-r--r--src/cmd/plot/libplot/closepl.c4
-rw-r--r--src/cmd/plot/libplot/color.c4
-rw-r--r--src/cmd/plot/libplot/disk.c12
-rw-r--r--src/cmd/plot/libplot/doublebuffer.c4
-rw-r--r--src/cmd/plot/libplot/dpoint.c6
-rw-r--r--src/cmd/plot/libplot/erase.c5
-rw-r--r--src/cmd/plot/libplot/fill.c167
-rw-r--r--src/cmd/plot/libplot/frame.c16
-rw-r--r--src/cmd/plot/libplot/grade.c4
-rw-r--r--src/cmd/plot/libplot/line.c5
-rw-r--r--src/cmd/plot/libplot/machdep.c141
-rw-r--r--src/cmd/plot/libplot/mkfile42
-rw-r--r--src/cmd/plot/libplot/move.c5
-rw-r--r--src/cmd/plot/libplot/mplot.h47
-rw-r--r--src/cmd/plot/libplot/openpl.c12
-rw-r--r--src/cmd/plot/libplot/parabola.c32
-rw-r--r--src/cmd/plot/libplot/pen.c6
-rw-r--r--src/cmd/plot/libplot/poly.c17
-rw-r--r--src/cmd/plot/libplot/ppause.c7
-rw-r--r--src/cmd/plot/libplot/pprompt.c5
-rw-r--r--src/cmd/plot/libplot/range.c11
-rw-r--r--src/cmd/plot/libplot/rarc.c44
-rw-r--r--src/cmd/plot/libplot/restore.c5
-rw-r--r--src/cmd/plot/libplot/rmove.c6
-rw-r--r--src/cmd/plot/libplot/rvec.c6
-rw-r--r--src/cmd/plot/libplot/save.c5
-rw-r--r--src/cmd/plot/libplot/sbox.c13
-rw-r--r--src/cmd/plot/libplot/spline.c51
-rw-r--r--src/cmd/plot/libplot/subr.c79
-rw-r--r--src/cmd/plot/libplot/text.c39
-rw-r--r--src/cmd/plot/libplot/vec.c26
-rw-r--r--src/cmd/plot/libplot/whoami.c4
-rw-r--r--src/cmd/plot/mkfile27
-rw-r--r--src/cmd/plot/plot.c605
-rw-r--r--src/cmd/plot/plot.h35
38 files changed, 1522 insertions, 0 deletions
diff --git a/src/cmd/plot/libplot/box.c b/src/cmd/plot/libplot/box.c
new file mode 100644
index 00000000..4654bc85
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/cfill.c b/src/cmd/plot/libplot/cfill.c
new file mode 100644
index 00000000..8f700c7f
--- /dev/null
+++ b/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;
+}
diff --git a/src/cmd/plot/libplot/circ.c b/src/cmd/plot/libplot/circ.c
new file mode 100644
index 00000000..53337117
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/closepl.c b/src/cmd/plot/libplot/closepl.c
new file mode 100644
index 00000000..b7a8c99a
--- /dev/null
+++ b/src/cmd/plot/libplot/closepl.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+void closepl(void){
+ m_finish();
+}
diff --git a/src/cmd/plot/libplot/color.c b/src/cmd/plot/libplot/color.c
new file mode 100644
index 00000000..bd9be4ea
--- /dev/null
+++ b/src/cmd/plot/libplot/color.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+void color(char *s){
+ e1->foregr=bcolor(s);
+}
diff --git a/src/cmd/plot/libplot/disk.c b/src/cmd/plot/libplot/disk.c
new file mode 100644
index 00000000..47b39012
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/doublebuffer.c b/src/cmd/plot/libplot/doublebuffer.c
new file mode 100644
index 00000000..485894fd
--- /dev/null
+++ b/src/cmd/plot/libplot/doublebuffer.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+void doublebuffer(void){
+ m_dblbuf();
+}
diff --git a/src/cmd/plot/libplot/dpoint.c b/src/cmd/plot/libplot/dpoint.c
new file mode 100644
index 00000000..7d5b6ff8
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/erase.c b/src/cmd/plot/libplot/erase.c
new file mode 100644
index 00000000..ab913475
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/fill.c b/src/cmd/plot/libplot/fill.c
new file mode 100644
index 00000000..a33294e5
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/frame.c b/src/cmd/plot/libplot/frame.c
new file mode 100644
index 00000000..bbc37a17
--- /dev/null
+++ b/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;
+}
diff --git a/src/cmd/plot/libplot/grade.c b/src/cmd/plot/libplot/grade.c
new file mode 100644
index 00000000..0afe7f40
--- /dev/null
+++ b/src/cmd/plot/libplot/grade.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+void grade(double x){
+ e1->grade = x;
+}
diff --git a/src/cmd/plot/libplot/line.c b/src/cmd/plot/libplot/line.c
new file mode 100644
index 00000000..416d2eea
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/machdep.c b/src/cmd/plot/libplot/machdep.c
new file mode 100644
index 00000000..abcb761f
--- /dev/null
+++ b/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;
+}
diff --git a/src/cmd/plot/libplot/mkfile b/src/cmd/plot/libplot/mkfile
new file mode 100644
index 00000000..a73bd617
--- /dev/null
+++ b/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
+
diff --git a/src/cmd/plot/libplot/move.c b/src/cmd/plot/libplot/move.c
new file mode 100644
index 00000000..4e60260b
--- /dev/null
+++ b/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;
+}
diff --git a/src/cmd/plot/libplot/mplot.h b/src/cmd/plot/libplot/mplot.h
new file mode 100644
index 00000000..99e27efd
--- /dev/null
+++ b/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);
diff --git a/src/cmd/plot/libplot/openpl.c b/src/cmd/plot/libplot/openpl.c
new file mode 100644
index 00000000..6972f956
--- /dev/null
+++ b/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.);
+}
diff --git a/src/cmd/plot/libplot/parabola.c b/src/cmd/plot/libplot/parabola.c
new file mode 100644
index 00000000..212b9c97
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/pen.c b/src/cmd/plot/libplot/pen.c
new file mode 100644
index 00000000..4e13e5cb
--- /dev/null
+++ b/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); */
+}
diff --git a/src/cmd/plot/libplot/poly.c b/src/cmd/plot/libplot/poly.c
new file mode 100644
index 00000000..e3ff7345
--- /dev/null
+++ b/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);
+ }
+ }
+}
diff --git a/src/cmd/plot/libplot/ppause.c b/src/cmd/plot/libplot/ppause.c
new file mode 100644
index 00000000..9fb8863d
--- /dev/null
+++ b/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();
+}
diff --git a/src/cmd/plot/libplot/pprompt.c b/src/cmd/plot/libplot/pprompt.c
new file mode 100644
index 00000000..2678ead5
--- /dev/null
+++ b/src/cmd/plot/libplot/pprompt.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void
+pprompt(void){
+ fprintf(stderr, ":");
+}
diff --git a/src/cmd/plot/libplot/range.c b/src/cmd/plot/libplot/range.c
new file mode 100644
index 00000000..c4485560
--- /dev/null
+++ b/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;
+}
diff --git a/src/cmd/plot/libplot/rarc.c b/src/cmd/plot/libplot/rarc.c
new file mode 100644
index 00000000..9c8ccf15
--- /dev/null
+++ b/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);
+ }
+ }
+}
diff --git a/src/cmd/plot/libplot/restore.c b/src/cmd/plot/libplot/restore.c
new file mode 100644
index 00000000..81bdd421
--- /dev/null
+++ b/src/cmd/plot/libplot/restore.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void restore(void){
+ e1--;
+ move(e1->copyx, e1->copyy);
+}
diff --git a/src/cmd/plot/libplot/rmove.c b/src/cmd/plot/libplot/rmove.c
new file mode 100644
index 00000000..faae7a13
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/rvec.c b/src/cmd/plot/libplot/rvec.c
new file mode 100644
index 00000000..2e23cdbc
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/save.c b/src/cmd/plot/libplot/save.c
new file mode 100644
index 00000000..e3dc4058
--- /dev/null
+++ b/src/cmd/plot/libplot/save.c
@@ -0,0 +1,5 @@
+#include "mplot.h"
+void save(void){
+ sscpy(e1, e1 + 1);
+ e1++;
+}
diff --git a/src/cmd/plot/libplot/sbox.c b/src/cmd/plot/libplot/sbox.c
new file mode 100644
index 00000000..479790b9
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/spline.c b/src/cmd/plot/libplot/spline.c
new file mode 100644
index 00000000..8cfa83d7
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/src/cmd/plot/libplot/subr.c b/src/cmd/plot/libplot/subr.c
new file mode 100644
index 00000000..cf4cf89e
--- /dev/null
+++ b/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);}
diff --git a/src/cmd/plot/libplot/text.c b/src/cmd/plot/libplot/text.c
new file mode 100644
index 00000000..530d5f96
--- /dev/null
+++ b/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;
+ }
+}
diff --git a/src/cmd/plot/libplot/vec.c b/src/cmd/plot/libplot/vec.c
new file mode 100644
index 00000000..89a51786
--- /dev/null
+++ b/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);
+}
diff --git a/src/cmd/plot/libplot/whoami.c b/src/cmd/plot/libplot/whoami.c
new file mode 100644
index 00000000..0672ecd1
--- /dev/null
+++ b/src/cmd/plot/libplot/whoami.c
@@ -0,0 +1,4 @@
+#include "mplot.h"
+char *whoami(void){
+ return("ramtek");
+}
diff --git a/src/cmd/plot/mkfile b/src/cmd/plot/mkfile
new file mode 100644
index 00000000..0eb1a795
--- /dev/null
+++ b/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]
diff --git a/src/cmd/plot/plot.c b/src/cmd/plot/plot.c
new file mode 100644
index 00000000..04e5cf54
--- /dev/null
+++ b/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];
+}
diff --git a/src/cmd/plot/plot.h b/src/cmd/plot/plot.h
new file mode 100644
index 00000000..81b41c91
--- /dev/null
+++ b/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);