xref: /freebsd/contrib/tcsh/ed.refresh.c (revision 7c1eefa6b6a2747a17b79470776cda01498de3a5)
1 /* $Header: /src/pub/tcsh/ed.refresh.c,v 3.39 2005/02/15 21:09:02 christos Exp $ */
2 /*
3  * ed.refresh.c: Lower level screen refreshing functions
4  */
5 /*-
6  * Copyright (c) 1980, 1991 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 #include "sh.h"
34 
35 RCSID("$Id: ed.refresh.c,v 3.39 2005/02/15 21:09:02 christos Exp $")
36 
37 #include "ed.h"
38 /* #define DEBUG_UPDATE */
39 /* #define DEBUG_REFRESH */
40 /* #define DEBUG_LITERAL */
41 
42 /* refresh.c -- refresh the current set of lines on the screen */
43 
44 Char   *litptr;
45 static int vcursor_h, vcursor_v;
46 static int rprompt_h, rprompt_v;
47 
48 static	int	MakeLiteral		__P((Char *, int, Char));
49 static	int	Draw 			__P((Char *, int));
50 static	void	Vdraw 			__P((Char, int));
51 static	void	RefreshPromptpart	__P((Char *));
52 static	void	update_line 		__P((Char *, Char *, int));
53 static	void	str_insert		__P((Char *, int, int, Char *, int));
54 static	void	str_delete		__P((Char *, int, int, int));
55 static	void	str_cp			__P((Char *, Char *, int));
56 #ifndef WINNT_NATIVE
57 static
58 #else
59 extern
60 #endif
61 	void    PutPlusOne      __P((Char, int));
62 static	void	cpy_pad_spaces		__P((Char *, Char *, int));
63 #if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL)
64 static	void	dprintf			__P((char *, ...));
65 #ifdef DEBUG_UPDATE
66 static	void	dprintstr		__P((char *, const Char *, const Char *));
67 
68 static void
69 dprintstr(str, f, t)
70 char *str;
71 const Char *f, *t;
72 {
73     dprintf("%s:\"", str);
74     while (f < t) {
75 	if (*f & ~ASCII)
76 	  dprintf("[%x]", *f++);
77 	else
78 	  dprintf("%c", *f++ & ASCII);
79     }
80     dprintf("\"\r\n");
81 }
82 #endif /* DEBUG_UPDATE */
83 
84 /* dprintf():
85  *	Print to $DEBUGTTY, so that we can test editing on one pty, and
86  *      print debugging stuff on another. Don't interrupt the shell while
87  *	debugging cause you'll mangle up the file descriptors!
88  */
89 static void
90 #ifdef PROTOTYPES
91 dprintf(char *fmt, ...)
92 #else
93 dprintf(va_list)
94     va_dcl
95 #endif /* __STDC__ */
96 {
97     static int fd = -1;
98     char *dtty;
99 
100     if ((dtty = getenv("DEBUGTTY"))) {
101 	int o;
102 	va_list va;
103 #ifdef PROTOTYPES
104 	va_start(va, fmt);
105 #else
106 	char *fmt;
107 	va_start(va);
108 	fmt = va_arg(va, char *);
109 #endif /* __STDC__ */
110 
111 	if (fd == -1)
112 	    fd = open(dtty, O_RDWR);
113 	o = SHOUT;
114 	flush();
115 	SHOUT = fd;
116 	xvprintf(fmt, va);
117 	va_end(va);
118 	flush();
119 	SHOUT = o;
120     }
121 }
122 #endif  /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */
123 
124 static int litlen = 0, litalloc = 0;
125 
126 static int MakeLiteral(str, len, addlit)
127     Char *str;
128     int len;
129     Char addlit;
130 {
131     int i, addlitlen = 0;
132     Char *addlitptr = 0;
133     if (addlit) {
134 	if ((addlit & LITERAL) != 0) {
135 	    addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
136 	    addlitlen = Strlen(addlitptr);
137 	} else {
138 	    addlitptr = &addlit;
139 	    addlitlen = 1;
140 	}
141 	for (i = 0; i < litlen; i += LIT_FACTOR)
142 	    if (!Strncmp(addlitptr, litptr + i, addlitlen) && !Strncmp(str, litptr + i + addlitlen, len) && litptr[i + addlitlen + len] == 0)
143 		return (i / LIT_FACTOR) | LITERAL;
144     } else {
145 	addlitlen = 0;
146 	for (i = 0; i < litlen; i += LIT_FACTOR)
147 	    if (!Strncmp(str, litptr + i, len) && litptr[i + len] == 0)
148 		return (i / LIT_FACTOR) | LITERAL;
149     }
150     if (litlen + addlitlen + len + 1 + (LIT_FACTOR - 1) > litalloc) {
151 	Char *newlitptr;
152 	int add = 256;
153 	while (len + addlitlen + 1 + (LIT_FACTOR - 1) > add)
154 	    add *= 2;
155 	if (litptr)
156 	    newlitptr = (Char *)xrealloc(litptr, (litalloc + add) * sizeof(Char));
157 	else
158 	    newlitptr = (Char *)xmalloc((litalloc + add) * sizeof(Char));
159 	if (!newlitptr)
160 	    return '?';
161 	litptr = newlitptr;
162 	litalloc += add;
163 	if (addlitptr && addlitptr != &addlit)
164 	    addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
165     }
166     i = litlen / LIT_FACTOR;
167     if (i >= LITERAL || i == CHAR_DBWIDTH)
168 	return '?';
169     if (addlitptr) {
170 	Strncpy(litptr + litlen, addlitptr, addlitlen);
171 	litlen += addlitlen;
172     }
173     Strncpy(litptr + litlen, str, len);
174     litlen += len;
175     do
176 	litptr[litlen++] = 0;
177     while (litlen % LIT_FACTOR);
178     return i | LITERAL;
179 }
180 
181 static int
182 Draw(cp, nocomb)	/* draw char at cp, expand tabs, ctl chars */
183     Char *cp;
184     int nocomb;
185 {
186     int l, w, i, lv, lh;
187     Char ch, attr;
188     NLSChar c;
189 
190     attr = *cp & ~CHAR;
191     l = NLSFrom(cp, NLSZEROT, &c);
192     w = NLSClassify(c, nocomb);
193     switch (w) {
194 	case NLSCLASS_NL:
195 	    Vdraw('\0', 0);		/* assure end of line	 */
196 	    vcursor_h = 0;		/* reset cursor pos	 */
197 	    vcursor_v++;
198 	    break;
199 	case NLSCLASS_TAB:
200 	    do {
201 		Vdraw(' ', 1);
202 	    } while ((vcursor_h & 07) != 0);
203 	    break;
204 	case NLSCLASS_CTRL:
205 	    Vdraw('^' | attr, 1);
206 	    if (c == CTL_ESC('\177')) {
207 		Vdraw('?' | attr, 1);
208 	    } else {
209 #ifdef IS_ASCII
210 		/* uncontrolify it; works only for iso8859-1 like sets */
211 		Vdraw(c | 0100 | attr, 1);
212 #else
213 		Vdraw(_toebcdic[_toascii[c]|0100] | attr, 1);
214 #endif
215 	    }
216 	    break;
217 	case NLSCLASS_ILLEGAL:
218 	    ch = *cp & CHAR;
219 	    Vdraw('\\' | attr, 1);
220 	    Vdraw((((ch >> 6) & 7) + '0') | attr, 1);
221 	    Vdraw((((ch >> 3) & 7) + '0') | attr, 1);
222 	    Vdraw(((ch & 7) + '0') | attr, 1);
223 	    break;
224 	case NLSCLASS_ILLEGAL2:
225 	case NLSCLASS_ILLEGAL3:
226 	case NLSCLASS_ILLEGAL4:
227 	    Vdraw('\\' | attr, 1);
228 	    Vdraw('U' | attr, 1);
229 	    Vdraw('+' | attr, 1);
230 	    for (i = 8 * NLSCLASS_ILLEGAL_SIZE(w) - 4; i >= 0; i -= 4)
231 		Vdraw("0123456789ABCDEF"[(c >> i) & 15] | attr, 1);
232 	    break;
233 	case 0:
234 	    lv = vcursor_v;
235 	    lh = vcursor_h;
236 	    for (;;) {
237 		lh--;
238 		if (lh < 0) {
239 		    lv--;
240 		    if (lv < 0)
241 			break;
242 		    lh = Strlen(Vdisplay[lv]) - 1;
243 		}
244 		if (Vdisplay[lv][lh] != CHAR_DBWIDTH)
245 		    break;
246 	    }
247 	    if (lv < 0) {
248 		int l2 = l;
249 		for (; l2-- > 0; cp++) {
250 		    ch = *cp & CHAR;
251 		    Vdraw('\\' | attr, 1);
252 		    Vdraw((((ch >> 6) & 7) + '0') | attr, 1);
253 		    Vdraw((((ch >> 3) & 7) + '0') | attr, 1);
254 		    Vdraw(((ch & 7) + '0') | attr, 1);
255 		}
256 		return l;
257 	    }
258 	    Vdisplay[lv][lh] = MakeLiteral(cp, l, Vdisplay[lv][lh]);
259 	    break;
260 	default:
261 	    if (l > 1)
262 		Vdraw(MakeLiteral(cp, l, 0), w);
263 	    else
264 		Vdraw(*cp, w);
265 	    break;
266     }
267     return l;
268 }
269 
270 static void
271 Vdraw(c, width)			/* draw char c onto V lines */
272     Char c;
273     int width;
274 {
275 #ifdef DEBUG_REFRESH
276 # ifdef SHORT_STRINGS
277     dprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c, (int)(c & ASCII), width);
278 # else
279     dprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c, (int)c, width);
280 # endif /* SHORT_STRNGS */
281 #endif  /* DEBUG_REFRESH */
282 
283     /* Hopefully this is what all the terminals do with multi-column characters
284        that "span line breaks". */
285     while (vcursor_h + width > TermH)
286 	Vdraw(' ', 1);
287     Vdisplay[vcursor_v][vcursor_h] = (Char) c;
288     if (width)
289 	vcursor_h++;		/* advance to next place */
290     while (--width > 0)
291 	Vdisplay[vcursor_v][vcursor_h++] = CHAR_DBWIDTH;
292     if (vcursor_h >= TermH) {
293 	Vdisplay[vcursor_v][TermH] = '\0';	/* assure end of line */
294 	vcursor_h = 0;		/* reset it. */
295 	vcursor_v++;
296 #ifdef DEBUG_REFRESH
297 	if (vcursor_v >= TermV) {	/* should NEVER happen. */
298 	    dprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n",
299 		    vcursor_v, TermV);
300 	    abort();
301 	}
302 #endif /* DEBUG_REFRESH */
303     }
304 }
305 
306 /*
307  *  RefreshPromptpart()
308  *	draws a prompt element, expanding literals (we know it's ASCIZ)
309  */
310 static void
311 RefreshPromptpart(buf)
312     Char *buf;
313 {
314     Char *cp;
315     NLSChar c;
316     int l, w;
317 
318     for (cp = buf; *cp; ) {
319 	if (*cp & LITERAL) {
320 	    Char *litstart = cp;
321 	    while (*cp & LITERAL)
322 		cp++;
323 	    if (*cp) {
324 		l = NLSFrom(cp, NLSZEROT, &c);
325 		w = NLSWidth(c);
326 		Vdraw(MakeLiteral(litstart, cp + l - litstart, 0), w);
327 		cp += l;
328 	    }
329 	    else {
330 		/*
331 		 * XXX: This is a bug, we lose the last literal, if it is not
332 		 * followed by a normal character, but it is too hard to fix
333 		 */
334 		break;
335 	    }
336 	}
337 	else
338 	    cp += Draw(cp, cp == buf);
339     }
340 }
341 
342 /*
343  *  Refresh()
344  *	draws the new virtual screen image from the current input
345  *  	line, then goes line-by-line changing the real image to the new
346  *	virtual image. The routine to re-draw a line can be replaced
347  *	easily in hopes of a smarter one being placed there.
348  */
349 #ifndef WINNT_NATIVE
350 static
351 #endif
352 int OldvcV = 0;
353 
354 void
355 Refresh()
356 {
357     int cur_line;
358     Char *cp;
359     int     cur_h, cur_v = 0, new_vcv;
360     int     rhdiff;
361     Char    oldgetting;
362 
363 #ifdef DEBUG_REFRESH
364     dprintf("PromptBuf = :%s:\r\n", short2str(PromptBuf));
365     dprintf("InputBuf = :%s:\r\n", short2str(InputBuf));
366 #endif /* DEBUG_REFRESH */
367     oldgetting = GettingInput;
368     GettingInput = 0;		/* avoid re-entrance via SIGWINCH */
369 
370     /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */
371     vcursor_h = 0;
372     vcursor_v = 0;
373     RefreshPromptpart(RPromptBuf);
374     rprompt_h = vcursor_h;
375     rprompt_v = vcursor_v;
376 
377     /* reset the Vdraw cursor, draw prompt */
378     vcursor_h = 0;
379     vcursor_v = 0;
380     RefreshPromptpart(PromptBuf);
381     cur_h = -1;			/* set flag in case I'm not set */
382 
383     /* draw the current input buffer */
384     for (cp = InputBuf; (cp < LastChar); ) {
385 	if (cp >= Cursor && cur_h == -1) {
386 	    cur_h = vcursor_h;	/* save for later */
387 	    cur_v = vcursor_v;
388 	    Cursor = cp;
389 	}
390 	cp += Draw(cp, cp == InputBuf);
391     }
392 
393     if (cur_h == -1) {		/* if I haven't been set yet, I'm at the end */
394 	cur_h = vcursor_h;
395 	cur_v = vcursor_v;
396     }
397 
398     rhdiff = TermH - vcursor_h - rprompt_h;
399     if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) {
400 			/*
401 			 * have a right-hand side prompt that will fit on
402 			 * the end of the first line with at least one
403 			 * character gap to the input buffer.
404 			 */
405 	while (--rhdiff > 0)		/* pad out with spaces */
406 	    Vdraw(' ', 1);
407 	RefreshPromptpart(RPromptBuf);
408     }
409     else {
410 	rprompt_h = 0;			/* flag "not using rprompt" */
411 	rprompt_v = 0;
412     }
413 
414     new_vcv = vcursor_v;	/* must be done BEFORE the NUL is written */
415     Vdraw('\0', 1);		/* put NUL on end */
416 
417 #if defined (DEBUG_REFRESH)
418     dprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n",
419 	    TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0]));
420 #endif /* DEBUG_REFRESH */
421 
422 #ifdef DEBUG_UPDATE
423     dprintf("updating %d lines.\r\n", new_vcv);
424 #endif  /* DEBUG_UPDATE */
425     for (cur_line = 0; cur_line <= new_vcv; cur_line++) {
426 	/* NOTE THAT update_line MAY CHANGE Display[cur_line] */
427 	update_line(Display[cur_line], Vdisplay[cur_line], cur_line);
428 #ifdef WINNT_NATIVE
429 	flush();
430 #endif /* WINNT_NATIVE */
431 
432 	/*
433 	 * Copy the new line to be the current one, and pad out with spaces
434 	 * to the full width of the terminal so that if we try moving the
435 	 * cursor by writing the character that is at the end of the
436 	 * screen line, it won't be a NUL or some old leftover stuff.
437 	 */
438 	cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH);
439     }
440 #ifdef DEBUG_REFRESH
441     dprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n",
442 	    vcursor_v, OldvcV, cur_line);
443 #endif /* DEBUG_REFRESH */
444     if (OldvcV > new_vcv) {
445 	for (; cur_line <= OldvcV; cur_line++) {
446 	    update_line(Display[cur_line], STRNULL, cur_line);
447 	    *Display[cur_line] = '\0';
448 	}
449     }
450     OldvcV = new_vcv;		/* set for next time */
451 #ifdef DEBUG_REFRESH
452     dprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n",
453 	    CursorH, CursorV, cur_h, cur_v);
454 #endif /* DEBUG_REFRESH */
455 #ifdef WINNT_NATIVE
456     flush();
457 #endif /* WINNT_NATIVE */
458     MoveToLine(cur_v);		/* go to where the cursor is */
459     MoveToChar(cur_h);
460     SetAttributes(0);		/* Clear all attributes */
461     flush();			/* send the output... */
462     GettingInput = oldgetting;	/* reset to old value */
463 }
464 
465 #ifdef notdef
466 GotoBottom()
467 {				/* used to go to last used screen line */
468     MoveToLine(OldvcV);
469 }
470 
471 #endif
472 
473 void
474 PastBottom()
475 {				/* used to go to last used screen line */
476     MoveToLine(OldvcV);
477     (void) putraw('\r');
478     (void) putraw('\n');
479     ClearDisp();
480     flush();
481 }
482 
483 
484 /* insert num characters of s into d (in front of the character) at dat,
485    maximum length of d is dlen */
486 static void
487 str_insert(d, dat, dlen, s, num)
488     Char *d;
489     int dat, dlen;
490     Char *s;
491     int num;
492 {
493     Char *a, *b;
494 
495     if (num <= 0)
496 	return;
497     if (num > dlen - dat)
498 	num = dlen - dat;
499 
500 #ifdef DEBUG_REFRESH
501     dprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n",
502 	    num, dat, dlen, short2str(d));
503     dprintf("s == \"%s\"n", short2str(s));
504 #endif /* DEBUG_REFRESH */
505 
506     /* open up the space for num chars */
507     if (num > 0) {
508 	b = d + dlen - 1;
509 	a = b - num;
510 	while (a >= &d[dat])
511 	    *b-- = *a--;
512 	d[dlen] = '\0';		/* just in case */
513     }
514 #ifdef DEBUG_REFRESH
515     dprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n",
516 	    num, dat, dlen, short2str(d));
517     dprintf("s == \"%s\"n", short2str(s));
518 #endif /* DEBUG_REFRESH */
519 
520     /* copy the characters */
521     for (a = d + dat; (a < d + dlen) && (num > 0); num--)
522 	*a++ = *s++;
523 
524 #ifdef DEBUG_REFRESH
525     dprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n",
526 	    num, dat, dlen, d, short2str(s));
527     dprintf("s == \"%s\"n", short2str(s));
528 #endif /* DEBUG_REFRESH */
529 }
530 
531 /* delete num characters d at dat, maximum length of d is dlen */
532 static void
533 str_delete(d, dat, dlen, num)
534     Char *d;
535     int dat, dlen, num;
536 {
537     Char *a, *b;
538 
539     if (num <= 0)
540 	return;
541     if (dat + num >= dlen) {
542 	d[dat] = '\0';
543 	return;
544     }
545 
546 #ifdef DEBUG_REFRESH
547     dprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n",
548 	    num, dat, dlen, short2str(d));
549 #endif /* DEBUG_REFRESH */
550 
551     /* open up the space for num chars */
552     if (num > 0) {
553 	b = d + dat;
554 	a = b + num;
555 	while (a < &d[dlen])
556 	    *b++ = *a++;
557 	d[dlen] = '\0';		/* just in case */
558     }
559 #ifdef DEBUG_REFRESH
560     dprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n",
561 	    num, dat, dlen, short2str(d));
562 #endif /* DEBUG_REFRESH */
563 }
564 
565 static void
566 str_cp(a, b, n)
567     Char *a, *b;
568     int n;
569 {
570     while (n-- && *b)
571 	*a++ = *b++;
572 }
573 
574 
575 /* ****************************************************************
576     update_line() is based on finding the middle difference of each line
577     on the screen; vis:
578 
579 			     /old first difference
580 	/beginning of line   |              /old last same       /old EOL
581 	v		     v              v                    v
582 old:	eddie> Oh, my little gruntle-buggy is to me, as lurgid as
583 new:	eddie> Oh, my little buggy says to me, as lurgid as
584 	^		     ^        ^			   ^
585 	\beginning of line   |        \new last same	   \new end of line
586 			     \new first difference
587 
588     all are character pointers for the sake of speed.  Special cases for
589     no differences, as well as for end of line additions must be handled.
590 **************************************************************** */
591 
592 /* Minimum at which doing an insert it "worth it".  This should be about
593  * half the "cost" of going into insert mode, inserting a character, and
594  * going back out.  This should really be calculated from the termcap
595  * data...  For the moment, a good number for ANSI terminals.
596  */
597 #define MIN_END_KEEP	4
598 
599 static void			/* could be changed to make it smarter */
600 update_line(old, new, cur_line)
601     Char *old, *new;
602     int     cur_line;
603 {
604     Char *o, *n, *p, c;
605     Char  *ofd, *ols, *oe, *nfd, *nls, *ne;
606     Char  *osb, *ose, *nsb, *nse;
607     int     fx, sx;
608 
609     /*
610      * find first diff (won't be CHAR_DBWIDTH in either line)
611      */
612     for (o = old, n = new; *o && (*o == *n); o++, n++)
613 	continue;
614     ofd = o;
615     nfd = n;
616 
617     /*
618      * Find the end of both old and new
619      */
620     while (*o)
621 	o++;
622     /*
623      * Remove any trailing blanks off of the end, being careful not to
624      * back up past the beginning.
625      */
626     while (ofd < o) {
627 	if (o[-1] != ' ')
628 	    break;
629 	o--;
630     }
631     oe = o;
632     *oe = (Char) 0;
633 
634     while (*n)
635 	n++;
636 
637     /* remove blanks from end of new */
638     while (nfd < n) {
639 	if (n[-1] != ' ')
640 	    break;
641 	n--;
642     }
643     ne = n;
644     *ne = (Char) 0;
645 
646     /*
647      * if no diff, continue to next line of redraw
648      */
649     if (*ofd == '\0' && *nfd == '\0') {
650 #ifdef DEBUG_UPDATE
651 	dprintf("no difference.\r\n");
652 #endif /* DEBUG_UPDATE */
653 	return;
654     }
655 
656     /*
657      * find last same pointer
658      */
659     while ((o > ofd) && (n > nfd) && (*--o == *--n))
660 	continue;
661     if (*o != *n) {
662 	o++;
663 	n++;
664     }
665     while (*o == CHAR_DBWIDTH) {
666 	o++;
667 	n++;
668     }
669     ols = o;
670     nls = n;
671 
672     /*
673      * find same begining and same end
674      */
675     osb = ols;
676     nsb = nls;
677     ose = ols;
678     nse = nls;
679 
680     /*
681      * case 1: insert: scan from nfd to nls looking for *ofd
682      */
683     if (*ofd) {
684 	for (c = *ofd, n = nfd; n < nls; n++) {
685 	    if (c == *n) {
686 		for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++)
687 		    continue;
688 		/*
689 		 * if the new match is longer and it's worth keeping, then we
690 		 * take it
691 		 */
692 		if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) {
693 		    nsb = n;
694 		    nse = p;
695 		    osb = ofd;
696 		    ose = o;
697 		}
698 	    }
699 	}
700     }
701 
702     /*
703      * case 2: delete: scan from ofd to ols looking for *nfd
704      */
705     if (*nfd) {
706 	for (c = *nfd, o = ofd; o < ols; o++) {
707 	    if (c == *o) {
708 		for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++)
709 		    continue;
710 		/*
711 		 * if the new match is longer and it's worth keeping, then we
712 		 * take it
713 		 */
714 		if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) {
715 		    nsb = nfd;
716 		    nse = n;
717 		    osb = o;
718 		    ose = p;
719 		}
720 	    }
721 	}
722     }
723 #ifdef notdef
724     /*
725      * If `last same' is before `same end' re-adjust
726      */
727     if (ols < ose)
728 	ols = ose;
729     if (nls < nse)
730 	nls = nse;
731 #endif
732 
733     /*
734      * Pragmatics I: If old trailing whitespace or not enough characters to
735      * save to be worth it, then don't save the last same info.
736      */
737     if ((oe - ols) < MIN_END_KEEP) {
738 	ols = oe;
739 	nls = ne;
740     }
741 
742     /*
743      * Pragmatics II: if the terminal isn't smart enough, make the data dumber
744      * so the smart update doesn't try anything fancy
745      */
746 
747     /*
748      * fx is the number of characters we need to insert/delete: in the
749      * beginning to bring the two same begins together
750      */
751     fx = (int) ((nsb - nfd) - (osb - ofd));
752     /*
753      * sx is the number of characters we need to insert/delete: in the end to
754      * bring the two same last parts together
755      */
756     sx = (int) ((nls - nse) - (ols - ose));
757 
758     if (!T_CanIns) {
759 	if (fx > 0) {
760 	    osb = ols;
761 	    ose = ols;
762 	    nsb = nls;
763 	    nse = nls;
764 	}
765 	if (sx > 0) {
766 	    ols = oe;
767 	    nls = ne;
768 	}
769 	if ((ols - ofd) < (nls - nfd)) {
770 	    ols = oe;
771 	    nls = ne;
772 	}
773     }
774     if (!T_CanDel) {
775 	if (fx < 0) {
776 	    osb = ols;
777 	    ose = ols;
778 	    nsb = nls;
779 	    nse = nls;
780 	}
781 	if (sx < 0) {
782 	    ols = oe;
783 	    nls = ne;
784 	}
785 	if ((ols - ofd) > (nls - nfd)) {
786 	    ols = oe;
787 	    nls = ne;
788 	}
789     }
790 
791     /*
792      * Pragmatics III: make sure the middle shifted pointers are correct if
793      * they don't point to anything (we may have moved ols or nls).
794      */
795     /* if the change isn't worth it, don't bother */
796     /* was: if (osb == ose) */
797     if ((ose - osb) < MIN_END_KEEP) {
798 	osb = ols;
799 	ose = ols;
800 	nsb = nls;
801 	nse = nls;
802     }
803 
804     /*
805      * Now that we are done with pragmatics we recompute fx, sx
806      */
807     fx = (int) ((nsb - nfd) - (osb - ofd));
808     sx = (int) ((nls - nse) - (ols - ose));
809 
810 #ifdef DEBUG_UPDATE
811     dprintf("\n");
812     dprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n",
813 	    ofd - old, osb - old, ose - old, ols - old, oe - old);
814     dprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
815 	    nfd - new, nsb - new, nse - new, nls - new, ne - new);
816     dprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n");
817     dprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n");
818     dprintstr("old- oe", old, oe);
819     dprintstr("new- ne", new, ne);
820     dprintstr("old-ofd", old, ofd);
821     dprintstr("new-nfd", new, nfd);
822     dprintstr("ofd-osb", ofd, osb);
823     dprintstr("nfd-nsb", nfd, nsb);
824     dprintstr("osb-ose", osb, ose);
825     dprintstr("nsb-nse", nsb, nse);
826     dprintstr("ose-ols", ose, ols);
827     dprintstr("nse-nls", nse, nls);
828     dprintstr("ols- oe", ols, oe);
829     dprintstr("nls- ne", nls, ne);
830 #endif /* DEBUG_UPDATE */
831 
832     /*
833      * CursorV to this line cur_line MUST be in this routine so that if we
834      * don't have to change the line, we don't move to it. CursorH to first
835      * diff char
836      */
837     MoveToLine(cur_line);
838 
839     /*
840      * at this point we have something like this:
841      *
842      * /old                  /ofd    /osb               /ose    /ols     /oe
843      * v.....................v       v..................v       v........v
844      * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
845      * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
846      * ^.....................^     ^..................^       ^........^
847      * \new                  \nfd  \nsb               \nse     \nls    \ne
848      *
849      * fx is the difference in length between the the chars between nfd and
850      * nsb, and the chars between ofd and osb, and is thus the number of
851      * characters to delete if < 0 (new is shorter than old, as above),
852      * or insert (new is longer than short).
853      *
854      * sx is the same for the second differences.
855      */
856 
857     /*
858      * if we have a net insert on the first difference, AND inserting the net
859      * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character
860      * (which is ne if nls != ne, otherwise is nse) off the edge of the screen
861      * (TermH - 1) else we do the deletes first so that we keep everything we
862      * need to.
863      */
864 
865     /*
866      * if the last same is the same like the end, there is no last same part,
867      * otherwise we want to keep the last same part set p to the last useful
868      * old character
869      */
870     p = (ols != oe) ? oe : ose;
871 
872     /*
873      * if (There is a diffence in the beginning) && (we need to insert
874      * characters) && (the number of characters to insert is less than the term
875      * width) We need to do an insert! else if (we need to delete characters)
876      * We need to delete characters! else No insert or delete
877      */
878     if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) {
879 #ifdef DEBUG_UPDATE
880 	dprintf("first diff insert at %d...\r\n", nfd - new);
881 #endif  /* DEBUG_UPDATE */
882 	/*
883 	 * Move to the first char to insert, where the first diff is.
884 	 */
885 	MoveToChar(nfd - new);
886 	/*
887 	 * Check if we have stuff to keep at end
888 	 */
889 	if (nsb != ne) {
890 #ifdef DEBUG_UPDATE
891 	    dprintf("with stuff to keep at end\r\n");
892 #endif  /* DEBUG_UPDATE */
893 	    /*
894 	     * insert fx chars of new starting at nfd
895 	     */
896 	    if (fx > 0) {
897 #ifdef DEBUG_UPDATE
898 		if (!T_CanIns)
899 		    dprintf("   ERROR: cannot insert in early first diff\n");
900 #endif  /* DEBUG_UPDATE */
901 		Insert_write(nfd, fx);
902 		str_insert(old, (int) (ofd - old), TermH, nfd, fx);
903 	    }
904 	    /*
905 	     * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
906 	     */
907 	    so_write(nfd + fx, (nsb - nfd) - fx);
908 	    str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
909 	}
910 	else {
911 #ifdef DEBUG_UPDATE
912 	    dprintf("without anything to save\r\n");
913 #endif  /* DEBUG_UPDATE */
914 	    so_write(nfd, (nsb - nfd));
915 	    str_cp(ofd, nfd, (int) (nsb - nfd));
916 	    /*
917 	     * Done
918 	     */
919 	    return;
920 	}
921     }
922     else if (fx < 0) {
923 #ifdef DEBUG_UPDATE
924 	dprintf("first diff delete at %d...\r\n", ofd - old);
925 #endif  /* DEBUG_UPDATE */
926 	/*
927 	 * move to the first char to delete where the first diff is
928 	 */
929 	MoveToChar(ofd - old);
930 	/*
931 	 * Check if we have stuff to save
932 	 */
933 	if (osb != oe) {
934 #ifdef DEBUG_UPDATE
935 	    dprintf("with stuff to save at end\r\n");
936 #endif  /* DEBUG_UPDATE */
937 	    /*
938 	     * fx is less than zero *always* here but we check for code
939 	     * symmetry
940 	     */
941 	    if (fx < 0) {
942 #ifdef DEBUG_UPDATE
943 		if (!T_CanDel)
944 		    dprintf("   ERROR: cannot delete in first diff\n");
945 #endif /* DEBUG_UPDATE */
946 		DeleteChars(-fx);
947 		str_delete(old, (int) (ofd - old), TermH, -fx);
948 	    }
949 	    /*
950 	     * write (nsb-nfd) chars of new starting at nfd
951 	     */
952 	    so_write(nfd, (nsb - nfd));
953 	    str_cp(ofd, nfd, (int) (nsb - nfd));
954 
955 	}
956 	else {
957 #ifdef DEBUG_UPDATE
958 	    dprintf("but with nothing left to save\r\n");
959 #endif  /* DEBUG_UPDATE */
960 	    /*
961 	     * write (nsb-nfd) chars of new starting at nfd
962 	     */
963 	    so_write(nfd, (nsb - nfd));
964 #ifdef DEBUG_REFRESH
965 	    dprintf("cleareol %d\n", (oe - old) - (ne - new));
966 #endif  /* DEBUG_UPDATE */
967 #ifndef WINNT_NATIVE
968 	    ClearEOL((oe - old) - (ne - new));
969 #else
970 	    /*
971 	     * The calculation above does not work too well on NT
972 	     */
973 	    ClearEOL(TermH - CursorH);
974 #endif /*WINNT_NATIVE*/
975 	    /*
976 	     * Done
977 	     */
978 	    return;
979 	}
980     }
981     else
982 	fx = 0;
983 
984     if (sx < 0) {
985 #ifdef DEBUG_UPDATE
986 	dprintf("second diff delete at %d...\r\n", (ose - old) + fx);
987 #endif  /* DEBUG_UPDATE */
988 	/*
989 	 * Check if we have stuff to delete
990 	 */
991 	/*
992 	 * fx is the number of characters inserted (+) or deleted (-)
993 	 */
994 
995 	MoveToChar((ose - old) + fx);
996 	/*
997 	 * Check if we have stuff to save
998 	 */
999 	if (ols != oe) {
1000 #ifdef DEBUG_UPDATE
1001 	    dprintf("with stuff to save at end\r\n");
1002 #endif  /* DEBUG_UPDATE */
1003 	    /*
1004 	     * Again a duplicate test.
1005 	     */
1006 	    if (sx < 0) {
1007 #ifdef DEBUG_UPDATE
1008 		if (!T_CanDel)
1009 		    dprintf("   ERROR: cannot delete in second diff\n");
1010 #endif  /* DEBUG_UPDATE */
1011 		DeleteChars(-sx);
1012 	    }
1013 
1014 	    /*
1015 	     * write (nls-nse) chars of new starting at nse
1016 	     */
1017 	    so_write(nse, (nls - nse));
1018 	}
1019 	else {
1020 	    int olen = (int) (oe - old + fx);
1021 	    if (olen > TermH)
1022 		olen = TermH;
1023 #ifdef DEBUG_UPDATE
1024 	    dprintf("but with nothing left to save\r\n");
1025 #endif /* DEBUG_UPDATE */
1026 	    so_write(nse, (nls - nse));
1027 #ifdef DEBUG_REFRESH
1028 	    dprintf("cleareol %d\n", olen - (ne - new));
1029 #endif /* DEBUG_UPDATE */
1030 #ifndef WINNT_NATIVE
1031 	    ClearEOL(olen - (ne - new));
1032 #else
1033 	    /*
1034 	     * The calculation above does not work too well on NT
1035 	     */
1036 	    ClearEOL(TermH - CursorH);
1037 #endif /*WINNT_NATIVE*/
1038 	}
1039     }
1040 
1041     /*
1042      * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
1043      */
1044     if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
1045 #ifdef DEBUG_UPDATE
1046 	dprintf("late first diff insert at %d...\r\n", nfd - new);
1047 #endif /* DEBUG_UPDATE */
1048 
1049 	MoveToChar(nfd - new);
1050 	/*
1051 	 * Check if we have stuff to keep at the end
1052 	 */
1053 	if (nsb != ne) {
1054 #ifdef DEBUG_UPDATE
1055 	    dprintf("with stuff to keep at end\r\n");
1056 #endif /* DEBUG_UPDATE */
1057 	    /*
1058 	     * We have to recalculate fx here because we set it
1059 	     * to zero above as a flag saying that we hadn't done
1060 	     * an early first insert.
1061 	     */
1062 	    fx = (int) ((nsb - nfd) - (osb - ofd));
1063 	    if (fx > 0) {
1064 		/*
1065 		 * insert fx chars of new starting at nfd
1066 		 */
1067 #ifdef DEBUG_UPDATE
1068 		if (!T_CanIns)
1069 		    dprintf("   ERROR: cannot insert in late first diff\n");
1070 #endif /* DEBUG_UPDATE */
1071 		Insert_write(nfd, fx);
1072 		str_insert(old, (int) (ofd - old), TermH, nfd, fx);
1073 	    }
1074 
1075 	    /*
1076 	     * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
1077 	     */
1078 	    so_write(nfd + fx, (nsb - nfd) - fx);
1079 	    str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
1080 	}
1081 	else {
1082 #ifdef DEBUG_UPDATE
1083 	    dprintf("without anything to save\r\n");
1084 #endif /* DEBUG_UPDATE */
1085 	    so_write(nfd, (nsb - nfd));
1086 	    str_cp(ofd, nfd, (int) (nsb - nfd));
1087 	}
1088     }
1089 
1090     /*
1091      * line is now NEW up to nse
1092      */
1093     if (sx >= 0) {
1094 #ifdef DEBUG_UPDATE
1095 	dprintf("second diff insert at %d...\r\n", nse - new);
1096 #endif /* DEBUG_UPDATE */
1097 	MoveToChar(nse - new);
1098 	if (ols != oe) {
1099 #ifdef DEBUG_UPDATE
1100 	    dprintf("with stuff to keep at end\r\n");
1101 #endif /* DEBUG_UPDATE */
1102 	    if (sx > 0) {
1103 		/* insert sx chars of new starting at nse */
1104 #ifdef DEBUG_UPDATE
1105 		if (!T_CanIns)
1106 		    dprintf("   ERROR: cannot insert in second diff\n");
1107 #endif /* DEBUG_UPDATE */
1108 		Insert_write(nse, sx);
1109 	    }
1110 
1111 	    /*
1112 	     * write (nls-nse) - sx chars of new starting at (nse + sx)
1113 	     */
1114 	    so_write(nse + sx, (nls - nse) - sx);
1115 	}
1116 	else {
1117 #ifdef DEBUG_UPDATE
1118 	    dprintf("without anything to save\r\n");
1119 #endif /* DEBUG_UPDATE */
1120 	    so_write(nse, (nls - nse));
1121 
1122 	    /*
1123              * No need to do a clear-to-end here because we were doing
1124 	     * a second insert, so we will have over written all of the
1125 	     * old string.
1126 	     */
1127 	}
1128     }
1129 #ifdef DEBUG_UPDATE
1130     dprintf("done.\r\n");
1131 #endif /* DEBUG_UPDATE */
1132 }
1133 
1134 
1135 static void
1136 cpy_pad_spaces(dst, src, width)
1137     Char *dst, *src;
1138     int width;
1139 {
1140     int i;
1141 
1142     for (i = 0; i < width; i++) {
1143 	if (*src == (Char) 0)
1144 	    break;
1145 	*dst++ = *src++;
1146     }
1147 
1148     while (i < width) {
1149 	*dst++ = ' ';
1150 	i++;
1151     }
1152     *dst = (Char) 0;
1153 }
1154 
1155 void
1156 RefCursor()
1157 {				/* only move to new cursor pos */
1158     Char *cp;
1159     NLSChar c;
1160     int l, w, h, th, v;
1161 
1162     /* first we must find where the cursor is... */
1163     h = 0;
1164     v = 0;
1165     th = TermH;			/* optimize for speed */
1166 
1167     for (cp = PromptBuf; *cp; ) {	/* do prompt */
1168 	if (*cp & LITERAL) {
1169 	    cp++;
1170 	    continue;
1171 	}
1172 	l = NLSFrom(cp, NLSZEROT, &c);
1173 	w = NLSClassify(c, cp == PromptBuf);
1174 	cp += l;
1175 	switch(w) {
1176 	    case NLSCLASS_NL:
1177 		h = 0;
1178 		v++;
1179 		break;
1180 	    case NLSCLASS_TAB:
1181 		while (++h & 07)
1182 		    ;
1183 		break;
1184 	    case NLSCLASS_CTRL:
1185 		h += 2;
1186 		break;
1187 	    case NLSCLASS_ILLEGAL:
1188 		h += 4;
1189 		break;
1190 	    case NLSCLASS_ILLEGAL2:
1191 	    case NLSCLASS_ILLEGAL3:
1192 	    case NLSCLASS_ILLEGAL4:
1193 		h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1194 		break;
1195 	    default:
1196 		h += w;
1197 	}
1198 	if (h >= th) {		/* check, extra long tabs picked up here also */
1199 	    h -= th;
1200 	    v++;
1201 	}
1202     }
1203 
1204     for (cp = InputBuf; cp < Cursor;) {	/* do input buffer to Cursor */
1205 	l = NLSFrom(cp, Cursor - cp, &c);
1206 	w = NLSClassify(c, cp == InputBuf);
1207 	cp += l;
1208 	switch(w) {
1209 	    case NLSCLASS_NL:
1210 		h = 0;
1211 		v++;
1212 		break;
1213 	    case NLSCLASS_TAB:
1214 		while (++h & 07)
1215 		    ;
1216 		break;
1217 	    case NLSCLASS_CTRL:
1218 		h += 2;
1219 		break;
1220 	    case NLSCLASS_ILLEGAL:
1221 		h += 4;
1222 		break;
1223 	    case NLSCLASS_ILLEGAL2:
1224 	    case NLSCLASS_ILLEGAL3:
1225 	    case NLSCLASS_ILLEGAL4:
1226 		h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1227 		break;
1228 	    default:
1229 		h += w;
1230 	}
1231 	if (h >= th) {		/* check, extra long tabs picked up here also */
1232 	    h -= th;
1233 	    v++;
1234 	}
1235     }
1236 
1237     /* now go there */
1238     MoveToLine(v);
1239     MoveToChar(h);
1240     flush();
1241 }
1242 
1243 #ifndef WINTT_NATIVE
1244 static void
1245 PutPlusOne(c, width)
1246     Char   c;
1247     int    width;
1248 {
1249     while (width > 1 && CursorH + width > TermH)
1250 	PutPlusOne(' ', 1);
1251     if ((c & LITERAL) != 0) {
1252 	Char *d;
1253 	for (d = litptr + (c & ~LITERAL) * LIT_FACTOR; *d; d++)
1254 	    (void) putwraw(*d);
1255     } else {
1256 	(void) putwraw(c);
1257     }
1258     Display[CursorV][CursorH++] = (Char) c;
1259     while (--width > 0)
1260 	Display[CursorV][CursorH++] = CHAR_DBWIDTH;
1261     if (CursorH >= TermH) {	/* if we must overflow */
1262 	CursorH = 0;
1263 	CursorV++;
1264 	OldvcV++;
1265 	if (T_Margin & MARGIN_AUTO) {
1266 	    if (T_Margin & MARGIN_MAGIC) {
1267 		(void) putraw(' ');
1268 		(void) putraw('\b');
1269 	    }
1270 	}
1271 	else {
1272 	    (void) putraw('\r');
1273 	    (void) putraw('\n');
1274 	}
1275     }
1276 }
1277 #endif
1278 
1279 void
1280 RefPlusOne(int l)
1281 {				/* we added just one char, handle it fast.
1282 				 * assumes that screen cursor == real cursor */
1283     Char *cp;
1284     int w;
1285     NLSChar c;
1286 
1287     if (Cursor != LastChar) {
1288 	Refresh();		/* too hard to handle */
1289 	return;
1290     }
1291     if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) {
1292 	Refresh();		/* clear out rprompt if less than one char gap*/
1293 	return;
1294     }
1295     cp = Cursor - l;
1296     NLSFrom(cp, (size_t)l, &c);
1297     w = NLSClassify(c, cp == InputBuf);
1298     switch(w) {
1299 	case NLSCLASS_CTRL:
1300 	    PutPlusOne('^', 1);
1301 	    if (c == CTL_ESC('\177')) {
1302 		PutPlusOne('?', 1);
1303 		break;
1304 	    }
1305 #ifdef IS_ASCII
1306 	    /* uncontrolify it; works only for iso8859-1 like sets */
1307 	    PutPlusOne((c | 0100), 1);
1308 #else
1309 	    PutPlusOne(_toebcdic[_toascii[c]|0100], 1);
1310 #endif
1311 	    break;
1312 	case NLSCLASS_ILLEGAL:
1313 	    PutPlusOne('\\', 1);
1314 	    PutPlusOne(((c >> 6) & 7) + '0', 1);
1315 	    PutPlusOne(((c >> 3) & 7) + '0', 1);
1316 	    PutPlusOne((c & 7) + '0', 1);
1317 	    break;
1318 	case 1:
1319 	    if (l > 1)
1320 		PutPlusOne(MakeLiteral(cp, l, 0), 1);
1321 	    else
1322 		PutPlusOne(*cp, 1);
1323 	    break;
1324 	default:
1325 	    Refresh();		/* too hard to handle */
1326 	    return;
1327     }
1328     flush();
1329 }
1330 
1331 /* clear the screen buffers so that new new prompt starts fresh. */
1332 
1333 void
1334 ClearDisp()
1335 {
1336     int i;
1337 
1338     CursorV = 0;		/* clear the display buffer */
1339     CursorH = 0;
1340     for (i = 0; i < TermV; i++)
1341 	(void) memset(Display[i], 0, TermH * sizeof(Display[0][0]));
1342     OldvcV = 0;
1343     litlen = 0;
1344 }
1345 
1346 void
1347 ClearLines()
1348 {				/* Make sure all lines are *really* blank */
1349     int i;
1350 
1351     if (T_CanCEOL) {
1352 	/*
1353 	 * Clear the lines from the bottom up so that if we try moving
1354 	 * the cursor down by writing the character that is at the end
1355 	 * of the screen line, we won't rewrite a character that shouldn't
1356 	 * be there.
1357 	 */
1358 	for (i = OldvcV; i >= 0; i--) {	/* for each line on the screen */
1359 	    MoveToLine(i);
1360 	    MoveToChar(0);
1361 	    ClearEOL(TermH);
1362 	}
1363     }
1364     else {
1365 	MoveToLine(OldvcV);	/* go to last line */
1366 	(void) putraw('\r');	/* go to BOL */
1367 	(void) putraw('\n');	/* go to new line */
1368     }
1369 }
1370