mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
implement the KVP utilities that have always been needed.
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@8945 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
@@ -102,7 +102,7 @@ Name: /book/open-date
|
||||
Type: Timespec
|
||||
Entities: Book
|
||||
Use: The posted opening date of this book. This book only contains transactions
|
||||
whose posted date is laterr than this closing date.
|
||||
whose posted date is later than this closing date.
|
||||
|
||||
Name: /book/prev-acct
|
||||
Type: GUID
|
||||
|
||||
@@ -172,7 +172,8 @@ kvp_frame_copy(const KvpFrame * frame)
|
||||
|
||||
static void
|
||||
kvp_frame_set_slot_destructively(KvpFrame * frame, const char * slot,
|
||||
KvpValue * new_value) {
|
||||
KvpValue * new_value)
|
||||
{
|
||||
/* FIXME: no way to indicate errors... */
|
||||
|
||||
gpointer orig_key;
|
||||
@@ -204,6 +205,64 @@ kvp_frame_set_slot_destructively(KvpFrame * frame, const char * slot,
|
||||
g_hash_table_thaw(frame->hash);
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
void
|
||||
kvp_frame_set_gint64(KvpFrame * frame, const char * path, gint64 ival)
|
||||
{
|
||||
KvpValue *value;
|
||||
value = kvp_value_new_gint64 (ival);
|
||||
frame = kvp_frame_set_slot_slash_nc (frame, path, value);
|
||||
if (!frame) kvp_value_delete (value);
|
||||
}
|
||||
|
||||
void
|
||||
kvp_frame_set_double(KvpFrame * frame, const char * path, double dval)
|
||||
{
|
||||
KvpValue *value;
|
||||
value = kvp_value_new_double (dval);
|
||||
frame = kvp_frame_set_slot_slash_nc (frame, path, value);
|
||||
if (!frame) kvp_value_delete (value);
|
||||
}
|
||||
|
||||
void
|
||||
kvp_frame_set_gnc_numeric(KvpFrame * frame, const char * path, gnc_numeric nval)
|
||||
{
|
||||
KvpValue *value;
|
||||
value = kvp_value_new_gnc_numeric (nval);
|
||||
frame = kvp_frame_set_slot_slash_nc (frame, path, value);
|
||||
if (!frame) kvp_value_delete (value);
|
||||
}
|
||||
|
||||
void
|
||||
kvp_frame_set_str(KvpFrame * frame, const char * path, const char* str)
|
||||
{
|
||||
KvpValue *value;
|
||||
value = kvp_value_new_string (str);
|
||||
frame = kvp_frame_set_slot_slash_nc (frame, path, value);
|
||||
if (!frame) kvp_value_delete (value);
|
||||
}
|
||||
|
||||
void
|
||||
kvp_frame_set_guid(KvpFrame * frame, const char * path, const GUID *guid)
|
||||
{
|
||||
KvpValue *value;
|
||||
value = kvp_value_new_guid (guid);
|
||||
frame = kvp_frame_set_slot_slash_nc (frame, path, value);
|
||||
if (!frame) kvp_value_delete (value);
|
||||
}
|
||||
|
||||
void
|
||||
kvp_frame_set_timespec(KvpFrame * frame, const char * path, Timespec ts)
|
||||
{
|
||||
KvpValue *value;
|
||||
value = kvp_value_new_timespec (ts);
|
||||
frame = kvp_frame_set_slot_slash_nc (frame, path, value);
|
||||
if (!frame) kvp_value_delete (value);
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
void
|
||||
kvp_frame_set_slot(KvpFrame * frame, const char * slot,
|
||||
const KvpValue * value)
|
||||
@@ -332,6 +391,126 @@ kvp_frame_set_slot_path_gslist (KvpFrame *frame,
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
/* Get the named frame, or create it if it doesn't exist.
|
||||
* gcc -O3 should inline it. It performs no error checks,
|
||||
* the caller is responsible of passing good keys and frames.
|
||||
*/
|
||||
static inline KvpFrame *
|
||||
get_or_make (KvpFrame *fr, const char * key)
|
||||
{
|
||||
KvpFrame *next_frame;
|
||||
KvpValue *value;
|
||||
|
||||
value = kvp_frame_get_slot (fr, key);
|
||||
if (value)
|
||||
{
|
||||
next_frame = kvp_value_get_frame (value);
|
||||
}
|
||||
else
|
||||
{
|
||||
next_frame = kvp_frame_new ();
|
||||
kvp_frame_set_slot_nc (fr, key,
|
||||
kvp_value_new_frame_nc (next_frame));
|
||||
}
|
||||
return next_frame;
|
||||
}
|
||||
|
||||
/* Get pointer to last frame in path. The string stored in
|
||||
* keypath will be hopelessly mangled .
|
||||
*/
|
||||
static inline KvpFrame *
|
||||
kvp_frame_get_frame_slash_trash (KvpFrame *frame, char *key_path)
|
||||
{
|
||||
char *key, *next;
|
||||
if (!frame || !key_path) return frame;
|
||||
|
||||
key = key_path;
|
||||
key --;
|
||||
|
||||
while (key)
|
||||
{
|
||||
key ++;
|
||||
while ('/' == *key) { key++; }
|
||||
if (0x0 == *key) break; /* trailing slash */
|
||||
next = strchr (key, '/');
|
||||
if (next) *next = 0x0;
|
||||
|
||||
frame = get_or_make (frame, key);
|
||||
if (!frame) break; /* error - should never happen */
|
||||
|
||||
key = next;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
/* return pointer to last frame in path, and also store the
|
||||
* last dangling part of path in 'end_key'.
|
||||
*/
|
||||
|
||||
static inline KvpFrame *
|
||||
get_trailer (KvpFrame * frame, const char * key_path, char **end_key)
|
||||
{
|
||||
char *last_key;
|
||||
|
||||
if (!frame || !key_path || (0 == key_path[0])) return NULL;
|
||||
|
||||
last_key = strrchr (key_path, '/');
|
||||
if (NULL == last_key)
|
||||
{
|
||||
last_key = (char *) key_path;
|
||||
}
|
||||
else if (last_key == key_path)
|
||||
{
|
||||
last_key ++;
|
||||
}
|
||||
else if (0 == last_key[1])
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *root, *lkey;
|
||||
root = g_strdup (key_path);
|
||||
lkey = strrchr (root, '/');
|
||||
*lkey = 0;
|
||||
frame = kvp_frame_get_frame_slash_trash (frame, root);
|
||||
g_free(root);
|
||||
|
||||
last_key ++;
|
||||
}
|
||||
|
||||
*end_key = last_key;
|
||||
return frame;
|
||||
}
|
||||
|
||||
KvpFrame *
|
||||
kvp_frame_set_slot_slash_nc (KvpFrame * frame, const char * key_path,
|
||||
KvpValue * value)
|
||||
{
|
||||
char *last_key;
|
||||
|
||||
frame = get_trailer (frame, key_path, &last_key);
|
||||
if (!frame) return NULL;
|
||||
kvp_frame_set_slot_destructively(frame, last_key, value);
|
||||
return frame;
|
||||
}
|
||||
|
||||
KvpFrame *
|
||||
kvp_frame_set_slot_slash (KvpFrame * frame, const char * key_path,
|
||||
const KvpValue * value)
|
||||
{
|
||||
KvpValue *new_value = NULL;
|
||||
char *last_key;
|
||||
|
||||
frame = get_trailer (frame, key_path, &last_key);
|
||||
if (!frame) return NULL;
|
||||
|
||||
if (value) new_value = kvp_value_copy(value);
|
||||
kvp_frame_set_slot_destructively(frame, last_key, new_value);
|
||||
return frame;
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
/* decode url-encoded string, do it in place
|
||||
* + == space
|
||||
@@ -411,41 +590,6 @@ kvp_frame_add_url_encoding (KvpFrame *frame, const char *enc)
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
/*
|
||||
* NOTE: This patch undoes a previous (brain-damaged) patch.
|
||||
* Please don't un-un-do it.
|
||||
* The following three routines were re-written to remove a
|
||||
* memory leak. The second and third routines were also
|
||||
* re-written to avoid an avalanche of mallocs needed to
|
||||
* shoehorn them into kvp_frame_get_frame_gslist() as an
|
||||
* intermediate step. The result is a simpler implementation,
|
||||
* bosted performance, less memory fragmentation, and the code
|
||||
* is easier to understand.
|
||||
*/
|
||||
|
||||
/* get the named frame, or create it if it doesn't exist.
|
||||
* gcc -O3 should inline it. It performs no error checks,
|
||||
* the caller is responsible of passing good keys and frames.
|
||||
*/
|
||||
static inline KvpFrame *
|
||||
get_or_make (KvpFrame *fr, const char * key)
|
||||
{
|
||||
KvpFrame *next_frame;
|
||||
KvpValue *value;
|
||||
|
||||
value = kvp_frame_get_slot (fr, key);
|
||||
if (value)
|
||||
{
|
||||
next_frame = kvp_value_get_frame (value);
|
||||
}
|
||||
else
|
||||
{
|
||||
next_frame = kvp_frame_new ();
|
||||
kvp_frame_set_slot_nc (fr, key,
|
||||
kvp_value_new_frame_nc (next_frame));
|
||||
}
|
||||
return next_frame;
|
||||
}
|
||||
|
||||
KvpFrame *
|
||||
kvp_frame_get_frame_gslist (KvpFrame *frame, GSList *key_path)
|
||||
@@ -486,30 +630,14 @@ kvp_frame_get_frame (KvpFrame *frame, const char *key, ...)
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
KvpFrame *
|
||||
kvp_frame_get_frame_slash (KvpFrame *frame, const char *key_path)
|
||||
{
|
||||
char *root, *key, *next;
|
||||
char *root;
|
||||
if (!frame || !key_path) return frame;
|
||||
|
||||
root = g_strdup (key_path);
|
||||
key = root;
|
||||
key --;
|
||||
|
||||
while (key)
|
||||
{
|
||||
key ++;
|
||||
while ('/' == *key) { key++; }
|
||||
if (0x0 == *key) break; /* trailing slash */
|
||||
next = strchr (key, '/');
|
||||
if (next) *next = 0x0;
|
||||
|
||||
frame = get_or_make (frame, key);
|
||||
if (!frame) break; /* error - should never happen */
|
||||
|
||||
key = next;
|
||||
}
|
||||
frame = kvp_frame_get_frame_slash_trash (frame, root);
|
||||
g_free(root);
|
||||
return frame;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
* a key such as 'some/key' or 'some/./other/../key' because you
|
||||
* may get unexpected results.
|
||||
*
|
||||
* In almost all cases, you want to be using the kvp_frame_set_gint64()
|
||||
* routine or one of its brothers. Most of the other routines provide
|
||||
* only low-level access.
|
||||
*/
|
||||
typedef struct _KvpFrame KvpFrame;
|
||||
|
||||
@@ -116,9 +119,66 @@ gchar* binary_to_string(const void *data, guint32 size);
|
||||
gchar* kvp_value_glist_to_string(const GList *list);
|
||||
GHashTable* kvp_frame_get_hash(const KvpFrame *frame);
|
||||
|
||||
|
||||
/** @name KvpFrame 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.
|
||||
* */
|
||||
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_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
|
||||
* indicated frame. URL-encoded strings are the things that are
|
||||
* returned by web browsers when a form is filled out. For example,
|
||||
* 'start-date=June&end-date=November' consists of two keys,
|
||||
* 'start-date' and 'end-date', which have the values 'June' and
|
||||
* 'November', respectively. This routine also handles % encoding.
|
||||
*
|
||||
* This routine treats all values as strings; it does *not* attempt
|
||||
* to perform any type-conversion.
|
||||
* */
|
||||
void kvp_frame_add_url_encoding (KvpFrame *frame, const char *enc);
|
||||
/*@}*/
|
||||
|
||||
/** @name KvpFrame KvpValue low-level storing routines. */
|
||||
/*@{*/
|
||||
|
||||
/** 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).
|
||||
*
|
||||
* 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_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).
|
||||
*/
|
||||
KvpFrame * kvp_frame_set_slot_slash_nc(KvpFrame * frame,
|
||||
const char * path, KvpValue * 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;
|
||||
@@ -152,19 +212,6 @@ void kvp_frame_set_slot_path_gslist (KvpFrame *frame,
|
||||
const KvpValue *value,
|
||||
GSList *key_path);
|
||||
|
||||
/** 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
|
||||
* indicated frame. URL-encoded strings are the things that are
|
||||
* returned by web browsers when a form is filled out. For example,
|
||||
* 'start-date=June&end-date=November' consists of two keys,
|
||||
* 'start-date' and 'end-date', which have the values 'June' and
|
||||
* 'November', respectively. This routine also handles % encoding.
|
||||
*
|
||||
* This routine treats all values as strings; it does *not* attempt
|
||||
* to perform any type-conversion.
|
||||
* */
|
||||
void kvp_frame_add_url_encoding (KvpFrame *frame, const char *enc);
|
||||
/*@}*/
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user