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