Diff for /sql/pgsql/libltdl/ltdl.c between versions 1.3 and 1.4

version 1.3, 2003/01/14 17:13:47 version 1.4, 2012/06/08 15:25:55
Line 1 Line 1
 /* ltdl.c -- system independent dlopen wrapper  /* ltdl.c -- system independent dlopen wrapper
    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.  
    Originally by Thomas Tanner <tanner@ffii.org>  
    This file is part of GNU Libtool.  
   
 This library is free software; you can redistribute it and/or     Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006,
                    2007, 2008, 2011 Free Software Foundation, Inc.
      Written by Thomas Tanner, 1998
   
      NOTE: The canonical source of this file is maintained with the
      GNU Libtool package.  Report bugs to bug-libtool@gnu.org.
   
   GNU Libltdl is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser 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 Lesser General Public License,  As a special exception to the GNU Lesser General Public License,
 if you distribute this file as part of a program or library that  if you distribute this file as part of a program or library that
 is built using GNU libtool, you may include it under the same  is built using GNU Libtool, you may include this file under the
 distribution terms that you use for the rest of that program.  same distribution terms that you use for the rest of that program.
   
 This library is distributed in the hope that it will be useful,  GNU Libltdl 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
 Lesser General Public License for more details.  GNU Lesser General Public License for more details.
   
 You should have received a copy of the GNU Lesser 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 GNU Libltdl; see the file COPYING.LIB.  If not, a
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
 02111-1307  USA  or obtained by writing to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */  */
   
 #include "config.h"  #include "lt__private.h"
   #include "lt_system.h"
 #if HAVE_UNISTD_H  #include "lt_dlloader.h"
 #  include <unistd.h>  
 #endif  
   
 #if HAVE_STDIO_H  
 #  include <stdio.h>  
 #endif  
   
 #if HAVE_STDLIB_H  
 #  include <stdlib.h>  
 #endif  
   
 #if HAVE_STRING_H  
 #  include <string.h>  
 #else  
 #  if HAVE_STRINGS_H  
 #    include <strings.h>  
 #  endif  
 #endif  
   
 #if HAVE_CTYPE_H  
 #  include <ctype.h>  
 #endif  
   
 #if HAVE_MALLOC_H  
 #  include <malloc.h>  
 #endif  
   
 #if HAVE_MEMORY_H  
 #  include <memory.h>  
 #endif  
   
 #if HAVE_ERRNO_H  
 #  include <errno.h>  
 #endif  
   
 #ifdef HAVE_CONFIG_H  
 #if HAVE_DIRENT_H  
 #  include <dirent.h>  
 #  define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name))  
 #else  
 #  define dirent direct  
 #  define LT_D_NAMLEN(dirent) ((dirent)->d_namlen)  
 #  if HAVE_SYS_NDIR_H  
 #    include <sys/ndir.h>  
 #  endif  
 #  if HAVE_SYS_DIR_H  
 #    include <sys/dir.h>  
 #  endif  
 #  if HAVE_NDIR_H  
 #    include <ndir.h>  
 #  endif  
 #endif  
 #endif  
   
 #if HAVE_ARGZ_H  
 #  include <argz.h>  
 #endif  
   
 #if HAVE_ASSERT_H  
 #  include <assert.h>  
 #else  
 #  define assert(arg)   ((void) 0)  
 #endif  
   
 #include "ltdl.h"  
   
 #if WITH_DMALLOC  
 #  include <dmalloc.h>  
 #endif  
   
   
   
   
 /* --- WINDOWS SUPPORT --- */  
   
   
 #ifdef DLL_EXPORT  
 #  define LT_GLOBAL_DATA        __declspec(dllexport)  
 #else  
 #  define LT_GLOBAL_DATA  
 #endif  
   
 /* fopen() mode flags for reading a text file */  
 #undef  LT_READTEXT_MODE  
 #ifdef __WINDOWS__  
 #  define LT_READTEXT_MODE "rt"  
 #else  
 #  define LT_READTEXT_MODE "r"  
 #endif  
   
   
   
   
 /* --- MANIFEST CONSTANTS --- */  /* --- MANIFEST CONSTANTS --- */
   
   
Line 129  Foundation, Inc., 59 Temple Place, Suite Line 42  Foundation, Inc., 59 Temple Place, Suite
 #define LTDL_SEARCHPATH_VAR     "LTDL_LIBRARY_PATH"  #define LTDL_SEARCHPATH_VAR     "LTDL_LIBRARY_PATH"
   
 /* Standard libtool archive file extension.  */  /* Standard libtool archive file extension.  */
 #undef  LTDL_ARCHIVE_EXT  #undef  LT_ARCHIVE_EXT
 #define LTDL_ARCHIVE_EXT        ".la"  #define LT_ARCHIVE_EXT  ".la"
   
 /* max. filename length */  /* max. filename length */
 #ifndef LT_FILENAME_MAX  #if !defined(LT_FILENAME_MAX)
 #  define LT_FILENAME_MAX       1024  #  define LT_FILENAME_MAX       1024
 #endif  #endif
   
   #if !defined(LT_LIBEXT)
   #  define LT_LIBEXT "a"
   #endif
   
   #if !defined(LT_LIBPREFIX)
   #  define LT_LIBPREFIX "lib"
   #endif
   
 /* This is the maximum symbol size that won't require malloc/free */  /* This is the maximum symbol size that won't require malloc/free */
 #undef  LT_SYMBOL_LENGTH  #undef  LT_SYMBOL_LENGTH
 #define LT_SYMBOL_LENGTH        128  #define LT_SYMBOL_LENGTH        128
Line 145  Foundation, Inc., 59 Temple Place, Suite Line 66  Foundation, Inc., 59 Temple Place, Suite
 #undef  LT_SYMBOL_OVERHEAD  #undef  LT_SYMBOL_OVERHEAD
 #define LT_SYMBOL_OVERHEAD      5  #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)))  
   
 #endif  
   
 #define LT_DLMEM_REASSIGN(p, q)                 LT_STMT_START { \  
         if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; }   \  
                                                 } LT_STMT_END  
   
   
 /* --- REPLACEMENT FUNCTIONS --- */  
   
   
 #undef strdup  
 #define strdup rpl_strdup  
   
 static char *strdup LT_PARAMS((const char *str));  
   
 static char *  
 strdup(str)  
      const char *str;  
 {  
   char *tmp = NULL;  
   
   if (str)  
     {  
       tmp = LT_DLMALLOC (char, 1+ strlen (str));  
       if (tmp)  
         {  
           strcpy(tmp, str);  
         }  
     }  
   
   return tmp;  
 }  
   
   
 #if ! HAVE_STRCMP  
   
 #undef strcmp  
 #define strcmp rpl_strcmp  
   
 static int strcmp LT_PARAMS((const char *str1, const char *str2));  
   
 static int  
 strcmp (str1, str2)  
      const char *str1;  
      const char *str2;  
 {  
   if (str1 == str2)  
     return 0;  
   if (str1 == NULL)  
     return -1;  
   if (str2 == NULL)  
     return 1;  
   
   for (;*str1 && *str2; ++str1, ++str2)  
     {  
       if (*str1 != *str2)  
         break;  
     }  
   
   return (int)(*str1 - *str2);  
 }  
 #endif  
   
   
 #if ! HAVE_STRCHR  
   
 #  if HAVE_INDEX  
 #    define strchr index  
 #  else  
 #    define strchr rpl_strchr  
   
 static const char *strchr LT_PARAMS((const char *str, int ch));  
   
 static const char*  
 strchr(str, ch)  
      const char *str;  
      int ch;  
 {  
   const char *p;  
   
   for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p)  
     /*NOWORK*/;  
   
   return (*p == (char)ch) ? p : 0;  
 }  
   
 #  endif  
 #endif /* !HAVE_STRCHR */  
   
   
 #if ! HAVE_STRRCHR  
   
 #  if HAVE_RINDEX  
 #    define strrchr rindex  
 #  else  
 #    define strrchr rpl_strrchr  
   
 static const char *strrchr LT_PARAMS((const char *str, int ch));  
   
 static const char*  
 strrchr(str, ch)  
      const char *str;  
      int ch;  
 {  
   const char *p, *q = NULL;  
   
   for (p = str; *p != LT_EOS_CHAR; ++p)  
     {  
       if (*p == (char) ch)  
         {  
           q = p;  
         }  
     }  
   
   return q;  
 }  
   
 # endif  
 #endif  
   
 /* NOTE:  Neither bcopy nor the memcpy implementation below can  
           reliably handle copying in overlapping areas of memory.  Use  
           memmove (for which there is a fallback implmentation below)  
           if you need that behaviour.  */  
 #if ! HAVE_MEMCPY  
   
 #  if HAVE_BCOPY  
 #    define memcpy(dest, src, size)     bcopy (src, dest, size)  
 #  else  
 #    define memcpy rpl_memcpy  
   
 static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));  
   
 static lt_ptr  
 memcpy (dest, src, size)  
      lt_ptr dest;  
      const lt_ptr src;  
      size_t size;  
 {  
   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;  
 {  
   size_t i;  
   
   if (dest < src)  
     for (i = 0; i < size; ++i)  
       {  
         dest[i] = src[i];  
       }  
   else if (dest > src)  
     for (i = size -1; i >= 0; --i)  
       {  
         dest[i] = src[i];  
       }  
   
   return dest;  
 }  
   
 #endif /* !HAVE_MEMMOVE */  
   
   
 /* According to Alexandre Oliva <oliva@lsd.ic.unicamp.br>,  
     ``realloc is not entirely portable''  
    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;  
     }  
 }  
   
   
 #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  /* Various boolean flags can be stored in the flags field of an
    lt_dlhandle_struct... */     lt_dlhandle... */
 #define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag))  #define LT_DLIS_RESIDENT(handle)  ((handle)->info.is_resident)
 #define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag))  #define LT_DLIS_SYMGLOBAL(handle) ((handle)->info.is_symglobal)
   #define LT_DLIS_SYMLOCAL(handle)  ((handle)->info.is_symlocal)
 #define LT_DLRESIDENT_FLAG          (0x01 << 0)  
 /* ...add more flags here... */  
   static  const char      objdir[]                = LT_OBJDIR;
 #define LT_DLIS_RESIDENT(handle)    LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG)  static  const char      archive_ext[]           = LT_ARCHIVE_EXT;
   static  const char      libext[]                = LT_LIBEXT;
   static  const char      libprefix[]             = LT_LIBPREFIX;
 #define LT_DLSTRERROR(name)     lt_dlerror_strings[LT_CONC(LT_ERROR_,name)]  #if defined(LT_MODULE_EXT)
   static  const char      shlib_ext[]             = LT_MODULE_EXT;
 static  const char      objdir[]                = LTDL_OBJDIR;  #endif
 static  const char      archive_ext[]           = LTDL_ARCHIVE_EXT;  /* If the loadable module suffix is not the same as the linkable
 #ifdef  LTDL_SHLIB_EXT   * shared library suffix, this will be defined. */
 static  const char      shlib_ext[]             = LTDL_SHLIB_EXT;  #if defined(LT_SHARED_EXT)
 #endif  static  const char      shared_ext[]            = LT_SHARED_EXT;
 #ifdef  LTDL_SYSSEARCHPATH  
 static  const char      sys_search_path[]       = LTDL_SYSSEARCHPATH;  
 #endif  
   
   
   
   
 /* --- MUTEX LOCKING --- */  
   
   
 /* Macros to make it easier to run the lock functions only if they have  
    been registered.  The reason for the complicated lock macro is to  
    ensure that the stored error message from the last error is not  
    accidentally erased if the current function doesn't generate an  
    error of its own.  */  
 #define LT_DLMUTEX_LOCK()                       LT_STMT_START { \  
         if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)();    \  
                                                 } LT_STMT_END  
 #define LT_DLMUTEX_UNLOCK()                     LT_STMT_START { \  
         if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\  
                                                 } LT_STMT_END  
 #define LT_DLMUTEX_SETERROR(errormsg)           LT_STMT_START { \  
         if (lt_dlmutex_seterror_func)                           \  
                 (*lt_dlmutex_seterror_func) (errormsg);         \  
         else    lt_dllast_error = (errormsg);   } LT_STMT_END  
 #define LT_DLMUTEX_GETERROR(errormsg)           LT_STMT_START { \  
         if (lt_dlmutex_seterror_func)                           \  
                 (errormsg) = (*lt_dlmutex_geterror_func) ();    \  
         else    (errormsg) = lt_dllast_error;   } LT_STMT_END  
   
 /* The mutex functions stored here are global, and are necessarily the  
    same for all threads that wish to share access to libltdl.  */  
 static  lt_dlmutex_lock     *lt_dlmutex_lock_func     = 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 */  
   
 #if HAVE_DLFCN_H  
 #  include <dlfcn.h>  
 #endif  #endif
   #if defined(LT_DLSEARCH_PATH)
 #if HAVE_SYS_DL_H  static  const char      sys_dlsearch_path[]     = LT_DLSEARCH_PATH;
 #  include <sys/dl.h>  
 #endif  #endif
   
 #ifdef RTLD_GLOBAL  
 #  define LT_GLOBAL             RTLD_GLOBAL  
 #else  
 #  ifdef DL_GLOBAL  
 #    define LT_GLOBAL           DL_GLOBAL  
 #  endif  
 #endif /* !RTLD_GLOBAL */  
 #ifndef LT_GLOBAL  
 #  define LT_GLOBAL             0  
 #endif /* !LT_GLOBAL */  
   
 /* We may have to define LT_LAZY_OR_NOW in the command line if we  
    find out it does not work in some platform. */  
 #ifndef LT_LAZY_OR_NOW  
 #  ifdef RTLD_LAZY  
 #    define LT_LAZY_OR_NOW      RTLD_LAZY  
 #  else  
 #    ifdef DL_LAZY  
 #      define LT_LAZY_OR_NOW    DL_LAZY  
 #    endif  
 #  endif /* !RTLD_LAZY */  
 #endif  
 #ifndef LT_LAZY_OR_NOW  
 #  ifdef RTLD_NOW  
 #    define LT_LAZY_OR_NOW      RTLD_NOW  
 #  else  
 #    ifdef DL_NOW  
 #      define LT_LAZY_OR_NOW    DL_NOW  
 #    endif  
 #  endif /* !RTLD_NOW */  
 #endif  
 #ifndef LT_LAZY_OR_NOW  
 #  define LT_LAZY_OR_NOW        0  
 #endif /* !LT_LAZY_OR_NOW */  
   
 #if HAVE_DLERROR  
 #  define DLERROR(arg)  dlerror ()  
 #else  
 #  define DLERROR(arg)  LT_DLSTRERROR (arg)  
 #endif  
   
 static lt_module  
 sys_dl_open (loader_data, filename)  
      lt_user_data loader_data;  
      const char *filename;  
 {  
   lt_module   module   = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW);  
   
   if (!module)  
     {  
       LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN));  
     }  
   
   return module;  
 }  
   
 static int  
 sys_dl_close (loader_data, module)  
      lt_user_data loader_data;  
      lt_module module;  
 {  
   int errors = 0;  
   
   if (dlclose (module) != 0)  
     {  
       LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE));  
       ++errors;  
     }  
   
   return errors;  
 }  
   
 static lt_ptr  
 sys_dl_sym (loader_data, module, symbol)  
      lt_user_data loader_data;  
      lt_module module;  
      const char *symbol;  
 {  
   lt_ptr address = dlsym (module, symbol);  
   
   if (!address)  
     {  
       LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND));  
     }  
   
   return address;  
 }  
   
 static struct lt_user_dlloader sys_dl =  
   {  
 #  ifdef NEED_USCORE  
     "_",  
 #  else  
     0,  
 #  endif  
     sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 };  
   
   
 #endif /* HAVE_LIBDL */  
   
   
   
 /* --- SHL_LOAD() INTERFACE LOADER --- */  /* --- DYNAMIC MODULE LOADING --- */
   
 #if HAVE_SHL_LOAD  
   
 /* dynamic linking with shl_load (HP-UX) (comments from gmodule) */  
   
 #ifdef HAVE_DL_H  
 #  include <dl.h>  
 #endif  
   
 /* some flags are missing on some systems, so we provide  
  * harmless defaults.  
  *  
  * Mandatory:  
  * BIND_IMMEDIATE  - Resolve symbol references when the library is loaded.  
  * BIND_DEFERRED   - Delay code symbol resolution until actual reference.  
  *  
  * Optionally:  
  * BIND_FIRST      - Place the library at the head of the symbol search  
  *                   order.  
  * BIND_NONFATAL   - The default BIND_IMMEDIATE behavior is to treat all  
  *                   unsatisfied symbols as fatal.  This flag allows  
  *                   binding of unsatisfied code symbols to be deferred  
  *                   until use.  
  *                   [Perl: For certain libraries, like DCE, deferred  
  *                   binding often causes run time problems. Adding  
  *                   BIND_NONFATAL to BIND_IMMEDIATE still allows  
  *                   unresolved references in situations like this.]  
  * BIND_NOSTART    - Do not call the initializer for the shared library  
  *                   when the library is loaded, nor on a future call to  
  *                   shl_unload().  
  * BIND_VERBOSE    - Print verbose messages concerning possible  
  *                   unsatisfied symbols.  
  *  
  * hp9000s700/hp9000s800:  
  * BIND_RESTRICTED - Restrict symbols visible by the library to those  
  *                   present at library load time.  
  * DYNAMIC_PATH    - Allow the loader to dynamically search for the  
  *                   library specified by the path argument.  
  */  
   
 #ifndef DYNAMIC_PATH  
 #  define DYNAMIC_PATH          0  
 #endif  
 #ifndef BIND_RESTRICTED  
 #  define BIND_RESTRICTED       0  
 #endif  
   
 #define LT_BIND_FLAGS   (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH)  
   
 static lt_module  
 sys_shl_open (loader_data, filename)  
      lt_user_data loader_data;  
      const char *filename;  
 {  
   static shl_t self = (shl_t) 0;  
   lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L);  
   
   /* Since searching for a symbol against a NULL module handle will also  
      look in everything else that was already loaded and exported with  
      the -E compiler flag, we always cache a handle saved before any  
      modules are loaded.  */  
   if (!self)  
     {  
       lt_ptr address;  
       shl_findsym (&self, "main", TYPE_UNDEFINED, &address);  
     }  
   
   if (!filename)  
     {  
       module = self;  
     }  
   else  
     {  
       module = shl_load (filename, LT_BIND_FLAGS, 0L);  
   
       if (!module)  /* The type of a function used at each iteration of  foreach_dirinpath().  */
         {  typedef int     foreach_callback_func (char *filename, void *data1,
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));                                         void *data2);
         }  /* foreachfile_callback itself calls a function of this type: */
     }  typedef int     file_worker_func      (const char *filename, void *data);
   
   return module;  
   static  int     foreach_dirinpath     (const char *search_path,
                                          const char *base_name,
                                          foreach_callback_func *func,
                                          void *data1, void *data2);
   static  int     find_file_callback    (char *filename, void *data1,
                                          void *data2);
   static  int     find_handle_callback  (char *filename, void *data,
                                          void *ignored);
   static  int     foreachfile_callback  (char *filename, void *data1,
                                          void *data2);
   
   
   static  int     canonicalize_path     (const char *path, char **pcanonical);
   static  int     argzize_path          (const char *path,
                                          char **pargz, size_t *pargz_len);
   static  FILE   *find_file             (const char *search_path,
                                          const char *base_name, char **pdir);
   static  lt_dlhandle *find_handle      (const char *search_path,
                                          const char *base_name,
                                          lt_dlhandle *handle,
                                          lt_dladvise advise);
   static  int     find_module           (lt_dlhandle *handle, const char *dir,
                                          const char *libdir, const char *dlname,
                                          const char *old_name, int installed,
                                          lt_dladvise advise);
   static  int     has_library_ext       (const char *filename);
   static  int     load_deplibs          (lt_dlhandle handle,  char *deplibs);
   static  int     trim                  (char **dest, const char *str);
   static  int     try_dlopen            (lt_dlhandle *handle,
                                          const char *filename, const char *ext,
                                          lt_dladvise advise);
   static  int     tryall_dlopen         (lt_dlhandle *handle,
                                          const char *filename,
                                          lt_dladvise padvise,
                                          const lt_dlvtable *vtable);
   static  int     unload_deplibs        (lt_dlhandle handle);
   static  int     lt_argz_insert        (char **pargz, size_t *pargz_len,
                                          char *before, const char *entry);
   static  int     lt_argz_insertinorder (char **pargz, size_t *pargz_len,
                                          const char *entry);
   static  int     lt_argz_insertdir     (char **pargz, size_t *pargz_len,
                                          const char *dirnam, struct dirent *dp);
   static  int     lt_dlpath_insertdir   (char **ppath, char *before,
                                          const char *dir);
   static  int     list_files_by_dir     (const char *dirnam,
                                          char **pargz, size_t *pargz_len);
   static  int     file_not_found        (void);
   
   #ifdef HAVE_LIBDLLOADER
   static  int     loader_init_callback  (lt_dlhandle handle);
   #endif /* HAVE_LIBDLLOADER */
   
   static  int     loader_init           (lt_get_vtable *vtable_func,
                                          lt_user_data data);
   
   static  char           *user_search_path= 0;
   static  lt_dlhandle     handles = 0;
   static  int             initialized     = 0;
   
   /* Our memory failure callback sets the error message to be passed back
      up to the client, so we must be careful to return from mallocation
      callers if allocation fails (as this callback returns!!).  */
   void
   lt__alloc_die_callback (void)
   {
     LT__SETERROR (NO_MEMORY);
   }
   
   #ifdef HAVE_LIBDLLOADER
   /* This function is called to initialise each preloaded module loader,
      and hook it into the list of loaders to be used when attempting to
      dlopen an application module.  */
   static int
   loader_init_callback (lt_dlhandle handle)
   {
     lt_get_vtable *vtable_func = (lt_get_vtable *) lt_dlsym (handle, "get_vtable");
     return loader_init (vtable_func, 0);
 }  }
   #endif /* HAVE_LIBDLLOADER */
   
 static int  static int
 sys_shl_close (loader_data, module)  loader_init (lt_get_vtable *vtable_func, lt_user_data data)
      lt_user_data loader_data;  
      lt_module module;  
 {  {
     const lt_dlvtable *vtable = 0;
   int errors = 0;    int errors = 0;
   
   if (module && (shl_unload ((shl_t) (module)) != 0))    if (vtable_func)
     {  
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));  
       ++errors;  
     }  
   
   return errors;  
 }  
   
 static lt_ptr  
 sys_shl_sym (loader_data, module, symbol)  
      lt_user_data loader_data;  
      lt_module module;  
      const char *symbol;  
 {  
   lt_ptr address = NULL;  
   
   /* 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 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, '.');        vtable = (*vtable_func) (data);
     }      }
   
   if (ext)    /* lt_dlloader_add will LT__SETERROR if it fails.  */
     {    errors += lt_dlloader_add (vtable);
       /* 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__    assert (errors || vtable);
   {  
     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    if ((!errors) && vtable->dlloader_init)
      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)        if ((*vtable->dlloader_init) (vtable->dlloader_data))
         {          {
           cur = NULL;            LT__SETERROR (INIT_LOADER);
           break;            ++errors;
         }  
   
       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  
 sys_wll_close (loader_data, module)  
      lt_user_data loader_data;  
      lt_module module;  
 {  
   int         errors   = 0;  
   
   if (FreeLibrary(module) == 0)  
     {  
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));  
       ++errors;  
     }  
   
   return errors;  
 }  
   
 static lt_ptr  
 sys_wll_sym (loader_data, module, symbol)  
      lt_user_data loader_data;  
      lt_module module;  
      const char *symbol;  
 {  
   lt_ptr      address  = GetProcAddress (module, symbol);  
   
   if (!address)  
     {  
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));  
     }  
   
   return address;  
 }  
   
 static struct lt_user_dlloader sys_wll = {  
   0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0  
 };  
   
 #endif /* __WINDOWS__ */  
   
   
   
   
 /* --- 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;    return errors;
 }  }
   
 static lt_ptr  /* Bootstrap the loader loading with the preopening loader.  */
 sys_bedl_sym (loader_data, module, symbol)  #define get_vtable              preopen_LTX_get_vtable
      lt_user_data loader_data;  #define preloaded_symbols       LT_CONC3(lt_, LTDLOPEN, _LTX_preloaded_symbols)
      lt_module module;  
      const char *symbol;  LT_BEGIN_C_DECLS
 {  LT_SCOPE const lt_dlvtable *    get_vtable (lt_user_data data);
   lt_ptr address = NULL;  LT_END_C_DECLS
   image_id image = (image_id) module;  #ifdef HAVE_LIBDLLOADER
   extern LT_DLSYM_CONST lt_dlsymlist preloaded_symbols[];
   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 --- */  
   
   
 #if HAVE_DLD  
   
 /* dynamic linking with dld */  
   
 #if HAVE_DLD_H  
 #include <dld.h>  
 #endif  #endif
   
 static lt_module  
 sys_dld_open (loader_data, filename)  
      lt_user_data loader_data;  
      const char *filename;  
 {  
   lt_module module = strdup (filename);  
   
   if (dld_link (filename) != 0)  
     {  
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));  
       LT_DLFREE (module);  
       module = NULL;  
     }  
   
   return module;  
 }  
   
 static int  
 sys_dld_close (loader_data, module)  
      lt_user_data loader_data;  
      lt_module module;  
 {  
   int errors = 0;  
   
   if (dld_unlink_by_file ((char*)(module), 1) != 0)  
     {  
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));  
       ++errors;  
     }  
   else  
     {  
       LT_DLFREE (module);  
     }  
   
   return errors;  
 }  
   
 static lt_ptr  
 sys_dld_sym (loader_data, module, symbol)  
      lt_user_data loader_data;  
      lt_module module;  
      const char *symbol;  
 {  
   lt_ptr address = dld_get_func (symbol);  
   
   if (!address)  
     {  
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));  
     }  
   
   return address;  
 }  
   
 static struct lt_user_dlloader sys_dld = {  
   0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0  
 };  
   
 #endif /* HAVE_DLD */  
   
   
   
   
 /* --- DLPREOPEN() INTERFACE LOADER --- */  
   
   
 /* 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  
 presym_init (loader_data)  
      lt_user_data loader_data;  
 {  
   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  
 presym_free_symlists ()  
 {  
   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;  
 }  
   
 static int  
 presym_exit (loader_data)  
      lt_user_data loader_data;  
 {  
   presym_free_symlists ();  
   return 0;  
 }  
   
 static int  
 presym_add_symlist (preloaded)  
      const lt_dlsymlist *preloaded;  
 {  
   lt_dlsymlists_t *tmp;  
   lt_dlsymlists_t *lists;  
   int              errors   = 0;  
   
   LT_DLMUTEX_LOCK ();  
   
   lists = preloaded_symbols;  
   while (lists)  
     {  
       if (lists->syms == preloaded)  
         {  
           goto done;  
         }  
       lists = lists->next;  
     }  
   
   tmp = LT_EMALLOC (lt_dlsymlists_t, 1);  
   if (tmp)  
     {  
       memset (tmp, 0, sizeof(lt_dlsymlists_t));  
       tmp->syms = preloaded;  
       tmp->next = preloaded_symbols;  
       preloaded_symbols = tmp;  
     }  
   else  
     {  
       ++errors;  
     }  
   
  done:  
   LT_DLMUTEX_UNLOCK ();  
   return errors;  
 }  
   
 static lt_module  
 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. */  /* Initialize libltdl. */
 int  int
 lt_dlinit ()  lt_dlinit (void)
 {  {
   int         errors   = 0;    int   errors  = 0;
   
   LT_DLMUTEX_LOCK ();  
   
   /* Initialize only at first call. */    /* Initialize only at first call. */
   if (++initialized == 1)    if (++initialized == 1)
     {      {
       handles = NULL;        lt__alloc_die     = lt__alloc_die_callback;
       user_search_path = NULL; /* empty search path */        handles           = 0;
         user_search_path  = 0; /* empty search path */
   
 #if HAVE_LIBDL && !defined(__CYGWIN__)        /* First set up the statically loaded preload module loader, so
       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen");           we can use it to preopen the other loaders we linked in at
 #endif           compile time.  */
 #if HAVE_SHL_LOAD        errors += loader_init (get_vtable, 0);
       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))        /* Now open all the preloaded module loaders, so the application
            can use _them_ to lt_dlopen its own modules.  */
   #ifdef HAVE_LIBDLLOADER
         if (!errors)
         {          {
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER));            errors += lt_dlpreload (preloaded_symbols);
           ++errors;  
         }          }
       else if (errors != 0)  
         {  
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED));  
           ++errors;  
         }  
     }  
   
   LT_DLMUTEX_UNLOCK ();  
   
   return errors;  
 }  
   
 int  
 lt_dlpreload (preloaded)  
      const lt_dlsymlist *preloaded;  
 {  
   int errors = 0;  
   
   if (preloaded)        if (!errors)
     {  
       errors = presym_add_symlist (preloaded);  
     }  
   else  
     {  
       presym_free_symlists();  
   
       LT_DLMUTEX_LOCK ();  
       if (default_preloaded_symbols)  
         {          {
           errors = lt_dlpreload (default_preloaded_symbols);            errors += lt_dlpreload_open (LT_STR(LTDLOPEN), loader_init_callback);
         }          }
       LT_DLMUTEX_UNLOCK ();  #endif /* HAVE_LIBDLLOADER */
     }      }
   
   return errors;  #ifdef LT_DEBUG_LOADERS
 }    lt_dlloader_dump();
   #endif
   
 int    return errors;
 lt_dlpreload_default (preloaded)  
      const lt_dlsymlist *preloaded;  
 {  
   LT_DLMUTEX_LOCK ();  
   default_preloaded_symbols = preloaded;  
   LT_DLMUTEX_UNLOCK ();  
   return 0;  
 }  }
   
 int  int
 lt_dlexit ()  lt_dlexit (void)
 {  {
   /* shut down libltdl */    /* shut down libltdl */
   lt_dlloader *loader;    lt_dlloader *loader   = 0;
     lt_dlhandle  handle   = handles;
   int          errors   = 0;    int          errors   = 0;
   
   LT_DLMUTEX_LOCK ();  
   loader = loaders;  
   
   if (!initialized)    if (!initialized)
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN));        LT__SETERROR (SHUTDOWN);
       ++errors;        ++errors;
       goto done;        goto done;
     }      }
Line 1826  lt_dlexit () Line 287  lt_dlexit ()
         }          }
   
       /* close all modules */        /* close all modules */
       for (level = 1; handles; ++level)        for (level = 1; handle; ++level)
         {          {
           lt_dlhandle cur = handles;            lt_dlhandle cur = handles;
           int saw_nonresident = 0;            int saw_nonresident = 0;
Line 1836  lt_dlexit () Line 297  lt_dlexit ()
               lt_dlhandle tmp = cur;                lt_dlhandle tmp = cur;
               cur = cur->next;                cur = cur->next;
               if (!LT_DLIS_RESIDENT (tmp))                if (!LT_DLIS_RESIDENT (tmp))
                 saw_nonresident = 1;  
               if (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level)  
                 {                  {
                   if (lt_dlclose (tmp))                    saw_nonresident = 1;
                     if (tmp->info.ref_count <= level)
                     {                      {
                       ++errors;                        if (lt_dlclose (tmp))
                           {
                             ++errors;
                           }
                         /* Make sure that the handle pointed to by 'cur' still exists.
                            lt_dlclose recursively closes dependent libraries which removes
                            them from the linked list.  One of these might be the one
                            pointed to by 'cur'.  */
                         if (cur)
                           {
                             for (tmp = handles; tmp; tmp = tmp->next)
                               if (tmp == cur)
                                 break;
                             if (! tmp)
                               cur = handles;
                           }
                     }                      }
                 }                  }
             }              }
Line 1850  lt_dlexit () Line 325  lt_dlexit ()
             break;              break;
         }          }
   
         /* When removing loaders, we can only find out failure by testing
            the error string, so avoid a spurious one from an earlier
            failed command. */
         if (!errors)
           LT__SETERRORSTR (0);
   
       /* close all loaders */        /* close all loaders */
       while (loader)        for (loader = (lt_dlloader *) lt_dlloader_next (NULL); loader;)
         {          {
           lt_dlloader *next = loader->next;            lt_dlloader *next   = (lt_dlloader *) lt_dlloader_next (loader);
           lt_user_data data = loader->dlloader_data;            lt_dlvtable *vtable = (lt_dlvtable *) lt_dlloader_get (loader);
           if (loader->dlloader_exit && loader->dlloader_exit (data))  
             if ((vtable = lt_dlloader_remove ((char *) vtable->name)))
             {              {
               ++errors;                FREE (vtable);
               }
             else
               {
                 /* ignore errors due to resident modules */
                 const char *err;
                 LT__GETERROR (err);
                 if (err)
                   ++errors;
             }              }
   
           LT_DLMEM_REASSIGN (loader, next);            loader = next;
         }          }
       loaders = NULL;  
         FREE(user_search_path);
     }      }
   
  done:   done:
   LT_DLMUTEX_UNLOCK ();  
   return errors;    return errors;
 }  }
   
   
   /* Try VTABLE or, if VTABLE is NULL, all available loaders for FILENAME.
      If the library is not successfully loaded, return non-zero.  Otherwise,
      the dlhandle is stored at the address given in PHANDLE.  */
 static int  static int
 tryall_dlopen (handle, filename)  tryall_dlopen (lt_dlhandle *phandle, const char *filename,
      lt_dlhandle *handle;                 lt_dladvise advise, const lt_dlvtable *vtable)
      const char *filename;  {
 {    lt_dlhandle   handle          = handles;
   lt_dlhandle    cur;    const char *  saved_error     = 0;
   lt_dlloader   *loader;    int           errors          = 0;
   const char    *saved_error;  
   int            errors         = 0;  
   
   LT_DLMUTEX_GETERROR (saved_error);  #ifdef LT_DEBUG_LOADERS
   LT_DLMUTEX_LOCK ();    fprintf (stderr, "tryall_dlopen (%s, %s)\n",
              filename ? filename : "(null)",
              vtable ? vtable->name : "(ALL)");
   #endif
   
   cur    = handles;    LT__GETERROR (saved_error);
   loader = loaders;  
   
   /* check whether the module was already opened */    /* check whether the module was already opened */
   while (cur)    for (;handle; handle = handle->next)
     {      {
       /* try to dlopen the program itself? */        if ((handle->info.filename == filename) /* dlopen self: 0 == 0 */
       if (!cur->info.filename && !filename)            || (handle->info.filename && filename
                 && streq (handle->info.filename, filename)))
         {          {
           break;            break;
         }          }
   
       if (cur->info.filename && filename  
           && strcmp (cur->info.filename, filename) == 0)  
         {  
           break;  
         }  
   
       cur = cur->next;  
     }      }
   
   if (cur)    if (handle)
     {      {
       ++cur->info.ref_count;        ++handle->info.ref_count;
       *handle = cur;        *phandle = handle;
       goto done;        goto done;
     }      }
   
   cur = *handle;    handle = *phandle;
   if (filename)    if (filename)
     {      {
       cur->info.filename = lt_estrdup (filename);        /* Comment out the check of file permissions using access.
       if (!cur->info.filename)           This call seems to always return -1 with error EACCES.
         */
         /* We need to catch missing file errors early so that
            file_not_found() can detect what happened.
         if (access (filename, R_OK) != 0)
           {
             LT__SETERROR (FILE_NOT_FOUND);
             ++errors;
             goto done;
           } */
   
         handle->info.filename = lt__strdup (filename);
         if (!handle->info.filename)
         {          {
           ++errors;            ++errors;
           goto done;            goto done;
Line 1923  tryall_dlopen (handle, filename) Line 422  tryall_dlopen (handle, filename)
     }      }
   else    else
     {      {
       cur->info.filename = NULL;        handle->info.filename = 0;
     }      }
   
   while (loader)    {
     {      lt_dlloader loader = lt_dlloader_next (0);
       lt_user_data data = loader->dlloader_data;      const lt_dlvtable *loader_vtable;
   
       cur->module = loader->module_open (data, filename);      do
         {
           if (vtable)
             loader_vtable = vtable;
           else
             loader_vtable = lt_dlloader_get (loader);
   
   #ifdef LT_DEBUG_LOADERS
           fprintf (stderr, "Calling %s->module_open (%s)\n",
                    (loader_vtable && loader_vtable->name) ? loader_vtable->name : "(null)",
                    filename ? filename : "(null)");
   #endif
           handle->module = (*loader_vtable->module_open) (loader_vtable->dlloader_data,
                                                           filename, advise);
   #ifdef LT_DEBUG_LOADERS
           fprintf (stderr, "  Result: %s\n",
                    handle->module ? "Success" : "Failed");
   #endif
   
       if (cur->module != NULL)          if (handle->module != 0)
         {            {
           break;              if (advise)
         }                {
       loader = loader->next;                  handle->info.is_resident  = advise->is_resident;
     }                  handle->info.is_symglobal = advise->is_symglobal;
                   handle->info.is_symlocal  = advise->is_symlocal;
                 }
               break;
             }
         }
       while (!vtable && (loader = lt_dlloader_next (loader)));
   
   if (!loader)      /* If VTABLE was given but couldn't open the module, or VTABLE wasn't
     {         given but we exhausted all loaders without opening the module, bail
       LT_DLFREE (cur->info.filename);         out!  */
       ++errors;      if ((vtable && !handle->module)
       goto done;          || (!vtable && !loader))
     }        {
           FREE (handle->info.filename);
           ++errors;
           goto done;
         }
   
   cur->loader   = loader;      handle->vtable = loader_vtable;
   LT_DLMUTEX_SETERROR (saved_error);    }
   
  done:    LT__SETERRORSTR (saved_error);
   LT_DLMUTEX_UNLOCK ();  
   
    done:
   return errors;    return errors;
 }  }
   
   
 static int  static int
 tryall_dlopen_module (handle, prefix, dirname, dlname)  tryall_dlopen_module (lt_dlhandle *handle, const char *prefix,
      lt_dlhandle *handle;                        const char *dirname, const char *dlname,
      const char *prefix;                        lt_dladvise advise)
      const char *dirname;  
      const char *dlname;  
 {  {
   int      error        = 0;    int      error        = 0;
   char     *filename    = NULL;    char     *filename    = 0;
   size_t   filename_len = 0;    size_t   filename_len = 0;
   size_t   dirname_len  = LT_STRLEN (dirname);    size_t   dirname_len  = LT_STRLEN (dirname);
   
   assert (handle);    assert (handle);
   assert (dirname);    assert (dirname);
   assert (dlname);    assert (dlname);
 #ifdef LT_DIRSEP_CHAR  #if defined(LT_DIRSEP_CHAR)
   /* Only canonicalized names (i.e. with DIRSEP chars already converted)    /* Only canonicalized names (i.e. with DIRSEP chars already converted)
      should make it into this function:  */       should make it into this function:  */
   assert (strchr (dirname, LT_DIRSEP_CHAR) == NULL);    assert (strchr (dirname, LT_DIRSEP_CHAR) == 0);
 #endif  #endif
   
   if (dirname[dirname_len -1] == '/')    if (dirname_len > 0)
     --dirname_len;      if (dirname[dirname_len -1] == '/')
         --dirname_len;
   filename_len = dirname_len + 1 + LT_STRLEN (dlname);    filename_len = dirname_len + 1 + LT_STRLEN (dlname);
   
   /* Allocate memory, and combine DIRNAME and MODULENAME into it.    /* Allocate memory, and combine DIRNAME and MODULENAME into it.
      The PREFIX (if any) is handled below.  */       The PREFIX (if any) is handled below.  */
   filename  = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1);    filename  = MALLOC (char, filename_len + 1);
   if (!filename)    if (!filename)
     return 1;      return 1;
   
Line 1993  tryall_dlopen_module (handle, prefix, di Line 519  tryall_dlopen_module (handle, prefix, di
      shuffled.  Otherwise, attempt to open FILENAME as a module.  */       shuffled.  Otherwise, attempt to open FILENAME as a module.  */
   if (prefix)    if (prefix)
     {      {
       error += tryall_dlopen_module (handle,        error += tryall_dlopen_module (handle, (const char *) 0,
                                      (const char *) 0, prefix, filename);                                       prefix, filename, advise);
     }      }
   else if (tryall_dlopen (handle, filename) != 0)    else if (tryall_dlopen (handle, filename, advise, 0) != 0)
     {      {
       ++error;        ++error;
     }      }
   
   LT_DLFREE (filename);    FREE (filename);
   return error;    return error;
 }  }
   
 static int  static int
 find_module (handle, dir, libdir, dlname, old_name, installed)  find_module (lt_dlhandle *handle, const char *dir, const char *libdir,
      lt_dlhandle *handle;               const char *dlname,  const char *old_name, int installed,
      const char *dir;               lt_dladvise advise)
      const char *libdir;  
      const char *dlname;  
      const char *old_name;  
      int installed;  
 {  {
   /* Try to open the old library first; if it was dlpreopened,    /* Try to open the old library first; if it was dlpreopened,
      we want the preopened version of it, even if a dlopenable       we want the preopened version of it, even if a dlopenable
      module is available.  */       module is available.  */
   if (old_name && tryall_dlopen (handle, old_name) == 0)    if (old_name && tryall_dlopen (handle, old_name,
                             advise, lt_dlloader_find ("lt_preopen") ) == 0)
     {      {
       return 0;        return 0;
     }      }
Line 2028  find_module (handle, dir, libdir, dlname Line 551  find_module (handle, dir, libdir, dlname
       /* try to open the installed module */        /* try to open the installed module */
       if (installed && libdir)        if (installed && libdir)
         {          {
           if (tryall_dlopen_module (handle,            if (tryall_dlopen_module (handle, (const char *) 0,
                                     (const char *) 0, libdir, dlname) == 0)                                      libdir, dlname, advise) == 0)
             return 0;              return 0;
         }          }
   
       /* try to open the not-installed module */        /* try to open the not-installed module */
       if (!installed)        if (!installed)
         {          {
           if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0)            if (tryall_dlopen_module (handle, dir, objdir,
                                       dlname, advise) == 0)
             return 0;              return 0;
         }          }
   
       /* maybe it was moved to another directory */        /* maybe it was moved to another directory */
       {        {
           if (tryall_dlopen_module (handle,            if (dir && (tryall_dlopen_module (handle, (const char *) 0,
                                     (const char *) 0, dir, dlname) == 0)                                              dir, dlname, advise) == 0))
             return 0;              return 0;
       }        }
     }      }
Line 2053  find_module (handle, dir, libdir, dlname Line 577  find_module (handle, dir, libdir, dlname
   
   
 static int  static int
 canonicalize_path (path, pcanonical)  canonicalize_path (const char *path, char **pcanonical)
      const char *path;  
      char **pcanonical;  
 {  {
   char *canonical = NULL;    char *canonical = 0;
   
   assert (path && *path);    assert (path && *path);
   assert (pcanonical);    assert (pcanonical);
   
   canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path));    canonical = MALLOC (char, 1+ LT_STRLEN (path));
   if (!canonical)    if (!canonical)
     return 1;      return 1;
   
Line 2084  canonicalize_path (path, pcanonical) Line 606  canonicalize_path (path, pcanonical)
   
         /* Anything other than a directory separator is copied verbatim.  */          /* Anything other than a directory separator is copied verbatim.  */
         if ((path[src] != '/')          if ((path[src] != '/')
 #ifdef LT_DIRSEP_CHAR  #if defined(LT_DIRSEP_CHAR)
             && (path[src] != LT_DIRSEP_CHAR)              && (path[src] != LT_DIRSEP_CHAR)
 #endif  #endif
             )              )
Line 2096  canonicalize_path (path, pcanonical) Line 618  canonicalize_path (path, pcanonical)
            NULL terminator.  */             NULL terminator.  */
         else if ((path[1+ src] != LT_PATHSEP_CHAR)          else if ((path[1+ src] != LT_PATHSEP_CHAR)
                  && (path[1+ src] != LT_EOS_CHAR)                   && (path[1+ src] != LT_EOS_CHAR)
 #ifdef LT_DIRSEP_CHAR  #if defined(LT_DIRSEP_CHAR)
                  && (path[1+ src] != LT_DIRSEP_CHAR)                   && (path[1+ src] != LT_DIRSEP_CHAR)
 #endif  #endif
                  && (path[1+ src] != '/'))                   && (path[1+ src] != '/'))
Line 2116  canonicalize_path (path, pcanonical) Line 638  canonicalize_path (path, pcanonical)
 }  }
   
 static int  static int
 argzize_path (path, pargz, pargz_len)  argzize_path (const char *path, char **pargz, size_t *pargz_len)
      const char *path;  
      char **pargz;  
      size_t *pargz_len;  
 {  {
   error_t error;    error_t error;
   
Line 2132  argzize_path (path, pargz, pargz_len) Line 651  argzize_path (path, pargz, pargz_len)
       switch (error)        switch (error)
         {          {
         case ENOMEM:          case ENOMEM:
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));            LT__SETERROR (NO_MEMORY);
           break;            break;
         default:          default:
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));            LT__SETERROR (UNKNOWN);
           break;            break;
         }          }
   
Line 2150  argzize_path (path, pargz, pargz_len) Line 669  argzize_path (path, pargz, pargz_len)
    non-zero or all elements are exhausted.  If BASE_NAME is non-NULL,     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.  */     it is appended to each SEARCH_PATH element before FUNC is called.  */
 static int  static int
 foreach_dirinpath (search_path, base_name, func, data1, data2)  foreach_dirinpath (const char *search_path, const char *base_name,
      const char *search_path;                     foreach_callback_func *func, void *data1, void *data2)
      const char *base_name;  
      foreach_callback_func *func;  
      lt_ptr data1;  
      lt_ptr data2;  
 {  {
   int    result         = 0;    int    result         = 0;
   int    filenamesize   = 0;    size_t filenamesize   = 0;
   size_t lenbase        = LT_STRLEN (base_name);    size_t lenbase        = LT_STRLEN (base_name);
   size_t argz_len       = 0;    size_t argz_len       = 0;
   char *argz            = NULL;    char *argz            = 0;
   char *filename        = NULL;    char *filename        = 0;
   char *canonical       = NULL;    char *canonical       = 0;
   
   LT_DLMUTEX_LOCK ();  
   
   if (!search_path || !*search_path)    if (!search_path || !*search_path)
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));        LT__SETERROR (FILE_NOT_FOUND);
       goto cleanup;        goto cleanup;
     }      }
   
Line 2180  foreach_dirinpath (search_path, base_nam Line 693  foreach_dirinpath (search_path, base_nam
     goto cleanup;      goto cleanup;
   
   {    {
     char *dir_name = NULL;      char *dir_name = 0;
     while ((dir_name = argz_next (argz, argz_len, dir_name)))      while ((dir_name = argz_next (argz, argz_len, dir_name)))
       {        {
         size_t lendir = LT_STRLEN (dir_name);          size_t lendir = LT_STRLEN (dir_name);
   
         if (lendir +1 +lenbase >= filenamesize)          if (1+ lendir + lenbase >= filenamesize)
         {          {
           LT_DLFREE (filename);            FREE (filename);
           filenamesize  = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */            filenamesize  = 1+ lendir + 1+ lenbase; /* "/d" + '/' + "f" + '\0' */
           filename      = LT_EMALLOC (char, filenamesize);            filename      = MALLOC (char, filenamesize);
           if (!filename)            if (!filename)
             goto cleanup;              goto cleanup;
         }          }
Line 2212  foreach_dirinpath (search_path, base_nam Line 725  foreach_dirinpath (search_path, base_nam
   }    }
   
  cleanup:   cleanup:
   LT_DLFREE (argz);    FREE (argz);
   LT_DLFREE (canonical);    FREE (canonical);
   LT_DLFREE (filename);    FREE (filename);
   
   LT_DLMUTEX_UNLOCK ();  
   
   return result;    return result;
 }  }
Line 2225  foreach_dirinpath (search_path, base_nam Line 736  foreach_dirinpath (search_path, base_nam
    in DATA1, and the opened FILE* structure address in DATA2.  Otherwise     in DATA1, and the opened FILE* structure address in DATA2.  Otherwise
    DATA1 is unchanged, but DATA2 is set to a pointer to NULL.  */     DATA1 is unchanged, but DATA2 is set to a pointer to NULL.  */
 static int  static int
 find_file_callback (filename, data1, data2)  find_file_callback (char *filename, void *data1, void *data2)
      char *filename;  
      lt_ptr data1;  
      lt_ptr data2;  
 {  {
   char       **pdir     = (char **) data1;    char       **pdir     = (char **) data1;
   FILE       **pfile    = (FILE **) data2;    FILE       **pfile    = (FILE **) data2;
Line 2245  find_file_callback (filename, data1, dat Line 753  find_file_callback (filename, data1, dat
       if (dirend > filename)        if (dirend > filename)
         *dirend   = LT_EOS_CHAR;          *dirend   = LT_EOS_CHAR;
   
       LT_DLFREE (*pdir);        FREE (*pdir);
       *pdir   = lt_estrdup (filename);        *pdir   = lt__strdup (filename);
       is_done = (*pdir == NULL) ? -1 : 1;        is_done = (*pdir == 0) ? -1 : 1;
     }      }
   
   return is_done;    return is_done;
 }  }
   
 static FILE *  static FILE *
 find_file (search_path, base_name, pdir)  find_file (const char *search_path, const char *base_name, char **pdir)
      const char *search_path;  
      const char *base_name;  
      char **pdir;  
 {  {
   FILE *file = NULL;    FILE *file = 0;
   
   foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file);    foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file);
   
Line 2267  find_file (search_path, base_name, pdir) Line 772  find_file (search_path, base_name, pdir)
 }  }
   
 static int  static int
 find_handle_callback (filename, data, ignored)  find_handle_callback (char *filename, void *data, void *data2)
      char *filename;  
      lt_ptr data;  
      lt_ptr ignored;  
 {  {
   lt_dlhandle  *handle          = (lt_dlhandle *) data;    lt_dlhandle  *phandle         = (lt_dlhandle *) data;
   int           notfound        = access (filename, R_OK);    int           notfound        = access (filename, R_OK);
     lt_dladvise   advise          = (lt_dladvise) data2;
   
   /* Bail out if file cannot be read...  */    /* Bail out if file cannot be read...  */
   if (notfound)    if (notfound)
Line 2281  find_handle_callback (filename, data, ig Line 784  find_handle_callback (filename, data, ig
   
   /* Try to dlopen the file, but do not continue searching in any    /* Try to dlopen the file, but do not continue searching in any
      case.  */       case.  */
   if (tryall_dlopen (handle, filename) != 0)    if (tryall_dlopen (phandle, filename, advise, 0) != 0)
     *handle = NULL;      *phandle = 0;
   
   return 1;    return 1;
 }  }
Line 2290  find_handle_callback (filename, data, ig Line 793  find_handle_callback (filename, data, ig
 /* If HANDLE was found return it, otherwise return 0.  If HANDLE was  /* If HANDLE was found return it, otherwise return 0.  If HANDLE was
    found but could not be opened, *HANDLE will be set to 0.  */     found but could not be opened, *HANDLE will be set to 0.  */
 static lt_dlhandle *  static lt_dlhandle *
 find_handle (search_path, base_name, handle)  find_handle (const char *search_path, const char *base_name,
      const char *search_path;               lt_dlhandle *phandle, lt_dladvise advise)
      const char *base_name;  
      lt_dlhandle *handle;  
 {  {
   if (!search_path)    if (!search_path)
     return 0;      return 0;
   
   if (!foreach_dirinpath (search_path, base_name, find_handle_callback,    if (!foreach_dirinpath (search_path, base_name, find_handle_callback,
                           handle, 0))                            phandle, advise))
     return 0;      return 0;
   
   return handle;    return phandle;
 }  }
   
   #if !defined(LTDL_DLOPEN_DEPLIBS)
 static int  static int
 load_deplibs (handle, deplibs)  load_deplibs (lt_dlhandle handle, char * LT__UNUSED deplibs)
      lt_dlhandle handle;  
      char *deplibs;  
 {  {
 #if LTDL_DLOPEN_DEPLIBS    handle->depcount = 0;
   char  *p, *save_search_path = NULL;    return 0;
   }
   
   #else /* defined(LTDL_DLOPEN_DEPLIBS) */
   static int
   load_deplibs (lt_dlhandle handle, char *deplibs)
   {
     char  *p, *save_search_path = 0;
   int   depcount = 0;    int   depcount = 0;
   int   i;    int   i;
   char  **names = NULL;    char  **names = 0;
 #endif  
   int   errors = 0;    int   errors = 0;
   
   handle->depcount = 0;    handle->depcount = 0;
   
 #if LTDL_DLOPEN_DEPLIBS  
   if (!deplibs)    if (!deplibs)
     {      {
       return errors;        return errors;
     }      }
   ++errors;    ++errors;
   
   LT_DLMUTEX_LOCK ();  
   if (user_search_path)    if (user_search_path)
     {      {
       save_search_path = lt_estrdup (user_search_path);        save_search_path = lt__strdup (user_search_path);
       if (!save_search_path)        if (!save_search_path)
         goto cleanup;          goto cleanup;
     }      }
Line 2339  load_deplibs (handle, deplibs) Line 843  load_deplibs (handle, deplibs)
   p = deplibs;    p = deplibs;
   while (*p)    while (*p)
     {      {
       if (!isspace ((int) *p))        if (!isspace ((unsigned char) *p))
         {          {
           char *end = p+1;            char *end = p+1;
           while (*end && !isspace((int) *end))            while (*end && !isspace((unsigned char) *end))
             {              {
               ++end;                ++end;
             }              }
Line 2350  load_deplibs (handle, deplibs) Line 854  load_deplibs (handle, deplibs)
           if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0)            if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0)
             {              {
               char save = *end;                char save = *end;
               *end = '\0'; /* set a temporary string terminator */                *end = 0; /* set a temporary string terminator */
               if (lt_dladdsearchdir(p+2))                if (lt_dladdsearchdir(p+2))
                 {                  {
                   goto cleanup;                    goto cleanup;
Line 2370  load_deplibs (handle, deplibs) Line 874  load_deplibs (handle, deplibs)
         }          }
     }      }
   
   /* restore the old search path */  
   LT_DLFREE (user_search_path);  
   user_search_path = save_search_path;  
   
   LT_DLMUTEX_UNLOCK ();  
   
   if (!depcount)    if (!depcount)
     {      {
Line 2382  load_deplibs (handle, deplibs) Line 881  load_deplibs (handle, deplibs)
       goto cleanup;        goto cleanup;
     }      }
   
   names = LT_EMALLOC (char *, depcount * sizeof (char*));    names = MALLOC (char *, depcount);
   if (!names)    if (!names)
     goto cleanup;      goto cleanup;
   
Line 2391  load_deplibs (handle, deplibs) Line 890  load_deplibs (handle, deplibs)
   p = deplibs;    p = deplibs;
   while (*p)    while (*p)
     {      {
       if (isspace ((int) *p))        if (isspace ((unsigned char) *p))
         {          {
           ++p;            ++p;
         }          }
       else        else
         {          {
           char *end = p+1;            char *end = p+1;
           while (*end && !isspace ((int) *end))            while (*end && !isspace ((unsigned char) *end))
             {              {
               ++end;                ++end;
             }              }
Line 2407  load_deplibs (handle, deplibs) Line 906  load_deplibs (handle, deplibs)
             {              {
               char *name;                char *name;
               char save = *end;                char save = *end;
               *end = '\0'; /* set a temporary string terminator */                *end = 0; /* set a temporary string terminator */
               if (strncmp(p, "-l", 2) == 0)                if (strncmp(p, "-l", 2) == 0)
                 {                  {
                   size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2);                    size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2);
                   name = LT_EMALLOC (char, 1+ name_len);                    name = MALLOC (char, 1+ name_len);
                   if (name)                    if (name)
                     sprintf (name, "lib%s", p+2);                      sprintf (name, "lib%s", p+2);
                 }                  }
               else                else
                 name = lt_estrdup(p);                  name = lt__strdup(p);
   
               if (!name)                if (!name)
                 goto cleanup_names;                  goto cleanup_names;
Line 2435  load_deplibs (handle, deplibs) Line 934  load_deplibs (handle, deplibs)
      later on if the loaded module cannot resolve all of its symbols.  */       later on if the loaded module cannot resolve all of its symbols.  */
   if (depcount)    if (depcount)
     {      {
         lt_dlhandle cur = handle;
       int       j = 0;        int       j = 0;
   
       handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount);        cur->deplibs = MALLOC (lt_dlhandle, depcount);
       if (!handle->deplibs)        if (!cur->deplibs)
         goto cleanup;          goto cleanup_names;
   
       for (i = 0; i < depcount; ++i)        for (i = 0; i < depcount; ++i)
         {          {
           handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]);            cur->deplibs[j] = lt_dlopenext(names[depcount-1-i]);
           if (handle->deplibs[j])            if (cur->deplibs[j])
             {              {
               ++j;                ++j;
             }              }
         }          }
   
       handle->depcount  = j;    /* Number of successfully loaded deplibs */        cur->depcount     = j;    /* Number of successfully loaded deplibs */
       errors            = 0;        errors            = 0;
     }      }
   
  cleanup_names:   cleanup_names:
   for (i = 0; i < depcount; ++i)    for (i = 0; i < depcount; ++i)
     {      {
       LT_DLFREE (names[i]);        FREE (names[i]);
     }      }
   
  cleanup:   cleanup:
   LT_DLFREE (names);    FREE (names);
 #endif    /* restore the old search path */
     if (save_search_path) {
       MEMREASSIGN (user_search_path, save_search_path);
     }
   
   return errors;    return errors;
 }  }
   #endif /* defined(LTDL_DLOPEN_DEPLIBS) */
   
 static int  static int
 unload_deplibs (handle)  unload_deplibs (lt_dlhandle handle)
      lt_dlhandle handle;  
 {  {
   int i;    int i;
   int errors = 0;    int errors = 0;
     lt_dlhandle cur = handle;
   
   if (handle->depcount)    if (cur->depcount)
     {      {
       for (i = 0; i < handle->depcount; ++i)        for (i = 0; i < cur->depcount; ++i)
         {          {
           if (!LT_DLIS_RESIDENT (handle->deplibs[i]))            if (!LT_DLIS_RESIDENT (cur->deplibs[i]))
             {              {
               errors += lt_dlclose (handle->deplibs[i]);                errors += lt_dlclose (cur->deplibs[i]);
             }              }
         }          }
         FREE (cur->deplibs);
     }      }
   
   return errors;    return errors;
 }  }
   
 static int  static int
 trim (dest, str)  trim (char **dest, const char *str)
      char **dest;  
      const char *str;  
 {  {
   /* remove the leading and trailing "'" from str    /* remove the leading and trailing "'" from str
      and store the result in dest */       and store the result in dest */
Line 2499  trim (dest, str) Line 1002  trim (dest, str)
   size_t len        = LT_STRLEN (str);    size_t len        = LT_STRLEN (str);
   char *tmp;    char *tmp;
   
   LT_DLFREE (*dest);    FREE (*dest);
   
     if (!end || end == str)
       return 1;
   
   if (len > 3 && str[0] == '\'')    if (len > 3 && str[0] == '\'')
     {      {
       tmp = LT_EMALLOC (char, end - str);        tmp = MALLOC (char, end - str);
       if (!tmp)        if (!tmp)
         return 1;          return 1;
   
       strncpy(tmp, &str[1], (end - str) - 1);        memcpy(tmp, &str[1], (end - str) - 1);
       tmp[len-3] = LT_EOS_CHAR;        tmp[(end - str) - 1] = LT_EOS_CHAR;
       *dest = tmp;        *dest = tmp;
     }      }
   else    else
     {      {
       *dest = NULL;        *dest = 0;
     }      }
   
   return 0;    return 0;
 }  }
   
   /* Read the .la file FILE. */
 static int  static int
 free_vars (dlname, oldname, libdir, deplibs)  parse_dotla_file(FILE *file, char **dlname, char **libdir, char **deplibs,
      char *dlname;      char **old_name, int *installed)
      char *oldname;  {
      char *libdir;    int           errors = 0;
      char *deplibs;    size_t        line_len = LT_FILENAME_MAX;
 {    char *        line = MALLOC (char, line_len);
   LT_DLFREE (dlname);  
   LT_DLFREE (oldname);  
   LT_DLFREE (libdir);  
   LT_DLFREE (deplibs);  
   
   return 0;    if (!line)
       {
         LT__SETERROR (FILE_NOT_FOUND);
         return 1;
       }
   
     while (!feof (file))
       {
         line[line_len-2] = '\0';
         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.
            Behave even if the file contains NUL bytes due to corruption. */
         while (line[line_len-2] != '\0' && line[line_len-2] != '\n' && !feof (file))
           {
             line = REALLOC (char, line, line_len *2);
             if (!line)
               {
                 ++errors;
                 goto cleanup;
               }
             line[line_len * 2 - 2] = '\0';
             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]);
           }
   
         /* Windows native tools do not understand the POSIX paths we store
            in libdir. */
   #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]);
   #ifdef __WINDOWS__
             /* Disallow following unix-style paths on MinGW.  */
             if (*libdir && (**libdir == '/' || **libdir == '\\'))
               **libdir = '\0';
   #endif
           }
   
   #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 (streq (line, "installed=yes\n"))
           {
             *installed = 1;
           }
         else if (streq (line, "installed=no\n"))
           {
             *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, ' ')) != 0)
               {
                 last_libname = lt__strdup (last_libname + 1);
                 if (!last_libname)
                   {
                     ++errors;
                     goto cleanup;
                   }
                 MEMREASSIGN (*dlname, last_libname);
               }
           }
   
         if (errors)
           break;
       }
   cleanup:
     FREE (line);
     return errors;
 }  }
   
   
   /* Try to open FILENAME as a module. */
 static int  static int
 try_dlopen (phandle, filename)  try_dlopen (lt_dlhandle *phandle, const char *filename, const char *ext,
      lt_dlhandle *phandle;              lt_dladvise advise)
      const char *filename;  {
 {    const char *  saved_error     = 0;
   const char *  ext             = NULL;    char *        archive_name    = 0;
   const char *  saved_error     = NULL;    char *        canonical       = 0;
   char *        canonical       = NULL;    char *        base_name       = 0;
   char *        base_name       = NULL;    char *        dir             = 0;
   char *        dir             = NULL;    char *        name            = 0;
   char *        name            = NULL;    char *        attempt         = 0;
   int           errors          = 0;    int           errors          = 0;
   lt_dlhandle   newhandle;    lt_dlhandle   newhandle;
   
   assert (phandle);    assert (phandle);
   assert (*phandle == NULL);    assert (*phandle == 0);
   
   LT_DLMUTEX_GETERROR (saved_error);  #ifdef LT_DEBUG_LOADERS
     fprintf (stderr, "try_dlopen (%s, %s)\n",
              filename ? filename : "(null)",
              ext ? ext : "(null)");
   #endif
   
     LT__GETERROR (saved_error);
   
   /* dlopen self? */    /* dlopen self? */
   if (!filename)    if (!filename)
     {      {
       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);        *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle));
       if (*phandle == NULL)        if (*phandle == 0)
         return 1;          return 1;
   
       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));  
       newhandle = *phandle;        newhandle = *phandle;
   
       /* lt_dlclose()ing yourself is very bad!  Disallow it.  */        /* lt_dlclose()ing yourself is very bad!  Disallow it.  */
       LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG);        newhandle->info.is_resident = 1;
   
       if (tryall_dlopen (&newhandle, 0) != 0)        if (tryall_dlopen (&newhandle, 0, advise, 0) != 0)
         {          {
           LT_DLFREE (*phandle);            FREE (*phandle);
           return 1;            return 1;
         }          }
   
Line 2577  try_dlopen (phandle, filename) Line 1196  try_dlopen (phandle, filename)
   
   assert (filename && *filename);    assert (filename && *filename);
   
     if (ext)
       {
         attempt = MALLOC (char, LT_STRLEN (filename) + LT_STRLEN (ext) + 1);
         if (!attempt)
           return 1;
   
         sprintf(attempt, "%s%s", filename, ext);
       }
     else
       {
         attempt = lt__strdup (filename);
         if (!attempt)
           return 1;
       }
   
   /* Doing this immediately allows internal functions to safely    /* Doing this immediately allows internal functions to safely
      assume only canonicalized paths are passed.  */       assume only canonicalized paths are passed.  */
   if (canonicalize_path (filename, &canonical) != 0)    if (canonicalize_path (attempt, &canonical) != 0)
     {      {
       ++errors;        ++errors;
       goto cleanup;        goto cleanup;
Line 2592  try_dlopen (phandle, filename) Line 1226  try_dlopen (phandle, filename)
     {      {
       size_t dirlen = (1+ base_name) - canonical;        size_t dirlen = (1+ base_name) - canonical;
   
       dir = LT_EMALLOC (char, 1+ dirlen);        dir = MALLOC (char, 1+ dirlen);
       if (!dir)        if (!dir)
         {          {
           ++errors;            ++errors;
Line 2605  try_dlopen (phandle, filename) Line 1239  try_dlopen (phandle, filename)
       ++base_name;        ++base_name;
     }      }
   else    else
     LT_DLMEM_REASSIGN (base_name, canonical);      MEMREASSIGN (base_name, canonical);
   
   assert (base_name && *base_name);    assert (base_name && *base_name);
   
   /* Check whether we are opening a libtool module (.la extension).  */  
   ext = strrchr (base_name, '.');    ext = strrchr (base_name, '.');
   if (ext && strcmp (ext, archive_ext) == 0)    if (!ext)
     {      {
       /* this seems to be a libtool module */        ext = base_name + LT_STRLEN (base_name);
       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 */    /* extract the module name from the file name */
       name = LT_EMALLOC (char, ext - base_name + 1);    name = MALLOC (char, ext - base_name + 1);
       if (!name)    if (!name)
         {      {
           ++errors;        ++errors;
           goto cleanup;        goto cleanup;
         }      }
   
       /* canonicalize the module name */    /* canonicalize the module name */
     {
       int i;
       for (i = 0; i < ext - base_name; ++i)
       {        {
         size_t i;          if (isalnum ((unsigned char)(base_name[i])))
         for (i = 0; i < ext - base_name; ++i)  
           {            {
             if (isalnum ((int)(base_name[i])))              name[i] = base_name[i];
               {            }
                 name[i] = base_name[i];          else
               }            {
             else              name[i] = '_';
               {  
                 name[i] = '_';  
               }  
           }            }
         name[ext - base_name] = LT_EOS_CHAR;  
       }        }
       name[ext - base_name] = LT_EOS_CHAR;
     }
   
     /* Before trawling through the filesystem in search of a module,
        check whether we are opening a preloaded module.  */
     if (!dir)
       {
         const lt_dlvtable *vtable = lt_dlloader_find ("lt_preopen");
   
         if (vtable)
           {
             /* libprefix + name + "." + libext + NULL */
             archive_name = MALLOC (char, strlen (libprefix) + LT_STRLEN (name) + strlen (libext) + 2);
             *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle));
   
             if ((*phandle == NULL) || (archive_name == NULL))
               {
                 ++errors;
                 goto cleanup;
               }
             newhandle = *phandle;
   
             /* Preloaded modules are always named according to their old
                archive name.  */
             if (strncmp(name, "lib", 3) == 0)
               {
                 sprintf (archive_name, "%s%s.%s", libprefix, name + 3, libext);
               }
             else
               {
                 sprintf (archive_name, "%s.%s", name, libext);
               }
   
             if (tryall_dlopen (&newhandle, archive_name, advise, vtable) == 0)
               {
                 goto register_handle;
               }
   
             /* If we're still here, there was no matching preloaded module,
                so put things back as we found them, and continue searching.  */
             FREE (*phandle);
             newhandle = NULL;
           }
       }
   
     /* If we are allowing only preloaded modules, and we didn't find
        anything yet, give up on the search here.  */
     if (advise && advise->try_preload_only)
       {
         goto cleanup;
       }
   
     /* Check whether we are opening a libtool module (.la extension).  */
     if (ext && streq (ext, archive_ext))
       {
         /* this seems to be a libtool module */
         FILE *    file     = 0;
         char *    dlname   = 0;
         char *    old_name = 0;
         char *    libdir   = 0;
         char *    deplibs  = 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;
   
       /* Now try to open the .la file.  If there is no directory name        /* 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           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           prescribed paths.  Otherwise (or in any case if the module was not
          yet found) try opening just the module name as passed.  */           yet found) try opening just the module name as passed.  */
       if (!dir)        if (!dir)
         {          {
           const char *search_path;            const char *search_path = user_search_path;
   
           LT_DLMUTEX_LOCK ();  
           search_path = user_search_path;  
           if (search_path)            if (search_path)
             file = find_file (user_search_path, base_name, &dir);              file = find_file (user_search_path, base_name, &dir);
           LT_DLMUTEX_UNLOCK ();  
   
           if (!file)            if (!file)
             {              {
Line 2673  try_dlopen (phandle, filename) Line 1356  try_dlopen (phandle, filename)
                 file = find_file (search_path, base_name, &dir);                  file = find_file (search_path, base_name, &dir);
             }              }
   
 #ifdef LTDL_SHLIBPATH_VAR  #if defined(LT_MODULE_PATH_VAR)
           if (!file)            if (!file)
             {              {
               search_path = getenv (LTDL_SHLIBPATH_VAR);                search_path = getenv (LT_MODULE_PATH_VAR);
               if (search_path)                if (search_path)
                 file = find_file (search_path, base_name, &dir);                  file = find_file (search_path, base_name, &dir);
             }              }
 #endif  #endif
 #ifdef LTDL_SYSSEARCHPATH  #if defined(LT_DLSEARCH_PATH)
           if (!file && sys_search_path)            if (!file && *sys_dlsearch_path)
             {              {
               file = find_file (sys_search_path, base_name, &dir);                file = find_file (sys_dlsearch_path, base_name, &dir);
             }              }
 #endif  #endif
         }          }
       if (!file)        else
         {          {
           file = fopen (filename, LT_READTEXT_MODE);            file = fopen (attempt, LT_READTEXT_MODE);
         }          }
   
       /* If we didn't find the file by now, it really isn't there.  Set        /* If we didn't find the file by now, it really isn't there.  Set
          the status flag, and bail out.  */           the status flag, and bail out.  */
       if (!file)        if (!file)
         {          {
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));            LT__SETERROR (FILE_NOT_FOUND);
           ++errors;  
           goto cleanup;  
         }  
   
       line_len = LT_FILENAME_MAX;  
       line = LT_EMALLOC (char, line_len);  
       if (!line)  
         {  
           fclose (file);  
           ++errors;            ++errors;
           goto cleanup;            goto cleanup;
         }          }
   
       /* read the .la file */        /* read the .la file */
       while (!feof (file))        if (parse_dotla_file(file, &dlname, &libdir, &deplibs,
         {              &old_name, &installed) != 0)
           if (!fgets (line, (int) line_len, file))          ++errors;
             {  
               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);        fclose (file);
       LT_DLFREE (line);  
   
       /* allocate the handle */        /* allocate the handle */
       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);        *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle));
       if (*phandle == NULL)        if (*phandle == 0)
         ++errors;          ++errors;
   
       if (errors)        if (errors)
         {          {
           free_vars (dlname, old_name, libdir, deplibs);            FREE (dlname);
           LT_DLFREE (*phandle);            FREE (old_name);
             FREE (libdir);
             FREE (deplibs);
             FREE (*phandle);
           goto cleanup;            goto cleanup;
         }          }
   
       assert (*phandle);        assert (*phandle);
   
       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));  
       if (load_deplibs (*phandle, deplibs) == 0)        if (load_deplibs (*phandle, deplibs) == 0)
         {          {
           newhandle = *phandle;            newhandle = *phandle;
           /* find_module may replace newhandle */            /* find_module may replace newhandle */
           if (find_module (&newhandle, dir, libdir, dlname, old_name, installed))            if (find_module (&newhandle, dir, libdir, dlname, old_name,
                              installed, advise))
             {              {
               unload_deplibs (*phandle);                unload_deplibs (*phandle);
               ++errors;                ++errors;
Line 2831  try_dlopen (phandle, filename) Line 1425  try_dlopen (phandle, filename)
           ++errors;            ++errors;
         }          }
   
       free_vars (dlname, old_name, libdir, deplibs);        FREE (dlname);
         FREE (old_name);
         FREE (libdir);
         FREE (deplibs);
   
       if (errors)        if (errors)
         {          {
           LT_DLFREE (*phandle);            FREE (*phandle);
           goto cleanup;            goto cleanup;
         }          }
   
Line 2846  try_dlopen (phandle, filename) Line 1444  try_dlopen (phandle, filename)
   else    else
     {      {
       /* not a libtool module */        /* not a libtool module */
       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);        *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle));
       if (*phandle == NULL)        if (*phandle == 0)
         {          {
           ++errors;            ++errors;
           goto cleanup;            goto cleanup;
         }          }
   
       memset (*phandle, 0, sizeof (struct lt_dlhandle_struct));  
       newhandle = *phandle;        newhandle = *phandle;
   
       /* If the module has no directory name component, try to find it        /* If the module has no directory name component, try to find it
          first in user_search_path and then other prescribed paths.           first in user_search_path and then other prescribed paths.
          Otherwise (or in any case if the module was not yet found) try           Otherwise (or in any case if the module was not yet found) try
          opening just the module name as passed.  */           opening just the module name as passed.  */
       if ((dir || (!find_handle (user_search_path, base_name, &newhandle)        if ((dir || (!find_handle (user_search_path, base_name,
                                    &newhandle, advise)
                    && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name,                     && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name,
                                     &newhandle)                                      &newhandle, advise)
 #ifdef LTDL_SHLIBPATH_VAR  #if defined(LT_MODULE_PATH_VAR)
                    && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name,                     && !find_handle (getenv (LT_MODULE_PATH_VAR), base_name,
                                     &newhandle)                                      &newhandle, advise)
 #endif  #endif
 #ifdef LTDL_SYSSEARCHPATH  #if defined(LT_DLSEARCH_PATH)
                    && !find_handle (sys_search_path, base_name, &newhandle)                     && !find_handle (sys_dlsearch_path, base_name,
                                       &newhandle, advise)
 #endif  #endif
                    )))                     )))
         {          {
           if (tryall_dlopen (&newhandle, filename) != 0)            if (tryall_dlopen (&newhandle, attempt, advise, 0) != 0)
             {              {
               newhandle = NULL;                newhandle = NULL;
             }              }
         }          }
   
       if (!newhandle)        if (!newhandle)
         {          {
           LT_DLFREE (*phandle);            FREE (*phandle);
           ++errors;            ++errors;
           goto cleanup;            goto cleanup;
         }          }
     }      }
   
  register_handle:   register_handle:
   LT_DLMEM_REASSIGN (*phandle, newhandle);    MEMREASSIGN (*phandle, newhandle);
   
   if ((*phandle)->info.ref_count == 0)    if ((*phandle)->info.ref_count == 0)
     {      {
       (*phandle)->info.ref_count        = 1;        (*phandle)->info.ref_count        = 1;
       LT_DLMEM_REASSIGN ((*phandle)->info.name, name);        MEMREASSIGN ((*phandle)->info.name, name);
   
       LT_DLMUTEX_LOCK ();        (*phandle)->next  = handles;
       (*phandle)->next          = handles;        handles           = *phandle;
       handles                   = *phandle;  
       LT_DLMUTEX_UNLOCK ();  
     }      }
   
   LT_DLMUTEX_SETERROR (saved_error);    LT__SETERRORSTR (saved_error);
   
  cleanup:   cleanup:
   LT_DLFREE (dir);    FREE (dir);
   LT_DLFREE (name);    FREE (attempt);
   LT_DLFREE (canonical);    FREE (name);
     if (!canonical)               /* was MEMREASSIGNed */
       FREE (base_name);
     FREE (canonical);
     FREE (archive_name);
   
   return errors;    return errors;
 }  }
   
 lt_dlhandle  
 lt_dlopen (filename)  /* If the last error message stored was `FILE_NOT_FOUND', then return
      const char *filename;     non-zero.  */
   static int
   file_not_found (void)
 {  {
   lt_dlhandle handle = NULL;    const char *error = 0;
   
   /* Just incase we missed a code path in try_dlopen() that reports    LT__GETERROR (error);
      an error, but forgets to reset handle... */    if (error == LT__STRERROR (FILE_NOT_FOUND))
   if (try_dlopen (&handle, filename) != 0)      return 1;
     return 0;  
   
   return handle;    return 0;
 }  }
   
 /* If the last error messge store was `FILE_NOT_FOUND', then return  
    non-zero.  */  /* Unless FILENAME already bears a suitable library extension, then
      return 0.  */
 static int  static int
 file_not_found ()  has_library_ext (const char *filename)
 {  {
   const char *error = NULL;    const char *  ext     = 0;
   
   LT_DLMUTEX_GETERROR (error);    assert (filename);
   if (error == LT_DLSTRERROR (FILE_NOT_FOUND))  
     return 1;  
   
     ext = strrchr (filename, '.');
   
     if (ext && ((streq (ext, archive_ext))
   #if defined(LT_MODULE_EXT)
                || (streq (ext, shlib_ext))
   #endif
   #if defined(LT_SHARED_EXT)
                || (streq (ext, shared_ext))
   #endif
       ))
       {
         return 1;
       }
   
     return 0;
   }
   
   
   /* Initialise and configure a user lt_dladvise opaque object.  */
   
   int
   lt_dladvise_init (lt_dladvise *padvise)
   {
     lt_dladvise advise = (lt_dladvise) lt__zalloc (sizeof (struct lt__advise));
     *padvise = advise;
     return (advise ? 0 : 1);
   }
   
   int
   lt_dladvise_destroy (lt_dladvise *padvise)
   {
     if (padvise)
       FREE(*padvise);
   return 0;    return 0;
 }  }
   
 /* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to  int
   lt_dladvise_ext (lt_dladvise *padvise)
   {
     assert (padvise && *padvise);
     (*padvise)->try_ext = 1;
     return 0;
   }
   
   int
   lt_dladvise_resident (lt_dladvise *padvise)
   {
     assert (padvise && *padvise);
     (*padvise)->is_resident = 1;
     return 0;
   }
   
   int
   lt_dladvise_local (lt_dladvise *padvise)
   {
     assert (padvise && *padvise);
     (*padvise)->is_symlocal = 1;
     return 0;
   }
   
   int
   lt_dladvise_global (lt_dladvise *padvise)
   {
     assert (padvise && *padvise);
     (*padvise)->is_symglobal = 1;
     return 0;
   }
   
   int
   lt_dladvise_preload (lt_dladvise *padvise)
   {
     assert (padvise && *padvise);
     (*padvise)->try_preload_only = 1;
     return 0;
   }
   
   /* Libtool-1.5.x interface for loading a new module named FILENAME.  */
   lt_dlhandle
   lt_dlopen (const char *filename)
   {
     return lt_dlopenadvise (filename, NULL);
   }
   
   
   /* If FILENAME has an ARCHIVE_EXT or MODULE_EXT extension, try to
    open the FILENAME as passed.  Otherwise try appending ARCHIVE_EXT,     open the FILENAME as passed.  Otherwise try appending ARCHIVE_EXT,
    and if a file is still not found try again with SHLIB_EXT appended     and if a file is still not found try again with MODULE_EXT appended
    instead.  */     instead.  */
 lt_dlhandle  lt_dlhandle
 lt_dlopenext (filename)  lt_dlopenext (const char *filename)
      const char *filename;  
 {  {
   lt_dlhandle   handle          = NULL;    lt_dlhandle   handle  = 0;
   char *        tmp             = NULL;    lt_dladvise   advise;
   char *        ext             = NULL;  
   size_t        len;  
   int           errors          = 0;  
   
   if (!filename)    if (!lt_dladvise_init (&advise) && !lt_dladvise_ext (&advise))
     {      handle = lt_dlopenadvise (filename, advise);
       return lt_dlopen (filename);  
     }  
   
   assert (filename);    lt_dladvise_destroy (&advise);
     return handle;
   }
   
   len = LT_STRLEN (filename);  
   ext = strrchr (filename, '.');  
   
   /* If FILENAME already bears a suitable extension, there is no need  lt_dlhandle
      to try appending additional extensions.  */  lt_dlopenadvise (const char *filename, lt_dladvise advise)
   if (ext && ((strcmp (ext, archive_ext) == 0)  {
 #ifdef LTDL_SHLIB_EXT    lt_dlhandle   handle  = 0;
               || (strcmp (ext, shlib_ext) == 0)    int           errors  = 0;
 #endif    const char *  saved_error     = 0;
       ))  
     {  
       return lt_dlopen (filename);  
     }  
   
   /* First try appending ARCHIVE_EXT.  */    LT__GETERROR (saved_error);
   tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1);  
   if (!tmp)  
     return 0;  
   
   strcpy (tmp, filename);    /* Can't have symbols hidden and visible at the same time!  */
   strcat (tmp, archive_ext);    if (advise && advise->is_symlocal && advise->is_symglobal)
   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);        LT__SETERROR (CONFLICTING_FLAGS);
       return handle;        return 0;
     }      }
   
 #ifdef LTDL_SHLIB_EXT    if (!filename
   /* Try appending SHLIB_EXT.   */        || !advise
   if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext))        || !advise->try_ext
     {        || has_library_ext (filename))
       LT_DLFREE (tmp);      {
       tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1);        /* Just incase we missed a code path in try_dlopen() that reports
       if (!tmp)           an error, but forgot to reset handle... */
         if (try_dlopen (&handle, filename, NULL, advise) != 0)
         return 0;          return 0;
   
       strcpy (tmp, filename);        return handle;
     }      }
   else    else if (filename && *filename)
     {      {
       tmp[len] = LT_EOS_CHAR;  
     }  
   
   strcat(tmp, shlib_ext);        /* First try appending ARCHIVE_EXT.  */
   errors = try_dlopen (&handle, tmp);        errors += try_dlopen (&handle, filename, archive_ext, advise);
   
   /* As before, if the file was found but loading failed, return now        /* If we found FILENAME, stop searching -- whether we were able to
      with the current error message.  */           load the file as a module or not.  If the file exists but loading
   if (handle || ((errors > 0) && file_not_found ()))           failed, it is better to return an error message here than to
     {           report FILE_NOT_FOUND when the alternatives (foo.so etc) are not
       LT_DLFREE (tmp);           in the module search path.  */
       return handle;        if (handle || ((errors > 0) && !file_not_found ()))
     }          return handle;
   
   #if defined(LT_MODULE_EXT)
         /* Try appending SHLIB_EXT.   */
         LT__SETERRORSTR (saved_error);
         errors = try_dlopen (&handle, filename, shlib_ext, advise);
   
         /* As before, if the file was found but loading failed, return now
            with the current error message.  */
         if (handle || ((errors > 0) && !file_not_found ()))
           return handle;
   #endif
   
   #if defined(LT_SHARED_EXT)
         /* Try appending SHARED_EXT.   */
         LT__SETERRORSTR (saved_error);
         errors = try_dlopen (&handle, filename, shared_ext, advise);
   
         /* As before, if the file was found but loading failed, return now
            with the current error message.  */
         if (handle || ((errors > 0) && !file_not_found ()))
           return handle;
 #endif  #endif
       }
   
   /* Still here?  Then we really did fail to locate any of the file    /* Still here?  Then we really did fail to locate any of the file
      names we tried.  */       names we tried.  */
   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));    LT__SETERROR (FILE_NOT_FOUND);
   LT_DLFREE (tmp);  
   return 0;    return 0;
 }  }
   
   
 static int  static int
 lt_argz_insert (pargz, pargz_len, before, entry)  lt_argz_insert (char **pargz, size_t *pargz_len, char *before,
      char **pargz;                  const char *entry)
      size_t *pargz_len;  
      char *before;  
      const char *entry;  
 {  {
   error_t error;    error_t error;
   
   if ((error = argz_insert (pargz, pargz_len, before, entry)))    /* Prior to Sep 8, 2005, newlib had a bug where argz_insert(pargz,
        pargz_len, NULL, entry) failed with EINVAL.  */
     if (before)
       error = argz_insert (pargz, pargz_len, before, entry);
     else
       error = argz_append (pargz, pargz_len, entry, 1 + strlen (entry));
   
     if (error)
     {      {
       switch (error)        switch (error)
         {          {
         case ENOMEM:          case ENOMEM:
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));            LT__SETERROR (NO_MEMORY);
           break;            break;
         default:          default:
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));            LT__SETERROR (UNKNOWN);
           break;            break;
         }          }
       return 1;        return 1;
Line 3056  lt_argz_insert (pargz, pargz_len, before Line 1741  lt_argz_insert (pargz, pargz_len, before
 }  }
   
 static int  static int
 lt_argz_insertinorder (pargz, pargz_len, entry)  lt_argz_insertinorder (char **pargz, size_t *pargz_len, const char *entry)
      char **pargz;  
      size_t *pargz_len;  
      const char *entry;  
 {  {
   char *before = NULL;    char *before = 0;
   
   assert (pargz);    assert (pargz);
   assert (pargz_len);    assert (pargz_len);
Line 3080  lt_argz_insertinorder (pargz, pargz_len, Line 1762  lt_argz_insertinorder (pargz, pargz_len,
 }  }
   
 static int  static int
 lt_argz_insertdir (pargz, pargz_len, dirnam, dp)  lt_argz_insertdir (char **pargz, size_t *pargz_len, const char *dirnam,
      char **pargz;                     struct dirent *dp)
      size_t *pargz_len;  
      const char *dirnam;  
      struct dirent *dp;  
 {  {
   char   *buf       = NULL;    char   *buf       = 0;
   size_t buf_len    = 0;    size_t buf_len    = 0;
   char   *end       = NULL;    char   *end       = 0;
   size_t end_offset = 0;    size_t end_offset = 0;
   size_t dir_len    = 0;    size_t dir_len    = 0;
   int    errors     = 0;    int    errors     = 0;
Line 3098  lt_argz_insertdir (pargz, pargz_len, dir Line 1777  lt_argz_insertdir (pargz, pargz_len, dir
   assert (dp);    assert (dp);
   
   dir_len = LT_STRLEN (dirnam);    dir_len = LT_STRLEN (dirnam);
   end     = dp->d_name + LT_D_NAMLEN(dp);    end     = dp->d_name + D_NAMLEN(dp);
   
   /* Ignore version numbers.  */    /* Ignore version numbers.  */
   {    {
Line 3125  lt_argz_insertdir (pargz, pargz_len, dir Line 1804  lt_argz_insertdir (pargz, pargz_len, dir
   /* Prepend the directory name.  */    /* Prepend the directory name.  */
   end_offset    = end - dp->d_name;    end_offset    = end - dp->d_name;
   buf_len       = dir_len + 1+ end_offset;    buf_len       = dir_len + 1+ end_offset;
   buf           = LT_EMALLOC (char, 1+ buf_len);    buf           = MALLOC (char, 1+ buf_len);
   if (!buf)    if (!buf)
     return ++errors;      return ++errors;
   
Line 3140  lt_argz_insertdir (pargz, pargz_len, dir Line 1819  lt_argz_insertdir (pargz, pargz_len, dir
   if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0)    if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0)
     ++errors;      ++errors;
   
   LT_DLFREE (buf);    FREE (buf);
   
   return errors;    return errors;
 }  }
   
 static int  static int
 list_files_by_dir (dirnam, pargz, pargz_len)  list_files_by_dir (const char *dirnam, char **pargz, size_t *pargz_len)
      const char *dirnam;  
      char **pargz;  
      size_t *pargz_len;  
 {  {
   DIR   *dirp     = NULL;    DIR   *dirp     = 0;
   int    errors   = 0;    int    errors   = 0;
   
   assert (dirnam && *dirnam);    assert (dirnam && *dirnam);
Line 3162  list_files_by_dir (dirnam, pargz, pargz_ Line 1838  list_files_by_dir (dirnam, pargz, pargz_
   dirp = opendir (dirnam);    dirp = opendir (dirnam);
   if (dirp)    if (dirp)
     {      {
       struct dirent *dp = NULL;        struct dirent *dp = 0;
   
       while ((dp = readdir (dirp)))        while ((dp = readdir (dirp)))
         if (dp->d_name[0] != '.')          if (dp->d_name[0] != '.')
Line 3184  list_files_by_dir (dirnam, pargz, pargz_ Line 1860  list_files_by_dir (dirnam, pargz, pargz_
 /* If there are any files in DIRNAME, call the function passed in  /* If there are any files in DIRNAME, call the function passed in
    DATA1 (with the name of each file and DATA2 as arguments).  */     DATA1 (with the name of each file and DATA2 as arguments).  */
 static int  static int
 foreachfile_callback (dirname, data1, data2)  foreachfile_callback (char *dirname, void *data1, void *data2)
      char *dirname;  
      lt_ptr data1;  
      lt_ptr data2;  
 {  {
   int (*func) LT_PARAMS((const char *filename, lt_ptr data))    file_worker_func *func = *(file_worker_func **) data1;
         = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1;  
   
   int     is_done  = 0;    int     is_done  = 0;
   char   *argz     = NULL;    char   *argz     = 0;
   size_t  argz_len = 0;    size_t  argz_len = 0;
   
   if (list_files_by_dir (dirname, &argz, &argz_len) != 0)    if (list_files_by_dir (dirname, &argz, &argz_len) != 0)
Line 3202  foreachfile_callback (dirname, data1, da Line 1874  foreachfile_callback (dirname, data1, da
     goto cleanup;      goto cleanup;
   
   {    {
     char *filename = NULL;      char *filename = 0;
     while ((filename = argz_next (argz, argz_len, filename)))      while ((filename = argz_next (argz, argz_len, filename)))
       if ((is_done = (*func) (filename, data2)))        if ((is_done = (*func) (filename, data2)))
         break;          break;
   }    }
   
  cleanup:   cleanup:
   LT_DLFREE (argz);    FREE (argz);
   
   return is_done;    return is_done;
 }  }
Line 3222  foreachfile_callback (dirname, data1, da Line 1894  foreachfile_callback (dirname, data1, da
    libfoo.so, libfoo.so.1, libfoo.so.1.0.0).  If SEARCH_PATH is NULL,     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.  */     then the same directories that lt_dlopen would search are examined.  */
 int  int
 lt_dlforeachfile (search_path, func, data)  lt_dlforeachfile (const char *search_path,
      const char *search_path;                    int (*func) (const char *filename, void *data),
      int (*func) LT_PARAMS ((const char *filename, lt_ptr data));                    void *data)
      lt_ptr data;  
 {  {
   int is_done = 0;    int is_done = 0;
     file_worker_func **fpptr = &func;
   
   if (search_path)    if (search_path)
     {      {
       /* If a specific path was passed, search only the directories        /* If a specific path was passed, search only the directories
          listed in it.  */           listed in it.  */
       is_done = foreach_dirinpath (search_path, 0,        is_done = foreach_dirinpath (search_path, 0,
                                    foreachfile_callback, func, data);                                     foreachfile_callback, fpptr, data);
     }      }
   else    else
     {      {
       /* Otherwise search the default paths.  */        /* Otherwise search the default paths.  */
       is_done = foreach_dirinpath (user_search_path, 0,        is_done = foreach_dirinpath (user_search_path, 0,
                                    foreachfile_callback, func, data);                                     foreachfile_callback, fpptr, data);
       if (!is_done)        if (!is_done)
         {          {
           is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0,            is_done = foreach_dirinpath (getenv(LTDL_SEARCHPATH_VAR), 0,
                                        foreachfile_callback, func, data);                                         foreachfile_callback, fpptr, data);
         }          }
   
 #ifdef LTDL_SHLIBPATH_VAR  #if defined(LT_MODULE_PATH_VAR)
       if (!is_done)        if (!is_done)
         {          {
           is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0,            is_done = foreach_dirinpath (getenv(LT_MODULE_PATH_VAR), 0,
                                        foreachfile_callback, func, data);                                         foreachfile_callback, fpptr, data);
         }          }
 #endif  #endif
 #ifdef LTDL_SYSSEARCHPATH  #if defined(LT_DLSEARCH_PATH)
       if (!is_done)        if (!is_done && *sys_dlsearch_path)
         {          {
           is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0,            is_done = foreach_dirinpath (sys_dlsearch_path, 0,
                                        foreachfile_callback, func, data);                                         foreachfile_callback, fpptr, data);
         }          }
 #endif  #endif
     }      }
Line 3267  lt_dlforeachfile (search_path, func, dat Line 1939  lt_dlforeachfile (search_path, func, dat
 }  }
   
 int  int
 lt_dlclose (handle)  lt_dlclose (lt_dlhandle handle)
      lt_dlhandle handle;  
 {  {
   lt_dlhandle cur, last;    lt_dlhandle cur, last;
   int errors = 0;    int errors = 0;
   
   LT_DLMUTEX_LOCK ();  
   
   /* check whether the handle is valid */    /* check whether the handle is valid */
   last = cur = handles;    last = cur = handles;
   while (cur && handle != cur)    while (cur && handle != cur)
Line 3285  lt_dlclose (handle) Line 1954  lt_dlclose (handle)
   
   if (!cur)    if (!cur)
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));        LT__SETERROR (INVALID_HANDLE);
       ++errors;        ++errors;
       goto done;        goto done;
     }      }
   
   handle->info.ref_count--;    cur = handle;
     cur->info.ref_count--;
   
   /* Note that even with resident modules, we must track the ref_count    /* Note that even with resident modules, we must track the ref_count
      correctly incase the user decides to reset the residency flag       correctly incase the user decides to reset the residency flag
      later (even though the API makes no provision for that at the       later (even though the API makes no provision for that at the
      moment).  */       moment).  */
   if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle))    if (cur->info.ref_count <= 0 && !LT_DLIS_RESIDENT (cur))
     {      {
       lt_user_data data = handle->loader->dlloader_data;        lt_user_data data = cur->vtable->dlloader_data;
   
       if (handle != handles)        if (cur != handles)
         {          {
           last->next = handle->next;            last->next = cur->next;
         }          }
       else        else
         {          {
           handles = handle->next;            handles = cur->next;
         }          }
   
       errors += handle->loader->module_close (data, handle->module);        errors += cur->vtable->module_close (data, cur->module);
       errors += unload_deplibs(handle);        errors += unload_deplibs (handle);
   
       /* It is up to the callers to free the data itself.  */        /* It is up to the callers to free the data itself.  */
       LT_DLFREE (handle->caller_data);        FREE (cur->interface_data);
   
       LT_DLFREE (handle->info.filename);        FREE (cur->info.filename);
       LT_DLFREE (handle->info.name);        FREE (cur->info.name);
       LT_DLFREE (handle);        FREE (cur);
   
       goto done;        goto done;
     }      }
   
   if (LT_DLIS_RESIDENT (handle))    if (LT_DLIS_RESIDENT (handle))
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE));        LT__SETERROR (CLOSE_RESIDENT_MODULE);
       ++errors;        ++errors;
     }      }
   
  done:   done:
   LT_DLMUTEX_UNLOCK ();  
   
   return errors;    return errors;
 }  }
   
 lt_ptr  void *
 lt_dlsym (handle, symbol)  lt_dlsym (lt_dlhandle place, const char *symbol)
      lt_dlhandle handle;  
      const char *symbol;  
 {  {
   size_t lensym;    size_t lensym;
   char  lsym[LT_SYMBOL_LENGTH];    char  lsym[LT_SYMBOL_LENGTH];
   char  *sym;    char  *sym;
   lt_ptr address;    void *address;
   lt_user_data data;    lt_user_data data;
     lt_dlhandle handle;
   
   if (!handle)    if (!place)
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));        LT__SETERROR (INVALID_HANDLE);
       return 0;        return 0;
     }      }
   
     handle = place;
   
   if (!symbol)    if (!symbol)
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));        LT__SETERROR (SYMBOL_NOT_FOUND);
       return 0;        return 0;
     }      }
   
   lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix)    lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->vtable->sym_prefix)
                                         + LT_STRLEN (handle->info.name);                                          + LT_STRLEN (handle->info.name);
   
   if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH)    if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH)
Line 3366  lt_dlsym (handle, symbol) Line 2035  lt_dlsym (handle, symbol)
     }      }
   else    else
     {      {
       sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1);        sym = MALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1);
       if (!sym)        if (!sym)
         {          {
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW));            LT__SETERROR (BUFFER_OVERFLOW);
           return 0;            return 0;
         }          }
     }      }
   
   data = handle->loader->dlloader_data;    data = handle->vtable->dlloader_data;
   if (handle->info.name)    if (handle->info.name)
     {      {
       const char *saved_error;        const char *saved_error;
   
       LT_DLMUTEX_GETERROR (saved_error);        LT__GETERROR (saved_error);
   
       /* this is a libtool module */        /* this is a libtool module */
       if (handle->loader->sym_prefix)        if (handle->vtable->sym_prefix)
         {          {
           strcpy(sym, handle->loader->sym_prefix);            strcpy(sym, handle->vtable->sym_prefix);
           strcat(sym, handle->info.name);            strcat(sym, handle->info.name);
         }          }
       else        else
Line 3396  lt_dlsym (handle, symbol) Line 2065  lt_dlsym (handle, symbol)
       strcat(sym, symbol);        strcat(sym, symbol);
   
       /* try "modulename_LTX_symbol" */        /* try "modulename_LTX_symbol" */
       address = handle->loader->find_sym (data, handle->module, sym);        address = handle->vtable->find_sym (data, handle->module, sym);
       if (address)        if (address)
         {          {
           if (sym != lsym)            if (sym != lsym)
             {              {
               LT_DLFREE (sym);                FREE (sym);
             }              }
           return address;            return address;
         }          }
       LT_DLMUTEX_SETERROR (saved_error);        LT__SETERRORSTR (saved_error);
     }      }
   
   /* otherwise try "symbol" */    /* otherwise try "symbol" */
   if (handle->loader->sym_prefix)    if (handle->vtable->sym_prefix)
     {      {
       strcpy(sym, handle->loader->sym_prefix);        strcpy(sym, handle->vtable->sym_prefix);
       strcat(sym, symbol);        strcat(sym, symbol);
     }      }
   else    else
Line 3419  lt_dlsym (handle, symbol) Line 2088  lt_dlsym (handle, symbol)
       strcpy(sym, symbol);        strcpy(sym, symbol);
     }      }
   
   address = handle->loader->find_sym (data, handle->module, sym);    address = handle->vtable->find_sym (data, handle->module, sym);
   if (sym != lsym)    if (sym != lsym)
     {      {
       LT_DLFREE (sym);        FREE (sym);
     }      }
   
   return address;    return address;
 }  }
   
 const char *  const char *
 lt_dlerror ()  lt_dlerror (void)
 {  {
   const char *error;    const char *error;
   
   LT_DLMUTEX_GETERROR (error);    LT__GETERROR (error);
   LT_DLMUTEX_SETERROR (0);    LT__SETERRORSTR (0);
   
   return error ? error : LT_DLSTRERROR (UNKNOWN);    return error;
 }  }
   
 static int  static int
 lt_dlpath_insertdir (ppath, before, dir)  lt_dlpath_insertdir (char **ppath, char *before, const char *dir)
      char **ppath;  
      char *before;  
      const char *dir;  
 {  {
   int    errors         = 0;    int    errors         = 0;
   char  *canonical      = NULL;    char  *canonical      = 0;
   char  *argz           = NULL;    char  *argz           = 0;
   size_t argz_len       = 0;    size_t argz_len       = 0;
   
   assert (ppath);    assert (ppath);
Line 3462  lt_dlpath_insertdir (ppath, before, dir) Line 2128  lt_dlpath_insertdir (ppath, before, dir)
   assert (canonical && *canonical);    assert (canonical && *canonical);
   
   /* If *PPATH is empty, set it to DIR.  */    /* If *PPATH is empty, set it to DIR.  */
   if (*ppath == NULL)    if (*ppath == 0)
     {      {
       assert (!before);         /* BEFORE cannot be set without PPATH.  */        assert (!before);         /* BEFORE cannot be set without PPATH.  */
       assert (dir);             /* Without DIR, don't call this function!  */        assert (dir);             /* Without DIR, don't call this function!  */
   
       *ppath = lt_estrdup (dir);        *ppath = lt__strdup (dir);
       if (*ppath == NULL)        if (*ppath == 0)
         ++errors;          ++errors;
   
       return errors;        goto cleanup;
     }      }
   
   assert (ppath && *ppath);    assert (ppath && *ppath);
Line 3490  lt_dlpath_insertdir (ppath, before, dir) Line 2156  lt_dlpath_insertdir (ppath, before, dir)
   if (before)    if (before)
     {      {
       assert (*ppath <= before);        assert (*ppath <= before);
       assert (before - *ppath <= strlen (*ppath));        assert ((int) (before - *ppath) <= (int) strlen (*ppath));
   
       before = before - *ppath + argz;        before = before - *ppath + argz;
     }      }
Line 3502  lt_dlpath_insertdir (ppath, before, dir) Line 2168  lt_dlpath_insertdir (ppath, before, dir)
     }      }
   
   argz_stringify (argz, argz_len, LT_PATHSEP_CHAR);    argz_stringify (argz, argz_len, LT_PATHSEP_CHAR);
   LT_DLMEM_REASSIGN (*ppath,  argz);    MEMREASSIGN(*ppath, argz);
   
  cleanup:   cleanup:
   LT_DLFREE (canonical);    FREE (argz);
   LT_DLFREE (argz);    FREE (canonical);
   
   return errors;    return errors;
 }  }
   
 int  int
 lt_dladdsearchdir (search_dir)  lt_dladdsearchdir (const char *search_dir)
      const char *search_dir;  
 {  {
   int errors = 0;    int errors = 0;
   
   if (search_dir && *search_dir)    if (search_dir && *search_dir)
     {      {
       LT_DLMUTEX_LOCK ();  
       if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)        if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)
         ++errors;          ++errors;
       LT_DLMUTEX_UNLOCK ();  
     }      }
   
   return errors;    return errors;
 }  }
   
 int  int
 lt_dlinsertsearchdir (before, search_dir)  lt_dlinsertsearchdir (const char *before, const char *search_dir)
      const char *before;  
      const char *search_dir;  
 {  {
   int errors = 0;    int errors = 0;
   
   if (before)    if (before)
     {      {
       LT_DLMUTEX_LOCK ();  
       if ((before < user_search_path)        if ((before < user_search_path)
           || (before >= user_search_path + LT_STRLEN (user_search_path)))            || (before >= user_search_path + LT_STRLEN (user_search_path)))
         {          {
           LT_DLMUTEX_UNLOCK ();            LT__SETERROR (INVALID_POSITION);
           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION));  
           return 1;            return 1;
         }          }
       LT_DLMUTEX_UNLOCK ();  
     }      }
   
   if (search_dir && *search_dir)    if (search_dir && *search_dir)
     {      {
       LT_DLMUTEX_LOCK ();  
       if (lt_dlpath_insertdir (&user_search_path,        if (lt_dlpath_insertdir (&user_search_path,
                                (char *) before, search_dir) != 0)                                 (char *) before, search_dir) != 0)
         {          {
           ++errors;            ++errors;
         }          }
       LT_DLMUTEX_UNLOCK ();  
     }      }
   
   return errors;    return errors;
 }  }
   
 int  int
 lt_dlsetsearchpath (search_path)  lt_dlsetsearchpath (const char *search_path)
      const char *search_path;  
 {  {
   int   errors      = 0;    int   errors      = 0;
   
   LT_DLMUTEX_LOCK ();    FREE (user_search_path);
   LT_DLFREE (user_search_path);  
   LT_DLMUTEX_UNLOCK ();  
   
   if (!search_path || !LT_STRLEN (search_path))    if (!search_path || !LT_STRLEN (search_path))
     {      {
       return errors;        return errors;
     }      }
   
   LT_DLMUTEX_LOCK ();  
   if (canonicalize_path (search_path, &user_search_path) != 0)    if (canonicalize_path (search_path, &user_search_path) != 0)
     ++errors;      ++errors;
   LT_DLMUTEX_UNLOCK ();  
   
   return errors;    return errors;
 }  }
   
 const char *  const char *
 lt_dlgetsearchpath ()  lt_dlgetsearchpath (void)
 {  {
   const char *saved_path;    const char *saved_path;
   
   LT_DLMUTEX_LOCK ();  
   saved_path = user_search_path;    saved_path = user_search_path;
   LT_DLMUTEX_UNLOCK ();  
   
   return saved_path;    return saved_path;
 }  }
   
 int  int
 lt_dlmakeresident (handle)  lt_dlmakeresident (lt_dlhandle handle)
      lt_dlhandle handle;  
 {  {
   int errors = 0;    int errors = 0;
   
   if (!handle)    if (!handle)
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));        LT__SETERROR (INVALID_HANDLE);
       ++errors;        ++errors;
     }      }
   else    else
     {      {
       LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG);        handle->info.is_resident = 1;
     }      }
   
   return errors;    return errors;
 }  }
   
 int  int
 lt_dlisresident (handle)  lt_dlisresident (lt_dlhandle handle)
      lt_dlhandle handle;  
 {  {
   if (!handle)    if (!handle)
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));        LT__SETERROR (INVALID_HANDLE);
       return -1;        return -1;
     }      }
   
Line 3631  lt_dlisresident (handle) Line 2278  lt_dlisresident (handle)
   
   
   
   
 /* --- MODULE INFORMATION --- */  /* --- MODULE INFORMATION --- */
   
 const lt_dlinfo *  typedef struct {
 lt_dlgetinfo (handle)    const char *id_string;
      lt_dlhandle handle;    lt_dlhandle_interface *iface;
 {  } lt__interface_id;
   if (!handle)  
     {  lt_dlinterface_id
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));  lt_dlinterface_register (const char *id_string, lt_dlhandle_interface *iface)
       return 0;  {
     }    lt__interface_id *interface_id = (lt__interface_id *) lt__malloc (sizeof *interface_id);
   
   return &(handle->info);    /* If lt__malloc fails, it will LT__SETERROR (NO_MEMORY), which
 }       can then be detected with lt_dlerror() if we return 0.  */
     if (interface_id)
 lt_dlhandle      {
 lt_dlhandle_next (place)        interface_id->id_string = lt__strdup (id_string);
      lt_dlhandle place;        if (!interface_id->id_string)
 {          FREE (interface_id);
   return place ? place->next : handles;        else
 }          interface_id->iface = iface;
   
 int  
 lt_dlforeach (func, data)  
      int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data));  
      lt_ptr data;  
 {  
   int errors = 0;  
   lt_dlhandle cur;  
   
   LT_DLMUTEX_LOCK ();  
   
   cur = handles;  
   while (cur)  
     {  
       lt_dlhandle tmp = cur;  
   
       cur = cur->next;  
       if ((*func) (tmp, data))  
         {  
           ++errors;  
           break;  
         }  
     }      }
   
   LT_DLMUTEX_UNLOCK ();    return (lt_dlinterface_id) interface_id;
   
   return errors;  
 }  }
   
 lt_dlcaller_id  void lt_dlinterface_free (lt_dlinterface_id key)
 lt_dlcaller_register ()  
 {  {
   static lt_dlcaller_id last_caller_id = 0;    lt__interface_id *interface_id = (lt__interface_id *)key;
   int result;    FREE (interface_id->id_string);
     FREE (interface_id);
   LT_DLMUTEX_LOCK ();  
   result = ++last_caller_id;  
   LT_DLMUTEX_UNLOCK ();  
   
   return result;  
 }  }
   
 lt_ptr  void *
 lt_dlcaller_set_data (key, handle, data)  lt_dlcaller_set_data (lt_dlinterface_id key, lt_dlhandle handle, void *data)
      lt_dlcaller_id key;  
      lt_dlhandle handle;  
      lt_ptr data;  
 {  {
   int n_elements = 0;    int n_elements = 0;
   lt_ptr stale = NULL;    void *stale = (void *) 0;
     lt_dlhandle cur = handle;
   int i;    int i;
   
   /* This needs to be locked so that the caller data can be updated    if (cur->interface_data)
      simultaneously by different threads.  */      while (cur->interface_data[n_elements].key)
   LT_DLMUTEX_LOCK ();  
   
   if (handle->caller_data)  
     while (handle->caller_data[n_elements].key)  
       ++n_elements;        ++n_elements;
   
   for (i = 0; i < n_elements; ++i)    for (i = 0; i < n_elements; ++i)
     {      {
       if (handle->caller_data[i].key == key)        if (cur->interface_data[i].key == key)
         {          {
           stale = handle->caller_data[i].data;            stale = cur->interface_data[i].data;
           break;            break;
         }          }
     }      }
   
   /* Ensure that there is enough room in this handle's caller_data    /* Ensure that there is enough room in this handle's interface_data
      array to accept a new element (and an empty end marker).  */       array to accept a new element (and an empty end marker).  */
   if (i == n_elements)    if (i == n_elements)
     {      {
       lt_caller_data *temp        lt_interface_data *temp
         = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements);          = REALLOC (lt_interface_data, cur->interface_data, 2+ n_elements);
   
       if (!temp)        if (!temp)
         {          {
           stale = NULL;            stale = 0;
           goto done;            goto done;
         }          }
   
       handle->caller_data = temp;        cur->interface_data = temp;
   
       /* We only need this if we needed to allocate a new caller_data.  */        /* We only need this if we needed to allocate a new interface_data.  */
       handle->caller_data[i].key  = key;        cur->interface_data[i].key        = key;
       handle->caller_data[1+ i].key = 0;        cur->interface_data[1+ i].key     = 0;
     }      }
   
   handle->caller_data[i].data = data;    cur->interface_data[i].data = data;
   
  done:   done:
   LT_DLMUTEX_UNLOCK ();  
   
   return stale;    return stale;
 }  }
   
 lt_ptr  void *
 lt_dlcaller_get_data  (key, handle)  lt_dlcaller_get_data (lt_dlinterface_id key, lt_dlhandle handle)
      lt_dlcaller_id key;  
      lt_dlhandle handle;  
 {  
   lt_ptr result = (lt_ptr) 0;  
   
   /* This needs to be locked so that the caller data isn't updated by  
      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  
 lt_dlloader_add (place, dlloader, loader_name)  
      lt_dlloader *place;  
      const struct lt_user_dlloader *dlloader;  
      const char *loader_name;  
 {  
   int errors = 0;  
   lt_dlloader *node = NULL, *ptr = NULL;  
   
   if ((dlloader == NULL)        /* diagnose null parameters */  
       || (dlloader->module_open == NULL)  
       || (dlloader->module_close == NULL)  
       || (dlloader->find_sym == NULL))  
     {  
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));  
       return 1;  
     }  
   
   /* Create a new dlloader node with copies of the user callbacks.  */  
   node = LT_EMALLOC (lt_dlloader, 1);  
   if (!node)  
     return 1;  
   
   node->next            = NULL;  
   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;  
         }  
     }  
   
   LT_DLMUTEX_UNLOCK ();  
   
   return errors;  
 }  
   
 int  
 lt_dlloader_remove (loader_name)  
      const char *loader_name;  
 {  {
   lt_dlloader *place = lt_dlloader_find (loader_name);    void *result = (void *) 0;
   lt_dlhandle handle;    lt_dlhandle cur = handle;
   int errors = 0;  
   
   if (!place)    /* Locate the index of the element with a matching KEY.  */
     {    if (cur->interface_data)
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));  
       return 1;  
     }  
   
   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. */        int i;
       lt_dlloader *prev;        for (i = 0; cur->interface_data[i].key; ++i)
       for (prev = loaders; prev->next; prev = prev->next)  
         {          {
           if (!strcmp (prev->next->loader_name, loader_name))            if (cur->interface_data[i].key == key)
             {              {
                 result = cur->interface_data[i].data;
               break;                break;
             }              }
         }          }
   
       place = prev->next;  
       prev->next = prev->next->next;  
     }  
   
   if (place->dlloader_exit)  
     {  
       errors = place->dlloader_exit (place->dlloader_data);  
     }      }
   
   LT_DLFREE (place);    return result;
   
  done:  
   LT_DLMUTEX_UNLOCK ();  
   
   return errors;  
 }  }
   
 lt_dlloader *  const lt_dlinfo *
 lt_dlloader_next (place)  lt_dlgetinfo (lt_dlhandle handle)
      lt_dlloader *place;  
 {  {
   lt_dlloader *next;    if (!handle)
       {
   LT_DLMUTEX_LOCK ();        LT__SETERROR (INVALID_HANDLE);
   next = place ? place->next : loaders;        return 0;
   LT_DLMUTEX_UNLOCK ();      }
   
   return next;    return &(handle->info);
 }  }
   
 const char *  
 lt_dlloader_name (place)  lt_dlhandle
      lt_dlloader *place;  lt_dlhandle_iterate (lt_dlinterface_id iface, lt_dlhandle place)
 {  {
   const char *name = NULL;    lt_dlhandle handle = place;
     lt__interface_id *iterator = (lt__interface_id *) iface;
   
   if (place)    assert (iface); /* iface is a required argument */
     {  
       LT_DLMUTEX_LOCK ();    if (!handle)
       name = place ? place->loader_name : 0;      handle = handles;
       LT_DLMUTEX_UNLOCK ();  
     }  
   else    else
       handle = handle->next;
   
     /* advance while the interface check fails */
     while (handle && iterator->iface
            && ((*iterator->iface) (handle, iterator->id_string) != 0))
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));        handle = handle->next;
     }      }
   
   return name;    return handle;
 }  }
   
 lt_user_data *  
 lt_dlloader_data (place)  lt_dlhandle
      lt_dlloader *place;  lt_dlhandle_fetch (lt_dlinterface_id iface, const char *module_name)
 {  {
   lt_user_data *data = NULL;    lt_dlhandle handle = 0;
   
   if (place)    assert (iface); /* iface is a required argument */
     {  
       LT_DLMUTEX_LOCK ();    while ((handle = lt_dlhandle_iterate (iface, handle)))
       data = place ? &(place->dlloader_data) : 0;  
       LT_DLMUTEX_UNLOCK ();  
     }  
   else  
     {      {
       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));        lt_dlhandle cur = handle;
         if (cur && cur->info.name && streq (cur->info.name, module_name))
           break;
     }      }
   
   return data;    return handle;
 }  }
   
 lt_dlloader *  
 lt_dlloader_find (loader_name)  int
      const char *loader_name;  lt_dlhandle_map (lt_dlinterface_id iface,
                    int (*func) (lt_dlhandle handle, void *data), void *data)
 {  {
   lt_dlloader *place = NULL;    lt__interface_id *iterator = (lt__interface_id *) iface;
     lt_dlhandle cur = handles;
   
   LT_DLMUTEX_LOCK ();    assert (iface); /* iface is a required argument */
   for (place = loaders; place; place = place->next)  
     while (cur)
     {      {
       if (strcmp (place->loader_name, loader_name) == 0)        int errorcode = 0;
   
         /* advance while the interface check fails */
         while (cur && iterator->iface
                && ((*iterator->iface) (cur, iterator->id_string) != 0))
         {          {
           break;            cur = cur->next;
         }          }
   
         if ((errorcode = (*func) (cur, data)) != 0)
           return errorcode;
     }      }
   LT_DLMUTEX_UNLOCK ();  
   
   return place;    return 0;
 }  }

Removed from v.1.3  
changed lines
  Added in v.1.4


E-mail: