aboutsummaryrefslogtreecommitdiff
path: root/locale/programs
diff options
context:
space:
mode:
Diffstat (limited to 'locale/programs')
-rw-r--r--locale/programs/ld-collate.c402
-rw-r--r--locale/programs/ld-ctype.c33
-rw-r--r--locale/programs/locale-spec.c33
-rw-r--r--locale/programs/locales.h3
-rw-r--r--locale/programs/locfile.c33
5 files changed, 476 insertions, 28 deletions
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c
index 4bdf0b2256..77e946535d 100644
--- a/locale/programs/ld-collate.c
+++ b/locale/programs/ld-collate.c
@@ -1,6 +1,6 @@
/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
-Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
@@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA. */
#include "locales.h"
#include "simple-hash.h"
#include "stringtrans.h"
+#include "strlen-hash.h"
/* Uncomment the following line in the production version. */
/* #define NDEBUG 1 */
@@ -83,7 +84,7 @@ typedef struct element_t
} element_t;
-/* The real definition of the struct for the LC_CTYPE locale. */
+/* The real definition of the struct for the LC_COLLATE locale. */
struct locale_collate_t
{
/* Collate symbol table. Simple mapping to number. */
@@ -275,15 +276,13 @@ collate_finish (struct localedef_t *locale, struct charset_t *charset)
collate->undefined_len = 2; /* For the name: 1 x wchar_t + L'\0'. */
for (cnt = 0; cnt < collate->nrules; ++cnt)
collate->undefined_len += 1 + collate->undefined.ordering[cnt];
-
- /* Collating symbols are not used anymore. */
- (void) delete_hash (&collate->symbols);
}
void
-collate_output (struct localedef_t *locale, const char *output_path)
+collate_output (struct localedef_t *locale, struct charset_t *charset,
+ const char *output_path)
{
struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
u_int32_t table_size, table_best, level_best, sum_best;
@@ -296,10 +295,29 @@ collate_output (struct localedef_t *locale, const char *output_path)
struct locale_file data;
u_int32_t idx[nelems];
struct obstack non_simple;
+ struct obstack string_pool;
size_t cnt, entry_size;
u_int32_t undefined_offset = UINT_MAX;
u_int32_t *table, *extra, *table2, *extra2;
size_t extra_len;
+ u_int32_t element_hash_tab_size;
+ u_int32_t *element_hash_tab;
+ u_int32_t *element_hash_tab_ob;
+ u_int32_t element_string_pool_size;
+ char *element_string_pool;
+ u_int32_t element_value_size;
+ wchar_t *element_value;
+ wchar_t *element_value_ob;
+ u_int32_t symbols_hash_tab_size;
+ u_int32_t *symbols_hash_tab;
+ u_int32_t *symbols_hash_tab_ob;
+ u_int32_t symbols_string_pool_size;
+ char *symbols_string_pool;
+ u_int32_t symbols_class_size;
+ u_int32_t *symbols_class;
+ u_int32_t *symbols_class_ob;
+ hash_table *hash_tab;
+ unsigned int dummy_weights[collate->nrules + 1];
sum_best = UINT_MAX;
table_best = 0xffff;
@@ -342,6 +360,7 @@ Computing table size for collation information might take a while..."),
fputs (_(" done\n"), stderr);
obstack_init (&non_simple);
+ obstack_init (&string_pool);
data.magic = LIMAGIC (LC_COLLATE);
data.n = nelems;
@@ -608,6 +627,258 @@ Computing table size for collation information might take a while..."),
for (cnt = 0; cnt < extra_len / sizeof (u_int32_t); ++cnt)
extra2[cnt] = SWAPU32 (extra2[cnt]);
+ /* We need a simple hashing table to get a collation-element->chars
+ mapping. We again use internal hasing using a secondary hashing
+ function.
+
+ Each string has an associate hashing value V, computed by a
+ fixed function. To locate the string we use open addressing with
+ double hashing. The first index will be V % M, where M is the
+ size of the hashing table. If no entry is found, iterating with
+ a second, independent hashing function takes place. This second
+ value will be 1 + V % (M - 2). The approximate number of probes
+ will be
+
+ for unsuccessful search: (1 - N / M) ^ -1
+ for successful search: - (N / M) ^ -1 * ln (1 - N / M)
+
+ where N is the number of keys.
+
+ If we now choose M to be the next prime bigger than 4 / 3 * N,
+ we get the values 4 and 1.85 resp. Because unsuccesful searches
+ are unlikely this is a good value. Formulas: [Knuth, The Art of
+ Computer Programming, Volume 3, Sorting and Searching, 1973,
+ Addison Wesley] */
+ if (collate->elements.filled == 0)
+ {
+ /* We don't need any element table since there are no collating
+ elements. */
+ element_hash_tab_size = 0;
+ element_hash_tab = NULL;
+ element_hash_tab_ob = NULL;
+ element_string_pool_size = 0;
+ element_string_pool = NULL;
+ element_value_size = 0;
+ element_value = NULL;
+ element_value_ob = NULL;
+ }
+ else
+ {
+ void *ptr; /* Running pointer. */
+ const char *key; /* Key for current bucket. */
+ size_t keylen; /* Length of key data. */
+ const element_t *data; /* Data, i.e., the character sequence. */
+
+ element_hash_tab_size = next_prime ((collate->elements.filled * 4) / 3);
+ if (element_hash_tab_size < 7)
+ /* We need a minimum to make the following code work. */
+ element_hash_tab_size = 7;
+
+ element_hash_tab = obstack_alloc (&non_simple, (2 * element_hash_tab_size
+ * sizeof (u_int32_t)));
+ memset (element_hash_tab, '\377', (2 * element_hash_tab_size
+ * sizeof (u_int32_t)));
+
+ ptr = NULL;
+ while (iterate_table (&collate->elements, &ptr, (const void **) &key,
+ &keylen, (void **) &data) == 0)
+ {
+ size_t hash_val = hash_string (key, keylen);
+ size_t idx = hash_val % element_hash_tab_size;
+
+ if (element_hash_tab[2 * idx] != (~((u_int32_t) 0)))
+ {
+ /* We need the second hashing function. */
+ size_t c = 1 + (hash_val % (element_hash_tab_size - 2));
+
+ do
+ if (idx >= element_hash_tab_size - c)
+ idx -= element_hash_tab_size - c;
+ else
+ idx += c;
+ while (element_hash_tab[2 * idx] != (~((u_int32_t) 0)));
+ }
+
+ element_hash_tab[2 * idx] = obstack_object_size (&non_simple);
+ element_hash_tab[2 * idx + 1] = (obstack_object_size (&string_pool)
+ / sizeof (wchar_t));
+
+ obstack_grow0 (&non_simple, key, keylen);
+ obstack_grow (&string_pool, data->name,
+ (wcslen (data->name) + 1) * sizeof (wchar_t));
+ }
+
+ if (obstack_object_size (&non_simple) % 4 != 0)
+ obstack_blank (&non_simple,
+ 4 - (obstack_object_size (&non_simple) % 4));
+ element_string_pool_size = obstack_object_size (&non_simple);
+ element_string_pool = obstack_finish (&non_simple);
+
+ element_value_size = obstack_object_size (&string_pool);
+ element_value = obstack_finish (&string_pool);
+
+ /* Create the tables for the other byte order. */
+ element_hash_tab_ob = obstack_alloc (&non_simple,
+ (2 * element_hash_tab_size
+ * sizeof (u_int32_t)));
+ for (cnt = 0; cnt < 2 * element_hash_tab_size; ++cnt)
+ element_hash_tab_ob[cnt] = SWAPU32 (element_hash_tab[cnt]);
+
+ element_value_ob = obstack_alloc (&string_pool, element_value_size);
+ if (sizeof (wchar_t) != 4)
+ {
+ fputs ("sizeof (wchar_t) != 4 currently not handled", stderr);
+ abort ();
+ }
+ for (cnt = 0; cnt < element_value_size / 4; ++cnt)
+ element_value_ob[cnt] = SWAPU32 (element_value[cnt]);
+ }
+
+ /* Store collation elements as map to collation class. There are
+ three kinds of symbols:
+ - simple characters
+ - collation elements
+ - collation symbols
+ We need to make a table which lets the user to access the primary
+ weight based on the symbol string. */
+ symbols_hash_tab_size = next_prime ((4 * (charset->char_table.filled
+ + collate->elements.filled
+ + collate->symbols.filled)) / 3);
+ symbols_hash_tab = obstack_alloc (&non_simple, (2 * symbols_hash_tab_size
+ * sizeof (u_int32_t)));
+ memset (symbols_hash_tab, '\377', (2 * symbols_hash_tab_size
+ * sizeof (u_int32_t)));
+
+ /* Now fill the array. First the symbols from the character set,
+ then the collation elements and last the collation symbols. */
+ hash_tab = &charset->char_table;
+ while (1)
+ {
+ void *ptr; /* Running pointer. */
+ const char *key; /* Key for current bucket. */
+ size_t keylen; /* Length of key data. */
+ void *data; /* Data. */
+
+ ptr = NULL;
+ while (iterate_table (hash_tab, &ptr, (const void **) &key,
+ &keylen, (void **) &data) == 0)
+ {
+ size_t hash_val;
+ size_t idx;
+ u_int32_t word;
+ unsigned int *weights;
+
+ if (hash_tab == &charset->char_table
+ || hash_tab == &collate->elements)
+ {
+ element_t *lastp, *firstp;
+ wchar_t dummy_name[2];
+ const wchar_t *name;
+ size_t name_len;
+
+ if (hash_tab == &charset->char_table)
+ {
+ dummy_name[0] = (wchar_t) ((unsigned long int) data);
+ dummy_name[1] = L'\0';
+ name = dummy_name;
+ name_len = sizeof (wchar_t);
+ }
+ else
+ {
+ element_t *elemp = (element_t *) data;
+ name = elemp->name;
+ name_len = wcslen (name) * sizeof (wchar_t);
+ }
+
+ /* First check whether this character is used at all. */
+ if (find_entry (&collate->result, name, name_len,
+ (void *) &firstp) < 0)
+ /* The symbol is not directly mentioned in the collation.
+ I.e., we use the value for UNDEFINED. */
+ lastp = &collate->undefined;
+ else
+ {
+ /* The entry for the simple character is always found at
+ the end. */
+ lastp = firstp;
+ while (lastp->next != NULL && wcscmp (name, lastp->name))
+ lastp = lastp->next;
+ }
+
+ weights = lastp->ordering;
+ }
+ else
+ {
+ dummy_weights[0] = 1;
+ dummy_weights[collate->nrules]
+ = (unsigned int) ((unsigned long int) data);
+
+ weights = dummy_weights;
+ }
+
+ /* In LASTP->ordering we now have the collation class.
+ Determine the place in the hashing table next. */
+ hash_val = hash_string (key, keylen);
+ idx = hash_val % symbols_hash_tab_size;
+
+ if (symbols_hash_tab[2 * idx] != (~((u_int32_t) 0)))
+ {
+ /* We need the second hashing function. */
+ size_t c = 1 + (hash_val % (symbols_hash_tab_size - 2));
+
+ do
+ if (idx >= symbols_hash_tab_size - c)
+ idx -= symbols_hash_tab_size - c;
+ else
+ idx += c;
+ while (symbols_hash_tab[2 * idx] != (~((u_int32_t) 0)));
+ }
+
+ symbols_hash_tab[2 * idx] = obstack_object_size (&string_pool);
+ symbols_hash_tab[2 * idx + 1] = (obstack_object_size (&non_simple)
+ / sizeof (u_int32_t));
+
+ obstack_grow0 (&string_pool, key, keylen);
+ /* Adding the first weight looks complicated. We have to deal
+ with the kind it is stored and with the fact that original
+ form uses `unsigned int's while we need `u_int32_t' here. */
+ word = weights[0];
+ obstack_grow (&non_simple, &word, sizeof (u_int32_t));
+ for (cnt = 0; cnt < weights[0]; ++cnt)
+ {
+ word = weights[collate->nrules + cnt];
+ obstack_grow (&non_simple, &word, sizeof (u_int32_t));
+ }
+ }
+
+ if (hash_tab == &charset->char_table)
+ hash_tab = &collate->elements;
+ else if (hash_tab == &collate->elements)
+ hash_tab = &collate->symbols;
+ else
+ break;
+ }
+
+ /* Now we have the complete tables. */
+ if (obstack_object_size (&string_pool) % 4 != 0)
+ obstack_blank (&non_simple, 4 - (obstack_object_size (&string_pool) % 4));
+ symbols_string_pool_size = obstack_object_size (&string_pool);
+ symbols_string_pool = obstack_finish (&string_pool);
+
+ symbols_class_size = obstack_object_size (&non_simple);
+ symbols_class = obstack_finish (&non_simple);
+
+ /* Generate tables with other byte order. */
+ symbols_hash_tab_ob = obstack_alloc (&non_simple, (2 * symbols_hash_tab_size
+ * sizeof (u_int32_t)));
+ for (cnt = 0; cnt < 2 * symbols_hash_tab_size; ++cnt)
+ symbols_hash_tab_ob[cnt] = SWAPU32 (symbols_hash_tab[cnt]);
+
+ symbols_class_ob = obstack_alloc (&non_simple, symbols_class_size);
+ for (cnt = 0; cnt < symbols_class_size / 4; ++cnt)
+ symbols_class_ob[cnt] = SWAPU32 (symbols_class[cnt]);
+
+
/* Store table adresses and lengths. */
#if __BYTE_ORDER == __BIG_ENDIAN
iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_TABLE_EB)].iov_base = table;
@@ -642,12 +913,124 @@ Computing table size for collation information might take a while..."),
iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_UNDEFINED)].iov_base = &undefined_offset;
iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_UNDEFINED)].iov_len = sizeof (u_int32_t);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_SIZE)].iov_base
+ = &element_hash_tab_size;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_SIZE)].iov_len
+ = sizeof (u_int32_t);
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_EB)].iov_base
+ = element_hash_tab;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_EB)].iov_len
+ = 2 * element_hash_tab_size * sizeof (u_int32_t);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_EL)].iov_base
+ = element_hash_tab_ob;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_EL)].iov_len
+ = 2 * element_hash_tab_size * sizeof (u_int32_t);
+#else
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_EL)].iov_base
+ = element_hash_tab;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_EL)].iov_len
+ = 2 * element_hash_tab_size * sizeof (u_int32_t);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_EB)].iov_base
+ = element_hash_tab_ob;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_HASH_EB)].iov_len
+ = 2 * element_hash_tab_size * sizeof (u_int32_t);
+#endif
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_STR_POOL)].iov_base
+ = element_string_pool;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_STR_POOL)].iov_len
+ = element_string_pool_size;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_VAL_EB)].iov_base
+ = element_value;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_VAL_EB)].iov_len
+ = element_value_size;
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_VAL_EL)].iov_base
+ = element_value_ob;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_VAL_EL)].iov_len
+ = element_value_size;
+#else
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_VAL_EL)].iov_base
+ = element_value;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_VAL_EL)].iov_len
+ = element_value_size;
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_VAL_EB)].iov_base
+ = element_value_ob;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_VAL_EB)].iov_len
+ = element_value_size;
+#endif
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_SIZE)].iov_base
+ = &symbols_hash_tab_size;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_SIZE)].iov_len
+ = sizeof (u_int32_t);
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_EB)].iov_base
+ = symbols_hash_tab;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_EB)].iov_len
+ = 2 * symbols_hash_tab_size * sizeof (u_int32_t);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_EL)].iov_base
+ = symbols_hash_tab_ob;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_EL)].iov_len
+ = 2 * symbols_hash_tab_size * sizeof (u_int32_t);
+#else
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_EL)].iov_base
+ = symbols_hash_tab;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_EL)].iov_len
+ = 2 * symbols_hash_tab_size * sizeof (u_int32_t);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_EB)].iov_base
+ = symbols_hash_tab_ob;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_EB)].iov_len
+ = 2 * symbols_hash_tab_size * sizeof (u_int32_t);
+#endif
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_STR_POOL)].iov_base
+ = symbols_string_pool;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_STR_POOL)].iov_len
+ = symbols_string_pool_size;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_CLASS_EB)].iov_base
+ = symbols_class;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_ELEM_CLASS_EB)].iov_len
+ = symbols_class_size;
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_CLASS_EL)].iov_base
+ = symbols_class_ob;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_CLASS_EL)].iov_len
+ = symbols_class_size;
+#else
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_CLASS_EL)].iov_base
+ = symbols_class;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_CLASS_EL)].iov_len
+ = symbols_class_size;
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_CLASS_EB)].iov_base
+ = symbols_class_ob;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_SYMB_CLASS_EB)].iov_len
+ = symbols_class_size;
+#endif
+
/* Update idx array. */
idx[0] = iov[0].iov_len + iov[1].iov_len;
for (cnt = 1; cnt < nelems; ++cnt)
idx[cnt] = idx[cnt - 1] + iov[1 + cnt].iov_len;
write_locale_data (output_path, "LC_COLLATE", 2 + nelems, iov);
+
+ obstack_free (&non_simple, NULL);
+ obstack_free (&string_pool, NULL);
}
@@ -729,7 +1112,7 @@ collate_element_from (struct linereader *lr, struct localedef_t *locale,
if (elemp->name[0] == L'\0' || elemp->name[1] == L'\0')
{
- lr_error (lr, _("illegal colltion element"));
+ lr_error (lr, _("illegal collation element"));
return;
}
@@ -762,8 +1145,7 @@ collate_element_from (struct linereader *lr, struct localedef_t *locale,
{
if (set_entry (&collate->result, elemp->name, sizeof (wchar_t),
elemp) < 0)
- error (EXIT_FAILURE, 0,
- _("\
+ error (EXIT_FAILURE, 0, _("\
error while inserting collation element into hash table"));
}
else
@@ -1019,7 +1401,7 @@ line before ellipsis does not contain definition for character constant"));
}
/* Now it's time to handle the ellipsis in the previous line. We do
- this only when the last line contained an definition for an
+ this only when the last line contained an definition for a
character, the current line also defines an character, the
character code for the later is bigger than the former. */
if (collate->was_ellipsis)
diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c
index 0ca3af584b..196f990745 100644
--- a/locale/programs/ld-ctype.c
+++ b/locale/programs/ld-ctype.c
@@ -387,8 +387,8 @@ ctype_output (struct localedef_t *locale, struct charset_t *charset,
{
#define CTYPE_DATA(name, base, len) \
case _NL_ITEM_INDEX (name): \
- iov[2 + elem + offset].iov_base = base; \
- iov[2 + elem + offset].iov_len = len; \
+ iov[2 + elem + offset].iov_base = (base); \
+ iov[2 + elem + offset].iov_len = (len); \
if (elem + 1 < nelems) \
idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len; \
break
@@ -443,9 +443,9 @@ ctype_output (struct localedef_t *locale, struct charset_t *charset,
= strlen (ctype->classnames[cnt]) + 1;
total += iov[2 + elem + offset].iov_len;
}
- iov[2 + elem + offset].iov_base = (void *) "";
- iov[2 + elem + offset].iov_len = 1;
- ++total;
+ iov[2 + elem + offset].iov_base = (void *) "\0\0\0";
+ iov[2 + elem + offset].iov_len = 1 + (4 - ((total + 1) % 4));
+ total += 1 + (4 - ((total + 1) % 4));
if (elem + 1 < nelems)
idx[elem + 1] = idx[elem] + total;
@@ -462,9 +462,9 @@ ctype_output (struct localedef_t *locale, struct charset_t *charset,
= strlen (ctype->mapnames[cnt]) + 1;
total += iov[2 + elem + offset].iov_len;
}
- iov[2 + elem + offset].iov_base = (void *) "";
- iov[2 + elem + offset].iov_len = 1;
- ++total;
+ iov[2 + elem + offset].iov_base = (void *) "\0\0\0";
+ iov[2 + elem + offset].iov_len = 1 + (4 - ((total + 1) % 4));
+ total += 1 + (4 - ((total + 1) % 4));
if (elem + 1 < nelems)
idx[elem + 1] = idx[elem] + total;
@@ -476,8 +476,21 @@ ctype_output (struct localedef_t *locale, struct charset_t *charset,
CTYPE_DATA (_NL_CTYPE_MB_CUR_MAX,
&ctype->mb_cur_max, sizeof (u_int32_t));
- CTYPE_DATA (_NL_CTYPE_CODESET_NAME,
- ctype->codeset_name, strlen (ctype->codeset_name) + 1);
+ 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);
+ memcpy (iov[2 + elem + offset].iov_base, ctype->codeset_name,
+ total);
+ total = (total + 3) & ~3;
+ }
+ iov[2 + elem + offset].iov_len = total;
+ if (elem + 1 < nelems)
+ idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
+ break;
default:
assert (! "unknown CTYPE element");
diff --git a/locale/programs/locale-spec.c b/locale/programs/locale-spec.c
index e408421656..c595524bbb 100644
--- a/locale/programs/locale-spec.c
+++ b/locale/programs/locale-spec.c
@@ -92,4 +92,37 @@ locale_special (const char *name, int show_category_name,
putchar ('\n');
return;
}
+
+ if (strcmp (name, "collate-classes") == 0)
+ {
+ size_t nelem = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZE);
+ size_t cnt;
+ int first = 1;
+
+ if (show_category_name)
+ puts ("LC_COLLATE");
+ if (show_keyword_name)
+ fputs ("collate-classes=", stdout);
+
+ for (cnt = 0; cnt < nelem; ++cnt)
+ if (__collate_symbol_hash[2 * cnt] != 0xffffffff)
+ {
+ printf ("%s<%s>", first ? "" : ",",
+ &__collate_symbol_strings[__collate_symbol_hash[2 * cnt]]);
+#if 1
+ {
+ size_t idx = __collate_symbol_hash[2 * cnt + 1];
+ size_t cls;
+
+ putchar ('=');
+ for (cls = 0; cls < __collate_symbol_classes[idx]; ++cls)
+ printf ("%s%d", cls == 0 ? "" : ":",
+ __collate_symbol_classes[idx + 1 + cls]);
+ }
+#endif
+ first = 0;
+ }
+ putchar ('\n');
+ return;
+ }
}
diff --git a/locale/programs/locales.h b/locale/programs/locales.h
index 9fe85e9e07..95e166e3ef 100644
--- a/locale/programs/locales.h
+++ b/locale/programs/locales.h
@@ -122,7 +122,8 @@ void collate_startup (struct linereader *lr, struct localedef_t *locale,
void collate_finish (struct localedef_t *locale,
struct charset_t *charset);
-void collate_output (struct localedef_t *locale, const char *output_path);
+void collate_output (struct localedef_t *locale, struct charset_t *charset,
+ const char *output_path);
void collate_element_to (struct linereader *lr, struct localedef_t *locale,
struct token *code, struct charset_t *charset);
diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c
index 436df2e976..63ebc4b856 100644
--- a/locale/programs/locfile.c
+++ b/locale/programs/locfile.c
@@ -919,7 +919,7 @@ write_all_categories (struct localedef_t *locale, struct charset_t *charset,
{
/* Call all functions to write locale data. */
ctype_output (locale, charset, output_path);
- collate_output (locale, output_path);
+ collate_output (locale, charset, output_path);
monetary_output (locale, output_path);
numeric_output (locale, output_path);
time_output (locale, output_path);
@@ -943,13 +943,31 @@ write_locale_data (const char *output_path, const char *category,
But for LC_MESSAGES we have to take care for the translation
data. This means we need to have a directory LC_MESSAGES in
which we place the file under the name SYS_LC_MESSAGES. */
+ sprintf (fname, "%s%s", output_path, category);
if (strcmp (category, "LC_MESSAGES") == 0)
- fd = -1;
- else
{
- sprintf (fname, "%s%s", output_path, category);
- fd = creat (fname, 0666);
+ struct stat st;
+
+ if (stat (fname, &st) < 0)
+ {
+ if (mkdir (fname, 0777) < 0)
+ fd = creat (fname, 0666);
+ else
+ {
+ fd = -1;
+ errno = EISDIR;
+ }
+ }
+ else if (S_ISREG (st.st_mode))
+ fd = creat (fname, 0666);
+ else
+ {
+ fd = -1;
+ errno = EISDIR;
+ }
}
+ else
+ fd = creat (fname, 0666);
if (fd == -1)
{
@@ -965,8 +983,9 @@ write_locale_data (const char *output_path, const char *category,
if (fd == -1)
{
- error (0, save_err, _("cannot open output file for category `%s'"),
- category);
+ error (0, save_err, _("\
+cannot open output file `%s' for category `%s'"),
+ fname, category);
return;
}
}