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