iconv: Sync#2 - Support ICONV_{GET,SET}_ILSEQ_INVALID
authorJohn Marino <draco@marino.st>
Fri, 10 Jan 2014 00:06:03 +0000 (01:06 +0100)
committerSascha Wildner <saw@online.de>
Fri, 10 Jan 2014 18:55:01 +0000 (19:55 +0100)
Add ICONV_{GET,SET}_ILSEQ_INVALID iconvctl. GNU iconv returns EILSEQ
when there is an invalid character in the output codeset while it is
valid in the input.  However, POSIX requires iconv() to perform an
implementation-defined conversion on the character.  So, Citrus iconv
converts such a character to a special character which means it is
invalid in the output codeset.

This is not a problem in most cases but some software like libxml2
depends on GNU's behavior to determine if a character is output as-is
or another form such as a character entity (&#NNN;).

Taken verbatim from:
FreeBSD SVN 258537 (24 NOV 2013)

include/iconv.h
lib/i18n_module/iconv_std/citrus_iconv_std.c
lib/libc/citrus/citrus_iconv_local.h
lib/libc/iconv/iconv.c
lib/libc/iconv/iconvctl.3

index 2cfbc96..65406f8 100644 (file)
@@ -89,6 +89,8 @@ void   iconv_set_relocation_prefix(const char *orig_prefix,
 #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);
index 65b075c..a510c69 100644 (file)
@@ -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) &&
index 6d4e56a..df0347c 100644 (file)
@@ -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 {
index 08e3fe0..4d31667 100644 (file)
@@ -301,6 +301,12 @@ 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);
index f1fe138..4c8ba9e 100644 (file)
@@ -34,7 +34,7 @@
 .\"
 .\" $FreeBSD: head/lib/libc/iconv/iconvctl.3 233577 2012-03-27 20:50:14Z joel $
 .\"
-.Dd September 19, 2013
+.Dd January 9, 2014
 .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