📄 ltdl.c
字号:
/* Copy characters from BUF after terminating '\0' in ARGZ. */ memcpy (argz + *pargz_len, buf, buf_len); /* Assign new values. */ *pargz = argz; *pargz_len = argz_len; return 0;}#endif /* !HAVE_ARGZ_APPEND */#if ! HAVE_ARGZ_CREATE_SEP# define argz_create_sep rpl_argz_create_sepstatic error_t argz_create_sep LT_PARAMS((const char *str, int delim, char **pargz, size_t *pargz_len));static error_targz_create_sep (str, delim, pargz, pargz_len) const char *str; int delim; char **pargz; size_t *pargz_len;{ size_t argz_len; char *argz = 0; assert (str); assert (pargz); assert (pargz_len); /* Make a copy of STR, but replacing each occurence of DELIM with '\0'. */ argz_len = 1+ LT_STRLEN (str); if (argz_len) { const char *p; char *q; argz = LT_DLMALLOC (char, argz_len); if (!argz) return ENOMEM; for (p = str, q = argz; *p != LT_EOS_CHAR; ++p) { if (*p == delim) { /* Ignore leading delimiters, and fold consecutive delimiters in STR into a single '\0' in ARGZ. */ if ((q > argz) && (q[-1] != LT_EOS_CHAR)) *q++ = LT_EOS_CHAR; else --argz_len; } else *q++ = *p; } /* Copy terminating LT_EOS_CHAR. */ *q = *p; } /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory. */ if (!argz_len) LT_DLFREE (argz); /* Assign new values. */ *pargz = argz; *pargz_len = argz_len; return 0;}#endif /* !HAVE_ARGZ_CREATE_SEP */#if ! HAVE_ARGZ_INSERT# define argz_insert rpl_argz_insertstatic error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len, char *before, const char *entry));static error_targz_insert (pargz, pargz_len, before, entry) char **pargz; size_t *pargz_len; char *before; const char *entry;{ assert (pargz); assert (pargz_len); assert (entry && *entry); /* No BEFORE address indicates ENTRY should be inserted after the current last element. */ if (!before) return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry)); /* This probably indicates a programmer error, but to preserve semantics, scan back to the start of an entry if BEFORE points into the middle of it. */ while ((before > *pargz) && (before[-1] != LT_EOS_CHAR)) --before; { size_t entry_len = 1+ LT_STRLEN (entry); size_t argz_len = *pargz_len + entry_len; size_t offset = before - *pargz; char *argz = LT_DLREALLOC (char, *pargz, argz_len); if (!argz) return ENOMEM; /* Make BEFORE point to the equivalent offset in ARGZ that it used to have in *PARGZ incase realloc() moved the block. */ before = argz + offset; /* Move the ARGZ entries starting at BEFORE up into the new space at the end -- making room to copy ENTRY into the resulting gap. */ memmove (before + entry_len, before, *pargz_len - offset); memcpy (before, entry, entry_len); /* Assign new values. */ *pargz = argz; *pargz_len = argz_len; } return 0;}#endif /* !HAVE_ARGZ_INSERT */#if ! HAVE_ARGZ_NEXT# define argz_next rpl_argz_nextstatic char *argz_next LT_PARAMS((char *argz, size_t argz_len, const char *entry));static char *argz_next (argz, argz_len, entry) char *argz; size_t argz_len; const char *entry;{ assert ((argz && argz_len) || (!argz && !argz_len)); if (entry) { /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address within the ARGZ vector. */ assert ((!argz && !argz_len) || ((argz <= entry) && (entry < (argz + argz_len)))); /* Move to the char immediately after the terminating '\0' of ENTRY. */ entry = 1+ strchr (entry, LT_EOS_CHAR); /* Return either the new ENTRY, or else NULL if ARGZ is exhausted. */ return (entry >= argz + argz_len) ? 0 : (char *) entry; } else { /* This should probably be flagged as a programmer error, since starting an argz_next loop with the iterator set to ARGZ is safer. To preserve semantics, handle the NULL case by returning the start of ARGZ (if any). */ if (argz_len > 0) return argz; else return 0; }}#endif /* !HAVE_ARGZ_NEXT */#if ! HAVE_ARGZ_STRINGIFY# define argz_stringify rpl_argz_stringifystatic void argz_stringify LT_PARAMS((char *argz, size_t argz_len, int sep));static voidargz_stringify (argz, argz_len, sep) char *argz; size_t argz_len; int sep;{ assert ((argz && argz_len) || (!argz && !argz_len)); if (sep) { --argz_len; /* don't stringify the terminating EOS */ while (--argz_len > 0) { if (argz[argz_len] == LT_EOS_CHAR) argz[argz_len] = sep; } }}#endif /* !HAVE_ARGZ_STRINGIFY *//* --- TYPE DEFINITIONS -- *//* This type is used for the array of caller data sets in each handler. */typedef struct { lt_dlcaller_id key; lt_ptr data;} lt_caller_data;/* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- *//* Extract the diagnostic strings from the error table macro in the same order as the enumerated indices in ltdl.h. */static const char *lt_dlerror_strings[] = {#define LT_ERROR(name, diagnostic) (diagnostic), lt_dlerror_table#undef LT_ERROR 0 };/* This structure is used for the list of registered loaders. */struct lt_dlloader { struct lt_dlloader *next; const char *loader_name; /* identifying name for each loader */ const char *sym_prefix; /* prefix for symbols */ lt_module_open *module_open; lt_module_close *module_close; lt_find_sym *find_sym; lt_dlloader_exit *dlloader_exit; lt_user_data dlloader_data;};struct lt_dlhandle_struct { struct lt_dlhandle_struct *next; lt_dlloader *loader; /* dlopening interface */ lt_dlinfo info; int depcount; /* number of dependencies */ lt_dlhandle *deplibs; /* dependencies */ lt_module module; /* system module handle */ lt_ptr system; /* system specific data */ lt_caller_data *caller_data; /* per caller associated data */ int flags; /* various boolean stats */};/* Various boolean flags can be stored in the flags field of an lt_dlhandle_struct... */#define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag))#define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag))#define LT_DLRESIDENT_FLAG (0x01 << 0)/* ...add more flags here... */#define LT_DLIS_RESIDENT(handle) LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG)#define LT_DLSTRERROR(name) lt_dlerror_strings[LT_CONC(LT_ERROR_,name)]static const char objdir[] = LTDL_OBJDIR;static const char archive_ext[] = LTDL_ARCHIVE_EXT;#ifdef LTDL_SHLIB_EXTstatic const char shlib_ext[] = LTDL_SHLIB_EXT;#endif#ifdef LTDL_SYSSEARCHPATHstatic const char sys_search_path[] = LTDL_SYSSEARCHPATH;#endif/* --- MUTEX LOCKING --- *//* Macros to make it easier to run the lock functions only if they have been registered. The reason for the complicated lock macro is to ensure that the stored error message from the last error is not accidentally erased if the current function doesn't generate an error of its own. */#define LT_DLMUTEX_LOCK() LT_STMT_START { \ if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)(); \ } LT_STMT_END#define LT_DLMUTEX_UNLOCK() LT_STMT_START { \ if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\ } LT_STMT_END#define LT_DLMUTEX_SETERROR(errormsg) LT_STMT_START { \ if (lt_dlmutex_seterror_func) \ (*lt_dlmutex_seterror_func) (errormsg); \ else lt_dllast_error = (errormsg); } LT_STMT_END#define LT_DLMUTEX_GETERROR(errormsg) LT_STMT_START { \ if (lt_dlmutex_seterror_func) \ (errormsg) = (*lt_dlmutex_geterror_func) (); \ else (errormsg) = lt_dllast_error; } LT_STMT_END/* The mutex functions stored here are global, and are necessarily the same for all threads that wish to share access to libltdl. */static lt_dlmutex_lock *lt_dlmutex_lock_func = 0;static lt_dlmutex_unlock *lt_dlmutex_unlock_func = 0;static lt_dlmutex_seterror *lt_dlmutex_seterror_func = 0;static lt_dlmutex_geterror *lt_dlmutex_geterror_func = 0;static const char *lt_dllast_error = 0;/* Either set or reset the mutex functions. Either all the arguments must be valid functions, or else all can be NULL to turn off locking entirely. The registered functions should be manipulating a static global lock from the lock() and unlock() callbacks, which needs to be reentrant. */intlt_dlmutex_register (lock, unlock, seterror, geterror) lt_dlmutex_lock *lock; lt_dlmutex_unlock *unlock; lt_dlmutex_seterror *seterror; lt_dlmutex_geterror *geterror;{ lt_dlmutex_unlock *old_unlock = unlock; int errors = 0; /* Lock using the old lock() callback, if any. */ LT_DLMUTEX_LOCK (); if ((lock && unlock && seterror && geterror) || !(lock || unlock || seterror || geterror)) { lt_dlmutex_lock_func = lock; lt_dlmutex_unlock_func = unlock; lt_dlmutex_geterror_func = geterror; } else { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS)); ++errors; } /* Use the old unlock() callback we saved earlier, if any. Otherwise record any errors using internal storage. */ if (old_unlock) (*old_unlock) (); /* Return the number of errors encountered during the execution of this function. */ return errors;}/* --- ERROR HANDLING --- */static const char **user_error_strings = 0;static int errorcount = LT_ERROR_MAX;intlt_dladderror (diagnostic) const char *diagnostic;{ int errindex = 0; int result = -1; const char **temp = (const char **) 0; assert (diagnostic); LT_DLMUTEX_LOCK (); errindex = errorcount - LT_ERROR_MAX; temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex); if (temp) { user_error_strings = temp; user_error_strings[errindex] = diagnostic; result = errorcount++; } LT_DLMUTEX_UNLOCK (); return result;}intlt_dlseterror (errindex) int errindex;{ int errors = 0; LT_DLMUTEX_LOCK (); if (errindex >= errorcount || errindex < 0) { /* Ack! Error setting the error message! */ LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE)); ++errors; } else if (errindex < LT_ERROR_MAX) { /* No error setting the error message! */ LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]); } else { /* No error setting the error message! */ LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]); } LT_DLMUTEX_UNLOCK (); return errors;}static lt_ptrlt_emalloc (size) size_t size;{ lt_ptr mem = lt_dlmalloc (size); if (size && !mem) LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return mem;}static lt_ptrlt_erealloc (addr, size) lt_ptr addr; size_t size;{ lt_ptr mem = lt_dlrealloc (addr, size); if (size && !mem) LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return mem;}static char *lt_estrdup (str) const char *str;{ char *copy = strdup (str); if (LT_STRLEN (str) && !copy) LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return copy;}/* --- DLOPEN() INTERFACE LOADER --- */#if HAVE_LIBDL/* dynamic linking with dlopen/dlsym */#if HAVE_DLFCN_H# include <dlfcn.h>#endif#if HAVE_SYS_DL_H# include <sys/dl.h>#endif#ifdef RTLD_GLOBAL# define LT_GLOBAL RTLD_GLOBAL#else# ifdef DL_GLOBAL# define LT_GLOBAL DL_GLOBAL# endif#endif /* !RTLD_GLOBAL */#ifndef LT_GLOBAL# define LT_GLOBAL 0#endif /* !LT_GLOBAL *//* We may have to define LT_LAZY_OR_NOW in the command line if we find out it does not work in some platform. */#ifndef LT_LAZY_OR_NOW# ifdef RTLD_LAZY# define LT_LAZY_OR_NOW RTLD_LAZY# else# ifdef DL_LAZY# define LT_LAZY_OR_NOW DL_LAZY# endif# endif /* !RTLD_LAZY */#endif#ifndef LT_LAZY_OR_NOW# ifdef RTLD_NOW# define LT_LAZY_OR_NOW RTLD_NOW# else# ifdef DL_NOW# define LT_LAZY_OR_NOW DL_NOW# endif# endif /* !RTLD_NOW */#endif#ifndef LT_LAZY_OR_NOW# define LT_LAZY_OR_NOW 0#endif /* !LT_LAZY_OR_NOW */#if HAVE_DLERROR# define DLERROR(arg) dlerror ()#else# define DLERROR(arg) LT_DLSTRERROR (arg)#endifstatic lt_modulesys_dl_open (loader_data, filename) lt_user_data loader_data; const char *filename;{ lt_module module = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW); if (!module) { LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN)); } return module;}static intsys_dl_close (loader_data, module) lt_user_data loader_data; lt_module module;{ int errors = 0; if (dlclose (module) != 0) { LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE)); ++errors; } return errors;}static lt_ptrsys_dl_sym (loader_data, module, symbol) lt_user_data loader_data; lt_module module; const char *symbol;{ lt_ptr address = dlsym (module, symbol); if (!address) { LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND)); } return address;}static struct lt_user_dlloader sys_dl = {# ifdef NEED_USCORE "_",# else 0,# endif sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 };#endif /* HAVE_LIBDL *//* --- SHL_LOAD() INTERFACE LOADER --- */#if HAVE_SHL_LOAD/* dynamic linking with shl_load (HP-UX) (comments from gmodule) */#ifdef HAVE_DL_H# include <dl.h>#endif/* some flags are missing on some systems, so we provide * harmless defaults. * * Mandatory:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -