diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2014-06-28 14:44:34 -0400 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2014-06-28 14:44:34 -0400 |
commit | 2ddeb74202633784b9ebb4b963e2df06ed7332df (patch) | |
tree | 0ddf05ea55842969d23a9f1dfe41c980150c3fca /src | |
parent | 2fcc07892fcf05479fa1142e6a4fe5101c1cdf7a (diff) | |
parent | 8c51804d525b771e0751603d0cb4470249dc0ae0 (diff) | |
download | rneovim-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.c | 70 | ||||
-rw-r--r-- | src/nvim/globals.h | 15 | ||||
-rw-r--r-- | src/nvim/os/dl.c | 86 | ||||
-rw-r--r-- | src/nvim/os/dl.h | 10 | ||||
-rw-r--r-- | src/nvim/os_unix.c | 190 | ||||
-rw-r--r-- | src/nvim/os_unix_defs.h | 11 | ||||
-rw-r--r-- | src/nvim/version.c | 4 |
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", |