aboutsummaryrefslogtreecommitdiffstats
path: root/src/module.c
diff options
context:
space:
mode:
authorStephen Leake2015-06-09 17:32:30 -0500
committerStephen Leake2015-06-09 17:32:30 -0500
commitf128e085bc0674967b988a72f8074a7d0cc8eba3 (patch)
tree09dbdeccc79ed5801582dc5aa860a4b04cafc5ef /src/module.c
parent76f2d766ad6691eae6ae4006264f59724cc73a23 (diff)
downloademacs-scratch/dynamic-modules-2.tar.gz
emacs-scratch/dynamic-modules-2.zip
Add loadable modules using Daniel Colascione's ideas.scratch/dynamic-modules-2
See https://lists.gnu.org/archive/html/emacs-devel/2015-02/msg00960.html * src/Makefile.in (base_obj): add module.o (LIBES): add -lltdl * src/emacs.c (main): add syms_of_module * src/lisp.h: add syms_of_module * src/emacs_module.h: New file; emacs API for modules. * src/module.c: New file; implement API. * modules/basic/Makefile: New file; build example module on Linux. * modules/basic/basic.c: New file; simple example module.
Diffstat (limited to 'src/module.c')
-rw-r--r--src/module.c435
1 files changed, 435 insertions, 0 deletions
diff --git a/src/module.c b/src/module.c
new file mode 100644
index 00000000000..d69a4b585e4
--- /dev/null
+++ b/src/module.c
@@ -0,0 +1,435 @@
1/*
2 module.c - Module loading and runtime implementation
3 Copyright (C) 2015 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <config.h>
22#include "lisp.h"
23#include "character.h"
24#include "buffer.h"
25
26/* see comment in emacs_module.h at emacs_value for this define */
27#define EMACS_VALUE_TYPE EMACS_INT
28#include "emacs_module.h"
29
30#include <ltdl.h>
31
32/* internal functions */
33void syms_of_module (void);
34static struct emacs_runtime* module_get_runtime (void);
35static emacs_env* module_get_environment (struct emacs_runtime *ert);
36
37/* emacs_module.h emacs_env_* functions; same order as there */
38/* FIXME: make_global_reference */
39/* FIXME: free_global_reference */
40/* FIXME: error_check */
41/* FIXME: clear_error */
42/* FIXME: get_error */
43static void module_signal_error (emacs_env *env,
44 const char* msg,
45 emacs_value error_data);
46static emacs_value module_make_function (emacs_env *env,
47 int min_arity,
48 int max_arity,
49 emacs_subr subr);
50static emacs_value module_funcall (emacs_env *env,
51 emacs_value fun,
52 int nargs,
53 emacs_value args[]);
54static emacs_value module_intern (emacs_env *env,
55 const char *name);
56static emacs_value module_intern_soft (emacs_env *env,
57 const char *name);
58static void module_bind_function (emacs_env *env,
59 const char *name,
60 emacs_value definition);
61/* FIXME: type_of */
62static int64_t module_fixnum_to_int (emacs_env *env,
63 emacs_value n);
64static emacs_value module_make_fixnum (emacs_env *env,
65 int64_t n);
66/* FIXME: float_to_c_double */
67/* FIXME: make_float */
68/* FIXME: copy_string_contents */
69static size_t module_buffer_byte_length (emacs_env *env,
70 emacs_value start,
71 emacs_value end);
72
73static void module_copy_buffer_substring (emacs_env *env,
74 emacs_value start,
75 emacs_value end,
76 char *buffer,
77 size_t *length_inout);
78static emacs_value module_make_string (emacs_env *env,
79 const char *contents);
80static void module_message (emacs_env *env,
81 emacs_value msg);
82static emacs_value module_symbol_value (emacs_env *env,
83 emacs_value symbol);
84
85
86static struct emacs_runtime* module_get_runtime (void)
87{
88 /* FIXME: why do we need module_get_runtime, as opposed to just module_get_environment? */
89 struct emacs_runtime *ert = xzalloc (sizeof *ert);
90
91 ert->size = sizeof *ert;
92 ert->get_environment = module_get_environment;
93
94 return ert;
95}
96
97static emacs_env* module_get_environment (struct emacs_runtime *ert)
98{
99 /* FIXME: error if not on main emacs thread? */
100
101 emacs_env *env = xzalloc (sizeof *env);
102
103 env->size = sizeof *env;
104 env->Qt_value = (emacs_value) Qt;
105 env->Qnil_value = (emacs_value) Qnil;
106 /* FIXME: make_global_reference */
107 /* FIXME: free_global_reference */
108 /* FIXME: error_check */
109 /* FIXME: clear_error */
110 /* FIXME: get_error */
111 env->signal_error = module_signal_error;
112 env->make_function = module_make_function;
113 env->funcall = module_funcall;
114 env->intern = module_intern;
115 env->intern_soft = module_intern_soft;
116 env->bind_function = module_bind_function;
117 env->fixnum_to_int = module_fixnum_to_int;
118 env->make_fixnum = module_make_fixnum;
119 /* FIXME: copy_string_contents */
120 env->buffer_byte_length = module_buffer_byte_length;
121 env->copy_buffer_substring = module_copy_buffer_substring;
122 env->make_string = module_make_string;
123 env->message = module_message;
124 env->symbol_value = module_symbol_value;
125
126 return env;
127}
128
129static emacs_value module_make_fixnum (emacs_env *env, int64_t n)
130{
131 return (emacs_value) make_number (n);
132}
133
134static int64_t module_fixnum_to_int (emacs_env *env, emacs_value n)
135{
136 return (int64_t) XINT ((Lisp_Object) n);
137}
138
139static emacs_value module_intern (emacs_env *env, const char *name)
140{
141 return (emacs_value) intern (name);
142}
143
144static emacs_value module_intern_soft (emacs_env *env, const char *name)
145{
146 register ptrdiff_t len = strlen (name);
147 register Lisp_Object tem = oblookup (Vobarray, name, len, len);
148
149 if (INTEGERP (tem))
150 return (emacs_value) Qnil;
151 else
152 return (emacs_value) tem;
153}
154
155static void module_bind_function (emacs_env *env,
156 const char *name,
157 emacs_value definition)
158{
159 Lisp_Object symbol = intern (name);
160 set_symbol_function (symbol, (Lisp_Object) definition);
161}
162
163static void module_signal_error (emacs_env *env,
164 const char* msg,
165 emacs_value error_data)
166{
167 signal_error (msg, (Lisp_Object) (error_data));
168}
169
170static emacs_value module_make_function (emacs_env *env,
171 int min_arity,
172 int max_arity,
173 emacs_subr subr)
174{
175 /*
176 (function
177 (lambda
178 (&rest arglist)
179 (module-call
180 envptr
181 subrptr
182 arglist)))
183 */
184 /* FIXME: allow for doc string and interactive */
185 Lisp_Object Qrest = intern ("&rest");
186 Lisp_Object Qarglist = intern ("arglist");
187 Lisp_Object Qmodule_call = intern ("module-call");
188 Lisp_Object envptr = make_save_ptr ((void*) env);
189 Lisp_Object subrptr = make_save_ptr ((void*) subr);
190
191 Lisp_Object form = list2 (Qfunction,
192 list3 (Qlambda,
193 list2 (Qrest, Qarglist),
194 list4 (Qmodule_call,
195 envptr,
196 subrptr,
197 Qarglist)));
198
199 struct gcpro gcpro1;
200 GCPRO1 (Qform);
201 Lisp_Object ret = Feval (form, Qnil);
202 UNGCPRO;
203
204 return (emacs_value) ret;
205}
206
207static emacs_value module_funcall (emacs_env *env,
208 emacs_value fun,
209 int nargs,
210 emacs_value args[])
211{
212 /*
213 * Make a new Lisp_Object array starting with the function as the
214 * first arg, because that's what Ffuncall takes
215 */
216 int i;
217 Lisp_Object *newargs = xmalloc ((nargs+1) * sizeof (*newargs));
218
219 newargs[0] = (Lisp_Object) fun;
220 for (i = 0; i < nargs; i++)
221 newargs[1 + i] = (Lisp_Object) args[i];
222
223 struct gcpro gcpro1;
224 GCPRO1 (newargs[0]);
225 Lisp_Object ret = Ffuncall (nargs+1, newargs);
226 UNGCPRO;
227
228 xfree (newargs);
229 return (emacs_value) ret;
230}
231
232static size_t module_buffer_byte_length (emacs_env *env,
233 emacs_value start,
234 emacs_value end)
235{
236 Lisp_Object start_1 = (Lisp_Object)start;
237 Lisp_Object end_1 = (Lisp_Object)end;
238
239 validate_region (&start_1, &end_1);
240
241 {
242 ptrdiff_t start_byte = CHAR_TO_BYTE (XINT (start_1));
243 ptrdiff_t end_byte = CHAR_TO_BYTE (XINT (end_1));
244
245 return (size_t) end_byte - start_byte;
246 }
247}
248
249static void module_copy_buffer_substring (emacs_env *env,
250 emacs_value start,
251 emacs_value end,
252 char *buffer,
253 size_t *length_inout)
254{
255 /* Copied from editfns.c "buffer-substring-no-properties" and make_buffer_string_both */
256 Lisp_Object start_1 = (Lisp_Object)start;
257 Lisp_Object end_1 = (Lisp_Object)end;
258
259 validate_region (&start_1, &end_1);
260
261 {
262 ptrdiff_t start = XINT (start_1);
263 ptrdiff_t start_byte = CHAR_TO_BYTE (start);
264 ptrdiff_t end = XINT (end_1);
265 ptrdiff_t end_byte = CHAR_TO_BYTE (end);
266 ptrdiff_t beg0, end0, beg1, end1;
267 size_t size;
268
269 if (end_byte - start_byte > *length_inout)
270 {
271 /* buffer too small */
272 /* FIXME: could copy less than requested, but that's
273 complicated for multi-byte characters */
274 signal_error ("module_copy_buffer_substring: buffer too small", Qnil);
275 }
276
277 if (start_byte < GPT_BYTE && GPT_BYTE < end_byte)
278 {
279 /* Two regions, before and after the gap. */
280 beg0 = start_byte;
281 end0 = GPT_BYTE;
282 beg1 = GPT_BYTE + GAP_SIZE - BEG_BYTE;
283 end1 = end_byte + GAP_SIZE - BEG_BYTE;
284 }
285 else
286 {
287 /* One region, before the gap. */
288 beg0 = start_byte;
289 end0 = end_byte;
290 beg1 = -1;
291 end1 = -1;
292 }
293
294 size = end0 - beg0;
295
296 /* FIXME: need to decode? See external process stuff. */
297
298 /* BYTE_POS_ADDR handles one region after the gap */
299 memcpy (buffer, BYTE_POS_ADDR (beg0), size);
300 if (beg1 != -1)
301 memcpy (buffer + size, BEG_ADDR + beg1, end1 - beg1);
302 }
303}
304
305static emacs_value module_make_string (emacs_env *env, const char *contents)
306{
307 return (emacs_value) make_string (contents, strlen (contents));
308}
309
310static void module_message (emacs_env *env,
311 emacs_value msg)
312{
313 message3 ((Lisp_Object) msg);
314}
315
316static emacs_value module_symbol_value (emacs_env *env,
317 emacs_value symbol)
318{
319 Lisp_Object val= find_symbol_value ((Lisp_Object) symbol);
320 if (!EQ (val, Qunbound))
321 return (emacs_value) val;
322
323 xsignal1 (Qvoid_variable, (Lisp_Object) symbol);
324}
325
326DEFUN ("module-call", Fmodule_call, Smodule_call, 3, 3, 0,
327 doc: "Call a module function")
328 (Lisp_Object envptr, Lisp_Object subrptr, Lisp_Object arglist)
329{
330 int len = XINT (Flength (arglist));
331 emacs_value *args = xzalloc (len * sizeof (*args));
332 int i;
333
334 for (i = 0; i < len; i++)
335 {
336 args[i] = (emacs_value) XCAR (arglist);
337 arglist = XCDR (arglist);
338 }
339
340 emacs_env *env = (emacs_env*) XSAVE_POINTER (envptr, 0);
341 emacs_subr subr = (emacs_subr) XSAVE_POINTER (subrptr, 0);
342 emacs_value ret = subr (env, len, args);
343 return (Lisp_Object) ret;
344}
345
346static int lt_init_done = 0;
347
348EXFUN (Fmodule_load, 1);
349DEFUN ("module-load", Fmodule_load, Smodule_load, 1, 1, 0,
350 doc: /* Load module FILE. */)
351 (Lisp_Object file)
352{
353 lt_dlhandle handle;
354 emacs_init_function module_init;
355 void *gpl_sym;
356 Lisp_Object doc_name, args[2];
357
358 /* init libtool once per emacs process */
359 if (!lt_init_done)
360 {
361 int ret = lt_dlinit ();
362 if (ret)
363 {
364 const char* s = lt_dlerror ();
365 error ("ltdl init fail: %s", s);
366 }
367 lt_init_done = 1;
368 }
369
370 /* FIXME: check for libltdl, load it if available; don't require
371 --with-ltdl at configure time. See image.c for example. */
372
373 CHECK_STRING (file);
374 handle = lt_dlopen (SDATA (file));
375 if (!handle)
376 error ("Cannot load file %s : %s", SDATA (file), lt_dlerror());
377
378 gpl_sym = lt_dlsym (handle, "plugin_is_GPL_compatible");
379 if (!gpl_sym)
380 error ("Module %s is not GPL compatible", SDATA (file));
381
382 module_init = (emacs_init_function) lt_dlsym (handle, "emacs_module_init");
383 if (!module_init)
384 error ("Module %s does not have an init function.", SDATA (file));
385
386
387 int r = module_init (module_get_runtime ());
388
389 /* Errors are reported by calling env->signal_error. FIXME: so why does module_init return anything? */
390 return Qt;
391}
392
393EXFUN (Fmodule_unsafe_unload, 1);
394DEFUN ("module-unsafe-unload", Fmodule_unsafe_unload, Smodule_unsafe_unload, 1, 1, 0,
395 doc: /* Unload module FILE; does not undefine any functions defined by the module.
396This permits re-compiling and re-loading while developing the module,
397but is otherwise not recommended. */)
398 (Lisp_Object file)
399{
400 lt_dlhandle handle;
401
402 if (!lt_init_done)
403 {
404 error ("no module loaded");
405 }
406
407 CHECK_STRING (file);
408 handle = lt_dlopen (SDATA (file));
409 if (!handle)
410 error ("file not loaded %s : %s", SDATA (file), lt_dlerror());
411
412 if (lt_dlclose (handle))
413 error ("Module %s not unloaded: %s", SDATA (file), lt_dlerror());
414
415 return Qt;
416}
417
418EXFUN (Fmodule_emacs_value_type, 0);
419DEFUN ("module-emacs_value-type", Fmodule_emacs_value_type, Smodule_emacs_value_type, 0, 0, 0,
420 doc: /* Return a string specifying the type for emacs_value in emacs_modules.h. */)
421 ()
422{
423 if (sizeof (EMACS_INT) == 4) /* 4 bytes == 32 bits */
424 return make_string ("uint32_t", 8);
425 else
426 return make_string ("uint64_t", 8);
427}
428
429void syms_of_module (void)
430{
431 defsubr (&Smodule_call);
432 defsubr (&Smodule_load);
433 defsubr (&Smodule_unsafe_unload);
434 defsubr (&Smodule_emacs_value_type);
435}