setlocale.c revision 1.7 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 if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE")))
95 PathLocale = _PATH_LOCALE;
96
97 if (category < 0 || category >= _LC_LAST)
98 return (NULL);
99
100 if (!locale)
101 return (category ?
102 current_categories[category] : currentlocale());
103
104 /*
105 * Default to the current locale for everything.
106 */
107 for (i = 1; i < _LC_LAST; ++i)
108 (void)strncpy(new_categories[i], current_categories[i],
109 sizeof(new_categories[i]) - 1);
110
111 /*
112 * Now go fill up new_categories from the locale argument
113 */
114 if (!*locale) {
115 env = getenv(categories[category]);
116
117 if (!env)
118 env = getenv(categories[0]);
119
120 if (!env)
121 env = getenv("LANG");
122
123 if (!env)
124 env = "C";
125
126 (void) strncpy(new_categories[category], env, 31);
127 new_categories[category][31] = 0;
128 if (!category) {
129 for (i = 1; i < _LC_LAST; ++i) {
130 if (!(env = getenv(categories[i])))
131 env = new_categories[0];
132 (void)strncpy(new_categories[i], env, 31);
133 new_categories[i][31] = 0;
134 }
135 }
136 } else if (category) {
137 (void)strncpy(new_categories[category], locale, 31);
138 new_categories[category][31] = 0;
139 } else {
140 if ((r = strchr(locale, '/')) == 0) {
141 for (i = 1; i < _LC_LAST; ++i) {
142 (void)strncpy(new_categories[i], locale, 31);
143 new_categories[i][31] = 0;
144 }
145 } else {
146 for (i = 1; r[1] == '/'; ++r);
147 if (!r[1])
148 return (NULL); /* Hmm, just slashes... */
149 do {
150 len = r - locale > 31 ? 31 : r - locale;
151 (void)strncpy(new_categories[i++], locale, len);
152 new_categories[i++][len] = 0;
153 locale = r;
154 while (*locale == '/')
155 ++locale;
156 while (*++r && *r != '/');
157 } while (*locale);
158 while (i < _LC_LAST)
159 (void)strncpy(new_categories[i],
160 new_categories[i-1],
161 sizeof(new_categories[i]) - 1);
162 }
163 }
164
165 if (category)
166 return (loadlocale(category));
167
168 found = 0;
169 for (i = 1; i < _LC_LAST; ++i)
170 if (loadlocale(i) != NULL)
171 found = 1;
172 if (found)
173 return (currentlocale());
174 return (NULL);
175 }
176
177 static char *
178 currentlocale()
179 {
180 int i;
181
182 (void)strncpy(current_locale_string, current_categories[1],
183 sizeof(current_locale_string) - 1);
184
185 for (i = 2; i < _LC_LAST; ++i)
186 if (strcmp(current_categories[1], current_categories[i])) {
187 (void)snprintf(current_locale_string,
188 sizeof(current_locale_string), "%s/%s/%s/%s/%s",
189 current_categories[1], current_categories[2],
190 current_categories[3], current_categories[4],
191 current_categories[5]);
192 break;
193 }
194 return (current_locale_string);
195 }
196
197 static char *
198 loadlocale(category)
199 int category;
200 {
201 char name[PATH_MAX];
202
203 if (strcmp(new_categories[category],
204 current_categories[category]) == 0)
205 return (current_categories[category]);
206
207 if (!strcmp(new_categories[category], "C") ||
208 !strcmp(new_categories[category], "POSIX")) {
209
210 /*
211 * Some day this will need to reset the locale to the default
212 * C locale. Since we have no way to change them as of yet,
213 * there is no need to reset them.
214 */
215 (void)strncpy(current_categories[category],
216 new_categories[category],
217 sizeof(current_categories[category]) - 1);
218 return (current_categories[category]);
219 }
220
221 /*
222 * Some day we will actually look at this file.
223 */
224 (void)snprintf(name, sizeof(name), "%s/%s/%s",
225 PathLocale, new_categories[category], categories[category]);
226
227 switch (category) {
228 case LC_CTYPE:
229 case LC_COLLATE:
230 case LC_MESSAGES:
231 case LC_MONETARY:
232 case LC_NUMERIC:
233 case LC_TIME:
234 return (NULL);
235 }
236 }
237