summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2018-10-21 01:09:20 -0400
committerRich Felker <dalias@aerifal.cx>2018-10-22 00:20:10 -0400
commit74e704006a0004058fc38806a19c1552b1e2463d (patch)
tree9cdfabba89d161a991ed93e0b9d368a59215c4b2 /src
parent6753fb68b84cd7155d8b9a3a3bc3eff1ab6a8030 (diff)
downloadmusl-74e704006a0004058fc38806a19c1552b1e2463d.tar.gz
simplify newlocale and allow failure for explicit locale names
unify the code paths for allocated and non-allocated locale objects, always using a tmp object. this is necessary to avoid clobbering the base locale object too soon if we allow for the possibility that looking up an explicitly requested locale name may fail, and makes the code simpler and cleaner anyway. eliminate the complex and fragile logic for checking whether one of the non-allocated locale objects can be used for the result, and instead just memcmp against each of them.
Diffstat (limited to 'src')
-rw-r--r--src/locale/newlocale.c37
1 files changed, 14 insertions, 23 deletions
diff --git a/src/locale/newlocale.c b/src/locale/newlocale.c
index 8fb006a7..68574605 100644
--- a/src/locale/newlocale.c
+++ b/src/locale/newlocale.c
@@ -9,37 +9,28 @@ int __loc_is_allocated(locale_t loc)
locale_t __newlocale(int mask, const char *name, locale_t loc)
{
- int i, j;
struct __locale_struct tmp;
- const struct __locale_map *lm;
+
+ for (int i=0; i<LC_ALL; i++) {
+ tmp.cat[i] = (!(mask & (1<<i)) && loc) ? loc->cat[i] :
+ __get_locale(i, (mask & (1<<i)) ? name : "");
+ if (tmp.cat[i] == LOC_MAP_FAILED)
+ return 0;
+ }
/* For locales with allocated storage, modify in-place. */
if (__loc_is_allocated(loc)) {
- for (i=0; i<LC_ALL; i++)
- if (mask & (1<<i))
- loc->cat[i] = __get_locale(i, name);
+ *loc = tmp;
return loc;
}
- /* Otherwise, build a temporary locale object, which will only
- * be instantiated in allocated storage if it does not match
- * one of the built-in static locales. This makes the common
- * usage case for newlocale, getting a C locale with predictable
- * behavior, very fast, and more importantly, fail-safe. */
- for (j=i=0; i<LC_ALL; i++) {
- if (loc && !(mask & (1<<i)))
- lm = loc->cat[i];
- else
- lm = __get_locale(i, mask & (1<<i) ? name : "");
- if (lm) j++;
- tmp.cat[i] = lm;
- }
-
- if (!j)
- return C_LOCALE;
- if (j==1 && tmp.cat[LC_CTYPE]==&__c_dot_utf8)
- return UTF8_LOCALE;
+ /* Otherwise, first see if we can use one of the builtin locales.
+ * This makes the common usage case for newlocale, getting a C locale
+ * with predictable behavior, very fast, and more importantly, fail-safe. */
+ if (!memcmp(&tmp, C_LOCALE, sizeof tmp)) return C_LOCALE;
+ if (!memcmp(&tmp, UTF8_LOCALE, sizeof tmp)) return UTF8_LOCALE;
+ /* If no builtin locale matched, attempt to allocate and copy. */
if ((loc = malloc(sizeof *loc))) *loc = tmp;
return loc;