r16173 - gnucash/branches/csv-import - Initial commit of csv-import.

Benjamin Sperisen lasindi at cvs.gnucash.org
Sat Jun 16 21:23:41 EDT 2007


Author: lasindi
Date: 2007-06-16 21:23:40 -0400 (Sat, 16 Jun 2007)
New Revision: 16173
Trac: http://svn.gnucash.org/trac/changeset/16173

Added:
   gnucash/branches/csv-import/lib/stf/
   gnucash/branches/csv-import/lib/stf/Makefile.am
   gnucash/branches/csv-import/lib/stf/README
   gnucash/branches/csv-import/lib/stf/stf-parse.c
   gnucash/branches/csv-import/lib/stf/stf-parse.h
   gnucash/branches/csv-import/src/import-export/csv/Makefile.am
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.c
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.h
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.c
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.h
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv-preview-dialog.glade
   gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv-ui.xml
   gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv.c
   gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv.h
   gnucash/branches/csv-import/src/import-export/csv/gncmod-csv-import.c
Removed:
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv2glist.c
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv2glist.h
Modified:
   gnucash/branches/csv-import/configure.in
   gnucash/branches/csv-import/lib/Makefile.am
   gnucash/branches/csv-import/src/bin/gnucash-bin.c
   gnucash/branches/csv-import/src/import-export/Makefile.am
Log:
Initial commit of csv-import.
Rudimentary preview and configuration works, but with minimal error 
checking and lots of bugs.


Modified: gnucash/branches/csv-import/configure.in
===================================================================
--- gnucash/branches/csv-import/configure.in	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/configure.in	2007-06-17 01:23:40 UTC (rev 16173)
@@ -1424,6 +1424,7 @@
           lib/libqof/qof/Makefile
           lib/libqof/backend/Makefile
           lib/libqof/backend/file/Makefile
+          lib/stf/Makefile
           packaging/Makefile
           packaging/win32/Makefile
           packaging/win32/gnucash.iss
@@ -1477,6 +1478,7 @@
           src/import-export/schemas/Makefile
           src/import-export/ofx/Makefile
           src/import-export/ofx/test/Makefile
+          src/import-export/csv/Makefile
           src/import-export/log-replay/Makefile
           src/import-export/hbci/Makefile
           src/import-export/hbci/glade/Makefile

Modified: gnucash/branches/csv-import/lib/Makefile.am
===================================================================
--- gnucash/branches/csv-import/lib/Makefile.am	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/lib/Makefile.am	2007-06-17 01:23:40 UTC (rev 16173)
@@ -1,5 +1,5 @@
-SUBDIRS = libc glib28 guile-www srfi
-DIST_SUBDIRS = libc glib28 guile-www srfi libqof
+SUBDIRS = libc glib28 guile-www srfi stf
+DIST_SUBDIRS = libc glib28 guile-www srfi libqof stf
 
 if USE_LIBQOF
 SUBDIRS += libqof

Added: gnucash/branches/csv-import/lib/stf/Makefile.am
===================================================================
--- gnucash/branches/csv-import/lib/stf/Makefile.am	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/lib/stf/Makefile.am	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,13 @@
+noinst_LTLIBRARIES = libgnc-stf.la
+
+REALSRCS = stf-parse.c
+REALHDRS = stf-parse.h
+
+libgnc_stf_la_SOURCES = ${REALSRCS}
+noinst_HEADERS = ${REALHDRS}
+
+libgnc_stf_la_LDFLAGS = $(pkg-config --libs libgoffice-0.3)
+
+AM_CFLAGS = $(GOFFICE_CFLAGS)
+
+EXTRA_DIST = $(REALSRCS) $(REALHDRS)

Added: gnucash/branches/csv-import/lib/stf/README
===================================================================
--- gnucash/branches/csv-import/lib/stf/README	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/lib/stf/README	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,2 @@
+This consists of code taken from Gnumeric's Structured Text Format
+parser. It is used for the CSV/Fixed-Width file importer.

Added: gnucash/branches/csv-import/lib/stf/stf-parse.c
===================================================================
--- gnucash/branches/csv-import/lib/stf/stf-parse.c	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/lib/stf/stf-parse.c	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,1411 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * stf-parse.c : Structured Text Format parser. (STF)
+ *               A general purpose engine for parsing data
+ *               in CSV and Fixed width format.
+ *
+ *
+ * Copyright (C) Almer. S. Tigelaar.
+ * EMail: almer1 at dds.nl or almer-t at bigfoot.com
+ *
+ * Copyright (C) 2003 Andreas J. Guelzow <aguelzow at taliesin.ca>
+ * Copyright (C) 2003 Morten Welinder <terra at gnome.org>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define GETTEXT_PACKAGE gnumeric
+
+#include <glib/gi18n-lib.h>
+/* #include "gnumeric.h" */
+#include "stf-parse.h"
+
+/* #include "workbook.h" */
+/* #include "cell.h" */
+/* #include "sheet.h" */
+/* #include "clipboard.h" */
+/* #include "sheet-style.h" */
+/* #include "value.h" */
+/* #include "mstyle.h" */
+/* #include "number-match.h" */
+/* #include "gutils.h" */
+/* #include "parse-util.h" */
+#include <goffice/utils/go-glib-extras.h>
+#include <goffice/utils/go-locale.h>
+#include <goffice/utils/go-format.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <locale.h>
+#include <string.h>
+#include <math.h>
+
+#define SETUP_LOCALE_SWITCH char *oldlocale = NULL
+
+#define START_LOCALE_SWITCH if (parseoptions->locale) {\
+oldlocale = g_strdup(go_setlocale (LC_ALL, NULL)); \
+go_setlocale(LC_ALL, parseoptions->locale);}
+
+#define END_LOCALE_SWITCH if (oldlocale) {\
+go_setlocale(LC_ALL, oldlocale);\
+g_free (oldlocale);}
+
+/* Source_t struct, used for interchanging parsing information between the low level parse functions */
+typedef struct {
+	GStringChunk *chunk;
+	char const *position;  /* Indicates the current position within data */
+
+	/* Used internally for fixed width parsing */
+	int splitpos;          /* Indicates current position in splitpositions array */
+	int linepos;           /* Position on the current line */
+} Source_t;
+
+/* Struct used for autodiscovery */
+typedef struct {
+	int start;
+	int stop;
+} AutoDiscovery_t;
+
+/*
+ * Some silly dude make the length field an unsigned int.  C just does
+ * not deal very well with that.
+ */
+static inline int
+my_garray_len (GArray const *a)
+{
+	return (int)a->len;
+}
+
+static inline int
+my_gptrarray_len (GPtrArray const *a)
+{
+	return (int)a->len;
+}
+
+static int
+compare_terminator (char const *s, StfParseOptions_t *parseoptions)
+{
+	guchar const *us = (guchar const *)s;
+	GSList *l;
+
+	if (*us > parseoptions->compiled_terminator.max ||
+	    *us < parseoptions->compiled_terminator.min)
+		return 0;
+
+	for (l = parseoptions->terminator; l; l = l->next) {
+		char const *term = l->data;
+		char const *d = s;
+
+		while (*term) {
+			if (*d != *term)
+				goto next;
+			term++;
+			d++;
+		}
+		return d - s;
+
+	next:
+		;
+	}
+	return 0;
+}
+
+
+/*******************************************************************************************************
+ * STF PARSE OPTIONS : StfParseOptions related
+ *******************************************************************************************************/
+
+/**
+ * stf_parse_options_new:
+ *
+ * This will return a new StfParseOptions_t struct.
+ * The struct should, after being used, freed with stf_parse_options_free.
+ **/
+StfParseOptions_t *
+stf_parse_options_new (void)
+{
+	StfParseOptions_t* parseoptions = g_new0 (StfParseOptions_t, 1);
+
+	parseoptions->parsetype   = PARSE_TYPE_NOTSET;
+
+	parseoptions->terminator  = NULL;
+	stf_parse_options_add_line_terminator (parseoptions, "\r\n");
+	stf_parse_options_add_line_terminator (parseoptions, "\n");
+	stf_parse_options_add_line_terminator (parseoptions, "\r");
+
+	parseoptions->trim_spaces = (TRIM_TYPE_RIGHT | TRIM_TYPE_LEFT);
+	parseoptions->locale = NULL;
+
+	parseoptions->splitpositions = NULL;
+	stf_parse_options_fixed_splitpositions_clear (parseoptions);
+
+	parseoptions->stringindicator = '"';
+	parseoptions->indicator_2x_is_single = TRUE;
+	parseoptions->duplicates = FALSE;
+	parseoptions->trim_seps = FALSE;
+
+	parseoptions->sep.str = NULL;
+	parseoptions->sep.chr = NULL;
+
+	parseoptions->col_import_array = NULL;
+	parseoptions->col_import_array_len = 0;
+	parseoptions->formats = NULL;
+
+	parseoptions->cols_exceeded = FALSE;
+
+	return parseoptions;
+}
+
+/**
+ * stf_parse_options_free:
+ *
+ * will free @parseoptions, note that this will not free the splitpositions
+ * member (GArray) of the struct, the caller is responsible for that.
+ **/
+void
+stf_parse_options_free (StfParseOptions_t *parseoptions)
+{
+	g_return_if_fail (parseoptions != NULL);
+
+	g_free (parseoptions->col_import_array);
+	g_free (parseoptions->locale);
+	g_free (parseoptions->sep.chr);
+
+	if (parseoptions->sep.str) {
+		GSList *l;
+
+		for (l = parseoptions->sep.str; l != NULL; l = l->next)
+			g_free ((char *) l->data);
+		g_slist_free (parseoptions->sep.str);
+	}
+
+	g_array_free (parseoptions->splitpositions, TRUE);
+
+	stf_parse_options_clear_line_terminator (parseoptions);
+
+	if (parseoptions->formats) {
+		unsigned int ui;
+		GPtrArray *formats = parseoptions->formats;
+
+		for (ui = 0; ui < formats->len; ui++)
+			go_format_unref (g_ptr_array_index (formats, ui));
+		g_ptr_array_free (formats, TRUE);
+		parseoptions->formats = NULL;
+	}
+
+	g_free (parseoptions);
+}
+
+void
+stf_parse_options_set_type (StfParseOptions_t *parseoptions, StfParseType_t const parsetype)
+{
+	g_return_if_fail (parseoptions != NULL);
+	g_return_if_fail (parsetype == PARSE_TYPE_CSV || parsetype == PARSE_TYPE_FIXED);
+
+	parseoptions->parsetype = parsetype;
+}
+
+static gint
+long_string_first (gchar const *a, gchar const *b)
+{
+	/* This actually is UTF-8 safe.  */
+	return strlen (b) - strlen (a);
+}
+
+static void
+compile_terminators (StfParseOptions_t *parseoptions)
+{
+	GSList *l;
+	GO_SLIST_SORT (parseoptions->terminator, (GCompareFunc)long_string_first);
+
+	parseoptions->compiled_terminator.min = 255;
+	parseoptions->compiled_terminator.max = 0;
+	for (l = parseoptions->terminator; l; l = l->next) {
+		const guchar *term = l->data;
+		parseoptions->compiled_terminator.min =
+			MIN (parseoptions->compiled_terminator.min, *term);
+		parseoptions->compiled_terminator.max =
+			MAX (parseoptions->compiled_terminator.max, *term);
+	}
+}
+
+/**
+ * stf_parse_options_add_line_terminator:
+ *
+ * This will add to the line terminators, in both the Fixed width and CSV delimited importers
+ * this indicates the end of a row.
+ *
+ **/
+void
+stf_parse_options_add_line_terminator (StfParseOptions_t *parseoptions, char const *terminator)
+{
+	g_return_if_fail (parseoptions != NULL);
+	g_return_if_fail (terminator != NULL && *terminator != 0);
+
+	GO_SLIST_PREPEND (parseoptions->terminator, g_strdup (terminator));
+	compile_terminators (parseoptions);
+}
+
+/**
+ * stf_parse_options_clear_line_terminator:
+ *
+ * This will clear the line terminator, in both the Fixed width and CSV delimited importers
+ * this indicates the end of a row.
+ *
+ **/
+void
+stf_parse_options_clear_line_terminator (StfParseOptions_t *parseoptions)
+{
+	g_return_if_fail (parseoptions != NULL);
+
+	go_slist_free_custom (parseoptions->terminator, g_free);
+	parseoptions->terminator = NULL;
+	compile_terminators (parseoptions);
+}
+
+/**
+ * stf_parse_options_set_trim_spaces:
+ *
+ * If enabled will trim spaces in every parsed field on left and/or right
+ * sides.
+ **/
+void
+stf_parse_options_set_trim_spaces (StfParseOptions_t *parseoptions, StfTrimType_t const trim_spaces)
+{
+	g_return_if_fail (parseoptions != NULL);
+
+	parseoptions->trim_spaces = trim_spaces;
+}
+
+/**
+ * stf_parse_options_csv_set_separators:
+ *
+ * A copy is made of the parameters.
+ **/
+void
+stf_parse_options_csv_set_separators (StfParseOptions_t *parseoptions, char const *character,
+				      GSList const *string)
+{
+	g_return_if_fail (parseoptions != NULL);
+
+	g_free (parseoptions->sep.chr);
+	parseoptions->sep.chr = g_strdup (character);
+
+	go_slist_free_custom (parseoptions->sep.str, g_free);
+	parseoptions->sep.str = go_slist_map (string, (GOMapFunc)g_strdup);
+}
+
+void
+stf_parse_options_csv_set_stringindicator (StfParseOptions_t *parseoptions, gunichar const stringindicator)
+{
+	g_return_if_fail (parseoptions != NULL);
+	g_return_if_fail (stringindicator != '\0');
+
+	parseoptions->stringindicator = stringindicator;
+}
+
+/**
+ * stf_parse_options_csv_set_indicator_2x_is_single:
+ * @indic_2x : a boolean value indicating whether we want to see two
+ * 		adjacent string indicators as a single string indicator
+ * 		that is part of the cell, rather than a terminator.
+ **/
+void
+stf_parse_options_csv_set_indicator_2x_is_single (StfParseOptions_t *parseoptions,
+						  gboolean const indic_2x)
+{
+	g_return_if_fail (parseoptions != NULL);
+
+	parseoptions->indicator_2x_is_single = indic_2x;
+}
+
+/**
+ * stf_parse_options_csv_set_duplicates:
+ * @duplicates : a boolean value indicating whether we want to see two
+ *               separators right behind each other as one
+ **/
+void
+stf_parse_options_csv_set_duplicates (StfParseOptions_t *parseoptions, gboolean const duplicates)
+{
+	g_return_if_fail (parseoptions != NULL);
+
+	parseoptions->duplicates = duplicates;
+}
+
+/**
+ * stf_parse_options_csv_set_trim_seps:
+ * @trim_seps : a boolean value indicating whether we want to ignore
+ *               separators at the beginning of lines
+ **/
+void
+stf_parse_options_csv_set_trim_seps (StfParseOptions_t *parseoptions, gboolean const trim_seps)
+{
+	g_return_if_fail (parseoptions != NULL);
+
+	parseoptions->trim_seps = trim_seps;
+}
+
+/**
+ * stf_parse_options_fixed_splitpositions_clear:
+ *
+ * This will clear the splitpositions (== points on which a line is split)
+ **/
+void
+stf_parse_options_fixed_splitpositions_clear (StfParseOptions_t *parseoptions)
+{
+	int minus_one = -1;
+	g_return_if_fail (parseoptions != NULL);
+
+	if (parseoptions->splitpositions)
+		g_array_free (parseoptions->splitpositions, TRUE);
+	parseoptions->splitpositions = g_array_new (FALSE, FALSE, sizeof (int));
+
+	g_array_append_val (parseoptions->splitpositions, minus_one);
+}
+
+/**
+ * stf_parse_options_fixed_splitpositions_add:
+ *
+ * @position will be added to the splitpositions.
+ **/
+void
+stf_parse_options_fixed_splitpositions_add (StfParseOptions_t *parseoptions, int position)
+{
+	unsigned int ui;
+
+	g_return_if_fail (parseoptions != NULL);
+	g_return_if_fail (position >= 0);
+
+	for (ui = 0; ui < parseoptions->splitpositions->len - 1; ui++) {
+		int here = g_array_index (parseoptions->splitpositions, int, ui);
+		if (position == here)
+			return;
+		if (position < here)
+			break;
+	}
+
+	g_array_insert_val (parseoptions->splitpositions, ui, position);
+}
+
+void
+stf_parse_options_fixed_splitpositions_remove (StfParseOptions_t *parseoptions, int position)
+{
+	unsigned int ui;
+
+	g_return_if_fail (parseoptions != NULL);
+	g_return_if_fail (position >= 0);
+
+	for (ui = 0; ui < parseoptions->splitpositions->len - 1; ui++) {
+		int here = g_array_index (parseoptions->splitpositions, int, ui);
+		if (position == here)
+			g_array_remove_index (parseoptions->splitpositions, ui);
+		if (position <= here)
+			return;
+	}
+}
+
+int
+stf_parse_options_fixed_splitpositions_count (StfParseOptions_t *parseoptions)
+{
+	return parseoptions->splitpositions->len;
+}
+
+int
+stf_parse_options_fixed_splitpositions_nth (StfParseOptions_t *parseoptions, int n)
+{
+	return g_array_index (parseoptions->splitpositions, int, n);
+}
+
+
+/**
+ * stf_parse_options_valid:
+ * @parseoptions : an import options struct
+ *
+ * Checks if @parseoptions is correctly filled
+ *
+ * returns : TRUE if it is correctly filled, FALSE otherwise.
+ **/
+static gboolean
+stf_parse_options_valid (StfParseOptions_t *parseoptions)
+{
+	g_return_val_if_fail (parseoptions != NULL, FALSE);
+
+	if (parseoptions->parsetype == PARSE_TYPE_CSV) {
+		if (parseoptions->stringindicator == '\0') {
+			g_warning ("STF: Cannot have \\0 as string indicator");
+			return FALSE;
+		}
+
+	} else if (parseoptions->parsetype == PARSE_TYPE_FIXED) {
+		if (!parseoptions->splitpositions) {
+			g_warning ("STF: No splitpositions in struct");
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+/*******************************************************************************************************
+ * STF PARSE : The actual routines that do the 'trick'
+ *******************************************************************************************************/
+
+static void
+trim_spaces_inplace (char *field, StfParseOptions_t const *parseoptions)
+{
+	if (!field) return;
+
+	if (parseoptions->trim_spaces & TRIM_TYPE_LEFT) {
+		char *s = field;
+
+		while (g_unichar_isspace (g_utf8_get_char (s)))
+			s = g_utf8_next_char (s);
+
+		if (s != field)
+			strcpy (field, s);
+	}
+
+	if (parseoptions->trim_spaces & TRIM_TYPE_RIGHT) {
+		char *s = field + strlen (field);
+
+		while (field != s) {
+			s = g_utf8_prev_char (s);
+			if (!g_unichar_isspace (g_utf8_get_char (s)))
+				break;
+			*s = 0;
+		}
+	}
+}
+
+/**
+ * stf_parse_csv_is_separator:
+ *
+ * returns NULL if @character is not a separator, a pointer to the character
+ * after the separator otherwise.
+ **/
+static char const *
+stf_parse_csv_is_separator (char const *character, char const *chr, GSList const *str)
+{
+	g_return_val_if_fail (character != NULL, NULL);
+
+	if (*character == 0)
+		return NULL;
+
+	if (str) {
+		GSList const *l;
+
+		for (l = str; l != NULL; l = l->next) {
+			char const *s = l->data;
+			char const *r;
+			glong cnt;
+			glong const len = g_utf8_strlen (s, -1);
+
+			/* Don't compare past the end of the buffer! */
+			for (r = character, cnt = 0; cnt < len; cnt++, r = g_utf8_next_char (r))
+				if (*r == '\0')
+					break;
+
+			if ((cnt == len) && (memcmp (character, s, len) == 0))
+				return g_utf8_offset_to_pointer (character, len);
+		}
+	}
+
+	if (chr && g_utf8_strchr (chr, -1,
+				  g_utf8_get_char (character)))
+		return g_utf8_next_char(character);
+
+	return NULL;
+}
+
+/*
+ * stf_parse_eat_separators:
+ *
+ * skip over leading separators
+ *
+ */
+
+static void
+stf_parse_eat_separators (Source_t *src, StfParseOptions_t *parseoptions)
+{
+	char const *cur, *next;
+
+	g_return_if_fail (src != NULL);
+        g_return_if_fail (parseoptions != NULL);
+
+	cur = src->position;
+
+	if (*cur == '\0' || compare_terminator (cur, parseoptions))
+		return;
+	while ((next = stf_parse_csv_is_separator (cur, parseoptions->sep.chr, parseoptions->sep.str)))
+		cur = next;
+	src->position = cur;
+	return;
+}
+
+
+typedef enum {
+	STF_CELL_ERROR,
+	STF_CELL_EOF,
+	STF_CELL_EOL,
+	STF_CELL_FIELD_NO_SEP,
+	STF_CELL_FIELD_SEP,
+} StfParseCellRes;
+
+static StfParseCellRes
+stf_parse_csv_cell (GString *text, Source_t *src, StfParseOptions_t *parseoptions)
+{
+	char const *cur;
+	gboolean saw_sep = FALSE;
+
+	g_return_val_if_fail (src != NULL, STF_CELL_ERROR);
+	g_return_val_if_fail (parseoptions != NULL, STF_CELL_ERROR);
+
+	cur = src->position;
+	g_return_val_if_fail (cur != NULL, STF_CELL_ERROR);
+
+	/* Skip whitespace, but stop at line terminators.  */
+	while (1) {
+		int term_len;
+
+		if (*cur == 0) {
+			src->position = cur;
+			return STF_CELL_EOF;
+		}
+
+		term_len = compare_terminator (cur, parseoptions);
+		if (term_len) {
+			src->position = cur + term_len;
+			return STF_CELL_EOL;
+		}
+
+		if ((parseoptions->trim_spaces & TRIM_TYPE_LEFT) == 0)
+			break;
+
+		if (stf_parse_csv_is_separator (cur, parseoptions->sep.chr,
+						parseoptions->sep.str))
+			break;
+
+		if (!g_unichar_isspace (g_utf8_get_char (cur)))
+			break;
+		cur = g_utf8_next_char (cur);
+	}
+
+	if (g_utf8_get_char (cur) == parseoptions->stringindicator) {
+		cur = g_utf8_next_char (cur);
+		while (*cur) {
+			gunichar uc = g_utf8_get_char (cur);
+			cur = g_utf8_next_char (cur);
+
+			if (uc == parseoptions->stringindicator) {
+				if (parseoptions->indicator_2x_is_single &&
+				    g_utf8_get_char (cur) == parseoptions->stringindicator)
+					cur = g_utf8_next_char (cur);
+				else {
+					/* "field content"dropped-garbage,  */
+					while (*cur && !compare_terminator (cur, parseoptions)) {
+						char const *post = stf_parse_csv_is_separator
+							(cur, parseoptions->sep.chr, parseoptions->sep.str);
+						if (post) {
+							cur = post;
+							saw_sep = TRUE;
+							break;
+						}
+						cur = g_utf8_next_char (cur);
+					}
+					break;
+				}
+			}
+
+			g_string_append_unichar (text, uc);
+		}
+
+		/* We silently allow a missing terminating quote.  */
+	} else {
+		/* Unquoted field.  */
+
+		while (*cur && !compare_terminator (cur, parseoptions)) {
+
+			char const *post = stf_parse_csv_is_separator
+				(cur, parseoptions->sep.chr, parseoptions->sep.str);
+			if (post) {
+				cur = post;
+				saw_sep = TRUE;
+				break;
+			}
+
+			g_string_append_unichar (text, g_utf8_get_char (cur));
+			cur = g_utf8_next_char (cur);
+		}
+
+		if (parseoptions->trim_spaces & TRIM_TYPE_RIGHT) {
+			while (text->len) {
+				const char *last = g_utf8_prev_char (text->str + text->len);
+				if (!g_unichar_isspace (g_utf8_get_char (last)))
+					break;
+				g_string_truncate (text, last - text->str);
+			}
+		}
+	}
+
+	src->position = cur;
+
+	if (saw_sep && parseoptions->duplicates)
+		stf_parse_eat_separators (src, parseoptions);
+
+	return saw_sep ? STF_CELL_FIELD_SEP : STF_CELL_FIELD_NO_SEP;
+}
+
+/**
+ * stf_parse_csv_line:
+ *
+ * This will parse one line from the current @src->position.
+ * NOTE: The calling routine is responsible for freeing the result.
+ *
+ * returns : a GPtrArray of char*'s
+ **/
+static GPtrArray *
+stf_parse_csv_line (Source_t *src, StfParseOptions_t *parseoptions)
+{
+	GPtrArray *line;
+	gboolean cont = FALSE;
+
+	g_return_val_if_fail (src != NULL, NULL);
+	g_return_val_if_fail (parseoptions != NULL, NULL);
+
+	line = g_ptr_array_new ();
+	if (parseoptions->trim_seps)
+		stf_parse_eat_separators (src, parseoptions);
+
+	while (1) {
+		GString *text = g_string_sized_new (30);
+		StfParseCellRes res =
+			stf_parse_csv_cell (text, src, parseoptions);
+		trim_spaces_inplace (text->str, parseoptions);
+		switch (res) {
+		case STF_CELL_FIELD_NO_SEP:
+			g_ptr_array_add (line, g_string_free (text, FALSE));
+			cont = FALSE;
+			break;
+
+		case STF_CELL_FIELD_SEP:
+			g_ptr_array_add (line, g_string_free (text, FALSE));
+			cont = TRUE;  /* Make sure we see one more field.  */
+			break;
+
+		default:
+			if (cont)
+				g_ptr_array_add (line, g_string_free (text, FALSE));
+			else
+				g_string_free (text, TRUE);
+			return line;
+		}
+	}
+}
+
+/**
+ * stf_parse_fixed_cell:
+ *
+ * returns a pointer to the parsed cell contents.
+ **/
+static char *
+stf_parse_fixed_cell (Source_t *src, StfParseOptions_t *parseoptions)
+{
+	char *res;
+	char const *cur;
+	int splitval;
+
+	g_return_val_if_fail (src != NULL, NULL);
+	g_return_val_if_fail (parseoptions != NULL, NULL);
+
+	cur = src->position;
+
+	if (src->splitpos < my_garray_len (parseoptions->splitpositions))
+		splitval = (int) g_array_index (parseoptions->splitpositions, int, src->splitpos);
+	else
+		splitval = -1;
+
+	while (*cur != 0 && !compare_terminator (cur, parseoptions) && splitval != src->linepos) {
+		src->linepos++;
+	        cur = g_utf8_next_char (cur);
+	}
+
+	res = g_string_chunk_insert_len (src->chunk,
+					 src->position,
+					 cur - src->position);
+
+	src->position = cur;
+
+	return res;
+}
+
+/**
+ * stf_parse_fixed_line:
+ *
+ * This will parse one line from the current @src->position.
+ * It will return a GPtrArray with the cell contents as strings.
+
+ * NOTE: The calling routine is responsible for freeing result.
+ **/
+static GPtrArray *
+stf_parse_fixed_line (Source_t *src, StfParseOptions_t *parseoptions)
+{
+	GPtrArray *line;
+
+	g_return_val_if_fail (src != NULL, NULL);
+	g_return_val_if_fail (parseoptions != NULL, NULL);
+
+	src->linepos = 0;
+	src->splitpos = 0;
+
+	line = g_ptr_array_new ();
+	while (*src->position != '\0' && !compare_terminator (src->position, parseoptions)) {
+		char *field = stf_parse_fixed_cell (src, parseoptions);
+
+		trim_spaces_inplace (field, parseoptions);
+		g_ptr_array_add (line, field);
+
+		src->splitpos++;
+	}
+
+	return line;
+}
+
+void
+stf_parse_general_free (GPtrArray *lines)
+{
+	unsigned lineno;
+	for (lineno = 0; lineno < lines->len; lineno++) {
+		GPtrArray *line = g_ptr_array_index (lines, lineno);
+		/* Fields are not free here.  */
+		g_ptr_array_free (line, TRUE);
+	}
+	g_ptr_array_free (lines, TRUE);
+}
+
+
+/**
+ * stf_parse_general:
+ *
+ * Returns a GPtrArray of lines, where each line is itself a
+ * GPtrArray of strings.
+ *
+ * The caller must free this entire structure, for example by calling
+ * stf_parse_general_free.
+ **/
+GPtrArray *
+stf_parse_general (StfParseOptions_t *parseoptions,
+		   GStringChunk *lines_chunk,
+		   char const *data, char const *data_end)
+{
+	GPtrArray *lines;
+	Source_t src;
+	int row;
+
+	g_return_val_if_fail (parseoptions != NULL, NULL);
+	g_return_val_if_fail (data != NULL, NULL);
+	g_return_val_if_fail (data_end != NULL, NULL);
+	g_return_val_if_fail (stf_parse_options_valid (parseoptions), NULL);
+	g_return_val_if_fail (g_utf8_validate (data, -1, NULL), NULL);
+
+	src.chunk = lines_chunk;
+	src.position = data;
+	row = 0;
+
+	lines = g_ptr_array_new ();
+	while (*src.position != '\0' && src.position < data_end) {
+		GPtrArray *line;
+
+		line = parseoptions->parsetype == PARSE_TYPE_CSV
+			? stf_parse_csv_line (&src, parseoptions)
+			: stf_parse_fixed_line (&src, parseoptions);
+
+		g_ptr_array_add (lines, line);
+		if (parseoptions->parsetype != PARSE_TYPE_CSV)
+			src.position += compare_terminator (src.position, parseoptions);
+
+		if (++row == SHEET_MAX_ROWS)
+			break;
+	}
+
+	return lines;
+}
+
+GPtrArray *
+stf_parse_lines (StfParseOptions_t *parseoptions,
+		 GStringChunk *lines_chunk,
+		 char const *data,
+		 int maxlines, gboolean with_lineno)
+{
+	GPtrArray *lines;
+	int lineno = 1;
+
+	g_return_val_if_fail (data != NULL, NULL);
+
+	lines = g_ptr_array_new ();
+	while (*data) {
+		char const *data0 = data;
+		GPtrArray *line = g_ptr_array_new ();
+
+		if (with_lineno) {
+			char buf[4 * sizeof (int)];
+			sprintf (buf, "%d", lineno);
+			g_ptr_array_add (line,
+					 g_string_chunk_insert (lines_chunk, buf));
+		}
+
+		while (1) {
+			int termlen = compare_terminator (data, parseoptions);
+			if (termlen > 0 || *data == 0) {
+				g_ptr_array_add (line,
+						 g_string_chunk_insert_len (lines_chunk,
+									    data0,
+									    data - data0));
+				data += termlen;
+				break;
+			} else
+				data = g_utf8_next_char (data);
+		}
+
+		g_ptr_array_add (lines, line);
+
+		lineno++;
+		if (lineno >= maxlines)
+			break;
+	}
+	return lines;
+}
+
+char const *
+stf_parse_find_line (StfParseOptions_t *parseoptions,
+		     char const *data,
+		     int line)
+{
+	while (line > 0) {
+		int termlen = compare_terminator (data, parseoptions);
+		if (termlen > 0) {
+			data += termlen;
+			line--;
+		} else if (*data == 0) {
+			return data;
+		} else {
+			data = g_utf8_next_char (data);
+		}
+	}
+	return data;
+}
+
+
+/**
+ * stf_parse_options_fixed_autodiscover:
+ * @parseoptions: a Parse options struct.
+ * @data_lines : The number of lines to look at in @data.
+ * @data : The actual data.
+ *
+ * Automatically try to discover columns in the text to be parsed.
+ * We ignore empty lines (only containing parseoptions->terminator)
+ *
+ * FIXME: This is so extremely ugly that I am too tired to rewrite it right now.
+ *        Think hard of a better more flexible solution...
+ **/
+void
+stf_parse_options_fixed_autodiscover (StfParseOptions_t *parseoptions,
+				      char const *data, char const *data_end)
+{
+	char const *iterator = data;
+	GSList *list = NULL;
+	GSList *list_start = NULL;
+	int lines = 0;
+	int effective_lines = 0;
+	int max_line_length = 0;
+	int *line_begin_hits = NULL;
+	int *line_end_hits = NULL;
+	int i;
+
+	stf_parse_options_fixed_splitpositions_clear (parseoptions);
+
+	/*
+	 * First take a look at all possible white space combinations
+	 */
+	while (*iterator && iterator < data_end) {
+		gboolean begin_recorded = FALSE;
+		AutoDiscovery_t *disc = NULL;
+		int position = 0;
+		int termlen = 0;
+
+		while (*iterator && (termlen = compare_terminator (iterator, parseoptions)) == 0) {
+			if (!begin_recorded && *iterator == ' ') {
+				disc = g_new0 (AutoDiscovery_t, 1);
+
+				disc->start = position;
+
+				begin_recorded = TRUE;
+			} else if (begin_recorded && *iterator != ' ') {
+				disc->stop = position;
+				list = g_slist_prepend (list, disc);
+
+				begin_recorded = FALSE;
+				disc = NULL;
+			}
+
+			position++;
+			iterator++;
+		}
+
+		if (position > max_line_length)
+			max_line_length = position;
+
+		/*
+		 * If there are excess spaces at the end of
+		 * the line : ignore them
+		 */
+		g_free (disc);
+
+		/*
+		 * Hop over the terminator
+		 */
+		iterator += termlen;
+
+		if (position != 0)
+			effective_lines++;
+
+		lines++;
+	}
+
+	list       = g_slist_reverse (list);
+	list_start = list;
+
+	/*
+	 * Kewl stuff :
+	 * Look at the number of hits at each line position
+	 * if the number of hits equals the number of lines
+	 * we can be pretty sure this is the start or end
+	 * of a column, we filter out empty columns
+	 * later
+	 */
+	line_begin_hits = g_new0 (int, max_line_length + 1);
+	line_end_hits   = g_new0 (int, max_line_length + 1);
+
+	while (list) {
+		AutoDiscovery_t *disc = list->data;
+
+		line_begin_hits[disc->start]++;
+		line_end_hits[disc->stop]++;
+
+		g_free (disc);
+
+		list = g_slist_next (list);
+	}
+	g_slist_free (list_start);
+
+	for (i = 0; i < max_line_length + 1; i++)
+		if (line_begin_hits[i] == effective_lines || line_end_hits[i] == effective_lines)
+			stf_parse_options_fixed_splitpositions_add (parseoptions, i);
+
+	/*
+	 * Do some corrections to the initial columns
+	 * detected here, we obviously don't need to
+	 * do this if there are no columns at all.
+	 */
+	if (my_garray_len (parseoptions->splitpositions) > 0) {
+		/*
+		 * Try to find columns that look like :
+		 *
+		 * Example     100
+		 * Example2      9
+		 *
+		 * (In other words : Columns with left & right justification with
+		 *  a minimum of 2 spaces in the middle)
+		 * Split these columns in 2
+		 */
+
+		for (i = 0; i < my_garray_len (parseoptions->splitpositions) - 1; i++) {
+			int begin = g_array_index (parseoptions->splitpositions, int, i);
+			int end   = g_array_index (parseoptions->splitpositions, int, i + 1);
+			int num_spaces   = -1;
+			int spaces_start = 0;
+			gboolean right_aligned = TRUE;
+			gboolean left_aligned  = TRUE;
+			gboolean has_2_spaces  = TRUE;
+
+			iterator = data;
+			lines = 0;
+			while (*iterator && iterator < data_end) {
+				gboolean trigger = FALSE;
+				gboolean space_trigger = FALSE;
+				int pos = 0;
+
+				num_spaces   = -1;
+				spaces_start = 0;
+				while (*iterator && !compare_terminator (iterator, parseoptions)) {
+					if (pos == begin) {
+						if (*iterator == ' ')
+							left_aligned = FALSE;
+
+						trigger = TRUE;
+					} else if (pos == end - 1) {
+						if (*iterator == ' ')
+							right_aligned = FALSE;
+
+						trigger = FALSE;
+					}
+
+					if (trigger || pos == end - 1) {
+						if (!space_trigger && *iterator == ' ') {
+							space_trigger = TRUE;
+							spaces_start = pos;
+						} else if (space_trigger && *iterator != ' ') {
+							space_trigger = FALSE;
+							num_spaces = pos - spaces_start;
+						}
+					}
+
+					iterator++;
+					pos++;
+				}
+
+				if (num_spaces < 2)
+					has_2_spaces = FALSE;
+
+				if (*iterator)
+					iterator++;
+
+				lines++;
+			}
+
+			/*
+			 * If this column meets all the criteria
+			 * split it into two at the last measured
+			 * spaces_start + num_spaces
+			 */
+			if (has_2_spaces && right_aligned && left_aligned) {
+				int val = (((spaces_start + num_spaces) - spaces_start) / 2) + spaces_start;
+
+				g_array_insert_val (parseoptions->splitpositions, i + 1, val);
+
+				/*
+				 * Skip over the inserted column
+				 */
+				i++;
+			}
+		}
+
+		/*
+		 * Remove empty columns here if needed
+		 */
+		for (i = 0; i < my_garray_len (parseoptions->splitpositions) - 1; i++) {
+			int begin = g_array_index (parseoptions->splitpositions, int, i);
+			int end = g_array_index (parseoptions->splitpositions, int, i + 1);
+			gboolean only_spaces = TRUE;
+
+			iterator = data;
+			lines = 0;
+			while (*iterator && iterator < data_end) {
+				gboolean trigger = FALSE;
+				int pos = 0;
+
+				while (*iterator && !compare_terminator (iterator, parseoptions)) {
+					if (pos == begin)
+						trigger = TRUE;
+					else if (pos == end)
+						trigger = FALSE;
+
+					if (trigger) {
+						if (*iterator != ' ')
+							only_spaces = FALSE;
+					}
+
+					iterator++;
+					pos++;
+				}
+
+				if (*iterator)
+					iterator++;
+
+				lines++;
+			}
+
+			/*
+			 * The column only contains spaces
+			 * remove it
+			 */
+			if (only_spaces) {
+				g_array_remove_index (parseoptions->splitpositions, i);
+
+				/*
+				 * We HAVE to make sure that the next column (end) also
+				 * gets checked out. If we don't decrease "i" here, we
+				 * will skip over it as the indexes shift down after
+				 * the removal
+				 */
+				i--;
+			}
+		}
+	}
+
+	g_free (line_begin_hits);
+	g_free (line_end_hits);
+}
+
+/*******************************************************************************************************
+ * STF PARSE HL: high-level functions that dump the raw data returned by the low-level parsing
+ *               functions into something meaningful (== application specific)
+ *******************************************************************************************************/
+
+/* gboolean */
+/* stf_parse_sheet (StfParseOptions_t *parseoptions, */
+/* 		 char const *data, char const *data_end, */
+/* 		 Sheet *sheet, int start_col, int start_row) */
+/* { */
+/* 	int row, col; */
+/* 	unsigned int lrow, lcol; */
+/* 	GODateConventions const *date_conv; */
+/* 	GStringChunk *lines_chunk; */
+/* 	GPtrArray *lines, *line; */
+
+/* 	SETUP_LOCALE_SWITCH; */
+
+/* 	g_return_val_if_fail (parseoptions != NULL, FALSE); */
+/* 	g_return_val_if_fail (data != NULL, FALSE); */
+/* 	g_return_val_if_fail (IS_SHEET (sheet), FALSE); */
+
+/* 	START_LOCALE_SWITCH; */
+
+/* 	date_conv = workbook_date_conv (sheet->workbook); */
+
+/* 	if (!data_end) */
+/* 		data_end = data + strlen (data); */
+/* 	lines_chunk = g_string_chunk_new (100 * 1024); */
+/* 	lines = stf_parse_general (parseoptions, lines_chunk, data, data_end); */
+/* 	if (lines == NULL) */
+/* 		return FALSE; */
+/* 	for (row = start_row, lrow = 0; lrow < lines->len ; row++, lrow++) { */
+/* 		col = start_col; */
+/* 		line = g_ptr_array_index (lines, lrow); */
+
+/* 		for (lcol = 0; lcol < line->len; lcol++) */
+/* 			if (parseoptions->col_import_array == NULL || */
+/* 			    parseoptions->col_import_array_len <= lcol || */
+/* 			    parseoptions->col_import_array[lcol]) { */
+/* 				if (col >= SHEET_MAX_COLS) { */
+/* 					if (!parseoptions->cols_exceeded) { */
+/* 						g_warning (_("There are more columns of data than " */
+/* 							     "there is room for in the sheet.  Extra " */
+/* 							     "columns will be ignored.")); */
+/* 						parseoptions->cols_exceeded = TRUE; */
+/* 					} */
+/* 				} else { */
+/* 					char const *text = g_ptr_array_index (line, lcol); */
+/* 					if (text && *text) */
+/* 						gnm_cell_set_text ( */
+/* 							sheet_cell_fetch (sheet, col, row), */
+/* 							text); */
+/* 				} */
+/* 				col++; */
+/* 			} */
+/* 	} */
+
+/* 	stf_parse_general_free (lines); */
+/* 	g_string_chunk_free (lines_chunk); */
+/* 	END_LOCALE_SWITCH; */
+/* 	return TRUE; */
+/* } */
+
+/* GnmCellRegion * */
+/* stf_parse_region (StfParseOptions_t *parseoptions, char const *data, char const *data_end, */
+/* 		  Workbook const *wb) */
+/* { */
+/* 	static GODateConventions const default_conv = {FALSE}; */
+/* 	GODateConventions const *date_conv = wb ? workbook_date_conv (wb) : &default_conv; */
+
+/* 	GnmCellRegion *cr; */
+/* 	unsigned int row, colhigh = 0; */
+/* 	char *text; */
+/* 	GStringChunk *lines_chunk; */
+/* 	GPtrArray *lines; */
+/* 	GnmCellCopy	*cc; */
+/* 	GOFormat	*fmt; */
+/* 	GnmValue	*v; */
+
+/* 	SETUP_LOCALE_SWITCH; */
+
+/* 	g_return_val_if_fail (parseoptions != NULL, NULL); */
+/* 	g_return_val_if_fail (data != NULL, NULL); */
+
+/* 	START_LOCALE_SWITCH; */
+
+/* 	cr = cellregion_new (NULL); */
+
+/* 	if (!data_end) */
+/* 		data_end = data + strlen (data); */
+/* 	lines_chunk = g_string_chunk_new (100 * 1024); */
+/* 	lines = stf_parse_general (parseoptions, lines_chunk, data, data_end); */
+/* 	for (row = 0; row < lines->len; row++) { */
+/* 		GPtrArray *line = g_ptr_array_index (lines, row); */
+/* 		unsigned int col, targetcol = 0; */
+/* 		for (col = 0; col < line->len; col++) { */
+/* 			if (parseoptions->col_import_array == NULL || */
+/* 			    parseoptions->col_import_array_len <= col || */
+/* 			    parseoptions->col_import_array[col]) { */
+/* 				if (NULL != (text = g_ptr_array_index (line, col))) { */
+/* 					fmt = g_ptr_array_index ( */
+/* 						parseoptions->formats, col); */
+/* 					if (NULL == (v = format_match (text, fmt, date_conv))) */
+/* 						v = value_new_string (text); */
+
+/* 					cc = gnm_cell_copy_new (cr, targetcol, row); */
+/* 					cc->val  = v; */
+/* 					cc->texpr = NULL; */
+/* 					targetcol++; */
+/* 					if (targetcol > colhigh) */
+/* 						colhigh = targetcol; */
+/* 				} */
+/* 			} */
+/* 		} */
+/* 	} */
+/* 	stf_parse_general_free (lines); */
+/* 	g_string_chunk_free (lines_chunk); */
+
+/* 	END_LOCALE_SWITCH; */
+
+/* 	cr->cols    = (colhigh > 0) ? colhigh : 1; */
+/* 	cr->rows    = row; */
+
+/* 	return cr; */
+/* } */
+
+static int
+int_sort (void const *a, void const *b)
+{
+	return *(int const *)a - *(int const *)b;
+}
+
+static int
+count_character (GPtrArray *lines, gunichar c, double quantile)
+{
+	int *counts, res;
+	unsigned int lno, cno;
+
+	if (lines->len == 0)
+		return 0;
+
+	counts = g_new (int, lines->len);
+	for (lno = cno = 0; lno < lines->len; lno++) {
+		int count = 0;
+		GPtrArray *boxline = g_ptr_array_index (lines, lno);
+		char const *line = g_ptr_array_index (boxline, 0);
+
+		/* Ignore empty lines.  */
+		if (*line == 0)
+			continue;
+
+		while (*line) {
+			if (g_utf8_get_char (line) == c)
+				count++;
+			line = g_utf8_next_char (line);
+		}
+
+		counts[cno++] = count;
+	}
+
+	if (cno == 0)
+		res = 0;
+	else {
+		unsigned int qi = (unsigned int)ceil (quantile * cno);
+		qsort (counts, cno, sizeof (counts[0]), int_sort);
+		if (qi == cno)
+			qi--;
+		res = counts[qi];
+	}
+
+	g_free (counts);
+
+	return res;
+}
+
+
+StfParseOptions_t *
+stf_parse_options_guess (char const *data)
+{
+	StfParseOptions_t *res;
+	GStringChunk *lines_chunk;
+	GPtrArray *lines;
+	int tabcount;
+	int sepcount;
+	gunichar sepchar = go_locale_get_arg_sep ();
+
+	g_return_val_if_fail (data != NULL, NULL);
+
+	res = stf_parse_options_new ();
+	lines_chunk = g_string_chunk_new (100 * 1024);
+	lines = stf_parse_lines (res, lines_chunk, data, SHEET_MAX_ROWS, FALSE);
+
+	tabcount = count_character (lines, '\t', 0.2);
+	sepcount = count_character (lines, sepchar, 0.2);
+
+	/* At least one tab per line and enough to separate every
+	   would-be sepchars.  */
+	if (tabcount >= 1 && tabcount >= sepcount - 1)
+		stf_parse_options_csv_set_separators (res, "\t", NULL);
+	else {
+		gunichar c;
+
+		/*
+		 * Try a few more or less likely characters and pick the first
+		 * one that occurs on at least half the lines.
+		 *
+		 * The order is mostly random, although ' ' and '!' which
+		 * could very easily occur in text are put last.
+		 */
+		if (count_character (lines, (c = sepchar), 0.5) > 0 ||
+		    count_character (lines, (c = go_locale_get_col_sep ()), 0.5) > 0 ||
+		    count_character (lines, (c = ':'), 0.5) > 0 ||
+		    count_character (lines, (c = ','), 0.5) > 0 ||
+		    count_character (lines, (c = ';'), 0.5) > 0 ||
+		    count_character (lines, (c = '|'), 0.5) > 0 ||
+		    count_character (lines, (c = '!'), 0.5) > 0 ||
+		    count_character (lines, (c = ' '), 0.5) > 0) {
+			char sep[7];
+			sep[g_unichar_to_utf8 (c, sep)] = 0;
+			if (c == ' ')
+				strcat (sep, "\t");
+			stf_parse_options_csv_set_separators (res, sep, NULL);
+		}
+	}
+
+	if (1) {
+		/* Separated */
+		gboolean dups =
+			res->sep.chr &&
+			strchr (res->sep.chr, ' ') != NULL;
+		gboolean trim =
+			res->sep.chr &&
+			strchr (res->sep.chr, ' ') != NULL;
+
+		stf_parse_options_set_type (res, PARSE_TYPE_CSV);
+		stf_parse_options_set_trim_spaces (res, TRIM_TYPE_LEFT | TRIM_TYPE_RIGHT);
+		stf_parse_options_csv_set_indicator_2x_is_single (res, TRUE);
+		stf_parse_options_csv_set_duplicates (res, dups);
+		stf_parse_options_csv_set_trim_seps (res, trim);
+
+		stf_parse_options_csv_set_stringindicator (res, '"');
+	} else {
+		/* Fixed-width */
+	}
+
+	stf_parse_general_free (lines);
+	g_string_chunk_free (lines_chunk);
+
+	return res;
+}

Added: gnucash/branches/csv-import/lib/stf/stf-parse.h
===================================================================
--- gnucash/branches/csv-import/lib/stf/stf-parse.h	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/lib/stf/stf-parse.h	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,112 @@
+#ifndef STF_PARSE_H
+#define STF_PARSE_H
+
+#include <glib.h>
+
+#define SHEET_MAX_ROWS          (16*16*16*16)   /* 0, 1, ... */
+#define SHEET_MAX_COLS          (4*4*4*4)       /* 0, 1, ... */
+
+typedef enum {
+	PARSE_TYPE_NOTSET    = 1 << 0,
+	PARSE_TYPE_CSV       = 1 << 1,
+	PARSE_TYPE_FIXED     = 1 << 2
+} StfParseType_t;
+
+/* Additive.  */
+typedef enum {
+	TRIM_TYPE_NEVER      = 0,
+	TRIM_TYPE_LEFT       = 1 << 0,
+	TRIM_TYPE_RIGHT      = 2 << 1
+} StfTrimType_t;
+
+typedef struct {
+	StfParseType_t       parsetype;             /* The type of import to do */
+	StfTrimType_t        trim_spaces;           /* Trim spaces in fields? */
+
+	GSList *             terminator;            /* Line terminators */
+	char *               locale;
+
+	struct {
+		guchar       min, max;
+	} compiled_terminator;
+     
+	/* CSV related */
+	struct {
+		GSList *str;
+		char   *chr;
+	} sep;
+	gunichar             stringindicator;       /* String indicator */
+	gboolean             indicator_2x_is_single;/* 2 quote chars form a single non-terminating quote */
+	gboolean             duplicates;            /* See two text separators as one? */
+	gboolean             trim_seps;             /* Ignore initial seps.  */
+     
+	/* Fixed width related */
+	GArray              *splitpositions;        /* Positions where text will be split vertically */
+     
+	int                  rowcount;              /* Number of rows parsed */
+	int                  colcount;              /* Number of columns parsed */
+        gboolean             *col_import_array;     /* 0/1 array indicating  */
+	                                            /* which cols to import  */
+	unsigned int         col_import_array_len;
+	GPtrArray            *formats       ;       /* Contains GnmFormat *s */
+	gboolean             cols_exceeded;         /* This is set to TRUE if */
+	                                            /* we tried to import more than */
+	                                            /* SHEET_MAX_COLS columns */
+} StfParseOptions_t;
+
+/* CREATION/DESTRUCTION of stf options struct */
+
+StfParseOptions_t  *stf_parse_options_new                             (void);
+void                stf_parse_options_free                            (StfParseOptions_t *parseoptions);
+
+StfParseOptions_t  *stf_parse_options_guess                           (char const *data);
+
+/* MANIPULATION of stf options struct */
+
+void stf_parse_options_set_type                        (StfParseOptions_t *parseoptions,
+							StfParseType_t const parsetype);
+void stf_parse_options_clear_line_terminator           (StfParseOptions_t *parseoptions);
+void stf_parse_options_add_line_terminator             (StfParseOptions_t *parseoptions,
+							char const *terminator);
+void stf_parse_options_set_trim_spaces                 (StfParseOptions_t *parseoptions,
+							StfTrimType_t const trim_spaces);
+void stf_parse_options_csv_set_separators              (StfParseOptions_t *parseoptions,
+							char const *character, GSList const *string);
+void stf_parse_options_csv_set_stringindicator         (StfParseOptions_t *parseoptions,
+							gunichar const stringindicator);
+void stf_parse_options_csv_set_indicator_2x_is_single  (StfParseOptions_t *parseoptions,
+							gboolean const indic_2x);
+void stf_parse_options_csv_set_duplicates              (StfParseOptions_t *parseoptions,
+							gboolean const duplicates);
+void stf_parse_options_csv_set_trim_seps               (StfParseOptions_t *parseoptions,
+							gboolean const trim_seps);
+void stf_parse_options_fixed_splitpositions_clear      (StfParseOptions_t *parseoptions);
+void stf_parse_options_fixed_splitpositions_add        (StfParseOptions_t *parseoptions,
+							int position);
+void stf_parse_options_fixed_splitpositions_remove     (StfParseOptions_t *parseoptions,
+							int position);
+int stf_parse_options_fixed_splitpositions_count       (StfParseOptions_t *parseoptions);
+int stf_parse_options_fixed_splitpositions_nth         (StfParseOptions_t *parseoptions, int n);
+
+/* USING the stf structs to actually do some parsing, these are the lower-level functions and utility functions */
+
+GPtrArray	*stf_parse_general			(StfParseOptions_t *parseoptions,
+							 GStringChunk *lines_chunk,
+							 char const *data,
+							 char const *data_end);
+void		 stf_parse_general_free			(GPtrArray *lines);
+GPtrArray	*stf_parse_lines			(StfParseOptions_t *parseoptions,
+							 GStringChunk *lines_chunk,
+							 char const *data,
+							 int maxlines,
+							 gboolean with_lineno);
+
+void		 stf_parse_options_fixed_autodiscover	(StfParseOptions_t *parseoptions,
+							 char const *data,
+							 char const *data_end);
+
+char const	*stf_parse_find_line			(StfParseOptions_t *parseoptions,
+							 char const *data,
+							 int line);
+
+#endif

Modified: gnucash/branches/csv-import/src/bin/gnucash-bin.c
===================================================================
--- gnucash/branches/csv-import/src/bin/gnucash-bin.c	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/bin/gnucash-bin.c	2007-06-17 01:23:40 UTC (rev 16173)
@@ -337,6 +337,7 @@
         { "gnucash/register/register-gnome", 0, FALSE },
         { "gnucash/import-export/qif-import", 0, FALSE },
         { "gnucash/import-export/ofx", 0, TRUE },
+        { "gnucash/import-export/csv", 0, TRUE },
         { "gnucash/import-export/log-replay", 0, TRUE },
         { "gnucash/import-export/hbci", 0, TRUE },
         { "gnucash/report/report-system", 0, FALSE },

Modified: gnucash/branches/csv-import/src/import-export/Makefile.am
===================================================================
--- gnucash/branches/csv-import/src/import-export/Makefile.am	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/Makefile.am	2007-06-17 01:23:40 UTC (rev 16173)
@@ -1,7 +1,7 @@
 SUBDIRS = . schemas qif qif-import \
-	${OFX_DIR} ${HBCI_DIR} log-replay test
+	${OFX_DIR} ${HBCI_DIR} log-replay test csv
 DIST_SUBDIRS = schemas qif qif-import qif-io-core \
-	ofx hbci log-replay test
+	ofx hbci log-replay test csv
 
 pkglib_LTLIBRARIES=libgncmod-generic-import.la
 

Added: gnucash/branches/csv-import/src/import-export/csv/Makefile.am
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/Makefile.am	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/Makefile.am	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,57 @@
+SUBDIRS = .
+
+pkglib_LTLIBRARIES=libgncmod-csv.la
+
+libgncmod_csv_la_SOURCES = \
+  gncmod-csv-import.c \
+  gnc-plugin-csv.c \
+  gnc-csv-import.c \
+  gnc-csv-model.c
+
+noinst_HEADERS = \
+  gnc-plugin-csv.h \
+  gnc-csv-import.h \
+  gnc-csv-model.h
+
+libgncmod_csv_la_LDFLAGS = -avoid-version $(pkg-config --libs libgoffice-0.3)
+
+libgncmod_csv_la_LIBADD = \
+  ${top_builddir}/src/import-export/libgncmod-generic-import.la \
+  ${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
+  ${top_builddir}/src/app-utils/libgncmod-app-utils.la \
+  ${top_builddir}/src/engine/libgncmod-engine.la \
+  ${top_builddir}/src/core-utils/libgnc-core-utils.la \
+  ${top_builddir}/src/gnc-module/libgnc-module.la \
+  ${top_builddir}/lib/stf/libgnc-stf.la \
+  ${QOF_LIBS} \
+  ${GLIB_LIBS}
+
+AM_CFLAGS = \
+  -I${top_srcdir}/src \
+  -I${top_srcdir}/src/core-utils \
+  -I${top_srcdir}/src/engine \
+  -I${top_srcdir}/src/gnc-module \
+  -I${top_srcdir}/src/app-utils \
+  -I${top_srcdir}/src/gnome \
+  -I${top_srcdir}/src/gnome-utils \
+  -I${top_srcdir}/src/import-export \
+  -I${top_srcdir}/lib \
+  ${GNOME_CFLAGS} \
+  ${GTKHTML_CFLAGS} \
+  ${GLADE_CFLAGS} \
+  ${GUILE_INCS} \
+  ${QOF_CFLAGS} \
+  ${GLIB_CFLAGS} \
+  $(GOFFICE_CFLAGS)
+
+uidir = $(GNC_UI_DIR)
+ui_DATA = \
+	gnc-plugin-csv-ui.xml
+
+gladedir = ${GNC_GLADE_DIR}
+glade_DATA = \
+	gnc-csv-preview-dialog.glade
+
+EXTRA_DIST = $(ui_DATA)
+
+INCLUDES = -DG_LOG_DOMAIN=\"gnc.import.csv\"

Added: gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.c
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.c	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.c	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,422 @@
+/*******************************************************************\
+ * 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                   *
+\********************************************************************/
+/** @addtogroup Import_Export
+    @{ */
+/** @internal
+    @file gnc-csv-import.c
+    @brief Csv import module code
+    @author Copyright (c) 2007 Benny Sperisen <lasindi at gmail.com>
+*/
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+#include <goffice/gtk/go-charmap-sel.h>
+
+#include "import-account-matcher.h"
+#include "import-main-matcher.h"
+
+#include "gnc-file.h"
+#include "gnc-book.h"
+#include "gnc-ui-util.h"
+#include "gnc-glib-utils.h"
+#include "dialog-utils.h"
+
+#include "gnc-csv-import.h"
+#include "gnc-csv-model.h"
+
+#include <stdio.h> /* Get rid of this */
+#include <stdlib.h> /* Get rid of this */
+
+#define GCONF_SECTION "dialogs/import/csv"
+
+static QofLogModule log_module = GNC_MOD_IMPORT;
+
+/* TODO Comment */
+
+enum SEP_BUTTON_TYPES {SEP_SPACE, SEP_TAB, SEP_COMMA, SEP_COLON, SEP_SEMICOLON, SEP_HYPHEN,
+                       SEP_NUM_OF_TYPES};
+
+
+typedef struct
+{
+  GncCsvParseData* parse_data;
+  GladeXML* xml;
+  GtkDialog* dialog;
+  GtkTreeView* treeview;
+  gboolean approved;
+  GtkCheckButton* sep_buttons[SEP_NUM_OF_TYPES];
+  GtkCheckButton* custom_cbutton;
+  GtkEntry* custom_entry;
+} GncCsvPreview;
+
+static void gnc_csv_preview_treeview(GncCsvPreview* preview, gboolean notEmpty);
+
+static void sep_button_clicked(GtkCheckButton* widget, GncCsvPreview* preview)
+{
+  char* sep_chars[] = {" ", "\t", ",", ":", ";", "-"};
+  GSList* separators = NULL;
+  int i;
+  for(i = 0; i < SEP_NUM_OF_TYPES; i++)
+  {
+    if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(preview->sep_buttons[i])))
+      separators = g_slist_append(separators, sep_chars[i]);
+  }
+  if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(preview->custom_cbutton)))
+  {
+    char* custom_sep = (char*)gtk_entry_get_text(preview->custom_entry);
+    if(custom_sep[0] != '\0')
+      separators = g_slist_append(separators, custom_sep);
+  }
+  
+  stf_parse_options_csv_set_separators(preview->parse_data->options, NULL, separators);
+  g_slist_free(separators);
+  /* TODO Handle error */
+  gnc_csv_parse(preview->parse_data, FALSE, NULL);
+  gnc_csv_preview_treeview(preview, TRUE);
+}
+
+static void encoding_selected(GOCharmapSel* selector, const char* enc,
+                              GncCsvPreview* preview)
+{
+  static gboolean second_call = FALSE;
+  if(second_call)
+  {
+    GError* error = NULL;
+    printf("Encoding selected! %p %p %s\n", selector, preview, enc);
+    /* TODO Handle errors */
+    gnc_csv_convert_enc(preview->parse_data, enc);
+    gnc_csv_parse(preview->parse_data, FALSE, &error);
+    gnc_csv_preview_treeview(preview, TRUE);
+    second_call = FALSE;
+  }
+  else
+  {
+    second_call = TRUE;
+  }
+}
+
+static void ok_button_clicked(GtkWidget* widget, GncCsvPreview* preview)
+{
+  preview->approved = TRUE;
+  gtk_widget_hide((GtkWidget*)(preview->dialog));
+}
+
+static void cancel_button_clicked(GtkWidget* widget, GncCsvPreview* preview)
+{
+  gtk_widget_hide((GtkWidget*)(preview->dialog));
+}
+
+static GncCsvPreview* gnc_csv_new_preview()
+{
+  GncCsvPreview* preview = g_malloc(sizeof(GncCsvPreview));
+  GtkWidget *ok_button, *cancel_button;
+  char* sep_button_names[] = {"space_cbutton",
+                              "tab_cbutton",
+                              "comma_cbutton",
+                              "colon_cbutton",
+                              "semicolon_cbutton",
+                              "hyphen_cbutton"};
+  int i;
+  GtkWidget *encselector = go_charmap_sel_new(GO_CHARMAP_SEL_TO_UTF8);
+  GtkTable* enctable;
+  preview->xml = gnc_glade_xml_new("gnc-csv-preview-dialog.glade", "dialog");
+  printf("xml is %p\n", preview->xml);
+  preview->dialog = (GtkDialog*)(glade_xml_get_widget(preview->xml, "dialog"));
+
+  for(i = 0; i < SEP_NUM_OF_TYPES; i++)
+  {
+    preview->sep_buttons[i]
+      = (GtkCheckButton*)glade_xml_get_widget(preview->xml, sep_button_names[i]);
+    g_signal_connect(G_OBJECT(preview->sep_buttons[i]), "toggled",
+                     G_CALLBACK(sep_button_clicked), (gpointer)preview);
+  }
+
+  preview->custom_cbutton
+    = (GtkCheckButton*)glade_xml_get_widget(preview->xml, "custom_cbutton");
+  g_signal_connect(G_OBJECT(preview->custom_cbutton), "clicked",
+                   G_CALLBACK(sep_button_clicked), (gpointer)preview);
+
+  preview->custom_entry = (GtkEntry*)glade_xml_get_widget(preview->xml, "custom_entry");
+  g_signal_connect(G_OBJECT(preview->custom_entry), "changed",
+                   G_CALLBACK(sep_button_clicked), (gpointer)preview);
+
+  enctable = GTK_TABLE(glade_xml_get_widget(preview->xml, "enctable"));
+  gtk_table_attach_defaults(enctable, encselector, 1, 2, 0, 1);
+  gtk_widget_show_all(GTK_WIDGET(enctable));
+  g_signal_connect(G_OBJECT(encselector), "charmap_changed",
+                   G_CALLBACK(encoding_selected), (gpointer)preview);
+
+  ok_button = glade_xml_get_widget(preview->xml, "ok_button");
+  g_signal_connect(G_OBJECT(ok_button), "clicked",
+                   G_CALLBACK(ok_button_clicked), (gpointer)preview);
+
+  cancel_button = glade_xml_get_widget(preview->xml, "cancel_button");
+  g_signal_connect(G_OBJECT(cancel_button), "clicked",
+                   G_CALLBACK(cancel_button_clicked), (gpointer)preview);
+
+  preview->treeview = (GtkTreeView*)(glade_xml_get_widget(preview->xml, "treeview"));
+  printf("treeview is %p \n", preview->treeview);
+  
+  preview->approved = FALSE;
+  return preview;
+}
+
+
+static void gnc_csv_preview_free(GncCsvPreview* preview)
+{
+  g_object_unref(preview->xml);
+  g_free(preview);
+}
+
+static void gnc_csv_preview_treeview(GncCsvPreview* preview, gboolean notEmpty)
+{
+  GtkListStore* store;
+  GtkTreeIter iter;
+  int i, j, ncols = preview->parse_data->column_types->len;
+  GType* types = g_malloc(ncols * sizeof(GType));
+  for(i = 0; i < ncols; i++)
+    types[i] = G_TYPE_STRING;
+  store = gtk_list_store_newv(ncols, types);
+
+  /* Clear out any exisiting columns. */
+  if(notEmpty)
+  {
+    int size;
+    do
+    {
+      GtkTreeViewColumn* col = gtk_tree_view_get_column(preview->treeview, 0);
+      size = gtk_tree_view_remove_column(preview->treeview, col);
+    } while(size);
+  }
+  
+  /* TODO free types */
+
+  for(i = 0; i < preview->parse_data->orig_lines->len; i++)
+  {
+    gtk_list_store_append(store, &iter);
+    for(j = 0; j < ((GPtrArray*)(preview->parse_data->orig_lines->pdata[i]))->len; j++)
+    {
+      gtk_list_store_set(store, &iter, j,
+                         ((GPtrArray*)(preview->parse_data->orig_lines->pdata[i]))->pdata[j],
+                         -1);
+    }
+  }
+
+  for(i = 0; i < ncols; i++)
+  {
+    GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
+    gtk_tree_view_insert_column_with_attributes(preview->treeview,
+                                                -1, "", renderer, "text", i, NULL);
+  }
+  
+  gtk_tree_view_set_model(preview->treeview, GTK_TREE_MODEL(store));
+  g_object_unref(GTK_TREE_MODEL(store));
+}
+
+static int gnc_csv_preview(GncCsvPreview* preview, GncCsvParseData* parse_data)
+{
+  preview->parse_data = parse_data;
+  gnc_csv_preview_treeview(preview, FALSE);
+  gtk_dialog_run(GTK_DIALOG(preview->dialog));
+
+  if(preview->approved)
+    return 0;
+  else
+    return 1;
+}
+
+typedef struct
+{
+  GncCsvParseData* parse_data;
+  char approved;
+  char* encoding;
+} EncodingDialog;
+
+static void encoding_dialog_selected(GOCharmapSel* selector, const char* enc,
+                                     EncodingDialog* encdialog)
+{
+  static gboolean second_call = FALSE;
+  if(second_call)
+  {
+    printf("set encoding %s\n", enc);
+    encdialog->encoding = (char*)enc;
+    second_call = FALSE;
+  }
+  else
+  {
+    second_call = TRUE;
+  }
+}
+
+static void enc_ok_button_clicked(GtkWidget* button, EncodingDialog* encdialog)
+{
+  printf("OK!\n");
+  printf("using dialog encoding %s\n", encdialog->encoding);
+  if(!gnc_csv_convert_enc(encdialog->parse_data, encdialog->encoding))
+    encdialog->approved = 1;
+}
+
+static void enc_cancel_button_clicked(GtkWidget* button, EncodingDialog* encdialog)
+{
+  printf("cancel!\n");
+  encdialog->approved = -1;
+}
+
+static int gnc_csv_encoding_dialog(GncCsvParseData* parse_data)
+{
+  EncodingDialog* encdialog = g_malloc(sizeof(encdialog));
+  GladeXML* xml;
+  GtkWidget *ok_button, *cancel_button;
+  GOCharmapSel* encselector = (GOCharmapSel*)go_charmap_sel_new(GO_CHARMAP_SEL_TO_UTF8);
+  GtkVBox* vbox;
+  GtkDialog* dialog;
+  encdialog->parse_data = parse_data;
+  encdialog->encoding = (char*)go_charmap_sel_get_encoding(encselector);
+  encdialog->approved = 0;
+  xml = gnc_glade_xml_new("preview-dialog.glade", "encdialog");
+  dialog = (GtkDialog*)(glade_xml_get_widget(xml, "encdialog"));
+
+  vbox = GTK_VBOX(glade_xml_get_widget(xml, "encvbox"));
+  gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(encselector), TRUE, TRUE, 5);
+  gtk_widget_show_all(GTK_WIDGET(vbox));
+  g_signal_connect(G_OBJECT(encselector), "charmap_changed",
+                   G_CALLBACK(encoding_dialog_selected), (gpointer)encdialog);
+
+  ok_button = glade_xml_get_widget(xml, "enc_ok_button");
+  g_signal_connect(G_OBJECT(ok_button), "clicked",
+                   G_CALLBACK(enc_ok_button_clicked), (gpointer)encdialog);
+
+  cancel_button = glade_xml_get_widget(xml, "enc_cancel_button");
+  g_signal_connect(G_OBJECT(cancel_button), "clicked",
+                   G_CALLBACK(enc_cancel_button_clicked), (gpointer)encdialog);
+
+  gtk_dialog_run(GTK_DIALOG(dialog));
+
+  g_object_unref(xml);
+  /* TODO Free stuff */
+
+  return encdialog->approved;
+}
+
+/* The function that actually imports a CSV/Fixed-Width file. */
+/* TODO Comment this function. */
+void gnc_file_csv_import(void)
+{
+  const char *selected_filename;
+  char *default_dir;
+  GNCImportMainMatcher* gnc_csv_importer_gui = NULL;
+
+  default_dir = gnc_get_default_directory(GCONF_SECTION);
+
+  selected_filename = gnc_file_dialog(_("Select an CSV/Fixed-Width file to import"),
+				      NULL,
+				      default_dir,
+				      GNC_FILE_DIALOG_IMPORT);
+  g_free(default_dir);
+
+  if(selected_filename!=NULL)
+  {
+    Account* account;
+    int i;
+    GncCsvParseData* parse_data;
+    GError* error = NULL;
+    GList *transactions;
+    GncCsvPreview* preview;
+    
+    /* Remember the directory as the default. */
+    default_dir = g_path_get_dirname(selected_filename);
+    gnc_set_default_directory(GCONF_SECTION, default_dir);
+    g_free(default_dir);
+
+    /* TODO Check for errors */
+
+    parse_data = gnc_csv_new_parse_data();
+    if(gnc_csv_load_file(parse_data, selected_filename, &error))
+    {
+      if(error->code == GNC_CSV_ENCODING_ERR)
+      {
+        int result;
+        do
+        {
+          result = gnc_csv_encoding_dialog(parse_data);
+        } while(result == 0);
+        if(result == -1)
+        {
+          printf("Canceled!\n");
+        }
+        else
+        {
+          printf("Success!\n");
+        }
+      }
+      else /* GNC_CSV_FILE_OPEN_ERR */
+      {
+        /* TODO Do real error handling */
+        printf("Couldn't open file\n");
+      }
+    }
+    if(gnc_csv_parse(parse_data, TRUE, &error))
+    {
+      /* TODO real error handling */
+      printf("Error in parsing: %s\n", error->message);
+    }
+
+    parse_data->column_types->data[0] = GNC_CSV_DATE;
+    parse_data->column_types->data[1] = GNC_CSV_DESCRIPTION;
+    parse_data->column_types->data[2] = GNC_CSV_AMOUNT;
+    printf("1ctype 1: %d\n", parse_data->column_types->data[0]);
+
+    preview = gnc_csv_new_preview();
+    if(gnc_csv_preview(preview, parse_data))
+    {
+      gnc_csv_preview_free(preview);
+      gnc_csv_parse_data_free(parse_data);
+      return;
+    }
+
+    /* TODO Move this after the parsing code. */
+    account = gnc_import_select_account(NULL, NULL, 1, NULL, NULL, 0, NULL, NULL);
+    printf("2ctype 1: %d\n", parse_data->column_types->data[0]);
+
+    gnc_parse_to_trans(parse_data, account);
+    printf("3ctype 1: %d\n", parse_data->column_types->data[0]);
+
+    /* Create the Generic transaction importer GUI. */
+    gnc_csv_importer_gui = gnc_gen_trans_list_new(NULL, NULL, FALSE, 42);
+    printf("4ctype 1: %d\n", parse_data->column_types->data[0]);
+
+    transactions = parse_data->transactions;
+    while(transactions != NULL)
+    {
+      gnc_gen_trans_list_add_trans(gnc_csv_importer_gui,
+                                   (Transaction*)(transactions->data));
+      transactions = g_list_next(transactions);
+    }
+    gnc_gen_trans_list_run(gnc_csv_importer_gui);
+    
+    gnc_csv_preview_free(preview);
+    gnc_csv_parse_data_free(parse_data);
+  }
+}
+
+
+
+/** @} */

Added: gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.h
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.h	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.h	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,33 @@
+/********************************************************************\
+ * 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                   *
+\********************************************************************/
+ /** @file
+     @brief Csv import module interface
+     *
+     gnc-csv-import.h
+     @author Copyright (c) 2007 Benny Sperisen <lasindi at gmail.com>
+ */
+#ifndef CSV_IMPORT_H
+#define CSV_IMPORT_H
+
+/** The gnc_file_csv_import() will let the user select a
+ * CSV/Fixed-Width file to open, select an account to import it to,
+ * and import the transactions into the account. It also allows the
+ * user to configure how the file is parsed. */
+void              gnc_file_csv_import (void);
+#endif

Added: gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.c
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.c	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.c	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,300 @@
+#include "gnc-csv-model.h"
+
+#include "gnc-book.h"
+
+#include <goffice/utils/go-glib-extras.h>
+
+#include <string.h>
+#include <sys/time.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <stdio.h> /* Get rid of this */
+
+/* Returns a set of sensible defaults for parsing CSV files. */
+static StfParseOptions_t* default_parse_options(void)
+{
+  StfParseOptions_t* options = stf_parse_options_new();
+  stf_parse_options_set_type(options, PARSE_TYPE_CSV);
+  stf_parse_options_csv_set_separators(options, ",", NULL);
+  return options;
+}
+
+/* TODO This will be replaced by something more sophisticated. */
+time_t parse_date(const char* date_str);
+
+time_t parse_date(const char* date_str)
+{
+  struct tm retvalue;
+  char mstr[3], dstr[3], ystr[3];
+  strncpy(mstr, date_str, 2);
+  strncpy(dstr, date_str + 3, 2);
+  strncpy(ystr, date_str + 6, 2);
+  mstr[2] = dstr[2] = ystr[2] = '\0';
+  retvalue.tm_mon = atoi(mstr) - 1;
+  retvalue.tm_mday = atoi(dstr);
+  retvalue.tm_year = atoi(ystr);
+  if(retvalue.tm_year < 10)
+    retvalue.tm_year += 100;
+  retvalue.tm_hour = 0;
+  retvalue.tm_min = 0;
+  retvalue.tm_sec = 1;
+  retvalue.tm_isdst = -1;
+  return mktime(&retvalue);
+}
+
+/* TODO Comment. */
+GncCsvStr file_to_string(const char* filename, GError** error)
+{
+  /* The file descriptor for opening the file, a flag indicating
+   * whether the file actually exists, the length of the file */
+  int fd, exists, length, max_cols = 0, i;
+
+  struct stat buf; /* Used to find file size */
+
+  /* What we want to return. */
+  GncCsvStr file_str;
+
+  /* Make sure filename is meaningful. */
+  if(filename == NULL)
+  {
+    g_set_error(error, 0, 0, "Received NULL filename.");
+    file_str.begin = file_str.end = NULL;
+    return file_str;
+  }
+
+  exists = stat(filename, &buf);
+  /* Make sure the file exists. */
+  if(exists == -1)
+  {
+    g_set_error(error, 0, 0, "File %s does not exist.", filename);
+    file_str.begin = file_str.end = NULL;
+    return file_str;
+  }
+
+  /* Now we can get the length of the file out of buf. */
+  length = (int)(buf.st_size);
+
+  /* Put the file's contents into a string starting at data_begin. */
+  fd = open(filename, O_RDONLY);
+  file_str.begin = mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
+  file_str.end = file_str.begin + length - 1; /* Point data_end to the end. */
+  close(fd);
+
+  return file_str;
+}
+
+/* TODO Comment */
+GncCsvParseData* gnc_csv_new_parse_data(void)
+{
+  GncCsvParseData* parse_data = g_malloc(sizeof(GncCsvParseData));
+  parse_data->encoding = "UTF-8";
+  parse_data->raw_str.begin = parse_data->raw_str.end
+    = parse_data->file_str.begin = parse_data->file_str.end = NULL;
+  parse_data->orig_lines = NULL;
+  parse_data->column_types = NULL;
+  parse_data->error_lines = parse_data->transactions = NULL;
+  parse_data->options = default_parse_options();
+  return parse_data;
+}
+
+/* TODO Comment */
+void gnc_csv_parse_data_free(GncCsvParseData* parse_data)
+{
+  if(parse_data->raw_str.begin != NULL)
+    munmap(parse_data->raw_str.begin,
+           parse_data->raw_str.end - parse_data->raw_str.begin);
+  if(parse_data->file_str.begin != NULL)
+    g_free(parse_data->file_str.begin);
+  if(parse_data->orig_lines != NULL)
+    g_ptr_array_free(parse_data->orig_lines, TRUE);
+  if(parse_data->options != NULL)
+    stf_parse_options_free(parse_data->options);
+  if(parse_data->column_types != NULL)
+    g_array_free(parse_data->column_types, TRUE);
+  if(parse_data->error_lines != NULL)
+    g_list_free(parse_data->error_lines);
+  /* TODO Find out if there's a potential memory leak here. */
+  if(parse_data->transactions != NULL)
+    g_list_free(parse_data->transactions);
+  g_free(parse_data);
+}
+
+/* TODO Comment */
+int gnc_csv_convert_enc(GncCsvParseData* parse_data, const char* enc)
+{
+  GError* error;
+  gsize bytes_read, bytes_written;
+  if(parse_data->file_str.begin != NULL)
+  {
+    g_free(parse_data->file_str.begin);
+  }
+  parse_data->file_str.begin = g_convert(parse_data->raw_str.begin,
+                                         parse_data->raw_str.end - parse_data->raw_str.begin,
+                                         "UTF-8", enc, &bytes_read,
+                                         &bytes_written, &error);
+  printf("using %s got %p\n", enc, parse_data->file_str.begin);
+  if(parse_data->file_str.begin == NULL)
+  {
+    return 1;
+  }
+  parse_data->file_str.end = parse_data->file_str.begin + bytes_written;
+  parse_data->encoding = (gchar*)enc;
+  return 0;
+}
+
+/* TODO Comment */
+int gnc_csv_load_file(GncCsvParseData* parse_data, const char* filename,
+                      GError** error)
+{
+  const char* guess_enc;
+  parse_data->raw_str = file_to_string(filename, error);
+  if(parse_data->raw_str.begin == NULL)
+  {
+    g_set_error(error, 0, GNC_CSV_FILE_OPEN_ERR, "File opening failed.");
+    return 1;
+  }
+  guess_enc = go_guess_encoding((const char*)(parse_data->raw_str.begin),
+                                (size_t)(parse_data->raw_str.end - parse_data->raw_str.begin),
+                                "UTF-8", NULL);
+  printf("Guessed %s\n", guess_enc);
+  /* TODO Handle error */
+  gnc_csv_convert_enc(parse_data, guess_enc);
+  if(parse_data->file_str.begin == NULL)
+  {
+    g_set_error(error, 0, GNC_CSV_ENCODING_ERR, "Encoding conversion failed.");
+    return 1;
+  }
+  else
+    return 0;
+}
+
+/* TODO Comment. */
+/* TODO Should we use 0 for domain and code in errors? */
+int gnc_csv_parse(GncCsvParseData* parse_data, gboolean guessColTypes, GError** error)
+{
+  GStringChunk* chunk; /* TODO Find out exactly what this is. */
+  int i, max_cols = 0;
+
+  /* Do the actual parsing. */
+  /* TODO: This size might have to change ... because I'm not exactly
+   * sure what it's for. ... */
+  chunk = g_string_chunk_new(100);
+  parse_data->orig_lines = stf_parse_general(parse_data->options, chunk,
+                                             parse_data->file_str.begin,
+                                             parse_data->file_str.end);
+  g_string_chunk_free(chunk);
+  if(parse_data->orig_lines == NULL) /* If it failed, generate an error message. */
+  {
+    g_set_error(error, 0, 0, "Parsing failed.");
+    return 1;
+  }
+
+  /* Now that we have data, let's update max_cols. */
+  for(i = 0; i < parse_data->orig_lines->len; i++)
+  {
+    if(max_cols < ((GPtrArray*)(parse_data->orig_lines->pdata[i]))->len)
+      max_cols = ((GPtrArray*)(parse_data->orig_lines->pdata[i]))->len;
+  }
+  printf("max_cols %d\n", max_cols);
+
+  if(guessColTypes)
+  {
+    if(parse_data->column_types != NULL)
+      g_array_free(parse_data->column_types, TRUE);
+    parse_data->column_types = g_array_sized_new(FALSE, FALSE, sizeof(int),
+                                                 max_cols);
+    g_array_set_size(parse_data->column_types, max_cols);
+    for(i = 0; i < parse_data->column_types->len; i++)
+    {
+      parse_data->column_types->data[i] = GNC_CSV_NONE;
+    }
+  }
+  else
+  {
+    int i = parse_data->column_types->len;
+    g_array_set_size(parse_data->column_types, max_cols);
+    for(; i < parse_data->column_types->len; i++)
+    {
+      parse_data->column_types->data[i] = GNC_CSV_NONE;
+    }
+  }
+
+  return 0;
+}
+
+/* TODO Comment. */
+int gnc_parse_to_trans(GncCsvParseData* parse_data, Account* account)
+{
+  int i, j;
+  GArray* column_types = parse_data->column_types;
+  GNCBook* book = gnc_account_get_book(account);
+
+  if(parse_data->error_lines != NULL)
+  {
+    g_list_free(parse_data->error_lines);
+    parse_data->error_lines = NULL;
+  }
+  if(parse_data->transactions != NULL)
+  {
+    g_list_free(parse_data->transactions);
+    parse_data->transactions = NULL;
+  }
+  
+  for(i = 0; i < parse_data->orig_lines->len; i++)
+  {
+    Transaction* trans = xaccMallocTransaction(book);
+    gboolean noErrors = TRUE;
+    GPtrArray* line = parse_data->orig_lines->pdata[i];
+    time_t date;
+    const char* description;
+    gnc_numeric amount;
+    Split* split;
+    xaccTransBeginEdit(trans);
+    for(j = column_types->len - 1; j >= 0; j--)
+    {
+      if(column_types->data[j] != GNC_CSV_NONE)
+      {
+        /* If this line is too short, it goes in errors list. */
+        if(j >= line->len)
+        {
+          parse_data->error_lines = g_list_append(parse_data->error_lines,
+                                                  line);
+          xaccTransDestroy(trans);
+          noErrors = FALSE;
+          break;
+        }
+        /* Affect the transaction appropriately. */
+        if(column_types->data[j] == GNC_CSV_DATE)
+        {
+          date = parse_date(line->pdata[j]);
+          xaccTransSetDatePostedSecs(trans, date);
+        }
+        else if(column_types->data[j] == GNC_CSV_DESCRIPTION)
+        {
+          description = line->pdata[j];
+          xaccTransSetDescription(trans, description);
+        }
+        else if(column_types->data[j] == GNC_CSV_AMOUNT)
+        {
+          amount = double_to_gnc_numeric(atof(line->pdata[j]), 1,
+                                         GNC_RND_ROUND);
+          split = xaccMallocSplit(book);
+          xaccSplitSetAccount(split, account);
+          xaccSplitSetParent(split, trans);
+          xaccSplitSetAmount(split, amount);
+          xaccSplitSetValue(split, amount);
+          xaccSplitSetAction(split, "Deposit");
+        }
+      }
+    }
+    if(noErrors)
+      parse_data->transactions = g_list_append(parse_data->transactions, trans);
+  }
+  return 0;
+}

Added: gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.h
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.h	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.h	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,59 @@
+#ifndef GNC_CSV_MODEL_H
+#define GNC_CSV_MODEL_H
+
+#include "config.h"
+
+#include "Account.h"
+#include "Transaction.h"
+
+#include "stf/stf-parse.h"
+
+/* TODO Comment. */
+enum GncCsvColumnType {GNC_CSV_NONE,
+                       GNC_CSV_DATE,
+                       GNC_CSV_DESCRIPTION,
+                       GNC_CSV_AMOUNT};
+
+enum GncCsvErrorType {GNC_CSV_FILE_OPEN_ERR,
+                      GNC_CSV_ENCODING_ERR};
+
+typedef struct
+{
+  char* begin;
+  char* end;
+} GncCsvStr;
+
+typedef struct
+{
+  int line_no;
+  Transaction* trans;
+} GncCsvTransLine;
+
+typedef struct
+{
+  gchar* encoding;
+  GncCsvStr raw_str;
+  GncCsvStr file_str;
+  GPtrArray* orig_lines;
+  StfParseOptions_t* options;
+  GArray* column_types;
+  GList* error_lines;
+  GList* transactions;
+} GncCsvParseData;
+
+GncCsvParseData* gnc_csv_new_parse_data(void);
+
+void gnc_csv_parse_data_free(GncCsvParseData* parse_data);
+
+int gnc_csv_convert_enc(GncCsvParseData* parse_data, const char* enc);
+
+int gnc_csv_load_file(GncCsvParseData* parse_data, const char* filename,
+                      GError** error);
+
+int gnc_csv_parse(GncCsvParseData* parse_data, gboolean guessColTypes, GError** error);
+
+int gnc_parse_to_trans(GncCsvParseData* parse_data, Account* account);
+
+GncCsvStr file_to_string(const char* filename, GError** error);
+
+#endif

Added: gnucash/branches/csv-import/src/import-export/csv/gnc-csv-preview-dialog.glade
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv-preview-dialog.glade	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv-preview-dialog.glade	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,463 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.2.0 on Sat Jun 16 19:20:02 2007 by lasindi at pi-->
+<glade-interface>
+  <widget class="GtkDialog" id="dialog">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Import CSV/Fixed-Width File</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <widget class="GtkTable" id="enctable">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="n_rows">4</property>
+                <property name="n_columns">2</property>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <widget class="GtkHSeparator" id="hseparator1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                    <property name="y_padding">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkHSeparator" id="hseparator2">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                    <property name="y_padding">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkHBox" id="hbox1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <widget class="GtkRadioButton" id="radiobutton1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Separated</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkRadioButton" id="radiobutton3">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Fixed-Width</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">radiobutton1</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">Data type: </property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkHSeparator" id="hseparator4">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkHSeparator" id="hseparator5">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                    <property name="y_padding">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">Encoding: </property>
+                  </widget>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">GTK_SHADOW_NONE</property>
+                <child>
+                  <widget class="GtkAlignment" id="alignment1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <widget class="GtkTable" id="table2">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="n_rows">3</property>
+                        <property name="n_columns">3</property>
+                        <property name="column_spacing">3</property>
+                        <property name="row_spacing">3</property>
+                        <child>
+                          <widget class="GtkCheckButton" id="space_cbutton">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">Space</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="y_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="tab_cbutton">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">Tab</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                            <property name="y_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="comma_cbutton">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">Comma (,)</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="left_attach">2</property>
+                            <property name="right_attach">3</property>
+                            <property name="y_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="colon_cbutton">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">Colon (:)</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="semicolon_cbutton">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">Semicolon (;)</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="hyphen_cbutton">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">Hyphen (-)</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="left_attach">2</property>
+                            <property name="right_attach">3</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="custom_cbutton">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">Custom</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkEntry" id="custom_entry">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                          </widget>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">3</property>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">Separators</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHSeparator" id="hseparator6">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">3</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox2">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="typehbox">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <placeholder/>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkTreeView" id="treeview">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="headers_clickable">True</property>
+                <property name="enable_grid_lines">GTK_TREE_VIEW_GRID_LINES_BOTH</property>
+              </widget>
+              <packing>
+                <property name="position">5</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="ok_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="encdialog">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox2">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="encvbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <widget class="GtkLabel" id="enclabel">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area2">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="enc_cancel_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="enc_ok_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Deleted: gnucash/branches/csv-import/src/import-export/csv/gnc-csv2glist.c
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv2glist.c	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv2glist.c	2007-06-17 01:23:40 UTC (rev 16173)
@@ -1,187 +0,0 @@
-
-/*
-    Copyright 2004 Kevin dot Hammack at comcast dot net
-
-    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, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-    02110-1301 USA
-
-
- */
-
-//#include "config.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-//#include "file-utils.h"
-
-#define TEST_CSV
-
-/*
-  <warlord> Yea, just returning a GList would be fine..  Or a GList of
-  GLists, one per row..  
-*/
-
-
-/* 
-   split_csv_list - Take a string, split on commas into a GList.  
-   Tricky part: honor quotes.  
-   Quotes aren't stripped.  
-   This would have been both easier and cleaner in scheme, and / or
-   using regular expressions.  
-   I was thinking small and fast when I wrote it. :-P
-*/
-
-static GList *
-split_csv_line(char *line) {
-     GList *csvlist = NULL;
-     gchar *begin;
-     gchar *current;
-     gchar *cell;
-     gchar quote=0;
-     gboolean eol = FALSE;
-
-     current = line;
-     begin = current;
-
-     while (!eol) {
-	  
-	  if (quote && 
-	      (*current == quote) && (*(current-1) != '\\') && 
-	      (current != begin)) {
-
-	       quote = 0;
-	  }
-	  else if (!quote && (*current == '"')) { quote = '"'; }
-	  else if (!quote && (*current == '\'')) { quote = '\''; }
-
-	  if (!quote && (*current == ',')) { *current = 0; }
-
-	  if (*current == '\n') {
-	       *current = 0;
-	       eol = TRUE;
-	  }
-
-	  if (*current == 0) {
-	       cell = g_strdup( begin );
-	       csvlist = g_list_prepend(csvlist, cell);
-	       current++;
-	       begin = current;
-	       quote = 0;
-	  }
-	  else {
-	       current++;
-	  }
-
-     }
-
-     return g_list_reverse(csvlist);
-}
-
-
-#if 1
-gint64
-gnc_getline (gchar **line, FILE *file)
-{
-  char str[BUFSIZ];
-  gint64 len;
-  GString *gs = g_string_new("");
-
-  if (!line || !file) return 0;
-
-  while (fgets(str, sizeof(str), file) != NULL) {
-    g_string_append(gs, str);
-
-    len = strlen(str);
-    if (str[len-1] == '\n')
-      break;
-  }
-
-  len = gs->len;
-  *line = g_string_free(gs, FALSE);
-  return len;
-}
-#endif
-
-
-GList *
-gnc_csv_parse (FILE *handle) 
-{
-     GList *csvlists = NULL;
-     ssize_t bytes_read;
-     char *line;
-    
-     while (bytes_read = gnc_getline (&line, handle) > 0) {
-	  csvlists = g_list_prepend(csvlists, split_csv_line(line));
-	  g_free(line);
-     }
-
-     return g_list_reverse(csvlists);
-}
-
-
-
-#ifdef TEST_CSV
-
-static void print_glist_rec (GList *list) {
-
-}
-//     print_glist_rec(list);
-
-static void print_glist(GList *list, gpointer dummy) {
-
-     printf("%d: (", g_list_length(list));
-     
-     while (list != NULL) {  
-	  if ((list->data != NULL) && ( *((char *) list->data) != 0)) {
-	       printf( "%s",  list->data) ;
-	  }
-	  else {
-	       printf( "\"\"" );
-	  }
-	  list = list->next;
-	  if (list) {
-	       printf(" ");
-	  }
-     }
-
-     printf(")\n");
-}
- 
-int main (int argc, char **argv) {
-
-     FILE *fp;
-     int result;
-     GList *parsed_csv;
-     GList *current;
-     int dummy = 1;
-
-     if (argc < 2) {
-	  printf("usage:\n\tcsv2glist fname.csv\n");
-     }
-
-     fp = g_fopen (argv[1], "r");
-     if (fp == NULL) return 1;
-
-     parsed_csv = gnc_csv_parse(fp);
-
-     g_list_foreach(parsed_csv, (GFunc)print_glist, &dummy);
-
-}
-
-#endif

Deleted: gnucash/branches/csv-import/src/import-export/csv/gnc-csv2glist.h
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv2glist.h	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv2glist.h	2007-06-17 01:23:40 UTC (rev 16173)
@@ -1,39 +0,0 @@
-/*
- * gnc-csv2glist.h -- Parse Comma Separated Variable files
- *
- * Created by:  Derek Atkins <derek at ihtfp.com>
- * Copyright (c) 2004 Derek Atkins <derek at ihtfp.com>
- *
- * 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 GNC_IMPORT_CSV_2GLIST_H
-#define GNC_IMPORT_CSV_2GLIST_H
-
-/**
- * gnc_csv_parse -- parse a Comma Separated Variable FILE into
- *                  a list of lists of values.
- *
- * Args:  file : the input file to read
- * Returns     : a list of lists of strings.  Both lists and all strings
- *               must be g_free()'d by the caller.
- */
-
-GList * gnc_csv_parse (FILE *file);
-
-#endif

Added: gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv-ui.xml
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv-ui.xml	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv-ui.xml	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,11 @@
+<ui>
+  <menubar>
+    <menu name="File" action="FileAction">
+      <menu name="FileImport" action="FileImportAction">
+      	<placeholder name="FileImportPlaceholder">
+      	   <menuitem name="FileCsvImport" action="CsvImportAction"/>
+      	</placeholder>
+      </menu>
+    </menu>
+  </menubar>
+</ui>

Added: gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv.c
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv.c	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv.c	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,160 @@
+/* 
+ * gnc-plugin-csv.c -- 
+ * Copyright (C) 2003 David Hampton <hampton at employees.org>
+ *
+ * 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 "config.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "gnc-plugin-csv.h"
+#include "gnc-plugin-manager.h"
+
+#include "gnc-csv-import.h"
+
+static void gnc_plugin_csv_class_init (GncPluginCsvClass *klass);
+static void gnc_plugin_csv_init (GncPluginCsv *plugin);
+static void gnc_plugin_csv_finalize (GObject *object);
+
+/* Command callbacks */
+static void gnc_plugin_csv_cmd_import (GtkAction *action, GncMainWindowActionData *data);
+
+
+#define PLUGIN_ACTIONS_NAME "gnc-plugin-csv-actions"
+#define PLUGIN_UI_FILENAME  "gnc-plugin-csv-ui.xml"
+
+static GtkActionEntry gnc_plugin_actions [] = {
+  { "CsvImportAction", GTK_STOCK_CONVERT, N_("Import _CSV/Fixed-Width..."), NULL,
+    N_(" a CSV/Fixed-Width file"),
+    G_CALLBACK (gnc_plugin_csv_cmd_import) },
+};
+static guint gnc_plugin_n_actions = G_N_ELEMENTS (gnc_plugin_actions);
+
+typedef struct GncPluginCsvPrivate
+{
+  gpointer dummy;
+} GncPluginCsvPrivate;
+
+#define GNC_PLUGIN_CSV_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_CSV, GncPluginCsvPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+GType
+gnc_plugin_csv_get_type (void)
+{
+  static GType gnc_plugin_csv_type = 0;
+
+  if (gnc_plugin_csv_type == 0) {
+    static const GTypeInfo our_info = {
+		sizeof (GncPluginCsvClass),
+		NULL,		/* base_init */
+		NULL,		/* base_finalize */
+		(GClassInitFunc) gnc_plugin_csv_class_init,
+		NULL,		/* class_finalize */
+		NULL,		/* class_data */
+		sizeof (GncPluginCsv),
+		0,		/* n_preallocs */
+		(GInstanceInitFunc) gnc_plugin_csv_init,
+    };
+
+    gnc_plugin_csv_type = g_type_register_static (GNC_TYPE_PLUGIN,
+						  "GncPluginCsv",
+						  &our_info, 0);
+  }
+
+  return gnc_plugin_csv_type;
+}
+
+GncPlugin *
+gnc_plugin_csv_new (void)
+{
+  return GNC_PLUGIN (g_object_new (GNC_TYPE_PLUGIN_CSV, NULL));
+}
+
+static void
+gnc_plugin_csv_class_init (GncPluginCsvClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GncPluginClass *plugin_class = GNC_PLUGIN_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->finalize = gnc_plugin_csv_finalize;
+
+  /* plugin info */
+  plugin_class->plugin_name  = GNC_PLUGIN_CSV_NAME;
+
+  /* widget addition/removal */
+  plugin_class->actions_name = PLUGIN_ACTIONS_NAME;
+  plugin_class->actions      = gnc_plugin_actions;
+  plugin_class->n_actions    = gnc_plugin_n_actions;
+  plugin_class->ui_filename  = PLUGIN_UI_FILENAME;
+
+  g_type_class_add_private(klass, sizeof(GncPluginCsvPrivate));
+}
+
+static void
+gnc_plugin_csv_init (GncPluginCsv *plugin)
+{
+}
+
+static void
+gnc_plugin_csv_finalize (GObject *object)
+{
+  GncPluginCsv *plugin;
+  GncPluginCsvPrivate *priv;
+
+  g_return_if_fail (GNC_IS_PLUGIN_CSV (object));
+
+  plugin = GNC_PLUGIN_CSV (object);
+  priv = GNC_PLUGIN_CSV_GET_PRIVATE(plugin);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/************************************************************
+ *              Plugin Function Implementation              *
+ ************************************************************/
+
+/************************************************************
+ *                    Command Callbacks                     *
+ ************************************************************/
+
+static void
+gnc_plugin_csv_cmd_import (GtkAction *action,
+			   GncMainWindowActionData *data)
+{
+  gnc_file_csv_import();
+}
+
+
+/************************************************************
+ *                    Plugin Bootstrapping                   *
+ ************************************************************/
+
+void
+gnc_plugin_csv_create_plugin (void)
+{
+  GncPlugin *plugin = gnc_plugin_csv_new ();
+
+  gnc_plugin_manager_add_plugin (gnc_plugin_manager_get (), plugin);
+}

Added: gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv.h
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv.h	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-plugin-csv.h	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,60 @@
+/* 
+ * gnc-plugin-csv.h -- 
+ * Copyright (C) 2003 David Hampton <hampton at employees.org>
+ *
+ * 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 __GNC_PLUGIN_CSV_H
+#define __GNC_PLUGIN_CSV_H
+
+#include <gtk/gtkwindow.h>
+
+#include "gnc-plugin.h"
+
+G_BEGIN_DECLS
+
+/* type macros */
+#define GNC_TYPE_PLUGIN_CSV            (gnc_plugin_csv_get_type ())
+#define GNC_PLUGIN_CSV(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNC_TYPE_PLUGIN_CSV, GncPluginCsv))
+#define GNC_PLUGIN_CSV_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GNC_TYPE_PLUGIN_CSV, GncPluginCsvClass))
+#define GNC_IS_PLUGIN_CSV(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNC_TYPE_PLUGIN_CSV))
+#define GNC_IS_PLUGIN_CSV_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_CSV))
+#define GNC_PLUGIN_CSV_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_CSV, GncPluginCsvClass))
+
+#define GNC_PLUGIN_CSV_NAME "gnc-plugin-csv"
+
+/* typedefs & structures */
+typedef struct {
+	GncPlugin gnc_plugin;
+} GncPluginCsv;
+
+typedef struct {
+	GncPluginClass gnc_plugin;
+} GncPluginCsvClass;
+
+/* function prototypes */
+GType      gnc_plugin_csv_get_type (void);
+
+GncPlugin *gnc_plugin_csv_new      (void);
+
+void       gnc_plugin_csv_create_plugin (void);
+
+G_END_DECLS
+
+#endif /* __GNC_PLUGIN_CSV_H */

Added: gnucash/branches/csv-import/src/import-export/csv/gncmod-csv-import.c
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gncmod-csv-import.c	2007-06-16 18:43:31 UTC (rev 16172)
+++ gnucash/branches/csv-import/src/import-export/csv/gncmod-csv-import.c	2007-06-17 01:23:40 UTC (rev 16173)
@@ -0,0 +1,91 @@
+/********************************************************************\
+ * 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                   *
+\********************************************************************/
+/** @addtogroup Import_Export
+    @{ */
+ /**@internal
+ @file gncmod-csv-import.c
+ @brief module definition/initialization for the csv importer
+ @author Copyright (c) 2002 Benoit Grégoire bock at step.polymtl.ca
+ */
+#include "config.h"
+
+#include <gmodule.h>
+
+#include "gnc-module.h"
+#include "gnc-module-api.h"
+#include "gnc-plugin-csv.h"
+
+GNC_MODULE_API_DECL(libgncmod_csv)
+
+/* version of the gnc module system interface we require */
+int libgncmod_csv_gnc_module_system_interface = 0;
+
+/* module versioning uses libtool semantics. */
+int libgncmod_csv_gnc_module_current  = 0;
+int libgncmod_csv_gnc_module_revision = 0;
+int libgncmod_csv_gnc_module_age      = 0;
+
+//static GNCModule bus_core;
+//static GNCModule file;
+
+
+char *
+libgncmod_csv_gnc_module_path(void)
+{
+  return g_strdup("gnucash/import-export/csv");
+}
+
+char *
+libgncmod_csv_gnc_module_description(void)
+{
+  return g_strdup("Gnome GUI and C code for CSV importer using libcsv");
+}
+
+int
+libgncmod_csv_gnc_module_init(int refcount)
+{
+  if(!gnc_module_load("gnucash/engine", 0))
+  {
+    return FALSE;
+  }
+  if(!gnc_module_load("gnucash/app-utils", 0))
+  {
+    return FALSE;
+  }
+  if(!gnc_module_load("gnucash/gnome-utils", 0))
+  {
+    return FALSE;
+  }
+    if(!gnc_module_load("gnucash/import-export", 0))
+  {
+    return FALSE;
+  }
+
+  /* Add menu items with C callbacks */
+  gnc_plugin_csv_create_plugin();
+
+  return TRUE;
+}
+
+int
+libgncmod_csv_gnc_module_end(int refcount)
+{
+  return TRUE;
+}
+/** @}*/



More information about the gnucash-changes mailing list