GnuCash  5.6-150-g038405b370+
io-example-account.cpp
1 /********************************************************************\
2  * io-example-account.c -- implementation for example accounts *
3  * *
4  * Copyright (C) 2001 James LewisMoss <dres@debian.org> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA gnu@gnu.org *
22  * *
23 \********************************************************************/
24 #include <glib.h>
25 #include <glib/gi18n.h>
26 #include <glib/gstdio.h>
27 
28 #include <config.h>
29 
30 #include <platform.h>
31 #if PLATFORM(WINDOWS)
32 #include <windows.h>
33 #endif
34 
35 #include <sys/types.h>
36 #include <ctype.h>
37 #ifdef HAVE_DIRENT_H
38 # include <dirent.h>
39 #endif
40 #include <string.h>
41 #include <sys/stat.h>
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 
46 #include "gnc-engine.h"
47 #include "Scrub.h"
48 #include "TransLog.h"
49 #include "platform.h"
50 #if COMPILER(MSVC)
51 # define g_fopen fopen
52 #endif
53 
54 #include "sixtp.h"
55 
56 #include "gnc-xml.h"
57 #include "io-example-account.h"
58 #include "io-gncxml-gen.h"
59 #include "io-utils.h"
60 #include "sixtp-dom-generators.h"
61 #include "sixtp-dom-parsers.h"
62 #include "sixtp-parsers.h"
63 
64 
65 static QofLogModule log_module = GNC_MOD_IO;
66 
67 #define GNC_ACCOUNT_STRING "gnc-account-example"
68 #define GNC_ACCOUNT_SHORT "gnc-act:short-description"
69 #define GNC_ACCOUNT_LONG "gnc-act:long-description"
70 #define GNC_ACCOUNT_TITLE "gnc-act:title"
71 #define GNC_ACCOUNT_EXCLUDEP "gnc-act:exclude-from-select-all"
72 #define GNC_ACCOUNT_SELECTED "gnc-act:start-selected"
73 
74 void
75 gnc_destroy_example_account (GncExampleAccount* gea)
76 {
77  if (gea->title != NULL)
78  {
79  g_free (gea->title);
80  gea->title = NULL;
81  }
82  if (gea->filename != NULL)
83  {
84  g_free (gea->filename);
85  gea->filename = NULL;
86  }
87  if (gea->root != NULL)
88  {
89  xaccAccountBeginEdit (gea->root);
90  xaccAccountDestroy (gea->root);
91  gea->root = NULL;
92  }
93  if (gea->short_description != NULL)
94  {
95  g_free (gea->short_description);
96  gea->short_description = NULL;
97  }
98  if (gea->long_description != NULL)
99  {
100  g_free (gea->long_description);
101  gea->long_description = NULL;
102  }
103  if (gea->book != NULL)
104  {
105  qof_book_destroy (gea->book);
106  gea->book = NULL;
107  }
108  g_free (gea);
109 }
110 
111 static void
112 clear_up_account_commodity (
113  gnc_commodity_table* tbl, Account* act,
114  gnc_commodity * (*getter) (const Account* account),
115  void (*setter) (Account* account, gnc_commodity* comm))
116 {
117  gnc_commodity* gcom;
118  gnc_commodity* com = getter (act);
119 
120  if (!com)
121  {
122  return;
123  }
124 
125  g_return_if_fail (tbl != NULL);
126 
127  gcom = gnc_commodity_table_lookup (tbl,
130 
131  if (gcom == com)
132  {
133  return;
134  }
135  else if (!gcom)
136  {
137  PWARN ("unable to find global commodity for %s adding new",
139  gnc_commodity_table_insert (tbl, com);
140  }
141  else
142  {
143  setter (act, gcom);
144  gnc_commodity_destroy (com);
145  }
146 }
147 
148 static void
149 add_account_local (GncExampleAccount* gea, Account* act)
150 {
151  gnc_commodity_table* table;
152 
153  table = gnc_commodity_table_get_table (gea->book);
154 
155  clear_up_account_commodity (table, act,
158 
160 
161  if (xaccAccountGetType (act) == ACCT_TYPE_ROOT)
162  {
163  gea->root = act;
164  }
165  else if (!gnc_account_get_parent (act))
166  {
167  if (!gea->root)
168  {
169  g_warning ("The example account file should declared a ROOT "
170  "account before declaring any other accounts.");
171  gea->root = gnc_book_get_root_account (gea->book);
172  }
173  gnc_account_append_child (gea->root, act);
174  }
175 }
176 
177 static gboolean
178 generic_callback (const char* tag, gpointer globaldata, gpointer data)
179 {
180  GncExampleAccount* gea = (GncExampleAccount*)globaldata;
181 
182  if (g_strcmp0 (tag, "gnc:account") == 0)
183  {
184  add_account_local (gea, (Account*)data);
185  }
186  return TRUE;
187 }
188 
189 static char*
190 squash_extra_whitespace (char* text)
191 {
192  int spot;
193  int length = strlen (text);
194 
195  for (spot = 1; spot < length; spot++)
196  {
197  if (isspace (text[spot]) && isspace (text[spot - 1]))
198  {
199  memmove (text + spot, text + spot + 1, length - spot + 1);
200  length--;
201  }
202  else
203  {
204  spot++;
205  }
206  }
207  return text;
208 }
209 
210 static char*
211 grab_clean_string (xmlNodePtr tree)
212 {
213  return squash_extra_whitespace (g_strstrip (dom_tree_to_text (tree)));
214 }
215 
216 static gboolean
217 gnc_short_descrip_end_handler (gpointer data_for_children,
218  GSList* data_from_children, GSList* sibling_data,
219  gpointer parent_data, gpointer global_data,
220  gpointer* result, const gchar* tag)
221 {
222  GncExampleAccount* gea =
223  (GncExampleAccount*) ((gxpf_data*)global_data)->parsedata;
224 
225  gea->short_description = grab_clean_string ((xmlNodePtr)data_for_children);
226 
227  return TRUE;
228 }
229 
230 static sixtp*
231 gnc_short_descrip_sixtp_parser_create (void)
232 {
233  return sixtp_dom_parser_new (gnc_short_descrip_end_handler, NULL, NULL);
234 }
235 
236 static gboolean
237 gnc_long_descrip_end_handler (gpointer data_for_children,
238  GSList* data_from_children, GSList* sibling_data,
239  gpointer parent_data, gpointer global_data,
240  gpointer* result, const gchar* tag)
241 {
242  GncExampleAccount* gea =
243  (GncExampleAccount*) ((gxpf_data*)global_data)->parsedata;
244 
245  gea->long_description = grab_clean_string ((xmlNodePtr)data_for_children);
246 
247  return TRUE;
248 }
249 
250 static sixtp*
251 gnc_long_descrip_sixtp_parser_create (void)
252 {
253  return sixtp_dom_parser_new (gnc_long_descrip_end_handler, NULL, NULL);
254 }
255 
256 static gboolean
257 gnc_excludep_end_handler (gpointer data_for_children,
258  GSList* data_from_children, GSList* sibling_data,
259  gpointer parent_data, gpointer global_data,
260  gpointer* result, const gchar* tag)
261 {
262  GncExampleAccount* gea =
263  (GncExampleAccount*) ((gxpf_data*)global_data)->parsedata;
264  gint64 val = 0;
265 
266  dom_tree_to_integer ((xmlNodePtr)data_for_children, &val);
267  gea->exclude_from_select_all = (val ? TRUE : FALSE);
268 
269  return TRUE;
270 }
271 
272 static sixtp*
273 gnc_excludep_sixtp_parser_create (void)
274 {
275  return sixtp_dom_parser_new (gnc_excludep_end_handler, NULL, NULL);
276 }
277 
278 static gboolean
279 gnc_selected_end_handler (gpointer data_for_children,
280  GSList* data_from_children, GSList* sibling_data,
281  gpointer parent_data, gpointer global_data,
282  gpointer* result, const gchar* tag)
283 {
284  GncExampleAccount* gea =
285  (GncExampleAccount*) ((gxpf_data*)global_data)->parsedata;
286  gint64 val = 0;
287 
288  dom_tree_to_integer ((xmlNodePtr)data_for_children, &val);
289  gea->start_selected = (val ? TRUE : FALSE);
290 
291  return TRUE;
292 }
293 
294 static sixtp*
295 gnc_selected_sixtp_parser_create (void)
296 {
297  return sixtp_dom_parser_new (gnc_selected_end_handler, NULL, NULL);
298 }
299 
300 static gboolean
301 gnc_title_end_handler (gpointer data_for_children,
302  GSList* data_from_children, GSList* sibling_data,
303  gpointer parent_data, gpointer global_data,
304  gpointer* result, const gchar* tag)
305 {
306  GncExampleAccount* gea =
307  (GncExampleAccount*) ((gxpf_data*)global_data)->parsedata;
308 
309  gea->title = grab_clean_string ((xmlNodePtr)data_for_children);
310 
311  return TRUE;
312 }
313 
314 static sixtp*
315 gnc_titse_sixtp_parser_create (void)
316 {
317  return sixtp_dom_parser_new (gnc_title_end_handler, NULL, NULL);
318 }
319 
320 
321 GncExampleAccount*
322 gnc_read_example_account (const gchar* filename)
323 {
324  GncExampleAccount* gea;
325  sixtp* top_parser;
326  sixtp* main_parser;
327 
328  g_return_val_if_fail (filename != NULL, NULL);
329 
330  gea = g_new0 (GncExampleAccount, 1);
331 
332  gea->book = qof_book_new ();
333  gea->filename = g_strdup (filename);
334 
335  top_parser = sixtp_new ();
336  main_parser = sixtp_new ();
337 
338  if (!sixtp_add_some_sub_parsers (
339  top_parser, TRUE,
340  GNC_ACCOUNT_STRING, main_parser,
341  NULL, NULL))
342  {
343  gnc_destroy_example_account (gea);
344  return FALSE;
345  }
346 
347  if (!sixtp_add_some_sub_parsers (
348  main_parser, TRUE,
349  GNC_ACCOUNT_TITLE, gnc_titse_sixtp_parser_create (),
350  GNC_ACCOUNT_SHORT, gnc_short_descrip_sixtp_parser_create (),
351  GNC_ACCOUNT_LONG, gnc_long_descrip_sixtp_parser_create (),
352  GNC_ACCOUNT_EXCLUDEP, gnc_excludep_sixtp_parser_create (),
353  GNC_ACCOUNT_SELECTED, gnc_selected_sixtp_parser_create (),
354  "gnc:account", gnc_account_sixtp_parser_create (),
355  NULL, NULL))
356  {
357  gnc_destroy_example_account (gea);
358  return FALSE;
359  }
360 
361  if (!gnc_xml_parse_file (top_parser, filename,
362  generic_callback, gea, gea->book))
363  {
364  sixtp_destroy (top_parser);
365  xaccLogEnable ();
366  gnc_destroy_example_account (gea);
367  return FALSE;
368  }
369 
370  return gea;
371 }
372 
373 static void
374 write_string_part (FILE* out, const char* tag, const char* data)
375 {
376  xmlNodePtr node;
377 
378  node = text_to_dom_tree (tag, data);
379 
380  xmlElemDump (out, NULL, node);
381  fprintf (out, "\n");
382 
383  xmlFreeNode (node);
384 }
385 
386 static void
387 write_bool_part (FILE* out, const char* tag, gboolean data)
388 {
389  xmlNodePtr node;
390 
391  node = int_to_dom_tree (tag, data);
392 
393  xmlElemDump (out, NULL, node);
394  fprintf (out, "\n");
395 
396  xmlFreeNode (node);
397 }
398 
399 gboolean
400 gnc_write_example_account (GncExampleAccount* gea, const gchar* filename)
401 {
402  FILE* out;
403  sixtp_gdv2 data = { 0 };
404 
405  out = g_fopen (filename, "w");
406  if (out == NULL)
407  {
408  return FALSE;
409  }
410 
411  fprintf (out, "<?xml version=\"1.0\"?>\n");
412  fprintf (out, "<" GNC_ACCOUNT_STRING ">\n");
413 
414  write_string_part (out, GNC_ACCOUNT_TITLE, gea->title);
415 
416  write_string_part (out, GNC_ACCOUNT_SHORT, gea->short_description);
417 
418  write_string_part (out, GNC_ACCOUNT_LONG, gea->long_description);
419 
420  write_bool_part (out, GNC_ACCOUNT_EXCLUDEP, gea->exclude_from_select_all);
421 
422  write_account_tree (out, gea->root, &data);
423 
424  fprintf (out, "</" GNC_ACCOUNT_STRING ">\n\n");
425 
426  fclose (out);
427 
428  return TRUE;
429 
430 }
431 
432 /***********************************************************************/
433 
434 static void
435 slist_destroy_example_account (gpointer data, gpointer user_data)
436 {
437  if (data != NULL)
438  {
439  gnc_destroy_example_account ((GncExampleAccount*)data);
440  }
441  else
442  {
443  PWARN ("GncExampleAccount pointer in slist was NULL");
444  }
445 }
446 
447 void
448 gnc_free_example_account_list (GSList* list)
449 {
450  g_slist_foreach (list, slist_destroy_example_account, NULL);
451  g_slist_free (list);
452 }
453 
454 GSList*
455 gnc_load_example_account_list (const char* dirname)
456 {
457  GSList* ret;
458  GDir* dir;
459  const gchar* direntry;
460 
461  dir = g_dir_open (dirname, 0, NULL);
462 
463  if (dir == NULL)
464  {
465  return NULL;
466  }
467 
468  ret = NULL;
469 
470  for (direntry = g_dir_read_name (dir); direntry != NULL;
471  direntry = g_dir_read_name (dir))
472  {
473  gchar* filename;
474  GncExampleAccount* gea;
475  if (!g_str_has_suffix (direntry, "xea"))
476  continue;
477 
478  filename = g_build_filename (dirname, direntry, (gchar*) NULL);
479 
480  if (!g_file_test (filename, G_FILE_TEST_IS_DIR))
481  {
482  gea = gnc_read_example_account (filename);
483 
484  if (gea == NULL)
485  {
486  g_free (filename);
487  gnc_free_example_account_list (ret);
488  g_dir_close (dir);
489  return NULL;
490  }
491 
492  ret = g_slist_append (ret, gea);
493  }
494 
495  g_free (filename);
496  }
497  g_dir_close (dir);
498 
499  return ret;
500 }
501 
502 
503 
504 /***********************************************************************/
505 /*
506 gboolean
507 gnc_is_example_account_xml(const gchar *name)
508 {
509  return gnc_is_our_xml_file(name, GNC_ACCOUNT_STRING, NULL);
510 } */
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
Add a new commodity to the commodity table.
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
Definition: Account.cpp:2906
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
Definition: sixtp.h:129
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:2807
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3237
void xaccAccountScrubCommodity(Account *account)
The xaccAccountScrubCommodity method fixed accounts without a commodity by using the old account curr...
Definition: Scrub.cpp:1222
STRUCTS.
QofBook * qof_book_new(void)
Allocate, initialise and return a new QofBook.
Definition: qofbook.cpp:290
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
Retrieve the namespace for the specified commodity.
void xaccAccountDestroy(Account *acc)
The xaccAccountDestroy() routine can be used to get rid of an account.
Definition: Account.cpp:1592
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
convert single-entry accounts to clean double-entry
All type declarations for the whole Gnucash engine.
API for the transaction logger.
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1477
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3371
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
Retrieve the &#39;unique&#39; name for the specified commodity.
The hidden root account of an account tree.
Definition: Account.h:153
void gnc_commodity_destroy(gnc_commodity *cm)
Destroy a commodity.
void xaccLogEnable(void)
document me
Definition: TransLog.cpp:99
void qof_book_destroy(QofBook *book)
End any editing sessions associated with book, and free all memory associated with it...
Definition: qofbook.cpp:331
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account&#39;s commodity.
Definition: Account.cpp:2649