kvp_frame.c

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

Generated on Fri Sep 15 14:24:56 2006 for QOF by  doxygen 1.4.7