30 #include <glib/gi18n.h>
34 #include <sys/types.h>
42 #include "qif-import-p.h"
43 #include "qif-objects-p.h"
45 #include "import-parse.h"
50 static QifHandler qif_handlers[QIF_TYPE_MAX+1] = { NULL };
53 static gboolean qifp_regex_compiled = FALSE;
54 static regex_t category_regex;
57 static GHashTable *qif_bangtype_map = NULL;
60 static GHashTable *qif_action_map = NULL;
63 static GHashTable *qif_atype_map = NULL;
69 qif_register_handler(QifType type,
QifHandler handler)
71 if (type <= 0 || type > QIF_TYPE_MAX)
73 PERR(
"Invalid type: %d", type);
76 qif_handlers[type] = handler;
82 regcomp(&category_regex,
83 "^ *(\\[)?([^]/|]*)(]?)(/([^|]*))?(\\|(\\[)?([^]/]*)(]?)(/(.*))?)? *$",
86 qifp_regex_compiled = TRUE;
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));
96 g_return_if_fail(!qif_bangtype_map);
98 qif_bangtype_map = g_hash_table_new(g_str_hash, g_str_equal);
99 g_assert(qif_bangtype_map);
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);
119 #define QIF_ADD_ACT(ts,t) \
120 g_hash_table_insert(qif_action_map, ts, GINT_TO_POINTER(t));
125 g_return_if_fail(!qif_action_map);
127 qif_action_map = g_hash_table_new(g_str_hash, g_str_equal);
128 g_assert(qif_action_map);
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);
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);
147 QIF_ADD_ACT(
"divx", QIF_A_DIVX);
152 QIF_ADD_ACT(
"int", QIF_A_INTINC);
153 QIF_ADD_ACT(
"intinc", QIF_A_INTINC);
154 QIF_ADD_ACT(
"aktzu", QIF_A_INTINC);
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);
180 QIF_ADD_ACT(
"sellx", QIF_A_SELLX);
181 QIF_ADD_ACT(
"shtsellx", QIF_A_SELLX);
182 QIF_ADD_ACT(
"verkaufx", QIF_A_SELLX);
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);
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);
198 make_list(
int count, ...)
200 GList *result = NULL;
204 va_start (ap, count);
208 result = g_list_prepend (result, GINT_TO_POINTER(type));
213 return g_list_reverse(result);
216 #define QIF_ADD_ATYPE(a,t) g_hash_table_insert(qif_atype_map, a, t);
220 g_return_if_fail(!qif_atype_map);
222 qif_atype_map = g_hash_table_new(g_str_hash, g_str_equal);
223 g_assert(qif_atype_map);
259 qif_parse_bangtype(
QifContext ctx,
const char *line)
265 g_return_if_fail(line && *line ==
'!');
267 if (!qif_bangtype_map)
268 build_bangtype_map();
274 bangtype = g_utf8_strdown(line + 1, -1);
275 g_strstrip(bangtype);
278 if (!strncmp(bangtype,
"type ", 5))
282 result = g_hash_table_lookup(qif_bangtype_map, bangtype);
287 PWARN(
"Unknown bang-type at line %d: %s. Ignored", ctx->lineno, line);
290 type = GPOINTER_TO_INT(result);
293 ctx->parse_type = type;
294 ctx->handler = qif_handlers[type];
297 if (ctx->handler && ctx->handler->init)
298 ctx->handler->init(ctx);
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,
325 regmatch_t pmatch[12];
327 g_return_val_if_fail(cat && cat_is_acct && cat_class &&
328 miscx_cat && miscx_cat_is_acct && miscx_class, FALSE);
331 if (!qifp_regex_compiled)
334 if (regexec(&category_regex, str, 12, pmatch, 0) != 0)
336 PERR(
"category match failed");
355 if (pmatch[2].rm_so == -1)
357 PERR(
"no category match found!");
362 *cat = g_strndup(str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so);
364 *cat_is_acct = (pmatch[1].rm_so != -1 && pmatch[3].rm_so != -1);
366 *cat_class = (pmatch[4].rm_so != -1 ?
367 g_strndup(str + pmatch[5].rm_so, pmatch[5].rm_eo - pmatch[5].rm_so) :
371 *miscx_cat = (pmatch[6].rm_so != -1 ?
372 g_strndup(str + pmatch[8].rm_so, pmatch[8].rm_eo - pmatch[8].rm_so) :
375 *miscx_cat_is_acct = (pmatch[7].rm_so != -1 && pmatch[9].rm_so != -1);
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);
392 qif_parse_cleared(
QifLine line)
394 g_return_val_if_fail(line, QIF_R_NO);
395 g_return_val_if_fail(line->line, QIF_R_NO);
400 return QIF_R_CLEARED;
403 return QIF_R_RECONCILED;
406 return QIF_R_BUDGETED;
408 PERR(
"Unknown QIF Cleared flag at line %d: %s", line->lineno, line->line);
413 QifAction qif_parse_action(
QifLine line)
419 g_return_val_if_fail(line, QIF_A_NONE);
420 g_return_val_if_fail(line->line, QIF_A_NONE);
426 action = g_utf8_strdown(line->line, -1);
429 result = g_hash_table_lookup(qif_action_map, action);
435 PWARN(
"Unknown Action at line %d: %s. Some transactions may be discarded",
436 line->lineno, line->line);
440 qaction = GPOINTER_TO_INT(result);
444 GList * qif_parse_acct_type(
const char *str, gint lineno)
453 type = g_utf8_strdown(str, -1);
456 result = g_hash_table_lookup(qif_atype_map, type);
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);
469 GList * qif_parse_acct_type_guess(QifType type)
471 const char *atype = NULL;
500 return qif_parse_acct_type(atype, -1);
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;
521 #define QIF_PARSE_CHECK_NUMBER(str,help) { \
522 if (str) (help) = gnc_import_test_numeric((str), (help)); \
524 #define QIF_PARSE_PARSE_NUMBER(str,fmt,val) { \
525 if (str) gnc_import_parse_numeric((str), (fmt), (val)); \
529 qif_parse_check_account(gpointer key, gpointer val, gpointer data)
534 QIF_PARSE_CHECK_NUMBER(acct->limitstr, helper->limit);
535 QIF_PARSE_CHECK_NUMBER(acct->budgetstr, helper->budget);
539 qif_parse_parse_account(gpointer key, gpointer val, gpointer data)
544 QIF_PARSE_PARSE_NUMBER(acct->limitstr, helper->limit, &acct->limit);
545 QIF_PARSE_PARSE_NUMBER(acct->budgetstr, helper->budget, &acct->budget);
549 qif_parse_check_category(gpointer key, gpointer val, gpointer data)
554 QIF_PARSE_CHECK_NUMBER(cat->budgetstr, helper->budget);
558 qif_parse_parse_category(gpointer key, gpointer val, gpointer data)
563 QIF_PARSE_PARSE_NUMBER(cat->budgetstr, helper->budget, &cat->budget);
567 qif_parse_check_txn(gpointer val, gpointer data)
576 helper->date = gnc_import_test_date(txn->datestr, helper->date);
581 itxn = txn->invst_info;
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);
593 split = txn->default_split;
597 QIF_PARSE_CHECK_NUMBER(split->amountstr, helper->amount);
612 qif_parse_parse_txn(gpointer val, gpointer data)
621 gnc_import_parse_date(txn->datestr, helper->date, &txn->date);
626 itxn = txn->invst_info;
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,
636 qif_invst_txn_setup_splits(helper->ctx, txn);
641 split = txn->default_split;
645 QIF_PARSE_PARSE_NUMBER(split->amountstr, helper->amount, &split->amount);
657 qif_txn_setup_splits(txn);
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);
676 if (helper.limit & (helper.limit - 1)) helper.limit = GNCIF_NUM_PERIOD;
677 if (helper.budget & (helper.budget - 1)) helper.budget = GNCIF_NUM_PERIOD;
680 qif_object_map_foreach(ctx, QIF_O_ACCOUNT, qif_parse_parse_account, &helper);
684 helper.budget = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
685 qif_object_map_foreach(ctx, QIF_O_CATEGORY, qif_parse_check_category, &helper);
688 if (helper.budget & (helper.budget - 1)) helper.budget = GNCIF_NUM_PERIOD;
691 qif_object_map_foreach(ctx, QIF_O_CATEGORY, qif_parse_parse_category, &helper);
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;
701 qif_object_list_foreach(ctx, QIF_O_TXN, qif_parse_check_txn, &helper);
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;
711 if (helper.date & (helper.date - 1))
713 helper.date = gnc_import_choose_fmt(_(
"The Date format is ambiguous. "
714 "Please choose the correct format."),
719 qif_object_list_foreach(ctx, QIF_O_TXN, qif_parse_parse_txn, &helper);
730 qif_merge_accts(gpointer key, gpointer value, gpointer data)
736 if (qif_account_merge(merge->ctx, acct) == acct)
737 merge->list = g_list_prepend(merge->list, acct->name);
741 qif_merge_cats(gpointer key, gpointer value, gpointer data)
747 if (qif_cat_merge(merge->ctx, cat) == cat)
748 merge->list = g_list_prepend(merge->list, cat->name);
752 qif_merge_classes(gpointer key, gpointer value, gpointer data)
758 if (qif_class_merge(merge->ctx, qclass) == qclass)
759 merge->list = g_list_prepend(merge->list, qclass->name);
763 qif_merge_secs(gpointer key, gpointer value, gpointer data)
769 if (qif_security_merge(merge->ctx, sec) == sec)
770 merge->list = g_list_prepend(merge->list, sec->name);
774 qif_merge_del(gpointer obj, gpointer data)
777 const char *name = obj;
779 qif_object_map_remove(merge->ctx, merge->type, name);
785 const char *type = QIF_O_CATEGORY;
790 if (split->cat_is_acct)
792 type = QIF_O_ACCOUNT;
793 name = split->cat.acct->name;
796 name = split->cat.cat->name;
798 split->cat.obj = qif_object_map_lookup(ctx, type, name);
801 if (split->cat_class)
803 split->cat_class = (
QifClass) qif_object_map_lookup(ctx, QIF_O_CLASS,
804 split->cat_class->name);
811 const char *type = QIF_O_CATEGORY;
814 if (itxn->far_cat.obj)
816 if (itxn->far_cat_is_acct)
818 type = QIF_O_ACCOUNT;
819 name = itxn->far_cat.acct->name;
822 name = itxn->far_cat.cat->name;
824 itxn->far_cat.obj = qif_object_map_lookup(ctx, type, name);
829 qif_massage_txn(gpointer obj, gpointer data)
837 txn->from_acct = (
QifAccount) qif_object_map_lookup(ctx, QIF_O_ACCOUNT,
838 txn->from_acct->name);
841 qif_massage_itxn(txn->invst_info, ctx);
843 if (txn->default_split)
844 qif_massage_split(txn->default_split, ctx);
846 for (node = txn->splits; node; node = node->next)
849 qif_massage_split(split, ctx);
859 GList *classes = NULL;
860 GList *securities = NULL;
865 g_return_if_fail(ctx);
871 for (node = ctx->files; node; node = node->next)
874 g_return_if_fail(fctx->parsed);
885 for (node = ctx->files; node; node = node->next)
893 qif_object_map_foreach(fctx, QIF_O_ACCOUNT, qif_merge_accts, &merge);
897 qif_object_map_foreach(fctx, QIF_O_CATEGORY, qif_merge_cats, &merge);
901 qif_object_map_foreach(fctx, QIF_O_CLASS, qif_merge_classes, &merge);
902 classes = merge.list;
905 qif_object_map_foreach(fctx, QIF_O_SECURITY, qif_merge_secs, &merge);
906 securities = merge.list;
910 qif_object_list_foreach(fctx, QIF_O_TXN, qif_massage_txn, ctx);
915 merge.type = QIF_O_ACCOUNT;
916 g_list_foreach(accts, qif_merge_del, &merge);
919 merge.type = QIF_O_CATEGORY;
920 g_list_foreach(cats, qif_merge_del, &merge);
923 merge.type = QIF_O_CLASS;
924 g_list_foreach(classes, qif_merge_del, &merge);
925 g_list_free(classes);
927 merge.type = QIF_O_SECURITY;
928 g_list_foreach(securities, qif_merge_del, &merge);
929 g_list_free(securities);
utility functions for the GnuCash UI
#define PERR(format, args...)
#define PWARN(format, args...)
All type declarations for the whole Gnucash engine.
const gchar * QofLogModule