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