1
/********************************************************************\
2
* Transaction-xml-parser-v1.c *
3
* Copyright (C) 2000 Gnumatic, Inc. *
5
* This program is free software; you can redistribute it and/or *
6
* modify it under the terms of the GNU General Public License as *
7
* published by the Free Software Foundation; either version 2 of *
8
* the License, or (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License*
16
* along with this program; if not, contact: *
18
* Free Software Foundation Voice: +1-617-542-5942 *
19
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
20
* Boston, MA 02111-1307, USA gnu@gnu.org *
21
\********************************************************************/
28
#include "sixtp-utils.h"
29
#include "sixtp-parsers.h"
30
#include "sixtp-writers.h"
31
#include "sixtp-xml-write-utils.h"
33
#include "Transaction.h"
34
#include "TransactionP.h"
37
/****************************************************************************/
38
/* <transaction> (parent <ledger-data>)
40
This block does nothing but pass the ledger-data account group down
41
to its children. It generates no data of its own, so it doesn't
46
to-children-via-*result: AccountGroup*
50
start: pass input to children.
52
characters: ignore whitespace only
69
transaction_start_handler(GSList* sibling_data, gpointer parent_data,
70
gpointer global_data, gpointer *data_for_children,
71
gpointer *result, const gchar *tag, gchar **attrs)
73
/* pass the parent data down to the children */
74
*data_for_children = parent_data;
78
/****************************************************************************/
79
/* <restore> (lineage <transaction> <ledger-data>)
81
restores a given transaction. We allocate the new transaction in
82
the start block, the children modify it, and in the end block, we
83
see if the resultant account is OK, and if so, we add it to the
84
ledger-data's account group.
86
from parent: AccountGroup*
88
for children: new Transaction*
94
start: create new Transaction*, and store in data_for_children.
96
chars: allow and ignore only whitespace.
98
end: commit transaction to group if appropriate.
104
fail: delete Transaction* in data_for_children
113
txn_restore_start_handler(GSList* sibling_data, gpointer parent_data,
114
gpointer global_data, gpointer *data_for_children,
115
gpointer *result, const gchar *tag, gchar **attrs)
117
Transaction *trans = xaccMallocTransaction();
118
g_return_val_if_fail(trans, FALSE);
119
xaccTransBeginEdit(trans);
120
*data_for_children = trans;
125
txn_restore_end_handler(gpointer data_for_children,
126
GSList *data_from_children, GSList *sibling_data,
127
gpointer parent_data, gpointer global_data,
128
gpointer *result, const gchar *tag)
130
AccountGroup *ag = (AccountGroup *) parent_data;
131
Transaction *trans = (Transaction *) data_for_children;
133
g_return_val_if_fail(trans, FALSE);
135
xaccTransDestroy(trans);
136
xaccTransCommitEdit(trans);
140
if(!xaccTransGetGUID(trans)) {
141
/* must at least have a GUID for a restore */
142
xaccTransDestroy(trans);
143
xaccTransCommitEdit(trans);
147
/* FIXME: what if the trans has no splits? */
148
xaccTransCommitEdit(trans);
154
txn_restore_after_child_handler(gpointer data_for_children,
155
GSList* data_from_children,
156
GSList* sibling_data,
157
gpointer parent_data,
158
gpointer global_data,
161
const gchar *child_tag,
162
sixtp_child_result *child_result)
164
Transaction *trans = (Transaction *) data_for_children;
165
g_return_val_if_fail(trans, FALSE);
166
if(!child_result) return(TRUE);
167
if(child_result->type != SIXTP_CHILD_RESULT_NODE) return(TRUE);
168
if(strcmp(child_result->tag, "slots") == 0) {
169
kvp_frame *f = (kvp_frame *) child_result->data;
170
g_return_val_if_fail(f, FALSE);
171
if(trans->kvp_data) kvp_frame_delete(trans->kvp_data);
173
child_result->should_cleanup = FALSE;
179
txn_restore_fail_handler(gpointer data_for_children,
180
GSList* data_from_children,
181
GSList* sibling_data,
182
gpointer parent_data,
183
gpointer global_data,
187
Transaction *trans = (Transaction *) data_for_children;
189
xaccTransDestroy(trans);
190
xaccTransCommitEdit(trans);
194
/****************************************************************************/
195
/* <guid> (lineage <restore> <transaction>)
197
restores a given account's guid.
199
from parent: Transaction*
204
characters: return string copy for accumulation in end handler.
205
end: concatenate all chars and set as transaction GUID if not duplicate.
208
cleanup-chars: g_free the result string.
211
chars-fail: g_free the result string.
216
txn_restore_guid_end_handler(gpointer data_for_children,
217
GSList *data_from_children, GSList *sibling_data,
218
gpointer parent_data, gpointer global_data,
219
gpointer *result, const gchar *tag)
221
Transaction *t = (Transaction *) parent_data;
226
g_return_val_if_fail(t, FALSE);
228
txt = concatenate_child_result_chars(data_from_children);
229
g_return_val_if_fail(txt, FALSE);
231
ok = string_to_guid(txt, &gid);
234
g_return_val_if_fail(ok, FALSE);
236
if(xaccTransLookup(&gid)) {
240
xaccTransSetGUID(t, &gid);
244
/****************************************************************************/
245
/* <num> (lineage <restore> <transaction>)
247
restores a given transaction's num.
249
from parent: Transaction*
254
characters: return string copy for accumulation in end handler.
255
end: concatenate all chars and set as transaction num.
258
cleanup-chars: g_free the result string.
261
chars-fail: g_free the result string.
266
txn_restore_num_end_handler(gpointer data_for_children,
267
GSList *data_from_children, GSList *sibling_data,
268
gpointer parent_data, gpointer global_data,
269
gpointer *result, const gchar *tag)
271
Transaction *t = (Transaction *) parent_data;
274
g_return_val_if_fail(t, FALSE);
276
txt = concatenate_child_result_chars(data_from_children);
277
g_return_val_if_fail(txt, FALSE);
279
xaccTransSetNum(t, txt);
284
/****************************************************************************/
285
/* <description> (lineage <restore> <transaction>)
287
restores a given transaction's description.
289
from parent: Transaction*
294
characters: return string copy for accumulation in end handler.
295
end: concatenate all chars and set as transaction description.
298
cleanup-chars: g_free the result string.
301
chars-fail: g_free the result string.
306
txn_restore_description_end_handler(gpointer data_for_children,
307
GSList *data_from_children, GSList *sibling_data,
308
gpointer parent_data, gpointer global_data,
309
gpointer *result, const gchar *tag)
311
Transaction *t = (Transaction *) parent_data;
314
g_return_val_if_fail(t, FALSE);
316
txt = concatenate_child_result_chars(data_from_children);
317
g_return_val_if_fail(txt, FALSE);
319
xaccTransSetDescription(t, txt);
324
/****************************************************************************/
325
/* <date-posted> (lineage <restore> <transaction>)
327
restores a given transaction's posted date.
329
Just uses a generic_timespec parser, but with our own end handler.
331
end: set date posted.
336
txn_rest_date_posted_end_handler(gpointer data_for_children,
337
GSList *data_from_children, GSList *sibling_data,
338
gpointer parent_data, gpointer global_data,
339
gpointer *result, const gchar *tag)
341
Transaction *t = (Transaction *) parent_data;
342
TimespecParseInfo *info = (TimespecParseInfo *) data_for_children;
344
g_return_val_if_fail(info, FALSE);
345
if(!t || !timespec_parse_ok(info)) {
350
xaccTransSetDateTS(t, &(info->ts));
355
/****************************************************************************/
356
/* <date-entered> (lineage <restore> <transaction>)
358
restores a given transaction's entered date.
360
Just uses a generic_timespec parser, but with our own end handler.
362
end: set date entered.
367
txn_rest_date_entered_end_handler(gpointer data_for_children,
368
GSList *data_from_children, GSList *sibling_data,
369
gpointer parent_data, gpointer global_data,
370
gpointer *result, const gchar *tag)
372
Transaction *t = (Transaction *) parent_data;
373
TimespecParseInfo *info = (TimespecParseInfo *) data_for_children;
375
g_return_val_if_fail(info, FALSE);
376
if(!t || !timespec_parse_ok(info)) {
381
xaccTransSetDateEnteredTS(t, &(info->ts));
388
/****************************************************************************/
390
/* <split> (lineage <restore> <transaction> <ledger-data>)
392
Restores a given split. We allocate the new split in the start
393
block, the children modify it, and in the end block, we see if the
394
resultant split is OK, and if so, we add it to the input Transaction*
397
from parent: Transaction*
398
for children: new Split*
401
start: create new Split*, and store in data_for_children.
402
chars: allow and ignore only whitespace.
403
end: commit split to transaction if appropriate.
406
fail: delete Transaction* in data_for_children
413
txn_restore_split_start_handler(GSList* sibling_data, gpointer parent_data,
414
gpointer global_data,
415
gpointer *data_for_children, gpointer *result,
416
const gchar *tag, gchar **attrs)
418
Split *s = xaccMallocSplit();
419
g_return_val_if_fail(s, FALSE);
420
*data_for_children = s;
425
txn_restore_split_end_handler(gpointer data_for_children,
426
GSList *data_from_children, GSList *sibling_data,
427
gpointer parent_data, gpointer global_data,
428
gpointer *result, const gchar *tag)
430
Transaction *t = (Transaction *) parent_data;
431
Split *s = (Split *) data_for_children;
433
g_return_val_if_fail(s, FALSE);
439
if(!xaccSplitGetGUID(s)) {
440
/* must at least have a GUID for a restore */
445
xaccTransAppendSplit(t, s);
450
txn_restore_split_after_child_handler(gpointer data_for_children,
451
GSList* data_from_children,
452
GSList* sibling_data,
453
gpointer parent_data,
454
gpointer global_data,
457
const gchar *child_tag,
458
sixtp_child_result *child_result)
460
Split *s = (Split *) data_for_children;
461
g_return_val_if_fail(s, FALSE);
462
if(!child_result) return(TRUE);
463
if(child_result->type != SIXTP_CHILD_RESULT_NODE) return(TRUE);
465
if(strcmp(child_result->tag, "slots") == 0) {
466
kvp_frame *f = (kvp_frame *) child_result->data;
467
g_return_val_if_fail(f, FALSE);
468
if(s->kvp_data) kvp_frame_delete(s->kvp_data);
470
child_result->should_cleanup = FALSE;
472
else if(strcmp(child_result->tag, "quantity") == 0) {
473
gnc_numeric *n = (gnc_numeric *) child_result->data;
474
g_return_val_if_fail(n, FALSE);
475
xaccSplitSetShareAmount(s, *n);
476
/* let the normal child_result handler clean up n */
478
else if(strcmp(child_result->tag, "value") == 0) {
479
gnc_numeric *n = (gnc_numeric *) child_result->data;
480
g_return_val_if_fail(n, FALSE);
481
xaccSplitSetValue(s, *n);
482
/* let the normal child_result handler clean up n */
489
txn_restore_split_fail_handler(gpointer data_for_children,
490
GSList* data_from_children,
491
GSList* sibling_data,
492
gpointer parent_data,
493
gpointer global_data,
497
Split *s = (Split *) data_for_children;
498
if(s) xaccSplitDestroy(s);
501
/****************************************************************************/
502
/* <guid> (lineage <split> <restore> <transaction>)
504
restores a given split's guid.
511
characters: return string copy for accumulation in end handler.
512
end: concatenate all chars and set as split GUID if not duplicate.
515
cleanup-chars: g_free the result string.
518
chars-fail: g_free the result string.
523
txn_restore_split_guid_end_handler(gpointer data_for_children,
524
GSList *data_from_children, GSList *sibling_data,
525
gpointer parent_data, gpointer global_data,
526
gpointer *result, const gchar *tag)
528
Split *s = (Split *) parent_data;
533
g_return_val_if_fail(s, FALSE);
535
txt = concatenate_child_result_chars(data_from_children);
536
g_return_val_if_fail(txt, FALSE);
538
ok = string_to_guid(txt, &gid);
541
g_return_val_if_fail(ok, FALSE);
543
if(xaccSplitLookup(&gid)) {
547
xaccSplitSetGUID(s, &gid);
551
/****************************************************************************/
552
/* <memo> (lineage <split> <restore> <transaction>)
554
restores a given split's memo.
561
characters: return string copy for accumulation in end handler.
562
end: concatenate all chars and set as split description.
565
cleanup-chars: g_free the result string.
568
chars-fail: g_free the result string.
573
txn_restore_split_memo_end_handler(gpointer data_for_children,
574
GSList *data_from_children, GSList *sibling_data,
575
gpointer parent_data, gpointer global_data,
576
gpointer *result, const gchar *tag)
578
Split *s = (Split *) parent_data;
581
g_return_val_if_fail(s, FALSE);
583
txt = concatenate_child_result_chars(data_from_children);
584
g_return_val_if_fail(txt, FALSE);
586
xaccSplitSetMemo(s, txt);
591
/****************************************************************************/
592
/* <action> (lineage <split> <restore> <transaction>)
594
restores a given split's action.
601
characters: return string copy for accumulation in end handler.
602
end: concatenate all chars and set as split action.
605
cleanup-chars: g_free the result string.
608
chars-fail: g_free the result string.
613
txn_restore_split_action_end_handler(gpointer data_for_children,
614
GSList *data_from_children, GSList *sibling_data,
615
gpointer parent_data, gpointer global_data,
616
gpointer *result, const gchar *tag)
618
Split *s = (Split *) parent_data;
621
g_return_val_if_fail(s, FALSE);
623
txt = concatenate_child_result_chars(data_from_children);
624
g_return_val_if_fail(txt, FALSE);
626
xaccSplitSetAction(s, txt);
631
/****************************************************************************/
632
/* <reconcile-state> (lineage <split> <restore> <transaction>)
634
restores a given split's reconcile-state.
641
characters: return string copy for accumulation in end handler.
642
end: concatenate all chars and set as split reconcile-state.
645
cleanup-chars: g_free the result string.
648
chars-fail: g_free the result string.
653
txn_restore_split_reconcile_state_end_handler(gpointer data_for_children,
654
GSList *data_from_children, GSList *sibling_data,
655
gpointer parent_data, gpointer global_data,
656
gpointer *result, const gchar *tag)
658
Split *s = (Split *) parent_data;
661
g_return_val_if_fail(s, FALSE);
663
txt = concatenate_child_result_chars(data_from_children);
664
g_return_val_if_fail(txt, FALSE);
666
if(strlen(txt) != 1) {
671
xaccSplitSetReconcile(s, txt[0]);
676
/****************************************************************************/
677
/* <reconcile-date> (lineage <split> <restore> <transaction>)
679
restores a given split's reconcile-date.
681
Just uses a generic_timespec parser, but with our own end handler.
683
end: set reconcile-date.
688
txn_restore_split_reconcile_date_end_handler(gpointer data_for_children,
689
GSList *data_from_children, GSList *sibling_data,
690
gpointer parent_data, gpointer global_data,
691
gpointer *result, const gchar *tag)
693
Split *s = (Split *) parent_data;
694
TimespecParseInfo *info = (TimespecParseInfo *) data_for_children;
696
g_return_val_if_fail(info, FALSE);
697
if(!s || !timespec_parse_ok(info)) {
702
xaccSplitSetDateReconciledTS(s, &(info->ts));
707
/****************************************************************************/
708
/* <account> (lineage <split> <restore> <transaction>)
710
restores a given split's account.
717
characters: return string copy for accumulation in end handler.
718
end: concatenate all chars and set as split account if GUID OK.
721
cleanup-chars: g_free the result string.
724
chars-fail: g_free the result string.
729
txn_restore_split_account_end_handler(gpointer data_for_children,
730
GSList *data_from_children, GSList *sibling_data,
731
gpointer parent_data, gpointer global_data,
732
gpointer *result, const gchar *tag)
734
Split *s = (Split *) parent_data;
740
g_return_val_if_fail(s, FALSE);
742
txt = concatenate_child_result_chars(data_from_children);
743
g_return_val_if_fail(txt, FALSE);
745
ok = string_to_guid(txt, &gid);
748
g_return_val_if_fail(ok, FALSE);
750
acct = xaccAccountLookup(&gid);
751
g_return_val_if_fail(acct, FALSE);
753
xaccAccountInsertSplit(acct, s);
758
/****************************************************************************/
761
/****************************************************************************/
764
gnc_txn_restore_split_parser_new(void)
769
sixtp_set_any(sixtp_new(), FALSE,
770
SIXTP_START_HANDLER_ID, txn_restore_split_start_handler,
771
SIXTP_CHARACTERS_HANDLER_ID,
772
allow_and_ignore_only_whitespace,
773
SIXTP_END_HANDLER_ID, txn_restore_split_end_handler,
774
SIXTP_FAIL_HANDLER_ID, txn_restore_split_fail_handler,
775
SIXTP_AFTER_CHILD_HANDLER_ID,
776
txn_restore_split_after_child_handler,
777
SIXTP_NO_MORE_HANDLERS)))
782
if(!sixtp_add_some_sub_parsers(
784
"guid", restore_char_generator(txn_restore_split_guid_end_handler),
785
"memo", restore_char_generator(txn_restore_split_memo_end_handler),
787
restore_char_generator(txn_restore_split_action_end_handler),
789
restore_char_generator(txn_restore_split_account_end_handler),
791
restore_char_generator(txn_restore_split_reconcile_state_end_handler),
793
generic_timespec_parser_new(
794
txn_restore_split_reconcile_date_end_handler),
795
"quantity", generic_gnc_numeric_parser_new(),
796
"value", generic_gnc_numeric_parser_new(),
797
"slots", kvp_frame_parser_new(),
806
/***************************************************************************/
809
gnc_transaction_parser_new(void)
815
sixtp_set_any(sixtp_new(), FALSE,
816
SIXTP_START_HANDLER_ID, transaction_start_handler,
817
SIXTP_CHARACTERS_HANDLER_ID,
818
allow_and_ignore_only_whitespace,
819
SIXTP_AFTER_CHILD_HANDLER_ID,
820
txn_restore_after_child_handler,
821
SIXTP_NO_MORE_HANDLERS)))
828
sixtp_set_any(sixtp_new(), FALSE,
829
SIXTP_START_HANDLER_ID, txn_restore_start_handler,
830
SIXTP_END_HANDLER_ID, txn_restore_end_handler,
831
SIXTP_FAIL_HANDLER_ID, txn_restore_fail_handler,
832
SIXTP_AFTER_CHILD_HANDLER_ID,
833
txn_restore_after_child_handler,
834
SIXTP_NO_MORE_HANDLERS)))
836
sixtp_destroy(top_level);
839
sixtp_add_sub_parser(top_level, "restore", restore_pr);
841
if(!(sixtp_add_some_sub_parsers(
843
"guid", restore_char_generator(txn_restore_guid_end_handler),
844
"num", restore_char_generator(txn_restore_num_end_handler),
846
restore_char_generator(txn_restore_description_end_handler),
848
generic_timespec_parser_new(txn_rest_date_posted_end_handler),
850
generic_timespec_parser_new(txn_rest_date_entered_end_handler),
851
"slots", kvp_frame_parser_new(),
852
"split", gnc_txn_restore_split_parser_new(),
855
sixtp_destroy(top_level);