LCOV - code coverage report
Current view: top level - libgnucash/engine - gnc-commodity.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 75.1 % 947 711
Test Date: 2025-02-07 16:25:45 Functions: 85.0 % 133 113
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /********************************************************************
       2                 :             :  * gnc-commodity.c -- api for tradable commodities (incl. currency) *
       3                 :             :  * Copyright (C) 2000 Bill Gribble                                  *
       4                 :             :  * Copyright (C) 2001,2003 Linas Vepstas <linas@linas.org>          *
       5                 :             :  * Copyright (c) 2006 David Hampton <hampton@employees.org>         *
       6                 :             :  *                                                                  *
       7                 :             :  * This program is free software; you can redistribute it and/or    *
       8                 :             :  * modify it under the terms of the GNU General Public License as   *
       9                 :             :  * published by the Free Software Foundation; either version 2 of   *
      10                 :             :  * the License, or (at your option) any later version.              *
      11                 :             :  *                                                                  *
      12                 :             :  * This program is distributed in the hope that it will be useful,  *
      13                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      14                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      15                 :             :  * GNU General Public License for more details.                     *
      16                 :             :  *                                                                  *
      17                 :             :  * You should have received a copy of the GNU General Public License*
      18                 :             :  * along with this program; if not, contact:                        *
      19                 :             :  *                                                                  *
      20                 :             :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      21                 :             :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      22                 :             :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      23                 :             :  *                                                                  *
      24                 :             :  *******************************************************************/
      25                 :             : 
      26                 :             : #include <config.h>
      27                 :             : 
      28                 :             : #include <glib.h>
      29                 :             : #include <glib/gi18n.h>
      30                 :             : #include <ctype.h>
      31                 :             : #include <limits.h>
      32                 :             : #include <string.h>
      33                 :             : #include <stdio.h>
      34                 :             : #include <stdlib.h>
      35                 :             : #include <regex.h>
      36                 :             : #include <qofinstance-p.h>
      37                 :             : 
      38                 :             : #include "gnc-commodity.hpp"
      39                 :             : #include "gnc-commodity.h"
      40                 :             : #include "gnc-locale-utils.h"
      41                 :             : #include "gnc-prefs.h"
      42                 :             : #include "guid.h"
      43                 :             : #include "qofinstance.h"
      44                 :             : 
      45                 :             : #include <list>
      46                 :             : #include <unordered_map>
      47                 :             : 
      48                 :             : static QofLogModule log_module = GNC_MOD_COMMODITY;
      49                 :             : 
      50                 :             : /* Parts per unit is nominal, i.e. number of 'partname' units in
      51                 :             :  * a 'unitname' unit.  fraction is transactional, i.e. how many
      52                 :             :  * of the smallest-transactional-units of the currency are there
      53                 :             :  * in a 'unitname' unit. */
      54                 :             : 
      55                 :             : enum
      56                 :             : {
      57                 :             :     PROP_0,
      58                 :             :     PROP_NAMESPACE,     /* Table */
      59                 :             :     PROP_FULL_NAME,     /* Table */
      60                 :             :     PROP_MNEMONIC,      /* Table */
      61                 :             :     PROP_PRINTNAME,     /* Constructed */
      62                 :             :     PROP_CUSIP,         /* Table */
      63                 :             :     PROP_FRACTION,      /* Table */
      64                 :             :     PROP_UNIQUE_NAME,   /* Constructed */
      65                 :             :     PROP_QUOTE_FLAG,    /* Table */
      66                 :             :     PROP_QUOTE_SOURCE,  /* Table */
      67                 :             :     PROP_QUOTE_TZ,      /* Table */
      68                 :             : };
      69                 :             : 
      70                 :             : struct gnc_commodity_s
      71                 :             : {
      72                 :             :     QofInstance inst;
      73                 :             : };
      74                 :             : 
      75                 :             : typedef struct gnc_commodityPrivate
      76                 :             : {
      77                 :             :     gnc_commodity_namespace *name_space;
      78                 :             : 
      79                 :             :     const char *fullname;
      80                 :             :     const char *mnemonic;
      81                 :             :     char       *printname;
      82                 :             :     const char *cusip;                /* CUSIP or other identifying code */
      83                 :             :     int         fraction;
      84                 :             :     char       *unique_name;
      85                 :             :     char       *user_symbol;
      86                 :             : 
      87                 :             :     gboolean    quote_flag;           /* user wants price quotes */
      88                 :             :     gnc_quote_source *quote_source;   /* current/old source of quotes */
      89                 :             :     const char *quote_tz;
      90                 :             : 
      91                 :             :     /* the number of accounts using this commodity - this field is not
      92                 :             :      * persisted */
      93                 :             :     int         usage_count;
      94                 :             : 
      95                 :             :     /* the default display_symbol, set in iso-4217-currencies at start-up */
      96                 :             :     const char *default_symbol;
      97                 :             : } gnc_commodityPrivate;
      98                 :             : 
      99                 :             : #define GET_PRIVATE(o) \
     100                 :             :     ((gnc_commodityPrivate*)gnc_commodity_get_instance_private((gnc_commodity*)o))
     101                 :             : 
     102                 :             : struct _GncCommodityClass
     103                 :             : {
     104                 :             :     QofInstanceClass parent_class;
     105                 :             : };
     106                 :             : 
     107                 :             : static void commodity_free(gnc_commodity * cm);
     108                 :             : static void gnc_commodity_set_default_symbol(gnc_commodity *, const char *);
     109                 :             : 
     110                 :             : struct gnc_commodity_namespace_s
     111                 :             : {
     112                 :             :     QofInstance inst;
     113                 :             : 
     114                 :             :     const gchar *name;
     115                 :             :     gboolean     iso4217;
     116                 :             :     GHashTable * cm_table;
     117                 :             :     GList      * cm_list;
     118                 :             : };
     119                 :             : 
     120                 :             : struct _GncCommodityNamespaceClass
     121                 :             : {
     122                 :             :     QofInstanceClass parent_class;
     123                 :             : };
     124                 :             : 
     125                 :             : struct gnc_commodity_table_s
     126                 :             : {
     127                 :             :     GHashTable * ns_table;
     128                 :             :     GList      * ns_list;
     129                 :             : };
     130                 :             : 
     131                 :             : static const std::unordered_map<std::string,std::string> gnc_new_iso_codes =
     132                 :             : {
     133                 :             :     {"RUR", "RUB"}, /* Russian Ruble: RUR through 1997-12, RUB from 1998-01 onwards; see bug #393185 */
     134                 :             :     {"PLZ", "PLN"}, /* Polish Zloty */
     135                 :             :     {"UAG", "UAH"}, /* Ukraine Hryvnia */
     136                 :             :     {"NIS", "ILS"}, /* New Israeli Shekel: The informal abbreviation may be "NIS", but
     137                 :             :                      its iso-4217 is clearly ILS and only this! Incorrectly changed
     138                 :             :                      due to bug#152755 (Nov 2004) and changed back again by bug#492417
     139                 :             :                      (Oct 2008). */
     140                 :             :     {"MXP", "MXN"}, /* Mexican (Nuevo) Peso */
     141                 :             :     {"TRL", "TRY"}, /* New Turkish Lira: changed 2005 */
     142                 :             : 
     143                 :             :     /* Only add currencies to this table when the old currency no longer
     144                 :             :      * exists in the file iso-4217-currencies.xml */
     145                 :             : };
     146                 :             : 
     147                 :             : static std::string fq_version;
     148                 :             : 
     149                 :             : struct gnc_quote_source_s
     150                 :             : {
     151                 :             : private:
     152                 :             :     gboolean m_supported;
     153                 :             :     QuoteSourceType m_type;
     154                 :             :     std::string m_user_name;            /* User friendly name incl. region code*/
     155                 :             :     std::string m_internal_name;        /* Name used internally and by finance::quote. */
     156                 :             : public:
     157                 :          23 :     bool get_supported () const { return m_supported; }
     158                 :          15 :     void set_supported (bool supported) { m_supported = supported; }
     159                 :           0 :     QuoteSourceType get_type () const { return m_type; }
     160                 :           2 :     const char* get_user_name () const { return m_user_name.c_str(); }
     161                 :      125392 :     const char* get_internal_name () const { return m_internal_name.c_str(); }
     162                 :        7611 :     gnc_quote_source_s (gboolean supported, QuoteSourceType type,
     163                 :             :                         const char* username, const char* int_name)
     164                 :        7611 :         : m_supported{supported}
     165                 :        7611 :         , m_type{type}
     166                 :       15222 :         , m_user_name{username ? username : ""}
     167                 :       22833 :         , m_internal_name{int_name ? int_name: ""} { };
     168                 :             : };
     169                 :             : 
     170                 :             : using QuoteSourceList = std::list<gnc_quote_source>;
     171                 :             : 
     172                 :             : /* To update the following lists scan
     173                 :             :  * from github.com/finance-quote/finance-quote
     174                 :             :  * in lib/Finance/Quote/ all *.pm for "methods"
     175                 :             :  * because many of them have more than one -
     176                 :             :  * ideally after each release of them.
     177                 :             :  *
     178                 :             :  * Apply changes here also to the FQ appendix of help.
     179                 :             :  */
     180                 :             : static QuoteSourceList currency_quote_sources =
     181                 :             : {
     182                 :             :     { true, SOURCE_CURRENCY, "Currency", "currency" }
     183                 :             : };
     184                 :             : 
     185                 :             : /* The single quote method is usually the module name, but
     186                 :             :  * sometimes it gets the suffix "_direct"
     187                 :             :  * and the failover method is without suffix.
     188                 :             :  */
     189                 :             : static QuoteSourceList single_quote_sources =
     190                 :             : {
     191                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Alphavantage"), "alphavantage" },
     192                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Amsterdam Euronext eXchange, NL"), "aex" },
     193                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Association of Mutual Funds in India"), "amfiindia" },
     194                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Athens Exchange Group, GR"), "asegr" },
     195                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Australian Stock Exchange, AU"), "asx" },
     196                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Bloomberg"), "bloomberg" },
     197                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Italian Stock Exchange, IT"), "borsa_italiana" },
     198                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "BSE India, IN"), "bseindia" },
     199                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Bucharest Stock Exchange, RO"), "bvb" },
     200                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Colombo Stock Exchange, LK"), "cse" },
     201                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "comdirect, DE"), "comdirect" },
     202                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Consors Bank, DE"), "consorsbank" },
     203                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Deka Investments, DE"), "deka" },
     204                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "DWS, DE"), "dwsfunds" },
     205                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Financial Times Funds service, GB"), "ftfunds" },
     206                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Finanzpartner, DE"), "finanzpartner" },
     207                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "FondsWeb, DE"), "fondsweb" },
     208                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "GoldMoney precious metals"), "goldmoney" },
     209                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Google Web, US Stocks"), "googleweb" },
     210                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "IEX (Investors Exchange), US"), "iexcloud" },
     211                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Market Watch"), "marketwatch" },
     212                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Morningstar, AU"), "morningstarau" },
     213                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Morningstar, CH"), "morningstarch" },
     214                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Morningstar, GB"), "morningstaruk" },
     215                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Morningstar, JP"), "morningstarjp" },
     216                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Motley Fool"), "fool" },
     217                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "New Zealand stock eXchange, NZ"), "nzx" },
     218                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "NSE (National Stock Exchange), IN"), "nseindia" },
     219                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "OnVista, DE"), "onvista"},
     220                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Paris Stock Exchange/Boursorama, FR"), "bourso" },
     221                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "S-Investor, DE"), "sinvestor"},
     222                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Sharenet, ZA"), "za" },
     223                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "SIX Swiss Exchange shares, CH"), "six" },
     224                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Skandinaviska Enskilda Banken, SE"), "seb_funds" },
     225                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "StockData"), "stockdata" },
     226                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Stooq, PL"), "stooq" },
     227                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "T. Rowe Price, US"), "troweprice" },
     228                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Tesouro Direto bonds, BR"), "tesouro_direto" },
     229                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "TIAA-CREF, US"), "tiaacref" },
     230                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Toronto Stock eXchange, CA"), "tsx" },
     231                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Tradegate, DE"), "tradegate" },
     232                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Treasury Direct bonds, US"), "treasurydirect" },
     233                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Twelve Data"), "twelvedata" },
     234                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Union Investment, DE"), "unionfunds" },
     235                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "US Govt. Thrift Savings Plan"), "tsp" },
     236                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "XETRA, DE"), "xetra" },
     237                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Yahoo as JSON"), "yahoo_json" },
     238                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "Yahoo Web"), "yahooweb" },
     239                 :             :     { false, SOURCE_SINGLE, NC_("FQ Source", "YH Finance (FinanceAPI)"), "financeapi" },
     240                 :             : };
     241                 :             : 
     242                 :             : static QuoteSourceList multiple_quote_sources =
     243                 :             : {
     244                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "Australia (ASX)"), "australia" },
     245                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "Australia Funds (MorningstarAU)"), "aufunds" },
     246                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "Canada (Alphavantage, TMX)"), "canada" },
     247                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "Dutch (AEX)"), "dutch" },
     248                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "Europe (ASEGR, Bourso, …)"), "europe" },
     249                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "France (Bourso)"), "france" },
     250                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "Greece (ASEGR)"), "greece" },
     251                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "India (BSEIndia, NSEIndia)"), "india"},
     252                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "India Mutual (AMFI)"), "indiamutual" },
     253                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "Nasdaq (Alphavantage, FinanceAPI, …)"), "nasdaq" },
     254                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "NYSE (Alphavantage, FinanceAPI, …)"), "nyse" },
     255                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "Poland (Stooq)"), "poland" },
     256                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "Romania (BVB)"), "romania" },
     257                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "South Africa (Sharenet)"), "za" },
     258                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "U.K. Funds (FTfunds, MorningstarUK)"), "ukfunds" },
     259                 :             :     { false, SOURCE_MULTI, NC_("FQ Source", "USA (Alphavantage, FinanceAPI, …)"), "usa" },
     260                 :             : };
     261                 :             : 
     262                 :             : static QuoteSourceList new_quote_sources;
     263                 :             : 
     264                 :             : // cannot use map or unordered_map because order must be preserved
     265                 :             : static const std::vector<std::pair<QuoteSourceType,QuoteSourceList&>> quote_sources_map =
     266                 :             :     {
     267                 :             :         { SOURCE_CURRENCY, currency_quote_sources },
     268                 :             :         { SOURCE_SINGLE, single_quote_sources },
     269                 :             :         { SOURCE_MULTI, multiple_quote_sources },
     270                 :             :         { SOURCE_UNKNOWN, new_quote_sources }
     271                 :             :     };
     272                 :             : 
     273                 :             : /********************************************************************
     274                 :             :  * gnc_quote_source_fq_installed
     275                 :             :  *
     276                 :             :  * This function indicates whether or not the Finance::Quote module
     277                 :             :  * is installed on a users computer.
     278                 :             :  ********************************************************************/
     279                 :             : gboolean
     280                 :           0 : gnc_quote_source_fq_installed (void)
     281                 :             : {
     282                 :           0 :     return (!fq_version.empty());
     283                 :             : }
     284                 :             : 
     285                 :             : 
     286                 :             : /********************************************************************
     287                 :             :  * gnc_quote_source_fq_version
     288                 :             :  *
     289                 :             :  * This function the version of the Finance::Quote module installed
     290                 :             :  * on a user's computer or nullptr if no installation is found.
     291                 :             :  ********************************************************************/
     292                 :             : const char*
     293                 :           0 : gnc_quote_source_fq_version (void)
     294                 :             : {
     295                 :           0 :     return fq_version.c_str();
     296                 :             : }
     297                 :             : 
     298                 :             : static QuoteSourceList&
     299                 :          11 : get_quote_source_from_type (QuoteSourceType type)
     300                 :             : {
     301                 :          11 :     auto quote_sources_it = std::find_if (quote_sources_map.begin(), quote_sources_map.end(),
     302                 :          38 :                                           [type] (const auto& qs) { return type == qs.first; });
     303                 :             : 
     304                 :          11 :     if (quote_sources_it != quote_sources_map.end())
     305                 :           7 :         return quote_sources_it->second;
     306                 :             : 
     307                 :           4 :     PWARN ("Invalid Quote Source %d, returning new_quote_sources", type);
     308                 :           4 :     return new_quote_sources;
     309                 :             : }
     310                 :             : 
     311                 :             : /********************************************************************
     312                 :             :  * gnc_quote_source_num_entries
     313                 :             :  *
     314                 :             :  * Return the number of entries for a given type of price source.
     315                 :             :  ********************************************************************/
     316                 :           5 : gint gnc_quote_source_num_entries(QuoteSourceType type)
     317                 :             : {
     318                 :           5 :     auto source{get_quote_source_from_type(type)};
     319                 :          15 :     return std::distance(source.begin(), source.end());
     320                 :           5 : }
     321                 :             : 
     322                 :             : 
     323                 :             : 
     324                 :             : /********************************************************************
     325                 :             :  * gnc_quote_source_add_new
     326                 :             :  *
     327                 :             :  * Add a new price source. Called when unknown source names are found
     328                 :             :  * either in the F::Q installation (a newly available source) or in
     329                 :             :  * the user's data file (a source that has vanished but needs to be
     330                 :             :  * tracked.)
     331                 :             :  ********************************************************************/
     332                 :             : gnc_quote_source *
     333                 :          21 : gnc_quote_source_add_new (const char *source_name, gboolean supported)
     334                 :             : {
     335                 :          21 :     DEBUG("Creating new source %s", (!source_name ? "(null)" : source_name));
     336                 :             :     /* This name can be changed if/when support for this price source is
     337                 :             :      * integrated into gnucash. */
     338                 :             :     /* This name is permanent and must be kept the same if/when support
     339                 :             :      * for this price source is integrated into gnucash (i.e. for a
     340                 :             :      * nice user name). */
     341                 :          21 :     return &new_quote_sources.emplace_back (supported, SOURCE_UNKNOWN, source_name, source_name);
     342                 :             : }
     343                 :             : 
     344                 :             : /********************************************************************
     345                 :             :  * gnc_quote_source_lookup_by_xxx
     346                 :             :  *
     347                 :             :  * Lookup a price source data structure based upon various criteria.
     348                 :             :  ********************************************************************/
     349                 :             : gnc_quote_source *
     350                 :           6 : gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
     351                 :             : {
     352                 :           6 :     ENTER("type/index is %d/%d", type, index);
     353                 :           6 :     auto& sources = get_quote_source_from_type (type);
     354                 :           6 :     if ((size_t) index < sources.size())
     355                 :             :     {
     356                 :           4 :         auto it = std::next(sources.begin(), index);
     357                 :           4 :         LEAVE("found %s", it->get_user_name());
     358                 :           4 :         return &*it;
     359                 :             :     }
     360                 :             : 
     361                 :           2 :     LEAVE("not found");
     362                 :           2 :     return nullptr;
     363                 :             : }
     364                 :             : 
     365                 :             : gnc_quote_source *
     366                 :      124714 : gnc_quote_source_lookup_by_internal(const char * name)
     367                 :             : {
     368                 :      124714 :     if (!name || !*name)
     369                 :           1 :         return nullptr;
     370                 :             : 
     371                 :      124751 :     for (const auto& [_, sources] : quote_sources_map)
     372                 :             :     {
     373                 :      124750 :         auto source_it = std::find_if (sources.begin(), sources.end(),
     374                 :      124859 :                                        [name] (const auto& qs)
     375                 :      124859 :                                        { return (g_strcmp0(name, qs.get_internal_name()) == 0); });
     376                 :      124750 :         if (source_it != sources.end())
     377                 :      124712 :             return &(*source_it);
     378                 :             :     }
     379                 :             : 
     380                 :           1 :     DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);
     381                 :           1 :     return nullptr;
     382                 :             : }
     383                 :             : 
     384                 :             : /********************************************************************
     385                 :             :  * gnc_quote_source_get_xxx
     386                 :             :  *
     387                 :             :  * Accessor functions - get functions only. There are no set functions.
     388                 :             :  ********************************************************************/
     389                 :             : QuoteSourceType
     390                 :           0 : gnc_quote_source_get_type (const gnc_quote_source *source)
     391                 :             : {
     392                 :           0 :     ENTER("%p", source);
     393                 :           0 :     if (!source)
     394                 :             :     {
     395                 :           0 :         LEAVE("bad source");
     396                 :           0 :         return SOURCE_SINGLE;
     397                 :             :     }
     398                 :             : 
     399                 :           0 :     LEAVE("type is %d", source->get_type());
     400                 :           0 :     return source->get_type();
     401                 :             : }
     402                 :             : 
     403                 :             : gint
     404                 :           0 : gnc_quote_source_get_index (const gnc_quote_source *source)
     405                 :             : {
     406                 :           0 :     if (!source)
     407                 :             :     {
     408                 :           0 :         PWARN ("bad source");
     409                 :           0 :         return 0;
     410                 :             :     }
     411                 :             : 
     412                 :           0 :     auto& sources = get_quote_source_from_type (source->get_type());
     413                 :           0 :     auto is_source = [&source](const auto& findif_source)
     414                 :           0 :     { return &findif_source == source; };
     415                 :             : 
     416                 :           0 :     auto iter = std::find_if (sources.begin(), sources.end(), is_source);
     417                 :           0 :     if (iter != sources.end())
     418                 :           0 :         return std::distance (sources.begin(), iter);
     419                 :             : 
     420                 :           0 :     PWARN ("couldn't locate source");
     421                 :           0 :     return 0;
     422                 :             : }
     423                 :             : 
     424                 :             : gboolean
     425                 :          23 : gnc_quote_source_get_supported (const gnc_quote_source *source)
     426                 :             : {
     427                 :          23 :     ENTER("%p", source);
     428                 :          23 :     if (!source)
     429                 :             :     {
     430                 :           0 :         LEAVE("bad source");
     431                 :           0 :         return FALSE;
     432                 :             :     }
     433                 :             : 
     434                 :          23 :     LEAVE("%s supported", source && source->get_supported() ? "" : "not ");
     435                 :          23 :     return source->get_supported();
     436                 :             : }
     437                 :             : 
     438                 :             : const char *
     439                 :           2 : gnc_quote_source_get_user_name (const gnc_quote_source *source)
     440                 :             : {
     441                 :           2 :     ENTER("%p", source);
     442                 :           2 :     if (!source)
     443                 :             :     {
     444                 :           0 :         LEAVE("bad source");
     445                 :           0 :         return nullptr;
     446                 :             :     }
     447                 :           2 :     LEAVE("user name %s", source->get_user_name());
     448                 :           2 :     return source->get_user_name();
     449                 :             : }
     450                 :             : 
     451                 :             : const char *
     452                 :          83 : gnc_quote_source_get_internal_name (const gnc_quote_source *source)
     453                 :             : {
     454                 :          83 :     ENTER("%p", source);
     455                 :          83 :     if (!source)
     456                 :             :     {
     457                 :           6 :         LEAVE("bad source");
     458                 :           6 :         return nullptr;
     459                 :             :     }
     460                 :          77 :     LEAVE("internal name %s", source->get_internal_name());
     461                 :          77 :     return source->get_internal_name();
     462                 :             : }
     463                 :             : 
     464                 :             : 
     465                 :             : /********************************************************************
     466                 :             :  * gnc_quote_source_set_fq_installed
     467                 :             :  *
     468                 :             :  * Update gnucash internal tables on what Finance::Quote sources are
     469                 :             :  * installed.
     470                 :             :  ********************************************************************/
     471                 :             : void
     472                 :          15 : gnc_quote_source_set_fq_installed (const char* version_string,
     473                 :             :                                    const std::vector<std::string>& sources_list)
     474                 :             : {
     475                 :          15 :     ENTER(" ");
     476                 :             : 
     477                 :          15 :     if (sources_list.empty())
     478                 :           0 :         return;
     479                 :             : 
     480                 :          15 :     if (version_string)
     481                 :          15 :         fq_version = version_string;
     482                 :             :     else
     483                 :           0 :         fq_version.clear();
     484                 :             : 
     485                 :          30 :     for (const auto& source_name_str : sources_list)
     486                 :             :     {
     487                 :          15 :         auto source_name = source_name_str.c_str();
     488                 :          15 :         auto source = gnc_quote_source_lookup_by_internal(source_name);
     489                 :             : 
     490                 :          15 :         if (source)
     491                 :             :         {
     492                 :          15 :             DEBUG("Found source %s: %s", source_name, source->get_user_name());
     493                 :          15 :             source->set_supported (true);
     494                 :          15 :             continue;
     495                 :             :         }
     496                 :             : 
     497                 :           0 :         gnc_quote_source_add_new(source_name, TRUE);
     498                 :             :     }
     499                 :          15 :     LEAVE(" ");
     500                 :             : }
     501                 :             : 
     502                 :             : /********************************************************************
     503                 :             :  * QoF Helpers
     504                 :             :  ********************************************************************/
     505                 :             : 
     506                 :             : void
     507                 :      501403 : gnc_commodity_begin_edit (gnc_commodity *cm)
     508                 :             : {
     509                 :      501403 :     qof_begin_edit(&cm->inst);
     510                 :      501403 : }
     511                 :             : 
     512                 :           0 : static void commit_err (QofInstance *inst, QofBackendError errcode)
     513                 :             : {
     514                 :           0 :     PERR ("Failed to commit: %d", errcode);
     515                 :           0 :     gnc_engine_signal_commit_error( errcode );
     516                 :           0 : }
     517                 :             : 
     518                 :       67160 : static void noop (QofInstance *inst) {}
     519                 :             : 
     520                 :             : static void
     521                 :       41354 : comm_free(QofInstance* inst)
     522                 :             : {
     523                 :       41354 :     commodity_free( GNC_COMMODITY(inst) );
     524                 :       41354 : }
     525                 :             : 
     526                 :             : void
     527                 :      501403 : gnc_commodity_commit_edit (gnc_commodity *cm)
     528                 :             : {
     529                 :      501403 :     if (!qof_commit_edit (QOF_INSTANCE(cm))) return;
     530                 :      108514 :     qof_commit_edit_part2 (&cm->inst, commit_err, noop, comm_free);
     531                 :             : }
     532                 :             : 
     533                 :             : /********************************************************************
     534                 :             :  * gnc_commodity_new
     535                 :             :  ********************************************************************/
     536                 :             : 
     537                 :             : static void
     538                 :      459836 : mark_commodity_dirty (gnc_commodity *cm)
     539                 :             : {
     540                 :      459836 :     qof_instance_set_dirty(&cm->inst);
     541                 :      459836 :     qof_event_gen (&cm->inst, QOF_EVENT_MODIFY, nullptr);
     542                 :      459836 : }
     543                 :             : 
     544                 :             : static void
     545                 :      264290 : reset_printname(gnc_commodityPrivate *priv)
     546                 :             : {
     547                 :      264290 :     g_free(priv->printname);
     548                 :      528580 :     priv->printname = g_strdup_printf("%s (%s)",
     549                 :      264290 :                                       priv->mnemonic ? priv->mnemonic : "",
     550                 :      264290 :                                       priv->fullname ? priv->fullname : "");
     551                 :      264290 : }
     552                 :             : 
     553                 :             : static void
     554                 :      198071 : reset_unique_name(gnc_commodityPrivate *priv)
     555                 :             : {
     556                 :             :     gnc_commodity_namespace *ns;
     557                 :             : 
     558                 :      198071 :     g_free(priv->unique_name);
     559                 :      198071 :     ns = priv->name_space;
     560                 :      198071 :     priv->unique_name = g_strdup_printf("%s::%s",
     561                 :             :                                         ns ? ns->name : "",
     562                 :      198071 :                                         priv->mnemonic ? priv->mnemonic : "");
     563                 :      198071 : }
     564                 :             : 
     565                 :             : /* GObject Initialization */
     566                 :     1659327 : G_DEFINE_TYPE_WITH_PRIVATE(gnc_commodity, gnc_commodity, QOF_TYPE_INSTANCE)
     567                 :             : 
     568                 :             : static void
     569                 :       66090 : gnc_commodity_init(gnc_commodity* com)
     570                 :             : {
     571                 :             :     gnc_commodityPrivate* priv;
     572                 :             : 
     573                 :       66090 :     priv = GET_PRIVATE(com);
     574                 :             : 
     575                 :       66090 :     priv->name_space = nullptr;
     576                 :       66090 :     priv->fullname = CACHE_INSERT("");
     577                 :       66090 :     priv->mnemonic = CACHE_INSERT("");
     578                 :       66090 :     priv->cusip = CACHE_INSERT("");
     579                 :       66090 :     priv->fraction = 10000;
     580                 :       66090 :     priv->quote_flag = 0;
     581                 :       66090 :     priv->quote_source = nullptr;
     582                 :       66090 :     priv->quote_tz = CACHE_INSERT("");
     583                 :             : 
     584                 :       66090 :     reset_printname(priv);
     585                 :       66090 :     reset_unique_name(priv);
     586                 :       66090 : }
     587                 :             : 
     588                 :             : static void
     589                 :       41508 : gnc_commodity_dispose(GObject *comp)
     590                 :             : {
     591                 :       41508 :     G_OBJECT_CLASS(gnc_commodity_parent_class)->dispose(comp);
     592                 :       41508 : }
     593                 :             : 
     594                 :             : static void
     595                 :       41508 : gnc_commodity_finalize(GObject* comp)
     596                 :             : {
     597                 :       41508 :     G_OBJECT_CLASS(gnc_commodity_parent_class)->finalize(comp);
     598                 :       41508 : }
     599                 :             : /* Note that g_value_set_object() refs the object, as does
     600                 :             :  * g_object_get(). But g_object_get() only unrefs once when it disgorges
     601                 :             :  * the object, leaving an unbalanced ref, which leaks. So instead of
     602                 :             :  * using g_value_set_object(), use g_value_take_object() which doesn't
     603                 :             :  * ref the object when used in get_property().
     604                 :             :  */
     605                 :             : static void
     606                 :         318 : gnc_commodity_get_property (GObject         *object,
     607                 :             :                             guint            prop_id,
     608                 :             :                             GValue          *value,
     609                 :             :                             GParamSpec      *pspec)
     610                 :             : {
     611                 :             :     gnc_commodity *commodity;
     612                 :             :     gnc_commodityPrivate* priv;
     613                 :             : 
     614                 :         318 :     g_return_if_fail(GNC_IS_COMMODITY(object));
     615                 :             : 
     616                 :         318 :     commodity = GNC_COMMODITY(object);
     617                 :         318 :     priv = GET_PRIVATE(commodity);
     618                 :         318 :     switch (prop_id)
     619                 :             :     {
     620                 :           0 :     case PROP_NAMESPACE:
     621                 :           0 :         g_value_take_object(value, priv->name_space);
     622                 :           0 :         break;
     623                 :          53 :     case PROP_FULL_NAME:
     624                 :          53 :         g_value_set_string(value, priv->fullname);
     625                 :          53 :         break;
     626                 :          53 :     case PROP_MNEMONIC:
     627                 :          53 :         g_value_set_string(value, priv->mnemonic);
     628                 :          53 :         break;
     629                 :           0 :     case PROP_PRINTNAME:
     630                 :           0 :         g_value_set_string(value, priv->printname);
     631                 :           0 :         break;
     632                 :          53 :     case PROP_CUSIP:
     633                 :          53 :         g_value_set_string(value, priv->cusip);
     634                 :          53 :         break;
     635                 :          53 :     case PROP_FRACTION:
     636                 :          53 :         g_value_set_int(value, priv->fraction);
     637                 :          53 :         break;
     638                 :           0 :     case PROP_UNIQUE_NAME:
     639                 :           0 :         g_value_set_string(value, priv->unique_name);
     640                 :           0 :         break;
     641                 :          53 :     case PROP_QUOTE_FLAG:
     642                 :          53 :         g_value_set_boolean(value, priv->quote_flag);
     643                 :          53 :         break;
     644                 :           0 :     case PROP_QUOTE_SOURCE:
     645                 :           0 :         g_value_set_pointer(value, priv->quote_source);
     646                 :           0 :         break;
     647                 :          53 :     case PROP_QUOTE_TZ:
     648                 :          53 :         g_value_set_string(value, priv->quote_tz);
     649                 :          53 :         break;
     650                 :           0 :     default:
     651                 :           0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     652                 :           0 :         break;
     653                 :             :     }
     654                 :             : }
     655                 :             : 
     656                 :             : static void
     657                 :          48 : gnc_commodity_set_property (GObject         *object,
     658                 :             :                             guint            prop_id,
     659                 :             :                             const GValue    *value,
     660                 :             :                             GParamSpec      *pspec)
     661                 :             : {
     662                 :             :     gnc_commodity *commodity;
     663                 :             : 
     664                 :          48 :     g_return_if_fail(GNC_IS_COMMODITY(object));
     665                 :             : 
     666                 :          48 :     commodity = GNC_COMMODITY(object);
     667                 :          48 :     g_assert (qof_instance_get_editlevel(commodity));
     668                 :             : 
     669                 :          48 :     switch (prop_id)
     670                 :             :     {
     671                 :           0 :     case PROP_NAMESPACE:
     672                 :           0 :         gnc_commodity_set_namespace(commodity, static_cast<const char*>(g_value_get_object(value)));
     673                 :           0 :         break;
     674                 :           8 :     case PROP_FULL_NAME:
     675                 :           8 :         gnc_commodity_set_fullname(commodity, g_value_get_string(value));
     676                 :           8 :         break;
     677                 :           8 :     case PROP_MNEMONIC:
     678                 :           8 :         gnc_commodity_set_mnemonic(commodity, g_value_get_string(value));
     679                 :           8 :         break;
     680                 :           8 :     case PROP_CUSIP:
     681                 :           8 :         gnc_commodity_set_cusip(commodity, g_value_get_string(value));
     682                 :           8 :         break;
     683                 :           8 :     case PROP_FRACTION:
     684                 :           8 :         gnc_commodity_set_fraction(commodity, g_value_get_int(value));
     685                 :           8 :         break;
     686                 :           8 :     case PROP_QUOTE_FLAG:
     687                 :           8 :         gnc_commodity_set_quote_flag(commodity, g_value_get_boolean(value));
     688                 :           8 :         break;
     689                 :           0 :     case PROP_QUOTE_SOURCE:
     690                 :           0 :         gnc_commodity_set_quote_source(commodity, static_cast<gnc_quote_source*>(g_value_get_pointer(value)));
     691                 :           0 :         break;
     692                 :           8 :     case PROP_QUOTE_TZ:
     693                 :           8 :         gnc_commodity_set_quote_tz(commodity, g_value_get_string(value));
     694                 :           8 :         break;
     695                 :           0 :     default:
     696                 :           0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     697                 :           0 :         break;
     698                 :             :     }
     699                 :             : }
     700                 :             : static void
     701                 :          62 : gnc_commodity_class_init(struct _GncCommodityClass* klass)
     702                 :             : {
     703                 :          62 :     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
     704                 :             : 
     705                 :          62 :     gobject_class->dispose = gnc_commodity_dispose;
     706                 :          62 :     gobject_class->finalize = gnc_commodity_finalize;
     707                 :          62 :     gobject_class->set_property = gnc_commodity_set_property;
     708                 :          62 :     gobject_class->get_property = gnc_commodity_get_property;
     709                 :             : 
     710                 :          62 :     g_object_class_install_property(gobject_class,
     711                 :             :                                     PROP_NAMESPACE,
     712                 :             :                                     g_param_spec_object ("namespace",
     713                 :             :                                             "Namespace",
     714                 :             :                                             "The namespace field denotes the "
     715                 :             :                                             "namespace for this commodity, either "
     716                 :             :                                             "a currency or symbol from a quote source.",
     717                 :             :                                             GNC_TYPE_COMMODITY_NAMESPACE,
     718                 :             :                                             G_PARAM_READWRITE));
     719                 :          62 :     g_object_class_install_property(gobject_class,
     720                 :             :                                     PROP_FULL_NAME,
     721                 :             :                                     g_param_spec_string ("fullname",
     722                 :             :                                             "Full Commodity Name",
     723                 :             :                                             "The fullname is the official full name of"
     724                 :             :                                             "the currency.",
     725                 :             :                                             nullptr,
     726                 :             :                                             G_PARAM_READWRITE));
     727                 :          62 :     g_object_class_install_property(gobject_class,
     728                 :             :                                     PROP_MNEMONIC,
     729                 :             :                                     g_param_spec_string ("mnemonic",
     730                 :             :                                             "Commodity Mnemonic",
     731                 :             :                                             "The mnemonic is the official abbreviated"
     732                 :             :                                             "designation for the currency.",
     733                 :             :                                             nullptr,
     734                 :             :                                             G_PARAM_READWRITE));
     735                 :          62 :     g_object_class_install_property(gobject_class,
     736                 :             :                                     PROP_PRINTNAME,
     737                 :             :                                     g_param_spec_string ("printname",
     738                 :             :                                             "Commodity Print Name",
     739                 :             :                                             "Printable form of the commodity name.",
     740                 :             :                                             nullptr,
     741                 :             :                                             G_PARAM_READABLE));
     742                 :          62 :     g_object_class_install_property(gobject_class,
     743                 :             :                                     PROP_CUSIP,
     744                 :             :                                     g_param_spec_string ("cusip",
     745                 :             :                                             "Commodity CUSIP Code",
     746                 :             :                                             "?????",
     747                 :             :                                             nullptr,
     748                 :             :                                             G_PARAM_READWRITE));
     749                 :          62 :     g_object_class_install_property(gobject_class,
     750                 :             :                                     PROP_FRACTION,
     751                 :             :                                     g_param_spec_int ("fraction",
     752                 :             :                                             "Fraction",
     753                 :             :                                             "The fraction is the number of sub-units that "
     754                 :             :                                             "the basic commodity can be divided into.",
     755                 :             :                                             1,
     756                 :             :                                             GNC_COMMODITY_MAX_FRACTION,
     757                 :             :                                             1,
     758                 :             :                                             G_PARAM_READWRITE));
     759                 :          62 :     g_object_class_install_property(gobject_class,
     760                 :             :                                     PROP_UNIQUE_NAME,
     761                 :             :                                     g_param_spec_string ("unique-name",
     762                 :             :                                             "Commodity Unique Name",
     763                 :             :                                             "Unique form of the commodity name which combines "
     764                 :             :                                             "the namespace name and the commodity name.",
     765                 :             :                                             nullptr,
     766                 :             :                                             G_PARAM_READABLE));
     767                 :          62 :     g_object_class_install_property(gobject_class,
     768                 :             :                                     PROP_QUOTE_FLAG,
     769                 :             :                                     g_param_spec_boolean ("quote_flag",
     770                 :             :                                             "Quote Flag",
     771                 :             :                                             "TRUE if prices are to be downloaded for this "
     772                 :             :                                             "commodity from a quote source.",
     773                 :             :                                             FALSE,
     774                 :             :                                             G_PARAM_READWRITE));
     775                 :          62 :     g_object_class_install_property(gobject_class,
     776                 :             :                                     PROP_QUOTE_SOURCE,
     777                 :             :                                     g_param_spec_pointer("quote-source",
     778                 :             :                                             "Quote Source",
     779                 :             :                                             "The quote source from which prices are downloaded.",
     780                 :             :                                             G_PARAM_READWRITE));
     781                 :          62 :     g_object_class_install_property(gobject_class,
     782                 :             :                                     PROP_QUOTE_TZ,
     783                 :             :                                     g_param_spec_string ("quote-tz",
     784                 :             :                                             "Commodity Quote Timezone",
     785                 :             :                                             "?????",
     786                 :             :                                             nullptr,
     787                 :             :                                             G_PARAM_READWRITE));
     788                 :          62 : }
     789                 :             : 
     790                 :             : gnc_commodity *
     791                 :       66090 : gnc_commodity_new(QofBook *book, const char * fullname,
     792                 :             :                   const char * name_space, const char * mnemonic,
     793                 :             :                   const char * cusip, int fraction)
     794                 :             : {
     795                 :       66090 :     auto retval = GNC_COMMODITY(g_object_new(GNC_TYPE_COMMODITY, nullptr));
     796                 :             : 
     797                 :       66090 :     qof_instance_init_data (&retval->inst, GNC_ID_COMMODITY, book);
     798                 :       66090 :     gnc_commodity_begin_edit(retval);
     799                 :             : 
     800                 :       66090 :     if ( name_space != nullptr )
     801                 :             :     {
     802                 :             :         /* Prevent setting anything except template in namespace template. */
     803                 :       66233 :         if (g_strcmp0 (name_space, GNC_COMMODITY_NS_TEMPLATE) == 0 &&
     804                 :         272 :             g_strcmp0 (mnemonic, "template") != 0)
     805                 :             :         {
     806                 :           0 :             PWARN("Converting commodity %s from namespace template to "
     807                 :             :                   "namespace User", mnemonic);
     808                 :           0 :             name_space = "User";
     809                 :             :         }
     810                 :       65961 :         gnc_commodity_set_namespace(retval, name_space);
     811                 :       65961 :         if (gnc_commodity_namespace_is_iso(name_space))
     812                 :             :         {
     813                 :       62422 :             gnc_commodity_set_quote_source(retval,
     814                 :             :                                            gnc_quote_source_lookup_by_internal("currency") );
     815                 :             :         }
     816                 :             :     }
     817                 :       66090 :     gnc_commodity_set_fullname(retval, fullname);
     818                 :       66090 :     gnc_commodity_set_mnemonic(retval, mnemonic);
     819                 :       66090 :     gnc_commodity_set_cusip(retval, cusip);
     820                 :       66090 :     gnc_commodity_set_fraction(retval, fraction);
     821                 :       66090 :     mark_commodity_dirty (retval);
     822                 :       66090 :     gnc_commodity_commit_edit(retval);
     823                 :             : 
     824                 :       66090 :     qof_event_gen (&retval->inst, QOF_EVENT_CREATE, nullptr);
     825                 :             : 
     826                 :       66090 :     return retval;
     827                 :             : }
     828                 :             : 
     829                 :             : 
     830                 :             : /********************************************************************
     831                 :             :  * gnc_commodity_destroy
     832                 :             :  ********************************************************************/
     833                 :             : 
     834                 :             : static void
     835                 :       41354 : commodity_free(gnc_commodity * cm)
     836                 :             : {
     837                 :             :     QofBook *book;
     838                 :             :     gnc_commodity_table *table;
     839                 :             :     gnc_commodityPrivate* priv;
     840                 :             : 
     841                 :       41354 :     if (!cm) return;
     842                 :             : 
     843                 :       41354 :     book = qof_instance_get_book(&cm->inst);
     844                 :       41354 :     table = gnc_commodity_table_get_table(book);
     845                 :       41354 :     gnc_commodity_table_remove(table, cm);
     846                 :       41354 :     priv = GET_PRIVATE(cm);
     847                 :             : 
     848                 :       41354 :     qof_event_gen (&cm->inst, QOF_EVENT_DESTROY, nullptr);
     849                 :             : 
     850                 :             :     /* Set at creation */
     851                 :       41354 :     CACHE_REMOVE (priv->fullname);
     852                 :       41354 :     CACHE_REMOVE (priv->cusip);
     853                 :       41354 :     CACHE_REMOVE (priv->mnemonic);
     854                 :       41354 :     CACHE_REMOVE (priv->quote_tz);
     855                 :       41354 :     priv->name_space = nullptr;
     856                 :             : 
     857                 :             :     /* Set through accessor functions */
     858                 :       41354 :     priv->quote_source = nullptr;
     859                 :             : 
     860                 :             :     /* Automatically generated */
     861                 :       41354 :     g_free(priv->printname);
     862                 :       41354 :     priv->printname = nullptr;
     863                 :             : 
     864                 :       41354 :     g_free(priv->unique_name);
     865                 :       41354 :     priv->unique_name = nullptr;
     866                 :             : 
     867                 :             : #ifdef ACCOUNTS_CLEANED_UP
     868                 :             :     /* Account objects are not actually cleaned up when a book is closed (in fact
     869                 :             :      * a memory leak), but commodities are, so in currently this warning gets hit
     870                 :             :      * quite frequently.  Disable the check until cleaning up of accounts objects
     871                 :             :      * on close is implemented.  */
     872                 :             :     if (priv->usage_count != 0)
     873                 :             :     {
     874                 :             :         PWARN("Destroying commodity (%p) with non-zero usage_count (%d).", cm,
     875                 :             :               priv->usage_count);
     876                 :             :     }
     877                 :             : #endif
     878                 :             : 
     879                 :             :     /* qof_instance_release (&cm->inst); */
     880                 :       41354 :     g_object_unref(cm);
     881                 :             : }
     882                 :             : 
     883                 :             : void
     884                 :       41354 : gnc_commodity_destroy(gnc_commodity * cm)
     885                 :             : {
     886                 :       41354 :     gnc_commodity_begin_edit(cm);
     887                 :       41354 :     qof_instance_set_destroying(cm, TRUE);
     888                 :       41354 :     gnc_commodity_commit_edit(cm);
     889                 :       41354 : }
     890                 :             : 
     891                 :             : void
     892                 :          61 : gnc_commodity_copy(gnc_commodity * dest, const gnc_commodity *src)
     893                 :             : {
     894                 :          61 :     gnc_commodityPrivate* src_priv = GET_PRIVATE(src);
     895                 :          61 :     gnc_commodityPrivate* dest_priv = GET_PRIVATE(dest);
     896                 :             : 
     897                 :          61 :     gnc_commodity_set_fullname (dest, src_priv->fullname);
     898                 :          61 :     gnc_commodity_set_mnemonic (dest, src_priv->mnemonic);
     899                 :          61 :     dest_priv->name_space = src_priv->name_space;
     900                 :          61 :     gnc_commodity_set_fraction (dest, src_priv->fraction);
     901                 :          61 :     gnc_commodity_set_cusip (dest, src_priv->cusip);
     902                 :          61 :     gnc_commodity_set_quote_flag (dest, src_priv->quote_flag);
     903                 :          61 :     gnc_commodity_set_quote_source (dest, gnc_commodity_get_quote_source (src));
     904                 :          61 :     gnc_commodity_set_quote_tz (dest, src_priv->quote_tz);
     905                 :          61 :     qof_instance_copy_kvp (QOF_INSTANCE (dest), QOF_INSTANCE (src));
     906                 :          61 : }
     907                 :             : 
     908                 :             : gnc_commodity *
     909                 :           0 : gnc_commodity_clone(const gnc_commodity *src, QofBook *dest_book)
     910                 :             : {
     911                 :             :     gnc_commodityPrivate* src_priv;
     912                 :             :     gnc_commodityPrivate* dest_priv;
     913                 :             : 
     914                 :           0 :     auto dest = GNC_COMMODITY (g_object_new(GNC_TYPE_COMMODITY, nullptr));
     915                 :           0 :     qof_instance_init_data (&dest->inst, GNC_ID_COMMODITY, dest_book);
     916                 :           0 :     src_priv = GET_PRIVATE(src);
     917                 :           0 :     dest_priv = GET_PRIVATE(dest);
     918                 :             : 
     919                 :           0 :     dest_priv->fullname = CACHE_INSERT(src_priv->fullname);
     920                 :           0 :     dest_priv->mnemonic = CACHE_INSERT(src_priv->mnemonic);
     921                 :           0 :     dest_priv->cusip = CACHE_INSERT(src_priv->cusip);
     922                 :           0 :     dest_priv->quote_tz = CACHE_INSERT(src_priv->quote_tz);
     923                 :             : 
     924                 :           0 :     dest_priv->name_space = src_priv->name_space;
     925                 :             : 
     926                 :           0 :     dest_priv->fraction = src_priv->fraction;
     927                 :           0 :     dest_priv->quote_flag = src_priv->quote_flag;
     928                 :             : 
     929                 :           0 :     gnc_commodity_set_quote_source (dest, gnc_commodity_get_quote_source (src));
     930                 :             : 
     931                 :           0 :     qof_instance_copy_kvp (QOF_INSTANCE (dest), QOF_INSTANCE (src));
     932                 :             : 
     933                 :           0 :     reset_printname(dest_priv);
     934                 :           0 :     reset_unique_name(dest_priv);
     935                 :             : 
     936                 :           0 :     return dest;
     937                 :             : }
     938                 :             : 
     939                 :             : /********************************************************************
     940                 :             :  * gnc_commodity_get_mnemonic
     941                 :             :  ********************************************************************/
     942                 :             : 
     943                 :             : const char *
     944                 :      137073 : gnc_commodity_get_mnemonic(const gnc_commodity * cm)
     945                 :             : {
     946                 :      137073 :     if (!cm) return nullptr;
     947                 :      137073 :     return GET_PRIVATE(cm)->mnemonic;
     948                 :             : }
     949                 :             : 
     950                 :             : /********************************************************************
     951                 :             :  * gnc_commodity_get_printname
     952                 :             :  ********************************************************************/
     953                 :             : 
     954                 :             : const char *
     955                 :       31024 : gnc_commodity_get_printname(const gnc_commodity * cm)
     956                 :             : {
     957                 :       31024 :     if (!cm) return nullptr;
     958                 :       31024 :     return GET_PRIVATE(cm)->printname;
     959                 :             : }
     960                 :             : 
     961                 :             : 
     962                 :             : /********************************************************************
     963                 :             :  * gnc_commodity_get_namespace
     964                 :             :  ********************************************************************/
     965                 :             : 
     966                 :             : const char *
     967                 :       19541 : gnc_commodity_get_namespace(const gnc_commodity * cm)
     968                 :             : {
     969                 :       19541 :     if (!cm) return nullptr;
     970                 :       19541 :     return gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->name_space);
     971                 :             : }
     972                 :             : 
     973                 :             : gnc_commodity_namespace *
     974                 :           0 : gnc_commodity_get_namespace_ds(const gnc_commodity * cm)
     975                 :             : {
     976                 :           0 :     if (!cm) return nullptr;
     977                 :           0 :     return GET_PRIVATE(cm)->name_space;
     978                 :             : }
     979                 :             : 
     980                 :             : /********************************************************************
     981                 :             :  * gnc_commodity_get_fullname
     982                 :             :  ********************************************************************/
     983                 :             : 
     984                 :             : const char *
     985                 :          70 : gnc_commodity_get_fullname(const gnc_commodity * cm)
     986                 :             : {
     987                 :          70 :     if (!cm) return nullptr;
     988                 :          70 :     return GET_PRIVATE(cm)->fullname;
     989                 :             : }
     990                 :             : 
     991                 :             : 
     992                 :             : /********************************************************************
     993                 :             :  * gnc_commodity_get_unique_name
     994                 :             :  ********************************************************************/
     995                 :             : 
     996                 :             : const char *
     997                 :          82 : gnc_commodity_get_unique_name(const gnc_commodity * cm)
     998                 :             : {
     999                 :          82 :     if (!cm) return nullptr;
    1000                 :          76 :     return GET_PRIVATE(cm)->unique_name;
    1001                 :             : }
    1002                 :             : 
    1003                 :             : 
    1004                 :             : /********************************************************************
    1005                 :             :  * gnc_commodity_get_cusip
    1006                 :             :  ********************************************************************/
    1007                 :             : 
    1008                 :             : const char *
    1009                 :          46 : gnc_commodity_get_cusip(const gnc_commodity * cm)
    1010                 :             : {
    1011                 :          46 :     if (!cm) return nullptr;
    1012                 :          46 :     return GET_PRIVATE(cm)->cusip;
    1013                 :             : }
    1014                 :             : 
    1015                 :             : /********************************************************************
    1016                 :             :  * gnc_commodity_get_fraction
    1017                 :             :  ********************************************************************/
    1018                 :             : 
    1019                 :             : int
    1020                 :      180793 : gnc_commodity_get_fraction(const gnc_commodity * cm)
    1021                 :             : {
    1022                 :      180793 :     if (!cm) return 0;
    1023                 :      180650 :     return GET_PRIVATE(cm)->fraction;
    1024                 :             : }
    1025                 :             : 
    1026                 :             : /********************************************************************
    1027                 :             :  * gnc_commodity_get_auto_quote_control_flag
    1028                 :             :  ********************************************************************/
    1029                 :             : 
    1030                 :             : static gboolean
    1031                 :         861 : gnc_commodity_get_auto_quote_control_flag(const gnc_commodity *cm)
    1032                 :             : {
    1033                 :         861 :     GValue v = G_VALUE_INIT;
    1034                 :         861 :     gboolean retval = TRUE;
    1035                 :             : 
    1036                 :         861 :     if (!cm) return FALSE;
    1037                 :         861 :     qof_instance_get_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
    1038                 :         861 :     if (G_VALUE_HOLDS_STRING (&v) &&
    1039                 :           0 :         strcmp(g_value_get_string (&v), "false") == 0)
    1040                 :           0 :         retval = FALSE;
    1041                 :         861 :     g_value_unset (&v);
    1042                 :         861 :     return retval;
    1043                 :             : }
    1044                 :             : 
    1045                 :             : /********************************************************************
    1046                 :             :  * gnc_commodity_get_quote_flag
    1047                 :             :  ********************************************************************/
    1048                 :             : 
    1049                 :             : gboolean
    1050                 :        1041 : gnc_commodity_get_quote_flag(const gnc_commodity *cm)
    1051                 :             : {
    1052                 :        1041 :     if (!cm) return FALSE;
    1053                 :        1041 :     return (GET_PRIVATE(cm)->quote_flag);
    1054                 :             : }
    1055                 :             : 
    1056                 :             : /********************************************************************
    1057                 :             :  * gnc_commodity_get_quote_source
    1058                 :             :  ********************************************************************/
    1059                 :             : 
    1060                 :             : gnc_quote_source*
    1061                 :         164 : gnc_commodity_get_quote_source(const gnc_commodity *cm)
    1062                 :             : {
    1063                 :             :     gnc_commodityPrivate* priv;
    1064                 :             : 
    1065                 :         164 :     if (!cm) return nullptr;
    1066                 :         164 :     priv = GET_PRIVATE(cm);
    1067                 :         164 :     if (!priv->quote_source && gnc_commodity_is_iso(cm))
    1068                 :           0 :         return &currency_quote_sources.front();
    1069                 :         164 :     return priv->quote_source;
    1070                 :             : }
    1071                 :             : 
    1072                 :             : gnc_quote_source*
    1073                 :         145 : gnc_commodity_get_default_quote_source(const gnc_commodity *cm)
    1074                 :             : {
    1075                 :         145 :     if (cm && gnc_commodity_is_iso(cm))
    1076                 :         145 :         return &currency_quote_sources.front();
    1077                 :             :     /* Should make this a user option at some point. */
    1078                 :           0 :     return gnc_quote_source_lookup_by_internal("alphavantage");
    1079                 :             : }
    1080                 :             : 
    1081                 :             : /********************************************************************
    1082                 :             :  * gnc_commodity_get_quote_tz
    1083                 :             :  ********************************************************************/
    1084                 :             : 
    1085                 :             : const char*
    1086                 :           4 : gnc_commodity_get_quote_tz(const gnc_commodity *cm)
    1087                 :             : {
    1088                 :           4 :     if (!cm) return nullptr;
    1089                 :           4 :     return GET_PRIVATE(cm)->quote_tz;
    1090                 :             : }
    1091                 :             : 
    1092                 :             : /********************************************************************
    1093                 :             :  * gnc_commodity_get_user_symbol
    1094                 :             :  ********************************************************************/
    1095                 :             : const char*
    1096                 :       61542 : gnc_commodity_get_user_symbol(const gnc_commodity *cm)
    1097                 :             : {
    1098                 :       61542 :     g_return_val_if_fail (GNC_IS_COMMODITY (cm), nullptr);
    1099                 :             : 
    1100                 :       61542 :     GValue v = G_VALUE_INIT;
    1101                 :       61542 :     qof_instance_get_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
    1102                 :       61542 :     const char *rv = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : nullptr;
    1103                 :       61542 :     g_value_unset (&v);
    1104                 :       61542 :     return rv;
    1105                 :             : }
    1106                 :             : 
    1107                 :             : /********************************************************************
    1108                 :             :  * gnc_commodity_get_default_symbol
    1109                 :             :  *******************************************************************/
    1110                 :             : const char*
    1111                 :       61083 : gnc_commodity_get_default_symbol(const gnc_commodity *cm)
    1112                 :             : {
    1113                 :       61083 :     if (!cm) return nullptr;
    1114                 :       61083 :     return GET_PRIVATE(cm)->default_symbol;
    1115                 :             : }
    1116                 :             : 
    1117                 :             : /********************************************************************
    1118                 :             :  * gnc_commodity_get_nice_symbol
    1119                 :             :  *******************************************************************/
    1120                 :             : const char*
    1121                 :       61540 : gnc_commodity_get_nice_symbol (const gnc_commodity *cm)
    1122                 :             : {
    1123                 :             :     const char *nice_symbol;
    1124                 :             :     struct lconv *lc;
    1125                 :       61540 :     if (!cm) return nullptr;
    1126                 :             : 
    1127                 :       61540 :     nice_symbol = gnc_commodity_get_user_symbol(cm);
    1128                 :       61540 :     if (nice_symbol && *nice_symbol)
    1129                 :         464 :         return nice_symbol;
    1130                 :             : 
    1131                 :       61076 :     lc = gnc_localeconv();
    1132                 :       61076 :     nice_symbol = lc->currency_symbol;
    1133                 :       61076 :     if (!g_strcmp0(gnc_commodity_get_mnemonic(cm), lc->int_curr_symbol))
    1134                 :           0 :         return nice_symbol;
    1135                 :             : 
    1136                 :       61076 :     nice_symbol = gnc_commodity_get_default_symbol(cm);
    1137                 :       61076 :     if (nice_symbol && *nice_symbol)
    1138                 :       60828 :         return nice_symbol;
    1139                 :             : 
    1140                 :         248 :     return gnc_commodity_get_mnemonic(cm);
    1141                 :             : }
    1142                 :             : 
    1143                 :             : /********************************************************************
    1144                 :             :  * gnc_commodity_set_mnemonic
    1145                 :             :  ********************************************************************/
    1146                 :             : 
    1147                 :             : void
    1148                 :       66280 : gnc_commodity_set_mnemonic(gnc_commodity * cm, const char * mnemonic)
    1149                 :             : {
    1150                 :             :     gnc_commodityPrivate* priv;
    1151                 :             : 
    1152                 :       66280 :     if (!cm) return;
    1153                 :       66280 :     priv = GET_PRIVATE(cm);
    1154                 :       66280 :     if (priv->mnemonic == mnemonic) return;
    1155                 :             : 
    1156                 :       66237 :     gnc_commodity_begin_edit(cm);
    1157                 :       66237 :     CACHE_REMOVE (priv->mnemonic);
    1158                 :       66237 :     priv->mnemonic = CACHE_INSERT(mnemonic);
    1159                 :             : 
    1160                 :       66237 :     mark_commodity_dirty (cm);
    1161                 :       66237 :     reset_printname(priv);
    1162                 :       66237 :     reset_unique_name(priv);
    1163                 :       66237 :     gnc_commodity_commit_edit(cm);
    1164                 :             : }
    1165                 :             : 
    1166                 :             : /********************************************************************
    1167                 :             :  * gnc_commodity_set_namespace
    1168                 :             :  ********************************************************************/
    1169                 :             : 
    1170                 :             : void
    1171                 :       66090 : gnc_commodity_set_namespace(gnc_commodity * cm, const char * name_space)
    1172                 :             : {
    1173                 :             :     QofBook *book;
    1174                 :             :     gnc_commodity_table *table;
    1175                 :             :     gnc_commodity_namespace *nsp;
    1176                 :             :     gnc_commodityPrivate* priv;
    1177                 :             : 
    1178                 :       66090 :     if (!cm) return;
    1179                 :       66090 :     priv = GET_PRIVATE(cm);
    1180                 :       66090 :     book = qof_instance_get_book (&cm->inst);
    1181                 :       66090 :     table = gnc_commodity_table_get_table(book);
    1182                 :       66090 :     nsp = gnc_commodity_table_add_namespace(table, name_space, book);
    1183                 :       66090 :     if (priv->name_space == nsp)
    1184                 :         346 :         return;
    1185                 :             : 
    1186                 :       65744 :     gnc_commodity_begin_edit(cm);
    1187                 :       65744 :     priv->name_space = nsp;
    1188                 :       65744 :     if (nsp->iso4217)
    1189                 :       62215 :         priv->quote_source = gnc_quote_source_lookup_by_internal("currency");
    1190                 :       65744 :     mark_commodity_dirty(cm);
    1191                 :       65744 :     reset_printname(priv);
    1192                 :       65744 :     reset_unique_name(priv);
    1193                 :       65744 :     gnc_commodity_commit_edit(cm);
    1194                 :             : }
    1195                 :             : 
    1196                 :             : /********************************************************************
    1197                 :             :  * gnc_commodity_set_fullname
    1198                 :             :  ********************************************************************/
    1199                 :             : 
    1200                 :             : void
    1201                 :       66262 : gnc_commodity_set_fullname(gnc_commodity * cm, const char * fullname)
    1202                 :             : {
    1203                 :             :     gnc_commodityPrivate* priv;
    1204                 :             : 
    1205                 :       66262 :     if (!cm) return;
    1206                 :       66262 :     priv = GET_PRIVATE(cm);
    1207                 :       66262 :     if (priv->fullname == fullname) return;
    1208                 :             : 
    1209                 :       66219 :     CACHE_REMOVE (priv->fullname);
    1210                 :       66219 :     priv->fullname = CACHE_INSERT (fullname);
    1211                 :             : 
    1212                 :       66219 :     gnc_commodity_begin_edit(cm);
    1213                 :       66219 :     mark_commodity_dirty(cm);
    1214                 :       66219 :     reset_printname(priv);
    1215                 :       66219 :     gnc_commodity_commit_edit(cm);
    1216                 :             : }
    1217                 :             : 
    1218                 :             : /********************************************************************
    1219                 :             :  * gnc_commodity_set_cusip
    1220                 :             :  ********************************************************************/
    1221                 :             : 
    1222                 :             : void
    1223                 :       66205 : gnc_commodity_set_cusip(gnc_commodity * cm,
    1224                 :             :                         const char * cusip)
    1225                 :             : {
    1226                 :             :     gnc_commodityPrivate* priv;
    1227                 :             : 
    1228                 :       66205 :     if (!cm) return;
    1229                 :             : 
    1230                 :       66205 :     priv = GET_PRIVATE(cm);
    1231                 :       66205 :     if (priv->cusip == cusip) return;
    1232                 :             : 
    1233                 :       66162 :     gnc_commodity_begin_edit(cm);
    1234                 :       66162 :     CACHE_REMOVE (priv->cusip);
    1235                 :       66162 :     priv->cusip = CACHE_INSERT (cusip);
    1236                 :       66162 :     mark_commodity_dirty(cm);
    1237                 :       66162 :     gnc_commodity_commit_edit(cm);
    1238                 :             : }
    1239                 :             : 
    1240                 :             : /********************************************************************
    1241                 :             :  * gnc_commodity_set_fraction
    1242                 :             :  ********************************************************************/
    1243                 :             : 
    1244                 :             : void
    1245                 :       66262 : gnc_commodity_set_fraction(gnc_commodity * cm, int fraction)
    1246                 :             : {
    1247                 :       66262 :     if (!cm) return;
    1248                 :       66262 :     gnc_commodity_begin_edit(cm);
    1249                 :       66262 :     GET_PRIVATE(cm)->fraction = fraction;
    1250                 :       66262 :     mark_commodity_dirty(cm);
    1251                 :       66262 :     gnc_commodity_commit_edit(cm);
    1252                 :             : }
    1253                 :             : 
    1254                 :             : /********************************************************************
    1255                 :             :  * gnc_commodity_set_auto_quote_control_flag
    1256                 :             :  ********************************************************************/
    1257                 :             : 
    1258                 :             : static void
    1259                 :           0 : gnc_commodity_set_auto_quote_control_flag(gnc_commodity *cm,
    1260                 :             :         const gboolean flag)
    1261                 :             : {
    1262                 :           0 :     GValue v = G_VALUE_INIT;
    1263                 :           0 :     ENTER ("(cm=%p, flag=%d)", cm, flag);
    1264                 :             : 
    1265                 :           0 :     if (!cm)
    1266                 :             :     {
    1267                 :           0 :         LEAVE("");
    1268                 :           0 :         return;
    1269                 :             :     }
    1270                 :           0 :     gnc_commodity_begin_edit(cm);
    1271                 :           0 :     if (flag)
    1272                 :           0 :         qof_instance_set_kvp (QOF_INSTANCE (cm), nullptr, 1, "auto_quote_control");
    1273                 :             :     else
    1274                 :             :     {
    1275                 :           0 :         g_value_init (&v, G_TYPE_STRING);
    1276                 :           0 :         g_value_set_string (&v, "false");
    1277                 :           0 :         qof_instance_set_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
    1278                 :             :     }
    1279                 :           0 :     g_value_unset (&v);
    1280                 :           0 :     mark_commodity_dirty(cm);
    1281                 :           0 :     gnc_commodity_commit_edit(cm);
    1282                 :           0 :     LEAVE("");
    1283                 :             : }
    1284                 :             : 
    1285                 :             : /********************************************************************
    1286                 :             :  * gnc_commodity_user_set_quote_flag
    1287                 :             :  ********************************************************************/
    1288                 :             : 
    1289                 :             : void
    1290                 :           0 : gnc_commodity_user_set_quote_flag(gnc_commodity *cm, const gboolean flag)
    1291                 :             : {
    1292                 :             :     gnc_commodityPrivate* priv;
    1293                 :             : 
    1294                 :           0 :     ENTER ("(cm=%p, flag=%d)", cm, flag);
    1295                 :             : 
    1296                 :           0 :     if (!cm)
    1297                 :             :     {
    1298                 :           0 :         LEAVE("");
    1299                 :           0 :         return;
    1300                 :             :     }
    1301                 :             : 
    1302                 :           0 :     priv = GET_PRIVATE(cm);
    1303                 :           0 :     gnc_commodity_begin_edit(cm);
    1304                 :           0 :     gnc_commodity_set_quote_flag(cm, flag);
    1305                 :           0 :     if (gnc_commodity_is_iso(cm))
    1306                 :             :     {
    1307                 :             :         /* For currencies, disable auto quote control if the quote flag is being
    1308                 :             :          * changed from its default value and enable it if the quote flag is being
    1309                 :             :          * reset to its default value.  The defaults for the quote flag are
    1310                 :             :          * disabled if no accounts are using the currency, and true otherwise.
    1311                 :             :          * Thus enable auto quote control if flag is FALSE and there are not any
    1312                 :             :          * accounts using this currency OR flag is TRUE and there are accounts
    1313                 :             :          * using this currency; otherwise disable auto quote control */
    1314                 :           0 :         gnc_commodity_set_auto_quote_control_flag(cm,
    1315                 :           0 :                 (!flag && (priv->usage_count == 0)) || (flag && (priv->usage_count != 0)));
    1316                 :             :     }
    1317                 :           0 :     gnc_commodity_commit_edit(cm);
    1318                 :           0 :     LEAVE("");
    1319                 :             : }
    1320                 :             : 
    1321                 :             : /********************************************************************
    1322                 :             :  * gnc_commodity_set_quote_flag
    1323                 :             :  ********************************************************************/
    1324                 :             : 
    1325                 :             : void
    1326                 :         374 : gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
    1327                 :             : {
    1328                 :         374 :     ENTER ("(cm=%p, flag=%d)", cm, flag);
    1329                 :             : 
    1330                 :         374 :     if (!cm) return;
    1331                 :         374 :     gnc_commodity_begin_edit(cm);
    1332                 :         374 :     GET_PRIVATE(cm)->quote_flag = flag;
    1333                 :         374 :     mark_commodity_dirty(cm);
    1334                 :         374 :     gnc_commodity_commit_edit(cm);
    1335                 :         374 :     LEAVE(" ");
    1336                 :             : }
    1337                 :             : 
    1338                 :             : /********************************************************************
    1339                 :             :  * gnc_commodity_set_quote_source
    1340                 :             :  ********************************************************************/
    1341                 :             : 
    1342                 :             : void
    1343                 :       62715 : gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
    1344                 :             : {
    1345                 :       62715 :     ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->get_internal_name() : "unknown");
    1346                 :             : 
    1347                 :       62715 :     if (!cm) return;
    1348                 :       62715 :     gnc_commodity_begin_edit(cm);
    1349                 :       62715 :     GET_PRIVATE(cm)->quote_source = src;
    1350                 :       62715 :     mark_commodity_dirty(cm);
    1351                 :       62715 :     gnc_commodity_commit_edit(cm);
    1352                 :       62715 :     LEAVE(" ");
    1353                 :             : }
    1354                 :             : 
    1355                 :             : /********************************************************************
    1356                 :             :  * gnc_commodity_set_quote_tz
    1357                 :             :  ********************************************************************/
    1358                 :             : 
    1359                 :             : void
    1360                 :          87 : gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz)
    1361                 :             : {
    1362                 :             :     gnc_commodityPrivate* priv;
    1363                 :             : 
    1364                 :          87 :     if (!cm) return;
    1365                 :             : 
    1366                 :          87 :     ENTER ("(cm=%p, tz=%s)", cm, tz ? tz : "(null)");
    1367                 :             : 
    1368                 :          87 :     priv = GET_PRIVATE(cm);
    1369                 :             : 
    1370                 :          87 :     if (tz == priv->quote_tz)
    1371                 :             :     {
    1372                 :          61 :         LEAVE("Already correct TZ");
    1373                 :          61 :         return;
    1374                 :             :     }
    1375                 :             : 
    1376                 :          26 :     gnc_commodity_begin_edit(cm);
    1377                 :          26 :     CACHE_REMOVE (priv->quote_tz);
    1378                 :          26 :     priv->quote_tz = CACHE_INSERT (tz);
    1379                 :          26 :     mark_commodity_dirty(cm);
    1380                 :          26 :     gnc_commodity_commit_edit(cm);
    1381                 :          26 :     LEAVE(" ");
    1382                 :             : }
    1383                 :             : 
    1384                 :             : /********************************************************************
    1385                 :             :  * gnc_commodity_set_user_symbol
    1386                 :             :  ********************************************************************/
    1387                 :             : 
    1388                 :             : void
    1389                 :           7 : gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
    1390                 :             : {
    1391                 :             :     struct lconv *lc;
    1392                 :             : 
    1393                 :           7 :     if (!cm) return;
    1394                 :             : 
    1395                 :           7 :     ENTER ("(cm=%p, symbol=%s)", cm, user_symbol ? user_symbol : "(null)");
    1396                 :             : 
    1397                 :           7 :     lc = gnc_localeconv();
    1398                 :           7 :     if (!user_symbol || !*user_symbol)
    1399                 :           0 :         user_symbol = nullptr;
    1400                 :           7 :     else if (!g_strcmp0(lc->int_curr_symbol, gnc_commodity_get_mnemonic(cm)) &&
    1401                 :           0 :              !g_strcmp0(lc->currency_symbol, user_symbol))
    1402                 :             :         /* if the user gives the ISO symbol for the locale currency or the
    1403                 :             :          * default symbol, actually remove the user symbol */
    1404                 :           0 :         user_symbol = nullptr;
    1405                 :           7 :     else if (!g_strcmp0(user_symbol, gnc_commodity_get_default_symbol(cm)))
    1406                 :           0 :         user_symbol = nullptr;
    1407                 :             : 
    1408                 :           7 :     gnc_commodity_begin_edit (cm);
    1409                 :             : 
    1410                 :           7 :     if (user_symbol)
    1411                 :             :     {
    1412                 :           7 :         GValue v = G_VALUE_INIT;
    1413                 :           7 :         g_value_init (&v, G_TYPE_STRING);
    1414                 :           7 :         g_value_set_static_string (&v, user_symbol);
    1415                 :           7 :         qof_instance_set_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
    1416                 :           7 :         g_value_unset (&v);
    1417                 :             :     }
    1418                 :             :     else
    1419                 :             :     {
    1420                 :           0 :         qof_instance_set_kvp (QOF_INSTANCE(cm), nullptr, 1, "user_symbol");
    1421                 :             :     }
    1422                 :             : 
    1423                 :           7 :     mark_commodity_dirty(cm);
    1424                 :           7 :     gnc_commodity_commit_edit(cm);
    1425                 :             : 
    1426                 :           7 :     LEAVE(" ");
    1427                 :             : }
    1428                 :             : 
    1429                 :             : /********************************************************************
    1430                 :             :  * gnc_commodity_set_default_symbol
    1431                 :             :  * Not made visible in gnc-commodity.h, it is only called from
    1432                 :             :  * iso-4217-currencies.c at startup.
    1433                 :             :  ********************************************************************/
    1434                 :             : void
    1435                 :       60155 : gnc_commodity_set_default_symbol(gnc_commodity * cm,
    1436                 :             :                                  const char * default_symbol)
    1437                 :             : {
    1438                 :       60155 :     GET_PRIVATE(cm)->default_symbol = default_symbol;
    1439                 :       60155 : }
    1440                 :             : 
    1441                 :             : /********************************************************************
    1442                 :             :  * gnc_commodity_increment_usage_count
    1443                 :             :  ********************************************************************/
    1444                 :             : 
    1445                 :             : void
    1446                 :        3042 : gnc_commodity_increment_usage_count(gnc_commodity *cm)
    1447                 :             : {
    1448                 :             :     gnc_commodityPrivate* priv;
    1449                 :             : 
    1450                 :        3042 :     ENTER("(cm=%p)", cm);
    1451                 :             : 
    1452                 :        3042 :     if (!cm)
    1453                 :             :     {
    1454                 :           1 :         LEAVE("");
    1455                 :           1 :         return;
    1456                 :             :     }
    1457                 :             : 
    1458                 :        3041 :     priv = GET_PRIVATE(cm);
    1459                 :             : 
    1460                 :         803 :     if ((priv->usage_count == 0) && !priv->quote_flag
    1461                 :         778 :             && gnc_commodity_get_auto_quote_control_flag(cm)
    1462                 :        3844 :             && gnc_commodity_is_iso(cm))
    1463                 :             :     {
    1464                 :             :         /* compatibility hack - Gnucash 1.8 gets currency quotes when a
    1465                 :             :            non-default currency is assigned to an account.  */
    1466                 :         145 :         gnc_commodity_begin_edit(cm);
    1467                 :         145 :         gnc_commodity_set_quote_flag(cm, TRUE);
    1468                 :         145 :         gnc_commodity_set_quote_source(cm,
    1469                 :             :                                        gnc_commodity_get_default_quote_source(cm));
    1470                 :         145 :         gnc_commodity_commit_edit(cm);
    1471                 :             :     }
    1472                 :        3041 :     priv->usage_count++;
    1473                 :        3041 :     LEAVE("(usage_count=%d)", priv->usage_count);
    1474                 :             : }
    1475                 :             : 
    1476                 :             : /********************************************************************
    1477                 :             :  * gnc_commodity_decrement_usage_count
    1478                 :             :  ********************************************************************/
    1479                 :             : 
    1480                 :             : void
    1481                 :        5135 : gnc_commodity_decrement_usage_count(gnc_commodity *cm)
    1482                 :             : {
    1483                 :             :     gnc_commodityPrivate* priv;
    1484                 :             : 
    1485                 :        5135 :     ENTER("(cm=%p)", cm);
    1486                 :             : 
    1487                 :        5135 :     if (!cm)
    1488                 :             :     {
    1489                 :        3745 :         LEAVE("");
    1490                 :        3745 :         return;
    1491                 :             :     }
    1492                 :             : 
    1493                 :        1390 :     priv = GET_PRIVATE(cm);
    1494                 :             : 
    1495                 :        1390 :     if (priv->usage_count == 0)
    1496                 :             :     {
    1497                 :           0 :         PWARN("usage_count already zero");
    1498                 :           0 :         LEAVE("");
    1499                 :           0 :         return;
    1500                 :             :     }
    1501                 :             : 
    1502                 :        1390 :     priv->usage_count--;
    1503                 :         293 :     if ((priv->usage_count == 0) && priv->quote_flag
    1504                 :          83 :             && gnc_commodity_get_auto_quote_control_flag(cm)
    1505                 :        1683 :             && gnc_commodity_is_iso(cm))
    1506                 :             :     {
    1507                 :             :         /* if this is a currency with auto quote control enabled and no more
    1508                 :             :          * accounts reference this currency, disable quote retrieval */
    1509                 :          81 :         gnc_commodity_set_quote_flag(cm, FALSE);
    1510                 :             :     }
    1511                 :        1390 :     LEAVE("(usage_count=%d)", priv->usage_count);
    1512                 :             : }
    1513                 :             : 
    1514                 :             : /********************************************************************\
    1515                 :             : \********************************************************************/
    1516                 :             : 
    1517                 :             : 
    1518                 :             : /********************************************************************
    1519                 :             :  * gnc_commodity_equiv
    1520                 :             :  * are two commodities the same?
    1521                 :             :  ********************************************************************/
    1522                 :             : 
    1523                 :             : gboolean
    1524                 :      118464 : gnc_commodity_equiv(const gnc_commodity * a, const gnc_commodity * b)
    1525                 :             : {
    1526                 :             :     gnc_commodityPrivate* priv_a;
    1527                 :             :     gnc_commodityPrivate* priv_b;
    1528                 :             : 
    1529                 :      118464 :     if (a == b) return TRUE;
    1530                 :       48466 :     if (!a || !b) return FALSE;
    1531                 :             : 
    1532                 :       21530 :     priv_a = GET_PRIVATE(a);
    1533                 :       21530 :     priv_b = GET_PRIVATE(b);
    1534                 :       21530 :     if (priv_a->name_space != priv_b->name_space) return FALSE;
    1535                 :       17571 :     if (g_strcmp0(priv_a->mnemonic, priv_b->mnemonic) != 0) return FALSE;
    1536                 :             : 
    1537                 :          69 :     return TRUE;
    1538                 :             : }
    1539                 :             : 
    1540                 :             : gboolean
    1541                 :       14702 : gnc_commodity_equal(const gnc_commodity * a, const gnc_commodity * b)
    1542                 :             : {
    1543                 :       14702 :     return gnc_commodity_compare(a, b) == 0;
    1544                 :             : }
    1545                 :             : 
    1546                 :             : // Used as a sorting callback for deleting old prices, so it needs to be
    1547                 :             : // stable but doesn't need to be in any particular order sensible to humans.
    1548                 :       14725 : int gnc_commodity_compare(const gnc_commodity * a, const gnc_commodity * b)
    1549                 :             : {
    1550                 :       14725 :     if (a == b) return 0;
    1551                 :        2449 :     if (a && !b) return 1;
    1552                 :        2441 :     if (b && !a) return -1;
    1553                 :        2417 :     return qof_instance_guid_compare(a, b);
    1554                 :             : }
    1555                 :             : 
    1556                 :             : // Used as a callback to g_list_find_custom, it should return 0
    1557                 :             : // when the commodities match.
    1558                 :           0 : int gnc_commodity_compare_void(const void * a, const void * b)
    1559                 :             : {
    1560                 :           0 :     return gnc_commodity_compare(GNC_COMMODITY (a), GNC_COMMODITY (b));
    1561                 :             : }
    1562                 :             : 
    1563                 :             : /************************************************************
    1564                 :             :  *                   Namespace functions                    *
    1565                 :             :  ************************************************************/
    1566                 :             : const char *
    1567                 :       95025 : gnc_commodity_namespace_get_name (const gnc_commodity_namespace *ns)
    1568                 :             : {
    1569                 :       95025 :     if (ns == nullptr)
    1570                 :          19 :         return nullptr;
    1571                 :       95006 :     return ns->name;
    1572                 :             : }
    1573                 :             : 
    1574                 :             : const char *
    1575                 :           0 : gnc_commodity_namespace_get_gui_name (const gnc_commodity_namespace *ns)
    1576                 :             : {
    1577                 :           0 :     if (ns == nullptr)
    1578                 :           0 :         return nullptr;
    1579                 :           0 :     if (g_strcmp0 (ns->name, GNC_COMMODITY_NS_CURRENCY) == 0)
    1580                 :           0 :         return GNC_COMMODITY_NS_ISO_GUI;
    1581                 :           0 :     return ns->name;
    1582                 :             : }
    1583                 :             : 
    1584                 :             : GList *
    1585                 :           0 : gnc_commodity_namespace_get_commodity_list(const gnc_commodity_namespace *name_space)
    1586                 :             : {
    1587                 :           0 :     if (!name_space)
    1588                 :           0 :         return nullptr;
    1589                 :             : 
    1590                 :           0 :     return g_list_copy (name_space->cm_list);
    1591                 :             : }
    1592                 :             : 
    1593                 :             : gboolean
    1594                 :       66988 : gnc_commodity_namespace_is_iso(const char *name_space)
    1595                 :             : {
    1596                 :       71895 :     return ((g_strcmp0(name_space, GNC_COMMODITY_NS_ISO) == 0) ||
    1597                 :       71895 :             (g_strcmp0(name_space, GNC_COMMODITY_NS_CURRENCY) == 0));
    1598                 :             : }
    1599                 :             : 
    1600                 :             : static const gchar *
    1601                 :      338653 : gnc_commodity_table_map_namespace(const char * name_space)
    1602                 :             : {
    1603                 :      338653 :     if (g_strcmp0(name_space, GNC_COMMODITY_NS_ISO) == 0)
    1604                 :       61988 :         return GNC_COMMODITY_NS_CURRENCY;
    1605                 :      276665 :     return name_space;
    1606                 :             : }
    1607                 :             : 
    1608                 :             : /********************************************************************
    1609                 :             :  * gnc_commodity_table_new
    1610                 :             :  * make a new commodity table
    1611                 :             :  ********************************************************************/
    1612                 :             : 
    1613                 :             : gnc_commodity_table *
    1614                 :         289 : gnc_commodity_table_new(void)
    1615                 :             : {
    1616                 :         289 :     gnc_commodity_table * retval = g_new0(gnc_commodity_table, 1);
    1617                 :         289 :     retval->ns_table = g_hash_table_new(&g_str_hash, &g_str_equal);
    1618                 :         289 :     retval->ns_list = nullptr;
    1619                 :         289 :     return retval;
    1620                 :             : }
    1621                 :             : 
    1622                 :             : /********************************************************************
    1623                 :             :  * book anchor functions
    1624                 :             :  ********************************************************************/
    1625                 :             : 
    1626                 :             : gnc_commodity_table *
    1627                 :      122294 : gnc_commodity_table_get_table(QofBook *book)
    1628                 :             : {
    1629                 :      122294 :     if (!book) return nullptr;
    1630                 :      122294 :     return static_cast<gnc_commodity_table*>(qof_book_get_data (book, GNC_COMMODITY_TABLE));
    1631                 :             : }
    1632                 :             : 
    1633                 :             : gnc_commodity *
    1634                 :           1 : gnc_commodity_obtain_twin (const gnc_commodity *from, QofBook *book)
    1635                 :             : {
    1636                 :             :     gnc_commodity *twin;
    1637                 :             :     const char * ucom;
    1638                 :             :     gnc_commodity_table * comtbl;
    1639                 :             : 
    1640                 :           1 :     if (!from) return nullptr;
    1641                 :           0 :     comtbl = gnc_commodity_table_get_table (book);
    1642                 :           0 :     if (!comtbl) return nullptr;
    1643                 :             : 
    1644                 :           0 :     ucom = gnc_commodity_get_unique_name (from);
    1645                 :           0 :     twin = gnc_commodity_table_lookup_unique (comtbl, ucom);
    1646                 :           0 :     if (!twin)
    1647                 :             :     {
    1648                 :           0 :         twin = gnc_commodity_clone (from, book);
    1649                 :           0 :         twin = gnc_commodity_table_insert (comtbl, twin);
    1650                 :             :     }
    1651                 :           0 :     return twin;
    1652                 :             : }
    1653                 :             : 
    1654                 :             : /********************************************************************
    1655                 :             :  * gnc_commodity_table_get_size
    1656                 :             :  * get the size of the commodity table
    1657                 :             :  ********************************************************************/
    1658                 :             : 
    1659                 :             : static void
    1660                 :         172 : count_coms(gpointer key, gpointer value, gpointer user_data)
    1661                 :             : {
    1662                 :         172 :     GHashTable *tbl = ((gnc_commodity_namespace*)value)->cm_table;
    1663                 :         172 :     guint *count = (guint*)user_data;
    1664                 :             : 
    1665                 :         172 :     if (g_strcmp0((char*)key, GNC_COMMODITY_NS_CURRENCY) == 0)
    1666                 :             :     {
    1667                 :             :         /* don't count default commodities */
    1668                 :           8 :         return;
    1669                 :             :     }
    1670                 :             : 
    1671                 :         164 :     if (!value) return;
    1672                 :             : 
    1673                 :         164 :     *count += g_hash_table_size(tbl);
    1674                 :             : }
    1675                 :             : 
    1676                 :             : guint
    1677                 :          49 : gnc_commodity_table_get_size(const gnc_commodity_table* tbl)
    1678                 :             : {
    1679                 :          49 :     guint count = 0;
    1680                 :          49 :     g_return_val_if_fail(tbl, 0);
    1681                 :          49 :     g_return_val_if_fail(tbl->ns_table, 0);
    1682                 :             : 
    1683                 :          49 :     g_hash_table_foreach(tbl->ns_table, count_coms, (gpointer)&count);
    1684                 :             : 
    1685                 :          49 :     return count;
    1686                 :             : }
    1687                 :             : 
    1688                 :             : /********************************************************************
    1689                 :             :  * gnc_commodity_table_lookup
    1690                 :             :  * locate a commodity by namespace and mnemonic.
    1691                 :             :  ********************************************************************/
    1692                 :             : 
    1693                 :             : gnc_commodity *
    1694                 :       81401 : gnc_commodity_table_lookup(const gnc_commodity_table * table,
    1695                 :             :                            const char * name_space, const char * mnemonic)
    1696                 :             : {
    1697                 :       81401 :     gnc_commodity_namespace * nsp = nullptr;
    1698                 :             : 
    1699                 :       81401 :     if (!table || !name_space || !mnemonic) return nullptr;
    1700                 :             : 
    1701                 :       81360 :     nsp = gnc_commodity_table_find_namespace(table, name_space);
    1702                 :             : 
    1703                 :       81360 :     if (nsp)
    1704                 :             :     {
    1705                 :             :         /*
    1706                 :             :          * Backward compatibility support for currencies that have
    1707                 :             :          * recently changed.
    1708                 :             :          */
    1709                 :       80219 :         if (nsp->iso4217)
    1710                 :             :         {
    1711                 :       72769 :             auto it = gnc_new_iso_codes.find (mnemonic);
    1712                 :       72769 :             if (it != gnc_new_iso_codes.end())
    1713                 :           0 :                 mnemonic = it->second.c_str();
    1714                 :             :         }
    1715                 :       80219 :         return GNC_COMMODITY(g_hash_table_lookup(nsp->cm_table, (gpointer)mnemonic));
    1716                 :             :     }
    1717                 :             :     else
    1718                 :             :     {
    1719                 :        1141 :         return nullptr;
    1720                 :             :     }
    1721                 :             : }
    1722                 :             : 
    1723                 :             : /********************************************************************
    1724                 :             :  * gnc_commodity_table_lookup
    1725                 :             :  * locate a commodity by unique name.
    1726                 :             :  ********************************************************************/
    1727                 :             : 
    1728                 :             : gnc_commodity *
    1729                 :           0 : gnc_commodity_table_lookup_unique(const gnc_commodity_table *table,
    1730                 :             :                                   const char * unique_name)
    1731                 :             : {
    1732                 :             :     char *name_space;
    1733                 :             :     char *mnemonic;
    1734                 :             :     gnc_commodity *commodity;
    1735                 :             : 
    1736                 :           0 :     if (!table || !unique_name) return nullptr;
    1737                 :             : 
    1738                 :           0 :     name_space = g_strdup (unique_name);
    1739                 :           0 :     mnemonic = strstr (name_space, "::");
    1740                 :           0 :     if (!mnemonic)
    1741                 :             :     {
    1742                 :           0 :         g_free (name_space);
    1743                 :           0 :         return nullptr;
    1744                 :             :     }
    1745                 :             : 
    1746                 :           0 :     *mnemonic = '\0';
    1747                 :           0 :     mnemonic += 2;
    1748                 :             : 
    1749                 :           0 :     commodity = gnc_commodity_table_lookup (table, name_space, mnemonic);
    1750                 :             : 
    1751                 :           0 :     g_free (name_space);
    1752                 :             : 
    1753                 :           0 :     return commodity;
    1754                 :             : }
    1755                 :             : 
    1756                 :             : /********************************************************************
    1757                 :             :  * gnc_commodity_table_find_full
    1758                 :             :  * locate a commodity by namespace and printable name
    1759                 :             :  ********************************************************************/
    1760                 :             : 
    1761                 :             : gnc_commodity *
    1762                 :           0 : gnc_commodity_table_find_full(const gnc_commodity_table * table,
    1763                 :             :                               const char * name_space,
    1764                 :             :                               const char * fullname)
    1765                 :             : {
    1766                 :           0 :     gnc_commodity * retval = nullptr;
    1767                 :             :     GList         * all;
    1768                 :             :     GList         * iterator;
    1769                 :             : 
    1770                 :           0 :     if (!fullname || (fullname[0] == '\0'))
    1771                 :           0 :         return nullptr;
    1772                 :             : 
    1773                 :           0 :     all = gnc_commodity_table_get_commodities(table, name_space);
    1774                 :             : 
    1775                 :           0 :     for (iterator = all; iterator; iterator = iterator->next)
    1776                 :             :     {
    1777                 :           0 :         auto commodity = GNC_COMMODITY (iterator->data);
    1778                 :           0 :         if (!strcmp(fullname,
    1779                 :             :                     gnc_commodity_get_printname(commodity)))
    1780                 :             :         {
    1781                 :           0 :             retval = commodity;
    1782                 :           0 :             break;
    1783                 :             :         }
    1784                 :             :     }
    1785                 :             : 
    1786                 :           0 :     g_list_free (all);
    1787                 :             : 
    1788                 :           0 :     return retval;
    1789                 :             : }
    1790                 :             : 
    1791                 :             : 
    1792                 :             : /********************************************************************
    1793                 :             :  * gnc_commodity_table_insert
    1794                 :             :  * add a commodity to the table.
    1795                 :             :  ********************************************************************/
    1796                 :             : 
    1797                 :             : gnc_commodity *
    1798                 :       62223 : gnc_commodity_table_insert(gnc_commodity_table * table,
    1799                 :             :                            gnc_commodity * comm)
    1800                 :             : {
    1801                 :       62223 :     gnc_commodity_namespace * nsp = nullptr;
    1802                 :             :     gnc_commodity *c;
    1803                 :             :     const char *ns_name;
    1804                 :             :     gnc_commodityPrivate* priv;
    1805                 :             :     QofBook *book;
    1806                 :             : 
    1807                 :       62223 :     if (!table) return nullptr;
    1808                 :       62223 :     if (!comm) return nullptr;
    1809                 :             : 
    1810                 :       62223 :     priv = GET_PRIVATE(comm);
    1811                 :             : 
    1812                 :       62223 :     ENTER ("(table=%p, comm=%p) %s %s", table, comm,
    1813                 :             :            (priv->mnemonic == nullptr ? "(null)" : priv->mnemonic),
    1814                 :             :            (priv->fullname == nullptr ? "(null)" : priv->fullname));
    1815                 :       62223 :     ns_name = gnc_commodity_namespace_get_name(priv->name_space);
    1816                 :       62223 :     c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
    1817                 :             : 
    1818                 :       62223 :     if (c)
    1819                 :             :     {
    1820                 :          46 :         if (c == comm)
    1821                 :             :         {
    1822                 :           3 :             LEAVE("already in table");
    1823                 :           3 :             return c;
    1824                 :             :         }
    1825                 :             : 
    1826                 :             :         /* Backward compatibility support for currencies that have
    1827                 :             :          * recently changed. */
    1828                 :          43 :         if (priv->name_space->iso4217)
    1829                 :             :         {
    1830                 :          24 :             auto it = gnc_new_iso_codes.find (priv->mnemonic);
    1831                 :          24 :             if (it != gnc_new_iso_codes.end())
    1832                 :           0 :                 gnc_commodity_set_mnemonic(comm, it->second.c_str());
    1833                 :             :         }
    1834                 :          43 :         gnc_commodity_copy (c, comm);
    1835                 :          43 :         gnc_commodity_destroy (comm);
    1836                 :          43 :         LEAVE("found at %p", c);
    1837                 :          43 :         return c;
    1838                 :             :     }
    1839                 :             : 
    1840                 :             :     /* Prevent setting anything except template in namespace template. */
    1841                 :       62442 :     if (g_strcmp0 (ns_name, GNC_COMMODITY_NS_TEMPLATE) == 0 &&
    1842                 :         265 :         g_strcmp0 (priv->mnemonic, "template") != 0)
    1843                 :             :     {
    1844                 :           0 :         PWARN("Converting commodity %s from namespace template to "
    1845                 :             :               "namespace User", priv->mnemonic);
    1846                 :           0 :         gnc_commodity_set_namespace (comm, "User");
    1847                 :           0 :         ns_name = "User";
    1848                 :           0 :         mark_commodity_dirty (comm);
    1849                 :             :     }
    1850                 :             : 
    1851                 :       62177 :     book = qof_instance_get_book (&comm->inst);
    1852                 :       62177 :     nsp = gnc_commodity_table_add_namespace(table, ns_name, book);
    1853                 :             : 
    1854                 :       62177 :     PINFO ("insert %p %s into nsp=%p %s", priv->mnemonic, priv->mnemonic,
    1855                 :             :            nsp->cm_table, nsp->name);
    1856                 :       62177 :     g_hash_table_insert(nsp->cm_table,
    1857                 :       62177 :                         (gpointer)CACHE_INSERT(priv->mnemonic),
    1858                 :             :                         (gpointer)comm);
    1859                 :       62177 :     nsp->cm_list = g_list_append(nsp->cm_list, comm);
    1860                 :             : 
    1861                 :       62177 :     qof_event_gen (&comm->inst, QOF_EVENT_ADD, nullptr);
    1862                 :       62177 :     LEAVE ("(table=%p, comm=%p)", table, comm);
    1863                 :       62177 :     return comm;
    1864                 :             : }
    1865                 :             : 
    1866                 :             : /********************************************************************
    1867                 :             :  * gnc_commodity_table_remove
    1868                 :             :  * remove a commodity from the table.
    1869                 :             :  ********************************************************************/
    1870                 :             : 
    1871                 :             : void
    1872                 :       41354 : gnc_commodity_table_remove(gnc_commodity_table * table,
    1873                 :             :                            gnc_commodity * comm)
    1874                 :             : {
    1875                 :             :     gnc_commodity_namespace * nsp;
    1876                 :             :     gnc_commodity *c;
    1877                 :             :     gnc_commodityPrivate* priv;
    1878                 :             :     const char *ns_name;
    1879                 :             : 
    1880                 :       41354 :     if (!table) return;
    1881                 :        4578 :     if (!comm) return;
    1882                 :             : 
    1883                 :        4578 :     priv = GET_PRIVATE(comm);
    1884                 :        4578 :     ns_name = gnc_commodity_namespace_get_name(priv->name_space);
    1885                 :        4578 :     c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
    1886                 :        4578 :     if (c != comm) return;
    1887                 :             : 
    1888                 :          65 :     qof_event_gen (&comm->inst, QOF_EVENT_REMOVE, nullptr);
    1889                 :             : 
    1890                 :          65 :     nsp = gnc_commodity_table_find_namespace(table, ns_name);
    1891                 :          65 :     if (!nsp) return;
    1892                 :             : 
    1893                 :          65 :     nsp->cm_list = g_list_remove(nsp->cm_list, comm);
    1894                 :          65 :     g_hash_table_remove (nsp->cm_table, priv->mnemonic);
    1895                 :             :     /* XXX minor mem leak, should remove the key as well */
    1896                 :             : }
    1897                 :             : 
    1898                 :             : /********************************************************************
    1899                 :             :  * gnc_commodity_table_has_namespace
    1900                 :             :  * see if the commodities namespace exists. May have zero commodities.
    1901                 :             :  ********************************************************************/
    1902                 :             : 
    1903                 :             : int
    1904                 :          20 : gnc_commodity_table_has_namespace(const gnc_commodity_table * table,
    1905                 :             :                                   const char * name_space)
    1906                 :             : {
    1907                 :          20 :     gnc_commodity_namespace * nsp = nullptr;
    1908                 :             : 
    1909                 :          20 :     if (!table || !name_space)
    1910                 :             :     {
    1911                 :           0 :         return 0;
    1912                 :             :     }
    1913                 :             : 
    1914                 :          20 :     nsp = gnc_commodity_table_find_namespace(table, name_space);
    1915                 :          20 :     if (nsp)
    1916                 :             :     {
    1917                 :          20 :         return 1;
    1918                 :             :     }
    1919                 :             :     else
    1920                 :             :     {
    1921                 :           0 :         return 0;
    1922                 :             :     }
    1923                 :             : }
    1924                 :             : 
    1925                 :             : static void
    1926                 :        1642 : hash_keys_helper(gpointer key, gpointer value, gpointer data)
    1927                 :             : {
    1928                 :        1642 :     auto l = (GList**)data;
    1929                 :        1642 :     *l = g_list_prepend(*l, key);
    1930                 :        1642 : }
    1931                 :             : 
    1932                 :             : static GList *
    1933                 :         241 : g_hash_table_keys(GHashTable * table)
    1934                 :             : {
    1935                 :         241 :     GList * l = nullptr;
    1936                 :         241 :     g_hash_table_foreach(table, &hash_keys_helper, (gpointer) &l);
    1937                 :         241 :     return l;
    1938                 :             : }
    1939                 :             : 
    1940                 :             : static void
    1941                 :       10164 : hash_values_helper(gpointer key, gpointer value, gpointer data)
    1942                 :             : {
    1943                 :       10164 :     auto l = (GList**)data;
    1944                 :       10164 :     *l = g_list_prepend(*l, value);
    1945                 :       10164 : }
    1946                 :             : 
    1947                 :             : static GList *
    1948                 :         240 : g_hash_table_values(GHashTable * table)
    1949                 :             : {
    1950                 :         240 :     GList * l = nullptr;
    1951                 :         240 :     g_hash_table_foreach(table, &hash_values_helper, (gpointer) &l);
    1952                 :         240 :     return l;
    1953                 :             : }
    1954                 :             : 
    1955                 :             : /********************************************************************
    1956                 :             :  * gnc_commodity_table_get_namespaces
    1957                 :             :  * see if any commodities in the namespace exist
    1958                 :             :  ********************************************************************/
    1959                 :             : 
    1960                 :             : GList *
    1961                 :         241 : gnc_commodity_table_get_namespaces(const gnc_commodity_table * table)
    1962                 :             : {
    1963                 :         241 :     if (!table)
    1964                 :           0 :         return nullptr;
    1965                 :             : 
    1966                 :         241 :     return g_hash_table_keys(table->ns_table);
    1967                 :             : }
    1968                 :             : 
    1969                 :             : GList *
    1970                 :           2 : gnc_commodity_table_get_namespaces_list(const gnc_commodity_table * table)
    1971                 :             : {
    1972                 :           2 :     if (!table)
    1973                 :           0 :         return nullptr;
    1974                 :             : 
    1975                 :           2 :     return g_list_copy (table->ns_list);
    1976                 :             : }
    1977                 :             : 
    1978                 :             : /* Because gnc_commodity_table_add_namespace maps GNC_COMMODITY_NS_ISO to
    1979                 :             :    GNC_COMMODITY_NS_CURRENCY and then sets iso4217 if the namespace is
    1980                 :             :    either of these, the net result is that the iso4217 bit is set only
    1981                 :             :    for GNC_COMMODITY_NS_CURRENCY.  This means that gnc_commodity_is_iso is
    1982                 :             :    a subset of gnc_commodity_is_currency.  Most callers seem to use
    1983                 :             :    gnc_commodity_is_iso. */
    1984                 :             : gboolean
    1985                 :      174596 : gnc_commodity_is_iso(const gnc_commodity * cm)
    1986                 :             : {
    1987                 :             :     gnc_commodityPrivate* priv;
    1988                 :             : 
    1989                 :      174596 :     if (!cm) return FALSE;
    1990                 :             : 
    1991                 :      174596 :     priv = GET_PRIVATE(cm);
    1992                 :      174596 :     if ( !priv->name_space) return FALSE;
    1993                 :      174412 :     return priv->name_space->iso4217;
    1994                 :             : }
    1995                 :             : 
    1996                 :             : gboolean
    1997                 :        8682 : gnc_commodity_is_currency(const gnc_commodity *cm)
    1998                 :             : {
    1999                 :             :     const char *ns_name;
    2000                 :        8682 :     if (!cm) return FALSE;
    2001                 :             : 
    2002                 :        8679 :     ns_name = gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->name_space);
    2003                 :       17358 :     return (!g_strcmp0(ns_name, GNC_COMMODITY_NS_LEGACY) ||
    2004                 :       17358 :             !g_strcmp0(ns_name, GNC_COMMODITY_NS_CURRENCY));
    2005                 :             : }
    2006                 :             : 
    2007                 :             : /********************************************************************
    2008                 :             :  * gnc_commodity_table_get_commodities
    2009                 :             :  * list commodities in a given namespace
    2010                 :             :  ********************************************************************/
    2011                 :             : 
    2012                 :             : static CommodityList*
    2013                 :           0 : commodity_table_get_all_noncurrency_commodities(const gnc_commodity_table* table)
    2014                 :             : {
    2015                 :           0 :     GList *node = nullptr, *nslist = gnc_commodity_table_get_namespaces(table);
    2016                 :           0 :     CommodityList *retval = nullptr;
    2017                 :           0 :     for (node = nslist; node; node=g_list_next(node))
    2018                 :             :     {
    2019                 :           0 :         gnc_commodity_namespace *ns = nullptr;
    2020                 :           0 :         if (g_strcmp0((char*)(node->data), GNC_COMMODITY_NS_CURRENCY) == 0
    2021                 :           0 :             || g_strcmp0((char*)(node->data), GNC_COMMODITY_NS_TEMPLATE) == 0)
    2022                 :           0 :             continue;
    2023                 :           0 :         ns = gnc_commodity_table_find_namespace(table, (char*)(node->data));
    2024                 :           0 :         if (!ns)
    2025                 :           0 :             continue;
    2026                 :           0 :         retval = g_list_concat(g_hash_table_values(ns->cm_table), retval);
    2027                 :             :     }
    2028                 :           0 :     g_list_free(nslist);
    2029                 :           0 :     return retval;
    2030                 :             : }
    2031                 :             : 
    2032                 :             : CommodityList *
    2033                 :         240 : gnc_commodity_table_get_commodities(const gnc_commodity_table * table,
    2034                 :             :                                     const char * name_space)
    2035                 :             : {
    2036                 :         240 :     gnc_commodity_namespace * ns = nullptr;
    2037                 :             : 
    2038                 :         240 :     if (!table)
    2039                 :           0 :         return nullptr;
    2040                 :         240 :     if (g_strcmp0(name_space, GNC_COMMODITY_NS_NONISO_GUI) == 0)
    2041                 :           0 :         return commodity_table_get_all_noncurrency_commodities(table);
    2042                 :         240 :     ns = gnc_commodity_table_find_namespace(table, name_space);
    2043                 :         240 :     if (!ns)
    2044                 :           0 :         return nullptr;
    2045                 :             : 
    2046                 :         240 :     return g_hash_table_values(ns->cm_table);
    2047                 :             : }
    2048                 :             : 
    2049                 :             : /********************************************************************
    2050                 :             :  * gnc_commodity_table_get_quotable_commodities
    2051                 :             :  * list commodities in a given namespace that get price quotes
    2052                 :             :  ********************************************************************/
    2053                 :             : 
    2054                 :             : static void
    2055                 :           0 : get_quotables_helper1(gpointer key, gpointer value, gpointer data)
    2056                 :             : {
    2057                 :           0 :     auto comm = GNC_COMMODITY(value);
    2058                 :           0 :     gnc_commodityPrivate* priv = GET_PRIVATE(comm);
    2059                 :           0 :     auto l = static_cast<GList**>(data);
    2060                 :             : 
    2061                 :           0 :     if (!priv->quote_flag || !priv->quote_source || !priv->quote_source->get_supported())
    2062                 :           0 :         return;
    2063                 :           0 :     *l = g_list_prepend(*l, value);
    2064                 :             : }
    2065                 :             : 
    2066                 :             : static gboolean
    2067                 :           0 : get_quotables_helper2 (gnc_commodity *comm, gpointer data)
    2068                 :             : {
    2069                 :           0 :     auto l = static_cast<GList**>(data);
    2070                 :           0 :     gnc_commodityPrivate* priv = GET_PRIVATE(comm);
    2071                 :             : 
    2072                 :           0 :     if (!priv->quote_flag || priv->quote_source || !priv->quote_source->get_supported())
    2073                 :           0 :         return TRUE;
    2074                 :           0 :     *l = g_list_prepend(*l, comm);
    2075                 :           0 :     return TRUE;
    2076                 :             : }
    2077                 :             : 
    2078                 :             : CommodityList *
    2079                 :           0 : gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table)
    2080                 :             : {
    2081                 :           0 :     gnc_commodity_namespace * ns = nullptr;
    2082                 :             :     const char *name_space;
    2083                 :             :     GList * nslist, * tmp;
    2084                 :           0 :     GList * l = nullptr;
    2085                 :             :     regex_t pattern;
    2086                 :           0 :     const char *expression = gnc_prefs_get_namespace_regexp();
    2087                 :             : 
    2088                 :           0 :     ENTER("table=%p, expression=%s", table, expression);
    2089                 :           0 :     if (!table)
    2090                 :           0 :         return nullptr;
    2091                 :             : 
    2092                 :           0 :     if (expression && *expression)
    2093                 :             :     {
    2094                 :           0 :         if (regcomp(&pattern, expression, REG_EXTENDED | REG_ICASE) != 0)
    2095                 :             :         {
    2096                 :           0 :             LEAVE("Cannot compile regex");
    2097                 :           0 :             return nullptr;
    2098                 :             :         }
    2099                 :             : 
    2100                 :           0 :         nslist = gnc_commodity_table_get_namespaces(table);
    2101                 :           0 :         for (tmp = nslist; tmp; tmp = tmp->next)
    2102                 :             :         {
    2103                 :           0 :             name_space = static_cast<const char*>(tmp->data);
    2104                 :           0 :             if (regexec(&pattern, name_space, 0, nullptr, 0) == 0)
    2105                 :             :             {
    2106                 :           0 :                 DEBUG("Running list of %s commodities", name_space);
    2107                 :           0 :                 ns = gnc_commodity_table_find_namespace(table, name_space);
    2108                 :           0 :                 if (ns)
    2109                 :             :                 {
    2110                 :           0 :                     g_hash_table_foreach(ns->cm_table, &get_quotables_helper1, (gpointer) &l);
    2111                 :             :                 }
    2112                 :             :             }
    2113                 :             :         }
    2114                 :           0 :         g_list_free(nslist);
    2115                 :           0 :         regfree(&pattern);
    2116                 :             :     }
    2117                 :             :     else
    2118                 :             :     {
    2119                 :           0 :         gnc_commodity_table_foreach_commodity(table, get_quotables_helper2,
    2120                 :             :                                               (gpointer) &l);
    2121                 :             :     }
    2122                 :           0 :     LEAVE("list head %p", l);
    2123                 :           0 :     return l;
    2124                 :             : }
    2125                 :             : 
    2126                 :             : /********************************************************************
    2127                 :             :  * gnc_commodity_table_add_namespace
    2128                 :             :  * add an empty namespace if it does not exist
    2129                 :             :  ********************************************************************/
    2130                 :             : 
    2131                 :             : /* GObject Initialization */
    2132                 :        2274 : QOF_GOBJECT_IMPL(gnc_commodity_namespace, gnc_commodity_namespace, QOF_TYPE_INSTANCE)
    2133                 :             : 
    2134                 :             : static void
    2135                 :         907 : gnc_commodity_namespace_init(gnc_commodity_namespace* ns)
    2136                 :             : {
    2137                 :         907 : }
    2138                 :             : 
    2139                 :             : static void
    2140                 :         560 : gnc_commodity_namespace_dispose_real (GObject *nsp)
    2141                 :             : {
    2142                 :         560 : }
    2143                 :             : 
    2144                 :             : static void
    2145                 :         560 : gnc_commodity_namespace_finalize_real(GObject* nsp)
    2146                 :             : {
    2147                 :         560 : }
    2148                 :             : 
    2149                 :             : gnc_commodity_namespace *
    2150                 :      128532 : gnc_commodity_table_add_namespace(gnc_commodity_table * table,
    2151                 :             :                                   const char * name_space,
    2152                 :             :                                   QofBook *book)
    2153                 :             : {
    2154                 :      128532 :     gnc_commodity_namespace * ns = nullptr;
    2155                 :             : 
    2156                 :      128532 :     if (!table) return nullptr;
    2157                 :             : 
    2158                 :      128204 :     name_space = gnc_commodity_table_map_namespace(name_space);
    2159                 :      128204 :     ns = gnc_commodity_table_find_namespace(table, name_space);
    2160                 :      128204 :     if (!ns)
    2161                 :             :     {
    2162                 :         907 :         ns = static_cast<gnc_commodity_namespace*>(g_object_new(GNC_TYPE_COMMODITY_NAMESPACE, nullptr));
    2163                 :         907 :         ns->cm_table = g_hash_table_new(g_str_hash, g_str_equal);
    2164                 :         907 :         ns->name = CACHE_INSERT(static_cast<const char*>(name_space));
    2165                 :         907 :         ns->iso4217 = gnc_commodity_namespace_is_iso(name_space);
    2166                 :         907 :         qof_instance_init_data (&ns->inst, GNC_ID_COMMODITY_NAMESPACE, book);
    2167                 :         907 :         qof_event_gen (&ns->inst, QOF_EVENT_CREATE, nullptr);
    2168                 :             : 
    2169                 :         907 :         g_hash_table_insert(table->ns_table,
    2170                 :         907 :                             (gpointer) ns->name,
    2171                 :             :                             (gpointer) ns);
    2172                 :         907 :         table->ns_list = g_list_append(table->ns_list, ns);
    2173                 :         907 :         qof_event_gen (&ns->inst, QOF_EVENT_ADD, nullptr);
    2174                 :             :     }
    2175                 :      128204 :     return ns;
    2176                 :             : }
    2177                 :             : 
    2178                 :             : 
    2179                 :             : gnc_commodity_namespace *
    2180                 :      210449 : gnc_commodity_table_find_namespace(const gnc_commodity_table * table,
    2181                 :             :                                    const char * name_space)
    2182                 :             : {
    2183                 :      210449 :     if (!table || !name_space)
    2184                 :           0 :         return nullptr;
    2185                 :             : 
    2186                 :      210449 :     name_space = gnc_commodity_table_map_namespace(name_space);
    2187                 :      210449 :     return static_cast<gnc_commodity_namespace*>(g_hash_table_lookup(table->ns_table, (gpointer)name_space));
    2188                 :             : }
    2189                 :             : 
    2190                 :             : 
    2191                 :             : gnc_commodity *
    2192                 :          38 : gnc_commodity_find_commodity_by_guid(const GncGUID *guid, QofBook *book)
    2193                 :             : {
    2194                 :             :     QofCollection *col;
    2195                 :          38 :     if (!guid || !book) return nullptr;
    2196                 :          38 :     col = qof_book_get_collection (book, GNC_ID_COMMODITY);
    2197                 :          38 :     return (gnc_commodity *) qof_collection_lookup_entity (col, guid);
    2198                 :             : }
    2199                 :             : 
    2200                 :             : /********************************************************************
    2201                 :             :  * gnc_commodity_table_delete_namespace
    2202                 :             :  * delete a namespace
    2203                 :             :  ********************************************************************/
    2204                 :             : 
    2205                 :             : static int
    2206                 :       37685 : ns_helper(gpointer key, gpointer value, gpointer user_data)
    2207                 :             : {
    2208                 :       37685 :     auto c = GNC_COMMODITY(value);
    2209                 :       37685 :     gnc_commodity_destroy(c);
    2210                 :       37685 :     CACHE_REMOVE(static_cast<char*>(key));  /* key is commodity mnemonic */
    2211                 :       37685 :     return TRUE;
    2212                 :             : }
    2213                 :             : 
    2214                 :             : void
    2215                 :         560 : gnc_commodity_table_delete_namespace(gnc_commodity_table * table,
    2216                 :             :                                      const char * name_space)
    2217                 :             : {
    2218                 :             :     gnc_commodity_namespace * ns;
    2219                 :             : 
    2220                 :         560 :     if (!table) return;
    2221                 :             : 
    2222                 :         560 :     ns = gnc_commodity_table_find_namespace(table, name_space);
    2223                 :         560 :     if (!ns)
    2224                 :           0 :         return;
    2225                 :             : 
    2226                 :         560 :     qof_event_gen (&ns->inst, QOF_EVENT_REMOVE, nullptr);
    2227                 :         560 :     g_hash_table_remove(table->ns_table, name_space);
    2228                 :         560 :     table->ns_list = g_list_remove(table->ns_list, ns);
    2229                 :             : 
    2230                 :         560 :     g_list_free(ns->cm_list);
    2231                 :         560 :     ns->cm_list = nullptr;
    2232                 :             : 
    2233                 :         560 :     g_hash_table_foreach_remove(ns->cm_table, ns_helper, nullptr);
    2234                 :         560 :     g_hash_table_destroy(ns->cm_table);
    2235                 :         560 :     CACHE_REMOVE(ns->name);
    2236                 :             : 
    2237                 :         560 :     qof_event_gen (&ns->inst, QOF_EVENT_DESTROY, nullptr);
    2238                 :             :     /* qof_instance_release(&ns->inst); */
    2239                 :         560 :     g_object_unref(ns);
    2240                 :             : }
    2241                 :             : 
    2242                 :             : /********************************************************************
    2243                 :             :  * gnc_commodity_table_foreach_commodity
    2244                 :             :  * call user-defined function once for every commodity in every
    2245                 :             :  * namespace
    2246                 :             :  ********************************************************************/
    2247                 :             : 
    2248                 :             : typedef struct
    2249                 :             : {
    2250                 :             :     gboolean ok;
    2251                 :             :     gboolean (*func)(gnc_commodity *, gpointer);
    2252                 :             :     gpointer user_data;
    2253                 :             : } IterData;
    2254                 :             : 
    2255                 :             : static void
    2256                 :        4872 : iter_commodity (gpointer key, gpointer value, gpointer user_data)
    2257                 :             : {
    2258                 :        4872 :     IterData *iter_data = (IterData *) user_data;
    2259                 :        4872 :     gnc_commodity *cm = (gnc_commodity *) value;
    2260                 :             : 
    2261                 :        4872 :     if (iter_data->ok)
    2262                 :             :     {
    2263                 :        4872 :         iter_data->ok = (iter_data->func)(cm, iter_data->user_data);
    2264                 :             :     }
    2265                 :        4872 : }
    2266                 :             : 
    2267                 :             : static void
    2268                 :          65 : iter_namespace (gpointer key, gpointer value, gpointer user_data)
    2269                 :             : {
    2270                 :          65 :     GHashTable *namespace_hash = ((gnc_commodity_namespace *) value)->cm_table;
    2271                 :          65 :     g_hash_table_foreach (namespace_hash, iter_commodity, user_data);
    2272                 :          65 : }
    2273                 :             : 
    2274                 :             : gboolean
    2275                 :          25 : gnc_commodity_table_foreach_commodity (const gnc_commodity_table * tbl,
    2276                 :             :                                        gboolean (*f)(gnc_commodity *, gpointer),
    2277                 :             :                                        gpointer user_data)
    2278                 :             : {
    2279                 :             :     IterData iter_data;
    2280                 :             : 
    2281                 :          25 :     if (!tbl || !f) return FALSE;
    2282                 :             : 
    2283                 :          25 :     iter_data.ok = TRUE;
    2284                 :          25 :     iter_data.func = f;
    2285                 :          25 :     iter_data.user_data = user_data;
    2286                 :             : 
    2287                 :          25 :     g_hash_table_foreach(tbl->ns_table, iter_namespace, (gpointer)&iter_data);
    2288                 :             : 
    2289                 :          25 :     return iter_data.ok;
    2290                 :             : }
    2291                 :             : 
    2292                 :             : /********************************************************************
    2293                 :             :  * gnc_commodity_table_destroy
    2294                 :             :  * cleanup and free.
    2295                 :             :  ********************************************************************/
    2296                 :             : 
    2297                 :             : void
    2298                 :         186 : gnc_commodity_table_destroy(gnc_commodity_table * t)
    2299                 :             : {
    2300                 :             :     gnc_commodity_namespace * ns;
    2301                 :             :     GList *item, *next;
    2302                 :             : 
    2303                 :         186 :     if (!t) return;
    2304                 :         186 :     ENTER ("table=%p", t);
    2305                 :             : 
    2306                 :         746 :     for (item = t->ns_list; item; item = next)
    2307                 :             :     {
    2308                 :         560 :         next = g_list_next(item);
    2309                 :         560 :         ns = static_cast<gnc_commodity_namespace*>(item->data);
    2310                 :         560 :         gnc_commodity_table_delete_namespace(t, ns->name);
    2311                 :             :     }
    2312                 :             : 
    2313                 :         186 :     g_list_free(t->ns_list);
    2314                 :         186 :     t->ns_list = nullptr;
    2315                 :         186 :     g_hash_table_destroy(t->ns_table);
    2316                 :         186 :     t->ns_table = nullptr;
    2317                 :         186 :     LEAVE ("table=%p", t);
    2318                 :         186 :     g_free(t);
    2319                 :             : }
    2320                 :             : 
    2321                 :             : /* =========================================================== */
    2322                 :             : 
    2323                 :             : /********************************************************************
    2324                 :             :  * gnc_commodity_table_add_default_data
    2325                 :             :  ********************************************************************/
    2326                 :             : 
    2327                 :             : #define CUR_I18N(String) dgettext ("iso_4217", String)
    2328                 :             : 
    2329                 :             : gboolean
    2330                 :         265 : gnc_commodity_table_add_default_data(gnc_commodity_table *table, QofBook *book)
    2331                 :             : {
    2332                 :             :     QofCollection *col;
    2333                 :             :     gnc_commodity* c;
    2334                 :             : 
    2335                 :         265 :     ENTER ("table=%p", table);
    2336                 :         265 :     gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_TEMPLATE, book);
    2337                 :         265 :     c = gnc_commodity_new(book, "template", GNC_COMMODITY_NS_TEMPLATE, "template", "template", 1);
    2338                 :         265 :     gnc_commodity_table_insert(table, c);
    2339                 :             : 
    2340                 :             : #include "iso-4217-currencies.c"
    2341                 :             : 
    2342                 :             :     /* We've just created the default namespaces and currencies.  Mark
    2343                 :             :      * these collections as clean because there is no USER entered data
    2344                 :             :      * in these collections as of yet. */
    2345                 :         265 :     col = qof_book_get_collection(book, GNC_ID_COMMODITY);
    2346                 :         265 :     qof_collection_mark_clean(col);
    2347                 :         265 :     col = qof_book_get_collection(book, GNC_ID_COMMODITY_NAMESPACE);
    2348                 :         265 :     qof_collection_mark_clean(col);
    2349                 :             : 
    2350                 :         265 :     LEAVE ("table=%p", table);
    2351                 :         265 :     return TRUE;
    2352                 :             : }
    2353                 :             : 
    2354                 :             : /********************************************************************
    2355                 :             :  ********************************************************************/
    2356                 :             : /* QofObject function implementation and registration */
    2357                 :             : 
    2358                 :             : #ifdef _MSC_VER
    2359                 :             : /* MSVC compiler doesn't have C99 "designated initializers"
    2360                 :             :  * so we wrap them in a macro that is empty on MSVC. */
    2361                 :             : # define DI(x) /* */
    2362                 :             : #else
    2363                 :             : # define DI(x) x
    2364                 :             : #endif
    2365                 :             : static QofObject commodity_object_def =
    2366                 :             : {
    2367                 :             :     DI(.interface_version = ) QOF_OBJECT_VERSION,
    2368                 :             :     DI(.e_type            = ) GNC_ID_COMMODITY,
    2369                 :             :     DI(.type_label        = ) "Commodity",
    2370                 :             :     DI(.create            = ) nullptr,
    2371                 :             :     DI(.book_begin        = ) nullptr,
    2372                 :             :     DI(.book_end          = ) nullptr,
    2373                 :             :     DI(.is_dirty          = ) qof_collection_is_dirty,
    2374                 :             :     DI(.mark_clean        = ) qof_collection_mark_clean,
    2375                 :             :     DI(.foreach           = ) qof_collection_foreach,
    2376                 :             :     DI(.printable         = ) (const char * (*)(gpointer)) gnc_commodity_get_fullname,
    2377                 :             : };
    2378                 :             : 
    2379                 :             : static QofObject namespace_object_def =
    2380                 :             : {
    2381                 :             :     DI(.interface_version = ) QOF_OBJECT_VERSION,
    2382                 :             :     DI(.e_type            = ) GNC_ID_COMMODITY_NAMESPACE,
    2383                 :             :     DI(.type_label        = ) "Namespace",
    2384                 :             :     DI(.create            = ) nullptr,
    2385                 :             :     DI(.book_begin        = ) nullptr,
    2386                 :             :     DI(.book_end          = ) nullptr,
    2387                 :             :     DI(.is_dirty          = ) nullptr,
    2388                 :             :     DI(.mark_clean        = ) nullptr,
    2389                 :             :     DI(.foreach           = ) nullptr,
    2390                 :             :     DI(.printable         = ) nullptr,
    2391                 :             : };
    2392                 :             : 
    2393                 :             : static void
    2394                 :         276 : commodity_table_book_begin (QofBook *book)
    2395                 :             : {
    2396                 :             :     gnc_commodity_table *ct;
    2397                 :         276 :     ENTER ("book=%p", book);
    2398                 :             : 
    2399                 :         276 :     if (gnc_commodity_table_get_table(book))
    2400                 :          15 :         return;
    2401                 :             : 
    2402                 :         261 :     ct = gnc_commodity_table_new ();
    2403                 :         261 :     qof_book_set_data (book, GNC_COMMODITY_TABLE, ct);
    2404                 :             : 
    2405                 :         261 :     if (!gnc_commodity_table_add_default_data(ct, book))
    2406                 :             :     {
    2407                 :           0 :         PWARN("unable to initialize book's commodity_table");
    2408                 :             :     }
    2409                 :             : 
    2410                 :         261 :     LEAVE ("book=%p", book);
    2411                 :             : }
    2412                 :             : 
    2413                 :             : static void
    2414                 :         173 : commodity_table_book_end (QofBook *book)
    2415                 :             : {
    2416                 :             :     gnc_commodity_table *ct;
    2417                 :             : 
    2418                 :         173 :     ct = gnc_commodity_table_get_table (book);
    2419                 :         173 :     qof_book_set_data (book, GNC_COMMODITY_TABLE, nullptr);
    2420                 :         173 :     gnc_commodity_table_destroy (ct);
    2421                 :         173 : }
    2422                 :             : 
    2423                 :             : static QofObject commodity_table_object_def =
    2424                 :             : {
    2425                 :             :     DI(.interface_version = ) QOF_OBJECT_VERSION,
    2426                 :             :     DI(.e_type            = ) GNC_ID_COMMODITY_TABLE,
    2427                 :             :     DI(.type_label        = ) "CommodityTable",
    2428                 :             :     DI(.create            = ) nullptr,
    2429                 :             :     DI(.book_begin        = ) commodity_table_book_begin,
    2430                 :             :     DI(.book_end          = ) commodity_table_book_end,
    2431                 :             :     DI(.is_dirty          = ) qof_collection_is_dirty,
    2432                 :             :     DI(.mark_clean        = ) qof_collection_mark_clean,
    2433                 :             :     DI(.foreach           = ) nullptr,
    2434                 :             :     DI(.printable         = ) nullptr,
    2435                 :             :     DI(.version_cmp       = ) nullptr,
    2436                 :             : };
    2437                 :             : 
    2438                 :             : gboolean
    2439                 :          99 : gnc_commodity_table_register (void)
    2440                 :             : {
    2441                 :          99 :     if (!qof_object_register (&commodity_object_def))
    2442                 :           1 :         return FALSE;
    2443                 :          98 :     if (!qof_object_register (&namespace_object_def))
    2444                 :           0 :         return FALSE;
    2445                 :          98 :     return qof_object_register (&commodity_table_object_def);
    2446                 :             : }
    2447                 :             : 
    2448                 :             : /* *******************************************************************
    2449                 :             : *  gnc_monetary methods
    2450                 :             : ********************************************************************/
    2451                 :             : 
    2452                 :             : /** Add a gnc_monetary to the list */
    2453                 :             : MonetaryList *
    2454                 :          44 : gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
    2455                 :             : {
    2456                 :          44 :     MonetaryList *l = list, *tmp;
    2457                 :          70 :     for (tmp = list; tmp; tmp = tmp->next)
    2458                 :             :     {
    2459                 :          49 :         auto list_mon = static_cast<gnc_monetary*>(tmp->data);
    2460                 :          49 :         if (gnc_commodity_equiv(list_mon->commodity, add_mon.commodity))
    2461                 :             :         {
    2462                 :          23 :             list_mon->value = gnc_numeric_add(list_mon->value, add_mon.value,
    2463                 :             :                                               GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
    2464                 :          23 :             break;
    2465                 :             :         }
    2466                 :             :     }
    2467                 :             : 
    2468                 :             :     /* See if we found an entry, and add one if not */
    2469                 :          44 :     if (tmp == nullptr)
    2470                 :             :     {
    2471                 :          21 :         auto new_mon = static_cast<gnc_monetary*>(g_new0(gnc_monetary, 1));
    2472                 :          21 :         *new_mon = add_mon;
    2473                 :          21 :         l = g_list_prepend(l, new_mon);
    2474                 :             :     }
    2475                 :             : 
    2476                 :          44 :     return l;
    2477                 :             : }
    2478                 :             : 
    2479                 :             : /** Delete all entries in the list that have zero value.  Return list
    2480                 :             :     pointer will be a null pointer if there are no non-zero entries **/
    2481                 :             : MonetaryList *
    2482                 :          12 : gnc_monetary_list_delete_zeros(MonetaryList *list)
    2483                 :             : {
    2484                 :             :     MonetaryList *node, *next;
    2485                 :          33 :     for (node = list; node; node = next)
    2486                 :             :     {
    2487                 :          21 :         auto mon = static_cast<gnc_monetary*>(node->data);
    2488                 :          21 :         next = node->next;
    2489                 :          21 :         if (gnc_numeric_zero_p(mon->value))
    2490                 :             :         {
    2491                 :          10 :             g_free(mon);
    2492                 :          10 :             list = g_list_delete_link(list, node);
    2493                 :             :         }
    2494                 :             :     }
    2495                 :          12 :     return list;
    2496                 :             : }
    2497                 :             : 
    2498                 :             : /** Free a MonetaryList and all the monetaries it points to */
    2499                 :             : void
    2500                 :          11 : gnc_monetary_list_free(MonetaryList *list)
    2501                 :             : {
    2502                 :             :     MonetaryList *tmp;
    2503                 :          22 :     for (tmp = list; tmp; tmp = tmp->next)
    2504                 :             :     {
    2505                 :          11 :         g_free(tmp->data);
    2506                 :             :     }
    2507                 :             : 
    2508                 :          11 :     g_list_free(list);
    2509                 :          11 : }
    2510                 :             : 
    2511                 :             : /* ========================= END OF FILE ============================== */
        

Generated by: LCOV version 2.0-1