aboutsummaryrefslogtreecommitdiff
path: root/locale
diff options
context:
space:
mode:
Diffstat (limited to 'locale')
-rw-r--r--locale/C-ctype.c9
-rw-r--r--locale/loadlocale.c73
-rw-r--r--locale/localeinfo.h23
3 files changed, 100 insertions, 5 deletions
diff --git a/locale/C-ctype.c b/locale/C-ctype.c
index ef4b670..6253f7f 100644
--- a/locale/C-ctype.c
+++ b/locale/C-ctype.c
@@ -19,6 +19,7 @@
#include <endian.h>
#include <stdalign.h>
#include <stdint.h>
+#include <wcsmbs/wcsmbsload.h>
#include "C-translit.h"
@@ -538,11 +539,17 @@ _nl_C_LC_CTYPE_width attribute_hidden =
NR_FIXED == _NL_ITEM_INDEX (_NL_CTYPE_EXTRA_MAP_1). */
typedef int assertion1[1 - 2 * (NR_FIXED != _NL_ITEM_INDEX (_NL_CTYPE_EXTRA_MAP_1))];
+static const struct lc_ctype_data lc_ctype_data =
+ {
+ .fcts = &__wcsmbs_gconv_fcts_c,
+ .outdigit_bytes_all_equal = 1,
+ };
+
const struct __locale_data _nl_C_LC_CTYPE attribute_hidden =
{
_nl_C_name,
NULL, 0, 0, /* no file mapped */
- NULL, /* No cached data. */
+ (void *) &lc_ctype_data,
UNDELETABLE,
1, /* Enable transliteration by default. */
NR_FIXED + NR_CLASSES + NR_MAPS,
diff --git a/locale/loadlocale.c b/locale/loadlocale.c
index 9069baf..d44310b4 100644
--- a/locale/loadlocale.c
+++ b/locale/loadlocale.c
@@ -62,6 +62,61 @@ static const enum value_type *const _nl_value_types[] =
#undef DEFINE_CATEGORY
};
+/* Fill in LOCDATA->private for the LC_CTYPE category. */
+static void
+_nl_intern_locale_data_fill_cache_ctype (struct __locale_data *locdata)
+{
+ struct lc_ctype_data *data = locdata->private;
+
+ /* Default to no translation. Assumes zero initialization of *data. */
+ memset (data->outdigit_bytes, 1, sizeof (data->outdigit_bytes));
+
+ for (int i = 0; i <= 9; ++i)
+ {
+ const char *digit
+ = locdata->values[_NL_ITEM_INDEX (_NL_CTYPE_OUTDIGIT0_MB + i)].string;
+ unsigned char len;
+ if (digit[0] != '0' + i || digit[1] != '\0')
+ {
+ data->outdigit_translation_needed = true;
+ len = strlen (locdata->values[_NL_ITEM_INDEX
+ (_NL_CTYPE_OUTDIGIT0_MB + i)].string);
+ }
+ else
+ len = 1;
+ data->outdigit_bytes[i] = len;
+ if (i == 0)
+ data->outdigit_bytes_all_equal = len;
+ else if (data->outdigit_bytes_all_equal != len)
+ data->outdigit_bytes_all_equal = 0;
+ }
+}
+
+/* Updates data in LOCDATA->private for CATEGORY. */
+static void
+_nl_intern_locale_data_fill_cache (int category, struct __locale_data *locdata)
+{
+ switch (category)
+ {
+ case LC_CTYPE:
+ _nl_intern_locale_data_fill_cache_ctype (locdata);
+ break;
+ }
+}
+
+/* Returns the number of bytes allocated of struct __locale_data for
+ CATEGORY. */
+static size_t
+_nl_intern_locale_data_extra_size (int category)
+{
+ switch (category)
+ {
+ case LC_CTYPE:
+ return sizeof (struct lc_ctype_data);
+ default:
+ return 0;
+ }
+}
struct __locale_data *
_nl_intern_locale_data (int category, const void *data, size_t datasize)
@@ -94,14 +149,23 @@ _nl_intern_locale_data (int category, const void *data, size_t datasize)
return NULL;
}
- newdata = malloc (sizeof *newdata
- + filedata->nstrings * sizeof (union locale_data_value));
+ size_t base_size = (sizeof *newdata
+ + filedata->nstrings * sizeof (union locale_data_value));
+ size_t extra_size = _nl_intern_locale_data_extra_size (category);
+
+ newdata = malloc (base_size + extra_size);
if (newdata == NULL)
return NULL;
newdata->filedata = (void *) filedata;
newdata->filesize = datasize;
- memset (&newdata->private, 0, sizeof (newdata->private));
+ if (extra_size == 0)
+ newdata->private = NULL;
+ else
+ {
+ newdata->private = (char *) newdata + base_size;
+ memset (newdata->private, 0, extra_size);
+ }
newdata->usage_count = 0;
newdata->use_translit = 0;
newdata->nstrings = filedata->nstrings;
@@ -157,6 +221,9 @@ _nl_intern_locale_data (int category, const void *data, size_t datasize)
}
}
+ if (extra_size > 0)
+ _nl_intern_locale_data_fill_cache (category, newdata);
+
return newdata;
}
diff --git a/locale/localeinfo.h b/locale/localeinfo.h
index 01ec553..fd43033 100644
--- a/locale/localeinfo.h
+++ b/locale/localeinfo.h
@@ -61,7 +61,7 @@ struct __locale_data
/* This provides a slot for category-specific code to cache data
computed about this locale. Type of the data pointed to:
- LC_CTYPE struct gconv_fcts (get_gconv_fcts, __wcsmbs_load_conv)
+ LC_CTYPE struct lc_ctype_data (_nl_intern_locale_data)
LC_TIME struct lc_time_data (_nl_init_alt_digit, _nl_init_era_entries)
This data deallocated at the start of _nl_unload_locale. */
@@ -161,6 +161,27 @@ struct lc_time_data
int walt_digits_initialized;
};
+/* Ancillary data for LC_CTYPE. Co-allocated after struct
+ __locale_data by _nl_intern_locale_data. */
+struct lc_ctype_data
+{
+ /* See get_gconv_fcts and __wcsmbs_load_conv. */
+ const struct gconv_fcts *fcts;
+
+ /* If false, outdigit just maps to the ASCII digits. */
+ bool outdigit_translation_needed;
+
+ /* Cached multi-byte string lengths. This could be added to the
+ locale data itself if the format is changed (which impacts
+ existing statically linked binaries). */
+
+ /* For the outdigit decimal digits (copied from LC_CTYPE). */
+ unsigned char outdigit_bytes[10];
+
+ /* If all outdigit_bytes elements are equal, this is that value,
+ otherwise it is 0. */
+ unsigned char outdigit_bytes_all_equal;
+};
/* LC_CTYPE specific:
Hardwired indices for standard wide character translation mappings. */