Back to index

glibc  2.9
wcsmbsload.c
Go to the documentation of this file.
00001 /* Copyright (C) 1998-2002,2004,2005,2008 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <ctype.h>
00021 #include <langinfo.h>
00022 #include <limits.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 
00026 #include <locale/localeinfo.h>
00027 #include <wcsmbsload.h>
00028 #include <bits/libc-lock.h>
00029 
00030 
00031 /* These are the descriptions for the default conversion functions.  */
00032 static const struct __gconv_step to_wc =
00033 {
00034   .__shlib_handle = NULL,
00035   .__modname = NULL,
00036   .__counter = INT_MAX,
00037   .__from_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
00038   .__to_name = (char *) "INTERNAL",
00039   .__fct = __gconv_transform_ascii_internal,
00040   .__btowc_fct = __gconv_btwoc_ascii,
00041   .__init_fct = NULL,
00042   .__end_fct = NULL,
00043   .__min_needed_from = 1,
00044   .__max_needed_from = 1,
00045   .__min_needed_to = 4,
00046   .__max_needed_to = 4,
00047   .__stateful = 0,
00048   .__data = NULL
00049 };
00050 
00051 static const struct __gconv_step to_mb =
00052 {
00053   .__shlib_handle = NULL,
00054   .__modname = NULL,
00055   .__counter = INT_MAX,
00056   .__from_name = (char *) "INTERNAL",
00057   .__to_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
00058   .__fct = __gconv_transform_internal_ascii,
00059   .__btowc_fct = NULL,
00060   .__init_fct = NULL,
00061   .__end_fct = NULL,
00062   .__min_needed_from = 4,
00063   .__max_needed_from = 4,
00064   .__min_needed_to = 1,
00065   .__max_needed_to = 1,
00066   .__stateful = 0,
00067   .__data = NULL
00068 };
00069 
00070 
00071 /* For the default locale we only have to handle ANSI_X3.4-1968.  */
00072 const struct gconv_fcts __wcsmbs_gconv_fcts_c =
00073 {
00074   .towc = (struct __gconv_step *) &to_wc,
00075   .towc_nsteps = 1,
00076   .tomb = (struct __gconv_step *) &to_mb,
00077   .tomb_nsteps = 1
00078 };
00079 
00080 
00081 attribute_hidden
00082 struct __gconv_step *
00083 __wcsmbs_getfct (const char *to, const char *from, size_t *nstepsp)
00084 {
00085   size_t nsteps;
00086   struct __gconv_step *result;
00087 #if 0
00088   size_t nstateful;
00089   size_t cnt;
00090 #endif
00091 
00092   if (__gconv_find_transform (to, from, &result, &nsteps, 0) != __GCONV_OK)
00093     /* Loading the conversion step is not possible.  */
00094     return NULL;
00095 
00096   /* Maybe it is someday necessary to allow more than one step.
00097      Currently this is not the case since the conversions handled here
00098      are from and to INTERNAL and there always is a converted for
00099      that.  It the directly following code is enabled the libio
00100      functions will have to allocate appropriate __gconv_step_data
00101      elements instead of only one.  */
00102 #if 0
00103   /* Count the number of stateful conversions.  Since we will only
00104      have one 'mbstate_t' object available we can only deal with one
00105      stateful conversion.  */
00106   nstateful = 0;
00107   for (cnt = 0; cnt < nsteps; ++cnt)
00108     if (result[cnt].__stateful)
00109       ++nstateful;
00110   if (nstateful > 1)
00111 #else
00112   if (nsteps > 1)
00113 #endif
00114     {
00115       /* We cannot handle this case.  */
00116       __gconv_close_transform (result, nsteps);
00117       result = NULL;
00118     }
00119   else
00120     *nstepsp = nsteps;
00121 
00122   return result;
00123 }
00124 
00125 
00126 /* Extract from the given locale name the character set portion.  Since
00127    only the XPG form of the name includes this information we don't have
00128    to take care for the CEN form.  */
00129 #define extract_charset_name(str) \
00130   ({                                                                 \
00131     const char *cp = str;                                            \
00132     char *result = NULL;                                             \
00133                                                                      \
00134     cp += strcspn (cp, "@.+,");                                             \
00135     if (*cp == '.')                                                  \
00136       {                                                                     \
00137        const char *endp = ++cp;                                      \
00138        while (*endp != '\0' && *endp != '@')                                \
00139          ++endp;                                                     \
00140        if (endp != cp)                                                      \
00141          result = strndupa (cp, endp - cp);                                 \
00142       }                                                                     \
00143     result;                                                          \
00144   })
00145 
00146 
00147 /* Some of the functions here must not be used while setlocale is called.  */
00148 __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
00149 
00150 /* Load conversion functions for the currently selected locale.  */
00151 void
00152 internal_function
00153 __wcsmbs_load_conv (struct locale_data *new_category)
00154 {
00155   /* Acquire the lock.  */
00156   __libc_rwlock_wrlock (__libc_setlocale_lock);
00157 
00158   /* We should repeat the test since while we waited some other thread
00159      might have run this function.  */
00160   if (__builtin_expect (new_category->private.ctype == NULL, 1))
00161     {
00162       /* We must find the real functions.  */
00163       const char *charset_name;
00164       const char *complete_name;
00165       struct gconv_fcts *new_fcts;
00166       int use_translit;
00167 
00168       /* Allocate the gconv_fcts structure.  */
00169       new_fcts = malloc (sizeof *new_fcts);
00170       if (new_fcts == NULL)
00171        goto failed;
00172 
00173       /* Get name of charset of the locale.  */
00174       charset_name = new_category->values[_NL_ITEM_INDEX(CODESET)].string;
00175 
00176       /* Does the user want transliteration?  */
00177       use_translit = new_category->use_translit;
00178 
00179       /* Normalize the name and add the slashes necessary for a
00180         complete lookup.  */
00181       complete_name = norm_add_slashes (charset_name,
00182                                    use_translit ? "TRANSLIT" : "");
00183 
00184       /* It is not necessary to use transliteration in this direction
00185         since the internal character set is supposed to be able to
00186         represent all others.  */
00187       new_fcts->towc = __wcsmbs_getfct ("INTERNAL", complete_name,
00188                                    &new_fcts->towc_nsteps);
00189       new_fcts->tomb = (new_fcts->towc != NULL
00190                      ? __wcsmbs_getfct (complete_name, "INTERNAL",
00191                                       &new_fcts->tomb_nsteps)
00192                      : NULL);
00193 
00194       /* If any of the conversion functions is not available we don't
00195         use any since this would mean we cannot convert back and
00196         forth.*/
00197       if (new_fcts->tomb == NULL)
00198        {
00199          if (new_fcts->towc != NULL)
00200            __gconv_close_transform (new_fcts->towc, new_fcts->towc_nsteps);
00201 
00202          free (new_fcts);
00203 
00204        failed:
00205          new_category->private.ctype = &__wcsmbs_gconv_fcts_c;
00206        }
00207       else
00208        {
00209          new_category->private.ctype = new_fcts;
00210          new_category->private.cleanup = &_nl_cleanup_ctype;
00211        }
00212     }
00213 
00214   __libc_rwlock_unlock (__libc_setlocale_lock);
00215 }
00216 
00217 
00218 /* Clone the current conversion function set.  */
00219 void
00220 internal_function
00221 __wcsmbs_clone_conv (struct gconv_fcts *copy)
00222 {
00223   const struct gconv_fcts *orig;
00224 
00225   orig = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
00226 
00227   /* Copy the data.  */
00228   *copy = *orig;
00229 
00230   /* Now increment the usage counters.
00231      Note: This assumes copy->towc_nsteps == 1 and copy->tomb_nsteps == 1.  */
00232   if (copy->towc->__shlib_handle != NULL)
00233     ++copy->towc->__counter;
00234   if (copy->tomb->__shlib_handle != NULL)
00235     ++copy->tomb->__counter;
00236 }
00237 
00238 
00239 /* Get converters for named charset.  */
00240 int
00241 internal_function
00242 __wcsmbs_named_conv (struct gconv_fcts *copy, const char *name)
00243 {
00244   copy->towc = __wcsmbs_getfct ("INTERNAL", name, &copy->towc_nsteps);
00245   if (copy->towc != NULL)
00246     {
00247       copy->tomb = __wcsmbs_getfct (name, "INTERNAL", &copy->tomb_nsteps);
00248       if (copy->tomb == NULL)
00249        __gconv_close_transform (copy->towc, copy->towc_nsteps);
00250     }
00251 
00252   return copy->towc == NULL || copy->tomb == NULL ? 1 : 0;
00253 }
00254 
00255 void internal_function
00256 _nl_cleanup_ctype (struct locale_data *locale)
00257 {
00258   const struct gconv_fcts *const data = locale->private.ctype;
00259   if (data != NULL)
00260     {
00261       locale->private.ctype = NULL;
00262       locale->private.cleanup = NULL;
00263 
00264       /* Free the old conversions.  */
00265       __gconv_close_transform (data->tomb, data->tomb_nsteps);
00266       __gconv_close_transform (data->towc, data->towc_nsteps);
00267       free ((char *) data);
00268     }
00269 }