diff options
author | Kurtis Rader <krader@skepticism.us> | 2016-03-10 18:17:39 -0800 |
---|---|---|
committer | Kurtis Rader <krader@skepticism.us> | 2016-03-20 18:47:38 -0700 |
commit | c2f1df1d4af0c7e633528cb4c8caa79ef04b0b5a (patch) | |
tree | 0776e975779488cb842c09a5d79d193cb7cf9fdc /src/output.cpp | |
parent | fb0921249f4584e68699e336be249a655b9c8ede (diff) |
fix handling of non-ASCII chars in C locale
The relevant standards allow the mbtowc/mbrtowc functions to reject
non-ASCII characters (i.e., chars with the high bit set) when the locale
is C or POSIX. The BSD libraries (e.g., on OS X) don't do this but
the GNU libraries (e.g., on Linux) do. Like most programs we need the
C/POSIX locales to allow arbitrary bytes. So explicitly check if we're
in a single-byte locale (which would also include ISO-8859 variants)
and simply pass-thru the chars without encoding or decoding.
Fixes #2802.
Diffstat (limited to 'src/output.cpp')
-rw-r--r-- | src/output.cpp | 58 |
1 files changed, 29 insertions, 29 deletions
diff --git a/src/output.cpp b/src/output.cpp index 1707f4fb..dbd97eb4 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -386,32 +386,35 @@ int writeb(tputs_arg_t b) int writech(wint_t ch) { - mbstate_t state; - size_t i; char buff[MB_LEN_MAX+1]; - size_t bytes; + size_t len; - if ((ch >= ENCODE_DIRECT_BASE) && - (ch < ENCODE_DIRECT_BASE+256)) + if (ch >= ENCODE_DIRECT_BASE && ch < ENCODE_DIRECT_BASE + 256) { buff[0] = ch - ENCODE_DIRECT_BASE; - bytes=1; + len = 1; + } + else if (MB_CUR_MAX == 1) // single-byte locale (C/POSIX/ISO-8859) + { + // If `wc` contains a wide character we emit a question-mark. + if (ch & ~0xFF) + { + ch = '?'; + } + buff[0] = ch; + len = 1; } else { - memset(&state, 0, sizeof(state)); - bytes= wcrtomb(buff, ch, &state); - - switch (bytes) + mbstate_t state = {}; + len = wcrtomb(buff, ch, &state); + if (len == (size_t)-1) { - case (size_t)(-1): - { - return 1; - } + return 1; } } - for (i=0; i<bytes; i++) + for (size_t i = 0; i < len; i++) { out(buff[i]); } @@ -420,29 +423,26 @@ int writech(wint_t ch) void writestr(const wchar_t *str) { - char *pos; - CHECK(str,); - // while( *str ) - // writech( *str++ ); - - /* - Check amount of needed space - */ - size_t len = wcstombs(0, str, 0); + if (MB_CUR_MAX == 1) // single-byte locale (C/POSIX/ISO-8859) + { + while( *str ) + { + writech( *str++ ); + } + return; + } + size_t len = wcstombs(0, str, 0); // figure amount of space needed if (len == (size_t)-1) { debug(1, L"Tried to print invalid wide character string"); return; } + // Convert the string. len++; - - /* - Convert - */ char *buffer, static_buffer[256]; if (len <= sizeof static_buffer) buffer = static_buffer; @@ -456,7 +456,7 @@ void writestr(const wchar_t *str) /* Write */ - for (pos = buffer; *pos; pos++) + for (char *pos = buffer; *pos; pos++) { out(*pos); } |