1#include <locale.h> 2#include <stdlib.h> 3#include <string.h> 4#include "locale_impl.h" 5#include "libc.h" 6#include "atomic.h" 7 8static char buf[LC_ALL*(LOCALE_NAME_MAX+1)]; 9 10static char *setlocale_one_unlocked(int cat, const char *name) 11{ 12 const struct __locale_map *lm; 13 14 if (name) libc.global_locale.cat[cat] = lm = __get_locale(cat, name); 15 else lm = libc.global_locale.cat[cat]; 16 17 return lm ? (char *)lm->name : "C"; 18} 19 20char *__strchrnul(const char *, int); 21 22char *setlocale(int cat, const char *name) 23{ 24 static volatile int lock[2]; 25 26 if ((unsigned)cat > LC_ALL) return 0; 27 28 LOCK(lock); 29 30 /* For LC_ALL, setlocale is required to return a string which 31 * encodes the current setting for all categories. The format of 32 * this string is unspecified, and only the following code, which 33 * performs both the serialization and deserialization, depends 34 * on the format, so it can easily be changed if needed. */ 35 if (cat == LC_ALL) { 36 int i; 37 if (name) { 38 char part[LOCALE_NAME_MAX+1] = "C.UTF-8"; 39 const char *p = name; 40 for (i=0; i<LC_ALL; i++) { 41 const char *z = __strchrnul(p, ';'); 42 if (z-p <= LOCALE_NAME_MAX) { 43 memcpy(part, p, z-p); 44 part[z-p] = 0; 45 if (*z) p = z+1; 46 } 47 setlocale_one_unlocked(i, part); 48 } 49 } 50 char *s = buf; 51 for (i=0; i<LC_ALL; i++) { 52 const struct __locale_map *lm = 53 libc.global_locale.cat[i]; 54 const char *part = lm ? lm->name : "C"; 55 size_t l = strlen(part); 56 memcpy(s, part, l); 57 s[l] = ';'; 58 s += l+1; 59 } 60 *--s = 0; 61 UNLOCK(lock); 62 return buf; 63 } 64 65 char *ret = setlocale_one_unlocked(cat, name); 66 67 UNLOCK(lock); 68 69 return ret; 70} 71