neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

dl.c (2677B)


      1 /// Functions for using external native libraries
      2 
      3 #include <stdbool.h>
      4 #include <stddef.h>
      5 #include <stdint.h>
      6 #include <uv.h>
      7 
      8 #include "nvim/gettext_defs.h"
      9 #include "nvim/memory.h"
     10 #include "nvim/message.h"
     11 #include "nvim/os/dl.h"
     12 
     13 /// possible function prototypes that can be called by os_libcall()
     14 /// int -> int
     15 /// int -> string
     16 /// string -> string
     17 /// string -> int
     18 typedef void (*gen_fn)(void);
     19 typedef const char *(*str_str_fn)(const char *str);
     20 typedef int (*str_int_fn)(const char *str);
     21 typedef const char *(*int_str_fn)(int i);
     22 typedef int (*int_int_fn)(int i);
     23 
     24 /// os_libcall - call a function in a dynamic loadable library
     25 ///
     26 /// an example of calling a function that takes a string and returns an int:
     27 ///
     28 ///   int int_out = 0;
     29 ///   os_libcall("mylib.so", "somefn", "string-argument", 0, NULL, &int_out);
     30 ///
     31 /// @param libname the name of the library to load (e.g.: libsomething.so)
     32 /// @param funcname the name of the library function (e.g.: myfunc)
     33 /// @param argv the input string, NULL when using `argi`
     34 /// @param argi the input integer, not used when using `argv` != NULL
     35 /// @param[out] str_out an allocated output string, caller must free if
     36 ///             not NULL. NULL when using `int_out`.
     37 /// @param[out] int_out the output integer param
     38 /// @return true on success, false on failure
     39 bool os_libcall(const char *libname, const char *funcname, const char *argv, int argi,
     40                char **str_out, int *int_out)
     41 {
     42  if (!libname || !funcname) {
     43    return false;
     44  }
     45 
     46  uv_lib_t lib;
     47 
     48  // open the dynamic loadable library
     49  if (uv_dlopen(libname, &lib)) {
     50    semsg(_("dlerror = \"%s\""), uv_dlerror(&lib));
     51    uv_dlclose(&lib);
     52    return false;
     53  }
     54 
     55  // find and load the requested function in the library
     56  gen_fn fn;
     57  if (uv_dlsym(&lib, funcname, (void **)&fn)) {
     58    semsg(_("dlerror = \"%s\""), uv_dlerror(&lib));
     59    uv_dlclose(&lib);
     60    return false;
     61  }
     62 
     63  // call the library and save the result
     64  // TODO(aktau): catch signals and use jmp (if available) to handle
     65  // exceptions. jmp's on Unix seem to interact trickily with signals as
     66  // well. So for now we only support those libraries that are well-behaved.
     67  if (str_out) {
     68    str_str_fn sfn = (str_str_fn)fn;
     69    int_str_fn ifn = (int_str_fn)fn;
     70 
     71    const char *res = argv ? sfn(argv) : ifn(argi);
     72 
     73    // assume that ptr values of NULL, 1 or -1 are illegal
     74    *str_out = (res && (intptr_t)res != 1 && (intptr_t)res != -1)
     75               ? xstrdup(res) : NULL;
     76  } else {
     77    str_int_fn sfn = (str_int_fn)fn;
     78    int_int_fn ifn = (int_int_fn)fn;
     79    *int_out = argv ? sfn(argv) : ifn(argi);
     80  }
     81 
     82  // free the library
     83  uv_dlclose(&lib);
     84 
     85  return true;
     86 }