setlocale.c revision 1.8 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 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93";
39 #endif /* LIBC_SCCS and not lint */
40
41 #include <sys/localedef.h>
42 #include <locale.h>
43 #include <limits.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <paths.h>
48
49 /*
50 * Category names for getenv()
51 */
52 static char *categories[_LC_LAST] = {
53 "LC_ALL",
54 "LC_COLLATE",
55 "LC_CTYPE",
56 "LC_MONETARY",
57 "LC_NUMERIC",
58 "LC_TIME",
59 "LC_MESSAGES"
60 };
61
62 /*
63 * Current locales for each category
64 */
65 static char current_categories[_LC_LAST][32] = {
66 "C",
67 "C",
68 "C",
69 "C",
70 "C",
71 "C",
72 "C"
73 };
74
75 /*
76 * The locales we are going to try and load
77 */
78 static char new_categories[_LC_LAST][32];
79
80 static char current_locale_string[_LC_LAST * 33];
81 static char *PathLocale;
82
83 static char *currentlocale __P((void));
84 static char *loadlocale __P((int));
85
86 char *
87 setlocale(category, locale)
88 int category;
89 const char *locale;
90 {
91 int found, i, len;
92 char *env, *r;
93
94 /*
95 * XXX potential security problem here with set-id programs
96 * being able to read files the user can not normally read.
97 */
98 if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE")))
99 PathLocale = _PATH_LOCALE;
100
101 if (category < 0 || category >= _LC_LAST)
102 return (NULL);
103
104 if (!locale)
105 return (category ?
106 current_categories[category] : currentlocale());
107
108 /*
109 * Default to the current locale for everything.
110 */
111 for (i = 1; i < _LC_LAST; ++i)
112 (void)strncpy(new_categories[i], current_categories[i],
113 sizeof(new_categories[i]) - 1);
114
115 /*
116 * Now go fill up new_categories from the locale argument
117 */
118 if (!*locale) {
119 env = getenv(categories[category]);
120
121 if (!env)
122 env = getenv(categories[0]);
123
124 if (!env)
125 env = getenv("LANG");
126
127 if (!env)
128 env = "C";
129
130 (void)strncpy(new_categories[category], env, 31);
131 new_categories[category][31] = 0;
132 if (!category) {
133 for (i = 1; i < _LC_LAST; ++i) {
134 if (!(env = getenv(categories[i])))
135 env = new_categories[0];
136 (void)strncpy(new_categories[i], env, 31);
137 new_categories[i][31] = 0;
138 }
139 }
140 } else if (category) {
141 (void)strncpy(new_categories[category], locale, 31);
142 new_categories[category][31] = 0;
143 } else {
144 if ((r = strchr(locale, '/')) == 0) {
145 for (i = 1; i < _LC_LAST; ++i) {
146 (void)strncpy(new_categories[i], locale, 31);
147 new_categories[i][31] = 0;
148 }
149 } else {
150 for (i = 1; r[1] == '/'; ++r);
151 if (!r[1])
152 return (NULL); /* Hmm, just slashes... */
153 do {
154 len = r - locale > 31 ? 31 : r - locale;
155 (void)strncpy(new_categories[i++], locale, len);
156 new_categories[i++][len] = 0;
157 locale = r;
158 while (*locale == '/')
159 ++locale;
160 while (*++r && *r != '/');
161 } while (*locale);
162 while (i < _LC_LAST)
163 (void)strncpy(new_categories[i],
164 new_categories[i-1],
165 sizeof(new_categories[i]) - 1);
166 }
167 }
168
169 if (category)
170 return (loadlocale(category));
171
172 found = 0;
173 for (i = 1; i < _LC_LAST; ++i)
174 if (loadlocale(i) != NULL)
175 found = 1;
176 if (found)
177 return (currentlocale());
178 return (NULL);
179 }
180
181 static char *
182 currentlocale()
183 {
184 int i;
185
186 (void)strncpy(current_locale_string, current_categories[1],
187 sizeof(current_locale_string) - 1);
188
189 for (i = 2; i < _LC_LAST; ++i)
190 if (strcmp(current_categories[1], current_categories[i])) {
191 (void)snprintf(current_locale_string,
192 sizeof(current_locale_string), "%s/%s/%s/%s/%s",
193 current_categories[1], current_categories[2],
194 current_categories[3], current_categories[4],
195 current_categories[5]);
196 break;
197 }
198 return (current_locale_string);
199 }
200
201 static char *
202 loadlocale(category)
203 int category;
204 {
205 char name[PATH_MAX];
206
207 if (strcmp(new_categories[category],
208 current_categories[category]) == 0)
209 return (current_categories[category]);
210
211 if (!strcmp(new_categories[category], "C") ||
212 !strcmp(new_categories[category], "POSIX")) {
213
214 /*
215 * Some day this will need to reset the locale to the default
216 * C locale. Since we have no way to change them as of yet,
217 * there is no need to reset them.
218 */
219 (void)strncpy(current_categories[category],
220 new_categories[category],
221 sizeof(current_categories[category]) - 1);
222 return (current_categories[category]);
223 }
224
225 /*
226 * Some day we will actually look at this file.
227 */
228 (void)snprintf(name, sizeof(name), "%s/%s/%s",
229 PathLocale, new_categories[category], categories[category]);
230
231 switch (category) {
232 case LC_CTYPE:
233 case LC_COLLATE:
234 case LC_MESSAGES:
235 case LC_MONETARY:
236 case LC_NUMERIC:
237 case LC_TIME:
238 return (NULL);
239 }
240 }
241