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 }