]>
Commit | Line | Data |
---|---|---|
bfff8b1b | 1 | /* Copyright (C) 1998-2017 Free Software Foundation, Inc. |
4bca4c17 UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
4bca4c17 UD |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
4bca4c17 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
4bca4c17 | 18 | |
e4d0709f | 19 | #include <ctype.h> |
4bca4c17 UD |
20 | #include <langinfo.h> |
21 | #include <limits.h> | |
4553f228 UD |
22 | #include <stdlib.h> |
23 | #include <string.h> | |
4bca4c17 | 24 | |
4553f228 | 25 | #include <locale/localeinfo.h> |
4bca4c17 | 26 | #include <wcsmbsload.h> |
ec999b8e | 27 | #include <libc-lock.h> |
4bca4c17 UD |
28 | |
29 | ||
4bca4c17 | 30 | /* These are the descriptions for the default conversion functions. */ |
bd62cef6 | 31 | static const struct __gconv_step to_wc = |
4bca4c17 | 32 | { |
d64b6ad0 UD |
33 | .__shlib_handle = NULL, |
34 | .__modname = NULL, | |
35 | .__counter = INT_MAX, | |
129d706d UD |
36 | .__from_name = (char *) "ANSI_X3.4-1968//TRANSLIT", |
37 | .__to_name = (char *) "INTERNAL", | |
d64b6ad0 | 38 | .__fct = __gconv_transform_ascii_internal, |
f9ad060c | 39 | .__btowc_fct = __gconv_btwoc_ascii, |
d64b6ad0 UD |
40 | .__init_fct = NULL, |
41 | .__end_fct = NULL, | |
42 | .__min_needed_from = 1, | |
43 | .__max_needed_from = 1, | |
44 | .__min_needed_to = 4, | |
45 | .__max_needed_to = 4, | |
46 | .__stateful = 0, | |
47 | .__data = NULL | |
4bca4c17 UD |
48 | }; |
49 | ||
bd62cef6 | 50 | static const struct __gconv_step to_mb = |
4bca4c17 | 51 | { |
d64b6ad0 UD |
52 | .__shlib_handle = NULL, |
53 | .__modname = NULL, | |
54 | .__counter = INT_MAX, | |
129d706d UD |
55 | .__from_name = (char *) "INTERNAL", |
56 | .__to_name = (char *) "ANSI_X3.4-1968//TRANSLIT", | |
d64b6ad0 | 57 | .__fct = __gconv_transform_internal_ascii, |
f9ad060c | 58 | .__btowc_fct = NULL, |
d64b6ad0 UD |
59 | .__init_fct = NULL, |
60 | .__end_fct = NULL, | |
61 | .__min_needed_from = 4, | |
62 | .__max_needed_from = 4, | |
63 | .__min_needed_to = 1, | |
64 | .__max_needed_to = 1, | |
65 | .__stateful = 0, | |
66 | .__data = NULL | |
4bca4c17 UD |
67 | }; |
68 | ||
69 | ||
70 | /* For the default locale we only have to handle ANSI_X3.4-1968. */ | |
96310297 | 71 | const struct gconv_fcts __wcsmbs_gconv_fcts_c = |
4bca4c17 | 72 | { |
bd62cef6 | 73 | .towc = (struct __gconv_step *) &to_wc, |
129d706d | 74 | .towc_nsteps = 1, |
bd62cef6 | 75 | .tomb = (struct __gconv_step *) &to_mb, |
db6af3eb | 76 | .tomb_nsteps = 1, |
4bca4c17 UD |
77 | }; |
78 | ||
79 | ||
01beb5b9 | 80 | attribute_hidden |
c4bb5cd8 | 81 | struct __gconv_step * |
01beb5b9 | 82 | __wcsmbs_getfct (const char *to, const char *from, size_t *nstepsp) |
4bca4c17 UD |
83 | { |
84 | size_t nsteps; | |
d64b6ad0 | 85 | struct __gconv_step *result; |
129d706d | 86 | #if 0 |
d64b6ad0 UD |
87 | size_t nstateful; |
88 | size_t cnt; | |
129d706d | 89 | #endif |
4bca4c17 | 90 | |
c90a2db6 | 91 | if (__gconv_find_transform (to, from, &result, &nsteps, 0) != __GCONV_OK) |
4bca4c17 UD |
92 | /* Loading the conversion step is not possible. */ |
93 | return NULL; | |
94 | ||
129d706d UD |
95 | /* Maybe it is someday necessary to allow more than one step. |
96 | Currently this is not the case since the conversions handled here | |
97 | are from and to INTERNAL and there always is a converted for | |
98 | that. It the directly following code is enabled the libio | |
99 | functions will have to allocate appropriate __gconv_step_data | |
100 | elements instead of only one. */ | |
101 | #if 0 | |
d64b6ad0 UD |
102 | /* Count the number of stateful conversions. Since we will only |
103 | have one 'mbstate_t' object available we can only deal with one | |
104 | stateful conversion. */ | |
105 | nstateful = 0; | |
106 | for (cnt = 0; cnt < nsteps; ++cnt) | |
107 | if (result[cnt].__stateful) | |
108 | ++nstateful; | |
109 | if (nstateful > 1) | |
129d706d UD |
110 | #else |
111 | if (nsteps > 1) | |
112 | #endif | |
d64b6ad0 UD |
113 | { |
114 | /* We cannot handle this case. */ | |
115 | __gconv_close_transform (result, nsteps); | |
116 | result = NULL; | |
117 | } | |
129d706d UD |
118 | else |
119 | *nstepsp = nsteps; | |
4bca4c17 UD |
120 | |
121 | return result; | |
122 | } | |
123 | ||
124 | ||
4553f228 UD |
125 | /* Extract from the given locale name the character set portion. Since |
126 | only the XPG form of the name includes this information we don't have | |
127 | to take care for the CEN form. */ | |
128 | #define extract_charset_name(str) \ | |
129 | ({ \ | |
130 | const char *cp = str; \ | |
131 | char *result = NULL; \ | |
132 | \ | |
b17277cf | 133 | cp += strcspn (cp, "@.+,"); \ |
4553f228 UD |
134 | if (*cp == '.') \ |
135 | { \ | |
a7c378d8 | 136 | const char *endp = ++cp; \ |
4553f228 UD |
137 | while (*endp != '\0' && *endp != '@') \ |
138 | ++endp; \ | |
139 | if (endp != cp) \ | |
a7c378d8 | 140 | result = strndupa (cp, endp - cp); \ |
4553f228 UD |
141 | } \ |
142 | result; \ | |
4553f228 UD |
143 | }) |
144 | ||
145 | ||
96310297 | 146 | /* Some of the functions here must not be used while setlocale is called. */ |
91e32540 | 147 | __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden) |
d64b6ad0 | 148 | |
4bca4c17 UD |
149 | /* Load conversion functions for the currently selected locale. */ |
150 | void | |
00995ca9 | 151 | internal_function |
f095bb72 | 152 | __wcsmbs_load_conv (struct __locale_data *new_category) |
4bca4c17 | 153 | { |
4bca4c17 | 154 | /* Acquire the lock. */ |
91e32540 | 155 | __libc_rwlock_wrlock (__libc_setlocale_lock); |
4bca4c17 | 156 | |
61d655c1 | 157 | /* We should repeat the test since while we waited some other thread |
4bca4c17 | 158 | might have run this function. */ |
a1ffb40e | 159 | if (__glibc_likely (new_category->private.ctype == NULL)) |
4bca4c17 | 160 | { |
96310297 RM |
161 | /* We must find the real functions. */ |
162 | const char *charset_name; | |
163 | const char *complete_name; | |
164 | struct gconv_fcts *new_fcts; | |
165 | int use_translit; | |
166 | ||
167 | /* Allocate the gconv_fcts structure. */ | |
9954432e | 168 | new_fcts = calloc (1, sizeof *new_fcts); |
96310297 | 169 | if (new_fcts == NULL) |
6e606fad | 170 | goto failed; |
96310297 RM |
171 | |
172 | /* Get name of charset of the locale. */ | |
173 | charset_name = new_category->values[_NL_ITEM_INDEX(CODESET)].string; | |
174 | ||
175 | /* Does the user want transliteration? */ | |
176 | use_translit = new_category->use_translit; | |
177 | ||
178 | /* Normalize the name and add the slashes necessary for a | |
179 | complete lookup. */ | |
180 | complete_name = norm_add_slashes (charset_name, | |
db2f05ba | 181 | use_translit ? "TRANSLIT" : ""); |
96310297 RM |
182 | |
183 | /* It is not necessary to use transliteration in this direction | |
184 | since the internal character set is supposed to be able to | |
185 | represent all others. */ | |
186 | new_fcts->towc = __wcsmbs_getfct ("INTERNAL", complete_name, | |
187 | &new_fcts->towc_nsteps); | |
9954432e UD |
188 | if (new_fcts->towc != NULL) |
189 | new_fcts->tomb = __wcsmbs_getfct (complete_name, "INTERNAL", | |
190 | &new_fcts->tomb_nsteps); | |
96310297 RM |
191 | |
192 | /* If any of the conversion functions is not available we don't | |
193 | use any since this would mean we cannot convert back and | |
d3ed7225 | 194 | forth. NB: NEW_FCTS was allocated with calloc. */ |
96310297 | 195 | if (new_fcts->tomb == NULL) |
4bca4c17 | 196 | { |
96310297 RM |
197 | if (new_fcts->towc != NULL) |
198 | __gconv_close_transform (new_fcts->towc, new_fcts->towc_nsteps); | |
199 | ||
200 | free (new_fcts); | |
4bca4c17 | 201 | |
6e606fad RM |
202 | failed: |
203 | new_category->private.ctype = &__wcsmbs_gconv_fcts_c; | |
204 | } | |
205 | else | |
206 | { | |
207 | new_category->private.ctype = new_fcts; | |
208 | new_category->private.cleanup = &_nl_cleanup_ctype; | |
209 | } | |
4bca4c17 UD |
210 | } |
211 | ||
91e32540 | 212 | __libc_rwlock_unlock (__libc_setlocale_lock); |
4bca4c17 | 213 | } |
d64b6ad0 UD |
214 | |
215 | ||
216 | /* Clone the current conversion function set. */ | |
217 | void | |
218 | internal_function | |
219 | __wcsmbs_clone_conv (struct gconv_fcts *copy) | |
220 | { | |
96310297 | 221 | const struct gconv_fcts *orig; |
34e3c127 | 222 | |
96310297 | 223 | orig = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE)); |
d64b6ad0 UD |
224 | |
225 | /* Copy the data. */ | |
96310297 | 226 | *copy = *orig; |
d64b6ad0 | 227 | |
f9ad060c | 228 | /* Now increment the usage counters. |
9954432e | 229 | Note: This assumes copy->*_nsteps == 1. */ |
d64b6ad0 UD |
230 | if (copy->towc->__shlib_handle != NULL) |
231 | ++copy->towc->__counter; | |
232 | if (copy->tomb->__shlib_handle != NULL) | |
233 | ++copy->tomb->__counter; | |
d64b6ad0 | 234 | } |
4e2e9999 UD |
235 | |
236 | ||
129d706d | 237 | /* Get converters for named charset. */ |
4e2e9999 UD |
238 | int |
239 | internal_function | |
240 | __wcsmbs_named_conv (struct gconv_fcts *copy, const char *name) | |
241 | { | |
01beb5b9 | 242 | copy->towc = __wcsmbs_getfct ("INTERNAL", name, ©->towc_nsteps); |
db6af3eb UD |
243 | if (copy->towc == NULL) |
244 | return 1; | |
245 | ||
246 | copy->tomb = __wcsmbs_getfct (name, "INTERNAL", ©->tomb_nsteps); | |
247 | if (copy->tomb == NULL) | |
4e2e9999 | 248 | { |
db6af3eb | 249 | __gconv_close_transform (copy->towc, copy->towc_nsteps); |
db6af3eb | 250 | return 1; |
4e2e9999 UD |
251 | } |
252 | ||
db6af3eb | 253 | return 0; |
129d706d | 254 | } |
4e2e9999 | 255 | |
96310297 | 256 | void internal_function |
f095bb72 | 257 | _nl_cleanup_ctype (struct __locale_data *locale) |
129d706d | 258 | { |
96310297 RM |
259 | const struct gconv_fcts *const data = locale->private.ctype; |
260 | if (data != NULL) | |
129d706d | 261 | { |
96310297 RM |
262 | locale->private.ctype = NULL; |
263 | locale->private.cleanup = NULL; | |
129d706d | 264 | |
96310297 RM |
265 | /* Free the old conversions. */ |
266 | __gconv_close_transform (data->tomb, data->tomb_nsteps); | |
267 | __gconv_close_transform (data->towc, data->towc_nsteps); | |
268 | free ((char *) data); | |
129d706d | 269 | } |
4e2e9999 | 270 | } |