mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
2003-05-26 Benoit Gr�goire <bock@step.polymtl.ca>
* src/import-export/import-settings.c: Revert previous gettext macro addition. * src/engine/TransLog.c,h: Change the log format to use GUID instead of C pointers and to use ISO8601 instead of proprietary format. * src/engine/gnc-numeric.h * src/import-export/import-match-map.c: Doxygen update * configure.in * src/scm/main.scm * src/import-export/Makefile.am * src/import-export/log-replay/*: New log replay module. This ALMOST works, except I forgot you can't set the GUID of gnucash's objects, and thus completely screwed up on the playback logic. I'll think of a solution when I am rested. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@8440 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
e67e3c4254
commit
dbed96de7b
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
||||
2003-05-26 Benoit Grégoire <bock@step.polymtl.ca>
|
||||
|
||||
* src/import-export/import-settings.c: Revert previous gettext macro addition.
|
||||
* src/engine/TransLog.c,h: Change the log format to use GUID instead of C pointers and to use ISO8601 instead of proprietary format.
|
||||
|
||||
* src/engine/gnc-numeric.h
|
||||
* src/import-export/import-match-map.c: Doxygen update
|
||||
|
||||
* configure.in
|
||||
* src/scm/main.scm
|
||||
* src/import-export/Makefile.am
|
||||
* src/import-export/log-replay/*: New log replay module. This ALMOST works, except I forgot you can't set the GUID of gnucash's objects, and thus completely screwed up on the playback logic. I'll think of a solution when I am rested.
|
||||
|
||||
2003-05-28 Derek Atkins <derek@ihtfp.com>
|
||||
|
||||
* src/business/business-core/gncTaxTable.c: when asking for
|
||||
|
@ -1169,6 +1169,7 @@ AC_OUTPUT( m4/Makefile intl/Makefile po/Makefile.in
|
||||
src/import-export/qif-io-core/test/Makefile
|
||||
src/import-export/ofx/Makefile
|
||||
src/import-export/ofx/test/Makefile
|
||||
src/import-export/log-replay/Makefile
|
||||
src/import-export/hbci/Makefile
|
||||
src/import-export/hbci/glade/Makefile
|
||||
src/import-export/hbci/test/Makefile
|
||||
|
@ -37,12 +37,6 @@
|
||||
#include "TransLog.h"
|
||||
#include "gnc-engine-util.h"
|
||||
|
||||
/*
|
||||
* The logfiles are useful for tracing, journalling, error recovery.
|
||||
* Note that the current support for journalling is at best
|
||||
* embryonic, at worst, is dangerous by setting the wrong expectations.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some design philosphy that I think would be good to keep in mind:
|
||||
* (0) Simplicity and foolproofness are the over-riding design points.
|
||||
@ -84,19 +78,6 @@
|
||||
* is needed for identifying the account.
|
||||
*/
|
||||
/* ------------------------------------------------------------------ */
|
||||
/*
|
||||
* The engine currently uses the log mechanism with flag char set as
|
||||
* follows:
|
||||
*
|
||||
* 'B' for 'begin edit' (followed by the transaction as it looks
|
||||
* before any changes, i.e. the 'old value')
|
||||
* 'D' for delete (i.e. delete the previous B; echoes the data in the
|
||||
* 'old B')
|
||||
* 'C' for commit (i.e. accept a previous B; data that follows is the
|
||||
* 'new value')
|
||||
* 'R' for rollback (i.e. revert to previous B; data that follows should
|
||||
* be identical to old B)
|
||||
*/
|
||||
|
||||
|
||||
static int gen_logs = 1;
|
||||
@ -160,11 +141,11 @@ xaccOpenLog (void)
|
||||
g_free (timestamp);
|
||||
|
||||
/* use tab-separated fields */
|
||||
fprintf (trans_log, "mod id time_now " \
|
||||
fprintf (trans_log, "mod trans_guid split_guid time_now " \
|
||||
"date_entered date_posted " \
|
||||
"account num description " \
|
||||
"acc_guid acc_name num description " \
|
||||
"memo action reconciled " \
|
||||
"amount price date_reconciled\n");
|
||||
"amount value date_reconciled\n");
|
||||
fprintf (trans_log, "-----------------\n");
|
||||
}
|
||||
|
||||
@ -187,35 +168,50 @@ void
|
||||
xaccTransWriteLog (Transaction *trans, char flag)
|
||||
{
|
||||
GList *node;
|
||||
char *dnow, *dent, *dpost, *drecn;
|
||||
char *trans_guid_str, *split_guid_str;
|
||||
char dnow[100], dent[100], dpost[100], drecn[100];
|
||||
Timespec ts;
|
||||
|
||||
if (!gen_logs) return;
|
||||
if (!trans_log) return;
|
||||
|
||||
dnow = xaccDateUtilGetStampNow ();
|
||||
dent = xaccDateUtilGetStamp (trans->date_entered.tv_sec);
|
||||
dpost = xaccDateUtilGetStamp (trans->date_posted.tv_sec);
|
||||
timespecFromTime_t(&ts,time(NULL));
|
||||
gnc_timespec_to_iso8601_buff (ts, dnow);
|
||||
|
||||
timespecFromTime_t(&ts,trans->date_entered.tv_sec);
|
||||
gnc_timespec_to_iso8601_buff (ts, dent);
|
||||
|
||||
timespecFromTime_t(&ts,trans->date_posted.tv_sec);
|
||||
gnc_timespec_to_iso8601_buff (ts, dpost);
|
||||
|
||||
trans_guid_str = guid_to_string (xaccTransGetGUID(trans));
|
||||
|
||||
fprintf (trans_log, "===== START\n");
|
||||
|
||||
for (node = trans->splits; node; node = node->next) {
|
||||
Split *split = node->data;
|
||||
const char * accname = "";
|
||||
char * acc_guid_str = NULL;
|
||||
|
||||
if (xaccSplitGetAccount(split))
|
||||
if (xaccSplitGetAccount(split)){
|
||||
accname = xaccAccountGetName (xaccSplitGetAccount(split));
|
||||
acc_guid_str = guid_to_string (xaccAccountGetGUID(xaccSplitGetAccount(split)));
|
||||
}
|
||||
|
||||
drecn = xaccDateUtilGetStamp (split->date_reconciled.tv_sec);
|
||||
timespecFromTime_t(&ts,split->date_reconciled.tv_sec);
|
||||
gnc_timespec_to_iso8601_buff (ts, drecn);
|
||||
|
||||
split_guid_str = guid_to_string (xaccSplitGetGUID(split));
|
||||
/* use tab-separated fields */
|
||||
fprintf (trans_log,
|
||||
"%c\t%p/%p\t%s\t%s\t%s\t%s\t%s\t"
|
||||
"%c\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t"
|
||||
"%s\t%s\t%s\t%c\t%lld/%lld\t%lld/%lld\t%s\n",
|
||||
flag,
|
||||
trans, split, /* trans+split make up unique id */
|
||||
trans_guid_str, split_guid_str, /* trans+split make up unique id */
|
||||
dnow ? dnow : "",
|
||||
dent ? dent : "",
|
||||
dpost ? dpost : "",
|
||||
acc_guid_str ? acc_guid_str : "",
|
||||
accname ? accname : "",
|
||||
trans->num ? trans->num : "",
|
||||
trans->description ? trans->description : "",
|
||||
@ -228,14 +224,12 @@ xaccTransWriteLog (Transaction *trans, char flag)
|
||||
(long long int) gnc_numeric_denom(split->value),
|
||||
drecn ? drecn : "");
|
||||
|
||||
g_free (drecn);
|
||||
g_free (split_guid_str);
|
||||
}
|
||||
|
||||
fprintf (trans_log, "===== END\n");
|
||||
|
||||
g_free (dnow);
|
||||
g_free (dent);
|
||||
g_free (dpost);
|
||||
g_free (trans_guid_str);
|
||||
|
||||
/* get data out to the disk */
|
||||
fflush (trans_log);
|
||||
|
@ -1,7 +1,4 @@
|
||||
/********************************************************************\
|
||||
* TransLog.h -- the transaction logger *
|
||||
* Copyright (C) 1998 Linas Vepstas *
|
||||
* *
|
||||
* 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 *
|
||||
@ -21,7 +18,17 @@
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file TransLog.h The transaction logger */
|
||||
/** @addtogroup Engine
|
||||
@{ */
|
||||
/** @file TransLog.h
|
||||
@brief API for the transaction logger
|
||||
*
|
||||
* The logfiles are useful for tracing, journalling, error recovery.
|
||||
* Note that the current support for journalling is at best
|
||||
* embryonic, at worst, is dangerous by setting the wrong expectations.
|
||||
*
|
||||
@author Copyright (C) 1998 Linas Vepstas
|
||||
*/
|
||||
|
||||
#ifndef XACC_TRANS_LOG_H
|
||||
#define XACC_TRANS_LOG_H
|
||||
@ -33,11 +40,27 @@
|
||||
|
||||
void xaccOpenLog (void);
|
||||
void xaccCloseLog (void);
|
||||
/**
|
||||
\param char The engine currently uses the log mechanism with flag char set as
|
||||
* follows:
|
||||
* 'B' for 'begin edit' (followed by the transaction as it looks
|
||||
* before any changes, i.e. the 'old value')
|
||||
* 'D' for delete (i.e. delete the previous B; echoes the data in the
|
||||
* 'old B')
|
||||
* 'C' for commit (i.e. accept a previous B; data that follows is the
|
||||
* 'new value')
|
||||
* 'R' for rollback (i.e. revert to previous B; data that follows should
|
||||
* be identical to old B)
|
||||
*/
|
||||
void xaccTransWriteLog (Transaction *, char);
|
||||
|
||||
/** document me */
|
||||
void xaccLogEnable (void);
|
||||
|
||||
/** document me */
|
||||
void xaccLogDisable (void);
|
||||
|
||||
/* The xaccLogSetBaseName() method sets the base filepath and the
|
||||
/** The xaccLogSetBaseName() method sets the base filepath and the
|
||||
* root part of the journal file name. If the journal file is
|
||||
* already open, it will close it and reopen it with the new
|
||||
* base name.
|
||||
@ -45,4 +68,5 @@ void xaccLogDisable (void);
|
||||
void xaccLogSetBaseName (const char *);
|
||||
|
||||
#endif /* XACC_TRANS_LOG_H */
|
||||
/** @} */
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
/********************************************************************
|
||||
* gnc-numeric.h -- an exact-number library for gnucash. *
|
||||
* Copyright (C) 2000 Bill Gribble *
|
||||
* *
|
||||
* 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 *
|
||||
@ -21,7 +18,12 @@
|
||||
* *
|
||||
*******************************************************************/
|
||||
|
||||
/** @file gnc-numeric.h @brief An exact-number library for gnucash.*/
|
||||
/** @addtogroup Engine
|
||||
@{ */
|
||||
/** @file gnc-numeric.h
|
||||
@brief An exact-number library for gnucash.
|
||||
@author Copyright (C) 2000 Bill Gribble
|
||||
*/
|
||||
|
||||
#ifndef GNC_NUMERIC_H
|
||||
#define GNC_NUMERIC_H
|
||||
@ -211,3 +213,5 @@ gnc_numeric gnc_numeric_reduce(gnc_numeric in);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*@}*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
SUBDIRS = . binary-import qif-import ${OFX_DIR} ${HBCI_DIR} test
|
||||
SUBDIRS = . binary-import qif-import ${OFX_DIR} ${HBCI_DIR} test log-replay
|
||||
|
||||
pkglib_LTLIBRARIES=libgncmod-generic-import.la
|
||||
|
||||
@ -80,4 +80,5 @@ EXTRA_DIST = \
|
||||
DISTCLEANFILES = gnucash g-wrapped .scm-links import-export
|
||||
|
||||
# FIXME remove this when qif-io-core is finished
|
||||
DIST_SUBDIRS = binary-import qif-import qif-io-core ofx test hbci
|
||||
DIST_SUBDIRS = binary-import qif-import qif-io-core ofx test hbci log-replay
|
||||
|
||||
|
@ -73,7 +73,7 @@ gnc_imap_create_from_frame (kvp_frame *frame, Account *acc, GNCBook *book)
|
||||
return imap;
|
||||
}
|
||||
|
||||
/* Obtain an ImportMatchMap object from an Account or a Book */
|
||||
/** Obtain an ImportMatchMap object from an Account or a Book */
|
||||
GncImportMatchMap * gnc_imap_create_from_account (Account *acc)
|
||||
{
|
||||
kvp_frame * frame;
|
||||
@ -96,14 +96,14 @@ GncImportMatchMap * gnc_imap_create_from_book (GNCBook *book)
|
||||
return gnc_imap_create_from_frame (frame, NULL, book);
|
||||
}
|
||||
|
||||
/* Destroy an import map */
|
||||
/** Destroy an import map */
|
||||
void gnc_imap_destroy (GncImportMatchMap *imap)
|
||||
{
|
||||
if (!imap) return;
|
||||
g_free (imap);
|
||||
}
|
||||
|
||||
/* Clear an import map -- this removes ALL entries in the map */
|
||||
/** Clear an import map -- this removes ALL entries in the map */
|
||||
void gnc_imap_clear (GncImportMatchMap *imap)
|
||||
{
|
||||
if (!imap) return;
|
||||
@ -117,7 +117,7 @@ void gnc_imap_clear (GncImportMatchMap *imap)
|
||||
/* XXX: mark the account (or book) as dirty! */
|
||||
}
|
||||
|
||||
/* Look up an Account in the map */
|
||||
/** Look up an Account in the map */
|
||||
Account * gnc_imap_find_account (GncImportMatchMap *imap, const char *category,
|
||||
const char *key)
|
||||
{
|
||||
@ -137,7 +137,7 @@ Account * gnc_imap_find_account (GncImportMatchMap *imap, const char *category,
|
||||
return xaccAccountLookup (guid, imap->book);
|
||||
}
|
||||
|
||||
/* Store an Account in the map */
|
||||
/** Store an Account in the map */
|
||||
void gnc_imap_add_account (GncImportMatchMap *imap, const char *category,
|
||||
const char *key, Account *acc)
|
||||
{
|
||||
@ -161,24 +161,28 @@ void gnc_imap_add_account (GncImportMatchMap *imap, const char *category,
|
||||
|
||||
|
||||
|
||||
/* Below here is the bayes transaction to account matching system */
|
||||
/*--------------------------------------------------------------------------
|
||||
Below here is the bayes transaction to account matching system
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
struct account_token_count
|
||||
{
|
||||
char* account_name;
|
||||
gint64 token_count; /* occurances of a given token for this account_name */
|
||||
gint64 token_count; /**< occurances of a given token for this account_name */
|
||||
};
|
||||
|
||||
/* total_count and the token_count for a given account let us calculate the
|
||||
/** total_count and the token_count for a given account let us calculate the
|
||||
* probability of a given account with any single token
|
||||
*/
|
||||
struct token_accounts_info
|
||||
{
|
||||
GList *accounts; /* array of struct account_token_count */
|
||||
GList *accounts; /**< array of struct account_token_count */
|
||||
gint64 total_count;
|
||||
};
|
||||
|
||||
/* gpointer is a pointer to a struct token_accounts_info
|
||||
* NOTE: can always assume that keys are unique, reduces code in this function
|
||||
/** gpointer is a pointer to a struct token_accounts_info
|
||||
* \note Can always assume that keys are unique, reduces code in this function
|
||||
*/
|
||||
static void buildTokenInfo(const char *key, kvp_value *value, gpointer data)
|
||||
{
|
||||
@ -203,9 +207,9 @@ static void buildTokenInfo(const char *key, kvp_value *value, gpointer data)
|
||||
tokenInfo->accounts = g_list_prepend(tokenInfo->accounts, this_account);
|
||||
}
|
||||
|
||||
/* intermediate values used to calculate the bayes probability of a given account
|
||||
* where p(AB) = (a*b)/[a*b + (1-a)(1-b)], product is (a*b),
|
||||
* product_difference is (1-a) * (1-b)
|
||||
/** intermediate values used to calculate the bayes probability of a given account
|
||||
where p(AB) = (a*b)/[a*b + (1-a)(1-b)], product is (a*b),
|
||||
product_difference is (1-a) * (1-b)
|
||||
*/
|
||||
struct account_probability
|
||||
{
|
||||
@ -213,9 +217,9 @@ struct account_probability
|
||||
double product_difference; /* product of (1-probabilities) */
|
||||
};
|
||||
|
||||
/* convert a hash table of account names and (struct account_probability*)
|
||||
* into a hash table of 100000x the percentage match value, ie. 10% would be
|
||||
* 0.10 * 100000 = 10000
|
||||
/** convert a hash table of account names and (struct account_probability*)
|
||||
into a hash table of 100000x the percentage match value, ie. 10% would be
|
||||
0.10 * 100000 = 10000
|
||||
*/
|
||||
#define PROBABILITY_FACTOR 100000
|
||||
static void buildProbabilities(gpointer key, gpointer value, gpointer data)
|
||||
@ -237,7 +241,7 @@ static void buildProbabilities(gpointer key, gpointer value, gpointer data)
|
||||
g_hash_table_insert(final_probabilities, key, (gpointer)probability);
|
||||
}
|
||||
|
||||
/* Frees an array of the same time that buildProperties built */
|
||||
/** Frees an array of the same time that buildProperties built */
|
||||
static void freeProbabilities(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
/* free up the struct account_probability that was allocated
|
||||
@ -246,8 +250,8 @@ static void freeProbabilities(gpointer key, gpointer value, gpointer data)
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
/* holds an account name and its corresponding integer probability
|
||||
* the integer probability is some factor of 10
|
||||
/** holds an account name and its corresponding integer probability
|
||||
the integer probability is some factor of 10
|
||||
*/
|
||||
struct account_info
|
||||
{
|
||||
@ -255,11 +259,11 @@ struct account_info
|
||||
gint32 probability;
|
||||
};
|
||||
|
||||
/* Find the highest probability and the corresponding account name
|
||||
* store in data, a (struct account_info*)
|
||||
* NOTE: this is a g_hash_table_foreach() function for a hash table of entries
|
||||
* key is a pointer to the account name, value is a gint32, 100000x
|
||||
* the probability for this account
|
||||
/** Find the highest probability and the corresponding account name
|
||||
store in data, a (struct account_info*)
|
||||
NOTE: this is a g_hash_table_foreach() function for a hash table of entries
|
||||
key is a pointer to the account name, value is a gint32, 100000x
|
||||
the probability for this account
|
||||
*/
|
||||
static void highestProbability(gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
@ -277,19 +281,19 @@ static void highestProbability(gpointer key, gpointer value, gpointer data)
|
||||
|
||||
#define threshold (.90 * PROBABILITY_FACTOR) /* 90% */
|
||||
|
||||
/* Look up an Account in the map */
|
||||
/** Look up an Account in the map */
|
||||
Account* gnc_imap_find_account_bayes(GncImportMatchMap *imap, GList *tokens)
|
||||
{
|
||||
struct token_accounts_info tokenInfo; /* holds the accounts and total
|
||||
struct token_accounts_info tokenInfo; /**< holds the accounts and total
|
||||
* token count for a single token */
|
||||
GList *current_token; /* pointer to the current token from the
|
||||
GList *current_token; /**< pointer to the current token from the
|
||||
* input GList *tokens */
|
||||
GList *current_account_token; /* pointer to the struct
|
||||
GList *current_account_token; /**< pointer to the struct
|
||||
* account_token_count */
|
||||
struct account_token_count *account_c; /* an account name and the number
|
||||
struct account_token_count *account_c; /**< an account name and the number
|
||||
* of times a token has appeared
|
||||
* for the account */
|
||||
struct account_probability *account_p; /* intermediate storage of values
|
||||
struct account_probability *account_p; /**< intermediate storage of values
|
||||
* to compute the bayes probability
|
||||
* of an account */
|
||||
GHashTable *running_probabilities = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
@ -300,6 +304,8 @@ Account* gnc_imap_find_account_bayes(GncImportMatchMap *imap, GList *tokens)
|
||||
|
||||
ENTER(" ");
|
||||
|
||||
gnc_set_log_level(MOD_IMPORT, GNC_LOG_INFO);
|
||||
|
||||
/* check to see if the imap is NULL */
|
||||
if(!imap)
|
||||
{
|
||||
@ -450,7 +456,7 @@ Account* gnc_imap_find_account_bayes(GncImportMatchMap *imap, GList *tokens)
|
||||
}
|
||||
|
||||
|
||||
/* Updates the imap for a given account using a list of tokens */
|
||||
/** Updates the imap for a given account using a list of tokens */
|
||||
void gnc_imap_add_account_bayes(GncImportMatchMap *imap, GList *tokens, Account *acc)
|
||||
{
|
||||
GList *current_token;
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include "dialog-utils.h"
|
||||
#include "global-options.h"
|
||||
#include "import-settings.h"
|
||||
@ -102,26 +101,26 @@ gnc_import_Settings_new (void)
|
||||
|
||||
settings->action_skip_enabled =
|
||||
gnc_lookup_boolean_option(MATCHER_PREF_PAGE,
|
||||
_("Enable SKIP transaction action"),
|
||||
"Enable SKIP transaction action",
|
||||
DEFAULT_ACTION_SKIP_ENABLED);
|
||||
settings->action_edit_enabled =
|
||||
gnc_lookup_boolean_option(MATCHER_PREF_PAGE,
|
||||
_("Enable EDIT match action"),
|
||||
"Enable EDIT match action",
|
||||
DEFAULT_ACTION_EDIT_ENABLED);
|
||||
settings->action_add_enabled=DEFAULT_ACTION_ADD_ENABLED;
|
||||
settings->action_clear_enabled=DEFAULT_ACTION_CLEAR_ENABLED;
|
||||
settings->clear_threshold=gnc_lookup_number_option(MATCHER_PREF_PAGE,
|
||||
_("Auto-CLEAR threshold"),
|
||||
"Auto-CLEAR threshold",
|
||||
DEFAULT_CLEAR_THRESHOLD);
|
||||
settings->add_threshold=gnc_lookup_number_option(MATCHER_PREF_PAGE,
|
||||
_("Auto-ADD threshold"),
|
||||
"Auto-ADD threshold",
|
||||
DEFAULT_ADD_THRESHOLD);
|
||||
settings->display_threshold =
|
||||
gnc_lookup_number_option(MATCHER_PREF_PAGE,_("Match display threshold"),
|
||||
gnc_lookup_number_option(MATCHER_PREF_PAGE,"Match display threshold",
|
||||
DEFAULT_DISPLAY_THRESHOLD);
|
||||
|
||||
settings->fuzzy_amount =
|
||||
gnc_lookup_number_option(MATCHER_PREF_PAGE,_("Commercial ATM fees threshold"),
|
||||
gnc_lookup_number_option(MATCHER_PREF_PAGE,"Commercial ATM fees threshold",
|
||||
DEFAULT_ATM_FEE_THRESHOLD);
|
||||
|
||||
return settings;
|
||||
|
6
src/import-export/log-replay/.cvsignore
Normal file
6
src/import-export/log-replay/.cvsignore
Normal file
@ -0,0 +1,6 @@
|
||||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
44
src/import-export/log-replay/Makefile.am
Normal file
44
src/import-export/log-replay/Makefile.am
Normal file
@ -0,0 +1,44 @@
|
||||
SUBDIRS = .
|
||||
|
||||
pkglib_LTLIBRARIES=libgncmod-log-replay.la
|
||||
|
||||
libgncmod_log_replay_la_SOURCES = \
|
||||
gnc-log-replay.c \
|
||||
gncmod-log-replay.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
gnc-log-replay.h
|
||||
|
||||
libgncmod_log_replay_la_LDFLAGS = -module
|
||||
|
||||
libgncmod_log_replay_la_LIBADD = \
|
||||
${top_builddir}/src/gnc-module/libgncmodule.la \
|
||||
${top_builddir}/src/engine/libgncmod-engine.la \
|
||||
${top_builddir}/src/import-export/libgncmod-generic-import.la \
|
||||
${GLIB_LIBS}
|
||||
|
||||
gncscmdir = ${GNC_SCM_INSTALL_DIR}/log-replay
|
||||
|
||||
gncscm_DATA = \
|
||||
log-replay.scm
|
||||
|
||||
AM_CFLAGS = \
|
||||
-I${top_srcdir}/src \
|
||||
-I${top_srcdir}/src/engine \
|
||||
-I${top_srcdir}/src/gnc-module \
|
||||
-I${top_srcdir}/src/app-utils \
|
||||
-I${top_srcdir}/src/app-file \
|
||||
-I${top_srcdir}/src/gnome \
|
||||
-I${top_srcdir}/src/gnome-utils \
|
||||
-I${top_srcdir}/src/import-export \
|
||||
${GNOME_INCLUDEDIR} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
${GUILE_INCS} \
|
||||
${GLIB_CFLAGS}
|
||||
|
||||
EXTRA_DIST = \
|
||||
.cvsignore \
|
||||
${gncscm_DATA}
|
||||
|
||||
CLEANFILES = g-wrapped .scm-links
|
573
src/import-export/log-replay/gnc-log-replay.c
Normal file
573
src/import-export/log-replay/gnc-log-replay.c
Normal file
@ -0,0 +1,573 @@
|
||||
/********************************************************************\
|
||||
* 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 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
/** @addtogroup Import_Export
|
||||
@{ */
|
||||
/** @internal
|
||||
@file gnc-log-replay.c
|
||||
@brief .log file replay code
|
||||
@author Copyright (c) 2003 Benoit Grégoire <bock@step.polymtl.ca>
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <libguile.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#include "libofx/libofx.h"
|
||||
#include "import-account-matcher.h"
|
||||
#include "import-commodity-matcher.h"
|
||||
#include "import-utilities.h"
|
||||
#include "import-main-matcher.h"
|
||||
|
||||
#include "Account.h"
|
||||
#include "Transaction.h"
|
||||
#include "global-options.h"
|
||||
#include "gnc-associate-account.h"
|
||||
#include "gnc-log-replay.h"
|
||||
#include "gnc-file-dialog.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-book.h"
|
||||
#include "gnc-ui-util.h"
|
||||
|
||||
|
||||
#include "dialog-utils.h"
|
||||
|
||||
|
||||
/*static short module = MOD_IMPORT;*/
|
||||
static short module = MOD_TEST;
|
||||
|
||||
/* fprintf (trans_log, "mod guid time_now " \
|
||||
"date_entered date_posted " \
|
||||
"acc_guid acc_name num description " \
|
||||
"memo action reconciled " \
|
||||
"amount value date_reconciled\n");
|
||||
"%c\t%s/%s\t%s\t%s\t%s\t%s\t%s\t%s\t"
|
||||
"%s\t%s\t%s\t%c\t%lld/%lld\t%lld/%lld\t%s\n",
|
||||
*/
|
||||
#define STRING_FIELD_SIZE 256
|
||||
typedef struct _split_record
|
||||
{
|
||||
enum _enum_action {LOG_BEGIN_EDIT, LOG_ROLLBACK, LOG_COMMIT, LOG_DELETE} log_action;
|
||||
int log_action_present;
|
||||
GUID trans_guid;
|
||||
int trans_guid_present;
|
||||
GUID split_guid;
|
||||
int split_guid_present;
|
||||
Timespec log_date;
|
||||
int log_date_present;
|
||||
Timespec date_entered;
|
||||
int date_entered_present;
|
||||
Timespec date_posted;
|
||||
int date_posted_present;
|
||||
GUID acc_guid;
|
||||
int acc_guid_present;
|
||||
char acc_name[STRING_FIELD_SIZE];
|
||||
int acc_name_present;
|
||||
char trans_num[STRING_FIELD_SIZE];
|
||||
int trans_num_present;
|
||||
char trans_descr[STRING_FIELD_SIZE];
|
||||
int trans_descr_present;
|
||||
char split_memo[STRING_FIELD_SIZE];
|
||||
int split_memo_present;
|
||||
char split_action[STRING_FIELD_SIZE];
|
||||
int split_action_present;
|
||||
char split_reconcile;
|
||||
int split_reconcile_present;
|
||||
gnc_numeric amount;
|
||||
int amount_present;
|
||||
gnc_numeric value;
|
||||
int value_present;
|
||||
Timespec date_reconciled;
|
||||
int date_reconciled_present;
|
||||
} split_record;
|
||||
/********************************************************************\
|
||||
* gnc_file_ofx_import
|
||||
* Entry point
|
||||
\********************************************************************/
|
||||
|
||||
SCM scm_gnc_file_log_replay ()
|
||||
{
|
||||
gnc_file_log_replay();
|
||||
return SCM_EOL;
|
||||
}
|
||||
|
||||
static char *olds;
|
||||
/* This version of strtok will only match SINGLE occurence of delim,
|
||||
returning a 0 length valid string between two consecutive ocurence of delim.
|
||||
It will also return a 0 length string instead of NULL when it reaches the end of s
|
||||
*/
|
||||
static char * my_strtok (s, delim)
|
||||
char *s;
|
||||
const char *delim;
|
||||
{
|
||||
char *token;
|
||||
/*DEBUG("strtok(): Start...");*/
|
||||
if (s == NULL)
|
||||
s = olds;
|
||||
|
||||
/* Scan leading delimiters. */
|
||||
/*s += strspn (s, delim);*/ /*Don't do it, or we will loose count.*/
|
||||
if (*s == '\0')
|
||||
{
|
||||
olds = s;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Find the end of the token. */
|
||||
token = s;
|
||||
s = strpbrk (token, delim);
|
||||
if (s == NULL)
|
||||
{
|
||||
/* This token finishes the string. */
|
||||
olds = strchr (token, '\0');
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Terminate the token and make OLDS point past it. */
|
||||
*s = '\0';
|
||||
olds = s + 1;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
static split_record interpret_split_record( char *record_line)
|
||||
{
|
||||
char * tok_ptr;
|
||||
split_record record;
|
||||
memset(&record,0,sizeof(record));
|
||||
DEBUG("interpret_split_record(): Start...");
|
||||
if(strlen(tok_ptr = my_strtok(record_line,"\t"))!=0)
|
||||
{
|
||||
switch(tok_ptr[0])
|
||||
{
|
||||
case 'B': record.log_action=LOG_BEGIN_EDIT;
|
||||
break;
|
||||
case 'D': record.log_action=LOG_DELETE;
|
||||
break;
|
||||
case 'C': record.log_action=LOG_COMMIT;
|
||||
break;
|
||||
case 'R': record.log_action=LOG_ROLLBACK;
|
||||
break;
|
||||
}
|
||||
record.log_action_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
string_to_guid(tok_ptr, &(record.trans_guid));
|
||||
record.trans_guid_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
string_to_guid(tok_ptr, &(record.split_guid));
|
||||
record.split_guid_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
record.log_date = gnc_iso8601_to_timespec_local(tok_ptr);
|
||||
record.log_date_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
record.date_entered = gnc_iso8601_to_timespec_local(tok_ptr);
|
||||
record.date_entered_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
record.date_posted = gnc_iso8601_to_timespec_local(tok_ptr);
|
||||
record.date_posted_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
string_to_guid(tok_ptr, &(record.acc_guid));
|
||||
record.acc_guid_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
strncpy(record.acc_name,tok_ptr,STRING_FIELD_SIZE-1);
|
||||
record.acc_name_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
strncpy(record.trans_num,tok_ptr,STRING_FIELD_SIZE-1);
|
||||
record.trans_num_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
strncpy(record.trans_descr,tok_ptr,STRING_FIELD_SIZE-1);
|
||||
record.trans_descr_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
strncpy(record.split_memo,tok_ptr,STRING_FIELD_SIZE-1);
|
||||
record.split_memo_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
strncpy(record.split_action,tok_ptr,STRING_FIELD_SIZE-1);
|
||||
record.split_action_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
record.split_reconcile = tok_ptr[0];
|
||||
record.split_reconcile_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
string_to_gnc_numeric(tok_ptr, &(record.amount));
|
||||
record.amount_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
string_to_gnc_numeric(tok_ptr, &(record.value));
|
||||
record.value_present=true;
|
||||
}
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
record.date_reconciled = gnc_iso8601_to_timespec_local(tok_ptr);
|
||||
record.date_reconciled_present=true;
|
||||
}
|
||||
|
||||
if(strlen(tok_ptr = my_strtok(NULL,"\t"))!=0)
|
||||
{
|
||||
PERR("interpret_split_record(): Expected number of fields exceeded!");
|
||||
}
|
||||
DEBUG("interpret_split_record(): End");
|
||||
return record;
|
||||
}
|
||||
|
||||
static void dump_split_record(split_record record)
|
||||
{
|
||||
char * string_ptr = NULL;
|
||||
char string_buf[256];
|
||||
|
||||
DEBUG("dump_split_record(): Start...");
|
||||
if(record.log_action_present)
|
||||
{
|
||||
switch(record.log_action)
|
||||
{
|
||||
case LOG_BEGIN_EDIT: DEBUG("Log action: LOG_BEGIN_EDIT");
|
||||
break;
|
||||
case LOG_DELETE: DEBUG("Log action: LOG_DELETE");
|
||||
break;
|
||||
case LOG_COMMIT: DEBUG("Log action: LOG_COMMIT");
|
||||
break;
|
||||
case LOG_ROLLBACK: DEBUG("Log action: LOG_ROLLBACK");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(record.trans_guid_present)
|
||||
{
|
||||
string_ptr = guid_to_string (&(record.trans_guid));
|
||||
DEBUG("Transaction GUID: %s", string_ptr);
|
||||
g_free(string_ptr);
|
||||
}
|
||||
|
||||
if(record.split_guid_present)
|
||||
{
|
||||
string_ptr = guid_to_string (&(record.split_guid));
|
||||
DEBUG("Split GUID: %s", string_ptr);
|
||||
g_free(string_ptr);
|
||||
}
|
||||
|
||||
if(record.log_date_present)
|
||||
{
|
||||
gnc_timespec_to_iso8601_buff (record.log_date, string_buf);
|
||||
DEBUG("Log entry date: %s", string_buf);
|
||||
}
|
||||
|
||||
if(record.date_entered_present)
|
||||
{
|
||||
gnc_timespec_to_iso8601_buff (record.date_entered, string_buf);
|
||||
DEBUG("Date entered: %s", string_buf);
|
||||
}
|
||||
|
||||
if(record.date_posted_present)
|
||||
{
|
||||
gnc_timespec_to_iso8601_buff (record.date_posted, string_buf);
|
||||
DEBUG("Date posted: %s", string_buf);
|
||||
}
|
||||
|
||||
if(record.acc_guid_present)
|
||||
{
|
||||
string_ptr = guid_to_string (&(record.acc_guid));
|
||||
DEBUG("Account GUID: %s", string_ptr);
|
||||
g_free(string_ptr);
|
||||
}
|
||||
|
||||
if(record.acc_name_present)
|
||||
{
|
||||
DEBUG("Account name: %s", record.acc_name);
|
||||
}
|
||||
if(record.trans_num_present)
|
||||
{
|
||||
DEBUG("Transaction number: %s", record.trans_num);
|
||||
}
|
||||
if(record.trans_descr_present)
|
||||
{
|
||||
DEBUG("Transaction description: %s", record.trans_descr);
|
||||
}
|
||||
if(record.split_memo_present)
|
||||
{
|
||||
DEBUG("Split memo: %s", record.split_memo);
|
||||
}
|
||||
if(record.split_action_present)
|
||||
{
|
||||
DEBUG("Split action: %s", record.split_action);
|
||||
}
|
||||
if(record.split_reconcile_present)
|
||||
{
|
||||
DEBUG("Split reconcile: %c", record.split_reconcile);
|
||||
}
|
||||
|
||||
if(record.amount_present)
|
||||
{
|
||||
string_ptr = gnc_numeric_to_string(record.amount);
|
||||
DEBUG("Record amount: %s", string_ptr);
|
||||
g_free(string_ptr);
|
||||
}
|
||||
|
||||
if(record.value_present)
|
||||
{
|
||||
string_ptr = gnc_numeric_to_string(record.value);
|
||||
DEBUG("Record value: %s", string_ptr);
|
||||
g_free(string_ptr);
|
||||
}
|
||||
|
||||
if(record.date_reconciled_present)
|
||||
{
|
||||
gnc_timespec_to_iso8601_buff (record.date_reconciled, string_buf);
|
||||
DEBUG("Reconciled date: %s", string_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* File pointer must already be at the begining of a record */
|
||||
static void process_trans_record( FILE *log_file)
|
||||
{
|
||||
char read_buf[256];
|
||||
char *read_retval;
|
||||
const char * record_end_str = "===== END";
|
||||
int first_record=true;
|
||||
int record_ended = false;
|
||||
int split_num = 0;
|
||||
split_record record;
|
||||
Transaction * trans = NULL;
|
||||
Split * split = NULL;
|
||||
Account * acct = NULL;
|
||||
GNCBook * book = gnc_get_current_book();
|
||||
|
||||
DEBUG("process_trans_record(): Begin...\n");
|
||||
|
||||
while( record_ended == false)
|
||||
{
|
||||
read_retval = fgets(read_buf,sizeof(read_buf),log_file);
|
||||
if(read_retval!=NULL && strncmp(record_end_str,read_buf,strlen(record_end_str))!=0)/* If we are not at the end of the record */
|
||||
{
|
||||
split_num++;
|
||||
/*DEBUG("process_trans_record(): Line read: %s%s",read_buf ,"\n");*/
|
||||
record = interpret_split_record( read_buf);
|
||||
dump_split_record( record);
|
||||
if(record.log_action_present)
|
||||
{
|
||||
switch(record.log_action)
|
||||
{
|
||||
case LOG_BEGIN_EDIT: DEBUG("process_trans_record():Ignoring log action: LOG_BEGIN_EDIT"); /*Do nothing, there is no point*/
|
||||
break;
|
||||
case LOG_ROLLBACK: DEBUG("process_trans_record():Ignoring log action: LOG_ROLLBACK");/*Do nothing, since we didn't do the begin_edit either*/
|
||||
break;
|
||||
case LOG_DELETE: DEBUG("process_trans_record(): Playing back LOG_DELETE");
|
||||
if((trans=xaccTransLookup (&(record.trans_guid), book))!=NULL
|
||||
&& first_record==true)
|
||||
{
|
||||
xaccTransBeginEdit(trans);
|
||||
xaccTransDestroy(trans);
|
||||
}
|
||||
else if(first_record==true)
|
||||
{
|
||||
PERR("The transaction to delete was not found!");
|
||||
}
|
||||
break;
|
||||
case LOG_COMMIT: DEBUG("process_trans_record(): Playing back LOG_COMMIT");
|
||||
if(record.trans_guid_present == true
|
||||
&& (trans=xaccTransLookupDirect (record.trans_guid, book)) != NULL
|
||||
&& first_record == true)
|
||||
{
|
||||
DEBUG("process_trans_record(): Transaction to be edited was found");/*Destroy the current transaction, we will create a new one to replace it*/
|
||||
xaccTransBeginEdit(trans);
|
||||
xaccTransDestroy(trans);
|
||||
xaccTransCommitEdit(trans);
|
||||
}
|
||||
|
||||
if(record.trans_guid_present == true
|
||||
&& first_record==true)
|
||||
{
|
||||
DEBUG("process_trans_record(): Creating the new transaction");
|
||||
trans = xaccMallocTransaction (book);
|
||||
xaccTransBeginEdit(trans);
|
||||
/*Fill the transaction info*/
|
||||
if(record.date_entered_present)
|
||||
{
|
||||
xaccTransSetDateEnteredTS(trans,&(record.date_entered));
|
||||
}
|
||||
if(record.date_posted_present)
|
||||
{
|
||||
xaccTransSetDatePostedTS(trans,&(record.date_posted));
|
||||
}
|
||||
if(record.trans_num_present)
|
||||
{
|
||||
xaccTransSetNum(trans,record.trans_num);
|
||||
}
|
||||
if(record.trans_descr_present)
|
||||
{
|
||||
xaccTransSetDescription(trans,record.trans_descr);
|
||||
}
|
||||
}
|
||||
if(record.split_guid_present == true) /*Fill the split info*/
|
||||
{
|
||||
split=xaccMallocSplit(book);
|
||||
if(record.acc_guid_present)
|
||||
{
|
||||
acct = xaccAccountLookupDirect(record.acc_guid,book);
|
||||
xaccAccountInsertSplit(acct,split);
|
||||
}
|
||||
xaccTransAppendSplit(trans,split);
|
||||
|
||||
if(record.split_memo_present)
|
||||
{
|
||||
xaccSplitSetMemo(split,record.split_memo);
|
||||
}
|
||||
if(record.split_action_present)
|
||||
{
|
||||
xaccSplitSetAction(split,record.split_action);
|
||||
}
|
||||
if(record.date_reconciled_present)
|
||||
{
|
||||
xaccSplitSetDateReconciledTS (split, &(record.date_reconciled));
|
||||
}
|
||||
if(record.split_reconcile_present)
|
||||
{
|
||||
xaccSplitSetReconcile(split, record.split_reconcile);
|
||||
}
|
||||
|
||||
if(record.amount_present)
|
||||
{
|
||||
xaccSplitSetAmount(split, record.amount);
|
||||
}
|
||||
if(record.value_present)
|
||||
{
|
||||
xaccSplitSetValue(split, record.value);
|
||||
}
|
||||
}
|
||||
first_record=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PERR("Corrupted record");
|
||||
}
|
||||
}
|
||||
else /* The record ended */
|
||||
{
|
||||
record_ended = true;
|
||||
DEBUG("process_trans_record(): Record ended\n");
|
||||
if(trans!=NULL)/*If we played with a transaction, commit it here*/
|
||||
{
|
||||
xaccTransCommitEdit(trans);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gnc_file_log_replay (void)
|
||||
{
|
||||
const char *selected_filename;
|
||||
char *default_dir;
|
||||
char read_buf[256];
|
||||
char *read_retval;
|
||||
FILE *log_file;
|
||||
char * expected_header = "mod trans_guid split_guid time_now date_entered date_posted acc_guid acc_name num description memo action reconciled amount value date_reconciled";
|
||||
char * record_start_str = "===== START";
|
||||
|
||||
gnc_should_log(MOD_IMPORT, GNC_LOG_DEBUG);
|
||||
DEBUG("gnc_file_log_replay(): Begin...\n");
|
||||
|
||||
default_dir = gnc_lookup_string_option("__paths", "Log Files", NULL);
|
||||
if (default_dir == NULL)
|
||||
gnc_init_default_directory(&default_dir);
|
||||
selected_filename = gnc_file_dialog(_("Select a .log file to replay"),
|
||||
NULL,
|
||||
default_dir);
|
||||
|
||||
if(selected_filename!=NULL)
|
||||
{
|
||||
/* Remember the directory as the default. */
|
||||
gnc_extract_directory(&default_dir, selected_filename);
|
||||
gnc_set_string_option("__paths", "Log Files", default_dir);
|
||||
g_free(default_dir);
|
||||
|
||||
/*strncpy(file,selected_filename, 255);*/
|
||||
DEBUG("Filename found: %s",selected_filename);
|
||||
|
||||
DEBUG("Opening selected file");
|
||||
log_file = fopen(selected_filename, "r");
|
||||
if(ferror(log_file)!=0)
|
||||
{
|
||||
perror("File open failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
if((read_retval = fgets(read_buf,sizeof(read_buf),log_file)) == NULL)
|
||||
{
|
||||
DEBUG("Read error or EOF");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(strncmp(expected_header,read_buf,strlen(expected_header))!=0)
|
||||
{
|
||||
PERR("File header not recognised:\n%s",read_buf);
|
||||
PERR("Expected:\n%s",expected_header);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
read_retval = fgets(read_buf,sizeof(read_buf),log_file);
|
||||
/*DEBUG("Chunk read: %s",read_retval);*/
|
||||
if(strncmp(record_start_str,read_buf,strlen(record_start_str))==0)/* If a record started */
|
||||
{
|
||||
process_trans_record(log_file);
|
||||
}
|
||||
}while(feof(log_file)==0);
|
||||
}
|
||||
}
|
||||
fclose(log_file);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
34
src/import-export/log-replay/gnc-log-replay.h
Normal file
34
src/import-export/log-replay/gnc-log-replay.h
Normal file
@ -0,0 +1,34 @@
|
||||
/********************************************************************\
|
||||
* 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 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
/** @file
|
||||
@brief .log replay module interface
|
||||
*
|
||||
gnc-log-replay.h
|
||||
@author Copyright (c) 2003 Benoit Grégoire <bock@step.polymtl.ca>
|
||||
*/
|
||||
#ifndef OFX_IMPORT_H
|
||||
#define OFX_IMPORT_H
|
||||
|
||||
/** The gnc_file_log_replay() routine will pop up a standard file
|
||||
* selection dialogue asking the user to pick a log file to replay. If one
|
||||
* is selected the the .log file is opened and read. It's contents
|
||||
* are then silently merged in the current log file. */
|
||||
void gnc_file_log_replay (void);
|
||||
SCM scm_gnc_file_log_replay (void);
|
||||
#endif
|
92
src/import-export/log-replay/gncmod-log-replay.c
Normal file
92
src/import-export/log-replay/gncmod-log-replay.c
Normal file
@ -0,0 +1,92 @@
|
||||
/********************************************************************\
|
||||
* 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 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
/** @addtogroup Import_Export
|
||||
@{ */
|
||||
/**@internal
|
||||
@file gncmod-log-replay.c
|
||||
@brief module definition/initialization for the log replay module
|
||||
@author Copyright (c) 2003 Benoit Grégoire bock@step.polymtl.ca
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <glib.h>
|
||||
#include <libguile.h>
|
||||
#include "guile-mappings.h"
|
||||
|
||||
#include "gnc-log-replay.h"
|
||||
#include "gnc-module.h"
|
||||
#include "gnc-module-api.h"
|
||||
|
||||
/* version of the gnc module system interface we require */
|
||||
int libgncmod_log_replay_LTX_gnc_module_system_interface = 0;
|
||||
|
||||
/* module versioning uses libtool semantics. */
|
||||
int libgncmod_log_replay_LTX_gnc_module_current = 0;
|
||||
int libgncmod_log_replay_LTX_gnc_module_revision = 0;
|
||||
int libgncmod_log_replay_LTX_gnc_module_age = 0;
|
||||
|
||||
//static GNCModule bus_core;
|
||||
//static GNCModule file;
|
||||
|
||||
/* forward references */
|
||||
char *libgncmod_log_replay_LTX_gnc_module_path(void);
|
||||
char *libgncmod_log_replay_LTX_gnc_module_description(void);
|
||||
int libgncmod_log_replay_LTX_gnc_module_init(int refcount);
|
||||
int libgncmod_log_replay_LTX_gnc_module_end(int refcount);
|
||||
|
||||
|
||||
char *
|
||||
libgncmod_log_replay_LTX_gnc_module_path(void)
|
||||
{
|
||||
return g_strdup("gnucash/import-export/log-replay");
|
||||
}
|
||||
char *
|
||||
libgncmod_log_replay_LTX_gnc_module_description(void)
|
||||
{
|
||||
return g_strdup("C code for log file replay");
|
||||
}
|
||||
int
|
||||
libgncmod_log_replay_LTX_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;
|
||||
}
|
||||
scm_c_eval_string("(load-from-path \"log-replay/log-replay.scm\")");
|
||||
scm_c_define_gsubr("gnc:log-replay", 0, 0, 0, scm_gnc_file_log_replay);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
libgncmod_log_replay_LTX_gnc_module_end(int refcount)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
/** @}*/
|
10
src/import-export/log-replay/log-replay.scm
Normal file
10
src/import-export/log-replay/log-replay.scm
Normal file
@ -0,0 +1,10 @@
|
||||
(define (add-log-replay-menu-item)
|
||||
(gnc:add-extension
|
||||
(gnc:make-menu-item(N_ "Replay GnuCash .log file")
|
||||
(N_ "Replay a gnucash log file after a crash. This cannot be undone.")
|
||||
(list gnc:window-name-main "File" "_Import" "")
|
||||
(lambda ()
|
||||
(gnc:log-replay)))))
|
||||
|
||||
(gnc:hook-add-dangler gnc:*ui-startup-hook* add-log-replay-menu-item)
|
||||
|
@ -427,6 +427,7 @@ string and 'directories' must be a list of strings."
|
||||
(load-module "gnucash/import-export/binary-import" 0 #f)
|
||||
(load-module "gnucash/import-export/qif-import" 0 #f)
|
||||
(load-module "gnucash/import-export/ofx" 0 #t)
|
||||
(load-module "gnucash/import-export/log-replay" 0 #t)
|
||||
(load-module "gnucash/import-export/hbci" 0 #t)
|
||||
(load-module "gnucash/report/report-system" 0 #f)
|
||||
(load-module "gnucash/report/stylesheets" 0 #f)
|
||||
|
Loading…
Reference in New Issue
Block a user