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