This is the mail archive of the libc-alpha@sourceware.org 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]

Add localedef --big-endian and --little-endian options


This patch adds localedef support for --big-endian and --little-endian
options for generating binary locale data for use on another system.

Building on the previous cleanups of internal interfaces
<https://sourceware.org/ml/libc-alpha/2013-09/msg00148.html>, the
changes outside of locarchive.c are closely based on the
cross-localedef changes implemented by Richard Sandiford in 2006 for
EGLIBC.  Those changes, however, did not do anything to support locale
archives of the other endianness, only the separate files for each
locale.  The changes to locale archive handling make up the bulk of
this patch; as well as one place where locale archive handling
examines individual locale data directly and byte-swapping is needed
for that, the archive handling makes a lots of use of structures
directly mmapped from or written to files.  This patch adds
getter/setter macros used to do the required byte-swapping instead of
accessing structure fields directly.  Fortunately the relevant
structures are just sequences of uint32_t values (possibly after a
16-byte MD5 hash value), so no other architecture-dependence affects
them.

The new options are mentioned in NEWS; there is no documentation for
the localedef program in the manual (nor in the Linux man-pages
collection), so nothing to update there.

Tested x86_64.  This patch does not change the generated
locale-archive from "make localedata/install-locales".  When used
together with my patch
<https://sourceware.org/ml/libc-alpha/2013-09/msg00408.html> for the
locale archive hash function depending on the signedness of plain
"char", the locale-archive generated with --big-endian is identical
with one generated on powerpc (both systems having page size of 4k).
Making it fully possible for any glibc system to generate locale data
identical to that generated natively on any other glibc system will
require at least two more changes, to resolve the issues with int32_t
alignment <https://sourceware.org/ml/libc-alpha/2013-09/msg00109.html>
and page size
<https://sourceware.org/ml/libc-alpha/2013-09/msg00365.html> - in each
case, either removing the architecture-dependence or adding a further
command-line option to control it.

2013-09-11  Joseph Myers  <joseph@codesourcery.com>
	    Richard Sandiford  <richard@codesourcery.com>

	* locale/programs/locfile.h: Include <byteswap.h>.
	(swap_endianness_p): New extern variable.
	(set_big_endian): New inline function.
	(maybe_swap_uint32): Likewise.
	(maybe_swap_uint32_array): Likewise.
	(maybe_swap_uint32_obstack): Likewise.
	* locale/programs/locfile.c (swap_endianness_p): New variable.
	(add_locale_uint32): Call maybe_swap_uint32.
	(add_locale_uint32_array): Call maybe_swap_uint32_obstack.
	(write_locale_data): Call maybe_swap_uint32_array.
	* locale/programs/ld-collate.c (obstack_int32_grow): Call
	maybe_swap_uint32.
	(obstack_int32_grow_fast): Likewise.
	(output_weightwc): Call maybe_swap_uint32_obstack.
	(collate_output): Likewise.
	* locale/programs/localedef.c (OPT_LITTLE_ENDIAN): New macro.
	(OPT_LITTLE_ENDIAN): Likewise.
	(options): Add --little-endian and --bit-endian options.
	(parse_opt): Handle OPT_LITTLE_ENDIAN and OPT_BIG_ENDIAN.
	* locale/programs/locarchive.c: Include "locfile.h".
	(GET): New macro.
	(SET): Likewise.
	(INC): Likewise.
	(create_archive): Use the new macros to access fields of
	structures directly mapped from or written to locale archives.
	(oldlocrecentcmp): Likewise.
	(enlarge_archive): Likewise.
	(insert_name): Likewise.
	(add_alias): Likewise.
	(add_locale): Likewise.
	(delete_locales_from_archive): Likewise.
	(show_archive_content): Likewise.
	(add_locale_to_archive): Likewise.  Use maybe_swap_uint32 on
	locale data.

diff --git a/NEWS b/NEWS
index f91afca..acc36bf 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,10 @@ Version 2.19
 
 * Update iso-1427.def and related occurrences.
 
+* The localedef utility now supports --big-endian and --little-endian
+  configure options to generate locales for a different system from that for
+  which glibc was built.
+
 * The configure option --disable-versioning has been removed.  Builds with
   --disable-versioning had not worked for several years.
 
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c
index c4d7e3d..e610389 100644
--- a/locale/programs/ld-collate.c
+++ b/locale/programs/ld-collate.c
@@ -44,6 +44,7 @@ static inline void
 __attribute ((always_inline))
 obstack_int32_grow (struct obstack *obstack, int32_t data)
 {
+  data = maybe_swap_uint32 (data);
   if (sizeof (int32_t) == sizeof (int))
     obstack_int_grow (obstack, data);
   else
@@ -54,6 +55,7 @@ static inline void
 __attribute ((always_inline))
 obstack_int32_grow_fast (struct obstack *obstack, int32_t data)
 {
+  data = maybe_swap_uint32 (data);
   if (sizeof (int32_t) == sizeof (int))
     obstack_int_grow_fast (obstack, data);
   else
@@ -1955,6 +1957,7 @@ output_weightwc (struct obstack *pool, struct locale_collate_t *collate,
       obstack_int32_grow (pool, j);
 
       obstack_grow (pool, buf, j * sizeof (int32_t));
+      maybe_swap_uint32_obstack (pool, j);
     }
 
   return retval | ((elem->section->ruleidx & 0x7f) << 24);
@@ -2479,6 +2482,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
 	  obstack_int32_grow (&extrapool, runp->nwcs);
 	  obstack_grow (&extrapool, runp->wcs,
 			runp->nwcs * sizeof (uint32_t));
+	  maybe_swap_uint32_obstack (&extrapool, runp->nwcs);
 
 	  obstack_int32_grow (&extrapool, runp->wcseqorder);
 	}
diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c
index 5a14f2c..82a8798 100644
--- a/locale/programs/localedef.c
+++ b/locale/programs/localedef.c
@@ -112,6 +112,8 @@ void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
 #define OPT_REPLACE 307
 #define OPT_DELETE_FROM_ARCHIVE 308
 #define OPT_LIST_ARCHIVE 309
+#define OPT_LITTLE_ENDIAN 400
+#define OPT_BIG_ENDIAN 401
 
 /* Definitions of arguments for argp functions.  */
 static const struct argp_option options[] =
@@ -144,6 +146,9 @@ static const struct argp_option options[] =
   { "list-archive", OPT_LIST_ARCHIVE, NULL, 0, N_("List content of archive") },
   { "alias-file", 'A', N_("FILE"), 0,
     N_("locale.alias file to consult when making archive")},
+  { "little-endian", OPT_LITTLE_ENDIAN, NULL, 0,
+    N_("Generate little-endian output") },
+  { "big-endian", OPT_BIG_ENDIAN, NULL, 0, N_("Generate big-endian output") },
   { NULL, 0, NULL, 0, NULL }
 };
 
@@ -326,6 +331,12 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case OPT_LIST_ARCHIVE:
       list_archive = true;
       break;
+    case OPT_LITTLE_ENDIAN:
+      set_big_endian (0);
+      break;
+    case OPT_BIG_ENDIAN:
+      set_big_endian (1);
+      break;
     case 'c':
       force_output = 1;
       break;
diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c
index d8df39a..9c93612 100644
--- a/locale/programs/locarchive.c
+++ b/locale/programs/locarchive.c
@@ -46,6 +46,7 @@
 #include "../localeinfo.h"
 #include "../locarchive.h"
 #include "localedef.h"
+#include "locfile.h"
 
 /* Define the hash function.  We define the function as static inline.
    We must change the name so as not to conflict with simple-hash.h.  */
@@ -74,6 +75,14 @@ static const char *locnames[] =
 #define INITIAL_NUM_SUMS	2000
 
 
+/* Get and set values (possibly endian-swapped) in structures mapped
+   from or written directly to locale archives.  */
+#define GET(VAR, FIELD)	maybe_swap_uint32 ((VAR).FIELD)
+#define SET(VAR, FIELD, VALUE)	((VAR).FIELD = maybe_swap_uint32 (VALUE))
+#define INC(VAR, FIELD, INCREMENT)			\
+  SET (VAR, FIELD, GET (VAR, FIELD) + (INCREMENT))
+
+
 /* Size of the reserved address space area.  */
 #define RESERVE_MMAP_SIZE	512 * 1024 * 1024
 
@@ -125,27 +134,31 @@ create_archive (const char *archivefname, struct locarhandle *ah)
     error (EXIT_FAILURE, errno, _("cannot create temporary file: %s"), fname);
 
   /* Create the initial content of the archive.  */
-  head.magic = AR_MAGIC;
-  head.serial = 0;
-  head.namehash_offset = sizeof (struct locarhead);
-  head.namehash_used = 0;
-  head.namehash_size = next_prime (INITIAL_NUM_NAMES);
-
-  head.string_offset = (head.namehash_offset
-			+ head.namehash_size * sizeof (struct namehashent));
-  head.string_used = 0;
-  head.string_size = INITIAL_SIZE_STRINGS;
-
-  head.locrectab_offset = head.string_offset + head.string_size;
-  head.locrectab_used = 0;
-  head.locrectab_size = INITIAL_NUM_LOCREC;
-
-  head.sumhash_offset = (head.locrectab_offset
-			 + head.locrectab_size * sizeof (struct locrecent));
-  head.sumhash_used = 0;
-  head.sumhash_size = next_prime (INITIAL_NUM_SUMS);
-
-  total = head.sumhash_offset + head.sumhash_size * sizeof (struct sumhashent);
+  SET (head, magic, AR_MAGIC);
+  SET (head, serial, 0);
+  SET (head, namehash_offset, sizeof (struct locarhead));
+  SET (head, namehash_used, 0);
+  SET (head, namehash_size, next_prime (INITIAL_NUM_NAMES));
+
+  SET (head, string_offset,
+       (GET (head, namehash_offset)
+	+ GET (head, namehash_size) * sizeof (struct namehashent)));
+  SET (head, string_used, 0);
+  SET (head, string_size, INITIAL_SIZE_STRINGS);
+
+  SET (head, locrectab_offset,
+       GET (head, string_offset) + GET (head, string_size));
+  SET (head, locrectab_used, 0);
+  SET (head, locrectab_size, INITIAL_NUM_LOCREC);
+
+  SET (head, sumhash_offset,
+       (GET (head, locrectab_offset)
+	+ GET (head, locrectab_size) * sizeof (struct locrecent)));
+  SET (head, sumhash_used, 0);
+  SET (head, sumhash_size, next_prime (INITIAL_NUM_SUMS));
+
+  total = (GET (head, sumhash_offset)
+	   + GET (head, sumhash_size) * sizeof (struct sumhashent));
 
   /* Write out the header and create room for the other data structures.  */
   if (TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head))) != sizeof (head))
@@ -240,10 +253,10 @@ oldlocrecentcmp (const void *a, const void *b)
   for (cnt = 0; cnt < __LC_LAST; ++cnt)
     if (cnt != LC_ALL)
       {
-	if (la->record[cnt].offset < start_a)
-	  start_a = la->record[cnt].offset;
-	if (la->record[cnt].offset + la->record[cnt].len > end_a)
-	  end_a = la->record[cnt].offset + la->record[cnt].len;
+	if (GET (la->record[cnt], offset) < start_a)
+	  start_a = GET (la->record[cnt], offset);
+	if (GET (la->record[cnt], offset) + GET (la->record[cnt], len) > end_a)
+	  end_a = GET (la->record[cnt], offset) + GET (la->record[cnt], len);
       }
   assert (start_a != (uint32_t)-1);
   assert (end_a != 0);
@@ -251,10 +264,10 @@ oldlocrecentcmp (const void *a, const void *b)
   for (cnt = 0; cnt < __LC_LAST; ++cnt)
     if (cnt != LC_ALL)
       {
-	if (lb->record[cnt].offset < start_b)
-	  start_b = lb->record[cnt].offset;
-	if (lb->record[cnt].offset + lb->record[cnt].len > end_b)
-	  end_b = lb->record[cnt].offset + lb->record[cnt].len;
+	if (GET (lb->record[cnt], offset) < start_b)
+	  start_b = GET (lb->record[cnt], offset);
+	if (GET (lb->record[cnt], offset) + GET (lb->record[cnt], len) > end_b)
+	  end_b = GET (lb->record[cnt], offset) + GET (lb->record[cnt], len);
       }
   assert (start_b != (uint32_t)-1);
   assert (end_b != 0);
@@ -371,38 +384,42 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
 
   /* Create the new archive header.  The sizes of the various tables
      should be double from what is currently used.  */
-  newhead.namehash_size = MAX (next_prime (2 * newhead.namehash_used),
-			       newhead.namehash_size);
+  SET (newhead, namehash_size,
+       MAX (next_prime (2 * GET (newhead, namehash_used)),
+	    GET (newhead, namehash_size)));
   if (verbose)
     printf ("name: size: %u, used: %d, new: size: %u\n",
-	    head->namehash_size, head->namehash_used, newhead.namehash_size);
+	    GET (*head, namehash_size),
+	    GET (*head, namehash_used), GET (newhead, namehash_size));
 
-  newhead.string_offset = (newhead.namehash_offset
-			   + (newhead.namehash_size
-			      * sizeof (struct namehashent)));
+  SET (newhead, string_offset, (GET (newhead, namehash_offset)
+				+ (GET (newhead, namehash_size)
+				   * sizeof (struct namehashent))));
   /* Keep the string table size aligned to 4 bytes, so that
      all the struct { uint32_t } types following are happy.  */
-  newhead.string_size = MAX ((2 * newhead.string_used + 3) & -4,
-			     newhead.string_size);
+  SET (newhead, string_size, MAX ((2 * GET (newhead, string_used) + 3) & -4,
+				  GET (newhead, string_size)));
 
-  newhead.locrectab_offset = newhead.string_offset + newhead.string_size;
-  newhead.locrectab_size = MAX (2 * newhead.locrectab_used,
-				newhead.locrectab_size);
+  SET (newhead, locrectab_offset,
+       GET (newhead, string_offset) + GET (newhead, string_size));
+  SET (newhead, locrectab_size, MAX (2 * GET (newhead, locrectab_used),
+				     GET (newhead, locrectab_size)));
 
-  newhead.sumhash_offset = (newhead.locrectab_offset
-			    + (newhead.locrectab_size
-			       * sizeof (struct locrecent)));
-  newhead.sumhash_size = MAX (next_prime (2 * newhead.sumhash_used),
-			      newhead.sumhash_size);
+  SET (newhead, sumhash_offset, (GET (newhead, locrectab_offset)
+				 + (GET (newhead, locrectab_size)
+				    * sizeof (struct locrecent))));
+  SET (newhead, sumhash_size,
+       MAX (next_prime (2 * GET (newhead, sumhash_used)),
+	    GET (newhead, sumhash_size)));
 
-  total = (newhead.sumhash_offset
-	   + newhead.sumhash_size * sizeof (struct sumhashent));
+  total = (GET (newhead, sumhash_offset)
+	   + GET (newhead, sumhash_size) * sizeof (struct sumhashent));
 
   /* The new file is empty now.  */
-  newhead.namehash_used = 0;
-  newhead.string_used = 0;
-  newhead.locrectab_used = 0;
-  newhead.sumhash_used = 0;
+  SET (newhead, namehash_used, 0);
+  SET (newhead, string_used, 0);
+  SET (newhead, locrectab_used, 0);
+  SET (newhead, sumhash_used, 0);
 
   /* Write out the header and create room for the other data structures.  */
   if (TEMP_FAILURE_RETRY (write (fd, &newhead, sizeof (newhead)))
@@ -453,17 +470,17 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
   /* Walk through the hash name hash table to find out what data is
      still referenced and transfer it into the new file.  */
   oldnamehashtab = (struct namehashent *) ((char *) ah->addr
-					   + head->namehash_offset);
+					   + GET (*head, namehash_offset));
 
   /* Sort the old locrec table in order of data position.  */
-  struct oldlocrecent oldlocrecarray[head->namehash_size];
-  for (cnt = 0, loccnt = 0; cnt < head->namehash_size; ++cnt)
-    if (oldnamehashtab[cnt].locrec_offset != 0)
+  struct oldlocrecent oldlocrecarray[GET (*head, namehash_size)];
+  for (cnt = 0, loccnt = 0; cnt < GET (*head, namehash_size); ++cnt)
+    if (GET (oldnamehashtab[cnt], locrec_offset) != 0)
       {
 	oldlocrecarray[loccnt].cnt = cnt;
 	oldlocrecarray[loccnt++].locrec
 	  = (struct locrecent *) ((char *) ah->addr
-				  + oldnamehashtab[cnt].locrec_offset);
+				  + GET (oldnamehashtab[cnt], locrec_offset));
       }
   qsort (oldlocrecarray, loccnt, sizeof (struct oldlocrecent),
 	 oldlocrecentcmp);
@@ -479,9 +496,9 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
       for (idx = 0; idx < __LC_LAST; ++idx)
 	if (idx != LC_ALL)
 	  {
-	    old_data[idx].size = oldlocrec->record[idx].len;
+	    old_data[idx].size = GET (oldlocrec->record[idx], len);
 	    old_data[idx].addr
-	      = ((char *) ah->addr + oldlocrec->record[idx].offset);
+	      = ((char *) ah->addr + GET (oldlocrec->record[idx], offset));
 
 	    __md5_buffer (old_data[idx].addr, old_data[idx].size,
 			  old_data[idx].sum);
@@ -491,11 +508,13 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
 	{
 	  const char *oldname
 	    = ((char *) ah->addr
-	       + oldnamehashtab[oldlocrecarray[cnt - 1].cnt].name_offset);
+	       + GET (oldnamehashtab[oldlocrecarray[cnt - 1].cnt],
+		      name_offset));
 
 	  add_alias (&new_ah,
 		     ((char *) ah->addr
-		      + oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset),
+		      + GET (oldnamehashtab[oldlocrecarray[cnt].cnt],
+			     name_offset)),
 		     0, oldname, &last_locrec_offset);
 	  continue;
 	}
@@ -503,7 +522,8 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
       last_locrec_offset =
 	add_locale (&new_ah,
 		    ((char *) ah->addr
-		     + oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset),
+		     + GET (oldnamehashtab[oldlocrecarray[cnt].cnt],
+			    name_offset)),
 		    old_data, 0);
       if (last_locrec_offset == 0)
 	error (EXIT_FAILURE, 0, _("cannot extend locale archive file"));
@@ -672,26 +692,28 @@ insert_name (struct locarhandle *ah,
 {
   const struct locarhead *const head = ah->addr;
   struct namehashent *namehashtab
-    = (struct namehashent *) ((char *) ah->addr + head->namehash_offset);
+    = (struct namehashent *) ((char *) ah->addr
+			      + GET (*head, namehash_offset));
   unsigned int insert_idx, idx, incr;
 
   /* Hash value of the locale name.  */
   uint32_t hval = archive_hashval (name, name_len);
 
   insert_idx = -1;
-  idx = hval % head->namehash_size;
-  incr = 1 + hval % (head->namehash_size - 2);
+  idx = hval % GET (*head, namehash_size);
+  incr = 1 + hval % (GET (*head, namehash_size) - 2);
 
   /* If the name_offset field is zero this means this is a
      deleted entry and therefore no entry can be found.  */
-  while (namehashtab[idx].name_offset != 0)
+  while (GET (namehashtab[idx], name_offset) != 0)
     {
-      if (namehashtab[idx].hashval == hval
-	  && strcmp (name,
-		     (char *) ah->addr + namehashtab[idx].name_offset) == 0)
+      if (GET (namehashtab[idx], hashval) == hval
+	  && (strcmp (name,
+		      (char *) ah->addr + GET (namehashtab[idx], name_offset))
+	      == 0))
 	{
 	  /* Found the entry.  */
-	  if (namehashtab[idx].locrec_offset != 0 && ! replace)
+	  if (GET (namehashtab[idx], locrec_offset) != 0 && ! replace)
 	    {
 	      if (! be_quiet)
 		error (0, 0, _("locale '%s' already exists"), name);
@@ -701,26 +723,27 @@ insert_name (struct locarhandle *ah,
 	  break;
 	}
 
-      if (namehashtab[idx].hashval == hval && ! be_quiet)
+      if (GET (namehashtab[idx], hashval) == hval && ! be_quiet)
 	{
 	  error (0, 0, "hash collision (%u) %s, %s",
-		 hval, name, (char *) ah->addr + namehashtab[idx].name_offset);
+		 hval, name, (char *) ah->addr + GET (namehashtab[idx],
+						      name_offset));
 	}
 
       /* Remember the first place we can insert the new entry.  */
-      if (namehashtab[idx].locrec_offset == 0 && insert_idx == -1)
+      if (GET (namehashtab[idx], locrec_offset) == 0 && insert_idx == -1)
 	insert_idx = idx;
 
       idx += incr;
-      if (idx >= head->namehash_size)
-	idx -= head->namehash_size;
+      if (idx >= GET (*head, namehash_size))
+	idx -= GET (*head, namehash_size);
     }
 
   /* Add as early as possible.  */
   if (insert_idx != -1)
     idx = insert_idx;
 
-  namehashtab[idx].hashval = hval; /* no-op if replacing an old entry.  */
+  SET (namehashtab[idx], hashval, hval); /* no-op if replacing an old entry.  */
   return &namehashtab[idx];
 }
 
@@ -736,12 +759,13 @@ add_alias (struct locarhandle *ah, const char *alias, bool replace,
   if (namehashent == NULL && ! replace)
     return;
 
-  if (namehashent->name_offset == 0)
+  if (GET (*namehashent, name_offset) == 0)
     {
       /* We are adding a new hash entry for this alias.
 	 Determine whether we have to resize the file.  */
-      if (head->string_used + name_len + 1 > head->string_size
-	  || 100 * head->namehash_used > 75 * head->namehash_size)
+      if (GET (*head, string_used) + name_len + 1 > GET (*head, string_size)
+	  || (100 * GET (*head, namehash_used)
+	      > 75 * GET (*head, namehash_size)))
 	{
 	  /* The current archive is not large enough.  */
 	  enlarge_archive (ah, head);
@@ -749,9 +773,9 @@ add_alias (struct locarhandle *ah, const char *alias, bool replace,
 	  /* The locrecent might have moved, so we have to look up
 	     the old name afresh.  */
 	  namehashent = insert_name (ah, oldname, strlen (oldname), true);
-	  assert (namehashent->name_offset != 0);
-	  assert (namehashent->locrec_offset != 0);
-	  *locrec_offset_p = namehashent->locrec_offset;
+	  assert (GET (*namehashent, name_offset) != 0);
+	  assert (GET (*namehashent, locrec_offset) != 0);
+	  *locrec_offset_p = GET (*namehashent, locrec_offset);
 
 	  /* Tail call to try the whole thing again.  */
 	  add_alias (ah, alias, replace, oldname, locrec_offset_p);
@@ -759,26 +783,27 @@ add_alias (struct locarhandle *ah, const char *alias, bool replace,
 	}
 
       /* Add the name string.  */
-      memcpy (ah->addr + head->string_offset + head->string_used,
+      memcpy (ah->addr + GET (*head, string_offset) + GET (*head, string_used),
 	      alias, name_len + 1);
-      namehashent->name_offset = head->string_offset + head->string_used;
-      head->string_used += name_len + 1;
+      SET (*namehashent, name_offset,
+	   GET (*head, string_offset) + GET (*head, string_used));
+      INC (*head, string_used, name_len + 1);
 
-      ++head->namehash_used;
+      INC (*head, namehash_used, 1);
     }
 
-  if (namehashent->locrec_offset != 0)
+  if (GET (*namehashent, locrec_offset) != 0)
     {
       /* Replacing an existing entry.
 	 Mark that we are no longer using the old locrecent.  */
       struct locrecent *locrecent
 	= (struct locrecent *) ((char *) ah->addr
-				+ namehashent->locrec_offset);
-      --locrecent->refs;
+				+ GET (*namehashent, locrec_offset));
+      INC (*locrecent, refs, -1);
     }
 
   /* Point this entry at the locrecent installed for the main name.  */
-  namehashent->locrec_offset = locrec_offset;
+  SET (*namehashent, locrec_offset, locrec_offset);
 }
 
 static int			/* qsort comparator used below */
@@ -819,7 +844,7 @@ add_locale (struct locarhandle *ah,
 
   head = ah->addr;
   sumhashtab = (struct sumhashent *) ((char *) ah->addr
-				      + head->sumhash_offset);
+				      + GET (*head, sumhash_offset));
 
   memset (file_offsets, 0, sizeof (file_offsets));
 
@@ -877,10 +902,10 @@ add_locale (struct locarhandle *ah,
 	   table.  */
 	hval = archive_hashval (data[cnt].sum, 16);
 
-	idx = hval % head->sumhash_size;
-	incr = 1 + hval % (head->sumhash_size - 2);
+	idx = hval % GET (*head, sumhash_size);
+	incr = 1 + hval % (GET (*head, sumhash_size) - 2);
 
-	while (sumhashtab[idx].file_offset != 0)
+	while (GET (sumhashtab[idx], file_offset) != 0)
 	  {
 	    if (memcmp (data[cnt].sum, sumhashtab[idx].sum, 16) == 0)
 	      {
@@ -891,39 +916,41 @@ add_locale (struct locarhandle *ah,
 		   the size of the stored data.  So we have to search for
 		   it.  */
 		locrecent = (struct locrecent *) ((char *) ah->addr
-						  + head->locrectab_offset);
+						  + GET (*head,
+							 locrectab_offset));
 		size_t iloc;
-		for (iloc = 0; iloc < head->locrectab_used; ++iloc)
-		  if (locrecent[iloc].refs != 0
-		      && (locrecent[iloc].record[cnt].offset
-			  == sumhashtab[idx].file_offset))
+		for (iloc = 0; iloc < GET (*head, locrectab_used); ++iloc)
+		  if (GET (locrecent[iloc], refs) != 0
+		      && (GET (locrecent[iloc].record[cnt], offset)
+			  == GET (sumhashtab[idx], file_offset)))
 		    break;
 
-		if (iloc != head->locrectab_used
-		    && data[cnt].size == locrecent[iloc].record[cnt].len
+		if (iloc != GET (*head, locrectab_used)
+		    && data[cnt].size == GET (locrecent[iloc].record[cnt], len)
 		    /* We have to compare the content.  Either we can
 		       have the data mmaped or we have to read from
 		       the file.  */
-		    && (file_data_available_p (ah, sumhashtab[idx].file_offset,
+		    && (file_data_available_p (ah, GET (sumhashtab[idx],
+							file_offset),
 					       data[cnt].size)
 			? memcmp (data[cnt].addr,
 				  (char *) ah->addr
-				  + sumhashtab[idx].file_offset,
+				  + GET (sumhashtab[idx], file_offset),
 				  data[cnt].size) == 0
 			: compare_from_file (ah, data[cnt].addr,
-					     sumhashtab[idx].file_offset,
+					     GET (sumhashtab[idx], file_offset),
 					     data[cnt].size) == 0))
 		  {
 		    /* Found it.  */
-		    file_offsets[cnt] = sumhashtab[idx].file_offset;
+		    file_offsets[cnt] = GET (sumhashtab[idx], file_offset);
 		    --num_new_offsets;
 		    break;
 		  }
 	      }
 
 	    idx += incr;
-	    if (idx >= head->sumhash_size)
-	      idx -= head->sumhash_size;
+	    if (idx >= GET (*head, sumhash_size))
+	      idx -= GET (*head, sumhash_size);
 	  }
       }
 
@@ -933,11 +960,14 @@ add_locale (struct locarhandle *ah,
     return 0;
 
   /* Determine whether we have to resize the file.  */
-  if (100 * (head->sumhash_used + num_new_offsets) > 75 * head->sumhash_size
-      || (namehashent->locrec_offset == 0
-	  && (head->locrectab_used == head->locrectab_size
-	      || head->string_used + name_len + 1 > head->string_size
-	      || 100 * head->namehash_used > 75 * head->namehash_size)))
+  if ((100 * (GET (*head, sumhash_used) + num_new_offsets)
+       > 75 * GET (*head, sumhash_size))
+      || (GET (*namehashent, locrec_offset) == 0
+	  && (GET (*head, locrectab_used) == GET (*head, locrectab_size)
+	      || (GET (*head, string_used) + name_len + 1
+		  > GET (*head, string_size))
+	      || (100 * GET (*head, namehash_used)
+		  > 75 * GET (*head, namehash_size)))))
     {
       /* The current archive is not large enough.  */
       enlarge_archive (ah, head);
@@ -1000,20 +1030,20 @@ add_locale (struct locarhandle *ah,
 	/* Add the hash value to the hash table.  */
 	md5hval = archive_hashval (data[cnt].sum, 16);
 
-	idx = md5hval % head->sumhash_size;
-	incr = 1 + md5hval % (head->sumhash_size - 2);
+	idx = md5hval % GET (*head, sumhash_size);
+	incr = 1 + md5hval % (GET (*head, sumhash_size) - 2);
 
-	while (sumhashtab[idx].file_offset != 0)
+	while (GET (sumhashtab[idx], file_offset) != 0)
 	  {
 	    idx += incr;
-	    if (idx >= head->sumhash_size)
-	      idx -= head->sumhash_size;
+	    if (idx >= GET (*head, sumhash_size))
+	      idx -= GET (*head, sumhash_size);
 	  }
 
 	memcpy (sumhashtab[idx].sum, data[cnt].sum, 16);
-	sumhashtab[idx].file_offset = file_offsets[cnt];
+	SET (sumhashtab[idx], file_offset, file_offsets[cnt]);
 
-	++head->sumhash_used;
+	INC (*head, sumhash_used, 1);
       }
 
   lastoffset = file_offsets[LC_ALL];
@@ -1024,25 +1054,28 @@ add_locale (struct locarhandle *ah,
 	lastoffset += (data[cnt].size + 15) & -16;
       }
 
-  if (namehashent->name_offset == 0)
+  if (GET (*namehashent, name_offset) == 0)
     {
       /* Add the name string.  */
-      memcpy ((char *) ah->addr + head->string_offset + head->string_used,
+      memcpy ((char *) ah->addr + GET (*head, string_offset)
+	      + GET (*head, string_used),
 	      name, name_len + 1);
-      namehashent->name_offset = head->string_offset + head->string_used;
-      head->string_used += name_len + 1;
-      ++head->namehash_used;
+      SET (*namehashent, name_offset,
+	   GET (*head, string_offset) + GET (*head, string_used));
+      INC (*head, string_used, name_len + 1);
+      INC (*head, namehash_used, 1);
     }
 
-  if (namehashent->locrec_offset == 0)
+  if (GET (*namehashent, locrec_offset == 0))
     {
       /* Allocate a name location record.  */
-      namehashent->locrec_offset = (head->locrectab_offset
-				    + (head->locrectab_used++
-				       * sizeof (struct locrecent)));
+      SET (*namehashent, locrec_offset, (GET (*head, locrectab_offset)
+					 + (GET (*head, locrectab_used)
+					    * sizeof (struct locrecent))));
+      INC (*head, locrectab_used, 1);
       locrecent = (struct locrecent *) ((char *) ah->addr
-					+ namehashent->locrec_offset);
-      locrecent->refs = 1;
+					+ GET (*namehashent, locrec_offset));
+      SET (*locrecent, refs, 1);
     }
   else
     {
@@ -1050,27 +1083,29 @@ add_locale (struct locarhandle *ah,
 	 we still need a new one.  If not, reuse the old one.  */
 
       locrecent = (struct locrecent *) ((char *) ah->addr
-					+ namehashent->locrec_offset);
-      if (locrecent->refs > 1)
+					+ GET (*namehashent, locrec_offset));
+      if (GET (*locrecent, refs) > 1)
 	{
-	  --locrecent->refs;
-	  namehashent->locrec_offset = (head->locrectab_offset
-					+ (head->locrectab_used++
-					   * sizeof (struct locrecent)));
+	  INC (*locrecent, refs, -1);
+	  SET (*namehashent, locrec_offset, (GET (*head, locrectab_offset)
+					     + (GET (*head, locrectab_used)
+						* sizeof (struct locrecent))));
+	  INC (*head, locrectab_used, 1);
 	  locrecent = (struct locrecent *) ((char *) ah->addr
-					    + namehashent->locrec_offset);
-	  locrecent->refs = 1;
+					    + GET (*namehashent,
+						   locrec_offset));
+	  SET (*locrecent, refs, 1);
 	}
     }
 
   /* Fill in the table with the locations of the locale data.  */
   for (cnt = 0; cnt < __LC_LAST; ++cnt)
     {
-      locrecent->record[cnt].offset = file_offsets[cnt];
-      locrecent->record[cnt].len = data[cnt].size;
+      SET (locrecent->record[cnt], offset, file_offsets[cnt]);
+      SET (locrecent->record[cnt], len, data[cnt].size);
     }
 
-  return namehashent->locrec_offset;
+  return GET (*namehashent, locrec_offset);
 }
 
 
@@ -1129,7 +1164,8 @@ add_locale_to_archive (ah, name, data, replace)
 	unsigned int strindex[0];
       } *filedata = data[LC_CTYPE].addr;
       codeset = (char *) filedata
-	+ filedata->strindex[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME)];
+	+ maybe_swap_uint32 (filedata->strindex[_NL_ITEM_INDEX
+						(_NL_CTYPE_CODESET_NAME)]);
       char *normalized_codeset_name = NULL;
 
       normalized_codeset = _nl_normalize_codeset (codeset, strlen (codeset));
@@ -1492,7 +1528,7 @@ delete_locales_from_archive (nlist, list)
 
   head = ah.addr;
   namehashtab = (struct namehashent *) ((char *) ah.addr
-					+ head->namehash_offset);
+					+ GET (*head, namehash_offset));
 
   while (nlist-- > 0)
     {
@@ -1504,30 +1540,31 @@ delete_locales_from_archive (nlist, list)
       /* Search for this locale in the archive.  */
       hval = archive_hashval (locname, strlen (locname));
 
-      idx = hval % head->namehash_size;
-      incr = 1 + hval % (head->namehash_size - 2);
+      idx = hval % GET (*head, namehash_size);
+      incr = 1 + hval % (GET (*head, namehash_size) - 2);
 
       /* If the name_offset field is zero this means this is no
 	 deleted entry and therefore no entry can be found.  */
-      while (namehashtab[idx].name_offset != 0)
+      while (GET (namehashtab[idx], name_offset) != 0)
 	{
-	  if (namehashtab[idx].hashval == hval
+	  if (GET (namehashtab[idx], hashval) == hval
 	      && (strcmp (locname,
-			  (char *) ah.addr + namehashtab[idx].name_offset)
+			  (char *) ah.addr + GET (namehashtab[idx],
+						  name_offset))
 		  == 0))
 	    {
 	      /* Found the entry.  Now mark it as removed by zero-ing
 		 the reference to the locale record.  */
-	      namehashtab[idx].locrec_offset = 0;
+	      SET (namehashtab[idx], locrec_offset, 0);
 	      break;
 	    }
 
 	  idx += incr;
-	  if (idx >= head->namehash_size)
-	    idx -= head->namehash_size;
+	  if (idx >= GET (*head, namehash_size))
+	    idx -= GET (*head, namehash_size);
 	}
 
-      if (namehashtab[idx].name_offset == 0 && ! be_quiet)
+      if (GET (namehashtab[idx], name_offset) == 0 && ! be_quiet)
 	error (0, 0, _("locale \"%s\" not in archive"), locname);
     }
 
@@ -1590,17 +1627,17 @@ show_archive_content (int verbose)
 
   head = ah.addr;
 
-  names = (struct nameent *) xmalloc (head->namehash_used
+  names = (struct nameent *) xmalloc (GET (*head, namehash_used)
 				      * sizeof (struct nameent));
 
   namehashtab = (struct namehashent *) ((char *) ah.addr
-					+ head->namehash_offset);
-  for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
-    if (namehashtab[cnt].locrec_offset != 0)
+					+ GET (*head, namehash_offset));
+  for (cnt = used = 0; cnt < GET (*head, namehash_size); ++cnt)
+    if (GET (namehashtab[cnt], locrec_offset) != 0)
       {
-	assert (used < head->namehash_used);
-	names[used].name = ah.addr + namehashtab[cnt].name_offset;
-	names[used++].locrec_offset = namehashtab[cnt].locrec_offset;
+	assert (used < GET (*head, namehash_used));
+	names[used].name = ah.addr + GET (namehashtab[cnt], name_offset);
+	names[used++].locrec_offset = GET (namehashtab[cnt], locrec_offset);
       }
 
   /* Sort the names.  */
@@ -1612,17 +1649,17 @@ show_archive_content (int verbose)
       struct sumhashent *sumhashtab;
       int sumused;
 
-      files = (struct dataent *) xmalloc (head->sumhash_used
+      files = (struct dataent *) xmalloc (GET (*head, sumhash_used)
 					  * sizeof (struct dataent));
 
       sumhashtab = (struct sumhashent *) ((char *) ah.addr
-					  + head->sumhash_offset);
-      for (cnt = sumused = 0; cnt < head->sumhash_size; ++cnt)
-	if (sumhashtab[cnt].file_offset != 0)
+					  + GET (*head, sumhash_offset));
+      for (cnt = sumused = 0; cnt < GET (*head, sumhash_size); ++cnt)
+	if (GET (sumhashtab[cnt], file_offset) != 0)
 	  {
-	    assert (sumused < head->sumhash_used);
+	    assert (sumused < GET (*head, sumhash_used));
 	    files[sumused].sum = (const unsigned char *) sumhashtab[cnt].sum;
-	    files[sumused].file_offset = sumhashtab[cnt].file_offset;
+	    files[sumused].file_offset = GET (sumhashtab[cnt], file_offset);
 	    files[sumused++].nlink = 0;
 	  }
 
@@ -1638,18 +1675,19 @@ show_archive_content (int verbose)
 	  locrec = (struct locrecent *) ((char *) ah.addr
 					 + names[cnt].locrec_offset);
 	  for (idx = 0; idx < __LC_LAST; ++idx)
-	    if (locrec->record[LC_ALL].offset != 0
+	    if (GET (locrec->record[LC_ALL], offset) != 0
 		? (idx == LC_ALL
-		   || (locrec->record[idx].offset
-		       < locrec->record[LC_ALL].offset)
-		   || (locrec->record[idx].offset + locrec->record[idx].len
-		       > (locrec->record[LC_ALL].offset
-			  + locrec->record[LC_ALL].len)))
+		   || (GET (locrec->record[idx], offset)
+		       < GET (locrec->record[LC_ALL], offset))
+		   || ((GET (locrec->record[idx], offset)
+			+ GET (locrec->record[idx], len))
+		       > (GET (locrec->record[LC_ALL], offset)
+			  + GET (locrec->record[LC_ALL], len))))
 		: idx != LC_ALL)
 	      {
 		struct dataent *data, dataent;
 
-		dataent.file_offset = locrec->record[idx].offset;
+		dataent.file_offset = GET (locrec->record[idx], offset);
 		data = (struct dataent *) bsearch (&dataent, files, sumused,
 						   sizeof (struct dataent),
 						   dataentcmp);
@@ -1671,21 +1709,24 @@ show_archive_content (int verbose)
 	      {
 		struct dataent *data, dataent;
 
-		dataent.file_offset = locrec->record[idx].offset;
-		if (locrec->record[LC_ALL].offset != 0
-		    && dataent.file_offset >= locrec->record[LC_ALL].offset
-		    && (dataent.file_offset + locrec->record[idx].len
-			<= (locrec->record[LC_ALL].offset
-			    + locrec->record[LC_ALL].len)))
-		  dataent.file_offset = locrec->record[LC_ALL].offset;
+		dataent.file_offset = GET (locrec->record[idx], offset);
+		if (GET (locrec->record[LC_ALL], offset) != 0
+		    && dataent.file_offset >= GET (locrec->record[LC_ALL],
+						   offset)
+		    && (dataent.file_offset + GET (locrec->record[idx], len)
+			<= (GET (locrec->record[LC_ALL], offset)
+			    + GET (locrec->record[LC_ALL], len))))
+		  dataent.file_offset = GET (locrec->record[LC_ALL], offset);
 
 		data = (struct dataent *) bsearch (&dataent, files, sumused,
 						   sizeof (struct dataent),
 						   dataentcmp);
 		printf ("%6d %7x %3d%c ",
-			locrec->record[idx].len, locrec->record[idx].offset,
+			GET (locrec->record[idx], len),
+			GET (locrec->record[idx], offset),
 			data->nlink,
-			dataent.file_offset == locrec->record[LC_ALL].offset
+			dataent.file_offset == GET (locrec->record[LC_ALL],
+						    offset)
 			? '+' : ' ');
 		for (i = 0; i < 16; i += 4)
 		    printf ("%02x%02x%02x%02x",
diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c
index cb53bbc..ce01bbc 100644
--- a/locale/programs/locfile.c
+++ b/locale/programs/locfile.c
@@ -538,6 +538,10 @@ compare_files (const char *filename1, const char *filename2, size_t size,
   return ret;
 }
 
+/* True if the locale files use the opposite endianness to the
+   machine running localedef.  */
+int swap_endianness_p;
+
 /* When called outside a start_locale_structure/end_locale_structure
    or start_locale_prelude/end_locale_prelude block, record that the
    next byte in FILE's obstack will be the first byte of a new element.
@@ -624,6 +628,7 @@ add_locale_uint32 (struct locale_file *file, uint32_t value)
 {
   align_locale_data (file, sizeof (uint32_t));
   record_offset (file);
+  value = maybe_swap_uint32 (value);
   obstack_grow (&file->data, &value, sizeof (value));
 }
 
@@ -636,6 +641,7 @@ add_locale_uint32_array (struct locale_file *file,
   align_locale_data (file, sizeof (uint32_t));
   record_offset (file);
   obstack_grow (&file->data, data, n_elems * sizeof (uint32_t));
+  maybe_swap_uint32_obstack (&file->data, n_elems);
 }
 
 /* Record that FILE's next element is the single byte given by VALUE.  */
@@ -708,6 +714,8 @@ write_locale_data (const char *output_path, int catidx, const char *category,
   vec[1].iov_base = file->offsets;
   vec[2].iov_len = obstack_object_size (&file->data);
   vec[2].iov_base = obstack_finish (&file->data);
+  maybe_swap_uint32_array (vec[0].iov_base, 2);
+  maybe_swap_uint32_array (vec[1].iov_base, file->n_elements);
   n_elem = 3;
   if (! no_archive)
     {
diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h
index bdd87cc..5396064 100644
--- a/locale/programs/locfile.h
+++ b/locale/programs/locfile.h
@@ -18,6 +18,7 @@
 #ifndef _LOCFILE_H
 #define _LOCFILE_H	1
 
+#include <byteswap.h>
 #include <stdint.h>
 #include <sys/uio.h>
 
@@ -67,6 +68,41 @@ extern void write_all_categories (struct localedef_t *definitions,
 				  const char *locname,
 				  const char *output_path);
 
+extern int swap_endianness_p;
+
+/* Change the output to be big-endian if BIG_ENDIAN is true and
+   little-endian otherwise.  */
+static inline void
+set_big_endian (int big_endian)
+{
+  swap_endianness_p = ((big_endian != 0) != (__BYTE_ORDER == __BIG_ENDIAN));
+}
+
+/* Munge VALUE so that, when stored, it has the correct byte order
+   for the output files.  */
+static inline uint32_t
+maybe_swap_uint32 (uint32_t value)
+{
+  return swap_endianness_p ? bswap_32 (value) : value;
+}
+
+/* Likewise, but munge an array of N uint32_ts starting at ARRAY.  */
+static inline void
+maybe_swap_uint32_array (uint32_t *array, size_t n)
+{
+  if (swap_endianness_p)
+    while (n-- > 0)
+      array[n] = bswap_32 (array[n]);
+}
+
+/* Like maybe_swap_uint32_array, but the array of N elements is at
+   the end of OBSTACK's current object.  */
+static inline void
+maybe_swap_uint32_obstack (struct obstack *obstack, size_t n)
+{
+  maybe_swap_uint32_array ((uint32_t *) obstack_next_free (obstack) - n, n);
+}
+
 /* Write out the data.  */
 extern void init_locale_data (struct locale_file *file, size_t n_elements);
 extern void align_locale_data (struct locale_file *file, size_t boundary);

-- 
Joseph S. Myers
joseph@codesourcery.com


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