overhaul locale internals to treat categories roughly uniformly
[musl] / src / locale / dcngettext.c
index 51e6522..a5ff847 100644 (file)
@@ -12,7 +12,7 @@
 struct binding {
        struct binding *next;
        int dirlen;
-       int active;
+       volatile int active;
        char *domainname;
        char *dirname;
        char buf[];
@@ -34,7 +34,7 @@ static char *gettextdir(const char *domainname, size_t *dirlen)
 
 char *bindtextdomain(const char *domainname, const char *dirname)
 {
-       static int lock[2];
+       static volatile int lock[2];
        struct binding *p, *q;
 
        if (!domainname) return 0;
@@ -84,20 +84,22 @@ char *bindtextdomain(const char *domainname, const char *dirname)
 }
 
 static const char catnames[][12] = {
+       "LC_CTYPE",
+       "LC_NUMERIC",
        "LC_TIME",
        "LC_COLLATE",
        "LC_MONETARY",
        "LC_MESSAGES",
 };
 
-static const char catlens[] = { 7, 10, 11, 11 };
+static const char catlens[] = { 8, 10, 7, 10, 11, 11 };
 
 struct msgcat {
        struct msgcat *next;
        const void *map;
        size_t map_size;
-       void *plural_rule;
-       int nplurals;
+       void *volatile plural_rule;
+       volatile int nplurals;
        char name[];
 };
 
@@ -117,10 +119,12 @@ char *dcngettext(const char *domainname, const char *msgid1, const char *msgid2,
        static struct msgcat *volatile cats;
        struct msgcat *p;
        struct __locale_struct *loc = CURRENT_LOCALE;
-       struct __locale_map *lm;
+       const struct __locale_map *lm;
        const char *dirname, *locname, *catname;
        size_t dirlen, loclen, catlen, domlen;
 
+       if ((unsigned)category >= LC_ALL) goto notrans;
+
        if (!domainname) domainname = __gettextdomain();
 
        domlen = strlen(domainname);
@@ -129,25 +133,15 @@ char *dcngettext(const char *domainname, const char *msgid1, const char *msgid2,
        dirname = gettextdir(domainname, &dirlen);
        if (!dirname) goto notrans;
 
-       switch (category) {
-       case LC_MESSAGES:
-               locname = loc->messages_name;
-               if (!*locname) goto notrans;
-               break;
-       case LC_TIME:
-       case LC_MONETARY:
-       case LC_COLLATE:
-               lm = loc->cat[category-2];
-               if (!lm) goto notrans;
-               locname = lm->name;
-               break;
-       default:
+       lm = loc->cat[category];
+       if (!lm) {
 notrans:
                return (char *) ((n == 1) ? msgid1 : msgid2);
        }
+       locname = lm->name;
 
-       catname = catnames[category-2];
-       catlen = catlens[category-2];
+       catname = catnames[category];
+       catlen = catlens[category];
        loclen = strlen(locname);
 
        size_t namelen = dirlen+1 + loclen+1 + catlen+1 + domlen+3;
@@ -229,8 +223,9 @@ notrans:
                unsigned long plural = __pleval(p->plural_rule, n);
                if (plural > p->nplurals) goto notrans;
                while (plural--) {
-                       size_t l = strlen(trans);
-                       if (l+1 >= p->map_size - (trans - (char *)p->map))
+                       size_t rem = p->map_size - (trans - (char *)p->map);
+                       size_t l = strnlen(trans, rem);
+                       if (l+1 >= rem)
                                goto notrans;
                        trans += l+1;
                }