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