gnucash maint: Remove abandoned C-language QIF implementation.
John Ralls
jralls at code.gnucash.org
Fri Jun 15 12:34:48 EDT 2018
Updated via https://github.com/Gnucash/gnucash/commit/edd439a0 (commit)
from https://github.com/Gnucash/gnucash/commit/55400160 (commit)
commit edd439a05e1468b1f55d0df7c05441b67aac8787
Author: John Ralls <jralls at ceridwen.us>
Date: Fri Jun 15 09:30:31 2018 -0700
Remove abandoned C-language QIF implementation.
diff --git a/gnucash/import-export/CMakeLists.txt b/gnucash/import-export/CMakeLists.txt
index 3b52ed8..cca8359 100644
--- a/gnucash/import-export/CMakeLists.txt
+++ b/gnucash/import-export/CMakeLists.txt
@@ -10,7 +10,6 @@ add_subdirectory(csv-imp)
add_subdirectory(customer-import)
add_subdirectory(log-replay)
add_subdirectory(ofx)
-add_subdirectory(qif)
add_subdirectory(qif-imp)
diff --git a/gnucash/import-export/qif-imp/assistant-qif-import.c b/gnucash/import-export/qif-imp/assistant-qif-import.c
index 21f3e74..e424182 100644
--- a/gnucash/import-export/qif-imp/assistant-qif-import.c
+++ b/gnucash/import-export/qif-imp/assistant-qif-import.c
@@ -59,6 +59,7 @@
#include "gnc-prefs.h"
#include "gnc-ui.h"
#include "guile-mappings.h"
+#include <gfec.h>
#include "swig-runtime.h"
@@ -1067,6 +1068,12 @@ gnc_ui_qif_import_commodity_update(QIFImportWindow * wind)
}
}
+static void
+_gfec_error_handler(const char *message)
+{
+ PERR("qif-import:qif-to-gnc-undo encountered an error: %s", message);
+}
+
/****************************************************************
* gnc_ui_qif_import_convert_undo
@@ -1082,7 +1089,7 @@ gnc_ui_qif_import_convert_undo(QIFImportWindow * wind)
gnc_set_busy_cursor(NULL, TRUE);
/* Undo the conversion. */
- scm_call_1(undo, wind->imported_account_tree);
+ gfec_apply(undo, wind->imported_account_tree, _gfec_error_handler);
/* There's no imported account tree any more. */
scm_gc_unprotect_object(wind->imported_account_tree);
diff --git a/gnucash/import-export/qif-imp/qif-to-gnc.scm b/gnucash/import-export/qif-imp/qif-to-gnc.scm
index 5f7e3f1..442cb47 100644
--- a/gnucash/import-export/qif-imp/qif-to-gnc.scm
+++ b/gnucash/import-export/qif-imp/qif-to-gnc.scm
@@ -910,7 +910,9 @@
;; this is the grind loop. Go over every unmarked transaction in
;; the candidate-xtns list.
(let xtn-loop ((xtns candidate-xtns))
- (if (and (not (qif-xtn:mark (car xtns)))
+ (if (and (and
+ (and far-acct-name near acct-name)
+ (not (qif-xtn:mark (car xtns))))
(string=? (qif-xtn:from-acct (car xtns)) far-acct-name))
(begin
(set! how
diff --git a/gnucash/import-export/qif/CMakeLists.txt b/gnucash/import-export/qif/CMakeLists.txt
deleted file mode 100644
index 608e14c..0000000
--- a/gnucash/import-export/qif/CMakeLists.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-
-#Tests for this directory are not run.
-add_subdirectory(test)
-
-set(qif_SOURCES
- qif-context.c
- qif-defaults.c
- qif-file.c
- qif-objects.c
- qif-parse.c
-)
-
-# Add dependency on config.h
-set_source_files_properties (${qif_SOURCES} PROPERTIES OBJECT_DEPENDS ${CONFIG_H})
-
-set(qif_noinst_HEADERS
- qif-file.h
- qif-defaults.h
- qif-import-p.h
- qif-import.h
- qif-objects.h
- qif-objects-p.h
- qif-parse.h
-)
-
-add_library(gncmod-qif ${qif_noinst_HEADERS} ${qif_SOURCES})
-
-target_link_libraries(gncmod-qif gncmod-generic-import gncmod-engine ${GLIB2_LDFLAGS})
-
-target_compile_definitions(gncmod-qif PRIVATE -DG_LOG_DOMAIN=\"gnc.import.qif\")
-
-if (APPLE)
- set_target_properties (gncmod-qif PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_FULL_LIBDIR}/gnucash")
-endif()
-
-install(TARGETS gncmod-qif
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
-# No headers to install.
-
-set_local_dist(qif_DIST_local CMakeLists.txt ${qif_SOURCES} ${qif_noinst_HEADERS})
-set(qif_DIST ${qif_DIST_local} ${test_qif_DIST} PARENT_SCOPE)
diff --git a/gnucash/import-export/qif/qif-context.c b/gnucash/import-export/qif/qif-context.c
deleted file mode 100644
index 17fa472..0000000
--- a/gnucash/import-export/qif/qif-context.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * qif-context.c -- create/destroy QIF Contexts
- *
- * Written By: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-
-#include "qif-import-p.h"
-#include "qif-objects-p.h"
-
-static void qif_object_map_get_helper(gpointer key, gpointer value, gpointer listp);
-
-QifContext
-qif_context_new(void)
-{
- QifContext ctx = g_new0(struct _QifContext, 1);
-
- ctx->object_lists = g_hash_table_new(g_str_hash, g_str_equal);
- ctx->object_maps = g_hash_table_new(g_str_hash, g_str_equal);
-
- return ctx;
-}
-
-void
-qif_context_destroy(QifContext ctx)
-{
- GList *node, *temp;
- QifContext fctx;
-
- if (!ctx) return;
-
- /* First, try to destroy all the children contexts */
- for (node = ctx->files; node; node = temp)
- {
- fctx = node->data;
- temp = node->next;
- qif_context_destroy(fctx);
- }
-
- /* ok, at this point we're actually destroying this context. */
-
- /* force the end of record */
- if (ctx->handler && ctx->handler->end)
- ctx->handler->end(ctx);
-
- /* destroy the state objects */
- qif_object_list_destroy(ctx);
- qif_object_map_destroy(ctx);
-
- /* Remove us from our parent context */
- if (ctx->parent)
- ctx->parent->files = g_list_remove(ctx->parent->files, ctx);
-
- g_free(ctx->filename);
-
- g_assert(ctx->files == NULL);
- g_free(ctx);
-}
-
-static GList *
-qif_context_get_foo_helper(QifContext ctx, GFunc get_helper)
-{
- GHashTable *ht;
- GList *node, *list = NULL;
- QifContext fctx;
-
- g_return_val_if_fail(ctx, NULL);
- g_return_val_if_fail(ctx->parsed, NULL);
- g_return_val_if_fail(get_helper, NULL);
-
- ht = g_hash_table_new(g_direct_hash, g_direct_equal);
-
- for (node = ctx->files; node; node = node->next)
- {
- fctx = node->data;
- qif_object_list_foreach(fctx, QIF_O_TXN, get_helper, ht);
- }
-
- g_hash_table_foreach(ht, qif_object_map_get_helper, &list);
- g_hash_table_destroy(ht);
-
- return list;
-}
-
-static void
-qif_get_accts_helper(gpointer obj, gpointer htp)
-{
- QifTxn txn = obj;
- QifSplit split;
- GHashTable *ht = htp;
- GList *node;
-
- if (txn->from_acct)
- g_hash_table_insert(ht, txn->from_acct, txn->from_acct);
-
- /* The default_split is using the from_acct, so we can ignore it */
-
- for (node = txn->splits; node; node = node->next)
- {
- split = node->data;
- if (split->cat.obj && split->cat_is_acct)
- g_hash_table_insert(ht, split->cat.acct, split->cat.acct);
- }
-}
-
-GList *
-qif_context_get_accounts(QifContext ctx)
-{
- return qif_context_get_foo_helper(ctx, qif_get_accts_helper);
-}
-
-static void
-qif_get_cats_helper(gpointer obj, gpointer htp)
-{
- QifTxn txn = obj;
- QifSplit split;
- GHashTable *ht = htp;
- GList *node;
-
- /* default_split uses from_acct, so no categories */
-
- for (node = txn->splits; node; node = node->next)
- {
- split = node->data;
- if (split->cat.obj && !split->cat_is_acct)
- g_hash_table_insert(ht, split->cat.cat, split->cat.cat);
- }
-}
-
-GList *
-qif_context_get_categories(QifContext ctx)
-{
- return qif_context_get_foo_helper(ctx, qif_get_cats_helper);
-}
-
-/*****************************************************************************/
-
-/*
- * Insert and remove a QifObject from the Object Maps in this Qif Context
- */
-
-gint
-qif_object_map_count(QifContext ctx, const char *type)
-{
- GHashTable *ht;
-
- g_return_val_if_fail(ctx, 0);
- g_return_val_if_fail(ctx->object_maps, 0);
- g_return_val_if_fail(type, 0);
-
- ht = g_hash_table_lookup(ctx->object_maps, type);
- if (!ht)
- return 0;
-
- return g_hash_table_size(ht);
-}
-
-void
-qif_object_map_foreach(QifContext ctx, const char *type, GHFunc func, gpointer arg)
-{
- GHashTable *ht;
-
- g_return_if_fail(ctx);
- g_return_if_fail(ctx->object_maps);
- g_return_if_fail(type);
-
- ht = g_hash_table_lookup(ctx->object_maps, type);
- if (ht)
- g_hash_table_foreach(ht, func, arg);
-}
-
-void
-qif_object_map_insert(QifContext ctx, const char *key, QifObject obj)
-{
- GHashTable *ht;
-
- g_return_if_fail(ctx);
- g_return_if_fail(ctx->object_maps);
- g_return_if_fail(key);
- g_return_if_fail(obj);
- g_return_if_fail(obj->type);
-
- ht = g_hash_table_lookup(ctx->object_maps, obj->type);
- if (!ht)
- {
- ht = g_hash_table_new(g_str_hash, g_str_equal);
- g_assert(ht);
- g_hash_table_insert(ctx->object_maps, (gpointer)obj->type, ht);
- }
-
- g_hash_table_insert(ht, (gpointer)key, obj);
-}
-
-void
-qif_object_map_remove(QifContext ctx, const char *type, const char *key)
-{
- GHashTable *ht;
-
- g_return_if_fail(ctx);
- g_return_if_fail(ctx->object_maps);
- g_return_if_fail(type);
- g_return_if_fail(key);
-
- ht = g_hash_table_lookup(ctx->object_maps, type);
- if (!ht) return;
-
- g_hash_table_remove(ht, key);
-}
-
-QifObject
-qif_object_map_lookup(QifContext ctx, const char *type, const char *key)
-{
- GHashTable *ht;
-
- g_return_val_if_fail(ctx, NULL);
- g_return_val_if_fail(ctx->object_maps, NULL);
- g_return_val_if_fail(type, NULL);
- g_return_val_if_fail(key, NULL);
-
- ht = g_hash_table_lookup(ctx->object_maps, type);
- if (!ht) return NULL;
-
- return g_hash_table_lookup(ht, key);
-}
-
-/* This GList _SHOULD_ be freed by the caller */
-
-static void
-qif_object_map_get_helper(gpointer key, gpointer value, gpointer arg)
-{
- GList **listp = arg;
- g_return_if_fail(listp);
-
- *listp = g_list_prepend(*listp, value);
-}
-
-GList *
-qif_object_map_get(QifContext ctx, const char *type)
-{
- GHashTable *ht;
- GList *list = NULL;
-
- g_return_val_if_fail(ctx, NULL);
- g_return_val_if_fail(ctx->object_maps, NULL);
- g_return_val_if_fail(type, NULL);
-
- ht = g_hash_table_lookup(ctx->object_maps, type);
- if (!ht)
- return NULL;
-
- g_hash_table_foreach(ht, qif_object_map_get_helper, &list);
-
- return list;
-}
-
-static gboolean
-qif_object_map_remove_each(gpointer key, gpointer value, gpointer arg)
-{
- QifObject obj = value;
- obj->destroy(obj);
- return TRUE;
-}
-
-static gboolean
-qif_object_map_remove_all(gpointer key, gpointer value, gpointer arg)
-{
- GHashTable *ht = value;
-
- g_hash_table_foreach_remove(ht, qif_object_map_remove_each, NULL);
- g_hash_table_destroy(ht);
- return TRUE;
-}
-
-void qif_object_map_destroy(QifContext ctx)
-{
- g_return_if_fail(ctx);
- g_return_if_fail(ctx->object_maps);
-
- g_hash_table_foreach_remove(ctx->object_maps, qif_object_map_remove_all, NULL);
- g_hash_table_destroy(ctx->object_maps);
-}
-
-/*****************************************************************************/
-
-/*
- * Insert and remove a QifObject from the Object Lists in this Qif Context
- */
-
-void
-qif_object_list_reverse(QifContext ctx, const char *type)
-{
- GList *list;
-
- g_return_if_fail(ctx);
- g_return_if_fail(ctx->object_lists);
- g_return_if_fail(type);
-
- list = qif_object_list_get(ctx, type);
- list = g_list_reverse(list);
- g_hash_table_insert(ctx->object_lists, (gpointer)type, list);
-}
-
-gint
-qif_object_list_count(QifContext ctx, const char *type)
-{
- GList *list;
-
- g_return_val_if_fail(ctx, 0);
- g_return_val_if_fail(ctx->object_lists, 0);
- g_return_val_if_fail(type, 0);
-
- list = g_hash_table_lookup(ctx->object_lists, type);
- return g_list_length(list);
-}
-
-void
-qif_object_list_foreach(QifContext ctx, const char *type, GFunc func, gpointer arg)
-{
- GList *list;
-
- g_return_if_fail(ctx);
- g_return_if_fail(ctx->object_lists);
- g_return_if_fail(type);
-
- list = qif_object_list_get(ctx, type);
- g_list_foreach(list, func, arg);
-}
-
-void
-qif_object_list_insert(QifContext ctx, QifObject obj)
-{
- GList *list;
-
- g_return_if_fail(ctx);
- g_return_if_fail(ctx->object_lists);
- g_return_if_fail(obj);
- g_return_if_fail(obj->type && *obj->type);
-
- list = g_hash_table_lookup(ctx->object_lists, obj->type);
- list = g_list_prepend(list, obj);
- g_hash_table_insert(ctx->object_lists, (gpointer)obj->type, list);
-}
-
-void
-qif_object_list_remove(QifContext ctx, QifObject obj)
-{
- GList *list;
-
- g_return_if_fail(ctx);
- g_return_if_fail(ctx->object_lists);
- g_return_if_fail(obj);
- g_return_if_fail(obj->type && *obj->type);
-
- list = g_hash_table_lookup(ctx->object_lists, obj->type);
- list = g_list_remove(list, obj);
- g_hash_table_insert(ctx->object_lists, (gpointer)obj->type, list);
-}
-
-GList *
-qif_object_list_get(QifContext ctx, const char *type)
-{
- g_return_val_if_fail(ctx, NULL);
- g_return_val_if_fail(ctx->object_lists, NULL);
- g_return_val_if_fail(type, NULL);
-
- return g_hash_table_lookup(ctx->object_lists, type);
-}
-
-static gboolean
-qif_object_list_remove_all(gpointer key, gpointer value, gpointer arg)
-{
- GList *list = value;
- GList *node;
- QifObject obj;
-
- for (node = list; node; node = node->next)
- {
- obj = node->data;
- obj->destroy(obj);
- }
-
- g_list_free(list);
- return TRUE;
-}
-
-void
-qif_object_list_destroy(QifContext ctx)
-{
- g_return_if_fail(ctx);
- g_return_if_fail(ctx->object_lists);
-
- g_hash_table_foreach_remove(ctx->object_lists, qif_object_list_remove_all, NULL);
- g_hash_table_destroy(ctx->object_lists);
-}
diff --git a/gnucash/import-export/qif/qif-defaults.c b/gnucash/import-export/qif/qif-defaults.c
deleted file mode 100644
index e29c141..0000000
--- a/gnucash/import-export/qif/qif-defaults.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * qif-defaults.c -- QIF Defaults -- default accounts...
- *
- * Created by: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include "gnc-helpers.h"
-#include "qif-import-p.h"
-#include "qif-objects-p.h"
-#include "qif-defaults.h"
-
-
-static GList *stock_list = NULL;
-static GList *ext_stock_list = NULL;
-static GList *income_list = NULL;
-static GList *expense_list = NULL;
-static GList *equity_list = NULL;
-
-#define RETURN_ACCT(c,n,l) { if (stock_list == NULL) acct_type_init(); \
- return find_or_make_acct(c, n, l); \
-}
-
-static void
-acct_type_init(void)
-{
- stock_list = qif_parse_acct_type("__stock__", -1);
- ext_stock_list = qif_parse_acct_type("__extstock__", -1);
- income_list = qif_parse_acct_type("__income__", -1);
- expense_list = qif_parse_acct_type("__expense__", -1);
- equity_list = qif_parse_acct_type("__equity__", -1);
-}
-
-QifAccount qif_default_equity_acct(QifContext ctx)
-{
- char *name = g_strdup(_("Retained Earnings"));
- RETURN_ACCT(ctx, name, equity_list);
-}
-
-QifAccount qif_default_margin_interest_acct(QifContext ctx)
-{
- char *name = g_strdup_printf("%s%s%s", _("Margin Interest"),
- gnc_get_account_separator_string(),
- ctx->current_acct->name);
- RETURN_ACCT(ctx, name, expense_list);
-}
-
-QifAccount qif_default_commission_acct(QifContext ctx)
-{
- char *name = g_strdup_printf("%s%s%s", _("Commissions"),
- gnc_get_account_separator_string(),
- ctx->current_acct->name);
- RETURN_ACCT(ctx, name, expense_list);
-}
-
-QifAccount qif_default_stock_acct(QifContext ctx, const char *security)
-{
- char *name = g_strdup_printf("%s%s%s", ctx->current_acct->name,
- gnc_get_account_separator_string(),
- security);
- RETURN_ACCT(ctx, name, stock_list);
-}
-
-QifAccount qif_default_cglong_acct(QifContext ctx, const char *security)
-{
- char *name = g_strdup_printf("%s%s%s%s%s", _("Cap. gain (long)"),
- gnc_get_account_separator_string(),
- ctx->current_acct->name,
- gnc_get_account_separator_string(),
- security);
- RETURN_ACCT(ctx, name, income_list);
-}
-
-QifAccount qif_default_cgmid_acct(QifContext ctx, const char *security)
-{
- char *name = g_strdup_printf("%s%s%s%s%s", _("Cap. gain (mid)"),
- gnc_get_account_separator_string(),
- ctx->current_acct->name,
- gnc_get_account_separator_string(),
- security);
- RETURN_ACCT(ctx, name, income_list);
-}
-
-QifAccount qif_default_cgshort_acct(QifContext ctx, const char *security)
-{
- char *name = g_strdup_printf("%s%s%s%s%s", _("Cap. gain (short)"),
- gnc_get_account_separator_string(),
- ctx->current_acct->name,
- gnc_get_account_separator_string(),
- security);
- RETURN_ACCT(ctx, name, income_list);
-}
-
-QifAccount qif_default_dividend_acct(QifContext ctx, const char *security)
-{
- char *name = g_strdup_printf("%s%s%s%s%s", _("Dividends"),
- gnc_get_account_separator_string(),
- ctx->current_acct->name,
- gnc_get_account_separator_string(),
- security);
- RETURN_ACCT(ctx, name, income_list);
-}
-
-QifAccount qif_default_interest_acct(QifContext ctx, const char *security)
-{
- char *name = g_strdup_printf("%s%s%s%s%s", _("Interest"),
- gnc_get_account_separator_string(),
- ctx->current_acct->name,
- gnc_get_account_separator_string(),
- security);
- RETURN_ACCT(ctx, name, income_list);
-}
-
-QifAccount qif_default_capital_return_acct(QifContext ctx, const char *security)
-{
- char *name = g_strdup_printf("%s%s%s%s%s", _("Cap Return"),
- gnc_get_account_separator_string(),
- ctx->current_acct->name,
- gnc_get_account_separator_string(),
- security);
- RETURN_ACCT(ctx, name, income_list);
-}
-
-QifAccount qif_default_equity_holding(QifContext ctx, const char *security)
-{
- return qif_default_equity_acct(ctx);
-}
-
diff --git a/gnucash/import-export/qif/qif-defaults.h b/gnucash/import-export/qif/qif-defaults.h
deleted file mode 100644
index 30c6562..0000000
--- a/gnucash/import-export/qif/qif-defaults.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * qif-defaults.h -- QIF Defaults -- default accounts...
- *
- * Created by: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifndef QIF_DEFAULTS_H
-#define QIF_DEFAULTS_H
-
-#include "qif-objects.h"
-#include "qif-import.h"
-
-QifAccount qif_default_equity_acct(QifContext ctx);
-QifAccount qif_default_equity_holding(QifContext ctx, const char *security);
-
-QifAccount qif_default_margin_interest_acct(QifContext ctx);
-QifAccount qif_default_commission_acct(QifContext ctx);
-QifAccount qif_default_stock_acct(QifContext ctx, const char *security);
-QifAccount qif_default_cglong_acct(QifContext ctx, const char *security);
-QifAccount qif_default_cgmid_acct(QifContext ctx, const char *security);
-QifAccount qif_default_cgshort_acct(QifContext ctx, const char *security);
-QifAccount qif_default_dividend_acct(QifContext ctx, const char *security);
-QifAccount qif_default_interest_acct(QifContext ctx, const char *security);
-QifAccount qif_default_capital_return_acct(QifContext ctx, const char *security);
-
-#endif /* QIF_DEFAULTS_H */
diff --git a/gnucash/import-export/qif/qif-file.c b/gnucash/import-export/qif/qif-file.c
deleted file mode 100644
index 775f0da..0000000
--- a/gnucash/import-export/qif/qif-file.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * qif-file.c -- parse a QIF File into its pieces
- *
- * Written by: Derek Atkins <derek@@ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <string.h>
-
-#include "gnc-engine.h"
-
-#include "qif-import-p.h"
-#include "qif-objects-p.h"
-
-static QofLogModule log_module = GNC_MOD_IMPORT;
-
-
-static QifLine
-qif_make_line(const char* buf, gint lineno)
-{
- QifLine line;
- g_return_val_if_fail(buf && *buf, NULL);
-
- line = g_new0(struct _QifLine, 1);
- line->type = *buf;
- line->lineno = lineno;
- line->line = g_strdup(buf + 1);
-
- return line;
-}
-
-void
-qif_record_destroy(GList *record)
-{
- GList *node;
- QifLine line;
-
- for (node = record; node; node = node->next)
- {
- line = node->data;
- g_free(line->line);
- g_free(line);
- }
-
- g_list_free(record);
-}
-
-/* This returns a record, which is a bunch of QifLines, ending
- * with a line with just a '^'. If it finds a line that begins
- * with a !, then destroy the current record state, set the "found_bangtype",
- * and return NULL.
- */
-static GList *
-qif_make_record(QifContext ctx, char *buf, size_t bufsiz, gboolean *found_bangtype)
-{
- GList *record = NULL;
- QifLine line;
-
- g_return_val_if_fail(ctx, NULL);
- g_return_val_if_fail(buf, NULL);
- g_return_val_if_fail(found_bangtype, NULL);
-
- *found_bangtype = FALSE;
-
- while (fgets(buf, bufsiz, ctx->fp) != NULL)
- {
-
- /* increment the line number */
- ctx->lineno++;
-
- /* strip start/end whitespace */
- g_strstrip(buf);
-
- /* if there is nothing left in the string, ignore it */
- if (strlen(buf) == 0)
- continue;
-
- /* If this is a bangline, then set the flag, clear our state, and return NULL */
- if (*buf == '!')
- {
- *found_bangtype = TRUE;
- break;
- }
-
- /* See if this is an End of Record marker */
- if (*buf == '^')
- {
- /* Yep. If we've got a record then break and return ... */
- if (record)
- break;
- /* ... otherwise just continue reading (i.e. ignore empty records) */
- else
- continue;
- }
-
- /* otherwise, add the line to the list */
- line = qif_make_line(buf, ctx->lineno);
- if (line)
- record = g_list_prepend(record, line);
-
- /* and continue... */
- }
-
- /* If we found a bangtype, destroy anything we've collected */
- if (*found_bangtype)
- {
- if (record)
- PERR("error loading file: incomplete record at line %d", ctx->lineno);
-
- qif_record_destroy(record);
- record = NULL;
- }
-
- return g_list_reverse(record);
-}
-
-/* read a qif file and parse it, line by line
- * return QIF_E_OK on success or some other QIF Error.
- */
-static QifError
-qif_read_file(QifContext ctx, FILE *f)
-{
- char buf[BUFSIZ];
- GList *record;
- gboolean found_bang;
- QifError err = QIF_E_OK;
-
- g_return_val_if_fail(ctx, QIF_E_BADARGS);
- g_return_val_if_fail(f, QIF_E_BADARGS);
-
- ctx->fp = f;
- ctx->lineno = -1;
-
- do
- {
- found_bang = FALSE;
- record = qif_make_record(ctx, buf, sizeof(buf), &found_bang);
-
- /* If we got a record, process it */
- if (record)
- {
- if (!ctx->handler || !ctx->handler->parse_record)
- {
- PERR("Trying to process QIF record without a handler at %d", ctx->lineno);
- }
- else
- {
- err = ctx->handler->parse_record(ctx, record);
- }
-
- /* Now destroy it; we don't need it anymore */
- qif_record_destroy(record);
- }
-
- /* if we found a bangtype, process that */
- if (found_bang)
- {
- g_assert(*buf == '!');
-
- /* First, process the end of the last handler. This could possibly
- * merge items into the context or perform some other operation
- */
- if (ctx->handler && ctx->handler->end)
- {
- err = ctx->handler->end(ctx);
- if (err != QIF_E_OK)
- break;
- }
-
- /* Now process the bangtype (stored in buf) to set the new handler */
- qif_parse_bangtype(ctx, buf);
- }
-
- }
- while ((record || found_bang) && err == QIF_E_OK);
-
- /* Make sure to run any end processor */
- if (err == QIF_E_OK && ctx->handler && ctx->handler->end)
- err = ctx->handler->end(ctx);
-
- if (err == QIF_E_OK)
- qif_object_list_reverse(ctx, QIF_O_TXN);
-
- return err;
-}
-
-static QifError
-qif_import_file(QifContext ctx, const char *filename)
-{
- QifError err;
- FILE *fp;
-
- g_return_val_if_fail(ctx, QIF_E_BADARGS);
- g_return_val_if_fail(filename, QIF_E_BADARGS);
- g_return_val_if_fail(*filename, QIF_E_BADARGS);
-
- /* Open the file */
- fp = g_fopen(filename, "r");
- if (fp == NULL)
- return QIF_E_NOFILE;
-
- ctx->filename = g_strdup(filename);
-
- /* read the file */
- err = qif_read_file(ctx, fp);
-
- /* close the file */
- fclose(fp);
-
- return err;
-}
-
-
-QifContext
-qif_file_new(QifContext ctx, const char *filename)
-{
- QifContext fctx;
-
- g_return_val_if_fail(ctx, NULL);
- g_return_val_if_fail(filename, NULL);
-
- fctx = qif_context_new();
-
- /* we should assume that we've got a bank account... just in case.. */
- qif_parse_bangtype(fctx, "!type:bank");
-
- /* Open the file */
- if (qif_import_file(fctx, filename) != QIF_E_OK)
- {
- qif_context_destroy(fctx);
- fctx = NULL;
- }
-
- /* Return the new context */
- if (fctx)
- {
- ctx->files = g_list_prepend(ctx->files, fctx);
- fctx->parent = ctx;
-
- /* Make sure the file gets merged into the parent */
- ctx->parsed = FALSE;
- }
-
- return fctx;
-}
-
-QifError
-qif_file_parse(QifContext ctx, gpointer ui_args)
-{
- g_return_val_if_fail(ctx, QIF_E_BADARGS);
- g_return_val_if_fail(!qif_file_needs_account(ctx), QIF_E_BADSTATE);
-
- qif_parse_all(ctx, ui_args);
- ctx->parsed = TRUE;
-
- return QIF_E_OK;
-}
-
-gboolean
-qif_file_needs_account(QifContext ctx)
-{
- g_return_val_if_fail(ctx, FALSE);
-
- return ((ctx->parse_flags & QIF_F_TXN_NEEDS_ACCT) ||
- (ctx->parse_flags & QIF_F_ITXN_NEEDS_ACCT));
-}
-
-const char *
-qif_file_filename(QifContext ctx)
-{
- g_return_val_if_fail(ctx, NULL);
- return ctx->filename;
-}
-
-static void
-set_txn_acct(gpointer obj, gpointer arg)
-{
- QifTxn txn = obj;
- QifAccount acct = arg;
-
- if (!txn->from_acct)
- txn->from_acct = acct;
-}
-
-void
-qif_file_set_default_account(QifContext ctx, const char *acct_name)
-{
- QifAccount acct;
-
- g_return_if_fail(ctx);
- g_return_if_fail(acct_name);
-
- if (! qif_file_needs_account(ctx)) return;
-
- acct = find_or_make_acct(ctx, g_strdup(acct_name),
- qif_parse_acct_type_guess(ctx->parse_type));
-
- qif_object_list_foreach(ctx, QIF_O_TXN, set_txn_acct, acct);
-
- qif_clear_flag(ctx->parse_flags, QIF_F_TXN_NEEDS_ACCT);
- qif_clear_flag(ctx->parse_flags, QIF_F_ITXN_NEEDS_ACCT);
-}
diff --git a/gnucash/import-export/qif/qif-file.h b/gnucash/import-export/qif/qif-file.h
deleted file mode 100644
index c4b85f1..0000000
--- a/gnucash/import-export/qif/qif-file.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* qif-import-p.h -- a QIF Importer module (private headers)
- *
- * Written By: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifndef QIF_FILE_H
-#define QIF_FILE_H
-
-struct _QifLine
-{
- char type;
- gint lineno;
- char * line;
-};
-
-void qif_record_destroy(GList *record);
-
-#endif /* QIF_FILE_H */
diff --git a/gnucash/import-export/qif/qif-import-p.h b/gnucash/import-export/qif/qif-import-p.h
deleted file mode 100644
index 96c6314..0000000
--- a/gnucash/import-export/qif/qif-import-p.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* qif-import-p.h -- a QIF Importer module (private headers)
- *
- * Written By: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifndef QIF_IMPORT_P_H
-#define QIF_IMPORT_P_H
-
-#include "qif-import.h"
-#include "qif-objects.h"
-#include "qif-parse.h"
-#include "qif-file.h"
-
-#include <stdio.h>
-
-struct _QifHandler
-{
- void (*init)(QifContext ctx);
- QifError (*parse_record)(QifContext ctx, GList *record);
- QifError (*end)(QifContext ctx);
-};
-
-struct _QifContext
-{
- /* The parent context */
- QifContext parent;
-
- /* file information */
- char * filename;
- FILE * fp;
- gint lineno;
-
- /* This describes what we are parsing right now */
- QifType parse_type;
- QifHandler handler;
- gpointer parse_state;
-
- /* A bunch of flags for the current handler */
- gint parse_flags;
- gboolean parsed;
-
- /* The current and "opening balance" account */
- QifAccount current_acct;
- QifAccount opening_bal_acct;
-
- /* HashTable of Maps of data objects */
- GHashTable * object_maps;
-
- /* HashTable of Lists of data objects */
- GHashTable * object_lists;
-
- /* List of files */
- GList *files;
-};
-
-/* Object Maps */
-gint qif_object_map_count(QifContext ctx, const char *type);
-void qif_object_map_foreach(QifContext ctx, const char *type,
- GHFunc func, gpointer arg);
-void qif_object_map_insert(QifContext ctx, const char *key, QifObject obj);
-void qif_object_map_remove(QifContext ctx, const char *type, const char *key);
-QifObject qif_object_map_lookup(QifContext ctx, const char *type, const char *key);
-void qif_object_map_destroy(QifContext ctx);
-/* GList _SHOULD_ be freed by the caller */
-GList * qif_object_map_get(QifContext ctx, const char *type);
-
-/* Object Lists */
-void qif_object_list_reverse(QifContext ctx, const char *type);
-gint qif_object_list_count(QifContext ctx, const char *type);
-void qif_object_list_foreach(QifContext ctx, const char *type,
- GFunc func, gpointer arg);
-void qif_object_list_insert(QifContext ctx, QifObject obj);
-void qif_object_list_remove(QifContext ctx, QifObject obj);
-void qif_object_list_destroy(QifContext ctx);
-/* GList should NOT be freed by the caller */
-GList *qif_object_list_get(QifContext ctx, const char *type);
-
-/* Set and clear flags in bit-flags */
-#define qif_set_flag(i,f) (i |= f)
-#define qif_clear_flag(i,f) (i &= ~f)
-
-#endif /* QIF_IMPORT_P_H */
diff --git a/gnucash/import-export/qif/qif-import.h b/gnucash/import-export/qif/qif-import.h
deleted file mode 100644
index 9602029..0000000
--- a/gnucash/import-export/qif/qif-import.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * qif-import.h -- a QIF Import module
- *
- * Written By: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifndef QIF_IMPORT_H
-#define QIF_IMPORT_H
-
-#include <stdio.h>
-#include "qof.h"
-
-typedef enum
-{
- QIF_TYPE_BANK = 1,
- QIF_TYPE_CASH,
- QIF_TYPE_CCARD,
- QIF_TYPE_INVST,
- QIF_TYPE_PORT,
- QIF_TYPE_OTH_A,
- QIF_TYPE_OTH_L,
- QIF_TYPE_CLASS,
- QIF_TYPE_CAT,
- QIF_TYPE_SECURITY,
- QIF_ACCOUNT,
- QIF_AUTOSWITCH,
- QIF_CLEAR_AUTOSWITCH
-} QifType;
-
-/* Make sure this patches */
-#define QIF_TYPE_MAX QIF_CLEAR_AUTOSWITCH
-
-typedef struct _QifHandler *QifHandler;
-typedef struct _QifContext *QifContext;
-typedef struct _QifLine *QifLine;
-
-/* Qif Flags */
-#define QIF_F_IGNORE_ACCOUNTS (1 << 0)
-#define QIF_F_TXN_NEEDS_ACCT (1 << 1)
-#define QIF_F_ITXN_NEEDS_ACCT (1 << 2)
-
-/* Qif Reconciled Flag */
-typedef enum
-{
- QIF_R_NO = 0,
- QIF_R_CLEARED,
- QIF_R_RECONCILED,
- QIF_R_BUDGETED,
-} QifRecnFlag;
-
-/* Qif Errors */
-
-typedef enum
-{
- QIF_E_OK = 0,
- QIF_E_INTERNAL,
- QIF_E_BADSTATE,
- QIF_E_BADARGS,
- QIF_E_NOFILE,
-} QifError;
-
-
-/* Qif (investment?) Actions */
-typedef enum
-{
- QIF_A_NONE = 0,
- QIF_A_BUY,
- QIF_A_BUYX,
- QIF_A_CGLONG,
- QIF_A_CGLONGX,
- QIF_A_CGMID,
- QIF_A_CGMIDX,
- QIF_A_CGSHORT,
- QIF_A_CGSHORTX,
- QIF_A_DIV,
- QIF_A_DIVX,
- QIF_A_EXERCISE,
- QIF_A_EXERCISEX,
- QIF_A_EXPIRE,
- QIF_A_GRANT,
- QIF_A_INTINC,
- QIF_A_INTINCX,
- QIF_A_MARGINT,
- QIF_A_MARGINTX,
- QIF_A_MISCEXP,
- QIF_A_MISCEXPX,
- QIF_A_MISCINC,
- QIF_A_MISCINCX,
- QIF_A_REINVDIV,
- QIF_A_REINVINT,
- QIF_A_REINVLG,
- QIF_A_REINVMD,
- QIF_A_REINVSG,
- QIF_A_REINVSH,
- QIF_A_REMINDER,
- QIF_A_RTRNCAP,
- QIF_A_RTRNCAPX,
- QIF_A_SELL,
- QIF_A_SELLX,
- QIF_A_SHRSIN,
- QIF_A_SHRSOUT,
- QIF_A_STKSPLIT,
- QIF_A_VEST,
- QIF_A_XIN,
- QIF_A_XOUT,
-} QifAction;
-
-/* Public API Functions */
-
-/* Create a QIF Import Context */
-QifContext qif_context_new(void);
-void qif_context_destroy(QifContext ctx);
-
-/* Open and read a QIF File. You must pass in the parent
- * context; it will return the child (file) context
- */
-QifContext qif_file_new(QifContext ctx, const char* filename);
-
-/* Does a qif-file need a default QIF account? */
-gboolean qif_file_needs_account(QifContext ctx);
-
-/* Return the filename of the QIF file */
-const char * qif_file_filename(QifContext ctx);
-
-/* Provide a default QIF Account for the QIF File */
-void qif_file_set_default_account(QifContext ctx, const char *acct_name);
-
-/* Parse the QIF File */
-QifError qif_file_parse(QifContext ctx, gpointer ui_arg);
-
-/* Merge all the qif-files from the children and into the context */
-void qif_parse_merge_files(QifContext ctx);
-
-/* Obtain the list of USED QifAccounts and QifCategories. Finds all
- * references from the transactions in the QifContext. The returned
- * GList must be freed by the caller.
- */
-GList *qif_context_get_accounts(QifContext ctx);
-GList *qif_context_get_categories(QifContext ctx);
-
-#endif /* QIF_IMPORT_H */
diff --git a/gnucash/import-export/qif/qif-objects-p.h b/gnucash/import-export/qif/qif-objects-p.h
deleted file mode 100644
index dbd3aa4..0000000
--- a/gnucash/import-export/qif/qif-objects-p.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * qif-objects-p.h -- Private header: QIF objects for the QIF importer
- *
- * Written By: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifndef QIF_OBJECTS_P_H
-#define QIF_OBJECTS_P_H
-
-#include "qof.h"
-
-#include "qif-import.h"
-#include "qif-objects.h"
-
-struct _QifAccount
-{
- struct _QifObject obj;
-
- char * name;
- char * desc;
-
- char * limitstr;
- gnc_numeric limit;
-
- char * budgetstr;
- gnc_numeric budget;
-
- GList * type_list;
-
-};
-
-struct _QifCategory
-{
- struct _QifObject obj;
-
- char * name;
- char * desc;
- char * taxclass;
-
- gboolean taxable;
- gboolean expense;
- gboolean income;
-
- char * budgetstr;
- gnc_numeric budget;
-
-};
-
-struct _QifClass
-{
- struct _QifObject obj;
-
- char * name;
- char * desc;
- char * taxdesig;
-
-};
-
-struct _QifSecurity
-{
- struct _QifObject obj;
-
- char * name;
- char * symbol;
- char * type;
-
-};
-
-struct _QifTxn
-{
- struct _QifObject obj;
-
- QifType txn_type;
-
- char * datestr;
- Timespec date;
-
- char * payee;
- char * address;
- char * num;
-
- QifRecnFlag cleared;
-
- /* Investment info */
- QifInvstTxn invst_info;
-
- /* The default_split is the default (forward) part of the QIF transaction */
- QifSplit default_split;
-
- /* The current_split (if any) defines the current "qif split" we are handling */
- QifSplit current_split;
-
- /* The "from" account */
- QifAccount from_acct;
-
- /* The list of splits for this txn */
- GList * splits;
-
-};
-
-struct _QifSplit
-{
- char * memo;
-
- char * amountstr;
- gnc_numeric amount;
- gnc_numeric value;
-
- char * catstr;
-
- /* parsed category/account info */
-
- union
- {
- QifObject obj;
- QifCategory cat;
- QifAccount acct;
- } cat;
- gboolean cat_is_acct;
- QifClass cat_class;
-
-};
-
-struct _QifInvstTxn
-{
- QifAction action;
-
- gnc_numeric amount;
- gnc_numeric d_amount;
- gnc_numeric price;
- gnc_numeric shares;
- gnc_numeric commission;
-
- char * amountstr;
- char * d_amountstr;
- char * pricestr;
- char * sharesstr;
- char * commissionstr;
-
- char * security;
- char * catstr;
-
- union
- {
- QifObject obj;
- QifCategory cat;
- QifAccount acct;
- } far_cat;
- gboolean far_cat_is_acct;
-};
-
-/* to be run after parsing all the dates and amounts */
-void qif_txn_setup_splits(QifTxn txn);
-void qif_invst_txn_setup_splits(QifContext ctx, QifTxn txn);
-
-#endif /* QIF_OBJECTS_P_H */
diff --git a/gnucash/import-export/qif/qif-objects.c b/gnucash/import-export/qif/qif-objects.c
deleted file mode 100644
index 0fad928..0000000
--- a/gnucash/import-export/qif/qif-objects.c
+++ /dev/null
@@ -1,1468 +0,0 @@
-/*
- * qif-objects.c -- Objects for the QIF Importer
- *
- * Written by: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <string.h>
-#include "Account.h"
-
-#include "gnc-engine.h"
-
-#include "qif-import-p.h"
-#include "qif-objects-p.h"
-#include "qif-defaults.h"
-
-static QofLogModule log_module = GNC_MOD_IMPORT;
-
-/* create a new object of type t, with type-string type and
- * destroy function dest. Requires 'obj' to be set.
- */
-#define qif_object_new(t,typ,dest) ({ \
- obj = (QifObject) g_new0(t, 1); \
- obj->type = typ; \
- obj->destroy = dest; \
- obj; \
-})
-
-/* Save the string from this "line". Also:
- * - make sure we're not over-writing anything.
- * - make sure the 'line' object no longer references the string.
- */
-#define qif_save_str(var) { \
- if (var) { \
- PERR("duplicate found at line %d: %s", line->lineno, line->line); \
- g_free(var); \
- } \
- (var) = line->line; \
- line->line = NULL; \
-}
-
-/* QIF Account */
-static void
-qif_account_destroy(QifObject obj)
-{
- QifAccount acct = (QifAccount) obj;
-
- g_free(acct->name);
- g_free(acct->desc);
- g_free(acct->limitstr);
- g_free(acct->budgetstr);
-
- g_free(acct);
-};
-
-static QifAccount
-qif_account_new(void)
-{
- QifObject obj;
- QifAccount acct;
-
- obj = qif_object_new(struct _QifAccount, QIF_O_ACCOUNT, qif_account_destroy);
-
- acct = (QifAccount)obj;
- acct->type_list = qif_parse_acct_type("bank", -1);
-
- acct->limit = gnc_numeric_zero();
- acct->budget = gnc_numeric_zero();
- return acct;
-}
-
-/*
- * Merge acct into ctx. If this account already exists in ctx then
- * merge in any new values from acct into the ctx version and return
- * the existing acct. If the account does not already exist, then
- * insert it into the ctx and return it.
- */
-QifAccount
-qif_account_merge(QifContext ctx, QifAccount acct)
-{
- QifAccount acct2 =
- (QifAccount)qif_object_map_lookup(ctx, acct->obj.type, acct->name);
-
- if (!acct2)
- {
- qif_object_map_insert(ctx, acct->obj.type, (QifObject)acct);
- return acct;
- }
-
- /* obviously the name is the same, so don't worry about that */
-
- if (!acct2->desc && acct->desc)
- acct2->desc = g_strdup(acct->desc);
-
- if (!acct2->type_list && acct->type_list)
- acct2->type_list = acct->type_list;
-
- if (!acct2->limitstr && acct->limitstr)
- {
- acct2->limitstr = g_strdup(acct->limitstr);
- acct2->limit = acct->limit;
- }
-
- if (!acct2->budgetstr && acct->budgetstr)
- {
- acct2->budgetstr = g_strdup(acct->budgetstr);
- acct2->budget = acct->budget;
- }
-
- return acct2;
-}
-
-static QifError
-qif_account_parse(QifContext ctx, GList *record)
-{
- QifAccount acct, temp;
- QifLine line;
-
- g_return_val_if_fail(ctx, QIF_E_INTERNAL);
- g_return_val_if_fail(record, QIF_E_BADSTATE);
-
- acct = qif_account_new();
-
- for (; record; record = record->next)
- {
- line = record->data;
-
- switch (line->type)
- {
- case 'N': /* N : account name */
- qif_save_str(acct->name);
- break;
- case 'D': /* D : account description */
- qif_save_str(acct->desc);
- break;
- case 'T': /* T : account type */
- acct->type_list = qif_parse_acct_type(line->line, line->lineno);
- break;
- case 'L': /* L : account limit */
- qif_save_str(acct->limitstr);
- break;
- case 'B': /* B : account budget */
- qif_save_str(acct->budgetstr);
- break;
- default:
- PERR("Unknown QIF account data at line %d: %s", line->lineno, line->line);
- }
- }
-
- /* Merge the account into the context */
- temp = qif_account_merge(ctx, acct);
- if (! (ctx->parse_flags & QIF_F_IGNORE_ACCOUNTS))
- ctx->current_acct = temp;
- if (temp != acct)
- qif_account_destroy((QifObject)acct);
-
- return QIF_E_OK;
-}
-
-/* QIF Category */
-static void
-qif_cat_destroy(QifObject obj)
-{
- QifCategory cat = (QifCategory) obj;
-
- g_free(cat->name);
- g_free(cat->desc);
- g_free(cat->taxclass);
- g_free(cat->budgetstr);
-
- g_free(cat);
-}
-
-static QifCategory
-qif_cat_new(void)
-{
- QifObject obj;
- QifCategory cat;
-
- obj = qif_object_new(struct _QifCategory, QIF_O_CATEGORY, qif_cat_destroy);
- cat = (QifCategory)obj;
- cat->budget = gnc_numeric_zero();
-
- return cat;
-}
-
-/*
- * Merge cat into ctx. If this category already exists in ctx then
- * merge in any new values from cat into the ctx version and return
- * the existing cat. If the category does not already exist, then
- * insert it into the ctx and return it.
- */
-QifCategory
-qif_cat_merge(QifContext ctx, QifCategory cat)
-{
- QifCategory cat2 =
- (QifCategory)qif_object_map_lookup(ctx, cat->obj.type, cat->name);
-
- if (!cat2)
- {
- qif_object_map_insert(ctx, cat->obj.type, (QifObject)cat);
- return cat;
- }
-
- /* obviously the name is the same, so don't worry about that */
-
- if (!cat2->desc && cat->desc)
- cat2->desc = g_strdup(cat->desc);
-
- if (!cat2->taxclass && cat->taxclass)
- cat2->taxclass = g_strdup(cat->taxclass);
-
- cat2->taxable = (cat2->taxable || cat->taxable);
- cat2->expense = (cat2->expense || cat->expense);
- cat2->income = (cat2->income || cat->income);
-
- if (!cat2->budgetstr && cat->budgetstr)
- {
- cat2->budgetstr = g_strdup(cat->budgetstr);
- cat2->budget = cat->budget;
- }
-
- return cat2;
-}
-
-static QifError
-qif_cat_parse(QifContext ctx, GList *record)
-{
- QifCategory cat;
- QifLine line;
-
- g_return_val_if_fail(ctx, QIF_E_INTERNAL);
- g_return_val_if_fail(record, QIF_E_BADSTATE);
-
- cat = qif_cat_new();
-
- for (; record; record = record->next)
- {
- line = record->data;
-
- switch (line->type)
- {
- case 'N': /* N : category name */
- qif_save_str(cat->name);
- break;
- case 'D': /* D : category description */
- qif_save_str(cat->desc);
- break;
- case 'T': /* T : category is taxable? */
- cat->taxable = TRUE;
- break;
- case 'E': /* E : category is expense? */
- cat->expense = TRUE;
- break;
- case 'I': /* I : category is income? */
- cat->income = TRUE;
- break;
- case 'R': /* R : category taxclass XXX */
- /* XXX: a number? */
- qif_save_str(cat->taxclass);
- break;
- case 'B': /* B : category budget */
- qif_save_str(cat->budgetstr);
- break;
- default:
- PERR("Unknown QIF category data at line %d: %s", line->lineno, line->line);
- }
- }
-
- if (qif_cat_merge(ctx, cat) != cat)
- qif_cat_destroy((QifObject)cat);
-
- return QIF_E_OK;
-}
-
-/* QIF Class */
-static void
-qif_class_destroy(QifObject obj)
-{
- QifClass qclass = (QifClass) obj;
-
- g_free(qclass->name);
- g_free(qclass->desc);
- g_free(qclass->taxdesig);
-
- g_free(qclass);
-}
-
-static QifClass
-qif_class_new()
-{
- QifObject obj;
-
- obj = qif_object_new(struct _QifClass, QIF_O_CLASS, qif_class_destroy);
- return (QifClass)obj;
-}
-
-/*
- * Merge qclass into ctx. If this class already exists in ctx then
- * merge in any new values from qclass into the ctx version and return
- * the existing qclass. If the class does not already exist, then
- * insert it into the ctx and return it.
- */
-QifClass
-qif_class_merge(QifContext ctx, QifClass qclass)
-{
- QifClass qclass2 =
- (QifClass)qif_object_map_lookup(ctx, qclass->obj.type, qclass->name);
-
- if (!qclass2)
- {
- qif_object_map_insert(ctx, qclass->obj.type, (QifObject)qclass);
- return qclass;
- }
-
- /* obviously the name is the same, so don't worry about that */
-
- if (!qclass2->desc && qclass->desc)
- qclass2->desc = g_strdup(qclass->desc);
-
- if (!qclass2->taxdesig && qclass->taxdesig)
- qclass2->taxdesig = g_strdup(qclass->taxdesig);
-
- return qclass2;
-}
-
-static QifError
-qif_class_parse(QifContext ctx, GList *record)
-{
- QifClass qclass;
- QifLine line;
-
- g_return_val_if_fail(ctx, QIF_E_INTERNAL);
- g_return_val_if_fail(record, QIF_E_BADSTATE);
-
- qclass = qif_class_new();
-
- for (; record; record = record->next)
- {
- line = record->data;
-
- switch (line->type)
- {
- case 'N': /* N : class name */
- qif_save_str(qclass->name);
- break;
- case 'D': /* D : class description */
- qif_save_str(qclass->desc);
- break;
- case 'R': /* R : Tax designator */
- qif_save_str(qclass->taxdesig);
- break;
- default:
- PERR("Unknown QIF class data at line %d: %s", line->lineno, line->line);
- }
- }
-
- if (qif_class_merge(ctx, qclass) != qclass)
- qif_class_destroy((QifObject)qclass);
-
- return QIF_E_OK;
-}
-
-/* QIF Security Symbol */
-static void
-qif_security_destroy(QifObject obj)
-{
- QifSecurity security = (QifSecurity) obj;
-
- g_free(security->name);
- g_free(security->symbol);
- g_free(security->type);
-
- g_free(security);
-}
-
-static QifSecurity
-qif_security_new()
-{
- QifObject obj;
-
- obj = qif_object_new(struct _QifSecurity, QIF_O_SECURITY, qif_security_destroy);
- return (QifSecurity)obj;
-}
-
-/*
- * Merge security into ctx. If this security already exists in ctx then
- * merge in any new values from security into the ctx version and return
- * the existing security. If the security does not already exist, then
- * insert it into the ctx and return it.
- */
-QifSecurity
-qif_security_merge(QifContext ctx, QifSecurity security)
-{
- QifSecurity security2 =
- (QifSecurity)qif_object_map_lookup(ctx, security->obj.type, security->name);
-
- if (!security2)
- {
- qif_object_map_insert(ctx, security->obj.type, (QifObject)security);
- return security;
- }
-
- /* obviously the name is the same, so don't worry about that */
-
- if (!security2->symbol && security->symbol)
- security2->symbol = g_strdup(security->symbol);
-
- if (!security2->type && security->type)
- security2->type = g_strdup(security->type);
-
- return security2;
-}
-
-static QifError
-qif_security_parse(QifContext ctx, GList *record)
-{
- QifSecurity security;
- QifLine line;
-
- g_return_val_if_fail(ctx, QIF_E_INTERNAL);
- g_return_val_if_fail(record, QIF_E_BADSTATE);
-
- security = qif_security_new();
-
- for (; record; record = record->next)
- {
- line = record->data;
-
- switch (line->type)
- {
- case 'N': /* N : security name */
- qif_save_str(security->name);
- break;
- case 'S': /* S : security symbol */
- qif_save_str(security->symbol);
- break;
- case 'T': /* T : security type */
- qif_save_str(security->type);
- break;
- default:
- PERR("Unknown QIF security data at line %d: %s", line->lineno, line->line);
- }
- }
-
- if (qif_security_merge(ctx, security) != security)
- qif_security_destroy((QifObject)security);
-
- return QIF_E_OK;
-}
-
-/********************* TXN *********************/
-
-static QifSplit
-qif_split_new()
-{
- QifSplit split = g_new0(struct _QifSplit, 1);
-
- /* Initialize to 'zero' (even though they are not valid) */
- split->amount = gnc_numeric_zero();
- split->value = gnc_numeric_zero();
-
- return split;
-}
-
-static void
-qif_split_destroy(QifSplit split)
-{
- if (!split) return;
-
- g_free(split->memo);
- g_free(split->catstr);
- g_free(split->amountstr);
-
- g_free(split);
-}
-
-static QifSplit
-qif_split_copy(QifSplit split)
-{
- QifSplit s = qif_split_new();
-
- memcpy(s, split, sizeof(*s));
- if (s->memo) s->memo = g_strdup(s->memo);
- if (s->amountstr) s->amountstr = g_strdup(s->amountstr);
- if (s->catstr) s->memo = g_strdup(s->catstr);
-
- return s;
-}
-
-/* Forward declarations */
-static void qif_txn_invst_destroy(QifInvstTxn);
-
-/* QIF Transaction */
-
-static void
-qif_split_parse_category(QifContext ctx, QifSplit split)
-{
- char *cat = NULL;
- char *cat_class = NULL;
- char *miscx_cat = NULL;
- char *miscx_class = NULL;
-
- gboolean miscx_is_acct;
-
- static GList *types = NULL;
-
- g_return_if_fail(ctx);
- g_return_if_fail(split);
- g_return_if_fail(split->cat.cat == NULL && split->cat_class == NULL);
-
- if (qif_parse_split_category(split->catstr,
- &cat, &split->cat_is_acct, &cat_class,
- &miscx_cat, &miscx_is_acct, &miscx_class))
- {
- g_assert(cat);
-
- if (split->cat_is_acct)
- {
- if (types == NULL)
- types = qif_parse_acct_type("__any_bank__", -1);
-
- split->cat.acct = find_or_make_acct(ctx, cat, types);
-
- }
- else
- split->cat.cat = find_or_make_cat(ctx, cat);
-
- if (cat_class)
- split->cat_class = find_or_make_class(ctx, cat_class);
-
- /* miscx isn't used in a normal transaction, so just ignore it */
- if (miscx_cat)
- g_free(miscx_cat);
- if (miscx_class)
- g_free(miscx_class);
-
- }
- else
- PERR("Problem parsing split category: %s", split->catstr);
-}
-
-static void
-qif_txn_destroy(QifObject obj)
-{
- QifTxn txn = (QifTxn) obj;
- GList *node;
- QifSplit split;
-
- g_free(txn->datestr);
- g_free(txn->payee);
- g_free(txn->address);
- g_free(txn->num);
-
- if (txn->invst_info)
- qif_txn_invst_destroy(txn->invst_info);
-
- for (node = txn->splits; node; node = node->next)
- {
- split = node->data;
- if (split == txn->default_split)
- txn->default_split = NULL;
- if (split == txn->current_split)
- txn->current_split = NULL;
-
- qif_split_destroy(split);
- }
-
- g_list_free(txn->splits);
- qif_split_destroy(txn->default_split);
- qif_split_destroy(txn->current_split);
-
- g_free(txn);
-}
-
-static QifTxn
-qif_txn_new(void)
-{
- QifObject obj;
- QifTxn txn;
-
- obj = qif_object_new(struct _QifTxn, "qif-txn", qif_txn_destroy);
- txn = (QifTxn) obj;
- txn->default_split = qif_split_new();
-
- return txn;
-}
-
-static void
-qif_txn_init(QifContext ctx)
-{
- qif_clear_flag(ctx->parse_flags, QIF_F_IGNORE_ACCOUNTS);
- ctx->parse_state = NULL;
-}
-
-static gboolean
-qif_is_bad_numeric_string(const char* line)
-{
- return (strncmp(line, "...", 3) == 0);
-}
-
-/*
- * this is called for the first transaction after each !Type: tag.
- *
- * if the first transaction after a !Type: tag has a payee of "Opening
- * Balance" or "Initial Balance", we have to massage the transaction a
- * little. The meaning of an OB transaction is "transfer from Equity
- * to the account specified in the L line." Idiomatically, ms-money
- * and some others use this transaction instead of an Account record
- * to specify "this" account (the from-account for all following
- * transactions), so we have to allow for that.
- *
- * Even if the payee isn't "Opening Balance", we if we have no default
- * from-account by this time we need to set one. In that case we set
- * the default account based on the file name.
- *
- * If we DO know the account already, and this is a transfer to it,
- * it's also an opening balance regardless of the payee.
- *
- * In the end make sure that the context 'current account' is set.
- */
-static void
-qif_process_opening_balance_txn(QifContext ctx, QifTxn txn)
-{
- QifSplit split = txn->default_split;
- QifAccount cur_acct = NULL; /* We know that ctx->current_acct is NULL */
-
- g_return_if_fail(txn->invst_info == NULL);
-
- if ((!cur_acct && txn->payee &&
- (!strcasecmp(txn->payee, "Opening Balance") ||
- !strcasecmp(txn->payee, "Initial Balance")) && split->cat_is_acct) ||
- (cur_acct &&
- ((split->cat_is_acct && !strcasecmp(split->cat.acct->name, cur_acct->name))
- ||
- (!split->cat_is_acct && !strcasecmp(split->cat.cat->name, cur_acct->name))))
- )
- {
-
- /* This is an explicit "Opening Balance" transactions. We need to
- * change the "from account" to point to the equity account that
- * the opening balance comes from...
- */
- if (split->cat_is_acct)
- cur_acct = split->cat.acct;
- else
- {
- g_assert(split->cat.cat);
- cur_acct = find_or_make_acct(ctx, g_strdup(split->cat.cat->name),
- qif_parse_acct_type_guess(txn->txn_type));
- split->cat_is_acct = TRUE;
- }
- split->cat.acct = qif_default_equity_acct(ctx);
- }
-
- /*
- * If we found an opening balance account then set up the context.
- * If we didn't actually succeed in finding an account then
- * set a flag so we can go back later and look for it.
- */
-
- if (cur_acct)
- {
- ctx->opening_bal_acct = cur_acct;
- ctx->current_acct = cur_acct;
- }
- else
- qif_set_flag(ctx->parse_flags, QIF_F_TXN_NEEDS_ACCT);
-}
-
-/* process all the splits in the transaction -- if this is a "split
- * transaction" then make sure the sum of all the amounts (including
- * the default split) does NOT equal zero -- if it does then we want
- * to reverse all the splits. The "amount" should be the 'T' amount
- * from the txn.
- */
-static void
-qif_txn_fix_amounts(QifTxn txn, gnc_numeric amount)
-{
- gnc_numeric sum = amount;
- QifSplit split;
- GList *node;
-
- g_return_if_fail(txn);
-
- /* No current_split, so this is NOT a split transaction. */
- if (!txn->current_split) return;
-
- /* Then add in every split in the split-list */
- for (node = txn->splits; node; node = node->next)
- {
- split = node->data;
- sum = gnc_numeric_add(sum, split->amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
- }
-
- /* if the sum is not zero then reverse all the amounts in the split list */
- if (!gnc_numeric_zero_p(sum))
- for (node = txn->splits; node; node = node->next)
- {
- split = node->data;
- split->amount = gnc_numeric_neg(split->amount);
- }
-}
-
-static QifError
-qif_txn_parse(QifContext ctx, GList *record)
-{
- QifTxn txn;
- QifLine line;
- GList *node;
- QifSplit split;
-
- g_return_val_if_fail(ctx, QIF_E_INTERNAL);
- g_return_val_if_fail(record, QIF_E_BADSTATE);
-
- txn = qif_txn_new();
- txn->txn_type = ctx->parse_type;
-
- for (; record; record = record->next)
- {
- line = record->data;
-
- switch (line->type)
- {
- case 'D': /* D : transaction date */
- qif_save_str(txn->datestr);
- break;
- case 'P': /* P : payee */
- qif_save_str(txn->payee);
- break;
- case 'A': /* A : address */
- /* multiple 'A' lines are appended together with newlines */
- if (txn->address)
- {
- char *tmp = txn->address;
- txn->address = g_strconcat(tmp, "\n", line->line, NULL);
- g_free(tmp);
- }
- else
- qif_save_str(txn->address);
- break;
- case 'N': /* N : check/transaction number */
- qif_save_str(txn->num);
- break;
- case 'C': /* C : transaction cleared flag */
- txn->cleared = qif_parse_cleared(line);
- break;
- case 'L': /* L : default split category */
- if (!txn->current_split) qif_save_str(txn->default_split->catstr);
- break;
- case 'M': /* M : default split memo */
- if (!txn->current_split) qif_save_str(txn->default_split->memo);
- break;
- case 'T': /* T : total transaction amount */
- if (!txn->current_split && !qif_is_bad_numeric_string(line->line))
- qif_save_str(txn->default_split->amountstr);
- break;
- case 'S': /* S : split category */
- /* This implies a quicken-style "split transaction", so we're mostly
- * going to ignore the default_split except for internal verification.
- */
- txn->current_split = qif_split_new();
- txn->splits = g_list_prepend(txn->splits, txn->current_split);
- qif_save_str(txn->current_split->catstr);
- break;
- case 'E': /* E : split memo */
- if (txn->current_split)
- qif_save_str(txn->current_split->memo);
- break;
- case '$': /* split amount */
- if (txn->current_split && !qif_is_bad_numeric_string(line->line))
- qif_save_str(txn->current_split->amountstr);
- break;
- default:
- PERR("Unknown QIF transaction data at line %d: %s", line->lineno, line->line);
- }
- }
-
- /* If we have no date string then there is no reason to do anything else */
- if (txn->datestr)
- {
- /* We delay processing the date and amount strings until later.. */
-
- /* parse the category on each split */
- for (node = txn->splits; node; node = node->next)
- {
- split = node->data;
- if (split->catstr)
- qif_split_parse_category(ctx, split);
- }
- /* ... including the default split */
- if (txn->default_split->catstr)
- qif_split_parse_category(ctx, txn->default_split);
-
- /* if we don't have an account, then deal with the opening balance */
- if (!ctx->current_acct)
- qif_process_opening_balance_txn(ctx, txn);
-
- /* Set the transaction's from account */
- txn->from_acct = ctx->current_acct;
-
- /* And add it to the process list */
- ctx->parse_state = g_list_prepend(ctx->parse_state, txn);
-
- }
- else
- /* no date? Ignore this txn */
- qif_txn_destroy((QifObject)txn);
-
- return QIF_E_OK;
-}
-
-/* after we parse the amounts, fix up the transaction splits */
-void
-qif_txn_setup_splits(QifTxn txn)
-{
- QifSplit split, this_split;
- GList *node;
- gnc_numeric total;
-
- if (txn->splits)
- {
- /* We have a bunch of "far" splits -- maybe fix up the totals.. */
- qif_txn_fix_amounts(txn, txn->default_split->amount);
-
- /* Re-Compute the total for the "near" (default) split */
- total = gnc_numeric_zero();
- for (node = txn->splits; node; node = node->next)
- {
- split = node->data;
- split->value = split->amount;
- total = gnc_numeric_add(total, split->amount, 0, GNC_HOW_DENOM_LCD);
- }
-
- /* And re-set the default-split amount */
- txn->default_split->amount = gnc_numeric_neg(total);
-
- }
- else
- {
- /* not a split txn. Compute the "far" split by copying the "near"
- * split and then moving the 'near' split to the far split.
- */
-
- /* First make a copy of this transaction and move the copy to the 'near' */
- split = txn->default_split;
- this_split = qif_split_copy(split);
- txn->default_split = this_split;
-
- /* then adjust the 'far' txn */
- split->amount = gnc_numeric_neg(split->amount);
- split->value = split->amount;
- txn->splits = g_list_prepend(txn->splits, split);
- }
-
- /* Set the default-split value from the default-split amount */
- txn->default_split->value = txn->default_split->amount;
-}
-
-/* This is called when we're done processing an account. We want
- * to merge the transactions in the "parse_state" into the Qif Context
- */
-static QifError
-qif_txn_end_acct(QifContext ctx)
-{
- GList *node;
- QifTxn txn;
- gboolean txn_needs_acct;
-
- g_return_val_if_fail(ctx, QIF_E_INTERNAL);
-
- /* Return now if there is nothing to do. */
- if (!ctx->parse_state) return QIF_E_OK;
-
- /* Walk through the list of transactions. First check if it
- * needs a from-account; then add it to the context.
- */
-
- txn_needs_acct = (ctx->parse_flags & QIF_F_TXN_NEEDS_ACCT);
-
- /* Invert the list so we're working in the right order */
- ctx->parse_state = g_list_reverse(ctx->parse_state);
-
- for (node = ctx->parse_state; node; node = node->next)
- {
- txn = node->data;
-
- /* If we need a from account, then set it.. */
- if (txn_needs_acct && ctx->opening_bal_acct && !txn->from_acct)
- txn->from_acct = ctx->opening_bal_acct;
-
- /* merge the txn into the context (prepends to the list) */
- qif_object_list_insert(ctx, (QifObject)txn);
- }
-
- if (txn_needs_acct && ctx->opening_bal_acct)
- qif_clear_flag(ctx->parse_flags, QIF_F_TXN_NEEDS_ACCT);
-
- /* clean up our state */
- g_list_free(ctx->parse_state);
- ctx->parse_state = NULL;
-
- return QIF_E_OK;
-}
-
-/* Extra info in an Investment Transaction */
-static QifInvstTxn
-qif_invst_txn_new(void)
-{
- QifInvstTxn itxn = g_new0(struct _QifInvstTxn, 1);
-
- itxn->amount = gnc_numeric_zero();
- itxn->d_amount = gnc_numeric_zero();
- itxn->price = gnc_numeric_zero();
- itxn->shares = gnc_numeric_zero();
- itxn->commission = gnc_numeric_zero();
-
- return itxn;
-}
-
-static void
-qif_txn_invst_destroy(QifInvstTxn itxn)
-{
- if (!itxn) return;
-
- g_free(itxn->amountstr);
- g_free(itxn->d_amountstr);
- g_free(itxn->pricestr);
- g_free(itxn->sharesstr);
- g_free(itxn->commissionstr);
- g_free(itxn->security);
-
- g_free(itxn->catstr);
-
- g_free(itxn);
-}
-
-static QifError
-qif_txn_invst_parse(QifContext ctx, GList *record)
-{
- QifTxn txn;
- QifInvstTxn itxn;
- QifLine line;
-
- g_return_val_if_fail(ctx, QIF_E_INTERNAL);
- g_return_val_if_fail(record, QIF_E_BADSTATE);
-
- txn = qif_txn_new();
- txn->txn_type = ctx->parse_type;
- itxn = qif_invst_txn_new();
- txn->invst_info = itxn;
-
- for (; record; record = record->next)
- {
- line = record->data;
-
- switch (line->type)
- {
- case 'D': /* D : transaction date */
- qif_save_str(txn->datestr);
- break;
- case 'P': /* P : txn payee */
- qif_save_str(txn->payee);
- break;
- case 'N': /* N : action */
- itxn->action = qif_parse_action(line);
- break;
- case 'C': /* C : cleared flag */
- txn->cleared = qif_parse_cleared(line);
- break;
- case 'M': /* M : memo */
- if (!txn->current_split)
- qif_save_str(txn->default_split->memo);
- break;
- case 'T': /* T : total amount */
- if (!qif_is_bad_numeric_string(line->line))
- qif_save_str(itxn->amountstr);
- break;
- case '$': /* $ : transfer amount */
- if (!qif_is_bad_numeric_string(line->line))
- qif_save_str(itxn->d_amountstr);
- break;
- case 'I': /* I : share price */
- qif_save_str(itxn->pricestr);
- break;
- case 'Q': /* Q : number of shares */
- qif_save_str(itxn->sharesstr);
- break;
- case 'Y': /* Y : name of security */
- qif_save_str(itxn->security);
- break;
- case 'O': /* O : commission */
- qif_save_str(itxn->commissionstr);
- break;
- case 'L': /* L : category */
- qif_save_str(itxn->catstr);
- break;
- default:
- PERR("Unknown QIF Investment transaction data at line %d: %s",
- line->lineno, line->line);
- }
- }
-
- /* If we have no date string then there is no reason to do anything else */
- if (txn->datestr && itxn->action != QIF_A_NONE)
- {
-
- /* Make sure we've got a security name */
- if (!itxn->security)
- itxn->security = g_strdup(""); /* XXX */
-
- /* if we don't have a from account, then mark the fact that
- * we'll need one later.
- */
- if (ctx->current_acct)
- txn->from_acct = ctx->current_acct;
- else
- qif_set_flag(ctx->parse_flags, QIF_F_ITXN_NEEDS_ACCT);
-
- /* Add this transaction to the parse state for later processing */
- ctx->parse_state = g_list_prepend(ctx->parse_state, txn);
-
- }
- else
- {
- /* no date? Just destroy it */
- qif_txn_destroy((QifObject)txn);
- }
-
- return QIF_E_OK;
-}
-
-
-void
-qif_invst_txn_setup_splits(QifContext ctx, QifTxn txn)
-{
- QifInvstTxn itxn;
- QifSplit near_split, far_split, comm_split;
- QifAccount from_acct;
-
- char *cat = NULL;
- char *cat_class = NULL;
- gboolean cat_is_acct = FALSE;
- char *miscx = NULL;
- char *miscx_class = NULL;
- gboolean miscx_is_acct = FALSE;
-
- /* Cached account-type lists */
- static GList *bank_list = NULL;
-
- gnc_numeric split_value;
-
- g_return_if_fail(ctx);
- g_return_if_fail(txn);
- g_return_if_fail(txn->invst_info);
-
- itxn = txn->invst_info;
-
- /* Compute the share value, because we'll probably need it */
- split_value = gnc_numeric_mul(itxn->shares, itxn->price, 0, GNC_HOW_DENOM_REDUCE);
-
- /* Make sure that "amount" is a valid "transaction amount" */
- if (!itxn->amountstr && itxn->d_amountstr)
- itxn->amount = itxn->d_amount;
-
- /* near and far splits.. for simplicity */
- near_split = txn->default_split;
- far_split = qif_split_new();
- from_acct = txn->from_acct;
-
- /* Parse the category string */
- if (!qif_parse_split_category(itxn->catstr,
- &cat, &cat_is_acct, &cat_class,
- &miscx, &miscx_is_acct, &miscx_class))
- PERR("Failure parsing category: %s", itxn->catstr);
-
- /* Make sure we've got a cached list */
- if (bank_list == NULL)
- bank_list = qif_parse_acct_type("__any_bank__", -1);
-
- /* find the NEAR account */
-
- switch (itxn->action)
- {
- case QIF_A_BUY:
- case QIF_A_BUYX:
- case QIF_A_REINVDIV:
- case QIF_A_REINVINT:
- case QIF_A_REINVLG:
- case QIF_A_REINVMD:
- case QIF_A_REINVSG:
- case QIF_A_REINVSH:
- case QIF_A_SELL:
- case QIF_A_SELLX:
- case QIF_A_SHRSIN:
- case QIF_A_SHRSOUT:
- case QIF_A_STKSPLIT:
- txn->from_acct = qif_default_stock_acct(ctx, itxn->security);
- break;
-
- case QIF_A_CGLONG:
- case QIF_A_CGMID:
- case QIF_A_CGSHORT:
- case QIF_A_DIV:
- case QIF_A_INTINC:
- case QIF_A_MARGINT:
- case QIF_A_MISCEXP:
- case QIF_A_MISCINC:
- case QIF_A_RTRNCAP:
- case QIF_A_XIN:
- case QIF_A_XOUT:
- txn->from_acct = from_acct;
- break;
-
- case QIF_A_CGLONGX:
- case QIF_A_CGMIDX:
- case QIF_A_CGSHORTX:
- case QIF_A_DIVX:
- case QIF_A_INTINCX:
- case QIF_A_MARGINTX:
- case QIF_A_RTRNCAPX:
- txn->from_acct = find_or_make_acct(ctx, cat, bank_list);
- cat = NULL;
- break;
-
- case QIF_A_MISCEXPX:
- case QIF_A_MISCINCX:
- txn->from_acct = find_or_make_acct(ctx, miscx, bank_list);
- miscx = NULL;
- break;
-
- default:
- PERR("Unhandled Action: %d", itxn->action);
- break;
- }
-
- /* find the FAR account */
-
- itxn->far_cat_is_acct = TRUE;
- switch (itxn->action)
- {
- case QIF_A_BUY:
- case QIF_A_SELL:
- itxn->far_cat.acct = from_acct;
- break;
-
- case QIF_A_BUYX:
- case QIF_A_MISCEXP:
- case QIF_A_MISCEXPX:
- case QIF_A_MISCINC:
- case QIF_A_MISCINCX:
- case QIF_A_SELLX:
- case QIF_A_XIN:
- case QIF_A_XOUT:
- itxn->far_cat.cat = find_or_make_cat(ctx, cat);
- itxn->far_cat_is_acct = FALSE;
- cat = NULL;
- break;
-
- case QIF_A_CGLONG:
- case QIF_A_CGLONGX:
- case QIF_A_REINVLG:
- itxn->far_cat.acct = qif_default_cglong_acct(ctx, itxn->security);
- break;
-
- case QIF_A_CGMID:
- case QIF_A_CGMIDX:
- case QIF_A_REINVMD:
- itxn->far_cat.acct = qif_default_cgmid_acct(ctx, itxn->security);
- break;
-
- case QIF_A_CGSHORT:
- case QIF_A_CGSHORTX:
- case QIF_A_REINVSG:
- case QIF_A_REINVSH:
- itxn->far_cat.acct = qif_default_cgshort_acct(ctx, itxn->security);
- break;
-
- case QIF_A_DIV:
- case QIF_A_DIVX:
- case QIF_A_REINVDIV:
- itxn->far_cat.acct = qif_default_dividend_acct(ctx, itxn->security);
- break;
-
- case QIF_A_INTINC:
- case QIF_A_INTINCX:
- case QIF_A_REINVINT:
- itxn->far_cat.acct = qif_default_interest_acct(ctx, itxn->security);
- break;
-
- case QIF_A_MARGINT:
- case QIF_A_MARGINTX:
- itxn->far_cat.acct = qif_default_margin_interest_acct(ctx);
- break;
-
- case QIF_A_RTRNCAP:
- case QIF_A_RTRNCAPX:
- itxn->far_cat.acct = qif_default_capital_return_acct(ctx, itxn->security);
- break;
-
- case QIF_A_SHRSIN:
- case QIF_A_SHRSOUT:
- itxn->far_cat.acct = qif_default_equity_holding(ctx, itxn->security);
- break;
-
- case QIF_A_STKSPLIT:
- itxn->far_cat.acct = qif_default_stock_acct(ctx, itxn->security);
- break;
-
- default:
- break;
- }
-
- /* If we don't have a far acct (or far category) then reset the flag */
- if (!itxn->far_cat.obj)
- itxn->far_cat_is_acct = FALSE;
-
- /* And now fill in the "near" and "far" splits. In particular we need
- *
- * NEAR: txn->from_acct, near_split->amount, value
- * FAR: cat, far_split->amount, value
- */
- switch (itxn->action)
- {
- case QIF_A_BUY:
- case QIF_A_BUYX:
- case QIF_A_REINVDIV:
- case QIF_A_REINVINT:
- case QIF_A_REINVLG:
- case QIF_A_REINVMD:
- case QIF_A_REINVSG:
- case QIF_A_REINVSH:
- case QIF_A_SHRSIN:
- near_split->amount = itxn->shares;
- near_split->value = split_value;
- far_split->amount = far_split->value = gnc_numeric_neg(itxn->amount);
- break;
-
- case QIF_A_SELL:
- case QIF_A_SELLX:
- case QIF_A_SHRSOUT:
- near_split->amount = gnc_numeric_neg(itxn->shares);
- near_split->value = gnc_numeric_neg(split_value);
- far_split->amount = far_split->value = itxn->amount;
- break;
-
- case QIF_A_CGLONG:
- case QIF_A_CGLONGX:
- case QIF_A_CGMID:
- case QIF_A_CGMIDX:
- case QIF_A_CGSHORT:
- case QIF_A_CGSHORTX:
- case QIF_A_DIV:
- case QIF_A_DIVX:
- case QIF_A_INTINC:
- case QIF_A_INTINCX:
- case QIF_A_MISCINC:
- case QIF_A_MISCINCX:
- case QIF_A_RTRNCAP:
- case QIF_A_RTRNCAPX:
- case QIF_A_XIN:
- near_split->amount = near_split->value = itxn->amount;
- far_split->amount = far_split->value = gnc_numeric_neg(itxn->amount);
- break;
-
- case QIF_A_MARGINT:
- case QIF_A_MARGINTX:
- case QIF_A_MISCEXP:
- case QIF_A_MISCEXPX:
- case QIF_A_XOUT:
- near_split->amount = near_split->value = gnc_numeric_neg(itxn->amount);
- far_split->amount = far_split->value = itxn->amount;
- break;
-
- case QIF_A_STKSPLIT:
- /* QIF just specifies the split ratio, not the number of shares
- * in and out, so we have to fetch the number of shares from the
- * security account.. FEH!
- */
-
- near_split->value = gnc_numeric_neg(split_value);
- far_split->value = split_value;
-
- /* XXX: FIXME: compute in-shares/out-shares based on ratio here:
- *
- * splitratio = num-shares / 10;
- * in_shares = gnc_account_get_balance(near_acct);
- * out_shares = in_shares * splitratio;
- *
- * near_split->amount = out_shares;
- * far_split->amount = gnc_numeric_neg(in_shares);
- *
- * We know (later) that near_split == txn->default_split and
- * far_split == txn->splits->data, so we'll just special-case this
- * kind of txn when we convert to GNC later.
- */
-
- break;
-
- default:
- break;
- }
-
- /* Just make sure to set that it's an account, not a category */
- far_split->cat.obj = itxn->far_cat.obj;
- if (itxn->far_cat_is_acct)
- far_split->cat_is_acct = TRUE;
-
- /* make the commission split if we need it, then add it to the split-list */
- if (itxn->commissionstr)
- {
- comm_split = qif_split_new();
- comm_split->cat.acct = qif_default_commission_acct(ctx);
- comm_split->cat_is_acct = TRUE;
- comm_split->amount = itxn->commission;
- comm_split->value = itxn->commission;
-
- txn->splits = g_list_prepend(txn->splits, comm_split);
- }
-
- /* Push the "far split" into the txn split-list */
- txn->splits = g_list_prepend(txn->splits, far_split);
-
- /* Free parsed strings.. */
- g_free(cat);
- g_free(cat_class);
- g_free(miscx);
- g_free(miscx_class);
-}
-
-
-/* Other handlers */
-static void
-qif_autoswitch_set(QifContext ctx)
-{
- qif_set_flag(ctx->parse_flags, QIF_F_IGNORE_ACCOUNTS);
-}
-
-static void
-qif_autoswitch_clear(QifContext ctx)
-{
- qif_clear_flag(ctx->parse_flags, QIF_F_IGNORE_ACCOUNTS);
-}
-
-/********************************************************************************
- * find or make ...
- */
-
-QifAccount
-find_or_make_acct(QifContext ctx, char *name, GList *types)
-{
- QifAccount res;
-
- res = (QifAccount)qif_object_map_lookup(ctx, QIF_O_ACCOUNT, name);
- if (res)
- g_free(name);
- else
- {
- res = qif_account_new();
- res->name = name;
- res->type_list = types;
-
- qif_object_map_insert(ctx, name, (QifObject)res);
- }
-
- return res;
-}
-
-QifCategory
-find_or_make_cat(QifContext ctx, char *name)
-{
- QifCategory res;
-
- res = (QifCategory)qif_object_map_lookup(ctx, QIF_O_CATEGORY, name);
- if (res)
- g_free(name);
- else
- {
- res = qif_cat_new();
-
- res->name = name;
-
- qif_object_map_insert(ctx, name, (QifObject)res);
- }
-
- return res;
-}
-
-QifClass
-find_or_make_class(QifContext ctx, char *name)
-{
- QifClass res;
-
- res = (QifClass)qif_object_map_lookup(ctx, QIF_O_CLASS, name);
- if (res)
- g_free(name);
- else
- {
- res = qif_class_new();
- res->name = name;
- qif_object_map_insert(ctx, name, (QifObject)res);
- }
- return res;
-}
-
-/*****************************************************************************/
-
-/*
- * initialize handlers
- */
-void
-qif_object_init(void)
-{
- int i;
- static struct
- {
- QifType type;
- struct _QifHandler handler;
- } handlers[] =
- {
- { QIF_TYPE_BANK, { qif_txn_init, qif_txn_parse, qif_txn_end_acct } },
- { QIF_TYPE_CASH, { qif_txn_init, qif_txn_parse, qif_txn_end_acct } },
- { QIF_TYPE_CCARD, { qif_txn_init, qif_txn_parse, qif_txn_end_acct } },
- { QIF_TYPE_INVST, { qif_txn_init, qif_txn_invst_parse, qif_txn_end_acct } },
- { QIF_TYPE_PORT, { qif_txn_init, qif_txn_invst_parse, qif_txn_end_acct } },
- { QIF_TYPE_OTH_A, { qif_txn_init, qif_txn_parse, qif_txn_end_acct } },
- { QIF_TYPE_OTH_L, { qif_txn_init, qif_txn_parse, qif_txn_end_acct } },
- { QIF_TYPE_CLASS, { NULL, qif_class_parse, NULL } },
- { QIF_TYPE_CAT, { NULL, qif_cat_parse, NULL } },
- { QIF_TYPE_SECURITY, { NULL, qif_security_parse, NULL } },
- { QIF_ACCOUNT, { NULL, qif_account_parse, NULL } },
- { QIF_AUTOSWITCH, { qif_autoswitch_set, NULL, NULL } },
- { QIF_CLEAR_AUTOSWITCH, { qif_autoswitch_clear, NULL, NULL } },
- { 0, {NULL, NULL, NULL} }
- };
-
- for (i = 0; handlers[i].type > 0; i++)
- {
- if (handlers[i].type <= 0)
- {
- PERR("Invalid type?!? (%d @ %d)", handlers[i].type, i);
- }
- else
- qif_register_handler(handlers[i].type, &(handlers[i].handler));
- }
-}
diff --git a/gnucash/import-export/qif/qif-objects.h b/gnucash/import-export/qif/qif-objects.h
deleted file mode 100644
index 2d28e59..0000000
--- a/gnucash/import-export/qif/qif-objects.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * qif-objects.h -- QIF objects for the QIF importer
- *
- * Written By: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifndef QIF_OBJECTS_H
-#define QIF_OBJECTS_H
-
-typedef struct _QifObject *QifObject;
-typedef struct _QifData *QifData;
-
-struct _QifObject
-{
- const char* type;
- void (*destroy)(QifObject);
-
- /* QIF Objects contain data beyond this point.. */
-};
-
-#define QIF_O_ACCOUNT "qif-acct"
-typedef struct _QifAccount *QifAccount;
-
-#define QIF_O_CATEGORY "qif-cat"
-typedef struct _QifCategory *QifCategory;
-
-#define QIF_O_CLASS "qif-class"
-typedef struct _QifClass *QifClass;
-
-#define QIF_O_SECURITY "qif-security"
-typedef struct _QifSecurity *QifSecurity;
-
-#define QIF_O_TXN "qif-txn"
-typedef struct _QifTxn *QifTxn;
-typedef struct _QifSplit *QifSplit;
-typedef struct _QifInvstTxn *QifInvstTxn;
-
-void qif_object_init(void);
-
-QifAccount find_or_make_acct(QifContext ctx, char *name, GList *types);
-QifCategory find_or_make_cat(QifContext ctx, char *name);
-QifClass find_or_make_class(QifContext ctx, char *name);
-
-/* merge the object into the context. Returns the object that's in
- * the context, which is either the supplied object or the
- * already-existing object.
- */
-QifAccount qif_account_merge(QifContext ctx, QifAccount acct);
-QifCategory qif_cat_merge(QifContext ctx, QifCategory cat);
-QifClass qif_class_merge(QifContext ctx, QifClass qclass);
-QifSecurity qif_security_merge(QifContext ctx, QifSecurity security);
-
-#endif /* QIF_OBJECTS_H */
diff --git a/gnucash/import-export/qif/qif-parse.c b/gnucash/import-export/qif/qif-parse.c
deleted file mode 100644
index f291c86..0000000
--- a/gnucash/import-export/qif/qif-parse.c
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * qif-parse.c -- parse QIF
- *
- * Written by: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <string.h>
-
-/* For regex */
-#include <sys/types.h>
-#include <regex.h>
-
-#include <stdarg.h>
-
-#include "gnc-engine.h"
-#include "gnc-ui-util.h"
-
-#include "qif-import-p.h"
-#include "qif-objects-p.h"
-
-#include "import-parse.h"
-
-static QofLogModule log_module = GNC_MOD_IMPORT;
-
-/* An array of handlers for the various bang-types */
-static QifHandler qif_handlers[QIF_TYPE_MAX+1] = { NULL };
-
-/* Parser Regular Expressions */
-static gboolean qifp_regex_compiled = FALSE;
-static regex_t category_regex;
-
-/* A Hash Table of bang-types */
-static GHashTable *qif_bangtype_map = NULL;
-
-/* A Hash Table of action strings */
-static GHashTable *qif_action_map = NULL;
-
-/* A Hash Table of account types */
-static GHashTable *qif_atype_map = NULL;
-
-/************************************************************************/
-
-/* Register a handler */
-void
-qif_register_handler(QifType type, QifHandler handler)
-{
- if (type <= 0 || type > QIF_TYPE_MAX)
- {
- PERR("Invalid type: %d", type);
- return;
- }
- qif_handlers[type] = handler;
-}
-
-static void
-compile_regex()
-{
- regcomp(&category_regex,
- "^ *(\\[)?([^]/|]*)(]?)(/([^|]*))?(\\|(\\[)?([^]/]*)(]?)(/(.*))?)? *$",
- REG_EXTENDED);
-
- qifp_regex_compiled = TRUE;
-}
-
-#define QIF_ADD_TYPE(ts,t) \
- g_hash_table_insert(qif_bangtype_map, ts, GINT_TO_POINTER(t)); \
- g_hash_table_insert(qif_bangtype_map, _(ts), GINT_TO_POINTER(t));
-
-static void
-build_bangtype_map()
-{
- g_return_if_fail(!qif_bangtype_map);
-
- qif_bangtype_map = g_hash_table_new(g_str_hash, g_str_equal);
- g_assert(qif_bangtype_map);
-
- /* Translators FIXME: It is unclear whether these strings should
- really be translated, and if yes, into which translation. */
- QIF_ADD_TYPE(N_("type:bank"), QIF_TYPE_BANK);
- QIF_ADD_TYPE(N_("type:cash"), QIF_TYPE_CASH);
- QIF_ADD_TYPE(N_("type:ccard"), QIF_TYPE_CCARD);
- QIF_ADD_TYPE(N_("type:invst"), QIF_TYPE_INVST);
- QIF_ADD_TYPE(N_("type:port"), QIF_TYPE_PORT);
- QIF_ADD_TYPE(N_("type:oth a"), QIF_TYPE_OTH_A);
- QIF_ADD_TYPE(N_("type:oth l"), QIF_TYPE_OTH_L);
- QIF_ADD_TYPE(N_("type:class"), QIF_TYPE_CLASS);
- QIF_ADD_TYPE(N_("type:cat"), QIF_TYPE_CAT);
- QIF_ADD_TYPE(N_("type:security"), QIF_TYPE_SECURITY);
- QIF_ADD_TYPE(N_("account"), QIF_ACCOUNT);
- QIF_ADD_TYPE(N_("option:autoswitch"), QIF_AUTOSWITCH);
- QIF_ADD_TYPE(N_("clear:autoswitch"), QIF_CLEAR_AUTOSWITCH);
-}
-#undef QIF_ADD_TYPE
-
-#define QIF_ADD_ACT(ts,t) \
- g_hash_table_insert(qif_action_map, ts, GINT_TO_POINTER(t));
-
-static void
-build_action_map()
-{
- g_return_if_fail(!qif_action_map);
-
- qif_action_map = g_hash_table_new(g_str_hash, g_str_equal);
- g_assert(qif_action_map);
-
- QIF_ADD_ACT("buy", QIF_A_BUY);
- QIF_ADD_ACT("cvrshrt", QIF_A_BUY);
- QIF_ADD_ACT("kauf", QIF_A_BUY);
- QIF_ADD_ACT("buyx", QIF_A_BUYX);
- QIF_ADD_ACT("cvrshrtx", QIF_A_BUYX);
- QIF_ADD_ACT("kaufx", QIF_A_BUYX);
- QIF_ADD_ACT("cglong", QIF_A_CGLONG);
- QIF_ADD_ACT("kapgew", QIF_A_CGLONG); /* Kapitalgewinnsteuer */
- QIF_ADD_ACT("cglongx", QIF_A_CGLONG);
- QIF_ADD_ACT("kapgewx", QIF_A_CGLONG);
- QIF_ADD_ACT("cgmid", QIF_A_CGMID);
- QIF_ADD_ACT("cgmidx", QIF_A_CGMIDX);
- QIF_ADD_ACT("cgshort", QIF_A_CGSHORT);
- QIF_ADD_ACT("k.gewsp", QIF_A_CGSHORT);
- QIF_ADD_ACT("cgshortx", QIF_A_CGSHORTX);
- QIF_ADD_ACT("k.gewspx", QIF_A_CGSHORTX);
- QIF_ADD_ACT("div", QIF_A_DIV); /* dividende */
- QIF_ADD_ACT("divx", QIF_A_DIVX);
- //QIF_ADD_ACT("exercise", QIF_A_EXERCISE);
- //QIF_ADD_ACT("exercisex", QIF_A_EXERCISEX);
- //QIF_ADD_ACT("expire", QIF_A_EXPIRE);
- //QIF_ADD_ACT("grant", QIF_A_GRANT);
- QIF_ADD_ACT("int", QIF_A_INTINC);
- QIF_ADD_ACT("intinc", QIF_A_INTINC);
- QIF_ADD_ACT("aktzu", QIF_A_INTINC); /* zinsen */
- QIF_ADD_ACT("intx", QIF_A_INTINCX);
- QIF_ADD_ACT("intincx", QIF_A_INTINCX);
- QIF_ADD_ACT("margint", QIF_A_MARGINT);
- QIF_ADD_ACT("margintx", QIF_A_MARGINTX);
- QIF_ADD_ACT("miscexp", QIF_A_MISCEXP);
- QIF_ADD_ACT("miscexpx", QIF_A_MISCEXPX);
- QIF_ADD_ACT("miscinc", QIF_A_MISCINC);
- QIF_ADD_ACT("cash", QIF_A_MISCINC);
- QIF_ADD_ACT("miscincx", QIF_A_MISCINCX);
- QIF_ADD_ACT("reinvdiv", QIF_A_REINVDIV);
- QIF_ADD_ACT("reinvint", QIF_A_REINVINT);
- QIF_ADD_ACT("reinvzin", QIF_A_REINVINT);
- QIF_ADD_ACT("reinvlg", QIF_A_REINVLG);
- QIF_ADD_ACT("reinvkur", QIF_A_REINVLG);
- QIF_ADD_ACT("reinvmd", QIF_A_REINVMD);
- QIF_ADD_ACT("reinvsg", QIF_A_REINVSG);
- QIF_ADD_ACT("reinvksp", QIF_A_REINVSG);
- QIF_ADD_ACT("reinvsh", QIF_A_REINVSH);
- QIF_ADD_ACT("reminder", QIF_A_REMINDER);
- QIF_ADD_ACT("erinnerg", QIF_A_REMINDER);
- QIF_ADD_ACT("rtrncap", QIF_A_RTRNCAP);
- QIF_ADD_ACT("rtrncapx", QIF_A_RTRNCAPX);
- QIF_ADD_ACT("sell", QIF_A_SELL);
- QIF_ADD_ACT("shtsell", QIF_A_SELL);
- QIF_ADD_ACT("verkauf", QIF_A_SELL); /* verkaufen */
- QIF_ADD_ACT("sellx", QIF_A_SELLX);
- QIF_ADD_ACT("shtsellx", QIF_A_SELLX);
- QIF_ADD_ACT("verkaufx", QIF_A_SELLX); /* verkaufen */
- QIF_ADD_ACT("shrsin", QIF_A_SHRSIN);
- QIF_ADD_ACT("aktzu", QIF_A_SHRSIN);
- QIF_ADD_ACT("shrsout", QIF_A_SHRSOUT);
- QIF_ADD_ACT("aktab", QIF_A_SHRSOUT);
- QIF_ADD_ACT("stksplit", QIF_A_STKSPLIT);
- QIF_ADD_ACT("aktsplit", QIF_A_STKSPLIT);
- //QIF_ADD_ACT("vest", QIF_A_VEST);
- QIF_ADD_ACT("xin", QIF_A_XIN);
- QIF_ADD_ACT("contribx", QIF_A_XIN);
- QIF_ADD_ACT("xout", QIF_A_XOUT);
- QIF_ADD_ACT("withdrwx", QIF_A_XOUT);
-}
-#undef QIF_ADD_ACT
-
-static GList *
-make_list(int count, ...)
-{
- GList *result = NULL;
- GNCAccountType type;
- va_list ap;
-
- va_start (ap, count);
- while (count--)
- {
- type = va_arg (ap, GNCAccountType);
- result = g_list_prepend (result, GINT_TO_POINTER(type));
- }
- va_end (ap);
-
-
- return g_list_reverse(result);
-}
-
-#define QIF_ADD_ATYPE(a,t) g_hash_table_insert(qif_atype_map, a, t);
-static void
-build_atype_map()
-{
- g_return_if_fail(!qif_atype_map);
-
- qif_atype_map = g_hash_table_new(g_str_hash, g_str_equal);
- g_assert(qif_atype_map);
-
- QIF_ADD_ATYPE("bank", make_list(1, ACCT_TYPE_BANK));
- QIF_ADD_ATYPE("port", make_list(1, ACCT_TYPE_BANK));
- QIF_ADD_ATYPE("cash", make_list(1, ACCT_TYPE_CASH));
- QIF_ADD_ATYPE("ccard", make_list(1, ACCT_TYPE_CREDIT));
- QIF_ADD_ATYPE("invst", make_list(3, ACCT_TYPE_BANK, ACCT_TYPE_STOCK,
- ACCT_TYPE_MUTUAL));
- QIF_ADD_ATYPE("oth a", make_list(3, ACCT_TYPE_ASSET, ACCT_TYPE_BANK,
- ACCT_TYPE_CASH));
- QIF_ADD_ATYPE("oth l", make_list(2, ACCT_TYPE_LIABILITY, ACCT_TYPE_CREDIT));
- QIF_ADD_ATYPE("mutual", make_list(3, ACCT_TYPE_BANK, ACCT_TYPE_MUTUAL,
- ACCT_TYPE_STOCK));
-
- /* Internal types */
- QIF_ADD_ATYPE("__any_bank__", make_list(5, ACCT_TYPE_BANK, ACCT_TYPE_CREDIT,
- ACCT_TYPE_CASH, ACCT_TYPE_ASSET,
- ACCT_TYPE_LIABILITY));
- QIF_ADD_ATYPE("__all__", make_list(7, ACCT_TYPE_BANK, ACCT_TYPE_CREDIT,
- ACCT_TYPE_CASH, ACCT_TYPE_ASSET,
- ACCT_TYPE_LIABILITY, ACCT_TYPE_STOCK,
- ACCT_TYPE_MUTUAL));
- QIF_ADD_ATYPE("__stock__", make_list(2, ACCT_TYPE_STOCK, ACCT_TYPE_MUTUAL));
- QIF_ADD_ATYPE("__income__", make_list(1, ACCT_TYPE_INCOME));
- QIF_ADD_ATYPE("__expense__", make_list(1, ACCT_TYPE_EXPENSE));
- QIF_ADD_ATYPE("__equity__", make_list(1, ACCT_TYPE_EQUITY));
-}
-#undef QIF_ADD_ATYPE
-
-/************************************************************************/
-
-/*
- * We've got a !Type line. Parse the line into the appropriate
- * type and then initialize the handler.
- */
-void
-qif_parse_bangtype(QifContext ctx, const char *line)
-{
- QifType type;
- char *bangtype;
- gpointer result;
-
- g_return_if_fail(line && *line == '!');
-
- if (!qif_bangtype_map)
- build_bangtype_map();
-
- /* Make a local copy so we can manipulate it.
- * - strip off leading/trailing whitespace
- * - make it all lower case
- */
- bangtype = g_utf8_strdown(line + 1, -1);
- g_strstrip(bangtype);
-
- /* In some cases we get "!Type Bank" -- change the space to a colon */
- if (!strncmp(bangtype, "type ", 5))
- bangtype[5] = ':';
-
- /* Lookup the bangtype in the map and then destroy the local copy */
- result = g_hash_table_lookup(qif_bangtype_map, bangtype);
- g_free(bangtype);
-
- if (!result)
- {
- PWARN("Unknown bang-type at line %d: %s. Ignored", ctx->lineno, line);
- return;
- }
- type = GPOINTER_TO_INT(result);
-
- /* Set the current context parse type and handler */
- ctx->parse_type = type;
- ctx->handler = qif_handlers[type];
-
- /* now initialize this new parse type (if there's an init function) */
- if (ctx->handler && ctx->handler->init)
- ctx->handler->init(ctx);
-}
-
-/* returns TRUE if successful, FALSE if there is a problem */
-gboolean
-qif_parse_split_category(const char* str,
- char** cat, gboolean *cat_is_acct, char** cat_class,
- char** miscx_cat, gboolean *miscx_cat_is_acct,
- char **miscx_class)
-{
- /* This is a pretty f**ked up string. Basically it looks like:
- * ([)cat-or-acct(])(/(class))(|([)cat-of-acct(])(/ext))
- *
- * where data in parens is "optional" (depending on the context).
- *
- * examples from reality:
- *
- * category
- * category:subcategory
- * category/class
- * category:subcat/class
- * [account]
- * [account]/class
- *
- * cat/cat-class|miscx-cat/miscx-class
- */
-
- regmatch_t pmatch[12];
-
- g_return_val_if_fail(cat && cat_is_acct && cat_class &&
- miscx_cat && miscx_cat_is_acct && miscx_class, FALSE);
-
-
- if (!qifp_regex_compiled)
- compile_regex();
-
- if (regexec(&category_regex, str, 12, pmatch, 0) != 0)
- {
- PERR("category match failed");
- return FALSE;
- }
-
- /*
- * what the substrings mean:
- * 1 the opening [ for a transfer
- * 2 the category
- * 3 the closing ]
- * 4 the class /
- * 5 the class
- * 6 the miscx expression (whole thing)
- * 7 the opening [
- * 8 the miscx category
- * 9 the closing ]
- * 10 the class /
- * 11 the class
- */
-
- if (pmatch[2].rm_so == -1)
- {
- PERR("no category match found!");
- return FALSE;
- }
-
- /* catgory name */
- *cat = g_strndup(str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so);
- /* category is account? */
- *cat_is_acct = (pmatch[1].rm_so != -1 && pmatch[3].rm_so != -1);
- /* category class */
- *cat_class = (pmatch[4].rm_so != -1 ?
- g_strndup(str + pmatch[5].rm_so, pmatch[5].rm_eo - pmatch[5].rm_so) :
- NULL);
-
- /* miscx category name */
- *miscx_cat = (pmatch[6].rm_so != -1 ?
- g_strndup(str + pmatch[8].rm_so, pmatch[8].rm_eo - pmatch[8].rm_so) :
- NULL);
- /* miscx cat is acct */
- *miscx_cat_is_acct = (pmatch[7].rm_so != -1 && pmatch[9].rm_so != -1);
- /* miscx class */
- *miscx_class = (pmatch[10].rm_so != -1 ?
- g_strndup(str + pmatch[11].rm_so,
- pmatch[11].rm_eo - pmatch[11].rm_so) : NULL);
-
- return TRUE;
-}
-
-/*
- * qif_parse_cleared -- parse the 'C'leared field of a QIF Transaction.
- * returns the QIF reconciled flag.
- *
- * * means cleared, x or X means reconciled, and ! or ? mean some
- * budget related stuff I don't understand.
- */
-QifRecnFlag
-qif_parse_cleared(QifLine line)
-{
- g_return_val_if_fail(line, QIF_R_NO);
- g_return_val_if_fail(line->line, QIF_R_NO);
-
- switch (*line->line)
- {
- case '*':
- return QIF_R_CLEARED;
- case 'x':
- case 'X':
- return QIF_R_RECONCILED;
- case '?':
- case '!':
- return QIF_R_BUDGETED;
- default:
- PERR("Unknown QIF Cleared flag at line %d: %s", line->lineno, line->line);
- return QIF_R_NO;
- }
-}
-
-QifAction qif_parse_action(QifLine line)
-{
- QifAction qaction;
- gpointer result;
- char *action;
-
- g_return_val_if_fail(line, QIF_A_NONE);
- g_return_val_if_fail(line->line, QIF_A_NONE);
-
- if (!qif_action_map)
- build_action_map();
-
- /* Duplicate the action and force it to lower case and strip any spaces */
- action = g_utf8_strdown(line->line, -1);
- g_strstrip(action);
-
- result = g_hash_table_lookup(qif_action_map, action);
- g_free(action);
-
- if (!result)
- {
- /* XXX: pop up a dialog? */
- PWARN("Unknown Action at line %d: %s. Some transactions may be discarded",
- line->lineno, line->line);
- return QIF_A_NONE;
- }
-
- qaction = GPOINTER_TO_INT(result);
- return qaction;
-}
-
-GList * qif_parse_acct_type(const char *str, gint lineno)
-{
- GList *result;
- char *type;
-
- if (!qif_atype_map)
- build_atype_map();
-
- /* Duplicate the type and force it to lower case and strip any spaces */
- type = g_utf8_strdown(str, -1);
- g_strstrip(type);
-
- result = g_hash_table_lookup(qif_atype_map, type);
- g_free(type);
-
- if (!result)
- {
- PWARN("Unknown account type at line %d: %s. ", lineno, str);
- result = g_hash_table_lookup(qif_atype_map, "bank");
- g_return_val_if_fail(result, NULL);
- }
-
- return result;
-}
-
-GList * qif_parse_acct_type_guess(QifType type)
-{
- const char *atype = NULL;
-
- switch (type)
- {
- case QIF_TYPE_BANK:
- atype = "bank";
- break;
- case QIF_TYPE_CASH:
- atype = "cash";
- break;
- case QIF_TYPE_CCARD:
- atype = "ccard";
- break;
- case QIF_TYPE_INVST:
- atype = "invst";
- break;
- case QIF_TYPE_PORT:
- atype = "port";
- break;
- case QIF_TYPE_OTH_A:
- atype = "oth a";
- break;
- case QIF_TYPE_OTH_L:
- atype = "oth l";
- break;
- default:
- return NULL;
- }
-
- return qif_parse_acct_type(atype, -1);
-}
-
-/***********************************************************************
- * Parsing numbers and dates...
- */
-
-typedef struct _parse_helper
-{
- QifContext ctx;
-
- GncImportFormat budget;
- GncImportFormat limit;
- GncImportFormat amount;
- GncImportFormat d_amount;
- GncImportFormat price;
- GncImportFormat shares;
- GncImportFormat commission;
- GncImportFormat date;
-} *parse_helper_t;
-
-#define QIF_PARSE_CHECK_NUMBER(str,help) { \
- if (str) (help) = gnc_import_test_numeric((str), (help)); \
-}
-#define QIF_PARSE_PARSE_NUMBER(str,fmt,val) { \
- if (str) gnc_import_parse_numeric((str), (fmt), (val)); \
-}
-
-static void
-qif_parse_check_account(gpointer key, gpointer val, gpointer data)
-{
- parse_helper_t helper = data;
- QifAccount acct = val;
-
- QIF_PARSE_CHECK_NUMBER(acct->limitstr, helper->limit);
- QIF_PARSE_CHECK_NUMBER(acct->budgetstr, helper->budget);
-}
-
-static void
-qif_parse_parse_account(gpointer key, gpointer val, gpointer data)
-{
- parse_helper_t helper = data;
- QifAccount acct = val;
-
- QIF_PARSE_PARSE_NUMBER(acct->limitstr, helper->limit, &acct->limit);
- QIF_PARSE_PARSE_NUMBER(acct->budgetstr, helper->budget, &acct->budget);
-}
-
-static void
-qif_parse_check_category(gpointer key, gpointer val, gpointer data)
-{
- parse_helper_t helper = data;
- QifCategory cat = val;
-
- QIF_PARSE_CHECK_NUMBER(cat->budgetstr, helper->budget);
-}
-
-static void
-qif_parse_parse_category(gpointer key, gpointer val, gpointer data)
-{
- parse_helper_t helper = data;
- QifCategory cat = val;
-
- QIF_PARSE_PARSE_NUMBER(cat->budgetstr, helper->budget, &cat->budget);
-}
-
-static void
-qif_parse_check_txn(gpointer val, gpointer data)
-{
- parse_helper_t helper = data;
- QifTxn txn = val;
- QifSplit split;
- QifInvstTxn itxn;
- GList *node;
-
- /* Check the date */
- helper->date = gnc_import_test_date(txn->datestr, helper->date);
-
- /* If this is an investment transaction, then all the info is in
- * the invst_info. Otherwise it's all in the splits.
- */
- itxn = txn->invst_info;
- if (itxn)
- {
- QIF_PARSE_CHECK_NUMBER(itxn->amountstr, helper->amount);
- QIF_PARSE_CHECK_NUMBER(itxn->d_amountstr, helper->d_amount);
- QIF_PARSE_CHECK_NUMBER(itxn->pricestr, helper->price);
- QIF_PARSE_CHECK_NUMBER(itxn->sharesstr, helper->shares);
- QIF_PARSE_CHECK_NUMBER(itxn->commissionstr, helper->commission);
-
- }
- else
- {
- split = txn->default_split;
- node = txn->splits;
- do
- {
- QIF_PARSE_CHECK_NUMBER(split->amountstr, helper->amount);
-
- if (node)
- {
- split = node->data;
- node = node->next;
- }
- else
- split = NULL;
- }
- while (split);
- }
-}
-
-static void
-qif_parse_parse_txn(gpointer val, gpointer data)
-{
- parse_helper_t helper = data;
- QifTxn txn = val;
- QifSplit split;
- QifInvstTxn itxn;
- GList *node;
-
- /* Parse the date */
- gnc_import_parse_date(txn->datestr, helper->date, &txn->date);
-
- /* If this is an investment transaction, then all the info is in
- * the invst_info. Otherwise it's all in the splits.
- */
- itxn = txn->invst_info;
- if (itxn)
- {
- QIF_PARSE_PARSE_NUMBER(itxn->amountstr, helper->amount, &itxn->amount);
- QIF_PARSE_PARSE_NUMBER(itxn->d_amountstr, helper->d_amount, &itxn->d_amount);
- QIF_PARSE_PARSE_NUMBER(itxn->pricestr, helper->price, &itxn->price);
- QIF_PARSE_PARSE_NUMBER(itxn->sharesstr, helper->shares, &itxn->shares);
- QIF_PARSE_PARSE_NUMBER(itxn->commissionstr, helper->commission,
- &itxn->commission);
-
- qif_invst_txn_setup_splits(helper->ctx, txn);
-
- }
- else
- {
- split = txn->default_split;
- node = txn->splits;
- do
- {
- QIF_PARSE_PARSE_NUMBER(split->amountstr, helper->amount, &split->amount);
-
- if (node)
- {
- split = node->data;
- node = node->next;
- }
- else
- split = NULL;
- }
- while (split);
-
- qif_txn_setup_splits(txn);
- }
-}
-
-void
-qif_parse_all(QifContext ctx, gpointer arg)
-{
- struct _parse_helper helper;
-
- helper.ctx = ctx;
-
- /* PARSE ACCOUNTS */
-
- /* First, figure out the formats */
- helper.limit = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
- helper.budget = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
- qif_object_map_foreach(ctx, QIF_O_ACCOUNT, qif_parse_check_account, &helper);
-
- /* Make sure it's not ambiguous */
- if (helper.limit & (helper.limit - 1)) helper.limit = GNCIF_NUM_PERIOD;
- if (helper.budget & (helper.budget - 1)) helper.budget = GNCIF_NUM_PERIOD;
-
- /* Now convert the numbers */
- qif_object_map_foreach(ctx, QIF_O_ACCOUNT, qif_parse_parse_account, &helper);
-
- /* PARSE CATEGORIES */
-
- helper.budget = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
- qif_object_map_foreach(ctx, QIF_O_CATEGORY, qif_parse_check_category, &helper);
-
- /* make sure it's not ambiguous */
- if (helper.budget & (helper.budget - 1)) helper.budget = GNCIF_NUM_PERIOD;
-
- /* Now convert the numbers */
- qif_object_map_foreach(ctx, QIF_O_CATEGORY, qif_parse_parse_category, &helper);
-
- /* PARSE TRANSACTIONS */
- helper.amount = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
- helper.d_amount = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
- helper.price = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
- helper.shares = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
- helper.commission = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
- helper.date = GNCIF_DATE_MDY | GNCIF_DATE_DMY | GNCIF_DATE_YMD | GNCIF_DATE_YDM;
-
- qif_object_list_foreach(ctx, QIF_O_TXN, qif_parse_check_txn, &helper);
-
- /* check/fix ambiguities */
- if (helper.amount & (helper.amount - 1)) helper.amount = GNCIF_NUM_PERIOD;
- if (helper.d_amount & (helper.d_amount - 1)) helper.d_amount = GNCIF_NUM_PERIOD;
- if (helper.price & (helper.price - 1)) helper.price = GNCIF_NUM_PERIOD;
- if (helper.shares & (helper.shares - 1)) helper.shares = GNCIF_NUM_PERIOD;
- if (helper.commission & (helper.commission - 1))
- helper.commission = GNCIF_NUM_PERIOD;
-
- if (helper.date & (helper.date - 1))
- {
- helper.date = gnc_import_choose_fmt(_("The Date format is ambiguous. "
- "Please choose the correct format."),
- helper.date, arg);
- }
-
- /* now parse it.. */
- qif_object_list_foreach(ctx, QIF_O_TXN, qif_parse_parse_txn, &helper);
-}
-
-typedef struct
-{
- QifContext ctx;
- GList * list;
- const char* type;
-} qif_merge_t;
-
-static void
-qif_merge_accts(gpointer key, gpointer value, gpointer data)
-{
- qif_merge_t *merge = data;
- QifAccount acct = value;
-
- /* Merge into the context. Remember items moved into the parent */
- if (qif_account_merge(merge->ctx, acct) == acct)
- merge->list = g_list_prepend(merge->list, acct->name);
-}
-
-static void
-qif_merge_cats(gpointer key, gpointer value, gpointer data)
-{
- qif_merge_t *merge = data;
- QifCategory cat = value;
-
- /* Merge into the context. Remember items moved into the parent */
- if (qif_cat_merge(merge->ctx, cat) == cat)
- merge->list = g_list_prepend(merge->list, cat->name);
-}
-
-static void
-qif_merge_classes(gpointer key, gpointer value, gpointer data)
-{
- qif_merge_t *merge = data;
- QifClass qclass = value;
-
- /* Merge into the context. Remember items moved into the parent */
- if (qif_class_merge(merge->ctx, qclass) == qclass)
- merge->list = g_list_prepend(merge->list, qclass->name);
-}
-
-static void
-qif_merge_secs(gpointer key, gpointer value, gpointer data)
-{
- qif_merge_t *merge = data;
- QifSecurity sec = value;
-
- /* Merge into the context. Remember items moved into the parent */
- if (qif_security_merge(merge->ctx, sec) == sec)
- merge->list = g_list_prepend(merge->list, sec->name);
-}
-
-static void
-qif_merge_del(gpointer obj, gpointer data)
-{
- qif_merge_t *merge = data;
- const char *name = obj;
-
- qif_object_map_remove(merge->ctx, merge->type, name);
-}
-
-static void
-qif_massage_split(QifSplit split, QifContext ctx)
-{
- const char *type = QIF_O_CATEGORY;
- char *name;
-
- if (split->cat.obj)
- {
- if (split->cat_is_acct)
- {
- type = QIF_O_ACCOUNT;
- name = split->cat.acct->name;
- }
- else
- name = split->cat.cat->name;
-
- split->cat.obj = qif_object_map_lookup(ctx, type, name);
- }
-
- if (split->cat_class)
- {
- split->cat_class = (QifClass) qif_object_map_lookup(ctx, QIF_O_CLASS,
- split->cat_class->name);
- }
-}
-
-static void
-qif_massage_itxn(QifInvstTxn itxn, QifContext ctx)
-{
- const char *type = QIF_O_CATEGORY;
- char *name;
-
- if (itxn->far_cat.obj)
- {
- if (itxn->far_cat_is_acct)
- {
- type = QIF_O_ACCOUNT;
- name = itxn->far_cat.acct->name;
- }
- else
- name = itxn->far_cat.cat->name;
-
- itxn->far_cat.obj = qif_object_map_lookup(ctx, type, name);
- }
-}
-
-static void
-qif_massage_txn(gpointer obj, gpointer data)
-{
- QifTxn txn = obj;
- QifContext ctx = data;
- QifSplit split;
- GList *node;
-
- if (txn->from_acct)
- txn->from_acct = (QifAccount) qif_object_map_lookup(ctx, QIF_O_ACCOUNT,
- txn->from_acct->name);
-
- if (txn->invst_info)
- qif_massage_itxn(txn->invst_info, ctx);
-
- if (txn->default_split)
- qif_massage_split(txn->default_split, ctx);
-
- for (node = txn->splits; node; node = node->next)
- {
- split = node->data;
- qif_massage_split(split, ctx);
- }
-}
-
-void
-qif_parse_merge_files(QifContext ctx)
-{
- GList *node;
- GList *accts = NULL;
- GList *cats = NULL;
- GList *classes = NULL;
- GList *securities = NULL;
- QifContext fctx;
-
- qif_merge_t merge;
-
- g_return_if_fail(ctx);
-
- /* Make sure each of the "file" contexts have been parsed.
- * note that we don't care about OUR context -- we can run this
- * process multiple times safely.
- */
- for (node = ctx->files; node; node = node->next)
- {
- fctx = node->data;
- g_return_if_fail(fctx->parsed);
- }
-
-
- /* Iterate over each file. Merge the Accounts, Categories, Classes,
- * Securities, and Transactions into the top-level context. Be sure
- * to re-point all Transaction/Split category/class/account pointers
- * to the new top-level item. Then be sure to remove the
- * "duplicated" items so we don't double-free (as we don't refcount,
- * either).
- */
- for (node = ctx->files; node; node = node->next)
- {
- fctx = node->data;
-
- /* Merge accts, categories, classes, and securities */
-
- merge.ctx = ctx;
- merge.list = NULL;
- qif_object_map_foreach(fctx, QIF_O_ACCOUNT, qif_merge_accts, &merge);
- accts = merge.list;
-
- merge.list = NULL;
- qif_object_map_foreach(fctx, QIF_O_CATEGORY, qif_merge_cats, &merge);
- cats = merge.list;
-
- merge.list = NULL;
- qif_object_map_foreach(fctx, QIF_O_CLASS, qif_merge_classes, &merge);
- classes = merge.list;
-
- merge.list = NULL;
- qif_object_map_foreach(fctx, QIF_O_SECURITY, qif_merge_secs, &merge);
- securities = merge.list;
-
-
- /* repoint the transactions to the merged context data */
- qif_object_list_foreach(fctx, QIF_O_TXN, qif_massage_txn, ctx);
-
-
- /* then remove from the file context objects referenced in the top context */
- merge.ctx = fctx;
- merge.type = QIF_O_ACCOUNT;
- g_list_foreach(accts, qif_merge_del, &merge);
- g_list_free(accts);
-
- merge.type = QIF_O_CATEGORY;
- g_list_foreach(cats, qif_merge_del, &merge);
- g_list_free(cats);
-
- merge.type = QIF_O_CLASS;
- g_list_foreach(classes, qif_merge_del, &merge);
- g_list_free(classes);
-
- merge.type = QIF_O_SECURITY;
- g_list_foreach(securities, qif_merge_del, &merge);
- g_list_free(securities);
-
- }
-
- /* We've been parsed */
- ctx->parsed = TRUE;
-}
diff --git a/gnucash/import-export/qif/qif-parse.h b/gnucash/import-export/qif/qif-parse.h
deleted file mode 100644
index 11d439c..0000000
--- a/gnucash/import-export/qif/qif-parse.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * qif-parse.h -- routines for parsing pieces of a QIF file
- *
- * Written By: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#ifndef QIF_PARSE_H
-#define QIF_PARSE_H
-
-#include "qif-import.h"
-
-void qif_register_handler(QifType type, QifHandler handler);
-void qif_parse_bangtype(QifContext ctx, const char *line);
-
-gboolean
-qif_parse_split_category(const char* str,
- char** cat, gboolean *cat_is_acct, char** cat_class,
- char** miscx_cat, gboolean *miscx_cat_is_acct,
- char **miscx_class);
-
-gboolean qif_parse_numeric(QifLine line, gnc_numeric *num);
-QifRecnFlag qif_parse_cleared(QifLine line);
-QifAction qif_parse_action(QifLine line);
-
-/* The caller should never destroy this list */
-GList * qif_parse_acct_type(const char *str, gint lineno);
-GList * qif_parse_acct_type_guess(QifType type);
-
-/* Parse all objects */
-void qif_parse_all(QifContext ctx, gpointer ui_args);
-
-#endif /* QIF_PARSE_H */
diff --git a/gnucash/import-export/qif/test/CMakeLists.txt b/gnucash/import-export/qif/test/CMakeLists.txt
deleted file mode 100644
index d874ca3..0000000
--- a/gnucash/import-export/qif/test/CMakeLists.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-
-set(QIF_TEST_INCLUDE_DIRS
- ${CMAKE_BINARY_DIR}/common
- ${CMAKE_SOURCE_DIR}/gnucash/import-export/qif
- ${CMAKE_SOURCE_DIR}/libgnucash/engine
- ${CMAKE_SOURCE_DIR}/common/test-core
- ${GLIB2_INCLUDE_DIRS}
-)
-set(QIF_TEST_LIBS gncmod-qif test-core)
-
-if (FALSE)
- # Tests for this directory are not run.
- gnc_add_test(test-link-qif test-link.c QIF_TEST_INCLUDE_DIRS QIF_TEST_LIBS)
- gnc_add_test(test-qif test-qif.c QIF_TEST_INCLUDE_DIRS QIF_TEST_LIBS
- GNC_TEST_FILES=${CMAKE_CURRENT_SOURCE_DIR}/test-files)
-endif()
-
-set_dist_list(test_qif_DIST CMakeLists.txt test-link.c test-qif.c test-files/test-1-bank-txn.qif)
diff --git a/gnucash/import-export/qif/test/test-files/test-1-bank-txn.qif b/gnucash/import-export/qif/test/test-files/test-1-bank-txn.qif
deleted file mode 100644
index 59592d0..0000000
--- a/gnucash/import-export/qif/test/test-files/test-1-bank-txn.qif
+++ /dev/null
@@ -1,6 +0,0 @@
-!Type:Bank
-D2003/01/27
-T123.45
-PTest Payee
-LTest Category
-^
diff --git a/gnucash/import-export/qif/test/test-link.c b/gnucash/import-export/qif/test/test-link.c
deleted file mode 100644
index fd55d42..0000000
--- a/gnucash/import-export/qif/test/test-link.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/********************************************************************\
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License as *
- * published by the Free Software Foundation; either version 2 of *
- * the License, or (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License*
- * along with this program; if not, contact: *
- * *
- * Free Software Foundation Voice: +1-617-542-5942 *
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
- * Boston, MA 02110-1301, USA gnu at gnu.org *
- * *
-\********************************************************************/
-
-#include "qif-import.h"
-
-int
-main(int argc, char *argv[])
-{
- qif_context_new();
- return 0;
-}
diff --git a/gnucash/import-export/qif/test/test-qif.c b/gnucash/import-export/qif/test/test-qif.c
deleted file mode 100644
index c331bef..0000000
--- a/gnucash/import-export/qif/test/test-qif.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * test-qif.c -- Test the QIF Import routines.
- *
- * Created by: Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2003 Derek Atkins <warlord at MIT.EDU>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation Voice: +1-617-542-5942
- * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
- * Boston, MA 02110-1301, USA gnu at gnu.org
- */
-
-#include <glib.h>
-#include <libguile.h>
-
-#include "gnc-module.h"
-#include "qif-import.h"
-#include "qif-import-p.h" /* Let's test some internal stuff, too */
-
-#include "test-stuff.h"
-
-/* XXX */
-extern void qif_object_init(void);
-
-static QifContext
-test_qif_load_file(QifContext ctx, const char *filename,
- gint txn_count, gint acct_count, gboolean needs_acct)
-{
- QifContext file;
-
- printf("qif loading \"%s\"...\n", filename);
- file = qif_file_new(ctx, filename);
- do_test(file != NULL, "failed to read file");
- if (!file) return NULL;
-
- do_test(qif_object_list_count(file, QIF_O_TXN) == txn_count,
- "Transaction count didn't match");
- do_test(qif_object_map_count(file, QIF_O_ACCOUNT) == acct_count,
- "Account count didn't match");
- do_test(qif_file_needs_account(file) == needs_acct,
- "Needs account flad didn't match");
-
- return file;
-}
-
-static void
-test_qif(void)
-{
- QifContext ctx, file;
- char *filename;
- const char *location = g_getenv("GNC_TEST_FILES");
- int i;
-
- ctx = qif_context_new();
- do_test(ctx != NULL, "failed to create the qif context");
- if (!ctx) return;
-
- if (!location)
- location = "test-files";
-
- for (i = 0; i < 1; i++)
- {
- filename = g_strdup_printf("%s/%s", location, "test-1-bank-txn.qif");
- file = test_qif_load_file(ctx, filename, 1, 0, TRUE);
- g_free(filename);
- if (!file) continue;
-
- if (qif_file_needs_account(file))
- qif_file_set_default_account(file, "test-1-bank-txn");
-
- do_test(qif_file_needs_account(file) == FALSE,
- "'Needs account' flag not cleared properly");
-
- do_test(qif_file_parse(file, NULL) == QIF_E_OK,
- "file failed to parse.");
- }
-
- qif_context_destroy(ctx);
-
- success("QIF test successful");
-}
-
-static void
-main_helper(void *closure, int argc, char **argv)
-{
- qif_object_init(); /* XXX:FIXME */
- test_qif();
- print_test_results();
- exit(get_rv());
-}
-
-int
-main(int argc, char **argv)
-{
- scm_boot_guile(argc, argv, main_helper, NULL);
- return 0;
-}
-
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 426b3f2..b8cc820 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -347,9 +347,6 @@ gnucash/import-export/ofx/gnc-ofx-import.c
gnucash/import-export/ofx/gnc-ofx-kvp.c
gnucash/import-export/ofx/gnc-plugin-ofx.c
gnucash/import-export/ofx/gschemas/org.gnucash.dialogs.import.ofx.gschema.xml.in
-gnucash/import-export/qif/qif-context.c
-gnucash/import-export/qif/qif-file.c
-gnucash/import-export/qif/qif-objects.c
gnucash/import-export/qif-imp/assistant-qif-import.c
gnucash/import-export/qif-imp/dialog-account-picker.c
gnucash/import-export/qif-imp/gncmod-qif-import.c
@@ -486,8 +483,7 @@ gnucash/report/standard-reports/general-journal.scm
gnucash/report/standard-reports/general-ledger.scm
gnucash/report/standard-reports/income-gst-statement.scm
gnucash/report/standard-reports/income-statement.scm
-gnucash/report/standard-reports/net-barchart.scm
-gnucash/report/standard-reports/net-linechart.scm
+gnucash/report/standard-reports/net-charts.scm
gnucash/report/standard-reports/portfolio.scm
gnucash/report/standard-reports/price-scatter.scm
gnucash/report/standard-reports/register.scm
@@ -575,7 +571,6 @@ libgnucash/backend/sql/gnc-sql-result.cpp
libgnucash/backend/sql/gnc-tax-table-sql.cpp
libgnucash/backend/sql/gnc-transaction-sql.cpp
libgnucash/backend/sql/gnc-vendor-sql.cpp
-libgnucash/backend/xml/.#gnc-invoice-xml-v2.cpp
libgnucash/backend/xml/gnc-account-xml-v2.cpp
libgnucash/backend/xml/gnc-address-xml-v2.cpp
libgnucash/backend/xml/gnc-backend-xml.cpp
Summary of changes:
gnucash/import-export/CMakeLists.txt | 1 -
.../import-export/qif-imp/assistant-qif-import.c | 9 +-
gnucash/import-export/qif-imp/qif-to-gnc.scm | 4 +-
gnucash/import-export/qif/CMakeLists.txt | 43 -
gnucash/import-export/qif/qif-context.c | 417 ------
gnucash/import-export/qif/qif-defaults.c | 152 --
gnucash/import-export/qif/qif-defaults.h | 44 -
gnucash/import-export/qif/qif-file.c | 326 -----
gnucash/import-export/qif/qif-file.h | 36 -
gnucash/import-export/qif/qif-import-p.h | 100 --
gnucash/import-export/qif/qif-import.h | 159 ---
gnucash/import-export/qif/qif-objects-p.h | 174 ---
gnucash/import-export/qif/qif-objects.c | 1468 --------------------
gnucash/import-export/qif/qif-objects.h | 71 -
gnucash/import-export/qif/qif-parse.c | 935 -------------
gnucash/import-export/qif/qif-parse.h | 50 -
gnucash/import-export/qif/test/CMakeLists.txt | 18 -
.../qif/test/test-files/test-1-bank-txn.qif | 6 -
gnucash/import-export/qif/test/test-link.c | 28 -
gnucash/import-export/qif/test/test-qif.c | 110 --
po/POTFILES.in | 7 +-
21 files changed, 12 insertions(+), 4146 deletions(-)
delete mode 100644 gnucash/import-export/qif/CMakeLists.txt
delete mode 100644 gnucash/import-export/qif/qif-context.c
delete mode 100644 gnucash/import-export/qif/qif-defaults.c
delete mode 100644 gnucash/import-export/qif/qif-defaults.h
delete mode 100644 gnucash/import-export/qif/qif-file.c
delete mode 100644 gnucash/import-export/qif/qif-file.h
delete mode 100644 gnucash/import-export/qif/qif-import-p.h
delete mode 100644 gnucash/import-export/qif/qif-import.h
delete mode 100644 gnucash/import-export/qif/qif-objects-p.h
delete mode 100644 gnucash/import-export/qif/qif-objects.c
delete mode 100644 gnucash/import-export/qif/qif-objects.h
delete mode 100644 gnucash/import-export/qif/qif-parse.c
delete mode 100644 gnucash/import-export/qif/qif-parse.h
delete mode 100644 gnucash/import-export/qif/test/CMakeLists.txt
delete mode 100644 gnucash/import-export/qif/test/test-files/test-1-bank-txn.qif
delete mode 100644 gnucash/import-export/qif/test/test-link.c
delete mode 100644 gnucash/import-export/qif/test/test-qif.c
More information about the gnucash-changes
mailing list