xref: /original-bsd/lib/libc/locale/setlocale.c (revision b5bcb3e5)
1 /*
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Paul Borman at Krystal Technologies.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)setlocale.c	5.3 (Berkeley) 05/26/93";
13 #endif /* LIBC_SCCS and not lint */
14 
15 #include <limits.h>
16 #include <locale.h>
17 #include <rune.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 /*
22  * Category names for getenv()
23  */
24 static char *categories[_LC_LAST] = {
25     "LC_ALL",
26     "LC_COLLATE",
27     "LC_CTYPE",
28     "LC_MONETARY",
29     "LC_NUMERIC",
30     "LC_TIME",
31 };
32 
33 /*
34  * Current locales for each category
35  */
36 static char current_categories[_LC_LAST][32] = {
37     "C",
38     "C",
39     "C",
40     "C",
41     "C",
42     "C",
43 };
44 
45 /*
46  * The locales we are going to try and load
47  */
48 static char new_categories[_LC_LAST][32];
49 
50 static char current_locale_string[_LC_LAST * 33];
51 static char *PathLocale;
52 
53 static char	*currentlocale __P((void));
54 static char	*loadlocale __P((int));
55 
56 char *
57 setlocale(category, locale)
58 	int category;
59 	const char *locale;
60 {
61 	int found, i, len;
62 	char *env, *r;
63 
64 	if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE")))
65 		PathLocale = _PATH_LOCALE;
66 
67 	if (category < 0 || category >= _LC_LAST)
68 		return (NULL);
69 
70 	if (!locale)
71 		return (category ?
72 		    current_categories[category] : currentlocale());
73 
74 	/*
75 	 * Default to the current locale for everything.
76 	 */
77 	for (i = 1; i < _LC_LAST; ++i)
78 		(void)strcpy(new_categories[i], current_categories[i]);
79 
80 	/*
81 	 * Now go fill up new_categories from the locale argument
82 	 */
83 	if (!*locale) {
84 		env = getenv(categories[category]);
85 
86 		if (!env)
87 			env = getenv(categories[0]);
88 
89 		if (!env)
90 			env = getenv("LANG");
91 
92 		if (!env)
93 			env = "C";
94 
95 		(void) strncpy(new_categories[category], env, 31);
96 		new_categories[category][31] = 0;
97 		if (!category) {
98 			for (i = 1; i < _LC_LAST; ++i) {
99 				if (!(env = getenv(categories[i])))
100 					env = new_categories[0];
101 				(void)strncpy(new_categories[i], env, 31);
102 				new_categories[i][31] = 0;
103 			}
104 		}
105 	} else if (category)  {
106 		(void)strncpy(new_categories[category], locale, 31);
107 		new_categories[category][31] = 0;
108 	} else {
109 		if ((r = strchr(locale, '/')) == 0) {
110 			for (i = 1; i < _LC_LAST; ++i) {
111 				(void)strncpy(new_categories[i], locale, 31);
112 				new_categories[i][31] = 0;
113 			}
114 		} else {
115 			for (i = 1; r[1] == '/'; ++r);
116 			if (!r[1])
117 				return (NULL);	/* Hmm, just slashes... */
118 			do {
119 				len = r - locale > 31 ? 31 : r - locale;
120 				(void)strncpy(new_categories[i++], locale, len);
121 				new_categories[i++][len] = 0;
122 				locale = r;
123 				while (*locale == '/')
124 				    ++locale;
125 				while (*++r && *r != '/');
126 			} while (*locale);
127 			while (i < _LC_LAST)
128 				(void)strcpy(new_categories[i],
129 				    new_categories[i-1]);
130 		}
131 	}
132 
133 	if (category)
134 		return (loadlocale(category));
135 
136 	found = 0;
137 	for (i = 1; i < _LC_LAST; ++i)
138 		if (loadlocale(i) != NULL)
139 			found = 1;
140 	if (found)
141 	    return (currentlocale());
142 	return (NULL);
143 }
144 
145 static char *
146 currentlocale()
147 {
148 	int i;
149 
150 	(void)strcpy(current_locale_string, current_categories[1]);
151 
152 	for (i = 2; i < _LC_LAST; ++i)
153 		if (strcmp(current_categories[1], current_categories[i])) {
154 			(void)snprintf(current_locale_string,
155 			    sizeof(current_locale_string), "%s/%s/%s/%s/%s",
156 			    current_categories[1], current_categories[2],
157 			    current_categories[3], current_categories[4],
158 			    current_categories[5]);
159 			break;
160 		}
161 	return (current_locale_string);
162 }
163 
164 static char *
165 loadlocale(category)
166 	int category;
167 {
168 	char name[PATH_MAX];
169 
170 	if (strcmp(new_categories[category],
171 	    current_categories[category]) == 0)
172 		return (current_categories[category]);
173 
174 	if (category == LC_CTYPE) {
175 		if (setrunelocale(new_categories[LC_CTYPE]))
176 			return (NULL);
177 		(void)strcpy(current_categories[LC_CTYPE],
178 		    new_categories[LC_CTYPE]);
179 		return (current_categories[LC_CTYPE]);
180 	}
181 
182 	if (!strcmp(new_categories[category], "C") ||
183 		!strcmp(new_categories[category], "POSIX")) {
184 
185 		/*
186 		 * Some day this will need to reset the locale to the default
187 		 * C locale.  Since we have no way to change them as of yet,
188 		 * there is no need to reset them.
189 		 */
190 		(void)strcpy(current_categories[category],
191 		    new_categories[category]);
192 		return (current_categories[category]);
193 	}
194 
195 	/*
196 	 * Some day we will actually look at this file.
197 	 */
198 	(void)sprintf(name, sizeof(name), "%s/%s/%s",
199 	    PathLocale, new_categories[category], categories[category]);
200 
201 	switch (category) {
202 		case LC_COLLATE:
203 		case LC_MONETARY:
204 		case LC_NUMERIC:
205 		case LC_TIME:
206 			return (NULL);
207 	}
208 }
209