implement locale file loading and state for remaining locale categories
authorRich Felker <dalias@aerifal.cx>
Thu, 24 Jul 2014 07:23:11 +0000 (03:23 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 24 Jul 2014 07:23:11 +0000 (03:23 -0400)
there is still no code which actually uses the loaded locale files, so
the main observable effect of this commit is that calls to setlocale
store and give back the names of the selected locales for the
remaining categories (LC_TIME, LC_COLLATE, LC_MONETARY) if a locale
file by the requested name could be loaded.

src/internal/libc.h
src/internal/locale_impl.h
src/locale/__setlocalecat.c
src/locale/setlocale.c

index 037d16b6e2cddc92a5ae86b101c84cffebca23a1..2eef98e446566ce0a137363f3d9adb8dc7981ff0 100644 (file)
@@ -5,9 +5,12 @@
 #include <stdio.h>
 #include <limits.h>
 
+struct __locale_map;
+
 struct __locale_struct {
        int ctype_utf8;
        char *messages_name;
+       struct __locale_map *cat[4];
 };
 
 struct __libc {
index 2747b85a4b483475cd62fb68f1eb538705fdbb21..0ee72d3e657f966c9c0a22217ac494872169738b 100644 (file)
@@ -5,6 +5,13 @@
 
 #define LOCALE_NAME_MAX 15
 
+struct __locale_map {
+       const void *map;
+       size_t map_size;
+       char name[LOCALE_NAME_MAX+1];
+       struct __locale_map *next;
+};
+
 int __setlocalecat(locale_t, int, const char *);
 
 #define CURRENT_LOCALE \
index a947dbfff8a3388f73cd993e42ec92fa5f538f04..bbecde413f6b772074ca2d6e4be513f3ad1c9189 100644 (file)
@@ -4,6 +4,58 @@
 #include "libc.h"
 #include "atomic.h"
 
+const unsigned char *__map_file(const char *, size_t *);
+int __munmap(void *, size_t);
+char *__strchrnul(const char *, int);
+
+static struct __locale_map *findlocale(const char *name, size_t n)
+{
+       static void *loc_head;
+       struct __locale_map *p, *new, *old_head;
+       const char *path = 0, *z;
+       char buf[256];
+       size_t l;
+       const void *map;
+       size_t map_size;
+
+       for (p=loc_head; p; p=p->next)
+               if (!strcmp(name, p->name)) return p;
+
+       if (strchr(name, '/')) return 0;
+
+       if (!libc.secure) path = getenv("MUSL_LOCPATH");
+       /* FIXME: add a default path? */
+       if (!path) return 0;
+
+       for (; *path; path=z+!!*z) {
+               z = __strchrnul(path, ':');
+               l = z - path - !!*z;
+               if (l >= sizeof buf - n - 2) continue;
+               memcpy(buf, path, l);
+               buf[l] = '/';
+               memcpy(buf+l+1, name, n);
+               buf[l+1+n] = 0;
+               map = __map_file(buf, &map_size);
+               if (map) {
+                       new = malloc(sizeof *new);
+                       if (!new) {
+                               __munmap((void *)map, map_size);
+                               return 0;
+                       }
+                       new->map = map;
+                       new->map_size = map_size;
+                       memcpy(new->name, name, n);
+                       new->name[n] = 0;
+                       do {
+                               old_head = loc_head;
+                               new->next = old_head;
+                       } while (a_cas_p(&loc_head, old_head, new) != old_head);
+                       return new;
+               }
+       }
+       return 0;
+}
+
 static const char envvars[][12] = {
        "LC_CTYPE",
        "LC_NUMERIC",
@@ -26,6 +78,7 @@ int __setlocalecat(locale_t loc, int cat, const char *val)
        int builtin = (val[0]=='C' && !val[1])
                || !strcmp(val, "C.UTF-8")
                || !strcmp(val, "POSIX");
+       struct __locale_map *data, *old;
 
        switch (cat) {
        case LC_CTYPE:
@@ -40,6 +93,11 @@ int __setlocalecat(locale_t loc, int cat, const char *val)
                }
                /* fall through */
        default:
+               data = builtin ? 0 : findlocale(val, n);
+               if (data == loc->cat[cat-2]) break;
+               do old = loc->cat[cat-2];
+               while (a_cas_p(&loc->cat[cat-2], old, data) != old);
+       case LC_NUMERIC:
                break;
        }
        return 0;
index cbc0b5517f04dcd6ce20e721a3d0bc13ba7c9293..8ea389a3c118d570cbc3a0eb54d03ba52df39bf2 100644 (file)
@@ -9,6 +9,9 @@ static char buf[2+4*(LOCALE_NAME_MAX+1)];
 
 char *setlocale(int cat, const char *name)
 {
+       struct __locale_map *lm;
+       int i, j;
+
        if (!libc.global_locale.messages_name) {
                libc.global_locale.messages_name =
                        buf + 2 + 3*(LOCALE_NAME_MAX+1);
@@ -24,7 +27,6 @@ char *setlocale(int cat, const char *name)
        if (cat == LC_ALL) {
                if (name) {
                        char part[LOCALE_NAME_MAX+1];
-                       int i, j;
                        if (name[0] && name[1]==';'
                            && strlen(name) > 2 + 3*(LOCALE_NAME_MAX+1)) {
                                part[0] = name[0];
@@ -45,6 +47,11 @@ char *setlocale(int cat, const char *name)
                }
                memset(buf, ';', 2 + 3*(LOCALE_NAME_MAX+1));
                buf[0] = libc.global_locale.ctype_utf8 ? 'U' : 'C';
+               for (i=LC_TIME; i<LC_MESSAGES; i++) {
+                       lm = libc.global_locale.cat[i-2];
+                       if (lm) memcpy(buf + 2 + (i-2)*(LOCALE_NAME_MAX+1),
+                               lm->name, strlen(lm->name));
+               }
                return buf;
        }
 
@@ -58,10 +65,13 @@ char *setlocale(int cat, const char *name)
        switch (cat) {
        case LC_CTYPE:
                return libc.global_locale.ctype_utf8 ? "C.UTF-8" : "C";
+       case LC_NUMERIC:
+               return "C";
        case LC_MESSAGES:
                return libc.global_locale.messages_name[0]
                        ? libc.global_locale.messages_name : "C";
        default:
-               return "C";
+               lm = libc.global_locale.cat[cat-2];
+               return lm ? lm->name : "C";
        }
 }