code:
/* Character set conversion.
   Copyright (C) 1999-2001, 2007, 2009-2010 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License along
   with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#include <config.h>

/* Specification.  */
#include <iconv.h>

#include <stddef.h>

#if REPLACE_ICONV_UTF
# include <errno.h>
# include <stdint.h>
# include <stdlib.h>
# include "unistr.h"
# ifndef uintptr_t
#  define uintptr_t unsigned long
# endif
#endif

#if REPLACE_ICONV_UTF

/* UTF-{16,32}{BE,LE} converters taken from GNU libiconv 1.11.  */

/* Return code if invalid. (xxx_mbtowc) */
# define RET_ILSEQ      -1
/* Return code if no bytes were read. (xxx_mbtowc) */
# define RET_TOOFEW     -2

/* Return code if invalid. (xxx_wctomb) */
# define RET_ILUNI      -1
/* Return code if output buffer is too small. (xxx_wctomb, xxx_reset) */
# define RET_TOOSMALL   -2

/*
 * UTF-16BE
 */

/* Specification: RFC 2781 */

static int
utf16be_mbtowc (ucs4_t *pwc, const unsigned char *s, size_t n)
{
  if (n >= 2)
    {
      ucs4_t wc = (s[0] << 8) + s[1];
      if (wc >= 0xd800 && wc < 0xdc00)
        {
          if (n >= 4)
            {
              ucs4_t wc2 = (s[2] << 8) + s[3];
              if (!(wc2 >= 0xdc00 && wc2 < 0xe000))
                return RET_ILSEQ;
              *pwc = 0x10000 + ((wc - 0xd800) << 10) + (wc2 - 0xdc00);
              return 4;
            }
        }
      else if (wc >= 0xdc00 && wc < 0xe000)
        {
          return RET_ILSEQ;
        }
      else
        {
          *pwc = wc;
          return 2;
        }
    }
  return RET_TOOFEW;
}

static int
utf16be_wctomb (unsigned char *r, ucs4_t wc, size_t n)
{
  if (!(wc >= 0xd800 && wc < 0xe000))
    {
      if (wc < 0x10000)
        {
          if (n >= 2)
            {
              r[0] = (unsigned char) (wc >> 8);
              r[1] = (unsigned char) wc;
              return 2;
            }
          else
            return RET_TOOSMALL;
        }
      else if (wc < 0x110000)
        {
          if (n >= 4)
            {
              ucs4_t wc1 = 0xd800 + ((wc - 0x10000) >> 10);
              ucs4_t wc2 = 0xdc00 + ((wc - 0x10000) & 0x3ff);
              r[0] = (unsigned char) (wc1 >> 8);
              r[1] = (unsigned char) wc1;
              r[2] = (unsigned char) (wc2 >> 8);
              r[3] = (unsigned char) wc2;
              return 4;
            }
          else
            return RET_TOOSMALL;
        }
    }
  return RET_ILUNI;
}

/*
 * UTF-16LE
 */

/* Specification: RFC 2781 */

static int
utf16le_mbtowc (ucs4_t *pwc, const unsigned char *s, size_t n)
{
  if (n >= 2)
    {
      ucs4_t wc = s[0] + (s[1] << 8);
      if (wc >= 0xd800 && wc < 0xdc00)
        {
          if (n >= 4)
            {
              ucs4_t wc2 = s[2] + (s[3] << 8);
              if (!(wc2 >= 0xdc00 && wc2 < 0xe000))
                return RET_ILSEQ;
              *pwc = 0x10000 + ((wc - 0xd800) << 10) + (wc2 - 0xdc00);
              return 4;
            }
        }
      else if (wc >= 0xdc00 && wc < 0xe000)
        {
          return RET_ILSEQ;
        }
      else
        {
          *pwc = wc;
          return 2;
        }
    }
  return RET_TOOFEW;
}

static int
utf16le_wctomb (unsigned char *r, ucs4_t wc, size_t n)
{
  if (!(wc >= 0xd800 && wc < 0xe000))
    {
      if (wc < 0x10000)
        {
          if (n >= 2)
            {
              r[0] = (unsigned char) wc;
              r[1] = (unsigned char) (wc >> 8);
              return 2;
            }
          else
            return RET_TOOSMALL;
        }
      else if (wc < 0x110000)
        {
          if (n >= 4)
            {
              ucs4_t wc1 = 0xd800 + ((wc - 0x10000) >> 10);
              ucs4_t wc2 = 0xdc00 + ((wc - 0x10000) & 0x3ff);
              r[0] = (unsigned char) wc1;
              r[1] = (unsigned char) (wc1 >> 8);
              r[2] = (unsigned char) wc2;
              r[3] = (unsigned char) (wc2 >> 8);
              return 4;
            }
          else
            return RET_TOOSMALL;
        }
    }
  return RET_ILUNI;
}

/*
 * UTF-32BE
 */

/* Specification: Unicode 3.1 Standard Annex #19 */

static int
utf32be_mbtowc (ucs4_t *pwc, const unsigned char *s, size_t n)
{
  if (n >= 4)
    {
      ucs4_t wc = (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
      if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000))
        {
          *pwc = wc;
          return 4;
        }
      else
        return RET_ILSEQ;
    }
  return RET_TOOFEW;
}

static int
utf32be_wctomb (unsigned char *r, ucs4_t wc, size_t n)
{
  if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000))
    {
      if (n >= 4)
        {
          r[0] = 0;
          r[1] = (unsigned char) (wc >> 16);
          r[2] = (unsigned char) (wc >> 8);
          r[3] = (unsigned char) wc;
          return 4;
        }
      else
        return RET_TOOSMALL;
    }
  return RET_ILUNI;
}

/*
 * UTF-32LE
 */

/* Specification: Unicode 3.1 Standard Annex #19 */

static int
utf32le_mbtowc (ucs4_t *pwc, const unsigned char *s, size_t n)
{
  if (n >= 4)
    {
      ucs4_t wc = s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24);
      if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000))
        {
          *pwc = wc;
          return 4;
        }
      else
        return RET_ILSEQ;
    }
  return RET_TOOFEW;
}

static int
utf32le_wctomb (unsigned char *r, ucs4_t wc, size_t n)
{
  if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000))
    {
      if (n >= 4)
        {
          r[0] = (unsigned char) wc;
          r[1] = (unsigned char) (wc >> 8);
          r[2] = (unsigned char) (wc >> 16);
          r[3] = 0;
          return 4;
        }
      else
        return RET_TOOSMALL;
    }
  return RET_ILUNI;
}

#endif

size_t
rpl_iconv (iconv_t cd,
           ICONV_CONST char **inbuf, size_t *inbytesleft,
           char **outbuf, size_t *outbytesleft)
#undef iconv
{
#if REPLACE_ICONV_UTF
  switch ((uintptr_t) cd)
    {
      {
        int (*xxx_wctomb) (unsigned char *, ucs4_t, size_t);

        case (uintptr_t) _ICONV_UTF8_UTF16BE:
          xxx_wctomb = utf16be_wctomb;
          goto loop_from_utf8;
        case (uintptr_t) _ICONV_UTF8_UTF16LE:
          xxx_wctomb = utf16le_wctomb;
          goto loop_from_utf8;
        case (uintptr_t) _ICONV_UTF8_UTF32BE:
          xxx_wctomb = utf32be_wctomb;
          goto loop_from_utf8;
        case (uintptr_t) _ICONV_UTF8_UTF32LE:
          xxx_wctomb = utf32le_wctomb;
          goto loop_from_utf8;

       loop_from_utf8:
        if (inbuf == NULL || *inbuf == NULL)
          return 0;
        {
          ICONV_CONST char *inptr = *inbuf;
          size_t inleft = *inbytesleft;
          char *outptr = *outbuf;
          size_t outleft = *outbytesleft;
          size_t res = 0;
          while (inleft > 0)
            {
              ucs4_t uc;
              int m = u8_mbtoucr (&uc, (const uint8_t *) inptr, inleft);
              if (m <= 0)
                {
                  if (m == -1)
                    {
                      errno = EILSEQ;
                      res = (size_t)(-1);
                      break;
                    }
                  if (m == -2)
                    {
                      errno = EINVAL;
                      res = (size_t)(-1);
                      break;
                    }
                  abort ();
                }
              else
                {
                  int n = xxx_wctomb ((uint8_t *) outptr, uc, outleft);
                  if (n < 0)
                    {
                      if (n == RET_ILUNI)
                        {
                          errno = EILSEQ;
                          res = (size_t)(-1);
                          break;
                        }
                      if (n == RET_TOOSMALL)
                        {
                          errno = E2BIG;
                          res = (size_t)(-1);
                          break;
                        }
                      abort ();
                    }
                  else
                    {
                      inptr += m;
                      inleft -= m;
                      outptr += n;
                      outleft -= n;
                    }
                }
            }
          *inbuf = inptr;
          *inbytesleft = inleft;
          *outbuf = outptr;
          *outbytesleft = outleft;
          return res;
        }
      }

      {
        int (*xxx_mbtowc) (ucs4_t *, const unsigned char *, size_t);

        case (uintptr_t) _ICONV_UTF16BE_UTF8:
          xxx_mbtowc = utf16be_mbtowc;
          goto loop_to_utf8;
        case (uintptr_t) _ICONV_UTF16LE_UTF8:
          xxx_mbtowc = utf16le_mbtowc;
          goto loop_to_utf8;
        case (uintptr_t) _ICONV_UTF32BE_UTF8:
          xxx_mbtowc = utf32be_mbtowc;
          goto loop_to_utf8;
        case (uintptr_t) _ICONV_UTF32LE_UTF8:
          xxx_mbtowc = utf32le_mbtowc;
          goto loop_to_utf8;

       loop_to_utf8:
        if (inbuf == NULL || *inbuf == NULL)
          return 0;
        {
          ICONV_CONST char *inptr = *inbuf;
          size_t inleft = *inbytesleft;
          char *outptr = *outbuf;
          size_t outleft = *outbytesleft;
          size_t res = 0;
          while (inleft > 0)
            {
              ucs4_t uc;
              int m = xxx_mbtowc (&uc, (const uint8_t *) inptr, inleft);
              if (m <= 0)
                {
                  if (m == RET_ILSEQ)
                    {
                      errno = EILSEQ;
                      res = (size_t)(-1);
                      break;
                    }
                  if (m == RET_TOOFEW)
                    {
                      errno = EINVAL;
                      res = (size_t)(-1);
                      break;
                    }
                  abort ();
                }
              else
                {
                  int n = u8_uctomb ((uint8_t *) outptr, uc, outleft);
                  if (n < 0)
                    {
                      if (n == -1)
                        {
                          errno = EILSEQ;
                          res = (size_t)(-1);
                          break;
                        }
                      if (n == -2)
                        {
                          errno = E2BIG;
                          res = (size_t)(-1);
                          break;
                        }
                      abort ();
                    }
                  else
                    {
                      inptr += m;
                      inleft -= m;
                      outptr += n;
                      outleft -= n;
                    }
                }
            }
          *inbuf = inptr;
          *inbytesleft = inleft;
          *outbuf = outptr;
          *outbytesleft = outleft;
          return res;
        }
      }
    }
#endif
  return iconv (cd, inbuf, inbytesleft, outbuf, outbytesleft);
}


code:
/* A GNU-like <iconv.h>.

   Copyright (C) 2007-2010 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#ifndef _GL_ICONV_H

#if __GNUC__ >= 3
@PRAGMA_SYSTEM_HEADER@
#endif

/* The include_next requires a split double-inclusion guard.  */
#@INCLUDE_NEXT@ @NEXT_ICONV_H@

#ifndef _GL_ICONV_H
#define _GL_ICONV_H

/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */

/* The definition of _GL_ARG_NONNULL is copied here.  */

/* The definition of _GL_WARN_ON_USE is copied here.  */

#if @REPLACE_ICONV_OPEN@
/* An iconv_open wrapper that supports the IANA standardized encoding names
   ("ISO-8859-1" etc.) as far as possible.  */
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#  define iconv_open rpl_iconv_open
# endif
_GL_FUNCDECL_RPL (iconv_open, iconv_t,
                  (const char *tocode, const char *fromcode)
                  _GL_ARG_NONNULL ((1, 2)));
_GL_CXXALIAS_RPL (iconv_open, iconv_t,
                  (const char *tocode, const char *fromcode));
#else
_GL_CXXALIAS_SYS (iconv_open, iconv_t,
                  (const char *tocode, const char *fromcode));
#endif
_GL_CXXALIASWARN (iconv_open);

#if @REPLACE_ICONV_UTF@
/* Special constants for supporting UTF-{16,32}{BE,LE} encodings.
   Not public.  */
# define _ICONV_UTF8_UTF16BE (iconv_t)(-161)
# define _ICONV_UTF8_UTF16LE (iconv_t)(-162)
# define _ICONV_UTF8_UTF32BE (iconv_t)(-163)
# define _ICONV_UTF8_UTF32LE (iconv_t)(-164)
# define _ICONV_UTF16BE_UTF8 (iconv_t)(-165)
# define _ICONV_UTF16LE_UTF8 (iconv_t)(-166)
# define _ICONV_UTF32BE_UTF8 (iconv_t)(-167)
# define _ICONV_UTF32LE_UTF8 (iconv_t)(-168)
#endif

#if @REPLACE_ICONV@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#  define iconv rpl_iconv
# endif
_GL_FUNCDECL_RPL (iconv, size_t,
                  (iconv_t cd,
                   @ICONV_CONST@ char **inbuf, size_t *inbytesleft,
                   char **outbuf, size_t *outbytesleft));
_GL_CXXALIAS_RPL (iconv, size_t,
                  (iconv_t cd,
                   @ICONV_CONST@ char **inbuf, size_t *inbytesleft,
                   char **outbuf, size_t *outbytesleft));
#else
_GL_CXXALIAS_SYS (iconv, size_t,
                  (iconv_t cd,
                   @ICONV_CONST@ char **inbuf, size_t *inbytesleft,
                   char **outbuf, size_t *outbytesleft));
#endif
_GL_CXXALIASWARN (iconv);

#if @REPLACE_ICONV@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#  define iconv_close rpl_iconv_close
# endif
_GL_FUNCDECL_RPL (iconv_close, int, (iconv_t cd));
_GL_CXXALIAS_RPL (iconv_close, int, (iconv_t cd));
#else
_GL_CXXALIAS_SYS (iconv_close, int, (iconv_t cd));
#endif
_GL_CXXALIASWARN (iconv_close);

#endif /* _GL_ICONV_H */
#endif /* _GL_ICONV_H */

license: mit


code:
/* Character set conversion.
   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License along
   with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#include <config.h>

/* Specification.  */
#include <iconv.h>

#include <stdint.h>
#ifndef uintptr_t
# define uintptr_t unsigned long
#endif

int
rpl_iconv_close (iconv_t cd)
#undef iconv_close
{
#if REPLACE_ICONV_UTF
  switch ((uintptr_t) cd)
    {
    case (uintptr_t) _ICONV_UTF8_UTF16BE:
    case (uintptr_t) _ICONV_UTF8_UTF16LE:
    case (uintptr_t) _ICONV_UTF8_UTF32BE:
    case (uintptr_t) _ICONV_UTF8_UTF32LE:
    case (uintptr_t) _ICONV_UTF16BE_UTF8:
    case (uintptr_t) _ICONV_UTF16LE_UTF8:
    case (uintptr_t) _ICONV_UTF32BE_UTF8:
    case (uintptr_t) _ICONV_UTF32LE_UTF8:
      return 0;
    }
#endif
  return iconv_close (cd);
}


code:
struct mapping { int standard_name; const char vendor_name[10 + 1]; };
%struct-type
%language=ANSI-C
%define slot-name standard_name
%define hash-function-name mapping_hash
%define lookup-function-name mapping_lookup
%readonly-tables
%global-table
%define word-array-name mappings
%pic
%%
# On AIX 5.1, look in /usr/lib/nls/loc/uconvTable.
ISO-8859-1, "ISO8859-1"
ISO-8859-2, "ISO8859-2"
ISO-8859-3, "ISO8859-3"
ISO-8859-4, "ISO8859-4"
ISO-8859-5, "ISO8859-5"
ISO-8859-6, "ISO8859-6"
ISO-8859-7, "ISO8859-7"
ISO-8859-8, "ISO8859-8"
ISO-8859-9, "ISO8859-9"
ISO-8859-15, "ISO8859-15"
CP437, "IBM-437"
CP850, "IBM-850"
CP852, "IBM-852"
CP856, "IBM-856"
CP857, "IBM-857"
CP861, "IBM-861"
CP865, "IBM-865"
CP869, "IBM-869"
ISO-8859-13, "IBM-921"
CP922, "IBM-922"
CP932, "IBM-932"
CP943, "IBM-943"
CP1046, "IBM-1046"
CP1124, "IBM-1124"
CP1125, "IBM-1125"
CP1129, "IBM-1129"
CP1252, "IBM-1252"
GB2312, "IBM-eucCN"
EUC-JP, "IBM-eucJP"
EUC-KR, "IBM-eucKR"
EUC-TW, "IBM-eucTW"
BIG5, "big5"


code:
struct mapping { int standard_name; const char vendor_name[9 + 1]; };
%struct-type
%language=ANSI-C
%define slot-name standard_name
%define hash-function-name mapping_hash
%define lookup-function-name mapping_lookup
%readonly-tables
%global-table
%define word-array-name mappings
%pic
%%
# On HP-UX 11.11, look in /usr/lib/nls/iconv.
ISO-8859-1, "iso88591"
ISO-8859-2, "iso88592"
ISO-8859-5, "iso88595"
ISO-8859-6, "iso88596"
ISO-8859-7, "iso88597"
ISO-8859-8, "iso88598"
ISO-8859-9, "iso88599"
ISO-8859-15, "iso885915"
CP437, "cp437"
CP775, "cp775"
CP850, "cp850"
CP852, "cp852"
CP855, "cp855"
CP857, "cp857"
CP861, "cp861"
CP862, "cp862"
CP864, "cp864"
CP865, "cp865"
CP866, "cp866"
CP869, "cp869"
CP874, "cp874"
CP1250, "cp1250"
CP1251, "cp1251"
CP1252, "cp1252"
CP1253, "cp1253"
CP1254, "cp1254"
CP1255, "cp1255"
CP1256, "cp1256"
CP1257, "cp1257"
CP1258, "cp1258"
HP-ROMAN8, "roman8"
HP-ARABIC8, "arabic8"
HP-GREEK8, "greek8"
HP-HEBREW8, "hebrew8"
HP-TURKISH8, "turkish8"
HP-KANA8, "kana8"
TIS-620, "tis620"
GB2312, "hp15CN"
EUC-JP, "eucJP"
EUC-KR, "eucKR"
EUC-TW, "eucTW"
BIG5, "big5"
SHIFT_JIS, "sjis"
UTF-8, "utf8"


code:
struct mapping { int standard_name; const char vendor_name[10 + 1]; };
%struct-type
%language=ANSI-C
%define slot-name standard_name
%define hash-function-name mapping_hash
%define lookup-function-name mapping_lookup
%readonly-tables
%global-table
%define word-array-name mappings
%pic
%%
# On IRIX 6.5, look in /usr/lib/iconv and /usr/lib/international/encodings.
ISO-8859-1, "ISO8859-1"
ISO-8859-2, "ISO8859-2"
ISO-8859-3, "ISO8859-3"
ISO-8859-4, "ISO8859-4"
ISO-8859-5, "ISO8859-5"
ISO-8859-6, "ISO8859-6"
ISO-8859-7, "ISO8859-7"
ISO-8859-8, "ISO8859-8"
ISO-8859-9, "ISO8859-9"
ISO-8859-15, "ISO8859-15"
KOI8-R, "KOI8"
CP855, "DOS855"
CP1251, "WIN1251"
GB2312, "eucCN"
EUC-JP, "eucJP"
EUC-KR, "eucKR"
EUC-TW, "eucTW"
SHIFT_JIS, "sjis"
TIS-620, "TIS620"


code:
struct mapping { int standard_name; const char vendor_name[10 + 1]; };
%struct-type
%language=ANSI-C
%define slot-name standard_name
%define hash-function-name mapping_hash
%define lookup-function-name mapping_lookup
%readonly-tables
%global-table
%define word-array-name mappings
%pic
%%
# On Solaris 10, look in the "iconv -l" output. Some aliases are advertised but
# not actually supported by the iconv() function and by the 'iconv' program.
# For example:
#   $ echo abc | iconv -f 646 -t ISO-8859-1
#   Not supported 646 to ISO-8859-1
#   $ echo abc | iconv -f 646 -t ISO8859-1
$   abc
ASCII, "646"
ISO-8859-1, "ISO8859-1"
ISO-8859-2, "ISO8859-2"
ISO-8859-3, "ISO8859-3"
ISO-8859-4, "ISO8859-4"
ISO-8859-5, "ISO8859-5"
ISO-8859-6, "ISO8859-6"
ISO-8859-7, "ISO8859-7"
ISO-8859-8, "ISO8859-8"
ISO-8859-9, "ISO8859-9"
ISO-8859-15, "ISO8859-15"
CP1251, "ansi-1251"


code:
/* Character set conversion.
   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License along
   with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#include <config.h>

/* Specification.  */
#include <iconv.h>

#include <errno.h>
#include <string.h>
#include "c-ctype.h"
#include "c-strcase.h"

#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))

/* Namespace cleanliness.  */
#define mapping_lookup rpl_iconv_open_mapping_lookup

/* The macro ICONV_FLAVOR is defined to one of these or undefined.  */

#define ICONV_FLAVOR_AIX "iconv_open-aix.h"
#define ICONV_FLAVOR_HPUX "iconv_open-hpux.h"
#define ICONV_FLAVOR_IRIX "iconv_open-irix.h"
#define ICONV_FLAVOR_OSF "iconv_open-osf.h"
#define ICONV_FLAVOR_SOLARIS "iconv_open-solaris.h"

#ifdef ICONV_FLAVOR
# include ICONV_FLAVOR
#endif

iconv_t
rpl_iconv_open (const char *tocode, const char *fromcode)
#undef iconv_open
{
  char fromcode_upper[32];
  char tocode_upper[32];
  char *fromcode_upper_end;
  char *tocode_upper_end;

#if REPLACE_ICONV_UTF
  /* Special handling of conversion between UTF-8 and UTF-{16,32}{BE,LE}.
     Do this here, before calling the real iconv_open(), because  OSF/1 5.1
     iconv() to these encoding inserts a BOM, which is wrong.
     We do not need to handle conversion between arbitrary encodings and
     UTF-{16,32}{BE,LE}, because the 'striconveh' module implements two-step
     conversion throough UTF-8.
     The _ICONV_* constants are chosen to be disjoint from any iconv_t
     returned by the system's iconv_open() functions.  Recall that iconv_t
     is a scalar type.  */
  if (c_toupper (fromcode[0]) == 'U'
      && c_toupper (fromcode[1]) == 'T'
      && c_toupper (fromcode[2]) == 'F'
      && fromcode[3] == '-')
    {
      if (c_toupper (tocode[0]) == 'U'
          && c_toupper (tocode[1]) == 'T'
          && c_toupper (tocode[2]) == 'F'
          && tocode[3] == '-')
        {
          if (strcmp (fromcode + 4, "8") == 0)
            {
              if (c_strcasecmp (tocode + 4, "16BE") == 0)
                return _ICONV_UTF8_UTF16BE;
              if (c_strcasecmp (tocode + 4, "16LE") == 0)
                return _ICONV_UTF8_UTF16LE;
              if (c_strcasecmp (tocode + 4, "32BE") == 0)
                return _ICONV_UTF8_UTF32BE;
              if (c_strcasecmp (tocode + 4, "32LE") == 0)
                return _ICONV_UTF8_UTF32LE;
            }
          else if (strcmp (tocode + 4, "8") == 0)
            {
              if (c_strcasecmp (fromcode + 4, "16BE") == 0)
                return _ICONV_UTF16BE_UTF8;
              if (c_strcasecmp (fromcode + 4, "16LE") == 0)
                return _ICONV_UTF16LE_UTF8;
              if (c_strcasecmp (fromcode + 4, "32BE") == 0)
                return _ICONV_UTF32BE_UTF8;
              if (c_strcasecmp (fromcode + 4, "32LE") == 0)
                return _ICONV_UTF32LE_UTF8;
            }
        }
    }
#endif

  /* Do *not* add special support for 8-bit encodings like ASCII or ISO-8859-1
     here.  This would lead to programs that work in some locales (such as the
     "C" or "en_US" locales) but do not work in East Asian locales.  It is
     better if programmers make their programs depend on GNU libiconv (except
     on glibc systems), e.g. by using the AM_ICONV macro and documenting the
     dependency in an INSTALL or DEPENDENCIES file.  */

  /* Try with the original names first.
     This covers the case when fromcode or tocode is a lowercase encoding name
     that is understood by the system's iconv_open but not listed in our
     mappings table.  */
  {
    iconv_t cd = iconv_open (tocode, fromcode);
    if (cd != (iconv_t)(-1))
      return cd;
  }

  /* Convert the encodings to upper case, because
       1. in the arguments of iconv_open() on AIX, HP-UX, and OSF/1 the case
          matters,
       2. it makes searching in the table faster.  */
  {
    const char *p = fromcode;
    char *q = fromcode_upper;
    while ((*q = c_toupper (*p)) != '\0')
      {
        p++;
        q++;
        if (q == &fromcode_upper[SIZEOF (fromcode_upper)])
          {
            errno = EINVAL;
            return (iconv_t)(-1);
          }
      }
    fromcode_upper_end = q;
  }

  {
    const char *p = tocode;
    char *q = tocode_upper;
    while ((*q = c_toupper (*p)) != '\0')
      {
        p++;
        q++;
        if (q == &tocode_upper[SIZEOF (tocode_upper)])
          {
            errno = EINVAL;
            return (iconv_t)(-1);
          }
      }
    tocode_upper_end = q;
  }

#ifdef ICONV_FLAVOR
  /* Apply the mappings.  */
  {
    const struct mapping *m =
      mapping_lookup (fromcode_upper, fromcode_upper_end - fromcode_upper);

    fromcode = (m != NULL ? m->vendor_name : fromcode_upper);
  }
  {
    const struct mapping *m =
      mapping_lookup (tocode_upper, tocode_upper_end - tocode_upper);

    tocode = (m != NULL ? m->vendor_name : tocode_upper);
  }
#else
  fromcode = fromcode_upper;
  tocode = tocode_upper;
#endif

  return iconv_open (tocode, fromcode);
}


code:
/* Character set conversion handler type.
   Copyright (C) 2001-2007, 2009-2010 Free Software Foundation, Inc.
   Written by Bruno Haible.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#ifndef _ICONVEH_H
#define _ICONVEH_H

#ifdef __cplusplus
extern "C" {
#endif

/* Handling of unconvertible characters.  */
enum iconv_ilseq_handler
{
  iconveh_error,                /* return and set errno = EILSEQ */
  iconveh_question_mark,        /* use one '?' per unconvertible character */
  iconveh_escape_sequence       /* use escape sequence \uxxxx or \Uxxxxxxxx */
};

#ifdef __cplusplus
}
#endif

#endif /* _ICONVEH_H */


code:
/* ignore a function return without a compiler warning

   Copyright (C) 2008-2009 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/* Written by Jim Meyering.  */

/* Use these functions to avoid a warning when using a function declared with
   gcc's warn_unused_result attribute, but for which you really do want to
   ignore the result.  Traditionally, people have used a "(void)" cast to
   indicate that a function's return value is deliberately unused.  However,
   if the function is declared with __attribute__((warn_unused_result)),
   gcc issues a warning even with the cast.

   Caution: most of the time, you really should heed gcc's warning, and
   check the return value.  However, in those exceptional cases in which
   you're sure you know what you're doing, use this function.

   For the record, here's one of the ignorable warnings:
   "copy.c:233: warning: ignoring return value of 'fchown',
   declared with attribute warn_unused_result".  */

static inline void ignore_value (int i) { (void) i; }
static inline void ignore_ptr (void* p) { (void) p; }
/* FIXME: what about aggregate types? */


code:
/* inet_ntop.c -- convert IPv4 and IPv6 addresses from binary to text form

   Copyright (C) 2005-2006, 2008-2010 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

/*
 * Copyright (c) 1996-1999 by Internet Software Consortium.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

#include <config.h>

/* Specification.  */
#include <arpa/inet.h>

#include <stdio.h>
#include <string.h>
#include <errno.h>

#define NS_IN6ADDRSZ 16
#define NS_INT16SZ 2

/*
 * WARNING: Don't even consider trying to compile this on a system where
 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
 */
typedef int verify_int_size[2 * sizeof (int) - 7];

static const char *inet_ntop4 (const unsigned char *src, char *dst, socklen_t size);
#if HAVE_IPV6
static const char *inet_ntop6 (const unsigned char *src, char *dst, socklen_t size);
#endif

/* char *
 * inet_ntop(af, src, dst, size)
 *      convert a network format address to presentation format.
 * return:
 *      pointer to presentation format address (`dst'), or NULL (see errno).
 * author:
 *      Paul Vixie, 1996.
 */
const char *
inet_ntop (int af, const void *restrict src,
           char *restrict dst, socklen_t cnt)
{
  switch (af)
    {
#if HAVE_IPV4
    case AF_INET:
      return (inet_ntop4 (src, dst, cnt));
#endif

#if HAVE_IPV6
    case AF_INET6:
      return (inet_ntop6 (src, dst, cnt));
#endif

    default:
      errno = EAFNOSUPPORT;
      return (NULL);
    }
  /* NOTREACHED */
}

/* const char *
 * inet_ntop4(src, dst, size)
 *      format an IPv4 address
 * return:
 *      `dst' (as a const)
 * notes:
 *      (1) uses no statics
 *      (2) takes a u_char* not an in_addr as input
 * author:
 *      Paul Vixie, 1996.
 */
static const char *
inet_ntop4 (const unsigned char *src, char *dst, socklen_t size)
{
  char tmp[sizeof "255.255.255.255"];
  int len;

  len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
  if (len < 0)
    return NULL;

  if (len > size)
    {
      errno = ENOSPC;
      return NULL;
    }

  return strcpy (dst, tmp);
}

#if HAVE_IPV6

/* const char *
 * inet_ntop6(src, dst, size)
 *      convert IPv6 binary address into presentation (printable) format
 * author:
 *      Paul Vixie, 1996.
 */
static const char *
inet_ntop6 (const unsigned char *src, char *dst, socklen_t size)
{
  /*
   * Note that int32_t and int16_t need only be "at least" large enough
   * to contain a value of the specified size.  On some systems, like
   * Crays, there is no such thing as an integer variable with 16 bits.
   * Keep this in mind if you think this function should have been coded
   * to use pointer overlays.  All the world's not a VAX.
   */
  char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
  struct
  {
    int base, len;
  } best, cur;
  unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
  int i;

  /*
   * Preprocess:
   *      Copy the input (bytewise) array into a wordwise array.
   *      Find the longest run of 0x00's in src[] for :: shorthanding.
   */
  memset (words, '\0', sizeof words);
  for (i = 0; i < NS_IN6ADDRSZ; i += 2)
    words[i / 2] = (src[i] << 8) | src[i + 1];
  best.base = -1;
  cur.base = -1;
  for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
    {
      if (words[i] == 0)
        {
          if (cur.base == -1)
            cur.base = i, cur.len = 1;
          else
            cur.len++;
        }
      else
        {
          if (cur.base != -1)
            {
              if (best.base == -1 || cur.len > best.len)
                best = cur;
              cur.base = -1;
            }
        }
    }
  if (cur.base != -1)
    {
      if (best.base == -1 || cur.len > best.len)
        best = cur;
    }
  if (best.base != -1 && best.len < 2)
    best.base = -1;

  /*
   * Format the result.
   */
  tp = tmp;
  for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
    {
      /* Are we inside the best run of 0x00's? */
      if (best.base != -1 && i >= best.base && i < (best.base + best.len))
        {
          if (i == best.base)
            *tp++ = ':';
          continue;
        }
      /* Are we following an initial run of 0x00s or any real hex? */
      if (i != 0)
        *tp++ = ':';
      /* Is this address an encapsulated IPv4? */
      if (i == 6 && best.base == 0 &&
          (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
        {
          if (!inet_ntop4 (src + 12, tp, sizeof tmp - (tp - tmp)))
            return (NULL);
          tp += strlen (tp);
          break;
        }
      {
        int len = sprintf (tp, "%x", words[i]);
        if (len < 0)
          return NULL;
        tp += len;
      }
    }
  /* Was it a trailing run of 0x00's? */
  if (best.base != -1 && (best.base + best.len) ==
      (NS_IN6ADDRSZ / NS_INT16SZ))
    *tp++ = ':';
  *tp++ = '\0';

  /*
   * Check for overflow, copy, and we're done.
   */
  if ((socklen_t) (tp - tmp) > size)
    {
      errno = ENOSPC;
      return NULL;
    }

  return strcpy (dst, tmp);
}

#endif


code:
/* inet_pton.c -- convert IPv4 and IPv6 addresses from text to binary form

   Copyright (C) 2006, 2008, 2009, 2010 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/*
 * Copyright (c) 1996,1999 by Internet Software Consortium.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

#include <config.h>

/* Specification.  */
#include <arpa/inet.h>

#include <c-ctype.h>
#include <string.h>
#include <errno.h>

#define NS_INADDRSZ 4
#define NS_IN6ADDRSZ 16
#define NS_INT16SZ 2

/*
 * WARNING: Don't even consider trying to compile this on a system where
 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
 */

static int inet_pton4 (const char *src, unsigned char *dst);
#if HAVE_IPV6
static int inet_pton6 (const char *src, unsigned char *dst);
#endif

/* int
 * inet_pton(af, src, dst)
 *      convert from presentation format (which usually means ASCII printable)
 *      to network format (which is usually some kind of binary format).
 * return:
 *      1 if the address was valid for the specified address family
 *      0 if the address wasn't valid (`dst' is untouched in this case)
 *      -1 if some other error occurred (`dst' is untouched in this case, too)
 * author:
 *      Paul Vixie, 1996.
 */
int
inet_pton (int af, const char *restrict src, void *restrict dst)
{
  switch (af)
    {
    case AF_INET:
      return (inet_pton4 (src, dst));

#if HAVE_IPV6
    case AF_INET6:
      return (inet_pton6 (src, dst));
#endif

    default:
      errno = EAFNOSUPPORT;
      return (-1);
    }
  /* NOTREACHED */
}

/* int
 * inet_pton4(src, dst)
 *      like inet_aton() but without all the hexadecimal, octal (with the
 *      exception of 0) and shorthand.
 * return:
 *      1 if `src' is a valid dotted quad, else 0.
 * notice:
 *      does not touch `dst' unless it's returning 1.
 * author:
 *      Paul Vixie, 1996.
 */
static int
inet_pton4 (const char *restrict src, unsigned char *restrict dst)
{
  int saw_digit, octets, ch;
  unsigned char tmp[NS_INADDRSZ], *tp;

  saw_digit = 0;
  octets = 0;
  *(tp = tmp) = 0;
  while ((ch = *src++) != '\0')
    {

      if (ch >= '0' && ch <= '9')
        {
          unsigned new = *tp * 10 + (ch - '0');

          if (saw_digit && *tp == 0)
            return (0);
          if (new > 255)
            return (0);
          *tp = new;
          if (!saw_digit)
            {
              if (++octets > 4)
                return (0);
              saw_digit = 1;
            }
        }
      else if (ch == '.' && saw_digit)
        {
          if (octets == 4)
            return (0);
          *++tp = 0;
          saw_digit = 0;
        }
      else
        return (0);
    }
  if (octets < 4)
    return (0);
  memcpy (dst, tmp, NS_INADDRSZ);
  return (1);
}

#if HAVE_IPV6

/* int
 * inet_pton6(src, dst)
 *      convert presentation level address to network order binary form.
 * return:
 *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
 * notice:
 *      (1) does not touch `dst' unless it's returning 1.
 *      (2) :: in a full address is silently ignored.
 * credit:
 *      inspired by Mark Andrews.
 * author:
 *      Paul Vixie, 1996.
 */
static int
inet_pton6 (const char *restrict src, unsigned char *restrict dst)
{
  static const char xdigits[] = "0123456789abcdef";
  unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
  const char *curtok;
  int ch, saw_xdigit;
  unsigned val;

  tp = memset (tmp, '\0', NS_IN6ADDRSZ);
  endp = tp + NS_IN6ADDRSZ;
  colonp = NULL;
  /* Leading :: requires some special handling. */
  if (*src == ':')
    if (*++src != ':')
      return (0);
  curtok = src;
  saw_xdigit = 0;
  val = 0;
  while ((ch = c_tolower (*src++)) != '\0')
    {
      const char *pch;

      pch = strchr (xdigits, ch);
      if (pch != NULL)
        {
          val <<= 4;
          val |= (pch - xdigits);
          if (val > 0xffff)
            return (0);
          saw_xdigit = 1;
          continue;
        }
      if (ch == ':')
        {
          curtok = src;
          if (!saw_xdigit)
            {
              if (colonp)
                return (0);
              colonp = tp;
              continue;
            }
          else if (*src == '\0')
            {
              return (0);
            }
          if (tp + NS_INT16SZ > endp)
            return (0);
          *tp++ = (u_char) (val >> 8) & 0xff;
          *tp++ = (u_char) val & 0xff;
          saw_xdigit = 0;
          val = 0;
          continue;
        }
      if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
          inet_pton4 (curtok, tp) > 0)
        {
          tp += NS_INADDRSZ;
          saw_xdigit = 0;
          break;                /* '\0' was seen by inet_pton4(). */
        }
      return (0);
    }
  if (saw_xdigit)
    {
      if (tp + NS_INT16SZ > endp)
        return (0);
      *tp++ = (u_char) (val >> 8) & 0xff;
      *tp++ = (u_char) val & 0xff;
    }
  if (colonp != NULL)
    {
      /*
       * Since some memmove()'s erroneously fail to handle
       * overlapping regions, we'll do the shift by hand.
       */
      const int n = tp - colonp;
      int i;

      if (tp == endp)
        return (0);
      for (i = 1; i <= n; i++)
        {
          endp[-i] = colonp[n - i];
          colonp[n - i] = 0;
        }
      tp = endp;
    }
  if (tp != endp)
    return (0);
  memcpy (dst, tmp, NS_IN6ADDRSZ);
  return (1);
}
#endif


code:
# Suppress valgrind messages in an installed libunistring.

# Suppress a valgrind message about use of uninitialized memory in freea().
# This use is OK because it provides only a speedup.
{
    libunistring_freea
    Memcheck:Cond
    fun:libunistring_freea
}


code:
/* Determine a canonical name for the current locale's character encoding.

   Copyright (C) 2000-2006, 2008-2010 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License along
   with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

/* Written by Bruno Haible <bruno@clisp.org>.  */

#include <config.h>

/* Specification.  */
#include "localcharset.h"

#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#if defined __APPLE__ && defined __MACH__ && HAVE_LANGINFO_CODESET
# define DARWIN7 /* Darwin 7 or newer, i.e. MacOS X 10.3 or newer */
#endif

#if defined _WIN32 || defined __WIN32__
# define WIN32_NATIVE
#endif

#if defined __EMX__
/* Assume EMX program runs on OS/2, even if compiled under DOS.  */
# ifndef OS2
#  define OS2
# endif
#endif

#if !defined WIN32_NATIVE
# include <unistd.h>
# if HAVE_LANGINFO_CODESET
#  include <langinfo.h>
# else
#  if 0 /* see comment below */
#   include <locale.h>
#  endif
# endif
# ifdef __CYGWIN__
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
# endif
#elif defined WIN32_NATIVE
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
#if defined OS2
# define INCL_DOS
# include <os2.h>
#endif

#if ENABLE_RELOCATABLE
# include "relocatable.h"
#else
# define relocate(pathname) (pathname)
#endif

/* Get LIBDIR.  */
#ifndef LIBDIR
# include "configmake.h"
#endif

/* Define O_NOFOLLOW to 0 on platforms where it does not exist.  */
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
#endif

#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
  /* Win32, Cygwin, OS/2, DOS */
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
#endif

#ifndef DIRECTORY_SEPARATOR
# define DIRECTORY_SEPARATOR '/'
#endif

#ifndef ISSLASH
# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
#endif

#if HAVE_DECL_GETC_UNLOCKED
# undef getc
# define getc getc_unlocked
#endif

/* The following static variable is declared 'volatile' to avoid a
   possible multithread problem in the function get_charset_aliases. If we
   are running in a threaded environment, and if two threads initialize
   'charset_aliases' simultaneously, both will produce the same value,
   and everything will be ok if the two assignments to 'charset_aliases'
   are atomic. But I don't know what will happen if the two assignments mix.  */
#if __STDC__ != 1
# define volatile /* empty */
#endif
/* Pointer to the contents of the charset.alias file, if it has already been
   read, else NULL.  Its format is:
   ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0'  */
static const char * volatile charset_aliases;

/* Return a pointer to the contents of the charset.alias file.  */
static const char *
get_charset_aliases (void)
{
  const char *cp;

  cp = charset_aliases;
  if (cp == NULL)
    {
#if !(defined DARWIN7 || defined VMS || defined WIN32_NATIVE || defined __CYGWIN__)
      const char *dir;
      const char *base = "charset.alias";
      char *file_name;

      /* Make it possible to override the charset.alias location.  This is
         necessary for running the testsuite before "make install".  */
      dir = getenv ("CHARSETALIASDIR");
      if (dir == NULL || dir[0] == '\0')
        dir = relocate (LIBDIR);

      /* Concatenate dir and base into freshly allocated file_name.  */
      {
        size_t dir_len = strlen (dir);
        size_t base_len = strlen (base);
        int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
        file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
        if (file_name != NULL)
          {
            memcpy (file_name, dir, dir_len);
            if (add_slash)
              file_name[dir_len] = DIRECTORY_SEPARATOR;
            memcpy (file_name + dir_len + add_slash, base, base_len + 1);
          }
      }

      if (file_name == NULL)
        /* Out of memory.  Treat the file as empty.  */
        cp = "";
      else
        {
          int fd;

          /* Open the file.  Reject symbolic links on platforms that support
             O_NOFOLLOW.  This is a security feature.  Without it, an attacker
             could retrieve parts of the contents (namely, the tail of the
             first line that starts with "* ") of an arbitrary file by placing
             a symbolic link to that file under the name "charset.alias" in
             some writable directory and defining the environment variable
             CHARSETALIASDIR to point to that directory.  */
          fd = open (file_name,
                     O_RDONLY | (HAVE_WORKING_O_NOFOLLOW ? O_NOFOLLOW : 0));
          if (fd < 0)
            /* File not found.  Treat it as empty.  */
            cp = "";
          else
            {
              FILE *fp;

              fp = fdopen (fd, "r");
              if (fp == NULL)
                {
                  /* Out of memory.  Treat the file as empty.  */
                  close (fd);
                  cp = "";
                }
              else
                {
                  /* Parse the file's contents.  */
                  char *res_ptr = NULL;
                  size_t res_size = 0;

                  for (;;)
                    {
                      int c;
                      char buf1[50+1];
                      char buf2[50+1];
                      size_t l1, l2;
                      char *old_res_ptr;

                      c = getc (fp);
                      if (c == EOF)
                        break;
                      if (c == '\n' || c == ' ' || c == '\t')
                        continue;
                      if (c == '#')
                        {
                          /* Skip comment, to end of line.  */
                          do
                            c = getc (fp);
                          while (!(c == EOF || c == '\n'));
                          if (c == EOF)
                            break;
                          continue;
                        }
                      ungetc (c, fp);
                      if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
                        break;
                      l1 = strlen (buf1);
                      l2 = strlen (buf2);
                      old_res_ptr = res_ptr;
                      if (res_size == 0)
                        {
                          res_size = l1 + 1 + l2 + 1;
                          res_ptr = (char *) malloc (res_size + 1);
                        }
                      else
                        {
                          res_size += l1 + 1 + l2 + 1;
                          res_ptr = (char *) realloc (res_ptr, res_size + 1);
                        }
                      if (res_ptr == NULL)
                        {
                          /* Out of memory. */
                          res_size = 0;
                          if (old_res_ptr != NULL)
                            free (old_res_ptr);
                          break;
                        }
                      strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
                      strcpy (res_ptr + res_size - (l2 + 1), buf2);
                    }
                  fclose (fp);
                  if (res_size == 0)
                    cp = "";
                  else
                    {
                      *(res_ptr + res_size) = '\0';
                      cp = res_ptr;
                    }
                }
            }

          free (file_name);
        }

#else

# if defined DARWIN7
      /* To avoid the trouble of installing a file that is shared by many
         GNU packages -- many packaging systems have problems with this --,
         simply inline the aliases here.  */
      cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
           "ISO8859-2" "\0" "ISO-8859-2" "\0"
           "ISO8859-4" "\0" "ISO-8859-4" "\0"
           "ISO8859-5" "\0" "ISO-8859-5" "\0"
           "ISO8859-7" "\0" "ISO-8859-7" "\0"
           "ISO8859-9" "\0" "ISO-8859-9" "\0"
           "ISO8859-13" "\0" "ISO-8859-13" "\0"
           "ISO8859-15" "\0" "ISO-8859-15" "\0"
           "KOI8-R" "\0" "KOI8-R" "\0"
           "KOI8-U" "\0" "KOI8-U" "\0"
           "CP866" "\0" "CP866" "\0"
           "CP949" "\0" "CP949" "\0"
           "CP1131" "\0" "CP1131" "\0"
           "CP1251" "\0" "CP1251" "\0"
           "eucCN" "\0" "GB2312" "\0"
           "GB2312" "\0" "GB2312" "\0"
           "eucJP" "\0" "EUC-JP" "\0"
           "eucKR" "\0" "EUC-KR" "\0"
           "Big5" "\0" "BIG5" "\0"
           "Big5HKSCS" "\0" "BIG5-HKSCS" "\0"
           "GBK" "\0" "GBK" "\0"
           "GB18030" "\0" "GB18030" "\0"
           "SJIS" "\0" "SHIFT_JIS" "\0"
           "ARMSCII-8" "\0" "ARMSCII-8" "\0"
           "PT154" "\0" "PT154" "\0"
         /*"ISCII-DEV" "\0" "?" "\0"*/
           "*" "\0" "UTF-8" "\0";
# endif

# if defined VMS
      /* To avoid the troubles of an extra file charset.alias_vms in the
         sources of many GNU packages, simply inline the aliases here.  */
      /* The list of encodings is taken from the OpenVMS 7.3-1 documentation
         "Compaq C Run-Time Library Reference Manual for OpenVMS systems"
         section 10.7 "Handling Different Character Sets".  */
      cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
           "ISO8859-2" "\0" "ISO-8859-2" "\0"
           "ISO8859-5" "\0" "ISO-8859-5" "\0"
           "ISO8859-7" "\0" "ISO-8859-7" "\0"
           "ISO8859-8" "\0" "ISO-8859-8" "\0"
           "ISO8859-9" "\0" "ISO-8859-9" "\0"
           /* Japanese */
           "eucJP" "\0" "EUC-JP" "\0"
           "SJIS" "\0" "SHIFT_JIS" "\0"
           "DECKANJI" "\0" "DEC-KANJI" "\0"
           "SDECKANJI" "\0" "EUC-JP" "\0"
           /* Chinese */
           "eucTW" "\0" "EUC-TW" "\0"
           "DECHANYU" "\0" "DEC-HANYU" "\0"
           "DECHANZI" "\0" "GB2312" "\0"
           /* Korean */
           "DECKOREAN" "\0" "EUC-KR" "\0";
# endif

# if defined WIN32_NATIVE || defined __CYGWIN__
      /* To avoid the troubles of installing a separate file in the same
         directory as the DLL and of retrieving the DLL's directory at
         runtime, simply inline the aliases here.  */

      cp = "CP936" "\0" "GBK" "\0"
           "CP1361" "\0" "JOHAB" "\0"
           "CP20127" "\0" "ASCII" "\0"
           "CP20866" "\0" "KOI8-R" "\0"
           "CP20936" "\0" "GB2312" "\0"
           "CP21866" "\0" "KOI8-RU" "\0"
           "CP28591" "\0" "ISO-8859-1" "\0"
           "CP28592" "\0" "ISO-8859-2" "\0"
           "CP28593" "\0" "ISO-8859-3" "\0"
           "CP28594" "\0" "ISO-8859-4" "\0"
           "CP28595" "\0" "ISO-8859-5" "\0"
           "CP28596" "\0" "ISO-8859-6" "\0"
           "CP28597" "\0" "ISO-8859-7" "\0"
           "CP28598" "\0" "ISO-8859-8" "\0"
           "CP28599" "\0" "ISO-8859-9" "\0"
           "CP28605" "\0" "ISO-8859-15" "\0"
           "CP38598" "\0" "ISO-8859-8" "\0"
           "CP51932" "\0" "EUC-JP" "\0"
           "CP51936" "\0" "GB2312" "\0"
           "CP51949" "\0" "EUC-KR" "\0"
           "CP51950" "\0" "EUC-TW" "\0"
           "CP54936" "\0" "GB18030" "\0"
           "CP65001" "\0" "UTF-8" "\0";
# endif
#endif

      charset_aliases = cp;
    }

  return cp;
}

/* Determine the current locale's character encoding, and canonicalize it
   into one of the canonical names listed in config.charset.
   The result must not be freed; it is statically allocated.
   If the canonical name cannot be determined, the result is a non-canonical
   name.  */

#ifdef STATIC
STATIC
#endif
const char *
locale_charset (void)
{
  const char *codeset;
  const char *aliases;

#if !(defined WIN32_NATIVE || defined OS2)

# if HAVE_LANGINFO_CODESET

  /* Most systems support nl_langinfo (CODESET) nowadays.  */
  codeset = nl_langinfo (CODESET);

#  ifdef __CYGWIN__
  /* Cygwin < 1.7 does not have locales.  nl_langinfo (CODESET) always
     returns "US-ASCII".  Return the suffix of the locale name from the
     environment variables (if present) or the codepage as a number.  */
  if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0)
    {
      const char *locale;
      static char buf[2 + 10 + 1];

      locale = getenv ("LC_ALL");
      if (locale == NULL || locale[0] == '\0')
        {
          locale = getenv ("LC_CTYPE");
          if (locale == NULL || locale[0] == '\0')
            locale = getenv ("LANG");
        }
      if (locale != NULL && locale[0] != '\0')
        {
          /* If the locale name contains an encoding after the dot, return
             it.  */
          const char *dot = strchr (locale, '.');

          if (dot != NULL)
            {
              const char *modifier;

              dot++;
              /* Look for the possible @... trailer and remove it, if any.  */
              modifier = strchr (dot, '@');
              if (modifier == NULL)
                return dot;
              if (modifier - dot < sizeof (buf))
                {
                  memcpy (buf, dot, modifier - dot);
                  buf [modifier - dot] = '\0';
                  return buf;
                }
            }
        }

      /* Woe32 has a function returning the locale's codepage as a number:
         GetACP().  This encoding is used by Cygwin, unless the user has set
         the environment variable CYGWIN=codepage:oem (which very few people
         do).
         Output directed to console windows needs to be converted (to
         GetOEMCP() if the console is using a raster font, or to
         GetConsoleOutputCP() if it is using a TrueType font).  Cygwin does
         this conversion transparently (see winsup/cygwin/fhandler_console.cc),
         converting to GetConsoleOutputCP().  This leads to correct results,
         except when SetConsoleOutputCP has been called and a raster font is
         in use.  */
      sprintf (buf, "CP%u", GetACP ());
      codeset = buf;
    }
#  endif

# else

  /* On old systems which lack it, use setlocale or getenv.  */
  const char *locale = NULL;

  /* But most old systems don't have a complete set of locales.  Some
     (like SunOS 4 or DJGPP) have only the C locale.  Therefore we don't
     use setlocale here; it would return "C" when it doesn't support the
     locale name the user has set.  */
#  if 0
  locale = setlocale (LC_CTYPE, NULL);
#  endif
  if (locale == NULL || locale[0] == '\0')
    {
      locale = getenv ("LC_ALL");
      if (locale == NULL || locale[0] == '\0')
        {
          locale = getenv ("LC_CTYPE");
          if (locale == NULL || locale[0] == '\0')
            locale = getenv ("LANG");
        }
    }

  /* On some old systems, one used to set locale = "iso8859_1". On others,
     you set it to "language_COUNTRY.charset". In any case, we resolve it
     through the charset.alias file.  */
  codeset = locale;

# endif

#elif defined WIN32_NATIVE

  static char buf[2 + 10 + 1];

  /* Woe32 has a function returning the locale's codepage as a number:
     GetACP().
     When the output goes to a console window, it needs to be provided in
     GetOEMCP() encoding if the console is using a raster font, or in
     GetConsoleOutputCP() encoding if it is using a TrueType font.
     But in GUI programs and for output sent to files and pipes, GetACP()
     encoding is the best bet.  */
  sprintf (buf, "CP%u", GetACP ());
  codeset = buf;

#elif defined OS2

  const char *locale;
  static char buf[2 + 10 + 1];
  ULONG cp[3];
  ULONG cplen;

  /* Allow user to override the codeset, as set in the operating system,
     with standard language environment variables.  */
  locale = getenv ("LC_ALL");
  if (locale == NULL || locale[0] == '\0')
    {
      locale = getenv ("LC_CTYPE");
      if (locale == NULL || locale[0] == '\0')
        locale = getenv ("LANG");
    }
  if (locale != NULL && locale[0] != '\0')
    {
      /* If the locale name contains an encoding after the dot, return it.  */
      const char *dot = strchr (locale, '.');

      if (dot != NULL)
        {
          const char *modifier;

          dot++;
          /* Look for the possible @... trailer and remove it, if any.  */
          modifier = strchr (dot, '@');
          if (modifier == NULL)
            return dot;
          if (modifier - dot < sizeof (buf))
            {
              memcpy (buf, dot, modifier - dot);
              buf [modifier - dot] = '\0';
              return buf;
            }
        }

      /* Resolve through the charset.alias file.  */
      codeset = locale;
    }
  else
    {
      /* OS/2 has a function returning the locale's codepage as a number.  */
      if (DosQueryCp (sizeof (cp), cp, &cplen))
        codeset = "";
      else
        {
          sprintf (buf, "CP%u", cp[0]);
          codeset = buf;
        }
    }

#endif

  if (codeset == NULL)
    /* The canonical name cannot be determined.  */
    codeset = "";

  /* Resolve alias. */
  for (aliases = get_charset_aliases ();
       *aliases != '\0';
       aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
    if (strcmp (codeset, aliases) == 0
        || (aliases[0] == '*' && aliases[1] == '\0'))
      {
        codeset = aliases + strlen (aliases) + 1;
        break;
      }

  /* Don't return an empty string.  GNU libc and GNU libiconv interpret
     the empty string as denoting "the locale's character encoding",
     thus GNU libiconv would call this function a second time.  */
  if (codeset[0] == '\0')
    codeset = "ASCII";

  return codeset;
}


code:
/* Determine a canonical name for the current locale's character encoding.
   Copyright (C) 2000-2003, 2009-2010 Free Software Foundation, Inc.
   This file is part of the GNU CHARSET Library.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License along
   with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#ifndef _LOCALCHARSET_H
#define _LOCALCHARSET_H

#ifdef __cplusplus
extern "C" {
#endif

/* Determine the current locale's character encoding, and canonicalize it
   into one of the canonical names listed in config.charset.
   The result must not be freed; it is statically allocated.
   If the canonical name cannot be determined, the result is a non-canonical
   name.  */
extern const char * locale_charset (void);

#ifdef __cplusplus
}
#endif

#endif /* _LOCALCHARSET_H */


code:
/* A POSIX <locale.h>.
   Copyright (C) 2007-2010 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#ifndef _GL_LOCALE_H

#if __GNUC__ >= 3
@PRAGMA_SYSTEM_HEADER@
#endif

/* The include_next requires a split double-inclusion guard.  */
#@INCLUDE_NEXT@ @NEXT_LOCALE_H@

#ifndef _GL_LOCALE_H
#define _GL_LOCALE_H

/* NetBSD 5.0 mis-defines NULL.  */
#include <stddef.h>

/* MacOS X 10.5 defines the locale_t type in <xlocale.h>.  */
#if @HAVE_XLOCALE_H@
# include <xlocale.h>
#endif

/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */

/* The definition of _GL_ARG_NONNULL is copied here.  */

/* The definition of _GL_WARN_ON_USE is copied here.  */

/* The LC_MESSAGES locale category is specified in POSIX, but not in ISO C.
   On systems that don't define it, use the same value as GNU libintl.  */
#if !defined LC_MESSAGES
# define LC_MESSAGES 1729
#endif

#if @GNULIB_DUPLOCALE@
# if @REPLACE_DUPLOCALE@
#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#   undef duplocale
#   define duplocale rpl_duplocale
#  endif
_GL_FUNCDECL_RPL (duplocale, locale_t, (locale_t locale) _GL_ARG_NONNULL ((1)));
_GL_CXXALIAS_RPL (duplocale, locale_t, (locale_t locale));
# else
#  if @HAVE_DUPLOCALE@
_GL_CXXALIAS_SYS (duplocale, locale_t, (locale_t locale));
#  endif
# endif
# if @HAVE_DUPLOCALE@
_GL_CXXALIASWARN (duplocale);
# endif
#elif defined GNULIB_POSIXCHECK
# undef duplocale
# if HAVE_RAW_DECL_DUPLOCALE
_GL_WARN_ON_USE (duplocale, "duplocale is buggy on some glibc systems - "
                 "use gnulib module duplocale for portability");
# endif
#endif

#endif /* _GL_LOCALE_H */
#endif /* _GL_LOCALE_H */


code:
/* Work around a bug of lstat on some systems

   Copyright (C) 1997-2006, 2008-2010 Free Software Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/* written by Jim Meyering */

#include <config.h>

#if !HAVE_LSTAT
/* On systems that lack symlinks, our replacement <sys/stat.h> already
   defined lstat as stat, so there is nothing further to do other than
   avoid an empty file.  */
typedef int dummy;
#else /* HAVE_LSTAT */

/* Get the original definition of lstat.  It might be defined as a macro.  */
# define __need_system_sys_stat_h
# include <sys/types.h>
# include <sys/stat.h>
# undef __need_system_sys_stat_h

static inline int
orig_lstat (const char *filename, struct stat *buf)
{
  return lstat (filename, buf);
}

/* Specification.  */
# include <sys/stat.h>

# include <string.h>
# include <errno.h>

/* lstat works differently on Linux and Solaris systems.  POSIX (see
   `pathname resolution' in the glossary) requires that programs like
   `ls' take into consideration the fact that FILE has a trailing slash
   when FILE is a symbolic link.  On Linux and Solaris 10 systems, the
   lstat function already has the desired semantics (in treating
   `lstat ("symlink/", sbuf)' just like `lstat ("symlink/.", sbuf)',
   but on Solaris 9 and earlier it does not.

   If FILE has a trailing slash and specifies a symbolic link,
   then use stat() to get more info on the referent of FILE.
   If the referent is a non-directory, then set errno to ENOTDIR
   and return -1.  Otherwise, return stat's result.  */

int
rpl_lstat (const char *file, struct stat *sbuf)
{
  size_t len;
  int lstat_result = orig_lstat (file, sbuf);

  if (lstat_result != 0)
    return lstat_result;

  /* This replacement file can blindly check against '/' rather than
     using the ISSLASH macro, because all platforms with '\\' either
     lack symlinks (mingw) or have working lstat (cygwin) and thus do
     not compile this file.  0 len should have already been filtered
     out above, with a failure return of ENOENT.  */
  len = strlen (file);
  if (file[len - 1] != '/' || S_ISDIR (sbuf->st_mode))
    return 0;

  /* At this point, a trailing slash is only permitted on
     symlink-to-dir; but it should have found information on the
     directory, not the symlink.  Call stat() to get info about the
     link's referent.  Our replacement stat guarantees valid results,
     even if the symlink is not pointing to a directory.  */
  if (!S_ISLNK (sbuf->st_mode))
    {
      errno = ENOTDIR;
      return -1;
    }
  return stat (file, sbuf);
}

#endif /* HAVE_LSTAT */


code:
/* malloc() function that is glibc compatible.

   Copyright (C) 1997-1998, 2006-2007, 2009-2010 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

/* written by Jim Meyering and Bruno Haible */

#include <config.h>
/* Only the AC_FUNC_MALLOC macro defines 'malloc' already in config.h.  */
#ifdef malloc
# define NEED_MALLOC_GNU
# undef malloc
#endif

/* Specification.  */
#include <stdlib.h>

#include <errno.h>

/* Call the system's malloc below.  */
#undef malloc

/* Allocate an N-byte block of memory from the heap.
   If N is zero, allocate a 1-byte block.  */

void *
rpl_malloc (size_t n)
{
  void *result;

#ifdef NEED_MALLOC_GNU
  if (n == 0)
    n = 1;
#endif

  result = malloc (n);

#if !HAVE_MALLOC_POSIX
  if (result == NULL)
    errno = ENOMEM;
#endif

  return result;
}


code:
/* Safe automatic memory allocation.
   Copyright (C) 2003, 2006-2007, 2009-2010 Free Software Foundation, Inc.
   Written by Bruno Haible <bruno@clisp.org>, 2003.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#include <config.h>

/* Specification.  */
#include "malloca.h"

/* The speed critical point in this file is freea() applied to an alloca()
   result: it must be fast, to match the speed of alloca().  The speed of
   mmalloca() and freea() in the other case are not critical, because they
   are only invoked for big memory sizes.  */

#if HAVE_ALLOCA

/* Store the mmalloca() results in a hash table.  This is needed to reliably
   distinguish a mmalloca() result and an alloca() result.

   Although it is possible that the same pointer is returned by alloca() and
   by mmalloca() at different times in the same application, it does not lead
   to a bug in freea(), because:
     - Before a pointer returned by alloca() can point into malloc()ed memory,
       the function must return, and once this has happened the programmer must
       not call freea() on it anyway.
     - Before a pointer returned by mmalloca() can point into the stack, it
       must be freed.  The only function that can free it is freea(), and
       when freea() frees it, it also removes it from the hash table.  */

#define MAGIC_NUMBER 0x1415fb4a
#define MAGIC_SIZE sizeof (int)
/* This is how the header info would look like without any alignment
   considerations.  */
struct preliminary_header { void *next; char room[MAGIC_SIZE]; };
/* But the header's size must be a multiple of sa_alignment_max.  */
#define HEADER_SIZE \
  (((sizeof (struct preliminary_header) + sa_alignment_max - 1) / sa_alignment_max) * sa_alignment_max)
struct header { void *next; char room[HEADER_SIZE - sizeof (struct preliminary_header) + MAGIC_SIZE]; };
/* Verify that HEADER_SIZE == sizeof (struct header).  */
typedef int verify1[2 * (HEADER_SIZE == sizeof (struct header)) - 1];
/* We make the hash table quite big, so that during lookups the probability
   of empty hash buckets is quite high.  There is no need to make the hash
   table resizable, because when the hash table gets filled so much that the
   lookup becomes slow, it means that the application has memory leaks.  */
#define HASH_TABLE_SIZE 257
static void * mmalloca_results[HASH_TABLE_SIZE];

#endif

void *
mmalloca (size_t n)
{
#if HAVE_ALLOCA
  /* Allocate one more word, that serves as an indicator for malloc()ed
     memory, so that freea() of an alloca() result is fast.  */
  size_t nplus = n + HEADER_SIZE;

  if (nplus >= n)
    {
      char *p = (char *) malloc (nplus);

      if (p != NULL)
        {
          size_t slot;

          p += HEADER_SIZE;

          /* Put a magic number into the indicator word.  */
          ((int *) p)[-1] = MAGIC_NUMBER;

          /* Enter p into the hash table.  */
          slot = (unsigned long) p % HASH_TABLE_SIZE;
          ((struct header *) (p - HEADER_SIZE))->next = mmalloca_results[slot];
          mmalloca_results[slot] = p;

          return p;
        }
    }
  /* Out of memory.  */
  return NULL;
#else
# if !MALLOC_0_IS_NONNULL
  if (n == 0)
    n = 1;
# endif
  return malloc (n);
#endif
}

#if HAVE_ALLOCA
void
freea (void *p)
{
  /* mmalloca() may have returned NULL.  */
  if (p != NULL)
    {
      /* Attempt to quickly distinguish the mmalloca() result - which has
         a magic indicator word - and the alloca() result - which has an
         uninitialized indicator word.  It is for this test that sa_increment
         additional bytes are allocated in the alloca() case.  */
      if (((int *) p)[-1] == MAGIC_NUMBER)
        {
          /* Looks like a mmalloca() result.  To see whether it really is one,
             perform a lookup in the hash table.  */
          size_t slot = (unsigned long) p % HASH_TABLE_SIZE;
          void **chain = &mmalloca_results[slot];
          for (; *chain != NULL;)
            {
              if (*chain == p)
                {
                  /* Found it.  Remove it from the hash table and free it.  */
                  char *p_begin = (char *) p - HEADER_SIZE;
                  *chain = ((struct header *) p_begin)->next;
                  free (p_begin);
                  return;
                }
              chain = &((struct header *) ((char *) *chain - HEADER_SIZE))->next;
            }
        }
      /* At this point, we know it was not a mmalloca() result.  */
    }
}
#endif


code:
/* Safe automatic memory allocation.
   Copyright (C) 2003-2007, 2009-2010 Free Software Foundation, Inc.
   Written by Bruno Haible <bruno@clisp.org>, 2003.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#ifndef _MALLOCA_H
#define _MALLOCA_H

#include <alloca.h>
#include <stddef.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

/* safe_alloca(N) is equivalent to alloca(N) when it is safe to call
   alloca(N); otherwise it returns NULL.  It either returns N bytes of
   memory allocated on the stack, that lasts until the function returns,
   or NULL.
   Use of safe_alloca should be avoided:
     - inside arguments of function calls - undefined behaviour,
     - in inline functions - the allocation may actually last until the
       calling function returns.
*/
#if HAVE_ALLOCA
/* The OS usually guarantees only one guard page at the bottom of the stack,
   and a page size can be as small as 4096 bytes.  So we cannot safely
   allocate anything larger than 4096 bytes.  Also care for the possibility
   of a few compiler-allocated temporary stack slots.
   This must be a macro, not an inline function.  */
# define safe_alloca(N) ((N) < 4032 ? alloca (N) : NULL)
#else
# define safe_alloca(N) ((void) (N), NULL)
#endif

/* malloca(N) is a safe variant of alloca(N).  It allocates N bytes of
   memory allocated on the stack, that must be freed using freea() before
   the function returns.  Upon failure, it returns NULL.  */
#if HAVE_ALLOCA
# define malloca(N) \
  ((N) < 4032 - sa_increment                                        \
   ? (void *) ((char *) alloca ((N) + sa_increment) + sa_increment) \
   : mmalloca (N))
#else
# define malloca(N) \
  mmalloca (N)
#endif
extern void * mmalloca (size_t n);

/* Free a block of memory allocated through malloca().  */
#if HAVE_ALLOCA
extern void freea (void *p);
#else
# define freea free
#endif

/* nmalloca(N,S) is an overflow-safe variant of malloca (N * S).
   It allocates an array of N objects, each with S bytes of memory,
   on the stack.  S must be positive and N must be nonnegative.
   The array must be freed using freea() before the function returns.  */
#if 1
/* Cf. the definition of xalloc_oversized.  */
# define nmalloca(n, s) \
    ((n) > (size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) \
     ? NULL \
     : malloca ((n) * (s)))
#else
extern void * nmalloca (size_t n, size_t s);
#endif

#ifdef __cplusplus
}
#endif

/* ------------------- Auxiliary, non-public definitions ------------------- */

/* Determine the alignment of a type at compile time.  */
#if defined __GNUC__
# define sa_alignof __alignof__
#elif defined __cplusplus
  template <class type> struct sa_alignof_helper { char __slot1; type __slot2; };
# define sa_alignof(type) offsetof (sa_alignof_helper<type>, __slot2)
#elif defined __hpux
  /* Work around a HP-UX 10.20 cc bug with enums constants defined as offsetof
     values.  */
# define sa_alignof(type) (sizeof (type) <= 4 ? 4 : 8)
#elif defined _AIX
  /* Work around an AIX 3.2.5 xlc bug with enums constants defined as offsetof
     values.  */
# define sa_alignof(type) (sizeof (type) <= 4 ? 4 : 8)
#else
# define sa_alignof(type) offsetof (struct { char __slot1; type __slot2; }, __slot2)
#endif

enum
{
/* The desired alignment of memory allocations is the maximum alignment
   among all elementary types.  */
  sa_alignment_long = sa_alignof (long),
  sa_alignment_double = sa_alignof (double),
#if HAVE_LONG_LONG_INT
  sa_alignment_longlong = sa_alignof (long long),
#endif
  sa_alignment_longdouble = sa_alignof (long double),
  sa_alignment_max = ((sa_alignment_long - 1) | (sa_alignment_double - 1)
#if HAVE_LONG_LONG_INT
                      | (sa_alignment_longlong - 1)
#endif
                      | (sa_alignment_longdouble - 1)
                     ) + 1,
/* The increment that guarantees room for a magic word must be >= sizeof (int)
   and a multiple of sa_alignment_max.  */
  sa_increment = ((sizeof (int) + sa_alignment_max - 1) / sa_alignment_max) * sa_alignment_max
};

#endif /* _MALLOCA_H */


code:
# Suppress a valgrind message about use of uninitialized memory in freea().
# This use is OK because it provides only a speedup.
{
    freea
    Memcheck:Cond
    fun:freea
}


code:
/* Recognize multibyte character.
   Copyright (C) 1999-2000, 2008-2010 Free Software Foundation, Inc.
   Written by Bruno Haible <bruno@clisp.org>, 2008.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#include <config.h>

/* Specification.  */
#include <wchar.h>

static mbstate_t internal_state;

size_t
mbrlen (const char *s, size_t n, mbstate_t *ps)
{
  if (ps == NULL)
    ps = &internal_state;
  return mbrtowc (NULL, s, n, ps);
}


code:
/* Convert multibyte character to wide character.
   Copyright (C) 1999-2002, 2005-2010 Free Software Foundation, Inc.
   Written by Bruno Haible <bruno@clisp.org>, 2008.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#include <config.h>

/* Specification.  */
#include <wchar.h>

#if GNULIB_defined_mbstate_t
/* Implement mbrtowc() on top of mbtowc().  */

# include <errno.h>
# include <stdlib.h>

# include "localcharset.h"
# include "streq.h"
# include "verify.h"

verify (sizeof (mbstate_t) >= 4);

static char internal_state[4];

size_t
mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
{
  char *pstate = (char *)ps;

  if (pstate == NULL)
    pstate = internal_state;

  if (s == NULL)
    {
      pwc = NULL;
      s = "";
      n = 1;
    }

  if (n == 0)
    return (size_t)(-2);

  /* Here n > 0.  */
  {
    size_t nstate = pstate[0];
    char buf[4];
    const char *p;
    size_t m;

    switch (nstate)
      {
      case 0:
        p = s;
        m = n;
        break;
      case 3:
        buf[2] = pstate[3];
        /*FALLTHROUGH*/
      case 2:
        buf[1] = pstate[2];
        /*FALLTHROUGH*/
      case 1:
        buf[0] = pstate[1];
        p = buf;
        m = nstate;
        buf[m++] = s[0];
        if (n >= 2 && m < 4)
          {
            buf[m++] = s[1];
            if (n >= 3 && m < 4)
              buf[m++] = s[2];
          }
        break;
      default:
        errno = EINVAL;
        return (size_t)(-1);
      }

    /* Here m > 0.  */

# if __GLIBC__
    /* Work around bug <http://sourceware.org/bugzilla/show_bug.cgi?id=9674> */
    mbtowc (NULL, NULL, 0);
# endif
    {
      int res = mbtowc (pwc, p, m);

      if (res >= 0)
        {
          if (pwc != NULL && ((*pwc == 0) != (res == 0)))
            abort ();
          if (nstate >= (res > 0 ? res : 1))
            abort ();
          res -= nstate;
          pstate[0] = 0;
          return res;
        }

      /* mbtowc does not distinguish between invalid and incomplete multibyte
         sequences.  But mbrtowc needs to make this distinction.
         There are two possible approaches:
           - Use iconv() and its return value.
           - Use built-in knowledge about the possible encodings.
         Given the low quality of implementation of iconv() on the systems that
         lack mbrtowc(), we use the second approach.
         The possible encodings are:
           - 8-bit encodings,
           - EUC-JP, EUC-KR, GB2312, EUC-TW, BIG5, GB18030, SJIS,
           - UTF-8.
         Use specialized code for each.  */
      if (m >= 4 || m >= MB_CUR_MAX)
        goto invalid;
      /* Here MB_CUR_MAX > 1 and 0 < m < 4.  */
      {
        const char *encoding = locale_charset ();

        if (STREQ (encoding, "UTF-8", 'U', 'T', 'F', '-', '8', 0, 0, 0, 0))
          {
            /* Cf. unistr/u8-mblen.c.  */
            unsigned char c = (unsigned char) p[0];

            if (c >= 0xc2)
              {
                if (c < 0xe0)
                  {
                    if (m == 1)
                      goto incomplete;
                  }
                else if (c < 0xf0)
                  {
                    if (m == 1)
                      goto incomplete;
                    if (m == 2)
                      {
                        unsigned char c2 = (unsigned char) p[1];

                        if ((c2 ^ 0x80) < 0x40
                            && (c >= 0xe1 || c2 >= 0xa0)
                            && (c != 0xed || c2 < 0xa0))
                          goto incomplete;
                      }
                  }
                else if (c <= 0xf4)
                  {
                    if (m == 1)
                      goto incomplete;
                    else /* m == 2 || m == 3 */
                      {
                        unsigned char c2 = (unsigned char) p[1];

                        if ((c2 ^ 0x80) < 0x40
                            && (c >= 0xf1 || c2 >= 0x90)
                            && (c < 0xf4 || (c == 0xf4 && c2 < 0x90)))
                          {
                            if (m == 2)
                              goto incomplete;
                            else /* m == 3 */
                              {
                                unsigned char c3 = (unsigned char) p[2];

                                if ((c3 ^ 0x80) < 0x40)
                                  goto incomplete;
                              }
                          }
                      }
                  }
              }
            goto invalid;
          }

        /* As a reference for this code, you can use the GNU libiconv
           implementation.  Look for uses of the RET_TOOFEW macro.  */

        if (STREQ (encoding, "EUC-JP", 'E', 'U', 'C', '-', 'J', 'P', 0, 0, 0))
          {
            if (m == 1)
              {
                unsigned char c = (unsigned char) p[0];

                if ((c >= 0xa1 && c < 0xff) || c == 0x8e || c == 0x8f)
                  goto incomplete;
              }
            if (m == 2)
              {
                unsigned char c = (unsigned char) p[0];

                if (c == 0x8f)
                  {
                    unsigned char c2 = (unsigned char) p[1];

                    if (c2 >= 0xa1 && c2 < 0xff)
                      goto incomplete;
                  }
              }
            goto invalid;
          }
        if (STREQ (encoding, "EUC-KR", 'E', 'U', 'C', '-', 'K', 'R', 0, 0, 0)
            || STREQ (encoding, "GB2312", 'G', 'B', '2', '3', '1', '2', 0, 0, 0)
            || STREQ (encoding, "BIG5", 'B', 'I', 'G', '5', 0, 0, 0, 0, 0))
          {
            if (m == 1)
              {
                unsigned char c = (unsigned char) p[0];

                if (c >= 0xa1 && c < 0xff)
                  goto incomplete;
              }
            goto invalid;
          }
        if (STREQ (encoding, "EUC-TW", 'E', 'U', 'C', '-', 'T', 'W', 0, 0, 0))
          {
            if (m == 1)
              {
                unsigned char c = (unsigned char) p[0];

                if ((c >= 0xa1 && c < 0xff) || c == 0x8e)
                  goto incomplete;
              }
            else /* m == 2 || m == 3 */
              {
                unsigned char c = (unsigned char) p[0];

                if (c == 0x8e)
                  goto incomplete;
              }
            goto invalid;
          }
        if (STREQ (encoding, "GB18030", 'G', 'B', '1', '8', '0', '3', '0', 0, 0))
          {
            if (m == 1)
              {
                unsigned char c = (unsigned char) p[0];

                if ((c >= 0x90 && c <= 0xe3) || (c >= 0xf8 && c <= 0xfe))
                  goto incomplete;
              }
            else /* m == 2 || m == 3 */
              {
                unsigned char c = (unsigned char) p[0];

                if (c >= 0x90 && c <= 0xe3)
                  {
                    unsigned char c2 = (unsigned char) p[1];

                    if (c2 >= 0x30 && c2 <= 0x39)
                      {
                        if (m == 2)
                          goto incomplete;
                        else /* m == 3 */
                          {
                            unsigned char c3 = (unsigned char) p[2];

                            if (c3 >= 0x81 && c3 <= 0xfe)
                              goto incomplete;
                          }
                      }
                  }
              }
            goto invalid;
          }
        if (STREQ (encoding, "SJIS", 'S', 'J', 'I', 'S', 0, 0, 0, 0, 0))
          {
            if (m == 1)
              {
                unsigned char c = (unsigned char) p[0];

                if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)
                    || (c >= 0xf0 && c <= 0xf9))
                  goto incomplete;
              }
            goto invalid;
          }

        /* An unknown multibyte encoding.  */
        goto incomplete;
      }

     incomplete:
      {
        size_t k = nstate;
        /* Here 0 <= k < m < 4.  */
        pstate[++k] = s[0];
        if (k < m)
          {
            pstate[++k] = s[1];
            if (k < m)
              pstate[++k] = s[2];
          }
        if (k != m)
          abort ();
      }
      pstate[0] = m;
      return (size_t)(-2);

     invalid:
      errno = EILSEQ;
      /* The conversion state is undefined, says POSIX.  */
      return (size_t)(-1);
    }
  }
}

#else
/* Override the system's mbrtowc() function.  */

# undef mbrtowc

size_t
rpl_mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
{
# if MBRTOWC_NULL_ARG_BUG || MBRTOWC_RETVAL_BUG
  if (s == NULL)
    {
      pwc = NULL;
      s = "";
      n = 1;
    }
# endif

# if MBRTOWC_RETVAL_BUG
  {
    static mbstate_t internal_state;

    /* Override mbrtowc's internal state.  We can not call mbsinit() on the
       hidden internal state, but we can call it on our variable.  */
    if (ps == NULL)
      ps = &internal_state;

    if (!mbsinit (ps))
      {
        /* Parse the rest of the multibyte character byte for byte.  */
        size_t count = 0;
        for (; n > 0; s++, n--)
          {
            wchar_t wc;
            size_t ret = mbrtowc (&wc, s, 1, ps);

            if (ret == (size_t)(-1))
              return (size_t)(-1);
            count++;
            if (ret != (size_t)(-2))
              {
                /* The multibyte character has been completed.  */
                if (pwc != NULL)
                  *pwc = wc;
                return (wc == 0 ? 0 : count);
              }
          }
        return (size_t)(-2);
      }
  }
# endif

# if MBRTOWC_NUL_RETVAL_BUG
  {
    wchar_t wc;
    size_t ret = mbrtowc (&wc, s, n, ps);

    if (ret != (size_t)(-1) && ret != (size_t)(-2))
      {
        if (pwc != NULL)
          *pwc = wc;
        if (wc == 0)
          ret = 0;
      }
    return ret;
  }
# else
  return mbrtowc (pwc, s, n, ps);
# endif
}

#endif


code:
/* Test for initial conversion state.
   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
   Written by Bruno Haible <bruno@clisp.org>, 2008.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#include <config.h>

/* Specification.  */
#include <wchar.h>

#include "verify.h"

/* Platforms that lack mbsinit() also lack mbrlen(), mbrtowc(), mbsrtowcs()
   and wcrtomb(), wcsrtombs().
   We assume that
     - sizeof (mbstate_t) >= 4,
     - only stateless encodings are supported (such as UTF-8 and EUC-JP, but
       not ISO-2022 variants),
     - for each encoding, the number of bytes for a wide character is <= 4.
       (This maximum is attained for UTF-8, GB18030, EUC-TW.)
   We define the meaning of mbstate_t as follows:
     - In mb -> wc direction, mbstate_t's first byte contains the number of
       buffered bytes (in the range 0..3), followed by up to 3 buffered bytes.
     - In wc -> mb direction, mbstate_t contains no information. In other
       words, it is always in the initial state.  */

verify (sizeof (mbstate_t) >= 4);

int
mbsinit (const mbstate_t *ps)
{
  const char *pstate = (const char *)ps;

  return pstate[0] == 0;
}


code:
/* Copyright (C) 1991, 1993, 1996-1997, 1999-2000, 2003-2004, 2006, 2008-2010
   Free Software Foundation, Inc.

   Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
   with help from Dan Sahlin (dan@sics.se) and
   commentary by Jim Blandy (jimb@ai.mit.edu);
   adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
   and implemented by Roland McGrath (roland@ai.mit.edu).

NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@prep.ai.mit.edu.

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or any
later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#ifndef _LIBC
# include <config.h>
#endif

#include <string.h>

#include <stddef.h>

#if defined _LIBC
# include <memcopy.h>
#else
# define reg_char char
#endif

#include <limits.h>

#if HAVE_BP_SYM_H || defined _LIBC
# include <bp-sym.h>
#else
# define BP_SYM(sym) sym
#endif

#undef __memchr
#ifdef _LIBC
# undef memchr
#endif

#ifndef weak_alias
# define __memchr memchr
#endif

/* Search no more than N bytes of S for C.  */
void *
__memchr (void const *s, int c_in, size_t n)
{
  /* On 32-bit hardware, choosing longword to be a 32-bit unsigned
     long instead of a 64-bit uintmax_t tends to give better
     performance.  On 64-bit hardware, unsigned long is generally 64
     bits already.  Change this typedef to experiment with
     performance.  */
  typedef unsigned long int longword;

  const unsigned char *char_ptr;
  const longword *longword_ptr;
  longword repeated_one;
  longword repeated_c;
  unsigned reg_char c;

  c = (unsigned char) c_in;

  /* Handle the first few bytes by reading one byte at a time.
     Do this until CHAR_PTR is aligned on a longword boundary.  */
  for (char_ptr = (const unsigned char *) s;
       n > 0 && (size_t) char_ptr % sizeof (longword) != 0;
       --n, ++char_ptr)
    if (*char_ptr == c)
      return (void *) char_ptr;

  longword_ptr = (const longword *) char_ptr;

  /* All these elucidatory comments refer to 4-byte longwords,
     but the theory applies equally well to any size longwords.  */

  /* Compute auxiliary longword values:
     repeated_one is a value which has a 1 in every byte.
     repeated_c has c in every byte.  */
  repeated_one = 0x01010101;
  repeated_c = c | (c << 8);
  repeated_c |= repeated_c << 16;
  if (0xffffffffU < (longword) -1)
    {
      repeated_one |= repeated_one << 31 << 1;
      repeated_c |= repeated_c << 31 << 1;
      if (8 < sizeof (longword))
        {
          size_t i;

          for (i = 64; i < sizeof (longword) * 8; i *= 2)
            {
              repeated_one |= repeated_one << i;
              repeated_c |= repeated_c << i;
            }
        }
    }

  /* Instead of the traditional loop which tests each byte, we will test a
     longword at a time.  The tricky part is testing if *any of the four*
     bytes in the longword in question are equal to c.  We first use an xor
     with repeated_c.  This reduces the task to testing whether *any of the
     four* bytes in longword1 is zero.

     We compute tmp =
       ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
     That is, we perform the following operations:
       1. Subtract repeated_one.
       2. & ~longword1.
       3. & a mask consisting of 0x80 in every byte.
     Consider what happens in each byte:
       - If a byte of longword1 is zero, step 1 and 2 transform it into 0xff,
         and step 3 transforms it into 0x80.  A carry can also be propagated
         to more significant bytes.
       - If a byte of longword1 is nonzero, let its lowest 1 bit be at
         position k (0 <= k <= 7); so the lowest k bits are 0.  After step 1,
         the byte ends in a single bit of value 0 and k bits of value 1.
         After step 2, the result is just k bits of value 1: 2^k - 1.  After
         step 3, the result is 0.  And no carry is produced.
     So, if longword1 has only non-zero bytes, tmp is zero.
     Whereas if longword1 has a zero byte, call j the position of the least
     significant zero byte.  Then the result has a zero at positions 0, ...,
     j-1 and a 0x80 at position j.  We cannot predict the result at the more
     significant bytes (positions j+1..3), but it does not matter since we
     already have a non-zero bit at position 8*j+7.

     So, the test whether any byte in longword1 is zero is equivalent to
     testing whether tmp is nonzero.  */

  while (n >= sizeof (longword))
    {
      longword longword1 = *longword_ptr ^ repeated_c;

      if ((((longword1 - repeated_one) & ~longword1)
           & (repeated_one << 7)) != 0)
        break;
      longword_ptr++;
      n -= sizeof (longword);
    }

  char_ptr = (const unsigned char *) longword_ptr;

  /* At this point, we know that either n < sizeof (longword), or one of the
     sizeof (longword) bytes starting at char_ptr is == c.  On little-endian
     machines, we could determine the first such byte without any further
     memory accesses, just by looking at the tmp result from the last loop
     iteration.  But this does not work on big-endian machines.  Choose code
     that works in both cases.  */

  for (; n > 0; --n, ++char_ptr)
    {
      if (*char_ptr == c)
        return (void *) char_ptr;
    }

  return NULL;
}
#ifdef weak_alias
weak_alias (__memchr, BP_SYM (memchr))
#endif


code:
# Suppress a valgrind message about use of uninitialized memory in memchr().
# POSIX states that when the character is found, memchr must not read extra
# bytes in an overestimated length (for example, where memchr is used to
# implement strnlen).  However, we use a safe word read to provide a speedup.
{
    memchr-value4
    Memcheck:Value4
    fun:rpl_memchr
}
{
    memchr-value8
    Memcheck:Value8
    fun:rpl_memchr
}