about summary refs log tree commit diff
path: root/Src/Zle/compmatch.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2005-10-02 19:13:44 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2005-10-02 19:13:44 +0000
commitdcc48ad81b0dee365ae5c3694103b06615c32351 (patch)
tree73df262f9bf6b3ffa1c026d43f5401c186687eff /Src/Zle/compmatch.c
parent4ecc04ec8b8e3c9047ae5ff7004131ed90a4cf8c (diff)
downloadzsh-dcc48ad81b0dee365ae5c3694103b06615c32351.tar.gz
zsh-dcc48ad81b0dee365ae5c3694103b06615c32351.tar.xz
zsh-dcc48ad81b0dee365ae5c3694103b06615c32351.zip
minor tidy-ups
Diffstat (limited to 'Src/Zle/compmatch.c')
-rw-r--r--Src/Zle/compmatch.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c
index 7054feb6d..e4c5a438f 100644
--- a/Src/Zle/compmatch.c
+++ b/Src/Zle/compmatch.c
@@ -1584,6 +1584,11 @@ sub_match(Cmdata md, char *str, int len, int sfx)
 {
     int ret = 0, l, ind, add;
     char *p, *q;
+#ifdef ZLE_UNICODE_SUPPORT
+    int fulllen = len;
+    char *fullstr = str;
+    mbstate_t ps;
+#endif
 
     if (sfx) {
 	str += len;
@@ -1614,6 +1619,85 @@ sub_match(Cmdata md, char *str, int len, int sfx)
 		   || (l < md->len && q[-1] == Meta)))
 		l--;
 	}
+#ifdef ZLE_UNICODE_SUPPORT
+	/*
+	 * Make sure we don't end in the middle of a multibyte character.
+	 * Don't need to do this if the match ended at the start
+	 * of the original string.
+	 *
+	 * Let q be the match point we've found.
+	 */
+	q = sfx ? str - l : str + l;
+	if (q != fullstr) {
+	    memset(&ps, 0, sizeof(ps));
+	    /*
+	     * Otherwise read characters from the start of the original
+	     * string until we reach or pass the match point.  This
+	     * is rather inefficient, but in general only reading
+	     * the full string can keep track of where we are in
+	     * a character.  With a prefix we could be more efficient,
+	     * but it's difficult with a suffix where the match point
+	     * moves backwards.
+	     */
+	    for (p = fullstr; p < fullstr + fulllen; ) {
+		wchar_t wc;
+		/*
+		 * ret must, in fact, be set by the current logic,
+		 * but gcc doesn't realise (at least some versions don't).
+		 */
+		int ret = -1, diff;
+		char *p2;
+
+		/*
+		 * Because the string is metafied, we need to
+		 * assembled wide characters a byte at a time.
+		 */
+		for (p2 = p; p2 < fullstr + fulllen; p2++) {
+		  char curchar = (*p2 == Meta) ? (*++p2 ^ 32) : *p2;
+		  ret = mbrtowc(&wc, &curchar, 1, &ps);
+		  /*
+		   * Continue while character is incomplete.
+		   */
+		  if (ret != -2)
+		    break;
+		}
+		if (ret < 0) {
+		    /* not a valid character, give up test */
+		    break;
+		}
+		/* increment p2 for last byte read */
+		diff = ++p2 - q;
+		if (diff == 0) {
+		    /*
+		     * Prefix or suffix matches at end of multbyte character,
+		     * so OK.
+		     */
+		    break;
+		} else if (diff > 0) {
+		    /*
+		     * The prefix or suffix finishes in the middle
+		     * of a character.  Shorten it until it doesn't.
+		     */
+		    if (sfx) {
+			/*
+			 * We need to remove the trailing part of
+			 * the character from the suffix.
+			 */
+			l -= diff;
+		    } else {
+			/*
+			 * We need to remove the initial part of
+			 * the character from the prefix.
+			 */
+			l -= (q - p);
+		    }
+		    break;
+		}
+		/* Advance over full character */
+		p += ret;
+	    }
+	}
+#endif
 	if (l) {
 	    /* There was a common prefix, use it. */
 	    md->len -= l; len -= l;