Define _POSIX_THREAD_PRIORITY_SCHEDULING.
[glibc/pb-stable.git] / locale / newlocale.c
blob1131f62c0bafaf7fbf1474357aaf1443ec901de6
1 /* Return a reference to locale information record.
2 Copyright (C) 1996,1997,1999,2000,2001,2002 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
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.
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
14 Lesser General Public License for more details.
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. */
21 #include <argz.h>
22 #include <errno.h>
23 #include <locale.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "localeinfo.h"
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)
38 __locale_t
39 __newlocale (int category_mask, const char *locale, __locale_t base)
41 /* Intermediate memory for result. */
42 const char *newnames[__LC_LAST];
43 struct __locale_struct result;
44 __locale_t result_ptr;
45 char *locale_path;
46 size_t locale_path_len;
47 const char *locpath_var;
48 int cnt;
49 size_t names_len;
51 /* We treat LC_ALL in the same way as if all bits were set. */
52 if (category_mask == 1 << LC_ALL)
53 category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL);
55 /* Sanity check for CATEGORY argument. */
56 if ((category_mask & ~((1 << __LC_LAST) - 1 - (1 << LC_ALL))) != 0)
57 ERROR_RETURN;
59 /* `newlocale' does not support asking for the locale name. */
60 if (locale == NULL)
61 ERROR_RETURN;
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;
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;
74 /* Allocate memory for the result. */
75 if (base != NULL)
76 result = *base;
77 else
78 /* Fill with pointers to C locale data. */
79 result = _nl_C_locobj;
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)
85 result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
86 if (result_ptr == NULL)
87 return NULL;
88 *result_ptr = result;
90 goto update;
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
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. */
98 locale_path = NULL;
99 locale_path_len = 0;
101 locpath_var = getenv ("LOCPATH");
102 if (locpath_var != NULL && locpath_var[0] != '\0')
104 if (__argz_create_sep (locpath_var, ':',
105 &locale_path, &locale_path_len) != 0)
106 return NULL;
108 if (__argz_add_sep (&locale_path, &locale_path_len,
109 _nl_default_locale_path, ':') != 0)
110 return NULL;
113 /* Get the names for the locales we are interested in. We either
114 allow a composite name or a single name. */
115 for (cnt = 0; cnt < __LC_LAST; ++cnt)
116 if (cnt != LC_ALL)
117 newnames[cnt] = locale;
118 if (strchr (locale, ';') != NULL)
120 /* This is a composite name. Make a copy and split it up. */
121 char *np = strdupa (locale);
122 char *cp;
123 int specified_mask = 0;
125 while ((cp = strchr (np, '=')) != NULL)
127 for (cnt = 0; cnt < __LC_LAST; ++cnt)
128 if (cnt != LC_ALL
129 && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
130 && memcmp (np, _nl_category_names[cnt], cp - np) == 0)
131 break;
133 if (cnt == __LC_LAST)
134 /* Bogus category name. */
135 ERROR_RETURN;
137 /* Found the category this clause sets. */
138 specified_mask |= 1 << cnt;
139 newnames[cnt] = ++cp;
140 cp = strchr (cp, ';');
141 if (cp != NULL)
143 /* Examine the next clause. */
144 *cp = '\0';
145 np = cp + 1;
147 else
148 /* This was the last clause. We are done. */
149 break;
152 if (category_mask &~ specified_mask)
153 /* The composite name did not specify all categories we need. */
154 ERROR_RETURN;
157 /* Now process all categories we are interested in. */
158 names_len = 0;
159 for (cnt = 0; cnt < __LC_LAST; ++cnt)
161 if ((category_mask & 1 << cnt) != 0)
163 result.__locales[cnt] = _nl_find_locale (locale_path,
164 locale_path_len,
165 cnt, &newnames[cnt]);
166 if (result.__locales[cnt] == NULL)
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;
177 if (newnames[cnt] != _nl_C_name)
178 names_len += strlen (newnames[cnt]) + 1;
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;
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)
193 cnt = __LC_LAST;
194 goto free_cnt_data_and_exit;
197 if (base == NULL)
199 /* Fill in this new structure from scratch. */
201 char *namep = (char *) (result_ptr + 1);
203 /* Install copied new names in the new structure's __names array.
204 If resolved to "C", that is already in RESULT.__names to start. */
205 for (cnt = 0; cnt < __LC_LAST; ++cnt)
206 if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name)
208 result.__names[cnt] = namep;
209 namep = __stpcpy (namep, newnames[cnt]) + 1;
212 *result_ptr = result;
214 else
216 /* We modify the base structure. */
218 char *namep = (char *) (result_ptr + 1);
220 for (cnt = 0; cnt < __LC_LAST; ++cnt)
221 if ((category_mask & 1 << cnt) != 0)
223 if (base->__locales[cnt]->usage_count != UNDELETABLE)
224 /* We can remove the old data. */
225 _nl_remove_locale (cnt, base->__locales[cnt]);
226 result_ptr->__locales[cnt] = result.__locales[cnt];
228 if (newnames[cnt] == _nl_C_name)
229 result_ptr->__names[cnt] = _nl_C_name;
230 else
232 result_ptr->__names[cnt] = namep;
233 namep = __stpcpy (namep, newnames[cnt]) + 1;
236 else if (cnt != LC_ALL)
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
244 result_ptr->__names[cnt] = namep;
245 namep = __stpcpy (namep, result.__names[cnt]) + 1;
249 free (base);
252 /* Update the special members. */
253 update:
255 union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
256 result_ptr->__ctype_b = (const unsigned short int *)
257 ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)].string + 128;
258 result_ptr->__ctype_tolower = (const int *)
259 ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER)].string + 128;
260 result_ptr->__ctype_toupper = (const int *)
261 ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER)].string + 128;
264 return result_ptr;
266 weak_alias (__newlocale, newlocale)