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