aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReid Spencer <rspencer@reidspencer.com>2004-11-29 12:02:25 +0000
committerReid Spencer <rspencer@reidspencer.com>2004-11-29 12:02:25 +0000
commit535af2be27f9aebda21b68c893f7c8148afd76b3 (patch)
tree2d14054df1c6da9a51d1a8f3f763e5b1bb9e832b
parent5252d956959837700520dc12c533ff5d0cce1bdd (diff)
Original version of ltdl.c from libtool 1.5.10
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@18344 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/System/ltdl.c4495
1 files changed, 4495 insertions, 0 deletions
diff --git a/lib/System/ltdl.c b/lib/System/ltdl.c
new file mode 100644
index 0000000000..cd99acceb8
--- /dev/null
+++ b/lib/System/ltdl.c
@@ -0,0 +1,4495 @@
+/* ltdl.c -- system independent dlopen wrapper
+ Copyright (C) 1998, 1999, 2000, 2004 Free Software Foundation, Inc.
+ Originally by Thomas Tanner <tanner@ffii.org>
+ This file is part of GNU Libtool.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+As a special exception to the GNU Lesser General Public License,
+if you distribute this file as part of a program or library that
+is built using GNU libtool, you may include it under the same
+distribution terms that you use for the rest of that program.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA
+
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_STDIO_H
+# include <stdio.h>
+#endif
+
+/* Include the header defining malloc. On K&R C compilers,
+ that's <malloc.h>, on ANSI C and ISO C compilers, that's <stdlib.h>. */
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#else
+# if HAVE_MALLOC_H
+# include <malloc.h>
+# endif
+#endif
+
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# if HAVE_STRINGS_H
+# include <strings.h>
+# endif
+#endif
+
+#if HAVE_CTYPE_H
+# include <ctype.h>
+#endif
+
+#if HAVE_MEMORY_H
+# include <memory.h>
+#endif
+
+#if HAVE_ERRNO_H
+# include <errno.h>
+#endif
+
+
+#ifndef __WINDOWS__
+# ifdef __WIN32__
+# define __WINDOWS__
+# endif
+#endif
+
+
+#undef LT_USE_POSIX_DIRENT
+#ifdef HAVE_CLOSEDIR
+# ifdef HAVE_OPENDIR
+# ifdef HAVE_READDIR
+# ifdef HAVE_DIRENT_H
+# define LT_USE_POSIX_DIRENT
+# endif /* HAVE_DIRENT_H */
+# endif /* HAVE_READDIR */
+# endif /* HAVE_OPENDIR */
+#endif /* HAVE_CLOSEDIR */
+
+
+#undef LT_USE_WINDOWS_DIRENT_EMULATION
+#ifndef LT_USE_POSIX_DIRENT
+# ifdef __WINDOWS__
+# define LT_USE_WINDOWS_DIRENT_EMULATION
+# endif /* __WINDOWS__ */
+#endif /* LT_USE_POSIX_DIRENT */
+
+
+#ifdef LT_USE_POSIX_DIRENT
+# include <dirent.h>
+# define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name))
+#else
+# ifdef LT_USE_WINDOWS_DIRENT_EMULATION
+# define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name))
+# else
+# define dirent direct
+# define LT_D_NAMLEN(dirent) ((dirent)->d_namlen)
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+# endif
+#endif
+
+#if HAVE_ARGZ_H
+# include <argz.h>
+#endif
+
+#if HAVE_ASSERT_H
+# include <assert.h>
+#else
+# define assert(arg) ((void) 0)
+#endif
+
+#include "ltdl.h"
+
+#if WITH_DMALLOC
+# include <dmalloc.h>
+#endif
+
+
+
+
+/* --- WINDOWS SUPPORT --- */
+
+
+#ifdef DLL_EXPORT
+# define LT_GLOBAL_DATA __declspec(dllexport)
+#else
+# define LT_GLOBAL_DATA
+#endif
+
+/* fopen() mode flags for reading a text file */
+#undef LT_READTEXT_MODE
+#ifdef __WINDOWS__
+# define LT_READTEXT_MODE "rt"
+#else
+# define LT_READTEXT_MODE "r"
+#endif
+
+#ifdef LT_USE_WINDOWS_DIRENT_EMULATION
+
+#include <windows.h>
+
+#define dirent lt_dirent
+#define DIR lt_DIR
+
+struct dirent
+{
+ char d_name[2048];
+ int d_namlen;
+};
+
+typedef struct _DIR
+{
+ HANDLE hSearch;
+ WIN32_FIND_DATA Win32FindData;
+ BOOL firsttime;
+ struct dirent file_info;
+} DIR;
+
+#endif /* LT_USE_WINDOWS_DIRENT_EMULATION */
+
+
+/* --- MANIFEST CONSTANTS --- */
+
+
+/* Standard libltdl search path environment variable name */
+#undef LTDL_SEARCHPATH_VAR
+#define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH"
+
+/* Standard libtool archive file extension. */
+#undef LTDL_ARCHIVE_EXT
+#define LTDL_ARCHIVE_EXT ".la"
+
+/* max. filename length */
+#ifndef LT_FILENAME_MAX
+# define LT_FILENAME_MAX 1024
+#endif
+
+/* This is the maximum symbol size that won't require malloc/free */
+#undef LT_SYMBOL_LENGTH
+#define LT_SYMBOL_LENGTH 128
+
+/* This accounts for the _LTX_ separator */
+#undef LT_SYMBOL_OVERHEAD
+#define LT_SYMBOL_OVERHEAD 5
+
+
+
+
+/* --- MEMORY HANDLING --- */
+
+
+/* These are the functions used internally. In addition to making
+ use of the associated function pointers above, they also perform
+ error handling. */
+static char *lt_estrdup LT_PARAMS((const char *str));
+static lt_ptr lt_emalloc LT_PARAMS((size_t size));
+static lt_ptr lt_erealloc LT_PARAMS((lt_ptr addr, size_t size));
+
+/* static lt_ptr rpl_realloc LT_PARAMS((lt_ptr ptr, size_t size)); */
+#define rpl_realloc realloc
+
+/* These are the pointers that can be changed by the caller: */
+LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size))
+ = (lt_ptr (*) LT_PARAMS((size_t))) malloc;
+LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size))
+ = (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc;
+LT_GLOBAL_DATA void (*lt_dlfree) LT_PARAMS((lt_ptr ptr))
+ = (void (*) LT_PARAMS((lt_ptr))) free;
+
+/* The following macros reduce the amount of typing needed to cast
+ assigned memory. */
+#if WITH_DMALLOC
+
+#define LT_DLMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp)))
+#define LT_DLREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp)))
+#define LT_DLFREE(p) \
+ LT_STMT_START { if (p) (p) = (xfree (p), (lt_ptr) 0); } LT_STMT_END
+
+#define LT_EMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp)))
+#define LT_EREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp)))
+
+#else
+
+#define LT_DLMALLOC(tp, n) ((tp *) lt_dlmalloc ((n) * sizeof(tp)))
+#define LT_DLREALLOC(tp, p, n) ((tp *) lt_dlrealloc ((p), (n) * sizeof(tp)))
+#define LT_DLFREE(p) \
+ LT_STMT_START { if (p) (p) = (lt_dlfree (p), (lt_ptr) 0); } LT_STMT_END
+
+#define LT_EMALLOC(tp, n) ((tp *) lt_emalloc ((n) * sizeof(tp)))
+#define LT_EREALLOC(tp, p, n) ((tp *) lt_erealloc ((p), (n) * sizeof(tp)))
+
+#endif
+
+#define LT_DLMEM_REASSIGN(p, q) LT_STMT_START { \
+ if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; } \
+ } LT_STMT_END
+
+
+/* --- REPLACEMENT FUNCTIONS --- */
+
+
+#undef strdup
+#define strdup rpl_strdup
+
+static char *strdup LT_PARAMS((const char *str));
+
+static char *
+strdup(str)
+ const char *str;
+{
+ char *tmp = 0;
+
+ if (str)
+ {
+ tmp = LT_DLMALLOC (char, 1+ strlen (str));
+ if (tmp)
+ {
+ strcpy(tmp, str);
+ }
+ }
+
+ return tmp;
+}
+
+
+#if ! HAVE_STRCMP
+
+#undef strcmp
+#define strcmp rpl_strcmp
+
+static int strcmp LT_PARAMS((const char *str1, const char *str2));
+
+static int
+strcmp (str1, str2)
+ const char *str1;
+ const char *str2;
+{
+ if (str1 == str2)
+ return 0;
+ if (str1 == 0)
+ return -1;
+ if (str2 == 0)
+ return 1;
+
+ for (;*str1 && *str2; ++str1, ++str2)
+ {
+ if (*str1 != *str2)
+ break;
+ }
+
+ return (int)(*str1 - *str2);
+}
+#endif
+
+
+#if ! HAVE_STRCHR
+
+# if HAVE_INDEX
+# define strchr index
+# else
+# define strchr rpl_strchr
+
+static const char *strchr LT_PARAMS((const char *str, int ch));
+
+static const char*
+strchr(str, ch)
+ const char *str;
+ int ch;
+{
+ const char *p;
+
+ for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p)
+ /*NOWORK*/;
+
+ return (*p == (char)ch) ? p : 0;
+}
+
+# endif
+#endif /* !HAVE_STRCHR */
+
+
+#if ! HAVE_STRRCHR
+
+# if HAVE_RINDEX
+# define strrchr rindex
+# else
+# define strrchr rpl_strrchr
+
+static const char *strrchr LT_PARAMS((const char *str, int ch));
+
+static const char*
+strrchr(str, ch)
+ const char *str;
+ int ch;
+{
+ const char *p, *q = 0;
+
+ for (p = str; *p != LT_EOS_CHAR; ++p)
+ {
+ if (*p == (char) ch)
+ {
+ q = p;
+ }
+ }
+
+ return q;
+}
+
+# endif
+#endif
+
+/* NOTE: Neither bcopy nor the memcpy implementation below can
+ reliably handle copying in overlapping areas of memory. Use
+ memmove (for which there is a fallback implmentation below)
+ if you need that behaviour. */
+#if ! HAVE_MEMCPY
+
+# if HAVE_BCOPY
+# define memcpy(dest, src, size) bcopy (src, dest, size)
+# else
+# define memcpy rpl_memcpy
+
+static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
+
+static lt_ptr
+memcpy (dest, src, size)
+ lt_ptr dest;
+ const lt_ptr src;
+ size_t size;
+{
+ const char * s = src;
+ char * d = dest;
+ size_t i = 0;
+
+ for (i = 0; i < size; ++i)
+ {
+ d[i] = s[i];
+ }
+
+ return dest;
+}
+
+# endif /* !HAVE_BCOPY */
+#endif /* !HAVE_MEMCPY */
+
+#if ! HAVE_MEMMOVE
+# define memmove rpl_memmove
+
+static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
+
+static lt_ptr
+memmove (dest, src, size)
+ lt_ptr dest;
+ const lt_ptr src;
+ size_t size;
+{
+ const char * s = src;
+ char * d = dest;
+ size_t i;
+
+ if (d < s)
+ for (i = 0; i < size; ++i)
+ {
+ d[i] = s[i];
+ }
+ else if (d > s && size > 0)
+ for (i = size -1; ; --i)
+ {
+ d[i] = s[i];
+ if (i == 0)
+ break;
+ }
+
+ return dest;
+}
+
+#endif /* !HAVE_MEMMOVE */
+
+#ifdef LT_USE_WINDOWS_DIRENT_EMULATION
+
+static void closedir LT_PARAMS((DIR *entry));
+
+static void
+closedir(entry)
+ DIR *entry;
+{
+ assert(entry != (DIR *) NULL);
+ FindClose(entry->hSearch);
+ lt_dlfree((lt_ptr)entry);
+}
+
+
+static DIR * opendir LT_PARAMS((const char *path));
+
+static DIR*
+opendir (path)
+ const char *path;
+{
+ char file_specification[LT_FILENAME_MAX];
+ DIR *entry;
+
+ assert(path != (char *) NULL);
+ (void) strncpy(file_specification,path,LT_FILENAME_MAX-1);
+ (void) strcat(file_specification,"\\");
+ entry = LT_DLMALLOC (DIR,sizeof(DIR));
+ if (entry != (DIR *) 0)
+ {
+ entry->firsttime = TRUE;
+ entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData);
+ }
+ if (entry->hSearch == INVALID_HANDLE_VALUE)
+ {
+ (void) strcat(file_specification,"\\*.*");
+ entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData);
+ if (entry->hSearch == INVALID_HANDLE_VALUE)
+ {
+ LT_DLFREE (entry);
+ return (DIR *) 0;
+ }
+ }
+ return(entry);
+}
+
+
+static struct dirent *readdir LT_PARAMS((DIR *entry));
+
+static struct dirent *readdir(entry)
+ DIR *entry;
+{
+ int
+ status;
+
+ if (entry == (DIR *) 0)
+ return((struct dirent *) 0);
+ if (!entry->firsttime)
+ {
+ status = FindNextFile(entry->hSearch,&entry->Win32FindData);
+ if (status == 0)
+ return((struct dirent *) 0);
+ }
+ entry->firsttime = FALSE;
+ (void) strncpy(entry->file_info.d_name,entry->Win32FindData.cFileName,
+ LT_FILENAME_MAX-1);
+ entry->file_info.d_namlen = strlen(entry->file_info.d_name);
+ return(&entry->file_info);
+}
+
+#endif /* LT_USE_WINDOWS_DIRENT_EMULATION */
+
+/* According to Alexandre Oliva <oliva@lsd.ic.unicamp.br>,
+ ``realloc is not entirely portable''
+ In any case we want to use the allocator supplied by the user without
+ burdening them with an lt_dlrealloc function pointer to maintain.
+ Instead implement our own version (with known boundary conditions)
+ using lt_dlmalloc and lt_dlfree. */
+
+/* #undef realloc
+ #define realloc rpl_realloc
+*/
+#if 0
+ /* You can't (re)define realloc unless you also (re)define malloc.
+ Right now, this code uses the size of the *destination* to decide
+ how much to copy. That's not right, but you can't know the size
+ of the source unless you know enough about, or wrote malloc. So
+ this code is disabled... */
+
+static lt_ptr
+realloc (ptr, size)
+ lt_ptr ptr;
+ size_t size;
+{
+ if (size == 0)
+ {
+ /* For zero or less bytes, free the original memory */
+ if (ptr != 0)
+ {
+ lt_dlfree (ptr);
+ }
+
+ return (lt_ptr) 0;
+ }
+ else if (ptr == 0)
+ {
+ /* Allow reallocation of a NULL pointer. */
+ return lt_dlmalloc (size);
+ }
+ else
+ {
+ /* Allocate a new block, copy and free the old block. */
+ lt_ptr mem = lt_dlmalloc (size);
+
+ if (mem)
+ {
+ memcpy (mem, ptr, size);
+ lt_dlfree (ptr);
+ }
+
+ /* Note that the contents of PTR are not damaged if there is
+ insufficient memory to realloc. */
+ return mem;
+ }
+}
+#endif
+
+
+#if ! HAVE_ARGZ_APPEND
+# define argz_append rpl_argz_append
+
+static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len,
+ const char *buf, size_t buf_len));
+
+static error_t
+argz_append (pargz, pargz_len, buf, buf_len)
+ char **pargz;
+ size_t *pargz_len;
+ const char *buf;
+ size_t buf_len;
+{
+ size_t argz_len;
+ char *argz;
+
+ assert (pargz);
+ assert (pargz_len);
+ assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len));
+
+ /* If nothing needs to be appended, no more work is required. */
+ if (buf_len == 0)
+ return 0;
+
+ /* Ensure there is enough room to append BUF_LEN. */
+ argz_len = *pargz_len + buf_len;
+ argz = LT_DLREALLOC (char, *pargz, argz_len);
+ if (!argz)
+ return ENOMEM;
+
+ /* 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_sep
+
+static error_t argz_create_sep LT_PARAMS((const char *str, int delim,
+ char **pargz, size_t *pargz_len));
+
+static error_t
+argz_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_insert
+
+static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len,
+ char *before, const char *entry));
+
+static error_t
+argz_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_next
+
+static 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_stringify
+
+static void argz_stringify LT_PARAMS((char *argz, size_t argz_len,
+ int sep));
+
+static void
+argz_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_EXT
+static const char shlib_ext[] = LTDL_SHLIB_EXT;
+#endif
+#ifdef LTDL_SYSSEARCHPATH
+static 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. */
+int
+lt_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;
+
+int
+lt_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;
+}
+
+int
+lt_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_ptr
+lt_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_ptr
+lt_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)
+#endif
+
+static lt_module
+sys_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 int
+sys_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_ptr
+sys_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:
+ * BIND_IMMEDIATE - Resolve symbol references when the library is loaded.
+ * BIND_DEFERRED - Delay code symbol resolution until actual reference.
+ *
+ * Optionally:
+ * BIND_FIRST - Place the library at the head of the symbol search
+ * order.
+ * BIND_NONFATAL - The default BIND_IMMEDIATE behavior is to treat all
+ * unsatisfied symbols as fatal. This flag allows
+ * binding of unsatisfied code symbols to be deferred
+ * until use.
+ * [Perl: For certain libraries, like DCE, deferred
+ * binding often causes run time problems. Adding
+ * BIND_NONFATAL to BIND_IMMEDIATE still allows
+ * unresolved references in situations like this.]
+ * BIND_NOSTART - Do not call the initializer for the shared library
+ * when the library is loaded, nor on a future call to
+ * shl_unload().
+ * BIND_VERBOSE - Print verbose messages concerning possible
+ * unsatisfied symbols.
+ *
+ * hp9000s700/hp9000s800:
+ * BIND_RESTRICTED - Restrict symbols visible by the library to those
+ * present at library load time.
+ * DYNAMIC_PATH - Allow the loader to dynamically search for the
+ * library specified by the path argument.
+ */
+
+#ifndef DYNAMIC_PATH
+# define DYNAMIC_PATH 0
+#endif
+#ifndef BIND_RESTRICTED
+# define BIND_RESTRICTED 0
+#endif
+
+#define LT_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH)
+
+static lt_module
+sys_shl_open (loader_data, filename)
+ lt_user_data loader_data;
+ const char *filename;
+{
+ static shl_t self = (shl_t) 0;
+ lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L);
+
+ /* Since searching for a symbol against a NULL module handle will also
+ look in everything else that was already loaded and exported with
+ the -E compiler flag, we always cache a handle saved before any
+ modules are loaded. */
+ if (!self)
+ {
+ lt_ptr address;
+ shl_findsym (&self, "main", TYPE_UNDEFINED, &address);
+ }
+
+ if (!filename)
+ {
+ module = self;
+ }
+ else
+ {
+ module = shl_load (filename, LT_BIND_FLAGS, 0L);
+
+ if (!module)
+ {
+ LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
+ }
+ }
+
+ r