1: /* Copyright (c) 1979 Regents of the University of California */
   2: #include "ex.h"
   3: #include "ex_tty.h"
   4: #include "ex_vis.h"
   5: 
   6: /*
   7:  * Deal with the screen, clearing, cursor positioning, putting characters
   8:  * into the screen image, and deleting characters.
   9:  * Really hard stuff here is utilizing insert character operations
  10:  * on intelligent terminals which differs widely from terminal to terminal.
  11:  */
  12: vclear()
  13: {
  14: 
  15: #ifdef ADEBUG
  16:     if (trace)
  17:         tfixnl(), fprintf(trace, "------\nvclear\n");
  18: #endif
  19:     tputs(CL, LINES, putch);
  20:     destcol = 0;
  21:     outcol = 0;
  22:     destline = 0;
  23:     outline = 0;
  24:     if (inopen)
  25:         vclrbyte(vtube0, WCOLS * (WECHO - ZERO + 1));
  26: }
  27: 
  28: /*
  29:  * Clear memory.
  30:  */
  31: vclrbyte(cp, i)
  32:     register char *cp;
  33:     register int i;
  34: {
  35: 
  36:     if (i > 0)
  37:         do
  38:             *cp++ = 0;
  39:         while (--i != 0);
  40: }
  41: 
  42: /*
  43:  * Clear a physical display line, high level.
  44:  */
  45: vclrlin(l, tp)
  46:     int l;
  47:     line *tp;
  48: {
  49: 
  50:     vigoto(l, 0);
  51:     if ((hold & HOLDAT) == 0)
  52:         putchar(tp > dol ? ((UPPERCASE || HZ) ? '^' : '~') : '@');
  53: #ifdef OPENCODE
  54:     if (state == HARDOPEN)
  55:         sethard();
  56: #endif
  57:     vclreol();
  58: }
  59: 
  60: /*
  61:  * Clear to the end of the current physical line
  62:  */
  63: vclreol()
  64: {
  65:     register int i, j;
  66:     register char *tp;
  67: 
  68:     if (destcol == WCOLS)
  69:         return;
  70:     destline += destcol / WCOLS;
  71:     destcol %= WCOLS;
  72:     if (destline < 0 || destline > WECHO)
  73:         error("Internal error: vclreol");
  74:     i = WCOLS - destcol;
  75:     tp = vtube[destline] + destcol;
  76:     if (CE) {
  77:         if (IN && *tp || !ateopr()) {
  78:             vcsync();
  79:             vputp(CE, 1);
  80:         }
  81:         vclrbyte(tp, i);
  82:         return;
  83:     }
  84:     if (*tp == 0)
  85:         return;
  86:     while (i > 0 && (j = *tp & (QUOTE|TRIM))) {
  87:         if (j != ' ' && (j & QUOTE) == 0) {
  88:             destcol = WCOLS - i;
  89:             vputchar(' ');
  90:         }
  91:         --i, *tp++ = 0;
  92:     }
  93: }
  94: 
  95: /*
  96:  * Clear the echo line.
  97:  * If didphys then its been cleared physically (as
  98:  * a side effect of a clear to end of display, e.g.)
  99:  * so just do it logically.
 100:  * If work here is being held off, just remember, in
 101:  * heldech, if work needs to be done, don't do anything.
 102:  */
 103: vclrech(didphys)
 104:     bool didphys;
 105: {
 106: 
 107:     if (Peekkey == ATTN)
 108:         return;
 109:     if (hold & HOLDECH) {
 110:         heldech = !didphys;
 111:         return;
 112:     }
 113:     if (!didphys && (CD || CE)) {
 114:         splitw++;
 115:         /*
 116: 		 * If display is retained below, then MUST use CD or CE
 117: 		 * since we don't really know whats out there.
 118: 		 * Vigoto might decide (incorrectly) to do nothing.
 119: 		 */
 120:         if (DB) {
 121:             vgoto(WECHO, 0);
 122:             vputp(CD ? CD : CE, 1);
 123:         } else {
 124:             if (XT) {
 125:                 /*
 126: 				 * This code basically handles the t1061
 127: 				 * where positioning at (0, 0) won't work
 128: 				 * because the terminal won't let you put
 129: 				 * the cursor on its magic cookie.
 130: 				 *
 131: 				 * Should probably be XS above, or even a
 132: 				 * new X? glitch, but right now t1061 is the
 133: 				 * only terminal with XT.
 134: 				 */
 135:                 vgoto(WECHO, 0);
 136:                 vputp(DL, 1);
 137:             } else {
 138:                 vigoto(WECHO, 0);
 139:                 vclreol();
 140:             }
 141:         }
 142:         splitw = 0;
 143:         didphys = 1;
 144:     }
 145:     if (didphys)
 146:         vclrbyte(vtube[WECHO], WCOLS);
 147:     heldech = 0;
 148: }
 149: 
 150: /*
 151:  * Fix the echo area for use, setting
 152:  * the state variable splitw so we wont rollup
 153:  * when we move the cursor there.
 154:  */
 155: fixech()
 156: {
 157: 
 158:     splitw++;
 159: #ifdef OPENCODE
 160:     if (state != VISUAL && state != CRTOPEN) {
 161:         vclean();
 162:         vcnt = 0;
 163:     }
 164: #endif
 165:     vgoto(WECHO, 0); flusho();
 166: }
 167: 
 168: /*
 169:  * Put the cursor ``before'' cp.
 170:  */
 171: vcursbef(cp)
 172:     register char *cp;
 173: {
 174: 
 175:     if (cp <= linebuf)
 176:         vgotoCL(value(NUMBER) << 3);
 177:     else
 178:         vgotoCL(column(cp - 1) - 1);
 179: }
 180: 
 181: /*
 182:  * Put the cursor ``at'' cp.
 183:  */
 184: vcursat(cp)
 185:     register char *cp;
 186: {
 187: 
 188:     if (cp <= linebuf && linebuf[0] == 0)
 189:         vgotoCL(value(NUMBER) << 3);
 190:     else
 191:         vgotoCL(column(cp - 1));
 192: }
 193: 
 194: /*
 195:  * Put the cursor ``after'' cp.
 196:  */
 197: vcursaft(cp)
 198:     register char *cp;
 199: {
 200: 
 201:     vgotoCL(column(cp));
 202: }
 203: 
 204: /*
 205:  * Fix the cursor to be positioned in the correct place
 206:  * to accept a command.
 207:  */
 208: vfixcurs()
 209: {
 210: 
 211:     vsetcurs(cursor);
 212: }
 213: 
 214: /*
 215:  * Compute the column position implied by the cursor at ``nc'',
 216:  * and move the cursor there.
 217:  */
 218: vsetcurs(nc)
 219:     register char *nc;
 220: {
 221:     register int col;
 222: 
 223:     col = column(nc);
 224:     if (linebuf[0])
 225:         col--;
 226:     vgotoCL(col);
 227:     cursor = nc;
 228: }
 229: 
 230: /*
 231:  * Move the cursor invisibly, i.e. only remember to do it.
 232:  */
 233: vigoto(y, x)
 234:     int y, x;
 235: {
 236: 
 237:     destline = y;
 238:     destcol = x;
 239: }
 240: 
 241: /*
 242:  * Move the cursor to the position implied by any previous
 243:  * vigoto (or low level hacking with destcol/destline as in readecho).
 244:  */
 245: vcsync()
 246: {
 247: 
 248:     vgoto(destline, destcol);
 249: }
 250: 
 251: /*
 252:  * Goto column x of the current line.
 253:  */
 254: vgotoCL(x)
 255:     register int x;
 256: {
 257: 
 258:     if (splitw)
 259:         vgoto(WECHO, x);
 260:     else
 261:         vgoto(LINE(vcline), x);
 262: }
 263: 
 264: /*
 265:  * Invisible goto column x of current line.
 266:  */
 267: vigotoCL(x)
 268:     register int x;
 269: {
 270: 
 271:     if (splitw)
 272:         vigoto(WECHO, x);
 273:     else
 274:         vigoto(LINE(vcline), x);
 275: }
 276: 
 277: /*
 278:  * Move cursor to line y, column x, handling wraparound and scrolling.
 279:  */
 280: vgoto(y, x)
 281:     register int y, x;
 282: {
 283:     register char *tp;
 284:     register int c;
 285: 
 286:     /*
 287: 	 * Fold the possibly too large value of x.
 288: 	 */
 289:     if (x >= WCOLS) {
 290:         y += x / WCOLS;
 291:         x %= WCOLS;
 292:     }
 293:     if (y < 0)
 294:         error("Internal error: vgoto");
 295:     if (outcol >= WCOLS) {
 296:         if (AM) {
 297:             outline += outcol / WCOLS;
 298:             outcol %= WCOLS;
 299:         } else
 300:             outcol = WCOLS - 1;
 301:     }
 302: 
 303: #ifdef OPENCODE
 304:     /*
 305: 	 * In a hardcopy or glass crt open, print the stuff
 306: 	 * implied by a motion, or backspace.
 307: 	 */
 308:     if (state == HARDOPEN || state == ONEOPEN) {
 309:         if (y != outline)
 310:             error("Line too long for open");
 311:         if (x + 1 < outcol - x || (outcol > x && !BS))
 312:             destcol = 0, fgoto();
 313:         tp = vtube[WBOT] + outcol;
 314:         while (outcol != x)
 315:             if (outcol < x) {
 316:                 if (*tp == 0)
 317:                     *tp = ' ';
 318:                 c = *tp++ & TRIM;
 319:                 vputc(c && (!OS || EO) ? c : ' '), outcol++;
 320:             } else {
 321:                 if (BC)
 322:                     vputp(BC, 0);
 323:                 else
 324:                     vputc('\b');
 325:                 outcol--;
 326:             }
 327:         destcol = outcol = x;
 328:         destline = outline;
 329:         return;
 330:     }
 331: #endif
 332: 
 333:     /*
 334: 	 * If the destination position implies a scroll, do it.
 335: 	 */
 336:     destline = y;
 337:     if (destline > WBOT && (!splitw || destline > WECHO)) {
 338:         endim();
 339:         vrollup(destline);
 340:     }
 341: 
 342:     /*
 343: 	 * If there really is a motion involved, do it.
 344: 	 * The check here is an optimization based on profiling.
 345: 	 */
 346:     destcol = x;
 347:     if ((destline - outline) * WCOLS != destcol - outcol) {
 348:         if (!MI)
 349:             endim();
 350:         fgoto();
 351:     }
 352: }
 353: 
 354: /*
 355:  * This is the hardest code in the editor, and deals with insert modes
 356:  * on different kinds of intelligent terminals.  The complexity is due
 357:  * to the cross product of three factors:
 358:  *
 359:  *	1. Lines may display as more than one segment on the screen.
 360:  *	2. There are 2 kinds of intelligent terminal insert modes.
 361:  *	3. Tabs squash when you insert characters in front of them,
 362:  *	   in a way in which current intelligent terminals don't handle.
 363:  *
 364:  * The two kinds of terminals are typified by the DM2500 or HP2645 for
 365:  * one and the CONCEPT-100 or the FOX for the other.
 366:  *
 367:  * The first (HP2645) kind has an insert mode where the characters
 368:  * fall off the end of the line and the screen is shifted rigidly
 369:  * no matter how the display came about.
 370:  *
 371:  * The second (CONCEPT-100) kind comes from terminals which are designed
 372:  * for forms editing and which distinguish between blanks and ``spaces''
 373:  * on the screen, spaces being like blank, but never having had
 374:  * and data typed into that screen position (since, e.g. a clear operation
 375:  * like clear screen).  On these terminals, when you insert a character,
 376:  * the characters from where you are to the end of the screen shift
 377:  * over till a ``space'' is found, and the null character there gets
 378:  * eaten up.
 379:  *
 380:  *
 381:  * The code here considers the line as consisting of several parts
 382:  * the first part is the ``doomed'' part, i.e. a part of the line
 383:  * which is being typed over.  Next comes some text up to the first
 384:  * following tab.  The tab is the next segment of the line, and finally
 385:  * text after the tab.
 386:  *
 387:  * We have to consider each of these segments and the effect of the
 388:  * insertion of a character on them.  On terminals like HP2645's we
 389:  * must simulate a multi-line insert mode using the primitive one
 390:  * line insert mode.  If we are inserting in front of a tab, we have
 391:  * to either delete characters from the tab or insert white space
 392:  * (when the tab reaches a new spot where it gets larger) before we
 393:  * insert the new character.
 394:  *
 395:  * On a terminal like a CONCEPT our strategy is to make all
 396:  * blanks be displayed, while trying to keep the screen having ``spaces''
 397:  * for portions of tabs.  In this way the terminal hardward does some
 398:  * of the hacking for compression of tabs, although this tends to
 399:  * disappear as you work on the line and spaces change into blanks.
 400:  *
 401:  * There are a number of boundary conditions (like typing just before
 402:  * the first following tab) where we can avoid a lot of work.  Most
 403:  * of them have to be dealt with explicitly because performance is
 404:  * much, much worse if we don't.
 405:  *
 406:  * A final thing which is hacked here is two flavors of insert mode.
 407:  * Datamedia's do this by an insert mode which you enter and leave
 408:  * and by having normal motion character operate differently in this
 409:  * mode, notably by having a newline insert a line on the screen in
 410:  * this mode.  This generally means it is unsafe to move around
 411:  * the screen ignoring the fact that we are in this mode.
 412:  * This is possible on some terminals, and wins big (e.g. HP), so
 413:  * we encode this as a ``can move in insert capability'' mi,
 414:  * and terminals which have it can do insert mode with much less
 415:  * work when tabs are present following the cursor on the current line.
 416:  */
 417: 
 418: /*
 419:  * Routine to expand a tab, calling the normal Outchar routine
 420:  * to put out each implied character.  Note that we call outchar
 421:  * with a QUOTE.  We use QUOTE internally to represent a position
 422:  * which is part of the expansion of a tab.
 423:  */
 424: vgotab()
 425: {
 426:     register int i = destcol;
 427: 
 428:     do
 429:         (*Outchar)(QUOTE);
 430:     while (++i % value(TABSTOP));
 431: }
 432: 
 433: /*
 434:  * Variables for insert mode.
 435:  */
 436: int linend;         /* The column position of end of line */
 437: int tabstart;       /* Column of start of first following tab */
 438: int tabend;         /* Column of end of following tabs */
 439: int tabsize;        /* Size of the following tabs */
 440: int tabslack;       /* Number of ``spaces'' in following tabs */
 441: int inssiz;         /* Number of characters to be inserted */
 442: int inscol;         /* Column where insertion is taking place */
 443: int shft;           /* Amount tab expansion shifted rest of line */
 444: int slakused;       /* This much of tabslack will be used up */
 445: 
 446: /*
 447:  * This routine MUST be called before insert mode is run,
 448:  * and brings all segments of the current line to the top
 449:  * of the screen image buffer so it is easier for us to
 450:  * maniuplate them.
 451:  */
 452: vprepins()
 453: {
 454:     register int i;
 455:     register char *cp = vtube0;
 456: 
 457:     for (i = 0; i < DEPTH(vcline); i++) {
 458:         vmaktop(LINE(vcline) + i, cp);
 459:         cp += WCOLS;
 460:     }
 461: }
 462: 
 463: vmaktop(p, cp)
 464:     register int p;
 465:     char *cp;
 466: {
 467:     register int i;
 468:     char temp[TUBECOLS];
 469: 
 470:     if (vtube[p] == cp)
 471:         return;
 472:     for (i = ZERO; i <= WECHO; i++)
 473:         if (vtube[i] == cp) {
 474:             copy(temp, vtube[i], WCOLS);
 475:             copy(vtube[i], vtube[p], WCOLS);
 476:             copy(vtube[p], temp, WCOLS);
 477:             vtube[i] = vtube[p];
 478:             vtube[p] = cp;
 479:             return;
 480:         }
 481:     error("Line too long");
 482: }
 483: 
 484: /*
 485:  * Insert character c at current cursor position.
 486:  * Multi-character inserts occur only as a result
 487:  * of expansion of tabs (i.e. inssize == 1 except
 488:  * for tabs) and code assumes this in several place
 489:  * to make life simpler.
 490:  */
 491: vinschar(c)
 492:     char c;
 493: {
 494:     register int i;
 495:     register char *tp;
 496: 
 497:     if ((!IM || !EI) && ((hold & HOLDQIK) || !value(REDRAW) || value(SLOWOPEN))) {
 498:         /*
 499: 		 * Don't want to try to use terminal
 500: 		 * insert mode, or to try to fake it.
 501: 		 * Just put the character out; the screen
 502: 		 * will probably be wrong but we will fix it later.
 503: 		 */
 504:         if (c == '\t') {
 505:             vgotab();
 506:             return;
 507:         }
 508:         vputchar(c);
 509:         if (DEPTH(vcline) * WCOLS + !value(REDRAW) >
 510:             (destline - LINE(vcline)) * WCOLS + destcol)
 511:             return;
 512:         /*
 513: 		 * The next line is about to be clobbered
 514: 		 * make space for another segment of this line
 515: 		 * (on an intelligent terminal) or just remember
 516: 		 * that next line was clobbered (on a dumb one
 517: 		 * if we don't care to redraw the tail.
 518: 		 */
 519:         if (AL) {
 520:             vnpins(0);
 521:         } else {
 522:             c = LINE(vcline) + DEPTH(vcline);
 523:             if (c < LINE(vcline + 1) || c > WBOT)
 524:                 return;
 525:             i = destcol;
 526:             vinslin(c, 1, vcline);
 527:             DEPTH(vcline)++;
 528:             vigoto(c, i);
 529:             vprepins();
 530:         }
 531:         return;
 532:     }
 533:     /*
 534: 	 * Compute the number of positions in the line image of the
 535: 	 * current line.  This is done from the physical image
 536: 	 * since that is faster.  Note that we have no memory
 537: 	 * from insertion to insertion so that routines which use
 538: 	 * us don't have to worry about moving the cursor around.
 539: 	 */
 540:     if (*vtube0 == 0)
 541:         linend = 0;
 542:     else {
 543:         /*
 544: 		 * Search backwards for a non-null character
 545: 		 * from the end of the displayed line.
 546: 		 */
 547:         i = WCOLS * DEPTH(vcline);
 548:         if (i == 0)
 549:             i = WCOLS;
 550:         tp = vtube0 + i;
 551:         while (*--tp == 0)
 552:             if (--i == 0)
 553:                 break;
 554:         linend = i;
 555:     }
 556: 
 557:     /*
 558: 	 * We insert at a position based on the physical location
 559: 	 * of the output cursor.
 560: 	 */
 561:     inscol = destcol + (destline - LINE(vcline)) * WCOLS;
 562:     if (c == '\t') {
 563:         /*
 564: 		 * Characters inserted from a tab must be
 565: 		 * remembered as being part of a tab, but we can't
 566: 		 * use QUOTE here since we really need to print blanks.
 567: 		 * QUOTE|' ' is the representation of this.
 568: 		 */
 569:         inssiz = value(TABSTOP) - inscol % value(TABSTOP);
 570:         c = ' ' | QUOTE;
 571:     } else
 572:         inssiz = 1;
 573: 
 574:     /*
 575: 	 * If the text to be inserted is less than the number
 576: 	 * of doomed positions, then we don't need insert mode,
 577: 	 * rather we can just typeover.
 578: 	 */
 579:     if (inssiz <= doomed) {
 580:         endim();
 581:         if (inscol != linend)
 582:             doomed -= inssiz;
 583:         do
 584:             vputchar(c);
 585:         while (--inssiz);
 586:         return;
 587:     }
 588: 
 589:     /*
 590: 	 * Have to really do some insertion, thus
 591: 	 * stake out the bounds of the first following
 592: 	 * group of tabs, computing starting position,
 593: 	 * ending position, and the number of ``spaces'' therein
 594: 	 * so we can tell how much it will squish.
 595: 	 */
 596:     tp = vtube0 + inscol;
 597:     for (i = inscol; i < linend; i++)
 598:         if (*tp++ & QUOTE) {
 599:             --tp;
 600:             break;
 601:         }
 602:     tabstart = tabend = i;
 603:     tabslack = 0;
 604:     while (tabend < linend) {
 605:         i = *tp++;
 606:         if ((i & QUOTE) == 0)
 607:             break;
 608:         if ((i & TRIM) == 0)
 609:             tabslack++;
 610:         tabsize++;
 611:         tabend++;
 612:     }
 613:     tabsize = tabend - tabstart;
 614: 
 615:     /*
 616: 	 * For HP's and DM's, e.g. tabslack has no meaning.
 617: 	 */
 618:     if (!IN)
 619:         tabslack = 0;
 620: #ifdef IDEBUG
 621:     if (trace) {
 622:         fprintf(trace, "inscol %d, inssiz %d, tabstart %d, ",
 623:             inscol, inssiz, tabstart);
 624:         fprintf(trace, "tabend %d, tabslack %d, linend %d\n",
 625:             tabend, tabslack, linend);
 626:     }
 627: #endif
 628: 
 629:     /*
 630: 	 * The real work begins.
 631: 	 */
 632:     slakused = 0;
 633:     shft = 0;
 634:     if (tabsize) {
 635:         /*
 636: 		 * There are tabs on this line.
 637: 		 * If they need to expand, then the rest of the line
 638: 		 * will have to be shifted over.  In this case,
 639: 		 * we will need to make sure there are no ``spaces''
 640: 		 * in the rest of the line (on e.g. CONCEPT-100)
 641: 		 * and then grab another segment on the screen if this
 642: 		 * line is now deeper.  We then do the shift
 643: 		 * implied by the insertion.
 644: 		 */
 645:         if (inssiz >= doomed + value(TABSTOP) - tabstart % value(TABSTOP)) {
 646:             if (IN)
 647:                 vrigid();
 648:             vneedpos(value(TABSTOP));
 649:             vishft();
 650:         }
 651:     } else if (inssiz > doomed)
 652:         /*
 653: 		 * No tabs, but line may still get deeper.
 654: 		 */
 655:         vneedpos(inssiz - doomed);
 656:     /*
 657: 	 * Now put in the inserted characters.
 658: 	 */
 659:     viin(c);
 660: 
 661:     /*
 662: 	 * Now put the cursor in its final resting place.
 663: 	 */
 664:     destline = LINE(vcline);
 665:     destcol = inscol + inssiz;
 666:     vcsync();
 667: }
 668: 
 669: /*
 670:  * Rigidify the rest of the line after the first
 671:  * group of following tabs, typing blanks over ``spaces''.
 672:  */
 673: vrigid()
 674: {
 675:     register int col;
 676:     register char *tp = vtube0 + tabend;
 677: 
 678:     for (col = tabend; col < linend; col++)
 679:         if ((*tp++ & TRIM) == 0) {
 680:             endim();
 681:             vgotoCL(col);
 682:             vputchar(' ' | QUOTE);
 683:         }
 684: }
 685: 
 686: /*
 687:  * We need cnt more positions on this line.
 688:  * Open up new space on the screen (this may in fact be a
 689:  * screen rollup).
 690:  *
 691:  * On a dumb terminal we may infact redisplay the rest of the
 692:  * screen here brute force to keep it pretty.
 693:  */
 694: vneedpos(cnt)
 695:     int cnt;
 696: {
 697:     register int d = DEPTH(vcline);
 698:     register int rmdr = d * WCOLS - linend;
 699: 
 700:     if (cnt <= rmdr - IN)
 701:         return;
 702:     endim();
 703:     vnpins(1);
 704: }
 705: 
 706: vnpins(dosync)
 707:     int dosync;
 708: {
 709:     register int d = DEPTH(vcline);
 710:     register int e;
 711: 
 712:     e = LINE(vcline) + DEPTH(vcline);
 713:     if (e < LINE(vcline + 1)) {
 714:         vigoto(e, 0);
 715:         vclreol();
 716:         return;
 717:     }
 718:     DEPTH(vcline)++;
 719:     if (e < WECHO) {
 720:         e = vglitchup(vcline, d);
 721:         vigoto(e, 0); vclreol();
 722:         if (dosync) {
 723:             Outchar = vputchar;
 724:             vsync(e + 1);
 725:             Outchar = vinschar;
 726:         }
 727:     } else {
 728:         vup1();
 729:         vigoto(WBOT, 0);
 730:         vclreol();
 731:     }
 732:     vprepins();
 733: }
 734: 
 735: /*
 736:  * Do the shift of the next tabstop implied by
 737:  * insertion so it expands.
 738:  */
 739: vishft()
 740: {
 741:     int tshft = 0;
 742:     int j;
 743:     register int i;
 744:     register char *tp = vtube0;
 745:     register char *up;
 746:     short oldhold = hold;
 747: 
 748:     shft = value(TABSTOP);
 749:     hold |= HOLDPUPD;
 750:     if (!IM && !EI) {
 751:         /*
 752: 		 * Dumb terminals are easy, we just have
 753: 		 * to retype the text.
 754: 		 */
 755:         vigotoCL(tabend + shft);
 756:         up = tp + tabend;
 757:         for (i = tabend; i < linend; i++)
 758:             vputchar(*up++);
 759:     } else if (IN) {
 760:         /*
 761: 		 * CONCEPT-like terminals do most of the work for us,
 762: 		 * we don't have to muck with simulation of multi-line
 763: 		 * insert mode.  Some of the shifting may come for free
 764: 		 * also if the tabs don't have enough slack to take up
 765: 		 * all the inserted characters.
 766: 		 */
 767:         i = shft;
 768:         slakused = inssiz - doomed;
 769:         if (slakused > tabslack) {
 770:             i -= slakused - tabslack;
 771:             slakused -= tabslack;
 772:         }
 773:         if (i > 0 && tabend != linend) {
 774:             tshft = i;
 775:             vgotoCL(tabend);
 776:             goim();
 777:             do
 778:                 vputchar(' ' | QUOTE);
 779:             while (--i);
 780:         }
 781:     } else {
 782:         /*
 783: 		 * HP and Datamedia type terminals have to have multi-line
 784: 		 * insert faked.  Hack each segment after where we are
 785: 		 * (going backwards to where we are.)  We then can
 786: 		 * hack the segment where the end of the first following
 787: 		 * tab group is.
 788: 		 */
 789:         for (j = DEPTH(vcline) - 1; j > (tabend + shft) / WCOLS; j--) {
 790:             vgotoCL(j * WCOLS);
 791:             goim();
 792:             up = tp + j * WCOLS - shft;
 793:             i = shft;
 794:             do {
 795:                 if (*up)
 796:                     vputchar(*up++);
 797:                 else
 798:                     break;
 799:             } while (--i);
 800:         }
 801:         vigotoCL(tabstart);
 802:         i = shft - (inssiz - doomed);
 803:         if (i > 0) {
 804:             tabslack = inssiz - doomed;
 805:             vcsync();
 806:             goim();
 807:             do
 808:                 vputchar(' ');
 809:             while (--i);
 810:         }
 811:     }
 812:     /*
 813: 	 * Now do the data moving in the internal screen
 814: 	 * image which is common to all three cases.
 815: 	 */
 816:     tp += linend;
 817:     up = tp + shft;
 818:     i = linend - tabend;
 819:     if (i > 0)
 820:         do
 821:             *--up = *--tp;
 822:         while (--i);
 823:     if (IN && tshft) {
 824:         i = tshft;
 825:         do
 826:             *--up = ' ' | QUOTE;
 827:         while (--i);
 828:     }
 829:     hold = oldhold;
 830: }
 831: 
 832: /*
 833:  * Now do the insert of the characters (finally).
 834:  */
 835: viin(c)
 836:     char c;
 837: {
 838:     register char *tp, *up;
 839:     register int i, j;
 840:     register bool noim = 0;
 841:     int remdoom;
 842:     short oldhold = hold;
 843: 
 844:     hold |= HOLDPUPD;
 845:     if (tabsize && (IM && EI) && inssiz - doomed > tabslack)
 846:         /*
 847: 		 * There is a tab out there which will be affected
 848: 		 * by the insertion since there aren't enough doomed
 849: 		 * characters to take up all the insertion and we do
 850: 		 * have insert mode capability.
 851: 		 */
 852:         if (inscol + doomed == tabstart) {
 853:             /*
 854: 			 * The end of the doomed characters sits right at the
 855: 			 * start of the tabs, then we don't need to use insert
 856: 			 * mode; unless the tab has already been expanded
 857: 			 * in which case we MUST use insert mode.
 858: 			 */
 859:             slakused = 0;
 860:             noim = !shft;
 861:         } else {
 862:             /*
 863: 			 * The last really special case to handle is case
 864: 			 * where the tab is just sitting there and doesn't
 865: 			 * have enough slack to let the insertion take
 866: 			 * place without shifting the rest of the line
 867: 			 * over.  In this case we have to go out and
 868: 			 * delete some characters of the tab before we start
 869: 			 * or the answer will be wrong, as the rest of the
 870: 			 * line will have been shifted.  This code means
 871: 			 * that terminals with only insert chracter (no
 872: 			 * delete character) won't work correctly.
 873: 			 */
 874:             i = inssiz - doomed - tabslack - slakused;
 875:             i %= value(TABSTOP);
 876:             if (i > 0) {
 877:                 vgotoCL(tabstart);
 878:                 godm();
 879:                 for (i = inssiz - doomed - tabslack; i > 0; i--)
 880:                     vputp(DC, DEPTH(vcline));
 881:                 enddm();
 882:             }
 883:         }
 884: 
 885:     /*
 886: 	 * Now put out the characters of the actual insertion.
 887: 	 */
 888:     vigotoCL(inscol);
 889:     remdoom = doomed;
 890:     for (i = inssiz; i > 0; i--) {
 891:         if (remdoom > 0) {
 892:             remdoom--;
 893:             endim();
 894:         } else if (noim)
 895:             endim();
 896:         else if (IM && EI) {
 897:             vcsync();
 898:             goim();
 899:         }
 900:         vputchar(c);
 901:     }
 902: 
 903:     if (!IM || !EI) {
 904:         /*
 905: 		 * We are a dumb terminal; brute force update
 906: 		 * the rest of the line; this is very much an n^^2 process,
 907: 		 * and totally unreasonable at low speed.
 908: 		 *
 909: 		 * You asked for it, you get it.
 910: 		 */
 911:         tp = vtube0 + inscol + doomed;
 912:         for (i = inscol + doomed; i < tabstart; i++)
 913:             vputchar(*tp++);
 914:         hold = oldhold;
 915:         vigotoCL(tabstart + inssiz - doomed);
 916:         for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--)
 917:             vputchar(' ' | QUOTE);
 918:     } else {
 919:         if (!IN) {
 920:             /*
 921: 			 * On terminals without multi-line
 922: 			 * insert in the hardware, we must go fix the segments
 923: 			 * between the inserted text and the following
 924: 			 * tabs, if they are on different lines.
 925: 			 *
 926: 			 * Aaargh.
 927: 			 */
 928:             tp = vtube0;
 929:             for (j = (inscol + inssiz - 1) / WCOLS + 1;
 930:                 j <= (tabstart + inssiz - doomed - 1) / WCOLS; j++) {
 931:                 vgotoCL(j * WCOLS);
 932:                 i = inssiz - doomed;
 933:                 up = tp + j * WCOLS - i;
 934:                 goim();
 935:                 do
 936:                     vputchar(*up++);
 937:                 while (--i && *up);
 938:             }
 939:         } else {
 940:             /*
 941: 			 * On terminals with multi line inserts,
 942: 			 * life is simpler, just reflect eating of
 943: 			 * the slack.
 944: 			 */
 945:             tp = vtube0 + tabend;
 946:             for (i = tabsize - (inssiz - doomed); i >= 0; i--) {
 947:                 if ((*--tp & (QUOTE|TRIM)) == QUOTE) {
 948:                     --tabslack;
 949:                     if (tabslack >= slakused)
 950:                         continue;
 951:                 }
 952:                 *tp = ' ' | QUOTE;
 953:             }
 954:         }
 955:         /*
 956: 		 * Blank out the shifted positions to be tab positions.
 957: 		 */
 958:         if (shft) {
 959:             tp = vtube0 + tabend + shft;
 960:             for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--)
 961:                 if ((*--tp & QUOTE) == 0)
 962:                     *tp = ' ' | QUOTE;
 963:         }
 964:     }
 965: 
 966:     /*
 967: 	 * Finally, complete the screen image update
 968: 	 * to reflect the insertion.
 969: 	 */
 970:     hold = oldhold;
 971:     tp = vtube0 + tabstart; up = tp + inssiz - doomed;
 972:     for (i = tabstart; i > inscol + doomed; i--)
 973:         *--up = *--tp;
 974:     for (i = inssiz; i > 0; i--)
 975:         *--up = c;
 976:     doomed = 0;
 977: }
 978: 
 979: /*
 980:  * Go into ``delete mode''.  If the
 981:  * sequence which goes into delete mode
 982:  * is the same as that which goes into insert
 983:  * mode, then we are in delete mode already.
 984:  */
 985: godm()
 986: {
 987: 
 988:     if (insmode) {
 989:         if (eq(DM, IM))
 990:             return;
 991:         endim();
 992:     }
 993:     vputp(DM, 0);
 994: }
 995: 
 996: /*
 997:  * If we are coming out of delete mode, but
 998:  * delete and insert mode end with the same sequence,
 999:  * it wins to pretend we are now in insert mode,
1000:  * since we will likely want to be there again soon
1001:  * if we just moved over to delete space from part of
1002:  * a tab (above).
1003:  */
1004: enddm()
1005: {
1006: 
1007:     if (eq(DM, IM)) {
1008:         insmode = 1;
1009:         return;
1010:     }
1011:     vputp(ED, 0);
1012: }
1013: 
1014: /*
1015:  * In and out of insert mode.
1016:  * Note that the code here demands that there be
1017:  * a string for insert mode (the null string) even
1018:  * if the terminal does all insertions a single character
1019:  * at a time, since it branches based on whether IM is null.
1020:  */
1021: goim()
1022: {
1023: 
1024:     if (!insmode)
1025:         vputp(IM, 0);
1026:     insmode = 1;
1027: }
1028: 
1029: endim()
1030: {
1031: 
1032:     if (insmode) {
1033:         vputp(EI, 0);
1034:         insmode = 0;
1035:     }
1036: }
1037: 
1038: /*
1039:  * Put the character c on the screen at the current cursor position.
1040:  * This routine handles wraparound and scrolling and understands not
1041:  * to roll when splitw is set, i.e. we are working in the echo area.
1042:  * There is a bunch of hacking here dealing with the difference between
1043:  * QUOTE, QUOTE|' ', and ' ' for CONCEPT-100 like terminals, and also
1044:  * code to deal with terminals which overstrike, including CRT's where
1045:  * you can erase overstrikes with some work.  CRT's which do underlining
1046:  * implicitly which has to be erased (like CONCEPTS) are also handled.
1047:  */
1048: vputchar(c)
1049:     register int c;
1050: {
1051:     register char *tp;
1052:     register int d;
1053: 
1054:     c &= (QUOTE|TRIM);
1055: #ifdef TRACE
1056:     if (trace)
1057:         tracec(c);
1058: #endif
1059:     /* Fix problem of >79 chars on echo line. */
1060:     if (destcol >= WCOLS-1 && splitw && destline == WECHO)
1061:         pofix();
1062:     if (destcol >= WCOLS) {
1063:         destline += destcol / WCOLS;
1064:         destcol %= WCOLS;
1065:     }
1066:     if (destline > WBOT && (!splitw || destline > WECHO))
1067:         vrollup(destline);
1068:     tp = vtube[destline] + destcol;
1069:     switch (c) {
1070: 
1071:     case '\t':
1072:         vgotab();
1073:         return;
1074: 
1075:     case ' ':
1076:         /*
1077: 		 * We can get away without printing a space in a number
1078: 		 * of cases, but not always.  We get away with doing nothing
1079: 		 * if we are not in insert mode, and not on a CONCEPT-100
1080: 		 * like terminal, and either not in hardcopy open or in hardcopy
1081: 		 * open on a terminal with no overstriking, provided,
1082: 		 * in all cases, that nothing has ever been displayed
1083: 		 * at this position.  Ugh.
1084: 		 */
1085:         if (!insmode && !IN &&
1086: #ifdef OPENCODE
1087:                       (state != HARDOPEN || OS) &&
1088: #endif
1089:                                  (*tp&TRIM) == 0) {
1090:             *tp = ' ';
1091:             destcol++;
1092:             return;
1093:         }
1094:         goto def;
1095: 
1096:     case QUOTE:
1097:         if (insmode) {
1098:             /*
1099: 			 * When in insert mode, tabs have to expand
1100: 			 * to real, printed blanks.
1101: 			 */
1102:             c = ' ' | QUOTE;
1103:             goto def;
1104:         }
1105:         if (*tp == 0) {
1106:             /*
1107: 			 * A ``space''.
1108: 			 */
1109:             if ((hold & HOLDPUPD) == 0)
1110:                 *tp = QUOTE;
1111:             destcol++;
1112:             return;
1113:         }
1114:         /*
1115: 		 * A ``space'' ontop of a part of a tab.
1116: 		 */
1117:         if (*tp & QUOTE) {
1118:             destcol++;
1119:             return;
1120:         }
1121:         c = ' ' | QUOTE;
1122:         /* fall into ... */
1123: 
1124: def:
1125:     default:
1126:         d = *tp & TRIM;
1127:         /*
1128: 		 * Now get away with doing nothing if the characters
1129: 		 * are the same, provided we are not in insert mode
1130: 		 * and if we are in hardopen, that the terminal has overstrike.
1131: 		 */
1132:         if (d == (c & TRIM) && !insmode
1133: #ifdef OPENCODE
1134:                         && (state != HARDOPEN || OS)
1135: #endif
1136:                                     ) {
1137:             if ((hold & HOLDPUPD) == 0)
1138:                 *tp = c;
1139:             destcol++;
1140:             return;
1141:         }
1142:         /*
1143: 		 * Backwards looking optimization.
1144: 		 * The low level cursor motion routines will use
1145: 		 * a cursor motion right sequence to step 1 character
1146: 		 * right.  On, e.g., a DM3025A this is 2 characters
1147: 		 * and printing is noticeably slower at 300 baud.
1148: 		 * Since the low level routines are not allowed to use
1149: 		 * spaces for positioning, we discover the common
1150: 		 * case of a single space here and force a space
1151: 		 * to be printed.
1152: 		 */
1153:         if (destcol == outcol + 1 && tp[-1] == ' ' && outline == destline) {
1154:             vputc(' ');
1155:             outcol++;
1156:         }
1157: 
1158:         /*
1159: 		 * This is an inline expansion a call to vcsync() dictated
1160: 		 * by high frequency in a profile.
1161: 		 */
1162:         if (outcol != destcol || outline != destline)
1163:             vgoto(destline, destcol);
1164: 
1165:         /*
1166: 		 * Deal with terminals which have overstrike.
1167: 		 * We handle erasing general overstrikes, erasing
1168: 		 * underlines on terminals (such as CONCEPTS) which
1169: 		 * do underlining correctly automatically (e.g. on nroff
1170: 		 * output), and remembering, in hardcopy mode,
1171: 		 * that we have overstruct something.
1172: 		 */
1173:         if (!insmode && d && d != ' ' && d != (c & TRIM)) {
1174:             if (EO && (OS || UL && (c == '_' || d == '_'))) {
1175:                 vputc(' ');
1176:                 outcol++, destcol++;
1177:                 back1();
1178:             } else
1179:                 rubble = 1;
1180:         }
1181: 
1182:         /*
1183: 		 * Unless we are just bashing characters around for
1184: 		 * inner working of insert mode, update the display.
1185: 		 */
1186:         if ((hold & HOLDPUPD) == 0)
1187:             *tp = c;
1188: 
1189:         /*
1190: 		 * In insert mode, put out the IC sequence, padded
1191: 		 * based on the depth of the current line.
1192: 		 * A terminal which had no real insert mode, rather
1193: 		 * opening a character position at a time could do this.
1194: 		 * Actually should use depth to end of current line
1195: 		 * but this rarely matters.
1196: 		 */
1197:         if (insmode)
1198:             vputp(IC, DEPTH(vcline));
1199:         vputc(c & TRIM);
1200: 
1201:         /*
1202: 		 * In insert mode, IP is a post insert pad.
1203: 		 */
1204:         if (insmode)
1205:             vputp(IP, DEPTH(vcline));
1206:         destcol++, outcol++;
1207: 
1208:         /*
1209: 		 * CONCEPT braindamage in early models:  after a wraparound
1210: 		 * the next newline is eaten.  It's hungry so we just
1211: 		 * feed it now rather than worrying about it.
1212: 		 */
1213:         if (XN && outcol % WCOLS == 0)
1214:             vputc('\n');
1215:     }
1216: }
1217: 
1218: /*
1219:  * Delete display positions stcol through endcol.
1220:  * Amount of use of special terminal features here is limited.
1221:  */
1222: physdc(stcol, endcol)
1223:     int stcol, endcol;
1224: {
1225:     register char *tp, *up;
1226:     char *tpe;
1227:     register int i;
1228:     register int nc = endcol - stcol;
1229: 
1230: #ifdef IDEBUG
1231:     if (trace)
1232:         tfixnl(), fprintf(trace, "physdc(%d, %d)\n", stcol, endcol);
1233: #endif
1234:     if (!DC || nc <= 0)
1235:         return;
1236:     if (IN) {
1237:         /*
1238: 		 * CONCEPT-100 like terminal.
1239: 		 * If there are any ``spaces'' in the material to be
1240: 		 * deleted, then this is too hard, just retype.
1241: 		 */
1242:         vprepins();
1243:         up = vtube0 + stcol;
1244:         i = nc;
1245:         do
1246:             if ((*up++ & (QUOTE|TRIM)) == QUOTE)
1247:                 return;
1248:         while (--i);
1249:         i = 2 * nc;
1250:         do
1251:             if (*up == 0 || (*up++ & QUOTE) == QUOTE)
1252:                 return;
1253:         while (--i);
1254:         vgotoCL(stcol);
1255:     } else {
1256:         /*
1257: 		 * HP like delete mode.
1258: 		 * Compute how much text we are moving over by deleting.
1259: 		 * If it appears to be faster to just retype
1260: 		 * the line, do nothing and that will be done later.
1261: 		 * We are assuming 2 output characters per deleted
1262: 		 * characters and that clear to end of line is available.
1263: 		 */
1264:         i = stcol / WCOLS;
1265:         if (i != endcol / WCOLS)
1266:             return;
1267:         i += LINE(vcline);
1268:         stcol %= WCOLS;
1269:         endcol %= WCOLS;
1270:         up = vtube[i]; tp = up + endcol; tpe = up + WCOLS;
1271:         while (tp < tpe && *tp)
1272:             tp++;
1273:         if (tp - (up + stcol) < 2 * nc)
1274:             return;
1275:         vgoto(i, stcol);
1276:     }
1277: 
1278:     /*
1279: 	 * Go into delete mode and do the actual delete.
1280: 	 * Padding is on DC itself.
1281: 	 */
1282:     godm();
1283:     for (i = nc; i > 0; i--)
1284:         vputp(DC, DEPTH(vcline));
1285:     vputp(ED, 0);
1286: 
1287:     /*
1288: 	 * Straighten up.
1289: 	 * With CONCEPT like terminals, characters are pulled left
1290: 	 * from first following null.  HP like terminals shift rest of
1291: 	 * this (single physical) line rigidly.
1292: 	 */
1293:     if (IN) {
1294:         up = vtube0 + stcol;
1295:         tp = vtube0 + endcol;
1296:         while (i = *tp++) {
1297:             if ((i & (QUOTE|TRIM)) == QUOTE)
1298:                 break;
1299:             *up++ = i;
1300:         }
1301:         do
1302:             *up++ = i;
1303:         while (--nc);
1304:     } else {
1305:         copy(up + stcol, up + endcol, WCOLS - endcol);
1306:         vclrbyte(tpe - nc, nc);
1307:     }
1308: }
1309: 
1310: #ifdef TRACE
1311: tfixnl()
1312: {
1313: 
1314:     if (trubble || techoin)
1315:         fprintf(trace, "\n");
1316:     trubble = 0, techoin = 0;
1317: }
1318: 
1319: tvliny()
1320: {
1321:     register int i;
1322: 
1323:     if (!trace)
1324:         return;
1325:     tfixnl();
1326:     fprintf(trace, "vcnt = %d, vcline = %d, vliny = ", vcnt, vcline);
1327:     for (i = 0; i <= vcnt; i++) {
1328:         fprintf(trace, "%d", LINE(i));
1329:         if (FLAGS(i) & VDIRT)
1330:             fprintf(trace, "*");
1331:         if (DEPTH(i) != 1)
1332:             fprintf(trace, "<%d>", DEPTH(i));
1333:         if (i < vcnt)
1334:             fprintf(trace, " ");
1335:     }
1336:     fprintf(trace, "\n");
1337: }
1338: 
1339: tracec(c)
1340:     char c;
1341: {
1342: 
1343:     if (!techoin)
1344:         trubble = 1;
1345:     if (c == ESCAPE)
1346:         fprintf(trace, "$");
1347:     else if (c < ' ' || c == DELETE)
1348:         fprintf(trace, "^%c", ctlof(c));
1349:     else
1350:         fprintf(trace, "%c", c);
1351: }
1352: #endif
1353: 
1354: /*
1355:  * Put a character with possible tracing.
1356:  */
1357: vputch(c)
1358:     int c;
1359: {
1360: 
1361: #ifdef TRACE
1362:     if (trace)
1363:         tracec(c);
1364: #endif
1365:     vputc(c);
1366: }

Defined functions

enddm defined in line 1004; used 1 times
godm defined in line 985; used 2 times
goim defined in line 1021; used 6 times
physdc defined in line 1222; used 3 times
tracec defined in line 1339; used 3 times
tvliny defined in line 1319; used 7 times
vclrbyte defined in line 31; used 10 times
vclrlin defined in line 45; used 3 times
vcsync defined in line 245; used 7 times
vcursaft defined in line 197; used 1 times
vcursat defined in line 184; used 4 times
vcursbef defined in line 171; used 1 times
vgotab defined in line 424; used 2 times
vgotoCL defined in line 254; used 15 times
vigoto defined in line 233; used 12 times
vigotoCL defined in line 267; used 4 times
viin defined in line 835; used 1 times
vinschar defined in line 491; used 2 times
vishft defined in line 739; used 1 times
vmaktop defined in line 463; used 1 times
vneedpos defined in line 694; used 2 times
vnpins defined in line 706; used 2 times
vprepins defined in line 452; used 5 times
vputch defined in line 1357; used 1 times
vrigid defined in line 673; used 1 times
vsetcurs defined in line 218; used 3 times

Defined variables

inscol defined in line 442; used 13 times
inssiz defined in line 441; used 26 times
linend defined in line 436; used 12 times
shft defined in line 443; used 14 times
slakused defined in line 444; used 8 times
tabend defined in line 438; used 16 times
tabsize defined in line 439; used 7 times
tabslack defined in line 440; used 13 times
tabstart defined in line 437; used 12 times
Last modified: 1980-09-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2965
Valid CSS Valid XHTML 1.0 Strict