]> git.saurik.com Git - apple/libc.git/blame - locale/setlocale.c
Libc-262.2.12.tar.gz
[apple/libc.git] / locale / setlocale.c
CommitLineData
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
38static 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)
43static 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 */
60static 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 */
73static 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 */
86static char new_categories[_LC_LAST][ENCODING_LEN + 1];
87static char saved_categories[_LC_LAST][ENCODING_LEN + 1];
88
89static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
90
91static char *currentlocale __P((void));
92static char *loadlocale __P((int));
93static int stub_load_locale __P((const char *));
94
95extern int __time_load_locale __P((const char *)); /* strftime.c */
96
97char *
98setlocale(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
192static char *
193currentlocale()
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
210static char *
211loadlocale(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
281static int
282stub_load_locale(encoding)
283const 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}