| 1 | /* Copyright (c) 1980 Regents of the University of California */ |
| 2 | static char *sccsid = "@(#)ex_vput.c 5.1 %G%"; |
| 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 | char c; |
| 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 | Outchar = vputchar; |
| 719 | vsync(e + 1); |
| 720 | Outchar = vinschar; |
| 721 | } |
| 722 | } else { |
| 723 | vup1(); |
| 724 | vigoto(WBOT, 0); |
| 725 | vclreol(); |
| 726 | } |
| 727 | vprepins(); |
| 728 | } |
| 729 | |
| 730 | /* |
| 731 | * Do the shift of the next tabstop implied by |
| 732 | * insertion so it expands. |
| 733 | */ |
| 734 | vishft() |
| 735 | { |
| 736 | int tshft = 0; |
| 737 | int j; |
| 738 | register int i; |
| 739 | register char *tp = vtube0; |
| 740 | register char *up; |
| 741 | short oldhold = hold; |
| 742 | |
| 743 | shft = value(TABSTOP); |
| 744 | hold |= HOLDPUPD; |
| 745 | if (!IM && !EI) { |
| 746 | /* |
| 747 | * Dumb terminals are easy, we just have |
| 748 | * to retype the text. |
| 749 | */ |
| 750 | vigotoCL(tabend + shft); |
| 751 | up = tp + tabend; |
| 752 | for (i = tabend; i < linend; i++) |
| 753 | vputchar(*up++); |
| 754 | } else if (IN) { |
| 755 | /* |
| 756 | * CONCEPT-like terminals do most of the work for us, |
| 757 | * we don't have to muck with simulation of multi-line |
| 758 | * insert mode. Some of the shifting may come for free |
| 759 | * also if the tabs don't have enough slack to take up |
| 760 | * all the inserted characters. |
| 761 | */ |
| 762 | i = shft; |
| 763 | slakused = inssiz - doomed; |
| 764 | if (slakused > tabslack) { |
| 765 | i -= slakused - tabslack; |
| 766 | slakused -= tabslack; |
| 767 | } |
| 768 | if (i > 0 && tabend != linend) { |
| 769 | tshft = i; |
| 770 | vgotoCL(tabend); |
| 771 | goim(); |
| 772 | do |
| 773 | vputchar(' ' | QUOTE); |
| 774 | while (--i); |
| 775 | } |
| 776 | } else { |
| 777 | /* |
| 778 | * HP and Datamedia type terminals have to have multi-line |
| 779 | * insert faked. Hack each segment after where we are |
| 780 | * (going backwards to where we are.) We then can |
| 781 | * hack the segment where the end of the first following |
| 782 | * tab group is. |
| 783 | */ |
| 784 | for (j = DEPTH(vcline) - 1; j > (tabend + shft) / WCOLS; j--) { |
| 785 | vgotoCL(j * WCOLS); |
| 786 | goim(); |
| 787 | up = tp + j * WCOLS - shft; |
| 788 | i = shft; |
| 789 | do { |
| 790 | if (*up) |
| 791 | vputchar(*up++); |
| 792 | else |
| 793 | break; |
| 794 | } while (--i); |
| 795 | } |
| 796 | vigotoCL(tabstart); |
| 797 | i = shft - (inssiz - doomed); |
| 798 | if (i > 0) { |
| 799 | tabslack = inssiz - doomed; |
| 800 | vcsync(); |
| 801 | goim(); |
| 802 | do |
| 803 | vputchar(' '); |
| 804 | while (--i); |
| 805 | } |
| 806 | } |
| 807 | /* |
| 808 | * Now do the data moving in the internal screen |
| 809 | * image which is common to all three cases. |
| 810 | */ |
| 811 | tp += linend; |
| 812 | up = tp + shft; |
| 813 | i = linend - tabend; |
| 814 | if (i > 0) |
| 815 | do |
| 816 | *--up = *--tp; |
| 817 | while (--i); |
| 818 | if (IN && tshft) { |
| 819 | i = tshft; |
| 820 | do |
| 821 | *--up = ' ' | QUOTE; |
| 822 | while (--i); |
| 823 | } |
| 824 | hold = oldhold; |
| 825 | } |
| 826 | |
| 827 | /* |
| 828 | * Now do the insert of the characters (finally). |
| 829 | */ |
| 830 | viin(c) |
| 831 | char c; |
| 832 | { |
| 833 | register char *tp, *up; |
| 834 | register int i, j; |
| 835 | register bool noim = 0; |
| 836 | int remdoom; |
| 837 | short oldhold = hold; |
| 838 | |
| 839 | hold |= HOLDPUPD; |
| 840 | if (tabsize && (IM && EI) && inssiz - doomed > tabslack) |
| 841 | /* |
| 842 | * There is a tab out there which will be affected |
| 843 | * by the insertion since there aren't enough doomed |
| 844 | * characters to take up all the insertion and we do |
| 845 | * have insert mode capability. |
| 846 | */ |
| 847 | if (inscol + doomed == tabstart) { |
| 848 | /* |
| 849 | * The end of the doomed characters sits right at the |
| 850 | * start of the tabs, then we don't need to use insert |
| 851 | * mode; unless the tab has already been expanded |
| 852 | * in which case we MUST use insert mode. |
| 853 | */ |
| 854 | slakused = 0; |
| 855 | noim = !shft; |
| 856 | } else { |
| 857 | /* |
| 858 | * The last really special case to handle is case |
| 859 | * where the tab is just sitting there and doesn't |
| 860 | * have enough slack to let the insertion take |
| 861 | * place without shifting the rest of the line |
| 862 | * over. In this case we have to go out and |
| 863 | * delete some characters of the tab before we start |
| 864 | * or the answer will be wrong, as the rest of the |
| 865 | * line will have been shifted. This code means |
| 866 | * that terminals with only insert chracter (no |
| 867 | * delete character) won't work correctly. |
| 868 | */ |
| 869 | i = inssiz - doomed - tabslack - slakused; |
| 870 | i %= value(TABSTOP); |
| 871 | if (i > 0) { |
| 872 | vgotoCL(tabstart); |
| 873 | godm(); |
| 874 | for (i = inssiz - doomed - tabslack; i > 0; i--) |
| 875 | vputp(DC, DEPTH(vcline)); |
| 876 | enddm(); |
| 877 | } |
| 878 | } |
| 879 | |
| 880 | /* |
| 881 | * Now put out the characters of the actual insertion. |
| 882 | */ |
| 883 | vigotoCL(inscol); |
| 884 | remdoom = doomed; |
| 885 | for (i = inssiz; i > 0; i--) { |
| 886 | if (remdoom > 0) { |
| 887 | remdoom--; |
| 888 | endim(); |
| 889 | } else if (noim) |
| 890 | endim(); |
| 891 | else if (IM && EI) { |
| 892 | vcsync(); |
| 893 | goim(); |
| 894 | } |
| 895 | vputchar(c); |
| 896 | } |
| 897 | |
| 898 | if (!IM || !EI) { |
| 899 | /* |
| 900 | * We are a dumb terminal; brute force update |
| 901 | * the rest of the line; this is very much an n^^2 process, |
| 902 | * and totally unreasonable at low speed. |
| 903 | * |
| 904 | * You asked for it, you get it. |
| 905 | */ |
| 906 | tp = vtube0 + inscol + doomed; |
| 907 | for (i = inscol + doomed; i < tabstart; i++) |
| 908 | vputchar(*tp++); |
| 909 | hold = oldhold; |
| 910 | vigotoCL(tabstart + inssiz - doomed); |
| 911 | for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--) |
| 912 | vputchar(' ' | QUOTE); |
| 913 | } else { |
| 914 | if (!IN) { |
| 915 | /* |
| 916 | * On terminals without multi-line |
| 917 | * insert in the hardware, we must go fix the segments |
| 918 | * between the inserted text and the following |
| 919 | * tabs, if they are on different lines. |
| 920 | * |
| 921 | * Aaargh. |
| 922 | */ |
| 923 | tp = vtube0; |
| 924 | for (j = (inscol + inssiz - 1) / WCOLS + 1; |
| 925 | j <= (tabstart + inssiz - doomed - 1) / WCOLS; j++) { |
| 926 | vgotoCL(j * WCOLS); |
| 927 | i = inssiz - doomed; |
| 928 | up = tp + j * WCOLS - i; |
| 929 | goim(); |
| 930 | do |
| 931 | vputchar(*up++); |
| 932 | while (--i && *up); |
| 933 | } |
| 934 | } else { |
| 935 | /* |
| 936 | * On terminals with multi line inserts, |
| 937 | * life is simpler, just reflect eating of |
| 938 | * the slack. |
| 939 | */ |
| 940 | tp = vtube0 + tabend; |
| 941 | for (i = tabsize - (inssiz - doomed); i >= 0; i--) { |
| 942 | if ((*--tp & (QUOTE|TRIM)) == QUOTE) { |
| 943 | --tabslack; |
| 944 | if (tabslack >= slakused) |
| 945 | continue; |
| 946 | } |
| 947 | *tp = ' ' | QUOTE; |
| 948 | } |
| 949 | } |
| 950 | /* |
| 951 | * Blank out the shifted positions to be tab positions. |
| 952 | */ |
| 953 | if (shft) { |
| 954 | tp = vtube0 + tabend + shft; |
| 955 | for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--) |
| 956 | if ((*--tp & QUOTE) == 0) |
| 957 | *tp = ' ' | QUOTE; |
| 958 | } |
| 959 | } |
| 960 | |
| 961 | /* |
| 962 | * Finally, complete the screen image update |
| 963 | * to reflect the insertion. |
| 964 | */ |
| 965 | hold = oldhold; |
| 966 | tp = vtube0 + tabstart; up = tp + inssiz - doomed; |
| 967 | for (i = tabstart; i > inscol + doomed; i--) |
| 968 | *--up = *--tp; |
| 969 | for (i = inssiz; i > 0; i--) |
| 970 | *--up = c; |
| 971 | doomed = 0; |
| 972 | } |
| 973 | |
| 974 | /* |
| 975 | * Go into ``delete mode''. If the |
| 976 | * sequence which goes into delete mode |
| 977 | * is the same as that which goes into insert |
| 978 | * mode, then we are in delete mode already. |
| 979 | */ |
| 980 | godm() |
| 981 | { |
| 982 | |
| 983 | if (insmode) { |
| 984 | if (eq(DM, IM)) |
| 985 | return; |
| 986 | endim(); |
| 987 | } |
| 988 | vputp(DM, 0); |
| 989 | } |
| 990 | |
| 991 | /* |
| 992 | * If we are coming out of delete mode, but |
| 993 | * delete and insert mode end with the same sequence, |
| 994 | * it wins to pretend we are now in insert mode, |
| 995 | * since we will likely want to be there again soon |
| 996 | * if we just moved over to delete space from part of |
| 997 | * a tab (above). |
| 998 | */ |
| 999 | enddm() |
| 1000 | { |
| 1001 | |
| 1002 | if (eq(DM, IM)) { |
| 1003 | insmode = 1; |
| 1004 | return; |
| 1005 | } |
| 1006 | vputp(ED, 0); |
| 1007 | } |
| 1008 | |
| 1009 | /* |
| 1010 | * In and out of insert mode. |
| 1011 | * Note that the code here demands that there be |
| 1012 | * a string for insert mode (the null string) even |
| 1013 | * if the terminal does all insertions a single character |
| 1014 | * at a time, since it branches based on whether IM is null. |
| 1015 | */ |
| 1016 | goim() |
| 1017 | { |
| 1018 | |
| 1019 | if (!insmode) |
| 1020 | vputp(IM, 0); |
| 1021 | insmode = 1; |
| 1022 | } |
| 1023 | |
| 1024 | endim() |
| 1025 | { |
| 1026 | |
| 1027 | if (insmode) { |
| 1028 | vputp(EI, 0); |
| 1029 | insmode = 0; |
| 1030 | } |
| 1031 | } |
| 1032 | |
| 1033 | /* |
| 1034 | * Put the character c on the screen at the current cursor position. |
| 1035 | * This routine handles wraparound and scrolling and understands not |
| 1036 | * to roll when splitw is set, i.e. we are working in the echo area. |
| 1037 | * There is a bunch of hacking here dealing with the difference between |
| 1038 | * QUOTE, QUOTE|' ', and ' ' for CONCEPT-100 like terminals, and also |
| 1039 | * code to deal with terminals which overstrike, including CRT's where |
| 1040 | * you can erase overstrikes with some work. CRT's which do underlining |
| 1041 | * implicitly which has to be erased (like CONCEPTS) are also handled. |
| 1042 | */ |
| 1043 | vputchar(c) |
| 1044 | register int c; |
| 1045 | { |
| 1046 | register char *tp; |
| 1047 | register int d; |
| 1048 | |
| 1049 | c &= (QUOTE|TRIM); |
| 1050 | #ifdef TRACE |
| 1051 | if (trace) |
| 1052 | tracec(c); |
| 1053 | #endif |
| 1054 | /* Fix problem of >79 chars on echo line. */ |
| 1055 | if (destcol >= WCOLS-1 && splitw && destline == WECHO) |
| 1056 | pofix(); |
| 1057 | if (destcol >= WCOLS) { |
| 1058 | destline += destcol / WCOLS; |
| 1059 | destcol %= WCOLS; |
| 1060 | } |
| 1061 | if (destline > WBOT && (!splitw || destline > WECHO)) |
| 1062 | vrollup(destline); |
| 1063 | tp = vtube[destline] + destcol; |
| 1064 | switch (c) { |
| 1065 | |
| 1066 | case '\t': |
| 1067 | vgotab(); |
| 1068 | return; |
| 1069 | |
| 1070 | case ' ': |
| 1071 | /* |
| 1072 | * We can get away without printing a space in a number |
| 1073 | * of cases, but not always. We get away with doing nothing |
| 1074 | * if we are not in insert mode, and not on a CONCEPT-100 |
| 1075 | * like terminal, and either not in hardcopy open or in hardcopy |
| 1076 | * open on a terminal with no overstriking, provided, |
| 1077 | * in all cases, that nothing has ever been displayed |
| 1078 | * at this position. Ugh. |
| 1079 | */ |
| 1080 | if (!insmode && !IN && (state != HARDOPEN || OS) && (*tp&TRIM) == 0) { |
| 1081 | *tp = ' '; |
| 1082 | destcol++; |
| 1083 | return; |
| 1084 | } |
| 1085 | goto def; |
| 1086 | |
| 1087 | case QUOTE: |
| 1088 | if (insmode) { |
| 1089 | /* |
| 1090 | * When in insert mode, tabs have to expand |
| 1091 | * to real, printed blanks. |
| 1092 | */ |
| 1093 | c = ' ' | QUOTE; |
| 1094 | goto def; |
| 1095 | } |
| 1096 | if (*tp == 0) { |
| 1097 | /* |
| 1098 | * A ``space''. |
| 1099 | */ |
| 1100 | if ((hold & HOLDPUPD) == 0) |
| 1101 | *tp = QUOTE; |
| 1102 | destcol++; |
| 1103 | return; |
| 1104 | } |
| 1105 | /* |
| 1106 | * A ``space'' ontop of a part of a tab. |
| 1107 | */ |
| 1108 | if (*tp & QUOTE) { |
| 1109 | destcol++; |
| 1110 | return; |
| 1111 | } |
| 1112 | c = ' ' | QUOTE; |
| 1113 | /* fall into ... */ |
| 1114 | |
| 1115 | def: |
| 1116 | default: |
| 1117 | d = *tp & TRIM; |
| 1118 | /* |
| 1119 | * Now get away with doing nothing if the characters |
| 1120 | * are the same, provided we are not in insert mode |
| 1121 | * and if we are in hardopen, that the terminal has overstrike. |
| 1122 | */ |
| 1123 | if (d == (c & TRIM) && !insmode && (state != HARDOPEN || OS)) { |
| 1124 | if ((hold & HOLDPUPD) == 0) |
| 1125 | *tp = c; |
| 1126 | destcol++; |
| 1127 | return; |
| 1128 | } |
| 1129 | /* |
| 1130 | * Backwards looking optimization. |
| 1131 | * The low level cursor motion routines will use |
| 1132 | * a cursor motion right sequence to step 1 character |
| 1133 | * right. On, e.g., a DM3025A this is 2 characters |
| 1134 | * and printing is noticeably slower at 300 baud. |
| 1135 | * Since the low level routines are not allowed to use |
| 1136 | * spaces for positioning, we discover the common |
| 1137 | * case of a single space here and force a space |
| 1138 | * to be printed. |
| 1139 | */ |
| 1140 | if (destcol == outcol + 1 && tp[-1] == ' ' && outline == destline) { |
| 1141 | vputc(' '); |
| 1142 | outcol++; |
| 1143 | } |
| 1144 | |
| 1145 | /* |
| 1146 | * This is an inline expansion a call to vcsync() dictated |
| 1147 | * by high frequency in a profile. |
| 1148 | */ |
| 1149 | if (outcol != destcol || outline != destline) |
| 1150 | vgoto(destline, destcol); |
| 1151 | |
| 1152 | /* |
| 1153 | * Deal with terminals which have overstrike. |
| 1154 | * We handle erasing general overstrikes, erasing |
| 1155 | * underlines on terminals (such as CONCEPTS) which |
| 1156 | * do underlining correctly automatically (e.g. on nroff |
| 1157 | * output), and remembering, in hardcopy mode, |
| 1158 | * that we have overstruct something. |
| 1159 | */ |
| 1160 | if (!insmode && d && d != ' ' && d != (c & TRIM)) { |
| 1161 | if (EO && (OS || UL && (c == '_' || d == '_'))) { |
| 1162 | vputc(' '); |
| 1163 | outcol++, destcol++; |
| 1164 | back1(); |
| 1165 | } else |
| 1166 | rubble = 1; |
| 1167 | } |
| 1168 | |
| 1169 | /* |
| 1170 | * Unless we are just bashing characters around for |
| 1171 | * inner working of insert mode, update the display. |
| 1172 | */ |
| 1173 | if ((hold & HOLDPUPD) == 0) |
| 1174 | *tp = c; |
| 1175 | |
| 1176 | /* |
| 1177 | * In insert mode, put out the IC sequence, padded |
| 1178 | * based on the depth of the current line. |
| 1179 | * A terminal which had no real insert mode, rather |
| 1180 | * opening a character position at a time could do this. |
| 1181 | * Actually should use depth to end of current line |
| 1182 | * but this rarely matters. |
| 1183 | */ |
| 1184 | if (insmode) |
| 1185 | vputp(IC, DEPTH(vcline)); |
| 1186 | vputc(c & TRIM); |
| 1187 | |
| 1188 | /* |
| 1189 | * In insert mode, IP is a post insert pad. |
| 1190 | */ |
| 1191 | if (insmode) |
| 1192 | vputp(IP, DEPTH(vcline)); |
| 1193 | destcol++, outcol++; |
| 1194 | |
| 1195 | /* |
| 1196 | * CONCEPT braindamage in early models: after a wraparound |
| 1197 | * the next newline is eaten. It's hungry so we just |
| 1198 | * feed it now rather than worrying about it. |
| 1199 | */ |
| 1200 | if (XN && outcol % WCOLS == 0) |
| 1201 | vputc('\n'); |
| 1202 | } |
| 1203 | } |
| 1204 | |
| 1205 | /* |
| 1206 | * Delete display positions stcol through endcol. |
| 1207 | * Amount of use of special terminal features here is limited. |
| 1208 | */ |
| 1209 | physdc(stcol, endcol) |
| 1210 | int stcol, endcol; |
| 1211 | { |
| 1212 | register char *tp, *up; |
| 1213 | char *tpe; |
| 1214 | register int i; |
| 1215 | register int nc = endcol - stcol; |
| 1216 | |
| 1217 | #ifdef IDEBUG |
| 1218 | if (trace) |
| 1219 | tfixnl(), fprintf(trace, "physdc(%d, %d)\n", stcol, endcol); |
| 1220 | #endif |
| 1221 | if (!DC || nc <= 0) |
| 1222 | return; |
| 1223 | if (IN) { |
| 1224 | /* |
| 1225 | * CONCEPT-100 like terminal. |
| 1226 | * If there are any ``spaces'' in the material to be |
| 1227 | * deleted, then this is too hard, just retype. |
| 1228 | */ |
| 1229 | vprepins(); |
| 1230 | up = vtube0 + stcol; |
| 1231 | i = nc; |
| 1232 | do |
| 1233 | if ((*up++ & (QUOTE|TRIM)) == QUOTE) |
| 1234 | return; |
| 1235 | while (--i); |
| 1236 | i = 2 * nc; |
| 1237 | do |
| 1238 | if (*up == 0 || (*up++ & QUOTE) == QUOTE) |
| 1239 | return; |
| 1240 | while (--i); |
| 1241 | vgotoCL(stcol); |
| 1242 | } else { |
| 1243 | /* |
| 1244 | * HP like delete mode. |
| 1245 | * Compute how much text we are moving over by deleting. |
| 1246 | * If it appears to be faster to just retype |
| 1247 | * the line, do nothing and that will be done later. |
| 1248 | * We are assuming 2 output characters per deleted |
| 1249 | * characters and that clear to end of line is available. |
| 1250 | */ |
| 1251 | i = stcol / WCOLS; |
| 1252 | if (i != endcol / WCOLS) |
| 1253 | return; |
| 1254 | i += LINE(vcline); |
| 1255 | stcol %= WCOLS; |
| 1256 | endcol %= WCOLS; |
| 1257 | up = vtube[i]; tp = up + endcol; tpe = up + WCOLS; |
| 1258 | while (tp < tpe && *tp) |
| 1259 | tp++; |
| 1260 | if (tp - (up + stcol) < 2 * nc) |
| 1261 | return; |
| 1262 | vgoto(i, stcol); |
| 1263 | } |
| 1264 | |
| 1265 | /* |
| 1266 | * Go into delete mode and do the actual delete. |
| 1267 | * Padding is on DC itself. |
| 1268 | */ |
| 1269 | godm(); |
| 1270 | for (i = nc; i > 0; i--) |
| 1271 | vputp(DC, DEPTH(vcline)); |
| 1272 | vputp(ED, 0); |
| 1273 | |
| 1274 | /* |
| 1275 | * Straighten up. |
| 1276 | * With CONCEPT like terminals, characters are pulled left |
| 1277 | * from first following null. HP like terminals shift rest of |
| 1278 | * this (single physical) line rigidly. |
| 1279 | */ |
| 1280 | if (IN) { |
| 1281 | up = vtube0 + stcol; |
| 1282 | tp = vtube0 + endcol; |
| 1283 | while (i = *tp++) { |
| 1284 | if ((i & (QUOTE|TRIM)) == QUOTE) |
| 1285 | break; |
| 1286 | *up++ = i; |
| 1287 | } |
| 1288 | do |
| 1289 | *up++ = i; |
| 1290 | while (--nc); |
| 1291 | } else { |
| 1292 | copy(up + stcol, up + endcol, WCOLS - endcol); |
| 1293 | vclrbyte(tpe - nc, nc); |
| 1294 | } |
| 1295 | } |
| 1296 | |
| 1297 | #ifdef TRACE |
| 1298 | tfixnl() |
| 1299 | { |
| 1300 | |
| 1301 | if (trubble || techoin) |
| 1302 | fprintf(trace, "\n"); |
| 1303 | trubble = 0, techoin = 0; |
| 1304 | } |
| 1305 | |
| 1306 | tvliny() |
| 1307 | { |
| 1308 | register int i; |
| 1309 | |
| 1310 | if (!trace) |
| 1311 | return; |
| 1312 | tfixnl(); |
| 1313 | fprintf(trace, "vcnt = %d, vcline = %d, vliny = ", vcnt, vcline); |
| 1314 | for (i = 0; i <= vcnt; i++) { |
| 1315 | fprintf(trace, "%d", LINE(i)); |
| 1316 | if (FLAGS(i) & VDIRT) |
| 1317 | fprintf(trace, "*"); |
| 1318 | if (DEPTH(i) != 1) |
| 1319 | fprintf(trace, "<%d>", DEPTH(i)); |
| 1320 | if (i < vcnt) |
| 1321 | fprintf(trace, " "); |
| 1322 | } |
| 1323 | fprintf(trace, "\n"); |
| 1324 | } |
| 1325 | |
| 1326 | tracec(c) |
| 1327 | char c; |
| 1328 | { |
| 1329 | |
| 1330 | if (!techoin) |
| 1331 | trubble = 1; |
| 1332 | if (c == ESCAPE) |
| 1333 | fprintf(trace, "$"); |
| 1334 | else if (c < ' ' || c == DELETE) |
| 1335 | fprintf(trace, "^%c", ctlof(c)); |
| 1336 | else |
| 1337 | fprintf(trace, "%c", c); |
| 1338 | } |
| 1339 | #endif |
| 1340 | |
| 1341 | /* |
| 1342 | * Put a character with possible tracing. |
| 1343 | */ |
| 1344 | vputch(c) |
| 1345 | int c; |
| 1346 | { |
| 1347 | |
| 1348 | #ifdef TRACE |
| 1349 | if (trace) |
| 1350 | tracec(c); |
| 1351 | #endif |
| 1352 | vputc(c); |
| 1353 | } |