GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-account-xml-v2.c
1 /********************************************************************\
2  * gnc-account-xml-v2.c -- account xml i/o implementation *
3  * *
4  * Copyright (C) 2001 James LewisMoss <[email protected]> *
5  * Copyright (C) 2002 Linas Vepstas <[email protected]> *
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 [email protected] *
23  * *
24 \********************************************************************/
25 
26 #include "config.h"
27 
28 #include <glib.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "gnc-xml-helper.h"
33 #include "sixtp.h"
34 #include "sixtp-utils.h"
35 #include "sixtp-parsers.h"
36 #include "sixtp-utils.h"
37 #include "sixtp-dom-parsers.h"
38 #include "sixtp-dom-generators.h"
39 
40 #include "gnc-xml.h"
41 #include "io-gncxml-gen.h"
42 #include "io-gncxml-v2.h"
43 
44 #include "sixtp-dom-parsers.h"
45 #include "AccountP.h"
46 #include "Account.h"
47 
48 static QofLogModule log_module = GNC_MOD_IO;
49 
50 const gchar *account_version_string = "2.0.0";
51 
52 /* ids */
53 #define gnc_account_string "gnc:account"
54 #define act_name_string "act:name"
55 #define act_id_string "act:id"
56 #define act_type_string "act:type"
57 #define act_commodity_string "act:commodity"
58 #define act_commodity_scu_string "act:commodity-scu"
59 #define act_non_standard_scu_string "act:non-standard-scu"
60 #define act_code_string "act:code"
61 #define act_description_string "act:description"
62 #define act_slots_string "act:slots"
63 #define act_parent_string "act:parent"
64 #define act_lots_string "act:lots"
65 /* The currency and security strings should not appear in newer
66  * xml files (anything post-gnucash-1.6) */
67 #define act_currency_string "act:currency"
68 #define act_currency_scu_string "act:currency-scu"
69 #define act_security_string "act:security"
70 #define act_security_scu_string "act:security-scu"
71 #define act_hidden_string "act:hidden"
72 #define act_placeholder_string "act:placeholder"
73 
74 /* EFFECTIVE FRIEND FUNCTION */
75 extern KvpFrame *qof_instance_get_slots (const QofInstance *);
76 
77 xmlNodePtr
78 gnc_account_dom_tree_create(Account *act,
79  gboolean exporting,
80  gboolean allow_incompat)
81 {
82  const char *str;
83  KvpFrame *kf;
84  xmlNodePtr ret;
85  GList *lots, *n;
86  Account *parent;
87  gnc_commodity *acct_commodity;
88 
89  ENTER ("(account=%p)", act);
90 
91  ret = xmlNewNode(NULL, BAD_CAST gnc_account_string);
92  xmlSetProp(ret, BAD_CAST "version", BAD_CAST account_version_string);
93 
94  xmlAddChild(ret, text_to_dom_tree(act_name_string,
95  xaccAccountGetName(act)));
96 
97  xmlAddChild(ret, guid_to_dom_tree(act_id_string, xaccAccountGetGUID(act)));
98 
99  xmlAddChild(ret, text_to_dom_tree(
100  act_type_string,
102 
103  /* Don't write new XML tags in version 2.3.x and 2.4.x because it
104  would mean 2.2.x cannot read those files again. But we can
105  enable writing these tags in 2.5.x or late in 2.4.x. */
106  /*
107  xmlAddChild(ret, boolean_to_dom_tree(
108  act_hidden_string,
109  xaccAccountGetHidden(act)));
110  xmlAddChild(ret, boolean_to_dom_tree(
111  act_placeholder_string,
112  xaccAccountGetPlaceholder(act)));
113  */
114 
115  acct_commodity = xaccAccountGetCommodity(act);
116  if (acct_commodity != NULL)
117  {
118  xmlAddChild(ret, commodity_ref_to_dom_tree(act_commodity_string,
119  acct_commodity));
120 
121  xmlAddChild(ret, int_to_dom_tree(act_commodity_scu_string,
123 
124  if (xaccAccountGetNonStdSCU(act))
125  xmlNewChild(ret, NULL, BAD_CAST act_non_standard_scu_string, NULL);
126  }
127 
128  str = xaccAccountGetCode(act);
129  if (str && strlen(str) > 0)
130  {
131  xmlAddChild(ret, text_to_dom_tree(act_code_string, str));
132  }
133 
134  str = xaccAccountGetDescription(act);
135  if (str && strlen(str) > 0)
136  {
137  xmlAddChild(ret, text_to_dom_tree(act_description_string, str));
138  }
139 
140  kf = qof_instance_get_slots (QOF_INSTANCE (act));
141  if (kf)
142  {
143  xmlNodePtr kvpnode = kvp_frame_to_dom_tree(act_slots_string, kf);
144  if (kvpnode)
145  {
146  xmlAddChild(ret, kvpnode);
147  }
148  }
149 
150  parent = gnc_account_get_parent(act);
151  if (parent)
152  {
153  if (!gnc_account_is_root(parent) || allow_incompat)
154  xmlAddChild(ret, guid_to_dom_tree(act_parent_string,
155  xaccAccountGetGUID(parent)));
156  }
157 
158  lots = xaccAccountGetLotList (act);
159  PINFO ("lot list=%p", lots);
160  if (lots && !exporting)
161  {
162  xmlNodePtr toaddto = xmlNewChild(ret, NULL, BAD_CAST act_lots_string, NULL);
163 
164  lots = g_list_sort(lots, qof_instance_guid_compare);
165 
166  for (n = lots; n; n = n->next)
167  {
168  GNCLot * lot = n->data;
169  xmlAddChild(toaddto, gnc_lot_dom_tree_create(lot));
170  }
171  }
172  g_list_free(lots);
173 
174  LEAVE("");
175  return ret;
176 }
177 
178 /***********************************************************************/
179 
181 {
182  Account *account;
183  QofBook *book;
184 };
185 
186 static inline gboolean
187 set_string(xmlNodePtr node, Account* act,
188  void (*func)(Account *act, const gchar *txt))
189 {
190  gchar* txt = dom_tree_to_text(node);
191  g_return_val_if_fail(txt, FALSE);
192 
193  func(act, txt);
194 
195  g_free(txt);
196 
197  return TRUE;
198 }
199 
200 static gboolean
201 account_name_handler (xmlNodePtr node, gpointer act_pdata)
202 {
203  struct account_pdata *pdata = act_pdata;
204 
205  return set_string(node, pdata->account, xaccAccountSetName);
206 }
207 
208 static gboolean
209 account_id_handler (xmlNodePtr node, gpointer act_pdata)
210 {
211  struct account_pdata *pdata = act_pdata;
212  GncGUID *guid;
213 
214  guid = dom_tree_to_guid(node);
215  g_return_val_if_fail(guid, FALSE);
216 
217  xaccAccountSetGUID(pdata->account, guid);
218 
219  g_free(guid);
220 
221  return TRUE;
222 }
223 
224 static gboolean
225 account_type_handler (xmlNodePtr node, gpointer act_pdata)
226 {
227  struct account_pdata *pdata = act_pdata;
229  char *string;
230 
231  string = (char*) xmlNodeGetContent (node->xmlChildrenNode);
232  xaccAccountStringToType(string, &type);
233  xmlFree (string);
234 
235  xaccAccountSetType(pdata->account, type);
236 
237  return TRUE;
238 }
239 
240 static gboolean
241 account_commodity_handler (xmlNodePtr node, gpointer act_pdata)
242 {
243  struct account_pdata *pdata = act_pdata;
244  gnc_commodity *ref;
245 
246 // ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
247  ref = dom_tree_to_commodity_ref(node, pdata->book);
248  xaccAccountSetCommodity(pdata->account, ref);
249 
250  return TRUE;
251 }
252 
253 static gboolean
254 account_commodity_scu_handler (xmlNodePtr node, gpointer act_pdata)
255 {
256  struct account_pdata *pdata = act_pdata;
257  gint64 val;
258 
259  dom_tree_to_integer(node, &val);
260  xaccAccountSetCommoditySCU(pdata->account, val);
261 
262  return TRUE;
263 }
264 
265 static gboolean
266 account_hidden_handler (xmlNodePtr node, gpointer act_pdata)
267 {
268  struct account_pdata *pdata = act_pdata;
269  gboolean val;
270 
271  dom_tree_to_boolean(node, &val);
272  xaccAccountSetHidden(pdata->account, val);
273 
274  return TRUE;
275 }
276 
277 static gboolean
278 account_placeholder_handler (xmlNodePtr node, gpointer act_pdata)
279 {
280  struct account_pdata *pdata = act_pdata;
281  gboolean val;
282 
283  dom_tree_to_boolean(node, &val);
284  xaccAccountSetPlaceholder(pdata->account, val);
285 
286  return TRUE;
287 }
288 
289 static gboolean
290 account_non_standard_scu_handler (xmlNodePtr node, gpointer act_pdata)
291 {
292  struct account_pdata *pdata = act_pdata;
293 
294  xaccAccountSetNonStdSCU(pdata->account, TRUE);
295 
296  return TRUE;
297 }
298 
299 /* ============================================================== */
300 /* The following deprecated routines are here only to service
301  * older XML files. */
302 
303 static gboolean
304 deprecated_account_currency_handler (xmlNodePtr node, gpointer act_pdata)
305 {
306  struct account_pdata *pdata = act_pdata;
307  gnc_commodity *ref;
308 
309  PWARN("Account %s: Obsolete xml tag 'act:currency' will not be preserved.",
310  xaccAccountGetName( pdata->account ));
311  ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
312  DxaccAccountSetCurrency(pdata->account, ref);
313 
314  return TRUE;
315 }
316 
317 static gboolean
318 deprecated_account_currency_scu_handler (xmlNodePtr node, gpointer act_pdata)
319 {
320  struct account_pdata *pdata = act_pdata;
321  PWARN("Account %s: Obsolete xml tag 'act:currency-scu' will not be preserved.",
322  xaccAccountGetName( pdata->account ));
323  return TRUE;
324 }
325 
326 static gboolean
327 deprecated_account_security_handler (xmlNodePtr node, gpointer act_pdata)
328 {
329  struct account_pdata *pdata = act_pdata;
330  gnc_commodity *ref, *orig = xaccAccountGetCommodity(pdata->account);
331 
332  PWARN("Account %s: Obsolete xml tag 'act:security' will not be preserved.",
333  xaccAccountGetName( pdata->account ));
334  /* If the account has both a commodity and a security elemet, and
335  the commodity is a currecny, then the commodity is probably
336  wrong. In that case we want to replace it with the
337  security. jralls 2010-11-02 */
338  if (!orig || gnc_commodity_is_currency( orig ) )
339  {
340  ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
341  xaccAccountSetCommodity(pdata->account, ref);
342  /* If the SCU was set, it was probably wrong, so zero it out
343  so that the SCU handler can fix it if there's a
344  security-scu element. jralls 2010-11-02 */
345  xaccAccountSetCommoditySCU(pdata->account, 0);
346  }
347 
348  return TRUE;
349 }
350 
351 static gboolean
352 deprecated_account_security_scu_handler (xmlNodePtr node, gpointer act_pdata)
353 {
354  struct account_pdata *pdata = act_pdata;
355  gint64 val;
356 
357  PWARN("Account %s: Obsolete xml tag 'act:security-scu' will not be preserved.",
358  xaccAccountGetName( pdata->account ));
359  if (!xaccAccountGetCommoditySCU(pdata->account))
360  {
361  dom_tree_to_integer(node, &val);
362  xaccAccountSetCommoditySCU(pdata->account, val);
363  }
364 
365  return TRUE;
366 }
367 
368 /* ============================================================== */
369 
370 static gboolean
371 account_slots_handler (xmlNodePtr node, gpointer act_pdata)
372 {
373  struct account_pdata *pdata = act_pdata;
374 
375  return dom_tree_to_kvp_frame_given
376  (node, qof_instance_get_slots (QOF_INSTANCE (pdata->account)));
377 }
378 
379 static gboolean
380 account_parent_handler (xmlNodePtr node, gpointer act_pdata)
381 {
382  struct account_pdata *pdata = act_pdata;
383  Account *parent;
384  GncGUID *gid;
385 
386  gid = dom_tree_to_guid(node);
387  g_return_val_if_fail(gid, FALSE);
388 
389  parent = xaccAccountLookup(gid, pdata->book);
390  if (!parent)
391  {
392  g_free (gid);
393  g_return_val_if_fail(parent, FALSE);
394  }
395 
396  gnc_account_append_child(parent, pdata->account);
397 
398  g_free (gid);
399 
400  return TRUE;
401 }
402 
403 static gboolean
404 account_code_handler(xmlNodePtr node, gpointer act_pdata)
405 {
406  struct account_pdata *pdata = act_pdata;
407 
408  return set_string(node, pdata->account, xaccAccountSetCode);
409 }
410 
411 static gboolean
412 account_description_handler(xmlNodePtr node, gpointer act_pdata)
413 {
414  struct account_pdata *pdata = act_pdata;
415 
416  return set_string(node, pdata->account, xaccAccountSetDescription);
417 }
418 
419 static gboolean
420 account_lots_handler(xmlNodePtr node, gpointer act_pdata)
421 {
422  struct account_pdata *pdata = act_pdata;
423  xmlNodePtr mark;
424 
425  g_return_val_if_fail(node, FALSE);
426  g_return_val_if_fail(node->xmlChildrenNode, FALSE);
427 
428  for (mark = node->xmlChildrenNode; mark; mark = mark->next)
429  {
430  GNCLot *lot;
431 
432  if (g_strcmp0("text", (char*) mark->name) == 0)
433  continue;
434 
435  lot = dom_tree_to_lot(mark, pdata->book);
436 
437  if (lot)
438  {
439  xaccAccountInsertLot (pdata->account, lot);
440  }
441  else
442  {
443  return FALSE;
444  }
445  }
446  return TRUE;
447 }
448 
449 static struct dom_tree_handler account_handlers_v2[] =
450 {
451  { act_name_string, account_name_handler, 1, 0 },
452  { act_id_string, account_id_handler, 1, 0 },
453  { act_type_string, account_type_handler, 1, 0 },
454  { act_commodity_string, account_commodity_handler, 0, 0 },
455  { act_commodity_scu_string, account_commodity_scu_handler, 0, 0 },
456  { act_non_standard_scu_string, account_non_standard_scu_handler, 0, 0 },
457  { act_code_string, account_code_handler, 0, 0 },
458  { act_description_string, account_description_handler, 0, 0},
459  { act_slots_string, account_slots_handler, 0, 0 },
460  { act_parent_string, account_parent_handler, 0, 0 },
461  { act_lots_string, account_lots_handler, 0, 0 },
462  { act_hidden_string, account_hidden_handler, 0, 0 },
463  { act_placeholder_string, account_placeholder_handler, 0, 0 },
464 
465  /* These should not appear in newer xml files; only in old
466  * (circa gnucash-1.6) xml files. We maintain them for backward
467  * compatibility. */
468  { act_currency_string, deprecated_account_currency_handler, 0, 0 },
469  { act_currency_scu_string, deprecated_account_currency_scu_handler, 0, 0 },
470  { act_security_string, deprecated_account_security_handler, 0, 0 },
471  { act_security_scu_string, deprecated_account_security_scu_handler, 0, 0 },
472  { NULL, 0, 0, 0 }
473 };
474 
475 static gboolean
476 gnc_account_end_handler(gpointer data_for_children,
477  GSList* data_from_children, GSList* sibling_data,
478  gpointer parent_data, gpointer global_data,
479  gpointer *result, const gchar *tag)
480 {
481  Account *acc, *parent, *root;
482  xmlNodePtr tree = (xmlNodePtr)data_for_children;
483  gxpf_data *gdata = (gxpf_data*)global_data;
484  QofBook *book = gdata->bookdata;
485  int type;
486 
487 
488  if (parent_data)
489  {
490  return TRUE;
491  }
492 
493  /* OK. For some messed up reason this is getting called again with a
494  NULL tag. So we ignore those cases */
495  if (!tag)
496  {
497  return TRUE;
498  }
499 
500  g_return_val_if_fail(tree, FALSE);
501 
502  acc = dom_tree_to_account(tree, book);
503  if (acc != NULL)
504  {
505  gdata->cb(tag, gdata->parsedata, acc);
506  /*
507  * Now return the account to the "edit" state. At the end of reading
508  * all the transactions, we will Commit. This replaces #splits
509  * rebalances with #accounts rebalances at the end. A BIG win!
510  */
512 
513  /* Backwards compatability. If there's no parent, see if this
514  * account is of type ROOT. If not, find or create a ROOT
515  * account and make that the parent. */
516  parent = gnc_account_get_parent(acc);
517  if (parent == NULL)
518  {
519  type = xaccAccountGetType(acc);
520  if (type != ACCT_TYPE_ROOT)
521  {
522  root = gnc_book_get_root_account(book);
523  if (root == NULL)
524  {
525  root = gnc_account_create_root(book);
526  }
527  gnc_account_append_child(root, acc);
528  }
529  }
530  }
531 
532  xmlFreeNode(tree);
533 
534  return acc != NULL;
535 }
536 
537 Account*
538 dom_tree_to_account (xmlNodePtr node, QofBook *book)
539 {
540  struct account_pdata act_pdata;
541  Account *accToRet;
542  gboolean successful;
543 
544  accToRet = xaccMallocAccount(book);
545  xaccAccountBeginEdit(accToRet);
546 
547  act_pdata.account = accToRet;
548  act_pdata.book = book;
549 
550  successful = dom_tree_generic_parse (node, account_handlers_v2,
551  &act_pdata);
552  if (successful)
553  {
554  xaccAccountCommitEdit (accToRet);
555  }
556  else
557  {
558  PERR ("failed to parse account tree");
559  xaccAccountDestroy (accToRet);
560  accToRet = NULL;
561  }
562 
563  return accToRet;
564 }
565 
566 sixtp*
567 gnc_account_sixtp_parser_create(void)
568 {
569  return sixtp_dom_parser_new(gnc_account_end_handler, NULL, NULL);
570 }
571 
572 /* ====================== END OF FILE ===================*/
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Definition: Account.c:2208
Account * gnc_account_get_parent(const Account *acc)
Definition: Account.c:2623
Definition: sixtp.h:93
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
void gnc_account_append_child(Account *new_parent, Account *child)
Definition: Account.c:2525
gboolean gnc_account_is_root(const Account *account)
Definition: Account.c:2647
gboolean xaccAccountGetNonStdSCU(const Account *acc)
Definition: Account.c:2487
int xaccAccountGetCommoditySCUi(const Account *acc)
Definition: Account.c:2451
#define PINFO(format, args...)
Definition: qoflog.h:249
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
int xaccAccountGetCommoditySCU(const Account *acc)
Definition: Account.c:2458
const char * xaccAccountGetCode(const Account *acc)
Definition: Account.c:3086
Account * gnc_account_create_root(QofBook *book)
Definition: Account.c:1097
void xaccAccountSetCode(Account *acc, const char *str)
Definition: Account.c:2249
const char * xaccAccountTypeEnumAsString(GNCAccountType type)
Definition: Account.c:4027
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
Definition: Account.c:1920
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
Definition: guid.h:65
void xaccAccountDestroy(Account *acc)
Definition: Account.c:1400
#define PWARN(format, args...)
Definition: qoflog.h:243
#define xaccAccountGetGUID(X)
Definition: Account.h:239
Account handling public routines.
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Definition: Account.c:3923
api for GnuCash version 2 XML-based file format
const char * xaccAccountGetDescription(const Account *acc)
Definition: Account.c:3093
LotList * xaccAccountGetLotList(const Account *acc)
Definition: Account.c:3744
gboolean xaccAccountStringToType(const char *str, GNCAccountType *type)
Definition: Account.c:4064
void xaccAccountSetCommoditySCU(Account *acc, int scu)
Definition: Account.c:2435
GNCAccountType
Definition: Account.h:96
void xaccAccountSetHidden(Account *acc, gboolean val)
Definition: Account.c:3970
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
gint qof_instance_guid_compare(const gconstpointer ptr1, const gconstpointer ptr2)
struct KvpFrameImpl KvpFrame
Definition: kvp_frame.h:76
#define LEAVE(format, args...)
Definition: qoflog.h:271
Account * xaccMallocAccount(QofBook *book)
Definition: Account.c:1083
void xaccAccountSetDescription(Account *acc, const char *str)
Definition: Account.c:2268
void DxaccAccountSetCurrency(Account *acc, gnc_commodity *currency)
Definition: Account.c:2498
void xaccAccountSetNonStdSCU(Account *acc, gboolean flag)
Definition: Account.c:2471
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void xaccAccountSetName(Account *acc, const char *str)
Definition: Account.c:2229
const gchar * QofLogModule
Definition: qofid.h:89
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
Definition: Account.c:1827