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