xref: /plan9/sys/src/cmd/proof/htroff.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include	<u.h>
23e12c5d1SDavid du Colombier #include	<libc.h>
33e12c5d1SDavid du Colombier #include	<libg.h>
43e12c5d1SDavid du Colombier #include	<bio.h>
53e12c5d1SDavid du Colombier #include	"proof.h"
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier int	res;
83e12c5d1SDavid du Colombier int	hpos;
93e12c5d1SDavid du Colombier int	vpos;
103e12c5d1SDavid du Colombier int	DIV = 11;
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier Point offset;
133e12c5d1SDavid du Colombier Point xyoffset = { 0,0 };
143e12c5d1SDavid du Colombier 
153e12c5d1SDavid du Colombier Rectangle	view[MAXVIEW];
163e12c5d1SDavid du Colombier Rectangle	bound[MAXVIEW];		/* extreme points */
173e12c5d1SDavid du Colombier int	nview = 1;
183e12c5d1SDavid du Colombier 
193e12c5d1SDavid du Colombier int	lastp;	/* last page number we were on */
203e12c5d1SDavid du Colombier 
213e12c5d1SDavid du Colombier #define	NPAGENUMS	200
223e12c5d1SDavid du Colombier struct pagenum {
233e12c5d1SDavid du Colombier 	int	num;
243e12c5d1SDavid du Colombier 	long	adr;
253e12c5d1SDavid du Colombier } pagenums[NPAGENUMS];
263e12c5d1SDavid du Colombier int	npagenums;
273e12c5d1SDavid du Colombier 
283e12c5d1SDavid du Colombier int	curfont, cursize;
293e12c5d1SDavid du Colombier 
303e12c5d1SDavid du Colombier char	*getcmdstr(void);
313e12c5d1SDavid du Colombier 
323e12c5d1SDavid du Colombier static void	initpage(void);
333e12c5d1SDavid du Colombier static void	view_setup(int);
343e12c5d1SDavid du Colombier static Point	scale(Point);
353e12c5d1SDavid du Colombier static void	clearview(Rectangle);
363e12c5d1SDavid du Colombier static int	addpage(int);
373e12c5d1SDavid du Colombier static void	spline(Bitmap *, int, Point *, int);
383e12c5d1SDavid du Colombier static int	skipto(int, int);
393e12c5d1SDavid du Colombier static void	wiggly(int);
403e12c5d1SDavid du Colombier static void	devcntrl(void);
413e12c5d1SDavid du Colombier static void	eatline(void);
423e12c5d1SDavid du Colombier static int	getn(void);
433e12c5d1SDavid du Colombier static int	botpage(int);
443e12c5d1SDavid du Colombier static void	getstr(char *);
453e12c5d1SDavid du Colombier static void	getutf(char *);
463e12c5d1SDavid du Colombier 
473e12c5d1SDavid du Colombier #define Do screen.r.min
483e12c5d1SDavid du Colombier #define Dc screen.r.max
493e12c5d1SDavid du Colombier 
503e12c5d1SDavid du Colombier /* declarations and definitions of font stuff are in font.c and main.c */
513e12c5d1SDavid du Colombier 
523e12c5d1SDavid du Colombier static void
533e12c5d1SDavid du Colombier initpage(void)
543e12c5d1SDavid du Colombier {
553e12c5d1SDavid du Colombier 	int i;
563e12c5d1SDavid du Colombier 
573e12c5d1SDavid du Colombier 	view_setup(nview);
583e12c5d1SDavid du Colombier 	for (i = 0; i < nview-1; i++)
593e12c5d1SDavid du Colombier 		bitblt(&screen, view[i].min, &screen, view[i+1], S);
603e12c5d1SDavid du Colombier 	clearview(view[nview-1]);
613e12c5d1SDavid du Colombier 	offset = view[nview-1].min;
623e12c5d1SDavid du Colombier 	vpos = 0;
633e12c5d1SDavid du Colombier }
643e12c5d1SDavid du Colombier 
653e12c5d1SDavid du Colombier static void
663e12c5d1SDavid du Colombier view_setup(int n)
673e12c5d1SDavid du Colombier {
683e12c5d1SDavid du Colombier 	int i, j, v, dx, dy, r, c;
693e12c5d1SDavid du Colombier 
703e12c5d1SDavid du Colombier 	switch (n) {
713e12c5d1SDavid du Colombier 	case 1: r = 1; c = 1; break;
723e12c5d1SDavid du Colombier 	case 2: r = 1; c = 2; break;
733e12c5d1SDavid du Colombier 	case 3: r = 1; c = 3; break;
743e12c5d1SDavid du Colombier 	case 4: r = 2; c = 2; break;
753e12c5d1SDavid du Colombier 	case 5: case 6: r = 2; c = 3; break;
763e12c5d1SDavid du Colombier 	case 7: case 8: case 9: r = 3; c = 3; break;
773e12c5d1SDavid du Colombier 	default: r = (n+2)/3; c = 3; break; /* finking out */
783e12c5d1SDavid du Colombier 	}
793e12c5d1SDavid du Colombier 	dx = (Dc.x - Do.x) / c;
803e12c5d1SDavid du Colombier 	dy = (Dc.y - Do.y) / r;
813e12c5d1SDavid du Colombier 	v = 0;
823e12c5d1SDavid du Colombier 	for (i = 0; i < r && v < n; i++)
833e12c5d1SDavid du Colombier 		for (j = 0; j < c && v < n; j++) {
843e12c5d1SDavid du Colombier 			view[v] = screen.r;
853e12c5d1SDavid du Colombier 			view[v].min.x = Do.x + j * dx;
863e12c5d1SDavid du Colombier 			view[v].max.x = Do.x + (j+1) * dx;
873e12c5d1SDavid du Colombier 			view[v].min.y = Do.y + i * dy;
883e12c5d1SDavid du Colombier 			view[v].max.y = Do.y + (i+1) * dy;
893e12c5d1SDavid du Colombier 			v++;
903e12c5d1SDavid du Colombier 		}
913e12c5d1SDavid du Colombier }
923e12c5d1SDavid du Colombier 
933e12c5d1SDavid du Colombier static void
943e12c5d1SDavid du Colombier clearview(Rectangle r)
953e12c5d1SDavid du Colombier {
963e12c5d1SDavid du Colombier 	bitblt(&screen, r.min, &screen, r, 0);
973e12c5d1SDavid du Colombier }
983e12c5d1SDavid du Colombier 
993e12c5d1SDavid du Colombier void ereshaped(Rectangle r)
1003e12c5d1SDavid du Colombier {
1013e12c5d1SDavid du Colombier 	/* this is called if we are reshaped */
102*219b2ee8SDavid du Colombier 	screen.r = r;
1033e12c5d1SDavid du Colombier 	initpage();
1043e12c5d1SDavid du Colombier }
1053e12c5d1SDavid du Colombier 
1063e12c5d1SDavid du Colombier static Point
1073e12c5d1SDavid du Colombier scale(Point p)
1083e12c5d1SDavid du Colombier {
1093e12c5d1SDavid du Colombier 	p.x /= DIV;
1103e12c5d1SDavid du Colombier 	p.y /= DIV;
1113e12c5d1SDavid du Colombier 	return add(xyoffset, add(offset,p));
1123e12c5d1SDavid du Colombier }
1133e12c5d1SDavid du Colombier 
1143e12c5d1SDavid du Colombier static int
1153e12c5d1SDavid du Colombier addpage(int n)
1163e12c5d1SDavid du Colombier {
1173e12c5d1SDavid du Colombier 	int i;
1183e12c5d1SDavid du Colombier 
1193e12c5d1SDavid du Colombier 	for (i = 0; i < npagenums; i++)
1203e12c5d1SDavid du Colombier 		if (n == pagenums[i].num)
1213e12c5d1SDavid du Colombier 			return i;
1223e12c5d1SDavid du Colombier 	if (npagenums < NPAGENUMS-1) {
1233e12c5d1SDavid du Colombier 		pagenums[npagenums].num = n;
1243e12c5d1SDavid du Colombier 		pagenums[npagenums].adr = Boffset(&bin);
1253e12c5d1SDavid du Colombier 		npagenums++;
1263e12c5d1SDavid du Colombier 	}
1273e12c5d1SDavid du Colombier 	return npagenums;
1283e12c5d1SDavid du Colombier }
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier void
1313e12c5d1SDavid du Colombier readpage(void)
1323e12c5d1SDavid du Colombier {
133*219b2ee8SDavid du Colombier 	int c, i;
1343e12c5d1SDavid du Colombier 	static int first = 0;
1353e12c5d1SDavid du Colombier 	int m, n, gonow = 1;
136*219b2ee8SDavid du Colombier 	char buf[300];
137*219b2ee8SDavid du Colombier 	Rune r[32], t;
1383e12c5d1SDavid du Colombier 	Point p,q,qq;
1393e12c5d1SDavid du Colombier 
140*219b2ee8SDavid du Colombier 	offset = screen.clipr.min;
1413e12c5d1SDavid du Colombier 	cursorswitch(&deadmouse);
1423e12c5d1SDavid du Colombier 	while (gonow)
1433e12c5d1SDavid du Colombier 	{
1443e12c5d1SDavid du Colombier 		c = BGETC(&bin);
1453e12c5d1SDavid du Colombier 		switch (c)
1463e12c5d1SDavid du Colombier 		{
1473e12c5d1SDavid du Colombier 		case -1:
1483e12c5d1SDavid du Colombier 			cursorswitch(0);
1493e12c5d1SDavid du Colombier 			if (botpage(lastp+1)) {
1503e12c5d1SDavid du Colombier 				initpage();
1513e12c5d1SDavid du Colombier 				break;
1523e12c5d1SDavid du Colombier 			}
1533e12c5d1SDavid du Colombier 			exits(0);
1543e12c5d1SDavid du Colombier 		case 'p':	/* new page */
1553e12c5d1SDavid du Colombier 			lastp = getn();
1563e12c5d1SDavid du Colombier 			addpage(lastp);
1573e12c5d1SDavid du Colombier 			if (first++ > 0) {
1583e12c5d1SDavid du Colombier 				cursorswitch(0);
1593e12c5d1SDavid du Colombier 				botpage(lastp);
1603e12c5d1SDavid du Colombier 				cursorswitch(&deadmouse);
1613e12c5d1SDavid du Colombier 			}
1623e12c5d1SDavid du Colombier 			initpage();
1633e12c5d1SDavid du Colombier 			break;
1643e12c5d1SDavid du Colombier 		case '\n':	/* when input is text */
1653e12c5d1SDavid du Colombier 		case ' ':
1663e12c5d1SDavid du Colombier 		case 0:		/* occasional noise creeps in */
1673e12c5d1SDavid du Colombier 			break;
1683e12c5d1SDavid du Colombier 		case '0': case '1': case '2': case '3': case '4':
1693e12c5d1SDavid du Colombier 		case '5': case '6': case '7': case '8': case '9':
1703e12c5d1SDavid du Colombier 			/* two motion digits plus a character */
1713e12c5d1SDavid du Colombier 			hpos += (c-'0')*10 + BGETC(&bin)-'0';
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier 		/* FALLS THROUGH */
1743e12c5d1SDavid du Colombier 		case 'c':	/* single ascii character */
175*219b2ee8SDavid du Colombier 			r[0] = Bgetrune(&bin);
176*219b2ee8SDavid du Colombier 			r[1] = 0;
177*219b2ee8SDavid du Colombier 			dochar(r);
1783e12c5d1SDavid du Colombier 			break;
1793e12c5d1SDavid du Colombier 
1803e12c5d1SDavid du Colombier 		case 'C':
181*219b2ee8SDavid du Colombier 			for(i=0; ; i++){
182*219b2ee8SDavid du Colombier 				t = Bgetrune(&bin);
183*219b2ee8SDavid du Colombier 				if(isspace(t))
1843e12c5d1SDavid du Colombier 					break;
185*219b2ee8SDavid du Colombier 				r[i] = t;
186*219b2ee8SDavid du Colombier 			}
187*219b2ee8SDavid du Colombier 			r[i] = 0;
188*219b2ee8SDavid du Colombier 			dochar(r);
189*219b2ee8SDavid du Colombier 			break;
190*219b2ee8SDavid du Colombier 
1913e12c5d1SDavid du Colombier 		case 'N':
192*219b2ee8SDavid du Colombier 			r[0] = getn();
193*219b2ee8SDavid du Colombier 			r[1] = 0;
194*219b2ee8SDavid du Colombier 			dochar(r);
1953e12c5d1SDavid du Colombier 			break;
196*219b2ee8SDavid du Colombier 
1973e12c5d1SDavid du Colombier 		case 'D':	/* draw function */
1983e12c5d1SDavid du Colombier 			switch (BGETC(&bin))
1993e12c5d1SDavid du Colombier 			{
2003e12c5d1SDavid du Colombier 			case 'l':	/* draw a line */
2013e12c5d1SDavid du Colombier 				n = getn();
2023e12c5d1SDavid du Colombier 				m = getn();
2033e12c5d1SDavid du Colombier 				p = Pt(hpos,vpos);
2043e12c5d1SDavid du Colombier 				q = add(p, Pt(n,m));
2053e12c5d1SDavid du Colombier 				hpos += n;
2063e12c5d1SDavid du Colombier 				vpos += m;
2073e12c5d1SDavid du Colombier 				segment(&screen, scale(p), scale(q), ONES, Mode);
2083e12c5d1SDavid du Colombier 				break;
2093e12c5d1SDavid du Colombier 			case 'c':	/* circle */
2103e12c5d1SDavid du Colombier 				/*nop*/
2113e12c5d1SDavid du Colombier 				m = getn()/2;
2123e12c5d1SDavid du Colombier 				p = Pt(hpos+m,vpos);
2133e12c5d1SDavid du Colombier 				hpos += 2*m;
2143e12c5d1SDavid du Colombier 				circle(&screen, scale(p), m/DIV, ONES, Mode);
2153e12c5d1SDavid du Colombier 				/* p=currentpt; p.x+=dmap(m/2);circle bp,p,a,ONES,Mode*/
2163e12c5d1SDavid du Colombier 				break;
2173e12c5d1SDavid du Colombier 			case 'e':	/* ellipse */
2183e12c5d1SDavid du Colombier 				/*nop*/
2193e12c5d1SDavid du Colombier 				m = getn()/2;
2203e12c5d1SDavid du Colombier 				n = getn()/2;
2213e12c5d1SDavid du Colombier 				p = Pt(hpos+m,vpos);
2223e12c5d1SDavid du Colombier 				hpos += 2*m;
2233e12c5d1SDavid du Colombier 				ellipse(&screen, scale(p), m/DIV, n/DIV, ONES, Mode);
2243e12c5d1SDavid du Colombier 				break;
2253e12c5d1SDavid du Colombier 			case 'a':	/* arc */
2263e12c5d1SDavid du Colombier 				p = scale(Pt(hpos,vpos));
2273e12c5d1SDavid du Colombier 				n = getn();
2283e12c5d1SDavid du Colombier 				m = getn();
2293e12c5d1SDavid du Colombier 				hpos += n;
2303e12c5d1SDavid du Colombier 				vpos += m;
2313e12c5d1SDavid du Colombier 				q = scale(Pt(hpos,vpos));
2323e12c5d1SDavid du Colombier 				n = getn();
2333e12c5d1SDavid du Colombier 				m = getn();
2343e12c5d1SDavid du Colombier 				hpos += n;
2353e12c5d1SDavid du Colombier 				vpos += m;
2363e12c5d1SDavid du Colombier 				qq = scale(Pt(hpos,vpos));
2373e12c5d1SDavid du Colombier 				arc(&screen,q,qq,p,ONES,Mode);
2383e12c5d1SDavid du Colombier 				break;
2393e12c5d1SDavid du Colombier 			case '~':	/* wiggly line */
2403e12c5d1SDavid du Colombier 				wiggly(0);
2413e12c5d1SDavid du Colombier 				break;
2423e12c5d1SDavid du Colombier 			default:
2433e12c5d1SDavid du Colombier 				break;
2443e12c5d1SDavid du Colombier 			}
2453e12c5d1SDavid du Colombier 			eatline();
2463e12c5d1SDavid du Colombier 			break;
2473e12c5d1SDavid du Colombier 		case 's':
2483e12c5d1SDavid du Colombier 			n = getn();	/* ignore fractional sizes */
2493e12c5d1SDavid du Colombier 			if (cursize == n)
2503e12c5d1SDavid du Colombier 				break;
2513e12c5d1SDavid du Colombier 			cursize = n;
2523e12c5d1SDavid du Colombier 			if (cursize >= NFONT)
2533e12c5d1SDavid du Colombier 				cursize = NFONT-1;
2543e12c5d1SDavid du Colombier 			break;
2553e12c5d1SDavid du Colombier 		case 'f':
2563e12c5d1SDavid du Colombier 			curfont = getn();
2573e12c5d1SDavid du Colombier 			break;
2583e12c5d1SDavid du Colombier 		case 'H':	/* absolute horizontal motion */
2593e12c5d1SDavid du Colombier 			hpos = getn();
2603e12c5d1SDavid du Colombier 			break;
2613e12c5d1SDavid du Colombier 		case 'h':	/* relative horizontal motion */
2623e12c5d1SDavid du Colombier 			hpos += getn();
2633e12c5d1SDavid du Colombier 			break;
2643e12c5d1SDavid du Colombier 		case 'w':	/* word space */
2653e12c5d1SDavid du Colombier 			break;
2663e12c5d1SDavid du Colombier 		case 'V':
2673e12c5d1SDavid du Colombier 			vpos = getn();
2683e12c5d1SDavid du Colombier 			break;
2693e12c5d1SDavid du Colombier 		case 'v':
2703e12c5d1SDavid du Colombier 			vpos += getn();
2713e12c5d1SDavid du Colombier 			break;
2723e12c5d1SDavid du Colombier 		case '#':	/* comment */
2733e12c5d1SDavid du Colombier 		case 'n':	/* end of line */
2743e12c5d1SDavid du Colombier 			eatline();
2753e12c5d1SDavid du Colombier 			break;
2763e12c5d1SDavid du Colombier 		case 'x':	/* device control */
2773e12c5d1SDavid du Colombier 			devcntrl();
2783e12c5d1SDavid du Colombier 			break;
2793e12c5d1SDavid du Colombier 		default:
2803e12c5d1SDavid du Colombier 			sprint(buf, "unknown input character %o %c\n", c, c);
2813e12c5d1SDavid du Colombier 			exits("bad char");
2823e12c5d1SDavid du Colombier 		}
2833e12c5d1SDavid du Colombier 	}
2843e12c5d1SDavid du Colombier 	cursorswitch(0);
2853e12c5d1SDavid du Colombier }
2863e12c5d1SDavid du Colombier 
2873e12c5d1SDavid du Colombier static void
2883e12c5d1SDavid du Colombier spline(Bitmap *b, int n, Point *pp, int f)
2893e12c5d1SDavid du Colombier {
2903e12c5d1SDavid du Colombier 	long w, t1, t2, t3, fac=1000;
2913e12c5d1SDavid du Colombier 	int i, j, steps=10;
2923e12c5d1SDavid du Colombier 	Point p, q;
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier 	for (i = n; i > 0; i--)
2953e12c5d1SDavid du Colombier 		pp[i] = pp[i-1];
2963e12c5d1SDavid du Colombier 	pp[n+1] = pp[n];
2973e12c5d1SDavid du Colombier 	n += 2;
2983e12c5d1SDavid du Colombier 	p = pp[0];
2993e12c5d1SDavid du Colombier 	for(i = 0; i < n-2; i++)
3003e12c5d1SDavid du Colombier 	{
3013e12c5d1SDavid du Colombier 		for(j = 0; j < steps; j++)
3023e12c5d1SDavid du Colombier 		{
3033e12c5d1SDavid du Colombier 			w = fac * j / steps;
3043e12c5d1SDavid du Colombier 			t1 = w * w / (2 * fac);
3053e12c5d1SDavid du Colombier 			w = w - fac/2;
3063e12c5d1SDavid du Colombier 			t2 = 3*fac/4 - w * w / fac;
3073e12c5d1SDavid du Colombier 			w = w - fac/2;
3083e12c5d1SDavid du Colombier 			t3 = w * w / (2*fac);
3093e12c5d1SDavid du Colombier 			q.x = (t1*pp[i+2].x + t2*pp[i+1].x +
3103e12c5d1SDavid du Colombier 				t3*pp[i].x + fac/2) / fac;
3113e12c5d1SDavid du Colombier 			q.y = (t1*pp[i+2].y + t2*pp[i+1].y +
3123e12c5d1SDavid du Colombier 				t3*pp[i].y + fac/2) / fac;
3133e12c5d1SDavid du Colombier 			segment(b, p, q, ONES, f);
3143e12c5d1SDavid du Colombier 			p = q;
3153e12c5d1SDavid du Colombier 		}
3163e12c5d1SDavid du Colombier 	}
3173e12c5d1SDavid du Colombier }
3183e12c5d1SDavid du Colombier 
3193e12c5d1SDavid du Colombier /* Have to parse skipped pages, to find out what fonts are loaded. */
3203e12c5d1SDavid du Colombier static int
3213e12c5d1SDavid du Colombier skipto(int gotop, int curp)
3223e12c5d1SDavid du Colombier {
3233e12c5d1SDavid du Colombier 	char *p;
3243e12c5d1SDavid du Colombier 	int i;
3253e12c5d1SDavid du Colombier 
3263e12c5d1SDavid du Colombier 	if (gotop == curp)
3273e12c5d1SDavid du Colombier 		return 1;
3283e12c5d1SDavid du Colombier 	for (i = 0; i < npagenums; i++)
3293e12c5d1SDavid du Colombier 		if (pagenums[i].num == gotop) {
3303e12c5d1SDavid du Colombier 			if (Bseek(&bin, pagenums[i].adr, 0) == Beof) {
3313e12c5d1SDavid du Colombier 				fprint(2, "can't rewind input\n");
3323e12c5d1SDavid du Colombier 				return 0;
3333e12c5d1SDavid du Colombier 			}
3343e12c5d1SDavid du Colombier 			return 1;
3353e12c5d1SDavid du Colombier 		}
3363e12c5d1SDavid du Colombier 	if (gotop <= curp) {
3373e12c5d1SDavid du Colombier 	    restart:
3383e12c5d1SDavid du Colombier 		if (Bseek(&bin,0,0) == Beof) {
3393e12c5d1SDavid du Colombier 			fprint(2, "can't rewind input\n");
3403e12c5d1SDavid du Colombier 			return 0;
3413e12c5d1SDavid du Colombier 		}
3423e12c5d1SDavid du Colombier 	}
3433e12c5d1SDavid du Colombier 	for(;;){
3443e12c5d1SDavid du Colombier 		p = Brdline(&bin, '\n');
3453e12c5d1SDavid du Colombier 		if (p == 0) {
3463e12c5d1SDavid du Colombier 			if(gotop>curp){
3473e12c5d1SDavid du Colombier 				gotop = curp;
3483e12c5d1SDavid du Colombier 				goto restart;
3493e12c5d1SDavid du Colombier 			}
3503e12c5d1SDavid du Colombier 			return 0;
3513e12c5d1SDavid du Colombier 		} else if (*p == 'p') {
3523e12c5d1SDavid du Colombier 			lastp = curp = atoi(p+1);
3533e12c5d1SDavid du Colombier 			addpage(lastp);	/* maybe 1 too high */
3543e12c5d1SDavid du Colombier 			if (curp>=gotop)
3553e12c5d1SDavid du Colombier 				return 1;
3563e12c5d1SDavid du Colombier 		}
3573e12c5d1SDavid du Colombier 	}
3583e12c5d1SDavid du Colombier }
3593e12c5d1SDavid du Colombier 
3603e12c5d1SDavid du Colombier static void
3613e12c5d1SDavid du Colombier wiggly(int skip)
3623e12c5d1SDavid du Colombier {
3633e12c5d1SDavid du Colombier 	Point p[300];
3643e12c5d1SDavid du Colombier 	int c,i,n;
3653e12c5d1SDavid du Colombier 	for (n = 1; (c = BGETC(&bin)) != '\n' && c>=0; n++) {
3663e12c5d1SDavid du Colombier 		Bungetc(&bin);
3673e12c5d1SDavid du Colombier 		p[n].x = getn();
3683e12c5d1SDavid du Colombier 		p[n].y = getn();
3693e12c5d1SDavid du Colombier 	}
3703e12c5d1SDavid du Colombier 	p[0] = Pt(hpos, vpos);
3713e12c5d1SDavid du Colombier 	for (i = 1; i < n; i++)
3723e12c5d1SDavid du Colombier 		p[i] = add(p[i],p[i-1]);
3733e12c5d1SDavid du Colombier 	hpos = p[n-1].x;
3743e12c5d1SDavid du Colombier 	vpos = p[n-1].y;
3753e12c5d1SDavid du Colombier 	for (i = 0; i < n; i++)
3763e12c5d1SDavid du Colombier 		p[i] = scale(p[i]);
3773e12c5d1SDavid du Colombier 	if (!skip)
3783e12c5d1SDavid du Colombier 		spline(&screen,n,p,Mode);
3793e12c5d1SDavid du Colombier }
3803e12c5d1SDavid du Colombier 
3813e12c5d1SDavid du Colombier static void
3823e12c5d1SDavid du Colombier devcntrl(void)	/* interpret device control functions */
3833e12c5d1SDavid du Colombier {
3843e12c5d1SDavid du Colombier         char str[80];
3853e12c5d1SDavid du Colombier 	int n;
3863e12c5d1SDavid du Colombier 
3873e12c5d1SDavid du Colombier 	getstr(str);
3883e12c5d1SDavid du Colombier 	switch (str[0]) {	/* crude for now */
3893e12c5d1SDavid du Colombier 	case 'i':	/* initialize */
3903e12c5d1SDavid du Colombier 		break;
3913e12c5d1SDavid du Colombier 	case 'T':	/* device name */
3923e12c5d1SDavid du Colombier 		getstr(devname);
3933e12c5d1SDavid du Colombier 		break;
3943e12c5d1SDavid du Colombier 	case 't':	/* trailer */
3953e12c5d1SDavid du Colombier 		break;
3963e12c5d1SDavid du Colombier 	case 'p':	/* pause -- can restart */
3973e12c5d1SDavid du Colombier 		break;
3983e12c5d1SDavid du Colombier 	case 's':	/* stop */
3993e12c5d1SDavid du Colombier 		break;
4003e12c5d1SDavid du Colombier 	case 'r':	/* resolution assumed when prepared */
4013e12c5d1SDavid du Colombier 		res=getn();
4023e12c5d1SDavid du Colombier 		DIV = floor(.5 + res/(100.0*mag));
4033e12c5d1SDavid du Colombier 		if (DIV < 1)
4043e12c5d1SDavid du Colombier 			DIV = 1;
4053e12c5d1SDavid du Colombier 		mag = res/(100.0*DIV); /* adjust mag according to DIV coarseness */
4063e12c5d1SDavid du Colombier 		break;
4073e12c5d1SDavid du Colombier 	case 'f':	/* font used */
4083e12c5d1SDavid du Colombier 		n = getn();
4093e12c5d1SDavid du Colombier 		getstr(str);
4103e12c5d1SDavid du Colombier 		loadfontname(n, str);
4113e12c5d1SDavid du Colombier 		break;
4123e12c5d1SDavid du Colombier 	/* these don't belong here... */
4133e12c5d1SDavid du Colombier 	case 'H':	/* char height */
4143e12c5d1SDavid du Colombier 		break;
4153e12c5d1SDavid du Colombier 	case 'S':	/* slant */
4163e12c5d1SDavid du Colombier 		break;
4173e12c5d1SDavid du Colombier 	case 'X':
4183e12c5d1SDavid du Colombier 		break;
4193e12c5d1SDavid du Colombier 	}
4203e12c5d1SDavid du Colombier 	eatline();
4213e12c5d1SDavid du Colombier }
4223e12c5d1SDavid du Colombier 
423*219b2ee8SDavid du Colombier int
424*219b2ee8SDavid du Colombier isspace(int c)
425*219b2ee8SDavid du Colombier {
426*219b2ee8SDavid du Colombier 	return c==' ' || c=='\t' || c=='\n';
427*219b2ee8SDavid du Colombier }
428*219b2ee8SDavid du Colombier 
4293e12c5d1SDavid du Colombier static void
4303e12c5d1SDavid du Colombier getstr(char *is)
4313e12c5d1SDavid du Colombier {
4323e12c5d1SDavid du Colombier 	uchar *s = (uchar *) is;
4333e12c5d1SDavid du Colombier 
4343e12c5d1SDavid du Colombier 	for (*s = BGETC(&bin); isspace(*s); *s = BGETC(&bin))
4353e12c5d1SDavid du Colombier 		;
4363e12c5d1SDavid du Colombier 	for (; !isspace(*s); *++s = BGETC(&bin))
4373e12c5d1SDavid du Colombier 		;
4383e12c5d1SDavid du Colombier 	Bungetc(&bin);
4393e12c5d1SDavid du Colombier 	*s = 0;
4403e12c5d1SDavid du Colombier }
4413e12c5d1SDavid du Colombier 
4423e12c5d1SDavid du Colombier static void
4433e12c5d1SDavid du Colombier getutf(char *s)		/* get next utf char, as bytes */
4443e12c5d1SDavid du Colombier {
4453e12c5d1SDavid du Colombier 	int c, i;
4463e12c5d1SDavid du Colombier 
4473e12c5d1SDavid du Colombier 	for (i=0;;) {
4483e12c5d1SDavid du Colombier 		c = BGETC(&bin);
4493e12c5d1SDavid du Colombier 		if (c < 0)
4503e12c5d1SDavid du Colombier 			return;
4513e12c5d1SDavid du Colombier 		s[i++] = c;
4523e12c5d1SDavid du Colombier 
4533e12c5d1SDavid du Colombier 		if (fullrune(s, i)) {
4543e12c5d1SDavid du Colombier 			s[i] = 0;
4553e12c5d1SDavid du Colombier 			return;
4563e12c5d1SDavid du Colombier 		}
4573e12c5d1SDavid du Colombier 	}
4583e12c5d1SDavid du Colombier }
4593e12c5d1SDavid du Colombier 
4603e12c5d1SDavid du Colombier static void
4613e12c5d1SDavid du Colombier eatline(void)
4623e12c5d1SDavid du Colombier {
4633e12c5d1SDavid du Colombier 	int c;
4643e12c5d1SDavid du Colombier 
4653e12c5d1SDavid du Colombier 	while ((c=BGETC(&bin)) != '\n' && c >= 0)
4663e12c5d1SDavid du Colombier 		;
4673e12c5d1SDavid du Colombier }
4683e12c5d1SDavid du Colombier 
4693e12c5d1SDavid du Colombier static int
4703e12c5d1SDavid du Colombier getn(void)
4713e12c5d1SDavid du Colombier {
4723e12c5d1SDavid du Colombier 	int n, c, sign;
4733e12c5d1SDavid du Colombier 
4743e12c5d1SDavid du Colombier 	while (c = BGETC(&bin))
4753e12c5d1SDavid du Colombier 		if (!isspace(c))
4763e12c5d1SDavid du Colombier 			break;
477*219b2ee8SDavid du Colombier 	if(c == '-'){
4783e12c5d1SDavid du Colombier 		sign = -1;
4793e12c5d1SDavid du Colombier 		c = BGETC(&bin);
480*219b2ee8SDavid du Colombier 	}else
4813e12c5d1SDavid du Colombier 		sign = 1;
482*219b2ee8SDavid du Colombier 	for (n = 0; '0'<=c && c<='9'; c = BGETC(&bin))
4833e12c5d1SDavid du Colombier 		n = n*10 + c - '0';
4843e12c5d1SDavid du Colombier 	while (c == ' ')
4853e12c5d1SDavid du Colombier 		c = BGETC(&bin);
4863e12c5d1SDavid du Colombier 	Bungetc(&bin);
4873e12c5d1SDavid du Colombier 	return(n*sign);
4883e12c5d1SDavid du Colombier }
4893e12c5d1SDavid du Colombier 
4903e12c5d1SDavid du Colombier static int
4913e12c5d1SDavid du Colombier botpage(int np)	/* called at bottom of page np-1 == top of page np */
4923e12c5d1SDavid du Colombier {
4933e12c5d1SDavid du Colombier 	char *p;
4943e12c5d1SDavid du Colombier 	int n;
4953e12c5d1SDavid du Colombier 
4963e12c5d1SDavid du Colombier 	while (p = getcmdstr()) {
4973e12c5d1SDavid du Colombier 		if (*p == '\0')
4983e12c5d1SDavid du Colombier 			return 0;
4993e12c5d1SDavid du Colombier 		if (*p == 'q')
5003e12c5d1SDavid du Colombier 			exits(p);
5013e12c5d1SDavid du Colombier 		if (*p == 'c')		/* nop */
5023e12c5d1SDavid du Colombier 			continue;
5033e12c5d1SDavid du Colombier 		if (*p == 'm') {
5043e12c5d1SDavid du Colombier 			mag = atof(p+1);
5053e12c5d1SDavid du Colombier 			if (mag <= .1 || mag >= 10)
5063e12c5d1SDavid du Colombier 				mag = DEFMAG;
5073e12c5d1SDavid du Colombier 			allfree();	/* zap fonts */
5083e12c5d1SDavid du Colombier 			DIV = floor(.5 + res/(100.0*mag));
5093e12c5d1SDavid du Colombier 			if (DIV < 1)
5103e12c5d1SDavid du Colombier 				DIV = 1;
5113e12c5d1SDavid du Colombier 			mag = res/(100.0*DIV);
5123e12c5d1SDavid du Colombier 			return skipto(np-1, np);	/* reprint the page */
5133e12c5d1SDavid du Colombier 		}
5143e12c5d1SDavid du Colombier 		if (*p == 'x') {
5153e12c5d1SDavid du Colombier 			xyoffset.x += atoi(p+1)*100;
5163e12c5d1SDavid du Colombier 			skipto(np-1, np);
5173e12c5d1SDavid du Colombier 			return 1;
5183e12c5d1SDavid du Colombier 		}
5193e12c5d1SDavid du Colombier 		if (*p == 'y') {
5203e12c5d1SDavid du Colombier 			xyoffset.y += atoi(p+1)*100;
5213e12c5d1SDavid du Colombier 			skipto(np-1, np);
5223e12c5d1SDavid du Colombier 			return 1;
5233e12c5d1SDavid du Colombier 		}
5243e12c5d1SDavid du Colombier 		if (*p == '/') {	/* divide into n pieces */
5253e12c5d1SDavid du Colombier 			nview = atoi(p+1);
5263e12c5d1SDavid du Colombier 			if (nview < 1)
5273e12c5d1SDavid du Colombier 				nview = 1;
5283e12c5d1SDavid du Colombier 			else if (nview > MAXVIEW)
5293e12c5d1SDavid du Colombier 				nview = MAXVIEW;
5303e12c5d1SDavid du Colombier 			return skipto(np-1, np);
5313e12c5d1SDavid du Colombier 		}
5323e12c5d1SDavid du Colombier 		if (*p == 'p') {
5333e12c5d1SDavid du Colombier 			if (p[1] == '\0')	/* bare 'p' */
5343e12c5d1SDavid du Colombier 				return skipto(np-1, np);
5353e12c5d1SDavid du Colombier 			p++;
5363e12c5d1SDavid du Colombier 		}
537*219b2ee8SDavid du Colombier 		if ('0'<=*p && *p<='9') {
5383e12c5d1SDavid du Colombier 			n = atoi(p);
5393e12c5d1SDavid du Colombier 			return skipto(n, np);
5403e12c5d1SDavid du Colombier 		}
5413e12c5d1SDavid du Colombier 		if (*p == '-' || *p == '+') {
5423e12c5d1SDavid du Colombier 			n = atoi(p);
5433e12c5d1SDavid du Colombier 			if (n == 0)
5443e12c5d1SDavid du Colombier 				n = *p == '-' ? -1 : 1;
5453e12c5d1SDavid du Colombier 			return skipto(np - 1 + n, np);
5463e12c5d1SDavid du Colombier 		}
5473e12c5d1SDavid du Colombier 		if (*p == 'd') {
5483e12c5d1SDavid du Colombier 			dbg = 1 - dbg;
5493e12c5d1SDavid du Colombier 			continue;
5503e12c5d1SDavid du Colombier 		}
5513e12c5d1SDavid du Colombier 
5523e12c5d1SDavid du Colombier 		fprint(2, "illegal;  try q, 17, +2, -1, p, m.7, /2, x1, y-.5 or return\n");
5533e12c5d1SDavid du Colombier 	}
5543e12c5d1SDavid du Colombier 	return 0;
5553e12c5d1SDavid du Colombier }
556