]> git.ipfire.org Git - thirdparty/libtool.git/commitdiff
Backported the following patches from the development branch:
authorGary V. Vaughan <gary@gnu.org>
Sun, 2 Sep 2001 18:54:31 +0000 (18:54 +0000)
committerGary V. Vaughan <gary@gnu.org>
Sun, 2 Sep 2001 18:54:31 +0000 (18:54 +0000)
Based on a patch from Marius Vollmer <mvo@zagadka.ping.de>:
* NEWS: updated.
* ltdl.m4 (AC_LIB_LTDL): Check for unistd.h.
* libltdl/ltdl.c: Include unistd.h if it exists.
(LTDL_SEARCHPATH_VAR): Macro to prevent hardcoding
"LTDL_LIBRARY_PATH".
(LTDL_ARCHIVE_EXT): Macro to prevent hardcoding ".la".
(archive_ext): Have only one copy of ".la" in the readonly
segment of the compiled library.
(find_handle_callback): Don't bother trying to dlopen the file if
it doesn't exist.
(find_handle): Don't bother searching for files if no search_path
was supplied.
(file_not_found): A new function to determine whether the last
error was due to a file not found condition.
(try_dlopen): Renamed from lt_dlopen() and changed to have the
same footprint as tryall_dlopen.  This involved a minor rewrite of
much of the internals of this function.
(lt_dlopen): A new function wrapped arounf try_dlopen().
(lt_dlopenext): If a file already has a suitable extension, don't
bother adding additional extensions and trying to open those.
Tidy up the rest of the code to prevent continued searching with
an eventual FILE_NOT_FOUND when a genuine failure earlier in the
search process could be legitimately reported.

* libltdl/ltdl.c (argz_create_sep): Don't forget to include the
terminating '0' when counting argz_len.
(argz_create_sep): When canonicalizing argz, don't forget to copy
the terminating '0', incase canonicalization has shortened argz.
(argz_stringify): Don't covert the final '0' to a separator.

* libltdl/ltdl.c (lt_dlhandle_next): Now we can loop through all
loaded module handles as originally intended.

* libltdl/ltdl.c (lt_dlseterror): Oops.  This never worked
either, due to a pair of typos.  Now fixed.

* libltdl/ltdl.c (N_ELEMENTS):  Deleted.  How come nobody noticed
there was no way this could have ever worked?
(lt_dlcaller_set_data): Now that valid caller_ids must be
non-zero, allocate an addition entry in the caller_data vector and
use a zero valued key as the end marker.
(lt_dlcaller_get_data): Iterate up to the end marker in one pass.

* libltdl/ltdl.c (lt_dlcaller_register): Caller ids are allocated
starting from value `1', so that clients can use a value of zero
to indicate that libltdl has not yet initialised.

* libltdl/ltdl.c (find_file_callback): Fix a multiple free()
bug.
(tryall_dlopen_module): Remove some unused variables.

* libltdl/ltdl.c (lt_dlinsertsearchdir): Calculate the address
of the end of user_search_path correctly.

* libltdl/ltdl.c (rpl_argz_stringify): New fallback implementation.
* ltdl.m4 (AC_LTDL_FUNC_ARGZ):  Test for argz_stringify in libc.
* libltdl/ltdl.c (lt_argz_insertinorder): Renamed from
lt_argz_insert to make room for...
(lt_argz_insert): Wraps argz_insert with libltdl error handling.
(lt_dlpath_insertdir): Insert new path elements into an
argzized path.
(lt_dlinsertsearchdir): New function to insert new search
directories anywhere into user_search_path using the above.
(lt_dladdsearchdir): Rewritten to use lt_dlpath_insertdir.
* libltdl/ltdl.h (lt_dlinsertsearchdir): Prototype for export.
* doc/libtool.texi (Libltdl interface): Document it.

ChangeLog
NEWS
libltdl/ltdl.c
libltdl/ltdl.h
ltdl.m4

index 389d9eeb61b696c241d007d72e0846a01ed2774c..fb1012f5e5cfef091000a047dc7283e2e1fdc886 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,75 @@
+2001-09-02  Gary V. Vaughan  <gary@gnu.org>
+
+       Backported the following patches from the development branch:
+
+       Based on a patch from Marius Vollmer <mvo@zagadka.ping.de>:
+       * NEWS: updated.
+       * ltdl.m4 (AC_LIB_LTDL): Check for unistd.h.
+       * libltdl/ltdl.c: Include unistd.h if it exists.
+       (LTDL_SEARCHPATH_VAR): Macro to prevent hardcoding
+       "LTDL_LIBRARY_PATH".
+       (LTDL_ARCHIVE_EXT): Macro to prevent hardcoding ".la".
+       (archive_ext): Have only one copy of ".la" in the readonly
+       segment of the compiled library.
+       (find_handle_callback): Don't bother trying to dlopen the file if
+       it doesn't exist.
+       (find_handle): Don't bother searching for files if no search_path
+       was supplied.
+       (file_not_found): A new function to determine whether the last
+       error was due to a file not found condition.
+       (try_dlopen): Renamed from lt_dlopen() and changed to have the
+       same footprint as tryall_dlopen.  This involved a minor rewrite of
+       much of the internals of this function.
+       (lt_dlopen): A new function wrapped arounf try_dlopen().
+       (lt_dlopenext): If a file already has a suitable extension, don't
+       bother adding additional extensions and trying to open those.
+       Tidy up the rest of the code to prevent continued searching with
+       an eventual FILE_NOT_FOUND when a genuine failure earlier in the
+       search process could be legitimately reported.
+
+       * libltdl/ltdl.c (argz_create_sep): Don't forget to include the
+       terminating '\0' when counting argz_len.
+       (argz_create_sep): When canonicalizing argz, don't forget to copy
+       the terminating '\0', incase canonicalization has shortened argz.
+       (argz_stringify): Don't covert the final '\0' to a separator.
+
+       * libltdl/ltdl.c (lt_dlhandle_next): Now we can loop through all
+       loaded module handles as originally intended.
+
+       * libltdl/ltdl.c (lt_dlseterror): Oops.  This never worked
+       either, due to a pair of typos.  Now fixed.
+
+       * libltdl/ltdl.c (N_ELEMENTS):  Deleted.  How come nobody noticed
+       there was no way this could have ever worked?
+       (lt_dlcaller_set_data): Now that valid caller_ids must be
+       non-zero, allocate an addition entry in the caller_data vector and
+       use a zero valued key as the end marker.
+       (lt_dlcaller_get_data): Iterate up to the end marker in one pass.
+
+       * libltdl/ltdl.c (lt_dlcaller_register): Caller ids are allocated
+       starting from value `1', so that clients can use a value of zero
+       to indicate that libltdl has not yet initialised.
+
+       * libltdl/ltdl.c (find_file_callback): Fix a multiple free()
+       bug.
+       (tryall_dlopen_module): Remove some unused variables.
+
+       * libltdl/ltdl.c (lt_dlinsertsearchdir): Calculate the address
+       of the end of user_search_path correctly.
+
+       * libltdl/ltdl.c (rpl_argz_stringify): New fallback implementation.
+       * ltdl.m4 (AC_LTDL_FUNC_ARGZ):  Test for argz_stringify in libc.
+       * libltdl/ltdl.c (lt_argz_insertinorder): Renamed from
+       lt_argz_insert to make room for...
+       (lt_argz_insert): Wraps argz_insert with libltdl error handling.
+       (lt_dlpath_insertdir): Insert new path elements into an
+       argzized path.
+       (lt_dlinsertsearchdir): New function to insert new search
+       directories anywhere into user_search_path using the above.
+       (lt_dladdsearchdir): Rewritten to use lt_dlpath_insertdir.
+       * libltdl/ltdl.h (lt_dlinsertsearchdir): Prototype for export.
+       * doc/libtool.texi (Libltdl interface): Document it.
+
 2001-08-18  Brad  <brad@comstyle.com>
 
        * ltmain.in: Do not remove -lm from deplibs for OpenBSD.
diff --git a/NEWS b/NEWS
index 7b496e8142ec83bcc8a6b2a5f9dce9f5ebee7013..8854c6dce1ebeae1f75498c8485607a8a630be8f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 NEWS - list of user-visible changes between releases of GNU Libtool
 
 New in 1.4.1: 2001-??-??; CVS version 1.4.0a, Libtool team:
+* Better error messages from libltdl when loading fails.
 * Don't leave here-doc files behind.
 * Improved support for OpenBSD.
 * Libtool will build with autoconf-2.50 and higher.
index 03c0650e4c27ead5d4f99ac81de8261f7d112715..3de6b3ca8b3f10eaef4884f260b7e85e035d01b1 100644 (file)
@@ -29,6 +29,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 #  include <config.h>
 #endif
 
+#if HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
 #if HAVE_STDIO_H
 #  include <stdio.h>
 #endif
@@ -57,6 +61,34 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 #  include <memory.h>
 #endif
 
+#if HAVE_ERRNO_H
+#  include <errno.h>
+#endif
+
+#if HAVE_DIRENT_H
+#  include <dirent.h>
+#  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
+
+#if HAVE_ARGZ_H
+#  include <argz.h>
+#endif
+
+/* I have never seen a system without this:  */
+#include <assert.h>
+
 #include "ltdl.h"
 
 
@@ -85,6 +117,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 /* --- 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
@@ -100,241 +140,41 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 
 
 
-\f
-/* --- 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;
-
-
-
-\f
-/* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */
-
-
-/* Extract the diagnostic strings from the error table macro in the same
-   order as the enumberated 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;
-#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
-
-
-
-\f
-/* --- 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 MUTEX_LOCK()                           LT_STMT_START { \
-       if (mutex_lock) (*mutex_lock)();        } LT_STMT_END
-#define MUTEX_UNLOCK()                         LT_STMT_START { \
-       if (mutex_unlock) (*mutex_unlock)();    } LT_STMT_END
-#define MUTEX_SETERROR(errormsg)               LT_STMT_START { \
-       if (mutex_seterror) (*mutex_seterror) (errormsg);       \
-       else last_error = (errormsg);           } LT_STMT_END
-#define MUTEX_GETERROR(errormsg)               LT_STMT_START { \
-       if (mutex_seterror) errormsg = (*mutex_geterror)();     \
-       else (errormsg) = last_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     *mutex_lock     = 0;
-static lt_dlmutex_unlock   *mutex_unlock   = 0;
-static lt_dlmutex_seterror *mutex_seterror = 0;
-static lt_dlmutex_geterror *mutex_geterror = 0;
-static const char          *last_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.  */
-  MUTEX_LOCK ();
-
-  if ((lock && unlock && seterror && geterror) 
-      || !(lock || unlock || seterror || geterror))
-    {
-      mutex_lock     = lock;
-      mutex_unlock   = unlock;
-      mutex_geterror = geterror;
-    }
-  else
-    {
-      MUTEX_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;
-}
-
-
-
 \f
 /* --- MEMORY HANDLING --- */
 
 
-LT_GLOBAL_DATA    lt_ptr       (*lt_dlmalloc)  LT_PARAMS((size_t size))
-                                   = (lt_ptr (*) LT_PARAMS((size_t))) malloc;
-LT_GLOBAL_DATA    void         (*lt_dlfree)    LT_PARAMS((lt_ptr ptr))
-                                   = (void (*) LT_PARAMS((lt_ptr))) free;
+/* 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));
 
-static           lt_ptr        rpl_realloc     LT_PARAMS((lt_ptr ptr,
-                                                          size_t size));
+/* 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.  */
 #define LT_DLMALLOC(tp, n)     ((tp *) lt_dlmalloc ((n) * sizeof(tp)))
 #define LT_DLREALLOC(tp, p, n) ((tp *) rpl_realloc ((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)))
+
 #define LT_DLMEM_REASSIGN(p, q)                        LT_STMT_START { \
-       if ((p) != (q)) { lt_dlfree (p); (p) = (q); }           \
+       if ((p) != (q)) { lt_dlfree (p); (p) = (q); (q) = 0; }  \
                                                } LT_STMT_END
 
-
-\f
-/* --- ERROR MESSAGES --- */
-
-
-static const char    **user_error_strings      = 0;
-static int             errorcount              = LT_ERROR_MAX;
-
-int
-lt_dladderror (diagnostic)
-     const char *diagnostic;
-{
-  int          index    = 0;
-  int          result   = -1;
-  const char  **temp     = (const char **) 0;
-
-  MUTEX_LOCK ();
-
-  index         = errorcount - LT_ERROR_MAX;
-  temp = LT_DLREALLOC (const char *, user_error_strings, 1 + index);
-  if (temp == 0)
-    {
-      MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-    }
-  else
-    {
-      user_error_strings       = temp;
-      user_error_strings[index] = diagnostic;
-      result                   = errorcount++;
-    }
-
-  MUTEX_UNLOCK ();
-
-  return result;
-}
-
-int
-lt_dlseterror (index)
-     int index;
-{
-  int          errors   = 0;
-
-  MUTEX_LOCK ();
-
-  if (index >= errorcount || index < 0)
-    {
-      /* Ack!  Error setting the error message! */
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE));
-      ++errors;
-    }
-  else if (index < LT_ERROR_MAX)
-    {
-      /* No error setting the error message! */
-      MUTEX_SETERROR (lt_dlerror_strings[errorcount]);
-    }
-  else
-    {
-      /* No error setting the error message! */
-      MUTEX_SETERROR (user_error_strings[errorcount - LT_ERROR_MAX]);
-    }
-
-  MUTEX_UNLOCK ();
-
-  return errors;
-}
-
-
-
 \f
 /* --- REPLACEMENT FUNCTIONS --- */
 
@@ -342,7 +182,9 @@ lt_dlseterror (index)
 #undef strdup
 #define strdup rpl_strdup
 
-static char *
+static char *strdup LT_PARAMS((const char *str));
+
+char *
 strdup(str)
      const char *str;
 {
@@ -366,7 +208,9 @@ strdup(str)
 #undef strcmp
 #define strcmp rpl_strcmp
 
-static int
+static int strcmp LT_PARAMS((const char *str1, const char *str2));
+
+int
 strcmp (str1, str2)
      const char *str1;
      const char *str2;
@@ -396,14 +240,16 @@ strcmp (str1, str2)
 #  else
 #    define strchr rpl_strchr
 
-static const char*
+static const char *strchr LT_PARAMS((const char *str, int ch));
+
+const char*
 strchr(str, ch)
      const char *str;
      int ch;
 {
   const char *p;
 
-  for (p = str; *p != (char)ch && *p != '\0'; ++p)
+  for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p)
     /*NOWORK*/;
 
   return (*p == (char)ch) ? p : 0;
@@ -412,6 +258,7 @@ strchr(str, ch)
 #  endif
 #endif /* !HAVE_STRCHR */
 
+
 #if ! HAVE_STRRCHR
 
 #  if HAVE_RINDEX
@@ -419,14 +266,16 @@ strchr(str, ch)
 #  else
 #    define strrchr rpl_strrchr
 
-static const char*
+static const char *strrchr LT_PARAMS((const char *str, int ch));
+
+const char*
 strrchr(str, ch)
      const char *str;
      int ch;
 {
   const char *p, *q = 0;
 
-  for (p = str; *p != '\0'; ++p)
+  for (p = str; *p != LT_EOS_CHAR; ++p)
     {
       if (*p == (char) ch)
        {
@@ -441,8 +290,9 @@ strrchr(str, ch)
 #endif
 
 /* NOTE:  Neither bcopy nor the memcpy implementation below can
-          reliably handle copying in overlapping areas of memory, so
-          do not rely on this behaviour when invoking memcpy later.  */
+          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
@@ -450,10 +300,12 @@ strrchr(str, ch)
 #  else
 #    define memcpy rpl_memcpy
 
-static char *
+static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
+
+lt_ptr
 memcpy (dest, src, size)
-     char *dest;
-     const char *src;
+     lt_ptr dest;
+     const lt_ptr src;
      size_t size;
 {
   size_t i = 0;
@@ -466,8 +318,38 @@ memcpy (dest, src, size)
   return dest;
 }
 
-#  endif
-#endif
+#  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));
+
+lt_ptr
+memmove (dest, src, size)
+     lt_ptr dest;
+     const lt_ptr src;
+     size_t size;
+{
+  size_t i;
+
+  if (dest < src)
+    for (i = 0; i < size; ++i)
+      {
+       dest[i] = src[i];
+      }
+  else if (dest > src)
+    for (i = size -1; i >= 0; --i)
+      {
+       dest[i] = src[i];
+      }
+
+  return dest;
+}
+
+#endif /* !HAVE_MEMMOVE */
+
 
 /* According to Alexandre Oliva <oliva@lsd.ic.unicamp.br>,
     ``realloc is not entirely portable''
@@ -475,12 +357,16 @@ memcpy (dest, src, size)
    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. */
-static lt_ptr
-rpl_realloc (ptr, size)
+
+#undef realloc
+#define realloc rpl_realloc
+
+lt_ptr
+realloc (ptr, size)
      lt_ptr ptr;
      size_t size;
 {
-  if (size < 1)
+  if (size <= 0)
     {
       /* For zero or less bytes, free the original memory */
       if (ptr != 0)
@@ -506,10 +392,496 @@ rpl_realloc (ptr, size)
          lt_dlfree (ptr);
        }
 
-      /* Note that the contents of PTR are not damaged if there is
-        insufficient memory to realloc.  */
-      return mem;
-    }
+      /* Note that the contents of PTR are not damaged if there is
+        insufficient memory to realloc.  */
+      return mem;
+    }
+}
+
+
+#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));
+
+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));
+
+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));
+
+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);
+
+  /* Either PARGZ/PARGZ_LEN is empty and BEFORE is NULL,
+     or BEFORE points into an address within the ARGZ vector.  */
+  assert ((!*pargz && !*pargz_len && !before)
+         || ((*pargz <= before) && (before < (*pargz + *pargz_len))));
+
+  /* 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));
+
+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));
+
+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 */
+
+
+
+\f
+/* --- 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;
+
+
+
+\f
+/* --- 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
+
+
+
+\f
+/* --- 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;
+}
+
+
+
+\f
+/* --- 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;
+}
+
+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;
+}
+
+lt_ptr
+lt_erealloc (addr, size)
+     lt_ptr addr;
+     size_t size;
+{
+  lt_ptr mem = realloc (addr, size);
+  if (size && !mem)
+    LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
+  return mem;
+}
+
+char *
+lt_estrdup (str)
+     const char *str;
+{
+  char *dup = strdup (str);
+  if (LT_STRLEN (str) && !dup)
+    LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
+  return dup;
 }
 
 
@@ -584,7 +956,7 @@ sys_dl_open (loader_data, filename)
 
   if (!module)
     {
-      MUTEX_SETERROR (DLERROR (CANNOT_OPEN));
+      LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN));
     }
 
   return module;
@@ -599,7 +971,7 @@ sys_dl_close (loader_data, module)
 
   if (dlclose (module) != 0)
     {
-      MUTEX_SETERROR (DLERROR (CANNOT_CLOSE));
+      LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE));
       ++errors;
     }
 
@@ -616,7 +988,7 @@ sys_dl_sym (loader_data, module, symbol)
 
   if (!address)
     {
-      MUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND));
+      LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND));
     }
 
   return address;
@@ -693,9 +1065,9 @@ sys_shl_open (loader_data, 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 
+     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)
@@ -703,7 +1075,7 @@ sys_shl_open (loader_data, filename)
       lt_ptr address;
       shl_findsym (&self, "main", TYPE_UNDEFINED, &address);
     }
-  
+
   if (!filename)
     {
       module = self;
@@ -714,10 +1086,10 @@ sys_shl_open (loader_data, filename)
 
       if (!module)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
        }
     }
-  
+
   return module;
 }
 
@@ -730,7 +1102,7 @@ sys_shl_close (loader_data, module)
 
   if (module && (shl_unload ((shl_t) (module)) != 0))
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
       ++errors;
     }
 
@@ -748,16 +1120,16 @@ sys_shl_sym (loader_data, module, symbol)
   /* sys_shl_open should never return a NULL module handle */
   if (module == (lt_module) 0)
   {
-    MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
+    LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
   }
   else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address))
     {
       if (!address)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
        }
     }
-  
+
   return address;
 }
 
@@ -808,21 +1180,18 @@ sys_wll_open (loader_data, filename)
   if (ext)
     {
       /* FILENAME already has an extension. */
-      searchname = strdup (filename);
+      searchname = lt_estrdup (filename);
     }
   else
     {
       /* Append a `.' to stop Windows from adding an
         implicit `.dll' extension. */
-      searchname = LT_DLMALLOC (char, 2+ strlen (filename));
-      if (!searchname)
-       {
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-         return 0;
-       }
-      strcpy (searchname, filename);
-      strcat (searchname, ".");
+      searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename));
+      if (searchname)
+       sprintf (searchname, "%s.", filename);
     }
+  if (!searchname)
+    return 0;
 
 #if __CYGWIN__
   {
@@ -843,7 +1212,7 @@ sys_wll_open (loader_data, filename)
      We check whether LoadLibrary is returning a handle to
      an already loaded module, and simulate failure if we
      find one. */
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   cur = handles;
   while (cur)
     {
@@ -860,11 +1229,11 @@ sys_wll_open (loader_data, filename)
 
       cur = cur->next;
   }
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   if (cur || !module)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
       module = 0;
     }
 
@@ -880,7 +1249,7 @@ sys_wll_close (loader_data, module)
 
   if (FreeLibrary(module) == 0)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
       ++errors;
     }
 
@@ -897,7 +1266,7 @@ sys_wll_sym (loader_data, module, symbol)
 
   if (!address)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
     }
 
   return address;
@@ -942,7 +1311,7 @@ sys_bedl_open (loader_data, filename)
 
   if (image <= 0)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
       image = 0;
     }
 
@@ -958,7 +1327,7 @@ sys_bedl_close (loader_data, module)
 
   if (unload_add_on ((image_id) module) != B_OK)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
       ++errors;
     }
 
@@ -976,7 +1345,7 @@ sys_bedl_sym (loader_data, module, symbol)
 
   if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
       address = 0;
     }
 
@@ -1010,14 +1379,9 @@ sys_dld_open (loader_data, filename)
 {
   lt_module module = strdup (filename);
 
-  if (!module)
-    {
-      MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-      module = 0;
-    }
-  else if (dld_link (filename) != 0)
+  if (dld_link (filename) != 0)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
       LT_DLFREE (module);
       module = 0;
     }
@@ -1034,7 +1398,7 @@ sys_dld_close (loader_data, module)
 
   if (dld_unlink_by_file ((char*)(module), 1) != 0)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
       ++errors;
     }
   else
@@ -1055,7 +1419,7 @@ sys_dld_sym (loader_data, module, symbol)
 
   if (!address)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
     }
 
   return address;
@@ -1090,7 +1454,7 @@ presym_init (loader_data)
 {
   int errors = 0;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
 
   preloaded_symbols = 0;
   if (default_preloaded_symbols)
@@ -1098,7 +1462,7 @@ presym_init (loader_data)
       errors = lt_dlpreload (default_preloaded_symbols);
     }
 
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return errors;
 }
@@ -1108,7 +1472,7 @@ presym_free_symlists ()
 {
   lt_dlsymlists_t *lists;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
 
   lists = preloaded_symbols;
   while (lists)
@@ -1120,7 +1484,7 @@ presym_free_symlists ()
     }
   preloaded_symbols = 0;
 
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return 0;
 }
@@ -1141,7 +1505,7 @@ presym_add_symlist (preloaded)
   lt_dlsymlists_t *lists;
   int             errors   = 0;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
 
   lists = preloaded_symbols;
   while (lists)
@@ -1153,22 +1517,21 @@ presym_add_symlist (preloaded)
       lists = lists->next;
     }
 
-  tmp = LT_DLMALLOC (lt_dlsymlists_t, 1);
+  tmp = LT_EMALLOC (lt_dlsymlists_t, 1);
   if (tmp)
     {
-      memset (tmp, 0, 1*sizeof(lt_dlsymlists_t));
+      memset (tmp, 0, sizeof(lt_dlsymlists_t));
       tmp->syms = preloaded;
       tmp->next = preloaded_symbols;
       preloaded_symbols = tmp;
     }
   else
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
       ++errors;
     }
 
  done:
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
   return errors;
 }
 
@@ -1180,15 +1543,19 @@ presym_open (loader_data, filename)
   lt_dlsymlists_t *lists;
   lt_module       module = (lt_module) 0;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   lists = preloaded_symbols;
 
   if (!lists)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS));
       goto done;
     }
 
+  /* Can't use NULL as the reflective symbol header, as NULL is
+     used to mark the end of the entire symbol list.  Self-dlpreopened
+     symbols follow this magic number, chosen to be an unlikely
+     clash with a real module name.  */
   if (!filename)
     {
       filename = "@PROGRAM@";
@@ -1211,10 +1578,10 @@ presym_open (loader_data, filename)
       lists = lists->next;
     }
 
-  MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
+  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
 
  done:
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
   return module;
 }
 
@@ -1247,7 +1614,7 @@ presym_sym (loader_data, module, symbol)
     ++syms;
   }
 
-  MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
+  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
 
   return 0;
 }
@@ -1263,6 +1630,62 @@ static struct lt_user_dlloader presym = {
 /* --- DYNAMIC MODULE LOADING --- */
 
 
+/* The type of a function used at each iteration of  foreach_dirinpath().  */
+typedef int    foreach_callback_func LT_PARAMS((char *filename, lt_ptr data1,
+                                                lt_ptr data2));
+
+static int     foreach_dirinpath     LT_PARAMS((const char *search_path,
+                                                const char *base_name,
+                                                foreach_callback_func *func,
+                                                lt_ptr data1, lt_ptr data2));
+
+static int     find_file_callback    LT_PARAMS((char *filename, lt_ptr data,
+                                                lt_ptr ignored));
+static int     find_handle_callback  LT_PARAMS((char *filename, lt_ptr data,
+                                                lt_ptr ignored));
+static int     foreachfile_callback  LT_PARAMS((char *filename, lt_ptr data1,
+                                                lt_ptr data2));
+
+
+static int     canonicalize_path     LT_PARAMS((const char *path,
+                                                char **pcanonical));
+static int     argzize_path          LT_PARAMS((const char *path,
+                                                char **pargz,
+                                                size_t *pargz_len));
+static FILE   *find_file             LT_PARAMS((const char *search_path,
+                                                const char *base_name,
+                                                char **pdir));
+static lt_dlhandle *find_handle      LT_PARAMS((const char *search_path,
+                                                const char *base_name,
+                                                lt_dlhandle *handle));
+static int     find_module           LT_PARAMS((lt_dlhandle *handle,
+                                                const char *dir,
+                                                const char *libdir,
+                                                const char *dlname,
+                                                const char *old_name,
+                                                int installed));
+static int     free_vars             LT_PARAMS((char *dlname, char *oldname,
+                                                char *libdir, char *deplibs));
+static int     load_deplibs          LT_PARAMS((lt_dlhandle handle,
+                                                char *deplibs));
+static int     trim                  LT_PARAMS((char **dest,
+                                                const char *str));
+static int     try_dlopen            LT_PARAMS((lt_dlhandle *handle,
+                                                const char *filename));
+static int     tryall_dlopen         LT_PARAMS((lt_dlhandle *handle,
+                                                const char *filename));
+static int     unload_deplibs        LT_PARAMS((lt_dlhandle handle));
+static int     lt_argz_insert        LT_PARAMS((char **pargz,
+                                                size_t *pargz_len,
+                                                char *before,
+                                                const char *entry));
+static int     lt_argz_insertinorder LT_PARAMS((char **pargz,
+                                                size_t *pargz_len,
+                                                const char *entry));
+static int     lt_dlpath_insertdir   LT_PARAMS((char **ppath,
+                                                char *before,
+                                                const char *dir));
+
 static char           *user_search_path= 0;
 static lt_dlloader    *loaders         = 0;
 static lt_dlhandle     handles         = 0;
@@ -1274,7 +1697,7 @@ lt_dlinit ()
 {
   int        errors   = 0;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
 
   /* Initialize only at first call. */
   if (++initialized == 1)
@@ -1301,17 +1724,17 @@ lt_dlinit ()
 
       if (presym_init (presym.dlloader_data))
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER));
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER));
          ++errors;
        }
       else if (errors != 0)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED));
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED));
          ++errors;
        }
     }
 
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return errors;
 }
@@ -1328,16 +1751,14 @@ lt_dlpreload (preloaded)
     }
   else
     {
-      const char *errormsg = 0;
-
       presym_free_symlists();
-  
-      MUTEX_LOCK ();
+
+      LT_DLMUTEX_LOCK ();
       if (default_preloaded_symbols)
        {
          errors = lt_dlpreload (default_preloaded_symbols);
        }
-      MUTEX_UNLOCK ();
+      LT_DLMUTEX_UNLOCK ();
     }
 
   return errors;
@@ -1347,9 +1768,9 @@ int
 lt_dlpreload_default (preloaded)
      const lt_dlsymlist *preloaded;
 {
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   default_preloaded_symbols = preloaded;
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
   return 0;
 }
 
@@ -1358,15 +1779,14 @@ lt_dlexit ()
 {
   /* shut down libltdl */
   lt_dlloader *loader;
-  const char  *errormsg;
   int         errors   = 0;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   loader = loaders;
 
   if (!initialized)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN));
       ++errors;
       goto done;
     }
@@ -1422,7 +1842,7 @@ lt_dlexit ()
     }
 
  done:
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
   return errors;
 }
 
@@ -1436,8 +1856,8 @@ tryall_dlopen (handle, filename)
   const char   *saved_error;
   int           errors         = 0;
 
-  MUTEX_GETERROR (saved_error);
-  MUTEX_LOCK ();
+  LT_DLMUTEX_GETERROR (saved_error);
+  LT_DLMUTEX_LOCK ();
 
   cur   = handles;
   loader = loaders;
@@ -1470,10 +1890,9 @@ tryall_dlopen (handle, filename)
   cur = *handle;
   if (filename)
     {
-      cur->info.filename = strdup (filename);
+      cur->info.filename = lt_estrdup (filename);
       if (!cur->info.filename)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
          ++errors;
          goto done;
        }
@@ -1504,14 +1923,63 @@ tryall_dlopen (handle, filename)
     }
 
   cur->loader  = loader;
-  last_error   = saved_error;
-  
+  LT_DLMUTEX_SETERROR (saved_error);
+
  done:
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return errors;
 }
 
+static int
+tryall_dlopen_module (handle, prefix, dirname, dlname)
+     lt_dlhandle *handle;
+     const char *prefix;
+     const char *dirname;
+     const char *dlname;
+{
+  int      error       = 0;
+  char     *filename   = 0;
+  size_t   filename_len        = 0;
+  size_t   dirname_len = LT_STRLEN (dirname);
+
+  assert (handle);
+  assert (dirname);
+  assert (dlname);
+#ifdef LT_DIRSEP_CHAR
+  /* Only canonicalized names (i.e. with DIRSEP chars already converted)
+     should make it into this function:  */
+  assert (strchr (dirname, LT_DIRSEP_CHAR) == 0);
+#endif
+
+  if (dirname[dirname_len -1] == '/')
+    --dirname_len;
+  filename_len = dirname_len + 1 + LT_STRLEN (dlname);
+
+  /* Allocate memory, and combine DIRNAME and MODULENAME into it.
+     The PREFIX (if any) is handled below.  */
+  filename  = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1);
+  if (!filename)
+    return 1;
+
+  sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname);
+
+  /* Now that we have combined DIRNAME and MODULENAME, if there is
+     also a PREFIX to contend with, simply recurse with the arguments
+     shuffled.  Otherwise, attempt to open FILENAME as a module.  */
+  if (prefix)
+    {
+      tryall_dlopen_module (handle, 0, prefix, filename);
+    }
+  else if (tryall_dlopen (handle, filename) != 0)
+    {
+      ++error;
+    }
+
+  LT_DLFREE (filename);
+  return error;
+}
+
 static int
 find_module (handle, dir, libdir, dlname, old_name, installed)
      lt_dlhandle *handle;
@@ -1521,252 +1989,300 @@ find_module (handle, dir, libdir, dlname, old_name, installed)
      const char *old_name;
      int installed;
 {
-  int  error;
-  char *filename;
-
-  /* try to open the old library first; if it was dlpreopened,
+  /* Try to open the old library first; if it was dlpreopened,
      we want the preopened version of it, even if a dlopenable
-     module is available */
-  if (old_name && tryall_dlopen(handle, old_name) == 0)
+     module is available */
+  if (old_name && tryall_dlopen (handle, old_name) == 0)
     {
       return 0;
     }
 
-  /* try to open the dynamic library */
+  /* Try to open the dynamic library.  */
   if (dlname)
     {
-      size_t len;
-
       /* try to open the installed module */
       if (installed && libdir)
        {
-         len       = strlen (libdir) + 1 + strlen (dlname);
-         filename  = LT_DLMALLOC (char, 1+ len);
-
-         if (!filename)
-           {
-             MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-             return 1;
-           }
-
-         sprintf (filename, "%s/%s", libdir, dlname);
-         error = (tryall_dlopen (handle, filename) != 0);
-         LT_DLFREE (filename);
-
-         if (!error)
-           {
-             return 0;
-           }
+         if (tryall_dlopen_module (handle, 0, libdir, dlname) == 0)
+           return 0;
        }
 
       /* try to open the not-installed module */
       if (!installed)
        {
-         len = (dir ? strlen (dir) : 0) + strlen (objdir) + strlen (dlname);
-         filename = LT_DLMALLOC (char, 1+ len);
-
-         if (!filename)
-           {
-             MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-             return 1;
-           }
-
-         if (dir)
-           {
-             strcpy (filename, dir);
-           }
-         else
-           {
-             *filename = 0;
-           }
-         strcat(filename, objdir);
-         strcat(filename, dlname);
-
-         error = tryall_dlopen (handle, filename) != 0;
-         LT_DLFREE (filename);
-         if (!error)
-           {
-             return 0;
-           }
+         if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0)
+           return 0;
        }
 
       /* maybe it was moved to another directory */
       {
-       len      = (dir ? strlen (dir) : 0) + strlen (dlname);
-       filename = LT_DLMALLOC (char, 1+ len);
+         if (tryall_dlopen_module (handle, 0, dir, dlname) == 0)
+           return 0;
+      }
+    }
+
+  return 1;
+}
+
+
+static int
+canonicalize_path (path, pcanonical)
+     const char *path;
+     char **pcanonical;
+{
+  char *canonical = 0;
+
+  assert (path && *path);
+  assert (pcanonical);
 
-       if (dir)
+  canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path));
+  if (!canonical)
+    return 1;
+
+  {
+    size_t dest = 0;
+    size_t src;
+    for (src = 0; path[src] != LT_EOS_CHAR; ++src)
+      {
+       /* Path separators are not copied to the beginning or end of
+          the destination, or if another separator would follow
+          immediately.  */
+       if (path[src] == LT_PATHSEP_CHAR)
          {
-           strcpy (filename, dir);
+           if ((dest == 0)
+               || (path[1+ src] == LT_PATHSEP_CHAR)
+               || (path[1+ src] == LT_EOS_CHAR))
+             continue;
          }
-       else
+
+       /* Anything other than a directory separator is copied verbatim.  */
+       if ((path[src] != '/')
+#ifdef LT_DIRSEP_CHAR
+           && (path[src] != LT_DIRSEP_CHAR)
+#endif
+           )
          {
-           *filename = 0;
+           canonical[dest++] = path[src];
          }
-       strcat(filename, dlname);
-
-       error = (tryall_dlopen (handle, filename) != 0);
-       LT_DLFREE (filename);
-       if (!error)
+       /* Directory separators are converted and copied only if they are
+          not at the end of a path -- i.e. before a path separator or
+          NULL terminator.  */
+       else if ((path[1+ src] != LT_PATHSEP_CHAR)
+                && (path[1+ src] != LT_EOS_CHAR)
+#ifdef LT_DIRSEP_CHAR
+                && (path[1+ src] != LT_DIRSEP_CHAR)
+#endif
+                && (path[1+ src] != '/'))
          {
-           return 0;
+           canonical[dest++] = '/';
          }
       }
-    }
 
-  return 1;
+    /* Add an end-of-string marker at the end.  */
+    canonical[dest] = LT_EOS_CHAR;
+  }
+
+  /* Assign new value.  */
+  *pcanonical = canonical;
+
+  return 0;
 }
 
-static char*
-canonicalize_path (path)
+static int
+argzize_path (path, pargz, pargz_len)
      const char *path;
+     char **pargz;
+     size_t *pargz_len;
 {
-  char *canonical = 0;
+  error_t error;
 
-  if (path && *path)
-    {
-      char *ptr = strdup (path);
-      canonical = ptr;
+  assert (path);
+  assert (pargz);
+  assert (pargz_len);
 
-#ifdef LT_DIRSEP_CHAR
-      /* Avoid this overhead where '/' is the only separator. */
-      while (ptr = strchr (ptr, LT_DIRSEP_CHAR))
+  if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len)))
+    {
+      switch (error)
        {
-         *ptr++ = '/';
+       case ENOMEM:
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
+         break;
+       default:
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
+         break;
        }
-#endif
+
+      return 1;
     }
 
-  return canonical;
+  return 0;
 }
 
-static lt_ptr
-find_file (basename, search_path, pdir, handle)
-     const char *basename;
+/* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element
+   of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns
+   non-zero or all elements are exhausted.  If BASE_NAME is non-NULL,
+   it is appended to each SEARCH_PATH element before FUNC is called.  */
+static int
+foreach_dirinpath (search_path, base_name, func, data1, data2)
      const char *search_path;
-     char **pdir;
-     lt_dlhandle *handle;
+     const char *base_name;
+     foreach_callback_func *func;
+     lt_ptr data1;
+     lt_ptr data2;
 {
-  /* When handle != NULL search a library, otherwise a file
-     return NULL on failure, otherwise the file/handle.  */
+  int  result          = 0;
+  int  filenamesize    = 0;
+  int  lenbase         = LT_STRLEN (base_name);
+  int  argz_len        = 0;
+  char *argz           = 0;
+  char *filename       = 0;
+  char *canonical      = 0;
 
-  lt_ptr    result     = 0;
-  char    *filename    = 0;
-  int      filenamesize= 0;
-  int      lenbase     = strlen (basename);
-  char    *canonical   = 0;
-  char    *next        = 0;
-
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
 
   if (!search_path || !*search_path)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
       goto cleanup;
     }
 
-  canonical = canonicalize_path (search_path);
-  if (!canonical)
-    {
-      MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-      goto cleanup;
-    }
+  if (canonicalize_path (search_path, &canonical) != 0)
+    goto cleanup;
 
-  next = canonical;
-  while (next)
-    {
-      int lendir;
-      char *cur = next;
+  if (argzize_path (canonical, &argz, &argz_len) != 0)
+    goto cleanup;
 
-      next = strchr (cur, LT_PATHSEP_CHAR);
-      if (!next)
-       {
-         next = cur + strlen (cur);
-       }
+  {
+    char *dir_name = 0;
+    while ((dir_name = argz_next (argz, argz_len, dir_name)))
+      {
+       int lendir = LT_STRLEN (dir_name);
 
-      lendir = next - cur;
-      if (*next == LT_PATHSEP_CHAR)
+       if (lendir +1 +lenbase >= filenamesize)
        {
-         ++next;
-       }
-      else
-       {
-         next = 0;
+         LT_DLFREE (filename);
+         filenamesize  = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */
+         filename      = LT_EMALLOC (char, filenamesize);
+         if (!filename)
+           goto cleanup;
        }
 
-      if (lendir == 0)
-       {
-         continue;
-       }
+       strncpy (filename, dir_name, lendir);
+       if (base_name && *base_name)
+         {
+           if (filename[lendir -1] != '/')
+             filename[lendir++] = '/';
+           strcpy (filename +lendir, base_name);
+         }
 
-      if (lendir + 1 + lenbase >= filenamesize)
-       {
-         LT_DLFREE (filename);
-         filenamesize = lendir + 1 + lenbase + 1;
-         filename = LT_DLMALLOC (char, filenamesize);
+       if ((result = (*func) (filename, data1, data2)))
+         {
+           break;
+         }
+      }
+  }
 
-         if (!filename)
-           {
-             MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-             goto cleanup;
-           }
-       }
+ cleanup:
+  LT_DLFREE (argz);
+  LT_DLFREE (canonical);
+  LT_DLFREE (filename);
 
-      strncpy(filename, cur, lendir);
-      if (filename[lendir-1] != '/')
-       {
-         filename[lendir++] = '/';
-       }
-      strcpy(filename+lendir, basename);
-      if (handle)
-       {
-         if (tryall_dlopen (handle, filename) == 0)
-           {
-             result = (lt_ptr) handle;
-             goto cleanup;
-           }
-       }
-      else
-       {
-         FILE *file = fopen (filename, LT_READTEXT_MODE);
-         if (file)
-           {
-             LT_DLFREE (*pdir);
+  LT_DLMUTEX_UNLOCK ();
 
-             filename[lendir] = '\0';
-             *pdir = strdup(filename);
-             if (!*pdir)
-               {
-                 /* We could have even avoided the strdup,
-                    but there would be some memory overhead. */
-                 *pdir = filename;
-                 filename = 0;
-               }
+  return result;
+}
 
-             result = (lt_ptr) file;
-             goto cleanup;
-           }
-       }
+/* If FILEPATH can be opened, store the name of the directory component
+   in DATA1, and the opened FILE* structure address in DATA2.  Otherwise
+   DATA1 is unchanged, but DATA2 is set to a pointer to NULL.  */
+static int
+find_file_callback (filename, data1, data2)
+     char *filename;
+     lt_ptr data1;
+     lt_ptr data2;
+{
+  char      **pdir     = (char **) data1;
+  FILE      **pfile    = (FILE **) data2;
+  int       is_done    = 0;
+
+  assert (filename && *filename);
+  assert (pdir);
+  assert (pfile);
+
+  if ((*pfile = fopen (filename, LT_READTEXT_MODE)))
+    {
+      char *dirend = strrchr (filename, '/');
+
+      if (dirend > filename)
+       *dirend   = LT_EOS_CHAR;
+
+      LT_DLFREE (*pdir);
+      *pdir   = lt_estrdup (filename);
+      is_done = (*pdir == 0) ? -1 : 1;
     }
 
-  MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
+  return is_done;
+}
 
- cleanup:
-  LT_DLFREE (filename);
-  LT_DLFREE (canonical);
+static FILE *
+find_file (search_path, base_name, pdir)
+     const char *search_path;
+     const char *base_name;
+     char **pdir;
+{
+  FILE *file = 0;
 
-  MUTEX_UNLOCK ();
+  foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file);
 
-  return result;
+  return file;
+}
+
+static int
+find_handle_callback (filename, data, ignored)
+     char *filename;
+     lt_ptr data;
+     lt_ptr ignored;
+{
+  lt_dlhandle  *handle = (lt_dlhandle *) data;
+  int          found   = access (filename, R_OK);
+
+  /* Bail out if file cannot be read...  */
+  if (!found)
+    return 0;
+
+  /* Try to dlopen the file, but do not continue searching in any
+     case.  */
+  if (tryall_dlopen (handle, filename) != 0)
+    *handle = 0;
+
+  return 1;
+}
+
+/* If HANDLE was found return it, otherwise return 0.  If HANDLE was
+   found but could not be opened, *HANDLE will be set to 0.  */
+static lt_dlhandle *
+find_handle (search_path, base_name, handle)
+     const char *search_path;
+     const char *base_name;
+     lt_dlhandle *handle;
+{
+  if (!search_path)
+    return 0;
+
+  if (!foreach_dirinpath (search_path, base_name, find_handle_callback,
+                         handle, 0))
+    return 0;
+
+  return handle;
 }
 
 static int
-load_deplibs(handle, deplibs)
+load_deplibs (handle, deplibs)
      lt_dlhandle handle;
      char *deplibs;
 {
 #if LTDL_DLOPEN_DEPLIBS
-  char *p, *save_search_path;
+  char *p, *save_search_path = 0;
   int   depcount = 0;
   int  i;
   char **names = 0;
@@ -1782,12 +2298,12 @@ load_deplibs(handle, deplibs)
     }
   ++errors;
 
-  MUTEX_LOCK ();
-  save_search_path = strdup (user_search_path);
-  if (user_search_path && !save_search_path)
+  LT_DLMUTEX_LOCK ();
+  if (user_search_path)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-      goto cleanup;
+      save_search_path = lt_estrdup (user_search_path);
+      if (!save_search_path)
+       goto cleanup;
     }
 
   /* extract search paths and count deplibs */
@@ -1829,7 +2345,7 @@ load_deplibs(handle, deplibs)
   LT_DLFREE (user_search_path);
   user_search_path = save_search_path;
 
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   if (!depcount)
     {
@@ -1837,11 +2353,9 @@ load_deplibs(handle, deplibs)
       goto cleanup;
     }
 
-  names = LT_DLMALLOC (char *, depcount * sizeof (char*));
+  names = LT_EMALLOC (char *, depcount * sizeof (char*));
   if (!names)
-    {
-      goto cleanup;
-    }
+    goto cleanup;
 
   /* now only extract the actual deplibs */
   depcount = 0;
@@ -1867,25 +2381,18 @@ load_deplibs(handle, deplibs)
              *end = 0; /* set a temporary string terminator */
              if (strncmp(p, "-l", 2) == 0)
                {
-                 name = LT_DLMALLOC (char, 3+ /* "lib" */ strlen (p+2) + 1);
+                 size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2);
+                 name = LT_EMALLOC (char, 1+ name_len);
                  if (name)
-                   {
-                     sprintf (name, "lib%s", p+2);
-                   }
+                   sprintf (name, "lib%s", p+2);
                }
              else
-               {
-                 name = strdup(p);
-               }
+               name = lt_estrdup(p);
 
-             if (name)
-               {
-                 names[depcount++] = name;
-               }
-             else
-               {
-                 goto cleanup_names;
-               }
+             if (!name)
+               goto cleanup_names;
+
+             names[depcount++] = name;
              *end = save;
            }
          p = end;
@@ -1901,11 +2408,9 @@ load_deplibs(handle, deplibs)
     {
       int      j = 0;
 
-      handle->deplibs = (lt_dlhandle*) LT_DLMALLOC (lt_dlhandle *, depcount);
+      handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount);
       if (!handle->deplibs)
-           {
-         goto cleanup;
-           }
+       goto cleanup;
 
       for (i = 0; i < depcount; ++i)
        {
@@ -1934,7 +2439,7 @@ load_deplibs(handle, deplibs)
 }
 
 static int
-unload_deplibs(handle)
+unload_deplibs (handle)
      lt_dlhandle handle;
 {
   int i;
@@ -1962,22 +2467,19 @@ trim (dest, str)
   /* remove the leading and trailing "'" from str
      and store the result in dest */
   const char *end   = strrchr (str, '\'');
-  int  len         = strlen  (str);
+  int  len         = LT_STRLEN (str);
   char *tmp;
 
   LT_DLFREE (*dest);
 
   if (len > 3 && str[0] == '\'')
     {
-      tmp = LT_DLMALLOC (char, end - str);
+      tmp = LT_EMALLOC (char, end - str);
       if (!tmp)
-       {
-         last_error = LT_DLSTRERROR (NO_MEMORY);
-         return 1;
-       }
+       return 1;
 
       strncpy(tmp, &str[1], (end - str) - 1);
-      tmp[len-3] = '\0';
+      tmp[len-3] = LT_EOS_CHAR;
       *dest = tmp;
     }
   else
@@ -1989,7 +2491,7 @@ trim (dest, str)
 }
 
 static int
-free_varsdlname, oldname, libdir, deplibs)
+free_vars (dlname, oldname, libdir, deplibs)
      char *dlname;
      char *oldname;
      char *libdir;
@@ -2003,83 +2505,94 @@ free_vars( dlname, oldname, libdir, deplibs)
   return 0;
 }
 
-lt_dlhandle
-lt_dlopen (filename)
+int
+try_dlopen (phandle, filename)
+     lt_dlhandle *phandle;
      const char *filename;
 {
-  lt_dlhandle handle = 0, newhandle;
-  const char *ext;
-  const char *saved_error;
-  char *canonical = 0, *basename = 0, *dir = 0, *name = 0;
+  const char * ext             = 0;
+  const char * saved_error     = 0;
+  char *       canonical       = 0;
+  char *       base_name       = 0;
+  char *       dir             = 0;
+  char *       name            = 0;
+  int          errors          = 0;
+  lt_dlhandle  newhandle;
 
-  MUTEX_GETERROR (saved_error);
+  assert (phandle);
+  assert (*phandle == 0);
+
+  LT_DLMUTEX_GETERROR (saved_error);
 
   /* dlopen self? */
   if (!filename)
     {
-      handle = (lt_dlhandle) LT_DLMALLOC (struct lt_dlhandle_struct, 1);
-      if (!handle)
-       {
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-         return 0;
-       }
+      *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
+      if (*phandle == 0)
+       return 1;
 
-      memset (handle, 0, 1*sizeof(struct lt_dlhandle_struct));
-      newhandle                        = handle;
+      memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
+      newhandle        = *phandle;
 
       /* lt_dlclose()ing yourself is very bad!  Disallow it.  */
-      LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG);
+      LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG);
 
       if (tryall_dlopen (&newhandle, 0) != 0)
        {
-         LT_DLFREE (handle);
-         return 0;
+         LT_DLFREE (*phandle);
+         return 1;
        }
+
       goto register_handle;
     }
 
-  canonical = canonicalize_path (filename);
-  if (!canonical)
+  assert (filename && *filename);
+
+  /* Doing this immediately allows internal functions to safely
+     assume only canonicalized paths are passed.  */
+  if (canonicalize_path (filename, &canonical) != 0)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-      LT_DLFREE (handle);
-      return 0;
+      ++errors;
+      goto cleanup;
     }
 
   /* If the canonical module name is a path (relative or absolute)
      then split it into a directory part and a name part.  */
-  basename = strrchr (canonical, '/');
-  if (basename)
+  base_name = strrchr (canonical, '/');
+  if (base_name)
     {
-      ++basename;
-      dir = LT_DLMALLOC (char, basename - canonical + 1);
+      size_t dirlen = (1+ base_name) - canonical;
+
+      dir = LT_EMALLOC (char, 1+ dirlen);
       if (!dir)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-         handle = 0;
+         ++errors;
          goto cleanup;
        }
 
-      strncpy (dir, canonical, basename - canonical);
-      dir[basename - canonical] = '\0';
+      strncpy (dir, canonical, dirlen);
+      dir[dirlen] = LT_EOS_CHAR;
+
+      ++base_name;
     }
   else
-    {
-      basename = canonical;
-    }
+    LT_DLMEM_REASSIGN (base_name, canonical);
+
+  assert (base_name && *base_name);
 
   /* Check whether we are opening a libtool module (.la extension).  */
-  ext = strrchr(basename, '.');
-  if (ext && strcmp(ext, ".la") == 0)
+  ext = strrchr (base_name, '.');
+  if (ext && strcmp (ext, archive_ext) == 0)
     {
       /* this seems to be a libtool module */
-      FILE     *file = 0;
-      int      i;
-      char     *dlname = 0, *old_name = 0;
-      char     *libdir = 0, *deplibs = 0;
-      char     *line;
+      FILE *   file     = 0;
+      char *   dlname   = 0;
+      char *   old_name = 0;
+      char *   libdir   = 0;
+      char *   deplibs  = 0;
+      char *    line    = 0;
       size_t   line_len;
-      int      error = 0;
+      int      i;
 
       /* if we can't find the installed flag, it is probably an
         installed libtool archive, produced with an old version
@@ -2087,28 +2600,26 @@ lt_dlopen (filename)
       int      installed = 1;
 
       /* extract the module name from the file name */
-      name = LT_DLMALLOC (char, ext - basename + 1);
+      name = LT_EMALLOC (char, ext - base_name + 1);
       if (!name)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-         handle = 0;
+         ++errors;
          goto cleanup;
        }
 
       /* canonicalize the module name */
-      for (i = 0; i < ext - basename; ++i)
+      for (i = 0; i < ext - base_name; ++i)
        {
-         if (isalnum ((int)(basename[i])))
+         if (isalnum ((int)(base_name[i])))
            {
-             name[i] = basename[i];
+             name[i] = base_name[i];
            }
          else
            {
              name[i] = '_';
            }
        }
-
-      name[ext - basename] = '\0';
+      name[ext - base_name] = LT_EOS_CHAR;
 
     /* Now try to open the .la file.  If there is no directory name
        component, try to find it first in user_search_path and then other
@@ -2116,24 +2627,33 @@ lt_dlopen (filename)
        yet found) try opening just the module name as passed.  */
       if (!dir)
        {
-         file = (FILE*) find_file(basename, user_search_path, &dir, 0);
+         const char *search_path;
+
+         LT_DLMUTEX_LOCK ();
+         search_path = user_search_path;
+         if (search_path)
+           file = find_file (user_search_path, base_name, &dir);
+         LT_DLMUTEX_UNLOCK ();
+
          if (!file)
            {
-             file = (FILE*) find_file(basename, getenv("LTDL_LIBRARY_PATH"),
-                                      &dir, 0);
+             search_path = getenv (LTDL_SEARCHPATH_VAR);
+             if (search_path)
+               file = find_file (search_path, base_name, &dir);
            }
 
 #ifdef LTDL_SHLIBPATH_VAR
          if (!file)
            {
-             file = (FILE*) find_file(basename, getenv(LTDL_SHLIBPATH_VAR),
-                                      &dir, 0);
+             search_path = getenv (LTDL_SHLIBPATH_VAR);
+             if (search_path)
+               file = find_file (search_path, base_name, &dir);
            }
 #endif
 #ifdef LTDL_SYSSEARCHPATH
-         if (!file)
+         if (!file && sys_search_path)
            {
-             file = (FILE*) find_file(basename, sys_search_path, &dir, 0);
+             file = find_file (sys_search_path, base_name, &dir);
            }
 #endif
        }
@@ -2141,39 +2661,36 @@ lt_dlopen (filename)
        {
          file = fopen (filename, LT_READTEXT_MODE);
        }
-      if (!file)
-       {
-         MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
-       }
 
+      /* If we didn't find the file by now, it really isn't there.  Set
+        the status flag, and bail out.  */
       if (!file)
        {
-         handle = 0;
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
+         ++errors;
          goto cleanup;
        }
 
       line_len = LT_FILENAME_MAX;
-      line = LT_DLMALLOC (char, line_len);
+      line = LT_EMALLOC (char, line_len);
       if (!line)
        {
          fclose (file);
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-         handle = 0;
+         ++errors;
          goto cleanup;
        }
 
       /* read the .la file */
-      while (!feof(file))
+      while (!feof (file))
        {
          if (!fgets (line, line_len, file))
            {
              break;
            }
 
-
-         /* Handle the case where we occasionally need to read a line 
+         /* Handle the case where we occasionally need to read a line
             that is longer than the initial buffer size.  */
-         while (line[strlen(line) -1] != '\n')
+         while (line[LT_STRLEN(line) -1] != '\n')
            {
              line = LT_DLREALLOC (char, line, line_len *2);
              if (!fgets (&line[line_len -1], line_len +1, file))
@@ -2192,7 +2709,7 @@ lt_dlopen (filename)
 #define STR_DLNAME     "dlname="
          if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0)
            {
-             error = trim (&dlname, &line[sizeof (STR_DLNAME) - 1]);
+             errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]);
            }
 
 #undef  STR_OLD_LIBRARY
@@ -2200,13 +2717,13 @@ lt_dlopen (filename)
          else if (strncmp (line, STR_OLD_LIBRARY,
                            sizeof (STR_OLD_LIBRARY) - 1) == 0)
            {
-             error = trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]);
+             errors += trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]);
            }
 #undef  STR_LIBDIR
 #define STR_LIBDIR     "libdir="
          else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0)
            {
-             error = trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]);
+             errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]);
            }
 
 #undef  STR_DL_DEPLIBS
@@ -2214,7 +2731,7 @@ lt_dlopen (filename)
          else if (strncmp (line, STR_DL_DEPLIBS,
                            sizeof (STR_DL_DEPLIBS) - 1) == 0)
            {
-             error = trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]);
+             errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]);
            }
          else if (strcmp (line, "installed=yes\n") == 0)
            {
@@ -2231,210 +2748,491 @@ lt_dlopen (filename)
                                        sizeof (STR_LIBRARY_NAMES) - 1) == 0)
            {
              char *last_libname;
-             error = trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]);
-             if (! error && dlname &&
-                 (last_libname = strrchr (dlname, ' ')) != NULL)
+             errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]);
+             if (!errors
+                 && dlname
+                 && (last_libname = strrchr (dlname, ' ')) != 0)
                {
-                 last_libname = strdup (last_libname + 1);
+                 last_libname = lt_estrdup (last_libname + 1);
+                 if (!last_libname)
+                   {
+                     ++errors;
+                     goto cleanup;
+                   }
                  LT_DLMEM_REASSIGN (dlname, last_libname);
                }
            }
 
-         if (error)
-           {
-             break;
-           }
+         if (errors)
+           break;
        }
 
       fclose (file);
       LT_DLFREE (line);
 
       /* allocate the handle */
-      handle = (lt_dlhandle) LT_DLMALLOC (struct lt_dlhandle_struct, 1);
-      if (!handle || error)
-       {
-         LT_DLFREE (handle);
-         if (!error)
-           {
-             MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-           }
+      *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
+      if (*phandle == 0)
+       ++errors;
 
+      if (errors)
+       {
          free_vars (dlname, old_name, libdir, deplibs);
-         /* handle is already set to 0 */
+         LT_DLFREE (*phandle);
          goto cleanup;
        }
 
-      memset (handle, 0, 1*sizeof(struct lt_dlhandle_struct));
-      if (load_deplibs (handle, deplibs) == 0)
+      assert (*phandle);
+
+      memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
+      if (load_deplibs (*phandle, deplibs) == 0)
        {
-         newhandle = handle;
+         newhandle = *phandle;
          /* find_module may replace newhandle */
          if (find_module (&newhandle, dir, libdir, dlname, old_name, installed))
            {
-             unload_deplibs (handle);
-             error = 1;
+             unload_deplibs (*phandle);
+             ++errors;
            }
        }
       else
        {
-         error = 1;
+         ++errors;
        }
 
       free_vars (dlname, old_name, libdir, deplibs);
-      if (error)
+      if (errors)
        {
-         LT_DLFREE (handle);
+         LT_DLFREE (*phandle);
          goto cleanup;
        }
 
-      if (handle != newhandle)
+      if (*phandle != newhandle)
        {
-         unload_deplibs (handle);
+         unload_deplibs (*phandle);
        }
     }
   else
     {
       /* not a libtool module */
-      handle = (lt_dlhandle) LT_DLMALLOC (struct lt_dlhandle_struct, 1);
-      if (!handle)
+      *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
+      if (*phandle == 0)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-         /* handle is already set to 0 */
+         ++errors;
          goto cleanup;
        }
-      handle->info.ref_count = 0;
-      /* non-libtool modules don't have dependencies */
-      handle->depcount    = 0;
-      handle->deplibs    = 0;
-      newhandle                  = handle;
+
+      memset (*phandle, 0, sizeof (struct lt_dlhandle_struct));
+      newhandle = *phandle;
 
       /* If the module has no directory name component, try to find it
         first in user_search_path and then other prescribed paths.
         Otherwise (or in any case if the module was not yet found) try
         opening just the module name as passed.  */
-      if ((dir || (!find_file (basename, user_search_path, 0, &newhandle)
-                  && !find_file (basename, getenv ("LTDL_LIBRARY_PATH"),
-                                 0, &newhandle)
+      if ((dir || (!find_handle (user_search_path, base_name, &newhandle)
+                  && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name,
+                                   &newhandle)
 #ifdef LTDL_SHLIBPATH_VAR
-                  && !find_file (basename, getenv (LTDL_SHLIBPATH_VAR),
-                                 0, &newhandle)
+                  && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name,
+                                   &newhandle)
 #endif
 #ifdef LTDL_SYSSEARCHPATH
-                  && !find_file (basename, sys_search_path, 0, &newhandle)
+                  && !find_handle (sys_search_path, base_name, &newhandle)
 #endif
-                  )) && tryall_dlopen (&newhandle, filename))
+                  )))
+       {
+         tryall_dlopen (&newhandle, filename);
+       }
+
+      if (!newhandle)
        {
-         LT_DLFREE (handle);
+         LT_DLFREE (*phandle);
+         ++errors;
          goto cleanup;
        }
     }
 
  register_handle:
-  LT_DLMEM_REASSIGN (handle, newhandle);
+  LT_DLMEM_REASSIGN (*phandle, newhandle);
 
-  if (handle->info.ref_count == 0)
+  if ((*phandle)->info.ref_count == 0)
     {
-      handle->info.ref_count   = 1;
-      handle->info.name                = name;
-      handle->next             = handles;
-
-      MUTEX_LOCK ();
-      handles                  = handle;
-      MUTEX_UNLOCK ();
+      (*phandle)->info.ref_count       = 1;
+      LT_DLMEM_REASSIGN ((*phandle)->info.name, name);
 
-      name = 0;        /* don't free this during `cleanup' */
+      LT_DLMUTEX_LOCK ();
+      (*phandle)->next         = handles;
+      handles                  = *phandle;
+      LT_DLMUTEX_UNLOCK ();
     }
 
-  MUTEX_SETERROR (saved_error);
+  LT_DLMUTEX_SETERROR (saved_error);
 
  cleanup:
   LT_DLFREE (dir);
   LT_DLFREE (name);
   LT_DLFREE (canonical);
 
+  return errors;
+}
+
+lt_dlhandle
+lt_dlopen (filename)
+     const char *filename;
+{
+  lt_dlhandle handle = 0;
+
+  /* Just incase we missed a code path in try_dlopen() that reports
+     an error, but forgets to reset handle... */
+  if (try_dlopen (&handle, filename) != 0)
+    return 0;
+
   return handle;
 }
 
+/* If the last error messge store was `FILE_NOT_FOUND', then return
+   non-zero.  */
+int
+file_not_found ()
+{
+  const char *error = 0;
+
+  LT_DLMUTEX_GETERROR (error);
+  if (error == LT_DLSTRERROR (FILE_NOT_FOUND))
+    return 1;
+
+  return 0;
+}
+
+/* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to
+   open the FILENAME as passed.  Otherwise try appending ARCHIVE_EXT,
+   and if a file is still not found try again with SHLIB_EXT appended
+   instead.  */
 lt_dlhandle
 lt_dlopenext (filename)
      const char *filename;
 {
-  lt_dlhandle handle;
-  char *tmp;
-  int  len;
-  const char *saved_error;
-
-  MUTEX_GETERROR (saved_error);
+  lt_dlhandle  handle          = 0;
+  char *       tmp             = 0;
+  char *       ext             = 0;
+  int          len;
+  int          errors          = 0;
+  int          file_found      = 1; /* until proven otherwise */
 
   if (!filename)
     {
       return lt_dlopen (filename);
     }
 
-  len = strlen (filename);
-  if (!len)
+  assert (filename);
+
+  len = LT_STRLEN (filename);
+  ext = strrchr (filename, '.');
+
+  /* If FILENAME already bears a suitable extension, there is no need
+     to try appending additional extensions.  */
+  if (ext && ((strcmp (ext, archive_ext) == 0)
+#ifdef LTDL_SHLIB_EXT
+             || (strcmp (ext, shlib_ext) == 0)
+#endif
+      ))
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
-      return 0;
+      return lt_dlopen (filename);
     }
 
-  /* try "filename.la" */
-  tmp = LT_DLMALLOC (char, len+4);
+  /* First try appending ARCHIVE_EXT.  */
+  tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1);
   if (!tmp)
-    {
-      MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-      return 0;
-    }
+    return 0;
+
   strcpy (tmp, filename);
-  strcat (tmp, ".la");
-  handle = lt_dlopen (tmp);
-  if (handle)
+  strcat (tmp, archive_ext);
+  errors = try_dlopen (&handle, tmp);
+
+  /* If we found FILENAME, stop searching -- whether we were able to
+     load the file as a module or not.  If the file exists but loading
+     failed, it is better to return an error message here than to
+     report FILE_NOT_FOUND when the alternatives (foo.so etc) are not
+     in the module search path.  */
+  if (handle || ((errors > 0) && file_not_found ()))
     {
-      MUTEX_SETERROR (saved_error);
       LT_DLFREE (tmp);
       return handle;
     }
 
 #ifdef LTDL_SHLIB_EXT
-  /* try "filename.EXT" */
-  if (strlen(shlib_ext) > 3)
+  /* Try appending SHLIB_EXT.   */
+  if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext))
     {
       LT_DLFREE (tmp);
-      tmp = LT_DLMALLOC (char, len + strlen (shlib_ext) + 1);
+      tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1);
       if (!tmp)
-       {
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-         return 0;
-       }
+       return 0;
+
       strcpy (tmp, filename);
     }
   else
     {
-      tmp[len] = '\0';
+      tmp[len] = LT_EOS_CHAR;
     }
 
   strcat(tmp, shlib_ext);
-  handle = lt_dlopen (tmp);
-  if (handle)
+  errors = try_dlopen (&handle, tmp);
+
+  /* As before, if the file was found but loading failed, return now
+     with the current error message.  */
+  if (handle || ((errors > 0) && file_not_found ()))
     {
-      MUTEX_SETERROR (saved_error);
       LT_DLFREE (tmp);
       return handle;
     }
 #endif
 
-  /* try the normal file name */
-  handle = lt_dlopen (filename);
-  if (handle)
+  /* Still here?  Then we really did fail to locate any of the file
+     names we tried.  */
+  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
+  LT_DLFREE (tmp);
+  return 0;
+}
+
+
+int
+lt_argz_insert (pargz, pargz_len, before, entry)
+     char **pargz;
+     size_t *pargz_len;
+     char *before;
+     const char *entry;
+{
+  error_t error;
+
+  if ((error = argz_insert (pargz, pargz_len, before, entry)))
     {
-      return handle;
+      switch (error)
+       {
+       case ENOMEM:
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
+         break;
+       default:
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
+         break;
+       }
+      return 1;
     }
 
-  MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
-  LT_DLFREE (tmp);
   return 0;
 }
 
+int
+lt_argz_insertinorder (pargz, pargz_len, entry)
+     char **pargz;
+     size_t *pargz_len;
+     const char *entry;
+{
+  char *before = 0;
+
+  assert (pargz);
+  assert (pargz_len);
+  assert (entry && *entry);
+
+  if (*pargz)
+    while ((before = argz_next (*pargz, *pargz_len, before)))
+      {
+       int cmp = strcmp (entry, before);
+
+       if (cmp < 0)  break;
+       if (cmp == 0) return 0; /* No duplicates! */
+      }
+
+  return lt_argz_insert (pargz, pargz_len, before, entry);
+}
+
+int
+lt_argz_insertdir (pargz, pargz_len, dirnam, dp)
+     char **pargz;
+     size_t *pargz_len;
+     const char *dirnam;
+     struct dirent *dp;
+{
+  char   *buf      = 0;
+  size_t buf_len    = 0;
+  char   *end      = 0;
+  size_t end_offset = 0;
+  size_t dir_len    = 0;
+  int    errors            = 0;
+
+  assert (pargz);
+  assert (pargz_len);
+  assert (dp);
+
+  dir_len = LT_STRLEN (dirnam);
+  end     = dp->d_name + LT_D_NAMLEN(dp);
+
+  /* Ignore version numbers.  */
+  {
+    char *p;
+    for (p = end; p -1 > dp->d_name; --p)
+      if (strchr (".0123456789", p[-1]) == 0)
+       break;
+
+    if (*p == '.')
+      end = p;
+  }
+
+  /* Ignore filename extension.  */
+  {
+    char *p;
+    for (p = end -1; p > dp->d_name; --p)
+      if (*p == '.')
+       {
+         end = p;
+         break;
+       }
+  }
+
+  /* Prepend the directory name.  */
+  end_offset   = end - dp->d_name;
+  buf_len      = dir_len + 1+ end_offset;
+  buf          = LT_EMALLOC (char, 1+ buf_len);
+  if (!buf)
+    return ++errors;
+
+  assert (buf);
+
+  strcpy  (buf, dirnam);
+  strcat  (buf, "/");
+  strncat (buf, dp->d_name, end_offset);
+  buf[buf_len] = LT_EOS_CHAR;
+
+  /* Try to insert (in order) into ARGZ/ARGZ_LEN.  */
+  if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0)
+    ++errors;
+
+  LT_DLFREE (buf);
+
+  return errors;
+}
+
+int
+list_files_by_dir (dirnam, pargz, pargz_len)
+     const char *dirnam;
+     char **pargz;
+     size_t *pargz_len;
+{
+  DIR  *dirp     = 0;
+  int    errors          = 0;
+
+  assert (dirnam && *dirnam);
+  assert (pargz);
+  assert (pargz_len);
+  assert (dirnam[LT_STRLEN(dirnam) -1] != '/');
+
+  dirp = opendir (dirnam);
+  if (dirp)
+    {
+      struct dirent *dp        = 0;
+
+      while ((dp = readdir (dirp)))
+       if (dp->d_name[0] != '.')
+         if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp))
+           {
+             ++errors;
+             break;
+           }
+
+      closedir (dirp);
+    }
+  else
+    ++errors;
+
+  return errors;
+}
+
+
+/* If there are any files in DIRNAME, call the function passed in
+   DATA1 (with the name of each file and DATA2 as arguments).  */
+static int
+foreachfile_callback (dirname, data1, data2)
+     char *dirname;
+     lt_ptr data1;
+     lt_ptr data2;
+{
+  int (*func) LT_PARAMS((const char *filename, lt_ptr data))
+       = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1;
+
+  int    is_done  = 0;
+  char   *argz     = 0;
+  size_t  argz_len = 0;
+
+  if (list_files_by_dir (dirname, &argz, &argz_len) != 0)
+    goto cleanup;
+  if (!argz)
+    goto cleanup;
+
+  {
+    char *filename = 0;
+    while ((filename = argz_next (argz, argz_len, filename)))
+      if ((is_done = (*func) (filename, data2)))
+       break;
+  }
+
+ cleanup:
+  LT_DLFREE (argz);
+
+  return is_done;
+}
+
+
+/* Call FUNC for each unique extensionless file in SEARCH_PATH, along
+   with DATA.  The filenames passed to FUNC would be suitable for
+   passing to lt_dlopenext.  The extensions are stripped so that
+   individual modules do not generate several entries (e.g. libfoo.la,
+   libfoo.so, libfoo.so.1, libfoo.so.1.0.0).  If SEARCH_PATH is NULL,
+   then the same directories that lt_dlopen would search are examined.  */
+int
+lt_dlforeachfile (search_path, func, data)
+     const char *search_path;
+     int (*func) LT_PARAMS ((const char *filename, lt_ptr data));
+     lt_ptr data;
+{
+  int is_done = 0;
+
+  if (search_path)
+    {
+      /* If a specific path was passed, search only the directories
+        listed in it.  */
+      is_done = foreach_dirinpath (search_path, 0,
+                                  foreachfile_callback, func, data);
+    }
+  else
+    {
+      /* Otherwise search the default paths.  */
+      is_done = foreach_dirinpath (user_search_path, 0,
+                                  foreachfile_callback, func, data);
+      if (!is_done)
+       {
+         is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0,
+                                      foreachfile_callback, func, data);
+       }
+
+#ifdef LTDL_SHLIBPATH_VAR
+      if (!is_done)
+       {
+         is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0,
+                                      foreachfile_callback, func, data);
+       }
+#endif
+#ifdef LTDL_SYSSEARCHPATH
+      if (!is_done)
+       {
+         is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0,
+                                      foreachfile_callback, func, data);
+       }
+#endif
+    }
+
+  return is_done;
+}
+
 int
 lt_dlclose (handle)
      lt_dlhandle handle;
@@ -2442,7 +3240,7 @@ lt_dlclose (handle)
   lt_dlhandle cur, last;
   int errors = 0;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
 
   /* check whether the handle is valid */
   last = cur = handles;
@@ -2454,7 +3252,7 @@ lt_dlclose (handle)
 
   if (!cur)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
       ++errors;
       goto done;
     }
@@ -2490,12 +3288,12 @@ lt_dlclose (handle)
 
   if (LT_DLIS_RESIDENT (handle))
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE));
       ++errors;
     }
 
  done:
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return errors;
 }
@@ -2513,26 +3311,18 @@ lt_dlsym (handle, symbol)
 
   if (!handle)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
       return 0;
     }
 
   if (!symbol)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
       return 0;
     }
 
-  lensym = strlen(symbol);
-  if (handle->loader->sym_prefix)
-    {
-      lensym += strlen(handle->loader->sym_prefix);
-    }
-
-  if (handle->info.name)
-    {
-      lensym += strlen(handle->info.name);
-    }
+  lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix)
+                                       + LT_STRLEN (handle->info.name);
 
   if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH)
     {
@@ -2540,13 +3330,12 @@ lt_dlsym (handle, symbol)
     }
   else
     {
-      sym = LT_DLMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1);
-    }
-
-  if (!sym)
-    {
-      MUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW));
-      return 0;
+      sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1);
+      if (!sym)
+       {
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW));
+         return 0;
+       }
     }
 
   data = handle->loader->dlloader_data;
@@ -2554,7 +3343,7 @@ lt_dlsym (handle, symbol)
     {
       const char *saved_error;
 
-      MUTEX_GETERROR (saved_error);
+      LT_DLMUTEX_GETERROR (saved_error);
 
       /* this is a libtool module */
       if (handle->loader->sym_prefix)
@@ -2580,7 +3369,7 @@ lt_dlsym (handle, symbol)
            }
          return address;
        }
-      MUTEX_SETERROR (saved_error);
+      LT_DLMUTEX_SETERROR (saved_error);
     }
 
   /* otherwise try "symbol" */
@@ -2608,10 +3397,82 @@ lt_dlerror ()
 {
   const char *error;
 
-  MUTEX_GETERROR (error);
-  MUTEX_SETERROR (0);
+  LT_DLMUTEX_GETERROR (error);
+  LT_DLMUTEX_SETERROR (0);
 
-  return error;
+  return error ? error : LT_DLSTRERROR (UNKNOWN);
+}
+
+int
+lt_dlpath_insertdir (ppath, before, dir)
+     char **ppath;
+     char *before;
+     const char *dir;
+{
+  int    errors                = 0;
+  char  *canonical     = 0;
+  char  *argz          = 0;
+  size_t argz_len      = 0;
+
+  assert (ppath);
+  assert (dir && *dir);
+
+  if (canonicalize_path (dir, &canonical) != 0)
+    {
+      ++errors;
+      goto cleanup;
+    }
+
+  assert (canonical && *canonical);
+
+  /* If *PPATH is empty, set it to DIR.  */
+  if (*ppath == 0)
+    {
+      assert (!before);                /* BEFORE cannot be set without PPATH.  */
+      assert (dir);            /* Without DIR, don't call this function!  */
+
+      *ppath = lt_estrdup (dir);
+      if (*ppath == 0)
+       ++errors;
+
+      return errors;
+    }
+
+  assert (ppath && *ppath);
+
+  if (argzize_path (*ppath, &argz, &argz_len) != 0)
+    {
+      ++errors;
+      goto cleanup;
+    }
+
+  /* Convert BEFORE into an equivalent offset into ARGZ.  This only works
+     if *PPATH is already canonicalized, and hence does not change length
+     with respect to ARGZ.  We canonicalize each entry as it is added to
+     the search path, and don't call this function with (uncanonicalized)
+     user paths, so this is a fair assumption.  */
+  if (before)
+    {
+      assert (*ppath <= before);
+      assert (before - *ppath <= strlen (*ppath));
+
+      before = before - *ppath + argz;
+    }
+
+  if (lt_argz_insert (&argz, &argz_len, before, dir) != 0)
+    {
+      ++errors;
+      goto cleanup;
+    }
+
+  argz_stringify (argz, argz_len, LT_PATHSEP_CHAR);
+  LT_DLMEM_REASSIGN (*ppath,  argz);
+
+ cleanup:
+  LT_DLFREE (canonical);
+  LT_DLFREE (argz);
+
+  return errors;
 }
 
 int
@@ -2620,40 +3481,47 @@ lt_dladdsearchdir (search_dir)
 {
   int errors = 0;
 
-  if (!search_dir || !strlen(search_dir))
+  if (search_dir && *search_dir)
     {
-      return errors;
+      LT_DLMUTEX_LOCK ();
+      if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)
+       ++errors;
+      LT_DLMUTEX_UNLOCK ();
     }
 
-  MUTEX_LOCK ();
-  if (!user_search_path)
+  return errors;
+}
+
+int
+lt_dlinsertsearchdir (before, search_dir)
+     const char *before;
+     const char *search_dir;
+{
+  int errors = 0;
+
+  if (before)
     {
-      user_search_path = strdup (search_dir);
-      if (!user_search_path)
+      LT_DLMUTEX_LOCK ();
+      if ((before < user_search_path)
+         || (before >= user_search_path + LT_STRLEN (user_search_path)))
        {
-         last_error = LT_DLSTRERROR (NO_MEMORY);
-         ++errors;
+         LT_DLMUTEX_UNLOCK ();
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION));
+         return 1;
        }
+      LT_DLMUTEX_UNLOCK ();
     }
-  else
-    {
-      size_t len = strlen (user_search_path) + 1 + strlen (search_dir);
-      char  *new_search_path = LT_DLMALLOC (char, 1+ len);
 
-      if (!new_search_path)
+  if (search_dir && *search_dir)
+    {
+      LT_DLMUTEX_LOCK ();
+      if (lt_dlpath_insertdir (&user_search_path,
+                              (char *) before, search_dir) != 0)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
          ++errors;
        }
-      else
-       {
-         sprintf (new_search_path, "%s%c%s", user_search_path,
-                  LT_PATHSEP_CHAR, search_dir);
-
-         LT_DLMEM_REASSIGN (user_search_path, new_search_path);
-       }
+      LT_DLMUTEX_UNLOCK ();
     }
-  MUTEX_UNLOCK ();
 
   return errors;
 }
@@ -2662,24 +3530,21 @@ int
 lt_dlsetsearchpath (search_path)
      const char *search_path;
 {
-  int errors = 0;
+  int   errors     = 0;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   LT_DLFREE (user_search_path);
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
-  if (!search_path || !strlen (search_path))
+  if (!search_path || !LT_STRLEN (search_path))
     {
       return errors;
     }
 
-  MUTEX_LOCK ();
-  user_search_path = strdup (search_path);
-  if (!user_search_path)
-    {
-      ++errors;
-    }
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_LOCK ();
+  if (canonicalize_path (search_path, &user_search_path) != 0)
+    ++errors;
+  LT_DLMUTEX_UNLOCK ();
 
   return errors;
 }
@@ -2689,9 +3554,9 @@ lt_dlgetsearchpath ()
 {
   const char *saved_path;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   saved_path = user_search_path;
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return saved_path;
 }
@@ -2704,7 +3569,7 @@ lt_dlmakeresident (handle)
 
   if (!handle)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
       ++errors;
     }
   else
@@ -2721,7 +3586,7 @@ lt_dlisresident   (handle)
 {
   if (!handle)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
       return -1;
     }
 
@@ -2739,7 +3604,7 @@ lt_dlgetinfo (handle)
 {
   if (!handle)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
       return 0;
     }
 
@@ -2750,7 +3615,7 @@ lt_dlhandle
 lt_dlhandle_next (place)
      lt_dlhandle place;
 {
-  return place ? place->next : (lt_dlhandle) 0;
+  return place ? place->next : handles;
 }
 
 int
@@ -2761,7 +3626,7 @@ lt_dlforeach (func, data)
   int errors = 0;
   lt_dlhandle cur;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
 
   cur = handles;
   while (cur)
@@ -2776,7 +3641,7 @@ lt_dlforeach (func, data)
        }
     }
 
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return errors;
 }
@@ -2784,18 +3649,16 @@ lt_dlforeach (func, data)
 lt_dlcaller_id
 lt_dlcaller_register ()
 {
-  static int last_caller_id = -1;
+  static lt_dlcaller_id last_caller_id = 0;
   int result;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   result = ++last_caller_id;
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return result;
 }
 
-#define N_ELEMENTS(a)  (sizeof(a) / sizeof(*(a)))
-
 lt_ptr
 lt_dlcaller_set_data (key, handle, data)
      lt_dlcaller_id key;
@@ -2808,10 +3671,11 @@ lt_dlcaller_set_data (key, handle, data)
 
   /* This needs to be locked so that the caller data can be updated
      simultaneously by different threads.  */
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
 
   if (handle->caller_data)
-    n_elements = N_ELEMENTS (handle->caller_data);
+    while (handle->caller_data[n_elements].key)
+      ++n_elements;
 
   for (i = 0; i < n_elements; ++i)
     {
@@ -2823,31 +3687,29 @@ lt_dlcaller_set_data (key, handle, data)
     }
 
   /* Ensure that there is enough room in this handle's caller_data
-     array to accept a new element.  */
+     array to accept a new element (and an empty end marker).  */
   if (i == n_elements)
     {
       lt_caller_data *temp
-       = LT_DLREALLOC (lt_caller_data, handle->caller_data, 1+ n_elements);
+       = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements);
 
-      if (temp == 0)
+      if (!temp)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-         stale =  (lt_ptr) 0;
+         stale = 0;
          goto done;
        }
-      else
-       {
-         handle->caller_data = temp;
-       }
+
+      handle->caller_data = temp;
 
       /* We only need this if we needed to allocate a new caller_data.  */
       handle->caller_data[i].key  = key;
+      handle->caller_data[1+ i].key = 0;
     }
 
   handle->caller_data[i].data = data;
 
  done:
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return stale;
 }
@@ -2858,19 +3720,15 @@ lt_dlcaller_get_data  (key, handle)
      lt_dlhandle handle;
 {
   lt_ptr result = (lt_ptr) 0;
-  int n_elements = 0;
 
   /* This needs to be locked so that the caller data isn't updated by
      another thread part way through this function.  */
-  MUTEX_LOCK ();
-
-  if (handle->caller_data)
-    n_elements = N_ELEMENTS (handle->caller_data);
+  LT_DLMUTEX_LOCK ();
 
   /* Locate the index of the element with a matching KEY.  */
   {
     int i;
-    for (i = 0; i < n_elements; ++i)
+    for (i = 0; handle->caller_data[i].key; ++i)
       {
        if (handle->caller_data[i].key == key)
          {
@@ -2880,7 +3738,7 @@ lt_dlcaller_get_data  (key, handle)
       }
   }
 
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return result;
 }
@@ -2904,17 +3762,14 @@ lt_dlloader_add (place, dlloader, loader_name)
       || (dlloader->module_close == 0)
       || (dlloader->find_sym == 0))
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
       return 1;
     }
 
   /* Create a new dlloader node with copies of the user callbacks.  */
-  node = LT_DLMALLOC (lt_dlloader, 1);
-  if (node == 0)
-    {
-      MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
-      return 1;
-    }
+  node = LT_EMALLOC (lt_dlloader, 1);
+  if (!node)
+    return 1;
 
   node->next           = 0;
   node->loader_name    = loader_name;
@@ -2925,7 +3780,7 @@ lt_dlloader_add (place, dlloader, loader_name)
   node->find_sym       = dlloader->find_sym;
   node->dlloader_data  = dlloader->dlloader_data;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   if (!loaders)
     {
       /* If there are no loaders, NODE becomes the list! */
@@ -2958,7 +3813,7 @@ lt_dlloader_add (place, dlloader, loader_name)
 
       if (ptr->next != place)
        {
-         last_error = LT_DLSTRERROR (INVALID_LOADER);
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
          ++errors;
        }
       else
@@ -2969,7 +3824,7 @@ lt_dlloader_add (place, dlloader, loader_name)
        }
     }
 
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return errors;
 }
@@ -2984,18 +3839,18 @@ lt_dlloader_remove (loader_name)
 
   if (!place)
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
       return 1;
     }
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
 
   /* Fail if there are any open modules which use this loader. */
   for  (handle = handles; handle; handle = handle->next)
     {
       if (handle->loader == place)
        {
-         MUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER));
+         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER));
          ++errors;
          goto done;
        }
@@ -3030,7 +3885,7 @@ lt_dlloader_remove (loader_name)
   LT_DLFREE (place);
 
  done:
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return errors;
 }
@@ -3041,9 +3896,9 @@ lt_dlloader_next (place)
 {
   lt_dlloader *next;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   next = place ? place->next : loaders;
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return next;
 }
@@ -3056,13 +3911,13 @@ lt_dlloader_name (place)
 
   if (place)
     {
-      MUTEX_LOCK ();
+      LT_DLMUTEX_LOCK ();
       name = place ? place->loader_name : 0;
-      MUTEX_UNLOCK ();
+      LT_DLMUTEX_UNLOCK ();
     }
   else
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
     }
 
   return name;
@@ -3076,13 +3931,13 @@ lt_dlloader_data (place)
 
   if (place)
     {
-      MUTEX_LOCK ();
+      LT_DLMUTEX_LOCK ();
       data = place ? &(place->dlloader_data) : 0;
-      MUTEX_UNLOCK ();
+      LT_DLMUTEX_UNLOCK ();
     }
   else
     {
-      MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
+      LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
     }
 
   return data;
@@ -3094,7 +3949,7 @@ lt_dlloader_find (loader_name)
 {
   lt_dlloader *place = 0;
 
-  MUTEX_LOCK ();
+  LT_DLMUTEX_LOCK ();
   for (place = loaders; place; place = place->next)
     {
       if (strcmp (place->loader_name, loader_name) == 0)
@@ -3102,7 +3957,7 @@ lt_dlloader_find (loader_name)
          break;
        }
     }
-  MUTEX_UNLOCK ();
+  LT_DLMUTEX_UNLOCK ();
 
   return place;
 }
index 28606c114849ed96c7a1fa23f53b1a02bfc3b8e4..2bbfa302cc4142f568d02ad4b5d8466e215e0523 100644 (file)
@@ -34,6 +34,9 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 /* --- MACROS FOR PORTABILITY --- */
 
 
+/* Saves on those hard to debug '\0' typos....  */
+#define LT_EOS_CHAR    '\0'
+
 /* LTDL_BEGIN_C_DECLS should be used at the beginning of your declarations,
    so that C++ compilers don't mangle their names.  Use LTDL_END_C_DECLS at
    the end of C declarations. */
@@ -82,6 +85,8 @@ LT_BEGIN_C_DECLS
 #  define LT_CONC(s,t) s/**/t
 #endif
 
+/* LT_STRLEN can be used safely on NULL pointers.  */
+#define LT_STRLEN(s)   (((s) && (s)[0]) ? strlen (s) : 0)
 
 
 \f
@@ -146,10 +151,16 @@ typedef   struct lt_dlhandle_struct *lt_dlhandle; /* A loaded module.  */
 extern int         lt_dlinit           LT_PARAMS((void));
 extern int         lt_dlexit           LT_PARAMS((void));
 
-/* Module search path manipultation.  */
-extern int         lt_dladdsearchdir   LT_PARAMS((const char *search_dir));
-extern int         lt_dlsetsearchpath  LT_PARAMS((const char *search_path));
-extern const char *lt_dlgetsearchpath  LT_PARAMS((void));
+/* Module search path manipulation.  */
+extern int         lt_dladdsearchdir    LT_PARAMS((const char *search_dir));
+extern int         lt_dlinsertsearchdir LT_PARAMS((const char *before,
+                                                   const char *search_dir));
+extern int         lt_dlsetsearchpath   LT_PARAMS((const char *search_path));
+extern const char *lt_dlgetsearchpath   LT_PARAMS((void));
+extern int         lt_dlforeachfile     LT_PARAMS((
+                       const char *search_path,
+                       int (*func) (const char *filename, lt_ptr data),
+                       lt_ptr data));
 
 /* Portable libltdl versions of the system dlopen() API. */
 extern lt_dlhandle lt_dlopen           LT_PARAMS((const char *filename));
@@ -171,7 +182,7 @@ extern      int         lt_dlisresident     LT_PARAMS((lt_dlhandle handle));
 
 typedef void   lt_dlmutex_lock         LT_PARAMS((void));
 typedef void   lt_dlmutex_unlock       LT_PARAMS((void));
-typedef void   lt_dlmutex_seterror     LT_PARAMS((const char *error));
+typedef void   lt_dlmutex_seterror     LT_PARAMS((const char *errmsg));
 typedef const char *lt_dlmutex_geterror        LT_PARAMS((void));
 
 extern int     lt_dlmutex_register     LT_PARAMS((lt_dlmutex_lock *lock,
@@ -185,8 +196,13 @@ extern     int     lt_dlmutex_register     LT_PARAMS((lt_dlmutex_lock *lock,
 /* --- MEMORY HANDLING --- */
 
 
-/* Pointers to memory management functions to be used by libltdl. */
+/* By default, the realloc function pointer is set to our internal
+   realloc implementation which iself uses lt_dlmalloc and lt_dlfree.
+   libltdl relies on a featureful realloc, but if you are sure yours
+   has the right semantics then you can assign it directly.  Generally,
+   it is safe to assign just a malloc() and a free() function.  */
 LT_SCOPE  lt_ptr   (*lt_dlmalloc)      LT_PARAMS((size_t size));
+LT_SCOPE  lt_ptr   (*lt_dlrealloc)     LT_PARAMS((lt_ptr ptr, size_t size));
 LT_SCOPE  void    (*lt_dlfree)         LT_PARAMS((lt_ptr ptr));
 
 
@@ -275,8 +291,8 @@ extern      lt_dlloader    *lt_dlloader_find    LT_PARAMS((
 extern const char     *lt_dlloader_name    LT_PARAMS((lt_dlloader *place));
 extern lt_user_data   *lt_dlloader_data    LT_PARAMS((lt_dlloader *place));
 extern int             lt_dlloader_add     LT_PARAMS((lt_dlloader *place,
-                                               const struct lt_user_dlloader *dlloader,
-                                               const char *loader_name));
+                               const struct lt_user_dlloader *dlloader,
+                               const char *loader_name));
 extern int             lt_dlloader_remove  LT_PARAMS((
                                                const char *loader_name));
 
@@ -307,7 +323,8 @@ extern      int             lt_dlloader_remove  LT_PARAMS((
     LT_ERROR(INVALID_ERRORCODE,     "invalid errorcode")               \
     LT_ERROR(SHUTDOWN,             "library already shutdown")         \
     LT_ERROR(CLOSE_RESIDENT_MODULE, "can't close resident module")     \
-    LT_ERROR(INVALID_MUTEX_ARGS,    "invalid mutex handler registration")
+    LT_ERROR(INVALID_MUTEX_ARGS,    "invalid mutex handler registration") \
+    LT_ERROR(INVALID_POSITION,     "invalid search path insert position")
 
 /* Enumerate the symbolic error names. */
 enum {
diff --git a/ltdl.m4 b/ltdl.m4
index d3ee602698c4233eecfddbaf9179c8fb3f10d73c..0038be241399565c51cca4657ce76458beebb8c1 100644 (file)
--- a/ltdl.m4
+++ b/ltdl.m4
 
 # AC_LIB_LTDL
 # -----------
+# Perform all the checks necessary for compilation of the ltdl objects
+#  -- including compiler checks and header checks.
 AC_DEFUN(AC_LIB_LTDL,
-[AC_PREREQ(2.13)dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_C_CONST])dnl
+[AC_PREREQ(2.13)
+AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AC_C_CONST])
+AC_REQUIRE([AC_HEADER_STDC])
+AC_REQUIRE([AC_HEADER_DIRENT])
+AC_REQUIRE([_LT_AC_CHECK_DLFCN])
+AC_REQUIRE([AC_LTDL_ENABLE_INSTALL])
+AC_REQUIRE([AC_LTDL_SHLIBEXT])
+AC_REQUIRE([AC_LTDL_SHLIBPATH])
+AC_REQUIRE([AC_LTDL_SYSSEARCHPATH])
+AC_REQUIRE([AC_LTDL_OBJDIR])
+AC_REQUIRE([AC_LTDL_DLPREOPEN])
+AC_REQUIRE([AC_LTDL_DLLIB])
+AC_REQUIRE([AC_LTDL_SYMBOL_USCORE])
+AC_REQUIRE([AC_LTDL_DLSYM_USCORE])
+AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS])
+AC_REQUIRE([AC_LTDL_FUNC_ARGZ])
 
-# Perform all the checks necessary for compilation of the ltdl objects
-#  -- including compiler checks (above) and header checks (below).
-AC_REQUIRE([AC_HEADER_STDC])dnl
-AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+AC_CHECK_HEADERS([errno.h malloc.h memory.h stdlib.h stdio.h ctype.h unistd.h])
+AC_CHECK_HEADERS([dl.h sys/dl.h dld.h])
+AC_CHECK_HEADERS([string.h strings.h], break)
 
-AC_CHECK_HEADERS(malloc.h memory.h stdlib.h stdio.h ctype.h dl.h sys/dl.h dld.h)
-AC_CHECK_HEADERS(string.h strings.h, break)
-AC_CHECK_FUNCS(strchr index, break)
-AC_CHECK_FUNCS(strrchr rindex, break)
-AC_CHECK_FUNCS(memcpy bcopy, break)
-AC_CHECK_FUNCS(strcmp)
+AC_CHECK_FUNCS([strchr index], break)
+AC_CHECK_FUNCS([strrchr rindex], break)
+AC_CHECK_FUNCS([memcpy bcopy], break)
+AC_CHECK_FUNCS([memmove strcmp])
 
-AC_REQUIRE([AC_LTDL_ENABLE_INSTALL])dnl
-AC_REQUIRE([AC_LTDL_SHLIBEXT])dnl
-AC_REQUIRE([AC_LTDL_SHLIBPATH])dnl
-AC_REQUIRE([AC_LTDL_SYSSEARCHPATH])dnl
-AC_REQUIRE([AC_LTDL_OBJDIR])dnl
-AC_REQUIRE([AC_LTDL_DLPREOPEN])dnl
-AC_REQUIRE([AC_LTDL_DLLIB])dnl
-AC_REQUIRE([AC_LTDL_SYMBOL_USCORE])dnl
-AC_REQUIRE([AC_LTDL_DLSYM_USCORE])dnl
-AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS])dnl
 ])# AC_LIB_LTDL
 
 # AC_LTDL_ENABLE_INSTALL
@@ -280,3 +283,21 @@ if test x"$libltdl_cv_need_uscore" = xyes; then
     [Define if dlsym() requires a leading underscode in symbol names. ])
 fi
 ])# AC_LTDL_DLSYM_USCORE
+
+
+# AC_LTDL_FUNC_ARGZ
+# -----------------
+AC_DEFUN([AC_LTDL_FUNC_ARGZ],
+[AC_CHECK_HEADERS([argz.h])
+
+AC_CHECK_TYPES([error_t],
+  [],
+  [AC_DEFINE([error_t], [int],
+    [Define to a type to use for `error_t' if it is not otherwise available.])],
+  [#if HAVE_ARGZ_H
+#  include <argz.h>
+#endif])
+
+AC_CHECK_FUNCS([argz_append argz_create_sep argz_insert argz_next argz_stringify])
+])# AC_LTDL_FUNC_ARGZ
+