1 #include	<u.h>
2 #include	<libc.h>
3 #include	<draw.h>
4 #include	<cursor.h>
5 #include	<event.h>
6 #include	<bio.h>
7 #include	"proof.h"
8 
9 int	res;
10 int	hpos;
11 int	vpos;
12 int	DIV = 11;
13 
14 Point offset;
15 Point xyoffset = { 0,0 };
16 
17 Rectangle	view[MAXVIEW];
18 Rectangle	bound[MAXVIEW];		/* extreme points */
19 int	nview = 1;
20 
21 int	lastp;	/* last page number we were on */
22 
23 #define	NPAGENUMS	200
24 struct pagenum {
25 	int	num;
26 	long	adr;
27 } pagenums[NPAGENUMS];
28 int	npagenums;
29 
30 int	curfont, cursize;
31 
32 char	*getcmdstr(void);
33 
34 static void	initpage(void);
35 static void	view_setup(int);
36 static Point	scale(Point);
37 static void	clearview(Rectangle);
38 static int	addpage(int);
39 static void	spline(Image *, int, Point *);
40 static int	skipto(int, int);
41 static void	wiggly(int);
42 static void	devcntrl(void);
43 static void	eatline(void);
44 static int	getn(void);
45 static int	botpage(int);
46 static void	getstr(char *);
47 /*
48 static void	getutf(char *);
49 */
50 
51 #define Do screen->r.min
52 #define Dc screen->r.max
53 
54 /* declarations and definitions of font stuff are in font.c and main.c */
55 
56 static void
initpage(void)57 initpage(void)
58 {
59 	int i;
60 
61 	view_setup(nview);
62 	for (i = 0; i < nview-1; i++)
63 		draw(screen, view[i], screen, nil, view[i+1].min);
64 	clearview(view[nview-1]);
65 	offset = view[nview-1].min;
66 	vpos = 0;
67 }
68 
69 static void
view_setup(int n)70 view_setup(int n)
71 {
72 	int i, j, v, dx, dy, r, c;
73 
74 	switch (n) {
75 	case 1: r = 1; c = 1; break;
76 	case 2: r = 1; c = 2; break;
77 	case 3: r = 1; c = 3; break;
78 	case 4: r = 2; c = 2; break;
79 	case 5: case 6: r = 2; c = 3; break;
80 	case 7: case 8: case 9: r = 3; c = 3; break;
81 	default: r = (n+2)/3; c = 3; break; /* finking out */
82 	}
83 	dx = (Dc.x - Do.x) / c;
84 	dy = (Dc.y - Do.y) / r;
85 	v = 0;
86 	for (i = 0; i < r && v < n; i++)
87 		for (j = 0; j < c && v < n; j++) {
88 			view[v] = screen->r;
89 			view[v].min.x = Do.x + j * dx;
90 			view[v].max.x = Do.x + (j+1) * dx;
91 			view[v].min.y = Do.y + i * dy;
92 			view[v].max.y = Do.y + (i+1) * dy;
93 			v++;
94 		}
95 }
96 
97 static void
clearview(Rectangle r)98 clearview(Rectangle r)
99 {
100 	draw(screen, r, display->white, nil, r.min);
101 }
102 
103 int resized;
eresized(int new)104 void eresized(int new)
105 {
106 	/* this is called if we are resized */
107 	if(new && getwindow(display, Refnone) < 0)
108 		drawerror(display, "can't reattach to window");
109 	initpage();
110 	resized = 1;
111 }
112 
113 static Point
scale(Point p)114 scale(Point p)
115 {
116 	p.x /= DIV;
117 	p.y /= DIV;
118 	return addpt(xyoffset, addpt(offset,p));
119 }
120 
121 static int
addpage(int n)122 addpage(int n)
123 {
124 	int i;
125 
126 	for (i = 0; i < npagenums; i++)
127 		if (n == pagenums[i].num)
128 			return i;
129 	if (npagenums < NPAGENUMS-1) {
130 		pagenums[npagenums].num = n;
131 		pagenums[npagenums].adr = offsetc();
132 		npagenums++;
133 	}
134 	return npagenums;
135 }
136 
137 void
readpage(void)138 readpage(void)
139 {
140 	int c, i, a, alpha, phi;
141 	static int first = 0;
142 	int m, n, gonow = 1;
143 	Rune r[32], t;
144 	Point p,q,qq;
145 
146 	offset = screen->clipr.min;
147 	esetcursor(&deadmouse);
148 	while (gonow)
149 	{
150 		c = getc();
151 		switch (c)
152 		{
153 		case -1:
154 			esetcursor(0);
155 			if (botpage(lastp+1)) {
156 				initpage();
157 				break;
158 			}
159 			exits(0);
160 		case 'p':	/* new page */
161 			lastp = getn();
162 			addpage(lastp);
163 			if (first++ > 0) {
164 				esetcursor(0);
165 				botpage(lastp);
166 				esetcursor(&deadmouse);
167 			}
168 			initpage();
169 			break;
170 		case '\n':	/* when input is text */
171 		case ' ':
172 		case 0:		/* occasional noise creeps in */
173 			break;
174 		case '0': case '1': case '2': case '3': case '4':
175 		case '5': case '6': case '7': case '8': case '9':
176 			/* two motion digits plus a character */
177 			hpos += (c-'0')*10 + getc()-'0';
178 
179 		/* FALLS THROUGH */
180 		case 'c':	/* single ascii character */
181 			r[0] = getrune();
182 			r[1] = 0;
183 			dochar(r);
184 			break;
185 
186 		case 'C':
187 			for(i=0; ; i++){
188 				t = getrune();
189 				if(isspace(t))
190 					break;
191 				r[i] = t;
192 			}
193 			r[i] = 0;
194 			dochar(r);
195 			break;
196 
197 		case 'N':
198 			r[0] = getn();
199 			r[1] = 0;
200 			dochar(r);
201 			break;
202 
203 		case 'D':	/* draw function */
204 			switch (getc())
205 			{
206 			case 'l':	/* draw a line */
207 				n = getn();
208 				m = getn();
209 				p = Pt(hpos,vpos);
210 				q = addpt(p, Pt(n,m));
211 				hpos += n;
212 				vpos += m;
213 				line(screen, scale(p), scale(q), 0, 0, 0, display->black, ZP);
214 				break;
215 			case 'c':	/* circle */
216 				/*nop*/
217 				m = getn()/2;
218 				p = Pt(hpos+m,vpos);
219 				hpos += 2*m;
220 				ellipse(screen, scale(p), m/DIV, m/DIV, 0, display->black, ZP);
221 				/* p=currentpt; p.x+=dmap(m/2);circle bp,p,a,ONES,Mode*/
222 				break;
223 			case 'e':	/* ellipse */
224 				/*nop*/
225 				m = getn()/2;
226 				n = getn()/2;
227 				p = Pt(hpos+m,vpos);
228 				hpos += 2*m;
229 				ellipse(screen, scale(p), m/DIV, n/DIV, 0, display->black, ZP);
230 				break;
231 			case 'a':	/* arc */
232 				p = scale(Pt(hpos,vpos));
233 				n = getn();
234 				m = getn();
235 				hpos += n;
236 				vpos += m;
237 				q = scale(Pt(hpos,vpos));
238 				n = getn();
239 				m = getn();
240 				hpos += n;
241 				vpos += m;
242 				qq = scale(Pt(hpos,vpos));
243 				/*
244 				  * tricky: convert from 3-point clockwise to
245 				  * center, angle1, delta-angle counterclockwise.
246 				 */
247 				a = hypot(qq.x-q.x, qq.y-q.y);
248 				phi = atan2(q.y-p.y, p.x-q.x)*180./PI;
249 				alpha = atan2(q.y-qq.y, qq.x-q.x)*180./PI - phi;
250 				if(alpha < 0)
251 					alpha += 360;
252 				arc(screen, q, a, a, 0, display->black, ZP, phi, alpha);
253 				break;
254 			case '~':	/* wiggly line */
255 				wiggly(0);
256 				break;
257 			default:
258 				break;
259 			}
260 			eatline();
261 			break;
262 		case 's':
263 			n = getn();	/* ignore fractional sizes */
264 			if (cursize == n)
265 				break;
266 			cursize = n;
267 			if (cursize >= NFONT)
268 				cursize = NFONT-1;
269 			break;
270 		case 'f':
271 			curfont = getn();
272 			break;
273 		case 'H':	/* absolute horizontal motion */
274 			hpos = getn();
275 			break;
276 		case 'h':	/* relative horizontal motion */
277 			hpos += getn();
278 			break;
279 		case 'w':	/* word space */
280 			break;
281 		case 'V':
282 			vpos = getn();
283 			break;
284 		case 'v':
285 			vpos += getn();
286 			break;
287 		case '#':	/* comment */
288 		case 'n':	/* end of line */
289 			eatline();
290 			break;
291 		case 'x':	/* device control */
292 			devcntrl();
293 			break;
294 		default:
295 			fprint(2, "unknown input character %o %c at offset %lud\n", c, c, offsetc());
296 			exits("bad char");
297 		}
298 	}
299 	esetcursor(0);
300 }
301 
302 static void
spline(Image * b,int n,Point * pp)303 spline(Image *b, int n, Point *pp)
304 {
305 	long w, t1, t2, t3, fac=1000;
306 	int i, j, steps=10;
307 	Point p, q;
308 
309 	for (i = n; i > 0; i--)
310 		pp[i] = pp[i-1];
311 	pp[n+1] = pp[n];
312 	n += 2;
313 	p = pp[0];
314 	for(i = 0; i < n-2; i++)
315 	{
316 		for(j = 0; j < steps; j++)
317 		{
318 			w = fac * j / steps;
319 			t1 = w * w / (2 * fac);
320 			w = w - fac/2;
321 			t2 = 3*fac/4 - w * w / fac;
322 			w = w - fac/2;
323 			t3 = w * w / (2*fac);
324 			q.x = (t1*pp[i+2].x + t2*pp[i+1].x +
325 				t3*pp[i].x + fac/2) / fac;
326 			q.y = (t1*pp[i+2].y + t2*pp[i+1].y +
327 				t3*pp[i].y + fac/2) / fac;
328 			line(b, p, q, 0, 0, 0, display->black, ZP);
329 			p = q;
330 		}
331 	}
332 }
333 
334 /* Have to parse skipped pages, to find out what fonts are loaded. */
335 static int
skipto(int gotop,int curp)336 skipto(int gotop, int curp)
337 {
338 	char *p;
339 	int i;
340 
341 	if (gotop == curp)
342 		return 1;
343 	for (i = 0; i < npagenums; i++)
344 		if (pagenums[i].num == gotop) {
345 			if (seekc(pagenums[i].adr) == Beof) {
346 				fprint(2, "can't rewind input\n");
347 				return 0;
348 			}
349 			return 1;
350 		}
351 	if (gotop <= curp) {
352 	    restart:
353 		if (seekc(0) == Beof) {
354 			fprint(2, "can't rewind input\n");
355 			return 0;
356 		}
357 	}
358 	for(;;){
359 		p = rdlinec();
360 		if (p == 0) {
361 			if(gotop>curp){
362 				gotop = curp;
363 				goto restart;
364 			}
365 			return 0;
366 		} else if (*p == 'p') {
367 			lastp = curp = atoi(p+1);
368 			addpage(lastp);	/* maybe 1 too high */
369 			if (curp>=gotop)
370 				return 1;
371 		}
372 	}
373 }
374 
375 static void
wiggly(int skip)376 wiggly(int skip)
377 {
378 	Point p[300];
379 	int c,i,n;
380 	for (n = 1; (c = getc()) != '\n' && c>=0; n++) {
381 		ungetc();
382 		p[n].x = getn();
383 		p[n].y = getn();
384 	}
385 	p[0] = Pt(hpos, vpos);
386 	for (i = 1; i < n; i++)
387 		p[i] = addpt(p[i],p[i-1]);
388 	hpos = p[n-1].x;
389 	vpos = p[n-1].y;
390 	for (i = 0; i < n; i++)
391 		p[i] = scale(p[i]);
392 	if (!skip)
393 		spline(screen,n,p);
394 }
395 
396 static void
devcntrl(void)397 devcntrl(void)	/* interpret device control functions */
398 {
399         char str[80];
400 	int n;
401 
402 	getstr(str);
403 	switch (str[0]) {	/* crude for now */
404 	case 'i':	/* initialize */
405 		break;
406 	case 'T':	/* device name */
407 		getstr(devname);
408 		break;
409 	case 't':	/* trailer */
410 		break;
411 	case 'p':	/* pause -- can restart */
412 		break;
413 	case 's':	/* stop */
414 		break;
415 	case 'r':	/* resolution assumed when prepared */
416 		res=getn();
417 		DIV = floor(.5 + res/(100.0*mag));
418 		if (DIV < 1)
419 			DIV = 1;
420 		mag = res/(100.0*DIV); /* adjust mag according to DIV coarseness */
421 		break;
422 	case 'f':	/* font used */
423 		n = getn();
424 		getstr(str);
425 		loadfontname(n, str);
426 		break;
427 	/* these don't belong here... */
428 	case 'H':	/* char height */
429 		break;
430 	case 'S':	/* slant */
431 		break;
432 	case 'X':
433 		break;
434 	}
435 	eatline();
436 }
437 
438 int
isspace(int c)439 isspace(int c)
440 {
441 	return c==' ' || c=='\t' || c=='\n';
442 }
443 
444 static void
getstr(char * is)445 getstr(char *is)
446 {
447 	uchar *s = (uchar *) is;
448 
449 	for (*s = getc(); isspace(*s); *s = getc())
450 		;
451 	for (; !isspace(*s); *++s = getc())
452 		;
453 	ungetc();
454 	*s = 0;
455 }
456 
457 #if 0
458 static void
459 getutf(char *s)		/* get next utf char, as bytes */
460 {
461 	int c, i;
462 
463 	for (i=0;;) {
464 		c = getc();
465 		if (c < 0)
466 			return;
467 		s[i++] = c;
468 
469 		if (fullrune(s, i)) {
470 			s[i] = 0;
471 			return;
472 		}
473 	}
474 }
475 #endif
476 
477 static void
eatline(void)478 eatline(void)
479 {
480 	int c;
481 
482 	while ((c=getc()) != '\n' && c >= 0)
483 		;
484 }
485 
486 static int
getn(void)487 getn(void)
488 {
489 	int n, c, sign;
490 
491 	while (c = getc())
492 		if (!isspace(c))
493 			break;
494 	if(c == '-'){
495 		sign = -1;
496 		c = getc();
497 	}else
498 		sign = 1;
499 	for (n = 0; '0'<=c && c<='9'; c = getc())
500 		n = n*10 + c - '0';
501 	while (c == ' ')
502 		c = getc();
503 	ungetc();
504 	return(n*sign);
505 }
506 
507 static int
botpage(int np)508 botpage(int np)	/* called at bottom of page np-1 == top of page np */
509 {
510 	char *p;
511 	int n;
512 
513 	while (p = getcmdstr()) {
514 		if (*p == '\0')
515 			return 0;
516 		if (*p == 'q')
517 			exits(p);
518 		if (*p == 'c')		/* nop */
519 			continue;
520 		if (*p == 'm') {
521 			mag = atof(p+1);
522 			if (mag <= .1 || mag >= 10)
523 				mag = DEFMAG;
524 			allfree();	/* zap fonts */
525 			DIV = floor(.5 + res/(100.0*mag));
526 			if (DIV < 1)
527 				DIV = 1;
528 			mag = res/(100.0*DIV);
529 			return skipto(np-1, np);	/* reprint the page */
530 		}
531 		if (*p == 'x') {
532 			xyoffset.x += atoi(p+1)*100;
533 			skipto(np-1, np);
534 			return 1;
535 		}
536 		if (*p == 'y') {
537 			xyoffset.y += atoi(p+1)*100;
538 			skipto(np-1, np);
539 			return 1;
540 		}
541 		if (*p == '/') {	/* divide into n pieces */
542 			nview = atoi(p+1);
543 			if (nview < 1)
544 				nview = 1;
545 			else if (nview > MAXVIEW)
546 				nview = MAXVIEW;
547 			return skipto(np-1, np);
548 		}
549 		if (*p == 'p') {
550 			if (p[1] == '\0'){	/* bare 'p' */
551 				if(skipto(np-1, np))
552 					return 1;
553 				continue;
554 			}
555 			p++;
556 		}
557 		if ('0'<=*p && *p<='9') {
558 			n = atoi(p);
559 			if(skipto(n, np))
560 				return 1;
561 			continue;
562 		}
563 		if (*p == '-' || *p == '+') {
564 			n = atoi(p);
565 			if (n == 0)
566 				n = *p == '-' ? -1 : 1;
567 			if(skipto(np - 1 + n, np))
568 				return 1;
569 			continue;
570 		}
571 		if (*p == 'd') {
572 			dbg = 1 - dbg;
573 			continue;
574 		}
575 
576 		fprint(2, "illegal;  try q, 17, +2, -1, p, m.7, /2, x1, y-.5 or return\n");
577 	}
578 	return 0;
579 }
580