add kvp support for slash-separated keys for frame paths,

so now you can specify kvp paths /just/like/this
a few additional routines added that use fewer mallocs/frees
to poke data into kvp trees; account.c and transaction.c
converted to use these routines (resulting in a few mem-leak fixes)


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3637 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 2001-02-12 07:15:37 +00:00
parent 5c51a5f2ca
commit eeb76cd05b
6 changed files with 256 additions and 156 deletions

View File

@ -1066,24 +1066,14 @@ xaccAccountSetDescription (Account *acc, const char *str) {
}
void
xaccAccountSetNotes (Account *acc, const char *str) {
kvp_value *new_value;
xaccAccountSetNotes (Account *acc, const char *str)
{
if ((!acc) || (!str)) return;
xaccAccountBeginEdit(acc);
{
new_value = kvp_value_new_string(str);
if(new_value) {
kvp_frame_set_slot(xaccAccountGetSlots(acc), "notes", new_value);
kvp_value_delete(new_value);
}
else {
PERR ("failed to allocate kvp");
}
mark_account (acc);
}
kvp_frame_set_slot_nc(acc->kvp_data, "notes",
kvp_value_new_string(str));
mark_account (acc);
acc->core_dirty = TRUE;
xaccAccountCommitEdit(acc);
}
@ -1344,11 +1334,12 @@ xaccAccountGetDescription (Account *acc)
}
const char *
xaccAccountGetNotes (Account *acc) {
xaccAccountGetNotes (Account *acc)
{
kvp_value *v;
if (!acc) return NULL;
v = kvp_frame_get_slot(xaccAccountGetSlots(acc), "notes");
v = kvp_frame_get_slot(acc->kvp_data, "notes");
if(v) return(kvp_value_get_string(v));
return(NULL);
}
@ -1497,7 +1488,7 @@ xaccAccountGetTaxRelated (Account *account)
if (!account)
return FALSE;
kvp = kvp_frame_get_slot (xaccAccountGetSlots (account), "tax-related");
kvp = kvp_frame_get_slot (account->kvp_data, "tax-related");
if (!kvp)
return FALSE;
@ -1518,15 +1509,9 @@ xaccAccountSetTaxRelated (Account *account, gboolean tax_related)
new_value = NULL;
xaccAccountBeginEdit (account);
{
kvp_frame_set_slot(xaccAccountGetSlots (account),
"tax-related", new_value);
kvp_frame_set_slot_nc(account->kvp_data, "tax-related", new_value);
if (new_value)
kvp_value_delete(new_value);
mark_account (account);
}
mark_account (account);
account->core_dirty = TRUE;
xaccAccountCommitEdit (account);
}
@ -1727,7 +1712,7 @@ xaccAccountGetReconcileLastDate (Account *account, time_t *last_date)
if (!account)
return FALSE;
value = kvp_frame_get_slot_path (xaccAccountGetSlots (account),
value = kvp_frame_get_slot_path (account->kvp_data,
"reconcile-info", "last-date", NULL);
if (!value)
return FALSE;
@ -1745,30 +1730,27 @@ xaccAccountGetReconcileLastDate (Account *account, time_t *last_date)
/********************************************************************\
\********************************************************************/
void
xaccAccountSetReconcileLastDate (Account *account, time_t last_date)
{
kvp_frame *frame;
if (!account)
return;
xaccAccountBeginEdit (account);
{
kvp_value *value;
value = kvp_value_new_gint64 (last_date);
frame = kvp_frame_get_frame (account->kvp_data, "reconcile-info", NULL);
kvp_frame_set_slot_nc (frame, "last-date",
kvp_value_new_gint64 (last_date));
kvp_frame_set_slot_path (xaccAccountGetSlots (account), value,
"reconcile-info", "last-date", NULL);
kvp_value_delete (value);
mark_account (account);
}
mark_account (account);
account->core_dirty = TRUE;
xaccAccountCommitEdit (account);
}
/********************************************************************\
\********************************************************************/
gboolean
xaccAccountGetReconcilePostponeDate (Account *account,
time_t *postpone_date)
@ -1778,7 +1760,7 @@ xaccAccountGetReconcilePostponeDate (Account *account,
if (!account)
return FALSE;
value = kvp_frame_get_slot_path (xaccAccountGetSlots (account),
value = kvp_frame_get_slot_path (account->kvp_data,
"reconcile-info", "postpone", "date", NULL);
if (!value)
return FALSE;
@ -1796,32 +1778,30 @@ xaccAccountGetReconcilePostponeDate (Account *account,
/********************************************************************\
\********************************************************************/
void
xaccAccountSetReconcilePostponeDate (Account *account,
time_t postpone_date)
{
kvp_frame *frame;
if (!account)
return;
xaccAccountBeginEdit (account);
{
kvp_value *value;
frame = kvp_frame_get_frame (account->kvp_data,
"reconcile-info", "postpone", NULL);
value = kvp_value_new_gint64 (postpone_date);
kvp_frame_set_slot_nc (frame, "date",
kvp_value_new_gint64 (postpone_date));
kvp_frame_set_slot_path (xaccAccountGetSlots (account), value,
"reconcile-info", "postpone", "date", NULL);
kvp_value_delete (value);
mark_account (account);
}
mark_account (account);
account->core_dirty = TRUE;
xaccAccountCommitEdit (account);
}
/********************************************************************\
\********************************************************************/
gboolean
xaccAccountGetReconcilePostponeBalance (Account *account,
gnc_numeric *balance)
@ -1831,7 +1811,7 @@ xaccAccountGetReconcilePostponeBalance (Account *account,
if (!account)
return FALSE;
value = kvp_frame_get_slot_path (xaccAccountGetSlots (account),
value = kvp_frame_get_slot_path (account->kvp_data,
"reconcile-info", "postpone", "balance",
NULL);
if (!value)
@ -1850,32 +1830,31 @@ xaccAccountGetReconcilePostponeBalance (Account *account,
/********************************************************************\
\********************************************************************/
void
xaccAccountSetReconcilePostponeBalance (Account *account,
gnc_numeric balance)
{
kvp_frame *frame;
if (!account)
return;
xaccAccountBeginEdit (account);
{
kvp_value *value;
frame = kvp_frame_get_frame (account->kvp_data,
"reconcile-info", "postpone", NULL);
value = kvp_value_new_gnc_numeric (balance);
kvp_frame_set_slot_nc (frame, "balance",
kvp_value_new_gnc_numeric (balance));
kvp_frame_set_slot_path (xaccAccountGetSlots (account), value,
"reconcile-info", "postpone", "balance", NULL);
kvp_value_delete (value);
mark_account (account);
}
mark_account (account);
account->core_dirty = TRUE;
xaccAccountCommitEdit (account);
}
/********************************************************************\
\********************************************************************/
void
xaccAccountClearReconcilePostpone (Account *account)
{
@ -1884,7 +1863,7 @@ xaccAccountClearReconcilePostpone (Account *account)
xaccAccountBeginEdit (account);
{
kvp_frame_set_slot_path (xaccAccountGetSlots (account), NULL,
kvp_frame_set_slot_path (account->kvp_data, NULL,
"reconcile-info", "postpone", NULL);
mark_account (account);
@ -1895,6 +1874,7 @@ xaccAccountClearReconcilePostpone (Account *account)
/********************************************************************\
\********************************************************************/
const char *
xaccAccountGetLastNum (Account *account)
{
@ -1903,7 +1883,7 @@ xaccAccountGetLastNum (Account *account)
if (!account)
return FALSE;
value = kvp_frame_get_slot (xaccAccountGetSlots (account), "last-num");
value = kvp_frame_get_slot (account->kvp_data, "last-num");
if (!value)
return FALSE;
@ -1912,6 +1892,7 @@ xaccAccountGetLastNum (Account *account)
/********************************************************************\
\********************************************************************/
void
xaccAccountSetLastNum (Account *account, const char *num)
{
@ -1919,25 +1900,19 @@ xaccAccountSetLastNum (Account *account, const char *num)
return;
xaccAccountBeginEdit (account);
{
kvp_value *value;
value = kvp_value_new_string (num);
kvp_frame_set_slot (xaccAccountGetSlots (account), "last-num", value);
kvp_value_delete (value);
mark_account (account);
}
kvp_frame_set_slot_nc (account->kvp_data, "last-num",
kvp_value_new_string (num));
mark_account (account);
account->core_dirty = TRUE;
xaccAccountCommitEdit (account);
}
/********************************************************************\
\********************************************************************/
void
xaccAccountSetPriceSrc(Account *acc, const char *src) {
xaccAccountSetPriceSrc(Account *acc, const char *src)
{
if(!acc) return;
if(!src) return;
@ -1947,16 +1922,10 @@ xaccAccountSetPriceSrc(Account *acc, const char *src) {
GNCAccountType t = xaccAccountGetType(acc);
if((t == STOCK) || (t == MUTUAL)) {
kvp_value *new_value = kvp_value_new_string(src);
if(new_value) {
kvp_frame_set_slot(xaccAccountGetSlots(acc),
kvp_frame_set_slot_nc(acc->kvp_data,
"old-price-source",
new_value);
kvp_value_delete(new_value);
mark_account (acc);
} else {
PERR ("xaccAccountSetPriceSrc: failed to allocate kvp_value.");
}
kvp_value_new_string(src));
mark_account (acc);
}
}
acc->core_dirty = TRUE;
@ -1967,22 +1936,19 @@ xaccAccountSetPriceSrc(Account *acc, const char *src) {
\********************************************************************/
const char*
xaccAccountGetPriceSrc(Account *acc) {
const char *result = NULL;
xaccAccountGetPriceSrc(Account *acc)
{
GNCAccountType t;
if(!acc) return NULL;
if(!acc) {
result = NULL;
} else {
GNCAccountType t = xaccAccountGetType(acc);
if((t == STOCK) || (t == MUTUAL)) {
kvp_value *value = kvp_frame_get_slot(xaccAccountGetSlots(acc),
t = xaccAccountGetType(acc);
if((t == STOCK) || (t == MUTUAL))
{
kvp_value *value = kvp_frame_get_slot(acc->kvp_data,
"old-price-source");
if(value) {
result = kvp_value_get_string(value);
}
}
if(value) return (kvp_value_get_string(value));
}
return(result);
return NULL;
}
/********************************************************************\

View File

@ -1917,23 +1917,12 @@ xaccTransSetDescription (Transaction *trans, const char *desc)
void
xaccTransSetNotes (Transaction *trans, const char *notes)
{
kvp_value *new_value;
if (!trans || !notes) return;
check_open (trans);
new_value = kvp_value_new_string (notes);
if (new_value)
{
kvp_frame_set_slot (xaccTransGetSlots (trans), "notes", new_value);
kvp_value_delete (new_value);
mark_trans (trans);
}
else
{
PERR ("failed to allocate kvp");
}
kvp_frame_set_slot_nc (trans->kvp_data, "notes",
kvp_value_new_string (notes));
mark_trans (trans);
}
/********************************************************************\
@ -2226,11 +2215,10 @@ xaccSplitGetType(const Split *s)
void
xaccSplitMakeStockSplit(Split *s)
{
kvp_frame *frame = xaccSplitGetSlots(s);
check_open (s->parent);
xaccSplitSetValue(s, gnc_numeric_zero());
kvp_frame_set_slot(frame,
kvp_frame_set_slot_nc(s->kvp_data,
"split-type",
kvp_value_new_string("stock-split"));
mark_split(s);

View File

@ -88,14 +88,11 @@ back_associate_expense_accounts(Account *stock_account,
g_return_if_fail(xaccGUIDType(existing_acc_guid) == GNC_ID_NONE);
kvp_frame_set_slot(acc_frame, "associated-stock-account",
kvp_frame_set_slot_nc(acc_frame, "associated-stock-account",
stock_acc_guid_kvpval);
kvp_value_delete(stock_acc_guid_kvpval);
kvp_frame_set_slot(acc_frame, "associated-stock-account-category",
kvp_frame_set_slot_nc(acc_frame, "associated-stock-account-category",
stock_acc_category_kvpval);
kvp_value_delete(stock_acc_category_kvpval);
}
return;
@ -124,12 +121,10 @@ back_associate_income_accounts(Account *stock_account,
g_return_if_fail(xaccGUIDType(existing_acc_guid) == GNC_ID_NONE);
kvp_frame_set_slot(acc_frame, "associated-stock-account",
kvp_frame_set_slot_nc(acc_frame, "associated-stock-account",
stock_acc_guid_kvpval);
kvp_value_delete(stock_acc_guid_kvpval);
kvp_frame_set_slot(acc_frame, "associated-stock-account-category",
kvp_frame_set_slot_nc(acc_frame, "associated-stock-account-category",
stock_acc_category_kvpval);
kvp_value_delete(stock_acc_category_kvpval);
}
return;
@ -221,12 +216,9 @@ gnc_tracking_associate_income_accounts(Account *stock_account,
back_associate_income_accounts(stock_account, account_list, category);
kvp_frame_set_slot(inc_account_frame,
kvp_frame_set_slot_nc(inc_account_frame,
income_to_key[category],
kvpd_on_account_list);
kvp_value_delete(kvpd_on_account_list);
return;
}
/*********************************************************************\
@ -265,11 +257,9 @@ void gnc_tracking_asssociate_expense_account(Account *stock_account,
back_associate_expense_accounts(stock_account, account_list, category);
kvp_frame_set_slot(expense_acc_frame,
kvp_frame_set_slot_nc(expense_acc_frame,
expense_to_key[category],
kvpd_on_account_list);
kvp_value_delete(kvpd_on_account_list);
return;
}
/*********************************************************************\
@ -285,7 +275,7 @@ void gnc_tracking_asssociate_expense_account(Account *stock_account,
\*********************************************************************/
GList *gnc_tracking_find_expense_accounts(Account *stock_account,
GNCTrackingExpenseCategory category)
GNCTrackingExpenseCategory category)
{
GNCAccountType type;
@ -462,10 +452,9 @@ gnc_tracking_dissociate_account(Account *inc_or_expense_account)
assoc_acc_list_start = g_list_remove_link(assoc_acc_list_start, assoc_acc_list);
g_list_free_1(assoc_acc_list);
acc_list_kvpval = kvp_value_new_glist_nc(assoc_acc_list);
kvp_frame_set_slot(assoc_acc_kvpframe,
kvp_frame_set_slot_nc(assoc_acc_kvpframe,
category_name,
acc_list_kvpval);
kvp_value_delete(acc_list_kvpval);
return;
}
}
@ -473,11 +462,4 @@ gnc_tracking_dissociate_account(Account *inc_or_expense_account)
PERR("Income/Expense account and stock account disagree on association");
}
/* ========================== END OF FILE ===================== */

View File

@ -907,8 +907,7 @@ readTransaction( int fd, Account *acc, int token )
free(tmp);
return(NULL);
}
kvp_frame_set_slot(xaccTransGetSlots(trans), "old-docref", new_value);
kvp_value_delete(new_value);
kvp_frame_set_slot_nc(xaccTransGetSlots(trans), "old-docref", new_value);
}
free (tmp);
}
@ -1252,8 +1251,7 @@ readSplit ( int fd, int token )
free(tmp);
return(NULL);
}
kvp_frame_set_slot(xaccSplitGetSlots(split), "old-docref", new_value);
kvp_value_delete(new_value);
kvp_frame_set_slot_nc(xaccSplitGetSlots(split), "old-docref", new_value);
}
free (tmp);
}

View File

@ -23,6 +23,7 @@
#include "config.h"
#define _GNU_SOURCE
#include <glib.h>
#include <stdio.h>
#include <string.h>
@ -185,6 +186,17 @@ kvp_frame_set_slot(kvp_frame * frame, const char * slot,
kvp_frame_set_slot_destructively(frame, slot, new_value);
}
void
kvp_frame_set_slot_nc(kvp_frame * frame, const char * slot,
kvp_value * value) {
/* FIXME: no way to indicate errors... */
if (!frame)
return;
kvp_frame_set_slot_destructively(frame, slot, value);
}
kvp_value *
kvp_frame_get_slot(kvp_frame * frame, const char * slot) {
if (!frame)
@ -193,6 +205,8 @@ kvp_frame_get_slot(kvp_frame * frame, const char * slot) {
return (kvp_value *)g_hash_table_lookup(frame->hash, slot);
}
/* ============================================================ */
void
kvp_frame_set_slot_path (kvp_frame *frame,
const kvp_value *new_value,
@ -222,10 +236,7 @@ kvp_frame_set_slot_path (kvp_frame *frame,
kvp_frame *new_frame = kvp_frame_new ();
kvp_value *frame_value = kvp_value_new_frame (new_frame);
kvp_frame_set_slot (frame, key, frame_value);
kvp_value_delete (frame_value);
kvp_frame_delete (new_frame);
kvp_frame_set_slot_nc (frame, key, frame_value);
value = kvp_frame_get_slot (frame, key);
if (!value)
@ -267,10 +278,7 @@ kvp_frame_set_slot_path_gslist (kvp_frame *frame,
kvp_frame *new_frame = kvp_frame_new ();
kvp_value *frame_value = kvp_value_new_frame (new_frame);
kvp_frame_set_slot (frame, key, frame_value);
kvp_value_delete (frame_value);
kvp_frame_delete (new_frame);
kvp_frame_set_slot_nc (frame, key, frame_value);
value = kvp_frame_get_slot (frame, key);
if (!value)
@ -283,6 +291,130 @@ kvp_frame_set_slot_path_gslist (kvp_frame *frame,
}
}
/* ============================================================ */
kvp_frame *
kvp_frame_get_frame (kvp_frame *frame, const char *first_key, ...)
{
va_list ap;
const char *key;
if (!frame || !first_key)
return frame;
va_start (ap, first_key);
key = first_key;
while (TRUE) {
kvp_value *value;
/* get the frame assoc with key, or create it if needed */
value = kvp_frame_get_slot (frame, key);
if (!value) {
kvp_frame *new_frame = kvp_frame_new ();
kvp_value *frame_value = kvp_value_new_frame (new_frame);
kvp_frame_set_slot_nc (frame, key, frame_value);
value = kvp_frame_get_slot (frame, key);
if (!value)
break; /* error, should never occur */
}
frame = kvp_value_get_frame (value);
if (!frame)
break; /* error, should never occur */
key = va_arg (ap, const char *);
if (!key) {
break; /* the normal exit to this routine. */
}
}
va_end (ap);
return frame;
}
kvp_frame *
kvp_frame_get_frame_gslist (kvp_frame *frame, GSList *key_path)
{
if (!frame || !key_path)
return frame;
while (TRUE) {
const char *key = key_path->data;
kvp_value *value;
if (!key)
return frame; /* an unusual but valid exit for this routine. */
/* get the named frame, or create it if it doesn't exist */
value = kvp_frame_get_slot (frame, key);
if (!value) {
kvp_frame *new_frame = kvp_frame_new ();
kvp_value *frame_value = kvp_value_new_frame (new_frame);
kvp_frame_set_slot_nc (frame, key, frame_value);
value = kvp_frame_get_slot (frame, key);
if (!value)
return frame; /* this should never happen */
}
frame = kvp_value_get_frame (value);
if (!frame)
return NULL; /* this should never happen */
key_path = key_path->next;
if (!key_path) {
return frame; /* this is the normal exit for this func */
}
}
}
kvp_frame *
kvp_frame_get_frame_slash (kvp_frame *frame, const char *key_path)
{
char *root, *key, *next;
if (!frame || !key_path)
return frame;
root = g_strdup (key_path);
key = root;
key --;
while (key) {
kvp_value *value;
key ++;
while ('/' == *key) { key++; }
if (0x0 == *key) break; /* trailing slash */
next = strchr (key, '/');
if (next) *next = 0x0;
value = kvp_frame_get_slot (frame, key);
if (!value) {
kvp_frame *new_frame = kvp_frame_new ();
kvp_value *frame_value = kvp_value_new_frame (new_frame);
kvp_frame_set_slot_nc (frame, key, frame_value);
value = kvp_frame_get_slot (frame, key);
if (!value) break; /* error - should never happen */
}
frame = kvp_value_get_frame (value);
if (!frame) break; /* error - should never happen */
key = next;
}
g_free(root);
return frame;
}
/* ============================================================ */
kvp_value *
kvp_frame_get_slot_path (kvp_frame *frame,
const char *first_key, ...) {

View File

@ -39,7 +39,8 @@
* owned by the kvp_frame. Make copies as needed.
*
* kvp_frame_delete and kvp_value_delete are deep (recursive) deletes.
* kvp_frame_copy and kvp_value_copy are deep value copies. */
* kvp_frame_copy and kvp_value_copy are deep value copies.
*/
typedef enum {
KVP_TYPE_GINT64,
@ -53,22 +54,31 @@ typedef enum {
} kvp_value_t;
typedef struct _kvp_frame kvp_frame;
#if 0
typedef union _kvp_value kvp_value;
#else
typedef struct _kvp_value kvp_value;
#endif
/* kvp_frame functions */
kvp_frame * kvp_frame_new(void);
void kvp_frame_delete(kvp_frame * frame);
kvp_frame * kvp_frame_copy(const kvp_frame * frame);
/* The kvp_frame_set_slot() routine copies the value into the frame,
* associating it with 'key'.
* The kvp_frame_set_slot_nc() routine puts the value (without copying
* it) into the frame, associating it with 'key'. This routine is
* handy for aviding excess memory allocations & frees.
*/
void kvp_frame_set_slot(kvp_frame * frame,
const char * key, const kvp_value * value);
void kvp_frame_set_slot_nc(kvp_frame * frame,
const char * key, kvp_value * value);
kvp_value * kvp_frame_get_slot(kvp_frame * frame,
const char * key);
/* The kvp_frame_set_slot_path() routines walk the heirarchy,
* using the key falues to pick each branch. When the terminal node
* is reached, the value is copied into it.
*/
void kvp_frame_set_slot_path (kvp_frame *frame,
const kvp_value *value,
const char *first_key, ...);
@ -77,6 +87,30 @@ void kvp_frame_set_slot_path_gslist (kvp_frame *frame,
const kvp_value *value,
GSList *key_path);
/* The following routines return the last frame of the path.
* If the frame path doesn't exist, it is created.
*
* The kvp_frame_get_frame_slash() routine takes a single string
* where the keys are separated by slashes; thus, for example:
* /this/is/a/valid/path and///so//is////this/
* Multiple slashes are compresed. leading slash is optional.
* The pointers . and .. are *not* followed/obeyed. (This is
* arguably a bug that needs fixing).
*
*
*/
kvp_frame * kvp_frame_get_frame (kvp_frame *frame,
const char *first_key, ...);
kvp_frame * kvp_frame_get_frame_gslist (kvp_frame *frame,
GSList *key_path);
kvp_frame * kvp_frame_get_frame_slash (kvp_frame *frame,
const char *path);
/* The following routines return the value att the end of the
* path, or NULL if any portion of the path doesn't exist.
*/
kvp_value * kvp_frame_get_slot_path (kvp_frame *frame,
const char *first_key, ...);