Subject: lib/18103 - libedit fixes
To: None <netbsd-bugs@netbsd.org>
From: David Laight <david@l8s.co.uk>
List: netbsd-bugs
Date: 10/27/2002 19:27:05
(resend to nsd-bsdbugs following semd to gnats-bugs)

The following patch fixes a lot of problems with 'vi' style
editing in libedit.  There are still a few unimplemented
features (in particular '.').  But it is a lot better.

Also fixed are the unresolved parts of lib/16444 lib/17246
and lib/17954.  I did start fixing parts of lib/17163 but
the whole issue of malloc failing is too complicated.

Fixes include:

- undo works on more commands (eg r, R, C, S and ~)
- cursor left in correct place after undo
- deleting chars which in insert mode doesn't kill undo buffer
- paste buffer separated from undo buffer, so you can paste
  deleted text after an insert
- word delimiters fixed to match vi spec
- counts of words (eg c2w) work
- selecting words backwards
- count works on ~ and r
- window size changes are picked up
- ERASE char not restricted to inserted chars

The undo code was getting complicated!  Saving the entire line
and curser position made it trivial.

	David

Index: Makefile
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/Makefile,v
retrieving revision 1.23
diff -u -r1.23 Makefile
--- Makefile	2002/08/19 14:55:15	1.23
+++ Makefile	2002/10/27 17:25:59
@@ -36,7 +36,7 @@
 CPPFLAGS+=-I. -I${LIBEDITDIR} 
 CPPFLAGS+=-I. -I${.CURDIR}
 CPPFLAGS+=#-DDEBUG_TTY -DDEBUG_KEY -DDEBUG_READ -DDEBUG -DDEBUG_REFRESH
-CPPFLAGS+=#-DDEBUG_PASTE
+CPPFLAGS+=#-DDEBUG_PASTE -DDEBUG_EDIT
 
 AHDR=vi.h emacs.h common.h 
 ASRC=${LIBEDITDIR}/vi.c ${LIBEDITDIR}/emacs.c ${LIBEDITDIR}/common.c
Index: chared.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/chared.c,v
retrieving revision 1.15
diff -u -r1.15 chared.c
--- chared.c	2002/03/18 16:00:50	1.15
+++ chared.c	2002/10/27 17:26:01
@@ -58,17 +58,18 @@
  *	Handle state for the vi undo command
  */
 protected void
-cv_undo(EditLine *el,int action, size_t size, char *ptr)
+cv_undo(EditLine *el, int size, char *ptr)
 {
 	c_undo_t *vu = &el->el_chared.c_undo;
-	vu->action = action;
-	vu->ptr    = ptr;
-	vu->isize  = size;
-	(void) memcpy(vu->buf, vu->ptr, size);
-#ifdef DEBUG_UNDO
-	(void) fprintf(el->el_errfile, "Undo buffer \"%s\" size = +%d -%d\n",
-	       vu->ptr, vu->isize, vu->dsize);
-#endif
+
+	vu->len = el->el_line.lastchar - el->el_line.buffer;
+	vu->cursor = el->el_line.cursor - el->el_line.buffer;
+	memcpy(vu->buf, el->el_line.buffer, vu->len + 1u);
+
+	if (ptr) {
+		memcpy(vu->paste, ptr, size +0u);
+		vu->paste_len = size;
+	}
 }
 
 
@@ -102,12 +103,12 @@
 	if (el->el_line.cursor + num > el->el_line.lastchar)
 		num = el->el_line.lastchar - el->el_line.cursor;
 
+	if (el->el_map.current != el->el_map.emacs)
+		cv_undo(el, num, el->el_line.cursor);
+
 	if (num > 0) {
 		char *cp;
 
-		if (el->el_map.current != el->el_map.emacs)
-			cv_undo(el, INSERT, (size_t)num, el->el_line.cursor);
-
 		for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
 			*cp = cp[num];
 
@@ -126,13 +127,12 @@
 	if (el->el_line.cursor - num < el->el_line.buffer)
 		num = el->el_line.cursor - el->el_line.buffer;
 
+	if (el->el_map.current != el->el_map.emacs)
+		cv_undo(el, num, el->el_line.cursor - num);
+
 	if (num > 0) {
 		char *cp;
 
-		if (el->el_map.current != el->el_map.emacs)
-			cv_undo(el, INSERT, (size_t)num,
-			    el->el_line.cursor - num);
-
 		for (cp = el->el_line.cursor - num;
 		    cp <= el->el_line.lastchar;
 		    cp++)
@@ -149,7 +149,7 @@
 protected int
 ce__isword(int p)
 {
-	return (isalpha(p) || isdigit(p) || strchr("*?_-.[]~=", p) != NULL);
+	return (isalnum(p) || strchr("*?_-.[]~=", p) != NULL);
 }
 
 
@@ -159,6 +159,16 @@
 protected int
 cv__isword(int p)
 {
+	return (isalnum(p));
+}
+
+
+/* cv__isWord():
+ *	Return if p is part of a big word according to vi
+ */
+protected int
+cv__isWord(int p)
+{
 	return (!isspace(p));
 }
 
@@ -221,7 +231,7 @@
 		 * vi historically deletes with cw only the word preserving the
 		 * trailing whitespace! This is not what 'w' does..
 		 */
-		if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
+		if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
 			while ((p < high) && isspace((unsigned char) *p))
 				p++;
 	}
@@ -238,26 +248,19 @@
  *	Find the previous word vi style
  */
 protected char *
-cv_prev_word(EditLine *el, char *p, char *low, int n, int (*wtest)(int))
+cv_prev_word(char *p, char *low, int n, int (*wtest)(int))
 {
 	int test;
 
+	p--;
 	while (n--) {
-		p--;
-		/*
-		 * vi historically deletes with cb only the word preserving the
-		 * leading whitespace! This is not what 'b' does..
-		 */
-		if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
-			while ((p > low) && isspace((unsigned char) *p))
-				p--;
+		while ((p > low) && isspace((unsigned char) *p))
+			p--;
 		test = (*wtest)((unsigned char) *p);
 		while ((p >= low) && (*wtest)((unsigned char) *p) == test)
 			p--;
-		p++;
-		while (isspace((unsigned char) *p))
-			p++;
 	}
+	p++;
 
 	/* p now points where we want it */
 	if (p < low)
@@ -308,47 +311,27 @@
 cv_delfini(EditLine *el)
 {
 	int size;
-	int oaction;
 
 	if (el->el_chared.c_vcmd.action & INSERT)
 		el->el_map.current = el->el_map.key;
 
-	oaction = el->el_chared.c_vcmd.action;
 	el->el_chared.c_vcmd.action = NOP;
 
 	if (el->el_chared.c_vcmd.pos == 0)
 		return;
-
 
-	if (el->el_line.cursor > el->el_chared.c_vcmd.pos) {
-		size = (int) (el->el_line.cursor - el->el_chared.c_vcmd.pos);
-		c_delbefore(el, size);
-		el->el_line.cursor = el->el_chared.c_vcmd.pos;
-		re_refresh_cursor(el);
-	} else if (el->el_line.cursor < el->el_chared.c_vcmd.pos) {
-		size = (int)(el->el_chared.c_vcmd.pos - el->el_line.cursor);
+	size = (int) (el->el_line.cursor - el->el_chared.c_vcmd.pos);
+	el->el_line.cursor = el->el_chared.c_vcmd.pos;
+	if (size > 0) {
 		c_delafter(el, size);
+		re_refresh_cursor(el);
+	} else if (size < 0) {
+		c_delbefore(el, -size);
+		el->el_line.cursor += size;
 	} else {
-		size = 1;
-		c_delafter(el, size);
+		c_delafter(el, 1);
+		el->el_line.cursor--;
 	}
-	switch (oaction) {
-	case DELETE|INSERT:
-		el->el_chared.c_undo.action = DELETE|INSERT;
-		break;
-	case DELETE:
-		el->el_chared.c_undo.action = INSERT;
-		break;
-	case NOP:
-	case INSERT:
-	default:
-		EL_ABORT((el->el_errfile, "Bad oaction %d\n", oaction));
-		break;
-	}
-
-
-	el->el_chared.c_undo.ptr = el->el_line.cursor;
-	el->el_chared.c_undo.dsize = size;
 }
 
 
@@ -378,21 +361,19 @@
  *	Go to the end of this word according to vi
  */
 protected char *
-cv__endword(char *p, char *high, int n)
+cv__endword(char *p, char *high, int n, int (*wtest)(int))
 {
+	int test;
+
 	p++;
 
 	while (n--) {
 		while ((p < high) && isspace((unsigned char) *p))
 			p++;
 
-		if (isalnum((unsigned char) *p))
-			while ((p < high) && isalnum((unsigned char) *p))
-				p++;
-		else
-			while ((p < high) && !(isspace((unsigned char) *p) ||
-			    isalnum((unsigned char) *p)))
-				p++;
+		test = (*wtest)((unsigned char) *p);
+		while ((p < high) && (*wtest)((unsigned char) *p) == test)
+			p++;
 	}
 	p--;
 	return (p);
@@ -411,20 +392,21 @@
 	(void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
 	el->el_line.cursor		= el->el_line.buffer;
 	el->el_line.lastchar		= el->el_line.buffer;
-	el->el_line.limit		= &el->el_line.buffer[EL_BUFSIZ - 2];
+	el->el_line.limit		= &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE];
 
 	el->el_chared.c_undo.buf	= (char *) el_malloc(EL_BUFSIZ);
 	if (el->el_chared.c_undo.buf == NULL)
 		return (-1);
 	(void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
-	el->el_chared.c_undo.action	= NOP;
-	el->el_chared.c_undo.isize	= 0;
-	el->el_chared.c_undo.dsize	= 0;
-	el->el_chared.c_undo.ptr	= el->el_line.buffer;
+	el->el_chared.c_undo.len	= -1;
+	el->el_chared.c_undo.cursor	= 0;
+	el->el_chared.c_undo.paste	= (char *) el_malloc(EL_BUFSIZ);
+	if (el->el_chared.c_undo.paste == NULL)
+		return (-1);
+	el->el_chared.c_undo.paste_len	= 0;
 
 	el->el_chared.c_vcmd.action	= NOP;
 	el->el_chared.c_vcmd.pos	= el->el_line.buffer;
-	el->el_chared.c_vcmd.ins	= el->el_line.buffer;
 
 	el->el_chared.c_kill.buf	= (char *) el_malloc(EL_BUFSIZ);
 	if (el->el_chared.c_kill.buf == NULL)
@@ -459,14 +441,11 @@
 	el->el_line.cursor		= el->el_line.buffer;
 	el->el_line.lastchar		= el->el_line.buffer;
 
-	el->el_chared.c_undo.action	= NOP;
-	el->el_chared.c_undo.isize	= 0;
-	el->el_chared.c_undo.dsize	= 0;
-	el->el_chared.c_undo.ptr	= el->el_line.buffer;
+	el->el_chared.c_undo.len	= -1;
+	el->el_chared.c_undo.cursor	= 0;
 
 	el->el_chared.c_vcmd.action	= NOP;
 	el->el_chared.c_vcmd.pos	= el->el_line.buffer;
-	el->el_chared.c_vcmd.ins	= el->el_line.buffer;
 
 	el->el_chared.c_kill.mark	= el->el_line.buffer;
 
@@ -521,7 +500,8 @@
 	el->el_line.buffer = newbuffer;
 	el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
 	el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
-	el->el_line.limit  = &newbuffer[newsz - EL_LEAVE];
+	/* don't set new size until all buffers are enlarged */
+	el->el_line.limit  = &newbuffer[sz - EL_LEAVE];
 
 	/*
 	 * Reallocate kill buffer.
@@ -550,14 +530,18 @@
 
 	/* zero the newly added memory, leave old data in */
 	(void) memset(&newbuffer[sz], 0, newsz - sz);
-
-	el->el_chared.c_undo.ptr = el->el_line.buffer +
-				    (el->el_chared.c_undo.ptr - oldbuf);
 	el->el_chared.c_undo.buf = newbuffer;
+
+	newbuffer = el_realloc(el->el_chared.c_undo.paste, newsz);
+	if (!newbuffer)
+		return 0;
+	el->el_chared.c_undo.paste = newbuffer;
 	
 	if (!hist_enlargebuf(el, sz, newsz))
 		return 0;
 
+	/* Safe to set enlarged buffer size */
+	el->el_line.limit  = &newbuffer[newsz - EL_LEAVE];
 	return 1;
 }
 
@@ -572,6 +556,9 @@
 	el->el_line.limit = NULL;
 	el_free((ptr_t) el->el_chared.c_undo.buf);
 	el->el_chared.c_undo.buf = NULL;
+	el_free((ptr_t) el->el_chared.c_undo.paste);
+	el->el_chared.c_undo.paste = NULL;
+	el->el_chared.c_undo.paste_len	= 0;
 	el_free((ptr_t) el->el_chared.c_kill.buf);
 	el->el_chared.c_kill.buf = NULL;
 	el_free((ptr_t) el->el_chared.c_macro.macro);
Index: chared.h
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/chared.h,v
retrieving revision 1.8
diff -u -r1.8 chared.h
--- chared.h	2002/03/18 16:00:51	1.8
+++ chared.h	2002/10/27 17:26:02
@@ -71,14 +71,14 @@
 } c_macro_t;
 
 /*
- * Undo information for both vi and emacs
+ * Undo information for vi - no undo in emacs (yet)
  */
 typedef struct c_undo_t {
-	int	 action;
-	size_t	 isize;
-	size_t	 dsize;
-	char	*ptr;
-	char	*buf;
+	int	 len;			/* length of saved line */
+	int	 cursor;		/* position of saved cursor */
+	char	*buf;			/* full saved text */
+	size_t	 paste_len;		/* bytes to paste */
+	char	*paste;			/* paste string */
 } c_undo_t;
 
 /*
@@ -87,7 +87,6 @@
 typedef struct c_vcmd_t {
 	int	 action;
 	char	*pos;
-	char	*ins;
 } c_vcmd_t;
 
 /*
@@ -120,7 +119,6 @@
 #define	NOP		0x00
 #define	DELETE		0x01
 #define	INSERT		0x02
-#define	CHANGE		0x04
 
 #define	CHAR_FWD	0
 #define	CHAR_BACK	1
@@ -137,12 +135,13 @@
 
 
 protected int	 cv__isword(int);
+protected int	 cv__isWord(int);
 protected void	 cv_delfini(EditLine *);
-protected char	*cv__endword(char *, char *, int);
+protected char	*cv__endword(char *, char *, int, int (*)(int));
 protected int	 ce__isword(int);
-protected void	 cv_undo(EditLine *, int, size_t, char *);
+protected void	 cv_undo(EditLine *, /* int,*/ int, char *);
 protected char	*cv_next_word(EditLine*, char *, char *, int, int (*)(int));
-protected char	*cv_prev_word(EditLine*, char *, char *, int, int (*)(int));
+protected char	*cv_prev_word(char *, char *, int, int (*)(int));
 protected char	*c__next_word(char *, char *, int, int (*)(int));
 protected char	*c__prev_word(char *, char *, int, int (*)(int));
 protected void	 c_insert(EditLine *, int);
Index: common.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/common.c,v
retrieving revision 1.11
diff -u -r1.11 common.c
--- common.c	2002/03/18 16:00:51	1.11
+++ common.c	2002/10/27 17:26:06
@@ -72,7 +72,6 @@
 protected el_action_t
 ed_insert(EditLine *el, int c)
 {
-	int i;
 
 	if (c == '\0')
 		return (CC_ERROR);
@@ -85,29 +84,16 @@
 	}
 
 	if (el->el_state.argument == 1) {
-		if (el->el_state.inputmode != MODE_INSERT) {
-			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] =
-			    *el->el_line.cursor;
-			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] =
-			    '\0';
-			c_delafter(el, 1);
-		}
-		c_insert(el, 1);
+		if (el->el_state.inputmode == MODE_INSERT
+		    || el->el_line.cursor >= el->el_line.lastchar)
+			c_insert(el, 1);
 
 		*el->el_line.cursor++ = c;
 		el->el_state.doingarg = 0;	/* just in case */
 		re_fastaddc(el);		/* fast refresh for one char. */
 	} else {
-		if (el->el_state.inputmode != MODE_INSERT) {
-			for (i = 0; i < el->el_state.argument; i++)
-				el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] =
-				    el->el_line.cursor[i];
-
-			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] =
-			    '\0';
-			c_delafter(el, el->el_state.argument);
-		}
-		c_insert(el, el->el_state.argument);
+		if (el->el_state.inputmode != MODE_REPLACE_1)
+			c_insert(el, el->el_state.argument);
 
 		while (el->el_state.argument--)
 			*el->el_line.cursor++ = c;
@@ -115,7 +101,7 @@
 	}
 
 	if (el->el_state.inputmode == MODE_REPLACE_1)
-		(void) vi_command_mode(el, 0);
+		return vi_command_mode(el, 0);
 
 	return (CC_NORM);
 }
@@ -411,25 +397,9 @@
 			    (el->el_state.argument * 10) + (c - '0');
 		}
 		return (CC_ARGHACK);
-	} else {
-		if (el->el_line.lastchar + 1 >= el->el_line.limit) {
-			if (!ch_enlargebufs(el, 1))
-				return (CC_ERROR);
-		}
-
-		if (el->el_state.inputmode != MODE_INSERT) {
-			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] =
-			    *el->el_line.cursor;
-			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] =
-			    '\0';
-			c_delafter(el, 1);
-		}
-		c_insert(el, 1);
-		*el->el_line.cursor++ = c;
-		el->el_state.doingarg = 0;
-		re_fastaddc(el);
 	}
-	return (CC_NORM);
+
+	return ed_insert(el, c);
 }
 
 
@@ -579,8 +549,6 @@
 	re_goto_bottom(el);
 	*el->el_line.lastchar++ = '\n';
 	*el->el_line.lastchar = '\0';
-	if (el->el_map.type == MAP_VI)
-		el->el_chared.c_vcmd.ins = el->el_line.buffer;
 	return (CC_NEWLINE);
 }
 
@@ -670,7 +638,7 @@
 {
 	char beep = 0;
 
-	el->el_chared.c_undo.action = NOP;
+	el->el_chared.c_undo.len = -1;
 	*el->el_line.lastchar = '\0';		/* just in case */
 
 	if (el->el_history.eventno == 0) {	/* save the current buffer
@@ -704,7 +672,7 @@
 ed_next_history(EditLine *el, int c)
 {
 
-	el->el_chared.c_undo.action = NOP;
+	el->el_chared.c_undo.len = -1;
 	*el->el_line.lastchar = '\0';	/* just in case */
 
 	el->el_history.eventno -= el->el_state.argument;
@@ -730,7 +698,7 @@
 	bool_t found = 0;
 
 	el->el_chared.c_vcmd.action = NOP;
-	el->el_chared.c_undo.action = NOP;
+	el->el_chared.c_undo.len = -1;
 	*el->el_line.lastchar = '\0';	/* just in case */
 	if (el->el_history.eventno < 0) {
 #ifdef DEBUG_EDIT
@@ -798,7 +766,7 @@
 	bool_t found = 0;
 
 	el->el_chared.c_vcmd.action = NOP;
-	el->el_chared.c_undo.action = NOP;
+	el->el_chared.c_undo.len = -1;
 	*el->el_line.lastchar = '\0';	/* just in case */
 
 	if (el->el_history.eventno == 0)
Index: el.h
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/el.h,v
retrieving revision 1.11
diff -u -r1.11 el.h
--- el.h	2002/03/18 16:00:52	1.11
+++ el.h	2002/10/27 17:26:09
@@ -137,8 +137,12 @@
 protected int	el_editmode(EditLine *, int, const char **);
 
 #ifdef DEBUG
-#define EL_ABORT(a)	(void) (fprintf(el->el_errfile, "%s, %d: ", \
-				__FILE__, __LINE__), fprintf a, abort())
+#define	EL_ABORT(a)	do { \
+				fprintf(el->el_errfile, "%s, %d: ", \
+					 __FILE__, __LINE__); \
+				fprintf a; \
+				abort(); \
+			} while( /*CONSTCOND*/0);
 #else
 #define EL_ABORT(a)	abort()
 #endif
Index: emacs.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/emacs.c,v
retrieving revision 1.10
diff -u -r1.10 emacs.c
--- emacs.c	2002/03/18 16:00:52	1.10
+++ emacs.c	2002/10/27 17:26:09
@@ -215,7 +215,7 @@
 {
 	char *kp, *cp;
 
-	if (el->el_chared.c_kill.mark)
+	if (!el->el_chared.c_kill.mark)
 		return (CC_ERROR);
 
 	if (el->el_chared.c_kill.mark > el->el_line.cursor) {
Index: map.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/map.c,v
retrieving revision 1.15
diff -u -r1.15 map.c
--- map.c	2002/03/18 16:00:55	1.15
+++ map.c	2002/10/27 17:26:14
@@ -379,7 +379,7 @@
 	/*   5 */	ED_MOVE_TO_END,		/* ^E */
 	/*   6 */	ED_NEXT_CHAR,		/* ^F */
 	/*   7 */	ED_UNASSIGNED,		/* ^G */
-	/*   8 */	ED_DELETE_PREV_CHAR,	/* ^H */   /* BackSpace key */
+	/*   8 */	VI_DELETE_PREV_CHAR,	/* ^H */   /* BackSpace key */
 	/*   9 */	ED_UNASSIGNED,		/* ^I */   /* Tab Key */
 	/*  10 */	ED_NEWLINE,		/* ^J */
 	/*  11 */	ED_KILL_LINE,		/* ^K */
@@ -499,7 +499,7 @@
 	/* 124 */	ED_INSERT,		/* | */
 	/* 125 */	ED_INSERT,		/* } */
 	/* 126 */	ED_INSERT,		/* ~ */
-	/* 127 */	ED_DELETE_PREV_CHAR,	/* ^? */
+	/* 127 */	VI_DELETE_PREV_CHAR,	/* ^? */
 	/* 128 */	ED_UNASSIGNED,		/* M-^@ */
 	/* 129 */	ED_UNASSIGNED,		/* M-^A */
 	/* 130 */	ED_UNASSIGNED,		/* M-^B */
@@ -639,7 +639,7 @@
 	/*   5 */	ED_MOVE_TO_END,		/* ^E */
 	/*   6 */	ED_UNASSIGNED,		/* ^F */
 	/*   7 */	ED_UNASSIGNED,		/* ^G */
-	/*   8 */	ED_PREV_CHAR,		/* ^H */
+	/*   8 */	ED_DELETE_PREV_CHAR,	/* ^H */
 	/*   9 */	ED_UNASSIGNED,		/* ^I */
 	/*  10 */	ED_NEWLINE,		/* ^J */
 	/*  11 */	ED_KILL_LINE,		/* ^K */
@@ -697,10 +697,10 @@
 	/*  63 */	VI_SEARCH_NEXT,		/* ? */
 	/*  64 */	ED_UNASSIGNED,		/* @ */
 	/*  65 */	VI_ADD_AT_EOL,		/* A */
-	/*  66 */	VI_PREV_SPACE_WORD,	/* B */
+	/*  66 */	VI_PREV_BIG_WORD,	/* B */
 	/*  67 */	VI_CHANGE_TO_EOL,	/* C */
 	/*  68 */	ED_KILL_LINE,		/* D */
-	/*  69 */	VI_TO_END_WORD,		/* E */
+	/*  69 */	VI_END_BIG_WORD,	/* E */
 	/*  70 */	VI_PREV_CHAR,		/* F */
 	/*  71 */	ED_UNASSIGNED,		/* G */
 	/*  72 */	ED_UNASSIGNED,		/* H */
@@ -718,7 +718,7 @@
 	/*  84 */	VI_TO_PREV_CHAR,	/* T */
 	/*  85 */	ED_UNASSIGNED,		/* U */
 	/*  86 */	ED_UNASSIGNED,		/* V */
-	/*  87 */	VI_NEXT_SPACE_WORD,	/* W */
+	/*  87 */	VI_NEXT_BIG_WORD,	/* W */
 	/*  88 */	ED_DELETE_PREV_CHAR,	/* X */
 	/*  89 */	ED_UNASSIGNED,		/* Y */
 	/*  90 */	ED_UNASSIGNED,		/* Z */
Index: read.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/read.c,v
retrieving revision 1.21
diff -u -r1.21 read.c
--- read.c	2002/03/18 16:00:57	1.21
+++ read.c	2002/10/27 17:26:16
@@ -389,6 +389,11 @@
 			*nread = el->el_line.cursor - el->el_line.buffer;
 		return (el->el_line.buffer);
 	}
+
+	/* This is relatively cheap, and things go terribly wrong if
+	   we have the wrong size. */
+	el_resize(el);
+
 	re_clear_display(el);	/* reset the display stuff */
 	ch_reset(el);
 
@@ -434,6 +439,7 @@
 			*nread = el->el_line.cursor - el->el_line.buffer;
 		return (el->el_line.buffer);
 	}
+
 	for (num = OKCMD; num == OKCMD;) {	/* while still editing this
 						 * line */
 #ifdef DEBUG_EDIT
@@ -470,6 +476,10 @@
 		}
 #endif /* DEBUG_READ */
 		retval = (*el->el_map.func[cmdnum]) (el, ch);
+#ifdef DEBUG_READ
+		(void) fprintf(el->el_errfile,
+			"Returned state %d\n", retval );
+#endif /* DEBUG_READ */
 
 		/* save the last command here */
 		el->el_state.lastcmd = cmdnum;
@@ -544,9 +554,9 @@
 		}
 	}
 
-				/* make sure the tty is set up correctly */
-	(void) tty_cookedmode(el);
 	term__flush();		/* flush any buffered output */
+	/* make sure the tty is set up correctly */
+	(void) tty_cookedmode(el);
 	if (el->el_flags & HANDLE_SIGNALS)
 		sig_clr(el);
 	if (nread)
Index: readline.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/readline.c,v
retrieving revision 1.22
diff -u -r1.22 readline.c
--- readline.c	2002/04/09 01:57:34	1.22
+++ readline.c	2002/10/27 17:26:21
@@ -287,10 +287,9 @@
 	/* get one line from input stream */
 	ret = el_gets(e, &count);
 
-	if (ret && count > 0) {
+	if (ret && count > 0 && (buf = strdup(ret))) {
 		int lastidx;
 
-		buf = strdup(ret);
 		lastidx = count - 1;
 		if (buf[lastidx] == '\n')
 			buf[lastidx] = '\0';
@@ -328,7 +327,7 @@
 _rl_compat_sub(const char *str, const char *what, const char *with,
     int globally)
 {
-	char *result;
+	char *result, *r;
 	const char *temp, *new;
 	int len, with_len, what_len, add;
 	size_t size, i;
@@ -345,7 +344,12 @@
 			add = i + with_len;
 			if (i + add + 1 >= size) {
 				size += add + 1;
-				result = realloc(result, size);
+				r = realloc(result, size);
+				if (!r) {
+					free(result);
+					return 0;
+				}
+				result = r;
 			}
 			(void) strncpy(&result[len], temp, i);
 			len += i;
@@ -356,7 +360,12 @@
 			add = strlen(temp);
 			if (len + add + 1 >= size) {
 				size += add + 1;
-				result = realloc(result, size);
+				r = realloc(result, size);
+				if (!r) {
+					free(result);
+					return 0;
+				}
+				result = r;
 			}
 			(void) strcpy(&result[len], temp);	/* safe */
 			len += add;
@@ -576,8 +585,10 @@
 
 				tempcmd = _rl_compat_sub(line, from, to,
 				    (g_on) ? 1 : 0);
-				free(line);
-				line = tempcmd;
+				if (tempcmd) {
+					free(line);
+					line = tempcmd;
+				}
 				g_on = 0;
 			}
 		}
@@ -790,11 +801,17 @@
 		}
 
 		if (result_idx + 2 >= size) {
+			char **r;
 			size <<= 1;
-			result = realloc(result, size * sizeof(char *));
+			r = realloc(result, size * sizeof(char *));
+			if (!r)
+				break;
+			result = r;
 		}
 		len = i - start;
 		temp = malloc(len + 1);
+		if (!temp)
+			break;
 		(void) strncpy(temp, &str[start], len);
 		temp[len] = '\0';
 		result[result_idx++] = temp;
@@ -1331,10 +1348,15 @@
 	matches = 0;
 	match_list_len = 1;
 	while ((retstr = (*genfunc) (text, matches)) != NULL) {
-		if (matches + 1 >= match_list_len) {
+		/* allow for list terminater here */
+		if (matches + 2 >= match_list_len) {
+			char **nml;
 			match_list_len <<= 1;
-			match_list = realloc(match_list,
+			nml = realloc(match_list,
 			    match_list_len * sizeof(char *));
+			if (!nml)
+				break;
+			match_list = nml;
 		}
 		match_list[++matches] = retstr;
 	}
@@ -1354,14 +1376,15 @@
 	}
 
 	retstr = malloc(max_equal + 1);
-	(void) strncpy(retstr, match_list[1], max_equal);
-	retstr[max_equal] = '\0';
-	match_list[0] = retstr;
+	if (retstr) {
+		(void) strncpy(retstr, match_list[1], max_equal);
+		retstr[max_equal] = '\0';
+		match_list[0] = retstr;
+	} else
+		/* avoid leaking memory */
+		match_list[0] = match_list[matches--];
 
 	/* add NULL as last pointer to the array */
-	if (matches + 1 >= match_list_len)
-		match_list = realloc(match_list,
-		    (match_list_len + 1) * sizeof(char *));
 	match_list[matches + 1] = (char *) NULL;
 
 	return (match_list);
Index: refresh.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/refresh.c,v
retrieving revision 1.18
diff -u -r1.18 refresh.c
--- refresh.c	2002/03/18 16:00:58	1.18
+++ refresh.c	2002/10/27 17:26:25
@@ -64,21 +64,21 @@
 private void	re__copy_and_pad(char *, const char *, size_t);
 
 #ifdef DEBUG_REFRESH
-private void	re_printstr(EditLine *, char *, char *, char *);
+private void	re_printstr(EditLine *, const char *, char *, char *);
 #define	__F el->el_errfile
 #define	ELRE_ASSERT(a, b, c)	do 				\
-				    if (a) {			\
+				    if (/*CONSTCOND*/ a) {	\
 					(void) fprintf b;	\
 					c;			\
 				    }				\
-				while (0)
+				while (/*CONSTCOND*/0)
 #define	ELRE_DEBUG(a, b)	ELRE_ASSERT(a,b,;)
 
 /* re_printstr():
  *	Print a string on the debugging pty
  */
 private void
-re_printstr(EditLine *el, char *str, char *f, char *t)
+re_printstr(EditLine *el, const char *str, char *f, char *t)
 {
 
 	ELRE_DEBUG(1, (__F, "%s:\"", str));
@@ -318,7 +318,6 @@
 {
 
 	term_move_to_line(el, el->el_refresh.r_oldcv);
-	term__putc('\r');
 	term__putc('\n');
 	re_clear_display(el);
 	term__flush();
Index: tokenizer.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/tokenizer.c,v
retrieving revision 1.10
diff -u -r1.10 tokenizer.c
--- tokenizer.c	2002/03/18 16:01:00	1.10
+++ tokenizer.c	2002/10/27 17:26:27
@@ -109,16 +109,19 @@
 {
 	Tokenizer *tok = (Tokenizer *) tok_malloc(sizeof(Tokenizer));
 
+	if (!tok)
+		return 0;
+
 	tok->ifs = strdup(ifs ? ifs : IFS);
+	tok->argv = (char **) tok_malloc(sizeof(char *) * tok->amax);
+	tok->wspace = (char *) tok_malloc(WINCR);
+	if (!tok->ifs || !tok->argv || !tok->wspace) {
+		tok_end(tok);
+		return 0;
+	}
 	tok->argc = 0;
 	tok->amax = AINCR;
-	tok->argv = (char **) tok_malloc(sizeof(char *) * tok->amax);
-	if (tok->argv == NULL)
-		return (NULL);
 	tok->argv[0] = NULL;
-	tok->wspace = (char *) tok_malloc(WINCR);
-	if (tok->wspace == NULL)
-		return (NULL);
 	tok->wmax = tok->wspace + WINCR;
 	tok->wstart = tok->wspace;
 	tok->wptr = tok->wspace;
Index: vi.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libedit/vi.c,v
retrieving revision 1.9
diff -u -r1.9 vi.c
--- vi.c	2002/03/18 16:01:01	1.9
+++ vi.c	2002/10/27 17:26:29
@@ -59,22 +59,14 @@
 private el_action_t
 cv_action(EditLine *el, int c)
 {
-	char *cp, *kp;
 
 	if (el->el_chared.c_vcmd.action & DELETE) {
+		/* 'dd' and (possibly) friends */
 		el->el_chared.c_vcmd.action = NOP;
 		el->el_chared.c_vcmd.pos = 0;
 
-		el->el_chared.c_undo.isize = 0;
-		el->el_chared.c_undo.dsize = 0;
-		kp = el->el_chared.c_undo.buf;
-		for (cp = el->el_line.buffer; cp < el->el_line.lastchar; cp++) {
-			*kp++ = *cp;
-			el->el_chared.c_undo.dsize++;
-		}
-
-		el->el_chared.c_undo.action = INSERT;
-		el->el_chared.c_undo.ptr = el->el_line.buffer;
+		cv_undo(el, el->el_line.lastchar - el->el_line.buffer,
+				el->el_line.buffer );
 		el->el_line.lastchar = el->el_line.buffer;
 		el->el_line.cursor = el->el_line.buffer;
 		if (c & INSERT)
@@ -103,7 +95,6 @@
 #endif
 }
 
-
 /* cv_paste():
  *	Paste previous deletion before or after the cursor
  */
@@ -114,20 +105,22 @@
 	c_undo_t *un = &el->el_chared.c_undo;
 
 #ifdef DEBUG_PASTE
-	(void) fprintf(el->el_errfile, "Paste: %x \"%s\" +%d -%d\n",
-	    un->action, un->buf, un->isize, un->dsize);
+	(void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n",
+	    (int)un->paste_len, un->paste ? un->paste : "<null>" );
 #endif
-	if (un->isize == 0)
+	if (!un->paste || !un->paste_len)
 		return (CC_ERROR);
 
+	cv_undo(el, 0, 0);
+
 	if (!c && el->el_line.cursor < el->el_line.lastchar)
 		el->el_line.cursor++;
 	ptr = el->el_line.cursor;
 
-	c_insert(el, (int) un->isize);
-	if (el->el_line.cursor + un->isize > el->el_line.lastchar)
+	c_insert(el, (int) un->paste_len);
+	if (el->el_line.cursor + un->paste_len > el->el_line.lastchar)
 		return (CC_ERROR);
-	(void) memcpy(ptr, un->buf, un->isize);
+	(void) memcpy(ptr, un->paste, un->paste_len);
 	return (CC_REFRESH);
 }
 
@@ -158,22 +151,22 @@
 }
 
 
-/* vi_prev_space_word():
+/* vi_prev_big_word():
  *	Vi move to the previous space delimited word
  *	[B]
  */
 protected el_action_t
 /*ARGSUSED*/
-vi_prev_space_word(EditLine *el, int c)
+vi_prev_big_word(EditLine *el, int c)
 {
 
 	if (el->el_line.cursor == el->el_line.buffer)
 		return (CC_ERROR);
 
-	el->el_line.cursor = cv_prev_word(el, el->el_line.cursor,
+	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
 	    el->el_line.buffer,
 	    el->el_state.argument,
-	    cv__isword);
+	    cv__isWord);
 
 	if (el->el_chared.c_vcmd.action & DELETE) {
 		cv_delfini(el);
@@ -185,7 +178,7 @@
 
 /* vi_prev_word():
  *	Vi move to the previous word
- *	[B]
+ *	[b]
  */
 protected el_action_t
 /*ARGSUSED*/
@@ -195,10 +188,10 @@
 	if (el->el_line.cursor == el->el_line.buffer)
 		return (CC_ERROR);
 
-	el->el_line.cursor = cv_prev_word(el, el->el_line.cursor,
+	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
 	    el->el_line.buffer,
 	    el->el_state.argument,
-	    ce__isword);
+	    cv__isword);
 
 	if (el->el_chared.c_vcmd.action & DELETE) {
 		cv_delfini(el);
@@ -208,13 +201,13 @@
 }
 
 
-/* vi_next_space_word():
+/* vi_next_big_word():
  *	Vi move to the next space delimited word
  *	[W]
  */
 protected el_action_t
 /*ARGSUSED*/
-vi_next_space_word(EditLine *el, int c)
+vi_next_big_word(EditLine *el, int c)
 {
 
 	if (el->el_line.cursor == el->el_line.lastchar)
@@ -223,7 +216,7 @@
 	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
 	    el->el_line.lastchar,
 	    el->el_state.argument,
-	    cv__isword);
+	    cv__isWord);
 
 	if (el->el_map.type == MAP_VI)
 		if (el->el_chared.c_vcmd.action & DELETE) {
@@ -249,7 +242,7 @@
 	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
 	    el->el_line.lastchar,
 	    el->el_state.argument,
-	    ce__isword);
+	    cv__isword);
 
 	if (el->el_map.type == MAP_VI)
 		if (el->el_chared.c_vcmd.action & DELETE) {
@@ -267,8 +260,15 @@
 protected el_action_t
 vi_change_case(EditLine *el, int c)
 {
+	int i;
 
-	if (el->el_line.cursor < el->el_line.lastchar) {
+	if (el->el_line.cursor >= el->el_line.lastchar)
+		return (CC_ERROR);
+	cv_undo(el, 0, 0);
+	for (i = 0; i < el->el_state.argument; i++) {
+		if (el->el_line.cursor >= el->el_line.lastchar)
+			break;
+
 		c = *el->el_line.cursor;
 		if (isupper(c))
 			*el->el_line.cursor++ = tolower(c);
@@ -277,9 +277,8 @@
 		else
 			el->el_line.cursor++;
 		re_fastaddc(el);
-		return (CC_NORM);
 	}
-	return (CC_ERROR);
+	return (CC_NORM);
 }
 
 
@@ -310,11 +309,7 @@
 {
 
 	el->el_line.cursor = el->el_line.buffer;
-	el->el_chared.c_vcmd.ins = el->el_line.cursor;
-
-	el->el_chared.c_undo.ptr = el->el_line.cursor;
-	el->el_chared.c_undo.action = DELETE;
-
+	cv_undo(el, 0, 0);
 	el->el_map.current = el->el_map.key;
 	return (CC_CURSOR);
 }
@@ -329,13 +324,13 @@
 vi_replace_char(EditLine *el, int c)
 {
 
+	if (el->el_state.argument > el->el_line.lastchar - el->el_line.cursor)
+		return CC_ERROR;
+
 	el->el_map.current = el->el_map.key;
 	el->el_state.inputmode = MODE_REPLACE_1;
-	el->el_chared.c_undo.action = CHANGE;
-	el->el_chared.c_undo.ptr = el->el_line.cursor;
-	el->el_chared.c_undo.isize = 0;
-	el->el_chared.c_undo.dsize = 0;
-	return (CC_NORM);
+	cv_undo(el, 0, 0);
+	return (CC_ARGHACK);
 }
 
 
@@ -350,17 +345,14 @@
 
 	el->el_map.current = el->el_map.key;
 	el->el_state.inputmode = MODE_REPLACE;
-	el->el_chared.c_undo.action = CHANGE;
-	el->el_chared.c_undo.ptr = el->el_line.cursor;
-	el->el_chared.c_undo.isize = 0;
-	el->el_chared.c_undo.dsize = 0;
+	cv_undo(el, 0, 0);
 	return (CC_NORM);
 }
 
 
 /* vi_substitute_char():
  *	Vi replace character under the cursor and enter insert mode
- *	[r]
+ *	[s]
  */
 protected el_action_t
 /*ARGSUSED*/
@@ -382,6 +374,8 @@
 vi_substitute_line(EditLine *el, int c)
 {
 
+	cv_undo(el, el->el_line.lastchar - el->el_line.buffer,
+		el->el_line.buffer);
 	(void) em_kill_line(el, 0);
 	el->el_map.current = el->el_map.key;
 	return (CC_REFRESH);
@@ -397,6 +391,8 @@
 vi_change_to_eol(EditLine *el, int c)
 {
 
+	cv_undo(el, el->el_line.lastchar - el->el_line.cursor,
+		el->el_line.cursor);
 	(void) ed_kill_line(el, 0);
 	el->el_map.current = el->el_map.key;
 	return (CC_REFRESH);
@@ -413,11 +409,7 @@
 {
 
 	el->el_map.current = el->el_map.key;
-
-	el->el_chared.c_vcmd.ins = el->el_line.cursor;
-	el->el_chared.c_undo.ptr = el->el_line.cursor;
-	el->el_chared.c_undo.action = DELETE;
-
+	cv_undo(el, 0, 0);
 	return (CC_NORM);
 }
 
@@ -441,9 +433,7 @@
 	} else
 		ret = CC_NORM;
 
-	el->el_chared.c_vcmd.ins = el->el_line.cursor;
-	el->el_chared.c_undo.ptr = el->el_line.cursor;
-	el->el_chared.c_undo.action = DELETE;
+	cv_undo(el, 0, 0);
 
 	return (ret);
 }
@@ -460,11 +450,7 @@
 
 	el->el_map.current = el->el_map.key;
 	el->el_line.cursor = el->el_line.lastchar;
-
-	/* Mark where insertion begins */
-	el->el_chared.c_vcmd.ins = el->el_line.lastchar;
-	el->el_chared.c_undo.ptr = el->el_line.lastchar;
-	el->el_chared.c_undo.action = DELETE;
+	cv_undo(el, 0, 0);
 	return (CC_CURSOR);
 }
 
@@ -482,20 +468,20 @@
 }
 
 
-/* vi_end_word():
+/* vi_end_big_word():
  *	Vi move to the end of the current space delimited word
  *	[E]
  */
 protected el_action_t
 /*ARGSUSED*/
-vi_end_word(EditLine *el, int c)
+vi_end_big_word(EditLine *el, int c)
 {
 
 	if (el->el_line.cursor == el->el_line.lastchar)
 		return (CC_ERROR);
 
 	el->el_line.cursor = cv__endword(el->el_line.cursor,
-	    el->el_line.lastchar, el->el_state.argument);
+	    el->el_line.lastchar, el->el_state.argument, cv__isWord);
 
 	if (el->el_chared.c_vcmd.action & DELETE) {
 		el->el_line.cursor++;
@@ -506,20 +492,20 @@
 }
 
 
-/* vi_to_end_word():
+/* vi_end_word():
  *	Vi move to the end of the current word
  *	[e]
  */
 protected el_action_t
 /*ARGSUSED*/
-vi_to_end_word(EditLine *el, int c)
+vi_end_word(EditLine *el, int c)
 {
 
 	if (el->el_line.cursor == el->el_line.lastchar)
 		return (CC_ERROR);
 
 	el->el_line.cursor = cv__endword(el->el_line.cursor,
-	    el->el_line.lastchar, el->el_state.argument);
+	    el->el_line.lastchar, el->el_state.argument, cv__isword);
 
 	if (el->el_chared.c_vcmd.action & DELETE) {
 		el->el_line.cursor++;
@@ -538,100 +524,19 @@
 /*ARGSUSED*/
 vi_undo(EditLine *el, int c)
 {
-	char *cp, *kp;
-	char temp;
-	int i, size;
-	c_undo_t *un = &el->el_chared.c_undo;
+	c_undo_t un = el->el_chared.c_undo;
 
-#ifdef DEBUG_UNDO
-	(void) fprintf(el->el_errfile, "Undo: %x \"%s\" +%d -%d\n",
-	    un->action, un->buf, un->isize, un->dsize);
-#endif
-	switch (un->action) {
-	case DELETE:
-		if (un->dsize == 0)
-			return (CC_NORM);
-
-		(void) memcpy(un->buf, un->ptr, un->dsize);
-		for (cp = un->ptr; cp <= el->el_line.lastchar; cp++)
-			*cp = cp[un->dsize];
-
-		el->el_line.lastchar -= un->dsize;
-		el->el_line.cursor = un->ptr;
-
-		un->action = INSERT;
-		un->isize = un->dsize;
-		un->dsize = 0;
-		break;
-
-	case DELETE | INSERT:
-		size = un->isize - un->dsize;
-		if (size > 0)
-			i = un->dsize;
-		else
-			i = un->isize;
-		cp = un->ptr;
-		kp = un->buf;
-		while (i-- > 0) {
-			temp = *kp;
-			*kp++ = *cp;
-			*cp++ = temp;
-		}
-		if (size > 0) {
-			el->el_line.cursor = cp;
-			c_insert(el, size);
-			while (size-- > 0 && cp < el->el_line.lastchar) {
-				temp = *kp;
-				*kp++ = *cp;
-				*cp++ = temp;
-			}
-		} else if (size < 0) {
-			size = -size;
-			for (; cp <= el->el_line.lastchar; cp++) {
-				*kp++ = *cp;
-				*cp = cp[size];
-			}
-			el->el_line.lastchar -= size;
-		}
-		el->el_line.cursor = un->ptr;
-		i = un->dsize;
-		un->dsize = un->isize;
-		un->isize = i;
-		break;
-
-	case INSERT:
-		if (un->isize == 0)
-			return (CC_NORM);
-
-		el->el_line.cursor = un->ptr;
-		c_insert(el, (int) un->isize);
-		(void) memcpy(un->ptr, un->buf, un->isize);
-		un->action = DELETE;
-		un->dsize = un->isize;
-		un->isize = 0;
-		break;
-
-	case CHANGE:
-		if (un->isize == 0)
-			return (CC_NORM);
-
-		el->el_line.cursor = un->ptr;
-		size = (int) (el->el_line.cursor - el->el_line.lastchar);
-		if (size < un->isize)
-			size = un->isize;
-		cp = un->ptr;
-		kp = un->buf;
-		for (i = 0; i < size; i++) {
-			temp = *kp;
-			*kp++ = *cp;
-			*cp++ = temp;
-		}
-		un->dsize = 0;
-		break;
+	if (un.len == -1)
+		return CC_ERROR;
 
-	default:
-		return (CC_ERROR);
-	}
+	/* switch line buffer and undo buffer */
+	el->el_chared.c_undo.buf = el->el_line.buffer;
+	el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer;
+	el->el_chared.c_undo.cursor = el->el_line.cursor - el->el_line.buffer;
+	el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer);
+	el->el_line.buffer = un.buf;
+	el->el_line.cursor = un.buf + un.cursor;
+	el->el_line.lastchar = un.buf + un.len;
 
 	return (CC_REFRESH);
 }
@@ -645,22 +550,12 @@
 /*ARGSUSED*/
 vi_command_mode(EditLine *el, int c)
 {
-	int size;
 
 	/* [Esc] cancels pending action */
-	el->el_chared.c_vcmd.ins = 0;
 	el->el_chared.c_vcmd.action = NOP;
 	el->el_chared.c_vcmd.pos = 0;
 
 	el->el_state.doingarg = 0;
-	size = el->el_chared.c_undo.ptr - el->el_line.cursor;
-	if (size < 0)
-		size = -size;
-	if (el->el_chared.c_undo.action == (INSERT | DELETE) ||
-	    el->el_chared.c_undo.action == DELETE)
-		el->el_chared.c_undo.dsize = size;
-	else
-		el->el_chared.c_undo.isize = size;
 
 	el->el_state.inputmode = MODE_INSERT;
 	el->el_map.current = el->el_map.alt;
@@ -699,22 +594,23 @@
 
 /* vi_delete_prev_char():
  * 	Vi move to previous character (backspace)
- *	[^H]
+ *	[^H] in insert mode only
  */
 protected el_action_t
 /*ARGSUSED*/
 vi_delete_prev_char(EditLine *el, int c)
 {
-
-	if (el->el_chared.c_vcmd.ins == 0)
-		return (CC_ERROR);
+	char *cp;
 
-	if (el->el_chared.c_vcmd.ins >
-	    el->el_line.cursor - el->el_state.argument)
+	cp = el->el_line.cursor;
+	if (cp <= el->el_line.buffer)
 		return (CC_ERROR);
 
-	c_delbefore(el, el->el_state.argument);
-	el->el_line.cursor -= el->el_state.argument;
+	/* do the delete here so we dont mess up the undo and paste buffers */
+	el->el_line.cursor = --cp;
+	for (; cp < el->el_line.lastchar; cp++)
+		cp[0] = cp[1];
+	el->el_line.lastchar = cp - 1;
 
 	return (CC_REFRESH);
 }

-- 
David Laight: david@l8s.co.uk