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

Generated by: LCOV version 2.0-1