summaryrefslogtreecommitdiff
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.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".
*