]> git.saurik.com Git - wxWidgets.git/commitdiff
extend wxXLocale with wxStrto[d,l,ul] functions; make wxXLocale::Init() a little...
authorFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Thu, 19 Mar 2009 18:05:49 +0000 (18:05 +0000)
committerFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Thu, 19 Mar 2009 18:05:49 +0000 (18:05 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59627 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/xlocale.h
interface/wx/xlocale.h
src/common/xlocale.cpp
tests/xlocale/xlocale.cpp

index 64b6e53a178f6e13f963e601fbfa77e434d36dc2..d2ca8d2008e2631e0b787958ec0428263a32f1f1 100644 (file)
@@ -18,8 +18,8 @@
     using decimal point &c.
 
     TODO: Currently only the character classification and transformation
-          functions are implemented, we also need at least
-            - numbers: atof_l(), strtod_l() &c
+          functions and number <-> string functions, are implemented, 
+          we also need at least
             - formatted IO: scanf_l(), printf_l() &c
             - time: strftime_l(), strptime_l()
  */
@@ -44,6 +44,7 @@
         #include <locale.h>
         #include <xlocale.h>
         #include <ctype.h>
+        #include <stdlib.h>
 
         #if wxUSE_UNICODE
             #include <wctype.h>
@@ -96,6 +97,9 @@ public:
     // Get the type
     wxXLocale_t Get() const { return m_locale; }
 
+    bool operator== (const wxXLocale& loc) const
+        { return m_locale == loc.m_locale; }
+
 private:
     // Special ctor for the "C" locale, it's only used internally as the user
     // code is supposed to use GetCLocale()
@@ -177,7 +181,7 @@ private:
 
 // A shorter synonym for the most commonly used locale object
 #define wxCLocale (wxXLocale::GetCLocale())
-
+extern WXDLLIMPEXP_DATA_BASE(wxXLocale) wxNullXLocale;
 
 // Wrappers for various functions:
 #ifdef wxHAS_XLOCALE_SUPPORT
@@ -224,7 +228,26 @@ private:
     inline int wxToupper_l(char c, const wxXLocale& loc)
         { return wxCRT_Toupper_lA(static_cast<unsigned char>(c), loc.Get()); }
 
+
+    // stdlib functions for numeric <-> string conversion
+    // NOTE: GNU libc does not have ato[fil]_l functions;
+    //       MSVC++8 does not have _strto[u]ll_l functions;
+    //       thus we take the minimal set of functions provided in both environments:
+
+    #define wxCRT_Strtod_lA wxXLOCALE_IDENT(strtod_l)
+    #define wxCRT_Strtol_lA wxXLOCALE_IDENT(strtol_l)
+    #define wxCRT_Strtoul_lA wxXLOCALE_IDENT(strtoul_l)
+
+    inline double wxStrtod_lA(const char *c, char **endptr, const wxXLocale& loc)
+        { return wxCRT_Strtod_lA(c, endptr, loc.Get()); }
+    inline long wxStrtol_lA(const char *c, char **endptr, int base, const wxXLocale& loc)
+        { return wxCRT_Strtol_lA(c, endptr, base, loc.Get()); }
+    inline unsigned long wxStrtoul_lA(const char *c, char **endptr, int base, const wxXLocale& loc)
+        { return wxCRT_Strtoul_lA(c, endptr, base, loc.Get()); }
+
     #if wxUSE_UNICODE
+    
+        // ctype functions
         #define wxCRT_Isalnum_lW wxXLOCALE_IDENT(iswalnum_l)
         #define wxCRT_Isalpha_lW wxXLOCALE_IDENT(iswalpha_l)
         #define wxCRT_Iscntrl_lW wxXLOCALE_IDENT(iswcntrl_l)
@@ -266,6 +289,20 @@ private:
         inline wchar_t wxToupper_l(wchar_t c, const wxXLocale& loc)
             { return wxCRT_Toupper_lW(c, loc.Get()); }
 
+
+        // stdlib functions for numeric <-> string conversion
+        // (see notes above about missing functions)
+        #define wxCRT_Strtod_lW wxXLOCALE_IDENT(wcstod_l)
+        #define wxCRT_Strtol_lW wxXLOCALE_IDENT(wcstol_l)
+        #define wxCRT_Strtoul_lW wxXLOCALE_IDENT(wcstoul_l)
+
+        inline double wxStrtod_l(const wchar_t *c, wchar_t **endptr, const wxXLocale& loc)
+            { return wxCRT_Strtod_lW(c, endptr, loc.Get()); }
+        inline long wxStrtol_l(const wchar_t *c, wchar_t **endptr, int base, const wxXLocale& loc)
+            { return wxCRT_Strtol_lW(c, endptr, base, loc.Get()); }
+        inline unsigned long wxStrtoul_l(const wchar_t *c, wchar_t **endptr, int base, const wxXLocale& loc)
+            { return wxCRT_Strtoul_lW(c, endptr, base, loc.Get()); }
+
     #endif // wxUSE_UNICDE (ctype functions)
 #else // !wxHAS_XLOCALE_SUPPORT
     // ctype functions
index 4d36bea6d6b1e9ba91833d55ca9dd31b1610e676..a4246a83416754fb6de2b6e17100f03d852b71b3 100644 (file)
@@ -27,6 +27,8 @@
     number in a standard format it can use:
     @code wxPrintf_l(wxXLocale::GetCLocale(), "%g", number) @endcode
     to do it.
+    
+    See @ref group_funcmacro_locale for a list of wxXLocale-enabled functions.
 
     Conversely, if a program wanted to output the number in French locale, even if
     the current locale is different, it could use wxXLocale(wxLANGUAGE_FRENCH).
     @c wxUSE_XLOCALE was set to 0 during the library compilation.
 
 
-    @section xlocale_func Locale-dependent functions
-
-    Currently the following @c _l-functions are available:
-    - Character classification functions:
-      @c wxIsxxx_l(), e.g. @c wxIsalpha_l(), @c wxIslower_l() and all the others.
-    - Character transformation functions:
-      @c wxTolower_l() and @c wxToupper_l()
-    We hope to provide many more functions (covering numbers, time and formatted
-    IO) in the near future.
-
     @library{wxbase}
     @category{cfg}
 
+    @stdobjects
+    @li ::wxNullXLocale
+    
     @see wxLocale
 */
 class wxXLocale
@@ -98,4 +93,44 @@ public:
         or @false otherwise.
     */
     bool IsOk() const;
+    
+    /**
+        Comparison operator.
+    */
+    bool operator==(const wxXLocale& loc) const;
 };
+
+/**
+    An empty and invalid wxXLocale object.
+*/
+wxXLocale wxNullXLocale;
+
+
+
+// ============================================================================
+// Global functions/macros
+// ============================================================================
+
+/** @addtogroup group_funcmacro_locale */
+//@{
+
+int wxIsalnum_l(wchar_t c, const wxXLocale& loc);
+int wxIsalpha_l(wchar_t c, const wxXLocale& loc);
+int wxIscntrl_l(wchar_t c, const wxXLocale& loc);
+int wxIsdigit_l(wchar_t c, const wxXLocale& loc);
+int wxIsgraph_l(wchar_t c, const wxXLocale& loc);
+int wxIslower_l(wchar_t c, const wxXLocale& loc);
+int wxIsprint_l(wchar_t c, const wxXLocale& loc);
+int wxIspunct_l(wchar_t c, const wxXLocale& loc);
+int wxIsspace_l(wchar_t c, const wxXLocale& loc);
+int wxIsupper_l(wchar_t c, const wxXLocale& loc);
+int wxIsxdigit_l(wchar_t c, const wxXLocale& loc);
+wchar_t wxTolower_l(wchar_t c, const wxXLocale& loc);
+wchar_t wxToupper_l(wchar_t c, const wxXLocale& loc);
+
+double wxStrtod_l(const wchar_t *c, wchar_t **endptr, const wxXLocale& loc);
+long wxStrtol_l(const wchar_t *c, wchar_t **endptr, int base, const wxXLocale& loc);
+unsigned long wxStrtoul_l(const wchar_t *c, wchar_t **endptr, int base, const wxXLocale& loc);
+
+//@}
+
index b04288c64869562cb034d51c12ea097fc7842c79..b2b035aed19af79b86999f53d1833cc8465bc07d 100644 (file)
@@ -38,6 +38,9 @@
 // This is the C locale object, it is created on demand
 static wxXLocale *gs_cLocale = NULL;
 
+wxXLocale wxNullXLocale;
+
+
 // ============================================================================
 // implementation
 // ============================================================================
@@ -100,6 +103,9 @@ wxXLocale::wxXLocale(wxLanguage lang)
 
 void wxXLocale::Init(const char *loc)
 {
+    if (!loc || *loc == '\0')
+        return;
+
     m_locale = _create_locale(LC_ALL, loc);
 }
 
@@ -117,7 +123,38 @@ void wxXLocale::Free()
 
 void wxXLocale::Init(const char *loc)
 {
+    if (!loc || *loc == '\0')
+        return;
+
     m_locale = newlocale(LC_ALL_MASK, loc, NULL);
+    if (!m_locale)
+    {
+        // NOTE: here we do something similar to what wxSetLocaleTryUTF8() does
+        //       in wxLocale code (but with newlocale() calls instead of wxSetlocale())
+        wxString buf(loc);
+        wxString buf2;
+        buf2 = buf + wxS(".UTF-8");
+        m_locale = newlocale(LC_ALL_MASK, buf2, NULL);
+        if ( !m_locale )
+        {
+            buf2 = buf + wxS(".utf-8");
+            m_locale = newlocale(LC_ALL_MASK, buf2, NULL);
+        }
+        if ( !m_locale )
+        {
+            buf2 = buf + wxS(".UTF8");
+            m_locale = newlocale(LC_ALL_MASK, buf2, NULL);
+        }
+        if ( !m_locale )
+        {
+            buf2 = buf + wxS(".utf8");
+            m_locale = newlocale(LC_ALL_MASK, buf2, NULL);
+        }
+    }
+    
+    // TODO: wxLocale performs many more manipulations of the given locale
+    //       string in the attempt to set a valid locale; reusing that code
+    //       (changing it to take a generic wxTryLocale callback) would be nice
 }
 
 void wxXLocale::Free()
index 07172bb09ccb45156f6bdce5ffded7b806a59ef8..d5cf8007c8f3e49916694edbca64cf69c83a547a 100644 (file)
@@ -40,12 +40,15 @@ private:
     CPPUNIT_TEST_SUITE( XLocaleTestCase );
         CPPUNIT_TEST( TestCtor );
         CPPUNIT_TEST( TestCtypeFunctions );
+        CPPUNIT_TEST( TestStdlibFunctions );
     CPPUNIT_TEST_SUITE_END();
 
     void TestCtor();
     void TestCtypeFunctions();
+    void TestStdlibFunctions();
 
     void TestCtypeFunctionsWith(const wxXLocale& loc);
+    void TestStdlibFunctionsWith(const wxXLocale& loc);
 
     DECLARE_NO_COPY_CLASS(XLocaleTestCase)
 };
@@ -63,6 +66,11 @@ void XLocaleTestCase::TestCtor()
     CPPUNIT_ASSERT( !wxXLocale().IsOk() );
     CPPUNIT_ASSERT( wxCLocale.IsOk() );
     CPPUNIT_ASSERT( wxXLocale("C").IsOk() );
+    CPPUNIT_ASSERT( !wxXLocale("bloordyblop").IsOk() );
+
+    if (!wxLocale::IsAvailable(wxLANGUAGE_FRENCH))
+        return;     // you should have french support installed to continue this test!
+
 #ifdef wxHAS_XLOCALE_SUPPORT
     CPPUNIT_ASSERT( wxXLocale(wxLANGUAGE_FRENCH).IsOk() );
 #ifdef __WXMSW__
@@ -71,12 +79,15 @@ void XLocaleTestCase::TestCtor()
     CPPUNIT_ASSERT( wxXLocale("fr_FR").IsOk() );
 #endif
 #endif
-    CPPUNIT_ASSERT( !wxXLocale("bloordyblop").IsOk() );
 }
 
 // test the ctype functions with the given locale
 void XLocaleTestCase::TestCtypeFunctionsWith(const wxXLocale& loc)
 {
+    // NOTE: here go the checks which must pass under _any_ locale "loc";
+    //       checks for specific locales are in TestCtypeFunctions()
+
+
     // isalnum
     CPPUNIT_ASSERT( wxIsalnum_l('0', loc) );
     CPPUNIT_ASSERT( wxIsalnum_l('9', loc) );
@@ -167,20 +178,132 @@ void XLocaleTestCase::TestCtypeFunctionsWith(const wxXLocale& loc)
     CPPUNIT_ASSERT_EQUAL( '9', (char)wxToupper_l('9', loc) );
 }
 
+// test the stdlib functions with the given locale
+void XLocaleTestCase::TestStdlibFunctionsWith(const wxXLocale& loc)
+{
+    // NOTE: here go the checks which must pass under _any_ locale "loc";
+    //       checks for specific locales are in TestStdlibFunctions()
+
+#if wxUSE_UNICODE
+    wchar_t* endptr;
+#else
+    char* endptr;
+#endif
+
+    // strtod (don't use decimal separator as it's locale-specific)
+    CPPUNIT_ASSERT_EQUAL( 0.0,        wxStrtod_l(wxT("0"), NULL, loc) );
+    CPPUNIT_ASSERT_EQUAL( 1234.0,     wxStrtod_l(wxT("1234"), NULL, loc) );
+
+    // strtol
+    endptr = NULL;
+    CPPUNIT_ASSERT_EQUAL( 100,        wxStrtol_l(wxT("100"), NULL, 0, loc) );
+    CPPUNIT_ASSERT_EQUAL( 0xFF,       wxStrtol_l(wxT("0xFF"), NULL, 0, loc) );
+    CPPUNIT_ASSERT_EQUAL( 2001,       wxStrtol_l(wxT("2001 60c0c0 -1101110100110100100000 0x6fffff"), &endptr, 10, loc) );
+    CPPUNIT_ASSERT_EQUAL( 0x60c0c0,   wxStrtol_l(endptr, &endptr, 16, loc) );
+    CPPUNIT_ASSERT_EQUAL( -0x374D20,  wxStrtol_l(endptr, &endptr, 2, loc) );
+    CPPUNIT_ASSERT_EQUAL( 0x6fffff,   wxStrtol_l(endptr, NULL, 0, loc) );
+    
+    // strtoul
+    // NOTE: 3147483647 and 0x12A05F200 are greater than LONG_MAX (on 32bit machines) but
+    //       smaller than ULONG_MAX
+    CPPUNIT_ASSERT_EQUAL( (unsigned long)3147483647,  wxStrtoul_l(wxT("3147483647"), NULL, 0, loc) );
+    CPPUNIT_ASSERT_EQUAL( (unsigned long)0x12A05F200, wxStrtoul_l(wxT("0x12A05F200"), NULL, 0, loc) );
+
+    // TODO: test for "failure" behaviour of the functions above
+}
+
 void XLocaleTestCase::TestCtypeFunctions()
 {
     TestCtypeFunctionsWith(wxCLocale);
 
 #ifdef wxHAS_XLOCALE_SUPPORT
+
+    // french
+
+    if (!wxLocale::IsAvailable(wxLANGUAGE_FRENCH))
+        return;     // you should have french support installed to continue this test!
+
     wxXLocale locFR(wxLANGUAGE_FRENCH);
     CPPUNIT_ASSERT( locFR.IsOk() ); // doesn't make sense to continue otherwise
 
     TestCtypeFunctionsWith(locFR);
 
-    CPPUNIT_ASSERT( wxIsalpha_l('\xe9', locFR) );
-    CPPUNIT_ASSERT( wxIslower_l('\xe9', locFR) );
-    CPPUNIT_ASSERT( !wxIslower_l('\xc9', locFR) );
-    CPPUNIT_ASSERT( wxIsupper_l('\xc9', locFR) );
+    CPPUNIT_ASSERT( wxIsalpha_l(wxT('\xe9'), locFR) );
+    CPPUNIT_ASSERT( wxIslower_l(wxT('\xe9'), locFR) );
+    CPPUNIT_ASSERT( !wxIslower_l(wxT('\xc9'), locFR) );
+    CPPUNIT_ASSERT( wxIsupper_l(wxT('\xc9'), locFR) );
+    CPPUNIT_ASSERT( wxIsalpha_l(wxT('\xe7'), locFR) );
+    CPPUNIT_ASSERT( wxIslower_l(wxT('\xe7'), locFR) );
+    CPPUNIT_ASSERT( wxIsupper_l(wxT('\xc7'), locFR) );
+
+
+    // italian
+
+    if (!wxLocale::IsAvailable(wxLANGUAGE_ITALIAN))
+        return;     // you should have italian support installed to continue this test!
+
+    wxXLocale locIT(wxLANGUAGE_ITALIAN);
+    CPPUNIT_ASSERT( locIT.IsOk() ); // doesn't make sense to continue otherwise
+
+    TestCtypeFunctionsWith(locIT);
+    
+    CPPUNIT_ASSERT( wxIsalpha_l(wxT('\xe1'), locIT) );
+    CPPUNIT_ASSERT( wxIslower_l(wxT('\xe1'), locIT) );
+#endif
+}
+
+void XLocaleTestCase::TestStdlibFunctions()
+{
+    TestStdlibFunctionsWith(wxCLocale);
+
+#if wxUSE_UNICODE
+    wchar_t* endptr;
+#else
+    char* endptr;
+#endif
+
+    // strtod checks specific for C locale
+    endptr = NULL;
+    CPPUNIT_ASSERT_EQUAL( 0.0,        wxStrtod_l(wxT("0.000"), NULL, wxCLocale) );
+    CPPUNIT_ASSERT_EQUAL( 1.234,      wxStrtod_l(wxT("1.234"), NULL, wxCLocale) );
+    CPPUNIT_ASSERT_EQUAL( -1.234E-5,  wxStrtod_l(wxT("-1.234E-5"), NULL, wxCLocale) );
+    CPPUNIT_ASSERT_EQUAL( 365.24,     wxStrtod_l(wxT("365.24 29.53"), &endptr, wxCLocale) );
+    CPPUNIT_ASSERT_EQUAL( 29.53,      wxStrtod_l(endptr, NULL, wxCLocale) );
+
+#ifdef wxHAS_XLOCALE_SUPPORT
+
+    // french
+
+    if (!wxLocale::IsAvailable(wxLANGUAGE_FRENCH))
+        return;     // you should have french support installed to continue this test!
+
+    wxXLocale locFR(wxLANGUAGE_FRENCH);
+    CPPUNIT_ASSERT( locFR.IsOk() ); // doesn't make sense to continue otherwise
+
+    TestCtypeFunctionsWith(locFR);
+
+    // comma as decimal point:
+    CPPUNIT_ASSERT_EQUAL( 1.234, wxStrtod_l(wxT("1,234"), NULL, locFR) );
+    
+    // space as thousands separator is not recognized by wxStrtod_l():
+    CPPUNIT_ASSERT( 1234.5 != wxStrtod_l(wxT("1 234,5"), NULL, locFR) );
+    
+    
+    // italian
+
+    if (!wxLocale::IsAvailable(wxLANGUAGE_ITALIAN))
+        return;     // you should have italian support installed to continue this test!
+
+    wxXLocale locIT(wxLANGUAGE_ITALIAN);
+    CPPUNIT_ASSERT( locIT.IsOk() ); // doesn't make sense to continue otherwise
+
+    TestStdlibFunctionsWith(locIT);
+
+    // comma as decimal point:
+    CPPUNIT_ASSERT_EQUAL( 1.234, wxStrtod_l(wxT("1,234"), NULL, locIT) );
+    
+    // dot as thousands separator is not recognized by wxStrtod_l():
+    CPPUNIT_ASSERT( 1234.5 != wxStrtod_l(wxT("1.234,5"), NULL, locIT) );
 #endif
 }