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