29 #include "gnc-pricedb-p.h"
53 G_DEFINE_TYPE(
GNCPrice, gnc_price, QOF_TYPE_INSTANCE);
59 price->value = gnc_numeric_zero();
65 gnc_price_dispose(GObject *pricep)
67 G_OBJECT_CLASS(gnc_price_parent_class)->dispose(pricep);
71 gnc_price_finalize(GObject* pricep)
73 G_OBJECT_CLASS(gnc_price_parent_class)->finalize(pricep);
83 gnc_price_get_property(GObject*
object, guint prop_id, GValue* value, GParamSpec* pspec)
87 g_return_if_fail(GNC_IS_PRICE(
object));
89 price = GNC_PRICE(
object);
93 g_value_set_string(value, price->source);
96 g_value_set_string(value, price->type);
99 g_value_set_boxed(value, &price->value);
102 g_value_take_object(value, price->commodity);
105 g_value_take_object(value, price->currency);
108 g_value_set_boxed(value, &price->tmspec);
111 G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop_id, pspec);
117 gnc_price_set_property(GObject*
object, guint prop_id,
const GValue* value, GParamSpec* pspec)
123 g_return_if_fail(GNC_IS_PRICE(
object));
125 price = GNC_PRICE(
object);
126 g_assert (qof_instance_get_editlevel(price));
131 gnc_price_set_source(price, g_value_get_string(value));
134 gnc_price_set_typestr(price, g_value_get_string(value));
137 number = g_value_get_boxed(value);
138 gnc_price_set_value(price, *number);
141 gnc_price_set_commodity(price, g_value_get_object(value));
144 gnc_price_set_currency(price, g_value_get_object(value));
147 ts = g_value_get_boxed(value);
148 gnc_price_set_time(price, *ts);
151 G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop_id, pspec);
159 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
161 gobject_class->dispose = gnc_price_dispose;
162 gobject_class->finalize = gnc_price_finalize;
163 gobject_class->set_property = gnc_price_set_property;
164 gobject_class->get_property = gnc_price_get_property;
166 g_object_class_install_property
169 g_param_spec_object (
"commodity",
171 "The commodity field denotes the base kind of "
172 "'stuff' for the units of this quote, whether "
173 "it is USD, gold, stock, etc.",
177 g_object_class_install_property
180 g_param_spec_object (
"currency",
182 "The currency field denotes the external kind "
183 "'stuff' for the units of this quote, whether "
184 "it is USD, gold, stock, etc.",
188 g_object_class_install_property
191 g_param_spec_string (
"source",
193 "The price source is a string describing the "
194 "source of a price quote. It will be something "
195 "like this: 'Finance::Quote', 'user:misc', "
200 g_object_class_install_property
203 g_param_spec_string (
"type",
205 "The quote type is a string describing the "
206 "type of a price quote. Types possible now "
207 "are 'bid', 'ask', 'last', 'nav' and 'unknown'.",
211 g_object_class_install_property
214 g_param_spec_boxed(
"date",
216 "The date of the price quote.",
220 g_object_class_install_property
223 g_param_spec_boxed(
"value",
225 "The value of the price quote.",
240 g_return_val_if_fail (book, NULL);
242 p = g_object_new(GNC_TYPE_PRICE, NULL);
256 if (p->type) CACHE_REMOVE(p->type);
257 if (p->source) CACHE_REMOVE(p->source);
275 if (p->refcount == 0)
282 if (p->refcount <= 0)
286 PERR(
"last unref while price in database");
288 gnc_price_destroy (p);
300 g_return_val_if_fail (book, NULL);
317 qof_instance_copy_version(new_p, p);
319 gnc_price_begin_edit(new_p);
321 gnc_price_set_commodity(new_p, gnc_price_get_commodity(p));
322 gnc_price_set_time(new_p, gnc_price_get_time(p));
323 gnc_price_set_source(new_p, gnc_price_get_source(p));
324 gnc_price_set_typestr(new_p, gnc_price_get_typestr(p));
325 gnc_price_set_value(new_p, gnc_price_get_value(p));
326 gnc_price_set_currency(new_p, gnc_price_get_currency(p));
327 gnc_price_commit_edit(new_p);
342 PERR (
"Failed to commit: %d", errcode);
343 gnc_engine_signal_commit_error( errcode );
376 qof_instance_set_dirty(&p->inst);
391 remove_price (p->db, p, TRUE);
392 gnc_price_begin_edit (p);
394 gnc_price_set_dirty(p);
395 gnc_price_commit_edit (p);
396 add_price (p->db, p);
413 remove_price (p->db, p, TRUE);
414 gnc_price_begin_edit (p);
416 gnc_price_set_dirty(p);
417 gnc_price_commit_edit (p);
418 add_price (p->db, p);
433 remove_price (p->db, p, FALSE);
434 gnc_price_begin_edit (p);
436 gnc_price_set_dirty(p);
437 gnc_price_commit_edit (p);
438 add_price (p->db, p);
444 gnc_price_set_source(
GNCPrice *p,
const char *s)
447 if (g_strcmp0(p->source, s) != 0)
451 gnc_price_begin_edit (p);
452 tmp = CACHE_INSERT((gpointer) s);
453 if (p->source) CACHE_REMOVE(p->source);
455 gnc_price_set_dirty(p);
456 gnc_price_commit_edit (p);
461 gnc_price_set_typestr(
GNCPrice *p,
const char* type)
464 if (g_strcmp0(p->type, type) != 0)
468 gnc_price_begin_edit (p);
469 tmp = CACHE_INSERT((gpointer) type);
470 if (p->type) CACHE_REMOVE(p->type);
472 gnc_price_set_dirty(p);
473 gnc_price_commit_edit (p);
483 gnc_price_begin_edit (p);
485 gnc_price_set_dirty(p);
486 gnc_price_commit_edit (p);
498 if (!guid || !book)
return NULL;
504 gnc_price_get_commodity(
const GNCPrice *p)
511 gnc_price_get_time(
const GNCPrice *p)
524 gnc_price_get_source(
const GNCPrice *p)
531 gnc_price_get_typestr(
const GNCPrice *p)
538 gnc_price_get_value(
const GNCPrice *p)
542 PERR(
"price NULL.\n");
543 return gnc_numeric_zero();
549 gnc_price_get_currency(
const GNCPrice *p)
561 if (p1 == p2)
return TRUE;
562 if (!p1 || !p2)
return FALSE;
565 gnc_price_get_commodity (p2)))
569 gnc_price_get_currency (p2)))
572 ts1 = gnc_price_get_time (p1);
573 ts2 = gnc_price_get_time (p2);
578 if (g_strcmp0 (gnc_price_get_source (p1),
579 gnc_price_get_source (p2)) != 0)
582 if (g_strcmp0 (gnc_price_get_typestr (p1),
583 gnc_price_get_typestr (p2)) != 0)
587 gnc_price_get_value (p2)))
597 compare_prices_by_date(gconstpointer a, gconstpointer b)
603 if (!a && !b)
return 0;
607 time_a = gnc_price_get_time((
GNCPrice *) a);
608 time_b = gnc_price_get_time((
GNCPrice *) b);
611 if (result)
return result;
614 return guid_compare (gnc_price_get_guid((
GNCPrice *) a),
615 gnc_price_get_guid((
GNCPrice *) b));
625 price_list_is_duplicate( gpointer data, gpointer user_data )
635 if ( !
gnc_numeric_equal( gnc_price_get_value( pPrice ), gnc_price_get_value( pStruct->pPrice ) ) )
return;
636 if ( gnc_price_get_commodity( pPrice ) != gnc_price_get_commodity( pStruct->pPrice ) )
return;
637 if ( gnc_price_get_currency( pPrice ) != gnc_price_get_currency( pStruct->pPrice ) )
return;
641 pStruct->isDupl = TRUE;
651 if (!prices || !p)
return FALSE;
658 pStruct->isDupl = FALSE;
659 g_list_foreach( *prices, price_list_is_duplicate, pStruct );
660 isDupl = pStruct->isDupl;
669 result_list = g_list_insert_sorted(*prices, p, compare_prices_by_date);
670 if (!result_list)
return FALSE;
671 *prices = result_list;
679 GList *found_element;
681 if (!prices || !p)
return FALSE;
683 found_element = g_list_find(*prices, p);
684 if (!found_element)
return TRUE;
686 result_list = g_list_remove_link(*prices, found_element);
688 g_list_free(found_element);
690 *prices = result_list;
695 price_list_destroy_helper(gpointer data, gpointer user_data)
703 g_list_foreach(prices, price_list_destroy_helper, NULL);
708 gnc_price_list_equal(PriceList *prices1, PriceList *prices2)
712 if (prices1 == prices2)
return TRUE;
714 if (g_list_length (prices1) < g_list_length (prices2))
716 PWARN (
"prices2 has extra prices");
720 if (g_list_length (prices1) > g_list_length (prices2))
722 PWARN (
"prices1 has extra prices");
726 for (n1 = prices1, n2 = prices2; n1 ; n1 = n1->next, n2 = n2->next)
727 if (!gnc_price_equal (n1->data, n2->data))
745 QOF_GOBJECT_IMPL(gnc_pricedb,
GNCPriceDB, QOF_TYPE_INSTANCE);
753 gnc_pricedb_dispose_real (GObject *pdbp)
758 gnc_pricedb_finalize_real(GObject* pdbp)
763 gnc_pricedb_create(
QofBook * book)
768 g_return_val_if_fail (book, NULL);
777 PWARN (
"A price database already exists for this book!");
781 result = g_object_new(GNC_TYPE_PRICEDB, NULL);
788 qof_collection_set_data (col, result);
790 result->commodity_hash = g_hash_table_new(NULL, NULL);
791 g_return_val_if_fail (result->commodity_hash, NULL);
796 destroy_pricedb_currency_hash_data(gpointer key,
800 GList *price_list = (GList *) data;
804 for (node = price_list; node; node = node->next)
815 destroy_pricedb_commodity_hash_data(gpointer key,
819 GHashTable *currency_hash = (GHashTable *) data;
820 if (!currency_hash)
return;
821 g_hash_table_foreach (currency_hash,
822 destroy_pricedb_currency_hash_data,
824 g_hash_table_destroy(currency_hash);
831 if (db->commodity_hash)
833 g_hash_table_foreach (db->commodity_hash,
834 destroy_pricedb_commodity_hash_data,
837 g_hash_table_destroy (db->commodity_hash);
838 db->commodity_hash = NULL;
846 db->bulk_update = bulk_update;
867 if (!col)
return NULL;
876 if (!book)
return NULL;
884 num_prices_helper (
GNCPrice *p, gpointer user_data)
886 guint *count = user_data;
917 pricedb_equal_foreach_pricelist(gpointer key, gpointer val, gpointer user_data)
921 GList *price_list1 = val;
925 equal_data->commodity,
928 if (!gnc_price_list_equal (price_list1, price_list2))
929 equal_data->equal = FALSE;
935 pricedb_equal_foreach_currencies_hash (gpointer key, gpointer val,
938 GHashTable *currencies_hash = val;
941 equal_data->commodity = key;
943 g_hash_table_foreach (currencies_hash,
944 pricedb_equal_foreach_pricelist,
953 if (db1 == db2)
return TRUE;
957 PWARN (
"one is NULL");
961 equal_data.equal = TRUE;
962 equal_data.db2 = db2;
964 g_hash_table_foreach (db1->commodity_hash,
965 pricedb_equal_foreach_currencies_hash,
968 return equal_data.equal;
983 GHashTable *currency_hash;
985 if (!db || !p)
return FALSE;
986 ENTER (
"db=%p, pr=%p dirty=%d destroying=%d",
992 PERR (
"attempted to mix up prices across different books");
997 commodity = gnc_price_get_commodity(p);
1000 PWARN(
"no commodity");
1004 currency = gnc_price_get_currency(p);
1007 PWARN(
"no currency");
1011 if (!db->commodity_hash)
1013 LEAVE (
"no commodity hash found ");
1017 currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
1020 currency_hash = g_hash_table_new(NULL, NULL);
1021 g_hash_table_insert(db->commodity_hash, commodity, currency_hash);
1024 price_list = g_hash_table_lookup(currency_hash, currency);
1027 LEAVE (
"gnc_price_list_insert failed");
1032 LEAVE (
" no price list");
1035 g_hash_table_insert(currency_hash, currency, price_list);
1039 LEAVE (
"db=%p, pr=%p dirty=%d dextroying=%d commodity=%s/%s currency_hash=%p",
1055 if (!db || !p)
return FALSE;
1057 ENTER (
"db=%p, pr=%p dirty=%d destroying=%d",
1061 if (FALSE == add_price(db, p))
1063 LEAVE (
" failed to add price");
1068 qof_instance_set_dirty(&db->inst);
1069 gnc_pricedb_commit_edit(db);
1071 LEAVE (
"db=%p, pr=%p dirty=%d destroying=%d",
1088 GHashTable *currency_hash;
1090 if (!db || !p)
return FALSE;
1091 ENTER (
"db=%p, pr=%p dirty=%d destroying=%d",
1095 commodity = gnc_price_get_commodity(p);
1098 LEAVE (
" no commodity");
1101 currency = gnc_price_get_currency(p);
1104 LEAVE (
" no currency");
1107 if (!db->commodity_hash)
1109 LEAVE (
" no commodity hash");
1113 currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
1116 LEAVE (
" no currency hash");
1121 price_list = g_hash_table_lookup(currency_hash, currency);
1126 LEAVE (
" cannot remove price list");
1134 g_hash_table_insert(currency_hash, currency, price_list);
1138 g_hash_table_remove(currency_hash, currency);
1145 guint num_currencies = g_hash_table_size (currency_hash);
1146 if (0 == num_currencies)
1148 g_hash_table_remove (db->commodity_hash, commodity);
1149 g_hash_table_destroy (currency_hash);
1155 LEAVE (
"db=%p, pr=%p", db, p);
1163 if (!db || !p)
return FALSE;
1164 ENTER (
"db=%p, pr=%p dirty=%d destroying=%d",
1169 rc = remove_price (db, p, TRUE);
1171 qof_instance_set_dirty(&db->inst);
1172 gnc_pricedb_commit_edit(db);
1175 gnc_price_begin_edit (p);
1176 qof_instance_set_destroying(p, TRUE);
1177 gnc_price_commit_edit (p);
1180 LEAVE (
"db=%p, pr=%p", db, p);
1188 gboolean delete_user;
1189 gboolean delete_last;
1194 check_one_price_date (
GNCPrice *price, gpointer user_data)
1197 const gchar *source;
1200 ENTER(
"price %p (%s), data %p", price,
1203 if (!data->delete_user)
1205 source = gnc_price_get_source (price);
1206 if (g_strcmp0(source,
"Finance::Quote") != 0)
1208 LEAVE(
"Not an automatic quote");
1213 pt = gnc_price_get_time (price);
1217 DEBUG(
"checking date %s", buf);
1221 data->list = g_slist_prepend(data->list, price);
1222 DEBUG(
"will delete");
1229 pricedb_remove_foreach_pricelist (gpointer key,
1233 GList *price_list = (GList *) val;
1234 GList *node = price_list;
1237 ENTER(
"key %p, value %p, data %p", key, val, user_data);
1240 if (!data->delete_last)
1241 node = g_list_next(node);
1244 g_list_foreach(node, (GFunc)check_one_price_date, data);
1250 pricedb_remove_foreach_currencies_hash (gpointer key,
1254 GHashTable *currencies_hash = (GHashTable *) val;
1256 ENTER(
"key %p, value %p, data %p", key, val, user_data);
1257 g_hash_table_foreach(currencies_hash,
1258 pricedb_remove_foreach_pricelist, user_data);
1264 gnc_pricedb_remove_old_prices(
GNCPriceDB *db,
1266 gboolean delete_user,
1267 gboolean delete_last)
1273 data.cutoff = cutoff;
1274 data.delete_user = delete_user;
1275 data.delete_last = delete_last;
1278 ENTER(
"db %p, delet_user %d, delete_last %d", db, delete_user, delete_last);
1282 DEBUG(
"checking date %s", buf);
1287 g_hash_table_foreach(db->commodity_hash,
1288 pricedb_remove_foreach_currencies_hash,
1291 if (data.list == NULL)
1295 for (item = data.list; item; item = g_slist_next(item))
1300 g_slist_free(data.list);
1315 GHashTable *currency_hash;
1319 if (!db || !commodity || !currency)
return NULL;
1320 ENTER (
"db=%p commodity=%p currency=%p", db, commodity, currency);
1323 #ifdef GNUCASH_MAJOR_VERSION
1327 pl.type = LOOKUP_LATEST;
1329 pl.commodity = commodity;
1330 pl.currency = currency;
1335 currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
1338 LEAVE (
" no currency hash");
1342 price_list = g_hash_table_lookup(currency_hash, currency);
1345 LEAVE (
" no price list");
1352 result = price_list->data;
1360 lookup_latest(gpointer key, gpointer val, gpointer user_data)
1363 GList *price_list = (GList *)val;
1364 GList **return_list = (GList **)user_data;
1366 if (!price_list)
return;
1377 GHashTable *currency_hash;
1383 if (!db || !commodity)
return NULL;
1384 ENTER (
"db=%p commodity=%p", db, commodity);
1387 #ifdef GNUCASH_MAJOR_VERSION
1391 pl.type = LOOKUP_LATEST;
1393 pl.commodity = commodity;
1398 currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
1401 LEAVE (
" no currency hash");
1405 g_hash_table_foreach(currency_hash, lookup_latest, &result);
1413 result = g_list_sort(result, compare_prices_by_date);
1421 hash_values_helper(gpointer key, gpointer value, gpointer data)
1424 *l = g_list_concat(*l, g_list_copy (value));
1433 GHashTable *currency_hash;
1438 if (!db || !commodity)
return FALSE;
1439 ENTER (
"db=%p commodity=%p currency=%p", db, commodity, currency);
1442 #ifdef GNUCASH_MAJOR_VERSION
1446 pl.type = LOOKUP_ALL;
1448 pl.commodity = commodity;
1449 pl.currency = currency;
1453 currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
1456 LEAVE(
"no, no currency_hash table");
1462 price_list = g_hash_table_lookup(currency_hash, currency);
1468 LEAVE(
"no, no price list");
1472 size = g_hash_table_size (currency_hash);
1473 LEAVE(
"%s", size > 0 ?
"yes" :
"no");
1486 GHashTable *currency_hash;
1490 if (!db || !commodity)
return NULL;
1491 ENTER (
"db=%p commodity=%p currency=%p", db, commodity, currency);
1494 #ifdef GNUCASH_MAJOR_VERSION
1498 pl.type = LOOKUP_ALL;
1500 pl.commodity = commodity;
1501 pl.currency = currency;
1505 currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
1508 LEAVE (
" no currency hash");
1514 price_list = g_hash_table_lookup(currency_hash, currency);
1517 LEAVE (
" no price list");
1520 result = g_list_copy (price_list);
1525 g_hash_table_foreach(currency_hash, hash_values_helper, (gpointer)&result);
1527 for (node = result; node; node = node->next)
1541 return lookup_nearest_in_time(db, c, currency, t, TRUE);
1551 GList *result = NULL;
1553 GHashTable *currency_hash;
1557 if (!db || !c || !currency)
return NULL;
1558 ENTER (
"db=%p commodity=%p currency=%p", db, c, currency);
1561 #ifdef GNUCASH_MAJOR_VERSION
1565 pl.type = LOOKUP_AT_TIME;
1568 pl.currency = currency;
1573 currency_hash = g_hash_table_lookup(db->commodity_hash, c);
1576 LEAVE (
" no currency hash");
1580 price_list = g_hash_table_lookup(currency_hash, currency);
1583 LEAVE (
" no price list");
1591 Timespec price_time = gnc_price_get_time(p);
1594 result = g_list_prepend(result, p);
1615 GHashTable *currency_hash;
1619 if (!db || !c || !currency)
return NULL;
1620 ENTER (
"db=%p commodity=%p currency=%p", db, c, currency);
1623 #ifdef GNUCASH_MAJOR_VERSION
1627 pl.type = LOOKUP_NEAREST_IN_TIME;
1630 pl.currency = currency;
1635 currency_hash = g_hash_table_lookup(db->commodity_hash, c);
1638 LEAVE (
"no currency hash");
1642 price_list = g_hash_table_lookup(currency_hash, currency);
1645 LEAVE (
"no price list");
1652 current_price = item->data;
1656 while (!next_price && item)
1659 Timespec price_time = gnc_price_get_time(p);
1662 next_price = item->data;
1665 current_price = item->data;
1674 result = current_price;
1690 Timespec current_t = gnc_price_get_time(current_price);
1691 Timespec next_t = gnc_price_get_time(next_price);
1709 result = current_price;
1711 result = next_price;
1715 result = current_price;
1719 result = next_price;
1728 result = current_price;
1732 result = next_price;
1749 return lookup_nearest_in_time(db, c, currency, t, FALSE);
1763 GHashTable *currency_hash;
1768 if (!db || !c || !currency)
return NULL;
1769 ENTER (
"db=%p commodity=%p currency=%p", db, c, currency);
1772 #ifdef GNUCASH_MAJOR_VERSION
1776 pl.type = LOOKUP_LATEST_BEFORE;
1779 pl.currency = currency;
1784 currency_hash = g_hash_table_lookup(db->commodity_hash, c);
1787 LEAVE (
"no currency hash");
1791 price_list = g_hash_table_lookup(currency_hash, currency);
1794 LEAVE (
"no price list");
1801 price_time = gnc_price_get_time (item->data);
1803 current_price = item->data;
1809 return current_price;
1814 lookup_nearest(gpointer key, gpointer val, gpointer user_data)
1817 GList *price_list = (GList *)val;
1823 GList **return_list = lookup_helper->return_list;
1829 current_price = item->data;
1833 while (!next_price && item)
1836 Timespec price_time = gnc_price_get_time(p);
1839 next_price = item->data;
1842 current_price = item->data;
1850 result = current_price;
1854 Timespec current_t = gnc_price_get_time(current_price);
1855 Timespec next_t = gnc_price_get_time(next_price);
1863 result = current_price;
1867 result = next_price;
1877 lookup_latest_before(gpointer key, gpointer val, gpointer user_data)
1880 GList *price_list = (GList *)val;
1886 GList **return_list = lookup_helper->return_list;
1895 price_time = gnc_price_get_time (item->data);
1897 current_price = item->data;
1912 GList *result = NULL;
1913 GHashTable *currency_hash;
1918 if (!db || !c)
return NULL;
1919 ENTER (
"db=%p commodity=%p", db, c);
1922 #ifdef GNUCASH_MAJOR_VERSION
1926 pl.type = LOOKUP_NEAREST_IN_TIME;
1934 currency_hash = g_hash_table_lookup(db->commodity_hash, c);
1937 LEAVE (
" no currency hash");
1941 lookup_helper.return_list = &result;
1942 lookup_helper.time = t;
1943 g_hash_table_foreach(currency_hash, lookup_nearest, &lookup_helper);
1951 result = g_list_sort(result, compare_prices_by_date);
1963 GList *result = NULL;
1964 GHashTable *currency_hash;
1969 if (!db || !c)
return NULL;
1970 ENTER (
"db=%p commodity=%p", db, c);
1973 #ifdef GNUCASH_MAJOR_VERSION
1977 pl.type = LOOKUP_LATEST_BEFORE;
1985 currency_hash = g_hash_table_lookup(db->commodity_hash, c);
1988 LEAVE (
" no currency hash");
1992 lookup_helper.return_list = &result;
1993 lookup_helper.time = t;
1994 g_hash_table_foreach(currency_hash, lookup_latest_before, &lookup_helper);
2002 result = g_list_sort(result, compare_prices_by_date);
2019 GList *price_list, *list_helper;
2058 balance = gnc_numeric_zero ();
2062 list_helper = price_list;
2063 currency_price_value = gnc_numeric_zero();
2067 price = (
GNCPrice *)(list_helper->data);
2069 intermediate_currency = gnc_price_get_currency(price);
2074 currency_price_value = gnc_price_get_value(currency_price);
2080 intermediate_currency);
2085 gnc_price_get_value(currency_price),
2092 list_helper = list_helper->next;
2094 while ((list_helper != NULL) &&
2116 GList *price_list, *list_helper;
2155 balance = gnc_numeric_zero ();
2159 list_helper = price_list;
2160 currency_price_value = gnc_numeric_zero();
2164 price = (
GNCPrice *)(list_helper->data);
2166 intermediate_currency = gnc_price_get_currency(price);
2171 currency_price_value = gnc_price_get_value(currency_price);
2177 intermediate_currency, t);
2182 gnc_price_get_value(currency_price),
2189 list_helper = list_helper->next;
2191 while ((list_helper != NULL) &&
2214 gboolean (*func)(
GNCPrice *p, gpointer user_data);
2219 pricedb_foreach_pricelist(gpointer key, gpointer val, gpointer user_data)
2221 GList *price_list = (GList *) val;
2222 GList *node = price_list;
2226 while (foreach_data->ok && node)
2229 foreach_data->ok = foreach_data->func(p, foreach_data->user_data);
2235 pricedb_foreach_currencies_hash(gpointer key, gpointer val, gpointer user_data)
2237 GHashTable *currencies_hash = (GHashTable *) val;
2238 g_hash_table_foreach(currencies_hash, pricedb_foreach_pricelist, user_data);
2243 gboolean (*f)(
GNCPrice *p, gpointer user_data),
2248 if (!db || !f)
return FALSE;
2249 foreach_data.ok = TRUE;
2250 foreach_data.func = f;
2251 foreach_data.user_data = user_data;
2252 if (db->commodity_hash == NULL)
2256 g_hash_table_foreach(db->commodity_hash,
2257 pricedb_foreach_currencies_hash,
2260 return foreach_data.ok;
2264 compare_kvpairs_by_commodity_key(gconstpointer a, gconstpointer b)
2272 if (a == b)
return 0;
2273 if (!a && !b)
return 0;
2283 if (cmp_result != 0)
return cmp_result;
2291 gboolean (*f)(
GNCPrice *p, gpointer user_data),
2294 GSList *currency_hashes = NULL;
2298 if (!db || !f)
return FALSE;
2301 currency_hashes = g_slist_sort(currency_hashes,
2302 compare_kvpairs_by_commodity_key);
2304 for (i = currency_hashes; i; i = i->next)
2307 GHashTable *currency_hash = (GHashTable *) kv_pair->value;
2311 price_lists = g_slist_sort(price_lists, compare_kvpairs_by_commodity_key);
2312 for (j = price_lists; j; j = j->next)
2315 GList *price_list = (GList *) pricelist_kvp->value;
2318 for (node = (GList *) price_list; node; node = node->next)
2323 if (FALSE == ok)
break;
2324 if (!f(price, user_data)) ok = FALSE;
2329 g_slist_foreach(price_lists, g_hash_table_kv_pair_free_gfunc, NULL);
2330 g_slist_free(price_lists);
2335 if (currency_hashes)
2337 g_slist_foreach(currency_hashes, g_hash_table_kv_pair_free_gfunc, NULL);
2338 g_slist_free(currency_hashes);
2345 gboolean (*f)(
GNCPrice *p, gpointer user_data),
2347 gboolean stable_order)
2349 ENTER (
"db=%p f=%p", db, f);
2352 LEAVE (
" stable order found");
2353 return stable_price_traversal(db, f, user_data);
2355 LEAVE (
" use unstable order");
2356 return unstable_price_traversal(db, f, user_data);
2369 add_price_to_list (
GNCPrice *p, gpointer data)
2371 GList **list = data;
2373 *list = g_list_prepend (*list, p);
2379 gnc_price_fixup_legacy_commods(gpointer data, gpointer user_data)
2387 price_c = gnc_price_get_commodity(p);
2390 gnc_price_set_commodity (p, fixup_data->new_c);
2392 price_c = gnc_price_get_currency(p);
2395 gnc_price_set_currency (p, fixup_data->new_c);
2400 gnc_pricedb_substitute_commodity(
GNCPriceDB *db,
2405 GList *prices = NULL;
2407 if (!db || !old_c || !new_c)
return;
2414 g_list_foreach (prices, gnc_price_fixup_legacy_commods, &data);
2416 g_list_free (prices);
2434 commodity = gnc_price_get_commodity(p);
2435 currency = gnc_price_get_currency(p);
2437 if (!commodity)
return;
2438 if (!currency)
return;
2440 istr = g_strnfill(indent,
' ');
2442 fprintf(f,
"%s<pdb:price>\n", istr);
2443 fprintf(f,
"%s <pdb:commodity pointer=%p>\n", istr, commodity);
2445 str = str ? str :
"(null)";
2446 fprintf(f,
"%s <cmdty:ref-space>%s</gnc:cmdty:ref-space>\n", istr, str);
2448 str = str ? str :
"(null)";
2449 fprintf(f,
"%s <cmdty:ref-id>%s</cmdty:ref-id>\n", istr, str);
2450 fprintf(f,
"%s </pdb:commodity>\n", istr);
2451 fprintf(f,
"%s <pdb:currency pointer=%p>\n", istr, currency);
2453 str = str ? str :
"(null)";
2454 fprintf(f,
"%s <cmdty:ref-space>%s</gnc:cmdty:ref-space>\n", istr, str);
2456 str = str ? str :
"(null)";
2457 fprintf(f,
"%s <cmdty:ref-id>%s</cmdty:ref-id>\n", istr, str);
2458 fprintf(f,
"%s </pdb:currency>\n", istr);
2459 str = gnc_price_get_source(p);
2460 str = str ? str :
"(null)";
2461 fprintf(f,
"%s %s\n", istr, str);
2462 str = gnc_price_get_typestr(p);
2463 str = str ? str :
"(null)";
2464 fprintf(f,
"%s %s\n", istr, str);
2466 fprintf(f,
"%s</pdb:price>\n", istr);
2472 print_pricedb_adapter(
GNCPrice *p, gpointer user_data)
2474 FILE *f = (FILE *) user_data;
2484 PERR(
"NULL PriceDB\n");
2489 PERR(
"NULL FILE*\n");
2493 fprintf(f,
"<gnc:pricedb>\n");
2495 fprintf(f,
"</gnc:pricedb>\n");
2502 pricedb_book_begin (
QofBook *book)
2504 gnc_pricedb_create(book);
2508 pricedb_book_end (
QofBook *book)
2517 qof_collection_set_data(col, NULL);
2532 void (*func)(
GNCPrice *p, gpointer user_data);
2538 void_pricedb_foreach_pricelist(gpointer key, gpointer val, gpointer user_data)
2540 GList *price_list = (GList *) val;
2541 GList *node = price_list;
2547 foreach_data->func(p, foreach_data->user_data);
2553 void_pricedb_foreach_currencies_hash(gpointer key, gpointer val, gpointer user_data)
2555 GHashTable *currencies_hash = (GHashTable *) val;
2556 g_hash_table_foreach(currencies_hash, void_pricedb_foreach_pricelist, user_data);
2560 void_unstable_price_traversal(
GNCPriceDB *db,
2561 void (*f)(
GNCPrice *p, gpointer user_data),
2566 if (!db || !f)
return;
2567 foreach_data.func = f;
2568 foreach_data.user_data = user_data;
2570 g_hash_table_foreach(db->commodity_hash,
2571 void_pricedb_foreach_currencies_hash,
2581 void_unstable_price_traversal(db,
2582 (
void (*)(
GNCPrice *, gpointer)) cb,
2589 price_printable(gpointer obj)
2594 static char buff[2048];
2602 commodity = gnc_price_get_commodity(pr);
2603 currency = gnc_price_get_currency(pr);
2605 g_snprintf (buff, 2048,
"%s %s / %s on %s", val,
2624 DI(.e_type = ) GNC_ID_PRICE,
2625 DI(.type_label = ) "Price",
2626 DI(.create = ) price_create,
2627 DI(.book_begin = ) NULL,
2628 DI(.book_end = ) NULL,
2631 DI(.foreach = ) price_foreach,
2632 DI(.printable = ) price_printable,
2633 DI(.version_cmp = ) NULL,
2639 DI(.e_type = ) GNC_ID_PRICEDB,
2640 DI(.type_label = ) "PriceDB",
2641 DI(.create = ) NULL,
2642 DI(.book_begin = ) pricedb_book_begin,
2643 DI(.book_end = ) pricedb_book_end,
2644 DI(.is_dirty = ) qof_collection_is_dirty,
2645 DI(.mark_clean = ) qof_collection_mark_clean,
2646 DI(.foreach = ) NULL,
2647 DI(.printable = ) NULL,
2648 DI(.version_cmp = ) NULL,
2652 gnc_pricedb_register (
void)
void gnc_price_list_destroy(PriceList *prices)
GNCPrice * gnc_price_create(QofBook *book)
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
gchar * gnc_timespec_to_iso8601_buff(Timespec ts, gchar *buff)
int gnc_commodity_get_fraction(const gnc_commodity *cm)
GNCPrice * gnc_pricedb_lookup_day(GNCPriceDB *db, const gnc_commodity *c, const gnc_commodity *currency, Timespec t)
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
PriceList * gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db, const gnc_commodity *c, Timespec t)
QofBook * qof_instance_get_book(gconstpointer)
gboolean qof_collection_is_dirty(const QofCollection *col)
QofInstance * qof_collection_lookup_entity(const QofCollection *, const GncGUID *)
void(* price_lookup)(QofBackend *, gpointer)
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Timespec timespecCanonicalDayTime(Timespec t)
void gnc_price_unref(GNCPrice *p)
#define DEBUG(format, args...)
gboolean qof_instance_get_destroying(gconstpointer ptr)
gboolean gnc_pricedb_add_price(GNCPriceDB *db, GNCPrice *p)
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_fcn, const QofParam *params)
gboolean timespec_equal(const Timespec *ta, const Timespec *tb)
GNCPriceDB * gnc_collection_get_pricedb(QofCollection *col)
gboolean gnc_pricedb_equal(GNCPriceDB *db1, GNCPriceDB *db2)
Use a 64-bit unsigned int timespec.
gboolean gnc_numeric_zero_p(gnc_numeric a)
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
#define QOF_OBJECT_VERSION
gchar * gnc_numeric_to_string(gnc_numeric n)
gboolean qof_commit_edit(QofInstance *inst)
#define PERR(format, args...)
gboolean gnc_price_list_insert(PriceList **prices, GNCPrice *p, gboolean check_dupl)
#define ENTER(format, args...)
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
PriceList * gnc_pricedb_lookup_at_time(GNCPriceDB *db, const gnc_commodity *c, const gnc_commodity *currency, Timespec t)
gnc_numeric gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb, gnc_numeric balance, const gnc_commodity *balance_currency, const gnc_commodity *new_currency)
Timespec timespec_abs(const Timespec *t)
#define PWARN(format, args...)
char * qof_print_date(time64 secs)
void qof_instance_init_data(QofInstance *, QofIdType, QofBook *)
gint timespec_cmp(const Timespec *ta, const Timespec *tb)
gboolean qof_begin_edit(QofInstance *inst)
gdouble gnc_numeric_to_double(gnc_numeric n)
GNCPrice * gnc_pricedb_lookup_latest_before(GNCPriceDB *db, gnc_commodity *c, gnc_commodity *currency, Timespec t)
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gboolean qof_instance_get_dirty_flag(gconstpointer ptr)
void gnc_pricedb_destroy(GNCPriceDB *db)
guint gnc_pricedb_get_num_prices(GNCPriceDB *db)
GSList * g_hash_table_key_value_pairs(GHashTable *table)
PriceList * gnc_pricedb_lookup_latest_before_any_currency(GNCPriceDB *db, gnc_commodity *c, Timespec t)
gboolean gnc_pricedb_foreach_price(GNCPriceDB *db, gboolean(*f)(GNCPrice *p, gpointer user_data), gpointer user_data, gboolean stable_order)
void gnc_price_print(GNCPrice *p, FILE *f, int indent)
void gnc_pricedb_begin_edit(GNCPriceDB *pdb)
PriceList * gnc_pricedb_lookup_latest_any_currency(GNCPriceDB *db, const gnc_commodity *commodity)
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
GNCPrice * gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db, const gnc_commodity *c, const gnc_commodity *currency, Timespec t)
void qof_collection_mark_clean(QofCollection *)
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
gboolean qof_instance_books_equal(gconstpointer ptr1, gconstpointer ptr2)
void(* QofInstanceForeachCB)(QofInstance *, gpointer user_data)
gboolean gnc_pricedb_remove_price(GNCPriceDB *db, GNCPrice *p)
gboolean gnc_pricedb_has_prices(GNCPriceDB *db, const gnc_commodity *commodity, const gnc_commodity *currency)
private api for data storage backend
gboolean gnc_price_list_remove(PriceList **prices, GNCPrice *p)
Timespec timespec_diff(const Timespec *ta, const Timespec *tb)
GNCPrice * gnc_price_clone(GNCPrice *p, QofBook *book)
#define LEAVE(format, args...)
void(* QofSetterFunc)(gpointer, gpointer)
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
void gnc_pricedb_set_bulk_update(GNCPriceDB *db, gboolean bulk_update)
QofCollection * qof_book_get_collection(const QofBook *, QofIdType)
gnc_numeric gnc_pricedb_convert_balance_nearest_price(GNCPriceDB *pdb, gnc_numeric balance, const gnc_commodity *balance_currency, const gnc_commodity *new_currency, Timespec t)
gboolean qof_object_register(const QofObject *object)
GNCPrice * gnc_pricedb_lookup_latest(GNCPriceDB *db, const gnc_commodity *commodity, const gnc_commodity *currency)
gpointer qof_collection_get_data(const QofCollection *col)
QofBackend * qof_book_get_backend(const QofBook *book)
Retrieve the backend used by this book.
void qof_event_gen(QofInstance *entity, QofEventId event_type, gpointer event_data)
Invoke all registered event handlers using the given arguments.
void gnc_pricedb_print_contents(GNCPriceDB *db, FILE *f)
void gnc_price_ref(GNCPrice *p)
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
const gchar * QofLogModule
PriceList * gnc_pricedb_get_prices(GNCPriceDB *db, const gnc_commodity *commodity, const gnc_commodity *currency)