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