summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/iconv.h2
-rw-r--r--lib/libc/iconv/citrus_iconv_local.h1
-rw-r--r--lib/libc/iconv/iconv.c6
-rw-r--r--lib/libc/iconv/iconvctl.327
-rw-r--r--lib/libiconv_modules/iconv_std/citrus_iconv_std.c10
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) &&
OpenPOWER on IntegriCloud