X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fhomebank;a=blobdiff_plain;f=src%2Fhb-import-csv.c;fp=src%2Fhb-import-csv.c;h=8d87f14ba53de9936ee794e09f5955df405632da;hp=0000000000000000000000000000000000000000;hb=996fa4ab9f6b836001f8ad0eecbfd3821687fea7;hpb=27f6e3b112df235c8e9afc9911b1f6bce208a001;ds=sidebyside
diff --git a/src/hb-import-csv.c b/src/hb-import-csv.c
new file mode 100644
index 0000000..8d87f14
--- /dev/null
+++ b/src/hb-import-csv.c
@@ -0,0 +1,382 @@
+/* HomeBank -- Free, easy, personal accounting for everyone.
+ * Copyright (C) 1995-2016 Maxime DOYEN
+ *
+ * This file is part of HomeBank.
+ *
+ * HomeBank 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.
+ *
+ * HomeBank 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, see .
+ */
+
+#include "homebank.h"
+
+
+#include "hb-import.h"
+
+
+/****************************************************************************/
+/* Debug macros */
+/****************************************************************************/
+#define MYDEBUG 0
+
+#if MYDEBUG
+#define DB(x) (x);
+#else
+#define DB(x);
+#endif
+
+/* our global datas */
+extern struct HomeBank *GLOBALS;
+extern struct Preferences *PREFS;
+
+
+static gchar *hb_csv_strndup (gchar *str, gsize n)
+{
+gchar *new_str;
+gchar *twoquote;
+
+ if (str)
+ {
+ new_str = g_new (gchar, n + 1);
+ if(*str=='\"')
+ {
+ str++; n--;
+ }
+ if(str[n-1]=='\"')
+ n--;
+
+ strncpy (new_str, str, n);
+ new_str[n] = '\0';
+
+ // replace ""
+ twoquote = strstr(new_str, "\"\"");
+ if(twoquote)
+ strcpy (twoquote, twoquote+1);
+
+ //todo: replace & < > ' " ??
+
+ }
+ else
+ new_str = NULL;
+
+ return new_str;
+}
+
+
+static gchar *hb_csv_find_delimiter(gchar *string)
+{
+ gchar *s = string;
+gboolean enclosed = FALSE;
+
+ while( *s != '\0' )
+ {
+ if( *s == ';' && enclosed == FALSE )
+ break;
+
+ if( *s == '\"' )
+ {
+ enclosed = !enclosed;
+ }
+
+ s++;
+ }
+
+ return s;
+}
+
+
+gboolean hb_csv_row_valid(gchar **str_array, guint nbcolumns, gint *csvtype)
+{
+gboolean valid = TRUE;
+guint i;
+extern int errno;
+
+#if MYDEBUG == 1
+gchar *type[5] = { "string", "date", "int", "double" };
+gint lasttype;
+#endif
+
+ DB( g_print("\n** hb_string_csv_valid: init %d\n", valid) );
+
+ DB( g_print(" -> length %d, nbcolumns %d\n", g_strv_length( str_array ), nbcolumns) );
+
+ if( g_strv_length( str_array ) != nbcolumns )
+ {
+ valid = FALSE;
+ goto csvend;
+ }
+
+ for(i=0;i fail on column %d, type: %s\n", i, type[lasttype]) );
+ break;
+ }
+
+ DB( g_print(" -> control column %d, type: %d, valid: %d '%s'\n", i, lasttype, valid, str_array[i]) );
+
+ switch( csvtype[i] )
+ {
+ case CSV_DATE:
+ valid = hb_string_isdate(str_array[i]);
+ break;
+ case CSV_STRING:
+ valid = hb_string_isprint(str_array[i]);
+ break;
+ case CSV_INT:
+ valid = hb_string_isdigit(str_array[i]);
+ break;
+ case CSV_DOUBLE :
+
+ //todo: use strtod (to take care or . or ,)
+ g_ascii_strtod(str_array[i], NULL);
+ //todo : see this errno
+ if( errno )
+ {
+ DB( g_print("errno: %d\n", errno) );
+ valid = FALSE;
+ }
+ break;
+ }
+ }
+
+csvend:
+
+ DB( g_print(" --> return %d\n", valid) );
+
+ return valid;
+}
+
+
+gchar **hb_csv_row_get(gchar *string, gchar *delimiter, gint max_tokens)
+{
+GSList *string_list = NULL, *slist;
+gchar **str_array, *s;
+guint n = 0;
+gchar *remainder;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (delimiter != NULL, NULL);
+ g_return_val_if_fail (delimiter[0] != '\0', NULL);
+
+ if (max_tokens < 1)
+ max_tokens = G_MAXINT;
+
+ remainder = string;
+ s = hb_csv_find_delimiter (remainder);
+ if (s)
+ {
+ gsize delimiter_len = strlen (delimiter);
+
+ while (--max_tokens && s && *s != '\0')
+ {
+ gsize len;
+
+ len = s - remainder;
+ string_list = g_slist_prepend (string_list, hb_csv_strndup (remainder, len));
+ DB( g_print(" stored=[%s]\n", (gchar *)string_list->data) );
+
+ n++;
+ remainder = s + delimiter_len;
+ s = hb_csv_find_delimiter (remainder);
+ }
+ }
+ if (*string)
+ {
+ gsize len;
+
+ len = s - remainder;
+ n++;
+ string_list = g_slist_prepend (string_list, hb_csv_strndup (remainder, len));
+ DB( g_print(" stored=[%s]\n", (gchar *)string_list->data) );
+ }
+
+ str_array = g_new (gchar*, n + 1);
+
+ str_array[n--] = NULL;
+ for (slist = string_list; slist; slist = slist->next)
+ str_array[n--] = slist->data;
+
+ g_slist_free (string_list);
+
+ return str_array;
+}
+
+
+GList *homebank_csv_import(gchar *filename, ImportContext *ictx)
+{
+GIOChannel *io;
+GList *list = NULL;
+static gint csvtype[7] = {
+ CSV_DATE,
+ CSV_INT,
+ CSV_STRING,
+ CSV_STRING,
+ CSV_STRING,
+ CSV_DOUBLE,
+ CSV_STRING,
+ };
+
+ DB( g_print("\n[import] homebank csv\n") );
+
+ io = g_io_channel_new_file(filename, "r", NULL);
+ if(io != NULL)
+ {
+ gchar *tmpstr;
+ gsize length;
+ gint io_stat;
+ gboolean isvalid;
+ gint count = 0;
+ gint error = 0;
+ Account *tmp_acc;
+ Payee *payitem;
+ Category *catitem;
+ GError *err = NULL;
+
+
+ gchar *accname = g_strdup_printf(_("(account %d)"), da_acc_get_max_key() + 1);
+ tmp_acc = import_create_account(accname, NULL);
+ g_free(accname);
+
+
+ if( ictx->encoding != NULL )
+ {
+ g_io_channel_set_encoding(io, ictx->encoding, NULL);
+ }
+
+ for(;;)
+ {
+ io_stat = g_io_channel_read_line(io, &tmpstr, &length, NULL, &err);
+ if( io_stat == G_IO_STATUS_EOF)
+ break;
+ if( io_stat == G_IO_STATUS_ERROR )
+ {
+ DB (g_print(" + ERROR %s\n",err->message));
+ break;
+ }
+ if( io_stat == G_IO_STATUS_NORMAL)
+ {
+ if( *tmpstr != '\0' )
+ {
+ gchar **str_array;
+
+ count++;
+
+ hb_string_strip_crlf(tmpstr);
+ DB( g_print("\n (row-%04d) ->|%s|<-\n", count, tmpstr) );
+
+ // 0:date; 1:paymode; 2:info; 3:payee, 4:wording; 5:amount; 6:category; 7:tags
+ str_array = hb_csv_row_get(tmpstr, ";", 8);
+ isvalid = hb_csv_row_valid(str_array, 8, csvtype);
+
+ DB( g_print(" valid %d, '%s'\n", isvalid, tmpstr) );
+
+ if( !isvalid )
+ {
+ g_warning ("csv parse: line %d, invalid column count or data", count);
+ error++;
+ //todo log line in error to report user
+ }
+ else
+ {
+ Transaction *newope = da_transaction_malloc();
+
+ //DB( g_print(" ->%s\n", tmpstr ) );
+
+ newope->date = hb_date_get_julian(str_array[0], ictx->datefmt);
+ if( newope->date == 0 )
+ {
+ g_warning ("csv parse: line %d, parse date failed", count);
+ ictx->cnt_err_date++;
+ }
+
+ newope->paymode = atoi(str_array[1]);
+ newope->info = g_strdup(str_array[2]);
+
+ /* payee */
+ g_strstrip(str_array[3]);
+ payitem = da_pay_get_by_name(str_array[3]);
+ if(payitem == NULL)
+ {
+ payitem = da_pay_malloc();
+ payitem->name = g_strdup(str_array[3]);
+ payitem->imported = TRUE;
+ da_pay_append(payitem);
+
+ if( payitem->imported == TRUE )
+ ictx->cnt_new_pay += 1;
+ }
+
+ newope->kpay = payitem->key;
+ newope->wording = g_strdup(str_array[4]);
+ newope->amount = hb_qif_parser_get_amount(str_array[5]);
+
+ /* category */
+ g_strstrip(str_array[6]);
+ catitem = da_cat_append_ifnew_by_fullname(str_array[6], TRUE);
+ if( catitem != NULL )
+ {
+ newope->kcat = catitem->key;
+
+ if( catitem->imported == TRUE && catitem->key > 0 )
+ ictx->cnt_new_cat += 1;
+ }
+
+ /* tags */
+ transaction_tags_parse(newope, str_array[7]);
+
+
+ newope->kacc = tmp_acc->key;
+ //newope->kxferacc = accnum;
+
+ newope->flags |= OF_ADDED;
+
+ if( newope->amount > 0)
+ newope->flags |= OF_INCOME;
+
+ /*
+ DB( g_print(" storing %s : %s : %s :%s : %s : %s : %s : %s\n",
+ str_array[0], str_array[1], str_array[2],
+ str_array[3], str_array[4], str_array[5],
+ str_array[6], str_array[7]
+ ) );
+ */
+
+ list = g_list_append(list, newope);
+
+ g_strfreev (str_array);
+ }
+ }
+ g_free(tmpstr);
+ }
+
+ }
+ g_io_channel_unref (io);
+
+ /*
+ ui_dialog_msg_infoerror(data->window, error > 0 ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO,
+ _("Transaction CSV import result"),
+ _("%d transactions inserted\n%d errors in the file"),
+ count, error);
+ */
+ }
+
+
+ return list;
+}
+
+