gnucash stable: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Wed Feb 21 19:37:26 EST 2024


Updated	 via  https://github.com/Gnucash/gnucash/commit/6cb2eeea (commit)
	 via  https://github.com/Gnucash/gnucash/commit/28cc26f2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/00640f9d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0732436e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/17f422f9 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/164453a8 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5d16d025 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/770045c4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/346499ae (commit)
	 via  https://github.com/Gnucash/gnucash/commit/47a1a56f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f49c2735 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d488faac (commit)
	from  https://github.com/Gnucash/gnucash/commit/226bfea1 (commit)



commit 6cb2eeeaa80124e04c763e207b9bb3cddd2a0b83
Merge: 226bfea108 28cc26f207
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Feb 22 07:39:35 2024 +0800

    Merge branch 'more-engine-cpp' into stable #1866


commit 28cc26f207881a1f9d0ea2dc708309f59a5bedb5
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Feb 19 09:19:44 2024 +0800

    [gnc-commodities.cpp] gnc_new_iso_codes is a std::unordered_map

diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index e2c6010559..18c84ce27f 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -42,6 +42,8 @@
 #include "guid.h"
 #include "qofinstance.h"
 
+#include <unordered_map>
+
 static QofLogModule log_module = GNC_MOD_COMMODITY;
 
 /* Parts per unit is nominal, i.e. number of 'partname' units in
@@ -125,11 +127,7 @@ struct gnc_commodity_table_s
     GList      * ns_list;
 };
 
-struct gnc_new_iso_code
-{
-    const char *old_code;
-    const char *new_code;
-} gnc_new_iso_codes[] =
+static const std::unordered_map<std::string,std::string> gnc_new_iso_codes =
 {
     {"RUR", "RUB"}, /* Russian Ruble: RUR through 1997-12, RUB from 1998-01 onwards; see bug #393185 */
     {"PLZ", "PLN"}, /* Polish Zloty */
@@ -144,8 +142,6 @@ struct gnc_new_iso_code
     /* Only add currencies to this table when the old currency no longer
      * exists in the file iso-4217-currencies.xml */
 };
-#define GNC_NEW_ISO_CODES \
-        (sizeof(gnc_new_iso_codes) / sizeof(struct gnc_new_iso_code))
 
 static std::string fq_version;
 
@@ -1714,7 +1710,6 @@ gnc_commodity_table_lookup(const gnc_commodity_table * table,
                            const char * name_space, const char * mnemonic)
 {
     gnc_commodity_namespace * nsp = NULL;
-    unsigned int i;
 
     if (!table || !name_space || !mnemonic) return NULL;
 
@@ -1728,14 +1723,9 @@ gnc_commodity_table_lookup(const gnc_commodity_table * table,
          */
         if (nsp->iso4217)
         {
-            for (i = 0; i < GNC_NEW_ISO_CODES; i++)
-            {
-                if (strcmp(mnemonic, gnc_new_iso_codes[i].old_code) == 0)
-                {
-                    mnemonic = gnc_new_iso_codes[i].new_code;
-                    break;
-                }
-            }
+            auto it = gnc_new_iso_codes.find (mnemonic);
+            if (it != gnc_new_iso_codes.end())
+                mnemonic = it->second.c_str();
         }
         return GNC_COMMODITY(g_hash_table_lookup(nsp->cm_table, (gpointer)mnemonic));
     }
@@ -1852,16 +1842,9 @@ gnc_commodity_table_insert(gnc_commodity_table * table,
          * recently changed. */
         if (priv->name_space->iso4217)
         {
-            guint i;
-            for (i = 0; i < GNC_NEW_ISO_CODES; i++)
-            {
-                if (!priv->mnemonic
-                        || !strcmp(priv->mnemonic, gnc_new_iso_codes[i].old_code))
-                {
-                    gnc_commodity_set_mnemonic(comm, gnc_new_iso_codes[i].new_code);
-                    break;
-                }
-            }
+            auto it = gnc_new_iso_codes.find (priv->mnemonic);
+            if (it != gnc_new_iso_codes.end())
+                gnc_commodity_set_mnemonic(comm, it->second.c_str());
         }
         gnc_commodity_copy (c, comm);
         gnc_commodity_destroy (comm);

commit 00640f9ded4967ee772cc275e25bfe3cae2ca7ad
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Fri Feb 16 10:47:03 2024 +0100

    Replace naked for loops with C++ algorithms

diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index e8cf95ef92..e2c6010559 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -318,10 +318,13 @@ gnc_quote_source_fq_version (void)
 static QuoteSourceVec&
 get_quote_source_from_type (QuoteSourceType type)
 {
-    for (const auto& [s_type, sources] : quote_sources_map)
-        if (type == s_type)
-            return sources;
+    auto quote_sources_it = std::find_if (quote_sources_map.begin(), quote_sources_map.end(),
+                                          [type] (const auto& qs) { return type == qs.first; });
 
+    if (quote_sources_it != quote_sources_map.end())
+        return quote_sources_it->second;
+
+    PWARN ("Invalid Quote Source %d, returning new_quote_sources", type);
     return new_quote_sources;
 }
 
@@ -386,11 +389,11 @@ gnc_quote_source_lookup_by_internal(const char * name)
 
     for (const auto& [_, sources] : quote_sources_map)
     {
-        for (const auto& source : sources)
-        {
-            if (g_strcmp0(name, source.get_internal_name()) == 0)
-                return (gnc_quote_source*)&source;
-        }
+        auto source_it = std::find_if (sources.begin(), sources.end(),
+                                       [name] (const auto& qs)
+                                       { return (g_strcmp0(name, qs.get_internal_name()) == 0); });
+        if (source_it != sources.end())
+            return &(*source_it);
     }
 
     DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);

commit 0732436e4477d6c8dd378e7a75e28f8f43be7896
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Fri Feb 16 10:46:21 2024 +0100

    A few NULL/nullptr related cleanups

diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index 268ac7725b..e8cf95ef92 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -348,7 +348,7 @@ gint gnc_quote_source_num_entries(QuoteSourceType type)
 gnc_quote_source *
 gnc_quote_source_add_new (const char *source_name, gboolean supported)
 {
-    DEBUG("Creating new source %s", (source_name == NULL ? "(null)" : source_name));
+    DEBUG("Creating new source %s", (!source_name ? "(null)" : source_name));
     /* This name can be changed if/when support for this price source is
      * integrated into gnucash. */
     /* This name is permanent and must be kept the same if/when support
@@ -375,16 +375,14 @@ gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
     }
 
     LEAVE("not found");
-    return NULL;
+    return nullptr;
 }
 
 gnc_quote_source *
 gnc_quote_source_lookup_by_internal(const char * name)
 {
-    if ((name == NULL) || (g_strcmp0(name, "") == 0))
-    {
-        return NULL;
-    }
+    if (!name || !*name)
+        return nullptr;
 
     for (const auto& [_, sources] : quote_sources_map)
     {
@@ -396,7 +394,7 @@ gnc_quote_source_lookup_by_internal(const char * name)
     }
 
     DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);
-    return NULL;
+    return nullptr;
 }
 
 /********************************************************************
@@ -449,7 +447,7 @@ gnc_quote_source_get_supported (const gnc_quote_source *source)
         return FALSE;
     }
 
-    LEAVE("%ssupported", source && source->get_supported() ? "" : "not ");
+    LEAVE("%s supported", source && source->get_supported() ? "" : "not ");
     return source->get_supported();
 }
 
@@ -460,7 +458,7 @@ gnc_quote_source_get_user_name (const gnc_quote_source *source)
     if (!source)
     {
         LEAVE("bad source");
-        return NULL;
+        return nullptr;
     }
     LEAVE("user name %s", source->get_user_name());
     return source->get_user_name();
@@ -473,7 +471,7 @@ gnc_quote_source_get_internal_name (const gnc_quote_source *source)
     if (!source)
     {
         LEAVE("bad source");
-        return NULL;
+        return nullptr;
     }
     LEAVE("internal name %s", source->get_internal_name());
     return source->get_internal_name();
@@ -505,7 +503,7 @@ gnc_quote_source_set_fq_installed (const char* version_string,
         auto source_name = source_name_str.c_str();
         auto source = gnc_quote_source_lookup_by_internal(source_name);
 
-        if (source != NULL)
+        if (source)
         {
             DEBUG("Found source %s: %s", source_name, source->get_user_name());
             source->set_supported (true);

commit 17f422f97c31f0821c43159050fc661d6e0b414e
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun Feb 18 17:20:09 2024 +0800

    [gnc-commodity.cpp] convert quote_sources to vector
    
    - all quote sources are now vector
    - get_quote_source_from_type to convert QuoteSourceType to vector<gnc_quote_source>
    - the quote sources are modifiable, therefore cannot be const:
    see gnc_quote_source_set_fq_installed

diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index 7954387e11..268ac7725b 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -170,6 +170,8 @@ public:
         , m_internal_name{int_name} { };
 };
 
+using QuoteSourceVec = std::vector<gnc_quote_source>;
+
 /* To update the following lists scan
  * from github.com/finance-quote/finance-quote
  * in lib/Finance/Quote/ all *.pm for "methods"
@@ -178,14 +180,16 @@ public:
  *
  * Apply changes here also to the FQ appendix of help.
  */
-static gnc_quote_source currency_quote_source =
-{ true, SOURCE_CURRENCY, "Currency", "currency" };
+static QuoteSourceVec currency_quote_sources =
+{
+    { true, SOURCE_CURRENCY, "Currency", "currency" }
+};
 
 /* The single quote method is usually the module name, but
  * sometimes it gets the suffix "_direct"
  * and the failover method is without suffix.
  */
-static gnc_quote_source single_quote_sources[] =
+static QuoteSourceVec single_quote_sources =
 {
     { false, SOURCE_SINGLE, "Alphavantage, US", "alphavantage" },
     { false, SOURCE_SINGLE, "Amsterdam Euronext eXchange, NL", "aex" },
@@ -250,7 +254,7 @@ static gnc_quote_source single_quote_sources[] =
     { false, SOURCE_SINGLE, "Yahoo as YQL", "yahoo_yql" },
 };
 
-static gnc_quote_source multiple_quote_sources[] =
+static QuoteSourceVec multiple_quote_sources =
 {
     { false, SOURCE_MULTI, "Australia (ASX, ...)", "australia" },
     { false, SOURCE_MULTI, "Canada (Alphavantage, TSX, ...)", "canada" },
@@ -275,12 +279,16 @@ static gnc_quote_source multiple_quote_sources[] =
     { false, SOURCE_MULTI, "USA (Alphavantage, Fool, ...)", "usa" },
 };
 
-static const int num_single_quote_sources =
-    sizeof(single_quote_sources) / sizeof(gnc_quote_source);
-static const int num_multiple_quote_sources =
-    sizeof(multiple_quote_sources) / sizeof(gnc_quote_source);
-static std::vector<gnc_quote_source> new_quote_sources;
+static QuoteSourceVec new_quote_sources;
 
+// cannot use map or unordered_map because order must be preserved
+static const std::vector<std::pair<QuoteSourceType,QuoteSourceVec&>> quote_sources_map =
+    {
+        { SOURCE_CURRENCY, currency_quote_sources },
+        { SOURCE_SINGLE, single_quote_sources },
+        { SOURCE_MULTI, multiple_quote_sources },
+        { SOURCE_UNKNOWN, new_quote_sources }
+    };
 
 /********************************************************************
  * gnc_quote_source_fq_installed
@@ -307,6 +315,16 @@ gnc_quote_source_fq_version (void)
     return fq_version.c_str();
 }
 
+static QuoteSourceVec&
+get_quote_source_from_type (QuoteSourceType type)
+{
+    for (const auto& [s_type, sources] : quote_sources_map)
+        if (type == s_type)
+            return sources;
+
+    return new_quote_sources;
+}
+
 /********************************************************************
  * gnc_quote_source_num_entries
  *
@@ -314,16 +332,7 @@ gnc_quote_source_fq_version (void)
  ********************************************************************/
 gint gnc_quote_source_num_entries(QuoteSourceType type)
 {
-    if  (type == SOURCE_CURRENCY)
-        return 1;
-
-    if  (type == SOURCE_SINGLE)
-        return num_single_quote_sources;
-
-    if (type == SOURCE_MULTI)
-        return num_multiple_quote_sources;
-
-    return new_quote_sources.size();
+    return get_quote_source_from_type(type).size();
 }
 
 
@@ -357,38 +366,12 @@ gnc_quote_source *
 gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
 {
     ENTER("type/index is %d/%d", type, index);
-    switch (type)
+    auto& sources = get_quote_source_from_type (type);
+    if ((size_t) index < sources.size())
     {
-    case SOURCE_CURRENCY:
-        LEAVE("found %s", currency_quote_source.get_user_name());
-        return &currency_quote_source;
-        break;
-
-    case SOURCE_SINGLE:
-        if (index < num_single_quote_sources)
-        {
-            LEAVE("found %s", single_quote_sources[index].get_user_name());
-            return &single_quote_sources[index];
-        }
-        break;
-
-    case SOURCE_MULTI:
-        if (index < num_multiple_quote_sources)
-        {
-            LEAVE("found %s", multiple_quote_sources[index].get_user_name());
-            return &multiple_quote_sources[index];
-        }
-        break;
-
-    case SOURCE_UNKNOWN:
-    default:
-        if ((size_t)index < new_quote_sources.size())
-        {
-            auto& source = new_quote_sources.at(index);
-            LEAVE("found %s", source.get_user_name());
-            return &source;
-        }
-        break;
+        auto& source = sources[index];
+        LEAVE("found %s", source.get_user_name());
+        return &source;
     }
 
     LEAVE("not found");
@@ -398,32 +381,18 @@ gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
 gnc_quote_source *
 gnc_quote_source_lookup_by_internal(const char * name)
 {
-    gint i;
-
     if ((name == NULL) || (g_strcmp0(name, "") == 0))
     {
         return NULL;
     }
 
-    if (g_strcmp0(name, currency_quote_source.get_internal_name()) == 0)
-        return &currency_quote_source;
-
-    for (i = 0; i < num_single_quote_sources; i++)
-    {
-        if (g_strcmp0(name, single_quote_sources[i].get_internal_name()) == 0)
-            return &single_quote_sources[i];
-    }
-
-    for (i = 0; i < num_multiple_quote_sources; i++)
-    {
-        if (g_strcmp0(name, multiple_quote_sources[i].get_internal_name()) == 0)
-            return &multiple_quote_sources[i];
-    }
-
-    for (auto& source : new_quote_sources)
+    for (const auto& [_, sources] : quote_sources_map)
     {
-        if (g_strcmp0(name, source.get_internal_name()) == 0)
-            return &source;
+        for (const auto& source : sources)
+        {
+            if (g_strcmp0(name, source.get_internal_name()) == 0)
+                return (gnc_quote_source*)&source;
+        }
     }
 
     DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);
@@ -458,30 +427,14 @@ gnc_quote_source_get_index (const gnc_quote_source *source)
         return 0;
     }
 
-    switch (source->get_type())
-    {
-    case SOURCE_CURRENCY:
-        return 0;
-    case SOURCE_SINGLE:
-        for (auto i = 0; i < num_single_quote_sources; ++i)
-            if (&single_quote_sources[i] == source)
-                return i;
-        break;
-    case SOURCE_MULTI:
-        for (auto i = 0; i < num_multiple_quote_sources; ++i)
-            if (&multiple_quote_sources[i] == source)
-                return i;
-        break;
-    case SOURCE_UNKNOWN:
-    {
-        for (size_t i = 0; i < new_quote_sources.size(); ++i)
-            if (&new_quote_sources[i] == source)
-                return i;
-        break;
-    }
-    default:
-        break;
-    }
+    auto& sources = get_quote_source_from_type (source->get_type());
+    auto is_source = [&source](const auto& findif_source)
+    { return &findif_source == source; };
+
+    auto iter = std::find_if (sources.begin(), sources.end(), is_source);
+    if (iter != sources.end())
+        return std::distance (sources.begin(), iter);
+
     PWARN ("couldn't locate source");
     return 0;
 }
@@ -1130,7 +1083,7 @@ gnc_commodity_get_quote_source(const gnc_commodity *cm)
     if (!cm) return NULL;
     priv = GET_PRIVATE(cm);
     if (!priv->quote_source && gnc_commodity_is_iso(cm))
-        return &currency_quote_source;
+        return &currency_quote_sources[0];
     return priv->quote_source;
 }
 
@@ -1138,7 +1091,7 @@ gnc_quote_source*
 gnc_commodity_get_default_quote_source(const gnc_commodity *cm)
 {
     if (cm && gnc_commodity_is_iso(cm))
-        return &currency_quote_source;
+        return &currency_quote_sources[0];
     /* Should make this a user option at some point. */
     return gnc_quote_source_lookup_by_internal("alphavantage");
 }

commit 164453a858ffff9c36c007cae37fa4d64f8e5108
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Feb 15 00:36:44 2024 +0800

    [gnc-commodity.cpp] gnc_quote_source_get_index searches index
    
    we can now remove init

diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index 53769035f2..7954387e11 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -154,22 +154,18 @@ struct gnc_quote_source_s
 private:
     gboolean m_supported;
     QuoteSourceType m_type;
-    gint m_index;
     std::string m_user_name;		/* User friendly name incl. region code*/
     std::string m_internal_name;	/* Name used internally and by finance::quote. */
 public:
     bool get_supported () const { return m_supported; }
     void set_supported (bool supported) { m_supported = supported; }
     QuoteSourceType get_type () const { return m_type; }
-    size_t get_index () const { return m_index; }
-    void set_index (size_t index) { m_index = index; }
     const char* get_user_name () const { return m_user_name.c_str(); }
     const char* get_internal_name () const { return m_internal_name.c_str(); }
-    gnc_quote_source_s (gboolean supported, QuoteSourceType type, gint index,
+    gnc_quote_source_s (gboolean supported, QuoteSourceType type,
                         const char* username, const char* int_name)
         : m_supported{supported}
         , m_type{type}
-        , m_index{index}
         , m_user_name{username}
         , m_internal_name{int_name} { };
 };
@@ -183,7 +179,7 @@ public:
  * Apply changes here also to the FQ appendix of help.
  */
 static gnc_quote_source currency_quote_source =
-{ true, SOURCE_CURRENCY, 0, "Currency", "currency" };
+{ true, SOURCE_CURRENCY, "Currency", "currency" };
 
 /* The single quote method is usually the module name, but
  * sometimes it gets the suffix "_direct"
@@ -191,92 +187,92 @@ static gnc_quote_source currency_quote_source =
  */
 static gnc_quote_source single_quote_sources[] =
 {
-    { false, SOURCE_SINGLE, 0, "Alphavantage, US", "alphavantage" },
-    { false, SOURCE_SINGLE, 0, "Amsterdam Euronext eXchange, NL", "aex" },
-    { false, SOURCE_SINGLE, 0, "American International Assurance, HK", "aiahk" },
-    { false, SOURCE_SINGLE, 0, "Association of Mutual Funds in India", "amfiindia" },
-    { false, SOURCE_SINGLE, 0, "Athens Stock Exchange, GR", "asegr" },
-    { false, SOURCE_SINGLE, 0, "Australian Stock Exchange, AU", "asx" },
-    { false, SOURCE_SINGLE, 0, "BAMOSZ funds, HU", "bamosz" },
-    { false, SOURCE_SINGLE, 0, "BMO NesbittBurns, CA", "bmonesbittburns" },
-    { false, SOURCE_SINGLE, 0, "Bucharest Stock Exchange, RO", "bsero" },
-    { false, SOURCE_SINGLE, 0, "Budapest Stock Exchange (BET), ex-BUX, HU", "bse" },
-    { false, SOURCE_SINGLE, 0, "Canada Mutual", "canadamutual" },
-    { false, SOURCE_SINGLE, 0, "Citywire Funds, GB", "citywire" },
-    { false, SOURCE_SINGLE, 0, "Colombo Stock Exchange, LK", "cse" },
-    { false, SOURCE_SINGLE, 0, "Cominvest, ex-Adig, DE", "cominvest" },
-    { false, SOURCE_SINGLE, 0, "Deka Investments, DE", "deka" },
-    { false, SOURCE_SINGLE, 0, "Dutch", "dutch" },
-    { false, SOURCE_SINGLE, 0, "DWS, DE", "dwsfunds" },
-    { false, SOURCE_SINGLE, 0, "Equinox Unit Trusts, ZA", "za_unittrusts" },
-    { false, SOURCE_SINGLE, 0, "Fidelity Direct", "fidelity_direct" },
-    { false, SOURCE_SINGLE, 0, "Fidelity Fixed", "fidelityfixed" },
-    { false, SOURCE_SINGLE, 0, "Finance Canada", "financecanada" },
-    { false, SOURCE_SINGLE, 0, "Financial Times Funds service, GB", "ftfunds" },
-    { false, SOURCE_SINGLE, 0, "Finanzpartner, DE", "finanzpartner" },
-    { false, SOURCE_SINGLE, 0, "First Trust Portfolios, US", "ftportfolios" },
-    { false, SOURCE_SINGLE, 0, "Fund Library, CA", "fundlibrary" },
-    { false, SOURCE_SINGLE, 0, "GoldMoney spot rates, JE", "goldmoney" },
-    { false, SOURCE_SINGLE, 0, "Greece", "greece" },
-    { false, SOURCE_SINGLE, 0, "Helsinki stock eXchange, FI", "hex" },
-    { false, SOURCE_SINGLE, 0, "Hungary", "hu" },
-    { false, SOURCE_SINGLE, 0, "India Mutual", "indiamutual" },
-    { false, SOURCE_SINGLE, 0, "Man Investments, AU", "maninv" },
-    { false, SOURCE_SINGLE, 0, "Morningstar, GB", "mstaruk" },
-    { false, SOURCE_SINGLE, 0, "Morningstar, JP", "morningstarjp" },
-    { false, SOURCE_SINGLE, 0, "Morningstar, SE", "morningstar" },
-    { false, SOURCE_SINGLE, 0, "Motley Fool, US", "fool" },
-    { false, SOURCE_SINGLE, 0, "New Zealand stock eXchange, NZ", "nzx" },
-    { false, SOURCE_SINGLE, 0, "Paris Stock Exchange/Boursorama, FR", "bourso" },
-    { false, SOURCE_SINGLE, 0, "Paris Stock Exchange/LeRevenu, FR", "lerevenu" },
-    { false, SOURCE_SINGLE, 0, "Platinum Asset Management, AU", "platinum" },
-    { false, SOURCE_SINGLE, 0, "Romania", "romania" },
-    { false, SOURCE_SINGLE, 0, "SIX Swiss Exchange funds, CH", "sixfunds" },
-    { false, SOURCE_SINGLE, 0, "SIX Swiss Exchange shares, CH", "sixshares" },
-    { false, SOURCE_SINGLE, 0, "Skandinaviska Enskilda Banken, SE", "seb_funds" },
-    { false, SOURCE_SINGLE, 0, "Sharenet, ZA", "za" },
-    { false, SOURCE_SINGLE, 0, "StockHouse Canada", "stockhousecanada_fund" },
-    { false, SOURCE_SINGLE, 0, "TD Waterhouse Funds, CA", "tdwaterhouse" },
-    { false, SOURCE_SINGLE, 0, "TD Efunds, CA", "tdefunds" },
-    { false, SOURCE_SINGLE, 0, "TIAA-CREF, US", "tiaacref" },
-    { false, SOURCE_SINGLE, 0, "Toronto Stock eXchange, CA", "tsx" },
-    { false, SOURCE_SINGLE, 0, "T. Rowe Price", "troweprice" },
-    { false, SOURCE_SINGLE, 0, "T. Rowe Price, US", "troweprice_direct" },
-    { false, SOURCE_SINGLE, 0, "Trustnet via tnetuk.pm, GB", "tnetuk" },
-    { false, SOURCE_SINGLE, 0, "Trustnet via trustnet.pm, GB", "trustnet" },
-    { false, SOURCE_SINGLE, 0, "U.K. Unit Trusts", "uk_unit_trusts" },
-    { false, SOURCE_SINGLE, 0, "Union Investment, DE", "unionfunds" },
-    { false, SOURCE_SINGLE, 0, "US Treasury Bonds", "usfedbonds" },
-    { false, SOURCE_SINGLE, 0, "US Govt. Thrift Savings Plan", "tsp" },
-    { false, SOURCE_SINGLE, 0, "Vanguard", "vanguard" }, /* Method of Alphavantage */
-    { false, SOURCE_SINGLE, 0, "VWD, DE (unmaintained)", "vwd" },
-    { false, SOURCE_SINGLE, 0, "Yahoo as JSON", "yahoo_json" },
-    { false, SOURCE_SINGLE, 0, "Yahoo as YQL", "yahoo_yql" },
+    { false, SOURCE_SINGLE, "Alphavantage, US", "alphavantage" },
+    { false, SOURCE_SINGLE, "Amsterdam Euronext eXchange, NL", "aex" },
+    { false, SOURCE_SINGLE, "American International Assurance, HK", "aiahk" },
+    { false, SOURCE_SINGLE, "Association of Mutual Funds in India", "amfiindia" },
+    { false, SOURCE_SINGLE, "Athens Stock Exchange, GR", "asegr" },
+    { false, SOURCE_SINGLE, "Australian Stock Exchange, AU", "asx" },
+    { false, SOURCE_SINGLE, "BAMOSZ funds, HU", "bamosz" },
+    { false, SOURCE_SINGLE, "BMO NesbittBurns, CA", "bmonesbittburns" },
+    { false, SOURCE_SINGLE, "Bucharest Stock Exchange, RO", "bsero" },
+    { false, SOURCE_SINGLE, "Budapest Stock Exchange (BET), ex-BUX, HU", "bse" },
+    { false, SOURCE_SINGLE, "Canada Mutual", "canadamutual" },
+    { false, SOURCE_SINGLE, "Citywire Funds, GB", "citywire" },
+    { false, SOURCE_SINGLE, "Colombo Stock Exchange, LK", "cse" },
+    { false, SOURCE_SINGLE, "Cominvest, ex-Adig, DE", "cominvest" },
+    { false, SOURCE_SINGLE, "Deka Investments, DE", "deka" },
+    { false, SOURCE_SINGLE, "Dutch", "dutch" },
+    { false, SOURCE_SINGLE, "DWS, DE", "dwsfunds" },
+    { false, SOURCE_SINGLE, "Equinox Unit Trusts, ZA", "za_unittrusts" },
+    { false, SOURCE_SINGLE, "Fidelity Direct", "fidelity_direct" },
+    { false, SOURCE_SINGLE, "Fidelity Fixed", "fidelityfixed" },
+    { false, SOURCE_SINGLE, "Finance Canada", "financecanada" },
+    { false, SOURCE_SINGLE, "Financial Times Funds service, GB", "ftfunds" },
+    { false, SOURCE_SINGLE, "Finanzpartner, DE", "finanzpartner" },
+    { false, SOURCE_SINGLE, "First Trust Portfolios, US", "ftportfolios" },
+    { false, SOURCE_SINGLE, "Fund Library, CA", "fundlibrary" },
+    { false, SOURCE_SINGLE, "GoldMoney spot rates, JE", "goldmoney" },
+    { false, SOURCE_SINGLE, "Greece", "greece" },
+    { false, SOURCE_SINGLE, "Helsinki stock eXchange, FI", "hex" },
+    { false, SOURCE_SINGLE, "Hungary", "hu" },
+    { false, SOURCE_SINGLE, "India Mutual", "indiamutual" },
+    { false, SOURCE_SINGLE, "Man Investments, AU", "maninv" },
+    { false, SOURCE_SINGLE, "Morningstar, GB", "mstaruk" },
+    { false, SOURCE_SINGLE, "Morningstar, JP", "morningstarjp" },
+    { false, SOURCE_SINGLE, "Morningstar, SE", "morningstar" },
+    { false, SOURCE_SINGLE, "Motley Fool, US", "fool" },
+    { false, SOURCE_SINGLE, "New Zealand stock eXchange, NZ", "nzx" },
+    { false, SOURCE_SINGLE, "Paris Stock Exchange/Boursorama, FR", "bourso" },
+    { false, SOURCE_SINGLE, "Paris Stock Exchange/LeRevenu, FR", "lerevenu" },
+    { false, SOURCE_SINGLE, "Platinum Asset Management, AU", "platinum" },
+    { false, SOURCE_SINGLE, "Romania", "romania" },
+    { false, SOURCE_SINGLE, "SIX Swiss Exchange funds, CH", "sixfunds" },
+    { false, SOURCE_SINGLE, "SIX Swiss Exchange shares, CH", "sixshares" },
+    { false, SOURCE_SINGLE, "Skandinaviska Enskilda Banken, SE", "seb_funds" },
+    { false, SOURCE_SINGLE, "Sharenet, ZA", "za" },
+    { false, SOURCE_SINGLE, "StockHouse Canada", "stockhousecanada_fund" },
+    { false, SOURCE_SINGLE, "TD Waterhouse Funds, CA", "tdwaterhouse" },
+    { false, SOURCE_SINGLE, "TD Efunds, CA", "tdefunds" },
+    { false, SOURCE_SINGLE, "TIAA-CREF, US", "tiaacref" },
+    { false, SOURCE_SINGLE, "Toronto Stock eXchange, CA", "tsx" },
+    { false, SOURCE_SINGLE, "T. Rowe Price", "troweprice" },
+    { false, SOURCE_SINGLE, "T. Rowe Price, US", "troweprice_direct" },
+    { false, SOURCE_SINGLE, "Trustnet via tnetuk.pm, GB", "tnetuk" },
+    { false, SOURCE_SINGLE, "Trustnet via trustnet.pm, GB", "trustnet" },
+    { false, SOURCE_SINGLE, "U.K. Unit Trusts", "uk_unit_trusts" },
+    { false, SOURCE_SINGLE, "Union Investment, DE", "unionfunds" },
+    { false, SOURCE_SINGLE, "US Treasury Bonds", "usfedbonds" },
+    { false, SOURCE_SINGLE, "US Govt. Thrift Savings Plan", "tsp" },
+    { false, SOURCE_SINGLE, "Vanguard", "vanguard" }, /* Method of Alphavantage */
+    { false, SOURCE_SINGLE, "VWD, DE (unmaintained)", "vwd" },
+    { false, SOURCE_SINGLE, "Yahoo as JSON", "yahoo_json" },
+    { false, SOURCE_SINGLE, "Yahoo as YQL", "yahoo_yql" },
 };
 
 static gnc_quote_source multiple_quote_sources[] =
 {
-    { false, SOURCE_MULTI, 0, "Australia (ASX, ...)", "australia" },
-    { false, SOURCE_MULTI, 0, "Canada (Alphavantage, TSX, ...)", "canada" },
-    { false, SOURCE_MULTI, 0, "Canada Mutual (Fund Library, StockHouse, ...)", "canadamutual" },
-    { false, SOURCE_MULTI, 0, "Dutch (AEX, ...)", "dutch" },
-    { false, SOURCE_MULTI, 0, "Europe (asegr,.bsero, hex ...)", "europe" },
-    { false, SOURCE_MULTI, 0, "Greece (ASE, ...)", "greece" },
-    { false, SOURCE_MULTI, 0, "Hungary (Bamosz, BET, ...)", "hu" },
-    { false, SOURCE_MULTI, 0, "India Mutual (AMFI, ...)", "indiamutual" },
-    { false, SOURCE_MULTI, 0, "Fidelity (Fidelity, ...)", "fidelity" },
-    { false, SOURCE_MULTI, 0, "Finland (HEX, ...)", "finland" },
-    { false, SOURCE_MULTI, 0, "First Trust (First Trust, ...)", "ftportfolios" },
-    { false, SOURCE_MULTI, 0, "France (bourso, ĺerevenu, ...)", "france" },
-    { false, SOURCE_MULTI, 0, "Nasdaq (alphavantage, fool, ...)", "nasdaq" },
-    { false, SOURCE_MULTI, 0, "New Zealand (NZX, ...)", "nz" },
-    { false, SOURCE_MULTI, 0, "NYSE (alphavantage, fool, ...)", "nyse" },
-    { false, SOURCE_MULTI, 0, "South Africa (Sharenet, ...)", "za" },
-    { false, SOURCE_MULTI, 0, "Romania (BSE-RO, ...)", "romania" },
-    { false, SOURCE_MULTI, 0, "T. Rowe Price", "troweprice" },
-    { false, SOURCE_MULTI, 0, "U.K. Funds (citywire, FTfunds, MStar, tnetuk, ...)", "ukfunds" },
-    { false, SOURCE_MULTI, 0, "U.K. Unit Trusts (trustnet, ...)", "uk_unit_trusts" },
-    { false, SOURCE_MULTI, 0, "USA (Alphavantage, Fool, ...)", "usa" },
+    { false, SOURCE_MULTI, "Australia (ASX, ...)", "australia" },
+    { false, SOURCE_MULTI, "Canada (Alphavantage, TSX, ...)", "canada" },
+    { false, SOURCE_MULTI, "Canada Mutual (Fund Library, StockHouse, ...)", "canadamutual" },
+    { false, SOURCE_MULTI, "Dutch (AEX, ...)", "dutch" },
+    { false, SOURCE_MULTI, "Europe (asegr,.bsero, hex ...)", "europe" },
+    { false, SOURCE_MULTI, "Greece (ASE, ...)", "greece" },
+    { false, SOURCE_MULTI, "Hungary (Bamosz, BET, ...)", "hu" },
+    { false, SOURCE_MULTI, "India Mutual (AMFI, ...)", "indiamutual" },
+    { false, SOURCE_MULTI, "Fidelity (Fidelity, ...)", "fidelity" },
+    { false, SOURCE_MULTI, "Finland (HEX, ...)", "finland" },
+    { false, SOURCE_MULTI, "First Trust (First Trust, ...)", "ftportfolios" },
+    { false, SOURCE_MULTI, "France (bourso, ĺerevenu, ...)", "france" },
+    { false, SOURCE_MULTI, "Nasdaq (alphavantage, fool, ...)", "nasdaq" },
+    { false, SOURCE_MULTI, "New Zealand (NZX, ...)", "nz" },
+    { false, SOURCE_MULTI, "NYSE (alphavantage, fool, ...)", "nyse" },
+    { false, SOURCE_MULTI, "South Africa (Sharenet, ...)", "za" },
+    { false, SOURCE_MULTI, "Romania (BSE-RO, ...)", "romania" },
+    { false, SOURCE_MULTI, "T. Rowe Price", "troweprice" },
+    { false, SOURCE_MULTI, "U.K. Funds (citywire, FTfunds, MStar, tnetuk, ...)", "ukfunds" },
+    { false, SOURCE_MULTI, "U.K. Unit Trusts (trustnet, ...)", "uk_unit_trusts" },
+    { false, SOURCE_MULTI, "USA (Alphavantage, Fool, ...)", "usa" },
 };
 
 static const int num_single_quote_sources =
@@ -330,26 +326,6 @@ gint gnc_quote_source_num_entries(QuoteSourceType type)
     return new_quote_sources.size();
 }
 
-/********************************************************************
- * gnc_quote_source_init_tables
- *
- * Update the type/index values for prices sources.
- ********************************************************************/
-static void
-gnc_quote_source_init_tables (void)
-{
-    gint i;
-
-    for (i = 0; i < num_single_quote_sources; i++)
-    {
-        single_quote_sources[i].set_index(i);
-    }
-
-    for (i = 0; i < num_multiple_quote_sources; i++)
-    {
-        multiple_quote_sources[i].set_index(i);
-    }
-}
 
 
 /********************************************************************
@@ -369,8 +345,7 @@ gnc_quote_source_add_new (const char *source_name, gboolean supported)
     /* This name is permanent and must be kept the same if/when support
      * for this price source is integrated into gnucash (i.e. for a
      * nice user name). */
-    return &new_quote_sources.emplace_back (supported, SOURCE_UNKNOWN, (gint)new_quote_sources.size(),
-                                            source_name, source_name);
+    return &new_quote_sources.emplace_back (supported, SOURCE_UNKNOWN, source_name, source_name);
 }
 
 /********************************************************************
@@ -477,15 +452,38 @@ gnc_quote_source_get_type (const gnc_quote_source *source)
 gint
 gnc_quote_source_get_index (const gnc_quote_source *source)
 {
-    ENTER("%p", source);
     if (!source)
     {
-        LEAVE("bad source");
+        PWARN ("bad source");
         return 0;
     }
 
-    LEAVE("index is %ld", source->get_index());
-    return source->get_index();
+    switch (source->get_type())
+    {
+    case SOURCE_CURRENCY:
+        return 0;
+    case SOURCE_SINGLE:
+        for (auto i = 0; i < num_single_quote_sources; ++i)
+            if (&single_quote_sources[i] == source)
+                return i;
+        break;
+    case SOURCE_MULTI:
+        for (auto i = 0; i < num_multiple_quote_sources; ++i)
+            if (&multiple_quote_sources[i] == source)
+                return i;
+        break;
+    case SOURCE_UNKNOWN:
+    {
+        for (size_t i = 0; i < new_quote_sources.size(); ++i)
+            if (&new_quote_sources[i] == source)
+                return i;
+        break;
+    }
+    default:
+        break;
+    }
+    PWARN ("couldn't locate source");
+    return 0;
 }
 
 gboolean
@@ -2518,8 +2516,6 @@ static QofObject commodity_table_object_def =
 gboolean
 gnc_commodity_table_register (void)
 {
-    gnc_quote_source_init_tables();
-
     if (!qof_object_register (&commodity_object_def))
         return FALSE;
     if (!qof_object_register (&namespace_object_def))

commit 5d16d025a619e88a4c9d366a02b9c91c4fc34e2a
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Feb 12 19:00:41 2024 +0800

    [gnc-commodity.cpp] gnc_quote_source_s is a cpp class
    
    ... this ensures the new_quote_sources vector now doesn't leak anymore.

diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index f230355d3c..53769035f2 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -151,11 +151,27 @@ static std::string fq_version;
 
 struct gnc_quote_source_s
 {
-    gboolean supported;
-    QuoteSourceType type;
-    gint index;
-    const char *user_name;		/* User friendly name incl. region code*/
-    const char *internal_name;	/* Name used internally and by finance::quote. */
+private:
+    gboolean m_supported;
+    QuoteSourceType m_type;
+    gint m_index;
+    std::string m_user_name;		/* User friendly name incl. region code*/
+    std::string m_internal_name;	/* Name used internally and by finance::quote. */
+public:
+    bool get_supported () const { return m_supported; }
+    void set_supported (bool supported) { m_supported = supported; }
+    QuoteSourceType get_type () const { return m_type; }
+    size_t get_index () const { return m_index; }
+    void set_index (size_t index) { m_index = index; }
+    const char* get_user_name () const { return m_user_name.c_str(); }
+    const char* get_internal_name () const { return m_internal_name.c_str(); }
+    gnc_quote_source_s (gboolean supported, QuoteSourceType type, gint index,
+                        const char* username, const char* int_name)
+        : m_supported{supported}
+        , m_type{type}
+        , m_index{index}
+        , m_user_name{username}
+        , m_internal_name{int_name} { };
 };
 
 /* To update the following lists scan
@@ -267,7 +283,7 @@ static const int num_single_quote_sources =
     sizeof(single_quote_sources) / sizeof(gnc_quote_source);
 static const int num_multiple_quote_sources =
     sizeof(multiple_quote_sources) / sizeof(gnc_quote_source);
-static GList *new_quote_sources = NULL;
+static std::vector<gnc_quote_source> new_quote_sources;
 
 
 /********************************************************************
@@ -311,7 +327,7 @@ gint gnc_quote_source_num_entries(QuoteSourceType type)
     if (type == SOURCE_MULTI)
         return num_multiple_quote_sources;
 
-    return g_list_length(new_quote_sources);
+    return new_quote_sources.size();
 }
 
 /********************************************************************
@@ -326,12 +342,12 @@ gnc_quote_source_init_tables (void)
 
     for (i = 0; i < num_single_quote_sources; i++)
     {
-        single_quote_sources[i].index = i;
+        single_quote_sources[i].set_index(i);
     }
 
     for (i = 0; i < num_multiple_quote_sources; i++)
     {
-        multiple_quote_sources[i].index = i;
+        multiple_quote_sources[i].set_index(i);
     }
 }
 
@@ -347,24 +363,14 @@ gnc_quote_source_init_tables (void)
 gnc_quote_source *
 gnc_quote_source_add_new (const char *source_name, gboolean supported)
 {
-    gnc_quote_source *new_source;
-
     DEBUG("Creating new source %s", (source_name == NULL ? "(null)" : source_name));
-    new_source = g_new0 (gnc_quote_source, 1);
-    new_source->supported = supported;
-    new_source->type = SOURCE_UNKNOWN;
-    new_source->index = g_list_length(new_quote_sources);
-
     /* This name can be changed if/when support for this price source is
      * integrated into gnucash. */
-    new_source->user_name = g_strdup(source_name);
-
     /* This name is permanent and must be kept the same if/when support
      * for this price source is integrated into gnucash (i.e. for a
      * nice user name). */
-    new_source->internal_name = g_strdup(source_name);
-    new_quote_sources = g_list_append(new_quote_sources, new_source);
-    return new_source;
+    return &new_quote_sources.emplace_back (supported, SOURCE_UNKNOWN, (gint)new_quote_sources.size(),
+                                            source_name, source_name);
 }
 
 /********************************************************************
@@ -375,21 +381,18 @@ gnc_quote_source_add_new (const char *source_name, gboolean supported)
 gnc_quote_source *
 gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
 {
-    gnc_quote_source *source;
-    GList *node;
-
     ENTER("type/index is %d/%d", type, index);
     switch (type)
     {
     case SOURCE_CURRENCY:
-        LEAVE("found %s", currency_quote_source.user_name);
+        LEAVE("found %s", currency_quote_source.get_user_name());
         return &currency_quote_source;
         break;
 
     case SOURCE_SINGLE:
         if (index < num_single_quote_sources)
         {
-            LEAVE("found %s", single_quote_sources[index].user_name);
+            LEAVE("found %s", single_quote_sources[index].get_user_name());
             return &single_quote_sources[index];
         }
         break;
@@ -397,19 +400,18 @@ gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
     case SOURCE_MULTI:
         if (index < num_multiple_quote_sources)
         {
-            LEAVE("found %s", multiple_quote_sources[index].user_name);
+            LEAVE("found %s", multiple_quote_sources[index].get_user_name());
             return &multiple_quote_sources[index];
         }
         break;
 
     case SOURCE_UNKNOWN:
     default:
-        node = g_list_nth(new_quote_sources, index);
-        if (node)
+        if ((size_t)index < new_quote_sources.size())
         {
-            source = static_cast<gnc_quote_source*>(node->data);
-            LEAVE("found %s", source->user_name);
-            return source;
+            auto& source = new_quote_sources.at(index);
+            LEAVE("found %s", source.get_user_name());
+            return &source;
         }
         break;
     }
@@ -421,8 +423,6 @@ gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
 gnc_quote_source *
 gnc_quote_source_lookup_by_internal(const char * name)
 {
-    gnc_quote_source *source;
-    GList *node;
     gint i;
 
     if ((name == NULL) || (g_strcmp0(name, "") == 0))
@@ -430,26 +430,25 @@ gnc_quote_source_lookup_by_internal(const char * name)
         return NULL;
     }
 
-    if (g_strcmp0(name, currency_quote_source.internal_name) == 0)
+    if (g_strcmp0(name, currency_quote_source.get_internal_name()) == 0)
         return &currency_quote_source;
 
     for (i = 0; i < num_single_quote_sources; i++)
     {
-        if (g_strcmp0(name, single_quote_sources[i].internal_name) == 0)
+        if (g_strcmp0(name, single_quote_sources[i].get_internal_name()) == 0)
             return &single_quote_sources[i];
     }
 
     for (i = 0; i < num_multiple_quote_sources; i++)
     {
-        if (g_strcmp0(name, multiple_quote_sources[i].internal_name) == 0)
+        if (g_strcmp0(name, multiple_quote_sources[i].get_internal_name()) == 0)
             return &multiple_quote_sources[i];
     }
 
-    for (i = 0, node = new_quote_sources; node; node = node->next, i++)
+    for (auto& source : new_quote_sources)
     {
-        source = static_cast<gnc_quote_source*>(node->data);
-        if (g_strcmp0(name, source->internal_name) == 0)
-            return source;
+        if (g_strcmp0(name, source.get_internal_name()) == 0)
+            return &source;
     }
 
     DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);
@@ -471,8 +470,8 @@ gnc_quote_source_get_type (const gnc_quote_source *source)
         return SOURCE_SINGLE;
     }
 
-    LEAVE("type is %d", source->type);
-    return source->type;
+    LEAVE("type is %d", source->get_type());
+    return source->get_type();
 }
 
 gint
@@ -485,8 +484,8 @@ gnc_quote_source_get_index (const gnc_quote_source *source)
         return 0;
     }
 
-    LEAVE("index is %d", source->index);
-    return source->index;
+    LEAVE("index is %ld", source->get_index());
+    return source->get_index();
 }
 
 gboolean
@@ -499,8 +498,8 @@ gnc_quote_source_get_supported (const gnc_quote_source *source)
         return FALSE;
     }
 
-    LEAVE("%ssupported", source && source->supported ? "" : "not ");
-    return source->supported;
+    LEAVE("%ssupported", source && source->get_supported() ? "" : "not ");
+    return source->get_supported();
 }
 
 const char *
@@ -512,8 +511,8 @@ gnc_quote_source_get_user_name (const gnc_quote_source *source)
         LEAVE("bad source");
         return NULL;
     }
-    LEAVE("user name %s", source->user_name);
-    return source->user_name;
+    LEAVE("user name %s", source->get_user_name());
+    return source->get_user_name();
 }
 
 const char *
@@ -525,8 +524,8 @@ gnc_quote_source_get_internal_name (const gnc_quote_source *source)
         LEAVE("bad source");
         return NULL;
     }
-    LEAVE("internal name %s", source->internal_name);
-    return source->internal_name;
+    LEAVE("internal name %s", source->get_internal_name());
+    return source->get_internal_name();
 }
 
 
@@ -557,8 +556,8 @@ gnc_quote_source_set_fq_installed (const char* version_string,
 
         if (source != NULL)
         {
-            DEBUG("Found source %s: %s", source_name, source->user_name);
-            source->supported = TRUE;
+            DEBUG("Found source %s: %s", source_name, source->get_user_name());
+            source->set_supported (true);
             continue;
         }
 
@@ -1410,7 +1409,7 @@ gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
 void
 gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
 {
-    ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->internal_name : "unknown");
+    ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->get_internal_name() : "unknown");
 
     if (!cm) return;
     gnc_commodity_begin_edit(cm);
@@ -2139,8 +2138,7 @@ get_quotables_helper1(gpointer key, gpointer value, gpointer data)
     gnc_commodityPrivate* priv = GET_PRIVATE(comm);
     auto l = static_cast<GList**>(data);
 
-    if (!priv->quote_flag ||
-            !priv->quote_source || !priv->quote_source->supported)
+    if (!priv->quote_flag || !priv->quote_source || !priv->quote_source->get_supported())
         return;
     *l = g_list_prepend(*l, value);
 }
@@ -2151,8 +2149,7 @@ get_quotables_helper2 (gnc_commodity *comm, gpointer data)
     auto l = static_cast<GList**>(data);
     gnc_commodityPrivate* priv = GET_PRIVATE(comm);
 
-    if (!priv->quote_flag ||
-            !priv->quote_source || !priv->quote_source->supported)
+    if (!priv->quote_flag || priv->quote_source || !priv->quote_source->get_supported())
         return TRUE;
     *l = g_list_prepend(*l, comm);
     return TRUE;

commit 770045c4a5530244eb19056cb4c63b14f8c218f5
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Feb 12 10:44:52 2024 +0800

    [gnc-quotes.cpp] remove sources_as_glist()

diff --git a/libgnucash/app-utils/gnc-quotes.cpp b/libgnucash/app-utils/gnc-quotes.cpp
index d666a69b1e..1438050c80 100644
--- a/libgnucash/app-utils/gnc-quotes.cpp
+++ b/libgnucash/app-utils/gnc-quotes.cpp
@@ -103,7 +103,6 @@ public:
 
     const std::string& version() noexcept { return m_quotesource->get_version(); }
     const QuoteSources& sources() noexcept { return m_sources; }
-    GList* sources_as_glist ();
     bool had_failures() noexcept { return !m_failures.empty(); }
     const QFVec& failures() noexcept;
     std::string report_failures() noexcept;
@@ -296,16 +295,6 @@ m_sources{}, m_book{book}, m_dflt_curr{gnc_default_currency()}
     m_sources = m_quotesource->get_sources();
 }
 
-GList*
-GncQuotesImpl::sources_as_glist()
-{
-    GList* slist = nullptr;
-    std::for_each (m_sources.rbegin(), m_sources.rend(),
-                    [&slist](const std::string& source) { slist  = g_list_prepend (slist, g_strdup(source.c_str())); });
-    return slist;
-}
-
-
 void
 GncQuotesImpl::fetch (QofBook *book)
 {
@@ -1081,11 +1070,6 @@ const QuoteSources& GncQuotes::sources() noexcept
     return m_impl->sources ();
 }
 
-GList* GncQuotes::sources_as_glist ()
-{
-    return m_impl->sources_as_glist ();
-}
-
 GncQuotes::~GncQuotes() = default;
 
 bool
diff --git a/libgnucash/app-utils/gnc-quotes.hpp b/libgnucash/app-utils/gnc-quotes.hpp
index 3e835e1843..5b40d76157 100644
--- a/libgnucash/app-utils/gnc-quotes.hpp
+++ b/libgnucash/app-utils/gnc-quotes.hpp
@@ -109,13 +109,6 @@ public:
      */
     const QuoteSources& sources() noexcept;
 
-    /** Get the available Finance::Quote sources as a GList
-     *
-     * @return A double-linked list containing the names of the installed quote sources.
-     * @note the list and its contents are owned by the caller and should be freed with `g_list_free_full(list, g_free)`.
-     */
-    GList* sources_as_glist () ;
-
     /** Report if there were quotes requested but not retrieved.
      *
      * @returns True if there were quote failures.

commit 346499ae0447d3310da443becb6ea23104cc27de
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Feb 12 10:40:11 2024 +0800

    [gnc-commodity.cpp] gnc_quote_source_set_fq_installed takes a StrVec
    
    instead of a GList* of strdup'd chars

diff --git a/gnucash/gnucash-commands.cpp b/gnucash/gnucash-commands.cpp
index 0ff5896ce1..db4dbda55b 100644
--- a/gnucash/gnucash-commands.cpp
+++ b/gnucash/gnucash-commands.cpp
@@ -361,9 +361,8 @@ Gnucash::add_quotes (const bo_str& uri)
     {
         GncQuotes quotes;
         std::cout << bl::format (bl::translate ("Found Finance::Quote version {1}.")) % quotes.version() << std::endl;
-        auto quote_sources = quotes.sources_as_glist();
+        auto quote_sources = quotes.sources();
         gnc_quote_source_set_fq_installed (quotes.version().c_str(), quote_sources);
-        g_list_free_full (quote_sources, g_free);
         quotes.fetch(qof_session_get_book(session));
         if (quotes.had_failures())
             std::cerr << quotes.report_failures() << std::endl;
diff --git a/gnucash/gnucash.cpp b/gnucash/gnucash.cpp
index 4cb4b2d3e0..c07e41f7a3 100644
--- a/gnucash/gnucash.cpp
+++ b/gnucash/gnucash.cpp
@@ -178,9 +178,8 @@ scm_run_gnucash (void *data, [[maybe_unused]] int argc, [[maybe_unused]] char **
         gnc_update_splash_screen (checking, GNC_SPLASH_PERCENTAGE_UNKNOWN);
         GncQuotes quotes;
         auto found = (bl::format (std::string{_("Found Finance::Quote version {1}.")}) % quotes.version()).str();
-        auto quote_sources = quotes.sources_as_glist();
+        auto quote_sources = quotes.sources();
         gnc_quote_source_set_fq_installed (quotes.version().c_str(), quote_sources);
-        g_list_free_full (quote_sources, g_free);
         gnc_update_splash_screen (found.c_str(), GNC_SPLASH_PERCENTAGE_UNKNOWN);
     }
     catch (const GncQuoteException& err)
diff --git a/libgnucash/app-utils/test/gtest-gnc-quotes.cpp b/libgnucash/app-utils/test/gtest-gnc-quotes.cpp
index 9d146d0bc4..fc719bfad3 100644
--- a/libgnucash/app-utils/test/gtest-gnc-quotes.cpp
+++ b/libgnucash/app-utils/test/gtest-gnc-quotes.cpp
@@ -127,9 +127,8 @@ protected:
         gnc_commodity_set_quote_source(fkcm, source);
         gnc_commodity_commit_edit(fkcm);
         gnc_commodity_table_insert(comm_table, fkcm);
-        GList *sources = g_list_prepend(nullptr, (void*)"alphavantage");
+        std::vector<std::string> sources = {"alphavantage"};
         gnc_quote_source_set_fq_installed("TestSuite", sources);
-        g_list_free(sources);
     }
     ~GncQuotesTest() {
         gnc_clear_current_session();
diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index f092703f82..f230355d3c 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -35,6 +35,7 @@
 #include <regex.h>
 #include <qofinstance-p.h>
 
+#include "gnc-commodity.hpp"
 #include "gnc-commodity.h"
 #include "gnc-locale-utils.h"
 #include "gnc-prefs.h"
@@ -537,15 +538,11 @@ gnc_quote_source_get_internal_name (const gnc_quote_source *source)
  ********************************************************************/
 void
 gnc_quote_source_set_fq_installed (const char* version_string,
-                                   const GList *sources_list)
+                                   const std::vector<std::string>& sources_list)
 {
-    gnc_quote_source *source;
-    char *source_name;
-    const GList *node;
-
     ENTER(" ");
 
-    if (!sources_list)
+    if (sources_list.empty())
         return;
 
     if (version_string)
@@ -553,11 +550,11 @@ gnc_quote_source_set_fq_installed (const char* version_string,
     else
         fq_version.clear();
 
-    for (node = sources_list; node; node = node->next)
+    for (const auto& source_name_str : sources_list)
     {
-        source_name = static_cast<char*>(node->data);
+        auto source_name = source_name_str.c_str();
+        auto source = gnc_quote_source_lookup_by_internal(source_name);
 
-        source = gnc_quote_source_lookup_by_internal(source_name);
         if (source != NULL)
         {
             DEBUG("Found source %s: %s", source_name, source->user_name);
diff --git a/libgnucash/engine/gnc-commodity.h b/libgnucash/engine/gnc-commodity.h
index 75d0bc693b..9fde3220da 100644
--- a/libgnucash/engine/gnc-commodity.h
+++ b/libgnucash/engine/gnc-commodity.h
@@ -158,18 +158,6 @@ gboolean gnc_quote_source_fq_installed (void);
  */
 const char* gnc_quote_source_fq_version (void);
 
-/** Update gnucash internal tables based on what Finance::Quote
- *  sources are installed.  Sources that have been explicitly coded
- *  into gnucash are marked sensitive/insensitive based upon whether
- *  they are present. New sources that gnucash doesn't know about are
- *  added to its internal tables.
- *
- *  @param sources_list A list of strings containing the source names
- *  as they are known to F::Q.
- */
-void gnc_quote_source_set_fq_installed (const char* version_string,
-                                        const GList *sources_list);
-
 /** Return the number of entries for a given type of quote source.
  *
  *  @param type The quote source type whose count should be returned.
diff --git a/libgnucash/engine/gnc-commodity.hpp b/libgnucash/engine/gnc-commodity.hpp
index b1e0c53cc7..223d9abe72 100644
--- a/libgnucash/engine/gnc-commodity.hpp
+++ b/libgnucash/engine/gnc-commodity.hpp
@@ -39,6 +39,18 @@
 
 using CommVec = std::vector<gnc_commodity*>;
 
+/** Update gnucash internal tables based on what Finance::Quote
+ *  sources are installed.  Sources that have been explicitly coded
+ *  into gnucash are marked sensitive/insensitive based upon whether
+ *  they are present. New sources that gnucash doesn't know about are
+ *  added to its internal tables.
+ *
+ *  @param sources_list A list of strings containing the source names
+ *  as they are known to F::Q.
+ */
+void gnc_quote_source_set_fq_installed (const char* version_string,
+                                        const std::vector<std::string>& sources_list);
+
 #endif /* GNC_COMMODITY_HPP */
 /** @} */
 /** @} */

commit 47a1a56f16cdd60a1e66f9160cb33bcb4c6b1b87
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun Feb 11 23:07:53 2024 +0800

    [gnc-commodity.cpp] fq_version is a std::string
    
    thus can free itself on exit

diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index c952bea489..f092703f82 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -146,7 +146,7 @@ struct gnc_new_iso_code
 #define GNC_NEW_ISO_CODES \
         (sizeof(gnc_new_iso_codes) / sizeof(struct gnc_new_iso_code))
 
-static char *fq_version = NULL;
+static std::string fq_version;
 
 struct gnc_quote_source_s
 {
@@ -278,7 +278,7 @@ static GList *new_quote_sources = NULL;
 gboolean
 gnc_quote_source_fq_installed (void)
 {
-    return (fq_version != NULL);
+    return (!fq_version.empty());
 }
 
 
@@ -291,7 +291,7 @@ gnc_quote_source_fq_installed (void)
 const char*
 gnc_quote_source_fq_version (void)
 {
-    return fq_version;
+    return fq_version.c_str();
 }
 
 /********************************************************************
@@ -548,14 +548,10 @@ gnc_quote_source_set_fq_installed (const char* version_string,
     if (!sources_list)
         return;
 
-    if (fq_version)
-    {
-        g_free (fq_version);
-        fq_version = NULL;
-    }
-
     if (version_string)
-        fq_version = g_strdup (version_string);
+        fq_version = version_string;
+    else
+        fq_version.clear();
 
     for (node = sources_list; node; node = node->next)
     {

commit f49c2735e352888071d59b2772ec915415c0fab5
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sat Feb 10 15:53:03 2024 +0800

    [gnc-commodity.cpp] initialize quote_sources at compile-time

diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index 0a27ca8729..c952bea489 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -166,7 +166,7 @@ struct gnc_quote_source_s
  * Apply changes here also to the FQ appendix of help.
  */
 static gnc_quote_source currency_quote_source =
-{ true, SOURCE_SINGLE, 0, "Currency", "currency" };
+{ true, SOURCE_CURRENCY, 0, "Currency", "currency" };
 
 /* The single quote method is usually the module name, but
  * sometimes it gets the suffix "_direct"
@@ -239,27 +239,27 @@ static gnc_quote_source single_quote_sources[] =
 
 static gnc_quote_source multiple_quote_sources[] =
 {
-    { false, SOURCE_SINGLE, 0, "Australia (ASX, ...)", "australia" },
-    { false, SOURCE_SINGLE, 0, "Canada (Alphavantage, TSX, ...)", "canada" },
-    { false, SOURCE_SINGLE, 0, "Canada Mutual (Fund Library, StockHouse, ...)", "canadamutual" },
-    { false, SOURCE_SINGLE, 0, "Dutch (AEX, ...)", "dutch" },
-    { false, SOURCE_SINGLE, 0, "Europe (asegr,.bsero, hex ...)", "europe" },
-    { false, SOURCE_SINGLE, 0, "Greece (ASE, ...)", "greece" },
-    { false, SOURCE_SINGLE, 0, "Hungary (Bamosz, BET, ...)", "hu" },
-    { false, SOURCE_SINGLE, 0, "India Mutual (AMFI, ...)", "indiamutual" },
-    { false, SOURCE_SINGLE, 0, "Fidelity (Fidelity, ...)", "fidelity" },
-    { false, SOURCE_SINGLE, 0, "Finland (HEX, ...)", "finland" },
-    { false, SOURCE_SINGLE, 0, "First Trust (First Trust, ...)", "ftportfolios" },
-    { false, SOURCE_SINGLE, 0, "France (bourso, ĺerevenu, ...)", "france" },
-    { false, SOURCE_SINGLE, 0, "Nasdaq (alphavantage, fool, ...)", "nasdaq" },
-    { false, SOURCE_SINGLE, 0, "New Zealand (NZX, ...)", "nz" },
-    { false, SOURCE_SINGLE, 0, "NYSE (alphavantage, fool, ...)", "nyse" },
-    { false, SOURCE_SINGLE, 0, "South Africa (Sharenet, ...)", "za" },
-    { false, SOURCE_SINGLE, 0, "Romania (BSE-RO, ...)", "romania" },
-    { false, SOURCE_SINGLE, 0, "T. Rowe Price", "troweprice" },
-    { false, SOURCE_SINGLE, 0, "U.K. Funds (citywire, FTfunds, MStar, tnetuk, ...)", "ukfunds" },
-    { false, SOURCE_SINGLE, 0, "U.K. Unit Trusts (trustnet, ...)", "uk_unit_trusts" },
-    { false, SOURCE_SINGLE, 0, "USA (Alphavantage, Fool, ...)", "usa" },
+    { false, SOURCE_MULTI, 0, "Australia (ASX, ...)", "australia" },
+    { false, SOURCE_MULTI, 0, "Canada (Alphavantage, TSX, ...)", "canada" },
+    { false, SOURCE_MULTI, 0, "Canada Mutual (Fund Library, StockHouse, ...)", "canadamutual" },
+    { false, SOURCE_MULTI, 0, "Dutch (AEX, ...)", "dutch" },
+    { false, SOURCE_MULTI, 0, "Europe (asegr,.bsero, hex ...)", "europe" },
+    { false, SOURCE_MULTI, 0, "Greece (ASE, ...)", "greece" },
+    { false, SOURCE_MULTI, 0, "Hungary (Bamosz, BET, ...)", "hu" },
+    { false, SOURCE_MULTI, 0, "India Mutual (AMFI, ...)", "indiamutual" },
+    { false, SOURCE_MULTI, 0, "Fidelity (Fidelity, ...)", "fidelity" },
+    { false, SOURCE_MULTI, 0, "Finland (HEX, ...)", "finland" },
+    { false, SOURCE_MULTI, 0, "First Trust (First Trust, ...)", "ftportfolios" },
+    { false, SOURCE_MULTI, 0, "France (bourso, ĺerevenu, ...)", "france" },
+    { false, SOURCE_MULTI, 0, "Nasdaq (alphavantage, fool, ...)", "nasdaq" },
+    { false, SOURCE_MULTI, 0, "New Zealand (NZX, ...)", "nz" },
+    { false, SOURCE_MULTI, 0, "NYSE (alphavantage, fool, ...)", "nyse" },
+    { false, SOURCE_MULTI, 0, "South Africa (Sharenet, ...)", "za" },
+    { false, SOURCE_MULTI, 0, "Romania (BSE-RO, ...)", "romania" },
+    { false, SOURCE_MULTI, 0, "T. Rowe Price", "troweprice" },
+    { false, SOURCE_MULTI, 0, "U.K. Funds (citywire, FTfunds, MStar, tnetuk, ...)", "ukfunds" },
+    { false, SOURCE_MULTI, 0, "U.K. Unit Trusts (trustnet, ...)", "uk_unit_trusts" },
+    { false, SOURCE_MULTI, 0, "USA (Alphavantage, Fool, ...)", "usa" },
 };
 
 static const int num_single_quote_sources =
@@ -325,18 +325,13 @@ gnc_quote_source_init_tables (void)
 
     for (i = 0; i < num_single_quote_sources; i++)
     {
-        single_quote_sources[i].type = SOURCE_SINGLE;
         single_quote_sources[i].index = i;
     }
 
     for (i = 0; i < num_multiple_quote_sources; i++)
     {
-        multiple_quote_sources[i].type = SOURCE_MULTI;
         multiple_quote_sources[i].index = i;
     }
-
-    currency_quote_source.type = SOURCE_CURRENCY;
-    currency_quote_source.index = 0;
 }
 
 

commit d488faacb20520e7d300eafc39f7eab9813af0e8
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sat Feb 10 12:14:40 2024 +0800

    [gnc-commodity.cpp] Convert to cpp

diff --git a/libgnucash/engine/CMakeLists.txt b/libgnucash/engine/CMakeLists.txt
index 2f3feddf53..d036388784 100644
--- a/libgnucash/engine/CMakeLists.txt
+++ b/libgnucash/engine/CMakeLists.txt
@@ -155,7 +155,7 @@ set (engine_SOURCES
   gnc-accounting-period.c
   gnc-aqbanking-templates.cpp
   gnc-budget.cpp
-  gnc-commodity.c
+  gnc-commodity.cpp
   gnc-date.cpp
   gnc-datetime.cpp
   gnc-engine.c
diff --git a/libgnucash/engine/gnc-commodity.c b/libgnucash/engine/gnc-commodity.cpp
similarity index 90%
rename from libgnucash/engine/gnc-commodity.c
rename to libgnucash/engine/gnc-commodity.cpp
index 47dfa0a620..0a27ca8729 100644
--- a/libgnucash/engine/gnc-commodity.c
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -153,8 +153,8 @@ struct gnc_quote_source_s
     gboolean supported;
     QuoteSourceType type;
     gint index;
-    char *user_name;		/* User friendly name incl. region code*/
-    char *internal_name;	/* Name used internally and by finance::quote. */
+    const char *user_name;		/* User friendly name incl. region code*/
+    const char *internal_name;	/* Name used internally and by finance::quote. */
 };
 
 /* To update the following lists scan
@@ -166,7 +166,7 @@ struct gnc_quote_source_s
  * Apply changes here also to the FQ appendix of help.
  */
 static gnc_quote_source currency_quote_source =
-{ TRUE, 0, 0, "Currency", "currency" };
+{ true, SOURCE_SINGLE, 0, "Currency", "currency" };
 
 /* The single quote method is usually the module name, but
  * sometimes it gets the suffix "_direct"
@@ -174,92 +174,92 @@ static gnc_quote_source currency_quote_source =
  */
 static gnc_quote_source single_quote_sources[] =
 {
-    { FALSE, 0, 0, "Alphavantage, US", "alphavantage" },
-    { FALSE, 0, 0, "Amsterdam Euronext eXchange, NL", "aex" },
-    { FALSE, 0, 0, "American International Assurance, HK", "aiahk" },
-    { FALSE, 0, 0, "Association of Mutual Funds in India", "amfiindia" },
-    { FALSE, 0, 0, "Athens Stock Exchange, GR", "asegr" },
-    { FALSE, 0, 0, "Australian Stock Exchange, AU", "asx" },
-    { FALSE, 0, 0, "BAMOSZ funds, HU", "bamosz" },
-    { FALSE, 0, 0, "BMO NesbittBurns, CA", "bmonesbittburns" },
-    { FALSE, 0, 0, "Bucharest Stock Exchange, RO", "bsero" },
-    { FALSE, 0, 0, "Budapest Stock Exchange (BET), ex-BUX, HU", "bse" },
-    { FALSE, 0, 0, "Canada Mutual", "canadamutual" },
-    { FALSE, 0, 0, "Citywire Funds, GB", "citywire" },
-    { FALSE, 0, 0, "Colombo Stock Exchange, LK", "cse" },
-    { FALSE, 0, 0, "Cominvest, ex-Adig, DE", "cominvest" },
-    { FALSE, 0, 0, "Deka Investments, DE", "deka" },
-    { FALSE, 0, 0, "Dutch", "dutch" },
-    { FALSE, 0, 0, "DWS, DE", "dwsfunds" },
-    { FALSE, 0, 0, "Equinox Unit Trusts, ZA", "za_unittrusts" },
-    { FALSE, 0, 0, "Fidelity Direct", "fidelity_direct" },
-    { FALSE, 0, 0, "Fidelity Fixed", "fidelityfixed" },
-    { FALSE, 0, 0, "Finance Canada", "financecanada" },
-    { FALSE, 0, 0, "Financial Times Funds service, GB", "ftfunds" },
-    { FALSE, 0, 0, "Finanzpartner, DE", "finanzpartner" },
-    { FALSE, 0, 0, "First Trust Portfolios, US", "ftportfolios" },
-    { FALSE, 0, 0, "Fund Library, CA", "fundlibrary" },
-    { FALSE, 0, 0, "GoldMoney spot rates, JE", "goldmoney" },
-    { FALSE, 0, 0, "Greece", "greece" },
-    { FALSE, 0, 0, "Helsinki stock eXchange, FI", "hex" },
-    { FALSE, 0, 0, "Hungary", "hu" },
-    { FALSE, 0, 0, "India Mutual", "indiamutual" },
-    { FALSE, 0, 0, "Man Investments, AU", "maninv" },
-    { FALSE, 0, 0, "Morningstar, GB", "mstaruk" },
-    { FALSE, 0, 0, "Morningstar, JP", "morningstarjp" },
-    { FALSE, 0, 0, "Morningstar, SE", "morningstar" },
-    { FALSE, 0, 0, "Motley Fool, US", "fool" },
-    { FALSE, 0, 0, "New Zealand stock eXchange, NZ", "nzx" },
-    { FALSE, 0, 0, "Paris Stock Exchange/Boursorama, FR", "bourso" },
-    { FALSE, 0, 0, "Paris Stock Exchange/LeRevenu, FR", "lerevenu" },
-    { FALSE, 0, 0, "Platinum Asset Management, AU", "platinum" },
-    { FALSE, 0, 0, "Romania", "romania" },
-    { FALSE, 0, 0, "SIX Swiss Exchange funds, CH", "sixfunds" },
-    { FALSE, 0, 0, "SIX Swiss Exchange shares, CH", "sixshares" },
-    { FALSE, 0, 0, "Skandinaviska Enskilda Banken, SE", "seb_funds" },
-    { FALSE, 0, 0, "Sharenet, ZA", "za" },
-    { FALSE, 0, 0, "StockHouse Canada", "stockhousecanada_fund" },
-    { FALSE, 0, 0, "TD Waterhouse Funds, CA", "tdwaterhouse" },
-    { FALSE, 0, 0, "TD Efunds, CA", "tdefunds" },
-    { FALSE, 0, 0, "TIAA-CREF, US", "tiaacref" },
-    { FALSE, 0, 0, "Toronto Stock eXchange, CA", "tsx" },
-    { FALSE, 0, 0, "T. Rowe Price", "troweprice" },
-    { FALSE, 0, 0, "T. Rowe Price, US", "troweprice_direct" },
-    { FALSE, 0, 0, "Trustnet via tnetuk.pm, GB", "tnetuk" },
-    { FALSE, 0, 0, "Trustnet via trustnet.pm, GB", "trustnet" },
-    { FALSE, 0, 0, "U.K. Unit Trusts", "uk_unit_trusts" },
-    { FALSE, 0, 0, "Union Investment, DE", "unionfunds" },
-    { FALSE, 0, 0, "US Treasury Bonds", "usfedbonds" },
-    { FALSE, 0, 0, "US Govt. Thrift Savings Plan", "tsp" },
-    { FALSE, 0, 0, "Vanguard", "vanguard" }, /* Method of Alphavantage */
-    { FALSE, 0, 0, "VWD, DE (unmaintained)", "vwd" },
-    { FALSE, 0, 0, "Yahoo as JSON", "yahoo_json" },
-    { FALSE, 0, 0, "Yahoo as YQL", "yahoo_yql" },
+    { false, SOURCE_SINGLE, 0, "Alphavantage, US", "alphavantage" },
+    { false, SOURCE_SINGLE, 0, "Amsterdam Euronext eXchange, NL", "aex" },
+    { false, SOURCE_SINGLE, 0, "American International Assurance, HK", "aiahk" },
+    { false, SOURCE_SINGLE, 0, "Association of Mutual Funds in India", "amfiindia" },
+    { false, SOURCE_SINGLE, 0, "Athens Stock Exchange, GR", "asegr" },
+    { false, SOURCE_SINGLE, 0, "Australian Stock Exchange, AU", "asx" },
+    { false, SOURCE_SINGLE, 0, "BAMOSZ funds, HU", "bamosz" },
+    { false, SOURCE_SINGLE, 0, "BMO NesbittBurns, CA", "bmonesbittburns" },
+    { false, SOURCE_SINGLE, 0, "Bucharest Stock Exchange, RO", "bsero" },
+    { false, SOURCE_SINGLE, 0, "Budapest Stock Exchange (BET), ex-BUX, HU", "bse" },
+    { false, SOURCE_SINGLE, 0, "Canada Mutual", "canadamutual" },
+    { false, SOURCE_SINGLE, 0, "Citywire Funds, GB", "citywire" },
+    { false, SOURCE_SINGLE, 0, "Colombo Stock Exchange, LK", "cse" },
+    { false, SOURCE_SINGLE, 0, "Cominvest, ex-Adig, DE", "cominvest" },
+    { false, SOURCE_SINGLE, 0, "Deka Investments, DE", "deka" },
+    { false, SOURCE_SINGLE, 0, "Dutch", "dutch" },
+    { false, SOURCE_SINGLE, 0, "DWS, DE", "dwsfunds" },
+    { false, SOURCE_SINGLE, 0, "Equinox Unit Trusts, ZA", "za_unittrusts" },
+    { false, SOURCE_SINGLE, 0, "Fidelity Direct", "fidelity_direct" },
+    { false, SOURCE_SINGLE, 0, "Fidelity Fixed", "fidelityfixed" },
+    { false, SOURCE_SINGLE, 0, "Finance Canada", "financecanada" },
+    { false, SOURCE_SINGLE, 0, "Financial Times Funds service, GB", "ftfunds" },
+    { false, SOURCE_SINGLE, 0, "Finanzpartner, DE", "finanzpartner" },
+    { false, SOURCE_SINGLE, 0, "First Trust Portfolios, US", "ftportfolios" },
+    { false, SOURCE_SINGLE, 0, "Fund Library, CA", "fundlibrary" },
+    { false, SOURCE_SINGLE, 0, "GoldMoney spot rates, JE", "goldmoney" },
+    { false, SOURCE_SINGLE, 0, "Greece", "greece" },
+    { false, SOURCE_SINGLE, 0, "Helsinki stock eXchange, FI", "hex" },
+    { false, SOURCE_SINGLE, 0, "Hungary", "hu" },
+    { false, SOURCE_SINGLE, 0, "India Mutual", "indiamutual" },
+    { false, SOURCE_SINGLE, 0, "Man Investments, AU", "maninv" },
+    { false, SOURCE_SINGLE, 0, "Morningstar, GB", "mstaruk" },
+    { false, SOURCE_SINGLE, 0, "Morningstar, JP", "morningstarjp" },
+    { false, SOURCE_SINGLE, 0, "Morningstar, SE", "morningstar" },
+    { false, SOURCE_SINGLE, 0, "Motley Fool, US", "fool" },
+    { false, SOURCE_SINGLE, 0, "New Zealand stock eXchange, NZ", "nzx" },
+    { false, SOURCE_SINGLE, 0, "Paris Stock Exchange/Boursorama, FR", "bourso" },
+    { false, SOURCE_SINGLE, 0, "Paris Stock Exchange/LeRevenu, FR", "lerevenu" },
+    { false, SOURCE_SINGLE, 0, "Platinum Asset Management, AU", "platinum" },
+    { false, SOURCE_SINGLE, 0, "Romania", "romania" },
+    { false, SOURCE_SINGLE, 0, "SIX Swiss Exchange funds, CH", "sixfunds" },
+    { false, SOURCE_SINGLE, 0, "SIX Swiss Exchange shares, CH", "sixshares" },
+    { false, SOURCE_SINGLE, 0, "Skandinaviska Enskilda Banken, SE", "seb_funds" },
+    { false, SOURCE_SINGLE, 0, "Sharenet, ZA", "za" },
+    { false, SOURCE_SINGLE, 0, "StockHouse Canada", "stockhousecanada_fund" },
+    { false, SOURCE_SINGLE, 0, "TD Waterhouse Funds, CA", "tdwaterhouse" },
+    { false, SOURCE_SINGLE, 0, "TD Efunds, CA", "tdefunds" },
+    { false, SOURCE_SINGLE, 0, "TIAA-CREF, US", "tiaacref" },
+    { false, SOURCE_SINGLE, 0, "Toronto Stock eXchange, CA", "tsx" },
+    { false, SOURCE_SINGLE, 0, "T. Rowe Price", "troweprice" },
+    { false, SOURCE_SINGLE, 0, "T. Rowe Price, US", "troweprice_direct" },
+    { false, SOURCE_SINGLE, 0, "Trustnet via tnetuk.pm, GB", "tnetuk" },
+    { false, SOURCE_SINGLE, 0, "Trustnet via trustnet.pm, GB", "trustnet" },
+    { false, SOURCE_SINGLE, 0, "U.K. Unit Trusts", "uk_unit_trusts" },
+    { false, SOURCE_SINGLE, 0, "Union Investment, DE", "unionfunds" },
+    { false, SOURCE_SINGLE, 0, "US Treasury Bonds", "usfedbonds" },
+    { false, SOURCE_SINGLE, 0, "US Govt. Thrift Savings Plan", "tsp" },
+    { false, SOURCE_SINGLE, 0, "Vanguard", "vanguard" }, /* Method of Alphavantage */
+    { false, SOURCE_SINGLE, 0, "VWD, DE (unmaintained)", "vwd" },
+    { false, SOURCE_SINGLE, 0, "Yahoo as JSON", "yahoo_json" },
+    { false, SOURCE_SINGLE, 0, "Yahoo as YQL", "yahoo_yql" },
 };
 
 static gnc_quote_source multiple_quote_sources[] =
 {
-    { FALSE, 0, 0, "Australia (ASX, ...)", "australia" },
-    { FALSE, 0, 0, "Canada (Alphavantage, TSX, ...)", "canada" },
-    { FALSE, 0, 0, "Canada Mutual (Fund Library, StockHouse, ...)", "canadamutual" },
-    { FALSE, 0, 0, "Dutch (AEX, ...)", "dutch" },
-    { FALSE, 0, 0, "Europe (asegr,.bsero, hex ...)", "europe" },
-    { FALSE, 0, 0, "Greece (ASE, ...)", "greece" },
-    { FALSE, 0, 0, "Hungary (Bamosz, BET, ...)", "hu" },
-    { FALSE, 0, 0, "India Mutual (AMFI, ...)", "indiamutual" },
-    { FALSE, 0, 0, "Fidelity (Fidelity, ...)", "fidelity" },
-    { FALSE, 0, 0, "Finland (HEX, ...)", "finland" },
-    { FALSE, 0, 0, "First Trust (First Trust, ...)", "ftportfolios" },
-    { FALSE, 0, 0, "France (bourso, ĺerevenu, ...)", "france" },
-    { FALSE, 0, 0, "Nasdaq (alphavantage, fool, ...)", "nasdaq" },
-    { FALSE, 0, 0, "New Zealand (NZX, ...)", "nz" },
-    { FALSE, 0, 0, "NYSE (alphavantage, fool, ...)", "nyse" },
-    { FALSE, 0, 0, "South Africa (Sharenet, ...)", "za" },
-    { FALSE, 0, 0, "Romania (BSE-RO, ...)", "romania" },
-    { FALSE, 0, 0, "T. Rowe Price", "troweprice" },
-    { FALSE, 0, 0, "U.K. Funds (citywire, FTfunds, MStar, tnetuk, ...)", "ukfunds" },
-    { FALSE, 0, 0, "U.K. Unit Trusts (trustnet, ...)", "uk_unit_trusts" },
-    { FALSE, 0, 0, "USA (Alphavantage, Fool, ...)", "usa" },
+    { false, SOURCE_SINGLE, 0, "Australia (ASX, ...)", "australia" },
+    { false, SOURCE_SINGLE, 0, "Canada (Alphavantage, TSX, ...)", "canada" },
+    { false, SOURCE_SINGLE, 0, "Canada Mutual (Fund Library, StockHouse, ...)", "canadamutual" },
+    { false, SOURCE_SINGLE, 0, "Dutch (AEX, ...)", "dutch" },
+    { false, SOURCE_SINGLE, 0, "Europe (asegr,.bsero, hex ...)", "europe" },
+    { false, SOURCE_SINGLE, 0, "Greece (ASE, ...)", "greece" },
+    { false, SOURCE_SINGLE, 0, "Hungary (Bamosz, BET, ...)", "hu" },
+    { false, SOURCE_SINGLE, 0, "India Mutual (AMFI, ...)", "indiamutual" },
+    { false, SOURCE_SINGLE, 0, "Fidelity (Fidelity, ...)", "fidelity" },
+    { false, SOURCE_SINGLE, 0, "Finland (HEX, ...)", "finland" },
+    { false, SOURCE_SINGLE, 0, "First Trust (First Trust, ...)", "ftportfolios" },
+    { false, SOURCE_SINGLE, 0, "France (bourso, ĺerevenu, ...)", "france" },
+    { false, SOURCE_SINGLE, 0, "Nasdaq (alphavantage, fool, ...)", "nasdaq" },
+    { false, SOURCE_SINGLE, 0, "New Zealand (NZX, ...)", "nz" },
+    { false, SOURCE_SINGLE, 0, "NYSE (alphavantage, fool, ...)", "nyse" },
+    { false, SOURCE_SINGLE, 0, "South Africa (Sharenet, ...)", "za" },
+    { false, SOURCE_SINGLE, 0, "Romania (BSE-RO, ...)", "romania" },
+    { false, SOURCE_SINGLE, 0, "T. Rowe Price", "troweprice" },
+    { false, SOURCE_SINGLE, 0, "U.K. Funds (citywire, FTfunds, MStar, tnetuk, ...)", "ukfunds" },
+    { false, SOURCE_SINGLE, 0, "U.K. Unit Trusts (trustnet, ...)", "uk_unit_trusts" },
+    { false, SOURCE_SINGLE, 0, "USA (Alphavantage, Fool, ...)", "usa" },
 };
 
 static const int num_single_quote_sources =
@@ -354,7 +354,7 @@ gnc_quote_source_add_new (const char *source_name, gboolean supported)
     gnc_quote_source *new_source;
 
     DEBUG("Creating new source %s", (source_name == NULL ? "(null)" : source_name));
-    new_source = malloc(sizeof(gnc_quote_source));
+    new_source = g_new0 (gnc_quote_source, 1);
     new_source->supported = supported;
     new_source->type = SOURCE_UNKNOWN;
     new_source->index = g_list_length(new_quote_sources);
@@ -411,7 +411,7 @@ gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
         node = g_list_nth(new_quote_sources, index);
         if (node)
         {
-            source = node->data;
+            source = static_cast<gnc_quote_source*>(node->data);
             LEAVE("found %s", source->user_name);
             return source;
         }
@@ -451,7 +451,7 @@ gnc_quote_source_lookup_by_internal(const char * name)
 
     for (i = 0, node = new_quote_sources; node; node = node->next, i++)
     {
-        source = node->data;
+        source = static_cast<gnc_quote_source*>(node->data);
         if (g_strcmp0(name, source->internal_name) == 0)
             return source;
     }
@@ -564,7 +564,7 @@ gnc_quote_source_set_fq_installed (const char* version_string,
 
     for (node = sources_list; node; node = node->next)
     {
-        source_name = node->data;
+        source_name = static_cast<char*>(node->data);
 
         source = gnc_quote_source_lookup_by_internal(source_name);
         if (source != NULL)
@@ -749,7 +749,7 @@ gnc_commodity_set_property (GObject         *object,
     switch (prop_id)
     {
     case PROP_NAMESPACE:
-        gnc_commodity_set_namespace(commodity, g_value_get_object(value));
+        gnc_commodity_set_namespace(commodity, static_cast<const char*>(g_value_get_object(value)));
         break;
     case PROP_FULL_NAME:
         gnc_commodity_set_fullname(commodity, g_value_get_string(value));
@@ -767,7 +767,7 @@ gnc_commodity_set_property (GObject         *object,
         gnc_commodity_set_quote_flag(commodity, g_value_get_boolean(value));
         break;
     case PROP_QUOTE_SOURCE:
-        gnc_commodity_set_quote_source(commodity, g_value_get_pointer(value));
+        gnc_commodity_set_quote_source(commodity, static_cast<gnc_quote_source*>(g_value_get_pointer(value)));
         break;
     case PROP_QUOTE_TZ:
         gnc_commodity_set_quote_tz(commodity, g_value_get_string(value));
@@ -872,7 +872,7 @@ gnc_commodity_new(QofBook *book, const char * fullname,
                   const char * name_space, const char * mnemonic,
                   const char * cusip, int fraction)
 {
-    gnc_commodity * retval = g_object_new(GNC_TYPE_COMMODITY, NULL);
+    auto retval = GNC_COMMODITY(g_object_new(GNC_TYPE_COMMODITY, NULL));
 
     qof_instance_init_data (&retval->inst, GNC_ID_COMMODITY, book);
     gnc_commodity_begin_edit(retval);
@@ -991,7 +991,7 @@ gnc_commodity_clone(const gnc_commodity *src, QofBook *dest_book)
     gnc_commodityPrivate* src_priv;
     gnc_commodityPrivate* dest_priv;
 
-    gnc_commodity * dest = g_object_new(GNC_TYPE_COMMODITY, NULL);
+    auto dest = GNC_COMMODITY (g_object_new(GNC_TYPE_COMMODITY, NULL));
     qof_instance_init_data (&dest->inst, GNC_ID_COMMODITY, dest_book);
     src_priv = GET_PRIVATE(src);
     dest_priv = GET_PRIVATE(dest);
@@ -1637,7 +1637,7 @@ int gnc_commodity_compare(const gnc_commodity * a, const gnc_commodity * b)
 // when the commodities match.
 int gnc_commodity_compare_void(const void * a, const void * b)
 {
-    return gnc_commodity_compare(a, b);
+    return gnc_commodity_compare(GNC_COMMODITY (a), GNC_COMMODITY (b));
 }
 
 /************************************************************
@@ -1707,7 +1707,7 @@ gnc_commodity_table *
 gnc_commodity_table_get_table(QofBook *book)
 {
     if (!book) return NULL;
-    return qof_book_get_data (book, GNC_COMMODITY_TABLE);
+    return static_cast<gnc_commodity_table*>(qof_book_get_data (book, GNC_COMMODITY_TABLE));
 }
 
 gnc_commodity *
@@ -1798,7 +1798,7 @@ gnc_commodity_table_lookup(const gnc_commodity_table * table,
                 }
             }
         }
-        return g_hash_table_lookup(nsp->cm_table, (gpointer)mnemonic);
+        return GNC_COMMODITY(g_hash_table_lookup(nsp->cm_table, (gpointer)mnemonic));
     }
     else
     {
@@ -1860,10 +1860,11 @@ gnc_commodity_table_find_full(const gnc_commodity_table * table,
 
     for (iterator = all; iterator; iterator = iterator->next)
     {
+        auto commodity = GNC_COMMODITY (iterator->data);
         if (!strcmp(fullname,
-                    gnc_commodity_get_printname(iterator->data)))
+                    gnc_commodity_get_printname(commodity)))
         {
-            retval = iterator->data;
+            retval = commodity;
             break;
         }
     }
@@ -2017,7 +2018,7 @@ gnc_commodity_table_has_namespace(const gnc_commodity_table * table,
 static void
 hash_keys_helper(gpointer key, gpointer value, gpointer data)
 {
-    GList ** l = data;
+    auto l = (GList**)data;
     *l = g_list_prepend(*l, key);
 }
 
@@ -2032,7 +2033,7 @@ g_hash_table_keys(GHashTable * table)
 static void
 hash_values_helper(gpointer key, gpointer value, gpointer data)
 {
-    GList ** l = data;
+    auto l = (GList**)data;
     *l = g_list_prepend(*l, value);
 }
 
@@ -2146,9 +2147,9 @@ gnc_commodity_table_get_commodities(const gnc_commodity_table * table,
 static void
 get_quotables_helper1(gpointer key, gpointer value, gpointer data)
 {
-    gnc_commodity *comm = value;
+    auto comm = GNC_COMMODITY(value);
     gnc_commodityPrivate* priv = GET_PRIVATE(comm);
-    GList ** l = data;
+    auto l = static_cast<GList**>(data);
 
     if (!priv->quote_flag ||
             !priv->quote_source || !priv->quote_source->supported)
@@ -2159,7 +2160,7 @@ get_quotables_helper1(gpointer key, gpointer value, gpointer data)
 static gboolean
 get_quotables_helper2 (gnc_commodity *comm, gpointer data)
 {
-    GList ** l = data;
+    auto l = static_cast<GList**>(data);
     gnc_commodityPrivate* priv = GET_PRIVATE(comm);
 
     if (!priv->quote_flag ||
@@ -2194,7 +2195,7 @@ gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table)
         nslist = gnc_commodity_table_get_namespaces(table);
         for (tmp = nslist; tmp; tmp = tmp->next)
         {
-            name_space = tmp->data;
+            name_space = static_cast<const char*>(tmp->data);
             if (regexec(&pattern, name_space, 0, NULL, 0) == 0)
             {
                 DEBUG("Running list of %s commodities", name_space);
@@ -2253,9 +2254,9 @@ gnc_commodity_table_add_namespace(gnc_commodity_table * table,
     ns = gnc_commodity_table_find_namespace(table, name_space);
     if (!ns)
     {
-        ns = g_object_new(GNC_TYPE_COMMODITY_NAMESPACE, NULL);
+        ns = static_cast<gnc_commodity_namespace*>(g_object_new(GNC_TYPE_COMMODITY_NAMESPACE, NULL));
         ns->cm_table = g_hash_table_new(g_str_hash, g_str_equal);
-        ns->name = CACHE_INSERT((gpointer)name_space);
+        ns->name = CACHE_INSERT(static_cast<const char*>(name_space));
         ns->iso4217 = gnc_commodity_namespace_is_iso(name_space);
         qof_instance_init_data (&ns->inst, GNC_ID_COMMODITY_NAMESPACE, book);
         qof_event_gen (&ns->inst, QOF_EVENT_CREATE, NULL);
@@ -2278,7 +2279,7 @@ gnc_commodity_table_find_namespace(const gnc_commodity_table * table,
         return NULL;
 
     name_space = gnc_commodity_table_map_namespace(name_space);
-    return g_hash_table_lookup(table->ns_table, (gpointer)name_space);
+    return static_cast<gnc_commodity_namespace*>(g_hash_table_lookup(table->ns_table, (gpointer)name_space));
 }
 
 
@@ -2299,9 +2300,9 @@ gnc_commodity_find_commodity_by_guid(const GncGUID *guid, QofBook *book)
 static int
 ns_helper(gpointer key, gpointer value, gpointer user_data)
 {
-    gnc_commodity * c = value;
+    auto c = GNC_COMMODITY(value);
     gnc_commodity_destroy(c);
-    CACHE_REMOVE(key);  /* key is commodity mnemonic */
+    CACHE_REMOVE(static_cast<char*>(key));  /* key is commodity mnemonic */
     return TRUE;
 }
 
@@ -2400,7 +2401,7 @@ gnc_commodity_table_destroy(gnc_commodity_table * t)
     for (item = t->ns_list; item; item = next)
     {
         next = g_list_next(item);
-        ns = item->data;
+        ns = static_cast<gnc_commodity_namespace*>(item->data);
         gnc_commodity_table_delete_namespace(t, ns->name);
     }
 
@@ -2552,7 +2553,7 @@ gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
     MonetaryList *l = list, *tmp;
     for (tmp = list; tmp; tmp = tmp->next)
     {
-        gnc_monetary *list_mon = tmp->data;
+        auto list_mon = static_cast<gnc_monetary*>(tmp->data);
         if (gnc_commodity_equiv(list_mon->commodity, add_mon.commodity))
         {
             list_mon->value = gnc_numeric_add(list_mon->value, add_mon.value,
@@ -2564,7 +2565,7 @@ gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
     /* See if we found an entry, and add one if not */
     if (tmp == NULL)
     {
-        gnc_monetary *new_mon = g_new0(gnc_monetary, 1);
+        auto new_mon = static_cast<gnc_monetary*>(g_new0(gnc_monetary, 1));
         *new_mon = add_mon;
         l = g_list_prepend(l, new_mon);
     }
@@ -2580,7 +2581,7 @@ gnc_monetary_list_delete_zeros(MonetaryList *list)
     MonetaryList *node, *next;
     for (node = list; node; node = next)
     {
-        gnc_monetary *mon = node->data;
+        auto mon = static_cast<gnc_monetary*>(node->data);
         next = node->next;
         if (gnc_numeric_zero_p(mon->value))
         {
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7a45a22348..088ff5056c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -631,7 +631,7 @@ libgnucash/engine/gnc-aqbanking-templates.cpp
 libgnucash/engine/gncBillTerm.c
 libgnucash/engine/gnc-budget.cpp
 libgnucash/engine/gncBusiness.c
-libgnucash/engine/gnc-commodity.c
+libgnucash/engine/gnc-commodity.cpp
 libgnucash/engine/gnc-commodity.h
 libgnucash/engine/gncCustomer.c
 libgnucash/engine/gnc-date.cpp



Summary of changes:
 gnucash/gnucash-commands.cpp                       |   3 +-
 gnucash/gnucash.cpp                                |   3 +-
 libgnucash/app-utils/gnc-quotes.cpp                |  16 -
 libgnucash/app-utils/gnc-quotes.hpp                |   7 -
 libgnucash/app-utils/test/gtest-gnc-quotes.cpp     |   3 +-
 libgnucash/engine/CMakeLists.txt                   |   2 +-
 .../engine/{gnc-commodity.c => gnc-commodity.cpp}  | 527 +++++++++------------
 libgnucash/engine/gnc-commodity.h                  |  12 -
 libgnucash/engine/gnc-commodity.hpp                |  12 +
 po/POTFILES.in                                     |   2 +-
 10 files changed, 240 insertions(+), 347 deletions(-)
 rename libgnucash/engine/{gnc-commodity.c => gnc-commodity.cpp} (84%)



More information about the gnucash-changes mailing list