qofbackend.c

00001 /********************************************************************\
00002  * qofbackend.c -- utility routines for dealing with the data backend  *
00003  * Copyright (C) 2000 Linas Vepstas <linas@linas.org>               *
00004  * Copyright (C) 2004-5 Neil Williams <linux@codehelp.co.uk>        *
00005  *                                                                  *
00006  * This program is free software; you can redistribute it and/or    *
00007  * modify it under the terms of the GNU General Public License as   *
00008  * published by the Free Software Foundation; either version 2 of   *
00009  * the License, or (at your option) any later version.              *
00010  *                                                                  *
00011  * This program is distributed in the hope that it will be useful,  *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00014  * GNU General Public License for more details.                     *
00015  *                                                                  *
00016  * You should have received a copy of the GNU General Public License*
00017  * along with this program; if not, contact:                        *
00018  *                                                                  *
00019  * Free Software Foundation           Voice:  +1-617-542-5942       *
00020  * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
00021  * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
00022  *                                                                  *
00023 \********************************************************************/
00024 
00025 #define _GNU_SOURCE
00026 #include "config.h"
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <stdarg.h>
00030 #include <regex.h>
00031 #include <glib.h>
00032 #include <gmodule.h>
00033 #include <dlfcn.h>
00034 #include <sys/stat.h>
00035 #include <errno.h>
00036 #include "qofbackend-p.h"
00037 
00038 static QofLogModule log_module = QOF_MOD_BACKEND;
00039 
00040 #define QOF_CONFIG_DESC    "desc"
00041 #define QOF_CONFIG_TIP     "tip"
00042 
00043 /* *******************************************************************\
00044  * error handling                                                   *
00045 \********************************************************************/
00046 
00047 void 
00048 qof_backend_set_error (QofBackend *be, QofBackendError err)
00049 {
00050    if (!be) return;
00051 
00052    /* use stack-push semantics. Only the earliest error counts */
00053    if (ERR_BACKEND_NO_ERR != be->last_err) return;
00054    be->last_err = err;
00055 }
00056 
00057 QofBackendError 
00058 qof_backend_get_error (QofBackend *be)
00059 {
00060    QofBackendError err;
00061    if (!be) return ERR_BACKEND_NO_BACKEND;
00062 
00063    /* use 'stack-pop' semantics */
00064    err = be->last_err;
00065    be->last_err = ERR_BACKEND_NO_ERR;
00066    return err;
00067 }
00068 
00069 void
00070 qof_backend_set_message (QofBackend *be, const char *format, ...) 
00071 {
00072    va_list args;
00073    char * buffer;
00074    
00075    if (!be) return;
00076   
00077    /* If there's already something here, free it */
00078    if (be->error_msg) g_free(be->error_msg);
00079 
00080    if (!format) {
00081        be->error_msg = NULL;
00082        return;
00083    }
00084 
00085    va_start(args, format);
00086    buffer = (char *)g_strdup_vprintf(format, args);
00087    va_end(args);
00088 
00089    be->error_msg = buffer;
00090 }
00091 
00092 /* This should always return a valid char * */
00093 char *
00094 qof_backend_get_message (QofBackend *be) 
00095 {
00096    char * msg;
00097    
00098    if (!be) return g_strdup("ERR_BACKEND_NO_BACKEND");
00099    if (!be->error_msg) return NULL;
00100 
00101    /* 
00102     * Just return the contents of the error_msg and then set it to
00103     * NULL.  This is necessary, because the Backends don't seem to
00104     * have a destroy_backend function to take care if freeing stuff
00105     * up.  The calling function should free the copy.
00106     * Also, this is consistent with the qof_backend_get_error() popping.
00107     */
00108 
00109    msg = be->error_msg;
00110    be->error_msg = NULL;
00111    return msg;
00112 }
00113 
00114 /***********************************************************************/
00115 /* Get a clean backend */
00116 void
00117 qof_backend_init(QofBackend *be)
00118 {
00119     be->session_begin = NULL;
00120     be->session_end = NULL;
00121     be->destroy_backend = NULL;
00122 
00123     be->load = NULL;
00124 
00125     be->begin = NULL;
00126     be->commit = NULL;
00127     be->rollback = NULL;
00128 
00129     be->compile_query = NULL;
00130     be->free_query = NULL;
00131     be->run_query = NULL;
00132 
00133     be->sync = NULL;
00134         be->load_config = NULL;
00135 
00136     be->events_pending = NULL;
00137     be->process_events = NULL;
00138 
00139     be->last_err = ERR_BACKEND_NO_ERR;
00140     if (be->error_msg) g_free (be->error_msg);
00141     be->error_msg = NULL;
00142     be->percentage = NULL;
00143         be->backend_configuration = kvp_frame_new();
00144 
00145         /* to be removed */
00146     be->price_lookup = NULL;
00147     be->export = NULL;
00148 }
00149 
00150 void
00151 qof_backend_run_begin(QofBackend *be, QofInstance *inst)
00152 {
00153         if(!be || !inst) { return; }
00154         if(!be->begin) { return; }
00155         (be->begin) (be, inst);
00156 }
00157 
00158 gboolean
00159 qof_backend_begin_exists(QofBackend *be)
00160 {
00161         if(be->begin) { return TRUE; }
00162         else { return FALSE; }
00163 }
00164 
00165 void
00166 qof_backend_run_commit(QofBackend *be, QofInstance *inst)
00167 {
00168         if(!be || !inst) { return; }
00169         if(!be->commit) { return; }
00170         (be->commit) (be, inst);
00171 }
00172 
00173 /* =========== Backend Configuration ================ */
00174 
00175 void qof_backend_prepare_frame(QofBackend *be)
00176 {
00177         g_return_if_fail(be);
00178         if(!kvp_frame_is_empty(be->backend_configuration)) {
00179                 kvp_frame_delete(be->backend_configuration);
00180                 be->backend_configuration = kvp_frame_new();
00181         }
00182         be->config_count = 0;
00183 }
00184 
00185 void qof_backend_prepare_option(QofBackend *be, QofBackendOption *option)
00186 {
00187         KvpValue *value;
00188         gchar *temp;
00189         gint count;
00190 
00191         g_return_if_fail(be || option);
00192         count = be->config_count;
00193         count++;
00194         value = NULL;
00195         ENTER (" %d", count);
00196         switch (option->type)
00197         {
00198                 case KVP_TYPE_GINT64   : {
00199                         value = kvp_value_new_gint64(*(gint64*)option->value);
00200                         break; 
00201                 }
00202                 case KVP_TYPE_DOUBLE   : { 
00203                         value = kvp_value_new_double(*(double*)option->value);
00204                         break; 
00205                 }
00206                 case KVP_TYPE_NUMERIC  : {
00207                         value = kvp_value_new_numeric(*(gnc_numeric*)option->value);
00208                         break; 
00209                 }
00210                 case KVP_TYPE_STRING   : {
00211                         value = kvp_value_new_string((const char*)option->value);
00212                         break;
00213                 }
00214                 case KVP_TYPE_GUID     : { break; } /* unsupported */
00215                 case KVP_TYPE_TIMESPEC : {
00216                         value = kvp_value_new_timespec(*(Timespec*)option->value);
00217                         break;
00218                 }
00219                 case KVP_TYPE_BINARY   : { break; } /* unsupported */
00220                 case KVP_TYPE_GLIST    : { break; } /* unsupported */
00221                 case KVP_TYPE_FRAME    : { break; } /* unsupported */
00222         }
00223         if(value) {
00224                 temp = g_strdup_printf("/%s", option->option_name);
00225                 kvp_frame_set_value(be->backend_configuration, temp, value);
00226                 PINFO (" setting value at %s", temp);
00227                 g_free(temp);
00228                 temp = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, option->option_name);
00229                 PINFO (" setting description %s at %s", option->description, temp);
00230                 kvp_frame_set_string(be->backend_configuration, temp, option->description);
00231                 PINFO (" check= %s", kvp_frame_get_string(be->backend_configuration, temp));
00232                 g_free(temp);
00233                 temp = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, option->option_name);
00234                 PINFO (" setting tooltip %s at %s", option->tooltip, temp);
00235                 kvp_frame_set_string(be->backend_configuration, temp, option->tooltip);
00236                 PINFO (" check= %s", kvp_frame_get_string(be->backend_configuration, temp));
00237                 g_free(temp);
00238                 /* only increment the counter if successful */
00239                 be->config_count = count;
00240         }
00241         LEAVE (" ");
00242 }
00243 
00244 KvpFrame* qof_backend_complete_frame(QofBackend *be)
00245 {
00246         g_return_val_if_fail(be, NULL);
00247         be->config_count = 0;
00248         return be->backend_configuration;
00249 }
00250 
00251 struct config_iterate {
00252         QofBackendOptionCB fcn;
00253         gpointer           data;
00254         gint               count;
00255         KvpFrame          *recursive;
00256 };
00257 
00258 static void
00259 config_foreach_cb (const char *key, KvpValue *value, gpointer data)
00260 {
00261         QofBackendOption option;
00262         gint64 int64;
00263         double db;
00264         gnc_numeric num;
00265         Timespec ts;
00266         gchar *parent;
00267         struct config_iterate *helper;
00268 
00269         g_return_if_fail(key || value || data);
00270         helper = (struct config_iterate*)data;
00271         if(!helper->recursive) { PERR (" no parent frame"); return;     }
00272         // skip the presets.
00273         if(0 == safe_strcmp(key, QOF_CONFIG_DESC)) { return; }
00274         if(0 == safe_strcmp(key, QOF_CONFIG_TIP)) { return; }
00275         ENTER (" key=%s", key);
00276         option.option_name = key;
00277         option.type = kvp_value_get_type(value);
00278         if(!option.type) { return; }
00279         switch (option.type)
00280         {
00281                 case KVP_TYPE_GINT64   : {
00282                         int64 = kvp_value_get_gint64(value);
00283                         option.value = (gpointer)&int64;
00284                         break; 
00285                 }
00286                 case KVP_TYPE_DOUBLE   : {
00287                         db = kvp_value_get_double(value);
00288                         option.value = (gpointer)&db;
00289                         break; 
00290                 }
00291                 case KVP_TYPE_NUMERIC  : {
00292                         num = kvp_value_get_numeric(value);
00293                         option.value = (gpointer)&num;
00294                         break; 
00295                 }
00296                 case KVP_TYPE_STRING   : {
00297                         option.value = (gpointer)kvp_value_get_string(value);
00298                         break;
00299                 }
00300                 case KVP_TYPE_GUID     : { break; } /* unsupported */
00301                 case KVP_TYPE_TIMESPEC : {
00302                         ts = kvp_value_get_timespec(value);
00303                         option.value = (gpointer)&ts;
00304                         break;
00305                 }
00306                 case KVP_TYPE_BINARY   : { break; } /* unsupported */
00307                 case KVP_TYPE_GLIST    : { break; } /* unsupported */
00308                 case KVP_TYPE_FRAME    : { break; } /* unsupported */
00309         }
00310         parent = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, key);
00311         option.description = kvp_frame_get_string(helper->recursive, parent);
00312         g_free(parent);
00313         parent = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, key);
00314         option.tooltip = kvp_frame_get_string(helper->recursive, parent);
00315         helper->count++;
00316         helper->fcn (&option, helper->data);
00317         LEAVE (" desc=%s tip=%s", option.description, option.tooltip);
00318 }
00319 
00320 void qof_backend_option_foreach(KvpFrame *config, QofBackendOptionCB cb, gpointer data)
00321 {
00322         struct config_iterate helper;
00323 
00324         if(!config || !cb) { return; }
00325         ENTER (" ");
00326         helper.fcn = cb;
00327         helper.count = 1;
00328         helper.data = data;
00329         helper.recursive = config;
00330         kvp_frame_for_each_slot(config, config_foreach_cb, &helper);
00331         LEAVE (" ");
00332 }
00333 
00334 void
00335 qof_backend_load_config(QofBackend *be, KvpFrame *config)
00336 {
00337         if(!be || !config) { return; }
00338         if(!be->load_config) { return; }
00339         (be->load_config) (be, config);
00340 }
00341 
00342 KvpFrame*
00343 qof_backend_get_config(QofBackend *be)
00344 {
00345         if(!be) { return NULL; }
00346         if(!be->get_config) { return NULL; }
00347         return (be->get_config) (be);
00348 }
00349 
00350 gboolean
00351 qof_backend_commit_exists(QofBackend *be)
00352 {
00353         if(!be) { return FALSE; }
00354         if(be->commit) { return TRUE; }
00355         else { return FALSE; }
00356 }
00357 
00358 gboolean
00359 qof_begin_edit(QofInstance *inst)
00360 {
00361   QofBackend * be;
00362 
00363   if (!inst) { return FALSE; }
00364   (inst->editlevel)++;
00365   if (1 < inst->editlevel) { return FALSE; }
00366   if (0 >= inst->editlevel) { inst->editlevel = 1; }
00367   be = qof_book_get_backend (inst->book);
00368     if (be && qof_backend_begin_exists(be)) {
00369      qof_backend_run_begin(be, inst);
00370   } else { inst->dirty = TRUE; }
00371   return TRUE;
00372 }
00373 
00374 gboolean qof_commit_edit(QofInstance *inst)
00375 {
00376   QofBackend * be;
00377 
00378   if (!inst) { return FALSE; }
00379   (inst->editlevel)--;
00380   if (0 < inst->editlevel) { return FALSE; }
00381   if ((-1 == inst->editlevel) && inst->dirty)
00382   {
00383     be = qof_book_get_backend ((inst)->book);
00384     if (be && qof_backend_begin_exists(be)) {
00385      qof_backend_run_begin(be, inst);
00386     }
00387     inst->editlevel = 0;
00388   }
00389   if (0 > inst->editlevel) { inst->editlevel = 0; }
00390   return TRUE;
00391 }
00392 
00393 gboolean
00394 qof_load_backend_library (const char *directory, 
00395                                 const char* filename, const char* init_fcn)
00396 {
00397         struct stat sbuf;
00398         gchar *fullpath;
00399         typedef void (* backend_init) (void);
00400         GModule *backend;
00401         backend_init gmod_init;
00402         gpointer g;
00403 
00404         g_return_val_if_fail(g_module_supported(), FALSE);
00405         fullpath = g_module_build_path(directory, filename);
00406         PINFO (" fullpath=%s", fullpath);
00407         g_return_val_if_fail((stat(fullpath, &sbuf) == 0), FALSE);
00408         backend = g_module_open(fullpath, G_MODULE_BIND_LAZY);
00409         if(!backend) { 
00410                 g_message ("%s: %s\n", PACKAGE, g_module_error ());
00411                 return FALSE;
00412         }
00413         g = &gmod_init;
00414         if (!g_module_symbol (backend, init_fcn, g))
00415         {
00416                 g_message ("%s: %s\n", PACKAGE, g_module_error ());
00417                 return FALSE;
00418         }
00419         g_module_make_resident(backend);
00420         gmod_init();
00421         return TRUE;
00422 }
00423 
00424 /************************* END OF FILE ********************************/

Generated on Fri Oct 21 15:49:55 2005 for QOF by  doxygen 1.4.5