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 <stdlib.h>
20 #include "locale_impl.h"
21 #include "libc.h"
22 #include "lock.h"
23 #include "fork_impl.h"
24
25 #define malloc __libc_malloc
26 #define calloc undef
27 #define realloc undef
28 #define free undef
29
__lctrans_impl(const char * msg,const struct __locale_map * lm)30 const char *__lctrans_impl(const char *msg, const struct __locale_map *lm)
31 {
32 const char *trans = 0;
33 if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg);
34 return trans ? trans : msg;
35 }
36
37 static const char envvars[][18] = {
38 "LC_CTYPE",
39 "LC_NUMERIC",
40 "LC_TIME",
41 "LC_COLLATE",
42 "LC_MONETARY",
43 "LC_MESSAGES",
44 "LC_PAPER",
45 "LC_NAME",
46 "LC_ADDRESS",
47 "LC_TELEPHONE",
48 "LC_MEASUREMENT",
49 "LC_IDENTIFICATION",
50 };
51
52 volatile int __locale_lock[1];
53 volatile int *const __locale_lockptr = __locale_lock;
54
__get_locale(int cat,const char * val)55 const struct __locale_map *__get_locale(int cat, const char *val)
56 {
57 static void *volatile loc_head;
58 const struct __locale_map *p;
59 struct __locale_map *new = 0;
60 const char *path = 0, *z;
61 char buf[256];
62 size_t l, n;
63
64 if (!*val) {
65 (val = getenv("LC_ALL")) && *val ||
66 (val = getenv(envvars[cat])) && *val ||
67 (val = getenv("LANG")) && *val ||
68 (val = "C.UTF-8");
69 }
70
71 /* Limit name length and forbid leading dot or any slashes. */
72 for (n=0; n<LOCALE_NAME_MAX && val[n] && val[n]!='/'; n++);
73 if (val[0]=='.' || val[n]) {
74 val = "C.UTF-8";
75 }
76 int builtin = (val[0]=='C' && !val[1])
77 || !strcmp(val, "POSIX")
78 || !strcmp(val, "en_US");
79
80 if (builtin) {
81 if (cat == LC_CTYPE && val[1] == '.')
82 return (void *)&__c_dot_utf8;
83 return 0;
84 }
85
86 for (p=loc_head; p; p=p->next) {
87 if (!strcmp(val, p->name)) {
88 return p;
89 }
90 }
91
92 if (!strcmp(val, "en_US.UTF-8") || !strcmp(val, "C.UTF-8")) {
93 /* If no locale definition was found, make a locale map
94 * object anyway to store the name, which is kept for the
95 * sake of being able to do message translations at the
96 * application level. */
97 if (!new && (new = malloc(sizeof *new))) {
98 new->map = __c_dot_utf8.map;
99 new->map_size = __c_dot_utf8.map_size;
100 memcpy(new->name, val, n);
101 new->name[n] = 0;
102 new->next = loc_head;
103 new->flag = VALID;
104 loc_head = new;
105 }
106 }
107
108 if (!libc.secure) {
109 path = getenv("MUSL_LOCPATH");
110 }
111
112 if (path) for (; *path; path=z+!!*z) {
113 z = __strchrnul(path, ':');
114 l = z - path;
115 if (l >= sizeof buf - n - 2) {
116 continue;
117 }
118 memcpy(buf, path, l);
119 buf[l] = '/';
120 memcpy(buf+l+1, val, n);
121 buf[l+1+n] = 0;
122 size_t map_size;
123 const void *map = __map_file(buf, &map_size);
124 if (map) {
125 new = malloc(sizeof *new);
126 if (!new) {
127 __munmap((void *)map, map_size);
128 break;
129 }
130 new->map = map;
131 new->map_size = map_size;
132 memcpy(new->name, val, n);
133 new->name[n] = 0;
134 new->next = loc_head;
135 new->flag = VALID;
136 loc_head = new;
137 break;
138 }
139 }
140
141
142 /* If no locale definition was found, make a locale map
143 * object anyway to store the name, which is kept for the
144 * sake of being able to do message translations at the
145 * application level. */
146 if (!new && (new = malloc(sizeof *new))) {
147 new->map = __c_dot_utf8.map;
148 new->map_size = __c_dot_utf8.map_size;
149 memcpy(new->name, val, n);
150 new->name[n] = 0;
151 new->next = loc_head;
152 new->flag = INVALID;
153 loc_head = new;
154 }
155
156 /* For LC_CTYPE, never return a null pointer unless the
157 * requested name was "C" or "POSIX". */
158 if (!new && cat == LC_CTYPE) new = (void *)&__c_dot_utf8;
159
160 return new;
161 }
162
163