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