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

Generated on Fri Sep 1 15:09:02 2006 for QOF by  doxygen 1.4.7