]> 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;
 
     // 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)
 #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
 #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
 #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;
 
     /**
     */
     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).
         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
         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.
         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;
 
     /**
     */
     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.
         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;
 
     /**
     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
         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).
 
         @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;
 
     */
     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.
     /**
         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/hashmap.h"
 #include "wx/vector.h"
+#include "wx/xlocale.h"
 
 // string handling functions used by wxString:
 #if wxUSE_UNICODE_UTF8
 
 // 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 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; )                                           \
     DO_IF_NOT_WINCE( errno = 0; )                                           \
-                                                                            \
     const wxStringCharType *start = wx_str();                               \
     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;                                                       \
     /* 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
 {
 
 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
 {
 }
 
 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
 {
 }
 
 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
 {
 }
 
 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
 {
 }
 
 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
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 // formatted output
 // ---------------------------------------------------------------------------
index 01c15182e796fceec1e3ba3527b24d6ef95a3430..b29747338ade7436b10072d2cd4b1c62f2171de1 100644 (file)
@@ -588,6 +588,13 @@ void StringTestCase::ToLong()
 
         if ( ld.flags & (Number_LongLong | Number_Unsigned) )
             continue;
 
         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() )
 
         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;
 
         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 );
         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("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];
 
     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 );
     }
         CPPUNIT_ASSERT_EQUAL( ld.ok, wxString(ld.str).ToDouble(&d) );
         if ( ld.ok )
             CPPUNIT_ASSERT_EQUAL( ld.value, d );
     }
+    
+    delete locale;
 }
 
 void StringTestCase::StringBuf()
 }
 
 void StringTestCase::StringBuf()