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

Generated on Fri May 12 17:57:20 2006 for QOF by  doxygen 1.4.4