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