diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/strerror.c | 25 |
2 files changed, 26 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index e15a321..c3faf99 100644 --- a/configure.ac +++ b/configure.ac @@ -82,6 +82,7 @@ AC_PROG_AWK AC_CHECK_TOOL(AR, ar, :) AC_USE_SYSTEM_EXTENSIONS +AM_LANGINFO_CODESET # Taken from mpfr-4.0.1, then modified for LDADD_FOR_TESTS_KLUDGE dnl Under Linux, make sure that the old dtags are used if LD_LIBRARY_PATH diff --git a/src/strerror.c b/src/strerror.c index 4cce17f..fb1bebf 100644 --- a/src/strerror.c +++ b/src/strerror.c @@ -32,6 +32,10 @@ #include "gettext.h" #include "err-codes.h" +#if defined(ENABLE_NLS) && defined(HAVE_LANGINFO_CODESET) +#include <langinfo.h> +#endif + /* Return a pointer to a string containing a description of the error code in the error value ERR. This function is not thread-safe. */ const char * @@ -169,9 +173,30 @@ _gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen) errstr = dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]); errstr_len = strlen (errstr) + 1; cpy_len = errstr_len < buflen ? errstr_len : buflen; +#if defined(ENABLE_NLS) && defined(HAVE_LANGINFO_CODESET) + /* Avoid truncation in the middle of "character" boundary. */ + if (buflen && errstr_len > buflen + && ((unsigned char)errstr[cpy_len-1] & 0xC0) == 0x80 + && !strcasecmp (nl_langinfo (CODESET), "UTF-8")) + { + /* Go back to the boundary */ + for (; cpy_len; cpy_len--) + if (((unsigned char)errstr[cpy_len-1] & 0xC0) != 0x80) + break; + memcpy (buf, errstr, cpy_len); + memset (buf+cpy_len, 0, buflen - cpy_len); + } + else + { + memcpy (buf, errstr, cpy_len); + if (buflen) + buf[buflen - 1] = '\0'; + } +#else memcpy (buf, errstr, cpy_len); if (buflen) buf[buflen - 1] = '\0'; +#endif return cpy_len == errstr_len ? 0 : ERANGE; } |