]> git.saurik.com Git - wxWidgets.git/commitdiff
add the ToCLong, ToCULong and ToCDouble functions, with docs and test units
authorFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Fri, 20 Mar 2009 14:50:06 +0000 (14:50 +0000)
committerFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Fri, 20 Mar 2009 14:50:06 +0000 (14:50 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59645 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/string.h
interface/wx/string.h
src/common/string.cpp
tests/strings/strings.cpp

index bdba1d23cf181b289c79e4752c501a8d198a9a7b..4a2dab67b338e9347aa8bb2f02e4b8effc57e7e9 100644 (file)
@@ -2202,25 +2202,34 @@ public:
     // check if the string contents matches a mask containing '*' and '?'
   bool Matches(const wxString& mask) const;
 
-    // conversion to numbers: all functions return true only if the whole
-    // string is a number and put the value of this number into the pointer
-    // provided, the base is the numeric base in which the conversion should be
-    // done and must be comprised between 2 and 36 or be 0 in which case the
-    // standard C rules apply (leading '0' => octal, "0x" => hex)
-        // convert to a signed integer
-    bool ToLong(long *val, int base = 10) const;
-        // convert to an unsigned integer
-    bool ToULong(unsigned long *val, int base = 10) const;
-        // convert to wxLongLong
+  // conversion to numbers: all functions return true only if the whole
+  // string is a number and put the value of this number into the pointer
+  // provided, the base is the numeric base in which the conversion should be
+  // done and must be comprised between 2 and 36 or be 0 in which case the
+  // standard C rules apply (leading '0' => octal, "0x" => hex)
+      // convert to a signed integer
+  bool ToLong(long *val, int base = 10) const;
+      // convert to an unsigned integer
+  bool ToULong(unsigned long *val, int base = 10) const;
+      // convert to wxLongLong
 #if defined(wxLongLong_t)
-    bool ToLongLong(wxLongLong_t *val, int base = 10) const;
-        // convert to wxULongLong
-    bool ToULongLong(wxULongLong_t *val, int base = 10) const;
+  bool ToLongLong(wxLongLong_t *val, int base = 10) const;
+      // convert to wxULongLong
+  bool ToULongLong(wxULongLong_t *val, int base = 10) const;
 #endif // wxLongLong_t
-        // convert to a double
-    bool ToDouble(double *val) const;
-
-
+      // convert to a double
+  bool ToDouble(double *val) const;
+
+#if wxUSE_XLOCALE
+  // conversions to numbers using C locale
+      // convert to a signed integer
+  bool ToCLong(long *val, int base = 10) const;
+      // convert to an unsigned integer
+  bool ToCULong(unsigned long *val, int base = 10) const;
+      // convert to a double
+  bool ToCDouble(double *val) const;
+#endif
+  
 #ifndef wxNEEDS_WXSTRING_PRINTF_MIXIN
   // formatted input/output
     // as sprintf(), returns the number of characters written or < 0 on error
index fe98211313bc1c53eef21d2a13dd13d044c391af..3056895ba79d9b87e627a7baa4219b5e74be89a4 100644 (file)
@@ -894,21 +894,43 @@ public:
     //@{
 
     /**
-        Attempts to convert the string to a floating point number. Returns @true on
-        success (the number is stored in the location pointed to by @e val) or @false
-        if the string does not represent such number (the value of @a val is not
-        modified in this case).
+        Attempts to convert the string to a floating point number. 
+        
+        Returns @true on success (the number is stored in the location pointed to by 
+        @a val) or @false if the string does not represent such number (the value of 
+        @a val is not modified in this case).
+        
+        Note that unlike ToCDouble() this function uses a localized version of
+        @c wxStrtod() and thus needs as decimal point (and thousands separator) the
+        locale-specific decimal point. Thus you should use this function only when
+        you are sure that this string contains a floating point number formatted with
+        the rules of the locale currently in use (see wxLocale).
+        
+        Refer to the docs of the standard function @c strtod() for more details about
+        the supported syntax.
 
-        @see ToLong(), ToULong()
+        @see ToCDouble(), ToLong(), ToULong()
     */
     bool ToDouble(double* val) const;
 
     /**
-        Attempts to convert the string to a signed integer in base @e base. Returns
-        @true on success in which case the number is stored in the location
+        Works like ToDouble() but unlike it this function expects the floating point
+        number to be formatted always with the rules dictated by the "C" locale
+        (in particular, the decimal point must be a dot), independently from the
+        current application-wide locale (see wxLocale).
+
+        @see ToDouble(), ToLong(), ToULong()
+    */
+    bool ToCDouble(double* val) const;
+
+    /**
+        Attempts to convert the string to a signed integer in base @a base. 
+        
+        Returns @true on success in which case the number is stored in the location
         pointed to by @a val or @false if the string does not represent a
         valid number in the given base (the value of @a val is not modified
         in this case).
+        
         The value of @a base must be comprised between 2 and 36, inclusive, or
         be a special value 0 which means that the usual rules of @c C numbers are
         applied: if the number starts with @c 0x it is considered to be in base
@@ -916,14 +938,31 @@ public:
         that you may not want to specify the base 0 if you are parsing the numbers
         which may have leading zeroes as they can yield unexpected (to the user not
         familiar with C) results.
+        
+        Note that unlike ToCLong() this function uses a localized version of
+        @c wxStrtol(). Thus you should use this function only when you are sure 
+        that this string contains an integer number formatted with
+        the rules of the locale currently in use (see wxLocale).
+        
+        Refer to the docs of the standard function @c strtol() for more details about
+        the supported syntax.
 
-        @see ToDouble(), ToULong()
+        @see ToCDouble(), ToDouble(), ToULong()
     */
     bool ToLong(long* val, int base = 10) const;
 
     /**
-        This is exactly the same as ToLong() but works with 64
-        bit integer numbers.
+        Works like ToLong() but unlike it this function expects the integer
+        number to be formatted always with the rules dictated by the "C" locale, 
+        independently from the current application-wide locale (see wxLocale).
+
+        @see ToDouble(), ToLong(), ToULong()
+    */
+    bool ToCLong(long* val, int base = 10) const;
+
+    /**
+        This is exactly the same as ToLong() but works with 64 bit integer numbers.
+        
         Notice that currently it doesn't work (always returns @false) if parsing of 64
         bit numbers is not supported by the underlying C run-time library. Compilers
         with C99 support and Microsoft Visual C++ version 7 and higher do support this.
@@ -933,7 +972,8 @@ public:
     bool ToLongLong(wxLongLong_t* val, int base = 10) const;
 
     /**
-        Attempts to convert the string to an unsigned integer in base @e base.
+        Attempts to convert the string to an unsigned integer in base @a base.
+        
         Returns @true on success in which case the number is stored in the
         location pointed to by @a val or @false if the string does not
         represent a valid number in the given base (the value of @a val is not
@@ -943,12 +983,22 @@ public:
         @c strtoul() and so it simply converts negative numbers to unsigned
         representation instead of rejecting them (e.g. -1 is returned as @c ULONG_MAX).
 
-        See ToLong() for the more detailed description of the @a base parameter.
+        See ToLong() for the more detailed description of the @a base parameter
+        (and of the locale-specific behaviour of this function).
 
-        @see ToDouble(), ToLong()
+        @see ToCULong(), ToDouble(), ToLong()
     */
     bool ToULong(unsigned long* val, int base = 10) const;
 
+    /**
+        Works like ToULong() but unlike it this function expects the integer
+        number to be formatted always with the rules dictated by the "C" locale, 
+        independently from the current application-wide locale (see wxLocale).
+
+        @see ToDouble(), ToLong(), ToULong()
+    */
+    bool ToCULong(unsigned long* val, int base = 10) const;
+
     /**
         This is exactly the same as ToULong() but works with 64
         bit integer numbers.
index e07b7eea8f74554e9350b0a402b5977528296c34..ed7a6a8670f42d467fd72028e22a8cefdc8d4eac 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "wx/hashmap.h"
 #include "wx/vector.h"
+#include "wx/xlocale.h"
 
 // string handling functions used by wxString:
 #if wxUSE_UNICODE_UTF8
@@ -1644,64 +1645,105 @@ int wxString::Find(wxUniChar ch, bool bFromEnd) const
     #define DO_IF_NOT_WINCE(x)
 #endif
 
-#define WX_STRING_TO_INT_TYPE(out, base, func, T)                           \
-    wxCHECK_MSG( out, false, _T("NULL output pointer") );                   \
-    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );  \
-                                                                            \
+#define WX_STRING_TO_X_TYPE_START                                           \
+    wxCHECK_MSG( pVal, false, _T("NULL output pointer") );                  \
     DO_IF_NOT_WINCE( errno = 0; )                                           \
-                                                                            \
     const wxStringCharType *start = wx_str();                               \
-    wxStringCharType *end;                                                  \
-    T val = func(start, &end, base);                                        \
-                                                                            \
+    wxStringCharType *end;
+
+#define WX_STRING_TO_X_TYPE_END                                             \
     /* return true only if scan was stopped by the terminating NUL and */   \
     /* if the string was not empty to start with and no under/overflow */   \
     /* occurred: */                                                         \
     if ( *end || end == start DO_IF_NOT_WINCE(|| errno == ERANGE) )         \
         return false;                                                       \
-    *out = val;                                                             \
-    return true
+    *pVal = val;                                                            \
+    return true;
 
 bool wxString::ToLong(long *pVal, int base) const
 {
-    WX_STRING_TO_INT_TYPE(pVal, base, wxStrtol, long);
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+    WX_STRING_TO_X_TYPE_START
+    long val = wxStrtol(start, &end, base);
+    WX_STRING_TO_X_TYPE_END
 }
 
 bool wxString::ToULong(unsigned long *pVal, int base) const
 {
-    WX_STRING_TO_INT_TYPE(pVal, base, wxStrtoul, unsigned long);
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+    WX_STRING_TO_X_TYPE_START
+    unsigned long val = wxStrtoul(start, &end, base);
+    WX_STRING_TO_X_TYPE_END
 }
 
 bool wxString::ToLongLong(wxLongLong_t *pVal, int base) const
 {
-    WX_STRING_TO_INT_TYPE(pVal, base, wxStrtoll, wxLongLong_t);
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+    WX_STRING_TO_X_TYPE_START
+    wxLongLong_t val = wxStrtoll(start, &end, base);
+    WX_STRING_TO_X_TYPE_END
 }
 
 bool wxString::ToULongLong(wxULongLong_t *pVal, int base) const
 {
-    WX_STRING_TO_INT_TYPE(pVal, base, wxStrtoull, wxULongLong_t);
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+    WX_STRING_TO_X_TYPE_START
+    wxULongLong_t val = wxStrtoull(start, &end, base);
+    WX_STRING_TO_X_TYPE_END
 }
 
 bool wxString::ToDouble(double *pVal) const
 {
-    wxCHECK_MSG( pVal, false, _T("NULL output pointer") );
+    WX_STRING_TO_X_TYPE_START
+    double val = wxStrtod(start, &end);
+    WX_STRING_TO_X_TYPE_END
+}
 
-    DO_IF_NOT_WINCE( errno = 0; )
+#if wxUSE_XLOCALE
 
-    const wxChar *start = c_str();
-    wxChar *end;
-    double val = wxStrtod(start, &end);
+bool wxString::ToCLong(long *pVal, int base) const
+{
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
-    // return true only if scan was stopped by the terminating NUL and if the
-    // string was not empty to start with and no under/overflow occurred
-    if ( *end || end == start DO_IF_NOT_WINCE(|| errno == ERANGE) )
-        return false;
+    WX_STRING_TO_X_TYPE_START
+#if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
+    long val = wxStrtol_lA(start, &end, base, wxCLocale);
+#else
+    long val = wxStrtol_l(start, &end, base, wxCLocale);
+#endif
+    WX_STRING_TO_X_TYPE_END
+}
 
-    *pVal = val;
+bool wxString::ToCULong(unsigned long *pVal, int base) const
+{
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
-    return true;
+    WX_STRING_TO_X_TYPE_START
+#if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
+    unsigned long val = wxStrtoul_lA(start, &end, base, wxCLocale);
+#else
+    unsigned long val = wxStrtoul_l(start, &end, base, wxCLocale);
+#endif
+    WX_STRING_TO_X_TYPE_END
 }
 
+bool wxString::ToCDouble(double *pVal) const
+{
+    WX_STRING_TO_X_TYPE_START
+#if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
+    double val = wxStrtod_lA(start, &end, wxCLocale);
+#else
+    double val = wxStrtod_l(start, &end, wxCLocale);
+#endif
+    WX_STRING_TO_X_TYPE_END
+}
+
+#endif  // wxUSE_XLOCALE
+
 // ---------------------------------------------------------------------------
 // formatted output
 // ---------------------------------------------------------------------------
index 01c15182e796fceec1e3ba3527b24d6ef95a3430..b29747338ade7436b10072d2cd4b1c62f2171de1 100644 (file)
@@ -588,6 +588,13 @@ void StringTestCase::ToLong()
 
         if ( ld.flags & (Number_LongLong | Number_Unsigned) )
             continue;
+        
+        // NOTE: unless you're using some exotic locale, ToCLong and ToLong
+        //       should behave the same for our test data set:
+
+        CPPUNIT_ASSERT_EQUAL( ld.IsOk(), wxString(ld.str).ToCLong(&l) );
+        if ( ld.IsOk() )
+            CPPUNIT_ASSERT_EQUAL( ld.LValue(), l );
 
         CPPUNIT_ASSERT_EQUAL( ld.IsOk(), wxString(ld.str).ToLong(&l) );
         if ( ld.IsOk() )
@@ -605,6 +612,13 @@ void StringTestCase::ToULong()
         if ( ld.flags & (Number_LongLong | Number_Signed) )
             continue;
 
+        // NOTE: unless you're using some exotic locale, ToCLong and ToLong
+        //       should behave the same for our test data set:
+
+        CPPUNIT_ASSERT_EQUAL( ld.IsOk(), wxString(ld.str).ToCULong(&ul) );
+        if ( ld.IsOk() )
+            CPPUNIT_ASSERT_EQUAL( ld.ULValue(), ul );
+        
         CPPUNIT_ASSERT_EQUAL( ld.IsOk(), wxString(ld.str).ToULong(&ul) );
         if ( ld.IsOk() )
             CPPUNIT_ASSERT_EQUAL( ld.ULValue(), ul );
@@ -667,20 +681,59 @@ void StringTestCase::ToDouble()
         { _T("12345"), 12345, true },
         { _T("-1"), -1, true },
         { _T("--1"), 0, false },
+        { _T("-3E-5"), -3E-5, true },
+        { _T("-3E-abcde5"), 0, false },
     };
 
-    // we need to use decimal point, not comma or whatever is its value for the
-    // current locale
-    wxSetlocale(LC_ALL, "C");
+    // test ToCDouble() first:
 
     size_t n;
     for ( n = 0; n < WXSIZEOF(doubleData); n++ )
     {
         const ToDoubleData& ld = doubleData[n];
+        CPPUNIT_ASSERT_EQUAL( ld.ok, wxString(ld.str).ToCDouble(&d) );
+        if ( ld.ok )
+            CPPUNIT_ASSERT_EQUAL( ld.value, d );
+    }
+
+
+    // test ToDouble() now:
+    // NOTE: for the test to be reliable, we need to set the locale explicitely
+    //       so that we know the decimal point character to use
+
+    if (!wxLocale::IsAvailable(wxLANGUAGE_FRENCH))
+        return;     // you should have french support installed to continue this test!
+
+    wxLocale *locale = new wxLocale;
+    
+    // don't load default catalog, it may be unavailable:
+    CPPUNIT_ASSERT( locale->Init(wxLANGUAGE_FRENCH, wxLOCALE_CONV_ENCODING) );
+    
+    static const struct ToDoubleData doubleData2[] =
+    {
+        { _T("1"), 1, true },
+        { _T("1,23"), 1.23, true },
+        { _T(",1"), .1, true },
+        { _T("1,"), 1, true },
+        { _T("1,,"), 0, false },
+        { _T("0"), 0, true },
+        { _T("a"), 0, false },
+        { _T("12345"), 12345, true },
+        { _T("-1"), -1, true },
+        { _T("--1"), 0, false },
+        { _T("-3E-5"), -3E-5, true },
+        { _T("-3E-abcde5"), 0, false },
+    };
+
+    for ( n = 0; n < WXSIZEOF(doubleData2); n++ )
+    {
+        const ToDoubleData& ld = doubleData2[n];
         CPPUNIT_ASSERT_EQUAL( ld.ok, wxString(ld.str).ToDouble(&d) );
         if ( ld.ok )
             CPPUNIT_ASSERT_EQUAL( ld.value, d );
     }
+    
+    delete locale;
 }
 
 void StringTestCase::StringBuf()