Diff for /sql/pgsql/libltdl/ltdl.c between versions 1.1 and 1.2

version 1.1, 2001/09/21 15:44:38 version 1.2, 2003/01/13 15:50:03
Line 1 Line 1
 /* ltdl.c -- system independent dlopen wrapper  /* ltdl.c -- system independent dlopen wrapper
    Copyright (C) 1998-1999 Free Software Foundation, Inc.     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
    Originally by Thomas Tanner <tanner@ffii.org>     Originally by Thomas Tanner <tanner@ffii.org>
    This file is part of GNU Libtool.     This file is part of GNU Libtool.
   
 This library is free software; you can redistribute it and/or  This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Library General Public  modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either  License as published by the Free Software Foundation; either
 version 2 of the License, or (at your option) any later version.  version 2 of the License, or (at your option) any later version.
   
 As a special exception to the GNU Library General Public License,  As a special exception to the GNU Lesser General Public License,
 if you distribute this file as part of a program that uses GNU libtool  if you distribute this file as part of a program or library that
 to create libraries and programs, you may include it under the same  is built using GNU libtool, you may include it under the same
 distribution terms that you use for the rest of that program.  distribution terms that you use for the rest of that program.
   
 This library is distributed in the hope that it will be useful,  This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of  but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Library General Public License for more details.  Lesser General Public License for more details.
   
 You should have received a copy of the GNU Library General Public  You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software  License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 02111-1307  USA  02111-1307  USA
   
 */  */
   
 #define _LTDL_COMPILE_  #if HAVE_CONFIG_H
   #  include <config.h>
   #endif
   
 #include "config.h"  #if HAVE_UNISTD_H
   #  include <unistd.h>
   #endif
   
 #if HAVE_STRING_H  #if HAVE_STDIO_H
 #include <string.h>  #  include <stdio.h>
   #endif
   
   #if HAVE_STDLIB_H
   #  include <stdlib.h>
 #endif  #endif
   
 #if HAVE_STRINGS_H  #if HAVE_STRING_H
 #include <strings.h>  #  include <string.h>
   #else
   #  if HAVE_STRINGS_H
   #    include <strings.h>
   #  endif
 #endif  #endif
   
 #if HAVE_CTYPE_H  #if HAVE_CTYPE_H
 #include <ctype.h>  #  include <ctype.h>
 #endif  #endif
   
 #if HAVE_MALLOC_H  #if HAVE_MALLOC_H
 #include <malloc.h>  #  include <malloc.h>
 #endif  #endif
   
 #if HAVE_MEMORY_H  #if HAVE_MEMORY_H
 #include <memory.h>  #  include <memory.h>
 #endif  #endif
   
 #if HAVE_STDLIB_H  #if HAVE_ERRNO_H
 #include <stdlib.h>  #  include <errno.h>
 #endif  #endif
   
 #if HAVE_STDIO_H  #if HAVE_DIRENT_H
 #include <stdio.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
   
   #if HAVE_ASSERT_H
   #  include <assert.h>
   #else
   #  define assert(arg)   ((void) 0)
 #endif  #endif
   
 #include "ltdl.h"  #include "ltdl.h"
   
 /* max. filename length */  #if WITH_DMALLOC
 #ifndef LTDL_FILENAME_MAX  #  include <dmalloc.h>
 #define LTDL_FILENAME_MAX 1024  #endif
   
   
   
   
   /* --- WINDOWS SUPPORT --- */
   
   
   #ifdef DLL_EXPORT
   #  define LT_GLOBAL_DATA        __declspec(dllexport)
   #else
   #  define LT_GLOBAL_DATA
 #endif  #endif
   
 #undef  LTDL_READTEXT_MODE  
 /* fopen() mode flags for reading a text file */  /* fopen() mode flags for reading a text file */
 #ifdef _WIN32  #undef  LT_READTEXT_MODE
 #define LTDL_READTEXT_MODE "rt"  #ifdef __WINDOWS__
   #  define LT_READTEXT_MODE "rt"
 #else  #else
 #define LTDL_READTEXT_MODE "r"  #  define LT_READTEXT_MODE "r"
   #endif
   
   
   
   
   /* --- MANIFEST CONSTANTS --- */
   
   
   /* Standard libltdl search path environment variable name  */
   #undef  LTDL_SEARCHPATH_VAR
   #define LTDL_SEARCHPATH_VAR     "LTDL_LIBRARY_PATH"
   
   /* Standard libtool archive file extension.  */
   #undef  LTDL_ARCHIVE_EXT
   #define LTDL_ARCHIVE_EXT        ".la"
   
   /* max. filename length */
   #ifndef LT_FILENAME_MAX
   #  define LT_FILENAME_MAX       1024
 #endif  #endif
   
 #undef  LTDL_SYMBOL_LENGTH  
 /* This is the maximum symbol size that won't require malloc/free */  /* This is the maximum symbol size that won't require malloc/free */
 #define LTDL_SYMBOL_LENGTH      128  #undef  LT_SYMBOL_LENGTH
   #define LT_SYMBOL_LENGTH        128
   
 #undef  LTDL_SYMBOL_OVERHEAD  
 /* This accounts for the _LTX_ separator */  /* This accounts for the _LTX_ separator */
 #define LTDL_SYMBOL_OVERHEAD    5  #undef  LT_SYMBOL_OVERHEAD
   #define LT_SYMBOL_OVERHEAD      5
   
   
   
   
   /* --- MEMORY HANDLING --- */
   
   
   /* These are the functions used internally.  In addition to making
      use of the associated function pointers above, they also perform
      error handling.  */
   static char   *lt_estrdup       LT_PARAMS((const char *str));
   static lt_ptr lt_emalloc        LT_PARAMS((size_t size));
   static lt_ptr lt_erealloc       LT_PARAMS((lt_ptr addr, size_t size));
   
   static lt_ptr rpl_realloc       LT_PARAMS((lt_ptr ptr, size_t size));
   
   /* These are the pointers that can be changed by the caller:  */
   LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc)    LT_PARAMS((size_t size))
                           = (lt_ptr (*) LT_PARAMS((size_t))) malloc;
   LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc)   LT_PARAMS((lt_ptr ptr, size_t size))
                           = (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc;
   LT_GLOBAL_DATA void   (*lt_dlfree)      LT_PARAMS((lt_ptr ptr))
                           = (void (*) LT_PARAMS((lt_ptr))) free;
   
   /* The following macros reduce the amount of typing needed to cast
      assigned memory.  */
   #if WITH_DMALLOC
   
   #define LT_DLMALLOC(tp, n)      ((tp *) xmalloc ((n) * sizeof(tp)))
   #define LT_DLREALLOC(tp, p, n)  ((tp *) xrealloc ((p), (n) * sizeof(tp)))
   #define LT_DLFREE(p)                                            \
           LT_STMT_START { if (p) (p) = (xfree (p), (lt_ptr) 0); } LT_STMT_END
   
   #define LT_EMALLOC(tp, n)       ((tp *) xmalloc ((n) * sizeof(tp)))
   #define LT_EREALLOC(tp, p, n)   ((tp *) xrealloc ((p), (n) * sizeof(tp)))
   
   #else
   
   #define LT_DLMALLOC(tp, n)      ((tp *) lt_dlmalloc ((n) * sizeof(tp)))
   #define LT_DLREALLOC(tp, p, n)  ((tp *) 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)))
   
 static const char objdir[] = LTDL_OBJDIR;  
 #ifdef  LTDL_SHLIB_EXT  
 static const char shlib_ext[] = LTDL_SHLIB_EXT;  
 #endif  #endif
   
 static const char unknown_error[] = "unknown error";  #define LT_DLMEM_REASSIGN(p, q)                 LT_STMT_START { \
 static const char dlopen_not_supported_error[] = "dlopen support not available";          if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; }   \
 static const char file_not_found_error[] = "file not found";                                                  } LT_STMT_END
 static const char no_symbols_error[] = "no symbols defined";  
 static const char cannot_open_error[] = "can't open the module";  
 static const char cannot_close_error[] = "can't close the module";  /* --- REPLACEMENT FUNCTIONS --- */
 static const char symbol_error[] = "symbol not found";  
 static const char memory_error[] = "not enough memory";  
 static const char invalid_handle_error[] = "invalid handle";  
 static const char buffer_overflow_error[] = "internal buffer overflow";  
 static const char shutdown_error[] = "library already shutdown";  
   
 #ifndef HAVE_PRELOADED_SYMBOLS  
 /* If libtool won't define it, we'd better do */  
 const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } };  
 #endif  
   
 static const char *last_error = 0;  
   
 lt_ptr_t (*lt_dlmalloc) LTDL_PARAMS((size_t size)) = (lt_ptr_t(*)LTDL_PARAMS((size_t)))malloc;  
 void     (*lt_dlfree)  LTDL_PARAMS((lt_ptr_t ptr)) = (void(*)LTDL_PARAMS((lt_ptr_t)))free;  
   
 typedef struct lt_dltype_t {  
         struct lt_dltype_t *next;  
         const char *sym_prefix; /* prefix for symbols */  
         int (*mod_init) LTDL_PARAMS((void));  
         int (*mod_exit) LTDL_PARAMS((void));  
         int (*lib_open) LTDL_PARAMS((lt_dlhandle handle, const char *filename));  
         int (*lib_close) LTDL_PARAMS((lt_dlhandle handle));  
         lt_ptr_t (*find_sym) LTDL_PARAMS((lt_dlhandle handle, const char *symbol));  
 } lt_dltype_t;  
   
 #define LTDL_TYPE_TOP 0  
   
 typedef struct lt_dlhandle_t {  
         struct lt_dlhandle_t *next;  
         lt_dltype_t *type;      /* dlopening interface */  
         char    *filename;      /* file name */  
         char    *name;          /* module name */  
         int     usage;          /* usage */  
         int     depcount;       /* number of dependencies */  
         lt_dlhandle *deplibs;   /* dependencies */  
         lt_ptr_t handle;        /* system handle */  
         lt_ptr_t system;        /* system specific data */  
 } lt_dlhandle_t;  
   
 #undef strdup  #undef strdup
 #define strdup xstrdup  #define strdup rpl_strdup
   
   static char *strdup LT_PARAMS((const char *str));
   
 static inline char *  static char *
 strdup(str)  strdup(str)
         const char *str;       const char *str;
 {  {
         char *tmp;    char *tmp = NULL;
   
         if (!str)    if (str)
                 return 0;      {
         tmp = (char*) lt_dlmalloc(strlen(str)+1);        tmp = LT_DLMALLOC (char, 1+ strlen (str));
         if (tmp)        if (tmp)
                 strcpy(tmp, str);          {
         return tmp;            strcpy(tmp, str);
           }
       }
   
     return tmp;
 }  }
   
 #if ! HAVE_STRCHR  
   
 # if HAVE_INDEX  #if ! HAVE_STRCMP
   
   #undef strcmp
   #define strcmp rpl_strcmp
   
 #  define strchr index  static int strcmp LT_PARAMS((const char *str1, const char *str2));
   
   static int
   strcmp (str1, str2)
        const char *str1;
        const char *str2;
   {
     if (str1 == str2)
       return 0;
     if (str1 == NULL)
       return -1;
     if (str2 == NULL)
       return 1;
   
 # else    for (;*str1 && *str2; ++str1, ++str2)
       {
         if (*str1 != *str2)
           break;
       }
   
 #  define strchr xstrchr    return (int)(*str1 - *str2);
   }
   #endif
   
   
   #if ! HAVE_STRCHR
   
 static inline const char*  #  if HAVE_INDEX
   #    define strchr index
   #  else
   #    define strchr rpl_strchr
   
   static const char *strchr LT_PARAMS((const char *str, int ch));
   
   static const char*
 strchr(str, ch)  strchr(str, ch)
         const char *str;       const char *str;
         int ch;       int ch;
 {  {
         const char *p;    const char *p;
   
         for (p = str; *p != (char)ch && *p != '\0'; p++)    for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p)
                 /*NOWORK*/;      /*NOWORK*/;
   
         return (*p == (char)ch) ? p : 0;    return (*p == (char)ch) ? p : 0;
 }  }
   
 # endif  #  endif
   #endif /* !HAVE_STRCHR */
   
 #endif  
   
 #if ! HAVE_STRRCHR  #if ! HAVE_STRRCHR
   
 # if HAVE_RINDEX  #  if HAVE_RINDEX
   #    define strrchr rindex
   #  else
   #    define strrchr rpl_strrchr
   
 #  define strrchr rindex  static const char *strrchr LT_PARAMS((const char *str, int ch));
   
 # else  static const char*
   strrchr(str, ch)
        const char *str;
        int ch;
   {
     const char *p, *q = NULL;
   
 #  define strrchr xstrrchr    for (p = str; *p != LT_EOS_CHAR; ++p)
       {
         if (*p == (char) ch)
           {
             q = p;
           }
       }
   
 static inline const char*    return q;
 strrchr(str, ch)  }
         const char *str;  
         int ch;  # endif
   #endif
   
   /* NOTE:  Neither bcopy nor the memcpy implementation below can
             reliably handle copying in overlapping areas of memory.  Use
             memmove (for which there is a fallback implmentation below)
             if you need that behaviour.  */
   #if ! HAVE_MEMCPY
   
   #  if HAVE_BCOPY
   #    define memcpy(dest, src, size)     bcopy (src, dest, size)
   #  else
   #    define memcpy rpl_memcpy
   
   static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
   
   static lt_ptr
   memcpy (dest, src, size)
        lt_ptr dest;
        const lt_ptr src;
        size_t size;
   {
     size_t i = 0;
   
     for (i = 0; i < size; ++i)
       {
         dest[i] = src[i];
       }
   
     return dest;
   }
   
   #  endif /* !HAVE_BCOPY */
   #endif   /* !HAVE_MEMCPY */
   
   #if ! HAVE_MEMMOVE
   #  define memmove rpl_memmove
   
   static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
   
   static lt_ptr
   memmove (dest, src, size)
        lt_ptr dest;
        const lt_ptr src;
        size_t size;
 {  {
         const char *p;    size_t i;
   
         for (p = str; *p != '\0'; p++)    if (dest < src)
                 /*NOWORK*/;      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 */
   
         while (*p != (char)ch && p >= str)  
                 p--;  
   
         return (*p == (char)ch) ? p : 0;  /* According to Alexandre Oliva <oliva@lsd.ic.unicamp.br>,
       ``realloc is not entirely portable''
      In any case we want to use the allocator supplied by the user without
      burdening them with an lt_dlrealloc function pointer to maintain.
      Instead implement our own version (with known boundary conditions)
      using lt_dlmalloc and lt_dlfree. */
   
   #undef realloc
   #define realloc rpl_realloc
   
   static lt_ptr
   realloc (ptr, size)
        lt_ptr ptr;
        size_t size;
   {
     if (size == 0)
       {
         /* For zero or less bytes, free the original memory */
         if (ptr != NULL)
           {
             lt_dlfree (ptr);
           }
   
         return (lt_ptr) 0;
       }
     else if (ptr == NULL)
       {
         /* Allow reallocation of a NULL pointer.  */
         return lt_dlmalloc (size);
       }
     else
       {
         /* Allocate a new block, copy and free the old block.  */
         lt_ptr mem = lt_dlmalloc (size);
   
         if (mem)
           {
             memcpy (mem, ptr, size);
             lt_dlfree (ptr);
           }
   
         /* Note that the contents of PTR are not damaged if there is
            insufficient memory to realloc.  */
         return mem;
       }
 }  }
   
 # endif  
   
   #if ! HAVE_ARGZ_APPEND
   #  define argz_append rpl_argz_append
   
   static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len,
                                           const char *buf, size_t buf_len));
   
   static error_t
   argz_append (pargz, pargz_len, buf, buf_len)
        char **pargz;
        size_t *pargz_len;
        const char *buf;
        size_t buf_len;
   {
     size_t argz_len;
     char  *argz;
   
     assert (pargz);
     assert (pargz_len);
     assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len));
   
     /* If nothing needs to be appended, no more work is required.  */
     if (buf_len == 0)
       return 0;
   
     /* Ensure there is enough room to append BUF_LEN.  */
     argz_len = *pargz_len + buf_len;
     argz = LT_DLREALLOC (char, *pargz, argz_len);
     if (!argz)
       return ENOMEM;
   
     /* Copy characters from BUF after terminating '\0' in ARGZ.  */
     memcpy (argz + *pargz_len, buf, buf_len);
   
     /* Assign new values.  */
     *pargz = argz;
     *pargz_len = argz_len;
   
     return 0;
   }
   #endif /* !HAVE_ARGZ_APPEND */
   
   
   #if ! HAVE_ARGZ_CREATE_SEP
   #  define argz_create_sep rpl_argz_create_sep
   
   static error_t argz_create_sep LT_PARAMS((const char *str, int delim,
                                               char **pargz, size_t *pargz_len));
   
   static error_t
   argz_create_sep (str, delim, pargz, pargz_len)
        const char *str;
        int delim;
        char **pargz;
        size_t *pargz_len;
   {
     size_t argz_len;
     char *argz = NULL;
   
     assert (str);
     assert (pargz);
     assert (pargz_len);
   
     /* Make a copy of STR, but replacing each occurence of
        DELIM with '\0'.  */
     argz_len = 1+ LT_STRLEN (str);
     if (argz_len)
       {
         const char *p;
         char *q;
   
         argz = LT_DLMALLOC (char, argz_len);
         if (!argz)
           return ENOMEM;
   
         for (p = str, q = argz; *p != LT_EOS_CHAR; ++p)
           {
             if (*p == delim)
               {
                 /* Ignore leading delimiters, and fold consecutive
                    delimiters in STR into a single '\0' in ARGZ.  */
                 if ((q > argz) && (q[-1] != LT_EOS_CHAR))
                   *q++ = LT_EOS_CHAR;
                 else
                   --argz_len;
               }
             else
               *q++ = *p;
           }
         /* Copy terminating LT_EOS_CHAR.  */
         *q = *p;
       }
   
     /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory.  */
     if (!argz_len)
       LT_DLFREE (argz);
   
     /* Assign new values.  */
     *pargz = argz;
     *pargz_len = argz_len;
   
     return 0;
   }
   #endif /* !HAVE_ARGZ_CREATE_SEP */
   
   
   #if ! HAVE_ARGZ_INSERT
   #  define argz_insert rpl_argz_insert
   
   static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len,
                                           char *before, const char *entry));
   
   static error_t
   argz_insert (pargz, pargz_len, before, entry)
        char **pargz;
        size_t *pargz_len;
        char *before;
        const char *entry;
   {
     assert (pargz);
     assert (pargz_len);
     assert (entry && *entry);
   
     /* No BEFORE address indicates ENTRY should be inserted after the
        current last element.  */
     if (!before)
       return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry));
   
     /* This probably indicates a programmer error, but to preserve
        semantics, scan back to the start of an entry if BEFORE points
        into the middle of it.  */
     while ((before >= *pargz) && (before[-1] != LT_EOS_CHAR))
       --before;
   
     {
       size_t entry_len    = 1+ LT_STRLEN (entry);
       size_t argz_len     = *pargz_len + entry_len;
       size_t offset       = before - *pargz;
       char   *argz        = LT_DLREALLOC (char, *pargz, argz_len);
   
       if (!argz)
         return ENOMEM;
   
       /* Make BEFORE point to the equivalent offset in ARGZ that it
          used to have in *PARGZ incase realloc() moved the block.  */
       before = argz + offset;
   
       /* Move the ARGZ entries starting at BEFORE up into the new
          space at the end -- making room to copy ENTRY into the
          resulting gap.  */
       memmove (before + entry_len, before, *pargz_len - offset);
       memcpy  (before, entry, entry_len);
   
       /* Assign new values.  */
       *pargz = argz;
       *pargz_len = argz_len;
     }
   
     return 0;
   }
   #endif /* !HAVE_ARGZ_INSERT */
   
   
   #if ! HAVE_ARGZ_NEXT
   #  define argz_next rpl_argz_next
   
   static char *argz_next LT_PARAMS((char *argz, size_t argz_len,
                                       const char *entry));
   
   static char *
   argz_next (argz, argz_len, entry)
        char *argz;
        size_t argz_len;
        const char *entry;
   {
     assert ((argz && argz_len) || (!argz && !argz_len));
   
     if (entry)
       {
         /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address
            within the ARGZ vector.  */
         assert ((!argz && !argz_len)
                 || ((argz <= entry) && (entry < (argz + argz_len))));
   
         /* Move to the char immediately after the terminating
            '\0' of ENTRY.  */
         entry = 1+ strchr (entry, LT_EOS_CHAR);
   
         /* Return either the new ENTRY, or else NULL if ARGZ is
            exhausted.  */
         return (entry >= argz + argz_len) ? 0 : (char *) entry;
       }
     else
       {
         /* This should probably be flagged as a programmer error,
            since starting an argz_next loop with the iterator set
            to ARGZ is safer.  To preserve semantics, handle the NULL
            case by returning the start of ARGZ (if any).  */
         if (argz_len > 0)
           return argz;
         else
           return 0;
       }
   }
   #endif /* !HAVE_ARGZ_NEXT */
   
   
   
   #if ! HAVE_ARGZ_STRINGIFY
   #  define argz_stringify rpl_argz_stringify
   
   static void argz_stringify LT_PARAMS((char *argz, size_t argz_len,
                                          int sep));
   
   static void
   argz_stringify (argz, argz_len, sep)
        char *argz;
        size_t argz_len;
        int sep;
   {
     assert ((argz && argz_len) || (!argz && !argz_len));
   
     if (sep)
       {
         --argz_len;               /* don't stringify the terminating EOS */
         while (--argz_len > 0)
           {
             if (argz[argz_len] == LT_EOS_CHAR)
               argz[argz_len] = sep;
           }
       }
   }
   #endif /* !HAVE_ARGZ_STRINGIFY */
   
   
   
   
   /* --- TYPE DEFINITIONS -- */
   
   
   /* This type is used for the array of caller data sets in each handler. */
   typedef struct {
     lt_dlcaller_id        key;
     lt_ptr                data;
   } lt_caller_data;
   
   
   
   
   /* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */
   
   
   /* Extract the diagnostic strings from the error table macro in the same
      order as the enumerated indices in ltdl.h. */
   
   static const char *lt_dlerror_strings[] =
     {
   #define LT_ERROR(name, diagnostic)      (diagnostic),
       lt_dlerror_table
   #undef LT_ERROR
   
       0
     };
   
   /* This structure is used for the list of registered loaders. */
   struct lt_dlloader {
     struct lt_dlloader   *next;
     const char           *loader_name;    /* identifying name for each loader */
     const char           *sym_prefix;     /* prefix for symbols */
     lt_module_open       *module_open;
     lt_module_close      *module_close;
     lt_find_sym          *find_sym;
     lt_dlloader_exit     *dlloader_exit;
     lt_user_data          dlloader_data;
   };
   
   struct lt_dlhandle_struct {
     struct lt_dlhandle_struct   *next;
     lt_dlloader          *loader;         /* dlopening interface */
     lt_dlinfo             info;
     int                   depcount;       /* number of dependencies */
     lt_dlhandle          *deplibs;        /* dependencies */
     lt_module             module;         /* system module handle */
     lt_ptr                system;         /* system specific data */
     lt_caller_data       *caller_data;    /* per caller associated data */
     int                   flags;          /* various boolean stats */
   };
   
   /* Various boolean flags can be stored in the flags field of an
      lt_dlhandle_struct... */
   #define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag))
   #define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag))
   
   #define LT_DLRESIDENT_FLAG          (0x01 << 0)
   /* ...add more flags here... */
   
   #define LT_DLIS_RESIDENT(handle)    LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG)
   
   
   #define LT_DLSTRERROR(name)     lt_dlerror_strings[LT_CONC(LT_ERROR_,name)]
   
   static  const char      objdir[]                = LTDL_OBJDIR;
   static  const char      archive_ext[]           = LTDL_ARCHIVE_EXT;
   #ifdef  LTDL_SHLIB_EXT
   static  const char      shlib_ext[]             = LTDL_SHLIB_EXT;
   #endif
   #ifdef  LTDL_SYSSEARCHPATH
   static  const char      sys_search_path[]       = LTDL_SYSSEARCHPATH;
 #endif  #endif
   
 #if HAVE_LIBDL  
   
   
   /* --- 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     = NULL;
   static  lt_dlmutex_unlock   *lt_dlmutex_unlock_func   = NULL;
   static  lt_dlmutex_seterror *lt_dlmutex_seterror_func = NULL;
   static  lt_dlmutex_geterror *lt_dlmutex_geterror_func = NULL;
   static  const char          *lt_dllast_error          = NULL;
   
   
   /* Either set or reset the mutex functions.  Either all the arguments must
      be valid functions, or else all can be NULL to turn off locking entirely.
      The registered functions should be manipulating a static global lock
      from the lock() and unlock() callbacks, which needs to be reentrant.  */
   int
   lt_dlmutex_register (lock, unlock, seterror, geterror)
        lt_dlmutex_lock *lock;
        lt_dlmutex_unlock *unlock;
        lt_dlmutex_seterror *seterror;
        lt_dlmutex_geterror *geterror;
   {
     lt_dlmutex_unlock *old_unlock = unlock;
     int                errors     = 0;
   
     /* Lock using the old lock() callback, if any.  */
     LT_DLMUTEX_LOCK ();
   
     if ((lock && unlock && seterror && geterror)
         || !(lock || unlock || seterror || geterror))
       {
         lt_dlmutex_lock_func     = lock;
         lt_dlmutex_unlock_func   = unlock;
         lt_dlmutex_geterror_func = geterror;
       }
     else
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS));
         ++errors;
       }
   
     /* Use the old unlock() callback we saved earlier, if any.  Otherwise
        record any errors using internal storage.  */
     if (old_unlock)
       (*old_unlock) ();
   
     /* Return the number of errors encountered during the execution of
        this function.  */
     return errors;
   }
   
   
   
   
   /* --- ERROR HANDLING --- */
   
   
   static  const char    **user_error_strings      = NULL;
   static  int             errorcount              = LT_ERROR_MAX;
   
   int
   lt_dladderror (diagnostic)
        const char *diagnostic;
   {
     int           errindex = 0;
     int           result   = -1;
     const char  **temp     = NULL;
   
     assert (diagnostic);
   
     LT_DLMUTEX_LOCK ();
   
     errindex = errorcount - LT_ERROR_MAX;
     temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex);
     if (temp)
       {
         user_error_strings                = temp;
         user_error_strings[errindex]      = diagnostic;
         result                            = errorcount++;
       }
   
     LT_DLMUTEX_UNLOCK ();
   
     return result;
   }
   
   int
   lt_dlseterror (errindex)
        int errindex;
   {
     int           errors   = 0;
   
     LT_DLMUTEX_LOCK ();
   
     if (errindex >= errorcount || errindex < 0)
       {
         /* Ack!  Error setting the error message! */
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE));
         ++errors;
       }
     else if (errindex < LT_ERROR_MAX)
       {
         /* No error setting the error message! */
         LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]);
       }
     else
       {
         /* No error setting the error message! */
         LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]);
       }
   
     LT_DLMUTEX_UNLOCK ();
   
     return errors;
   }
   
   static lt_ptr
   lt_emalloc (size)
        size_t size;
   {
     lt_ptr mem = lt_dlmalloc (size);
     if (size && !mem)
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
     return mem;
   }
   
   static lt_ptr
   lt_erealloc (addr, size)
        lt_ptr addr;
        size_t size;
   {
     lt_ptr mem = realloc (addr, size);
     if (size && !mem)
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
     return mem;
   }
   
   static char *
   lt_estrdup (str)
        const char *str;
   {
     char *copy = strdup (str);
     if (LT_STRLEN (str) && !copy)
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
     return copy;
   }
   
   
   
   
   /* --- DLOPEN() INTERFACE LOADER --- */
   
   
   /* The Cygwin dlopen implementation prints a spurious error message to
      stderr if its call to LoadLibrary() fails for any reason.  We can
      mitigate this by not using the Cygwin implementation, and falling
      back to our own LoadLibrary() wrapper. */
   #if HAVE_LIBDL && !defined(__CYGWIN__)
   
 /* dynamic linking with dlopen/dlsym */  /* dynamic linking with dlopen/dlsym */
   
 #if HAVE_DLFCN_H  #if HAVE_DLFCN_H
 # include <dlfcn.h>  #  include <dlfcn.h>
   #endif
   
   #if HAVE_SYS_DL_H
   #  include <sys/dl.h>
 #endif  #endif
   
 #ifdef RTLD_GLOBAL  #ifdef RTLD_GLOBAL
 # define LTDL_GLOBAL    RTLD_GLOBAL  #  define LT_GLOBAL             RTLD_GLOBAL
 #else  #else
 # ifdef DL_GLOBAL  #  ifdef DL_GLOBAL
 #  define LTDL_GLOBAL   DL_GLOBAL  #    define LT_GLOBAL           DL_GLOBAL
 # else  #  endif
 #  define LTDL_GLOBAL   0  #endif /* !RTLD_GLOBAL */
 # endif  #ifndef LT_GLOBAL
 #endif  #  define LT_GLOBAL             0
   #endif /* !LT_GLOBAL */
   
 /* We may have to define LTDL_LAZY_OR_NOW in the command line if we  /* We may have to define LT_LAZY_OR_NOW in the command line if we
    find out it does not work in some platform. */     find out it does not work in some platform. */
 #ifndef LTDL_LAZY_OR_NOW  #ifndef LT_LAZY_OR_NOW
 # ifdef RTLD_LAZY  #  ifdef RTLD_LAZY
 #  define LTDL_LAZY_OR_NOW      RTLD_LAZY  #    define LT_LAZY_OR_NOW      RTLD_LAZY
 # else  #  else
 #  ifdef DL_LAZY  #    ifdef DL_LAZY
 #   define LTDL_LAZY_OR_NOW     DL_LAZY  #      define LT_LAZY_OR_NOW    DL_LAZY
   #    endif
   #  endif /* !RTLD_LAZY */
   #endif
   #ifndef LT_LAZY_OR_NOW
   #  ifdef RTLD_NOW
   #    define LT_LAZY_OR_NOW      RTLD_NOW
 #  else  #  else
 #   ifdef RTLD_NOW  
 #    define LTDL_LAZY_OR_NOW    RTLD_NOW  
 #   else  
 #    ifdef DL_NOW  #    ifdef DL_NOW
 #     define LTDL_LAZY_OR_NOW   DL_NOW  #      define LT_LAZY_OR_NOW    DL_NOW
 #    else  
 #     define LTDL_LAZY_OR_NOW   0  
 #    endif  #    endif
 #   endif  #  endif /* !RTLD_NOW */
 #  endif  
 # endif  
 #endif  #endif
   #ifndef LT_LAZY_OR_NOW
   #  define LT_LAZY_OR_NOW        0
   #endif /* !LT_LAZY_OR_NOW */
   
 static int  #if HAVE_DLERROR
 sys_dl_init LTDL_PARAMS((void))  #  define DLERROR(arg)  dlerror ()
 {  #else
         return 0;  #  define DLERROR(arg)  LT_DLSTRERROR (arg)
 }  #endif
   
 static int  static lt_module
 sys_dl_exit LTDL_PARAMS((void))  sys_dl_open (loader_data, filename)
        lt_user_data loader_data;
        const char *filename;
 {  {
         return 0;    lt_module   module   = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW);
   
     if (!module)
       {
         LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN));
       }
   
     return module;
 }  }
   
 static int  static int
 sys_dl_open (handle, filename)  sys_dl_close (loader_data, module)
         lt_dlhandle handle;       lt_user_data loader_data;
         const char *filename;       lt_module module;
 {  {
         handle->handle = dlopen(filename, LTDL_GLOBAL | LTDL_LAZY_OR_NOW);    int errors = 0;
         if (!handle->handle) {  
 #if HAVE_DLERROR    if (dlclose (module) != 0)
                 last_error = dlerror();      {
 #else        LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE));
                 last_error = cannot_open_error;        ++errors;
 #endif      }
                 return 1;  
         }    return errors;
         return 0;  
 }  }
   
 static int  static lt_ptr
 sys_dl_close (handle)  sys_dl_sym (loader_data, module, symbol)
         lt_dlhandle handle;       lt_user_data loader_data;
        lt_module module;
        const char *symbol;
 {  {
         if (dlclose(handle->handle) != 0) {    lt_ptr address = dlsym (module, symbol);
 #if HAVE_DLERROR  
                 last_error = dlerror();  
 #else  
                 last_error = cannot_close_error;  
 #endif  
                 return 1;  
         }  
         return 0;  
 }  
   
 static lt_ptr_t    if (!address)
 sys_dl_sym (handle, symbol)      {
         lt_dlhandle handle;        LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND));
         const char *symbol;      }
 {  
         lt_ptr_t address = dlsym(handle->handle, symbol);    return address;
           
         if (!address)  
 #if HAVE_DLERROR  
                 last_error = dlerror();  
 #else  
                 last_error = symbol_error;  
 #endif  
         return address;  
 }  }
   
 static  static struct lt_user_dlloader sys_dl =
 lt_dltype_t    {
 #ifdef NEED_USCORE  #  ifdef NEED_USCORE
 sys_dl = { LTDL_TYPE_TOP, "_", sys_dl_init, sys_dl_exit,      "_",
         sys_dl_open, sys_dl_close, sys_dl_sym };  #  else
 #else      0,
 sys_dl = { LTDL_TYPE_TOP, 0, sys_dl_init, sys_dl_exit,  #  endif
         sys_dl_open, sys_dl_close, sys_dl_sym };      sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 };
 #endif  
   
 #undef LTDL_TYPE_TOP  
 #define LTDL_TYPE_TOP &sys_dl  
   
 #endif  #endif /* HAVE_LIBDL */
   
   
   
   /* --- SHL_LOAD() INTERFACE LOADER --- */
   
 #if HAVE_SHL_LOAD  #if HAVE_SHL_LOAD
   
 /* dynamic linking with shl_load (HP-UX) (comments from gmodule) */  /* dynamic linking with shl_load (HP-UX) (comments from gmodule) */
   
 #ifdef HAVE_DL_H  #ifdef HAVE_DL_H
 #include <dl.h>  #  include <dl.h>
 #endif  #endif
   
 /* some flags are missing on some systems, so we provide  /* some flags are missing on some systems, so we provide
Line 335  sys_dl = { LTDL_TYPE_TOP, 0, sys_dl_init Line 1042  sys_dl = { LTDL_TYPE_TOP, 0, sys_dl_init
  * BIND_DEFERRED   - Delay code symbol resolution until actual reference.   * BIND_DEFERRED   - Delay code symbol resolution until actual reference.
  *   *
  * Optionally:   * Optionally:
  * BIND_FIRST      - Place the library at the head of the symbol search order.   * BIND_FIRST      - Place the library at the head of the symbol search
  * BIND_NONFATAL   - The default BIND_IMMEDIATE behavior is to treat all unsatisfied   *                   order.
  *                   symbols as fatal.  This flag allows binding of unsatisfied code   * BIND_NONFATAL   - The default BIND_IMMEDIATE behavior is to treat all
  *                   symbols to be deferred until use.   *                   unsatisfied symbols as fatal.  This flag allows
  *                   [Perl: For certain libraries, like DCE, deferred binding often   *                   binding of unsatisfied code symbols to be deferred
  *                   causes run time problems.  Adding BIND_NONFATAL to BIND_IMMEDIATE   *                   until use.
  *                   still allows unresolved references in situations like this.]   *                   [Perl: For certain libraries, like DCE, deferred
  * BIND_NOSTART    - Do not call the initializer for the shared library when the   *                   binding often causes run time problems. Adding
  *                   library is loaded, nor on a future call to shl_unload().   *                   BIND_NONFATAL to BIND_IMMEDIATE still allows
  * BIND_VERBOSE    - Print verbose messages concerning possible unsatisfied symbols.   *                   unresolved references in situations like this.]
    * BIND_NOSTART    - Do not call the initializer for the shared library
    *                   when the library is loaded, nor on a future call to
    *                   shl_unload().
    * BIND_VERBOSE    - Print verbose messages concerning possible
    *                   unsatisfied symbols.
  *   *
  * hp9000s700/hp9000s800:   * hp9000s700/hp9000s800:
  * BIND_RESTRICTED - Restrict symbols visible by the library to those present at   * BIND_RESTRICTED - Restrict symbols visible by the library to those
  *                   library load time.   *                   present at library load time.
  * DYNAMIC_PATH    - Allow the loader to dynamically search for the library specified   * DYNAMIC_PATH    - Allow the loader to dynamically search for the
  *                   by the path argument.   *                   library specified by the path argument.
  */   */
   
 #ifndef DYNAMIC_PATH  #ifndef DYNAMIC_PATH
 #define DYNAMIC_PATH    0  #  define DYNAMIC_PATH          0
 #endif  /* DYNAMIC_PATH */  #endif
 #ifndef BIND_RESTRICTED  #ifndef BIND_RESTRICTED
 #define BIND_RESTRICTED 0  #  define BIND_RESTRICTED       0
 #endif  /* BIND_RESTRICTED */  #endif
   
 #define LTDL_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH)  #define LT_BIND_FLAGS   (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH)
   
 static int  static lt_module
 sys_shl_init LTDL_PARAMS((void))  sys_shl_open (loader_data, filename)
        lt_user_data loader_data;
        const char *filename;
 {  {
         return 0;    static shl_t self = (shl_t) 0;
     lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L);
   
     /* Since searching for a symbol against a NULL module handle will also
        look in everything else that was already loaded and exported with
        the -E compiler flag, we always cache a handle saved before any
        modules are loaded.  */
     if (!self)
       {
         lt_ptr address;
         shl_findsym (&self, "main", TYPE_UNDEFINED, &address);
       }
   
     if (!filename)
       {
         module = self;
       }
     else
       {
         module = shl_load (filename, LT_BIND_FLAGS, 0L);
   
         if (!module)
           {
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
           }
       }
   
     return module;
 }  }
   
 static int  static int
 sys_shl_exit LTDL_PARAMS((void))  sys_shl_close (loader_data, module)
        lt_user_data loader_data;
        lt_module module;
 {  {
         return 0;    int errors = 0;
   
     if (module && (shl_unload ((shl_t) (module)) != 0))
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
         ++errors;
       }
   
     return errors;
 }  }
   
 static int  static lt_ptr
 sys_shl_open (handle, filename)  sys_shl_sym (loader_data, module, symbol)
         lt_dlhandle handle;       lt_user_data loader_data;
         const char *filename;       lt_module module;
 {       const char *symbol;
         handle->handle = shl_load(filename, LTDL_BIND_FLAGS, 0L);  {
         if (!handle->handle) {    lt_ptr address = NULL;
                 last_error = cannot_open_error;  
                 return 1;    /* sys_shl_open should never return a NULL module handle */
     if (module == (lt_module) 0)
     {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
     }
     else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address))
       {
         if (!address)
           {
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
         }          }
         return 0;      }
   
     return address;
   }
   
   static struct lt_user_dlloader sys_shl = {
     0, sys_shl_open, sys_shl_close, sys_shl_sym, 0, 0
   };
   
   #endif /* HAVE_SHL_LOAD */
   
   
   
   
   /* --- LOADLIBRARY() INTERFACE LOADER --- */
   
   #ifdef __WINDOWS__
   
   /* dynamic linking for Win32 */
   
   #include <windows.h>
   
   /* Forward declaration; required to implement handle search below. */
   static lt_dlhandle handles;
   
   static lt_module
   sys_wll_open (loader_data, filename)
        lt_user_data loader_data;
        const char *filename;
   {
     lt_dlhandle   cur;
     lt_module     module     = NULL;
     const char   *errormsg   = NULL;
     char         *searchname = NULL;
     char         *ext;
     char          self_name_buf[MAX_PATH];
   
     if (!filename)
       {
         /* Get the name of main module */
         *self_name_buf = '\0';
         GetModuleFileName (NULL, self_name_buf, sizeof (self_name_buf));
         filename = ext = self_name_buf;
       }
     else
       {
         ext = strrchr (filename, '.');
       }
   
     if (ext)
       {
         /* FILENAME already has an extension. */
         searchname = lt_estrdup (filename);
       }
     else
       {
         /* Append a `.' to stop Windows from adding an
            implicit `.dll' extension. */
         searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename));
         if (searchname)
           sprintf (searchname, "%s.", filename);
       }
     if (!searchname)
       return 0;
   
   #if __CYGWIN__
     {
       char wpath[MAX_PATH];
       cygwin_conv_to_full_win32_path(searchname, wpath);
       module = LoadLibrary(wpath);
     }
   #else
     module = LoadLibrary (searchname);
   #endif
     LT_DLFREE (searchname);
   
     /* libltdl expects this function to fail if it is unable
        to physically load the library.  Sadly, LoadLibrary
        will search the loaded libraries for a match and return
        one of them if the path search load fails.
   
        We check whether LoadLibrary is returning a handle to
        an already loaded module, and simulate failure if we
        find one. */
     LT_DLMUTEX_LOCK ();
     cur = handles;
     while (cur)
       {
         if (!cur->module)
           {
             cur = NULL;
             break;
           }
   
         if (cur->module == module)
           {
             break;
           }
   
         cur = cur->next;
     }
     LT_DLMUTEX_UNLOCK ();
   
     if (cur || !module)
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
         module = NULL;
       }
   
     return module;
 }  }
   
 static int  static int
 sys_shl_close (handle)  sys_wll_close (loader_data, module)
         lt_dlhandle handle;       lt_user_data loader_data;
        lt_module module;
 {  {
         if (shl_unload((shl_t) (handle->handle)) != 0) {    int         errors   = 0;
                 last_error = cannot_close_error;  
                 return 1;    if (FreeLibrary(module) == 0)
         }      {
         return 0;        LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
         ++errors;
       }
   
     return errors;
 }  }
   
 static lt_ptr_t  static lt_ptr
 sys_shl_sym (handle, symbol)  sys_wll_sym (loader_data, module, symbol)
         lt_dlhandle handle;       lt_user_data loader_data;
         const char *symbol;       lt_module module;
 {       const char *symbol;
         lt_ptr_t address;  {
     lt_ptr      address  = GetProcAddress (module, symbol);
         if (handle->handle && shl_findsym((shl_t*) &(handle->handle),  
             symbol, TYPE_UNDEFINED, &address) == 0)    if (!address)
                 if (address)      {
                         return address;        LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
         last_error = symbol_error;      }
         return 0;  
     return address;
 }  }
   
 static  static struct lt_user_dlloader sys_wll = {
 lt_dltype_t    0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0
 sys_shl = { LTDL_TYPE_TOP, 0, sys_shl_init, sys_shl_exit,  };
         sys_shl_open, sys_shl_close, sys_shl_sym };  
   
 #undef LTDL_TYPE_TOP  #endif /* __WINDOWS__ */
 #define LTDL_TYPE_TOP &sys_shl  
   
   
   
   /* --- LOAD_ADD_ON() INTERFACE LOADER --- */
   
   
   #ifdef __BEOS__
   
   /* dynamic linking for BeOS */
   
   #include <kernel/image.h>
   
   static lt_module
   sys_bedl_open (loader_data, filename)
        lt_user_data loader_data;
        const char *filename;
   {
     image_id image = 0;
   
     if (filename)
       {
         image = load_add_on (filename);
       }
     else
       {
         image_info info;
         int32 cookie = 0;
         if (get_next_image_info (0, &cookie, &info) == B_OK)
           image = load_add_on (info.name);
       }
   
     if (image <= 0)
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
         image = 0;
       }
   
     return (lt_module) image;
   }
   
   static int
   sys_bedl_close (loader_data, module)
        lt_user_data loader_data;
        lt_module module;
   {
     int errors = 0;
   
     if (unload_add_on ((image_id) module) != B_OK)
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
         ++errors;
       }
   
     return errors;
   }
   
   static lt_ptr
   sys_bedl_sym (loader_data, module, symbol)
        lt_user_data loader_data;
        lt_module module;
        const char *symbol;
   {
     lt_ptr address = NULL;
     image_id image = (image_id) module;
   
     if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK)
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
         address = NULL;
       }
   
     return address;
   }
   
   static struct lt_user_dlloader sys_bedl = {
     0, sys_bedl_open, sys_bedl_close, sys_bedl_sym, 0, 0
   };
   
   #endif /* __BEOS__ */
   
   
   
   
   /* --- DLD_LINK() INTERFACE LOADER --- */
   
 #endif  
   
 #if HAVE_DLD  #if HAVE_DLD
   
Line 431  sys_shl = { LTDL_TYPE_TOP, 0, sys_shl_in Line 1388  sys_shl = { LTDL_TYPE_TOP, 0, sys_shl_in
 #include <dld.h>  #include <dld.h>
 #endif  #endif
   
 static int  static lt_module
 sys_dld_init LTDL_PARAMS((void))  sys_dld_open (loader_data, filename)
        lt_user_data loader_data;
        const char *filename;
 {  {
         return 0;    lt_module module = strdup (filename);
 }  
   
 static int    if (dld_link (filename) != 0)
 sys_dld_exit LTDL_PARAMS((void))      {
 {        LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
         return 0;        LT_DLFREE (module);
 }        module = NULL;
       }
   
 static int    return module;
 sys_dld_open (handle, filename)  
         lt_dlhandle handle;  
         const char *filename;  
 {  
         handle->handle = strdup(filename);  
         if (!handle->handle) {  
                 last_error = memory_error;  
                 return 1;  
         }  
         if (dld_link(filename) != 0) {  
                 last_error = cannot_open_error;  
                 lt_dlfree(handle->handle);  
                 return 1;  
         }  
         return 0;  
 }  }
   
 static int  static int
 sys_dld_close (handle)  sys_dld_close (loader_data, module)
         lt_dlhandle handle;       lt_user_data loader_data;
        lt_module module;
 {  {
         if (dld_unlink_by_file((char*)(handle->handle), 1) != 0) {    int errors = 0;
                 last_error = cannot_close_error;  
                 return 1;    if (dld_unlink_by_file ((char*)(module), 1) != 0)
         }      {
         lt_dlfree(handle->filename);        LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
         return 0;        ++errors;
       }
     else
       {
         LT_DLFREE (module);
       }
   
     return errors;
 }  }
   
 static lt_ptr_t  static lt_ptr
 sys_dld_sym (handle, symbol)  sys_dld_sym (loader_data, module, symbol)
         lt_dlhandle handle;       lt_user_data loader_data;
         const char *symbol;       lt_module module;
        const char *symbol;
 {  {
         lt_ptr_t address = dld_get_func(symbol);    lt_ptr address = dld_get_func (symbol);
           
         if (!address)    if (!address)
                 last_error = symbol_error;      {
         return address;        LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
       }
   
     return address;
 }  }
   
 static  static struct lt_user_dlloader sys_dld = {
 lt_dltype_t    0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0
 sys_dld = { LTDL_TYPE_TOP, 0, sys_dld_init, sys_dld_exit,  };
         sys_dld_open, sys_dld_close, sys_dld_sym };  
   
 #undef LTDL_TYPE_TOP  #endif /* HAVE_DLD */
 #define LTDL_TYPE_TOP &sys_dld  
   
 #endif  
   
 #ifdef _WIN32  
   
 /* dynamic linking for Win32 */  
   /* --- DLPREOPEN() INTERFACE LOADER --- */
   
 #include <windows.h>  
   /* emulate dynamic linking using preloaded_symbols */
   
   typedef struct lt_dlsymlists_t
   {
     struct lt_dlsymlists_t       *next;
     const lt_dlsymlist           *syms;
   } lt_dlsymlists_t;
   
   static  const lt_dlsymlist     *default_preloaded_symbols       = NULL;
   static  lt_dlsymlists_t        *preloaded_symbols               = NULL;
   
 static int  static int
 sys_wll_init LTDL_PARAMS((void))  presym_init (loader_data)
        lt_user_data loader_data;
 {  {
         return 0;    int errors = 0;
   
     LT_DLMUTEX_LOCK ();
   
     preloaded_symbols = NULL;
     if (default_preloaded_symbols)
       {
         errors = lt_dlpreload (default_preloaded_symbols);
       }
   
     LT_DLMUTEX_UNLOCK ();
   
     return errors;
 }  }
   
 static int  static int
 sys_wll_exit LTDL_PARAMS((void))  presym_free_symlists ()
 {  {
         return 0;    lt_dlsymlists_t *lists;
   
     LT_DLMUTEX_LOCK ();
   
     lists = preloaded_symbols;
     while (lists)
       {
         lt_dlsymlists_t   *tmp = lists;
   
         lists = lists->next;
         LT_DLFREE (tmp);
       }
     preloaded_symbols = NULL;
   
     LT_DLMUTEX_UNLOCK ();
   
     return 0;
 }  }
   
 /* Forward declaration; required to implement handle search below. */  static int
 static lt_dlhandle handles;  presym_exit (loader_data)
        lt_user_data loader_data;
   {
     presym_free_symlists ();
     return 0;
   }
   
 static int  static int
 sys_wll_open (handle, filename)  presym_add_symlist (preloaded)
         lt_dlhandle handle;       const lt_dlsymlist *preloaded;
         const char *filename;  {
 {    lt_dlsymlists_t *tmp;
         lt_dlhandle cur;    lt_dlsymlists_t *lists;
         char *searchname = NULL;    int              errors   = 0;
         char *ext = strrchr(filename, '.');  
     LT_DLMUTEX_LOCK ();
         if (ext) {  
                 /* FILENAME already has an extension. */    lists = preloaded_symbols;
                 searchname = strdup(filename);    while (lists)
         } else {      {
                 /* Append a `.' to stop Windows from adding an        if (lists->syms == preloaded)
                    implicit `.dll' extension. */          {
                 searchname = (char*)lt_dlmalloc(2+ strlen(filename));            goto done;
                 strcpy(searchname, filename);          }
                 strcat(searchname, ".");        lists = lists->next;
         }      }
       
         handle->handle = LoadLibrary(searchname);    tmp = LT_EMALLOC (lt_dlsymlists_t, 1);
         lt_dlfree(searchname);    if (tmp)
               {
         /* libltdl expects this function to fail if it is unable        memset (tmp, 0, sizeof(lt_dlsymlists_t));
            to physically load the library.  Sadly, LoadLibrary        tmp->syms = preloaded;
            will search the loaded libraries for a match and return        tmp->next = preloaded_symbols;
            one of them if the path search load fails.        preloaded_symbols = tmp;
       }
            We check whether LoadLibrary is returning a handle to    else
            an already loaded module, and simulate failure if we      {
            find one. */        ++errors;
         cur = handles;      }
         while (cur) {  
                 if (!cur->handle) {   done:
                         cur = 0;    LT_DLMUTEX_UNLOCK ();
                         break;    return errors;
                 }  }
                 if (cur->handle == handle->handle)  
                         break;  static lt_module
                 cur = cur->next;  presym_open (loader_data, filename)
        lt_user_data loader_data;
        const char *filename;
   {
     lt_dlsymlists_t *lists;
     lt_module        module = (lt_module) 0;
   
     LT_DLMUTEX_LOCK ();
     lists = preloaded_symbols;
   
     if (!lists)
       {
         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@";
       }
   
     while (lists)
       {
         const lt_dlsymlist *syms = lists->syms;
   
         while (syms->name)
           {
             if (!syms->address && strcmp(syms->name, filename) == 0)
               {
                 module = (lt_module) syms;
                 goto done;
               }
             ++syms;
           }
   
         lists = lists->next;
       }
   
     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
   
    done:
     LT_DLMUTEX_UNLOCK ();
     return module;
   }
   
   static int
   presym_close (loader_data, module)
        lt_user_data loader_data;
        lt_module module;
   {
     /* Just to silence gcc -Wall */
     module = NULL;
     return 0;
   }
   
   static lt_ptr
   presym_sym (loader_data, module, symbol)
        lt_user_data loader_data;
        lt_module module;
        const char *symbol;
   {
     lt_dlsymlist *syms = (lt_dlsymlist*) module;
   
     ++syms;
     while (syms->address)
       {
         if (strcmp(syms->name, symbol) == 0)
           {
             return syms->address;
           }
   
       ++syms;
     }
   
     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
   
     return 0;
   }
   
   static struct lt_user_dlloader presym = {
     0, presym_open, presym_close, presym_sym, presym_exit, 0
   };
   
   
   
   
   
   /* --- 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_argz_insertdir     LT_PARAMS((char **pargz,
                                                    size_t *pargz_len,
                                                    const char *dirnam,
                                                    struct dirent *dp));
   static  int     lt_dlpath_insertdir   LT_PARAMS((char **ppath,
                                                    char *before,
                                                    const char *dir));
   static  int     list_files_by_dir     LT_PARAMS((const char *dirnam,
                                                    char **pargz,
                                                    size_t *pargz_len));
   static  int     file_not_found        LT_PARAMS((void));
   
   static  char           *user_search_path= NULL;
   static  lt_dlloader    *loaders         = NULL;
   static  lt_dlhandle     handles         = NULL;
   static  int             initialized     = 0;
   
   /* Initialize libltdl. */
   int
   lt_dlinit ()
   {
     int         errors   = 0;
   
     LT_DLMUTEX_LOCK ();
   
     /* Initialize only at first call. */
     if (++initialized == 1)
       {
         handles = NULL;
         user_search_path = NULL; /* empty search path */
   
   #if HAVE_LIBDL && !defined(__CYGWIN__)
         errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen");
   #endif
   #if HAVE_SHL_LOAD
         errors += lt_dlloader_add (lt_dlloader_next (0), &sys_shl, "dlopen");
   #endif
   #ifdef __WINDOWS__
         errors += lt_dlloader_add (lt_dlloader_next (0), &sys_wll, "dlopen");
   #endif
   #ifdef __BEOS__
         errors += lt_dlloader_add (lt_dlloader_next (0), &sys_bedl, "dlopen");
   #endif
   #if HAVE_DLD
         errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dld, "dld");
   #endif
         errors += lt_dlloader_add (lt_dlloader_next (0), &presym, "dlpreload");
   
         if (presym_init (presym.dlloader_data))
           {
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER));
             ++errors;
           }
         else if (errors != 0)
           {
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED));
             ++errors;
         }          }
       }
   
         if (cur || !handle->handle) {    LT_DLMUTEX_UNLOCK ();
                 last_error = cannot_open_error;  
                 return 1;    return errors;
   }
   
   int
   lt_dlpreload (preloaded)
        const lt_dlsymlist *preloaded;
   {
     int errors = 0;
   
     if (preloaded)
       {
         errors = presym_add_symlist (preloaded);
       }
     else
       {
         presym_free_symlists();
   
         LT_DLMUTEX_LOCK ();
         if (default_preloaded_symbols)
           {
             errors = lt_dlpreload (default_preloaded_symbols);
         }          }
         LT_DLMUTEX_UNLOCK ();
       }
   
         return 0;    return errors;
   }
   
   int
   lt_dlpreload_default (preloaded)
        const lt_dlsymlist *preloaded;
   {
     LT_DLMUTEX_LOCK ();
     default_preloaded_symbols = preloaded;
     LT_DLMUTEX_UNLOCK ();
     return 0;
   }
   
   int
   lt_dlexit ()
   {
     /* shut down libltdl */
     lt_dlloader *loader;
     int          errors   = 0;
   
     LT_DLMUTEX_LOCK ();
     loader = loaders;
   
     if (!initialized)
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN));
         ++errors;
         goto done;
       }
   
     /* shut down only at last call. */
     if (--initialized == 0)
       {
         int       level;
   
         while (handles && LT_DLIS_RESIDENT (handles))
           {
             handles = handles->next;
           }
   
         /* close all modules */
         for (level = 1; handles; ++level)
           {
             lt_dlhandle cur = handles;
             int saw_nonresident = 0;
   
             while (cur)
               {
                 lt_dlhandle tmp = cur;
                 cur = cur->next;
                 if (!LT_DLIS_RESIDENT (tmp))
                   saw_nonresident = 1;
                 if (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level)
                   {
                     if (lt_dlclose (tmp))
                       {
                         ++errors;
                       }
                   }
               }
             /* done if only resident modules are left */
             if (!saw_nonresident)
               break;
           }
   
         /* close all loaders */
         while (loader)
           {
             lt_dlloader *next = loader->next;
             lt_user_data data = loader->dlloader_data;
             if (loader->dlloader_exit && loader->dlloader_exit (data))
               {
                 ++errors;
               }
   
             LT_DLMEM_REASSIGN (loader, next);
           }
         loaders = NULL;
       }
   
    done:
     LT_DLMUTEX_UNLOCK ();
     return errors;
 }  }
   
 static int  static int
 sys_wll_close (handle)  tryall_dlopen (handle, filename)
         lt_dlhandle handle;       lt_dlhandle *handle;
        const char *filename;
 {  {
         if (FreeLibrary(handle->handle) == 0) {    lt_dlhandle    cur;
                 last_error = cannot_close_error;    lt_dlloader   *loader;
                 return 1;    const char    *saved_error;
         }    int            errors         = 0;
         return 0;  
     LT_DLMUTEX_GETERROR (saved_error);
     LT_DLMUTEX_LOCK ();
   
     cur    = handles;
     loader = loaders;
   
     /* check whether the module was already opened */
     while (cur)
       {
         /* try to dlopen the program itself? */
         if (!cur->info.filename && !filename)
           {
             break;
           }
   
         if (cur->info.filename && filename
             && strcmp (cur->info.filename, filename) == 0)
           {
             break;
           }
   
         cur = cur->next;
       }
   
     if (cur)
       {
         ++cur->info.ref_count;
         *handle = cur;
         goto done;
       }
   
     cur = *handle;
     if (filename)
       {
         cur->info.filename = lt_estrdup (filename);
         if (!cur->info.filename)
           {
             ++errors;
             goto done;
           }
       }
     else
       {
         cur->info.filename = NULL;
       }
   
     while (loader)
       {
         lt_user_data data = loader->dlloader_data;
   
         cur->module = loader->module_open (data, filename);
   
         if (cur->module != NULL)
           {
             break;
           }
         loader = loader->next;
       }
   
     if (!loader)
       {
         LT_DLFREE (cur->info.filename);
         ++errors;
         goto done;
       }
   
     cur->loader   = loader;
     LT_DLMUTEX_SETERROR (saved_error);
   
    done:
     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    = NULL;
     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) == NULL);
   #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)
       {
         error += tryall_dlopen_module (handle,
                                        (const char *) 0, prefix, filename);
       }
     else if (tryall_dlopen (handle, filename) != 0)
       {
         ++error;
       }
   
     LT_DLFREE (filename);
     return error;
 }  }
   
 static lt_ptr_t  static int
 sys_wll_sym (handle, symbol)  find_module (handle, dir, libdir, dlname, old_name, installed)
         lt_dlhandle handle;       lt_dlhandle *handle;
         const char *symbol;       const char *dir;
 {       const char *libdir;
         lt_ptr_t address = GetProcAddress(handle->handle, symbol);       const char *dlname;
                const char *old_name;
         if (!address)       int installed;
                 last_error = symbol_error;  {
         return address;    /* 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.  */
 static    if (old_name && tryall_dlopen (handle, old_name) == 0)
 lt_dltype_t      {
 sys_wll = { LTDL_TYPE_TOP, 0, sys_wll_init, sys_wll_exit,        return 0;
         sys_wll_open, sys_wll_close, sys_wll_sym };      }
   
     /* Try to open the dynamic library.  */
     if (dlname)
       {
         /* try to open the installed module */
         if (installed && libdir)
           {
             if (tryall_dlopen_module (handle,
                                       (const char *) 0, libdir, dlname) == 0)
               return 0;
           }
   
         /* try to open the not-installed module */
         if (!installed)
           {
             if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0)
               return 0;
           }
   
         /* maybe it was moved to another directory */
         {
             if (tryall_dlopen_module (handle,
                                       (const char *) 0, dir, dlname) == 0)
               return 0;
         }
       }
   
     return 1;
   }
   
   
   static int
   canonicalize_path (path, pcanonical)
        const char *path;
        char **pcanonical;
   {
     char *canonical = NULL;
   
     assert (path && *path);
     assert (pcanonical);
   
     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)
             {
               if ((dest == 0)
                   || (path[1+ src] == LT_PATHSEP_CHAR)
                   || (path[1+ src] == LT_EOS_CHAR))
                 continue;
             }
   
           /* Anything other than a directory separator is copied verbatim.  */
           if ((path[src] != '/')
   #ifdef LT_DIRSEP_CHAR
               && (path[src] != LT_DIRSEP_CHAR)
   #endif
               )
             {
               canonical[dest++] = path[src];
             }
           /* 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] != '/'))
             {
               canonical[dest++] = '/';
             }
         }
   
       /* Add an end-of-string marker at the end.  */
       canonical[dest] = LT_EOS_CHAR;
     }
   
     /* Assign new value.  */
     *pcanonical = canonical;
   
     return 0;
   }
   
   static int
   argzize_path (path, pargz, pargz_len)
        const char *path;
        char **pargz;
        size_t *pargz_len;
   {
     error_t error;
   
     assert (path);
     assert (pargz);
     assert (pargz_len);
   
     if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len)))
       {
         switch (error)
           {
           case ENOMEM:
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
             break;
           default:
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
             break;
           }
   
         return 1;
       }
   
     return 0;
   }
   
   /* 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;
        const char *base_name;
        foreach_callback_func *func;
        lt_ptr data1;
        lt_ptr data2;
   {
     int    result         = 0;
     int    filenamesize   = 0;
     size_t lenbase        = LT_STRLEN (base_name);
     size_t argz_len       = 0;
     char *argz            = NULL;
     char *filename        = NULL;
     char *canonical       = NULL;
   
     LT_DLMUTEX_LOCK ();
   
     if (!search_path || !*search_path)
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
         goto cleanup;
       }
   
     if (canonicalize_path (search_path, &canonical) != 0)
       goto cleanup;
   
     if (argzize_path (canonical, &argz, &argz_len) != 0)
       goto cleanup;
   
     {
       char *dir_name = NULL;
       while ((dir_name = argz_next (argz, argz_len, dir_name)))
         {
           size_t lendir = LT_STRLEN (dir_name);
   
           if (lendir +1 +lenbase >= filenamesize)
           {
             LT_DLFREE (filename);
             filenamesize  = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */
             filename      = LT_EMALLOC (char, filenamesize);
             if (!filename)
               goto cleanup;
           }
   
           assert (filenamesize > lendir);
           strcpy (filename, dir_name);
   
           if (base_name && *base_name)
             {
               if (filename[lendir -1] != '/')
                 filename[lendir++] = '/';
               strcpy (filename +lendir, base_name);
             }
   
           if ((result = (*func) (filename, data1, data2)))
             {
               break;
             }
         }
     }
   
    cleanup:
     LT_DLFREE (argz);
     LT_DLFREE (canonical);
     LT_DLFREE (filename);
   
     LT_DLMUTEX_UNLOCK ();
   
     return result;
   }
   
   /* 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 == NULL) ? -1 : 1;
       }
   
     return is_done;
   }
   
   static FILE *
   find_file (search_path, base_name, pdir)
        const char *search_path;
        const char *base_name;
        char **pdir;
   {
     FILE *file = NULL;
   
     foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file);
   
     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           notfound        = access (filename, R_OK);
   
     /* Bail out if file cannot be read...  */
     if (notfound)
       return 0;
   
     /* Try to dlopen the file, but do not continue searching in any
        case.  */
     if (tryall_dlopen (handle, filename) != 0)
       *handle = NULL;
   
     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)
        lt_dlhandle handle;
        char *deplibs;
   {
   #if LTDL_DLOPEN_DEPLIBS
     char  *p, *save_search_path = NULL;
     int   depcount = 0;
     int   i;
     char  **names = NULL;
   #endif
     int   errors = 0;
   
     handle->depcount = 0;
   
   #if LTDL_DLOPEN_DEPLIBS
     if (!deplibs)
       {
         return errors;
       }
     ++errors;
   
     LT_DLMUTEX_LOCK ();
     if (user_search_path)
       {
         save_search_path = lt_estrdup (user_search_path);
         if (!save_search_path)
           goto cleanup;
       }
   
     /* extract search paths and count deplibs */
     p = deplibs;
     while (*p)
       {
         if (!isspace ((int) *p))
           {
             char *end = p+1;
             while (*end && !isspace((int) *end))
               {
                 ++end;
               }
   
             if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0)
               {
                 char save = *end;
                 *end = '\0'; /* set a temporary string terminator */
                 if (lt_dladdsearchdir(p+2))
                   {
                     goto cleanup;
                   }
                 *end = save;
               }
             else
               {
                 ++depcount;
               }
   
             p = end;
           }
         else
           {
             ++p;
           }
       }
   
     /* restore the old search path */
     LT_DLFREE (user_search_path);
     user_search_path = save_search_path;
   
     LT_DLMUTEX_UNLOCK ();
   
     if (!depcount)
       {
         errors = 0;
         goto cleanup;
       }
   
     names = LT_EMALLOC (char *, depcount * sizeof (char*));
     if (!names)
       goto cleanup;
   
     /* now only extract the actual deplibs */
     depcount = 0;
     p = deplibs;
     while (*p)
       {
         if (isspace ((int) *p))
           {
             ++p;
           }
         else
           {
             char *end = p+1;
             while (*end && !isspace ((int) *end))
               {
                 ++end;
               }
   
             if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0)
               {
                 char *name;
                 char save = *end;
                 *end = '\0'; /* set a temporary string terminator */
                 if (strncmp(p, "-l", 2) == 0)
                   {
                     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);
                   }
                 else
                   name = lt_estrdup(p);
   
 #undef LTDL_TYPE_TOP                if (!name)
 #define LTDL_TYPE_TOP &sys_wll                  goto cleanup_names;
   
 #endif                names[depcount++] = name;
                 *end = save;
               }
             p = end;
           }
       }
   
 #ifdef __BEOS__    /* load the deplibs (in reverse order)
        At this stage, don't worry if the deplibs do not load correctly,
        they may already be statically linked into the loading application
        for instance.  There will be a more enlightening error message
        later on if the loaded module cannot resolve all of its symbols.  */
     if (depcount)
       {
         int       j = 0;
   
 /* dynamic linking for BeOS */        handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount);
         if (!handle->deplibs)
           goto cleanup;
   
 #include <kernel/image.h>        for (i = 0; i < depcount; ++i)
           {
             handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]);
             if (handle->deplibs[j])
               {
                 ++j;
               }
           }
   
         handle->depcount  = j;    /* Number of successfully loaded deplibs */
         errors            = 0;
       }
   
    cleanup_names:
     for (i = 0; i < depcount; ++i)
       {
         LT_DLFREE (names[i]);
       }
   
    cleanup:
     LT_DLFREE (names);
   #endif
   
     return errors;
   }
   
 static int  static int
 sys_bedl_init LTDL_PARAMS((void))  unload_deplibs (handle)
        lt_dlhandle handle;
 {  {
         return 0;    int i;
     int errors = 0;
   
     if (handle->depcount)
       {
         for (i = 0; i < handle->depcount; ++i)
           {
             if (!LT_DLIS_RESIDENT (handle->deplibs[i]))
               {
                 errors += lt_dlclose (handle->deplibs[i]);
               }
           }
       }
   
     return errors;
 }  }
   
 static int  static int
 sys_bedl_exit LTDL_PARAMS((void))  trim (dest, str)
        char **dest;
        const char *str;
 {  {
         return 0;    /* remove the leading and trailing "'" from str
        and store the result in dest */
     const char *end   = strrchr (str, '\'');
     size_t len        = LT_STRLEN (str);
     char *tmp;
   
     LT_DLFREE (*dest);
   
     if (len > 3 && str[0] == '\'')
       {
         tmp = LT_EMALLOC (char, end - str);
         if (!tmp)
           return 1;
   
         strncpy(tmp, &str[1], (end - str) - 1);
         tmp[len-3] = LT_EOS_CHAR;
         *dest = tmp;
       }
     else
       {
         *dest = NULL;
       }
   
     return 0;
 }  }
   
 static int  static int
 sys_bedl_open (handle, filename)  free_vars (dlname, oldname, libdir, deplibs)
         lt_dlhandle handle;       char *dlname;
         const char *filename;       char *oldname;
 {       char *libdir;
         image_id image = 0;       char *deplibs;
           {
         if (filename) {    LT_DLFREE (dlname);
                 image = load_add_on(filename);    LT_DLFREE (oldname);
         } else {    LT_DLFREE (libdir);
                 image_info info;     LT_DLFREE (deplibs);
                 int32 cookie = 0;   
                 if (get_next_image_info(0, &cookie, &info) == B_OK)    return 0;
                         image = load_add_on(info.name);  
         }  
         if (image <= 0) {  
                 last_error = cannot_open_error;  
                 return 1;  
         }  
         handle->handle = (void*) image;  
         return 0;  
 }  }
   
 static int  static int
 sys_bedl_close (handle)  try_dlopen (phandle, filename)
         lt_dlhandle handle;       lt_dlhandle *phandle;
        const char *filename;
 {  {
         if (unload_add_on((image_id)handle->handle) != B_OK) {    const char *  ext             = NULL;
                 last_error = cannot_close_error;    const char *  saved_error     = NULL;
                 return 1;    char *        canonical       = NULL;
         }    char *        base_name       = NULL;
         return 0;    char *        dir             = NULL;
 }    char *        name            = NULL;
     int           errors          = 0;
     lt_dlhandle   newhandle;
   
 static lt_ptr_t    assert (phandle);
 sys_bedl_sym (handle, symbol)    assert (*phandle == NULL);
         lt_dlhandle handle;  
         const char *symbol;  
 {  
         lt_ptr_t address = 0;  
         image_id image = (image_id)handle->handle;  
      
         if (get_image_symbol(image, symbol, B_SYMBOL_TYPE_ANY,  
                 &address) != B_OK) {  
                 last_error = symbol_error;  
                 return 0;  
         }  
         return address;  
 }  
   
 static  
 lt_dltype_t  
 sys_bedl = { LTDL_TYPE_TOP, 0, sys_bedl_init, sys_bedl_exit,  
         sys_bedl_open, sys_bedl_close, sys_bedl_sym };  
   
 #undef LTDL_TYPE_TOP    LT_DLMUTEX_GETERROR (saved_error);
 #define LTDL_TYPE_TOP &sys_bedl  
   
     /* dlopen self? */
     if (!filename)
       {
         *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
         if (*phandle == NULL)
           return 1;
   
         memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
         newhandle = *phandle;
   
         /* lt_dlclose()ing yourself is very bad!  Disallow it.  */
         LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG);
   
         if (tryall_dlopen (&newhandle, 0) != 0)
           {
             LT_DLFREE (*phandle);
             return 1;
           }
   
         goto register_handle;
       }
   
     assert (filename && *filename);
   
     /* Doing this immediately allows internal functions to safely
        assume only canonicalized paths are passed.  */
     if (canonicalize_path (filename, &canonical) != 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.  */
     base_name = strrchr (canonical, '/');
     if (base_name)
       {
         size_t dirlen = (1+ base_name) - canonical;
   
         dir = LT_EMALLOC (char, 1+ dirlen);
         if (!dir)
           {
             ++errors;
             goto cleanup;
           }
   
         strncpy (dir, canonical, dirlen);
         dir[dirlen] = LT_EOS_CHAR;
   
         ++base_name;
       }
     else
       LT_DLMEM_REASSIGN (base_name, canonical);
   
     assert (base_name && *base_name);
   
     /* Check whether we are opening a libtool module (.la extension).  */
     ext = strrchr (base_name, '.');
     if (ext && strcmp (ext, archive_ext) == 0)
       {
         /* this seems to be a libtool module */
         FILE *    file     = NULL;
         char *    dlname   = NULL;
         char *    old_name = NULL;
         char *    libdir   = NULL;
         char *    deplibs  = NULL;
         char *    line     = NULL;
         size_t    line_len;
   
         /* if we can't find the installed flag, it is probably an
            installed libtool archive, produced with an old version
            of libtool */
         int       installed = 1;
   
         /* extract the module name from the file name */
         name = LT_EMALLOC (char, ext - base_name + 1);
         if (!name)
           {
             ++errors;
             goto cleanup;
           }
   
         /* canonicalize the module name */
         {
           size_t i;
           for (i = 0; i < ext - base_name; ++i)
             {
               if (isalnum ((int)(base_name[i])))
                 {
                   name[i] = base_name[i];
                 }
               else
                 {
                   name[i] = '_';
                 }
             }
           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
            prescribed paths.  Otherwise (or in any case if the module was not
            yet found) try opening just the module name as passed.  */
         if (!dir)
           {
             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)
               {
                 search_path = getenv (LTDL_SEARCHPATH_VAR);
                 if (search_path)
                   file = find_file (search_path, base_name, &dir);
               }
   
   #ifdef LTDL_SHLIBPATH_VAR
             if (!file)
               {
                 search_path = getenv (LTDL_SHLIBPATH_VAR);
                 if (search_path)
                   file = find_file (search_path, base_name, &dir);
               }
   #endif
   #ifdef LTDL_SYSSEARCHPATH
             if (!file && sys_search_path)
               {
                 file = find_file (sys_search_path, base_name, &dir);
               }
   #endif
           }
         if (!file)
           {
             file = fopen (filename, LT_READTEXT_MODE);
           }
   
         /* If we didn't find the file by now, it really isn't there.  Set
            the status flag, and bail out.  */
         if (!file)
           {
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
             ++errors;
             goto cleanup;
           }
   
         line_len = LT_FILENAME_MAX;
         line = LT_EMALLOC (char, line_len);
         if (!line)
           {
             fclose (file);
             ++errors;
             goto cleanup;
           }
   
         /* read the .la file */
         while (!feof (file))
           {
             if (!fgets (line, (int) line_len, file))
               {
                 break;
               }
   
             /* Handle the case where we occasionally need to read a line
                that is longer than the initial buffer size.  */
             while (line[LT_STRLEN(line) -1] != '\n')
               {
                 line = LT_DLREALLOC (char, line, line_len *2);
                 if (!fgets (&line[line_len -1], (int) line_len +1, file))
                   {
                     break;
                   }
                 line_len *= 2;
               }
   
             if (line[0] == '\n' || line[0] == '#')
               {
                 continue;
               }
   
   #undef  STR_DLNAME
   #define STR_DLNAME      "dlname="
             if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0)
               {
                 errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]);
               }
   
   #undef  STR_OLD_LIBRARY
   #define STR_OLD_LIBRARY "old_library="
             else if (strncmp (line, STR_OLD_LIBRARY,
                               sizeof (STR_OLD_LIBRARY) - 1) == 0)
               {
                 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)
               {
                 errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]);
               }
   
   #undef  STR_DL_DEPLIBS
   #define STR_DL_DEPLIBS  "dependency_libs="
             else if (strncmp (line, STR_DL_DEPLIBS,
                               sizeof (STR_DL_DEPLIBS) - 1) == 0)
               {
                 errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]);
               }
             else if (strcmp (line, "installed=yes\n") == 0)
               {
                 installed = 1;
               }
             else if (strcmp (line, "installed=no\n") == 0)
               {
                 installed = 0;
               }
   
   #undef  STR_LIBRARY_NAMES
   #define STR_LIBRARY_NAMES "library_names="
             else if (! dlname && strncmp (line, STR_LIBRARY_NAMES,
                                           sizeof (STR_LIBRARY_NAMES) - 1) == 0)
               {
                 char *last_libname;
                 errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]);
                 if (!errors
                     && dlname
                     && (last_libname = strrchr (dlname, ' ')) != NULL)
                   {
                     last_libname = lt_estrdup (last_libname + 1);
                     if (!last_libname)
                       {
                         ++errors;
                         goto cleanup;
                       }
                     LT_DLMEM_REASSIGN (dlname, last_libname);
                   }
               }
   
             if (errors)
               break;
           }
   
         fclose (file);
         LT_DLFREE (line);
   
         /* allocate the handle */
         *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
         if (*phandle == NULL)
           ++errors;
   
         if (errors)
           {
             free_vars (dlname, old_name, libdir, deplibs);
             LT_DLFREE (*phandle);
             goto cleanup;
           }
   
         assert (*phandle);
   
         memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
         if (load_deplibs (*phandle, deplibs) == 0)
           {
             newhandle = *phandle;
             /* find_module may replace newhandle */
             if (find_module (&newhandle, dir, libdir, dlname, old_name, installed))
               {
                 unload_deplibs (*phandle);
                 ++errors;
               }
           }
         else
           {
             ++errors;
           }
   
         free_vars (dlname, old_name, libdir, deplibs);
         if (errors)
           {
             LT_DLFREE (*phandle);
             goto cleanup;
           }
   
         if (*phandle != newhandle)
           {
             unload_deplibs (*phandle);
           }
       }
     else
       {
         /* not a libtool module */
         *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
         if (*phandle == NULL)
           {
             ++errors;
             goto cleanup;
           }
   
         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_handle (user_search_path, base_name, &newhandle)
                      && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name,
                                       &newhandle)
   #ifdef LTDL_SHLIBPATH_VAR
                      && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name,
                                       &newhandle)
   #endif
   #ifdef LTDL_SYSSEARCHPATH
                      && !find_handle (sys_search_path, base_name, &newhandle)
 #endif  #endif
                      )))
           {
             if (tryall_dlopen (&newhandle, filename) != 0)
               {
                 newhandle = NULL;
               }
           }
   
         if (!newhandle)
           {
             LT_DLFREE (*phandle);
             ++errors;
             goto cleanup;
           }
       }
   
    register_handle:
     LT_DLMEM_REASSIGN (*phandle, newhandle);
   
     if ((*phandle)->info.ref_count == 0)
       {
         (*phandle)->info.ref_count        = 1;
         LT_DLMEM_REASSIGN ((*phandle)->info.name, name);
   
         LT_DLMUTEX_LOCK ();
         (*phandle)->next          = handles;
         handles                   = *phandle;
         LT_DLMUTEX_UNLOCK ();
       }
   
     LT_DLMUTEX_SETERROR (saved_error);
   
    cleanup:
     LT_DLFREE (dir);
     LT_DLFREE (name);
     LT_DLFREE (canonical);
   
 /* emulate dynamic linking using preloaded_symbols */    return errors;
   }
   
 typedef struct lt_dlsymlists_t {  lt_dlhandle
         struct lt_dlsymlists_t *next;  lt_dlopen (filename)
         const lt_dlsymlist *syms;       const char *filename;
 } lt_dlsymlists_t;  {
     lt_dlhandle handle = NULL;
   
 static const lt_dlsymlist *default_preloaded_symbols = 0;    /* Just incase we missed a code path in try_dlopen() that reports
 static lt_dlsymlists_t *preloaded_symbols = 0;       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.  */
 static int  static int
 presym_init LTDL_PARAMS((void))  file_not_found ()
 {  {
         preloaded_symbols = 0;    const char *error = NULL;
         if (default_preloaded_symbols)  
                 return lt_dlpreload(default_preloaded_symbols);    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          = NULL;
     char *        tmp             = NULL;
     char *        ext             = NULL;
     size_t        len;
     int           errors          = 0;
   
     if (!filename)
       {
         return lt_dlopen (filename);
       }
   
     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
         ))
       {
         return lt_dlopen (filename);
       }
   
     /* First try appending ARCHIVE_EXT.  */
     tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1);
     if (!tmp)
       return 0;
   
     strcpy (tmp, filename);
     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 ()))
       {
         LT_DLFREE (tmp);
         return handle;
       }
   
   #ifdef LTDL_SHLIB_EXT
     /* Try appending SHLIB_EXT.   */
     if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext))
       {
         LT_DLFREE (tmp);
         tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1);
         if (!tmp)
         return 0;          return 0;
   
         strcpy (tmp, filename);
       }
     else
       {
         tmp[len] = LT_EOS_CHAR;
       }
   
     strcat(tmp, shlib_ext);
     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 ()))
       {
         LT_DLFREE (tmp);
         return handle;
       }
   #endif
   
     /* 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;
 }  }
   
   
 static int  static int
 presym_free_symlists LTDL_PARAMS((void))  lt_argz_insert (pargz, pargz_len, before, entry)
        char **pargz;
        size_t *pargz_len;
        char *before;
        const char *entry;
 {  {
         lt_dlsymlists_t *lists = preloaded_symbols;    error_t error;
           
         while (lists) {    if ((error = argz_insert (pargz, pargz_len, before, entry)))
                 lt_dlsymlists_t *tmp = lists;      {
                         switch (error)
                 lists = lists->next;          {
                 lt_dlfree(tmp);          case ENOMEM:
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
             break;
           default:
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
             break;
         }          }
         preloaded_symbols = 0;        return 1;
         return 0;      }
   
     return 0;
 }  }
   
 static int  static int
 presym_exit LTDL_PARAMS((void))  lt_argz_insertinorder (pargz, pargz_len, entry)
        char **pargz;
        size_t *pargz_len;
        const char *entry;
 {  {
         presym_free_symlists();    char *before = NULL;
         return 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);
 }  }
   
 static int  static int
 presym_add_symlist (preloaded)  lt_argz_insertdir (pargz, pargz_len, dirnam, dp)
         const lt_dlsymlist *preloaded;       char **pargz;
        size_t *pargz_len;
        const char *dirnam;
        struct dirent *dp;
 {  {
         lt_dlsymlists_t *tmp;    char   *buf       = NULL;
         lt_dlsymlists_t *lists = preloaded_symbols;    size_t buf_len    = 0;
             char   *end       = NULL;
         while (lists) {    size_t end_offset = 0;
                 if (lists->syms == preloaded)    size_t dir_len    = 0;
                         return 0;    int    errors     = 0;
                 lists = lists->next;  
         }    assert (pargz);
     assert (pargz_len);
         tmp = (lt_dlsymlists_t*) lt_dlmalloc(sizeof(lt_dlsymlists_t));    assert (dp);
         if (!tmp) {  
                 last_error = memory_error;    dir_len = LT_STRLEN (dirnam);
                 return 1;    end     = dp->d_name + LT_D_NAMLEN(dp);
         }  
         tmp->syms = preloaded;    /* Ignore version numbers.  */
         tmp->next = 0;    {
         if (!preloaded_symbols)      char *p;
                 preloaded_symbols = tmp;      for (p = end; p -1 > dp->d_name; --p)
         else {        if (strchr (".0123456789", p[-1]) == 0)
                 /* append to the end */          break;
                 lists = preloaded_symbols;  
                 while (lists->next)      if (*p == '.')
                         lists = lists->next;        end = p;
                 lists->next = tmp;    }
   
     /* Ignore filename extension.  */
     {
       char *p;
       for (p = end -1; p > dp->d_name; --p)
         if (*p == '.')
           {
             end = p;
             break;
         }          }
         return 0;    }
   
     /* 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;
 }  }
   
 static int  static int
 presym_open (handle, filename)  list_files_by_dir (dirnam, pargz, pargz_len)
         lt_dlhandle handle;       const char *dirnam;
         const char *filename;       char **pargz;
 {       size_t *pargz_len;
         lt_dlsymlists_t *lists = preloaded_symbols;  {
     DIR   *dirp     = NULL;
         if (!lists) {    int    errors   = 0;
                 last_error = no_symbols_error;  
                 return 1;    assert (dirnam && *dirnam);
         }    assert (pargz);
         if (!filename)    assert (pargz_len);
                 filename = "@PROGRAM@";    assert (dirnam[LT_STRLEN(dirnam) -1] != '/');
         while (lists) {  
                 const lt_dlsymlist *syms = lists->syms;    dirp = opendir (dirnam);
             if (dirp)
                 while (syms->name) {      {
                         if (!syms->address &&        struct dirent *dp = NULL;
                             strcmp(syms->name, filename) == 0) {  
                                 handle->handle = (lt_ptr_t) syms;        while ((dp = readdir (dirp)))
                                 return 0;          if (dp->d_name[0] != '.')
                         }            if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp))
                         syms++;              {
                 }                ++errors;
                 lists = lists->next;                break;
         }              }
         last_error = file_not_found_error;  
         return 1;        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  static int
 presym_close (handle)  foreachfile_callback (dirname, data1, data2)
         lt_dlhandle handle;       char *dirname;
        lt_ptr data1;
        lt_ptr data2;
 {  {
         /* Just to silence gcc -Wall */    int (*func) LT_PARAMS((const char *filename, lt_ptr data))
         handle = 0;          = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1;
         return 0;  
 }  
   
 static lt_ptr_t    int     is_done  = 0;
 presym_sym (handle, symbol)    char   *argz     = NULL;
         lt_dlhandle handle;    size_t  argz_len = 0;
         const char *symbol;  
 {    if (list_files_by_dir (dirname, &argz, &argz_len) != 0)
         lt_dlsymlist *syms = (lt_dlsymlist*)(handle->handle);      goto cleanup;
     if (!argz)
         syms++;      goto cleanup;
         while (syms->address) {  
                 if (strcmp(syms->name, symbol) == 0)  
                         return syms->address;  
                 syms++;  
         }  
         last_error = symbol_error;  
         return 0;  
 }  
   
 static    {
 lt_dltype_t      char *filename = NULL;
 presym = { LTDL_TYPE_TOP, 0, presym_init, presym_exit,      while ((filename = argz_next (argz, argz_len, filename)))
            presym_open, presym_close, presym_sym };        if ((is_done = (*func) (filename, data2)))
           break;
 #undef LTDL_TYPE_TOP    }
 #define LTDL_TYPE_TOP &presym  
   
 static char *user_search_path = 0;  
 static lt_dlhandle handles = 0;  
 static int initialized = 0;  
   
 static lt_dltype_t *types = LTDL_TYPE_TOP;   cleanup:
 #undef LTDL_TYPE_TOP    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  int
 lt_dlinit LTDL_PARAMS((void))  lt_dlforeachfile (search_path, func, data)
 {       const char *search_path;
         /* initialize libltdl */       int (*func) LT_PARAMS ((const char *filename, lt_ptr data));
         lt_dltype_t **type = &types;       lt_ptr data;
         int typecount = 0;  {
     int is_done = 0;
         if (initialized) {      /* Initialize only at first call. */  
                 initialized++;    if (search_path)
                 return 0;      {
         }        /* If a specific path was passed, search only the directories
         handles = 0;           listed in it.  */
         user_search_path = 0; /* empty search path */        is_done = foreach_dirinpath (search_path, 0,
                                      foreachfile_callback, func, data);
         while (*type) {      }
                 if ((*type)->mod_init())    else
                         *type = (*type)->next; /* Remove it from the list */      {
                 else {        /* Otherwise search the default paths.  */
                         type = &(*type)->next; /* Keep it */        is_done = foreach_dirinpath (user_search_path, 0,
                         typecount++;                                     foreachfile_callback, func, data);
                 }        if (!is_done)
           {
             is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0,
                                          foreachfile_callback, func, data);
         }          }
         if (typecount == 0) {  
                 last_error = dlopen_not_supported_error;  #ifdef LTDL_SHLIBPATH_VAR
                 return 1;        if (!is_done)
           {
             is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0,
                                          foreachfile_callback, func, data);
         }          }
         last_error = 0;  #endif
         initialized = 1;  #ifdef LTDL_SYSSEARCHPATH
         return 0;        if (!is_done)
           {
             is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0,
                                          foreachfile_callback, func, data);
           }
   #endif
       }
   
     return is_done;
 }  }
   
 int  int
 lt_dlpreload (preloaded)  lt_dlclose (handle)
         const lt_dlsymlist *preloaded;       lt_dlhandle handle;
 {  {
         if (preloaded)    lt_dlhandle cur, last;
                 return presym_add_symlist(preloaded);    int errors = 0;
         presym_free_symlists();  
         if (default_preloaded_symbols)    LT_DLMUTEX_LOCK ();
                 return lt_dlpreload(default_preloaded_symbols);  
         return 0;    /* check whether the handle is valid */
     last = cur = handles;
     while (cur && handle != cur)
       {
         last = cur;
         cur = cur->next;
       }
   
     if (!cur)
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
         ++errors;
         goto done;
       }
   
     handle->info.ref_count--;
   
     /* Note that even with resident modules, we must track the ref_count
        correctly incase the user decides to reset the residency flag
        later (even though the API makes no provision for that at the
        moment).  */
     if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle))
       {
         lt_user_data data = handle->loader->dlloader_data;
   
         if (handle != handles)
           {
             last->next = handle->next;
           }
         else
           {
             handles = handle->next;
           }
   
         errors += handle->loader->module_close (data, handle->module);
         errors += unload_deplibs(handle);
   
         /* It is up to the callers to free the data itself.  */
         LT_DLFREE (handle->caller_data);
   
         LT_DLFREE (handle->info.filename);
         LT_DLFREE (handle->info.name);
         LT_DLFREE (handle);
   
         goto done;
       }
   
     if (LT_DLIS_RESIDENT (handle))
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE));
         ++errors;
       }
   
    done:
     LT_DLMUTEX_UNLOCK ();
   
     return errors;
 }  }
   
 int  lt_ptr
 lt_dlpreload_default (preloaded)  lt_dlsym (handle, symbol)
         const lt_dlsymlist *preloaded;       lt_dlhandle handle;
        const char *symbol;
 {  {
         default_preloaded_symbols = preloaded;    size_t lensym;
         return 0;    char  lsym[LT_SYMBOL_LENGTH];
     char  *sym;
     lt_ptr address;
     lt_user_data data;
   
     if (!handle)
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
         return 0;
       }
   
     if (!symbol)
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
         return 0;
       }
   
     lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix)
                                           + LT_STRLEN (handle->info.name);
   
     if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH)
       {
         sym = lsym;
       }
     else
       {
         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;
     if (handle->info.name)
       {
         const char *saved_error;
   
         LT_DLMUTEX_GETERROR (saved_error);
   
         /* this is a libtool module */
         if (handle->loader->sym_prefix)
           {
             strcpy(sym, handle->loader->sym_prefix);
             strcat(sym, handle->info.name);
           }
         else
           {
             strcpy(sym, handle->info.name);
           }
   
         strcat(sym, "_LTX_");
         strcat(sym, symbol);
   
         /* try "modulename_LTX_symbol" */
         address = handle->loader->find_sym (data, handle->module, sym);
         if (address)
           {
             if (sym != lsym)
               {
                 LT_DLFREE (sym);
               }
             return address;
           }
         LT_DLMUTEX_SETERROR (saved_error);
       }
   
     /* otherwise try "symbol" */
     if (handle->loader->sym_prefix)
       {
         strcpy(sym, handle->loader->sym_prefix);
         strcat(sym, symbol);
       }
     else
       {
         strcpy(sym, symbol);
       }
   
     address = handle->loader->find_sym (data, handle->module, sym);
     if (sym != lsym)
       {
         LT_DLFREE (sym);
       }
   
     return address;
 }  }
   
 int  const char *
 lt_dlexit LTDL_PARAMS((void))  lt_dlerror ()
 {  {
         /* shut down libltdl */    const char *error;
         lt_dltype_t *type = types;  
         int     errors;    LT_DLMUTEX_GETERROR (error);
             LT_DLMUTEX_SETERROR (0);
         if (!initialized) {  
                 last_error = shutdown_error;    return error ? error : LT_DLSTRERROR (UNKNOWN);
                 return 1;  
         }  
         if (initialized != 1) { /* shut down only at last call. */  
                 initialized--;  
                 return 0;  
         }  
         /* close all modules */  
         errors = 0;  
         while (handles) {  
                 /* FIXME: what if a module depends on another one? */  
                 if (lt_dlclose(handles))  
                         errors++;  
         }  
         initialized = 0;  
         while (type) {  
                 if (type->mod_exit())  
                         errors++;  
                 type = type->next;  
         }  
         return errors;  
 }  }
   
 static int  static int
 tryall_dlopen (handle, filename)  lt_dlpath_insertdir (ppath, before, dir)
         lt_dlhandle *handle;       char **ppath;
         const char *filename;       char *before;
        const char *dir;
 {  {
         lt_dlhandle cur;    int    errors         = 0;
         lt_dltype_t *type = types;    char  *canonical      = NULL;
         const char *saved_error = last_error;    char  *argz           = NULL;
             size_t argz_len       = 0;
         /* check whether the module was already opened */  
         cur = handles;    assert (ppath);
         while (cur) {    assert (dir && *dir);
                 if (!cur->filename && !filename)  
                         break;    if (canonicalize_path (dir, &canonical) != 0)
                 if (cur->filename && filename &&       {
                     strcmp(cur->filename, filename) == 0)        ++errors;
                         break;        goto cleanup;
                 cur = cur->next;      }
         }  
         if (cur) {    assert (canonical && *canonical);
                 cur->usage++;  
                 *handle = cur;    /* If *PPATH is empty, set it to DIR.  */
                 return 0;    if (*ppath == NULL)
         }      {
                 assert (!before);         /* BEFORE cannot be set without PPATH.  */
         cur = *handle;        assert (dir);             /* Without DIR, don't call this function!  */
         if (filename) {  
                 cur->filename = strdup(filename);        *ppath = lt_estrdup (dir);
                 if (!cur->filename) {        if (*ppath == NULL)
                         last_error = memory_error;          ++errors;
                         return 1;  
                 }        return errors;
         } else      }
                 cur->filename = 0;  
         while (type) {    assert (ppath && *ppath);
                 if (type->lib_open(cur, filename) == 0)  
                         break;    if (argzize_path (*ppath, &argz, &argz_len) != 0)
                 type = type->next;      {
         }        ++errors;
         if (!type) {        goto cleanup;
                 if (cur->filename)      }
                         lt_dlfree(cur->filename);  
                 return 1;    /* Convert BEFORE into an equivalent offset into ARGZ.  This only works
         }       if *PPATH is already canonicalized, and hence does not change length
         cur->type = type;       with respect to ARGZ.  We canonicalize each entry as it is added to
         last_error = saved_error;       the search path, and don't call this function with (uncanonicalized)
         return 0;       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;
 }  }
   
 static int  int
 find_module (handle, dir, libdir, dlname, old_name, installed)  lt_dladdsearchdir (search_dir)
         lt_dlhandle *handle;       const char *search_dir;
         const char *dir;  {
         const char *libdir;    int errors = 0;
         const char *dlname;  
         const char *old_name;    if (search_dir && *search_dir)
         int installed;      {
 {        LT_DLMUTEX_LOCK ();
         int     error;        if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)
         char    *filename;          ++errors;
         /* try to open the old library first; if it was dlpreopened,         LT_DLMUTEX_UNLOCK ();
            we want the preopened version of it, even if a dlopenable      }
            module is available */  
         if (old_name && tryall_dlopen(handle, old_name) == 0)    return errors;
                 return 0;  
         /* try to open the dynamic library */  
         if (dlname) {  
                 /* try to open the installed module */  
                 if (installed && libdir) {  
                         filename = (char*)  
                                 lt_dlmalloc(strlen(libdir)+1+strlen(dlname)+1);  
                         if (!filename) {  
                                 last_error = memory_error;  
                                 return 1;  
                         }  
                         strcpy(filename, libdir);  
                         strcat(filename, "/");  
                         strcat(filename, dlname);  
                         error = tryall_dlopen(handle, filename) == 0;  
                         lt_dlfree(filename);  
                         if (error)  
                                 return 0;  
                 }  
                 /* try to open the not-installed module */  
                 if (!installed) {  
                         filename = (char*)  
                                 lt_dlmalloc((dir ? strlen(dir) : 0)  
                                        + strlen(objdir) + strlen(dlname) + 1);  
                         if (!filename) {  
                                 last_error = memory_error;  
                                 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;  
                 }  
                 /* hmm, maybe it was moved to another directory */  
                 {  
                         filename = (char*)  
                                 lt_dlmalloc((dir ? strlen(dir) : 0)  
                                        + strlen(dlname) + 1);  
                         if (dir)  
                                 strcpy(filename, dir);  
                         else  
                                 *filename = 0;  
                         strcat(filename, dlname);  
                         error = tryall_dlopen(handle, filename) == 0;  
                         lt_dlfree(filename);  
                         if (error)  
                                 return 0;  
                 }  
         }  
         last_error = file_not_found_error;  
         return 1;  
 }  }
   
 static lt_ptr_t  int
 find_file (basename, search_path, pdir, handle)  lt_dlinsertsearchdir (before, search_dir)
         const char *basename;       const char *before;
         const char *search_path;       const char *search_dir;
         char **pdir;  {
         lt_dlhandle *handle;    int errors = 0;
 {  
         /* when handle != NULL search a library, otherwise a file */    if (before)
         /* return NULL on failure, otherwise the file/handle */      {
         LT_DLMUTEX_LOCK ();
         char    *filename = 0;        if ((before < user_search_path)
         int     filenamesize = 0;            || (before >= user_search_path + LT_STRLEN (user_search_path)))
         const char *next = search_path;          {
         int     lenbase = strlen(basename);            LT_DLMUTEX_UNLOCK ();
                     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION));
         if (!next || !*next) {            return 1;
                 last_error = file_not_found_error;          }
                 return 0;        LT_DLMUTEX_UNLOCK ();
         }      }
         while (next) {  
                 int lendir;    if (search_dir && *search_dir)
                 const char *cur = next;      {
         LT_DLMUTEX_LOCK ();
                 next = strchr(cur, ':');        if (lt_dlpath_insertdir (&user_search_path,
                 if (!next)                                 (char *) before, search_dir) != 0)
                         next = cur + strlen(cur);          {
                 lendir = next - cur;            ++errors;
                 if (*next == ':')  
                         ++next;  
                 else  
                         next = 0;  
                 if (lendir == 0)  
                         continue;  
                 if (lendir + 1 + lenbase >= filenamesize) {  
                         if (filename)  
                                 lt_dlfree(filename);  
                         filenamesize = lendir + 1 + lenbase + 1;  
                         filename = (char*) lt_dlmalloc(filenamesize);  
                         if (!filename) {  
                                 last_error = memory_error;  
                                 return 0;  
                         }  
                 }  
                 strncpy(filename, cur, lendir);  
                 if (filename[lendir-1] != '/')  
                         filename[lendir++] = '/';  
                 strcpy(filename+lendir, basename);  
                 if (handle) {  
                         if (tryall_dlopen(handle, filename) == 0) {  
                                 lt_dlfree(filename);  
                                 return (lt_ptr_t) handle;  
                         }  
                 } else {  
                         FILE *file = fopen(filename, LTDL_READTEXT_MODE);  
                         if (file) {  
                                 if (*pdir)  
                                         lt_dlfree(*pdir);  
                                 filename[lendir] = '\0';  
                                 *pdir = strdup(filename);  
                                 if (!*pdir) {  
                                         /* We could have even avoided the  
                                            strdup, but there would be some  
                                            memory overhead. */  
                                         *pdir = filename;  
                                 } else  
                                         lt_dlfree(filename);  
                                 return (lt_ptr_t) file;  
                         }  
                 }  
         }          }
         if (filename)        LT_DLMUTEX_UNLOCK ();
                 lt_dlfree(filename);      }
         last_error = file_not_found_error;  
         return 0;    return errors;
 }  }
   
 static int  int
 load_deplibs(handle, deplibs)  lt_dlsetsearchpath (search_path)
         lt_dlhandle handle;       const char *search_path;
         const char *deplibs;  {
 {    int   errors      = 0;
         /* FIXME: load deplibs */  
         handle->depcount = 0;    LT_DLMUTEX_LOCK ();
         handle->deplibs = 0;    LT_DLFREE (user_search_path);
         /* Just to silence gcc -Wall */    LT_DLMUTEX_UNLOCK ();
         deplibs = 0;  
         return 0;    if (!search_path || !LT_STRLEN (search_path))
       {
         return errors;
       }
   
     LT_DLMUTEX_LOCK ();
     if (canonicalize_path (search_path, &user_search_path) != 0)
       ++errors;
     LT_DLMUTEX_UNLOCK ();
   
     return errors;
 }  }
   
 static int  const char *
 unload_deplibs(handle)  lt_dlgetsearchpath ()
         lt_dlhandle handle;  
 {  {
         /* FIXME: unload deplibs */    const char *saved_path;
         /* Just to silence gcc -Wall */  
         handle = 0;    LT_DLMUTEX_LOCK ();
         return 0;    saved_path = user_search_path;
     LT_DLMUTEX_UNLOCK ();
   
     return saved_path;
 }  }
   
 static inline int  int
 trim (dest, str)  lt_dlmakeresident (handle)
         char **dest;       lt_dlhandle handle;
         const char *str;  
 {  {
         /* remove the leading and trailing "'" from str     int errors = 0;
            and store the result in dest */  
         char *tmp;    if (!handle)
         const char *end = strrchr(str, '\'');      {
         int len = strlen(str);        LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
         ++errors;
         if (*dest)      }
                 lt_dlfree(*dest);    else
         if (len > 3 && str[0] == '\'') {      {
                 tmp = (char*) lt_dlmalloc(end - str);        LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG);
                 if (!tmp) {      }
                         last_error = memory_error;  
                         return 1;    return errors;
                 }  
                 strncpy(tmp, &str[1], (end - str) - 1);  
                 tmp[len-3] = '\0';  
                 *dest = tmp;  
         } else  
                 *dest = 0;  
         return 0;  
 }  }
   
 static inline int  int
 free_vars(dir, name, dlname, oldname, libdir, deplibs)  lt_dlisresident (handle)
         char *dir;       lt_dlhandle handle;
         char *name;  {
         char *dlname;    if (!handle)
         char *oldname;      {
         char *libdir;        LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
         char *deplibs;        return -1;
 {      }
         if (dir)  
                 lt_dlfree(dir);    return LT_DLIS_RESIDENT (handle);
         if (name)  
                 lt_dlfree(name);  
         if (dlname)  
                 lt_dlfree(dlname);  
         if (oldname)  
                 lt_dlfree(oldname);  
         if (libdir)  
                 lt_dlfree(libdir);  
         if (deplibs)  
                 lt_dlfree(deplibs);  
         return 0;  
 }  }
   
 lt_dlhandle  
 lt_dlopen (filename)  
         const char *filename;  
   /* --- MODULE INFORMATION --- */
   
   const lt_dlinfo *
   lt_dlgetinfo (handle)
        lt_dlhandle handle;
 {  {
         lt_dlhandle handle, newhandle;    if (!handle)
         const char *basename, *ext;      {
         const char *saved_error = last_error;        LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
         char    *dir = 0, *name = 0;        return 0;
               }
         if (!filename) {  
                 handle = (lt_dlhandle) lt_dlmalloc(sizeof(lt_dlhandle_t));    return &(handle->info);
                 if (!handle) {  
                         last_error = memory_error;  
                         return 0;  
                 }  
                 handle->usage = 0;  
                 handle->depcount = 0;  
                 handle->deplibs = 0;  
                 newhandle = handle;  
                 if (tryall_dlopen(&newhandle, 0) != 0) {  
                         lt_dlfree(handle);  
                         return 0;  
                 }  
                 goto register_handle;  
         }  
         basename = strrchr(filename, '/');  
         if (basename) {  
                 basename++;  
                 dir = (char*) lt_dlmalloc(basename - filename + 1);  
                 if (!dir) {  
                         last_error = memory_error;  
                         return 0;  
                 }  
                 strncpy(dir, filename, basename - filename);  
                 dir[basename - filename] = '\0';  
         } else  
                 basename = filename;  
         /* check whether we open a libtool module (.la extension) */  
         ext = strrchr(basename, '.');  
         if (ext && strcmp(ext, ".la") == 0) {  
                 /* this seems to be a libtool module */  
                 FILE    *file;  
                 int     i;  
                 char    *dlname = 0, *old_name = 0;  
                 char    *libdir = 0, *deplibs = 0;  
                 char    *line;  
                 int     error = 0;  
                 /* if we can't find the installed flag, it is probably an  
                    installed libtool archive, produced with an old version  
                    of libtool */  
                 int     installed = 1;   
   
                 /* extract the module name from the file name */  
                 name = (char*) lt_dlmalloc(ext - basename + 1);  
                 if (!name) {  
                         last_error = memory_error;  
                         if (dir)  
                                 lt_dlfree(dir);  
                         return 0;  
                 }  
                 /* canonicalize the module name */  
                 for (i = 0; i < ext - basename; i++)  
                         if (isalnum((int)(basename[i])))  
                                 name[i] = basename[i];  
                         else  
                                 name[i] = '_';  
                 name[ext - basename] = '\0';  
                 /* now try to open the .la file */  
                 file = fopen(filename, LTDL_READTEXT_MODE);  
                 if (!file)  
                         last_error = file_not_found_error;  
                 if (!file && !dir) {  
                         /* try other directories */  
                         file = (FILE*) find_file(basename,   
                                                  user_search_path,  
                                                  &dir, 0);  
                         if (!file)  
                                 file = (FILE*) find_file(basename,  
                                                  getenv("LTDL_LIBRARY_PATH"),  
                                                  &dir, 0);  
 #ifdef LTDL_SHLIBPATH_VAR  
                         if (!file)  
                                 file = (FILE*) find_file(basename,  
                                                  getenv(LTDL_SHLIBPATH_VAR),  
                                                  &dir, 0);  
 #endif  
                 }  
                 if (!file) {  
                         if (name)  
                                 lt_dlfree(name);  
                         if (dir)  
                                 lt_dlfree(dir);  
                         return 0;  
                 }  
                 line = (char*) lt_dlmalloc(LTDL_FILENAME_MAX);  
                 if (!line) {  
                         fclose(file);  
                         last_error = memory_error;  
                         return 0;  
                 }  
                 /* read the .la file */  
                 while (!feof(file)) {  
                         if (!fgets(line, LTDL_FILENAME_MAX, file))  
                                 break;  
                         if (line[0] == '\n' || line[0] == '#')  
                                 continue;  
 #                       undef  STR_DLNAME  
 #                       define STR_DLNAME       "dlname="  
                         if (strncmp(line, STR_DLNAME,  
                                 sizeof(STR_DLNAME) - 1) == 0)  
                                 error = trim(&dlname,  
                                         &line[sizeof(STR_DLNAME) - 1]);  
                         else  
 #                       undef  STR_OLD_LIBRARY  
 #                       define STR_OLD_LIBRARY  "old_library="  
                         if (strncmp(line, STR_OLD_LIBRARY,  
                                 sizeof(STR_OLD_LIBRARY) - 1) == 0)  
                                 error = trim(&old_name,  
                                         &line[sizeof(STR_OLD_LIBRARY) - 1]);  
                         else  
 #                       undef  STR_LIBDIR  
 #                       define STR_LIBDIR       "libdir="  
                         if (strncmp(line, STR_LIBDIR,  
                                 sizeof(STR_LIBDIR) - 1) == 0)  
                                 error = trim(&libdir,  
                                         &line[sizeof(STR_LIBDIR) - 1]);  
                         else  
 #                       undef  STR_DL_DEPLIBS  
 #                       define STR_DL_DEPLIBS   "dl_dependency_libs="  
                         if (strncmp(line, STR_DL_DEPLIBS,  
                                 sizeof(STR_DL_DEPLIBS) - 1) == 0)  
                                 error = trim(&deplibs,  
                                         &line[sizeof(STR_DL_DEPLIBS) - 1]);  
                         else  
                         if (strcmp(line, "installed=yes\n") == 0)  
                                 installed = 1;  
                         else  
                         if (strcmp(line, "installed=no\n") == 0)  
                                 installed = 0;  
                         if (error)  
                                 break;  
                 }  
                 fclose(file);  
                 lt_dlfree(line);  
                 /* allocate the handle */  
                 handle = (lt_dlhandle) lt_dlmalloc(sizeof(lt_dlhandle_t));  
                 if (!handle || error) {  
                         if (handle)  
                                 lt_dlfree(handle);  
                         if (!error)  
                                 last_error = memory_error;  
                         free_vars(name, dir, dlname, old_name, libdir, deplibs);  
                         return 0;  
                 }  
                 handle->usage = 0;  
                 if (load_deplibs(handle, deplibs) == 0) {  
                         newhandle = handle;  
                         /* find_module may replace newhandle */  
                         if (find_module(&newhandle, dir, libdir,   
                                         dlname, old_name, installed)) {  
                                 unload_deplibs(handle);  
                                 error = 1;  
                         }  
                 } else  
                         error = 1;  
                 if (error) {  
                         lt_dlfree(handle);  
                         free_vars(name, dir, dlname, old_name, libdir, deplibs);  
                         return 0;  
                 }  
                 if (handle != newhandle) {  
                         unload_deplibs(handle);  
                 }  
         } else {  
                 /* not a libtool module */  
                 handle = (lt_dlhandle) lt_dlmalloc(sizeof(lt_dlhandle_t));  
                 if (!handle) {  
                         last_error = memory_error;  
                         if (dir)  
                                 lt_dlfree(dir);  
                         return 0;  
                 }  
                 handle->usage = 0;  
                 /* non-libtool modules don't have dependencies */  
                 handle->depcount = 0;  
                 handle->deplibs = 0;  
                 newhandle = handle;  
                 if (tryall_dlopen(&newhandle, filename)  
                     && (dir  
                         || (!find_file(basename, user_search_path,  
                                           0, &newhandle)  
                             && !find_file(basename,  
                                           getenv("LTDL_LIBRARY_PATH"),  
                                           0, &newhandle)  
 #ifdef LTDL_SHLIBPATH_VAR  
                             && !find_file(basename,  
                                           getenv(LTDL_SHLIBPATH_VAR),  
                                           0, &newhandle)  
 #endif  
                                 ))) {  
                         lt_dlfree(handle);  
                         if (dir)  
                                 lt_dlfree(dir);  
                         return 0;  
                 }  
         }  
 register_handle:  
         if (newhandle != handle) {  
                 lt_dlfree(handle);  
                 handle = newhandle;  
         }  
         if (!handle->usage) {  
                 handle->usage = 1;  
                 handle->name = name;  
                 handle->next = handles;  
                 handles = handle;  
         } else if (name)  
                 lt_dlfree(name);  
         if (dir)  
                 lt_dlfree(dir);  
         last_error = saved_error;  
         return handle;  
 }  }
   
 lt_dlhandle  lt_dlhandle
 lt_dlopenext (filename)  lt_dlhandle_next (place)
         const char *filename;       lt_dlhandle place;
 {  {
         lt_dlhandle handle;    return place ? place->next : handles;
         char    *tmp;  
         int     len;  
         const char *saved_error = last_error;  
           
         if (!filename)  
                 return lt_dlopen(filename);  
         len = strlen(filename);  
         if (!len) {  
                 last_error = file_not_found_error;  
                 return 0;  
         }  
         /* try the normal file name */  
         handle = lt_dlopen(filename);  
         if (handle)  
                 return handle;  
         /* try "filename.la" */  
         tmp = (char*) lt_dlmalloc(len+4);  
         if (!tmp) {  
                 last_error = memory_error;  
                 return 0;  
         }  
         strcpy(tmp, filename);  
         strcat(tmp, ".la");  
         handle = lt_dlopen(tmp);  
         if (handle) {  
                 last_error = saved_error;  
                 lt_dlfree(tmp);  
                 return handle;  
         }  
 #ifdef LTDL_SHLIB_EXT  
         /* try "filename.EXT" */  
         if (strlen(shlib_ext) > 3) {  
                 lt_dlfree(tmp);  
                 tmp = (char*) lt_dlmalloc(len + strlen(shlib_ext) + 1);  
                 if (!tmp) {  
                         last_error = memory_error;  
                         return 0;  
                 }  
                 strcpy(tmp, filename);  
         } else  
                 tmp[len] = '\0';  
         strcat(tmp, shlib_ext);  
         handle = lt_dlopen(tmp);  
         if (handle) {  
                 last_error = saved_error;  
                 lt_dlfree(tmp);  
                 return handle;  
         }  
 #endif    
         last_error = file_not_found_error;  
         lt_dlfree(tmp);  
         return 0;  
 }  }
   
 int  int
 lt_dlclose (handle)  lt_dlforeach (func, data)
         lt_dlhandle handle;       int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data));
        lt_ptr data;
 {  {
         lt_dlhandle cur, last;    int errors = 0;
             lt_dlhandle cur;
         /* check whether the handle is valid */  
         last = cur = handles;    LT_DLMUTEX_LOCK ();
         while (cur && handle != cur) {  
                 last = cur;    cur = handles;
                 cur = cur->next;    while (cur)
         }      {
         if (!cur) {        lt_dlhandle tmp = cur;
                 last_error = invalid_handle_error;  
                 return 1;        cur = cur->next;
         }        if ((*func) (tmp, data))
         handle->usage--;          {
         if (!handle->usage) {            ++errors;
                 int     error;            break;
           
                 if (handle != handles)  
                         last->next = handle->next;  
                 else  
                         handles = handle->next;  
                 error = handle->type->lib_close(handle);  
                 error += unload_deplibs(handle);  
                 if (handle->filename)  
                         lt_dlfree(handle->filename);  
                 if (handle->name)  
                         lt_dlfree(handle->name);  
                 lt_dlfree(handle);  
                 return error;  
         }          }
         return 0;      }
   
     LT_DLMUTEX_UNLOCK ();
   
     return errors;
 }  }
   
 lt_ptr_t  lt_dlcaller_id
 lt_dlsym (handle, symbol)  lt_dlcaller_register ()
         lt_dlhandle handle;  
         const char *symbol;  
 {  {
         int     lensym;    static lt_dlcaller_id last_caller_id = 0;
         char    lsym[LTDL_SYMBOL_LENGTH];    int result;
         char    *sym;  
         lt_ptr_t address;    LT_DLMUTEX_LOCK ();
     result = ++last_caller_id;
         if (!handle) {    LT_DLMUTEX_UNLOCK ();
                 last_error = invalid_handle_error;  
                 return 0;    return result;
         }  }
         if (!symbol) {  
                 last_error = symbol_error;  lt_ptr
                 return 0;  lt_dlcaller_set_data (key, handle, data)
         }       lt_dlcaller_id key;
         lensym = strlen(symbol);       lt_dlhandle handle;
         if (handle->type->sym_prefix)       lt_ptr data;
                 lensym += strlen(handle->type->sym_prefix);  {
         if (handle->name)    int n_elements = 0;
                 lensym += strlen(handle->name);    lt_ptr stale = NULL;
         if (lensym + LTDL_SYMBOL_OVERHEAD < LTDL_SYMBOL_LENGTH)    int i;
                 sym = lsym;  
         else    /* This needs to be locked so that the caller data can be updated
                 sym = (char*) lt_dlmalloc(lensym + LTDL_SYMBOL_OVERHEAD + 1);       simultaneously by different threads.  */
         if (!sym) {    LT_DLMUTEX_LOCK ();
                 last_error = buffer_overflow_error;  
                 return 0;    if (handle->caller_data)
         }      while (handle->caller_data[n_elements].key)
         if (handle->name) {        ++n_elements;
                 const char *saved_error = last_error;  
                     for (i = 0; i < n_elements; ++i)
                 /* this is a libtool module */      {
                 if (handle->type->sym_prefix) {        if (handle->caller_data[i].key == key)
                         strcpy(sym, handle->type->sym_prefix);          {
                         strcat(sym, handle->name);            stale = handle->caller_data[i].data;
                 } else            break;
                         strcpy(sym, handle->name);  
                 strcat(sym, "_LTX_");  
                 strcat(sym, symbol);  
                 /* try "modulename_LTX_symbol" */  
                 address = handle->type->find_sym(handle, sym);  
                 if (address) {  
                         if (sym != lsym)  
                                 lt_dlfree(sym);  
                         return address;  
                 }  
                 last_error = saved_error;  
         }          }
         /* otherwise try "symbol" */      }
         if (handle->type->sym_prefix) {  
                 strcpy(sym, handle->type->sym_prefix);    /* Ensure that there is enough room in this handle's caller_data
                 strcat(sym, symbol);       array to accept a new element (and an empty end marker).  */
         } else    if (i == n_elements)
                 strcpy(sym, symbol);      {
         address = handle->type->find_sym(handle, sym);        lt_caller_data *temp
         if (sym != lsym)          = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements);
                 lt_dlfree(sym);  
         return address;        if (!temp)
           {
             stale = NULL;
             goto done;
           }
   
         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:
     LT_DLMUTEX_UNLOCK ();
   
     return stale;
 }  }
   
 const char *  lt_ptr
 lt_dlerror LTDL_PARAMS((void))  lt_dlcaller_get_data  (key, handle)
        lt_dlcaller_id key;
        lt_dlhandle handle;
 {  {
         const char *error = last_error;    lt_ptr result = (lt_ptr) 0;
           
         last_error = 0;    /* This needs to be locked so that the caller data isn't updated by
         return error;       another thread part way through this function.  */
     LT_DLMUTEX_LOCK ();
   
     /* Locate the index of the element with a matching KEY.  */
     {
       int i;
       for (i = 0; handle->caller_data[i].key; ++i)
         {
           if (handle->caller_data[i].key == key)
             {
               result = handle->caller_data[i].data;
               break;
             }
         }
     }
   
     LT_DLMUTEX_UNLOCK ();
   
     return result;
 }  }
   
   
   
   /* --- USER MODULE LOADER API --- */
   
   
 int  int
 lt_dladdsearchdir (search_dir)  lt_dlloader_add (place, dlloader, loader_name)
         const char *search_dir;       lt_dlloader *place;
 {       const struct lt_user_dlloader *dlloader;
         if (!search_dir || !strlen(search_dir))       const char *loader_name;
                 return 0;  {
         if (!user_search_path) {    int errors = 0;
                 user_search_path = strdup(search_dir);    lt_dlloader *node = NULL, *ptr = NULL;
                 if (!user_search_path) {  
                         last_error = memory_error;    if ((dlloader == NULL)        /* diagnose null parameters */
                         return 1;        || (dlloader->module_open == NULL)
                 }        || (dlloader->module_close == NULL)
         } else {        || (dlloader->find_sym == NULL))
                 char    *new_search_path = (char*)      {
                         lt_dlmalloc(strlen(user_search_path) +         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
                                 strlen(search_dir) + 2); /* ':' + '\0' == 2 */        return 1;
                 if (!new_search_path) {      }
                         last_error = memory_error;  
                         return 1;    /* Create a new dlloader node with copies of the user callbacks.  */
                 }    node = LT_EMALLOC (lt_dlloader, 1);
                 strcpy(new_search_path, user_search_path);    if (!node)
                 strcat(new_search_path, ":");      return 1;
                 strcat(new_search_path, search_dir);  
                 lt_dlfree(user_search_path);    node->next            = NULL;
                 user_search_path = new_search_path;    node->loader_name     = loader_name;
     node->sym_prefix      = dlloader->sym_prefix;
     node->dlloader_exit   = dlloader->dlloader_exit;
     node->module_open     = dlloader->module_open;
     node->module_close    = dlloader->module_close;
     node->find_sym        = dlloader->find_sym;
     node->dlloader_data   = dlloader->dlloader_data;
   
     LT_DLMUTEX_LOCK ();
     if (!loaders)
       {
         /* If there are no loaders, NODE becomes the list! */
         loaders = node;
       }
     else if (!place)
       {
         /* If PLACE is not set, add NODE to the end of the
            LOADERS list. */
         for (ptr = loaders; ptr->next; ptr = ptr->next)
           {
             /*NOWORK*/;
           }
   
         ptr->next = node;
       }
     else if (loaders == place)
       {
         /* If PLACE is the first loader, NODE goes first. */
         node->next = place;
         loaders = node;
       }
     else
       {
         /* Find the node immediately preceding PLACE. */
         for (ptr = loaders; ptr->next != place; ptr = ptr->next)
           {
             /*NOWORK*/;
           }
   
         if (ptr->next != place)
           {
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
             ++errors;
           }
         else
           {
             /* Insert NODE between PTR and PLACE. */
             node->next = place;
             ptr->next  = node;
         }          }
         return 0;      }
   
     LT_DLMUTEX_UNLOCK ();
   
     return errors;
 }  }
   
 int  int
 lt_dlsetsearchpath (search_path)  lt_dlloader_remove (loader_name)
         const char *search_path;       const char *loader_name;
 {  {
         if (user_search_path)    lt_dlloader *place = lt_dlloader_find (loader_name);
                 lt_dlfree(user_search_path);    lt_dlhandle handle;
         user_search_path = 0; /* reset the search path */    int errors = 0;
         if (!search_path || !strlen(search_path))  
                 return 0;    if (!place)
         user_search_path = strdup(search_path);      {
         if (!user_search_path)        LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
                 return 1;        return 1;
         return 0;      }
   
     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)
           {
             LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER));
             ++errors;
             goto done;
           }
       }
   
     if (place == loaders)
       {
         /* PLACE is the first loader in the list. */
         loaders = loaders->next;
       }
     else
       {
         /* Find the loader before the one being removed. */
         lt_dlloader *prev;
         for (prev = loaders; prev->next; prev = prev->next)
           {
             if (!strcmp (prev->next->loader_name, loader_name))
               {
                 break;
               }
           }
   
         place = prev->next;
         prev->next = prev->next->next;
       }
   
     if (place->dlloader_exit)
       {
         errors = place->dlloader_exit (place->dlloader_data);
       }
   
     LT_DLFREE (place);
   
    done:
     LT_DLMUTEX_UNLOCK ();
   
     return errors;
   }
   
   lt_dlloader *
   lt_dlloader_next (place)
        lt_dlloader *place;
   {
     lt_dlloader *next;
   
     LT_DLMUTEX_LOCK ();
     next = place ? place->next : loaders;
     LT_DLMUTEX_UNLOCK ();
   
     return next;
 }  }
   
 const char *  const char *
 lt_dlgetsearchpath LTDL_PARAMS((void))  lt_dlloader_name (place)
        lt_dlloader *place;
 {  {
         return user_search_path;    const char *name = NULL;
   
     if (place)
       {
         LT_DLMUTEX_LOCK ();
         name = place ? place->loader_name : 0;
         LT_DLMUTEX_UNLOCK ();
       }
     else
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
       }
   
     return name;
   }
   
   lt_user_data *
   lt_dlloader_data (place)
        lt_dlloader *place;
   {
     lt_user_data *data = NULL;
   
     if (place)
       {
         LT_DLMUTEX_LOCK ();
         data = place ? &(place->dlloader_data) : 0;
         LT_DLMUTEX_UNLOCK ();
       }
     else
       {
         LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
       }
   
     return data;
   }
   
   lt_dlloader *
   lt_dlloader_find (loader_name)
        const char *loader_name;
   {
     lt_dlloader *place = NULL;
   
     LT_DLMUTEX_LOCK ();
     for (place = loaders; place; place = place->next)
       {
         if (strcmp (place->loader_name, loader_name) == 0)
           {
             break;
           }
       }
     LT_DLMUTEX_UNLOCK ();
   
     return place;
 }  }

Removed from v.1.1  
changed lines
  Added in v.1.2


E-mail: