GnuCash  5.6-150-g038405b370+
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 
47 static QofLogModule log_module = GNC_MOD_IO;
48 
49 const 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 
73 xmlNodePtr
74 gnc_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 
174 static gboolean
175 account_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 
182 static gboolean
183 account_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 
195 static gboolean
196 account_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 
211 static gboolean
212 account_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 
224 static gboolean
225 account_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 
236 static gboolean
237 account_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 
248 static gboolean
249 account_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 
260 static gboolean
261 account_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 
274 static gboolean
275 deprecated_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 
288 static gboolean
289 deprecated_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 
297 static gboolean
298 deprecated_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 
322 static gboolean
323 deprecated_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 
341 static gboolean
342 account_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 
348 static gboolean
349 account_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 
368 static gboolean
369 account_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 
376 static gboolean
377 account_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 
384 static gboolean
385 account_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 
414 static 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 
440 static gboolean
441 gnc_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  */
476  xaccAccountBeginEdit (acc);
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 
502 Account*
503 dom_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 
531 sixtp*
532 gnc_account_sixtp_parser_create (void)
533 {
534  return sixtp_dom_parser_new (gnc_account_end_handler, NULL, NULL);
535 }
536 
537 /* ====================== END OF FILE ===================*/
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Set the account&#39;s type.
Definition: Account.cpp:2418
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
Definition: Account.cpp:2909
This is the private header for the account structure.
Definition: sixtp.h:129
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...
void gnc_account_append_child(Account *new_parent, Account *child)
This function will remove from the child account any pre-existing parent relationship, and will then add the account as a child of the new parent.
Definition: Account.cpp:2810
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:2927
gboolean xaccAccountGetNonStdSCU(const Account *acc)
Return boolean, indicating whether this account uses a non-standard SCU.
Definition: Account.cpp:2748
int xaccAccountGetCommoditySCUi(const Account *acc)
Return the &#39;internal&#39; SCU setting.
Definition: Account.cpp:2712
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3241
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2719
const char * xaccAccountGetCode(const Account *acc)
Get the account&#39;s accounting code.
Definition: Account.cpp:3310
STRUCTS.
Account * gnc_account_create_root(QofBook *book)
Create a new root level account.
Definition: Account.cpp:1283
void xaccAccountSetCode(Account *acc, const char *str)
Set the account&#39;s accounting code.
Definition: Account.cpp:2459
const char * xaccAccountTypeEnumAsString(GNCAccountType type)
Conversion routines for the account types to/from strings that are used in persistent storage...
Definition: Account.cpp:4206
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition: Account.cpp:2138
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void xaccAccountDestroy(Account *acc)
The xaccAccountDestroy() routine can be used to get rid of an account.
Definition: Account.cpp:1588
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
#define xaccAccountGetGUID(X)
Definition: Account.h:252
Account handling public routines.
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Set the "placeholder" flag for an account.
Definition: Account.cpp:4084
api for GnuCash version 2 XML-based file format
const char * xaccAccountGetDescription(const Account *acc)
Get the account&#39;s description.
Definition: Account.cpp:3317
LotList * xaccAccountGetLotList(const Account *acc)
The xaccAccountGetLotList() routine returns a list of all lots in this account.
Definition: Account.cpp:3934
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:4243
void xaccAccountSetCommoditySCU(Account *acc, int scu)
Set the SCU for the account.
Definition: Account.cpp:2696
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
Definition: Account.h:101
Not a type.
Definition: Account.h:104
void xaccAccountSetHidden(Account *acc, gboolean val)
Set the "hidden" flag for an account.
Definition: Account.cpp:4155
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1473
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3375
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition: Account.cpp:1269
void xaccAccountSetDescription(Account *acc, const char *str)
Set the account&#39;s description.
Definition: Account.cpp:2478
void DxaccAccountSetCurrency(Account *acc, gnc_commodity *currency)
Definition: Account.cpp:2759
void xaccAccountSetNonStdSCU(Account *acc, gboolean flag)
Set the flag indicating that this account uses a non-standard SCU.
Definition: Account.cpp:2732
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3263
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1514
void xaccAccountSetName(Account *acc, const char *str)
Set the account&#39;s name.
Definition: Account.cpp:2439
The hidden root account of an account tree.
Definition: Account.h:153
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account&#39;s commodity.
Definition: Account.cpp:2652
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2048