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