about summary refs log tree commit diff
path: root/intl/dcigettext.c
diff options
context:
space:
mode:
Diffstat (limited to 'intl/dcigettext.c')
-rw-r--r--intl/dcigettext.c328
1 files changed, 201 insertions, 127 deletions
diff --git a/intl/dcigettext.c b/intl/dcigettext.c
index be312ce967..4f27cbb3d8 100644
--- a/intl/dcigettext.c
+++ b/intl/dcigettext.c
@@ -16,6 +16,13 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+/* Tell glibc's <string.h> to provide a prototype for mempcpy().
+   This must come before <config.h> because <config.h> may include
+   <features.h>, and once <features.h> has been included, it's too late.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE	1
+#endif
+
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
@@ -59,9 +66,6 @@ void free ();
 #endif
 
 #if defined HAVE_STRING_H || defined _LIBC
-# ifndef _GNU_SOURCE
-#  define _GNU_SOURCE	1
-# endif
 # include <string.h>
 #else
 # include <strings.h>
@@ -98,9 +102,12 @@ void free ();
 # include <bits/libc-lock.h>
 #else
 /* Provide dummy implementation if this is outside glibc.  */
-# define __libc_lock_define_initialized (CLASS, NAME)
+# define __libc_lock_define_initialized(CLASS, NAME)
 # define __libc_lock_lock(NAME)
 # define __libc_lock_unlock(NAME)
+# define __libc_rwlock_define_initialized(CLASS, NAME)
+# define __libc_rwlock_rdlock(NAME)
+# define __libc_rwlock_unlock(NAME)
 #endif
 
 /* @@ end of prolog @@ */
@@ -626,9 +633,9 @@ _nl_find_msg (domain_file, msgid, index)
      const char *msgid;
      unsigned long int index;
 {
-  size_t act = 0;
-  size_t top, bottom;
   struct loaded_domain *domain;
+  size_t act;
+  char *result;
 
   if (domain_file->decided == 0)
     _nl_load_domain (domain_file);
@@ -657,103 +664,8 @@ _nl_find_msg (domain_file, msgid, index)
 		     domain->data + W (domain->must_swap,
 				       domain->orig_tab[nstr - 1].offset)) == 0)
 	{
-	  /* We found an entry.  If we have to convert the string to use
-	     a different character set this is the time.  */
-	  char *result =
-	    (char *) domain->data + W (domain->must_swap,
-				       domain->trans_tab[nstr - 1].offset);
-
-	  /* Now skip some strings.  How much depends on the index passed
-	     in.  */
-	  while (index-- > 0)
-	    {
-#ifdef _LIBC
-	      result = __rawmemchr (result, '\0');
-#else
-	      result = strchr (result, '\0');
-#endif
-	      /* And skip over the NUL byte.  */
-	      ++result;
-	    }
-
-	  if (
-#ifdef _LIBC
-	      domain->conv != (__gconv_t) -1
-#else
-# if HAVE_ICONV
-	      domain->conv != (iconv_t) -1
-# endif
-#endif
-	      )
-	    {
-	      /* We are supposed to do a conversion.  First allocate an
-		 appropriate table with the same structure as the hash
-		 table in the file where we can put the pointers to the
-		 converted strings in.  */
-	      if (domain->conv_tab == NULL
-		  && ((domain->conv_tab = (char **) calloc (domain->hash_size,
-							    sizeof (char *)))
-		      == NULL))
-		/* Mark that we didn't succeed allocating a table.  */
-		domain->conv_tab = (char **) -1;
-
-	      if (domain->conv_tab == (char **) -1)
-		/* Nothing we can do, no more memory.  */
-		return NULL;
-
-	      if (domain->conv_tab[idx] == NULL)
-		{
-		  /* We haven't used this string so far, so it is not
-		     translated yet.  Do this now.  */
-#ifdef _LIBC
-		  /* For glibc we use a bit more efficient memory handling.
-		     We allocate always larger blocks which get used over
-		     time.  This is faster than many small allocations.   */
-		  __libc_lock_define_initialized (static, lock)
-		  static unsigned char *freemem;
-		  static size_t freemem_size;
-		  /* Note that we include the NUL byte.  */
-		  size_t resultlen = strlen (result) + 1;
-		  const unsigned char *inbuf = result;
-		  unsigned char *outbuf = freemem;
-		  size_t written;
-		  int res;
-
-		  __libc_lock_lock (lock);
-
-		  while ((res = __gconv (domain->conv,
-					 &inbuf, inbuf + resultlen,
-					 &outbuf, outbuf + freemem_size,
-					 &written)) == __GCONV_OK)
-		    {
-		      if (res != __GCONV_FULL_OUTPUT)
-			goto out;
-
-		      /* We must resize the buffer.  */
-		      freemem_size = MAX (2 * freemem_size, 4064);
-		      freemem = (char *) malloc (freemem_size);
-		      if (freemem == NULL)
-			goto out;
-
-		      inbuf = result;
-		      outbuf = freemem;
-		    }
-
-		  /* We have now in our buffer a converted string.  Put this
-		     in the hash table  */
-		  domain->conv_tab[idx] = freemem;
-		  freemem_size -= outbuf - freemem;
-		  freemem = outbuf;
-
-		out:
-		  __libc_lock_unlock (lock);
-#endif
-		}
-
-	      result = domain->conv_tab[idx];
-	    }
-
-	  return result;
+	  act = nstr - 1;
+	  goto found;
 	}
 
       while (1)
@@ -773,37 +685,199 @@ _nl_find_msg (domain_file, msgid, index)
 			  domain->data + W (domain->must_swap,
 					    domain->orig_tab[nstr - 1].offset))
 		  == 0))
-	    return ((char *) domain->data
-		    + W (domain->must_swap,
-			 domain->trans_tab[nstr - 1].offset));
+	    {
+	      act = nstr - 1;
+	      goto found;
+	    }
 	}
       /* NOTREACHED */
     }
+  else
+    {
+      /* Try the default method:  binary search in the sorted array of
+	 messages.  */
+      size_t top, bottom;
+
+      bottom = 0;
+      top = domain->nstrings;
+      while (bottom < top)
+	{
+	  int cmp_val;
+
+	  act = (bottom + top) / 2;
+	  cmp_val = strcmp (msgid, (domain->data
+				    + W (domain->must_swap,
+					 domain->orig_tab[act].offset)));
+	  if (cmp_val < 0)
+	    top = act;
+	  else if (cmp_val > 0)
+	    bottom = act + 1;
+	  else
+	    goto found;
+	}
+      /* No translation was found.  */
+      return NULL;
+    }
 
-  /* Now we try the default method:  binary search in the sorted
-     array of messages.  */
-  bottom = 0;
-  top = domain->nstrings;
-  while (bottom < top)
+ found:
+  /* The translation was found at index ACT.  If we have to convert the
+     string to use a different character set, this is the time.  */
+  result = (char *) domain->data
+	   + W (domain->must_swap, domain->trans_tab[act].offset);
+
+#if defined _LIBC || HAVE_ICONV
+  if (
+# ifdef _LIBC
+      domain->conv != (__gconv_t) -1
+# else
+#  if HAVE_ICONV
+      domain->conv != (iconv_t) -1
+#  endif
+# endif
+      )
     {
-      int cmp_val;
-
-      act = (bottom + top) / 2;
-      cmp_val = strcmp (msgid, (domain->data
-				+ W (domain->must_swap,
-				     domain->orig_tab[act].offset)));
-      if (cmp_val < 0)
-	top = act;
-      else if (cmp_val > 0)
-	bottom = act + 1;
-      else
-	break;
+      /* We are supposed to do a conversion.  First allocate an
+	 appropriate table with the same structure as the table
+	 of translations in the file, where we can put the pointers
+	 to the converted strings in.
+	 The is a slight complication with the INDEX: We don't know
+	 a priori which entries are plural entries. Therefore at any
+	 moment we can only translate the variants 0 .. INDEX.  */
+
+      if (domain->conv_tab == NULL
+	  && ((domain->conv_tab = (char **) calloc (domain->nstrings,
+						    sizeof (char *)))
+	      == NULL))
+	/* Mark that we didn't succeed allocating a table.  */
+	domain->conv_tab = (char **) -1;
+
+      if (domain->conv_tab == (char **) -1)
+	/* Nothing we can do, no more memory.  */
+	goto converted;
+
+      if (domain->conv_tab[act] == NULL
+	  || *(nls_uint32 *) domain->conv_tab[act] < index)
+	{
+	  /* We haven't used this string so far, so it is not
+	     translated yet.  Do this now.  */
+	  /* We use a bit more efficient memory handling.
+	     We allocate always larger blocks which get used over
+	     time.  This is faster than many small allocations.   */
+	  __libc_lock_define_initialized (static, lock)
+	  static unsigned char *freemem;
+	  static size_t freemem_size;
+
+	  size_t resultlen;
+	  const unsigned char *inbuf;
+	  unsigned char *outbuf;
+
+	  /* Note that we translate (index + 1) consecutive strings at
+	     once, including the final NUL byte.  */
+	  {
+	    unsigned long int i = index;
+	    char *p = result;
+	    do
+	      p += strlen (p) + 1;
+	    while (i-- > 0);
+	    resultlen = p - result;
+	  }
+
+	  inbuf = result;
+	  outbuf = freemem + 4;
+
+	  __libc_lock_lock (lock);
+
+# ifdef _LIBC
+	  {
+	    size_t written;
+	    int res;
+
+	    while ((res = __gconv (domain->conv,
+				   &inbuf, inbuf + resultlen,
+				   &outbuf, outbuf + freemem_size,
+				   &written)) == __GCONV_OK)
+	      {
+		if (res != __GCONV_FULL_OUTPUT)
+		  goto out;
+
+		/* We must resize the buffer.  */
+		freemem_size = MAX (2 * freemem_size, 4064);
+		freemem = (char *) malloc (freemem_size);
+		if (freemem == NULL)
+		  goto out;
+
+		inbuf = result;
+		outbuf = freemem + 4;
+	      }
+	  }
+# else
+#  if HAVE_ICONV
+	  for (;;)
+	    {
+	      const char *inptr = (const char *) inbuf;
+	      size_t inleft = resultlen;
+	      char *outptr = (char *) outbuf;
+	      size_t outleft = freemem_size;
+
+	      if (iconv (domain->conv, &inptr, &inleft, &outptr, &outleft)
+		  != (size_t)(-1))
+		{
+		  outbuf = (unsigned char *) outptr;
+		  break;
+		}
+	      if (errno != E2BIG)
+		goto out;
+
+	      /* We must resize the buffer.  */
+	      freemem_size = 2 * freemem_size;
+	      if (freemem_size < 4064)
+		freemem_size = 4064;
+	      freemem = (char *) malloc (freemem_size);
+	      if (freemem == NULL)
+		goto out;
+
+	      outbuf = freemem + 4;
+	    }
+#  endif
+# endif
+
+	  /* We have now in our buffer a converted string.  Put this
+	     into the table of conversions.  */
+	  *(nls_uint32 *) freemem = index;
+	  domain->conv_tab[act] = freemem;
+	  /* Shrink freemem, but keep it aligned.  */
+	  freemem_size -= outbuf - freemem;
+	  freemem = outbuf;
+	  freemem += freemem_size & 3;
+	  freemem_size = freemem_size & ~3;
+
+	out:
+	  __libc_lock_unlock (lock);
+	}
+
+      /* Now domain->conv_tab[act] contains the translation of at least
+	 the variants 0 .. INDEX.  */
+      result = domain->conv_tab[act] + 4;
+    }
+
+ converted:
+  /* The result string is converted.  */
+
+#endif /* _LIBC || HAVE_ICONV */
+
+  /* Now skip some strings.  How much depends on the index passed in.  */
+  while (index-- > 0)
+    {
+#ifdef _LIBC
+      result = __rawmemchr (result, '\0');
+#else
+      result = strchr (result, '\0');
+#endif
+      /* And skip over the NUL byte.  */
+      ++result;
     }
 
-  /* If an translation is found return this.  */
-  return bottom >= top ? NULL : ((char *) domain->data
-				 + W (domain->must_swap,
-				      domain->trans_tab[act].offset));
+  return result;
 }