Update copyright dates with scripts/update-copyrights.
[platform/upstream/glibc.git] / wcsmbs / wcsmbsload.c
1 /* Copyright (C) 1998-2015 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, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <ctype.h>
20 #include <langinfo.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <locale/localeinfo.h>
26 #include <wcsmbsload.h>
27 #include <bits/libc-lock.h>
28
29
30 /* These are the descriptions for the default conversion functions.  */
31 static const struct __gconv_step to_wc =
32 {
33   .__shlib_handle = NULL,
34   .__modname = NULL,
35   .__counter = INT_MAX,
36   .__from_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
37   .__to_name = (char *) "INTERNAL",
38   .__fct = __gconv_transform_ascii_internal,
39   .__btowc_fct = __gconv_btwoc_ascii,
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
48 };
49
50 static const struct __gconv_step to_mb =
51 {
52   .__shlib_handle = NULL,
53   .__modname = NULL,
54   .__counter = INT_MAX,
55   .__from_name = (char *) "INTERNAL",
56   .__to_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
57   .__fct = __gconv_transform_internal_ascii,
58   .__btowc_fct = NULL,
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
67 };
68
69
70 /* For the default locale we only have to handle ANSI_X3.4-1968.  */
71 const struct gconv_fcts __wcsmbs_gconv_fcts_c =
72 {
73   .towc = (struct __gconv_step *) &to_wc,
74   .towc_nsteps = 1,
75   .tomb = (struct __gconv_step *) &to_mb,
76   .tomb_nsteps = 1,
77 };
78
79
80 attribute_hidden
81 struct __gconv_step *
82 __wcsmbs_getfct (const char *to, const char *from, size_t *nstepsp)
83 {
84   size_t nsteps;
85   struct __gconv_step *result;
86 #if 0
87   size_t nstateful;
88   size_t cnt;
89 #endif
90
91   if (__gconv_find_transform (to, from, &result, &nsteps, 0) != __GCONV_OK)
92     /* Loading the conversion step is not possible.  */
93     return NULL;
94
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
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)
110 #else
111   if (nsteps > 1)
112 #endif
113     {
114       /* We cannot handle this case.  */
115       __gconv_close_transform (result, nsteps);
116       result = NULL;
117     }
118   else
119     *nstepsp = nsteps;
120
121   return result;
122 }
123
124
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                                                                               \
133     cp += strcspn (cp, "@.+,");                                               \
134     if (*cp == '.')                                                           \
135       {                                                                       \
136         const char *endp = ++cp;                                              \
137         while (*endp != '\0' && *endp != '@')                                 \
138           ++endp;                                                             \
139         if (endp != cp)                                                       \
140           result = strndupa (cp, endp - cp);                                  \
141       }                                                                       \
142     result;                                                                   \
143   })
144
145
146 /* Some of the functions here must not be used while setlocale is called.  */
147 __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
148
149 /* Load conversion functions for the currently selected locale.  */
150 void
151 internal_function
152 __wcsmbs_load_conv (struct __locale_data *new_category)
153 {
154   /* Acquire the lock.  */
155   __libc_rwlock_wrlock (__libc_setlocale_lock);
156
157   /* We should repeat the test since while we waited some other thread
158      might have run this function.  */
159   if (__glibc_likely (new_category->private.ctype == NULL))
160     {
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.  */
168       new_fcts = calloc (1, sizeof *new_fcts);
169       if (new_fcts == NULL)
170         goto failed;
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,
181                                         use_translit ? "TRANSLIT" : "");
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);
188       if (new_fcts->towc != NULL)
189         new_fcts->tomb = __wcsmbs_getfct (complete_name, "INTERNAL",
190                                           &new_fcts->tomb_nsteps);
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
194          forth.  NB: NEW_FCTS was allocated with calloc.  */
195       if (new_fcts->tomb == NULL)
196         {
197           if (new_fcts->towc != NULL)
198             __gconv_close_transform (new_fcts->towc, new_fcts->towc_nsteps);
199
200           free (new_fcts);
201
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         }
210     }
211
212   __libc_rwlock_unlock (__libc_setlocale_lock);
213 }
214
215
216 /* Clone the current conversion function set.  */
217 void
218 internal_function
219 __wcsmbs_clone_conv (struct gconv_fcts *copy)
220 {
221   const struct gconv_fcts *orig;
222
223   orig = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
224
225   /* Copy the data.  */
226   *copy = *orig;
227
228   /* Now increment the usage counters.
229      Note: This assumes copy->*_nsteps == 1.  */
230   if (copy->towc->__shlib_handle != NULL)
231     ++copy->towc->__counter;
232   if (copy->tomb->__shlib_handle != NULL)
233     ++copy->tomb->__counter;
234 }
235
236
237 /* Get converters for named charset.  */
238 int
239 internal_function
240 __wcsmbs_named_conv (struct gconv_fcts *copy, const char *name)
241 {
242   copy->towc = __wcsmbs_getfct ("INTERNAL", name, &copy->towc_nsteps);
243   if (copy->towc == NULL)
244     return 1;
245
246   copy->tomb = __wcsmbs_getfct (name, "INTERNAL", &copy->tomb_nsteps);
247   if (copy->tomb == NULL)
248     {
249       __gconv_close_transform (copy->towc, copy->towc_nsteps);
250       return 1;
251     }
252
253   return 0;
254 }
255
256 void internal_function
257 _nl_cleanup_ctype (struct __locale_data *locale)
258 {
259   const struct gconv_fcts *const data = locale->private.ctype;
260   if (data != NULL)
261     {
262       locale->private.ctype = NULL;
263       locale->private.cleanup = NULL;
264
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);
269     }
270 }