Merge csv-import branch back into trunk.

configure.in                                       |    2
 lib/Makefile.am                                    |    4
 lib/stf/Makefile.am                                |   13
 lib/stf/README                                     |    2
 lib/stf/stf-parse.c                                | 1414 +++++++++++++++++++++
 lib/stf/stf-parse.h                                |  112 +
 src/bin/gnucash-bin.c                              |    1
 src/import-export/Makefile.am                      |    4
 src/import-export/csv/Makefile.am                  |   59
 src/import-export/csv/example-file.csv             |    4
 src/import-export/csv/gnc-csv-gnumeric-popup.c     |  194 ++
 src/import-export/csv/gnc-csv-gnumeric-popup.h     |   78 +
 src/import-export/csv/gnc-csv-import.c             | 1173 +++++++++++++++++
 src/import-export/csv/gnc-csv-import.h             |   33
 src/import-export/csv/gnc-csv-model.c              | 1199 +++++++++++++++++
 src/import-export/csv/gnc-csv-model.h              |  122 +
 src/import-export/csv/gnc-csv-preview-dialog.glade |  496 +++++++
 src/import-export/csv/gnc-csv2glist.c              |  187 --
 src/import-export/csv/gnc-csv2glist.h              |   39
 src/import-export/csv/gnc-plugin-csv-ui.xml        |   11
 src/import-export/csv/gnc-plugin-csv.c             |  160 ++
 src/import-export/csv/gnc-plugin-csv.h             |   60
 src/import-export/csv/gncmod-csv-import.c          |   91 +
 23 files changed, 5228 insertions(+), 230 deletions(-)


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@16561 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Andreas Köhler 2007-10-12 22:51:34 +00:00
parent 4fe5a31886
commit a6839478a4
23 changed files with 5228 additions and 230 deletions

View File

@ -1436,6 +1436,7 @@ AC_CONFIG_FILES(po/Makefile.in
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
@ -1489,6 +1490,7 @@ AC_CONFIG_FILES(po/Makefile.in
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

View File

@ -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

13
lib/stf/Makefile.am Normal file
View File

@ -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)

2
lib/stf/README Normal file
View File

@ -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.

1414
lib/stf/stf-parse.c Normal file

File diff suppressed because it is too large Load Diff

112
lib/stf/stf-parse.h Normal file
View File

@ -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

View File

@ -337,6 +337,7 @@ load_gnucash_modules()
{ "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 },

View File

@ -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

View File

@ -0,0 +1,59 @@
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 \
gnc-csv-gnumeric-popup.c
noinst_HEADERS = \
gnc-plugin-csv.h \
gnc-csv-import.h \
gnc-csv-model.h \
gnc-csv-gnumeric-popup.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\"

View File

@ -0,0 +1,4 @@
"This file has colon separators":100:01/03/95
"and the last line":-50:02.28.96
"uses a different":-25.13:03/15/00
"date format.":12.5:30-4-02
Can't render this file because it contains an unexpected character in line 1 and column 32.

View File

@ -0,0 +1,194 @@
/* The following is code copied from Gnumeric 1.7.8 licensed under the
* GNU General Public License version 2. It is from the file
* gnumeric/src/gui-util.c, and it has been modified slightly to work
* within GnuCash. */
/* Miguel de Icaza is not sure specifically who from the Gnumeric
* community is the copyright owner of the code below, so, on his
* recommendation, here is the full list of Gnumeric authors.
*
* Miguel de Icaza, creator.
* Jody Goldberg, maintainer.
* Harald Ashburner, Options pricers
* Sean Atkinson, functions and X-Base importing.
* Michel Berkelaar, Simplex algorithm for Solver (LP Solve).
* Jean Brefort, Core charting engine.
* Grandma Chema Celorio, Tester and sheet copy.
* Frank Chiulli, OLE support.
* Kenneth Christiansen, i18n, misc stuff.
* Zbigniew Chyla, plugin system, i18n.
* J.H.M. Dassen (Ray), debian packaging.
* Jeroen Dirks, Simplex algorithm for Solver (LP Solve).
* Tom Dyas, plugin support.
* Gergo Erdi, Gnumeric hacker.
* John Gotts, rpm packaging.
* Andreas J. Guelzow, Gnumeric hacker.
* Jon K. Hellan, Gnumeric hacker.
* Ross Ihaka, special functions.
* Jukka-Pekka Iivonen, numerous functions and tools.
* Jakub Jelinek, Gnumeric hacker.
* Chris Lahey, number format engine.
* Adrian Likins, documentation, debugging.
* Takashi Matsuda, original text plugin.
* Michael Meeks, Excel and OLE2 importing.
* Lutz Muller, SheetObject improvements.
* Emmanuel Pacaud, Many plot types for charting engine.
* Federico M. Quintero, canvas support.
* Mark Probst, Guile support.
* Rasca, HTML, troff, LaTeX exporters.
* Vincent Renardias, original CSV support, French localization.
* Ariel Rios, Guile support.
* Uwe Steinmann, Paradox Importer.
* Arturo Tena, OLE support.
* Almer S. Tigelaar, Gnumeric hacker.
* Bruno Unna, Excel bits.
* Daniel Veillard, XML support.
* Vladimir Vuksan, financial functions.
* Morten Welinder, Gnumeric hacker and leak plugging demi-god.
*/
#include "gnc-csv-gnumeric-popup.h"
#include <glib/gi18n.h>
static void
popup_item_activate (GtkWidget *item, gpointer *user_data)
{
GnumericPopupMenuElement const *elem =
g_object_get_data (G_OBJECT (item), "descriptor");
GnumericPopupMenuHandler handler =
g_object_get_data (G_OBJECT (item), "handler");
g_return_if_fail (elem != NULL);
g_return_if_fail (handler != NULL);
if (handler (elem, user_data))
gtk_widget_destroy (gtk_widget_get_toplevel (item));
}
static void
gnumeric_create_popup_menu_list (GSList *elements,
GnumericPopupMenuHandler handler,
gpointer user_data,
int display_filter,
int sensitive_filter,
GdkEventButton *event)
{
GtkWidget *menu, *item;
char const *trans;
menu = gtk_menu_new ();
for (; elements != NULL ; elements = elements->next) {
GnumericPopupMenuElement const *element = elements->data;
char const * const name = element->name;
char const * const pix_name = element->pixmap;
item = NULL;
if (element->display_filter != 0 &&
!(element->display_filter & display_filter))
continue;
if (name != NULL && *name != '\0') {
trans = _(name);
item = gtk_image_menu_item_new_with_mnemonic (trans);
if (element->sensitive_filter != 0 &&
(element->sensitive_filter & sensitive_filter))
gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
if (pix_name != NULL) {
GtkWidget *image = gtk_image_new_from_stock (pix_name,
GTK_ICON_SIZE_MENU);
gtk_widget_show (image);
gtk_image_menu_item_set_image (
GTK_IMAGE_MENU_ITEM (item),
image);
}
} else {
/* separator */
item = gtk_menu_item_new ();
gtk_widget_set_sensitive (item, FALSE);
}
if (element->index != 0) {
g_signal_connect (G_OBJECT (item),
"activate",
G_CALLBACK (&popup_item_activate), user_data);
g_object_set_data (
G_OBJECT (item), "descriptor", (gpointer)(element));
g_object_set_data (
G_OBJECT (item), "handler", (gpointer)handler);
}
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
}
gnumeric_popup_menu (GTK_MENU (menu), event);
}
void
gnumeric_create_popup_menu (GnumericPopupMenuElement const *elements,
GnumericPopupMenuHandler handler,
gpointer user_data,
int display_filter, int sensitive_filter,
GdkEventButton *event)
{
int i;
GSList *tmp = NULL;
for (i = 0; elements [i].name != NULL; i++)
tmp = g_slist_prepend (tmp, (gpointer)(elements + i));
tmp = g_slist_reverse (tmp);
gnumeric_create_popup_menu_list (tmp, handler, user_data,
display_filter, sensitive_filter, event);
g_slist_free (tmp);
}
static void
kill_popup_menu (GtkWidget *widget, GtkMenu *menu)
{
g_return_if_fail (menu != NULL);
g_return_if_fail (GTK_IS_MENU (menu));
g_object_unref (G_OBJECT (menu));
}
/**
* gnumeric_popup_menu :
* @menu : #GtkMenu
* @event : #GdkEventButton optionally NULL
*
* Bring up a popup and if @event is non-NULL ensure that the popup is on the
* right screen.
**/
void
gnumeric_popup_menu (GtkMenu *menu, GdkEventButton *event)
{
g_return_if_fail (menu != NULL);
g_return_if_fail (GTK_IS_MENU (menu));
#if GLIB_CHECK_VERSION(2,10,0) && GTK_CHECK_VERSION(2,8,14)
g_object_ref_sink (menu);
#else
g_object_ref (menu);
gtk_object_sink (GTK_OBJECT (menu));
#endif
if (event)
gtk_menu_set_screen (menu,
gdk_drawable_get_screen (event->window));
g_signal_connect (G_OBJECT (menu),
"hide",
G_CALLBACK (kill_popup_menu), menu);
/* Do NOT pass the button used to create the menu.
* instead pass 0. Otherwise bringing up a menu with
* the right button will disable clicking on the menu with the left.
*/
gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0,
(event != NULL) ? event->time
: gtk_get_current_event_time());
}

View File

@ -0,0 +1,78 @@
/* The following is code copied from Gnumeric 1.7.8 licensed under the
* GNU General Public License version 2. It is from the file
* gnumeric/src/gui-util.h, and it has been modified slightly to work
* within GnuCash. */
/* Miguel de Icaza is not sure specifically who from the Gnumeric
* community is the copyright owner of the code below, so, on his
* recommendation, here is the full list of Gnumeric authors.
*
* Miguel de Icaza, creator.
* Jody Goldberg, maintainer.
* Harald Ashburner, Options pricers
* Sean Atkinson, functions and X-Base importing.
* Michel Berkelaar, Simplex algorithm for Solver (LP Solve).
* Jean Brefort, Core charting engine.
* Grandma Chema Celorio, Tester and sheet copy.
* Frank Chiulli, OLE support.
* Kenneth Christiansen, i18n, misc stuff.
* Zbigniew Chyla, plugin system, i18n.
* J.H.M. Dassen (Ray), debian packaging.
* Jeroen Dirks, Simplex algorithm for Solver (LP Solve).
* Tom Dyas, plugin support.
* Gergo Erdi, Gnumeric hacker.
* John Gotts, rpm packaging.
* Andreas J. Guelzow, Gnumeric hacker.
* Jon K. Hellan, Gnumeric hacker.
* Ross Ihaka, special functions.
* Jukka-Pekka Iivonen, numerous functions and tools.
* Jakub Jelinek, Gnumeric hacker.
* Chris Lahey, number format engine.
* Adrian Likins, documentation, debugging.
* Takashi Matsuda, original text plugin.
* Michael Meeks, Excel and OLE2 importing.
* Lutz Muller, SheetObject improvements.
* Emmanuel Pacaud, Many plot types for charting engine.
* Federico M. Quintero, canvas support.
* Mark Probst, Guile support.
* Rasca, HTML, troff, LaTeX exporters.
* Vincent Renardias, original CSV support, French localization.
* Ariel Rios, Guile support.
* Uwe Steinmann, Paradox Importer.
* Arturo Tena, OLE support.
* Almer S. Tigelaar, Gnumeric hacker.
* Bruno Unna, Excel bits.
* Daniel Veillard, XML support.
* Vladimir Vuksan, financial functions.
* Morten Welinder, Gnumeric hacker and leak plugging demi-god.
*/
#ifndef GNC_CSV_GNUMERIC_POPUP
#define GNC_CSV_GNUMERIC_POPUP
#include <gtk/gtk.h>
typedef struct {
char const *name;
char const *pixmap;
int display_filter;
int sensitive_filter;
int index;
} GnumericPopupMenuElement;
typedef gboolean (*GnumericPopupMenuHandler) (GnumericPopupMenuElement const *e,
gpointer user_data);
/* Use this on menus that are popped up */
void gnumeric_popup_menu (GtkMenu *menu, GdkEventButton *event);
void gnumeric_create_popup_menu (GnumericPopupMenuElement const *elements,
GnumericPopupMenuHandler handler,
gpointer user_data,
int display_filter,
int sensitive_filter,
GdkEventButton *event);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -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@gnu.org *
\********************************************************************/
/** @file
@brief CSV import GUI
*
gnc-csv-import.h
@author Copyright (c) 2007 Benny Sperisen <lasindi@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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,122 @@
/********************************************************************\
* 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@gnu.org *
\********************************************************************/
/** @file
@brief CSV import GUI
*
gnc-csv-import.h
@author Copyright (c) 2007 Benny Sperisen <lasindi@gmail.com>
*/
#ifndef GNC_CSV_MODEL_H
#define GNC_CSV_MODEL_H
#include "config.h"
#include "Account.h"
#include "Transaction.h"
#include "stf/stf-parse.h"
/** Enumeration for column types. These are the different types of
* columns that can exist in a CSV/Fixed-Width file. There should be
* no two columns with the same type except for the GNC_CSV_NONE
* type. */
enum GncCsvColumnType {GNC_CSV_NONE,
GNC_CSV_DATE,
GNC_CSV_DESCRIPTION,
GNC_CSV_BALANCE,
GNC_CSV_DEPOSIT,
GNC_CSV_WITHDRAWAL,
GNC_CSV_NUM,
GNC_CSV_NUM_COL_TYPES};
/** Enumeration for error types. These are the different types of
* errors that various functions used for the CSV/Fixed-Width importer
* can have. */
enum GncCsvErrorType {GNC_CSV_FILE_OPEN_ERR,
GNC_CSV_ENCODING_ERR};
/** Struct for containing a string. This struct simply contains
* pointers to the beginning and end of a string. We need this because
* the STF code that gnc_csv_parse calls requires these pointers. */
typedef struct
{
char* begin;
char* end;
} GncCsvStr;
/* TODO We now sort transactions by date, not line number, so we
* should probably get rid of this struct and uses of it. */
/** Struct pairing a transaction with a line number. This struct is
* used to keep the transactions in order. When rows are separated
* into "valid" and "error" lists (in case some of the rows have cells
* that are unparseable), we want the user to still be able to
* "correct" the error list. If we keep the line numbers of valid
* transactions, we can then put transactions created from the newly
* corrected rows into the right places. */
typedef struct
{
int line_no;
Transaction* trans;
gnc_numeric balance; /**< The (supposed) balance after this transaction takes place */
gboolean balance_set; /**< TRUE if balance has been set from user data, FALSE otherwise */
} GncCsvTransLine;
extern const int num_date_formats;
/* A set of date formats that the user sees. */
extern const gchar* date_format_user[];
/* This array contains all of the different strings for different column types. */
extern gchar* gnc_csv_column_type_strs[];
/** Struct containing data for parsing a CSV/Fixed-Width file. */
typedef struct
{
gchar* encoding;
GMappedFile* raw_mapping; /**< The mapping containing raw_str */
GncCsvStr raw_str; /**< Untouched data from the file as a string */
GncCsvStr file_str; /**< raw_str translated into UTF-8 */
GPtrArray* orig_lines; /**< file_str parsed into a two-dimensional array of strings */
GArray* orig_row_lengths; /**< The lengths of rows in orig_lines
* before error messages are appended */
int orig_max_row; /**< Holds the maximum value in orig_row_lengths */
GStringChunk* chunk; /**< A chunk of memory in which the contents of orig_lines is stored */
StfParseOptions_t* options; /**< Options controlling how file_str should be parsed */
GArray* column_types; /**< Array of values from the GncCsvColumnType enumeration */
GList* error_lines; /**< List of row numbers in orig_lines that have errors */
GList* transactions; /**< List of GncCsvTransLine*s created using orig_lines and column_types */
int date_format; /**< The format of the text in the date columns from date_format_internal. */
} GncCsvParseData;
GncCsvParseData* gnc_csv_new_parse_data(void);
void gnc_csv_parse_data_free(GncCsvParseData* parse_data);
int gnc_csv_load_file(GncCsvParseData* parse_data, const char* filename,
GError** error);
int gnc_csv_convert_encoding(GncCsvParseData* parse_data, const char* encoding, GError** error);
int gnc_csv_parse(GncCsvParseData* parse_data, gboolean guessColTypes, GError** error);
int gnc_csv_parse_to_trans(GncCsvParseData* parse_data, Account* account, gboolean redo_errors);
#endif

View File

@ -0,0 +1,496 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.2.0 on Tue Jul 17 09:11:23 2007 by lasindi@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>
<placeholder/>
</child>
<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="csv_button">
<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="radiobutton2">
<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">csv_button</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>
<property name="position">1</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="table1">
<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">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="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">4</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame2">
<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="date_format_container">
<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>
<placeholder/>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label4">
<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">Date Format</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">5</property>
</packing>
</child>
<child>
<widget class="GtkHSeparator" id="hseparator3">
<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">6</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox3">
<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="GtkImage" id="instructions_image">
<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="stock">gtk-dialog-info</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="padding">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="instructions_label">
<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="xalign">0</property>
<property name="label" translatable="yes">Select the type of each column below.</property>
<property name="wrap">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">7</property>
</packing>
</child>
<child>
<widget class="GtkTreeView" id="ctreeview">
<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_visible">False</property>
<property name="headers_clickable">True</property>
<property name="enable_grid_lines">GTK_TREE_VIEW_GRID_LINES_BOTH</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">8</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<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="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<child>
<widget class="GtkViewport" id="viewport1">
<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="resize_mode">GTK_RESIZE_QUEUE</property>
<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>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">9</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>
</glade-interface>

View File

@ -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

View File

@ -1,39 +0,0 @@
/*
* gnc-csv2glist.h -- Parse Comma Separated Variable files
*
* Created by: Derek Atkins <derek@ihtfp.com>
* Copyright (c) 2004 Derek Atkins <derek@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@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

View File

@ -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>

View File

@ -0,0 +1,160 @@
/*
* gnc-plugin-csv.c --
* Copyright (C) 2003 David Hampton <hampton@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@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);
}

View File

@ -0,0 +1,60 @@
/*
* gnc-plugin-csv.h --
* Copyright (C) 2003 David Hampton <hampton@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@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 */

View File

@ -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@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@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;
}
/** @}*/