summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/strerror.c25
1 files changed, 25 insertions, 0 deletions
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;
}