intl patches (19)

Bruno Haible haible@ilog.fr
Mon Apr 9 06:22:00 GMT 2001


There is a bug in intl: bind_textdomain_codeset() has no effect when
gettext() has already been called on the same domain. Example:

      printf ("%s\n", gettext ("cheese"));
      bind_textdomain_codeset ("domain", "UTF-8");
      printf ("%s\n", gettext ("cheese"));

But applications like vim rely on bind_textdomain_codeset() having an
effect on later gettext() calls.

There is currently no workaround for this bug, because applications cannot
turn off gettext's caching mechanisms.

Here is a fix. The patch
  - increments a domain-specific counter when bind_textdomain_codeset()
    changes the codeset for a domain. The counter works like a timestamp.
  - stores the domain-specific counter in the 'struct loaded_domain' when
    it is created,
  - compares the two counters when a message is to be fetched through
    the catalog, and if the one in the 'struct loaded_domain' is too old,
    the previous iconv() results are abandoned, and a new __gconv_t/iconv_t
    descriptor is fetched,
  - stops storing the domainbinding in 'struct loaded_l10nfile', because
    this domainbinding can be NULL before bind_textdomain_codeset() but will
    be != NULL after bind_textdomain_codeset(), thus the older (stored)
    value may be invalid.
  - adds a new test 'tst-codeset' to verify the bug is fixed.

Bruno


2001-04-07  Bruno Haible <haible@clisp.cons.org>

	* intl/gettextP.h (struct loaded_domain): Add codeset_cntr field.
	(struct binding): Add codeset_cntr field.
	(_nl_load_domain): Add domainbinding argument.
	(_nl_init_domain_conv, _nl_free_domain_conv): New declarations.
	(_nl_find_msg): New declaration, moved here from loadinfo.h.
	* intl/loadinfo.h (struct loaded_l10nfile): Remove domainbinding field.
	(_nl_make_l10nflist): Remove domainbinding argument.
	(_nl_find_msg): Move declaration to gettextP.h.
	* intl/bindtextdom.c (set_binding_values): Initialize ->codeset_cntr
	to 0. Increment it when ->codeset is changed.
	* intl/dcigettext.c (DCIGETTEXT): Pass binding to _nl_find_msg.
	(_nl_find_msg): Add domainbinding argument. Reinitialize the converter
	if domainbinding->codeset_cntr has been incremented.
	* intl/finddomain.c (_nl_find_domain): Don't pass domainbinding to
	_nl_make_l10nflist(). Pass it to _nl_load_domain() instead.
	* intl/l10nflist.c (_nl_make_l10nflist): Remove domainbinding argument.
	* intl/loadmsgcat.c (_nl_init_domain_conv): New function, extracted
	 from _nl_load_domain. Append //TRANSLIT also when using libiconv.
	(_nl_free_domain_conv): New function, extracted from _nl_unload_domain.
	(_nl_load_domain): Add domainbinding argument. Call
	_nl_init_domain_conv.
	(_nl_unload_domain): Call _nl_free_domain_conv.
	* intl/Makefile (distribute): Add tst-codeset.sh, tstcodeset.po.
	(test-srcs): Add tst-codeset.
	(tests): Depend on tst-codeset.out.
	(tst-codeset.out): New rule.
	(CFLAGS-tst-codeset.c): New variable.
	* intl/tst-codeset.sh: New file.
	* intl/tstcodeset.po: New file.
	* intl/tst-codeset.c: New file.
	* locale/findlocale.c (_nl_find_locale): Update _nl_make_l10nflist
	calls.

*** glibc-20010315/intl/gettextP.h.bak	Sun Mar 18 00:19:31 2001
--- glibc-20010315/intl/gettextP.h	Sat Apr  7 22:28:54 2001
***************
*** 129,134 ****
--- 129,135 ----
    struct string_desc *trans_tab;
    nls_uint32 hash_size;
    nls_uint32 *hash_tab;
+   int codeset_cntr;
  #ifdef _LIBC
    __gconv_t conv;
  #else
***************
*** 156,161 ****
--- 157,163 ----
  {
    struct binding *next;
    char *dirname;
+   int codeset_cntr;	/* Incremented each time codeset changes.  */
    char *codeset;
    char domainname[ZERO];
  };
***************
*** 170,179 ****
  						 const char *__domainname,
  					      struct binding *__domainbinding))
       internal_function;
! void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain))
       internal_function;
  void _nl_unload_domain PARAMS ((struct loaded_domain *__domain))
       internal_function;
  
  #ifdef _LIBC
  extern char *__gettext PARAMS ((const char *__msgid));
--- 172,193 ----
  						 const char *__domainname,
  					      struct binding *__domainbinding))
       internal_function;
! void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain,
! 			      struct binding *__domainbinding))
       internal_function;
  void _nl_unload_domain PARAMS ((struct loaded_domain *__domain))
       internal_function;
+ const char *_nl_init_domain_conv PARAMS ((struct loaded_l10nfile *__domain_file,
+ 					  struct loaded_domain *__domain,
+ 					  struct binding *__domainbinding))
+      internal_function;
+ void _nl_free_domain_conv PARAMS ((struct loaded_domain *__domain))
+      internal_function;
+ 
+ char *_nl_find_msg PARAMS ((struct loaded_l10nfile *domain_file,
+ 			    struct binding *domainbinding,
+ 			    const char *msgid, size_t *lengthp))
+      internal_function;
  
  #ifdef _LIBC
  extern char *__gettext PARAMS ((const char *__msgid));
*** glibc-20010315/intl/loadinfo.h.bak	Sat Mar 17 19:45:29 2001
--- glibc-20010315/intl/loadinfo.h	Sat Apr  7 22:28:54 2001
***************
*** 64,70 ****
  struct loaded_l10nfile
  {
    const char *filename;
-   struct binding *domainbinding;
    int decided;
  
    const void *data;
--- 64,69 ----
***************
*** 89,96 ****
  			    const char *normalized_codeset,
  			    const char *modifier, const char *special,
  			    const char *sponsor, const char *revision,
! 			    const char *filename,
! 			    struct binding *domainbinding, int do_allocate));
  
  
  extern const char *_nl_expand_alias PARAMS ((const char *name));
--- 88,94 ----
  			    const char *normalized_codeset,
  			    const char *modifier, const char *special,
  			    const char *sponsor, const char *revision,
! 			    const char *filename, int do_allocate));
  
  
  extern const char *_nl_expand_alias PARAMS ((const char *name));
***************
*** 108,116 ****
  
  extern char *_nl_find_language PARAMS ((const char *name));
  
- 
- extern char *_nl_find_msg PARAMS ((struct loaded_l10nfile *domain_file,
- 				   const char *msgid, size_t *lengthp))
-      internal_function;
- 
  #endif	/* loadinfo.h */
--- 106,109 ----
*** glibc-20010315/intl/bindtextdom.c.bak	Sat Mar 17 18:23:23 2001
--- glibc-20010315/intl/bindtextdom.c	Sat Apr  7 22:28:54 2001
***************
*** 218,223 ****
--- 218,224 ----
  			free (binding->codeset);
  
  		      binding->codeset = result;
+ 		      binding->codeset_cntr++;
  		      modified = 1;
  		    }
  		}
***************
*** 281,286 ****
--- 282,289 ----
  	/* The default value.  */
  	new_binding->dirname = (char *) _nl_default_dirname;
  
+       new_binding->codeset_cntr = 0;
+ 
        if (codesetp)
  	{
  	  const char *codeset = *codesetp;
***************
*** 301,306 ****
--- 304,310 ----
  	      memcpy (result, codeset, len);
  #endif
  	      codeset = result;
+ 	      new_binding->codeset_cntr++;
  	    }
  	  *codesetp = codeset;
  	  new_binding->codeset = (char *) codeset;
*** glibc-20010315/intl/dcigettext.c.bak	Sun Mar 18 00:26:39 2001
--- glibc-20010315/intl/dcigettext.c	Sat Apr  7 22:28:54 2001
***************
*** 598,604 ****
  
        if (domain != NULL)
  	{
! 	  retval = _nl_find_msg (domain, msgid1, &retlen);
  
  	  if (retval == NULL)
  	    {
--- 598,604 ----
  
        if (domain != NULL)
  	{
! 	  retval = _nl_find_msg (domain, binding, msgid1, &retlen);
  
  	  if (retval == NULL)
  	    {
***************
*** 606,613 ****
  
  	      for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
  		{
! 		  retval = _nl_find_msg (domain->successor[cnt], msgid1,
! 					 &retlen);
  
  		  if (retval != NULL)
  		    {
--- 606,613 ----
  
  	      for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
  		{
! 		  retval = _nl_find_msg (domain->successor[cnt], binding,
! 					 msgid1, &retlen);
  
  		  if (retval != NULL)
  		    {
***************
*** 676,683 ****
  
  char *
  internal_function
! _nl_find_msg (domain_file, msgid, lengthp)
       struct loaded_l10nfile *domain_file;
       const char *msgid;
       size_t *lengthp;
  {
--- 676,684 ----
  
  char *
  internal_function
! _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
       struct loaded_l10nfile *domain_file;
+      struct binding *domainbinding;
       const char *msgid;
       size_t *lengthp;
  {
***************
*** 687,693 ****
    size_t resultlen;
  
    if (domain_file->decided == 0)
!     _nl_load_domain (domain_file);
  
    if (domain_file->data == NULL)
      return NULL;
--- 688,694 ----
    size_t resultlen;
  
    if (domain_file->decided == 0)
!     _nl_load_domain (domain_file, domainbinding);
  
    if (domain_file->data == NULL)
      return NULL;
***************
*** 766,771 ****
--- 767,782 ----
    resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
  
  #if defined _LIBC || HAVE_ICONV
+   if (domain->codeset_cntr
+       != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
+     {
+       /* The domain's codeset has changed through bind_textdomain_codeset()
+ 	 since the message catalog was initialized or last accessed.  We
+ 	 have to reinitialize the converter.  */
+       _nl_free_domain_conv (domain);
+       _nl_init_domain_conv (domain_file, domain, domainbinding);
+     }
+ 
    if (
  # ifdef _LIBC
        domain->conv != (__gconv_t) -1
*** glibc-20010315/intl/finddomain.c.bak	Sat Mar 17 17:42:23 2001
--- glibc-20010315/intl/finddomain.c	Sat Apr  7 22:28:54 2001
***************
*** 107,121 ****
       be one data set in the list of loaded domains.  */
    retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
  			       strlen (dirname) + 1, 0, locale, NULL, NULL,
! 			       NULL, NULL, NULL, NULL, NULL, domainname,
! 			       domainbinding, 0);
    if (retval != NULL)
      {
        /* We know something about this locale.  */
        int cnt;
  
        if (retval->decided == 0)
! 	_nl_load_domain (retval);
  
        if (retval->data != NULL)
  	return retval;
--- 107,120 ----
       be one data set in the list of loaded domains.  */
    retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
  			       strlen (dirname) + 1, 0, locale, NULL, NULL,
! 			       NULL, NULL, NULL, NULL, NULL, domainname, 0);
    if (retval != NULL)
      {
        /* We know something about this locale.  */
        int cnt;
  
        if (retval->decided == 0)
! 	_nl_load_domain (retval, domainbinding);
  
        if (retval->data != NULL)
  	return retval;
***************
*** 123,129 ****
        for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
  	{
  	  if (retval->successor[cnt]->decided == 0)
! 	    _nl_load_domain (retval->successor[cnt]);
  
  	  if (retval->successor[cnt]->data != NULL)
  	    break;
--- 122,128 ----
        for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
  	{
  	  if (retval->successor[cnt]->decided == 0)
! 	    _nl_load_domain (retval->successor[cnt], domainbinding);
  
  	  if (retval->successor[cnt]->data != NULL)
  	    break;
***************
*** 164,184 ****
    retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
  			       strlen (dirname) + 1, mask, language, territory,
  			       codeset, normalized_codeset, modifier, special,
! 			       sponsor, revision, domainname, domainbinding,
! 			       1);
    if (retval == NULL)
      /* This means we are out of core.  */
      return NULL;
  
    if (retval->decided == 0)
!     _nl_load_domain (retval);
    if (retval->data == NULL)
      {
        int cnt;
        for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
  	{
  	  if (retval->successor[cnt]->decided == 0)
! 	    _nl_load_domain (retval->successor[cnt]);
  	  if (retval->successor[cnt]->data != NULL)
  	    break;
  	}
--- 163,182 ----
    retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
  			       strlen (dirname) + 1, mask, language, territory,
  			       codeset, normalized_codeset, modifier, special,
! 			       sponsor, revision, domainname, 1);
    if (retval == NULL)
      /* This means we are out of core.  */
      return NULL;
  
    if (retval->decided == 0)
!     _nl_load_domain (retval, domainbinding);
    if (retval->data == NULL)
      {
        int cnt;
        for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
  	{
  	  if (retval->successor[cnt]->decided == 0)
! 	    _nl_load_domain (retval->successor[cnt], domainbinding);
  	  if (retval->successor[cnt]->data != NULL)
  	    break;
  	}
*** glibc-20010315/intl/l10nflist.c.bak	Sat Mar 17 19:45:29 2001
--- glibc-20010315/intl/l10nflist.c	Sat Apr  7 22:28:54 2001
***************
*** 175,181 ****
  struct loaded_l10nfile *
  _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
  		    territory, codeset, normalized_codeset, modifier, special,
! 		    sponsor, revision, filename, domainbinding, do_allocate)
       struct loaded_l10nfile **l10nfile_list;
       const char *dirlist;
       size_t dirlist_len;
--- 175,181 ----
  struct loaded_l10nfile *
  _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
  		    territory, codeset, normalized_codeset, modifier, special,
! 		    sponsor, revision, filename, do_allocate)
       struct loaded_l10nfile **l10nfile_list;
       const char *dirlist;
       size_t dirlist_len;
***************
*** 189,195 ****
       const char *sponsor;
       const char *revision;
       const char *filename;
-      struct binding *domainbinding;
       int do_allocate;
  {
    char *abs_filename;
--- 189,194 ----
***************
*** 310,316 ****
      return NULL;
  
    retval->filename = abs_filename;
-   retval->domainbinding = domainbinding;
    retval->decided = (__argz_count (dirlist, dirlist_len) != 1
  		     || ((mask & XPG_CODESET) != 0
  			 && (mask & XPG_NORM_CODESET) != 0));
--- 309,314 ----
***************
*** 346,353 ****
  	    = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
  				  language, territory, codeset,
  				  normalized_codeset, modifier, special,
! 				  sponsor, revision, filename, domainbinding,
! 				  1);
        }
    retval->successor[entries] = NULL;
  
--- 344,350 ----
  	    = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
  				  language, territory, codeset,
  				  normalized_codeset, modifier, special,
! 				  sponsor, revision, filename, 1);
        }
    retval->successor[entries] = NULL;
  
*** glibc-20010315/intl/loadmsgcat.c.bak	Sat Mar 17 23:39:33 2001
--- glibc-20010315/intl/loadmsgcat.c	Sat Apr  7 22:28:55 2001
***************
*** 207,218 ****
  #endif
  
  
  /* Load the message catalogs specified by FILENAME.  If it is no valid
     message catalog do nothing.  */
  void
  internal_function
! _nl_load_domain (domain_file)
       struct loaded_l10nfile *domain_file;
  {
    int fd;
    size_t size;
--- 207,352 ----
  #endif
  
  
+ /* Initialize the codeset dependent parts of an opened message catalog.
+    Return the header entry.  */
+ const char *
+ internal_function
+ _nl_init_domain_conv (domain_file, domain, domainbinding)
+      struct loaded_l10nfile *domain_file;
+      struct loaded_domain *domain;
+      struct binding *domainbinding;
+ {
+   /* Find out about the character set the file is encoded with.
+      This can be found (in textual form) in the entry "".  If this
+      entry does not exist or if this does not contain the `charset='
+      information, we will assume the charset matches the one the
+      current locale and we don't have to perform any conversion.  */
+   char *nullentry;
+   size_t nullentrylen;
+ 
+   /* Preinitialize fields, to avoid recursion during _nl_find_msg.  */
+   domain->codeset_cntr =
+     (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
+ #ifdef _LIBC
+   domain->conv = (__gconv_t) -1;
+ #else
+ # if HAVE_ICONV
+   domain->conv = (iconv_t) -1;
+ # endif
+ #endif
+   domain->conv_tab = NULL;
+ 
+   /* Get the header entry.  */
+   nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
+ 
+   if (nullentry != NULL)
+     {
+ #if defined _LIBC || HAVE_ICONV
+       const char *charsetstr;
+ 
+       charsetstr = strstr (nullentry, "charset=");
+       if (charsetstr != NULL)
+ 	{
+ 	  size_t len;
+ 	  char *charset;
+ 	  const char *outcharset;
+ 
+ 	  charsetstr += strlen ("charset=");
+ 	  len = strcspn (charsetstr, " \t\n");
+ 
+ 	  charset = (char *) alloca (len + 1);
+ # if defined _LIBC || HAVE_MEMPCPY
+ 	  *((char *) mempcpy (charset, charsetstr, len)) = '\0';
+ # else
+ 	  memcpy (charset, charsetstr, len);
+ 	  charset[len] = '\0';
+ # endif
+ 
+ 	  /* The output charset should normally be determined by the
+ 	     locale.  But sometimes the locale is not used or not correctly
+ 	     set up, so we provide a possibility for the user to override
+ 	     this.  Moreover, the value specified through
+ 	     bind_textdomain_codeset overrides both.  */
+ 	  if (domainbinding != NULL && domainbinding->codeset != NULL)
+ 	    outcharset = domainbinding->codeset;
+ 	  else
+ 	    {
+ 	      outcharset = getenv ("OUTPUT_CHARSET");
+ 	      if (outcharset == NULL || outcharset[0] == '\0')
+ 		{
+ # ifdef _LIBC
+ 		  outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
+ # else
+ #  if HAVE_ICONV
+ 		  extern const char *locale_charset (void);
+ 		  outcharset = locale_charset ();
+ #  endif
+ # endif
+ 		}
+ 	    }
+ 
+ # ifdef _LIBC
+ 	  /* We always want to use transliteration.  */
+ 	  outcharset = norm_add_slashes (outcharset, "TRANSLIT");
+ 	  charset = norm_add_slashes (charset, NULL);
+ 	  if (__gconv_open (outcharset, charset, &domain->conv,
+ 			    GCONV_AVOID_NOCONV)
+ 	      != __GCONV_OK)
+ 	    domain->conv = (__gconv_t) -1;
+ # else
+ #  if HAVE_ICONV
+ 	  /* When using GNU libiconv, we want to use transliteration.  */
+ #   if _LIBICONV_VERSION
+ 	  len = strlen (outcharset);
+ 	  {
+ 	    char *tmp = (char *) alloca (len + 10 + 1);
+ 	    memcpy (tmp, outcharset, len);
+ 	    memcpy (tmp + len, "//TRANSLIT", 10 + 1);
+ 	    outcharset = tmp;
+ 	  }
+ #   endif
+ 	  domain->conv = iconv_open (outcharset, charset);
+ #   if _LIBICONV_VERSION
+ 	  freea (outcharset);
+ #   endif
+ #  endif
+ # endif
+ 
+ 	  freea (charset);
+ 	}
+ #endif /* _LIBC || HAVE_ICONV */
+     }
+ 
+   return nullentry;
+ }
+ 
+ /* Frees the codeset dependent parts of an opened message catalog.  */
+ void
+ internal_function
+ _nl_free_domain_conv (domain)
+      struct loaded_domain *domain;
+ {
+   if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
+     free (domain->conv_tab);
+ 
+ #ifdef _LIBC
+   if (domain->conv != (__gconv_t) -1)
+     __gconv_close (domain->conv);
+ #else
+ # if HAVE_ICONV
+   if (domain->conv != (iconv_t) -1)
+     iconv_close (domain->conv);
+ # endif
+ #endif
+ }
+ 
  /* Load the message catalogs specified by FILENAME.  If it is no valid
     message catalog do nothing.  */
  void
  internal_function
! _nl_load_domain (domain_file, domainbinding)
       struct loaded_l10nfile *domain_file;
+      struct binding *domainbinding;
  {
    int fd;
    size_t size;
***************
*** 224,235 ****
    struct mo_file_header *data = (struct mo_file_header *) -1;
    int use_mmap = 0;
    struct loaded_domain *domain;
!   char *nullentry;
!   size_t nullentrylen;
  
    domain_file->decided = 1;
    domain_file->data = NULL;
  
    /* If the record does not represent a valid locale the FILENAME
       might be NULL.  This can happen when according to the given
       specification the locale file name is different for XPG and CEN
--- 358,372 ----
    struct mo_file_header *data = (struct mo_file_header *) -1;
    int use_mmap = 0;
    struct loaded_domain *domain;
!   const char *nullentry;
  
    domain_file->decided = 1;
    domain_file->data = NULL;
  
+   /* Note that it would be useless to store domainbinding in domain_file
+      because domainbinding might be == NULL now but != NULL later (after
+      a call to bind_textdomain_codeset).  */
+ 
    /* If the record does not represent a valid locale the FILENAME
       might be NULL.  This can happen when according to the given
       specification the locale file name is different for XPG and CEN
***************
*** 355,439 ****
        return;
      }
  
!   /* Now find out about the character set the file is encoded with.
!      This can be found (in textual form) in the entry "".  If this
!      entry does not exist or if this does not contain the `charset='
!      information, we will assume the charset matches the one the
!      current locale and we don't have to perform any conversion.  */
! #ifdef _LIBC
!   domain->conv = (__gconv_t) -1;
! #else
! # if HAVE_ICONV
!   domain->conv = (iconv_t) -1;
! # endif
! #endif
!   domain->conv_tab = NULL;
!   nullentry = _nl_find_msg (domain_file, "", &nullentrylen);
!   if (nullentry != NULL)
!     {
! #if defined _LIBC || HAVE_ICONV
!       const char *charsetstr;
! 
!       charsetstr = strstr (nullentry, "charset=");
!       if (charsetstr != NULL)
! 	{
! 	  size_t len;
! 	  char *charset;
! 	  const char *outcharset;
! 
! 	  charsetstr += strlen ("charset=");
! 	  len = strcspn (charsetstr, " \t\n");
! 
! 	  charset = (char *) alloca (len + 1);
! # if defined _LIBC || HAVE_MEMPCPY
! 	  *((char *) mempcpy (charset, charsetstr, len)) = '\0';
! # else
! 	  memcpy (charset, charsetstr, len);
! 	  charset[len] = '\0';
! # endif
! 
! 	  /* The output charset should normally be determined by the
! 	     locale.  But sometimes the locale is not used or not correctly
! 	     set up, so we provide a possibility for the user to override
! 	     this.  Moreover, the value specified through
! 	     bind_textdomain_codeset overrides both.  */
! 	  if (domain_file->domainbinding != NULL
! 	      && domain_file->domainbinding->codeset != NULL)
! 	    outcharset = domain_file->domainbinding->codeset;
! 	  else
! 	    {
! 	      outcharset = getenv ("OUTPUT_CHARSET");
! 	      if (outcharset == NULL || outcharset[0] == '\0')
! 		{
! # ifdef _LIBC
! 		  outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
! # else
! #  if HAVE_ICONV
! 		  extern const char *locale_charset (void);
! 		  outcharset = locale_charset ();
! #  endif
! # endif
! 		}
! 	    }
! 
! # ifdef _LIBC
! 	  /* We always want to use transliteration.  */
! 	  outcharset = norm_add_slashes (outcharset, "TRANSLIT");
! 	  charset = norm_add_slashes (charset, NULL);
! 	  if (__gconv_open (outcharset, charset, &domain->conv,
! 			    GCONV_AVOID_NOCONV)
! 	      != __GCONV_OK)
! 	    domain->conv = (__gconv_t) -1;
! # else
! #  if HAVE_ICONV
! 	  domain->conv = iconv_open (outcharset, charset);
! #  endif
! # endif
! 
! 	  freea (charset);
! 	}
! #endif /* _LIBC || HAVE_ICONV */
!     }
  
    /* Also look for a plural specification.  */
    if (nullentry != NULL)
--- 492,501 ----
        return;
      }
  
!   /* Now initialize the character set converter from the character set
!      the file is encoded with (found in the header entry) to the domain's
!      specified character set or the locale's character set.  */
!   nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
  
    /* Also look for a plural specification.  */
    if (nullentry != NULL)
***************
*** 498,508 ****
    if (domain->plural != &germanic_plural)
      __gettext_free_exp (domain->plural);
  
!   if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
!     free (domain->conv_tab);
! 
!   if (domain->conv != (__gconv_t) -1)
!     __gconv_close (domain->conv);
  
  # ifdef _POSIX_MAPPED_FILES
    if (domain->use_mmap)
--- 560,566 ----
    if (domain->plural != &germanic_plural)
      __gettext_free_exp (domain->plural);
  
!   _nl_free_domain_conv (domain);
  
  # ifdef _POSIX_MAPPED_FILES
    if (domain->use_mmap)
*** glibc-20010315/intl/Makefile.bak	Sat Apr  7 21:46:54 2001
--- glibc-20010315/intl/Makefile	Sat Apr  7 22:21:44 2001
***************
*** 25,34 ****
  	   finddomain loadmsgcat localealias textdomain	\
  	   l10nflist explodename plural
  distribute = gettext.h gettextP.h hash-string.h loadinfo.h locale.alias \
! 	     plural.y po2test.sed tst-gettext.sh tst-translit.sh	\
! 	     translit.po tst-gettext2.sh tstlang1.po tstlang2.po
  
! test-srcs := tst-gettext tst-translit tst-gettext2
  tests = tst-ngettext
  
  before-compile = $(objpfx)msgs.h
--- 25,34 ----
  	   finddomain loadmsgcat localealias textdomain	\
  	   l10nflist explodename plural
  distribute = gettext.h gettextP.h hash-string.h loadinfo.h locale.alias \
! 	     plural.y po2test.sed tst-gettext.sh tst-translit.sh tst-codeset.sh \
! 	     translit.po tst-gettext2.sh tstlang1.po tstlang2.po tstcodeset.po
  
! test-srcs := tst-gettext tst-translit tst-gettext2 tst-codeset
  tests = tst-ngettext
  
  before-compile = $(objpfx)msgs.h
***************
*** 54,60 ****
  ifeq (no,$(cross-compiling))
  ifeq (yes,$(build-shared))
  ifneq ($(strip $(MSGFMT)),:)
! tests: $(objpfx)tst-translit.out $(objpfx)tst-gettext2.out
  endif
  ifneq (no,$(PERL))
  tests: $(objpfx)mtrace-tst-gettext
--- 54,61 ----
  ifeq (no,$(cross-compiling))
  ifeq (yes,$(build-shared))
  ifneq ($(strip $(MSGFMT)),:)
! tests: $(objpfx)tst-translit.out $(objpfx)tst-gettext2.out \
!        $(objpfx)tst-codeset.out
  endif
  ifneq (no,$(PERL))
  tests: $(objpfx)mtrace-tst-gettext
***************
*** 68,73 ****
--- 69,76 ----
  	$(SHELL) -e $< $(common-objpfx) $(common-objpfx)intl/
  $(objpfx)tst-gettext2.out: tst-gettext2.sh $(objpfx)tst-gettext2
  	$(SHELL) -e $< $(common-objpfx) $(common-objpfx)intl/
+ $(objpfx)tst-codeset.out: tst-codeset.sh $(objpfx)tst-codeset
+ 	$(SHELL) -e $< $(common-objpfx) $(common-objpfx)intl/
  endif
  endif
  
***************
*** 78,83 ****
--- 81,87 ----
  CFLAGS-tst-gettext.c = -DTESTSTRS_H=\"$(objpfx)msgs.h\"
  CFLAGS-tst-gettext2.c = -DOBJPFX=\"$(objpfx)\"
  CFLAGS-tst-translit.c = -DOBJPFX=\"$(objpfx)\"
+ CFLAGS-tst-codeset.c = -DOBJPFX=\"$(objpfx)\"
  
  $(objpfx)tst-translit.out: $(objpfx)tst-gettext.out
  
*** glibc-20010315/intl/tst-codeset.sh.bak	Sat Apr  7 21:48:27 2001
--- glibc-20010315/intl/tst-codeset.sh	Sat Apr  7 22:18:19 2001
***************
*** 0 ****
--- 1,42 ----
+ #! /bin/sh
+ # Test of bind_textdomain_codeset.
+ # Copyright (C) 2001 Free Software Foundation, Inc.
+ # This file is part of the GNU C Library.
+ #
+ # The GNU C Library is free software; you can redistribute it and/or
+ # modify it under the terms of the GNU Library General Public License as
+ # published by the Free Software Foundation; either version 2 of the
+ # License, or (at your option) any later version.
+ #
+ # The GNU C Library is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ # Library General Public License for more details.
+ #
+ # You should have received a copy of the GNU Library General Public
+ # License along with the GNU C Library; see the file COPYING.LIB.  If
+ # not, write to the Free Software Foundation, Inc.,
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ 
+ common_objpfx=$1
+ objpfx=$2
+ 
+ GCONV_PATH=${common_objpfx}iconvdata
+ export GCONV_PATH
+ LOCPATH=${common_objpfx}localedata
+ export LOCPATH
+ LC_ALL=C
+ export LC_ALL
+ 
+ # Generate the test data.
+ test -d ${objpfx}domaindir || mkdir ${objpfx}domaindir
+ # Create the domain directories.
+ test -d ${objpfx}domaindir/de_DE || mkdir ${objpfx}domaindir/de_DE
+ test -d ${objpfx}domaindir/de_DE/LC_MESSAGES || mkdir ${objpfx}domaindir/de_DE/LC_MESSAGES
+ # Populate them.
+ msgfmt -o ${objpfx}domaindir/de_DE/LC_MESSAGES/codeset.mo tstcodeset.po
+ 
+ ${common_objpfx}elf/ld.so --library-path $common_objpfx \
+ ${objpfx}tst-codeset > ${objpfx}tst-codeset.out
+ 
+ exit $?
*** glibc-20010315/intl/tstcodeset.po.bak	Sat Apr  7 22:02:38 2001
--- glibc-20010315/intl/tstcodeset.po	Sat Apr  7 22:02:26 2001
***************
*** 0 ****
--- 1,8 ----
+ msgid ""
+ msgstr ""
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=ISO-8859-1\n"
+ "Content-Transfer-Encoding: 8-bit\n"
+ 
+ msgid "cheese"
+ msgstr "Käse"
*** glibc-20010315/intl/tst-codeset.c.bak	Sat Apr  7 22:18:42 2001
--- glibc-20010315/intl/tst-codeset.c	Sat Apr  7 22:27:36 2001
***************
*** 0 ****
--- 1,56 ----
+ /* Test of bind_textdomain_codeset.
+    Copyright (C) 2001 Free Software Foundation, Inc.
+    Contributed by Bruno Haible <haible@clisp.cons.org>, 2001.
+ 
+    The GNU C Library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+ 
+    The GNU C Library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+ 
+    You should have received a copy of the GNU Library General Public
+    License along with the GNU C Library; see the file COPYING.LIB.  If not,
+    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #include <libintl.h>
+ #include <locale.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ 
+ int
+ main (void)
+ {
+   char *s;
+   int result = 0;
+ 
+   unsetenv ("LANGUAGE");
+   unsetenv ("OUTPUT_CHARSET");
+   setlocale (LC_ALL, "de_DE.ISO-8859-1");
+   textdomain ("codeset");
+   bindtextdomain ("codeset", OBJPFX "domaindir");
+ 
+   /* Here we expect output in ISO-8859-1.  */
+   s = gettext ("cheese");
+   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.  */
+   s = gettext ("cheese");
+   if (strcmp (s, "K\303\244se"))
+     {
+       printf ("call 2 returned: %s\n", s);
+       result = 1;
+     }
+ 
+   return result;
+ }
*** glibc-20010315/locale/findlocale.c.bak	Mon Nov 27 23:28:39 2000
--- glibc-20010315/locale/findlocale.c	Sat Apr  7 22:30:29 2001
***************
*** 121,127 ****
  				    language, territory, codeset,
  				    normalized_codeset, modifier, special,
  				    sponsor, revision,
! 				    _nl_category_names[category], NULL, 0);
  
    if (locale_file == NULL)
      {
--- 121,127 ----
  				    language, territory, codeset,
  				    normalized_codeset, modifier, special,
  				    sponsor, revision,
! 				    _nl_category_names[category], 0);
  
    if (locale_file == NULL)
      {
***************
*** 132,138 ****
  					language, territory, codeset,
  					normalized_codeset, modifier, special,
  					sponsor, revision,
! 					_nl_category_names[category], NULL, 1);
        if (locale_file == NULL)
  	/* This means we are out of core.  */
  	return NULL;
--- 132,138 ----
  					language, territory, codeset,
  					normalized_codeset, modifier, special,
  					sponsor, revision,
! 					_nl_category_names[category], 1);
        if (locale_file == NULL)
  	/* This means we are out of core.  */
  	return NULL;



More information about the Libc-alpha mailing list