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