GnuCash c935c2f+
Loading...
Searching...
No Matches
io-gncxml-v1.cpp
1/********************************************************************
2 * io-gncxml-r.c -- read XML-format gnucash data file *
3 * Copyright (C) 2000 Gnumatic, Inc. *
4 * *
5 * Initial code by Rob L. Browning 4Q 2000 *
6 * Tuneups by James LewisMoss Dec 2000 *
7 * Excessive hacking Linas Vepstas January 2001 *
8 * *
9 * This program is free software; you can redistribute it and/or *
10 * modify it under the terms of the GNU General Public License as *
11 * published by the Free Software Foundation; either version 2 of *
12 * the License, or (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License*
20 * along with this program; if not, contact: *
21 * *
22 * Free Software Foundation Voice: +1-617-542-5942 *
23 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
24 * Boston, MA 02110-1301, USA gnu@gnu.org *
25 * *
26 *******************************************************************/
27#include <guid.hpp>
28#include <config.h>
29
30#include <stdlib.h>
31#include <string.h>
32
33#include <glib.h>
34
35#include <gnc-xml-helper.h>
36#include <Account.h>
37#include <AccountP.hpp>
38#include <Query.h>
39#include <Scrub.h>
40#include <Transaction.h>
41#include <TransactionP.hpp>
42#include <TransLog.h>
43#include <gnc-pricedb.h>
44#include <gnc-pricedb-p.h>
45
46#include "io-gncxml.h"
47#include "sixtp.h"
48#include "sixtp-dom-parsers.h"
49#include "sixtp-stack.h"
50#include "sixtp-parsers.h"
51#include "sixtp-utils.h"
52
53#include <kvp-frame.hpp>
54
55/* from Transaction-xml-parser-v1.c */
56static sixtp* gnc_transaction_parser_new (void);
57
58/* from Account-xml-parser-v1.c */
59static sixtp* gnc_account_parser_new (void);
60
61/* from Ledger-xml-parser-v1.c */
62static sixtp* ledger_data_parser_new (void);
63
64/* from Commodity-xml-parser-v1.c */
65static sixtp* commodity_restore_parser_new (void);
66
67/* from Commodity-xml-parser-v1.c */
68static sixtp* generic_gnc_commodity_lookup_parser_new (void);
69
70/* from Query-xml-parser-v1.c */
71//static sixtp* query_server_parser_new (void);
72
73/* from sixtp-kvp-parser.c */
74static sixtp* kvp_frame_parser_new (void);
75
76/* from gnc-pricedb-xml-v1.c */
77static sixtp* gnc_pricedb_parser_new (void);
78
79
80typedef enum
81{
82 GNC_PARSE_ERR_NONE,
83 GNC_PARSE_ERR_BAD_VERSION,
84} GNCParseErr;
85
86typedef struct
87{
88 /* have we gotten the file version yet? */
89 gboolean seen_version;
90 gint64 version;
91
92 /* top level <gnc-data> parser - we need this so we can set it up
93 after we see the file version. */
94 sixtp* gnc_parser;
95
96 /* The book */
97 QofBook* book;
98
99 /* The root account */
100 Account* root_account;
101
102 /* The pricedb */
103 GNCPriceDB* pricedb;
104
105 /* The query */
106 // Query *query;
107
108 GNCParseErr error;
110
111
112/* result for a characters handler is shared across all character
113 handlers for a given node. result for start/end pair is shared as
114 well.
115
116 Cleaning up the results returned by children and characters
117 handlers is the user's responsibility.
118
119 results have to have cleanup pointers for exceptional failures
120
121 stack frames also have to have cleanup funcs for exceptional
122 failures after the start tag handler has been called, but before
123 the end tag handler has been called. If the end tag handler is
124 called, but returns FALSE, it is expected that the end tag handler
125 has taken care of any cleanup itself.
126
127 result cleanup functions are called for a node's children just
128 after the end handler unless should_cleanup has been set to FALSE,
129 or unless there's a failure. If there's a failure, then the
130 cleanup is left to the failure handler.
131
132
133*/
134
135static QofLogModule log_module = GNC_MOD_IO;
136
137/* ================================================================= */
138/* <version> (lineage <gnc>)
139
140 Fancy and strange - look for an integer version number. If we get
141 one, then modify the parent parser to handle the input.
142
143 this is a simple_chars_only_parser with an end handler that grabs
144 the version number and tweaks the parser, if possible.
145
146 */
147
148static gboolean
149gnc_parser_configure_for_input_version (GNCParseStatus* status, gint64 version)
150{
151
152 status->version = version;
153 status->seen_version = TRUE;
154
155 /* Check for a legal version here. */
156 if (version != 1)
157 {
158 status->error = GNC_PARSE_ERR_BAD_VERSION;
159 return (FALSE);
160 }
161
162 /* Now set up the parser based on the version. */
163
164 /* add <ledger-data> */
165 {
166 sixtp* ledger_data_pr = ledger_data_parser_new ();
167 g_return_val_if_fail (ledger_data_pr, FALSE);
168 sixtp_add_sub_parser (status->gnc_parser, "ledger-data", ledger_data_pr);
169 }
170
171 return (TRUE);
172}
173
174static gboolean
175gnc_version_end_handler (gpointer data_for_children,
176 GSList* data_from_children, GSList* sibling_data,
177 gpointer parent_data, gpointer global_data,
178 gpointer* result, const gchar* tag)
179{
180 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
181 gint64 version;
182 gboolean ok;
183 gchar* txt;
184
185 g_return_val_if_fail (pstatus, FALSE);
186 if (pstatus->seen_version) return (FALSE);
187
188 txt = concatenate_child_result_chars (data_from_children);
189 g_return_val_if_fail (txt, FALSE);
190
191 ok = string_to_gint64 (txt, &version);
192 g_free (txt);
193 g_return_val_if_fail (ok, FALSE);
194
195 if (!gnc_parser_configure_for_input_version (pstatus, version)) return (FALSE);
196
197 return (TRUE);
198}
199
200static sixtp*
201gnc_version_parser_new (void)
202{
203 return (simple_chars_only_parser_new (gnc_version_end_handler));
204}
205
206/****************************************************************************/
207/* <gnc> (lineage #f)
208
209 Takes the results from various children and puts them in the
210 global_data result structure.
211
212 from parent: NA
213 for children: NA
214 result: NA
215 -----------
216 start: NA
217 before-child: make sure we don't get two ledger-data's (not allowed ATM).
218 after-child: if a ledger-data child, parse_data->root_account = *result.
219 characters: allow_and_ignore_only_whitespace
220
221 Similarly, only one query is allowed ...
222 end: NA
223
224 cleanup-result: NA
225 cleanup-chars: NA
226 fail: NA
227 result-fail: NA
228 chars-fail: NA
229
230 */
231
232static gboolean
233gnc_parser_before_child_handler (gpointer data_for_children,
234 GSList* data_from_children,
235 GSList* sibling_data,
236 gpointer parent_data,
237 gpointer global_data,
238 gpointer* result,
239
240 const gchar* tag,
241 const gchar* child_tag)
242{
243 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
244
245 g_return_val_if_fail (pstatus, FALSE);
246
247 if (strcmp (child_tag, "ledger-data") == 0)
248 {
249 if (pstatus->root_account)
250 {
251 return (FALSE);
252 }
253 }
254
255 return (TRUE);
256}
257
258static gboolean
259gnc_parser_after_child_handler (gpointer data_for_children,
260 GSList* data_from_children,
261 GSList* sibling_data,
262 gpointer parent_data,
263 gpointer global_data,
264 gpointer* result,
265 const gchar* tag,
266 const gchar* child_tag,
267 sixtp_child_result* child_result)
268{
269 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
270 g_return_val_if_fail (pstatus, FALSE);
271
272 if (strcmp (child_tag, "ledger-data") == 0)
273 {
274 g_return_val_if_fail (child_result, FALSE);
275 g_return_val_if_fail (child_result->data, FALSE);
276 pstatus->root_account = (Account*) child_result->data;
277 child_result->should_cleanup = FALSE;
278 }
279
280 return (TRUE);
281}
282
283static sixtp*
284gnc_parser_new (void)
285{
286 return sixtp_set_any (
287 sixtp_new (), FALSE,
288 SIXTP_CHARACTERS_HANDLER_ID, allow_and_ignore_only_whitespace,
289 SIXTP_BEFORE_CHILD_HANDLER_ID, gnc_parser_before_child_handler,
290 SIXTP_AFTER_CHILD_HANDLER_ID, gnc_parser_after_child_handler,
291 SIXTP_NO_MORE_HANDLERS);
292}
293
294/* ================================================================== */
295
296static sixtp*
297gncxml_setup_for_read (GNCParseStatus* global_parse_status)
298{
299
300 sixtp* top_level_pr;
301 sixtp* gnc_pr;
302 sixtp* gnc_version_pr;
303
304 /* top-level: This is just a dummy node. It doesn't do anything.
305 For now, the result is communicated through the global_data
306 parser. */
307 top_level_pr = sixtp_new ();
308 g_return_val_if_fail (top_level_pr, FALSE);
309 sixtp_set_chars (top_level_pr, allow_and_ignore_only_whitespace);
310
311 /* <gnc> */
312 gnc_pr = gnc_parser_new ();
313 if (!gnc_pr)
314 {
315 sixtp_destroy (top_level_pr);
316 return (NULL);
317 }
318 sixtp_add_sub_parser (top_level_pr, "gnc", gnc_pr);
319
320 /* <version> */
321 gnc_version_pr = gnc_version_parser_new ();
322 if (!gnc_version_pr)
323 {
324 sixtp_destroy (top_level_pr);
325 return (NULL);
326 }
327 sixtp_add_sub_parser (gnc_pr, "version", gnc_version_pr);
328
329 global_parse_status->seen_version = FALSE;
330 global_parse_status->gnc_parser = gnc_pr;
331 global_parse_status->root_account = NULL;
332 global_parse_status->pricedb = NULL;
333 // global_parse_status->query = NULL;
334 global_parse_status->error = GNC_PARSE_ERR_NONE;
335
336 return top_level_pr;
337}
338
339/* ================================================================== */
340
341gboolean
342qof_session_load_from_xml_file (QofBook* book, const char* filename)
343{
344 gboolean parse_ok;
345 gpointer parse_result = NULL;
346 sixtp* top_level_pr;
347 GNCParseStatus global_parse_status;
348 Account* root;
349
350 global_parse_status.book = book;
351 g_return_val_if_fail (book, FALSE);
352 g_return_val_if_fail (filename, FALSE);
353
354 xaccDisableDataScrubbing ();
355 top_level_pr = gncxml_setup_for_read (&global_parse_status);
356 g_return_val_if_fail (top_level_pr, FALSE);
357
358 parse_ok = sixtp_parse_file (top_level_pr,
359 filename,
360 NULL,
361 &global_parse_status,
362 &parse_result);
363
364 sixtp_destroy (top_level_pr);
365 xaccEnableDataScrubbing ();
366
367 if (parse_ok)
368 {
369 if (!global_parse_status.root_account) return FALSE;
370
371 root = global_parse_status.root_account;
372 gnc_book_set_root_account (book, root);
373
374 /* Fix account and transaction commodities */
376
377 /* Fix split amount/value */
378 xaccAccountTreeScrubSplits (root);
379
380 return (TRUE);
381 }
382 else
383 {
384 return (FALSE);
385 }
386}
387
388/* ================================================================== */
389
390gboolean
391gnc_is_xml_data_file (const gchar* filename)
392{
393 if ((gnc_is_our_xml_file (filename, NULL)) == GNC_BOOK_XML1_FILE)
394 return TRUE;
395 return FALSE;
396}
397
398/* ================================================================== */
399#include "qof.h"
400
401/****************************************************************************/
402/* <kvp-frame>
403
404 A collection of node functions intended to parse a sub-node set
405 that looks like this:
406
407 <kvp-frame>
408 <s>
409 <k>notes</k>
410 <string>foo</string>
411 </s>
412 <s>
413 <k>temp</k>
414 <gint64>97</gint64>
415 </s>
416 </kvp-frame>
417
418 and return a KvpFrame*. The start handler for the top allocates
419 the KvpFrame* and passes it to the children. The <s> blocks add
420 slots according to their <k> (key) and value blocks.
421
422 FIXME: right now this is totally inappropriate for cases where we
423 want to read in a set of new values that should "merge" with the
424 existing values. This is only appropriate for wholesale
425 replacement of the slots.
426
427*/
428
429/* kvp-frame [value] handlers
430
431 Handle the possible values. Each value handler is expected to
432 parse it's subtree and return an appropriate kvp_value* in its
433 result. The <kvp-frame> <slot> handler will then cram it where it
434 belongs. */
435
436
437static void
438kvp_value_result_cleanup (sixtp_child_result* cr)
439{
440 KvpValue* v = static_cast<KvpValue*> (cr->data);
441 if (v) delete v;
442}
443
444static sixtp*
445simple_kvp_value_parser_new (sixtp_end_handler end_handler)
446{
447 return sixtp_set_any (sixtp_new (), FALSE,
448 SIXTP_CHARACTERS_HANDLER_ID,
449 generic_accumulate_chars,
450 SIXTP_END_HANDLER_ID, end_handler,
451 SIXTP_CLEANUP_RESULT_ID, kvp_value_result_cleanup,
452 SIXTP_CLEANUP_CHARS_ID, sixtp_child_free_data,
453 SIXTP_RESULT_FAIL_ID, kvp_value_result_cleanup,
454 SIXTP_CHARS_FAIL_ID, sixtp_child_free_data,
455 SIXTP_NO_MORE_HANDLERS);
456}
457
458/* <gint64> - gint64 kvp_value parser.
459
460 input: NA
461 returns: gint64 kvp_value
462
463 start: NA
464 chars: generic_accumulate_chars.
465 end: convert chars to gint64 kvp_value* if possible and return.
466
467 cleanup-result: kvp_value_delete.
468 cleanup-chars: g_free (for chars)
469 fail: NA
470 result-fail: kvp_value_delete
471 chars-fail: g_free (for chars)
472
473 */
474
475static gboolean
476string_to_gnc_numeric(const gchar* str, gnc_numeric *n)
477{
478 *n = gnc_numeric_from_string (str);
479 return (!gnc_numeric_check (*n));
480}
481
482/* ------------------------------------------------------------ */
483/* generic type copnversion for kvp types */
484#define KVP_CVT_VALUE(TYPE) \
485{ \
486 gchar *txt = NULL; \
487 TYPE val; \
488 KvpValue *kvpv; \
489 gboolean ok; \
490 \
491 txt = concatenate_child_result_chars(data_from_children); \
492 g_return_val_if_fail(txt, FALSE); \
493 \
494 ok = (gboolean) string_to_##TYPE(txt, &val); \
495 g_free(txt); \
496 g_return_val_if_fail(ok, FALSE); \
497 \
498 kvpv = new KvpValue{val}; \
499 g_return_val_if_fail(kvpv, FALSE); \
500 \
501 *result = kvpv; \
502 return(TRUE); \
503}
504/* ------------------------------------------------------------ */
505
506static gboolean
507gint64_kvp_value_end_handler (gpointer data_for_children,
508 GSList* data_from_children,
509 GSList* sibling_data,
510 gpointer parent_data,
511 gpointer global_data,
512 gpointer* result,
513 const gchar* tag)
514{
515 KVP_CVT_VALUE (gint64);
516}
517
518
519static sixtp*
520gint64_kvp_value_parser_new (void)
521{
522 return (simple_kvp_value_parser_new (gint64_kvp_value_end_handler));
523}
524
525static gboolean
526double_kvp_value_end_handler (gpointer data_for_children,
527 GSList* data_from_children,
528 GSList* sibling_data,
529 gpointer parent_data,
530 gpointer global_data,
531 gpointer* result,
532 const gchar* tag)
533{
534 KVP_CVT_VALUE (double);
535}
536
537static sixtp*
538double_kvp_value_parser_new (void)
539{
540 return (simple_kvp_value_parser_new (double_kvp_value_end_handler));
541}
542
543static gboolean
544gnc_numeric_kvp_value_end_handler (gpointer data_for_children,
545 GSList* data_from_children,
546 GSList* sibling_data,
547 gpointer parent_data,
548 gpointer global_data,
549 gpointer* result,
550 const gchar* tag)
551{
552 KVP_CVT_VALUE (gnc_numeric);
553}
554
555static sixtp*
556gnc_numeric_kvp_value_parser_new (void)
557{
558 return (simple_kvp_value_parser_new (gnc_numeric_kvp_value_end_handler));
559}
560
561static gboolean
562string_kvp_value_end_handler (gpointer data_for_children,
563 GSList* data_from_children,
564 GSList* sibling_data,
565 gpointer parent_data,
566 gpointer global_data,
567 gpointer* result,
568 const gchar* tag)
569{
570 gchar* txt = NULL;
571 KvpValue* kvpv;
572
573 txt = concatenate_child_result_chars (data_from_children);
574 g_return_val_if_fail (txt, FALSE);
575
576 kvpv = new KvpValue {g_strdup (txt)};
577 g_free (txt);
578 g_return_val_if_fail (kvpv, FALSE);
579
580 *result = kvpv;
581 return (TRUE);
582}
583
584static sixtp*
585string_kvp_value_parser_new (void)
586{
587 return (simple_kvp_value_parser_new (string_kvp_value_end_handler));
588}
589
590/* the guid handler is almost the same as above, but has
591 * inconsistent type handling */
592static gboolean
593guid_kvp_value_end_handler (gpointer data_for_children,
594 GSList* data_from_children,
595 GSList* sibling_data,
596 gpointer parent_data,
597 gpointer global_data,
598 gpointer* result,
599 const gchar* tag)
600{
601 gchar* txt = NULL;
602 GncGUID val;
603 KvpValue* kvpv;
604 gboolean ok;
605
606 txt = concatenate_child_result_chars (data_from_children);
607 g_return_val_if_fail (txt, FALSE);
608
609 ok = string_to_guid (txt, &val);
610 g_free (txt);
611
612 g_return_val_if_fail (ok, FALSE);
613
614 kvpv = new KvpValue {guid_copy (&val)};
615 g_return_val_if_fail (kvpv, FALSE);
616
617 *result = kvpv;
618 return (TRUE);
619}
620
621static sixtp*
622guid_kvp_value_parser_new (void)
623{
624 return (simple_kvp_value_parser_new (guid_kvp_value_end_handler));
625}
626
627/*********************************/
628/* glist kvp-value handler
629 */
630
631/* <glist> (lineage <s> <kvp-frame>)
632 input: NA
633 returns: glist kvp_value
634
635 start: NA
636 chars: allow_and_ignore_only_whitespace
637 end: convert the child list pointer to a glist kvp_value and return.
638
639 cleanup-result: kvp_value_delete
640 cleanup-chars: NA
641 fail: NA
642 result-fail: kvp_value_delete
643 chars-fail: NA
644
645 */
646
647
648static gboolean
649glist_kvp_value_end_handler (gpointer data_for_children,
650 GSList* data_from_children, GSList* sibling_data,
651 gpointer parent_data, gpointer global_data,
652 gpointer* result, const gchar* tag)
653{
654 GSList* lp;
655 GList* result_glist;
656 KvpValue* kvp_result;
657
658 result_glist = NULL;
659 for (lp = data_from_children; lp; lp = lp->next)
660 {
661 sixtp_child_result* cr = (sixtp_child_result*) lp->data;
662 KvpValue* kvp = (KvpValue*) cr->data;
663
664 /* children are in reverse chron order, so this fixes it. */
665 result_glist = g_list_prepend (result_glist, kvp);
666 cr->should_cleanup = FALSE;
667 }
668
669 kvp_result = new KvpValue {result_glist};
670 if (!kvp_result)
671 g_list_free_full (result_glist,
672 [] (void * data) { delete static_cast<KvpValue*> (data);});
673 *result = kvp_result;
674 return (TRUE);
675}
676
677/* ---------------------------------------------- */
678#define KVP_TOKEN(NAME,TOK) \
679 child_pr = NAME##_kvp_value_parser_new(); \
680 g_return_val_if_fail(child_pr, FALSE); \
681 sixtp_add_sub_parser(p, TOK, child_pr);
682/* ---------------------------------------------- */
683
684
685static gboolean
686add_all_kvp_value_parsers_as_sub_nodes (sixtp* p,
687 sixtp* kvp_frame_parser,
688 sixtp* glist_parser)
689{
690 sixtp* child_pr;
691
692 g_return_val_if_fail (p, FALSE);
693 g_return_val_if_fail (kvp_frame_parser, FALSE);
694
695 KVP_TOKEN (gint64, "gint64");
696 KVP_TOKEN (double, "double");
697 KVP_TOKEN (gnc_numeric, "numeric");
698 KVP_TOKEN (string, "string");
699 KVP_TOKEN (guid, "guid");
700
701 sixtp_add_sub_parser (p, "glist", glist_parser);
702 sixtp_add_sub_parser (p, "frame", kvp_frame_parser);
703
704 return (TRUE);
705}
706
707static sixtp*
708glist_kvp_value_parser_new (sixtp* kvp_frame_parser)
709{
710 sixtp* top_level = sixtp_set_any (
711 sixtp_new (), FALSE,
712 SIXTP_CHARACTERS_HANDLER_ID, allow_and_ignore_only_whitespace,
713 SIXTP_END_HANDLER_ID, glist_kvp_value_end_handler,
714 SIXTP_CLEANUP_RESULT_ID, kvp_value_result_cleanup,
715 SIXTP_RESULT_FAIL_ID, kvp_value_result_cleanup,
716 SIXTP_NO_MORE_HANDLERS);
717 if (!top_level)
718 {
719 return NULL;
720 }
721
722 if (!add_all_kvp_value_parsers_as_sub_nodes (top_level,
723 kvp_frame_parser,
724 top_level))
725 {
726 sixtp_destroy (top_level);
727 return (NULL);
728 }
729
730 return (top_level);
731}
732
733/*********************************/
734/* kvp-frame slot handlers
735
736 handlers for the <s><k>some key</k><[value]>data</[value]> sub-structure.
737*/
738
739/* <k> (lineage <s> <kvp-frame>)
740
741 kvp-frame slot key handler - just a generic-string-parser
742
743 */
744
745/* <s> (lineage <kvp-frame>)
746
747 kvp-frame slot handler.
748
749 input: KvpFrame*
750 returns: NA
751
752 start: NA
753 characters: allow_and_ignore_only_whitespace
754 end: check for two children - one must be a <k> - if OK, set slot.
755
756 cleanup-result: NA
757 cleanup-chars: NA
758 fail: NA
759 result-fail: NA
760 chars-fail: NA
761
762 */
763
764static gboolean
765kvp_frame_slot_end_handler (gpointer data_for_children,
766 GSList* data_from_children, GSList* sibling_data,
767 gpointer parent_data, gpointer global_data,
768 gpointer* result, const gchar* tag)
769{
770 KvpFrame* f = (KvpFrame*) parent_data;
771 gchar* key = NULL;
772 KvpValue* value = NULL;
773 gboolean delete_value = FALSE;
774 sixtp_child_result *cr1 = NULL, *cr2 = NULL, *cr = NULL;
775 g_return_val_if_fail (f, FALSE);
776
777 if (g_slist_length (data_from_children) != 2) return (FALSE);
778 cr1 = (sixtp_child_result*)data_from_children->data;
779 cr2 = (sixtp_child_result*)data_from_children->next->data;
780
781 if (is_child_result_from_node_named(cr1, "k"))
782 {
783 key = (char*)cr1->data;
784 cr = cr2;
785 }
786 else if (is_child_result_from_node_named(cr2, "k"))
787 {
788 key = (char*)cr2->data;
789 cr = cr1;
790 }
791 else
792 return FALSE;
793
794 if (is_child_result_from_node_named (cr, "frame"))
795 {
796 KvpFrame* frame = static_cast<KvpFrame*> (cr->data);
797 value = new KvpValue {frame};
798 delete_value = TRUE;
799 }
800 else
801 {
802 value = static_cast<KvpValue*> (cr->data);
803 delete_value = FALSE;
804 }
805
806 f->set ({key}, value);
807 if (delete_value)
808 delete value;
809 return (TRUE);
810}
811
812static sixtp*
813kvp_frame_slot_parser_new (sixtp* kvp_frame_parser)
814{
815 sixtp* top_level;
816 sixtp* child_pr;
817 sixtp* glist_pr;
818
819 g_return_val_if_fail (kvp_frame_parser, NULL);
820
821 if (! (top_level = sixtp_set_any (
822 sixtp_new (), FALSE,
823 SIXTP_CHARACTERS_HANDLER_ID, allow_and_ignore_only_whitespace,
824 SIXTP_END_HANDLER_ID, kvp_frame_slot_end_handler,
825 SIXTP_NO_MORE_HANDLERS)))
826 {
827 return NULL;
828 }
829
830 child_pr = simple_chars_only_parser_new (NULL);
831 if (!child_pr)
832 {
833 sixtp_destroy (top_level);
834 return (NULL);
835 }
836 sixtp_add_sub_parser (top_level, "k", child_pr);
837
838 glist_pr = glist_kvp_value_parser_new (kvp_frame_parser);
839 if (!glist_pr)
840 {
841 sixtp_destroy (top_level);
842 return (NULL);
843 }
844
845 if (!add_all_kvp_value_parsers_as_sub_nodes (top_level,
846 kvp_frame_parser,
847 glist_pr))
848 {
849 sixtp_destroy (top_level);
850 return (NULL);
851 }
852
853 return (top_level);
854}
855
856
857/* <kvp-frame> - can be used anywhere.
858
859 input: NA
860 returns: KvpFrame*
861
862 start: Allocates KvpFrame* and places in data_for_children.
863 characters: none (whitespace only).
864 end: put KvpFrame* into result if everything's OK.
865
866 cleanup-result: delete KvpFrame*
867 cleanup-chars: NA
868 fail: delete KvpFrame*
869 result-fail: delete KvpFrame*
870 chars-fail: NA
871
872 */
873
874static gboolean
875kvp_frame_start_handler (GSList* sibling_data, gpointer parent_data,
876 gpointer global_data, gpointer* data_for_children,
877 gpointer* result, const gchar* tag, gchar** attrs)
878{
879 auto f = new KvpFrame;
880 *data_for_children = f;
881 return (TRUE);
882}
883
884static gboolean
885kvp_frame_end_handler (gpointer data_for_children,
886 GSList* data_from_children, GSList* sibling_data,
887 gpointer parent_data, gpointer global_data,
888 gpointer* result, const gchar* tag)
889{
890 g_return_val_if_fail (data_for_children != NULL, FALSE);
891 *result = data_for_children;
892 return (TRUE);
893}
894
895static void
896kvp_frame_fail_handler (gpointer data_for_children,
897 GSList* data_from_children,
898 GSList* sibling_data,
899 gpointer parent_data,
900 gpointer global_data,
901 gpointer* result,
902 const gchar* tag)
903{
904 auto f = static_cast<KvpFrame*> (data_for_children);
905 if (f) delete f;
906}
907
908static void
909kvp_frame_result_cleanup (sixtp_child_result* cr)
910{
911 auto f = static_cast<KvpFrame*> (cr->data);
912 if (f) delete f;
913}
914
915static sixtp*
916kvp_frame_parser_new (void)
917{
918 sixtp* top_level;
919
920 if (! (top_level = sixtp_set_any (
921 sixtp_new (), FALSE,
922 SIXTP_START_HANDLER_ID, kvp_frame_start_handler,
923 SIXTP_CHARACTERS_HANDLER_ID, allow_and_ignore_only_whitespace,
924 SIXTP_END_HANDLER_ID, kvp_frame_end_handler,
925 SIXTP_CLEANUP_RESULT_ID, kvp_frame_result_cleanup,
926 SIXTP_RESULT_FAIL_ID, kvp_frame_result_cleanup,
927 SIXTP_FAIL_HANDLER_ID, kvp_frame_fail_handler,
928 SIXTP_NO_MORE_HANDLERS)))
929 {
930 return NULL;
931 }
932
933 if (! (sixtp_add_some_sub_parsers (
934 top_level, TRUE,
935 "s", kvp_frame_slot_parser_new (top_level),
936 NULL, NULL)))
937 {
938 return NULL;
939 }
940
941 return (top_level);
942}
943
944/****************************************************************************/
945/****************************************************************************/
946/****************************************************************************/
947/* <ledger-data> (parent <gnc-data>)
948
949 On failure or on normal cleanup, the root account will be killed,
950 so if you want it, you better set should_cleanup to false
951
952 input: NA
953 to-children-via-*result: new root Account*
954 returns: an Account*
955 start: creates the root account and puts it into *result
956 characters: NA
957 end: finishes up the root account and leaves it in result.
958 cleanup-result: deletes the root account (use should_cleanup to avoid).
959 cleanup-chars: NA
960 fail: deletes the root account in *result.
961 result-fail: same as cleanup-result.
962 chars-fail: NA
963
964*/
965
966
967static gboolean
968ledger_data_start_handler (GSList* sibling_data, gpointer parent_data,
969 gpointer global_data, gpointer* data_for_children,
970 gpointer* result, const gchar* tag, gchar** attrs)
971{
972 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
973 Account* ra;
974
975 /* disable logging during load; otherwise its just a mess */
977 ra = xaccMallocAccount (pstatus->book);
978
979 g_return_val_if_fail (ra, FALSE);
980
981 *data_for_children = ra;
982 return (ra != NULL);
983}
984
985static gboolean
986ledger_data_after_child_handler (gpointer data_for_children,
987 GSList* data_from_children,
988 GSList* sibling_data,
989 gpointer parent_data,
990 gpointer global_data,
991 gpointer* result,
992 const gchar* tag,
993 const gchar* child_tag,
994 sixtp_child_result* child_result)
995{
996 if (!child_result) return (TRUE);
997
998 /* if we see the pricedb, deal with it */
999 if (child_result->type != SIXTP_CHILD_RESULT_NODE) return (TRUE);
1000 if (strcmp (child_result->tag, "pricedb") == 0)
1001 {
1002 GNCPriceDB* pdb = (GNCPriceDB*) child_result->data;
1003 GNCParseStatus* status = (GNCParseStatus*) global_data;
1004
1005 g_return_val_if_fail (pdb, FALSE);
1006 g_return_val_if_fail (status, FALSE);
1007
1008 if (status->pricedb)
1009 {
1010 PERR ("hit pricedb twice in data file.");
1011 return FALSE;
1012 }
1013 status->pricedb = pdb;
1014 child_result->should_cleanup = FALSE;
1015 }
1016 return (TRUE);
1017}
1018
1019static gboolean
1020ledger_data_end_handler (gpointer data_for_children,
1021 GSList* data_from_children, GSList* sibling_data,
1022 gpointer parent_data, gpointer global_data,
1023 gpointer* result, const gchar* tag)
1024{
1025
1026 Account* ra = (Account*) data_for_children;
1027 GList* descendants;
1028
1029 g_return_val_if_fail (ra, FALSE);
1030
1031 /* commit all accounts, this completes the BeginEdit started when the
1032 * account_end_handler finished reading the account.
1033 */
1034 descendants = gnc_account_get_descendants (ra);
1035 g_list_foreach (descendants, (GFunc)xaccAccountCommitEdit, NULL);
1036 g_list_free (descendants);
1037
1038 xaccLogEnable ();
1039
1040 *result = ra;
1041 return (TRUE);
1042}
1043
1044static void
1045ledger_data_fail_handler (gpointer data_for_children,
1046 GSList* data_from_children,
1047 GSList* sibling_data,
1048 gpointer parent_data,
1049 gpointer global_data,
1050 gpointer* result,
1051 const gchar* tag)
1052{
1053 Account* account = (Account*) data_for_children;
1054 if (account)
1055 {
1056 xaccAccountBeginEdit (account);
1057 xaccAccountDestroy (account);
1058 }
1059}
1060
1061static void
1062ledger_data_result_cleanup (sixtp_child_result* cr)
1063{
1064 Account* account = (Account*) cr->data;
1065 if (account)
1066 {
1067 xaccAccountBeginEdit (account);
1068 xaccAccountDestroy (account);
1069 }
1070}
1071
1072
1073static sixtp*
1074ledger_data_parser_new (void)
1075{
1076 sixtp* top_level;
1077
1078 /* <ledger-data> */
1079 if (! (top_level = sixtp_set_any (
1080 sixtp_new (), FALSE,
1081 SIXTP_START_HANDLER_ID, ledger_data_start_handler,
1082 SIXTP_CHARACTERS_HANDLER_ID, allow_and_ignore_only_whitespace,
1083 SIXTP_AFTER_CHILD_HANDLER_ID, ledger_data_after_child_handler,
1084 SIXTP_END_HANDLER_ID, ledger_data_end_handler,
1085 SIXTP_CLEANUP_RESULT_ID, ledger_data_result_cleanup,
1086 SIXTP_FAIL_HANDLER_ID, ledger_data_fail_handler,
1087 SIXTP_RESULT_FAIL_ID, ledger_data_result_cleanup,
1088 SIXTP_NO_MORE_HANDLERS)))
1089 {
1090 return NULL;
1091 }
1092
1093 if (!sixtp_add_some_sub_parsers (
1094 top_level, TRUE,
1095 "commodity", commodity_restore_parser_new (),
1096 "pricedb", gnc_pricedb_parser_new (),
1097 "account", gnc_account_parser_new (),
1098 "transaction", gnc_transaction_parser_new (),
1099 NULL, NULL))
1100 {
1101 return NULL;
1102 }
1103
1104 return (top_level);
1105}
1106
1107/***********************************************************************/
1108/****************************************************************************/
1109/* <account> (parent <ledger-data>)
1110
1111 This block does nothing but pass the ledger-data account group down
1112 to its children. It generates no data of its own, so it doesn't
1113 need any cleanup.
1114
1115 input: Account*
1116
1117 to-children-via-*result: Account*
1118
1119 returns: NA
1120
1121 start: pass input to children.
1122
1123 characters: NA
1124
1125 end: NA
1126
1127 cleanup-result: NA
1128
1129 cleanup-chars: NA
1130
1131 fail: NA
1132
1133 result-fail: NA
1134
1135 chars-fail: NA
1136
1137 */
1138
1139static gboolean
1140account_start_handler (GSList* sibling_data,
1141 gpointer parent_data,
1142 gpointer global_data,
1143 gpointer* data_for_children,
1144 gpointer* result,
1145 const gchar* tag,
1146 gchar** attrs)
1147{
1148 /* pass the parent data down to the children */
1149 *data_for_children = parent_data;
1150 return (TRUE);
1151}
1152
1153/****************************************************************************/
1154/* <restore> (lineage <account> <ledger-data>)
1155
1156 restores a given account. We allocate the new account in the
1157 start block, the children modify it, and in the end block, we see
1158 if the resultant account is OK, and if so, we add it to the
1159 ledger-data's account group.
1160
1161 input: Account*
1162 to-children-via-*result: new Account*
1163 returns: NA
1164 start: create new Account*, and leave in for children.
1165 characters: NA
1166 end: clear *result
1167 cleanup-result: NA
1168 cleanup-chars: NA
1169 fail: delete Account*
1170 result-fail: NA
1171 chars-fail: NA
1172 */
1173
1174static gboolean
1175account_restore_start_handler (GSList* sibling_data,
1176 gpointer parent_data,
1177 gpointer global_data,
1178 gpointer* data_for_children,
1179 gpointer* result,
1180 const gchar* tag,
1181 gchar** attrs)
1182{
1183 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
1184 Account* acc = xaccMallocAccount (pstatus->book);
1185
1186 g_return_val_if_fail (acc, FALSE);
1188
1189 *data_for_children = acc;
1190 *result = acc;
1191
1192 return (TRUE);
1193}
1194
1195static gboolean
1196account_restore_end_handler (gpointer data_for_children,
1197 GSList* data_from_children, GSList* sibling_data,
1198 gpointer parent_data, gpointer global_data,
1199 gpointer* result, const gchar* tag)
1200{
1201 Account* parent = (Account*) parent_data;
1202 Account* acc = (Account*) * result;
1203
1204 g_return_val_if_fail ((parent && acc), FALSE);
1205
1206 /* CHECKME: do we need to xaccAccountRecomputeBalance(acc) here? */
1208
1209 /* If the account doesn't have a parent yet, just cram it into the
1210 top level */
1211 if (!gnc_account_get_parent (acc))
1212 gnc_account_append_child (parent, acc);
1213
1214 *result = NULL;
1215
1216 /* Now return the account to the "edit" state. At the end of reading
1217 * all the transactions, we will Commit. This replaces #splits
1218 * rebalances with #accounts rebalances at the end. A BIG win!
1219 */
1221 return (TRUE);
1222}
1223
1224static gboolean
1225account_restore_after_child_handler (gpointer data_for_children,
1226 GSList* data_from_children,
1227 GSList* sibling_data,
1228 gpointer parent_data,
1229 gpointer global_data,
1230 gpointer* result,
1231 const gchar* tag,
1232 const gchar* child_tag,
1233 sixtp_child_result* child_result)
1234{
1235 Account* a = (Account*) data_for_children;
1236 /* GNCParseStatus *pstatus = (GNCParseStatus *) global_data; */
1237
1238 g_return_val_if_fail (a, FALSE);
1239
1240 if (!child_result) return (TRUE);
1241 if (child_result->type != SIXTP_CHILD_RESULT_NODE) return (TRUE);
1242 if (strcmp (child_result->tag, "slots") == 0)
1243 {
1244 auto f = static_cast<KvpFrame*> (child_result->data);
1245 g_return_val_if_fail (f, FALSE);
1246 if (a->inst.kvp_data) delete a->inst.kvp_data;
1247 a->inst.kvp_data = f;
1248 child_result->should_cleanup = FALSE;
1249 }
1250 else if (strcmp (child_result->tag, "currency") == 0)
1251 {
1252 gnc_commodity* com = (gnc_commodity*) child_result->data;
1253 g_return_val_if_fail (com, FALSE);
1254 if (DxaccAccountGetCurrency (a)) return FALSE;
1255 DxaccAccountSetCurrency (a, com);
1256 /* let the normal child_result handler clean up com */
1257 }
1258 else if (strcmp (child_result->tag, "security") == 0)
1259 {
1260 gnc_commodity* com = (gnc_commodity*) child_result->data;
1261 g_return_val_if_fail (com, FALSE);
1262 if (xaccAccountGetCommodity (a)) return FALSE;
1263 xaccAccountSetCommodity (a, com);
1264 /* let the normal child_result handler clean up com */
1265 }
1266
1267 return (TRUE);
1268}
1269
1270static void
1271account_restore_fail_handler (gpointer data_for_children,
1272 GSList* data_from_children,
1273 GSList* sibling_data,
1274 gpointer parent_data,
1275 gpointer global_data,
1276 gpointer* result,
1277 const gchar* tag)
1278{
1279 Account* acc = (Account*) * result;
1280 if (acc)
1281 {
1283 xaccAccountDestroy (acc);
1284 }
1285}
1286
1287/****************************************************************************/
1288/* <name> (lineage <restore> <account>)
1289
1290 restores a given account's name.
1291 input: Account*
1292 returns: NA
1293
1294 start: NA
1295 characters: return string copy for accumulation in end handler.
1296 end: concatenate all chars and set as account name.
1297
1298 cleanup-result: NA
1299 cleanup-chars: g_free the result string.
1300 fail: NA
1301 result-fail: NA
1302 chars-fail: g_free the result string.
1303
1304 */
1305static gboolean
1306acc_restore_name_end_handler (gpointer data_for_children,
1307 GSList* data_from_children, GSList* sibling_data,
1308 gpointer parent_data, gpointer global_data,
1309 gpointer* result, const gchar* tag)
1310{
1311 Account* acc = (Account*) parent_data;
1312 gchar* name = NULL;
1313
1314 g_return_val_if_fail (acc, FALSE);
1315
1316 name = concatenate_child_result_chars (data_from_children);
1317 g_return_val_if_fail (name, FALSE);
1318
1319 xaccAccountSetName (acc, name);
1320 g_free (name);
1321 return (TRUE);
1322}
1323
1324/****************************************************************************/
1325/* <guid> (lineage <restore> <account>)
1326
1327 restores a given account's guid.
1328 input: Account*
1329 returns: NA
1330
1331 start: NA
1332 characters: return string copy for accumulation in end handler.
1333 end: concatenate all chars and set as account GncGUID if not duplicate.
1334
1335 cleanup-result: NA
1336 cleanup-chars: g_free the result string.
1337 fail: NA
1338 result-fail: NA
1339 chars-fail: g_free the result string.
1340
1341 */
1342
1343static gboolean
1344acc_restore_guid_end_handler (gpointer data_for_children,
1345 GSList* data_from_children, GSList* sibling_data,
1346 gpointer parent_data, gpointer global_data,
1347 gpointer* result, const gchar* tag)
1348{
1349 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
1350 Account* acc = (Account*) parent_data;
1351 gchar* txt = NULL;
1352 GncGUID gid;
1353 gboolean ok;
1354
1355 g_return_val_if_fail (acc, FALSE);
1356
1357 txt = concatenate_child_result_chars (data_from_children);
1358 g_return_val_if_fail (txt, FALSE);
1359
1360 ok = string_to_guid (txt, &gid);
1361 g_free (txt);
1362
1363 g_return_val_if_fail (ok, FALSE);
1364
1365 if (xaccAccountLookup (&gid, pstatus->book))
1366 {
1367 return (FALSE);
1368 }
1369
1370 xaccAccountSetGUID (acc, &gid);
1371 return (TRUE);
1372}
1373
1374/****************************************************************************/
1375/* <type> (lineage <restore> <account>)
1376
1377 restores a given account's type.
1378 input: Account*
1379 returns: NA
1380
1381 start: NA
1382 characters: return string copy for accumulation in end handler.
1383 end: concatenate all chars and set as account type.
1384
1385 cleanup-result: NA
1386 cleanup-chars: g_free the result string.
1387 fail: NA
1388 result-fail: NA
1389 chars-fail: g_free the result string.
1390
1391 */
1392
1393static gboolean
1394acc_restore_type_end_handler (gpointer data_for_children,
1395 GSList* data_from_children, GSList* sibling_data,
1396 gpointer parent_data, gpointer global_data,
1397 gpointer* result, const gchar* tag)
1398{
1399 Account* acc = (Account*) parent_data;
1400 gchar* txt = NULL;
1401 GNCAccountType type;
1402 gboolean ok;
1403
1404 g_return_val_if_fail (acc, FALSE);
1405
1406 txt = concatenate_child_result_chars (data_from_children);
1407 g_return_val_if_fail (txt, FALSE);
1408
1409 ok = xaccAccountStringToType (txt, &type);
1410 g_free (txt);
1411
1412 g_return_val_if_fail (ok, FALSE);
1413
1414 xaccAccountSetType (acc, type);
1415 return (TRUE);
1416}
1417
1418/****************************************************************************/
1419/* <code> (lineage <restore> <account>)
1420
1421 restores a given account's code.
1422 input: Account*
1423 returns: NA
1424
1425 start: NA
1426 characters: return string copy for accumulation in end handler.
1427 end: concatenate all chars and set as account type.
1428
1429 cleanup-result: NA
1430 cleanup-chars: g_free the result string.
1431 fail: NA
1432 result-fail: NA
1433 chars-fail: g_free the result string.
1434
1435 */
1436
1437static gboolean
1438acc_restore_code_end_handler (gpointer data_for_children,
1439 GSList* data_from_children, GSList* sibling_data,
1440 gpointer parent_data, gpointer global_data,
1441 gpointer* result, const gchar* tag)
1442{
1443 Account* acc = (Account*) parent_data;
1444 gchar* txt = NULL;
1445
1446 g_return_val_if_fail (acc, FALSE);
1447
1448 txt = concatenate_child_result_chars (data_from_children);
1449 g_return_val_if_fail (txt, FALSE);
1450
1451 xaccAccountSetCode (acc, txt);
1452 g_free (txt);
1453 return (TRUE);
1454}
1455
1456/****************************************************************************/
1457/* <description> (lineage <restore> <account>)
1458
1459 restores a given account's description.
1460 input: Account*
1461 returns: NA
1462
1463 start: NA
1464 characters: return string copy for accumulation in end handler.
1465 end: concatenate all chars and set as account description.
1466
1467 cleanup-result: NA
1468 cleanup-chars: g_free the result string.
1469 fail: NA
1470 result-fail: NA
1471 chars-fail: g_free the result string.
1472 restores a given account's description.
1473
1474 */
1475
1476static gboolean
1477acc_restore_description_end_handler (gpointer data_for_children,
1478 GSList* data_from_children, GSList* sibling_data,
1479 gpointer parent_data, gpointer global_data,
1480 gpointer* result, const gchar* tag)
1481{
1482 Account* acc = (Account*) parent_data;
1483 gchar* txt = NULL;
1484
1485 g_return_val_if_fail (acc, FALSE);
1486
1487 txt = concatenate_child_result_chars (data_from_children);
1488 g_return_val_if_fail (txt, FALSE);
1489
1490 xaccAccountSetDescription (acc, txt);
1491 g_free (txt);
1492 return (TRUE);
1493}
1494
1495/****************************************************************************/
1496/* <notes> (lineage <restore> <account>)
1497
1498 restores a given account's notes.
1499 input: Account*
1500 returns: NA
1501
1502 start: NA
1503 characters: return string copy for accumulation in end handler.
1504 end: concatenate all chars and set as account notes.
1505
1506 cleanup-result: NA
1507 cleanup-chars: g_free the result string.
1508 fail: NA
1509 result-fail: NA
1510 chars-fail: g_free the result string.
1511
1512 */
1513
1514static gboolean
1515acc_restore_notes_end_handler (gpointer data_for_children,
1516 GSList* data_from_children, GSList* sibling_data,
1517 gpointer parent_data, gpointer global_data,
1518 gpointer* result, const gchar* tag)
1519{
1520 Account* acc = (Account*) parent_data;
1521 gchar* txt = NULL;
1522
1523 g_return_val_if_fail (acc, FALSE);
1524
1525 txt = concatenate_child_result_chars (data_from_children);
1526 g_return_val_if_fail (txt, FALSE);
1527
1528 xaccAccountSetNotes (acc, txt);
1529 g_free (txt);
1530 return (TRUE);
1531}
1532
1533/****************************************************************************/
1534/* <parent> (lineage <restore> <account>)
1535
1536 restores a given account's parent.
1537 input: Account*
1538 returns: NA
1539
1540 start: NA
1541
1542 characters: allow and ignore only whitespace.
1543
1544 end: check for single <guid> child and if found, use result to set
1545 account guid.
1546
1547 cleanup-result: NA
1548 cleanup-chars: NA
1549 fail: NA
1550 result-fail: NA
1551 chars-fail: NA
1552
1553 */
1554
1555static gboolean
1556acc_restore_parent_end_handler (gpointer data_for_children,
1557 GSList* data_from_children, GSList* sibling_data,
1558 gpointer parent_data, gpointer global_data,
1559 gpointer* result, const gchar* tag)
1560{
1561 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
1562 Account* acc = (Account*) parent_data;
1563 Account* parent;
1564 sixtp_child_result* child_result;
1565 GncGUID gid;
1566
1567 g_return_val_if_fail (acc, FALSE);
1568
1569 if (g_slist_length (data_from_children) != 1)
1570 return (FALSE);
1571
1572 child_result = (sixtp_child_result*) data_from_children->data;
1573
1574 if (!is_child_result_from_node_named (child_result, "guid"))
1575 return (FALSE);
1576
1577 /* otherwise this must be a good result - use it */
1578 gid = * ((GncGUID*) child_result->data);
1579
1580 parent = xaccAccountLookup (&gid, pstatus->book);
1581
1582 g_return_val_if_fail (parent, FALSE);
1583
1584 gnc_account_append_child (parent, acc);
1585
1586 return (TRUE);
1587}
1588
1589static sixtp*
1590parent_lookup_parser_new (void)
1591{
1592 return sixtp_set_any (sixtp_new (), TRUE,
1593 SIXTP_CHARACTERS_HANDLER_ID,
1594 allow_and_ignore_only_whitespace,
1595 SIXTP_END_HANDLER_ID,
1596 acc_restore_parent_end_handler,
1597 SIXTP_NO_MORE_HANDLERS);
1598}
1599
1600static sixtp*
1601gnc_account_parser_new (void)
1602{
1603 sixtp* restore_pr;
1604 sixtp* ret;
1605
1606 /* <account> */
1607 if (! (ret = sixtp_set_any (
1608 sixtp_new (), FALSE,
1609 SIXTP_START_HANDLER_ID, account_start_handler,
1610 SIXTP_CHARACTERS_HANDLER_ID, allow_and_ignore_only_whitespace,
1611 SIXTP_NO_MORE_HANDLERS)))
1612 {
1613 return NULL;
1614 }
1615
1616 /* <account> <restore> */
1617 if (! (restore_pr =
1618 sixtp_set_any (sixtp_new (), FALSE,
1619 SIXTP_START_HANDLER_ID, account_restore_start_handler,
1620 SIXTP_END_HANDLER_ID, account_restore_end_handler,
1621 SIXTP_FAIL_HANDLER_ID, account_restore_fail_handler,
1622 SIXTP_AFTER_CHILD_HANDLER_ID,
1623 account_restore_after_child_handler,
1624 SIXTP_NO_MORE_HANDLERS)))
1625 {
1626 sixtp_destroy (ret);
1627 return NULL;
1628 }
1629
1630 /* <restore> (<name> | <guid> | <type> | <code> | <description> | <notes>)*/
1631 if (!sixtp_add_some_sub_parsers (
1632 restore_pr, TRUE,
1633 "name", restore_char_generator (acc_restore_name_end_handler),
1634 "guid", restore_char_generator (acc_restore_guid_end_handler),
1635 "type", restore_char_generator (acc_restore_type_end_handler),
1636 "code", restore_char_generator (acc_restore_code_end_handler),
1637 "description",
1638 restore_char_generator (acc_restore_description_end_handler),
1639 "notes", restore_char_generator (acc_restore_notes_end_handler),
1640 /* <account> <restore> <currency> */
1641 "currency", generic_gnc_commodity_lookup_parser_new (),
1642 /* <account> <restore> <security> */
1643 "security", generic_gnc_commodity_lookup_parser_new (),
1644 /* <account> <restore> <parent> */
1645 "parent", sixtp_add_some_sub_parsers (
1646 parent_lookup_parser_new (), TRUE,
1647 "guid", generic_guid_parser_new (),
1648 NULL, NULL),
1649 "slots", kvp_frame_parser_new (),
1650 NULL, NULL))
1651 {
1652 sixtp_destroy (ret);
1653 return NULL;
1654 }
1655
1656 sixtp_add_sub_parser (ret, "restore", restore_pr);
1657
1658 return ret;
1659}
1660/***********************************************************************/
1661/****************************************************************************/
1662/* Commodity restorer.
1663
1664 Right now we just check to see that fields aren't duplicated. If
1665 fields don't show up, then we just use "".
1666
1667 We also check to see that we get a <fraction>. If not, it's an
1668 error.
1669
1670 Example:
1671 <commodity>
1672 <restore>
1673 <space>NASDAQ</space>
1674 <id>XYZZY</id>
1675 <name>Grue Enterprises</name>
1676 <xcode>XXX</xcode>
1677 <fraction>100</fraction>
1678 </restore>
1679 </commodity>
1680
1681 */
1682
1683/* ==================================================================== */
1684
1685/*********************************/
1686/* <restore> (lineage <commodity>)
1687
1688 Start handler allocates a gnc_commodity. The end_handler, if
1689 everything's OK, crams the commodity into the engine, otherwise it
1690 deletes it.
1691
1692 input: NA
1693 returns: NA
1694
1695 start: allocate CommodityParseInfo* and put it into data_for_children.
1696 characters: allow and ignore only whitespace.
1697 after-child: handle strings from simple chars children.
1698 end: if OK create gnc_commodity and add to engine. delete CommodityParseInfo.
1699
1700 cleanup-result: NA
1701 cleanup-chars: NA
1702 fail: delete CommodityParseInfo*.
1703 result-fail: NA
1704 chars-fail: NA
1705
1706 */
1707
1708typedef struct
1709{
1710 gchar* space;
1711 gchar* id;
1712 gchar* name;
1713 gchar* xcode;
1714 gboolean seen_fraction;
1715 int fraction;
1717
1718static gboolean
1719commodity_restore_start_handler (GSList* sibling_data, gpointer parent_data,
1720 gpointer global_data,
1721 gpointer* data_for_children, gpointer* result,
1722 const gchar* tag, gchar** attrs)
1723{
1724 CommodityParseInfo* cpi =
1726
1727 g_return_val_if_fail (cpi, FALSE);
1728
1729 *data_for_children = cpi;
1730 return (TRUE);
1731}
1732
1733/* ----------------------------------------------------*/
1734#define COMMOD_TOKEN(NAME) \
1735 if(strcmp(child_result->tag, #NAME) == 0) { \
1736 if(cpi->NAME) return(FALSE); \
1737 cpi->NAME = (gchar *) child_result->data; \
1738 child_result->should_cleanup = FALSE; \
1739 } \
1740 else
1741/* ----------------------------------------------------*/
1742
1743static gboolean
1744commodity_restore_after_child_handler (gpointer data_for_children,
1745 GSList* data_from_children,
1746 GSList* sibling_data,
1747 gpointer parent_data,
1748 gpointer global_data,
1749 gpointer* result,
1750 const gchar* tag,
1751 const gchar* child_tag,
1752 sixtp_child_result* child_result)
1753{
1754 CommodityParseInfo* cpi = (CommodityParseInfo*) data_for_children;
1755
1756 g_return_val_if_fail (cpi, FALSE);
1757 g_return_val_if_fail (child_result, FALSE);
1758
1759 COMMOD_TOKEN (space)
1760 COMMOD_TOKEN (id)
1761 COMMOD_TOKEN (name)
1762 COMMOD_TOKEN (xcode)
1763 if (strcmp (child_result->tag, "fraction") == 0)
1764 {
1765 gint64 frac;
1766
1767 if (cpi->seen_fraction) return (FALSE);
1768 string_to_gint64 ((gchar*) child_result->data, &frac);
1769 cpi->fraction = frac;
1770 cpi->seen_fraction = TRUE;
1771 child_result->should_cleanup = TRUE;
1772 }
1773 else
1774 {
1775 /* redundant because the parser won't allow any other children */
1776 return (FALSE);
1777 }
1778
1779 return (TRUE);
1780}
1781
1782static gboolean
1783commodity_restore_end_handler (gpointer data_for_children,
1784 GSList* data_from_children, GSList* sibling_data,
1785 gpointer parent_data, gpointer global_data,
1786 gpointer* result, const gchar* tag)
1787{
1788 CommodityParseInfo* cpi = (CommodityParseInfo*) data_for_children;
1789 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
1790 gboolean ok = FALSE;
1791 gnc_commodity* comm = NULL;
1792
1793 g_return_val_if_fail (cpi, FALSE);
1794
1795 if (cpi->seen_fraction)
1796 {
1797 gnc_commodity* comm;
1798
1799 if (!cpi->space) cpi->space = g_strdup ("");
1800 if (!cpi->id) cpi->id = g_strdup ("");
1801 if (!cpi->name) cpi->name = g_strdup ("");
1802 if (!cpi->xcode) cpi->xcode = g_strdup ("");
1803
1804 comm = gnc_commodity_new (pstatus->book,
1805 cpi->name,
1806 cpi->space,
1807 cpi->id,
1808 cpi->xcode,
1809 cpi->fraction);
1810 if (comm)
1811 {
1812 gnc_commodity_table* ctab;
1813
1814 ctab = gnc_commodity_table_get_table (pstatus->book);
1815
1816 if (ctab)
1817 {
1818 gnc_commodity_table_insert (ctab, comm);
1819 ok = TRUE;
1820 }
1821 }
1822 }
1823
1824 g_free (cpi->space);
1825 g_free (cpi->id);
1826 g_free (cpi->name);
1827 g_free (cpi->xcode);
1828 g_free (cpi);
1829
1830 if (!ok) gnc_commodity_destroy (comm);
1831
1832 return (ok);
1833}
1834
1835
1836static sixtp*
1837commodity_restore_parser_new (void)
1838{
1839 sixtp* top_level;
1840 sixtp* restore_pr;
1841
1842 top_level = sixtp_new ();
1843 g_return_val_if_fail (top_level, NULL);
1844
1845 if (! (restore_pr = sixtp_set_any (
1846 sixtp_new (), FALSE,
1847 SIXTP_START_HANDLER_ID, commodity_restore_start_handler,
1848 SIXTP_END_HANDLER_ID, commodity_restore_end_handler,
1849 SIXTP_FAIL_HANDLER_ID, generic_free_data_for_children,
1850 SIXTP_AFTER_CHILD_HANDLER_ID, commodity_restore_after_child_handler,
1851 SIXTP_NO_MORE_HANDLERS)))
1852 {
1853 sixtp_destroy (top_level);
1854 return (NULL);
1855 }
1856 sixtp_add_sub_parser (top_level, "restore", restore_pr);
1857
1858 if (!sixtp_add_some_sub_parsers (
1859 restore_pr, TRUE,
1860 "space", simple_chars_only_parser_new (NULL),
1861 "id", simple_chars_only_parser_new (NULL),
1862 "name", simple_chars_only_parser_new (NULL),
1863 "xcode", simple_chars_only_parser_new (NULL),
1864 "fraction", simple_chars_only_parser_new (NULL),
1865 NULL, NULL))
1866 {
1867 return NULL;
1868 }
1869
1870 return (top_level);
1871}
1872
1873/****************************************************************************/
1874/* generic gnc_commodity lookup handler.
1875
1876 A collection of node functions intended to parse a sub-node set
1877 that looks like this:
1878
1879 <security>
1880 <space>NASDAQ</space>
1881 <id>ZXDDQ</id>
1882 </security>
1883
1884 and produce a gnc_commodity* by looking up the unique combination
1885 of namespace and ID (mnemonic).
1886
1887 The start handler for the top allocates a CommodityParseInfo* and
1888 passes it to the children. The <space> block sets the namespace
1889 and the <id> block sets the ID. The end handler performs the
1890 lookup. If all goes well, returns the gnc_commodity* as the
1891 result. */
1892
1893/* Top level gnc_commodity lookup node:
1894
1895 input: NA
1896 returns: gnc_commodity*
1897
1898 start: Allocates CommodityParseInfo* for data_for_children.
1899 characters: none (whitespace only).
1900 end: lookup commodity and place into *result, free data_for_children.
1901
1902 fail: g_free data_for_children (CommodityParseInfo and contents).
1903 cleanup-chars: NA
1904 chars-fail: NA
1905 cleanup-result: NA (we didn't create the gnc_commodity we're returning)
1906 result-fail: NA
1907
1908 */
1909
1910typedef struct
1911{
1912 gchar* name_space;
1913 gchar* id;
1915
1916static gboolean
1917generic_gnc_commodity_lookup_start_handler (
1918 GSList* sibling_data, gpointer parent_data, gpointer global_data,
1919 gpointer* data_for_children, gpointer* result, const gchar* tag,
1920 gchar** attrs)
1921{
1923 g_return_val_if_fail (cpi, FALSE);
1924 *data_for_children = cpi;
1925 return (TRUE);
1926}
1927
1928static gboolean
1929generic_gnc_commodity_lookup_after_child_handler (gpointer data_for_children,
1930 GSList* data_from_children,
1931 GSList* sibling_data,
1932 gpointer parent_data,
1933 gpointer global_data,
1934 gpointer* result,
1935 const gchar* tag,
1936 const gchar* child_tag,
1937 sixtp_child_result* child_result)
1938{
1940 (CommodityLookupParseInfo*) data_for_children;
1941
1942 g_return_val_if_fail (cpi, FALSE);
1943 g_return_val_if_fail (child_result, FALSE);
1944 if (child_result->type != SIXTP_CHILD_RESULT_NODE) return (FALSE);
1945
1946 if (strcmp (child_result->tag, "space") == 0)
1947 {
1948 if (cpi->name_space) return (FALSE);
1949 cpi->name_space = (gchar*) child_result->data;
1950 child_result->should_cleanup = FALSE;
1951 }
1952 else if (strcmp (child_result->tag, "id") == 0)
1953 {
1954 if (cpi->id) return (FALSE);
1955 cpi->id = (gchar*) child_result->data;
1956 child_result->should_cleanup = FALSE;
1957 }
1958 else
1959 {
1960 /* redundant because the parser won't allow any other children */
1961 return (FALSE);
1962 }
1963
1964 return (TRUE);
1965}
1966
1967static gboolean
1968generic_gnc_commodity_lookup_end_handler (gpointer data_for_children,
1969 GSList* data_from_children, GSList* sibling_data,
1970 gpointer parent_data, gpointer global_data,
1971 gpointer* result, const gchar* tag)
1972{
1974 (CommodityLookupParseInfo*) data_for_children;
1975 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
1976 gboolean ok = FALSE;
1977
1978 g_return_val_if_fail (cpi, FALSE);
1979
1980 if (cpi->name_space && cpi->id)
1981 {
1982 gnc_commodity_table* table;
1983 gnc_commodity* com;
1984
1985 table = gnc_commodity_table_get_table (pstatus->book);
1986
1987 com = gnc_commodity_table_lookup (table, cpi->name_space, cpi->id);
1988
1989 if (com)
1990 {
1991 *result = com;
1992 ok = TRUE;
1993 }
1994 }
1995
1996 g_free (cpi->name_space);
1997 g_free (cpi->id);
1998 g_free (cpi);
1999
2000 return (ok);
2001}
2002
2003
2004static sixtp*
2005generic_gnc_commodity_lookup_parser_new (void)
2006{
2007 sixtp* top_level;
2008
2009 if (! (top_level = sixtp_set_any (
2010 sixtp_new (), FALSE,
2011 SIXTP_START_HANDLER_ID, generic_gnc_commodity_lookup_start_handler,
2012 SIXTP_CHARACTERS_HANDLER_ID, allow_and_ignore_only_whitespace,
2013 SIXTP_END_HANDLER_ID, generic_gnc_commodity_lookup_end_handler,
2014 SIXTP_FAIL_HANDLER_ID, generic_free_data_for_children,
2015 SIXTP_AFTER_CHILD_HANDLER_ID,
2016 generic_gnc_commodity_lookup_after_child_handler,
2017 SIXTP_NO_MORE_HANDLERS)))
2018 {
2019 return NULL;
2020 }
2021
2022 if (!sixtp_add_some_sub_parsers (
2023 top_level, TRUE,
2024 "space", simple_chars_only_parser_new (NULL),
2025 "id", simple_chars_only_parser_new (NULL),
2026 NULL, NULL))
2027 {
2028 return NULL;
2029 }
2030
2031 return (top_level);
2032}
2033
2034/****************************************************************************/
2035/* <transaction> (parent <ledger-data>)
2036
2037 This block does nothing but pass the ledger-data account group down
2038 to its children. It generates no data of its own, so it doesn't
2039 need any cleanup.
2040
2041 input: Account*
2042
2043 to-children-via-*result: Account*
2044
2045 returns: NA
2046
2047 start: pass input to children.
2048
2049 characters: ignore whitespace only
2050
2051 end: NA
2052
2053 cleanup-result: NA
2054
2055 cleanup-chars: NA
2056
2057 fail: NA
2058
2059 result-fail: NA
2060
2061 chars-fail: NA
2062
2063 */
2064
2065static gboolean
2066transaction_start_handler (GSList* sibling_data, gpointer parent_data,
2067 gpointer global_data, gpointer* data_for_children,
2068 gpointer* result, const gchar* tag, gchar** attrs)
2069{
2070 /* pass the parent data down to the children */
2071 *data_for_children = parent_data;
2072 return (TRUE);
2073}
2074
2075/****************************************************************************/
2076/* <restore> (lineage <transaction> <ledger-data>)
2077
2078 restores a given transaction. We allocate the new transaction in
2079 the start block, the children modify it, and in the end block, we
2080 see if the resultant account is OK, and if so, we add it to the
2081 ledger-data's account group.
2082
2083 from parent: Account*
2084
2085 for children: new Transaction*
2086
2087 result: NA
2088
2089 -----------
2090
2091 start: create new Transaction*, and store in data_for_children.
2092
2093 chars: allow and ignore only whitespace.
2094
2095 end: commit transaction to group if appropriate.
2096
2097 cleanup-result: NA
2098
2099 cleanup-chars: NA
2100
2101 fail: delete Transaction* in data_for_children
2102
2103 result-fail: NA
2104
2105 chars-fail: NA
2106
2107 */
2108
2109static gboolean
2110txn_restore_start_handler (GSList* sibling_data, gpointer parent_data,
2111 gpointer global_data, gpointer* data_for_children,
2112 gpointer* result, const gchar* tag, gchar** attrs)
2113{
2114 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
2115 Transaction* trans = xaccMallocTransaction (pstatus->book);
2116
2117 g_return_val_if_fail (trans, FALSE);
2118
2119 xaccTransBeginEdit (trans);
2120 *data_for_children = trans;
2121
2122 return (TRUE);
2123}
2124
2125static gboolean
2126txn_restore_end_handler (gpointer data_for_children,
2127 GSList* data_from_children, GSList* sibling_data,
2128 gpointer parent_data, gpointer global_data,
2129 gpointer* result, const gchar* tag)
2130{
2131 Account* parent = (Account*) parent_data;
2132 Transaction* trans = (Transaction*) data_for_children;
2133
2134 g_return_val_if_fail (trans, FALSE);
2135 if (!parent)
2136 {
2137 xaccTransDestroy (trans);
2138 xaccTransCommitEdit (trans);
2139 return (FALSE);
2140 }
2141
2142 if (!xaccTransGetGUID (trans))
2143 {
2144 /* must at least have a GncGUID for a restore */
2145 xaccTransDestroy (trans);
2146 xaccTransCommitEdit (trans);
2147 return (FALSE);
2148 }
2149
2150 /* FIXME: what if the trans has no splits? */
2151 xaccTransCommitEdit (trans);
2152
2153 return (TRUE);
2154}
2155
2156static gboolean
2157txn_restore_after_child_handler (gpointer data_for_children,
2158 GSList* data_from_children,
2159 GSList* sibling_data,
2160 gpointer parent_data,
2161 gpointer global_data,
2162 gpointer* result,
2163 const gchar* tag,
2164 const gchar* child_tag,
2165 sixtp_child_result* child_result)
2166{
2167 Transaction* trans = (Transaction*) data_for_children;
2168 g_return_val_if_fail (trans, FALSE);
2169 if (!child_result) return (TRUE);
2170 if (child_result->type != SIXTP_CHILD_RESULT_NODE) return (TRUE);
2171 if (strcmp (child_result->tag, "slots") == 0)
2172 {
2173 KvpFrame* f = (KvpFrame*) child_result->data;
2174 g_return_val_if_fail (f, FALSE);
2175 qof_instance_set_slots (QOF_INSTANCE (trans), f);
2176 child_result->should_cleanup = FALSE;
2177 }
2178 return (TRUE);
2179}
2180
2181static void
2182txn_restore_fail_handler (gpointer data_for_children,
2183 GSList* data_from_children,
2184 GSList* sibling_data,
2185 gpointer parent_data,
2186 gpointer global_data,
2187 gpointer* result,
2188 const gchar* tag)
2189{
2190 Transaction* trans = (Transaction*) data_for_children;
2191 if (trans)
2192 {
2193 xaccTransDestroy (trans);
2194 xaccTransCommitEdit (trans);
2195 }
2196}
2197
2198/****************************************************************************/
2199/* <guid> (lineage <restore> <transaction>)
2200
2201 restores a given account's guid.
2202
2203 from parent: Transaction*
2204 for children: NA
2205 result: NA
2206 -----------
2207 start: NA
2208 characters: return string copy for accumulation in end handler.
2209 end: concatenate all chars and set as transaction GncGUID if not duplicate.
2210
2211 cleanup-result: NA
2212 cleanup-chars: g_free the result string.
2213 fail: NA
2214 result-fail: NA
2215 chars-fail: g_free the result string.
2216
2217 */
2218
2219static gboolean
2220txn_restore_guid_end_handler (gpointer data_for_children,
2221 GSList* data_from_children, GSList* sibling_data,
2222 gpointer parent_data, gpointer global_data,
2223 gpointer* result, const gchar* tag)
2224{
2225 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
2226 Transaction* t = (Transaction*) parent_data;
2227 gchar* txt = NULL;
2228 GncGUID gid;
2229 gboolean ok;
2230
2231 g_return_val_if_fail (t, FALSE);
2232
2233 txt = concatenate_child_result_chars (data_from_children);
2234 g_return_val_if_fail (txt, FALSE);
2235
2236 ok = string_to_guid (txt, &gid);
2237 g_free (txt);
2238
2239 g_return_val_if_fail (ok, FALSE);
2240
2241 if (xaccTransLookup (&gid, pstatus->book))
2242 {
2243 return (FALSE);
2244 }
2245
2246 xaccTransSetGUID (t, &gid);
2247 return (TRUE);
2248}
2249
2250/****************************************************************************/
2251/* <num> (lineage <restore> <transaction>)
2252
2253 restores a given transaction's num.
2254
2255 from parent: Transaction*
2256 for children: NA
2257 result: NA
2258 -----------
2259 start: NA
2260 characters: return string copy for accumulation in end handler.
2261 end: concatenate all chars and set as transaction num.
2262
2263 cleanup-result: NA
2264 cleanup-chars: g_free the result string.
2265 fail: NA
2266 result-fail: NA
2267 chars-fail: g_free the result string.
2268
2269 */
2270
2271static gboolean
2272txn_restore_num_end_handler (gpointer data_for_children,
2273 GSList* data_from_children, GSList* sibling_data,
2274 gpointer parent_data, gpointer global_data,
2275 gpointer* result, const gchar* tag)
2276{
2277 Transaction* t = (Transaction*) parent_data;
2278 gchar* txt = NULL;
2279
2280 g_return_val_if_fail (t, FALSE);
2281
2282 txt = concatenate_child_result_chars (data_from_children);
2283 g_return_val_if_fail (txt, FALSE);
2284
2285 xaccTransSetNum (t, txt);
2286 g_free (txt);
2287 return (TRUE);
2288}
2289
2290/****************************************************************************/
2291/* <description> (lineage <restore> <transaction>)
2292
2293 restores a given transaction's description.
2294
2295 from parent: Transaction*
2296 for children: NA
2297 result: NA
2298 -----------
2299 start: NA
2300 characters: return string copy for accumulation in end handler.
2301 end: concatenate all chars and set as transaction description.
2302
2303 cleanup-result: NA
2304 cleanup-chars: g_free the result string.
2305 fail: NA
2306 result-fail: NA
2307 chars-fail: g_free the result string.
2308
2309 */
2310
2311static gboolean
2312txn_restore_description_end_handler (gpointer data_for_children,
2313 GSList* data_from_children, GSList* sibling_data,
2314 gpointer parent_data, gpointer global_data,
2315 gpointer* result, const gchar* tag)
2316{
2317 Transaction* t = (Transaction*) parent_data;
2318 gchar* txt = NULL;
2319
2320 g_return_val_if_fail (t, FALSE);
2321
2322 txt = concatenate_child_result_chars (data_from_children);
2323 g_return_val_if_fail (txt, FALSE);
2324
2325 xaccTransSetDescription (t, txt);
2326 g_free (txt);
2327 return (TRUE);
2328}
2329
2330/****************************************************************************/
2331/* <date-posted> (lineage <restore> <transaction>)
2332
2333 restores a given transaction's posted date.
2334
2335 Just uses a generic_timespec parser, but with our own end handler.
2336
2337 end: set date posted.
2338
2339 */
2340
2341static gboolean
2342txn_rest_date_posted_end_handler (gpointer data_for_children,
2343 GSList* data_from_children, GSList* sibling_data,
2344 gpointer parent_data, gpointer global_data,
2345 gpointer* result, const gchar* tag)
2346{
2347 Transaction* t = (Transaction*) parent_data;
2348 Time64ParseInfo* info = (Time64ParseInfo*) data_for_children;
2349
2350 g_return_val_if_fail (info, FALSE);
2351 if (!t || !timespec_parse_ok (info))
2352 {
2353 g_free (info);
2354 return (FALSE);
2355 }
2356
2357 xaccTransSetDatePostedSecs (t, info->time);
2358 g_free (info);
2359 return (TRUE);
2360}
2361
2362/****************************************************************************/
2363/* <date-entered> (lineage <restore> <transaction>)
2364
2365 restores a given transaction's entered date.
2366
2367 Just uses a generic_timespec parser, but with our own end handler.
2368
2369 end: set date entered.
2370
2371 */
2372
2373static gboolean
2374txn_rest_date_entered_end_handler (gpointer data_for_children,
2375 GSList* data_from_children, GSList* sibling_data,
2376 gpointer parent_data, gpointer global_data,
2377 gpointer* result, const gchar* tag)
2378{
2379 Transaction* t = (Transaction*) parent_data;
2380 Time64ParseInfo* info = (Time64ParseInfo*) data_for_children;
2381
2382 g_return_val_if_fail (info, FALSE);
2383 if (!t || !timespec_parse_ok (info))
2384 {
2385 g_free (info);
2386 return (FALSE);
2387 }
2388
2389 xaccTransSetDateEnteredSecs (t, info->time);
2390 g_free (info);
2391 return (TRUE);
2392}
2393
2394
2395
2396/****************************************************************************/
2397
2398/* <split> (lineage <restore> <transaction> <ledger-data>)
2399
2400 Restores a given split. We allocate the new split in the start
2401 block, the children modify it, and in the end block, we see if the
2402 resultant split is OK, and if so, we add it to the input Transaction*
2403 account group.
2404
2405 from parent: Transaction*
2406 for children: new Split*
2407 result: NA
2408 -----------
2409 start: create new Split*, and store in data_for_children.
2410 chars: allow and ignore only whitespace.
2411 end: commit split to transaction if appropriate.
2412 cleanup-result: NA
2413 cleanup-chars: NA
2414 fail: delete Transaction* in data_for_children
2415 result-fail: NA
2416 chars-fail: NA
2417
2418 */
2419
2420static gboolean
2421txn_restore_split_start_handler (GSList* sibling_data, gpointer parent_data,
2422 gpointer global_data,
2423 gpointer* data_for_children, gpointer* result,
2424 const gchar* tag, gchar** attrs)
2425{
2426 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
2427 Split* s = xaccMallocSplit (pstatus->book);
2428 g_return_val_if_fail (s, FALSE);
2429 *data_for_children = s;
2430 return (TRUE);
2431}
2432
2433static gboolean
2434txn_restore_split_end_handler (gpointer data_for_children,
2435 GSList* data_from_children, GSList* sibling_data,
2436 gpointer parent_data, gpointer global_data,
2437 gpointer* result, const gchar* tag)
2438{
2439 Transaction* t = (Transaction*) parent_data;
2440 Split* s = (Split*) data_for_children;
2441
2442 g_return_val_if_fail (s, FALSE);
2443 if (!t)
2444 {
2445 xaccSplitDestroy (s);
2446 return (FALSE);
2447 }
2448
2449 if (!xaccSplitGetGUID (s))
2450 {
2451 /* must at least have a GncGUID for a restore */
2452 xaccSplitDestroy (s);
2453 return (FALSE);
2454 }
2455
2456 xaccTransAppendSplit (t, s);
2457 return (TRUE);
2458}
2459
2460static gboolean
2461txn_restore_split_after_child_handler (gpointer data_for_children,
2462 GSList* data_from_children,
2463 GSList* sibling_data,
2464 gpointer parent_data,
2465 gpointer global_data,
2466 gpointer* result,
2467 const gchar* tag,
2468 const gchar* child_tag,
2469 sixtp_child_result* child_result)
2470{
2471 Split* s = (Split*) data_for_children;
2472 g_return_val_if_fail (s, FALSE);
2473 if (!child_result) return (TRUE);
2474 if (child_result->type != SIXTP_CHILD_RESULT_NODE) return (TRUE);
2475
2476 if (strcmp (child_result->tag, "slots") == 0)
2477 {
2478 KvpFrame* f = static_cast<KvpFrame*> (child_result->data);
2479 g_return_val_if_fail (f, FALSE);
2480 if (s->inst.kvp_data) delete s->inst.kvp_data;
2481 s->inst.kvp_data = f;
2482 child_result->should_cleanup = FALSE;
2483 }
2484 else if (strcmp (child_result->tag, "quantity") == 0)
2485 {
2486 gnc_numeric* n = (gnc_numeric*) child_result->data;
2487 g_return_val_if_fail (n, FALSE);
2488 xaccSplitSetAmount (s, *n);
2489 /* let the normal child_result handler clean up n */
2490 }
2491 else if (strcmp (child_result->tag, "value") == 0)
2492 {
2493 gnc_numeric* n = (gnc_numeric*) child_result->data;
2494 g_return_val_if_fail (n, FALSE);
2495 xaccSplitSetValue (s, *n);
2496 /* let the normal child_result handler clean up n */
2497 }
2498
2499 return (TRUE);
2500}
2501
2502static void
2503txn_restore_split_fail_handler (gpointer data_for_children,
2504 GSList* data_from_children,
2505 GSList* sibling_data,
2506 gpointer parent_data,
2507 gpointer global_data,
2508 gpointer* result,
2509 const gchar* tag)
2510{
2511 Split* s = (Split*) data_for_children;
2512 if (s) xaccSplitDestroy (s);
2513}
2514
2515/****************************************************************************/
2516/* <guid> (lineage <split> <restore> <transaction>)
2517
2518 restores a given split's guid.
2519
2520 from parent: Split*
2521 for children: NA
2522 result: NA
2523 -----------
2524 start: NA
2525 characters: return string copy for accumulation in end handler.
2526 end: concatenate all chars and set as split GncGUID if not duplicate.
2527
2528 cleanup-result: NA
2529 cleanup-chars: g_free the result string.
2530 fail: NA
2531 result-fail: NA
2532 chars-fail: g_free the result string.
2533
2534 */
2535
2536static gboolean
2537txn_restore_split_guid_end_handler (gpointer data_for_children,
2538 GSList* data_from_children, GSList* sibling_data,
2539 gpointer parent_data, gpointer global_data,
2540 gpointer* result, const gchar* tag)
2541{
2542 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
2543 Split* s = (Split*) parent_data;
2544 gchar* txt = NULL;
2545 GncGUID gid;
2546 gboolean ok;
2547
2548 g_return_val_if_fail (s, FALSE);
2549
2550 txt = concatenate_child_result_chars (data_from_children);
2551 g_return_val_if_fail (txt, FALSE);
2552
2553 ok = string_to_guid (txt, &gid);
2554 g_free (txt);
2555
2556 g_return_val_if_fail (ok, FALSE);
2557
2558 if (xaccSplitLookup (&gid, pstatus->book))
2559 {
2560 return (FALSE);
2561 }
2562
2563 xaccSplitSetGUID (s, &gid);
2564 return (TRUE);
2565}
2566
2567/****************************************************************************/
2568/* <memo> (lineage <split> <restore> <transaction>)
2569
2570 restores a given split's memo.
2571
2572 from parent: Split*
2573 for children: NA
2574 result: NA
2575 -----------
2576 start: NA
2577 characters: return string copy for accumulation in end handler.
2578 end: concatenate all chars and set as split description.
2579
2580 cleanup-result: NA
2581 cleanup-chars: g_free the result string.
2582 fail: NA
2583 result-fail: NA
2584 chars-fail: g_free the result string.
2585
2586 */
2587
2588static gboolean
2589txn_restore_split_memo_end_handler (gpointer data_for_children,
2590 GSList* data_from_children, GSList* sibling_data,
2591 gpointer parent_data, gpointer global_data,
2592 gpointer* result, const gchar* tag)
2593{
2594 Split* s = (Split*) parent_data;
2595 gchar* txt = NULL;
2596
2597 g_return_val_if_fail (s, FALSE);
2598
2599 txt = concatenate_child_result_chars (data_from_children);
2600 g_return_val_if_fail (txt, FALSE);
2601
2602 xaccSplitSetMemo (s, txt);
2603 g_free (txt);
2604 return (TRUE);
2605}
2606
2607/****************************************************************************/
2608/* <action> (lineage <split> <restore> <transaction>)
2609
2610 restores a given split's action.
2611
2612 from parent: Split*
2613 for children: NA
2614 result: NA
2615 -----------
2616 start: NA
2617 characters: return string copy for accumulation in end handler.
2618 end: concatenate all chars and set as split action.
2619
2620 cleanup-result: NA
2621 cleanup-chars: g_free the result string.
2622 fail: NA
2623 result-fail: NA
2624 chars-fail: g_free the result string.
2625
2626 */
2627
2628static gboolean
2629txn_restore_split_action_end_handler (gpointer data_for_children,
2630 GSList* data_from_children, GSList* sibling_data,
2631 gpointer parent_data, gpointer global_data,
2632 gpointer* result, const gchar* tag)
2633{
2634 Split* s = (Split*) parent_data;
2635 gchar* txt = NULL;
2636
2637 g_return_val_if_fail (s, FALSE);
2638
2639 txt = concatenate_child_result_chars (data_from_children);
2640 g_return_val_if_fail (txt, FALSE);
2641
2642 xaccSplitSetAction (s, txt);
2643 g_free (txt);
2644 return (TRUE);
2645}
2646
2647/****************************************************************************/
2648/* <reconcile-state> (lineage <split> <restore> <transaction>)
2649
2650 restores a given split's reconcile-state.
2651
2652 from parent: Split*
2653 for children: NA
2654 result: NA
2655 -----------
2656 start: NA
2657 characters: return string copy for accumulation in end handler.
2658 end: concatenate all chars and set as split reconcile-state.
2659
2660 cleanup-result: NA
2661 cleanup-chars: g_free the result string.
2662 fail: NA
2663 result-fail: NA
2664 chars-fail: g_free the result string.
2665
2666 */
2667
2668static gboolean
2669txn_restore_split_reconcile_state_end_handler (gpointer data_for_children,
2670 GSList* data_from_children, GSList* sibling_data,
2671 gpointer parent_data, gpointer global_data,
2672 gpointer* result, const gchar* tag)
2673{
2674 Split* s = (Split*) parent_data;
2675 gchar* txt = NULL;
2676
2677 g_return_val_if_fail (s, FALSE);
2678
2679 txt = concatenate_child_result_chars (data_from_children);
2680 g_return_val_if_fail (txt, FALSE);
2681
2682 if (strlen (txt) != 1)
2683 {
2684 g_free (txt);
2685 return (FALSE);
2686 }
2687
2688 xaccSplitSetReconcile (s, txt[0]);
2689 g_free (txt);
2690 return (TRUE);
2691}
2692
2693/****************************************************************************/
2694/* <reconcile-date> (lineage <split> <restore> <transaction>)
2695
2696 restores a given split's reconcile-date.
2697
2698 Just uses a generic_timespec parser, but with our own end handler.
2699
2700 end: set reconcile-date.
2701
2702 */
2703
2704static gboolean
2705txn_restore_split_reconcile_date_end_handler (gpointer data_for_children,
2706 GSList* data_from_children, GSList* sibling_data,
2707 gpointer parent_data, gpointer global_data,
2708 gpointer* result, const gchar* tag)
2709{
2710 Split* s = (Split*) parent_data;
2711 Time64ParseInfo* info = (Time64ParseInfo*) data_for_children;
2712
2713 g_return_val_if_fail (info, FALSE);
2714 if (!s || !timespec_parse_ok (info))
2715 {
2716 g_free (info);
2717 return (FALSE);
2718 }
2719
2720 xaccSplitSetDateReconciledSecs (s, info->time);
2721 g_free (info);
2722 return (TRUE);
2723}
2724
2725/****************************************************************************/
2726/* <account> (lineage <split> <restore> <transaction>)
2727
2728 restores a given split's account.
2729
2730 from parent: Split*
2731 for children: NA
2732 result: NA
2733 -----------
2734 start: NA
2735 characters: return string copy for accumulation in end handler.
2736 end: concatenate all chars and set as split account if GncGUID OK.
2737
2738 cleanup-result: NA
2739 cleanup-chars: g_free the result string.
2740 fail: NA
2741 result-fail: NA
2742 chars-fail: g_free the result string.
2743
2744 */
2745
2746static gboolean
2747txn_restore_split_account_end_handler (gpointer data_for_children,
2748 GSList* data_from_children, GSList* sibling_data,
2749 gpointer parent_data, gpointer global_data,
2750 gpointer* result, const gchar* tag)
2751{
2752 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
2753 Split* s = (Split*) parent_data;
2754 Account* acct;
2755 gchar* txt = NULL;
2756 GncGUID gid;
2757 gboolean ok;
2758
2759 g_return_val_if_fail (s, FALSE);
2760
2761 txt = concatenate_child_result_chars (data_from_children);
2762 g_return_val_if_fail (txt, FALSE);
2763
2764 ok = string_to_guid (txt, &gid);
2765 g_free (txt);
2766
2767 g_return_val_if_fail (ok, FALSE);
2768
2769 acct = xaccAccountLookup (&gid, pstatus->book);
2770 g_return_val_if_fail (acct, FALSE);
2771
2772 xaccAccountInsertSplit (acct, s);
2773 return (TRUE);
2774}
2775
2776
2777/****************************************************************************/
2778
2779
2780/****************************************************************************/
2781
2782static sixtp*
2783gnc_txn_restore_split_parser_new (void)
2784{
2785 sixtp* top_level;
2786
2787 if (! (top_level =
2788 sixtp_set_any (sixtp_new (), FALSE,
2789 SIXTP_START_HANDLER_ID, txn_restore_split_start_handler,
2790 SIXTP_CHARACTERS_HANDLER_ID,
2791 allow_and_ignore_only_whitespace,
2792 SIXTP_END_HANDLER_ID, txn_restore_split_end_handler,
2793 SIXTP_FAIL_HANDLER_ID, txn_restore_split_fail_handler,
2794 SIXTP_AFTER_CHILD_HANDLER_ID,
2795 txn_restore_split_after_child_handler,
2796 SIXTP_NO_MORE_HANDLERS)))
2797 {
2798 return NULL;
2799 }
2800
2801 if (!sixtp_add_some_sub_parsers (
2802 top_level, TRUE,
2803 "guid", restore_char_generator (txn_restore_split_guid_end_handler),
2804 "memo", restore_char_generator (txn_restore_split_memo_end_handler),
2805 "action",
2806 restore_char_generator (txn_restore_split_action_end_handler),
2807 "account",
2808 restore_char_generator (txn_restore_split_account_end_handler),
2809 "reconcile-state",
2810 restore_char_generator (txn_restore_split_reconcile_state_end_handler),
2811 "reconcile-date",
2812 generic_timespec_parser_new (
2813 txn_restore_split_reconcile_date_end_handler),
2814 "quantity", generic_gnc_numeric_parser_new (),
2815 "value", generic_gnc_numeric_parser_new (),
2816 "slots", kvp_frame_parser_new (),
2817 NULL, NULL))
2818 {
2819 return NULL;
2820 }
2821
2822 return (top_level);
2823}
2824
2825/***************************************************************************/
2826
2827static sixtp*
2828gnc_transaction_parser_new (void)
2829{
2830 sixtp* top_level;
2831 sixtp* restore_pr;
2832
2833 if (! (top_level =
2834 sixtp_set_any (sixtp_new (), FALSE,
2835 SIXTP_START_HANDLER_ID, transaction_start_handler,
2836 SIXTP_CHARACTERS_HANDLER_ID,
2837 allow_and_ignore_only_whitespace,
2838 SIXTP_AFTER_CHILD_HANDLER_ID,
2839 txn_restore_after_child_handler,
2840 SIXTP_NO_MORE_HANDLERS)))
2841 {
2842 return NULL;
2843 }
2844
2845 /* <restore> */
2846 if (! (restore_pr =
2847 sixtp_set_any (sixtp_new (), FALSE,
2848 SIXTP_START_HANDLER_ID, txn_restore_start_handler,
2849 SIXTP_END_HANDLER_ID, txn_restore_end_handler,
2850 SIXTP_FAIL_HANDLER_ID, txn_restore_fail_handler,
2851 SIXTP_AFTER_CHILD_HANDLER_ID,
2852 txn_restore_after_child_handler,
2853 SIXTP_NO_MORE_HANDLERS)))
2854 {
2855 sixtp_destroy (top_level);
2856 return (NULL);
2857 }
2858 sixtp_add_sub_parser (top_level, "restore", restore_pr);
2859
2860 if (! (sixtp_add_some_sub_parsers (
2861 restore_pr, TRUE,
2862 "guid", restore_char_generator (txn_restore_guid_end_handler),
2863 "num", restore_char_generator (txn_restore_num_end_handler),
2864 "description",
2865 restore_char_generator (txn_restore_description_end_handler),
2866 "date-posted",
2867 generic_timespec_parser_new (txn_rest_date_posted_end_handler),
2868 "date-entered",
2869 generic_timespec_parser_new (txn_rest_date_entered_end_handler),
2870 "slots", kvp_frame_parser_new (),
2871 "split", gnc_txn_restore_split_parser_new (),
2872 NULL, NULL)))
2873 {
2874 sixtp_destroy (top_level);
2875 return NULL;
2876 }
2877
2878 return (top_level);
2879}
2880
2881/****************************************************************************/
2882/****************************************************************************/
2883
2884/* Read and Write the pricedb as XML -- something like this:
2885
2886 <pricedb>
2887 price-1
2888 price-2
2889 ...
2890 </pricedb>
2891
2892 where each price should look roughly like this:
2893
2894 <price>
2895 <price:id>
2896 00000000111111112222222233333333
2897 </price:id>
2898 <price:commodity>
2899 <cmdty:space>NASDAQ</cmdty:space>
2900 <cmdty:id>RHAT</cmdty:id>
2901 </price:commodity>
2902 <price:currency>
2903 <cmdty:space>ISO?</cmdty:space>
2904 <cmdty:id>USD</cmdty:id>
2905 </price:currency>
2906 <price:time><ts:date>Mon ...</ts:date><ts:ns>12</ts:ns></price:time>
2907 <price:source>Finance::Quote</price:source>
2908 <price:type>bid</price:type>
2909 <price:value>11011/100</price:value>
2910 </price>
2911
2912*/
2913
2914/***********************************************************************/
2915/* READING */
2916/***********************************************************************/
2917
2918/****************************************************************************/
2919/* <price>
2920
2921 restores a price. Does so via a walk of the XML tree in memory.
2922 Returns a GNCPrice * in result.
2923
2924 Right now, a price is legitimate even if all of it's fields are not
2925 set. We may need to change that later, but at the moment.
2926
2927*/
2928
2929static gboolean
2930price_parse_xml_sub_node (GNCPrice* p, xmlNodePtr sub_node, QofBook* book)
2931{
2932 if (!p || !sub_node) return FALSE;
2933
2934 gnc_price_begin_edit (p);
2935
2936 if (g_strcmp0 ("price:id", (char*)sub_node->name) == 0)
2937 {
2938 auto c = dom_tree_to_guid (sub_node);
2939 if (!c) return FALSE;
2940 gnc_price_set_guid (p, &*c);
2941 }
2942 else if (g_strcmp0 ("price:commodity", (char*)sub_node->name) == 0)
2943 {
2944 gnc_commodity* c = dom_tree_to_commodity_ref (sub_node, book);
2945 if (!c) return FALSE;
2946 gnc_price_set_commodity (p, c);
2947 }
2948 else if (g_strcmp0 ("price:currency", (char*)sub_node->name) == 0)
2949 {
2950 gnc_commodity* c = dom_tree_to_commodity_ref (sub_node, book);
2951 if (!c) return FALSE;
2952 gnc_price_set_currency (p, c);
2953 }
2954 else if (g_strcmp0 ("price:time", (char*)sub_node->name) == 0)
2955 {
2956 time64 time = dom_tree_to_time64 (sub_node);
2957 if (!dom_tree_valid_time64 (time, sub_node->name)) time = 0;
2958 gnc_price_set_time64 (p, time);
2959 }
2960 else if (g_strcmp0 ("price:source", (char*)sub_node->name) == 0)
2961 {
2962 if (!apply_xmlnode_text (gnc_price_set_source_string, p, sub_node))
2963 return false;
2964 }
2965 else if (g_strcmp0 ("price:type", (char*)sub_node->name) == 0)
2966 {
2967 if (!apply_xmlnode_text (gnc_price_set_typestr, p, sub_node))
2968 return false;
2969 }
2970 else if (g_strcmp0 ("price:value", (char*)sub_node->name) == 0)
2971 {
2972 gnc_price_set_value (p, dom_tree_to_gnc_numeric (sub_node));
2973 }
2974 gnc_price_commit_edit (p);
2975 return TRUE;
2976}
2977
2978static gboolean
2979price_parse_xml_end_handler (gpointer data_for_children,
2980 GSList* data_from_children,
2981 GSList* sibling_data,
2982 gpointer parent_data,
2983 gpointer global_data,
2984 gpointer* result,
2985 const gchar* tag)
2986{
2987 gboolean ok = TRUE;
2988 xmlNodePtr price_xml = (xmlNodePtr) data_for_children;
2989 xmlNodePtr child;
2990 GNCPrice* p = NULL;
2991 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
2992
2993 /* we haven't been handed the *top* level node yet... */
2994 if (parent_data) return TRUE;
2995
2996 *result = NULL;
2997
2998 if (!price_xml) return FALSE;
2999 if (price_xml->next)
3000 {
3001 ok = FALSE;
3002 goto cleanup_and_exit;
3003 }
3004 if (price_xml->prev)
3005 {
3006 ok = FALSE;
3007 goto cleanup_and_exit;
3008 }
3009 if (!price_xml->xmlChildrenNode)
3010 {
3011 ok = FALSE;
3012 goto cleanup_and_exit;
3013 }
3014
3015 p = gnc_price_create (pstatus->book);
3016 if (!p)
3017 {
3018 ok = FALSE;
3019 goto cleanup_and_exit;
3020 }
3021
3022 for (child = price_xml->xmlChildrenNode; child; child = child->next)
3023 {
3024 switch (child->type)
3025 {
3026 case XML_COMMENT_NODE:
3027 case XML_TEXT_NODE:
3028 break;
3029 case XML_ELEMENT_NODE:
3030 if (!price_parse_xml_sub_node (p, child, pstatus->book))
3031 {
3032 ok = FALSE;
3033 goto cleanup_and_exit;
3034 }
3035 break;
3036 default:
3037 PERR ("Unknown node type (%d) while parsing gnc-price xml.", child->type);
3038 child = NULL;
3039 ok = FALSE;
3040 goto cleanup_and_exit;
3041 break;
3042 }
3043 }
3044
3045cleanup_and_exit:
3046 if (ok)
3047 {
3048 *result = p;
3049 }
3050 else
3051 {
3052 *result = NULL;
3053 gnc_price_unref (p);
3054 }
3055 xmlFreeNode (price_xml);
3056 return ok;
3057}
3058
3059static void
3060cleanup_gnc_price (sixtp_child_result* result)
3061{
3062 if (result->data) gnc_price_unref ((GNCPrice*) result->data);
3063}
3064
3065static sixtp*
3066gnc_price_parser_new (void)
3067{
3068 return sixtp_dom_parser_new (price_parse_xml_end_handler,
3069 cleanup_gnc_price,
3070 cleanup_gnc_price);
3071}
3072
3073
3074/****************************************************************************/
3075/* <pricedb> (lineage <ledger-data>)
3076
3077 restores a pricedb. We allocate the new db in the start block, the
3078 children add to it, and it gets returned in result. Note that the
3079 cleanup handler will destroy the pricedb, so the parent needs to
3080 stop that if desired.
3081
3082 result: GNCPriceDB*
3083
3084 start: create new GNCPriceDB*, and leave in *data_for_children.
3085 cleanup-result: destroy GNCPriceDB*
3086 result-fail: destroy GNCPriceDB*
3087
3088*/
3089
3090static gboolean
3091pricedb_start_handler (GSList* sibling_data,
3092 gpointer parent_data,
3093 gpointer global_data,
3094 gpointer* data_for_children,
3095 gpointer* result,
3096 const gchar* tag,
3097 gchar** attrs)
3098{
3099 GNCParseStatus* pstatus = (GNCParseStatus*) global_data;
3100 GNCPriceDB* db = gnc_pricedb_get_db (pstatus->book);
3101 g_return_val_if_fail (db, FALSE);
3102 *result = db;
3103 return (TRUE);
3104}
3105
3106static gboolean
3107pricedb_after_child_handler (gpointer data_for_children,
3108 GSList* data_from_children,
3109 GSList* sibling_data,
3110 gpointer parent_data,
3111 gpointer global_data,
3112 gpointer* result,
3113 const gchar* tag,
3114 const gchar* child_tag,
3115 sixtp_child_result* child_result)
3116{
3117 GNCPriceDB* db = (GNCPriceDB*) * result;
3118
3119 g_return_val_if_fail (db, FALSE);
3120
3121 /* right now children have to produce results :> */
3122 if (!child_result) return (FALSE);
3123 if (child_result->type != SIXTP_CHILD_RESULT_NODE) return (FALSE);
3124
3125 if (strcmp (child_result->tag, "price") == 0)
3126 {
3127 GNCPrice* p = (GNCPrice*) child_result->data;
3128
3129 g_return_val_if_fail (p, FALSE);
3130 gnc_pricedb_add_price (db, p);
3131 return TRUE;
3132 }
3133 else
3134 {
3135 return FALSE;
3136 }
3137 return FALSE;
3138}
3139
3140static void
3141pricedb_cleanup_result_handler (sixtp_child_result* result)
3142{
3143 if (result->data)
3144 {
3145 GNCPriceDB* db = (GNCPriceDB*) result->data;
3146 if (db) gnc_pricedb_destroy (db);
3147 result->data = NULL;
3148 }
3149}
3150
3151static sixtp*
3152gnc_pricedb_parser_new (void)
3153{
3154 sixtp* top_level;
3155 sixtp* price_parser;
3156
3157 top_level =
3158 sixtp_set_any (sixtp_new (), TRUE,
3159 SIXTP_START_HANDLER_ID, pricedb_start_handler,
3160 SIXTP_AFTER_CHILD_HANDLER_ID, pricedb_after_child_handler,
3161 SIXTP_CHARACTERS_HANDLER_ID,
3162 allow_and_ignore_only_whitespace,
3163 SIXTP_RESULT_FAIL_ID, pricedb_cleanup_result_handler,
3164 SIXTP_CLEANUP_RESULT_ID, pricedb_cleanup_result_handler,
3165 SIXTP_NO_MORE_HANDLERS);
3166
3167 if (!top_level) return NULL;
3168
3169 price_parser = gnc_price_parser_new ();
3170
3171 if (!price_parser)
3172 {
3173 sixtp_destroy (top_level);
3174 return NULL;
3175 }
3176
3177 sixtp_add_sub_parser (top_level, "price", price_parser);
3178
3179 return top_level;
3180}
3181
3182/* ======================= END OF FILE ============================== */
This is the private header for the account structure.
Account handling public routines.
convert single-entry accounts to clean double-entry
API for the transaction logger.
API for Transactions and Splits (journal entries)
a simple price database for gnucash
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition Account.cpp:1516
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition Account.cpp:1475
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed.
Definition Account.h:103
void gnc_account_append_child(Account *new_parent, Account *child)
This function will remove from the child account any pre-existing parent relationship,...
Definition Account.cpp:2836
void xaccAccountSetName(Account *acc, const char *str)
Set the account's name.
Definition Account.cpp:2458
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition Account.cpp:3044
void xaccAccountSetDescription(Account *acc, const char *str)
Set the account's description.
Definition Account.cpp:2497
void xaccAccountDestroy(Account *acc)
The xaccAccountDestroy() routine can be used to get rid of an account.
Definition Account.cpp:1590
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
Definition Account.cpp:2935
void xaccAccountSetNotes(Account *acc, const char *str)
Set the account's notes.
Definition Account.cpp:2655
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Set the account's type.
Definition Account.cpp:2437
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition Account.cpp:1270
void xaccAccountSetCode(Account *acc, const char *str)
Set the account's accounting code.
Definition Account.cpp:2478
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account's commodity.
Definition Account.cpp:2678
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
Definition Account.cpp:2050
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
Create a new commodity.
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
Add a new commodity to the commodity table.
void gnc_commodity_destroy(gnc_commodity *cm)
Destroy a commodity.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
gboolean xaccAccountStringToType(const char *str, GNCAccountType *type)
Conversion routines for the account types to/from strings that are used in persistent storage,...
Definition Account.cpp:4284
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
void xaccTransSetNum(Transaction *trans, const char *xnum)
Sets the transaction Number (or ID) field; rather than use this function directly,...
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
void DxaccAccountSetCurrency(Account *acc, gnc_commodity *currency)
Definition Account.cpp:2785
#define xaccTransGetGUID(X)
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id,...
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction,...
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account.
Definition Account.h:1069
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
Definition Account.cpp:3396
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition guid.cpp:155
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
gnc_numeric gnc_numeric_from_string(const gchar *str)
Read a gnc_numeric from str, skipping any leading whitespace.
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Return the pricedb associated with the book.
void gnc_pricedb_destroy(GNCPriceDB *db)
Destroy the given pricedb and unref all of the prices it contains.
gboolean gnc_pricedb_add_price(GNCPriceDB *db, GNCPrice *p)
Add a price to the pricedb.
GNCPrice * gnc_price_create(QofBook *book)
gnc_price_create - returns a newly allocated and initialized price with a reference count of 1.
void gnc_price_unref(GNCPrice *p)
gnc_price_unref - indicate you're finished with a price (i.e.
void xaccAccountTreeScrubCommodities(Account *acc)
The xaccAccountTreeScrubCommodities will scrub the currency/commodity of all accounts & transactions ...
Definition Scrub.cpp:1303
void xaccLogEnable(void)
document me
Definition TransLog.cpp:100
void xaccLogDisable(void)
document me
Definition TransLog.cpp:96
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition Split.cpp:1506
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id,...
Definition Split.cpp:1091
#define xaccSplitGetGUID(X)
Definition Split.h:579
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
Split * xaccMallocSplit(QofBook *book)
Constructor.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64.
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition Split.cpp:1786
api for Version 1 XML-based file format
STRUCTS.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47
Definition sixtp.h:130