11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1992, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Christos Zoulas of Cornell University.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
16148834Sstefanf * 3. Neither the name of the University nor the names of its contributors
171573Srgrimes *    may be used to endorse or promote products derived from this software
181573Srgrimes *    without specific prior written permission.
191573Srgrimes *
201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
3184260Sobrien *
32237448Spfg *	$NetBSD: refresh.c,v 1.34 2009/12/28 22:15:36 christos Exp $
331573Srgrimes */
341573Srgrimes
351573Srgrimes#if !defined(lint) && !defined(SCCSID)
361573Srgrimesstatic char sccsid[] = "@(#)refresh.c	8.1 (Berkeley) 6/4/93";
371573Srgrimes#endif /* not lint && not SCCSID */
3884260Sobrien#include <sys/cdefs.h>
3984260Sobrien__FBSDID("$FreeBSD$");
401573Srgrimes
411573Srgrimes/*
421573Srgrimes * refresh.c: Lower level screen refreshing functions
431573Srgrimes */
441573Srgrimes#include "sys.h"
451573Srgrimes#include <stdio.h>
46148834Sstefanf#include <ctype.h>
471573Srgrimes#include <unistd.h>
481573Srgrimes#include <string.h>
491573Srgrimes
501573Srgrimes#include "el.h"
511573Srgrimes
52237448Spfgprivate void	re_nextline(EditLine *);
5384260Sobrienprivate void	re_addc(EditLine *, int);
5484260Sobrienprivate void	re_update_line(EditLine *, char *, char *, int);
5584260Sobrienprivate void	re_insert (EditLine *, char *, int, int, char *, int);
5684260Sobrienprivate void	re_delete(EditLine *, char *, int, int, int);
5784260Sobrienprivate void	re_fastputc(EditLine *, int);
58153079Sstefanfprivate void	re_clear_eol(EditLine *, int, int, int);
5984260Sobrienprivate void	re__strncopy(char *, char *, size_t);
60148834Sstefanfprivate void	re__copy_and_pad(char *, const char *, size_t);
611573Srgrimes
621573Srgrimes#ifdef DEBUG_REFRESH
63148834Sstefanfprivate void	re_printstr(EditLine *, const char *, char *, char *);
6484260Sobrien#define	__F el->el_errfile
6584260Sobrien#define	ELRE_ASSERT(a, b, c)	do 				\
66148834Sstefanf				    if (/*CONSTCOND*/ a) {	\
671573Srgrimes					(void) fprintf b;	\
681573Srgrimes					c;			\
691573Srgrimes				    }				\
70148834Sstefanf				while (/*CONSTCOND*/0)
7184260Sobrien#define	ELRE_DEBUG(a, b)	ELRE_ASSERT(a,b,;)
7284260Sobrien
731573Srgrimes/* re_printstr():
741573Srgrimes *	Print a string on the debugging pty
751573Srgrimes */
761573Srgrimesprivate void
77148834Sstefanfre_printstr(EditLine *el, const char *str, char *f, char *t)
781573Srgrimes{
7984260Sobrien
8084260Sobrien	ELRE_DEBUG(1, (__F, "%s:\"", str));
8184260Sobrien	while (f < t)
8284260Sobrien		ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
8384260Sobrien	ELRE_DEBUG(1, (__F, "\"\r\n"));
848870Srgrimes}
851573Srgrimes#else
8684260Sobrien#define	ELRE_ASSERT(a, b, c)
8784260Sobrien#define	ELRE_DEBUG(a, b)
881573Srgrimes#endif
891573Srgrimes
90237448Spfg/* re_nextline():
91237448Spfg *	Move to the next line or scroll
92237448Spfg */
93237448Spfgprivate void
94237448Spfgre_nextline(EditLine *el)
95237448Spfg{
96237448Spfg	el->el_refresh.r_cursor.h = 0;	/* reset it. */
971573Srgrimes
98237448Spfg	/*
99237448Spfg	 * If we would overflow (input is longer than terminal size),
100237448Spfg	 * emulate scroll by dropping first line and shuffling the rest.
101237448Spfg	 * We do this via pointer shuffling - it's safe in this case
102237448Spfg	 * and we avoid memcpy().
103237448Spfg	 */
104237448Spfg	if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) {
105237448Spfg		int i, lins = el->el_term.t_size.v;
106237448Spfg		char *firstline = el->el_vdisplay[0];
107237448Spfg
108237448Spfg		for(i = 1; i < lins; i++)
109237448Spfg			el->el_vdisplay[i - 1] = el->el_vdisplay[i];
110237448Spfg
111237448Spfg		firstline[0] = '\0';		/* empty the string */
112237448Spfg		el->el_vdisplay[i - 1] = firstline;
113237448Spfg	} else
114237448Spfg		el->el_refresh.r_cursor.v++;
115237448Spfg
116237448Spfg	ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,
117237448Spfg	    (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
118237448Spfg	    el->el_refresh.r_cursor.v, el->el_term.t_size.v),
119237448Spfg	    abort());
120237448Spfg}
121237448Spfg
1221573Srgrimes/* re_addc():
1231573Srgrimes *	Draw c, expanding tabs, control chars etc.
1241573Srgrimes */
1251573Srgrimesprivate void
12684260Sobrienre_addc(EditLine *el, int c)
1271573Srgrimes{
12817524Sache
12984260Sobrien	if (isprint(c)) {
13084260Sobrien		re_putc(el, c, 1);
13184260Sobrien		return;
1321573Srgrimes	}
13384260Sobrien	if (c == '\n') {				/* expand the newline */
13484260Sobrien		int oldv = el->el_refresh.r_cursor.v;
13584260Sobrien		re_putc(el, '\0', 0);			/* assure end of line */
136237448Spfg		if (oldv == el->el_refresh.r_cursor.v)	/* XXX */
137237448Spfg			re_nextline(el);
13884260Sobrien		return;
13984260Sobrien	}
14084260Sobrien	if (c == '\t') {				/* expand the tab */
14184260Sobrien		for (;;) {
14284260Sobrien			re_putc(el, ' ', 1);
14384260Sobrien			if ((el->el_refresh.r_cursor.h & 07) == 0)
14484260Sobrien				break;			/* go until tab stop */
14584260Sobrien		}
14684260Sobrien	} else if (iscntrl(c)) {
14784260Sobrien		re_putc(el, '^', 1);
14884260Sobrien		if (c == 0177)
14984260Sobrien			re_putc(el, '?', 1);
15084260Sobrien		else
15184260Sobrien		    /* uncontrolify it; works only for iso8859-1 like sets */
15284260Sobrien			re_putc(el, (toascii(c) | 0100), 1);
15384260Sobrien	} else {
15484260Sobrien		re_putc(el, '\\', 1);
15584260Sobrien		re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1);
15684260Sobrien		re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1);
15784260Sobrien		re_putc(el, (c & 07) + '0', 1);
15884260Sobrien	}
15984260Sobrien}
1601573Srgrimes
1611573Srgrimes
1621573Srgrimes/* re_putc():
1631573Srgrimes *	Draw the character given
1641573Srgrimes */
1651573Srgrimesprotected void
16684260Sobrienre_putc(EditLine *el, int c, int shift)
1671573Srgrimes{
1681573Srgrimes
16984260Sobrien	ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c));
1701573Srgrimes
17184260Sobrien	el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c;
17284260Sobrien	if (!shift)
17384260Sobrien		return;
1741573Srgrimes
17584260Sobrien	el->el_refresh.r_cursor.h++;	/* advance to next place */
17684260Sobrien	if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) {
17784260Sobrien		/* assure end of line */
178237448Spfg		el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h]
179237448Spfg		    = '\0';
180237448Spfg		re_nextline(el);
181237448Spfg	}
18284260Sobrien
18384260Sobrien}
18484260Sobrien
18584260Sobrien
1861573Srgrimes/* re_refresh():
1871573Srgrimes *	draws the new virtual screen image from the current input
1881573Srgrimes *  	line, then goes line-by-line changing the real image to the new
1891573Srgrimes *	virtual image. The routine to re-draw a line can be replaced
1901573Srgrimes *	easily in hopes of a smarter one being placed there.
1911573Srgrimes */
1921573Srgrimesprotected void
19384260Sobrienre_refresh(EditLine *el)
1941573Srgrimes{
19584260Sobrien	int i, rhdiff;
19684260Sobrien	char *cp, *st;
19784260Sobrien	coord_t cur;
19884260Sobrien#ifdef notyet
19984260Sobrien	size_t termsz;
20084260Sobrien#endif
2011573Srgrimes
20284260Sobrien	ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n",
20384260Sobrien	    el->el_line.buffer));
2041573Srgrimes
20584260Sobrien	/* reset the Drawing cursor */
20684260Sobrien	el->el_refresh.r_cursor.h = 0;
20784260Sobrien	el->el_refresh.r_cursor.v = 0;
2081573Srgrimes
20984260Sobrien	/* temporarily draw rprompt to calculate its size */
21084260Sobrien	prompt_print(el, EL_RPROMPT);
2111573Srgrimes
21284260Sobrien	/* reset the Drawing cursor */
21384260Sobrien	el->el_refresh.r_cursor.h = 0;
21484260Sobrien	el->el_refresh.r_cursor.v = 0;
2151573Srgrimes
216148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar) {
217148834Sstefanf		if (el->el_map.current == el->el_map.alt
218148834Sstefanf		    && el->el_line.lastchar != el->el_line.buffer)
219148834Sstefanf			el->el_line.cursor = el->el_line.lastchar - 1;
220148834Sstefanf		else
221148834Sstefanf			el->el_line.cursor = el->el_line.lastchar;
222148834Sstefanf	}
223148834Sstefanf
22484260Sobrien	cur.h = -1;		/* set flag in case I'm not set */
22584260Sobrien	cur.v = 0;
22684260Sobrien
22784260Sobrien	prompt_print(el, EL_PROMPT);
22884260Sobrien
22984260Sobrien	/* draw the current input buffer */
23084260Sobrien#if notyet
23184260Sobrien	termsz = el->el_term.t_size.h * el->el_term.t_size.v;
23284260Sobrien	if (el->el_line.lastchar - el->el_line.buffer > termsz) {
23384260Sobrien		/*
23484260Sobrien		 * If line is longer than terminal, process only part
23584260Sobrien		 * of line which would influence display.
23684260Sobrien		 */
23784260Sobrien		size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
23884260Sobrien
23984260Sobrien		st = el->el_line.lastchar - rem
24084260Sobrien			- (termsz - (((rem / el->el_term.t_size.v) - 1)
24184260Sobrien					* el->el_term.t_size.v));
24284260Sobrien	} else
24384260Sobrien#endif
24484260Sobrien		st = el->el_line.buffer;
24584260Sobrien
24684260Sobrien	for (cp = st; cp < el->el_line.lastchar; cp++) {
24784260Sobrien		if (cp == el->el_line.cursor) {
24884260Sobrien			/* save for later */
24984260Sobrien			cur.h = el->el_refresh.r_cursor.h;
25084260Sobrien			cur.v = el->el_refresh.r_cursor.v;
25184260Sobrien		}
25284260Sobrien		re_addc(el, (unsigned char) *cp);
2531573Srgrimes	}
2541573Srgrimes
25584260Sobrien	if (cur.h == -1) {	/* if I haven't been set yet, I'm at the end */
25684260Sobrien		cur.h = el->el_refresh.r_cursor.h;
25784260Sobrien		cur.v = el->el_refresh.r_cursor.v;
25884260Sobrien	}
25984260Sobrien	rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h -
26084260Sobrien	    el->el_rprompt.p_pos.h;
26184260Sobrien	if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
26284260Sobrien	    !el->el_refresh.r_cursor.v && rhdiff > 1) {
26384260Sobrien		/*
26484260Sobrien		 * have a right-hand side prompt that will fit
26584260Sobrien		 * on the end of the first line with at least
26684260Sobrien		 * one character gap to the input buffer.
26784260Sobrien		 */
26884260Sobrien		while (--rhdiff > 0)	/* pad out with spaces */
26984260Sobrien			re_putc(el, ' ', 1);
27084260Sobrien		prompt_print(el, EL_RPROMPT);
27184260Sobrien	} else {
27284260Sobrien		el->el_rprompt.p_pos.h = 0;	/* flag "not using rprompt" */
27384260Sobrien		el->el_rprompt.p_pos.v = 0;
27484260Sobrien	}
2751573Srgrimes
27684260Sobrien	re_putc(el, '\0', 0);	/* make line ended with NUL, no cursor shift */
2771573Srgrimes
27884260Sobrien	el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
2791573Srgrimes
28084260Sobrien	ELRE_DEBUG(1, (__F,
28184260Sobrien		"term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
28284260Sobrien		el->el_term.t_size.h, el->el_refresh.r_cursor.h,
28384260Sobrien		el->el_refresh.r_cursor.v, el->el_vdisplay[0]));
2841573Srgrimes
28584260Sobrien	ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
28684260Sobrien	for (i = 0; i <= el->el_refresh.r_newcv; i++) {
28784260Sobrien		/* NOTE THAT re_update_line MAY CHANGE el_display[i] */
28884260Sobrien		re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
28984260Sobrien
29084260Sobrien		/*
29184260Sobrien		 * Copy the new line to be the current one, and pad out with
29284260Sobrien		 * spaces to the full width of the terminal so that if we try
29384260Sobrien		 * moving the cursor by writing the character that is at the
29484260Sobrien		 * end of the screen line, it won't be a NUL or some old
29584260Sobrien		 * leftover stuff.
29684260Sobrien		 */
29784260Sobrien		re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
29884260Sobrien		    (size_t) el->el_term.t_size.h);
29984260Sobrien	}
30084260Sobrien	ELRE_DEBUG(1, (__F,
30184260Sobrien	"\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
30284260Sobrien	    el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
30384260Sobrien
30484260Sobrien	if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
30584260Sobrien		for (; i <= el->el_refresh.r_oldcv; i++) {
30684260Sobrien			term_move_to_line(el, i);
30784260Sobrien			term_move_to_char(el, 0);
30884260Sobrien			term_clear_EOL(el, (int) strlen(el->el_display[i]));
3091573Srgrimes#ifdef DEBUG_REFRESH
310237448Spfg			term_overwrite(el, "C\b", (size_t)2);
3111573Srgrimes#endif /* DEBUG_REFRESH */
31284260Sobrien			el->el_display[i][0] = '\0';
31384260Sobrien		}
3148870Srgrimes
31584260Sobrien	el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
31684260Sobrien	ELRE_DEBUG(1, (__F,
31784260Sobrien	    "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
31884260Sobrien	    el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
31984260Sobrien	    cur.h, cur.v));
32084260Sobrien	term_move_to_line(el, cur.v);	/* go to where the cursor is */
32184260Sobrien	term_move_to_char(el, cur.h);
32284260Sobrien}
3231573Srgrimes
3241573Srgrimes
3251573Srgrimes/* re_goto_bottom():
3268870Srgrimes *	 used to go to last used screen line
3271573Srgrimes */
3281573Srgrimesprotected void
32984260Sobrienre_goto_bottom(EditLine *el)
3301573Srgrimes{
3311573Srgrimes
33284260Sobrien	term_move_to_line(el, el->el_refresh.r_oldcv);
333237448Spfg	term__putc(el, '\n');
33484260Sobrien	re_clear_display(el);
335237448Spfg	term__flush(el);
33684260Sobrien}
3371573Srgrimes
33884260Sobrien
3391573Srgrimes/* re_insert():
3401573Srgrimes *	insert num characters of s into d (in front of the character)
3418870Srgrimes *	at dat, maximum length of d is dlen
3421573Srgrimes */
3431573Srgrimesprivate void
3441573Srgrimes/*ARGSUSED*/
345148834Sstefanfre_insert(EditLine *el __unused,
346148834Sstefanf    char *d, int dat, int dlen, char *s, int num)
3471573Srgrimes{
34884260Sobrien	char *a, *b;
3491573Srgrimes
35084260Sobrien	if (num <= 0)
35184260Sobrien		return;
35284260Sobrien	if (num > dlen - dat)
35384260Sobrien		num = dlen - dat;
3541573Srgrimes
35584260Sobrien	ELRE_DEBUG(1,
35684260Sobrien	    (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
35784260Sobrien	    num, dat, dlen, d));
358153079Sstefanf	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
3591573Srgrimes
36084260Sobrien	/* open up the space for num chars */
36184260Sobrien	if (num > 0) {
36284260Sobrien		b = d + dlen - 1;
36384260Sobrien		a = b - num;
36484260Sobrien		while (a >= &d[dat])
36584260Sobrien			*b-- = *a--;
36684260Sobrien		d[dlen] = '\0';	/* just in case */
36784260Sobrien	}
36884260Sobrien	ELRE_DEBUG(1, (__F,
3691573Srgrimes		"re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
37084260Sobrien		num, dat, dlen, d));
371153079Sstefanf	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
3721573Srgrimes
37384260Sobrien	/* copy the characters */
37484260Sobrien	for (a = d + dat; (a < d + dlen) && (num > 0); num--)
37584260Sobrien		*a++ = *s++;
3761573Srgrimes
37784260Sobrien	ELRE_DEBUG(1,
37884260Sobrien	    (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
37984260Sobrien	    num, dat, dlen, d, s));
380153079Sstefanf	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
38184260Sobrien}
3821573Srgrimes
3831573Srgrimes
3841573Srgrimes/* re_delete():
3858870Srgrimes *	delete num characters d at dat, maximum length of d is dlen
3861573Srgrimes */
3871573Srgrimesprivate void
3881573Srgrimes/*ARGSUSED*/
389148834Sstefanfre_delete(EditLine *el __unused,
390148834Sstefanf    char *d, int dat, int dlen, int num)
3911573Srgrimes{
39284260Sobrien	char *a, *b;
3931573Srgrimes
39484260Sobrien	if (num <= 0)
39584260Sobrien		return;
39684260Sobrien	if (dat + num >= dlen) {
39784260Sobrien		d[dat] = '\0';
39884260Sobrien		return;
39984260Sobrien	}
40084260Sobrien	ELRE_DEBUG(1,
40184260Sobrien	    (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
40284260Sobrien	    num, dat, dlen, d));
4031573Srgrimes
40484260Sobrien	/* open up the space for num chars */
40584260Sobrien	if (num > 0) {
40684260Sobrien		b = d + dat;
40784260Sobrien		a = b + num;
40884260Sobrien		while (a < &d[dlen])
40984260Sobrien			*b++ = *a++;
41084260Sobrien		d[dlen] = '\0';	/* just in case */
41184260Sobrien	}
41284260Sobrien	ELRE_DEBUG(1,
41384260Sobrien	    (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
41484260Sobrien	    num, dat, dlen, d));
41584260Sobrien}
4161573Srgrimes
4171573Srgrimes
4181573Srgrimes/* re__strncopy():
4191573Srgrimes *	Like strncpy without padding.
4201573Srgrimes */
4211573Srgrimesprivate void
42284260Sobrienre__strncopy(char *a, char *b, size_t n)
4231573Srgrimes{
4241573Srgrimes
42584260Sobrien	while (n-- && *b)
42684260Sobrien		*a++ = *b++;
42784260Sobrien}
4281573Srgrimes
429153079Sstefanf/* re_clear_eol():
430153079Sstefanf *	Find the number of characters we need to clear till the end of line
431153079Sstefanf *	in order to make sure that we have cleared the previous contents of
432153079Sstefanf *	the line. fx and sx is the number of characters inserted or deleted
433153079Sstefanf *	int the first or second diff, diff is the difference between the
434153079Sstefanf * 	number of characters between the new and old line.
435153079Sstefanf */
436153079Sstefanfprivate void
437153079Sstefanfre_clear_eol(EditLine *el, int fx, int sx, int diff)
438153079Sstefanf{
43984260Sobrien
440153079Sstefanf	ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
441153079Sstefanf	    sx, fx, diff));
442153079Sstefanf
443153079Sstefanf	if (fx < 0)
444153079Sstefanf		fx = -fx;
445153079Sstefanf	if (sx < 0)
446153079Sstefanf		sx = -sx;
447153079Sstefanf	if (fx > diff)
448153079Sstefanf		diff = fx;
449153079Sstefanf	if (sx > diff)
450153079Sstefanf		diff = sx;
451153079Sstefanf
452153079Sstefanf	ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
453153079Sstefanf	term_clear_EOL(el, diff);
454153079Sstefanf}
455153079Sstefanf
45684260Sobrien/*****************************************************************
4571573Srgrimes    re_update_line() is based on finding the middle difference of each line
4581573Srgrimes    on the screen; vis:
4591573Srgrimes
4601573Srgrimes			     /old first difference
4611573Srgrimes	/beginning of line   |              /old last same       /old EOL
4621573Srgrimes	v		     v              v                    v
4631573Srgrimesold:	eddie> Oh, my little gruntle-buggy is to me, as lurgid as
4641573Srgrimesnew:	eddie> Oh, my little buggy says to me, as lurgid as
4651573Srgrimes	^		     ^        ^			   ^
4661573Srgrimes	\beginning of line   |        \new last same	   \new end of line
4671573Srgrimes			     \new first difference
4681573Srgrimes
4691573Srgrimes    all are character pointers for the sake of speed.  Special cases for
4701573Srgrimes    no differences, as well as for end of line additions must be handled.
4711573Srgrimes**************************************************************** */
4721573Srgrimes
4731573Srgrimes/* Minimum at which doing an insert it "worth it".  This should be about
4741573Srgrimes * half the "cost" of going into insert mode, inserting a character, and
4751573Srgrimes * going back out.  This should really be calculated from the termcap
4761573Srgrimes * data...  For the moment, a good number for ANSI terminals.
4771573Srgrimes */
47884260Sobrien#define	MIN_END_KEEP	4
4791573Srgrimes
4801573Srgrimesprivate void
48184260Sobrienre_update_line(EditLine *el, char *old, char *new, int i)
4821573Srgrimes{
48384260Sobrien	char *o, *n, *p, c;
48484260Sobrien	char *ofd, *ols, *oe, *nfd, *nls, *ne;
48584260Sobrien	char *osb, *ose, *nsb, *nse;
48684260Sobrien	int fx, sx;
487237448Spfg	size_t len;
4881573Srgrimes
48984260Sobrien	/*
49084260Sobrien         * find first diff
49184260Sobrien         */
49284260Sobrien	for (o = old, n = new; *o && (*o == *n); o++, n++)
49384260Sobrien		continue;
49484260Sobrien	ofd = o;
49584260Sobrien	nfd = n;
4961573Srgrimes
49784260Sobrien	/*
49884260Sobrien         * Find the end of both old and new
49984260Sobrien         */
50084260Sobrien	while (*o)
50184260Sobrien		o++;
50284260Sobrien	/*
50384260Sobrien         * Remove any trailing blanks off of the end, being careful not to
50484260Sobrien         * back up past the beginning.
50584260Sobrien         */
50684260Sobrien	while (ofd < o) {
50784260Sobrien		if (o[-1] != ' ')
50884260Sobrien			break;
50984260Sobrien		o--;
51084260Sobrien	}
51184260Sobrien	oe = o;
51284260Sobrien	*oe = '\0';
5138870Srgrimes
51484260Sobrien	while (*n)
51584260Sobrien		n++;
5161573Srgrimes
51784260Sobrien	/* remove blanks from end of new */
51884260Sobrien	while (nfd < n) {
51984260Sobrien		if (n[-1] != ' ')
52084260Sobrien			break;
52184260Sobrien		n--;
5221573Srgrimes	}
52384260Sobrien	ne = n;
52484260Sobrien	*ne = '\0';
5251573Srgrimes
52684260Sobrien	/*
52784260Sobrien         * if no diff, continue to next line of redraw
52884260Sobrien         */
52984260Sobrien	if (*ofd == '\0' && *nfd == '\0') {
53084260Sobrien		ELRE_DEBUG(1, (__F, "no difference.\r\n"));
53184260Sobrien		return;
5321573Srgrimes	}
53384260Sobrien	/*
53484260Sobrien         * find last same pointer
53584260Sobrien         */
53684260Sobrien	while ((o > ofd) && (n > nfd) && (*--o == *--n))
53784260Sobrien		continue;
53884260Sobrien	ols = ++o;
53984260Sobrien	nls = ++n;
5401573Srgrimes
54184260Sobrien	/*
54284260Sobrien         * find same begining and same end
54384260Sobrien         */
5441573Srgrimes	osb = ols;
54584260Sobrien	nsb = nls;
5461573Srgrimes	ose = ols;
5471573Srgrimes	nse = nls;
5481573Srgrimes
5491573Srgrimes	/*
55084260Sobrien         * case 1: insert: scan from nfd to nls looking for *ofd
55184260Sobrien         */
55284260Sobrien	if (*ofd) {
55384260Sobrien		for (c = *ofd, n = nfd; n < nls; n++) {
55484260Sobrien			if (c == *n) {
55584260Sobrien				for (o = ofd, p = n;
55684260Sobrien				    p < nls && o < ols && *o == *p;
55784260Sobrien				    o++, p++)
55884260Sobrien					continue;
55984260Sobrien				/*
56084260Sobrien				 * if the new match is longer and it's worth
56184260Sobrien				 * keeping, then we take it
56284260Sobrien				 */
56384260Sobrien				if (((nse - nsb) < (p - n)) &&
56484260Sobrien				    (2 * (p - n) > n - nfd)) {
56584260Sobrien					nsb = n;
56684260Sobrien					nse = p;
56784260Sobrien					osb = ofd;
56884260Sobrien					ose = o;
56984260Sobrien				}
57084260Sobrien			}
57184260Sobrien		}
57284260Sobrien	}
5731573Srgrimes	/*
57484260Sobrien         * case 2: delete: scan from ofd to ols looking for *nfd
57584260Sobrien         */
57684260Sobrien	if (*nfd) {
57784260Sobrien		for (c = *nfd, o = ofd; o < ols; o++) {
57884260Sobrien			if (c == *o) {
57984260Sobrien				for (n = nfd, p = o;
58084260Sobrien				    p < ols && n < nls && *p == *n;
58184260Sobrien				    p++, n++)
58284260Sobrien					continue;
58384260Sobrien				/*
58484260Sobrien				 * if the new match is longer and it's worth
58584260Sobrien				 * keeping, then we take it
58684260Sobrien				 */
58784260Sobrien				if (((ose - osb) < (p - o)) &&
58884260Sobrien				    (2 * (p - o) > o - ofd)) {
58984260Sobrien					nsb = nfd;
59084260Sobrien					nse = n;
59184260Sobrien					osb = o;
59284260Sobrien					ose = p;
59384260Sobrien				}
59484260Sobrien			}
59584260Sobrien		}
5961573Srgrimes	}
59784260Sobrien	/*
59884260Sobrien         * Pragmatics I: If old trailing whitespace or not enough characters to
59984260Sobrien         * save to be worth it, then don't save the last same info.
60084260Sobrien         */
60184260Sobrien	if ((oe - ols) < MIN_END_KEEP) {
60284260Sobrien		ols = oe;
60384260Sobrien		nls = ne;
6041573Srgrimes	}
6051573Srgrimes	/*
60684260Sobrien         * Pragmatics II: if the terminal isn't smart enough, make the data
60784260Sobrien         * dumber so the smart update doesn't try anything fancy
60884260Sobrien         */
60984260Sobrien
6101573Srgrimes	/*
61184260Sobrien         * fx is the number of characters we need to insert/delete: in the
61284260Sobrien         * beginning to bring the two same begins together
61384260Sobrien         */
614237448Spfg	fx = (int)((nsb - nfd) - (osb - ofd));
61584260Sobrien	/*
61684260Sobrien         * sx is the number of characters we need to insert/delete: in the
61784260Sobrien         * end to bring the two same last parts together
61884260Sobrien         */
619237448Spfg	sx = (int)((nls - nse) - (ols - ose));
6201573Srgrimes
62184260Sobrien	if (!EL_CAN_INSERT) {
62284260Sobrien		if (fx > 0) {
62384260Sobrien			osb = ols;
62484260Sobrien			ose = ols;
62584260Sobrien			nsb = nls;
62684260Sobrien			nse = nls;
62784260Sobrien		}
62884260Sobrien		if (sx > 0) {
62984260Sobrien			ols = oe;
63084260Sobrien			nls = ne;
63184260Sobrien		}
63284260Sobrien		if ((ols - ofd) < (nls - nfd)) {
63384260Sobrien			ols = oe;
63484260Sobrien			nls = ne;
63584260Sobrien		}
6361573Srgrimes	}
63784260Sobrien	if (!EL_CAN_DELETE) {
63884260Sobrien		if (fx < 0) {
63984260Sobrien			osb = ols;
64084260Sobrien			ose = ols;
64184260Sobrien			nsb = nls;
64284260Sobrien			nse = nls;
64384260Sobrien		}
64484260Sobrien		if (sx < 0) {
64584260Sobrien			ols = oe;
64684260Sobrien			nls = ne;
64784260Sobrien		}
64884260Sobrien		if ((ols - ofd) > (nls - nfd)) {
64984260Sobrien			ols = oe;
65084260Sobrien			nls = ne;
65184260Sobrien		}
6521573Srgrimes	}
6531573Srgrimes	/*
65484260Sobrien         * Pragmatics III: make sure the middle shifted pointers are correct if
65584260Sobrien         * they don't point to anything (we may have moved ols or nls).
65684260Sobrien         */
65784260Sobrien	/* if the change isn't worth it, don't bother */
65884260Sobrien	/* was: if (osb == ose) */
65984260Sobrien	if ((ose - osb) < MIN_END_KEEP) {
66084260Sobrien		osb = ols;
66184260Sobrien		ose = ols;
66284260Sobrien		nsb = nls;
66384260Sobrien		nse = nls;
66484260Sobrien	}
6651573Srgrimes	/*
66684260Sobrien         * Now that we are done with pragmatics we recompute fx, sx
66784260Sobrien         */
668237448Spfg	fx = (int)((nsb - nfd) - (osb - ofd));
669237448Spfg	sx = (int)((nls - nse) - (ols - ose));
6701573Srgrimes
671153079Sstefanf	ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
67284260Sobrien	ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
67384260Sobrien		ofd - old, osb - old, ose - old, ols - old, oe - old));
67484260Sobrien	ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
67584260Sobrien		nfd - new, nsb - new, nse - new, nls - new, ne - new));
67684260Sobrien	ELRE_DEBUG(1, (__F,
67784260Sobrien		"xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
67884260Sobrien	ELRE_DEBUG(1, (__F,
67984260Sobrien		"xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
68084260Sobrien#ifdef DEBUG_REFRESH
68184260Sobrien	re_printstr(el, "old- oe", old, oe);
68284260Sobrien	re_printstr(el, "new- ne", new, ne);
68384260Sobrien	re_printstr(el, "old-ofd", old, ofd);
68484260Sobrien	re_printstr(el, "new-nfd", new, nfd);
68584260Sobrien	re_printstr(el, "ofd-osb", ofd, osb);
68684260Sobrien	re_printstr(el, "nfd-nsb", nfd, nsb);
68784260Sobrien	re_printstr(el, "osb-ose", osb, ose);
68884260Sobrien	re_printstr(el, "nsb-nse", nsb, nse);
68984260Sobrien	re_printstr(el, "ose-ols", ose, ols);
69084260Sobrien	re_printstr(el, "nse-nls", nse, nls);
69184260Sobrien	re_printstr(el, "ols- oe", ols, oe);
69284260Sobrien	re_printstr(el, "nls- ne", nls, ne);
69384260Sobrien#endif /* DEBUG_REFRESH */
69484260Sobrien
6951573Srgrimes	/*
69684260Sobrien         * el_cursor.v to this line i MUST be in this routine so that if we
69784260Sobrien         * don't have to change the line, we don't move to it. el_cursor.h to
69884260Sobrien         * first diff char
69984260Sobrien         */
70084260Sobrien	term_move_to_line(el, i);
7011573Srgrimes
70284260Sobrien	/*
70384260Sobrien         * at this point we have something like this:
70484260Sobrien         *
70584260Sobrien         * /old                  /ofd    /osb               /ose    /ols     /oe
70684260Sobrien         * v.....................v       v..................v       v........v
70784260Sobrien         * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
70884260Sobrien         * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
70984260Sobrien         * ^.....................^     ^..................^       ^........^
71084260Sobrien         * \new                  \nfd  \nsb               \nse     \nls    \ne
71184260Sobrien         *
71284260Sobrien         * fx is the difference in length between the chars between nfd and
71384260Sobrien         * nsb, and the chars between ofd and osb, and is thus the number of
71484260Sobrien         * characters to delete if < 0 (new is shorter than old, as above),
71584260Sobrien         * or insert (new is longer than short).
71684260Sobrien         *
71784260Sobrien         * sx is the same for the second differences.
71884260Sobrien         */
7191573Srgrimes
72084260Sobrien	/*
72184260Sobrien         * if we have a net insert on the first difference, AND inserting the
72284260Sobrien         * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
72384260Sobrien         * character (which is ne if nls != ne, otherwise is nse) off the edge
72484260Sobrien	 * of the screen (el->el_term.t_size.h) else we do the deletes first
72584260Sobrien	 * so that we keep everything we need to.
72684260Sobrien         */
7271573Srgrimes
7281573Srgrimes	/*
72984260Sobrien         * if the last same is the same like the end, there is no last same
73084260Sobrien         * part, otherwise we want to keep the last same part set p to the
73184260Sobrien         * last useful old character
73284260Sobrien         */
73384260Sobrien	p = (ols != oe) ? oe : ose;
73484260Sobrien
73584260Sobrien	/*
73684260Sobrien         * if (There is a diffence in the beginning) && (we need to insert
73784260Sobrien         *   characters) && (the number of characters to insert is less than
73884260Sobrien         *   the term width)
73984260Sobrien	 *	We need to do an insert!
74084260Sobrien	 * else if (we need to delete characters)
74184260Sobrien	 *	We need to delete characters!
74284260Sobrien	 * else
74384260Sobrien	 *	No insert or delete
74484260Sobrien         */
74584260Sobrien	if ((nsb != nfd) && fx > 0 &&
74684260Sobrien	    ((p - old) + fx <= el->el_term.t_size.h)) {
74784260Sobrien		ELRE_DEBUG(1,
74884260Sobrien		    (__F, "first diff insert at %d...\r\n", nfd - new));
7491573Srgrimes		/*
75084260Sobrien		 * Move to the first char to insert, where the first diff is.
7511573Srgrimes		 */
752237448Spfg		term_move_to_char(el, (int)(nfd - new));
75384260Sobrien		/*
75484260Sobrien		 * Check if we have stuff to keep at end
75584260Sobrien		 */
75684260Sobrien		if (nsb != ne) {
75784260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
75884260Sobrien			/*
75984260Sobrien		         * insert fx chars of new starting at nfd
76084260Sobrien		         */
76184260Sobrien			if (fx > 0) {
76284260Sobrien				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
76384260Sobrien				"ERROR: cannot insert in early first diff\n"));
76484260Sobrien				term_insertwrite(el, nfd, fx);
765237448Spfg				re_insert(el, old, (int)(ofd - old),
76684260Sobrien				    el->el_term.t_size.h, nfd, fx);
76784260Sobrien			}
76884260Sobrien			/*
76984260Sobrien		         * write (nsb-nfd) - fx chars of new starting at
77084260Sobrien		         * (nfd + fx)
77184260Sobrien			 */
772237448Spfg			len = (size_t) ((nsb - nfd) - fx);
773237448Spfg			term_overwrite(el, (nfd + fx), len);
774237448Spfg			re__strncopy(ofd + fx, nfd + fx, len);
77584260Sobrien		} else {
77684260Sobrien			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
777237448Spfg			len = (size_t)(nsb - nfd);
778237448Spfg			term_overwrite(el, nfd, len);
779237448Spfg			re__strncopy(ofd, nfd, len);
78084260Sobrien			/*
78184260Sobrien		         * Done
78284260Sobrien		         */
78384260Sobrien			return;
78484260Sobrien		}
78584260Sobrien	} else if (fx < 0) {
78684260Sobrien		ELRE_DEBUG(1,
78784260Sobrien		    (__F, "first diff delete at %d...\r\n", ofd - old));
78884260Sobrien		/*
78984260Sobrien		 * move to the first char to delete where the first diff is
79084260Sobrien		 */
791237448Spfg		term_move_to_char(el, (int)(ofd - old));
79284260Sobrien		/*
79384260Sobrien		 * Check if we have stuff to save
79484260Sobrien		 */
79584260Sobrien		if (osb != oe) {
79684260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
79784260Sobrien			/*
79884260Sobrien		         * fx is less than zero *always* here but we check
79984260Sobrien		         * for code symmetry
80084260Sobrien		         */
80184260Sobrien			if (fx < 0) {
80284260Sobrien				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
80384260Sobrien				    "ERROR: cannot delete in first diff\n"));
80484260Sobrien				term_deletechars(el, -fx);
805237448Spfg				re_delete(el, old, (int)(ofd - old),
80684260Sobrien				    el->el_term.t_size.h, -fx);
80784260Sobrien			}
80884260Sobrien			/*
80984260Sobrien		         * write (nsb-nfd) chars of new starting at nfd
81084260Sobrien		         */
811237448Spfg			len = (size_t) (nsb - nfd);
812237448Spfg			term_overwrite(el, nfd, len);
813237448Spfg			re__strncopy(ofd, nfd, len);
8141573Srgrimes
81584260Sobrien		} else {
81684260Sobrien			ELRE_DEBUG(1, (__F,
81784260Sobrien			    "but with nothing left to save\r\n"));
81884260Sobrien			/*
81984260Sobrien		         * write (nsb-nfd) chars of new starting at nfd
82084260Sobrien		         */
821237448Spfg			term_overwrite(el, nfd, (size_t)(nsb - nfd));
822237448Spfg			re_clear_eol(el, fx, sx,
823237448Spfg			    (int)((oe - old) - (ne - new)));
82484260Sobrien			/*
82584260Sobrien		         * Done
82684260Sobrien		         */
82784260Sobrien			return;
82884260Sobrien		}
82984260Sobrien	} else
83084260Sobrien		fx = 0;
8311573Srgrimes
83284260Sobrien	if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) {
83384260Sobrien		ELRE_DEBUG(1, (__F,
83484260Sobrien		    "second diff delete at %d...\r\n", (ose - old) + fx));
83584260Sobrien		/*
83684260Sobrien		 * Check if we have stuff to delete
83784260Sobrien		 */
83884260Sobrien		/*
83984260Sobrien		 * fx is the number of characters inserted (+) or deleted (-)
84084260Sobrien		 */
8411573Srgrimes
842237448Spfg		term_move_to_char(el, (int)((ose - old) + fx));
84384260Sobrien		/*
84484260Sobrien		 * Check if we have stuff to save
84584260Sobrien		 */
84684260Sobrien		if (ols != oe) {
84784260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
84884260Sobrien			/*
84984260Sobrien		         * Again a duplicate test.
85084260Sobrien		         */
85184260Sobrien			if (sx < 0) {
85284260Sobrien				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
85384260Sobrien				    "ERROR: cannot delete in second diff\n"));
85484260Sobrien				term_deletechars(el, -sx);
85584260Sobrien			}
85684260Sobrien			/*
85784260Sobrien		         * write (nls-nse) chars of new starting at nse
85884260Sobrien		         */
859237448Spfg			term_overwrite(el, nse, (size_t)(nls - nse));
86084260Sobrien		} else {
86184260Sobrien			ELRE_DEBUG(1, (__F,
86284260Sobrien			    "but with nothing left to save\r\n"));
863237448Spfg			term_overwrite(el, nse, (size_t)(nls - nse));
864237448Spfg			re_clear_eol(el, fx, sx,
865237448Spfg			    (int)((oe - old) - (ne - new)));
86684260Sobrien		}
8671573Srgrimes	}
86884260Sobrien	/*
86984260Sobrien         * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
87084260Sobrien         */
87184260Sobrien	if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
87284260Sobrien		ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
87384260Sobrien		    nfd - new));
8741573Srgrimes
875237448Spfg		term_move_to_char(el, (int)(nfd - new));
87684260Sobrien		/*
87784260Sobrien		 * Check if we have stuff to keep at the end
87884260Sobrien		 */
87984260Sobrien		if (nsb != ne) {
88084260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
88184260Sobrien			/*
88284260Sobrien		         * We have to recalculate fx here because we set it
88384260Sobrien		         * to zero above as a flag saying that we hadn't done
88484260Sobrien		         * an early first insert.
88584260Sobrien		         */
886237448Spfg			fx = (int)((nsb - nfd) - (osb - ofd));
88784260Sobrien			if (fx > 0) {
88884260Sobrien				/*
88984260Sobrien				 * insert fx chars of new starting at nfd
89084260Sobrien				 */
89184260Sobrien				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
89284260Sobrien				 "ERROR: cannot insert in late first diff\n"));
89384260Sobrien				term_insertwrite(el, nfd, fx);
894237448Spfg				re_insert(el, old, (int)(ofd - old),
89584260Sobrien				    el->el_term.t_size.h, nfd, fx);
89684260Sobrien			}
89784260Sobrien			/*
89884260Sobrien		         * write (nsb-nfd) - fx chars of new starting at
89984260Sobrien		         * (nfd + fx)
90084260Sobrien			 */
901237448Spfg			len = (size_t) ((nsb - nfd) - fx);
902237448Spfg			term_overwrite(el, (nfd + fx), len);
903237448Spfg			re__strncopy(ofd + fx, nfd + fx, len);
90484260Sobrien		} else {
90584260Sobrien			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
906237448Spfg			len = (size_t) (nsb - nfd);
907237448Spfg			term_overwrite(el, nfd, len);
908237448Spfg			re__strncopy(ofd, nfd, len);
90984260Sobrien		}
9101573Srgrimes	}
91184260Sobrien	/*
91284260Sobrien         * line is now NEW up to nse
91384260Sobrien         */
91484260Sobrien	if (sx >= 0) {
91584260Sobrien		ELRE_DEBUG(1, (__F,
916237448Spfg		    "second diff insert at %d...\r\n", (int)(nse - new)));
917237448Spfg		term_move_to_char(el, (int)(nse - new));
91884260Sobrien		if (ols != oe) {
91984260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
92084260Sobrien			if (sx > 0) {
92184260Sobrien				/* insert sx chars of new starting at nse */
92284260Sobrien				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
92384260Sobrien				    "ERROR: cannot insert in second diff\n"));
92484260Sobrien				term_insertwrite(el, nse, sx);
92584260Sobrien			}
92684260Sobrien			/*
92784260Sobrien		         * write (nls-nse) - sx chars of new starting at
92884260Sobrien			 * (nse + sx)
92984260Sobrien		         */
930237448Spfg			term_overwrite(el, (nse + sx),
931237448Spfg			    (size_t)((nls - nse) - sx));
93284260Sobrien		} else {
93384260Sobrien			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
934237448Spfg			term_overwrite(el, nse, (size_t)(nls - nse));
9351573Srgrimes
93684260Sobrien			/*
93784260Sobrien	                 * No need to do a clear-to-end here because we were
93884260Sobrien	                 * doing a second insert, so we will have over
93984260Sobrien	                 * written all of the old string.
94084260Sobrien		         */
94184260Sobrien		}
94284260Sobrien	}
94384260Sobrien	ELRE_DEBUG(1, (__F, "done.\r\n"));
94484260Sobrien}
9451573Srgrimes
94684260Sobrien
9471573Srgrimes/* re__copy_and_pad():
9481573Srgrimes *	Copy string and pad with spaces
9491573Srgrimes */
9501573Srgrimesprivate void
951148834Sstefanfre__copy_and_pad(char *dst, const char *src, size_t width)
9521573Srgrimes{
953148834Sstefanf	size_t i;
9541573Srgrimes
95584260Sobrien	for (i = 0; i < width; i++) {
95684260Sobrien		if (*src == '\0')
95784260Sobrien			break;
95884260Sobrien		*dst++ = *src++;
95984260Sobrien	}
9601573Srgrimes
96184260Sobrien	for (; i < width; i++)
96284260Sobrien		*dst++ = ' ';
9631573Srgrimes
96484260Sobrien	*dst = '\0';
96584260Sobrien}
9661573Srgrimes
96784260Sobrien
9681573Srgrimes/* re_refresh_cursor():
9691573Srgrimes *	Move to the new cursor position
9701573Srgrimes */
9711573Srgrimesprotected void
97284260Sobrienre_refresh_cursor(EditLine *el)
9731573Srgrimes{
97484260Sobrien	char *cp, c;
97584260Sobrien	int h, v, th;
9761573Srgrimes
977148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar) {
978148834Sstefanf		if (el->el_map.current == el->el_map.alt
979148834Sstefanf		    && el->el_line.lastchar != el->el_line.buffer)
980148834Sstefanf			el->el_line.cursor = el->el_line.lastchar - 1;
981148834Sstefanf		else
982148834Sstefanf			el->el_line.cursor = el->el_line.lastchar;
983148834Sstefanf	}
984148834Sstefanf
98584260Sobrien	/* first we must find where the cursor is... */
98684260Sobrien	h = el->el_prompt.p_pos.h;
98784260Sobrien	v = el->el_prompt.p_pos.v;
98884260Sobrien	th = el->el_term.t_size.h;	/* optimize for speed */
9891573Srgrimes
99084260Sobrien	/* do input buffer to el->el_line.cursor */
99184260Sobrien	for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
992148834Sstefanf		c = *cp;
9931573Srgrimes
994237448Spfg		switch (c) {
995237448Spfg		case '\n':	/* handle newline in data part too */
99684260Sobrien			h = 0;
99784260Sobrien			v++;
998237448Spfg			break;
999237448Spfg		case '\t':	/* if a tab, to next tab stop */
1000237448Spfg			while (++h & 07)
1001237448Spfg				continue;
1002237448Spfg			break;
1003237448Spfg		default:
1004237448Spfg			if (iscntrl((unsigned char) c))
1005237448Spfg				h += 2;	/* ^x */
1006237448Spfg			else if (!isprint((unsigned char) c))
1007237448Spfg				h += 4; /* octal \xxx */
1008237448Spfg			else
100984260Sobrien				h++;
1010237448Spfg			break;
10111573Srgrimes		}
101284260Sobrien
101384260Sobrien		if (h >= th) {	/* check, extra long tabs picked up here also */
1014237448Spfg			h -= th;
101584260Sobrien			v++;
10161573Srgrimes		}
10171573Srgrimes	}
10181573Srgrimes
101984260Sobrien	/* now go there */
102084260Sobrien	term_move_to_line(el, v);
102184260Sobrien	term_move_to_char(el, h);
1022237448Spfg	term__flush(el);
102384260Sobrien}
10241573Srgrimes
10251573Srgrimes
10261573Srgrimes/* re_fastputc():
10271573Srgrimes *	Add a character fast.
10281573Srgrimes */
10291573Srgrimesprivate void
103084260Sobrienre_fastputc(EditLine *el, int c)
10311573Srgrimes{
10321573Srgrimes
1033237448Spfg	term__putc(el, c);
103484260Sobrien	el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
103584260Sobrien	if (el->el_cursor.h >= el->el_term.t_size.h) {
103684260Sobrien		/* if we must overflow */
103784260Sobrien		el->el_cursor.h = 0;
10381573Srgrimes
103984260Sobrien		/*
104084260Sobrien		 * If we would overflow (input is longer than terminal size),
104184260Sobrien		 * emulate scroll by dropping first line and shuffling the rest.
104284260Sobrien		 * We do this via pointer shuffling - it's safe in this case
104384260Sobrien		 * and we avoid memcpy().
104484260Sobrien		 */
104584260Sobrien		if (el->el_cursor.v + 1 >= el->el_term.t_size.v) {
104684260Sobrien			int i, lins = el->el_term.t_size.v;
104784260Sobrien			char *firstline = el->el_display[0];
104884260Sobrien
1049237448Spfg			for(i = 1; i < lins; i++)
1050237448Spfg				el->el_display[i - 1] = el->el_display[i];
105184260Sobrien
105284260Sobrien			re__copy_and_pad(firstline, "", 0);
1053237448Spfg			el->el_display[i - 1] = firstline;
105484260Sobrien		} else {
105584260Sobrien			el->el_cursor.v++;
105684260Sobrien			el->el_refresh.r_oldcv++;
105784260Sobrien		}
105884260Sobrien		if (EL_HAS_AUTO_MARGINS) {
105984260Sobrien			if (EL_HAS_MAGIC_MARGINS) {
1060237448Spfg				term__putc(el, ' ');
1061237448Spfg				term__putc(el, '\b');
106284260Sobrien			}
106384260Sobrien		} else {
1064237448Spfg			term__putc(el, '\r');
1065237448Spfg			term__putc(el, '\n');
106684260Sobrien		}
106784260Sobrien	}
106884260Sobrien}
106984260Sobrien
107084260Sobrien
10711573Srgrimes/* re_fastaddc():
10721573Srgrimes *	we added just one char, handle it fast.
10738870Srgrimes *	Assumes that screen cursor == real cursor
10741573Srgrimes */
10751573Srgrimesprotected void
107684260Sobrienre_fastaddc(EditLine *el)
10771573Srgrimes{
107884260Sobrien	char c;
107984260Sobrien	int rhdiff;
10801573Srgrimes
108184260Sobrien	c = (unsigned char)el->el_line.cursor[-1];
10821573Srgrimes
108384260Sobrien	if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
108484260Sobrien		re_refresh(el);	/* too hard to handle */
108584260Sobrien		return;
108684260Sobrien	}
108784260Sobrien	rhdiff = el->el_term.t_size.h - el->el_cursor.h -
108884260Sobrien	    el->el_rprompt.p_pos.h;
108984260Sobrien	if (el->el_rprompt.p_pos.h && rhdiff < 3) {
109084260Sobrien		re_refresh(el);	/* clear out rprompt if less than 1 char gap */
109184260Sobrien		return;
109284260Sobrien	}			/* else (only do at end of line, no TAB) */
109384260Sobrien	if (iscntrl((unsigned char) c)) {	/* if control char, do caret */
109484260Sobrien		char mc = (c == 0177) ? '?' : (toascii(c) | 0100);
109584260Sobrien		re_fastputc(el, '^');
109684260Sobrien		re_fastputc(el, mc);
109784260Sobrien	} else if (isprint((unsigned char) c)) {	/* normal char */
109884260Sobrien		re_fastputc(el, c);
109984260Sobrien	} else {
110084260Sobrien		re_fastputc(el, '\\');
1101148834Sstefanf		re_fastputc(el, (int)(((((unsigned int)c) >> 6) & 3) + '0'));
1102148834Sstefanf		re_fastputc(el, (int)(((((unsigned int)c) >> 3) & 7) + '0'));
110384260Sobrien		re_fastputc(el, (c & 7) + '0');
110484260Sobrien	}
1105237448Spfg	term__flush(el);
110684260Sobrien}
11071573Srgrimes
11081573Srgrimes
11091573Srgrimes/* re_clear_display():
11108870Srgrimes *	clear the screen buffers so that new new prompt starts fresh.
11111573Srgrimes */
11121573Srgrimesprotected void
111384260Sobrienre_clear_display(EditLine *el)
11141573Srgrimes{
111584260Sobrien	int i;
11161573Srgrimes
111784260Sobrien	el->el_cursor.v = 0;
111884260Sobrien	el->el_cursor.h = 0;
111984260Sobrien	for (i = 0; i < el->el_term.t_size.v; i++)
112084260Sobrien		el->el_display[i][0] = '\0';
112184260Sobrien	el->el_refresh.r_oldcv = 0;
112284260Sobrien}
11231573Srgrimes
11241573Srgrimes
11251573Srgrimes/* re_clear_lines():
11268870Srgrimes *	Make sure all lines are *really* blank
11271573Srgrimes */
11281573Srgrimesprotected void
112984260Sobrienre_clear_lines(EditLine *el)
11301573Srgrimes{
113184260Sobrien
113284260Sobrien	if (EL_CAN_CEOL) {
113384260Sobrien		int i;
1134237448Spfg		for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
113584260Sobrien			/* for each line on the screen */
113684260Sobrien			term_move_to_line(el, i);
1137237448Spfg			term_move_to_char(el, 0);
113884260Sobrien			term_clear_EOL(el, el->el_term.t_size.h);
113984260Sobrien		}
114084260Sobrien	} else {
114184260Sobrien		term_move_to_line(el, el->el_refresh.r_oldcv);
114284260Sobrien					/* go to last line */
1143237448Spfg		term__putc(el, '\r');	/* go to BOL */
1144237448Spfg		term__putc(el, '\n');	/* go to new line */
11451573Srgrimes	}
114684260Sobrien}
1147