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