qofbackend.c

00001 /********************************************************************\
00002  * qofbackend.c -- utility routines for the data backend            *
00003  * Copyright (C) 2000 Linas Vepstas <linas@linas.org>               *
00004  * Copyright (C) 2004-2006 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 #include "config.h"
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <stdarg.h>
00029 #include <regex.h>
00030 #include <glib.h>
00031 #include <gmodule.h>
00032 #include <errno.h>
00033 #include "qof.h"
00034 #include "qofbackend-p.h"
00035 
00036 static QofLogModule log_module = QOF_MOD_BACKEND;
00037 
00038 #define QOF_CONFIG_DESC    "desc"
00039 #define QOF_CONFIG_TIP     "tip"
00040 
00041 /* *******************************************************************\
00042  * error handling                                                   *
00043 \********************************************************************/
00044 
00045 void
00046 qof_backend_set_error (QofBackend * be, QofBackendError err)
00047 {
00048     if (!be)
00049         return;
00050 
00051     /* use stack-push semantics. Only the earliest error counts */
00052     if (ERR_BACKEND_NO_ERR != be->last_err)
00053         return;
00054     be->last_err = err;
00055 }
00056 
00057 QofBackendError
00058 qof_backend_get_error (QofBackend * be)
00059 {
00060     QofBackendError err;
00061     if (!be)
00062         return ERR_BACKEND_NO_BACKEND;
00063 
00064     /* use 'stack-pop' semantics */
00065     err = be->last_err;
00066     be->last_err = ERR_BACKEND_NO_ERR;
00067     return err;
00068 }
00069 
00070 void
00071 qof_backend_set_message (QofBackend * be, const gchar * format, ...)
00072 {
00073     va_list args;
00074     gchar *buffer;
00075 
00076     if (!be)
00077         return;
00078 
00079     /* If there's already something here, free it */
00080     if (be->error_msg)
00081         g_free (be->error_msg);
00082 
00083     if (!format)
00084     {
00085         be->error_msg = NULL;
00086         return;
00087     }
00088 
00089     va_start (args, format);
00090     buffer = (gchar *) g_strdup_vprintf (format, args);
00091     va_end (args);
00092 
00093     be->error_msg = buffer;
00094 }
00095 
00096 gchar *
00097 qof_backend_get_message (QofBackend * be)
00098 {
00099     gchar *msg;
00100 
00101     if (!be)
00102         return g_strdup ("ERR_BACKEND_NO_BACKEND");
00103     if (!be->error_msg)
00104         return NULL;
00105 
00106     /* 
00107      * Just return the contents of the error_msg and then set it to
00108      * NULL. This is necessary, because the Backends don't seem to
00109      * have a destroy_backend function to take care of freeing stuff
00110      * up. The calling function should free the copy.
00111      * Also, this is consistent with the qof_backend_get_error() popping.
00112      */
00113 
00114     msg = be->error_msg;
00115     be->error_msg = NULL;
00116     return msg;
00117 }
00118 
00119 /***********************************************************************/
00120 /* Get a clean backend */
00121 void
00122 qof_backend_init (QofBackend * be)
00123 {
00124     be->session_begin = NULL;
00125     be->session_end = NULL;
00126     be->destroy_backend = NULL;
00127     be->load = NULL;
00128     be->begin = NULL;
00129     be->commit = NULL;
00130     be->rollback = NULL;
00131     be->compile_query = NULL;
00132     be->free_query = NULL;
00133     be->run_query = NULL;
00134     be->sync = NULL;
00135     be->load_config = NULL;
00136     be->events_pending = NULL;
00137     be->process_events = NULL;
00138     be->last_err = ERR_BACKEND_NO_ERR;
00139     if (be->error_msg)
00140         g_free (be->error_msg);
00141     be->error_msg = NULL;
00142     be->percentage = NULL;
00143     be->backend_configuration = kvp_frame_new ();
00144 #ifndef QOF_DISABLE_DEPRECATED
00145 
00146     be->price_lookup = NULL;
00148     be->export = NULL;
00149 #endif
00150 }
00151 
00152 void
00153 qof_backend_run_begin (QofBackend * be, QofInstance * inst)
00154 {
00155     if (!be || !inst)
00156         return;
00157     if (!be->begin)
00158         return;
00159     (be->begin) (be, inst);
00160 }
00161 
00162 gboolean
00163 qof_backend_begin_exists (QofBackend * be)
00164 {
00165     if (be->begin)
00166         return TRUE;
00167     else
00168         return FALSE;
00169 }
00170 
00171 void
00172 qof_backend_run_commit (QofBackend * be, QofInstance * inst)
00173 {
00174     if (!be || !inst)
00175         return;
00176     if (!be->commit)
00177         return;
00178     (be->commit) (be, inst);
00179 }
00180 
00181 /* =========== Backend Configuration ================ */
00182 
00183 void
00184 qof_backend_prepare_frame (QofBackend * be)
00185 {
00186     g_return_if_fail (be);
00187     if (!kvp_frame_is_empty (be->backend_configuration))
00188     {
00189         kvp_frame_delete (be->backend_configuration);
00190         be->backend_configuration = kvp_frame_new ();
00191     }
00192     be->config_count = 0;
00193 }
00194 
00195 void
00196 qof_backend_prepare_option (QofBackend * be, 
00197                             QofBackendOption * option)
00198 {
00199     KvpValue *value;
00200     gchar *temp;
00201     gint count;
00202 
00203     g_return_if_fail (be || option);
00204     count = be->config_count;
00205     count++;
00206     value = NULL;
00207     switch (option->type)
00208     {
00209     case KVP_TYPE_GINT64:
00210         {
00211             value = kvp_value_new_gint64 (*(gint64 *) option->value);
00212             break;
00213         }
00214     case KVP_TYPE_DOUBLE:
00215         {
00216             value = kvp_value_new_double (*(gdouble *) option->value);
00217             break;
00218         }
00219     case KVP_TYPE_NUMERIC:
00220         {
00221             value = kvp_value_new_numeric (*(QofNumeric *) option->value);
00222             break;
00223         }
00224     case KVP_TYPE_STRING:
00225         {
00226             value = kvp_value_new_string ((const gchar *) option->value);
00227             break;
00228         }
00229     case KVP_TYPE_GUID:
00230         {
00231             break;
00232         }                       /* unsupported */
00233     case KVP_TYPE_TIME :
00234         {
00235             value = kvp_value_new_time ((QofTime*) option->value);
00236             break;
00237         }
00238 #ifndef QOF_DISABLE_DEPRECATED
00239     case KVP_TYPE_TIMESPEC:
00240         {
00241             value = kvp_value_new_timespec (*(Timespec *) option->value);
00242             break;
00243         }
00244 #endif
00245     case KVP_TYPE_BINARY:
00246         {
00247             break;
00248         }                       /* unsupported */
00249     case KVP_TYPE_GLIST:
00250         {
00251             break;
00252         }                       /* unsupported */
00253     case KVP_TYPE_FRAME:
00254         {
00255             break;
00256         }                       /* unsupported */
00257     }
00258     if (value)
00259     {
00260         temp = g_strdup_printf ("/%s", option->option_name);
00261         kvp_frame_set_value (be->backend_configuration, temp, value);
00262         g_free (temp);
00263         temp =
00264             g_strdup_printf ("/%s/%s", QOF_CONFIG_DESC,
00265             option->option_name);
00266         kvp_frame_set_string (be->backend_configuration, temp,
00267             option->description);
00268         g_free (temp);
00269         temp =
00270             g_strdup_printf ("/%s/%s", QOF_CONFIG_TIP,
00271             option->option_name);
00272         kvp_frame_set_string (be->backend_configuration, temp,
00273             option->tooltip);
00274         g_free (temp);
00275         /* only increment the counter if successful */
00276         be->config_count = count;
00277     }
00278 }
00279 
00280 KvpFrame *
00281 qof_backend_complete_frame (QofBackend * be)
00282 {
00283     g_return_val_if_fail (be, NULL);
00284     be->config_count = 0;
00285     return be->backend_configuration;
00286 }
00287 
00288 struct config_iterate
00289 {
00290     QofBackendOptionCB fcn;
00291     gpointer data;
00292     gint count;
00293     KvpFrame *recursive;
00294 };
00295 
00296 /* Set the option with the default KvpValue,
00297 manipulate the option in the supplied callback routine
00298 then set the value of the option into the KvpValue
00299 in the configuration frame. */
00300 static void
00301 config_foreach_cb (const gchar * key, KvpValue * value, gpointer data)
00302 {
00303     QofBackendOption option;
00304     gint64 int64;
00305     gdouble db;
00306     QofNumeric num;
00307     gchar *parent;
00308     struct config_iterate *helper;
00309 
00310     g_return_if_fail (key || value || data);
00311     helper = (struct config_iterate *) data;
00312     if (!helper->recursive)
00313     {
00314         PERR (" no parent frame");
00315         return;
00316     }
00317     // skip the presets.
00318     if (0 == safe_strcmp (key, QOF_CONFIG_DESC))
00319     {
00320         return;
00321     }
00322     if (0 == safe_strcmp (key, QOF_CONFIG_TIP))
00323     {
00324         return;
00325     }
00326     ENTER (" key=%s", key);
00327     option.option_name = key;
00328     option.type = kvp_value_get_type (value);
00329     if (!option.type)
00330         return;
00331     switch (option.type)
00332     {                           /* set the KvpFrame value into the option */
00333     case KVP_TYPE_GINT64:
00334         {
00335             int64 = kvp_value_get_gint64 (value);
00336             option.value = (gpointer) & int64;
00337             break;
00338         }
00339     case KVP_TYPE_DOUBLE:
00340         {
00341             db = kvp_value_get_double (value);
00342             option.value = (gpointer) & db;
00343             break;
00344         }
00345     case KVP_TYPE_NUMERIC:
00346         {
00347             num = kvp_value_get_numeric (value);
00348             option.value = (gpointer) & num;
00349             break;
00350         }
00351     case KVP_TYPE_STRING:
00352         {
00353             option.value = (gpointer) kvp_value_get_string (value);
00354             break;
00355         }
00356     case KVP_TYPE_TIME :
00357     {
00358         option.value = (gpointer) kvp_value_get_time (value);
00359     }
00360 #ifndef QOF_DISABLE_DEPRECATED
00361     case KVP_TYPE_TIMESPEC:
00362         {
00363             Timespec ts;
00364             ts = kvp_value_get_timespec (value);
00365             option.value = (gpointer) & ts;
00366             break;
00367         }
00368 #endif
00369     case KVP_TYPE_GUID:
00370         {
00371             break;
00372         }                       /* unsupported */
00373     case KVP_TYPE_BINARY:
00374         {
00375             break;
00376         }                       /* unsupported */
00377     case KVP_TYPE_GLIST:
00378         {
00379             break;
00380         }                       /* unsupported */
00381     case KVP_TYPE_FRAME:
00382         {
00383             break;
00384         }                       /* unsupported */
00385     }
00386     parent = g_strdup_printf ("/%s/%s", QOF_CONFIG_DESC, key);
00387     option.description = kvp_frame_get_string (helper->recursive, parent);
00388     g_free (parent);
00389     parent = g_strdup_printf ("/%s/%s", QOF_CONFIG_TIP, key);
00390     option.tooltip = kvp_frame_get_string (helper->recursive, parent);
00391     g_free (parent);
00392     helper->count++;
00393     /* manipulate the option */
00394     helper->fcn (&option, helper->data);
00395     switch (option.type)
00396     {                           /* set the option value into the KvpFrame */
00397     case KVP_TYPE_GINT64:
00398         {
00399             kvp_frame_set_gint64 (helper->recursive, key,
00400                 (*(gint64 *) option.value));
00401             break;
00402         }
00403     case KVP_TYPE_DOUBLE:
00404         {
00405             kvp_frame_set_double (helper->recursive, key,
00406                 (*(gdouble *) option.value));
00407             break;
00408         }
00409     case KVP_TYPE_NUMERIC:
00410         {
00411             kvp_frame_set_numeric (helper->recursive, key,
00412                 (*(QofNumeric *) option.value));
00413             break;
00414         }
00415     case KVP_TYPE_STRING:
00416         {
00417             kvp_frame_set_string (helper->recursive, key,
00418                 (gchar *) option.value);
00419             break;
00420         }
00421     case KVP_TYPE_TIME :
00422     {
00423         kvp_frame_set_time (helper->recursive, key,
00424             (QofTime*) option.value);
00425         break;
00426     }
00427 #ifndef QOF_DISABLE_DEPRECATED
00428     case KVP_TYPE_TIMESPEC:
00429         {
00430             kvp_frame_set_timespec (helper->recursive, key,
00431                 (*(Timespec *) option.value));
00432             break;
00433         }
00434 #endif
00435     case KVP_TYPE_GUID:
00436         {
00437             break;
00438         }                       /* unsupported */
00439     case KVP_TYPE_BINARY:
00440         {
00441             break;
00442         }                       /* unsupported */
00443     case KVP_TYPE_GLIST:
00444         {
00445             break;
00446         }                       /* unsupported */
00447     case KVP_TYPE_FRAME:
00448         {
00449             break;
00450         }                       /* unsupported */
00451     }
00452     LEAVE (" ");
00453 }
00454 
00455 void
00456 qof_backend_option_foreach (KvpFrame * config, 
00457     QofBackendOptionCB cb, gpointer data)
00458 {
00459     struct config_iterate helper;
00460 
00461     if (!config || !cb)
00462         return;
00463     ENTER (" ");
00464     helper.fcn = cb;
00465     helper.count = 1;
00466     helper.data = data;
00467     helper.recursive = config;
00468     kvp_frame_for_each_slot (config, config_foreach_cb, &helper);
00469     LEAVE (" ");
00470 }
00471 
00472 void
00473 qof_backend_load_config (QofBackend * be, KvpFrame * config)
00474 {
00475     if (!be || !config)
00476         return;
00477     if (!be->load_config)
00478         return;
00479     (be->load_config) (be, config);
00480 }
00481 
00482 KvpFrame *
00483 qof_backend_get_config (QofBackend * be)
00484 {
00485     if (!be)
00486         return NULL;
00487     if (!be->get_config)
00488         return NULL;
00489     return (be->get_config) (be);
00490 }
00491 
00492 gboolean
00493 qof_backend_commit_exists (QofBackend * be)
00494 {
00495     if (!be)
00496         return FALSE;
00497     if (be->commit)
00498         return TRUE;
00499     else
00500         return FALSE;
00501 }
00502 
00503 gboolean
00504 qof_load_backend_library (const gchar * directory,
00505     const gchar * filename, const gchar * init_fcn)
00506 {
00507     gchar *fullpath;
00508     typedef void (*backend_init) (void);
00509     GModule *backend;
00510     backend_init gmod_init;
00511     gpointer g;
00512 
00513     g_return_val_if_fail (g_module_supported (), FALSE);
00514     fullpath = g_module_build_path (directory, filename);
00515     backend = g_module_open (fullpath, G_MODULE_BIND_LAZY);
00516     if (!backend)
00517     {
00518         PERR (" No backend found. %s", g_module_error ());
00519         return FALSE;
00520     }
00521     g = &gmod_init;
00522     if (!g_module_symbol (backend, init_fcn, g))
00523     {
00524         PERR (" Backend did not initialise. %s", g_module_error ());
00525         return FALSE;
00526     }
00527     g_module_make_resident (backend);
00528     gmod_init ();
00529     g_free (fullpath);
00530     return TRUE;
00531 }
00532 
00533 /************************* END OF FILE ********************************/

Generated on Fri Sep 15 14:24:56 2006 for QOF by  doxygen 1.4.7