Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2016-07-22 23:54:07 +0300
committerCorinna Vinschen <corinna@vinschen.de>2016-08-15 11:56:57 +0300
commitaefd8b5b518b958f64506a6f74aeffb4f47bde8a (patch)
tree2eb483eb3ab883d1426e7783d8eb322bb66c7952 /newlib/libc/locale
parentd4f6cae9cd526290bfa2a0be7d3dc9fd20f31dba (diff)
Implement newlocale, freelocale, duplocale, uselocale
Add global const __C_locale for reference purposes. Bump Cygwin API minor number and DLL major version number to 2.6.0. Signed-off by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'newlib/libc/locale')
-rw-r--r--newlib/libc/locale/locale.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/newlib/libc/locale/locale.c b/newlib/libc/locale/locale.c
index 35c5e6c6f..4f2d6d271 100644
--- a/newlib/libc/locale/locale.c
+++ b/newlib/libc/locale/locale.c
@@ -226,6 +226,34 @@ static char *categories[_LC_LAST] = {
*/
char __default_locale[ENCODING_LEN + 1] = DEFAULT_LOCALE;
+const struct __locale_t __C_locale =
+{
+ { "C", "C", "C", "C", "C", "C", "C", },
+ __ascii_wctomb,
+ __ascii_mbtowc,
+ 0,
+ NULL,
+#ifndef __HAVE_LOCALE_INFO__
+ "\1",
+ "ASCII",
+ "ASCII",
+#else
+ {
+ { NULL, NULL }, /* LC_ALL */
+#ifdef __CYGWIN__
+ { &_C_collate_locale, NULL }, /* LC_COLLATE */
+#else
+ { NULL, NULL }, /* LC_COLLATE */
+#endif
+ { &_C_ctype_locale, NULL }, /* LC_CTYPE */
+ { &_C_monetary_locale, NULL }, /* LC_MONETARY */
+ { &_C_numeric_locale, NULL }, /* LC_NUMERIC */
+ { &_C_time_locale, NULL }, /* LC_TIME */
+ { &_C_messages_locale, NULL }, /* LC_MESSAGES */
+ },
+#endif
+};
+
struct __locale_t __global_locale =
{
{ "C", "C", DEFAULT_LOCALE, "C", "C", "C", "C", },
@@ -1008,6 +1036,205 @@ _DEFUN (_localeconv_r, (data),
return (struct lconv *) &lconv;
}
+#define LC_VALID_MASK (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MONETARY_MASK \
+ | LC_NUMERIC_MASK | LC_TIME_MASK | LC_MESSAGES_MASK)
+
+struct __locale_t *
+_newlocale_r (struct _reent *p, int category_mask, const char *locale,
+ struct __locale_t *base)
+{
+ struct __locale_t tmp_locale, *new_locale;
+ int i;
+
+ /* Convert LC_ALL_MASK to a mask containing all valid MASK values.
+ This simplifies the code below. */
+ if (category_mask & LC_ALL_MASK)
+ {
+ category_mask &= ~LC_ALL_MASK;
+ category_mask |= LC_VALID_MASK;
+ }
+ /* Check for invalid mask values and valid locale ptr. */
+ if (category_mask & ~LC_VALID_MASK || !locale)
+ {
+ p->_errno = EINVAL;
+ return NULL;
+ }
+ /* If the new locale is supposed to be all default locale, just return
+ a pointer to the default locale. */
+ if ((!base && category_mask == 0)
+ || (category_mask == LC_VALID_MASK
+ && (!strcmp (locale, "C") || !strcmp (locale, "POSIX"))))
+ return (struct __locale_t *) &__C_locale;
+ /* Start with setting all values to the default locale values. */
+ tmp_locale = __C_locale;
+ /* Fill out category strings. */
+ if (!*locale)
+ {
+ for (i = 1; i < _LC_LAST; ++i)
+ if (((1 << i) & category_mask) != 0)
+ {
+ const char *env = __get_locale_env (p, i);
+ if (strlen (env) > ENCODING_LEN)
+ {
+ p->_errno = EINVAL;
+ return NULL;
+ }
+ strcpy (tmp_locale.categories[i], env);
+ }
+ }
+ else
+ {
+ for (i = 1; i < _LC_LAST; ++i)
+ if (((1 << i) & category_mask) != 0)
+ strcpy (tmp_locale.categories[i], locale);
+ }
+ /* Now go over all categories and set them. */
+ for (i = 1; i < _LC_LAST; ++i)
+ {
+ if (((1 << i) & category_mask) != 0)
+ {
+ /* Nothing to do for "C"/"POSIX" locale. */
+ if (!strcmp (tmp_locale.categories[i], "C")
+ || !strcmp (tmp_locale.categories[i], "POSIX"))
+ continue;
+ /* If the new locale is the old locale, just copy it over. */
+ if (base && !strcmp (base->categories[i], tmp_locale.categories[i]))
+ {
+ if (i == LC_CTYPE)
+ {
+ tmp_locale.wctomb = base->wctomb;
+ tmp_locale.mbtowc = base->mbtowc;
+ tmp_locale.cjk_lang = base->cjk_lang;
+ tmp_locale.ctype_ptr - base->ctype_ptr;
+ }
+#ifdef __HAVE_LOCALE_INFO__
+ tmp_locale.lc_cat[i].ptr = base->lc_cat[i].ptr;
+ /* Mark the value as "has still to be copied". We do this in
+ two steps to simplify freeing new locale types in case of a
+ subsequent error. */
+ tmp_locale.lc_cat[i].buf = (void *) -1;
+#else
+ if (i == LC_CTYPE)
+ strcpy (tmp_locale.ctype_codeset, base->ctype_codeset);
+ else if (i == LC_MESSAGES)
+ strcpy (tmp_locale.message_codeset, base->message_codeset);
+#endif
+ continue;
+ }
+ /* Otherwise load locale data. */
+ if (!loadlocale (&tmp_locale, i, tmp_locale.categories[i]))
+ goto error;
+ }
+ }
+ /* Allocate new locale_t. */
+ new_locale = (struct __locale_t *) _calloc_r (p, 1, sizeof *new_locale);
+ if (!new_locale)
+ goto error;
+#ifdef __HAVE_LOCALE_INFO__
+ /* Second step of copying over. At this point we can safely copy. Make
+ sure to invalidate the copied buffer pointers in base, so a subsequent
+ freelocale (base) doesn't free the buffers now used in the new locale. */
+ for (i = 1; i < _LC_LAST; ++i)
+ if (tmp_locale.lc_cat[i].buf == (const void *) -1)
+ {
+ tmp_locale.lc_cat[i].buf = base->lc_cat[i].buf;
+ base->lc_cat[i].buf = NULL;
+ }
+#endif
+
+ *new_locale = tmp_locale;
+ return new_locale;
+
+error:
+ /* An error occured while we had already (potentially) allocated memory.
+ Free memory and return NULL. errno is supposed to be set already. */
+#ifdef __HAVE_LOCALE_INFO__
+ for (i = 1; i < _LC_LAST; ++i)
+ if (tmp_locale.lc_cat[i].buf
+ && tmp_locale.lc_cat[i].buf != (const void *) -1)
+ _free_r (p, tmp_locale.lc_cat[i].buf);
+#endif
+
+ return NULL;
+}
+
+void
+_freelocale_r (struct _reent *p, struct __locale_t *locobj)
+{
+ /* Sanity check. The "C" locale is static, don't try to free it. */
+ if (!locobj || locobj == &__C_locale || locobj == LC_GLOBAL_LOCALE)
+ return;
+#ifdef __HAVE_LOCALE_INFO__
+ for (int i = 1; i < _LC_LAST; ++i)
+ if (locobj->lc_cat[i].buf)
+ _free_r (p, locobj->lc_cat[i].buf);
+#endif
+ _free_r (p, locobj);
+}
+
+struct __locale_t *
+_duplocale_r (struct _reent *p, struct __locale_t *locobj)
+{
+ struct __locale_t tmp_locale, *new_locale;
+ int i;
+
+ /* LC_GLOBAL_LOCALE denotes the global locale. */
+ if (locobj == LC_GLOBAL_LOCALE)
+ locobj = __get_global_locale ();
+ /* The "C" locale is used statically, never copied. */
+ else if (locobj == &__C_locale)
+ return (struct __locale_t *) &__C_locale;
+ /* Copy locale content. */
+ tmp_locale = *locobj;
+#ifdef __HAVE_LOCALE_INFO__
+ for (i = 1; i < _LC_LAST; ++i)
+ if (locobj->lc_cat[i].buf)
+ {
+ /* If the object is not a "C" locale category, copy it. Just call
+ loadlocale. It knows what to do to replicate the category. */
+ tmp_locale.lc_cat[i].ptr = NULL;
+ tmp_locale.lc_cat[i].buf = NULL;
+ if (!loadlocale (&tmp_locale, i, tmp_locale.categories[i]))
+ goto error;
+ }
+#endif
+ /* Allocate new locale_t. */
+ new_locale = (struct __locale_t *) _calloc_r (p, 1, sizeof *new_locale);
+ if (!new_locale)
+ goto error;
+
+ *new_locale = tmp_locale;
+ return new_locale;
+
+error:
+ /* An error occured while we had already (potentially) allocated memory.
+ Free memory and return NULL. errno is supposed to be set already. */
+#ifdef __HAVE_LOCALE_INFO__
+ while (--i > 0)
+ if (tmp_locale.lc_cat[i].buf)
+ _free_r (p, tmp_locale.lc_cat[i].buf);
+#endif
+
+ return NULL;
+}
+
+struct __locale_t *
+_uselocale_r (struct _reent *p, struct __locale_t *newloc)
+{
+ struct __locale_t *current_locale;
+
+ current_locale = __get_locale_r (p);
+ if (!current_locale)
+ current_locale = LC_GLOBAL_LOCALE;
+
+ if (newloc == LC_GLOBAL_LOCALE)
+ p->_locale = NULL;
+ else if (newloc)
+ p->_locale = newloc;
+
+ return current_locale;
+}
+
#ifndef _REENT_ONLY
char *
@@ -1024,4 +1251,27 @@ _DEFUN_VOID (localeconv)
return _localeconv_r (_REENT);
}
+struct __locale_t *
+newlocale (int category_mask, const char *locale, struct __locale_t *base)
+{
+ return _newlocale_r (_REENT, category_mask, locale, base);
+}
+
+void
+freelocale (struct __locale_t *locobj)
+{
+ _freelocale_r (_REENT, locobj);
+}
+
+struct __locale_t *
+duplocale (struct __locale_t *locobj)
+{
+ return _duplocale_r (_REENT, locobj);
+}
+
+struct __locale_t *
+uselocale (struct __locale_t *newloc)
+{
+ return _uselocale_r (_REENT, newloc);
+}
#endif