aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/output.cpp
diff options
context:
space:
mode:
authorGravatar Kurtis Rader <krader@skepticism.us>2016-03-10 18:17:39 -0800
committerGravatar Kurtis Rader <krader@skepticism.us>2016-03-20 18:47:38 -0700
commitc2f1df1d4af0c7e633528cb4c8caa79ef04b0b5a (patch)
tree0776e975779488cb842c09a5d79d193cb7cf9fdc /src/output.cpp
parentfb0921249f4584e68699e336be249a655b9c8ede (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.cpp58
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);
}