GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sixtp-dom-parsers.c
1 /********************************************************************
2  * sixtp-dom-parsers.c *
3  * Copyright 2001 Gnumatic, Inc. *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact: *
17  * *
18  * Free Software Foundation Voice: +1-617-542-5942 *
19  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20  * Boston, MA 02110-1301, USA [email protected] *
21  * *
22  ********************************************************************/
23 
24 #include "config.h"
25 
26 #include <glib.h>
27 #include <string.h>
28 
29 #include "gnc-xml-helper.h"
30 #include "gnc-engine.h"
31 #include "sixtp-utils.h"
32 #include "sixtp-dom-parsers.h"
33 
34 static QofLogModule log_module = GNC_MOD_IO;
35 
36 GncGUID*
37 dom_tree_to_guid(xmlNodePtr node)
38 {
39  if (!node->properties)
40  {
41  return NULL;
42  }
43 
44  if (strcmp((char*) node->properties->name, "type") != 0)
45  {
46  PERR("Unknown attribute for id tag: %s",
47  node->properties->name ?
48  (char *) node->properties->name : "(null)");
49  return NULL;
50  }
51 
52  {
53  char *type;
54 
55  type = (char*)xmlNodeGetContent (node->properties->xmlAttrPropertyValue);
56 
57  /* handle new and guid the same for the moment */
58  if ((g_strcmp0("guid", type) == 0) || (g_strcmp0("new", type) == 0))
59  {
60  GncGUID *gid = g_new(GncGUID, 1);
61  char *guid_str;
62 
63  guid_str = (char*)xmlNodeGetContent (node->xmlChildrenNode);
64  string_to_guid(guid_str, gid);
65  xmlFree (guid_str);
66  xmlFree (type);
67  return gid;
68  }
69  else
70  {
71  PERR("Unknown type %s for attribute type for tag %s",
72  type ? type : "(null)",
73  node->properties->name ?
74  (char *) node->properties->name : "(null)");
75  xmlFree (type);
76  return NULL;
77  }
78  }
79 }
80 
81 KvpValue*
82 dom_tree_to_integer_kvp_value(xmlNodePtr node)
83 {
84  gchar *text;
85  gint64 daint;
86  KvpValue* ret = NULL;
87 
88  text = dom_tree_to_text(node);
89 
90  if (string_to_gint64(text, &daint))
91  {
92  ret = kvp_value_new_gint64(daint);
93  }
94  g_free(text);
95 
96  return ret;
97 }
98 
99 gboolean
100 dom_tree_to_integer(xmlNodePtr node, gint64 *daint)
101 {
102  gchar *text;
103  gboolean ret;
104 
105  text = dom_tree_to_text(node);
106 
107  ret = string_to_gint64(text, daint);
108 
109  g_free (text);
110 
111  return ret;
112 }
113 
114 gboolean
115 dom_tree_to_guint16(xmlNodePtr node, guint16 *i)
116 {
117  gboolean ret;
118  guint j = 0;
119 
120  ret = dom_tree_to_guint(node, &j);
121  *i = (guint16) j;
122  return ret;
123 }
124 
125 gboolean
126 dom_tree_to_guint(xmlNodePtr node, guint *i)
127 {
128  gchar *text, *endptr;
129  gboolean ret;
130 
131  text = dom_tree_to_text(node);
132  /* In spite of the strange string_to_gint64 function, I'm just
133  going to use strtoul here until someone shows me the error of
134  my ways. -CAS */
135  *i = (guint) strtoul(text, &endptr, 0);
136  ret = (endptr != text);
137  g_free(text);
138  return ret;
139 }
140 
141 gboolean
142 dom_tree_to_boolean(xmlNodePtr node, gboolean* b)
143 {
144  gchar* text;
145 
146  text = dom_tree_to_text(node);
147  if (g_ascii_strncasecmp(text, "true", 4) == 0)
148  {
149  *b = TRUE;
150  return TRUE;
151  }
152  else if (g_ascii_strncasecmp(text, "false", 5) == 0)
153  {
154  *b = FALSE;
155  return TRUE;
156  }
157  else
158  {
159  *b = FALSE;
160  return FALSE;
161  }
162 }
163 
164 KvpValue*
165 dom_tree_to_double_kvp_value(xmlNodePtr node)
166 {
167  gchar *text;
168  double dadoub;
169  KvpValue *ret = NULL;
170 
171  text = dom_tree_to_text(node);
172 
173  if (string_to_double(text, &dadoub))
174  {
175  ret = kvp_value_new_double(dadoub);
176  }
177 
178  g_free(text);
179 
180  return ret;
181 }
182 
183 KvpValue*
184 dom_tree_to_numeric_kvp_value(xmlNodePtr node)
185 {
186  gnc_numeric *danum;
187  KvpValue *ret = NULL;
188 
189  danum = dom_tree_to_gnc_numeric(node);
190 
191  if (danum)
192  {
193  ret = kvp_value_new_gnc_numeric(*danum);
194  }
195 
196  g_free(danum);
197 
198  return ret;
199 }
200 
201 KvpValue*
202 dom_tree_to_string_kvp_value(xmlNodePtr node)
203 {
204  gchar *datext;
205  KvpValue *ret = NULL;
206 
207  datext = dom_tree_to_text(node);
208  if (datext)
209  {
210  ret = kvp_value_new_string(datext);
211  }
212 
213  g_free(datext);
214 
215  return ret;
216 }
217 
218 KvpValue*
219 dom_tree_to_guid_kvp_value(xmlNodePtr node)
220 {
221  GncGUID *daguid;
222  KvpValue *ret = NULL;
223 
224  daguid = dom_tree_to_guid(node);
225  if (daguid)
226  {
227  ret = kvp_value_new_guid(daguid);
228  }
229 
230  g_free(daguid);
231 
232  return ret;
233 }
234 
235 KvpValue*
236 dom_tree_to_timespec_kvp_value (xmlNodePtr node)
237 {
238  Timespec ts;
239  KvpValue * ret = NULL;
240 
241  ts = dom_tree_to_timespec (node);
242  if (ts.tv_sec || ts.tv_nsec)
243  {
244  ret = kvp_value_new_timespec (ts);
245  }
246  return ret;
247 }
248 
249 KvpValue*
250 dom_tree_to_gdate_kvp_value (xmlNodePtr node)
251 {
252  GDate *date;
253  KvpValue *ret = NULL;
254 
255  date = dom_tree_to_gdate(node);
256 
257  if (date)
258  {
259  ret = kvp_value_new_gdate(*date);
260  }
261 
262  g_free(date);
263 
264  return ret;
265 }
266 
267 gboolean
268 string_to_binary(const gchar *str, void **v, guint64 *data_len)
269 {
270  guint64 str_len;
271  guchar *data;
272  unsigned int i, j;
273 
274  g_return_val_if_fail(v != NULL, FALSE);
275  g_return_val_if_fail(data_len != NULL, FALSE);
276 
277  str_len = strlen(str);
278 
279  /* Since no whitespace is allowed and hex encoding is 2 text chars
280  per binary char, the result must be half the input size and the
281  input size must be even. */
282  if ((str_len % 2) != 0)
283  return(FALSE);
284  *data_len = str_len / 2;
285  data = g_new0(guchar, *data_len);
286 
287  for (j = 0, i = 0; i < str_len; i += 2, j++)
288  {
289  gchar tmpstr[3];
290  long int converted;
291 
292  tmpstr[0] = str[i];
293  tmpstr[1] = str[i + 1];
294  tmpstr[2] = '\0';
295 
296  converted = strtol(tmpstr, NULL, 16);
297 
298  data[j] = (unsigned char)converted;
299  }
300 
301  *v = data;
302 
303  return(TRUE);
304 }
305 
306 KvpValue*
307 dom_tree_to_list_kvp_value(xmlNodePtr node)
308 {
309  GList *list = NULL;
310  xmlNodePtr mark;
311  KvpValue *ret = NULL;
312 
313  for (mark = node->xmlChildrenNode; mark; mark = mark->next)
314  {
315  KvpValue *new_val;
316 
317  if (g_strcmp0 ((char*)mark->name, "text") == 0)
318  continue;
319 
320  new_val = dom_tree_to_kvp_value(mark);
321  if (new_val)
322  {
323  list = g_list_append(list, (gpointer)new_val);
324  }
325  }
326 
327  ret = kvp_value_new_glist_nc(list);
328 
329  return ret;
330 }
331 
332 KvpValue*
333 dom_tree_to_frame_kvp_value(xmlNodePtr node)
334 {
335  KvpFrame *frame;
336  KvpValue *ret = NULL;
337 
338  frame = dom_tree_to_kvp_frame(node);
339 
340  if (frame)
341  {
342  ret = kvp_value_new_frame(frame);
343  }
344 
345  kvp_frame_delete(frame);
346 
347  return ret;
348 }
349 
350 
352 {
353  gchar *tag;
354  KvpValue* (*converter)(xmlNodePtr node);
355 };
356 
357 struct kvp_val_converter val_converters[] =
358 {
359  { "integer", dom_tree_to_integer_kvp_value },
360  { "double", dom_tree_to_double_kvp_value },
361  { "numeric", dom_tree_to_numeric_kvp_value },
362  { "string", dom_tree_to_string_kvp_value },
363  { "guid", dom_tree_to_guid_kvp_value },
364  { "timespec", dom_tree_to_timespec_kvp_value },
365  { "gdate", dom_tree_to_gdate_kvp_value },
366  { "list", dom_tree_to_list_kvp_value },
367  { "frame", dom_tree_to_frame_kvp_value },
368  { 0, 0 },
369 };
370 
371 KvpValue*
372 dom_tree_to_kvp_value(xmlNodePtr node)
373 {
374  xmlChar *xml_type;
375  gchar *type;
376  struct kvp_val_converter *mark;
377  KvpValue *ret = NULL;
378 
379  xml_type = xmlGetProp(node, BAD_CAST "type");
380  if (xml_type)
381  {
382  type = g_strdup ((char*) xml_type);
383  xmlFree (xml_type);
384  }
385  else
386  type = NULL;
387 
388  for (mark = val_converters; mark->tag; mark++)
389  {
390  if (g_strcmp0(type, mark->tag) == 0)
391  {
392  ret = (mark->converter)(node);
393  }
394  }
395 
396  if (!mark->tag)
397  {
398  /* FIXME: deal with unknown type tag here */
399  }
400 
401  g_free(type);
402 
403  return ret;
404 }
405 
406 gboolean
407 dom_tree_to_kvp_frame_given(xmlNodePtr node, KvpFrame *frame)
408 {
409  xmlNodePtr mark;
410 
411  g_return_val_if_fail(node, FALSE);
412  g_return_val_if_fail(frame, FALSE);
413 
414  for (mark = node->xmlChildrenNode; mark; mark = mark->next)
415  {
416  if (g_strcmp0((char*)mark->name, "slot") == 0)
417  {
418  xmlNodePtr mark2;
419  gchar *key = NULL;
420  KvpValue *val = NULL;
421 
422  for (mark2 = mark->xmlChildrenNode; mark2; mark2 = mark2->next)
423  {
424  if (g_strcmp0((char*)mark2->name, "slot:key") == 0)
425  {
426  key = dom_tree_to_text(mark2);
427  }
428  else if (g_strcmp0((char*)mark2->name, "slot:value") == 0)
429  {
430  val = dom_tree_to_kvp_value(mark2);
431  }
432  else
433  {
434  /* FIXME: should put some error here.
435  * But ignore text type! */
436  }
437  }
438 
439  if (key)
440  {
441  if (val)
442  {
443  kvp_frame_set_slot_nc(frame, key, val);
444  }
445  else
446  {
447  /* FIXME: should put some error here */
448  }
449  g_free(key);
450  }
451  }
452  }
453 
454  return TRUE;
455 }
456 
457 
458 KvpFrame*
459 dom_tree_to_kvp_frame(xmlNodePtr node)
460 {
461  KvpFrame *ret;
462 
463  g_return_val_if_fail(node, NULL);
464 
465  ret = kvp_frame_new();
466 
467  if (dom_tree_to_kvp_frame_given(node, ret))
468  return ret;
469 
470  kvp_frame_delete(ret);
471 
472  return NULL;
473 }
474 
475 
476 gchar *
477 dom_tree_to_text(xmlNodePtr tree)
478 {
479  /* Expect *only* text and comment sibling nodes in the given tree --
480  which actually may only be a "list". i.e. if you're trying to
481  extract bar from <foo>bar</foo>, pass in <foo>->xmlChildrenNode
482  to this function. This expectation is different from the rest of
483  the dom_tree_to_* converters...
484 
485  Ignores comment nodes and collapse text nodes into one string.
486  Returns NULL if expectations are unsatisfied.
487  */
488  gchar *result;
489  gchar *temp;
490 
491  g_return_val_if_fail(tree, NULL);
492 
493  /* no nodes means it's an empty string text */
494  if (!tree->xmlChildrenNode)
495  {
496  DEBUG("No children");
497  return g_strdup("");
498  }
499 
500  temp = (char*)xmlNodeListGetString (NULL, tree->xmlChildrenNode, TRUE);
501  if (!temp)
502  {
503  DEBUG("Null string");
504  return NULL;
505  }
506 
507  DEBUG("node string [%s]", (temp == NULL ? "(null)" : temp));
508  result = g_strdup (temp);
509  xmlFree (temp);
510  return result;
511 }
512 
514 dom_tree_to_gnc_numeric(xmlNodePtr node)
515 {
516  gchar *content = dom_tree_to_text(node);
517  gnc_numeric *ret;
518  if (!content)
519  return NULL;
520 
521  ret = g_new(gnc_numeric, 1);
522 
523  if (string_to_gnc_numeric(content, ret))
524  {
525  g_free(content);
526  return ret;
527  }
528  else
529  {
530  g_free(content);
531  g_free(ret);
532  return NULL;
533  }
534 }
535 
536 static inline Timespec
537 timespec_failure(Timespec ts)
538 {
539  ts.tv_sec = 0;
540  ts.tv_nsec = 0;
541  return ts;
542 }
543 
544 
545 Timespec
546 dom_tree_to_timespec(xmlNodePtr node)
547 {
548  /* Turn something like this
549 
550  <date-posted>
551  <s>Mon, 05 Jun 2000 23:16:19 -0500</s>
552  <ns>658864000</ns>
553  </date-posted>
554 
555  into a Timespec. If this returns FALSE, the effects on *ts are
556  undefined. The XML is valid if it has at least one of <s> or <ns>
557  and no more than one of each. Order is irrelevant. */
558 
559  Timespec ret;
560  gboolean seen_s = FALSE;
561  gboolean seen_ns = FALSE;
562  xmlNodePtr n;
563 
564 
565  ret.tv_sec = 0;
566  ret.tv_nsec = 0;
567  for (n = node->xmlChildrenNode; n; n = n->next)
568  {
569  switch (n->type)
570  {
571  case XML_COMMENT_NODE:
572  case XML_TEXT_NODE:
573  break;
574  case XML_ELEMENT_NODE:
575  if (g_strcmp0("ts:date", (char*)n->name) == 0)
576  {
577  if (seen_s)
578  {
579  return timespec_failure(ret);
580  }
581  else
582  {
583  gchar *content = dom_tree_to_text(n);
584  if (!content)
585  {
586  return timespec_failure(ret);
587  }
588 
589  if (!string_to_timespec_secs(content, &ret))
590  {
591  g_free(content);
592  return timespec_failure(ret);
593  }
594  g_free(content);
595  seen_s = TRUE;
596  }
597  }
598  else if (g_strcmp0("ts:ns", (char*)n->name) == 0)
599  {
600  if (seen_ns)
601  {
602  return timespec_failure(ret);
603  }
604  else
605  {
606  gchar *content = dom_tree_to_text(n);
607  if (!content)
608  {
609  return timespec_failure(ret);
610  }
611 
612  if (!string_to_timespec_nsecs(content, &ret))
613  {
614  g_free(content);
615  return timespec_failure(ret);
616  }
617  g_free(content);
618  seen_ns = TRUE;
619  }
620  }
621  break;
622  default:
623  PERR("unexpected sub-node.");
624  return timespec_failure(ret);
625  break;
626  }
627  }
628 
629  if (!seen_s)
630  {
631  PERR("no ts:date node found.");
632  return timespec_failure(ret);
633  }
634 
635  return ret;
636 }
637 
638 GDate*
639 dom_tree_to_gdate(xmlNodePtr node)
640 {
641  /* Turn something like this
642 
643  <sx:startdate>
644  <gdate>2001-04-03</gdate>
645  </sx:startdate>
646 
647  into a GDate. If the xml is invalid, returns NULL. */
648 
649  GDate *ret;
650  gboolean seen_date = FALSE;
651  xmlNodePtr n;
652 
653  /* creates an invalid date */
654  ret = g_date_new();
655 
656  for (n = node->xmlChildrenNode; n; n = n->next)
657  {
658  switch (n->type)
659  {
660  case XML_COMMENT_NODE:
661  case XML_TEXT_NODE:
662  break;
663  case XML_ELEMENT_NODE:
664  if (g_strcmp0("gdate", (char*)n->name) == 0)
665  {
666  if (seen_date)
667  {
668  goto failure;
669  }
670  else
671  {
672  gchar *content = dom_tree_to_text(n);
673  gint year, month, day;
674  if (!content)
675  {
676  goto failure;
677  }
678 
679  if (sscanf(content, "%d-%d-%d", &year, &month, &day ) != 3)
680  {
681  g_free(content);
682  goto failure;
683  }
684  g_free(content);
685  seen_date = TRUE;
686  g_date_set_dmy( ret, day, month, year );
687  if ( !g_date_valid( ret ) )
688  {
689  PWARN("invalid date");
690  goto failure;
691  }
692  }
693  }
694  break;
695  default:
696  PERR("unexpected sub-node.");
697  goto failure;
698  }
699  }
700 
701  if (!seen_date)
702  {
703  PWARN("no gdate node found.");
704  goto failure;
705  }
706 
707  return ret;
708 failure:
709  g_date_free( ret );
710  return NULL;
711 }
712 
713 
715 dom_tree_to_commodity_ref_no_engine(xmlNodePtr node, QofBook *book)
716 {
717  /* Turn something like this
718 
719  <currency>
720  <cmdty:space>NASDAQ</cmdty:space>
721  <cmdty:id>LNUX</cmdty:space>
722  </currency>
723 
724  into a gnc_commodity*, returning NULL on failure. Both sub-nodes
725  are required, though for now, order is irrelevant. */
726 
727  gnc_commodity *c = NULL;
728  gchar *space_str = NULL;
729  gchar *id_str = NULL;
730  xmlNodePtr n;
731 
732  if (!node) return NULL;
733  if (!node->xmlChildrenNode) return NULL;
734 
735  for (n = node->xmlChildrenNode; n; n = n->next)
736  {
737  switch (n->type)
738  {
739  case XML_COMMENT_NODE:
740  case XML_TEXT_NODE:
741  break;
742  case XML_ELEMENT_NODE:
743  if (g_strcmp0("cmdty:space", (char*)n->name) == 0)
744  {
745  if (space_str)
746  {
747  return NULL;
748  }
749  else
750  {
751  gchar *content = dom_tree_to_text(n);
752  if (!content) return NULL;
753  space_str = content;
754  }
755  }
756  else if (g_strcmp0("cmdty:id", (char*)n->name) == 0)
757  {
758  if (id_str)
759  {
760  return NULL;
761  }
762  else
763  {
764  gchar *content = dom_tree_to_text(n);
765  if (!content) return NULL;
766  id_str = content;
767  }
768  }
769  break;
770  default:
771  PERR("unexpected sub-node.");
772  return NULL;
773  break;
774  }
775  }
776  if (!(space_str && id_str))
777  {
778  c = NULL;
779  }
780  else
781  {
782  g_strstrip(space_str);
783  g_strstrip(id_str);
784  c = gnc_commodity_new(book, NULL, space_str, id_str, NULL, 0);
785  }
786 
787  g_free(space_str);
788  g_free(id_str);
789 
790  return c;
791 }
792 
794 dom_tree_to_commodity_ref(xmlNodePtr node, QofBook *book)
795 {
796  gnc_commodity *daref;
797  gnc_commodity *ret;
799 
800  daref = dom_tree_to_commodity_ref_no_engine(node, book);
801 
802  table = gnc_commodity_table_get_table (book);
803 
804  g_return_val_if_fail (table != NULL, NULL);
805 
806  ret = gnc_commodity_table_lookup (table,
809 
810  gnc_commodity_destroy(daref);
811 
812  g_return_val_if_fail (ret != NULL, NULL);
813 
814  return ret;
815 }
816 
817 /***********************************************************************/
818 /* generic parser */
819 
820 static inline void
821 dom_tree_handlers_reset(struct dom_tree_handler *handlers)
822 {
823  for (; handlers->tag != NULL; handlers++)
824  {
825  handlers->gotten = 0;
826  }
827 }
828 
829 static inline gboolean
830 dom_tree_handlers_all_gotten_p(struct dom_tree_handler *handlers)
831 {
832  gboolean ret = TRUE;
833  for (; handlers->tag != NULL; handlers++)
834  {
835  if (handlers->required && ! handlers->gotten)
836  {
837  PERR("Not defined and it should be: %s",
838  handlers->tag ? handlers->tag : "(null)");
839  ret = FALSE;
840  }
841  }
842  return ret;
843 }
844 
845 
846 static inline gboolean
847 gnc_xml_set_data(const gchar* tag, xmlNodePtr node, gpointer item,
848  struct dom_tree_handler *handlers)
849 {
850  for (; handlers->tag != NULL; handlers++)
851  {
852  if (g_strcmp0(tag, handlers->tag) == 0)
853  {
854  (handlers->handler)(node, item);
855  handlers->gotten = TRUE;
856  break;
857  }
858  }
859 
860  if (!handlers->tag)
861  {
862  PERR("Unhandled tag: %s",
863  tag ? tag : "(null)");
864  return FALSE;
865  }
866 
867  return TRUE;
868 }
869 
870 gboolean
871 dom_tree_generic_parse(xmlNodePtr node, struct dom_tree_handler *handlers,
872  gpointer data)
873 {
874  xmlNodePtr achild;
875  gboolean successful = TRUE;
876 
877  dom_tree_handlers_reset(handlers);
878 
879  for (achild = node->xmlChildrenNode; achild; achild = achild->next)
880  {
881  /* ignore stray text nodes */
882  if (g_strcmp0 ((char*)achild->name, "text") == 0)
883  continue;
884 
885  if (!gnc_xml_set_data((char*)achild->name, achild, data, handlers))
886  {
887  PERR("gnc_xml_set_data failed");
888  successful = FALSE;
889  continue;
890  }
891  }
892 
893  if (!dom_tree_handlers_all_gotten_p(handlers))
894  {
895  PERR("didn't find all of the expected tags in the input");
896  successful = FALSE;
897  }
898 
899  return successful;
900 }
901 
902 gboolean
903 dom_tree_valid_timespec (Timespec *ts, const xmlChar *name)
904 {
905 
906  if (ts->tv_sec || ts->tv_nsec)
907  return TRUE;
908 
909  g_warning("Invalid timestamp in data file. Look for a '%s' entry "
910  "with a date of 1969-12-31 or 1970-01-01.", name);
911  return FALSE;
912 }
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
#define DEBUG(format, args...)
Definition: qoflog.h:255
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
#define PERR(format, args...)
Definition: qoflog.h:237
gboolean string_to_gnc_numeric(const gchar *str, gnc_numeric *n)
void kvp_frame_delete(KvpFrame *frame)
Definition: guid.h:65
#define PWARN(format, args...)
Definition: qoflog.h:243
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
void kvp_frame_set_slot_nc(KvpFrame *frame, const gchar *key, KvpValue *value)
#define kvp_value_new_gnc_numeric
Definition: kvp_frame.h:466
All type declarations for the whole Gnucash engine.
KvpValue * kvp_value_new_glist_nc(GList *lst)
struct KvpFrameImpl KvpFrame
Definition: kvp_frame.h:76
KvpFrame * kvp_frame_new(void)
struct KvpValueImpl KvpValue
Definition: kvp_frame.h:80
void gnc_commodity_destroy(gnc_commodity *cm)
const gchar * QofLogModule
Definition: qofid.h:89