simplify newlocale and allow failure for explicit locale names
authorRich Felker <dalias@aerifal.cx>
Sun, 21 Oct 2018 05:09:20 +0000 (01:09 -0400)
committerRich Felker <dalias@aerifal.cx>
Mon, 22 Oct 2018 04:20:10 +0000 (00:20 -0400)
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.

src/locale/newlocale.c

index 8fb006a7fcdb934ec7031942f5fa1cb6eda6888c..68574605ab10b1de5d10181a9d9982ee45a66dca 100644 (file)
@@ -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;