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