Back to index

glibc  2.9
Defines | Functions
iconvme.c File Reference
#include "iconvme.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "strdup.h"

Go to the source code of this file.

Defines

#define SIZE_MAX   ((size_t) -1)

Functions

char * iconv_string (const char *str, const char *from_codeset, const char *to_codeset)

Define Documentation

#define SIZE_MAX   ((size_t) -1)

Definition at line 49 of file iconvme.c.


Function Documentation

char* iconv_string ( const char *  str,
const char *  from_codeset,
const char *  to_codeset 
)

Definition at line 60 of file iconvme.c.

{
  char *dest = NULL;
#if HAVE_ICONV
  iconv_t cd;
  char *outp;
  char *p = (char *) str;
  size_t inbytes_remaining = strlen (p);
  /* Guess the maximum length the output string can have.  */
  size_t outbuf_size = inbytes_remaining + 1;
  size_t outbytes_remaining;
  size_t err;
  int have_error = 0;

  /* Use a worst-case output size guess, so long as that wouldn't be
     too large for comfort.  It's OK if the guess is wrong so long as
     it's nonzero.  */
  size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
  if (outbuf_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
    outbuf_size *= MB_LEN_MAX;
  outbytes_remaining = outbuf_size - 1;
#endif

  if (strcmp (to_codeset, from_codeset) == 0)
    return strdup (str);

#if HAVE_ICONV
  cd = iconv_open (to_codeset, from_codeset);
  if (cd == (iconv_t) -1)
    return NULL;

  outp = dest = (char *) malloc (outbuf_size);
  if (dest == NULL)
    goto out;

again:
  err = iconv (cd, &p, &inbytes_remaining, &outp, &outbytes_remaining);

  if (err == (size_t) - 1)
    {
      switch (errno)
       {
       case EINVAL:
         /* Incomplete text, do not report an error */
         break;

       case E2BIG:
         {
           size_t used = outp - dest;
           size_t newsize = outbuf_size * 2;
           char *newdest;

           if (newsize <= outbuf_size)
             {
              errno = ENOMEM;
              have_error = 1;
              goto out;
             }
           newdest = (char *) realloc (dest, newsize);
           if (newdest == NULL)
             {
              have_error = 1;
              goto out;
             }
           dest = newdest;
           outbuf_size = newsize;

           outp = dest + used;
           outbytes_remaining = outbuf_size - used - 1; /* -1 for NUL */

           goto again;
         }
         break;

       case EILSEQ:
         have_error = 1;
         break;

       default:
         have_error = 1;
         break;
       }
    }

  *outp = '\0';

out:
  {
    int save_errno = errno;

    if (iconv_close (cd) < 0 && !have_error)
      {
       /* If we didn't have a real error before, make sure we restore
          the iconv_close error below. */
       save_errno = errno;
       have_error = 1;
      }

    if (have_error && dest)
      {
       free (dest);
       dest = NULL;
       errno = save_errno;
      }
  }
#else
  errno = ENOSYS;
#endif

  return dest;
}

Here is the call graph for this function:

Here is the caller graph for this function: