Back to index

glibc  2.9
Functions
gconv_open.c File Reference
#include <errno.h>
#include <locale.h>
#include "../locale/localeinfo.h"
#include <stdlib.h>
#include <string.h>
#include <gconv_int.h>

Go to the source code of this file.

Functions

int internal_function __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, int flags)

Function Documentation

int internal_function __gconv_open ( const char *  toset,
const char *  fromset,
__gconv_t handle,
int  flags 
)

Definition at line 33 of file gconv_open.c.

{
  struct __gconv_step *steps;
  size_t nsteps;
  __gconv_t result = NULL;
  size_t cnt = 0;
  int res;
  int conv_flags = 0;
  const char *errhand;
  const char *ignore;
  struct trans_struct *trans = NULL;

  /* Find out whether any error handling method is specified.  */
  errhand = strchr (toset, '/');
  if (errhand != NULL)
    errhand = strchr (errhand + 1, '/');
  if (__builtin_expect (errhand != NULL, 1))
    {
      if (*++errhand == '\0')
       errhand = NULL;
      else
       {
         /* Make copy without the error handling description.  */
         char *newtoset = (char *) alloca (errhand - toset + 1);
         char *tok;
         char *ptr = NULL /* Work around a bogus warning */;

         newtoset[errhand - toset] = '\0';
         toset = memcpy (newtoset, toset, errhand - toset);

         /* Find the appropriate transliteration handlers.  */
         tok = strdupa (errhand);

         tok = __strtok_r (tok, ",", &ptr);
         while (tok != NULL)
           {
             if (__strcasecmp_l (tok, "TRANSLIT", _nl_C_locobj_ptr) == 0)
              {
                /* It's the builtin transliteration handling.  We only
                   support it for working on the internal encoding.  */
                static const char *const internal_trans_names[1]
                  = { "INTERNAL" };
                struct trans_struct *lastp = NULL;
                struct trans_struct *runp;

                for (runp = trans; runp != NULL; runp = runp->next)
                  if (runp->trans_fct == __gconv_transliterate)
                    break;
                  else
                    lastp = runp;

                if (runp == NULL)
                  {
                    struct trans_struct *newp;

                    newp = (struct trans_struct *) alloca (sizeof (*newp));
                    memset (newp, '\0', sizeof (*newp));

                    /* We leave the `name' field zero to signal that
                      this is an internal transliteration step.  */
                    newp->csnames = (const char **) internal_trans_names;
                    newp->ncsnames = 1;
                    newp->trans_fct = __gconv_transliterate;

                    if (lastp == NULL)
                     trans = newp;
                    else
                     lastp->next = newp;
                  }
              }
             else if (__strcasecmp_l (tok, "IGNORE", _nl_C_locobj_ptr) == 0)
              /* Set the flag to ignore all errors.  */
              conv_flags |= __GCONV_IGNORE_ERRORS;
             else
              {
                /* `tok' is possibly a module name.  We'll see later
                   whether we can find it.  But first see that we do
                   not already a module of this name.  */
                struct trans_struct *lastp = NULL;
                struct trans_struct *runp;

                for (runp = trans; runp != NULL; runp = runp->next)
                  if (runp->name != NULL
                     && __strcasecmp_l (tok, runp->name,
                                      _nl_C_locobj_ptr) == 0)
                    break;
                  else
                    lastp = runp;

                if (runp == NULL)
                  {
                    struct trans_struct *newp;

                    newp = (struct trans_struct *) alloca (sizeof (*newp));
                    memset (newp, '\0', sizeof (*newp));
                    newp->name = tok;

                    if (lastp == NULL)
                     trans = newp;
                    else
                     lastp->next = newp;
                  }
              }

             tok = __strtok_r (NULL, ",", &ptr);
           }
       }
    }

  /* For the source character set we ignore the error handler specification.
     XXX Is this really always the best?  */
  ignore = strchr (fromset, '/');
  if (ignore != NULL && (ignore = strchr (ignore + 1, '/')) != NULL
      && *++ignore != '\0')
    {
      char *newfromset = (char *) alloca (ignore - fromset + 1);

      newfromset[ignore - fromset] = '\0';
      fromset = memcpy (newfromset, fromset, ignore - fromset);
    }

  /* If the string is empty define this to mean the charset of the
     currently selected locale.  */
  if (strcmp (toset, "//") == 0)
    {
      const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
      size_t len = strlen (codeset);
      char *dest;
      toset = dest = (char *) alloca (len + 3);
      memcpy (__mempcpy (dest, codeset, len), "//", 3);
    }
  if (strcmp (fromset, "//") == 0)
    {
      const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
      size_t len = strlen (codeset);
      char *dest;
      fromset = dest = (char *) alloca (len + 3);
      memcpy (__mempcpy (dest, codeset, len), "//", 3);
    }

  res = __gconv_find_transform (toset, fromset, &steps, &nsteps, flags);
  if (res == __GCONV_OK)
    {
      /* Find the modules.  */
      struct trans_struct *lastp = NULL;
      struct trans_struct *runp;

      for (runp = trans; runp != NULL; runp = runp->next)
       {
         if (runp->name == NULL
             || __builtin_expect (__gconv_translit_find (runp), 0) == 0)
           lastp = runp;
         else
           {
             /* This means we haven't found the module.  Remove it.  */
             if (lastp == NULL)
              trans  = runp->next;
             else
              lastp->next  = runp->next;
           }
       }

      /* Allocate room for handle.  */
      result = (__gconv_t) malloc (sizeof (struct __gconv_info)
                               + (nsteps
                                  * sizeof (struct __gconv_step_data)));
      if (result == NULL)
       res = __GCONV_NOMEM;
      else
       {
         size_t n;

         /* Remember the list of steps.  */
         result->__steps = steps;
         result->__nsteps = nsteps;

         /* Clear the array for the step data.  */
         memset (result->__data, '\0',
                nsteps * sizeof (struct __gconv_step_data));

         /* Call all initialization functions for the transformation
            step implementations.  */
         for (cnt = 0; cnt < nsteps; ++cnt)
           {
             size_t size;

             /* Would have to be done if we would not clear the whole
                 array above.  */
#if 0
             /* Reset the counter.  */
             result->__data[cnt].__invocation_counter = 0;

             /* It's a regular use.  */
             result->__data[cnt].__internal_use = 0;
#endif

             /* We use the `mbstate_t' member in DATA.  */
             result->__data[cnt].__statep = &result->__data[cnt].__state;

             /* Now see whether we can use any of the transliteration
               modules for this step.  */
             for (runp = trans; runp != NULL; runp = runp->next)
              for (n = 0; n < runp->ncsnames; ++n)
                if (__strcasecmp_l (steps[cnt].__from_name,
                                  runp->csnames[n], _nl_C_locobj_ptr) == 0)
                  {
                    void *data = NULL;

                    /* Match!  Now try the initializer.  */
                    if (runp->trans_init_fct == NULL
                       || (runp->trans_init_fct (&data,
                                              steps[cnt].__to_name)
                           == __GCONV_OK))
                     {
                       /* Append at the end of the list.  */
                       struct __gconv_trans_data *newp;
                       struct __gconv_trans_data **lastp;

                       newp = (struct __gconv_trans_data *)
                         malloc (sizeof (struct __gconv_trans_data));
                       if (newp == NULL)
                         {
                           res = __GCONV_NOMEM;
                           goto bail;
                         }

                       newp->__trans_fct = runp->trans_fct;
                       newp->__trans_context_fct = runp->trans_context_fct;
                       newp->__trans_end_fct = runp->trans_end_fct;
                       newp->__data = data;
                       newp->__next = NULL;

                       lastp = &result->__data[cnt].__trans;
                       while (*lastp != NULL)
                         lastp = &(*lastp)->__next;

                       *lastp = newp;
                     }
                    break;
                  }

             /* If this is the last step we must not allocate an
               output buffer.  */
             if (cnt < nsteps - 1)
              {
                result->__data[cnt].__flags = conv_flags;

                /* Allocate the buffer.  */
                size = (GCONV_NCHAR_GOAL * steps[cnt].__max_needed_to);

                result->__data[cnt].__outbuf = malloc (size);
                if (result->__data[cnt].__outbuf == NULL)
                  {
                    res = __GCONV_NOMEM;
                    goto bail;
                  }

                result->__data[cnt].__outbufend =
                  result->__data[cnt].__outbuf + size;
              }
             else
              {
                /* Handle the last entry.  */
                result->__data[cnt].__flags = conv_flags | __GCONV_IS_LAST;

                break;
              }
           }
       }

      if (res != __GCONV_OK)
       {
         /* Something went wrong.  Free all the resources.  */
         int serrno;
       bail:
         serrno = errno;

         if (result != NULL)
           {
             while (cnt-- > 0)
              {
                struct __gconv_trans_data *transp;

                transp = result->__data[cnt].__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);
                  }

                free (result->__data[cnt].__outbuf);
              }

             free (result);
             result = NULL;
           }

         __gconv_close_transform (steps, nsteps);

         __set_errno (serrno);
       }
    }

  *handle = result;
  return res;
}

Here is the call graph for this function:

Here is the caller graph for this function: