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