diff options
Diffstat (limited to 'src/locale/setlocale.c')
-rw-r--r-- | src/locale/setlocale.c | 72 |
1 files changed, 27 insertions, 45 deletions
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; } |