From 8eff299771b8da7a5363a033d2e57af6812f8f7f Mon Sep 17 00:00:00 2001
From: David Lawrence Ramsey <pooka109@gmail.com>
Date: Sun, 26 Feb 2017 12:14:55 -0600
Subject: [PATCH] input: fix wrong character count after verbatim Unicode input

Detect whether we get Unicode input (via hooks in get_verbatim_input()
and parse_verbatim_kbinput()), and if we did, put the multibyte sequence
back so it gets counted as one character and not one character per byte.

This fixes bug #50403.
---
 src/prompt.c |  2 +-
 src/proto.h  |  4 ++--
 src/text.c   | 29 ++++++++++++++++++-----------
 src/winio.c  | 18 +++++++++++++-----
 4 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/src/prompt.c b/src/prompt.c
index 8dceece..12a4dfa 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -354,7 +354,7 @@ void do_statusbar_verbatim_input(void)
     int *kbinput;
     size_t kbinput_len;
 
-    kbinput = get_verbatim_kbinput(bottomwin, &kbinput_len);
+    kbinput = get_verbatim_kbinput(bottomwin, &kbinput_len, NULL);
 
     do_statusbar_output(kbinput, kbinput_len, FALSE);
 }
diff --git a/src/proto.h b/src/proto.h
index 45cba51..f47a601 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -719,8 +719,8 @@ long get_unicode_kbinput(WINDOW *win, int kbinput);
 #endif
 int get_control_kbinput(int kbinput);
 void unparse_kbinput(char *output, size_t output_len);
-int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len);
-int *parse_verbatim_kbinput(WINDOW *win, size_t *count);
+int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len, bool *unicode);
+int *parse_verbatim_kbinput(WINDOW *win, size_t *count, bool *unicode);
 #ifndef DISABLE_MOUSE
 int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts);
 #endif
diff --git a/src/text.c b/src/text.c
index 7822bf0..390f8e3 100644
--- a/src/text.c
+++ b/src/text.c
@@ -3619,7 +3619,7 @@ void do_verbatim_input(void)
 {
     int *kbinput;
     size_t kbinput_len, i;
-    char *output;
+    bool unicode;
 
     /* TRANSLATORS: This is displayed when the next keystroke will be
      * inserted verbatim. */
@@ -3628,7 +3628,7 @@ void do_verbatim_input(void)
     curs_set(1);
 
     /* Read in all the verbatim characters. */
-    kbinput = get_verbatim_kbinput(edit, &kbinput_len);
+    kbinput = get_verbatim_kbinput(edit, &kbinput_len, &unicode);
 
     /* Unsuppress cursor-position display or blank the statusbar. */
     if (ISSET(CONST_UPDATE))
@@ -3638,19 +3638,26 @@ void do_verbatim_input(void)
 	wnoutrefresh(bottomwin);
     }
 
-    /* Display all the verbatim characters at once, not filtering out
-     * control characters. */
-    output = charalloc(kbinput_len + 1);
+    /* If we didn't get Unicode input, display all the verbatim
+     * characters at once, not filtering out control characters. */
+    if (!unicode) {
+	char *output = charalloc(kbinput_len + 1);
 
-    for (i = 0; i < kbinput_len; i++)
-	output[i] = (char)kbinput[i];
-    output[i] = '\0';
+	for (i = 0; i < kbinput_len; i++)
+	    output[i] = (char)kbinput[i];
+	output[i] = '\0';
 
-    free(kbinput);
+	do_output(output, kbinput_len, TRUE);
 
-    do_output(output, kbinput_len, TRUE);
+	free(output);
+    /* Otherwise, put back the Unicode multibyte sequence so it gets
+     * read as one character. */
+    } else {
+	for (i = 0; i < kbinput_len; i++)
+	    unget_kbinput(kbinput[i], FALSE);
+    }
 
-    free(output);
+    free(kbinput);
 }
 
 #ifdef ENABLE_WORDCOMPLETION
diff --git a/src/winio.c b/src/winio.c
index 00c6a6a..6d0f855 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -1429,8 +1429,9 @@ void unparse_kbinput(char *output, size_t output_len)
 }
 
 /* Read in a stream of characters verbatim, and return the length of the
- * string in kbinput_len.  Assume nodelay(win) is FALSE. */
-int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len)
+ * string in kbinput_len.  Return in unicode whether we got Unicode
+ * input.  Assume nodelay(win) is FALSE. */
+int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len, bool *unicode)
 {
     int *retval;
 
@@ -1443,7 +1444,7 @@ int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len)
 	keypad(win, FALSE);
 
     /* Read in one keycode, or one or two escapes. */
-    retval = parse_verbatim_kbinput(win, kbinput_len);
+    retval = parse_verbatim_kbinput(win, kbinput_len, unicode);
 
     /* If the code is invalid in the current mode, discard it. */
     if ((*retval == '\n' && as_an_at) || (*retval == '\0' && !as_an_at)) {
@@ -1468,11 +1469,15 @@ int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len)
 /* Read in one control character (or an iTerm/Eterm/rxvt double Escape),
  * or convert a series of six digits into a Unicode codepoint.  Return
  * in count either 1 (for a control character or the first byte of a
- * multibyte sequence), or 2 (for an iTerm/Eterm/rxvt double Escape). */
-int *parse_verbatim_kbinput(WINDOW *win, size_t *count)
+ * multibyte sequence), or 2 (for an iTerm/Eterm/rxvt double Escape).
+ * Return in unicode whether we got Unicode input. */
+int *parse_verbatim_kbinput(WINDOW *win, size_t *count, bool *unicode)
 {
     int *kbinput;
 
+    if (unicode != NULL)
+	*unicode = FALSE;
+
     /* Read in the first code. */
     while ((kbinput = get_input(win, 1)) == NULL)
 	;
@@ -1520,6 +1525,9 @@ int *parse_verbatim_kbinput(WINDOW *win, size_t *count)
 
 	    free(seq);
 	    free(uni_mb);
+
+	    if (unicode != NULL)
+		*unicode = TRUE;
 	}
     } else
 #endif /* ENABLE_UTF8 */
-- 
2.9.0

