Sun Dec 17 15:56:35 1995 Miles Bader <miles@gnu.ai.mit.edu>
[glibc.git] / locale / setlocale.c
blob509bb4ffa1e45674940aef1648ff03c3af2ad345
1 /* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
19 #include <errno.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <locale.h>
23 #include <langinfo.h>
24 #include "localeinfo.h"
26 /* For each category declare two external variables (with weak references):
27 extern const struct locale_data *_nl_current_CATEGORY;
28 This points to the current locale's in-core data for CATEGORY.
29 extern const struct locale_data _nl_C_CATEGORY;
30 This contains the built-in "C"/"POSIX" locale's data for CATEGORY.
31 Both are weak references; if &_nl_current_CATEGORY is zero,
32 then nothing is using the locale data. */
33 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
34 extern const struct locale_data *_nl_current_##category; \
35 extern const struct locale_data _nl_C_##category; \
36 /* XXX The linker is broken so we cannot do the weak symbols right just now. */
37 /* weak_symbol (_nl_current_##category) weak_symbol (_nl_C_##category) */
38 #include "categories.def"
39 #undef DEFINE_CATEGORY
41 /* Array indexed by category of pointers to _nl_current_CATEGORY slots.
42 Elements are zero for categories whose data is never used. */
43 const struct locale_data * *const _nl_current[] =
45 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
46 [category] = &_nl_current_##category,
47 #include "categories.def"
48 #undef DEFINE_CATEGORY
51 /* Array indexed by category of pointers to _nl_C_CATEGORY slots.
52 Elements are zero for categories whose data is never used. */
53 const struct locale_data *const _nl_C[] =
55 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
56 [category] = &_nl_C_##category,
57 #include "categories.def"
58 #undef DEFINE_CATEGORY
62 /* Define an array of category names (also the environment variable names),
63 indexed by integral category. */
64 const char *const _nl_category_names[] =
66 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
67 [category] = category_name,
68 #include "categories.def"
69 #undef DEFINE_CATEGORY
71 /* An array of their lengths, for convenience. */
72 const size_t _nl_category_name_sizes[] =
74 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
75 [category] = sizeof (category_name) - 1,
76 #include "categories.def"
77 #undef DEFINE_CATEGORY
81 /* Declare the postload functions used below. */
82 #undef NO_POSTLOAD
83 #define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist. */
84 #define DEFINE_CATEGORY(category, category_name, items, postload, b, c, d) \
85 extern void postload (void);
86 #include "categories.def"
87 #undef DEFINE_CATEGORY
88 #undef NO_POSTLOAD
90 /* Define an array indexed by category of postload functions to call after
91 loading and installing that category's data. */
92 void (*const _nl_category_postload[]) (void) =
94 #define DEFINE_CATEGORY(category, category_name, items, postload, b, c, d) \
95 [category] = postload,
96 #include "categories.def"
97 #undef DEFINE_CATEGORY
101 const char _nl_C_name[] = "C";
103 /* Name of current locale for each individual category.
104 Each is malloc'd unless it is nl_C_name. */
105 const char *_nl_current_names[] =
107 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
108 _nl_C_name,
109 #include "categories.def"
110 #undef DEFINE_CATEGORY
113 /* Composite LC_ALL name for current locale.
114 This is malloc'd unless it's _nl_C_name. */
115 char *_nl_current_composite_name = (char *) _nl_C_name;
118 /* Switch to the locale called NAME in CATEGORY. Return a string
119 describing the locale. This string can be used as the NAME argument in
120 a later call. If NAME is NULL, don't switch locales, but return the
121 current one. If NAME is "", switch to a locale based on the environment
122 variables, as per POSIX. Return NULL on error. */
124 char *
125 setlocale (int category, const char *name)
127 /* Return a malloc'd copy of STRING. */
128 char *copy (const char *string)
130 size_t len = strlen (string) + 1;
131 char *new = malloc (len);
132 return new ? memcpy (new, string, len) : NULL;
135 /* Construct a new composite name. */
136 char *new_composite_name (int category, char *newnames[LC_ALL])
138 size_t lens[LC_ALL], cumlen = 0;
139 int i;
140 char *new, *p;
141 int same = 1;
143 for (i = 0; i < LC_ALL; ++i)
145 char *name = (category == LC_ALL ? newnames[i] :
146 category == i ? newnames[0] :
147 (char *) _nl_current_names[i]);
148 lens[i] = strlen (name);
149 cumlen += _nl_category_name_sizes[i] + 1 + lens[i] + 1;
150 if (i > 0 && same && strcmp (name, newnames[0]))
151 same = 0;
154 if (same)
156 /* All the categories use the same name. */
157 new = malloc (lens[0] + 1);
158 if (! new)
160 if (!strcmp (newnames[0], "C") || !strcmp (newnames[0], "POSIX"))
161 return (char *) _nl_C_name;
162 return NULL;
164 memcpy (new, newnames[0], lens[0] + 1);
165 return new;
168 new = malloc (cumlen);
169 if (! new)
170 return NULL;
171 p = new;
172 for (i = 0; i < LC_ALL; ++i)
174 /* Add "CATEGORY=NAME;" to the string. */
175 char *name = (category == LC_ALL ? newnames[i] :
176 category == i ? newnames[0] :
177 (char *) _nl_current_names[i]);
178 memcpy (p, _nl_category_names[i], _nl_category_name_sizes[i]);
179 p += _nl_category_name_sizes[i];
180 *p++ = '=';
181 memcpy (p, name, lens[i]);
182 p += lens[i];
183 *p++ = ';';
185 p[-1] = '\0'; /* Clobber the last ';'. */
186 return new;
188 /* Put COMPOSITE in _nl_current_composite_name and free the old value. */
189 void setcomposite (char *composite)
191 char *old = _nl_current_composite_name;
192 _nl_current_composite_name = composite;
193 if (old != _nl_C_name)
194 free (old);
196 /* Put NAME in _nl_current_names and free the old value. */
197 void setname (int category, const char *name)
199 const char *oldname = _nl_current_names[category];
200 _nl_current_names[category] = name;
201 if (oldname != _nl_C_name)
202 free ((char *) oldname);
204 /* Put DATA in *_nl_current[CATEGORY] and free the old value. */
205 void setdata (int category, struct locale_data *data)
207 if (_nl_current[category])
209 const struct locale_data *olddata = *_nl_current[category];
210 *_nl_current[category] = data;
211 if (_nl_category_postload[category])
212 (*_nl_category_postload[category]) ();
213 if (olddata != _nl_C[category])
214 _nl_free_locale ((struct locale_data *) olddata);
218 const char *current_name;
219 char *composite;
221 if (category < 0 || category > LC_ALL)
223 errno = EINVAL;
224 return NULL;
227 if (category == LC_ALL)
228 current_name = _nl_current_composite_name;
229 else
230 current_name = _nl_current_names[category];
232 if (name == NULL)
233 /* Return the name of the current locale. */
234 return (char *) current_name;
236 if (name == current_name)
237 /* Changing to the same thing. */
238 return (char *) current_name;
240 if (category == LC_ALL)
242 const size_t len = strlen (name) + 1;
243 char *newnames[LC_ALL];
244 char *p;
245 struct locale_data *newdata[LC_ALL];
247 /* Set all name pointers to the argument name. */
248 for (category = 0; category < LC_ALL; ++category)
249 newnames[category] = (char *) name;
251 p = strchr (name, ';');
252 if (p)
254 /* This is a composite name. Make a local copy and split it up. */
255 int i;
256 char *n = alloca (len);
257 memcpy (n, name, len);
259 while ((p = strchr (n, '=')) != NULL)
261 for (i = 0; i < LC_ALL; ++i)
262 if (_nl_category_name_sizes[i] == p - n &&
263 !memcmp (_nl_category_names[i], n, p - n))
264 break;
265 if (i == LC_ALL)
267 /* Bogus category name. */
268 errno = EINVAL;
269 return NULL;
271 if (i < LC_ALL)
273 /* Found the category this clause sets. */
274 char *end = strchr (++p, ';');
275 newnames[i] = p;
276 if (end)
278 /* Examine the next clause. */
279 *end = '\0';
280 n = end + 1;
282 else
283 /* This was the last clause. We are done. */
284 break;
288 for (i = 0; i < LC_ALL; ++i)
289 if (newnames[i] == name)
290 /* The composite name did not specify all categories. */
291 return NULL;
294 /* Load the new data for each category. */
295 while (category-- > 0)
296 /* Only actually load the data if anything will use it. */
297 if (_nl_current[category])
299 newdata[category] = _nl_load_locale (category,
300 &newnames[category]);
301 if (newdata[category])
302 newnames[category] = copy (newnames[category]);
303 if (! newdata[category] || ! newnames[category])
305 if (!strcmp (newnames[category], "C") ||
306 !strcmp (newnames[category], "POSIX"))
308 /* Loading from a file failed, but this is a request
309 for the default locale. Use the built-in data. */
310 if (! newdata[category])
311 newdata[category]
312 = (struct locale_data *) _nl_C[category];
313 newnames[category] = (char *) _nl_C_name;
315 else
317 /* Loading this part of the locale failed.
318 Abort the composite load. */
319 abort_composite:
320 while (++category < LC_ALL)
322 if (_nl_current[category])
323 _nl_free_locale (newdata[category]);
324 if (newnames[category] != _nl_C_name)
325 free (newnames[category]);
327 return NULL;
331 else
333 /* The data is never used; just change the name. */
334 newnames[category] = copy (newnames[category]);
335 if (! newnames[category])
337 if (!strcmp (newnames[category], "C") ||
338 !strcmp (newnames[category], "POSIX"))
339 newnames[category] = (char *) _nl_C_name;
340 else
342 while (++category < LC_ALL)
343 if (newnames[category] != _nl_C_name)
344 free (newnames[category]);
349 composite = new_composite_name (LC_ALL, newnames);
350 if (! composite)
352 category = -1;
353 goto abort_composite;
356 /* Now we have loaded all the new data. Put it in place. */
357 for (category = 0; category < LC_ALL; ++category)
359 setdata (category, newdata[category]);
360 setname (category, newnames[category]);
362 setcomposite (composite);
364 return composite;
366 else
368 char *newname = copy (name);
369 if (! newname)
371 if (!strcmp (name, "C") || !strcmp (name, "POSIX"))
372 newname = (char *) _nl_C_name;
373 else
374 return NULL;
377 composite = new_composite_name (category, &newname);
378 if (! composite)
380 if (newname != _nl_C_name)
381 free (newname);
382 return NULL;
385 /* Only actually load the data if anything will use it. */
386 if (_nl_current[category])
388 struct locale_data *newdata = _nl_load_locale (category,
389 (char **) &name);
390 if (! newdata)
392 if (!strcmp (name, "C") || !strcmp (name, "POSIX"))
393 newdata = (struct locale_data *) _nl_C[category];
394 else
395 return NULL;
397 setdata (category, newdata);
400 setname (category, newname);
401 setcomposite (composite);
403 return newname;