char * _setlocale_r (struct _reent *p, int category, const char *locale) { #ifndef _MB_CAPABLE if (locale) { if (strcmp (locale, "POSIX") && strcmp (locale, "C") && strcmp (locale, "")) return NULL; } return "C"; #else /* _MB_CAPABLE */ static char new_categories[_LC_LAST][ENCODING_LEN + 1]; static char saved_categories[_LC_LAST][ENCODING_LEN + 1]; int i, j, len, saverr; const char *env, *r; if (category < LC_ALL || category >= _LC_LAST) { p->_errno = EINVAL; return NULL; } if (locale == NULL) return category != LC_ALL ? __get_global_locale ()->categories[category] : currentlocale(); /* * Default to the current locale for everything. */ for (i = 1; i < _LC_LAST; ++i) strcpy (new_categories[i], __get_global_locale ()->categories[i]); /* * Now go fill up new_categories from the locale argument */ if (!*locale) { if (category == LC_ALL) { for (i = 1; i < _LC_LAST; ++i) { env = __get_locale_env (p, i); if (strlen (env) > ENCODING_LEN) { p->_errno = EINVAL; return NULL; } strcpy (new_categories[i], env); } } else { env = __get_locale_env (p, category); if (strlen (env) > ENCODING_LEN) { p->_errno = EINVAL; return NULL; } strcpy (new_categories[category], env); } } else if (category != LC_ALL) { if (strlen (locale) > ENCODING_LEN) { p->_errno = EINVAL; return NULL; } strcpy (new_categories[category], locale); } else { if ((r = strchr (locale, '/')) == NULL) { if (strlen (locale) > ENCODING_LEN) { p->_errno = EINVAL; return NULL; } for (i = 1; i < _LC_LAST; ++i) strcpy (new_categories[i], locale); } else { for (i = 1; r[1] == '/'; ++r) ; if (!r[1]) { p->_errno = EINVAL; return NULL; /* Hmm, just slashes... */ } do { if (i == _LC_LAST) break; /* Too many slashes... */ if ((len = r - locale) > ENCODING_LEN) { p->_errno = EINVAL; return NULL; } strlcpy (new_categories[i], locale, len + 1); i++; while (*r == '/') r++; locale = r; while (*r && *r != '/') r++; } while (*locale); while (i < _LC_LAST) { strcpy (new_categories[i], new_categories[i-1]); i++; } } } if (category != LC_ALL) return __loadlocale (__get_global_locale (), category, new_categories[category]); for (i = 1; i < _LC_LAST; ++i) { strcpy (saved_categories[i], __get_global_locale ()->categories[i]); if (__loadlocale (__get_global_locale (), i, new_categories[i]) == NULL) { saverr = p->_errno; for (j = 1; j < i; j++) { strcpy (new_categories[j], saved_categories[j]); if (__loadlocale (__get_global_locale (), j, new_categories[j]) == NULL) { strcpy (new_categories[j], "C"); __loadlocale (__get_global_locale (), j, new_categories[j]); } } p->_errno = saverr; return NULL; } } return currentlocale (); #endif /* _MB_CAPABLE */ }
struct __locale_t * _newlocale_r (struct _reent *p, int category_mask, const char *locale, struct __locale_t *base) { #ifndef _MB_CAPABLE return __get_C_locale (); #else /* _MB_CAPABLE */ char new_categories[_LC_LAST][ENCODING_LEN + 1]; 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 __get_C_locale (); /* Start with setting all values to the default locale values. */ tmp_locale = *__get_C_locale (); /* Fill out new category strings. */ for (i = 1; i < _LC_LAST; ++i) { if (((1 << i) & category_mask) != 0) { /* If locale is "", fetch from environment. Otherwise use locale name verbatim. */ const char *cat = (locale[0] == '\0') ? __get_locale_env (p, i) : locale; if (strlen (cat) > ENCODING_LEN) { p->_errno = EINVAL; return NULL; } strcpy (new_categories[i], cat); } else strcpy (new_categories[i], base ? base->categories[i] : "C"); } /* Now go over all categories and set them. */ for (i = 1; i < _LC_LAST; ++i) { /* If we have a base locale, and the category is not in category_mask or the new category is the base categroy, just copy over. */ if (base && (((1 << i) & category_mask) == 0 || !strcmp (base->categories[i], new_categories[i]))) { strcpy (tmp_locale.categories[i], new_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__ /* Mark the values 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].ptr = base->lc_cat[i].ptr; tmp_locale.lc_cat[i].buf = (void *) -1; #else /* !__HAVE_LOCALE_INFO__ */ 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 /* !__HAVE_LOCALE_INFO__ */ } /* Otherwise, if the category is in category_mask, create entry. */ else if (((1 << i) & category_mask) != 0) { /* Nothing to do for "C"/"POSIX" locale. */ if (!strcmp (new_categories[i], "C") || !strcmp (new_categories[i], "POSIX")) continue; /* Otherwise load locale data. */ else if (!__loadlocale (&tmp_locale, i, new_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; if (base) { #ifdef __HAVE_LOCALE_INFO__ /* Step 2 of copying over.. Make sure to invalidate the copied buffer pointers in base, so the subsequent _freelocale_r (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].ptr = base->lc_cat[i].buf = NULL; } #endif /* __HAVE_LOCALE_INFO__ */ _freelocale_r (p, base); } *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 (((1 << i) & category_mask) != 0 && tmp_locale.lc_cat[i].buf && tmp_locale.lc_cat[i].buf != (const void *) -1) { _free_r (p, (void *) tmp_locale.lc_cat[i].ptr); _free_r (p, tmp_locale.lc_cat[i].buf); } #endif /* __HAVE_LOCALE_INFO__ */ return NULL; #endif /* _MB_CAPABLE */ }
#define NSTRINGS \ (offsetof(_MonetaryLocale, int_frac_digits)/sizeof(const char **)) #define NCHARS \ (offsetof(_MonetaryLocale, int_n_sign_posn) - \ offsetof(_MonetaryLocale, int_frac_digits) + 1) static int _localeio_LC_MONETARY_create_impl(const char * __restrict root, const char * __restrict name, _MonetaryLocale ** __restrict pdata) { char path[PATH_MAX + 1]; int ret; _DIAGASSERT(root != NULL); _DIAGASSERT(name != NULL); _DIAGASSERT(pdata != NULL); snprintf(path, sizeof(path), "%s/%s/LC_MONETARY", root, name); ret = __loadlocale(path, NSTRINGS, NCHARS, sizeof(_MonetaryLocale), (void *)pdata); if (!ret) { (*pdata)->mon_grouping = __fix_locale_grouping_str((*pdata)->mon_grouping); } return ret; } #include "nb_lc_template.h" _LOCALE_CATEGORY_ENTRY(_localeio_LC_MONETARY_);