Rewrite by Zack Weinberg.
[glibc.git] / locale / newlocale.c
blob33cc7fa09ac03b84a00c49aa9ecb1cdf75c3671b
1 /* Return a reference to locale information record.
2 Copyright (C) 1996, 1997 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 Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 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 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include <argz.h>
22 #include <errno.h>
23 #include <locale.h>
24 #include <stdlib.h>
26 #include "localeinfo.h"
29 /* Constant data defined in setlocale.c. */
30 extern struct locale_data *const _nl_C[];
32 /* Use this when we come along an error. */
33 #define ERROR_RETURN \
34 do { \
35 __set_errno (EINVAL); \
36 return NULL; \
37 } while (0)
40 __locale_t
41 __newlocale (int category_mask, const char *locale, __locale_t base)
43 /* Intermediate memory for result. */
44 const char *newnames[LC_ALL];
45 struct __locale_struct result;
46 __locale_t result_ptr;
47 char *locale_path;
48 size_t locale_path_len;
49 const char *locpath_var;
50 int cnt;
52 /* We treat LC_ALL in the same way as if all bits were set. */
53 if (category_mask == LC_ALL)
54 category_mask = (1 << LC_ALL) - 1;
56 /* Sanity check for CATEGORY argument. */
57 if ((category_mask & ~(1 << LC_ALL) - 1) != 0)
58 ERROR_RETURN;
60 /* `newlocale' does not support asking for the locale name. */
61 if (locale == NULL)
62 ERROR_RETURN;
64 /* Allocate memory for the result. */
65 if (base != NULL)
67 if (base != NULL)
68 return base;
70 result = *base;
72 else
74 /* Fill with pointers to C locale data to . */
75 for (cnt = 0; cnt < LC_ALL; ++cnt)
76 result.__locales[cnt] = _nl_C[cnt];
78 /* If no category is to be set we return BASE if available or a
79 dataset using the C locale data. */
80 if (category_mask == 0)
82 result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
83 *result_ptr = result;
85 goto update;
89 /* We perhaps really have to load some data. So we determine the
90 path in which to look for the data now. The environment variable
91 `LOCPATH' must only be used when the binary has no SUID or SGID
92 bit set. */
93 locale_path = NULL;
94 locale_path_len = 0;
96 locpath_var = __secure_getenv ("LOCPATH");
97 if (locpath_var != NULL && locpath_var[0] != '\0')
98 if (__argz_create_sep (locpath_var, ':',
99 &locale_path, &locale_path_len) != 0)
100 return NULL;
102 if (__argz_append (&locale_path, &locale_path_len,
103 LOCALE_PATH, sizeof (LOCALE_PATH)) != 0)
104 return NULL;
106 /* Get the names for the locales we are interested in. We either
107 allow a composite name or a single name. */
108 for (cnt = 0; cnt < LC_ALL; ++cnt)
109 newnames[cnt] = locale;
110 if (strchr (locale, ';') != NULL)
112 /* This is a composite name. Make a copy and split it up. */
113 char *np = strdupa (locale);
114 char *cp;
116 while ((cp = strchr (np, '=')) != NULL)
118 for (cnt = 0; cnt < LC_ALL; ++cnt)
119 if ((size_t) (cp - np) == _nl_category_name_sizes[cnt]
120 && memcmp (np, _nl_category_names[cnt], cp - np) == 0)
121 break;
123 if (cnt == LC_ALL)
124 /* Bogus category name. */
125 ERROR_RETURN;
127 /* Found the category this clause sets. */
128 newnames[cnt] = ++cp;
129 cp = strchr (cp, ';');
130 if (cp != NULL)
132 /* Examine the next clause. */
133 *cp = '\0';
134 np = cp + 1;
136 else
137 /* This was the last clause. We are done. */
138 break;
141 for (cnt = 0; cnt < LC_ALL; ++cnt)
142 if ((category_mask & 1 << cnt) != 0 && newnames[cnt] == locale)
143 /* The composite name did not specify the category we need. */
144 ERROR_RETURN;
147 /* Now process all categories we are interested in. */
148 for (cnt = 0; cnt < LC_ALL; ++cnt)
149 if ((category_mask & 1 << cnt) != 0)
151 result.__locales[cnt] = _nl_find_locale (locale_path, locale_path_len,
152 cnt, &newnames[cnt]);
153 if (result.__locales[cnt] == NULL)
154 return NULL;
157 /* We successfully loaded all required data. */
158 if (base == NULL)
160 /* Allocate new structure. */
161 result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
162 if (result_ptr == NULL)
163 return NULL;
165 *result_ptr = result;
167 else
168 *(result_ptr = base) = result;
170 /* Update the special members. */
171 update:
173 union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
174 result_ptr->__ctype_b = (const unsigned short int *)
175 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)] .string);
176 #if BYTE_ORDER == BIG_ENDIAN
177 result_ptr->__ctype_tolower = (const int *)
178 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER_EB)].string);
179 result_ptr->__ctype_toupper = (const int *)
180 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER_EB)].string);
181 #elif BYTE_ORDER == LITTLE_ENDIAN
182 result_ptr->__ctype_tolower = (const int *)
183 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER_EL)].string);
184 result_ptr->__ctype_toupper = (const int *)
185 (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER_EL)].string);
186 #else
187 #error bizarre byte order
188 #endif
191 return result_ptr;