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.
This commit is contained in:
Kurtis Rader
2016-03-10 18:17:39 -08:00
parent fb0921249f
commit c2f1df1d4a
14 changed files with 215 additions and 165 deletions

View File

@@ -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);
}