fmt_scan: support multibyte characters in putstr decoding
authorc_14 <git@c-14.de>
Tue, 16 May 2017 16:13:27 +0000 (18:13 +0200)
committerPhilipp Takacs <philipp@bureaucracy.de>
Thu, 15 Jun 2017 19:53:47 +0000 (21:53 +0200)
Fixes an issue where the string output by scan with a putstr format is
truncated within a multibyte character causing terminal corruption

sbr/fmt_scan.c

index 2485e6c..d0b112b 100644 (file)
@@ -188,17 +188,48 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) {
 static void
 cpstripped(char **start, char *end, char *str)
 {
+#ifdef MULTIBYTE_SUPPORT
+       int char_len;  /* bytes in current character */
+       int nbytes;
+       wchar_t wide_char;
+#else
        int c;
+#endif
        char *s = str;
 
        if (!s)
                return;
 
        /* skip any initial control characters or spaces */
+#ifdef MULTIBYTE_SUPPORT
+       nbytes = end - *start + 1;
+       mbtowc(NULL, NULL, 0); /* reset shift state */
+       while ((char_len = mbtowc(&wide_char, s, nbytes)) > 0 && (iswcntrl(wide_char) || iswspace(wide_char))) {
+               s += char_len;
+               nbytes -= char_len;
+       }
+#else
        while ((c = (unsigned char) *s) && (iscntrl(c) || isspace(c)))
                s++;
+#endif
 
        /* compact repeated control characters and spaces into a single space */
+#ifdef MULTIBYTE_SUPPORT
+       while ((char_len = mbtowc(&wide_char, s, nbytes)) > 0 && *start < end) {
+               if (!iswcntrl(wide_char) && !iswspace(wide_char)) {
+                       strncpy(*start, s, char_len);
+                       s += char_len;
+                       *start += char_len;
+                       nbytes -= char_len;
+               } else {
+                       while ((char_len = mbtowc(&wide_char, s, nbytes)) > 0 && (iswcntrl(wide_char) || iswspace(wide_char))) {
+                               s += char_len;
+                               nbytes -= char_len;
+                       }
+                       *(*start)++ = ' ';
+               }
+       }
+#else
        while((c = (unsigned char) *s++) && *start < end)
                if (!iscntrl(c) && !isspace(c))
                        *(*start)++ = c;
@@ -208,6 +239,7 @@ cpstripped(char **start, char *end, char *str)
                                s++;
                        *(*start)++ = ' ';
                }
+#endif
 }
 
 static char *lmonth[] = {