Home | History | Annotate | Line # | Download | only in libedit
refresh.c revision 1.45
      1 /*	$NetBSD: refresh.c,v 1.45 2016/03/02 19:24:20 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1992, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Christos Zoulas of Cornell University.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include "config.h"
     36 #if !defined(lint) && !defined(SCCSID)
     37 #if 0
     38 static char sccsid[] = "@(#)refresh.c	8.1 (Berkeley) 6/4/93";
     39 #else
     40 __RCSID("$NetBSD: refresh.c,v 1.45 2016/03/02 19:24:20 christos Exp $");
     41 #endif
     42 #endif /* not lint && not SCCSID */
     43 
     44 /*
     45  * refresh.c: Lower level screen refreshing functions
     46  */
     47 #include <stdio.h>
     48 #include <string.h>
     49 #include <unistd.h>
     50 
     51 #include "el.h"
     52 
     53 private void	re_nextline(EditLine *);
     54 private void	re_addc(EditLine *, wint_t);
     55 private void	re_update_line(EditLine *, Char *, Char *, int);
     56 private void	re_insert (EditLine *, Char *, int, int, Char *, int);
     57 private void	re_delete(EditLine *, Char *, int, int, int);
     58 private void	re_fastputc(EditLine *, wint_t);
     59 private void	re_clear_eol(EditLine *, int, int, int);
     60 private void	re__strncopy(Char *, Char *, size_t);
     61 private void	re__copy_and_pad(Char *, const Char *, size_t);
     62 
     63 #ifdef DEBUG_REFRESH
     64 private void	re_printstr(EditLine *, const char *, Char *, Char *);
     65 #define	__F el->el_errfile
     66 #define	ELRE_ASSERT(a, b, c)	do				\
     67 				    if (/*CONSTCOND*/ a) {	\
     68 					(void) fprintf b;	\
     69 					c;			\
     70 				    }				\
     71 				while (/*CONSTCOND*/0)
     72 #define	ELRE_DEBUG(a, b)	ELRE_ASSERT(a,b,;)
     73 
     74 /* re_printstr():
     75  *	Print a string on the debugging pty
     76  */
     77 private void
     78 re_printstr(EditLine *el, const char *str, Char *f, Char *t)
     79 {
     80 
     81 	ELRE_DEBUG(1, (__F, "%s:\"", str));
     82 	while (f < t)
     83 		ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
     84 	ELRE_DEBUG(1, (__F, "\"\r\n"));
     85 }
     86 #else
     87 #define	ELRE_ASSERT(a, b, c)
     88 #define	ELRE_DEBUG(a, b)
     89 #endif
     90 
     91 /* re_nextline():
     92  *	Move to the next line or scroll
     93  */
     94 private void
     95 re_nextline(EditLine *el)
     96 {
     97 	el->el_refresh.r_cursor.h = 0;	/* reset it. */
     98 
     99 	/*
    100 	 * If we would overflow (input is longer than terminal size),
    101 	 * emulate scroll by dropping first line and shuffling the rest.
    102 	 * We do this via pointer shuffling - it's safe in this case
    103 	 * and we avoid memcpy().
    104 	 */
    105 	if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) {
    106 		int i, lins = el->el_terminal.t_size.v;
    107 		Char *firstline = el->el_vdisplay[0];
    108 
    109 		for(i = 1; i < lins; i++)
    110 			el->el_vdisplay[i - 1] = el->el_vdisplay[i];
    111 
    112 		firstline[0] = '\0';		/* empty the string */
    113 		el->el_vdisplay[i - 1] = firstline;
    114 	} else
    115 		el->el_refresh.r_cursor.v++;
    116 
    117 	ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v,
    118 	    (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
    119 	    el->el_refresh.r_cursor.v, el->el_terminal.t_size.v),
    120 	    abort());
    121 }
    122 
    123 /* re_addc():
    124  *	Draw c, expanding tabs, control chars etc.
    125  */
    126 private void
    127 re_addc(EditLine *el, wint_t c)
    128 {
    129 	switch (ct_chr_class((Char)c)) {
    130 	case CHTYPE_TAB:        /* expand the tab */
    131 		for (;;) {
    132 			re_putc(el, ' ', 1);
    133 			if ((el->el_refresh.r_cursor.h & 07) == 0)
    134 				break;			/* go until tab stop */
    135 		}
    136 		break;
    137 	case CHTYPE_NL: {
    138 		int oldv = el->el_refresh.r_cursor.v;
    139 		re_putc(el, '\0', 0);			/* assure end of line */
    140 		if (oldv == el->el_refresh.r_cursor.v)	/* XXX */
    141 			re_nextline(el);
    142 		break;
    143 	}
    144 	case CHTYPE_PRINT:
    145 		re_putc(el, c, 1);
    146 		break;
    147 	default: {
    148 		Char visbuf[VISUAL_WIDTH_MAX];
    149 		ssize_t i, n =
    150 		    ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c);
    151 		for (i = 0; n-- > 0; ++i)
    152 		    re_putc(el, visbuf[i], 1);
    153 		break;
    154 	}
    155 	}
    156 }
    157 
    158 
    159 /* re_putc():
    160  *	Draw the character given
    161  */
    162 protected void
    163 re_putc(EditLine *el, wint_t c, int shift)
    164 {
    165 	int i, w = Width(c);
    166 	ELRE_DEBUG(1, (__F, "printing %5x '%lc'\r\n", c, c));
    167 
    168 	while (shift && (el->el_refresh.r_cursor.h + w > el->el_terminal.t_size.h))
    169 	    re_putc(el, ' ', 1);
    170 
    171 	el->el_vdisplay[el->el_refresh.r_cursor.v]
    172 	    [el->el_refresh.r_cursor.h] = (Char)c;
    173 	/* assumes !shift is only used for single-column chars */
    174 	i = w;
    175 	while (--i > 0)
    176 		el->el_vdisplay[el->el_refresh.r_cursor.v]
    177 		    [el->el_refresh.r_cursor.h + i] = MB_FILL_CHAR;
    178 
    179 	if (!shift)
    180 		return;
    181 
    182 	el->el_refresh.r_cursor.h += w;	/* advance to next place */
    183 	if (el->el_refresh.r_cursor.h >= el->el_terminal.t_size.h) {
    184 		/* assure end of line */
    185 		el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_terminal.t_size.h]
    186 		    = '\0';
    187 		re_nextline(el);
    188 	}
    189 }
    190 
    191 
    192 /* re_refresh():
    193  *	draws the new virtual screen image from the current input
    194  *	line, then goes line-by-line changing the real image to the new
    195  *	virtual image. The routine to re-draw a line can be replaced
    196  *	easily in hopes of a smarter one being placed there.
    197  */
    198 protected void
    199 re_refresh(EditLine *el)
    200 {
    201 	int i, rhdiff;
    202 	Char *cp, *st;
    203 	coord_t cur;
    204 #ifdef notyet
    205 	size_t termsz;
    206 #endif
    207 
    208 	ELRE_DEBUG(1, (__F, "el->el_line.buffer = :" FSTR ":\r\n",
    209 	    el->el_line.buffer));
    210 
    211 	/* reset the Drawing cursor */
    212 	el->el_refresh.r_cursor.h = 0;
    213 	el->el_refresh.r_cursor.v = 0;
    214 
    215 	/* temporarily draw rprompt to calculate its size */
    216 	prompt_print(el, EL_RPROMPT);
    217 
    218 	/* reset the Drawing cursor */
    219 	el->el_refresh.r_cursor.h = 0;
    220 	el->el_refresh.r_cursor.v = 0;
    221 
    222 	if (el->el_line.cursor >= el->el_line.lastchar) {
    223 		if (el->el_map.current == el->el_map.alt
    224 		    && el->el_line.lastchar != el->el_line.buffer)
    225 			el->el_line.cursor = el->el_line.lastchar - 1;
    226 		else
    227 			el->el_line.cursor = el->el_line.lastchar;
    228 	}
    229 
    230 	cur.h = -1;		/* set flag in case I'm not set */
    231 	cur.v = 0;
    232 
    233 	prompt_print(el, EL_PROMPT);
    234 
    235 	/* draw the current input buffer */
    236 #if notyet
    237 	termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v;
    238 	if (el->el_line.lastchar - el->el_line.buffer > termsz) {
    239 		/*
    240 		 * If line is longer than terminal, process only part
    241 		 * of line which would influence display.
    242 		 */
    243 		size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
    244 
    245 		st = el->el_line.lastchar - rem
    246 			- (termsz - (((rem / el->el_terminal.t_size.v) - 1)
    247 					* el->el_terminal.t_size.v));
    248 	} else
    249 #endif
    250 		st = el->el_line.buffer;
    251 
    252 	for (cp = st; cp < el->el_line.lastchar; cp++) {
    253 		if (cp == el->el_line.cursor) {
    254                         int w = Width(*cp);
    255 			/* save for later */
    256 			cur.h = el->el_refresh.r_cursor.h;
    257 			cur.v = el->el_refresh.r_cursor.v;
    258                         /* handle being at a linebroken doublewidth char */
    259                         if (w > 1 && el->el_refresh.r_cursor.h + w >
    260 			    el->el_terminal.t_size.h) {
    261 				cur.h = 0;
    262 				cur.v++;
    263                         }
    264 		}
    265 		re_addc(el, *cp);
    266 	}
    267 
    268 	if (cur.h == -1) {	/* if I haven't been set yet, I'm at the end */
    269 		cur.h = el->el_refresh.r_cursor.h;
    270 		cur.v = el->el_refresh.r_cursor.v;
    271 	}
    272 	rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h -
    273 	    el->el_rprompt.p_pos.h;
    274 	if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
    275 	    !el->el_refresh.r_cursor.v && rhdiff > 1) {
    276 		/*
    277 		 * have a right-hand side prompt that will fit
    278 		 * on the end of the first line with at least
    279 		 * one character gap to the input buffer.
    280 		 */
    281 		while (--rhdiff > 0)	/* pad out with spaces */
    282 			re_putc(el, ' ', 1);
    283 		prompt_print(el, EL_RPROMPT);
    284 	} else {
    285 		el->el_rprompt.p_pos.h = 0;	/* flag "not using rprompt" */
    286 		el->el_rprompt.p_pos.v = 0;
    287 	}
    288 
    289 	re_putc(el, '\0', 0);	/* make line ended with NUL, no cursor shift */
    290 
    291 	el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
    292 
    293 	ELRE_DEBUG(1, (__F,
    294 		"term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
    295 		el->el_terminal.t_size.h, el->el_refresh.r_cursor.h,
    296 		el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0],
    297 		&el->el_scratch)));
    298 
    299 	ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
    300 	for (i = 0; i <= el->el_refresh.r_newcv; i++) {
    301 		/* NOTE THAT re_update_line MAY CHANGE el_display[i] */
    302 		re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
    303 
    304 		/*
    305 		 * Copy the new line to be the current one, and pad out with
    306 		 * spaces to the full width of the terminal so that if we try
    307 		 * moving the cursor by writing the character that is at the
    308 		 * end of the screen line, it won't be a NUL or some old
    309 		 * leftover stuff.
    310 		 */
    311 		re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
    312 		    (size_t) el->el_terminal.t_size.h);
    313 	}
    314 	ELRE_DEBUG(1, (__F,
    315 	"\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
    316 	    el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
    317 
    318 	if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
    319 		for (; i <= el->el_refresh.r_oldcv; i++) {
    320 			terminal_move_to_line(el, i);
    321 			terminal_move_to_char(el, 0);
    322                         /* This Strlen should be safe even with MB_FILL_CHARs */
    323 			terminal_clear_EOL(el, (int) Strlen(el->el_display[i]));
    324 #ifdef DEBUG_REFRESH
    325 			terminal_overwrite(el, STR("C\b"), 2);
    326 #endif /* DEBUG_REFRESH */
    327 			el->el_display[i][0] = '\0';
    328 		}
    329 
    330 	el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
    331 	ELRE_DEBUG(1, (__F,
    332 	    "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
    333 	    el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
    334 	    cur.h, cur.v));
    335 	terminal_move_to_line(el, cur.v);	/* go to where the cursor is */
    336 	terminal_move_to_char(el, cur.h);
    337 }
    338 
    339 
    340 /* re_goto_bottom():
    341  *	 used to go to last used screen line
    342  */
    343 protected void
    344 re_goto_bottom(EditLine *el)
    345 {
    346 
    347 	terminal_move_to_line(el, el->el_refresh.r_oldcv);
    348 	terminal__putc(el, '\n');
    349 	re_clear_display(el);
    350 	terminal__flush(el);
    351 }
    352 
    353 
    354 /* re_insert():
    355  *	insert num characters of s into d (in front of the character)
    356  *	at dat, maximum length of d is dlen
    357  */
    358 private void
    359 /*ARGSUSED*/
    360 re_insert(EditLine *el __attribute__((__unused__)),
    361     Char *d, int dat, int dlen, Char *s, int num)
    362 {
    363 	Char *a, *b;
    364 
    365 	if (num <= 0)
    366 		return;
    367 	if (num > dlen - dat)
    368 		num = dlen - dat;
    369 
    370 	ELRE_DEBUG(1,
    371 	    (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
    372 	    num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
    373 	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
    374 	    &el->el_scratch)));
    375 
    376 	/* open up the space for num chars */
    377 	if (num > 0) {
    378 		b = d + dlen - 1;
    379 		a = b - num;
    380 		while (a >= &d[dat])
    381 			*b-- = *a--;
    382 		d[dlen] = '\0';	/* just in case */
    383 	}
    384 
    385 	ELRE_DEBUG(1, (__F,
    386 		"re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
    387 		num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
    388 	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
    389 		&el->el_scratch)));
    390 
    391 	/* copy the characters */
    392 	for (a = d + dat; (a < d + dlen) && (num > 0); num--)
    393 		*a++ = *s++;
    394 
    395 #ifdef notyet
    396         /* ct_encode_string() uses a static buffer, so we can't conveniently
    397          * encode both d & s here */
    398 	ELRE_DEBUG(1,
    399 	    (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
    400 	    num, dat, dlen, d, s));
    401 	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
    402 #endif
    403 }
    404 
    405 
    406 /* re_delete():
    407  *	delete num characters d at dat, maximum length of d is dlen
    408  */
    409 private void
    410 /*ARGSUSED*/
    411 re_delete(EditLine *el __attribute__((__unused__)),
    412     Char *d, int dat, int dlen, int num)
    413 {
    414 	Char *a, *b;
    415 
    416 	if (num <= 0)
    417 		return;
    418 	if (dat + num >= dlen) {
    419 		d[dat] = '\0';
    420 		return;
    421 	}
    422 	ELRE_DEBUG(1,
    423 	    (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
    424 	    num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
    425 
    426 	/* open up the space for num chars */
    427 	if (num > 0) {
    428 		b = d + dat;
    429 		a = b + num;
    430 		while (a < &d[dlen])
    431 			*b++ = *a++;
    432 		d[dlen] = '\0';	/* just in case */
    433 	}
    434 	ELRE_DEBUG(1,
    435 	    (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
    436 	    num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
    437 }
    438 
    439 
    440 /* re__strncopy():
    441  *	Like strncpy without padding.
    442  */
    443 private void
    444 re__strncopy(Char *a, Char *b, size_t n)
    445 {
    446 
    447 	while (n-- && *b)
    448 		*a++ = *b++;
    449 }
    450 
    451 /* re_clear_eol():
    452  *	Find the number of characters we need to clear till the end of line
    453  *	in order to make sure that we have cleared the previous contents of
    454  *	the line. fx and sx is the number of characters inserted or deleted
    455  *	in the first or second diff, diff is the difference between the
    456  *	number of characters between the new and old line.
    457  */
    458 private void
    459 re_clear_eol(EditLine *el, int fx, int sx, int diff)
    460 {
    461 
    462 	ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
    463 	    sx, fx, diff));
    464 
    465 	if (fx < 0)
    466 		fx = -fx;
    467 	if (sx < 0)
    468 		sx = -sx;
    469 	if (fx > diff)
    470 		diff = fx;
    471 	if (sx > diff)
    472 		diff = sx;
    473 
    474 	ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
    475 	terminal_clear_EOL(el, diff);
    476 }
    477 
    478 /*****************************************************************
    479     re_update_line() is based on finding the middle difference of each line
    480     on the screen; vis:
    481 
    482 			     /old first difference
    483 	/beginning of line   |              /old last same       /old EOL
    484 	v		     v              v                    v
    485 old:	eddie> Oh, my little gruntle-buggy is to me, as lurgid as
    486 new:	eddie> Oh, my little buggy says to me, as lurgid as
    487 	^		     ^        ^			   ^
    488 	\beginning of line   |        \new last same	   \new end of line
    489 			     \new first difference
    490 
    491     all are character pointers for the sake of speed.  Special cases for
    492     no differences, as well as for end of line additions must be handled.
    493 **************************************************************** */
    494 
    495 /* Minimum at which doing an insert it "worth it".  This should be about
    496  * half the "cost" of going into insert mode, inserting a character, and
    497  * going back out.  This should really be calculated from the termcap
    498  * data...  For the moment, a good number for ANSI terminals.
    499  */
    500 #define	MIN_END_KEEP	4
    501 
    502 private void
    503 re_update_line(EditLine *el, Char *old, Char *new, int i)
    504 {
    505 	Char *o, *n, *p, c;
    506 	Char *ofd, *ols, *oe, *nfd, *nls, *ne;
    507 	Char *osb, *ose, *nsb, *nse;
    508 	int fx, sx;
    509 	size_t len;
    510 
    511 	/*
    512          * find first diff
    513          */
    514 	for (o = old, n = new; *o && (*o == *n); o++, n++)
    515 		continue;
    516 	ofd = o;
    517 	nfd = n;
    518 
    519 	/*
    520          * Find the end of both old and new
    521          */
    522 	while (*o)
    523 		o++;
    524 	/*
    525          * Remove any trailing blanks off of the end, being careful not to
    526          * back up past the beginning.
    527          */
    528 	while (ofd < o) {
    529 		if (o[-1] != ' ')
    530 			break;
    531 		o--;
    532 	}
    533 	oe = o;
    534 	*oe = '\0';
    535 
    536 	while (*n)
    537 		n++;
    538 
    539 	/* remove blanks from end of new */
    540 	while (nfd < n) {
    541 		if (n[-1] != ' ')
    542 			break;
    543 		n--;
    544 	}
    545 	ne = n;
    546 	*ne = '\0';
    547 
    548 	/*
    549          * if no diff, continue to next line of redraw
    550          */
    551 	if (*ofd == '\0' && *nfd == '\0') {
    552 		ELRE_DEBUG(1, (__F, "no difference.\r\n"));
    553 		return;
    554 	}
    555 	/*
    556          * find last same pointer
    557          */
    558 	while ((o > ofd) && (n > nfd) && (*--o == *--n))
    559 		continue;
    560 	ols = ++o;
    561 	nls = ++n;
    562 
    563 	/*
    564          * find same begining and same end
    565          */
    566 	osb = ols;
    567 	nsb = nls;
    568 	ose = ols;
    569 	nse = nls;
    570 
    571 	/*
    572          * case 1: insert: scan from nfd to nls looking for *ofd
    573          */
    574 	if (*ofd) {
    575 		for (c = *ofd, n = nfd; n < nls; n++) {
    576 			if (c == *n) {
    577 				for (o = ofd, p = n;
    578 				    p < nls && o < ols && *o == *p;
    579 				    o++, p++)
    580 					continue;
    581 				/*
    582 				 * if the new match is longer and it's worth
    583 				 * keeping, then we take it
    584 				 */
    585 				if (((nse - nsb) < (p - n)) &&
    586 				    (2 * (p - n) > n - nfd)) {
    587 					nsb = n;
    588 					nse = p;
    589 					osb = ofd;
    590 					ose = o;
    591 				}
    592 			}
    593 		}
    594 	}
    595 	/*
    596          * case 2: delete: scan from ofd to ols looking for *nfd
    597          */
    598 	if (*nfd) {
    599 		for (c = *nfd, o = ofd; o < ols; o++) {
    600 			if (c == *o) {
    601 				for (n = nfd, p = o;
    602 				    p < ols && n < nls && *p == *n;
    603 				    p++, n++)
    604 					continue;
    605 				/*
    606 				 * if the new match is longer and it's worth
    607 				 * keeping, then we take it
    608 				 */
    609 				if (((ose - osb) < (p - o)) &&
    610 				    (2 * (p - o) > o - ofd)) {
    611 					nsb = nfd;
    612 					nse = n;
    613 					osb = o;
    614 					ose = p;
    615 				}
    616 			}
    617 		}
    618 	}
    619 	/*
    620          * Pragmatics I: If old trailing whitespace or not enough characters to
    621          * save to be worth it, then don't save the last same info.
    622          */
    623 	if ((oe - ols) < MIN_END_KEEP) {
    624 		ols = oe;
    625 		nls = ne;
    626 	}
    627 	/*
    628          * Pragmatics II: if the terminal isn't smart enough, make the data
    629          * dumber so the smart update doesn't try anything fancy
    630          */
    631 
    632 	/*
    633          * fx is the number of characters we need to insert/delete: in the
    634          * beginning to bring the two same begins together
    635          */
    636 	fx = (int)((nsb - nfd) - (osb - ofd));
    637 	/*
    638          * sx is the number of characters we need to insert/delete: in the
    639          * end to bring the two same last parts together
    640          */
    641 	sx = (int)((nls - nse) - (ols - ose));
    642 
    643 	if (!EL_CAN_INSERT) {
    644 		if (fx > 0) {
    645 			osb = ols;
    646 			ose = ols;
    647 			nsb = nls;
    648 			nse = nls;
    649 		}
    650 		if (sx > 0) {
    651 			ols = oe;
    652 			nls = ne;
    653 		}
    654 		if ((ols - ofd) < (nls - nfd)) {
    655 			ols = oe;
    656 			nls = ne;
    657 		}
    658 	}
    659 	if (!EL_CAN_DELETE) {
    660 		if (fx < 0) {
    661 			osb = ols;
    662 			ose = ols;
    663 			nsb = nls;
    664 			nse = nls;
    665 		}
    666 		if (sx < 0) {
    667 			ols = oe;
    668 			nls = ne;
    669 		}
    670 		if ((ols - ofd) > (nls - nfd)) {
    671 			ols = oe;
    672 			nls = ne;
    673 		}
    674 	}
    675 	/*
    676          * Pragmatics III: make sure the middle shifted pointers are correct if
    677          * they don't point to anything (we may have moved ols or nls).
    678          */
    679 	/* if the change isn't worth it, don't bother */
    680 	/* was: if (osb == ose) */
    681 	if ((ose - osb) < MIN_END_KEEP) {
    682 		osb = ols;
    683 		ose = ols;
    684 		nsb = nls;
    685 		nse = nls;
    686 	}
    687 	/*
    688          * Now that we are done with pragmatics we recompute fx, sx
    689          */
    690 	fx = (int)((nsb - nfd) - (osb - ofd));
    691 	sx = (int)((nls - nse) - (ols - ose));
    692 
    693 	ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
    694 	ELRE_DEBUG(1, (__F, "ofd %td, osb %td, ose %td, ols %td, oe %td\n",
    695 		ofd - old, osb - old, ose - old, ols - old, oe - old));
    696 	ELRE_DEBUG(1, (__F, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n",
    697 		nfd - new, nsb - new, nse - new, nls - new, ne - new));
    698 	ELRE_DEBUG(1, (__F,
    699 		"xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
    700 	ELRE_DEBUG(1, (__F,
    701 		"xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
    702 #ifdef DEBUG_REFRESH
    703 	re_printstr(el, "old- oe", old, oe);
    704 	re_printstr(el, "new- ne", new, ne);
    705 	re_printstr(el, "old-ofd", old, ofd);
    706 	re_printstr(el, "new-nfd", new, nfd);
    707 	re_printstr(el, "ofd-osb", ofd, osb);
    708 	re_printstr(el, "nfd-nsb", nfd, nsb);
    709 	re_printstr(el, "osb-ose", osb, ose);
    710 	re_printstr(el, "nsb-nse", nsb, nse);
    711 	re_printstr(el, "ose-ols", ose, ols);
    712 	re_printstr(el, "nse-nls", nse, nls);
    713 	re_printstr(el, "ols- oe", ols, oe);
    714 	re_printstr(el, "nls- ne", nls, ne);
    715 #endif /* DEBUG_REFRESH */
    716 
    717 	/*
    718          * el_cursor.v to this line i MUST be in this routine so that if we
    719          * don't have to change the line, we don't move to it. el_cursor.h to
    720          * first diff char
    721          */
    722 	terminal_move_to_line(el, i);
    723 
    724 	/*
    725          * at this point we have something like this:
    726          *
    727          * /old                  /ofd    /osb               /ose    /ols     /oe
    728          * v.....................v       v..................v       v........v
    729          * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
    730          * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
    731          * ^.....................^     ^..................^       ^........^
    732          * \new                  \nfd  \nsb               \nse     \nls    \ne
    733          *
    734          * fx is the difference in length between the chars between nfd and
    735          * nsb, and the chars between ofd and osb, and is thus the number of
    736          * characters to delete if < 0 (new is shorter than old, as above),
    737          * or insert (new is longer than short).
    738          *
    739          * sx is the same for the second differences.
    740          */
    741 
    742 	/*
    743          * if we have a net insert on the first difference, AND inserting the
    744          * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
    745          * character (which is ne if nls != ne, otherwise is nse) off the edge
    746 	 * of the screen (el->el_terminal.t_size.h) else we do the deletes first
    747 	 * so that we keep everything we need to.
    748          */
    749 
    750 	/*
    751          * if the last same is the same like the end, there is no last same
    752          * part, otherwise we want to keep the last same part set p to the
    753          * last useful old character
    754          */
    755 	p = (ols != oe) ? oe : ose;
    756 
    757 	/*
    758          * if (There is a diffence in the beginning) && (we need to insert
    759          *   characters) && (the number of characters to insert is less than
    760          *   the term width)
    761 	 *	We need to do an insert!
    762 	 * else if (we need to delete characters)
    763 	 *	We need to delete characters!
    764 	 * else
    765 	 *	No insert or delete
    766          */
    767 	if ((nsb != nfd) && fx > 0 &&
    768 	    ((p - old) + fx <= el->el_terminal.t_size.h)) {
    769 		ELRE_DEBUG(1,
    770 		    (__F, "first diff insert at %td...\r\n", nfd - new));
    771 		/*
    772 		 * Move to the first char to insert, where the first diff is.
    773 		 */
    774 		terminal_move_to_char(el, (int)(nfd - new));
    775 		/*
    776 		 * Check if we have stuff to keep at end
    777 		 */
    778 		if (nsb != ne) {
    779 			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
    780 			/*
    781 		         * insert fx chars of new starting at nfd
    782 		         */
    783 			if (fx > 0) {
    784 				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
    785 				"ERROR: cannot insert in early first diff\n"));
    786 				terminal_insertwrite(el, nfd, fx);
    787 				re_insert(el, old, (int)(ofd - old),
    788 				    el->el_terminal.t_size.h, nfd, fx);
    789 			}
    790 			/*
    791 		         * write (nsb-nfd) - fx chars of new starting at
    792 		         * (nfd + fx)
    793 			 */
    794 			len = (size_t) ((nsb - nfd) - fx);
    795 			terminal_overwrite(el, (nfd + fx), len);
    796 			re__strncopy(ofd + fx, nfd + fx, len);
    797 		} else {
    798 			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
    799 			len = (size_t)(nsb - nfd);
    800 			terminal_overwrite(el, nfd, len);
    801 			re__strncopy(ofd, nfd, len);
    802 			/*
    803 		         * Done
    804 		         */
    805 			return;
    806 		}
    807 	} else if (fx < 0) {
    808 		ELRE_DEBUG(1,
    809 		    (__F, "first diff delete at %td...\r\n", ofd - old));
    810 		/*
    811 		 * move to the first char to delete where the first diff is
    812 		 */
    813 		terminal_move_to_char(el, (int)(ofd - old));
    814 		/*
    815 		 * Check if we have stuff to save
    816 		 */
    817 		if (osb != oe) {
    818 			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
    819 			/*
    820 		         * fx is less than zero *always* here but we check
    821 		         * for code symmetry
    822 		         */
    823 			if (fx < 0) {
    824 				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
    825 				    "ERROR: cannot delete in first diff\n"));
    826 				terminal_deletechars(el, -fx);
    827 				re_delete(el, old, (int)(ofd - old),
    828 				    el->el_terminal.t_size.h, -fx);
    829 			}
    830 			/*
    831 		         * write (nsb-nfd) chars of new starting at nfd
    832 		         */
    833 			len = (size_t) (nsb - nfd);
    834 			terminal_overwrite(el, nfd, len);
    835 			re__strncopy(ofd, nfd, len);
    836 
    837 		} else {
    838 			ELRE_DEBUG(1, (__F,
    839 			    "but with nothing left to save\r\n"));
    840 			/*
    841 		         * write (nsb-nfd) chars of new starting at nfd
    842 		         */
    843 			terminal_overwrite(el, nfd, (size_t)(nsb - nfd));
    844 			re_clear_eol(el, fx, sx,
    845 			    (int)((oe - old) - (ne - new)));
    846 			/*
    847 		         * Done
    848 		         */
    849 			return;
    850 		}
    851 	} else
    852 		fx = 0;
    853 
    854 	if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) {
    855 		ELRE_DEBUG(1, (__F,
    856 		    "second diff delete at %td...\r\n", (ose - old) + fx));
    857 		/*
    858 		 * Check if we have stuff to delete
    859 		 */
    860 		/*
    861 		 * fx is the number of characters inserted (+) or deleted (-)
    862 		 */
    863 
    864 		terminal_move_to_char(el, (int)((ose - old) + fx));
    865 		/*
    866 		 * Check if we have stuff to save
    867 		 */
    868 		if (ols != oe) {
    869 			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
    870 			/*
    871 		         * Again a duplicate test.
    872 		         */
    873 			if (sx < 0) {
    874 				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
    875 				    "ERROR: cannot delete in second diff\n"));
    876 				terminal_deletechars(el, -sx);
    877 			}
    878 			/*
    879 		         * write (nls-nse) chars of new starting at nse
    880 		         */
    881 			terminal_overwrite(el, nse, (size_t)(nls - nse));
    882 		} else {
    883 			ELRE_DEBUG(1, (__F,
    884 			    "but with nothing left to save\r\n"));
    885 			terminal_overwrite(el, nse, (size_t)(nls - nse));
    886 			re_clear_eol(el, fx, sx,
    887 			    (int)((oe - old) - (ne - new)));
    888 		}
    889 	}
    890 	/*
    891          * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
    892          */
    893 	if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
    894 		ELRE_DEBUG(1, (__F, "late first diff insert at %td...\r\n",
    895 		    nfd - new));
    896 
    897 		terminal_move_to_char(el, (int)(nfd - new));
    898 		/*
    899 		 * Check if we have stuff to keep at the end
    900 		 */
    901 		if (nsb != ne) {
    902 			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
    903 			/*
    904 		         * We have to recalculate fx here because we set it
    905 		         * to zero above as a flag saying that we hadn't done
    906 		         * an early first insert.
    907 		         */
    908 			fx = (int)((nsb - nfd) - (osb - ofd));
    909 			if (fx > 0) {
    910 				/*
    911 				 * insert fx chars of new starting at nfd
    912 				 */
    913 				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
    914 				 "ERROR: cannot insert in late first diff\n"));
    915 				terminal_insertwrite(el, nfd, fx);
    916 				re_insert(el, old, (int)(ofd - old),
    917 				    el->el_terminal.t_size.h, nfd, fx);
    918 			}
    919 			/*
    920 		         * write (nsb-nfd) - fx chars of new starting at
    921 		         * (nfd + fx)
    922 			 */
    923 			len = (size_t) ((nsb - nfd) - fx);
    924 			terminal_overwrite(el, (nfd + fx), len);
    925 			re__strncopy(ofd + fx, nfd + fx, len);
    926 		} else {
    927 			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
    928 			len = (size_t) (nsb - nfd);
    929 			terminal_overwrite(el, nfd, len);
    930 			re__strncopy(ofd, nfd, len);
    931 		}
    932 	}
    933 	/*
    934          * line is now NEW up to nse
    935          */
    936 	if (sx >= 0) {
    937 		ELRE_DEBUG(1, (__F,
    938 		    "second diff insert at %d...\r\n", (int)(nse - new)));
    939 		terminal_move_to_char(el, (int)(nse - new));
    940 		if (ols != oe) {
    941 			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
    942 			if (sx > 0) {
    943 				/* insert sx chars of new starting at nse */
    944 				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
    945 				    "ERROR: cannot insert in second diff\n"));
    946 				terminal_insertwrite(el, nse, sx);
    947 			}
    948 			/*
    949 		         * write (nls-nse) - sx chars of new starting at
    950 			 * (nse + sx)
    951 		         */
    952 			terminal_overwrite(el, (nse + sx),
    953 			    (size_t)((nls - nse) - sx));
    954 		} else {
    955 			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
    956 			terminal_overwrite(el, nse, (size_t)(nls - nse));
    957 
    958 			/*
    959 	                 * No need to do a clear-to-end here because we were
    960 	                 * doing a second insert, so we will have over
    961 	                 * written all of the old string.
    962 		         */
    963 		}
    964 	}
    965 	ELRE_DEBUG(1, (__F, "done.\r\n"));
    966 }
    967 
    968 
    969 /* re__copy_and_pad():
    970  *	Copy string and pad with spaces
    971  */
    972 private void
    973 re__copy_and_pad(Char *dst, const Char *src, size_t width)
    974 {
    975 	size_t i;
    976 
    977 	for (i = 0; i < width; i++) {
    978 		if (*src == '\0')
    979 			break;
    980 		*dst++ = *src++;
    981 	}
    982 
    983 	for (; i < width; i++)
    984 		*dst++ = ' ';
    985 
    986 	*dst = '\0';
    987 }
    988 
    989 
    990 /* re_refresh_cursor():
    991  *	Move to the new cursor position
    992  */
    993 protected void
    994 re_refresh_cursor(EditLine *el)
    995 {
    996 	Char *cp;
    997 	int h, v, th, w;
    998 
    999 	if (el->el_line.cursor >= el->el_line.lastchar) {
   1000 		if (el->el_map.current == el->el_map.alt
   1001 		    && el->el_line.lastchar != el->el_line.buffer)
   1002 			el->el_line.cursor = el->el_line.lastchar - 1;
   1003 		else
   1004 			el->el_line.cursor = el->el_line.lastchar;
   1005 	}
   1006 
   1007 	/* first we must find where the cursor is... */
   1008 	h = el->el_prompt.p_pos.h;
   1009 	v = el->el_prompt.p_pos.v;
   1010 	th = el->el_terminal.t_size.h;	/* optimize for speed */
   1011 
   1012 	/* do input buffer to el->el_line.cursor */
   1013 	for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
   1014                 switch (ct_chr_class(*cp)) {
   1015 		case CHTYPE_NL:  /* handle newline in data part too */
   1016 			h = 0;
   1017 			v++;
   1018 			break;
   1019 		case CHTYPE_TAB: /* if a tab, to next tab stop */
   1020 			while (++h & 07)
   1021 				continue;
   1022 			break;
   1023 		default:
   1024 			w = Width(*cp);
   1025 			if (w > 1 && h + w > th) { /* won't fit on line */
   1026 				h = 0;
   1027 				v++;
   1028 			}
   1029 			h += ct_visual_width(*cp);
   1030 			break;
   1031                 }
   1032 
   1033 		if (h >= th) {	/* check, extra long tabs picked up here also */
   1034 			h -= th;
   1035 			v++;
   1036 		}
   1037 	}
   1038         /* if we have a next character, and it's a doublewidth one, we need to
   1039          * check whether we need to linebreak for it to fit */
   1040         if (cp < el->el_line.lastchar && (w = Width(*cp)) > 1)
   1041                 if (h + w > th) {
   1042                     h = 0;
   1043                     v++;
   1044                 }
   1045 
   1046 	/* now go there */
   1047 	terminal_move_to_line(el, v);
   1048 	terminal_move_to_char(el, h);
   1049 	terminal__flush(el);
   1050 }
   1051 
   1052 
   1053 /* re_fastputc():
   1054  *	Add a character fast.
   1055  */
   1056 private void
   1057 re_fastputc(EditLine *el, wint_t c)
   1058 {
   1059 	int w = Width((Char)c);
   1060 	while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h)
   1061 	    re_fastputc(el, ' ');
   1062 
   1063 	terminal__putc(el, c);
   1064 	el->el_display[el->el_cursor.v][el->el_cursor.h++] = (Char)c;
   1065 	while (--w > 0)
   1066 		el->el_display[el->el_cursor.v][el->el_cursor.h++]
   1067 			= MB_FILL_CHAR;
   1068 
   1069 	if (el->el_cursor.h >= el->el_terminal.t_size.h) {
   1070 		/* if we must overflow */
   1071 		el->el_cursor.h = 0;
   1072 
   1073 		/*
   1074 		 * If we would overflow (input is longer than terminal size),
   1075 		 * emulate scroll by dropping first line and shuffling the rest.
   1076 		 * We do this via pointer shuffling - it's safe in this case
   1077 		 * and we avoid memcpy().
   1078 		 */
   1079 		if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) {
   1080 			int i, lins = el->el_terminal.t_size.v;
   1081 			Char *firstline = el->el_display[0];
   1082 
   1083 			for(i = 1; i < lins; i++)
   1084 				el->el_display[i - 1] = el->el_display[i];
   1085 
   1086 			re__copy_and_pad(firstline, STR(""), (size_t)0);
   1087 			el->el_display[i - 1] = firstline;
   1088 		} else {
   1089 			el->el_cursor.v++;
   1090 			el->el_refresh.r_oldcv++;
   1091 		}
   1092 		if (EL_HAS_AUTO_MARGINS) {
   1093 			if (EL_HAS_MAGIC_MARGINS) {
   1094 				terminal__putc(el, ' ');
   1095 				terminal__putc(el, '\b');
   1096 			}
   1097 		} else {
   1098 			terminal__putc(el, '\r');
   1099 			terminal__putc(el, '\n');
   1100 		}
   1101 	}
   1102 }
   1103 
   1104 
   1105 /* re_fastaddc():
   1106  *	we added just one char, handle it fast.
   1107  *	Assumes that screen cursor == real cursor
   1108  */
   1109 protected void
   1110 re_fastaddc(EditLine *el)
   1111 {
   1112 	Char c;
   1113 	int rhdiff;
   1114 
   1115 	c = el->el_line.cursor[-1];
   1116 
   1117 	if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
   1118 		re_refresh(el);	/* too hard to handle */
   1119 		return;
   1120 	}
   1121 	rhdiff = el->el_terminal.t_size.h - el->el_cursor.h -
   1122 	    el->el_rprompt.p_pos.h;
   1123 	if (el->el_rprompt.p_pos.h && rhdiff < 3) {
   1124 		re_refresh(el);	/* clear out rprompt if less than 1 char gap */
   1125 		return;
   1126 	}			/* else (only do at end of line, no TAB) */
   1127 	switch (ct_chr_class(c)) {
   1128 	case CHTYPE_TAB: /* already handled, should never happen here */
   1129 		break;
   1130 	case CHTYPE_NL:
   1131 	case CHTYPE_PRINT:
   1132 		re_fastputc(el, c);
   1133 		break;
   1134 	case CHTYPE_ASCIICTL:
   1135 	case CHTYPE_NONPRINT: {
   1136 		Char visbuf[VISUAL_WIDTH_MAX];
   1137 		ssize_t i, n =
   1138 		    ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c);
   1139 		for (i = 0; n-- > 0; ++i)
   1140 			re_fastputc(el, visbuf[i]);
   1141 		break;
   1142 	}
   1143 	}
   1144 	terminal__flush(el);
   1145 }
   1146 
   1147 
   1148 /* re_clear_display():
   1149  *	clear the screen buffers so that new new prompt starts fresh.
   1150  */
   1151 protected void
   1152 re_clear_display(EditLine *el)
   1153 {
   1154 	int i;
   1155 
   1156 	el->el_cursor.v = 0;
   1157 	el->el_cursor.h = 0;
   1158 	for (i = 0; i < el->el_terminal.t_size.v; i++)
   1159 		el->el_display[i][0] = '\0';
   1160 	el->el_refresh.r_oldcv = 0;
   1161 }
   1162 
   1163 
   1164 /* re_clear_lines():
   1165  *	Make sure all lines are *really* blank
   1166  */
   1167 protected void
   1168 re_clear_lines(EditLine *el)
   1169 {
   1170 
   1171 	if (EL_CAN_CEOL) {
   1172 		int i;
   1173 		for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
   1174 			/* for each line on the screen */
   1175 			terminal_move_to_line(el, i);
   1176 			terminal_move_to_char(el, 0);
   1177 			terminal_clear_EOL(el, el->el_terminal.t_size.h);
   1178 		}
   1179 	} else {
   1180 		terminal_move_to_line(el, el->el_refresh.r_oldcv);
   1181 					/* go to last line */
   1182 		terminal__putc(el, '\r');	/* go to BOL */
   1183 		terminal__putc(el, '\n');	/* go to new line */
   1184 	}
   1185 }
   1186