Blame wcsmbs/wcsmbsload.c

Packit Service 82fcde
/* Copyright (C) 1998-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <ctype.h>
Packit Service 82fcde
#include <langinfo.h>
Packit Service 82fcde
#include <limits.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
Packit Service 82fcde
#include <locale/localeinfo.h>
Packit Service 82fcde
#include <wcsmbsload.h>
Packit Service 82fcde
#include <libc-lock.h>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* These are the descriptions for the default conversion functions.  */
Packit Service 82fcde
static const struct __gconv_step to_wc =
Packit Service 82fcde
{
Packit Service 82fcde
  .__shlib_handle = NULL,
Packit Service 82fcde
  .__modname = NULL,
Packit Service 82fcde
  .__counter = INT_MAX,
Packit Service 82fcde
  .__from_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
Packit Service 82fcde
  .__to_name = (char *) "INTERNAL",
Packit Service 82fcde
  .__fct = __gconv_transform_ascii_internal,
Packit Service 82fcde
  .__btowc_fct = __gconv_btwoc_ascii,
Packit Service 82fcde
  .__init_fct = NULL,
Packit Service 82fcde
  .__end_fct = NULL,
Packit Service 82fcde
  .__min_needed_from = 1,
Packit Service 82fcde
  .__max_needed_from = 1,
Packit Service 82fcde
  .__min_needed_to = 4,
Packit Service 82fcde
  .__max_needed_to = 4,
Packit Service 82fcde
  .__stateful = 0,
Packit Service 82fcde
  .__data = NULL
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
static const struct __gconv_step to_mb =
Packit Service 82fcde
{
Packit Service 82fcde
  .__shlib_handle = NULL,
Packit Service 82fcde
  .__modname = NULL,
Packit Service 82fcde
  .__counter = INT_MAX,
Packit Service 82fcde
  .__from_name = (char *) "INTERNAL",
Packit Service 82fcde
  .__to_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
Packit Service 82fcde
  .__fct = __gconv_transform_internal_ascii,
Packit Service 82fcde
  .__btowc_fct = NULL,
Packit Service 82fcde
  .__init_fct = NULL,
Packit Service 82fcde
  .__end_fct = NULL,
Packit Service 82fcde
  .__min_needed_from = 4,
Packit Service 82fcde
  .__max_needed_from = 4,
Packit Service 82fcde
  .__min_needed_to = 1,
Packit Service 82fcde
  .__max_needed_to = 1,
Packit Service 82fcde
  .__stateful = 0,
Packit Service 82fcde
  .__data = NULL
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* For the default locale we only have to handle ANSI_X3.4-1968.  */
Packit Service 82fcde
const struct gconv_fcts __wcsmbs_gconv_fcts_c =
Packit Service 82fcde
{
Packit Service 82fcde
  .towc = (struct __gconv_step *) &to_wc,
Packit Service 82fcde
  .towc_nsteps = 1,
Packit Service 82fcde
  .tomb = (struct __gconv_step *) &to_mb,
Packit Service 82fcde
  .tomb_nsteps = 1,
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
attribute_hidden
Packit Service 82fcde
struct __gconv_step *
Packit Service 82fcde
__wcsmbs_getfct (const char *to, const char *from, size_t *nstepsp)
Packit Service 82fcde
{
Packit Service 82fcde
  size_t nsteps;
Packit Service 82fcde
  struct __gconv_step *result;
Packit Service 82fcde
#if 0
Packit Service 82fcde
  size_t nstateful;
Packit Service 82fcde
  size_t cnt;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  if (__gconv_find_transform (to, from, &result, &nsteps, 0) != __GCONV_OK)
Packit Service 82fcde
    /* Loading the conversion step is not possible.  */
Packit Service 82fcde
    return NULL;
Packit Service 82fcde
Packit Service 82fcde
  /* Maybe it is someday necessary to allow more than one step.
Packit Service 82fcde
     Currently this is not the case since the conversions handled here
Packit Service 82fcde
     are from and to INTERNAL and there always is a converted for
Packit Service 82fcde
     that.  It the directly following code is enabled the libio
Packit Service 82fcde
     functions will have to allocate appropriate __gconv_step_data
Packit Service 82fcde
     elements instead of only one.  */
Packit Service 82fcde
#if 0
Packit Service 82fcde
  /* Count the number of stateful conversions.  Since we will only
Packit Service 82fcde
     have one 'mbstate_t' object available we can only deal with one
Packit Service 82fcde
     stateful conversion.  */
Packit Service 82fcde
  nstateful = 0;
Packit Service 82fcde
  for (cnt = 0; cnt < nsteps; ++cnt)
Packit Service 82fcde
    if (result[cnt].__stateful)
Packit Service 82fcde
      ++nstateful;
Packit Service 82fcde
  if (nstateful > 1)
Packit Service 82fcde
#else
Packit Service 82fcde
  if (nsteps > 1)
Packit Service 82fcde
#endif
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We cannot handle this case.  */
Packit Service 82fcde
      __gconv_close_transform (result, nsteps);
Packit Service 82fcde
      result = NULL;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    *nstepsp = nsteps;
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Extract from the given locale name the character set portion.  Since
Packit Service 82fcde
   only the XPG form of the name includes this information we don't have
Packit Service 82fcde
   to take care for the CEN form.  */
Packit Service 82fcde
#define extract_charset_name(str) \
Packit Service 82fcde
  ({									      \
Packit Service 82fcde
    const char *cp = str;						      \
Packit Service 82fcde
    char *result = NULL;						      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    cp += strcspn (cp, "@.+,");						      \
Packit Service 82fcde
    if (*cp == '.')							      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	const char *endp = ++cp;					      \
Packit Service 82fcde
	while (*endp != '\0' && *endp != '@')				      \
Packit Service 82fcde
	  ++endp;							      \
Packit Service 82fcde
	if (endp != cp)							      \
Packit Service 82fcde
	  result = strndupa (cp, endp - cp);				      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
    result;								      \
Packit Service 82fcde
  })
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Some of the functions here must not be used while setlocale is called.  */
Packit Service 82fcde
__libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
Packit Service 82fcde
Packit Service 82fcde
/* Load conversion functions for the currently selected locale.  */
Packit Service 82fcde
void
Packit Service 82fcde
__wcsmbs_load_conv (struct __locale_data *new_category)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Acquire the lock.  */
Packit Service 82fcde
  __libc_rwlock_wrlock (__libc_setlocale_lock);
Packit Service 82fcde
Packit Service 82fcde
  /* We should repeat the test since while we waited some other thread
Packit Service 82fcde
     might have run this function.  */
Packit Service 82fcde
  if (__glibc_likely (new_category->private.ctype == NULL))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We must find the real functions.  */
Packit Service 82fcde
      const char *charset_name;
Packit Service 82fcde
      const char *complete_name;
Packit Service 82fcde
      struct gconv_fcts *new_fcts;
Packit Service 82fcde
      int use_translit;
Packit Service 82fcde
Packit Service 82fcde
      /* Allocate the gconv_fcts structure.  */
Packit Service 82fcde
      new_fcts = calloc (1, sizeof *new_fcts);
Packit Service 82fcde
      if (new_fcts == NULL)
Packit Service 82fcde
	goto failed;
Packit Service 82fcde
Packit Service 82fcde
      /* Get name of charset of the locale.  */
Packit Service 82fcde
      charset_name = new_category->values[_NL_ITEM_INDEX(CODESET)].string;
Packit Service 82fcde
Packit Service 82fcde
      /* Does the user want transliteration?  */
Packit Service 82fcde
      use_translit = new_category->use_translit;
Packit Service 82fcde
Packit Service 82fcde
      /* Normalize the name and add the slashes necessary for a
Packit Service 82fcde
	 complete lookup.  */
Packit Service 82fcde
      complete_name = norm_add_slashes (charset_name,
Packit Service 82fcde
					use_translit ? "TRANSLIT" : "");
Packit Service 82fcde
Packit Service 82fcde
      /* It is not necessary to use transliteration in this direction
Packit Service 82fcde
	 since the internal character set is supposed to be able to
Packit Service 82fcde
	 represent all others.  */
Packit Service 82fcde
      new_fcts->towc = __wcsmbs_getfct ("INTERNAL", complete_name,
Packit Service 82fcde
					&new_fcts->towc_nsteps);
Packit Service 82fcde
      if (new_fcts->towc != NULL)
Packit Service 82fcde
	new_fcts->tomb = __wcsmbs_getfct (complete_name, "INTERNAL",
Packit Service 82fcde
					  &new_fcts->tomb_nsteps);
Packit Service 82fcde
Packit Service 82fcde
      /* If any of the conversion functions is not available we don't
Packit Service 82fcde
	 use any since this would mean we cannot convert back and
Packit Service 82fcde
	 forth.  NB: NEW_FCTS was allocated with calloc.  */
Packit Service 82fcde
      if (new_fcts->tomb == NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (new_fcts->towc != NULL)
Packit Service 82fcde
	    __gconv_close_transform (new_fcts->towc, new_fcts->towc_nsteps);
Packit Service 82fcde
Packit Service 82fcde
	  free (new_fcts);
Packit Service 82fcde
Packit Service 82fcde
	failed:
Packit Service 82fcde
	  new_category->private.ctype = &__wcsmbs_gconv_fcts_c;
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  new_category->private.ctype = new_fcts;
Packit Service 82fcde
	  new_category->private.cleanup = &_nl_cleanup_ctype;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  __libc_rwlock_unlock (__libc_setlocale_lock);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Clone the current conversion function set.  */
Packit Service 82fcde
void
Packit Service 82fcde
__wcsmbs_clone_conv (struct gconv_fcts *copy)
Packit Service 82fcde
{
Packit Service 82fcde
  const struct gconv_fcts *orig;
Packit Service 82fcde
Packit Service 82fcde
  orig = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
Packit Service 82fcde
Packit Service 82fcde
  /* Copy the data.  */
Packit Service 82fcde
  *copy = *orig;
Packit Service 82fcde
Packit Service 82fcde
  /* Now increment the usage counters.
Packit Service 82fcde
     Note: This assumes copy->*_nsteps == 1.  */
Packit Service 82fcde
  if (copy->towc->__shlib_handle != NULL)
Packit Service 82fcde
    ++copy->towc->__counter;
Packit Service 82fcde
  if (copy->tomb->__shlib_handle != NULL)
Packit Service 82fcde
    ++copy->tomb->__counter;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Get converters for named charset.  */
Packit Service 82fcde
int
Packit Service 82fcde
__wcsmbs_named_conv (struct gconv_fcts *copy, const char *name)
Packit Service 82fcde
{
Packit Service 82fcde
  copy->towc = __wcsmbs_getfct ("INTERNAL", name, &copy->towc_nsteps);
Packit Service 82fcde
  if (copy->towc == NULL)
Packit Service 82fcde
    return 1;
Packit Service 82fcde
Packit Service 82fcde
  copy->tomb = __wcsmbs_getfct (name, "INTERNAL", &copy->tomb_nsteps);
Packit Service 82fcde
  if (copy->tomb == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      __gconv_close_transform (copy->towc, copy->towc_nsteps);
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_nl_cleanup_ctype (struct __locale_data *locale)
Packit Service 82fcde
{
Packit Service 82fcde
  const struct gconv_fcts *const data = locale->private.ctype;
Packit Service 82fcde
  if (data != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      locale->private.ctype = NULL;
Packit Service 82fcde
      locale->private.cleanup = NULL;
Packit Service 82fcde
Packit Service 82fcde
      /* Free the old conversions.  */
Packit Service 82fcde
      __gconv_close_transform (data->tomb, data->tomb_nsteps);
Packit Service 82fcde
      __gconv_close_transform (data->towc, data->towc_nsteps);
Packit Service 82fcde
      free ((char *) data);
Packit Service 82fcde
    }
Packit Service 82fcde
}