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  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00021  * Boston, MA  02110-1301,  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 <errno.h>
00034 #include "qof.h"
00035 #include "qofbackend-p.h"
00036 
00037 static QofLogModule log_module = QOF_MOD_BACKEND;
00038 
00039 #define QOF_CONFIG_DESC    "desc"
00040 #define QOF_CONFIG_TIP     "tip"
00041 
00042 /* *******************************************************************\
00043  * error handling                                                   *
00044 \********************************************************************/
00045 
00046 void 
00047 qof_backend_set_error (QofBackend *be, QofBackendError err)
00048 {
00049    if (!be) return;
00050 
00051    /* use stack-push semantics. Only the earliest error counts */
00052    if (ERR_BACKEND_NO_ERR != be->last_err) return;
00053    be->last_err = err;
00054 }
00055 
00056 QofBackendError 
00057 qof_backend_get_error (QofBackend *be)
00058 {
00059    QofBackendError err;
00060    if (!be) return ERR_BACKEND_NO_BACKEND;
00061 
00062    /* use 'stack-pop' semantics */
00063    err = be->last_err;
00064    be->last_err = ERR_BACKEND_NO_ERR;
00065    return err;
00066 }
00067 
00068 void
00069 qof_backend_set_message (QofBackend *be, const char *format, ...) 
00070 {
00071    va_list args;
00072    char * buffer;
00073    
00074    if (!be) return;
00075   
00076    /* If there's already something here, free it */
00077    if (be->error_msg) g_free(be->error_msg);
00078 
00079    if (!format) {
00080        be->error_msg = NULL;
00081        return;
00082    }
00083 
00084    va_start(args, format);
00085    buffer = (char *)g_strdup_vprintf(format, args);
00086    va_end(args);
00087 
00088    be->error_msg = buffer;
00089 }
00090 
00091 char *
00092 qof_backend_get_message (QofBackend *be) 
00093 {
00094    char * msg;
00095    
00096    if (!be) return g_strdup("ERR_BACKEND_NO_BACKEND");
00097    if (!be->error_msg) return NULL;
00098 
00099    /* 
00100     * Just return the contents of the error_msg and then set it to
00101     * NULL. This is necessary, because the Backends don't seem to
00102     * have a destroy_backend function to take care of freeing stuff
00103     * up. The calling function should free the copy.
00104     * Also, this is consistent with the qof_backend_get_error() popping.
00105     */
00106 
00107    msg = be->error_msg;
00108    be->error_msg = NULL;
00109    return msg;
00110 }
00111 
00112 /***********************************************************************/
00113 /* Get a clean backend */
00114 void
00115 qof_backend_init(QofBackend *be)
00116 {
00117     be->session_begin = NULL;
00118     be->session_end = NULL;
00119     be->destroy_backend = NULL;
00120 
00121     be->load = NULL;
00122 
00123     be->begin = NULL;
00124     be->commit = NULL;
00125     be->rollback = NULL;
00126 
00127     be->compile_query = NULL;
00128     be->free_query = NULL;
00129     be->run_query = NULL;
00130 
00131     be->sync = NULL;
00132         be->load_config = NULL;
00133 
00134     be->events_pending = NULL;
00135     be->process_events = NULL;
00136 
00137     be->last_err = ERR_BACKEND_NO_ERR;
00138     if (be->error_msg) g_free (be->error_msg);
00139     be->error_msg = NULL;
00140     be->percentage = NULL;
00141         be->backend_configuration = kvp_frame_new();
00142         
00143         /* to be removed */
00144         be->price_lookup = NULL;
00145         be->export = NULL;
00146 }
00147 
00148 void
00149 qof_backend_run_begin(QofBackend *be, QofInstance *inst)
00150 {
00151         if(!be || !inst) { return; }
00152         if(!be->begin) { return; }
00153         (be->begin) (be, inst);
00154 }
00155 
00156 gboolean
00157 qof_backend_begin_exists(QofBackend *be)
00158 {
00159         if(be->begin) { return TRUE; }
00160         else { return FALSE; }
00161 }
00162 
00163 void
00164 qof_backend_run_commit(QofBackend *be, QofInstance *inst)
00165 {
00166         if(!be || !inst) { return; }
00167         if(!be->commit) { return; }
00168         (be->commit) (be, inst);
00169 }
00170 
00171 /* =========== Backend Configuration ================ */
00172 
00173 void qof_backend_prepare_frame(QofBackend *be)
00174 {
00175         g_return_if_fail(be);
00176         if(!kvp_frame_is_empty(be->backend_configuration)) {
00177                 kvp_frame_delete(be->backend_configuration);
00178                 be->backend_configuration = kvp_frame_new();
00179         }
00180         be->config_count = 0;
00181 }
00182 
00183 void qof_backend_prepare_option(QofBackend *be, QofBackendOption *option)
00184 {
00185         KvpValue *value;
00186         gchar *temp;
00187         gint count;
00188 
00189         g_return_if_fail(be || option);
00190         count = be->config_count;
00191         count++;
00192         value = NULL;
00193         switch (option->type)
00194         {
00195                 case KVP_TYPE_GINT64   : {
00196                         value = kvp_value_new_gint64(*(gint64*)option->value);
00197                         break; 
00198                 }
00199                 case KVP_TYPE_DOUBLE   : { 
00200                         value = kvp_value_new_double(*(double*)option->value);
00201                         break; 
00202                 }
00203                 case KVP_TYPE_NUMERIC  : {
00204                         value = kvp_value_new_numeric(*(gnc_numeric*)option->value);
00205                         break; 
00206                 }
00207                 case KVP_TYPE_STRING   : {
00208                         value = kvp_value_new_string((const char*)option->value);
00209                         break;
00210                 }
00211                 case KVP_TYPE_GUID     : { break; } /* unsupported */
00212                 case KVP_TYPE_TIMESPEC : {
00213                         value = kvp_value_new_timespec(*(Timespec*)option->value);
00214                         break;
00215                 }
00216                 case KVP_TYPE_BINARY   : { break; } /* unsupported */
00217                 case KVP_TYPE_GLIST    : { break; } /* unsupported */
00218                 case KVP_TYPE_FRAME    : { break; } /* unsupported */
00219         }
00220         if(value) {
00221                 temp = g_strdup_printf("/%s", option->option_name);
00222                 kvp_frame_set_value(be->backend_configuration, temp, value);
00223                 g_free(temp);
00224                 temp = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, option->option_name);
00225                 kvp_frame_set_string(be->backend_configuration, temp, option->description);
00226                 g_free(temp);
00227                 temp = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, option->option_name);
00228                 kvp_frame_set_string(be->backend_configuration, temp, option->tooltip);
00229                 g_free(temp);
00230                 /* only increment the counter if successful */
00231                 be->config_count = count;
00232         }
00233 }
00234 
00235 KvpFrame* qof_backend_complete_frame(QofBackend *be)
00236 {
00237         g_return_val_if_fail(be, NULL);
00238         be->config_count = 0;
00239         return be->backend_configuration;
00240 }
00241 
00242 struct config_iterate {
00243         QofBackendOptionCB fcn;
00244         gpointer           data;
00245         gint               count;
00246         KvpFrame          *recursive;
00247 };
00248 
00249 /* Set the option with the default KvpValue,
00250 manipulate the option in the supplied callback routine
00251 then set the value of the option into the KvpValue
00252 in the configuration frame. */
00253 static void
00254 config_foreach_cb (const char *key, KvpValue *value, gpointer data)
00255 {
00256         QofBackendOption option;
00257         gint64 int64;
00258         double db;
00259         gnc_numeric num;
00260         Timespec ts;
00261         gchar *parent;
00262         struct config_iterate *helper;
00263 
00264         g_return_if_fail(key || value || data);
00265         helper = (struct config_iterate*)data;
00266         if(!helper->recursive) { PERR (" no parent frame"); return;     }
00267         // skip the presets.
00268         if(0 == safe_strcmp(key, QOF_CONFIG_DESC)) { return; }
00269         if(0 == safe_strcmp(key, QOF_CONFIG_TIP)) { return; }
00270         ENTER (" key=%s", key);
00271         option.option_name = key;
00272         option.type = kvp_value_get_type(value);
00273         if(!option.type) { return; }
00274         switch (option.type)
00275         { /* set the KvpFrame value into the option */
00276                 case KVP_TYPE_GINT64   : {
00277                         int64 = kvp_value_get_gint64(value);
00278                         option.value = (gpointer)&int64;
00279                         break;
00280                 }
00281                 case KVP_TYPE_DOUBLE   : {
00282                         db = kvp_value_get_double(value);
00283                         option.value = (gpointer)&db;
00284                         break; 
00285                 }
00286                 case KVP_TYPE_NUMERIC  : {
00287                         num = kvp_value_get_numeric(value);
00288                         option.value = (gpointer)&num;
00289                         break; 
00290                 }
00291                 case KVP_TYPE_STRING   : {
00292                         option.value = (gpointer)kvp_value_get_string(value);
00293                         break;
00294                 }
00295                 case KVP_TYPE_TIMESPEC : {
00296                         ts = kvp_value_get_timespec(value);
00297                         option.value = (gpointer)&ts;
00298                         break;
00299                 }
00300                 case KVP_TYPE_GUID     : { break; } /* unsupported */
00301                 case KVP_TYPE_BINARY   : { break; } /* unsupported */
00302                 case KVP_TYPE_GLIST    : { break; } /* unsupported */
00303                 case KVP_TYPE_FRAME    : { break; } /* unsupported */
00304         }
00305         parent = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, key);
00306         option.description = kvp_frame_get_string(helper->recursive, parent);
00307         g_free(parent);
00308         parent = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, key);
00309         option.tooltip = kvp_frame_get_string(helper->recursive, parent);
00310         g_free(parent);
00311         helper->count++;
00312     /* manipulate the option */
00313         helper->fcn (&option, helper->data);
00314         switch (option.type)
00315         { /* set the option value into the KvpFrame */
00316                 case KVP_TYPE_GINT64   : {
00317                         kvp_frame_set_gint64(helper->recursive, key, 
00318                                 (*(gint64*)option.value));
00319                         break;
00320                 }
00321                 case KVP_TYPE_DOUBLE   : {
00322                         kvp_frame_set_double(helper->recursive, key, 
00323                                 (*(double*)option.value));
00324                         break; 
00325                 }
00326                 case KVP_TYPE_NUMERIC  : {
00327                         kvp_frame_set_numeric(helper->recursive, key, 
00328                                 (*(gnc_numeric*)option.value));
00329                         break; 
00330                 }
00331                 case KVP_TYPE_STRING   : {
00332                         kvp_frame_set_string(helper->recursive, key, 
00333                                 (gchar*)option.value);
00334                         break;
00335                 }
00336                 case KVP_TYPE_TIMESPEC : {
00337                         kvp_frame_set_timespec(helper->recursive, key, 
00338                                 (*(Timespec*)option.value));
00339                         break;
00340                 }
00341                 case KVP_TYPE_GUID     : { break; } /* unsupported */
00342                 case KVP_TYPE_BINARY   : { break; } /* unsupported */
00343                 case KVP_TYPE_GLIST    : { break; } /* unsupported */
00344                 case KVP_TYPE_FRAME    : { break; } /* unsupported */
00345         }
00346         LEAVE (" ");
00347 }
00348 
00349 void qof_backend_option_foreach(KvpFrame *config, QofBackendOptionCB cb, gpointer data)
00350 {
00351         struct config_iterate helper;
00352 
00353         if(!config || !cb) { return; }
00354         ENTER (" ");
00355         helper.fcn = cb;
00356         helper.count = 1;
00357         helper.data = data;
00358         helper.recursive = config;
00359         kvp_frame_for_each_slot(config, config_foreach_cb, &helper);
00360         LEAVE (" ");
00361 }
00362 
00363 void
00364 qof_backend_load_config(QofBackend *be, KvpFrame *config)
00365 {
00366         if(!be || !config) { return; }
00367         if(!be->load_config) { return; }
00368         (be->load_config) (be, config);
00369 }
00370 
00371 KvpFrame*
00372 qof_backend_get_config(QofBackend *be)
00373 {
00374         if(!be) { return NULL; }
00375         if(!be->get_config) { return NULL; }
00376         return (be->get_config) (be);
00377 }
00378 
00379 gboolean
00380 qof_backend_commit_exists(QofBackend *be)
00381 {
00382         if(!be) { return FALSE; }
00383         if(be->commit) { return TRUE; }
00384         else { return FALSE; }
00385 }
00386 
00387 gboolean
00388 qof_load_backend_library (const char *directory, 
00389                                 const char* filename, const char* init_fcn)
00390 {
00391         gchar *fullpath;
00392         typedef void (* backend_init) (void);
00393         GModule *backend;
00394         backend_init gmod_init;
00395         gpointer g;
00396 
00397         g_return_val_if_fail(g_module_supported(), FALSE);
00398         fullpath = g_module_build_path(directory, filename);
00399         backend = g_module_open(fullpath, G_MODULE_BIND_LAZY);
00400         if(!backend) { 
00401                 g_message ("%s: %s\n", PACKAGE, g_module_error ());
00402                 return FALSE;
00403         }
00404         g = &gmod_init;
00405         if (!g_module_symbol (backend, init_fcn, g))
00406         {
00407                 g_message ("%s: %s\n", PACKAGE, g_module_error ());
00408                 return FALSE;
00409         }
00410         g_module_make_resident(backend);
00411         gmod_init();
00412         return TRUE;
00413 }
00414 
00415 /************************* END OF FILE ********************************/

Generated on Fri May 12 17:57:20 2006 for QOF by  doxygen 1.4.4