|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.