summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rwxr-xr-xconfigure2
-rw-r--r--intl/gmo.h5
-rw-r--r--intl/loadmsgcat.c358
-rw-r--r--stdio-common/vfprintf.c4
5 files changed, 256 insertions, 130 deletions
diff --git a/ChangeLog b/ChangeLog
index 6219a934d3..9cb5202118 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2004-01-09  Bruno Haible  <bruno@clisp.org>
+
+	* intl/gmo.h (MO_REVISION_NUMBER_WITH_SYSDEP_I): New definition.
+	* intl/loadmsgcat.c (get_sysdep_segment_value): Handle "I".
+	(_nl_load_domain): Treat major revision 1 like major revision 0.
+
+2004-01-11  Bruno Haible  <bruno@clisp.org>
+
+	* stdio-common/vfprintf.c (vfprintf): Disallow the 'I' flag after
+	width or precision has been seen.
+
+2004-01-08  Bruno Haible  <bruno@clisp.org>
+
+	* intl/loadmsgcat.c (_nl_load_domain): When a string pair uses a system
+	dependent segment not known to this version of the library, ignore
+	the string pair instead of crashing.
+
 2004-01-13  Ulrich Drepper  <drepper@redhat.com>
 
 	* configure.in: Rewrite test to give gcc to clean up after itself.
diff --git a/configure b/configure
index 20c44f4fc2..8f5fa38d33 100755
--- a/configure
+++ b/configure
@@ -6286,7 +6286,7 @@ if { ac_try='$libc_unwind_check >&5'
   (exit $ac_status); }; }
 then
   if $libc_unwind_check -v 2>&1 >/dev/null \
-     | grep -q -- --eh-frame-hdr; then
+     | grep -- --eh-frame-hdr 2>&1 >/dev/null; then
     libc_cv_gcc_dwarf2_unwind_info=no_registry_needed
   else
     libc_cv_gcc_dwarf2_unwind_info=static
diff --git a/intl/gmo.h b/intl/gmo.h
index 65e0b27440..81003fcee6 100644
--- a/intl/gmo.h
+++ b/intl/gmo.h
@@ -1,5 +1,5 @@
 /* Internal header for GNU gettext internationalization functions.
-   Copyright (C) 1995, 1997, 2000-2002 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1997, 2000-2002, 2004 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
@@ -30,6 +30,7 @@
 
 /* Revision number of the currently used .mo (binary) file format.  */
 #define MO_REVISION_NUMBER 0
+#define MO_REVISION_NUMBER_WITH_SYSDEP_I 1
 
 /* The following contortions are an attempt to use the C preprocessor
    to determine an unsigned integral type that is 32 bits wide.  An
@@ -77,7 +78,7 @@ struct mo_file_header
   /* The revision number of the file format.  */
   nls_uint32 revision;
 
-  /* The following are only used in .mo files with major revision 0.  */
+  /* The following are only used in .mo files with major revision 0 or 1.  */
 
   /* The number of strings pairs.  */
   nls_uint32 nstrings;
diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c
index 6a70feccb0..d70d77e9ed 100644
--- a/intl/loadmsgcat.c
+++ b/intl/loadmsgcat.c
@@ -1,5 +1,5 @@
 /* Load needed message catalogs.
-   Copyright (C) 1995-2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1995-2004 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
@@ -735,6 +735,18 @@ get_sysdep_segment_value (name)
 	    }
 	}
     }
+  /* Test for a glibc specific printf() format directive flag.  */
+  if (name[0] == 'I' && name[1] == '\0')
+    {
+#if defined _LIBC || __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
+      /* The 'I' flag, in numeric format directives, replaces ASCII digits
+	 with the 'outdigits' defined in the LC_CTYPE locale facet.  This is
+	 used for Farsi (Persian) and maybe Arabic.  */
+      return "I";
+#else
+      return "";
+#endif
+    }
   /* Other system dependent strings are not valid.  */
   return NULL;
 }
@@ -1009,10 +1021,11 @@ _nl_load_domain (domain_file, domainbinding)
 
   /* Fill in the information about the available tables.  */
   revision = W (domain->must_swap, data->revision);
-  /* We support only the major revision 0.  */
+  /* We support only the major revisions 0 and 1.  */
   switch (revision >> 16)
     {
     case 0:
+    case 1:
       domain->nstrings = W (domain->must_swap, data->nstrings);
       domain->orig_tab = (const struct string_desc *)
 	((char *) data + W (domain->must_swap, data->orig_tab_offset));
@@ -1052,12 +1065,13 @@ _nl_load_domain (domain_file, domainbinding)
 		const char **sysdep_segment_values;
 		const nls_uint32 *orig_sysdep_tab;
 		const nls_uint32 *trans_sysdep_tab;
+		nls_uint32 n_inmem_sysdep_strings;
 		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;
+		unsigned int i, j;
 
 		/* Get the values of the system dependent segments.  */
 		n_sysdep_segments =
@@ -1092,153 +1106,247 @@ _nl_load_domain (domain_file, domainbinding)
 		   + 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++)
+		   system dependent strings and the augmented hash table.
+		   At the same time, also drop string pairs which refer to
+		   an undefined system dependent segment.  */
+		n_inmem_sysdep_strings = 0;
+		memneed = domain->hash_size * sizeof (nls_uint32);
+		for (i = 0; i < 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)
+		    int valid = 1;
+		    size_t needs[2];
+
+		    for (j = 0; j < 2; j++)
+		      {
+			const struct sysdep_string *sysdep_string =
+			  (const struct sysdep_string *)
+			  ((char *) data
+			   + W (domain->must_swap,
+				j == 0
+				? orig_sysdep_tab[i]
+				: trans_sysdep_tab[i]));
+			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++)
 			    {
-			      /* Invalid.  */
-			      freea (sysdep_segment_values);
-			      goto invalid;
-			    }
+			      nls_uint32 sysdepref;
 
-			  need += strlen (sysdep_segment_values[sysdepref]);
-			}
+			      need += W (domain->must_swap, p->segsize);
 
-		    memneed += need;
-		  }
+			      sysdepref = W (domain->must_swap, p->sysdepref);
+			      if (sysdepref == SEGMENTS_END)
+				break;
 
-		/* 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;
+			      if (sysdepref >= n_sysdep_segments)
+				{
+				  /* Invalid.  */
+				  freea (sysdep_segment_values);
+				  goto invalid;
+				}
+
+			      if (sysdep_segment_values[sysdepref] == NULL)
+				{
+				  /* This particular string pair is invalid.  */
+				  valid = 0;
+				  break;
+				}
 
-		    /* 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).  */
+			      need += strlen (sysdep_segment_values[sysdepref]);
+			    }
+
+			needs[j] = need;
+			if (!valid)
+			  break;
+		      }
 
-		    if (W (domain->must_swap, p->sysdepref) == SEGMENTS_END)
+		    if (valid)
 		      {
-			/* Only one static segment.  */
-			inmem_orig_sysdep_tab[i].length =
-			  W (domain->must_swap, p->segsize);
-			inmem_orig_sysdep_tab[i].pointer = static_segments;
+			n_inmem_sysdep_strings++;
+			memneed += needs[0] + needs[1];
 		      }
-		    else
+		  }
+		memneed += 2 * n_inmem_sysdep_strings
+			   * sizeof (struct sysdep_string_desc);
+
+		if (n_inmem_sysdep_strings > 0)
+		  {
+		    unsigned int k;
+
+		    /* 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_inmem_sysdep_strings
+			   * sizeof (struct sysdep_string_desc);
+		    inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem;
+		    mem += n_inmem_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.  */
+		    k = 0;
+		    for (i = 0; i < n_sysdep_strings; i++)
 		      {
-			inmem_orig_sysdep_tab[i].pointer = mem;
+			int valid = 1;
 
-			for (p = sysdep_string->segments;; p++)
+			for (j = 0; j < 2; j++)
 			  {
-			    nls_uint32 segsize =
-			      W (domain->must_swap, p->segsize);
-			    nls_uint32 sysdepref =
-			      W (domain->must_swap, p->sysdepref);
-			    size_t n;
+			    const struct sysdep_string *sysdep_string =
+			      (const struct sysdep_string *)
+			      ((char *) data
+			       + W (domain->must_swap,
+				    j == 0
+				    ? orig_sysdep_tab[i]
+				    : trans_sysdep_tab[i]));
+			    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;
+
+				  sysdepref =
+				    W (domain->must_swap, p->sysdepref);
+				  if (sysdepref == SEGMENTS_END)
+				    break;
+
+				  if (sysdep_segment_values[sysdepref] == NULL)
+				    {
+				      /* This particular string pair is
+					 invalid.  */
+				      valid = 0;
+				      break;
+				    }
+				}
+
+			    if (!valid)
+			      break;
+			  }
 
-			    if (segsize > 0)
+			if (valid)
+			  {
+			    for (j = 0; j < 2; j++)
 			      {
-				memcpy (mem, static_segments, segsize);
-				mem += segsize;
-				static_segments += segsize;
+				const struct sysdep_string *sysdep_string =
+				  (const struct sysdep_string *)
+				  ((char *) data
+				   + W (domain->must_swap,
+					j == 0
+					? orig_sysdep_tab[i]
+					: trans_sysdep_tab[i]));
+				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[k] (for j == 0) and
+				   inmem_trans_sysdep_tab[k] (for j == 1).  */
+
+				struct sysdep_string_desc *inmem_tab_entry =
+				  (j == 0
+				   ? inmem_orig_sysdep_tab
+				   : inmem_trans_sysdep_tab)
+				  + k;
+
+				if (W (domain->must_swap, p->sysdepref)
+				    == SEGMENTS_END)
+				  {
+				    /* Only one static segment.  */
+				    inmem_tab_entry->length =
+				      W (domain->must_swap, p->segsize);
+				    inmem_tab_entry->pointer = static_segments;
+				  }
+				else
+				  {
+				    inmem_tab_entry->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_tab_entry->length =
+				      mem - inmem_tab_entry->pointer;
+				  }
 			      }
 
-			    if (sysdepref == SEGMENTS_END)
-			      break;
-
-			    n = strlen (sysdep_segment_values[sysdepref]);
-			    memcpy (mem, sysdep_segment_values[sysdepref], n);
-			    mem += n;
+			    k++;
 			  }
-
-			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 (k != n_inmem_sysdep_strings)
+		      abort ();
+
+		    /* 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_inmem_sysdep_strings; i++)
 		      {
-			if (inmem_hash_tab[idx] == 0)
+			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 (;;)
 			  {
-			    /* Hash table entry is empty.  Use it.  */
-			    inmem_hash_tab[idx] = 1 + domain->nstrings + i;
-			    break;
-			  }
+			    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;
+			    if (idx >= domain->hash_size - incr)
+			      idx -= domain->hash_size - incr;
+			    else
+			      idx += incr;
+			  }
 		      }
-		  }
 
-		freea (sysdep_segment_values);
+		    domain->n_sysdep_strings = n_inmem_sysdep_strings;
+		    domain->orig_sysdep_tab = inmem_orig_sysdep_tab;
+		    domain->trans_sysdep_tab = inmem_trans_sysdep_tab;
 
-		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;
+		  }
 
-		domain->hash_tab = inmem_hash_tab;
-		domain->must_swap_hash_tab = 0;
+		freea (sysdep_segment_values);
 	      }
 	    else
 	      {
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index b84107ab6f..8465680312 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -399,7 +399,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
       REF (form_floathex),	/* for 'A', 'a' */			      \
       REF (mod_ptrdiff_t),      /* for 't' */				      \
       REF (mod_intmax_t),       /* for 'j' */				      \
-      REF (flag_i18n)	        /* for 'I' */				      \
+      REF (form_unknown)        /* for 'I' */				      \
     };									      \
     /* Step 2: after processing precision.  */				      \
     static JUMP_TABLE_TYPE step2_jumps[30] =				      \
@@ -433,7 +433,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
       REF (form_floathex),	/* for 'A', 'a' */			      \
       REF (mod_ptrdiff_t),      /* for 't' */				      \
       REF (mod_intmax_t),       /* for 'j' */				      \
-      REF (flag_i18n)	        /* for 'I' */				      \
+      REF (form_unknown)        /* for 'I' */				      \
     };									      \
     /* Step 3a: after processing first 'h' modifier.  */		      \
     static JUMP_TABLE_TYPE step3a_jumps[30] =				      \