mirror of
git://sourceware.org/git/glibc.git
synced 2024-12-15 04:20:28 +08:00
intl: Handle translation output codesets with suffixes [BZ #26383]
Commit91927b7c76
(Rewrite iconv option parsing [BZ #19519]) did not handle cases where the output codeset for translations (via the `gettext' family of functions) might have a caller specified encoding suffix such as TRANSLIT or IGNORE. This led to a regression where translations did not work when the codeset had a suffix. This commit fixes the above issue by parsing any suffixes passed to __dcigettext and adds two new test-cases to intl/tst-codeset.c to verify correct behaviour. The iconv-internal function __gconv_create_spec and the static iconv-internal function gconv_destroy_spec are now visible internally within glibc and used in intl/dcigettext.c. (cherry picked from commit7d4ec75e11
)
This commit is contained in:
parent
386543bc44
commit
fe62c4d173
@ -6,7 +6,9 @@ libc {
|
|||||||
GLIBC_PRIVATE {
|
GLIBC_PRIVATE {
|
||||||
# functions shared with iconv program
|
# functions shared with iconv program
|
||||||
__gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db;
|
__gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db;
|
||||||
__gconv_open; __gconv_create_spec;
|
|
||||||
|
# functions used elsewhere in glibc
|
||||||
|
__gconv_open; __gconv_create_spec; __gconv_destroy_spec;
|
||||||
|
|
||||||
# function used by the gconv modules
|
# function used by the gconv modules
|
||||||
__gconv_transliterate;
|
__gconv_transliterate;
|
||||||
|
@ -216,3 +216,13 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
libc_hidden_def (__gconv_create_spec)
|
libc_hidden_def (__gconv_create_spec)
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
__gconv_destroy_spec (struct gconv_spec *conv_spec)
|
||||||
|
{
|
||||||
|
free (conv_spec->fromcode);
|
||||||
|
free (conv_spec->tocode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
libc_hidden_def (__gconv_destroy_spec)
|
||||||
|
@ -48,33 +48,6 @@
|
|||||||
#define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE"
|
#define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE"
|
||||||
|
|
||||||
|
|
||||||
/* This function accepts the charset names of the source and destination of the
|
|
||||||
conversion and populates *conv_spec with an equivalent conversion
|
|
||||||
specification that may later be used by __gconv_open. The charset names
|
|
||||||
might contain options in the form of suffixes that alter the conversion,
|
|
||||||
e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
|
|
||||||
and truncating any suffix options in fromcode, and processing and truncating
|
|
||||||
any suffix options in tocode. Supported suffix options ("TRANSLIT" or
|
|
||||||
"IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
|
|
||||||
to be set to true. Unrecognized suffix options are silently discarded. If
|
|
||||||
the function succeeds, it returns conv_spec back to the caller. It returns
|
|
||||||
NULL upon failure. */
|
|
||||||
struct gconv_spec *
|
|
||||||
__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
|
|
||||||
const char *tocode);
|
|
||||||
libc_hidden_proto (__gconv_create_spec)
|
|
||||||
|
|
||||||
|
|
||||||
/* This function frees all heap memory allocated by __gconv_create_spec. */
|
|
||||||
static void __attribute__ ((unused))
|
|
||||||
gconv_destroy_spec (struct gconv_spec *conv_spec)
|
|
||||||
{
|
|
||||||
free (conv_spec->fromcode);
|
|
||||||
free (conv_spec->tocode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This function copies in-order, characters from the source 's' that are
|
/* This function copies in-order, characters from the source 's' that are
|
||||||
either alpha-numeric or one in one of these: "_-.,:/" - into the destination
|
either alpha-numeric or one in one of these: "_-.,:/" - into the destination
|
||||||
'wp' while dropping all other characters. In the process, it converts all
|
'wp' while dropping all other characters. In the process, it converts all
|
||||||
|
@ -152,6 +152,27 @@ extern int __gconv_open (struct gconv_spec *conv_spec,
|
|||||||
__gconv_t *handle, int flags);
|
__gconv_t *handle, int flags);
|
||||||
libc_hidden_proto (__gconv_open)
|
libc_hidden_proto (__gconv_open)
|
||||||
|
|
||||||
|
/* This function accepts the charset names of the source and destination of the
|
||||||
|
conversion and populates *conv_spec with an equivalent conversion
|
||||||
|
specification that may later be used by __gconv_open. The charset names
|
||||||
|
might contain options in the form of suffixes that alter the conversion,
|
||||||
|
e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
|
||||||
|
and truncating any suffix options in fromcode, and processing and truncating
|
||||||
|
any suffix options in tocode. Supported suffix options ("TRANSLIT" or
|
||||||
|
"IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
|
||||||
|
to be set to true. Unrecognized suffix options are silently discarded. If
|
||||||
|
the function succeeds, it returns conv_spec back to the caller. It returns
|
||||||
|
NULL upon failure. */
|
||||||
|
extern struct gconv_spec *
|
||||||
|
__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
|
||||||
|
const char *tocode);
|
||||||
|
libc_hidden_proto (__gconv_create_spec)
|
||||||
|
|
||||||
|
/* This function frees all heap memory allocated by __gconv_create_spec. */
|
||||||
|
extern void
|
||||||
|
__gconv_destroy_spec (struct gconv_spec *conv_spec);
|
||||||
|
libc_hidden_proto (__gconv_destroy_spec)
|
||||||
|
|
||||||
/* Free resources associated with transformation descriptor CD. */
|
/* Free resources associated with transformation descriptor CD. */
|
||||||
extern int __gconv_close (__gconv_t cd)
|
extern int __gconv_close (__gconv_t cd)
|
||||||
attribute_hidden;
|
attribute_hidden;
|
||||||
|
@ -39,7 +39,7 @@ iconv_open (const char *tocode, const char *fromcode)
|
|||||||
|
|
||||||
int res = __gconv_open (&conv_spec, &cd, 0);
|
int res = __gconv_open (&conv_spec, &cd, 0);
|
||||||
|
|
||||||
gconv_destroy_spec (&conv_spec);
|
__gconv_destroy_spec (&conv_spec);
|
||||||
|
|
||||||
if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
|
if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
|
||||||
{
|
{
|
||||||
|
@ -184,7 +184,7 @@ main (int argc, char *argv[])
|
|||||||
/* Let's see whether we have these coded character sets. */
|
/* Let's see whether we have these coded character sets. */
|
||||||
res = __gconv_open (&conv_spec, &cd, 0);
|
res = __gconv_open (&conv_spec, &cd, 0);
|
||||||
|
|
||||||
gconv_destroy_spec (&conv_spec);
|
__gconv_destroy_spec (&conv_spec);
|
||||||
|
|
||||||
if (res != __GCONV_OK)
|
if (res != __GCONV_OK)
|
||||||
{
|
{
|
||||||
|
@ -1120,15 +1120,18 @@ _nl_find_msg (struct loaded_l10nfile *domain_file,
|
|||||||
|
|
||||||
# ifdef _LIBC
|
# ifdef _LIBC
|
||||||
|
|
||||||
struct gconv_spec conv_spec
|
struct gconv_spec conv_spec;
|
||||||
= { .fromcode = norm_add_slashes (charset, ""),
|
|
||||||
.tocode = norm_add_slashes (outcharset, ""),
|
__gconv_create_spec (&conv_spec, charset, outcharset);
|
||||||
/* We always want to use transliteration. */
|
|
||||||
.translit = true,
|
/* We always want to use transliteration. */
|
||||||
.ignore = false
|
conv_spec.translit = true;
|
||||||
};
|
|
||||||
int r = __gconv_open (&conv_spec, &convd->conv,
|
int r = __gconv_open (&conv_spec, &convd->conv,
|
||||||
GCONV_AVOID_NOCONV);
|
GCONV_AVOID_NOCONV);
|
||||||
|
|
||||||
|
__gconv_destroy_spec (&conv_spec);
|
||||||
|
|
||||||
if (__builtin_expect (r != __GCONV_OK, 0))
|
if (__builtin_expect (r != __GCONV_OK, 0))
|
||||||
{
|
{
|
||||||
/* If the output encoding is the same there is
|
/* If the output encoding is the same there is
|
||||||
|
@ -22,13 +22,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <support/check.h>
|
||||||
|
|
||||||
static int
|
static int
|
||||||
do_test (void)
|
do_test (void)
|
||||||
{
|
{
|
||||||
char *s;
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
unsetenv ("LANGUAGE");
|
unsetenv ("LANGUAGE");
|
||||||
unsetenv ("OUTPUT_CHARSET");
|
unsetenv ("OUTPUT_CHARSET");
|
||||||
setlocale (LC_ALL, "de_DE.ISO-8859-1");
|
setlocale (LC_ALL, "de_DE.ISO-8859-1");
|
||||||
@ -36,25 +34,21 @@ do_test (void)
|
|||||||
bindtextdomain ("codeset", OBJPFX "domaindir");
|
bindtextdomain ("codeset", OBJPFX "domaindir");
|
||||||
|
|
||||||
/* Here we expect output in ISO-8859-1. */
|
/* Here we expect output in ISO-8859-1. */
|
||||||
s = gettext ("cheese");
|
TEST_COMPARE_STRING (gettext ("cheese"), "K\344se");
|
||||||
if (strcmp (s, "K\344se"))
|
|
||||||
{
|
|
||||||
printf ("call 1 returned: %s\n", s);
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bind_textdomain_codeset ("codeset", "UTF-8");
|
|
||||||
|
|
||||||
/* Here we expect output in UTF-8. */
|
/* Here we expect output in UTF-8. */
|
||||||
s = gettext ("cheese");
|
bind_textdomain_codeset ("codeset", "UTF-8");
|
||||||
if (strcmp (s, "K\303\244se"))
|
TEST_COMPARE_STRING (gettext ("cheese"), "K\303\244se");
|
||||||
{
|
|
||||||
printf ("call 2 returned: %s\n", s);
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
/* `a with umlaut' is transliterated to `ae'. */
|
||||||
|
bind_textdomain_codeset ("codeset", "ASCII//TRANSLIT");
|
||||||
|
TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
|
||||||
|
|
||||||
|
/* Transliteration also works by default even if not set. */
|
||||||
|
bind_textdomain_codeset ("codeset", "ASCII");
|
||||||
|
TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TEST_FUNCTION do_test ()
|
#include <support/test-driver.c>
|
||||||
#include "../test-skeleton.c"
|
|
||||||
|
Loading…
Reference in New Issue
Block a user