GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
io-example-account.c
1 /********************************************************************\
2  * io-example-account.c -- implementation for example accounts *
3  * *
4  * Copyright (C) 2001 James LewisMoss <[email protected]> *
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 [email protected] *
22  * *
23 \********************************************************************/
24 
25 #include "config.h"
26 
27 #include <sys/types.h>
28 #include <ctype.h>
29 #ifdef HAVE_DIRENT_H
30 # include <dirent.h>
31 #endif
32 #include <string.h>
33 #include <sys/stat.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 
38 #include <glib.h>
39 #include <glib/gi18n.h>
40 #include <glib/gstdio.h>
41 #include "sixtp.h"
42 
43 #include "gnc-engine.h"
44 #include "gnc-xml.h"
45 #include "io-example-account.h"
46 #include "io-gncxml-gen.h"
47 #include "io-utils.h"
48 #include "sixtp-dom-generators.h"
49 #include "sixtp-dom-parsers.h"
50 #include "sixtp-parsers.h"
51 
52 #include "Scrub.h"
53 #include "TransLog.h"
54 #include "platform.h"
55 #if COMPILER(MSVC)
56 # define g_fopen fopen
57 #endif
58 
59 static QofLogModule log_module = GNC_MOD_IO;
60 
61 #define GNC_ACCOUNT_STRING "gnc-account-example"
62 #define GNC_ACCOUNT_SHORT "gnc-act:short-description"
63 #define GNC_ACCOUNT_LONG "gnc-act:long-description"
64 #define GNC_ACCOUNT_TITLE "gnc-act:title"
65 #define GNC_ACCOUNT_EXCLUDEP "gnc-act:exclude-from-select-all"
66 #define GNC_ACCOUNT_SELECTED "gnc-act:start-selected"
67 
68 void
69 gnc_destroy_example_account(GncExampleAccount *gea)
70 {
71  if (gea->title != NULL)
72  {
73  g_free(gea->title);
74  gea->title = NULL;
75  }
76  if (gea->filename != NULL)
77  {
78  g_free(gea->filename);
79  gea->filename = NULL;
80  }
81  if (gea->root != NULL)
82  {
83  xaccAccountBeginEdit (gea->root);
84  xaccAccountDestroy(gea->root);
85  gea->root = NULL;
86  }
87  if (gea->short_description != NULL)
88  {
89  g_free(gea->short_description);
90  gea->short_description = NULL;
91  }
92  if (gea->long_description != NULL)
93  {
94  g_free(gea->long_description);
95  gea->long_description = NULL;
96  }
97  if (gea->book != NULL)
98  {
99  qof_book_destroy(gea->book);
100  gea->book = NULL;
101  }
102  g_free(gea);
103 }
104 
105 static void
106 clear_up_account_commodity(
107  gnc_commodity_table *tbl, Account *act,
108  gnc_commodity * (*getter) (const Account *account),
109  void (*setter) (Account *account, gnc_commodity *comm))
110 {
111  gnc_commodity *gcom;
112  gnc_commodity *com = getter(act);
113 
114  if (!com)
115  {
116  return;
117  }
118 
119  g_return_if_fail (tbl != NULL);
120 
121  gcom = gnc_commodity_table_lookup(tbl,
124 
125  if (gcom == com)
126  {
127  return;
128  }
129  else if (!gcom)
130  {
131  PWARN("unable to find global commodity for %s adding new",
133  gnc_commodity_table_insert(tbl, com);
134  }
135  else
136  {
137  setter(act, gcom);
139  }
140 }
141 
142 static void
143 add_account_local(GncExampleAccount *gea, Account *act)
144 {
146 
147  table = gnc_commodity_table_get_table (gea->book);
148 
149  clear_up_account_commodity(table, act,
152 
154 
156  {
157  gea->root = act;
158  }
159  else if (!gnc_account_get_parent(act))
160  {
161  if (!gea->root)
162  {
163  g_warning("The example account file should declared a ROOT "
164  "account before declaring any other accounts.");
165  gea->root = gnc_book_get_root_account(gea->book);
166  }
167  gnc_account_append_child(gea->root, act);
168  }
169 }
170 
171 static gboolean
172 generic_callback(const char *tag, gpointer globaldata, gpointer data)
173 {
174  GncExampleAccount *gea = (GncExampleAccount*)globaldata;
175 
176  if (g_strcmp0(tag, "gnc:account") == 0)
177  {
178  add_account_local(gea, (Account*)data);
179  }
180  return TRUE;
181 }
182 
183 static char*
184 squash_extra_whitespace(char *text)
185 {
186  int spot;
187  int length = strlen(text);
188 
189  for (spot = 1; spot < length; spot++)
190  {
191  if (isspace(text[spot]) && isspace(text[spot - 1]))
192  {
193  memmove(text + spot, text + spot + 1, length - spot + 1);
194  length--;
195  }
196  else
197  {
198  spot++;
199  }
200  }
201  return text;
202 }
203 
204 static char*
205 grab_clean_string(xmlNodePtr tree)
206 {
207  return squash_extra_whitespace(g_strstrip(dom_tree_to_text(tree)));
208 }
209 
210 static gboolean
211 gnc_short_descrip_end_handler(gpointer data_for_children,
212  GSList* data_from_children, GSList* sibling_data,
213  gpointer parent_data, gpointer global_data,
214  gpointer *result, const gchar *tag)
215 {
216  GncExampleAccount *gea =
217  (GncExampleAccount*)((gxpf_data*)global_data)->parsedata;
218 
219  gea->short_description = grab_clean_string((xmlNodePtr)data_for_children);
220 
221  return TRUE;
222 }
223 
224 static sixtp*
225 gnc_short_descrip_sixtp_parser_create(void)
226 {
227  return sixtp_dom_parser_new(gnc_short_descrip_end_handler, NULL, NULL);
228 }
229 
230 static gboolean
231 gnc_long_descrip_end_handler(gpointer data_for_children,
232  GSList* data_from_children, GSList* sibling_data,
233  gpointer parent_data, gpointer global_data,
234  gpointer *result, const gchar *tag)
235 {
236  GncExampleAccount *gea =
237  (GncExampleAccount*)((gxpf_data*)global_data)->parsedata;
238 
239  gea->long_description = grab_clean_string((xmlNodePtr)data_for_children);
240 
241  return TRUE;
242 }
243 
244 static sixtp*
245 gnc_long_descrip_sixtp_parser_create(void)
246 {
247  return sixtp_dom_parser_new(gnc_long_descrip_end_handler, NULL, NULL);
248 }
249 
250 static gboolean
251 gnc_excludep_end_handler(gpointer data_for_children,
252  GSList* data_from_children, GSList* sibling_data,
253  gpointer parent_data, gpointer global_data,
254  gpointer *result, const gchar *tag)
255 {
256  GncExampleAccount *gea =
257  (GncExampleAccount*)((gxpf_data*)global_data)->parsedata;
258  gint64 val = 0;
259 
260  dom_tree_to_integer ((xmlNodePtr)data_for_children, &val);
261  gea->exclude_from_select_all = (val ? TRUE : FALSE);
262 
263  return TRUE;
264 }
265 
266 static sixtp*
267 gnc_excludep_sixtp_parser_create(void)
268 {
269  return sixtp_dom_parser_new(gnc_excludep_end_handler, NULL, NULL);
270 }
271 
272 static gboolean
273 gnc_selected_end_handler(gpointer data_for_children,
274  GSList* data_from_children, GSList* sibling_data,
275  gpointer parent_data, gpointer global_data,
276  gpointer *result, const gchar *tag)
277 {
278  GncExampleAccount *gea =
279  (GncExampleAccount*)((gxpf_data*)global_data)->parsedata;
280  gint64 val = 0;
281 
282  dom_tree_to_integer ((xmlNodePtr)data_for_children, &val);
283  gea->start_selected = (val ? TRUE : FALSE);
284 
285  return TRUE;
286 }
287 
288 static sixtp*
289 gnc_selected_sixtp_parser_create(void)
290 {
291  return sixtp_dom_parser_new(gnc_selected_end_handler, NULL, NULL);
292 }
293 
294 static gboolean
295 gnc_title_end_handler(gpointer data_for_children,
296  GSList* data_from_children, GSList* sibling_data,
297  gpointer parent_data, gpointer global_data,
298  gpointer *result, const gchar *tag)
299 {
300  GncExampleAccount *gea =
301  (GncExampleAccount*)((gxpf_data*)global_data)->parsedata;
302 
303  gea->title = grab_clean_string((xmlNodePtr)data_for_children);
304 
305  return TRUE;
306 }
307 
308 static sixtp*
309 gnc_titse_sixtp_parser_create(void)
310 {
311  return sixtp_dom_parser_new(gnc_title_end_handler, NULL, NULL);
312 }
313 
314 
316 gnc_read_example_account(const gchar *filename)
317 {
318  GncExampleAccount *gea;
319  sixtp *top_parser;
320  sixtp *main_parser;
321 
322  g_return_val_if_fail (filename != NULL, NULL);
323 
324  gea = g_new0(GncExampleAccount, 1);
325 
326  gea->book = qof_book_new();
327  gea->filename = g_strdup(filename);
328 
329  top_parser = sixtp_new();
330  main_parser = sixtp_new();
331 
332  if (!sixtp_add_some_sub_parsers(
333  top_parser, TRUE,
334  GNC_ACCOUNT_STRING, main_parser,
335  NULL, NULL))
336  {
337  gnc_destroy_example_account(gea);
338  return FALSE;
339  }
340 
341  if (!sixtp_add_some_sub_parsers(
342  main_parser, TRUE,
343  GNC_ACCOUNT_TITLE, gnc_titse_sixtp_parser_create(),
344  GNC_ACCOUNT_SHORT, gnc_short_descrip_sixtp_parser_create(),
345  GNC_ACCOUNT_LONG, gnc_long_descrip_sixtp_parser_create(),
346  GNC_ACCOUNT_EXCLUDEP, gnc_excludep_sixtp_parser_create(),
347  GNC_ACCOUNT_SELECTED, gnc_selected_sixtp_parser_create(),
348  "gnc:account", gnc_account_sixtp_parser_create(),
349  NULL, NULL))
350  {
351  gnc_destroy_example_account(gea);
352  return FALSE;
353  }
354 
355  if (!gnc_xml_parse_file(top_parser, filename,
356  generic_callback, gea, gea->book))
357  {
358  sixtp_destroy(top_parser);
359  xaccLogEnable ();
360  gnc_destroy_example_account(gea);
361  return FALSE;
362  }
363 
364  return gea;
365 }
366 
367 static void
368 write_string_part(FILE *out, const char *tag, const char *data)
369 {
370  xmlNodePtr node;
371 
372  node = text_to_dom_tree(tag, data);
373 
374  xmlElemDump(out, NULL, node);
375  fprintf(out, "\n");
376 
377  xmlFreeNode(node);
378 }
379 
380 static void
381 write_bool_part(FILE *out, const char *tag, gboolean data)
382 {
383  xmlNodePtr node;
384 
385  node = int_to_dom_tree(tag, data);
386 
387  xmlElemDump(out, NULL, node);
388  fprintf(out, "\n");
389 
390  xmlFreeNode(node);
391 }
392 
393 gboolean
394 gnc_write_example_account(GncExampleAccount *gea, const gchar *filename)
395 {
396  FILE *out;
397  sixtp_gdv2 data = { 0 };;
398 
399  out = g_fopen(filename, "w");
400  if (out == NULL)
401  {
402  return FALSE;
403  }
404 
405  fprintf(out, "<?xml version=\"1.0\"?>\n");
406  fprintf(out, "<" GNC_ACCOUNT_STRING ">\n");
407 
408  write_string_part(out, GNC_ACCOUNT_TITLE, gea->title);
409 
410  write_string_part(out, GNC_ACCOUNT_SHORT, gea->short_description);
411 
412  write_string_part(out, GNC_ACCOUNT_LONG, gea->long_description);
413 
414  write_bool_part(out, GNC_ACCOUNT_EXCLUDEP, gea->exclude_from_select_all);
415 
416  write_account_tree(out, gea->root, &data);
417 
418  fprintf(out, "</" GNC_ACCOUNT_STRING ">\n\n");
419 
420  write_emacs_trailer(out);
421 
422  fclose(out);
423 
424  return TRUE;
425 
426 }
427 
428 /***********************************************************************/
429 
430 static void
431 slist_destroy_example_account(gpointer data, gpointer user_data)
432 {
433  if (data != NULL)
434  {
435  gnc_destroy_example_account((GncExampleAccount*)data);
436  }
437  else
438  {
439  PWARN("GncExampleAccount pointer in slist was NULL");
440  }
441 }
442 
443 void
444 gnc_free_example_account_list(GSList *list)
445 {
446  g_slist_foreach(list, slist_destroy_example_account, NULL);
447  g_slist_free(list);
448 }
449 
450 GSList*
451 gnc_load_example_account_list(const char *dirname)
452 {
453  GSList *ret;
454  GDir *dir;
455  const gchar *direntry;
456 
457  dir = g_dir_open(dirname, 0, NULL);
458 
459  if (dir == NULL)
460  {
461  return NULL;
462  }
463 
464  ret = NULL;
465 
466  for (direntry = g_dir_read_name(dir); direntry != NULL;
467  direntry = g_dir_read_name(dir))
468  {
469  gchar *filename;
470  GncExampleAccount *gea;
471  if (!g_str_has_suffix(direntry, "xea"))
472  continue;
473 
474  filename = g_build_filename(dirname, direntry, (gchar*) NULL);
475 
476  if (!g_file_test(filename, G_FILE_TEST_IS_DIR))
477  {
478  gea = gnc_read_example_account(filename);
479 
480  if (gea == NULL)
481  {
482  g_free(filename);
483  gnc_free_example_account_list(ret);
484  g_dir_close(dir);
485  return NULL;
486  }
487 
488  ret = g_slist_append(ret, gea);
489  }
490 
491  g_free(filename);
492  }
493  g_dir_close(dir);
494 
495  return ret;
496 }
497 
498 
499 
500 /***********************************************************************/
501 /*
502 gboolean
503 gnc_is_example_account_xml(const gchar *name)
504 {
505  return gnc_is_our_xml_file(name, GNC_ACCOUNT_STRING, NULL);
506 } */
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
Account * gnc_account_get_parent(const Account *acc)
Definition: Account.c:2623
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Definition: sixtp.h:93
void gnc_account_append_child(Account *new_parent, Account *child)
Definition: Account.c:2525
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
void xaccAccountScrubCommodity(Account *account)
Definition: Scrub.c:1110
QofBook * qof_book_new(void)
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
void xaccAccountDestroy(Account *acc)
Definition: Account.c:1400
#define PWARN(format, args...)
Definition: qoflog.h:243
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)
Definition: Account.c:1280
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
void gnc_commodity_destroy(gnc_commodity *cm)
void xaccLogEnable(void)
Definition: TransLog.c:97
void qof_book_destroy(QofBook *book)
const gchar * QofLogModule
Definition: qofid.h:89
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389