GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
qif-parse.c
1 /*
2  * qif-parse.c -- parse QIF
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 #include <glib/gi18n.h>
31 #include <string.h>
32 
33 /* For regex */
34 #include <sys/types.h>
35 #include <regex.h>
36 
37 #include <stdarg.h>
38 
39 #include "gnc-engine.h"
40 #include "gnc-ui-util.h"
41 
42 #include "qif-import-p.h"
43 #include "qif-objects-p.h"
44 
45 #include "import-parse.h"
46 
47 static QofLogModule log_module = GNC_MOD_IMPORT;
48 
49 /* An array of handlers for the various bang-types */
50 static QifHandler qif_handlers[QIF_TYPE_MAX+1] = { NULL };
51 
52 /* Parser Regular Expressions */
53 static gboolean qifp_regex_compiled = FALSE;
54 static regex_t category_regex;
55 
56 /* A Hash Table of bang-types */
57 static GHashTable *qif_bangtype_map = NULL;
58 
59 /* A Hash Table of action strings */
60 static GHashTable *qif_action_map = NULL;
61 
62 /* A Hash Table of account types */
63 static GHashTable *qif_atype_map = NULL;
64 
65 /************************************************************************/
66 
67 /* Register a handler */
68 void
69 qif_register_handler(QifType type, QifHandler handler)
70 {
71  if (type <= 0 || type > QIF_TYPE_MAX)
72  {
73  PERR("Invalid type: %d", type);
74  return;
75  }
76  qif_handlers[type] = handler;
77 }
78 
79 static void
80 compile_regex()
81 {
82  regcomp(&category_regex,
83  "^ *(\\[)?([^]/|]*)(]?)(/([^|]*))?(\\|(\\[)?([^]/]*)(]?)(/(.*))?)? *$",
84  REG_EXTENDED);
85 
86  qifp_regex_compiled = TRUE;
87 }
88 
89 #define QIF_ADD_TYPE(ts,t) \
90  g_hash_table_insert(qif_bangtype_map, ts, GINT_TO_POINTER(t)); \
91  g_hash_table_insert(qif_bangtype_map, _(ts), GINT_TO_POINTER(t));
92 
93 static void
94 build_bangtype_map()
95 {
96  g_return_if_fail(!qif_bangtype_map);
97 
98  qif_bangtype_map = g_hash_table_new(g_str_hash, g_str_equal);
99  g_assert(qif_bangtype_map);
100 
101  /* Translators FIXME: It is unclear whether these strings should
102  really be translated, and if yes, into which translation. */
103  QIF_ADD_TYPE(N_("type:bank"), QIF_TYPE_BANK);
104  QIF_ADD_TYPE(N_("type:cash"), QIF_TYPE_CASH);
105  QIF_ADD_TYPE(N_("type:ccard"), QIF_TYPE_CCARD);
106  QIF_ADD_TYPE(N_("type:invst"), QIF_TYPE_INVST);
107  QIF_ADD_TYPE(N_("type:port"), QIF_TYPE_PORT);
108  QIF_ADD_TYPE(N_("type:oth a"), QIF_TYPE_OTH_A);
109  QIF_ADD_TYPE(N_("type:oth l"), QIF_TYPE_OTH_L);
110  QIF_ADD_TYPE(N_("type:class"), QIF_TYPE_CLASS);
111  QIF_ADD_TYPE(N_("type:cat"), QIF_TYPE_CAT);
112  QIF_ADD_TYPE(N_("type:security"), QIF_TYPE_SECURITY);
113  QIF_ADD_TYPE(N_("account"), QIF_ACCOUNT);
114  QIF_ADD_TYPE(N_("option:autoswitch"), QIF_AUTOSWITCH);
115  QIF_ADD_TYPE(N_("clear:autoswitch"), QIF_CLEAR_AUTOSWITCH);
116 }
117 #undef QIF_ADD_TYPE
118 
119 #define QIF_ADD_ACT(ts,t) \
120  g_hash_table_insert(qif_action_map, ts, GINT_TO_POINTER(t));
121 
122 static void
123 build_action_map()
124 {
125  g_return_if_fail(!qif_action_map);
126 
127  qif_action_map = g_hash_table_new(g_str_hash, g_str_equal);
128  g_assert(qif_action_map);
129 
130  QIF_ADD_ACT("buy", QIF_A_BUY);
131  QIF_ADD_ACT("cvrshrt", QIF_A_BUY);
132  QIF_ADD_ACT("kauf", QIF_A_BUY);
133  QIF_ADD_ACT("buyx", QIF_A_BUYX);
134  QIF_ADD_ACT("cvrshrtx", QIF_A_BUYX);
135  QIF_ADD_ACT("kaufx", QIF_A_BUYX);
136  QIF_ADD_ACT("cglong", QIF_A_CGLONG);
137  QIF_ADD_ACT("kapgew", QIF_A_CGLONG); /* Kapitalgewinnsteuer */
138  QIF_ADD_ACT("cglongx", QIF_A_CGLONG);
139  QIF_ADD_ACT("kapgewx", QIF_A_CGLONG);
140  QIF_ADD_ACT("cgmid", QIF_A_CGMID);
141  QIF_ADD_ACT("cgmidx", QIF_A_CGMIDX);
142  QIF_ADD_ACT("cgshort", QIF_A_CGSHORT);
143  QIF_ADD_ACT("k.gewsp", QIF_A_CGSHORT);
144  QIF_ADD_ACT("cgshortx", QIF_A_CGSHORTX);
145  QIF_ADD_ACT("k.gewspx", QIF_A_CGSHORTX);
146  QIF_ADD_ACT("div", QIF_A_DIV); /* dividende */
147  QIF_ADD_ACT("divx", QIF_A_DIVX);
148  //QIF_ADD_ACT("exercise", QIF_A_EXERCISE);
149  //QIF_ADD_ACT("exercisex", QIF_A_EXERCISEX);
150  //QIF_ADD_ACT("expire", QIF_A_EXPIRE);
151  //QIF_ADD_ACT("grant", QIF_A_GRANT);
152  QIF_ADD_ACT("int", QIF_A_INTINC);
153  QIF_ADD_ACT("intinc", QIF_A_INTINC);
154  QIF_ADD_ACT("aktzu", QIF_A_INTINC); /* zinsen */
155  QIF_ADD_ACT("intx", QIF_A_INTINCX);
156  QIF_ADD_ACT("intincx", QIF_A_INTINCX);
157  QIF_ADD_ACT("margint", QIF_A_MARGINT);
158  QIF_ADD_ACT("margintx", QIF_A_MARGINTX);
159  QIF_ADD_ACT("miscexp", QIF_A_MISCEXP);
160  QIF_ADD_ACT("miscexpx", QIF_A_MISCEXPX);
161  QIF_ADD_ACT("miscinc", QIF_A_MISCINC);
162  QIF_ADD_ACT("cash", QIF_A_MISCINC);
163  QIF_ADD_ACT("miscincx", QIF_A_MISCINCX);
164  QIF_ADD_ACT("reinvdiv", QIF_A_REINVDIV);
165  QIF_ADD_ACT("reinvint", QIF_A_REINVINT);
166  QIF_ADD_ACT("reinvzin", QIF_A_REINVINT);
167  QIF_ADD_ACT("reinvlg", QIF_A_REINVLG);
168  QIF_ADD_ACT("reinvkur", QIF_A_REINVLG);
169  QIF_ADD_ACT("reinvmd", QIF_A_REINVMD);
170  QIF_ADD_ACT("reinvsg", QIF_A_REINVSG);
171  QIF_ADD_ACT("reinvksp", QIF_A_REINVSG);
172  QIF_ADD_ACT("reinvsh", QIF_A_REINVSH);
173  QIF_ADD_ACT("reminder", QIF_A_REMINDER);
174  QIF_ADD_ACT("erinnerg", QIF_A_REMINDER);
175  QIF_ADD_ACT("rtrncap", QIF_A_RTRNCAP);
176  QIF_ADD_ACT("rtrncapx", QIF_A_RTRNCAPX);
177  QIF_ADD_ACT("sell", QIF_A_SELL);
178  QIF_ADD_ACT("shtsell", QIF_A_SELL);
179  QIF_ADD_ACT("verkauf", QIF_A_SELL); /* verkaufen */
180  QIF_ADD_ACT("sellx", QIF_A_SELLX);
181  QIF_ADD_ACT("shtsellx", QIF_A_SELLX);
182  QIF_ADD_ACT("verkaufx", QIF_A_SELLX); /* verkaufen */
183  QIF_ADD_ACT("shrsin", QIF_A_SHRSIN);
184  QIF_ADD_ACT("aktzu", QIF_A_SHRSIN);
185  QIF_ADD_ACT("shrsout", QIF_A_SHRSOUT);
186  QIF_ADD_ACT("aktab", QIF_A_SHRSOUT);
187  QIF_ADD_ACT("stksplit", QIF_A_STKSPLIT);
188  QIF_ADD_ACT("aktsplit", QIF_A_STKSPLIT);
189  //QIF_ADD_ACT("vest", QIF_A_VEST);
190  QIF_ADD_ACT("xin", QIF_A_XIN);
191  QIF_ADD_ACT("contribx", QIF_A_XIN);
192  QIF_ADD_ACT("xout", QIF_A_XOUT);
193  QIF_ADD_ACT("withdrwx", QIF_A_XOUT);
194 }
195 #undef QIF_ADD_ACT
196 
197 static GList *
198 make_list(int count, ...)
199 {
200  GList *result = NULL;
201  GNCAccountType type;
202  va_list ap;
203 
204  va_start (ap, count);
205  while (count--)
206  {
207  type = va_arg (ap, GNCAccountType);
208  result = g_list_prepend (result, GINT_TO_POINTER(type));
209  }
210  va_end (ap);
211 
212 
213  return g_list_reverse(result);
214 }
215 
216 #define QIF_ADD_ATYPE(a,t) g_hash_table_insert(qif_atype_map, a, t);
217 static void
218 build_atype_map()
219 {
220  g_return_if_fail(!qif_atype_map);
221 
222  qif_atype_map = g_hash_table_new(g_str_hash, g_str_equal);
223  g_assert(qif_atype_map);
224 
225  QIF_ADD_ATYPE("bank", make_list(1, ACCT_TYPE_BANK));
226  QIF_ADD_ATYPE("port", make_list(1, ACCT_TYPE_BANK));
227  QIF_ADD_ATYPE("cash", make_list(1, ACCT_TYPE_CASH));
228  QIF_ADD_ATYPE("ccard", make_list(1, ACCT_TYPE_CREDIT));
229  QIF_ADD_ATYPE("invst", make_list(3, ACCT_TYPE_BANK, ACCT_TYPE_STOCK,
231  QIF_ADD_ATYPE("oth a", make_list(3, ACCT_TYPE_ASSET, ACCT_TYPE_BANK,
232  ACCT_TYPE_CASH));
233  QIF_ADD_ATYPE("oth l", make_list(2, ACCT_TYPE_LIABILITY, ACCT_TYPE_CREDIT));
234  QIF_ADD_ATYPE("mutual", make_list(3, ACCT_TYPE_BANK, ACCT_TYPE_MUTUAL,
235  ACCT_TYPE_STOCK));
236 
237  /* Internal types */
238  QIF_ADD_ATYPE("__any_bank__", make_list(5, ACCT_TYPE_BANK, ACCT_TYPE_CREDIT,
241  QIF_ADD_ATYPE("__all__", make_list(7, ACCT_TYPE_BANK, ACCT_TYPE_CREDIT,
245  QIF_ADD_ATYPE("__stock__", make_list(2, ACCT_TYPE_STOCK, ACCT_TYPE_MUTUAL));
246  QIF_ADD_ATYPE("__income__", make_list(1, ACCT_TYPE_INCOME));
247  QIF_ADD_ATYPE("__expense__", make_list(1, ACCT_TYPE_EXPENSE));
248  QIF_ADD_ATYPE("__equity__", make_list(1, ACCT_TYPE_EQUITY));
249 }
250 #undef QIF_ADD_ATYPE
251 
252 /************************************************************************/
253 
254 /*
255  * We've got a !Type line. Parse the line into the appropriate
256  * type and then initialize the handler.
257  */
258 void
259 qif_parse_bangtype(QifContext ctx, const char *line)
260 {
261  QifType type;
262  char *bangtype;
263  gpointer result;
264 
265  g_return_if_fail(line && *line == '!');
266 
267  if (!qif_bangtype_map)
268  build_bangtype_map();
269 
270  /* Make a local copy so we can manipulate it.
271  * - strip off leading/trailing whitespace
272  * - make it all lower case
273  */
274  bangtype = g_utf8_strdown(line + 1, -1);
275  g_strstrip(bangtype);
276 
277  /* In some cases we get "!Type Bank" -- change the space to a colon */
278  if (!strncmp(bangtype, "type ", 5))
279  bangtype[5] = ':';
280 
281  /* Lookup the bangtype in the map and then destroy the local copy */
282  result = g_hash_table_lookup(qif_bangtype_map, bangtype);
283  g_free(bangtype);
284 
285  if (!result)
286  {
287  PWARN("Unknown bang-type at line %d: %s. Ignored", ctx->lineno, line);
288  return;
289  }
290  type = GPOINTER_TO_INT(result);
291 
292  /* Set the current context parse type and handler */
293  ctx->parse_type = type;
294  ctx->handler = qif_handlers[type];
295 
296  /* now initialize this new parse type (if there's an init function) */
297  if (ctx->handler && ctx->handler->init)
298  ctx->handler->init(ctx);
299 }
300 
301 /* returns TRUE if successful, FALSE if there is a problem */
302 gboolean
303 qif_parse_split_category(const char* str,
304  char** cat, gboolean *cat_is_acct, char** cat_class,
305  char** miscx_cat, gboolean *miscx_cat_is_acct,
306  char **miscx_class)
307 {
308  /* This is a pretty f**ked up string. Basically it looks like:
309  * ([)cat-or-acct(])(/(class))(|([)cat-of-acct(])(/ext))
310  *
311  * where data in parens is "optional" (depending on the context).
312  *
313  * examples from reality:
314  *
315  * category
316  * category:subcategory
317  * category/class
318  * category:subcat/class
319  * [account]
320  * [account]/class
321  *
322  * cat/cat-class|miscx-cat/miscx-class
323  */
324 
325  regmatch_t pmatch[12];
326 
327  g_return_val_if_fail(cat && cat_is_acct && cat_class &&
328  miscx_cat && miscx_cat_is_acct && miscx_class, FALSE);
329 
330 
331  if (!qifp_regex_compiled)
332  compile_regex();
333 
334  if (regexec(&category_regex, str, 12, pmatch, 0) != 0)
335  {
336  PERR("category match failed");
337  return FALSE;
338  }
339 
340  /*
341  * what the substrings mean:
342  * 1 the opening [ for a transfer
343  * 2 the category
344  * 3 the closing ]
345  * 4 the class /
346  * 5 the class
347  * 6 the miscx expression (whole thing)
348  * 7 the opening [
349  * 8 the miscx category
350  * 9 the closing ]
351  * 10 the class /
352  * 11 the class
353  */
354 
355  if (pmatch[2].rm_so == -1)
356  {
357  PERR("no category match found!");
358  return FALSE;
359  }
360 
361  /* catgory name */
362  *cat = g_strndup(str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so);
363  /* category is account? */
364  *cat_is_acct = (pmatch[1].rm_so != -1 && pmatch[3].rm_so != -1);
365  /* category class */
366  *cat_class = (pmatch[4].rm_so != -1 ?
367  g_strndup(str + pmatch[5].rm_so, pmatch[5].rm_eo - pmatch[5].rm_so) :
368  NULL);
369 
370  /* miscx category name */
371  *miscx_cat = (pmatch[6].rm_so != -1 ?
372  g_strndup(str + pmatch[8].rm_so, pmatch[8].rm_eo - pmatch[8].rm_so) :
373  NULL);
374  /* miscx cat is acct */
375  *miscx_cat_is_acct = (pmatch[7].rm_so != -1 && pmatch[9].rm_so != -1);
376  /* miscx class */
377  *miscx_class = (pmatch[10].rm_so != -1 ?
378  g_strndup(str + pmatch[11].rm_so,
379  pmatch[11].rm_eo - pmatch[11].rm_so) : NULL);
380 
381  return TRUE;
382 }
383 
384 /*
385  * qif_parse_cleared -- parse the 'C'leared field of a QIF Transaction.
386  * returns the QIF reconciled flag.
387  *
388  * * means cleared, x or X means reconciled, and ! or ? mean some
389  * budget related stuff I don't understand.
390  */
391 QifRecnFlag
392 qif_parse_cleared(QifLine line)
393 {
394  g_return_val_if_fail(line, QIF_R_NO);
395  g_return_val_if_fail(line->line, QIF_R_NO);
396 
397  switch (*line->line)
398  {
399  case '*':
400  return QIF_R_CLEARED;
401  case 'x':
402  case 'X':
403  return QIF_R_RECONCILED;
404  case '?':
405  case '!':
406  return QIF_R_BUDGETED;
407  default:
408  PERR("Unknown QIF Cleared flag at line %d: %s", line->lineno, line->line);
409  return QIF_R_NO;
410  }
411 }
412 
413 QifAction qif_parse_action(QifLine line)
414 {
415  QifAction qaction;
416  gpointer result;
417  char *action;
418 
419  g_return_val_if_fail(line, QIF_A_NONE);
420  g_return_val_if_fail(line->line, QIF_A_NONE);
421 
422  if (!qif_action_map)
423  build_action_map();
424 
425  /* Duplicate the action and force it to lower case and strip any spaces */
426  action = g_utf8_strdown(line->line, -1);
427  g_strstrip(action);
428 
429  result = g_hash_table_lookup(qif_action_map, action);
430  g_free(action);
431 
432  if (!result)
433  {
434  /* XXX: pop up a dialog? */
435  PWARN("Unknown Action at line %d: %s. Some transactions may be discarded",
436  line->lineno, line->line);
437  return QIF_A_NONE;
438  }
439 
440  qaction = GPOINTER_TO_INT(result);
441  return qaction;
442 }
443 
444 GList * qif_parse_acct_type(const char *str, gint lineno)
445 {
446  GList *result;
447  char *type;
448 
449  if (!qif_atype_map)
450  build_atype_map();
451 
452  /* Duplicate the type and force it to lower case and strip any spaces */
453  type = g_utf8_strdown(str, -1);
454  g_strstrip(type);
455 
456  result = g_hash_table_lookup(qif_atype_map, type);
457  g_free(type);
458 
459  if (!result)
460  {
461  PWARN("Unknown account type at line %d: %s. ", lineno, str);
462  result = g_hash_table_lookup(qif_atype_map, "bank");
463  g_return_val_if_fail(result, NULL);
464  }
465 
466  return result;
467 }
468 
469 GList * qif_parse_acct_type_guess(QifType type)
470 {
471  const char *atype = NULL;
472 
473  switch (type)
474  {
475  case QIF_TYPE_BANK:
476  atype = "bank";
477  break;
478  case QIF_TYPE_CASH:
479  atype = "cash";
480  break;
481  case QIF_TYPE_CCARD:
482  atype = "ccard";
483  break;
484  case QIF_TYPE_INVST:
485  atype = "invst";
486  break;
487  case QIF_TYPE_PORT:
488  atype = "port";
489  break;
490  case QIF_TYPE_OTH_A:
491  atype = "oth a";
492  break;
493  case QIF_TYPE_OTH_L:
494  atype = "oth l";
495  break;
496  default:
497  return NULL;
498  }
499 
500  return qif_parse_acct_type(atype, -1);
501 }
502 
503 /***********************************************************************
504  * Parsing numbers and dates...
505  */
506 
507 typedef struct _parse_helper
508 {
509  QifContext ctx;
510 
511  GncImportFormat budget;
512  GncImportFormat limit;
513  GncImportFormat amount;
514  GncImportFormat d_amount;
515  GncImportFormat price;
516  GncImportFormat shares;
517  GncImportFormat commission;
518  GncImportFormat date;
519 } *parse_helper_t;
520 
521 #define QIF_PARSE_CHECK_NUMBER(str,help) { \
522  if (str) (help) = gnc_import_test_numeric((str), (help)); \
523 }
524 #define QIF_PARSE_PARSE_NUMBER(str,fmt,val) { \
525  if (str) gnc_import_parse_numeric((str), (fmt), (val)); \
526 }
527 
528 static void
529 qif_parse_check_account(gpointer key, gpointer val, gpointer data)
530 {
531  parse_helper_t helper = data;
532  QifAccount acct = val;
533 
534  QIF_PARSE_CHECK_NUMBER(acct->limitstr, helper->limit);
535  QIF_PARSE_CHECK_NUMBER(acct->budgetstr, helper->budget);
536 }
537 
538 static void
539 qif_parse_parse_account(gpointer key, gpointer val, gpointer data)
540 {
541  parse_helper_t helper = data;
542  QifAccount acct = val;
543 
544  QIF_PARSE_PARSE_NUMBER(acct->limitstr, helper->limit, &acct->limit);
545  QIF_PARSE_PARSE_NUMBER(acct->budgetstr, helper->budget, &acct->budget);
546 }
547 
548 static void
549 qif_parse_check_category(gpointer key, gpointer val, gpointer data)
550 {
551  parse_helper_t helper = data;
552  QifCategory cat = val;
553 
554  QIF_PARSE_CHECK_NUMBER(cat->budgetstr, helper->budget);
555 }
556 
557 static void
558 qif_parse_parse_category(gpointer key, gpointer val, gpointer data)
559 {
560  parse_helper_t helper = data;
561  QifCategory cat = val;
562 
563  QIF_PARSE_PARSE_NUMBER(cat->budgetstr, helper->budget, &cat->budget);
564 }
565 
566 static void
567 qif_parse_check_txn(gpointer val, gpointer data)
568 {
569  parse_helper_t helper = data;
570  QifTxn txn = val;
571  QifSplit split;
572  QifInvstTxn itxn;
573  GList *node;
574 
575  /* Check the date */
576  helper->date = gnc_import_test_date(txn->datestr, helper->date);
577 
578  /* If this is an investment transaction, then all the info is in
579  * the invst_info. Otherwise it's all in the splits.
580  */
581  itxn = txn->invst_info;
582  if (itxn)
583  {
584  QIF_PARSE_CHECK_NUMBER(itxn->amountstr, helper->amount);
585  QIF_PARSE_CHECK_NUMBER(itxn->d_amountstr, helper->d_amount);
586  QIF_PARSE_CHECK_NUMBER(itxn->pricestr, helper->price);
587  QIF_PARSE_CHECK_NUMBER(itxn->sharesstr, helper->shares);
588  QIF_PARSE_CHECK_NUMBER(itxn->commissionstr, helper->commission);
589 
590  }
591  else
592  {
593  split = txn->default_split;
594  node = txn->splits;
595  do
596  {
597  QIF_PARSE_CHECK_NUMBER(split->amountstr, helper->amount);
598 
599  if (node)
600  {
601  split = node->data;
602  node = node->next;
603  }
604  else
605  split = NULL;
606  }
607  while (split);
608  }
609 }
610 
611 static void
612 qif_parse_parse_txn(gpointer val, gpointer data)
613 {
614  parse_helper_t helper = data;
615  QifTxn txn = val;
616  QifSplit split;
617  QifInvstTxn itxn;
618  GList *node;
619 
620  /* Parse the date */
621  gnc_import_parse_date(txn->datestr, helper->date, &txn->date);
622 
623  /* If this is an investment transaction, then all the info is in
624  * the invst_info. Otherwise it's all in the splits.
625  */
626  itxn = txn->invst_info;
627  if (itxn)
628  {
629  QIF_PARSE_PARSE_NUMBER(itxn->amountstr, helper->amount, &itxn->amount);
630  QIF_PARSE_PARSE_NUMBER(itxn->d_amountstr, helper->d_amount, &itxn->d_amount);
631  QIF_PARSE_PARSE_NUMBER(itxn->pricestr, helper->price, &itxn->price);
632  QIF_PARSE_PARSE_NUMBER(itxn->sharesstr, helper->shares, &itxn->shares);
633  QIF_PARSE_PARSE_NUMBER(itxn->commissionstr, helper->commission,
634  &itxn->commission);
635 
636  qif_invst_txn_setup_splits(helper->ctx, txn);
637 
638  }
639  else
640  {
641  split = txn->default_split;
642  node = txn->splits;
643  do
644  {
645  QIF_PARSE_PARSE_NUMBER(split->amountstr, helper->amount, &split->amount);
646 
647  if (node)
648  {
649  split = node->data;
650  node = node->next;
651  }
652  else
653  split = NULL;
654  }
655  while (split);
656 
657  qif_txn_setup_splits(txn);
658  }
659 }
660 
661 void
662 qif_parse_all(QifContext ctx, gpointer arg)
663 {
664  struct _parse_helper helper;
665 
666  helper.ctx = ctx;
667 
668  /* PARSE ACCOUNTS */
669 
670  /* First, figure out the formats */
671  helper.limit = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
672  helper.budget = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
673  qif_object_map_foreach(ctx, QIF_O_ACCOUNT, qif_parse_check_account, &helper);
674 
675  /* Make sure it's not ambiguous */
676  if (helper.limit & (helper.limit - 1)) helper.limit = GNCIF_NUM_PERIOD;
677  if (helper.budget & (helper.budget - 1)) helper.budget = GNCIF_NUM_PERIOD;
678 
679  /* Now convert the numbers */
680  qif_object_map_foreach(ctx, QIF_O_ACCOUNT, qif_parse_parse_account, &helper);
681 
682  /* PARSE CATEGORIES */
683 
684  helper.budget = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
685  qif_object_map_foreach(ctx, QIF_O_CATEGORY, qif_parse_check_category, &helper);
686 
687  /* make sure it's not ambiguous */
688  if (helper.budget & (helper.budget - 1)) helper.budget = GNCIF_NUM_PERIOD;
689 
690  /* Now convert the numbers */
691  qif_object_map_foreach(ctx, QIF_O_CATEGORY, qif_parse_parse_category, &helper);
692 
693  /* PARSE TRANSACTIONS */
694  helper.amount = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
695  helper.d_amount = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
696  helper.price = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
697  helper.shares = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
698  helper.commission = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
699  helper.date = GNCIF_DATE_MDY | GNCIF_DATE_DMY | GNCIF_DATE_YMD | GNCIF_DATE_YDM;
700 
701  qif_object_list_foreach(ctx, QIF_O_TXN, qif_parse_check_txn, &helper);
702 
703  /* check/fix ambiguities */
704  if (helper.amount & (helper.amount - 1)) helper.amount = GNCIF_NUM_PERIOD;
705  if (helper.d_amount & (helper.d_amount - 1)) helper.d_amount = GNCIF_NUM_PERIOD;
706  if (helper.price & (helper.price - 1)) helper.price = GNCIF_NUM_PERIOD;
707  if (helper.shares & (helper.shares - 1)) helper.shares = GNCIF_NUM_PERIOD;
708  if (helper.commission & (helper.commission - 1))
709  helper.commission = GNCIF_NUM_PERIOD;
710 
711  if (helper.date & (helper.date - 1))
712  {
713  helper.date = gnc_import_choose_fmt(_("The Date format is ambiguous. "
714  "Please choose the correct format."),
715  helper.date, arg);
716  }
717 
718  /* now parse it.. */
719  qif_object_list_foreach(ctx, QIF_O_TXN, qif_parse_parse_txn, &helper);
720 }
721 
722 typedef struct
723 {
724  QifContext ctx;
725  GList * list;
726  const char* type;
727 } qif_merge_t;
728 
729 static void
730 qif_merge_accts(gpointer key, gpointer value, gpointer data)
731 {
732  qif_merge_t *merge = data;
733  QifAccount acct = value;
734 
735  /* Merge into the context. Remember items moved into the parent */
736  if (qif_account_merge(merge->ctx, acct) == acct)
737  merge->list = g_list_prepend(merge->list, acct->name);
738 }
739 
740 static void
741 qif_merge_cats(gpointer key, gpointer value, gpointer data)
742 {
743  qif_merge_t *merge = data;
744  QifCategory cat = value;
745 
746  /* Merge into the context. Remember items moved into the parent */
747  if (qif_cat_merge(merge->ctx, cat) == cat)
748  merge->list = g_list_prepend(merge->list, cat->name);
749 }
750 
751 static void
752 qif_merge_classes(gpointer key, gpointer value, gpointer data)
753 {
754  qif_merge_t *merge = data;
755  QifClass qclass = value;
756 
757  /* Merge into the context. Remember items moved into the parent */
758  if (qif_class_merge(merge->ctx, qclass) == qclass)
759  merge->list = g_list_prepend(merge->list, qclass->name);
760 }
761 
762 static void
763 qif_merge_secs(gpointer key, gpointer value, gpointer data)
764 {
765  qif_merge_t *merge = data;
766  QifSecurity sec = value;
767 
768  /* Merge into the context. Remember items moved into the parent */
769  if (qif_security_merge(merge->ctx, sec) == sec)
770  merge->list = g_list_prepend(merge->list, sec->name);
771 }
772 
773 static void
774 qif_merge_del(gpointer obj, gpointer data)
775 {
776  qif_merge_t *merge = data;
777  const char *name = obj;
778 
779  qif_object_map_remove(merge->ctx, merge->type, name);
780 }
781 
782 static void
783 qif_massage_split(QifSplit split, QifContext ctx)
784 {
785  const char *type = QIF_O_CATEGORY;
786  char *name;
787 
788  if (split->cat.obj)
789  {
790  if (split->cat_is_acct)
791  {
792  type = QIF_O_ACCOUNT;
793  name = split->cat.acct->name;
794  }
795  else
796  name = split->cat.cat->name;
797 
798  split->cat.obj = qif_object_map_lookup(ctx, type, name);
799  }
800 
801  if (split->cat_class)
802  {
803  split->cat_class = (QifClass) qif_object_map_lookup(ctx, QIF_O_CLASS,
804  split->cat_class->name);
805  }
806 }
807 
808 static void
809 qif_massage_itxn(QifInvstTxn itxn, QifContext ctx)
810 {
811  const char *type = QIF_O_CATEGORY;
812  char *name;
813 
814  if (itxn->far_cat.obj)
815  {
816  if (itxn->far_cat_is_acct)
817  {
818  type = QIF_O_ACCOUNT;
819  name = itxn->far_cat.acct->name;
820  }
821  else
822  name = itxn->far_cat.cat->name;
823 
824  itxn->far_cat.obj = qif_object_map_lookup(ctx, type, name);
825  }
826 }
827 
828 static void
829 qif_massage_txn(gpointer obj, gpointer data)
830 {
831  QifTxn txn = obj;
832  QifContext ctx = data;
833  QifSplit split;
834  GList *node;
835 
836  if (txn->from_acct)
837  txn->from_acct = (QifAccount) qif_object_map_lookup(ctx, QIF_O_ACCOUNT,
838  txn->from_acct->name);
839 
840  if (txn->invst_info)
841  qif_massage_itxn(txn->invst_info, ctx);
842 
843  if (txn->default_split)
844  qif_massage_split(txn->default_split, ctx);
845 
846  for (node = txn->splits; node; node = node->next)
847  {
848  split = node->data;
849  qif_massage_split(split, ctx);
850  }
851 }
852 
853 void
854 qif_parse_merge_files(QifContext ctx)
855 {
856  GList *node;
857  GList *accts = NULL;
858  GList *cats = NULL;
859  GList *classes = NULL;
860  GList *securities = NULL;
861  QifContext fctx;
862 
863  qif_merge_t merge;
864 
865  g_return_if_fail(ctx);
866 
867  /* Make sure each of the "file" contexts have been parsed.
868  * note that we don't care about OUR context -- we can run this
869  * process multiple times safely.
870  */
871  for (node = ctx->files; node; node = node->next)
872  {
873  fctx = node->data;
874  g_return_if_fail(fctx->parsed);
875  }
876 
877 
878  /* Iterate over each file. Merge the Accounts, Categories, Classes,
879  * Securities, and Transactions into the top-level context. Be sure
880  * to re-point all Transaction/Split category/class/account pointers
881  * to the new top-level item. Then be sure to remove the
882  * "duplicated" items so we don't double-free (as we don't refcount,
883  * either).
884  */
885  for (node = ctx->files; node; node = node->next)
886  {
887  fctx = node->data;
888 
889  /* Merge accts, categories, classes, and securities */
890 
891  merge.ctx = ctx;
892  merge.list = NULL;
893  qif_object_map_foreach(fctx, QIF_O_ACCOUNT, qif_merge_accts, &merge);
894  accts = merge.list;
895 
896  merge.list = NULL;
897  qif_object_map_foreach(fctx, QIF_O_CATEGORY, qif_merge_cats, &merge);
898  cats = merge.list;
899 
900  merge.list = NULL;
901  qif_object_map_foreach(fctx, QIF_O_CLASS, qif_merge_classes, &merge);
902  classes = merge.list;
903 
904  merge.list = NULL;
905  qif_object_map_foreach(fctx, QIF_O_SECURITY, qif_merge_secs, &merge);
906  securities = merge.list;
907 
908 
909  /* repoint the transactions to the merged context data */
910  qif_object_list_foreach(fctx, QIF_O_TXN, qif_massage_txn, ctx);
911 
912 
913  /* then remove from the file context objects referenced in the top context */
914  merge.ctx = fctx;
915  merge.type = QIF_O_ACCOUNT;
916  g_list_foreach(accts, qif_merge_del, &merge);
917  g_list_free(accts);
918 
919  merge.type = QIF_O_CATEGORY;
920  g_list_foreach(cats, qif_merge_del, &merge);
921  g_list_free(cats);
922 
923  merge.type = QIF_O_CLASS;
924  g_list_foreach(classes, qif_merge_del, &merge);
925  g_list_free(classes);
926 
927  merge.type = QIF_O_SECURITY;
928  g_list_foreach(securities, qif_merge_del, &merge);
929  g_list_free(securities);
930 
931  }
932 
933  /* We've been parsed */
934  ctx->parsed = TRUE;
935 }
utility functions for the GnuCash UI
#define PERR(format, args...)
Definition: qoflog.h:237
#define PWARN(format, args...)
Definition: qoflog.h:243
All type declarations for the whole Gnucash engine.
GNCAccountType
Definition: Account.h:96
const gchar * QofLogModule
Definition: qofid.h:89