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>
* .gitignore: Ignore loaddefs directly under lisp, and in
......
......@@ -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
......
*/*.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)
{
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)
{