xref: /csrg-svn/old/vpr/vtools/fed/subr.c (revision 14547)
1*14547Ssam #ifndef lint
2*14547Ssam static char sccsid[] = "@(#)subr.c	4.2 (Berkeley) 08/11/83";
3*14547Ssam #endif
4*14547Ssam 
511508Sralph /*
611508Sralph  * subr.c: general subroutines for fed.
711508Sralph  */
811508Sralph 
911508Sralph #include "fed.h"
1011508Sralph 
1111508Sralph /*
1211508Sralph  * initialize: various one time initializations.
1311508Sralph  */
initialize()1411508Sralph initialize()
1511508Sralph {
1611508Sralph 	register int i, j;
1711508Sralph 	register char *cp;
1811508Sralph 
1911508Sralph 	/* Initialize random variables */
2011508Sralph 	curwind = -1;
2111508Sralph 	pencolor = 1;
2211508Sralph 	penweight = 0;
2311508Sralph 
2411508Sralph 	/*
2511508Sralph 	 * Initialize value of sqrtmat.  This is a constant table
2611508Sralph 	 * so we don't have to redo all these square roots when the pen
2711508Sralph 	 * changes every time.
2811508Sralph 	 */
2911508Sralph 	for (i=0; i<10; i++) {
3011508Sralph 		for (j=0; j<10; j++) {
3111508Sralph 			sqrtmat[i][j] = sqrt((float) i*i + j*j);
3211508Sralph 		}
3311508Sralph 	}
3411508Sralph 
3511508Sralph 	/* Initialize base locations on screen. These remain fixed. */
3611508Sralph 	for (i=0; i<NROW; i++)
3711508Sralph 		for (j=0; j<NCOL; j++) {
3811508Sralph 			base[NCOL*i+j].c = (GLCOL+GLPAD) * j + 1;
3911508Sralph 			base[NCOL*i+j].r = SCRHI - (GLROW+GLPAD+10) * i - GLROW - 3;
4011508Sralph 		}
4111508Sralph 
4211508Sralph 	setbuf(stdout, stoutbuf);
4311508Sralph 
4411508Sralph 	curzoom = 1;	/* default is zoomed completely out */
4511508Sralph 	ttyinit();
4611508Sralph }
4711508Sralph 
4811508Sralph /*
4911508Sralph  * showfont: Wipe clean the screen, display the font
5011508Sralph  * in a properly spaced fashion, wait for a char to be typed, if it's
5111508Sralph  * p print the font, then clear the screen and ungetc the char.
5211508Sralph  */
showfont()5311508Sralph showfont()
5411508Sralph {
5511508Sralph 	register int i, cr, cc, nc;
5611508Sralph 	int roff, coff;
5711508Sralph 	char maxc, minc;
5811508Sralph 	char nextcmd;
5911508Sralph 	char tmpbuf[WINDSIZE];
6011508Sralph 
6111508Sralph 	zoomout();
6211508Sralph 	message("Show font from <char>");
6311508Sralph 	minc = inchar();
6411508Sralph 	sprintf(msgbuf, "Show font from %s to <char>", rdchar(minc));
6511508Sralph 	message(msgbuf);
6611508Sralph 	maxc = inchar();
6711508Sralph 
6811508Sralph 	clearg();
6911508Sralph 	zermat(tmpbuf, GLROW, GLCOL);
7011508Sralph 	cr = SCRHI-GLROW; cc = 3;
7111508Sralph 	for (i=minc; i<=maxc; i++) {
7211508Sralph 		if (disptable[i].nbytes) {
7311508Sralph 			/*
7411508Sralph 			 * We really should try to find out how far to the
7511508Sralph 			 * left the glyph goes so we don't run off the left
7611508Sralph 			 * end of the screen, but this is hard, so we fake it.
7711508Sralph 			 * Usually glyphs don't run past the left so it's OK.
7811508Sralph 			 */
7911508Sralph 			if (cc - disptable[i].left < 0)
8011508Sralph 				cc = disptable[i].left;
8111508Sralph 			nc = cc + disptable[i].width;
8211508Sralph 			if (nc >= SCRWID) {
8311508Sralph 				cc = 0;
8411508Sralph 				nc = disptable[i].width;
8511508Sralph 				cr -= 85; /* Should be GLROW but 4*100>360 */
8611508Sralph 				if (cr < 0)
8711508Sralph 					break;	/* Screen full.  Just stop. */
8811508Sralph 			}
8911508Sralph 			dispmsg(rdchar(i), cc, cr, 2);
9011508Sralph 			placechar(i, cr+BASELINE, cc, tmpbuf);
9111508Sralph 			cc = nc;
9211508Sralph 		}
9311508Sralph 	}
9411508Sralph 	for (;;) {
9511508Sralph 		nextcmd = inchar();
9611508Sralph 		if (nextcmd != 'p')
9711508Sralph 			break;
9811508Sralph 		printg();
9911508Sralph 	}
10011508Sralph 	if (nextcmd != 'Q' && nextcmd != 'E' && nextcmd != 'N')
10111508Sralph 		redraw();
10211508Sralph 	else
10311508Sralph 		clearg();
10411508Sralph 	ungetc(nextcmd, stdin);
10511508Sralph }
10611508Sralph 
10711508Sralph /*
10811508Sralph  * typein: Like showfont but takes a line of text from the user
10911508Sralph  * and "typesets" it on the screen.
11011508Sralph  */
typein()11111508Sralph typein()
11211508Sralph {
11311508Sralph 	register int i, cr, cc, nc;
11411508Sralph 	char *p;
11511508Sralph 	int roff, coff;
11611508Sralph 	char maxc, minc;
11711508Sralph 	char nextcmd;
11811508Sralph 	char tmpbuf[WINDSIZE];
11911508Sralph 	char msgtype[100];
12011508Sralph 
12111508Sralph 	zoomout();
12211508Sralph 	readline("Input line to be typeset: ", msgtype, sizeof msgtype);
12311508Sralph 
12411508Sralph 	clearg();
12511508Sralph 	zermat(tmpbuf, GLROW, GLCOL);
12611508Sralph 	cr = SCRHI-GLROW; cc = 3;
12711508Sralph 	for (p=msgtype; *p; p++) {
12811508Sralph 		i = *p;
12911508Sralph 		if (disptable[i].nbytes) {
13011508Sralph 			if (cc - disptable[i].left < 0)
13111508Sralph 				cc = disptable[i].left;
13211508Sralph 			nc = cc + disptable[i].width;
13311508Sralph 			if (nc >= SCRWID) {
13411508Sralph 				cc = 0;
13511508Sralph 				nc = disptable[i].width;
13611508Sralph 				cr -= 85; /* Should be GLROW but 4*100>360 */
13711508Sralph 				if (cr < 0)
13811508Sralph 					break;	/* Screen full.  Just stop. */
13911508Sralph 			}
14011508Sralph 			dispmsg(rdchar(i), cc, cr, 2);
14111508Sralph 			placechar(i, cr+BASELINE, cc, tmpbuf);
14211508Sralph 			cc = nc;
14311508Sralph 		}
14411508Sralph 	}
14511508Sralph 	for (;;) {
14611508Sralph 		nextcmd = inchar();
14711508Sralph 		if (nextcmd != 'p')
14811508Sralph 			break;
14911508Sralph 		printg();
15011508Sralph 	}
15111508Sralph 	if (nextcmd != 'Q' && nextcmd != 'E' && nextcmd != 'N')
15211508Sralph 		redraw();
15311508Sralph 	else
15411508Sralph 		clearg();
15511508Sralph 	ungetc(nextcmd, stdin);
15611508Sralph }
15711508Sralph 
15811508Sralph /*
15911508Sralph  * placechar: draw the character ch at position (llr, llc) on the screen.
16011508Sralph  * Position means the logical center of the character.  zero is a GLROW x GLCOL
16111508Sralph  * matrix of zeros which is needed for comparison, that is, we assume that
16211508Sralph  * the spot on the screen where this is going is blank, so the chars better
16311508Sralph  * not overlap.
16411508Sralph  */
placechar(ch,llr,llc,zero)16511508Sralph placechar(ch, llr, llc, zero)
16611508Sralph int ch;
16711508Sralph int llr, llc;
16811508Sralph bitmat zero;
16911508Sralph {
17011508Sralph 	bitmat glbuf;
17111508Sralph 	int roff, coff;
17211508Sralph 
17311508Sralph 	glbuf = findbits(ch, GLROW, GLCOL, 0, 0, &roff, &coff);
17411508Sralph 	if (glbuf == NULL)
17511508Sralph 		return;
17611508Sralph 	if (trace)
17711508Sralph 		fprintf(trace, "placechar('%s'), roff=%d, coff=%d, llr=%d, llc=%d, down=%d, left=%d, r=%d, c=%d\n", rdchar(ch), roff, coff, llr, llc, disptable[ch].down, disptable[ch].left, llr-disptable[ch].down, llc-disptable[ch].left);
17811508Sralph 
17911508Sralph 	update(zero, glbuf, GLROW, GLCOL, llr-GLROW+roff, llc-coff);
18011508Sralph 	if (trace)
18111508Sralph 		fprintf(trace, "placechar, free %x\n", glbuf);
18211508Sralph 	free(glbuf);
18311508Sralph }
18411508Sralph 
18511508Sralph /*
18611508Sralph  * redraw: The screen has gotten screwed up somehow.
18711508Sralph  * Assume nothing but make it look right.
18811508Sralph  */
redraw()18911508Sralph redraw()
19011508Sralph {
19111508Sralph 	register int i;
19211508Sralph 
19311508Sralph 	zoomout();
19411508Sralph 	clearg();
19511508Sralph 	turnofrb();
19611508Sralph 	for (i=0; i<NWIND; i++)
19711508Sralph 		if (wind[i].onscreen != NULL) {
19811508Sralph 			zermat(wind[i].onscreen, GLROW, GLCOL);
19911508Sralph 			syncwind(i);
20011508Sralph 
20111508Sralph 			/* Print the char at the lower left of the window */
20211508Sralph 			sprintf(msgbuf, "%s", rdchar(wind[i].used));
20311508Sralph 			dispmsg(msgbuf, base[i].c, base[i].r-11, 2);
20411508Sralph 		}
20511508Sralph 	if (curwind >= 0)
20611508Sralph 		drawbox(base[curwind].r-1, base[curwind].c-1, 1, GLROW+2, GLCOL+2);
20711508Sralph }
20811508Sralph 
20911508Sralph /*
21011508Sralph  * findbits: find the data bits of glyph c, wherever they are, and make
21111508Sralph  * nr x nc bitmat and put them in it, shifted by horoff and vertoff.
21211508Sralph  */
21311508Sralph bitmat
findbits(c,nr,nc,horoff,vertoff,rcenter,ccenter)21411508Sralph findbits(c, nr, nc, horoff, vertoff, rcenter, ccenter)
21511508Sralph int c;
21611508Sralph int nr, nc;	/* the size of the dest */
21711508Sralph int horoff, vertoff;
21811508Sralph int *rcenter, *ccenter;
21911508Sralph {
22011508Sralph 	register int i, j;
22111508Sralph 	register int r1, r2, c1, c2;
22211508Sralph 	bitmat retval, source;
22311508Sralph 	int tr, tc;	/* the size of source */
22411508Sralph 	char tmp[WINDSIZE];
22511508Sralph 
22611508Sralph 	if (trace)
22711508Sralph 		fprintf(trace, "findbits(c=%s, nr=%d, nc=%d, horoff=%d, vertoff=%d\n", rdchar(c), nr, nc, horoff, vertoff);
22811508Sralph 	if (disptable[c].nbytes == 0)
22911508Sralph 		return (NULL);
23011508Sralph 	switch (cht[c].wherewind) {
23111508Sralph 	case -2:
23211508Sralph 		if (trace)
23311508Sralph 			fprintf(trace, "case -2, saved from prev place\n");
23411508Sralph 		/* Saved from previous place */
23511508Sralph 		source = cht[c].whereat;
23611508Sralph 
23711508Sralph 		/* Ignore horoff/vertoff assuming they are already right */
23811508Sralph 		*rcenter = cht[c].rcent;
23911508Sralph 		*ccenter = cht[c].ccent;
24011508Sralph 		/*
24111508Sralph 		 * Small but important optimization: if the desired result is
24211508Sralph 		 * a whole window and the source happens to be in a whole
24311508Sralph 		 * window, just return the source pointer.  This saves
24411508Sralph 		 * lots of memory copies and happens quite often.
24511508Sralph 		 */
24611508Sralph 		if (nr == GLROW && nc == GLCOL)
24711508Sralph 			return (source);
24811508Sralph 		tr = GLROW; tc = GLCOL;
24911508Sralph 		break;
25011508Sralph 	case -1:
25111508Sralph 		if (trace)
25211508Sralph 			fprintf(trace, "case -1: first time\n");
25311508Sralph 		/* First time for this glyph: get it from font file */
25411508Sralph 		fseek(fontdes, (long) fbase+disptable[c].addr, 0);
25511508Sralph 		tr = cht[c].nrow; tc = cht[c].ncol;
25611508Sralph 		if (tr > GLROW || tc > GLCOL || disptable[c].nbytes > WINDSIZE)
25711508Sralph 			error("glyph too large for window");
25811508Sralph 		*rcenter = vertoff + disptable[c].up;
25911508Sralph 		*ccenter = horoff  + disptable[c].left;
26011508Sralph 		source = tmp;
26111508Sralph 		fread(source, disptable[c].nbytes, 1, fontdes);
26211508Sralph 		break;
26311508Sralph 	default:
26411508Sralph 		if (trace)
26511508Sralph 			fprintf(trace, "case default, in window %d", cht[c].wherewind);
26611508Sralph 		source = wind[cht[c].wherewind].val;
26711508Sralph 		tr = GLROW; tc = GLCOL;
26811508Sralph 		*rcenter = vertoff + cht[c].rcent;
26911508Sralph 		*ccenter = horoff  + cht[c].ccent;
27011508Sralph 		break;
27111508Sralph 	}
27211508Sralph 	if (trace)
27311508Sralph 		fprintf(trace, "curchar=%c=%d, tr=%d, tc=%d\n", curchar, curchar, tr, tc);
27411508Sralph 
27511508Sralph 	dumpmat("before copy, source", source, tr, tc);
27611508Sralph 	/* Copy in the bits into a bitmat of the right size */
27711508Sralph 	retval = newmat(nr, nc);
27811508Sralph 	r1 = max(0, -vertoff);
27911508Sralph 	r2 = min(GLROW-vertoff-1, GLROW-1);
28011508Sralph 	r2 = min(r2, tr-1);
28111508Sralph 	c1 = max(0, -horoff);
28211508Sralph 	c2 = min(GLCOL-horoff-1, GLCOL-1);
28311508Sralph 	c2 = min(c2, tc-1);
28411508Sralph 	if (trace)
28511508Sralph 		fprintf(trace, "findbits copy: r1=%d, r2=%d, c1=%d, c2=%d, horoff=%d, vertoff=%d\n", r1, r2, c1, c2, horoff, vertoff);
28611508Sralph 	for (i=r1; i<=r2; i++) {
28711508Sralph 		for (j=c1; j<=c2; j++)
28811508Sralph 			setmat(retval, nr, nc, i+vertoff, j+horoff, mat(source, tr, tc, i, j, 6));
28911508Sralph 	}
29011508Sralph 	dumpmat("result of copy", retval, nr, nc);
29111508Sralph 	return (retval);
29211508Sralph }
29311508Sralph 
29411508Sralph /*
29511508Sralph  * bufmod: called just before a buffer modifying command.
29611508Sralph  * Makes a backup copy of the glyph so we can undo later.
29711508Sralph  */
bufmod()29811508Sralph bufmod()
29911508Sralph {
30011508Sralph 	changes++;
30111508Sralph 	if (curwind < 0)
30211508Sralph 		return;
30311508Sralph 	if (wind[curwind].undval == NULL)
30411508Sralph 		wind[curwind].undval = newmat(GLROW, GLCOL);
30511508Sralph 	bitcopy(wind[curwind].undval, wind[curwind].val, GLROW, GLCOL);
30611508Sralph 	und_p_r = pen_r; und_p_c = pen_c;
30711508Sralph 	und_c_r = curs_r; und_c_c = curs_c;
30811508Sralph }
30911508Sralph 
31011508Sralph /*
31111508Sralph  * undo: restore the backup copy.  We just swap pointers, which is
31211508Sralph  * the same as interchanging the two matrices.  This way, undo is
31311508Sralph  * its own inverse.
31411508Sralph  */
undo()31511508Sralph undo()
31611508Sralph {
31711508Sralph 	register bitmat tmp;
31811508Sralph 
31911508Sralph 	if (wind[curwind].undval == NULL) {
32011508Sralph 		error("Nothing to undo");
32111508Sralph 	}
32211508Sralph 	tmp = wind[curwind].val;
32311508Sralph 	wind[curwind].val = wind[curwind].undval;
32411508Sralph 	wind[curwind].undval = tmp;
32511508Sralph 	pen_r = und_p_r; pen_c = und_p_c;
32611508Sralph 	move(base[curwind].c+pen_c, base[curwind].r+GLROW-pen_r);
32711508Sralph 	curs_r = und_c_r; curs_c = und_c_c;
32811508Sralph 	syncwind(curwind);
32911508Sralph 	changes++;
33011508Sralph }
33111508Sralph 
33211508Sralph /*
33311508Sralph  * drawline: draw a line of current flavor between the named two points.
33411508Sralph  * All points are relative to current window.
33511508Sralph  *
33611508Sralph  * The algorithm is that of a simple DDA.  This is similar to what the
33711508Sralph  * hardware of the HP 2648 does but the placing of the points will be
33811508Sralph  * different (because of thick pens and erasers).
33911508Sralph  */
drawline(from_r,from_c,to_r,to_c)34011508Sralph drawline(from_r, from_c, to_r, to_c)
34111508Sralph {
34211508Sralph 	int length, i;
34311508Sralph 	float x, y, xinc, yinc;
34411508Sralph 
34511508Sralph 	if (trace)
34611508Sralph 		fprintf(trace, "drawline from (%d, %d) to (%d, %d)\n", from_r, from_c, to_r, to_c);
34711508Sralph 	length = max(abs(to_r-from_r), abs(to_c-from_c));
34811508Sralph 	if (length <= 0) {
34911508Sralph 		/*
35011508Sralph 		 * The actual value doesn't matter, we're just avoiding
35111508Sralph 		 * division by zero here.
35211508Sralph 		 */
35311508Sralph 		xinc = yinc = 1.0;
35411508Sralph 	} else {
35511508Sralph 		xinc = ((float) (to_r-from_r))/length;
35611508Sralph 		yinc = ((float) (to_c-from_c))/length;
35711508Sralph 	}
35811508Sralph 	drawpoint(from_r, from_c);
35911508Sralph 	x = from_r + 0.5; y = from_c + 0.5;
36011508Sralph 
36111508Sralph 	for (i=0; i<length; i++) {
36211508Sralph 		x += xinc; y += yinc;
36311508Sralph 		drawpoint((int) x, (int) y);
36411508Sralph 	}
36511508Sralph }
36611508Sralph 
36711508Sralph /*
36811508Sralph  * drawpoint: make a point of the current flavor at (r, c).
36911508Sralph  */
drawpoint(r,c)37011508Sralph drawpoint(r, c)
37111508Sralph register int r, c;
37211508Sralph {
37311508Sralph 	register int i, j;
37411508Sralph 
37511508Sralph 	if (penweight == 0)
37611508Sralph 		setmat(wind[curwind].val, GLROW, GLCOL, r, c, pencolor);
37711508Sralph 	else {
37811508Sralph 		for (i=0; i<10; i++)
37911508Sralph 			for (j=0; j<10; j++)
38011508Sralph 				if (penmat[i][j])
38111508Sralph 					setmat(wind[curwind].val, GLROW, GLCOL, r+i-4, c+j-4, pencolor);
38211508Sralph 	}
38311508Sralph }
38411508Sralph 
38511508Sralph /*
38611508Sralph  * setcmd: handle the s command.  Format: s <what> <where>.
38711508Sralph  */
setcmd()38811508Sralph setcmd()
38911508Sralph {
39011508Sralph 	char what, where;
39111508Sralph 
39211508Sralph 	message("set <what>");
39311508Sralph 	what = inchar();
39411508Sralph 	switch (what) {
39511508Sralph 
39611508Sralph 	case 'p':	/* set pen */
39711508Sralph 		message("set pen <weight>");
39811508Sralph 		where = inchar();
39911508Sralph 		switch (where) {
40011508Sralph 		case 'f':	/* set pen fine */
40111508Sralph 		case 'l':	/* set pen light */
40211508Sralph 			message("set pen fine");
40311508Sralph 			penweight = 0;
40411508Sralph 			break;
40511508Sralph 		case 'h':	/* set pen heavy */
40611508Sralph 		case 'b':	/* set pen bold */
40711508Sralph 			message("set pen heavy");
40811508Sralph 			penweight = 1;
40911508Sralph 			break;
41011508Sralph 		default:
41111508Sralph 			error("Illegal kind of pen weight");
41211508Sralph 		}
41311508Sralph 		break;
41411508Sralph 
41511508Sralph 	case 's':	/* set size of heavy pen */
41611508Sralph 		message("set pen size to <size>");
41711508Sralph 		where = inchar() - '0';
41811508Sralph 		sprintf(msgbuf, "set pen size to %d", where);
41911508Sralph 		message(msgbuf);
42011508Sralph 		if (where > 0 && where < 10) {
42111508Sralph 			setpen(where);
42211508Sralph 		} else
42311508Sralph 			error("Illegal size");
42411508Sralph 		break;
42511508Sralph 
42611508Sralph 	case 'd':
42711508Sralph 		message("set draw");
42811508Sralph 		pencolor = 1;
42911508Sralph 		break;
43011508Sralph 
43111508Sralph 	case 'e':
43211508Sralph 		message("set erase");
43311508Sralph 		pencolor = 0;
43411508Sralph 		break;
43511508Sralph 
43611508Sralph 	default:
43711508Sralph 		error("Illegal set");
43811508Sralph 	}
43911508Sralph }
44011508Sralph 
44111508Sralph /*
44211508Sralph  * setpen: set the heavy pen size to s.
44311508Sralph  * Main work here is defining template of pen.
44411508Sralph  */
setpen(s)44511508Sralph setpen(s)
44611508Sralph int s;
44711508Sralph {
44811508Sralph 	register int i, j;
44911508Sralph 	register float radius;
45011508Sralph 
45111508Sralph 	if (s < 1)
45211508Sralph 		s = 1;
45311508Sralph 	hpensize = s;
45411508Sralph 	radius = hpensize;
45511508Sralph 	radius /= 2;
45611508Sralph 	for (i=0; i<10; i++) {
45711508Sralph 		for (j=0; j<10; j++) {
45811508Sralph 			penmat[i][j] = (radius >= sqrtmat[abs(i-4)][abs(j-4)]);
45911508Sralph 		}
46011508Sralph 	}
46111508Sralph 
46211508Sralph 	/*
46311508Sralph 	 * Kludge to make a 2-wide pen possible by specifying 1.
46411508Sralph 	 */
46511508Sralph 	if (hpensize == 1)
46611508Sralph 		penmat[4][5] = 1;
46711508Sralph 
46811508Sralph 	if (trace)
46911508Sralph 		for (i=0; i<10; i++) {
47011508Sralph 			for (j=0; j<10; j++) {
47111508Sralph 				fprintf(trace, "%c", penmat[i][j] ? 'P' : '.');
47211508Sralph 			}
47311508Sralph 			fprintf(trace, "\n");
47411508Sralph 		}
47511508Sralph }
47611508Sralph 
47711508Sralph /*
47811508Sralph  * error: print the given error message and return for another command.
47911508Sralph  */
error(msg)48011508Sralph error(msg)
48111508Sralph char *msg;
48211508Sralph {
48311508Sralph 	message(msg);
48411508Sralph 	longjmp(env);
48511508Sralph }
48611508Sralph 
48711508Sralph /*
48811508Sralph  * copymove: do a move or copy command.
48911508Sralph  * cmd is C or M, the command.
49011508Sralph  */
copymove(cmd)49111508Sralph copymove(cmd)
49211508Sralph char cmd;
49311508Sralph {
49411508Sralph 	char *action;
49511508Sralph 	char src, dest;
49611508Sralph 	bitmat cpy;
49711508Sralph 	char lochr[5];
49811508Sralph 
49911508Sralph 	if (cmd == 'C')
50011508Sralph 		action = "copy";
50111508Sralph 	else
50211508Sralph 		action = "move";
50311508Sralph 	sprintf(msgbuf, "%s <from>", action);
50411508Sralph 	message(msgbuf);
50511508Sralph 	src = inchar();
50611508Sralph 	sprintf(msgbuf, "%s %s to <to>", action, rdchar(src));
50711508Sralph 	message(msgbuf);
50811508Sralph 	dest = inchar();
50911508Sralph 	strcpy(lochr, rdchar(src));
51011508Sralph 	sprintf(msgbuf, "%s %s to %s", action, lochr, rdchar(dest));
51111508Sralph 	message(msgbuf);
51211508Sralph 
51311508Sralph 	/* Do the copy */
51411508Sralph 	disptable[dest] = disptable[src];
51511508Sralph 	cht[dest] = cht[src];
51611508Sralph 	if (cht[dest].wherewind >= 0)
51711508Sralph 		wind[cht[dest].wherewind].used = dest;
51811508Sralph 
51911508Sralph 	if (cmd == 'C') {
52011508Sralph 		if (cht[dest].wherewind != -1) {
52111508Sralph 			/*
52211508Sralph 			 * Make copies of the window so changing
52311508Sralph 			 * one won't change the other.
52411508Sralph 			 * The old copy gets the window on the screen, if any,
52511508Sralph 			 * relegating the new copy to the background.
52611508Sralph 			 */
52711508Sralph 			cpy = newmat(GLROW, GLCOL);
52811508Sralph 			if (cht[dest].wherewind >= 0)
52911508Sralph 				bitcopy(cpy, wind[cht[src].wherewind].val, GLROW, GLCOL);
53011508Sralph 			else
53111508Sralph 				bitcopy(cpy, cht[src].whereat, GLROW, GLCOL);
53211508Sralph 			if (cht[dest].wherewind == curwind)
53311508Sralph 				curwind = -1;
53411508Sralph 			cht[dest].wherewind = -2;
53511508Sralph 			cht[dest].whereat = cpy;
53611508Sralph 		}
53711508Sralph 	} else {
53811508Sralph 		/*
53911508Sralph 		 * Move. Delete the old entries.
54011508Sralph 		 */
54111508Sralph 		disptable[src].addr = disptable[src].nbytes = 0;
54211508Sralph 		cht[src].wherewind = -1;
54311508Sralph 	}
54411508Sralph 	changes++;
54511508Sralph }
54611508Sralph 
54711508Sralph /*
54811508Sralph  * cch: make sure there is a current character.
54911508Sralph  */
cch()55011508Sralph cch()
55111508Sralph {
55211508Sralph 	if (curwind < 0)
55311508Sralph 		error("No current glyph");
55411508Sralph }
55511508Sralph 
55611508Sralph /*
55711508Sralph  * confirm: if there have been changes, ask user if he is sure.
55811508Sralph  */
confirm()55911508Sralph confirm()
56011508Sralph {
56111508Sralph 	char ch;
56211508Sralph 
56311508Sralph 	if (changes == 0)
56411508Sralph 		return;
56511508Sralph 	message("Changes since last write -- Are you sure?");
56611508Sralph 	ch = inchar();
56711508Sralph 	if (isupper(ch))
56811508Sralph 		ch = tolower(ch);
56911508Sralph 	switch (ch) {
57011508Sralph 	case 'y':
57111508Sralph 	case 'q':
57211508Sralph 	case 'e':
57311508Sralph 		return;
57411508Sralph 	case 'n':
57511508Sralph 	default:
57611508Sralph 		error("Not sure - aborted");
57711508Sralph 	}
57811508Sralph }
57911508Sralph 
58011508Sralph /*
58111508Sralph  * delchar: the D command.  Delete a character from the buffer.
58211508Sralph  */
delchar()58311508Sralph delchar()
58411508Sralph {
58511508Sralph 	register char c, c1, c2;
58611508Sralph 	register int w;
58711508Sralph 	char buf[5];
58811508Sralph 
58911508Sralph 	message("delete <char>");
59011508Sralph 	c1 = inchar();
59111508Sralph 	sprintf(msgbuf, "delete %s through <char>", rdchar(c1));
59211508Sralph 	message(msgbuf);
59311508Sralph 	c2 = inchar();
59411508Sralph 	strcpy(buf, rdchar(c1));
59511508Sralph 	sprintf(msgbuf, "delete %s through %s", buf, rdchar(c2));
59611508Sralph 	message(msgbuf);
59711508Sralph 	changes++;
59811508Sralph 
59911508Sralph 	for (c=c1; c<=c2; c++) {
60011508Sralph 		if ((w = cht[c].wherewind) >= 0) {
60111508Sralph 			zermat(wind[w].val, GLROW, GLCOL);
60211508Sralph 			syncwind(w);
60311508Sralph 		}
60411508Sralph 		cht[c].wherewind = -1;
60511508Sralph 		disptable[c].addr = 0;
60611508Sralph 		disptable[c].nbytes = 0;
60711508Sralph 		disptable[c].up = 0;
60811508Sralph 		disptable[c].down = 0;
60911508Sralph 		disptable[c].left = 0;
61011508Sralph 		disptable[c].right = 0;
61111508Sralph 		disptable[c].width = 0;
61211508Sralph 	}
61311508Sralph }
61411508Sralph 
61511508Sralph /*
61611508Sralph  * zoom out to full screen so the screen doean't go nuts when we
61711508Sralph  * print off the current zoom window.  Save old value of zoom in
61811508Sralph  * oldzoom so space can put us back.
61911508Sralph  */
zoomout()62011508Sralph zoomout()
62111508Sralph {
62211508Sralph 	if (curzoom != 1)
62311508Sralph 		zoomn(curzoom = 1);
62411508Sralph }
62511508Sralph 
62611508Sralph /*
62711508Sralph  * newglyph: the n command.
62811508Sralph  */
newglyph()62911508Sralph newglyph()
63011508Sralph {
63111508Sralph 	register int i, j;
63211508Sralph 	int windno;
63311508Sralph 	int vertoff, horoff;
63411508Sralph 	char *tmp;
63511508Sralph 
63611508Sralph 	message("new glyph <char>");
63711508Sralph 	curchar = inchar();
63811508Sralph 	sprintf(msgbuf, "new glyph %s", rdchar(curchar));
63911508Sralph 	message(msgbuf);
64011508Sralph 
64111508Sralph 	if (trace)
64211508Sralph 		fprintf(trace, "\n\nnewglyph(%s)\n", rdchar(curchar));
64311508Sralph 	if (disptable[curchar].nbytes != 0) {
64411508Sralph 		if (trace)
64511508Sralph 			fprintf(trace, "char exists: %s\n", rdchar(curchar));
64611508Sralph 		sprintf(msgbuf, "char exists: %s", rdchar(curchar));
64711508Sralph 		error(msgbuf);
64811508Sralph 	}
64911508Sralph 
65011508Sralph 	turnofcurs();
65111508Sralph 	/*
65211508Sralph 	 * Not on screen.  First find a suitable window,
65311508Sralph 	 * using round robin.
65411508Sralph 	 */
65511508Sralph 	windno = nextwind;
65611508Sralph 	if (trace)
65711508Sralph 		fprintf(trace, "chose window %d\n", windno);
65811508Sralph 	if (++nextwind >= NWIND)
65911508Sralph 		nextwind = 0;
66011508Sralph #ifdef notdef
66111508Sralph 	if (nextwind >= 3)
66211508Sralph 		nextwind = 0;
66311508Sralph #endif
66411508Sralph 	wind[windno].used = curchar;
66511508Sralph 
66611508Sralph 	/* Put a box around the current window */
66711508Sralph 	if (windno != curwind) {
66811508Sralph 		drawbox(base[curwind].r-1, base[curwind].c-1, 0, GLROW+2, GLCOL+2);
66911508Sralph 		drawbox(base[windno].r-1, base[windno].c-1, 1, GLROW+2, GLCOL+2);
67011508Sralph 	}
67111508Sralph 
67211508Sralph 	/* Print the char at the lower left of the window */
67311508Sralph 	sprintf(msgbuf, "%s", rdchar(curchar));
67411508Sralph 	dispmsg(msgbuf, base[windno].c, base[windno].r-11, 2);
67511508Sralph 
67611508Sralph 	/* Now make room in the window */
67711508Sralph 	if (wind[windno].onscreen == NULL) {
67811508Sralph 		/* Brand new window, have to allocate space */
67911508Sralph 		wind[windno].onscreen = newmat(GLROW, GLCOL);
68011508Sralph 	} else {
68111508Sralph 		/* Save prev glyph for later */
68211508Sralph 		cht[wind[curchar].used].whereat = wind[windno].val;
68311508Sralph 		cht[wind[curchar].used].wherewind = -2;
68411508Sralph 	}
68511508Sralph 	if (wind[windno].undval != NULL) {
68611508Sralph 		if (trace)
68711508Sralph 			fprintf(trace, "newglyph frees undo: %x\n", wind[windno].undval);
68811508Sralph 		free(wind[windno].undval);
68911508Sralph 	}
69011508Sralph 	wind[windno].undval = NULL;
69111508Sralph 
69211508Sralph 	/*
69311508Sralph 	 * Vertical & horizontal offsets.  Line up the baseline
69411508Sralph 	 * of the char at BASELINE from bottom, but center
69511508Sralph 	 * horizontally.
69611508Sralph 	 */
69711508Sralph 	wind[windno].val = newmat(GLROW, GLCOL);
69811508Sralph 
69911508Sralph 	curwind = windno;
70011508Sralph 	cht[curchar].wherewind = windno;
70111508Sralph 	cht[curchar].rcent = curs_r = GLROW - BASELINE;
70211508Sralph 	cht[curchar].ccent = curs_c = GLCOL / 2;
70311508Sralph 
70411508Sralph #ifdef notdef
70511508Sralph 	dumpmat("wind[windno].onscreen", wind[windno].onscreen, GLROW, GLCOL);
70611508Sralph #endif
70711508Sralph 	syncwind(windno);
70811508Sralph 
70911508Sralph 	/*
71011508Sralph 	 * Mung the zoom out to 1 and back.  This is needed to
71111508Sralph 	 * re-center the glyph on the screen if zoomed in, otherwise
71211508Sralph 	 * if you move by one window it puts the cursor way over at
71311508Sralph 	 * the right with only half the window visible.
71411508Sralph 	 */
71511508Sralph 	if ((i = curzoom) > 1) {
71611508Sralph 		zoomn(1);
71711508Sralph 		zoomn(i);
71811508Sralph 	}
71911508Sralph }
72011508Sralph 
72111508Sralph /*
72211508Sralph  * numedit: change one of the numerical parameters.
72311508Sralph  */
numedit()72411508Sralph numedit()
72511508Sralph {
72611508Sralph 	short * sp = 0;
72711508Sralph 	char * cp = 0;
72811508Sralph 	char c, f;
72911508Sralph 	char *fld;
73011508Sralph 	short ovalue, nvalue;
73111508Sralph 	char numb[20];
73211508Sralph 
73311508Sralph 	message("number of <char>");
73411508Sralph 	c = inchar();
73511508Sralph 	sprintf(msgbuf, "number of %s <field>", rdchar(c));
73611508Sralph 	message(msgbuf);
73711508Sralph 	f = inchar();
73811508Sralph 
73911508Sralph 	switch (f) {
74011508Sralph 	case 'a': sp = (short *)
74111508Sralph 			&disptable[c].addr;	fld = "addr";	break;
74211508Sralph 	case 'n': sp = &disptable[c].nbytes;	fld = "nbytes";	break;
74311508Sralph 	case 'u': cp = &disptable[c].up;	fld = "up";	break;
74411508Sralph 	case 'd': cp = &disptable[c].down;	fld = "down";	break;
74511508Sralph 	case 'l': cp = &disptable[c].left;	fld = "left";	break;
74611508Sralph 	case 'r': cp = &disptable[c].right;	fld = "right";	break;
74711508Sralph 	case 'w': sp = &disptable[c].width;	fld = "width";	break;
74811508Sralph 	case 's': sp = (short *) &disptable[c].nbytes;
74911508Sralph 						fld = "size";	break;
75011508Sralph 	default: error("No such field");
75111508Sralph 	}
75211508Sralph 
75311508Sralph 	ovalue = sp ? *sp : *cp;
75411508Sralph 	sprintf(msgbuf, "number of %s %s (old value %d) is ", rdchar(c), fld, ovalue);
75511508Sralph 	readline(msgbuf, numb, sizeof numb);
75611508Sralph 	nvalue = atoi(numb);
75711508Sralph 	if (cp)
75811508Sralph 		*cp = nvalue;
75911508Sralph 	else
76011508Sralph 		*sp = nvalue;
76111508Sralph 	changes++;
76211508Sralph }
76311508Sralph 
76411508Sralph /*
76511508Sralph  * These routines turn the cursor and rubber band line on and off,
76611508Sralph  * remembering its state for the o and r commands.
76711508Sralph  */
turnoncurs()76811508Sralph turnoncurs()
76911508Sralph {
77011508Sralph 	curon();
77111508Sralph 	curcurs = 1;
77211508Sralph }
77311508Sralph 
turnofcurs()77411508Sralph turnofcurs()
77511508Sralph {
77611508Sralph 	curoff();
77711508Sralph 	curcurs = 0;
77811508Sralph }
77911508Sralph 
turnonrb()78011508Sralph turnonrb()
78111508Sralph {
78211508Sralph 	rbon();
78311508Sralph 	currb = 1;
78411508Sralph }
78511508Sralph 
turnofrb()78611508Sralph turnofrb()
78711508Sralph {
78811508Sralph 	rboff();
78911508Sralph 	currb = 0;
79011508Sralph }
79111508Sralph 
synccurs()79211508Sralph synccurs()
79311508Sralph {
79411508Sralph 	register int x, y;
79511508Sralph 
79611508Sralph 	x = base[curwind].c + curs_c;
79711508Sralph 	y = base[curwind].r + GLROW - curs_r - 1;
79811508Sralph 	movecurs(x, y);
79911508Sralph }
80011508Sralph 
inchar()80111508Sralph inchar()
80211508Sralph {
80311508Sralph 	sync();
80411508Sralph 	synccurs();
80511508Sralph 	return (rawchar());
80611508Sralph }
80711508Sralph 
80811508Sralph /*
80911508Sralph  * fillin - fill in with 1's all the spots that are in the enclosed
81011508Sralph  * area that (x, y) is in.
81111508Sralph  */
fillin(x,y)81211508Sralph fillin(x, y)
81311508Sralph int x, y;
81411508Sralph {
81511508Sralph 	if (x<0 || x>=GLROW || y<0 || y>=GLCOL ||
81611508Sralph 		mat(wind[curwind].val, GLROW, GLCOL, x, y))
81711508Sralph 		return;
81811508Sralph 
81911508Sralph 	setmat(wind[curwind].val, GLROW, GLCOL, x, y, 1);
82011508Sralph 	fillin(x-1, y);
82111508Sralph 	fillin(x+1, y);
82211508Sralph 	fillin(x, y-1);
82311508Sralph 	fillin(x, y+1);
82411508Sralph }
82511508Sralph 
82611508Sralph /*
82711508Sralph  * syncwind: make sure that window #n shows on the screen what it's
82811508Sralph  * supposed to after an arbitrary change.
82911508Sralph  */
syncwind(n)83011508Sralph syncwind(n)
83111508Sralph int n;
83211508Sralph {
83311508Sralph 	if (trace)
83411508Sralph 		fprintf(trace, "syncwind(%d)\n", n);
83511508Sralph 	update(wind[n].onscreen, wind[n].val, GLROW, GLCOL, base[n].r, base[n].c);
83611508Sralph 	bitcopy(wind[n].onscreen, wind[n].val, GLROW, GLCOL);
83711508Sralph }
83811508Sralph 
83911508Sralph /*
84011508Sralph  * Embolden artificially emboldens the glyphs in the font by smearing
84111508Sralph  * them to the right by the current heavy pen size.  Or else italicize it.
84211508Sralph  */
artificial()84311508Sralph artificial()
84411508Sralph {
84511508Sralph 	int low, high, cur;
84611508Sralph 	int oldps, newps;
84711508Sralph 	char lowch[10];
84811508Sralph #define ITAL	0
84911508Sralph #define BOLD	1
85011508Sralph #define RESIZE	2
85111508Sralph #define SMOOTH	3
85211508Sralph 	int kind;
85311508Sralph 	char *strbold;
85411508Sralph 
85511508Sralph 	sprintf(msgbuf, "Artificially <embolden/italicize/resize/smooth>");
85611508Sralph 	message(msgbuf);
85711508Sralph 
85811508Sralph 	cur = inchar();
85911508Sralph 	switch(cur) {
86011508Sralph 	case 'i': case 'I': kind = ITAL; strbold = "italicize"; break;
86111508Sralph 	case 'e': case 'E': kind = BOLD; strbold = "embolden"; break;
86211508Sralph 	case 'r': case 'R': kind = RESIZE; strbold = "resize"; break;
86311508Sralph 	case 's': case 'S': kind = SMOOTH; strbold = "smooth"; break;
86411508Sralph 	default: error("No such artificial operation");
86511508Sralph 	}
86611508Sralph 
86711508Sralph 	sprintf(msgbuf, "Artificially %s glyphs from <char>", strbold);
86811508Sralph 	message(msgbuf);
86911508Sralph 	low = inchar();
87011508Sralph 	strcpy(lowch, rdchar(low));
87111508Sralph 	sprintf(msgbuf, "Artificially %s glyphs from %s to <char>", strbold, lowch);
87211508Sralph 	message(msgbuf);
87311508Sralph 	high = inchar();
87411508Sralph 	if (kind == RESIZE) {
87511508Sralph 		sprintf(msgbuf, "Artificially %s glyphs from %s to %s from <point size>", strbold, lowch, rdchar(high));
87611508Sralph 		oldps = readnum(msgbuf);
87711508Sralph 		sprintf(msgbuf, "Artificially %s glyphs from %s to %s from %dP to <point size>P", strbold, lowch, rdchar(high), oldps);
87811508Sralph 		newps = readnum(msgbuf);
87911508Sralph 		sprintf(msgbuf, "Artificially %s glyphs from %s to %s from %dP to %dP", strbold, lowch, rdchar(high), oldps, newps);
88011508Sralph 		message(msgbuf);
88111508Sralph 		if (oldps <= 0 || oldps > 36 || newps <= 0 || newps > 36 || oldps == newps)
88211508Sralph 			error("Bad point sizes");
88311508Sralph 	} else {
88411508Sralph 		sprintf(msgbuf, "Artificially %s glyphs from %s to %s", strbold, lowch, rdchar(high));
88511508Sralph 		message(msgbuf);
88611508Sralph 	}
88711508Sralph 
88811508Sralph 	for (cur=low; cur<=high; cur++) {
88911508Sralph 		getglyph(cur);
89011508Sralph 		if (curchar == cur) {	/* e.g. if the getglyph succeeded */
89111508Sralph 			fflush(stdout);
89211508Sralph 			switch (kind) {
89311508Sralph 			case BOLD:
89411508Sralph 				boldglyph();
89511508Sralph 				break;
89611508Sralph 			case ITAL:
89711508Sralph 				italglyph();
89811508Sralph 				break;
89911508Sralph 			case RESIZE:
90011508Sralph 				if (oldps > newps)
90111508Sralph 					shrinkglyph(oldps, newps);
90211508Sralph 				else
90311508Sralph 					blowupglyph(oldps, newps);
90411508Sralph 				break;
90511508Sralph 			case SMOOTH:
90611508Sralph 				smoothglyph();
90711508Sralph 				break;
90811508Sralph 			}
90911508Sralph 			syncwind(curwind);
91011508Sralph 		}
91111508Sralph 	}
91211508Sralph 	message("Done");
91311508Sralph }
91411508Sralph 
91511508Sralph /*
91611508Sralph  * Artificially embolden the current glyph.
91711508Sralph  */
boldglyph()91811508Sralph boldglyph()
91911508Sralph {
92011508Sralph 	register int r, c, i;
92111508Sralph 	int smear = hpensize < 2 ? 2 : hpensize;
92211508Sralph 
92311508Sralph 	for (r=0; r<GLROW; r++)
92411508Sralph 		for (c=GLCOL-1; c>=smear; c--)
92511508Sralph 			for (i=1; i<=smear; i++)
92611508Sralph 				if (mat(wind[curwind].val, GLROW, GLCOL, r, c-i))
92711508Sralph 					setmat(wind[curwind].val, GLROW, GLCOL, r, c, 1);
92811508Sralph }
92911508Sralph 
93011508Sralph /*
93111508Sralph  * Artificially italicize the current glyph.
93211508Sralph  */
italglyph()93311508Sralph italglyph()
93411508Sralph {
93511508Sralph 	register int r, c, i, off;
93611508Sralph 	int baser = cht[curchar].rcent; /* GLROW - BASELINE; */
93711508Sralph 
93811508Sralph 	for (r=0; r<baser; r++) {
93911508Sralph 		off = (baser-r) / SLOPE + 0.5;
94011508Sralph 		for (c=GLCOL-1; c>=off; c--) {
94111508Sralph 			setmat(wind[curwind].val, GLROW, GLCOL, r, c,
94211508Sralph 				mat(wind[curwind].val, GLROW, GLCOL, r, c-off));
94311508Sralph 		}
94411508Sralph 		for (c=off-1; c>=0; c--)
94511508Sralph 			setmat(wind[curwind].val, GLROW, GLCOL, r, c, 0);
94611508Sralph 	}
94711508Sralph 	for (r=baser; r<GLROW; r++) {
94811508Sralph 		off = (r-baser) * (2.0/7.0) + 0.5;
94911508Sralph 		for (c=off; c<GLCOL; c++)
95011508Sralph 			setmat(wind[curwind].val, GLROW, GLCOL, r, c-off,
95111508Sralph 				mat(wind[curwind].val, GLROW, GLCOL, r, c));
95211508Sralph 		for (c=off-1; c>=0; c--)
95311508Sralph 			setmat(wind[curwind].val, GLROW, GLCOL, r, c, 0);
95411508Sralph 	}
95511508Sralph }
95611508Sralph 
95711508Sralph /*
95811508Sralph  * Blow up or shrink a glyph from oldps points to newps points.
95911508Sralph  * The basic idea is that for each on point in the old glyph we
96011508Sralph  * find the corresponding point in the new glyph and copy the value.
96111508Sralph  */
shrinkglyph(oldps,newps)96211508Sralph shrinkglyph(oldps, newps)
96311508Sralph int oldps, newps;
96411508Sralph {
96511508Sralph 	float ratio;
96611508Sralph 	register int or, oc, nr, nc;
96711508Sralph 	int n;
96811508Sralph 	bitmat tmp, curw;
96911508Sralph 	int baser = cht[curchar].rcent;
97011508Sralph 	int basec = cht[curchar].ccent;
97111508Sralph 
97211508Sralph 	ratio = (float) newps / (float) oldps;
97311508Sralph 	tmp = newmat(GLROW, GLCOL);
97411508Sralph 	curw = wind[curwind].val;
97511508Sralph 	bitcopy(tmp, curw, GLROW, GLCOL);
97611508Sralph 	zermat(curw, GLROW, GLCOL);
97711508Sralph 	for (or=0; or<GLROW; or++) {
97811508Sralph 		nr = baser + (or-baser)*ratio + 0.5;
97911508Sralph 		for (oc=0; oc<GLCOL; oc++) {
98011508Sralph 			nc = basec + (oc-basec)*ratio + 0.5;
98111508Sralph 			if (nr < 0 || nr >= GLROW || nc < 0 || nc >= GLCOL)
98211508Sralph 				n = 0;
98311508Sralph 			else
98411508Sralph 				n = mat(tmp, GLROW, GLCOL, or, oc);
98511508Sralph 			if (n)
98611508Sralph 				setmat(curw, GLROW, GLCOL, nr, nc, n);
98711508Sralph 		}
98811508Sralph 	}
98911508Sralph 	disptable[curchar].width = disptable[curchar].width * ratio + 0.5;
99011508Sralph 	free(tmp);
99111508Sralph }
99211508Sralph 
99311508Sralph /*
99411508Sralph  * blow up a glyph.  Otherwise like shrinkglyph.
99511508Sralph  */
blowupglyph(oldps,newps)99611508Sralph blowupglyph(oldps, newps)
99711508Sralph int oldps, newps;
99811508Sralph {
99911508Sralph 	float ratio;
100011508Sralph 	register int or, oc, nr, nc;
100111508Sralph 	int n;
100211508Sralph 	bitmat tmp, curw;
100311508Sralph 	int baser = cht[curchar].rcent;
100411508Sralph 	int basec = cht[curchar].ccent;
100511508Sralph 
100611508Sralph 	ratio = (float) oldps / (float) newps;
100711508Sralph 	tmp = newmat(GLROW, GLCOL);
100811508Sralph 	curw = wind[curwind].val;
100911508Sralph 	bitcopy(tmp, curw, GLROW, GLCOL);
101011508Sralph 	zermat(curw, GLROW, GLCOL);
101111508Sralph 	for (nr=0; nr<GLROW; nr++) {
101211508Sralph 		or = baser + (nr-baser)*ratio + 0.5;
101311508Sralph 		for (nc=0; nc<GLCOL; nc++) {
101411508Sralph 			oc = basec + (nc-basec)*ratio + 0.5;
101511508Sralph 			if (or < 0 || or >= GLROW || oc < 0 || oc >= GLCOL)
101611508Sralph 				n = 0;
101711508Sralph 			else
101811508Sralph 				n = mat(tmp, GLROW, GLCOL, or, oc);
101911508Sralph 			if (n)
102011508Sralph 				setmat(curw, GLROW, GLCOL, nr, nc, n);
102111508Sralph 		}
102211508Sralph 	}
102311508Sralph 	disptable[curchar].width = disptable[curchar].width / ratio + 0.5;
102411508Sralph 	free(tmp);
102511508Sralph }
102611508Sralph 
102711508Sralph /*
102811508Sralph  * Smooth a glyph.  We look for corners and trim the point.  Corners of
102911508Sralph  * both blanks and dots in all 4 orientations are looked for.
103011508Sralph  */
smoothglyph()103111508Sralph smoothglyph()
103211508Sralph {
103311508Sralph 	bitmat tmp, curw;
103411508Sralph 	register int r, c;
103511508Sralph 	register int c3;
103611508Sralph 	int a3, b2, b3, b4, c1, c2, c4, c5, d2, d3, d4, e3;
103711508Sralph 
103811508Sralph 	tmp = newmat(GLROW, GLCOL);
103911508Sralph 	curw = wind[curwind].val;
104011508Sralph 	bitcopy(tmp, curw, GLROW, GLCOL);
104111508Sralph 	for (r=2; r<GLROW-2; r++)
104211508Sralph 		for (c=2; c<GLCOL-2; c++) {
104311508Sralph 			/*
104411508Sralph 			 *		a3
104511508Sralph 			 *	     b2 b3 b4
104611508Sralph 			 *	  c1 c2 c3 c4 c5
104711508Sralph 			 *	     d2 d3 d4
104811508Sralph 			 *	        d4
104911508Sralph 			 * where c3 is the square we are interested in
105011508Sralph 			 */
105111508Sralph 			b3 = mat(tmp, GLROW, GLCOL, r-1, c  );
105211508Sralph 			c2 = mat(tmp, GLROW, GLCOL, r  , c-1);
105311508Sralph 			c4 = mat(tmp, GLROW, GLCOL, r  , c+1);
105411508Sralph 			d3 = mat(tmp, GLROW, GLCOL, r+1, c  );
105511508Sralph 			/* exactly 2 of the 4 neighbors must be dots */
105611508Sralph 			if (b3+c2+c4+d3 != 2) continue;
105711508Sralph 
105811508Sralph 			c3 = mat(tmp, GLROW, GLCOL, r  , c  );
105911508Sralph 			b2 = mat(tmp, GLROW, GLCOL, r-1, c-1);
106011508Sralph 			b4 = mat(tmp, GLROW, GLCOL, r-1, c+1);
106111508Sralph 			d2 = mat(tmp, GLROW, GLCOL, r+1, c-1);
106211508Sralph 			d4 = mat(tmp, GLROW, GLCOL, r+1, c+1);
106311508Sralph 			/* exactly one of the 4 diags must match the center */
106411508Sralph 			if (b2+b4+d2+d4 != 3 - 2*c3) continue;
106511508Sralph 
106611508Sralph 			a3 = mat(tmp, GLROW, GLCOL, r-2, c  );
106711508Sralph 			c1 = mat(tmp, GLROW, GLCOL, r  , c-2);
106811508Sralph 			c5 = mat(tmp, GLROW, GLCOL, r  , c+2);
106911508Sralph 			e3 = mat(tmp, GLROW, GLCOL, r+2, c  );
107011508Sralph 
107111508Sralph 			/* Figure out which of the 4 directions */
107211508Sralph 			if (b2==c3) {
107311508Sralph 				if (b3+c2+c1+a3 != 4*c3) continue;
107411508Sralph 			} else
107511508Sralph 			if (b4==c3) {
107611508Sralph 				if (b3+c4+c5+a3 != 4*c3) continue;
107711508Sralph 			} else
107811508Sralph 			if (d2==c3) {
107911508Sralph 				if (d3+c2+c1+e3 != 4*c3) continue;
108011508Sralph 			} else
108111508Sralph 			if (d4==c3) {
108211508Sralph 				if (d3+c4+c5+e3 != 4*c3) continue;
108311508Sralph 			}
108411508Sralph 
108511508Sralph 			/* It must be a corner.  Toggle it. */
108611508Sralph 			setmat(curw, GLROW, GLCOL, r, c, !c3);
108711508Sralph 		}
108811508Sralph 	free(tmp);
108911508Sralph }
109011508Sralph 
109111508Sralph /*
109211508Sralph  * Read a number from bottom line ala readline.
109311508Sralph  * This should probably go in lib2648.
109411508Sralph  */
109511508Sralph int
readnum(prompt)109611508Sralph readnum(prompt)
109711508Sralph char *prompt;
109811508Sralph {
109911508Sralph 	char buf[10];
110011508Sralph 	int retval;
110111508Sralph 
110211508Sralph 	readline(prompt, buf, sizeof buf);
110311508Sralph 	retval = atoi(buf);
110411508Sralph 	if (trace)
110511508Sralph 		fprintf(trace, "readline returns '%s', retval=%d\n", buf, retval);
110611508Sralph 	return (retval);
110711508Sralph }
110811508Sralph 
invert()110911508Sralph invert()
111011508Sralph {
111111508Sralph 	register int r, c;
111211508Sralph 	int tmp1, tmp2, kind;
111311508Sralph 	bitmat curw = wind[curwind].val;
111411508Sralph 
111511508Sralph 	message("Invert <horizontally/vertically>");
111611508Sralph 	kind = inchar();
111711508Sralph 	switch (kind) {
111811508Sralph 	case 'h': case 'H':
111911508Sralph 		message("Invert horizontally");
112011508Sralph 		for (r=0; r<GLROW; r++) {
112111508Sralph 			if (trace)
112211508Sralph 				fprintf(trace, "row %d\n", r);
112311508Sralph 			for (c=0; c<=(GLCOL-1)/2; c++) {
112411508Sralph 				tmp1 = mat(curw, GLROW, GLCOL, r, c);
112511508Sralph 				tmp2 = mat(curw, GLROW, GLCOL, r, GLCOL-1-c);
112611508Sralph 				if (trace)
112711508Sralph 					fprintf(trace, "cols %d (%d) <=> %d (%d)\n", c, tmp1, GLCOL-1-c, tmp2);
112811508Sralph 				setmat(curw, GLROW, GLCOL, r, c, tmp2);
112911508Sralph 				setmat(curw, GLROW, GLCOL, r, GLCOL-1-c, tmp1);
113011508Sralph 			}
113111508Sralph 		}
113211508Sralph 		break;
113311508Sralph 	case 'v': case 'V':
113411508Sralph 		message("Invert vertically");
113511508Sralph 		for (c=0; c<GLCOL; c++) {
113611508Sralph 			for (r=0; r<=(GLROW-1)/2; r++) {
113711508Sralph 				tmp1 = mat(curw, GLROW, GLCOL, r, c);
113811508Sralph 				tmp2 = mat(curw, GLROW, GLCOL, GLROW-1-r, c);
113911508Sralph 				setmat(curw, GLROW, GLCOL, r, c, tmp2);
114011508Sralph 				setmat(curw, GLROW, GLCOL, GLROW-1-r, c, tmp1);
114111508Sralph 			}
114211508Sralph 		}
114311508Sralph 		break;
114411508Sralph 	default:
114511508Sralph 		error("Bad choice");
114611508Sralph 	}
114711508Sralph 	syncwind(curwind);
114811508Sralph }
1149