gnucash maint: Multiple changes pushed
Christopher Lam
clam at code.gnucash.org
Sun Aug 29 21:16:44 EDT 2021
Updated via https://github.com/Gnucash/gnucash/commit/e13644df (commit)
via https://github.com/Gnucash/gnucash/commit/8a48ed97 (commit)
via https://github.com/Gnucash/gnucash/commit/001b3461 (commit)
via https://github.com/Gnucash/gnucash/commit/a47bee97 (commit)
via https://github.com/Gnucash/gnucash/commit/0ecbcb4e (commit)
via https://github.com/Gnucash/gnucash/commit/ac2afc7e (commit)
via https://github.com/Gnucash/gnucash/commit/3bf49ed8 (commit)
via https://github.com/Gnucash/gnucash/commit/e3af2f22 (commit)
from https://github.com/Gnucash/gnucash/commit/57f73d70 (commit)
commit e13644dffc1375c568ffcd2f80efd2d9825be561
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Sat Aug 28 22:05:37 2021 +0800
free GtkTreePath after calling gtk_tree_view_get_path_at_pos
diff --git a/gnucash/gnome/dialog-custom-report.c b/gnucash/gnome/dialog-custom-report.c
index f2af3b0ef..4badfe983 100644
--- a/gnucash/gnome/dialog-custom-report.c
+++ b/gnucash/gnome/dialog-custom-report.c
@@ -423,6 +423,7 @@ custom_report_list_view_clicked_cb(GtkTreeView *view, GdkEventButton *event, gpo
{
SCM guid = get_custom_report_selection(crd, _("You must select a report configuration to load."));
custom_report_run_report (guid, crd);
+ gtk_tree_path_free (path);
return TRUE;
}
else if (column == crd->editcol)
@@ -430,14 +431,17 @@ custom_report_list_view_clicked_cb(GtkTreeView *view, GdkEventButton *event, gpo
g_object_set(G_OBJECT(crd->namerenderer), "editable", TRUE, NULL);
gtk_tree_view_set_cursor_on_cell (view, path, crd->namecol,
crd->namerenderer, TRUE);
+ gtk_tree_path_free (path);
return TRUE;
}
else if (column == crd->delcol)
{
SCM guid = get_custom_report_selection(crd, _("You must select a report configuration to delete."));
custom_report_delete (guid, crd);
+ gtk_tree_path_free (path);
return TRUE;
}
+ gtk_tree_path_free (path);
}
return FALSE;
}
@@ -489,10 +493,12 @@ custom_report_query_tooltip_cb (GtkTreeView *view,
gtk_tooltip_set_text (tooltip, _("Edit report configuration name"));
else if (column == crd->delcol)
gtk_tooltip_set_text (tooltip, _("Delete report configuration"));
+ gtk_tree_path_free (path);
return TRUE;
}
else
gtk_tooltip_set_text (tooltip, NULL);
+ gtk_tree_path_free (path);
}
return FALSE;
}
diff --git a/gnucash/gnome/gnc-budget-view.c b/gnucash/gnome/gnc-budget-view.c
index 924db4c25..c57221615 100644
--- a/gnucash/gnome/gnc-budget-view.c
+++ b/gnucash/gnome/gnc-budget-view.c
@@ -945,19 +945,31 @@ query_tooltip_tree_view_cb (GtkWidget *widget, gint x, gint y,
if (keyboard_tip || !gtk_tree_view_get_path_at_pos (tree_view, x, y, &path,
&column, NULL, NULL))
+ {
+ gtk_tree_path_free (path);
return FALSE;
+ }
if (!column)
+ {
+ gtk_tree_path_free (path);
return FALSE;
+ }
period_num = GPOINTER_TO_UINT(g_object_get_data (G_OBJECT(column), "period_num"));
if (!period_num && priv->period_col_list->data != column)
+ {
+ gtk_tree_path_free (path);
return FALSE;
+ }
account = gnc_tree_view_account_get_account_from_path (
GNC_TREE_VIEW_ACCOUNT(widget), path);
note = gnc_budget_get_account_period_note (priv->budget, account, period_num);
if (!note)
+ {
+ gtk_tree_path_free (path);
return FALSE;
+ }
gtk_tooltip_set_text (tooltip, note);
gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, column, NULL);
diff --git a/gnucash/import-export/import-main-matcher.c b/gnucash/import-export/import-main-matcher.c
index ae4ae4d10..dca451efb 100644
--- a/gnucash/import-export/import-main-matcher.c
+++ b/gnucash/import-export/import-main-matcher.c
@@ -1898,7 +1898,10 @@ query_tooltip_tree_view_cb (GtkWidget *widget, gint x, gint y,
gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &x, &y);
if (keyboard_tip || !gtk_tree_view_get_path_at_pos (tree_view, x, y, &path,
&column, NULL, NULL))
+ {
+ gtk_tree_path_free (path);
return FALSE;
+ }
// Get the iter pointing to our current column
if (gtk_tree_model_get_iter(model, &iter, path) && column)
commit 8a48ed977750798dfc0fd49a243a593347d256c5
Merge: 57f73d70c 001b34616
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Mon Aug 30 08:43:13 2021 +0800
Merge branch 'maint-cache-gvalue-string' into maint #1117
Will store a copy of kvp data onto struct so that GValue can be
freed (unset) cleanly.
commit 001b34616f0b0b9450ae55ca0effab4ae9f55c5a
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Tue Aug 24 21:38:16 2021 +0800
[Transaction.c] GValue string must be unset
diff --git a/libgnucash/engine/Transaction.c b/libgnucash/engine/Transaction.c
index 4890c2f01..7f12f80a2 100644
--- a/libgnucash/engine/Transaction.c
+++ b/libgnucash/engine/Transaction.c
@@ -255,6 +255,9 @@ void gen_event_trans (Transaction *trans)
}
}
+static const char*
+is_unset = "unset";
+
/* GObject Initialization */
G_DEFINE_TYPE(Transaction, gnc_transaction, QOF_TYPE_INSTANCE)
@@ -274,6 +277,9 @@ gnc_transaction_init(Transaction* trans)
trans->readonly_reason = NULL;
trans->reason_cache_valid = FALSE;
trans->isClosingTxn_cached = -1;
+ trans->notes = (char*) is_unset;
+ trans->doclink = (char*) is_unset;
+ trans->void_reason = (char*) is_unset;
LEAVE (" ");
}
@@ -813,6 +819,12 @@ xaccFreeTransaction (Transaction *trans)
CACHE_REMOVE(trans->num);
CACHE_REMOVE(trans->description);
g_free (trans->readonly_reason);
+ if (trans->doclink != is_unset)
+ g_free (trans->doclink);
+ if (trans->void_reason != is_unset)
+ g_free (trans->void_reason);
+ if (trans->notes != is_unset)
+ g_free (trans->notes);
/* Just in case someone looks up freed memory ... */
trans->num = (char *) 1;
@@ -821,6 +833,9 @@ xaccFreeTransaction (Transaction *trans)
trans->date_posted = 0;
trans->readonly_reason = NULL;
trans->reason_cache_valid = FALSE;
+ trans->doclink = NULL;
+ trans->notes = NULL;
+ trans->void_reason = NULL;
if (trans->orig)
{
xaccFreeTransaction (trans->orig);
@@ -2189,12 +2204,24 @@ void
xaccTransSetDocLink (Transaction *trans, const char *doclink)
{
if (!trans || !doclink) return;
+
+ if (trans->doclink != is_unset)
+ {
+ if (!g_strcmp0 (doclink, trans->doclink))
+ return;
+
+ g_free (trans->doclink);
+ }
xaccTransBeginEdit(trans);
- if (g_strcmp0 (doclink, "") == 0)
+ if (doclink[0] == '\0')
+ {
+ trans->doclink = NULL;
qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, doclink_uri_str);
+ }
else
{
GValue v = G_VALUE_INIT;
+ trans->doclink = g_strdup (doclink);
g_value_init (&v, G_TYPE_STRING);
g_value_set_string (&v, doclink);
qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, doclink_uri_str);
@@ -2217,10 +2244,18 @@ xaccTransSetNotes (Transaction *trans, const char *notes)
{
GValue v = G_VALUE_INIT;
if (!trans || !notes) return;
+ if (trans->notes != is_unset)
+ {
+ if (!g_strcmp0 (notes, trans->notes))
+ return;
+
+ g_free (trans->notes);
+ }
g_value_init (&v, G_TYPE_STRING);
g_value_set_string (&v, notes);
xaccTransBeginEdit(trans);
+ trans->notes = g_strdup (notes);
qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
qof_instance_set_dirty(QOF_INSTANCE(trans));
g_value_unset (&v);
@@ -2382,23 +2417,31 @@ xaccTransGetDescription (const Transaction *trans)
const char *
xaccTransGetDocLink (const Transaction *trans)
{
- GValue v = G_VALUE_INIT;
- if (!trans) return NULL;
- qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, doclink_uri_str);
- if (G_VALUE_HOLDS_STRING (&v))
- return g_value_get_string (&v);
- return NULL;
+ g_return_val_if_fail (trans, NULL);
+ if (trans->doclink == is_unset)
+ {
+ GValue v = G_VALUE_INIT;
+ Transaction *t = (Transaction*) trans;
+ qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, doclink_uri_str);
+ t->doclink = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
+ g_value_unset (&v);
+ }
+ return trans->doclink;
}
const char *
xaccTransGetNotes (const Transaction *trans)
{
- GValue v = G_VALUE_INIT;
- if (!trans) return NULL;
- qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
- if (G_VALUE_HOLDS_STRING (&v))
- return g_value_get_string (&v);
- return NULL;
+ g_return_val_if_fail (trans, NULL);
+ if (trans->notes == is_unset)
+ {
+ GValue v = G_VALUE_INIT;
+ Transaction *t = (Transaction*) trans;
+ qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
+ t->notes = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
+ g_value_unset (&v);
+ }
+ return trans->notes;
}
gboolean
@@ -2746,6 +2789,9 @@ xaccTransVoid(Transaction *trans, const char *reason)
qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
g_value_set_string (&v, reason);
qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
+ if (trans->void_reason != is_unset)
+ g_free (trans->void_reason);
+ trans->void_reason = g_strdup (reason);
gnc_time64_to_iso8601_buff (gnc_time(NULL), iso8601_str);
g_value_set_string (&v, iso8601_str);
@@ -2762,31 +2808,23 @@ xaccTransVoid(Transaction *trans, const char *reason)
gboolean
xaccTransGetVoidStatus(const Transaction *trans)
{
- const char *s = NULL;
- GValue v = G_VALUE_INIT;
- gboolean retval = FALSE;
- g_return_val_if_fail(trans, FALSE);
-
- qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
- if (G_VALUE_HOLDS_STRING (&v))
- {
- s = g_value_get_string (&v);
- retval = (s && (s[0] != '\0'));
- }
- g_value_unset (&v);
- return retval;
+ const char *s = xaccTransGetVoidReason (trans);
+ return (s && *s);
}
const char *
xaccTransGetVoidReason(const Transaction *trans)
{
- GValue v = G_VALUE_INIT;
- g_return_val_if_fail(trans, FALSE);
-
- qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
- if (G_VALUE_HOLDS_STRING (&v))
- return g_value_get_string (&v);
- return NULL;
+ g_return_val_if_fail (trans, NULL);
+ if (trans->void_reason == is_unset)
+ {
+ GValue v = G_VALUE_INIT;
+ Transaction *t = (Transaction*) trans;
+ qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
+ t->void_reason = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
+ g_value_unset (&v);
+ }
+ return trans->void_reason;
}
time64
@@ -2815,10 +2853,7 @@ xaccTransUnvoid (Transaction *trans)
const char *s = NULL;
g_return_if_fail(trans);
- qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
- if (G_VALUE_HOLDS_STRING (&v))
- s = g_value_get_string (&v);
- g_value_unset (&v);
+ s = xaccTransGetVoidReason (trans);
if (s == NULL) return; /* Transaction isn't voided. Bail. */
xaccTransBeginEdit(trans);
@@ -2829,6 +2864,8 @@ xaccTransUnvoid (Transaction *trans)
qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, void_reason_str);
qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, void_time_str);
g_value_unset (&v);
+ g_free (trans->void_reason);
+ trans->void_reason = NULL;
FOR_EACH_SPLIT(trans, xaccSplitUnvoid(s));
diff --git a/libgnucash/engine/TransactionP.h b/libgnucash/engine/TransactionP.h
index c42f988c1..f7c455381 100644
--- a/libgnucash/engine/TransactionP.h
+++ b/libgnucash/engine/TransactionP.h
@@ -120,6 +120,10 @@ struct transaction_s
char * readonly_reason;
gboolean reason_cache_valid;
+ char * doclink;
+ char * void_reason;
+ char * notes;
+
/* Cached bool value to indicate whether this is a closing txn. This is
* cached from the KVP value because it is queried a lot. Tri-state value: -1
* = uninitialized; 0 = FALSE, 1 = TRUE. */
commit a47bee97d634204a742e05e02c18c5ad5107ff00
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Mon Aug 23 23:22:06 2021 +0800
[Split.c] GValue string must be unset
diff --git a/libgnucash/engine/Split.c b/libgnucash/engine/Split.c
index 9392ddd33..d771e1f8b 100644
--- a/libgnucash/engine/Split.c
+++ b/libgnucash/engine/Split.c
@@ -97,6 +97,10 @@ enum
};
+static const char * is_unset = "unset";
+static const char * split_type_normal = "normal";
+static const char * split_type_stock_split = "stock-split";
+
/* GObject Initialization */
G_DEFINE_TYPE(Split, gnc_split, QOF_TYPE_INSTANCE)
@@ -116,6 +120,7 @@ gnc_split_init(Split* split)
split->value = gnc_numeric_zero();
split->date_reconciled = 0;
+ split->split_type = is_unset;
split->balance = gnc_numeric_zero();
split->cleared_balance = gnc_numeric_zero();
@@ -714,6 +719,7 @@ xaccFreeSplit (Split *split)
split->lot = NULL;
split->acc = NULL;
split->orig_acc = NULL;
+ split->split_type = NULL;
split->date_reconciled = 0;
G_OBJECT_CLASS (QOF_INSTANCE_GET_CLASS (&split->inst))->dispose(G_OBJECT (split));
@@ -1968,14 +1974,26 @@ xaccSplitGetBook (const Split *split)
const char *
xaccSplitGetType(const Split *s)
{
- GValue v = G_VALUE_INIT;
- const char *split_type = NULL;
-
if (!s) return NULL;
- qof_instance_get_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
- if (G_VALUE_HOLDS_STRING (&v))
- split_type = g_value_get_string (&v);
- return split_type ? split_type : "normal";
+ if (s->split_type == is_unset)
+ {
+ GValue v = G_VALUE_INIT;
+ Split *split = (Split*) s;
+ const char* type;
+ qof_instance_get_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
+ type = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
+ if (!type || !g_strcmp0 (type, split_type_normal))
+ split->split_type = (char*) split_type_normal;
+ else if (!g_strcmp0 (type, split_type_stock_split))
+ split->split_type = (char*) split_type_stock_split;
+ else
+ {
+ PERR ("unexpected split-type %s, reset to normal.", type);
+ split->split_type = split_type_normal;
+ }
+ g_value_unset (&v);
+ }
+ return s->split_type;
}
/* reconfigure a split to be a stock split - after this, you shouldn't
@@ -1988,7 +2006,8 @@ xaccSplitMakeStockSplit(Split *s)
s->value = gnc_numeric_zero();
g_value_init (&v, G_TYPE_STRING);
- g_value_set_string (&v, "stock-split");
+ g_value_set_static_string (&v, split_type_stock_split);
+ s->split_type = split_type_stock_split;
qof_instance_set_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
SET_GAINS_VDIRTY(s);
mark_split(s);
diff --git a/libgnucash/engine/SplitP.h b/libgnucash/engine/SplitP.h
index 335db9174..4192cc5dd 100644
--- a/libgnucash/engine/SplitP.h
+++ b/libgnucash/engine/SplitP.h
@@ -115,6 +115,8 @@ struct split_s
gnc_numeric value;
gnc_numeric amount;
+ const gchar * split_type;
+
/* -------------------------------------------------------------- */
/* Below follow some 'temporary' fields */
commit 0ecbcb4ef1701732872a205779633e3e36160bbf
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Mon Aug 23 23:21:46 2021 +0800
[gnc-lot.c] GValue string must be unset
diff --git a/libgnucash/engine/gnc-lot.c b/libgnucash/engine/gnc-lot.c
index d1b411782..a8eaf7902 100644
--- a/libgnucash/engine/gnc-lot.c
+++ b/libgnucash/engine/gnc-lot.c
@@ -86,6 +86,9 @@ typedef struct GNCLotPrivate
/* List of splits that belong to this lot. */
SplitList *splits;
+ char *title;
+ char *notes;
+
GncInvoice *cached_invoice;
/* Handy cached value to indicate if lot is closed. */
/* If value is negative, then the cache is invalid. */
@@ -103,6 +106,9 @@ typedef struct GNCLotPrivate
/* ============================================================= */
+static char*
+is_unset = "unset";
+
/* GObject Initialization */
G_DEFINE_TYPE_WITH_PRIVATE(GNCLot, gnc_lot, QOF_TYPE_INSTANCE)
@@ -116,6 +122,8 @@ gnc_lot_init(GNCLot* lot)
priv->splits = NULL;
priv->cached_invoice = NULL;
priv->is_closed = LOT_CLOSED_UNKNOWN;
+ priv->title = is_unset;
+ priv->notes = is_unset;
priv->marker = 0;
}
@@ -295,6 +303,14 @@ gnc_lot_free(GNCLot* lot)
if (priv->account && !qof_instance_get_destroying(priv->account))
xaccAccountRemoveLot (priv->account, lot);
+ if (priv->notes != is_unset)
+ g_free (priv->notes);
+
+ if (priv->title != is_unset)
+ g_free (priv->title);
+
+ priv->notes = NULL;
+ priv->title = NULL;
priv->account = NULL;
priv->is_closed = TRUE;
/* qof_instance_release (&lot->inst); */
@@ -439,30 +455,46 @@ gint gnc_lot_count_splits (const GNCLot *lot)
const char *
gnc_lot_get_title (const GNCLot *lot)
{
- GValue v = G_VALUE_INIT;
+ GNCLotPrivate* priv;
if (!lot) return NULL;
- qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "title");
- if (G_VALUE_HOLDS_STRING (&v))
- return g_value_get_string (&v);
- return NULL;
+ priv = GET_PRIVATE (lot);
+ if (priv->title == is_unset)
+ {
+ GNCLotPrivate* priv = GET_PRIVATE (lot);
+ GValue v = G_VALUE_INIT;
+ qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "title");
+ priv->title = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
+ g_value_unset (&v);
+ }
+ return priv->title;
}
const char *
gnc_lot_get_notes (const GNCLot *lot)
{
- GValue v = G_VALUE_INIT;
+ GNCLotPrivate* priv;
if (!lot) return NULL;
- qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
- if (G_VALUE_HOLDS_STRING (&v))
- return g_value_get_string (&v);
- return NULL;
+ priv = GET_PRIVATE (lot);
+ if (priv->notes == is_unset)
+ {
+ GValue v = G_VALUE_INIT;
+ qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
+ priv->notes = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
+ g_value_unset (&v);
+ }
+ return priv->notes;
}
void
gnc_lot_set_title (GNCLot *lot, const char *str)
{
GValue v = G_VALUE_INIT;
+ GNCLotPrivate* priv;
if (!lot) return;
+ priv = GET_PRIVATE (lot);
+ if (priv->title != is_unset)
+ g_free (priv->title);
+
qof_begin_edit(QOF_INSTANCE(lot));
g_value_init (&v, G_TYPE_STRING);
g_value_set_string (&v, str);
@@ -476,7 +508,11 @@ void
gnc_lot_set_notes (GNCLot *lot, const char *str)
{
GValue v = G_VALUE_INIT;
+ GNCLotPrivate* priv;
if (!lot) return;
+ priv = GET_PRIVATE (lot);
+ if (priv->notes != is_unset)
+ g_free (priv->notes);
qof_begin_edit(QOF_INSTANCE(lot));
g_value_init (&v, G_TYPE_STRING);
g_value_set_string (&v, str);
commit ac2afc7e13babd4c850e3831318a705f9996feef
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Mon Aug 23 18:44:23 2021 +0800
[gncInvoice.c] GValue string must be unset
diff --git a/libgnucash/engine/gncInvoice.c b/libgnucash/engine/gncInvoice.c
index 6ab155f81..f3a5c5db1 100644
--- a/libgnucash/engine/gncInvoice.c
+++ b/libgnucash/engine/gncInvoice.c
@@ -65,6 +65,8 @@ struct _gncInvoice
time64 date_opened;
time64 date_posted;
+ char *doclink;
+
gnc_numeric to_charge_amount;
gnc_commodity *currency;
@@ -282,6 +284,9 @@ impl_get_typed_referring_object_list (const QofInstance* inst, const QofInstance
return qof_instance_get_referring_object_list_from_collection (qof_instance_get_collection (inst), ref);
}
+static const char*
+is_unset = "unset";
+
static void
gnc_invoice_class_init (GncInvoiceClass *klass)
{
@@ -327,6 +332,7 @@ GncInvoice *gncInvoiceCreate (QofBook *book)
invoice->active = TRUE;
invoice->to_charge_amount = gnc_numeric_zero ();
+ invoice->doclink = (char*) is_unset;
qof_event_gen (&invoice->inst, QOF_EVENT_CREATE, NULL);
@@ -372,6 +378,8 @@ GncInvoice *gncInvoiceCopy (const GncInvoice *from)
// Oops. Do not forget to copy the pointer to the correct currency here.
invoice->currency = from->currency;
+ invoice->doclink = from->doclink;
+
// Copy all invoice->entries
for (node = from->entries; node; node = node->next)
{
@@ -428,6 +436,9 @@ static void gncInvoiceFree (GncInvoice *invoice)
if (invoice->terms)
gncBillTermDecRef (invoice->terms);
+ if (invoice->doclink != is_unset)
+ g_free (invoice->doclink);
+
/* qof_instance_release (&invoice->inst); */
g_object_unref (invoice);
}
@@ -538,15 +549,29 @@ void gncInvoiceSetNotes (GncInvoice *invoice, const char *notes)
void gncInvoiceSetDocLink (GncInvoice *invoice, const char *doclink)
{
if (!invoice || !doclink) return;
+
+ if (invoice->doclink != is_unset)
+ {
+ if (!g_strcmp0 (doclink, invoice->doclink))
+ return;
+
+ g_free (invoice->doclink);
+ }
+
gncInvoiceBeginEdit (invoice);
- if (g_strcmp0 (doclink, "") == 0)
+
+ if (doclink[0] == '\0')
+ {
+ invoice->doclink = NULL;
qof_instance_set_kvp (QOF_INSTANCE (invoice), NULL, 1, GNC_INVOICE_DOCLINK);
+ }
else
{
GValue v = G_VALUE_INIT;
g_value_init (&v, G_TYPE_STRING);
g_value_set_string (&v, doclink);
qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_DOCLINK);
+ invoice->doclink = g_strdup (doclink);
g_value_unset (&v);
}
qof_instance_set_dirty (QOF_INSTANCE(invoice));
@@ -864,12 +889,16 @@ const char * gncInvoiceGetNotes (const GncInvoice *invoice)
const char * gncInvoiceGetDocLink (const GncInvoice *invoice)
{
- GValue v = G_VALUE_INIT;
if (!invoice) return NULL;
- qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_DOCLINK);
- if (G_VALUE_HOLDS_STRING(&v))
- return g_value_get_string (&v);
- return NULL;
+ if (invoice->doclink == is_unset)
+ {
+ GValue v = G_VALUE_INIT;
+ GncInvoice *inv = (GncInvoice*) invoice;
+ qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_DOCLINK);
+ inv->doclink = G_VALUE_HOLDS_STRING(&v) ? g_value_dup_string (&v) : NULL;
+ g_value_unset (&v);
+ }
+ return invoice->doclink;
}
GncOwnerType gncInvoiceGetOwnerType (const GncInvoice *invoice)
commit 3bf49ed8d7c806a550d07fc2d803b64c2e78f196
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Mon Aug 23 18:05:08 2021 +0800
[Account.cpp] GValue string must be unset
diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index ba0942758..14e4dfd4b 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -286,6 +286,8 @@ mark_account (Account *acc)
/********************************************************************\
\********************************************************************/
+static constexpr const char* is_unset {"unset"};
+
/* GObject Initialization */
G_DEFINE_TYPE_WITH_PRIVATE(Account, gnc_account, QOF_TYPE_INSTANCE)
@@ -323,6 +325,13 @@ gnc_account_init(Account* acc)
priv->starting_reconciled_balance = gnc_numeric_zero();
priv->balance_dirty = FALSE;
+ priv->color == is_unset;
+ priv->sort_order == is_unset;
+ priv->notes == is_unset;
+ priv->filter == is_unset;
+ priv->equity_type == TriState::Unset;
+ priv->sort_reversed == TriState::Unset;
+
priv->splits = NULL;
priv->sort_dirty = FALSE;
}
@@ -1365,9 +1374,23 @@ xaccFreeAccount (Account *acc)
qof_string_cache_remove(priv->description);
priv->accountName = priv->accountCode = priv->description = nullptr;
+ if (priv->color != is_unset)
+ g_free (priv->color);
+ if (priv->sort_order != is_unset)
+ g_free (priv->sort_order);
+ if (priv->notes != is_unset)
+ g_free (priv->notes);
+ if (priv->filter != is_unset)
+ g_free (priv->filter);
+
/* zero out values, just in case stray
* pointers are pointing here. */
+ priv->color == nullptr;
+ priv->sort_order == nullptr;
+ priv->notes == nullptr;
+ priv->filter == nullptr;
+
priv->parent = nullptr;
priv->children = nullptr;
@@ -2476,36 +2499,52 @@ set_kvp_string_tag (Account *acc, const char *tag, const char *value)
xaccAccountCommitEdit(acc);
}
-static const char*
+static char*
get_kvp_string_tag (const Account *acc, const char *tag)
{
GValue v = G_VALUE_INIT;
if (acc == NULL || tag == NULL) return NULL;
qof_instance_get_path_kvp (QOF_INSTANCE (acc), &v, {tag});
- return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
+ auto retval = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
+ g_value_unset (&v);
+ return retval;
}
void
xaccAccountSetColor (Account *acc, const char *str)
{
+ auto priv = GET_PRIVATE (acc);
+ if (priv->color != is_unset)
+ g_free (priv->color);
+ priv->color = g_strdup (str);
set_kvp_string_tag (acc, "color", str);
}
void
xaccAccountSetFilter (Account *acc, const char *str)
{
+ auto priv = GET_PRIVATE (acc);
+ if (priv->filter != is_unset)
+ g_free (priv->filter);
+ priv->filter = g_strdup (str);
set_kvp_string_tag (acc, "filter", str);
}
void
xaccAccountSetSortOrder (Account *acc, const char *str)
{
+ auto priv = GET_PRIVATE (acc);
+ if (priv->sort_order != is_unset)
+ g_free (priv->sort_order);
+ priv->sort_order = g_strdup (str);
set_kvp_string_tag (acc, "sort-order", str);
}
void
xaccAccountSetSortReversed (Account *acc, gboolean sortreversed)
{
+ auto priv = GET_PRIVATE (acc);
+ priv->sort_reversed = sortreversed ? TriState::True : TriState::False;
set_kvp_string_tag (acc, "sort-reversed", sortreversed ? "true" : NULL);
}
@@ -2530,6 +2569,10 @@ qofAccountSetParent (Account *acc, QofInstance *parent)
void
xaccAccountSetNotes (Account *acc, const char *str)
{
+ auto priv = GET_PRIVATE (acc);
+ if (priv->notes != is_unset)
+ g_free (priv->notes);
+ priv->notes = g_strdup (str);
set_kvp_string_tag (acc, "notes", str);
}
@@ -3250,21 +3293,30 @@ const char *
xaccAccountGetColor (const Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
- return get_kvp_string_tag (acc, "color");
+ auto priv = GET_PRIVATE (acc);
+ if (priv->color == is_unset)
+ priv->color = get_kvp_string_tag (acc, "color");
+ return priv->color;
}
const char *
xaccAccountGetFilter (const Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
- return get_kvp_string_tag (acc, "filter");
+ auto priv = GET_PRIVATE (acc);
+ if (priv->filter == is_unset)
+ priv->filter = get_kvp_string_tag (acc, "filter");
+ return priv->filter;
}
const char *
xaccAccountGetSortOrder (const Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
- return get_kvp_string_tag (acc, "sort-order");
+ auto priv = GET_PRIVATE (acc);
+ if (priv->sort_order == is_unset)
+ priv->sort_order = get_kvp_string_tag (acc, "sort-order");
+ return priv->sort_order;
}
gboolean
@@ -3272,14 +3324,25 @@ xaccAccountGetSortReversed (const Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
- return g_strcmp0 (get_kvp_string_tag (acc, "sort-reversed"), "true") == 0;
+ auto priv = GET_PRIVATE (acc);
+ if (priv->sort_reversed == TriState::Unset)
+ {
+ auto sort_reversed = get_kvp_string_tag (acc, "sort-reversed");
+ priv->sort_reversed = g_strcmp0 (sort_reversed, "true") ?
+ TriState::False : TriState::True;
+ g_free (sort_reversed);
+ }
+ return (priv->sort_reversed == TriState::True);
}
const char *
xaccAccountGetNotes (const Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
- return get_kvp_string_tag (acc, "notes");
+ auto priv = GET_PRIVATE (acc);
+ if (priv->notes == is_unset)
+ priv->notes = get_kvp_string_tag (acc, "notes");
+ return priv->notes;
}
gnc_commodity *
@@ -4142,7 +4205,15 @@ xaccAccountGetIsOpeningBalance (const Account *acc)
{
if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
return false;
- return g_strcmp0(get_kvp_string_tag(acc, "equity-type"), "opening-balance") == 0;
+ auto priv = GET_PRIVATE(acc);
+ if (priv->equity_type == TriState::Unset)
+ {
+ auto equity_type = get_kvp_string_tag (acc, "equity-type");
+ priv->equity_type = g_strcmp0 (equity_type, "true") ?
+ TriState::False : TriState::True;
+ g_free (equity_type);
+ }
+ return (priv->equity_type == TriState::True);
}
void
@@ -4150,6 +4221,8 @@ xaccAccountSetIsOpeningBalance (Account *acc, gboolean val)
{
if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
return;
+ auto priv = GET_PRIVATE (acc);
+ priv->equity_type = val ? TriState::True : TriState::False;
set_kvp_string_tag(acc, "equity-type", val ? "opening-balance" : "");
}
diff --git a/libgnucash/engine/AccountP.h b/libgnucash/engine/AccountP.h
index 746a1c504..250232206 100644
--- a/libgnucash/engine/AccountP.h
+++ b/libgnucash/engine/AccountP.h
@@ -55,6 +55,13 @@ extern "C" {
* No one outside of the engine should ever include this file.
*/
+typedef enum
+{
+ Unset = -1,
+ False,
+ True
+} TriState;
+
/** \struct Account */
typedef struct AccountPrivate
{
@@ -122,6 +129,13 @@ typedef struct AccountPrivate
LotList *lots; /* list of lot pointers */
GNCPolicy *policy; /* Cached pointer to policy method */
+ TriState sort_reversed;
+ TriState equity_type;
+ char *notes;
+ char *color;
+ char *sort_order;
+ char *filter;
+
/* The "mark" flag can be used by the user to mark this account
* in any way desired. Handy for specialty traversals of the
* account tree. */
commit e3af2f22f9aec70131dc2da8d9c9eceade1a52ad
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Sun Aug 22 11:17:28 2021 +0800
[gnc-commodity.c] cache user_symbol into commodity struct
Continuation of ff2ceb111 which introduced issue whereby user_symbol
returned could become stale, leading to invalid read fixed with
c398bef59. There are likely other user_symbol pointers becoming stale
without this commit.
This change will save the user_symbol into the commodity struct,
avoids gchar* becoming stale.
diff --git a/libgnucash/engine/gnc-commodity.c b/libgnucash/engine/gnc-commodity.c
index 56763e7a0..745be68bc 100644
--- a/libgnucash/engine/gnc-commodity.c
+++ b/libgnucash/engine/gnc-commodity.c
@@ -76,6 +76,7 @@ typedef struct gnc_commodityPrivate
const char *cusip; /* CUSIP or other identifying code */
int fraction;
char *unique_name;
+ char *user_symbol;
gboolean quote_flag; /* user wants price quotes */
gnc_quote_source *quote_source; /* current/old source of quotes */
@@ -89,6 +90,9 @@ typedef struct gnc_commodityPrivate
const char *default_symbol;
} gnc_commodityPrivate;
+static const char*
+is_unset = "unset";
+
#define GET_PRIVATE(o) \
((gnc_commodityPrivate*)g_type_instance_get_private((GTypeInstance*)o, GNC_TYPE_COMMODITY))
@@ -667,6 +671,7 @@ gnc_commodity_init(gnc_commodity* com)
priv->quote_flag = 0;
priv->quote_source = NULL;
priv->quote_tz = CACHE_INSERT("");
+ priv->user_symbol = (char*) is_unset;
reset_printname(priv);
reset_unique_name(priv);
@@ -951,6 +956,10 @@ commodity_free(gnc_commodity * cm)
g_free(priv->unique_name);
priv->unique_name = NULL;
+ if (priv->user_symbol != is_unset)
+ g_free (priv->user_symbol);
+ priv->user_symbol = NULL;
+
#ifdef ACCOUNTS_CLEANED_UP
/* Account objects are not actually cleaned up when a book is closed (in fact
* a memory leak), but commodities are, so in currently this warning gets hit
@@ -1182,14 +1191,17 @@ gnc_commodity_get_quote_tz(const gnc_commodity *cm)
const char*
gnc_commodity_get_user_symbol(const gnc_commodity *cm)
{
- GValue v = G_VALUE_INIT;
- static char* retval = NULL;
- if (!cm) return NULL;
- qof_instance_get_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
- g_free (retval);
- retval = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v): NULL;
- g_value_unset (&v);
- return retval;
+ gnc_commodityPrivate* priv;
+ g_return_val_if_fail (GNC_IS_COMMODITY (cm), NULL);
+ priv = GET_PRIVATE(cm);
+ if (priv->user_symbol == is_unset)
+ {
+ GValue v = G_VALUE_INIT;
+ qof_instance_get_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
+ priv->user_symbol = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
+ g_value_unset (&v);
+ }
+ return priv->user_symbol;
}
/********************************************************************
@@ -1477,13 +1489,13 @@ void
gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
{
struct lconv *lc;
- GValue v = G_VALUE_INIT;
+ gnc_commodityPrivate* priv;
+
if (!cm) return;
+ priv = GET_PRIVATE(cm);
ENTER ("(cm=%p, symbol=%s)", cm, user_symbol ? user_symbol : "(null)");
- gnc_commodity_begin_edit(cm);
-
lc = gnc_localeconv();
if (!user_symbol || !*user_symbol)
user_symbol = NULL;
@@ -1494,15 +1506,33 @@ gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
user_symbol = NULL;
else if (!g_strcmp0(user_symbol, gnc_commodity_get_default_symbol(cm)))
user_symbol = NULL;
+
+ if (priv->user_symbol != is_unset)
+ {
+ if (!g_strcmp0 (user_symbol, priv->user_symbol))
+ {
+ LEAVE ("gnc_commodity_set_user_symbol: no change");
+ return;
+ }
+ g_free (priv->user_symbol);
+ }
+
+ gnc_commodity_begin_edit (cm);
+
if (user_symbol)
{
+ GValue v = G_VALUE_INIT;
g_value_init (&v, G_TYPE_STRING);
g_value_set_string (&v, user_symbol);
qof_instance_set_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
+ priv->user_symbol = g_strdup (user_symbol);
g_value_unset (&v);
}
else
+ {
qof_instance_set_kvp (QOF_INSTANCE(cm), NULL, 1, "user_symbol");
+ priv->user_symbol = NULL;
+ }
mark_commodity_dirty(cm);
gnc_commodity_commit_edit(cm);
Summary of changes:
gnucash/gnome/dialog-custom-report.c | 6 ++
gnucash/gnome/gnc-budget-view.c | 12 +++
gnucash/import-export/import-main-matcher.c | 3 +
libgnucash/engine/Account.cpp | 89 ++++++++++++++++++++--
libgnucash/engine/AccountP.h | 14 ++++
libgnucash/engine/Split.c | 35 +++++++--
libgnucash/engine/SplitP.h | 2 +
libgnucash/engine/Transaction.c | 111 ++++++++++++++++++----------
libgnucash/engine/TransactionP.h | 4 +
libgnucash/engine/gnc-commodity.c | 52 ++++++++++---
libgnucash/engine/gnc-lot.c | 56 +++++++++++---
libgnucash/engine/gncInvoice.c | 41 ++++++++--
12 files changed, 345 insertions(+), 80 deletions(-)
More information about the gnucash-changes
mailing list