Back to index

glibc  2.9
Classes | Defines | Enumerations | Functions | Variables
gconv_int.h File Reference
#include "gconv.h"
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <bits/libc-lock.h>
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  path_elem
struct  gconv_alias
struct  __gconv_loaded_object
struct  gconv_module
struct  trans_struct

Defines

#define GCONV_NCHAR_GOAL   8160
#define norm_add_slashes(str, suffix)

Enumerations

enum  { GCONV_AVOID_NOCONV = 1 << 0 }
enum  { __GCONV_NULCONV = -1 }

Functions

 __libc_lock_define (extern, __gconv_lock attribute_hidden) extern int __gconv_open(const char *toset
int __gconv_close (__gconv_t cd) internal_function
int __gconv (__gconv_t cd, const unsigned char **inbuf, const unsigned char *inbufend, unsigned char **outbuf, unsigned char *outbufend, size_t *irreversible) internal_function
int __gconv_find_transform (const char *toset, const char *fromset, struct __gconv_step **handle, size_t *nsteps, int flags) internal_function
int __gconv_lookup_cache (const char *toset, const char *fromset, struct __gconv_step **handle, size_t *nsteps, int flags) internal_function
int __gconv_compare_alias_cache (const char *name1, const char *name2, int *result) internal_function
void __gconv_release_step (struct __gconv_step *step) internal_function
void __gconv_read_conf (void) attribute_hidden
int __gconv_load_cache (void) internal_function
void * __gconv_get_cache (void)
struct gconv_module__gconv_get_modules_db (void)
void * __gconv_get_alias_db (void)
void __gconv_get_path (void) internal_function
int __gconv_alias_compare (const void *p1, const void *p2) attribute_hidden
int __gconv_close_transform (struct __gconv_step *steps, size_t nsteps) internal_function
void __gconv_release_cache (struct __gconv_step *steps, size_t nsteps) internal_function
struct __gconv_loaded_object__gconv_find_shlib (const char *name) internal_function
void __gconv_release_shlib (struct __gconv_loaded_object *handle) internal_function
void __gconv_get_builtin_trans (const char *name, struct __gconv_step *step) internal_function
int __gconv_translit_find (struct trans_struct *trans) internal_function
int __gconv_transliterate (struct __gconv_step *step, struct __gconv_step_data *step_data, void *trans_data, __const unsigned char *inbufstart, __const unsigned char **inbufp, __const unsigned char *inbufend, unsigned char **outbufstart, size_t *irreversible) attribute_hidden
int __gconv_compare_alias (const char *name1, const char *name2) internal_function

Variables

struct path_elem *__gconv_path_elem attribute_hidden
size_t __gconv_nmodules
const char * fromset
const char __gconv_thandle
const char __gconv_t int flags internal_function

Class Documentation

struct path_elem

Definition at line 33 of file gconv_int.h.

Class Members
size_t len
const char * name
struct gconv_alias

Definition at line 46 of file gconv_int.h.

Class Members
char * fromname
char * toname
struct __gconv_loaded_object

Definition at line 60 of file gconv_int.h.

Collaboration diagram for __gconv_loaded_object:
Class Members
int counter
__gconv_end_fct end_fct
__gconv_fct fct
void * handle
__gconv_init_fct init_fct
const char * name
struct gconv_module

Definition at line 80 of file gconv_int.h.

Collaboration diagram for gconv_module:
Class Members
int cost_hi
int cost_lo
const char * from_string
struct gconv_module * left
const char * module_name
struct gconv_module * right
struct gconv_module * same
const char * to_string
struct trans_struct

Definition at line 97 of file gconv_int.h.

Collaboration diagram for trans_struct:
Class Members
const char ** csnames
const char * name
size_t ncsnames
struct trans_struct * next
__gconv_trans_context_fct trans_context_fct
__gconv_trans_end_fct trans_end_fct
__gconv_trans_fct trans_fct
__gconv_trans_init_fct trans_init_fct

Define Documentation

#define GCONV_NCHAR_GOAL   8160

Definition at line 54 of file gconv_int.h.

#define norm_add_slashes (   str,
  suffix 
)
Value:
({                                                                   \
    const char *cp = (str);                                          \
    char *result;                                                    \
    char *tmp;                                                              \
    size_t cnt = 0;                                                  \
    const size_t suffix_len = strlen (suffix);                              \
                                                                     \
    while (*cp != '\0')                                                     \
      if (*cp++ == '/')                                                     \
       ++cnt;                                                        \
                                                                     \
    tmp = result = __alloca (cp - (str) + 3 + suffix_len);                  \
    cp = (str);                                                             \
    while (*cp != '\0')                                                     \
      *tmp++ = __toupper_l (*cp++, _nl_C_locobj_ptr);                       \
    if (cnt < 2)                                                     \
      {                                                                     \
       *tmp++ = '/';                                                 \
       if (cnt < 1)                                                  \
         {                                                           \
           *tmp++ = '/';                                             \
           if (suffix_len != 0)                                      \
             tmp = __mempcpy (tmp, suffix, suffix_len);              \
         }                                                           \
      }                                                                     \
    *tmp = '\0';                                                     \
    result;                                                          \
  })

Enumeration Type Documentation

anonymous enum
Enumerator:
GCONV_AVOID_NOCONV 

Definition at line 112 of file gconv_int.h.

{
  GCONV_AVOID_NOCONV = 1 << 0
};
anonymous enum
Enumerator:
__GCONV_NULCONV 

Definition at line 119 of file gconv_int.h.

{
  __GCONV_NULCONV = -1
};

Function Documentation

int __gconv ( __gconv_t  cd,
const unsigned char **  inbuf,
const unsigned char *  inbufend,
unsigned char **  outbuf,
unsigned char *  outbufend,
size_t irreversible 
)

Definition at line 33 of file gconv.c.

{
  size_t last_step;
  int result;

  if (cd == (__gconv_t) -1L)
    return __GCONV_ILLEGAL_DESCRIPTOR;

  last_step = cd->__nsteps - 1;

  assert (irreversible != NULL);
  *irreversible = 0;

  cd->__data[last_step].__outbuf = outbuf != NULL ? *outbuf : NULL;
  cd->__data[last_step].__outbufend = outbufend;

  __gconv_fct fct = cd->__steps->__fct;
#ifdef PTR_DEMANGLE
  if (cd->__steps->__shlib_handle != NULL)
    PTR_DEMANGLE (fct);
#endif

  if (inbuf == NULL || *inbuf == NULL)
    {
      /* We just flush.  */
      result = DL_CALL_FCT (fct,
                         (cd->__steps, cd->__data, NULL, NULL, NULL,
                          irreversible,
                          cd->__data[last_step].__outbuf == NULL ? 2 : 1,
                          0));

      /* If the flush was successful clear the rest of the state.  */
      if (result == __GCONV_OK)
       for (size_t cnt = 0; cnt <= last_step; ++cnt)
         cd->__data[cnt].__invocation_counter = 0;
    }
  else
    {
      const unsigned char *last_start;

      assert (outbuf != NULL && *outbuf != NULL);

      do
       {
         last_start = *inbuf;
         result = DL_CALL_FCT (fct,
                            (cd->__steps, cd->__data, inbuf, inbufend,
                             NULL, irreversible, 0, 0));
       }
      while (result == __GCONV_EMPTY_INPUT && last_start != *inbuf
            && *inbuf + cd->__steps->__min_needed_from <= inbufend);
    }

  if (outbuf != NULL && *outbuf != NULL)
    *outbuf = cd->__data[last_step].__outbuf;

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __gconv_alias_compare ( const void *  p1,
const void *  p2 
)

Definition at line 63 of file gconv_db.c.

{
  const struct gconv_alias *s1 = (const struct gconv_alias *) p1;
  const struct gconv_alias *s2 = (const struct gconv_alias *) p2;
  return strcmp (s1->fromname, s2->fromname);
}

Here is the caller graph for this function:

Definition at line 28 of file gconv_close.c.

{
  struct __gconv_step *srunp;
  struct __gconv_step_data *drunp;
  size_t nsteps;

  /* Free all resources by calling destructor functions and release
     the implementations.  */
  srunp = cd->__steps;
  nsteps = cd->__nsteps;
  drunp = cd->__data;
  do
    {
      struct __gconv_trans_data *transp;

      transp = drunp->__trans;
      while (transp != NULL)
       {
         struct __gconv_trans_data *curp = transp;
         transp = transp->__next;

         if (__builtin_expect (curp->__trans_end_fct != NULL, 0))
           curp->__trans_end_fct (curp->__data);

         free (curp);
       }

      if (!(drunp->__flags & __GCONV_IS_LAST) && drunp->__outbuf != NULL)
       free (drunp->__outbuf);
    }
  while (!((drunp++)->__flags & __GCONV_IS_LAST));

  /* Free the data allocated for the descriptor.  */
  free (cd);

  /* Close the participating modules.  */
  return __gconv_close_transform (srunp, nsteps);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __gconv_close_transform ( struct __gconv_step steps,
size_t  nsteps 
)

Definition at line 781 of file gconv_db.c.

{
  int result = __GCONV_OK;
  size_t cnt;

  /* Acquire the lock.  */
  __libc_lock_lock (__gconv_lock);

#ifndef STATIC_GCONV
  cnt = nsteps;
  while (cnt-- > 0)
    __gconv_release_step (&steps[cnt]);
#endif

  /* If we use the cache we free a bit more since we don't keep any
     transformation records around, they are cheap enough to
     recreate.  */
  __gconv_release_cache (steps, nsteps);

  /* Release the lock.  */
  __libc_lock_unlock (__gconv_lock);

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __gconv_compare_alias ( const char *  name1,
const char *  name2 
)

Definition at line 698 of file gconv_db.c.

{
  int result;

  /* Ensure that the configuration data is read.  */
  __libc_once (once, __gconv_read_conf);

  if (__gconv_compare_alias_cache (name1, name2, &result) != 0)
    result = strcmp (do_lookup_alias (name1) ?: name1,
                   do_lookup_alias (name2) ?: name2);

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __gconv_compare_alias_cache ( const char *  name1,
const char *  name2,
int result 
)

Definition at line 233 of file gconv_cache.c.

{
  size_t name1_idx;
  size_t name2_idx;

  if (gconv_cache == NULL)
    return -1;

  if (find_module_idx (name1, &name1_idx) != 0
      || find_module_idx (name2, &name2_idx) != 0)
    *result = strcmp (name1, name2);
  else
    *result = (int) (name1_idx - name2_idx);

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct __gconv_loaded_object* __gconv_find_shlib ( const char *  name) [read]

Definition at line 70 of file gconv_dl.c.

{
  struct __gconv_loaded_object *found;
  void *keyp;

  /* Search the tree of shared objects previously requested.  Data in
     the tree are `loaded_object' structures, whose first member is a
     `const char *', the lookup key.  The search returns a pointer to
     the tree node structure; the first member of the is a pointer to
     our structure (i.e. what will be a `loaded_object'); since the
     first member of that is the lookup key string, &FCT_NAME is close
     enough to a pointer to our structure to use as a lookup key that
     will be passed to `known_compare' (above).  */

  keyp = __tfind (&name, &loaded, known_compare);
  if (keyp == NULL)
    {
      /* This name was not known before.  */
      size_t namelen = strlen (name) + 1;

      found = malloc (sizeof (struct __gconv_loaded_object) + namelen);
      if (found != NULL)
       {
         /* Point the tree node at this new structure.  */
         found->name = (char *) memcpy (found + 1, name, namelen);
         found->counter = -TRIES_BEFORE_UNLOAD - 1;
         found->handle = NULL;

         if (__builtin_expect (__tsearch (found, &loaded, known_compare)
                            == NULL, 0))
           {
             /* Something went wrong while inserting the entry.  */
             free (found);
             found = NULL;
           }
       }
    }
  else
    found = *(struct __gconv_loaded_object **) keyp;

  /* Try to load the shared object if the usage count is 0.  This
     implies that if the shared object is not loadable, the handle is
     NULL and the usage count > 0.  */
  if (found != NULL)
    {
      if (found->counter < -TRIES_BEFORE_UNLOAD)
       {
         assert (found->handle == NULL);
         found->handle = __libc_dlopen (found->name);
         if (found->handle != NULL)
           {
             found->fct = __libc_dlsym (found->handle, "gconv");
             if (found->fct == NULL)
              {
                /* Argh, no conversion function.  There is something
                     wrong here.  */
                __gconv_release_shlib (found);
                found = NULL;
              }
             else
              {
                found->init_fct = __libc_dlsym (found->handle, "gconv_init");
                found->end_fct = __libc_dlsym (found->handle, "gconv_end");

#ifdef PTR_MANGLE
                PTR_MANGLE (found->fct);
                if (found->init_fct != NULL)
                  PTR_MANGLE (found->init_fct);
                if (found->end_fct !=  NULL)
                  PTR_MANGLE (found->end_fct);
#endif

                /* We have succeeded in loading the shared object.  */
                found->counter = 1;
              }
           }
         else
           /* Error while loading the shared object.  */
           found = NULL;
       }
      else if (found->handle != NULL)
       found->counter = MAX (found->counter + 1, 1);
    }

  return found;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __gconv_find_transform ( const char *  toset,
const char *  fromset,
struct __gconv_step **  handle,
size_t nsteps,
int  flags 
)

Definition at line 715 of file gconv_db.c.

{
  const char *fromset_expand;
  const char *toset_expand;
  int result;

  /* Ensure that the configuration data is read.  */
  __libc_once (once, __gconv_read_conf);

  /* Acquire the lock.  */
  __libc_lock_lock (__gconv_lock);

  result = __gconv_lookup_cache (toset, fromset, handle, nsteps, flags);
  if (result != __GCONV_NODB)
    {
      /* We have a cache and could resolve the request, successful or not.  */
      __libc_lock_unlock (__gconv_lock);
      return result;
    }

  /* If we don't have a module database return with an error.  */
  if (__gconv_modules_db == NULL)
    {
      __libc_lock_unlock (__gconv_lock);
      return __GCONV_NOCONV;
    }

  /* See whether the names are aliases.  */
  fromset_expand = do_lookup_alias (fromset);
  toset_expand = do_lookup_alias (toset);

  if (__builtin_expect (flags & GCONV_AVOID_NOCONV, 0)
      /* We are not supposed to create a pseudo transformation (means
        copying) when the input and output character set are the same.  */
      && (strcmp (toset, fromset) == 0
         || (toset_expand != NULL && strcmp (toset_expand, fromset) == 0)
         || (fromset_expand != NULL
             && (strcmp (toset, fromset_expand) == 0
                || (toset_expand != NULL
                    && strcmp (toset_expand, fromset_expand) == 0)))))
    {
      /* Both character sets are the same.  */
      __libc_lock_unlock (__gconv_lock);
      return __GCONV_NULCONV;
    }

  result = find_derivation (toset, toset_expand, fromset, fromset_expand,
                         handle, nsteps);

  /* Release the lock.  */
  __libc_lock_unlock (__gconv_lock);

  /* The following code is necessary since `find_derivation' will return
     GCONV_OK even when no derivation was found but the same request
     was processed before.  I.e., negative results will also be cached.  */
  return (result == __GCONV_OK
         ? (*handle == NULL ? __GCONV_NOCONV : __GCONV_OK)
         : result);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* __gconv_get_alias_db ( void  )

Definition at line 55 of file gconv_db.c.

{
  return __gconv_alias_db;
}
void __gconv_get_builtin_trans ( const char *  name,
struct __gconv_step step 
)

Definition at line 64 of file gconv_builtin.c.

{
  size_t cnt;

  for (cnt = 0; cnt < sizeof (map) / sizeof (map[0]); ++cnt)
    if (strcmp (name, map[cnt].name) == 0)
      break;

  assert (cnt < sizeof (map) / sizeof (map[0]));

  step->__fct = map[cnt].fct;
  step->__btowc_fct = map[cnt].btowc_fct;
  step->__init_fct = NULL;
  step->__end_fct = NULL;
  step->__shlib_handle = NULL;
  step->__modname = NULL;

  step->__min_needed_from = map[cnt].min_needed_from;
  step->__max_needed_from = map[cnt].max_needed_from;
  step->__min_needed_to = map[cnt].min_needed_to;
  step->__max_needed_to = map[cnt].max_needed_to;

  /* None of the builtin converters handles stateful encoding.  */
  step->__stateful = 0;
}

Here is the caller graph for this function:

void* __gconv_get_cache ( void  )

Definition at line 42 of file gconv_cache.c.

{
  return gconv_cache;
}

Here is the caller graph for this function:

struct gconv_module* __gconv_get_modules_db ( void  ) [read]
void __gconv_get_path ( void  )

Definition at line 432 of file gconv_conf.c.

{
  struct path_elem *result;
  __libc_lock_define_initialized (static, lock);

  __libc_lock_lock (lock);

  /* Make sure there wasn't a second thread doing it already.  */
  result = (struct path_elem *) __gconv_path_elem;
  if (result == NULL)
    {
      /* Determine the complete path first.  */
      char *gconv_path;
      size_t gconv_path_len;
      char *elem;
      char *oldp;
      char *cp;
      int nelems;
      char *cwd;
      size_t cwdlen;

      if (__gconv_path_envvar == NULL)
       {
         /* No user-defined path.  Make a modifiable copy of the
            default path.  */
         gconv_path = strdupa (default_gconv_path);
         gconv_path_len = sizeof (default_gconv_path);
         cwd = NULL;
         cwdlen = 0;
       }
      else
       {
         /* Append the default path to the user-defined path.  */
         size_t user_len = strlen (__gconv_path_envvar);

         gconv_path_len = user_len + 1 + sizeof (default_gconv_path);
         gconv_path = alloca (gconv_path_len);
         __mempcpy (__mempcpy (__mempcpy (gconv_path, __gconv_path_envvar,
                                      user_len),
                            ":", 1),
                   default_gconv_path, sizeof (default_gconv_path));
         cwd = __getcwd (NULL, 0);
         cwdlen = strlen (cwd);
       }
      assert (default_gconv_path[0] == '/');

      /* In a first pass we calculate the number of elements.  */
      oldp = NULL;
      cp = strchr (gconv_path, ':');
      nelems = 1;
      while (cp != NULL)
       {
         if (cp != oldp + 1)
           ++nelems;
         oldp = cp;
         cp =  strchr (cp + 1, ':');
       }

      /* Allocate the memory for the result.  */
      result = (struct path_elem *) malloc ((nelems + 1)
                                       * sizeof (struct path_elem)
                                       + gconv_path_len + nelems
                                       + (nelems - 1) * (cwdlen + 1));
      if (result != NULL)
       {
         char *strspace = (char *) &result[nelems + 1];
         int n = 0;

         /* Separate the individual parts.  */
         __gconv_max_path_elem_len = 0;
         elem = __strtok_r (gconv_path, ":", &gconv_path);
         assert (elem != NULL);
         do
           {
             result[n].name = strspace;
             if (elem[0] != '/')
              {
                assert (cwd != NULL);
                strspace = __mempcpy (strspace, cwd, cwdlen);
                *strspace++ = '/';
              }
             strspace = __stpcpy (strspace, elem);
             if (strspace[-1] != '/')
              *strspace++ = '/';

             result[n].len = strspace - result[n].name;
             if (result[n].len > __gconv_max_path_elem_len)
              __gconv_max_path_elem_len = result[n].len;

             *strspace++ = '\0';
             ++n;
           }
         while ((elem = __strtok_r (NULL, ":", &gconv_path)) != NULL);

         result[n].name = NULL;
         result[n].len = 0;
       }

      __gconv_path_elem = result ?: (struct path_elem *) &empty_path_elem;

      free (cwd);
    }

  __libc_lock_unlock (lock);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __gconv_load_cache ( void  )

Definition at line 50 of file gconv_cache.c.

{
  int fd;
  struct stat64 st;
  struct gconvcache_header *header;

  /* We cannot use the cache if the GCONV_PATH environment variable is
     set.  */
  __gconv_path_envvar = getenv ("GCONV_PATH");
  if (__gconv_path_envvar != NULL)
    return -1;

  /* See whether the cache file exists.  */
  fd = open_not_cancel (GCONV_MODULES_CACHE, O_RDONLY, 0);
  if (__builtin_expect (fd, 0) == -1)
    /* Not available.  */
    return -1;

  /* Get information about the file.  */
  if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0
      /* We do not have to start looking at the file if it cannot contain
        at least the cache header.  */
      || (size_t) st.st_size < sizeof (struct gconvcache_header))
    {
    close_and_exit:
      close_not_cancel_no_status (fd);
      return -1;
    }

  /* Make the file content available.  */
  cache_size = st.st_size;
#ifdef _POSIX_MAPPED_FILES
  gconv_cache = __mmap (NULL, cache_size, PROT_READ, MAP_SHARED, fd, 0);
  if (__builtin_expect (gconv_cache == MAP_FAILED, 0))
#endif
    {
      size_t already_read;

      gconv_cache = malloc (cache_size);
      if (gconv_cache == NULL)
       goto close_and_exit;

      already_read = 0;
      do
       {
         ssize_t n = __read (fd, (char *) gconv_cache + already_read,
                           cache_size - already_read);
         if (__builtin_expect (n, 0) == -1)
           {
             free (gconv_cache);
             gconv_cache = NULL;
             goto close_and_exit;
           }

         already_read += n;
       }
      while (already_read < cache_size);

      cache_malloced = 1;
    }

  /* We don't need the file descriptor anymore.  */
  close_not_cancel_no_status (fd);

  /* Check the consistency.  */
  header = (struct gconvcache_header *) gconv_cache;
  if (__builtin_expect (header->magic, GCONVCACHE_MAGIC) != GCONVCACHE_MAGIC
      || __builtin_expect (header->string_offset >= cache_size, 0)
      || __builtin_expect (header->hash_offset >= cache_size, 0)
      || __builtin_expect (header->hash_size == 0, 0)
      || __builtin_expect ((header->hash_offset
                         + header->hash_size * sizeof (struct hash_entry))
                        > cache_size, 0)
      || __builtin_expect (header->module_offset >= cache_size, 0)
      || __builtin_expect (header->otherconv_offset > cache_size, 0))
    {
      if (cache_malloced)
       {
         free (gconv_cache);
         cache_malloced = 0;
       }
#ifdef _POSIX_MAPPED_FILES
      else
       __munmap (gconv_cache, cache_size);
#endif
      gconv_cache = NULL;

      return -1;
    }

  /* That worked.  */
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __gconv_lookup_cache ( const char *  toset,
const char *  fromset,
struct __gconv_step **  handle,
size_t nsteps,
int  flags 
)

Definition at line 253 of file gconv_cache.c.

{
  const struct gconvcache_header *header;
  const char *strtab;
  size_t fromidx;
  size_t toidx;
  const struct module_entry *modtab;
  const struct module_entry *from_module;
  const struct module_entry *to_module;
  struct __gconv_step *result;

  if (gconv_cache == NULL)
    /* We have no cache available.  */
    return __GCONV_NODB;

  header = (const struct gconvcache_header *) gconv_cache;
  strtab = (char *) gconv_cache + header->string_offset;
  modtab = (const struct module_entry *) ((char *) gconv_cache
                                     + header->module_offset);

  if (find_module_idx (fromset, &fromidx) != 0
      || (header->module_offset + (fromidx + 1) * sizeof (struct module_entry)
         > cache_size))
    return __GCONV_NOCONV;
  from_module = &modtab[fromidx];

  if (find_module_idx (toset, &toidx) != 0
      || (header->module_offset + (toidx + 1) * sizeof (struct module_entry)
         > cache_size))
    return __GCONV_NOCONV;
  to_module = &modtab[toidx];

  /* Avoid copy-only transformations if the user requests.   */
  if (__builtin_expect (flags & GCONV_AVOID_NOCONV, 0) && fromidx == toidx)
    return __GCONV_NULCONV;

  /* If there are special conversions available examine them first.  */
  if (fromidx != 0 && toidx != 0
      && __builtin_expect (from_module->extra_offset, 0) != 0)
    {
      /* Search through the list to see whether there is a module
        matching the destination character set.  */
      const struct extra_entry *extra;

      /* Note the -1.  This is due to the offset added in iconvconfig.
        See there for more explanations.  */
      extra = (const struct extra_entry *) ((char *) gconv_cache
                                       + header->otherconv_offset
                                       + from_module->extra_offset - 1);
      while (extra->module_cnt != 0
            && extra->module[extra->module_cnt - 1].outname_offset != toidx)
       extra = (const struct extra_entry *) ((char *) extra
                                         + sizeof (struct extra_entry)
                                         + (extra->module_cnt
                                           * sizeof (struct extra_entry_module)));

      if (extra->module_cnt != 0)
       {
         /* Use the extra module.  First determine how many steps.  */
         char *fromname;
         int idx;

         *nsteps = extra->module_cnt;
         *handle = result =
           (struct __gconv_step *) malloc (extra->module_cnt
                                       * sizeof (struct __gconv_step));
         if (result == NULL)
           return __GCONV_NOMEM;

         fromname = (char *) strtab + from_module->canonname_offset;
         idx = 0;
         do
           {
             result[idx].__from_name = fromname;
             fromname = result[idx].__to_name =
              (char *) strtab + modtab[extra->module[idx].outname_offset].canonname_offset;

             result[idx].__counter = 1;
             result[idx].__data = NULL;

#ifndef STATIC_GCONV
             if (strtab[extra->module[idx].dir_offset] != '\0')
              {
                /* Load the module, return handle for it.  */
                int res;

                res = find_module (strtab + extra->module[idx].dir_offset,
                                 strtab + extra->module[idx].name_offset,
                                 &result[idx]);
                if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
                  {
                    /* Something went wrong.  */
                    free (result);
                    goto try_internal;
                  }
              }
             else
#endif
              /* It's a builtin transformation.  */
              __gconv_get_builtin_trans (strtab
                                      + extra->module[idx].name_offset,
                                      &result[idx]);

           }
         while (++idx < extra->module_cnt);

         return __GCONV_OK;
       }
    }

 try_internal:
  /* See whether we can convert via the INTERNAL charset.  */
  if ((fromidx != 0 && __builtin_expect (from_module->fromname_offset, 1) == 0)
      || (toidx != 0 && __builtin_expect (to_module->toname_offset, 1) == 0)
      || (fromidx == 0 && toidx == 0))
    /* Not possible.  Nothing we can do.  */
    return __GCONV_NOCONV;

  /* We will use up to two modules.  Always allocate room for two.  */
  result = (struct __gconv_step *) malloc (2 * sizeof (struct __gconv_step));
  if (result == NULL)
    return __GCONV_NOMEM;

  *handle = result;
  *nsteps = 0;

  /* Generate data structure for conversion to INTERNAL.  */
  if (fromidx != 0)
    {
      result[0].__from_name = (char *) strtab + from_module->canonname_offset;
      result[0].__to_name = (char *) "INTERNAL";

      result[0].__counter = 1;
      result[0].__data = NULL;

#ifndef STATIC_GCONV
      if (strtab[from_module->todir_offset] != '\0')
       {
         /* Load the module, return handle for it.  */
         int res = find_module (strtab + from_module->todir_offset,
                             strtab + from_module->toname_offset,
                             &result[0]);
         if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
           {
             /* Something went wrong.  */
             free (result);
             return res;
           }
       }
      else
#endif
       /* It's a builtin transformation.  */
       __gconv_get_builtin_trans (strtab + from_module->toname_offset,
                               &result[0]);

      ++*nsteps;
    }

  /* Generate data structure for conversion from INTERNAL.  */
  if (toidx != 0)
    {
      int idx = *nsteps;

      result[idx].__from_name = (char *) "INTERNAL";
      result[idx].__to_name = (char *) strtab + to_module->canonname_offset;

      result[idx].__counter = 1;
      result[idx].__data = NULL;

#ifndef STATIC_GCONV
      if (strtab[to_module->fromdir_offset] != '\0')
       {
         /* Load the module, return handle for it.  */
         int res = find_module (strtab + to_module->fromdir_offset,
                             strtab + to_module->fromname_offset,
                             &result[idx]);
         if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
           {
             /* Something went wrong.  */
             if (idx != 0)
              __gconv_release_step (&result[0]);
             free (result);
             return res;
           }
       }
      else
#endif
       /* It's a builtin transformation.  */
       __gconv_get_builtin_trans (strtab + to_module->fromname_offset,
                               &result[idx]);

      ++*nsteps;
    }

  return __GCONV_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void __gconv_read_conf ( void  )

Definition at line 543 of file gconv_conf.c.

{
  void *modules = NULL;
  size_t nmodules = 0;
  int save_errno = errno;
  size_t cnt;

  /* First see whether we should use the cache.  */
  if (__gconv_load_cache () == 0)
    {
      /* Yes, we are done.  */
      __set_errno (save_errno);
      return;
    }

#ifndef STATIC_GCONV
  /* Find out where we have to look.  */
  if (__gconv_path_elem == NULL)
    __gconv_get_path ();

  for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
    {
      const char *elem = __gconv_path_elem[cnt].name;
      size_t elem_len = __gconv_path_elem[cnt].len;
      char *filename;

      /* No slash needs to be inserted between elem and gconv_conf_filename;
        elem already ends in a slash.  */
      filename = alloca (elem_len + sizeof (gconv_conf_filename));
      __mempcpy (__mempcpy (filename, elem, elem_len),
               gconv_conf_filename, sizeof (gconv_conf_filename));

      /* Read the next configuration file.  */
      read_conf_file (filename, elem, elem_len, &modules, &nmodules);
    }
#endif

  /* Add the internal modules.  */
  for (cnt = 0; cnt < sizeof (builtin_modules) / sizeof (builtin_modules[0]);
       ++cnt)
    {
      struct gconv_alias fake_alias;

      fake_alias.fromname = (char *) builtin_modules[cnt].from_string;

      if (__tfind (&fake_alias, &__gconv_alias_db, __gconv_alias_compare)
         != NULL)
       /* It'll conflict so don't add it.  */
       continue;

      insert_module (&builtin_modules[cnt], 0);
    }

  /* Add aliases for builtin conversions.  */
  const char *cp = builtin_aliases;
  do
    {
      const char *from = cp;
      const char *to = __rawmemchr (from, '\0') + 1;
      cp = __rawmemchr (to, '\0') + 1;

      add_alias2 (from, to, cp, modules);
    }
  while (*cp != '\0');

  /* Restore the error number.  */
  __set_errno (save_errno);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void __gconv_release_cache ( struct __gconv_step steps,
size_t  nsteps 
)

Definition at line 455 of file gconv_cache.c.

{
  if (gconv_cache != NULL)
    /* The only thing we have to deallocate is the record with the
       steps.  */
    free (steps);
}

Here is the caller graph for this function:

void __gconv_release_shlib ( struct __gconv_loaded_object handle)

Definition at line 191 of file gconv_dl.c.

{
  /* Urgh, this is ugly but we have no other possibility.  */
  release_handle = handle;

  /* Process all entries.  Please note that we also visit entries
     with release counts <= 0.  This way we can finally unload them
     if necessary.  */
  __twalk (loaded, (__action_fn_t) do_release_shlib);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void __gconv_release_step ( struct __gconv_step step)

Definition at line 208 of file gconv_db.c.

{
  /* Skip builtin modules; they are not reference counted.  */
  if (step->__shlib_handle != NULL && --step->__counter == 0)
    {
      /* Call the destructor.  */
      if (step->__end_fct != NULL)
       {
         assert (step->__shlib_handle != NULL);

         __gconv_end_fct end_fct = step->__end_fct;
#ifdef PTR_DEMANGLE
         PTR_DEMANGLE (end_fct);
#endif
         DL_CALL_FCT (end_fct, (step));
       }

#ifndef STATIC_GCONV
      /* Release the loaded module.  */
      __gconv_release_shlib (step->__shlib_handle);
      step->__shlib_handle = NULL;
#endif
    }
  else if (step->__shlib_handle == NULL)
    /* Builtin modules should not have end functions.  */
    assert (step->__end_fct == NULL);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __gconv_translit_find ( struct trans_struct trans)

Definition at line 320 of file gconv_trans.c.

{
  struct known_trans **found;
  const struct path_elem *runp;
  int res = 1;

  /* We have to have a name.  */
  assert (trans->name != NULL);

  /* Acquire the lock.  */
  __libc_lock_lock (lock);

  /* See whether we know this module already.  */
  found = __tfind (trans, &search_tree, trans_compare);
  if (found != NULL)
    {
      /* Is this module available?  */
      if ((*found)->handle != NULL)
       {
         /* Maybe we have to reopen the file.  */
         if ((*found)->handle != (void *) -1)
           /* The object is not unloaded.  */
           res = 0;
         else if (open_translit (*found) == 0)
           {
             /* Copy the data.  */
             *trans = (*found)->info;
             (*found)->open_count++;
             res = 0;
           }
       }
    }
  else
    {
      size_t name_len = strlen (trans->name) + 1;
      int need_so = 0;
      struct known_trans *newp;

      /* We have to continue looking for the module.  */
      if (__gconv_path_elem == NULL)
       __gconv_get_path ();

      /* See whether we have to append .so.  */
      if (name_len <= 4 || memcmp (&trans->name[name_len - 4], ".so", 3) != 0)
       need_so = 1;

      /* Create a new entry.  */
      newp = (struct known_trans *) malloc (sizeof (struct known_trans)
                                       + (__gconv_max_path_elem_len
                                          + name_len + 3)
                                       + name_len);
      if (newp != NULL)
       {
         char *cp;

         /* Clear the struct.  */
         memset (newp, '\0', sizeof (struct known_trans));

         /* Store a copy of the module name.  */
         newp->info.name = cp = (char *) (newp + 1);
         cp = __mempcpy (cp, trans->name, name_len);

         newp->fname = cp;

         /* Search in all the directories.  */
         for (runp = __gconv_path_elem; runp->name != NULL; ++runp)
           {
             cp = __mempcpy (__stpcpy ((char *) newp->fname, runp->name),
                           trans->name, name_len);
             if (need_so)
              memcpy (cp, ".so", sizeof (".so"));

             if (open_translit (newp) == 0)
              {
                /* We found a module.  */
                res = 0;
                break;
              }
           }

         if (res)
           newp->fname = NULL;

         /* In any case we'll add the entry to our search tree.  */
         if (__tsearch (newp, &search_tree, trans_compare) == NULL)
           {
             /* Yickes, this should not happen.  Unload the object.  */
             res = 1;
             /* XXX unload here.  */
           }
       }
    }

  __libc_lock_unlock (lock);

  return res;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __gconv_transliterate ( struct __gconv_step step,
struct __gconv_step_data step_data,
void *  trans_data,
__const unsigned char *  inbufstart,
__const unsigned char **  inbufp,
__const unsigned char *  inbufend,
unsigned char **  outbufstart,
size_t irreversible 
)

Here is the caller graph for this function:

__libc_lock_define ( extern  ,
__gconv_lock  attribute_hidden 
) const

Variable Documentation

Definition at line 42 of file gconv_int.h.

const char* fromset

Definition at line 174 of file gconv_int.h.

Definition at line 174 of file gconv_int.h.

Definition at line 174 of file gconv_int.h.