/********************************************************************\ * qofbackend.c -- utility routines for dealing with the data backend * * Copyright (C) 2000 Linas Vepstas * * Copyright (C) 2004-5 Neil Williams * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License* * along with this program; if not, contact: * * * * Free Software Foundation Voice: +1-617-542-5942 * * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * * Boston, MA 02110-1301, USA gnu@gnu.org * * * \********************************************************************/ extern "C" { #include #include "qof.h" #include #include "gncla-dir.h" } #include #include #include #include "qof-backend.hpp" G_GNUC_UNUSED static QofLogModule log_module = QOF_MOD_BACKEND; #define QOF_CONFIG_DESC "desc" #define QOF_CONFIG_TIP "tip" /* *******************************************************************\ * error handling * \********************************************************************/ GModuleVec QofBackend::c_be_registry{}; void QofBackend::set_error(QofBackendError err) { /* use stack-push semantics. Only the earliest error counts */ if (m_last_err != ERR_BACKEND_NO_ERR) return; m_last_err = err; } QofBackendError QofBackend::get_error() { /* use 'stack-pop' semantics */ auto err = m_last_err; m_last_err = ERR_BACKEND_NO_ERR; return err; } bool QofBackend::check_error() { return m_last_err != ERR_BACKEND_NO_ERR; } void QofBackend::set_message (std::string&& msg) { m_error_msg = msg; } const std::string&& QofBackend::get_message () { return std::move(m_error_msg); } /* Helper function that returns a directory from which the requested module * can be loaded. This is needed because the location of the modules * depends on * - whether we're running in an installed environment or the build environment * - the operating system * - (in the build environment) which build system is used * * Note parameter rel_path is only used when invoked in the build environment * and even then only for autotools builds because each backend module is likely * to reside in its own directory in that configuration. At install time or in a * cmake build it is assumed all backend modules reside in one single directory. */ static char* get_default_module_dir(const char* rel_path) { gchar *pkglibdir; const gchar *builddir = g_getenv ("GNC_BUILDDIR"); gboolean uninstalled = (g_getenv ("GNC_UNINSTALLED") != NULL && builddir != NULL); if (uninstalled) { #ifdef CMAKE_BUILD pkglibdir = gnc_path_get_pkglibdir (); #else if (rel_path) pkglibdir = g_build_path (G_DIR_SEPARATOR_S, builddir, "libgnucash", "backend", rel_path, ".libs", NULL); else pkglibdir = g_build_path (G_DIR_SEPARATOR_S, builddir, "libgnucash", "backend", ".libs", NULL); #endif } else pkglibdir = gnc_path_get_pkglibdir (); return pkglibdir; } bool QofBackend::register_backend(const char* directory, const char* module_name) { if (!g_module_supported ()) { PWARN("Modules not supported."); return false; } auto absdir = g_strdup(directory); if (!absdir || !g_path_is_absolute(absdir)) absdir = get_default_module_dir(directory); auto fullpath = g_module_build_path (absdir, module_name); /* Darwin modules can have either .so or .dylib for a suffix */ if (!g_file_test (fullpath, G_FILE_TEST_EXISTS) && g_strcmp0 (G_MODULE_SUFFIX, "so") == 0) { auto modname = g_strdup_printf ("lib%s.dylib", module_name); g_free (fullpath); fullpath = g_build_filename (absdir, modname, NULL); g_free (modname); } g_free (absdir); auto backend = g_module_open (fullpath, G_MODULE_BIND_LAZY); g_free (fullpath); if (!backend) { PINFO ("%s: %s\n", PACKAGE, g_module_error ()); return false; } void (*module_init_func)(void); if (g_module_symbol (backend, "qof_backend_module_init", reinterpret_cast(&module_init_func))) module_init_func (); g_module_make_resident (backend); c_be_registry.push_back(backend); return TRUE; } void QofBackend::release_backends() { for (auto backend : c_be_registry) { void (*module_finalize_func)(void); if (g_module_symbol(backend, "qof_backend_module_finalize", reinterpret_cast(&module_finalize_func))) module_finalize_func(); } } /***********************************************************************/ QofBackendError qof_backend_get_error (QofBackend* qof_be) { if (qof_be == nullptr) return ERR_BACKEND_NO_ERR; return ((QofBackend*)qof_be)->get_error(); } void qof_backend_set_error (QofBackend* qof_be, QofBackendError err) { if (qof_be == nullptr) return; ((QofBackend*)qof_be)->set_error(err); } gboolean qof_backend_can_rollback (QofBackend* qof_be) { if (qof_be == nullptr) return FALSE; return true; } void qof_backend_rollback_instance (QofBackend* qof_be, QofInstance* inst) { if (qof_be == nullptr) return; ((QofBackend*)qof_be)->rollback(inst); } gboolean qof_load_backend_library (const char *directory, const char* module_name) { return QofBackend::register_backend(directory, module_name); } void qof_finalize_backend_libraries(void) { QofBackend::release_backends(); } /************************* END OF FILE ********************************/