about summary refs log tree commit diff
path: root/Src/Zle/zle_move.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2008-04-20 21:17:29 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2008-04-20 21:17:29 +0000
commitb8ec06c870ac09d5949907640dca4c1a2b711ed5 (patch)
treef5676d7f945f34fe69e30e67fa7fbc8a82730b94 /Src/Zle/zle_move.c
parenta12b1f35aaeff5724c1d7b4824de62cb4e480698 (diff)
downloadzsh-b8ec06c870ac09d5949907640dca4c1a2b711ed5.tar.gz
zsh-b8ec06c870ac09d5949907640dca4c1a2b711ed5.tar.xz
zsh-b8ec06c870ac09d5949907640dca4c1a2b711ed5.zip
24853: use metafied strings for inner loops over history
Diffstat (limited to 'Src/Zle/zle_move.c')
-rw-r--r--Src/Zle/zle_move.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c
index 4568e2696..5bfe8ffcb 100644
--- a/Src/Zle/zle_move.c
+++ b/Src/Zle/zle_move.c
@@ -158,6 +158,144 @@ decpos(int *pos)
 }
 #endif
 
+
+/* Size of buffer in the following function */
+#define BMC_BUFSIZE MB_CUR_MAX
+/*
+ * For a metafied string that starts at "start" and where the
+ * current position is "ptr", go back one full character,
+ * taking account of combining characters if necessary.
+ */
+
+/**/
+char *
+backwardmetafiedchar(char *start, char *ptr, convchar_t *retchr)
+{
+#ifdef MULTIBYTE_SUPPORT
+    int charlen = 0;
+    char *last = NULL, *bufptr, *endptr = ptr;
+    convchar_t lastc;
+    mbstate_t mbs;
+    size_t ret;
+    wchar_t wc;
+    VARARR(char, buf, BMC_BUFSIZE);
+
+    bufptr = buf + BMC_BUFSIZE;
+    while (ptr > start) {
+	ptr--;
+	/*
+	 * Scanning backwards we're not guaranteed ever to find a
+	 * valid character.  If we've looked as far as we should
+	 * need to, give up.
+	 */
+	if (bufptr-- == buf)
+	    break;
+	charlen++;
+	if (ptr > start && ptr[-1] == Meta)
+	    *bufptr = *ptr-- ^ 32;
+	else
+	    *bufptr = *ptr;
+
+	/* we always need to restart the character from scratch */
+	memset(&mbs, 0, sizeof(mbs));
+	ret = mbrtowc(&wc, bufptr, charlen, &mbs);
+	if (ret == 0) {
+	    /* NULL: unlikely, but handle anyway. */
+	    if (last) {
+		if (retchr)
+		    *retchr = lastc;
+		return last;
+	    } else {
+		if (retchr)
+		    *retchr = wc;
+		return ptr;
+	    }
+	}
+	if (ret >= 0) {
+	    if (ret < charlen) {
+		/* The last character didn't convert, so use it raw. */
+		break;
+	    }
+	    if (!isset(COMBININGCHARS)) {
+		if (retchr)
+		    *retchr = wc;
+		return ptr;
+	    }
+ 	    /* HERE: test for combining char, fix when test changes */
+	    if (!iswpunct(wc) || wcwidth(wc) != 0) {
+		/* not a combining character... */
+		if (last) {
+		    /*
+		     * ... but we were looking for a suitable base character,
+		     * test it.
+		     */
+		    /* HERE this test will change too */
+		    if (iwsalnum(wc) && wcwidth(wc) > 0) {
+			/*
+			 * Yes, this will do.
+			 */
+			if (retchr)
+			    *retchr = wc;
+			return ptr;
+		    } else {
+			/* No, just return the first character we found */
+			if (retchr)
+			    *retchr = lastc;
+			return last;
+		    }
+		}
+		/* This is the first character, so just return it. */
+		if (retchr)
+		    *retchr = wc;
+		return ptr;    
+	    }
+	    if (!last) {
+		/* still looking for the character immediately before ptr */
+		last = ptr;
+	    }
+	    /* searching for base character of combining character */
+	    charlen = 0;
+	    bufptr = buf + BMC_BUFSIZE;
+	}
+	/*
+	 * Else keep scanning this character even if MB_INVALID:  we can't
+	 * expect MB_INCOMPLETE to work when moving backwards.
+	 */
+    }
+    /*
+     * Found something we didn't like, was there a good character
+     * immediately before ptr?
+     */
+    if (last) {
+	if (retchr)
+	    *retchr = lastc;
+	return last;
+    }
+    /*
+     * No, we couldn't find any good character, so just treat
+     * the last unmetafied byte we found as a character.
+     */
+#endif
+    if (endptr > start) {
+	if (endptr > start - 1 && endptr[-2] == Meta)
+	{
+	    if (retchr)
+		*retchr = (convchar_t)(endptr[-1] ^ 32);
+	    return endptr - 2;
+	}
+	else
+	{
+	    if (retchr)
+		*retchr = (convchar_t)endptr[-1];
+	    return endptr - 1;
+	}
+    }
+    if (retchr)
+	*retchr = (convchar_t)0;
+    return endptr;
+}
+
+
 /**/
 int
 beginningofline(char **args)