diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/internal/libc.h | 4 | ||||
-rw-r--r-- | src/internal/locale_impl.h | 8 | ||||
-rw-r--r-- | src/locale/__lctrans.c | 2 | ||||
-rw-r--r-- | src/locale/__setlocalecat.c | 116 | ||||
-rw-r--r-- | src/locale/dcngettext.c | 28 | ||||
-rw-r--r-- | src/locale/duplocale.c | 11 | ||||
-rw-r--r-- | src/locale/newlocale.c | 7 | ||||
-rw-r--r-- | src/locale/setlocale.c | 72 |
8 files changed, 112 insertions, 136 deletions
diff --git a/src/internal/libc.h b/src/internal/libc.h index 212f0e8b..6810cd8b 100644 --- a/src/internal/libc.h +++ b/src/internal/libc.h @@ -8,9 +8,7 @@ struct __locale_map; struct __locale_struct { - volatile int ctype_utf8; - char *messages_name; - struct __locale_map *volatile cat[4]; + const struct __locale_map *volatile cat[6]; }; struct __libc { diff --git a/src/internal/locale_impl.h b/src/internal/locale_impl.h index 5aebbf68..9b8385e9 100644 --- a/src/internal/locale_impl.h +++ b/src/internal/locale_impl.h @@ -9,20 +9,20 @@ struct __locale_map { const void *map; size_t map_size; char name[LOCALE_NAME_MAX+1]; - struct __locale_map *next; + const struct __locale_map *next; }; -int __setlocalecat(locale_t, int, const char *); +const struct __locale_map *__get_locale(int, const char *); const char *__mo_lookup(const void *, size_t, const char *); const char *__lctrans(const char *, const struct __locale_map *); const char *__lctrans_cur(const char *); -#define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)-2]) +#define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)]) #define LCTRANS_CUR(msg) __lctrans_cur(msg) #define CURRENT_LOCALE (__pthread_self()->locale) -#define CURRENT_UTF8 (__pthread_self()->locale->ctype_utf8) +#define CURRENT_UTF8 (!!__pthread_self()->locale->cat[LC_CTYPE]) #undef MB_CUR_MAX #define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1) diff --git a/src/locale/__lctrans.c b/src/locale/__lctrans.c index 15994c57..107fe14a 100644 --- a/src/locale/__lctrans.c +++ b/src/locale/__lctrans.c @@ -16,5 +16,5 @@ const char *__lctrans(const char *msg, const struct __locale_map *lm) const char *__lctrans_cur(const char *msg) { - return __lctrans_impl(msg, CURRENT_LOCALE->cat[LC_MESSAGES-2]); + return __lctrans_impl(msg, CURRENT_LOCALE->cat[LC_MESSAGES]); } diff --git a/src/locale/__setlocalecat.c b/src/locale/__setlocalecat.c index e829da56..30aa7fcc 100644 --- a/src/locale/__setlocalecat.c +++ b/src/locale/__setlocalecat.c @@ -15,24 +15,60 @@ 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 const char envvars[][12] = { + "LC_CTYPE", + "LC_NUMERIC", + "LC_TIME", + "LC_COLLATE", + "LC_MONETARY", + "LC_MESSAGES", +}; + +static const uint32_t empty_mo[] = { 0x950412de, 0, -1, -1, -1 }; + +static const struct __locale_map c_dot_utf8 = { + .map = empty_mo, + .map_size = sizeof empty_mo, + .name = "C.UTF-8" +}; + +const struct __locale_map *__get_locale(int cat, const char *val) { static int lock[2]; static void *volatile loc_head; - struct __locale_map *p, *new = 0; + const struct __locale_map *p; + struct __locale_map *new = 0; const char *path = 0, *z; char buf[256]; - size_t l; - const void *map; - size_t map_size; + size_t l, n; + + if (!*val) { + (val = getenv("LC_ALL")) && *val || + (val = getenv(envvars[cat])) && *val || + (val = getenv("LANG")) && *val || + (val = "C.UTF-8"); + } + + /* Limit name length and forbid leading dot or any slashes. */ + for (n=0; n<LOCALE_NAME_MAX && val[n] && val[n]!='/'; n++); + if (val[0]=='.' || val[n]) val = "C.UTF-8"; + int builtin = (val[0]=='C' && !val[1]) + || !strcmp(val, "C.UTF-8") + || !strcmp(val, "POSIX"); + + if (builtin) { + if (cat == LC_CTYPE && val[1]=='.') + return (void *)&c_dot_utf8; + return 0; + } for (p=loc_head; p; p=p->next) - if (!strcmp(name, p->name)) return p; + if (!strcmp(val, p->name)) return p; LOCK(lock); for (p=loc_head; p; p=p->next) - if (!strcmp(name, p->name)) { + if (!strcmp(val, p->name)) { UNLOCK(lock); return p; } @@ -46,9 +82,10 @@ static struct __locale_map *findlocale(const char *name, size_t n) if (l >= sizeof buf - n - 2) continue; memcpy(buf, path, l); buf[l] = '/'; - memcpy(buf+l+1, name, n); + memcpy(buf+l+1, val, n); buf[l+1+n] = 0; - map = __map_file(buf, &map_size); + size_t map_size; + const void *map = __map_file(buf, &map_size); if (map) { new = malloc(sizeof *new); if (!new) { @@ -57,58 +94,31 @@ static struct __locale_map *findlocale(const char *name, size_t n) } new->map = map; new->map_size = map_size; - memcpy(new->name, name, n); + memcpy(new->name, val, n); new->name[n] = 0; new->next = loc_head; loc_head = new; break; } } - UNLOCK(lock); - return new; -} - -static const char envvars[][12] = { - "LC_CTYPE", - "LC_NUMERIC", - "LC_TIME", - "LC_COLLATE", - "LC_MONETARY", - "LC_MESSAGES", -}; -int __setlocalecat(locale_t loc, int cat, const char *val) -{ - if (!*val) { - (val = getenv("LC_ALL")) && *val || - (val = getenv(envvars[cat])) && *val || - (val = getenv("LANG")) && *val || - (val = "C.UTF-8"); + /* If no locale definition was found, make a locale map + * object anyway to store the name, which is kept for the + * sake of being able to do message translations at the + * application level. */ + if (!new && (new = malloc(sizeof *new))) { + new->map = empty_mo; + new->map_size = sizeof empty_mo; + memcpy(new->name, val, n); + new->name[n] = 0; + new->next = loc_head; + loc_head = new; } - size_t n; - for (n=0; n<LOCALE_NAME_MAX && val[n] && val[n]!='/'; n++); - if (val[0]=='.' || val[n]) val = "C.UTF-8"; - int builtin = (val[0]=='C' && !val[1]) - || !strcmp(val, "C.UTF-8") - || !strcmp(val, "POSIX"); + /* For LC_CTYPE, never return a null pointer unless the + * requested name was "C" or "POSIX". */ + if (!new && cat == LC_CTYPE) new = (void *)&c_dot_utf8; - switch (cat) { - case LC_CTYPE: - loc->ctype_utf8 = !builtin || val[1]=='.'; - break; - case LC_MESSAGES: - if (builtin) { - loc->messages_name[0] = 0; - } else { - memcpy(loc->messages_name, val, n); - loc->messages_name[n] = 0; - } - /* fall through */ - default: - loc->cat[cat-2] = builtin ? 0 : findlocale(val, n); - case LC_NUMERIC: - break; - } - return 0; + UNLOCK(lock); + return new; } diff --git a/src/locale/dcngettext.c b/src/locale/dcngettext.c index 30dd41d4..a5ff8475 100644 --- a/src/locale/dcngettext.c +++ b/src/locale/dcngettext.c @@ -84,13 +84,15 @@ 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; @@ -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 || !*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; diff --git a/src/locale/duplocale.c b/src/locale/duplocale.c index b87c933e..030b64cb 100644 --- a/src/locale/duplocale.c +++ b/src/locale/duplocale.c @@ -5,17 +5,10 @@ locale_t __duplocale(locale_t old) { - locale_t new = calloc(1, sizeof *new + LOCALE_NAME_MAX + 1); + locale_t new = malloc(sizeof *new); if (!new) return 0; - new->messages_name = (void *)(new+1); - if (old == LC_GLOBAL_LOCALE) old = &libc.global_locale; - new->ctype_utf8 = old->ctype_utf8; - if (old->messages_name) - strcpy(new->messages_name, old->messages_name); - - for (size_t i=0; i<sizeof new->cat/sizeof new->cat[0]; i++) - new->cat[i] = old->cat[i]; + *new = *old; return new; } diff --git a/src/locale/newlocale.c b/src/locale/newlocale.c index 39501d0c..4e0cbd34 100644 --- a/src/locale/newlocale.c +++ b/src/locale/newlocale.c @@ -8,17 +8,16 @@ locale_t __newlocale(int mask, const char *name, locale_t loc) int i; if (!loc) { - loc = calloc(1, sizeof *loc + LOCALE_NAME_MAX + 1); + loc = malloc(sizeof *loc); if (!loc) return 0; - loc->messages_name = (void *)(loc+1); for (i=0; i<LC_ALL; i++) if (!(mask & (1<<i))) - __setlocalecat(loc, i, ""); + loc->cat[i] = __get_locale(i, ""); } for (i=0; i<LC_ALL; i++) if (mask & (1<<i)) - __setlocalecat(loc, i, name); + loc->cat[i] = __get_locale(i, name); return loc; } diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c index 32a8fcab..8dae5a4e 100644 --- a/src/locale/setlocale.c +++ b/src/locale/setlocale.c @@ -5,38 +5,23 @@ #include "libc.h" #include "atomic.h" -static char buf[2+4*(LOCALE_NAME_MAX+1)]; +static char buf[LC_ALL*(LOCALE_NAME_MAX+1)]; static char *setlocale_one_unlocked(int cat, const char *name) { - struct __locale_map *lm; + const struct __locale_map *lm; - if (name) __setlocalecat(&libc.global_locale, cat, name); + if (name) libc.global_locale.cat[cat] = lm = __get_locale(cat, name); + else lm = libc.global_locale.cat[cat]; - 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: - lm = libc.global_locale.cat[cat-2]; - return lm ? lm->name : "C"; - } + return lm ? (char *)lm->name : "C"; } +char *__strchrnul(const char *, int); + char *setlocale(int cat, const char *name) { static volatile int lock[2]; - 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); - } if ((unsigned)cat > LC_ALL) return 0; @@ -48,34 +33,31 @@ char *setlocale(int cat, const char *name) * performs both the serialization and deserialization, depends * on the format, so it can easily be changed if needed. */ if (cat == LC_ALL) { + int i; if (name) { - char part[LOCALE_NAME_MAX+1]; - if (name[0] && name[1]==';' - && strlen(name) > 2 + 3*(LOCALE_NAME_MAX+1)) { - part[0] = name[0]; - part[1] = 0; - setlocale(LC_CTYPE, part); - part[LOCALE_NAME_MAX] = 0; - for (i=LC_TIME; i<LC_MESSAGES; i++) { - memcpy(part, name + 2 + (i-2)*(LOCALE_NAME_MAX+1), LOCALE_NAME_MAX); - for (j=LOCALE_NAME_MAX-1; j && part[j]==';'; j--) - part[j] = 0; - setlocale_one_unlocked(i, part); + char part[LOCALE_NAME_MAX+1] = "C.UTF-8"; + const char *p = name; + for (i=0; i<LC_ALL; i++) { + const char *z = __strchrnul(p, ';'); + if (z-p <= LOCALE_NAME_MAX) { + memcpy(part, p, z-p); + part[z-p] = 0; + if (*z) p = z+1; } - setlocale_one_unlocked(LC_MESSAGES, name - + 2 + 3*(LOCALE_NAME_MAX+1)); - } else { - for (i=0; i<LC_ALL; i++) - setlocale_one_unlocked(i, name); + setlocale_one_unlocked(i, part); } } - 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)); + char *s = buf; + for (i=0; i<LC_ALL; i++) { + const struct __locale_map *lm = + libc.global_locale.cat[i]; + const char *part = lm ? lm->name : "C"; + size_t l = strlen(part); + memcpy(s, part, l); + s[l] = ';'; + s += l+1; } + *--s = 0; UNLOCK(lock); return buf; } |