| 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) %G%"; |
| 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 | } |