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