plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

htroff.c (10511B)


      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
     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
     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
     98 clearview(Rectangle r)
     99 {
    100 	draw(screen, r, display->white, nil, r.min);
    101 }
    102 
    103 int resized;
    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
    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
    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
    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
    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
    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
    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
    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
    439 isspace(int c)
    440 {
    441 	return c==' ' || c=='\t' || c=='\n';
    442 }
    443 
    444 static void
    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
    478 eatline(void)
    479 {
    480 	int c;
    481 
    482 	while ((c=getc()) != '\n' && c >= 0)
    483 		;
    484 }
    485 
    486 static int
    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
    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 }