merge cahnges from the cap-gains5 development branch,

consisting primarily of enhance KVP functionality, including
better support for lists of values, and the implementation
of a 'bag' for holding collection of (un-named) data.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@9317 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 2003-09-14 18:47:51 +00:00
parent c4f465d164
commit ef6b5dad26
12 changed files with 1044 additions and 520 deletions

View File

@ -233,44 +233,21 @@ xaccCloneAccount (const Account *from, QofBook *book)
Account *
xaccAccountLookupTwin (Account *acc, QofBook *book)
{
KvpValue *v_ncopies;
int i, ncopies = 0;
KvpFrame *fr;
GUID * twin_guid;
Account * twin;
if (!acc || !book) return NULL;
ENTER (" ");
v_ncopies = kvp_frame_get_slot_path (acc->kvp_data, "gemini", "ncopies", NULL);
if (!v_ncopies) return NULL;
ncopies = kvp_value_get_gint64 (v_ncopies);
for (i=0; i<ncopies; i++)
{
GUID * book_guid;
KvpValue *v_book_guid;
char buff[80];
fr = gnc_kvp_bag_find_by_guid (acc->kvp_data, "gemini",
"book_guid", &book->guid);
sprintf (buff, "%d", i);
v_book_guid = kvp_frame_get_slot_path (acc->kvp_data,
"gemini", buff, "book_guid", NULL);
if (!v_book_guid) continue;
book_guid = kvp_value_get_guid (v_book_guid);
twin_guid = kvp_frame_get_guid (fr, "acct_guid");
twin = xaccAccountLookup (twin_guid, book);
if (guid_equal(book_guid, &book->guid))
{
Account *twin;
GUID * acct_guid;
KvpValue *v_acct_guid;
v_acct_guid = kvp_frame_get_slot_path (acc->kvp_data,
"gemini", buff, "acct_guid", NULL);
if (!v_acct_guid) return NULL;
acct_guid = kvp_value_get_guid (v_acct_guid);
twin = xaccAccountLookup (acct_guid, book);
return twin;
}
}
LEAVE (" ");
return NULL;
LEAVE (" found twin=%p", twin);
return twin;
}
/********************************************************************\
@ -2190,17 +2167,10 @@ xaccAccountGetTaxUSCode (Account *account)
void
xaccAccountSetTaxUSCode (Account *account, const char *code)
{
KvpFrame *frame;
if (!account)
return;
if (!account) return;
xaccAccountBeginEdit (account);
frame = kvp_frame_get_frame (account->kvp_data, "tax-US", NULL);
kvp_frame_set_slot_nc (frame, "code",
code ? kvp_value_new_string (code) : NULL);
kvp_frame_set_str (account->kvp_data, "/tax-US/code", code);
mark_account (account);
account->core_dirty = TRUE;
@ -2210,33 +2180,17 @@ xaccAccountSetTaxUSCode (Account *account, const char *code)
const char *
xaccAccountGetTaxUSPayerNameSource (Account *account)
{
KvpValue *value;
if (!account)
return FALSE;
value = kvp_frame_get_slot_path (account->kvp_data,
"tax-US", "payer-name-source", NULL);
if (!value)
return NULL;
return kvp_value_get_string (value);
if (!account) return NULL;
return kvp_frame_get_string (account->kvp_data, "/tax-US/payer-name-source");
}
void
xaccAccountSetTaxUSPayerNameSource (Account *account, const char *source)
{
KvpFrame *frame;
if (!account)
return;
if (!account) return;
xaccAccountBeginEdit (account);
frame = kvp_frame_get_frame (account->kvp_data, "tax-US", NULL);
kvp_frame_set_slot_nc (frame, "payer-name-source",
source ? kvp_value_new_string (source) : NULL);
kvp_frame_set_str (account->kvp_data, "/tax-US/payer-name-source", source);
mark_account (account);
account->core_dirty = TRUE;
@ -2539,14 +2493,11 @@ xaccAccountGetReconcileLastDate (Account *account, time_t *last_date)
void
xaccAccountSetReconcileLastDate (Account *account, time_t last_date)
{
KvpFrame *frame;
if (!account)
return;
if (!account) return;
xaccAccountBeginEdit (account);
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_gint64 (account->kvp_data,
"/reconcile-info/last-date", last_date);
mark_account (account);
account->core_dirty = TRUE;
@ -2586,16 +2537,15 @@ void
xaccAccountSetReconcileLastInterval (Account *account, int months, int days)
{
KvpFrame *frame;
if (!account)
return;
if (!account) return;
xaccAccountBeginEdit (account);
frame = kvp_frame_get_frame (account->kvp_data, "reconcile-info",
"last-interval", NULL);
kvp_frame_set_slot_nc (frame, "months",
kvp_value_new_gint64 (months));
kvp_frame_set_slot_nc (frame, "days",
kvp_value_new_gint64 (days));
frame = kvp_frame_get_frame (account->kvp_data,
"/reconcile-info/last-interval");
kvp_frame_set_gint64 (frame, "months", months);
kvp_frame_set_gint64 (frame, "days", days);
mark_account (account);
account->core_dirty = TRUE;
@ -2637,16 +2587,13 @@ void
xaccAccountSetReconcilePostponeDate (Account *account,
time_t postpone_date)
{
KvpFrame *frame;
if (!account)
return;
if (!account) return;
xaccAccountBeginEdit (account);
frame = kvp_frame_get_frame (account->kvp_data,
"reconcile-info", "postpone", NULL);
kvp_frame_set_slot_nc (frame, "date",
kvp_value_new_gint64 (postpone_date));
/* XXX this should be using timespecs, not gints !! */
kvp_frame_set_gint64 (account->kvp_data,
"/reconcile-info/postpone/date", postpone_date);
mark_account (account);
account->core_dirty = TRUE;
@ -2689,16 +2636,11 @@ void
xaccAccountSetReconcilePostponeBalance (Account *account,
gnc_numeric balance)
{
KvpFrame *frame;
if (!account)
return;
if (!account) return;
xaccAccountBeginEdit (account);
frame = kvp_frame_get_frame (account->kvp_data,
"reconcile-info", "postpone", NULL);
kvp_frame_set_slot_nc (frame, "balance",
kvp_value_new_gnc_numeric (balance));
kvp_frame_set_gnc_numeric (account->kvp_data,
"/reconcile-info/postpone/balance", balance);
mark_account (account);
account->core_dirty = TRUE;
@ -2763,18 +2705,15 @@ xaccAccountGetAutoInterestXfer (Account *account, gboolean default_value)
void
xaccAccountSetAutoInterestXfer (Account *account, gboolean option)
{
KvpFrame *frame;
if (!account)
return;
xaccAccountBeginEdit (account);
frame = kvp_frame_get_frame (account->kvp_data,
"reconcile-info", NULL);
/* FIXME: need KVP_TYPE_BOOLEAN for this someday */
kvp_frame_set_slot_nc (frame, "auto-interest-transfer",
kvp_value_new_string (option ? "true" : "false"));
kvp_frame_set_str (account->kvp_data,
"/reconcile-info/auto-interest-transfer",
(option ? "true" : "false"));
mark_account (account);
account->core_dirty = TRUE;
@ -2904,19 +2843,16 @@ dxaccAccountGetQuoteTZ(Account *acc)
void
xaccAccountSetReconcileChildrenStatus(Account *account, gboolean status)
{
KvpFrame *frame;
if (!account)
return;
if (!account) return;
xaccAccountBeginEdit (account);
frame = kvp_frame_get_frame (account->kvp_data, "reconcile-info", NULL);
kvp_frame_set_slot_nc (frame,
"include-children",
status ? kvp_value_new_gint64 (status) : NULL);
/* XXX FIXME: someday this should use KVP_TYPE_BOOLEAN */
kvp_frame_set_gint64 (account->kvp_data,
"/reconcile-info/include-children", status);
account->core_dirty = TRUE;
xaccAccountCommitEdit (account);
return;
}
/********************************************************************\

View File

@ -598,7 +598,7 @@ find_nearest_equity_acct (Account *acc)
AccountGroup *parent;
Account *next_up, *candidate;
/* see if we can find an equity account that is peered to this account */
/* See if we can find an equity account that is peered to this account */
parent = xaccAccountGetParent (acc);
g_return_val_if_fail (parent, NULL);

View File

@ -38,6 +38,8 @@
#include "gnc-numeric.h"
#include "gnc-trace.h"
#include "kvp_frame.h"
#include "kvp-util-p.h"
#include "Account.h"
#include "Scrub3.h"
#include "Transaction.h"
#include "TransactionP.h"
@ -125,48 +127,118 @@ xaccScrubSubSplitPrice (Split *split)
/* ================================================================= */
#if LATER
/* Remove the guid of b from a */
static void
remove_guids (Split *sa, Split *sb)
{
KvpFrame *ksub;
/* Find and remove the matching guid's */
ksub = gnc_kvp_bag_find_by_guid (sa->kvp_data, "lot-split",
"peer_guid", &sb->guid);
if (!ksub)
{
PERR ("merging splits that didn't have correct gemini values!");
return;
}
gnc_kvp_bag_remove_frame (sa->kvp_data, "lot-split", ksub);
kvp_frame_delete (ksub);
}
/* The 'merge_splits() routine causes the amount & value of sb
* to be merged into sa; it then destroys sb. It also performs
* some other misc cleanup */
static void
merge_splits (Split *sa, Split *sb)
{
Account *act;
Transaction *txn;
gnc_numeric amt, val;
act = xaccSplitGetAccount (sb);
xaccAccountBeginEdit (act);
txn = sa->parent;
xaccTransBeginEdit (txn);
/* whack kvp of b, remove gem kvp of a */
/* whack memo etc. b */
/* set reconsile to no */
/* add amounts, values */
/* Remove the guid of sb from the 'gemini' of sa */
remove_guids (sa, sb);
/* Add amount of sb into sa, ditto for value. */
amt = xaccSplitGetAmount (sa);
amt = gnc_numeric_add_fixed (amt, xaccSplitGetAmount (sb));
xaccSplitSetAmount (sa, amt);
val = xaccSplitGetValue (sa);
val = gnc_numeric_add_fixed (val, xaccSplitGetValue (sb));
xaccSplitSetValue (sa, val);
/* Set reconcile to no; after this much violence,
* no way its reconciled. */
xaccSplitSetReconcile (sa, NREC);
/* Finally, delete sb */
xaccSplitDestroy(sb);
xaccTransCommitEdit (txn);
xaccAccountCommitEdit (act);
}
void
gboolean
xaccScrubMergeSubSplits (Split *split)
{
gboolean rc = FALSE;
Transaction *txn;
KvpFrame *sf;
SplitList *node;
GNCLot *lot;
sf = is_subsplit (split);
if (!sf) return;
if (!sf) return FALSE;
txn = split->parent;
lot = xaccSplitGetLot (split);
ENTER (" ");
for (node=split->parent->splits; node; node=node->next)
restart:
for (node=txn->splits; node; node=node->next)
{
Split *s = node->data;
if (xaccSplitGetLot (s) != lot) continue;
/* OK, this split is in the same lot (and thus same account)
* as the indicated split. It must be a subsplit. Merge the
* as the indicated split. It must be a subsplit (although
* we should double-check the kvp's to be sure). Merge the
* two back together again. */
merge_splits (split, s);
rc = TRUE;
goto restart;
}
LEAVE (" ");
LEAVE (" splits merged=%d", rc);
return rc;
}
gboolean
xaccScrubMergeTxnSubSplits (Transaction *txn)
{
gboolean rc = FALSE;
SplitList *node;
if (!txn) return FALSE;
ENTER (" ");
restart:
for (node=txn->splits; node; node=node->next)
{
Split *s = node->data;
if (!xaccScrubMergeSubSplits(s)) continue;
rc = TRUE;
goto restart;
}
LEAVE (" splits merged=%d", rc);
return rc;
}
#endif
/* ========================== END OF FILE ========================= */

View File

@ -50,5 +50,23 @@
*/
void xaccScrubSubSplitPrice (Split *split);
/** The xaccScrubMergeSubSplits() routine will merge together
* all of the splits that were at one time split off from this
* split, but are no longer needed to be kept separate. Splits
* migt be split up if they need to be divided over multiple
* lots; they can be merged back together if the lots change.
* In particular, two sub-splits may be merged if they are in
* the same lot, or in no lot. Note that, by definition, all
* subsplits belong to the same transaction.
*
* The routine returns TRUE if a merger was performed, else
* it returns FALSE.
*
* The xaccScrubMergeTxnSubSplits() routine does the same, except
* that it does it for all of the splits in the transaction.
*/
gboolean xaccScrubMergeSubSplits (Split *split);
gboolean xaccScrubMergeTxnSubSplits (Transaction *txn);
#endif /* XACC_SCRUB3_H */
/** @} */

View File

@ -2696,17 +2696,20 @@ xaccTransGetNotes (const Transaction *trans)
/********************************************************************\
\********************************************************************/
/* The posted date is kept in sync using a lazy-evaluation scheme.
* If xaccTransactionSetDatePosted() is called, the date change is
* accepted, and the split is marked date-dirty. If the posted date
* is queried for (using GetDatePosted()), then the transaction is
* evaluated. If its a gains-transaction, then it's date is copied
* from the source transaction that created the gains.
/** The xaccScrubGainsDate() routine is used to keep the posted date
* of gains splis in sync with the posted date of the transaction
* that caused the gains.
*
* The posted date is kept in sync using a lazy-evaluation scheme.
* If xaccTransactionSetDatePosted() is called, the date change is
* accepted, and the split is marked date-dirty. If the posted date
* is queried for (using GetDatePosted()), then the transaction is
* evaluated. If its a gains-transaction, then it's date is copied
* from the source transaction that created the gains.
*/
static inline void
handle_gains_date (Transaction *trans)
xaccScrubGainsDate (Transaction *trans)
{
SplitList *node;
Timespec ts = {0,0};
@ -2750,7 +2753,7 @@ time_t
xaccTransGetDate (const Transaction *trans)
{
if (!trans) return 0;
handle_gains_date((Transaction *) trans); /* XXX wrong not const ! */
xaccScrubGainsDate((Transaction *) trans); /* XXX wrong not const ! */
return (trans->date_posted.tv_sec);
}
@ -2758,7 +2761,7 @@ void
xaccTransGetDatePostedTS (const Transaction *trans, Timespec *ts)
{
if (!trans || !ts) return;
handle_gains_date((Transaction *) trans); /* XXX wrong not const ! */
xaccScrubGainsDate((Transaction *) trans); /* XXX wrong not const ! */
*ts = (trans->date_posted);
}
@ -2774,7 +2777,7 @@ xaccTransRetDatePostedTS (const Transaction *trans)
{
Timespec ts = {0, 0};
if (!trans) return ts;
handle_gains_date((Transaction *) trans); /* XXX wrong not const ! */
xaccScrubGainsDate((Transaction *) trans); /* XXX wrong not const ! */
return (trans->date_posted);
}

View File

@ -407,13 +407,13 @@ xaccSplitAssignToLot (Split *split,
/* Add kvp markup to indicate that these two splits used
* to be one before being 'split'
*/
gnc_kvp_array (split->kvp_data, "/lot-split", now,
"peer_guid", xaccSplitGetGUID (new_split),
NULL);
gnc_kvp_bag_add (split->kvp_data, "lot-split", now,
"peer_guid", xaccSplitGetGUID (new_split),
NULL);
gnc_kvp_array (new_split->kvp_data, "/lot-split", now,
"peer_guid", xaccSplitGetGUID (split),
NULL);
gnc_kvp_bag_add (new_split->kvp_data, "lot-split", now,
"peer_guid", xaccSplitGetGUID (split),
NULL);
xaccSplitSetAmount (new_split, amt_b);
xaccSplitSetValue (new_split, val_b);

View File

@ -81,6 +81,7 @@ gnc_log_init (void)
{
fout = stderr;
fout = stdout;
fout = fopen ("/tmp/gnucash.trace", "w");
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, fh_printer, fout);
}

View File

@ -36,8 +36,9 @@
* outside of the engine.
*/
/** The gnc_kvp_array() routine is used to maintain a list of pointers
* in a kvp tree.
/** The gnc_kvp_bag_add() routine is used to maintain a collection
* of pointers in a kvp tree.
*
* The thing being pointed at is uniquely identified by its GUID.
* This routine is typically used to create a linked list, and/or
* a collection of pointers to objects that are 'related' to each
@ -47,22 +48,53 @@
* the corresponding GUID pointer (const GUID *). Terminate the varargs
* with a NULL as the last string argument.
*
* The actual 'pointer' is stored in an array in a subdirectory
* of the directory 'path'.
* The size of the array is in /ncopies. The pointer is stored in
* /<n>/<name> where <n> = ncopies -1, <name> was passed as an argument.
* In addition, the date is logged. Thus, for example:
* The actual 'pointer' is stored in a subdirectory in a bag located at
* the node directory 'path'. A 'bag' is merely a collection of
* (unamed) values. The name of our bag is 'path'. A bag can contain
* any kind of values, including frames. This routine will create a
* frame, and put it in the bag. The frame will contain named data
* from the subroutine arguments. Thus, for example:
*
* gnc_kvp_array (kvp, "foo", secs, "acct_guid", aguid,
* "book_guid", bguid, NULL);
* will increment /foo/ncopies, and will store aguid in
* /foo/<n>/acct_guid and bguid in /foo/<n>/book_guid, where <n> = ncopies-1
*
* will create a frame containing "/acct_guid" and "/book_guid", whose
* values are aguid and bguid respecitvely. The frame will also
* contain "/date", whose value will be secs. This frame will be
* placed into the bag located at "foo".
*
* This routine returns a pointer to the frame that was created, or
* NULL if an error occured.
*/
void gnc_kvp_array (KvpFrame *kvp_root, const char *path, time_t secs,
KvpFrame * gnc_kvp_bag_add (KvpFrame *kvp_root, const char *path, time_t secs,
const char *first_name, ...);
/* Equivalent to gnc_kvp_array(kvp_root, "gemini", secs, firstname, ...); */
/* Equivalent to gnc_kvp_bag_add(kvp_root, "gemini", secs, firstname, ...); */
void gnc_kvp_gemini (KvpFrame *kvp_root, time_t secs,
const char *first_name, ...);
/** The gnc_kvp_bag_find_by_guid() routine examines the bag pointed
* located at root. It looks for a frame in that bag that has the
* guid value of "desired_guid" filed under the key name "guid_name".
* If it finds that matching guid, then it returns a pointer to
* the KVP frame that contains it. If it is not found, or if there
* is any other error, NULL is returned.
*/
KvpFrame * gnc_kvp_bag_find_by_guid (KvpFrame *root, const char * path,
const char *guid_name, GUID *desired_guid);
/** Remove the given frame from the bag. The frame is removed,
* however, it is not deleted. Note that the frame pointer must
* be a pointer to the actual frame (for example, as returned by
* gnc_kvp_bag_find_by_guid() for by gnc_kvp_bag_add()), and not
* some copy of the frame.
*/
void gnc_kvp_bag_remove_frame (KvpFrame *root, const char *path,
KvpFrame *fr);
#endif /* XACC_KVP_UTIL_P_H */

View File

@ -33,46 +33,19 @@
/* ================================================================ */
static void
static KvpFrame *
gnc_kvp_array_va (KvpFrame *kvp_root, const char * path,
time_t secs, const char * first_name, va_list ap)
{
char buff[80];
KvpFrame *cwd, *pwd;
KvpValue *v_ncopies;
gint64 ncopies = 0;
KvpFrame *cwd;
Timespec ts;
const char *name;
if (!kvp_root) return;
if (!first_name) return;
if (!kvp_root) return NULL;
if (!first_name) return NULL;
if (!path)
{
pwd = kvp_root;
}
else
{
pwd = kvp_frame_get_frame_slash (kvp_root, path);
if (!pwd) return; /* error: can't ever happen */
}
/* Find, increment, store number of copies */
v_ncopies = kvp_frame_get_slot (pwd, "ncopies");
if (v_ncopies)
{
ncopies = kvp_value_get_gint64 (v_ncopies);
}
ncopies ++;
kvp_frame_set_gint64 (pwd, "ncopies", ncopies);
/* OK, now create subdirectory and put the actual data */
--ncopies;
sprintf (buff, GNC_SCANF_LLD, (long long int) ncopies);
/* Create subdirectory and put the actual data */
cwd = kvp_frame_new();
kvp_frame_set_slot_nc(pwd, buff, kvp_value_new_frame_nc(cwd));
/* Record the time */
ts.tv_sec = secs;
@ -81,7 +54,6 @@ gnc_kvp_array_va (KvpFrame *kvp_root, const char * path,
/* Loop over the args */
name = first_name;
while (name)
{
const GUID *guid;
@ -91,18 +63,24 @@ gnc_kvp_array_va (KvpFrame *kvp_root, const char * path,
name = va_arg (ap, const char *);
}
/* Attach cwd into the array */
kvp_frame_add_frame_nc (kvp_root, path, cwd);
return cwd;
}
/* ================================================================ */
void
gnc_kvp_array (KvpFrame *pwd, const char * path,
time_t secs, const char *first_name, ...)
KvpFrame *
gnc_kvp_bag_add (KvpFrame *pwd, const char * path,
time_t secs, const char *first_name, ...)
{
KvpFrame *cwd;
va_list ap;
va_start (ap, first_name);
gnc_kvp_array_va (pwd, path, secs, first_name, ap);
cwd = gnc_kvp_array_va (pwd, path, secs, first_name, ap);
va_end (ap);
return cwd;
}
/* ================================================================ */
@ -116,6 +94,78 @@ gnc_kvp_gemini (KvpFrame *kvp_root, time_t secs, const char *first_name, ...)
va_end (ap);
}
/* ================================================================ */
#define MATCH_GUID(elt) { \
KvpFrame *fr = kvp_value_get_frame (elt); \
if (fr) { \
GUID *guid = kvp_frame_get_guid (fr, guid_name); \
if (guid && guid_equal (desired_guid, guid)) return fr; \
} \
}
KvpFrame *
gnc_kvp_bag_find_by_guid (KvpFrame *root, const char * path,
const char *guid_name, GUID *desired_guid)
{
KvpValue *arr;
KvpValueType valtype;
GList *node;
arr = kvp_frame_get_value (root, path);
valtype = kvp_value_get_type (arr);
if (KVP_TYPE_FRAME == valtype)
{
MATCH_GUID (arr);
return NULL;
}
/* Its gotta be a single isolated frame, or a list of them. */
if (KVP_TYPE_GLIST != valtype) return NULL;
for (node = kvp_value_get_glist(arr); node; node=node->next)
{
KvpValue *va = node->data;
MATCH_GUID (va);
}
return NULL;
}
/* ================================================================ */
#define KILL_MATCH(elt) \
if (fr == kvp_value_get_frame (elt)) { \
KvpValue *old_val = kvp_frame_replace_value_nc (root, path, NULL); \
kvp_value_replace_frame_nc (old_val, NULL); \
kvp_value_delete (old_val); \
return; \
}
void
gnc_kvp_bag_remove_frame (KvpFrame *root, const char *path, KvpFrame *fr)
{
KvpValue *arr;
KvpValueType valtype;
GList *node;
arr = kvp_frame_get_value (root, path);
valtype = kvp_value_get_type (arr);
if (KVP_TYPE_FRAME == valtype)
{
KILL_MATCH (arr);
return;
}
/* Its gotta be a single isolated frame, or a list of them. */
if (KVP_TYPE_GLIST != valtype) return;
for (node = kvp_value_get_glist(arr); node; node=node->next)
{
KvpValue *va = node->data;
KILL_MATCH (va);
}
}
/* ================================================================ */
/*
* See header for docs.

View File

@ -159,36 +159,30 @@ Use: GUID of the split that records the capital gains for this split.
-----------------------
Name: /gemini/
Type: kvp_frame
Type: kvp_glist
Entities: Account, Book
Use: kvp subdirectory holding identification of accounts or books
Use: kvp bag holding frames that identify accounts or books
that are copies of this account.
Name: /gemini/ncopies
Type: int64
Entities: Account, Book
Use: number of subdirectories containing copy info.
Name: /gemini/0/
Name: /gemini/*
Type: kvp_frame
Entities: Account, Book
Use: subdirectory holding identification of the first copied account.
Other copies would appear in directories /gemini/1/, /gemini/2/,
etc.
Use: bag value holds a frame that identifies a single copied account.
Other copies would appear in other bag values.
Name: /gemini/0/acct_guid
Name: /gemini/*/acct_guid
Type: guid
Entities: Account
Use: guid of another account that is a copy of this one.
Name: /gemini/0/book_guid
Name: /gemini/*/book_guid
Type: guid
Entities: Account, Book
Use: When this appears in an account, then it contains the guid of
the book that the other account belongs to. When this appears
in a book, then this is the guid of the other book.
Name: /gemini/0/date
Name: /gemini/*/date
Type: timespec
Entities: Account, Book
Use: date that the copy was created.
@ -268,13 +262,13 @@ Use: The next unused lot id number, used to autogenerate
Name: /lot-split/
Type: kvp_frame
Type: kvp_glist
Entities: Split
Use: A gemini-style kvp subdirectory holding identification of splits
that were split off of this split. See /gemini/ for additional
doco's.
Use: A bag of kvp frames holding identification of splits
that were split off of this split. Same style as the
/gemini/, look there for additional doco's.
Name: /lot-split/0/peer_guid
Name: /lot-split/*/peer_guid
Type: GUID
Entities: Split
Use: The GUID of the peer split which was split from this split.

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
/********************************************************************\
* kvp_frame.h -- Implements a key-value frame system *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
@ -20,7 +21,7 @@
/** @addtogroup Engine
@{ */
/** @file kvp_frame.h
@brief A key-value frame system for gnucash
@brief A key-value frame system
@author Copyright (C) 2000 Bill Gribble
@author Copyright (C) 2003 Linas Vepstas <linas@linas.org>
*/
@ -70,7 +71,10 @@ typedef struct _KvpFrame KvpFrame;
* KvpValueType enum. */
typedef struct _KvpValue KvpValue;
/** Enum to enumerate possible types in the union KvpValue */
/** Enum to enumerate possible types in the union KvpValue
* XXX FIXME TODO: People have asked for boolean values,
* e.g. in xaccAccountSetAutoInterestXfer
*/
typedef enum {
KVP_TYPE_GINT64,
KVP_TYPE_DOUBLE,
@ -114,19 +118,83 @@ gboolean kvp_frame_is_empty(KvpFrame * frame);
/*@}*/
/* -------------------------------------------------------- */
/** @name KvpFrame Value Storing */
/** @name KvpFrame Basic Value Storing */
/*@{*/
/** The kvp_frame_set_str() routine will store a string at the indicated path.
* If not all frame components of the path exist, they are created.
* */
/** The kvp_frame_set_gint64() routine will store the value of the
* gint64 at the indicated path. If not all frame components of
* the path exist, they are created.
*
* Similarly, the set_double, set_numeric, and set_timespec
* routines perform the same function, for each of the respective
* types.
*/
void kvp_frame_set_gint64(KvpFrame * frame, const char * path, gint64 ival);
void kvp_frame_set_double(KvpFrame * frame, const char * path, double dval);
void kvp_frame_set_gnc_numeric(KvpFrame * frame, const char * path, gnc_numeric nval);
void kvp_frame_set_str(KvpFrame * frame, const char * path, const char* str);
void kvp_frame_set_guid(KvpFrame * frame, const char * path, const GUID *guid);
void kvp_frame_set_timespec(KvpFrame * frame, const char * path, Timespec ts);
/** The kvp_frame_set_str() routine will store a copy of the string
* at the indicated path. If not all frame components of the path
* exist, they are created. If there was another string previously
* stored at that path, the old copy is deleted.
*
* Similarly, the set_guid and set_frame will make copies and
* store those. Old copies, if any, are deleted.
*
* The kvp_frame_set_frame_nc() routine works as above, but does
* *NOT* copy the frame.
*/
void kvp_frame_set_str(KvpFrame * frame, const char * path, const char* str);
void kvp_frame_set_guid(KvpFrame * frame, const char * path, const GUID *guid);
void kvp_frame_set_frame(KvpFrame *frame, const char *path, KvpFrame *chld);
void kvp_frame_set_frame_nc(KvpFrame *frame, const char *path, KvpFrame *chld);
/** The kvp_frame_set_value() routine copies the value into the frame,
* at the location 'path'. If the path contains slashes '/', these
* are assumed to represent a sequence of keys. The returned value
* is a pointer to the actual frame into which the value was inserted;
* it is NULL if the frame couldn't be found (and thus the value wasn't
* inserted). The old value at this location, if any, is destroyed.
*
* Pointers passed as arguments into this routine are the responsibility
* of the caller; the pointers are *not* taken over or managed.
*/
KvpFrame * kvp_frame_set_value(KvpFrame * frame,
const char * path, const KvpValue * value);
/**
* The kvp_frame_set_value_nc() routine puts the value (without copying
* it) into the frame, putting it at the location 'path'. If the path
* contains slashes '/', these are assumed to represent a sequence of keys.
* The returned value is a pointer to the actual frame into which the value
* was inserted; it is NULL if the frame couldn't be found (and thus the
* value wasn't inserted). The old value at this location, if any,
* is destroyed.
*
* This routine is handy for avoiding excess memory allocations & frees.
* Note that because the KvpValue was grabbed, you can't just delete
* unless you remove the key as well (or unless you replace the value).
*/
KvpFrame * kvp_frame_set_value_nc(KvpFrame * frame,
const char * path, KvpValue * value);
/** The kvp_frame_replace_value_nc() routine places the new value
* at the indicated path. It returns the old value, if any.
* It returns NULL if there was an error, or if there was no
* old value. If the path doesn't exist, it is created, unless
* new_value is NULL. Passing in a NULL new_value has the
* effect of deleting the trailing slot (i.e. the trailing path
* element).
*/
KvpValue * kvp_frame_replace_value_nc (KvpFrame * frame, const char * slot,
KvpValue * new_value);
/*@}*/
/** @name KvpFrame URL handling */
/*@{*/
/** The kvp_frame_add_url_encoding() routine will parse the
* value string, assuming it to be URL-encoded in the standard way,
* turning it into a set of key-value pairs, and adding those to the
@ -142,6 +210,62 @@ void kvp_frame_set_timespec(KvpFrame * frame, const char * path, Timespec ts);
void kvp_frame_add_url_encoding (KvpFrame *frame, const char *enc);
/*@}*/
/** @name KvpFrame Glist Bag Storing */
/*@{*/
/** The kvp_frame_add_gint64() routine will add the value of the
* gint64 to the glist bag of values at the indicated path.
* If not all frame components of the path exist, they are
* created. If the value previously stored at this path was
* not a glist bag, then a bag will be formed there, the old
* value placed in the bag, and the new value added to the bag.
*
* Similarly, the add_double, add_numeric, and add_timespec
* routines perform the same function, for each of the respective
* types.
*/
void kvp_frame_add_gint64(KvpFrame * frame, const char * path, gint64 ival);
void kvp_frame_add_double(KvpFrame * frame, const char * path, double dval);
void kvp_frame_add_gnc_numeric(KvpFrame * frame, const char * path, gnc_numeric nval);
void kvp_frame_add_timespec(KvpFrame * frame, const char * path, Timespec ts);
/** The kvp_frame_add_str() routine will add a copy of the string
* to the glist bag at the indicated path. If not all frame components
* of the path exist, they are created. If there was another
* item previously stored at that path, then the path is converted
* to a bag, and the old value, along with the new value, is added
* to the bag.
*
* Similarly, the add_guid and add_frame will make copies and
* add those.
*
* The kvp_frame_add_frame_nc() routine works as above, but does
* *NOT* copy the frame.
*/
void kvp_frame_add_str(KvpFrame * frame, const char * path, const char* str);
void kvp_frame_add_guid(KvpFrame * frame, const char * path, const GUID *guid);
void kvp_frame_add_frame(KvpFrame *frame, const char *path, KvpFrame *chld);
void kvp_frame_add_frame_nc(KvpFrame *frame, const char *path, KvpFrame *chld);
/* The kvp_frame_add_value() routine will add a copy of the value
* to the glist bag at the indicated path. If not all frame components
* of the path exist, they are created. If there was another
* item previously stored at that path, then the path is converted
* to a bag, and the old value, along with the new value, is added
* to the bag. This routine returns the pointer to the last frame
* (the actual frame to which the value was added), or NULL if there
* was an error of any sort (typically, a parse error in the path).
*
* The *_nc() routine is analogous, except that it doesn't copy the
* value.
*/
KvpFrame * kvp_frame_add_value(KvpFrame * frame, const char * path, KvpValue *value);
KvpFrame * kvp_frame_add_value_nc(KvpFrame * frame, const char * path, KvpValue *value);
/*@}*/
/* -------------------------------------------------------- */
/** @name KvpFrame Value Fetching */
/*@{*/
@ -152,12 +276,24 @@ void kvp_frame_add_url_encoding (KvpFrame *frame, const char *enc);
asked for, then a NULL or a zero is returned. So, for example,
asking for a string when the path stored an int will return a NULL.
In some future date, this may be changed to a looser type system,
such as perl's automatic re-typing.
such as perl's automatic re-typing (e.g. an integer value might be
converted to a printed string representing that value).
If any part of the path does not exist, then NULL or zero will be
returned.
The values returned for GUID, binary, GList, KvpFrame and string
are "non-copying" -- the returned item is the actual item stored.
Do not delete this item unless you take the required care to avoid
possible bad pointer derefrences (i.e. core dumps).
possible bad pointer derefrences (i.e. core dumps). Also, be
careful anging on to those references if you are also storing
at the same path names: the referenced item will be freed during
the store.
That is, if you get a string value (or guid, binary or frame),
and then store something else at that path, the string that you've
gotten will be freed during the store (internally, by the set_*()
routines), and you will be left hanging onto an invalid pointer.
*/
gint64 kvp_frame_get_gint64(const KvpFrame *frame, const char *path);
@ -168,20 +304,25 @@ GUID * kvp_frame_get_guid(const KvpFrame *frame, const char *path);
void * kvp_frame_get_binary(const KvpFrame *frame, const char *path,
guint64 * size_return);
Timespec kvp_frame_get_timespec(const KvpFrame *frame, const char *path);
KvpValue * kvp_frame_get_value(const KvpFrame *frame, const char *path);
KvpFrame * kvp_frame_get_frame(const KvpFrame *frame, const char *path);
/** This routine returns the last frame of the path.
* If the frame path doesn't exist, it is created.
* Note that this is *VERY DIFFERENT FROM* like kvp_frame_get_frame()
*/
KvpFrame * kvp_frame_get_frame (KvpFrame *frame, const char *,...);
KvpFrame * kvp_frame_get_frame_path (KvpFrame *frame, const char *,...);
/** This routine return the last frame of the path.
* If the frame path doesn't exist, it is created.
* Note that this is *VERY DIFFERENT FROM* like kvp_frame_get_frame()
*/
KvpFrame * kvp_frame_get_frame_gslist (KvpFrame *frame,
GSList *key_path);
/** This routine return the last frame of the path.
* If the frame path doesn't exist, it is created.
* Note that this is *VERY DIFFERENT FROM* like kvp_frame_get_frame()
*
* The kvp_frame_get_frame_slash() routine takes a single string
* where the keys are separated by slashes; thus, for example:
@ -200,37 +341,31 @@ KvpFrame * kvp_frame_get_frame_slash (KvpFrame *frame,
/** You probably shouldn't be using these low-level routines */
/** The kvp_frame_set_slot_slash() routine copies the value into the frame,
* at the location 'path'. If the path contains slashes '/', these
* are assumed to represent a sequence of keys. The returned value
* is a pointer to the actual frame into which the value was inserted;
* it is NULL if the frame couldn't be found (and thus the value wasn't
* inserted).
/** All of the kvp_frame_set_slot_*() routines set the slot values
* "destructively", in that if there was an old value there, that
* old value is destroyed (and the memory freed). Thus, one
* should not hang on to value pointers, as these will get
* trashed if set_slot is called on the corresponding key.
*
* Pointers passed as arguments into this routine are the responsibility
* of the caller; the pointers are *not* taken over or managed.
* If you want the old value, use kvp_frame_replace_slot().
*/
KvpFrame * kvp_frame_set_slot_slash(KvpFrame * frame,
const char * path, const KvpValue * value);
/**
* The kvp_frame_set_slot_slash_nc() routine puts the value (without copying
* it) into the frame, putting it at the location 'path'. If the path
* contains slashes '/', these are assumed to represent a sequence of keys.
* The returned value is a pointer to the actual frame into which the value
* was inserted; it is NULL if the frame couldn't be found (and thus the
* value wasn't inserted).
*
* This routine is handy for avoiding excess memory allocations & frees.
* Note that because the KvpValue was grabbed, you can't just delete
* unless you remove the key as well (or unless you replace the value).
/** The kvp_frame_replace_slot_nc() routine places the new value into
* the indicated frame, for the given key. It returns the old
* value, if any. It returns NULL if the slot doesn't exist,
* if there was some other an error, or if there was no old value.
* Passing in a NULL new_value has the effect of deleting that
* slot.
*/
KvpFrame * kvp_frame_set_slot_slash_nc(KvpFrame * frame,
const char * path, KvpValue * value);
KvpValue * kvp_frame_replace_slot_nc (KvpFrame * frame, const char * slot,
KvpValue * new_value);
/** The kvp_frame_set_slot() routine copies the value into the frame,
* associating it with a copy of 'key'. Pointers passed as arguments
* into kvp_frame_set_slot are the responsibility of the caller;
* the pointers are *not* taken over or managed.
* the pointers are *not* taken over or managed. The old value at
* this location, if any, is destroyed.
*/
void kvp_frame_set_slot(KvpFrame * frame,
const char * key, const KvpValue * value);
@ -240,21 +375,24 @@ void kvp_frame_set_slot(KvpFrame * frame,
* routine is handy for avoiding excess memory allocations & frees.
* Note that because the KvpValue was grabbed, you can't just delete
* unless you remove the key as well (or unless you replace the value).
* The old value at this location, if any, is destroyed.
*/
void kvp_frame_set_slot_nc(KvpFrame * frame,
const char * key, KvpValue * value);
/** The kvp_frame_set_slot_path() routine walks the hierarchy,
* using the key values to pick each branch. When the terminal node
* is reached, the value is copied into it.
* using the key values to pick each branch. When the terminal
* node is reached, the value is copied into it. The old value
* at this location, if any, is destroyed.
*/
void kvp_frame_set_slot_path (KvpFrame *frame,
const KvpValue *value,
const char *first_key, ...);
/** The kvp_frame_set_slot_path_gslist() routine walks the hierarchy,
* using the key values to pick each branch. When the terminal node
* is reached, the value is copied into it.
* using the key values to pick each branch. When the terminal node
* is reached, the value is copied into it. The old value at this
* location, if any, is destroyed.
*/
void kvp_frame_set_slot_path_gslist (KvpFrame *frame,
const KvpValue *value,
@ -268,7 +406,9 @@ void kvp_frame_set_slot_path_gslist (KvpFrame *frame,
/** You probably shouldn't be using these low-level routines */
/** Returns the KvpValue in the given KvpFrame 'frame' that is
* associated with 'key'.
* associated with 'key'. If there is no key in the frame, NULL
* is returned. If the value associated with the key is NULL,
* NULL is returned.
*
* Pointers passed as arguments into get_slot are the responsibility
* of the caller. Pointers returned by get_slot are owned by the
@ -297,22 +437,30 @@ gint kvp_frame_compare(const KvpFrame *fa, const KvpFrame *fb);
gint double_compare(double v1, double v2);
/** list convenience funcs. */
/** @name KvpValue List Convenience Functions */
/*@{*/
/** You probably shouldn't be using these low-level routines */
/** kvp_glist_compare() compares <b>GLists of kvp_values</b> (not to
* be confused with GLists of something else): it iterates over
* the list elements, performing a kvp_value_compare on each.
*/
gint kvp_glist_compare(const GList * list1, const GList * list2);
/** kvp_glist_copy() performs a deep copy of a <b>GList of
* kvp_frame's</b> (not to be confused with GLists of something
/** kvp_glist_copy() performs a deep copy of a <b>GList of
* kvp_values</b> (not to be confused with GLists of something
* else): same as mapping kvp_value_copy() over the elements and
* then copying the spine.
*/
GList * kvp_glist_copy(const GList * list);
/** kvp_glist_delete() performs a deep delete of a <b>GList of
* kvp_frame's</b> (not to be confused with GLists of something
* kvp_values</b> (not to be confused with GLists of something
* else): same as mapping * kvp_value_delete() over the elements
* and then deleting the GList.
*/
void kvp_glist_delete(GList * list);
/*@}*/
/** @name KvpValue Constructors */
@ -331,11 +479,11 @@ KvpValue * kvp_value_new_string(const char * value);
KvpValue * kvp_value_new_guid(const GUID * guid);
KvpValue * kvp_value_new_timespec(Timespec timespec);
KvpValue * kvp_value_new_binary(const void * data, guint64 datasize);
KvpValue * kvp_value_new_frame(const KvpFrame * value);
/** Creates a KvpValue from a <b>GList of kvp_value's</b>! (Not to be
* confused with GList's of something else!) */
KvpValue * kvp_value_new_glist(const GList * value);
KvpValue * kvp_value_new_frame(const KvpFrame * value);
/** value constructors (non-copying - KvpValue takes pointer ownership)
values *must* have been allocated via glib allocators! (gnew, etc.) */
@ -358,21 +506,30 @@ void kvp_value_delete(KvpValue * value);
/** This is a deep value copy. */
KvpValue * kvp_value_copy(const KvpValue * value);
/** replace old frame value with new, return old frame */
KvpFrame * kvp_value_replace_frame_nc(KvpValue *value, KvpFrame * newframe);
/*@}*/
/** @name KvpValue Value access */
/*@{*/
/** You probably shouldn't be using these low-level routines */
/** Value accessors. Those for GUID, binary, GList, KvpFrame and
string are non-copying -- the caller can modify the value directly.
Note that the above non-copying list did not include the
get_string() function. But in fact that function has always been a
non-copying one -- therefore don't free the result unless you want
to delete the whole KvpFrame by yourself. */
KvpValueType kvp_value_get_type(const KvpValue * value);
/** Value accessors. Those for GUID, binary, GList, KvpFrame and
* string are non-copying -- the caller can modify the value
* directly. Just don't free it, or you screw up everything.
* Note that if another value is stored at the key location
* that this value came from, then this value will be
* uncermoniously deleted, and you will be left pointing to
* garbage. So don't store values at the same time you are
* examining thier contents.
*/
gint64 kvp_value_get_gint64(const KvpValue * value);
double kvp_value_get_double(const KvpValue * value);
gnc_numeric kvp_value_get_numeric(const KvpValue * value);