|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)subr.c 4.2 (Berkeley) 8/11/83"; ! 3: #endif ! 4: ! 5: /* ! 6: * subr.c: general subroutines for fed. ! 7: */ ! 8: ! 9: #include "fed.h" ! 10: ! 11: /* ! 12: * initialize: various one time initializations. ! 13: */ ! 14: initialize() ! 15: { ! 16: register int i, j; ! 17: register char *cp; ! 18: ! 19: /* Initialize random variables */ ! 20: curwind = -1; ! 21: pencolor = 1; ! 22: penweight = 0; ! 23: ! 24: /* ! 25: * Initialize value of sqrtmat. This is a constant table ! 26: * so we don't have to redo all these square roots when the pen ! 27: * changes every time. ! 28: */ ! 29: for (i=0; i<10; i++) { ! 30: for (j=0; j<10; j++) { ! 31: sqrtmat[i][j] = sqrt((float) i*i + j*j); ! 32: } ! 33: } ! 34: ! 35: /* Initialize base locations on screen. These remain fixed. */ ! 36: for (i=0; i<NROW; i++) ! 37: for (j=0; j<NCOL; j++) { ! 38: base[NCOL*i+j].c = (GLCOL+GLPAD) * j + 1; ! 39: base[NCOL*i+j].r = SCRHI - (GLROW+GLPAD+10) * i - GLROW - 3; ! 40: } ! 41: ! 42: setbuf(stdout, stoutbuf); ! 43: ! 44: curzoom = 1; /* default is zoomed completely out */ ! 45: ttyinit(); ! 46: } ! 47: ! 48: /* ! 49: * showfont: Wipe clean the screen, display the font ! 50: * in a properly spaced fashion, wait for a char to be typed, if it's ! 51: * p print the font, then clear the screen and ungetc the char. ! 52: */ ! 53: showfont() ! 54: { ! 55: register int i, cr, cc, nc; ! 56: int roff, coff; ! 57: char maxc, minc; ! 58: char nextcmd; ! 59: char tmpbuf[WINDSIZE]; ! 60: ! 61: zoomout(); ! 62: message("Show font from <char>"); ! 63: minc = inchar(); ! 64: sprintf(msgbuf, "Show font from %s to <char>", rdchar(minc)); ! 65: message(msgbuf); ! 66: maxc = inchar(); ! 67: ! 68: clearg(); ! 69: zermat(tmpbuf, GLROW, GLCOL); ! 70: cr = SCRHI-GLROW; cc = 3; ! 71: for (i=minc; i<=maxc; i++) { ! 72: if (disptable[i].nbytes) { ! 73: /* ! 74: * We really should try to find out how far to the ! 75: * left the glyph goes so we don't run off the left ! 76: * end of the screen, but this is hard, so we fake it. ! 77: * Usually glyphs don't run past the left so it's OK. ! 78: */ ! 79: if (cc - disptable[i].left < 0) ! 80: cc = disptable[i].left; ! 81: nc = cc + disptable[i].width; ! 82: if (nc >= SCRWID) { ! 83: cc = 0; ! 84: nc = disptable[i].width; ! 85: cr -= 85; /* Should be GLROW but 4*100>360 */ ! 86: if (cr < 0) ! 87: break; /* Screen full. Just stop. */ ! 88: } ! 89: dispmsg(rdchar(i), cc, cr, 2); ! 90: placechar(i, cr+BASELINE, cc, tmpbuf); ! 91: cc = nc; ! 92: } ! 93: } ! 94: for (;;) { ! 95: nextcmd = inchar(); ! 96: if (nextcmd != 'p') ! 97: break; ! 98: printg(); ! 99: } ! 100: if (nextcmd != 'Q' && nextcmd != 'E' && nextcmd != 'N') ! 101: redraw(); ! 102: else ! 103: clearg(); ! 104: ungetc(nextcmd, stdin); ! 105: } ! 106: ! 107: /* ! 108: * typein: Like showfont but takes a line of text from the user ! 109: * and "typesets" it on the screen. ! 110: */ ! 111: typein() ! 112: { ! 113: register int i, cr, cc, nc; ! 114: char *p; ! 115: int roff, coff; ! 116: char maxc, minc; ! 117: char nextcmd; ! 118: char tmpbuf[WINDSIZE]; ! 119: char msgtype[100]; ! 120: ! 121: zoomout(); ! 122: readline("Input line to be typeset: ", msgtype, sizeof msgtype); ! 123: ! 124: clearg(); ! 125: zermat(tmpbuf, GLROW, GLCOL); ! 126: cr = SCRHI-GLROW; cc = 3; ! 127: for (p=msgtype; *p; p++) { ! 128: i = *p; ! 129: if (disptable[i].nbytes) { ! 130: if (cc - disptable[i].left < 0) ! 131: cc = disptable[i].left; ! 132: nc = cc + disptable[i].width; ! 133: if (nc >= SCRWID) { ! 134: cc = 0; ! 135: nc = disptable[i].width; ! 136: cr -= 85; /* Should be GLROW but 4*100>360 */ ! 137: if (cr < 0) ! 138: break; /* Screen full. Just stop. */ ! 139: } ! 140: dispmsg(rdchar(i), cc, cr, 2); ! 141: placechar(i, cr+BASELINE, cc, tmpbuf); ! 142: cc = nc; ! 143: } ! 144: } ! 145: for (;;) { ! 146: nextcmd = inchar(); ! 147: if (nextcmd != 'p') ! 148: break; ! 149: printg(); ! 150: } ! 151: if (nextcmd != 'Q' && nextcmd != 'E' && nextcmd != 'N') ! 152: redraw(); ! 153: else ! 154: clearg(); ! 155: ungetc(nextcmd, stdin); ! 156: } ! 157: ! 158: /* ! 159: * placechar: draw the character ch at position (llr, llc) on the screen. ! 160: * Position means the logical center of the character. zero is a GLROW x GLCOL ! 161: * matrix of zeros which is needed for comparison, that is, we assume that ! 162: * the spot on the screen where this is going is blank, so the chars better ! 163: * not overlap. ! 164: */ ! 165: placechar(ch, llr, llc, zero) ! 166: int ch; ! 167: int llr, llc; ! 168: bitmat zero; ! 169: { ! 170: bitmat glbuf; ! 171: int roff, coff; ! 172: ! 173: glbuf = findbits(ch, GLROW, GLCOL, 0, 0, &roff, &coff); ! 174: if (glbuf == NULL) ! 175: return; ! 176: if (trace) ! 177: 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); ! 178: ! 179: update(zero, glbuf, GLROW, GLCOL, llr-GLROW+roff, llc-coff); ! 180: if (trace) ! 181: fprintf(trace, "placechar, free %x\n", glbuf); ! 182: free(glbuf); ! 183: } ! 184: ! 185: /* ! 186: * redraw: The screen has gotten screwed up somehow. ! 187: * Assume nothing but make it look right. ! 188: */ ! 189: redraw() ! 190: { ! 191: register int i; ! 192: ! 193: zoomout(); ! 194: clearg(); ! 195: turnofrb(); ! 196: for (i=0; i<NWIND; i++) ! 197: if (wind[i].onscreen != NULL) { ! 198: zermat(wind[i].onscreen, GLROW, GLCOL); ! 199: syncwind(i); ! 200: ! 201: /* Print the char at the lower left of the window */ ! 202: sprintf(msgbuf, "%s", rdchar(wind[i].used)); ! 203: dispmsg(msgbuf, base[i].c, base[i].r-11, 2); ! 204: } ! 205: if (curwind >= 0) ! 206: drawbox(base[curwind].r-1, base[curwind].c-1, 1, GLROW+2, GLCOL+2); ! 207: } ! 208: ! 209: /* ! 210: * findbits: find the data bits of glyph c, wherever they are, and make ! 211: * nr x nc bitmat and put them in it, shifted by horoff and vertoff. ! 212: */ ! 213: bitmat ! 214: findbits(c, nr, nc, horoff, vertoff, rcenter, ccenter) ! 215: int c; ! 216: int nr, nc; /* the size of the dest */ ! 217: int horoff, vertoff; ! 218: int *rcenter, *ccenter; ! 219: { ! 220: register int i, j; ! 221: register int r1, r2, c1, c2; ! 222: bitmat retval, source; ! 223: int tr, tc; /* the size of source */ ! 224: char tmp[WINDSIZE]; ! 225: ! 226: if (trace) ! 227: fprintf(trace, "findbits(c=%s, nr=%d, nc=%d, horoff=%d, vertoff=%d\n", rdchar(c), nr, nc, horoff, vertoff); ! 228: if (disptable[c].nbytes == 0) ! 229: return (NULL); ! 230: switch (cht[c].wherewind) { ! 231: case -2: ! 232: if (trace) ! 233: fprintf(trace, "case -2, saved from prev place\n"); ! 234: /* Saved from previous place */ ! 235: source = cht[c].whereat; ! 236: ! 237: /* Ignore horoff/vertoff assuming they are already right */ ! 238: *rcenter = cht[c].rcent; ! 239: *ccenter = cht[c].ccent; ! 240: /* ! 241: * Small but important optimization: if the desired result is ! 242: * a whole window and the source happens to be in a whole ! 243: * window, just return the source pointer. This saves ! 244: * lots of memory copies and happens quite often. ! 245: */ ! 246: if (nr == GLROW && nc == GLCOL) ! 247: return (source); ! 248: tr = GLROW; tc = GLCOL; ! 249: break; ! 250: case -1: ! 251: if (trace) ! 252: fprintf(trace, "case -1: first time\n"); ! 253: /* First time for this glyph: get it from font file */ ! 254: fseek(fontdes, (long) fbase+disptable[c].addr, 0); ! 255: tr = cht[c].nrow; tc = cht[c].ncol; ! 256: if (tr > GLROW || tc > GLCOL || disptable[c].nbytes > WINDSIZE) ! 257: error("glyph too large for window"); ! 258: *rcenter = vertoff + disptable[c].up; ! 259: *ccenter = horoff + disptable[c].left; ! 260: source = tmp; ! 261: fread(source, disptable[c].nbytes, 1, fontdes); ! 262: break; ! 263: default: ! 264: if (trace) ! 265: fprintf(trace, "case default, in window %d", cht[c].wherewind); ! 266: source = wind[cht[c].wherewind].val; ! 267: tr = GLROW; tc = GLCOL; ! 268: *rcenter = vertoff + cht[c].rcent; ! 269: *ccenter = horoff + cht[c].ccent; ! 270: break; ! 271: } ! 272: if (trace) ! 273: fprintf(trace, "curchar=%c=%d, tr=%d, tc=%d\n", curchar, curchar, tr, tc); ! 274: ! 275: dumpmat("before copy, source", source, tr, tc); ! 276: /* Copy in the bits into a bitmat of the right size */ ! 277: retval = newmat(nr, nc); ! 278: r1 = max(0, -vertoff); ! 279: r2 = min(GLROW-vertoff-1, GLROW-1); ! 280: r2 = min(r2, tr-1); ! 281: c1 = max(0, -horoff); ! 282: c2 = min(GLCOL-horoff-1, GLCOL-1); ! 283: c2 = min(c2, tc-1); ! 284: if (trace) ! 285: fprintf(trace, "findbits copy: r1=%d, r2=%d, c1=%d, c2=%d, horoff=%d, vertoff=%d\n", r1, r2, c1, c2, horoff, vertoff); ! 286: for (i=r1; i<=r2; i++) { ! 287: for (j=c1; j<=c2; j++) ! 288: setmat(retval, nr, nc, i+vertoff, j+horoff, mat(source, tr, tc, i, j, 6)); ! 289: } ! 290: dumpmat("result of copy", retval, nr, nc); ! 291: return (retval); ! 292: } ! 293: ! 294: /* ! 295: * bufmod: called just before a buffer modifying command. ! 296: * Makes a backup copy of the glyph so we can undo later. ! 297: */ ! 298: bufmod() ! 299: { ! 300: changes++; ! 301: if (curwind < 0) ! 302: return; ! 303: if (wind[curwind].undval == NULL) ! 304: wind[curwind].undval = newmat(GLROW, GLCOL); ! 305: bitcopy(wind[curwind].undval, wind[curwind].val, GLROW, GLCOL); ! 306: und_p_r = pen_r; und_p_c = pen_c; ! 307: und_c_r = curs_r; und_c_c = curs_c; ! 308: } ! 309: ! 310: /* ! 311: * undo: restore the backup copy. We just swap pointers, which is ! 312: * the same as interchanging the two matrices. This way, undo is ! 313: * its own inverse. ! 314: */ ! 315: undo() ! 316: { ! 317: register bitmat tmp; ! 318: ! 319: if (wind[curwind].undval == NULL) { ! 320: error("Nothing to undo"); ! 321: } ! 322: tmp = wind[curwind].val; ! 323: wind[curwind].val = wind[curwind].undval; ! 324: wind[curwind].undval = tmp; ! 325: pen_r = und_p_r; pen_c = und_p_c; ! 326: move(base[curwind].c+pen_c, base[curwind].r+GLROW-pen_r); ! 327: curs_r = und_c_r; curs_c = und_c_c; ! 328: syncwind(curwind); ! 329: changes++; ! 330: } ! 331: ! 332: /* ! 333: * drawline: draw a line of current flavor between the named two points. ! 334: * All points are relative to current window. ! 335: * ! 336: * The algorithm is that of a simple DDA. This is similar to what the ! 337: * hardware of the HP 2648 does but the placing of the points will be ! 338: * different (because of thick pens and erasers). ! 339: */ ! 340: drawline(from_r, from_c, to_r, to_c) ! 341: { ! 342: int length, i; ! 343: float x, y, xinc, yinc; ! 344: ! 345: if (trace) ! 346: fprintf(trace, "drawline from (%d, %d) to (%d, %d)\n", from_r, from_c, to_r, to_c); ! 347: length = max(abs(to_r-from_r), abs(to_c-from_c)); ! 348: if (length <= 0) { ! 349: /* ! 350: * The actual value doesn't matter, we're just avoiding ! 351: * division by zero here. ! 352: */ ! 353: xinc = yinc = 1.0; ! 354: } else { ! 355: xinc = ((float) (to_r-from_r))/length; ! 356: yinc = ((float) (to_c-from_c))/length; ! 357: } ! 358: drawpoint(from_r, from_c); ! 359: x = from_r + 0.5; y = from_c + 0.5; ! 360: ! 361: for (i=0; i<length; i++) { ! 362: x += xinc; y += yinc; ! 363: drawpoint((int) x, (int) y); ! 364: } ! 365: } ! 366: ! 367: /* ! 368: * drawpoint: make a point of the current flavor at (r, c). ! 369: */ ! 370: drawpoint(r, c) ! 371: register int r, c; ! 372: { ! 373: register int i, j; ! 374: ! 375: if (penweight == 0) ! 376: setmat(wind[curwind].val, GLROW, GLCOL, r, c, pencolor); ! 377: else { ! 378: for (i=0; i<10; i++) ! 379: for (j=0; j<10; j++) ! 380: if (penmat[i][j]) ! 381: setmat(wind[curwind].val, GLROW, GLCOL, r+i-4, c+j-4, pencolor); ! 382: } ! 383: } ! 384: ! 385: /* ! 386: * setcmd: handle the s command. Format: s <what> <where>. ! 387: */ ! 388: setcmd() ! 389: { ! 390: char what, where; ! 391: ! 392: message("set <what>"); ! 393: what = inchar(); ! 394: switch (what) { ! 395: ! 396: case 'p': /* set pen */ ! 397: message("set pen <weight>"); ! 398: where = inchar(); ! 399: switch (where) { ! 400: case 'f': /* set pen fine */ ! 401: case 'l': /* set pen light */ ! 402: message("set pen fine"); ! 403: penweight = 0; ! 404: break; ! 405: case 'h': /* set pen heavy */ ! 406: case 'b': /* set pen bold */ ! 407: message("set pen heavy"); ! 408: penweight = 1; ! 409: break; ! 410: default: ! 411: error("Illegal kind of pen weight"); ! 412: } ! 413: break; ! 414: ! 415: case 's': /* set size of heavy pen */ ! 416: message("set pen size to <size>"); ! 417: where = inchar() - '0'; ! 418: sprintf(msgbuf, "set pen size to %d", where); ! 419: message(msgbuf); ! 420: if (where > 0 && where < 10) { ! 421: setpen(where); ! 422: } else ! 423: error("Illegal size"); ! 424: break; ! 425: ! 426: case 'd': ! 427: message("set draw"); ! 428: pencolor = 1; ! 429: break; ! 430: ! 431: case 'e': ! 432: message("set erase"); ! 433: pencolor = 0; ! 434: break; ! 435: ! 436: default: ! 437: error("Illegal set"); ! 438: } ! 439: } ! 440: ! 441: /* ! 442: * setpen: set the heavy pen size to s. ! 443: * Main work here is defining template of pen. ! 444: */ ! 445: setpen(s) ! 446: int s; ! 447: { ! 448: register int i, j; ! 449: register float radius; ! 450: ! 451: if (s < 1) ! 452: s = 1; ! 453: hpensize = s; ! 454: radius = hpensize; ! 455: radius /= 2; ! 456: for (i=0; i<10; i++) { ! 457: for (j=0; j<10; j++) { ! 458: penmat[i][j] = (radius >= sqrtmat[abs(i-4)][abs(j-4)]); ! 459: } ! 460: } ! 461: ! 462: /* ! 463: * Kludge to make a 2-wide pen possible by specifying 1. ! 464: */ ! 465: if (hpensize == 1) ! 466: penmat[4][5] = 1; ! 467: ! 468: if (trace) ! 469: for (i=0; i<10; i++) { ! 470: for (j=0; j<10; j++) { ! 471: fprintf(trace, "%c", penmat[i][j] ? 'P' : '.'); ! 472: } ! 473: fprintf(trace, "\n"); ! 474: } ! 475: } ! 476: ! 477: /* ! 478: * error: print the given error message and return for another command. ! 479: */ ! 480: error(msg) ! 481: char *msg; ! 482: { ! 483: message(msg); ! 484: longjmp(env); ! 485: } ! 486: ! 487: /* ! 488: * copymove: do a move or copy command. ! 489: * cmd is C or M, the command. ! 490: */ ! 491: copymove(cmd) ! 492: char cmd; ! 493: { ! 494: char *action; ! 495: char src, dest; ! 496: bitmat cpy; ! 497: char lochr[5]; ! 498: ! 499: if (cmd == 'C') ! 500: action = "copy"; ! 501: else ! 502: action = "move"; ! 503: sprintf(msgbuf, "%s <from>", action); ! 504: message(msgbuf); ! 505: src = inchar(); ! 506: sprintf(msgbuf, "%s %s to <to>", action, rdchar(src)); ! 507: message(msgbuf); ! 508: dest = inchar(); ! 509: strcpy(lochr, rdchar(src)); ! 510: sprintf(msgbuf, "%s %s to %s", action, lochr, rdchar(dest)); ! 511: message(msgbuf); ! 512: ! 513: /* Do the copy */ ! 514: disptable[dest] = disptable[src]; ! 515: cht[dest] = cht[src]; ! 516: if (cht[dest].wherewind >= 0) ! 517: wind[cht[dest].wherewind].used = dest; ! 518: ! 519: if (cmd == 'C') { ! 520: if (cht[dest].wherewind != -1) { ! 521: /* ! 522: * Make copies of the window so changing ! 523: * one won't change the other. ! 524: * The old copy gets the window on the screen, if any, ! 525: * relegating the new copy to the background. ! 526: */ ! 527: cpy = newmat(GLROW, GLCOL); ! 528: if (cht[dest].wherewind >= 0) ! 529: bitcopy(cpy, wind[cht[src].wherewind].val, GLROW, GLCOL); ! 530: else ! 531: bitcopy(cpy, cht[src].whereat, GLROW, GLCOL); ! 532: if (cht[dest].wherewind == curwind) ! 533: curwind = -1; ! 534: cht[dest].wherewind = -2; ! 535: cht[dest].whereat = cpy; ! 536: } ! 537: } else { ! 538: /* ! 539: * Move. Delete the old entries. ! 540: */ ! 541: disptable[src].addr = disptable[src].nbytes = 0; ! 542: cht[src].wherewind = -1; ! 543: } ! 544: changes++; ! 545: } ! 546: ! 547: /* ! 548: * cch: make sure there is a current character. ! 549: */ ! 550: cch() ! 551: { ! 552: if (curwind < 0) ! 553: error("No current glyph"); ! 554: } ! 555: ! 556: /* ! 557: * confirm: if there have been changes, ask user if he is sure. ! 558: */ ! 559: confirm() ! 560: { ! 561: char ch; ! 562: ! 563: if (changes == 0) ! 564: return; ! 565: message("Changes since last write -- Are you sure?"); ! 566: ch = inchar(); ! 567: if (isupper(ch)) ! 568: ch = tolower(ch); ! 569: switch (ch) { ! 570: case 'y': ! 571: case 'q': ! 572: case 'e': ! 573: return; ! 574: case 'n': ! 575: default: ! 576: error("Not sure - aborted"); ! 577: } ! 578: } ! 579: ! 580: /* ! 581: * delchar: the D command. Delete a character from the buffer. ! 582: */ ! 583: delchar() ! 584: { ! 585: register char c, c1, c2; ! 586: register int w; ! 587: char buf[5]; ! 588: ! 589: message("delete <char>"); ! 590: c1 = inchar(); ! 591: sprintf(msgbuf, "delete %s through <char>", rdchar(c1)); ! 592: message(msgbuf); ! 593: c2 = inchar(); ! 594: strcpy(buf, rdchar(c1)); ! 595: sprintf(msgbuf, "delete %s through %s", buf, rdchar(c2)); ! 596: message(msgbuf); ! 597: changes++; ! 598: ! 599: for (c=c1; c<=c2; c++) { ! 600: if ((w = cht[c].wherewind) >= 0) { ! 601: zermat(wind[w].val, GLROW, GLCOL); ! 602: syncwind(w); ! 603: } ! 604: cht[c].wherewind = -1; ! 605: disptable[c].addr = 0; ! 606: disptable[c].nbytes = 0; ! 607: disptable[c].up = 0; ! 608: disptable[c].down = 0; ! 609: disptable[c].left = 0; ! 610: disptable[c].right = 0; ! 611: disptable[c].width = 0; ! 612: } ! 613: } ! 614: ! 615: /* ! 616: * zoom out to full screen so the screen doean't go nuts when we ! 617: * print off the current zoom window. Save old value of zoom in ! 618: * oldzoom so space can put us back. ! 619: */ ! 620: zoomout() ! 621: { ! 622: if (curzoom != 1) ! 623: zoomn(curzoom = 1); ! 624: } ! 625: ! 626: /* ! 627: * newglyph: the n command. ! 628: */ ! 629: newglyph() ! 630: { ! 631: register int i, j; ! 632: int windno; ! 633: int vertoff, horoff; ! 634: char *tmp; ! 635: ! 636: message("new glyph <char>"); ! 637: curchar = inchar(); ! 638: sprintf(msgbuf, "new glyph %s", rdchar(curchar)); ! 639: message(msgbuf); ! 640: ! 641: if (trace) ! 642: fprintf(trace, "\n\nnewglyph(%s)\n", rdchar(curchar)); ! 643: if (disptable[curchar].nbytes != 0) { ! 644: if (trace) ! 645: fprintf(trace, "char exists: %s\n", rdchar(curchar)); ! 646: sprintf(msgbuf, "char exists: %s", rdchar(curchar)); ! 647: error(msgbuf); ! 648: } ! 649: ! 650: turnofcurs(); ! 651: /* ! 652: * Not on screen. First find a suitable window, ! 653: * using round robin. ! 654: */ ! 655: windno = nextwind; ! 656: if (trace) ! 657: fprintf(trace, "chose window %d\n", windno); ! 658: if (++nextwind >= NWIND) ! 659: nextwind = 0; ! 660: #ifdef notdef ! 661: if (nextwind >= 3) ! 662: nextwind = 0; ! 663: #endif ! 664: wind[windno].used = curchar; ! 665: ! 666: /* Put a box around the current window */ ! 667: if (windno != curwind) { ! 668: drawbox(base[curwind].r-1, base[curwind].c-1, 0, GLROW+2, GLCOL+2); ! 669: drawbox(base[windno].r-1, base[windno].c-1, 1, GLROW+2, GLCOL+2); ! 670: } ! 671: ! 672: /* Print the char at the lower left of the window */ ! 673: sprintf(msgbuf, "%s", rdchar(curchar)); ! 674: dispmsg(msgbuf, base[windno].c, base[windno].r-11, 2); ! 675: ! 676: /* Now make room in the window */ ! 677: if (wind[windno].onscreen == NULL) { ! 678: /* Brand new window, have to allocate space */ ! 679: wind[windno].onscreen = newmat(GLROW, GLCOL); ! 680: } else { ! 681: /* Save prev glyph for later */ ! 682: cht[wind[curchar].used].whereat = wind[windno].val; ! 683: cht[wind[curchar].used].wherewind = -2; ! 684: } ! 685: if (wind[windno].undval != NULL) { ! 686: if (trace) ! 687: fprintf(trace, "newglyph frees undo: %x\n", wind[windno].undval); ! 688: free(wind[windno].undval); ! 689: } ! 690: wind[windno].undval = NULL; ! 691: ! 692: /* ! 693: * Vertical & horizontal offsets. Line up the baseline ! 694: * of the char at BASELINE from bottom, but center ! 695: * horizontally. ! 696: */ ! 697: wind[windno].val = newmat(GLROW, GLCOL); ! 698: ! 699: curwind = windno; ! 700: cht[curchar].wherewind = windno; ! 701: cht[curchar].rcent = curs_r = GLROW - BASELINE; ! 702: cht[curchar].ccent = curs_c = GLCOL / 2; ! 703: ! 704: #ifdef notdef ! 705: dumpmat("wind[windno].onscreen", wind[windno].onscreen, GLROW, GLCOL); ! 706: #endif ! 707: syncwind(windno); ! 708: ! 709: /* ! 710: * Mung the zoom out to 1 and back. This is needed to ! 711: * re-center the glyph on the screen if zoomed in, otherwise ! 712: * if you move by one window it puts the cursor way over at ! 713: * the right with only half the window visible. ! 714: */ ! 715: if ((i = curzoom) > 1) { ! 716: zoomn(1); ! 717: zoomn(i); ! 718: } ! 719: } ! 720: ! 721: /* ! 722: * numedit: change one of the numerical parameters. ! 723: */ ! 724: numedit() ! 725: { ! 726: short * sp = 0; ! 727: char * cp = 0; ! 728: char c, f; ! 729: char *fld; ! 730: short ovalue, nvalue; ! 731: char numb[20]; ! 732: ! 733: message("number of <char>"); ! 734: c = inchar(); ! 735: sprintf(msgbuf, "number of %s <field>", rdchar(c)); ! 736: message(msgbuf); ! 737: f = inchar(); ! 738: ! 739: switch (f) { ! 740: case 'a': sp = (short *) ! 741: &disptable[c].addr; fld = "addr"; break; ! 742: case 'n': sp = &disptable[c].nbytes; fld = "nbytes"; break; ! 743: case 'u': cp = &disptable[c].up; fld = "up"; break; ! 744: case 'd': cp = &disptable[c].down; fld = "down"; break; ! 745: case 'l': cp = &disptable[c].left; fld = "left"; break; ! 746: case 'r': cp = &disptable[c].right; fld = "right"; break; ! 747: case 'w': sp = &disptable[c].width; fld = "width"; break; ! 748: case 's': sp = (short *) &disptable[c].nbytes; ! 749: fld = "size"; break; ! 750: default: error("No such field"); ! 751: } ! 752: ! 753: ovalue = sp ? *sp : *cp; ! 754: sprintf(msgbuf, "number of %s %s (old value %d) is ", rdchar(c), fld, ovalue); ! 755: readline(msgbuf, numb, sizeof numb); ! 756: nvalue = atoi(numb); ! 757: if (cp) ! 758: *cp = nvalue; ! 759: else ! 760: *sp = nvalue; ! 761: changes++; ! 762: } ! 763: ! 764: /* ! 765: * These routines turn the cursor and rubber band line on and off, ! 766: * remembering its state for the o and r commands. ! 767: */ ! 768: turnoncurs() ! 769: { ! 770: curon(); ! 771: curcurs = 1; ! 772: } ! 773: ! 774: turnofcurs() ! 775: { ! 776: curoff(); ! 777: curcurs = 0; ! 778: } ! 779: ! 780: turnonrb() ! 781: { ! 782: rbon(); ! 783: currb = 1; ! 784: } ! 785: ! 786: turnofrb() ! 787: { ! 788: rboff(); ! 789: currb = 0; ! 790: } ! 791: ! 792: synccurs() ! 793: { ! 794: register int x, y; ! 795: ! 796: x = base[curwind].c + curs_c; ! 797: y = base[curwind].r + GLROW - curs_r - 1; ! 798: movecurs(x, y); ! 799: } ! 800: ! 801: inchar() ! 802: { ! 803: sync(); ! 804: synccurs(); ! 805: return (rawchar()); ! 806: } ! 807: ! 808: /* ! 809: * fillin - fill in with 1's all the spots that are in the enclosed ! 810: * area that (x, y) is in. ! 811: */ ! 812: fillin(x, y) ! 813: int x, y; ! 814: { ! 815: if (x<0 || x>=GLROW || y<0 || y>=GLCOL || ! 816: mat(wind[curwind].val, GLROW, GLCOL, x, y)) ! 817: return; ! 818: ! 819: setmat(wind[curwind].val, GLROW, GLCOL, x, y, 1); ! 820: fillin(x-1, y); ! 821: fillin(x+1, y); ! 822: fillin(x, y-1); ! 823: fillin(x, y+1); ! 824: } ! 825: ! 826: /* ! 827: * syncwind: make sure that window #n shows on the screen what it's ! 828: * supposed to after an arbitrary change. ! 829: */ ! 830: syncwind(n) ! 831: int n; ! 832: { ! 833: if (trace) ! 834: fprintf(trace, "syncwind(%d)\n", n); ! 835: update(wind[n].onscreen, wind[n].val, GLROW, GLCOL, base[n].r, base[n].c); ! 836: bitcopy(wind[n].onscreen, wind[n].val, GLROW, GLCOL); ! 837: } ! 838: ! 839: /* ! 840: * Embolden artificially emboldens the glyphs in the font by smearing ! 841: * them to the right by the current heavy pen size. Or else italicize it. ! 842: */ ! 843: artificial() ! 844: { ! 845: int low, high, cur; ! 846: int oldps, newps; ! 847: char lowch[10]; ! 848: #define ITAL 0 ! 849: #define BOLD 1 ! 850: #define RESIZE 2 ! 851: #define SMOOTH 3 ! 852: int kind; ! 853: char *strbold; ! 854: ! 855: sprintf(msgbuf, "Artificially <embolden/italicize/resize/smooth>"); ! 856: message(msgbuf); ! 857: ! 858: cur = inchar(); ! 859: switch(cur) { ! 860: case 'i': case 'I': kind = ITAL; strbold = "italicize"; break; ! 861: case 'e': case 'E': kind = BOLD; strbold = "embolden"; break; ! 862: case 'r': case 'R': kind = RESIZE; strbold = "resize"; break; ! 863: case 's': case 'S': kind = SMOOTH; strbold = "smooth"; break; ! 864: default: error("No such artificial operation"); ! 865: } ! 866: ! 867: sprintf(msgbuf, "Artificially %s glyphs from <char>", strbold); ! 868: message(msgbuf); ! 869: low = inchar(); ! 870: strcpy(lowch, rdchar(low)); ! 871: sprintf(msgbuf, "Artificially %s glyphs from %s to <char>", strbold, lowch); ! 872: message(msgbuf); ! 873: high = inchar(); ! 874: if (kind == RESIZE) { ! 875: sprintf(msgbuf, "Artificially %s glyphs from %s to %s from <point size>", strbold, lowch, rdchar(high)); ! 876: oldps = readnum(msgbuf); ! 877: sprintf(msgbuf, "Artificially %s glyphs from %s to %s from %dP to <point size>P", strbold, lowch, rdchar(high), oldps); ! 878: newps = readnum(msgbuf); ! 879: sprintf(msgbuf, "Artificially %s glyphs from %s to %s from %dP to %dP", strbold, lowch, rdchar(high), oldps, newps); ! 880: message(msgbuf); ! 881: if (oldps <= 0 || oldps > 36 || newps <= 0 || newps > 36 || oldps == newps) ! 882: error("Bad point sizes"); ! 883: } else { ! 884: sprintf(msgbuf, "Artificially %s glyphs from %s to %s", strbold, lowch, rdchar(high)); ! 885: message(msgbuf); ! 886: } ! 887: ! 888: for (cur=low; cur<=high; cur++) { ! 889: getglyph(cur); ! 890: if (curchar == cur) { /* e.g. if the getglyph succeeded */ ! 891: fflush(stdout); ! 892: switch (kind) { ! 893: case BOLD: ! 894: boldglyph(); ! 895: break; ! 896: case ITAL: ! 897: italglyph(); ! 898: break; ! 899: case RESIZE: ! 900: if (oldps > newps) ! 901: shrinkglyph(oldps, newps); ! 902: else ! 903: blowupglyph(oldps, newps); ! 904: break; ! 905: case SMOOTH: ! 906: smoothglyph(); ! 907: break; ! 908: } ! 909: syncwind(curwind); ! 910: } ! 911: } ! 912: message("Done"); ! 913: } ! 914: ! 915: /* ! 916: * Artificially embolden the current glyph. ! 917: */ ! 918: boldglyph() ! 919: { ! 920: register int r, c, i; ! 921: int smear = hpensize < 2 ? 2 : hpensize; ! 922: ! 923: for (r=0; r<GLROW; r++) ! 924: for (c=GLCOL-1; c>=smear; c--) ! 925: for (i=1; i<=smear; i++) ! 926: if (mat(wind[curwind].val, GLROW, GLCOL, r, c-i)) ! 927: setmat(wind[curwind].val, GLROW, GLCOL, r, c, 1); ! 928: } ! 929: ! 930: /* ! 931: * Artificially italicize the current glyph. ! 932: */ ! 933: italglyph() ! 934: { ! 935: register int r, c, i, off; ! 936: int baser = cht[curchar].rcent; /* GLROW - BASELINE; */ ! 937: ! 938: for (r=0; r<baser; r++) { ! 939: off = (baser-r) / SLOPE + 0.5; ! 940: for (c=GLCOL-1; c>=off; c--) { ! 941: setmat(wind[curwind].val, GLROW, GLCOL, r, c, ! 942: mat(wind[curwind].val, GLROW, GLCOL, r, c-off)); ! 943: } ! 944: for (c=off-1; c>=0; c--) ! 945: setmat(wind[curwind].val, GLROW, GLCOL, r, c, 0); ! 946: } ! 947: for (r=baser; r<GLROW; r++) { ! 948: off = (r-baser) * (2.0/7.0) + 0.5; ! 949: for (c=off; c<GLCOL; c++) ! 950: setmat(wind[curwind].val, GLROW, GLCOL, r, c-off, ! 951: mat(wind[curwind].val, GLROW, GLCOL, r, c)); ! 952: for (c=off-1; c>=0; c--) ! 953: setmat(wind[curwind].val, GLROW, GLCOL, r, c, 0); ! 954: } ! 955: } ! 956: ! 957: /* ! 958: * Blow up or shrink a glyph from oldps points to newps points. ! 959: * The basic idea is that for each on point in the old glyph we ! 960: * find the corresponding point in the new glyph and copy the value. ! 961: */ ! 962: shrinkglyph(oldps, newps) ! 963: int oldps, newps; ! 964: { ! 965: float ratio; ! 966: register int or, oc, nr, nc; ! 967: int n; ! 968: bitmat tmp, curw; ! 969: int baser = cht[curchar].rcent; ! 970: int basec = cht[curchar].ccent; ! 971: ! 972: ratio = (float) newps / (float) oldps; ! 973: tmp = newmat(GLROW, GLCOL); ! 974: curw = wind[curwind].val; ! 975: bitcopy(tmp, curw, GLROW, GLCOL); ! 976: zermat(curw, GLROW, GLCOL); ! 977: for (or=0; or<GLROW; or++) { ! 978: nr = baser + (or-baser)*ratio + 0.5; ! 979: for (oc=0; oc<GLCOL; oc++) { ! 980: nc = basec + (oc-basec)*ratio + 0.5; ! 981: if (nr < 0 || nr >= GLROW || nc < 0 || nc >= GLCOL) ! 982: n = 0; ! 983: else ! 984: n = mat(tmp, GLROW, GLCOL, or, oc); ! 985: if (n) ! 986: setmat(curw, GLROW, GLCOL, nr, nc, n); ! 987: } ! 988: } ! 989: disptable[curchar].width = disptable[curchar].width * ratio + 0.5; ! 990: free(tmp); ! 991: } ! 992: ! 993: /* ! 994: * blow up a glyph. Otherwise like shrinkglyph. ! 995: */ ! 996: blowupglyph(oldps, newps) ! 997: int oldps, newps; ! 998: { ! 999: float ratio; ! 1000: register int or, oc, nr, nc; ! 1001: int n; ! 1002: bitmat tmp, curw; ! 1003: int baser = cht[curchar].rcent; ! 1004: int basec = cht[curchar].ccent; ! 1005: ! 1006: ratio = (float) oldps / (float) newps; ! 1007: tmp = newmat(GLROW, GLCOL); ! 1008: curw = wind[curwind].val; ! 1009: bitcopy(tmp, curw, GLROW, GLCOL); ! 1010: zermat(curw, GLROW, GLCOL); ! 1011: for (nr=0; nr<GLROW; nr++) { ! 1012: or = baser + (nr-baser)*ratio + 0.5; ! 1013: for (nc=0; nc<GLCOL; nc++) { ! 1014: oc = basec + (nc-basec)*ratio + 0.5; ! 1015: if (or < 0 || or >= GLROW || oc < 0 || oc >= GLCOL) ! 1016: n = 0; ! 1017: else ! 1018: n = mat(tmp, GLROW, GLCOL, or, oc); ! 1019: if (n) ! 1020: setmat(curw, GLROW, GLCOL, nr, nc, n); ! 1021: } ! 1022: } ! 1023: disptable[curchar].width = disptable[curchar].width / ratio + 0.5; ! 1024: free(tmp); ! 1025: } ! 1026: ! 1027: /* ! 1028: * Smooth a glyph. We look for corners and trim the point. Corners of ! 1029: * both blanks and dots in all 4 orientations are looked for. ! 1030: */ ! 1031: smoothglyph() ! 1032: { ! 1033: bitmat tmp, curw; ! 1034: register int r, c; ! 1035: register int c3; ! 1036: int a3, b2, b3, b4, c1, c2, c4, c5, d2, d3, d4, e3; ! 1037: ! 1038: tmp = newmat(GLROW, GLCOL); ! 1039: curw = wind[curwind].val; ! 1040: bitcopy(tmp, curw, GLROW, GLCOL); ! 1041: for (r=2; r<GLROW-2; r++) ! 1042: for (c=2; c<GLCOL-2; c++) { ! 1043: /* ! 1044: * a3 ! 1045: * b2 b3 b4 ! 1046: * c1 c2 c3 c4 c5 ! 1047: * d2 d3 d4 ! 1048: * d4 ! 1049: * where c3 is the square we are interested in ! 1050: */ ! 1051: b3 = mat(tmp, GLROW, GLCOL, r-1, c ); ! 1052: c2 = mat(tmp, GLROW, GLCOL, r , c-1); ! 1053: c4 = mat(tmp, GLROW, GLCOL, r , c+1); ! 1054: d3 = mat(tmp, GLROW, GLCOL, r+1, c ); ! 1055: /* exactly 2 of the 4 neighbors must be dots */ ! 1056: if (b3+c2+c4+d3 != 2) continue; ! 1057: ! 1058: c3 = mat(tmp, GLROW, GLCOL, r , c ); ! 1059: b2 = mat(tmp, GLROW, GLCOL, r-1, c-1); ! 1060: b4 = mat(tmp, GLROW, GLCOL, r-1, c+1); ! 1061: d2 = mat(tmp, GLROW, GLCOL, r+1, c-1); ! 1062: d4 = mat(tmp, GLROW, GLCOL, r+1, c+1); ! 1063: /* exactly one of the 4 diags must match the center */ ! 1064: if (b2+b4+d2+d4 != 3 - 2*c3) continue; ! 1065: ! 1066: a3 = mat(tmp, GLROW, GLCOL, r-2, c ); ! 1067: c1 = mat(tmp, GLROW, GLCOL, r , c-2); ! 1068: c5 = mat(tmp, GLROW, GLCOL, r , c+2); ! 1069: e3 = mat(tmp, GLROW, GLCOL, r+2, c ); ! 1070: ! 1071: /* Figure out which of the 4 directions */ ! 1072: if (b2==c3) { ! 1073: if (b3+c2+c1+a3 != 4*c3) continue; ! 1074: } else ! 1075: if (b4==c3) { ! 1076: if (b3+c4+c5+a3 != 4*c3) continue; ! 1077: } else ! 1078: if (d2==c3) { ! 1079: if (d3+c2+c1+e3 != 4*c3) continue; ! 1080: } else ! 1081: if (d4==c3) { ! 1082: if (d3+c4+c5+e3 != 4*c3) continue; ! 1083: } ! 1084: ! 1085: /* It must be a corner. Toggle it. */ ! 1086: setmat(curw, GLROW, GLCOL, r, c, !c3); ! 1087: } ! 1088: free(tmp); ! 1089: } ! 1090: ! 1091: /* ! 1092: * Read a number from bottom line ala readline. ! 1093: * This should probably go in lib2648. ! 1094: */ ! 1095: int ! 1096: readnum(prompt) ! 1097: char *prompt; ! 1098: { ! 1099: char buf[10]; ! 1100: int retval; ! 1101: ! 1102: readline(prompt, buf, sizeof buf); ! 1103: retval = atoi(buf); ! 1104: if (trace) ! 1105: fprintf(trace, "readline returns '%s', retval=%d\n", buf, retval); ! 1106: return (retval); ! 1107: } ! 1108: ! 1109: invert() ! 1110: { ! 1111: register int r, c; ! 1112: int tmp1, tmp2, kind; ! 1113: bitmat curw = wind[curwind].val; ! 1114: ! 1115: message("Invert <horizontally/vertically>"); ! 1116: kind = inchar(); ! 1117: switch (kind) { ! 1118: case 'h': case 'H': ! 1119: message("Invert horizontally"); ! 1120: for (r=0; r<GLROW; r++) { ! 1121: if (trace) ! 1122: fprintf(trace, "row %d\n", r); ! 1123: for (c=0; c<=(GLCOL-1)/2; c++) { ! 1124: tmp1 = mat(curw, GLROW, GLCOL, r, c); ! 1125: tmp2 = mat(curw, GLROW, GLCOL, r, GLCOL-1-c); ! 1126: if (trace) ! 1127: fprintf(trace, "cols %d (%d) <=> %d (%d)\n", c, tmp1, GLCOL-1-c, tmp2); ! 1128: setmat(curw, GLROW, GLCOL, r, c, tmp2); ! 1129: setmat(curw, GLROW, GLCOL, r, GLCOL-1-c, tmp1); ! 1130: } ! 1131: } ! 1132: break; ! 1133: case 'v': case 'V': ! 1134: message("Invert vertically"); ! 1135: for (c=0; c<GLCOL; c++) { ! 1136: for (r=0; r<=(GLROW-1)/2; r++) { ! 1137: tmp1 = mat(curw, GLROW, GLCOL, r, c); ! 1138: tmp2 = mat(curw, GLROW, GLCOL, GLROW-1-r, c); ! 1139: setmat(curw, GLROW, GLCOL, r, c, tmp2); ! 1140: setmat(curw, GLROW, GLCOL, GLROW-1-r, c, tmp1); ! 1141: } ! 1142: } ! 1143: break; ! 1144: default: ! 1145: error("Bad choice"); ! 1146: } ! 1147: syncwind(curwind); ! 1148: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.