• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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