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: }