(_nl_category_names): Change into an array with fixed width char
[kopensolaris-gnu/glibc.git] / locale / setlocale.c
1 /* Copyright (C) 1991, 92, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
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.
8
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.
13
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 not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include <alloca.h>
20 #include <argz.h>
21 #include <errno.h>
22 #include <bits/libc-lock.h>
23 #include <locale.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "localeinfo.h"
29
30 /* For each category declare two external variables (with weak references):
31      extern const struct locale_data *_nl_current_CATEGORY;
32    This points to the current locale's in-core data for CATEGORY.
33      extern const struct locale_data _nl_C_CATEGORY;
34    This contains the built-in "C"/"POSIX" locale's data for CATEGORY.
35    Both are weak references; if &_nl_current_CATEGORY is zero,
36    then nothing is using the locale data.  */
37 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
38 extern struct locale_data *_nl_current_##category;                            \
39 extern struct locale_data _nl_C_##category;
40 #include "categories.def"
41 #undef  DEFINE_CATEGORY
42
43 /* Array indexed by category of pointers to _nl_current_CATEGORY slots.  */
44 struct locale_data * *const _nl_current[] =
45   {
46 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
47     [category] = &_nl_current_##category,
48 #include "categories.def"
49 #undef  DEFINE_CATEGORY
50     /* We need this additional element to simplify the code.  It must
51        simply be != NULL.  */
52     [LC_ALL] = (struct locale_data **) ~0ul
53   };
54
55 /* Array indexed by category of pointers to _nl_C_CATEGORY slots.
56    Elements are zero for categories whose data is never used.  */
57 struct locale_data *const _nl_C[] =
58   {
59 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
60     [category] = &_nl_C_##category,
61 #include "categories.def"
62 #undef  DEFINE_CATEGORY
63   };
64
65
66 /* Define an array of category names (also the environment variable names),
67    indexed by integral category.
68
69    We have entries of fixed width (12 for now) do avoid an array of
70    pointers.  Update the size of the outer array if new, longer locale
71    names are introduced.  */
72 const char _nl_category_names[][12] =
73   {
74 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
75     [category] = category_name,
76 #include "categories.def"
77 #undef  DEFINE_CATEGORY
78     [LC_ALL] = "LC_ALL"
79   };
80 /* An array of their lengths, for convenience.  */
81 const size_t _nl_category_name_sizes[] =
82   {
83 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
84     [category] = sizeof (category_name) - 1,
85 #include "categories.def"
86 #undef  DEFINE_CATEGORY
87     [LC_ALL] = sizeof ("LC_ALL") - 1
88   };
89
90
91 /* Declare the postload functions used below.  */
92 #undef  NO_POSTLOAD
93 #define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist.  */
94 #define DEFINE_CATEGORY(category, category_name, items, postload, b, c, d) \
95 extern void postload (void);
96 #include "categories.def"
97 #undef  DEFINE_CATEGORY
98 #undef  NO_POSTLOAD
99
100 /* Define an array indexed by category of postload functions to call after
101    loading and installing that category's data.  */
102 static void (*const _nl_category_postload[]) (void) =
103   {
104 #define DEFINE_CATEGORY(category, category_name, items, postload, b, c, d) \
105     [category] = postload,
106 #include "categories.def"
107 #undef  DEFINE_CATEGORY
108   };
109
110
111 /* Name of current locale for each individual category.
112    Each is malloc'd unless it is nl_C_name.  */
113 static const char *_nl_current_names[] =
114   {
115 #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
116     [category] = _nl_C_name,
117 #include "categories.def"
118 #undef  DEFINE_CATEGORY
119     [LC_ALL] = _nl_C_name               /* For LC_ALL.  */
120   };
121
122
123 /* Lock for protecting global data.  */
124 __libc_lock_define_initialized (, __libc_setlocale_lock)
125
126
127 /* Use this when we come along an error.  */
128 #define ERROR_RETURN                                                          \
129   do {                                                                        \
130     __set_errno (EINVAL);                                                     \
131     return NULL;                                                              \
132   } while (0)
133
134
135 /* Construct a new composite name.  */
136 static inline char *
137 new_composite_name (int category, const char *newnames[LC_ALL])
138 {
139   size_t last_len = 0;
140   size_t cumlen = 0;
141   int i;
142   char *new, *p;
143   int same = 1;
144
145   for (i = 0; i < LC_ALL; ++i)
146     {
147       const char *name = (category == LC_ALL ? newnames[i] :
148                           category == i ? newnames[0] :
149                           _nl_current_names[i]);
150       last_len = strlen (name);
151       cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1;
152       if (i > 0 && same && strcmp (name, newnames[0]) != 0)
153         same = 0;
154     }
155
156   if (same)
157     {
158       /* All the categories use the same name.  */
159       if (strcmp (newnames[0], _nl_C_name) == 0
160           || strcmp (newnames[0], _nl_POSIX_name) == 0)
161         return (char *) _nl_C_name;
162
163       new = malloc (last_len + 1);
164
165       return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1);
166     }
167
168   new = malloc (cumlen);
169   if (new == NULL)
170     return NULL;
171   p = new;
172   for (i = 0; i < LC_ALL; ++i)
173     {
174       /* Add "CATEGORY=NAME;" to the string.  */
175       const char *name = (category == LC_ALL ? newnames[i] :
176                           category == i ? newnames[0] :
177                           _nl_current_names[i]);
178       p = __stpcpy (p, _nl_category_names[i]);
179       *p++ = '=';
180       p = __stpcpy (p, name);
181       *p++ = ';';
182     }
183   p[-1] = '\0';         /* Clobber the last ';'.  */
184   return new;
185 }
186
187
188 /* Put NAME in _nl_current_names.  */
189 static inline void
190 setname (int category, const char *name)
191 {
192   if (_nl_current_names[category] == name)
193     return;
194
195   if (category == LC_ALL && _nl_current_names[category] != _nl_C_name)
196     free ((char *) _nl_current_names[category]);
197
198   _nl_current_names[category] = name;
199 }
200
201
202 /* Put DATA in *_nl_current[CATEGORY].  */
203 static inline void
204 setdata (int category, struct locale_data *data)
205 {
206   if (_nl_current[category] != NULL)
207     {
208       *_nl_current[category] = data;
209       if (_nl_category_postload[category])
210         (*_nl_category_postload[category]) ();
211     }
212 }
213
214
215 char *
216 setlocale (int category, const char *locale)
217 {
218   char *locale_path;
219   size_t locale_path_len;
220   const char *locpath_var;
221   char *composite;
222
223   /* Sanity check for CATEGORY argument.  */
224   if (category < 0 || category > LC_ALL)
225     ERROR_RETURN;
226
227   /* Does user want name of current locale?  */
228   if (locale == NULL)
229     return (char *) _nl_current_names[category];
230
231   if (strcmp (locale, _nl_current_names[category]) == 0)
232     /* Changing to the same thing.  */
233     return (char *) _nl_current_names[category];
234
235   /* We perhaps really have to load some data.  So we determine the
236      path in which to look for the data now.  The environment variable
237      `LOCPATH' must only be used when the binary has no SUID or SGID
238      bit set.  */
239   locale_path = NULL;
240   locale_path_len = 0;
241
242   locpath_var = __secure_getenv ("LOCPATH");
243   if (locpath_var != NULL && locpath_var[0] != '\0')
244     if (__argz_create_sep (locpath_var, ':',
245                            &locale_path, &locale_path_len) != 0)
246       return NULL;
247
248   if (__argz_add_sep (&locale_path, &locale_path_len, LOCALE_PATH, ':') != 0)
249     return NULL;
250
251   if (category == LC_ALL)
252     {
253       /* The user wants to set all categories.  The desired locales
254          for the individual categories can be selected by using a
255          composite locale name.  This is a semi-colon separated list
256          of entries of the form `CATEGORY=VALUE'.  */
257       const char *newnames[LC_ALL];
258       struct locale_data *newdata[LC_ALL];
259
260       /* Set all name pointers to the argument name.  */
261       for (category = 0; category < LC_ALL; ++category)
262         newnames[category] = (char *) locale;
263
264       if (strchr (locale, ';') != NULL)
265         {
266           /* This is a composite name.  Make a copy and split it up.  */
267           char *np = strdupa (locale);
268           char *cp;
269           int cnt;
270
271           while ((cp = strchr (np, '=')) != NULL)
272             {
273               for (cnt = 0; cnt < LC_ALL; ++cnt)
274                 if ((size_t) (cp - np) == _nl_category_name_sizes[cnt]
275                     && memcmp (np, _nl_category_names[cnt], cp - np) == 0)
276                   break;
277
278               if (cnt == LC_ALL)
279                 /* Bogus category name.  */
280                 ERROR_RETURN;
281
282               /* Found the category this clause sets.  */
283               newnames[cnt] = ++cp;
284               cp = strchr (cp, ';');
285               if (cp != NULL)
286                 {
287                   /* Examine the next clause.  */
288                   *cp = '\0';
289                   np = cp + 1;
290                 }
291               else
292                 /* This was the last clause.  We are done.  */
293                 break;
294             }
295
296           for (cnt = 0; cnt < LC_ALL; ++cnt)
297             if (newnames[cnt] == locale)
298               /* The composite name did not specify all categories.  */
299               ERROR_RETURN;
300         }
301
302       /* Protect global data.  */
303       __libc_lock_lock (__libc_setlocale_lock);
304
305       /* Load the new data for each category.  */
306       while (category-- > 0)
307         {
308           newdata[category] = _nl_find_locale (locale_path, locale_path_len,
309                                                category,
310                                                &newnames[category]);
311
312           if (newdata[category] == NULL)
313             break;
314
315           /* We must not simply free a global locale since we have no
316              control over the usage.  So we mark it as un-deletable.  */
317           if (newdata[category]->usage_count != UNDELETABLE)
318             newdata[category]->usage_count = UNDELETABLE;
319         }
320
321       /* Create new composite name.  */
322       if (category >= 0
323           || (composite = new_composite_name (LC_ALL, newnames)) == NULL)
324         /* Loading this part of the locale failed.  Abort the
325            composite load.  */
326         composite = NULL;
327       else
328         {
329           /* Now we have loaded all the new data.  Put it in place.  */
330           for (category = 0; category < LC_ALL; ++category)
331             {
332               setdata (category, newdata[category]);
333               setname (category, newnames[category]);
334             }
335           setname (LC_ALL, composite);
336         }
337
338       /* Critical section left.  */
339       __libc_lock_unlock (__libc_setlocale_lock);
340
341       /* Free the resources (the locale path variable.  */
342       free (locale_path);
343
344       return composite;
345     }
346   else
347     {
348       struct locale_data *newdata = NULL;
349       const char *newname[1] = { locale };
350
351       /* Protect global data.  */
352       __libc_lock_lock (__libc_setlocale_lock);
353
354       if (_nl_current[category] != NULL)
355         {
356           /* Only actually load the data if anything will use it.  */
357           newdata = _nl_find_locale (locale_path, locale_path_len, category,
358                                      &newname[0]);
359           if (newdata == NULL)
360             goto abort_single;
361
362           /* We must not simply free a global locale since we have no
363              control over the usage.  So we mark it as un-deletable.
364
365              Note: do not remove the `if', it's necessary to copy with
366              the builtin locale data.  */
367           if (newdata->usage_count != UNDELETABLE)
368             newdata->usage_count = UNDELETABLE;
369         }
370
371       /* Create new composite name.  */
372       composite = new_composite_name (category, newname);
373       if (composite == NULL)
374         {
375           /* Say that we don't have any data loaded.  */
376         abort_single:
377           newname[0] = NULL;
378         }
379       else
380         {
381           if (_nl_current[category] != NULL)
382             setdata (category, newdata);
383
384           setname (category, newname[0]);
385           setname (LC_ALL, composite);
386         }
387
388       /* Critical section left.  */
389       __libc_lock_unlock (__libc_setlocale_lock);
390
391       /* Free the resources (the locale path variable.  */
392       free (locale_path);
393
394       return (char *) newname[0];
395     }
396 }
397
398
399 static void __attribute__ ((unused))
400 free_mem (void)
401 {
402   int category;
403
404   for (category = 0; category < LC_ALL; ++category)
405     {
406       struct locale_data *here = *_nl_current[category];
407
408       /* If this category is already "C" don't do anything.  */
409       if (here == _nl_C[category])
410         continue;
411
412       /* We have to be prepared that sometime later me still might
413          need the locale information.  */
414       setdata (category, _nl_C[category]);
415       setname (category, _nl_C_name);
416
417       _nl_unload_locale (here);
418     }
419
420   setname (LC_ALL, _nl_C_name);
421 }
422 text_set_element (__libc_subfreeres, free_mem);