1 /**
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <locale.h>
17 #include <string.h>
18 #include <sys/mman.h>
19 #include "locale_impl.h"
20 #include "libc.h"
21 #include "lock.h"
22
__lctrans_impl(const char * msg,const struct __locale_map * lm)23 const char *__lctrans_impl(const char *msg, const struct __locale_map *lm)
24 {
25 const char *trans = 0;
26 if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg);
27 return trans ? trans : msg;
28 }
29
30 static const char envvars[][18] = {
31 "LC_CTYPE",
32 "LC_NUMERIC",
33 "LC_TIME",
34 "LC_COLLATE",
35 "LC_MONETARY",
36 "LC_MESSAGES",
37 "LC_PAPER",
38 "LC_NAME",
39 "LC_ADDRESS",
40 "LC_TELEPHONE",
41 "LC_MEASUREMENT",
42 "LC_IDENTIFICATION",
43 };
44
__get_locale(int cat,const char * val)45 const struct __locale_map *__get_locale(int cat, const char *val)
46 {
47 static volatile int lock[1];
48 static void *volatile loc_head;
49 const struct __locale_map *p;
50 struct __locale_map *new = 0;
51 const char *path = 0, *z;
52 char buf[256];
53 size_t l, n;
54 if (!*val) {
55 (val = getenv("LC_ALL")) && *val ||
56 (val = getenv(envvars[cat])) && *val ||
57 (val = getenv("LANG")) && *val ||
58 (val = "C.UTF-8");
59 }
60
61 /* Limit name length and forbid leading dot or any slashes. */
62 for (n=0; n<LOCALE_NAME_MAX && val[n] && val[n]!='/'; n++);
63 if (val[0]=='.' || val[n]) {
64 val = "C.UTF-8";
65 }
66 int builtin = (val[0]=='C' && !val[1])
67 || !strcmp(val, "C.UTF-8")
68 || !strcmp(val, "POSIX");
69
70 if (builtin) {
71 if (cat == LC_CTYPE && val[1]=='.')
72 return (void *)&__c_dot_utf8;
73 return 0;
74 }
75
76 for (p=loc_head; p; p=p->next) {
77 if (!strcmp(val, p->name)) {
78 return p;
79 }
80 }
81
82 LOCK(lock);
83
84 for (p=loc_head; p; p=p->next) {
85 if (!strcmp(val, p->name)) {
86 UNLOCK(lock);
87 return p;
88 }
89 }
90
91 if (!libc.secure) {
92 path = getenv("MUSL_LOCPATH");
93 }
94
95 if (path) {
96 for (; *path; path=z+!!*z) {
97 z = __strchrnul(path, ':');
98 l = z - path - !!*z;
99 if (l >= sizeof buf - n - 2) {
100 continue;
101 }
102 memcpy(buf, path, l);
103 buf[l] = '/';
104 memcpy(buf+l+1, val, n);
105 buf[l+1+n] = 0;
106 size_t map_size;
107 const void *map = __map_file(buf, &map_size);
108 if (map) {
109 new = malloc(sizeof *new);
110 if (!new) {
111 __munmap((void *)map, map_size);
112 break;
113 }
114 new->map = map;
115 new->map_size = map_size;
116 memcpy(new->name, val, n);
117 new->name[n] = 0;
118 new->next = loc_head;
119 loc_head = new;
120 break;
121 }
122 }
123 }
124
125 /* If no locale definition was found, make a locale map
126 * object anyway to store the name, which is kept for the
127 * sake of being able to do message translations at the
128 * application level. */
129 if (!new && (new = malloc(sizeof *new))) {
130 new->map = __c_dot_utf8.map;
131 new->map_size = __c_dot_utf8.map_size;
132 memcpy(new->name, val, n);
133 new->name[n] = 0;
134 new->next = loc_head;
135 loc_head = new;
136 }
137
138 /* For LC_CTYPE, never return a null pointer unless the
139 * requested name was "C" or "POSIX". */
140 if (!new && cat == LC_CTYPE) new = (void *)&__c_dot_utf8;
141
142 UNLOCK(lock);
143 return new;
144 }
145