kvpframe.c

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

Generated on Thu Jan 31 22:50:25 2008 for QOF by  doxygen 1.5.4