Remove the file-path utilities from qofsession.c and move them into

a temp file 'gnc-filepath-utils.c' which is used by both the
file backend and by the app-file GUI routines.  Some of the file-resolution
logic was oved to the file backend.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@10063 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas
2004-06-13 20:01:29 +00:00
parent c69fa356d0
commit 17531066a1
11 changed files with 571 additions and 843 deletions
+22
View File
@@ -36,6 +36,7 @@
#include "gnc-file-dialog.h"
#include "gnc-file-history.h"
#include "gnc-file-p.h"
#include "gnc-filepath-utils.h"
#include "gnc-gui-query.h"
#include "gnc-ui.h"
#include "gnc-ui-util.h"
@@ -43,6 +44,7 @@
#include "qofbook.h"
#include "qofsession.h"
#include "messages.h"
#include "TransLog.h"
/** GLOBALS *********************************************************/
/* This static indicates the debugging module that this .o belongs to. */
@@ -287,7 +289,9 @@ gnc_file_new (void)
SCM_BOOL_F));
gnc_close_gui_component_by_session (session);
xaccLogDisable();
qof_session_destroy (session);
xaccLogEnable();
/* start a new book */
qof_session_get_current_session ();
@@ -375,7 +379,9 @@ gnc_post_file_open (const char * filename)
gw_wcp_assimilate_ptr (current_session,
scm_c_eval_string("<gnc:Session*>")) :
SCM_BOOL_F));
xaccLogDisable();
qof_session_destroy (current_session);
xaccLogEnable();
/* load the accounts from the users datafile */
/* but first, check to make sure we've got a session going. */
@@ -462,6 +468,11 @@ gnc_post_file_open (const char * filename)
{
AccountGroup *new_group;
char * logpath = xaccResolveFilePath(newfile);
PINFO ("logpath=%s", logpath ? logpath : "(null)");
xaccLogSetBaseName (logpath);
xaccLogDisable();
if (file_percentage_func) {
file_percentage_func(_("Reading file..."), 0.0);
qof_session_load (new_session, file_percentage_func);
@@ -469,6 +480,7 @@ gnc_post_file_open (const char * filename)
} else {
qof_session_load (new_session, NULL);
}
xaccLogEnable();
/* check for i/o error, put up appropriate error dialog */
io_err = qof_session_get_error (new_session);
@@ -490,7 +502,9 @@ gnc_post_file_open (const char * filename)
/* going down -- abandon ship */
if (uh_oh)
{
xaccLogDisable();
qof_session_destroy (new_session);
xaccLogEnable();
/* well, no matter what, I think it's a good idea to have a
* topgroup around. For example, early in the gnucash startup
@@ -645,7 +659,9 @@ gnc_file_export_file(const char * newfile)
ok = qof_session_export (new_session, current_session, NULL);
}
gnc_unset_busy_cursor (NULL);
xaccLogDisable();
qof_session_destroy (new_session);
xaccLogEnable();
gnc_engine_resume_events();
if (!ok)
@@ -801,7 +817,9 @@ gnc_file_save_as (void)
if (ERR_BACKEND_NO_ERR != io_err)
{
show_session_error (io_err, newfile);
xaccLogDisable();
qof_session_destroy (new_session);
xaccLogEnable();
g_free (newfile);
return;
}
@@ -809,7 +827,9 @@ gnc_file_save_as (void)
/* if we got to here, then we've successfully gotten a new session */
/* close up the old file session (if any) */
qof_session_swap_data (session, new_session);
xaccLogDisable();
qof_session_destroy (session);
xaccLogEnable();
session = NULL;
/* XXX At this point, we should really mark the data in the new session
@@ -859,7 +879,9 @@ gnc_file_quit (void)
gw_wcp_assimilate_ptr (session, scm_c_eval_string("<gnc:Session*>")) :
SCM_BOOL_F));
xaccLogDisable();
qof_session_destroy (session);
xaccLogEnable();
qof_session_get_current_session ();
+471 -451
View File
@@ -46,6 +46,7 @@
#include "gnc-date.h"
#include "gnc-trace.h"
#include "gnc-engine-util.h"
#include "gnc-filepath-utils.h"
#include "io-gncxml.h"
#include "io-gncbin.h"
@@ -63,18 +64,6 @@ static short module = MOD_BACKEND;
static int file_retention_days = 0;
static gboolean file_compression = FALSE;
static void gnc_file_be_load_from_file(QofBackend *, QofBook *);
static gboolean gnc_file_be_get_file_lock (FileBackend *be);
static gboolean gnc_file_be_write_to_file(FileBackend *be, QofBook *,
const gchar *filepath,
gboolean make_backup);
static void gnc_file_be_write_accounts_to_file(QofBackend *be,
QofBook *book);
static void gnc_file_be_remove_old_files(FileBackend *be);
QofBackend * libgncmod_backend_file_LTX_gnc_backend_new(void);
void
gnc_file_be_set_retention_days (int days)
{
@@ -89,263 +78,6 @@ gnc_file_be_set_compression (gboolean compress)
/* ================================================================= */
static void
file_session_begin(QofBackend *be_start, QofSession *session,
const char *book_id,
gboolean ignore_lock, gboolean create_if_nonexistent)
{
FileBackend *be = (FileBackend*) be_start;
char *p;
ENTER (" ");
/* Make sure the directory is there */
be->dirname = g_strdup (qof_session_get_file_path (session));
be->fullpath = g_strdup (be->dirname);
p = strrchr (be->dirname, '/');
if (p && p != be->dirname)
{
struct stat statbuf;
int rc;
*p = '\0';
rc = stat (be->dirname, &statbuf);
if (rc != 0 || !S_ISDIR(statbuf.st_mode))
{
qof_backend_set_error (be_start, ERR_FILEIO_FILE_NOT_FOUND);
g_free (be->fullpath); be->fullpath = NULL;
g_free (be->dirname); be->dirname = NULL;
return;
}
rc = stat (be->fullpath, &statbuf);
if (rc == 0 && S_ISDIR(statbuf.st_mode))
{
qof_backend_set_error (be_start, ERR_FILEIO_UNKNOWN_FILE_TYPE);
g_free (be->fullpath); be->fullpath = NULL;
g_free (be->dirname); be->dirname = NULL;
return;
}
}
/* ---------------------------------------------------- */
/* We should now have a fully resolved path name.
* Lets see if we can get a lock on it. */
be->lockfile = g_strconcat(be->fullpath, ".LCK", NULL);
if (!ignore_lock && !gnc_file_be_get_file_lock (be))
{
g_free (be->lockfile); be->lockfile = NULL;
return;
}
LEAVE (" ");
return;
}
/* ================================================================= */
static void
file_session_end(QofBackend *be_start)
{
FileBackend *be = (FileBackend*)be_start;
ENTER (" ");
if (be->linkfile)
unlink (be->linkfile);
if (be->lockfd > 0)
close (be->lockfd);
if (be->lockfile)
unlink (be->lockfile);
g_free (be->dirname);
be->dirname = NULL;
g_free (be->fullpath);
be->fullpath = NULL;
g_free (be->lockfile);
be->lockfile = NULL;
g_free (be->linkfile);
be->linkfile = NULL;
LEAVE (" ");
}
static void
file_destroy_backend(QofBackend *be)
{
g_free(be);
}
static void
file_sync_all(QofBackend* be, QofBook *book)
{
FileBackend *fbe = (FileBackend *) be;
ENTER ("book=%p, primary=%p", book, fbe->primary_book);
/* We make an important assumption here, that we might want to change
* in the future: when the user says 'save', we really save the one,
* the only, the current open book, and nothing else. We do this
* because we assume that any other books that we are dealing with
* are 'read-only', non-editable, because they are closed books.
* If we ever want to have more than one book open read-write,
* this will have to change.
*/
if (NULL == fbe->primary_book) fbe->primary_book = book;
if (book != fbe->primary_book) return;
gnc_file_be_write_to_file (fbe, book, fbe->fullpath, TRUE);
gnc_file_be_remove_old_files (fbe);
LEAVE ("book=%p", book);
}
/* ================================================================= */
/* Routines to deal with the creation of multiple books.
* The core design assumption here is that the book
* begin-edit/commit-edit routines are used solely to write out
* closed accounting periods to files. They're not currently
* designed to do anything other than this. (Although they could be).
*/
static char *
build_period_filepath (FileBackend *fbe, QofBook *book)
{
int len;
char *str, *p, *q;
len = strlen (fbe->fullpath) + GUID_ENCODING_LENGTH + 14;
str = g_new (char, len);
strcpy (str, fbe->fullpath);
/* XXX it would be nice for the user if we made the book
* closing date and/or title part of the file-name. */
p = strrchr (str, '/');
p++;
p = stpcpy (p, "book-");
p = guid_to_string_buff (qof_book_get_guid(book), p);
p = stpcpy (p, "-");
q = strrchr (fbe->fullpath, '/');
q++;
p = stpcpy (p, q);
p = stpcpy (p, ".gml");
return str;
}
static void
file_begin_edit (QofBackend *be, QofInstance *inst)
{
if (0) build_period_filepath(0, 0);
#if BORKEN_FOR_NOW
FileBackend *fbe = (FileBackend *) be;
QofBook *book = gp;
const char * filepath;
QofIdTypeConst typ = QOF_ENTITY(inst)->e_type;
if (strcmp (GNC_ID_PERIOD, typ)) return;
filepath = build_period_filepath(fbe, book);
PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
if (NULL == fbe->primary_book)
{
PERR ("You should have saved the data "
"at least once before closing the books!\n");
}
/* XXX To be anal about it, we should really be checking to see
* if there already is a file with this book GUID, and disallowing
* further progress. This is because we are not allowed to
* modify books that are closed (They should be treated as
* 'read-only').
*/
#endif
}
static void
file_rollback_edit (QofBackend *be, QofInstance *inst)
{
#if BORKEN_FOR_NOW
QofBook *book = gp;
if (strcmp (GNC_ID_PERIOD, typ)) return;
PINFO ("book=%p", book);
#endif
}
static void
file_commit_edit (QofBackend *be, QofInstance *inst)
{
#if BORKEN_FOR_NOW
FileBackend *fbe = (FileBackend *) be;
QofBook *book = gp;
const char * filepath;
if (strcmp (GNC_ID_PERIOD, typ)) return;
filepath = build_period_filepath(fbe, book);
PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
gnc_file_be_write_to_file(fbe, book, filepath, FALSE);
/* We want to force a save of the current book at this point,
* because if we don't, and the user forgets to do so, then
* there'll be the same transactions in the closed book,
* and also in the current book. */
gnc_file_be_write_to_file (fbe, fbe->primary_book, fbe->fullpath, TRUE);
#endif
}
/* ================================================================= */
QofBackend *
libgncmod_backend_file_LTX_gnc_backend_new(void)
{
FileBackend *fbe;
QofBackend *be;
fbe = g_new0(FileBackend, 1);
be = (QofBackend*)fbe;
qof_backend_init(be);
be->session_begin = file_session_begin;
be->session_end = file_session_end;
be->destroy_backend = file_destroy_backend;
be->load = gnc_file_be_load_from_file;
/* The file backend treats accounting periods transactionally. */
be->begin = file_begin_edit;
be->commit = file_commit_edit;
be->rollback = file_rollback_edit;
/* The file backend always loads all data ... */
be->compile_query = NULL;
be->free_query = NULL;
be->run_query = NULL;
be->price_lookup = NULL;
be->counter = NULL;
/* The file backend will never be multi-user... */
be->events_pending = NULL;
be->process_events = NULL;
be->sync = file_sync_all;
be->export = gnc_file_be_write_accounts_to_file;
fbe->dirname = NULL;
fbe->fullpath = NULL;
fbe->lockfile = NULL;
fbe->linkfile = NULL;
fbe->lockfd = -1;
fbe->primary_book = NULL;
return be;
}
/* ================================================================= */
static gboolean
gnc_file_be_get_file_lock (FileBackend *be)
{
@@ -444,96 +176,106 @@ gnc_file_be_get_file_lock (FileBackend *be)
return TRUE;
}
/* ---------------------------------------------------------------------- */
static gboolean
is_gzipped_file(const gchar *name)
{
unsigned char buf[2];
int fd = open(name, O_RDONLY);
if(fd == 0)
{
return FALSE;
}
if(read(fd, buf, 2) != 2)
{
return FALSE;
}
if(buf[0] == 037 && buf[1] == 0213)
{
return TRUE;
}
return FALSE;
}
static QofBookFileType
gnc_file_be_determine_file_type(const char *path)
{
if(gnc_is_xml_data_file_v2(path)) {
return GNC_BOOK_XML2_FILE;
} else if(gnc_is_xml_data_file(path)) {
return GNC_BOOK_XML1_FILE;
} else if(is_gzipped_file(path)) {
return GNC_BOOK_XML2_FILE;
} else {
return GNC_BOOK_BIN_FILE;
}
}
/* Load financial data from a file into the book, automtically
detecting the format of the file, if possible. Return FALSE on
error, and set the error parameter to indicate what went wrong if
it's not NULL. This function does not manage file locks in any
way. */
/* ================================================================= */
static void
gnc_file_be_load_from_file (QofBackend *bend, QofBook *book)
file_session_begin(QofBackend *be_start, QofSession *session,
const char *book_id,
gboolean ignore_lock, gboolean create_if_nonexistent)
{
QofBackendError error = ERR_BACKEND_NO_ERR;
gboolean rc;
FileBackend *be = (FileBackend *) bend;
FileBackend *be = (FileBackend*) be_start;
char *p;
be->primary_book = book;
ENTER (" ");
switch (gnc_file_be_determine_file_type(be->fullpath))
/* Make sure the directory is there */
be->dirname = xaccResolveFilePath(book_id);
if (NULL == be->dirname)
{
case GNC_BOOK_XML2_FILE:
rc = qof_session_load_from_xml_file_v2 (be, book);
if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
break;
qof_backend_set_error (be_start, ERR_FILEIO_FILE_NOT_FOUND);
return;
}
be->fullpath = g_strdup (be->dirname);
be->be.fullpath = be->fullpath;
p = strrchr (be->dirname, '/');
if (p && p != be->dirname)
{
struct stat statbuf;
int rc;
case GNC_BOOK_XML1_FILE:
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(book, be->fullpath);
error = gnc_get_binfile_io_error();
break;
default:
PWARN("File not any known type");
error = ERR_FILEIO_UNKNOWN_FILE_TYPE;
break;
*p = '\0';
rc = stat (be->dirname, &statbuf);
if (rc != 0 || !S_ISDIR(statbuf.st_mode))
{
qof_backend_set_error (be_start, ERR_FILEIO_FILE_NOT_FOUND);
g_free (be->fullpath); be->fullpath = NULL;
g_free (be->dirname); be->dirname = NULL;
return;
}
rc = stat (be->fullpath, &statbuf);
if (rc == 0 && S_ISDIR(statbuf.st_mode))
{
qof_backend_set_error (be_start, ERR_FILEIO_UNKNOWN_FILE_TYPE);
g_free (be->fullpath); be->fullpath = NULL;
g_free (be->dirname); be->dirname = NULL;
return;
}
}
if(error != ERR_BACKEND_NO_ERR)
/* ---------------------------------------------------- */
/* We should now have a fully resolved path name.
* Lets see if we can get a lock on it. */
be->lockfile = g_strconcat(be->fullpath, ".LCK", NULL);
if (!ignore_lock && !gnc_file_be_get_file_lock (be))
{
qof_backend_set_error(bend, error);
g_free (be->lockfile); be->lockfile = NULL;
return;
}
/* We just got done loading, it can't possibly be dirty !! */
qof_book_mark_saved (book);
LEAVE (" ");
return;
}
/* ---------------------------------------------------------------------- */
/* ================================================================= */
static void
file_session_end(QofBackend *be_start)
{
FileBackend *be = (FileBackend*)be_start;
ENTER (" ");
if (be->linkfile)
unlink (be->linkfile);
if (be->lockfd > 0)
close (be->lockfd);
if (be->lockfile)
unlink (be->lockfile);
g_free (be->dirname);
be->dirname = NULL;
g_free (be->fullpath);
be->fullpath = NULL;
g_free (be->lockfile);
be->lockfile = NULL;
g_free (be->linkfile);
be->linkfile = NULL;
LEAVE (" ");
}
static void
file_destroy_backend(QofBackend *be)
{
g_free(be);
}
/* ================================================================= */
/* Write the financial data in a book to a file, returning FALSE on
error and setting the error_result to indicate what went wrong if
it's not NULL. This function does not manage file locks in any
@@ -594,6 +336,8 @@ copy_file(const char *orig, const char *bkup)
return TRUE;
}
/* ================================================================= */
static gboolean
gnc_int_link_or_make_backup(FileBackend *be, const char *orig, const char *bkup)
{
@@ -617,6 +361,47 @@ gnc_int_link_or_make_backup(FileBackend *be, const char *orig, const char *bkup)
return TRUE;
}
/* ================================================================= */
static gboolean
is_gzipped_file(const gchar *name)
{
unsigned char buf[2];
int fd = open(name, O_RDONLY);
if(fd == 0)
{
return FALSE;
}
if(read(fd, buf, 2) != 2)
{
return FALSE;
}
if(buf[0] == 037 && buf[1] == 0213)
{
return TRUE;
}
return FALSE;
}
static QofBookFileType
gnc_file_be_determine_file_type(const char *path)
{
if(gnc_is_xml_data_file_v2(path)) {
return GNC_BOOK_XML2_FILE;
} else if(gnc_is_xml_data_file(path)) {
return GNC_BOOK_XML1_FILE;
} else if(is_gzipped_file(path)) {
return GNC_BOOK_XML2_FILE;
} else {
return GNC_BOOK_BIN_FILE;
}
}
static gboolean
gnc_file_be_backup_file(FileBackend *be)
{
@@ -662,112 +447,8 @@ gnc_file_be_backup_file(FileBackend *be)
return bkup_ret;
}
static int
gnc_file_be_select_files (const struct dirent *d)
{
int len = strlen(d->d_name) - 4;
if (len <= 0)
return(0);
return((strcmp(d->d_name + len, ".LNK") == 0) ||
(strcmp(d->d_name + len, ".xac") == 0) ||
(strcmp(d->d_name + len, ".log") == 0));
}
static void
gnc_file_be_remove_old_files(FileBackend *be)
{
struct dirent *dent;
DIR *dir;
struct stat lockstatbuf, statbuf;
int pathlen;
time_t now;
if (stat (be->lockfile, &lockstatbuf) != 0)
return;
pathlen = strlen(be->fullpath);
/*
* Clean up any lockfiles from prior crashes, and clean up old
* data and log files. Scandir will do a fist pass on the
* filenames and cull the directory down to just files with the
* appropriate extensions. Pity you can't pass user data into
* scandir...
*/
/*
* Unfortunately scandir() is not portable, so re-write this
* function without it. Note that this version will be even a bit
* faster because it does not have to sort, malloc, or anything
* else that scandir did, and it only performs a single pass
* through the directory rather than one pass through the
* directory and then one pass over the 'matching' files. --
* warlord@MIT.EDU 2002-05-06
*/
dir = opendir (be->dirname);
if (!dir)
return;
now = time(NULL);
while((dent = readdir(dir)) != NULL) {
char *name;
int len;
if (gnc_file_be_select_files (dent) == 0)
continue;
name = g_strconcat(be->dirname, "/", dent->d_name, NULL);
len = strlen(name) - 4;
/* Is this file associated with the current data file */
if (strncmp(name, be->fullpath, pathlen) == 0)
{
if ((safe_strcmp(name + len, ".LNK") == 0) &&
/* Is a lock file. Skip the active lock file */
(safe_strcmp(name, be->linkfile) != 0) &&
/* Only delete lock files older than the active one */
(stat(name, &statbuf) == 0) &&
(statbuf.st_mtime <lockstatbuf.st_mtime))
{
PINFO ("unlink lock file: %s", name);
unlink(name);
}
else if (file_retention_days > 0)
{
time_t file_time;
struct tm file_tm;
int days;
const char* res;
PINFO ("file retention = %d days", file_retention_days);
/* Is the backup file old enough to delete */
memset(&file_tm, 0, sizeof(file_tm));
res = strptime(name+pathlen+1, "%Y%m%d%H%M%S", &file_tm);
file_time = mktime(&file_tm);
days = (int)(difftime(now, file_time) / 86400);
/* Make sure this file actually has a date before unlinking */
if (res && res != name+pathlen+1 &&
/* We consumed some but not all of the filename */
file_time > 0 &&
/* we actually have a reasonable time and it is old enough */
days > file_retention_days)
{
PINFO ("unlink stale (%d days old) file: %s", days, name);
unlink(name);
}
}
}
g_free(name);
}
closedir (dir);
}
/* ---------------------------------------------------------------------- */
/* ================================================================= */
static gboolean
gnc_file_be_write_to_file(FileBackend *fbe,
QofBook *book,
@@ -892,6 +573,295 @@ gnc_file_be_write_to_file(FileBackend *fbe,
return TRUE;
}
/* ================================================================= */
static int
gnc_file_be_select_files (const struct dirent *d)
{
int len = strlen(d->d_name) - 4;
if (len <= 0)
return(0);
return((strcmp(d->d_name + len, ".LNK") == 0) ||
(strcmp(d->d_name + len, ".xac") == 0) ||
(strcmp(d->d_name + len, ".log") == 0));
}
static void
gnc_file_be_remove_old_files(FileBackend *be)
{
struct dirent *dent;
DIR *dir;
struct stat lockstatbuf, statbuf;
int pathlen;
time_t now;
if (stat (be->lockfile, &lockstatbuf) != 0)
return;
pathlen = strlen(be->fullpath);
/*
* Clean up any lockfiles from prior crashes, and clean up old
* data and log files. Scandir will do a fist pass on the
* filenames and cull the directory down to just files with the
* appropriate extensions. Pity you can't pass user data into
* scandir...
*/
/*
* Unfortunately scandir() is not portable, so re-write this
* function without it. Note that this version will be even a bit
* faster because it does not have to sort, malloc, or anything
* else that scandir did, and it only performs a single pass
* through the directory rather than one pass through the
* directory and then one pass over the 'matching' files. --
* warlord@MIT.EDU 2002-05-06
*/
dir = opendir (be->dirname);
if (!dir)
return;
now = time(NULL);
while((dent = readdir(dir)) != NULL) {
char *name;
int len;
if (gnc_file_be_select_files (dent) == 0)
continue;
name = g_strconcat(be->dirname, "/", dent->d_name, NULL);
len = strlen(name) - 4;
/* Is this file associated with the current data file */
if (strncmp(name, be->fullpath, pathlen) == 0)
{
if ((safe_strcmp(name + len, ".LNK") == 0) &&
/* Is a lock file. Skip the active lock file */
(safe_strcmp(name, be->linkfile) != 0) &&
/* Only delete lock files older than the active one */
(stat(name, &statbuf) == 0) &&
(statbuf.st_mtime <lockstatbuf.st_mtime))
{
PINFO ("unlink lock file: %s", name);
unlink(name);
}
else if (file_retention_days > 0)
{
time_t file_time;
struct tm file_tm;
int days;
const char* res;
PINFO ("file retention = %d days", file_retention_days);
/* Is the backup file old enough to delete */
memset(&file_tm, 0, sizeof(file_tm));
res = strptime(name+pathlen+1, "%Y%m%d%H%M%S", &file_tm);
file_time = mktime(&file_tm);
days = (int)(difftime(now, file_time) / 86400);
/* Make sure this file actually has a date before unlinking */
if (res && res != name+pathlen+1 &&
/* We consumed some but not all of the filename */
file_time > 0 &&
/* we actually have a reasonable time and it is old enough */
days > file_retention_days)
{
PINFO ("unlink stale (%d days old) file: %s", days, name);
unlink(name);
}
}
}
g_free(name);
}
closedir (dir);
}
static void
file_sync_all(QofBackend* be, QofBook *book)
{
FileBackend *fbe = (FileBackend *) be;
ENTER ("book=%p, primary=%p", book, fbe->primary_book);
/* We make an important assumption here, that we might want to change
* in the future: when the user says 'save', we really save the one,
* the only, the current open book, and nothing else. We do this
* because we assume that any other books that we are dealing with
* are 'read-only', non-editable, because they are closed books.
* If we ever want to have more than one book open read-write,
* this will have to change.
*/
if (NULL == fbe->primary_book) fbe->primary_book = book;
if (book != fbe->primary_book) return;
gnc_file_be_write_to_file (fbe, book, fbe->fullpath, TRUE);
gnc_file_be_remove_old_files (fbe);
LEAVE ("book=%p", book);
}
/* ================================================================= */
/* Routines to deal with the creation of multiple books.
* The core design assumption here is that the book
* begin-edit/commit-edit routines are used solely to write out
* closed accounting periods to files. They're not currently
* designed to do anything other than this. (Although they could be).
*/
static char *
build_period_filepath (FileBackend *fbe, QofBook *book)
{
int len;
char *str, *p, *q;
len = strlen (fbe->fullpath) + GUID_ENCODING_LENGTH + 14;
str = g_new (char, len);
strcpy (str, fbe->fullpath);
/* XXX it would be nice for the user if we made the book
* closing date and/or title part of the file-name. */
p = strrchr (str, '/');
p++;
p = stpcpy (p, "book-");
p = guid_to_string_buff (qof_book_get_guid(book), p);
p = stpcpy (p, "-");
q = strrchr (fbe->fullpath, '/');
q++;
p = stpcpy (p, q);
p = stpcpy (p, ".gml");
return str;
}
static void
file_begin_edit (QofBackend *be, QofInstance *inst)
{
if (0) build_period_filepath(0, 0);
#if BORKEN_FOR_NOW
FileBackend *fbe = (FileBackend *) be;
QofBook *book = gp;
const char * filepath;
QofIdTypeConst typ = QOF_ENTITY(inst)->e_type;
if (strcmp (GNC_ID_PERIOD, typ)) return;
filepath = build_period_filepath(fbe, book);
PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
if (NULL == fbe->primary_book)
{
PERR ("You should have saved the data "
"at least once before closing the books!\n");
}
/* XXX To be anal about it, we should really be checking to see
* if there already is a file with this book GUID, and disallowing
* further progress. This is because we are not allowed to
* modify books that are closed (They should be treated as
* 'read-only').
*/
#endif
}
static void
file_rollback_edit (QofBackend *be, QofInstance *inst)
{
#if BORKEN_FOR_NOW
QofBook *book = gp;
if (strcmp (GNC_ID_PERIOD, typ)) return;
PINFO ("book=%p", book);
#endif
}
static void
file_commit_edit (QofBackend *be, QofInstance *inst)
{
#if BORKEN_FOR_NOW
FileBackend *fbe = (FileBackend *) be;
QofBook *book = gp;
const char * filepath;
if (strcmp (GNC_ID_PERIOD, typ)) return;
filepath = build_period_filepath(fbe, book);
PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
gnc_file_be_write_to_file(fbe, book, filepath, FALSE);
/* We want to force a save of the current book at this point,
* because if we don't, and the user forgets to do so, then
* there'll be the same transactions in the closed book,
* and also in the current book. */
gnc_file_be_write_to_file (fbe, fbe->primary_book, fbe->fullpath, TRUE);
#endif
}
/* ---------------------------------------------------------------------- */
/* Load financial data from a file into the book, automtically
detecting the format of the file, if possible. Return FALSE on
error, and set the error parameter to indicate what went wrong if
it's not NULL. This function does not manage file locks in any
way. */
static void
gnc_file_be_load_from_file (QofBackend *bend, QofBook *book)
{
QofBackendError error = ERR_BACKEND_NO_ERR;
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, book);
if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
break;
case GNC_BOOK_XML1_FILE:
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(book, be->fullpath);
error = gnc_get_binfile_io_error();
break;
default:
PWARN("File not any known type");
error = ERR_FILEIO_UNKNOWN_FILE_TYPE;
break;
}
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);
}
/* ---------------------------------------------------------------------- */
static gboolean
gnc_file_be_save_may_clobber_data (QofBackend *bend)
{
struct stat statbuf;
if (!bend->fullpath) return FALSE;
/* FIXME: Make sure this doesn't need more sophisticated semantics
* in the face of special file, devices, pipes, symlinks, etc. */
if (stat(bend->fullpath, &statbuf) == 0) return TRUE;
return FALSE;
}
static void
gnc_file_be_write_accounts_to_file(QofBackend *be, QofBook *book)
{
@@ -901,4 +871,54 @@ gnc_file_be_write_accounts_to_file(QofBackend *be, QofBook *book)
gnc_book_write_accounts_to_xml_file_v2(be, book, datafile);
}
/* ================================================================= */
QofBackend *
libgncmod_backend_file_LTX_gnc_backend_new(void)
{
FileBackend *fbe;
QofBackend *be;
fbe = g_new0(FileBackend, 1);
be = (QofBackend*)fbe;
qof_backend_init(be);
be->session_begin = file_session_begin;
be->session_end = file_session_end;
be->destroy_backend = file_destroy_backend;
be->load = gnc_file_be_load_from_file;
be->save_may_clobber_data = gnc_file_be_save_may_clobber_data;
/* The file backend treats accounting periods transactionally. */
be->begin = file_begin_edit;
be->commit = file_commit_edit;
be->rollback = file_rollback_edit;
/* The file backend always loads all data ... */
be->compile_query = NULL;
be->free_query = NULL;
be->run_query = NULL;
be->price_lookup = NULL;
be->counter = NULL;
/* The file backend will never be multi-user... */
be->events_pending = NULL;
be->process_events = NULL;
be->sync = file_sync_all;
be->export = gnc_file_be_write_accounts_to_file;
fbe->dirname = NULL;
fbe->fullpath = NULL;
fbe->lockfile = NULL;
fbe->linkfile = NULL;
fbe->lockfd = -1;
fbe->primary_book = NULL;
return be;
}
/* ========================== END OF FILE ===================== */
+2
View File
@@ -57,4 +57,6 @@ typedef enum
GNC_BOOK_XML2_FILE,
} QofBookFileType;
QofBackend * libgncmod_backend_file_LTX_gnc_backend_new(void);
#endif /* GNC_BACKEND_FILE_H_ */
+2
View File
@@ -30,6 +30,7 @@ libgncmod_engine_la_SOURCES = \
gnc-engine-util.c \
gnc-engine.c \
gnc-event.c \
gnc-filepath-utils.c \
gnc-lot.c \
gnc-numeric.c \
gnc-pricedb.c \
@@ -83,6 +84,7 @@ gncinclude_HEADERS = \
gnc-engine-util.h \
gnc-engine.h \
gnc-event.h \
gnc-filepath-utils.h \
gnc-numeric.h \
gnc-pricedb.h \
gnc-session.h \
+1
View File
@@ -21,6 +21,7 @@
ws
(lambda (wrapset client-wrapset)
(list
"#include <config.h>\n"
"#include <glib.h>\n"
"#include <guid.h>\n"
"#include <Group.h>\n"
+28 -19
View File
@@ -1,8 +1,6 @@
/********************************************************************\
* qofbackend-p.h -- private api for data storage backend *
* *
* Copyright (c) 2000, 2001 Linas Vepstas <linas@linas.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 *
@@ -34,6 +32,10 @@
The callbacks will be called at the appropriate times during
a book session to allow the backend to store the data as needed.
@file qofbackend-p.h
@brief private api for data storage backend
@author Copyright (c) 2000,2001,2004 Linas Vepstas <linas@linas.org>
@{ */
#ifndef QOF_BACKEND_P_H
@@ -242,7 +244,6 @@ struct QofBackendProvider_s
struct QofBackend_s
{
void (*session_begin) (QofBackend *be,
QofSession *session,
const char *book_id,
@@ -265,14 +266,24 @@ struct QofBackend_s
gint64 (*counter) (QofBackend *, const char *counter_name);
gboolean (*events_pending) (QofBackend *be);
gboolean (*process_events) (QofBackend *be);
gboolean (*events_pending) (QofBackend *);
gboolean (*process_events) (QofBackend *);
QofBePercentageFunc percentage;
/** Document Me !!! what is this supposed to do ?? */
gboolean (*save_may_clobber_data) (QofBackend *);
QofBackendError last_err;
char * error_msg;
/** XXX the file backend resolves the if to a fully-qualified file
* path. This holds the filepath and communicates it to the GUI.
* This is temprary scaffolding and should be removed. Deprecated.
*/
char * fullpath;
#ifdef GNUCASH_MAJOR_VERSION
/** XXX price_lookup should be removed during the redesign
* of the SQL backend... prices can now be queried using
* the generic query mechanism.
@@ -285,12 +296,15 @@ struct QofBackend_s
/** XXX Export should really _NOT_ be here, but is left here for now.
* I'm not sure where this should be going to. It should be
* removed ASAP.
* removed ASAP. This is a temporary hack-around until period-closing
* is fully implemented.
*/
void (*export) (QofBackend *, QofBook *);
#endif
};
/** Let the ssytem know about a new provider of backends. This function
/** Let the sytem know about a new provider of backends. This function
* is typically called by the provider library at library load time.
* This function allows the backend library to tell the QOF infrastructure
* that it can handle URL's of a certain type. Note that a single
@@ -299,26 +313,21 @@ struct QofBackend_s
*/
void qof_backend_register_provider (QofBackendProvider *);
/**
* The qof_backend_set_error() routine pushes an error code onto the error
* stack. (FIXME: the stack is 1 deep in current implementation).
/** The qof_backend_set_error() routine pushes an error code onto the error
* stack. (FIXME: the stack is 1 deep in current implementation).
*/
void qof_backend_set_error (QofBackend *be, QofBackendError err);
/**
* The qof_backend_get_error() routine pops an error code off the error
* stack.
/** The qof_backend_get_error() routine pops an error code off the error stack.
*/
QofBackendError qof_backend_get_error (QofBackend *be);
/**
* The qof_backend_set_message() assigns a string to the backend error
* message.
/** The qof_backend_set_message() assigns a string to the backend error message.
*/
void qof_backend_set_message(QofBackend *be, const char *format, ...);
/**
* The qof_backend_get_message() pops the error message string from
* the Backend. This string should be freed with g_free().
/** The qof_backend_get_message() pops the error message string from
* the Backend. This string should be freed with g_free().
*/
char * qof_backend_get_message(QofBackend *be);
+3
View File
@@ -130,9 +130,12 @@ qof_backend_init(QofBackend *be)
be->error_msg = NULL;
be->percentage = NULL;
#ifdef GNUCASH_MAJOR_VERSION
/* XXX remove these */
be->fullpath = NULL;
be->price_lookup = NULL;
be->export = NULL;
#endif
}
/************************* END OF FILE ********************************/
-3
View File
@@ -53,9 +53,6 @@ struct _QofSession
QofBackendError last_err;
char *error_message;
char *fullpath;
char *logpath;
/* ---------------------------------------------------- */
/* Pointer to the backend that is actually used to move data
* between the persistant store and the local engine. */
+30 -352
View File
@@ -59,13 +59,8 @@
#include "qofsession-p.h"
/* Some gnucash-specific code */
#ifdef GNUCASH
#ifdef GNUCASH_MAJOR_VERSION
#include "gnc-module.h"
#include "TransLog.h"
#else
#define xaccLogSetBaseName(x)
#define xaccLogEnable()
#define xaccLogDisable()
#endif /* GNUCASH */
static QofSession * current_session = NULL;
@@ -172,8 +167,6 @@ qof_session_init (QofSession *session)
session->books = g_list_append (NULL, qof_book_new ());
session->book_id = NULL;
session->fullpath = NULL;
session->logpath = NULL;
session->backend = NULL;
qof_session_clear_error (session);
@@ -265,7 +258,8 @@ const char *
qof_session_get_file_path (QofSession *session)
{
if (!session) return NULL;
return session->fullpath;
if (!session->backend) return NULL;
return session->backend->fullpath;
}
const char *
@@ -277,7 +271,7 @@ qof_session_get_url (QofSession *session)
/* ====================================================================== */
#ifdef GNUCASH
#ifdef GNUCASH_MAJOR_VERSION
static void
qof_session_int_backend_load_error(QofSession *session,
@@ -285,12 +279,6 @@ qof_session_int_backend_load_error(QofSession *session,
{
PWARN ("%s %s", message, dll_err ? dll_err : "");
g_free(session->fullpath);
session->fullpath = NULL;
g_free(session->logpath);
session->logpath = NULL;
g_free(session->book_id);
session->book_id = NULL;
@@ -437,57 +425,30 @@ qof_session_begin (QofSession *session, const char * book_id,
LEAVE("push error missing book_id");
return;
}
/* Store the sessionid URL */
/* Store the session URL */
session->book_id = g_strdup (book_id);
/* XXX we should probably move this resolve function to the
* file backend. I think the idea would be to open the backend
* and then ask it if it can contact it's storage media (disk,
* network, server, etc.) and abort if it can't. Mal-formed
* file URL's would be handled the same way!
*/
/* ResolveURL tries to find the file in the file system. */
session->fullpath = xaccResolveURL(book_id);
if (!session->fullpath)
{
qof_session_push_error (session, ERR_FILEIO_FILE_NOT_FOUND, NULL);
LEAVE("push error: can't resolve file path");
return;
}
PINFO ("filepath=%s", session->fullpath ? session->fullpath : "(null)");
session->logpath = xaccResolveFilePath(session->fullpath);
PINFO ("logpath=%s", session->logpath ? session->logpath : "(null)");
/* destroy the old backend */
qof_session_destroy_backend(session);
/* check to see if this is a type we know how to handle */
if (!g_strncasecmp(book_id, "file:", 5) ||
*session->fullpath == '/')
/* Look for somthing of the form of "file:/", "http://" or
* "postgres://". Everything before the colon is the access
* method. Load the first backend found for that access method.
*/
char * p = strchr (book_id, ':');
if (p)
{
qof_session_load_backend(session, "file" );
char * access_method = g_strdup (book_id);
p = strchr (access_method, ':');
*p = 0;
qof_session_load_backend(session, access_method);
g_free (access_method);
}
else
{
/* Look for somthing of the form of "http://" or
* "postgres://". Everything before the colon is the access
* method. Load the first backend found for that access method.
*/
char * p = strchr (book_id, ':');
if (p)
{
char * access_method = g_strdup (book_id);
p = strchr (access_method, ':');
*p = 0;
qof_session_load_backend(session, access_method);
g_free (access_method);
}
else
{
/* If no colon found, assume it must be a file-path */
qof_session_load_backend(session, "file");
}
/* If no colon found, assume it must be a file-path */
qof_session_load_backend(session, "file");
}
/* No backend was found. That's bad. */
@@ -513,10 +474,6 @@ qof_session_begin (QofSession *session, const char * book_id,
msg = qof_backend_get_message(session->backend);
if (err != ERR_BACKEND_NO_ERR)
{
g_free(session->fullpath);
session->fullpath = NULL;
g_free(session->logpath);
session->logpath = NULL;
g_free(session->book_id);
session->book_id = NULL;
qof_session_push_error (session, err, msg);
@@ -560,8 +517,6 @@ qof_session_load (QofSession *session,
session->books = g_list_append (NULL, newbook);
PINFO ("new book=%p", newbook);
xaccLogSetBaseName(session->logpath);
qof_session_clear_error (session);
/* This code should be sufficient to initialize *any* backend,
@@ -580,7 +535,6 @@ qof_session_load (QofSession *session,
*/
if (be)
{
xaccLogDisable();
be->percentage = percentage_func;
if (be->load)
@@ -588,7 +542,6 @@ qof_session_load (QofSession *session,
be->load (be, newbook);
qof_session_push_error (session, qof_backend_get_error(be), NULL);
}
xaccLogEnable();
}
err = qof_session_get_error(session);
@@ -597,24 +550,20 @@ qof_session_load (QofSession *session,
(err != ERR_SQL_DB_TOO_OLD))
{
/* Something broke, put back the old stuff */
xaccLogDisable();
qof_book_set_backend (newbook, NULL);
qof_book_destroy (newbook);
g_list_free (session->books);
session->books = oldbooks;
LEAVE("error from backend %d", qof_session_get_error(session));
xaccLogEnable();
return;
}
xaccLogDisable();
for (node=oldbooks; node; node=node->next)
{
QofBook *ob = node->data;
qof_book_set_backend (ob, NULL);
qof_book_destroy (ob);
}
xaccLogEnable();
LEAVE ("sess = %p, book_id=%s", session, qof_session_get_url(session)
? qof_session_get_url(session) : "(null)");
@@ -625,19 +574,11 @@ qof_session_load (QofSession *session,
gboolean
qof_session_save_may_clobber_data (QofSession *session)
{
struct stat statbuf;
if (!session) return FALSE;
if (!session->fullpath) return FALSE;
if (!session->backend) return FALSE;
if (!session->backend->save_may_clobber_data) return FALSE;
/* FIXME: This should really be sent to the backend. The stat is
* correct only for the file backend */
/* FIXME: Make sure this doesn't need more sophisticated semantics
* in the face of special file, devices, pipes, symlinks, etc. */
if (stat(session->fullpath, &statbuf) == 0) return TRUE;
return FALSE;
return (*(session->backend->save_may_clobber_data)) (session->backend);
}
static gboolean
@@ -717,7 +658,11 @@ qof_session_save (QofSession *session,
}
/* ====================================================================== */
/* XXX what does this function do ?? */
/* XXX This exports the list of accounts to a file. It does not export
* any transactions. Its a place-holder until full book-closing is implemented.
*/
#ifdef GNUCASH_MAJOR_VERSION
gboolean
qof_session_export (QofSession *tmp_session,
@@ -752,6 +697,7 @@ qof_session_export (QofSession *tmp_session,
return TRUE;
}
#endif /* GNUCASH_MAJOR_VERSION */
/* ====================================================================== */
@@ -771,12 +717,6 @@ qof_session_end (QofSession *session)
qof_session_clear_error (session);
g_free (session->fullpath);
session->fullpath = NULL;
g_free (session->logpath);
session->logpath = NULL;
g_free (session->book_id);
session->book_id = NULL;
@@ -794,7 +734,6 @@ qof_session_destroy (QofSession *session)
qof_session_get_url(session)
? qof_session_get_url(session) : "(null)");
xaccLogDisable();
qof_session_end (session);
/* destroy the backend */
@@ -811,8 +750,6 @@ qof_session_destroy (QofSession *session)
if (session == current_session)
current_session = NULL;
xaccLogEnable();
g_free (session);
LEAVE ("sess=%p", session);
@@ -874,273 +811,14 @@ qof_session_process_events (QofSession *session)
}
/* ====================================================================== */
/*
* If $HOME/.gnucash/data directory doesn't exist, then create it.
*/
static void
MakeHomeDir (void)
{
int rc;
struct stat statbuf;
char *home;
char *path;
char *data;
/* Punt. Can't figure out where home is. */
home = getenv ("HOME");
if (!home) return;
path = g_strconcat(home, "/.gnucash", NULL);
rc = stat (path, &statbuf);
if (rc)
{
/* assume that the stat failed only because the dir is absent,
* and not because its read-protected or other error.
* Go ahead and make it. Don't bother much with checking mkdir
* for errors; seems pointless. */
mkdir (path, S_IRWXU); /* perms = S_IRWXU = 0700 */
}
data = g_strconcat (path, "/data", NULL);
rc = stat (data, &statbuf);
if (rc)
mkdir (data, S_IRWXU);
g_free (path);
g_free (data);
}
/* ====================================================================== */
/* XXX hack alert -- we should be yanking this out of some config file */
static char * searchpaths[] =
{
"/usr/share/gnucash/data/",
"/usr/local/share/gnucash/data/",
"/usr/share/gnucash/accounts/",
"/usr/local/share/gnucash/accounts/",
NULL,
};
typedef gboolean (*pathGenerator)(char *pathbuf, int which);
static gboolean
xaccAddEndPath(char *pathbuf, const char *ending, int len)
{
if(len + strlen(pathbuf) >= PATH_MAX)
return FALSE;
strcat (pathbuf, ending);
return TRUE;
}
static gboolean
xaccCwdPathGenerator(char *pathbuf, int which)
{
if(which != 0)
{
return FALSE;
}
else
{
/* try to find a file by this name in the cwd ... */
if (getcwd (pathbuf, PATH_MAX) == NULL)
return FALSE;
strcat (pathbuf, "/");
return TRUE;
}
}
static gboolean
xaccDataPathGenerator(char *pathbuf, int which)
{
char *path;
if(which != 0)
{
return FALSE;
}
else
{
path = getenv ("HOME");
if (!path)
return FALSE;
if (PATH_MAX <= (strlen (path) + 20))
return FALSE;
strcpy (pathbuf, path);
strcat (pathbuf, "/.gnucash/data/");
return TRUE;
}
}
static gboolean
xaccUserPathPathGenerator(char *pathbuf, int which)
{
char *path = NULL;
if(searchpaths[which] == NULL)
{
return FALSE;
}
else
{
path = searchpaths[which];
if (PATH_MAX <= strlen(path))
return FALSE;
strcpy (pathbuf, path);
return TRUE;
}
}
/* ====================================================================== */
char *
xaccResolveFilePath (const char * filefrag)
{
struct stat statbuf;
char pathbuf[PATH_MAX];
pathGenerator gens[4];
char *filefrag_dup;
int namelen;
int i;
/* seriously invalid */
if (!filefrag)
{
PERR("filefrag is NULL");
return NULL;
}
ENTER ("filefrag=%s", filefrag);
/* ---------------------------------------------------- */
/* OK, now we try to find or build an absolute file path */
/* check for an absolute file path */
if (*filefrag == '/')
return g_strdup (filefrag);
if (!g_strncasecmp(filefrag, "file:", 5))
{
char *ret = g_new(char, strlen(filefrag) - 5 + 1);
strcpy(ret, filefrag + 5);
return ret;
}
/* get conservative on the length so that sprintf(getpid()) works ... */
/* strlen ("/.LCK") + sprintf (%x%d) */
namelen = strlen (filefrag) + 25;
gens[0] = xaccCwdPathGenerator;
gens[1] = xaccDataPathGenerator;
gens[2] = xaccUserPathPathGenerator;
gens[3] = NULL;
for (i = 0; gens[i] != NULL; i++)
{
int j;
for(j = 0; gens[i](pathbuf, j) ; j++)
{
if(xaccAddEndPath(pathbuf, filefrag, namelen))
{
int rc = stat (pathbuf, &statbuf);
if ((!rc) && (S_ISREG(statbuf.st_mode)))
{
return (g_strdup (pathbuf));
}
}
}
}
/* OK, we didn't find the file. */
/* make sure that the gnucash home dir exists. */
MakeHomeDir();
filefrag_dup = g_strdup (filefrag);
/* Replace '/' with ',' for non file backends */
if (strstr (filefrag, "://"))
{
char *p;
p = strchr (filefrag_dup, '/');
while (p) {
*p = ',';
p = strchr (filefrag_dup, '/');
}
}
/* Lets try creating a new file in $HOME/.gnucash/data */
if (xaccDataPathGenerator(pathbuf, 0))
{
if(xaccAddEndPath(pathbuf, filefrag_dup, namelen))
{
g_free (filefrag_dup);
return (g_strdup (pathbuf));
}
}
/* OK, we still didn't find the file */
/* Lets try creating a new file in the cwd */
if (xaccCwdPathGenerator(pathbuf, 0))
{
if(xaccAddEndPath(pathbuf, filefrag_dup, namelen))
{
g_free (filefrag_dup);
return (g_strdup (pathbuf));
}
}
g_free (filefrag_dup);
return NULL;
}
/* ====================================================================== */
char *
xaccResolveURL (const char * pathfrag)
{
/* seriously invalid */
if (!pathfrag) return NULL;
/* At this stage of checking, URL's are always, by definition,
* resolved. If there's an error connecting, we'll find out later.
*
* FIXME -- we should probably use ghttp_uri_validate
* to make sure the uri is in good form.
*/
if (!g_strncasecmp (pathfrag, "http://", 7) ||
!g_strncasecmp (pathfrag, "https://", 8) ||
!g_strncasecmp (pathfrag, "postgres://", 11) ||
!g_strncasecmp (pathfrag, "rpc://", 6))
{
return g_strdup(pathfrag);
}
if (!g_strncasecmp (pathfrag, "file:", 5)) {
return (xaccResolveFilePath (pathfrag));
}
return (xaccResolveFilePath (pathfrag));
}
/* ====================================================================== */
#ifdef GNUCASH_MAJOR_VERSION
/* this should go in a separate binary to create a rpc server */
void
gnc_run_rpc_server (void)
{
#ifdef GNUCASH
const char * dll_err;
void * dll_handle;
int (*rpc_run)(short);
@@ -1173,7 +851,7 @@ gnc_run_rpc_server (void)
ret = (*rpc_run)(0);
/* XXX How do we force an exit? */
#endif /* GNUCASH */
}
#endif /* GNUCASH_MAJOR_VERSION */
/* =================== END OF FILE ====================================== */
+11 -18
View File
@@ -156,11 +156,6 @@ typedef void (*QofPercentageFunc) (const char *message, double percent);
void qof_session_load (QofSession *session,
QofPercentageFunc percentage_func);
/** XXX session_export really doesn't belong here */
gboolean qof_session_export (QofSession *tmp_session,
QofSession *real_session,
QofPercentageFunc percentage_func);
/** @name Session Errors
@{ */
/** The qof_session_get_error() routine can be used to obtain the reason
@@ -251,22 +246,20 @@ gboolean qof_session_events_pending (QofSession *session);
gboolean qof_session_process_events (QofSession *session);
/* @} */
/** The xaccResolveFilePath() routine is a utility that will accept
* a fragmentary filename as input, and resolve it into a fully
* qualified path in the file system, i.e. a path that begins with
* a leading slash. First, the current working directory is
* searched for the file. Next, the directory $HOME/.gnucash/data,
* and finally, a list of other (configurable) paths. If the file
* is not found, then the path $HOME/.gnucash/data is used. If
* $HOME is not defined, then the current working directory is
* used.
*/
char * xaccResolveFilePath (const char * filefrag);
char * xaccResolveURL (const char * pathfrag);
#ifdef GNUCASH_MAJOR_VERSION
/** Run the RPC Server
* @deprecated will go away */
void gnc_run_rpc_server (void);
/** XXX session_export really doesn't belong here .
* This functino exports the list of accounts to a file. Its a stop-gap
* measure until full book-closing is implemented.
*/
gboolean qof_session_export (QofSession *tmp_session,
QofSession *real_session,
QofPercentageFunc percentage_func);
#endif /* GNUCASH_MJOR_VERSION */
#endif /* QOF_SESSION_H */
/** @} */
+1
View File
@@ -5,6 +5,7 @@
#include "test-stuff.h"
#include "gnc-engine-util.h"
#include "gnc-filepath-utils.h"
#include "qofsession.h"
struct test_strings_struct