This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

support for ISO C 99 format string directive macros in gettext


Hi Ulrich,

Here is the patch that adds support for the <inttypes.h> macros PRId64 etc.
to libintl. Parallel to this, I'm adding the support to xgettext, msgfmt,
msgunfmt also.

The patch does the following:
- It splits the revision into a major and minor revision. The distinction is
  that the library rejects MO files with a major revision that it doesn't
  understand, whereas it processes files with a different minor revision.
- A new minor revision is introduced, which contains a separate section of
  system dependent strings. The values of these strings are determined
  (through simple string concatenation - nothing security relevant) and
  entered into the hash table during _nl_load_domain. A maximum of the
  .mo file is kept in read-only memory, as in the past. Only the new
  new system dependent strings and the modified hash table are allocated
  in malloced memory.
- The older minor revision is still recognized and processed with the same
  efficiency. In fact, the vast majority of .mo files will continue to
  belong to this older minor revision.
- The only publicly visible interface change is a new macro
  __GNU_GETTEXT_SUPPORTED_REVISION in libintl.h which will be used by
  the gettext.m4 autoconf macro to detect the libintl versions supporting
  PRId64 (and works whether cross-compiling or not).


2002-07-21  Bruno Haible  <bruno@clisp.org>

	* intl/libintl.h (__GNU_GETTEXT_SUPPORTED_REVISION): New macro.
	* intl/gettext.h (struct mo_file_header): New fields n_sysdep_segments,
	sysdep_segments_offset, n_sysdep_strings, orig_sysdep_tab_offset,
	trans_sysdep_tab_offset.
	(struct sysdep_segment): New type.
	(struct sysdep_string): New type.
	(SEGMENTS_END): New macro.
	* intl/gettextP.h (struct sysdep_string_desc): New type.
	(struct loaded_domain): New fields malloced, n_sysdep_strings,
	orig_sysdep_tab, trans_sysdep_tab, must_swap_hash_tab. Make fields
	orig_tab, trans_tab, hash_tab to const pointers because they point
	into read-only memory.
	* intl/loadmsgcat.c: Include stdint.h, inttypes.h, hash-string.h.
	(PRI*): Define fallback values.
	(get_sysdep_segment_value): New function.
	(_nl_load_domain): Distinguish major and minor revision parts. Add
	support for minor revision 1 with system dependent strings.
	(_nl_unload_domain): Also free the 'malloced' field.
	* intl/dcigettext.c (_nl_find_msg): Remove test for domain->hash_size,
	now done in loadmsgcat.c. Add support for system dependent strings.

--- glibc-20020627/intl/dcigettext.c.bak	2002-04-04 20:11:22.000000000 +0200
+++ glibc-20020627/intl/dcigettext.c	2002-07-21 16:38:23.000000000 +0200
@@ -636,6 +636,7 @@
      size_t *lengthp;
 {
   struct loaded_domain *domain;
+  nls_uint32 nstrings;
   size_t act;
   char *result;
   size_t resultlen;
@@ -648,8 +649,10 @@
 
   domain = (struct loaded_domain *) domain_file->data;
 
+  nstrings = domain->nstrings;
+
   /* Locate the MSGID and its translation.  */
-  if (domain->hash_size > 2 && domain->hash_tab != NULL)
+  if (domain->hash_tab != NULL)
     {
       /* Use the hashing table.  */
       nls_uint32 len = strlen (msgid);
@@ -659,22 +662,30 @@
 
       while (1)
 	{
-	  nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
+	  nls_uint32 nstr =
+	    W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
 
 	  if (nstr == 0)
 	    /* Hash table entry is empty.  */
 	    return NULL;
 
-	  /* Compare msgid with the original string at index nstr-1.
+	  nstr--;
+
+	  /* Compare msgid with the original string at index nstr.
 	     We compare the lengths with >=, not ==, because plural entries
 	     are represented by strings with an embedded NUL.  */
-	  if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
-	      && (strcmp (msgid,
-			  domain->data + W (domain->must_swap,
-					    domain->orig_tab[nstr - 1].offset))
-		  == 0))
+	  if (nstr < nstrings
+	      ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
+		&& (strcmp (msgid,
+			    domain->data + W (domain->must_swap,
+					      domain->orig_tab[nstr].offset))
+		    == 0)
+	      : domain->orig_sysdep_tab[nstr - nstrings].length > len
+		&& (strcmp (msgid,
+			    domain->orig_sysdep_tab[nstr - nstrings].pointer)
+		    == 0))
 	    {
-	      act = nstr - 1;
+	      act = nstr;
 	      goto found;
 	    }
 
@@ -692,7 +703,7 @@
       size_t top, bottom;
 
       bottom = 0;
-      top = domain->nstrings;
+      top = nstrings;
       while (bottom < top)
 	{
 	  int cmp_val;
@@ -715,9 +726,17 @@
  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));
-  resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
+  if (act < nstrings)
+    {
+      result = (char *)
+	(domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
+      resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
+    }
+  else
+    {
+      result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
+      resultlen = domain->trans_sysdep_tab[act - nstrings].length;
+    }
 
 #if defined _LIBC || HAVE_ICONV
   if (domain->codeset_cntr
@@ -750,8 +769,9 @@
 	 NULs.  */
 
       if (domain->conv_tab == NULL
-	  && ((domain->conv_tab = (char **) calloc (domain->nstrings,
-						    sizeof (char *)))
+	  && ((domain->conv_tab =
+		 (char **) calloc (nstrings + domain->n_sysdep_strings,
+				   sizeof (char *)))
 	      == NULL))
 	/* Mark that we didn't succeed allocating a table.  */
 	domain->conv_tab = (char **) -1;
--- glibc-20020627/intl/gettextP.h.bak	2001-11-28 14:46:39.000000000 +0100
+++ glibc-20020627/intl/gettextP.h	2002-07-21 16:38:23.000000000 +0200
@@ -75,18 +75,50 @@
 #endif
 
 
+/* In-memory representation of system dependent string.  */
+struct sysdep_string_desc
+{
+  /* Length of addressed string, including the trailing NUL.  */
+  size_t length;
+  /* Pointer to addressed string.  */
+  const char *pointer;
+};
+
 /* The representation of an opened message catalog.  */
 struct loaded_domain
 {
+  /* Pointer to memory containing the .mo file.  */
   const char *data;
+  /* 1 if the memory is mmap()ed, 0 if the memory is malloc()ed.  */
   int use_mmap;
+  /* Size of mmap()ed memory.  */
   size_t mmap_size;
+  /* 1 if the .mo file uses a different endianness than this machine.  */
   int must_swap;
+  /* Pointer to additional malloc()ed memory.  */
+  void *malloced;
+
+  /* Number of static strings pairs.  */
   nls_uint32 nstrings;
-  struct string_desc *orig_tab;
-  struct string_desc *trans_tab;
+  /* Pointer to descriptors of original strings in the file.  */
+  const struct string_desc *orig_tab;
+  /* Pointer to descriptors of translated strings in the file.  */
+  const struct string_desc *trans_tab;
+
+  /* Number of system dependent strings pairs.  */
+  nls_uint32 n_sysdep_strings;
+  /* Pointer to descriptors of original sysdep strings.  */
+  const struct sysdep_string_desc *orig_sysdep_tab;
+  /* Pointer to descriptors of translated sysdep strings.  */
+  const struct sysdep_string_desc *trans_sysdep_tab;
+
+  /* Size of hash table.  */
   nls_uint32 hash_size;
-  nls_uint32 *hash_tab;
+  /* Pointer to hash table.  */
+  const nls_uint32 *hash_tab;
+  /* 1 if the hash table uses a different endianness than this machine.  */
+  int must_swap_hash_tab;
+
   int codeset_cntr;
 #ifdef _LIBC
   __gconv_t conv;
--- glibc-20020627/intl/gettext.h.bak	2001-11-28 14:46:39.000000000 +0100
+++ glibc-20020627/intl/gettext.h	2002-07-21 16:40:31.000000000 +0200
@@ -1,5 +1,5 @@
 /* Internal header for GNU gettext internationalization functions.
-   Copyright (C) 1995, 1997, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1997, 2000-2002 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
@@ -76,26 +76,74 @@
   nls_uint32 magic;
   /* The revision number of the file format.  */
   nls_uint32 revision;
+
+  /* The following are only used in .mo files with major revision 0.  */
+
   /* The number of strings pairs.  */
   nls_uint32 nstrings;
   /* Offset of table with start offsets of original strings.  */
   nls_uint32 orig_tab_offset;
-  /* Offset of table with start offsets of translation strings.  */
+  /* Offset of table with start offsets of translated strings.  */
   nls_uint32 trans_tab_offset;
-  /* Size of hashing table.  */
+  /* Size of hash table.  */
   nls_uint32 hash_tab_size;
-  /* Offset of first hashing entry.  */
+  /* Offset of first hash table entry.  */
   nls_uint32 hash_tab_offset;
+
+  /* The following are only used in .mo files with minor revision >= 1.  */
+
+  /* The number of system dependent segments.  */
+  nls_uint32 n_sysdep_segments;
+  /* Offset of table describing system dependent segments.  */
+  nls_uint32 sysdep_segments_offset;
+  /* The number of system dependent strings pairs.  */
+  nls_uint32 n_sysdep_strings;
+  /* Offset of table with start offsets of original sysdep strings.  */
+  nls_uint32 orig_sysdep_tab_offset;
+  /* Offset of table with start offsets of translated sysdep strings.  */
+  nls_uint32 trans_sysdep_tab_offset;
 };
 
+/* Descriptor for static string contained in the binary .mo file.  */
 struct string_desc
 {
-  /* Length of addressed string.  */
+  /* Length of addressed string, not including the trailing NUL.  */
+  nls_uint32 length;
+  /* Offset of string in file.  */
+  nls_uint32 offset;
+};
+
+/* The following are only used in .mo files with minor revision >= 1.  */
+
+/* Descriptor for system dependent string segment.  */
+struct sysdep_segment
+{
+  /* Length of addressed string, including the trailing NUL.  */
   nls_uint32 length;
   /* Offset of string in file.  */
   nls_uint32 offset;
 };
 
+/* Descriptor for system dependent string.  */
+struct sysdep_string
+{
+  /* Offset of static string segments in file.  */
+  nls_uint32 offset;
+  /* Alternating sequence of static and system dependent segments.
+     The last segment is a static segment, including the trailing NUL.  */
+  struct segment_pair
+  {
+    /* Size of static segment.  */
+    nls_uint32 segsize;
+    /* Reference to system dependent string segment, or ~0 at the end.  */
+    nls_uint32 sysdepref;
+  } segments[1];
+};
+
+/* Marker for the end of the segments[] array.  This has the value 0xFFFFFFFF,
+   regardless whether 'int' is 16 bit, 32 bit, or 64 bit.  */
+#define SEGMENTS_END ((nls_uint32) ~0)
+
 /* @@ begin of epilog @@ */
 
 #endif	/* gettext.h  */
--- glibc-20020627/intl/libintl.h.bak	2001-07-27 18:47:16.000000000 +0200
+++ glibc-20020627/intl/libintl.h	2002-07-21 16:42:02.000000000 +0200
@@ -1,5 +1,5 @@
 /* Message catalogs for internationalization.
-   Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1995-1999, 2000-2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    This file is derived from the file libgettext.h in the GNU gettext package.
 
@@ -27,6 +27,11 @@
    implementation of gettext.  */
 #define __USE_GNU_GETTEXT 1
 
+/* Provide information about the supported file formats.  Returns the
+   maximum minor revision number supported for a given major revision.  */
+#define __GNU_GETTEXT_SUPPORTED_REVISION(major) \
+  ((major) == 0 ? 1 : -1)
+
 __BEGIN_DECLS
 
 /* Look up MSGID in the current default message catalog for the current
--- glibc-20020627/intl/loadmsgcat.c.bak	2002-05-04 00:00:00.000000000 +0200
+++ glibc-20020627/intl/loadmsgcat.c	2002-07-21 16:44:39.000000000 +0200
@@ -72,14 +72,296 @@
 # undef HAVE_MMAP
 #endif
 
+#if defined HAVE_STDINT_H_WITH_UINTMAX || defined _LIBC
+# include <stdint.h>
+#endif
+#if defined HAVE_INTTYPES_H || defined _LIBC
+# include <inttypes.h>
+#endif
+
 #include "gettext.h"
 #include "gettextP.h"
+#include "hash-string.h"
 #include "plural-exp.h"
 
 #ifdef _LIBC
 # include "../locale/localeinfo.h"
 #endif
 
+/* Provide fallback values for macros that ought to be defined in <inttypes.h>.
+   Note that our fallback values need not be literal strings, because we don't
+   use them with preprocessor string concatenation.  */
+#ifndef PRId8
+# define PRId8 "d"
+#endif
+#ifndef PRIi8
+# define PRIi8 "i"
+#endif
+#ifndef PRIo8
+# define PRIo8 "o"
+#endif
+#ifndef PRIu8
+# define PRIu8 "u"
+#endif
+#ifndef PRIx8
+# define PRIx8 "x"
+#endif
+#ifndef PRIX8
+# define PRIX8 "X"
+#endif
+#ifndef PRId16
+# define PRId16 "d"
+#endif
+#ifndef PRIi16
+# define PRIi16 "i"
+#endif
+#ifndef PRIo16
+# define PRIo16 "o"
+#endif
+#ifndef PRIu16
+# define PRIu16 "u"
+#endif
+#ifndef PRIx16
+# define PRIx16 "x"
+#endif
+#ifndef PRIX16
+# define PRIX16 "X"
+#endif
+#ifndef PRId32
+# define PRId32 "d"
+#endif
+#ifndef PRIi32
+# define PRIi32 "i"
+#endif
+#ifndef PRIo32
+# define PRIo32 "o"
+#endif
+#ifndef PRIu32
+# define PRIu32 "u"
+#endif
+#ifndef PRIx32
+# define PRIx32 "x"
+#endif
+#ifndef PRIX32
+# define PRIX32 "X"
+#endif
+#ifndef PRId64
+# define PRId64 (sizeof (long) == 8 ? "ld" : "lld")
+#endif
+#ifndef PRIi64
+# define PRIi64 (sizeof (long) == 8 ? "li" : "lli")
+#endif
+#ifndef PRIo64
+# define PRIo64 (sizeof (long) == 8 ? "lo" : "llo")
+#endif
+#ifndef PRIu64
+# define PRIu64 (sizeof (long) == 8 ? "lu" : "llu")
+#endif
+#ifndef PRIx64
+# define PRIx64 (sizeof (long) == 8 ? "lx" : "llx")
+#endif
+#ifndef PRIX64
+# define PRIX64 (sizeof (long) == 8 ? "lX" : "llX")
+#endif
+#ifndef PRIdLEAST8
+# define PRIdLEAST8 "d"
+#endif
+#ifndef PRIiLEAST8
+# define PRIiLEAST8 "i"
+#endif
+#ifndef PRIoLEAST8
+# define PRIoLEAST8 "o"
+#endif
+#ifndef PRIuLEAST8
+# define PRIuLEAST8 "u"
+#endif
+#ifndef PRIxLEAST8
+# define PRIxLEAST8 "x"
+#endif
+#ifndef PRIXLEAST8
+# define PRIXLEAST8 "X"
+#endif
+#ifndef PRIdLEAST16
+# define PRIdLEAST16 "d"
+#endif
+#ifndef PRIiLEAST16
+# define PRIiLEAST16 "i"
+#endif
+#ifndef PRIoLEAST16
+# define PRIoLEAST16 "o"
+#endif
+#ifndef PRIuLEAST16
+# define PRIuLEAST16 "u"
+#endif
+#ifndef PRIxLEAST16
+# define PRIxLEAST16 "x"
+#endif
+#ifndef PRIXLEAST16
+# define PRIXLEAST16 "X"
+#endif
+#ifndef PRIdLEAST32
+# define PRIdLEAST32 "d"
+#endif
+#ifndef PRIiLEAST32
+# define PRIiLEAST32 "i"
+#endif
+#ifndef PRIoLEAST32
+# define PRIoLEAST32 "o"
+#endif
+#ifndef PRIuLEAST32
+# define PRIuLEAST32 "u"
+#endif
+#ifndef PRIxLEAST32
+# define PRIxLEAST32 "x"
+#endif
+#ifndef PRIXLEAST32
+# define PRIXLEAST32 "X"
+#endif
+#ifndef PRIdLEAST64
+# define PRIdLEAST64 PRId64
+#endif
+#ifndef PRIiLEAST64
+# define PRIiLEAST64 PRIi64
+#endif
+#ifndef PRIoLEAST64
+# define PRIoLEAST64 PRIo64
+#endif
+#ifndef PRIuLEAST64
+# define PRIuLEAST64 PRIu64
+#endif
+#ifndef PRIxLEAST64
+# define PRIxLEAST64 PRIx64
+#endif
+#ifndef PRIXLEAST64
+# define PRIXLEAST64 PRIX64
+#endif
+#ifndef PRIdFAST8
+# define PRIdFAST8 "d"
+#endif
+#ifndef PRIiFAST8
+# define PRIiFAST8 "i"
+#endif
+#ifndef PRIoFAST8
+# define PRIoFAST8 "o"
+#endif
+#ifndef PRIuFAST8
+# define PRIuFAST8 "u"
+#endif
+#ifndef PRIxFAST8
+# define PRIxFAST8 "x"
+#endif
+#ifndef PRIXFAST8
+# define PRIXFAST8 "X"
+#endif
+#ifndef PRIdFAST16
+# define PRIdFAST16 "d"
+#endif
+#ifndef PRIiFAST16
+# define PRIiFAST16 "i"
+#endif
+#ifndef PRIoFAST16
+# define PRIoFAST16 "o"
+#endif
+#ifndef PRIuFAST16
+# define PRIuFAST16 "u"
+#endif
+#ifndef PRIxFAST16
+# define PRIxFAST16 "x"
+#endif
+#ifndef PRIXFAST16
+# define PRIXFAST16 "X"
+#endif
+#ifndef PRIdFAST32
+# define PRIdFAST32 "d"
+#endif
+#ifndef PRIiFAST32
+# define PRIiFAST32 "i"
+#endif
+#ifndef PRIoFAST32
+# define PRIoFAST32 "o"
+#endif
+#ifndef PRIuFAST32
+# define PRIuFAST32 "u"
+#endif
+#ifndef PRIxFAST32
+# define PRIxFAST32 "x"
+#endif
+#ifndef PRIXFAST32
+# define PRIXFAST32 "X"
+#endif
+#ifndef PRIdFAST64
+# define PRIdFAST64 PRId64
+#endif
+#ifndef PRIiFAST64
+# define PRIiFAST64 PRIi64
+#endif
+#ifndef PRIoFAST64
+# define PRIoFAST64 PRIo64
+#endif
+#ifndef PRIuFAST64
+# define PRIuFAST64 PRIu64
+#endif
+#ifndef PRIxFAST64
+# define PRIxFAST64 PRIx64
+#endif
+#ifndef PRIXFAST64
+# define PRIXFAST64 PRIX64
+#endif
+#ifndef PRIdMAX
+# define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld")
+#endif
+#ifndef PRIiMAX
+# define PRIiMAX (sizeof (uintmax_t) == sizeof (long) ? "li" : "lli")
+#endif
+#ifndef PRIoMAX
+# define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo")
+#endif
+#ifndef PRIuMAX
+# define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu")
+#endif
+#ifndef PRIxMAX
+# define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx")
+#endif
+#ifndef PRIXMAX
+# define PRIXMAX (sizeof (uintmax_t) == sizeof (long) ? "lX" : "llX")
+#endif
+#ifndef PRIdPTR
+# define PRIdPTR \
+  (sizeof (void *) == sizeof (long) ? "ld" : \
+   sizeof (void *) == sizeof (int) ? "d" : \
+   "lld")
+#endif
+#ifndef PRIiPTR
+# define PRIiPTR \
+  (sizeof (void *) == sizeof (long) ? "li" : \
+   sizeof (void *) == sizeof (int) ? "i" : \
+   "lli")
+#endif
+#ifndef PRIoPTR
+# define PRIoPTR \
+  (sizeof (void *) == sizeof (long) ? "lo" : \
+   sizeof (void *) == sizeof (int) ? "o" : \
+   "llo")
+#endif
+#ifndef PRIuPTR
+# define PRIuPTR \
+  (sizeof (void *) == sizeof (long) ? "lu" : \
+   sizeof (void *) == sizeof (int) ? "u" : \
+   "llu")
+#endif
+#ifndef PRIxPTR
+# define PRIxPTR \
+  (sizeof (void *) == sizeof (long) ? "lx" : \
+   sizeof (void *) == sizeof (int) ? "x" : \
+   "llx")
+#endif
+#ifndef PRIXPTR
+# define PRIXPTR \
+  (sizeof (void *) == sizeof (long) ? "lX" : \
+   sizeof (void *) == sizeof (int) ? "X" : \
+   "llX")
+#endif
+
 /* @@ end of prolog @@ */
 
 #ifdef _LIBC
@@ -102,12 +384,274 @@
 # define freea(p) free (p)
 #endif
 
+
+/* Prototypes for local functions.  Needed to ensure compiler checking of
+   function argument counts despite of K&R C function definition syntax.  */
+static const char *get_sysdep_segment_value PARAMS ((const char *name));
+
+
 /* We need a sign, whether a new catalog was loaded, which can be associated
    with all translations.  This is important if the translations are
    cached by one of GCC's features.  */
 int _nl_msg_cat_cntr;
 
 
+/* Expand a system dependent string segment.  Return NULL if unsupported.  */
+static const char *
+get_sysdep_segment_value (name)
+     const char *name;
+{
+  /* Test for an ISO C 99 section 7.8.1 format string directive.
+     Syntax:
+     P R I { d | i | o | u | x | X }
+     { { | LEAST | FAST } { 8 | 16 | 32 | 64 } | MAX | PTR }  */
+  /* We don't use a table of 14 times 6 'const char *' strings here, because
+     data relocations cost startup time.  */
+  if (name[0] == 'P' && name[1] == 'R' && name[2] == 'I')
+    {
+      if (name[3] == 'd' || name[3] == 'i' || name[3] == 'o' || name[3] == 'u'
+	  || name[3] == 'x' || name[3] == 'X')
+	{
+	  if (name[4] == '8' && name[5] == '\0')
+	    {
+	      if (name[3] == 'd')
+		return PRId8;
+	      if (name[3] == 'i')
+		return PRIi8;
+	      if (name[3] == 'o')
+		return PRIo8;
+	      if (name[3] == 'u')
+		return PRIu8;
+	      if (name[3] == 'x')
+		return PRIx8;
+	      if (name[3] == 'X')
+		return PRIX8;
+	      abort ();
+	    }
+	  if (name[4] == '1' && name[5] == '6' && name[6] == '\0')
+	    {
+	      if (name[3] == 'd')
+		return PRId16;
+	      if (name[3] == 'i')
+		return PRIi16;
+	      if (name[3] == 'o')
+		return PRIo16;
+	      if (name[3] == 'u')
+		return PRIu16;
+	      if (name[3] == 'x')
+		return PRIx16;
+	      if (name[3] == 'X')
+		return PRIX16;
+	      abort ();
+	    }
+	  if (name[4] == '3' && name[5] == '2' && name[6] == '\0')
+	    {
+	      if (name[3] == 'd')
+		return PRId32;
+	      if (name[3] == 'i')
+		return PRIi32;
+	      if (name[3] == 'o')
+		return PRIo32;
+	      if (name[3] == 'u')
+		return PRIu32;
+	      if (name[3] == 'x')
+		return PRIx32;
+	      if (name[3] == 'X')
+		return PRIX32;
+	      abort ();
+	    }
+	  if (name[4] == '6' && name[5] == '4' && name[6] == '\0')
+	    {
+	      if (name[3] == 'd')
+		return PRId64;
+	      if (name[3] == 'i')
+		return PRIi64;
+	      if (name[3] == 'o')
+		return PRIo64;
+	      if (name[3] == 'u')
+		return PRIu64;
+	      if (name[3] == 'x')
+		return PRIx64;
+	      if (name[3] == 'X')
+		return PRIX64;
+	      abort ();
+	    }
+	  if (name[4] == 'L' && name[5] == 'E' && name[6] == 'A'
+	      && name[7] == 'S' && name[8] == 'T')
+	    {
+	      if (name[9] == '8' && name[10] == '\0')
+		{
+		  if (name[3] == 'd')
+		    return PRIdLEAST8;
+		  if (name[3] == 'i')
+		    return PRIiLEAST8;
+		  if (name[3] == 'o')
+		    return PRIoLEAST8;
+		  if (name[3] == 'u')
+		    return PRIuLEAST8;
+		  if (name[3] == 'x')
+		    return PRIxLEAST8;
+		  if (name[3] == 'X')
+		    return PRIXLEAST8;
+		  abort ();
+		}
+	      if (name[9] == '1' && name[10] == '6' && name[11] == '\0')
+		{
+		  if (name[3] == 'd')
+		    return PRIdLEAST16;
+		  if (name[3] == 'i')
+		    return PRIiLEAST16;
+		  if (name[3] == 'o')
+		    return PRIoLEAST16;
+		  if (name[3] == 'u')
+		    return PRIuLEAST16;
+		  if (name[3] == 'x')
+		    return PRIxLEAST16;
+		  if (name[3] == 'X')
+		    return PRIXLEAST16;
+		  abort ();
+		}
+	      if (name[9] == '3' && name[10] == '2' && name[11] == '\0')
+		{
+		  if (name[3] == 'd')
+		    return PRIdLEAST32;
+		  if (name[3] == 'i')
+		    return PRIiLEAST32;
+		  if (name[3] == 'o')
+		    return PRIoLEAST32;
+		  if (name[3] == 'u')
+		    return PRIuLEAST32;
+		  if (name[3] == 'x')
+		    return PRIxLEAST32;
+		  if (name[3] == 'X')
+		    return PRIXLEAST32;
+		  abort ();
+		}
+	      if (name[9] == '6' && name[10] == '4' && name[11] == '\0')
+		{
+		  if (name[3] == 'd')
+		    return PRIdLEAST64;
+		  if (name[3] == 'i')
+		    return PRIiLEAST64;
+		  if (name[3] == 'o')
+		    return PRIoLEAST64;
+		  if (name[3] == 'u')
+		    return PRIuLEAST64;
+		  if (name[3] == 'x')
+		    return PRIxLEAST64;
+		  if (name[3] == 'X')
+		    return PRIXLEAST64;
+		  abort ();
+		}
+	    }
+	  if (name[4] == 'F' && name[5] == 'A' && name[6] == 'S'
+	      && name[7] == 'T')
+	    {
+	      if (name[8] == '8' && name[9] == '\0')
+		{
+		  if (name[3] == 'd')
+		    return PRIdFAST8;
+		  if (name[3] == 'i')
+		    return PRIiFAST8;
+		  if (name[3] == 'o')
+		    return PRIoFAST8;
+		  if (name[3] == 'u')
+		    return PRIuFAST8;
+		  if (name[3] == 'x')
+		    return PRIxFAST8;
+		  if (name[3] == 'X')
+		    return PRIXFAST8;
+		  abort ();
+		}
+	      if (name[8] == '1' && name[9] == '6' && name[10] == '\0')
+		{
+		  if (name[3] == 'd')
+		    return PRIdFAST16;
+		  if (name[3] == 'i')
+		    return PRIiFAST16;
+		  if (name[3] == 'o')
+		    return PRIoFAST16;
+		  if (name[3] == 'u')
+		    return PRIuFAST16;
+		  if (name[3] == 'x')
+		    return PRIxFAST16;
+		  if (name[3] == 'X')
+		    return PRIXFAST16;
+		  abort ();
+		}
+	      if (name[8] == '3' && name[9] == '2' && name[10] == '\0')
+		{
+		  if (name[3] == 'd')
+		    return PRIdFAST32;
+		  if (name[3] == 'i')
+		    return PRIiFAST32;
+		  if (name[3] == 'o')
+		    return PRIoFAST32;
+		  if (name[3] == 'u')
+		    return PRIuFAST32;
+		  if (name[3] == 'x')
+		    return PRIxFAST32;
+		  if (name[3] == 'X')
+		    return PRIXFAST32;
+		  abort ();
+		}
+	      if (name[8] == '6' && name[9] == '4' && name[10] == '\0')
+		{
+		  if (name[3] == 'd')
+		    return PRIdFAST64;
+		  if (name[3] == 'i')
+		    return PRIiFAST64;
+		  if (name[3] == 'o')
+		    return PRIoFAST64;
+		  if (name[3] == 'u')
+		    return PRIuFAST64;
+		  if (name[3] == 'x')
+		    return PRIxFAST64;
+		  if (name[3] == 'X')
+		    return PRIXFAST64;
+		  abort ();
+		}
+	    }
+	  if (name[4] == 'M' && name[5] == 'A' && name[6] == 'X'
+	      && name[7] == '\0')
+	    {
+	      if (name[3] == 'd')
+		return PRIdMAX;
+	      if (name[3] == 'i')
+		return PRIiMAX;
+	      if (name[3] == 'o')
+		return PRIoMAX;
+	      if (name[3] == 'u')
+		return PRIuMAX;
+	      if (name[3] == 'x')
+		return PRIxMAX;
+	      if (name[3] == 'X')
+		return PRIXMAX;
+	      abort ();
+	    }
+	  if (name[4] == 'P' && name[5] == 'T' && name[6] == 'R'
+	      && name[7] == '\0')
+	    {
+	      if (name[3] == 'd')
+		return PRIdPTR;
+	      if (name[3] == 'i')
+		return PRIiPTR;
+	      if (name[3] == 'o')
+		return PRIoPTR;
+	      if (name[3] == 'u')
+		return PRIuPTR;
+	      if (name[3] == 'x')
+		return PRIxPTR;
+	      if (name[3] == 'X')
+		return PRIXPTR;
+	      abort ();
+	    }
+	}
+    }
+  /* Other system dependent strings are not valid.  */
+  return NULL;
+}
+
 /* Initialize the codeset dependent parts of an opened message catalog.
    Return the header entry.  */
 const char *
@@ -263,6 +807,7 @@
   struct mo_file_header *data = (struct mo_file_header *) -1;
   int use_mmap = 0;
   struct loaded_domain *domain;
+  int revision;
   const char *nullentry;
 
   domain_file->decided = 1;
@@ -370,22 +915,257 @@
   domain->use_mmap = use_mmap;
   domain->mmap_size = size;
   domain->must_swap = data->magic != _MAGIC;
+  domain->malloced = NULL;
 
   /* Fill in the information about the available tables.  */
-  switch (W (domain->must_swap, data->revision))
+  revision = W (domain->must_swap, data->revision);
+  /* We support only the major revision 0.  */
+  switch (revision >> 16)
     {
     case 0:
       domain->nstrings = W (domain->must_swap, data->nstrings);
-      domain->orig_tab = (struct string_desc *)
+      domain->orig_tab = (const struct string_desc *)
 	((char *) data + W (domain->must_swap, data->orig_tab_offset));
-      domain->trans_tab = (struct string_desc *)
+      domain->trans_tab = (const struct string_desc *)
 	((char *) data + W (domain->must_swap, data->trans_tab_offset));
       domain->hash_size = W (domain->must_swap, data->hash_tab_size);
-      domain->hash_tab = (nls_uint32 *)
-	((char *) data + W (domain->must_swap, data->hash_tab_offset));
+      domain->hash_tab =
+	(domain->hash_size > 2
+	 ? (const nls_uint32 *)
+	   ((char *) data + W (domain->must_swap, data->hash_tab_offset))
+	 : NULL);
+      domain->must_swap_hash_tab = domain->must_swap;
+
+      /* Now dispatch on the minor revision.  */
+      switch (revision & 0xffff)
+	{
+	case 0:
+	  domain->n_sysdep_strings = 0;
+	  domain->orig_sysdep_tab = NULL;
+	  domain->trans_sysdep_tab = NULL;
+	  break;
+	case 1:
+	default:
+	  {
+	    nls_uint32 n_sysdep_strings;
+
+	    if (domain->hash_tab == NULL)
+	      /* This is invalid.  These minor revisions need a hash table.  */
+	      goto invalid;
+
+	    n_sysdep_strings =
+	      W (domain->must_swap, data->n_sysdep_strings);
+	    if (n_sysdep_strings > 0)
+	      {
+		nls_uint32 n_sysdep_segments;
+		const struct sysdep_segment *sysdep_segments;
+		const char **sysdep_segment_values;
+		const nls_uint32 *orig_sysdep_tab;
+		const nls_uint32 *trans_sysdep_tab;
+		size_t memneed;
+		char *mem;
+		struct sysdep_string_desc *inmem_orig_sysdep_tab;
+		struct sysdep_string_desc *inmem_trans_sysdep_tab;
+		nls_uint32 *inmem_hash_tab;
+		unsigned int i;
+
+		/* Get the values of the system dependent segments.  */
+		n_sysdep_segments =
+		  W (domain->must_swap, data->n_sysdep_segments);
+		sysdep_segments = (const struct sysdep_segment *)
+		  ((char *) data
+		   + W (domain->must_swap, data->sysdep_segments_offset));
+		sysdep_segment_values =
+		  alloca (n_sysdep_segments * sizeof (const char *));
+		for (i = 0; i < n_sysdep_segments; i++)
+		  {
+		    const char *name =
+		      (char *) data
+		      + W (domain->must_swap, sysdep_segments[i].offset);
+		    nls_uint32 namelen =
+		      W (domain->must_swap, sysdep_segments[i].length);
+
+		    if (!(namelen > 0 && name[namelen - 1] == '\0'))
+		      {
+			freea (sysdep_segment_values);
+			goto invalid;
+		      }
+
+		    sysdep_segment_values[i] = get_sysdep_segment_value (name);
+		  }
+
+		orig_sysdep_tab = (const nls_uint32 *)
+		  ((char *) data
+		   + W (domain->must_swap, data->orig_sysdep_tab_offset));
+		trans_sysdep_tab = (const nls_uint32 *)
+		  ((char *) data
+		   + W (domain->must_swap, data->trans_sysdep_tab_offset));
+
+		/* Compute the amount of additional memory needed for the
+		   system dependent strings and the augmented hash table.  */
+		memneed = 2 * n_sysdep_strings
+			  * sizeof (struct sysdep_string_desc)
+			  + domain->hash_size * sizeof (nls_uint32);
+		for (i = 0; i < 2 * n_sysdep_strings; i++)
+		  {
+		    const struct sysdep_string *sysdep_string =
+		      (const struct sysdep_string *)
+		      ((char *) data
+		       + W (domain->must_swap,
+			    i < n_sysdep_strings
+			    ? orig_sysdep_tab[i]
+			    : trans_sysdep_tab[i - n_sysdep_strings]));
+		    size_t need = 0;
+		    const struct segment_pair *p = sysdep_string->segments;
+
+		    if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END)
+		      for (p = sysdep_string->segments;; p++)
+			{
+			  nls_uint32 sysdepref;
+
+			  need += W (domain->must_swap, p->segsize);
+
+			  sysdepref = W (domain->must_swap, p->sysdepref);
+			  if (sysdepref == SEGMENTS_END)
+			    break;
+
+			  if (sysdepref >= n_sysdep_segments)
+			    {
+			      /* Invalid.  */
+			      freea (sysdep_segment_values);
+			      goto invalid;
+			    }
+
+			  need += strlen (sysdep_segment_values[sysdepref]);
+			}
+
+		    memneed += need;
+		  }
+
+		/* Allocate additional memory.  */
+		mem = (char *) malloc (memneed);
+		if (mem == NULL)
+		  goto invalid;
+
+		domain->malloced = mem;
+		inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem;
+		mem += n_sysdep_strings * sizeof (struct sysdep_string_desc);
+		inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem;
+		mem += n_sysdep_strings * sizeof (struct sysdep_string_desc);
+		inmem_hash_tab = (nls_uint32 *) mem;
+		mem += domain->hash_size * sizeof (nls_uint32);
+
+		/* Compute the system dependent strings.  */
+		for (i = 0; i < 2 * n_sysdep_strings; i++)
+		  {
+		    const struct sysdep_string *sysdep_string =
+		      (const struct sysdep_string *)
+		      ((char *) data
+		       + W (domain->must_swap,
+			    i < n_sysdep_strings
+			    ? orig_sysdep_tab[i]
+			    : trans_sysdep_tab[i - n_sysdep_strings]));
+		    const char *static_segments =
+		      (char *) data
+		      + W (domain->must_swap, sysdep_string->offset);
+		    const struct segment_pair *p = sysdep_string->segments;
+
+		    /* Concatenate the segments, and fill
+		       inmem_orig_sysdep_tab[i] (for i < n_sysdep_strings) and
+		       inmem_trans_sysdep_tab[i-n_sysdep_strings] (for
+		       i >= n_sysdep_strings).  */
+
+		    if (W (domain->must_swap, p->sysdepref) == SEGMENTS_END)
+		      {
+			/* Only one static segment.  */
+			inmem_orig_sysdep_tab[i].length =
+			  W (domain->must_swap, p->segsize);
+			inmem_orig_sysdep_tab[i].pointer = static_segments;
+		      }
+		    else
+		      {
+			inmem_orig_sysdep_tab[i].pointer = mem;
+
+			for (p = sysdep_string->segments;; p++)
+			  {
+			    nls_uint32 segsize =
+			      W (domain->must_swap, p->segsize);
+			    nls_uint32 sysdepref =
+			      W (domain->must_swap, p->sysdepref);
+			    size_t n;
+
+			    if (segsize > 0)
+			      {
+				memcpy (mem, static_segments, segsize);
+				mem += segsize;
+				static_segments += segsize;
+			      }
+
+			    if (sysdepref == SEGMENTS_END)
+			      break;
+
+			    n = strlen (sysdep_segment_values[sysdepref]);
+			    memcpy (mem, sysdep_segment_values[sysdepref], n);
+			    mem += n;
+			  }
+
+			inmem_orig_sysdep_tab[i].length =
+			  mem - inmem_orig_sysdep_tab[i].pointer;
+		      }
+		  }
+
+		/* Compute the augmented hash table.  */
+		for (i = 0; i < domain->hash_size; i++)
+		  inmem_hash_tab[i] =
+		    W (domain->must_swap_hash_tab, domain->hash_tab[i]);
+		for (i = 0; i < n_sysdep_strings; i++)
+		  {
+		    const char *msgid = inmem_orig_sysdep_tab[i].pointer;
+		    nls_uint32 hash_val = hash_string (msgid);
+		    nls_uint32 idx = hash_val % domain->hash_size;
+		    nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
+
+		    for (;;)
+		      {
+			if (inmem_hash_tab[idx] == 0)
+			  {
+			    /* Hash table entry is empty.  Use it.  */
+			    inmem_hash_tab[idx] = 1 + domain->nstrings + i;
+			    break;
+			  }
+
+			if (idx >= domain->hash_size - incr)
+			  idx -= domain->hash_size - incr;
+			else
+			  idx += incr;
+		      }
+		  }
+
+		freea (sysdep_segment_values);
+
+		domain->n_sysdep_strings = n_sysdep_strings;
+		domain->orig_sysdep_tab = inmem_orig_sysdep_tab;
+		domain->trans_sysdep_tab = inmem_trans_sysdep_tab;
+
+		domain->hash_tab = inmem_hash_tab;
+		domain->must_swap_hash_tab = 0;
+	      }
+	    else
+	      {
+		domain->n_sysdep_strings = 0;
+		domain->orig_sysdep_tab = NULL;
+		domain->trans_sysdep_tab = NULL;
+	      }
+	  }
+	  break;
+	}
       break;
     default:
       /* This is an invalid revision.  */
+    invalid:
+      /* This is an invalid .mo file.  */
+      if (domain->malloced)
+	free (domain->malloced);
 #ifdef HAVE_MMAP
       if (use_mmap)
 	munmap ((caddr_t) data, size);
@@ -418,6 +1198,9 @@
 
   _nl_free_domain_conv (domain);
 
+  if (domain->malloced)
+    free (domain->malloced);
+
 # ifdef _POSIX_MAPPED_FILES
   if (domain->use_mmap)
     munmap ((caddr_t) domain->data, domain->mmap_size);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]