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

Defined functions

artificial defined in line 843; used 1 times
blowupglyph defined in line 996; used 1 times
boldglyph defined in line 918; used 1 times
bufmod defined in line 298; used 6 times
cch defined in line 550; used 12 times
confirm defined in line 559; used 2 times
copymove defined in line 491; used 1 times
delchar defined in line 583; used 1 times
drawline defined in line 340; used 1 times
drawpoint defined in line 370; used 2 times
error defined in line 480; used 25 times
fillin defined in line 812; used 5 times
findbits defined in line 213; used 4 times
inchar defined in line 801; used 28 times
initialize defined in line 14; used 1 times
invert defined in line 1109; used 1 times
italglyph defined in line 933; used 1 times
newglyph defined in line 629; used 1 times
numedit defined in line 724; used 1 times
placechar defined in line 165; used 2 times
readnum defined in line 1095; used 2 times
redraw defined in line 189; used 3 times
setcmd defined in line 388; used 1 times
setpen defined in line 445; used 3 times
showfont defined in line 53; used 1 times
shrinkglyph defined in line 962; used 1 times
smoothglyph defined in line 1031; used 1 times
synccurs defined in line 792; used 1 times
syncwind defined in line 830; used 12 times
turnofcurs defined in line 774; used 5 times
turnofrb defined in line 786; used 3 times
turnoncurs defined in line 768; used 8 times
turnonrb defined in line 780; used 2 times
typein defined in line 111; used 1 times
undo defined in line 315; used 1 times
zoomout defined in line 620; used 3 times

Defined variables

sccsid defined in line 2; never used

Defined macros

BOLD defined in line 849; used 1 times
ITAL defined in line 848; used 1 times
RESIZE defined in line 850; used 2 times
SMOOTH defined in line 851; used 1 times
Last modified: 1983-08-12
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3416
Valid CSS Valid XHTML 1.0 Strict