GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-account-xml-v2.cpp
1/********************************************************************\
2 * gnc-account-xml-v2.c -- account xml i/o implementation *
3 * *
4 * Copyright (C) 2001 James LewisMoss <dres@debian.org> *
5 * Copyright (C) 2002 Linas Vepstas <linas@linas.org> *
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License as *
9 * published by the Free Software Foundation; either version 2 of *
10 * the License, or (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License*
18 * along with this program; if not, contact: *
19 * *
20 * Free Software Foundation Voice: +1-617-542-5942 *
21 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22 * Boston, MA 02110-1301, USA gnu@gnu.org *
23 * *
24\********************************************************************/
25#include <glib.h>
26
27#include <config.h>
28#include <stdlib.h>
29#include <string.h>
30#include <AccountP.hpp>
31#include <Account.h>
32
33#include "gnc-xml-helper.h"
34#include "sixtp.h"
35#include "sixtp-utils.h"
36#include "sixtp-parsers.h"
37#include "sixtp-utils.h"
38#include "sixtp-dom-parsers.h"
39#include "sixtp-dom-generators.h"
40
41#include "gnc-xml.h"
42#include "io-gncxml-gen.h"
43#include "io-gncxml-v2.h"
44
45#include "sixtp-dom-parsers.h"
46
47static QofLogModule log_module = GNC_MOD_IO;
48
49const gchar* account_version_string = "2.0.0";
50
51/* ids */
52#define gnc_account_string "gnc:account"
53#define act_name_string "act:name"
54#define act_id_string "act:id"
55#define act_type_string "act:type"
56#define act_commodity_string "act:commodity"
57#define act_commodity_scu_string "act:commodity-scu"
58#define act_non_standard_scu_string "act:non-standard-scu"
59#define act_code_string "act:code"
60#define act_description_string "act:description"
61#define act_slots_string "act:slots"
62#define act_parent_string "act:parent"
63#define act_lots_string "act:lots"
64/* The currency and security strings should not appear in newer
65 * xml files (anything post-gnucash-1.6) */
66#define act_currency_string "act:currency"
67#define act_currency_scu_string "act:currency-scu"
68#define act_security_string "act:security"
69#define act_security_scu_string "act:security-scu"
70#define act_hidden_string "act:hidden"
71#define act_placeholder_string "act:placeholder"
72
73xmlNodePtr
74gnc_account_dom_tree_create (Account* act,
75 gboolean exporting,
76 gboolean allow_incompat)
77{
78 const char* str;
79 xmlNodePtr ret;
80 GList* lots, *n;
81 Account* parent;
82 gnc_commodity* acct_commodity;
83
84 ENTER ("(account=%p)", act);
85
86 ret = xmlNewNode (NULL, BAD_CAST gnc_account_string);
87 xmlSetProp (ret, BAD_CAST "version", BAD_CAST account_version_string);
88
89 xmlAddChild (ret, text_to_dom_tree (act_name_string,
90 xaccAccountGetName (act)));
91
92 xmlAddChild (ret, guid_to_dom_tree (act_id_string, xaccAccountGetGUID (act)));
93
94 xmlAddChild (ret, text_to_dom_tree (
95 act_type_string,
97
98 /* Don't write new XML tags in version 2.3.x and 2.4.x because it
99 would mean 2.2.x cannot read those files again. But we can
100 enable writing these tags in 2.5.x or late in 2.4.x. */
101 /*
102 xmlAddChild(ret, boolean_to_dom_tree(
103 act_hidden_string,
104 xaccAccountGetHidden(act)));
105 xmlAddChild(ret, boolean_to_dom_tree(
106 act_placeholder_string,
107 xaccAccountGetPlaceholder(act)));
108 */
109
110 acct_commodity = xaccAccountGetCommodity (act);
111 if (acct_commodity != NULL)
112 {
113 xmlAddChild (ret, commodity_ref_to_dom_tree (act_commodity_string,
114 acct_commodity));
115
116 xmlAddChild (ret, int_to_dom_tree (act_commodity_scu_string,
118
119 if (xaccAccountGetNonStdSCU (act))
120 xmlNewChild (ret, NULL, BAD_CAST act_non_standard_scu_string, NULL);
121 }
122
123 str = xaccAccountGetCode (act);
124 if (str && *str)
125 {
126 xmlAddChild (ret, text_to_dom_tree (act_code_string, str));
127 }
128
129 str = xaccAccountGetDescription (act);
130 if (str && *str)
131 {
132 xmlAddChild (ret, text_to_dom_tree (act_description_string, str));
133 }
134
135 /* xmlAddChild won't do anything with a NULL, so tests are superfluous. */
136 xmlAddChild (ret, qof_instance_slots_to_dom_tree (act_slots_string,
137 QOF_INSTANCE (act)));
138 parent = gnc_account_get_parent (act);
139 if (parent)
140 {
141 if (!gnc_account_is_root (parent) || allow_incompat)
142 xmlAddChild (ret, guid_to_dom_tree (act_parent_string,
143 xaccAccountGetGUID (parent)));
144 }
145
146 lots = xaccAccountGetLotList (act);
147 PINFO ("lot list=%p", lots);
148 if (lots && !exporting)
149 {
150 xmlNodePtr toaddto = xmlNewChild (ret, NULL, BAD_CAST act_lots_string, NULL);
151
152 lots = g_list_sort (lots, qof_instance_guid_compare);
153
154 for (n = lots; n; n = n->next)
155 {
156 GNCLot* lot = static_cast<decltype (lot)> (n->data);
157 xmlAddChild (toaddto, gnc_lot_dom_tree_create (lot));
158 }
159 }
160 g_list_free (lots);
161
162 LEAVE ("");
163 return ret;
164}
165
166/***********************************************************************/
167
169{
170 Account* account;
171 QofBook* book;
172};
173
174static gboolean
175account_name_handler (xmlNodePtr node, gpointer act_pdata)
176{
177 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
178
179 return apply_xmlnode_text (xaccAccountSetName, pdata->account, node);
180}
181
182static gboolean
183account_id_handler (xmlNodePtr node, gpointer act_pdata)
184{
185 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
186
187 auto guid = dom_tree_to_guid (node);
188 g_return_val_if_fail (guid, FALSE);
189
190 xaccAccountSetGUID (pdata->account, &*guid);
191
192 return TRUE;
193}
194
195static gboolean
196account_type_handler (xmlNodePtr node, gpointer act_pdata)
197{
198 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
200 char* string;
201
202 string = (char*) xmlNodeGetContent (node->xmlChildrenNode);
203 xaccAccountStringToType (string, &type);
204 xmlFree (string);
205
206 xaccAccountSetType (pdata->account, type);
207
208 return TRUE;
209}
210
211static gboolean
212account_commodity_handler (xmlNodePtr node, gpointer act_pdata)
213{
214 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
215 gnc_commodity* ref;
216
217// ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
218 ref = dom_tree_to_commodity_ref (node, pdata->book);
219 xaccAccountSetCommodity (pdata->account, ref);
220
221 return TRUE;
222}
223
224static gboolean
225account_commodity_scu_handler (xmlNodePtr node, gpointer act_pdata)
226{
227 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
228 gint64 val;
229
230 dom_tree_to_integer (node, &val);
231 xaccAccountSetCommoditySCU (pdata->account, val);
232
233 return TRUE;
234}
235
236static gboolean
237account_hidden_handler (xmlNodePtr node, gpointer act_pdata)
238{
239 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
240 gboolean val;
241
242 dom_tree_to_boolean (node, &val);
243 xaccAccountSetHidden (pdata->account, val);
244
245 return TRUE;
246}
247
248static gboolean
249account_placeholder_handler (xmlNodePtr node, gpointer act_pdata)
250{
251 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
252 gboolean val;
253
254 dom_tree_to_boolean (node, &val);
255 xaccAccountSetPlaceholder (pdata->account, val);
256
257 return TRUE;
258}
259
260static gboolean
261account_non_standard_scu_handler (xmlNodePtr node, gpointer act_pdata)
262{
263 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
264
265 xaccAccountSetNonStdSCU (pdata->account, TRUE);
266
267 return TRUE;
268}
269
270/* ============================================================== */
271/* The following deprecated routines are here only to service
272 * older XML files. */
273
274static gboolean
275deprecated_account_currency_handler (xmlNodePtr node, gpointer act_pdata)
276{
277 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
278 gnc_commodity* ref;
279
280 PWARN ("Account %s: Obsolete xml tag 'act:currency' will not be preserved.",
281 xaccAccountGetName (pdata->account));
282 ref = dom_tree_to_commodity_ref_no_engine (node, pdata->book);
283 DxaccAccountSetCurrency (pdata->account, ref);
284
285 return TRUE;
286}
287
288static gboolean
289deprecated_account_currency_scu_handler (xmlNodePtr node, gpointer act_pdata)
290{
291 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
292 PWARN ("Account %s: Obsolete xml tag 'act:currency-scu' will not be preserved.",
293 xaccAccountGetName (pdata->account));
294 return TRUE;
295}
296
297static gboolean
298deprecated_account_security_handler (xmlNodePtr node, gpointer act_pdata)
299{
300 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
301 gnc_commodity* ref, *orig = xaccAccountGetCommodity (pdata->account);
302
303 PWARN ("Account %s: Obsolete xml tag 'act:security' will not be preserved.",
304 xaccAccountGetName (pdata->account));
305 /* If the account has both a commodity and a security element, and
306 the commodity is a currency, then the commodity is probably
307 wrong. In that case we want to replace it with the
308 security. jralls 2010-11-02 */
309 if (!orig || gnc_commodity_is_currency (orig))
310 {
311 ref = dom_tree_to_commodity_ref_no_engine (node, pdata->book);
312 xaccAccountSetCommodity (pdata->account, ref);
313 /* If the SCU was set, it was probably wrong, so zero it out
314 so that the SCU handler can fix it if there's a
315 security-scu element. jralls 2010-11-02 */
316 xaccAccountSetCommoditySCU (pdata->account, 0);
317 }
318
319 return TRUE;
320}
321
322static gboolean
323deprecated_account_security_scu_handler (xmlNodePtr node, gpointer act_pdata)
324{
325 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
326 gint64 val;
327
328 PWARN ("Account %s: Obsolete xml tag 'act:security-scu' will not be preserved.",
329 xaccAccountGetName (pdata->account));
330 if (!xaccAccountGetCommoditySCU (pdata->account))
331 {
332 dom_tree_to_integer (node, &val);
333 xaccAccountSetCommoditySCU (pdata->account, val);
334 }
335
336 return TRUE;
337}
338
339/* ============================================================== */
340
341static gboolean
342account_slots_handler (xmlNodePtr node, gpointer act_pdata)
343{
344 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
345 return dom_tree_create_instance_slots (node, QOF_INSTANCE (pdata->account));
346}
347
348static gboolean
349account_parent_handler (xmlNodePtr node, gpointer act_pdata)
350{
351 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
352 Account* parent;
353
354 auto gid = dom_tree_to_guid (node);
355 g_return_val_if_fail (gid, FALSE);
356
357 parent = xaccAccountLookup (&*gid, pdata->book);
358 if (!parent)
359 {
360 g_return_val_if_fail (parent, FALSE);
361 }
362
363 gnc_account_append_child (parent, pdata->account);
364
365 return TRUE;
366}
367
368static gboolean
369account_code_handler (xmlNodePtr node, gpointer act_pdata)
370{
371 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
372
373 return apply_xmlnode_text (xaccAccountSetCode, pdata->account, node);
374}
375
376static gboolean
377account_description_handler (xmlNodePtr node, gpointer act_pdata)
378{
379 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
380
381 return apply_xmlnode_text (xaccAccountSetDescription, pdata->account, node);
382}
383
384static gboolean
385account_lots_handler (xmlNodePtr node, gpointer act_pdata)
386{
387 struct account_pdata* pdata = static_cast<decltype (pdata)> (act_pdata);
388 xmlNodePtr mark;
389
390 g_return_val_if_fail (node, FALSE);
391 g_return_val_if_fail (node->xmlChildrenNode, FALSE);
392
393 for (mark = node->xmlChildrenNode; mark; mark = mark->next)
394 {
395 GNCLot* lot;
396
397 if (g_strcmp0 ("text", (char*) mark->name) == 0)
398 continue;
399
400 lot = dom_tree_to_lot (mark, pdata->book);
401
402 if (lot)
403 {
404 xaccAccountInsertLot (pdata->account, lot);
405 }
406 else
407 {
408 return FALSE;
409 }
410 }
411 return TRUE;
412}
413
414static struct dom_tree_handler account_handlers_v2[] =
415{
416 { act_name_string, account_name_handler, 1, 0 },
417 { act_id_string, account_id_handler, 1, 0 },
418 { act_type_string, account_type_handler, 1, 0 },
419 { act_commodity_string, account_commodity_handler, 0, 0 },
420 { act_commodity_scu_string, account_commodity_scu_handler, 0, 0 },
421 { act_non_standard_scu_string, account_non_standard_scu_handler, 0, 0 },
422 { act_code_string, account_code_handler, 0, 0 },
423 { act_description_string, account_description_handler, 0, 0},
424 { act_slots_string, account_slots_handler, 0, 0 },
425 { act_parent_string, account_parent_handler, 0, 0 },
426 { act_lots_string, account_lots_handler, 0, 0 },
427 { act_hidden_string, account_hidden_handler, 0, 0 },
428 { act_placeholder_string, account_placeholder_handler, 0, 0 },
429
430 /* These should not appear in newer xml files; only in old
431 * (circa gnucash-1.6) xml files. We maintain them for backward
432 * compatibility. */
433 { act_currency_string, deprecated_account_currency_handler, 0, 0 },
434 { act_currency_scu_string, deprecated_account_currency_scu_handler, 0, 0 },
435 { act_security_string, deprecated_account_security_handler, 0, 0 },
436 { act_security_scu_string, deprecated_account_security_scu_handler, 0, 0 },
437 { NULL, 0, 0, 0 }
438};
439
440static gboolean
441gnc_account_end_handler (gpointer data_for_children,
442 GSList* data_from_children, GSList* sibling_data,
443 gpointer parent_data, gpointer global_data,
444 gpointer* result, const gchar* tag)
445{
446 Account* acc, *parent, *root;
447 xmlNodePtr tree = (xmlNodePtr)data_for_children;
448 gxpf_data* gdata = (gxpf_data*)global_data;
449 QofBook* book = static_cast<decltype (book)> (gdata->bookdata);
450 int type;
451
452
453 if (parent_data)
454 {
455 return TRUE;
456 }
457
458 /* OK. For some messed up reason this is getting called again with a
459 NULL tag. So we ignore those cases */
460 if (!tag)
461 {
462 return TRUE;
463 }
464
465 g_return_val_if_fail (tree, FALSE);
466
467 acc = dom_tree_to_account (tree, book);
468 if (acc != NULL)
469 {
470 gdata->cb (tag, gdata->parsedata, acc);
471 /*
472 * Now return the account to the "edit" state. At the end of reading
473 * all the transactions, we will Commit. This replaces #splits
474 * rebalances with #accounts rebalances at the end. A BIG win!
475 */
477
478 /* Backwards compatibility. If there's no parent, see if this
479 * account is of type ROOT. If not, find or create a ROOT
480 * account and make that the parent. */
481 parent = gnc_account_get_parent (acc);
482 if (parent == NULL)
483 {
484 type = xaccAccountGetType (acc);
485 if (type != ACCT_TYPE_ROOT)
486 {
487 root = gnc_book_get_root_account (book);
488 if (root == NULL)
489 {
490 root = gnc_account_create_root (book);
491 }
492 gnc_account_append_child (root, acc);
493 }
494 }
495 }
496
497 xmlFreeNode (tree);
498
499 return acc != NULL;
500}
501
502Account*
503dom_tree_to_account (xmlNodePtr node, QofBook* book)
504{
505 struct account_pdata act_pdata;
506 Account* accToRet;
507 gboolean successful;
508
509 accToRet = xaccMallocAccount (book);
510 xaccAccountBeginEdit (accToRet);
511
512 act_pdata.account = accToRet;
513 act_pdata.book = book;
514
515 successful = dom_tree_generic_parse (node, account_handlers_v2,
516 &act_pdata);
517 if (successful)
518 {
519 xaccAccountCommitEdit (accToRet);
520 }
521 else
522 {
523 PERR ("failed to parse account tree");
524 xaccAccountDestroy (accToRet);
525 accToRet = NULL;
526 }
527
528 return accToRet;
529}
530
531sixtp*
532gnc_account_sixtp_parser_create (void)
533{
534 return sixtp_dom_parser_new (gnc_account_end_handler, NULL, NULL);
535}
536
537/* ====================== END OF FILE ===================*/
This is the private header for the account structure.
Account handling public routines.
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition Account.cpp:3289
const char * xaccAccountGetDescription(const Account *acc)
Get the account's description.
Definition Account.cpp:3343
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
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition Account.cpp:3267
int xaccAccountGetCommoditySCUi(const Account *acc)
Return the 'internal' SCU setting.
Definition Account.cpp:2738
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition Account.cpp:2745
void xaccAccountSetName(Account *acc, const char *str)
Set the account's name.
Definition Account.cpp:2458
void xaccAccountSetCommoditySCU(Account *acc, int scu)
Set the SCU for the account.
Definition Account.cpp:2722
gboolean gnc_account_is_root(const Account *account)
This routine indicates whether the specified account is the root node of an account tree.
Definition Account.cpp:2953
void xaccAccountSetNonStdSCU(Account *acc, gboolean flag)
Set the flag indicating that this account uses a non-standard SCU.
Definition Account.cpp:2758
Account * gnc_account_create_root(QofBook *book)
Create a new root level account.
Definition Account.cpp:1284
#define xaccAccountGetGUID(X)
Definition Account.h:252
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 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
gboolean xaccAccountGetNonStdSCU(const Account *acc)
Return boolean, indicating whether this account uses a non-standard SCU.
Definition Account.cpp:2774
const char * xaccAccountGetCode(const Account *acc)
Get the account's accounting code.
Definition Account.cpp:3336
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
@ ACCT_TYPE_INVALID
Not a type.
Definition Account.h:104
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency or a legacy currency.
LotList * xaccAccountGetLotList(const Account *acc)
The xaccAccountGetLotList() routine returns a list of all lots in this account.
Definition Account.cpp:3975
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
const char * xaccAccountTypeEnumAsString(GNCAccountType type)
Conversion routines for the account types to/from strings that are used in persistent storage,...
Definition Account.cpp:4247
void DxaccAccountSetCurrency(Account *acc, gnc_commodity *currency)
Definition Account.cpp:2785
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition Account.cpp:2140
void xaccAccountSetHidden(Account *acc, gboolean val)
Set the "hidden" flag for an account.
Definition Account.cpp:4196
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Set the "placeholder" flag for an account.
Definition Account.cpp:4125
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
api for GnuCash version 2 XML-based file format
STRUCTS.
QofBook reference.
Definition qofbook-p.hpp:47
Definition sixtp.h:130