]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/newlocale.c
[BZ #5443]
[thirdparty/glibc.git] / locale / newlocale.c
CommitLineData
c84142e8 1/* Return a reference to locale information record.
9a69db29 2 Copyright (C) 1996, 1997, 1999, 2000-2002, 2004, 2005, 2006, 2008
531b71dd 3 Free Software Foundation, Inc.
c84142e8
UD
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
41bdb6e2
AJ
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.
c84142e8
UD
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
41bdb6e2 15 Lesser General Public License for more details.
c84142e8 16
41bdb6e2
AJ
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. */
c84142e8
UD
21
22#include <argz.h>
531b71dd 23#include <bits/libc-lock.h>
c84142e8
UD
24#include <errno.h>
25#include <locale.h>
26#include <stdlib.h>
26e40124 27#include <string.h>
c84142e8
UD
28
29#include "localeinfo.h"
30
31
531b71dd 32/* Lock for protecting global data. */
9a69db29 33__libc_rwlock_define (extern , __libc_setlocale_lock attribute_hidden)
531b71dd
UD
34
35
c84142e8
UD
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. */
4b10dd6c 48 const char *newnames[__LC_LAST];
4cca6b86 49 struct __locale_struct result;
c84142e8
UD
50 __locale_t result_ptr;
51 char *locale_path;
52 size_t locale_path_len;
53 const char *locpath_var;
54 int cnt;
a0fc81e1 55 size_t names_len;
c84142e8
UD
56
57 /* We treat LC_ALL in the same way as if all bits were set. */
f7719a9a 58 if (category_mask == 1 << LC_ALL)
4b10dd6c 59 category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL);
c84142e8
UD
60
61 /* Sanity check for CATEGORY argument. */
5bef2820 62 if ((category_mask & ~((1 << __LC_LAST) - 1 - (1 << LC_ALL))) != 0)
c84142e8
UD
63 ERROR_RETURN;
64
65 /* `newlocale' does not support asking for the locale name. */
66 if (locale == NULL)
67 ERROR_RETURN;
68
4b5b009c 69 if (base == _nl_C_locobj_ptr)
679e4c43
RM
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. */
4b5b009c 78 return _nl_C_locobj_ptr;
679e4c43 79
c84142e8
UD
80 /* Allocate memory for the result. */
81 if (base != NULL)
5bef2820 82 result = *base;
c84142e8 83 else
30c14c31
RM
84 /* Fill with pointers to C locale data. */
85 result = _nl_C_locobj;
c84142e8 86
5bef2820
UD
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;
c84142e8 95
5bef2820 96 goto update;
c84142e8
UD
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
cb09a2cd
RM
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. */
c84142e8
UD
104 locale_path = NULL;
105 locale_path_len = 0;
106
74955460 107 locpath_var = getenv ("LOCPATH");
c84142e8 108 if (locpath_var != NULL && locpath_var[0] != '\0')
cb09a2cd
RM
109 {
110 if (__argz_create_sep (locpath_var, ':',
111 &locale_path, &locale_path_len) != 0)
112 return NULL;
c84142e8 113
cb09a2cd
RM
114 if (__argz_add_sep (&locale_path, &locale_path_len,
115 _nl_default_locale_path, ':') != 0)
116 return NULL;
117 }
c84142e8
UD
118
119 /* Get the names for the locales we are interested in. We either
120 allow a composite name or a single name. */
4b10dd6c
UD
121 for (cnt = 0; cnt < __LC_LAST; ++cnt)
122 if (cnt != LC_ALL)
123 newnames[cnt] = locale;
c84142e8
UD
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;
78323b5b 129 int specified_mask = 0;
c84142e8
UD
130
131 while ((cp = strchr (np, '=')) != NULL)
132 {
4b10dd6c
UD
133 for (cnt = 0; cnt < __LC_LAST; ++cnt)
134 if (cnt != LC_ALL
135 && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
9446614c
UD
136 && memcmp (np, (_nl_category_names.str
137 + _nl_category_name_idxs[cnt]), cp - np) == 0)
c84142e8
UD
138 break;
139
4b10dd6c 140 if (cnt == __LC_LAST)
c84142e8
UD
141 /* Bogus category name. */
142 ERROR_RETURN;
143
144 /* Found the category this clause sets. */
78323b5b 145 specified_mask |= 1 << cnt;
c84142e8
UD
146 newnames[cnt] = ++cp;
147 cp = strchr (cp, ';');
148 if (cp != NULL)
149 {
150 /* Examine the next clause. */
151 *cp = '\0';
152 np = cp + 1;
153 }
154 else
155 /* This was the last clause. We are done. */
156 break;
157 }
158
78323b5b
RM
159 if (category_mask &~ specified_mask)
160 /* The composite name did not specify all categories we need. */
161 ERROR_RETURN;
c84142e8
UD
162 }
163
531b71dd 164 /* Protect global data. */
9a69db29 165 __libc_rwlock_wrlock (__libc_setlocale_lock);
531b71dd 166
c84142e8 167 /* Now process all categories we are interested in. */
a0fc81e1 168 names_len = 0;
4b10dd6c 169 for (cnt = 0; cnt < __LC_LAST; ++cnt)
a0fc81e1
RM
170 {
171 if ((category_mask & 1 << cnt) != 0)
172 {
173 result.__locales[cnt] = _nl_find_locale (locale_path,
174 locale_path_len,
175 cnt, &newnames[cnt]);
176 if (result.__locales[cnt] == NULL)
177 {
178 free_cnt_data_and_exit:
179 while (cnt-- > 0)
180 if (((category_mask & 1 << cnt) != 0)
181 && result.__locales[cnt]->usage_count != UNDELETABLE)
182 /* We can remove the data. */
183 _nl_remove_locale (cnt, result.__locales[cnt]);
531b71dd
UD
184
185 /* Critical section left. */
9a69db29 186 __libc_rwlock_unlock (__libc_setlocale_lock);
a0fc81e1
RM
187 return NULL;
188 }
189
190 if (newnames[cnt] != _nl_C_name)
191 names_len += strlen (newnames[cnt]) + 1;
192 }
193 else if (cnt != LC_ALL && result.__names[cnt] != _nl_C_name)
194 /* Tally up the unchanged names from BASE as well. */
195 names_len += strlen (result.__names[cnt]) + 1;
196 }
197
198 /* We successfully loaded all required data. Allocate a new structure.
199 We can't just reuse the BASE pointer, because the name strings are
200 changing and we need the old name string area intact so we can copy
201 out of it into the new one without overlap problems should some
202 category's name be getting longer. */
203 result_ptr = malloc (sizeof (struct __locale_struct) + names_len);
204 if (result_ptr == NULL)
205 {
206 cnt = __LC_LAST;
207 goto free_cnt_data_and_exit;
208 }
c84142e8 209
c84142e8
UD
210 if (base == NULL)
211 {
a0fc81e1
RM
212 /* Fill in this new structure from scratch. */
213
214 char *namep = (char *) (result_ptr + 1);
c84142e8 215
a0fc81e1 216 /* Install copied new names in the new structure's __names array.
252e7983 217 If resolved to "C", that is already in RESULT.__names to start. */
26e40124 218 for (cnt = 0; cnt < __LC_LAST; ++cnt)
252e7983 219 if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name)
26e40124 220 {
a0fc81e1
RM
221 result.__names[cnt] = namep;
222 namep = __stpcpy (namep, newnames[cnt]) + 1;
26e40124 223 }
252e7983
RM
224
225 *result_ptr = result;
c84142e8
UD
226 }
227 else
26e40124 228 {
a0fc81e1 229 /* We modify the base structure. */
26e40124 230
a0fc81e1 231 char *namep = (char *) (result_ptr + 1);
26e40124 232
26e40124 233 for (cnt = 0; cnt < __LC_LAST; ++cnt)
252e7983 234 if ((category_mask & 1 << cnt) != 0)
26e40124 235 {
252e7983
RM
236 if (base->__locales[cnt]->usage_count != UNDELETABLE)
237 /* We can remove the old data. */
238 _nl_remove_locale (cnt, base->__locales[cnt]);
a0fc81e1 239 result_ptr->__locales[cnt] = result.__locales[cnt];
252e7983 240
a0fc81e1
RM
241 if (newnames[cnt] == _nl_C_name)
242 result_ptr->__names[cnt] = _nl_C_name;
243 else
244 {
245 result_ptr->__names[cnt] = namep;
246 namep = __stpcpy (namep, newnames[cnt]) + 1;
247 }
248 }
249 else if (cnt != LC_ALL)
250 {
251 /* The RESULT members point into the old BASE structure. */
252 result_ptr->__locales[cnt] = result.__locales[cnt];
253 if (result.__names[cnt] == _nl_C_name)
254 result_ptr->__names[cnt] = _nl_C_name;
255 else
256 {
257 result_ptr->__names[cnt] = namep;
258 namep = __stpcpy (namep, result.__names[cnt]) + 1;
259 }
26e40124
RM
260 }
261
a0fc81e1 262 free (base);
26e40124 263 }
5db91571 264
531b71dd 265 /* Critical section left. */
9a69db29 266 __libc_rwlock_unlock (__libc_setlocale_lock);
531b71dd 267
c84142e8
UD
268 /* Update the special members. */
269 update:
270 {
271 union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
5bef2820 272 result_ptr->__ctype_b = (const unsigned short int *)
671ab00d 273 ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)].string + 128;
5bef2820 274 result_ptr->__ctype_tolower = (const int *)
671ab00d 275 ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER)].string + 128;
5bef2820 276 result_ptr->__ctype_toupper = (const int *)
671ab00d 277 ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER)].string + 128;
c84142e8
UD
278 }
279
280 return result_ptr;
281}
30c14c31 282weak_alias (__newlocale, newlocale)