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 
00146     be->price_lookup = NULL;
00148     be->export = NULL;
00149 }
00150 
00151 void
00152 qof_backend_run_begin (QofBackend * be, QofInstance * inst)
00153 {
00154     if (!be || !inst)
00155         return;
00156     if (!be->begin)
00157         return;
00158     (be->begin) (be, inst);
00159 }
00160 
00161 gboolean
00162 qof_backend_begin_exists (QofBackend * be)
00163 {
00164     if (be->begin)
00165         return TRUE;
00166     else
00167         return FALSE;
00168 }
00169 
00170 void
00171 qof_backend_run_commit (QofBackend * be, QofInstance * inst)
00172 {
00173     if (!be || !inst)
00174         return;
00175     if (!be->commit)
00176         return;
00177     (be->commit) (be, inst);
00178 }
00179 
00180 /* =========== Backend Configuration ================ */
00181 
00182 void
00183 qof_backend_prepare_frame (QofBackend * be)
00184 {
00185     g_return_if_fail (be);
00186     if (!kvp_frame_is_empty (be->backend_configuration))
00187     {
00188         kvp_frame_delete (be->backend_configuration);
00189         be->backend_configuration = kvp_frame_new ();
00190     }
00191     be->config_count = 0;
00192 }
00193 
00194 void
00195 qof_backend_prepare_option (QofBackend * be, 
00196                             QofBackendOption * option)
00197 {
00198     KvpValue *value;
00199     gchar *temp;
00200     gint count;
00201 
00202     g_return_if_fail (be || option);
00203     count = be->config_count;
00204     count++;
00205     value = NULL;
00206     switch (option->type)
00207     {
00208     case KVP_TYPE_GINT64:
00209         {
00210             value = kvp_value_new_gint64 (*(gint64 *) option->value);
00211             break;
00212         }
00213     case KVP_TYPE_DOUBLE:
00214         {
00215             value = kvp_value_new_double (*(double *) option->value);
00216             break;
00217         }
00218     case KVP_TYPE_NUMERIC:
00219         {
00220             value = kvp_value_new_numeric (*(gnc_numeric *) option->value);
00221             break;
00222         }
00223     case KVP_TYPE_STRING:
00224         {
00225             value = kvp_value_new_string ((const char *) option->value);
00226             break;
00227         }
00228     case KVP_TYPE_GUID:
00229         {
00230             break;
00231         }                       /* unsupported */
00232     case KVP_TYPE_TIME :
00233         {
00234             value = kvp_value_new_time ((QofTime*) option->value);
00235             break;
00236         }
00237 #ifndef QOF_DISABLE_DEPRECATED
00238     case KVP_TYPE_TIMESPEC:
00239         {
00240             value = kvp_value_new_timespec (*(Timespec *) option->value);
00241             break;
00242         }
00243 #endif
00244     case KVP_TYPE_BINARY:
00245         {
00246             break;
00247         }                       /* unsupported */
00248     case KVP_TYPE_GLIST:
00249         {
00250             break;
00251         }                       /* unsupported */
00252     case KVP_TYPE_FRAME:
00253         {
00254             break;
00255         }                       /* unsupported */
00256     }
00257     if (value)
00258     {
00259         temp = g_strdup_printf ("/%s", option->option_name);
00260         kvp_frame_set_value (be->backend_configuration, temp, value);
00261         g_free (temp);
00262         temp =
00263             g_strdup_printf ("/%s/%s", QOF_CONFIG_DESC,
00264             option->option_name);
00265         kvp_frame_set_string (be->backend_configuration, temp,
00266             option->description);
00267         g_free (temp);
00268         temp =
00269             g_strdup_printf ("/%s/%s", QOF_CONFIG_TIP,
00270             option->option_name);
00271         kvp_frame_set_string (be->backend_configuration, temp,
00272             option->tooltip);
00273         g_free (temp);
00274         /* only increment the counter if successful */
00275         be->config_count = count;
00276     }
00277 }
00278 
00279 KvpFrame *
00280 qof_backend_complete_frame (QofBackend * be)
00281 {
00282     g_return_val_if_fail (be, NULL);
00283     be->config_count = 0;
00284     return be->backend_configuration;
00285 }
00286 
00287 struct config_iterate
00288 {
00289     QofBackendOptionCB fcn;
00290     gpointer data;
00291     gint count;
00292     KvpFrame *recursive;
00293 };
00294 
00295 /* Set the option with the default KvpValue,
00296 manipulate the option in the supplied callback routine
00297 then set the value of the option into the KvpValue
00298 in the configuration frame. */
00299 static void
00300 config_foreach_cb (const gchar * key, KvpValue * value, gpointer data)
00301 {
00302     QofBackendOption option;
00303     gint64 int64;
00304     double db;
00305     gnc_numeric num;
00306     gchar *parent;
00307     struct config_iterate *helper;
00308 
00309     g_return_if_fail (key || value || data);
00310     helper = (struct config_iterate *) data;
00311     if (!helper->recursive)
00312     {
00313         PERR (" no parent frame");
00314         return;
00315     }
00316     // skip the presets.
00317     if (0 == safe_strcmp (key, QOF_CONFIG_DESC))
00318     {
00319         return;
00320     }
00321     if (0 == safe_strcmp (key, QOF_CONFIG_TIP))
00322     {
00323         return;
00324     }
00325     ENTER (" key=%s", key);
00326     option.option_name = key;
00327     option.type = kvp_value_get_type (value);
00328     if (!option.type)
00329         return;
00330     switch (option.type)
00331     {                           /* set the KvpFrame value into the option */
00332     case KVP_TYPE_GINT64:
00333         {
00334             int64 = kvp_value_get_gint64 (value);
00335             option.value = (gpointer) & int64;
00336             break;
00337         }
00338     case KVP_TYPE_DOUBLE:
00339         {
00340             db = kvp_value_get_double (value);
00341             option.value = (gpointer) & db;
00342             break;
00343         }
00344     case KVP_TYPE_NUMERIC:
00345         {
00346             num = kvp_value_get_numeric (value);
00347             option.value = (gpointer) & num;
00348             break;
00349         }
00350     case KVP_TYPE_STRING:
00351         {
00352             option.value = (gpointer) kvp_value_get_string (value);
00353             break;
00354         }
00355     case KVP_TYPE_TIME :
00356     {
00357         option.value = (gpointer) kvp_value_get_time (value);
00358     }
00359 #ifndef QOF_DISABLE_DEPRECATED
00360     case KVP_TYPE_TIMESPEC:
00361         {
00362             Timespec ts;
00363             ts = kvp_value_get_timespec (value);
00364             option.value = (gpointer) & ts;
00365             break;
00366         }
00367 #endif
00368     case KVP_TYPE_GUID:
00369         {
00370             break;
00371         }                       /* unsupported */
00372     case KVP_TYPE_BINARY:
00373         {
00374             break;
00375         }                       /* unsupported */
00376     case KVP_TYPE_GLIST:
00377         {
00378             break;
00379         }                       /* unsupported */
00380     case KVP_TYPE_FRAME:
00381         {
00382             break;
00383         }                       /* unsupported */
00384     }
00385     parent = g_strdup_printf ("/%s/%s", QOF_CONFIG_DESC, key);
00386     option.description = kvp_frame_get_string (helper->recursive, parent);
00387     g_free (parent);
00388     parent = g_strdup_printf ("/%s/%s", QOF_CONFIG_TIP, key);
00389     option.tooltip = kvp_frame_get_string (helper->recursive, parent);
00390     g_free (parent);
00391     helper->count++;
00392     /* manipulate the option */
00393     helper->fcn (&option, helper->data);
00394     switch (option.type)
00395     {                           /* set the option value into the KvpFrame */
00396     case KVP_TYPE_GINT64:
00397         {
00398             kvp_frame_set_gint64 (helper->recursive, key,
00399                 (*(gint64 *) option.value));
00400             break;
00401         }
00402     case KVP_TYPE_DOUBLE:
00403         {
00404             kvp_frame_set_double (helper->recursive, key,
00405                 (*(double *) option.value));
00406             break;
00407         }
00408     case KVP_TYPE_NUMERIC:
00409         {
00410             kvp_frame_set_numeric (helper->recursive, key,
00411                 (*(gnc_numeric *) option.value));
00412             break;
00413         }
00414     case KVP_TYPE_STRING:
00415         {
00416             kvp_frame_set_string (helper->recursive, key,
00417                 (gchar *) option.value);
00418             break;
00419         }
00420     case KVP_TYPE_TIME :
00421     {
00422         kvp_frame_set_time (helper->recursive, key,
00423             (QofTime*) option.value);
00424         break;
00425     }
00426 #ifndef QOF_DISABLE_DEPRECATED
00427     case KVP_TYPE_TIMESPEC:
00428         {
00429             kvp_frame_set_timespec (helper->recursive, key,
00430                 (*(Timespec *) option.value));
00431             break;
00432         }
00433 #endif
00434     case KVP_TYPE_GUID:
00435         {
00436             break;
00437         }                       /* unsupported */
00438     case KVP_TYPE_BINARY:
00439         {
00440             break;
00441         }                       /* unsupported */
00442     case KVP_TYPE_GLIST:
00443         {
00444             break;
00445         }                       /* unsupported */
00446     case KVP_TYPE_FRAME:
00447         {
00448             break;
00449         }                       /* unsupported */
00450     }
00451     LEAVE (" ");
00452 }
00453 
00454 void
00455 qof_backend_option_foreach (KvpFrame * config, 
00456     QofBackendOptionCB cb, gpointer data)
00457 {
00458     struct config_iterate helper;
00459 
00460     if (!config || !cb)
00461         return;
00462     ENTER (" ");
00463     helper.fcn = cb;
00464     helper.count = 1;
00465     helper.data = data;
00466     helper.recursive = config;
00467     kvp_frame_for_each_slot (config, config_foreach_cb, &helper);
00468     LEAVE (" ");
00469 }
00470 
00471 void
00472 qof_backend_load_config (QofBackend * be, KvpFrame * config)
00473 {
00474     if (!be || !config)
00475         return;
00476     if (!be->load_config)
00477         return;
00478     (be->load_config) (be, config);
00479 }
00480 
00481 KvpFrame *
00482 qof_backend_get_config (QofBackend * be)
00483 {
00484     if (!be)
00485         return NULL;
00486     if (!be->get_config)
00487         return NULL;
00488     return (be->get_config) (be);
00489 }
00490 
00491 gboolean
00492 qof_backend_commit_exists (QofBackend * be)
00493 {
00494     if (!be)
00495         return FALSE;
00496     if (be->commit)
00497         return TRUE;
00498     else
00499         return FALSE;
00500 }
00501 
00502 gboolean
00503 qof_load_backend_library (const gchar * directory,
00504     const gchar * filename, const gchar * init_fcn)
00505 {
00506     gchar *fullpath;
00507     typedef void (*backend_init) (void);
00508     GModule *backend;
00509     backend_init gmod_init;
00510     gpointer g;
00511 
00512     g_return_val_if_fail (g_module_supported (), FALSE);
00513     fullpath = g_module_build_path (directory, filename);
00514     backend = g_module_open (fullpath, G_MODULE_BIND_LAZY);
00515     if (!backend)
00516     {
00517         g_message ("%s: %s\n", PACKAGE, g_module_error ());
00518         return FALSE;
00519     }
00520     g = &gmod_init;
00521     if (!g_module_symbol (backend, init_fcn, g))
00522     {
00523         g_message ("%s: %s\n", PACKAGE, g_module_error ());
00524         return FALSE;
00525     }
00526     g_module_make_resident (backend);
00527     gmod_init ();
00528     g_free (fullpath);
00529     return TRUE;
00530 }
00531 
00532 /************************* END OF FILE ********************************/

Generated on Fri Sep 1 15:37:32 2006 for QOF by  doxygen 1.4.6