gnucash stable: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Tue Aug 29 07:38:30 EDT 2023


Updated	 via  https://github.com/Gnucash/gnucash/commit/7ce4198c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/75f6ee18 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c45b9736 (commit)
	from  https://github.com/Gnucash/gnucash/commit/9802c809 (commit)



commit 7ce4198c20e290eabcfb98712b98d0f54efbad06
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue Aug 29 08:29:53 2023 +0800

    rename string_to_gnc_numeric to gnc_numeric_from_string

diff --git a/bindings/python/gnucash_core.py b/bindings/python/gnucash_core.py
index c688097f4b..8903f7c555 100644
--- a/bindings/python/gnucash_core.py
+++ b/bindings/python/gnucash_core.py
@@ -49,8 +49,8 @@ from gnucash.gnucash_core_c import gncInvoiceLookup, gncInvoiceGetInvoiceFromTxn
     gnc_search_customer_on_id, gnc_search_bill_on_id , \
     gnc_search_vendor_on_id, gncInvoiceNextID, gncCustomerNextID, \
     gncVendorNextID, gncTaxTableGetTables, gnc_numeric_zero, \
-    gnc_numeric_create, double_to_gnc_numeric, string_to_gnc_numeric, \
-    gnc_numeric_to_string
+    gnc_numeric_create, double_to_gnc_numeric, gnc_numeric_from_string, \
+    gnc_numeric_to_string, gnc_numeric_check
 
 from gnucash.deprecation import (
     deprecated_args_session,
@@ -432,8 +432,8 @@ class GncNumeric(GnuCashCoreClass):
             elif isinstance(arg, float):
                 return double_to_gnc_numeric(arg, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER)
             elif isinstance(arg, str):
-                instance = gnc_numeric_zero()
-                if not string_to_gnc_numeric(arg, instance):
+                instance = gnc_numeric_from_string(arg)
+                if gnc_numeric_check(instance):
                     raise TypeError('Failed to convert to GncNumeric: ' + str(args))
                 return instance
             elif isinstance(arg, GncNumeric):
diff --git a/gnucash/gnome/dialog-fincalc.c b/gnucash/gnome/dialog-fincalc.c
index b6477d44ed..0b7afab19d 100644
--- a/gnucash/gnome/dialog-fincalc.c
+++ b/gnucash/gnome/dialog-fincalc.c
@@ -194,9 +194,8 @@ gui_to_fi (FinCalcDialog *fcd)
     text = gtk_entry_get_text (GTK_ENTRY(entry));
     if (text && *text)
     {
-        gnc_numeric out;
-        gboolean result = string_to_gnc_numeric (text, &out);
-        if (result)
+        gnc_numeric out = gnc_numeric_from_string (text);
+        if (!gnc_numeric_check (out))
             npp = gnc_numeric_convert (out, 1, GNC_HOW_RND_TRUNC);
         else
             npp = gnc_numeric_zero ();
diff --git a/gnucash/import-export/log-replay/gnc-log-replay.c b/gnucash/import-export/log-replay/gnc-log-replay.c
index 68244a4b56..98885753dd 100644
--- a/gnucash/import-export/log-replay/gnc-log-replay.c
+++ b/gnucash/import-export/log-replay/gnc-log-replay.c
@@ -233,12 +233,12 @@ static split_record interpret_split_record( char *record_line)
     }
     if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
     {
-        string_to_gnc_numeric(tok_ptr, &(record.amount));
+        record.amount = gnc_numeric_from_string (tok_ptr);
         record.amount_present = TRUE;
     }
     if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
     {
-        string_to_gnc_numeric(tok_ptr, &(record.value));
+        record.value = gnc_numeric_from_string (tok_ptr);
         record.value_present = TRUE;
     }
     if (strlen(tok_ptr = my_strtok(NULL, "\t")) != 0)
diff --git a/libgnucash/app-utils/gnc-exp-parser.c b/libgnucash/app-utils/gnc-exp-parser.c
index ebca57a74a..9d4545a82d 100644
--- a/libgnucash/app-utils/gnc-exp-parser.c
+++ b/libgnucash/app-utils/gnc-exp-parser.c
@@ -98,10 +98,9 @@ gnc_exp_parser_real_init ( gboolean addPredefined )
             for (key = keys; key && *key; key++)
             {
                 str_value = g_key_file_get_string(key_file, GEP_GROUP_NAME, *key, NULL);
-                if (str_value && string_to_gnc_numeric(str_value, &value))
-                {
+                value = gnc_numeric_from_string (str_value);
+                if (!gnc_numeric_check (value))
                     gnc_exp_parser_set_value (*key, gnc_numeric_reduce (value));
-                }
             }
             g_strfreev(keys);
             g_key_file_free(key_file);
diff --git a/libgnucash/backend/xml/io-gncxml-v1.cpp b/libgnucash/backend/xml/io-gncxml-v1.cpp
index 7791205dde..d7aecc4b18 100644
--- a/libgnucash/backend/xml/io-gncxml-v1.cpp
+++ b/libgnucash/backend/xml/io-gncxml-v1.cpp
@@ -472,6 +472,13 @@ simple_kvp_value_parser_new (sixtp_end_handler end_handler)
 
  */
 
+static gboolean
+string_to_gnc_numeric(const gchar* str, gnc_numeric *n)
+{
+    *n = gnc_numeric_from_string (str);
+    return (!gnc_numeric_check (*n));
+}
+
 /* ------------------------------------------------------------ */
 /* generic type copnversion for kvp types */
 #define KVP_CVT_VALUE(TYPE)                 \
diff --git a/libgnucash/backend/xml/sixtp-dom-parsers.cpp b/libgnucash/backend/xml/sixtp-dom-parsers.cpp
index b1d30d2640..f59a0afd5b 100644
--- a/libgnucash/backend/xml/sixtp-dom-parsers.cpp
+++ b/libgnucash/backend/xml/sixtp-dom-parsers.cpp
@@ -509,8 +509,8 @@ dom_tree_to_gnc_numeric (xmlNodePtr node)
     if (!content)
         return gnc_numeric_zero ();
 
-    gnc_numeric num;
-    if (!string_to_gnc_numeric (content, &num))
+    gnc_numeric num = gnc_numeric_from_string (content);
+    if (gnc_numeric_check (num))
         num = gnc_numeric_zero ();
 
     g_free (content);
diff --git a/libgnucash/backend/xml/sixtp-utils.cpp b/libgnucash/backend/xml/sixtp-utils.cpp
index 0cf032b6ca..b65d547357 100644
--- a/libgnucash/backend/xml/sixtp-utils.cpp
+++ b/libgnucash/backend/xml/sixtp-utils.cpp
@@ -611,7 +611,8 @@ generic_gnc_numeric_end_handler (gpointer data_for_children,
         num = g_new (gnc_numeric, 1);
         if (num)
         {
-            if (string_to_gnc_numeric (txt, num))
+            *num = gnc_numeric_from_string (txt);
+            if (!gnc_numeric_check (*num))
             {
                 ok = TRUE;
                 *result = num;

commit 75f6ee181709f76bae33d66397a90fb74ad0fad6
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Aug 28 00:40:10 2023 +0800

    [test-scm-engine] tests gnc-numeric-from-string

diff --git a/bindings/guile/test/test-scm-engine.scm b/bindings/guile/test/test-scm-engine.scm
index 098ab21928..c85791c6c1 100644
--- a/bindings/guile/test/test-scm-engine.scm
+++ b/bindings/guile/test/test-scm-engine.scm
@@ -6,9 +6,45 @@
   (test-runner-factory gnc:test-runner)
   (test-begin "test-engine")
   (test-engine)
+  (test-gnc-numeric-from-string)
   (test-end "test-engine"))
 
 (define (test-engine)
   (test-begin "testing function availability")
 
   (test-end "testing deprecated functions"))
+
+(define (test-gnc-numeric-from-string)
+  (test-equal "gnc-numeric-from-string 1"
+    1
+    (gnc-numeric-from-string "1"))
+
+  (test-equal "gnc-numeric-from-string 3/4"
+    3/4
+    (gnc-numeric-from-string "3/4"))
+
+  (test-equal "gnc-numeric-from-string 12 3/4"
+    51/4
+    (gnc-numeric-from-string "12 3/4"))
+
+  (test-equal "gnc-numeric-from-string 2.5"
+    5/2
+    (gnc-numeric-from-string "2.5"))
+
+  (test-equal "gnc-numeric-from-string .5"
+    1/2
+    (gnc-numeric-from-string ".5"))
+
+  (test-equal "gnc-numeric-from-string 1/3"
+    1/3
+    (gnc-numeric-from-string "1/3"))
+
+  ;; should error out; however "1 3" is parsed as 1.
+  (test-skip 1)
+  (test-equal "gnc-numeric-from-string 1 3"
+    #f
+    (gnc-numeric-from-string "1 3"))
+
+  (test-equal "gnc-numeric-from-string #f"
+    #f
+    (gnc-numeric-from-string "#f")))

commit c45b9736ab9a78f7ab807c274f61ff1eda695dbf
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue Aug 29 08:29:59 2023 +0800

    [gnc-numeric.cpp] parse integer + fraction; e.g."10 1/4" == 10.25

diff --git a/libgnucash/engine/gnc-numeric.cpp b/libgnucash/engine/gnc-numeric.cpp
index 4401592943..4297cab309 100644
--- a/libgnucash/engine/gnc-numeric.cpp
+++ b/libgnucash/engine/gnc-numeric.cpp
@@ -208,21 +208,24 @@ numeric_from_scientific_match(smatch &m)
 }
 
 GncNumeric::GncNumeric(const std::string &str, bool autoround) {
-    static const std::string numer_frag("(-?[0-9]*)");
-    static const std::string denom_frag("([0-9]+)");
+    static const std::string maybe_sign ("(-?)");
+    static const std::string opt_signed_int("(-?[0-9]*)");
+    static const std::string unsigned_int("([0-9]+)");
     static const std::string hex_frag("(0[xX][A-Fa-f0-9]+)");
     static const std::string slash("[ \\t]*/[ \\t]*");
+    static const std::string whitespace("[ \\t]+");
     /* The llvm standard C++ library refused to recognize the - in the
-     * numer_frag pattern with the default ECMAScript syntax so we use the
+     * opt_signed_int pattern with the default ECMAScript syntax so we use the
      * awk syntax.
      */
-    static const regex numeral(numer_frag);
+    static const regex numeral(opt_signed_int);
     static const regex hex(hex_frag);
-    static const regex numeral_rational(numer_frag + slash + denom_frag);
+    static const regex numeral_rational(opt_signed_int + slash + unsigned_int);
+    static const regex integer_and_fraction(maybe_sign + unsigned_int + whitespace + unsigned_int + slash + unsigned_int);
     static const regex hex_rational(hex_frag + slash + hex_frag);
-    static const regex hex_over_num(hex_frag + slash + denom_frag);
-    static const regex num_over_hex(numer_frag + slash + hex_frag);
-    static const regex decimal(numer_frag + "[.,]" + denom_frag);
+    static const regex hex_over_num(hex_frag + slash + unsigned_int);
+    static const regex num_over_hex(opt_signed_int + slash + hex_frag);
+    static const regex decimal(opt_signed_int + "[.,]" + unsigned_int);
     static const regex scientific("(?:(-?[0-9]+[.,]?)|(-?[0-9]*)[.,]([0-9]+))[Ee](-?[0-9]+)");
     static const regex has_hex_prefix(".*0[xX]$");
     smatch m, x;
@@ -256,6 +259,14 @@ GncNumeric::GncNumeric(const std::string &str, bool autoround) {
         m_den = n.denom();
         return;
     }
+    if (regex_search(str, m, integer_and_fraction))
+    {
+        GncNumeric n(stoll(m[3].str()), stoll(m[4].str()));
+        n += stoll(m[2].str());
+        m_num = m[1].str().empty() ? n.num() : -n.num();
+        m_den = n.denom();
+        return;
+    }
     if (regex_search(str, m, numeral_rational))
     {
         GncNumeric n(stoll(m[1].str()), stoll(m[2].str()));
@@ -1303,19 +1314,19 @@ gnc_num_dbg_to_string(gnc_numeric n)
     return p;
 }
 
-gboolean
-string_to_gnc_numeric(const gchar* str, gnc_numeric *n)
+gnc_numeric
+gnc_numeric_from_string (const gchar* str)
 {
+    if (!str)
+        return gnc_numeric_error (GNC_ERROR_ARG);
     try
     {
-        GncNumeric an(str);
-        *n = static_cast<gnc_numeric>(an);
-        return TRUE;
+        return GncNumeric (str);
     }
     catch (const std::exception& err)
     {
         PWARN("%s", err.what());
-        return FALSE;
+        return gnc_numeric_error (GNC_ERROR_ARG);
     }
 }
 
diff --git a/libgnucash/engine/gnc-numeric.h b/libgnucash/engine/gnc-numeric.h
index 254d18ca9f..f08c0c5266 100644
--- a/libgnucash/engine/gnc-numeric.h
+++ b/libgnucash/engine/gnc-numeric.h
@@ -296,10 +296,9 @@ gnc_numeric double_to_gnc_numeric(double n, gint64 denom,
                                   gint how);
 
 /** Read a gnc_numeric from str, skipping any leading whitespace.
- *  Return TRUE on success and store the resulting value in "n".
- *  Return NULL on error. */
-gboolean string_to_gnc_numeric(const gchar* str, gnc_numeric *n);
-
+ *  Returns the resulting gnc_numeric.
+ *  Return GNC_ERROR_ARG on error. */
+gnc_numeric gnc_numeric_from_string (const gchar* str);
 /** Create a gnc_numeric object that signals the error condition
  *  noted by error_code, rather than a number.
  */
diff --git a/libgnucash/engine/test/gtest-gnc-numeric.cpp b/libgnucash/engine/test/gtest-gnc-numeric.cpp
index 8194359d1c..ac6b1fe964 100644
--- a/libgnucash/engine/test/gtest-gnc-numeric.cpp
+++ b/libgnucash/engine/test/gtest-gnc-numeric.cpp
@@ -180,6 +180,28 @@ TEST(gncnumeric_constructors, test_string_constructor)
     GncNumeric neg_embedded("The number is -123456/456");
     EXPECT_EQ(-123456, neg_embedded.num());
     EXPECT_EQ(456, neg_embedded.denom());
+    ASSERT_NO_THROW(GncNumeric integer_fraction("The number is 1234 567/890"));
+    GncNumeric integer_fraction("The number is 1234 567/890");
+    EXPECT_EQ(1098827, integer_fraction.num());
+    EXPECT_EQ(890, integer_fraction.denom());
+    ASSERT_NO_THROW(GncNumeric neg_integer_fraction("The number is -1234 567/890"));
+    GncNumeric neg_integer_fraction("The number is -1234 567/890");
+    EXPECT_EQ(-1098827, neg_integer_fraction.num());
+    EXPECT_EQ(890, neg_integer_fraction.denom());
+    GncNumeric integer_large_fraction("The number is 1234 4567/890");
+    EXPECT_EQ(1102827, integer_large_fraction.num());
+    EXPECT_EQ(890, integer_large_fraction.denom());
+    GncNumeric neg_integer_large_fraction("The number is -1234 4567/890");
+    EXPECT_EQ(-1102827, neg_integer_large_fraction.num());
+    EXPECT_EQ(890, neg_integer_large_fraction.denom());
+    ASSERT_NO_THROW(GncNumeric zero_integer_fraction("The number is 0 567/890"));
+    GncNumeric zero_integer_fraction("The number is 0 567/890");
+    EXPECT_EQ(567, zero_integer_fraction.num());
+    EXPECT_EQ(890, zero_integer_fraction.denom());
+    ASSERT_NO_THROW(GncNumeric neg_zero_integer_fraction("The number is -0 567/890"));
+    GncNumeric neg_zero_integer_fraction("The number is -0 567/890");
+    EXPECT_EQ(-567, neg_zero_integer_fraction.num());
+    EXPECT_EQ(890, neg_zero_integer_fraction.denom());
     EXPECT_THROW(GncNumeric throw_zero_denom("123/0"), std::invalid_argument);
     EXPECT_THROW(GncNumeric overflow("12345678987654321.123456"),
                  std::overflow_error);



Summary of changes:
 bindings/guile/test/test-scm-engine.scm           | 36 +++++++++++++++++++++
 bindings/python/gnucash_core.py                   |  8 ++---
 gnucash/gnome/dialog-fincalc.c                    |  5 ++-
 gnucash/import-export/log-replay/gnc-log-replay.c |  4 +--
 libgnucash/app-utils/gnc-exp-parser.c             |  5 ++-
 libgnucash/backend/xml/io-gncxml-v1.cpp           |  7 ++++
 libgnucash/backend/xml/sixtp-dom-parsers.cpp      |  4 +--
 libgnucash/backend/xml/sixtp-utils.cpp            |  3 +-
 libgnucash/engine/gnc-numeric.cpp                 | 39 +++++++++++++++--------
 libgnucash/engine/gnc-numeric.h                   |  7 ++--
 libgnucash/engine/test/gtest-gnc-numeric.cpp      | 22 +++++++++++++
 11 files changed, 107 insertions(+), 33 deletions(-)



More information about the gnucash-changes mailing list