xref: /haiku/src/system/libroot/posix/glibc/wcsmbs/wcsmbsload.c (revision 3e216965baa8d58a67bf7372e2bfa13d999f5a9d)
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, &copy->towc_nsteps);
277   if (copy->towc != NULL)
278     {
279       copy->tomb = getfct (name, "INTERNAL", &copy->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