1 /* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. 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 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. 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 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with the GNU C Library; if not, write to the Free 17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 02111-1307 USA. */ 19 20 #include <ctype.h> 21 #include <langinfo.h> 22 #include <limits.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include <locale/localeinfo.h> 27 #include <wcsmbsload.h> 28 #include <bits/libc-lock.h> 29 #include <iconv/gconv_int.h> 30 31 void 32 internal_function 33 __wcsmbs_load_conv (const struct locale_data *new_category) 34 { 35 } 36 37 static void __attribute__ ((unused)) 38 free_mem (void) 39 { 40 } 41 42 /* Last loaded locale for LC_CTYPE. We initialize for the C locale 43 which is enabled at startup. */ 44 extern const struct locale_data _nl_C_LC_CTYPE; 45 const struct locale_data *__wcsmbs_last_locale = &_nl_C_LC_CTYPE; 46 47 48 /* These are the descriptions for the default conversion functions. */ 49 static struct __gconv_step to_wc = 50 { 51 .__shlib_handle = NULL, 52 .__modname = NULL, 53 .__counter = INT_MAX, 54 .__from_name = (char *) "ANSI_X3.4-1968//TRANSLIT", 55 .__to_name = (char *) "INTERNAL", 56 .__fct = NULL, // __gconv_transform_ascii_internal, 57 .__init_fct = NULL, 58 .__end_fct = NULL, 59 .__min_needed_from = 1, 60 .__max_needed_from = 1, 61 .__min_needed_to = 4, 62 .__max_needed_to = 4, 63 .__stateful = 0, 64 .__data = NULL 65 }; 66 67 static struct __gconv_step to_mb = 68 { 69 .__shlib_handle = NULL, 70 .__modname = NULL, 71 .__counter = INT_MAX, 72 .__from_name = (char *) "INTERNAL", 73 .__to_name = (char *) "ANSI_X3.4-1968//TRANSLIT", 74 .__fct = NULL, // __gconv_transform_internal_ascii, 75 .__init_fct = NULL, 76 .__end_fct = NULL, 77 .__min_needed_from = 4, 78 .__max_needed_from = 4, 79 .__min_needed_to = 1, 80 .__max_needed_to = 1, 81 .__stateful = 0, 82 .__data = NULL 83 }; 84 85 86 /* For the default locale we only have to handle ANSI_X3.4-1968. */ 87 struct gconv_fcts __wcsmbs_gconv_fcts = 88 { 89 .towc = &to_wc, 90 .towc_nsteps = 1, 91 .tomb = &to_mb, 92 .tomb_nsteps = 1 93 }; 94 95 #if 0 96 97 static inline struct __gconv_step * 98 getfct (const char *to, const char *from, size_t *nstepsp) 99 { 100 size_t nsteps; 101 struct __gconv_step *result; 102 #if 0 103 size_t nstateful; 104 size_t cnt; 105 #endif 106 107 if (__gconv_find_transform (to, from, &result, &nsteps, 0) != __GCONV_OK) 108 /* Loading the conversion step is not possible. */ 109 return NULL; 110 111 /* Maybe it is someday necessary to allow more than one step. 112 Currently this is not the case since the conversions handled here 113 are from and to INTERNAL and there always is a converted for 114 that. It the directly following code is enabled the libio 115 functions will have to allocate appropriate __gconv_step_data 116 elements instead of only one. */ 117 #if 0 118 /* Count the number of stateful conversions. Since we will only 119 have one 'mbstate_t' object available we can only deal with one 120 stateful conversion. */ 121 nstateful = 0; 122 for (cnt = 0; cnt < nsteps; ++cnt) 123 if (result[cnt].__stateful) 124 ++nstateful; 125 if (nstateful > 1) 126 #else 127 if (nsteps > 1) 128 #endif 129 { 130 /* We cannot handle this case. */ 131 __gconv_close_transform (result, nsteps); 132 result = NULL; 133 } 134 else 135 *nstepsp = nsteps; 136 137 return result; 138 } 139 140 141 /* Extract from the given locale name the character set portion. Since 142 only the XPG form of the name includes this information we don't have 143 to take care for the CEN form. */ 144 #define extract_charset_name(str) \ 145 ({ \ 146 const char *cp = str; \ 147 char *result = NULL; \ 148 \ 149 cp += strcspn (cp, "@.+,"); \ 150 if (*cp == '.') \ 151 { \ 152 const char *endp = ++cp; \ 153 while (*endp != '\0' && *endp != '@') \ 154 ++endp; \ 155 if (endp != cp) \ 156 result = strndupa (cp, endp - cp); \ 157 } \ 158 result; \ 159 }) 160 161 162 /* We must modify global data. */ 163 __libc_lock_define_initialized (static, lock) 164 165 166 /* Load conversion functions for the currently selected locale. */ 167 void 168 internal_function 169 __wcsmbs_load_conv (const struct locale_data *new_category) 170 { 171 /* Acquire the lock. */ 172 __libc_lock_lock (lock); 173 174 /* We should repeat the test since while we waited some other thread 175 might have run this function. */ 176 if (__builtin_expect (__wcsmbs_last_locale != new_category, 1)) 177 { 178 if (new_category->name == _nl_C_name) /* Yes, pointer comparison. */ 179 { 180 failed: 181 __wcsmbs_gconv_fcts.towc = &to_wc; 182 __wcsmbs_gconv_fcts.tomb = &to_mb; 183 } 184 else 185 { 186 /* We must find the real functions. */ 187 const char *charset_name; 188 const char *complete_name; 189 struct __gconv_step *new_towc; 190 size_t new_towc_nsteps; 191 struct __gconv_step *new_tomb; 192 size_t new_tomb_nsteps; 193 int use_translit; 194 195 /* Free the old conversions. */ 196 if (__wcsmbs_gconv_fcts.tomb != &to_mb) 197 __gconv_close_transform (__wcsmbs_gconv_fcts.tomb, 198 __wcsmbs_gconv_fcts.tomb_nsteps); 199 if (__wcsmbs_gconv_fcts.towc != &to_wc) 200 __gconv_close_transform (__wcsmbs_gconv_fcts.towc, 201 __wcsmbs_gconv_fcts.towc_nsteps); 202 203 /* Get name of charset of the locale. */ 204 charset_name = new_category->values[_NL_ITEM_INDEX(CODESET)].string; 205 206 /* Does the user want transliteration? */ 207 use_translit = new_category->use_translit; 208 209 /* Normalize the name and add the slashes necessary for a 210 complete lookup. */ 211 complete_name = norm_add_slashes (charset_name, 212 use_translit ? "TRANSLIT" : NULL); 213 214 /* It is not necessary to use transliteration in this direction 215 since the internal character set is supposed to be able to 216 represent all others. */ 217 new_towc = getfct ("INTERNAL", complete_name, &new_towc_nsteps); 218 new_tomb = (new_towc != NULL 219 ? getfct (complete_name, "INTERNAL", &new_tomb_nsteps) 220 : NULL); 221 222 /* If any of the conversion functions is not available we don't 223 use any since this would mean we cannot convert back and 224 forth.*/ 225 if (new_towc == NULL || new_tomb == NULL) 226 { 227 if (new_towc != NULL) 228 __gconv_close_transform (new_towc, 1); 229 230 goto failed; 231 } 232 233 __wcsmbs_gconv_fcts.tomb = new_tomb; 234 __wcsmbs_gconv_fcts.tomb_nsteps = new_tomb_nsteps; 235 __wcsmbs_gconv_fcts.towc = new_towc; 236 __wcsmbs_gconv_fcts.towc_nsteps = new_towc_nsteps; 237 } 238 239 /* Set last-used variable for current locale. */ 240 __wcsmbs_last_locale = new_category; 241 } 242 243 __libc_lock_unlock (lock); 244 } 245 246 247 /* Clone the current conversion function set. */ 248 void 249 internal_function 250 __wcsmbs_clone_conv (struct gconv_fcts *copy) 251 { 252 /* First make sure the function table is up-to-date. */ 253 update_conversion_ptrs (); 254 255 /* Make sure the data structures remain the same until we are finished. */ 256 __libc_lock_lock (lock); 257 258 /* Copy the data. */ 259 *copy = __wcsmbs_gconv_fcts; 260 261 /* Now increment the usage counters. */ 262 if (copy->towc->__shlib_handle != NULL) 263 ++copy->towc->__counter; 264 if (copy->tomb->__shlib_handle != NULL) 265 ++copy->tomb->__counter; 266 267 __libc_lock_unlock (lock); 268 } 269 270 271 /* Get converters for named charset. */ 272 int 273 internal_function 274 __wcsmbs_named_conv (struct gconv_fcts *copy, const char *name) 275 { 276 copy->towc = getfct ("INTERNAL", name, ©->towc_nsteps); 277 if (copy->towc != NULL) 278 { 279 copy->tomb = getfct (name, "INTERNAL", ©->tomb_nsteps); 280 if (copy->tomb == NULL) 281 __gconv_close_transform (copy->towc, copy->towc_nsteps); 282 } 283 284 return copy->towc == NULL || copy->tomb == NULL ? 1 : 0; 285 } 286 287 288 /* Free all resources if necessary. */ 289 static void __attribute__ ((unused)) 290 free_mem (void) 291 { 292 if (__wcsmbs_gconv_fcts.tomb != &to_mb) 293 { 294 struct __gconv_step *old = __wcsmbs_gconv_fcts.tomb; 295 size_t nold = __wcsmbs_gconv_fcts.tomb_nsteps; 296 __wcsmbs_gconv_fcts.tomb = &to_mb; 297 __wcsmbs_gconv_fcts.tomb_nsteps = 1; 298 __gconv_release_cache (old, nold); 299 } 300 301 if (__wcsmbs_gconv_fcts.towc != &to_wc) 302 { 303 struct __gconv_step *old = __wcsmbs_gconv_fcts.towc; 304 size_t nold = __wcsmbs_gconv_fcts.towc_nsteps; 305 __wcsmbs_gconv_fcts.towc = &to_wc; 306 __wcsmbs_gconv_fcts.towc_nsteps = 1; 307 __gconv_release_cache (old, nold); 308 } 309 } 310 311 #endif 312 313 text_set_element (__libc_subfreeres, free_mem); 314