]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wxcrt.cpp
add wx/unix/private directory
[wxWidgets.git] / src / common / wxcrt.cpp
index 5f08d6d4d4e64eb32b5ad89f3d60be697db09c88..a3abc326bf75ea0631364d82ef0793f64f44f10f 100644 (file)
     #include <winnt.h>
 #endif
 
+#ifndef wxStrtoll
+    #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
+#endif
+
 #if defined(__MWERKS__) && __MSL__ >= 0x6000
 namespace std {}
 using namespace std ;
@@ -152,31 +163,16 @@ bool WXDLLEXPORT wxOKlibc()
     #undef wxVsprintf
     #undef wxVprintf
     #undef wxVsnprintf_
-    #undef wxSnprintf_
 
     #define wxNEED_WPRINTF
 
     int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr );
 #endif
 
-#if !defined(wxSnprintf_)
-int WXDLLEXPORT wxDoSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...)
-{
-    va_list argptr;
-    va_start(argptr, format);
-
-    int iLen = wxVsnprintf_(buf, len, format, argptr);
-
-    va_end(argptr);
-
-    return iLen;
-}
-#endif // wxSnprintf_
-
 #if defined(__DMC__)
     /* Digital Mars adds count to _stprintf (C99) so convert */
     #if wxUSE_UNICODE
-        int wxDoSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
+        int wxSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... )
         {
             va_list arglist;
 
@@ -257,9 +253,7 @@ int vswscanf(const wxChar *ws, const wxChar *format, va_list argptr)
     wxCHECK_MSG( wxStrstr(format, _T("%c")) == NULL, -1,
                  _T("incomplete vswscanf implementation doesn't allow %c") );
 
-    va_list argcopy;
-    wxVaCopy(argcopy, argptr);
-    return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argcopy);
+    return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argptr);
 }
 
 int vfwscanf(FILE *stream, const wxChar *format, va_list argptr)
@@ -516,7 +510,7 @@ wxString wxConvertFormat(const wxChar *format)
 
 #if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF)
 
-int wxDoScanf( const wxChar *format, ... )
+int wxCRT_Scanf( const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -528,7 +522,7 @@ int wxDoScanf( const wxChar *format, ... )
     return ret;
 }
 
-int wxDoSscanf( const wxChar *str, const wxChar *format, ... )
+int wxCRT_Sscanf( const wxChar *str, const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -540,7 +534,7 @@ int wxDoSscanf( const wxChar *str, const wxChar *format, ... )
     return ret;
 }
 
-int wxDoFscanf( FILE *stream, const wxChar *format, ... )
+int wxCRT_Fscanf( FILE *stream, const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -551,7 +545,7 @@ int wxDoFscanf( FILE *stream, const wxChar *format, ... )
     return ret;
 }
 
-int wxDoPrintf( const wxChar *format, ... )
+int wxCRT_Printf( const wxChar *format, ... )
 {
     va_list argptr;
     va_start(argptr, format);
@@ -563,80 +557,300 @@ int wxDoPrintf( const wxChar *format, ... )
     return ret;
 }
 
-#ifndef wxSnprintf
-int wxDoSnprintf( wxChar *str, size_t size, const wxChar *format, ... )
+int wxCRT_Fprintf( FILE *stream, const wxChar *format, ... )
+{
+    va_list argptr;
+    va_start( argptr, format );
+
+    int ret = vfwprintf( stream, wxFormatConverter(format), argptr );
+
+    va_end(argptr);
+
+    return ret;
+}
+
+int wxCRT_Vsscanf( const wxChar *str, const wxChar *format, va_list argptr )
+{
+    return vswscanf( str, wxFormatConverter(format), argptr );
+}
+
+int wxCRT_Vfprintf( FILE *stream, const wxChar *format, va_list argptr )
+{
+    return vfwprintf( stream, wxFormatConverter(format), argptr );
+}
+
+int wxCRT_Vprintf( const wxChar *format, va_list argptr )
+{
+    return vwprintf( wxFormatConverter(format), argptr );
+}
+
+#ifndef wxCRT_Vsnprintf
+int wxCRT_Vsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr )
+{
+    return vswprintf( str, size, wxFormatConverter(format), argptr );
+}
+#endif // wxCRT_Vsnprintf
+
+int wxCRT_Vsprintf( wxChar *str, const wxChar *format, va_list argptr )
+{
+    // same as for wxSprintf()
+    return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr);
+}
+
+#endif // wxNEED_PRINTF_CONVERSION
+
+
+// ----------------------------------------------------------------------------
+// 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 ret = vswprintf( str, size, wxFormatConverter(format), argptr );
+    int rv = wxVsprintf(str, format, argptr);
 
-    // VsnprintfTestCase reveals that glibc's implementation of vswprintf
-    // doesn't nul terminate on truncation.
-    str[size - 1] = 0;
+    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
 
-    return ret;
+#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 // wxSnprintf
+#endif // !wxUSE_UTF8_LOCALE_ONLY
 
-int wxDoSprintf( wxChar *str, const wxChar *format, ... )
+#if wxUSE_UNICODE_UTF8
+int wxDoSprintfUtf8(wchar_t *str, const char *format, ...)
 {
     va_list argptr;
     va_start(argptr, format);
 
-    // note that wxString::FormatV() uses wxVsnprintf(), not wxSprintf(), so
-    // it's safe to implement this one in terms of it
-    wxString s(wxString::FormatV(format, argptr));
-    wxStrcpy(str, s);
+    int rv = wxVsprintf(str, format, argptr);
 
     va_end(argptr);
+    return rv;
+}
+#endif // wxUSE_UNICODE_UTF8
 
-    return s.length();
+#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
 
-int wxDoFprintf( FILE *stream, const wxChar *format, ... )
+#if wxUSE_UNICODE_UTF8
+int wxDoSnprintfUtf8(char *str, size_t size, const char *format, ...)
 {
     va_list argptr;
-    va_start( argptr, format );
+    va_start(argptr, format);
 
-    int ret = vfwprintf( stream, wxFormatConverter(format), argptr );
+    int rv = wxVsnprintf(str, size, format, argptr);
 
     va_end(argptr);
+    return rv;
+}
+#endif // wxUSE_UNICODE_UTF8
 
-    return ret;
+#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
 
-int wxVsscanf( const wxChar *str, const wxChar *format, va_list argptr )
+#if wxUSE_UNICODE_UTF8
+int wxDoSnprintfUtf8(wchar_t *str, size_t size, const char *format, ...)
 {
-    return vswscanf( str, wxFormatConverter(format), argptr );
+    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
 
-int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr )
+
+#ifdef HAVE_BROKEN_VSNPRINTF_DECL
+    #define vsnprintf wx_fixed_vsnprintf
+#endif
+
+#if wxUSE_UNICODE
+
+#if !wxUSE_UTF8_LOCALE_ONLY
+static int ConvertStringToBuf(const wxString& s, char *out, size_t outsize)
 {
-    return vfwprintf( stream, wxFormatConverter(format), argptr );
+    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
 
-int wxVprintf( const wxChar *format, va_list argptr )
+#if wxUSE_UNICODE_UTF8
+static int ConvertStringToBuf(const wxString& s, wchar_t *out, size_t outsize)
 {
-    return vwprintf( wxFormatConverter(format), argptr );
+    const wxWX2WCbuf buf(s.wc_str());
+    size_t len = wxWcslen(buf);
+    if ( outsize > len )
+        memcpy(out, buf, (len+1) * sizeof(wchar_t));
+    // else: not enough space
+    return len;
 }
+#endif // wxUSE_UNICODE_UTF8
 
-#ifndef wxVsnprintf
-int wxVsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr )
+template<typename T>
+static size_t PrintfViaString(T *out, size_t outsize,
+                              const wxString& format, va_list argptr)
 {
-    return vswprintf( str, size, wxFormatConverter(format), argptr );
+    wxString s;
+    s.PrintfV(format, argptr);
+
+    return ConvertStringToBuf(s, out, outsize);
 }
-#endif // wxVsnprintf
+#endif // wxUSE_UNICODE
 
-int wxVsprintf( wxChar *str, const wxChar *format, va_list argptr )
+int wxVsprintf(char *str, const wxString& format, va_list argptr)
 {
-    // same as for wxSprintf()
-    return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr);
+#if wxUSE_UTF8_LOCALE_ONLY
+    return vsprintf(str, format.wx_str(), argptr);
+#else
+    #if wxUSE_UNICODE_UTF8
+    if ( wxLocaleIsUtf8 )
+        return vsprintf(str, format.wx_str(), argptr);
+    else
+    #endif
+    #if wxUSE_UNICODE
+    return PrintfViaString(str, wxNO_LEN, format, argptr);
+    #else
+    return wxCRT_Vsprintf(str, format, argptr);
+    #endif
+#endif
 }
 
-#endif // wxNEED_PRINTF_CONVERSION
+#if wxUSE_UNICODE
+int wxVsprintf(wchar_t *str, const wxString& format, va_list argptr)
+{
+#if wxUSE_UNICODE_WCHAR
+    return wxCRT_Vsprintf(str, format, argptr);
+#else // wxUSE_UNICODE_UTF8
+    #if !wxUSE_UTF8_LOCALE_ONLY
+    if ( !wxLocaleIsUtf8 )
+        return wxCRT_Vsprintf(str, format, 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 = vsnprintf(str, size, format.wx_str(), argptr);
+#else
+    #if wxUSE_UNICODE_UTF8
+    if ( wxLocaleIsUtf8 )
+        rv = vsnprintf(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_Vsnprintf(str, size, format, 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_Vsnprintf(str, size, format, argptr);
+#else // wxUSE_UNICODE_UTF8
+    #if !wxUSE_UTF8_LOCALE_ONLY
+    if ( !wxLocaleIsUtf8 )
+        rv = wxCRT_Vsnprintf(str, size, format, 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
 
 #if wxUSE_WCHAR_T
 
@@ -793,14 +1007,30 @@ int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n)
 }
 #endif
 
-#ifndef wxSetlocale
-WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale)
+#ifndef wxSetlocale_
+wxWCharBuffer wxSetlocale_(int category, const wxChar *locale)
 {
     char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale));
 
     return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld));
 }
-#endif
+
+wxWCharBuffer wxSetlocale(int category, const wxChar *locale)
+{
+    wxWCharBuffer rv = wxSetlocale_(category, locale);
+    if ( rv )
+        wxUpdateLocaleIsUtf8();
+    return rv;
+}
+#else // defined(wxSetlocale_)
+wxChar *wxSetlocale(int category, const wxChar *locale)
+{
+    wxChar *rv = wxSetlocale_(category, locale);
+    if ( rv )
+        wxUpdateLocaleIsUtf8();
+    return rv;
+}
+#endif // wxSetlocale_ defined or not
 
 #if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN)
 WXDLLEXPORT size_t wxWcslen(const wchar_t *s)
@@ -1081,12 +1311,14 @@ wxChar * WXDLLEXPORT wxGetenv(const wxChar *name)
 #endif
 }
 
+#endif // wxNEED_WX_STDLIB_H
+
+#ifdef wxNEED_WXSYSTEM
 int WXDLLEXPORT wxSystem(const wxChar *psz)
 {
     return system(wxConvLibc.cWX2MB(psz));
 }
-
-#endif // wxNEED_WX_STDLIB_H
+#endif // wxNEED_WXSYSTEM
 
 #ifdef wxNEED_WX_TIME_H
 WXDLLEXPORT size_t
@@ -1132,6 +1364,139 @@ WXDLLEXPORT wxChar *wxCtime(const time_t *timep)
 
 #endif // wxUSE_WCHAR_T
 
+#ifndef wxStrtoll
+static wxULongLong_t wxStrtoullBase(const wxChar* nptr, wxChar** endptr, int base, wxChar* 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 )
+    {
+        wxChar 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 = (wxChar*) nptr;
+                wxSET_ERRNO(EINVAL);
+                return sum;
+            }
+        }
+        else
+            i--;
+    }
+
+    if ( base == 0 )
+        base = 10;
+
+    for ( ; i != end; i++ )
+    {
+        unsigned int n;
+
+        wxChar c = *i;
+        if ( c >= wxT('0') )
+        {
+            if ( c <= wxT('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 = (wxChar*)(nptr + (i - wxstr.begin()));
+    }
+
+    return sum;
+}
+
+wxULongLong_t wxStrtoull(const wxChar* nptr, wxChar** endptr, int base)
+{
+    wxChar sign;
+    wxULongLong_t uval = wxStrtoullBase(nptr, endptr, base, &sign);
+
+    if ( sign == wxT('-') )
+    {
+        wxSET_ERRNO(ERANGE);
+        uval = 0;
+    }
+
+    return uval;
+}
+
+wxLongLong_t wxStrtoll(const wxChar* nptr, wxChar** endptr, int base)
+{
+    wxChar sign;
+    wxULongLong_t uval = wxStrtoullBase(nptr, endptr, base, &sign);
+    wxLongLong_t val = 0;
+
+    if ( sign == wxT('-') )
+    {
+        if ( uval <= wxULL(wxINT64_MAX+1) )
+        {
+            if ( uval == wxULL(wxINT64_MAX+1))
+                val = -((wxLongLong_t)wxINT64_MAX) - 1;
+            else
+                val = -((wxLongLong_t)uval);
+        }
+        else
+        {
+            wxSET_ERRNO(ERANGE);
+        }
+    }
+    else if ( uval <= wxINT64_MAX )
+    {
+        val = uval;
+    }
+    else
+    {
+        wxSET_ERRNO(ERANGE);
+    }
+
+    return val;
+}
+#endif // wxStrtoll
+
 // ----------------------------------------------------------------------------
 // functions which we may need even if !wxUSE_WCHAR_T
 // ----------------------------------------------------------------------------
@@ -1205,3 +1570,66 @@ int wxRemove(const wxChar *path)
 }
 
 #endif
+
+
+// ----------------------------------------------------------------------------
+// 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
+
+    // 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(_T("This program requires UTF-8 locale to run."));
+    }
+#else // !wxUSE_UTF8_LOCALE_ONLY
+    wxLocaleIsUtf8 = wxIsLocaleUtf8();
+#endif
+}
+
+#endif // wxUSE_UTF8_LOCALE_ONLY