]>
Commit | Line | Data |
---|---|---|
5b2abdfb A |
1 | /* |
2 | * Copyright (c) 1991, 1993 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Paul Borman at Krystal Technologies. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. All advertising materials mentioning features or use of this software | |
17 | * must display the following acknowledgement: | |
18 | * This product includes software developed by the University of | |
19 | * California, Berkeley and its contributors. | |
20 | * 4. Neither the name of the University nor the names of its contributors | |
21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | */ | |
36 | ||
37 | #ifdef LIBC_RCS | |
38 | static const char rcsid[] = | |
39 | "$FreeBSD: src/lib/libc/locale/setlocale.c,v 1.25.2.4 2001/03/05 13:08:42 ru Exp $"; | |
40 | #endif | |
41 | ||
42 | #if defined(LIBC_SCCS) && !defined(lint) | |
43 | static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93"; | |
44 | #endif /* LIBC_SCCS and not lint */ | |
45 | ||
46 | #include <sys/types.h> | |
47 | #include <sys/stat.h> | |
48 | #include <limits.h> | |
49 | #include <locale.h> | |
50 | #include <rune.h> | |
51 | #include <stdlib.h> | |
52 | #include <string.h> | |
53 | #include <unistd.h> | |
54 | #include "collate.h" | |
55 | #include "setlocale.h" | |
56 | ||
57 | /* | |
58 | * Category names for getenv() | |
59 | */ | |
60 | static char *categories[_LC_LAST] = { | |
61 | "LC_ALL", | |
62 | "LC_COLLATE", | |
63 | "LC_CTYPE", | |
64 | "LC_MONETARY", | |
65 | "LC_NUMERIC", | |
66 | "LC_TIME", | |
67 | "LC_MESSAGES" | |
68 | }; | |
69 | ||
70 | /* | |
71 | * Current locales for each category | |
72 | */ | |
73 | static char current_categories[_LC_LAST][ENCODING_LEN + 1] = { | |
74 | "C", | |
75 | "C", | |
76 | "C", | |
77 | "C", | |
78 | "C", | |
79 | "C", | |
80 | "C" | |
81 | }; | |
82 | ||
83 | /* | |
84 | * The locales we are going to try and load | |
85 | */ | |
86 | static char new_categories[_LC_LAST][ENCODING_LEN + 1]; | |
87 | static char saved_categories[_LC_LAST][ENCODING_LEN + 1]; | |
88 | ||
89 | static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)]; | |
90 | ||
91 | static char *currentlocale __P((void)); | |
92 | static char *loadlocale __P((int)); | |
93 | static int stub_load_locale __P((const char *)); | |
94 | ||
95 | extern int __time_load_locale __P((const char *)); /* strftime.c */ | |
96 | ||
97 | char * | |
98 | setlocale(category, locale) | |
99 | int category; | |
100 | const char *locale; | |
101 | { | |
102 | int i, j, len; | |
103 | char *env, *r; | |
104 | ||
105 | if (category < LC_ALL || category >= _LC_LAST) | |
106 | return (NULL); | |
107 | ||
108 | if (!locale) | |
109 | return (category != LC_ALL ? | |
110 | current_categories[category] : currentlocale()); | |
111 | ||
112 | /* | |
113 | * Default to the current locale for everything. | |
114 | */ | |
115 | for (i = 1; i < _LC_LAST; ++i) | |
116 | (void)strcpy(new_categories[i], current_categories[i]); | |
117 | ||
118 | /* | |
119 | * Now go fill up new_categories from the locale argument | |
120 | */ | |
121 | if (!*locale) { | |
122 | env = getenv("LC_ALL"); | |
123 | ||
124 | if (category != LC_ALL && (!env || !*env)) | |
125 | env = getenv(categories[category]); | |
126 | ||
127 | if (!env || !*env) | |
128 | env = getenv("LANG"); | |
129 | ||
130 | if (!env || !*env || strchr(env, '/')) | |
131 | env = "C"; | |
132 | ||
133 | (void) strncpy(new_categories[category], env, ENCODING_LEN); | |
134 | new_categories[category][ENCODING_LEN] = '\0'; | |
135 | if (category == LC_ALL) { | |
136 | for (i = 1; i < _LC_LAST; ++i) { | |
137 | if (!(env = getenv(categories[i])) || !*env) | |
138 | env = new_categories[LC_ALL]; | |
139 | (void)strncpy(new_categories[i], env, ENCODING_LEN); | |
140 | new_categories[i][ENCODING_LEN] = '\0'; | |
141 | } | |
142 | } | |
143 | } else if (category != LC_ALL) { | |
144 | (void)strncpy(new_categories[category], locale, ENCODING_LEN); | |
145 | new_categories[category][ENCODING_LEN] = '\0'; | |
146 | } else { | |
147 | if ((r = strchr(locale, '/')) == NULL) { | |
148 | for (i = 1; i < _LC_LAST; ++i) { | |
149 | (void)strncpy(new_categories[i], locale, ENCODING_LEN); | |
150 | new_categories[i][ENCODING_LEN] = '\0'; | |
151 | } | |
152 | } else { | |
153 | for (i = 1; r[1] == '/'; ++r); | |
154 | if (!r[1]) | |
155 | return (NULL); /* Hmm, just slashes... */ | |
156 | do { | |
157 | len = r - locale > ENCODING_LEN ? ENCODING_LEN : r - locale; | |
158 | (void)strncpy(new_categories[i], locale, len); | |
159 | new_categories[i][len] = '\0'; | |
160 | i++; | |
161 | locale = r; | |
162 | while (*locale == '/') | |
163 | ++locale; | |
164 | while (*++r && *r != '/'); | |
165 | } while (*locale); | |
166 | while (i < _LC_LAST) { | |
167 | (void)strcpy(new_categories[i], | |
168 | new_categories[i-1]); | |
169 | i++; | |
170 | } | |
171 | } | |
172 | } | |
173 | ||
174 | if (category) | |
175 | return (loadlocale(category)); | |
176 | ||
177 | for (i = 1; i < _LC_LAST; ++i) { | |
178 | (void)strcpy(saved_categories[i], current_categories[i]); | |
179 | if (loadlocale(i) == NULL) { | |
180 | for (j = 1; j < i; j++) { | |
181 | (void)strcpy(new_categories[j], | |
182 | saved_categories[j]); | |
183 | /* XXX can fail too */ | |
184 | (void)loadlocale(j); | |
185 | } | |
186 | return (NULL); | |
187 | } | |
188 | } | |
189 | return (currentlocale()); | |
190 | } | |
191 | ||
192 | static char * | |
193 | currentlocale() | |
194 | { | |
195 | int i; | |
196 | ||
197 | (void)strcpy(current_locale_string, current_categories[1]); | |
198 | ||
199 | for (i = 2; i < _LC_LAST; ++i) | |
200 | if (strcmp(current_categories[1], current_categories[i])) { | |
201 | for (i = 2; i < _LC_LAST; ++i) { | |
202 | (void) strcat(current_locale_string, "/"); | |
203 | (void) strcat(current_locale_string, current_categories[i]); | |
204 | } | |
205 | break; | |
206 | } | |
207 | return (current_locale_string); | |
208 | } | |
209 | ||
210 | static char * | |
211 | loadlocale(category) | |
212 | int category; | |
213 | { | |
214 | char *ret; | |
215 | char *new = new_categories[category]; | |
216 | char *old = current_categories[category]; | |
217 | ||
218 | if (_PathLocale == NULL) { | |
219 | char *p = getenv("PATH_LOCALE"); | |
220 | ||
221 | if (p != NULL | |
222 | #ifndef __NETBSD_SYSCALLS | |
223 | && !issetugid() | |
224 | #endif | |
225 | ) { | |
226 | if (strlen(p) + 1/*"/"*/ + ENCODING_LEN + | |
227 | 1/*"/"*/ + CATEGORY_LEN >= PATH_MAX) | |
228 | return (NULL); | |
229 | _PathLocale = strdup(p); | |
230 | if (_PathLocale == NULL) | |
231 | return (NULL); | |
232 | } else | |
233 | _PathLocale = _PATH_LOCALE; | |
234 | } | |
235 | ||
236 | if (strcmp(new, old) == 0) | |
237 | return (old); | |
238 | ||
239 | if (category == LC_CTYPE) { | |
240 | ret = setrunelocale(new) ? NULL : new; | |
241 | if (!ret) | |
242 | (void)setrunelocale(old); | |
243 | else | |
244 | (void)strcpy(old, new); | |
245 | return (ret); | |
246 | } | |
247 | ||
248 | if (category == LC_COLLATE) { | |
249 | ret = (__collate_load_tables(new) < 0) ? NULL : new; | |
250 | if (!ret) | |
251 | (void)__collate_load_tables(old); | |
252 | else | |
253 | (void)strcpy(old, new); | |
254 | return (ret); | |
255 | } | |
256 | ||
257 | if (category == LC_TIME) { | |
258 | ret = (__time_load_locale(new) < 0) ? NULL : new; | |
259 | if (!ret) | |
260 | (void)__time_load_locale(old); | |
261 | else | |
262 | (void)strcpy(old, new); | |
263 | return (ret); | |
264 | } | |
265 | ||
266 | if (category == LC_MONETARY || | |
267 | category == LC_MESSAGES || | |
268 | category == LC_NUMERIC) { | |
269 | ret = stub_load_locale(new) ? NULL : new; | |
270 | if (!ret) | |
271 | (void)stub_load_locale(old); | |
272 | else | |
273 | (void)strcpy(old, new); | |
274 | return (ret); | |
275 | } | |
276 | ||
277 | /* Just in case...*/ | |
278 | return (NULL); | |
279 | } | |
280 | ||
281 | static int | |
282 | stub_load_locale(encoding) | |
283 | const char *encoding; | |
284 | { | |
285 | char name[PATH_MAX]; | |
286 | struct stat st; | |
287 | ||
288 | if (!encoding) | |
289 | return(1); | |
290 | /* | |
291 | * The "C" and "POSIX" locale are always here. | |
292 | */ | |
293 | if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX")) | |
294 | return(0); | |
295 | if (!_PathLocale) | |
296 | return(1); | |
297 | /* Range checking not needed, encoding has fixed size */ | |
298 | strcpy(name, _PathLocale); | |
299 | strcat(name, "/"); | |
300 | strcat(name, encoding); | |
301 | #if 0 | |
302 | /* | |
303 | * Some day we will actually look at this file. | |
304 | */ | |
305 | #endif | |
306 | return (stat(name, &st) != 0 || !S_ISDIR(st.st_mode)); | |
307 | } |