GnuCash  5.6-150-g038405b370+
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
gnc-commodity.cpp
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 
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;
98 
99 #define GET_PRIVATE(o) \
100  ((gnc_commodityPrivate*)gnc_commodity_get_instance_private((gnc_commodity*)o))
101 
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 
111 {
112  QofInstance inst;
113 
114  const gchar *name;
115  gboolean iso4217;
116  GHashTable * cm_table;
117  GList * cm_list;
118 };
119 
121 {
122  QofInstanceClass parent_class;
123 };
124 
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 
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  bool get_supported () const { return m_supported; }
158  void set_supported (bool supported) { m_supported = supported; }
159  QuoteSourceType get_type () const { return m_type; }
160  const char* get_user_name () const { return m_user_name.c_str(); }
161  const char* get_internal_name () const { return m_internal_name.c_str(); }
162  gnc_quote_source_s (gboolean supported, QuoteSourceType type,
163  const char* username, const char* int_name)
164  : m_supported{supported}
165  , m_type{type}
166  , m_user_name{username ? username : ""}
167  , 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
269 {
270  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*
282 {
283  return fq_version.c_str();
284 }
285 
286 static QuoteSourceList&
287 get_quote_source_from_type (QuoteSourceType type)
288 {
289  auto quote_sources_it = std::find_if (quote_sources_map.begin(), quote_sources_map.end(),
290  [type] (const auto& qs) { return type == qs.first; });
291 
292  if (quote_sources_it != quote_sources_map.end())
293  return quote_sources_it->second;
294 
295  PWARN ("Invalid Quote Source %d, returning new_quote_sources", type);
296  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  ********************************************************************/
305 {
306  auto source{get_quote_source_from_type(type)};
307  return std::distance(source.begin(), source.end());
308 }
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 gnc_quote_source_add_new (const char *source_name, gboolean supported)
322 {
323  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  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 *
339 {
340  ENTER("type/index is %d/%d", type, index);
341  auto& sources = get_quote_source_from_type (type);
342  if ((size_t) index < sources.size())
343  {
344  auto it = std::next(sources.begin(), index);
345  LEAVE("found %s", it->get_user_name());
346  return &*it;
347  }
348 
349  LEAVE("not found");
350  return nullptr;
351 }
352 
353 gnc_quote_source *
355 {
356  if (!name || !*name)
357  return nullptr;
358 
359  for (const auto& [_, sources] : quote_sources_map)
360  {
361  auto source_it = std::find_if (sources.begin(), sources.end(),
362  [name] (const auto& qs)
363  { return (g_strcmp0(name, qs.get_internal_name()) == 0); });
364  if (source_it != sources.end())
365  return &(*source_it);
366  }
367 
368  DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);
369  return nullptr;
370 }
371 
372 /********************************************************************
373  * gnc_quote_source_get_xxx
374  *
375  * Accessor functions - get functions only. There are no set functions.
376  ********************************************************************/
378 gnc_quote_source_get_type (const gnc_quote_source *source)
379 {
380  ENTER("%p", source);
381  if (!source)
382  {
383  LEAVE("bad source");
384  return SOURCE_SINGLE;
385  }
386 
387  LEAVE("type is %d", source->get_type());
388  return source->get_type();
389 }
390 
391 gint
392 gnc_quote_source_get_index (const gnc_quote_source *source)
393 {
394  if (!source)
395  {
396  PWARN ("bad source");
397  return 0;
398  }
399 
400  auto& sources = get_quote_source_from_type (source->get_type());
401  auto is_source = [&source](const auto& findif_source)
402  { return &findif_source == source; };
403 
404  auto iter = std::find_if (sources.begin(), sources.end(), is_source);
405  if (iter != sources.end())
406  return std::distance (sources.begin(), iter);
407 
408  PWARN ("couldn't locate source");
409  return 0;
410 }
411 
412 gboolean
413 gnc_quote_source_get_supported (const gnc_quote_source *source)
414 {
415  ENTER("%p", source);
416  if (!source)
417  {
418  LEAVE("bad source");
419  return FALSE;
420  }
421 
422  LEAVE("%s supported", source && source->get_supported() ? "" : "not ");
423  return source->get_supported();
424 }
425 
426 const char *
427 gnc_quote_source_get_user_name (const gnc_quote_source *source)
428 {
429  ENTER("%p", source);
430  if (!source)
431  {
432  LEAVE("bad source");
433  return nullptr;
434  }
435  LEAVE("user name %s", source->get_user_name());
436  return source->get_user_name();
437 }
438 
439 const char *
440 gnc_quote_source_get_internal_name (const gnc_quote_source *source)
441 {
442  ENTER("%p", source);
443  if (!source)
444  {
445  LEAVE("bad source");
446  return nullptr;
447  }
448  LEAVE("internal name %s", source->get_internal_name());
449  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 gnc_quote_source_set_fq_installed (const char* version_string,
461  const std::vector<std::string>& sources_list)
462 {
463  ENTER(" ");
464 
465  if (sources_list.empty())
466  return;
467 
468  if (version_string)
469  fq_version = version_string;
470  else
471  fq_version.clear();
472 
473  for (const auto& source_name_str : sources_list)
474  {
475  auto source_name = source_name_str.c_str();
476  auto source = gnc_quote_source_lookup_by_internal(source_name);
477 
478  if (source)
479  {
480  DEBUG("Found source %s: %s", source_name, source->get_user_name());
481  source->set_supported (true);
482  continue;
483  }
484 
485  gnc_quote_source_add_new(source_name, TRUE);
486  }
487  LEAVE(" ");
488 }
489 
490 /********************************************************************
491  * QoF Helpers
492  ********************************************************************/
493 
494 void
495 gnc_commodity_begin_edit (gnc_commodity *cm)
496 {
497  qof_begin_edit(&cm->inst);
498 }
499 
500 static void commit_err (QofInstance *inst, QofBackendError errcode)
501 {
502  PERR ("Failed to commit: %d", errcode);
503  gnc_engine_signal_commit_error( errcode );
504 }
505 
506 static void noop (QofInstance *inst) {}
507 
508 static void
509 comm_free(QofInstance* inst)
510 {
511  commodity_free( GNC_COMMODITY(inst) );
512 }
513 
514 void
515 gnc_commodity_commit_edit (gnc_commodity *cm)
516 {
517  if (!qof_commit_edit (QOF_INSTANCE(cm))) return;
518  qof_commit_edit_part2 (&cm->inst, commit_err, noop, comm_free);
519 }
520 
521 /********************************************************************
522  * gnc_commodity_new
523  ********************************************************************/
524 
525 static void
526 mark_commodity_dirty (gnc_commodity *cm)
527 {
528  qof_instance_set_dirty(&cm->inst);
529  qof_event_gen (&cm->inst, QOF_EVENT_MODIFY, nullptr);
530 }
531 
532 static void
533 reset_printname(gnc_commodityPrivate *priv)
534 {
535  g_free(priv->printname);
536  priv->printname = g_strdup_printf("%s (%s)",
537  priv->mnemonic ? priv->mnemonic : "",
538  priv->fullname ? priv->fullname : "");
539 }
540 
541 static void
542 reset_unique_name(gnc_commodityPrivate *priv)
543 {
544  gnc_commodity_namespace *ns;
545 
546  g_free(priv->unique_name);
547  ns = priv->name_space;
548  priv->unique_name = g_strdup_printf("%s::%s",
549  ns ? ns->name : "",
550  priv->mnemonic ? priv->mnemonic : "");
551 }
552 
553 /* GObject Initialization */
554 G_DEFINE_TYPE_WITH_PRIVATE(gnc_commodity, gnc_commodity, QOF_TYPE_INSTANCE)
555 
556 static void
557 gnc_commodity_init(gnc_commodity* com)
558 {
559  gnc_commodityPrivate* priv;
560 
561  priv = GET_PRIVATE(com);
562 
563  priv->name_space = nullptr;
564  priv->fullname = CACHE_INSERT("");
565  priv->mnemonic = CACHE_INSERT("");
566  priv->cusip = CACHE_INSERT("");
567  priv->fraction = 10000;
568  priv->quote_flag = 0;
569  priv->quote_source = nullptr;
570  priv->quote_tz = CACHE_INSERT("");
571 
572  reset_printname(priv);
573  reset_unique_name(priv);
574 }
575 
576 static void
577 gnc_commodity_dispose(GObject *comp)
578 {
579  G_OBJECT_CLASS(gnc_commodity_parent_class)->dispose(comp);
580 }
581 
582 static void
583 gnc_commodity_finalize(GObject* comp)
584 {
585  G_OBJECT_CLASS(gnc_commodity_parent_class)->finalize(comp);
586 }
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 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  g_return_if_fail(GNC_IS_COMMODITY(object));
603 
604  commodity = GNC_COMMODITY(object);
605  priv = GET_PRIVATE(commodity);
606  switch (prop_id)
607  {
608  case PROP_NAMESPACE:
609  g_value_take_object(value, priv->name_space);
610  break;
611  case PROP_FULL_NAME:
612  g_value_set_string(value, priv->fullname);
613  break;
614  case PROP_MNEMONIC:
615  g_value_set_string(value, priv->mnemonic);
616  break;
617  case PROP_PRINTNAME:
618  g_value_set_string(value, priv->printname);
619  break;
620  case PROP_CUSIP:
621  g_value_set_string(value, priv->cusip);
622  break;
623  case PROP_FRACTION:
624  g_value_set_int(value, priv->fraction);
625  break;
626  case PROP_UNIQUE_NAME:
627  g_value_set_string(value, priv->unique_name);
628  break;
629  case PROP_QUOTE_FLAG:
630  g_value_set_boolean(value, priv->quote_flag);
631  break;
632  case PROP_QUOTE_SOURCE:
633  g_value_set_pointer(value, priv->quote_source);
634  break;
635  case PROP_QUOTE_TZ:
636  g_value_set_string(value, priv->quote_tz);
637  break;
638  default:
639  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
640  break;
641  }
642 }
643 
644 static void
645 gnc_commodity_set_property (GObject *object,
646  guint prop_id,
647  const GValue *value,
648  GParamSpec *pspec)
649 {
650  gnc_commodity *commodity;
651 
652  g_return_if_fail(GNC_IS_COMMODITY(object));
653 
654  commodity = GNC_COMMODITY(object);
655  g_assert (qof_instance_get_editlevel(commodity));
656 
657  switch (prop_id)
658  {
659  case PROP_NAMESPACE:
660  gnc_commodity_set_namespace(commodity, static_cast<const char*>(g_value_get_object(value)));
661  break;
662  case PROP_FULL_NAME:
663  gnc_commodity_set_fullname(commodity, g_value_get_string(value));
664  break;
665  case PROP_MNEMONIC:
666  gnc_commodity_set_mnemonic(commodity, g_value_get_string(value));
667  break;
668  case PROP_CUSIP:
669  gnc_commodity_set_cusip(commodity, g_value_get_string(value));
670  break;
671  case PROP_FRACTION:
672  gnc_commodity_set_fraction(commodity, g_value_get_int(value));
673  break;
674  case PROP_QUOTE_FLAG:
675  gnc_commodity_set_quote_flag(commodity, g_value_get_boolean(value));
676  break;
677  case PROP_QUOTE_SOURCE:
678  gnc_commodity_set_quote_source(commodity, static_cast<gnc_quote_source*>(g_value_get_pointer(value)));
679  break;
680  case PROP_QUOTE_TZ:
681  gnc_commodity_set_quote_tz(commodity, g_value_get_string(value));
682  break;
683  default:
684  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
685  break;
686  }
687 }
688 static void
689 gnc_commodity_class_init(struct _GncCommodityClass* klass)
690 {
691  GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
692 
693  gobject_class->dispose = gnc_commodity_dispose;
694  gobject_class->finalize = gnc_commodity_finalize;
695  gobject_class->set_property = gnc_commodity_set_property;
696  gobject_class->get_property = gnc_commodity_get_property;
697 
698  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  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  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  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  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  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,
745  1,
746  G_PARAM_READWRITE));
747  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  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  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  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 }
777 
778 gnc_commodity *
779 gnc_commodity_new(QofBook *book, const char * fullname,
780  const char * name_space, const char * mnemonic,
781  const char * cusip, int fraction)
782 {
783  auto retval = GNC_COMMODITY(g_object_new(GNC_TYPE_COMMODITY, nullptr));
784 
785  qof_instance_init_data (&retval->inst, GNC_ID_COMMODITY, book);
786  gnc_commodity_begin_edit(retval);
787 
788  if ( name_space != nullptr )
789  {
790  /* Prevent setting anything except template in namespace template. */
791  if (g_strcmp0 (name_space, GNC_COMMODITY_NS_TEMPLATE) == 0 &&
792  g_strcmp0 (mnemonic, "template") != 0)
793  {
794  PWARN("Converting commodity %s from namespace template to "
795  "namespace User", mnemonic);
796  name_space = "User";
797  }
798  gnc_commodity_set_namespace(retval, name_space);
799  if (gnc_commodity_namespace_is_iso(name_space))
800  {
803  }
804  }
805  gnc_commodity_set_fullname(retval, fullname);
806  gnc_commodity_set_mnemonic(retval, mnemonic);
807  gnc_commodity_set_cusip(retval, cusip);
808  gnc_commodity_set_fraction(retval, fraction);
809  mark_commodity_dirty (retval);
810  gnc_commodity_commit_edit(retval);
811 
812  qof_event_gen (&retval->inst, QOF_EVENT_CREATE, nullptr);
813 
814  return retval;
815 }
816 
817 
818 /********************************************************************
819  * gnc_commodity_destroy
820  ********************************************************************/
821 
822 static void
823 commodity_free(gnc_commodity * cm)
824 {
825  QofBook *book;
826  gnc_commodity_table *table;
827  gnc_commodityPrivate* priv;
828 
829  if (!cm) return;
830 
831  book = qof_instance_get_book(&cm->inst);
834  priv = GET_PRIVATE(cm);
835 
836  qof_event_gen (&cm->inst, QOF_EVENT_DESTROY, nullptr);
837 
838  /* Set at creation */
839  CACHE_REMOVE (priv->fullname);
840  CACHE_REMOVE (priv->cusip);
841  CACHE_REMOVE (priv->mnemonic);
842  CACHE_REMOVE (priv->quote_tz);
843  priv->name_space = nullptr;
844 
845  /* Set through accessor functions */
846  priv->quote_source = nullptr;
847 
848  /* Automatically generated */
849  g_free(priv->printname);
850  priv->printname = nullptr;
851 
852  g_free(priv->unique_name);
853  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  g_object_unref(cm);
869 }
870 
871 void
872 gnc_commodity_destroy(gnc_commodity * cm)
873 {
874  gnc_commodity_begin_edit(cm);
875  qof_instance_set_destroying(cm, TRUE);
876  gnc_commodity_commit_edit(cm);
877 }
878 
879 void
880 gnc_commodity_copy(gnc_commodity * dest, const gnc_commodity *src)
881 {
882  gnc_commodityPrivate* src_priv = GET_PRIVATE(src);
883  gnc_commodityPrivate* dest_priv = GET_PRIVATE(dest);
884 
885  gnc_commodity_set_fullname (dest, src_priv->fullname);
886  gnc_commodity_set_mnemonic (dest, src_priv->mnemonic);
887  dest_priv->name_space = src_priv->name_space;
888  gnc_commodity_set_fraction (dest, src_priv->fraction);
889  gnc_commodity_set_cusip (dest, src_priv->cusip);
890  gnc_commodity_set_quote_flag (dest, src_priv->quote_flag);
892  gnc_commodity_set_quote_tz (dest, src_priv->quote_tz);
893  qof_instance_copy_kvp (QOF_INSTANCE (dest), QOF_INSTANCE (src));
894 }
895 
896 gnc_commodity *
897 gnc_commodity_clone(const gnc_commodity *src, QofBook *dest_book)
898 {
899  gnc_commodityPrivate* src_priv;
900  gnc_commodityPrivate* dest_priv;
901 
902  auto dest = GNC_COMMODITY (g_object_new(GNC_TYPE_COMMODITY, nullptr));
903  qof_instance_init_data (&dest->inst, GNC_ID_COMMODITY, dest_book);
904  src_priv = GET_PRIVATE(src);
905  dest_priv = GET_PRIVATE(dest);
906 
907  dest_priv->fullname = CACHE_INSERT(src_priv->fullname);
908  dest_priv->mnemonic = CACHE_INSERT(src_priv->mnemonic);
909  dest_priv->cusip = CACHE_INSERT(src_priv->cusip);
910  dest_priv->quote_tz = CACHE_INSERT(src_priv->quote_tz);
911 
912  dest_priv->name_space = src_priv->name_space;
913 
914  dest_priv->fraction = src_priv->fraction;
915  dest_priv->quote_flag = src_priv->quote_flag;
916 
918 
919  qof_instance_copy_kvp (QOF_INSTANCE (dest), QOF_INSTANCE (src));
920 
921  reset_printname(dest_priv);
922  reset_unique_name(dest_priv);
923 
924  return dest;
925 }
926 
927 /********************************************************************
928  * gnc_commodity_get_mnemonic
929  ********************************************************************/
930 
931 const char *
932 gnc_commodity_get_mnemonic(const gnc_commodity * cm)
933 {
934  if (!cm) return nullptr;
935  return GET_PRIVATE(cm)->mnemonic;
936 }
937 
938 /********************************************************************
939  * gnc_commodity_get_printname
940  ********************************************************************/
941 
942 const char *
943 gnc_commodity_get_printname(const gnc_commodity * cm)
944 {
945  if (!cm) return nullptr;
946  return GET_PRIVATE(cm)->printname;
947 }
948 
949 
950 /********************************************************************
951  * gnc_commodity_get_namespace
952  ********************************************************************/
953 
954 const char *
955 gnc_commodity_get_namespace(const gnc_commodity * cm)
956 {
957  if (!cm) return nullptr;
958  return gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->name_space);
959 }
960 
961 gnc_commodity_namespace *
962 gnc_commodity_get_namespace_ds(const gnc_commodity * cm)
963 {
964  if (!cm) return nullptr;
965  return GET_PRIVATE(cm)->name_space;
966 }
967 
968 /********************************************************************
969  * gnc_commodity_get_fullname
970  ********************************************************************/
971 
972 const char *
973 gnc_commodity_get_fullname(const gnc_commodity * cm)
974 {
975  if (!cm) return nullptr;
976  return GET_PRIVATE(cm)->fullname;
977 }
978 
979 
980 /********************************************************************
981  * gnc_commodity_get_unique_name
982  ********************************************************************/
983 
984 const char *
985 gnc_commodity_get_unique_name(const gnc_commodity * cm)
986 {
987  if (!cm) return nullptr;
988  return GET_PRIVATE(cm)->unique_name;
989 }
990 
991 
992 /********************************************************************
993  * gnc_commodity_get_cusip
994  ********************************************************************/
995 
996 const char *
997 gnc_commodity_get_cusip(const gnc_commodity * cm)
998 {
999  if (!cm) return nullptr;
1000  return GET_PRIVATE(cm)->cusip;
1001 }
1002 
1003 /********************************************************************
1004  * gnc_commodity_get_fraction
1005  ********************************************************************/
1006 
1007 int
1008 gnc_commodity_get_fraction(const gnc_commodity * cm)
1009 {
1010  if (!cm) return 0;
1011  return GET_PRIVATE(cm)->fraction;
1012 }
1013 
1014 /********************************************************************
1015  * gnc_commodity_get_auto_quote_control_flag
1016  ********************************************************************/
1017 
1018 static gboolean
1019 gnc_commodity_get_auto_quote_control_flag(const gnc_commodity *cm)
1020 {
1021  GValue v = G_VALUE_INIT;
1022  gboolean retval = TRUE;
1023 
1024  if (!cm) return FALSE;
1025  qof_instance_get_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
1026  if (G_VALUE_HOLDS_STRING (&v) &&
1027  strcmp(g_value_get_string (&v), "false") == 0)
1028  retval = FALSE;
1029  g_value_unset (&v);
1030  return retval;
1031 }
1032 
1033 /********************************************************************
1034  * gnc_commodity_get_quote_flag
1035  ********************************************************************/
1036 
1037 gboolean
1038 gnc_commodity_get_quote_flag(const gnc_commodity *cm)
1039 {
1040  if (!cm) return FALSE;
1041  return (GET_PRIVATE(cm)->quote_flag);
1042 }
1043 
1044 /********************************************************************
1045  * gnc_commodity_get_quote_source
1046  ********************************************************************/
1047 
1048 gnc_quote_source*
1049 gnc_commodity_get_quote_source(const gnc_commodity *cm)
1050 {
1051  gnc_commodityPrivate* priv;
1052 
1053  if (!cm) return nullptr;
1054  priv = GET_PRIVATE(cm);
1055  if (!priv->quote_source && gnc_commodity_is_iso(cm))
1056  return &currency_quote_sources.front();
1057  return priv->quote_source;
1058 }
1059 
1060 gnc_quote_source*
1061 gnc_commodity_get_default_quote_source(const gnc_commodity *cm)
1062 {
1063  if (cm && gnc_commodity_is_iso(cm))
1064  return &currency_quote_sources.front();
1065  /* Should make this a user option at some point. */
1066  return gnc_quote_source_lookup_by_internal("alphavantage");
1067 }
1068 
1069 /********************************************************************
1070  * gnc_commodity_get_quote_tz
1071  ********************************************************************/
1072 
1073 const char*
1074 gnc_commodity_get_quote_tz(const gnc_commodity *cm)
1075 {
1076  if (!cm) return nullptr;
1077  return GET_PRIVATE(cm)->quote_tz;
1078 }
1079 
1080 /********************************************************************
1081  * gnc_commodity_get_user_symbol
1082  ********************************************************************/
1083 const char*
1084 gnc_commodity_get_user_symbol(const gnc_commodity *cm)
1085 {
1086  g_return_val_if_fail (GNC_IS_COMMODITY (cm), nullptr);
1087 
1088  GValue v = G_VALUE_INIT;
1089  qof_instance_get_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
1090  const char *rv = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : nullptr;
1091  g_value_unset (&v);
1092  return rv;
1093 }
1094 
1095 /********************************************************************
1096  * gnc_commodity_get_default_symbol
1097  *******************************************************************/
1098 const char*
1099 gnc_commodity_get_default_symbol(const gnc_commodity *cm)
1100 {
1101  if (!cm) return nullptr;
1102  return GET_PRIVATE(cm)->default_symbol;
1103 }
1104 
1105 /********************************************************************
1106  * gnc_commodity_get_nice_symbol
1107  *******************************************************************/
1108 const char*
1109 gnc_commodity_get_nice_symbol (const gnc_commodity *cm)
1110 {
1111  const char *nice_symbol;
1112  struct lconv *lc;
1113  if (!cm) return nullptr;
1114 
1115  nice_symbol = gnc_commodity_get_user_symbol(cm);
1116  if (nice_symbol && *nice_symbol)
1117  return nice_symbol;
1118 
1119  lc = gnc_localeconv();
1120  nice_symbol = lc->currency_symbol;
1121  if (!g_strcmp0(gnc_commodity_get_mnemonic(cm), lc->int_curr_symbol))
1122  return nice_symbol;
1123 
1124  nice_symbol = gnc_commodity_get_default_symbol(cm);
1125  if (nice_symbol && *nice_symbol)
1126  return nice_symbol;
1127 
1128  return gnc_commodity_get_mnemonic(cm);
1129 }
1130 
1131 /********************************************************************
1132  * gnc_commodity_set_mnemonic
1133  ********************************************************************/
1134 
1135 void
1136 gnc_commodity_set_mnemonic(gnc_commodity * cm, const char * mnemonic)
1137 {
1138  gnc_commodityPrivate* priv;
1139 
1140  if (!cm) return;
1141  priv = GET_PRIVATE(cm);
1142  if (priv->mnemonic == mnemonic) return;
1143 
1144  gnc_commodity_begin_edit(cm);
1145  CACHE_REMOVE (priv->mnemonic);
1146  priv->mnemonic = CACHE_INSERT(mnemonic);
1147 
1148  mark_commodity_dirty (cm);
1149  reset_printname(priv);
1150  reset_unique_name(priv);
1151  gnc_commodity_commit_edit(cm);
1152 }
1153 
1154 /********************************************************************
1155  * gnc_commodity_set_namespace
1156  ********************************************************************/
1157 
1158 void
1159 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  if (!cm) return;
1167  priv = GET_PRIVATE(cm);
1168  book = qof_instance_get_book (&cm->inst);
1170  nsp = gnc_commodity_table_add_namespace(table, name_space, book);
1171  if (priv->name_space == nsp)
1172  return;
1173 
1174  gnc_commodity_begin_edit(cm);
1175  priv->name_space = nsp;
1176  if (nsp->iso4217)
1177  priv->quote_source = gnc_quote_source_lookup_by_internal("currency");
1178  mark_commodity_dirty(cm);
1179  reset_printname(priv);
1180  reset_unique_name(priv);
1181  gnc_commodity_commit_edit(cm);
1182 }
1183 
1184 /********************************************************************
1185  * gnc_commodity_set_fullname
1186  ********************************************************************/
1187 
1188 void
1189 gnc_commodity_set_fullname(gnc_commodity * cm, const char * fullname)
1190 {
1191  gnc_commodityPrivate* priv;
1192 
1193  if (!cm) return;
1194  priv = GET_PRIVATE(cm);
1195  if (priv->fullname == fullname) return;
1196 
1197  CACHE_REMOVE (priv->fullname);
1198  priv->fullname = CACHE_INSERT (fullname);
1199 
1200  gnc_commodity_begin_edit(cm);
1201  mark_commodity_dirty(cm);
1202  reset_printname(priv);
1203  gnc_commodity_commit_edit(cm);
1204 }
1205 
1206 /********************************************************************
1207  * gnc_commodity_set_cusip
1208  ********************************************************************/
1209 
1210 void
1211 gnc_commodity_set_cusip(gnc_commodity * cm,
1212  const char * cusip)
1213 {
1214  gnc_commodityPrivate* priv;
1215 
1216  if (!cm) return;
1217 
1218  priv = GET_PRIVATE(cm);
1219  if (priv->cusip == cusip) return;
1220 
1221  gnc_commodity_begin_edit(cm);
1222  CACHE_REMOVE (priv->cusip);
1223  priv->cusip = CACHE_INSERT (cusip);
1224  mark_commodity_dirty(cm);
1225  gnc_commodity_commit_edit(cm);
1226 }
1227 
1228 /********************************************************************
1229  * gnc_commodity_set_fraction
1230  ********************************************************************/
1231 
1232 void
1233 gnc_commodity_set_fraction(gnc_commodity * cm, int fraction)
1234 {
1235  if (!cm) return;
1236  gnc_commodity_begin_edit(cm);
1237  GET_PRIVATE(cm)->fraction = fraction;
1238  mark_commodity_dirty(cm);
1239  gnc_commodity_commit_edit(cm);
1240 }
1241 
1242 /********************************************************************
1243  * gnc_commodity_set_auto_quote_control_flag
1244  ********************************************************************/
1245 
1246 static void
1247 gnc_commodity_set_auto_quote_control_flag(gnc_commodity *cm,
1248  const gboolean flag)
1249 {
1250  GValue v = G_VALUE_INIT;
1251  ENTER ("(cm=%p, flag=%d)", cm, flag);
1252 
1253  if (!cm)
1254  {
1255  LEAVE("");
1256  return;
1257  }
1258  gnc_commodity_begin_edit(cm);
1259  if (flag)
1260  qof_instance_set_kvp (QOF_INSTANCE (cm), nullptr, 1, "auto_quote_control");
1261  else
1262  {
1263  g_value_init (&v, G_TYPE_STRING);
1264  g_value_set_string (&v, "false");
1265  qof_instance_set_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
1266  }
1267  g_value_unset (&v);
1268  mark_commodity_dirty(cm);
1269  gnc_commodity_commit_edit(cm);
1270  LEAVE("");
1271 }
1272 
1273 /********************************************************************
1274  * gnc_commodity_user_set_quote_flag
1275  ********************************************************************/
1276 
1277 void
1278 gnc_commodity_user_set_quote_flag(gnc_commodity *cm, const gboolean flag)
1279 {
1280  gnc_commodityPrivate* priv;
1281 
1282  ENTER ("(cm=%p, flag=%d)", cm, flag);
1283 
1284  if (!cm)
1285  {
1286  LEAVE("");
1287  return;
1288  }
1289 
1290  priv = GET_PRIVATE(cm);
1291  gnc_commodity_begin_edit(cm);
1292  gnc_commodity_set_quote_flag(cm, flag);
1293  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  gnc_commodity_set_auto_quote_control_flag(cm,
1303  (!flag && (priv->usage_count == 0)) || (flag && (priv->usage_count != 0)));
1304  }
1305  gnc_commodity_commit_edit(cm);
1306  LEAVE("");
1307 }
1308 
1309 /********************************************************************
1310  * gnc_commodity_set_quote_flag
1311  ********************************************************************/
1312 
1313 void
1314 gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
1315 {
1316  ENTER ("(cm=%p, flag=%d)", cm, flag);
1317 
1318  if (!cm) return;
1319  gnc_commodity_begin_edit(cm);
1320  GET_PRIVATE(cm)->quote_flag = flag;
1321  mark_commodity_dirty(cm);
1322  gnc_commodity_commit_edit(cm);
1323  LEAVE(" ");
1324 }
1325 
1326 /********************************************************************
1327  * gnc_commodity_set_quote_source
1328  ********************************************************************/
1329 
1330 void
1331 gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
1332 {
1333  ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->get_internal_name() : "unknown");
1334 
1335  if (!cm) return;
1336  gnc_commodity_begin_edit(cm);
1337  GET_PRIVATE(cm)->quote_source = src;
1338  mark_commodity_dirty(cm);
1339  gnc_commodity_commit_edit(cm);
1340  LEAVE(" ");
1341 }
1342 
1343 /********************************************************************
1344  * gnc_commodity_set_quote_tz
1345  ********************************************************************/
1346 
1347 void
1348 gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz)
1349 {
1350  gnc_commodityPrivate* priv;
1351 
1352  if (!cm) return;
1353 
1354  ENTER ("(cm=%p, tz=%s)", cm, tz ? tz : "(null)");
1355 
1356  priv = GET_PRIVATE(cm);
1357 
1358  if (tz == priv->quote_tz)
1359  {
1360  LEAVE("Already correct TZ");
1361  return;
1362  }
1363 
1364  gnc_commodity_begin_edit(cm);
1365  CACHE_REMOVE (priv->quote_tz);
1366  priv->quote_tz = CACHE_INSERT (tz);
1367  mark_commodity_dirty(cm);
1368  gnc_commodity_commit_edit(cm);
1369  LEAVE(" ");
1370 }
1371 
1372 /********************************************************************
1373  * gnc_commodity_set_user_symbol
1374  ********************************************************************/
1375 
1376 void
1377 gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
1378 {
1379  struct lconv *lc;
1380 
1381  if (!cm) return;
1382 
1383  ENTER ("(cm=%p, symbol=%s)", cm, user_symbol ? user_symbol : "(null)");
1384 
1385  lc = gnc_localeconv();
1386  if (!user_symbol || !*user_symbol)
1387  user_symbol = nullptr;
1388  else if (!g_strcmp0(lc->int_curr_symbol, gnc_commodity_get_mnemonic(cm)) &&
1389  !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  user_symbol = nullptr;
1393  else if (!g_strcmp0(user_symbol, gnc_commodity_get_default_symbol(cm)))
1394  user_symbol = nullptr;
1395 
1396  gnc_commodity_begin_edit (cm);
1397 
1398  if (user_symbol)
1399  {
1400  GValue v = G_VALUE_INIT;
1401  g_value_init (&v, G_TYPE_STRING);
1402  g_value_set_static_string (&v, user_symbol);
1403  qof_instance_set_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
1404  g_value_unset (&v);
1405  }
1406  else
1407  {
1408  qof_instance_set_kvp (QOF_INSTANCE(cm), nullptr, 1, "user_symbol");
1409  }
1410 
1411  mark_commodity_dirty(cm);
1412  gnc_commodity_commit_edit(cm);
1413 
1414  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 gnc_commodity_set_default_symbol(gnc_commodity * cm,
1424  const char * default_symbol)
1425 {
1426  GET_PRIVATE(cm)->default_symbol = default_symbol;
1427 }
1428 
1429 /********************************************************************
1430  * gnc_commodity_increment_usage_count
1431  ********************************************************************/
1432 
1433 void
1435 {
1436  gnc_commodityPrivate* priv;
1437 
1438  ENTER("(cm=%p)", cm);
1439 
1440  if (!cm)
1441  {
1442  LEAVE("");
1443  return;
1444  }
1445 
1446  priv = GET_PRIVATE(cm);
1447 
1448  if ((priv->usage_count == 0) && !priv->quote_flag
1449  && gnc_commodity_get_auto_quote_control_flag(cm)
1450  && 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  gnc_commodity_begin_edit(cm);
1455  gnc_commodity_set_quote_flag(cm, TRUE);
1457  gnc_commodity_get_default_quote_source(cm));
1458  gnc_commodity_commit_edit(cm);
1459  }
1460  priv->usage_count++;
1461  LEAVE("(usage_count=%d)", priv->usage_count);
1462 }
1463 
1464 /********************************************************************
1465  * gnc_commodity_decrement_usage_count
1466  ********************************************************************/
1467 
1468 void
1470 {
1471  gnc_commodityPrivate* priv;
1472 
1473  ENTER("(cm=%p)", cm);
1474 
1475  if (!cm)
1476  {
1477  LEAVE("");
1478  return;
1479  }
1480 
1481  priv = GET_PRIVATE(cm);
1482 
1483  if (priv->usage_count == 0)
1484  {
1485  PWARN("usage_count already zero");
1486  LEAVE("");
1487  return;
1488  }
1489 
1490  priv->usage_count--;
1491  if ((priv->usage_count == 0) && priv->quote_flag
1492  && gnc_commodity_get_auto_quote_control_flag(cm)
1493  && 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  gnc_commodity_set_quote_flag(cm, FALSE);
1498  }
1499  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 gnc_commodity_equiv(const gnc_commodity * a, const gnc_commodity * b)
1513 {
1514  gnc_commodityPrivate* priv_a;
1515  gnc_commodityPrivate* priv_b;
1516 
1517  if (a == b) return TRUE;
1518  if (!a || !b) return FALSE;
1519 
1520  priv_a = GET_PRIVATE(a);
1521  priv_b = GET_PRIVATE(b);
1522  if (priv_a->name_space != priv_b->name_space) return FALSE;
1523  if (g_strcmp0(priv_a->mnemonic, priv_b->mnemonic) != 0) return FALSE;
1524 
1525  return TRUE;
1526 }
1527 
1528 gboolean
1529 gnc_commodity_equal(const gnc_commodity * a, const gnc_commodity * b)
1530 {
1531  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 int gnc_commodity_compare(const gnc_commodity * a, const gnc_commodity * b)
1537 {
1538  if (a == b) return 0;
1539  if (a && !b) return 1;
1540  if (b && !a) return -1;
1541  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 int gnc_commodity_compare_void(const void * a, const void * b)
1547 {
1548  return gnc_commodity_compare(GNC_COMMODITY (a), GNC_COMMODITY (b));
1549 }
1550 
1551 /************************************************************
1552  * Namespace functions *
1553  ************************************************************/
1554 const char *
1555 gnc_commodity_namespace_get_name (const gnc_commodity_namespace *ns)
1556 {
1557  if (ns == nullptr)
1558  return nullptr;
1559  return ns->name;
1560 }
1561 
1562 const char *
1563 gnc_commodity_namespace_get_gui_name (const gnc_commodity_namespace *ns)
1564 {
1565  if (ns == nullptr)
1566  return nullptr;
1567  if (g_strcmp0 (ns->name, GNC_COMMODITY_NS_CURRENCY) == 0)
1568  return GNC_COMMODITY_NS_ISO_GUI;
1569  return ns->name;
1570 }
1571 
1572 GList *
1573 gnc_commodity_namespace_get_commodity_list(const gnc_commodity_namespace *name_space)
1574 {
1575  if (!name_space)
1576  return nullptr;
1577 
1578  return g_list_copy (name_space->cm_list);
1579 }
1580 
1581 gboolean
1582 gnc_commodity_namespace_is_iso(const char *name_space)
1583 {
1584  return ((g_strcmp0(name_space, GNC_COMMODITY_NS_ISO) == 0) ||
1585  (g_strcmp0(name_space, GNC_COMMODITY_NS_CURRENCY) == 0));
1586 }
1587 
1588 static const gchar *
1589 gnc_commodity_table_map_namespace(const char * name_space)
1590 {
1591  if (g_strcmp0(name_space, GNC_COMMODITY_NS_ISO) == 0)
1592  return GNC_COMMODITY_NS_CURRENCY;
1593  return name_space;
1594 }
1595 
1596 /********************************************************************
1597  * gnc_commodity_table_new
1598  * make a new commodity table
1599  ********************************************************************/
1600 
1601 gnc_commodity_table *
1603 {
1604  gnc_commodity_table * retval = g_new0(gnc_commodity_table, 1);
1605  retval->ns_table = g_hash_table_new(&g_str_hash, &g_str_equal);
1606  retval->ns_list = nullptr;
1607  return retval;
1608 }
1609 
1610 /********************************************************************
1611  * book anchor functions
1612  ********************************************************************/
1613 
1614 gnc_commodity_table *
1616 {
1617  if (!book) return nullptr;
1618  return static_cast<gnc_commodity_table*>(qof_book_get_data (book, GNC_COMMODITY_TABLE));
1619 }
1620 
1621 gnc_commodity *
1622 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  if (!from) return nullptr;
1629  comtbl = gnc_commodity_table_get_table (book);
1630  if (!comtbl) return nullptr;
1631 
1632  ucom = gnc_commodity_get_unique_name (from);
1633  twin = gnc_commodity_table_lookup_unique (comtbl, ucom);
1634  if (!twin)
1635  {
1636  twin = gnc_commodity_clone (from, book);
1637  twin = gnc_commodity_table_insert (comtbl, twin);
1638  }
1639  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 count_coms(gpointer key, gpointer value, gpointer user_data)
1649 {
1650  GHashTable *tbl = ((gnc_commodity_namespace*)value)->cm_table;
1651  guint *count = (guint*)user_data;
1652 
1653  if (g_strcmp0((char*)key, GNC_COMMODITY_NS_CURRENCY) == 0)
1654  {
1655  /* don't count default commodities */
1656  return;
1657  }
1658 
1659  if (!value) return;
1660 
1661  *count += g_hash_table_size(tbl);
1662 }
1663 
1664 guint
1665 gnc_commodity_table_get_size(const gnc_commodity_table* tbl)
1666 {
1667  guint count = 0;
1668  g_return_val_if_fail(tbl, 0);
1669  g_return_val_if_fail(tbl->ns_table, 0);
1670 
1671  g_hash_table_foreach(tbl->ns_table, count_coms, (gpointer)&count);
1672 
1673  return count;
1674 }
1675 
1676 /********************************************************************
1677  * gnc_commodity_table_lookup
1678  * locate a commodity by namespace and mnemonic.
1679  ********************************************************************/
1680 
1681 gnc_commodity *
1682 gnc_commodity_table_lookup(const gnc_commodity_table * table,
1683  const char * name_space, const char * mnemonic)
1684 {
1685  gnc_commodity_namespace * nsp = nullptr;
1686 
1687  if (!table || !name_space || !mnemonic) return nullptr;
1688 
1689  nsp = gnc_commodity_table_find_namespace(table, name_space);
1690 
1691  if (nsp)
1692  {
1693  /*
1694  * Backward compatibility support for currencies that have
1695  * recently changed.
1696  */
1697  if (nsp->iso4217)
1698  {
1699  auto it = gnc_new_iso_codes.find (mnemonic);
1700  if (it != gnc_new_iso_codes.end())
1701  mnemonic = it->second.c_str();
1702  }
1703  return GNC_COMMODITY(g_hash_table_lookup(nsp->cm_table, (gpointer)mnemonic));
1704  }
1705  else
1706  {
1707  return nullptr;
1708  }
1709 }
1710 
1711 /********************************************************************
1712  * gnc_commodity_table_lookup
1713  * locate a commodity by unique name.
1714  ********************************************************************/
1715 
1716 gnc_commodity *
1717 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  if (!table || !unique_name) return nullptr;
1725 
1726  name_space = g_strdup (unique_name);
1727  mnemonic = strstr (name_space, "::");
1728  if (!mnemonic)
1729  {
1730  g_free (name_space);
1731  return nullptr;
1732  }
1733 
1734  *mnemonic = '\0';
1735  mnemonic += 2;
1736 
1737  commodity = gnc_commodity_table_lookup (table, name_space, mnemonic);
1738 
1739  g_free (name_space);
1740 
1741  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 gnc_commodity_table_find_full(const gnc_commodity_table * table,
1751  const char * name_space,
1752  const char * fullname)
1753 {
1754  gnc_commodity * retval = nullptr;
1755  GList * all;
1756  GList * iterator;
1757 
1758  if (!fullname || (fullname[0] == '\0'))
1759  return nullptr;
1760 
1761  all = gnc_commodity_table_get_commodities(table, name_space);
1762 
1763  for (iterator = all; iterator; iterator = iterator->next)
1764  {
1765  auto commodity = GNC_COMMODITY (iterator->data);
1766  if (!strcmp(fullname,
1767  gnc_commodity_get_printname(commodity)))
1768  {
1769  retval = commodity;
1770  break;
1771  }
1772  }
1773 
1774  g_list_free (all);
1775 
1776  return retval;
1777 }
1778 
1779 
1780 /********************************************************************
1781  * gnc_commodity_table_insert
1782  * add a commodity to the table.
1783  ********************************************************************/
1784 
1785 gnc_commodity *
1786 gnc_commodity_table_insert(gnc_commodity_table * table,
1787  gnc_commodity * comm)
1788 {
1789  gnc_commodity_namespace * nsp = nullptr;
1790  gnc_commodity *c;
1791  const char *ns_name;
1792  gnc_commodityPrivate* priv;
1793  QofBook *book;
1794 
1795  if (!table) return nullptr;
1796  if (!comm) return nullptr;
1797 
1798  priv = GET_PRIVATE(comm);
1799 
1800  ENTER ("(table=%p, comm=%p) %s %s", table, comm,
1801  (priv->mnemonic == nullptr ? "(null)" : priv->mnemonic),
1802  (priv->fullname == nullptr ? "(null)" : priv->fullname));
1803  ns_name = gnc_commodity_namespace_get_name(priv->name_space);
1804  c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
1805 
1806  if (c)
1807  {
1808  if (c == comm)
1809  {
1810  LEAVE("already in table");
1811  return c;
1812  }
1813 
1814  /* Backward compatibility support for currencies that have
1815  * recently changed. */
1816  if (priv->name_space->iso4217)
1817  {
1818  auto it = gnc_new_iso_codes.find (priv->mnemonic);
1819  if (it != gnc_new_iso_codes.end())
1820  gnc_commodity_set_mnemonic(comm, it->second.c_str());
1821  }
1822  gnc_commodity_copy (c, comm);
1823  gnc_commodity_destroy (comm);
1824  LEAVE("found at %p", c);
1825  return c;
1826  }
1827 
1828  /* Prevent setting anything except template in namespace template. */
1829  if (g_strcmp0 (ns_name, GNC_COMMODITY_NS_TEMPLATE) == 0 &&
1830  g_strcmp0 (priv->mnemonic, "template") != 0)
1831  {
1832  PWARN("Converting commodity %s from namespace template to "
1833  "namespace User", priv->mnemonic);
1834  gnc_commodity_set_namespace (comm, "User");
1835  ns_name = "User";
1836  mark_commodity_dirty (comm);
1837  }
1838 
1839  book = qof_instance_get_book (&comm->inst);
1840  nsp = gnc_commodity_table_add_namespace(table, ns_name, book);
1841 
1842  PINFO ("insert %p %s into nsp=%p %s", priv->mnemonic, priv->mnemonic,
1843  nsp->cm_table, nsp->name);
1844  g_hash_table_insert(nsp->cm_table,
1845  (gpointer)CACHE_INSERT(priv->mnemonic),
1846  (gpointer)comm);
1847  nsp->cm_list = g_list_append(nsp->cm_list, comm);
1848 
1849  qof_event_gen (&comm->inst, QOF_EVENT_ADD, nullptr);
1850  LEAVE ("(table=%p, comm=%p)", table, comm);
1851  return comm;
1852 }
1853 
1854 /********************************************************************
1855  * gnc_commodity_table_remove
1856  * remove a commodity from the table.
1857  ********************************************************************/
1858 
1859 void
1860 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  if (!table) return;
1869  if (!comm) return;
1870 
1871  priv = GET_PRIVATE(comm);
1872  ns_name = gnc_commodity_namespace_get_name(priv->name_space);
1873  c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
1874  if (c != comm) return;
1875 
1876  qof_event_gen (&comm->inst, QOF_EVENT_REMOVE, nullptr);
1877 
1878  nsp = gnc_commodity_table_find_namespace(table, ns_name);
1879  if (!nsp) return;
1880 
1881  nsp->cm_list = g_list_remove(nsp->cm_list, comm);
1882  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 gnc_commodity_table_has_namespace(const gnc_commodity_table * table,
1893  const char * name_space)
1894 {
1895  gnc_commodity_namespace * nsp = nullptr;
1896 
1897  if (!table || !name_space)
1898  {
1899  return 0;
1900  }
1901 
1902  nsp = gnc_commodity_table_find_namespace(table, name_space);
1903  if (nsp)
1904  {
1905  return 1;
1906  }
1907  else
1908  {
1909  return 0;
1910  }
1911 }
1912 
1913 static void
1914 hash_keys_helper(gpointer key, gpointer value, gpointer data)
1915 {
1916  auto l = (GList**)data;
1917  *l = g_list_prepend(*l, key);
1918 }
1919 
1920 static GList *
1921 g_hash_table_keys(GHashTable * table)
1922 {
1923  GList * l = nullptr;
1924  g_hash_table_foreach(table, &hash_keys_helper, (gpointer) &l);
1925  return l;
1926 }
1927 
1928 static void
1929 hash_values_helper(gpointer key, gpointer value, gpointer data)
1930 {
1931  auto l = (GList**)data;
1932  *l = g_list_prepend(*l, value);
1933 }
1934 
1935 static GList *
1936 g_hash_table_values(GHashTable * table)
1937 {
1938  GList * l = nullptr;
1939  g_hash_table_foreach(table, &hash_values_helper, (gpointer) &l);
1940  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 gnc_commodity_table_get_namespaces(const gnc_commodity_table * table)
1950 {
1951  if (!table)
1952  return nullptr;
1953 
1954  return g_hash_table_keys(table->ns_table);
1955 }
1956 
1957 GList *
1959 {
1960  if (!table)
1961  return nullptr;
1962 
1963  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 gnc_commodity_is_iso(const gnc_commodity * cm)
1974 {
1975  gnc_commodityPrivate* priv;
1976 
1977  if (!cm) return FALSE;
1978 
1979  priv = GET_PRIVATE(cm);
1980  if ( !priv->name_space) return FALSE;
1981  return priv->name_space->iso4217;
1982 }
1983 
1984 gboolean
1985 gnc_commodity_is_currency(const gnc_commodity *cm)
1986 {
1987  const char *ns_name;
1988  if (!cm) return FALSE;
1989 
1990  ns_name = gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->name_space);
1991  return (!g_strcmp0(ns_name, GNC_COMMODITY_NS_LEGACY) ||
1992  !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 commodity_table_get_all_noncurrency_commodities(const gnc_commodity_table* table)
2002 {
2003  GList *node = nullptr, *nslist = gnc_commodity_table_get_namespaces(table);
2004  CommodityList *retval = nullptr;
2005  for (node = nslist; node; node=g_list_next(node))
2006  {
2007  gnc_commodity_namespace *ns = nullptr;
2008  if (g_strcmp0((char*)(node->data), GNC_COMMODITY_NS_CURRENCY) == 0
2009  || g_strcmp0((char*)(node->data), GNC_COMMODITY_NS_TEMPLATE) == 0)
2010  continue;
2011  ns = gnc_commodity_table_find_namespace(table, (char*)(node->data));
2012  if (!ns)
2013  continue;
2014  retval = g_list_concat(g_hash_table_values(ns->cm_table), retval);
2015  }
2016  g_list_free(nslist);
2017  return retval;
2018 }
2019 
2020 CommodityList *
2021 gnc_commodity_table_get_commodities(const gnc_commodity_table * table,
2022  const char * name_space)
2023 {
2024  gnc_commodity_namespace * ns = nullptr;
2025 
2026  if (!table)
2027  return nullptr;
2028  if (g_strcmp0(name_space, GNC_COMMODITY_NS_NONISO_GUI) == 0)
2029  return commodity_table_get_all_noncurrency_commodities(table);
2030  ns = gnc_commodity_table_find_namespace(table, name_space);
2031  if (!ns)
2032  return nullptr;
2033 
2034  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 get_quotables_helper1(gpointer key, gpointer value, gpointer data)
2044 {
2045  auto comm = GNC_COMMODITY(value);
2046  gnc_commodityPrivate* priv = GET_PRIVATE(comm);
2047  auto l = static_cast<GList**>(data);
2048 
2049  if (!priv->quote_flag || !priv->quote_source || !priv->quote_source->get_supported())
2050  return;
2051  *l = g_list_prepend(*l, value);
2052 }
2053 
2054 static gboolean
2055 get_quotables_helper2 (gnc_commodity *comm, gpointer data)
2056 {
2057  auto l = static_cast<GList**>(data);
2058  gnc_commodityPrivate* priv = GET_PRIVATE(comm);
2059 
2060  if (!priv->quote_flag || priv->quote_source || !priv->quote_source->get_supported())
2061  return TRUE;
2062  *l = g_list_prepend(*l, comm);
2063  return TRUE;
2064 }
2065 
2066 CommodityList *
2068 {
2069  gnc_commodity_namespace * ns = nullptr;
2070  const char *name_space;
2071  GList * nslist, * tmp;
2072  GList * l = nullptr;
2073  regex_t pattern;
2074  const char *expression = gnc_prefs_get_namespace_regexp();
2075 
2076  ENTER("table=%p, expression=%s", table, expression);
2077  if (!table)
2078  return nullptr;
2079 
2080  if (expression && *expression)
2081  {
2082  if (regcomp(&pattern, expression, REG_EXTENDED | REG_ICASE) != 0)
2083  {
2084  LEAVE("Cannot compile regex");
2085  return nullptr;
2086  }
2087 
2089  for (tmp = nslist; tmp; tmp = tmp->next)
2090  {
2091  name_space = static_cast<const char*>(tmp->data);
2092  if (regexec(&pattern, name_space, 0, nullptr, 0) == 0)
2093  {
2094  DEBUG("Running list of %s commodities", name_space);
2095  ns = gnc_commodity_table_find_namespace(table, name_space);
2096  if (ns)
2097  {
2098  g_hash_table_foreach(ns->cm_table, &get_quotables_helper1, (gpointer) &l);
2099  }
2100  }
2101  }
2102  g_list_free(nslist);
2103  regfree(&pattern);
2104  }
2105  else
2106  {
2107  gnc_commodity_table_foreach_commodity(table, get_quotables_helper2,
2108  (gpointer) &l);
2109  }
2110  LEAVE("list head %p", l);
2111  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 QOF_GOBJECT_IMPL(gnc_commodity_namespace, gnc_commodity_namespace, QOF_TYPE_INSTANCE)
2121 
2122 static void
2123 gnc_commodity_namespace_init(gnc_commodity_namespace* ns)
2124 {
2125 }
2126 
2127 static void
2128 gnc_commodity_namespace_dispose_real (GObject *nsp)
2129 {
2130 }
2131 
2132 static void
2133 gnc_commodity_namespace_finalize_real(GObject* nsp)
2134 {
2135 }
2136 
2137 gnc_commodity_namespace *
2139  const char * name_space,
2140  QofBook *book)
2141 {
2142  gnc_commodity_namespace * ns = nullptr;
2143 
2144  if (!table) return nullptr;
2145 
2146  name_space = gnc_commodity_table_map_namespace(name_space);
2147  ns = gnc_commodity_table_find_namespace(table, name_space);
2148  if (!ns)
2149  {
2150  ns = static_cast<gnc_commodity_namespace*>(g_object_new(GNC_TYPE_COMMODITY_NAMESPACE, nullptr));
2151  ns->cm_table = g_hash_table_new(g_str_hash, g_str_equal);
2152  ns->name = CACHE_INSERT(static_cast<const char*>(name_space));
2153  ns->iso4217 = gnc_commodity_namespace_is_iso(name_space);
2154  qof_instance_init_data (&ns->inst, GNC_ID_COMMODITY_NAMESPACE, book);
2155  qof_event_gen (&ns->inst, QOF_EVENT_CREATE, nullptr);
2156 
2157  g_hash_table_insert(table->ns_table,
2158  (gpointer) ns->name,
2159  (gpointer) ns);
2160  table->ns_list = g_list_append(table->ns_list, ns);
2161  qof_event_gen (&ns->inst, QOF_EVENT_ADD, nullptr);
2162  }
2163  return ns;
2164 }
2165 
2166 
2167 gnc_commodity_namespace *
2168 gnc_commodity_table_find_namespace(const gnc_commodity_table * table,
2169  const char * name_space)
2170 {
2171  if (!table || !name_space)
2172  return nullptr;
2173 
2174  name_space = gnc_commodity_table_map_namespace(name_space);
2175  return static_cast<gnc_commodity_namespace*>(g_hash_table_lookup(table->ns_table, (gpointer)name_space));
2176 }
2177 
2178 
2179 gnc_commodity *
2180 gnc_commodity_find_commodity_by_guid(const GncGUID *guid, QofBook *book)
2181 {
2182  QofCollection *col;
2183  if (!guid || !book) return nullptr;
2184  col = qof_book_get_collection (book, GNC_ID_COMMODITY);
2185  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 ns_helper(gpointer key, gpointer value, gpointer user_data)
2195 {
2196  auto c = GNC_COMMODITY(value);
2198  CACHE_REMOVE(static_cast<char*>(key)); /* key is commodity mnemonic */
2199  return TRUE;
2200 }
2201 
2202 void
2204  const char * name_space)
2205 {
2206  gnc_commodity_namespace * ns;
2207 
2208  if (!table) return;
2209 
2210  ns = gnc_commodity_table_find_namespace(table, name_space);
2211  if (!ns)
2212  return;
2213 
2214  qof_event_gen (&ns->inst, QOF_EVENT_REMOVE, nullptr);
2215  g_hash_table_remove(table->ns_table, name_space);
2216  table->ns_list = g_list_remove(table->ns_list, ns);
2217 
2218  g_list_free(ns->cm_list);
2219  ns->cm_list = nullptr;
2220 
2221  g_hash_table_foreach_remove(ns->cm_table, ns_helper, nullptr);
2222  g_hash_table_destroy(ns->cm_table);
2223  CACHE_REMOVE(ns->name);
2224 
2225  qof_event_gen (&ns->inst, QOF_EVENT_DESTROY, nullptr);
2226  /* qof_instance_release(&ns->inst); */
2227  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 iter_commodity (gpointer key, gpointer value, gpointer user_data)
2245 {
2246  IterData *iter_data = (IterData *) user_data;
2247  gnc_commodity *cm = (gnc_commodity *) value;
2248 
2249  if (iter_data->ok)
2250  {
2251  iter_data->ok = (iter_data->func)(cm, iter_data->user_data);
2252  }
2253 }
2254 
2255 static void
2256 iter_namespace (gpointer key, gpointer value, gpointer user_data)
2257 {
2258  GHashTable *namespace_hash = ((gnc_commodity_namespace *) value)->cm_table;
2259  g_hash_table_foreach (namespace_hash, iter_commodity, user_data);
2260 }
2261 
2262 gboolean
2263 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  if (!tbl || !f) return FALSE;
2270 
2271  iter_data.ok = TRUE;
2272  iter_data.func = f;
2273  iter_data.user_data = user_data;
2274 
2275  g_hash_table_foreach(tbl->ns_table, iter_namespace, (gpointer)&iter_data);
2276 
2277  return iter_data.ok;
2278 }
2279 
2280 /********************************************************************
2281  * gnc_commodity_table_destroy
2282  * cleanup and free.
2283  ********************************************************************/
2284 
2285 void
2286 gnc_commodity_table_destroy(gnc_commodity_table * t)
2287 {
2288  gnc_commodity_namespace * ns;
2289  GList *item, *next;
2290 
2291  if (!t) return;
2292  ENTER ("table=%p", t);
2293 
2294  for (item = t->ns_list; item; item = next)
2295  {
2296  next = g_list_next(item);
2297  ns = static_cast<gnc_commodity_namespace*>(item->data);
2299  }
2300 
2301  g_list_free(t->ns_list);
2302  t->ns_list = nullptr;
2303  g_hash_table_destroy(t->ns_table);
2304  t->ns_table = nullptr;
2305  LEAVE ("table=%p", t);
2306  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 gnc_commodity_table_add_default_data(gnc_commodity_table *table, QofBook *book)
2319 {
2320  QofCollection *col;
2321  gnc_commodity* c;
2322 
2323  ENTER ("table=%p", table);
2324  gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_TEMPLATE, book);
2325  c = gnc_commodity_new(book, "template", GNC_COMMODITY_NS_TEMPLATE, "template", "template", 1);
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  col = qof_book_get_collection(book, GNC_ID_COMMODITY);
2335  col = qof_book_get_collection(book, GNC_ID_COMMODITY_NAMESPACE);
2337 
2338  LEAVE ("table=%p", table);
2339  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 commodity_table_book_begin (QofBook *book)
2383 {
2384  gnc_commodity_table *ct;
2385  ENTER ("book=%p", book);
2386 
2388  return;
2389 
2390  ct = gnc_commodity_table_new ();
2391  qof_book_set_data (book, GNC_COMMODITY_TABLE, ct);
2392 
2393  if (!gnc_commodity_table_add_default_data(ct, book))
2394  {
2395  PWARN("unable to initialize book's commodity_table");
2396  }
2397 
2398  LEAVE ("book=%p", book);
2399 }
2400 
2401 static void
2402 commodity_table_book_end (QofBook *book)
2403 {
2404  gnc_commodity_table *ct;
2405 
2406  ct = gnc_commodity_table_get_table (book);
2407  qof_book_set_data (book, GNC_COMMODITY_TABLE, nullptr);
2408  gnc_commodity_table_destroy (ct);
2409 }
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
2428 {
2429  if (!qof_object_register (&commodity_object_def))
2430  return FALSE;
2431  if (!qof_object_register (&namespace_object_def))
2432  return FALSE;
2433  return qof_object_register (&commodity_table_object_def);
2434 }
2435 
2436 /* *******************************************************************
2437 * gnc_monetary methods
2438 ********************************************************************/
2439 
2441 MonetaryList *
2442 gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
2443 {
2444  MonetaryList *l = list, *tmp;
2445  for (tmp = list; tmp; tmp = tmp->next)
2446  {
2447  auto list_mon = static_cast<gnc_monetary*>(tmp->data);
2448  if (gnc_commodity_equiv(list_mon->commodity, add_mon.commodity))
2449  {
2450  list_mon->value = gnc_numeric_add(list_mon->value, add_mon.value,
2452  break;
2453  }
2454  }
2455 
2456  /* See if we found an entry, and add one if not */
2457  if (tmp == nullptr)
2458  {
2459  auto new_mon = static_cast<gnc_monetary*>(g_new0(gnc_monetary, 1));
2460  *new_mon = add_mon;
2461  l = g_list_prepend(l, new_mon);
2462  }
2463 
2464  return l;
2465 }
2466 
2469 MonetaryList *
2471 {
2472  MonetaryList *node, *next;
2473  for (node = list; node; node = next)
2474  {
2475  auto mon = static_cast<gnc_monetary*>(node->data);
2476  next = node->next;
2477  if (gnc_numeric_zero_p(mon->value))
2478  {
2479  g_free(mon);
2480  list = g_list_delete_link(list, node);
2481  }
2482  }
2483  return list;
2484 }
2485 
2487 void
2488 gnc_monetary_list_free(MonetaryList *list)
2489 {
2490  MonetaryList *tmp;
2491  for (tmp = list; tmp; tmp = tmp->next)
2492  {
2493  g_free(tmp->data);
2494  }
2495 
2496  g_list_free(list);
2497 }
2498 
2499 /* ========================= END OF FILE ============================== */
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
Add a new commodity to the commodity table.
const char * gnc_commodity_get_cusip(const gnc_commodity *cm)
Retrieve the &#39;exchange code&#39; for the specified commodity.
gboolean gnc_commodity_table_foreach_commodity(const gnc_commodity_table *table, gboolean(*f)(gnc_commodity *cm, gpointer user_data), gpointer user_data)
Call a function once for each commodity in the commodity table.
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
A gnc_commodity_table is a database of commodity info.
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency or a legacy currency...
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
gboolean gnc_commodity_table_add_default_data(gnc_commodity_table *table, QofBook *book)
Add all the standard namespaces and currencies to the commodity table.
const char * gnc_quote_source_get_user_name(const gnc_quote_source *source)
Given a gnc_quote_source data structure, return the user friendly name of this quote source...
void qof_instance_set_kvp(QofInstance *, GValue const *value, unsigned count,...)
Sets a KVP slot to a value from a GValue.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
#define GNC_COMMODITY_MAX_FRACTION
Max fraction is 10^9 because 10^10 would require changing it to an int64_t.
This quote source pulls from a single specific web site.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:255
gnc_quote_source * gnc_quote_source_add_new(const char *source_name, gboolean supported)
Create a new quote source.
const char * gnc_commodity_namespace_get_gui_name(const gnc_commodity_namespace *ns)
Return the textual name of a namespace data structure in a form suitable to present to the user...
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:212
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
gboolean gnc_commodity_get_quote_flag(const gnc_commodity *cm)
Retrieve the automatic price quote flag for the specified commodity.
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
const char * gnc_commodity_get_user_symbol(const gnc_commodity *cm)
Retrieve the user-defined symbol for the specified commodity.
void gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz)
Set the automatic price quote timezone for the specified commodity.
void gnc_commodity_decrement_usage_count(gnc_commodity *cm)
Decrement a commodity&#39;s internal counter that tracks how many accounts are using that commodity...
Commodity handling public routines (C++ api)
const char * gnc_commodity_get_quote_tz(const gnc_commodity *cm)
Retrieve the automatic price quote timezone for the specified commodity.
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
void gnc_commodity_set_fraction(gnc_commodity *cm, int fraction)
Set the fraction for the specified commodity.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
gboolean gnc_quote_source_get_supported(const gnc_quote_source *source)
Given a gnc_quote_source data structure, return the flag that indicates whether this particular quote...
globally unique ID User API
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
QuoteSourceType gnc_quote_source_get_type(const gnc_quote_source *source)
Given a gnc_quote_source data structure, return the type of this particular quote source...
The special currency quote source.
int gnc_commodity_compare_void(const void *a, const void *b)
A wrapper around gnc_commodity_compare() which offers the function declaration that is needed for g_l...
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Object instance holds common fields that most gnucash objects use.
gnc_commodity * gnc_commodity_clone(const gnc_commodity *src, QofBook *dest_book)
allocate and copy
This is a locally installed quote source that gnucash knows nothing about.
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
Retrieve the namespace for the specified commodity.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:188
A gnc_commodity_namespace is an collection of commodities.
void gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
Set the automatic price quote flag for the specified commodity.
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:63
QuoteSourceType
The quote source type enum account types are used to determine how the transaction data in the accoun...
gnc_quote_source * gnc_quote_source_lookup_by_ti(QuoteSourceType type, gint index)
Given the type/index of a quote source, find the data structure identified by this pair...
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void gnc_commodity_user_set_quote_flag(gnc_commodity *cm, const gboolean flag)
Set the automatic price quote flag for the specified commodity, based on user input.
gnc_commodity_namespace * gnc_commodity_table_add_namespace(gnc_commodity_table *table, const char *name_space, QofBook *book)
This function adds a new string to the list of commodity namespaces.
GList * gnc_commodity_namespace_get_commodity_list(const gnc_commodity_namespace *name_space)
Return a list of all commodity data structures in the specified namespace.
void qof_instance_get_kvp(QofInstance *, GValue *value, unsigned count,...)
Retrieves the contents of a KVP slot into a provided GValue.
void gnc_commodity_set_user_symbol(gnc_commodity *cm, const char *user_symbol)
Set a user-defined symbol for the specified commodity.
const char * gnc_commodity_namespace_get_name(const gnc_commodity_namespace *ns)
Return the textual name of a namespace data structure.
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
MonetaryList * gnc_monetary_list_delete_zeros(MonetaryList *list)
Delete all entries in the list that have zero value.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
void gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
Set the automatic price quote source for the specified commodity.
gint gnc_quote_source_num_entries(QuoteSourceType type)
Return the number of entries for a given type of quote source.
GList * gnc_commodity_table_get_namespaces(const gnc_commodity_table *table)
Return a list of all namespaces in the commodity table.
gboolean gnc_commodity_table_register(void)
You should probably not be using gnc_commodity_table_register() It is an internal routine for registe...
void gnc_commodity_increment_usage_count(gnc_commodity *cm)
Increment a commodity&#39;s internal counter that tracks how many accounts are using that commodity...
void gnc_commodity_set_cusip(gnc_commodity *cm, const char *cusip)
Set the &#39;exchange code&#39; for the specified commodity.
void gnc_monetary_list_free(MonetaryList *list)
Free a MonetaryList and all the monetaries it points to.
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
Create a new commodity.
int gnc_commodity_table_has_namespace(const gnc_commodity_table *table, const char *name_space)
Test to see if the indicated namespace exits in the commodity table.
void gnc_commodity_table_delete_namespace(gnc_commodity_table *table, const char *name_space)
This function deletes a string from the list of commodity namespaces.
gboolean gnc_commodity_namespace_is_iso(const char *name_space)
Checks to see if the specified commodity namespace is the namespace for ISO 4217 currencies.
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
Retrieve the full name for the specified commodity.
#define GNC_COMMODITY_NS_LEGACY
The commodity namespace definitions are used to tag a commodity by its type, or a stocks by the excha...
void qof_book_set_data(QofBook *book, const gchar *key, gpointer data)
The qof_book_set_data() allows arbitrary pointers to structs to be stored in QofBook.
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
const char * gnc_commodity_get_nice_symbol(const gnc_commodity *cm)
Retrieve a symbol for the specified commodity, suitable for display to the user.
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:261
void gnc_quote_source_set_fq_installed(const char *version_string, const std::vector< std::string > &sources_list)
Update gnucash internal tables based on what Finance::Quote sources are installed.
const char * gnc_quote_source_fq_version(void)
This function returns the version of the Finance::Quote module installed on a user&#39;s computer...
Generic api to store and retrieve preferences.
CommodityList * gnc_commodity_table_get_commodities(const gnc_commodity_table *table, const char *name_space)
Return a list of all commodities in the commodity table that are in the given namespace.
gnc_quote_source * gnc_quote_source_lookup_by_internal(const char *name)
Given the internal (gnucash or F::Q) name of a quote source, find the data structure identified by th...
const char * gnc_commodity_get_printname(const gnc_commodity *cm)
Retrieve the &#39;print&#39; name for the specified commodity.
int gnc_commodity_compare(const gnc_commodity *a, const gnc_commodity *b)
This routine returns 0 if the two commodities are equal, 1 otherwise.
void gnc_commodity_set_fullname(gnc_commodity *cm, const char *fullname)
Set the full name for the specified commodity.
This quote source may pull from multiple web sites.
gnc_quote_source * gnc_commodity_get_quote_source(const gnc_commodity *cm)
Retrieve the automatic price quote source for the specified commodity.
gnc_commodity_namespace * gnc_commodity_table_find_namespace(const gnc_commodity_table *table, const char *name_space)
This function finds a commodity namespace in the set of existing commodity namespaces.
void gnc_commodity_set_mnemonic(gnc_commodity *cm, const char *mnemonic)
Set the mnemonic for the specified commodity.
const char * gnc_commodity_get_default_symbol(const gnc_commodity *cm)
Retrieve the default symbol for the specified commodity.
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
CommodityList * gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table *table)
This function returns a list of commodities for which price quotes should be retrieved.
gnc_commodity_table * gnc_commodity_table_new(void)
You probably shouldn&#39;t be using gnc_commodity_table_new() directly, it&#39;s for internal use only...
gint gnc_quote_source_get_index(const gnc_quote_source *source)
Given a gnc_quote_source data structure, return the index of this particular quote source within its ...
gnc_commodity_namespace * gnc_commodity_get_namespace_ds(const gnc_commodity *cm)
Retrieve the namespace data structure for the specified commodity.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
Retrieve the &#39;unique&#39; name for the specified commodity.
MonetaryList * gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
Add a gnc_monetary to the list.
void gnc_commodity_table_remove(gnc_commodity_table *table, gnc_commodity *comm)
Remove a commodity from the commodity table.
void gnc_commodity_set_namespace(gnc_commodity *cm, const char *name_space)
Set the namespace for the specified commodity.
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition: qofbook.cpp:521
guint gnc_commodity_table_get_size(const gnc_commodity_table *tbl)
Returns the number of commodities in the commodity table.
const char * gnc_quote_source_get_internal_name(const gnc_quote_source *source)
Given a gnc_quote_source data structure, return the internal name of this quote source.
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:299
An article that is bought and sold.
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
The type used to store guids in C.
Definition: guid.h:75
void gnc_commodity_copy(gnc_commodity *dest, const gnc_commodity *src)
Copy src into dest.
gpointer qof_book_get_data(const QofBook *book, const gchar *key)
Retrieves arbitrary pointers to structs stored by qof_book_set_data.
GList * gnc_commodity_table_get_namespaces_list(const gnc_commodity_table *table)
Return a list of all namespace data structures in the commodity table.
gnc_commodity * gnc_commodity_obtain_twin(const gnc_commodity *from, QofBook *book)
Given the commodity &#39;findlike&#39;, this routine will find and return the equivalent commodity (commodity...
Commodity handling public routines.
void gnc_commodity_destroy(gnc_commodity *cm)
Destroy a commodity.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency.
gboolean gnc_quote_source_fq_installed(void)
This function indicates whether or not the Finance::Quote module is installed on a user&#39;s computer...