1313981Spfg/*	$NetBSD: refresh.c,v 1.45 2016/03/02 19:24:20 christos Exp $	*/
2276881Sbapt
31573Srgrimes/*-
41573Srgrimes * Copyright (c) 1992, 1993
51573Srgrimes *	The Regents of the University of California.  All rights reserved.
61573Srgrimes *
71573Srgrimes * This code is derived from software contributed to Berkeley by
81573Srgrimes * Christos Zoulas of Cornell University.
91573Srgrimes *
101573Srgrimes * Redistribution and use in source and binary forms, with or without
111573Srgrimes * modification, are permitted provided that the following conditions
121573Srgrimes * are met:
131573Srgrimes * 1. Redistributions of source code must retain the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer.
151573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161573Srgrimes *    notice, this list of conditions and the following disclaimer in the
171573Srgrimes *    documentation and/or other materials provided with the distribution.
18148834Sstefanf * 3. Neither the name of the University nor the names of its contributors
191573Srgrimes *    may be used to endorse or promote products derived from this software
201573Srgrimes *    without specific prior written permission.
211573Srgrimes *
221573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321573Srgrimes * SUCH DAMAGE.
331573Srgrimes */
341573Srgrimes
35276881Sbapt#include "config.h"
361573Srgrimes#if !defined(lint) && !defined(SCCSID)
37276881Sbapt#if 0
381573Srgrimesstatic char sccsid[] = "@(#)refresh.c	8.1 (Berkeley) 6/4/93";
39276881Sbapt#else
40313981Spfg__RCSID("$NetBSD: refresh.c,v 1.45 2016/03/02 19:24:20 christos Exp $");
41276881Sbapt#endif
421573Srgrimes#endif /* not lint && not SCCSID */
4384260Sobrien#include <sys/cdefs.h>
4484260Sobrien__FBSDID("$FreeBSD: stable/11/lib/libedit/refresh.c 330446 2018-03-05 06:59:30Z eadler $");
451573Srgrimes
461573Srgrimes/*
471573Srgrimes * refresh.c: Lower level screen refreshing functions
481573Srgrimes */
491573Srgrimes#include <stdio.h>
50313981Spfg#include <string.h>
51296435Spfg#include <unistd.h>
521573Srgrimes
531573Srgrimes#include "el.h"
541573Srgrimes
55237448Spfgprivate void	re_nextline(EditLine *);
56313981Spfgprivate void	re_addc(EditLine *, wint_t);
57276881Sbaptprivate void	re_update_line(EditLine *, Char *, Char *, int);
58276881Sbaptprivate void	re_insert (EditLine *, Char *, int, int, Char *, int);
59276881Sbaptprivate void	re_delete(EditLine *, Char *, int, int, int);
60313981Spfgprivate void	re_fastputc(EditLine *, wint_t);
61153079Sstefanfprivate void	re_clear_eol(EditLine *, int, int, int);
62276881Sbaptprivate void	re__strncopy(Char *, Char *, size_t);
63276881Sbaptprivate void	re__copy_and_pad(Char *, const Char *, size_t);
641573Srgrimes
651573Srgrimes#ifdef DEBUG_REFRESH
66313981Spfgprivate void	re_printstr(EditLine *, const char *, Char *, Char *);
6784260Sobrien#define	__F el->el_errfile
68313981Spfg#define	ELRE_ASSERT(a, b, c)	do				\
69148834Sstefanf				    if (/*CONSTCOND*/ a) {	\
701573Srgrimes					(void) fprintf b;	\
711573Srgrimes					c;			\
721573Srgrimes				    }				\
73148834Sstefanf				while (/*CONSTCOND*/0)
7484260Sobrien#define	ELRE_DEBUG(a, b)	ELRE_ASSERT(a,b,;)
7584260Sobrien
761573Srgrimes/* re_printstr():
771573Srgrimes *	Print a string on the debugging pty
781573Srgrimes */
791573Srgrimesprivate void
80313981Spfgre_printstr(EditLine *el, const char *str, Char *f, Char *t)
811573Srgrimes{
8284260Sobrien
8384260Sobrien	ELRE_DEBUG(1, (__F, "%s:\"", str));
8484260Sobrien	while (f < t)
8584260Sobrien		ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
8684260Sobrien	ELRE_DEBUG(1, (__F, "\"\r\n"));
878870Srgrimes}
881573Srgrimes#else
8984260Sobrien#define	ELRE_ASSERT(a, b, c)
9084260Sobrien#define	ELRE_DEBUG(a, b)
911573Srgrimes#endif
921573Srgrimes
93237448Spfg/* re_nextline():
94237448Spfg *	Move to the next line or scroll
95237448Spfg */
96237448Spfgprivate void
97237448Spfgre_nextline(EditLine *el)
98237448Spfg{
99237448Spfg	el->el_refresh.r_cursor.h = 0;	/* reset it. */
1001573Srgrimes
101237448Spfg	/*
102237448Spfg	 * If we would overflow (input is longer than terminal size),
103237448Spfg	 * emulate scroll by dropping first line and shuffling the rest.
104237448Spfg	 * We do this via pointer shuffling - it's safe in this case
105237448Spfg	 * and we avoid memcpy().
106237448Spfg	 */
107276881Sbapt	if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) {
108276881Sbapt		int i, lins = el->el_terminal.t_size.v;
109276881Sbapt		Char *firstline = el->el_vdisplay[0];
110237448Spfg
111237448Spfg		for(i = 1; i < lins; i++)
112237448Spfg			el->el_vdisplay[i - 1] = el->el_vdisplay[i];
113237448Spfg
114313981Spfg		firstline[0] = '\0';		/* empty the string */
115237448Spfg		el->el_vdisplay[i - 1] = firstline;
116237448Spfg	} else
117237448Spfg		el->el_refresh.r_cursor.v++;
118237448Spfg
119276881Sbapt	ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v,
120237448Spfg	    (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
121276881Sbapt	    el->el_refresh.r_cursor.v, el->el_terminal.t_size.v),
122237448Spfg	    abort());
123237448Spfg}
124237448Spfg
1251573Srgrimes/* re_addc():
1261573Srgrimes *	Draw c, expanding tabs, control chars etc.
1271573Srgrimes */
1281573Srgrimesprivate void
129313981Spfgre_addc(EditLine *el, wint_t c)
1301573Srgrimes{
131276881Sbapt	switch (ct_chr_class((Char)c)) {
132276881Sbapt	case CHTYPE_TAB:        /* expand the tab */
13384260Sobrien		for (;;) {
13484260Sobrien			re_putc(el, ' ', 1);
13584260Sobrien			if ((el->el_refresh.r_cursor.h & 07) == 0)
13684260Sobrien				break;			/* go until tab stop */
13784260Sobrien		}
138276881Sbapt		break;
139276881Sbapt	case CHTYPE_NL: {
140276881Sbapt		int oldv = el->el_refresh.r_cursor.v;
141276881Sbapt		re_putc(el, '\0', 0);			/* assure end of line */
142276881Sbapt		if (oldv == el->el_refresh.r_cursor.v)	/* XXX */
143276881Sbapt			re_nextline(el);
144276881Sbapt		break;
14584260Sobrien	}
146276881Sbapt	case CHTYPE_PRINT:
147276881Sbapt		re_putc(el, c, 1);
148276881Sbapt		break;
149276881Sbapt	default: {
150276881Sbapt		Char visbuf[VISUAL_WIDTH_MAX];
151276881Sbapt		ssize_t i, n =
152276881Sbapt		    ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c);
153276881Sbapt		for (i = 0; n-- > 0; ++i)
154276881Sbapt		    re_putc(el, visbuf[i], 1);
155276881Sbapt		break;
156276881Sbapt	}
157276881Sbapt	}
15884260Sobrien}
1591573Srgrimes
1601573Srgrimes
1611573Srgrimes/* re_putc():
1621573Srgrimes *	Draw the character given
1631573Srgrimes */
1641573Srgrimesprotected void
165313981Spfgre_putc(EditLine *el, wint_t c, int shift)
1661573Srgrimes{
167276881Sbapt	int i, w = Width(c);
168313981Spfg	ELRE_DEBUG(1, (__F, "printing %5x '%lc'\r\n", c, c));
1691573Srgrimes
170276881Sbapt	while (shift && (el->el_refresh.r_cursor.h + w > el->el_terminal.t_size.h))
171276881Sbapt	    re_putc(el, ' ', 1);
1721573Srgrimes
173276881Sbapt	el->el_vdisplay[el->el_refresh.r_cursor.v]
174313981Spfg	    [el->el_refresh.r_cursor.h] = (Char)c;
175276881Sbapt	/* assumes !shift is only used for single-column chars */
176276881Sbapt	i = w;
177276881Sbapt	while (--i > 0)
178276881Sbapt		el->el_vdisplay[el->el_refresh.r_cursor.v]
179276881Sbapt		    [el->el_refresh.r_cursor.h + i] = MB_FILL_CHAR;
180276881Sbapt
18184260Sobrien	if (!shift)
18284260Sobrien		return;
1831573Srgrimes
184276881Sbapt	el->el_refresh.r_cursor.h += w;	/* advance to next place */
185276881Sbapt	if (el->el_refresh.r_cursor.h >= el->el_terminal.t_size.h) {
18684260Sobrien		/* assure end of line */
187276881Sbapt		el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_terminal.t_size.h]
188237448Spfg		    = '\0';
189237448Spfg		re_nextline(el);
190237448Spfg	}
19184260Sobrien}
19284260Sobrien
19384260Sobrien
1941573Srgrimes/* re_refresh():
1951573Srgrimes *	draws the new virtual screen image from the current input
196313981Spfg *	line, then goes line-by-line changing the real image to the new
1971573Srgrimes *	virtual image. The routine to re-draw a line can be replaced
1981573Srgrimes *	easily in hopes of a smarter one being placed there.
1991573Srgrimes */
2001573Srgrimesprotected void
20184260Sobrienre_refresh(EditLine *el)
2021573Srgrimes{
20384260Sobrien	int i, rhdiff;
204276881Sbapt	Char *cp, *st;
20584260Sobrien	coord_t cur;
20684260Sobrien#ifdef notyet
20784260Sobrien	size_t termsz;
20884260Sobrien#endif
2091573Srgrimes
210313981Spfg	ELRE_DEBUG(1, (__F, "el->el_line.buffer = :" FSTR ":\r\n",
21184260Sobrien	    el->el_line.buffer));
2121573Srgrimes
21384260Sobrien	/* reset the Drawing cursor */
21484260Sobrien	el->el_refresh.r_cursor.h = 0;
21584260Sobrien	el->el_refresh.r_cursor.v = 0;
2161573Srgrimes
21784260Sobrien	/* temporarily draw rprompt to calculate its size */
21884260Sobrien	prompt_print(el, EL_RPROMPT);
2191573Srgrimes
22084260Sobrien	/* reset the Drawing cursor */
22184260Sobrien	el->el_refresh.r_cursor.h = 0;
22284260Sobrien	el->el_refresh.r_cursor.v = 0;
2231573Srgrimes
224148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar) {
225148834Sstefanf		if (el->el_map.current == el->el_map.alt
226148834Sstefanf		    && el->el_line.lastchar != el->el_line.buffer)
227148834Sstefanf			el->el_line.cursor = el->el_line.lastchar - 1;
228148834Sstefanf		else
229148834Sstefanf			el->el_line.cursor = el->el_line.lastchar;
230148834Sstefanf	}
231148834Sstefanf
23284260Sobrien	cur.h = -1;		/* set flag in case I'm not set */
23384260Sobrien	cur.v = 0;
23484260Sobrien
23584260Sobrien	prompt_print(el, EL_PROMPT);
23684260Sobrien
23784260Sobrien	/* draw the current input buffer */
23884260Sobrien#if notyet
239276881Sbapt	termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v;
24084260Sobrien	if (el->el_line.lastchar - el->el_line.buffer > termsz) {
24184260Sobrien		/*
24284260Sobrien		 * If line is longer than terminal, process only part
24384260Sobrien		 * of line which would influence display.
24484260Sobrien		 */
24584260Sobrien		size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
24684260Sobrien
24784260Sobrien		st = el->el_line.lastchar - rem
248276881Sbapt			- (termsz - (((rem / el->el_terminal.t_size.v) - 1)
249276881Sbapt					* el->el_terminal.t_size.v));
25084260Sobrien	} else
25184260Sobrien#endif
25284260Sobrien		st = el->el_line.buffer;
25384260Sobrien
25484260Sobrien	for (cp = st; cp < el->el_line.lastchar; cp++) {
25584260Sobrien		if (cp == el->el_line.cursor) {
256276881Sbapt                        int w = Width(*cp);
25784260Sobrien			/* save for later */
25884260Sobrien			cur.h = el->el_refresh.r_cursor.h;
25984260Sobrien			cur.v = el->el_refresh.r_cursor.v;
260276881Sbapt                        /* handle being at a linebroken doublewidth char */
261276881Sbapt                        if (w > 1 && el->el_refresh.r_cursor.h + w >
262276881Sbapt			    el->el_terminal.t_size.h) {
263276881Sbapt				cur.h = 0;
264276881Sbapt				cur.v++;
265276881Sbapt                        }
26684260Sobrien		}
267276881Sbapt		re_addc(el, *cp);
2681573Srgrimes	}
2691573Srgrimes
27084260Sobrien	if (cur.h == -1) {	/* if I haven't been set yet, I'm at the end */
27184260Sobrien		cur.h = el->el_refresh.r_cursor.h;
27284260Sobrien		cur.v = el->el_refresh.r_cursor.v;
27384260Sobrien	}
274276881Sbapt	rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h -
27584260Sobrien	    el->el_rprompt.p_pos.h;
27684260Sobrien	if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
27784260Sobrien	    !el->el_refresh.r_cursor.v && rhdiff > 1) {
27884260Sobrien		/*
27984260Sobrien		 * have a right-hand side prompt that will fit
28084260Sobrien		 * on the end of the first line with at least
28184260Sobrien		 * one character gap to the input buffer.
28284260Sobrien		 */
28384260Sobrien		while (--rhdiff > 0)	/* pad out with spaces */
28484260Sobrien			re_putc(el, ' ', 1);
28584260Sobrien		prompt_print(el, EL_RPROMPT);
28684260Sobrien	} else {
28784260Sobrien		el->el_rprompt.p_pos.h = 0;	/* flag "not using rprompt" */
28884260Sobrien		el->el_rprompt.p_pos.v = 0;
28984260Sobrien	}
2901573Srgrimes
29184260Sobrien	re_putc(el, '\0', 0);	/* make line ended with NUL, no cursor shift */
2921573Srgrimes
29384260Sobrien	el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
2941573Srgrimes
29584260Sobrien	ELRE_DEBUG(1, (__F,
29684260Sobrien		"term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
297276881Sbapt		el->el_terminal.t_size.h, el->el_refresh.r_cursor.h,
298313981Spfg		el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0],
299313981Spfg		&el->el_scratch)));
3001573Srgrimes
30184260Sobrien	ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
30284260Sobrien	for (i = 0; i <= el->el_refresh.r_newcv; i++) {
30384260Sobrien		/* NOTE THAT re_update_line MAY CHANGE el_display[i] */
30484260Sobrien		re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
30584260Sobrien
30684260Sobrien		/*
30784260Sobrien		 * Copy the new line to be the current one, and pad out with
30884260Sobrien		 * spaces to the full width of the terminal so that if we try
30984260Sobrien		 * moving the cursor by writing the character that is at the
31084260Sobrien		 * end of the screen line, it won't be a NUL or some old
31184260Sobrien		 * leftover stuff.
31284260Sobrien		 */
31384260Sobrien		re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
314276881Sbapt		    (size_t) el->el_terminal.t_size.h);
31584260Sobrien	}
31684260Sobrien	ELRE_DEBUG(1, (__F,
31784260Sobrien	"\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
31884260Sobrien	    el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
31984260Sobrien
32084260Sobrien	if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
32184260Sobrien		for (; i <= el->el_refresh.r_oldcv; i++) {
322276881Sbapt			terminal_move_to_line(el, i);
323276881Sbapt			terminal_move_to_char(el, 0);
324276881Sbapt                        /* This Strlen should be safe even with MB_FILL_CHARs */
325276881Sbapt			terminal_clear_EOL(el, (int) Strlen(el->el_display[i]));
3261573Srgrimes#ifdef DEBUG_REFRESH
327313981Spfg			terminal_overwrite(el, STR("C\b"), 2);
3281573Srgrimes#endif /* DEBUG_REFRESH */
32984260Sobrien			el->el_display[i][0] = '\0';
33084260Sobrien		}
3318870Srgrimes
33284260Sobrien	el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
33384260Sobrien	ELRE_DEBUG(1, (__F,
33484260Sobrien	    "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
33584260Sobrien	    el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
33684260Sobrien	    cur.h, cur.v));
337276881Sbapt	terminal_move_to_line(el, cur.v);	/* go to where the cursor is */
338276881Sbapt	terminal_move_to_char(el, cur.h);
33984260Sobrien}
3401573Srgrimes
3411573Srgrimes
3421573Srgrimes/* re_goto_bottom():
3438870Srgrimes *	 used to go to last used screen line
3441573Srgrimes */
3451573Srgrimesprotected void
34684260Sobrienre_goto_bottom(EditLine *el)
3471573Srgrimes{
3481573Srgrimes
349276881Sbapt	terminal_move_to_line(el, el->el_refresh.r_oldcv);
350276881Sbapt	terminal__putc(el, '\n');
35184260Sobrien	re_clear_display(el);
352276881Sbapt	terminal__flush(el);
35384260Sobrien}
3541573Srgrimes
35584260Sobrien
3561573Srgrimes/* re_insert():
3571573Srgrimes *	insert num characters of s into d (in front of the character)
3588870Srgrimes *	at dat, maximum length of d is dlen
3591573Srgrimes */
3601573Srgrimesprivate void
3611573Srgrimes/*ARGSUSED*/
362276881Sbaptre_insert(EditLine *el __attribute__((__unused__)),
363276881Sbapt    Char *d, int dat, int dlen, Char *s, int num)
3641573Srgrimes{
365276881Sbapt	Char *a, *b;
3661573Srgrimes
36784260Sobrien	if (num <= 0)
36884260Sobrien		return;
36984260Sobrien	if (num > dlen - dat)
37084260Sobrien		num = dlen - dat;
3711573Srgrimes
37284260Sobrien	ELRE_DEBUG(1,
37384260Sobrien	    (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
374313981Spfg	    num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
375313981Spfg	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
376313981Spfg	    &el->el_scratch)));
3771573Srgrimes
37884260Sobrien	/* open up the space for num chars */
37984260Sobrien	if (num > 0) {
38084260Sobrien		b = d + dlen - 1;
38184260Sobrien		a = b - num;
38284260Sobrien		while (a >= &d[dat])
38384260Sobrien			*b-- = *a--;
38484260Sobrien		d[dlen] = '\0';	/* just in case */
38584260Sobrien	}
386276881Sbapt
38784260Sobrien	ELRE_DEBUG(1, (__F,
3881573Srgrimes		"re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
389313981Spfg		num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
390313981Spfg	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
391313981Spfg		&el->el_scratch)));
3921573Srgrimes
39384260Sobrien	/* copy the characters */
39484260Sobrien	for (a = d + dat; (a < d + dlen) && (num > 0); num--)
39584260Sobrien		*a++ = *s++;
3961573Srgrimes
397276881Sbapt#ifdef notyet
398276881Sbapt        /* ct_encode_string() uses a static buffer, so we can't conveniently
399276881Sbapt         * encode both d & s here */
40084260Sobrien	ELRE_DEBUG(1,
40184260Sobrien	    (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
40284260Sobrien	    num, dat, dlen, d, s));
403153079Sstefanf	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
404276881Sbapt#endif
40584260Sobrien}
4061573Srgrimes
4071573Srgrimes
4081573Srgrimes/* re_delete():
4098870Srgrimes *	delete num characters d at dat, maximum length of d is dlen
4101573Srgrimes */
4111573Srgrimesprivate void
4121573Srgrimes/*ARGSUSED*/
413276881Sbaptre_delete(EditLine *el __attribute__((__unused__)),
414276881Sbapt    Char *d, int dat, int dlen, int num)
4151573Srgrimes{
416276881Sbapt	Char *a, *b;
4171573Srgrimes
41884260Sobrien	if (num <= 0)
41984260Sobrien		return;
42084260Sobrien	if (dat + num >= dlen) {
42184260Sobrien		d[dat] = '\0';
42284260Sobrien		return;
42384260Sobrien	}
42484260Sobrien	ELRE_DEBUG(1,
42584260Sobrien	    (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
426313981Spfg	    num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
4271573Srgrimes
42884260Sobrien	/* open up the space for num chars */
42984260Sobrien	if (num > 0) {
43084260Sobrien		b = d + dat;
43184260Sobrien		a = b + num;
43284260Sobrien		while (a < &d[dlen])
43384260Sobrien			*b++ = *a++;
43484260Sobrien		d[dlen] = '\0';	/* just in case */
43584260Sobrien	}
43684260Sobrien	ELRE_DEBUG(1,
43784260Sobrien	    (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
438313981Spfg	    num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
43984260Sobrien}
4401573Srgrimes
4411573Srgrimes
4421573Srgrimes/* re__strncopy():
4431573Srgrimes *	Like strncpy without padding.
4441573Srgrimes */
4451573Srgrimesprivate void
446276881Sbaptre__strncopy(Char *a, Char *b, size_t n)
4471573Srgrimes{
4481573Srgrimes
44984260Sobrien	while (n-- && *b)
45084260Sobrien		*a++ = *b++;
45184260Sobrien}
4521573Srgrimes
453153079Sstefanf/* re_clear_eol():
454153079Sstefanf *	Find the number of characters we need to clear till the end of line
455153079Sstefanf *	in order to make sure that we have cleared the previous contents of
456153079Sstefanf *	the line. fx and sx is the number of characters inserted or deleted
457276881Sbapt *	in the first or second diff, diff is the difference between the
458313981Spfg *	number of characters between the new and old line.
459153079Sstefanf */
460153079Sstefanfprivate void
461153079Sstefanfre_clear_eol(EditLine *el, int fx, int sx, int diff)
462153079Sstefanf{
46384260Sobrien
464153079Sstefanf	ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
465153079Sstefanf	    sx, fx, diff));
466153079Sstefanf
467153079Sstefanf	if (fx < 0)
468153079Sstefanf		fx = -fx;
469153079Sstefanf	if (sx < 0)
470153079Sstefanf		sx = -sx;
471153079Sstefanf	if (fx > diff)
472153079Sstefanf		diff = fx;
473153079Sstefanf	if (sx > diff)
474153079Sstefanf		diff = sx;
475153079Sstefanf
476153079Sstefanf	ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
477276881Sbapt	terminal_clear_EOL(el, diff);
478153079Sstefanf}
479153079Sstefanf
48084260Sobrien/*****************************************************************
4811573Srgrimes    re_update_line() is based on finding the middle difference of each line
4821573Srgrimes    on the screen; vis:
4831573Srgrimes
4841573Srgrimes			     /old first difference
4851573Srgrimes	/beginning of line   |              /old last same       /old EOL
4861573Srgrimes	v		     v              v                    v
4871573Srgrimesold:	eddie> Oh, my little gruntle-buggy is to me, as lurgid as
4881573Srgrimesnew:	eddie> Oh, my little buggy says to me, as lurgid as
4891573Srgrimes	^		     ^        ^			   ^
4901573Srgrimes	\beginning of line   |        \new last same	   \new end of line
4911573Srgrimes			     \new first difference
4921573Srgrimes
4931573Srgrimes    all are character pointers for the sake of speed.  Special cases for
4941573Srgrimes    no differences, as well as for end of line additions must be handled.
4951573Srgrimes**************************************************************** */
4961573Srgrimes
4971573Srgrimes/* Minimum at which doing an insert it "worth it".  This should be about
4981573Srgrimes * half the "cost" of going into insert mode, inserting a character, and
4991573Srgrimes * going back out.  This should really be calculated from the termcap
5001573Srgrimes * data...  For the moment, a good number for ANSI terminals.
5011573Srgrimes */
50284260Sobrien#define	MIN_END_KEEP	4
5031573Srgrimes
5041573Srgrimesprivate void
505276881Sbaptre_update_line(EditLine *el, Char *old, Char *new, int i)
5061573Srgrimes{
507276881Sbapt	Char *o, *n, *p, c;
508276881Sbapt	Char *ofd, *ols, *oe, *nfd, *nls, *ne;
509276881Sbapt	Char *osb, *ose, *nsb, *nse;
51084260Sobrien	int fx, sx;
511237448Spfg	size_t len;
5121573Srgrimes
51384260Sobrien	/*
51484260Sobrien         * find first diff
51584260Sobrien         */
51684260Sobrien	for (o = old, n = new; *o && (*o == *n); o++, n++)
51784260Sobrien		continue;
51884260Sobrien	ofd = o;
51984260Sobrien	nfd = n;
5201573Srgrimes
52184260Sobrien	/*
52284260Sobrien         * Find the end of both old and new
52384260Sobrien         */
52484260Sobrien	while (*o)
52584260Sobrien		o++;
52684260Sobrien	/*
52784260Sobrien         * Remove any trailing blanks off of the end, being careful not to
52884260Sobrien         * back up past the beginning.
52984260Sobrien         */
53084260Sobrien	while (ofd < o) {
53184260Sobrien		if (o[-1] != ' ')
53284260Sobrien			break;
53384260Sobrien		o--;
53484260Sobrien	}
53584260Sobrien	oe = o;
53684260Sobrien	*oe = '\0';
5378870Srgrimes
53884260Sobrien	while (*n)
53984260Sobrien		n++;
5401573Srgrimes
54184260Sobrien	/* remove blanks from end of new */
54284260Sobrien	while (nfd < n) {
54384260Sobrien		if (n[-1] != ' ')
54484260Sobrien			break;
54584260Sobrien		n--;
5461573Srgrimes	}
54784260Sobrien	ne = n;
54884260Sobrien	*ne = '\0';
5491573Srgrimes
55084260Sobrien	/*
55184260Sobrien         * if no diff, continue to next line of redraw
55284260Sobrien         */
55384260Sobrien	if (*ofd == '\0' && *nfd == '\0') {
55484260Sobrien		ELRE_DEBUG(1, (__F, "no difference.\r\n"));
55584260Sobrien		return;
5561573Srgrimes	}
55784260Sobrien	/*
55884260Sobrien         * find last same pointer
55984260Sobrien         */
56084260Sobrien	while ((o > ofd) && (n > nfd) && (*--o == *--n))
56184260Sobrien		continue;
56284260Sobrien	ols = ++o;
56384260Sobrien	nls = ++n;
5641573Srgrimes
56584260Sobrien	/*
566298896Spfg         * find same beginning and same end
56784260Sobrien         */
5681573Srgrimes	osb = ols;
56984260Sobrien	nsb = nls;
5701573Srgrimes	ose = ols;
5711573Srgrimes	nse = nls;
5721573Srgrimes
5731573Srgrimes	/*
57484260Sobrien         * case 1: insert: scan from nfd to nls looking for *ofd
57584260Sobrien         */
57684260Sobrien	if (*ofd) {
57784260Sobrien		for (c = *ofd, n = nfd; n < nls; n++) {
57884260Sobrien			if (c == *n) {
57984260Sobrien				for (o = ofd, p = n;
58084260Sobrien				    p < nls && o < ols && *o == *p;
58184260Sobrien				    o++, p++)
58284260Sobrien					continue;
58384260Sobrien				/*
58484260Sobrien				 * if the new match is longer and it's worth
58584260Sobrien				 * keeping, then we take it
58684260Sobrien				 */
58784260Sobrien				if (((nse - nsb) < (p - n)) &&
58884260Sobrien				    (2 * (p - n) > n - nfd)) {
58984260Sobrien					nsb = n;
59084260Sobrien					nse = p;
59184260Sobrien					osb = ofd;
59284260Sobrien					ose = o;
59384260Sobrien				}
59484260Sobrien			}
59584260Sobrien		}
59684260Sobrien	}
5971573Srgrimes	/*
59884260Sobrien         * case 2: delete: scan from ofd to ols looking for *nfd
59984260Sobrien         */
60084260Sobrien	if (*nfd) {
60184260Sobrien		for (c = *nfd, o = ofd; o < ols; o++) {
60284260Sobrien			if (c == *o) {
60384260Sobrien				for (n = nfd, p = o;
60484260Sobrien				    p < ols && n < nls && *p == *n;
60584260Sobrien				    p++, n++)
60684260Sobrien					continue;
60784260Sobrien				/*
60884260Sobrien				 * if the new match is longer and it's worth
60984260Sobrien				 * keeping, then we take it
61084260Sobrien				 */
61184260Sobrien				if (((ose - osb) < (p - o)) &&
61284260Sobrien				    (2 * (p - o) > o - ofd)) {
61384260Sobrien					nsb = nfd;
61484260Sobrien					nse = n;
61584260Sobrien					osb = o;
61684260Sobrien					ose = p;
61784260Sobrien				}
61884260Sobrien			}
61984260Sobrien		}
6201573Srgrimes	}
62184260Sobrien	/*
62284260Sobrien         * Pragmatics I: If old trailing whitespace or not enough characters to
62384260Sobrien         * save to be worth it, then don't save the last same info.
62484260Sobrien         */
62584260Sobrien	if ((oe - ols) < MIN_END_KEEP) {
62684260Sobrien		ols = oe;
62784260Sobrien		nls = ne;
6281573Srgrimes	}
6291573Srgrimes	/*
63084260Sobrien         * Pragmatics II: if the terminal isn't smart enough, make the data
63184260Sobrien         * dumber so the smart update doesn't try anything fancy
63284260Sobrien         */
63384260Sobrien
6341573Srgrimes	/*
63584260Sobrien         * fx is the number of characters we need to insert/delete: in the
63684260Sobrien         * beginning to bring the two same begins together
63784260Sobrien         */
638237448Spfg	fx = (int)((nsb - nfd) - (osb - ofd));
63984260Sobrien	/*
64084260Sobrien         * sx is the number of characters we need to insert/delete: in the
64184260Sobrien         * end to bring the two same last parts together
64284260Sobrien         */
643237448Spfg	sx = (int)((nls - nse) - (ols - ose));
6441573Srgrimes
64584260Sobrien	if (!EL_CAN_INSERT) {
64684260Sobrien		if (fx > 0) {
64784260Sobrien			osb = ols;
64884260Sobrien			ose = ols;
64984260Sobrien			nsb = nls;
65084260Sobrien			nse = nls;
65184260Sobrien		}
65284260Sobrien		if (sx > 0) {
65384260Sobrien			ols = oe;
65484260Sobrien			nls = ne;
65584260Sobrien		}
65684260Sobrien		if ((ols - ofd) < (nls - nfd)) {
65784260Sobrien			ols = oe;
65884260Sobrien			nls = ne;
65984260Sobrien		}
6601573Srgrimes	}
66184260Sobrien	if (!EL_CAN_DELETE) {
66284260Sobrien		if (fx < 0) {
66384260Sobrien			osb = ols;
66484260Sobrien			ose = ols;
66584260Sobrien			nsb = nls;
66684260Sobrien			nse = nls;
66784260Sobrien		}
66884260Sobrien		if (sx < 0) {
66984260Sobrien			ols = oe;
67084260Sobrien			nls = ne;
67184260Sobrien		}
67284260Sobrien		if ((ols - ofd) > (nls - nfd)) {
67384260Sobrien			ols = oe;
67484260Sobrien			nls = ne;
67584260Sobrien		}
6761573Srgrimes	}
6771573Srgrimes	/*
67884260Sobrien         * Pragmatics III: make sure the middle shifted pointers are correct if
67984260Sobrien         * they don't point to anything (we may have moved ols or nls).
68084260Sobrien         */
68184260Sobrien	/* if the change isn't worth it, don't bother */
68284260Sobrien	/* was: if (osb == ose) */
68384260Sobrien	if ((ose - osb) < MIN_END_KEEP) {
68484260Sobrien		osb = ols;
68584260Sobrien		ose = ols;
68684260Sobrien		nsb = nls;
68784260Sobrien		nse = nls;
68884260Sobrien	}
6891573Srgrimes	/*
69084260Sobrien         * Now that we are done with pragmatics we recompute fx, sx
69184260Sobrien         */
692237448Spfg	fx = (int)((nsb - nfd) - (osb - ofd));
693237448Spfg	sx = (int)((nls - nse) - (ols - ose));
6941573Srgrimes
695153079Sstefanf	ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
696313981Spfg	ELRE_DEBUG(1, (__F, "ofd %td, osb %td, ose %td, ols %td, oe %td\n",
69784260Sobrien		ofd - old, osb - old, ose - old, ols - old, oe - old));
698313981Spfg	ELRE_DEBUG(1, (__F, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n",
69984260Sobrien		nfd - new, nsb - new, nse - new, nls - new, ne - new));
70084260Sobrien	ELRE_DEBUG(1, (__F,
70184260Sobrien		"xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
70284260Sobrien	ELRE_DEBUG(1, (__F,
70384260Sobrien		"xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
70484260Sobrien#ifdef DEBUG_REFRESH
70584260Sobrien	re_printstr(el, "old- oe", old, oe);
70684260Sobrien	re_printstr(el, "new- ne", new, ne);
70784260Sobrien	re_printstr(el, "old-ofd", old, ofd);
70884260Sobrien	re_printstr(el, "new-nfd", new, nfd);
70984260Sobrien	re_printstr(el, "ofd-osb", ofd, osb);
71084260Sobrien	re_printstr(el, "nfd-nsb", nfd, nsb);
71184260Sobrien	re_printstr(el, "osb-ose", osb, ose);
71284260Sobrien	re_printstr(el, "nsb-nse", nsb, nse);
71384260Sobrien	re_printstr(el, "ose-ols", ose, ols);
71484260Sobrien	re_printstr(el, "nse-nls", nse, nls);
71584260Sobrien	re_printstr(el, "ols- oe", ols, oe);
71684260Sobrien	re_printstr(el, "nls- ne", nls, ne);
71784260Sobrien#endif /* DEBUG_REFRESH */
71884260Sobrien
7191573Srgrimes	/*
72084260Sobrien         * el_cursor.v to this line i MUST be in this routine so that if we
72184260Sobrien         * don't have to change the line, we don't move to it. el_cursor.h to
72284260Sobrien         * first diff char
72384260Sobrien         */
724276881Sbapt	terminal_move_to_line(el, i);
7251573Srgrimes
72684260Sobrien	/*
72784260Sobrien         * at this point we have something like this:
72884260Sobrien         *
72984260Sobrien         * /old                  /ofd    /osb               /ose    /ols     /oe
73084260Sobrien         * v.....................v       v..................v       v........v
73184260Sobrien         * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
73284260Sobrien         * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
73384260Sobrien         * ^.....................^     ^..................^       ^........^
73484260Sobrien         * \new                  \nfd  \nsb               \nse     \nls    \ne
73584260Sobrien         *
73684260Sobrien         * fx is the difference in length between the chars between nfd and
73784260Sobrien         * nsb, and the chars between ofd and osb, and is thus the number of
73884260Sobrien         * characters to delete if < 0 (new is shorter than old, as above),
73984260Sobrien         * or insert (new is longer than short).
74084260Sobrien         *
74184260Sobrien         * sx is the same for the second differences.
74284260Sobrien         */
7431573Srgrimes
74484260Sobrien	/*
74584260Sobrien         * if we have a net insert on the first difference, AND inserting the
74684260Sobrien         * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
74784260Sobrien         * character (which is ne if nls != ne, otherwise is nse) off the edge
748276881Sbapt	 * of the screen (el->el_terminal.t_size.h) else we do the deletes first
74984260Sobrien	 * so that we keep everything we need to.
75084260Sobrien         */
7511573Srgrimes
7521573Srgrimes	/*
75384260Sobrien         * if the last same is the same like the end, there is no last same
75484260Sobrien         * part, otherwise we want to keep the last same part set p to the
75584260Sobrien         * last useful old character
75684260Sobrien         */
75784260Sobrien	p = (ols != oe) ? oe : ose;
75884260Sobrien
75984260Sobrien	/*
76084260Sobrien         * if (There is a diffence in the beginning) && (we need to insert
76184260Sobrien         *   characters) && (the number of characters to insert is less than
76284260Sobrien         *   the term width)
76384260Sobrien	 *	We need to do an insert!
76484260Sobrien	 * else if (we need to delete characters)
76584260Sobrien	 *	We need to delete characters!
76684260Sobrien	 * else
76784260Sobrien	 *	No insert or delete
76884260Sobrien         */
76984260Sobrien	if ((nsb != nfd) && fx > 0 &&
770276881Sbapt	    ((p - old) + fx <= el->el_terminal.t_size.h)) {
77184260Sobrien		ELRE_DEBUG(1,
772313981Spfg		    (__F, "first diff insert at %td...\r\n", nfd - new));
7731573Srgrimes		/*
77484260Sobrien		 * Move to the first char to insert, where the first diff is.
7751573Srgrimes		 */
776276881Sbapt		terminal_move_to_char(el, (int)(nfd - new));
77784260Sobrien		/*
77884260Sobrien		 * Check if we have stuff to keep at end
77984260Sobrien		 */
78084260Sobrien		if (nsb != ne) {
78184260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
78284260Sobrien			/*
78384260Sobrien		         * insert fx chars of new starting at nfd
78484260Sobrien		         */
78584260Sobrien			if (fx > 0) {
78684260Sobrien				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
78784260Sobrien				"ERROR: cannot insert in early first diff\n"));
788276881Sbapt				terminal_insertwrite(el, nfd, fx);
789237448Spfg				re_insert(el, old, (int)(ofd - old),
790276881Sbapt				    el->el_terminal.t_size.h, nfd, fx);
79184260Sobrien			}
79284260Sobrien			/*
79384260Sobrien		         * write (nsb-nfd) - fx chars of new starting at
79484260Sobrien		         * (nfd + fx)
79584260Sobrien			 */
796237448Spfg			len = (size_t) ((nsb - nfd) - fx);
797276881Sbapt			terminal_overwrite(el, (nfd + fx), len);
798237448Spfg			re__strncopy(ofd + fx, nfd + fx, len);
79984260Sobrien		} else {
80084260Sobrien			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
801237448Spfg			len = (size_t)(nsb - nfd);
802276881Sbapt			terminal_overwrite(el, nfd, len);
803237448Spfg			re__strncopy(ofd, nfd, len);
80484260Sobrien			/*
80584260Sobrien		         * Done
80684260Sobrien		         */
80784260Sobrien			return;
80884260Sobrien		}
80984260Sobrien	} else if (fx < 0) {
81084260Sobrien		ELRE_DEBUG(1,
811313981Spfg		    (__F, "first diff delete at %td...\r\n", ofd - old));
81284260Sobrien		/*
81384260Sobrien		 * move to the first char to delete where the first diff is
81484260Sobrien		 */
815276881Sbapt		terminal_move_to_char(el, (int)(ofd - old));
81684260Sobrien		/*
81784260Sobrien		 * Check if we have stuff to save
81884260Sobrien		 */
81984260Sobrien		if (osb != oe) {
82084260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
82184260Sobrien			/*
82284260Sobrien		         * fx is less than zero *always* here but we check
82384260Sobrien		         * for code symmetry
82484260Sobrien		         */
82584260Sobrien			if (fx < 0) {
82684260Sobrien				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
82784260Sobrien				    "ERROR: cannot delete in first diff\n"));
828276881Sbapt				terminal_deletechars(el, -fx);
829237448Spfg				re_delete(el, old, (int)(ofd - old),
830276881Sbapt				    el->el_terminal.t_size.h, -fx);
83184260Sobrien			}
83284260Sobrien			/*
83384260Sobrien		         * write (nsb-nfd) chars of new starting at nfd
83484260Sobrien		         */
835237448Spfg			len = (size_t) (nsb - nfd);
836276881Sbapt			terminal_overwrite(el, nfd, len);
837237448Spfg			re__strncopy(ofd, nfd, len);
8381573Srgrimes
83984260Sobrien		} else {
84084260Sobrien			ELRE_DEBUG(1, (__F,
84184260Sobrien			    "but with nothing left to save\r\n"));
84284260Sobrien			/*
84384260Sobrien		         * write (nsb-nfd) chars of new starting at nfd
84484260Sobrien		         */
845276881Sbapt			terminal_overwrite(el, nfd, (size_t)(nsb - nfd));
846237448Spfg			re_clear_eol(el, fx, sx,
847237448Spfg			    (int)((oe - old) - (ne - new)));
84884260Sobrien			/*
84984260Sobrien		         * Done
85084260Sobrien		         */
85184260Sobrien			return;
85284260Sobrien		}
85384260Sobrien	} else
85484260Sobrien		fx = 0;
8551573Srgrimes
856276881Sbapt	if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) {
85784260Sobrien		ELRE_DEBUG(1, (__F,
858313981Spfg		    "second diff delete at %td...\r\n", (ose - old) + fx));
85984260Sobrien		/*
86084260Sobrien		 * Check if we have stuff to delete
86184260Sobrien		 */
86284260Sobrien		/*
86384260Sobrien		 * fx is the number of characters inserted (+) or deleted (-)
86484260Sobrien		 */
8651573Srgrimes
866276881Sbapt		terminal_move_to_char(el, (int)((ose - old) + fx));
86784260Sobrien		/*
86884260Sobrien		 * Check if we have stuff to save
86984260Sobrien		 */
87084260Sobrien		if (ols != oe) {
87184260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
87284260Sobrien			/*
87384260Sobrien		         * Again a duplicate test.
87484260Sobrien		         */
87584260Sobrien			if (sx < 0) {
87684260Sobrien				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
87784260Sobrien				    "ERROR: cannot delete in second diff\n"));
878276881Sbapt				terminal_deletechars(el, -sx);
87984260Sobrien			}
88084260Sobrien			/*
88184260Sobrien		         * write (nls-nse) chars of new starting at nse
88284260Sobrien		         */
883276881Sbapt			terminal_overwrite(el, nse, (size_t)(nls - nse));
88484260Sobrien		} else {
88584260Sobrien			ELRE_DEBUG(1, (__F,
88684260Sobrien			    "but with nothing left to save\r\n"));
887276881Sbapt			terminal_overwrite(el, nse, (size_t)(nls - nse));
888237448Spfg			re_clear_eol(el, fx, sx,
889237448Spfg			    (int)((oe - old) - (ne - new)));
89084260Sobrien		}
8911573Srgrimes	}
89284260Sobrien	/*
89384260Sobrien         * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
89484260Sobrien         */
89584260Sobrien	if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
896313981Spfg		ELRE_DEBUG(1, (__F, "late first diff insert at %td...\r\n",
89784260Sobrien		    nfd - new));
8981573Srgrimes
899276881Sbapt		terminal_move_to_char(el, (int)(nfd - new));
90084260Sobrien		/*
90184260Sobrien		 * Check if we have stuff to keep at the end
90284260Sobrien		 */
90384260Sobrien		if (nsb != ne) {
90484260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
90584260Sobrien			/*
90684260Sobrien		         * We have to recalculate fx here because we set it
90784260Sobrien		         * to zero above as a flag saying that we hadn't done
90884260Sobrien		         * an early first insert.
90984260Sobrien		         */
910237448Spfg			fx = (int)((nsb - nfd) - (osb - ofd));
91184260Sobrien			if (fx > 0) {
91284260Sobrien				/*
91384260Sobrien				 * insert fx chars of new starting at nfd
91484260Sobrien				 */
91584260Sobrien				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
91684260Sobrien				 "ERROR: cannot insert in late first diff\n"));
917276881Sbapt				terminal_insertwrite(el, nfd, fx);
918237448Spfg				re_insert(el, old, (int)(ofd - old),
919276881Sbapt				    el->el_terminal.t_size.h, nfd, fx);
92084260Sobrien			}
92184260Sobrien			/*
92284260Sobrien		         * write (nsb-nfd) - fx chars of new starting at
92384260Sobrien		         * (nfd + fx)
92484260Sobrien			 */
925237448Spfg			len = (size_t) ((nsb - nfd) - fx);
926276881Sbapt			terminal_overwrite(el, (nfd + fx), len);
927237448Spfg			re__strncopy(ofd + fx, nfd + fx, len);
92884260Sobrien		} else {
92984260Sobrien			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
930237448Spfg			len = (size_t) (nsb - nfd);
931276881Sbapt			terminal_overwrite(el, nfd, len);
932237448Spfg			re__strncopy(ofd, nfd, len);
93384260Sobrien		}
9341573Srgrimes	}
93584260Sobrien	/*
93684260Sobrien         * line is now NEW up to nse
93784260Sobrien         */
93884260Sobrien	if (sx >= 0) {
93984260Sobrien		ELRE_DEBUG(1, (__F,
940237448Spfg		    "second diff insert at %d...\r\n", (int)(nse - new)));
941276881Sbapt		terminal_move_to_char(el, (int)(nse - new));
94284260Sobrien		if (ols != oe) {
94384260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
94484260Sobrien			if (sx > 0) {
94584260Sobrien				/* insert sx chars of new starting at nse */
94684260Sobrien				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
94784260Sobrien				    "ERROR: cannot insert in second diff\n"));
948276881Sbapt				terminal_insertwrite(el, nse, sx);
94984260Sobrien			}
95084260Sobrien			/*
95184260Sobrien		         * write (nls-nse) - sx chars of new starting at
95284260Sobrien			 * (nse + sx)
95384260Sobrien		         */
954276881Sbapt			terminal_overwrite(el, (nse + sx),
955237448Spfg			    (size_t)((nls - nse) - sx));
95684260Sobrien		} else {
95784260Sobrien			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
958276881Sbapt			terminal_overwrite(el, nse, (size_t)(nls - nse));
9591573Srgrimes
96084260Sobrien			/*
96184260Sobrien	                 * No need to do a clear-to-end here because we were
96284260Sobrien	                 * doing a second insert, so we will have over
96384260Sobrien	                 * written all of the old string.
96484260Sobrien		         */
96584260Sobrien		}
96684260Sobrien	}
96784260Sobrien	ELRE_DEBUG(1, (__F, "done.\r\n"));
96884260Sobrien}
9691573Srgrimes
97084260Sobrien
9711573Srgrimes/* re__copy_and_pad():
9721573Srgrimes *	Copy string and pad with spaces
9731573Srgrimes */
9741573Srgrimesprivate void
975276881Sbaptre__copy_and_pad(Char *dst, const Char *src, size_t width)
9761573Srgrimes{
977148834Sstefanf	size_t i;
9781573Srgrimes
97984260Sobrien	for (i = 0; i < width; i++) {
98084260Sobrien		if (*src == '\0')
98184260Sobrien			break;
98284260Sobrien		*dst++ = *src++;
98384260Sobrien	}
9841573Srgrimes
98584260Sobrien	for (; i < width; i++)
98684260Sobrien		*dst++ = ' ';
9871573Srgrimes
98884260Sobrien	*dst = '\0';
98984260Sobrien}
9901573Srgrimes
99184260Sobrien
9921573Srgrimes/* re_refresh_cursor():
9931573Srgrimes *	Move to the new cursor position
9941573Srgrimes */
9951573Srgrimesprotected void
99684260Sobrienre_refresh_cursor(EditLine *el)
9971573Srgrimes{
998276881Sbapt	Char *cp;
999276881Sbapt	int h, v, th, w;
10001573Srgrimes
1001148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar) {
1002148834Sstefanf		if (el->el_map.current == el->el_map.alt
1003148834Sstefanf		    && el->el_line.lastchar != el->el_line.buffer)
1004148834Sstefanf			el->el_line.cursor = el->el_line.lastchar - 1;
1005148834Sstefanf		else
1006148834Sstefanf			el->el_line.cursor = el->el_line.lastchar;
1007148834Sstefanf	}
1008148834Sstefanf
100984260Sobrien	/* first we must find where the cursor is... */
101084260Sobrien	h = el->el_prompt.p_pos.h;
101184260Sobrien	v = el->el_prompt.p_pos.v;
1012276881Sbapt	th = el->el_terminal.t_size.h;	/* optimize for speed */
10131573Srgrimes
101484260Sobrien	/* do input buffer to el->el_line.cursor */
101584260Sobrien	for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
1016276881Sbapt                switch (ct_chr_class(*cp)) {
1017276881Sbapt		case CHTYPE_NL:  /* handle newline in data part too */
101884260Sobrien			h = 0;
101984260Sobrien			v++;
1020237448Spfg			break;
1021276881Sbapt		case CHTYPE_TAB: /* if a tab, to next tab stop */
1022237448Spfg			while (++h & 07)
1023237448Spfg				continue;
1024237448Spfg			break;
1025237448Spfg		default:
1026276881Sbapt			w = Width(*cp);
1027276881Sbapt			if (w > 1 && h + w > th) { /* won't fit on line */
1028276881Sbapt				h = 0;
1029276881Sbapt				v++;
1030276881Sbapt			}
1031276881Sbapt			h += ct_visual_width(*cp);
1032237448Spfg			break;
1033276881Sbapt                }
103484260Sobrien
103584260Sobrien		if (h >= th) {	/* check, extra long tabs picked up here also */
1036237448Spfg			h -= th;
103784260Sobrien			v++;
10381573Srgrimes		}
10391573Srgrimes	}
1040276881Sbapt        /* if we have a next character, and it's a doublewidth one, we need to
1041276881Sbapt         * check whether we need to linebreak for it to fit */
1042276881Sbapt        if (cp < el->el_line.lastchar && (w = Width(*cp)) > 1)
1043276881Sbapt                if (h + w > th) {
1044276881Sbapt                    h = 0;
1045276881Sbapt                    v++;
1046276881Sbapt                }
10471573Srgrimes
104884260Sobrien	/* now go there */
1049276881Sbapt	terminal_move_to_line(el, v);
1050276881Sbapt	terminal_move_to_char(el, h);
1051276881Sbapt	terminal__flush(el);
105284260Sobrien}
10531573Srgrimes
10541573Srgrimes
10551573Srgrimes/* re_fastputc():
10561573Srgrimes *	Add a character fast.
10571573Srgrimes */
10581573Srgrimesprivate void
1059313981Spfgre_fastputc(EditLine *el, wint_t c)
10601573Srgrimes{
1061276881Sbapt	int w = Width((Char)c);
1062276881Sbapt	while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h)
1063276881Sbapt	    re_fastputc(el, ' ');
10641573Srgrimes
1065276881Sbapt	terminal__putc(el, c);
1066313981Spfg	el->el_display[el->el_cursor.v][el->el_cursor.h++] = (Char)c;
1067276881Sbapt	while (--w > 0)
1068276881Sbapt		el->el_display[el->el_cursor.v][el->el_cursor.h++]
1069276881Sbapt			= MB_FILL_CHAR;
1070276881Sbapt
1071276881Sbapt	if (el->el_cursor.h >= el->el_terminal.t_size.h) {
107284260Sobrien		/* if we must overflow */
107384260Sobrien		el->el_cursor.h = 0;
10741573Srgrimes
107584260Sobrien		/*
107684260Sobrien		 * If we would overflow (input is longer than terminal size),
107784260Sobrien		 * emulate scroll by dropping first line and shuffling the rest.
107884260Sobrien		 * We do this via pointer shuffling - it's safe in this case
107984260Sobrien		 * and we avoid memcpy().
108084260Sobrien		 */
1081276881Sbapt		if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) {
1082276881Sbapt			int i, lins = el->el_terminal.t_size.v;
1083276881Sbapt			Char *firstline = el->el_display[0];
1084313981Spfg
1085237448Spfg			for(i = 1; i < lins; i++)
1086237448Spfg				el->el_display[i - 1] = el->el_display[i];
108784260Sobrien
1088276881Sbapt			re__copy_and_pad(firstline, STR(""), (size_t)0);
1089237448Spfg			el->el_display[i - 1] = firstline;
109084260Sobrien		} else {
109184260Sobrien			el->el_cursor.v++;
109284260Sobrien			el->el_refresh.r_oldcv++;
109384260Sobrien		}
109484260Sobrien		if (EL_HAS_AUTO_MARGINS) {
109584260Sobrien			if (EL_HAS_MAGIC_MARGINS) {
1096276881Sbapt				terminal__putc(el, ' ');
1097276881Sbapt				terminal__putc(el, '\b');
109884260Sobrien			}
109984260Sobrien		} else {
1100276881Sbapt			terminal__putc(el, '\r');
1101276881Sbapt			terminal__putc(el, '\n');
110284260Sobrien		}
110384260Sobrien	}
110484260Sobrien}
110584260Sobrien
110684260Sobrien
11071573Srgrimes/* re_fastaddc():
11081573Srgrimes *	we added just one char, handle it fast.
11098870Srgrimes *	Assumes that screen cursor == real cursor
11101573Srgrimes */
11111573Srgrimesprotected void
111284260Sobrienre_fastaddc(EditLine *el)
11131573Srgrimes{
1114276881Sbapt	Char c;
111584260Sobrien	int rhdiff;
11161573Srgrimes
1117276881Sbapt	c = el->el_line.cursor[-1];
11181573Srgrimes
111984260Sobrien	if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
112084260Sobrien		re_refresh(el);	/* too hard to handle */
112184260Sobrien		return;
112284260Sobrien	}
1123276881Sbapt	rhdiff = el->el_terminal.t_size.h - el->el_cursor.h -
112484260Sobrien	    el->el_rprompt.p_pos.h;
112584260Sobrien	if (el->el_rprompt.p_pos.h && rhdiff < 3) {
112684260Sobrien		re_refresh(el);	/* clear out rprompt if less than 1 char gap */
112784260Sobrien		return;
112884260Sobrien	}			/* else (only do at end of line, no TAB) */
1129276881Sbapt	switch (ct_chr_class(c)) {
1130276881Sbapt	case CHTYPE_TAB: /* already handled, should never happen here */
1131276881Sbapt		break;
1132276881Sbapt	case CHTYPE_NL:
1133276881Sbapt	case CHTYPE_PRINT:
113484260Sobrien		re_fastputc(el, c);
1135276881Sbapt		break;
1136276881Sbapt	case CHTYPE_ASCIICTL:
1137276881Sbapt	case CHTYPE_NONPRINT: {
1138276881Sbapt		Char visbuf[VISUAL_WIDTH_MAX];
1139276881Sbapt		ssize_t i, n =
1140276881Sbapt		    ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c);
1141276881Sbapt		for (i = 0; n-- > 0; ++i)
1142276881Sbapt			re_fastputc(el, visbuf[i]);
1143276881Sbapt		break;
114484260Sobrien	}
1145276881Sbapt	}
1146276881Sbapt	terminal__flush(el);
114784260Sobrien}
11481573Srgrimes
11491573Srgrimes
11501573Srgrimes/* re_clear_display():
1151330446Seadler *	clear the screen buffers so that new prompt starts fresh.
11521573Srgrimes */
11531573Srgrimesprotected void
115484260Sobrienre_clear_display(EditLine *el)
11551573Srgrimes{
115684260Sobrien	int i;
11571573Srgrimes
115884260Sobrien	el->el_cursor.v = 0;
115984260Sobrien	el->el_cursor.h = 0;
1160276881Sbapt	for (i = 0; i < el->el_terminal.t_size.v; i++)
116184260Sobrien		el->el_display[i][0] = '\0';
116284260Sobrien	el->el_refresh.r_oldcv = 0;
116384260Sobrien}
11641573Srgrimes
11651573Srgrimes
11661573Srgrimes/* re_clear_lines():
11678870Srgrimes *	Make sure all lines are *really* blank
11681573Srgrimes */
11691573Srgrimesprotected void
117084260Sobrienre_clear_lines(EditLine *el)
11711573Srgrimes{
117284260Sobrien
117384260Sobrien	if (EL_CAN_CEOL) {
117484260Sobrien		int i;
1175237448Spfg		for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
117684260Sobrien			/* for each line on the screen */
1177276881Sbapt			terminal_move_to_line(el, i);
1178276881Sbapt			terminal_move_to_char(el, 0);
1179276881Sbapt			terminal_clear_EOL(el, el->el_terminal.t_size.h);
118084260Sobrien		}
118184260Sobrien	} else {
1182276881Sbapt		terminal_move_to_line(el, el->el_refresh.r_oldcv);
118384260Sobrien					/* go to last line */
1184276881Sbapt		terminal__putc(el, '\r');	/* go to BOL */
1185276881Sbapt		terminal__putc(el, '\n');	/* go to new line */
11861573Srgrimes	}
118784260Sobrien}
1188