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:
Linas Vepstas
2003-07-26 23:25:56 +00:00
parent 9fd213bdb3
commit 7263dfdae4
3 changed files with 244 additions and 69 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
/*@}*/