/* Portable API for dynamic loading. Copyright 2015 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ /* Assume modules are enabled on modern systems... *Yes*, the preprocessor macro checks could be more precise. I don't care. If you think the abstraction is too leaky use libltdl (libtool), don't reinvent the wheel by fixing this one. */ #include #include "dynlib.h" #ifdef WINDOWSNT /* MS-Windows systems. */ #include #include "lisp.h" #include "w32.h" static DWORD dynlib_last_err; /* This needs to be called at startup to countermand any non-zero values recorded by temacs. */ void dynlib_reset_last_error (void) { dynlib_last_err = 0; } dynlib_handle_ptr dynlib_open (const char *dll_fname) { HMODULE hdll; char dll_fname_local[MAX_UTF8_PATH]; if (!dll_fname) { errno = ENOTSUP; return NULL; } if (!dll_fname) hdll = GetModuleHandle (NULL); else { /* LoadLibrary wants backslashes. */ strcpy (dll_fname_local, dll_fname); unixtodos_filename (dll_fname_local); if (w32_unicode_filenames) { wchar_t dll_fname_w[MAX_PATH]; filename_to_utf16 (dll_fname_local, dll_fname_w); hdll = LoadLibraryW (dll_fname_w); } else { char dll_fname_a[MAX_PATH]; filename_to_ansi (dll_fname_local, dll_fname_a); hdll = LoadLibraryA (dll_fname_a); } } if (!hdll) dynlib_last_err = GetLastError (); return (dynlib_handle_ptr) hdll; } void * dynlib_sym (dynlib_handle_ptr h, const char *sym) { FARPROC sym_addr = NULL; if (!h || h == INVALID_HANDLE_VALUE || !sym) { dynlib_last_err = ERROR_INVALID_PARAMETER; return NULL; } sym_addr = GetProcAddress ((HMODULE) h, sym); if (!sym_addr) dynlib_last_err = GetLastError (); return (void *)sym_addr; } bool dynlib_addr (void *ptr, const char **path, const char **sym) { return false; /* Not implemented yet. */ } const char * dynlib_error (void) { char *error_string = NULL; if (dynlib_last_err) { error_string = w32_strerror (dynlib_last_err); dynlib_last_err = 0; } return error_string; } int dynlib_close (dynlib_handle_ptr h) { if (!h || h == INVALID_HANDLE_VALUE) { dynlib_last_err = ERROR_INVALID_PARAMETER; return -1; } /* If the handle is for the main module (the .exe file), it shouldn't be passed to FreeLibrary, because GetModuleHandle doesn't increment the refcount, but FreeLibrary does decrement it. I don't think this should matter for the main module, but just in case, we avoid the call here, relying on another call to GetModuleHandle to return the same value. */ if (h == GetModuleHandle (NULL)) return 0; if (!FreeLibrary ((HMODULE) h)) { dynlib_last_err = GetLastError (); return -1; } return 0; } #elif defined HAVE_UNISTD_H /* POSIX systems. */ #include dynlib_handle_ptr dynlib_open (const char *path) { return dlopen (path, RTLD_LAZY); } void * dynlib_sym (dynlib_handle_ptr h, const char *sym) { return dlsym (h, sym); } bool dynlib_addr (void *ptr, const char **path, const char **sym) { #ifdef HAVE_DLADDR Dl_info info; if (dladdr (ptr, &info) && info.dli_fname && info.dli_sname) { *path = info.dli_fname; *sym = info.dli_sname; return true; } #endif return false; } const char * dynlib_error (void) { return dlerror (); } /* FIXME: Currently there is no way to unload a module, so this function is never used. */ #if false int dynlib_close (dynlib_handle_ptr h) { return dlclose (h) == 0; } #endif #else #error "No dynamic loading for this system" #endif