/////////////////////////////////////////////////////////////////////////////
// Name:        src/common/wxcrt.cpp
// Purpose:     wxChar CRT wrappers implementation
// Author:      Ove Kaven
// Modified by: Ron Lee, Francesco Montorsi
// Created:     09/04/99
// RCS-ID:      $Id$
// Copyright:   (c) wxWidgets copyright
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ===========================================================================
// headers, declarations, constants
// ===========================================================================

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#include "wx/crt.h"
#include "wx/strconv.h" // wxMBConv::cWC2MB()

#define _ISOC9X_SOURCE 1 // to get vsscanf()
#define _BSD_SOURCE    1 // to still get strdup()

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

#ifdef __SGI__
    // wide character functions are declared in std namespace under IRIX
    using namespace std;

    // and this one is only declared if __c99 is defined which is not the case
    // for C++ builds, so declare it ourselves
    extern "C" int vswscanf(const wchar_t *, const wchar_t *, va_list);
#endif

#ifndef __WXPALMOS5__
#ifndef __WXWINCE__
    #include <time.h>
    #include <locale.h>
#else
    #include "wx/msw/wince/time.h"
#endif
#endif // !__WXPALMOS5__

#ifndef WX_PRECOMP
    #include "wx/string.h"
    #include "wx/hash.h"
    #include "wx/utils.h"     // for wxMin and wxMax
    #include "wx/log.h"
#endif

#ifdef HAVE_LANGINFO_H
    #include <langinfo.h>
#endif

#ifdef __WXWINCE__
    // there is no errno.h under CE apparently
    #define wxSET_ERRNO(value)
#else
    #include <errno.h>

    #define wxSET_ERRNO(value) errno = value
#endif

#if defined(__MWERKS__) && __MSL__ >= 0x6000
namespace std {}
using namespace std ;
#endif

#if defined(__DARWIN__)
    #include "wx/osx/core/cfref.h"
    #include <CoreFoundation/CFLocale.h>
    #include "wx/osx/core/cfstring.h"
    #include <xlocale.h>
#endif

WXDLLIMPEXP_BASE size_t wxMB2WC(wchar_t *buf, const char *psz, size_t n)
{
  // assume that we have mbsrtowcs() too if we have wcsrtombs()
#ifdef HAVE_WCSRTOMBS
  mbstate_t mbstate;
  memset(&mbstate, 0, sizeof(mbstate_t));
#endif

  if (buf) {
    if (!n || !*psz) {
      if (n) *buf = wxT('\0');
      return 0;
    }
#ifdef HAVE_WCSRTOMBS
    return mbsrtowcs(buf, &psz, n, &mbstate);
#else
    return wxMbstowcs(buf, psz, n);
#endif
  }

  // note that we rely on common (and required by Unix98 but unfortunately not
  // C99) extension which allows to call mbs(r)towcs() with NULL output pointer
  // to just get the size of the needed buffer -- this is needed as otherwise
  // we have no idea about how much space we need and if the CRT doesn't
  // support it (the only currently known example being Metrowerks, see
  // wx/crt.h) we don't use its mbstowcs() at all
#ifdef HAVE_WCSRTOMBS
  return mbsrtowcs(NULL, &psz, 0, &mbstate);
#else
  return wxMbstowcs(NULL, psz, 0);
#endif
}

WXDLLIMPEXP_BASE size_t wxWC2MB(char *buf, const wchar_t *pwz, size_t n)
{
#ifdef HAVE_WCSRTOMBS
  mbstate_t mbstate;
  memset(&mbstate, 0, sizeof(mbstate_t));
#endif

  if (buf) {
    if (!n || !*pwz) {
      // glibc2.1 chokes on null input
      if (n) *buf = '\0';
      return 0;
    }
#ifdef HAVE_WCSRTOMBS
    return wcsrtombs(buf, &pwz, n, &mbstate);
#else
    return wxWcstombs(buf, pwz, n);
#endif
  }

#ifdef HAVE_WCSRTOMBS
  return wcsrtombs(NULL, &pwz, 0, &mbstate);
#else
  return wxWcstombs(NULL, pwz, 0);
#endif
}

char* wxSetlocale(int category, const char *locale)
{
#ifdef __WXWINCE__
    // FIXME-CE: there is no setlocale() in CE CRT, use SetThreadLocale()?
    wxUnusedVar(category);
    wxUnusedVar(locale);

    return NULL;
#else // !__WXWINCE__
#ifdef __WXMAC__
    char *rv = NULL ;
    if ( locale != NULL && locale[0] == 0 )
    {
        // the attempt to use newlocale(LC_ALL_MASK, "", NULL);
        // here in order to deduce the language along the environment vars rules
        // lead to strange crashes later...

        // we have to emulate the behaviour under OS X
        wxCFRef<CFLocaleRef> userLocaleRef(CFLocaleCopyCurrent());
        wxCFStringRef str(wxCFRetain((CFStringRef)CFLocaleGetValue(userLocaleRef, kCFLocaleLanguageCode)));
        wxString langFull = str.AsString()+"_";
        str.reset(wxCFRetain((CFStringRef)CFLocaleGetValue(userLocaleRef, kCFLocaleCountryCode)));
        langFull += str.AsString();
        rv = setlocale(category, langFull.c_str());
    }
    else
        rv = setlocale(category, locale);
#else
    char *rv = setlocale(category, locale);
#endif
    if ( locale != NULL /* setting locale, not querying */ &&
         rv /* call was successful */ )
    {
        wxUpdateLocaleIsUtf8();
    }
    return rv;
#endif // __WXWINCE__/!__WXWINCE__
}

// ============================================================================
// printf() functions business
// ============================================================================

// special test mode: define all functions below even if we don't really need
// them to be able to test them
#ifdef wxTEST_PRINTF
    #undef wxFprintf
    #undef wxPrintf
    #undef wxSprintf
    #undef wxVfprintf
    #undef wxVsprintf
    #undef wxVprintf
    #undef wxVsnprintf_

    #define wxNEED_WPRINTF

    int wxCRT_VfprintfW( FILE *stream, const wchar_t *format, va_list argptr );
#endif

#if defined(__DMC__)
/* Digital Mars adds count to _stprintf (C99) so convert */
int wxCRT_SprintfW (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
{
    va_list arglist;

    va_start( arglist, format );
    int iLen = swprintf ( s, -1, format, arglist );
    va_end( arglist );
    return iLen ;
}
#endif //__DMC__

// ----------------------------------------------------------------------------
// implement the standard IO functions for wide char if libc doesn't have them
// ----------------------------------------------------------------------------

#ifndef wxCRT_FputsW
int wxCRT_FputsW(const wchar_t *ws, FILE *stream)
{
    wxCharBuffer buf(wxConvLibc.cWC2MB(ws));
    if ( !buf )
        return -1;

    // counting the number of wide characters written isn't worth the trouble,
    // simply distinguish between ok and error
    return wxCRT_FputsA(buf, stream) == -1 ? -1 : 0;
}
#endif // !wxCRT_FputsW

#ifndef wxCRT_PutsW
int wxCRT_PutsW(const wchar_t *ws)
{
    int rc = wxCRT_FputsW(ws, stdout);
    if ( rc != -1 )
    {
        if ( wxCRT_FputsW(L"\n", stdout) == -1 )
            return -1;

        rc++;
    }

    return rc;
}
#endif // !wxCRT_PutsW

#ifndef wxCRT_FputcW
int /* not wint_t */ wxCRT_FputcW(wchar_t wc, FILE *stream)
{
    wchar_t ws[2] = { wc, L'\0' };

    return wxCRT_FputsW(ws, stream);
}
#endif // !wxCRT_FputcW

// NB: we only implement va_list functions here, the ones taking ... are
//     defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse
//     the definitions there to avoid duplicating them here
#ifdef wxNEED_WPRINTF

// TODO: implement the scanf() functions
static int vwscanf(const wchar_t *format, va_list argptr)
{
    wxFAIL_MSG( wxT("TODO") );

    return -1;
}

static int vfwscanf(FILE *stream, const wchar_t *format, va_list argptr)
{
    wxFAIL_MSG( wxT("TODO") );

    return -1;
}

#define vswprintf wxCRT_VsnprintfW

static int vfwprintf(FILE *stream, const wchar_t *format, va_list argptr)
{
    wxString s;
    int rc = s.PrintfV(format, argptr);

    if ( rc != -1 )
    {
        // we can't do much better without Unicode support in libc...
        if ( fprintf(stream, "%s", (const char*)s.mb_str() ) == -1 )
            return -1;
    }

    return rc;
}

static int vwprintf(const wchar_t *format, va_list argptr)
{
    return wxCRT_VfprintfW(stdout, format, argptr);
}

#endif // wxNEED_WPRINTF

#ifdef wxNEED_VSWSCANF
static int vswscanf(const wchar_t *ws, const wchar_t *format, va_list argptr)
{
    // The best we can do without proper Unicode support in glibc is to
    // convert the strings into MB representation and run ANSI version
    // of the function. This doesn't work with %c and %s because of difference
    // in size of char and wchar_t, though.

    wxCHECK_MSG( wxStrstr(format, wxT("%s")) == NULL, -1,
                 wxT("incomplete vswscanf implementation doesn't allow %s") );
    wxCHECK_MSG( wxStrstr(format, wxT("%c")) == NULL, -1,
                 wxT("incomplete vswscanf implementation doesn't allow %c") );

    return vsscanf(static_cast<const char*>(wxConvLibc.cWX2MB(ws)),
        wxConvLibc.cWX2MB(format), argptr);
}
#endif

// ----------------------------------------------------------------------------
// wxPrintf(), wxScanf() and relatives
// ----------------------------------------------------------------------------

// FIXME-UTF8: do format conversion using (modified) wxFormatConverter in
//             template wrappers, not here; note that it will needed to
//             translate all forms of string specifiers to %(l)s for wxPrintf(),
//             but it only should do what it did in 2.8 for wxScanf()!

#ifndef wxCRT_PrintfW
int wxCRT_PrintfW( const wchar_t *format, ... )
{
    va_list argptr;
    va_start(argptr, format);

    int ret = vwprintf( format, argptr );

    va_end(argptr);

    return ret;
}
#endif

#ifndef wxCRT_FprintfW
int wxCRT_FprintfW( FILE *stream, const wchar_t *format, ... )
{
    va_list argptr;
    va_start( argptr, format );

    int ret = vfwprintf( stream, format, argptr );

    va_end(argptr);

    return ret;
}
#endif

#ifndef wxCRT_VfprintfW
int wxCRT_VfprintfW( FILE *stream, const wchar_t *format, va_list argptr )
{
    return vfwprintf( stream, format, argptr );
}
#endif

#ifndef wxCRT_VprintfW
int wxCRT_VprintfW( const wchar_t *format, va_list argptr )
{
    return vwprintf( format, argptr );
}
#endif

#ifndef wxCRT_VsprintfW
int wxCRT_VsprintfW( wchar_t *str, const wchar_t *format, va_list argptr )
{
    // same as for wxSprintf()
    return vswprintf(str, INT_MAX / 4, format, argptr);
}
#endif

#ifndef wxCRT_ScanfW
int wxCRT_ScanfW(const wchar_t *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

#ifdef __VMS
#if (__DECCXX_VER >= 70100000) && !defined(__STD_CFRONT) && !defined( __NONAMESPACE_STD )
   int ret = std::vwscanf(format, argptr);
#else
   int ret = vwscanf(format, argptr);
#endif
#else
   int ret = vwscanf(format, argptr);
#endif

    va_end(argptr);

    return ret;
}
#endif

#ifndef wxCRT_SscanfW
int wxCRT_SscanfW(const wchar_t *str, const wchar_t *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

#ifdef __VMS
#if (__DECCXX_VER >= 70100000) && !defined(__STD_CFRONT) && !defined( __NONAMESPACE_STD )
   int ret = std::vswscanf(str, format, argptr);
#else
   int ret = vswscanf(str, format, argptr);
#endif
#else
   int ret = vswscanf(str, format, argptr);
#endif

    va_end(argptr);

    return ret;
}
#endif

#ifndef wxCRT_FscanfW
int wxCRT_FscanfW(FILE *stream, const wchar_t *format, ...)
{
    va_list argptr;
    va_start(argptr, format);
#ifdef __VMS
#if (__DECCXX_VER >= 70100000) && !defined(__STD_CFRONT) && !defined( __NONAMESPACE_STD )
   int ret = std::vfwscanf(stream, format, argptr);
#else
   int ret = vfwscanf(stream, format, argptr);
#endif
#else
   int ret = vfwscanf(stream, format, argptr);
#endif

    va_end(argptr);

    return ret;
}
#endif

#ifndef wxCRT_VsscanfW
int wxCRT_VsscanfW(const wchar_t *str, const wchar_t *format, va_list argptr)
{
#ifdef __VMS
#if (__DECCXX_VER >= 70100000) && !defined(__STD_CFRONT) && !defined( __NONAMESPACE_STD )
   return std::vswscanf(str, format, argptr);
#else
   return vswscanf(str, format, argptr);
#endif
#else
   return vswscanf(str, format, argptr);
#endif
}
#endif


// ----------------------------------------------------------------------------
// wrappers to printf and scanf function families
// ----------------------------------------------------------------------------

#if !wxUSE_UTF8_LOCALE_ONLY
int wxDoSprintfWchar(char *str, const wxChar *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

    int rv = wxVsprintf(str, format, argptr);

    va_end(argptr);
    return rv;
}
#endif // !wxUSE_UTF8_LOCALE_ONLY

#if wxUSE_UNICODE_UTF8
int wxDoSprintfUtf8(char *str, const char *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

    int rv = wxVsprintf(str, format, argptr);

    va_end(argptr);
    return rv;
}
#endif // wxUSE_UNICODE_UTF8

#if wxUSE_UNICODE

#if !wxUSE_UTF8_LOCALE_ONLY
int wxDoSprintfWchar(wchar_t *str, const wxChar *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

    int rv = wxVsprintf(str, format, argptr);

    va_end(argptr);
    return rv;
}
#endif // !wxUSE_UTF8_LOCALE_ONLY

#if wxUSE_UNICODE_UTF8
int wxDoSprintfUtf8(wchar_t *str, const char *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

    int rv = wxVsprintf(str, format, argptr);

    va_end(argptr);
    return rv;
}
#endif // wxUSE_UNICODE_UTF8

#endif // wxUSE_UNICODE

#if !wxUSE_UTF8_LOCALE_ONLY
int wxDoSnprintfWchar(char *str, size_t size, const wxChar *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

    int rv = wxVsnprintf(str, size, format, argptr);

    va_end(argptr);
    return rv;
}
#endif // !wxUSE_UTF8_LOCALE_ONLY

#if wxUSE_UNICODE_UTF8
int wxDoSnprintfUtf8(char *str, size_t size, const char *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

    int rv = wxVsnprintf(str, size, format, argptr);

    va_end(argptr);
    return rv;
}
#endif // wxUSE_UNICODE_UTF8

#if wxUSE_UNICODE

#if !wxUSE_UTF8_LOCALE_ONLY
int wxDoSnprintfWchar(wchar_t *str, size_t size, const wxChar *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

    int rv = wxVsnprintf(str, size, format, argptr);

    va_end(argptr);
    return rv;
}
#endif // !wxUSE_UTF8_LOCALE_ONLY

#if wxUSE_UNICODE_UTF8
int wxDoSnprintfUtf8(wchar_t *str, size_t size, const char *format, ...)
{
    va_list argptr;
    va_start(argptr, format);

    int rv = wxVsnprintf(str, size, format, argptr);

    va_end(argptr);
    return rv;
}
#endif // wxUSE_UNICODE_UTF8

#endif // wxUSE_UNICODE


#ifdef HAVE_BROKEN_VSNPRINTF_DECL
    #define vsnprintf wx_fixed_vsnprintf
#endif

#if wxUSE_UNICODE

namespace
{

#if !wxUSE_UTF8_LOCALE_ONLY
int ConvertStringToBuf(const wxString& s, char *out, size_t outsize)
{
    const wxWX2WCbuf buf = s.wc_str();

    size_t len = wxConvLibc.FromWChar(out, outsize, buf);
    if ( len != wxCONV_FAILED )
        return len-1;
    else
        return wxConvLibc.FromWChar(NULL, 0, buf);
}
#endif // !wxUSE_UTF8_LOCALE_ONLY

#if wxUSE_UNICODE_UTF8
int ConvertStringToBuf(const wxString& s, wchar_t *out, size_t outsize)
{
    const wxWX2WCbuf buf(s.wc_str());
    size_t len = s.length(); // same as buf length for wchar_t*
    if ( outsize > len )
    {
        memcpy(out, buf, (len+1) * sizeof(wchar_t));
    }
    else // not enough space
    {
        memcpy(out, buf, (outsize-1) * sizeof(wchar_t));
        out[outsize-1] = 0;
    }
    return len;
}
#endif // wxUSE_UNICODE_UTF8

} // anonymous namespace

template<typename T>
static size_t PrintfViaString(T *out, size_t outsize,
                              const wxString& format, va_list argptr)
{
    wxString s;
    s.PrintfV(format, argptr);

    return ConvertStringToBuf(s, out, outsize);
}
#endif // wxUSE_UNICODE

int wxVsprintf(char *str, const wxString& format, va_list argptr)
{
#if wxUSE_UTF8_LOCALE_ONLY
    return wxCRT_VsprintfA(str, format.wx_str(), argptr);
#else
    #if wxUSE_UNICODE_UTF8
    if ( wxLocaleIsUtf8 )
        return wxCRT_VsprintfA(str, format.wx_str(), argptr);
    else
    #endif
    #if wxUSE_UNICODE
    return PrintfViaString(str, wxNO_LEN, format, argptr);
    #else
    return wxCRT_VsprintfA(str, format.mb_str(), argptr);
    #endif
#endif
}

#if wxUSE_UNICODE
int wxVsprintf(wchar_t *str, const wxString& format, va_list argptr)
{
#if wxUSE_UNICODE_WCHAR
#ifdef __DMC__
/*
This fails with a bug similar to
http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=c++.beta&artnum=680
in DMC 8.49 and 8.50
I don't see it being used in the wxWidgets sources at present (oct 2007) CE
*/
#pragma message ( "warning ::::: wxVsprintf(wchar_t *str, const wxString& format, va_list argptr) not yet implemented" )
    wxFAIL_MSG( wxT("TODO") );

    return -1;
#else
    return wxCRT_VsprintfW(str, format.wc_str(), argptr);
#endif //DMC
#else // wxUSE_UNICODE_UTF8
    #if !wxUSE_UTF8_LOCALE_ONLY
    if ( !wxLocaleIsUtf8 )
        return wxCRT_VsprintfW(str, format.wc_str(), argptr);
    else
    #endif
        return PrintfViaString(str, wxNO_LEN, format, argptr);
#endif // wxUSE_UNICODE_UTF8
}
#endif // wxUSE_UNICODE

int wxVsnprintf(char *str, size_t size, const wxString& format, va_list argptr)
{
    int rv;
#if wxUSE_UTF8_LOCALE_ONLY
    rv = wxCRT_VsnprintfA(str, size, format.wx_str(), argptr);
#else
    #if wxUSE_UNICODE_UTF8
    if ( wxLocaleIsUtf8 )
        rv = wxCRT_VsnprintfA(str, size, format.wx_str(), argptr);
    else
    #endif
    #if wxUSE_UNICODE
    {
        // NB: if this code is called, then wxString::PrintV() would use the
        //     wchar_t* version of wxVsnprintf(), so it's safe to use PrintV()
        //     from here
        rv = PrintfViaString(str, size, format, argptr);
    }
    #else
    rv = wxCRT_VsnprintfA(str, size, format.mb_str(), argptr);
    #endif
#endif

    // VsnprintfTestCase reveals that glibc's implementation of vswprintf
    // doesn't nul terminate on truncation.
    str[size - 1] = 0;

    return rv;
}

#if wxUSE_UNICODE
int wxVsnprintf(wchar_t *str, size_t size, const wxString& format, va_list argptr)
{
    int rv;

#if wxUSE_UNICODE_WCHAR
    rv = wxCRT_VsnprintfW(str, size, format.wc_str(), argptr);
#else // wxUSE_UNICODE_UTF8
    #if !wxUSE_UTF8_LOCALE_ONLY
    if ( !wxLocaleIsUtf8 )
        rv = wxCRT_VsnprintfW(str, size, format.wc_str(), argptr);
    else
    #endif
    {
        // NB: if this code is called, then wxString::PrintV() would use the
        //     char* version of wxVsnprintf(), so it's safe to use PrintV()
        //     from here
        rv = PrintfViaString(str, size, format, argptr);
    }
#endif // wxUSE_UNICODE_UTF8

    // VsnprintfTestCase reveals that glibc's implementation of vswprintf
    // doesn't nul terminate on truncation.
    str[size - 1] = 0;

    return rv;
}
#endif // wxUSE_UNICODE


// ----------------------------------------------------------------------------
// ctype.h stuff (currently unused)
// ----------------------------------------------------------------------------

#ifdef wxNEED_WX_MBSTOWCS

WXDLLIMPEXP_BASE size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen)
{
    if (!out)
    {
        size_t outsize = 0;
        while(*in++)
            outsize++;
        return outsize;
    }

    const char* origin = in;

    while (outlen-- && *in)
    {
        *out++ = (wchar_t) *in++;
    }

    *out = '\0';

    return in - origin;
}

WXDLLIMPEXP_BASE size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen)
{
    if (!out)
    {
        size_t outsize = 0;
        while(*in++)
            outsize++;
        return outsize;
    }

    const wchar_t* origin = in;

    while (outlen-- && *in)
    {
        *out++ = (char) *in++;
    }

    *out = '\0';

    return in - origin;
}

#endif // wxNEED_WX_MBSTOWCS

#ifndef wxCRT_StrdupA
WXDLLIMPEXP_BASE char *wxCRT_StrdupA(const char *s)
{
    return strcpy((char *)malloc(strlen(s) + 1), s);
}
#endif // wxCRT_StrdupA

#ifndef wxCRT_StrdupW
WXDLLIMPEXP_BASE wchar_t * wxCRT_StrdupW(const wchar_t *pwz)
{
  size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t);
  wchar_t *ret = (wchar_t *) malloc(size);
  memcpy(ret, pwz, size);
  return ret;
}
#endif // wxCRT_StrdupW

#ifndef wxWCHAR_T_IS_WXCHAR16
size_t wxStrlen(const wxChar16 *s )
{
    if (!s) return 0;
    size_t i=0;
    while (*s!=0) { ++i; ++s; };
    return i;
}

wxChar16* wxStrdup(const wxChar16* s)
{
  size_t size = (wxStrlen(s) + 1) * sizeof(wxChar16);
  wxChar16 *ret = (wxChar16*) malloc(size);
  memcpy(ret, s, size);
  return ret;
}
#endif

#ifndef wxWCHAR_T_IS_WXCHAR32
size_t wxStrlen(const wxChar32 *s )
{
    if (!s) return 0;
    size_t i=0;
    while (*s!=0) { ++i; ++s; };
    return i;
}

wxChar32* wxStrdup(const wxChar32* s)
{
  size_t size = (wxStrlen(s) + 1) * sizeof(wxChar32);
  wxChar32 *ret = (wxChar32*) malloc(size);
  memcpy(ret, s, size);
  return ret;
}
#endif

#ifndef wxCRT_StricmpA
WXDLLIMPEXP_BASE int wxCRT_StricmpA(const char *psz1, const char *psz2)
{
  register char c1, c2;
  do {
    c1 = wxTolower(*psz1++);
    c2 = wxTolower(*psz2++);
  } while ( c1 && (c1 == c2) );
  return c1 - c2;
}
#endif // !defined(wxCRT_StricmpA)

#ifndef wxCRT_StricmpW
WXDLLIMPEXP_BASE int wxCRT_StricmpW(const wchar_t *psz1, const wchar_t *psz2)
{
  register wchar_t c1, c2;
  do {
    c1 = wxTolower(*psz1++);
    c2 = wxTolower(*psz2++);
  } while ( c1 && (c1 == c2) );
  return c1 - c2;
}
#endif // !defined(wxCRT_StricmpW)

#ifndef wxCRT_StrnicmpA
WXDLLIMPEXP_BASE int wxCRT_StrnicmpA(const char *s1, const char *s2, size_t n)
{
  // initialize the variables just to suppress stupid gcc warning
  register char c1 = 0, c2 = 0;
  while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
  if (n) {
    if (c1 < c2) return -1;
    if (c1 > c2) return 1;
  }
  return 0;
}
#endif // !defined(wxCRT_StrnicmpA)

#ifndef wxCRT_StrnicmpW
WXDLLIMPEXP_BASE int wxCRT_StrnicmpW(const wchar_t *s1, const wchar_t *s2, size_t n)
{
  // initialize the variables just to suppress stupid gcc warning
  register wchar_t c1 = 0, c2 = 0;
  while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++;
  if (n) {
    if (c1 < c2) return -1;
    if (c1 > c2) return 1;
  }
  return 0;
}
#endif // !defined(wxCRT_StrnicmpW)

// ----------------------------------------------------------------------------
// string.h functions
// ----------------------------------------------------------------------------

// this (and wxCRT_StrncmpW below) are extern "C" because they are needed
// by regex code, the rest isn't needed, so it's not declared as extern "C"
#ifndef wxCRT_StrlenW
extern "C" WXDLLIMPEXP_BASE size_t wxCRT_StrlenW(const wchar_t *s)
{
    size_t n = 0;
    while ( *s++ )
        n++;

    return n;
}
#endif

// ----------------------------------------------------------------------------
// stdlib.h functions
// ----------------------------------------------------------------------------

#ifndef wxCRT_GetenvW
WXDLLIMPEXP_BASE wchar_t* wxCRT_GetenvW(const wchar_t *name)
{
    // NB: buffer returned by getenv() is allowed to be overwritten next
    //     time getenv() is called, so it is OK to use static string
    //     buffer to hold the data.
    static wxWCharBuffer value;
    value = wxConvLibc.cMB2WC(getenv(wxConvLibc.cWC2MB(name)));
    return value.data();
}
#endif // !wxCRT_GetenvW

#ifndef wxCRT_StrftimeW
WXDLLIMPEXP_BASE size_t
wxCRT_StrftimeW(wchar_t *s, size_t maxsize, const wchar_t *fmt, const struct tm *tm)
{
    if ( !maxsize )
        return 0;

    wxCharBuffer buf(maxsize);

    wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt));
    if ( !bufFmt )
        return 0;

    size_t ret = strftime(buf.data(), maxsize, bufFmt, tm);
    if  ( !ret )
        return 0;

    wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf);
    if ( !wbuf )
        return 0;

    wxCRT_StrncpyW(s, wbuf, maxsize);
    return wxCRT_StrlenW(s);
}
#endif // !wxCRT_StrftimeW

#ifdef wxLongLong_t
template<typename T>
static wxULongLong_t
wxCRT_StrtoullBase(const T* nptr, T** endptr, int base, T* sign)
{
    wxULongLong_t sum = 0;
    wxString wxstr(nptr);
    wxString::const_iterator i = wxstr.begin();
    wxString::const_iterator end = wxstr.end();

    // Skip spaces
    while ( i != end && wxIsspace(*i) ) ++i;

    // Starts with sign?
    *sign = wxT(' ');
    if ( i != end )
    {
        T c = *i;
        if ( c == wxT('+') || c == wxT('-') )
        {
            *sign = c;
            ++i;
        }
    }

    // Starts with 0x?
    if ( i != end && *i == wxT('0') )
    {
        ++i;
        if ( i != end )
        {
            if ( *i == wxT('x') && (base == 16 || base == 0) )
            {
                base = 16;
                ++i;
            }
            else
            {
                if ( endptr )
                    *endptr = (T*) nptr;
                wxSET_ERRNO(EINVAL);
                return sum;
            }
        }
        else
            --i;
    }

    if ( base == 0 )
        base = 10;

    for ( ; i != end; ++i )
    {
        unsigned int n;

        T c = *i;
        if ( c >= '0' )
        {
            if ( c <= '9' )
                n = c - wxT('0');
            else
                n = wxTolower(c) - wxT('a') + 10;
        }
        else
            break;

        if ( n >= (unsigned int)base )
            // Invalid character (for this base)
            break;

        wxULongLong_t prevsum = sum;
        sum = (sum * base) + n;

        if ( sum < prevsum )
        {
            wxSET_ERRNO(ERANGE);
            break;
        }
    }

    if ( endptr )
    {
        *endptr = (T*)(nptr + (i - wxstr.begin()));
    }

    return sum;
}

template<typename T>
static wxULongLong_t wxCRT_DoStrtoull(const T* nptr, T** endptr, int base)
{
    T sign;
    wxULongLong_t uval = ::wxCRT_StrtoullBase(nptr, endptr, base, &sign);

    if ( sign == wxT('-') )
    {
        wxSET_ERRNO(ERANGE);
        uval = 0;
    }

    return uval;
}

template<typename T>
static wxLongLong_t wxCRT_DoStrtoll(const T* nptr, T** endptr, int base)
{
    T sign;
    wxULongLong_t uval = ::wxCRT_StrtoullBase(nptr, endptr, base, &sign);
    wxLongLong_t val = 0;

    if ( sign == wxT('-') )
    {
        if (uval <= (wxULongLong_t)wxINT64_MAX + 1)
        {
            val = -(wxLongLong_t)uval;
        }
        else
        {
            wxSET_ERRNO(ERANGE);
        }
    }
    else if ( uval <= wxINT64_MAX )
    {
        val = uval;
    }
    else
    {
        wxSET_ERRNO(ERANGE);
    }

    return val;
}

#ifndef wxCRT_StrtollA
wxLongLong_t wxCRT_StrtollA(const char* nptr, char** endptr, int base)
    { return wxCRT_DoStrtoll(nptr, endptr, base); }
#endif
#ifndef wxCRT_StrtollW
wxLongLong_t wxCRT_StrtollW(const wchar_t* nptr, wchar_t** endptr, int base)
    { return wxCRT_DoStrtoll(nptr, endptr, base); }
#endif

#ifndef wxCRT_StrtoullA
wxULongLong_t wxCRT_StrtoullA(const char* nptr, char** endptr, int base)
    { return wxCRT_DoStrtoull(nptr, endptr, base); }
#endif
#ifndef wxCRT_StrtoullW
wxULongLong_t wxCRT_StrtoullW(const wchar_t* nptr, wchar_t** endptr, int base)
    { return wxCRT_DoStrtoull(nptr, endptr, base); }
#endif

#endif // wxLongLong_t

// ----------------------------------------------------------------------------
// strtok() functions
// ----------------------------------------------------------------------------

template<typename T>
static T *wxCRT_DoStrtok(T *psz, const T *delim, T **save_ptr)
{
    if (!psz)
    {
        psz = *save_ptr;
        if ( !psz )
            return NULL;
    }

    psz += wxStrspn(psz, delim);
    if (!*psz)
    {
        *save_ptr = NULL;
        return NULL;
    }

    T *ret = psz;
    psz = wxStrpbrk(psz, delim);
    if (!psz)
    {
        *save_ptr = NULL;
    }
    else
    {
        *psz = wxT('\0');
        *save_ptr = psz + 1;
    }

    return ret;
}

#ifndef wxCRT_StrtokA
char *wxCRT_StrtokA(char *psz, const char *delim, char **save_ptr)
    { return wxCRT_DoStrtok(psz, delim, save_ptr); }
#endif
#ifndef wxCRT_StrtokW
wchar_t *wxCRT_StrtokW(wchar_t *psz, const wchar_t *delim, wchar_t **save_ptr)
    { return wxCRT_DoStrtok(psz, delim, save_ptr); }
#endif

// ----------------------------------------------------------------------------
// missing C RTL functions
// ----------------------------------------------------------------------------

#ifdef wxNEED_STRDUP

char *strdup(const char *s)
{
    char *dest = (char*) malloc( strlen( s ) + 1 ) ;
    if ( dest )
        strcpy( dest , s ) ;
    return dest ;
}
#endif // wxNEED_STRDUP

#if defined(__WXWINCE__) && (_WIN32_WCE <= 211)

void *calloc( size_t num, size_t size )
{
    void** ptr = (void **)malloc(num * size);
    memset( ptr, 0, num * size);
    return ptr;
}

#endif // __WXWINCE__ <= 211

// ============================================================================
// wxLocaleIsUtf8
// ============================================================================

#if wxUSE_UNICODE_UTF8

#if !wxUSE_UTF8_LOCALE_ONLY
bool wxLocaleIsUtf8 = false; // the safer setting if not known
#endif

static bool wxIsLocaleUtf8()
{
    // NB: we intentionally don't use wxLocale::GetSystemEncodingName(),
    //     because a) it may be unavailable in some builds and b) has slightly
    //     different semantics (default locale instead of current)

#if defined(HAVE_LANGINFO_H) && defined(CODESET)
    // GNU libc provides current character set this way (this conforms to
    // Unix98)
    const char *charset = nl_langinfo(CODESET);
    if ( charset )
    {
        // "UTF-8" is used by modern glibc versions, but test other variants
        // as well, just in case:
        if ( strcmp(charset, "UTF-8") == 0 ||
             strcmp(charset, "utf-8") == 0 ||
             strcmp(charset, "UTF8") == 0 ||
             strcmp(charset, "utf8") == 0 )
        {
            return true;
        }
    }
#endif // HAVE_LANGINFO_H

    // check if we're running under the "C" locale: it is 7bit subset
    // of UTF-8, so it can be safely used with the UTF-8 build:
    const char *lc_ctype = setlocale(LC_CTYPE, NULL);
    if ( lc_ctype &&
         (strcmp(lc_ctype, "C") == 0 || strcmp(lc_ctype, "POSIX") == 0) )
    {
        return true;
    }

    // we don't know what charset libc is using, so assume the worst
    // to be safe:
    return false;
}

void wxUpdateLocaleIsUtf8()
{
#if wxUSE_UTF8_LOCALE_ONLY
    if ( !wxIsLocaleUtf8() )
    {
        wxLogFatalError(wxT("This program requires UTF-8 locale to run."));
    }
#else // !wxUSE_UTF8_LOCALE_ONLY
    wxLocaleIsUtf8 = wxIsLocaleUtf8();
#endif
}

#endif // wxUSE_UNICODE_UTF8

// ============================================================================
// wx wrappers for CRT functions
// ============================================================================

#if wxUSE_UNICODE_WCHAR
    #define CALL_ANSI_OR_UNICODE(return_kw, callA, callW)  return_kw callW
#elif wxUSE_UNICODE_UTF8 && !wxUSE_UTF8_LOCALE_ONLY
    #define CALL_ANSI_OR_UNICODE(return_kw, callA, callW) \
            return_kw wxLocaleIsUtf8 ? callA : callW
#else // ANSI or UTF8 only
    #define CALL_ANSI_OR_UNICODE(return_kw, callA, callW)  return_kw callA
#endif

int wxPuts(const wxString& s)
{
    // under IRIX putws() takes a non-const argument so use wchar_str() instead
    // of wc_str()
    CALL_ANSI_OR_UNICODE(return,
                         wxCRT_PutsA(s.mb_str()),
                         wxCRT_PutsW(s.wchar_str()));
}

int wxFputs(const wxString& s, FILE *stream)
{
    CALL_ANSI_OR_UNICODE(return,
                         wxCRT_FputsA(s.mb_str(), stream),
                         wxCRT_FputsW(s.wc_str(), stream));
}

int wxFputc(const wxUniChar& c, FILE *stream)
{
#if !wxUSE_UNICODE // FIXME-UTF8: temporary, remove this with ANSI build
    return wxCRT_FputcA((char)c, stream);
#else
    CALL_ANSI_OR_UNICODE(return,
                         wxCRT_FputsA(c.AsUTF8(), stream),
                         wxCRT_FputcW((wchar_t)c, stream));
#endif
}

#ifdef wxCRT_PerrorA

void wxPerror(const wxString& s)
{
#ifdef wxCRT_PerrorW
    CALL_ANSI_OR_UNICODE(wxEMPTY_PARAMETER_VALUE,
                         wxCRT_PerrorA(s.mb_str()),
                         wxCRT_PerrorW(s.wc_str()));
#else
    wxCRT_PerrorA(s.mb_str());
#endif
}

#endif // wxCRT_PerrorA

wchar_t *wxFgets(wchar_t *s, int size, FILE *stream)
{
    wxCHECK_MSG( s, NULL, "empty buffer passed to wxFgets()" );

    wxCharBuffer buf(size - 1);
    // FIXME: this reads too little data if wxConvLibc uses UTF-8 ('size' wide
    //        characters may be encoded by up to 'size'*4 bytes), but what
    //        else can we do?
    if ( wxFgets(buf.data(), size, stream) == NULL )
        return NULL;

    if ( wxConvLibc.ToWChar(s, size, buf, wxNO_LEN) == wxCONV_FAILED )
        return NULL;

    return s;
}

// ----------------------------------------------------------------------------
// wxScanf() and friends
// ----------------------------------------------------------------------------

#ifdef HAVE_VSSCANF // __VISUALC__ and __DMC__ see wx/crt.h
int wxVsscanf(const char *str, const char *format, va_list ap)
    { return wxCRT_VsscanfA(str, format, ap); }
int wxVsscanf(const wchar_t *str, const wchar_t *format, va_list ap)
    { return wxCRT_VsscanfW(str, format, ap); }
int wxVsscanf(const wxCharBuffer& str, const char *format, va_list ap)
    { return wxCRT_VsscanfA(static_cast<const char*>(str), format, ap); }
int wxVsscanf(const wxWCharBuffer& str, const wchar_t *format, va_list ap)
    { return wxCRT_VsscanfW(str, format, ap); }
int wxVsscanf(const wxString& str, const char *format, va_list ap)
    { return wxCRT_VsscanfA(static_cast<const char*>(str.mb_str()), format, ap); }
int wxVsscanf(const wxString& str, const wchar_t *format, va_list ap)
    { return wxCRT_VsscanfW(str.wc_str(), format, ap); }
int wxVsscanf(const wxCStrData& str, const char *format, va_list ap)
    { return wxCRT_VsscanfA(static_cast<const char*>(str.AsCharBuf()), format, ap); }
int wxVsscanf(const wxCStrData& str, const wchar_t *format, va_list ap)
    { return wxCRT_VsscanfW(str.AsWCharBuf(), format, ap); }
#endif // HAVE_NO_VSSCANF
