PageRenderTime 33ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/src/engine/gnc-commodity.c

http://github.com/mchochlov/Gnucash
C | 2551 lines | 1854 code | 405 blank | 292 comment | 247 complexity | 684590e3236492c6f1c7de19e9b01a6c MD5 | raw file
Possible License(s): GPL-2.0
  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. #include "config.h"
  26. #include <glib.h>
  27. #include <glib/gi18n.h>
  28. #include <ctype.h>
  29. #include <limits.h>
  30. #include <string.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <regex.h>
  34. #include "gnc-commodity.h"
  35. #include "gnc-main.h"
  36. static QofLogModule log_module = GNC_MOD_COMMODITY;
  37. /* Parts per unit is nominal, i.e. number of 'partname' units in
  38. * a 'unitname' unit. fraction is transactional, i.e. how many
  39. * of the smallest-transactional-units of the currency are there
  40. * in a 'unitname' unit. */
  41. enum
  42. {
  43. PROP_0,
  44. PROP_NAMESPACE,
  45. PROP_FULL_NAME,
  46. PROP_MNEMONIC,
  47. PROP_PRINTNAME,
  48. PROP_CUSIP,
  49. PROP_FRACTION,
  50. PROP_UNIQUE_NAME,
  51. PROP_QUOTE_FLAG,
  52. PROP_QUOTE_SOURCE,
  53. PROP_QUOTE_TZ,
  54. };
  55. struct gnc_commodity_s
  56. {
  57. QofInstance inst;
  58. };
  59. typedef struct CommodityPrivate
  60. {
  61. gnc_commodity_namespace *namespace;
  62. char * fullname;
  63. char * mnemonic;
  64. char * printname;
  65. char * cusip; /* CUSIP or other identifying code */
  66. int fraction;
  67. char * unique_name;
  68. gboolean quote_flag; /* user wants price quotes */
  69. gnc_quote_source * quote_source; /* current/old source of quotes */
  70. char * quote_tz;
  71. /* the number of accounts using this commodity - this field is not
  72. * persisted */
  73. int usage_count;
  74. } CommodityPrivate;
  75. #define GET_PRIVATE(o) \
  76. (G_TYPE_INSTANCE_GET_PRIVATE((o), GNC_TYPE_COMMODITY, CommodityPrivate))
  77. struct _GncCommodityClass
  78. {
  79. QofInstanceClass parent_class;
  80. };
  81. static void commodity_free(gnc_commodity * cm);
  82. struct gnc_commodity_namespace_s
  83. {
  84. QofInstance inst;
  85. gchar * name;
  86. gboolean iso4217;
  87. GHashTable * cm_table;
  88. GList * cm_list;
  89. };
  90. struct _GncCommodityNamespaceClass
  91. {
  92. QofInstanceClass parent_class;
  93. };
  94. struct gnc_commodity_table_s
  95. {
  96. GHashTable * ns_table;
  97. GList * ns_list;
  98. };
  99. struct gnc_new_iso_code
  100. {
  101. const char *old_code;
  102. const char *new_code;
  103. } gnc_new_iso_codes[] =
  104. {
  105. {"RUR", "RUB"}, /* Russian Ruble: RUR through 1997-12, RUB from 1998-01 onwards; see bug #393185 */
  106. {"PLZ", "PLN"}, /* Polish Zloty */
  107. {"UAG", "UAH"}, /* Ukraine Hryvnia */
  108. {"NIS", "ILS"}, /* New Israeli Shekel: The informal abbreviation may be "NIS", but
  109. its iso-4217 is clearly ILS and only this! Incorrectly changed
  110. due to bug#152755 (Nov 2004) and changed back again by bug#492417
  111. (Oct 2008). */
  112. {"MXP", "MXN"}, /* Mexican (Nuevo) Peso */
  113. {"TRL", "TRY"}, /* New Turkish Lira: changed 2005 */
  114. /* Only add currencies to this table when the old currency no longer
  115. * exists in the file iso-4217-currencies.scm */
  116. };
  117. #define GNC_NEW_ISO_CODES \
  118. (sizeof(gnc_new_iso_codes) / sizeof(struct gnc_new_iso_code))
  119. static gboolean fq_is_installed = FALSE;
  120. struct gnc_quote_source_s
  121. {
  122. gboolean supported;
  123. QuoteSourceType type;
  124. gint index;
  125. char *user_name; /* User friendly name */
  126. char *old_internal_name; /* Name used internally (deprecated) */
  127. char *internal_name; /* Name used internally and by finance::quote. */
  128. };
  129. static gnc_quote_source currency_quote_source =
  130. { TRUE, 0, 0, "Currency", "CURRENCY", "currency" };
  131. static gnc_quote_source single_quote_sources[] =
  132. {
  133. { FALSE, 0, 0, "Amsterdam Euronext eXchange, NL", "AEX", "aex" },
  134. { FALSE, 0, 0, "AEX Futures (now in AEX)", "AEX_FUTURES", "aex_futures" },
  135. { FALSE, 0, 0, "AEX Options (now in AEX)", "AEX_OPTIONS", "aex_options" },
  136. { FALSE, 0, 0, "American International Assurance, HK", "AIAHK", "aiahk" },
  137. { FALSE, 0, 0, "Association of Mutual Funds in India", "AMFIINDIA", "amfiindia" },
  138. { FALSE, 0, 0, "Athens Stock Exchange, GR", "ASEGR", "asegr" },
  139. { FALSE, 0, 0, "Australian Stock Exchange, AU", "ASX", "asx" },
  140. { FALSE, 0, 0, "BMO NesbittBurns, CA", "BMONESBITTBURNS", "bmonesbittburns" },
  141. { FALSE, 0, 0, "BUX/Magyar Tökepiac, HU", "BUX", "bux" },
  142. { FALSE, 0, 0, "Cominvest, ex-Adig, DE", "COMINVEST", "cominvest" },
  143. { FALSE, 0, 0, "Deka Investments, DE", "DEKA", "deka" },
  144. { FALSE, 0, 0, "DWS, DE", "DWS", "dwsfunds" },
  145. { FALSE, 0, 0, "Fidelity Direct", "FIDELITY_DIRECT", "fidelity_direct" },
  146. { FALSE, 0, 0, "Finance Canada", "FINANCECANADA", "financecanada" },
  147. { FALSE, 0, 0, "Finanzpartner, DE", "FINANZPARTNER", "finanzpartner" },
  148. { FALSE, 0, 0, "First Trust Portfolios, US", "FTPORTFOLIOS_DIRECT", "ftportfolios_direct" },
  149. { FALSE, 0, 0, "Fund Library, CA", "FUNDLIBRARY", "fundlibrary" },
  150. { FALSE, 0, 0, "GoldMoney spot rates, JE", "GOLDMONEY", "goldmoney" },
  151. { FALSE, 0, 0, "HElsinki stock eXchange, FI", "HEX", "hex" },
  152. { FALSE, 0, 0, "Man Investments, AU", "maninv", "maninv" },
  153. { FALSE, 0, 0, "Morningstar, SE", "MORNINGSTAR", "morningstar" },
  154. { FALSE, 0, 0, "Motley Fool, US", "FOOL", "fool" },
  155. { FALSE, 0, 0, "New Zealand stock eXchange, NZ", "NZX", "nzx" },
  156. { FALSE, 0, 0, "Paris Stock Exchange/Boursorama, FR", "BOURSO", "bourso" },
  157. { FALSE, 0, 0, "Paris Stock Exchange/LeRevenu, FR", "LEREVENU", "lerevenu" },
  158. { FALSE, 0, 0, "Platinum Asset Management, AU", "PLATINUM", "platinum" },
  159. { FALSE, 0, 0, "Skandinaviska Enskilda Banken, SE", "SEB_FUNDS", "seb_funds" },
  160. { FALSE, 0, 0, "Sharenet, ZA", "ZA", "za" },
  161. { FALSE, 0, 0, "StockHouse Canada", "STOCKHOUSE_FUND", "stockhousecanada_fund" },
  162. { FALSE, 0, 0, "TD Waterhouse Canada", "TDWATERHOUSE", "tdwaterhouse" },
  163. { FALSE, 0, 0, "TD Efunds, CA", "TDEFUNDS", "tdefunds" },
  164. { FALSE, 0, 0, "TIAA-CREF, US", "TIAACREF", "tiaacref" },
  165. { FALSE, 0, 0, "Toronto Stock eXchange, CA", "TSX", "tsx" },
  166. { FALSE, 0, 0, "T. Rowe Price, US", "TRPRICE_DIRECT", "troweprice_direct" },
  167. { FALSE, 0, 0, "Trustnet, GB", "TRUSTNET", "trustnet" },
  168. { FALSE, 0, 0, "Union Investment, DE", "UNIONFUNDS", "unionfunds" },
  169. { FALSE, 0, 0, "US Treasury Bonds", "usfedbonds", "usfedbonds" },
  170. { FALSE, 0, 0, "US Govt. Thrift Savings Plan", "TSP", "tsp" },
  171. { FALSE, 0, 0, "Vanguard", "VANGUARD", "vanguard" }, /* No module seen in F::Q 1.17. */
  172. { FALSE, 0, 0, "VWD, DE (unmaintained)", "VWD", "vwd" },
  173. { FALSE, 0, 0, "Yahoo USA", "YAHOO", "yahoo" },
  174. { FALSE, 0, 0, "Yahoo Asia", "YAHOO_ASIA", "yahoo_asia" },
  175. { FALSE, 0, 0, "Yahoo Australia", "YAHOO_AUSTRALIA", "yahoo_australia" },
  176. { FALSE, 0, 0, "Yahoo Brasil", "YAHOO_BRASIL", "yahoo_brasil" },
  177. { FALSE, 0, 0, "Yahoo Europe", "YAHOO_EUROPE", "yahoo_europe" },
  178. { FALSE, 0, 0, "Yahoo New Zealand", "YAHOO_NZ", "yahoo_nz" },
  179. { FALSE, 0, 0, "Zuerich Investments (outdated)", "ZIFUNDS", "zifunds" }, /* Removed from F::Q 1.11. */
  180. };
  181. static gnc_quote_source multiple_quote_sources[] =
  182. {
  183. { FALSE, 0, 0, "Asia (Yahoo, ...)", "ASIA", "asia" },
  184. { FALSE, 0, 0, "Australia (ASX, Yahoo, ...)", "AUSTRALIA", "australia" },
  185. { FALSE, 0, 0, "Brasil (Yahoo, ...)", "BRASIL", "brasil" },
  186. { FALSE, 0, 0, "Canada (Yahoo, ...)", "CANADA", "canada" },
  187. { FALSE, 0, 0, "Canada Mutual (Fund Library, ...)", "CANADAMUTUAL", "canadamutual" },
  188. { FALSE, 0, 0, "Dutch (AEX, ...)", "DUTCH", "dutch" },
  189. { FALSE, 0, 0, "Europe (Yahoo, ...)", "EUROPE", "europe" },
  190. { FALSE, 0, 0, "Greece (ASE, ...)", "GREECE", "greece" },
  191. { FALSE, 0, 0, "India Mutual (AMFI, ...)", "INDIAMUTUAL", "indiamutual" },
  192. { FALSE, 0, 0, "Fidelity (Fidelity, ...)", "FIDELITY", "fidelity" },
  193. { FALSE, 0, 0, "Finland (HEX, ...)", "FINLAND", "finland" },
  194. { FALSE, 0, 0, "First Trust (First Trust, ...)", "FTPORTFOLIOS", "ftportfolios" },
  195. { FALSE, 0, 0, "France (Boursorama, ...)", "FRANCE", "france" },
  196. { FALSE, 0, 0, "Nasdaq (Yahoo, ...)", "NASDAQ", "nasdaq" },
  197. { FALSE, 0, 0, "New Zealand (Yahoo, ...)", "NZ", "nz" },
  198. { FALSE, 0, 0, "NYSE (Yahoo, ...)", "NYSE", "nyse" },
  199. /* { FALSE, 0, 0, "South Africa (Sharenet, ...)", "ZA", "za" }, */
  200. { FALSE, 0, 0, "T. Rowe Price", "TRPRICE", "troweprice" },
  201. { FALSE, 0, 0, "U.K. Unit Trusts", "UKUNITTRUSTS", "uk_unit_trusts" },
  202. { FALSE, 0, 0, "USA (Yahoo, Fool ...)", "USA", "usa" },
  203. };
  204. static const int num_single_quote_sources =
  205. sizeof(single_quote_sources) / sizeof(gnc_quote_source);
  206. static const int num_multiple_quote_sources =
  207. sizeof(multiple_quote_sources) / sizeof(gnc_quote_source);
  208. static GList *new_quote_sources = NULL;
  209. /********************************************************************
  210. * gnc_quote_source_fq_installed
  211. *
  212. * This function indicates whether or not the Finance::Quote module
  213. * is installed on a users computer.
  214. ********************************************************************/
  215. gboolean
  216. gnc_quote_source_fq_installed (void)
  217. {
  218. return fq_is_installed;
  219. }
  220. /********************************************************************
  221. * gnc_quote_source_num_entries
  222. *
  223. * Return the number of entries for a given type of price source.
  224. ********************************************************************/
  225. gint gnc_quote_source_num_entries(QuoteSourceType type)
  226. {
  227. if (type == SOURCE_CURRENCY)
  228. return 1;
  229. if (type == SOURCE_SINGLE)
  230. return num_single_quote_sources;
  231. if (type == SOURCE_MULTI)
  232. return num_multiple_quote_sources;
  233. return g_list_length(new_quote_sources);
  234. }
  235. /********************************************************************
  236. * gnc_quote_source_init_tables
  237. *
  238. * Update the type/index values for prices sources.
  239. ********************************************************************/
  240. static void
  241. gnc_quote_source_init_tables (void)
  242. {
  243. gint i;
  244. for (i = 0; i < num_single_quote_sources; i++)
  245. {
  246. single_quote_sources[i].type = SOURCE_SINGLE;
  247. single_quote_sources[i].index = i;
  248. }
  249. for (i = 0; i < num_multiple_quote_sources; i++)
  250. {
  251. multiple_quote_sources[i].type = SOURCE_MULTI;
  252. multiple_quote_sources[i].index = i;
  253. }
  254. currency_quote_source.type = SOURCE_CURRENCY;
  255. currency_quote_source.index = 0;
  256. }
  257. /********************************************************************
  258. * gnc_quote_source_add_new
  259. *
  260. * Add a new price source. Called when unknown source names are found
  261. * either in the F::Q installation (a newly available source) or in
  262. * the user's data file (a source that has vanished but needs to be
  263. * tracked.)
  264. ********************************************************************/
  265. gnc_quote_source *
  266. gnc_quote_source_add_new (const char *source_name, gboolean supported)
  267. {
  268. gnc_quote_source *new_source;
  269. DEBUG("Creating new source %s", (source_name == NULL ? "(null)" : source_name));
  270. new_source = malloc(sizeof(gnc_quote_source));
  271. new_source->supported = supported;
  272. new_source->type = SOURCE_UNKNOWN;
  273. new_source->index = g_list_length(new_quote_sources);
  274. /* This name can be changed if/when support for this price source is
  275. * integrated into gnucash. */
  276. new_source->user_name = g_strdup(source_name);
  277. /* This name is permanent and must be kept the same if/when support
  278. * for this price source is integrated into gnucash (i.e. for a
  279. * nice user name). */
  280. new_source->old_internal_name = g_strdup(source_name);
  281. new_source->internal_name = g_strdup(source_name);
  282. new_quote_sources = g_list_append(new_quote_sources, new_source);
  283. return new_source;
  284. }
  285. /********************************************************************
  286. * gnc_quote_source_lookup_by_xxx
  287. *
  288. * Lookup a price source data structure based upon various criteria.
  289. ********************************************************************/
  290. gnc_quote_source *
  291. gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
  292. {
  293. gnc_quote_source *source;
  294. GList *node;
  295. ENTER("type/index is %d/%d", type, index);
  296. switch (type)
  297. {
  298. case SOURCE_CURRENCY:
  299. LEAVE("found %s", currency_quote_source.user_name);
  300. return &currency_quote_source;
  301. break;
  302. case SOURCE_SINGLE:
  303. if (index < num_single_quote_sources)
  304. {
  305. LEAVE("found %s", single_quote_sources[index].user_name);
  306. return &single_quote_sources[index];
  307. }
  308. break;
  309. case SOURCE_MULTI:
  310. if (index < num_multiple_quote_sources)
  311. {
  312. LEAVE("found %s", multiple_quote_sources[index].user_name);
  313. return &multiple_quote_sources[index];
  314. }
  315. break;
  316. case SOURCE_UNKNOWN:
  317. default:
  318. node = g_list_nth(new_quote_sources, index);
  319. if (node)
  320. {
  321. source = node->data;
  322. LEAVE("found %s", source->user_name);
  323. return source;
  324. }
  325. }
  326. LEAVE("not found");
  327. return NULL;
  328. }
  329. gnc_quote_source *
  330. gnc_quote_source_lookup_by_internal(const char * name)
  331. {
  332. gnc_quote_source *source;
  333. GList *node;
  334. gint i;
  335. if ((name == NULL) || (safe_strcmp(name, "") == 0))
  336. {
  337. return NULL;
  338. }
  339. if (safe_strcmp(name, currency_quote_source.internal_name) == 0)
  340. return &currency_quote_source;
  341. if (safe_strcmp(name, currency_quote_source.old_internal_name) == 0)
  342. return &currency_quote_source;
  343. for (i = 0; i < num_single_quote_sources; i++)
  344. {
  345. if (safe_strcmp(name, single_quote_sources[i].internal_name) == 0)
  346. return &single_quote_sources[i];
  347. if (safe_strcmp(name, single_quote_sources[i].old_internal_name) == 0)
  348. return &single_quote_sources[i];
  349. }
  350. for (i = 0; i < num_multiple_quote_sources; i++)
  351. {
  352. if (safe_strcmp(name, multiple_quote_sources[i].internal_name) == 0)
  353. return &multiple_quote_sources[i];
  354. if (safe_strcmp(name, multiple_quote_sources[i].old_internal_name) == 0)
  355. return &multiple_quote_sources[i];
  356. }
  357. for (i = 0, node = new_quote_sources; node; node = node->next, i++)
  358. {
  359. source = node->data;
  360. if (safe_strcmp(name, source->internal_name) == 0)
  361. return source;
  362. if (safe_strcmp(name, source->old_internal_name) == 0)
  363. return source;
  364. }
  365. DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);
  366. return NULL;
  367. }
  368. /********************************************************************
  369. * gnc_quote_source_get_xxx
  370. *
  371. * Accessor functions - get functions only. There are no set functions.
  372. ********************************************************************/
  373. QuoteSourceType
  374. gnc_quote_source_get_type (const gnc_quote_source *source)
  375. {
  376. ENTER("%p", source);
  377. if (!source)
  378. {
  379. LEAVE("bad source");
  380. return SOURCE_SINGLE;
  381. }
  382. LEAVE("type is %d", source->type);
  383. return source->type;
  384. }
  385. gint
  386. gnc_quote_source_get_index (const gnc_quote_source *source)
  387. {
  388. ENTER("%p", source);
  389. if (!source)
  390. {
  391. LEAVE("bad source");
  392. return 0;
  393. }
  394. LEAVE("index is %d", source->index);
  395. return source->index;
  396. }
  397. gboolean
  398. gnc_quote_source_get_supported (const gnc_quote_source *source)
  399. {
  400. ENTER("%p", source);
  401. if (!source)
  402. {
  403. LEAVE("bad source");
  404. return FALSE;
  405. }
  406. LEAVE("%ssupported", source && source->supported ? "" : "not ");
  407. return source->supported;
  408. }
  409. const char *
  410. gnc_quote_source_get_user_name (const gnc_quote_source *source)
  411. {
  412. ENTER("%p", source);
  413. if (!source)
  414. {
  415. LEAVE("bad source");
  416. return NULL;
  417. }
  418. LEAVE("user name %s", source->user_name);
  419. return source->user_name;
  420. }
  421. const char *
  422. gnc_quote_source_get_old_internal_name (const gnc_quote_source *source)
  423. {
  424. ENTER("%p", source);
  425. if (!source)
  426. {
  427. LEAVE("bad source");
  428. return NULL;
  429. }
  430. LEAVE("old internal name %s", source->old_internal_name);
  431. return source->old_internal_name;
  432. }
  433. const char *
  434. gnc_quote_source_get_internal_name (const gnc_quote_source *source)
  435. {
  436. ENTER("%p", source);
  437. if (!source)
  438. {
  439. LEAVE("bad source");
  440. return NULL;
  441. }
  442. LEAVE("internal name %s", source->internal_name);
  443. return source->internal_name;
  444. }
  445. /********************************************************************
  446. * gnc_quote_source_set_fq_installed
  447. *
  448. * Update gnucash internal tables on what Finance::Quote sources are
  449. * installed.
  450. ********************************************************************/
  451. void
  452. gnc_quote_source_set_fq_installed (const GList *sources_list)
  453. {
  454. gnc_quote_source *source;
  455. char *source_name;
  456. const GList *node;
  457. ENTER(" ");
  458. fq_is_installed = TRUE;
  459. if (!sources_list)
  460. return;
  461. for (node = sources_list; node; node = node->next)
  462. {
  463. source_name = node->data;
  464. source = gnc_quote_source_lookup_by_internal(source_name);
  465. if (source != NULL)
  466. {
  467. DEBUG("Found source %s: %s", source_name, source->user_name);
  468. source->supported = TRUE;
  469. continue;
  470. }
  471. gnc_quote_source_add_new(source_name, TRUE);
  472. }
  473. LEAVE(" ");
  474. }
  475. /********************************************************************
  476. * QoF Helpers
  477. ********************************************************************/
  478. void
  479. gnc_commodity_begin_edit (gnc_commodity *cm)
  480. {
  481. qof_begin_edit(&cm->inst);
  482. }
  483. static void commit_err (QofInstance *inst, QofBackendError errcode)
  484. {
  485. PERR ("Failed to commit: %d", errcode);
  486. gnc_engine_signal_commit_error( errcode );
  487. }
  488. static void noop (QofInstance *inst) {}
  489. static void
  490. comm_free(QofInstance* inst)
  491. {
  492. commodity_free( GNC_COMMODITY(inst) );
  493. }
  494. void
  495. gnc_commodity_commit_edit (gnc_commodity *cm)
  496. {
  497. if (!qof_commit_edit (QOF_INSTANCE(cm))) return;
  498. qof_commit_edit_part2 (&cm->inst, commit_err, noop, comm_free);
  499. }
  500. /********************************************************************
  501. * gnc_commodity_new
  502. ********************************************************************/
  503. static void
  504. mark_commodity_dirty (gnc_commodity *cm)
  505. {
  506. qof_instance_set_dirty(&cm->inst);
  507. qof_event_gen (&cm->inst, QOF_EVENT_MODIFY, NULL);
  508. }
  509. static void
  510. reset_printname(CommodityPrivate *priv)
  511. {
  512. g_free(priv->printname);
  513. priv->printname = g_strdup_printf("%s (%s)",
  514. priv->mnemonic ? priv->mnemonic : "",
  515. priv->fullname ? priv->fullname : "");
  516. }
  517. static void
  518. reset_unique_name(CommodityPrivate *priv)
  519. {
  520. gnc_commodity_namespace *ns;
  521. g_free(priv->unique_name);
  522. ns = priv->namespace;
  523. priv->unique_name = g_strdup_printf("%s::%s",
  524. ns ? ns->name : "",
  525. priv->mnemonic ? priv->mnemonic : "");
  526. }
  527. /* GObject Initialization */
  528. G_DEFINE_TYPE(gnc_commodity, gnc_commodity, QOF_TYPE_INSTANCE);
  529. static void
  530. gnc_commodity_init(gnc_commodity* com)
  531. {
  532. CommodityPrivate* priv;
  533. priv = GET_PRIVATE(com);
  534. priv->namespace = NULL;
  535. priv->fullname = CACHE_INSERT("");
  536. priv->mnemonic = CACHE_INSERT("");
  537. priv->cusip = CACHE_INSERT("");
  538. priv->fraction = 10000;
  539. priv->quote_flag = 0;
  540. priv->quote_source = NULL;
  541. priv->quote_tz = CACHE_INSERT("");
  542. reset_printname(priv);
  543. reset_unique_name(priv);
  544. }
  545. static void
  546. gnc_commodity_dispose(GObject *comp)
  547. {
  548. G_OBJECT_CLASS(gnc_commodity_parent_class)->dispose(comp);
  549. }
  550. static void
  551. gnc_commodity_finalize(GObject* comp)
  552. {
  553. G_OBJECT_CLASS(gnc_commodity_parent_class)->finalize(comp);
  554. }
  555. static void
  556. gnc_commodity_get_property (GObject *object,
  557. guint prop_id,
  558. GValue *value,
  559. GParamSpec *pspec)
  560. {
  561. gnc_commodity *commodity;
  562. CommodityPrivate* priv;
  563. g_return_if_fail(GNC_IS_COMMODITY(object));
  564. commodity = GNC_COMMODITY(object);
  565. priv = GET_PRIVATE(commodity);
  566. switch (prop_id)
  567. {
  568. case PROP_NAMESPACE:
  569. g_value_set_object(value, priv->namespace);
  570. break;
  571. case PROP_FULL_NAME:
  572. g_value_set_string(value, priv->fullname);
  573. break;
  574. case PROP_MNEMONIC:
  575. g_value_set_string(value, priv->mnemonic);
  576. break;
  577. case PROP_PRINTNAME:
  578. g_value_set_string(value, priv->printname);
  579. break;
  580. case PROP_CUSIP:
  581. g_value_set_string(value, priv->cusip);
  582. break;
  583. case PROP_FRACTION:
  584. g_value_set_int(value, priv->fraction);
  585. break;
  586. case PROP_UNIQUE_NAME:
  587. g_value_set_string(value, priv->unique_name);
  588. break;
  589. case PROP_QUOTE_FLAG:
  590. g_value_set_boolean(value, priv->quote_flag);
  591. break;
  592. case PROP_QUOTE_SOURCE:
  593. g_value_set_pointer(value, priv->quote_source);
  594. break;
  595. case PROP_QUOTE_TZ:
  596. g_value_set_string(value, priv->quote_tz);
  597. break;
  598. default:
  599. G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
  600. break;
  601. }
  602. }
  603. static void
  604. gnc_commodity_set_property (GObject *object,
  605. guint prop_id,
  606. const GValue *value,
  607. GParamSpec *pspec)
  608. {
  609. gnc_commodity *commodity;
  610. g_return_if_fail(GNC_IS_COMMODITY(object));
  611. commodity = GNC_COMMODITY(object);
  612. switch (prop_id)
  613. {
  614. case PROP_NAMESPACE:
  615. gnc_commodity_set_namespace(commodity, g_value_get_object(value));
  616. break;
  617. case PROP_FULL_NAME:
  618. gnc_commodity_set_fullname(commodity, g_value_get_string(value));
  619. break;
  620. case PROP_MNEMONIC:
  621. gnc_commodity_set_mnemonic(commodity, g_value_get_string(value));
  622. break;
  623. case PROP_CUSIP:
  624. gnc_commodity_set_cusip(commodity, g_value_get_string(value));
  625. break;
  626. case PROP_FRACTION:
  627. gnc_commodity_set_fraction(commodity, g_value_get_int(value));
  628. break;
  629. case PROP_QUOTE_FLAG:
  630. gnc_commodity_set_quote_flag(commodity, g_value_get_boolean(value));
  631. break;
  632. case PROP_QUOTE_SOURCE:
  633. gnc_commodity_set_quote_source(commodity, g_value_get_pointer(value));
  634. break;
  635. case PROP_QUOTE_TZ:
  636. gnc_commodity_set_quote_tz(commodity, g_value_get_string(value));
  637. break;
  638. default:
  639. G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
  640. break;
  641. }
  642. }
  643. static void
  644. gnc_commodity_class_init(struct _GncCommodityClass* klass)
  645. {
  646. GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
  647. gobject_class->dispose = gnc_commodity_dispose;
  648. gobject_class->finalize = gnc_commodity_finalize;
  649. gobject_class->set_property = gnc_commodity_set_property;
  650. gobject_class->get_property = gnc_commodity_get_property;
  651. g_type_class_add_private(klass, sizeof(CommodityPrivate));
  652. g_object_class_install_property(gobject_class,
  653. PROP_NAMESPACE,
  654. g_param_spec_object ("namespace",
  655. "Namespace",
  656. "The namespace field denotes the "
  657. "namespace for this commodity, either "
  658. "a currency or symbol from a quote source.",
  659. GNC_TYPE_COMMODITY_NAMESPACE,
  660. G_PARAM_READWRITE));
  661. g_object_class_install_property(gobject_class,
  662. PROP_FULL_NAME,
  663. g_param_spec_string ("fullname",
  664. "Full Commodity Name",
  665. "The fullname is the official full name of"
  666. "the currency.",
  667. NULL,
  668. G_PARAM_READWRITE));
  669. g_object_class_install_property(gobject_class,
  670. PROP_MNEMONIC,
  671. g_param_spec_string ("mnemonic",
  672. "Commodity Mnemonic",
  673. "The mnemonic is the official abbreviated"
  674. "designation for the currency.",
  675. NULL,
  676. G_PARAM_READWRITE));
  677. g_object_class_install_property(gobject_class,
  678. PROP_PRINTNAME,
  679. g_param_spec_string ("printname",
  680. "Commodity Print Name",
  681. "Printable form of the commodity name.",
  682. NULL,
  683. G_PARAM_READABLE));
  684. g_object_class_install_property(gobject_class,
  685. PROP_CUSIP,
  686. g_param_spec_string ("cusip",
  687. "Commodity CUSIP Code",
  688. "?????",
  689. NULL,
  690. G_PARAM_READWRITE));
  691. g_object_class_install_property(gobject_class,
  692. PROP_FRACTION,
  693. g_param_spec_int ("fraction",
  694. "Fraction",
  695. "The fraction is the number of sub-units that "
  696. "the basic commodity can be divided into.",
  697. 1,
  698. 1000000,
  699. 1,
  700. G_PARAM_READWRITE));
  701. g_object_class_install_property(gobject_class,
  702. PROP_UNIQUE_NAME,
  703. g_param_spec_string ("unique-name",
  704. "Commodity Unique Name",
  705. "Unique form of the commodity name which combines "
  706. "the namespace name and the commodity name.",
  707. NULL,
  708. G_PARAM_READABLE));
  709. g_object_class_install_property(gobject_class,
  710. PROP_QUOTE_FLAG,
  711. g_param_spec_boolean ("quote_flag",
  712. "Quote Flag",
  713. "TRUE if prices are to be downloaded for this "
  714. "commodity from a quote source.",
  715. FALSE,
  716. G_PARAM_READWRITE));
  717. g_object_class_install_property(gobject_class,
  718. PROP_QUOTE_SOURCE,
  719. g_param_spec_pointer("quote-source",
  720. "Quote Source",
  721. "The quote source from which prices are downloaded.",
  722. G_PARAM_READWRITE));
  723. g_object_class_install_property(gobject_class,
  724. PROP_QUOTE_TZ,
  725. g_param_spec_string ("quote-tz",
  726. "Commodity Quote Timezone",
  727. "?????",
  728. NULL,
  729. G_PARAM_READWRITE));
  730. }
  731. gnc_commodity *
  732. gnc_commodity_new(QofBook *book, const char * fullname,
  733. const char * namespace, const char * mnemonic,
  734. const char * cusip, int fraction)
  735. {
  736. gnc_commodity * retval = g_object_new(GNC_TYPE_COMMODITY, NULL);
  737. qof_instance_init_data (&retval->inst, GNC_ID_COMMODITY, book);
  738. gnc_commodity_begin_edit(retval);
  739. if ( namespace != NULL )
  740. {
  741. gnc_commodity_set_namespace(retval, namespace);
  742. if (gnc_commodity_namespace_is_iso(namespace))
  743. {
  744. gnc_commodity_set_quote_source(retval,
  745. gnc_quote_source_lookup_by_internal("currency") );
  746. }
  747. }
  748. gnc_commodity_set_fullname(retval, fullname);
  749. gnc_commodity_set_mnemonic(retval, mnemonic);
  750. gnc_commodity_set_cusip(retval, cusip);
  751. gnc_commodity_set_fraction(retval, fraction);
  752. gnc_commodity_commit_edit(retval);
  753. qof_event_gen (&retval->inst, QOF_EVENT_CREATE, NULL);
  754. return retval;
  755. }
  756. /********************************************************************
  757. * gnc_commodity_destroy
  758. ********************************************************************/
  759. static void
  760. commodity_free(gnc_commodity * cm)
  761. {
  762. QofBook *book;
  763. gnc_commodity_table *table;
  764. CommodityPrivate* priv;
  765. if (!cm) return;
  766. book = qof_instance_get_book(&cm->inst);
  767. table = gnc_commodity_table_get_table(book);
  768. gnc_commodity_table_remove(table, cm);
  769. priv = GET_PRIVATE(cm);
  770. qof_event_gen (&cm->inst, QOF_EVENT_DESTROY, NULL);
  771. /* Set at creation */
  772. CACHE_REMOVE (priv->fullname);
  773. CACHE_REMOVE (priv->cusip);
  774. CACHE_REMOVE (priv->mnemonic);
  775. CACHE_REMOVE (priv->quote_tz);
  776. priv->namespace = NULL;
  777. /* Set through accessor functions */
  778. priv->quote_source = NULL;
  779. /* Automatically generated */
  780. g_free(priv->printname);
  781. priv->printname = NULL;
  782. g_free(priv->unique_name);
  783. priv->unique_name = NULL;
  784. #ifdef ACCOUNTS_CLEANED_UP
  785. /* Account objects are not actually cleaned up when a book is closed (in fact
  786. * a memory leak), but commodities are, so in currently this warning gets hit
  787. * quite frequently. Disable the check until cleaning up of accounts objects
  788. * on close is implemented. */
  789. if (priv->usage_count != 0)
  790. {
  791. PWARN("Destroying commodity (%p) with non-zero usage_count (%d).", cm,
  792. priv->usage_count);
  793. }
  794. #endif
  795. /* qof_instance_release (&cm->inst); */
  796. g_object_unref(cm);
  797. }
  798. void
  799. gnc_commodity_destroy(gnc_commodity * cm)
  800. {
  801. gnc_commodity_begin_edit(cm);
  802. qof_instance_set_destroying(cm, TRUE);
  803. gnc_commodity_commit_edit(cm);
  804. }
  805. void
  806. gnc_commodity_copy(gnc_commodity * dest, const gnc_commodity *src)
  807. {
  808. CommodityPrivate* src_priv = GET_PRIVATE(src);
  809. CommodityPrivate* dest_priv = GET_PRIVATE(dest);
  810. gnc_commodity_set_fullname (dest, src_priv->fullname);
  811. gnc_commodity_set_mnemonic (dest, src_priv->mnemonic);
  812. dest_priv->namespace = src_priv->namespace;
  813. gnc_commodity_set_fraction (dest, src_priv->fraction);
  814. gnc_commodity_set_cusip (dest, src_priv->cusip);
  815. gnc_commodity_set_quote_flag (dest, src_priv->quote_flag);
  816. gnc_commodity_set_quote_source (dest, gnc_commodity_get_quote_source (src));
  817. gnc_commodity_set_quote_tz (dest, src_priv->quote_tz);
  818. kvp_frame_delete (dest->inst.kvp_data);
  819. dest->inst.kvp_data = kvp_frame_copy (src->inst.kvp_data);
  820. kvp_frame_delete (dest->inst.kvp_data);
  821. dest->inst.kvp_data = kvp_frame_copy (src->inst.kvp_data);
  822. }
  823. gnc_commodity *
  824. gnc_commodity_clone(const gnc_commodity *src, QofBook *dest_book)
  825. {
  826. CommodityPrivate* src_priv;
  827. CommodityPrivate* dest_priv;
  828. gnc_commodity * dest = g_object_new(GNC_TYPE_COMMODITY, NULL);
  829. qof_instance_init_data (&dest->inst, GNC_ID_COMMODITY, dest_book);
  830. src_priv = GET_PRIVATE(src);
  831. dest_priv = GET_PRIVATE(dest);
  832. dest_priv->fullname = CACHE_INSERT(src_priv->fullname);
  833. dest_priv->mnemonic = CACHE_INSERT(src_priv->mnemonic);
  834. dest_priv->cusip = CACHE_INSERT(src_priv->cusip);
  835. dest_priv->quote_tz = CACHE_INSERT(src_priv->quote_tz);
  836. dest_priv->namespace = src_priv->namespace;
  837. dest_priv->fraction = src_priv->fraction;
  838. dest_priv->quote_flag = src_priv->quote_flag;
  839. gnc_commodity_set_quote_source (dest, gnc_commodity_get_quote_source (src));
  840. kvp_frame_delete (dest->inst.kvp_data);
  841. dest->inst.kvp_data = kvp_frame_copy (src->inst.kvp_data);
  842. reset_printname(dest_priv);
  843. reset_unique_name(dest_priv);
  844. return dest;
  845. }
  846. /********************************************************************
  847. * gnc_commodity_get_mnemonic
  848. ********************************************************************/
  849. const char *
  850. gnc_commodity_get_mnemonic(const gnc_commodity * cm)
  851. {
  852. if (!cm) return NULL;
  853. return GET_PRIVATE(cm)->mnemonic;
  854. }
  855. /********************************************************************
  856. * gnc_commodity_get_printname
  857. ********************************************************************/
  858. const char *
  859. gnc_commodity_get_printname(const gnc_commodity * cm)
  860. {
  861. if (!cm) return NULL;
  862. return GET_PRIVATE(cm)->printname;
  863. }
  864. /********************************************************************
  865. * gnc_commodity_get_namespace
  866. ********************************************************************/
  867. const char *
  868. gnc_commodity_get_namespace(const gnc_commodity * cm)
  869. {
  870. if (!cm) return NULL;
  871. return gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->namespace);
  872. }
  873. const char *
  874. gnc_commodity_get_namespace_compat(const gnc_commodity * cm)
  875. {
  876. CommodityPrivate* priv;
  877. if (!cm) return NULL;
  878. priv = GET_PRIVATE(cm);
  879. if (!priv->namespace) return NULL;
  880. if (priv->namespace->iso4217)
  881. {
  882. /* Data files are still written with ISO4217. */
  883. return GNC_COMMODITY_NS_ISO;
  884. }
  885. return gnc_commodity_namespace_get_name(priv->namespace);
  886. }
  887. gnc_commodity_namespace *
  888. gnc_commodity_get_namespace_ds(const gnc_commodity * cm)
  889. {
  890. if (!cm) return NULL;
  891. return GET_PRIVATE(cm)->namespace;
  892. }
  893. /********************************************************************
  894. * gnc_commodity_get_fullname
  895. ********************************************************************/
  896. const char *
  897. gnc_commodity_get_fullname(const gnc_commodity * cm)
  898. {
  899. if (!cm) return NULL;
  900. return GET_PRIVATE(cm)->fullname;
  901. }
  902. /********************************************************************
  903. * gnc_commodity_get_unique_name
  904. ********************************************************************/
  905. const char *
  906. gnc_commodity_get_unique_name(const gnc_commodity * cm)
  907. {
  908. if (!cm) return NULL;
  909. return GET_PRIVATE(cm)->unique_name;
  910. }
  911. /********************************************************************
  912. * gnc_commodity_get_cusip
  913. ********************************************************************/
  914. const char *
  915. gnc_commodity_get_cusip(const gnc_commodity * cm)
  916. {
  917. if (!cm) return NULL;
  918. return GET_PRIVATE(cm)->cusip;
  919. }
  920. /********************************************************************
  921. * gnc_commodity_get_fraction
  922. ********************************************************************/
  923. int
  924. gnc_commodity_get_fraction(const gnc_commodity * cm)
  925. {
  926. if (!cm) return 0;
  927. return GET_PRIVATE(cm)->fraction;
  928. }
  929. /********************************************************************
  930. * gnc_commodity_get_auto_quote_control_flag
  931. ********************************************************************/
  932. static gboolean
  933. gnc_commodity_get_auto_quote_control_flag(const gnc_commodity *cm)
  934. {
  935. const char *str;
  936. if (!cm) return FALSE;
  937. str = kvp_frame_get_string(cm->inst.kvp_data, "auto_quote_control");
  938. return !str || (strcmp(str, "false") != 0);
  939. }
  940. /********************************************************************
  941. * gnc_commodity_get_quote_flag
  942. ********************************************************************/
  943. gboolean
  944. gnc_commodity_get_quote_flag(const gnc_commodity *cm)
  945. {
  946. if (!cm) return FALSE;
  947. return (GET_PRIVATE(cm)->quote_flag);
  948. }
  949. /********************************************************************
  950. * gnc_commodity_get_quote_source
  951. ********************************************************************/
  952. gnc_quote_source*
  953. gnc_commodity_get_quote_source(const gnc_commodity *cm)
  954. {
  955. CommodityPrivate* priv;
  956. if (!cm) return NULL;
  957. priv = GET_PRIVATE(cm);
  958. if (!priv->quote_source && gnc_commodity_is_iso(cm))
  959. return &currency_quote_source;
  960. return priv->quote_source;
  961. }
  962. gnc_quote_source*
  963. gnc_commodity_get_default_quote_source(const gnc_commodity *cm)
  964. {
  965. if (cm && gnc_commodity_is_iso(cm))
  966. return &currency_quote_source;
  967. /* Should make this a user option at some point. */
  968. return gnc_quote_source_lookup_by_internal("yahoo");
  969. }
  970. /********************************************************************
  971. * gnc_commodity_get_quote_tz
  972. ********************************************************************/
  973. const char*
  974. gnc_commodity_get_quote_tz(const gnc_commodity *cm)
  975. {
  976. if (!cm) return NULL;
  977. return GET_PRIVATE(cm)->quote_tz;
  978. }
  979. /********************************************************************
  980. * gnc_commodity_set_mnemonic
  981. ********************************************************************/
  982. void
  983. gnc_commodity_set_mnemonic(gnc_commodity * cm, const char * mnemonic)
  984. {
  985. CommodityPrivate* priv;
  986. if (!cm) return;
  987. priv = GET_PRIVATE(cm);
  988. if (priv->mnemonic == mnemonic) return;
  989. gnc_commodity_begin_edit(cm);
  990. CACHE_REMOVE (priv->mnemonic);
  991. priv->mnemonic = CACHE_INSERT(mnemonic);
  992. mark_commodity_dirty (cm);
  993. reset_printname(priv);
  994. reset_unique_name(priv);
  995. gnc_commodity_commit_edit(cm);
  996. }
  997. /********************************************************************
  998. * gnc_commodity_set_namespace
  999. ********************************************************************/
  1000. void
  1001. gnc_commodity_set_namespace(gnc_commodity * cm, const char * namespace)
  1002. {
  1003. QofBook *book;
  1004. gnc_commodity_table *table;
  1005. gnc_commodity_namespace *nsp;
  1006. CommodityPrivate* priv;
  1007. if (!cm) return;
  1008. priv = GET_PRIVATE(cm);
  1009. book = qof_instance_get_book (&cm->inst);
  1010. table = gnc_commodity_table_get_table(book);
  1011. nsp = gnc_commodity_table_add_namespace(table, namespace, book);
  1012. if (priv->namespace == nsp)
  1013. return;
  1014. gnc_commodity_begin_edit(cm);
  1015. priv->namespace = nsp;
  1016. if (nsp->iso4217)
  1017. priv->quote_source = gnc_quote_source_lookup_by_internal("currency");
  1018. mark_commodity_dirty(cm);
  1019. reset_printname(priv);
  1020. reset_unique_name(priv);
  1021. gnc_commodity_commit_edit(cm);
  1022. }
  1023. /********************************************************************
  1024. * gnc_commodity_set_fullname
  1025. ********************************************************************/
  1026. void
  1027. gnc_commodity_set_fullname(gnc_commodity * cm, const char * fullname)
  1028. {
  1029. CommodityPrivate* priv;
  1030. if (!cm) return;
  1031. priv = GET_PRIVATE(cm);
  1032. if (priv->fullname == fullname) return;
  1033. CACHE_REMOVE (priv->fullname);
  1034. priv->fullname = CACHE_INSERT (fullname);
  1035. gnc_commodity_begin_edit(cm);
  1036. mark_commodity_dirty(cm);
  1037. reset_printname(priv);
  1038. gnc_commodity_commit_edit(cm);
  1039. }
  1040. /********************************************************************
  1041. * gnc_commodity_set_cusip
  1042. ********************************************************************/
  1043. void
  1044. gnc_commodity_set_cusip(gnc_commodity * cm,
  1045. const char * cusip)
  1046. {
  1047. CommodityPrivate* priv;
  1048. if (!cm) return;
  1049. priv = GET_PRIVATE(cm);
  1050. if (priv->cusip == cusip) return;
  1051. gnc_commodity_begin_edit(cm);
  1052. CACHE_REMOVE (priv->cusip);
  1053. priv->cusip = CACHE_INSERT (cusip);
  1054. mark_commodity_dirty(cm);
  1055. gnc_commodity_commit_edit(cm);
  1056. }
  1057. /********************************************************************
  1058. * gnc_commodity_set_fraction
  1059. ********************************************************************/
  1060. void
  1061. gnc_commodity_set_fraction(gnc_commodity * cm, int fraction)
  1062. {
  1063. if (!cm) return;
  1064. gnc_commodity_begin_edit(cm);
  1065. GET_PRIVATE(cm)->fraction = fraction;
  1066. mark_commodity_dirty(cm);
  1067. gnc_commodity_commit_edit(cm);
  1068. }
  1069. /********************************************************************
  1070. * gnc_commodity_set_auto_quote_control_flag
  1071. ********************************************************************/
  1072. static void
  1073. gnc_commodity_set_auto_quote_control_flag(gnc_commodity *cm,
  1074. const gboolean flag)
  1075. {
  1076. ENTER ("(cm=%p, flag=%d)", cm, flag);
  1077. if (!cm)
  1078. {
  1079. LEAVE("");
  1080. return;
  1081. }
  1082. gnc_commodity_begin_edit(cm);
  1083. kvp_frame_set_string(cm->inst.kvp_data,
  1084. "auto_quote_control", flag ? NULL : "false");
  1085. mark_commodity_dirty(cm);
  1086. gnc_commodity_commit_edit(cm);
  1087. LEAVE("");
  1088. }
  1089. /********************************************************************
  1090. * gnc_commodity_user_set_quote_flag
  1091. ********************************************************************/
  1092. void
  1093. gnc_commodity_user_set_quote_flag(gnc_commodity *cm, const gboolean flag)
  1094. {
  1095. CommodityPrivate* priv;
  1096. ENTER ("(cm=%p, flag=%d)", cm, flag);
  1097. if (!cm)
  1098. {
  1099. LEAVE("");
  1100. return;
  1101. }
  1102. priv = GET_PRIVATE(cm);
  1103. gnc_commodity_begin_edit(cm);
  1104. gnc_commodity_set_quote_flag(cm, flag);
  1105. if (gnc_commodity_is_iso(cm))
  1106. {
  1107. /* For currencies, disable auto quote control if the quote flag is being
  1108. * changed from its default value and enable it if the quote flag is being
  1109. * reset to its default value. The defaults for the quote flag are
  1110. * disabled if no accounts are using the currency, and true otherwise.
  1111. * Thus enable auto quote control if flag is FALSE and there are not any
  1112. * accounts using this currency OR flag is TRUE and there are accounts
  1113. * using this currency; otherwise disable auto quote control */
  1114. gnc_commodity_set_auto_quote_control_flag(cm,
  1115. (!flag && (priv->usage_count == 0)) || (flag && (priv->usage_count != 0)));
  1116. }
  1117. gnc_commodity_commit_edit(cm);
  1118. LEAVE("");
  1119. }
  1120. /********************************************************************
  1121. * gnc_commodity_set_quote_flag
  1122. ********************************************************************/
  1123. void
  1124. gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
  1125. {
  1126. ENTER ("(cm=%p, flag=%d)", cm, flag);
  1127. if (!cm) return;
  1128. gnc_commodity_begin_edit(cm);
  1129. GET_PRIVATE(cm)->quote_flag = flag;
  1130. mark_commodity_dirty(cm);
  1131. gnc_commodity_commit_edit(cm);
  1132. LEAVE(" ");
  1133. }
  1134. /********************************************************************
  1135. * gnc_commodity_set_quote_source
  1136. ********************************************************************/
  1137. void
  1138. gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
  1139. {
  1140. ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->internal_name : "unknown");
  1141. if (!cm) return;
  1142. gnc_commodity_begin_edit(cm);
  1143. GET_PRIVATE(cm)->quote_source = src;
  1144. mark_commodity_dirty(cm);
  1145. gnc_commodity_commit_edit(cm);
  1146. LEAVE(" ");
  1147. }
  1148. /********************************************************************
  1149. * gnc_commodity_set_quote_tz
  1150. ********************************************************************/
  1151. void
  1152. gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz)
  1153. {
  1154. CommodityPrivate* priv;
  1155. if (!cm) return;
  1156. ENTER ("(cm=%p, tz=%s)", cm, tz ? tz : "(null)");
  1157. priv = GET_PRIVATE(cm);
  1158. if (tz == priv->quote_tz)
  1159. {
  1160. LEAVE("Already correct TZ");
  1161. return;
  1162. }
  1163. gnc_commodity_begin_edit(cm);
  1164. CACHE_REMOVE (priv->quote_tz);
  1165. priv->quote_tz = CACHE_INSERT (tz);
  1166. mark_commodity_dirty(cm);
  1167. gnc_commodity_commit_edit(cm);
  1168. LEAVE(" ");
  1169. }
  1170. /********************************************************************
  1171. * gnc_commodity_increment_usage_count
  1172. ********************************************************************/
  1173. void
  1174. gnc_commodity_increment_usage_count(gnc_commodity *cm)
  1175. {
  1176. CommodityPrivate* priv;
  1177. ENTER("(cm=%p)", cm);
  1178. if (!cm)
  1179. {
  1180. LEAVE("");
  1181. return;
  1182. }
  1183. priv = GET_PRIVATE(cm);
  1184. if ((priv->usage_count == 0) && !priv->quote_flag
  1185. && gnc_commodity_get_auto_quote_control_flag(cm)
  1186. && gnc_commodity_is_iso(cm))
  1187. {
  1188. /* compatability hack - Gnucash 1.8 gets currency quotes when a
  1189. non-default currency is assigned to an account. */
  1190. gnc_commodity_begin_edit(cm);
  1191. gnc_commodity_set_quote_flag(cm, TRUE);
  1192. gnc_commodity_set_quote_source(cm,
  1193. gnc_commodity_get_default_quote_source(cm));
  1194. gnc_commodity_commit_edit(cm);
  1195. }
  1196. priv->usage_count++;
  1197. LEAVE("(usage_count=%d)", priv->usage_count);
  1198. }
  1199. /********************************************************************
  1200. * gnc_commodity_decrement_usage_count
  1201. ********************************************************************/
  1202. void
  1203. gnc_commodity_decrement_usage_count(gnc_commodity *cm)
  1204. {
  1205. CommodityPrivate* priv;
  1206. ENTER("(cm=%p)", cm);
  1207. if (!cm)
  1208. {
  1209. LEAVE("");
  1210. return;
  1211. }
  1212. priv = GET_PRIVATE(cm);
  1213. if (priv->usage_count == 0)
  1214. {
  1215. PWARN("usage_count already zero");
  1216. LEAVE("");
  1217. return;
  1218. }
  1219. priv->usage_count--;
  1220. if ((priv->usage_count == 0) && priv->quote_flag
  1221. && gnc_commodity_get_auto_quote_control_flag(cm)
  1222. && gnc_commodity_is_iso(cm))
  1223. {
  1224. /* if this is a currency with auto quote control enabled and no more
  1225. * accounts reference this currency, disable quote retrieval */
  1226. gnc_commodity_set_quote_flag(cm, FALSE);
  1227. }
  1228. LEAVE("(usage_count=%d)", priv->usage_count);
  1229. }
  1230. /********************************************************************\
  1231. \********************************************************************/
  1232. /********************************************************************
  1233. * gnc_commodity_equiv
  1234. * are two commodities the same?
  1235. ********************************************************************/
  1236. gboolean
  1237. gnc_commodity_equiv(const gnc_commodity * a, const gnc_commodity * b)
  1238. {
  1239. CommodityPrivate* priv_a;
  1240. CommodityPrivate* priv_b;
  1241. if (a == b) return TRUE;
  1242. if (!a || !b) return FALSE;
  1243. priv_a = GET_PRIVATE(a);
  1244. priv_b = GET_PRIVATE(b);
  1245. if (priv_a->namespace != priv_b->namespace) return FALSE;
  1246. if (safe_strcmp(priv_a->mnemonic, priv_b->mnemonic) != 0) return FALSE;
  1247. return TRUE;
  1248. }
  1249. gboolean
  1250. gnc_commodity_equal(const gnc_commodity * a, const gnc_commodity * b)
  1251. {
  1252. CommodityPrivate* priv_a;
  1253. CommodityPrivate* priv_b;
  1254. gboolean same_book;
  1255. if (a == b) return TRUE;
  1256. if (!a || !b)
  1257. {
  1258. DEBUG ("one is NULL");
  1259. return FALSE;
  1260. }
  1261. priv_a = GET_PRIVATE(a);
  1262. priv_b = GET_PRIVATE(b);
  1263. same_book = qof_instance_get_book(QOF_INSTANCE(a)) == qof_instance_get_book(QOF_INSTANCE(b));
  1264. if ((same_book && priv_a->namespace != priv_b->namespace)
  1265. || (!same_book && safe_strcmp( gnc_commodity_namespace_get_name(priv_a->namespace),
  1266. gnc_commodity_namespace_get_name(priv_b->namespace)) != 0))
  1267. {
  1268. DEBUG ("namespaces differ: %p(%s) vs %p(%s)",
  1269. priv_a->namespace, gnc_commodity_namespace_get_name(priv_a->namespace),
  1270. priv_b->namespace, gnc_commodity_namespace_get_name(priv_b->namespace));
  1271. return FALSE;
  1272. }
  1273. if (safe_strcmp(priv_a->mnemonic, priv_b->mnemonic) != 0)
  1274. {
  1275. DEBUG ("mnemonics differ: %s vs %s", priv_a->mnemonic, priv_b->mnemonic);
  1276. return FALSE;
  1277. }
  1278. if (safe_strcmp(priv_a->fullname, priv_b->fullname) != 0)
  1279. {
  1280. DEBUG ("fullnames differ: %s vs %s", priv_a->fullname, priv_b->fullname);
  1281. return FALSE;
  1282. }
  1283. if (safe_strcmp(priv_a->cusip, priv_b->cusip) != 0)
  1284. {
  1285. DEBUG ("cusips differ: %s vs %s", priv_a->cusip, priv_b->cusip);
  1286. return FALSE;
  1287. }
  1288. if (priv_a->fraction != priv_b->fraction)
  1289. {
  1290. DEBUG ("fractions differ: %d vs %d", priv_a->fraction, priv_b->fraction);
  1291. return FALSE;
  1292. }
  1293. return TRUE;
  1294. }
  1295. int gnc_commodity_compare(const gnc_commodity * a, const gnc_commodity * b)
  1296. {
  1297. if (gnc_commodity_equal(a, b))
  1298. {
  1299. return 0;
  1300. }
  1301. else
  1302. {
  1303. return 1;
  1304. }
  1305. }
  1306. int gnc_commodity_compare_void(const void * a, const void * b)
  1307. {
  1308. return gnc_commodity_compare(a, b);
  1309. }
  1310. /************************************************************
  1311. * Namespace functions *
  1312. ************************************************************/
  1313. const char *
  1314. gnc_commodity_namespace_get_name (const gnc_commodity_namespace *ns)
  1315. {
  1316. if (ns == NULL)
  1317. return NULL;
  1318. return ns->name;
  1319. }
  1320. GList *
  1321. gnc_commodity_namespace_get_commodity_list(const gnc_commodity_namespace *namespace)
  1322. {
  1323. if (!namespace)
  1324. return NULL;
  1325. return namespace->cm_list;
  1326. }
  1327. gboolean
  1328. gnc_commodity_namespace_is_iso(const char *namespace)
  1329. {
  1330. return ((safe_strcmp(namespace, GNC_COMMODITY_NS_ISO) == 0) ||
  1331. (safe_strcmp(namespace, GNC_COMMODITY_NS_CURRENCY) == 0));
  1332. }
  1333. static const gchar *
  1334. gnc_commodity_table_map_namespace(const char * namespace)
  1335. {
  1336. if (safe_strcmp(namespace, GNC_COMMODITY_NS_ISO) == 0)
  1337. return GNC_COMMODITY_NS_CURRENCY;
  1338. return namespace;
  1339. }
  1340. /********************************************************************
  1341. * gnc_commodity_table_new
  1342. * make a new commodity table
  1343. ********************************************************************/
  1344. gnc_commodity_table *
  1345. gnc_commodity_table_new(void)
  1346. {
  1347. gnc_commodity_table * retval = g_new0(gnc_commodity_table, 1);
  1348. retval->ns_table = g_hash_table_new(&g_str_hash, &g_str_equal);
  1349. retval->ns_list = NULL;
  1350. return retval;
  1351. }
  1352. /********************************************************************
  1353. * book anchor functons
  1354. ********************************************************************/
  1355. gnc_commodity_table *
  1356. gnc_commodity_table_get_table(QofBook *book)
  1357. {
  1358. if (!book) return NULL;
  1359. return qof_book_get_data (book, GNC_COMMODITY_TABLE);
  1360. }
  1361. gnc_commodity *
  1362. gnc_commodity_obtain_twin (const gnc_commodity *from, QofBook *book)
  1363. {
  1364. gnc_commodity *twin;
  1365. const char * ucom;
  1366. gnc_commodity_table * comtbl;
  1367. if (!from) return NULL;
  1368. comtbl = gnc_commodity_table_get_table (book);
  1369. if (!comtbl) return NULL;
  1370. ucom = gnc_commodity_get_unique_name (from);
  1371. twin = gnc_commodity_table_lookup_unique (comtbl, ucom);
  1372. if (!twin)
  1373. {
  1374. twin = gnc_commodity_clone (from, book);
  1375. twin = gnc_commodity_table_insert (comtbl, twin);
  1376. }
  1377. return twin;
  1378. }
  1379. /********************************************************************
  1380. * gnc_commodity_table_get_size
  1381. * get the size of the commodity table
  1382. ********************************************************************/
  1383. guint
  1384. gnc_commodity_table_get_number_of_namespaces(const gnc_commodity_table* tbl)
  1385. {
  1386. g_return_val_if_fail(tbl, 0);
  1387. g_return_val_if_fail(tbl->ns_table, 0);
  1388. return g_hash_table_size(tbl->ns_table);
  1389. }
  1390. static void
  1391. count_coms(gpointer key, gpointer value, gpointer user_data)
  1392. {
  1393. GHashTable *tbl = ((gnc_commodity_namespace*)value)->cm_table;
  1394. guint *count = (guint*)user_data;
  1395. if (safe_strcmp((char*)key, GNC_COMMODITY_NS_CURRENCY) == 0)
  1396. {
  1397. /* don't count default commodities */
  1398. return;
  1399. }
  1400. if (!value) return;
  1401. *count += g_hash_table_size(tbl);
  1402. }
  1403. guint
  1404. gnc_commodity_table_get_size(const gnc_commodity_table* tbl)
  1405. {
  1406. guint count = 0;
  1407. g_return_val_if_fail(tbl, 0);
  1408. g_return_val_if_fail(tbl->ns_table, 0);
  1409. g_hash_table_foreach(tbl->ns_table, count_coms, (gpointer)&count);
  1410. return count;
  1411. }
  1412. /********************************************************************
  1413. * gnc_commodity_table_lookup
  1414. * locate a commodity by namespace and mnemonic.
  1415. ********************************************************************/
  1416. gnc_commodity *
  1417. gnc_commodity_table_lookup(const gnc_commodity_table * table,
  1418. const char * namespace, const char * mnemonic)
  1419. {
  1420. gnc_commodity_namespace * nsp = NULL;
  1421. unsigned int i;
  1422. if (!table || !namespace || !mnemonic) return NULL;
  1423. nsp = gnc_commodity_table_find_namespace(table, namespace);
  1424. if (nsp)
  1425. {
  1426. /*
  1427. * Backward compatability support for currencies that have
  1428. * recently changed.
  1429. */
  1430. if (nsp->iso4217)
  1431. {
  1432. for (i = 0; i < GNC_NEW_ISO_CODES; i++)
  1433. {
  1434. if (strcmp(mnemonic, gnc_new_iso_codes[i].old_code) == 0)
  1435. {
  1436. mnemonic = gnc_new_iso_codes[i].new_code;
  1437. break;
  1438. }
  1439. }
  1440. }
  1441. return g_hash_table_lookup(nsp->cm_table, (gpointer)mnemonic);
  1442. }
  1443. else
  1444. {
  1445. return NULL;
  1446. }
  1447. }
  1448. /********************************************************************
  1449. * gnc_commodity_table_lookup
  1450. * locate a commodity by unique name.
  1451. ********************************************************************/
  1452. gnc_commodity *
  1453. gnc_commodity_table_lookup_unique(const gnc_commodity_table *table,
  1454. const char * unique_name)
  1455. {
  1456. char *namespace;
  1457. char *mnemonic;
  1458. gnc_commodity *commodity;
  1459. if (!table || !unique_name) return NULL;
  1460. namespace = g_strdup (unique_name);
  1461. mnemonic = strstr (namespace, "::");
  1462. if (!mnemonic)
  1463. {
  1464. g_free (namespace);
  1465. return NULL;
  1466. }
  1467. *mnemonic = '\0';
  1468. mnemonic += 2;
  1469. commodity = gnc_commodity_table_lookup (table, namespace, mnemonic);
  1470. g_free (namespace);
  1471. return commodity;
  1472. }
  1473. /********************************************************************
  1474. * gnc_commodity_table_find_full
  1475. * locate a commodity by namespace and printable name
  1476. ********************************************************************/
  1477. gnc_commodity *
  1478. gnc_commodity_table_find_full(const gnc_commodity_table * table,
  1479. const char * namespace,
  1480. const char * fullname)
  1481. {
  1482. gnc_commodity * retval = NULL;
  1483. GList * all;
  1484. GList * iterator;
  1485. if (!fullname || (fullname[0] == '\0'))
  1486. return NULL;
  1487. all = gnc_commodity_table_get_commodities(table, namespace);
  1488. for (iterator = all; iterator; iterator = iterator->next)
  1489. {
  1490. if (!strcmp(fullname,
  1491. gnc_commodity_get_printname(iterator->data)))
  1492. {
  1493. retval = iterator->data;
  1494. break;
  1495. }
  1496. }
  1497. g_list_free (all);
  1498. return retval;
  1499. }
  1500. /********************************************************************
  1501. * gnc_commodity_table_insert
  1502. * add a commodity to the table.
  1503. ********************************************************************/
  1504. gnc_commodity *
  1505. gnc_commodity_table_insert(gnc_commodity_table * table,
  1506. gnc_commodity * comm)
  1507. {
  1508. gnc_commodity_namespace * nsp = NULL;
  1509. gnc_commodity *c;
  1510. const char *ns_name;
  1511. CommodityPrivate* priv;
  1512. QofBook *book;
  1513. if (!table) return NULL;
  1514. if (!comm) return NULL;
  1515. priv = GET_PRIVATE(comm);
  1516. ENTER ("(table=%p, comm=%p) %s %s", table, comm,
  1517. (priv->mnemonic == NULL ? "(null)" : priv->mnemonic),
  1518. (priv->fullname == NULL ? "(null)" : priv->fullname));
  1519. ns_name = gnc_commodity_namespace_get_name(priv->namespace);
  1520. c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
  1521. if (c)
  1522. {
  1523. if (c == comm)
  1524. {
  1525. LEAVE("already in table");
  1526. return c;
  1527. }
  1528. /* Backward compatability support for currencies that have
  1529. * recently changed. */
  1530. if (priv->namespace->iso4217)
  1531. {
  1532. guint i;
  1533. for (i = 0; i < GNC_NEW_ISO_CODES; i++)
  1534. {
  1535. if (!priv->mnemonic
  1536. || !strcmp(priv->mnemonic, gnc_new_iso_codes[i].old_code))
  1537. {
  1538. gnc_commodity_set_mnemonic(comm, gnc_new_iso_codes[i].new_code);
  1539. break;
  1540. }
  1541. }
  1542. }
  1543. gnc_commodity_copy (c, comm);
  1544. gnc_commodity_destroy (comm);
  1545. LEAVE("found at %p", c);
  1546. return c;
  1547. }
  1548. book = qof_instance_get_book (&comm->inst);
  1549. nsp = gnc_commodity_table_add_namespace(table, ns_name, book);
  1550. PINFO ("insert %p %s into nsp=%p %s", priv->mnemonic, priv->mnemonic,
  1551. nsp->cm_table, nsp->name);
  1552. g_hash_table_insert(nsp->cm_table,
  1553. CACHE_INSERT(priv->mnemonic),
  1554. (gpointer)comm);
  1555. nsp->cm_list = g_list_append(nsp->cm_list, comm);
  1556. qof_event_gen (&comm->inst, QOF_EVENT_ADD, NULL);
  1557. LEAVE ("(table=%p, comm=%p)", table, comm);
  1558. return comm;
  1559. }
  1560. /********************************************************************
  1561. * gnc_commodity_table_remove
  1562. * remove a commodity from the table.
  1563. ********************************************************************/
  1564. void
  1565. gnc_commodity_table_remove(gnc_commodity_table * table,
  1566. gnc_commodity * comm)
  1567. {
  1568. gnc_commodity_namespace * nsp;
  1569. gnc_commodity *c;
  1570. CommodityPrivate* priv;
  1571. const char *ns_name;
  1572. if (!table) return;
  1573. if (!comm) return;
  1574. priv = GET_PRIVATE(comm);
  1575. ns_name = gnc_commodity_namespace_get_name(priv->namespace);
  1576. c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
  1577. if (c != comm) return;
  1578. qof_event_gen (&comm->inst, QOF_EVENT_REMOVE, NULL);
  1579. nsp = gnc_commodity_table_find_namespace(table, ns_name);
  1580. if (!nsp) return;
  1581. nsp->cm_list = g_list_remove(nsp->cm_list, comm);
  1582. g_hash_table_remove (nsp->cm_table, priv->mnemonic);
  1583. /* XXX minor mem leak, should remove the key as well */
  1584. }
  1585. /********************************************************************
  1586. * gnc_commodity_table_has_namespace
  1587. * see if the commodities namespace exists. May have zero commodities.
  1588. ********************************************************************/
  1589. int
  1590. gnc_commodity_table_has_namespace(const gnc_commodity_table * table,
  1591. const char * namespace)
  1592. {
  1593. gnc_commodity_namespace * nsp = NULL;
  1594. if (!table || !namespace)
  1595. {
  1596. return 0;
  1597. }
  1598. nsp = gnc_commodity_table_find_namespace(table, namespace);
  1599. if (nsp)
  1600. {
  1601. return 1;
  1602. }
  1603. else
  1604. {
  1605. return 0;
  1606. }
  1607. }
  1608. static void
  1609. hash_keys_helper(gpointer key, gpointer value, gpointer data)
  1610. {
  1611. GList ** l = data;
  1612. *l = g_list_prepend(*l, key);
  1613. }
  1614. static GList *
  1615. g_hash_table_keys(GHashTable * table)
  1616. {
  1617. GList * l = NULL;
  1618. g_hash_table_foreach(table, &hash_keys_helper, (gpointer) &l);
  1619. return l;
  1620. }
  1621. static void
  1622. hash_values_helper(gpointer key, gpointer value, gpointer data)
  1623. {
  1624. GList ** l = data;
  1625. *l = g_list_prepend(*l, value);
  1626. }
  1627. static GList *
  1628. g_hash_table_values(GHashTable * table)
  1629. {
  1630. GList * l = NULL;
  1631. g_hash_table_foreach(table, &hash_values_helper, (gpointer) &l);
  1632. return l;
  1633. }
  1634. /********************************************************************
  1635. * gnc_commodity_table_get_namespaces
  1636. * see if any commodities in the namespace exist
  1637. ********************************************************************/
  1638. GList *
  1639. gnc_commodity_table_get_namespaces(const gnc_commodity_table * table)
  1640. {
  1641. if (!table)
  1642. return NULL;
  1643. return g_hash_table_keys(table->ns_table);
  1644. }
  1645. GList *
  1646. gnc_commodity_table_get_namespaces_list(const gnc_commodity_table * table)
  1647. {
  1648. if (!table)
  1649. return NULL;
  1650. return table->ns_list;
  1651. }
  1652. /* Because gnc_commodity_table_add_namespace maps GNC_COMMODITY_NS_ISO to
  1653. GNC_COMMODITY_NS_CURRENCY and then sets iso4217 if the namespace is
  1654. either of these, the net result is that the iso4217 bit is set only
  1655. for GNC_COMMODITY_NS_CURRENCY. This means that gnc_commodity_is_iso is
  1656. a subset of gnc_commodity_is_currency. Most callers seem to use
  1657. gnc_commodity_is_iso. */
  1658. gboolean
  1659. gnc_commodity_is_iso(const gnc_commodity * cm)
  1660. {
  1661. CommodityPrivate* priv;
  1662. if (!cm) return FALSE;
  1663. priv = GET_PRIVATE(cm);
  1664. if ( !priv->namespace) return FALSE;
  1665. return priv->namespace->iso4217;
  1666. }
  1667. gboolean
  1668. gnc_commodity_is_currency(const gnc_commodity *cm)
  1669. {
  1670. const char *ns_name;
  1671. if (!cm) return FALSE;
  1672. ns_name = gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->namespace);
  1673. return (!safe_strcmp(ns_name, GNC_COMMODITY_NS_LEGACY) ||
  1674. !safe_strcmp(ns_name, GNC_COMMODITY_NS_CURRENCY));
  1675. }
  1676. /********************************************************************
  1677. * gnc_commodity_table_get_commodities
  1678. * list commodities in a give namespace
  1679. ********************************************************************/
  1680. CommodityList *
  1681. gnc_commodity_table_get_commodities(const gnc_commodity_table * table,
  1682. const char * namespace)
  1683. {
  1684. gnc_commodity_namespace * ns = NULL;
  1685. if (!table)
  1686. return NULL;
  1687. ns = gnc_commodity_table_find_namespace(table, namespace);
  1688. if (!ns)
  1689. return NULL;
  1690. return g_hash_table_values(ns->cm_table);
  1691. }
  1692. /********************************************************************
  1693. * gnc_commodity_table_get_quotable_commodities
  1694. * list commodities in a given namespace that get price quotes
  1695. ********************************************************************/
  1696. static void
  1697. get_quotables_helper1(gpointer key, gpointer value, gpointer data)
  1698. {
  1699. gnc_commodity *comm = value;
  1700. CommodityPrivate* priv = GET_PRIVATE(comm);
  1701. GList ** l = data;
  1702. if (!priv->quote_flag ||
  1703. !priv->quote_source || !priv->quote_source->supported)
  1704. return;
  1705. *l = g_list_prepend(*l, value);
  1706. }
  1707. static gboolean
  1708. get_quotables_helper2 (gnc_commodity *comm, gpointer data)
  1709. {
  1710. GList ** l = data;
  1711. CommodityPrivate* priv = GET_PRIVATE(comm);
  1712. if (!priv->quote_flag ||
  1713. !priv->quote_source || !priv->quote_source->supported)
  1714. return TRUE;
  1715. *l = g_list_prepend(*l, comm);
  1716. return TRUE;
  1717. }
  1718. CommodityList *
  1719. gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table)
  1720. {
  1721. gnc_commodity_namespace * ns = NULL;
  1722. const char *namespace;
  1723. GList * nslist, * tmp;
  1724. GList * l = NULL;
  1725. regex_t pattern;
  1726. const char *expression = gnc_main_get_namespace_regexp();
  1727. ENTER("table=%p, expression=%s", table, expression);
  1728. if (!table)
  1729. return NULL;
  1730. if (expression && *expression)
  1731. {
  1732. if (regcomp(&pattern, expression, REG_EXTENDED | REG_ICASE) != 0)
  1733. {
  1734. LEAVE("Cannot compile regex");
  1735. return NULL;
  1736. }
  1737. nslist = gnc_commodity_table_get_namespaces(table);
  1738. for (tmp = nslist; tmp; tmp = tmp->next)
  1739. {
  1740. namespace = tmp->data;
  1741. if (regexec(&pattern, namespace, 0, NULL, 0) == 0)
  1742. {
  1743. DEBUG("Running list of %s commodities", namespace);
  1744. ns = gnc_commodity_table_find_namespace(table, namespace);
  1745. if (ns)
  1746. {
  1747. g_hash_table_foreach(ns->cm_table, &get_quotables_helper1, (gpointer) &l);
  1748. }
  1749. }
  1750. }
  1751. g_list_free(nslist);
  1752. regfree(&pattern);
  1753. }
  1754. else
  1755. {
  1756. gnc_commodity_table_foreach_commodity(table, get_quotables_helper2,
  1757. (gpointer) &l);
  1758. }
  1759. LEAVE("list head %p", l);
  1760. return l;
  1761. }
  1762. /********************************************************************
  1763. * gnc_commodity_table_add_namespace
  1764. * add an empty namespace if it does not exist
  1765. ********************************************************************/
  1766. /* GObject Initialization */
  1767. QOF_GOBJECT_IMPL(gnc_commodity_namespace, gnc_commodity_namespace, QOF_TYPE_INSTANCE);
  1768. static void
  1769. gnc_commodity_namespace_init(gnc_commodity_namespace* ns)
  1770. {
  1771. }
  1772. static void
  1773. gnc_commodity_namespace_dispose_real (GObject *nsp)
  1774. {
  1775. }
  1776. static void
  1777. gnc_commodity_namespace_finalize_real(GObject* nsp)
  1778. {
  1779. }
  1780. gnc_commodity_namespace *
  1781. gnc_commodity_table_add_namespace(gnc_commodity_table * table,
  1782. const char * namespace,
  1783. QofBook *book)
  1784. {
  1785. gnc_commodity_namespace * ns = NULL;
  1786. if (!table) return NULL;
  1787. namespace = gnc_commodity_table_map_namespace(namespace);
  1788. ns = gnc_commodity_table_find_namespace(table, namespace);
  1789. if (!ns)
  1790. {
  1791. ns = g_object_new(GNC_TYPE_COMMODITY_NAMESPACE, NULL);
  1792. ns->cm_table = g_hash_table_new(g_str_hash, g_str_equal);
  1793. ns->name = CACHE_INSERT((gpointer)namespace);
  1794. ns->iso4217 = gnc_commodity_namespace_is_iso(namespace);
  1795. qof_instance_init_data (&ns->inst, GNC_ID_COMMODITY_NAMESPACE, book);
  1796. qof_event_gen (&ns->inst, QOF_EVENT_CREATE, NULL);
  1797. g_hash_table_insert(table->ns_table,
  1798. (gpointer) ns->name,
  1799. (gpointer) ns);
  1800. table->ns_list = g_list_append(table->ns_list, ns);
  1801. qof_event_gen (&ns->inst, QOF_EVENT_ADD, NULL);
  1802. }
  1803. return ns;
  1804. }
  1805. gnc_commodity_namespace *
  1806. gnc_commodity_table_find_namespace(const gnc_commodity_table * table,
  1807. const char * namespace)
  1808. {
  1809. if (!table || !namespace)
  1810. return NULL;
  1811. namespace = gnc_commodity_table_map_namespace(namespace);
  1812. return g_hash_table_lookup(table->ns_table, (gpointer)namespace);
  1813. }
  1814. gnc_commodity *
  1815. gnc_commodity_find_commodity_by_guid(const GncGUID *guid, QofBook *book)
  1816. {
  1817. QofCollection *col;
  1818. if (!guid || !book) return NULL;
  1819. col = qof_book_get_collection (book, GNC_ID_COMMODITY);
  1820. return (gnc_commodity *) qof_collection_lookup_entity (col, guid);
  1821. }
  1822. gnc_commodity_namespace *
  1823. gnc_commodity_find_namespace_by_guid(const GncGUID *guid, QofBook *book)
  1824. {
  1825. QofCollection *col;
  1826. if (!guid || !book) return NULL;
  1827. col = qof_book_get_collection (book, GNC_ID_COMMODITY_NAMESPACE);
  1828. return (gnc_commodity_namespace *) qof_collection_lookup_entity (col, guid);
  1829. }
  1830. /********************************************************************
  1831. * gnc_commodity_table_delete_namespace
  1832. * delete a namespace
  1833. ********************************************************************/
  1834. static int
  1835. ns_helper(gpointer key, gpointer value, gpointer user_data)
  1836. {
  1837. gnc_commodity * c = value;
  1838. gnc_commodity_destroy(c);
  1839. CACHE_REMOVE(key); /* key is commodity mnemonic */
  1840. return TRUE;
  1841. }
  1842. void
  1843. gnc_commodity_table_delete_namespace(gnc_commodity_table * table,
  1844. const char * namespace)
  1845. {
  1846. gnc_commodity_namespace * ns;
  1847. if (!table) return;
  1848. ns = gnc_commodity_table_find_namespace(table, namespace);
  1849. if (!ns)
  1850. return;
  1851. qof_event_gen (&ns->inst, QOF_EVENT_REMOVE, NULL);
  1852. g_hash_table_remove(table->ns_table, namespace);
  1853. table->ns_list = g_list_remove(table->ns_list, ns);
  1854. g_list_free(ns->cm_list);
  1855. ns->cm_list = NULL;
  1856. g_hash_table_foreach_remove(ns->cm_table, ns_helper, NULL);
  1857. g_hash_table_destroy(ns->cm_table);
  1858. CACHE_REMOVE(ns->name);
  1859. qof_event_gen (&ns->inst, QOF_EVENT_DESTROY, NULL);
  1860. /* qof_instance_release(&ns->inst); */
  1861. g_object_unref(ns);
  1862. }
  1863. /********************************************************************
  1864. * gnc_commodity_table_foreach_commodity
  1865. * call user-defined function once for every commodity in every
  1866. * namespace
  1867. ********************************************************************/
  1868. typedef struct
  1869. {
  1870. gboolean ok;
  1871. gboolean (*func)(gnc_commodity *, gpointer);
  1872. gpointer user_data;
  1873. } IterData;
  1874. static void
  1875. iter_commodity (gpointer key, gpointer value, gpointer user_data)
  1876. {
  1877. IterData *iter_data = (IterData *) user_data;
  1878. gnc_commodity *cm = (gnc_commodity *) value;
  1879. if (iter_data->ok)
  1880. {
  1881. iter_data->ok = (iter_data->func)(cm, iter_data->user_data);
  1882. }
  1883. }
  1884. static void
  1885. iter_namespace (gpointer key, gpointer value, gpointer user_data)
  1886. {
  1887. GHashTable *namespace_hash = ((gnc_commodity_namespace *) value)->cm_table;
  1888. g_hash_table_foreach (namespace_hash, iter_commodity, user_data);
  1889. }
  1890. gboolean
  1891. gnc_commodity_table_foreach_commodity (const gnc_commodity_table * tbl,
  1892. gboolean (*f)(gnc_commodity *, gpointer),
  1893. gpointer user_data)
  1894. {
  1895. IterData iter_data;
  1896. if (!tbl || !f) return FALSE;
  1897. iter_data.ok = TRUE;
  1898. iter_data.func = f;
  1899. iter_data.user_data = user_data;
  1900. g_hash_table_foreach(tbl->ns_table, iter_namespace, (gpointer)&iter_data);
  1901. return iter_data.ok;
  1902. }
  1903. /********************************************************************
  1904. * gnc_commodity_table_destroy
  1905. * cleanup and free.
  1906. ********************************************************************/
  1907. void
  1908. gnc_commodity_table_destroy(gnc_commodity_table * t)
  1909. {
  1910. gnc_commodity_namespace * ns;
  1911. GList *item, *next;
  1912. if (!t) return;
  1913. ENTER ("table=%p", t);
  1914. for (item = t->ns_list; item; item = next)
  1915. {
  1916. next = g_list_next(item);
  1917. ns = item->data;
  1918. gnc_commodity_table_delete_namespace(t, ns->name);
  1919. }
  1920. g_list_free(t->ns_list);
  1921. t->ns_list = NULL;
  1922. g_hash_table_destroy(t->ns_table);
  1923. t->ns_table = NULL;
  1924. g_free(t);
  1925. LEAVE ("table=%p", t);
  1926. }
  1927. /* =========================================================== */
  1928. static gboolean
  1929. table_equal_helper (gnc_commodity *cm_1, gpointer user_data)
  1930. {
  1931. gnc_commodity_table *t_2 = user_data;
  1932. gnc_commodity *cm_2;
  1933. cm_2 = gnc_commodity_table_lookup (t_2,
  1934. gnc_commodity_get_namespace (cm_1),
  1935. gnc_commodity_get_mnemonic (cm_1));
  1936. if (!cm_2)
  1937. {
  1938. PWARN ("one has commodity %s, the other does not",
  1939. gnc_commodity_get_unique_name (cm_1));
  1940. return FALSE;
  1941. }
  1942. return gnc_commodity_equal (cm_1, cm_2);
  1943. }
  1944. gboolean
  1945. gnc_commodity_table_equal(gnc_commodity_table *t_1,
  1946. gnc_commodity_table *t_2)
  1947. {
  1948. gboolean ok;
  1949. if (t_1 == t_2) return TRUE;
  1950. if (!t_1 || !t_2) return FALSE;
  1951. ok = gnc_commodity_table_foreach_commodity (t_1, table_equal_helper, t_2);
  1952. if (!ok)
  1953. return FALSE;
  1954. return gnc_commodity_table_foreach_commodity (t_2, table_equal_helper, t_1);
  1955. }
  1956. /* =========================================================== */
  1957. typedef struct
  1958. {
  1959. gnc_commodity_table *dest;
  1960. QofBook *dest_book;
  1961. } table_copy_helper_data;
  1962. static gboolean
  1963. table_copy_helper (gnc_commodity *src_cm, gpointer user_data)
  1964. {
  1965. table_copy_helper_data *data = user_data;
  1966. gnc_commodity_table_insert (data->dest,
  1967. gnc_commodity_clone (src_cm, data->dest_book));
  1968. return TRUE;
  1969. }
  1970. void
  1971. gnc_commodity_table_copy(gnc_commodity_table *dest,
  1972. gnc_commodity_table *src,
  1973. QofBook *dest_book)
  1974. {
  1975. table_copy_helper_data data = {dest, dest_book};
  1976. gnc_commodity_table_foreach_commodity (src, table_copy_helper, &data);
  1977. }
  1978. /********************************************************************
  1979. * gnc_commodity_table_add_default_data
  1980. ********************************************************************/
  1981. #define CUR_I18N(String) dgettext ("iso_4217", String)
  1982. gboolean
  1983. gnc_commodity_table_add_default_data(gnc_commodity_table *table, QofBook *book)
  1984. {
  1985. QofCollection *col;
  1986. gnc_commodity* c;
  1987. ENTER ("table=%p", table);
  1988. gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_AMEX, book);
  1989. gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_NYSE, book);
  1990. gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_NASDAQ, book);
  1991. gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_EUREX, book);
  1992. gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_MUTUAL, book);
  1993. gnc_commodity_table_add_namespace(table, "template", book);
  1994. c = gnc_commodity_new(book, "template", "template", "template", "template", 1);
  1995. gnc_commodity_table_insert(table, c);
  1996. #include "iso-4217-currencies.c"
  1997. /* We've just created the default namespaces and currencies. Mark
  1998. * these collections as clean because there is no USER entered data
  1999. * in these collections as of yet. */
  2000. col = qof_book_get_collection(book, GNC_ID_COMMODITY);
  2001. qof_collection_mark_clean(col);
  2002. col = qof_book_get_collection(book, GNC_ID_COMMODITY_NAMESPACE);
  2003. qof_collection_mark_clean(col);
  2004. LEAVE ("table=%p", table);
  2005. return TRUE;
  2006. }
  2007. /********************************************************************
  2008. ********************************************************************/
  2009. /* QofObject function implementation and registration */
  2010. #ifdef _MSC_VER
  2011. /* MSVC compiler doesn't have C99 "designated initializers"
  2012. * so we wrap them in a macro that is empty on MSVC. */
  2013. # define DI(x) /* */
  2014. #else
  2015. # define DI(x) x
  2016. #endif
  2017. static QofObject commodity_object_def =
  2018. {
  2019. DI(.interface_version = ) QOF_OBJECT_VERSION,
  2020. DI(.e_type = ) GNC_ID_COMMODITY,
  2021. DI(.type_label = ) "Commodity",
  2022. DI(.create = ) NULL,
  2023. DI(.book_begin = ) NULL,
  2024. DI(.book_end = ) NULL,
  2025. DI(.is_dirty = ) qof_collection_is_dirty,
  2026. DI(.mark_clean = ) qof_collection_mark_clean,
  2027. DI(.foreach = ) qof_collection_foreach,
  2028. DI(.printable = ) (const char * (*)(gpointer)) gnc_commodity_get_fullname,
  2029. };
  2030. static QofObject namespace_object_def =
  2031. {
  2032. DI(.interface_version = ) QOF_OBJECT_VERSION,
  2033. DI(.e_type = ) GNC_ID_COMMODITY_NAMESPACE,
  2034. DI(.type_label = ) "Namespace",
  2035. DI(.create = ) NULL,
  2036. DI(.book_begin = ) NULL,
  2037. DI(.book_end = ) NULL,
  2038. DI(.is_dirty = ) NULL,
  2039. DI(.mark_clean = ) NULL,
  2040. DI(.foreach = ) NULL,
  2041. DI(.printable = ) NULL,
  2042. };
  2043. static void
  2044. commodity_table_book_begin (QofBook *book)
  2045. {
  2046. gnc_commodity_table *ct;
  2047. ENTER ("book=%p", book);
  2048. if (gnc_commodity_table_get_table(book))
  2049. return;
  2050. ct = gnc_commodity_table_new ();
  2051. qof_book_set_data (book, GNC_COMMODITY_TABLE, ct);
  2052. if (!gnc_commodity_table_add_default_data(ct, book))
  2053. {
  2054. PWARN("unable to initialize book's commodity_table");
  2055. }
  2056. LEAVE ("book=%p", book);
  2057. }
  2058. static void
  2059. commodity_table_book_end (QofBook *book)
  2060. {
  2061. gnc_commodity_table *ct;
  2062. ct = gnc_commodity_table_get_table (book);
  2063. qof_book_set_data (book, GNC_COMMODITY_TABLE, NULL);
  2064. gnc_commodity_table_destroy (ct);
  2065. }
  2066. static QofObject commodity_table_object_def =
  2067. {
  2068. DI(.interface_version = ) QOF_OBJECT_VERSION,
  2069. DI(.e_type = ) GNC_ID_COMMODITY_TABLE,
  2070. DI(.type_label = ) "CommodityTable",
  2071. DI(.create = ) NULL,
  2072. DI(.book_begin = ) commodity_table_book_begin,
  2073. DI(.book_end = ) commodity_table_book_end,
  2074. DI(.is_dirty = ) qof_collection_is_dirty,
  2075. DI(.mark_clean = ) qof_collection_mark_clean,
  2076. DI(.foreach = ) NULL,
  2077. DI(.printable = ) NULL,
  2078. DI(.version_cmp = ) NULL,
  2079. };
  2080. gboolean
  2081. gnc_commodity_table_register (void)
  2082. {
  2083. gnc_quote_source_init_tables();
  2084. if (!qof_object_register (&commodity_object_def))
  2085. return FALSE;
  2086. if (!qof_object_register (&namespace_object_def))
  2087. return FALSE;
  2088. return qof_object_register (&commodity_table_object_def);
  2089. }
  2090. /* *******************************************************************
  2091. * gnc_monetary methods
  2092. ********************************************************************/
  2093. /** Add a gnc_monetary to the list */
  2094. MonetaryList *
  2095. gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
  2096. {
  2097. MonetaryList *l = list, *tmp;
  2098. for (tmp = list; tmp; tmp = tmp->next)
  2099. {
  2100. gnc_monetary *list_mon = tmp->data;
  2101. if (gnc_commodity_equiv(list_mon->commodity, add_mon.commodity))
  2102. {
  2103. list_mon->value = gnc_numeric_add(list_mon->value, add_mon.value,
  2104. GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
  2105. break;
  2106. }
  2107. }
  2108. /* See if we found an entry, and add one if not */
  2109. if (tmp == NULL)
  2110. {
  2111. gnc_monetary *new_mon = g_new0(gnc_monetary, 1);
  2112. *new_mon = add_mon;
  2113. l = g_list_prepend(l, new_mon);
  2114. }
  2115. return l;
  2116. }
  2117. /** Delete all entries in the list that have zero value. Return list
  2118. pointer will be a null pointer if there are no non-zero entries **/
  2119. MonetaryList *
  2120. gnc_monetary_list_delete_zeros(MonetaryList *list)
  2121. {
  2122. MonetaryList *node, *next;
  2123. for (node = list; node; node = next)
  2124. {
  2125. gnc_monetary *mon = node->data;
  2126. next = node->next;
  2127. if (gnc_numeric_zero_p(mon->value))
  2128. {
  2129. g_free(mon);
  2130. list = g_list_delete_link(list, node);
  2131. }
  2132. }
  2133. return list;
  2134. }
  2135. /** Free a MonetaryList and all the monetaries it points to */
  2136. void
  2137. gnc_monetary_list_free(MonetaryList *list)
  2138. {
  2139. MonetaryList *tmp;
  2140. for (tmp = list; tmp; tmp = tmp->next)
  2141. {
  2142. g_free(tmp->data);
  2143. }
  2144. g_list_free(list);
  2145. }
  2146. /* ========================= END OF FILE ============================== */