1 /********************************************************************
2 * kvpframe.c -- Implements a key-value frame system *
3 * Copyright (C) 2000 Bill Gribble *
4 * Copyright (C) 2001,2003 Linas Vepstas <linas@linas.org> *
5 * Copyright (c) 2006-2008 Neil Williams <linux@codehelp.co.uk> *
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License as *
9 * published by the Free Software Foundation; either version 2 of *
10 * the License, or (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License*
18 * along with this program; if not, contact: *
19 * *
20 * Free Software Foundation Voice: +1-617-542-5942 *
21 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22 * Boston, MA 02110-1301, USA gnu@gnu.org *
23 * *
24 ********************************************************************/
25
26 #include "config.h"
27
28 #include <glib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include "qof.h"
33
34 /* Note that we keep the keys for this hash table in a GCache
35 * (qof_util_string_cache), as it is very likely we will see the
36 * same keys over and over again */
37
38 struct _KvpFrame
39 {
40 GHashTable *hash;
41 };
42
43 typedef struct
44 {
45 gpointer data;
46 gint64 datasize;
47 } KvpValueBinaryData;
48
49 struct _KvpValue
50 {
51 KvpValueType type;
52 union
53 {
54 gint64 int64;
55 gdouble dbl;
56 QofNumeric numeric;
57 gchar *str;
58 GUID *guid;
59 QofTime *qt;
60 gboolean gbool; /* since 0.7.2 */
61 KvpValueBinaryData binary;
62 GList *list;
63 KvpFrame *frame;
64 } value;
65 };
66
67 /* This static indicates the debugging module that this .o belongs to. */
68 static QofLogModule log_module = QOF_MOD_KVP;
69
70 /* *******************************************************************
71 * KvpFrame functions
72 ********************************************************************/
73
74 static guint
kvp_hash_func(gconstpointer v)75 kvp_hash_func (gconstpointer v)
76 {
77 return g_str_hash (v);
78 }
79
80 static gint
kvp_comp_func(gconstpointer v,gconstpointer v2)81 kvp_comp_func (gconstpointer v, gconstpointer v2)
82 {
83 return g_str_equal (v, v2);
84 }
85
86 static gboolean
init_frame_body_if_needed(KvpFrame * f)87 init_frame_body_if_needed (KvpFrame * f)
88 {
89 if (!f->hash)
90 {
91 f->hash = g_hash_table_new (&kvp_hash_func, &kvp_comp_func);
92 }
93 return (f->hash != NULL);
94 }
95
96 KvpFrame *
kvp_frame_new(void)97 kvp_frame_new (void)
98 {
99 KvpFrame *retval = g_new0 (KvpFrame, 1);
100
101 /* Save space until the frame is actually used */
102 retval->hash = NULL;
103 return retval;
104 }
105
106 static void
kvp_frame_delete_worker(gpointer key,gpointer value,gpointer user_data)107 kvp_frame_delete_worker (gpointer key, gpointer value,
108 gpointer user_data __attribute__ ((unused)))
109 {
110 qof_util_string_cache_remove (key);
111 kvp_value_delete ((KvpValue *) value);
112 }
113
114 void
kvp_frame_delete(KvpFrame * frame)115 kvp_frame_delete (KvpFrame * frame)
116 {
117 if (!frame)
118 return;
119
120 if (frame->hash)
121 {
122 /* free any allocated resource for frame or its children */
123 g_hash_table_foreach (frame->hash, &kvp_frame_delete_worker,
124 (gpointer) frame);
125
126 /* delete the hash table */
127 g_hash_table_destroy (frame->hash);
128 frame->hash = NULL;
129 }
130 g_free (frame);
131 }
132
133 gboolean
kvp_frame_is_empty(KvpFrame * frame)134 kvp_frame_is_empty (KvpFrame * frame)
135 {
136 if (!frame)
137 return TRUE;
138 if (!frame->hash)
139 return TRUE;
140 return FALSE;
141 }
142
143 static void
kvp_frame_copy_worker(gpointer key,gpointer value,gpointer user_data)144 kvp_frame_copy_worker (gpointer key, gpointer value, gpointer user_data)
145 {
146 KvpFrame *dest = (KvpFrame *) user_data;
147 g_hash_table_insert (dest->hash,
148 qof_util_string_cache_insert (key),
149 (gpointer) kvp_value_copy (value));
150 }
151
152 KvpFrame *
kvp_frame_copy(const KvpFrame * frame)153 kvp_frame_copy (const KvpFrame * frame)
154 {
155 KvpFrame *retval = kvp_frame_new ();
156
157 if (!frame)
158 return retval;
159
160 if (frame->hash)
161 {
162 if (!init_frame_body_if_needed (retval))
163 return (NULL);
164 g_hash_table_foreach (frame->hash,
165 &kvp_frame_copy_worker, (gpointer) retval);
166 }
167 return retval;
168 }
169
170 /* Replace the old value with the new value. Return the old value.
171 * Passing in a null value into this routine has the effect of
172 * removing the key from the KVP tree.
173 */
174 KvpValue *
kvp_frame_replace_slot_nc(KvpFrame * frame,const gchar * slot,KvpValue * new_value)175 kvp_frame_replace_slot_nc (KvpFrame * frame, const gchar *slot,
176 KvpValue * new_value)
177 {
178 gpointer orig_key;
179 gpointer orig_value = NULL;
180 int key_exists;
181
182 if (!frame || !slot)
183 return NULL;
184 if (!init_frame_body_if_needed (frame))
185 return NULL; /* Error ... */
186
187 key_exists = g_hash_table_lookup_extended (frame->hash, slot,
188 &orig_key, &orig_value);
189 if (key_exists)
190 {
191 g_hash_table_remove (frame->hash, slot);
192 qof_util_string_cache_remove (orig_key);
193 }
194 else
195 orig_value = NULL;
196 if (new_value)
197 g_hash_table_insert (frame->hash,
198 qof_util_string_cache_insert ((gpointer) slot), new_value);
199 return (KvpValue *) orig_value;
200 }
201
202 /* Passing in a null value into this routine has the effect
203 * of deleting the old value stored at this slot.
204 */
205 static inline void
kvp_frame_set_slot_destructively(KvpFrame * frame,const gchar * slot,KvpValue * new_value)206 kvp_frame_set_slot_destructively (KvpFrame * frame, const gchar *slot,
207 KvpValue * new_value)
208 {
209 KvpValue *old_value;
210 old_value = kvp_frame_replace_slot_nc (frame, slot, new_value);
211 kvp_value_delete (old_value);
212 }
213
214 /* ============================================================ */
215 /* Get the named frame, or create it if it doesn't exist.
216 * gcc -O3 should inline it. It performs no error checks,
217 * the caller is responsible of passing good keys and frames.
218 */
219 static inline KvpFrame *
get_or_make(KvpFrame * fr,const gchar * key)220 get_or_make (KvpFrame * fr, const gchar *key)
221 {
222 KvpFrame *next_frame;
223 KvpValue *value;
224
225 value = kvp_frame_get_slot (fr, key);
226 if (value)
227 next_frame = kvp_value_get_frame (value);
228 else
229 {
230 next_frame = kvp_frame_new ();
231 kvp_frame_set_slot_nc (fr, key,
232 kvp_value_new_frame_nc (next_frame));
233 }
234 return next_frame;
235 }
236
237 /* Get pointer to last frame in path. If the path doesn't exist,
238 * it is created. The string stored in keypath will be hopelessly
239 * mangled .
240 */
241 static KvpFrame *
kvp_frame_get_frame_slash_trash(KvpFrame * frame,gchar * key_path)242 kvp_frame_get_frame_slash_trash (KvpFrame * frame, gchar *key_path)
243 {
244 gchar *key, *next;
245 if (!frame || !key_path)
246 return frame;
247
248 key = key_path;
249 key--;
250
251 while (key)
252 {
253 key++;
254 while ('/' == *key)
255 key++;
256 if (0x0 == *key)
257 break; /* trailing slash */
258 next = strchr (key, '/');
259 if (next)
260 *next = 0x0;
261
262 frame = get_or_make (frame, key);
263 if (!frame)
264 break; /* error - should never happen */
265
266 key = next;
267 }
268 return frame;
269 }
270
271 /* ============================================================ */
272 /* Get pointer to last frame in path, or NULL if the path doesn't
273 * exist. The string stored in keypath will be hopelessly mangled .
274 */
275 static inline const KvpFrame *
kvp_frame_get_frame_or_null_slash_trash(const KvpFrame * frame,gchar * key_path)276 kvp_frame_get_frame_or_null_slash_trash (const KvpFrame * frame,
277 gchar *key_path)
278 {
279 KvpValue *value;
280 gchar *key, *next;
281 if (!frame || !key_path)
282 return NULL;
283
284 key = key_path;
285 key--;
286
287 while (key)
288 {
289 key++;
290 while ('/' == *key)
291 key++;
292 if (0x0 == *key)
293 break; /* trailing slash */
294 next = strchr (key, '/');
295 if (next)
296 *next = 0x0;
297
298 value = kvp_frame_get_slot (frame, key);
299 if (!value)
300 return NULL;
301 frame = kvp_value_get_frame (value);
302 if (!frame)
303 return NULL;
304
305 key = next;
306 }
307 return frame;
308 }
309
310 /* Return pointer to last frame in path, and also store the
311 * last dangling part of path in 'end_key'. If path doesn't
312 * exist, it is created.
313 */
314
315 static inline KvpFrame *
get_trailer_make(KvpFrame * frame,const gchar * key_path,gchar ** end_key)316 get_trailer_make (KvpFrame * frame, const gchar *key_path,
317 gchar **end_key)
318 {
319 gchar *last_key;
320
321 if (!frame || !key_path || (0 == key_path[0]))
322 return NULL;
323
324 last_key = strrchr (key_path, '/');
325 if (NULL == last_key)
326 last_key = (gchar *) key_path;
327 else if (last_key == key_path)
328 last_key++;
329 else if (0 == last_key[1])
330 return NULL;
331 else
332 {
333 gchar *root, *lkey;
334 root = g_strdup (key_path);
335 lkey = strrchr (root, '/');
336 *lkey = 0;
337 frame = kvp_frame_get_frame_slash_trash (frame, root);
338 g_free (root);
339 last_key++;
340 }
341
342 *end_key = last_key;
343 return frame;
344 }
345
346
347 /* Return pointer to last frame in path, or NULL if the path
348 * doesn't exist. Also store the last dangling part of path
349 * in 'end_key'.
350 */
351
352 static inline const KvpFrame *
get_trailer_or_null(const KvpFrame * frame,const gchar * key_path,gchar ** end_key)353 get_trailer_or_null (const KvpFrame * frame, const gchar *key_path,
354 gchar **end_key)
355 {
356 gchar *last_key;
357
358 if (!frame || !key_path || (0 == key_path[0]))
359 return NULL;
360
361 last_key = strrchr (key_path, '/');
362 if (NULL == last_key)
363 last_key = (gchar *) key_path;
364 else if (last_key == key_path)
365 last_key++;
366 else if (0 == last_key[1])
367 return NULL;
368 else
369 {
370 gchar *root, *lkey;
371 root = g_strdup (key_path);
372 lkey = strrchr (root, '/');
373 *lkey = 0;
374 frame = kvp_frame_get_frame_or_null_slash_trash (frame, root);
375 g_free (root);
376
377 last_key++;
378 }
379
380 *end_key = last_key;
381 return frame;
382 }
383
384 /* ============================================================ */
385
386 void
kvp_frame_set_gint64(KvpFrame * frame,const gchar * path,gint64 ival)387 kvp_frame_set_gint64 (KvpFrame * frame, const gchar *path, gint64 ival)
388 {
389 KvpValue *value;
390 value = kvp_value_new_gint64 (ival);
391 frame = kvp_frame_set_value_nc (frame, path, value);
392 if (!frame)
393 kvp_value_delete (value);
394 }
395
396 void
kvp_frame_set_double(KvpFrame * frame,const gchar * path,gdouble dval)397 kvp_frame_set_double (KvpFrame * frame, const gchar *path, gdouble dval)
398 {
399 KvpValue *value;
400 value = kvp_value_new_double (dval);
401 frame = kvp_frame_set_value_nc (frame, path, value);
402 if (!frame)
403 kvp_value_delete (value);
404 }
405
406 void
kvp_frame_set_time(KvpFrame * frame,const gchar * path,QofTime * qt)407 kvp_frame_set_time (KvpFrame * frame, const gchar *path, QofTime *qt)
408 {
409 KvpValue *value;
410 value = kvp_value_new_time (qt);
411 frame = kvp_frame_set_value_nc (frame, path, value);
412 if (!frame)
413 kvp_value_delete (value);
414 }
415
416 void
kvp_frame_set_numeric(KvpFrame * frame,const gchar * path,QofNumeric nval)417 kvp_frame_set_numeric (KvpFrame * frame, const gchar *path,
418 QofNumeric nval)
419 {
420 KvpValue *value;
421 value = kvp_value_new_numeric (nval);
422 frame = kvp_frame_set_value_nc (frame, path, value);
423 if (!frame)
424 kvp_value_delete (value);
425 }
426
427 void
kvp_frame_set_boolean(KvpFrame * frame,const gchar * path,gboolean val)428 kvp_frame_set_boolean (KvpFrame * frame, const gchar * path,
429 gboolean val)
430 {
431 KvpValue * value;
432 value = kvp_value_new_boolean (val);
433 frame = kvp_frame_set_value_nc (frame, path, value);
434 if (!frame)
435 kvp_value_delete (value);
436 }
437
438 void
kvp_frame_set_string(KvpFrame * frame,const gchar * path,const gchar * str)439 kvp_frame_set_string (KvpFrame * frame, const gchar *path,
440 const gchar *str)
441 {
442 KvpValue *value;
443 value = kvp_value_new_string (str);
444 frame = kvp_frame_set_value_nc (frame, path, value);
445 if (!frame)
446 kvp_value_delete (value);
447 }
448
449 void
kvp_frame_set_guid(KvpFrame * frame,const gchar * path,const GUID * guid)450 kvp_frame_set_guid (KvpFrame * frame, const gchar *path,
451 const GUID * guid)
452 {
453 KvpValue *value;
454 value = kvp_value_new_guid (guid);
455 frame = kvp_frame_set_value_nc (frame, path, value);
456 if (!frame)
457 kvp_value_delete (value);
458 }
459
460 void
kvp_frame_set_frame(KvpFrame * frame,const gchar * path,KvpFrame * fr)461 kvp_frame_set_frame (KvpFrame * frame, const gchar *path, KvpFrame * fr)
462 {
463 KvpValue *value;
464 value = kvp_value_new_frame (fr);
465 frame = kvp_frame_set_value_nc (frame, path, value);
466 if (!frame)
467 kvp_value_delete (value);
468 }
469
470 void
kvp_frame_set_frame_nc(KvpFrame * frame,const gchar * path,KvpFrame * fr)471 kvp_frame_set_frame_nc (KvpFrame * frame, const gchar *path, KvpFrame * fr)
472 {
473 KvpValue *value;
474 value = kvp_value_new_frame_nc (fr);
475 frame = kvp_frame_set_value_nc (frame, path, value);
476 if (!frame)
477 kvp_value_delete (value);
478 }
479
480 /* ============================================================ */
481
482 KvpFrame *
kvp_frame_set_value_nc(KvpFrame * frame,const gchar * key_path,KvpValue * value)483 kvp_frame_set_value_nc (KvpFrame * frame, const gchar *key_path,
484 KvpValue * value)
485 {
486 gchar *last_key;
487
488 frame = get_trailer_make (frame, key_path, &last_key);
489 if (!frame)
490 return NULL;
491 kvp_frame_set_slot_destructively (frame, last_key, value);
492 return frame;
493 }
494
495 KvpFrame *
kvp_frame_set_value(KvpFrame * frame,const gchar * key_path,const KvpValue * value)496 kvp_frame_set_value (KvpFrame * frame, const gchar *key_path,
497 const KvpValue * value)
498 {
499 KvpValue *new_value = NULL;
500 gchar *last_key;
501
502 frame = get_trailer_make (frame, key_path, &last_key);
503 if (!frame)
504 return NULL;
505
506 if (value)
507 new_value = kvp_value_copy (value);
508 kvp_frame_set_slot_destructively (frame, last_key, new_value);
509 return frame;
510 }
511
512 KvpValue *
kvp_frame_replace_value_nc(KvpFrame * frame,const gchar * key_path,KvpValue * new_value)513 kvp_frame_replace_value_nc (KvpFrame * frame, const gchar *key_path,
514 KvpValue * new_value)
515 {
516 KvpValue *old_value;
517 gchar *last_key;
518
519 last_key = NULL;
520 if (new_value)
521 frame = get_trailer_make (frame, key_path, &last_key);
522 else
523 frame =
524 (KvpFrame *) get_trailer_or_null (frame, key_path, &last_key);
525 if (!frame)
526 return NULL;
527
528 old_value = kvp_frame_replace_slot_nc (frame, last_key, new_value);
529 return old_value;
530 }
531
532 /* ============================================================ */
533
534 KvpFrame *
kvp_frame_add_value_nc(KvpFrame * frame,const gchar * path,KvpValue * value)535 kvp_frame_add_value_nc (KvpFrame * frame, const gchar *path,
536 KvpValue * value)
537 {
538 gchar *key = NULL;
539 KvpValue *oldvalue;
540
541 frame = (KvpFrame *) get_trailer_or_null (frame, path, &key);
542 oldvalue = kvp_frame_get_slot (frame, key);
543
544 ENTER ("old frame=%s", kvp_frame_to_string (frame));
545 if (oldvalue)
546 {
547 /* If already a glist here, just append */
548 if (KVP_TYPE_GLIST == oldvalue->type)
549 {
550 GList *vlist = oldvalue->value.list;
551 vlist = g_list_append (vlist, value);
552 oldvalue->value.list = vlist;
553 }
554 else
555 /* If some other value, convert it to a glist */
556 {
557 KvpValue *klist;
558 GList *vlist = NULL;
559
560 vlist = g_list_append (vlist, oldvalue);
561 vlist = g_list_append (vlist, value);
562 klist = kvp_value_new_glist_nc (vlist);
563
564 kvp_frame_replace_slot_nc (frame, key, klist);
565 }
566 LEAVE ("new frame=%s", kvp_frame_to_string (frame));
567 return frame;
568 }
569
570 /* Hmm, if we are here, the path doesn't exist. We need to
571 * create the path, add the value to it. */
572 frame = kvp_frame_set_value_nc (frame, path, value);
573 LEAVE ("new frame=%s", kvp_frame_to_string (frame));
574 return frame;
575 }
576
577 KvpFrame *
kvp_frame_add_value(KvpFrame * frame,const gchar * path,KvpValue * value)578 kvp_frame_add_value (KvpFrame * frame, const gchar *path, KvpValue * value)
579 {
580 value = kvp_value_copy (value);
581 frame = kvp_frame_add_value_nc (frame, path, value);
582 if (!frame)
583 kvp_value_delete (value);
584 return frame;
585 }
586
587 void
kvp_frame_add_gint64(KvpFrame * frame,const gchar * path,gint64 ival)588 kvp_frame_add_gint64 (KvpFrame * frame, const gchar *path, gint64 ival)
589 {
590 KvpValue *value;
591 value = kvp_value_new_gint64 (ival);
592 frame = kvp_frame_add_value_nc (frame, path, value);
593 if (!frame)
594 kvp_value_delete (value);
595 }
596
597 void
kvp_frame_add_double(KvpFrame * frame,const gchar * path,gdouble dval)598 kvp_frame_add_double (KvpFrame * frame, const gchar *path, gdouble dval)
599 {
600 KvpValue *value;
601 value = kvp_value_new_double (dval);
602 frame = kvp_frame_add_value_nc (frame, path, value);
603 if (!frame)
604 kvp_value_delete (value);
605 }
606
607 void
kvp_frame_add_numeric(KvpFrame * frame,const gchar * path,QofNumeric nval)608 kvp_frame_add_numeric (KvpFrame * frame, const gchar *path,
609 QofNumeric nval)
610 {
611 KvpValue *value;
612 value = kvp_value_new_numeric (nval);
613 frame = kvp_frame_add_value_nc (frame, path, value);
614 if (!frame)
615 kvp_value_delete (value);
616 }
617
618 void
kvp_frame_add_time(KvpFrame * frame,const gchar * path,QofTime * qt)619 kvp_frame_add_time (KvpFrame * frame, const gchar *path, QofTime *qt)
620 {
621 KvpValue *value;
622 value = kvp_value_new_time (qt);
623 frame = kvp_frame_add_value_nc (frame, path, value);
624 if (!frame)
625 kvp_value_delete (value);
626 }
627
628 void
kvp_frame_add_boolean(KvpFrame * frame,const gchar * path,gboolean val)629 kvp_frame_add_boolean (KvpFrame * frame, const gchar * path, gboolean val)
630 {
631 KvpValue * value;
632 value = kvp_value_new_boolean (val);
633 frame = kvp_frame_add_value_nc (frame, path, value);
634 if (!frame)
635 kvp_value_delete (value);
636 }
637
638 void
kvp_frame_add_string(KvpFrame * frame,const gchar * path,const gchar * str)639 kvp_frame_add_string (KvpFrame * frame, const gchar *path, const gchar *str)
640 {
641 KvpValue *value;
642 value = kvp_value_new_string (str);
643 frame = kvp_frame_add_value_nc (frame, path, value);
644 if (!frame)
645 kvp_value_delete (value);
646 }
647
648 void
kvp_frame_add_guid(KvpFrame * frame,const gchar * path,const GUID * guid)649 kvp_frame_add_guid (KvpFrame * frame, const gchar *path, const GUID * guid)
650 {
651 KvpValue *value;
652 value = kvp_value_new_guid (guid);
653 frame = kvp_frame_add_value_nc (frame, path, value);
654 if (!frame)
655 kvp_value_delete (value);
656 }
657
658 void
kvp_frame_add_frame(KvpFrame * frame,const gchar * path,KvpFrame * fr)659 kvp_frame_add_frame (KvpFrame * frame, const gchar *path, KvpFrame * fr)
660 {
661 KvpValue *value;
662 value = kvp_value_new_frame (fr);
663 frame = kvp_frame_add_value_nc (frame, path, value);
664 if (!frame)
665 kvp_value_delete (value);
666 }
667
668 void
kvp_frame_add_frame_nc(KvpFrame * frame,const gchar * path,KvpFrame * fr)669 kvp_frame_add_frame_nc (KvpFrame * frame, const gchar *path, KvpFrame * fr)
670 {
671 KvpValue *value;
672 value = kvp_value_new_frame_nc (fr);
673 frame = kvp_frame_add_value_nc (frame, path, value);
674 if (!frame)
675 kvp_value_delete (value);
676 }
677
678 /* ============================================================ */
679
680 void
kvp_frame_set_slot(KvpFrame * frame,const gchar * slot,const KvpValue * value)681 kvp_frame_set_slot (KvpFrame * frame, const gchar *slot,
682 const KvpValue * value)
683 {
684 KvpValue *new_value = NULL;
685
686 if (!frame)
687 return;
688
689 g_return_if_fail (slot && *slot != '\0');
690
691 if (value)
692 new_value = kvp_value_copy (value);
693 kvp_frame_set_slot_destructively (frame, slot, new_value);
694 }
695
696 void
kvp_frame_set_slot_nc(KvpFrame * frame,const gchar * slot,KvpValue * value)697 kvp_frame_set_slot_nc (KvpFrame * frame, const gchar *slot,
698 KvpValue * value)
699 {
700 if (!frame)
701 return;
702
703 g_return_if_fail (slot && *slot != '\0');
704
705 kvp_frame_set_slot_destructively (frame, slot, value);
706 }
707
708 KvpValue *
kvp_frame_get_slot(const KvpFrame * frame,const gchar * slot)709 kvp_frame_get_slot (const KvpFrame * frame, const gchar *slot)
710 {
711 KvpValue *v;
712 if (!frame)
713 return NULL;
714 if (!frame->hash)
715 return NULL; /* Error ... */
716 v = g_hash_table_lookup (frame->hash, slot);
717 return v;
718 }
719
720 /* ============================================================ */
721
722 void
kvp_frame_set_slot_path(KvpFrame * frame,const KvpValue * new_value,const gchar * first_key,...)723 kvp_frame_set_slot_path (KvpFrame * frame,
724 const KvpValue * new_value, const gchar *first_key, ...)
725 {
726 va_list ap;
727 const gchar *key;
728
729 if (!frame)
730 return;
731
732 g_return_if_fail (first_key && *first_key != '\0');
733
734 va_start (ap, first_key);
735
736 key = first_key;
737
738 while (TRUE)
739 {
740 KvpValue *value;
741 const gchar *next_key;
742
743 next_key = va_arg (ap, const gchar *);
744 if (!next_key)
745 {
746 kvp_frame_set_slot (frame, key, new_value);
747 break;
748 }
749
750 g_return_if_fail (*next_key != '\0');
751
752 value = kvp_frame_get_slot (frame, key);
753 if (!value)
754 {
755 KvpFrame *new_frame = kvp_frame_new ();
756 KvpValue *frame_value = kvp_value_new_frame (new_frame);
757
758 kvp_frame_set_slot_nc (frame, key, frame_value);
759
760 value = kvp_frame_get_slot (frame, key);
761 if (!value)
762 break;
763 }
764
765 frame = kvp_value_get_frame (value);
766 if (!frame)
767 break;
768
769 key = next_key;
770 }
771
772 va_end (ap);
773 }
774
775 void
kvp_frame_set_slot_path_gslist(KvpFrame * frame,const KvpValue * new_value,GSList * key_path)776 kvp_frame_set_slot_path_gslist (KvpFrame * frame,
777 const KvpValue * new_value, GSList * key_path)
778 {
779 if (!frame || !key_path)
780 return;
781
782 while (TRUE)
783 {
784 const gchar *key = key_path->data;
785 KvpValue *value;
786
787 if (!key)
788 return;
789
790 g_return_if_fail (*key != '\0');
791
792 key_path = key_path->next;
793 if (!key_path)
794 {
795 kvp_frame_set_slot (frame, key, new_value);
796 return;
797 }
798
799 value = kvp_frame_get_slot (frame, key);
800 if (!value)
801 {
802 KvpFrame *new_frame = kvp_frame_new ();
803 KvpValue *frame_value = kvp_value_new_frame (new_frame);
804
805 kvp_frame_set_slot_nc (frame, key, frame_value);
806
807 value = kvp_frame_get_slot (frame, key);
808 if (!value)
809 return;
810 }
811
812 frame = kvp_value_get_frame (value);
813 if (!frame)
814 return;
815 }
816 }
817
818 /* ============================================================ */
819 /* decode url-encoded string, do it in place
820 * + == space
821 * %xx == asci char where xx is hexadecimal ascii value
822 */
823
824 static void
decode(gchar * enc)825 decode (gchar *enc)
826 {
827 gchar *p, *w;
828
829 /* Loop, convert +'s to blanks */
830 p = strchr (enc, '+');
831 while (p)
832 {
833 *p = ' ';
834 p = strchr (p, '+');
835 }
836
837 p = strchr (enc, '%');
838 w = p;
839
840 while (p)
841 {
842 gint ch, cl;
843 p++;
844 ch = *p - 0x30; /* ascii 0 = 0x30 */
845 if (9 < ch)
846 ch -= 0x11 - 10; /* uppercase A = 0x41 */
847 if (16 < ch)
848 ch -= 0x20; /* lowercase a = 0x61 */
849
850 p++;
851 cl = *p - 0x30; /* ascii 0 = 0x30 */
852 if (9 < cl)
853 cl -= 0x11 - 10; /* uppercase A = 0x41 */
854 if (16 < cl)
855 cl -= 0x20; /* lowercase a = 0x61 */
856
857 *w = (gchar) (ch << 4 | cl);
858
859 do
860 {
861 ++w;
862 ++p;
863 *w = *p;
864 if (0x0 == *p)
865 {
866 p = 0;
867 break;
868 }
869 if ('%' == *p)
870 break;
871 }
872 while (*p);
873 }
874 }
875
876 void
kvp_frame_add_url_encoding(KvpFrame * frame,const gchar * enc)877 kvp_frame_add_url_encoding (KvpFrame * frame, const gchar *enc)
878 {
879 gchar *buff, *p;
880 if (!frame || !enc)
881 return;
882
883 /* Loop over all key-value pairs in the encoded string */
884 buff = g_strdup (enc);
885 p = buff;
886 while (*p)
887 {
888 gchar *n, *v;
889 n = strchr (p, '&'); /* n = next key-value */
890 if (n)
891 *n = 0x0;
892
893 v = strchr (p, '='); /* v = pointer to value */
894 if (!v)
895 break;
896 *v = 0x0;
897 v++;
898
899 decode (p);
900 decode (v);
901 kvp_frame_set_slot_nc (frame, p, kvp_value_new_string (v));
902
903 if (!n)
904 break; /* no next key, we are done */
905 p = ++n;
906 }
907
908 g_free (buff);
909 }
910
911 /* ============================================================ */
912
913
914 gint64
kvp_frame_get_gint64(const KvpFrame * frame,const gchar * path)915 kvp_frame_get_gint64 (const KvpFrame * frame, const gchar *path)
916 {
917 gchar *key = NULL;
918 frame = get_trailer_or_null (frame, path, &key);
919 return kvp_value_get_gint64 (kvp_frame_get_slot (frame, key));
920 }
921
922 gdouble
kvp_frame_get_double(const KvpFrame * frame,const gchar * path)923 kvp_frame_get_double (const KvpFrame * frame, const gchar *path)
924 {
925 gchar *key = NULL;
926 frame = get_trailer_or_null (frame, path, &key);
927 return kvp_value_get_double (kvp_frame_get_slot (frame, key));
928 }
929
930 QofNumeric
kvp_frame_get_numeric(const KvpFrame * frame,const gchar * path)931 kvp_frame_get_numeric (const KvpFrame * frame, const gchar *path)
932 {
933 gchar *key = NULL;
934 frame = get_trailer_or_null (frame, path, &key);
935 return kvp_value_get_numeric (kvp_frame_get_slot (frame, key));
936 }
937
938 gchar *
kvp_frame_get_string(const KvpFrame * frame,const gchar * path)939 kvp_frame_get_string (const KvpFrame * frame, const gchar *path)
940 {
941 gchar *key = NULL;
942 frame = get_trailer_or_null (frame, path, &key);
943 return kvp_value_get_string (kvp_frame_get_slot (frame, key));
944 }
945
946 gboolean
kvp_frame_get_boolean(const KvpFrame * frame,const gchar * path)947 kvp_frame_get_boolean (const KvpFrame * frame, const gchar * path)
948 {
949 gchar * key = NULL;
950 frame = get_trailer_or_null (frame, path, &key);
951 return kvp_value_get_boolean (kvp_frame_get_slot (frame, key));
952 }
953
954 GUID *
kvp_frame_get_guid(const KvpFrame * frame,const gchar * path)955 kvp_frame_get_guid (const KvpFrame * frame, const gchar *path)
956 {
957 gchar *key = NULL;
958 frame = get_trailer_or_null (frame, path, &key);
959 return kvp_value_get_guid (kvp_frame_get_slot (frame, key));
960 }
961
962 void *
kvp_frame_get_binary(const KvpFrame * frame,const gchar * path,guint64 * size_return)963 kvp_frame_get_binary (const KvpFrame * frame, const gchar *path,
964 guint64 * size_return)
965 {
966 gchar *key = NULL;
967 frame = get_trailer_or_null (frame, path, &key);
968 return kvp_value_get_binary (kvp_frame_get_slot (frame, key),
969 size_return);
970 }
971
972 QofTime *
kvp_frame_get_time(const KvpFrame * frame,const gchar * path)973 kvp_frame_get_time (const KvpFrame * frame, const gchar *path)
974 {
975 gchar *key = NULL;
976 frame = get_trailer_or_null (frame, path, &key);
977 return kvp_value_get_time (kvp_frame_get_slot (frame, key));
978 }
979
980 KvpFrame *
kvp_frame_get_frame(const KvpFrame * frame,const gchar * path)981 kvp_frame_get_frame (const KvpFrame * frame, const gchar *path)
982 {
983 gchar *key = NULL;
984 frame = get_trailer_or_null (frame, path, &key);
985 return kvp_value_get_frame (kvp_frame_get_slot (frame, key));
986 }
987
988 KvpValue *
kvp_frame_get_value(const KvpFrame * frame,const gchar * path)989 kvp_frame_get_value (const KvpFrame * frame, const gchar *path)
990 {
991 gchar *key = NULL;
992 frame = get_trailer_or_null (frame, path, &key);
993 return kvp_frame_get_slot (frame, key);
994 }
995
996 /* ============================================================ */
997
998 KvpFrame *
kvp_frame_get_frame_gslist(KvpFrame * frame,GSList * key_path)999 kvp_frame_get_frame_gslist (KvpFrame * frame, GSList * key_path)
1000 {
1001 if (!frame)
1002 return frame;
1003
1004 while (key_path)
1005 {
1006 const gchar *key = key_path->data;
1007
1008 if (!key)
1009 return frame; /* an unusual but valid exit for this routine. */
1010
1011 frame = get_or_make (frame, key);
1012 if (!frame)
1013 return frame; /* this should never happen */
1014
1015 key_path = key_path->next;
1016 }
1017 return frame; /* this is the normal exit for this func */
1018 }
1019
1020 KvpFrame *
kvp_frame_get_frame_path(KvpFrame * frame,const gchar * key,...)1021 kvp_frame_get_frame_path (KvpFrame * frame, const gchar *key, ...)
1022 {
1023 va_list ap;
1024 if (!frame || !key)
1025 return frame;
1026
1027 va_start (ap, key);
1028
1029 while (key)
1030 {
1031 frame = get_or_make (frame, key);
1032 if (!frame)
1033 break; /* error, should never occur */
1034 key = va_arg (ap, const char *);
1035 }
1036
1037 va_end (ap);
1038 return frame;
1039 }
1040
1041 KvpFrame *
kvp_frame_get_frame_slash(KvpFrame * frame,const gchar * key_path)1042 kvp_frame_get_frame_slash (KvpFrame * frame, const gchar *key_path)
1043 {
1044 gchar *root;
1045 if (!frame || !key_path)
1046 return frame;
1047
1048 root = g_strdup (key_path);
1049 frame = kvp_frame_get_frame_slash_trash (frame, root);
1050 g_free (root);
1051 return frame;
1052 }
1053
1054 /* ============================================================ */
1055
1056 KvpValue *
kvp_frame_get_slot_path(KvpFrame * frame,const gchar * first_key,...)1057 kvp_frame_get_slot_path (KvpFrame * frame, const gchar *first_key, ...)
1058 {
1059 va_list ap;
1060 KvpValue *value;
1061 const gchar *key;
1062
1063 if (!frame || !first_key)
1064 return NULL;
1065
1066 va_start (ap, first_key);
1067
1068 key = first_key;
1069 value = NULL;
1070
1071 while (TRUE)
1072 {
1073 value = kvp_frame_get_slot (frame, key);
1074 if (!value)
1075 break;
1076
1077 key = va_arg (ap, const gchar *);
1078 if (!key)
1079 break;
1080
1081 frame = kvp_value_get_frame (value);
1082 if (!frame)
1083 {
1084 value = NULL;
1085 break;
1086 }
1087 }
1088
1089 va_end (ap);
1090
1091 return value;
1092 }
1093
1094 KvpValue *
kvp_frame_get_slot_path_gslist(KvpFrame * frame,GSList * key_path)1095 kvp_frame_get_slot_path_gslist (KvpFrame * frame, GSList * key_path)
1096 {
1097 if (!frame || !key_path)
1098 return NULL;
1099
1100 while (TRUE)
1101 {
1102 const gchar *key = key_path->data;
1103 KvpValue *value;
1104
1105 if (!key)
1106 return NULL;
1107
1108 value = kvp_frame_get_slot (frame, key);
1109 if (!value)
1110 return NULL;
1111
1112 key_path = key_path->next;
1113 if (!key_path)
1114 return value;
1115
1116 frame = kvp_value_get_frame (value);
1117 if (!frame)
1118 return NULL;
1119 }
1120 }
1121
1122 /* *******************************************************************
1123 * kvp glist functions
1124 ********************************************************************/
1125
1126 void
kvp_glist_delete(GList * list)1127 kvp_glist_delete (GList * list)
1128 {
1129 GList *node;
1130 if (!list)
1131 return;
1132
1133 /* Delete the data in the list */
1134 for (node = list; node; node = node->next)
1135 {
1136 KvpValue *val = node->data;
1137 kvp_value_delete (val);
1138 }
1139
1140 /* Free the backbone */
1141 g_list_free (list);
1142 }
1143
1144 GList *
kvp_glist_copy(const GList * list)1145 kvp_glist_copy (const GList * list)
1146 {
1147 GList *retval = NULL;
1148 GList *lptr;
1149
1150 if (!list)
1151 return retval;
1152
1153 /* Duplicate the backbone of the list (this duplicates the POINTERS
1154 * to the values; we need to deep-copy the values separately) */
1155 retval = g_list_copy ((GList *) list);
1156
1157 /* This step deep-copies the values */
1158 for (lptr = retval; lptr; lptr = lptr->next)
1159 {
1160 lptr->data = kvp_value_copy (lptr->data);
1161 }
1162
1163 return retval;
1164 }
1165
1166 gint
kvp_glist_compare(const GList * list1,const GList * list2)1167 kvp_glist_compare (const GList * list1, const GList * list2)
1168 {
1169 const GList *lp1;
1170 const GList *lp2;
1171
1172 if (list1 == list2)
1173 return 0;
1174
1175 /* Nothing is always less than something */
1176 if (!list1 && list2)
1177 return -1;
1178 if (list1 && !list2)
1179 return 1;
1180
1181 lp1 = list1;
1182 lp2 = list2;
1183 while (lp1 && lp2)
1184 {
1185 KvpValue *v1 = (KvpValue *) lp1->data;
1186 KvpValue *v2 = (KvpValue *) lp2->data;
1187 gint vcmp = kvp_value_compare (v1, v2);
1188 if (vcmp != 0)
1189 return vcmp;
1190 lp1 = lp1->next;
1191 lp2 = lp2->next;
1192 }
1193 if (!lp1 && lp2)
1194 return -1;
1195 if (!lp2 && lp1)
1196 return 1;
1197 return 0;
1198 }
1199
1200 /* *******************************************************************
1201 * KvpValue functions
1202 ********************************************************************/
1203
1204 KvpValue *
kvp_value_new_gint64(gint64 value)1205 kvp_value_new_gint64 (gint64 value)
1206 {
1207 KvpValue *retval = g_new0 (KvpValue, 1);
1208 retval->type = KVP_TYPE_GINT64;
1209 retval->value.int64 = value;
1210 return retval;
1211 }
1212
1213 KvpValue *
kvp_value_new_double(gdouble value)1214 kvp_value_new_double (gdouble value)
1215 {
1216 KvpValue *retval = g_new0 (KvpValue, 1);
1217 retval->type = KVP_TYPE_DOUBLE;
1218 retval->value.dbl = value;
1219 return retval;
1220 }
1221
1222 KvpValue *
kvp_value_new_boolean(gboolean value)1223 kvp_value_new_boolean (gboolean value)
1224 {
1225 KvpValue * retval = g_new0 (KvpValue, 1);
1226 retval->type = KVP_TYPE_BOOLEAN;
1227 retval->value.gbool = value;
1228 return retval;
1229 }
1230
1231 KvpValue *
kvp_value_new_numeric(QofNumeric value)1232 kvp_value_new_numeric (QofNumeric value)
1233 {
1234 KvpValue *retval = g_new0 (KvpValue, 1);
1235 retval->type = KVP_TYPE_NUMERIC;
1236 retval->value.numeric = value;
1237 return retval;
1238 }
1239
1240 KvpValue *
kvp_value_new_string(const gchar * value)1241 kvp_value_new_string (const gchar *value)
1242 {
1243 KvpValue *retval;
1244 if (!value)
1245 return NULL;
1246
1247 retval = g_new0 (KvpValue, 1);
1248 retval->type = KVP_TYPE_STRING;
1249 retval->value.str = g_strdup (value);
1250 return retval;
1251 }
1252
1253 KvpValue *
kvp_value_new_guid(const GUID * value)1254 kvp_value_new_guid (const GUID * value)
1255 {
1256 KvpValue *retval;
1257 if (!value)
1258 return NULL;
1259
1260 retval = g_new0 (KvpValue, 1);
1261 retval->type = KVP_TYPE_GUID;
1262 retval->value.guid = g_new0 (GUID, 1);
1263 memcpy (retval->value.guid, value, sizeof (GUID));
1264 return retval;
1265 }
1266
1267 KvpValue *
kvp_value_new_time(QofTime * value)1268 kvp_value_new_time (QofTime *value)
1269 {
1270 KvpValue *retval = g_new0 (KvpValue, 1);
1271 retval->type = KVP_TYPE_TIME;
1272 retval->value.qt = value;
1273 return retval;
1274 }
1275
1276 KvpValue *
kvp_value_new_binary(gconstpointer value,guint64 datasize)1277 kvp_value_new_binary (gconstpointer value, guint64 datasize)
1278 {
1279 KvpValue *retval;
1280 if (!value)
1281 return NULL;
1282
1283 retval = g_new0 (KvpValue, 1);
1284 retval->type = KVP_TYPE_BINARY;
1285 retval->value.binary.data = g_new0 (gpointer, datasize);
1286 retval->value.binary.datasize = datasize;
1287 memcpy (retval->value.binary.data, value, datasize);
1288 return retval;
1289 }
1290
1291 KvpValue *
kvp_value_new_binary_nc(gpointer value,guint64 datasize)1292 kvp_value_new_binary_nc (gpointer value, guint64 datasize)
1293 {
1294 KvpValue *retval;
1295 if (!value)
1296 return NULL;
1297
1298 retval = g_new0 (KvpValue, 1);
1299 retval->type = KVP_TYPE_BINARY;
1300 retval->value.binary.data = value;
1301 retval->value.binary.datasize = datasize;
1302 return retval;
1303 }
1304
1305 KvpValue *
kvp_value_new_glist(const GList * value)1306 kvp_value_new_glist (const GList * value)
1307 {
1308 KvpValue *retval;
1309 if (!value)
1310 return NULL;
1311
1312 retval = g_new0 (KvpValue, 1);
1313 retval->type = KVP_TYPE_GLIST;
1314 retval->value.list = kvp_glist_copy (value);
1315 return retval;
1316 }
1317
1318 KvpValue *
kvp_value_new_glist_nc(GList * value)1319 kvp_value_new_glist_nc (GList * value)
1320 {
1321 KvpValue *retval;
1322 if (!value)
1323 return NULL;
1324
1325 retval = g_new0 (KvpValue, 1);
1326 retval->type = KVP_TYPE_GLIST;
1327 retval->value.list = value;
1328 return retval;
1329 }
1330
1331 KvpValue *
kvp_value_new_frame(const KvpFrame * value)1332 kvp_value_new_frame (const KvpFrame * value)
1333 {
1334 KvpValue *retval;
1335 if (!value)
1336 return NULL;
1337
1338 retval = g_new0 (KvpValue, 1);
1339 retval->type = KVP_TYPE_FRAME;
1340 retval->value.frame = kvp_frame_copy (value);
1341 return retval;
1342 }
1343
1344 KvpValue *
kvp_value_new_frame_nc(KvpFrame * value)1345 kvp_value_new_frame_nc (KvpFrame * value)
1346 {
1347 KvpValue *retval;
1348 if (!value)
1349 return NULL;
1350
1351 retval = g_new0 (KvpValue, 1);
1352 retval->type = KVP_TYPE_FRAME;
1353 retval->value.frame = value;
1354 return retval;
1355 }
1356
1357 void
kvp_value_delete(KvpValue * value)1358 kvp_value_delete (KvpValue * value)
1359 {
1360 if (!value)
1361 return;
1362
1363 switch (value->type)
1364 {
1365 case KVP_TYPE_STRING:
1366 g_free (value->value.str);
1367 break;
1368 case KVP_TYPE_GUID:
1369 g_free (value->value.guid);
1370 break;
1371 case KVP_TYPE_BINARY:
1372 g_free (value->value.binary.data);
1373 break;
1374 case KVP_TYPE_GLIST:
1375 kvp_glist_delete (value->value.list);
1376 break;
1377 case KVP_TYPE_FRAME:
1378 kvp_frame_delete (value->value.frame);
1379 break;
1380 case KVP_TYPE_BOOLEAN:
1381 case KVP_TYPE_GINT64:
1382 case KVP_TYPE_DOUBLE:
1383 case KVP_TYPE_NUMERIC:
1384 default:
1385 break;
1386 }
1387 g_free (value);
1388 }
1389
1390 KvpValueType
kvp_value_get_type(const KvpValue * value)1391 kvp_value_get_type (const KvpValue * value)
1392 {
1393 if (!value)
1394 return QOF_FATAL;
1395 return value->type;
1396 }
1397
1398 gint64
kvp_value_get_gint64(const KvpValue * value)1399 kvp_value_get_gint64 (const KvpValue * value)
1400 {
1401 if (!value)
1402 return 0;
1403 if (value->type == KVP_TYPE_GINT64)
1404 return value->value.int64;
1405 else
1406 {
1407 PERR (" value type %d does not match KVP_TYPE_GINT64",
1408 value->type);
1409 return 0;
1410 }
1411 }
1412
1413 gdouble
kvp_value_get_double(const KvpValue * value)1414 kvp_value_get_double (const KvpValue * value)
1415 {
1416 if (!value)
1417 return 0.0;
1418 if (value->type == KVP_TYPE_DOUBLE)
1419 return value->value.dbl;
1420 else
1421 {
1422 PERR (" value type %d does not match KVP_TYPE_DOUBLE",
1423 value->type);
1424 return 0.0;
1425 }
1426 }
1427
1428 QofNumeric
kvp_value_get_numeric(const KvpValue * value)1429 kvp_value_get_numeric (const KvpValue * value)
1430 {
1431 if (!value)
1432 return qof_numeric_zero ();
1433 if (value->type == KVP_TYPE_NUMERIC)
1434 return value->value.numeric;
1435 else
1436 {
1437 PERR (" value type %d does not match KVP_TYPE_NUMERIC",
1438 value->type);
1439 return qof_numeric_zero ();
1440 }
1441 }
1442
1443 gchar *
kvp_value_get_string(const KvpValue * value)1444 kvp_value_get_string (const KvpValue * value)
1445 {
1446 if (!value)
1447 return NULL;
1448 if (value->type == KVP_TYPE_STRING)
1449 return value->value.str;
1450 else
1451 {
1452 PERR (" value type %d does not match KVP_TYPE_STRING",
1453 value->type);
1454 return NULL;
1455 }
1456 }
1457
1458 gboolean
kvp_value_get_boolean(const KvpValue * value)1459 kvp_value_get_boolean (const KvpValue * value)
1460 {
1461 if (!value)
1462 return FALSE;
1463 if (value->type == KVP_TYPE_BOOLEAN)
1464 return value->value.gbool;
1465 else
1466 {
1467 PERR (" value type %d does not match KVP_TYPE_BOOLEAN",
1468 value->type);
1469 return FALSE;
1470 }
1471 }
1472
1473 GUID *
kvp_value_get_guid(const KvpValue * value)1474 kvp_value_get_guid (const KvpValue * value)
1475 {
1476 if (!value)
1477 return NULL;
1478 if (value->type == KVP_TYPE_GUID)
1479 return value->value.guid;
1480 else
1481 {
1482 PERR (" value type %d does not match KVP_TYPE_GUID",
1483 value->type);
1484 return NULL;
1485 }
1486 }
1487
1488 QofTime*
kvp_value_get_time(const KvpValue * value)1489 kvp_value_get_time (const KvpValue * value)
1490 {
1491 if (!value)
1492 return NULL;
1493 if (value->type == KVP_TYPE_TIME)
1494 return value->value.qt;
1495 else
1496 {
1497 PERR (" value type %d does not match KVP_TYPE_TIME",
1498 value->type);
1499 return NULL;
1500 }
1501 }
1502
1503 void *
kvp_value_get_binary(const KvpValue * value,guint64 * size_return)1504 kvp_value_get_binary (const KvpValue * value, guint64 * size_return)
1505 {
1506 if (!value)
1507 {
1508 if (size_return)
1509 *size_return = 0;
1510 PERR (" no size specified");
1511 return NULL;
1512 }
1513
1514 if (value->type == KVP_TYPE_BINARY)
1515 {
1516 if (size_return)
1517 *size_return = value->value.binary.datasize;
1518 return value->value.binary.data;
1519 }
1520 else
1521 {
1522 if (size_return)
1523 *size_return = 0;
1524 PERR (" value type %d does not match KVP_TYPE_BINARY",
1525 value->type);
1526 return NULL;
1527 }
1528 }
1529
1530 GList *
kvp_value_get_glist(const KvpValue * value)1531 kvp_value_get_glist (const KvpValue * value)
1532 {
1533 if (!value)
1534 return NULL;
1535 if (value->type == KVP_TYPE_GLIST)
1536 return value->value.list;
1537 else
1538 {
1539 PERR (" value type %d does not match KVP_TYPE_GLIST",
1540 value->type);
1541 return NULL;
1542 }
1543 }
1544
1545 KvpFrame *
kvp_value_get_frame(const KvpValue * value)1546 kvp_value_get_frame (const KvpValue * value)
1547 {
1548 if (!value)
1549 return NULL;
1550 if (value->type == KVP_TYPE_FRAME)
1551 return value->value.frame;
1552 else
1553 {
1554 PERR (" value type %d does not match KVP_TYPE_FRAME",
1555 value->type);
1556 return NULL;
1557 }
1558 }
1559
1560 KvpFrame *
kvp_value_replace_frame_nc(KvpValue * value,KvpFrame * newframe)1561 kvp_value_replace_frame_nc (KvpValue * value, KvpFrame * newframe)
1562 {
1563 KvpFrame *oldframe;
1564 if (!value)
1565 return NULL;
1566 if (KVP_TYPE_FRAME != value->type)
1567 {
1568 PERR (" value type %d does not match KVP_TYPE_FRAME",
1569 value->type);
1570 return NULL;
1571 }
1572 oldframe = value->value.frame;
1573 value->value.frame = newframe;
1574 return oldframe;
1575 }
1576
1577 GList *
kvp_value_replace_glist_nc(KvpValue * value,GList * newlist)1578 kvp_value_replace_glist_nc (KvpValue * value, GList * newlist)
1579 {
1580 GList *oldlist;
1581 if (!value)
1582 return NULL;
1583 if (KVP_TYPE_GLIST != value->type)
1584 {
1585 PERR (" value type %d does not match KVP_TYPE_GLIST",
1586 value->type);
1587 return NULL;
1588 }
1589
1590 oldlist = value->value.list;
1591 value->value.list = newlist;
1592 return oldlist;
1593 }
1594
1595 /* manipulators */
1596
1597 KvpValue *
kvp_value_copy(const KvpValue * value)1598 kvp_value_copy (const KvpValue * value)
1599 {
1600 if (!value)
1601 return NULL;
1602
1603 switch (value->type)
1604 {
1605 case KVP_TYPE_GINT64:
1606 return kvp_value_new_gint64 (value->value.int64);
1607 break;
1608 case KVP_TYPE_DOUBLE:
1609 return kvp_value_new_double (value->value.dbl);
1610 break;
1611 case KVP_TYPE_NUMERIC:
1612 return kvp_value_new_numeric (value->value.numeric);
1613 break;
1614 case KVP_TYPE_STRING:
1615 return kvp_value_new_string (value->value.str);
1616 break;
1617 case KVP_TYPE_GUID:
1618 return kvp_value_new_guid (value->value.guid);
1619 break;
1620 case KVP_TYPE_BOOLEAN:
1621 return NULL;
1622 return kvp_value_new_boolean (value->value.gbool);
1623 break;
1624 case KVP_TYPE_TIME :
1625 return kvp_value_new_time (value->value.qt);
1626 break;
1627 case KVP_TYPE_BINARY:
1628 return kvp_value_new_binary (value->value.binary.data,
1629 value->value.binary.datasize);
1630 break;
1631 case KVP_TYPE_GLIST:
1632 return kvp_value_new_glist (value->value.list);
1633 break;
1634 case KVP_TYPE_FRAME:
1635 return kvp_value_new_frame (value->value.frame);
1636 break;
1637 }
1638 return NULL;
1639 }
1640
1641 void
kvp_frame_for_each_slot(KvpFrame * f,KvpValueForeachCB proc,gpointer data)1642 kvp_frame_for_each_slot (KvpFrame * f, KvpValueForeachCB proc, gpointer data)
1643 {
1644 if (!f)
1645 return;
1646 if (!proc)
1647 return;
1648 if (!(f->hash))
1649 return;
1650 g_hash_table_foreach (f->hash, (GHFunc) proc, data);
1651 }
1652
1653 gint
kvp_value_compare(const KvpValue * kva,const KvpValue * kvb)1654 kvp_value_compare (const KvpValue * kva, const KvpValue * kvb)
1655 {
1656 if (kva == kvb)
1657 return 0;
1658 /* nothing is always less than something */
1659 if (!kva && kvb)
1660 return -1;
1661 if (kva && !kvb)
1662 return 1;
1663
1664 if (kva->type < kvb->type)
1665 return -1;
1666 if (kva->type > kvb->type)
1667 return 1;
1668
1669 switch (kva->type)
1670 {
1671 case KVP_TYPE_GINT64:
1672 if (kva->value.int64 < kvb->value.int64)
1673 return -1;
1674 if (kva->value.int64 > kvb->value.int64)
1675 return 1;
1676 return 0;
1677 break;
1678 case KVP_TYPE_DOUBLE:
1679 return qof_util_double_compare (kva->value.dbl, kvb->value.dbl);
1680 break;
1681 case KVP_TYPE_NUMERIC:
1682 return qof_numeric_compare (kva->value.numeric,
1683 kvb->value.numeric);
1684 break;
1685 case KVP_TYPE_STRING:
1686 return strcmp (kva->value.str, kvb->value.str);
1687 break;
1688 case KVP_TYPE_GUID:
1689 return guid_compare (kva->value.guid, kvb->value.guid);
1690 break;
1691 case KVP_TYPE_BOOLEAN:
1692 {
1693 /* true > false */
1694 if (kva->value.gbool != kvb->value.gbool)
1695 return (kva->value.gbool) ? 1 : -1;
1696 return 0;
1697 break;
1698 }
1699 case KVP_TYPE_TIME :
1700 return qof_time_cmp (kva->value.qt, kvb->value.qt);
1701 break;
1702 case KVP_TYPE_BINARY:
1703 if (kva->value.binary.datasize < kvb->value.binary.datasize)
1704 return -1;
1705 if (kva->value.binary.datasize > kvb->value.binary.datasize)
1706 return 1;
1707 return memcmp (kva->value.binary.data,
1708 kvb->value.binary.data, kva->value.binary.datasize);
1709 break;
1710 case KVP_TYPE_GLIST:
1711 return kvp_glist_compare (kva->value.list, kvb->value.list);
1712 break;
1713 case KVP_TYPE_FRAME:
1714 return kvp_frame_compare (kva->value.frame, kvb->value.frame);
1715 break;
1716 }
1717 return 0;
1718 }
1719
1720 typedef struct
1721 {
1722 gint compare;
1723 KvpFrame *other_frame;
1724 } KvpFrameCompare;
1725
1726 static void
kvp_frame_compare_helper(const gchar * key,KvpValue * val,gpointer data)1727 kvp_frame_compare_helper (const gchar *key, KvpValue * val, gpointer data)
1728 {
1729 KvpFrameCompare *status = (KvpFrameCompare *) data;
1730 if (status->compare == 0)
1731 {
1732 KvpFrame *other_frame = status->other_frame;
1733 KvpValue *other_val = kvp_frame_get_slot (other_frame, key);
1734
1735 if (other_val)
1736 status->compare = kvp_value_compare (val, other_val);
1737 else
1738 status->compare = 1;
1739 }
1740 }
1741
1742 gint
kvp_frame_compare(const KvpFrame * fa,const KvpFrame * fb)1743 kvp_frame_compare (const KvpFrame * fa, const KvpFrame * fb)
1744 {
1745 KvpFrameCompare status;
1746
1747 if (fa == fb)
1748 return 0;
1749 /* nothing is always less than something */
1750 if (!fa && fb)
1751 return -1;
1752 if (fa && !fb)
1753 return 1;
1754
1755 /* nothing is always less than something */
1756 if (!fa->hash && fb->hash)
1757 return -1;
1758 if (fa->hash && !fb->hash)
1759 return 1;
1760
1761 status.compare = 0;
1762 status.other_frame = (KvpFrame *) fb;
1763
1764 kvp_frame_for_each_slot ((KvpFrame *) fa, kvp_frame_compare_helper,
1765 &status);
1766
1767 if (status.compare != 0)
1768 return status.compare;
1769
1770 status.other_frame = (KvpFrame *) fa;
1771
1772 kvp_frame_for_each_slot ((KvpFrame *) fb, kvp_frame_compare_helper,
1773 &status);
1774
1775 return (-status.compare);
1776 }
1777
1778 /* FIXME: genuine binary content cannot be made a string reliably. */
1779 gchar *
binary_to_string(gconstpointer data,guint32 size)1780 binary_to_string (gconstpointer data, guint32 size)
1781 {
1782 GString *output;
1783 guint32 i;
1784 guchar *data_str = (guchar *) data;
1785
1786 output = g_string_sized_new (size * sizeof (gchar));
1787
1788 for (i = 0; i < size; i++)
1789 {
1790 g_string_append_printf (output, "%02x",
1791 (guint32) (data_str[i]));
1792 }
1793
1794 return output->str;
1795 }
1796
1797 gchar *
kvp_value_glist_to_string(const GList * list)1798 kvp_value_glist_to_string (const GList * list)
1799 {
1800 gchar *tmp1;
1801 gchar *tmp2;
1802 const GList *cursor;
1803
1804 tmp1 = g_strdup_printf ("[ ");
1805
1806 for (cursor = list; cursor; cursor = cursor->next)
1807 {
1808 gchar *tmp3;
1809
1810 tmp3 = kvp_value_to_string ((KvpValue *) cursor->data);
1811 tmp2 = g_strdup_printf ("%s %s,", tmp1, tmp3 ? tmp3 : "");
1812 g_free (tmp1);
1813 g_free (tmp3);
1814 tmp1 = tmp2;
1815 }
1816
1817 tmp2 = g_strdup_printf ("%s ]", tmp1);
1818 g_free (tmp1);
1819
1820 return tmp2;
1821 }
1822
1823 static void
kvp_frame_to_bare_string_helper(gpointer key,gpointer value,gpointer data)1824 kvp_frame_to_bare_string_helper (gpointer key __attribute__ ((unused)),
1825 gpointer value, gpointer data)
1826 {
1827 gchar **str = (gchar **) data;
1828 *str =
1829 g_strdup_printf ("%s",
1830 kvp_value_to_bare_string ((KvpValue *) value));
1831 }
1832
1833 gchar *
kvp_value_to_bare_string(const KvpValue * val)1834 kvp_value_to_bare_string (const KvpValue * val)
1835 {
1836 gchar *tmp1;
1837 gchar *tmp2;
1838 const gchar *ctmp;
1839
1840 g_return_val_if_fail (val, NULL);
1841 tmp1 = g_strdup ("");
1842 switch (kvp_value_get_type (val))
1843 {
1844 case KVP_TYPE_GINT64:
1845 {
1846 return g_strdup_printf ("%" G_GINT64_FORMAT,
1847 kvp_value_get_gint64 (val));
1848 break;
1849 }
1850 case KVP_TYPE_DOUBLE:
1851 {
1852 return g_strdup_printf ("(%g)", kvp_value_get_double (val));
1853 break;
1854 }
1855 case KVP_TYPE_NUMERIC:
1856 {
1857 tmp1 = qof_numeric_to_string (kvp_value_get_numeric (val));
1858 tmp2 = g_strdup_printf ("%s", tmp1 ? tmp1 : "");
1859 g_free (tmp1);
1860 return tmp2;
1861 break;
1862 }
1863 case KVP_TYPE_STRING:
1864 {
1865 tmp1 = kvp_value_get_string (val);
1866 return g_strdup_printf ("%s", tmp1 ? tmp1 : "");
1867 break;
1868 }
1869 case KVP_TYPE_GUID:
1870 {
1871 ctmp = guid_to_string (kvp_value_get_guid (val));
1872 tmp2 = g_strdup_printf ("%s", ctmp ? ctmp : "");
1873 return tmp2;
1874 break;
1875 }
1876 case KVP_TYPE_BOOLEAN :
1877 return (kvp_value_get_boolean (val)) ? "TRUE" : "FALSE";
1878 case KVP_TYPE_BINARY:
1879 {
1880 guint64 len;
1881 gpointer data;
1882 data = kvp_value_get_binary (val, &len);
1883 tmp1 = binary_to_string (data, len);
1884 return g_strdup_printf ("%s", tmp1 ? tmp1 : "");
1885 break;
1886 }
1887 case KVP_TYPE_GLIST:
1888 /* borked. kvp_value_glist_to_string is a debug fcn */
1889 {
1890 tmp1 = kvp_value_glist_to_string (kvp_value_get_glist (val));
1891 tmp2 = g_strdup_printf ("%s", tmp1 ? tmp1 : "");
1892 g_free (tmp1);
1893 return tmp2;
1894 break;
1895 }
1896 case KVP_TYPE_FRAME:
1897 {
1898 KvpFrame *frame;
1899
1900 frame = kvp_value_get_frame (val);
1901 if (frame->hash)
1902 {
1903 tmp1 = g_strdup ("");
1904 g_hash_table_foreach (frame->hash,
1905 kvp_frame_to_bare_string_helper, &tmp1);
1906 }
1907 return tmp1;
1908 break;
1909 }
1910 default:
1911 return g_strdup_printf (" ");
1912 break;
1913 }
1914 }
1915
1916 gchar *
kvp_value_to_string(const KvpValue * val)1917 kvp_value_to_string (const KvpValue * val)
1918 {
1919 gchar *tmp1;
1920 gchar *tmp2;
1921 const gchar *ctmp;
1922
1923 g_return_val_if_fail (val, NULL);
1924
1925 switch (kvp_value_get_type (val))
1926 {
1927 case KVP_TYPE_GINT64:
1928 {
1929 return g_strdup_printf ("KVP_VALUE_GINT64(%" G_GINT64_FORMAT ")",
1930 kvp_value_get_gint64 (val));
1931 break;
1932 }
1933 case KVP_TYPE_DOUBLE:
1934 {
1935 return g_strdup_printf ("KVP_VALUE_DOUBLE(%g)",
1936 kvp_value_get_double (val));
1937 break;
1938 }
1939 case KVP_TYPE_NUMERIC:
1940 {
1941 tmp1 = qof_numeric_to_string (kvp_value_get_numeric (val));
1942 tmp2 = g_strdup_printf ("KVP_VALUE_NUMERIC(%s)", tmp1 ? tmp1 : "");
1943 g_free (tmp1);
1944 return tmp2;
1945 break;
1946 }
1947 case KVP_TYPE_STRING:
1948 {
1949 tmp1 = kvp_value_get_string (val);
1950 return g_strdup_printf ("KVP_VALUE_STRING(%s)", tmp1 ? tmp1 : "");
1951 break;
1952 }
1953 case KVP_TYPE_GUID:
1954 {
1955 /* THREAD-UNSAFE */
1956 ctmp = guid_to_string (kvp_value_get_guid (val));
1957 tmp2 = g_strdup_printf ("KVP_VALUE_GUID(%s)", ctmp ? ctmp : "");
1958 return tmp2;
1959 break;
1960 }
1961 case KVP_TYPE_BINARY:
1962 {
1963 guint64 len;
1964 gpointer data;
1965 data = kvp_value_get_binary (val, &len);
1966 tmp1 = binary_to_string (data, len);
1967 return g_strdup_printf ("KVP_VALUE_BINARY(%s)",
1968 tmp1 ? tmp1 : "");
1969 break;
1970 }
1971 case KVP_TYPE_GLIST:
1972 {
1973 tmp1 = kvp_value_glist_to_string (kvp_value_get_glist (val));
1974 tmp2 = g_strdup_printf ("KVP_VALUE_GLIST(%s)", tmp1 ? tmp1 : "");
1975 g_free (tmp1);
1976 return tmp2;
1977 break;
1978 }
1979 case KVP_TYPE_FRAME:
1980 {
1981 tmp1 = kvp_frame_to_string (kvp_value_get_frame (val));
1982 tmp2 = g_strdup_printf ("KVP_VALUE_FRAME(%s)", tmp1 ? tmp1 : "");
1983 g_free (tmp1);
1984 return tmp2;
1985 break;
1986 }
1987 default:
1988 return g_strdup_printf (" ");
1989 break;
1990 }
1991 }
1992
1993 static void
kvp_frame_to_string_helper(gpointer key,gpointer value,gpointer data)1994 kvp_frame_to_string_helper (gpointer key, gpointer value, gpointer data)
1995 {
1996 gchar *tmp_val;
1997 gchar **str = (gchar **) data;
1998 gchar *old_data = *str;
1999
2000 tmp_val = kvp_value_to_string ((KvpValue *) value);
2001
2002 *str = g_strdup_printf ("%s %s => %s,\n",
2003 *str ? *str : "", key ? (gchar *) key : "", tmp_val ? tmp_val : "");
2004
2005 g_free (old_data);
2006 g_free (tmp_val);
2007 }
2008
2009 gchar *
kvp_frame_to_string(const KvpFrame * frame)2010 kvp_frame_to_string (const KvpFrame * frame)
2011 {
2012 gchar *tmp1;
2013
2014 g_return_val_if_fail (frame != NULL, NULL);
2015
2016 tmp1 = g_strdup_printf ("{\n");
2017
2018 if (frame->hash)
2019 g_hash_table_foreach (frame->hash, kvp_frame_to_string_helper,
2020 &tmp1);
2021 {
2022 gchar *tmp2;
2023 tmp2 = g_strdup_printf ("%s}\n", tmp1);
2024 g_free (tmp1);
2025 tmp1 = tmp2;
2026 }
2027
2028 return tmp1;
2029 }
2030
2031 GHashTable *
kvp_frame_get_hash(const KvpFrame * frame)2032 kvp_frame_get_hash (const KvpFrame * frame)
2033 {
2034 g_return_val_if_fail (frame != NULL, NULL);
2035 return frame->hash;
2036 }
2037
2038 /* ========================== END OF FILE ======================= */
2039