summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurélien Aptel <aurelien.aptel@gmail.com>2014-12-02 16:17:10 -0500
committerTed Zlatanov <tzz@lifelogs.com>2014-12-04 19:54:16 -0500
commitae901ddbfff04e8b1b0d63c452a6ca3f4c81fb17 (patch)
treeb806504944c633be45255321d1203bbcc2504781
parentdd601050e7db69f322eea09d99751d8e6363b153 (diff)
downloademacs-dynamic-modules-rc2.tar.gz
* configure.ac: Add libtool support and module Makefiles. * src/Makefile.in: Support libtool. * src/alloc.c (mark_object): Mark the doc field of Lisp_Subr as object. * src/doc.c (doc_is_from_module_p, get_doc_string, reread_doc_file) (store_function_docstring, build_file_p, Fsnarf_documentation): Support docstrings for external modules. * src/lisp.h: Make the doc field of Lisp_Subr a Lisp_Object. * src/lread.c (Fget_load_suffixes, Fload_module, string_suffixes_p) (string_suffix_p, Fload, intern_c_string_1, defsubr) (syms_of_lread): Add loading of external modules and the docstrings of their functions. * modules/curl: New module. * modules/elisp: New module. * modules/fmod: New module. * modules/opaque: New module. * modules/yaml: New module.
-rw-r--r--ChangeLog4
-rw-r--r--configure.ac23
-rw-r--r--modules/.gitignore2
-rw-r--r--modules/ChangeLog11
-rw-r--r--modules/curl/Makefile.in15
-rw-r--r--modules/curl/curl.c118
-rw-r--r--modules/elisp/Makefile.in12
-rw-r--r--modules/elisp/elisp.c38
-rw-r--r--modules/fmod/Makefile.in12
-rw-r--r--modules/fmod/fmod.c60
-rw-r--r--modules/opaque/Makefile.in12
-rw-r--r--modules/opaque/opaque.c64
-rw-r--r--modules/yaml/Makefile.in15
-rw-r--r--modules/yaml/tests/alias.yaml14
-rw-r--r--modules/yaml/tests/map.yaml4
-rw-r--r--modules/yaml/tests/multi.yaml16
-rw-r--r--modules/yaml/tests/nest.yaml12
-rw-r--r--modules/yaml/tests/scal.yaml2
-rw-r--r--modules/yaml/tests/seq.yaml5
-rw-r--r--modules/yaml/yaml-test.el24
-rw-r--r--modules/yaml/yaml.c232
-rw-r--r--src/ChangeLog17
-rw-r--r--src/Makefile.in4
-rw-r--r--src/alloc.c1
-rw-r--r--src/doc.c139
-rw-r--r--src/lisp.h2
-rw-r--r--src/lread.c162
27 files changed, 942 insertions, 78 deletions
diff --git a/ChangeLog b/ChangeLog
index cd7698c0ab5..2152f9ecb10 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2014-12-02 Aurélien Aptel <aurelien.aptel@gmail.com>
+
+ * configure.ac: Add libtool support and module Makefiles.
+
2014-12-01 Lars Magne Ingebrigtsen <larsi@gnus.org>
* .gitignore: Ignore loaddefs directly under lisp, and in
diff --git a/configure.ac b/configure.ac
index 010abc8544c..f9fee9d884d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -355,6 +355,8 @@ OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support])
OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
OPTION_DEFAULT_ON([zlib],[don't compile with zlib decompression support])
+OPTION_DEFAULT_OFF([ltdl], [compile with dynamic module loading support])
+
AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB],
[use a file notification library (LIB one of: yes, gfile, inotify, w32, no)])],
@@ -3179,6 +3181,18 @@ if test "${HAVE_ZLIB}" = "yes"; then
fi
AC_SUBST(LIBZ)
+HAVE_LTDL=no
+LIBLTDL=
+if test "${with_ltdl}" != "no"; then
+ AC_CHECK_HEADER(ltdl.h, HAVE_LTDL=yes, HAVE_LTDL=no)
+ AC_CHECK_LIB(ltdl, lt_dlopen, HAVE_LTDL=yes, HAVE_LTDL=no)
+fi
+if test "${HAVE_LTDL}" = "yes"; then
+ AC_DEFINE(HAVE_LTDL, 1, [Define to 1 if you have the ltdl library (-lltdl).])
+ LIBLTDL="-lltdl -Wl,--export-dynamic"
+fi
+AC_SUBST(LIBLTDL)
+
### Use -lpng if available, unless `--with-png=no'.
HAVE_PNG=no
LIBPNG=
@@ -5049,7 +5063,7 @@ optsep=
emacs_config_features=
for opt in XAW3D XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND GPM DBUS \
GCONF GSETTINGS NOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT \
- LIBOTF XFT ZLIB; do
+ LIBOTF XFT ZLIB LTDL; do
case $opt in
NOTIFY|ACL) eval val=\${${opt}_SUMMARY} ;;
@@ -5088,6 +5102,7 @@ echo " Does Emacs use -lm17n-flt? ${HAVE_M17N_FLT}
echo " Does Emacs use -lotf? ${HAVE_LIBOTF}"
echo " Does Emacs use -lxft? ${HAVE_XFT}"
echo " Does Emacs directly use zlib? ${HAVE_ZLIB}"
+echo " Does Emacs use -lltdl? ${HAVE_LTDL}"
echo " Does Emacs use toolkit scroll bars? ${USE_TOOLKIT_SCROLL_BARS}"
echo
@@ -5154,12 +5169,14 @@ dnl This will work, but you get a config.status that is not quite right
dnl (see http://lists.gnu.org/archive/html/bug-autoconf/2008-08/msg00028.html).
dnl That doesn't have any obvious consequences for Emacs, but on the whole
dnl it seems better to just live with the duplication.
-SUBDIR_MAKEFILES="lib/Makefile lib-src/Makefile oldXMenu/Makefile doc/emacs/Makefile doc/misc/Makefile doc/lispintro/Makefile doc/lispref/Makefile src/Makefile lwlib/Makefile lisp/Makefile leim/Makefile nextstep/Makefile nt/Makefile"
+SUBDIR_MAKEFILES="lib/Makefile lib-src/Makefile oldXMenu/Makefile doc/emacs/Makefile doc/misc/Makefile doc/lispintro/Makefile doc/lispref/Makefile src/Makefile lwlib/Makefile lisp/Makefile leim/Makefile modules/curl/Makefile modules/elisp/Makefile modules/fmod/Makefile modules/opaque/Makefile modules/yaml/Makefile nextstep/Makefile nt/Makefile"
AC_CONFIG_FILES([Makefile lib/Makefile lib-src/Makefile oldXMenu/Makefile \
doc/emacs/Makefile doc/misc/Makefile doc/lispintro/Makefile \
doc/lispref/Makefile src/Makefile lwlib/Makefile lisp/Makefile \
- leim/Makefile nextstep/Makefile nt/Makefile])
+ leim/Makefile \
+ modules/curl/Makefile modules/elisp/Makefile modules/fmod/Makefile modules/yaml/Makefile \
+ nextstep/Makefile nt/Makefile])
dnl test/ is not present in release tarfiles.
opt_makefile=test/automated/Makefile
diff --git a/modules/.gitignore b/modules/.gitignore
new file mode 100644
index 00000000000..fc15e0a56d7
--- /dev/null
+++ b/modules/.gitignore
@@ -0,0 +1,2 @@
+*/*.doc
+*/*.so
diff --git a/modules/ChangeLog b/modules/ChangeLog
new file mode 100644
index 00000000000..180d48e5bc4
--- /dev/null
+++ b/modules/ChangeLog
@@ -0,0 +1,11 @@
+2014-12-02 Aurélien Aptel <aurelien.aptel@gmail.com>
+
+ * curl: Add new module.
+
+ * elisp: Add new module.
+
+ * fmod: Add new module.
+
+ * yaml: Add new module.
+
+ * opaque: Add new module.
diff --git a/modules/curl/Makefile.in b/modules/curl/Makefile.in
new file mode 100644
index 00000000000..2e7fda08bae
--- /dev/null
+++ b/modules/curl/Makefile.in
@@ -0,0 +1,15 @@
+ROOT = ../..
+
+CFLAGS = `pkg-config libcurl --cflags`
+LDFLAGS = `pkg-config libcurl --libs`
+
+all: curl.so curl.doc
+
+%.so: %.o
+ gcc -shared $(LDFLAGS) -o $@ $<
+
+%.o: %.c
+ gcc -ggdb3 -Wall -I$(ROOT)/src -I$(ROOT)/lib $(CFLAGS) -fPIC -c $<
+
+%.doc: %.c
+ $(ROOT)/lib-src/make-docfile $< > $@
diff --git a/modules/curl/curl.c b/modules/curl/curl.c
new file mode 100644
index 00000000000..b8b2bb63a44
--- /dev/null
+++ b/modules/curl/curl.c
@@ -0,0 +1,118 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <curl/curl.h>
+
+#include <config.h>
+#include <lisp.h>
+
+int plugin_is_GPL_compatible;
+static Lisp_Object Qcurl;
+
+struct buffer
+{
+ char *p;
+ size_t size, capacity;
+};
+
+struct Lisp_CURL
+{
+ struct buffer buf;
+ CURL *curl;
+};
+
+#define XCURL(x) ((struct Lisp_CURL*)XSAVE_POINTER (x, 0))
+
+/* curl write callback */
+static size_t
+write_cb (void *src, size_t size, size_t nb, void *userp)
+{
+ struct buffer *buf = userp;
+ size_t total = size*nb;
+
+ if (buf->size + total > buf->capacity)
+ {
+ buf->capacity = 2 * (buf->size + total);
+ buf->p = realloc (buf->p, buf->capacity);
+ }
+
+ memcpy (buf->p + buf->size, src, total);
+ buf->size += total;
+ buf->p[buf->size] = 0;
+
+ return total;
+}
+
+
+EXFUN (Fcurl_make, 0);
+DEFUN ("curl-make", Fcurl_make, Scurl_make, 0, 0, 0,
+ doc: "Return a new CURL handle.")
+ (void)
+{
+ struct Lisp_CURL *p = calloc (sizeof (*p), 1);
+ p->buf.p = calloc (1, 1); /* so that realloc always work */
+ p->buf.capacity = 0;
+ p->curl = curl_easy_init ();
+ return make_save_ptr ((void*)p);
+}
+
+
+EXFUN (Fcurl_fetch_url, 2);
+DEFUN ("curl-fetch-url", Fcurl_fetch_url, Scurl_fetch_url, 2, 2, 0,
+ doc: "Fetch and store the content of URL using HANDLE.\n"
+ "Return t if successful otherwise return an error string.")
+ (Lisp_Object handle, Lisp_Object url)
+{
+ CURLcode res;
+ struct Lisp_CURL *c = XCURL (handle);
+
+ curl_easy_setopt (c->curl, CURLOPT_URL, SSDATA (url));
+ curl_easy_setopt (c->curl, CURLOPT_WRITEFUNCTION, write_cb);
+ curl_easy_setopt (c->curl, CURLOPT_WRITEDATA, (void*)&c->buf);
+ curl_easy_setopt (c->curl, CURLOPT_USERAGENT, "curl-in-emacs/1.0");
+ res = curl_easy_perform (c->curl);
+
+ if (res != CURLE_OK)
+ {
+ const char* error = curl_easy_strerror (res);
+ return make_string (error, strlen (error));
+ }
+
+ return Qt;
+}
+
+EXFUN (Fcurl_content, 1);
+DEFUN ("curl-content", Fcurl_content, Scurl_content, 1, 1, 0,
+ doc: "Return the content of a successful fetch made in HANDLE.")
+ (Lisp_Object handle)
+{
+ struct Lisp_CURL *c = XCURL (handle);
+ return make_string (c->buf.p, c->buf.size);
+}
+
+EXFUN (Fcurl_free, 1);
+DEFUN ("curl-free", Fcurl_free, Scurl_free, 1, 1, 0,
+ doc: "Free curl HANDLE.")
+ (Lisp_Object handle)
+{
+ struct Lisp_CURL *c = XCURL (handle);
+ free (c->buf.p);
+ curl_easy_cleanup (c->curl);
+
+ return Qt;
+}
+
+void init ()
+{
+ curl_global_init (CURL_GLOBAL_ALL);
+ /* when unloading: curl_global_cleanup(); */
+
+ DEFSYM (Qcurl, "curl");
+
+ defsubr (&Scurl_make);
+ defsubr (&Scurl_fetch_url);
+ defsubr (&Scurl_content);
+ defsubr (&Scurl_free);
+
+ Fprovide (Qcurl, Qnil);
+}
diff --git a/modules/elisp/Makefile.in b/modules/elisp/Makefile.in
new file mode 100644
index 00000000000..8df325e76b7
--- /dev/null
+++ b/modules/elisp/Makefile.in
@@ -0,0 +1,12 @@
+ROOT = ../..
+
+all: elisp.so elisp.doc
+
+%.so: %.o
+ gcc -shared -o $@ $<
+
+%.o: %.c
+ gcc -ggdb3 -Wall -I$(ROOT)/src -I$(ROOT)/lib -fPIC -c $<
+
+%.doc: %.c
+ $(ROOT)/lib-src/make-docfile $< > $@
diff --git a/modules/elisp/elisp.c b/modules/elisp/elisp.c
new file mode 100644
index 00000000000..aabb24e01c6
--- /dev/null
+++ b/modules/elisp/elisp.c
@@ -0,0 +1,38 @@
+#include <string.h>
+#include <config.h>
+#include <lisp.h>
+
+int plugin_is_GPL_compatible;
+
+static Lisp_Object Qelisp, Qreplace_regexp_in_string;
+
+#define MAKE_STRING(s) (make_string (s, sizeof(s)-1))
+
+EXFUN (Felisp_test, 0);
+DEFUN ("elisp-test", Felisp_test, Selisp_test, 0, 0, 0,
+ doc: "Eval some lisp.")
+ (void)
+{
+ Lisp_Object string = MAKE_STRING ("no-more-dash");
+ Lisp_Object regex = MAKE_STRING ("[-]");
+ Lisp_Object replace = MAKE_STRING (" ");
+ Lisp_Object res;
+
+ struct gcpro gcpro1, gcpro2, gcpro3;
+ GCPRO3 (string, regex, replace);
+ res = call3 (Qreplace_regexp_in_string, regex, replace, string);
+ UNGCPRO;
+
+ return res;
+}
+
+
+void init ()
+{
+ DEFSYM (Qelisp, "elisp");
+ DEFSYM (Qreplace_regexp_in_string, "replace-regexp-in-string");
+
+ defsubr (&Selisp_test);
+
+ Fprovide (Qelisp, Qnil);
+}
diff --git a/modules/fmod/Makefile.in b/modules/fmod/Makefile.in
new file mode 100644
index 00000000000..ad9016a1cee
--- /dev/null
+++ b/modules/fmod/Makefile.in
@@ -0,0 +1,12 @@
+ROOT = ../..
+
+all: fmod.so fmod.doc
+
+%.so: %.o
+ gcc -shared -o $@ $<
+
+%.o: %.c
+ gcc -ggdb3 -Wall -I$(ROOT)/src -I$(ROOT)/lib -fPIC -c $<
+
+%.doc: %.c
+ $(ROOT)/lib-src/make-docfile $< > $@
diff --git a/modules/fmod/fmod.c b/modules/fmod/fmod.c
new file mode 100644
index 00000000000..57da6168ae2
--- /dev/null
+++ b/modules/fmod/fmod.c
@@ -0,0 +1,60 @@
+#include <config.h>
+#include <lisp.h>
+
+#include <math.h>
+
+/* emacs checks for this symbol before running the module */
+
+int plugin_is_GPL_compatible;
+
+/* module feature name */
+static Lisp_Object Qfmod;
+
+/* define a new lisp function */
+
+EXFUN (Ffmod, 2);
+DEFUN ("fmod", Ffmod, Sfmod, 2, 2, 0,
+ doc: "Returns the floating-point remainder of NUMER/DENOM")
+ (Lisp_Object numer, Lisp_Object denom)
+{
+ return make_float (fmod (extract_float (numer), extract_float (denom)));
+}
+
+EXFUN (Ffmod_test1, 0);
+DEFUN ("fmod-test1", Ffmod_test1, Sfmod_test1, 0, 0, 0,
+ doc: "Return 1")
+ (void)
+{
+ return make_float (1.);
+}
+
+EXFUN (Ffmod_test2, 0);
+DEFUN ("fmod-test2", Ffmod_test2, Sfmod_test2, 0, 0, 0,
+ doc: "Return 2")
+ (void)
+{
+ return make_float (2.);
+}
+
+
+EXFUN (Ffmod_test3, 0);
+DEFUN ("fmod-test3", Ffmod_test3, Sfmod_test3, 0, 0, 0,
+ doc: "Return 3")
+ (void)
+{
+ return make_float (3.);
+}
+
+/* entry point of the module */
+
+void init ()
+{
+ DEFSYM (Qfmod, "fmod");
+
+ defsubr (&Sfmod);
+ defsubr (&Sfmod_test1);
+ defsubr (&Sfmod_test2);
+ defsubr (&Sfmod_test3);
+
+ Fprovide (Qfmod, Qnil);
+}
diff --git a/modules/opaque/Makefile.in b/modules/opaque/Makefile.in
new file mode 100644
index 00000000000..7f507326cfe
--- /dev/null
+++ b/modules/opaque/Makefile.in
@@ -0,0 +1,12 @@
+ROOT = ../..
+
+all: opaque.so opaque.doc
+
+%.so: %.o
+ gcc -shared -o $@ $<
+
+%.o: %.c
+ gcc -ggdb3 -Wall -I$(ROOT)/src -I$(ROOT)/lib -fPIC -c $<
+
+%.doc: %.c
+ $(ROOT)/lib-src/make-docfile $< > $@
diff --git a/modules/opaque/opaque.c b/modules/opaque/opaque.c
new file mode 100644
index 00000000000..2366b2ed2e9
--- /dev/null
+++ b/modules/opaque/opaque.c
@@ -0,0 +1,64 @@
+#include <config.h>
+#include <lisp.h>
+
+int plugin_is_GPL_compatible;
+static Lisp_Object Qopaque;
+
+struct opaque
+{
+ int a, b, c;
+};
+
+static Lisp_Object Qa, Qb, Qc;
+
+EXFUN (Fopaque_make, 3);
+DEFUN ("opaque-make", Fopaque_make, Sopaque_make, 3, 3, 0,
+ doc: "Make opaque type.")
+ (Lisp_Object a, Lisp_Object b, Lisp_Object c)
+{
+ struct opaque *p = malloc (sizeof (*p));
+ p->a = XINT (a);
+ p->b = XINT (b);
+ p->c = XINT (c);
+
+ /*
+ store p as a the first slot (index 0) of a Lisp_Save_Value (which
+ is a Lisp_Misc)
+ */
+ return make_save_ptr ((void*)p);
+}
+
+EXFUN (Fopaque_free, 1);
+DEFUN ("opaque-free", Fopaque_free, Sopaque_free, 1, 1, 0,
+ doc: "Free opaque object OBJ.")
+ (Lisp_Object obj)
+{
+ /* the pointer is in the first slot (index 0) */
+ free (XSAVE_POINTER (obj, 0));
+ return Qnil;
+}
+
+EXFUN (Fopaque_get, 2);
+DEFUN ("opaque-get", Fopaque_get, Sopaque_get, 2, 2, 0,
+ doc: "Return the field F (`a', `b', `c') of the opaque object OBJ.")
+ (Lisp_Object obj, Lisp_Object f)
+{
+ struct opaque *p = XSAVE_POINTER (obj, 0);
+ int val = EQ (f, Qa) ? p->a : EQ (f, Qb) ? p->b : EQ (f, Qc) ? p->c : -1;
+ return make_number (val);
+}
+
+void init ()
+{
+ DEFSYM (Qopaque, "opaque");
+
+ DEFSYM (Qa, "a");
+ DEFSYM (Qb, "b");
+ DEFSYM (Qc, "c");
+
+ defsubr (&Sopaque_make);
+ defsubr (&Sopaque_free);
+ defsubr (&Sopaque_get);
+
+ Fprovide (Qopaque, Qnil);
+}
diff --git a/modules/yaml/Makefile.in b/modules/yaml/Makefile.in
new file mode 100644
index 00000000000..32f61e9df4f
--- /dev/null
+++ b/modules/yaml/Makefile.in
@@ -0,0 +1,15 @@
+ROOT = ../..
+
+CFLAGS = `pkg-config yaml-0.1 --cflags`
+LDFLAGS = `pkg-config yaml-0.1 --libs`
+
+all: yaml.so yaml.doc
+
+%.so: %.o
+ gcc -shared $(LDFLAGS) -o $@ $<
+
+%.o: %.c
+ gcc -ggdb3 -Wall -I$(ROOT)/src -I$(ROOT)/lib $(CFLAGS) -fPIC -c $<
+
+%.doc: %.c
+ $(ROOT)/lib-src/make-docfile $< > $@
diff --git a/modules/yaml/tests/alias.yaml b/modules/yaml/tests/alias.yaml
new file mode 100644
index 00000000000..c3dade3a011
--- /dev/null
+++ b/modules/yaml/tests/alias.yaml
@@ -0,0 +1,14 @@
+---
+invoice: 34843
+date : 2001-01-23
+bill-to: &id001
+ given : Chris
+ family : Dumars
+ address:
+ lines: |
+ 458 Walkman Dr.
+ Suite #292
+ city : Royal Oak
+ state : MI
+ postal : 48046
+ship-to: *id001
diff --git a/modules/yaml/tests/map.yaml b/modules/yaml/tests/map.yaml
new file mode 100644
index 00000000000..4021d74248a
--- /dev/null
+++ b/modules/yaml/tests/map.yaml
@@ -0,0 +1,4 @@
+---
+a: 1
+b: 2
+c: 3
diff --git a/modules/yaml/tests/multi.yaml b/modules/yaml/tests/multi.yaml
new file mode 100644
index 00000000000..1eb61f7df3e
--- /dev/null
+++ b/modules/yaml/tests/multi.yaml
@@ -0,0 +1,16 @@
+---
+a: 1
+b:
+ - 1
+ - 2
+ - 3
+---
+foo:
+ bar: 1
+ baz: 2
+ bad: 3
+zob:
+ - 42
+ - 43
+---
+abc
diff --git a/modules/yaml/tests/nest.yaml b/modules/yaml/tests/nest.yaml
new file mode 100644
index 00000000000..8a453dfc771
--- /dev/null
+++ b/modules/yaml/tests/nest.yaml
@@ -0,0 +1,12 @@
+---
+product:
+ - sku : BL394D
+ quantity : 4
+ description : Basketball
+ price : 450.00
+ - sku : BL4438H
+ quantity : 1
+ description : Super Hoop
+ price : 2392.00
+tax : 251.42
+total: 4443.52
diff --git a/modules/yaml/tests/scal.yaml b/modules/yaml/tests/scal.yaml
new file mode 100644
index 00000000000..aecd198b598
--- /dev/null
+++ b/modules/yaml/tests/scal.yaml
@@ -0,0 +1,2 @@
+---
+abc
diff --git a/modules/yaml/tests/seq.yaml b/modules/yaml/tests/seq.yaml
new file mode 100644
index 00000000000..15b6a9e3dc0
--- /dev/null
+++ b/modules/yaml/tests/seq.yaml
@@ -0,0 +1,5 @@
+---
+- abc
+- def
+- ghi
+- jkl
diff --git a/modules/yaml/yaml-test.el b/modules/yaml/yaml-test.el
new file mode 100644
index 00000000000..5f9b5c0ef10
--- /dev/null
+++ b/modules/yaml/yaml-test.el
@@ -0,0 +1,24 @@
+
+(defun yaml-expand-file (file)
+ (if (not (string-match-p "/" file))
+ (expand-file-name
+ (concat "~/prog/c/emacs/dyn/modules/yaml/tests/" file))
+ file))
+
+(defun yaml-test-file (file)
+ (require 'yaml)
+ (require 'json)
+ (with-current-buffer (get-buffer-create "out")
+ (erase-buffer)
+ (insert (json-encode (yaml-parse-file (yaml-expand-file file))))
+ (json-pretty-print (point-min) (point-max))))
+
+(defun yaml-test-buffer (file)
+ (require 'yaml)
+ (require 'json)
+ (with-current-buffer (get-buffer-create "out")
+ (erase-buffer)
+ (insert (json-encode (with-temp-buffer
+ (insert-file-contents (yaml-expand-file file))
+ (yaml-parse))))
+ (json-pretty-print (point-min) (point-max))))
diff --git a/modules/yaml/yaml.c b/modules/yaml/yaml.c
new file mode 100644
index 00000000000..3ff133476ee
--- /dev/null
+++ b/modules/yaml/yaml.c
@@ -0,0 +1,232 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <yaml.h>
+
+
+#include <config.h>
+#include <lisp.h>
+
+#include <character.h> /* buffer.h needs it */
+#include <buffer.h>
+
+int plugin_is_GPL_compatible;
+static Lisp_Object Qyaml;
+
+typedef unsigned char uchar;
+
+struct context
+{
+ yaml_parser_t p;
+ int error;
+ Lisp_Object anchors; /* hashtable mapping alias to values */
+};
+
+static Lisp_Object parse_scalar (struct context *ctx, yaml_event_t *e);
+static Lisp_Object parse_sequence (struct context *ctx, yaml_event_t *e);
+static Lisp_Object parse_mapping (struct context *ctx, yaml_event_t *e);
+
+static Lisp_Object
+parse_element (struct context *ctx)
+{
+ Lisp_Object res = Qnil;
+ yaml_event_t e;
+
+ redo:
+ yaml_parser_parse (&ctx->p, &e);
+ const char *s = (char*)e.data.alias.anchor;
+
+ switch (e.type)
+ {
+ case YAML_STREAM_START_EVENT:
+ /* a stream is a sequence of documents */
+ res = parse_sequence (ctx, &e);
+ break;
+
+ case YAML_DOCUMENT_START_EVENT:
+ case YAML_DOCUMENT_END_EVENT:
+ /* keep reading */
+ yaml_event_delete (&e);
+ goto redo;
+
+ case YAML_ALIAS_EVENT:
+ res = Fgethash (make_string (s, strlen (s)), ctx->anchors, Qnil);
+ break;
+
+ case YAML_SCALAR_EVENT:
+ res = parse_scalar (ctx, &e);
+ if (s)
+ Fputhash (make_string (s, strlen (s)), res, ctx->anchors);
+ break;
+
+ case YAML_SEQUENCE_START_EVENT:
+ res = parse_sequence (ctx, &e);
+ if (s)
+ Fputhash (make_string (s, strlen (s)), res, ctx->anchors);
+ break;
+
+ case YAML_MAPPING_START_EVENT:
+ res = parse_mapping (ctx, &e);
+ if (s)
+ Fputhash (make_string (s, strlen (s)), res, ctx->anchors);
+ break;
+
+ case YAML_NO_EVENT:
+ case YAML_MAPPING_END_EVENT:
+ case YAML_SEQUENCE_END_EVENT:
+ case YAML_STREAM_END_EVENT:
+ res = Qnil;
+ break;
+ }
+
+ yaml_event_delete (&e);
+ return res;
+}
+
+static Lisp_Object
+parse_scalar (struct context *ctx, yaml_event_t *e)
+{
+ return make_string ((char*)e->data.scalar.value, e->data.scalar.length);
+}
+
+static Lisp_Object
+parse_sequence (struct context *ctx, yaml_event_t *e)
+{
+ /* always >= 1 elements in sequence */
+ Lisp_Object cons = Fcons (parse_element (ctx), Qnil);
+ Lisp_Object res = cons;
+
+ while (1)
+ {
+ Lisp_Object e = parse_element (ctx);
+
+ if (NILP (e))
+ break;
+
+ XSETCDR (cons, Fcons(e, Qnil));
+ cons = XCDR (cons);
+ }
+
+ return res;
+}
+
+static Lisp_Object
+parse_mapping (struct context *ctx, yaml_event_t *e)
+{
+ Lisp_Object args[2];
+ args[0] = QCtest;
+ args[1] = Qequal;
+ Lisp_Object res = Fmake_hash_table (2, args);
+
+ while (1)
+ {
+ Lisp_Object key = parse_element (ctx);
+
+ if (NILP (key))
+ break;
+
+ Lisp_Object val = parse_element (ctx);
+
+ Fputhash (key, val, res);
+ }
+
+ return res;
+}
+
+static void
+context_init (struct context *ctx)
+{
+ memset (ctx, 0, sizeof (*ctx));
+ Lisp_Object args[2];
+ args[0] = QCtest;
+ args[1] = Qequal;
+ ctx->anchors = Fmake_hash_table (2, args);
+}
+
+EXFUN (Fyaml_parse_string, 1);
+DEFUN ("yaml-parse-string", Fyaml_parse_string, Syaml_parse_string, 1, 1, 0,
+ doc: "Parse STRING as yaml.")
+ (Lisp_Object string)
+{
+ struct context ctx;
+ Lisp_Object res = Qnil;
+
+ context_init (&ctx);
+
+ yaml_parser_initialize (&ctx.p);
+ yaml_parser_set_input_string (&ctx.p, SDATA (string), SBYTES (string));
+ res = parse_element (&ctx);
+ yaml_parser_delete (&ctx.p);
+
+ return res;
+}
+
+
+EXFUN (Fyaml_parse_buffer, 0);
+DEFUN ("yaml-parse-buffer", Fyaml_parse_buffer, Syaml_parse_buffer, 0, 0, 0,
+ doc: "Parse current buffer as yaml.")
+ (void)
+{
+ struct context ctx;
+ Lisp_Object res = Qnil;
+
+ context_init (&ctx);
+
+ yaml_parser_initialize (&ctx.p);
+ yaml_parser_set_input_string (&ctx.p, BYTE_POS_ADDR (BEGV_BYTE), ZV_BYTE - BEGV_BYTE);
+ res = parse_element (&ctx);
+ yaml_parser_delete (&ctx.p);
+
+ return res;
+}
+
+
+EXFUN (Fyaml_parse_file, 1);
+DEFUN ("yaml-parse-file", Fyaml_parse_file, Syaml_parse_file, 1, 1, 0,
+ doc: "Parse FILE as yaml.")
+ (Lisp_Object file)
+{
+ struct gcpro gcpro1;
+ struct context ctx;
+
+ context_init (&ctx);
+
+ int r;
+ FILE *fh;
+ Lisp_Object res = Qnil;
+
+ fh = fopen((char*)SDATA (file), "r");
+
+ if (!fh)
+ goto out;
+
+ r = yaml_parser_initialize (&ctx.p);
+
+ if (!r)
+ goto out_close;
+
+ yaml_parser_set_input_file (&ctx.p, fh);
+
+ GCPRO1 (ctx.anchors);
+ res = parse_element (&ctx);
+ UNGCPRO;
+
+ yaml_parser_delete (&ctx.p);
+
+ out_close:
+ fclose (fh);
+
+ out:
+ return res;
+}
+
+void init ()
+{
+ DEFSYM (Qyaml, "yaml");
+
+ defsubr (&Syaml_parse_file);
+ defsubr (&Syaml_parse_string);
+ defsubr (&Syaml_parse_buffer);
+
+ Fprovide (Qyaml, Qnil);
+}
diff --git a/src/ChangeLog b/src/ChangeLog
index 7dc2b928f1e..c344a0f9433 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,20 @@
+2014-12-02 Aurélien Aptel <aurelien.aptel@gmail.com>
+
+ * lread.c (Fget_load_suffixes, Fload_module, string_suffixes_p)
+ (string_suffix_p, Fload, intern_c_string_1, defsubr)
+ (syms_of_lread): Add loading of external modules and the
+ docstrings of their functions.
+
+ * lisp.h: Make the doc field of Lisp_Subr a Lisp_Object.
+
+ * doc.c (doc_is_from_module_p, get_doc_string, reread_doc_file)
+ (store_function_docstring, build_file_p, Fsnarf_documentation):
+ Support docstrings for external modules.
+
+ * alloc.c (mark_object): Mark the doc field of Lisp_Subr as object.
+
+ * Makefile.in: Support libtool.
+
2014-12-02 Eli Zaretskii <eliz@gnu.org>
* bidi.c (bidi_find_first_overridden): New function.
diff --git a/src/Makefile.in b/src/Makefile.in
index 00ac04aa836..d3468d1d1e3 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -224,6 +224,8 @@ LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
LIBZ = @LIBZ@
+LIBLTDL = @LIBLTDL@
+
XRANDR_LIBS = @XRANDR_LIBS@
XRANDR_CFLAGS = @XRANDR_CFLAGS@
@@ -425,7 +427,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
$(LIBGNUTLS_LIBS) $(LIB_PTHREAD) \
- $(GFILENOTIFY_LIBS) $(LIB_MATH) $(LIBZ)
+ $(GFILENOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBLTDL)
all: emacs$(EXEEXT) $(OTHER_FILES)
.PHONY: all
diff --git a/src/alloc.c b/src/alloc.c
index 1019c2af6cc..f15b978d52d 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6348,6 +6348,7 @@ mark_object (Lisp_Object arg)
break;
case PVEC_SUBR:
+ mark_object (XSUBR (obj)->doc);
break;
case PVEC_FREE:
diff --git a/src/doc.c b/src/doc.c
index 1b87c23e949..5290b5d277a 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -56,6 +56,15 @@ read_bytecode_char (bool unreadflag)
return *read_bytecode_pointer++;
}
+/* A module doc file must have a doc extension */
+static bool
+doc_is_from_module_p (const char* path)
+{
+ int len = strlen (path);
+ return len > 4 && (strcmp (path + len - 4, ".doc") == 0
+ || (strcmp (path + len - 4, ".DOC") == 0));
+}
+
/* Extract a doc string from a file. FILEPOS says where to get it.
If it is an integer, use that position in the standard DOC file.
If it is (FILE . INTEGER), use FILE as the file name
@@ -109,11 +118,11 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
return Qnil;
/* Put the file name in NAME as a C string.
- If it is relative, combine it with Vdoc_directory. */
+ If it is relative and not from a module, combine it with Vdoc_directory. */
tem = Ffile_name_absolute_p (file);
file = ENCODE_FILE (file);
- if (NILP (tem))
+ if (NILP (tem) && !doc_is_from_module_p (SSDATA (file)))
{
Lisp_Object docdir = ENCODE_FILE (Vdoc_directory);
minsize = SCHARS (docdir);
@@ -211,7 +220,7 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
SAFE_FREE ();
/* Sanity checking. */
- if (CONSP (filepos))
+ if (CONSP (filepos) && !doc_is_from_module_p (name))
{
int test = 1;
/* A dynamic docstring should be either at the very beginning of a "#@
@@ -321,7 +330,7 @@ reread_doc_file (Lisp_Object file)
#endif
if (NILP (file))
- Fsnarf_documentation (Vdoc_file_name);
+ Fsnarf_documentation (Vdoc_file_name, Qnil);
else
Fload (file, Qt, Qt, Qt, Qnil);
@@ -356,14 +365,16 @@ string is passed through `substitute-command-keys'. */)
fun = XCDR (fun);
if (SUBRP (fun))
{
- if (XSUBR (fun)->doc == 0)
- return Qnil;
- /* FIXME: This is not portable, as it assumes that string
- pointers have the top bit clear. */
- else if ((intptr_t) XSUBR (fun)->doc >= 0)
- doc = build_string (XSUBR (fun)->doc);
+ Lisp_Object subrdoc = XSUBR (fun)->doc;
+
+ if (NILP (subrdoc))
+ return Qnil;
+ else if (STRINGP (subrdoc))
+ return subrdoc;
+ else if (INTEGERP (subrdoc) || CONSP (subrdoc))
+ doc = subrdoc;
else
- doc = make_number ((intptr_t) XSUBR (fun)->doc);
+ error ("invalid value in subr doc field");
}
else if (COMPILEDP (fun))
{
@@ -495,7 +506,7 @@ aren't strings. */)
/* Scanning the DOC files and placing docstring offsets into functions. */
static void
-store_function_docstring (Lisp_Object obj, ptrdiff_t offset)
+store_function_docstring (Lisp_Object obj, Lisp_Object filename, ptrdiff_t offset, bool module)
{
/* Don't use indirect_function here, or defaliases will apply their
docstrings to the base functions (Bug#2603). */
@@ -506,8 +517,8 @@ store_function_docstring (Lisp_Object obj, ptrdiff_t offset)
/* Lisp_Subrs have a slot for it. */
if (SUBRP (fun))
{
- intptr_t negative_offset = - offset;
- XSUBR (fun)->doc = (char *) negative_offset;
+ Lisp_Object neg = make_number (-offset); /* XXX: no sure why.. */
+ XSUBR (fun)->doc = module ? Fcons (filename, neg) : neg;
}
/* If it's a lisp form, stick it in the form. */
@@ -526,7 +537,7 @@ store_function_docstring (Lisp_Object obj, ptrdiff_t offset)
XSETCAR (tem, make_number (offset));
}
else if (EQ (tem, Qmacro))
- store_function_docstring (XCDR (fun), offset);
+ store_function_docstring (XCDR (fun), filename, offset, module);
}
/* Bytecode objects sometimes have slots for it. */
@@ -542,9 +553,24 @@ store_function_docstring (Lisp_Object obj, ptrdiff_t offset)
}
}
+static bool
+build_file_p (const char* file, ptrdiff_t len)
+{
+ /* file can be longer than len, can't use xstrdup */
+ char *ofile = xmalloc (len + 1);
+ memcpy (ofile, file, len);
+ ofile[len] = 0;
+
+ if (ofile[len-1] == 'c')
+ ofile[len-1] = 'o';
+
+ bool res = NILP (Fmember (build_string (ofile), Vbuild_files));
+ xfree (ofile);
+ return res;
+}
DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
- 1, 1, 0,
+ 1, 2, 0,
doc: /* Used during Emacs initialization to scan the `etc/DOC...' file.
This searches the `etc/DOC...' file for doc strings and
records them in function and variable definitions.
@@ -552,7 +578,7 @@ The function takes one argument, FILENAME, a string;
it specifies the file name (without a directory) of the DOC file.
That file is found in `../etc' now; later, when the dumped Emacs is run,
the same file name is found in the `doc-directory'. */)
- (Lisp_Object filename)
+ (Lisp_Object filename, Lisp_Object module)
{
int fd;
char buf[1024 + 1];
@@ -573,22 +599,48 @@ the same file name is found in the `doc-directory'. */)
CHECK_STRING (filename);
- if
+ /* Vbuild_files is nil when temacs is run, and non-nil after that. */
+ if (NILP (Vbuild_files))
+ {
+ static char const *const buildobj[] =
+ {
+ #include "buildobj.h"
+ };
+ int i = ARRAYELTS (buildobj);
+ while (0 <= --i)
+ Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
+ Vbuild_files = Fpurecopy (Vbuild_files);
+ }
+
+ if (NILP (module))
+ {
+ /* If we're not processing a module doc, the doc file becomes
+ the "global" DOC file */
+ Vdoc_file_name = filename;
+
+ if
#ifndef CANNOT_DUMP
- (!NILP (Vpurify_flag))
+ (!NILP (Vpurify_flag))
#else /* CANNOT_DUMP */
- (0)
+ (0)
#endif /* CANNOT_DUMP */
- {
- static char const sibling_etc[] = "../etc/";
- dirname = sibling_etc;
- dirlen = sizeof sibling_etc - 1;
+ {
+ static char const sibling_etc[] = "../etc/";
+ dirname = sibling_etc;
+ dirlen = sizeof sibling_etc - 1;
+ }
+ else
+ {
+ CHECK_STRING (Vdoc_directory);
+ dirname = SSDATA (Vdoc_directory);
+ dirlen = SBYTES (Vdoc_directory);
+ }
}
else
{
- CHECK_STRING (Vdoc_directory);
- dirname = SSDATA (Vdoc_directory);
- dirlen = SBYTES (Vdoc_directory);
+ static char const empty_prefix_dir[] = "";
+ dirname = empty_prefix_dir;
+ dirlen = 0;
}
count = SPECPDL_INDEX ();
@@ -597,18 +649,6 @@ the same file name is found in the `doc-directory'. */)
strcpy (name, dirname);
strcat (name, SSDATA (filename)); /*** Add this line ***/
- /* Vbuild_files is nil when temacs is run, and non-nil after that. */
- if (NILP (Vbuild_files))
- {
- static char const *const buildobj[] =
- {
- #include "buildobj.h"
- };
- int i = ARRAYELTS (buildobj);
- while (0 <= --i)
- Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
- Vbuild_files = Fpurecopy (Vbuild_files);
- }
fd = emacs_open (name, O_RDONLY, 0);
if (fd < 0)
@@ -618,7 +658,6 @@ the same file name is found in the `doc-directory'. */)
open_errno);
}
record_unwind_protect_int (close_file_unwind, fd);
- Vdoc_file_name = filename;
filled = 0;
pos = 0;
while (1)
@@ -641,18 +680,13 @@ the same file name is found in the `doc-directory'. */)
if (p[1] == 'S')
{
skip_file = 0;
- if (end - p > 4 && end[-2] == '.'
- && (end[-1] == 'o' || end[-1] == 'c'))
+ if (NILP (module)
+ && end - p > 4
+ && end[-2] == '.'
+ && (end[-1] == 'o' || end[-1] == 'c')
+ && build_file_p (&p[2], end - p - 2))
{
- ptrdiff_t len = end - p - 2;
- char *fromfile = SAFE_ALLOCA (len + 1);
- memcpy (fromfile, &p[2], len);
- fromfile[len] = 0;
- if (fromfile[len-1] == 'c')
- fromfile[len-1] = 'o';
-
- skip_file = NILP (Fmember (build_string (fromfile),
- Vbuild_files));
+ skip_file = 1;
}
}
@@ -672,6 +706,7 @@ the same file name is found in the `doc-directory'. */)
/* Install file-position as variable-documentation property
and make it negative for a user-variable
(doc starts with a `*'). */
+ /* TODO: handle module var */
if (!NILP (Fboundp (sym))
|| !NILP (Fmemq (sym, delayed_init)))
Fput (sym, Qvariable_documentation,
@@ -683,7 +718,7 @@ the same file name is found in the `doc-directory'. */)
else if (p[1] == 'F')
{
if (!NILP (Ffboundp (sym)))
- store_function_docstring (sym, pos + end + 1 - buf);
+ store_function_docstring (sym, filename, pos + end + 1 - buf, !NILP (module));
}
else if (p[1] == 'S')
; /* Just a source file name boundary marker. Ignore it. */
diff --git a/src/lisp.h b/src/lisp.h
index a56c4a73bf8..dc855f5e2bf 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1513,7 +1513,7 @@ struct Lisp_Subr
short min_args, max_args;
const char *symbol_name;
const char *intspec;
- const char *doc;
+ Lisp_Object doc;
};
enum char_table_specials
diff --git a/src/lread.c b/src/lread.c
index 6f71ff5f468..3a2c29a616b 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -64,6 +64,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#define file_tell ftell
#endif
+#ifdef HAVE_LTDL
+#include <ltdl.h>
+#endif
+
/* Hash table read constants. */
static Lisp_Object Qhash_table, Qdata;
static Lisp_Object Qtest;
@@ -982,7 +986,15 @@ required.
This uses the variables `load-suffixes' and `load-file-rep-suffixes'. */)
(void)
{
- Lisp_Object lst = Qnil, suffixes = Vload_suffixes, suffix, ext;
+ Lisp_Object lst = Qnil, suffixes, suffix, ext;
+
+ /* module suffixes, then regular elisp suffixes */
+
+ Lisp_Object args[2];
+ args[0] = Vload_module_suffixes;
+ args[1] = Vload_suffixes;
+ suffixes = Fappend (2, args);
+
while (CONSP (suffixes))
{
Lisp_Object exts = Vload_file_rep_suffixes;
@@ -998,6 +1010,86 @@ This uses the variables `load-suffixes' and `load-file-rep-suffixes'. */)
return Fnreverse (lst);
}
+DEFUN ("load-module", Fload_module, Sload_module, 1, 1, 0,
+ doc: /* Dymamically load a compiled module. */)
+ (Lisp_Object file)
+{
+#ifdef HAVE_LTDL
+ static int lt_init_done = 0;
+ lt_dlhandle handle;
+ void (*module_init) ();
+ void *gpl_sym;
+ Lisp_Object doc_name, args[2];
+
+ /* init libtool once per emacs process */
+ if (!lt_init_done)
+ {
+ int ret = lt_dlinit ();
+ if (ret)
+ {
+ const char* s = lt_dlerror ();
+ error ("ltdl init fail: %s", s);
+ }
+ lt_init_done = 1;
+ }
+
+ CHECK_STRING (file);
+
+ handle = lt_dlopen (SDATA (file));
+ if (!handle)
+ error ("Cannot load file %s", SDATA (file));
+
+ gpl_sym = lt_dlsym (handle, "plugin_is_GPL_compatible");
+ if (!gpl_sym)
+ error ("Module %s is not GPL compatible", SDATA (file));
+
+ module_init = (void (*) ()) lt_dlsym (handle, "init");
+ if (!module_init)
+ error ("Module %s does not have an init function.", SDATA (file));
+
+ module_init ();
+
+ /* build doc file path and install it */
+ args[0] = Fsubstring (file, make_number (0), make_number (-3));
+ args[1] = build_string (".doc");
+ doc_name = Fconcat (2, args);
+ Fsnarf_documentation (doc_name, Qt);
+
+ return Qt;
+#else
+ return Qnil;
+#endif
+}
+
+
+/* Return true if STRING ends with SUFFIX. */
+static bool string_suffix_p (Lisp_Object string, const char *suffix)
+{
+ const ptrdiff_t len = strlen (suffix);
+ return memcmp (SDATA (string) + SBYTES (string) - len, suffix, len) == 0;
+}
+
+/* Return true if STRING ends with any element of SUFFIXES. */
+static bool string_suffixes_p (Lisp_Object string, Lisp_Object suffixes)
+{
+ ptrdiff_t length = SBYTES (string), suflen;
+ Lisp_Object tail, suffix;
+
+ for (tail = suffixes; CONSP (tail); tail = XCDR (tail))
+ {
+ suffix = XCAR (tail);
+ suflen = SBYTES (suffix);
+
+ if (suflen <= length)
+ {
+ if (memcmp (SDATA (string) + length - suflen, SDATA (suffix), suflen) == 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+
DEFUN ("load", Fload, Sload, 1, 5, 0,
doc: /* Execute a file of Lisp code named FILE.
First try FILE with `.elc' appended, then try with `.el',
@@ -1055,6 +1147,8 @@ Return t if the file exists and loads successfully. */)
bool newer = 0;
/* True means we are loading a compiled file. */
bool compiled = 0;
+ /* True means we are loading a dynamic module. */
+ bool module = 0;
Lisp_Object handler;
bool safe_p = 1;
const char *fmode = "r";
@@ -1105,18 +1199,14 @@ Return t if the file exists and loads successfully. */)
if (! NILP (must_suffix))
{
- /* Don't insist on adding a suffix if FILE already ends with one. */
- ptrdiff_t size = SBYTES (file);
- if (size > 3
- && !strcmp (SSDATA (file) + size - 3, ".el"))
- must_suffix = Qnil;
- else if (size > 4
- && !strcmp (SSDATA (file) + size - 4, ".elc"))
- must_suffix = Qnil;
- /* Don't insist on adding a suffix
- if the argument includes a directory name. */
- else if (! NILP (Ffile_name_directory (file)))
- must_suffix = Qnil;
+ /* Don't insist on adding a suffix if FILE already ends with
+ one or if FILE includes a directory name. */
+ if (string_suffixes_p (file, Vload_module_suffixes)
+ || string_suffixes_p (file, Vload_suffixes)
+ || ! NILP (Ffile_name_directory (file)))
+ {
+ must_suffix = Qnil;
+ }
}
if (!NILP (nosuffix))
@@ -1227,7 +1317,7 @@ Return t if the file exists and loads successfully. */)
specbind (Qold_style_backquotes, Qnil);
record_unwind_protect (load_warn_old_style_backquotes, file);
- if (!memcmp (SDATA (found) + SBYTES (found) - 4, ".elc", 4)
+ if (string_suffix_p (found, ".elc")
|| (fd >= 0 && (version = safe_to_load_version (fd)) > 0))
/* Load .elc files directly, but not when they are
remote and have no handler! */
@@ -1289,6 +1379,12 @@ Return t if the file exists and loads successfully. */)
UNGCPRO;
}
}
+#ifdef HAVE_LTDL
+ else if (string_suffixes_p (found, Vload_module_suffixes))
+ {
+ module = 1;
+ }
+#endif
else
{
/* We are loading a source file (*.el). */
@@ -1338,7 +1434,9 @@ Return t if the file exists and loads successfully. */)
if (NILP (nomessage) || force_load_messages)
{
- if (!safe_p)
+ if (module)
+ message_with_string ("Loading %s (dymamic module)...", file, 1);
+ else if (!safe_p)
message_with_string ("Loading %s (compiled; note unsafe, not compiled in Emacs)...",
file, 1);
else if (!compiled)
@@ -1358,7 +1456,14 @@ Return t if the file exists and loads successfully. */)
if (lisp_file_lexically_bound_p (Qget_file_char))
Fset (Qlexical_binding, Qt);
- if (! version || version >= 22)
+#ifdef HAVE_LTDL
+ if (module)
+ {
+ /* XXX: should the fd/stream be closed before loading the module? */
+ Fload_module (found);
+ }
+#endif
+ else if (! version || version >= 22)
readevalloop (Qget_file_char, stream, hist_file_name,
0, Qnil, Qnil, Qnil, Qnil);
else
@@ -1387,7 +1492,9 @@ Return t if the file exists and loads successfully. */)
if (!noninteractive && (NILP (nomessage) || force_load_messages))
{
- if (!safe_p)
+ if (module)
+ message_with_string ("Loading %s (dymamic module)...done", file, 1);
+ else if (!safe_p)
message_with_string ("Loading %s (compiled; note unsafe, not compiled in Emacs)...done",
file, 1);
else if (!compiled)
@@ -3837,9 +3944,6 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
if (!SYMBOLP (tem))
{
- /* Creating a non-pure string from a string literal not implemented yet.
- We could just use make_string here and live with the extra copy. */
- eassert (!NILP (Vpurify_flag));
tem = intern_driver (make_pure_c_string (str, len), obarray, XINT (tem));
}
return tem;
@@ -4094,6 +4198,7 @@ void
defsubr (struct Lisp_Subr *sname)
{
Lisp_Object sym, tem;
+ sname->doc = Qnil;
sym = intern_c_string (sname->symbol_name);
XSETPVECTYPE (sname, PVEC_SUBR);
XSETSUBR (tem, sname);
@@ -4491,6 +4596,7 @@ syms_of_lread (void)
defsubr (&Sget_file_char);
defsubr (&Smapatoms);
defsubr (&Slocate_file_internal);
+ defsubr (&Sload_module);
DEFVAR_LISP ("obarray", Vobarray,
doc: /* Symbol table for use by `intern' and `read'.
@@ -4551,8 +4657,22 @@ Initialized during startup as described in Info node `(elisp)Library Search'. *
This list should not include the empty string.
`load' and related functions try to append these suffixes, in order,
to the specified file name if a Lisp suffix is allowed or required. */);
+
Vload_suffixes = list2 (build_pure_c_string (".elc"),
- build_pure_c_string (".el"));
+ build_pure_c_string (".el"));
+
+ DEFVAR_LISP ("load-module-suffixes", Vload_module_suffixes,
+ doc: /* List of suffixes for modules files.
+This list should not include the empty string. See `load-suffixes'. */);
+
+#ifdef HAVE_LTDL
+ Vload_module_suffixes = list3 (build_pure_c_string (".dll"),
+ build_pure_c_string (".so"),
+ build_pure_c_string (".dylib"));
+#else
+ Vload_module_suffixes = Qnil;
+#endif
+
DEFVAR_LISP ("load-file-rep-suffixes", Vload_file_rep_suffixes,
doc: /* List of suffixes that indicate representations of \
the same file.