1 /********************************************************************\
2 * qofbackend.c -- utility routines for dealing with the data backend *
3 * Copyright (C) 2000 Linas Vepstas <linas@linas.org> *
4 * Copyright (C) 2004-5 Neil Williams <linux@codehelp.co.uk> *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22 * *
23 \********************************************************************/
24
25 extern "C"
26 {
27
28 #include <config.h>
29 #include "qof.h"
30 #include <gnc-path.h>
31 #include "gncla-dir.h"
32 }
33
34 #include <string>
35 #include <algorithm>
36 #include <vector>
37
38 #include "qof-backend.hpp"
39
40 G_GNUC_UNUSED static QofLogModule log_module = QOF_MOD_BACKEND;
41
42 #define QOF_CONFIG_DESC "desc"
43 #define QOF_CONFIG_TIP "tip"
44
45 /* *******************************************************************\
46 * error handling *
47 \********************************************************************/
48
49 GModuleVec QofBackend::c_be_registry{};
50
51 void
commit(QofInstance * instance)52 QofBackend::commit(QofInstance* instance)
53 {
54 if (qof_instance_is_dirty(instance))
55 qof_instance_mark_clean(instance);
56 }
57
58 void
set_error(QofBackendError err)59 QofBackend::set_error(QofBackendError err)
60 {
61 /* use stack-push semantics. Only the earliest error counts */
62 if (m_last_err != ERR_BACKEND_NO_ERR) return;
63 m_last_err = err;
64 }
65
66 QofBackendError
get_error()67 QofBackend::get_error()
68 {
69 /* use 'stack-pop' semantics */
70 auto err = m_last_err;
71 m_last_err = ERR_BACKEND_NO_ERR;
72 return err;
73 }
74
75 bool
check_error()76 QofBackend::check_error()
77 {
78 return m_last_err != ERR_BACKEND_NO_ERR;
79 }
80
81 void
set_message(std::string && msg)82 QofBackend::set_message (std::string&& msg)
83 {
84 m_error_msg = msg;
85 }
86
87 const std::string&&
get_message()88 QofBackend::get_message ()
89 {
90 return std::move(m_error_msg);
91 }
92
93 bool
register_backend(const char * directory,const char * module_name)94 QofBackend::register_backend(const char* directory, const char* module_name)
95 {
96 if (!g_module_supported ())
97 {
98 PWARN("Modules not supported.");
99 return false;
100 }
101
102 auto absdir = directory;
103 auto pkgdir = gnc_path_get_pkglibdir ();
104 if (!absdir || !g_path_is_absolute(absdir))
105 absdir = pkgdir;
106 auto fullpath = g_module_build_path (absdir, module_name);
107 /* Darwin modules can have either .so or .dylib for a suffix */
108 if (!g_file_test (fullpath, G_FILE_TEST_EXISTS) &&
109 g_strcmp0 (G_MODULE_SUFFIX, "so") == 0)
110 {
111 auto modname = g_strdup_printf ("lib%s.dylib", module_name);
112 g_free (fullpath);
113 fullpath = g_build_filename (absdir, modname, nullptr);
114 g_free (modname);
115 }
116 auto backend = g_module_open (fullpath, G_MODULE_BIND_LAZY);
117 g_free (fullpath);
118 g_free (pkgdir);
119 if (!backend)
120 {
121 PINFO ("%s: %s\n", PROJECT_NAME, g_module_error ());
122 return false;
123 }
124 void (*module_init_func)(void);
125 if (g_module_symbol (backend, "qof_backend_module_init",
126 reinterpret_cast<void**>(&module_init_func)))
127 module_init_func ();
128
129 g_module_make_resident (backend);
130 c_be_registry.push_back(backend);
131 return TRUE;
132 }
133
134 void
release_backends()135 QofBackend::release_backends()
136 {
137 for (auto backend : c_be_registry)
138 {
139 void (*module_finalize_func)(void);
140 if (g_module_symbol(backend, "qof_backend_module_finalize",
141 reinterpret_cast<void**>(&module_finalize_func)))
142 module_finalize_func();
143 }
144 }
145 /***********************************************************************/
146 QofBackendError
qof_backend_get_error(QofBackend * qof_be)147 qof_backend_get_error (QofBackend* qof_be)
148 {
149 if (qof_be == nullptr) return ERR_BACKEND_NO_ERR;
150 return ((QofBackend*)qof_be)->get_error();
151 }
152
153 void
qof_backend_set_error(QofBackend * qof_be,QofBackendError err)154 qof_backend_set_error (QofBackend* qof_be, QofBackendError err)
155 {
156 if (qof_be == nullptr) return;
157 ((QofBackend*)qof_be)->set_error(err);
158 }
159
160 gboolean
qof_backend_can_rollback(QofBackend * qof_be)161 qof_backend_can_rollback (QofBackend* qof_be)
162 {
163 if (qof_be == nullptr) return FALSE;
164 return true;
165 }
166
167 void
qof_backend_rollback_instance(QofBackend * qof_be,QofInstance * inst)168 qof_backend_rollback_instance (QofBackend* qof_be, QofInstance* inst)
169 {
170 if (qof_be == nullptr) return;
171 ((QofBackend*)qof_be)->rollback(inst);
172 }
173
174 gboolean
qof_load_backend_library(const char * directory,const char * module_name)175 qof_load_backend_library (const char *directory, const char* module_name)
176 {
177 return QofBackend::register_backend(directory, module_name);
178 }
179
180 void
qof_finalize_backend_libraries(void)181 qof_finalize_backend_libraries(void)
182 {
183 QofBackend::release_backends();
184 }
185
186 /************************* END OF FILE ********************************/
187