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

Defined functions

enddm defined in line 1000; used 1 times
godm defined in line 981; used 2 times
goim defined in line 1017; used 6 times
physdc defined in line 1214; used 3 times
tracec defined in line 1331; used 3 times
tvliny defined in line 1311; used 8 times
vclrbyte defined in line 32; used 10 times
vclrlin defined in line 46; used 3 times
vcsync defined in line 242; used 7 times
vcursaft defined in line 194; used 1 times
vcursat defined in line 181; used 4 times
vcursbef defined in line 168; used 1 times
vgotab defined in line 419; used 2 times
vgotoCL defined in line 251; used 15 times
vigoto defined in line 230; used 12 times
vigotoCL defined in line 264; used 4 times
viin defined in line 831; used 1 times
vinschar defined in line 486; used 1 times
vishft defined in line 735; used 1 times
vmaktop defined in line 458; used 1 times
vneedpos defined in line 689; used 2 times
vnpins defined in line 701; used 2 times
vprepins defined in line 447; used 5 times
vputch defined in line 1351; used 1 times
vrigid defined in line 668; used 1 times
vsetcurs defined in line 215; used 3 times

Defined variables

inscol defined in line 437; used 14 times
inssiz defined in line 436; used 26 times
linend defined in line 431; used 12 times
sccsid defined in line 2; never used
shft defined in line 438; used 14 times
slakused defined in line 439; used 8 times
tabend defined in line 433; used 16 times
tabsize defined in line 434; used 7 times
tabslack defined in line 435; used 13 times
tabstart defined in line 432; used 13 times
Last modified: 1981-07-10
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3095
Valid CSS Valid XHTML 1.0 Strict