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