diff options
-rw-r--r-- | include/iconv.h | 2 | ||||
-rw-r--r-- | lib/libc/iconv/citrus_iconv_local.h | 1 | ||||
-rw-r--r-- | lib/libc/iconv/iconv.c | 6 | ||||
-rw-r--r-- | lib/libc/iconv/iconvctl.3 | 27 | ||||
-rw-r--r-- | lib/libiconv_modules/iconv_std/citrus_iconv_std.c | 10 |
5 files changed, 45 insertions, 1 deletions
diff --git a/include/iconv.h b/include/iconv.h index da1036a..c07d02e 100644 --- a/include/iconv.h +++ b/include/iconv.h @@ -86,6 +86,8 @@ void iconv_set_relocation_prefix(const char *, const char *); #define ICONV_SET_DISCARD_ILSEQ 4 #define ICONV_SET_HOOKS 5 #define ICONV_SET_FALLBACKS 6 +#define ICONV_GET_ILSEQ_INVALID 128 +#define ICONV_SET_ILSEQ_INVALID 129 typedef void (*iconv_unicode_char_hook) (unsigned int mbr, void *data); typedef void (*iconv_wide_char_hook) (wchar_t wc, void *data); diff --git a/lib/libc/iconv/citrus_iconv_local.h b/lib/libc/iconv/citrus_iconv_local.h index e673c9a..12d2fa3 100644 --- a/lib/libc/iconv/citrus_iconv_local.h +++ b/lib/libc/iconv/citrus_iconv_local.h @@ -99,6 +99,7 @@ struct _citrus_iconv_shared { char *ci_convname; bool ci_discard_ilseq; struct iconv_hooks *ci_hooks; + bool ci_ilseq_invalid; }; struct _citrus_iconv { diff --git a/lib/libc/iconv/iconv.c b/lib/libc/iconv/iconv.c index 555efd8..40a1a4e 100644 --- a/lib/libc/iconv/iconv.c +++ b/lib/libc/iconv/iconv.c @@ -298,6 +298,12 @@ __bsd_iconvctl(iconv_t cd, int request, void *argument) case ICONV_SET_FALLBACKS: errno = EOPNOTSUPP; return (-1); + case ICONV_GET_ILSEQ_INVALID: + *i = cv->cv_shared->ci_ilseq_invalid ? 1 : 0; + return (0); + case ICONV_SET_ILSEQ_INVALID: + cv->cv_shared->ci_ilseq_invalid = *i; + return (0); default: errno = EINVAL; return (-1); diff --git a/lib/libc/iconv/iconvctl.3 b/lib/libc/iconv/iconvctl.3 index f012157..5bd06ea 100644 --- a/lib/libc/iconv/iconvctl.3 +++ b/lib/libc/iconv/iconvctl.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 7, 2009 +.Dd November 25, 2009 .Dt ICONVCTL 3 .Os .Sh NAME @@ -110,6 +110,31 @@ variable, which is passed to via .Fa argument by its address. +.It ICONV_GET_ILSEQ_INVALID +Determines if a character in the input buffer that is valid, +but for which an identical character does not exist in the target +codeset returns +.Er EILSEQ +or not. +The answer is stored in +.Fa argument , +which is of +.Ft int * . +It will be set to 1 if this feature is enabled or set to 0 otherwise. +.It ICONV_SET_ILSEQ_INVALID +Sets whether a character in the input buffer that is valid, +but for which an identical character does not exist in the target +codeset returns +.Er EILSEQ +or not. +If +.Fa argument , +which is of +.Ft int * +is set to 1 it will be enabled, +and if +.Fa argument +is set to 0 it will be disabled. .El .\" XXX: fallbacks are unimplemented and trying to set them will always .\" return EOPNOTSUPP but definitions are provided for source-level diff --git a/lib/libiconv_modules/iconv_std/citrus_iconv_std.c b/lib/libiconv_modules/iconv_std/citrus_iconv_std.c index b30f099..54a00d0 100644 --- a/lib/libiconv_modules/iconv_std/citrus_iconv_std.c +++ b/lib/libiconv_modules/iconv_std/citrus_iconv_std.c @@ -543,6 +543,16 @@ _citrus_iconv_std_iconv_convert(struct _citrus_iconv * __restrict cv, ret = do_conv(is, &csid, &idx); if (ret) { if (ret == E_NO_CORRESPONDING_CHAR) { + /* + * GNU iconv returns EILSEQ when no + * corresponding character in the output. + * Some software depends on this behavior + * though this is against POSIX specification. + */ + if (cv->cv_shared->ci_ilseq_invalid != 0) { + ret = EILSEQ; + goto err; + } inval++; szrout = 0; if ((((flags & _CITRUS_ICONV_F_HIDE_INVALID) == 0) && |