aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2014-06-28 14:44:34 -0400
committerJustin M. Keyes <justinkz@gmail.com>2014-06-28 14:44:34 -0400
commit2ddeb74202633784b9ebb4b963e2df06ed7332df (patch)
tree0ddf05ea55842969d23a9f1dfe41c980150c3fca /src
parent2fcc07892fcf05479fa1142e6a4fe5101c1cdf7a (diff)
parent8c51804d525b771e0751603d0cb4470249dc0ae0 (diff)
downloadrneovim-2ddeb74202633784b9ebb4b963e2df06ed7332df.tar.gz
rneovim-2ddeb74202633784b9ebb4b963e2df06ed7332df.tar.bz2
rneovim-2ddeb74202633784b9ebb4b963e2df06ed7332df.zip
Merge #802 'implement VimL libcall with os_libcall'
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.c70
-rw-r--r--src/nvim/globals.h15
-rw-r--r--src/nvim/os/dl.c86
-rw-r--r--src/nvim/os/dl.h10
-rw-r--r--src/nvim/os_unix.c190
-rw-r--r--src/nvim/os_unix_defs.h11
-rw-r--r--src/nvim/version.c4
7 files changed, 134 insertions, 252 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index adc411afc7..3abc148e8f 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -72,6 +72,7 @@
#include "nvim/os/channel.h"
#include "nvim/api/private/helpers.h"
#include "nvim/os/msgpack_rpc_helpers.h"
+#include "nvim/os/dl.h"
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
@@ -9673,9 +9674,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
"jumplist",
"keymap",
"langmap",
-#ifdef FEAT_LIBCALL
"libcall",
-#endif
"linebreak",
"lispindent",
"listcmds",
@@ -10623,42 +10622,49 @@ static void f_len(typval_T *argvars, typval_T *rettv)
}
}
-
-static void libcall_common(typval_T *argvars, typval_T *rettv, int type)
+static void libcall_common(typval_T *argvars, typval_T *rettv, int out_type)
{
-#ifdef FEAT_LIBCALL
- char_u *string_in;
- char_u **string_result;
- int nr_result;
-#endif
-
- rettv->v_type = type;
- if (type != VAR_NUMBER)
+ rettv->v_type = out_type;
+ if (out_type != VAR_NUMBER) {
rettv->vval.v_string = NULL;
+ }
- if (check_restricted() || check_secure())
+ if (check_restricted() || check_secure()) {
return;
+ }
-#ifdef FEAT_LIBCALL
- /* The first two args must be strings, otherwise its meaningless */
- if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING) {
- string_in = NULL;
- if (argvars[2].v_type == VAR_STRING)
- string_in = argvars[2].vval.v_string;
- if (type == VAR_NUMBER)
- string_result = NULL;
- else
- string_result = &rettv->vval.v_string;
- if (mch_libcall(argvars[0].vval.v_string,
- argvars[1].vval.v_string,
- string_in,
- argvars[2].vval.v_number,
- string_result,
- &nr_result) == OK
- && type == VAR_NUMBER)
- rettv->vval.v_number = nr_result;
+ // The first two args (libname and funcname) must be strings
+ if (argvars[0].v_type != VAR_STRING || argvars[1].v_type != VAR_STRING) {
+ return;
+ }
+
+ const char *libname = (char *) argvars[0].vval.v_string;
+ const char *funcname = (char *) argvars[1].vval.v_string;
+
+ int in_type = argvars[2].v_type;
+
+ // input variables
+ char *str_in = (in_type == VAR_STRING)
+ ? (char *) argvars[2].vval.v_string : NULL;
+ int64_t int_in = argvars[2].vval.v_number;
+
+ // output variables
+ char **str_out = (out_type == VAR_STRING)
+ ? (char **) &rettv->vval.v_string : NULL;
+ int64_t int_out = 0;
+
+ bool success = os_libcall(libname, funcname,
+ str_in, int_in,
+ str_out, &int_out);
+
+ if (!success) {
+ EMSG2(_(e_libcall), funcname);
+ return;
+ }
+
+ if (out_type == VAR_NUMBER) {
+ rettv->vval.v_number = (int) int_out;
}
-#endif
}
/*
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 903a02ca4e..8394f57f51 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -600,19 +600,6 @@ EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */
/*
- * Stuff for setjmp() and longjmp().
- * Used to protect areas where we could crash.
- */
-EXTERN JMP_BUF lc_jump_env; /* argument to SETJMP() */
-# ifdef SIGHASARG
-/* volatile because it is used in signal handlers. */
-EXTERN volatile int lc_signal; /* caught signal number, 0 when no was signal
- caught; used for mch_libcall() */
-# endif
-/* volatile because it is used in signal handler deathtrap(). */
-EXTERN volatile int lc_active INIT(= FALSE); /* TRUE when lc_jump_env is valid. */
-
-/*
* These flags are set based upon 'fileencoding'.
* Note that "enc_utf8" is also set for "unicode", because the characters are
* internally stored as UTF-8 (to avoid trouble with NUL bytes).
@@ -1019,9 +1006,7 @@ EXTERN char_u e_isadir2[] INIT(= N_("E17: \"%s\" is a directory"));
EXTERN char_u e_invjob[] INIT(= N_("E900: Invalid job id"));
EXTERN char_u e_jobtblfull[] INIT(= N_("E901: Job table is full"));
EXTERN char_u e_jobexe[] INIT(= N_("E902: \"%s\" is not an executable"));
-#ifdef FEAT_LIBCALL
EXTERN char_u e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
-#endif
EXTERN char_u e_markinval[] INIT(= N_("E19: Mark has invalid line number"));
EXTERN char_u e_marknotset[] INIT(= N_("E20: Mark not set"));
EXTERN char_u e_modifiable[] INIT(= N_(
diff --git a/src/nvim/os/dl.c b/src/nvim/os/dl.c
new file mode 100644
index 0000000000..980998eb40
--- /dev/null
+++ b/src/nvim/os/dl.c
@@ -0,0 +1,86 @@
+/// Functions for using external native libraries
+
+#include <stdint.h>
+#include <uv.h>
+
+#include "nvim/os/os.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
+
+/// possible function prototypes that can be called by os_libcall()
+/// int -> int
+/// int -> string
+/// string -> string
+/// string -> int
+typedef void (*gen_fn)();
+typedef const char *(*str_str_fn)(const char *str);
+typedef int64_t (*str_int_fn)(const char *str);
+typedef const char *(*int_str_fn)(int64_t i);
+typedef int64_t (*int_int_fn)(int64_t i);
+
+/// os_libcall - call a function in a dynamic loadable library
+///
+/// an example of calling a function that takes a string and returns an int:
+///
+/// int64_t int_out = 0;
+/// os_libcall("mylib.so", "somefn", "string-argument", 0, NULL, &int_out);
+///
+/// @param libname the name of the library to load (e.g.: libsomething.so)
+/// @param funcname the name of the library function (e.g.: myfunc)
+/// @param argv the input string, NULL when using `argi`
+/// @param argi the input integer, not used when using `argv` != NULL
+/// @param[out] str_out an allocated output string, caller must free if
+/// not NULL. NULL when using `int_out`.
+/// @param[out] int_out the output integer param
+/// @return true on success, false on failure
+bool os_libcall(const char *libname,
+ const char *funcname,
+ const char *argv,
+ int64_t argi,
+ char **str_out,
+ int64_t *int_out)
+{
+ if (!libname || !funcname) {
+ return false;
+ }
+
+ uv_lib_t lib;
+
+ // open the dynamic loadable library
+ if (uv_dlopen(libname, &lib)) {
+ EMSG2(_("dlerror = \"%s\""), uv_dlerror(&lib));
+ return false;
+ }
+
+ // find and load the requested function in the library
+ gen_fn fn;
+ if (uv_dlsym(&lib, funcname, (void **) &fn)) {
+ EMSG2(_("dlerror = \"%s\""), uv_dlerror(&lib));
+ uv_dlclose(&lib);
+ return false;
+ }
+
+ // call the library and save the result
+ // TODO(aktau): catch signals and use jmp (if available) to handle
+ // exceptions. jmp's on UNIX seem to interact trickily with signals as
+ // well. So for now we only support those libraries that are well-behaved.
+ if (str_out) {
+ str_str_fn sfn = (str_str_fn) fn;
+ int_str_fn ifn = (int_str_fn) fn;
+
+ const char *res = argv ? sfn(argv) : ifn(argi);
+
+ // assume that ptr values of NULL, 1 or -1 are illegal
+ *str_out = (res && (intptr_t) res != 1 && (intptr_t) res != -1)
+ ? xstrdup(res) : NULL;
+ } else {
+ str_int_fn sfn = (str_int_fn) fn;
+ int_int_fn ifn = (int_int_fn) fn;
+ *int_out = argv ? sfn(argv) : ifn(argi);
+ }
+
+ // free the library
+ uv_dlclose(&lib);
+
+ return true;
+}
diff --git a/src/nvim/os/dl.h b/src/nvim/os/dl.h
new file mode 100644
index 0000000000..302e4e6678
--- /dev/null
+++ b/src/nvim/os/dl.h
@@ -0,0 +1,10 @@
+#ifndef NVIM_OS_DL_H
+#define NVIM_OS_DL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/dl.h.generated.h"
+#endif
+#endif // NVIM_OS_DL_H
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index 6d1b06dbcf..01c2ef4164 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -70,11 +70,6 @@
# include <termios.h>
#endif
-/* shared library access */
-#if defined(HAVE_DLFCN_H) && defined(USE_DLOPEN)
-# include <dlfcn.h>
-#endif
-
#ifdef HAVE_SELINUX
# include <selinux/selinux.h>
static int selinux_enabled = -1;
@@ -102,36 +97,6 @@ void mch_write(char_u *s, int len)
}
/*
- * A simplistic version of setjmp() that only allows one level of using.
- * Don't call twice before calling mch_endjmp()!.
- * Usage:
- * mch_startjmp();
- * if (SETJMP(lc_jump_env) != 0)
- * {
- * mch_didjmp();
- * EMSG("crash!");
- * }
- * else
- * {
- * do_the_work;
- * mch_endjmp();
- * }
- * Note: Can't move SETJMP() here, because a function calling setjmp() must
- * not return before the saved environment is used.
- * Returns OK for normal return, FAIL when the protected code caused a
- * problem and LONGJMP() was used.
- */
-void mch_startjmp()
-{
- lc_active = TRUE;
-}
-
-void mch_endjmp()
-{
- lc_active = FALSE;
-}
-
-/*
* If the machine has job control, use it to suspend the program,
* otherwise fake it by starting a new shell.
*/
@@ -1490,158 +1455,3 @@ static int have_dollars(int num, char_u **file)
return TRUE;
return FALSE;
}
-
-#if defined(FEAT_LIBCALL) || defined(PROTO)
-typedef char_u * (*STRPROCSTR)(char_u *);
-typedef char_u * (*INTPROCSTR)(int);
-typedef int (*STRPROCINT)(char_u *);
-typedef int (*INTPROCINT)(int);
-
-/*
- * Call a DLL routine which takes either a string or int param
- * and returns an allocated string.
- */
-int mch_libcall(char_u *libname,
- char_u *funcname,
- char_u *argstring, /* NULL when using an argint */
- int argint,
- char_u **string_result, /* NULL when using number_result */
- int *number_result)
-{
-# if defined(USE_DLOPEN)
- void *hinstLib;
- char *dlerr = NULL;
-# else
- shl_t hinstLib;
-# endif
- STRPROCSTR ProcAdd;
- INTPROCSTR ProcAddI;
- char_u *retval_str = NULL;
- int retval_int = 0;
- int success = FALSE;
-
- /*
- * Get a handle to the DLL module.
- */
-# if defined(USE_DLOPEN)
- /* First clear any error, it's not cleared by the dlopen() call. */
- (void)dlerror();
-
- hinstLib = dlopen((char *)libname, RTLD_LAZY
-# ifdef RTLD_LOCAL
- | RTLD_LOCAL
-# endif
- );
- if (hinstLib == NULL) {
- /* "dlerr" must be used before dlclose() */
- dlerr = (char *)dlerror();
- if (dlerr != NULL)
- EMSG2(_("dlerror = \"%s\""), dlerr);
- }
-# else
- hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
-# endif
-
- /* If the handle is valid, try to get the function address. */
- if (hinstLib != NULL) {
- /*
- * Catch a crash when calling the library function. For example when
- * using a number where a string pointer is expected.
- */
- mch_startjmp();
- if (SETJMP(lc_jump_env) != 0) {
- success = FALSE;
-# if defined(USE_DLOPEN)
- dlerr = NULL;
-# endif
- } else
- {
- retval_str = NULL;
- retval_int = 0;
-
- if (argstring != NULL) {
-# if defined(USE_DLOPEN)
- ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
- dlerr = (char *)dlerror();
-# else
- if (shl_findsym(&hinstLib, (const char *)funcname,
- TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
- ProcAdd = NULL;
-# endif
- if ((success = (ProcAdd != NULL
-# if defined(USE_DLOPEN)
- && dlerr == NULL
-# endif
- ))) {
- if (string_result == NULL)
- retval_int = ((STRPROCINT)ProcAdd)(argstring);
- else
- retval_str = (ProcAdd)(argstring);
- }
- } else {
-# if defined(USE_DLOPEN)
- ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
- dlerr = (char *)dlerror();
-# else
- if (shl_findsym(&hinstLib, (const char *)funcname,
- TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
- ProcAddI = NULL;
-# endif
- if ((success = (ProcAddI != NULL
-# if defined(USE_DLOPEN)
- && dlerr == NULL
-# endif
- ))) {
- if (string_result == NULL)
- retval_int = ((INTPROCINT)ProcAddI)(argint);
- else
- retval_str = (ProcAddI)(argint);
- }
- }
-
- /* Save the string before we free the library. */
- /* Assume that a "1" or "-1" result is an illegal pointer. */
- if (string_result == NULL)
- *number_result = retval_int;
- else if (retval_str != NULL
- && retval_str != (char_u *)1
- && retval_str != (char_u *)-1)
- *string_result = vim_strsave(retval_str);
- }
-
- mch_endjmp();
-# ifdef SIGHASARG
- if (lc_signal != 0) {
- int i;
-
- /* try to find the name of this signal */
- for (i = 0; signal_info[i].sig != -1; i++)
- if (lc_signal == signal_info[i].sig)
- break;
- EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
- }
-# endif
-
-# if defined(USE_DLOPEN)
- /* "dlerr" must be used before dlclose() */
- if (dlerr != NULL)
- EMSG2(_("dlerror = \"%s\""), dlerr);
-
- /* Free the DLL module. */
- (void)dlclose(hinstLib);
-# else
- (void)shl_unload(hinstLib);
-# endif
- }
-
- if (!success) {
- EMSG2(_(e_libcall), funcname);
- return FAIL;
- }
-
- return OK;
-}
-#endif
-
-
-
diff --git a/src/nvim/os_unix_defs.h b/src/nvim/os_unix_defs.h
index ebecca3aae..6a3934b0c8 100644
--- a/src/nvim/os_unix_defs.h
+++ b/src/nvim/os_unix_defs.h
@@ -262,17 +262,6 @@
# include <strings.h>
#endif
-#include <setjmp.h>
-#ifdef HAVE_SIGSETJMP
-# define JMP_BUF sigjmp_buf
-# define SETJMP(x) sigsetjmp((x), 1)
-# define LONGJMP siglongjmp
-#else
-# define JMP_BUF jmp_buf
-# define SETJMP(x) setjmp(x)
-# define LONGJMP longjmp
-#endif
-
#define HAVE_DUP /* have dup() */
/* We have three kinds of ACL support. */
diff --git a/src/nvim/version.c b/src/nvim/version.c
index a220791039..5af9105eed 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -98,11 +98,7 @@ static char *(features[]) = {
"+jumplist",
"+keymap",
"+langmap",
-#ifdef FEAT_LIBCALL
"+libcall",
-#else // ifdef FEAT_LIBCALL
- "-libcall",
-#endif // ifdef FEAT_LIBCALL
"+linebreak",
"+lispindent",
"+listcmds",