about summary refs log tree commit diff
path: root/Src/utils.c
diff options
context:
space:
mode:
authorBarton E. Schaefer <schaefer@zsh.org>2017-03-08 21:26:55 -0800
committerBarton E. Schaefer <schaefer@zsh.org>2017-03-08 21:26:55 -0800
commit071017965f469c88b10467205f30ea3e609e56dc (patch)
treea6472c26ba37ff83be987c782eef231d989d2607 /Src/utils.c
parent67d882479b61165c5d58bd72430d6009f4a7f25f (diff)
downloadzsh-071017965f469c88b10467205f30ea3e609e56dc.tar.gz
zsh-071017965f469c88b10467205f30ea3e609e56dc.tar.xz
zsh-071017965f469c88b10467205f30ea3e609e56dc.zip
40763: count wide characters and Cmatcher pointers more sanely in cfp_matcher_pats(), and count characters in pattern_match() the same way to stay in sync
Might not fix wide-char matching in completion matcher-lists but should
avoid wild pointer crash
Diffstat (limited to 'Src/utils.c')
-rw-r--r--Src/utils.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/Src/utils.c b/Src/utils.c
index 9669944f6..b3fa3d24c 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -4788,6 +4788,48 @@ unmeta(const char *file_name)
 }
 
 /*
+ * Unmetafy just one character and store the number of bytes it occupied.
+ */
+/**/
+mod_export convchar_t
+unmeta_one(const char *in, int *sz)
+{
+    convchar_t wc;
+    int newsz;
+#ifdef MULTIBYTE_SUPPORT
+    int ulen;
+    mbstate_t wstate;
+#endif
+
+    if (!sz)
+	sz = &newsz;
+    *sz = 0;
+
+    if (!in || !*in)
+	return 0;
+
+#ifdef MULTIBYTE_SUPPORT
+    memset(&wstate, 0, sizeof(wstate));
+    ulen = mb_metacharlenconv_r(in, &wc, &wstate);
+    while (ulen-- > 0) {
+	if (in[*sz] == Meta)
+	    *sz += 2;
+	else
+	    *sz += 1;
+    }
+#else
+    if (in[0] == Meta) {
+      *sz = 2;
+      wc = STOUC(in[1] ^ 32);
+    } else {
+      *sz = 1;
+      wc = STOUC(in[0]);
+    }
+#endif
+    return wc;
+}
+
+/*
  * Unmetafy and compare two strings, comparing unsigned character values.
  * "a\0" sorts after "a".
  *