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]

Make localedef output generation use more logical interfaces


This patch reworks how localedef generates its output files, to use
logical interfaces such as add_locale_uint32 and add_locale_wstring to
add different kinds of elements to output files instead of the
previous approach of generating raw iovecs everywhere.

The motivation of this patch is to enable making localedef support
generating files for a system with a different architecture, by making
it so that only a limited number of places need to do byte-swapping if
that architecture has a different endianness.  I hope it should also
be clear that the logical interface here makes for cleaner code than
the previous approach with raw iovecs.

This patch is based on changes originally implemented by Richard
Sandiford in 2006 which included the byte-swapping (and, as noted in
<https://sourceware.org/ml/libc-alpha/2013-09/msg00109.html>, support
for different alignment of int32_t).  I've tried to limit this
particular patch to the interface cleanup only, without any of the
actual support for byte-swapping or int32_t alignment variation, and
without any cleanups or bug fixes not actually required for the new
interface (I propose to deal with merging those other things
separately), as well as updating the code to current standards.
However, as a large patch, it's quite possible there are still stray
cleanups or other changes that should not be present here (even if
desirable as separate patches), or bits of code not following current
standards; please review the changes carefully.

The existing localedef code is generally not careful about
distinguishing 32-bit integer types (int32_t, uint32_t, u_int32_t,
wchar_t, int, unsigned int, enums) or using them in a consistent
fashion and freely casts between pointers to such types and assumes
all such types are 32-bit.  The new code does not try to be any more
careful than the old in this regard (and I don't plan any changes to
make localedef more careful here, except for a few cases where such
changes to existing code were already in the cross-localedef code but
omitted from this patch to keep it down to the one intended logical
change).

Tested x86_64.  The locale-archive generated by "make
localedata/install-locales" is identical before and after the patch.

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

	* locale/programs/locfile.c: Include <assert.h>, <wchar.h> and
	"localeinfo.h".
	(obstack_chunk_alloc): New macro.
	(obstack_chunk_free): Likewise.
	(record_offset): New function.
	(init_locale_data): Likewise.
	(align_locale_data): Likewise.
	(add_locale_empty): Likewise.
	(add_locale_raw_data): Likewise.
	(add_locale_raw_obstack): Likewise.
	(add_locale_string): Likewise.
	(add_locale_wstring): Likewise.
	(add_locale_uint32): Likewise.
	(add_locale_uint32_array): Likewise.
	(add_locale_char): Likewise.
	(start_locale_structure): Likewise.
	(end_locale_structure): Likewise.
	(start_locale_prelude): Likewise.
	(end_locale_prelude): Likewise.
	(write_locale_data): Take locale_file structure rather than an
	iovec.
	* locale/programs/locfile.h: Include "obstack.h".
	(struct locale_file): Change to store locale file contents instead
	of header.
	(init_locale_data): New prototype.
	(align_locale_data): Likewise.
	(add_locale_empty): Likewise.
	(add_locale_raw_data): Likewise.
	(add_locale_raw_obstack): Likewise.
	(add_locale_string): Likewise.
	(add_locale_wstring): Likewise.
	(add_locale_uint32): Likewise.
	(add_locale_uint32_array): Likewise.
	(add_locale_char): Likewise.
	(start_locale_structure): Likewise.
	(end_locale_structure): Likewise.
	(start_locale_prelude): Likewise.
	(end_locale_prelude): Likewise.
	(write_locale_data): Update prototype.
	* locale/programs/3level.h (struct TABLE): Remove result field.
	(CONCAT(TABLE,_finalize)): Change to CONCAT(add_locale_,TABLE).
	Use new locale_file interface.
	[!NO_FINALIZE]: Change condition to [!NO_ADD_LOCALE].
	(NO_FINALIZE): Change #undef to #undef of NO_ADD_LOCALE.
	* locale/programs/ld-address.c (address_output): Use new
	locale_file interface.
	* locale/programs/ld-collate.c (NO_FINALIZE): Change to
	NO_ADD_LOCALE.
	(collate_finish): Don't call collseq_table_finalize.
	(collate_output): Use new locale_file interface.
	* locale/programs/ld-ctype.c: Move includes of "3level.h" earlier
	in file.
	(NO_FINALIZE): Change to NO_ADD_LOCALE.
	(TABLE): Move defines earlier in file.
	(ELEMENT): Likewise.
	(DEFAULT): Likewise.
	(wctrans_table_add): Move macro and inline function earlier in
	file.
	(struct wctype_table): Move type earlier in file.
	(add_locale_wctype_table): New static prototype.
	(struct locale_ctype_t): Use logical types instead of struct iovec
	pointers for members.
	(ctype_output): Use new locale_file interface.
	(wctype_table_finalize): Change to add_locale_wctype_table.  Use
	new locale_file interface.
	(allocate_arrays): Update for use of new locale_file interface.
	* locale/programs/ld-identification.c (identification_output): Use
	new locale_file interface.
	* locale/programs/ld-measurement.c (measurement_output): Likewise.
	* locale/programs/ld-messages.c (messages_output): Likewise.
	* locale/programs/ld-monetary.c (monetary_output): Likewise.
	* locale/programs/ld-name.c (name_output): Likewise.
	* locale/programs/ld-numeric.c (numeric_output): Likewise.
	* locale/programs/ld-paper.c (paper_output): Likewise.
	* locale/programs/ld-telephone.c (telephone_output): Likewise.
	* locale/programs/ld-time.c (time_output): Likewise.

diff --git a/locale/programs/3level.h b/locale/programs/3level.h
index 9b8b1b9..b8d6ca0 100644
--- a/locale/programs/3level.h
+++ b/locale/programs/3level.h
@@ -26,7 +26,8 @@
      ELEMENT      to the type of every entry
      DEFAULT      to the default value for empty entries
      ITERATE      if you want the TABLE_iterate function to be defined
-     NO_FINALIZE  if you don't want the TABLE_finalize function to be defined
+     NO_ADD_LOCALE  if you don't want the add_locale_TABLE function
+		    to be defined
 
    This will define
 
@@ -36,7 +37,7 @@
      void TABLE_add (struct TABLE *t, uint32_t wc, ELEMENT value);
      void TABLE_iterate (struct TABLE *t,
 			 void (*fn) (uint32_t wc, ELEMENT value));
-     void TABLE_finalize (struct TABLE *t);
+     void add_locale_TABLE (struct locale_file *file, struct TABLE *t);
 */
 
 #define CONCAT(a,b) CONCAT1(a,b)
@@ -57,9 +58,8 @@ struct TABLE
   size_t level3_alloc;
   size_t level3_size;
   ELEMENT *level3;
-  /* Compressed representation.  */
+  /* Size of compressed representation.  */
   size_t result_size;
-  char *result;
 };
 
 /* Initialize.  Assumes t->p and t->q have already been set.  */
@@ -206,15 +206,15 @@ CONCAT(TABLE,_iterate) (struct TABLE *t,
 }
 #endif
 
-#ifndef NO_FINALIZE
+#ifndef NO_ADD_LOCALE
 /* Finalize and shrink.  */
 static void
-CONCAT(TABLE,_finalize) (struct TABLE *t)
+CONCAT(add_locale_,TABLE) (struct locale_file *file, struct TABLE *t)
 {
   size_t i, j, k;
   uint32_t reorder3[t->level3_size];
   uint32_t reorder2[t->level2_size];
-  uint32_t level1_offset, level2_offset, level3_offset, last_offset;
+  uint32_t level2_offset, level3_offset, last_offset;
 
   /* Uniquify level3 blocks.  */
   k = 0;
@@ -271,10 +271,7 @@ CONCAT(TABLE,_finalize) (struct TABLE *t)
     + (t->level2_size << t->q) * sizeof (uint32_t)
     + (t->level3_size << t->p) * sizeof (ELEMENT);
   t->result_size = (last_offset + 3) & ~3ul;
-  t->result = (char *) xmalloc (t->result_size);
 
-  level1_offset =
-    5 * sizeof (uint32_t);
   level2_offset =
     5 * sizeof (uint32_t)
     + t->level1_size * sizeof (uint32_t);
@@ -283,29 +280,36 @@ CONCAT(TABLE,_finalize) (struct TABLE *t)
     + t->level1_size * sizeof (uint32_t)
     + (t->level2_size << t->q) * sizeof (uint32_t);
 
-  ((uint32_t *) t->result)[0] = t->q + t->p;
-  ((uint32_t *) t->result)[1] = t->level1_size;
-  ((uint32_t *) t->result)[2] = t->p;
-  ((uint32_t *) t->result)[3] = (1 << t->q) - 1;
-  ((uint32_t *) t->result)[4] = (1 << t->p) - 1;
+  start_locale_structure (file);
+  add_locale_uint32 (file, t->q + t->p);
+  add_locale_uint32 (file, t->level1_size);
+  add_locale_uint32 (file, t->p);
+  add_locale_uint32 (file, (1 << t->q) - 1);
+  add_locale_uint32 (file, (1 << t->p) - 1);
 
   for (i = 0; i < t->level1_size; i++)
-    ((uint32_t *) (t->result + level1_offset))[i] =
-      (t->level1[i] == EMPTY
+    add_locale_uint32
+      (file,
+       t->level1[i] == EMPTY
        ? 0
        : (t->level1[i] << t->q) * sizeof (uint32_t) + level2_offset);
 
   for (i = 0; i < (t->level2_size << t->q); i++)
-    ((uint32_t *) (t->result + level2_offset))[i] =
-      (t->level2[i] == EMPTY
+    add_locale_uint32
+      (file,
+       t->level2[i] == EMPTY
        ? 0
        : (t->level2[i] << t->p) * sizeof (ELEMENT) + level3_offset);
 
-  for (i = 0; i < (t->level3_size << t->p); i++)
-    ((ELEMENT *) (t->result + level3_offset))[i] = t->level3[i];
-
-  if (last_offset < t->result_size)
-    memset (t->result + last_offset, 0, t->result_size - last_offset);
+  if (sizeof (ELEMENT) == 1)
+    add_locale_raw_data (file, t->level3, t->level3_size << t->p);
+  else if (sizeof (ELEMENT) == sizeof (uint32_t))
+    add_locale_uint32_array (file, (uint32_t *) t->level3,
+			     t->level3_size << t->p);
+  else
+    abort ();
+  align_locale_data (file, 4);
+  end_locale_structure (file);
 
   if (t->level1_alloc > 0)
     free (t->level1);
@@ -321,4 +325,4 @@ CONCAT(TABLE,_finalize) (struct TABLE *t)
 #undef ELEMENT
 #undef DEFAULT
 #undef ITERATE
-#undef NO_FINALIZE
+#undef NO_ADD_LOCALE
diff --git a/locale/programs/ld-address.c b/locale/programs/ld-address.c
index 39b9a83..291e7b7 100644
--- a/locale/programs/ld-address.c
+++ b/locale/programs/ld-address.c
@@ -349,97 +349,23 @@ address_output (struct localedef_t *locale, const struct charmap_t *charmap,
 		const char *output_path)
 {
   struct locale_address_t *address = locale->categories[LC_ADDRESS].address;
-  struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS)];
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS)];
-  size_t cnt = 0;
-
-  data.magic = LIMAGIC (LC_ADDRESS);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS);
-  iov[cnt].iov_base = (void *) &data;
-  iov[cnt].iov_len = sizeof (data);
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) idx;
-  iov[cnt].iov_len = sizeof (idx);
-  ++cnt;
-
-  idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
-  iov[cnt].iov_base = (void *) address->postal_fmt;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->country_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->country_post;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->country_ab2;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->country_ab3;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->country_car;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-
-  /* Align following data */
-  iov[cnt].iov_base = (void *) "\0\0";
-  iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
-  idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) &address->country_num;
-  iov[cnt].iov_len = sizeof (uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->country_isbn;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->lang_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->lang_ab;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->lang_term;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) address->lang_lib;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) charmap->code_set_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS));
-
-  write_locale_data (output_path, LC_ADDRESS, "LC_ADDRESS",
-		     3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS), iov);
+  struct locale_file file;
+
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS));
+  add_locale_string (&file, address->postal_fmt);
+  add_locale_string (&file, address->country_name);
+  add_locale_string (&file, address->country_post);
+  add_locale_string (&file, address->country_ab2);
+  add_locale_string (&file, address->country_ab3);
+  add_locale_string (&file, address->country_car);
+  add_locale_uint32 (&file, address->country_num);
+  add_locale_string (&file, address->country_isbn);
+  add_locale_string (&file, address->lang_name);
+  add_locale_string (&file, address->lang_ab);
+  add_locale_string (&file, address->lang_term);
+  add_locale_string (&file, address->lang_lib);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_ADDRESS, "LC_ADDRESS", &file);
 }
 
 
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c
index e58c8f7..c4d7e3d 100644
--- a/locale/programs/ld-collate.c
+++ b/locale/programs/ld-collate.c
@@ -165,7 +165,7 @@ struct symbol_t
 #define ELEMENT struct element_t *
 #define DEFAULT NULL
 #define ITERATE
-#define NO_FINALIZE
+#define NO_ADD_LOCALE
 #include "3level.h"
 
 /* Sparse table of int32_t.  */
@@ -1813,8 +1813,6 @@ symbol `%s' has the same encoding as"), (*eptr)->name);
       runp = runp->next;
     }
 
-  collseq_table_finalize (&collate->wcseqorder);
-
   /* Now determine whether the UNDEFINED entry is needed and if yes,
      whether it was defined.  */
   collate->undefined.used_in_level = need_undefined ? ~0ul : 0;
@@ -2098,10 +2096,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
 {
   struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
   const size_t nelems = _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE);
-  struct iovec iov[2 + nelems];
-  struct locale_file data;
-  uint32_t idx[nelems];
-  size_t cnt;
+  struct locale_file file;
   size_t ch;
   int32_t tablemb[256];
   struct obstack weightpool;
@@ -2114,51 +2109,22 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
   int i;
   struct element_t *runp;
 
-  data.magic = LIMAGIC (LC_COLLATE);
-  data.n = nelems;
-  iov[0].iov_base = (void *) &data;
-  iov[0].iov_len = sizeof (data);
-
-  iov[1].iov_base = (void *) idx;
-  iov[1].iov_len = sizeof (idx);
-
-  idx[0] = iov[0].iov_len + iov[1].iov_len;
-  cnt = 0;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_NRULES));
-  iov[2 + cnt].iov_base = &nrules;
-  iov[2 + cnt].iov_len = sizeof (uint32_t);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  ++cnt;
+  init_locale_data (&file, nelems);
+  add_locale_uint32 (&file, nrules);
 
   /* If we have no LC_COLLATE data emit only the number of rules as zero.  */
   if (collate == NULL)
     {
-      int32_t dummy = 0;
-
-      while (cnt < _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE))
+      size_t idx;
+      for (idx = 1; idx < nelems; idx++)
 	{
 	  /* The words have to be handled specially.  */
-	  if (cnt == _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_SIZEMB))
-	    {
-	      iov[2 + cnt].iov_base = &dummy;
-	      iov[2 + cnt].iov_len = sizeof (int32_t);
-	    }
+	  if (idx == _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_SIZEMB))
+	    add_locale_uint32 (&file, 0);
 	  else
-	    {
-	      iov[2 + cnt].iov_base = NULL;
-	      iov[2 + cnt].iov_len = 0;
-	    }
-
-	  if (cnt + 1 < _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE))
-	    idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-	  ++cnt;
+	    add_locale_empty (&file);
 	}
-
-      assert (cnt == _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE));
-
-      write_locale_data (output_path, LC_COLLATE, "LC_COLLATE", 2 + cnt, iov);
-
+      write_locale_data (output_path, LC_COLLATE, "LC_COLLATE", &file);
       return;
     }
 
@@ -2191,11 +2157,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
       obstack_1grow (&weightpool, '\0');
     while (++i < __alignof__ (int32_t));
 
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_RULESETS));
-  iov[2 + cnt].iov_len = obstack_object_size (&weightpool);
-  iov[2 + cnt].iov_base = obstack_finish (&weightpool);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  ++cnt;
+  add_locale_raw_obstack (&file, &weightpool);
 
   /* Generate the 8-bit table.  Walk through the lists of sequences
      starting with the same byte and add them one after the other to
@@ -2382,55 +2344,16 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
     obstack_1grow (&weightpool, 0);
 
   /* Now add the four tables.  */
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_TABLEMB));
-  iov[2 + cnt].iov_base = tablemb;
-  iov[2 + cnt].iov_len = sizeof (tablemb);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert ((iov[2 + cnt].iov_len & (__alignof__ (int32_t) - 1)) == 0);
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_WEIGHTMB));
-  iov[2 + cnt].iov_len = obstack_object_size (&weightpool);
-  iov[2 + cnt].iov_base = obstack_finish (&weightpool);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_EXTRAMB));
-  iov[2 + cnt].iov_len = obstack_object_size (&extrapool);
-  iov[2 + cnt].iov_base = obstack_finish (&extrapool);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_INDIRECTMB));
-  iov[2 + cnt].iov_len = obstack_object_size (&indirectpool);
-  iov[2 + cnt].iov_base = obstack_finish (&indirectpool);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert ((iov[2 + cnt].iov_len & (__alignof__ (int32_t) - 1)) == 0);
-  ++cnt;
-
+  add_locale_uint32_array (&file, (const uint32_t *) tablemb, 256);
+  add_locale_raw_obstack (&file, &weightpool);
+  add_locale_raw_obstack (&file, &extrapool);
+  add_locale_raw_obstack (&file, &indirectpool);
 
   /* Now the same for the wide character table.  We need to store some
      more information here.  */
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_GAP1));
-  iov[2 + cnt].iov_base = NULL;
-  iov[2 + cnt].iov_len = 0;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_GAP2));
-  iov[2 + cnt].iov_base = NULL;
-  iov[2 + cnt].iov_len = 0;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_GAP3));
-  iov[2 + cnt].iov_base = NULL;
-  iov[2 + cnt].iov_len = 0;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
+  add_locale_empty (&file);
+  add_locale_empty (&file);
+  add_locale_empty (&file);
 
   /* Since we are using the sign of an integer to mark indirection the
      offsets in the arrays we are indirectly referring to must not be
@@ -2462,41 +2385,11 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
 
   memset (&atwc, 0, sizeof (atwc));
 
-  collidx_table_finalize (&tablewc);
-
   /* Now add the four tables.  */
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_TABLEWC));
-  iov[2 + cnt].iov_base = tablewc.result;
-  iov[2 + cnt].iov_len = tablewc.result_size;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (iov[2 + cnt].iov_len % sizeof (int32_t) == 0);
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_WEIGHTWC));
-  iov[2 + cnt].iov_len = obstack_object_size (&weightpool);
-  iov[2 + cnt].iov_base = obstack_finish (&weightpool);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (iov[2 + cnt].iov_len % sizeof (int32_t) == 0);
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_EXTRAWC));
-  iov[2 + cnt].iov_len = obstack_object_size (&extrapool);
-  iov[2 + cnt].iov_base = obstack_finish (&extrapool);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (iov[2 + cnt].iov_len % sizeof (int32_t) == 0);
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_INDIRECTWC));
-  iov[2 + cnt].iov_len = obstack_object_size (&indirectpool);
-  iov[2 + cnt].iov_base = obstack_finish (&indirectpool);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (iov[2 + cnt].iov_len % sizeof (int32_t) == 0);
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
-
+  add_locale_collidx_table (&file, &tablewc);
+  add_locale_raw_obstack (&file, &weightpool);
+  add_locale_raw_obstack (&file, &extrapool);
+  add_locale_raw_obstack (&file, &indirectpool);
 
   /* Finally write the table with collation element names out.  It is
      a hash table with a simple function which gets the name of the
@@ -2594,47 +2487,13 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
     }
 
   /* Prepare to write out this data.  */
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_SIZEMB));
-  iov[2 + cnt].iov_base = &elem_size;
-  iov[2 + cnt].iov_len = sizeof (int32_t);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_SYMB_TABLEMB));
-  iov[2 + cnt].iov_base = elem_table;
-  iov[2 + cnt].iov_len = elem_size * 2 * sizeof (int32_t);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_SYMB_EXTRAMB));
-  iov[2 + cnt].iov_len = obstack_object_size (&extrapool);
-  iov[2 + cnt].iov_base = obstack_finish (&extrapool);
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_COLLSEQMB));
-  iov[2 + cnt].iov_base = collate->mbseqorder;
-  iov[2 + cnt].iov_len = 256;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_COLLSEQWC));
-  iov[2 + cnt].iov_base = collate->wcseqorder.result;
-  iov[2 + cnt].iov_len = collate->wcseqorder.result_size;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  assert (idx[cnt] % __alignof__ (int32_t) == 0);
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_COLLATE_CODESET));
-  iov[2 + cnt].iov_base = (void *) charmap->code_set_name;
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  ++cnt;
-
-  assert (cnt == _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE));
-
-  write_locale_data (output_path, LC_COLLATE, "LC_COLLATE", 2 + cnt, iov);
+  add_locale_uint32 (&file, elem_size);
+  add_locale_uint32_array (&file, elem_table, 2 * elem_size);
+  add_locale_raw_obstack (&file, &extrapool);
+  add_locale_raw_data (&file, collate->mbseqorder, 256);
+  add_locale_collseq_table (&file, &collate->wcseqorder);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_COLLATE, "LC_COLLATE", &file);
 
   obstack_free (&weightpool, NULL);
   obstack_free (&extrapool, NULL);
diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c
index 8be7fce..3903ee0 100644
--- a/locale/programs/ld-ctype.c
+++ b/locale/programs/ld-ctype.c
@@ -119,9 +119,51 @@ struct translit_include_t
 #define TABLE idx_table
 #define ELEMENT uint32_t
 #define DEFAULT ((uint32_t) ~0)
-#define NO_FINALIZE
+#define NO_ADD_LOCALE
 #include "3level.h"
 
+#define TABLE wcwidth_table
+#define ELEMENT uint8_t
+#define DEFAULT 0xff
+#include "3level.h"
+
+#define TABLE wctrans_table
+#define ELEMENT int32_t
+#define DEFAULT 0
+#define wctrans_table_add wctrans_table_add_internal
+#include "3level.h"
+#undef wctrans_table_add
+/* The wctrans_table must actually store the difference between the
+   desired result and the argument.  */
+static inline void
+wctrans_table_add (struct wctrans_table *t, uint32_t wc, uint32_t mapped_wc)
+{
+  wctrans_table_add_internal (t, wc, mapped_wc - wc);
+}
+
+/* Construction of sparse 3-level tables.
+   See wchar-lookup.h for their structure and the meaning of p and q.  */
+
+struct wctype_table
+{
+  /* Parameters.  */
+  unsigned int p;
+  unsigned int q;
+  /* Working representation.  */
+  size_t level1_alloc;
+  size_t level1_size;
+  uint32_t *level1;
+  size_t level2_alloc;
+  size_t level2_size;
+  uint32_t *level2;
+  size_t level3_alloc;
+  size_t level3_size;
+  uint32_t *level3;
+  size_t result_size;
+};
+
+static void add_locale_wctype_table (struct locale_file *file,
+				     struct wctype_table *t);
 
 /* The real definition of the struct for the LC_CTYPE locale.  */
 struct locale_ctype_t
@@ -189,11 +231,11 @@ struct locale_ctype_t
   uint32_t **map_b;
   uint32_t **map32_b;
   uint32_t **class_b;
-  struct iovec *class_3level;
-  struct iovec *map_3level;
+  struct wctype_table *class_3level;
+  struct wctrans_table *map_3level;
   uint32_t *class_name_ptr;
   uint32_t *map_name_ptr;
-  struct iovec width;
+  struct wcwidth_table width;
   uint32_t mb_cur_max;
   const char *codeset_name;
   uint32_t *translit_from_idx;
@@ -905,33 +947,21 @@ void
 ctype_output (struct localedef_t *locale, const struct charmap_t *charmap,
 	      const char *output_path)
 {
-  static const char nulbytes[4] = { 0, 0, 0, 0 };
   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
   const size_t nelems = (_NL_ITEM_INDEX (_NL_CTYPE_EXTRA_MAP_1)
 			 + ctype->nr_charclass + ctype->map_collection_nr);
-  struct iovec *iov = alloca (sizeof *iov
-			      * (2 + nelems + 2 * ctype->nr_charclass
-				 + ctype->map_collection_nr + 4));
-  struct locale_file data;
-  uint32_t *idx = alloca (sizeof *idx * (nelems + 1));
+  struct locale_file file;
   uint32_t default_missing_len;
-  size_t elem, cnt, offset, total;
-  char *cp;
+  size_t elem, cnt;
 
   /* Now prepare the output: Find the sizes of the table we can use.  */
   allocate_arrays (ctype, charmap, ctype->repertoire);
 
-  data.magic = LIMAGIC (LC_CTYPE);
-  data.n = nelems;
-  iov[0].iov_base = (void *) &data;
-  iov[0].iov_len = sizeof (data);
-
-  iov[1].iov_base = (void *) idx;
-  iov[1].iov_len = nelems * sizeof (uint32_t);
-
-  idx[0] = iov[0].iov_len + iov[1].iov_len;
-  offset = 0;
+  default_missing_len = (ctype->default_missing
+			 ? wcslen ((wchar_t *) ctype->default_missing)
+			 : 0);
 
+  init_locale_data (&file, nelems);
   for (elem = 0; elem < nelems; ++elem)
     {
       if (elem < _NL_ITEM_INDEX (_NL_CTYPE_EXTRA_MAP_1))
@@ -939,9 +969,7 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap,
 	  {
 #define CTYPE_EMPTY(name) \
 	  case name:							      \
-	    iov[2 + elem + offset].iov_base = NULL;			      \
-	    iov[2 + elem + offset].iov_len = 0;				      \
-	    idx[elem + 1] = idx[elem];					      \
+	    add_locale_empty (&file);					      \
 	    break
 
 	  CTYPE_EMPTY(_NL_CTYPE_GAP1);
@@ -951,273 +979,156 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap,
 	  CTYPE_EMPTY(_NL_CTYPE_GAP5);
 	  CTYPE_EMPTY(_NL_CTYPE_GAP6);
 
-#define CTYPE_DATA(name, base, len)					      \
+#define CTYPE_RAW_DATA(name, base, size)				      \
 	  case _NL_ITEM_INDEX (name):					      \
-	    iov[2 + elem + offset].iov_base = (base);			      \
-	    iov[2 + elem + offset].iov_len = (len);			      \
-	    idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;	      \
+	    add_locale_raw_data (&file, base, size);			      \
 	    break
 
-	  CTYPE_DATA (_NL_CTYPE_CLASS,
-		      ctype->ctype_b,
-		      (256 + 128) * sizeof (char_class_t));
+	  CTYPE_RAW_DATA (_NL_CTYPE_CLASS,
+			  ctype->ctype_b,
+			  (256 + 128) * sizeof (char_class_t));
 
-	  CTYPE_DATA (_NL_CTYPE_TOUPPER,
-		      ctype->map_b[0],
-		      (256 + 128) * sizeof (uint32_t));
-	  CTYPE_DATA (_NL_CTYPE_TOLOWER,
-		      ctype->map_b[1],
-		      (256 + 128) * sizeof (uint32_t));
-
-	  CTYPE_DATA (_NL_CTYPE_TOUPPER32,
-		      ctype->map32_b[0],
-		      256 * sizeof (uint32_t));
-	  CTYPE_DATA (_NL_CTYPE_TOLOWER32,
-		      ctype->map32_b[1],
-		      256 * sizeof (uint32_t));
-
-	  CTYPE_DATA (_NL_CTYPE_CLASS32,
-		      ctype->ctype32_b,
-		      256 * sizeof (char_class32_t));
+#define CTYPE_UINT32_ARRAY(name, base, n_elems)				      \
+	  case _NL_ITEM_INDEX (name):					      \
+	    add_locale_uint32_array (&file, base, n_elems);		      \
+	    break
 
-	  CTYPE_DATA (_NL_CTYPE_CLASS_OFFSET,
-		      &ctype->class_offset, sizeof (uint32_t));
+	  CTYPE_UINT32_ARRAY (_NL_CTYPE_TOUPPER, ctype->map_b[0], 256 + 128);
+	  CTYPE_UINT32_ARRAY (_NL_CTYPE_TOLOWER, ctype->map_b[1], 256 + 128);
+	  CTYPE_UINT32_ARRAY (_NL_CTYPE_TOUPPER32, ctype->map32_b[0], 256);
+	  CTYPE_UINT32_ARRAY (_NL_CTYPE_TOLOWER32, ctype->map32_b[1], 256);
+	  CTYPE_RAW_DATA (_NL_CTYPE_CLASS32,
+			  ctype->ctype32_b,
+			  256 * sizeof (char_class32_t));
 
-	  CTYPE_DATA (_NL_CTYPE_MAP_OFFSET,
-		      &ctype->map_offset, sizeof (uint32_t));
+#define CTYPE_UINT32(name, value)					      \
+	  case _NL_ITEM_INDEX (name):					      \
+	    add_locale_uint32 (&file, value);				      \
+	    break
 
-	  CTYPE_DATA (_NL_CTYPE_TRANSLIT_TAB_SIZE,
-		      &ctype->translit_idx_size, sizeof (uint32_t));
+	  CTYPE_UINT32 (_NL_CTYPE_CLASS_OFFSET, ctype->class_offset);
+	  CTYPE_UINT32 (_NL_CTYPE_MAP_OFFSET, ctype->map_offset);
+	  CTYPE_UINT32 (_NL_CTYPE_TRANSLIT_TAB_SIZE, ctype->translit_idx_size);
 
-	  CTYPE_DATA (_NL_CTYPE_TRANSLIT_FROM_IDX,
-		      ctype->translit_from_idx,
-		      ctype->translit_idx_size * sizeof (uint32_t));
+	  CTYPE_UINT32_ARRAY (_NL_CTYPE_TRANSLIT_FROM_IDX,
+			      ctype->translit_from_idx,
+			      ctype->translit_idx_size);
 
-	  CTYPE_DATA (_NL_CTYPE_TRANSLIT_FROM_TBL,
-		      ctype->translit_from_tbl,
-		      ctype->translit_from_tbl_size);
+	  CTYPE_UINT32_ARRAY (_NL_CTYPE_TRANSLIT_FROM_TBL,
+			      ctype->translit_from_tbl,
+			      ctype->translit_from_tbl_size
+			      / sizeof (uint32_t));
 
-	  CTYPE_DATA (_NL_CTYPE_TRANSLIT_TO_IDX,
-		      ctype->translit_to_idx,
-		      ctype->translit_idx_size * sizeof (uint32_t));
+	  CTYPE_UINT32_ARRAY (_NL_CTYPE_TRANSLIT_TO_IDX,
+			      ctype->translit_to_idx,
+			      ctype->translit_idx_size);
 
-	  CTYPE_DATA (_NL_CTYPE_TRANSLIT_TO_TBL,
-		      ctype->translit_to_tbl, ctype->translit_to_tbl_size);
+	  CTYPE_UINT32_ARRAY (_NL_CTYPE_TRANSLIT_TO_TBL,
+			      ctype->translit_to_tbl,
+			      ctype->translit_to_tbl_size / sizeof (uint32_t));
 
 	  case _NL_ITEM_INDEX (_NL_CTYPE_CLASS_NAMES):
 	    /* The class name array.  */
-	    total = 0;
-	    for (cnt = 0; cnt < ctype->nr_charclass; ++cnt, ++offset)
-	      {
-		iov[2 + elem + offset].iov_base
-		  = (void *) ctype->classnames[cnt];
-		iov[2 + elem + offset].iov_len
-		  = strlen (ctype->classnames[cnt]) + 1;
-		total += iov[2 + elem + offset].iov_len;
-	      }
-	    iov[2 + elem + offset].iov_base = (void *) nulbytes;
-	    iov[2 + elem + offset].iov_len = 4 - (total % 4);
-	    total += 4 - (total % 4);
-
-	    idx[elem + 1] = idx[elem] + total;
+	    start_locale_structure (&file);
+	    for (cnt = 0; cnt < ctype->nr_charclass; ++cnt)
+	      add_locale_string (&file, ctype->classnames[cnt]);
+	    add_locale_char (&file, 0);
+	    align_locale_data (&file, 4);
+	    end_locale_structure (&file);
 	    break;
 
 	  case _NL_ITEM_INDEX (_NL_CTYPE_MAP_NAMES):
 	    /* The class name array.  */
-	    total = 0;
-	    for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt, ++offset)
-	      {
-		iov[2 + elem + offset].iov_base
-		  = (void *) ctype->mapnames[cnt];
-		iov[2 + elem + offset].iov_len
-		  = strlen (ctype->mapnames[cnt]) + 1;
-		total += iov[2 + elem + offset].iov_len;
-	      }
-	    iov[2 + elem + offset].iov_base = (void *) nulbytes;
-	    iov[2 + elem + offset].iov_len = 4 - (total % 4);
-	    total += 4 - (total % 4);
-
-	    idx[elem + 1] = idx[elem] + total;
+	    start_locale_structure (&file);
+	    for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
+	      add_locale_string (&file, ctype->mapnames[cnt]);
+	    add_locale_char (&file, 0);
+	    align_locale_data (&file, 4);
+	    end_locale_structure (&file);
 	    break;
 
-	  CTYPE_DATA (_NL_CTYPE_WIDTH,
-		      ctype->width.iov_base,
-		      ctype->width.iov_len);
+	  case _NL_ITEM_INDEX (_NL_CTYPE_WIDTH):
+	    add_locale_wcwidth_table (&file, &ctype->width);
+	    break;
 
-	  CTYPE_DATA (_NL_CTYPE_MB_CUR_MAX,
-		      &ctype->mb_cur_max, sizeof (uint32_t));
+	  CTYPE_UINT32 (_NL_CTYPE_MB_CUR_MAX, ctype->mb_cur_max);
 
 	  case _NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME):
-	    total = strlen (ctype->codeset_name) + 1;
-	    if (total % 4 == 0)
-	      iov[2 + elem + offset].iov_base = (char *) ctype->codeset_name;
-	    else
-	      {
-		iov[2 + elem + offset].iov_base = alloca ((total + 3) & ~3);
-		memset (mempcpy (iov[2 + elem + offset].iov_base,
-				 ctype->codeset_name, total),
-			'\0', 4 - (total & 3));
-		total = (total + 3) & ~3;
-	      }
-	    iov[2 + elem + offset].iov_len = total;
-	    idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+	    add_locale_string (&file, ctype->codeset_name);
 	    break;
 
+	  CTYPE_UINT32 (_NL_CTYPE_MAP_TO_NONASCII, ctype->to_nonascii);
 
-	  CTYPE_DATA (_NL_CTYPE_MAP_TO_NONASCII,
-		      &ctype->to_nonascii, sizeof (uint32_t));
-
-	  CTYPE_DATA (_NL_CTYPE_NONASCII_CASE,
-		      &ctype->nonascii_case, sizeof (uint32_t));
+	  CTYPE_UINT32 (_NL_CTYPE_NONASCII_CASE, ctype->nonascii_case);
 
 	  case _NL_ITEM_INDEX (_NL_CTYPE_INDIGITS_MB_LEN):
-	    iov[2 + elem + offset].iov_base = alloca (sizeof (uint32_t));
-	    iov[2 + elem + offset].iov_len = sizeof (uint32_t);
-	    *(uint32_t *) iov[2 + elem + offset].iov_base =
-	      ctype->mbdigits_act / 10;
-	    idx[elem + 1] = idx[elem] + sizeof (uint32_t);
+	    add_locale_uint32 (&file, ctype->mbdigits_act / 10);
 	    break;
 
 	  case _NL_ITEM_INDEX (_NL_CTYPE_INDIGITS_WC_LEN):
-	    /* Align entries.  */
-	    iov[2 + elem + offset].iov_base = (void *) nulbytes;
-	    iov[2 + elem + offset].iov_len = (4 - idx[elem] % 4) % 4;
-	    idx[elem] += iov[2 + elem + offset].iov_len;
-	    ++offset;
-
-	    iov[2 + elem + offset].iov_base = alloca (sizeof (uint32_t));
-	    iov[2 + elem + offset].iov_len = sizeof (uint32_t);
-	    *(uint32_t *) iov[2 + elem + offset].iov_base =
-	      ctype->wcdigits_act / 10;
-	    idx[elem + 1] = idx[elem] + sizeof (uint32_t);
+	    add_locale_uint32 (&file, ctype->wcdigits_act / 10);
 	    break;
 
 	  case _NL_ITEM_INDEX (_NL_CTYPE_INDIGITS0_MB) ... _NL_ITEM_INDEX (_NL_CTYPE_INDIGITS9_MB):
-	    /* Compute the length of all possible characters.  For INDIGITS
-	       there might be more than one.  We simply concatenate all of
-	       them with a NUL byte following.  The NUL byte wouldn't be
-	       necessary but it makes it easier for the user.  */
-	    total = 0;
-
-	    for (cnt = elem - _NL_ITEM_INDEX (_NL_CTYPE_INDIGITS0_MB);
-		 cnt < ctype->mbdigits_act; cnt += 10)
-	      total += ctype->mbdigits[cnt]->nbytes + 1;
-	    iov[2 + elem + offset].iov_base = (char *) alloca (total);
-	    iov[2 + elem + offset].iov_len = total;
-
-	    cp = iov[2 + elem + offset].iov_base;
+	    start_locale_structure (&file);
 	    for (cnt = elem - _NL_ITEM_INDEX (_NL_CTYPE_INDIGITS0_MB);
 		 cnt < ctype->mbdigits_act; cnt += 10)
 	      {
-		cp = mempcpy (cp, ctype->mbdigits[cnt]->bytes,
-			      ctype->mbdigits[cnt]->nbytes);
-		*cp++ = '\0';
+		add_locale_raw_data (&file, ctype->mbdigits[cnt]->bytes,
+				     ctype->mbdigits[cnt]->nbytes);
+		add_locale_char (&file, 0);
 	      }
-	    idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+	    end_locale_structure (&file);
 	    break;
 
 	  case _NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT0_MB) ... _NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT9_MB):
-	    /* Compute the length of all possible characters.  For INDIGITS
-	       there might be more than one.  We simply concatenate all of
-	       them with a NUL byte following.  The NUL byte wouldn't be
-	       necessary but it makes it easier for the user.  */
+	    start_locale_structure (&file);
 	    cnt = elem - _NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT0_MB);
-	    total = ctype->mboutdigits[cnt]->nbytes + 1;
-	    iov[2 + elem + offset].iov_base = (char *) alloca (total);
-	    iov[2 + elem + offset].iov_len = total;
-
-	    *(char *) mempcpy (iov[2 + elem + offset].iov_base,
-			       ctype->mboutdigits[cnt]->bytes,
-			       ctype->mboutdigits[cnt]->nbytes) = '\0';
-	    idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+	    add_locale_raw_data (&file, ctype->mboutdigits[cnt]->bytes,
+				 ctype->mboutdigits[cnt]->nbytes);
+	    add_locale_char (&file, 0);
+	    end_locale_structure (&file);
 	    break;
 
 	  case _NL_ITEM_INDEX (_NL_CTYPE_INDIGITS0_WC) ... _NL_ITEM_INDEX (_NL_CTYPE_INDIGITS9_WC):
-	    total = ctype->wcdigits_act / 10;
-
-	    iov[2 + elem + offset].iov_base =
-	      (uint32_t *) alloca (total * sizeof (uint32_t));
-	    iov[2 + elem + offset].iov_len = total * sizeof (uint32_t);
-
+	    start_locale_structure (&file);
 	    for (cnt = elem - _NL_ITEM_INDEX (_NL_CTYPE_INDIGITS0_WC);
 		 cnt < ctype->wcdigits_act; cnt += 10)
-	      ((uint32_t *) iov[2 + elem + offset].iov_base)[cnt / 10]
-		= ctype->wcdigits[cnt];
-	    idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+	      add_locale_uint32 (&file, ctype->wcdigits[cnt]);
+	    end_locale_structure (&file);
 	    break;
 
-	  case _NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT0_WC):
-	    /* Align entries.  */
-	    iov[2 + elem + offset].iov_base = (void *) nulbytes;
-	    iov[2 + elem + offset].iov_len = (4 - idx[elem] % 4) % 4;
-	    idx[elem] += iov[2 + elem + offset].iov_len;
-	    ++offset;
-	    /* FALLTRHOUGH */
-
-	  case _NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT1_WC) ... _NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT9_WC):
+	  case _NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT0_WC) ... _NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT9_WC):
 	    cnt = elem - _NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT0_WC);
-	    iov[2 + elem + offset].iov_base = &ctype->wcoutdigits[cnt];
-	    iov[2 + elem + offset].iov_len = sizeof (uint32_t);
-	    idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+	    add_locale_uint32 (&file, ctype->wcoutdigits[cnt]);
 	    break;
 
 	  case _NL_ITEM_INDEX(_NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN):
-	    /* Align entries.  */
-	    iov[2 + elem + offset].iov_base = (void *) nulbytes;
-	    iov[2 + elem + offset].iov_len = (4 - idx[elem] % 4) % 4;
-	    idx[elem] += iov[2 + elem + offset].iov_len;
-	    ++offset;
-
-	    default_missing_len = (ctype->default_missing
-				   ? wcslen ((wchar_t *)ctype->default_missing)
-				   : 0);
-	    iov[2 + elem + offset].iov_base = &default_missing_len;
-	    iov[2 + elem + offset].iov_len = sizeof (uint32_t);
-	    idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+	    add_locale_uint32 (&file, default_missing_len);
 	    break;
 
 	  case _NL_ITEM_INDEX(_NL_CTYPE_TRANSLIT_DEFAULT_MISSING):
-	    iov[2 + elem + offset].iov_base =
-	      ctype->default_missing ?: (uint32_t *) L"";
-	    iov[2 + elem + offset].iov_len =
-	      wcslen (iov[2 + elem + offset].iov_base) * sizeof (uint32_t);
-	    idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+	    add_locale_uint32_array (&file, ctype->default_missing,
+				     default_missing_len);
 	    break;
 
 	  case _NL_ITEM_INDEX(_NL_CTYPE_TRANSLIT_IGNORE_LEN):
-	    /* Align entries.  */
-	    iov[2 + elem + offset].iov_base = (void *) nulbytes;
-	    iov[2 + elem + offset].iov_len = (4 - idx[elem] % 4) % 4;
-	    idx[elem] += iov[2 + elem + offset].iov_len;
-	    ++offset;
-
-	    iov[2 + elem + offset].iov_base = &ctype->ntranslit_ignore;
-	    iov[2 + elem + offset].iov_len = sizeof (uint32_t);
-	    idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+	    add_locale_uint32 (&file, ctype->ntranslit_ignore);
 	    break;
 
 	  case _NL_ITEM_INDEX(_NL_CTYPE_TRANSLIT_IGNORE):
+	    start_locale_structure (&file);
 	    {
-	      uint32_t *ranges = (uint32_t *) alloca (ctype->ntranslit_ignore
-						      * 3 * sizeof (uint32_t));
 	      struct translit_ignore_t *runp;
-
-	      iov[2 + elem + offset].iov_base = ranges;
-	      iov[2 + elem + offset].iov_len = (ctype->ntranslit_ignore
-						* 3 * sizeof (uint32_t));
-
 	      for (runp = ctype->translit_ignore; runp != NULL;
 		   runp = runp->next)
 		{
-		  *ranges++ = runp->from;
-		  *ranges++ = runp->to;
-		  *ranges++ = runp->step;
+		  add_locale_uint32 (&file, runp->from);
+		  add_locale_uint32 (&file, runp->to);
+		  add_locale_uint32 (&file, runp->step);
 		}
 	    }
-	    /* Remove the following line in case a new entry is added
-	       after _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN.  */
-	    if (elem < nelems)
-	      idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+	    end_locale_structure (&file);
 	    break;
 
 	  default:
@@ -1229,28 +1140,21 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap,
 	  size_t nr = elem - _NL_ITEM_INDEX (_NL_CTYPE_EXTRA_MAP_1);
 	  if (nr < ctype->nr_charclass)
 	    {
-	      iov[2 + elem + offset].iov_base = ctype->class_b[nr];
-	      iov[2 + elem + offset].iov_len = 256 / 32 * sizeof (uint32_t);
-	      idx[elem] += iov[2 + elem + offset].iov_len;
-	      ++offset;
-
-	      iov[2 + elem + offset] = ctype->class_3level[nr];
+	      start_locale_prelude (&file);
+	      add_locale_uint32_array (&file, ctype->class_b[nr], 256 / 32);
+	      end_locale_prelude (&file);
+	      add_locale_wctype_table (&file, &ctype->class_3level[nr]);
 	    }
 	  else
 	    {
 	      nr -= ctype->nr_charclass;
 	      assert (nr < ctype->map_collection_nr);
-	      iov[2 + elem + offset] = ctype->map_3level[nr];
+	      add_locale_wctrans_table (&file, &ctype->map_3level[nr]);
 	    }
-	  idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
 	}
     }
 
-  assert (2 + elem + offset == (nelems + 2 * ctype->nr_charclass
-				+ ctype->map_collection_nr + 4 + 2));
-
-  write_locale_data (output_path, LC_CTYPE, "LC_CTYPE", 2 + elem + offset,
-		     iov);
+  write_locale_data (output_path, LC_CTYPE, "LC_CTYPE", &file);
 }
 
 
@@ -3529,29 +3433,6 @@ no output digits defined and none of the standard names in the charmap")));
 }
 
 
-/* Construction of sparse 3-level tables.
-   See wchar-lookup.h for their structure and the meaning of p and q.  */
-
-struct wctype_table
-{
-  /* Parameters.  */
-  unsigned int p;
-  unsigned int q;
-  /* Working representation.  */
-  size_t level1_alloc;
-  size_t level1_size;
-  uint32_t *level1;
-  size_t level2_alloc;
-  size_t level2_size;
-  uint32_t *level2;
-  size_t level3_alloc;
-  size_t level3_size;
-  uint32_t *level3;
-  /* Compressed representation.  */
-  size_t result_size;
-  char *result;
-};
-
 /* Initialize.  Assumes t->p and t->q have already been set.  */
 static inline void
 wctype_table_init (struct wctype_table *t)
@@ -3657,12 +3538,12 @@ wctype_table_add (struct wctype_table *t, uint32_t wc)
 
 /* Finalize and shrink.  */
 static void
-wctype_table_finalize (struct wctype_table *t)
+add_locale_wctype_table (struct locale_file *file, struct wctype_table *t)
 {
   size_t i, j, k;
   uint32_t reorder3[t->level3_size];
   uint32_t reorder2[t->level2_size];
-  uint32_t level1_offset, level2_offset, level3_offset;
+  uint32_t level2_offset, level3_offset;
 
   /* Uniquify level3 blocks.  */
   k = 0;
@@ -3712,16 +3593,12 @@ wctype_table_finalize (struct wctype_table *t)
     if (t->level1[i] != EMPTY)
       t->level1[i] = reorder2[t->level1[i]];
 
-  /* Create and fill the resulting compressed representation.  */
   t->result_size =
     5 * sizeof (uint32_t)
     + t->level1_size * sizeof (uint32_t)
     + (t->level2_size << t->q) * sizeof (uint32_t)
     + (t->level3_size << t->p) * sizeof (uint32_t);
-  t->result = (char *) xmalloc (t->result_size);
 
-  level1_offset =
-    5 * sizeof (uint32_t);
   level2_offset =
     5 * sizeof (uint32_t)
     + t->level1_size * sizeof (uint32_t);
@@ -3730,26 +3607,29 @@ wctype_table_finalize (struct wctype_table *t)
     + t->level1_size * sizeof (uint32_t)
     + (t->level2_size << t->q) * sizeof (uint32_t);
 
-  ((uint32_t *) t->result)[0] = t->q + t->p + 5;
-  ((uint32_t *) t->result)[1] = t->level1_size;
-  ((uint32_t *) t->result)[2] = t->p + 5;
-  ((uint32_t *) t->result)[3] = (1 << t->q) - 1;
-  ((uint32_t *) t->result)[4] = (1 << t->p) - 1;
+  start_locale_structure (file);
+  add_locale_uint32 (file, t->q + t->p + 5);
+  add_locale_uint32 (file, t->level1_size);
+  add_locale_uint32 (file, t->p + 5);
+  add_locale_uint32 (file, (1 << t->q) - 1);
+  add_locale_uint32 (file, (1 << t->p) - 1);
 
   for (i = 0; i < t->level1_size; i++)
-    ((uint32_t *) (t->result + level1_offset))[i] =
-      (t->level1[i] == EMPTY
+    add_locale_uint32
+      (file,
+       t->level1[i] == EMPTY
        ? 0
        : (t->level1[i] << t->q) * sizeof (uint32_t) + level2_offset);
 
   for (i = 0; i < (t->level2_size << t->q); i++)
-    ((uint32_t *) (t->result + level2_offset))[i] =
-      (t->level2[i] == EMPTY
+    add_locale_uint32
+      (file,
+       t->level2[i] == EMPTY
        ? 0
        : (t->level2[i] << t->p) * sizeof (uint32_t) + level3_offset);
 
-  for (i = 0; i < (t->level3_size << t->p); i++)
-    ((uint32_t *) (t->result + level3_offset))[i] = t->level3[i];
+  add_locale_uint32_array (file, t->level3, t->level3_size << t->p);
+  end_locale_structure (file);
 
   if (t->level1_alloc > 0)
     free (t->level1);
@@ -3759,26 +3639,6 @@ wctype_table_finalize (struct wctype_table *t)
     free (t->level3);
 }
 
-#define TABLE wcwidth_table
-#define ELEMENT uint8_t
-#define DEFAULT 0xff
-#include "3level.h"
-
-#define TABLE wctrans_table
-#define ELEMENT int32_t
-#define DEFAULT 0
-#define wctrans_table_add wctrans_table_add_internal
-#include "3level.h"
-#undef wctrans_table_add
-/* The wctrans_table must actually store the difference between the
-   desired result and the argument.  */
-static inline void
-wctrans_table_add (struct wctrans_table *t, uint32_t wc, uint32_t mapped_wc)
-{
-  wctrans_table_add_internal (t, wc, mapped_wc - wc);
-}
-
-
 /* Flattens the included transliterations into a translit list.
    Inserts them in the list at `cursor', and returns the new cursor.  */
 static struct translit_t **
@@ -3855,8 +3715,8 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
   ctype->ctype32_b = (char_class32_t *) xcalloc (256, sizeof (char_class32_t));
   ctype->class_b = (uint32_t **)
     xmalloc (ctype->nr_charclass * sizeof (uint32_t *));
-  ctype->class_3level = (struct iovec *)
-    xmalloc (ctype->nr_charclass * sizeof (struct iovec));
+  ctype->class_3level = (struct wctype_table *)
+    xmalloc (ctype->nr_charclass * sizeof (struct wctype_table));
 
   /* This is the array accessed using the multibyte string elements.  */
   for (idx = 0; idx < 256; ++idx)
@@ -3888,34 +3748,30 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
 
   for (nr = 0; nr < ctype->nr_charclass; nr++)
     {
-      struct wctype_table t;
+      struct wctype_table *t;
 
-      t.p = 4; /* or: 5 */
-      t.q = 7; /* or: 6 */
-      wctype_table_init (&t);
+      t = &ctype->class_3level[nr];
+      t->p = 4; /* or: 5 */
+      t->q = 7; /* or: 6 */
+      wctype_table_init (t);
 
       for (idx = 0; idx < ctype->class_collection_act; ++idx)
 	if (ctype->class_collection[idx] & _ISwbit (nr))
-	  wctype_table_add (&t, ctype->charnames[idx]);
-
-      wctype_table_finalize (&t);
+	  wctype_table_add (t, ctype->charnames[idx]);
 
       if (verbose)
 	WITH_CUR_LOCALE (fprintf (stderr, _("\
 %s: table for class \"%s\": %lu bytes\n"),
 				 "LC_CTYPE", ctype->classnames[nr],
-				 (unsigned long int) t.result_size));
-
-      ctype->class_3level[nr].iov_base = t.result;
-      ctype->class_3level[nr].iov_len = t.result_size;
+				 (unsigned long int) t->result_size));
     }
 
   /* Room for table of mappings.  */
   ctype->map_b = (uint32_t **) xmalloc (2 * sizeof (uint32_t *));
   ctype->map32_b = (uint32_t **) xmalloc (ctype->map_collection_nr
 					  * sizeof (uint32_t *));
-  ctype->map_3level = (struct iovec *)
-    xmalloc (ctype->map_collection_nr * sizeof (struct iovec));
+  ctype->map_3level = (struct wctrans_table *)
+    xmalloc (ctype->map_collection_nr * sizeof (struct wctrans_table));
 
   /* Fill in all mappings.  */
   for (idx = 0; idx < 2; ++idx)
@@ -3956,27 +3812,23 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
 
   for (nr = 0; nr < ctype->map_collection_nr; nr++)
     {
-      struct wctrans_table t;
+      struct wctrans_table *t;
 
-      t.p = 7;
-      t.q = 9;
-      wctrans_table_init (&t);
+      t = &ctype->map_3level[nr];
+      t->p = 7;
+      t->q = 9;
+      wctrans_table_init (t);
 
       for (idx = 0; idx < ctype->map_collection_act[nr]; ++idx)
 	if (ctype->map_collection[nr][idx] != 0)
-	  wctrans_table_add (&t, ctype->charnames[idx],
+	  wctrans_table_add (t, ctype->charnames[idx],
 			     ctype->map_collection[nr][idx]);
 
-      wctrans_table_finalize (&t);
-
       if (verbose)
 	WITH_CUR_LOCALE (fprintf (stderr, _("\
 %s: table for map \"%s\": %lu bytes\n"),
 				 "LC_CTYPE", ctype->mapnames[nr],
-				 (unsigned long int) t.result_size));
-
-      ctype->map_3level[nr].iov_base = t.result;
-      ctype->map_3level[nr].iov_len = t.result_size;
+				 (unsigned long int) t->result_size));
     }
 
   /* Extra array for class and map names.  */
@@ -3996,11 +3848,12 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
      saves a run-time check.
      But we put L'\0' in the table.  This again saves a run-time check.  */
   {
-    struct wcwidth_table t;
+    struct wcwidth_table *t;
 
-    t.p = 7;
-    t.q = 9;
-    wcwidth_table_init (&t);
+    t = &ctype->width;
+    t->p = 7;
+    t->q = 9;
+    wcwidth_table_init (t);
 
     /* First set all the printable characters of the character set to
        the default width.  */
@@ -4020,7 +3873,7 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
 			&ctype->class_collection_act, data->ucs4);
 
 	    if (class_bits != NULL && (*class_bits & BITw (tok_print)))
-	      wcwidth_table_add (&t, data->ucs4, charmap->width_default);
+	      wcwidth_table_add (t, data->ucs4, charmap->width_default);
 	  }
       }
 
@@ -4068,7 +3921,7 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
 				&ctype->class_collection_act, wch);
 
 		    if (class_bits != NULL && (*class_bits & BITw (tok_print)))
-		      wcwidth_table_add (&t, wch,
+		      wcwidth_table_add (t, wch,
 					 charmap->width_rules[cnt].width);
 		  }
 
@@ -4098,16 +3951,11 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap,
       }
 
     /* Set the width of L'\0' to 0.  */
-    wcwidth_table_add (&t, 0, 0);
-
-    wcwidth_table_finalize (&t);
+    wcwidth_table_add (t, 0, 0);
 
     if (verbose)
       WITH_CUR_LOCALE (fprintf (stderr, _("%s: table for width: %lu bytes\n"),
-			       "LC_CTYPE", (unsigned long int) t.result_size));
-
-    ctype->width.iov_base = t.result;
-    ctype->width.iov_len = t.result_size;
+			       "LC_CTYPE", (unsigned long int) t->result_size));
   }
 
   /* Set MB_CUR_MAX.  */
diff --git a/locale/programs/ld-identification.c b/locale/programs/ld-identification.c
index 4b03fb6..5487aae 100644
--- a/locale/programs/ld-identification.c
+++ b/locale/programs/ld-identification.c
@@ -182,116 +182,32 @@ identification_output (struct localedef_t *locale,
 {
   struct locale_identification_t *identification
     = locale->categories[LC_IDENTIFICATION].identification;
-  struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_IDENTIFICATION)
-		  + (__LC_LAST - 2)];
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_IDENTIFICATION)];
-  size_t cnt = 0;
+  struct locale_file file;
   size_t num;
-  size_t last_idx;
-
-  data.magic = LIMAGIC (LC_IDENTIFICATION);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_IDENTIFICATION);
-  iov[cnt].iov_base = (void *) &data;
-  iov[cnt].iov_len = sizeof (data);
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) idx;
-  iov[cnt].iov_len = sizeof (idx);
-  ++cnt;
-
-  idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
-  iov[cnt].iov_base = (void *) identification->title;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->source;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->address;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->contact;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->email;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->tel;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->fax;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->language;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->territory;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->audience;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->application;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->abbreviation;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->revision;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) identification->date;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  last_idx = cnt - 1;
-  idx[last_idx] = idx[cnt - 2];
+
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_IDENTIFICATION));
+  add_locale_string (&file, identification->title);
+  add_locale_string (&file, identification->source);
+  add_locale_string (&file, identification->address);
+  add_locale_string (&file, identification->contact);
+  add_locale_string (&file, identification->email);
+  add_locale_string (&file, identification->tel);
+  add_locale_string (&file, identification->fax);
+  add_locale_string (&file, identification->language);
+  add_locale_string (&file, identification->territory);
+  add_locale_string (&file, identification->audience);
+  add_locale_string (&file, identification->application);
+  add_locale_string (&file, identification->abbreviation);
+  add_locale_string (&file, identification->revision);
+  add_locale_string (&file, identification->date);
+  start_locale_structure (&file);
   for (num = 0; num < __LC_LAST; ++num)
     if (num != LC_ALL)
-      {
-	iov[cnt].iov_base = (void *) identification->category[num];
-	iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-	idx[last_idx] += iov[cnt].iov_len;
-	++cnt;
-      }
-
-  assert (last_idx == _NL_ITEM_INDEX (_NL_NUM_LC_IDENTIFICATION) - 1);
-  iov[cnt].iov_base = (void *) charmap->code_set_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  assert (cnt == (2 + _NL_ITEM_INDEX (_NL_NUM_LC_IDENTIFICATION)
-		  + (__LC_LAST - 2)));
-
-  write_locale_data (output_path, LC_IDENTIFICATION, "LC_IDENTIFICATION", cnt,
-		     iov);
+      add_locale_string (&file, identification->category[num]);
+  end_locale_structure (&file);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_IDENTIFICATION, "LC_IDENTIFICATION",
+		     &file);
 }
 
 
diff --git a/locale/programs/ld-measurement.c b/locale/programs/ld-measurement.c
index 4aa0ea9..5be54e7 100644
--- a/locale/programs/ld-measurement.c
+++ b/locale/programs/ld-measurement.c
@@ -122,35 +122,12 @@ measurement_output (struct localedef_t *locale,
 {
   struct locale_measurement_t *measurement =
     locale->categories[LC_MEASUREMENT].measurement;
-  struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT)];
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT)];
-  size_t cnt = 0;
-
-  data.magic = LIMAGIC (LC_MEASUREMENT);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT);
-  iov[cnt].iov_base = (void *) &data;
-  iov[cnt].iov_len = sizeof (data);
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) idx;
-  iov[cnt].iov_len = sizeof (idx);
-  ++cnt;
-
-  idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
-  iov[cnt].iov_base = &measurement->measurement;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) charmap->code_set_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT));
-
-  write_locale_data (output_path, LC_MEASUREMENT, "LC_MEASUREMENT",
-		     2 + _NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT), iov);
+  struct locale_file file;
+
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT));
+  add_locale_char (&file, measurement->measurement);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_MEASUREMENT, "LC_MEASUREMENT", &file);
 }
 
 
diff --git a/locale/programs/ld-messages.c b/locale/programs/ld-messages.c
index f1b9f93..116f3a2 100644
--- a/locale/programs/ld-messages.c
+++ b/locale/programs/ld-messages.c
@@ -184,49 +184,15 @@ messages_output (struct localedef_t *locale, const struct charmap_t *charmap,
 {
   struct locale_messages_t *messages
     = locale->categories[LC_MESSAGES].messages;
-  struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES)];
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES)];
-  size_t cnt = 0;
-
-  data.magic = LIMAGIC (LC_MESSAGES);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES);
-  iov[cnt].iov_base = (void *) &data;
-  iov[cnt].iov_len = sizeof (data);
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) idx;
-  iov[cnt].iov_len = sizeof (idx);
-  ++cnt;
-
-  idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
-  iov[cnt].iov_base = (char *) messages->yesexpr;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (char *) messages->noexpr;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (char *) messages->yesstr;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (char *) messages->nostr;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (char *) charmap->code_set_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-
-  assert (cnt + 1 == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES));
-
-  write_locale_data (output_path, LC_MESSAGES, "LC_MESSAGES",
-		     2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES), iov);
+  struct locale_file file;
+
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES));
+  add_locale_string (&file, messages->yesexpr);
+  add_locale_string (&file, messages->noexpr);
+  add_locale_string (&file, messages->yesstr);
+  add_locale_string (&file, messages->nostr);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_MESSAGES, "LC_MESSAGES", &file);
 }
 
 
diff --git a/locale/programs/ld-monetary.c b/locale/programs/ld-monetary.c
index 4dfca3d..ec86223 100644
--- a/locale/programs/ld-monetary.c
+++ b/locale/programs/ld-monetary.c
@@ -364,262 +364,57 @@ monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
 {
   struct locale_monetary_t *monetary
     = locale->categories[LC_MONETARY].monetary;
-  struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
-  size_t cnt = 0;
-
-  data.magic = LIMAGIC (LC_MONETARY);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
-  iov[cnt].iov_base = (void *) &data;
-  iov[cnt].iov_len = sizeof (data);
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) idx;
-  iov[cnt].iov_len = sizeof (idx);
-  ++cnt;
-
-  idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->currency_symbol;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = monetary->mon_grouping;
-  iov[cnt].iov_len = monetary->mon_grouping_len;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->positive_sign;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->negative_sign;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->frac_digits;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->crncystr;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
-  iov[cnt].iov_len = 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-
-  /* Align following data */
-  iov[cnt].iov_base = (void *) "\0\0";
-  iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
-  idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
-  iov[cnt].iov_len = sizeof(uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
-  iov[cnt].iov_len = sizeof(uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
-  iov[cnt].iov_len = sizeof(uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
-  iov[cnt].iov_len = sizeof(uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) monetary->conversion_rate;
-  iov[cnt].iov_len = 2 * sizeof(uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->mon_decimal_point_wc;
-  iov[cnt].iov_len = sizeof (uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &monetary->mon_thousands_sep_wc;
-  iov[cnt].iov_len = sizeof (uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) charmap->code_set_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
-
-  write_locale_data (output_path, LC_MONETARY, "LC_MONETARY",
-		     3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
+  struct locale_file file;
+
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
+  add_locale_string (&file, monetary->int_curr_symbol);
+  add_locale_string (&file, monetary->currency_symbol);
+  add_locale_string (&file, monetary->mon_decimal_point);
+  add_locale_string (&file, monetary->mon_thousands_sep);
+  add_locale_raw_data (&file, monetary->mon_grouping,
+		       monetary->mon_grouping_len);
+  add_locale_string (&file, monetary->positive_sign);
+  add_locale_string (&file, monetary->negative_sign);
+  add_locale_char (&file, monetary->int_frac_digits);
+  add_locale_char (&file, monetary->frac_digits);
+  add_locale_char (&file, monetary->p_cs_precedes);
+  add_locale_char (&file, monetary->p_sep_by_space);
+  add_locale_char (&file, monetary->n_cs_precedes);
+  add_locale_char (&file, monetary->n_sep_by_space);
+  add_locale_char (&file, monetary->p_sign_posn);
+  add_locale_char (&file, monetary->n_sign_posn);
+  add_locale_string (&file, monetary->crncystr);
+  add_locale_char (&file, monetary->int_p_cs_precedes);
+  add_locale_char (&file, monetary->int_p_sep_by_space);
+  add_locale_char (&file, monetary->int_n_cs_precedes);
+  add_locale_char (&file, monetary->int_n_sep_by_space);
+  add_locale_char (&file, monetary->int_p_sign_posn);
+  add_locale_char (&file, monetary->int_n_sign_posn);
+  add_locale_string (&file, monetary->duo_int_curr_symbol);
+  add_locale_string (&file, monetary->duo_currency_symbol);
+  add_locale_char (&file, monetary->duo_int_frac_digits);
+  add_locale_char (&file, monetary->duo_frac_digits);
+  add_locale_char (&file, monetary->duo_p_cs_precedes);
+  add_locale_char (&file, monetary->duo_p_sep_by_space);
+  add_locale_char (&file, monetary->duo_n_cs_precedes);
+  add_locale_char (&file, monetary->duo_n_sep_by_space);
+  add_locale_char (&file, monetary->duo_int_p_cs_precedes);
+  add_locale_char (&file, monetary->duo_int_p_sep_by_space);
+  add_locale_char (&file, monetary->duo_int_n_cs_precedes);
+  add_locale_char (&file, monetary->duo_int_n_sep_by_space);
+  add_locale_char (&file, monetary->duo_p_sign_posn);
+  add_locale_char (&file, monetary->duo_n_sign_posn);
+  add_locale_char (&file, monetary->duo_int_p_sign_posn);
+  add_locale_char (&file, monetary->duo_int_n_sign_posn);
+  add_locale_uint32 (&file, monetary->uno_valid_from);
+  add_locale_uint32 (&file, monetary->uno_valid_to);
+  add_locale_uint32 (&file, monetary->duo_valid_from);
+  add_locale_uint32 (&file, monetary->duo_valid_to);
+  add_locale_uint32_array (&file, monetary->conversion_rate, 2);
+  add_locale_uint32 (&file, monetary->mon_decimal_point_wc);
+  add_locale_uint32 (&file, monetary->mon_thousands_sep_wc);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_MONETARY, "LC_MONETARY", &file);
 }
 
 
diff --git a/locale/programs/ld-name.c b/locale/programs/ld-name.c
index 207bf01..efc541e 100644
--- a/locale/programs/ld-name.c
+++ b/locale/programs/ld-name.c
@@ -157,60 +157,17 @@ name_output (struct localedef_t *locale, const struct charmap_t *charmap,
 	     const char *output_path)
 {
   struct locale_name_t *name = locale->categories[LC_NAME].name;
-  struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_NAME)];
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_NAME)];
-  size_t cnt = 0;
-
-  data.magic = LIMAGIC (LC_NAME);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_NAME);
-  iov[cnt].iov_base = (void *) &data;
-  iov[cnt].iov_len = sizeof (data);
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) idx;
-  iov[cnt].iov_len = sizeof (idx);
-  ++cnt;
-
-  idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
-  iov[cnt].iov_base = (void *) name->name_fmt;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) name->name_gen;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) name->name_mr;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) name->name_mrs;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) name->name_miss;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) name->name_ms;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) charmap->code_set_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_NAME));
-
-  write_locale_data (output_path, LC_NAME, "LC_NAME",
-		     2 + _NL_ITEM_INDEX (_NL_NUM_LC_NAME), iov);
+  struct locale_file file;
+
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_NAME));
+  add_locale_string (&file, name->name_fmt);
+  add_locale_string (&file, name->name_gen);
+  add_locale_string (&file, name->name_mr);
+  add_locale_string (&file, name->name_mrs);
+  add_locale_string (&file, name->name_miss);
+  add_locale_string (&file, name->name_ms);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_NAME, "LC_NAME", &file);
 }
 
 
diff --git a/locale/programs/ld-numeric.c b/locale/programs/ld-numeric.c
index 929409c..093a049 100644
--- a/locale/programs/ld-numeric.c
+++ b/locale/programs/ld-numeric.c
@@ -133,61 +133,16 @@ numeric_output (struct localedef_t *locale, const struct charmap_t *charmap,
 		const char *output_path)
 {
   struct locale_numeric_t *numeric = locale->categories[LC_NUMERIC].numeric;
-  struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC)];
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC)];
-  size_t cnt = 0;
-
-  data.magic = LIMAGIC (LC_NUMERIC);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC);
-  iov[cnt].iov_base = (void *) &data;
-  iov[cnt].iov_len = sizeof (data);
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) idx;
-  iov[cnt].iov_len = sizeof (idx);
-  ++cnt;
-
-  idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
-  iov[cnt].iov_base = (void *) (numeric->decimal_point ?: "");
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) (numeric->thousands_sep ?: "");
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = numeric->grouping;
-  iov[cnt].iov_len = numeric->grouping_len;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-
-  /* Align following data */
-  iov[cnt].iov_base = (void *) "\0\0";
-  iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
-  idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) &numeric->decimal_point_wc;
-  iov[cnt].iov_len = sizeof (uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) &numeric->thousands_sep_wc;
-  iov[cnt].iov_len = sizeof (uint32_t);
-  ++cnt;
-
-  idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) charmap->code_set_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-
-  assert (cnt + 1 == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC));
-
-  write_locale_data (output_path, LC_NUMERIC, "LC_NUMERIC",
-		     3 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC), iov);
+  struct locale_file file;
+
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC));
+  add_locale_string (&file, numeric->decimal_point ?: "");
+  add_locale_string (&file, numeric->thousands_sep ?: "");
+  add_locale_raw_data (&file, numeric->grouping, numeric->grouping_len);
+  add_locale_uint32 (&file, numeric->decimal_point_wc);
+  add_locale_uint32 (&file, numeric->thousands_sep_wc);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_NUMERIC, "LC_NUMERIC", &file);
 }
 
 
diff --git a/locale/programs/ld-paper.c b/locale/programs/ld-paper.c
index c6239df..595a600 100644
--- a/locale/programs/ld-paper.c
+++ b/locale/programs/ld-paper.c
@@ -121,40 +121,13 @@ paper_output (struct localedef_t *locale, const struct charmap_t *charmap,
 	      const char *output_path)
 {
   struct locale_paper_t *paper = locale->categories[LC_PAPER].paper;
-  struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_PAPER)];
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_PAPER)];
-  size_t cnt = 0;
-
-  data.magic = LIMAGIC (LC_PAPER);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_PAPER);
-  iov[cnt].iov_base = (void *) &data;
-  iov[cnt].iov_len = sizeof (data);
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) idx;
-  iov[cnt].iov_len = sizeof (idx);
-  ++cnt;
-
-  idx[cnt - 2] = iov[cnt - 2].iov_len + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = &paper->height;
-  iov[cnt].iov_len = 4;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = &paper->width;
-  iov[cnt].iov_len = 4;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) charmap->code_set_name;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_PAPER));
-
-  write_locale_data (output_path, LC_PAPER, "LC_PAPER",
-		     2 + _NL_ITEM_INDEX (_NL_NUM_LC_PAPER), iov);
+  struct locale_file file;
+
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_PAPER));
+  add_locale_uint32 (&file, paper->height);
+  add_locale_uint32 (&file, paper->width);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_PAPER, "LC_PAPER", &file);
 }
 
 
diff --git a/locale/programs/ld-telephone.c b/locale/programs/ld-telephone.c
index 4452750..3e71a36 100644
--- a/locale/programs/ld-telephone.c
+++ b/locale/programs/ld-telephone.c
@@ -175,50 +175,15 @@ telephone_output (struct localedef_t *locale, const struct charmap_t *charmap,
 {
   struct locale_telephone_t *telephone =
     locale->categories[LC_TELEPHONE].telephone;
-  struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE)];
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE)];
-  size_t cnt = 0;
-
-  data.magic = LIMAGIC (LC_TELEPHONE);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE);
-  iov[cnt].iov_base = (void *) &data;
-  iov[cnt].iov_len = sizeof (data);
-  ++cnt;
-
-  iov[cnt].iov_base = (void *) idx;
-  iov[cnt].iov_len = sizeof (idx);
-  ++cnt;
-
-  idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
-  iov[cnt].iov_base = (void *) telephone->tel_int_fmt;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) telephone->tel_dom_fmt;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) telephone->int_select;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) telephone->int_prefix;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
-  iov[cnt].iov_base = (void *) charmap->code_set_name;;
-  iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
-  ++cnt;
-
-  assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE));
-
-  write_locale_data (output_path, LC_TELEPHONE, "LC_TELEPHONE",
-		     2 + _NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE), iov);
+  struct locale_file file;
+
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE));
+  add_locale_string (&file, telephone->tel_int_fmt);
+  add_locale_string (&file, telephone->tel_dom_fmt);
+  add_locale_string (&file, telephone->int_select);
+  add_locale_string (&file, telephone->int_prefix);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_TELEPHONE, "LC_TELEPHONE", &file);
 }
 
 
diff --git a/locale/programs/ld-time.c b/locale/programs/ld-time.c
index d3646b8..5956cb3 100644
--- a/locale/programs/ld-time.c
+++ b/locale/programs/ld-time.c
@@ -539,394 +539,116 @@ time_output (struct localedef_t *locale, const struct charmap_t *charmap,
 	     const char *output_path)
 {
   struct locale_time_t *time = locale->categories[LC_TIME].time;
-  struct iovec *iov = alloca (sizeof *iov
-			      * (2 + _NL_ITEM_INDEX (_NL_NUM_LC_TIME)
-				 + time->num_era - 1
-				 + 2 * 99
-				 + 2 + time->num_era * 10));
-  struct locale_file data;
-  uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_TIME)];
-  size_t cnt, last_idx, num, n;
+  struct locale_file file;
+  size_t num, n;
 
-  data.magic = LIMAGIC (LC_TIME);
-  data.n = _NL_ITEM_INDEX (_NL_NUM_LC_TIME);
-  iov[0].iov_base = (void *) &data;
-  iov[0].iov_len = sizeof (data);
-
-  iov[1].iov_base = (void *) idx;
-  iov[1].iov_len = sizeof (idx);
-
-  idx[0] = iov[0].iov_len + iov[1].iov_len;
+  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
 
   /* The ab'days.  */
-  for (cnt = 0; cnt <= _NL_ITEM_INDEX (ABDAY_7); ++cnt)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->abday[cnt - _NL_ITEM_INDEX (ABDAY_1)] ?: "");
-      iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-      idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-    }
+  for (n = 0; n < 7; ++n)
+    add_locale_string (&file, time->abday[n] ?: "");
 
   /* The days.  */
-  for (; cnt <= _NL_ITEM_INDEX (DAY_7); ++cnt)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->day[cnt - _NL_ITEM_INDEX (DAY_1)] ?: "");
-      iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-      idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-    }
+  for (n = 0; n < 7; ++n)
+    add_locale_string (&file, time->day[n] ?: "");
 
   /* The ab'mons.  */
-  for (; cnt <= _NL_ITEM_INDEX (ABMON_12); ++cnt)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->abmon[cnt - _NL_ITEM_INDEX (ABMON_1)] ?: "");
-      iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-      idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-    }
+  for (n = 0; n < 12; ++n)
+    add_locale_string (&file, time->abmon[n] ?: "");
 
   /* The mons.  */
-  for (; cnt <= _NL_ITEM_INDEX (MON_12); ++cnt)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->mon[cnt - _NL_ITEM_INDEX (MON_1)] ?: "");
-      iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-      idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-    }
+  for (n = 0; n < 12; ++n)
+    add_locale_string (&file, time->mon[n] ?: "");
 
   /* AM/PM.  */
-  for (; cnt <= _NL_ITEM_INDEX (PM_STR); ++cnt)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->am_pm[cnt - _NL_ITEM_INDEX (AM_STR)] ?: "");
-      iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-      idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-    }
+  for (n = 0; n < 2; ++n)
+    add_locale_string (&file, time->am_pm[n]);
 
-  iov[2 + cnt].iov_base = (void *) (time->d_t_fmt ?: "");
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  ++cnt;
+  add_locale_string (&file, time->d_t_fmt ?: "");
+  add_locale_string (&file, time->d_fmt ?: "");
+  add_locale_string (&file, time->t_fmt ?: "");
+  add_locale_string (&file, time->t_fmt_ampm ?: "");
 
-  iov[2 + cnt].iov_base = (void *) (time->d_fmt ?: "");
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  ++cnt;
+  start_locale_structure (&file);
+  for (num = 0; num < time->num_era; ++num)
+    add_locale_string (&file, time->era[num]);
+  end_locale_structure (&file);
 
-  iov[2 + cnt].iov_base = (void *) (time->t_fmt ?: "");
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  ++cnt;
+  add_locale_string (&file, time->era_year ?: "");
+  add_locale_string (&file, time->era_d_fmt ?: "");
 
-  iov[2 + cnt].iov_base = (void *) (time->t_fmt_ampm ?: "");
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
-  last_idx = ++cnt;
+  start_locale_structure (&file);
+  for (num = 0; num < 100; ++num)
+    add_locale_string (&file, time->alt_digits[num] ?: "");
+  end_locale_structure (&file);
 
-  idx[1 + last_idx] = idx[last_idx];
-  for (num = 0; num < time->num_era; ++num, ++cnt)
-    {
-      iov[2 + cnt].iov_base = (void *) time->era[num];
-      iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-      idx[1 + last_idx] += iov[2 + cnt].iov_len;
-    }
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->era_year ?: "");
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->era_d_fmt ?: "");
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  idx[1 + last_idx] = idx[last_idx];
-  for (num = 0; num < 100; ++num, ++cnt)
-    {
-      iov[2 + cnt].iov_base = (void *) (time->alt_digits[num] ?: "");
-      iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-      idx[1 + last_idx] += iov[2 + cnt].iov_len;
-    }
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->era_d_t_fmt ?: "");
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->era_t_fmt ?: "");
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-
-  /* We must align the following data.  */
-  iov[2 + cnt].iov_base = (void *) "\0\0";
-  iov[2 + cnt].iov_len = ((idx[last_idx] + 3) & ~3) - idx[last_idx];
-  idx[last_idx] = (idx[last_idx] + 3) & ~3;
-  ++cnt;
-
-  /* The `era' data in usable form.  */
-  iov[2 + cnt].iov_base = (void *) &time->num_era;
-  iov[2 + cnt].iov_len = sizeof (uint32_t);
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  idx[1 + last_idx] = idx[last_idx];
+  add_locale_string (&file, time->era_d_t_fmt ?: "");
+  add_locale_string (&file, time->era_t_fmt ?: "");
+  add_locale_uint32 (&file, time->num_era);
+
+  start_locale_structure (&file);
   for (num = 0; num < time->num_era; ++num)
     {
-      size_t l, l2;
-
-      iov[2 + cnt].iov_base = (void *) &time->era_entries[num].direction;
-      iov[2 + cnt].iov_len = sizeof (int32_t);
-      ++cnt;
-      iov[2 + cnt].iov_base = (void *) &time->era_entries[num].offset;
-      iov[2 + cnt].iov_len = sizeof (int32_t);
-      ++cnt;
-      iov[2 + cnt].iov_base = (void *) &time->era_entries[num].start_date[0];
-      iov[2 + cnt].iov_len = sizeof (int32_t);
-      ++cnt;
-      iov[2 + cnt].iov_base = (void *) &time->era_entries[num].start_date[1];
-      iov[2 + cnt].iov_len = sizeof (int32_t);
-      ++cnt;
-      iov[2 + cnt].iov_base = (void *) &time->era_entries[num].start_date[2];
-      iov[2 + cnt].iov_len = sizeof (int32_t);
-      ++cnt;
-      iov[2 + cnt].iov_base = (void *) &time->era_entries[num].stop_date[0];
-      iov[2 + cnt].iov_len = sizeof (int32_t);
-      ++cnt;
-      iov[2 + cnt].iov_base = (void *) &time->era_entries[num].stop_date[1];
-      iov[2 + cnt].iov_len = sizeof (int32_t);
-      ++cnt;
-      iov[2 + cnt].iov_base = (void *) &time->era_entries[num].stop_date[2];
-      iov[2 + cnt].iov_len = sizeof (int32_t);
-      ++cnt;
-
-      l = ((char *) rawmemchr (time->era_entries[num].format, '\0')
-	   - time->era_entries[num].name) + 1;
-      l2 = (l + 3) & ~3;
-      iov[2 + cnt].iov_base = alloca (l2);
-      memset (mempcpy (iov[2 + cnt].iov_base, time->era_entries[num].name, l),
-	      '\0', l2 - l);
-      iov[2 + cnt].iov_len = l2;
-      ++cnt;
-
-      idx[1 + last_idx] += 8 * sizeof (int32_t) + l2;
-
-      assert (idx[1 + last_idx] % 4 == 0);
-
-      iov[2 + cnt].iov_base = (void *) time->era_entries[num].wname;
-      iov[2 + cnt].iov_len = ((wcschr ((wchar_t *) time->era_entries[num].wformat, L'\0')
-			       - (wchar_t *) time->era_entries[num].wname + 1)
-			      * sizeof (uint32_t));
-      idx[1 + last_idx] += iov[2 + cnt].iov_len;
-      ++cnt;
+      add_locale_uint32 (&file, time->era_entries[num].direction);
+      add_locale_uint32 (&file, time->era_entries[num].offset);
+      add_locale_uint32 (&file, time->era_entries[num].start_date[0]);
+      add_locale_uint32 (&file, time->era_entries[num].start_date[1]);
+      add_locale_uint32 (&file, time->era_entries[num].start_date[2]);
+      add_locale_uint32 (&file, time->era_entries[num].stop_date[0]);
+      add_locale_uint32 (&file, time->era_entries[num].stop_date[1]);
+      add_locale_uint32 (&file, time->era_entries[num].stop_date[2]);
+      add_locale_string (&file, time->era_entries[num].name);
+      add_locale_string (&file, time->era_entries[num].format);
+      add_locale_wstring (&file, time->era_entries[num].wname);
+      add_locale_wstring (&file, time->era_entries[num].wformat);
     }
-  ++last_idx;
+  end_locale_structure (&file);
 
   /* The wide character ab'days.  */
-  for (n = 0; n < 7; ++n, ++cnt, ++last_idx)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->wabday[n] ?: empty_wstr);
-      iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			      * sizeof (uint32_t));
-      idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-    }
+  for (n = 0; n < 7; ++n)
+    add_locale_wstring (&file, time->wabday[n] ?: empty_wstr);
 
   /* The wide character days.  */
-  for (n = 0; n < 7; ++n, ++cnt, ++last_idx)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->wday[n] ?: empty_wstr);
-      iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			      * sizeof (uint32_t));
-      idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-    }
+  for (n = 0; n < 7; ++n)
+    add_locale_wstring (&file, time->wday[n] ?: empty_wstr);
 
   /* The wide character ab'mons.  */
-  for (n = 0; n < 12; ++n, ++cnt, ++last_idx)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->wabmon[n] ?: empty_wstr);
-      iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			      * sizeof (uint32_t));
-      idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-    }
+  for (n = 0; n < 12; ++n)
+    add_locale_wstring (&file, time->wabmon[n] ?: empty_wstr);
 
   /* The wide character mons.  */
-  for (n = 0; n < 12; ++n, ++cnt, ++last_idx)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->wmon[n] ?: empty_wstr);
-      iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			      * sizeof (uint32_t));
-      idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-    }
+  for (n = 0; n < 12; ++n)
+    add_locale_wstring (&file, time->wmon[n] ?: empty_wstr);
 
   /* Wide character AM/PM.  */
-  for (n = 0; n < 2; ++n, ++cnt, ++last_idx)
-    {
-      iov[2 + cnt].iov_base =
-	(void *) (time->wam_pm[n] ?: empty_wstr);
-      iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			      * sizeof (uint32_t));
-      idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-    }
-
-  iov[2 + cnt].iov_base = (void *) (time->wd_t_fmt ?: empty_wstr);
-  iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			  * sizeof (uint32_t));
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->wd_fmt ?: empty_wstr);
-  iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			  * sizeof (uint32_t));
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->wt_fmt ?: empty_wstr);
-  iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			  * sizeof (uint32_t));
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->wt_fmt_ampm ?: empty_wstr);
-  iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			  * sizeof (uint32_t));
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->wera_year ?: empty_wstr);
-  iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			  * sizeof (uint32_t));
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->wera_d_fmt ?: empty_wstr);
-  iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			  * sizeof (uint32_t));
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  idx[1 + last_idx] = idx[last_idx];
-  for (num = 0; num < 100; ++num, ++cnt)
-    {
-      iov[2 + cnt].iov_base = (void *) (time->walt_digits[num]
-					?: empty_wstr);
-      iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			      * sizeof (uint32_t));
-      idx[1 + last_idx] += iov[2 + cnt].iov_len;
-    }
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->wera_d_t_fmt ?: empty_wstr);
-  iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			  * sizeof (uint32_t));
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) (time->wera_t_fmt ?: empty_wstr);
-  iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-			  * sizeof (uint32_t));
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) &time->week_ndays;
-  iov[2 + cnt].iov_len = 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  /* We must align the following data.  */
-  iov[2 + cnt].iov_base = (void *) "\0\0";
-  iov[2 + cnt].iov_len = ((idx[last_idx] + 3) & ~3) - idx[last_idx];
-  idx[last_idx] = (idx[last_idx] + 3) & ~3;
-  ++cnt;
-
-  iov[2 + cnt].iov_base = (void *) &time->week_1stday;
-  iov[2 + cnt].iov_len = sizeof(uint32_t);
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) &time->week_1stweek;
-  iov[2 + cnt].iov_len = 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) &time->first_weekday;
-  iov[2 + cnt].iov_len = 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) &time->first_workday;
-  iov[2 + cnt].iov_len = 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) &time->cal_direction;
-  iov[2 + cnt].iov_len = 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) time->timezone;
-  iov[2 + cnt].iov_len = strlen (time->timezone) + 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) time->date_fmt;
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  /* We must align the following data.  */
-  iov[2 + cnt].iov_base = (void *) "\0\0";
-  iov[2 + cnt].iov_len = -idx[last_idx] & 3;
-  idx[last_idx] += -idx[last_idx] & 3;
-  ++cnt;
-
-  iov[2 + cnt].iov_base = (void *) time->wdate_fmt;
-  iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1)
-                          * sizeof (uint32_t));
-  idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
-  ++cnt;
-  ++last_idx;
-
-  iov[2 + cnt].iov_base = (void *) charmap->code_set_name;
-  iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
-  ++cnt;
-  ++last_idx;
-
-  assert (cnt == (_NL_ITEM_INDEX (_NL_NUM_LC_TIME)
-		  + time->num_era - 1
-		  + 2 * 99
-		  + 2 + time->num_era * 10));
-  assert (last_idx  == _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
-
-  write_locale_data (output_path, LC_TIME, "LC_TIME", 2 + cnt, iov);
+  for (n = 0; n < 2; ++n)
+    add_locale_wstring (&file, time->wam_pm[n] ?: empty_wstr);
+
+  add_locale_wstring (&file, time->wd_t_fmt ?: empty_wstr);
+  add_locale_wstring (&file, time->wd_fmt ?: empty_wstr);
+  add_locale_wstring (&file, time->wt_fmt ?: empty_wstr);
+  add_locale_wstring (&file, time->wt_fmt_ampm ?: empty_wstr);
+  add_locale_wstring (&file, time->wera_year ?: empty_wstr);
+  add_locale_wstring (&file, time->wera_d_fmt ?: empty_wstr);
+
+  start_locale_structure (&file);
+  for (num = 0; num < 100; ++num)
+    add_locale_wstring (&file, time->walt_digits[num] ?: empty_wstr);
+  end_locale_structure (&file);
+
+  add_locale_wstring (&file, time->wera_d_t_fmt ?: empty_wstr);
+  add_locale_wstring (&file, time->wera_t_fmt ?: empty_wstr);
+  add_locale_char (&file, time->week_ndays);
+  add_locale_uint32 (&file, time->week_1stday);
+  add_locale_char (&file, time->week_1stweek);
+  add_locale_char (&file, time->first_weekday);
+  add_locale_char (&file, time->first_workday);
+  add_locale_char (&file, time->cal_direction);
+  add_locale_string (&file, time->timezone);
+  add_locale_string (&file, time->date_fmt);
+  add_locale_wstring (&file, time->wdate_fmt);
+  add_locale_string (&file, charmap->code_set_name);
+  write_locale_data (output_path, LC_TIME, "LC_TIME", &file);
 }
 
 
diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c
index 3cbd6f1..cb53bbc 100644
--- a/locale/programs/locfile.c
+++ b/locale/programs/locfile.c
@@ -27,14 +27,19 @@
 #include <unistd.h>
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <assert.h>
+#include <wchar.h>
 
 #include "../../crypt/md5.h"
 #include "localedef.h"
+#include "localeinfo.h"
 #include "locfile.h"
 #include "simple-hash.h"
 
 #include "locfile-kw.h"
 
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
 
 /* Temporary storage of the locale data before writing it to the archive.  */
 static locale_data_t to_archive;
@@ -533,17 +538,177 @@ compare_files (const char *filename1, const char *filename2, size_t size,
   return ret;
 }
 
+/* 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.
+   Do likewise for the first call inside a start_locale_structure/
+   end_locale_structure block.  */
+static void
+record_offset (struct locale_file *file)
+{
+  if (file->structure_stage < 2)
+    {
+      assert (file->next_element < file->n_elements);
+      file->offsets[file->next_element++]
+	= (obstack_object_size (&file->data)
+	   + (file->n_elements + 2) * sizeof (uint32_t));
+      if (file->structure_stage == 1)
+	file->structure_stage = 2;
+    }
+}
+
+/* Initialize FILE for a new output file.  N_ELEMENTS is the number
+   of elements in the file.  */
+void
+init_locale_data (struct locale_file *file, size_t n_elements)
+{
+  file->n_elements = n_elements;
+  file->next_element = 0;
+  file->offsets = xmalloc (sizeof (uint32_t) * n_elements);
+  obstack_init (&file->data);
+  file->structure_stage = 0;
+}
+
+/* Align the size of FILE's obstack object to BOUNDARY bytes.  */
+void
+align_locale_data (struct locale_file *file, size_t boundary)
+{
+  size_t size = -obstack_object_size (&file->data) & (boundary - 1);
+  obstack_blank (&file->data, size);
+  memset (obstack_next_free (&file->data) - size, 0, size);
+}
+
+/* Record that FILE's next element contains no data.  */
+void
+add_locale_empty (struct locale_file *file)
+{
+  record_offset (file);
+}
 
-/* Write a locale file, with contents given by N_ELEM and VEC.  */
+/* Record that FILE's next element consists of SIZE bytes starting at DATA.  */
+void
+add_locale_raw_data (struct locale_file *file, const void *data, size_t size)
+{
+  record_offset (file);
+  obstack_grow (&file->data, data, size);
+}
+
+/* Finish the current object on OBSTACK and use it as the data for FILE's
+   next element.  */
+void
+add_locale_raw_obstack (struct locale_file *file, struct obstack *obstack)
+{
+  size_t size = obstack_object_size (obstack);
+  record_offset (file);
+  obstack_grow (&file->data, obstack_finish (obstack), size);
+}
+
+/* Use STRING as FILE's next element.  */
+void
+add_locale_string (struct locale_file *file, const char *string)
+{
+  record_offset (file);
+  obstack_grow (&file->data, string, strlen (string) + 1);
+}
+
+/* Likewise for wide strings.  */
+void
+add_locale_wstring (struct locale_file *file, const uint32_t *string)
+{
+  add_locale_uint32_array (file, string, wcslen ((const wchar_t *) string) + 1);
+}
+
+/* Record that FILE's next element is the 32-bit integer VALUE.  */
+void
+add_locale_uint32 (struct locale_file *file, uint32_t value)
+{
+  align_locale_data (file, sizeof (uint32_t));
+  record_offset (file);
+  obstack_grow (&file->data, &value, sizeof (value));
+}
+
+/* Record that FILE's next element is an array of N_ELEMS integers
+   starting at DATA.  */
+void
+add_locale_uint32_array (struct locale_file *file,
+			 const uint32_t *data, size_t n_elems)
+{
+  align_locale_data (file, sizeof (uint32_t));
+  record_offset (file);
+  obstack_grow (&file->data, data, n_elems * sizeof (uint32_t));
+}
+
+/* Record that FILE's next element is the single byte given by VALUE.  */
+void
+add_locale_char (struct locale_file *file, char value)
+{
+  record_offset (file);
+  obstack_1grow (&file->data, value);
+}
+
+/* Start building an element that contains several different pieces of data.
+   Subsequent calls to add_locale_* will add data to the same element up
+   till the next call to end_locale_structure.  The element's alignment
+   is dictated by the first piece of data added to it.  */
+void
+start_locale_structure (struct locale_file *file)
+{
+  assert (file->structure_stage == 0);
+  file->structure_stage = 1;
+}
+
+/* Finish a structure element that was started by start_locale_structure.
+   Empty structures are OK and behave like add_locale_empty.  */
+void
+end_locale_structure (struct locale_file *file)
+{
+  record_offset (file);
+  assert (file->structure_stage == 2);
+  file->structure_stage = 0;
+}
+
+/* Start building data that goes before the next element's recorded offset.
+   Subsequent calls to add_locale_* will add data to the file without
+   treating any of it as the start of a new element.  Calling
+   end_locale_prelude switches back to the usual behavior.  */
+void
+start_locale_prelude (struct locale_file *file)
+{
+  assert (file->structure_stage == 0);
+  file->structure_stage = 3;
+}
+
+/* End a block started by start_locale_prelude.  */
+void
+end_locale_prelude (struct locale_file *file)
+{
+  assert (file->structure_stage == 3);
+  file->structure_stage = 0;
+}
+
+/* Write a locale file, with contents given by FILE.  */
 void
 write_locale_data (const char *output_path, int catidx, const char *category,
-		   size_t n_elem, struct iovec *vec)
+		   struct locale_file *file)
 {
   size_t cnt, step, maxiov;
   int fd;
   char *fname;
   const char **other_paths;
-
+  uint32_t header[2];
+  size_t n_elem;
+  struct iovec vec[3];
+
+  assert (file->n_elements == file->next_element);
+  header[0] = LIMAGIC (catidx);
+  header[1] = file->n_elements;
+  vec[0].iov_len = sizeof (header);
+  vec[0].iov_base = header;
+  vec[1].iov_len = sizeof (uint32_t) * file->n_elements;
+  vec[1].iov_base = file->offsets;
+  vec[2].iov_len = obstack_object_size (&file->data);
+  vec[2].iov_base = obstack_finish (&file->data);
+  n_elem = 3;
   if (! no_archive)
     {
       /* The data will be added to the archive.  For now we simply
diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h
index 83bf421..bdd87cc 100644
--- a/locale/programs/locfile.h
+++ b/locale/programs/locfile.h
@@ -21,15 +21,17 @@
 #include <stdint.h>
 #include <sys/uio.h>
 
+#include "obstack.h"
 #include "linereader.h"
 #include "localedef.h"
 
-
-/* Header of the locale data files.  */
+/* Structure for storing the contents of a category file.  */
 struct locale_file
 {
-  int magic;
-  int n;
+  size_t n_elements, next_element;
+  uint32_t *offsets;
+  struct obstack data;
+  int structure_stage;
 };
 
 
@@ -66,9 +68,26 @@ extern void write_all_categories (struct localedef_t *definitions,
 				  const char *output_path);
 
 /* 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);
+extern void add_locale_empty (struct locale_file *file);
+extern void add_locale_raw_data (struct locale_file *file, const void *data,
+				 size_t size);
+extern void add_locale_raw_obstack (struct locale_file *file,
+				    struct obstack *obstack);
+extern void add_locale_string (struct locale_file *file, const char *string);
+extern void add_locale_wstring (struct locale_file *file,
+				const uint32_t *string);
+extern void add_locale_uint32 (struct locale_file *file, uint32_t value);
+extern void add_locale_uint32_array (struct locale_file *file,
+				     const uint32_t *data, size_t n_elems);
+extern void add_locale_char (struct locale_file *file, char value);
+extern void start_locale_structure (struct locale_file *file);
+extern void end_locale_structure (struct locale_file *file);
+extern void start_locale_prelude (struct locale_file *file);
+extern void end_locale_prelude (struct locale_file *file);
 extern void write_locale_data (const char *output_path, int catidx,
-			       const char *category, size_t n_elem,
-			       struct iovec *vec);
+			       const char *category, struct locale_file *file);
 
 
 /* Entrypoints for the parsers of the individual categories.  */

-- 
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]