]>
Commit | Line | Data |
---|---|---|
c84142e8 | 1 | /* Return a reference to locale information record. |
4b10dd6c | 2 | Copyright (C) 1996, 1997, 1999 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 | |
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. | |
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 | |
14 | Library General Public License for more details. | |
15 | ||
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. */ | |
20 | ||
21 | #include <argz.h> | |
22 | #include <errno.h> | |
23 | #include <locale.h> | |
24 | #include <stdlib.h> | |
25 | ||
26 | #include "localeinfo.h" | |
27 | ||
28 | ||
29 | /* Constant data defined in setlocale.c. */ | |
30 | extern struct locale_data *const _nl_C[]; | |
31 | ||
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) | |
38 | ||
39 | ||
40 | __locale_t | |
41 | __newlocale (int category_mask, const char *locale, __locale_t base) | |
42 | { | |
43 | /* Intermediate memory for result. */ | |
4b10dd6c | 44 | const char *newnames[__LC_LAST]; |
4cca6b86 | 45 | struct __locale_struct result; |
c84142e8 UD |
46 | __locale_t result_ptr; |
47 | char *locale_path; | |
48 | size_t locale_path_len; | |
49 | const char *locpath_var; | |
50 | int cnt; | |
51 | ||
52 | /* We treat LC_ALL in the same way as if all bits were set. */ | |
53 | if (category_mask == LC_ALL) | |
4b10dd6c | 54 | category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL); |
c84142e8 UD |
55 | |
56 | /* Sanity check for CATEGORY argument. */ | |
4b10dd6c | 57 | if ((category_mask & ~((1 << LC_ALL) - 1 - (1 << LC_ALL))) != 0) |
c84142e8 UD |
58 | ERROR_RETURN; |
59 | ||
60 | /* `newlocale' does not support asking for the locale name. */ | |
61 | if (locale == NULL) | |
62 | ERROR_RETURN; | |
63 | ||
64 | /* Allocate memory for the result. */ | |
65 | if (base != NULL) | |
66 | { | |
67 | if (base != NULL) | |
68 | return base; | |
69 | ||
70 | result = *base; | |
71 | } | |
72 | else | |
73 | { | |
74 | /* Fill with pointers to C locale data to . */ | |
4b10dd6c UD |
75 | for (cnt = 0; cnt < __LC_LAST; ++cnt) |
76 | if (cnt != LC_ALL) | |
77 | result.__locales[cnt] = _nl_C[cnt]; | |
c84142e8 UD |
78 | |
79 | /* If no category is to be set we return BASE if available or a | |
80 | dataset using the C locale data. */ | |
81 | if (category_mask == 0) | |
82 | { | |
4cca6b86 | 83 | result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct)); |
c84142e8 UD |
84 | *result_ptr = result; |
85 | ||
86 | goto update; | |
87 | } | |
88 | } | |
89 | ||
90 | /* We perhaps really have to load some data. So we determine the | |
91 | path in which to look for the data now. The environment variable | |
92 | `LOCPATH' must only be used when the binary has no SUID or SGID | |
93 | bit set. */ | |
94 | locale_path = NULL; | |
95 | locale_path_len = 0; | |
96 | ||
97 | locpath_var = __secure_getenv ("LOCPATH"); | |
98 | if (locpath_var != NULL && locpath_var[0] != '\0') | |
99 | if (__argz_create_sep (locpath_var, ':', | |
100 | &locale_path, &locale_path_len) != 0) | |
101 | return NULL; | |
102 | ||
103 | if (__argz_append (&locale_path, &locale_path_len, | |
104 | LOCALE_PATH, sizeof (LOCALE_PATH)) != 0) | |
105 | return NULL; | |
106 | ||
107 | /* Get the names for the locales we are interested in. We either | |
108 | allow a composite name or a single name. */ | |
4b10dd6c UD |
109 | for (cnt = 0; cnt < __LC_LAST; ++cnt) |
110 | if (cnt != LC_ALL) | |
111 | newnames[cnt] = locale; | |
c84142e8 UD |
112 | if (strchr (locale, ';') != NULL) |
113 | { | |
114 | /* This is a composite name. Make a copy and split it up. */ | |
115 | char *np = strdupa (locale); | |
116 | char *cp; | |
117 | ||
118 | while ((cp = strchr (np, '=')) != NULL) | |
119 | { | |
4b10dd6c UD |
120 | for (cnt = 0; cnt < __LC_LAST; ++cnt) |
121 | if (cnt != LC_ALL | |
122 | && (size_t) (cp - np) == _nl_category_name_sizes[cnt] | |
c84142e8 UD |
123 | && memcmp (np, _nl_category_names[cnt], cp - np) == 0) |
124 | break; | |
125 | ||
4b10dd6c | 126 | if (cnt == __LC_LAST) |
c84142e8 UD |
127 | /* Bogus category name. */ |
128 | ERROR_RETURN; | |
129 | ||
130 | /* Found the category this clause sets. */ | |
131 | newnames[cnt] = ++cp; | |
132 | cp = strchr (cp, ';'); | |
133 | if (cp != NULL) | |
134 | { | |
135 | /* Examine the next clause. */ | |
136 | *cp = '\0'; | |
137 | np = cp + 1; | |
138 | } | |
139 | else | |
140 | /* This was the last clause. We are done. */ | |
141 | break; | |
142 | } | |
143 | ||
4b10dd6c UD |
144 | for (cnt = 0; cnt < __LC_LAST; ++cnt) |
145 | if (cnt != LC_ALL | |
146 | && (category_mask & 1 << cnt) != 0 && newnames[cnt] == locale) | |
c84142e8 UD |
147 | /* The composite name did not specify the category we need. */ |
148 | ERROR_RETURN; | |
149 | } | |
150 | ||
151 | /* Now process all categories we are interested in. */ | |
4b10dd6c UD |
152 | for (cnt = 0; cnt < __LC_LAST; ++cnt) |
153 | if (cnt != LC_ALL && (category_mask & 1 << cnt) != 0) | |
c84142e8 UD |
154 | { |
155 | result.__locales[cnt] = _nl_find_locale (locale_path, locale_path_len, | |
156 | cnt, &newnames[cnt]); | |
157 | if (result.__locales[cnt] == NULL) | |
158 | return NULL; | |
159 | } | |
160 | ||
161 | /* We successfully loaded all required data. */ | |
162 | if (base == NULL) | |
163 | { | |
164 | /* Allocate new structure. */ | |
4cca6b86 | 165 | result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct)); |
c84142e8 UD |
166 | if (result_ptr == NULL) |
167 | return NULL; | |
168 | ||
169 | *result_ptr = result; | |
170 | } | |
171 | else | |
172 | *(result_ptr = base) = result; | |
173 | ||
174 | /* Update the special members. */ | |
175 | update: | |
176 | { | |
177 | union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values; | |
178 | result_ptr->__ctype_b = (const unsigned short int *) | |
179 | (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)] .string); | |
180 | #if BYTE_ORDER == BIG_ENDIAN | |
181 | result_ptr->__ctype_tolower = (const int *) | |
182 | (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER_EB)].string); | |
183 | result_ptr->__ctype_toupper = (const int *) | |
184 | (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER_EB)].string); | |
185 | #elif BYTE_ORDER == LITTLE_ENDIAN | |
186 | result_ptr->__ctype_tolower = (const int *) | |
187 | (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER_EL)].string); | |
188 | result_ptr->__ctype_toupper = (const int *) | |
189 | (ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER_EL)].string); | |
190 | #else | |
191 | #error bizarre byte order | |
192 | #endif | |
193 | } | |
194 | ||
195 | return result_ptr; | |
196 | } |