[Gnucash-changes] Backend configuration support and new method for dlopen()

Neil Williams codehelp at cvs.gnucash.org
Mon Aug 22 16:00:44 EDT 2005


Log Message:
-----------
Backend configuration support and new method for dlopen()

Tags:
----
gnucash-gnome2-dev

Modified Files:
--------------
    gnucash/src/engine:
        qofbackend-p.h
        qofbackend.c
        qofbackend.h

Revision Data
-------------
Index: qofbackend.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbackend.c,v
retrieving revision 1.2.4.3
retrieving revision 1.2.4.4
diff -Lsrc/engine/qofbackend.c -Lsrc/engine/qofbackend.c -u -r1.2.4.3 -r1.2.4.4
--- src/engine/qofbackend.c
+++ src/engine/qofbackend.c
@@ -21,11 +21,16 @@
  *                                                                  *
 \********************************************************************/
 
+#define _GNU_SOURCE
 #include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
 #include <stdarg.h>
+#include <regex.h>
 #include <glib.h>
-
-#include "qofbackend.h"
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <errno.h>
 #include "qofbackend-p.h"
 
 /* static short module = MOD_BACKEND; */
@@ -121,6 +126,7 @@
     be->run_query = NULL;
 
     be->sync = NULL;
+	be->load_config = NULL;
 
     be->events_pending = NULL;
     be->process_events = NULL;
@@ -129,6 +135,7 @@
     if (be->error_msg) g_free (be->error_msg);
     be->error_msg = NULL;
     be->percentage = NULL;
+	be->backend_configuration = kvp_frame_new();
 
 #ifdef GNUCASH_MAJOR_VERSION
     /* XXX remove these */
@@ -141,6 +148,8 @@
 void
 qof_backend_run_begin(QofBackend *be, QofInstance *inst)
 {
+	if(!be | !inst) { return; }
+	if(!be->begin) { return; }
 	(be->begin) (be, inst);
 }
 
@@ -154,16 +163,43 @@
 void
 qof_backend_run_commit(QofBackend *be, QofInstance *inst)
 {
+	if(!be | !inst) { return; }
+	if(!be->commit) { return; }
 	(be->commit) (be, inst);
 }
 
+void
+qof_backend_load_config(QofBackend *be, KvpFrame *config)
+{
+	if(!be | !config) { return; }
+	if(!be->load_config) { return; }
+	(be->load_config) (be, config);
+}
+
+KvpFrame*
+qof_backend_get_config(QofBackend *be)
+{
+	if(!be) { return NULL; }
+	if(!be->get_config) { return NULL; }
+	return (be->get_config) (be);
+}
+
 gboolean
 qof_backend_commit_exists(QofBackend *be)
 {
+	if(!be) { return FALSE; }
 	if(be->commit) { return TRUE; }
 	else { return FALSE; }
 }
 
+gboolean
+qof_backend_check_type (QofBackend *be, const char *path)
+{
+	if(!be) { return FALSE; }
+	if(!be->check_data_type) { return FALSE; }
+	return (gboolean)(be->check_data_type) (be, path);
+}
+
 void 
 qof_begin_edit(QofInstance *inst)
 {
@@ -197,5 +233,96 @@
   if (0 > inst->editlevel) { inst->editlevel = 0; }
 }
 
+#define STR_DLNAME     "dlname="
+#define STR_LIBDIR     "libdir="
+
+gboolean
+qof_load_backend_library (const char* filename, const char* init_fcn)
+{
+	FILE *filehandle;
+	void (*initfn) (void);
+	void *dl_hand = NULL;
+#ifndef HAVE_GETLINE
+	char lineptr[1024];
+#else
+	char *lineptr;
+#endif
+	const char * err_str;
+	gchar *dlname, *libdirpath, *tempstr;
+	int errors;
+	guint n, end;
+	struct stat sbuf;
+
+	errors = 0;
+	dlname = NULL;
+	tempstr = NULL;
+	libdirpath = NULL;
+	g_return_val_if_fail((filename || init_fcn), FALSE); 
+	g_return_val_if_fail(g_str_has_suffix (filename, ".la"), FALSE);
+	/* now we have a filename ending in .la, see if we can open it. */
+	n = (guint)strlen(STR_DLNAME);
+	g_return_val_if_fail((stat(filename, &sbuf) <0), FALSE);
+	filehandle = fopen(filename, "r");
+	g_return_val_if_fail((filehandle), FALSE);
+#ifndef HAVE_GETLINE
+	while (NULL != (fgets(lineptr, sizeof(lineptr), filehandle)))
+#else
+	lineptr = NULL;
+	while (0 < getline(&lineptr, &n, filehandle))
+#endif
+	{
+		if (strncmp (lineptr, STR_DLNAME, n - 1) == 0)
+		{
+			/* obtain substring from dlname='.*'\n
+			 where .* matches the library .so|.dylib name
+			 allowing for single quotes, if used. */
+			tempstr = g_strdup(lineptr + n);
+			if(tempstr[0] == '\'') { tempstr++; }
+			dlname = g_strndup(tempstr, strlen(tempstr) - 1);
+			end = strlen(dlname);
+			if(dlname[end-1] == '\'') 
+			{ 
+				tempstr = g_strndup(dlname, end - 1);
+				dlname = tempstr;
+			}
+		}
+		/* now get the path, just in case */
+		n = (guint)strlen(STR_LIBDIR);
+		if (strncmp (lineptr, STR_LIBDIR, n - 1) == 0)
+		{
+			tempstr = g_strdup(lineptr + n);
+			if(tempstr[0] == '\'') { tempstr++; }
+			libdirpath = g_strndup(tempstr, strlen(tempstr) - 1);
+			end = strlen(libdirpath);
+			if(libdirpath[end-1] == '\'')
+			{
+				tempstr = g_strndup(libdirpath, end - 1);
+				libdirpath = tempstr;
+			}
+			break;
+		}
+	}
+	fclose(filehandle);
+	tempstr = g_strconcat(libdirpath, "/", dlname, NULL);
+	dlname = tempstr;
+	g_free(libdirpath);
+	dl_hand = dlopen (dlname, RTLD_LAZY);
+	if (NULL == dl_hand)
+	{
+		err_str = dlerror();
+		g_message ("Can't load backend, %s\n", err_str);
+		return FALSE;
+	}
+	initfn = dlsym (dl_hand, init_fcn);
+	if (initfn) { (*initfn)(); }
+	else
+	{
+		err_str = dlerror();
+		g_message("Can't find %s:%s, %s\n", dlname, init_fcn, err_str);
+		return FALSE;
+	}
+	g_free(dlname);
+	return TRUE;
+}
 
 /************************* END OF FILE ********************************/
Index: qofbackend-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbackend-p.h,v
retrieving revision 1.2.4.4
retrieving revision 1.2.4.5
diff -Lsrc/engine/qofbackend-p.h -Lsrc/engine/qofbackend-p.h -u -r1.2.4.4 -r1.2.4.5
--- src/engine/qofbackend-p.h
+++ src/engine/qofbackend-p.h
@@ -27,8 +27,7 @@
 /** @name  Backend_Private
    Pseudo-object defining how the engine can interact with different
    back-ends (which may be SQL databases, or network interfaces to 
-   remote GnuCash servers.  In theory, file-io should be a type of 
-   backend).
+   remote GnuCash servers. File-io is just one type of backend).
    
    The callbacks will be called at the appropriate times during 
    a book session to allow the backend to store the data as needed.
@@ -36,6 +35,7 @@
    @file qofbackend-p.h
    @brief private api for data storage backend
    @author Copyright (c) 2000,2001,2004 Linas Vepstas <linas at linas.org> 
+   @author Copyright (c) 2005 Neil Williams <linux at codehelp.co.uk>
 @{ */
 
 #ifndef QOF_BACKEND_P_H
@@ -231,6 +231,16 @@
  *    a mass transfer of transactions between books without having
  *    to actually move much (or any) data to the engine.
  *
+ *
+ * To support configuration options from the frontend, the backend
+ *    can be passed a GHashTable - according to the allowed options
+ *    for that backend, using load_config(). Configuration can be
+ *    updated at any point - it is up to the frontend to load the
+ *    data in time for whatever the backend needs to do. e.g. an
+ *    option to save a new book in a compressed format need not be
+ *    loaded until the backend is about to save. If the configuration
+ *    is updated by the user, the frontend should call load_config
+ *    again to update the backend.
  */
 
 struct QofBackendProvider_s
@@ -254,6 +264,21 @@
   /** Return a new, initialized backend backend. */
   QofBackend * (*backend_new) (void);
 
+  /** \brief Name of the QofBackendProvider XML Configuration file
+	
+	This is to be generated from a Perl script to utilise gettext
+	translations and includes translated strings that describe
+	what each configuration option achieves. 
+	
+	The file itself can be located in the QSF_SCHEMA_DIR or
+	in any directory accessible to the frontend program.
+	
+	The filename should include the name of the backend as
+	specified in provider_name and the version of the backend 
+	that can use the file: myname-backend-v1.xml
+  */
+  const char* provider_config;
+  
   /** Free this structure, unregister this backend handler. */
   void (*provider_free) (QofBackendProvider *);
 };
@@ -279,7 +304,8 @@
   void (*run_query) (QofBackend *, gpointer);
 
   void (*sync) (QofBackend *, QofBook *);
-
+  void (*load_config) (QofBackend *, KvpFrame *);
+  KvpFrame* (*get_config) (QofBackend *);
   gint64 (*counter) (QofBackend *, const char *counter_name);
 
   gboolean (*events_pending) (QofBackend *);
@@ -295,12 +321,27 @@
   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.
+  KvpFrame* backend_configuration;
+  /** Each backend resolves a fully-qualified file path.
+   * This holds the filepath and communicates it to the frontends.
    */
   char * fullpath;
 
+  /** \brief Distinguish two providers with same access method.
+  
+  When more than 1 backend is registered under the same access_method,
+  each one is passed the path to the data (usually a file) and
+  should return TRUE only if the backend recognises the type 
+  as one that it can load and write.
+  
+  \note If the backend can cope with more than one type, the backend
+  should not try to store or cache the sub-type for this data.
+  It is sufficient only to return TRUE if any ONE of the supported
+  types match the incoming data. The backend should not assume that
+  returning TRUE will mean that the data will naturally follow.
+  */
+  gboolean (*check_data_type) (QofBackend *, const char*);
+
 #ifdef GNUCASH_MAJOR_VERSION
   /** XXX price_lookup should be removed during the redesign
    * of the SQL backend... prices can now be queried using
Index: qofbackend.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbackend.h,v
retrieving revision 1.3.4.7
retrieving revision 1.3.4.8
diff -Lsrc/engine/qofbackend.h -Lsrc/engine/qofbackend.h -u -r1.3.4.7 -r1.3.4.8
--- src/engine/qofbackend.h
+++ src/engine/qofbackend.h
@@ -161,6 +161,21 @@
 used when QOF is built as a library.
 @{
 */
+
+/** \brief Load configuration options specific to this backend.
+
+ at param be The backend to configure.
+ at param config A hash table with specific keys that this backend
+will recognise. Each backend needs to document their own config
+keys and acceptable values.
+
+The hash table remains the property of the caller and should
+be freed / destroyed once loaded in the backend.
+*/
+void qof_backend_load_config (QofBackend *be, KvpFrame *config);
+
+KvpFrame* qof_backend_get_config(QofBackend *be);
+
 void qof_backend_run_begin(QofBackend *be, QofInstance *inst);
 
 gboolean qof_backend_begin_exists(QofBackend *be);
@@ -169,6 +184,9 @@
 
 gboolean qof_backend_commit_exists(QofBackend *be);
 
+gboolean
+qof_load_backend_library (const char* filename, const char* init_fcn);
+
 /** @} */
 /** \brief Retrieve the backend used by this book */
 QofBackend* qof_book_get_backend (QofBook *book);


More information about the gnucash-changes mailing list