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