mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
This commit tries to do the minimum necessary to move the guile bits from engine to bindings/guile. As engine is a very central piece in the software, this unfortunately still touches many other source files: - A few helper objects have been squashed together: * engine-helpers-guile.[ch] (of which the c part is extracted from engine-helpers.c) * gncBusGuile.[ch] * gnc-hooks-scm.[ch] - The initialization function of gncmod-engine no longer initializes the scm bits. Any scm code that wants to interact with the engine code now has to load the (gnucash engine) scm module, or sometimes (gnucash business-core). The bulk of changes in this commit actually is updating all the scm consumers to do so. - scm-scm target has been removed. Instead (gnucash utilities) is part of scm-engine. A few dependency graphs have been updated for this. More refinements will be in followup commits.
2660 lines
82 KiB
C
2660 lines
82 KiB
C
/********************************************************************
|
|
* gnc-commodity.c -- api for tradable commodities (incl. currency) *
|
|
* Copyright (C) 2000 Bill Gribble *
|
|
* Copyright (C) 2001,2003 Linas Vepstas <linas@linas.org> *
|
|
* Copyright (c) 2006 David Hampton <hampton@employees.org> *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of *
|
|
* the License, or (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License*
|
|
* along with this program; if not, contact: *
|
|
* *
|
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
|
* *
|
|
*******************************************************************/
|
|
|
|
#include <config.h>
|
|
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <regex.h>
|
|
#include <qofinstance-p.h>
|
|
|
|
#include "gnc-commodity.h"
|
|
#include "gnc-locale-utils.h"
|
|
#include "gnc-prefs.h"
|
|
|
|
static QofLogModule log_module = GNC_MOD_COMMODITY;
|
|
|
|
/* Parts per unit is nominal, i.e. number of 'partname' units in
|
|
* a 'unitname' unit. fraction is transactional, i.e. how many
|
|
* of the smallest-transactional-units of the currency are there
|
|
* in a 'unitname' unit. */
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_NAMESPACE, /* Table */
|
|
PROP_FULL_NAME, /* Table */
|
|
PROP_MNEMONIC, /* Table */
|
|
PROP_PRINTNAME, /* Constructed */
|
|
PROP_CUSIP, /* Table */
|
|
PROP_FRACTION, /* Table */
|
|
PROP_UNIQUE_NAME, /* Constructed */
|
|
PROP_QUOTE_FLAG, /* Table */
|
|
PROP_QUOTE_SOURCE, /* Table */
|
|
PROP_QUOTE_TZ, /* Table */
|
|
};
|
|
|
|
struct gnc_commodity_s
|
|
{
|
|
QofInstance inst;
|
|
};
|
|
|
|
typedef struct gnc_commodityPrivate
|
|
{
|
|
gnc_commodity_namespace *name_space;
|
|
|
|
char * fullname;
|
|
char * mnemonic;
|
|
char * printname;
|
|
char * cusip; /* CUSIP or other identifying code */
|
|
int fraction;
|
|
char * unique_name;
|
|
|
|
gboolean quote_flag; /* user wants price quotes */
|
|
gnc_quote_source * quote_source; /* current/old source of quotes */
|
|
char * quote_tz;
|
|
|
|
/* the number of accounts using this commodity - this field is not
|
|
* persisted */
|
|
int usage_count;
|
|
|
|
/* the default display_symbol, set in iso-4217-currencies at start-up */
|
|
const char * default_symbol;
|
|
} gnc_commodityPrivate;
|
|
|
|
#define GET_PRIVATE(o) \
|
|
((gnc_commodityPrivate*)g_type_instance_get_private((GTypeInstance*)o, GNC_TYPE_COMMODITY))
|
|
|
|
struct _GncCommodityClass
|
|
{
|
|
QofInstanceClass parent_class;
|
|
};
|
|
|
|
static void commodity_free(gnc_commodity * cm);
|
|
static void gnc_commodity_set_default_symbol(gnc_commodity *, const char *);
|
|
|
|
struct gnc_commodity_namespace_s
|
|
{
|
|
QofInstance inst;
|
|
|
|
gchar * name;
|
|
gboolean iso4217;
|
|
GHashTable * cm_table;
|
|
GList * cm_list;
|
|
};
|
|
|
|
struct _GncCommodityNamespaceClass
|
|
{
|
|
QofInstanceClass parent_class;
|
|
};
|
|
|
|
struct gnc_commodity_table_s
|
|
{
|
|
GHashTable * ns_table;
|
|
GList * ns_list;
|
|
};
|
|
|
|
struct gnc_new_iso_code
|
|
{
|
|
const char *old_code;
|
|
const char *new_code;
|
|
} gnc_new_iso_codes[] =
|
|
{
|
|
{"RUR", "RUB"}, /* Russian Ruble: RUR through 1997-12, RUB from 1998-01 onwards; see bug #393185 */
|
|
{"PLZ", "PLN"}, /* Polish Zloty */
|
|
{"UAG", "UAH"}, /* Ukraine Hryvnia */
|
|
{"NIS", "ILS"}, /* New Israeli Shekel: The informal abbreviation may be "NIS", but
|
|
its iso-4217 is clearly ILS and only this! Incorrectly changed
|
|
due to bug#152755 (Nov 2004) and changed back again by bug#492417
|
|
(Oct 2008). */
|
|
{"MXP", "MXN"}, /* Mexican (Nuevo) Peso */
|
|
{"TRL", "TRY"}, /* New Turkish Lira: changed 2005 */
|
|
|
|
/* Only add currencies to this table when the old currency no longer
|
|
* exists in the file iso-4217-currencies.xml */
|
|
};
|
|
#define GNC_NEW_ISO_CODES \
|
|
(sizeof(gnc_new_iso_codes) / sizeof(struct gnc_new_iso_code))
|
|
|
|
static char *fq_version = NULL;
|
|
|
|
struct gnc_quote_source_s
|
|
{
|
|
gboolean supported;
|
|
QuoteSourceType type;
|
|
gint index;
|
|
char *user_name; /* User friendly name incl. region code*/
|
|
char *old_internal_name; /* Name used internally (deprecated) */
|
|
char *internal_name; /* Name used internally and by finance::quote. */
|
|
};
|
|
|
|
/* To update the following lists scan
|
|
* from github.com/finance-quote/finance-quote
|
|
* in lib/Finance/Quote/ all *.pm for "methods"
|
|
* because many of them have more than one -
|
|
* ideally after each release of them.
|
|
*
|
|
* Apply changes here also to the FQ appendix of help.
|
|
*/
|
|
static gnc_quote_source currency_quote_source =
|
|
{ TRUE, 0, 0, "Currency", "CURRENCY", "currency" };
|
|
|
|
/* The single quote method is usually the module name, but
|
|
* sometimes it get's the suffix "_direct"
|
|
* and the failover method is without suffix.
|
|
*/
|
|
static gnc_quote_source single_quote_sources[] =
|
|
{
|
|
{ FALSE, 0, 0, "Alphavantage, US", "ALPHAVANTAGE", "alphavantage" },
|
|
{ FALSE, 0, 0, "Amsterdam Euronext eXchange, NL", "AEX", "aex" },
|
|
{ FALSE, 0, 0, "American International Assurance, HK", "AIAHK", "aiahk" },
|
|
{ FALSE, 0, 0, "Association of Mutual Funds in India", "AMFIINDIA", "amfiindia" },
|
|
{ FALSE, 0, 0, "Athens Stock Exchange, GR", "ASEGR", "asegr" },
|
|
{ FALSE, 0, 0, "Australian Stock Exchange, AU", "ASX", "asx" },
|
|
{ FALSE, 0, 0, "BAMOSZ funds, HU", "BAMOSZ", "bamosz" },
|
|
{ FALSE, 0, 0, "BMO NesbittBurns, CA", "BMONESBITTBURNS", "bmonesbittburns" },
|
|
{ FALSE, 0, 0, "Bucharest Stock Exchange, RO", "BSERO", "bsero" },
|
|
{ FALSE, 0, 0, "Budapest Stock Exchange (BET), ex-BUX, HU", "BSE", "bse" },
|
|
{ FALSE, 0, 0, "Canada Mutual", "CANADAMUTUAL", "canadamutual" },
|
|
{ FALSE, 0, 0, "Citywire Funds, GB", "citywire", "citywire" },
|
|
{ FALSE, 0, 0, "Colombo Stock Exchange, LK", "CSE", "cse" },
|
|
{ FALSE, 0, 0, "Cominvest, ex-Adig, DE", "COMINVEST", "cominvest" },
|
|
{ FALSE, 0, 0, "Deka Investments, DE", "DEKA", "deka" },
|
|
{ FALSE, 0, 0, "Dutch", "DUTCH", "dutch" },
|
|
{ FALSE, 0, 0, "DWS, DE", "DWS", "dwsfunds" },
|
|
{ FALSE, 0, 0, "Equinox Unit Trusts, ZA", "ZA_unittrusts", "za_unittrusts" },
|
|
{ FALSE, 0, 0, "Fidelity Direct", "FIDELITY_DIRECT", "fidelity_direct" },
|
|
{ FALSE, 0, 0, "Fidelity Fixed", "FIDELITY_DIRECT", "fidelityfixed" },
|
|
{ FALSE, 0, 0, "Finance Canada", "FINANCECANADA", "financecanada" },
|
|
{ FALSE, 0, 0, "Financial Times Funds service, GB", "FTFUNDS", "ftfunds" },
|
|
{ FALSE, 0, 0, "Finanzpartner, DE", "FINANZPARTNER", "finanzpartner" },
|
|
{ FALSE, 0, 0, "First Trust Portfolios, US", "FTPORTFOLIOS", "ftportfolios" },
|
|
{ FALSE, 0, 0, "Fund Library, CA", "FUNDLIBRARY", "fundlibrary" },
|
|
{ FALSE, 0, 0, "GoldMoney spot rates, JE", "GOLDMONEY", "goldmoney" },
|
|
{ FALSE, 0, 0, "Greece", "GREECE", "greece" },
|
|
{ FALSE, 0, 0, "Helsinki stock eXchange, FI", "HEX", "hex" },
|
|
{ FALSE, 0, 0, "Hungary", "HU", "hu" },
|
|
{ FALSE, 0, 0, "India Mutual", "INDIAMUTUAL", "indiamutual" },
|
|
{ FALSE, 0, 0, "Man Investments, AU", "maninv", "maninv" },
|
|
{ FALSE, 0, 0, "Morningstar, GB", "MSTARUK", "mstaruk" },
|
|
{ FALSE, 0, 0, "Morningstar, JP", "MORNINGSTARJP", "morningstarjp" },
|
|
{ FALSE, 0, 0, "Morningstar, SE", "MORNINGSTAR", "morningstar" },
|
|
{ FALSE, 0, 0, "Motley Fool, US", "FOOL", "fool" },
|
|
{ FALSE, 0, 0, "New Zealand stock eXchange, NZ", "NZX", "nzx" },
|
|
{ FALSE, 0, 0, "Paris Stock Exchange/Boursorama, FR", "BOURSO", "bourso" },
|
|
{ FALSE, 0, 0, "Paris Stock Exchange/LeRevenu, FR", "LEREVENU", "lerevenu" },
|
|
{ FALSE, 0, 0, "Platinum Asset Management, AU", "PLATINUM", "platinum" },
|
|
{ FALSE, 0, 0, "Romania", "romania", "romania" },
|
|
{ FALSE, 0, 0, "SIX Swiss Exchange funds, CH", "SIXFUNDS", "sixfunds" },
|
|
{ FALSE, 0, 0, "SIX Swiss Exchange shares, CH", "SIXSHARES", "sixshares" },
|
|
{ FALSE, 0, 0, "Skandinaviska Enskilda Banken, SE", "SEB_FUNDS", "seb_funds" },
|
|
{ FALSE, 0, 0, "Sharenet, ZA", "ZA", "za" },
|
|
{ FALSE, 0, 0, "StockHouse Canada", "STOCKHOUSE_FUND", "stockhousecanada_fund" },
|
|
{ FALSE, 0, 0, "TD Waterhouse Funds, CA", "TDWATERHOUSE", "tdwaterhouse" },
|
|
{ FALSE, 0, 0, "TD Efunds, CA", "TDEFUNDS", "tdefunds" },
|
|
{ FALSE, 0, 0, "TIAA-CREF, US", "TIAACREF", "tiaacref" },
|
|
{ FALSE, 0, 0, "Toronto Stock eXchange, CA", "TSX", "tsx" },
|
|
{ FALSE, 0, 0, "T. Rowe Price", "TRPRICE", "troweprice" },
|
|
{ FALSE, 0, 0, "T. Rowe Price, US", "TRPRICE_DIRECT", "troweprice_direct" },
|
|
{ FALSE, 0, 0, "Trustnet via tnetuk.pm, GB", "TNETUK", "tnetuk" },
|
|
{ FALSE, 0, 0, "Trustnet via trustnet.pm, GB", "TRUSTNET", "trustnet" },
|
|
{ FALSE, 0, 0, "U.K. Unit Trusts", "UKUNITTRUSTS", "uk_unit_trusts" },
|
|
{ FALSE, 0, 0, "Union Investment, DE", "UNIONFUNDS", "unionfunds" },
|
|
{ FALSE, 0, 0, "US Treasury Bonds", "usfedbonds", "usfedbonds" },
|
|
{ FALSE, 0, 0, "US Govt. Thrift Savings Plan", "TSP", "tsp" },
|
|
{ FALSE, 0, 0, "Vanguard", "VANGUARD", "vanguard" }, /* Method of Alphavantage */
|
|
{ FALSE, 0, 0, "VWD, DE (unmaintained)", "VWD", "vwd" },
|
|
{ FALSE, 0, 0, "Yahoo as JSON", "YAHOO_JSON", "yahoo_json" },
|
|
{ FALSE, 0, 0, "Yahoo as YQL", "YAHOO_YQL", "yahoo_yql" },
|
|
};
|
|
|
|
static gnc_quote_source multiple_quote_sources[] =
|
|
{
|
|
{ FALSE, 0, 0, "Australia (ASX, ...)", "AUSTRALIA", "australia" },
|
|
{ FALSE, 0, 0, "Canada (Alphavantage, TSX, ...)", "CANADA", "canada" },
|
|
{ FALSE, 0, 0, "Canada Mutual (Fund Library, StockHouse, ...)", "CANADAMUTUAL", "canadamutual" },
|
|
{ FALSE, 0, 0, "Dutch (AEX, ...)", "DUTCH", "dutch" },
|
|
{ FALSE, 0, 0, "Europe (asegr,.bsero, hex ...)", "EUROPE", "europe" },
|
|
{ FALSE, 0, 0, "Greece (ASE, ...)", "GREECE", "greece" },
|
|
{ FALSE, 0, 0, "Hungary (Bamosz, BET, ...)", "HU", "hu" },
|
|
{ FALSE, 0, 0, "India Mutual (AMFI, ...)", "INDIAMUTUAL", "indiamutual" },
|
|
{ FALSE, 0, 0, "Fidelity (Fidelity, ...)", "FIDELITY", "fidelity" },
|
|
{ FALSE, 0, 0, "Finland (HEX, ...)", "FINLAND", "finland" },
|
|
{ FALSE, 0, 0, "First Trust (First Trust, ...)", "FTPORTFOLIOS", "ftportfolios" },
|
|
{ FALSE, 0, 0, "France (bourso, ĺerevenu, ...)", "FRANCE", "france" },
|
|
{ FALSE, 0, 0, "Nasdaq (alphavantage, fool, ...)", "NASDAQ", "nasdaq" },
|
|
{ FALSE, 0, 0, "New Zealand (NZX, ...)", "NZ", "nz" },
|
|
{ FALSE, 0, 0, "NYSE (alphavantage, fool, ...)", "NYSE", "nyse" },
|
|
{ FALSE, 0, 0, "South Africa (Sharenet, ...)", "ZA", "za" },
|
|
{ FALSE, 0, 0, "Romania (BSE-RO, ...)", "romania", "romania" },
|
|
{ FALSE, 0, 0, "T. Rowe Price", "TRPRICE", "troweprice" },
|
|
{ FALSE, 0, 0, "U.K. Funds (citywire, FTfunds, MStar, tnetuk, ...)", "ukfunds", "ukfunds" },
|
|
{ FALSE, 0, 0, "U.K. Unit Trusts (trustnet, ...)", "UKUNITTRUSTS", "uk_unit_trusts" },
|
|
{ FALSE, 0, 0, "USA (Alphavantage, Fool, ...)", "USA", "usa" },
|
|
};
|
|
|
|
static const int num_single_quote_sources =
|
|
sizeof(single_quote_sources) / sizeof(gnc_quote_source);
|
|
static const int num_multiple_quote_sources =
|
|
sizeof(multiple_quote_sources) / sizeof(gnc_quote_source);
|
|
static GList *new_quote_sources = NULL;
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_quote_source_fq_installed
|
|
*
|
|
* This function indicates whether or not the Finance::Quote module
|
|
* is installed on a users computer.
|
|
********************************************************************/
|
|
gboolean
|
|
gnc_quote_source_fq_installed (void)
|
|
{
|
|
return (fq_version != NULL);
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_quote_source_fq_version
|
|
*
|
|
* This function the version of the Finance::Quote module installed
|
|
* on a user's computer or NULL if no installation is found.
|
|
********************************************************************/
|
|
const char*
|
|
gnc_quote_source_fq_version (void)
|
|
{
|
|
return fq_version;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_quote_source_num_entries
|
|
*
|
|
* Return the number of entries for a given type of price source.
|
|
********************************************************************/
|
|
gint gnc_quote_source_num_entries(QuoteSourceType type)
|
|
{
|
|
if (type == SOURCE_CURRENCY)
|
|
return 1;
|
|
|
|
if (type == SOURCE_SINGLE)
|
|
return num_single_quote_sources;
|
|
|
|
if (type == SOURCE_MULTI)
|
|
return num_multiple_quote_sources;
|
|
|
|
return g_list_length(new_quote_sources);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_quote_source_init_tables
|
|
*
|
|
* Update the type/index values for prices sources.
|
|
********************************************************************/
|
|
static void
|
|
gnc_quote_source_init_tables (void)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < num_single_quote_sources; i++)
|
|
{
|
|
single_quote_sources[i].type = SOURCE_SINGLE;
|
|
single_quote_sources[i].index = i;
|
|
}
|
|
|
|
for (i = 0; i < num_multiple_quote_sources; i++)
|
|
{
|
|
multiple_quote_sources[i].type = SOURCE_MULTI;
|
|
multiple_quote_sources[i].index = i;
|
|
}
|
|
|
|
currency_quote_source.type = SOURCE_CURRENCY;
|
|
currency_quote_source.index = 0;
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_quote_source_add_new
|
|
*
|
|
* Add a new price source. Called when unknown source names are found
|
|
* either in the F::Q installation (a newly available source) or in
|
|
* the user's data file (a source that has vanished but needs to be
|
|
* tracked.)
|
|
********************************************************************/
|
|
gnc_quote_source *
|
|
gnc_quote_source_add_new (const char *source_name, gboolean supported)
|
|
{
|
|
gnc_quote_source *new_source;
|
|
|
|
DEBUG("Creating new source %s", (source_name == NULL ? "(null)" : source_name));
|
|
new_source = malloc(sizeof(gnc_quote_source));
|
|
new_source->supported = supported;
|
|
new_source->type = SOURCE_UNKNOWN;
|
|
new_source->index = g_list_length(new_quote_sources);
|
|
|
|
/* This name can be changed if/when support for this price source is
|
|
* integrated into gnucash. */
|
|
new_source->user_name = g_strdup(source_name);
|
|
|
|
/* This name is permanent and must be kept the same if/when support
|
|
* for this price source is integrated into gnucash (i.e. for a
|
|
* nice user name). */
|
|
new_source->old_internal_name = g_strdup(source_name);
|
|
new_source->internal_name = g_strdup(source_name);
|
|
new_quote_sources = g_list_append(new_quote_sources, new_source);
|
|
return new_source;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_quote_source_lookup_by_xxx
|
|
*
|
|
* Lookup a price source data structure based upon various criteria.
|
|
********************************************************************/
|
|
gnc_quote_source *
|
|
gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
|
|
{
|
|
gnc_quote_source *source;
|
|
GList *node;
|
|
|
|
ENTER("type/index is %d/%d", type, index);
|
|
switch (type)
|
|
{
|
|
case SOURCE_CURRENCY:
|
|
LEAVE("found %s", currency_quote_source.user_name);
|
|
return ¤cy_quote_source;
|
|
break;
|
|
|
|
case SOURCE_SINGLE:
|
|
if (index < num_single_quote_sources)
|
|
{
|
|
LEAVE("found %s", single_quote_sources[index].user_name);
|
|
return &single_quote_sources[index];
|
|
}
|
|
break;
|
|
|
|
case SOURCE_MULTI:
|
|
if (index < num_multiple_quote_sources)
|
|
{
|
|
LEAVE("found %s", multiple_quote_sources[index].user_name);
|
|
return &multiple_quote_sources[index];
|
|
}
|
|
break;
|
|
|
|
case SOURCE_UNKNOWN:
|
|
default:
|
|
node = g_list_nth(new_quote_sources, index);
|
|
if (node)
|
|
{
|
|
source = node->data;
|
|
LEAVE("found %s", source->user_name);
|
|
return source;
|
|
}
|
|
break;
|
|
}
|
|
|
|
LEAVE("not found");
|
|
return NULL;
|
|
}
|
|
|
|
gnc_quote_source *
|
|
gnc_quote_source_lookup_by_internal(const char * name)
|
|
{
|
|
gnc_quote_source *source;
|
|
GList *node;
|
|
gint i;
|
|
|
|
if ((name == NULL) || (g_strcmp0(name, "") == 0))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (g_strcmp0(name, currency_quote_source.internal_name) == 0)
|
|
return ¤cy_quote_source;
|
|
if (g_strcmp0(name, currency_quote_source.old_internal_name) == 0)
|
|
return ¤cy_quote_source;
|
|
|
|
for (i = 0; i < num_single_quote_sources; i++)
|
|
{
|
|
if (g_strcmp0(name, single_quote_sources[i].internal_name) == 0)
|
|
return &single_quote_sources[i];
|
|
if (g_strcmp0(name, single_quote_sources[i].old_internal_name) == 0)
|
|
return &single_quote_sources[i];
|
|
}
|
|
|
|
for (i = 0; i < num_multiple_quote_sources; i++)
|
|
{
|
|
if (g_strcmp0(name, multiple_quote_sources[i].internal_name) == 0)
|
|
return &multiple_quote_sources[i];
|
|
if (g_strcmp0(name, multiple_quote_sources[i].old_internal_name) == 0)
|
|
return &multiple_quote_sources[i];
|
|
}
|
|
|
|
for (i = 0, node = new_quote_sources; node; node = node->next, i++)
|
|
{
|
|
source = node->data;
|
|
if (g_strcmp0(name, source->internal_name) == 0)
|
|
return source;
|
|
if (g_strcmp0(name, source->old_internal_name) == 0)
|
|
return source;
|
|
}
|
|
|
|
DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);
|
|
return NULL;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_quote_source_get_xxx
|
|
*
|
|
* Accessor functions - get functions only. There are no set functions.
|
|
********************************************************************/
|
|
QuoteSourceType
|
|
gnc_quote_source_get_type (const gnc_quote_source *source)
|
|
{
|
|
ENTER("%p", source);
|
|
if (!source)
|
|
{
|
|
LEAVE("bad source");
|
|
return SOURCE_SINGLE;
|
|
}
|
|
|
|
LEAVE("type is %d", source->type);
|
|
return source->type;
|
|
}
|
|
|
|
gint
|
|
gnc_quote_source_get_index (const gnc_quote_source *source)
|
|
{
|
|
ENTER("%p", source);
|
|
if (!source)
|
|
{
|
|
LEAVE("bad source");
|
|
return 0;
|
|
}
|
|
|
|
LEAVE("index is %d", source->index);
|
|
return source->index;
|
|
}
|
|
|
|
gboolean
|
|
gnc_quote_source_get_supported (const gnc_quote_source *source)
|
|
{
|
|
ENTER("%p", source);
|
|
if (!source)
|
|
{
|
|
LEAVE("bad source");
|
|
return FALSE;
|
|
}
|
|
|
|
LEAVE("%ssupported", source && source->supported ? "" : "not ");
|
|
return source->supported;
|
|
}
|
|
|
|
const char *
|
|
gnc_quote_source_get_user_name (const gnc_quote_source *source)
|
|
{
|
|
ENTER("%p", source);
|
|
if (!source)
|
|
{
|
|
LEAVE("bad source");
|
|
return NULL;
|
|
}
|
|
LEAVE("user name %s", source->user_name);
|
|
return source->user_name;
|
|
}
|
|
|
|
const char *
|
|
gnc_quote_source_get_internal_name (const gnc_quote_source *source)
|
|
{
|
|
ENTER("%p", source);
|
|
if (!source)
|
|
{
|
|
LEAVE("bad source");
|
|
return NULL;
|
|
}
|
|
LEAVE("internal name %s", source->internal_name);
|
|
return source->internal_name;
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_quote_source_set_fq_installed
|
|
*
|
|
* Update gnucash internal tables on what Finance::Quote sources are
|
|
* installed.
|
|
********************************************************************/
|
|
void
|
|
gnc_quote_source_set_fq_installed (const char* version_string,
|
|
const GList *sources_list)
|
|
{
|
|
gnc_quote_source *source;
|
|
char *source_name;
|
|
const GList *node;
|
|
|
|
ENTER(" ");
|
|
|
|
if (!sources_list)
|
|
return;
|
|
|
|
if (fq_version)
|
|
{
|
|
g_free (fq_version);
|
|
fq_version = NULL;
|
|
}
|
|
|
|
if (version_string)
|
|
fq_version = g_strdup (version_string);
|
|
|
|
for (node = sources_list; node; node = node->next)
|
|
{
|
|
source_name = node->data;
|
|
|
|
source = gnc_quote_source_lookup_by_internal(source_name);
|
|
if (source != NULL)
|
|
{
|
|
DEBUG("Found source %s: %s", source_name, source->user_name);
|
|
source->supported = TRUE;
|
|
continue;
|
|
}
|
|
|
|
gnc_quote_source_add_new(source_name, TRUE);
|
|
}
|
|
LEAVE(" ");
|
|
}
|
|
|
|
/********************************************************************
|
|
* QoF Helpers
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_begin_edit (gnc_commodity *cm)
|
|
{
|
|
qof_begin_edit(&cm->inst);
|
|
}
|
|
|
|
static void commit_err (QofInstance *inst, QofBackendError errcode)
|
|
{
|
|
PERR ("Failed to commit: %d", errcode);
|
|
gnc_engine_signal_commit_error( errcode );
|
|
}
|
|
|
|
static void noop (QofInstance *inst) {}
|
|
|
|
static void
|
|
comm_free(QofInstance* inst)
|
|
{
|
|
commodity_free( GNC_COMMODITY(inst) );
|
|
}
|
|
|
|
void
|
|
gnc_commodity_commit_edit (gnc_commodity *cm)
|
|
{
|
|
if (!qof_commit_edit (QOF_INSTANCE(cm))) return;
|
|
qof_commit_edit_part2 (&cm->inst, commit_err, noop, comm_free);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_new
|
|
********************************************************************/
|
|
|
|
static void
|
|
mark_commodity_dirty (gnc_commodity *cm)
|
|
{
|
|
qof_instance_set_dirty(&cm->inst);
|
|
qof_event_gen (&cm->inst, QOF_EVENT_MODIFY, NULL);
|
|
}
|
|
|
|
static void
|
|
reset_printname(gnc_commodityPrivate *priv)
|
|
{
|
|
g_free(priv->printname);
|
|
priv->printname = g_strdup_printf("%s (%s)",
|
|
priv->mnemonic ? priv->mnemonic : "",
|
|
priv->fullname ? priv->fullname : "");
|
|
}
|
|
|
|
static void
|
|
reset_unique_name(gnc_commodityPrivate *priv)
|
|
{
|
|
gnc_commodity_namespace *ns;
|
|
|
|
g_free(priv->unique_name);
|
|
ns = priv->name_space;
|
|
priv->unique_name = g_strdup_printf("%s::%s",
|
|
ns ? ns->name : "",
|
|
priv->mnemonic ? priv->mnemonic : "");
|
|
}
|
|
|
|
/* GObject Initialization */
|
|
G_DEFINE_TYPE_WITH_PRIVATE(gnc_commodity, gnc_commodity, QOF_TYPE_INSTANCE);
|
|
|
|
static void
|
|
gnc_commodity_init(gnc_commodity* com)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
priv = GET_PRIVATE(com);
|
|
|
|
priv->name_space = NULL;
|
|
priv->fullname = CACHE_INSERT("");
|
|
priv->mnemonic = CACHE_INSERT("");
|
|
priv->cusip = CACHE_INSERT("");
|
|
priv->fraction = 10000;
|
|
priv->quote_flag = 0;
|
|
priv->quote_source = NULL;
|
|
priv->quote_tz = CACHE_INSERT("");
|
|
|
|
reset_printname(priv);
|
|
reset_unique_name(priv);
|
|
}
|
|
|
|
static void
|
|
gnc_commodity_dispose(GObject *comp)
|
|
{
|
|
G_OBJECT_CLASS(gnc_commodity_parent_class)->dispose(comp);
|
|
}
|
|
|
|
static void
|
|
gnc_commodity_finalize(GObject* comp)
|
|
{
|
|
G_OBJECT_CLASS(gnc_commodity_parent_class)->finalize(comp);
|
|
}
|
|
/* Note that g_value_set_object() refs the object, as does
|
|
* g_object_get(). But g_object_get() only unrefs once when it disgorges
|
|
* the object, leaving an unbalanced ref, which leaks. So instead of
|
|
* using g_value_set_object(), use g_value_take_object() which doesn't
|
|
* ref the object when used in get_property().
|
|
*/
|
|
static void
|
|
gnc_commodity_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
gnc_commodity *commodity;
|
|
gnc_commodityPrivate* priv;
|
|
|
|
g_return_if_fail(GNC_IS_COMMODITY(object));
|
|
|
|
commodity = GNC_COMMODITY(object);
|
|
priv = GET_PRIVATE(commodity);
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAMESPACE:
|
|
g_value_take_object(value, priv->name_space);
|
|
break;
|
|
case PROP_FULL_NAME:
|
|
g_value_set_string(value, priv->fullname);
|
|
break;
|
|
case PROP_MNEMONIC:
|
|
g_value_set_string(value, priv->mnemonic);
|
|
break;
|
|
case PROP_PRINTNAME:
|
|
g_value_set_string(value, priv->printname);
|
|
break;
|
|
case PROP_CUSIP:
|
|
g_value_set_string(value, priv->cusip);
|
|
break;
|
|
case PROP_FRACTION:
|
|
g_value_set_int(value, priv->fraction);
|
|
break;
|
|
case PROP_UNIQUE_NAME:
|
|
g_value_set_string(value, priv->unique_name);
|
|
break;
|
|
case PROP_QUOTE_FLAG:
|
|
g_value_set_boolean(value, priv->quote_flag);
|
|
break;
|
|
case PROP_QUOTE_SOURCE:
|
|
g_value_set_pointer(value, priv->quote_source);
|
|
break;
|
|
case PROP_QUOTE_TZ:
|
|
g_value_set_string(value, priv->quote_tz);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gnc_commodity_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
gnc_commodity *commodity;
|
|
|
|
g_return_if_fail(GNC_IS_COMMODITY(object));
|
|
|
|
commodity = GNC_COMMODITY(object);
|
|
g_assert (qof_instance_get_editlevel(commodity));
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAMESPACE:
|
|
gnc_commodity_set_namespace(commodity, g_value_get_object(value));
|
|
break;
|
|
case PROP_FULL_NAME:
|
|
gnc_commodity_set_fullname(commodity, g_value_get_string(value));
|
|
break;
|
|
case PROP_MNEMONIC:
|
|
gnc_commodity_set_mnemonic(commodity, g_value_get_string(value));
|
|
break;
|
|
case PROP_CUSIP:
|
|
gnc_commodity_set_cusip(commodity, g_value_get_string(value));
|
|
break;
|
|
case PROP_FRACTION:
|
|
gnc_commodity_set_fraction(commodity, g_value_get_int(value));
|
|
break;
|
|
case PROP_QUOTE_FLAG:
|
|
gnc_commodity_set_quote_flag(commodity, g_value_get_boolean(value));
|
|
break;
|
|
case PROP_QUOTE_SOURCE:
|
|
gnc_commodity_set_quote_source(commodity, g_value_get_pointer(value));
|
|
break;
|
|
case PROP_QUOTE_TZ:
|
|
gnc_commodity_set_quote_tz(commodity, g_value_get_string(value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
static void
|
|
gnc_commodity_class_init(struct _GncCommodityClass* klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
|
|
|
|
gobject_class->dispose = gnc_commodity_dispose;
|
|
gobject_class->finalize = gnc_commodity_finalize;
|
|
gobject_class->set_property = gnc_commodity_set_property;
|
|
gobject_class->get_property = gnc_commodity_get_property;
|
|
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_NAMESPACE,
|
|
g_param_spec_object ("namespace",
|
|
"Namespace",
|
|
"The namespace field denotes the "
|
|
"namespace for this commodity, either "
|
|
"a currency or symbol from a quote source.",
|
|
GNC_TYPE_COMMODITY_NAMESPACE,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_FULL_NAME,
|
|
g_param_spec_string ("fullname",
|
|
"Full Commodity Name",
|
|
"The fullname is the official full name of"
|
|
"the currency.",
|
|
NULL,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_MNEMONIC,
|
|
g_param_spec_string ("mnemonic",
|
|
"Commodity Mnemonic",
|
|
"The mnemonic is the official abbreviated"
|
|
"designation for the currency.",
|
|
NULL,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_PRINTNAME,
|
|
g_param_spec_string ("printname",
|
|
"Commodity Print Name",
|
|
"Printable form of the commodity name.",
|
|
NULL,
|
|
G_PARAM_READABLE));
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_CUSIP,
|
|
g_param_spec_string ("cusip",
|
|
"Commodity CUSIP Code",
|
|
"?????",
|
|
NULL,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_FRACTION,
|
|
g_param_spec_int ("fraction",
|
|
"Fraction",
|
|
"The fraction is the number of sub-units that "
|
|
"the basic commodity can be divided into.",
|
|
1,
|
|
GNC_COMMODITY_MAX_FRACTION,
|
|
1,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_UNIQUE_NAME,
|
|
g_param_spec_string ("unique-name",
|
|
"Commodity Unique Name",
|
|
"Unique form of the commodity name which combines "
|
|
"the namespace name and the commodity name.",
|
|
NULL,
|
|
G_PARAM_READABLE));
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_QUOTE_FLAG,
|
|
g_param_spec_boolean ("quote_flag",
|
|
"Quote Flag",
|
|
"TRUE if prices are to be downloaded for this "
|
|
"commodity from a quote source.",
|
|
FALSE,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_QUOTE_SOURCE,
|
|
g_param_spec_pointer("quote-source",
|
|
"Quote Source",
|
|
"The quote source from which prices are downloaded.",
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property(gobject_class,
|
|
PROP_QUOTE_TZ,
|
|
g_param_spec_string ("quote-tz",
|
|
"Commodity Quote Timezone",
|
|
"?????",
|
|
NULL,
|
|
G_PARAM_READWRITE));
|
|
}
|
|
|
|
gnc_commodity *
|
|
gnc_commodity_new(QofBook *book, const char * fullname,
|
|
const char * name_space, const char * mnemonic,
|
|
const char * cusip, int fraction)
|
|
{
|
|
gnc_commodity * retval = g_object_new(GNC_TYPE_COMMODITY, NULL);
|
|
|
|
qof_instance_init_data (&retval->inst, GNC_ID_COMMODITY, book);
|
|
gnc_commodity_begin_edit(retval);
|
|
|
|
if ( name_space != NULL )
|
|
{
|
|
/* Prevent setting anything except template in namespace template. */
|
|
if (g_strcmp0 (name_space, GNC_COMMODITY_NS_TEMPLATE) == 0 &&
|
|
g_strcmp0 (mnemonic, "template") != 0)
|
|
{
|
|
PWARN("Converting commodity %s from namespace template to "
|
|
"namespace User", mnemonic);
|
|
name_space = "User";
|
|
}
|
|
gnc_commodity_set_namespace(retval, name_space);
|
|
if (gnc_commodity_namespace_is_iso(name_space))
|
|
{
|
|
gnc_commodity_set_quote_source(retval,
|
|
gnc_quote_source_lookup_by_internal("currency") );
|
|
}
|
|
}
|
|
gnc_commodity_set_fullname(retval, fullname);
|
|
gnc_commodity_set_mnemonic(retval, mnemonic);
|
|
gnc_commodity_set_cusip(retval, cusip);
|
|
gnc_commodity_set_fraction(retval, fraction);
|
|
mark_commodity_dirty (retval);
|
|
gnc_commodity_commit_edit(retval);
|
|
|
|
qof_event_gen (&retval->inst, QOF_EVENT_CREATE, NULL);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_destroy
|
|
********************************************************************/
|
|
|
|
static void
|
|
commodity_free(gnc_commodity * cm)
|
|
{
|
|
QofBook *book;
|
|
gnc_commodity_table *table;
|
|
gnc_commodityPrivate* priv;
|
|
|
|
if (!cm) return;
|
|
|
|
book = qof_instance_get_book(&cm->inst);
|
|
table = gnc_commodity_table_get_table(book);
|
|
gnc_commodity_table_remove(table, cm);
|
|
priv = GET_PRIVATE(cm);
|
|
|
|
qof_event_gen (&cm->inst, QOF_EVENT_DESTROY, NULL);
|
|
|
|
/* Set at creation */
|
|
CACHE_REMOVE (priv->fullname);
|
|
CACHE_REMOVE (priv->cusip);
|
|
CACHE_REMOVE (priv->mnemonic);
|
|
CACHE_REMOVE (priv->quote_tz);
|
|
priv->name_space = NULL;
|
|
|
|
/* Set through accessor functions */
|
|
priv->quote_source = NULL;
|
|
|
|
/* Automatically generated */
|
|
g_free(priv->printname);
|
|
priv->printname = NULL;
|
|
|
|
g_free(priv->unique_name);
|
|
priv->unique_name = NULL;
|
|
|
|
#ifdef ACCOUNTS_CLEANED_UP
|
|
/* Account objects are not actually cleaned up when a book is closed (in fact
|
|
* a memory leak), but commodities are, so in currently this warning gets hit
|
|
* quite frequently. Disable the check until cleaning up of accounts objects
|
|
* on close is implemented. */
|
|
if (priv->usage_count != 0)
|
|
{
|
|
PWARN("Destroying commodity (%p) with non-zero usage_count (%d).", cm,
|
|
priv->usage_count);
|
|
}
|
|
#endif
|
|
|
|
/* qof_instance_release (&cm->inst); */
|
|
g_object_unref(cm);
|
|
}
|
|
|
|
void
|
|
gnc_commodity_destroy(gnc_commodity * cm)
|
|
{
|
|
gnc_commodity_begin_edit(cm);
|
|
qof_instance_set_destroying(cm, TRUE);
|
|
gnc_commodity_commit_edit(cm);
|
|
}
|
|
|
|
void
|
|
gnc_commodity_copy(gnc_commodity * dest, const gnc_commodity *src)
|
|
{
|
|
gnc_commodityPrivate* src_priv = GET_PRIVATE(src);
|
|
gnc_commodityPrivate* dest_priv = GET_PRIVATE(dest);
|
|
|
|
gnc_commodity_set_fullname (dest, src_priv->fullname);
|
|
gnc_commodity_set_mnemonic (dest, src_priv->mnemonic);
|
|
dest_priv->name_space = src_priv->name_space;
|
|
gnc_commodity_set_fraction (dest, src_priv->fraction);
|
|
gnc_commodity_set_cusip (dest, src_priv->cusip);
|
|
gnc_commodity_set_quote_flag (dest, src_priv->quote_flag);
|
|
gnc_commodity_set_quote_source (dest, gnc_commodity_get_quote_source (src));
|
|
gnc_commodity_set_quote_tz (dest, src_priv->quote_tz);
|
|
qof_instance_copy_kvp (QOF_INSTANCE (dest), QOF_INSTANCE (src));
|
|
}
|
|
|
|
gnc_commodity *
|
|
gnc_commodity_clone(const gnc_commodity *src, QofBook *dest_book)
|
|
{
|
|
gnc_commodityPrivate* src_priv;
|
|
gnc_commodityPrivate* dest_priv;
|
|
|
|
gnc_commodity * dest = g_object_new(GNC_TYPE_COMMODITY, NULL);
|
|
qof_instance_init_data (&dest->inst, GNC_ID_COMMODITY, dest_book);
|
|
src_priv = GET_PRIVATE(src);
|
|
dest_priv = GET_PRIVATE(dest);
|
|
|
|
dest_priv->fullname = CACHE_INSERT(src_priv->fullname);
|
|
dest_priv->mnemonic = CACHE_INSERT(src_priv->mnemonic);
|
|
dest_priv->cusip = CACHE_INSERT(src_priv->cusip);
|
|
dest_priv->quote_tz = CACHE_INSERT(src_priv->quote_tz);
|
|
|
|
dest_priv->name_space = src_priv->name_space;
|
|
|
|
dest_priv->fraction = src_priv->fraction;
|
|
dest_priv->quote_flag = src_priv->quote_flag;
|
|
|
|
gnc_commodity_set_quote_source (dest, gnc_commodity_get_quote_source (src));
|
|
|
|
qof_instance_copy_kvp (QOF_INSTANCE (dest), QOF_INSTANCE (src));
|
|
|
|
reset_printname(dest_priv);
|
|
reset_unique_name(dest_priv);
|
|
|
|
return dest;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_mnemonic
|
|
********************************************************************/
|
|
|
|
const char *
|
|
gnc_commodity_get_mnemonic(const gnc_commodity * cm)
|
|
{
|
|
if (!cm) return NULL;
|
|
return GET_PRIVATE(cm)->mnemonic;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_printname
|
|
********************************************************************/
|
|
|
|
const char *
|
|
gnc_commodity_get_printname(const gnc_commodity * cm)
|
|
{
|
|
if (!cm) return NULL;
|
|
return GET_PRIVATE(cm)->printname;
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_namespace
|
|
********************************************************************/
|
|
|
|
const char *
|
|
gnc_commodity_get_namespace(const gnc_commodity * cm)
|
|
{
|
|
if (!cm) return NULL;
|
|
return gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->name_space);
|
|
}
|
|
|
|
gnc_commodity_namespace *
|
|
gnc_commodity_get_namespace_ds(const gnc_commodity * cm)
|
|
{
|
|
if (!cm) return NULL;
|
|
return GET_PRIVATE(cm)->name_space;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_fullname
|
|
********************************************************************/
|
|
|
|
const char *
|
|
gnc_commodity_get_fullname(const gnc_commodity * cm)
|
|
{
|
|
if (!cm) return NULL;
|
|
return GET_PRIVATE(cm)->fullname;
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_unique_name
|
|
********************************************************************/
|
|
|
|
const char *
|
|
gnc_commodity_get_unique_name(const gnc_commodity * cm)
|
|
{
|
|
if (!cm) return NULL;
|
|
return GET_PRIVATE(cm)->unique_name;
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_cusip
|
|
********************************************************************/
|
|
|
|
const char *
|
|
gnc_commodity_get_cusip(const gnc_commodity * cm)
|
|
{
|
|
if (!cm) return NULL;
|
|
return GET_PRIVATE(cm)->cusip;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_fraction
|
|
********************************************************************/
|
|
|
|
int
|
|
gnc_commodity_get_fraction(const gnc_commodity * cm)
|
|
{
|
|
if (!cm) return 0;
|
|
return GET_PRIVATE(cm)->fraction;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_auto_quote_control_flag
|
|
********************************************************************/
|
|
|
|
static gboolean
|
|
gnc_commodity_get_auto_quote_control_flag(const gnc_commodity *cm)
|
|
{
|
|
GValue v = G_VALUE_INIT;
|
|
|
|
if (!cm) return FALSE;
|
|
qof_instance_get_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
|
|
if (G_VALUE_HOLDS_STRING (&v) &&
|
|
strcmp(g_value_get_string (&v), "false") == 0)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_quote_flag
|
|
********************************************************************/
|
|
|
|
gboolean
|
|
gnc_commodity_get_quote_flag(const gnc_commodity *cm)
|
|
{
|
|
if (!cm) return FALSE;
|
|
return (GET_PRIVATE(cm)->quote_flag);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_quote_source
|
|
********************************************************************/
|
|
|
|
gnc_quote_source*
|
|
gnc_commodity_get_quote_source(const gnc_commodity *cm)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
if (!cm) return NULL;
|
|
priv = GET_PRIVATE(cm);
|
|
if (!priv->quote_source && gnc_commodity_is_iso(cm))
|
|
return ¤cy_quote_source;
|
|
return priv->quote_source;
|
|
}
|
|
|
|
gnc_quote_source*
|
|
gnc_commodity_get_default_quote_source(const gnc_commodity *cm)
|
|
{
|
|
if (cm && gnc_commodity_is_iso(cm))
|
|
return ¤cy_quote_source;
|
|
/* Should make this a user option at some point. */
|
|
return gnc_quote_source_lookup_by_internal("alphavantage");
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_quote_tz
|
|
********************************************************************/
|
|
|
|
const char*
|
|
gnc_commodity_get_quote_tz(const gnc_commodity *cm)
|
|
{
|
|
if (!cm) return NULL;
|
|
return GET_PRIVATE(cm)->quote_tz;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_user_symbol
|
|
********************************************************************/
|
|
const char*
|
|
gnc_commodity_get_user_symbol(const gnc_commodity *cm)
|
|
{
|
|
GValue v = G_VALUE_INIT;
|
|
if (!cm) return NULL;
|
|
qof_instance_get_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
|
|
if (G_VALUE_HOLDS_STRING (&v))
|
|
return g_value_get_string (&v);
|
|
return NULL;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_default_symbol
|
|
*******************************************************************/
|
|
const char*
|
|
gnc_commodity_get_default_symbol(const gnc_commodity *cm)
|
|
{
|
|
if (!cm) return NULL;
|
|
return GET_PRIVATE(cm)->default_symbol;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_get_nice_symbol
|
|
*******************************************************************/
|
|
const char*
|
|
gnc_commodity_get_nice_symbol (const gnc_commodity *cm)
|
|
{
|
|
const char *nice_symbol;
|
|
struct lconv *lc;
|
|
if (!cm) return NULL;
|
|
|
|
nice_symbol = gnc_commodity_get_user_symbol(cm);
|
|
if (nice_symbol && *nice_symbol)
|
|
return nice_symbol;
|
|
|
|
lc = gnc_localeconv();
|
|
nice_symbol = lc->currency_symbol;
|
|
if (!g_strcmp0(gnc_commodity_get_mnemonic(cm), lc->int_curr_symbol))
|
|
return nice_symbol;
|
|
|
|
nice_symbol = gnc_commodity_get_default_symbol(cm);
|
|
if (nice_symbol && *nice_symbol)
|
|
return nice_symbol;
|
|
|
|
return gnc_commodity_get_mnemonic(cm);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_mnemonic
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_set_mnemonic(gnc_commodity * cm, const char * mnemonic)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
if (!cm) return;
|
|
priv = GET_PRIVATE(cm);
|
|
if (priv->mnemonic == mnemonic) return;
|
|
|
|
gnc_commodity_begin_edit(cm);
|
|
CACHE_REMOVE (priv->mnemonic);
|
|
priv->mnemonic = CACHE_INSERT(mnemonic);
|
|
|
|
mark_commodity_dirty (cm);
|
|
reset_printname(priv);
|
|
reset_unique_name(priv);
|
|
gnc_commodity_commit_edit(cm);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_namespace
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_set_namespace(gnc_commodity * cm, const char * name_space)
|
|
{
|
|
QofBook *book;
|
|
gnc_commodity_table *table;
|
|
gnc_commodity_namespace *nsp;
|
|
gnc_commodityPrivate* priv;
|
|
|
|
if (!cm) return;
|
|
priv = GET_PRIVATE(cm);
|
|
book = qof_instance_get_book (&cm->inst);
|
|
table = gnc_commodity_table_get_table(book);
|
|
nsp = gnc_commodity_table_add_namespace(table, name_space, book);
|
|
if (priv->name_space == nsp)
|
|
return;
|
|
|
|
gnc_commodity_begin_edit(cm);
|
|
priv->name_space = nsp;
|
|
if (nsp->iso4217)
|
|
priv->quote_source = gnc_quote_source_lookup_by_internal("currency");
|
|
mark_commodity_dirty(cm);
|
|
reset_printname(priv);
|
|
reset_unique_name(priv);
|
|
gnc_commodity_commit_edit(cm);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_fullname
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_set_fullname(gnc_commodity * cm, const char * fullname)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
if (!cm) return;
|
|
priv = GET_PRIVATE(cm);
|
|
if (priv->fullname == fullname) return;
|
|
|
|
CACHE_REMOVE (priv->fullname);
|
|
priv->fullname = CACHE_INSERT (fullname);
|
|
|
|
gnc_commodity_begin_edit(cm);
|
|
mark_commodity_dirty(cm);
|
|
reset_printname(priv);
|
|
gnc_commodity_commit_edit(cm);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_cusip
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_set_cusip(gnc_commodity * cm,
|
|
const char * cusip)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
if (!cm) return;
|
|
|
|
priv = GET_PRIVATE(cm);
|
|
if (priv->cusip == cusip) return;
|
|
|
|
gnc_commodity_begin_edit(cm);
|
|
CACHE_REMOVE (priv->cusip);
|
|
priv->cusip = CACHE_INSERT (cusip);
|
|
mark_commodity_dirty(cm);
|
|
gnc_commodity_commit_edit(cm);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_fraction
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_set_fraction(gnc_commodity * cm, int fraction)
|
|
{
|
|
if (!cm) return;
|
|
gnc_commodity_begin_edit(cm);
|
|
GET_PRIVATE(cm)->fraction = fraction;
|
|
mark_commodity_dirty(cm);
|
|
gnc_commodity_commit_edit(cm);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_auto_quote_control_flag
|
|
********************************************************************/
|
|
|
|
static void
|
|
gnc_commodity_set_auto_quote_control_flag(gnc_commodity *cm,
|
|
const gboolean flag)
|
|
{
|
|
GValue v = G_VALUE_INIT;
|
|
ENTER ("(cm=%p, flag=%d)", cm, flag);
|
|
|
|
if (!cm)
|
|
{
|
|
LEAVE("");
|
|
return;
|
|
}
|
|
gnc_commodity_begin_edit(cm);
|
|
if (flag)
|
|
qof_instance_set_kvp (QOF_INSTANCE (cm), NULL, 1, "auto_quote_control");
|
|
else
|
|
{
|
|
g_value_init (&v, G_TYPE_STRING);
|
|
g_value_set_string (&v, "false");
|
|
qof_instance_set_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
|
|
}
|
|
mark_commodity_dirty(cm);
|
|
gnc_commodity_commit_edit(cm);
|
|
LEAVE("");
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_user_set_quote_flag
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_user_set_quote_flag(gnc_commodity *cm, const gboolean flag)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
ENTER ("(cm=%p, flag=%d)", cm, flag);
|
|
|
|
if (!cm)
|
|
{
|
|
LEAVE("");
|
|
return;
|
|
}
|
|
|
|
priv = GET_PRIVATE(cm);
|
|
gnc_commodity_begin_edit(cm);
|
|
gnc_commodity_set_quote_flag(cm, flag);
|
|
if (gnc_commodity_is_iso(cm))
|
|
{
|
|
/* For currencies, disable auto quote control if the quote flag is being
|
|
* changed from its default value and enable it if the quote flag is being
|
|
* reset to its default value. The defaults for the quote flag are
|
|
* disabled if no accounts are using the currency, and true otherwise.
|
|
* Thus enable auto quote control if flag is FALSE and there are not any
|
|
* accounts using this currency OR flag is TRUE and there are accounts
|
|
* using this currency; otherwise disable auto quote control */
|
|
gnc_commodity_set_auto_quote_control_flag(cm,
|
|
(!flag && (priv->usage_count == 0)) || (flag && (priv->usage_count != 0)));
|
|
}
|
|
gnc_commodity_commit_edit(cm);
|
|
LEAVE("");
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_quote_flag
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
|
|
{
|
|
ENTER ("(cm=%p, flag=%d)", cm, flag);
|
|
|
|
if (!cm) return;
|
|
gnc_commodity_begin_edit(cm);
|
|
GET_PRIVATE(cm)->quote_flag = flag;
|
|
mark_commodity_dirty(cm);
|
|
gnc_commodity_commit_edit(cm);
|
|
LEAVE(" ");
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_quote_source
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
|
|
{
|
|
ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->internal_name : "unknown");
|
|
|
|
if (!cm) return;
|
|
gnc_commodity_begin_edit(cm);
|
|
GET_PRIVATE(cm)->quote_source = src;
|
|
mark_commodity_dirty(cm);
|
|
gnc_commodity_commit_edit(cm);
|
|
LEAVE(" ");
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_quote_tz
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
if (!cm) return;
|
|
|
|
ENTER ("(cm=%p, tz=%s)", cm, tz ? tz : "(null)");
|
|
|
|
priv = GET_PRIVATE(cm);
|
|
|
|
if (tz == priv->quote_tz)
|
|
{
|
|
LEAVE("Already correct TZ");
|
|
return;
|
|
}
|
|
|
|
gnc_commodity_begin_edit(cm);
|
|
CACHE_REMOVE (priv->quote_tz);
|
|
priv->quote_tz = CACHE_INSERT (tz);
|
|
mark_commodity_dirty(cm);
|
|
gnc_commodity_commit_edit(cm);
|
|
LEAVE(" ");
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_user_symbol
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
|
|
{
|
|
struct lconv *lc;
|
|
GValue v = G_VALUE_INIT;
|
|
if (!cm) return;
|
|
|
|
ENTER ("(cm=%p, symbol=%s)", cm, user_symbol ? user_symbol : "(null)");
|
|
|
|
gnc_commodity_begin_edit(cm);
|
|
|
|
lc = gnc_localeconv();
|
|
if (!user_symbol || !*user_symbol)
|
|
user_symbol = NULL;
|
|
else if (!g_strcmp0(lc->int_curr_symbol, gnc_commodity_get_mnemonic(cm)) &&
|
|
!g_strcmp0(lc->currency_symbol, user_symbol))
|
|
/* if the user gives the ISO symbol for the locale currency or the
|
|
* default symbol, actually remove the user symbol */
|
|
user_symbol = NULL;
|
|
else if (!g_strcmp0(user_symbol, gnc_commodity_get_default_symbol(cm)))
|
|
user_symbol = NULL;
|
|
if (user_symbol)
|
|
{
|
|
g_value_init (&v, G_TYPE_STRING);
|
|
g_value_set_string (&v, user_symbol);
|
|
qof_instance_set_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
|
|
}
|
|
else
|
|
qof_instance_set_kvp (QOF_INSTANCE(cm), NULL, 1, "user_symbol");
|
|
|
|
mark_commodity_dirty(cm);
|
|
gnc_commodity_commit_edit(cm);
|
|
|
|
LEAVE(" ");
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_set_default_symbol
|
|
* Not made visible in gnc-commodity.h, it is only called from
|
|
* iso-4217-currencies.c at startup.
|
|
********************************************************************/
|
|
void
|
|
gnc_commodity_set_default_symbol(gnc_commodity * cm,
|
|
const char * default_symbol)
|
|
{
|
|
GET_PRIVATE(cm)->default_symbol = default_symbol;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_increment_usage_count
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_increment_usage_count(gnc_commodity *cm)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
ENTER("(cm=%p)", cm);
|
|
|
|
if (!cm)
|
|
{
|
|
LEAVE("");
|
|
return;
|
|
}
|
|
|
|
priv = GET_PRIVATE(cm);
|
|
|
|
if ((priv->usage_count == 0) && !priv->quote_flag
|
|
&& gnc_commodity_get_auto_quote_control_flag(cm)
|
|
&& gnc_commodity_is_iso(cm))
|
|
{
|
|
/* compatibility hack - Gnucash 1.8 gets currency quotes when a
|
|
non-default currency is assigned to an account. */
|
|
gnc_commodity_begin_edit(cm);
|
|
gnc_commodity_set_quote_flag(cm, TRUE);
|
|
gnc_commodity_set_quote_source(cm,
|
|
gnc_commodity_get_default_quote_source(cm));
|
|
gnc_commodity_commit_edit(cm);
|
|
}
|
|
priv->usage_count++;
|
|
LEAVE("(usage_count=%d)", priv->usage_count);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_decrement_usage_count
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_decrement_usage_count(gnc_commodity *cm)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
ENTER("(cm=%p)", cm);
|
|
|
|
if (!cm)
|
|
{
|
|
LEAVE("");
|
|
return;
|
|
}
|
|
|
|
priv = GET_PRIVATE(cm);
|
|
|
|
if (priv->usage_count == 0)
|
|
{
|
|
PWARN("usage_count already zero");
|
|
LEAVE("");
|
|
return;
|
|
}
|
|
|
|
priv->usage_count--;
|
|
if ((priv->usage_count == 0) && priv->quote_flag
|
|
&& gnc_commodity_get_auto_quote_control_flag(cm)
|
|
&& gnc_commodity_is_iso(cm))
|
|
{
|
|
/* if this is a currency with auto quote control enabled and no more
|
|
* accounts reference this currency, disable quote retrieval */
|
|
gnc_commodity_set_quote_flag(cm, FALSE);
|
|
}
|
|
LEAVE("(usage_count=%d)", priv->usage_count);
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_equiv
|
|
* are two commodities the same?
|
|
********************************************************************/
|
|
|
|
gboolean
|
|
gnc_commodity_equiv(const gnc_commodity * a, const gnc_commodity * b)
|
|
{
|
|
gnc_commodityPrivate* priv_a;
|
|
gnc_commodityPrivate* priv_b;
|
|
|
|
if (a == b) return TRUE;
|
|
if (!a || !b) return FALSE;
|
|
|
|
priv_a = GET_PRIVATE(a);
|
|
priv_b = GET_PRIVATE(b);
|
|
if (priv_a->name_space != priv_b->name_space) return FALSE;
|
|
if (g_strcmp0(priv_a->mnemonic, priv_b->mnemonic) != 0) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gnc_commodity_equal(const gnc_commodity * a, const gnc_commodity * b)
|
|
{
|
|
gnc_commodityPrivate* priv_a;
|
|
gnc_commodityPrivate* priv_b;
|
|
gboolean same_book;
|
|
|
|
if (a == b) return TRUE;
|
|
|
|
if (!a || !b)
|
|
{
|
|
DEBUG ("one is NULL");
|
|
return FALSE;
|
|
}
|
|
|
|
priv_a = GET_PRIVATE(a);
|
|
priv_b = GET_PRIVATE(b);
|
|
same_book = qof_instance_get_book(QOF_INSTANCE(a)) == qof_instance_get_book(QOF_INSTANCE(b));
|
|
|
|
if ((same_book && priv_a->name_space != priv_b->name_space)
|
|
|| (!same_book && g_strcmp0( gnc_commodity_namespace_get_name(priv_a->name_space),
|
|
gnc_commodity_namespace_get_name(priv_b->name_space)) != 0))
|
|
{
|
|
DEBUG ("namespaces differ: %p(%s) vs %p(%s)",
|
|
priv_a->name_space, gnc_commodity_namespace_get_name(priv_a->name_space),
|
|
priv_b->name_space, gnc_commodity_namespace_get_name(priv_b->name_space));
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_strcmp0(priv_a->mnemonic, priv_b->mnemonic) != 0)
|
|
{
|
|
DEBUG ("mnemonics differ: %s vs %s", priv_a->mnemonic, priv_b->mnemonic);
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_strcmp0(priv_a->fullname, priv_b->fullname) != 0)
|
|
{
|
|
DEBUG ("fullnames differ: %s vs %s", priv_a->fullname, priv_b->fullname);
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_strcmp0(priv_a->cusip, priv_b->cusip) != 0)
|
|
{
|
|
DEBUG ("cusips differ: %s vs %s", priv_a->cusip, priv_b->cusip);
|
|
return FALSE;
|
|
}
|
|
|
|
if (priv_a->fraction != priv_b->fraction)
|
|
{
|
|
DEBUG ("fractions differ: %d vs %d", priv_a->fraction, priv_b->fraction);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int gnc_commodity_compare(const gnc_commodity * a, const gnc_commodity * b)
|
|
{
|
|
if (gnc_commodity_equal(a, b))
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int gnc_commodity_compare_void(const void * a, const void * b)
|
|
{
|
|
return gnc_commodity_compare(a, b);
|
|
}
|
|
|
|
/************************************************************
|
|
* Namespace functions *
|
|
************************************************************/
|
|
const char *
|
|
gnc_commodity_namespace_get_name (const gnc_commodity_namespace *ns)
|
|
{
|
|
if (ns == NULL)
|
|
return NULL;
|
|
return ns->name;
|
|
}
|
|
|
|
const char *
|
|
gnc_commodity_namespace_get_gui_name (const gnc_commodity_namespace *ns)
|
|
{
|
|
if (ns == NULL)
|
|
return NULL;
|
|
if (g_strcmp0 (ns->name, GNC_COMMODITY_NS_CURRENCY) == 0)
|
|
return GNC_COMMODITY_NS_ISO_GUI;
|
|
return ns->name;
|
|
}
|
|
|
|
GList *
|
|
gnc_commodity_namespace_get_commodity_list(const gnc_commodity_namespace *name_space)
|
|
{
|
|
if (!name_space)
|
|
return NULL;
|
|
|
|
return name_space->cm_list;
|
|
}
|
|
|
|
gboolean
|
|
gnc_commodity_namespace_is_iso(const char *name_space)
|
|
{
|
|
return ((g_strcmp0(name_space, GNC_COMMODITY_NS_ISO) == 0) ||
|
|
(g_strcmp0(name_space, GNC_COMMODITY_NS_CURRENCY) == 0));
|
|
}
|
|
|
|
static const gchar *
|
|
gnc_commodity_table_map_namespace(const char * name_space)
|
|
{
|
|
if (g_strcmp0(name_space, GNC_COMMODITY_NS_ISO) == 0)
|
|
return GNC_COMMODITY_NS_CURRENCY;
|
|
return name_space;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_new
|
|
* make a new commodity table
|
|
********************************************************************/
|
|
|
|
gnc_commodity_table *
|
|
gnc_commodity_table_new(void)
|
|
{
|
|
gnc_commodity_table * retval = g_new0(gnc_commodity_table, 1);
|
|
retval->ns_table = g_hash_table_new(&g_str_hash, &g_str_equal);
|
|
retval->ns_list = NULL;
|
|
return retval;
|
|
}
|
|
|
|
/********************************************************************
|
|
* book anchor functons
|
|
********************************************************************/
|
|
|
|
gnc_commodity_table *
|
|
gnc_commodity_table_get_table(QofBook *book)
|
|
{
|
|
if (!book) return NULL;
|
|
return qof_book_get_data (book, GNC_COMMODITY_TABLE);
|
|
}
|
|
|
|
gnc_commodity *
|
|
gnc_commodity_obtain_twin (const gnc_commodity *from, QofBook *book)
|
|
{
|
|
gnc_commodity *twin;
|
|
const char * ucom;
|
|
gnc_commodity_table * comtbl;
|
|
|
|
if (!from) return NULL;
|
|
comtbl = gnc_commodity_table_get_table (book);
|
|
if (!comtbl) return NULL;
|
|
|
|
ucom = gnc_commodity_get_unique_name (from);
|
|
twin = gnc_commodity_table_lookup_unique (comtbl, ucom);
|
|
if (!twin)
|
|
{
|
|
twin = gnc_commodity_clone (from, book);
|
|
twin = gnc_commodity_table_insert (comtbl, twin);
|
|
}
|
|
return twin;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_get_size
|
|
* get the size of the commodity table
|
|
********************************************************************/
|
|
|
|
static void
|
|
count_coms(gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
GHashTable *tbl = ((gnc_commodity_namespace*)value)->cm_table;
|
|
guint *count = (guint*)user_data;
|
|
|
|
if (g_strcmp0((char*)key, GNC_COMMODITY_NS_CURRENCY) == 0)
|
|
{
|
|
/* don't count default commodities */
|
|
return;
|
|
}
|
|
|
|
if (!value) return;
|
|
|
|
*count += g_hash_table_size(tbl);
|
|
}
|
|
|
|
guint
|
|
gnc_commodity_table_get_size(const gnc_commodity_table* tbl)
|
|
{
|
|
guint count = 0;
|
|
g_return_val_if_fail(tbl, 0);
|
|
g_return_val_if_fail(tbl->ns_table, 0);
|
|
|
|
g_hash_table_foreach(tbl->ns_table, count_coms, (gpointer)&count);
|
|
|
|
return count;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_lookup
|
|
* locate a commodity by namespace and mnemonic.
|
|
********************************************************************/
|
|
|
|
gnc_commodity *
|
|
gnc_commodity_table_lookup(const gnc_commodity_table * table,
|
|
const char * name_space, const char * mnemonic)
|
|
{
|
|
gnc_commodity_namespace * nsp = NULL;
|
|
unsigned int i;
|
|
|
|
if (!table || !name_space || !mnemonic) return NULL;
|
|
|
|
nsp = gnc_commodity_table_find_namespace(table, name_space);
|
|
|
|
if (nsp)
|
|
{
|
|
/*
|
|
* Backward compatibility support for currencies that have
|
|
* recently changed.
|
|
*/
|
|
if (nsp->iso4217)
|
|
{
|
|
for (i = 0; i < GNC_NEW_ISO_CODES; i++)
|
|
{
|
|
if (strcmp(mnemonic, gnc_new_iso_codes[i].old_code) == 0)
|
|
{
|
|
mnemonic = gnc_new_iso_codes[i].new_code;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return g_hash_table_lookup(nsp->cm_table, (gpointer)mnemonic);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_lookup
|
|
* locate a commodity by unique name.
|
|
********************************************************************/
|
|
|
|
gnc_commodity *
|
|
gnc_commodity_table_lookup_unique(const gnc_commodity_table *table,
|
|
const char * unique_name)
|
|
{
|
|
char *name_space;
|
|
char *mnemonic;
|
|
gnc_commodity *commodity;
|
|
|
|
if (!table || !unique_name) return NULL;
|
|
|
|
name_space = g_strdup (unique_name);
|
|
mnemonic = strstr (name_space, "::");
|
|
if (!mnemonic)
|
|
{
|
|
g_free (name_space);
|
|
return NULL;
|
|
}
|
|
|
|
*mnemonic = '\0';
|
|
mnemonic += 2;
|
|
|
|
commodity = gnc_commodity_table_lookup (table, name_space, mnemonic);
|
|
|
|
g_free (name_space);
|
|
|
|
return commodity;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_find_full
|
|
* locate a commodity by namespace and printable name
|
|
********************************************************************/
|
|
|
|
gnc_commodity *
|
|
gnc_commodity_table_find_full(const gnc_commodity_table * table,
|
|
const char * name_space,
|
|
const char * fullname)
|
|
{
|
|
gnc_commodity * retval = NULL;
|
|
GList * all;
|
|
GList * iterator;
|
|
|
|
if (!fullname || (fullname[0] == '\0'))
|
|
return NULL;
|
|
|
|
all = gnc_commodity_table_get_commodities(table, name_space);
|
|
|
|
for (iterator = all; iterator; iterator = iterator->next)
|
|
{
|
|
if (!strcmp(fullname,
|
|
gnc_commodity_get_printname(iterator->data)))
|
|
{
|
|
retval = iterator->data;
|
|
break;
|
|
}
|
|
}
|
|
|
|
g_list_free (all);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_insert
|
|
* add a commodity to the table.
|
|
********************************************************************/
|
|
|
|
gnc_commodity *
|
|
gnc_commodity_table_insert(gnc_commodity_table * table,
|
|
gnc_commodity * comm)
|
|
{
|
|
gnc_commodity_namespace * nsp = NULL;
|
|
gnc_commodity *c;
|
|
const char *ns_name;
|
|
gnc_commodityPrivate* priv;
|
|
QofBook *book;
|
|
|
|
if (!table) return NULL;
|
|
if (!comm) return NULL;
|
|
|
|
priv = GET_PRIVATE(comm);
|
|
|
|
ENTER ("(table=%p, comm=%p) %s %s", table, comm,
|
|
(priv->mnemonic == NULL ? "(null)" : priv->mnemonic),
|
|
(priv->fullname == NULL ? "(null)" : priv->fullname));
|
|
ns_name = gnc_commodity_namespace_get_name(priv->name_space);
|
|
c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
|
|
|
|
if (c)
|
|
{
|
|
if (c == comm)
|
|
{
|
|
LEAVE("already in table");
|
|
return c;
|
|
}
|
|
|
|
/* Backward compatibility support for currencies that have
|
|
* recently changed. */
|
|
if (priv->name_space->iso4217)
|
|
{
|
|
guint i;
|
|
for (i = 0; i < GNC_NEW_ISO_CODES; i++)
|
|
{
|
|
if (!priv->mnemonic
|
|
|| !strcmp(priv->mnemonic, gnc_new_iso_codes[i].old_code))
|
|
{
|
|
gnc_commodity_set_mnemonic(comm, gnc_new_iso_codes[i].new_code);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
gnc_commodity_copy (c, comm);
|
|
gnc_commodity_destroy (comm);
|
|
LEAVE("found at %p", c);
|
|
return c;
|
|
}
|
|
|
|
/* Prevent setting anything except template in namespace template. */
|
|
if (g_strcmp0 (ns_name, GNC_COMMODITY_NS_TEMPLATE) == 0 &&
|
|
g_strcmp0 (priv->mnemonic, "template") != 0)
|
|
{
|
|
PWARN("Converting commodity %s from namespace template to "
|
|
"namespace User", priv->mnemonic);
|
|
gnc_commodity_set_namespace (comm, "User");
|
|
ns_name = "User";
|
|
mark_commodity_dirty (comm);
|
|
}
|
|
|
|
book = qof_instance_get_book (&comm->inst);
|
|
nsp = gnc_commodity_table_add_namespace(table, ns_name, book);
|
|
|
|
PINFO ("insert %p %s into nsp=%p %s", priv->mnemonic, priv->mnemonic,
|
|
nsp->cm_table, nsp->name);
|
|
g_hash_table_insert(nsp->cm_table,
|
|
CACHE_INSERT(priv->mnemonic),
|
|
(gpointer)comm);
|
|
nsp->cm_list = g_list_append(nsp->cm_list, comm);
|
|
|
|
qof_event_gen (&comm->inst, QOF_EVENT_ADD, NULL);
|
|
LEAVE ("(table=%p, comm=%p)", table, comm);
|
|
return comm;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_remove
|
|
* remove a commodity from the table.
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_table_remove(gnc_commodity_table * table,
|
|
gnc_commodity * comm)
|
|
{
|
|
gnc_commodity_namespace * nsp;
|
|
gnc_commodity *c;
|
|
gnc_commodityPrivate* priv;
|
|
const char *ns_name;
|
|
|
|
if (!table) return;
|
|
if (!comm) return;
|
|
|
|
priv = GET_PRIVATE(comm);
|
|
ns_name = gnc_commodity_namespace_get_name(priv->name_space);
|
|
c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
|
|
if (c != comm) return;
|
|
|
|
qof_event_gen (&comm->inst, QOF_EVENT_REMOVE, NULL);
|
|
|
|
nsp = gnc_commodity_table_find_namespace(table, ns_name);
|
|
if (!nsp) return;
|
|
|
|
nsp->cm_list = g_list_remove(nsp->cm_list, comm);
|
|
g_hash_table_remove (nsp->cm_table, priv->mnemonic);
|
|
/* XXX minor mem leak, should remove the key as well */
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_has_namespace
|
|
* see if the commodities namespace exists. May have zero commodities.
|
|
********************************************************************/
|
|
|
|
int
|
|
gnc_commodity_table_has_namespace(const gnc_commodity_table * table,
|
|
const char * name_space)
|
|
{
|
|
gnc_commodity_namespace * nsp = NULL;
|
|
|
|
if (!table || !name_space)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
nsp = gnc_commodity_table_find_namespace(table, name_space);
|
|
if (nsp)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
hash_keys_helper(gpointer key, gpointer value, gpointer data)
|
|
{
|
|
GList ** l = data;
|
|
*l = g_list_prepend(*l, key);
|
|
}
|
|
|
|
static GList *
|
|
g_hash_table_keys(GHashTable * table)
|
|
{
|
|
GList * l = NULL;
|
|
g_hash_table_foreach(table, &hash_keys_helper, (gpointer) &l);
|
|
return l;
|
|
}
|
|
|
|
static void
|
|
hash_values_helper(gpointer key, gpointer value, gpointer data)
|
|
{
|
|
GList ** l = data;
|
|
*l = g_list_prepend(*l, value);
|
|
}
|
|
|
|
static GList *
|
|
g_hash_table_values(GHashTable * table)
|
|
{
|
|
GList * l = NULL;
|
|
g_hash_table_foreach(table, &hash_values_helper, (gpointer) &l);
|
|
return l;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_get_namespaces
|
|
* see if any commodities in the namespace exist
|
|
********************************************************************/
|
|
|
|
GList *
|
|
gnc_commodity_table_get_namespaces(const gnc_commodity_table * table)
|
|
{
|
|
if (!table)
|
|
return NULL;
|
|
|
|
return g_hash_table_keys(table->ns_table);
|
|
}
|
|
|
|
GList *
|
|
gnc_commodity_table_get_namespaces_list(const gnc_commodity_table * table)
|
|
{
|
|
if (!table)
|
|
return NULL;
|
|
|
|
return table->ns_list;
|
|
}
|
|
|
|
/* Because gnc_commodity_table_add_namespace maps GNC_COMMODITY_NS_ISO to
|
|
GNC_COMMODITY_NS_CURRENCY and then sets iso4217 if the namespace is
|
|
either of these, the net result is that the iso4217 bit is set only
|
|
for GNC_COMMODITY_NS_CURRENCY. This means that gnc_commodity_is_iso is
|
|
a subset of gnc_commodity_is_currency. Most callers seem to use
|
|
gnc_commodity_is_iso. */
|
|
gboolean
|
|
gnc_commodity_is_iso(const gnc_commodity * cm)
|
|
{
|
|
gnc_commodityPrivate* priv;
|
|
|
|
if (!cm) return FALSE;
|
|
|
|
priv = GET_PRIVATE(cm);
|
|
if ( !priv->name_space) return FALSE;
|
|
return priv->name_space->iso4217;
|
|
}
|
|
|
|
gboolean
|
|
gnc_commodity_is_currency(const gnc_commodity *cm)
|
|
{
|
|
const char *ns_name;
|
|
if (!cm) return FALSE;
|
|
|
|
ns_name = gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->name_space);
|
|
return (!g_strcmp0(ns_name, GNC_COMMODITY_NS_LEGACY) ||
|
|
!g_strcmp0(ns_name, GNC_COMMODITY_NS_CURRENCY));
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_get_commodities
|
|
* list commodities in a given namespace
|
|
********************************************************************/
|
|
|
|
static CommodityList*
|
|
commodity_table_get_all_noncurrency_commodities(const gnc_commodity_table* table)
|
|
{
|
|
GList *node = NULL, *nslist = gnc_commodity_table_get_namespaces(table);
|
|
CommodityList *retval = NULL;
|
|
for (node = nslist; node; node=g_list_next(node))
|
|
{
|
|
gnc_commodity_namespace *ns = NULL;
|
|
if (g_strcmp0((char*)(node->data), GNC_COMMODITY_NS_CURRENCY) == 0
|
|
|| g_strcmp0((char*)(node->data), GNC_COMMODITY_NS_TEMPLATE) == 0)
|
|
continue;
|
|
ns = gnc_commodity_table_find_namespace(table, (char*)(node->data));
|
|
if (!ns)
|
|
continue;
|
|
retval = g_list_concat(g_hash_table_values(ns->cm_table), retval);
|
|
}
|
|
g_list_free(nslist);
|
|
return retval;
|
|
}
|
|
|
|
CommodityList *
|
|
gnc_commodity_table_get_commodities(const gnc_commodity_table * table,
|
|
const char * name_space)
|
|
{
|
|
gnc_commodity_namespace * ns = NULL;
|
|
|
|
if (!table)
|
|
return NULL;
|
|
if (g_strcmp0(name_space, GNC_COMMODITY_NS_NONCURRENCY) == 0)
|
|
return commodity_table_get_all_noncurrency_commodities(table);
|
|
ns = gnc_commodity_table_find_namespace(table, name_space);
|
|
if (!ns)
|
|
return NULL;
|
|
|
|
return g_hash_table_values(ns->cm_table);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_get_quotable_commodities
|
|
* list commodities in a given namespace that get price quotes
|
|
********************************************************************/
|
|
|
|
static void
|
|
get_quotables_helper1(gpointer key, gpointer value, gpointer data)
|
|
{
|
|
gnc_commodity *comm = value;
|
|
gnc_commodityPrivate* priv = GET_PRIVATE(comm);
|
|
GList ** l = data;
|
|
|
|
if (!priv->quote_flag ||
|
|
!priv->quote_source || !priv->quote_source->supported)
|
|
return;
|
|
*l = g_list_prepend(*l, value);
|
|
}
|
|
|
|
static gboolean
|
|
get_quotables_helper2 (gnc_commodity *comm, gpointer data)
|
|
{
|
|
GList ** l = data;
|
|
gnc_commodityPrivate* priv = GET_PRIVATE(comm);
|
|
|
|
if (!priv->quote_flag ||
|
|
!priv->quote_source || !priv->quote_source->supported)
|
|
return TRUE;
|
|
*l = g_list_prepend(*l, comm);
|
|
return TRUE;
|
|
}
|
|
|
|
CommodityList *
|
|
gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table)
|
|
{
|
|
gnc_commodity_namespace * ns = NULL;
|
|
const char *name_space;
|
|
GList * nslist, * tmp;
|
|
GList * l = NULL;
|
|
regex_t pattern;
|
|
const char *expression = gnc_prefs_get_namespace_regexp();
|
|
|
|
ENTER("table=%p, expression=%s", table, expression);
|
|
if (!table)
|
|
return NULL;
|
|
|
|
if (expression && *expression)
|
|
{
|
|
if (regcomp(&pattern, expression, REG_EXTENDED | REG_ICASE) != 0)
|
|
{
|
|
LEAVE("Cannot compile regex");
|
|
return NULL;
|
|
}
|
|
|
|
nslist = gnc_commodity_table_get_namespaces(table);
|
|
for (tmp = nslist; tmp; tmp = tmp->next)
|
|
{
|
|
name_space = tmp->data;
|
|
if (regexec(&pattern, name_space, 0, NULL, 0) == 0)
|
|
{
|
|
DEBUG("Running list of %s commodities", name_space);
|
|
ns = gnc_commodity_table_find_namespace(table, name_space);
|
|
if (ns)
|
|
{
|
|
g_hash_table_foreach(ns->cm_table, &get_quotables_helper1, (gpointer) &l);
|
|
}
|
|
}
|
|
}
|
|
g_list_free(nslist);
|
|
regfree(&pattern);
|
|
}
|
|
else
|
|
{
|
|
gnc_commodity_table_foreach_commodity(table, get_quotables_helper2,
|
|
(gpointer) &l);
|
|
}
|
|
LEAVE("list head %p", l);
|
|
return l;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_add_namespace
|
|
* add an empty namespace if it does not exist
|
|
********************************************************************/
|
|
|
|
/* GObject Initialization */
|
|
QOF_GOBJECT_IMPL(gnc_commodity_namespace, gnc_commodity_namespace, QOF_TYPE_INSTANCE);
|
|
|
|
static void
|
|
gnc_commodity_namespace_init(gnc_commodity_namespace* ns)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gnc_commodity_namespace_dispose_real (GObject *nsp)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gnc_commodity_namespace_finalize_real(GObject* nsp)
|
|
{
|
|
}
|
|
|
|
gnc_commodity_namespace *
|
|
gnc_commodity_table_add_namespace(gnc_commodity_table * table,
|
|
const char * name_space,
|
|
QofBook *book)
|
|
{
|
|
gnc_commodity_namespace * ns = NULL;
|
|
|
|
if (!table) return NULL;
|
|
|
|
name_space = gnc_commodity_table_map_namespace(name_space);
|
|
ns = gnc_commodity_table_find_namespace(table, name_space);
|
|
if (!ns)
|
|
{
|
|
ns = g_object_new(GNC_TYPE_COMMODITY_NAMESPACE, NULL);
|
|
ns->cm_table = g_hash_table_new(g_str_hash, g_str_equal);
|
|
ns->name = CACHE_INSERT((gpointer)name_space);
|
|
ns->iso4217 = gnc_commodity_namespace_is_iso(name_space);
|
|
qof_instance_init_data (&ns->inst, GNC_ID_COMMODITY_NAMESPACE, book);
|
|
qof_event_gen (&ns->inst, QOF_EVENT_CREATE, NULL);
|
|
|
|
g_hash_table_insert(table->ns_table,
|
|
(gpointer) ns->name,
|
|
(gpointer) ns);
|
|
table->ns_list = g_list_append(table->ns_list, ns);
|
|
qof_event_gen (&ns->inst, QOF_EVENT_ADD, NULL);
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
|
|
gnc_commodity_namespace *
|
|
gnc_commodity_table_find_namespace(const gnc_commodity_table * table,
|
|
const char * name_space)
|
|
{
|
|
if (!table || !name_space)
|
|
return NULL;
|
|
|
|
name_space = gnc_commodity_table_map_namespace(name_space);
|
|
return g_hash_table_lookup(table->ns_table, (gpointer)name_space);
|
|
}
|
|
|
|
|
|
gnc_commodity *
|
|
gnc_commodity_find_commodity_by_guid(const GncGUID *guid, QofBook *book)
|
|
{
|
|
QofCollection *col;
|
|
if (!guid || !book) return NULL;
|
|
col = qof_book_get_collection (book, GNC_ID_COMMODITY);
|
|
return (gnc_commodity *) qof_collection_lookup_entity (col, guid);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_delete_namespace
|
|
* delete a namespace
|
|
********************************************************************/
|
|
|
|
static int
|
|
ns_helper(gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
gnc_commodity * c = value;
|
|
gnc_commodity_destroy(c);
|
|
CACHE_REMOVE(key); /* key is commodity mnemonic */
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
gnc_commodity_table_delete_namespace(gnc_commodity_table * table,
|
|
const char * name_space)
|
|
{
|
|
gnc_commodity_namespace * ns;
|
|
|
|
if (!table) return;
|
|
|
|
ns = gnc_commodity_table_find_namespace(table, name_space);
|
|
if (!ns)
|
|
return;
|
|
|
|
qof_event_gen (&ns->inst, QOF_EVENT_REMOVE, NULL);
|
|
g_hash_table_remove(table->ns_table, name_space);
|
|
table->ns_list = g_list_remove(table->ns_list, ns);
|
|
|
|
g_list_free(ns->cm_list);
|
|
ns->cm_list = NULL;
|
|
|
|
g_hash_table_foreach_remove(ns->cm_table, ns_helper, NULL);
|
|
g_hash_table_destroy(ns->cm_table);
|
|
CACHE_REMOVE(ns->name);
|
|
|
|
qof_event_gen (&ns->inst, QOF_EVENT_DESTROY, NULL);
|
|
/* qof_instance_release(&ns->inst); */
|
|
g_object_unref(ns);
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_foreach_commodity
|
|
* call user-defined function once for every commodity in every
|
|
* namespace
|
|
********************************************************************/
|
|
|
|
typedef struct
|
|
{
|
|
gboolean ok;
|
|
gboolean (*func)(gnc_commodity *, gpointer);
|
|
gpointer user_data;
|
|
} IterData;
|
|
|
|
static void
|
|
iter_commodity (gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
IterData *iter_data = (IterData *) user_data;
|
|
gnc_commodity *cm = (gnc_commodity *) value;
|
|
|
|
if (iter_data->ok)
|
|
{
|
|
iter_data->ok = (iter_data->func)(cm, iter_data->user_data);
|
|
}
|
|
}
|
|
|
|
static void
|
|
iter_namespace (gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
GHashTable *namespace_hash = ((gnc_commodity_namespace *) value)->cm_table;
|
|
g_hash_table_foreach (namespace_hash, iter_commodity, user_data);
|
|
}
|
|
|
|
gboolean
|
|
gnc_commodity_table_foreach_commodity (const gnc_commodity_table * tbl,
|
|
gboolean (*f)(gnc_commodity *, gpointer),
|
|
gpointer user_data)
|
|
{
|
|
IterData iter_data;
|
|
|
|
if (!tbl || !f) return FALSE;
|
|
|
|
iter_data.ok = TRUE;
|
|
iter_data.func = f;
|
|
iter_data.user_data = user_data;
|
|
|
|
g_hash_table_foreach(tbl->ns_table, iter_namespace, (gpointer)&iter_data);
|
|
|
|
return iter_data.ok;
|
|
}
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_destroy
|
|
* cleanup and free.
|
|
********************************************************************/
|
|
|
|
void
|
|
gnc_commodity_table_destroy(gnc_commodity_table * t)
|
|
{
|
|
gnc_commodity_namespace * ns;
|
|
GList *item, *next;
|
|
|
|
if (!t) return;
|
|
ENTER ("table=%p", t);
|
|
|
|
for (item = t->ns_list; item; item = next)
|
|
{
|
|
next = g_list_next(item);
|
|
ns = item->data;
|
|
gnc_commodity_table_delete_namespace(t, ns->name);
|
|
}
|
|
|
|
g_list_free(t->ns_list);
|
|
t->ns_list = NULL;
|
|
g_hash_table_destroy(t->ns_table);
|
|
t->ns_table = NULL;
|
|
LEAVE ("table=%p", t);
|
|
g_free(t);
|
|
}
|
|
|
|
/* =========================================================== */
|
|
|
|
/********************************************************************
|
|
* gnc_commodity_table_add_default_data
|
|
********************************************************************/
|
|
|
|
#define CUR_I18N(String) dgettext ("iso_4217", String)
|
|
|
|
gboolean
|
|
gnc_commodity_table_add_default_data(gnc_commodity_table *table, QofBook *book)
|
|
{
|
|
QofCollection *col;
|
|
gnc_commodity* c;
|
|
|
|
ENTER ("table=%p", table);
|
|
gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_AMEX, book);
|
|
gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_NYSE, book);
|
|
gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_NASDAQ, book);
|
|
gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_EUREX, book);
|
|
gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_MUTUAL, book);
|
|
gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_TEMPLATE, book);
|
|
c = gnc_commodity_new(book, "template", GNC_COMMODITY_NS_TEMPLATE, "template", "template", 1);
|
|
gnc_commodity_table_insert(table, c);
|
|
|
|
#include "iso-4217-currencies.c"
|
|
|
|
/* We've just created the default namespaces and currencies. Mark
|
|
* these collections as clean because there is no USER entered data
|
|
* in these collections as of yet. */
|
|
col = qof_book_get_collection(book, GNC_ID_COMMODITY);
|
|
qof_collection_mark_clean(col);
|
|
col = qof_book_get_collection(book, GNC_ID_COMMODITY_NAMESPACE);
|
|
qof_collection_mark_clean(col);
|
|
|
|
LEAVE ("table=%p", table);
|
|
return TRUE;
|
|
}
|
|
|
|
/********************************************************************
|
|
********************************************************************/
|
|
/* QofObject function implementation and registration */
|
|
|
|
#ifdef _MSC_VER
|
|
/* MSVC compiler doesn't have C99 "designated initializers"
|
|
* so we wrap them in a macro that is empty on MSVC. */
|
|
# define DI(x) /* */
|
|
#else
|
|
# define DI(x) x
|
|
#endif
|
|
static QofObject commodity_object_def =
|
|
{
|
|
DI(.interface_version = ) QOF_OBJECT_VERSION,
|
|
DI(.e_type = ) GNC_ID_COMMODITY,
|
|
DI(.type_label = ) "Commodity",
|
|
DI(.create = ) NULL,
|
|
DI(.book_begin = ) NULL,
|
|
DI(.book_end = ) NULL,
|
|
DI(.is_dirty = ) qof_collection_is_dirty,
|
|
DI(.mark_clean = ) qof_collection_mark_clean,
|
|
DI(.foreach = ) qof_collection_foreach,
|
|
DI(.printable = ) (const char * (*)(gpointer)) gnc_commodity_get_fullname,
|
|
};
|
|
|
|
static QofObject namespace_object_def =
|
|
{
|
|
DI(.interface_version = ) QOF_OBJECT_VERSION,
|
|
DI(.e_type = ) GNC_ID_COMMODITY_NAMESPACE,
|
|
DI(.type_label = ) "Namespace",
|
|
DI(.create = ) NULL,
|
|
DI(.book_begin = ) NULL,
|
|
DI(.book_end = ) NULL,
|
|
DI(.is_dirty = ) NULL,
|
|
DI(.mark_clean = ) NULL,
|
|
DI(.foreach = ) NULL,
|
|
DI(.printable = ) NULL,
|
|
};
|
|
|
|
static void
|
|
commodity_table_book_begin (QofBook *book)
|
|
{
|
|
gnc_commodity_table *ct;
|
|
ENTER ("book=%p", book);
|
|
|
|
if (gnc_commodity_table_get_table(book))
|
|
return;
|
|
|
|
ct = gnc_commodity_table_new ();
|
|
qof_book_set_data (book, GNC_COMMODITY_TABLE, ct);
|
|
|
|
if (!gnc_commodity_table_add_default_data(ct, book))
|
|
{
|
|
PWARN("unable to initialize book's commodity_table");
|
|
}
|
|
|
|
LEAVE ("book=%p", book);
|
|
}
|
|
|
|
static void
|
|
commodity_table_book_end (QofBook *book)
|
|
{
|
|
gnc_commodity_table *ct;
|
|
|
|
ct = gnc_commodity_table_get_table (book);
|
|
qof_book_set_data (book, GNC_COMMODITY_TABLE, NULL);
|
|
gnc_commodity_table_destroy (ct);
|
|
}
|
|
|
|
static QofObject commodity_table_object_def =
|
|
{
|
|
DI(.interface_version = ) QOF_OBJECT_VERSION,
|
|
DI(.e_type = ) GNC_ID_COMMODITY_TABLE,
|
|
DI(.type_label = ) "CommodityTable",
|
|
DI(.create = ) NULL,
|
|
DI(.book_begin = ) commodity_table_book_begin,
|
|
DI(.book_end = ) commodity_table_book_end,
|
|
DI(.is_dirty = ) qof_collection_is_dirty,
|
|
DI(.mark_clean = ) qof_collection_mark_clean,
|
|
DI(.foreach = ) NULL,
|
|
DI(.printable = ) NULL,
|
|
DI(.version_cmp = ) NULL,
|
|
};
|
|
|
|
gboolean
|
|
gnc_commodity_table_register (void)
|
|
{
|
|
gnc_quote_source_init_tables();
|
|
|
|
if (!qof_object_register (&commodity_object_def))
|
|
return FALSE;
|
|
if (!qof_object_register (&namespace_object_def))
|
|
return FALSE;
|
|
return qof_object_register (&commodity_table_object_def);
|
|
}
|
|
|
|
/* *******************************************************************
|
|
* gnc_monetary methods
|
|
********************************************************************/
|
|
|
|
/** Add a gnc_monetary to the list */
|
|
MonetaryList *
|
|
gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
|
|
{
|
|
MonetaryList *l = list, *tmp;
|
|
for (tmp = list; tmp; tmp = tmp->next)
|
|
{
|
|
gnc_monetary *list_mon = tmp->data;
|
|
if (gnc_commodity_equiv(list_mon->commodity, add_mon.commodity))
|
|
{
|
|
list_mon->value = gnc_numeric_add(list_mon->value, add_mon.value,
|
|
GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* See if we found an entry, and add one if not */
|
|
if (tmp == NULL)
|
|
{
|
|
gnc_monetary *new_mon = g_new0(gnc_monetary, 1);
|
|
*new_mon = add_mon;
|
|
l = g_list_prepend(l, new_mon);
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
/** Delete all entries in the list that have zero value. Return list
|
|
pointer will be a null pointer if there are no non-zero entries **/
|
|
MonetaryList *
|
|
gnc_monetary_list_delete_zeros(MonetaryList *list)
|
|
{
|
|
MonetaryList *node, *next;
|
|
for (node = list; node; node = next)
|
|
{
|
|
gnc_monetary *mon = node->data;
|
|
next = node->next;
|
|
if (gnc_numeric_zero_p(mon->value))
|
|
{
|
|
g_free(mon);
|
|
list = g_list_delete_link(list, node);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
/** Free a MonetaryList and all the monetaries it points to */
|
|
void
|
|
gnc_monetary_list_free(MonetaryList *list)
|
|
{
|
|
MonetaryList *tmp;
|
|
for (tmp = list; tmp; tmp = tmp->next)
|
|
{
|
|
g_free(tmp->data);
|
|
}
|
|
|
|
g_list_free(list);
|
|
}
|
|
|
|
/* ========================= END OF FILE ============================== */
|