Commit ae901ddb authored by Aurélien Aptel's avatar Aurélien Aptel Committed by Ted Zlatanov

Add external modules

* 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.
parent dd601050
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> 2014-12-01 Lars Magne Ingebrigtsen <larsi@gnus.org>
* .gitignore: Ignore loaddefs directly under lisp, and in * .gitignore: Ignore loaddefs directly under lisp, and in
......
...@@ -355,6 +355,8 @@ OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support]) ...@@ -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([selinux],[don't compile with SELinux support])
OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS 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_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], 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)])], [use a file notification library (LIB one of: yes, gfile, inotify, w32, no)])],
...@@ -3179,6 +3181,18 @@ if test "${HAVE_ZLIB}" = "yes"; then ...@@ -3179,6 +3181,18 @@ if test "${HAVE_ZLIB}" = "yes"; then
fi fi
AC_SUBST(LIBZ) 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'. ### Use -lpng if available, unless `--with-png=no'.
HAVE_PNG=no HAVE_PNG=no
LIBPNG= LIBPNG=
...@@ -5049,7 +5063,7 @@ optsep= ...@@ -5049,7 +5063,7 @@ optsep=
emacs_config_features= emacs_config_features=
for opt in XAW3D XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND GPM DBUS \ for opt in XAW3D XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND GPM DBUS \
GCONF GSETTINGS NOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT \ GCONF GSETTINGS NOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT \
LIBOTF XFT ZLIB; do LIBOTF XFT ZLIB LTDL; do
case $opt in case $opt in
NOTIFY|ACL) eval val=\${${opt}_SUMMARY} ;; NOTIFY|ACL) eval val=\${${opt}_SUMMARY} ;;
...@@ -5088,6 +5102,7 @@ echo " Does Emacs use -lm17n-flt? ${HAVE_M17N_FLT} ...@@ -5088,6 +5102,7 @@ echo " Does Emacs use -lm17n-flt? ${HAVE_M17N_FLT}
echo " Does Emacs use -lotf? ${HAVE_LIBOTF}" echo " Does Emacs use -lotf? ${HAVE_LIBOTF}"
echo " Does Emacs use -lxft? ${HAVE_XFT}" echo " Does Emacs use -lxft? ${HAVE_XFT}"
echo " Does Emacs directly use zlib? ${HAVE_ZLIB}" 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 " Does Emacs use toolkit scroll bars? ${USE_TOOLKIT_SCROLL_BARS}"
echo echo
...@@ -5154,12 +5169,14 @@ dnl This will work, but you get a config.status that is not quite right ...@@ -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 (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 That doesn't have any obvious consequences for Emacs, but on the whole
dnl it seems better to just live with the duplication. 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 \ AC_CONFIG_FILES([Makefile lib/Makefile lib-src/Makefile oldXMenu/Makefile \
doc/emacs/Makefile doc/misc/Makefile doc/lispintro/Makefile \ doc/emacs/Makefile doc/misc/Makefile doc/lispintro/Makefile \
doc/lispref/Makefile src/Makefile lwlib/Makefile lisp/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. dnl test/ is not present in release tarfiles.
opt_makefile=test/automated/Makefile opt_makefile=test/automated/Makefile
......
*/*.doc
*/*.so
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.
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 $< > $@
#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);
}
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 $< > $@
#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);
}
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 $< > $@
#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);
}
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 $< > $@
#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);
}
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 $< > $@
---
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
---
a: 1
b:
- 1
- 2
- 3
---
foo:
bar: 1
baz: 2
bad: 3
zob:
- 42
- 43
---
abc
---
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
---
- abc
- def
- ghi
- jkl
(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))))
#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)
{