cleanups, tweaks to support mutiple book saving

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@9012 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 2003-08-09 19:24:05 +00:00
parent a81a3cbf95
commit de6ba90d29
10 changed files with 195 additions and 128 deletions

View File

@ -36,6 +36,7 @@ libgncmod_backend_file_la_SOURCES = \
sixtp.c
noinst_HEADERS = \
gnc-backend-file.h \
gnc-xml.h \
gnc-xml-helper.h \
io-example-account.h \

View File

@ -1,8 +1,32 @@
/*********************************************************************
* gnc-backend-file.c: load and save data to files
/********************************************************************
* gnc-backend-file.c: load and save data to files *
* *
* 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 gnc-backend-file.c
* @breif load and save data to files
* @author Copyright (c) 2000 Gnumatic Inc.
* @author Copyright (c) 2002 Derek Atkins <warlord@MIT.EDU>
* @author Copyright (c) 2003 Linas Vepstas <linas@linas.org>
*
*
*********************************************************************/
* This file implements the top-level QofBackend API for saving/
* restoring data to/from an ordinary Unix filesystem file.
*/
#define _GNU_SOURCE
@ -17,47 +41,25 @@
#include <dirent.h>
#include <time.h>
#include "Group.h"
#include "TransLog.h"
#include "gnc-engine.h"
#include "gnc-date.h"
#include "gnc-trace.h"
#include "gnc-engine-util.h"
#include "gnc-pricedb-p.h"
#include "io-gncxml.h"
#include "io-gncbin.h"
#include "io-gncxml-v2.h"
#include "gnc-backend-api.h"
#include "gnc-engine.h"
#include "gnc-engine-util.h"
#include "gnc-backend-file.h"
#include "qofbackend-p.h"
#include "qofbook-p.h"
#include "qofsession.h"
static short module = MOD_BACKEND;
struct FileBackend_struct
{
QofBackend be;
char *dirname;
char *fullpath;
char *lockfile;
char *linkfile;
int lockfd;
QofSession *session;
};
typedef struct FileBackend_struct FileBackend;
typedef enum
{
GNC_BOOK_NOT_OURS,
GNC_BOOK_BIN_FILE,
GNC_BOOK_XML1_FILE,
GNC_BOOK_XML2_FILE,
} QofBookFileType;
static int file_retention_days = 0;
static gboolean file_compression = FALSE;
@ -97,8 +99,6 @@ file_session_begin(QofBackend *be_start, QofSession *session,
ENTER (" ");
be->session = session;
/* Make sure the directory is there */
be->dirname = g_strdup (qof_session_get_file_path (session));
be->fullpath = g_strdup (be->dirname);
@ -184,6 +184,8 @@ static void
file_sync_all(QofBackend* be, QofBook *book)
{
FileBackend *fbe = (FileBackend *) be;
/* XXX fullpath is correct only for the current open book ! */
gnc_file_be_write_to_file (fbe, book, fbe->fullpath, TRUE);
gnc_file_be_remove_old_files (fbe);
}
@ -294,7 +296,7 @@ libgncmod_backend_file_LTX_gnc_backend_new(void)
fbe->linkfile = NULL;
fbe->lockfd = -1;
fbe->session = NULL;
fbe->primary_book = NULL;
return be;
}
@ -453,21 +455,23 @@ gnc_file_be_load_from_file (QofBackend *bend, QofBook *book)
gboolean rc;
FileBackend *be = (FileBackend *) bend;
be->primary_book = book;
switch (gnc_file_be_determine_file_type(be->fullpath))
{
case GNC_BOOK_XML2_FILE:
rc = qof_session_load_from_xml_file_v2 (be->session);
rc = qof_session_load_from_xml_file_v2 (be, book);
if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
break;
case GNC_BOOK_XML1_FILE:
rc = qof_session_load_from_xml_file (be->session);
rc = qof_session_load_from_xml_file (book, be->fullpath);
if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
break;
case GNC_BOOK_BIN_FILE:
/* presume it's an old-style binary file */
qof_session_load_from_binfile(be->session);
qof_session_load_from_binfile(book, be->fullpath);
error = gnc_get_binfile_io_error();
break;
@ -478,7 +482,12 @@ gnc_file_be_load_from_file (QofBackend *bend, QofBook *book)
}
if(error != ERR_BACKEND_NO_ERR)
{
qof_backend_set_error(bend, error);
}
/* We just got done loading, it can't possibly be dirty !! */
qof_book_mark_saved (book);
}
/* ---------------------------------------------------------------------- */
@ -729,6 +738,10 @@ gnc_file_be_write_to_file(FileBackend *fbe,
QofBackendError be_err;
ENTER (" book=%p file=%s", book, datafile);
/* If the book is 'clean', recently saved, then don't save again. */
if (FALSE == qof_book_not_saved (book)) return FALSE;
tmp_name = g_new(char, strlen(datafile) + 12);
strcpy(tmp_name, datafile);
strcat(tmp_name, ".tmp-XXXXXX");
@ -756,20 +769,22 @@ gnc_file_be_write_to_file(FileBackend *fbe,
/* Use the permissions from the original data file */
if(chmod(tmp_name, statbuf.st_mode) != 0)
{
qof_backend_set_error(be, ERR_BACKEND_PERM);
PWARN("unable to chmod filename %s: %s",
datafile ? datafile : "(null)",
strerror(errno) ? strerror(errno) : "");
#if VFAT_DOESNT_SUCK
#if VFAT_DOESNT_SUCK /* chmod always fails on vfat fs */
g_free(tmp_name);
return FALSE;
#endif
}
if(chown(tmp_name, statbuf.st_uid, statbuf.st_gid) != 0)
{
qof_backend_set_error(be, ERR_BACKEND_PERM);
PWARN("unable to chown filename %s: %s",
datafile ? datafile : "(null)",
strerror(errno) ? strerror(errno) : "");
#if VFAT_DOESNT_SUCK
#if VFAT_DOESNT_SUCK /* chown always fails on vfat fs */
g_free(tmp_name);
return FALSE;
#endif
@ -777,7 +792,7 @@ gnc_file_be_write_to_file(FileBackend *fbe,
}
if(unlink(datafile) != 0 && errno != ENOENT)
{
qof_backend_set_error(be, ERR_BACKEND_MISC);
qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
PWARN("unable to unlink filename %s: %s",
datafile ? datafile : "(null)",
strerror(errno) ? strerror(errno) : "");
@ -786,12 +801,13 @@ gnc_file_be_write_to_file(FileBackend *fbe,
}
if(!gnc_int_link_or_make_backup(fbe, tmp_name, datafile))
{
qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
g_free(tmp_name);
return FALSE;
}
if(unlink(tmp_name) != 0)
{
qof_backend_set_error(be, ERR_BACKEND_MISC);
qof_backend_set_error(be, ERR_BACKEND_PERM);
PWARN("unable to unlink temp filename %s: %s",
tmp_name ? tmp_name : "(null)",
strerror(errno) ? strerror(errno) : "");
@ -799,7 +815,11 @@ gnc_file_be_write_to_file(FileBackend *fbe,
return FALSE;
}
g_free(tmp_name);
LEAVE (" book=%p file=%s", book, datafile);
/* Since we successfully saved the book,
* we should mark it clean. */
qof_book_mark_saved (book);
LEAVE (" sucessful save of book=%p to file=%s", book, datafile);
return TRUE;
}
else

View File

@ -0,0 +1,60 @@
/********************************************************************
* gnc-backend-file.h: load and save data to files *
* *
* 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 gnc-backend-file.h
* @breif load and save data to files
* @author Copyright (c) 2000 Gnumatic Inc.
* @author Copyright (c) 2002 Derek Atkins <warlord@MIT.EDU>
* @author Copyright (c) 2003 Linas Vepstas <linas@linas.org>
*
* This file implements the top-level QofBackend API for saving/
* restoring data to/from an ordinary Unix filesystem file.
*/
#ifndef GNC_BACKEND_FILE_H_
#define GNC_BACKEND_FILE_H_
#include "qofbackend.h"
#include "qofbackend-p.h"
struct FileBackend_struct
{
QofBackend be;
char *dirname;
char *fullpath; /* Fully qualified path to book */
char *lockfile;
char *linkfile;
int lockfd;
QofBook *primary_book; /* The primary, main open book */
};
typedef struct FileBackend_struct FileBackend;
typedef enum
{
GNC_BOOK_NOT_OURS,
GNC_BOOK_BIN_FILE,
GNC_BOOK_XML1_FILE,
GNC_BOOK_XML2_FILE,
} QofBookFileType;
#endif /* GNC_BACKEND_FILE_H_ */

View File

@ -1,9 +1,5 @@
/********************************************************************\
* io-gncbin.c -- read and write (old format) binary datafile *
* (GnuCash/X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* Copyright (C) 1997-2001 Linas Vepstas <linas@linas.org> *
* Copyright (C) 1999-2000 Rob Browning *
* io-gncbin-r.c -- read (old X-Accountant format) binary datafile *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@ -23,6 +19,12 @@
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
********************************************************************
* @file io-gncbin-r.c
* @breif read (old X-Accountant format) binary datafile
* @author Copyright (C) 1997 Robin D. Clark
* @author Copyright (C) 1997-2001 Linas Vepstas <linas@linas.org>
* @author Copyright (C) 1999-2000 Rob Browning
*
* NOTE: the readxxxx/writexxxx functions changed the current *
* position in the file, and so the order which these *
* functions are called in important *
@ -536,11 +538,10 @@ gnc_load_financials_from_fd(QofBook *book, int fd)
* Return: the struct with the program data in it *
\********************************************************************/
void
qof_session_load_from_binfile(QofSession *session)
qof_session_load_from_binfile(QofBook *book, const char * datafile)
{
int fd;
const gchar *datafile = qof_session_get_file_path(session);
if(!datafile) {
error_code = ERR_BACKEND_MISC;
return;
@ -555,8 +556,7 @@ qof_session_load_from_binfile(QofSession *session)
return;
}
if (!gnc_load_financials_from_fd(qof_session_get_book(session), fd))
return;
gnc_load_financials_from_fd(book, fd);
close(fd);
}
@ -617,7 +617,7 @@ readGroup (QofBook *book, int fd, Account *aparent, int token)
* readAccount *
* reads in the data for an account from the datafile *
* *
* Args: book - the session *
* Args: book - the top-level account object *
* fd - the filedescriptor of the data file *
* acc - the account structure to be filled in *
* token - the datafile version *

View File

@ -1,9 +1,5 @@
/********************************************************************\
* io-gncbin.h -- read and write (old format) binary datafile *
* (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* Copyright (C) 1998, 1999 Linas Vepstas *
* *
* io-gncbin.h -- read (old X-Accountant format) binary datafile *
* 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 *
@ -31,11 +27,13 @@
#define IO_GNCBIN_H
#include "qofbackend.h"
#include "qofsession.h"
#include "qofbook.h"
/** PROTOTYPES ******************************************************/
/*
/* @file io-gncbin.h
* @breif read (old X-Accountant format) binary datafile
* @author Copyright (C) 1997 Robin D. Clark
* @author Copyright (C) 1998, 1999 Linas Vepstas <linas@linas.org>
*
* NOTE: These routines should not be used directly for file IO. They
* are not inherently safe against file-locking errors. For direct
* file IO, the gnc-book's higher level functions should be used.
@ -49,7 +47,7 @@
* thought of as a "stack of depth one", and this routine as a "pop".
* Future implementations may have a deeper stack.
*/
void qof_session_load_from_binfile(QofSession *session);
void qof_session_load_from_binfile(QofBook *, const char * filepath);
QofBackendError gnc_get_binfile_io_error(void);
#endif /* IO_GNCBIN_H */

View File

@ -359,23 +359,15 @@ gncxml_setup_for_read (GNCParseStatus *global_parse_status)
/* ================================================================== */
gboolean
qof_session_load_from_xml_file(QofSession *session)
qof_session_load_from_xml_file(QofBook *book, const char *filename)
{
gboolean parse_ok;
gpointer parse_result = NULL;
sixtp *top_level_pr;
GNCParseStatus global_parse_status;
const gchar *filename;
QofBook *book;
g_return_val_if_fail(session, FALSE);
book = qof_session_get_book (session);
global_parse_status.book = book;
g_return_val_if_fail(book, FALSE);
filename = qof_session_get_file_path(session);
g_return_val_if_fail(filename, FALSE);
top_level_pr = gncxml_setup_for_read (&global_parse_status);

View File

@ -41,8 +41,6 @@
#include "qofbackend-p.h"
#include "qofbook.h"
#include "qofbook-p.h"
#include "qofsession.h"
#include "qofsession-p.h"
#include "sixtp-dom-parsers.h"
#include "io-gncxml-v2.h"
@ -59,17 +57,17 @@ static short module = MOD_IO;
/* Callback structure */
struct file_backend {
gboolean ok;
gpointer data;
sixtp_gdv2 * gd;
const char * tag;
sixtp * parser;
FILE * out;
QofBook * book;
gboolean ok;
gpointer data;
sixtp_gdv2 * gd;
const char * tag;
sixtp * parser;
FILE * out;
QofBook * book;
};
#define GNC_V2_STRING "gnc-v2"
extern const gchar *gnc_v2_book_version_string; /* see gnc-book-xml-v2 */
extern const gchar *gnc_v2_book_version_string; /* see gnc-book-xml-v2 */
void
run_callback(sixtp_gdv2 *data, const char *type)
@ -410,9 +408,9 @@ gnc_counter_end_handler(gpointer data_for_children,
if (be_data.ok == FALSE)
{
PERR("Unknown type: %s", type ? type : "(null)");
xmlFree (type);
return FALSE;
PERR("Unknown type: %s", type ? type : "(null)");
xmlFree (type);
return FALSE;
}
}
@ -466,15 +464,15 @@ file_rw_feedback (sixtp_gdv2 *gd, const char *type)
percentage = (loaded * 100)/total;
if (percentage > 100) {
printf("Transactions: Total: %d, Loaded: %d\n",
counter->transactions_total, counter->transactions_loaded);
counter->transactions_total, counter->transactions_loaded);
printf("Accounts: Total: %d, Loaded: %d\n",
counter->accounts_total, counter->accounts_loaded);
counter->accounts_total, counter->accounts_loaded);
printf("Books: Total: %d, Loaded: %d\n",
counter->books_total, counter->books_loaded);
counter->books_total, counter->books_loaded);
printf("Commodities: Total: %d, Loaded: %d\n",
counter->commodities_total, counter->commodities_loaded);
counter->commodities_total, counter->commodities_loaded);
printf("Scheduled Tansactions: Total: %d, Loaded: %d\n",
counter->schedXactions_total, counter->schedXactions_loaded);
counter->schedXactions_total, counter->schedXactions_loaded);
}
percentage = MIN(percentage, 100);
gd->gui_display_fn(NULL, percentage);
@ -592,8 +590,8 @@ add_parser_cb (const char *type, gpointer data_p, gpointer be_data_p)
if (data->create_parser)
if(!sixtp_add_some_sub_parsers(
be_data->parser, TRUE,
data->type_name, (data->create_parser)(),
NULL, NULL))
data->type_name, (data->create_parser)(),
NULL, NULL))
be_data->ok = FALSE;
}
@ -641,19 +639,16 @@ gnc_sixtp_gdv2_new (
}
gboolean
qof_session_load_from_xml_file_v2(QofSession *session)
qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book)
{
QofBook *book;
AccountGroup *grp;
QofBackend *be;
AccountGroup *grp;
QofBackend *be = &fbe->be;
sixtp_gdv2 *gd;
sixtp *top_parser;
sixtp *main_parser;
sixtp *book_parser;
struct file_backend be_data;
book = qof_session_get_book (session);
be = qof_book_get_backend(book);
gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage);
top_parser = sixtp_new();
@ -712,7 +707,7 @@ qof_session_load_from_xml_file_v2(QofSession *session)
/* stop logging while we load */
xaccLogDisable ();
if(!gnc_xml_parse_file(top_parser, qof_session_get_file_path(session),
if(!gnc_xml_parse_file(top_parser, fbe->fullpath,
generic_callback, gd, book))
{
sixtp_destroy(top_parser);
@ -728,8 +723,8 @@ qof_session_load_from_xml_file_v2(QofSession *session)
be_data.book = book;
gncObjectForeachBackend (GNC_FILE_BACKEND, scrub_cb, &be_data);
grp = gnc_book_get_group(book);
/* fix price quote sources */
grp = gnc_book_get_group(book);
xaccGroupScrubQuoteSources (grp, gnc_book_get_commodity_table(book));
/* Fix account and transaction commodities */
@ -832,8 +827,8 @@ write_counts_cb (const char *type, gpointer data_p, gpointer be_data_p)
if (data->get_count)
write_counts (be_data->out, data->type_name,
(data->get_count) (be_data->book),
NULL);
(data->get_count) (be_data->book),
NULL);
}
static void
@ -942,8 +937,8 @@ write_commodities(FILE *out, QofBook *book, sixtp_gdv2 *gd)
fprintf(out, "\n");
xmlFreeNode(comnode);
gd->counter.commodities_loaded++;
run_callback(gd, "commodities");
gd->counter.commodities_loaded++;
run_callback(gd, "commodities");
}
g_list_free (comms);
@ -1038,8 +1033,8 @@ write_schedXactions( FILE *out, QofBook *book, sixtp_gdv2 *gd)
xmlElemDump( out, NULL, node );
fprintf( out, "\n" );
xmlFreeNode( node );
gd->counter.schedXactions_loaded++;
run_callback(gd, "schedXactions");
gd->counter.schedXactions_loaded++;
run_callback(gd, "schedXactions");
} while ( (schedXactions = schedXactions->next) );
}
@ -1115,7 +1110,7 @@ gnc_book_write_accounts_to_xml_filehandle_v2(QofBackend *be, QofBook *book, FILE
if (!out) return FALSE;
grp = gnc_book_get_group(book);
grp = gnc_book_get_group(book);
nacc = 1 + xaccGroupGetNumSubAccounts(grp);
table = gnc_book_get_commodity_table(book);

View File

@ -23,9 +23,10 @@
\********************************************************************/
/*
* io-gncxml.h -- api for new XML-based file format
* @file io-gncxml.h
* @breif api for GnuCash version 2 XML-based file format
*
* Initial code by James LewisMoss
* @author Initial code by James LewisMoss, 2001
*/
#ifndef IO_GNCXML_V2_H
@ -33,16 +34,9 @@
#include <glib.h>
#include "Account.h"
#include "Transaction.h"
#include "gnc-commodity.h"
#include "gnc-engine.h"
#include "gnc-pricedb.h"
#include "SchedXaction.h"
#include "qofbook.h"
#include "qofsession.h"
#include "qofbackend.h"
#include "gnc-backend-file.h"
#include "gnc-engine.h"
#include "sixtp.h"
@ -129,7 +123,7 @@ typedef struct
void run_callback(sixtp_gdv2 *data, const char *type);
/* read in an account group from a file */
gboolean qof_session_load_from_xml_file_v2(QofSession *session);
gboolean qof_session_load_from_xml_file_v2(FileBackend *, QofBook *);
/* write all book info to a file */
gboolean gnc_book_write_to_xml_filehandle_v2(QofBook *book, FILE *fh);

View File

@ -23,9 +23,10 @@
\********************************************************************/
/*
* io-gncxml.h -- api for new XML-based file format
* @file io-gncxml.h
* @breif api for Version 1 XML-based file format
*
* Initial code by Rob l. Browning 4Q 2000
* Initial code by Rob L. Browning 4Q 2000
* Tuneups by James LewisMoss Dec 2000
*/
@ -33,17 +34,15 @@
#define IO_GNCXML_H
#include <glib.h>
#include "qofsession.h"
#include "Query.h"
#include "qofbook.h"
/* FIXME: eventually, we probably need to add an error stack
accessable via gnc_book_get_xml_io_error() a la binfile. */
/* read in an account group from a file */
gboolean qof_session_load_from_xml_file(QofSession *session);
/** Read in an account group from a file */
gboolean qof_session_load_from_xml_file(QofBook *, const char * filename);
/* The is_gncxml_file() routine checks to see if the first few
/** The is_gncxml_file() routine checks to see if the first few
* chars of the file look like gnc-xml data.
*/
gboolean gnc_is_xml_data_file(const gchar *name);

View File

@ -1,3 +1,8 @@
/* @file test-load-xml2.c
* @breif test the loading of a vrsion-2 gnucash XML file
*/
#include <glib.h>
#include <libguile.h>
#include <stdlib.h>
@ -12,6 +17,8 @@
#include "Group.h"
#include "TransLog.h"
#include "gnc-engine.h"
#include "gnc-backend-file.h"
#include "qofsession-p.h"
#include "gnc-module.h"
#include "io-gncxml-v2.h"
@ -47,6 +54,7 @@ test_load_file(const char *filename)
{
QofSession *session;
QofBook *book;
QofBackend *be;
gboolean ignore_lock;
session = qof_session_new();
@ -56,9 +64,9 @@ test_load_file(const char *filename)
ignore_lock = (strcmp(getenv("SRCDIR"), ".") != 0);
qof_session_begin(session, filename, ignore_lock, FALSE);
qof_session_load_from_xml_file_v2(session);
book = qof_session_get_book (session);
be = qof_session_get_backend (session);
qof_session_load_from_xml_file_v2((FileBackend *)be, book);
do_test (xaccGroupGetBook (xaccGetAccountGroup (book)) == book,
"book and group don't match");