1 /*
2 $Id:$
3
4 dynlib.c: Bare dynamic library load/unload support for uim
5
6 Copyright (c) 2004-2013 uim Project https://github.com/uim/uim
7
8 All rights reserved.
9
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions
12 are met:
13
14 1. Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
16 2. Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in the
18 documentation and/or other materials provided with the distribution.
19 3. Neither the name of authors nor the names of its contributors
20 may be used to endorse or promote products derived from this software
21 without specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
24 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
27 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 SUCH DAMAGE.
34 */
35
36 #include <config.h>
37
38 #include <stdio.h>
39 #include <dlfcn.h>
40
41 #include "uim.h"
42 #include "uim-internal.h"
43 #include "uim-scm.h"
44 #include "uim-scm-abbrev.h"
45 #if UIM_USE_NOTIFY_PLUGINS
46 #include "uim-notify.h"
47 #endif
48 #include "gettext.h"
49
50 #ifndef HAVE_DLFUNC
51 #define dlfunc(handle, symbol) \
52 ((void (*)(void))(uintptr_t)dlsym((handle), (symbol)))
53 #endif
54
55 /*
56 * SIOD's verbose-level compatible definition.
57 * See sigscheme/operations-siod.c for further information.
58 */
59 #define UIM_VLEVEL_DYNLIB 3
60
61 #ifdef DEBUG
62 #define DPRINTFN(n,x) if ((n) <= verbose_level()) fprintf x;
63 #else
64 #define DPRINTFN(n,x)
65 #endif
66
67 static long verbose_level(void);
68
69 struct dynlib_unbind_args {
70 uim_lisp lib_ptr;
71 uim_lisp init_proc;
72 uim_lisp quit_proc;
73 };
74 static uim_lisp dynlib_unbind(uim_lisp, uim_lisp, uim_lisp);
75 static void *dynlib_unbind_internal(struct dynlib_unbind_args *);
76 static uim_lisp dynlib_bind(uim_lisp);
77 static void *dynlib_bind_internal(uim_lisp);
78 static uim_lisp dynlib_unbind_all(uim_lisp);
79
80 static long
verbose_level(void)81 verbose_level(void)
82 {
83 uim_lisp vlevel;
84
85 vlevel = uim_scm_callf("verbose", "");
86 return C_INT(vlevel);
87 }
88
89 /* Called from uim_init */
90 void
uim_init_dynlib(void)91 uim_init_dynlib(void)
92 {
93 uim_scm_init_proc1("%%dynlib-bind", dynlib_bind);
94 uim_scm_init_proc3("%%dynlib-unbind", dynlib_unbind);
95 uim_scm_init_proc1("%%dynlib-unbind-all", dynlib_unbind_all);
96 }
97
98 /* Called from uim_quit */
99 void
uim_quit_dynlib(void)100 uim_quit_dynlib(void)
101 {
102 }
103
104 static uim_lisp
dynlib_unbind(uim_lisp lib_ptr,uim_lisp init_proc,uim_lisp quit_proc)105 dynlib_unbind(uim_lisp lib_ptr,
106 uim_lisp init_proc,
107 uim_lisp quit_proc)
108 {
109 struct dynlib_unbind_args args;
110 args.lib_ptr = lib_ptr;
111 args.init_proc = init_proc;
112 args.quit_proc = quit_proc;
113
114 return uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)dynlib_unbind_internal, (void *)&args);
115 }
116
117 static void *
dynlib_unbind_internal(struct dynlib_unbind_args * args)118 dynlib_unbind_internal(struct dynlib_unbind_args *args)
119 {
120 void *library;
121 void (*dynlib_instance_quit)(void);
122
123 library = C_PTR(args->lib_ptr);
124 dynlib_instance_quit = C_FPTR(args->quit_proc);
125
126 (*dynlib_instance_quit)();
127 dlclose(library);
128
129 return uim_scm_t();
130 }
131
132 static uim_lisp
dynlib_bind(uim_lisp name)133 dynlib_bind(uim_lisp name)
134 {
135 return uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)dynlib_bind_internal, (void *)name);
136 }
137
138 static void *
dynlib_bind_internal(uim_lisp name)139 dynlib_bind_internal(uim_lisp name)
140 {
141 void *library;
142 void (*dynlib_instance_init)(void);
143 void (*dynlib_instance_quit)(void);
144
145 DPRINTFN(UIM_VLEVEL_DYNLIB, (stderr, "Loading %s", REFER_C_STR(name)));
146 library = dlopen(REFER_C_STR(name), RTLD_NOW);
147
148 if (library == NULL) {
149 uim_notify_fatal(_("dynlib: %s: Load failed."), dlerror());
150 return uim_scm_f();
151 }
152
153 dynlib_instance_init
154 = (void (*)(void))dlfunc(library, "uim_dynlib_instance_init");
155 dynlib_instance_quit
156 = (void (*)(void))dlfunc(library, "uim_dynlib_instance_quit");
157 if (!dynlib_instance_init) {
158 uim_notify_fatal(_("dynlib: %s: Initialization failed."), REFER_C_STR(name));
159 return uim_scm_f();
160 }
161
162 DPRINTFN(UIM_VLEVEL_DYNLIB, (stderr, "Calling dynlib_instance_init() for %s.\n", REFER_C_STR(name)));
163 (*dynlib_instance_init)();
164
165 return LIST3(MAKE_PTR(library),
166 MAKE_FPTR(dynlib_instance_init),
167 MAKE_FPTR(dynlib_instance_quit));
168 }
169
170
171 static void *
dynlib_unbind_all_internal(uim_lisp plugin_alist_)172 dynlib_unbind_all_internal(uim_lisp plugin_alist_)
173 {
174 /* call dlclose(3) collectively at the end in order to avoid GC problem */
175 uim_lisp alist_ = plugin_alist_;
176
177 while (!NULLP(alist_)) {
178 uim_lisp plugin_, quit_proc_;
179 void (*dynlib_instance_quit)(void);
180
181 plugin_ = CAR(alist_);
182 quit_proc_ = CAR(CDR(CDR(CDR(plugin_))));
183 if (!FALSEP(quit_proc_)) {
184 dynlib_instance_quit = C_FPTR(quit_proc_);
185 (*dynlib_instance_quit)();
186 }
187 alist_ = CDR(alist_);
188 }
189
190 alist_ = plugin_alist_;
191 while (!NULLP(alist_)) {
192 uim_lisp plugin_, lib_;
193 void *library;
194
195 plugin_ = CAR(alist_);
196 lib_ = CAR(CDR(plugin_));
197 if (!FALSEP(lib_)) {
198 library = C_PTR(lib_);
199 dlclose(library);
200 }
201 alist_ = CDR(alist_);
202 }
203
204 return uim_scm_t();
205 }
206
207 static uim_lisp
dynlib_unbind_all(uim_lisp plugin_alist_)208 dynlib_unbind_all(uim_lisp plugin_alist_)
209 {
210 return uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)dynlib_unbind_all_internal, plugin_alist_);
211 }
212