fix wide printf forms ignoring width for %lc format specifier
[musl] / src / locale / dcngettext.c
index eefa31a..0b53286 100644 (file)
@@ -9,6 +9,13 @@
 #include "locale_impl.h"
 #include "atomic.h"
 #include "pleval.h"
+#include "lock.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define calloc __libc_calloc
+#define realloc undef
+#define free undef
 
 struct binding {
        struct binding *next;
@@ -33,9 +40,11 @@ static char *gettextdir(const char *domainname, size_t *dirlen)
        return 0;
 }
 
+static volatile int lock[1];
+volatile int *const __gettext_lockptr = lock;
+
 char *bindtextdomain(const char *domainname, const char *dirname)
 {
-       static volatile int lock[1];
        struct binding *p, *q;
 
        if (!domainname) return 0;
@@ -99,8 +108,8 @@ struct msgcat {
        struct msgcat *next;
        const void *map;
        size_t map_size;
-       void *volatile plural_rule;
-       volatile int nplurals;
+       const char *plural_rule;
+       int nplurals;
        struct binding *binding;
        const struct __locale_map *lm;
        int cat;
@@ -121,6 +130,10 @@ char *dcngettext(const char *domainname, const char *msgid1, const char *msgid2,
        const struct __locale_map *lm;
        size_t domlen;
        struct binding *q;
+       int old_errno = errno;
+
+       /* match gnu gettext behaviour */
+       if (!msgid1) goto notrans;
 
        if ((unsigned)category >= LC_ALL) goto notrans;
 
@@ -137,6 +150,7 @@ char *dcngettext(const char *domainname, const char *msgid1, const char *msgid2,
        lm = loc->cat[category];
        if (!lm) {
 notrans:
+               errno = old_errno;
                return (char *) ((n == 1) ? msgid1 : msgid2);
        }
 
@@ -199,20 +213,7 @@ notrans:
                p->lm = lm;
                p->map = map;
                p->map_size = map_size;
-               do {
-                       old_cats = cats;
-                       p->next = old_cats;
-               } while (a_cas_p(&cats, old_cats, p) != old_cats);
-       }
-
-       const char *trans = __mo_lookup(p->map, p->map_size, msgid1);
-       if (!trans) goto notrans;
-
-       /* Non-plural-processing gettext forms pass a null pointer as
-        * msgid2 to request that dcngettext suppress plural processing. */
-       if (!msgid2) return (char *)trans;
 
-       if (!p->plural_rule) {
                const char *rule = "n!=1;";
                unsigned long np = 2;
                const char *r = __mo_lookup(p->map, p->map_size, "");
@@ -236,10 +237,22 @@ notrans:
                                        rule = r+7;
                        }
                }
-               a_store(&p->nplurals, np);
-               a_cas_p(&p->plural_rule, 0, (void *)rule);
+               p->nplurals = np;
+               p->plural_rule = rule;
+
+               do {
+                       old_cats = cats;
+                       p->next = old_cats;
+               } while (a_cas_p(&cats, old_cats, p) != old_cats);
        }
-       if (p->nplurals) {
+
+       const char *trans = __mo_lookup(p->map, p->map_size, msgid1);
+       if (!trans) goto notrans;
+
+       /* Non-plural-processing gettext forms pass a null pointer as
+        * msgid2 to request that dcngettext suppress plural processing. */
+
+       if (msgid2 && p->nplurals) {
                unsigned long plural = __pleval(p->plural_rule, n);
                if (plural > p->nplurals) goto notrans;
                while (plural--) {
@@ -250,6 +263,7 @@ notrans:
                        trans += l+1;
                }
        }
+       errno = old_errno;
        return (char *)trans;
 }