[grisbi-cvs] grisbi/src gsb_real.c, 1.43, 1.44 gsb_real.h, 1.17, 1.18 gsb_real_cunit.c, 1.9, 1.10

Mickaƫl Remars mykeul at users.sourceforge.net
Thu May 21 11:04:51 CEST 2009


Update of /cvsroot/grisbi/grisbi/src
In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv21543/src

Modified Files:
	gsb_real.c gsb_real.h gsb_real_cunit.c 
Log Message:
Added new function gsb_real_raw_get_from_string() and its unit-tests

Index: gsb_real.c
===================================================================
RCS file: /cvsroot/grisbi/grisbi/src/gsb_real.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- gsb_real.c	20 May 2009 21:15:06 -0000	1.43
+++ gsb_real.c	21 May 2009 09:04:48 -0000	1.44
@@ -307,6 +307,99 @@
 }
 
 
+/**
+ * get a gsb_real number from a string
+ * the string can be formatted :
+ * - spaces and the given utf8-encoded thousands separators are ignored
+ * - handle ",", "." and the given utf8-encoded decimal separator
+ * - another character makes a error_real return
+ *
+ * \param string
+ * \param mon_thousands_sep, can be NULL or empty, but only one utf8 sequence
+ * \param mon_decimal_point, can be NULL or empty, but only one utf8 sequence
+ *
+ * \return the number in the string transformed to gsb_real
+ */
+gsb_real gsb_real_raw_get_from_string ( const gchar *string,
+                                        const gchar *mon_thousands_sep,
+                                        const gchar *mon_decimal_point )
+{
+    assert ( !mon_thousands_sep || ( g_utf8_strlen ( mon_thousands_sep, -1 ) <= 1 ) );
+    assert ( !mon_decimal_point || ( g_utf8_strlen ( mon_decimal_point, -1 ) <= 1 ) );
+
+    if ( !string)
+        return error_real;
+
+    unsigned mts_len = mon_thousands_sep
+                       ? strlen ( mon_thousands_sep )
+                       : 0;
+    unsigned mdp_len = mon_decimal_point ? strlen ( mon_decimal_point ) : 0;
+
+    static const gchar *space_chars = " ";
+    static const gchar *decimal_chars = ".,";
+    static const gchar *positive_chars = "+";
+    static const gchar *negative_chars = "-";
+
+    unsigned nb_digits = 0;
+    gint64 mantissa = 0;
+    gint8 sign = 0;
+    gint8 dot_position = -1;
+    const gchar *p = string;
+    for ( ; ; )
+    {
+        if ( g_ascii_isdigit ( *p ) )
+        {
+            mantissa *= 10;
+            mantissa += ( *p - '0' );
+            if ( mantissa > G_MAXLONG )
+                return error_real;
+            if ( sign == 0 ) sign = 1; // no sign found yet ==> positive
+            ++nb_digits;
+            ++p;
+        }
+        else if ( *p == 0 ) // terminal zero
+        {
+            gint exponent = ( dot_position >= 0 )
+                              ? nb_digits - dot_position
+                              : 0;
+            gsb_real result = { sign * mantissa, exponent };
+            return result;
+        }
+        else if ( strchr ( space_chars, *p )
+             || ( mts_len && ( strncmp ( p, mon_thousands_sep, mts_len ) == 0 ) ) )
+        {
+            // just skip spaces and thousands separators
+            p = g_utf8_find_next_char ( p, NULL );
+        }
+        else if ( strchr ( decimal_chars, *p )
+             || ( mdp_len && ( strncmp ( p, mon_decimal_point, mdp_len ) == 0 ) ) )
+        {
+            if ( dot_position >= 0 ) // already found a decimal separator
+                return error_real;
+            dot_position = nb_digits;
+            p = g_utf8_find_next_char ( p, NULL );
+        }
+        else if ( strchr ( negative_chars, *p ) )
+        {
+            if ( sign != 0 ) // sign already set
+                return error_real;
+            sign = -1;
+            ++p;
+        }
+        else if ( strchr ( positive_chars, *p ) )
+        {
+            if ( sign != 0 ) // sign already set
+                return error_real;
+            sign = 1;
+            ++p;
+        }
+        else // unknown char ==> error
+        {
+            return error_real;
+        }
+    }
+}
+
 
 /**
  * get a real number from a string

Index: gsb_real_cunit.c
===================================================================
RCS file: /cvsroot/grisbi/grisbi/src/gsb_real_cunit.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- gsb_real_cunit.c	20 May 2009 21:15:06 -0000	1.9
+++ gsb_real_cunit.c	21 May 2009 09:04:48 -0000	1.10
@@ -73,6 +73,237 @@
     CU_ASSERT_EQUAL(0, val.exponent);
 }
 
+void gsb_real_cunit__gsb_real_raw_get_from_string()
+{
+    gsb_real val;
+    // NULL ==> error
+    val = gsb_real_raw_get_from_string ( NULL, NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    val = gsb_real_raw_get_from_string ( "", NULL, NULL );
+    // empty ==> 0
+    CU_ASSERT_EQUAL ( 0, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    val = gsb_real_raw_get_from_string ( "0", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    val = gsb_real_raw_get_from_string ( "1", NULL, NULL );
+    CU_ASSERT_EQUAL ( 1, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    val = gsb_real_raw_get_from_string ( "12", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // ignore left spaces
+    val = gsb_real_raw_get_from_string ( "   12", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // ignore right spaces
+    val = gsb_real_raw_get_from_string ( "12   ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // ignore left-middle-right spaces
+    val = gsb_real_raw_get_from_string ( "    1   2   ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // significant zeros
+    val = gsb_real_raw_get_from_string ( "12000", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // useless zeros
+    val = gsb_real_raw_get_from_string ( "00012", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // comma decimal separator
+    val = gsb_real_raw_get_from_string ( "123,45", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12345, val.mantissa );
+    CU_ASSERT_EQUAL ( 2, val.exponent );
+
+    // dot decimal separator
+    val = gsb_real_raw_get_from_string ( "123.45", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12345, val.mantissa );
+    CU_ASSERT_EQUAL ( 2, val.exponent );
+
+    // decimal separator with spaces
+    val = gsb_real_raw_get_from_string ( "  123  .  45  ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12345, val.mantissa );
+    CU_ASSERT_EQUAL ( 2, val.exponent );
+
+    // decimal separator with space, and zeroes
+    val = gsb_real_raw_get_from_string ( "0 0123.4500", NULL, NULL );
+    CU_ASSERT_EQUAL ( 1234500, val.mantissa );
+    CU_ASSERT_EQUAL ( 4, val.exponent );
+
+    // decimal separator with space, zero, and value less than 1
+    val = gsb_real_raw_get_from_string ( "  0.123  45 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12345, val.mantissa );
+    CU_ASSERT_EQUAL ( 5, val.exponent );
+
+    // decimal separator with space, no zero, and value less than 1
+    val = gsb_real_raw_get_from_string ( "  .123  45 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12345, val.mantissa );
+    CU_ASSERT_EQUAL ( 5, val.exponent );
+
+    // multiple decimal separators ==> error
+    val = gsb_real_raw_get_from_string ( "  123  .  45 . ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // large number
+    val = gsb_real_raw_get_from_string ( "21000000", NULL, NULL );
+    CU_ASSERT_EQUAL ( 21000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // large number with thousands separators
+    val = gsb_real_raw_get_from_string ( "21 000 000", NULL, NULL );
+    CU_ASSERT_EQUAL ( 21000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // large number (largest-1) with thousands separators
+    val = gsb_real_raw_get_from_string ( " 2 147 483 646 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 2147483646, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // largest positive number with thousands separators
+    val = gsb_real_raw_get_from_string ( " 2 147 483 647 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 2147483647, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // too large positive number ==> error
+    val = gsb_real_raw_get_from_string ( " 2 147 483 648 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // too large positive number ==> error
+    val = gsb_real_raw_get_from_string ( " 2 147 483 649 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // very large positive number ==> error
+    val = gsb_real_raw_get_from_string ( " 112 147 483 649 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // 0 with positive sign
+    val = gsb_real_raw_get_from_string ( "+0", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // 0 with negative sign
+    val = gsb_real_raw_get_from_string ( "-0", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // negative number
+    val = gsb_real_raw_get_from_string ( "-1", NULL, NULL );
+    CU_ASSERT_EQUAL ( -1, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // positive number
+    val = gsb_real_raw_get_from_string ( "+1", NULL, NULL );
+    CU_ASSERT_EQUAL ( 1, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // negative two digits
+    val = gsb_real_raw_get_from_string ( "-12", NULL, NULL );
+    CU_ASSERT_EQUAL ( -12, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // positive two digits
+    val = gsb_real_raw_get_from_string ( "+12", NULL, NULL );
+    CU_ASSERT_EQUAL ( 12, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // negative sign at unexpected position ==> error
+    val = gsb_real_raw_get_from_string ( "1-2", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // positive sign at unexpected position ==> error
+    val = gsb_real_raw_get_from_string ( "1+2", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // two signs ==> error
+    val = gsb_real_raw_get_from_string ( "-1+2", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // two signs ==> error
+    val = gsb_real_raw_get_from_string ( "+1-2", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // two signs ==> error
+    val = gsb_real_raw_get_from_string ( "--1", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // decimal separator, no zero, and value less than 1
+    val = gsb_real_raw_get_from_string ( "-.12345", NULL, NULL );
+    CU_ASSERT_EQUAL ( -12345, val.mantissa );
+    CU_ASSERT_EQUAL ( 5, val.exponent );
+
+    // large negative number (largest+1) with thousands separators
+    val = gsb_real_raw_get_from_string ( " -2 147 483 646 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( -2147483646, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // largest negative number with thousands separators
+    val = gsb_real_raw_get_from_string ( " -2 147 483 647 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( -2147483647, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // too large negative number ==> error
+    val = gsb_real_raw_get_from_string ( " -2 147 483 648 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // too large negative number ==> error
+    val = gsb_real_raw_get_from_string ( " -2 147 483 649 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // too large negative number ==> error
+    val = gsb_real_raw_get_from_string ( " -112 147 483 649 ", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+
+    // error number as string ==> error
+    val = gsb_real_raw_get_from_string ( "###ERR###", NULL, NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+}
+
+void gsb_real_cunit__gsb_real_raw_get_from_string__locale()
+{
+    gsb_real val;
+    // locale's thousands separator override comma
+    val = gsb_real_raw_get_from_string ( "1,000.00", ",", "." );
+    CU_ASSERT_EQUAL ( 100000, val.mantissa );
+    CU_ASSERT_EQUAL ( 2, val.exponent );
+
+    // utf8 thousands separator (non-break space)
+    gchar tmp[] = { '1', 0xC2, 0xA0, '0', '0', '0', '.', '0', '0', 0x0 };
+    val = gsb_real_raw_get_from_string ( tmp, "\xC2\xA0", NULL );
+    CU_ASSERT_EQUAL ( 100000, val.mantissa );
+    CU_ASSERT_EQUAL ( 2, val.exponent );
+
+    // non-break space used as separator, but locale says somthing else
+    val = gsb_real_raw_get_from_string ( tmp, "\xC2\xA1", NULL );
+    CU_ASSERT_EQUAL ( 0x80000000, val.mantissa );
+    CU_ASSERT_EQUAL ( 0, val.exponent );
+}
+
 void gsb_real_cunit__gsb_real_raw_format_string ( void )
 {
     gchar *s;
@@ -397,12 +628,14 @@
     if(NULL == pSuite)
         return NULL;
 
-    if((NULL == CU_add_test(pSuite, "of gsb_real_get_from_string()",   gsb_real_cunit__gsb_real_get_from_string))
-    || (NULL == CU_add_test(pSuite, "of gsb_real_raw_format_string()", gsb_real_cunit__gsb_real_raw_format_string))
-    || (NULL == CU_add_test(pSuite, "of gsb_real_gsb_real_normalize()",  gsb_real_cunit__gsb_real_normalize))
-    || (NULL == CU_add_test(pSuite, "of gsb_real_add()",               gsb_real_cunit__gsb_real_add))
-    || (NULL == CU_add_test(pSuite, "of gsb_real_sub()",               gsb_real_cunit__gsb_real_sub))
-    || (NULL == CU_add_test(pSuite, "of gsb_real_mul()",               gsb_real_cunit__gsb_real_mul))
+    if ( ( NULL == CU_add_test( pSuite, "of gsb_real_get_from_string()",     gsb_real_cunit__gsb_real_get_from_string ) )
+      || ( NULL == CU_add_test( pSuite, "of gsb_real_raw_get_from_string()", gsb_real_cunit__gsb_real_raw_get_from_string ) )
+      || ( NULL == CU_add_test( pSuite, "of gsb_real_raw_get_from_string() with locale", gsb_real_cunit__gsb_real_raw_get_from_string__locale ) )
+      || ( NULL == CU_add_test( pSuite, "of gsb_real_raw_format_string()",   gsb_real_cunit__gsb_real_raw_format_string ) )
+      || ( NULL == CU_add_test( pSuite, "of gsb_real_gsb_real_normalize()",  gsb_real_cunit__gsb_real_normalize ) )
+      || ( NULL == CU_add_test( pSuite, "of gsb_real_add()",                 gsb_real_cunit__gsb_real_add ) )
+      || ( NULL == CU_add_test( pSuite, "of gsb_real_sub()",                 gsb_real_cunit__gsb_real_sub ) )
+      || ( NULL == CU_add_test( pSuite, "of gsb_real_mul()",                 gsb_real_cunit__gsb_real_mul ) )
        )
         return NULL;
 

Index: gsb_real.h
===================================================================
RCS file: /cvsroot/grisbi/grisbi/src/gsb_real.h,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- gsb_real.h	20 May 2009 19:49:29 -0000	1.17
+++ gsb_real.h	21 May 2009 09:04:48 -0000	1.18
@@ -28,6 +28,9 @@
 gsb_real gsb_real_div ( gsb_real number_1,
                         gsb_real number_2 );
 gsb_real gsb_real_double_to_real ( gdouble number );
+gsb_real gsb_real_raw_get_from_string ( const gchar *string,
+                                        const gchar *mon_thousands_sep,
+                                        const gchar *mon_decimal_point );
 gsb_real gsb_real_get_from_string ( const gchar *string );
 gchar *gsb_real_get_string ( gsb_real number );
 gchar *gsb_real_get_string_with_currency ( gsb_real number,



More information about the cvs mailing list