QOF 0.8.4
kvpframe.c
00001 /********************************************************************
00002  * kvpframe.c -- Implements a key-value frame system                *
00003  * Copyright (C) 2000 Bill Gribble                                  *
00004  * Copyright (C) 2001,2003 Linas Vepstas <linas@linas.org>          *
00005  * Copyright (c) 2006-2008 Neil Williams <linux@codehelp.co.uk>     *
00006  *                                                                  *
00007  * This program is free software; you can redistribute it and/or    *
00008  * modify it under the terms of the GNU General Public License as   *
00009  * published by the Free Software Foundation; either version 2 of   *
00010  * the License, or (at your option) any later version.              *
00011  *                                                                  *
00012  * This program is distributed in the hope that it will be useful,  *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00015  * GNU General Public License for more details.                     *
00016  *                                                                  *
00017  * You should have received a copy of the GNU General Public License*
00018  * along with this program; if not, contact:                        *
00019  *                                                                  *
00020  * Free Software Foundation           Voice:  +1-617-542-5942       *
00021  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00022  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00023  *                                                                  *
00024  ********************************************************************/
00025 
00026 #include "config.h"
00027 
00028 #include <glib.h>
00029 #include <stdarg.h>
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include "qof.h"
00033 
00034  /* Note that we keep the keys for this hash table in a GCache
00035   * (qof_util_string_cache), as it is very likely we will see the 
00036   * same keys over and over again  */
00037 
00038 struct _KvpFrame
00039 {
00040     GHashTable *hash;
00041 };
00042 
00043 typedef struct
00044 {
00045     gpointer data;
00046     gint64 datasize;
00047 } KvpValueBinaryData;
00048 
00049 struct _KvpValue
00050 {
00051     KvpValueType type;
00052     union
00053     {
00054         gint64 int64;
00055         gdouble dbl;
00056         QofNumeric numeric;
00057         gchar *str;
00058         GUID *guid;
00059         QofTime *qt;
00060         gboolean gbool;     /* since 0.7.2 */
00061         KvpValueBinaryData binary;
00062         GList *list;
00063         KvpFrame *frame;
00064     } value;
00065 };
00066 
00067 /* This static indicates the debugging module that this .o belongs to.  */
00068 static QofLogModule log_module = QOF_MOD_KVP;
00069 
00070 /* *******************************************************************
00071  * KvpFrame functions
00072  ********************************************************************/
00073 
00074 static guint
00075 kvp_hash_func (gconstpointer v)
00076 {
00077     return g_str_hash (v);
00078 }
00079 
00080 static gint
00081 kvp_comp_func (gconstpointer v, gconstpointer v2)
00082 {
00083     return g_str_equal (v, v2);
00084 }
00085 
00086 static gboolean
00087 init_frame_body_if_needed (KvpFrame * f)
00088 {
00089     if (!f->hash)
00090     {
00091         f->hash = g_hash_table_new (&kvp_hash_func, &kvp_comp_func);
00092     }
00093     return (f->hash != NULL);
00094 }
00095 
00096 KvpFrame *
00097 kvp_frame_new (void)
00098 {
00099     KvpFrame *retval = g_new0 (KvpFrame, 1);
00100 
00101     /* Save space until the frame is actually used */
00102     retval->hash = NULL;
00103     return retval;
00104 }
00105 
00106 static void
00107 kvp_frame_delete_worker (gpointer key, gpointer value, 
00108     gpointer user_data __attribute__ ((unused)))
00109 {
00110     qof_util_string_cache_remove (key);
00111     kvp_value_delete ((KvpValue *) value);
00112 }
00113 
00114 void
00115 kvp_frame_delete (KvpFrame * frame)
00116 {
00117     if (!frame)
00118         return;
00119 
00120     if (frame->hash)
00121     {
00122         /* free any allocated resource for frame or its children */
00123         g_hash_table_foreach (frame->hash, &kvp_frame_delete_worker,
00124             (gpointer) frame);
00125 
00126         /* delete the hash table */
00127         g_hash_table_destroy (frame->hash);
00128         frame->hash = NULL;
00129     }
00130     g_free (frame);
00131 }
00132 
00133 gboolean
00134 kvp_frame_is_empty (KvpFrame * frame)
00135 {
00136     if (!frame)
00137         return TRUE;
00138     if (!frame->hash)
00139         return TRUE;
00140     return FALSE;
00141 }
00142 
00143 static void
00144 kvp_frame_copy_worker (gpointer key, gpointer value, gpointer user_data)
00145 {
00146     KvpFrame *dest = (KvpFrame *) user_data;
00147     g_hash_table_insert (dest->hash,
00148         qof_util_string_cache_insert (key),
00149         (gpointer) kvp_value_copy (value));
00150 }
00151 
00152 KvpFrame *
00153 kvp_frame_copy (const KvpFrame * frame)
00154 {
00155     KvpFrame *retval = kvp_frame_new ();
00156 
00157     if (!frame)
00158         return retval;
00159 
00160     if (frame->hash)
00161     {
00162         if (!init_frame_body_if_needed (retval))
00163             return (NULL);
00164         g_hash_table_foreach (frame->hash,
00165             &kvp_frame_copy_worker, (gpointer) retval);
00166     }
00167     return retval;
00168 }
00169 
00170 /* Replace the old value with the new value.  Return the old value.
00171  * Passing in a null value into this routine has the effect of 
00172  * removing the key from the KVP tree.
00173  */
00174 KvpValue *
00175 kvp_frame_replace_slot_nc (KvpFrame * frame, const gchar *slot,
00176     KvpValue * new_value)
00177 {
00178     gpointer orig_key;
00179     gpointer orig_value = NULL;
00180     int key_exists;
00181 
00182     if (!frame || !slot)
00183         return NULL;
00184     if (!init_frame_body_if_needed (frame))
00185         return NULL;            /* Error ... */
00186 
00187     key_exists = g_hash_table_lookup_extended (frame->hash, slot,
00188         &orig_key, &orig_value);
00189     if (key_exists)
00190     {
00191         g_hash_table_remove (frame->hash, slot);
00192         qof_util_string_cache_remove (orig_key);
00193     }
00194     else
00195         orig_value = NULL;
00196     if (new_value)
00197         g_hash_table_insert (frame->hash,
00198             qof_util_string_cache_insert ((gpointer) slot), new_value);
00199     return (KvpValue *) orig_value;
00200 }
00201 
00202 /* Passing in a null value into this routine has the effect
00203  * of deleting the old value stored at this slot.
00204  */
00205 static inline void
00206 kvp_frame_set_slot_destructively (KvpFrame * frame, const gchar *slot,
00207     KvpValue * new_value)
00208 {
00209     KvpValue *old_value;
00210     old_value = kvp_frame_replace_slot_nc (frame, slot, new_value);
00211     kvp_value_delete (old_value);
00212 }
00213 
00214 /* ============================================================ */
00215 /* Get the named frame, or create it if it doesn't exist.
00216  * gcc -O3 should inline it.  It performs no error checks,
00217  * the caller is responsible of passing good keys and frames.
00218  */
00219 static inline KvpFrame *
00220 get_or_make (KvpFrame * fr, const gchar *key)
00221 {
00222     KvpFrame *next_frame;
00223     KvpValue *value;
00224 
00225     value = kvp_frame_get_slot (fr, key);
00226     if (value)
00227         next_frame = kvp_value_get_frame (value);
00228     else
00229     {
00230         next_frame = kvp_frame_new ();
00231         kvp_frame_set_slot_nc (fr, key,
00232             kvp_value_new_frame_nc (next_frame));
00233     }
00234     return next_frame;
00235 }
00236 
00237 /* Get pointer to last frame in path. If the path doesn't exist,
00238  * it is created.  The string stored in keypath will be hopelessly 
00239  * mangled .
00240  */
00241 static KvpFrame *
00242 kvp_frame_get_frame_slash_trash (KvpFrame * frame, gchar *key_path)
00243 {
00244     gchar *key, *next;
00245     if (!frame || !key_path)
00246         return frame;
00247 
00248     key = key_path;
00249     key--;
00250 
00251     while (key)
00252     {
00253         key++;
00254         while ('/' == *key)
00255             key++;
00256         if (0x0 == *key)
00257             break;              /* trailing slash */
00258         next = strchr (key, '/');
00259         if (next)
00260             *next = 0x0;
00261 
00262         frame = get_or_make (frame, key);
00263         if (!frame)
00264             break;              /* error - should never happen */
00265 
00266         key = next;
00267     }
00268     return frame;
00269 }
00270 
00271 /* ============================================================ */
00272 /* Get pointer to last frame in path, or NULL if the path doesn't
00273  * exist. The string stored in keypath will be hopelessly mangled .
00274  */
00275 static inline const KvpFrame *
00276 kvp_frame_get_frame_or_null_slash_trash (const KvpFrame * frame,
00277     gchar *key_path)
00278 {
00279     KvpValue *value;
00280     gchar *key, *next;
00281     if (!frame || !key_path)
00282         return NULL;
00283 
00284     key = key_path;
00285     key--;
00286 
00287     while (key)
00288     {
00289         key++;
00290         while ('/' == *key)
00291             key++;
00292         if (0x0 == *key)
00293             break;              /* trailing slash */
00294         next = strchr (key, '/');
00295         if (next)
00296             *next = 0x0;
00297 
00298         value = kvp_frame_get_slot (frame, key);
00299         if (!value)
00300             return NULL;
00301         frame = kvp_value_get_frame (value);
00302         if (!frame)
00303             return NULL;
00304 
00305         key = next;
00306     }
00307     return frame;
00308 }
00309 
00310 /* Return pointer to last frame in path, and also store the
00311  * last dangling part of path in 'end_key'.  If path doesn't 
00312  * exist, it is created.
00313  */
00314 
00315 static inline KvpFrame *
00316 get_trailer_make (KvpFrame * frame, const gchar *key_path, 
00317                   gchar **end_key)
00318 {
00319     gchar *last_key;
00320 
00321     if (!frame || !key_path || (0 == key_path[0]))
00322         return NULL;
00323 
00324     last_key = strrchr (key_path, '/');
00325     if (NULL == last_key)
00326         last_key = (gchar *) key_path;
00327     else if (last_key == key_path)
00328         last_key++;
00329     else if (0 == last_key[1])
00330         return NULL;
00331     else
00332     {
00333         gchar *root, *lkey;
00334         root = g_strdup (key_path);
00335         lkey = strrchr (root, '/');
00336         *lkey = 0;
00337         frame = kvp_frame_get_frame_slash_trash (frame, root);
00338         g_free (root);
00339         last_key++;
00340     }
00341 
00342     *end_key = last_key;
00343     return frame;
00344 }
00345 
00346 
00347 /* Return pointer to last frame in path, or NULL if the path
00348  * doesn't exist.  Also store the last dangling part of path
00349  * in 'end_key'.
00350  */
00351 
00352 static inline const KvpFrame *
00353 get_trailer_or_null (const KvpFrame * frame, const gchar *key_path,
00354     gchar **end_key)
00355 {
00356     gchar *last_key;
00357 
00358     if (!frame || !key_path || (0 == key_path[0]))
00359         return NULL;
00360 
00361     last_key = strrchr (key_path, '/');
00362     if (NULL == last_key)
00363         last_key = (gchar *) key_path;
00364     else if (last_key == key_path)
00365         last_key++;
00366     else if (0 == last_key[1])
00367         return NULL;
00368     else
00369     {
00370         gchar *root, *lkey;
00371         root = g_strdup (key_path);
00372         lkey = strrchr (root, '/');
00373         *lkey = 0;
00374         frame = kvp_frame_get_frame_or_null_slash_trash (frame, root);
00375         g_free (root);
00376 
00377         last_key++;
00378     }
00379 
00380     *end_key = last_key;
00381     return frame;
00382 }
00383 
00384 /* ============================================================ */
00385 
00386 void
00387 kvp_frame_set_gint64 (KvpFrame * frame, const gchar *path, gint64 ival)
00388 {
00389     KvpValue *value;
00390     value = kvp_value_new_gint64 (ival);
00391     frame = kvp_frame_set_value_nc (frame, path, value);
00392     if (!frame)
00393         kvp_value_delete (value);
00394 }
00395 
00396 void
00397 kvp_frame_set_double (KvpFrame * frame, const gchar *path, gdouble dval)
00398 {
00399     KvpValue *value;
00400     value = kvp_value_new_double (dval);
00401     frame = kvp_frame_set_value_nc (frame, path, value);
00402     if (!frame)
00403         kvp_value_delete (value);
00404 }
00405 
00406 void
00407 kvp_frame_set_time (KvpFrame * frame, const gchar *path, QofTime *qt)
00408 {
00409     KvpValue *value;
00410     value = kvp_value_new_time (qt);
00411     frame = kvp_frame_set_value_nc (frame, path, value);
00412     if (!frame)
00413         kvp_value_delete (value);
00414 }
00415 
00416 void
00417 kvp_frame_set_numeric (KvpFrame * frame, const gchar *path,
00418     QofNumeric nval)
00419 {
00420     KvpValue *value;
00421     value = kvp_value_new_numeric (nval);
00422     frame = kvp_frame_set_value_nc (frame, path, value);
00423     if (!frame)
00424         kvp_value_delete (value);
00425 }
00426 
00427 void
00428 kvp_frame_set_boolean (KvpFrame * frame, const gchar * path, 
00429                        gboolean val)
00430 {
00431     KvpValue * value;
00432     value = kvp_value_new_boolean (val);
00433     frame = kvp_frame_set_value_nc (frame, path, value);
00434     if (!frame)
00435         kvp_value_delete (value);
00436 }
00437 
00438 void
00439 kvp_frame_set_string (KvpFrame * frame, const gchar *path, 
00440                       const gchar *str)
00441 {
00442     KvpValue *value;
00443     value = kvp_value_new_string (str);
00444     frame = kvp_frame_set_value_nc (frame, path, value);
00445     if (!frame)
00446         kvp_value_delete (value);
00447 }
00448 
00449 void
00450 kvp_frame_set_guid (KvpFrame * frame, const gchar *path, 
00451                     const GUID * guid)
00452 {
00453     KvpValue *value;
00454     value = kvp_value_new_guid (guid);
00455     frame = kvp_frame_set_value_nc (frame, path, value);
00456     if (!frame)
00457         kvp_value_delete (value);
00458 }
00459 
00460 void
00461 kvp_frame_set_frame (KvpFrame * frame, const gchar *path, KvpFrame * fr)
00462 {
00463     KvpValue *value;
00464     value = kvp_value_new_frame (fr);
00465     frame = kvp_frame_set_value_nc (frame, path, value);
00466     if (!frame)
00467         kvp_value_delete (value);
00468 }
00469 
00470 void
00471 kvp_frame_set_frame_nc (KvpFrame * frame, const gchar *path, KvpFrame * fr)
00472 {
00473     KvpValue *value;
00474     value = kvp_value_new_frame_nc (fr);
00475     frame = kvp_frame_set_value_nc (frame, path, value);
00476     if (!frame)
00477         kvp_value_delete (value);
00478 }
00479 
00480 /* ============================================================ */
00481 
00482 KvpFrame *
00483 kvp_frame_set_value_nc (KvpFrame * frame, const gchar *key_path,
00484     KvpValue * value)
00485 {
00486     gchar *last_key;
00487 
00488     frame = get_trailer_make (frame, key_path, &last_key);
00489     if (!frame)
00490         return NULL;
00491     kvp_frame_set_slot_destructively (frame, last_key, value);
00492     return frame;
00493 }
00494 
00495 KvpFrame *
00496 kvp_frame_set_value (KvpFrame * frame, const gchar *key_path,
00497     const KvpValue * value)
00498 {
00499     KvpValue *new_value = NULL;
00500     gchar *last_key;
00501 
00502     frame = get_trailer_make (frame, key_path, &last_key);
00503     if (!frame)
00504         return NULL;
00505 
00506     if (value)
00507         new_value = kvp_value_copy (value);
00508     kvp_frame_set_slot_destructively (frame, last_key, new_value);
00509     return frame;
00510 }
00511 
00512 KvpValue *
00513 kvp_frame_replace_value_nc (KvpFrame * frame, const gchar *key_path,
00514     KvpValue * new_value)
00515 {
00516     KvpValue *old_value;
00517     gchar *last_key;
00518 
00519     last_key = NULL;
00520     if (new_value)
00521         frame = get_trailer_make (frame, key_path, &last_key);
00522     else
00523         frame =
00524             (KvpFrame *) get_trailer_or_null (frame, key_path, &last_key);
00525     if (!frame)
00526         return NULL;
00527 
00528     old_value = kvp_frame_replace_slot_nc (frame, last_key, new_value);
00529     return old_value;
00530 }
00531 
00532 /* ============================================================ */
00533 
00534 KvpFrame *
00535 kvp_frame_add_value_nc (KvpFrame * frame, const gchar *path,
00536     KvpValue * value)
00537 {
00538     gchar *key = NULL;
00539     KvpValue *oldvalue;
00540 
00541     frame = (KvpFrame *) get_trailer_or_null (frame, path, &key);
00542     oldvalue = kvp_frame_get_slot (frame, key);
00543 
00544     ENTER ("old frame=%s", kvp_frame_to_string (frame));
00545     if (oldvalue)
00546     {
00547         /* If already a glist here, just append */
00548         if (KVP_TYPE_GLIST == oldvalue->type)
00549         {
00550             GList *vlist = oldvalue->value.list;
00551             vlist = g_list_append (vlist, value);
00552             oldvalue->value.list = vlist;
00553         }
00554         else
00555             /* If some other value, convert it to a glist */
00556         {
00557             KvpValue *klist;
00558             GList *vlist = NULL;
00559 
00560             vlist = g_list_append (vlist, oldvalue);
00561             vlist = g_list_append (vlist, value);
00562             klist = kvp_value_new_glist_nc (vlist);
00563 
00564             kvp_frame_replace_slot_nc (frame, key, klist);
00565         }
00566         LEAVE ("new frame=%s", kvp_frame_to_string (frame));
00567         return frame;
00568     }
00569 
00570     /* Hmm, if we are here, the path doesn't exist. We need to 
00571      * create the path, add the value to it. */
00572     frame = kvp_frame_set_value_nc (frame, path, value);
00573     LEAVE ("new frame=%s", kvp_frame_to_string (frame));
00574     return frame;
00575 }
00576 
00577 KvpFrame *
00578 kvp_frame_add_value (KvpFrame * frame, const gchar *path, KvpValue * value)
00579 {
00580     value = kvp_value_copy (value);
00581     frame = kvp_frame_add_value_nc (frame, path, value);
00582     if (!frame)
00583         kvp_value_delete (value);
00584     return frame;
00585 }
00586 
00587 void
00588 kvp_frame_add_gint64 (KvpFrame * frame, const gchar *path, gint64 ival)
00589 {
00590     KvpValue *value;
00591     value = kvp_value_new_gint64 (ival);
00592     frame = kvp_frame_add_value_nc (frame, path, value);
00593     if (!frame)
00594         kvp_value_delete (value);
00595 }
00596 
00597 void
00598 kvp_frame_add_double (KvpFrame * frame, const gchar *path, gdouble dval)
00599 {
00600     KvpValue *value;
00601     value = kvp_value_new_double (dval);
00602     frame = kvp_frame_add_value_nc (frame, path, value);
00603     if (!frame)
00604         kvp_value_delete (value);
00605 }
00606 
00607 void
00608 kvp_frame_add_numeric (KvpFrame * frame, const gchar *path,
00609     QofNumeric nval)
00610 {
00611     KvpValue *value;
00612     value = kvp_value_new_numeric (nval);
00613     frame = kvp_frame_add_value_nc (frame, path, value);
00614     if (!frame)
00615         kvp_value_delete (value);
00616 }
00617 
00618 void
00619 kvp_frame_add_time (KvpFrame * frame, const gchar *path, QofTime *qt)
00620 {
00621     KvpValue *value;
00622     value = kvp_value_new_time (qt);
00623     frame = kvp_frame_add_value_nc (frame, path, value);
00624     if (!frame)
00625         kvp_value_delete (value);
00626 }
00627 
00628 void
00629 kvp_frame_add_boolean (KvpFrame * frame, const gchar * path, gboolean val)
00630 {
00631     KvpValue * value;
00632     value = kvp_value_new_boolean (val);
00633     frame = kvp_frame_add_value_nc (frame, path, value);
00634     if (!frame)
00635         kvp_value_delete (value);
00636 }
00637 
00638 void
00639 kvp_frame_add_string (KvpFrame * frame, const gchar *path, const gchar *str)
00640 {
00641     KvpValue *value;
00642     value = kvp_value_new_string (str);
00643     frame = kvp_frame_add_value_nc (frame, path, value);
00644     if (!frame)
00645         kvp_value_delete (value);
00646 }
00647 
00648 void
00649 kvp_frame_add_guid (KvpFrame * frame, const gchar *path, const GUID * guid)
00650 {
00651     KvpValue *value;
00652     value = kvp_value_new_guid (guid);
00653     frame = kvp_frame_add_value_nc (frame, path, value);
00654     if (!frame)
00655         kvp_value_delete (value);
00656 }
00657 
00658 void
00659 kvp_frame_add_frame (KvpFrame * frame, const gchar *path, KvpFrame * fr)
00660 {
00661     KvpValue *value;
00662     value = kvp_value_new_frame (fr);
00663     frame = kvp_frame_add_value_nc (frame, path, value);
00664     if (!frame)
00665         kvp_value_delete (value);
00666 }
00667 
00668 void
00669 kvp_frame_add_frame_nc (KvpFrame * frame, const gchar *path, KvpFrame * fr)
00670 {
00671     KvpValue *value;
00672     value = kvp_value_new_frame_nc (fr);
00673     frame = kvp_frame_add_value_nc (frame, path, value);
00674     if (!frame)
00675         kvp_value_delete (value);
00676 }
00677 
00678 /* ============================================================ */
00679 
00680 void
00681 kvp_frame_set_slot (KvpFrame * frame, const gchar *slot,
00682     const KvpValue * value)
00683 {
00684     KvpValue *new_value = NULL;
00685 
00686     if (!frame)
00687         return;
00688 
00689     g_return_if_fail (slot && *slot != '\0');
00690 
00691     if (value)
00692         new_value = kvp_value_copy (value);
00693     kvp_frame_set_slot_destructively (frame, slot, new_value);
00694 }
00695 
00696 void
00697 kvp_frame_set_slot_nc (KvpFrame * frame, const gchar *slot,
00698     KvpValue * value)
00699 {
00700     if (!frame)
00701         return;
00702 
00703     g_return_if_fail (slot && *slot != '\0');
00704 
00705     kvp_frame_set_slot_destructively (frame, slot, value);
00706 }
00707 
00708 KvpValue *
00709 kvp_frame_get_slot (const KvpFrame * frame, const gchar *slot)
00710 {
00711     KvpValue *v;
00712     if (!frame)
00713         return NULL;
00714     if (!frame->hash)
00715         return NULL;            /* Error ... */
00716     v = g_hash_table_lookup (frame->hash, slot);
00717     return v;
00718 }
00719 
00720 /* ============================================================ */
00721 
00722 void
00723 kvp_frame_set_slot_path (KvpFrame * frame,
00724     const KvpValue * new_value, const gchar *first_key, ...)
00725 {
00726     va_list ap;
00727     const gchar *key;
00728 
00729     if (!frame)
00730         return;
00731 
00732     g_return_if_fail (first_key && *first_key != '\0');
00733 
00734     va_start (ap, first_key);
00735 
00736     key = first_key;
00737 
00738     while (TRUE)
00739     {
00740         KvpValue *value;
00741         const gchar *next_key;
00742 
00743         next_key = va_arg (ap, const gchar *);
00744         if (!next_key)
00745         {
00746             kvp_frame_set_slot (frame, key, new_value);
00747             break;
00748         }
00749 
00750         g_return_if_fail (*next_key != '\0');
00751 
00752         value = kvp_frame_get_slot (frame, key);
00753         if (!value)
00754         {
00755             KvpFrame *new_frame = kvp_frame_new ();
00756             KvpValue *frame_value = kvp_value_new_frame (new_frame);
00757 
00758             kvp_frame_set_slot_nc (frame, key, frame_value);
00759 
00760             value = kvp_frame_get_slot (frame, key);
00761             if (!value)
00762                 break;
00763         }
00764 
00765         frame = kvp_value_get_frame (value);
00766         if (!frame)
00767             break;
00768 
00769         key = next_key;
00770     }
00771 
00772     va_end (ap);
00773 }
00774 
00775 void
00776 kvp_frame_set_slot_path_gslist (KvpFrame * frame,
00777     const KvpValue * new_value, GSList * key_path)
00778 {
00779     if (!frame || !key_path)
00780         return;
00781 
00782     while (TRUE)
00783     {
00784         const gchar *key = key_path->data;
00785         KvpValue *value;
00786 
00787         if (!key)
00788             return;
00789 
00790         g_return_if_fail (*key != '\0');
00791 
00792         key_path = key_path->next;
00793         if (!key_path)
00794         {
00795             kvp_frame_set_slot (frame, key, new_value);
00796             return;
00797         }
00798 
00799         value = kvp_frame_get_slot (frame, key);
00800         if (!value)
00801         {
00802             KvpFrame *new_frame = kvp_frame_new ();
00803             KvpValue *frame_value = kvp_value_new_frame (new_frame);
00804 
00805             kvp_frame_set_slot_nc (frame, key, frame_value);
00806 
00807             value = kvp_frame_get_slot (frame, key);
00808             if (!value)
00809                 return;
00810         }
00811 
00812         frame = kvp_value_get_frame (value);
00813         if (!frame)
00814             return;
00815     }
00816 }
00817 
00818 /* ============================================================ */
00819 /* decode url-encoded string, do it in place
00820  * + == space
00821  * %xx == asci char where xx is hexadecimal ascii value
00822  */
00823 
00824 static void
00825 decode (gchar *enc)
00826 {
00827     gchar *p, *w;
00828 
00829     /* Loop, convert +'s to blanks */
00830     p = strchr (enc, '+');
00831     while (p)
00832     {
00833         *p = ' ';
00834         p = strchr (p, '+');
00835     }
00836 
00837     p = strchr (enc, '%');
00838     w = p;
00839 
00840     while (p)
00841     {
00842         gint ch, cl;
00843         p++;
00844         ch = *p - 0x30;         /* ascii 0 = 0x30 */
00845         if (9 < ch)
00846             ch -= 0x11 - 10;    /* uppercase A = 0x41 */
00847         if (16 < ch)
00848             ch -= 0x20;         /* lowercase a = 0x61 */
00849 
00850         p++;
00851         cl = *p - 0x30;         /* ascii 0 = 0x30 */
00852         if (9 < cl)
00853             cl -= 0x11 - 10;    /* uppercase A = 0x41 */
00854         if (16 < cl)
00855             cl -= 0x20;         /* lowercase a = 0x61 */
00856 
00857         *w = (gchar) (ch << 4 | cl);
00858 
00859         do
00860         {
00861             ++w;
00862             ++p;
00863             *w = *p;
00864             if (0x0 == *p)
00865             {
00866                 p = 0;
00867                 break;
00868             }
00869             if ('%' == *p)
00870                 break;
00871         }
00872         while (*p);
00873     }
00874 }
00875 
00876 void
00877 kvp_frame_add_url_encoding (KvpFrame * frame, const gchar *enc)
00878 {
00879     gchar *buff, *p;
00880     if (!frame || !enc)
00881         return;
00882 
00883     /* Loop over all key-value pairs in the encoded string */
00884     buff = g_strdup (enc);
00885     p = buff;
00886     while (*p)
00887     {
00888         gchar *n, *v;
00889         n = strchr (p, '&');    /* n = next key-value */
00890         if (n)
00891             *n = 0x0;
00892 
00893         v = strchr (p, '=');    /* v =  pointer to value */
00894         if (!v)
00895             break;
00896         *v = 0x0;
00897         v++;
00898 
00899         decode (p);
00900         decode (v);
00901         kvp_frame_set_slot_nc (frame, p, kvp_value_new_string (v));
00902 
00903         if (!n)
00904             break;              /* no next key, we are done */
00905         p = ++n;
00906     }
00907 
00908     g_free (buff);
00909 }
00910 
00911 /* ============================================================ */
00912 
00913 
00914 gint64
00915 kvp_frame_get_gint64 (const KvpFrame * frame, const gchar *path)
00916 {
00917     gchar *key = NULL;
00918     frame = get_trailer_or_null (frame, path, &key);
00919     return kvp_value_get_gint64 (kvp_frame_get_slot (frame, key));
00920 }
00921 
00922 gdouble
00923 kvp_frame_get_double (const KvpFrame * frame, const gchar *path)
00924 {
00925     gchar *key = NULL;
00926     frame = get_trailer_or_null (frame, path, &key);
00927     return kvp_value_get_double (kvp_frame_get_slot (frame, key));
00928 }
00929 
00930 QofNumeric
00931 kvp_frame_get_numeric (const KvpFrame * frame, const gchar *path)
00932 {
00933     gchar *key = NULL;
00934     frame = get_trailer_or_null (frame, path, &key);
00935     return kvp_value_get_numeric (kvp_frame_get_slot (frame, key));
00936 }
00937 
00938 gchar *
00939 kvp_frame_get_string (const KvpFrame * frame, const gchar *path)
00940 {
00941     gchar *key = NULL;
00942     frame = get_trailer_or_null (frame, path, &key);
00943     return kvp_value_get_string (kvp_frame_get_slot (frame, key));
00944 }
00945 
00946 gboolean
00947 kvp_frame_get_boolean (const KvpFrame * frame, const gchar * path)
00948 {
00949     gchar * key = NULL;
00950     frame = get_trailer_or_null (frame, path, &key);
00951     return kvp_value_get_boolean (kvp_frame_get_slot (frame, key));
00952 }
00953 
00954 GUID *
00955 kvp_frame_get_guid (const KvpFrame * frame, const gchar *path)
00956 {
00957     gchar *key = NULL;
00958     frame = get_trailer_or_null (frame, path, &key);
00959     return kvp_value_get_guid (kvp_frame_get_slot (frame, key));
00960 }
00961 
00962 void *
00963 kvp_frame_get_binary (const KvpFrame * frame, const gchar *path,
00964     guint64 * size_return)
00965 {
00966     gchar *key = NULL;
00967     frame = get_trailer_or_null (frame, path, &key);
00968     return kvp_value_get_binary (kvp_frame_get_slot (frame, key),
00969         size_return);
00970 }
00971 
00972 QofTime *
00973 kvp_frame_get_time (const KvpFrame * frame, const gchar *path)
00974 {
00975     gchar *key = NULL;
00976     frame = get_trailer_or_null (frame, path, &key);
00977     return kvp_value_get_time (kvp_frame_get_slot (frame, key));
00978 }
00979 
00980 KvpFrame *
00981 kvp_frame_get_frame (const KvpFrame * frame, const gchar *path)
00982 {
00983     gchar *key = NULL;
00984     frame = get_trailer_or_null (frame, path, &key);
00985     return kvp_value_get_frame (kvp_frame_get_slot (frame, key));
00986 }
00987 
00988 KvpValue *
00989 kvp_frame_get_value (const KvpFrame * frame, const gchar *path)
00990 {
00991     gchar *key = NULL;
00992     frame = get_trailer_or_null (frame, path, &key);
00993     return kvp_frame_get_slot (frame, key);
00994 }
00995 
00996 /* ============================================================ */
00997 
00998 KvpFrame *
00999 kvp_frame_get_frame_gslist (KvpFrame * frame, GSList * key_path)
01000 {
01001     if (!frame)
01002         return frame;
01003 
01004     while (key_path)
01005     {
01006         const gchar *key = key_path->data;
01007 
01008         if (!key)
01009             return frame;       /* an unusual but valid exit for this routine. */
01010 
01011         frame = get_or_make (frame, key);
01012         if (!frame)
01013             return frame;       /* this should never happen */
01014 
01015         key_path = key_path->next;
01016     }
01017     return frame;               /* this is the normal exit for this func */
01018 }
01019 
01020 KvpFrame *
01021 kvp_frame_get_frame_path (KvpFrame * frame, const gchar *key, ...)
01022 {
01023     va_list ap;
01024     if (!frame || !key)
01025         return frame;
01026 
01027     va_start (ap, key);
01028 
01029     while (key)
01030     {
01031         frame = get_or_make (frame, key);
01032         if (!frame)
01033             break;              /* error, should never occur */
01034         key = va_arg (ap, const char *);
01035     }
01036 
01037     va_end (ap);
01038     return frame;
01039 }
01040 
01041 KvpFrame *
01042 kvp_frame_get_frame_slash (KvpFrame * frame, const gchar *key_path)
01043 {
01044     gchar *root;
01045     if (!frame || !key_path)
01046         return frame;
01047 
01048     root = g_strdup (key_path);
01049     frame = kvp_frame_get_frame_slash_trash (frame, root);
01050     g_free (root);
01051     return frame;
01052 }
01053 
01054 /* ============================================================ */
01055 
01056 KvpValue *
01057 kvp_frame_get_slot_path (KvpFrame * frame, const gchar *first_key, ...)
01058 {
01059     va_list ap;
01060     KvpValue *value;
01061     const gchar *key;
01062 
01063     if (!frame || !first_key)
01064         return NULL;
01065 
01066     va_start (ap, first_key);
01067 
01068     key = first_key;
01069     value = NULL;
01070 
01071     while (TRUE)
01072     {
01073         value = kvp_frame_get_slot (frame, key);
01074         if (!value)
01075             break;
01076 
01077         key = va_arg (ap, const gchar *);
01078         if (!key)
01079             break;
01080 
01081         frame = kvp_value_get_frame (value);
01082         if (!frame)
01083         {
01084             value = NULL;
01085             break;
01086         }
01087     }
01088 
01089     va_end (ap);
01090 
01091     return value;
01092 }
01093 
01094 KvpValue *
01095 kvp_frame_get_slot_path_gslist (KvpFrame * frame, GSList * key_path)
01096 {
01097     if (!frame || !key_path)
01098         return NULL;
01099 
01100     while (TRUE)
01101     {
01102         const gchar *key = key_path->data;
01103         KvpValue *value;
01104 
01105         if (!key)
01106             return NULL;
01107 
01108         value = kvp_frame_get_slot (frame, key);
01109         if (!value)
01110             return NULL;
01111 
01112         key_path = key_path->next;
01113         if (!key_path)
01114             return value;
01115 
01116         frame = kvp_value_get_frame (value);
01117         if (!frame)
01118             return NULL;
01119     }
01120 }
01121 
01122 /* *******************************************************************
01123  * kvp glist functions
01124  ********************************************************************/
01125 
01126 void
01127 kvp_glist_delete (GList * list)
01128 {
01129     GList *node;
01130     if (!list)
01131         return;
01132 
01133     /* Delete the data in the list */
01134     for (node = list; node; node = node->next)
01135     {
01136         KvpValue *val = node->data;
01137         kvp_value_delete (val);
01138     }
01139 
01140     /* Free the backbone */
01141     g_list_free (list);
01142 }
01143 
01144 GList *
01145 kvp_glist_copy (const GList * list)
01146 {
01147     GList *retval = NULL;
01148     GList *lptr;
01149 
01150     if (!list)
01151         return retval;
01152 
01153     /* Duplicate the backbone of the list (this duplicates the POINTERS
01154      * to the values; we need to deep-copy the values separately) */
01155     retval = g_list_copy ((GList *) list);
01156 
01157     /* This step deep-copies the values */
01158     for (lptr = retval; lptr; lptr = lptr->next)
01159     {
01160         lptr->data = kvp_value_copy (lptr->data);
01161     }
01162 
01163     return retval;
01164 }
01165 
01166 gint
01167 kvp_glist_compare (const GList * list1, const GList * list2)
01168 {
01169     const GList *lp1;
01170     const GList *lp2;
01171 
01172     if (list1 == list2)
01173         return 0;
01174 
01175     /* Nothing is always less than something */
01176     if (!list1 && list2)
01177         return -1;
01178     if (list1 && !list2)
01179         return 1;
01180 
01181     lp1 = list1;
01182     lp2 = list2;
01183     while (lp1 && lp2)
01184     {
01185         KvpValue *v1 = (KvpValue *) lp1->data;
01186         KvpValue *v2 = (KvpValue *) lp2->data;
01187         gint vcmp = kvp_value_compare (v1, v2);
01188         if (vcmp != 0)
01189             return vcmp;
01190         lp1 = lp1->next;
01191         lp2 = lp2->next;
01192     }
01193     if (!lp1 && lp2)
01194         return -1;
01195     if (!lp2 && lp1)
01196         return 1;
01197     return 0;
01198 }
01199 
01200 /* *******************************************************************
01201  * KvpValue functions
01202  ********************************************************************/
01203 
01204 KvpValue *
01205 kvp_value_new_gint64 (gint64 value)
01206 {
01207     KvpValue *retval = g_new0 (KvpValue, 1);
01208     retval->type = KVP_TYPE_GINT64;
01209     retval->value.int64 = value;
01210     return retval;
01211 }
01212 
01213 KvpValue *
01214 kvp_value_new_double (gdouble value)
01215 {
01216     KvpValue *retval = g_new0 (KvpValue, 1);
01217     retval->type = KVP_TYPE_DOUBLE;
01218     retval->value.dbl = value;
01219     return retval;
01220 }
01221 
01222 KvpValue *
01223 kvp_value_new_boolean (gboolean value)
01224 {
01225     KvpValue * retval = g_new0 (KvpValue, 1);
01226     retval->type = KVP_TYPE_BOOLEAN;
01227     retval->value.gbool = value;
01228     return retval;
01229 }
01230 
01231 KvpValue *
01232 kvp_value_new_numeric (QofNumeric value)
01233 {
01234     KvpValue *retval = g_new0 (KvpValue, 1);
01235     retval->type = KVP_TYPE_NUMERIC;
01236     retval->value.numeric = value;
01237     return retval;
01238 }
01239 
01240 KvpValue *
01241 kvp_value_new_string (const gchar *value)
01242 {
01243     KvpValue *retval;
01244     if (!value)
01245         return NULL;
01246 
01247     retval = g_new0 (KvpValue, 1);
01248     retval->type = KVP_TYPE_STRING;
01249     retval->value.str = g_strdup (value);
01250     return retval;
01251 }
01252 
01253 KvpValue *
01254 kvp_value_new_guid (const GUID * value)
01255 {
01256     KvpValue *retval;
01257     if (!value)
01258         return NULL;
01259 
01260     retval = g_new0 (KvpValue, 1);
01261     retval->type = KVP_TYPE_GUID;
01262     retval->value.guid = g_new0 (GUID, 1);
01263     memcpy (retval->value.guid, value, sizeof (GUID));
01264     return retval;
01265 }
01266 
01267 KvpValue *
01268 kvp_value_new_time (QofTime *value)
01269 {
01270     KvpValue *retval = g_new0 (KvpValue, 1);
01271     retval->type = KVP_TYPE_TIME;
01272     retval->value.qt = value;
01273     return retval;
01274 }
01275 
01276 KvpValue *
01277 kvp_value_new_binary (gconstpointer value, guint64 datasize)
01278 {
01279     KvpValue *retval;
01280     if (!value)
01281         return NULL;
01282 
01283     retval = g_new0 (KvpValue, 1);
01284     retval->type = KVP_TYPE_BINARY;
01285     retval->value.binary.data = g_new0 (gpointer, datasize);
01286     retval->value.binary.datasize = datasize;
01287     memcpy (retval->value.binary.data, value, datasize);
01288     return retval;
01289 }
01290 
01291 KvpValue *
01292 kvp_value_new_binary_nc (gpointer value, guint64 datasize)
01293 {
01294     KvpValue *retval;
01295     if (!value)
01296         return NULL;
01297 
01298     retval = g_new0 (KvpValue, 1);
01299     retval->type = KVP_TYPE_BINARY;
01300     retval->value.binary.data = value;
01301     retval->value.binary.datasize = datasize;
01302     return retval;
01303 }
01304 
01305 KvpValue *
01306 kvp_value_new_glist (const GList * value)
01307 {
01308     KvpValue *retval;
01309     if (!value)
01310         return NULL;
01311 
01312     retval = g_new0 (KvpValue, 1);
01313     retval->type = KVP_TYPE_GLIST;
01314     retval->value.list = kvp_glist_copy (value);
01315     return retval;
01316 }
01317 
01318 KvpValue *
01319 kvp_value_new_glist_nc (GList * value)
01320 {
01321     KvpValue *retval;
01322     if (!value)
01323         return NULL;
01324 
01325     retval = g_new0 (KvpValue, 1);
01326     retval->type = KVP_TYPE_GLIST;
01327     retval->value.list = value;
01328     return retval;
01329 }
01330 
01331 KvpValue *
01332 kvp_value_new_frame (const KvpFrame * value)
01333 {
01334     KvpValue *retval;
01335     if (!value)
01336         return NULL;
01337 
01338     retval = g_new0 (KvpValue, 1);
01339     retval->type = KVP_TYPE_FRAME;
01340     retval->value.frame = kvp_frame_copy (value);
01341     return retval;
01342 }
01343 
01344 KvpValue *
01345 kvp_value_new_frame_nc (KvpFrame * value)
01346 {
01347     KvpValue *retval;
01348     if (!value)
01349         return NULL;
01350 
01351     retval = g_new0 (KvpValue, 1);
01352     retval->type = KVP_TYPE_FRAME;
01353     retval->value.frame = value;
01354     return retval;
01355 }
01356 
01357 void
01358 kvp_value_delete (KvpValue * value)
01359 {
01360     if (!value)
01361         return;
01362 
01363     switch (value->type)
01364     {
01365     case KVP_TYPE_STRING:
01366         g_free (value->value.str);
01367         break;
01368     case KVP_TYPE_GUID:
01369         g_free (value->value.guid);
01370         break;
01371     case KVP_TYPE_BINARY:
01372         g_free (value->value.binary.data);
01373         break;
01374     case KVP_TYPE_GLIST:
01375         kvp_glist_delete (value->value.list);
01376         break;
01377     case KVP_TYPE_FRAME:
01378         kvp_frame_delete (value->value.frame);
01379         break;
01380     case KVP_TYPE_BOOLEAN:
01381     case KVP_TYPE_GINT64:
01382     case KVP_TYPE_DOUBLE:
01383     case KVP_TYPE_NUMERIC:
01384     default:
01385         break;
01386     }
01387     g_free (value);
01388 }
01389 
01390 KvpValueType
01391 kvp_value_get_type (const KvpValue * value)
01392 {
01393     if (!value)
01394         return QOF_FATAL;
01395     return value->type;
01396 }
01397 
01398 gint64
01399 kvp_value_get_gint64 (const KvpValue * value)
01400 {
01401     if (!value)
01402         return 0;
01403     if (value->type == KVP_TYPE_GINT64)
01404         return value->value.int64;
01405     else
01406     {
01407         PERR (" value type %d does not match KVP_TYPE_GINT64",
01408             value->type);
01409         return 0;
01410     }
01411 }
01412 
01413 gdouble
01414 kvp_value_get_double (const KvpValue * value)
01415 {
01416     if (!value)
01417         return 0.0;
01418     if (value->type == KVP_TYPE_DOUBLE)
01419         return value->value.dbl;
01420     else
01421     {
01422         PERR (" value type %d does not match KVP_TYPE_DOUBLE",
01423             value->type);
01424         return 0.0;
01425     }
01426 }
01427 
01428 QofNumeric
01429 kvp_value_get_numeric (const KvpValue * value)
01430 {
01431     if (!value)
01432         return qof_numeric_zero ();
01433     if (value->type == KVP_TYPE_NUMERIC)
01434         return value->value.numeric;
01435     else
01436     {
01437         PERR (" value type %d does not match KVP_TYPE_NUMERIC",
01438             value->type);
01439         return qof_numeric_zero ();
01440     }
01441 }
01442 
01443 gchar *
01444 kvp_value_get_string (const KvpValue * value)
01445 {
01446     if (!value)
01447         return NULL;
01448     if (value->type == KVP_TYPE_STRING)
01449         return value->value.str;
01450     else
01451     {
01452         PERR (" value type %d does not match KVP_TYPE_STRING",
01453             value->type);
01454         return NULL;
01455     }
01456 }
01457 
01458 gboolean
01459 kvp_value_get_boolean (const KvpValue * value)
01460 {
01461     if (!value)
01462         return FALSE;
01463     if (value->type == KVP_TYPE_BOOLEAN)
01464         return value->value.gbool;
01465     else
01466     {
01467         PERR (" value type %d does not match KVP_TYPE_BOOLEAN",
01468             value->type);
01469         return FALSE;
01470     }
01471 }
01472 
01473 GUID *
01474 kvp_value_get_guid (const KvpValue * value)
01475 {
01476     if (!value)
01477         return NULL;
01478     if (value->type == KVP_TYPE_GUID)
01479         return value->value.guid;
01480     else
01481     {
01482         PERR (" value type %d does not match KVP_TYPE_GUID",
01483             value->type);
01484         return NULL;
01485     }
01486 }
01487 
01488 QofTime*
01489 kvp_value_get_time (const KvpValue * value)
01490 {
01491     if (!value)
01492         return NULL;
01493     if (value->type == KVP_TYPE_TIME)
01494         return value->value.qt;
01495     else
01496     {
01497         PERR (" value type %d does not match KVP_TYPE_TIME",
01498             value->type);
01499         return NULL;
01500     }
01501 }
01502 
01503 void *
01504 kvp_value_get_binary (const KvpValue * value, guint64 * size_return)
01505 {
01506     if (!value)
01507     {
01508         if (size_return)
01509             *size_return = 0;
01510         PERR (" no size specified");
01511         return NULL;
01512     }
01513 
01514     if (value->type == KVP_TYPE_BINARY)
01515     {
01516         if (size_return)
01517             *size_return = value->value.binary.datasize;
01518         return value->value.binary.data;
01519     }
01520     else
01521     {
01522         if (size_return)
01523             *size_return = 0;
01524         PERR (" value type %d does not match KVP_TYPE_BINARY",
01525             value->type);
01526         return NULL;
01527     }
01528 }
01529 
01530 GList *
01531 kvp_value_get_glist (const KvpValue * value)
01532 {
01533     if (!value)
01534         return NULL;
01535     if (value->type == KVP_TYPE_GLIST)
01536         return value->value.list;
01537     else
01538     {
01539         PERR (" value type %d does not match KVP_TYPE_GLIST",
01540             value->type);
01541         return NULL;
01542     }
01543 }
01544 
01545 KvpFrame *
01546 kvp_value_get_frame (const KvpValue * value)
01547 {
01548     if (!value)
01549         return NULL;
01550     if (value->type == KVP_TYPE_FRAME)
01551         return value->value.frame;
01552     else
01553     {
01554         PERR (" value type %d does not match KVP_TYPE_FRAME",
01555             value->type);
01556         return NULL;
01557     }
01558 }
01559 
01560 KvpFrame *
01561 kvp_value_replace_frame_nc (KvpValue * value, KvpFrame * newframe)
01562 {
01563     KvpFrame *oldframe;
01564     if (!value)
01565         return NULL;
01566     if (KVP_TYPE_FRAME != value->type)
01567     {
01568         PERR (" value type %d does not match KVP_TYPE_FRAME",
01569             value->type);
01570         return NULL;
01571     }
01572     oldframe = value->value.frame;
01573     value->value.frame = newframe;
01574     return oldframe;
01575 }
01576 
01577 GList *
01578 kvp_value_replace_glist_nc (KvpValue * value, GList * newlist)
01579 {
01580     GList *oldlist;
01581     if (!value)
01582         return NULL;
01583     if (KVP_TYPE_GLIST != value->type)
01584     {
01585         PERR (" value type %d does not match KVP_TYPE_GLIST",
01586             value->type);
01587         return NULL;
01588     }
01589 
01590     oldlist = value->value.list;
01591     value->value.list = newlist;
01592     return oldlist;
01593 }
01594 
01595 /* manipulators */
01596 
01597 KvpValue *
01598 kvp_value_copy (const KvpValue * value)
01599 {
01600     if (!value)
01601         return NULL;
01602 
01603     switch (value->type)
01604     {
01605     case KVP_TYPE_GINT64:
01606         return kvp_value_new_gint64 (value->value.int64);
01607         break;
01608     case KVP_TYPE_DOUBLE:
01609         return kvp_value_new_double (value->value.dbl);
01610         break;
01611     case KVP_TYPE_NUMERIC:
01612         return kvp_value_new_numeric (value->value.numeric);
01613         break;
01614     case KVP_TYPE_STRING:
01615         return kvp_value_new_string (value->value.str);
01616         break;
01617     case KVP_TYPE_GUID:
01618         return kvp_value_new_guid (value->value.guid);
01619         break;
01620     case KVP_TYPE_BOOLEAN:
01621         return NULL;
01622         return kvp_value_new_boolean (value->value.gbool);
01623         break;
01624     case KVP_TYPE_TIME :
01625         return kvp_value_new_time (value->value.qt);
01626         break;
01627     case KVP_TYPE_BINARY:
01628         return kvp_value_new_binary (value->value.binary.data,
01629             value->value.binary.datasize);
01630         break;
01631     case KVP_TYPE_GLIST:
01632         return kvp_value_new_glist (value->value.list);
01633         break;
01634     case KVP_TYPE_FRAME:
01635         return kvp_value_new_frame (value->value.frame);
01636         break;
01637     }
01638     return NULL;
01639 }
01640 
01641 void
01642 kvp_frame_for_each_slot (KvpFrame * f, KvpValueForeachCB proc, gpointer data)
01643 {
01644     if (!f)
01645         return;
01646     if (!proc)
01647         return;
01648     if (!(f->hash))
01649         return;
01650     g_hash_table_foreach (f->hash, (GHFunc) proc, data);
01651 }
01652 
01653 gint
01654 kvp_value_compare (const KvpValue * kva, const KvpValue * kvb)
01655 {
01656     if (kva == kvb)
01657         return 0;
01658     /* nothing is always less than something */
01659     if (!kva && kvb)
01660         return -1;
01661     if (kva && !kvb)
01662         return 1;
01663 
01664     if (kva->type < kvb->type)
01665         return -1;
01666     if (kva->type > kvb->type)
01667         return 1;
01668 
01669     switch (kva->type)
01670     {
01671     case KVP_TYPE_GINT64:
01672         if (kva->value.int64 < kvb->value.int64)
01673             return -1;
01674         if (kva->value.int64 > kvb->value.int64)
01675             return 1;
01676         return 0;
01677         break;
01678     case KVP_TYPE_DOUBLE:
01679         return qof_util_double_compare (kva->value.dbl, kvb->value.dbl);
01680         break;
01681     case KVP_TYPE_NUMERIC:
01682         return qof_numeric_compare (kva->value.numeric,
01683             kvb->value.numeric);
01684         break;
01685     case KVP_TYPE_STRING:
01686         return strcmp (kva->value.str, kvb->value.str);
01687         break;
01688     case KVP_TYPE_GUID:
01689         return guid_compare (kva->value.guid, kvb->value.guid);
01690         break;
01691     case KVP_TYPE_BOOLEAN:
01692     {
01693         /* true > false */
01694         if (kva->value.gbool != kvb->value.gbool)
01695             return (kva->value.gbool) ? 1 : -1;
01696         return 0;
01697         break;
01698     }
01699     case KVP_TYPE_TIME :
01700         return qof_time_cmp (kva->value.qt, kvb->value.qt);
01701         break;
01702     case KVP_TYPE_BINARY:
01703         if (kva->value.binary.datasize < kvb->value.binary.datasize)
01704             return -1;
01705         if (kva->value.binary.datasize > kvb->value.binary.datasize)
01706             return 1;
01707         return memcmp (kva->value.binary.data,
01708             kvb->value.binary.data, kva->value.binary.datasize);
01709         break;
01710     case KVP_TYPE_GLIST:
01711         return kvp_glist_compare (kva->value.list, kvb->value.list);
01712         break;
01713     case KVP_TYPE_FRAME:
01714         return kvp_frame_compare (kva->value.frame, kvb->value.frame);
01715         break;
01716     }
01717     return 0;
01718 }
01719 
01720 typedef struct
01721 {
01722     gint compare;
01723     KvpFrame *other_frame;
01724 } KvpFrameCompare;
01725 
01726 static void
01727 kvp_frame_compare_helper (const gchar *key, KvpValue * val, gpointer data)
01728 {
01729     KvpFrameCompare *status = (KvpFrameCompare *) data;
01730     if (status->compare == 0)
01731     {
01732         KvpFrame *other_frame = status->other_frame;
01733         KvpValue *other_val = kvp_frame_get_slot (other_frame, key);
01734 
01735         if (other_val)
01736             status->compare = kvp_value_compare (val, other_val);
01737         else
01738             status->compare = 1;
01739     }
01740 }
01741 
01742 gint
01743 kvp_frame_compare (const KvpFrame * fa, const KvpFrame * fb)
01744 {
01745     KvpFrameCompare status;
01746 
01747     if (fa == fb)
01748         return 0;
01749     /* nothing is always less than something */
01750     if (!fa && fb)
01751         return -1;
01752     if (fa && !fb)
01753         return 1;
01754 
01755     /* nothing is always less than something */
01756     if (!fa->hash && fb->hash)
01757         return -1;
01758     if (fa->hash && !fb->hash)
01759         return 1;
01760 
01761     status.compare = 0;
01762     status.other_frame = (KvpFrame *) fb;
01763 
01764     kvp_frame_for_each_slot ((KvpFrame *) fa, kvp_frame_compare_helper,
01765         &status);
01766 
01767     if (status.compare != 0)
01768         return status.compare;
01769 
01770     status.other_frame = (KvpFrame *) fa;
01771 
01772     kvp_frame_for_each_slot ((KvpFrame *) fb, kvp_frame_compare_helper,
01773         &status);
01774 
01775     return (-status.compare);
01776 }
01777 
01778 /* FIXME: genuine binary content cannot be made a string reliably. */
01779 gchar *
01780 binary_to_string (gconstpointer data, guint32 size)
01781 {
01782     GString *output;
01783     guint32 i;
01784     guchar *data_str = (guchar *) data;
01785 
01786     output = g_string_sized_new (size * sizeof (gchar));
01787 
01788     for (i = 0; i < size; i++)
01789     {
01790         g_string_append_printf (output, "%02x",
01791             (guint32) (data_str[i]));
01792     }
01793 
01794     return output->str;
01795 }
01796 
01797 gchar *
01798 kvp_value_glist_to_string (const GList * list)
01799 {
01800     gchar *tmp1;
01801     gchar *tmp2;
01802     const GList *cursor;
01803 
01804     tmp1 = g_strdup_printf ("[ ");
01805 
01806     for (cursor = list; cursor; cursor = cursor->next)
01807     {
01808         gchar *tmp3;
01809 
01810         tmp3 = kvp_value_to_string ((KvpValue *) cursor->data);
01811         tmp2 = g_strdup_printf ("%s %s,", tmp1, tmp3 ? tmp3 : "");
01812         g_free (tmp1);
01813         g_free (tmp3);
01814         tmp1 = tmp2;
01815     }
01816 
01817     tmp2 = g_strdup_printf ("%s ]", tmp1);
01818     g_free (tmp1);
01819 
01820     return tmp2;
01821 }
01822 
01823 static void
01824 kvp_frame_to_bare_string_helper (gpointer key __attribute__ ((unused)), 
01825     gpointer value, gpointer data)
01826 {
01827     gchar **str = (gchar **) data;
01828     *str =
01829         g_strdup_printf ("%s",
01830         kvp_value_to_bare_string ((KvpValue *) value));
01831 }
01832 
01833 gchar *
01834 kvp_value_to_bare_string (const KvpValue * val)
01835 {
01836     gchar *tmp1;
01837     gchar *tmp2;
01838     const gchar *ctmp;
01839 
01840     g_return_val_if_fail (val, NULL);
01841     tmp1 = g_strdup ("");
01842     switch (kvp_value_get_type (val))
01843     {
01844         case KVP_TYPE_GINT64:
01845         {
01846             return g_strdup_printf ("%" G_GINT64_FORMAT,
01847                 kvp_value_get_gint64 (val));
01848             break;
01849         }
01850         case KVP_TYPE_DOUBLE:
01851         {
01852             return g_strdup_printf ("(%g)", kvp_value_get_double (val));
01853             break;
01854         }
01855         case KVP_TYPE_NUMERIC:
01856         {
01857             tmp1 = qof_numeric_to_string (kvp_value_get_numeric (val));
01858             tmp2 = g_strdup_printf ("%s", tmp1 ? tmp1 : "");
01859             g_free (tmp1);
01860             return tmp2;
01861             break;
01862         }
01863         case KVP_TYPE_STRING:
01864         {
01865             tmp1 = kvp_value_get_string (val);
01866             return g_strdup_printf ("%s", tmp1 ? tmp1 : "");
01867             break;
01868         }
01869         case KVP_TYPE_GUID:
01870         {
01871             ctmp = guid_to_string (kvp_value_get_guid (val));
01872             tmp2 = g_strdup_printf ("%s", ctmp ? ctmp : "");
01873             return tmp2;
01874             break;
01875         }
01876         case KVP_TYPE_BOOLEAN :
01877             return (kvp_value_get_boolean (val)) ? "TRUE" : "FALSE";
01878         case KVP_TYPE_BINARY:
01879         {
01880             guint64 len;
01881             gpointer data;
01882             data = kvp_value_get_binary (val, &len);
01883             tmp1 = binary_to_string (data, len);
01884             return g_strdup_printf ("%s", tmp1 ? tmp1 : "");
01885             break;
01886         }
01887         case KVP_TYPE_GLIST:
01888         /* borked. kvp_value_glist_to_string is a debug fcn */
01889         {
01890             tmp1 = kvp_value_glist_to_string (kvp_value_get_glist (val));
01891             tmp2 = g_strdup_printf ("%s", tmp1 ? tmp1 : "");
01892             g_free (tmp1);
01893             return tmp2;
01894             break;
01895         }
01896         case KVP_TYPE_FRAME:
01897         {
01898             KvpFrame *frame;
01899 
01900             frame = kvp_value_get_frame (val);
01901             if (frame->hash)
01902             {
01903                 tmp1 = g_strdup ("");
01904                 g_hash_table_foreach (frame->hash,
01905                     kvp_frame_to_bare_string_helper, &tmp1);
01906             }
01907             return tmp1;
01908             break;
01909         }
01910         default:
01911             return g_strdup_printf (" ");
01912             break;
01913     }
01914 }
01915 
01916 gchar *
01917 kvp_value_to_string (const KvpValue * val)
01918 {
01919     gchar *tmp1;
01920     gchar *tmp2;
01921     const gchar *ctmp;
01922 
01923     g_return_val_if_fail (val, NULL);
01924 
01925     switch (kvp_value_get_type (val))
01926     {
01927         case KVP_TYPE_GINT64:
01928         {
01929             return g_strdup_printf ("KVP_VALUE_GINT64(%" G_GINT64_FORMAT ")",
01930                 kvp_value_get_gint64 (val));
01931             break;
01932         }
01933         case KVP_TYPE_DOUBLE:
01934         {
01935             return g_strdup_printf ("KVP_VALUE_DOUBLE(%g)",
01936                 kvp_value_get_double (val));
01937             break;
01938         }
01939         case KVP_TYPE_NUMERIC:
01940         {
01941             tmp1 = qof_numeric_to_string (kvp_value_get_numeric (val));
01942             tmp2 = g_strdup_printf ("KVP_VALUE_NUMERIC(%s)", tmp1 ? tmp1 : "");
01943             g_free (tmp1);
01944             return tmp2;
01945             break;
01946         }
01947         case KVP_TYPE_STRING:
01948         {
01949             tmp1 = kvp_value_get_string (val);
01950             return g_strdup_printf ("KVP_VALUE_STRING(%s)", tmp1 ? tmp1 : "");
01951             break;
01952         }
01953         case KVP_TYPE_GUID:
01954         {
01955             /* THREAD-UNSAFE */
01956             ctmp = guid_to_string (kvp_value_get_guid (val));
01957             tmp2 = g_strdup_printf ("KVP_VALUE_GUID(%s)", ctmp ? ctmp : "");
01958             return tmp2;
01959             break;
01960         }
01961         case KVP_TYPE_BINARY:
01962         {
01963             guint64 len;
01964             gpointer data;
01965             data = kvp_value_get_binary (val, &len);
01966             tmp1 = binary_to_string (data, len);
01967             return g_strdup_printf ("KVP_VALUE_BINARY(%s)",
01968                 tmp1 ? tmp1 : "");
01969             break;
01970         }
01971         case KVP_TYPE_GLIST:
01972         {
01973             tmp1 = kvp_value_glist_to_string (kvp_value_get_glist (val));
01974             tmp2 = g_strdup_printf ("KVP_VALUE_GLIST(%s)", tmp1 ? tmp1 : "");
01975             g_free (tmp1);
01976             return tmp2;
01977             break;
01978         }
01979         case KVP_TYPE_FRAME:
01980         {
01981             tmp1 = kvp_frame_to_string (kvp_value_get_frame (val));
01982             tmp2 = g_strdup_printf ("KVP_VALUE_FRAME(%s)", tmp1 ? tmp1 : "");
01983             g_free (tmp1);
01984             return tmp2;
01985             break;
01986         }
01987         default:
01988             return g_strdup_printf (" ");
01989             break;
01990     }
01991 }
01992 
01993 static void
01994 kvp_frame_to_string_helper (gpointer key, gpointer value, gpointer data)
01995 {
01996     gchar *tmp_val;
01997     gchar **str = (gchar **) data;
01998     gchar *old_data = *str;
01999 
02000     tmp_val = kvp_value_to_string ((KvpValue *) value);
02001 
02002     *str = g_strdup_printf ("%s    %s => %s,\n",
02003         *str ? *str : "", key ? (gchar *) key : "", tmp_val ? tmp_val : "");
02004 
02005     g_free (old_data);
02006     g_free (tmp_val);
02007 }
02008 
02009 gchar *
02010 kvp_frame_to_string (const KvpFrame * frame)
02011 {
02012     gchar *tmp1;
02013 
02014     g_return_val_if_fail (frame != NULL, NULL);
02015 
02016     tmp1 = g_strdup_printf ("{\n");
02017 
02018     if (frame->hash)
02019         g_hash_table_foreach (frame->hash, kvp_frame_to_string_helper,
02020             &tmp1);
02021     {
02022         gchar *tmp2;
02023         tmp2 = g_strdup_printf ("%s}\n", tmp1);
02024         g_free (tmp1);
02025         tmp1 = tmp2;
02026     }
02027 
02028     return tmp1;
02029 }
02030 
02031 GHashTable *
02032 kvp_frame_get_hash (const KvpFrame * frame)
02033 {
02034     g_return_val_if_fail (frame != NULL, NULL);
02035     return frame->hash;
02036 }
02037 
02038 /* ========================== END OF FILE ======================= */