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