b3d4b464b1fc5874778d348b4446740c4cc7549e
[platform/upstream/linaro-glibc.git] / locale / newlocale.c
1 /* Return a reference to locale information record.
2    Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2004, 2005
3    Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, write to the Free
19    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307 USA.  */
21
22 #include <argz.h>
23 #include <bits/libc-lock.h>
24 #include <errno.h>
25 #include <locale.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "localeinfo.h"
30
31
32 /* Lock for protecting global data.  */
33 __libc_lock_define (extern , __libc_setlocale_lock attribute_hidden)
34
35
36 /* Use this when we come along an error.  */
37 #define ERROR_RETURN                                                          \
38   do {                                                                        \
39     __set_errno (EINVAL);                                                     \
40     return NULL;                                                              \
41   } while (0)
42
43
44 __locale_t
45 __newlocale (int category_mask, const char *locale, __locale_t base)
46 {
47   /* Intermediate memory for result.  */
48   const char *newnames[__LC_LAST];
49   struct __locale_struct result;
50   __locale_t result_ptr;
51   char *locale_path;
52   size_t locale_path_len;
53   const char *locpath_var;
54   int cnt;
55   size_t names_len;
56
57   /* We treat LC_ALL in the same way as if all bits were set.  */
58   if (category_mask == 1 << LC_ALL)
59     category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL);
60
61   /* Sanity check for CATEGORY argument.  */
62   if ((category_mask & ~((1 << __LC_LAST) - 1 - (1 << LC_ALL))) != 0)
63     ERROR_RETURN;
64
65   /* `newlocale' does not support asking for the locale name. */
66   if (locale == NULL)
67     ERROR_RETURN;
68
69   if (base == _nl_C_locobj_ptr)
70     /* We're to modify BASE, returned for a previous call with "C".
71        We can't really modify the read-only structure, so instead
72        start over by copying it.  */
73     base = NULL;
74
75   if ((base == NULL || category_mask == (1 << __LC_LAST) - 1 - (1 << LC_ALL))
76       && (category_mask == 0 || !strcmp (locale, "C")))
77     /* Asking for the "C" locale needn't allocate a new object.  */
78     return _nl_C_locobj_ptr;
79
80   /* Allocate memory for the result.  */
81   if (base != NULL)
82     result = *base;
83   else
84     /* Fill with pointers to C locale data.  */
85     result = _nl_C_locobj;
86
87   /* If no category is to be set we return BASE if available or a
88      dataset using the C locale data.  */
89   if (category_mask == 0)
90     {
91       result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
92       if (result_ptr == NULL)
93         return NULL;
94       *result_ptr = result;
95
96       goto update;
97     }
98
99   /* We perhaps really have to load some data.  So we determine the
100      path in which to look for the data now.  The environment variable
101      `LOCPATH' must only be used when the binary has no SUID or SGID
102      bit set.  If using the default path, we tell _nl_find_locale
103      by passing null and it can check the canonical locale archive.  */
104   locale_path = NULL;
105   locale_path_len = 0;
106
107   locpath_var = getenv ("LOCPATH");
108   if (locpath_var != NULL && locpath_var[0] != '\0')
109     {
110       if (__argz_create_sep (locpath_var, ':',
111                              &locale_path, &locale_path_len) != 0)
112         return NULL;
113
114       if (__argz_add_sep (&locale_path, &locale_path_len,
115                           _nl_default_locale_path, ':') != 0)
116         return NULL;
117     }
118
119   /* Get the names for the locales we are interested in.  We either
120      allow a composite name or a single name.  */
121   for (cnt = 0; cnt < __LC_LAST; ++cnt)
122     if (cnt != LC_ALL)
123       newnames[cnt] = locale;
124   if (strchr (locale, ';') != NULL)
125     {
126       /* This is a composite name.  Make a copy and split it up.  */
127       char *np = strdupa (locale);
128       char *cp;
129       int specified_mask = 0;
130
131       while ((cp = strchr (np, '=')) != NULL)
132         {
133           for (cnt = 0; cnt < __LC_LAST; ++cnt)
134             if (cnt != LC_ALL
135                 && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
136                 && memcmp (np, _nl_category_names[cnt], cp - np) == 0)
137               break;
138
139           if (cnt == __LC_LAST)
140             /* Bogus category name.  */
141             ERROR_RETURN;
142
143           /* Found the category this clause sets.  */
144           specified_mask |= 1 << cnt;
145           newnames[cnt] = ++cp;
146           cp = strchr (cp, ';');
147           if (cp != NULL)
148             {
149               /* Examine the next clause.  */
150               *cp = '\0';
151               np = cp + 1;
152             }
153           else
154             /* This was the last clause.  We are done.  */
155             break;
156         }
157
158       if (category_mask &~ specified_mask)
159         /* The composite name did not specify all categories we need.  */
160         ERROR_RETURN;
161     }
162
163   /* Protect global data.  */
164   __libc_lock_lock (__libc_setlocale_lock);
165
166   /* Now process all categories we are interested in.  */
167   names_len = 0;
168   for (cnt = 0; cnt < __LC_LAST; ++cnt)
169     {
170       if ((category_mask & 1 << cnt) != 0)
171         {
172           result.__locales[cnt] = _nl_find_locale (locale_path,
173                                                    locale_path_len,
174                                                    cnt, &newnames[cnt]);
175           if (result.__locales[cnt] == NULL)
176             {
177             free_cnt_data_and_exit:
178               while (cnt-- > 0)
179                 if (((category_mask & 1 << cnt) != 0)
180                     && result.__locales[cnt]->usage_count != UNDELETABLE)
181                   /* We can remove the data.  */
182                   _nl_remove_locale (cnt, result.__locales[cnt]);
183
184               /* Critical section left.  */
185               __libc_lock_unlock (__libc_setlocale_lock);
186               return NULL;
187             }
188
189           if (newnames[cnt] != _nl_C_name)
190             names_len += strlen (newnames[cnt]) + 1;
191         }
192       else if (cnt != LC_ALL && result.__names[cnt] != _nl_C_name)
193         /* Tally up the unchanged names from BASE as well.  */
194         names_len += strlen (result.__names[cnt]) + 1;
195     }
196
197   /* We successfully loaded all required data.  Allocate a new structure.
198      We can't just reuse the BASE pointer, because the name strings are
199      changing and we need the old name string area intact so we can copy
200      out of it into the new one without overlap problems should some
201      category's name be getting longer.  */
202   result_ptr = malloc (sizeof (struct __locale_struct) + names_len);
203   if (result_ptr == NULL)
204     {
205       cnt = __LC_LAST;
206       goto free_cnt_data_and_exit;
207     }
208
209   if (base == NULL)
210     {
211       /* Fill in this new structure from scratch.  */
212
213       char *namep = (char *) (result_ptr + 1);
214
215       /* Install copied new names in the new structure's __names array.
216          If resolved to "C", that is already in RESULT.__names to start.  */
217       for (cnt = 0; cnt < __LC_LAST; ++cnt)
218         if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name)
219           {
220             result.__names[cnt] = namep;
221             namep = __stpcpy (namep, newnames[cnt]) + 1;
222           }
223
224       *result_ptr = result;
225     }
226   else
227     {
228       /* We modify the base structure.  */
229
230       char *namep = (char *) (result_ptr + 1);
231
232       for (cnt = 0; cnt < __LC_LAST; ++cnt)
233         if ((category_mask & 1 << cnt) != 0)
234           {
235             if (base->__locales[cnt]->usage_count != UNDELETABLE)
236               /* We can remove the old data.  */
237               _nl_remove_locale (cnt, base->__locales[cnt]);
238             result_ptr->__locales[cnt] = result.__locales[cnt];
239
240             if (newnames[cnt] == _nl_C_name)
241               result_ptr->__names[cnt] = _nl_C_name;
242             else
243               {
244                 result_ptr->__names[cnt] = namep;
245                 namep = __stpcpy (namep, newnames[cnt]) + 1;
246               }
247           }
248         else if (cnt != LC_ALL)
249           {
250             /* The RESULT members point into the old BASE structure.  */
251             result_ptr->__locales[cnt] = result.__locales[cnt];
252             if (result.__names[cnt] == _nl_C_name)
253               result_ptr->__names[cnt] = _nl_C_name;
254             else
255               {
256                 result_ptr->__names[cnt] = namep;
257                 namep = __stpcpy (namep, result.__names[cnt]) + 1;
258               }
259           }
260
261       free (base);
262     }
263
264   /* Critical section left.  */
265   __libc_lock_unlock (__libc_setlocale_lock);
266
267   /* Update the special members.  */
268  update:
269   {
270     union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
271     result_ptr->__ctype_b = (const unsigned short int *)
272       ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)].string + 128;
273     result_ptr->__ctype_tolower = (const int *)
274       ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER)].string + 128;
275     result_ptr->__ctype_toupper = (const int *)
276       ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER)].string + 128;
277   }
278
279   return result_ptr;
280 }
281 weak_alias (__newlocale, newlocale)