GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
qif-context.c
1 /*
2  * qif-context.c -- create/destroy QIF Contexts
3  *
4  * Written By: Derek Atkins <[email protected]>
5  * Copyright (c) 2003 Derek Atkins <[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 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <glib.h>
30 
31 #include "qif-import-p.h"
32 #include "qif-objects-p.h"
33 
34 static void qif_object_map_get_helper(gpointer key, gpointer value, gpointer listp);
35 
37 qif_context_new(void)
38 {
39  QifContext ctx = g_new0(struct _QifContext, 1);
40 
41  ctx->object_lists = g_hash_table_new(g_str_hash, g_str_equal);
42  ctx->object_maps = g_hash_table_new(g_str_hash, g_str_equal);
43 
44  return ctx;
45 }
46 
47 void
48 qif_context_destroy(QifContext ctx)
49 {
50  GList *node, *temp;
51  QifContext fctx;
52 
53  if (!ctx) return;
54 
55  /* First, try to destroy all the children contexts */
56  for (node = ctx->files; node; node = temp)
57  {
58  fctx = node->data;
59  temp = node->next;
60  qif_context_destroy(fctx);
61  }
62 
63  /* ok, at this point we're actually destroying this context. */
64 
65  /* force the end of record */
66  if (ctx->handler && ctx->handler->end)
67  ctx->handler->end(ctx);
68 
69  /* destroy the state objects */
70  qif_object_list_destroy(ctx);
71  qif_object_map_destroy(ctx);
72 
73  /* Remove us from our parent context */
74  if (ctx->parent)
75  ctx->parent->files = g_list_remove(ctx->parent->files, ctx);
76 
77  g_free(ctx->filename);
78 
79  g_assert(ctx->files == NULL);
80  g_free(ctx);
81 }
82 
83 static GList *
84 qif_context_get_foo_helper(QifContext ctx, GFunc get_helper)
85 {
86  GHashTable *ht;
87  GList *node, *list = NULL;
88  QifContext fctx;
89 
90  g_return_val_if_fail(ctx, NULL);
91  g_return_val_if_fail(ctx->parsed, NULL);
92  g_return_val_if_fail(get_helper, NULL);
93 
94  ht = g_hash_table_new(g_direct_hash, g_direct_equal);
95 
96  for (node = ctx->files; node; node = node->next)
97  {
98  fctx = node->data;
99  qif_object_list_foreach(fctx, QIF_O_TXN, get_helper, ht);
100  }
101 
102  g_hash_table_foreach(ht, qif_object_map_get_helper, &list);
103  g_hash_table_destroy(ht);
104 
105  return list;
106 }
107 
108 static void
109 qif_get_accts_helper(gpointer obj, gpointer htp)
110 {
111  QifTxn txn = obj;
112  QifSplit split;
113  GHashTable *ht = htp;
114  GList *node;
115 
116  if (txn->from_acct)
117  g_hash_table_insert(ht, txn->from_acct, txn->from_acct);
118 
119  /* The default_split is using the from_acct, so we can ignore it */
120 
121  for (node = txn->splits; node; node = node->next)
122  {
123  split = node->data;
124  if (split->cat.obj && split->cat_is_acct)
125  g_hash_table_insert(ht, split->cat.acct, split->cat.acct);
126  }
127 }
128 
129 GList *
130 qif_context_get_accounts(QifContext ctx)
131 {
132  return qif_context_get_foo_helper(ctx, qif_get_accts_helper);
133 }
134 
135 static void
136 qif_get_cats_helper(gpointer obj, gpointer htp)
137 {
138  QifTxn txn = obj;
139  QifSplit split;
140  GHashTable *ht = htp;
141  GList *node;
142 
143  /* default_split uses from_acct, so no categories */
144 
145  for (node = txn->splits; node; node = node->next)
146  {
147  split = node->data;
148  if (split->cat.obj && !split->cat_is_acct)
149  g_hash_table_insert(ht, split->cat.cat, split->cat.cat);
150  }
151 }
152 
153 GList *
154 qif_context_get_categories(QifContext ctx)
155 {
156  return qif_context_get_foo_helper(ctx, qif_get_cats_helper);
157 }
158 
159 /*****************************************************************************/
160 
161 /*
162  * Insert and remove a QifObject from the Object Maps in this Qif Context
163  */
164 
165 gint
166 qif_object_map_count(QifContext ctx, const char *type)
167 {
168  GHashTable *ht;
169 
170  g_return_val_if_fail(ctx, 0);
171  g_return_val_if_fail(ctx->object_maps, 0);
172  g_return_val_if_fail(type, 0);
173 
174  ht = g_hash_table_lookup(ctx->object_maps, type);
175  if (!ht)
176  return 0;
177 
178  return g_hash_table_size(ht);
179 }
180 
181 void
182 qif_object_map_foreach(QifContext ctx, const char *type, GHFunc func, gpointer arg)
183 {
184  GHashTable *ht;
185 
186  g_return_if_fail(ctx);
187  g_return_if_fail(ctx->object_maps);
188  g_return_if_fail(type);
189 
190  ht = g_hash_table_lookup(ctx->object_maps, type);
191  if (ht)
192  g_hash_table_foreach(ht, func, arg);
193 }
194 
195 void
196 qif_object_map_insert(QifContext ctx, const char *key, QifObject obj)
197 {
198  GHashTable *ht;
199 
200  g_return_if_fail(ctx);
201  g_return_if_fail(ctx->object_maps);
202  g_return_if_fail(key);
203  g_return_if_fail(obj);
204  g_return_if_fail(obj->type);
205 
206  ht = g_hash_table_lookup(ctx->object_maps, obj->type);
207  if (!ht)
208  {
209  ht = g_hash_table_new(g_str_hash, g_str_equal);
210  g_assert(ht);
211  g_hash_table_insert(ctx->object_maps, (gpointer)obj->type, ht);
212  }
213 
214  g_hash_table_insert(ht, (gpointer)key, obj);
215 }
216 
217 void
218 qif_object_map_remove(QifContext ctx, const char *type, const char *key)
219 {
220  GHashTable *ht;
221 
222  g_return_if_fail(ctx);
223  g_return_if_fail(ctx->object_maps);
224  g_return_if_fail(type);
225  g_return_if_fail(key);
226 
227  ht = g_hash_table_lookup(ctx->object_maps, type);
228  if (!ht) return;
229 
230  g_hash_table_remove(ht, key);
231 }
232 
233 QifObject
234 qif_object_map_lookup(QifContext ctx, const char *type, const char *key)
235 {
236  GHashTable *ht;
237 
238  g_return_val_if_fail(ctx, NULL);
239  g_return_val_if_fail(ctx->object_maps, NULL);
240  g_return_val_if_fail(type, NULL);
241  g_return_val_if_fail(key, NULL);
242 
243  ht = g_hash_table_lookup(ctx->object_maps, type);
244  if (!ht) return NULL;
245 
246  return g_hash_table_lookup(ht, key);
247 }
248 
249 /* This GList _SHOULD_ be freed by the caller */
250 
251 static void
252 qif_object_map_get_helper(gpointer key, gpointer value, gpointer arg)
253 {
254  GList **listp = arg;
255  g_return_if_fail(listp);
256 
257  *listp = g_list_prepend(*listp, value);
258 }
259 
260 GList *
261 qif_object_map_get(QifContext ctx, const char *type)
262 {
263  GHashTable *ht;
264  GList *list = NULL;
265 
266  g_return_val_if_fail(ctx, NULL);
267  g_return_val_if_fail(ctx->object_maps, NULL);
268  g_return_val_if_fail(type, NULL);
269 
270  ht = g_hash_table_lookup(ctx->object_maps, type);
271  if (!ht)
272  return NULL;
273 
274  g_hash_table_foreach(ht, qif_object_map_get_helper, &list);
275 
276  return list;
277 }
278 
279 static gboolean
280 qif_object_map_remove_each(gpointer key, gpointer value, gpointer arg)
281 {
282  QifObject obj = value;
283  obj->destroy(obj);
284  return TRUE;
285 }
286 
287 static gboolean
288 qif_object_map_remove_all(gpointer key, gpointer value, gpointer arg)
289 {
290  GHashTable *ht = value;
291 
292  g_hash_table_foreach_remove(ht, qif_object_map_remove_each, NULL);
293  g_hash_table_destroy(ht);
294  return TRUE;
295 }
296 
297 void qif_object_map_destroy(QifContext ctx)
298 {
299  g_return_if_fail(ctx);
300  g_return_if_fail(ctx->object_maps);
301 
302  g_hash_table_foreach_remove(ctx->object_maps, qif_object_map_remove_all, NULL);
303  g_hash_table_destroy(ctx->object_maps);
304 }
305 
306 /*****************************************************************************/
307 
308 /*
309  * Insert and remove a QifObject from the Object Lists in this Qif Context
310  */
311 
312 void
313 qif_object_list_reverse(QifContext ctx, const char *type)
314 {
315  GList *list;
316 
317  g_return_if_fail(ctx);
318  g_return_if_fail(ctx->object_lists);
319  g_return_if_fail(type);
320 
321  list = qif_object_list_get(ctx, type);
322  list = g_list_reverse(list);
323  g_hash_table_insert(ctx->object_lists, (gpointer)type, list);
324 }
325 
326 gint
327 qif_object_list_count(QifContext ctx, const char *type)
328 {
329  GList *list;
330 
331  g_return_val_if_fail(ctx, 0);
332  g_return_val_if_fail(ctx->object_lists, 0);
333  g_return_val_if_fail(type, 0);
334 
335  list = g_hash_table_lookup(ctx->object_lists, type);
336  return g_list_length(list);
337 }
338 
339 void
340 qif_object_list_foreach(QifContext ctx, const char *type, GFunc func, gpointer arg)
341 {
342  GList *list;
343 
344  g_return_if_fail(ctx);
345  g_return_if_fail(ctx->object_lists);
346  g_return_if_fail(type);
347 
348  list = qif_object_list_get(ctx, type);
349  g_list_foreach(list, func, arg);
350 }
351 
352 void
353 qif_object_list_insert(QifContext ctx, QifObject obj)
354 {
355  GList *list;
356 
357  g_return_if_fail(ctx);
358  g_return_if_fail(ctx->object_lists);
359  g_return_if_fail(obj);
360  g_return_if_fail(obj->type && *obj->type);
361 
362  list = g_hash_table_lookup(ctx->object_lists, obj->type);
363  list = g_list_prepend(list, obj);
364  g_hash_table_insert(ctx->object_lists, (gpointer)obj->type, list);
365 }
366 
367 void
368 qif_object_list_remove(QifContext ctx, QifObject obj)
369 {
370  GList *list;
371 
372  g_return_if_fail(ctx);
373  g_return_if_fail(ctx->object_lists);
374  g_return_if_fail(obj);
375  g_return_if_fail(obj->type && *obj->type);
376 
377  list = g_hash_table_lookup(ctx->object_lists, obj->type);
378  list = g_list_remove(list, obj);
379  g_hash_table_insert(ctx->object_lists, (gpointer)obj->type, list);
380 }
381 
382 GList *
383 qif_object_list_get(QifContext ctx, const char *type)
384 {
385  g_return_val_if_fail(ctx, NULL);
386  g_return_val_if_fail(ctx->object_lists, NULL);
387  g_return_val_if_fail(type, NULL);
388 
389  return g_hash_table_lookup(ctx->object_lists, type);
390 }
391 
392 static gboolean
393 qif_object_list_remove_all(gpointer key, gpointer value, gpointer arg)
394 {
395  GList *list = value;
396  GList *node;
397  QifObject obj;
398 
399  for (node = list; node; node = node->next)
400  {
401  obj = node->data;
402  obj->destroy(obj);
403  }
404 
405  g_list_free(list);
406  return TRUE;
407 }
408 
409 void
410 qif_object_list_destroy(QifContext ctx)
411 {
412  g_return_if_fail(ctx);
413  g_return_if_fail(ctx->object_lists);
414 
415  g_hash_table_foreach_remove(ctx->object_lists, qif_object_list_remove_all, NULL);
416  g_hash_table_destroy(ctx->object_lists);
417 }