OLD | NEW |
(Empty) | |
| 1 #include <locale.h> |
| 2 #include <string.h> |
| 3 #include "locale_impl.h" |
| 4 #include "libc.h" |
| 5 #include "atomic.h" |
| 6 |
| 7 const char *__lctrans_impl(const char *msg, const struct __locale_map *lm) |
| 8 { |
| 9 const char *trans = 0; |
| 10 if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg); |
| 11 return trans ? trans : msg; |
| 12 } |
| 13 |
| 14 const unsigned char *__map_file(const char *, size_t *); |
| 15 int __munmap(void *, size_t); |
| 16 char *__strchrnul(const char *, int); |
| 17 |
| 18 static const char envvars[][12] = { |
| 19 "LC_CTYPE", |
| 20 "LC_NUMERIC", |
| 21 "LC_TIME", |
| 22 "LC_COLLATE", |
| 23 "LC_MONETARY", |
| 24 "LC_MESSAGES", |
| 25 }; |
| 26 |
| 27 const struct __locale_map *__get_locale(int cat, const char *val) |
| 28 { |
| 29 static int lock[2]; |
| 30 static void *volatile loc_head; |
| 31 const struct __locale_map *p; |
| 32 struct __locale_map *new = 0; |
| 33 const char *path = 0, *z; |
| 34 char buf[256]; |
| 35 size_t l, n; |
| 36 |
| 37 if (!*val) { |
| 38 (val = getenv("LC_ALL")) && *val || |
| 39 (val = getenv(envvars[cat])) && *val || |
| 40 (val = getenv("LANG")) && *val || |
| 41 (val = "C.UTF-8"); |
| 42 } |
| 43 |
| 44 /* Limit name length and forbid leading dot or any slashes. */ |
| 45 for (n=0; n<LOCALE_NAME_MAX && val[n] && val[n]!='/'; n++); |
| 46 if (val[0]=='.' || val[n]) val = "C.UTF-8"; |
| 47 int builtin = (val[0]=='C' && !val[1]) |
| 48 || !strcmp(val, "C.UTF-8") |
| 49 || !strcmp(val, "POSIX"); |
| 50 |
| 51 if (builtin) { |
| 52 if (cat == LC_CTYPE && val[1]=='.') |
| 53 return (void *)&__c_dot_utf8; |
| 54 return 0; |
| 55 } |
| 56 |
| 57 for (p=loc_head; p; p=p->next) |
| 58 if (!strcmp(val, p->name)) return p; |
| 59 |
| 60 LOCK(lock); |
| 61 |
| 62 for (p=loc_head; p; p=p->next) |
| 63 if (!strcmp(val, p->name)) { |
| 64 UNLOCK(lock); |
| 65 return p; |
| 66 } |
| 67 |
| 68 if (!libc.secure) path = getenv("MUSL_LOCPATH"); |
| 69 /* FIXME: add a default path? */ |
| 70 |
| 71 if (path) for (; *path; path=z+!!*z) { |
| 72 z = __strchrnul(path, ':'); |
| 73 l = z - path - !!*z; |
| 74 if (l >= sizeof buf - n - 2) continue; |
| 75 memcpy(buf, path, l); |
| 76 buf[l] = '/'; |
| 77 memcpy(buf+l+1, val, n); |
| 78 buf[l+1+n] = 0; |
| 79 size_t map_size; |
| 80 const void *map = __map_file(buf, &map_size); |
| 81 if (map) { |
| 82 new = malloc(sizeof *new); |
| 83 if (!new) { |
| 84 __munmap((void *)map, map_size); |
| 85 break; |
| 86 } |
| 87 new->map = map; |
| 88 new->map_size = map_size; |
| 89 memcpy(new->name, val, n); |
| 90 new->name[n] = 0; |
| 91 new->next = loc_head; |
| 92 loc_head = new; |
| 93 break; |
| 94 } |
| 95 } |
| 96 |
| 97 /* If no locale definition was found, make a locale map |
| 98 * object anyway to store the name, which is kept for the |
| 99 * sake of being able to do message translations at the |
| 100 * application level. */ |
| 101 if (!new && (new = malloc(sizeof *new))) { |
| 102 new->map = __c_dot_utf8.map; |
| 103 new->map_size = __c_dot_utf8.map_size; |
| 104 memcpy(new->name, val, n); |
| 105 new->name[n] = 0; |
| 106 new->next = loc_head; |
| 107 loc_head = new; |
| 108 } |
| 109 |
| 110 /* For LC_CTYPE, never return a null pointer unless the |
| 111 * requested name was "C" or "POSIX". */ |
| 112 if (!new && cat == LC_CTYPE) new = (void *)&__c_dot_utf8; |
| 113 |
| 114 UNLOCK(lock); |
| 115 return new; |
| 116 } |
OLD | NEW |