GridLab
Grid Application Toolkit

A simple API for Grid Applications
GAT

Menu



Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

ltdl.c

Go to the documentation of this file.
00001 /* ltdl.c -- system independent dlopen wrapper
00002    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
00003    Originally by Thomas Tanner <tanner@ffii.org>
00004    This file is part of GNU Libtool.
00005 
00006 This library is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU Lesser General Public
00008 License as published by the Free Software Foundation; either
00009 version 2 of the License, or (at your option) any later version.
00010 
00011 As a special exception to the GNU Lesser General Public License,
00012 if you distribute this file as part of a program or library that
00013 is built using GNU libtool, you may include it under the same
00014 distribution terms that you use for the rest of that program.
00015 
00016 This library is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 Lesser General Public License for more details.
00020 
00021 You should have received a copy of the GNU Lesser General Public
00022 License along with this library; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00024 02111-1307  USA
00025 
00026 */
00027 
00028 #if HAVE_CONFIG_H
00029 #  include <config.h>
00030 #endif
00031 
00032 #if HAVE_UNISTD_H
00033 #  include <unistd.h>
00034 #endif
00035 
00036 #if HAVE_STDIO_H
00037 #  include <stdio.h>
00038 #endif
00039 
00040 #if HAVE_STDLIB_H
00041 #  include <stdlib.h>
00042 #endif
00043 
00044 #if HAVE_STRING_H
00045 #  include <string.h>
00046 #else
00047 #  if HAVE_STRINGS_H
00048 #    include <strings.h>
00049 #  endif
00050 #endif
00051 
00052 #if HAVE_CTYPE_H
00053 #  include <ctype.h>
00054 #endif
00055 
00056 #if HAVE_MALLOC_H
00057 #  include <malloc.h>
00058 #endif
00059 
00060 #if HAVE_MEMORY_H
00061 #  include <memory.h>
00062 #endif
00063 
00064 #if HAVE_ERRNO_H
00065 #  include <errno.h>
00066 #endif
00067 
00068 #if HAVE_DIRENT_H
00069 #  include <dirent.h>
00070 #  define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name))
00071 #else
00072 #  define dirent direct
00073 #  define LT_D_NAMLEN(dirent) ((dirent)->d_namlen)
00074 #  if HAVE_SYS_NDIR_H
00075 #    include <sys/ndir.h>
00076 #  endif
00077 #  if HAVE_SYS_DIR_H
00078 #    include <sys/dir.h>
00079 #  endif
00080 #  if HAVE_NDIR_H
00081 #    include <ndir.h>
00082 #  endif
00083 #endif
00084 
00085 #if HAVE_ARGZ_H
00086 #  include <argz.h>
00087 #endif
00088 
00089 #if HAVE_ASSERT_H
00090 #  include <assert.h>
00091 #else
00092 #  define assert(arg) ((void) 0)
00093 #endif
00094 
00095 #include "ltdl.h"
00096 
00097 
00098 
00099 
00100 /* --- WINDOWS SUPPORT --- */
00101 
00102 
00103 #ifdef DLL_EXPORT
00104 #  define LT_GLOBAL_DATA  __declspec(dllexport)
00105 #else
00106 #  define LT_GLOBAL_DATA
00107 #endif
00108 
00109 /* fopen() mode flags for reading a text file */
00110 #undef  LT_READTEXT_MODE
00111 #ifdef __WINDOWS__
00112 #  define LT_READTEXT_MODE "rt"
00113 #else
00114 #  define LT_READTEXT_MODE "r"
00115 #endif
00116 
00117 
00118 
00119 
00120 /* --- MANIFEST CONSTANTS --- */
00121 
00122 
00123 /* Standard libltdl search path environment variable name  */
00124 #undef  LTDL_SEARCHPATH_VAR
00125 #define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH"
00126 
00127 /* Standard libtool archive file extension.  */
00128 #undef  LTDL_ARCHIVE_EXT
00129 #define LTDL_ARCHIVE_EXT  ".la"
00130 
00131 /* max. filename length */
00132 #ifndef LT_FILENAME_MAX
00133 #  define LT_FILENAME_MAX 1024
00134 #endif
00135 
00136 /* This is the maximum symbol size that won't require malloc/free */
00137 #undef  LT_SYMBOL_LENGTH
00138 #define LT_SYMBOL_LENGTH  128
00139 
00140 /* This accounts for the _LTX_ separator */
00141 #undef  LT_SYMBOL_OVERHEAD
00142 #define LT_SYMBOL_OVERHEAD  5
00143 
00144 
00145 
00146 
00147 /* --- MEMORY HANDLING --- */
00148 
00149 
00150 /* These are the functions used internally.  In addition to making
00151    use of the associated function pointers above, they also perform
00152    error handling.  */
00153 static char   *lt_estrdup LT_PARAMS((const char *str));
00154 static lt_ptr lt_emalloc  LT_PARAMS((size_t size));
00155 static lt_ptr lt_erealloc LT_PARAMS((lt_ptr addr, size_t size));
00156 
00157 static lt_ptr rpl_realloc LT_PARAMS((lt_ptr ptr, size_t size));
00158 
00159 /* These are the pointers that can be changed by the caller:  */
00160 LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc)  LT_PARAMS((size_t size))
00161       = (lt_ptr (*) LT_PARAMS((size_t))) malloc;
00162 LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size))
00163       = (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc;
00164 LT_GLOBAL_DATA void   (*lt_dlfree)  LT_PARAMS((lt_ptr ptr))
00165       = (void (*) LT_PARAMS((lt_ptr))) free;
00166 
00167 /* The following macros reduce the amount of typing needed to cast
00168    assigned memory.  */
00169 #define LT_DLMALLOC(tp, n)  ((tp *) lt_dlmalloc ((n) * sizeof(tp)))
00170 #define LT_DLREALLOC(tp, p, n)  ((tp *) rpl_realloc ((p), (n) * sizeof(tp)))
00171 #define LT_DLFREE(p)            \
00172   LT_STMT_START { if (p) (p) = (lt_dlfree (p), (lt_ptr) 0); } LT_STMT_END
00173 
00174 #define LT_EMALLOC(tp, n) ((tp *) lt_emalloc ((n) * sizeof(tp)))
00175 #define LT_EREALLOC(tp, p, n) ((tp *) lt_erealloc ((p), (n) * sizeof(tp)))
00176 
00177 #define LT_DLMEM_REASSIGN(p, q)     LT_STMT_START { \
00178   if ((p) != (q)) { lt_dlfree (p); (p) = (q); (q) = 0; }  \
00179             } LT_STMT_END
00180 
00181 
00182 /* --- REPLACEMENT FUNCTIONS --- */
00183 
00184 
00185 #undef strdup
00186 #define strdup rpl_strdup
00187 
00188 static char *strdup LT_PARAMS((const char *str));
00189 
00190 char *
00191 strdup(str)
00192      const char *str;
00193 {
00194   char *tmp = 0;
00195 
00196   if (str)
00197     {
00198       tmp = LT_DLMALLOC (char, 1+ strlen (str));
00199       if (tmp)
00200   {
00201     strcpy(tmp, str);
00202   }
00203     }
00204 
00205   return tmp;
00206 }
00207 
00208 
00209 #if ! HAVE_STRCMP
00210 
00211 #undef strcmp
00212 #define strcmp rpl_strcmp
00213 
00214 static int strcmp LT_PARAMS((const char *str1, const char *str2));
00215 
00216 int
00217 strcmp (str1, str2)
00218      const char *str1;
00219      const char *str2;
00220 {
00221   if (str1 == str2)
00222     return 0;
00223   if (str1 == 0)
00224     return -1;
00225   if (str2 == 0)
00226     return 1;
00227 
00228   for (;*str1 && *str2; ++str1, ++str2)
00229     {
00230       if (*str1 != *str2)
00231   break;
00232     }
00233 
00234   return (int)(*str1 - *str2);
00235 }
00236 #endif
00237 
00238 
00239 #if ! HAVE_STRCHR
00240 
00241 #  if HAVE_INDEX
00242 #    define strchr index
00243 #  else
00244 #    define strchr rpl_strchr
00245 
00246 static const char *strchr LT_PARAMS((const char *str, int ch));
00247 
00248 const char*
00249 strchr(str, ch)
00250      const char *str;
00251      int ch;
00252 {
00253   const char *p;
00254 
00255   for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p)
00256     /*NOWORK*/;
00257 
00258   return (*p == (char)ch) ? p : 0;
00259 }
00260 
00261 #  endif
00262 #endif /* !HAVE_STRCHR */
00263 
00264 
00265 #if ! HAVE_STRRCHR
00266 
00267 #  if HAVE_RINDEX
00268 #    define strrchr rindex
00269 #  else
00270 #    define strrchr rpl_strrchr
00271 
00272 static const char *strrchr LT_PARAMS((const char *str, int ch));
00273 
00274 const char*
00275 strrchr(str, ch)
00276      const char *str;
00277      int ch;
00278 {
00279   const char *p, *q = 0;
00280 
00281   for (p = str; *p != LT_EOS_CHAR; ++p)
00282     {
00283       if (*p == (char) ch)
00284   {
00285     q = p;
00286   }
00287     }
00288 
00289   return q;
00290 }
00291 
00292 # endif
00293 #endif
00294 
00295 /* NOTE:  Neither bcopy nor the memcpy implementation below can
00296           reliably handle copying in overlapping areas of memory.  Use
00297           memmove (for which there is a fallback implmentation below)
00298     if you need that behaviour.  */
00299 #if ! HAVE_MEMCPY
00300 
00301 #  if HAVE_BCOPY
00302 #    define memcpy(dest, src, size) bcopy (src, dest, size)
00303 #  else
00304 #    define memcpy rpl_memcpy
00305 
00306 static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
00307 
00308 lt_ptr
00309 memcpy (dest, src, size)
00310      lt_ptr dest;
00311      const lt_ptr src;
00312      size_t size;
00313 {
00314   size_t i = 0;
00315 
00316   for (i = 0; i < size; ++i)
00317     {
00318       dest[i] = src[i];
00319     }
00320 
00321   return dest;
00322 }
00323 
00324 #  endif /* !HAVE_BCOPY */
00325 #endif   /* !HAVE_MEMCPY */
00326 
00327 #if ! HAVE_MEMMOVE
00328 #  define memmove rpl_memmove
00329 
00330 static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
00331 
00332 lt_ptr
00333 memmove (dest, src, size)
00334      lt_ptr dest;
00335      const lt_ptr src;
00336      size_t size;
00337 {
00338   size_t i;
00339 
00340   if (dest < src)
00341     for (i = 0; i < size; ++i)
00342       {
00343   dest[i] = src[i];
00344       }
00345   else if (dest > src)
00346     for (i = size -1; i >= 0; --i)
00347       {
00348   dest[i] = src[i];
00349       }
00350 
00351   return dest;
00352 }
00353 
00354 #endif /* !HAVE_MEMMOVE */
00355 
00356 
00357 /* According to Alexandre Oliva <oliva@lsd.ic.unicamp.br>,
00358     ``realloc is not entirely portable''
00359    In any case we want to use the allocator supplied by the user without
00360    burdening them with an lt_dlrealloc function pointer to maintain.
00361    Instead implement our own version (with known boundary conditions)
00362    using lt_dlmalloc and lt_dlfree. */
00363 
00364 #undef realloc
00365 #define realloc rpl_realloc
00366 
00367 lt_ptr
00368 realloc (ptr, size)
00369      lt_ptr ptr;
00370      size_t size;
00371 {
00372   if (size <= 0)
00373     {
00374       /* For zero or less bytes, free the original memory */
00375       if (ptr != 0)
00376   {
00377     lt_dlfree (ptr);
00378   }
00379 
00380       return (lt_ptr) 0;
00381     }
00382   else if (ptr == 0)
00383     {
00384       /* Allow reallocation of a NULL pointer.  */
00385       return lt_dlmalloc (size);
00386     }
00387   else
00388     {
00389       /* Allocate a new block, copy and free the old block.  */
00390       lt_ptr mem = lt_dlmalloc (size);
00391 
00392       if (mem)
00393   {
00394     memcpy (mem, ptr, size);
00395     lt_dlfree (ptr);
00396   }
00397 
00398       /* Note that the contents of PTR are not damaged if there is
00399    insufficient memory to realloc.  */
00400       return mem;
00401     }
00402 }
00403 
00404 
00405 #if ! HAVE_ARGZ_APPEND
00406 #  define argz_append rpl_argz_append
00407 
00408 static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len,
00409           const char *buf, size_t buf_len));
00410 
00411 error_t
00412 argz_append (pargz, pargz_len, buf, buf_len)
00413      char **pargz;
00414      size_t *pargz_len;
00415      const char *buf;
00416      size_t buf_len;
00417 {
00418   size_t argz_len;
00419   char  *argz;
00420 
00421   assert (pargz);
00422   assert (pargz_len);
00423   assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len));
00424 
00425   /* If nothing needs to be appended, no more work is required.  */
00426   if (buf_len == 0)
00427     return 0;
00428 
00429   /* Ensure there is enough room to append BUF_LEN.  */
00430   argz_len = *pargz_len + buf_len;
00431   argz = LT_DLREALLOC (char, *pargz, argz_len);
00432   if (!argz)
00433     return ENOMEM;
00434 
00435   /* Copy characters from BUF after terminating '\0' in ARGZ.  */
00436   memcpy (argz + *pargz_len, buf, buf_len);
00437 
00438   /* Assign new values.  */
00439   *pargz = argz;
00440   *pargz_len = argz_len;
00441 
00442   return 0;
00443 }
00444 #endif /* !HAVE_ARGZ_APPEND */
00445 
00446 
00447 #if ! HAVE_ARGZ_CREATE_SEP
00448 #  define argz_create_sep rpl_argz_create_sep
00449 
00450 static error_t argz_create_sep LT_PARAMS((const char *str, int delim,
00451               char **pargz, size_t *pargz_len));
00452 
00453 error_t
00454 argz_create_sep (str, delim, pargz, pargz_len)
00455      const char *str;
00456      int delim;
00457      char **pargz;
00458      size_t *pargz_len;
00459 {
00460   size_t argz_len;
00461   char *argz = 0;
00462 
00463   assert (str);
00464   assert (pargz);
00465   assert (pargz_len);
00466 
00467   /* Make a copy of STR, but replacing each occurence of
00468      DELIM with '\0'.  */
00469   argz_len = 1+ LT_STRLEN (str);
00470   if (argz_len)
00471     {
00472       const char *p;
00473       char *q;
00474 
00475       argz = LT_DLMALLOC (char, argz_len);
00476       if (!argz)
00477   return ENOMEM;
00478 
00479       for (p = str, q = argz; *p != LT_EOS_CHAR; ++p)
00480   {
00481     if (*p == delim)
00482       {
00483         /* Ignore leading delimiters, and fold consecutive
00484      delimiters in STR into a single '\0' in ARGZ.  */
00485         if ((q > argz) && (q[-1] != LT_EOS_CHAR))
00486     *q++ = LT_EOS_CHAR;
00487         else
00488     --argz_len;
00489       }
00490     else
00491       *q++ = *p;
00492   }
00493       /* Copy terminating LT_EOS_CHAR.  */
00494       *q = *p;
00495     }
00496 
00497   /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory.  */
00498   if (!argz_len)
00499     LT_DLFREE (argz);
00500 
00501   /* Assign new values.  */
00502   *pargz = argz;
00503   *pargz_len = argz_len;
00504 
00505   return 0;
00506 }
00507 #endif /* !HAVE_ARGZ_CREATE_SEP */
00508 
00509 
00510 #if ! HAVE_ARGZ_INSERT
00511 #  define argz_insert rpl_argz_insert
00512 
00513 static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len,
00514           char *before, const char *entry));
00515 
00516 error_t
00517 argz_insert (pargz, pargz_len, before, entry)
00518      char **pargz;
00519      size_t *pargz_len;
00520      char *before;
00521      const char *entry;
00522 {
00523   assert (pargz);
00524   assert (pargz_len);
00525   assert (entry && *entry);
00526 
00527   /* Either PARGZ/PARGZ_LEN is empty and BEFORE is NULL,
00528      or BEFORE points into an address within the ARGZ vector.  */
00529   assert ((!*pargz && !*pargz_len && !before)
00530     || ((*pargz <= before) && (before < (*pargz + *pargz_len))));
00531 
00532   /* No BEFORE address indicates ENTRY should be inserted after the
00533      current last element.  */
00534   if (!before)
00535     return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry));
00536 
00537   /* This probably indicates a programmer error, but to preserve
00538      semantics, scan back to the start of an entry if BEFORE points
00539      into the middle of it.  */
00540   while ((before >= *pargz) && (before[-1] != LT_EOS_CHAR))
00541     --before;
00542 
00543   {
00544     size_t entry_len  = 1+ LT_STRLEN (entry);
00545     size_t argz_len = *pargz_len + entry_len;
00546     size_t offset = before - *pargz;
00547     char   *argz  = LT_DLREALLOC (char, *pargz, argz_len);
00548 
00549     if (!argz)
00550       return ENOMEM;
00551 
00552     /* Make BEFORE point to the equivalent offset in ARGZ that it
00553        used to have in *PARGZ incase realloc() moved the block.  */
00554     before = argz + offset;
00555 
00556     /* Move the ARGZ entries starting at BEFORE up into the new
00557        space at the end -- making room to copy ENTRY into the
00558        resulting gap.  */
00559     memmove (before + entry_len, before, *pargz_len - offset);
00560     memcpy  (before, entry, entry_len);
00561 
00562     /* Assign new values.  */
00563     *pargz = argz;
00564     *pargz_len = argz_len;
00565   }
00566 
00567   return 0;
00568 }
00569 #endif /* !HAVE_ARGZ_INSERT */
00570 
00571 
00572 #if ! HAVE_ARGZ_NEXT
00573 #  define argz_next rpl_argz_next
00574 
00575 static char *argz_next LT_PARAMS((char *argz, size_t argz_len,
00576             const char *entry));
00577 
00578 char *
00579 argz_next (argz, argz_len, entry)
00580      char *argz;
00581      size_t argz_len;
00582      const char *entry;
00583 {
00584   assert ((argz && argz_len) || (!argz && !argz_len));
00585 
00586   if (entry)
00587     {
00588       /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address
00589    within the ARGZ vector.  */
00590       assert ((!argz && !argz_len)
00591         || ((argz <= entry) && (entry < (argz + argz_len))));
00592 
00593       /* Move to the char immediately after the terminating
00594    '\0' of ENTRY.  */
00595       entry = 1+ strchr (entry, LT_EOS_CHAR);
00596 
00597       /* Return either the new ENTRY, or else NULL if ARGZ is
00598    exhausted.  */
00599       return (entry >= argz + argz_len) ? 0 : (char *) entry;
00600     }
00601   else
00602     {
00603       /* This should probably be flagged as a programmer error,
00604    since starting an argz_next loop with the iterator set
00605    to ARGZ is safer.  To preserve semantics, handle the NULL
00606    case by returning the start of ARGZ (if any).  */
00607       if (argz_len > 0)
00608   return argz;
00609       else
00610   return 0;
00611     }
00612 }
00613 #endif /* !HAVE_ARGZ_NEXT */
00614 
00615 
00616 
00617 #if ! HAVE_ARGZ_STRINGIFY
00618 #  define argz_stringify rpl_argz_stringify
00619 
00620 static void argz_stringify LT_PARAMS((char *argz, size_t argz_len,
00621                int sep));
00622 
00623 void
00624 argz_stringify (argz, argz_len, sep)
00625      char *argz;
00626      size_t argz_len;
00627      int sep;
00628 {
00629   assert ((argz && argz_len) || (!argz && !argz_len));
00630 
00631   if (sep)
00632     {
00633       --argz_len;   /* don't stringify the terminating EOS */
00634       while (--argz_len > 0)
00635   {
00636     if (argz[argz_len] == LT_EOS_CHAR)
00637       argz[argz_len] = sep;
00638   }
00639     }
00640 }
00641 #endif /* !HAVE_ARGZ_STRINGIFY */
00642 
00643 
00644 
00645 
00646 /* --- TYPE DEFINITIONS -- */
00647 
00648 
00649 /* This type is used for the array of caller data sets in each handler. */
00650 typedef struct {
00651   lt_dlcaller_id  key;
00652   lt_ptr    data;
00653 } lt_caller_data;
00654 
00655 
00656 
00657 
00658 /* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */
00659 
00660 
00661 /* Extract the diagnostic strings from the error table macro in the same
00662    order as the enumerated indices in ltdl.h. */
00663 
00664 static const char *lt_dlerror_strings[] =
00665   {
00666 #define LT_ERROR(name, diagnostic)  (diagnostic),
00667     lt_dlerror_table
00668 #undef LT_ERROR
00669 
00670     0
00671   };
00672 
00673 /* This structure is used for the list of registered loaders. */
00674 struct lt_dlloader {
00675   struct lt_dlloader   *next;
00676   const char         *loader_name;  /* identifying name for each loader */
00677   const char         *sym_prefix; /* prefix for symbols */
00678   lt_module_open       *module_open;
00679   lt_module_close      *module_close;
00680   lt_find_sym        *find_sym;
00681   lt_dlloader_exit     *dlloader_exit;
00682   lt_user_data    dlloader_data;
00683 };
00684 
00685 struct lt_dlhandle_struct {
00686   struct lt_dlhandle_struct   *next;
00687   lt_dlloader        *loader;   /* dlopening interface */
00688   lt_dlinfo   info;
00689   int     depcount; /* number of dependencies */
00690   lt_dlhandle        *deplibs;  /* dependencies */
00691   lt_module   module;   /* system module handle */
00692   lt_ptr    system;   /* system specific data */
00693   lt_caller_data       *caller_data;  /* per caller associated data */
00694   int     flags;    /* various boolean stats */
00695 };
00696 
00697 /* Various boolean flags can be stored in the flags field of an
00698    lt_dlhandle_struct... */
00699 #define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag))
00700 #define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag))
00701 
00702 #define LT_DLRESIDENT_FLAG      (0x01 << 0)
00703 /* ...add more flags here... */
00704 
00705 #define LT_DLIS_RESIDENT(handle)    LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG)
00706 
00707 
00708 #define LT_DLSTRERROR(name) lt_dlerror_strings[LT_CONC(LT_ERROR_,name)]
00709 
00710 static  const char  objdir[]    = LTDL_OBJDIR;
00711 static  const char  archive_ext[]   = LTDL_ARCHIVE_EXT;
00712 #ifdef  LTDL_SHLIB_EXT
00713 static  const char  shlib_ext[]   = LTDL_SHLIB_EXT;
00714 #endif
00715 #ifdef  LTDL_SYSSEARCHPATH
00716 static  const char  sys_search_path[] = LTDL_SYSSEARCHPATH;
00717 #endif
00718 
00719 
00720 
00721 
00722 /* --- MUTEX LOCKING --- */
00723 
00724 
00725 /* Macros to make it easier to run the lock functions only if they have
00726    been registered.  The reason for the complicated lock macro is to
00727    ensure that the stored error message from the last error is not
00728    accidentally erased if the current function doesn't generate an
00729    error of its own.  */
00730 #define LT_DLMUTEX_LOCK()     LT_STMT_START { \
00731   if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)();  \
00732             } LT_STMT_END
00733 #define LT_DLMUTEX_UNLOCK()     LT_STMT_START { \
00734   if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\
00735             } LT_STMT_END
00736 #define LT_DLMUTEX_SETERROR(errormsg)   LT_STMT_START { \
00737   if (lt_dlmutex_seterror_func)       \
00738     (*lt_dlmutex_seterror_func) (errormsg);   \
00739   else  lt_dllast_error = (errormsg); } LT_STMT_END
00740 #define LT_DLMUTEX_GETERROR(errormsg)   LT_STMT_START { \
00741   if (lt_dlmutex_seterror_func)       \
00742     (errormsg) = (*lt_dlmutex_geterror_func) ();  \
00743   else  (errormsg) = lt_dllast_error; } LT_STMT_END
00744 
00745 /* The mutex functions stored here are global, and are necessarily the
00746    same for all threads that wish to share access to libltdl.  */
00747 static  lt_dlmutex_lock     *lt_dlmutex_lock_func     = 0;
00748 static  lt_dlmutex_unlock   *lt_dlmutex_unlock_func   = 0;
00749 static  lt_dlmutex_seterror *lt_dlmutex_seterror_func = 0;
00750 static  lt_dlmutex_geterror *lt_dlmutex_geterror_func = 0;
00751 static  const char      *lt_dllast_error        = 0;
00752 
00753 
00754 /* Either set or reset the mutex functions.  Either all the arguments must
00755    be valid functions, or else all can be NULL to turn off locking entirely.
00756    The registered functions should be manipulating a static global lock
00757    from the lock() and unlock() callbacks, which needs to be reentrant.  */
00758 int
00759 lt_dlmutex_register (lock, unlock, seterror, geterror)
00760      lt_dlmutex_lock *lock;
00761      lt_dlmutex_unlock *unlock;
00762      lt_dlmutex_seterror *seterror;
00763      lt_dlmutex_geterror *geterror;
00764 {
00765   lt_dlmutex_unlock *old_unlock = unlock;
00766   int        errors = 0;
00767 
00768   /* Lock using the old lock() callback, if any.  */
00769   LT_DLMUTEX_LOCK ();
00770 
00771   if ((lock && unlock && seterror && geterror)
00772       || !(lock || unlock || seterror || geterror))
00773     {
00774       lt_dlmutex_lock_func     = lock;
00775       lt_dlmutex_unlock_func   = unlock;
00776       lt_dlmutex_geterror_func = geterror;
00777     }
00778   else
00779     {
00780       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS));
00781       ++errors;
00782     }
00783 
00784   /* Use the old unlock() callback we saved earlier, if any.  Otherwise
00785      record any errors using internal storage.  */
00786   if (old_unlock)
00787     (*old_unlock) ();
00788 
00789   /* Return the number of errors encountered during the execution of
00790      this function.  */
00791   return errors;
00792 }
00793 
00794 
00795 
00796 
00797 /* --- ERROR HANDLING --- */
00798 
00799 
00800 static  const char    **user_error_strings  = 0;
00801 static  int   errorcount    = LT_ERROR_MAX;
00802 
00803 int
00804 lt_dladderror (diagnostic)
00805      const char *diagnostic;
00806 {
00807   int   errindex = 0;
00808   int   result   = -1;
00809   const char  **temp     = (const char **) 0;
00810 
00811   assert (diagnostic);
00812 
00813   LT_DLMUTEX_LOCK ();
00814 
00815   errindex = errorcount - LT_ERROR_MAX;
00816   temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex);
00817   if (temp)
00818     {
00819       user_error_strings    = temp;
00820       user_error_strings[errindex]  = diagnostic;
00821       result        = errorcount++;
00822     }
00823 
00824   LT_DLMUTEX_UNLOCK ();
00825 
00826   return result;
00827 }
00828 
00829 int
00830 lt_dlseterror (errindex)
00831      int errindex;
00832 {
00833   int   errors   = 0;
00834 
00835   LT_DLMUTEX_LOCK ();
00836 
00837   if (errindex >= errorcount || errindex < 0)
00838     {
00839       /* Ack!  Error setting the error message! */
00840       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE));
00841       ++errors;
00842     }
00843   else if (errindex < LT_ERROR_MAX)
00844     {
00845       /* No error setting the error message! */
00846       LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]);
00847     }
00848   else
00849     {
00850       /* No error setting the error message! */
00851       LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]);
00852     }
00853 
00854   LT_DLMUTEX_UNLOCK ();
00855 
00856   return errors;
00857 }
00858 
00859 lt_ptr
00860 lt_emalloc (size)
00861      size_t size;
00862 {
00863   lt_ptr mem = lt_dlmalloc (size);
00864   if (size && !mem)
00865     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
00866   return mem;
00867 }
00868 
00869 lt_ptr
00870 lt_erealloc (addr, size)
00871      lt_ptr addr;
00872      size_t size;
00873 {
00874   lt_ptr mem = realloc (addr, size);
00875   if (size && !mem)
00876     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
00877   return mem;
00878 }
00879 
00880 char *
00881 lt_estrdup (str)
00882      const char *str;
00883 {
00884   char *dup = strdup (str);
00885   if (LT_STRLEN (str) && !dup)
00886     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
00887   return dup;
00888 }
00889 
00890 
00891 
00892 
00893 /* --- DLOPEN() INTERFACE LOADER --- */
00894 
00895 
00896 /* The Cygwin dlopen implementation prints a spurious error message to
00897    stderr if its call to LoadLibrary() fails for any reason.  We can
00898    mitigate this by not using the Cygwin implementation, and falling
00899    back to our own LoadLibrary() wrapper. */
00900 #if HAVE_LIBDL && !defined(__CYGWIN__)
00901 
00902 /* dynamic linking with dlopen/dlsym */
00903 
00904 #if HAVE_DLFCN_H
00905 #  include <dlfcn.h>
00906 #endif
00907 
00908 #if HAVE_SYS_DL_H
00909 #  include <sys/dl.h>
00910 #endif
00911 
00912 #ifdef RTLD_GLOBAL
00913 #  define LT_GLOBAL   RTLD_GLOBAL
00914 #else
00915 #  ifdef DL_GLOBAL
00916 #    define LT_GLOBAL   DL_GLOBAL
00917 #  endif
00918 #endif /* !RTLD_GLOBAL */
00919 #ifndef LT_GLOBAL
00920 #  define LT_GLOBAL   0
00921 #endif /* !LT_GLOBAL */
00922 
00923 /* We may have to define LT_LAZY_OR_NOW in the command line if we
00924    find out it does not work in some platform. */
00925 #ifndef LT_LAZY_OR_NOW
00926 #  ifdef RTLD_LAZY
00927 #    define LT_LAZY_OR_NOW  RTLD_LAZY
00928 #  else
00929 #    ifdef DL_LAZY
00930 #      define LT_LAZY_OR_NOW  DL_LAZY
00931 #    endif
00932 #  endif /* !RTLD_LAZY */
00933 #endif
00934 #ifndef LT_LAZY_OR_NOW
00935 #  ifdef RTLD_NOW
00936 #    define LT_LAZY_OR_NOW  RTLD_NOW
00937 #  else
00938 #    ifdef DL_NOW
00939 #      define LT_LAZY_OR_NOW  DL_NOW
00940 #    endif
00941 #  endif /* !RTLD_NOW */
00942 #endif
00943 #ifndef LT_LAZY_OR_NOW
00944 #  define LT_LAZY_OR_NOW  0
00945 #endif /* !LT_LAZY_OR_NOW */
00946 
00947 #if HAVE_DLERROR
00948 #  define DLERROR(arg)  dlerror ()
00949 #else
00950 #  define DLERROR(arg)  LT_DLSTRERROR (arg)
00951 #endif
00952 
00953 static lt_module
00954 sys_dl_open (loader_data, filename)
00955      lt_user_data loader_data;
00956      const char *filename;
00957 {
00958   lt_module   module   = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW);
00959 
00960   if (!module)
00961     {
00962       const char* tmp   = dlerror();
00963       const char* match = strstr (tmp, "undefined symbol:" );
00964       if ( match )
00965       {
00966         fprintf (stderr, "Failed to open shared lib: %s\n"
00967                          "                    Error: %s\n",
00968                          filename, tmp);
00969       }
00970       LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN));
00971     }
00972 
00973   return module;
00974 }
00975 
00976 static int
00977 sys_dl_close (loader_data, module)
00978      lt_user_data loader_data;
00979      lt_module module;
00980 {
00981   int errors = 0;
00982 
00983   if (dlclose (module) != 0)
00984     {
00985       LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE));
00986       ++errors;
00987     }
00988 
00989   return errors;
00990 }
00991 
00992 static lt_ptr
00993 sys_dl_sym (loader_data, module, symbol)
00994      lt_user_data loader_data;
00995      lt_module module;
00996      const char *symbol;
00997 {
00998   lt_ptr address = dlsym (module, symbol);
00999 
01000   if (!address)
01001     {
01002       LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND));
01003     }
01004 
01005   return address;
01006 }
01007 
01008 static struct lt_user_dlloader sys_dl =
01009   {
01010 #  ifdef NEED_USCORE
01011     "_",
01012 #  else
01013     0,
01014 #  endif
01015     sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 };
01016 
01017 
01018 #endif /* HAVE_LIBDL */
01019 
01020 
01021 
01022 /* --- SHL_LOAD() INTERFACE LOADER --- */
01023 
01024 #if HAVE_SHL_LOAD
01025 
01026 /* dynamic linking with shl_load (HP-UX) (comments from gmodule) */
01027 
01028 #ifdef HAVE_DL_H
01029 #  include <dl.h>
01030 #endif
01031 
01032 /* some flags are missing on some systems, so we provide
01033  * harmless defaults.
01034  *
01035  * Mandatory:
01036  * BIND_IMMEDIATE  - Resolve symbol references when the library is loaded.
01037  * BIND_DEFERRED   - Delay code symbol resolution until actual reference.
01038  *
01039  * Optionally:
01040  * BIND_FIRST    - Place the library at the head of the symbol search
01041  *         order.
01042  * BIND_NONFATAL   - The default BIND_IMMEDIATE behavior is to treat all
01043  *         unsatisfied symbols as fatal.  This flag allows
01044  *         binding of unsatisfied code symbols to be deferred
01045  *         until use.
01046  *         [Perl: For certain libraries, like DCE, deferred
01047  *         binding often causes run time problems. Adding
01048  *         BIND_NONFATAL to BIND_IMMEDIATE still allows
01049  *         unresolved references in situations like this.]
01050  * BIND_NOSTART    - Do not call the initializer for the shared library
01051  *         when the library is loaded, nor on a future call to
01052  *         shl_unload().
01053  * BIND_VERBOSE    - Print verbose messages concerning possible
01054  *         unsatisfied symbols.
01055  *
01056  * hp9000s700/hp9000s800:
01057  * BIND_RESTRICTED - Restrict symbols visible by the library to those
01058  *         present at library load time.
01059  * DYNAMIC_PATH    - Allow the loader to dynamically search for the
01060  *         library specified by the path argument.
01061  */
01062 
01063 #ifndef DYNAMIC_PATH
01064 #  define DYNAMIC_PATH    0
01065 #endif
01066 #ifndef BIND_RESTRICTED
01067 #  define BIND_RESTRICTED 0
01068 #endif
01069 
01070 #define LT_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH)
01071 
01072 static lt_module
01073 sys_shl_open (loader_data, filename)
01074      lt_user_data loader_data;
01075      const char *filename;
01076 {
01077   static shl_t self = (shl_t) 0;
01078   lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L);
01079 
01080   /* Since searching for a symbol against a NULL module handle will also
01081      look in everything else that was already loaded and exported with
01082      the -E compiler flag, we always cache a handle saved before any
01083      modules are loaded.  */
01084   if (!self)
01085     {
01086       lt_ptr address;
01087       shl_findsym (&self, "main", TYPE_UNDEFINED, &address);
01088     }
01089 
01090   if (!filename)
01091     {
01092       module = self;
01093     }
01094   else
01095     {
01096       module = shl_load (filename, LT_BIND_FLAGS, 0L);
01097 
01098       if (!module)
01099   {
01100     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
01101   }
01102     }
01103 
01104   return module;
01105 }
01106 
01107 static int
01108 sys_shl_close (loader_data, module)
01109      lt_user_data loader_data;
01110      lt_module module;
01111 {
01112   int errors = 0;
01113 
01114   if (module && (shl_unload ((shl_t) (module)) != 0))
01115     {
01116       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
01117       ++errors;
01118     }
01119 
01120   return errors;
01121 }
01122 
01123 static lt_ptr
01124 sys_shl_sym (loader_data, module, symbol)
01125      lt_user_data loader_data;
01126      lt_module module;
01127      const char *symbol;
01128 {
01129   lt_ptr address = 0;
01130 
01131   /* sys_shl_open should never return a NULL module handle */
01132   if (module == (lt_module) 0)
01133   {
01134     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
01135   }
01136   else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address))
01137     {
01138       if (!address)
01139   {
01140     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
01141   }
01142     }
01143 
01144   return address;
01145 }
01146 
01147 static struct lt_user_dlloader sys_shl = {
01148   0, sys_shl_open, sys_shl_close, sys_shl_sym, 0, 0
01149 };
01150 
01151 #endif /* HAVE_SHL_LOAD */
01152 
01153 
01154 
01155 
01156 /* --- LOADLIBRARY() INTERFACE LOADER --- */
01157 
01158 #ifdef __WINDOWS__
01159 
01160 /* dynamic linking for Win32 */
01161 
01162 #include <windows.h>
01163 
01164 /* Forward declaration; required to implement handle search below. */
01165 static lt_dlhandle handles;
01166 
01167 static lt_module
01168 sys_wll_open (loader_data, filename)
01169      lt_user_data loader_data;
01170      const char *filename;
01171 {
01172   lt_dlhandle cur;
01173   lt_module module     = 0;
01174   const char   *errormsg   = 0;
01175   char         *searchname = 0;
01176   char         *ext;
01177   char    self_name_buf[MAX_PATH];
01178 
01179   if (!filename)
01180     {
01181       /* Get the name of main module */
01182       *self_name_buf = 0;
01183       GetModuleFileName (NULL, self_name_buf, sizeof (self_name_buf));
01184       filename = ext = self_name_buf;
01185     }
01186   else
01187     {
01188       ext = strrchr (filename, '.');
01189     }
01190 
01191   if (ext)
01192     {
01193       /* FILENAME already has an extension. */
01194       searchname = lt_estrdup (filename);
01195     }
01196   else
01197     {
01198       /* Append a `.' to stop Windows from adding an
01199    implicit `.dll' extension. */
01200       searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename));
01201       if (searchname)
01202   sprintf (searchname, "%s.", filename);
01203     }
01204   if (!searchname)
01205     return 0;
01206 
01207 #if __CYGWIN__
01208   {
01209     char wpath[MAX_PATH];
01210     cygwin_conv_to_full_win32_path(searchname, wpath);
01211     module = LoadLibrary(wpath);
01212   }
01213 #else
01214   module = LoadLibrary (searchname);
01215 #endif
01216   LT_DLFREE (searchname);
01217 
01218   /* libltdl expects this function to fail if it is unable
01219      to physically load the library.  Sadly, LoadLibrary
01220      will search the loaded libraries for a match and return
01221      one of them if the path search load fails.
01222 
01223      We check whether LoadLibrary is returning a handle to
01224      an already loaded module, and simulate failure if we
01225      find one. */
01226   LT_DLMUTEX_LOCK ();
01227   cur = handles;
01228   while (cur)
01229     {
01230       if (!cur->module)
01231   {
01232     cur = 0;
01233     break;
01234   }
01235 
01236       if (cur->module == module)
01237   {
01238     break;
01239   }
01240 
01241       cur = cur->next;
01242   }
01243   LT_DLMUTEX_UNLOCK ();
01244 
01245   if (cur || !module)
01246     {
01247       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
01248       module = 0;
01249     }
01250 
01251   return module;
01252 }
01253 
01254 static int
01255 sys_wll_close (loader_data, module)
01256      lt_user_data loader_data;
01257      lt_module module;
01258 {
01259   int       errors   = 0;
01260 
01261   if (FreeLibrary(module) == 0)
01262     {
01263       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
01264       ++errors;
01265     }
01266 
01267   return errors;
01268 }
01269 
01270 static lt_ptr
01271 sys_wll_sym (loader_data, module, symbol)
01272      lt_user_data loader_data;
01273      lt_module module;
01274      const char *symbol;
01275 {
01276   lt_ptr      address  = GetProcAddress (module, symbol);
01277 
01278   if (!address)
01279     {
01280       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
01281     }
01282 
01283   return address;
01284 }
01285 
01286 static struct lt_user_dlloader sys_wll = {
01287   0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0
01288 };
01289 
01290 #endif /* __WINDOWS__ */
01291 
01292 
01293 
01294 
01295 /* --- LOAD_ADD_ON() INTERFACE LOADER --- */
01296 
01297 
01298 #ifdef __BEOS__
01299 
01300 /* dynamic linking for BeOS */
01301 
01302 #include <kernel/image.h>
01303 
01304 static lt_module
01305 sys_bedl_open (loader_data, filename)
01306      lt_user_data loader_data;
01307      const char *filename;
01308 {
01309   image_id image = 0;
01310 
01311   if (filename)
01312     {
01313       image = load_add_on (filename);
01314     }
01315   else
01316     {
01317       image_info info;
01318       int32 cookie = 0;
01319       if (get_next_image_info (0, &cookie, &info) == B_OK)
01320   image = load_add_on (info.name);
01321     }
01322 
01323   if (image <= 0)
01324     {
01325       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
01326       image = 0;
01327     }
01328 
01329   return (lt_module) image;
01330 }
01331 
01332 static int
01333 sys_bedl_close (loader_data, module)
01334      lt_user_data loader_data;
01335      lt_module module;
01336 {
01337   int errors = 0;
01338 
01339   if (unload_add_on ((image_id) module) != B_OK)
01340     {
01341       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
01342       ++errors;
01343     }
01344 
01345   return errors;
01346 }
01347 
01348 static lt_ptr
01349 sys_bedl_sym (loader_data, module, symbol)
01350      lt_user_data loader_data;
01351      lt_module module;
01352      const char *symbol;
01353 {
01354   lt_ptr address = 0;
01355   image_id image = (image_id) module;
01356 
01357   if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK)
01358     {
01359       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
01360       address = 0;
01361     }
01362 
01363   return address;
01364 }
01365 
01366 static struct lt_user_dlloader sys_bedl = {
01367   0, sys_bedl_open, sys_bedl_close, sys_bedl_sym, 0, 0
01368 };
01369 
01370 #endif /* __BEOS__ */
01371 
01372 
01373 
01374 
01375 /* --- DLD_LINK() INTERFACE LOADER --- */
01376 
01377 
01378 #if HAVE_DLD
01379 
01380 /* dynamic linking with dld */
01381 
01382 #if HAVE_DLD_H
01383 #include <dld.h>
01384 #endif
01385 
01386 static lt_module
01387 sys_dld_open (loader_data, filename)
01388      lt_user_data loader_data;
01389      const char *filename;
01390 {
01391   lt_module module = strdup (filename);
01392 
01393   if (dld_link (filename) != 0)
01394     {
01395       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
01396       LT_DLFREE (module);
01397       module = 0;
01398     }
01399 
01400   return module;
01401 }
01402 
01403 static int
01404 sys_dld_close (loader_data, module)
01405      lt_user_data loader_data;
01406      lt_module module;
01407 {
01408   int errors = 0;
01409 
01410   if (dld_unlink_by_file ((char*)(module), 1) != 0)
01411     {
01412       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
01413       ++errors;
01414     }
01415   else
01416     {
01417       LT_DLFREE (module);
01418     }
01419 
01420   return errors;
01421 }
01422 
01423 static lt_ptr
01424 sys_dld_sym (loader_data, module, symbol)
01425      lt_user_data loader_data;
01426      lt_module module;
01427      const char *symbol;
01428 {
01429   lt_ptr address = dld_get_func (symbol);
01430 
01431   if (!address)
01432     {
01433       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
01434     }
01435 
01436   return address;
01437 }
01438 
01439 static struct lt_user_dlloader sys_dld = {
01440   0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0
01441 };
01442 
01443 #endif /* HAVE_DLD */
01444 
01445 
01446 
01447 
01448 /* --- DLPREOPEN() INTERFACE LOADER --- */
01449 
01450 
01451 /* emulate dynamic linking using preloaded_symbols */
01452 
01453 typedef struct lt_dlsymlists_t
01454 {
01455   struct lt_dlsymlists_t       *next;
01456   const lt_dlsymlist         *syms;
01457 } lt_dlsymlists_t;
01458 
01459 static  const lt_dlsymlist     *default_preloaded_symbols = 0;
01460 static  lt_dlsymlists_t        *preloaded_symbols   = 0;
01461 
01462 static int
01463 presym_init (loader_data)
01464      lt_user_data loader_data;
01465 {
01466   int errors = 0;
01467 
01468   LT_DLMUTEX_LOCK ();
01469 
01470   preloaded_symbols = 0;
01471   if (default_preloaded_symbols)
01472     {
01473       errors = lt_dlpreload (default_preloaded_symbols);
01474     }
01475 
01476   LT_DLMUTEX_UNLOCK ();
01477 
01478   return errors;
01479 }
01480 
01481 static int
01482 presym_free_symlists ()
01483 {
01484   lt_dlsymlists_t *lists;
01485 
01486   LT_DLMUTEX_LOCK ();
01487 
01488   lists = preloaded_symbols;
01489   while (lists)
01490     {
01491       lt_dlsymlists_t *tmp = lists;
01492 
01493       lists = lists->next;
01494       LT_DLFREE (tmp);
01495     }
01496   preloaded_symbols = 0;
01497 
01498   LT_DLMUTEX_UNLOCK ();
01499 
01500   return 0;
01501 }
01502 
01503 static int
01504 presym_exit (loader_data)
01505      lt_user_data loader_data;
01506 {
01507   presym_free_symlists ();
01508   return 0;
01509 }
01510 
01511 static int
01512 presym_add_symlist (preloaded)
01513      const lt_dlsymlist *preloaded;
01514 {
01515   lt_dlsymlists_t *tmp;
01516   lt_dlsymlists_t *lists;
01517   int      errors   = 0;
01518 
01519   LT_DLMUTEX_LOCK ();
01520 
01521   lists = preloaded_symbols;
01522   while (lists)
01523     {
01524       if (lists->syms == preloaded)
01525   {
01526     goto done;
01527   }
01528       lists = lists->next;
01529     }
01530 
01531   tmp = LT_EMALLOC (lt_dlsymlists_t, 1);
01532   if (tmp)
01533     {
01534       memset (tmp, 0, sizeof(lt_dlsymlists_t));
01535       tmp->syms = preloaded;
01536       tmp->next = preloaded_symbols;
01537       preloaded_symbols = tmp;
01538     }
01539   else
01540     {
01541       ++errors;
01542     }
01543 
01544  done:
01545   LT_DLMUTEX_UNLOCK ();
01546   return errors;
01547 }
01548 
01549 static lt_module
01550 presym_open (loader_data, filename)
01551      lt_user_data loader_data;
01552      const char *filename;
01553 {
01554   lt_dlsymlists_t *lists;
01555   lt_module    module = (lt_module) 0;
01556 
01557   LT_DLMUTEX_LOCK ();
01558   lists = preloaded_symbols;
01559 
01560   if (!lists)
01561     {
01562       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS));
01563       goto done;
01564     }
01565 
01566   /* Can't use NULL as the reflective symbol header, as NULL is
01567      used to mark the end of the entire symbol list.  Self-dlpreopened
01568      symbols follow this magic number, chosen to be an unlikely
01569      clash with a real module name.  */
01570   if (!filename)
01571     {
01572       filename = "@PROGRAM@";
01573     }
01574 
01575   while (lists)
01576     {
01577       const lt_dlsymlist *syms = lists->syms;
01578 
01579       while (syms->name)
01580   {
01581     if (!syms->address && strcmp(syms->name, filename) == 0)
01582       {
01583         module = (lt_module) syms;
01584         goto done;
01585       }
01586     ++syms;
01587   }
01588 
01589       lists = lists->next;
01590     }
01591 
01592   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
01593 
01594  done:
01595   LT_DLMUTEX_UNLOCK ();
01596   return module;
01597 }
01598 
01599 static int
01600 presym_close (loader_data, module)
01601      lt_user_data loader_data;
01602      lt_module module;
01603 {
01604   /* Just to silence gcc -Wall */
01605   module = 0;
01606   return 0;
01607 }
01608 
01609 static lt_ptr
01610 presym_sym (loader_data, module, symbol)
01611      lt_user_data loader_data;
01612      lt_module module;
01613      const char *symbol;
01614 {
01615   lt_dlsymlist *syms = (lt_dlsymlist*) module;
01616 
01617   ++syms;
01618   while (syms->address)
01619     {
01620       if (strcmp(syms->name, symbol) == 0)
01621   {
01622     return syms->address;
01623   }
01624 
01625     ++syms;
01626   }
01627 
01628   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
01629 
01630   return 0;
01631 }
01632 
01633 static struct lt_user_dlloader presym = {
01634   0, presym_open, presym_close, presym_sym, presym_exit, 0
01635 };
01636 
01637 
01638 
01639 
01640 
01641 /* --- DYNAMIC MODULE LOADING --- */
01642 
01643 
01644 /* The type of a function used at each iteration of  foreach_dirinpath().  */
01645 typedef int foreach_callback_func LT_PARAMS((char *filename, lt_ptr data1,
01646              lt_ptr data2));
01647 
01648 static  int foreach_dirinpath     LT_PARAMS((const char *search_path,
01649              const char *base_name,
01650              foreach_callback_func *func,
01651              lt_ptr data1, lt_ptr data2));
01652 
01653 static  int find_file_callback    LT_PARAMS((char *filename, lt_ptr data,
01654              lt_ptr ignored));
01655 static  int find_handle_callback  LT_PARAMS((char *filename, lt_ptr data,
01656              lt_ptr ignored));
01657 static  int foreachfile_callback  LT_PARAMS((char *filename, lt_ptr data1,
01658              lt_ptr data2));
01659 
01660 
01661 static  int     canonicalize_path     LT_PARAMS((const char *path,
01662              char **pcanonical));
01663 static  int argzize_path        LT_PARAMS((const char *path,
01664              char **pargz,
01665              size_t *pargz_len));
01666 static  FILE   *find_file       LT_PARAMS((const char *search_path,
01667              const char *base_name,
01668              char **pdir));
01669 static  lt_dlhandle *find_handle      LT_PARAMS((const char *search_path,
01670              const char *base_name,
01671              lt_dlhandle *handle));
01672 static  int find_module       LT_PARAMS((lt_dlhandle *handle,
01673              const char *dir,
01674              const char *libdir,
01675              const char *dlname,
01676              const char *old_name,
01677              int installed));
01678 static  int free_vars       LT_PARAMS((char *dlname, char *oldname,
01679              char *libdir, char *deplibs));
01680 static  int load_deplibs        LT_PARAMS((lt_dlhandle handle,
01681              char *deplibs));
01682 static  int trim          LT_PARAMS((char **dest,
01683              const char *str));
01684 static  int try_dlopen        LT_PARAMS((lt_dlhandle *handle,
01685              const char *filename));
01686 static  int tryall_dlopen       LT_PARAMS((lt_dlhandle *handle,
01687              const char *filename));
01688 static  int unload_deplibs        LT_PARAMS((lt_dlhandle handle));
01689 static  int lt_argz_insert        LT_PARAMS((char **pargz,
01690              size_t *pargz_len,
01691              char *before,
01692              const char *entry));
01693 static  int lt_argz_insertinorder LT_PARAMS((char **pargz,
01694              size_t *pargz_len,
01695              const char *entry));
01696 static  int lt_dlpath_insertdir   LT_PARAMS((char **ppath,
01697              char *before,
01698              const char *dir));
01699 
01700 static  char         *user_search_path= 0;
01701 static  lt_dlloader    *loaders   = 0;
01702 static  lt_dlhandle handles   = 0;
01703 static  int   initialized   = 0;
01704 
01705 /* Initialize libltdl. */
01706 int
01707 lt_dlinit ()
01708 {
01709   int       errors   = 0;
01710 
01711   LT_DLMUTEX_LOCK ();
01712 
01713   /* Initialize only at first call. */
01714   if (++initialized == 1)
01715     {
01716       handles = 0;
01717       user_search_path = 0; /* empty search path */
01718 
01719 #if HAVE_LIBDL && !defined(__CYGWIN__)
01720       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen");
01721 #endif
01722 #if HAVE_SHL_LOAD
01723       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_shl, "dlopen");
01724 #endif
01725 #ifdef __WINDOWS__
01726       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_wll, "dlopen");
01727 #endif
01728 #ifdef __BEOS__
01729       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_bedl, "dlopen");
01730 #endif
01731 #if HAVE_DLD
01732       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dld, "dld");
01733 #endif
01734       errors += lt_dlloader_add (lt_dlloader_next (0), &presym, "dlpreload");
01735 
01736       if (presym_init (presym.dlloader_data))
01737   {
01738     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER));
01739     ++errors;
01740   }
01741       else if (errors != 0)
01742   {
01743     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED));
01744     ++errors;
01745   }
01746     }
01747 
01748   LT_DLMUTEX_UNLOCK ();
01749 
01750   return errors;
01751 }
01752 
01753 int
01754 lt_dlpreload (preloaded)
01755      const lt_dlsymlist *preloaded;
01756 {
01757   int errors = 0;
01758 
01759   if (preloaded)
01760     {
01761       errors = presym_add_symlist (preloaded);
01762     }
01763   else
01764     {
01765       presym_free_symlists();
01766 
01767       LT_DLMUTEX_LOCK ();
01768       if (default_preloaded_symbols)
01769   {
01770     errors = lt_dlpreload (default_preloaded_symbols);
01771   }
01772       LT_DLMUTEX_UNLOCK ();
01773     }
01774 
01775   return errors;
01776 }
01777 
01778 int
01779 lt_dlpreload_default (preloaded)
01780      const lt_dlsymlist *preloaded;
01781 {
01782   LT_DLMUTEX_LOCK ();
01783   default_preloaded_symbols = preloaded;
01784   LT_DLMUTEX_UNLOCK ();
01785   return 0;
01786 }
01787 
01788 int
01789 lt_dlexit ()
01790 {
01791   /* shut down libltdl */
01792   lt_dlloader *loader;
01793   int        errors   = 0;
01794 
01795   LT_DLMUTEX_LOCK ();
01796   loader = loaders;
01797 
01798   if (!initialized)
01799     {
01800       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN));
01801       ++errors;
01802       goto done;
01803     }
01804 
01805   /* shut down only at last call. */
01806   if (--initialized == 0)
01807     {
01808       int level;
01809 
01810       while (handles && LT_DLIS_RESIDENT (handles))
01811   {
01812     handles = handles->next;
01813   }
01814 
01815       /* close all modules */
01816       for (level = 1; handles; ++level)
01817   {
01818     lt_dlhandle cur = handles;
01819     int saw_nonresident = 0;
01820 
01821     while (cur)
01822       {
01823         lt_dlhandle tmp = cur;
01824         cur = cur->next;
01825         if (!LT_DLIS_RESIDENT (tmp))
01826     saw_nonresident = 1;
01827         if (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level)
01828     {
01829       if (lt_dlclose (tmp))
01830         {
01831           ++errors;
01832         }
01833     }
01834       }
01835     /* done if only resident modules are left */
01836     if (!saw_nonresident)
01837       break;
01838   }
01839 
01840       /* close all loaders */
01841       while (loader)
01842   {
01843     lt_dlloader *next = loader->next;
01844     lt_user_data data = loader->dlloader_data;
01845     if (loader->dlloader_exit && loader->dlloader_exit (data))
01846       {
01847         ++errors;
01848       }
01849 
01850     LT_DLMEM_REASSIGN (loader, next);
01851   }
01852       loaders = 0;
01853     }
01854 
01855  done:
01856   LT_DLMUTEX_UNLOCK ();
01857   return errors;
01858 }
01859 
01860 static int
01861 tryall_dlopen (handle, filename)
01862      lt_dlhandle *handle;
01863      const char *filename;
01864 {
01865   lt_dlhandle  cur;
01866   lt_dlloader   *loader;
01867   const char  *saved_error;
01868   int    errors   = 0;
01869 
01870   LT_DLMUTEX_GETERROR (saved_error);
01871   LT_DLMUTEX_LOCK ();
01872 
01873   cur  = handles;
01874   loader = loaders;
01875 
01876   /* check whether the module was already opened */
01877   while (cur)
01878     {
01879       /* try to dlopen the program itself? */
01880       if (!cur->info.filename && !filename)
01881   {
01882     break;
01883   }
01884 
01885       if (cur->info.filename && filename
01886     && strcmp (cur->info.filename, filename) == 0)
01887   {
01888     break;
01889   }
01890 
01891       cur = cur->next;
01892     }
01893 
01894   if (cur)
01895     {
01896       ++cur->info.ref_count;
01897       *handle = cur;
01898       goto done;
01899     }
01900 
01901   cur = *handle;
01902   if (filename)
01903     {
01904       cur->info.filename = lt_estrdup (filename);
01905       if (!cur->info.filename)
01906   {
01907     ++errors;
01908     goto done;
01909   }
01910     }
01911   else
01912     {
01913       cur->info.filename = 0;
01914     }
01915 
01916   while (loader)
01917     {
01918       lt_user_data data = loader->dlloader_data;
01919 
01920       cur->module = loader->module_open (data, filename);
01921 
01922       if (cur->module != 0)
01923   {
01924     break;
01925   }
01926       loader = loader->next;
01927     }
01928 
01929   if (!loader)
01930     {
01931       LT_DLFREE (cur->info.filename);
01932       ++errors;
01933       goto done;
01934     }
01935 
01936   cur->loader = loader;
01937   LT_DLMUTEX_SETERROR (saved_error);
01938 
01939  done:
01940   LT_DLMUTEX_UNLOCK ();
01941 
01942   return errors;
01943 }
01944 
01945 static int
01946 tryall_dlopen_module (handle, prefix, dirname, dlname)
01947      lt_dlhandle *handle;
01948      const char *prefix;
01949      const char *dirname;
01950      const char *dlname;
01951 {
01952   int      error  = 0;
01953   char     *filename  = 0;
01954   size_t   filename_len = 0;
01955   size_t   dirname_len  = LT_STRLEN (dirname);
01956 
01957   assert (handle);
01958   assert (dirname);
01959   assert (dlname);
01960 #ifdef LT_DIRSEP_CHAR
01961   /* Only canonicalized names (i.e. with DIRSEP chars already converted)
01962      should make it into this function:  */
01963   assert (strchr (dirname, LT_DIRSEP_CHAR) == 0);
01964 #endif
01965 
01966   if (dirname[dirname_len -1] == '/')
01967     --dirname_len;
01968   filename_len = dirname_len + 1 + LT_STRLEN (dlname);
01969 
01970   /* Allocate memory, and combine DIRNAME and MODULENAME into it.
01971      The PREFIX (if any) is handled below.  */
01972   filename  = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1);
01973   if (!filename)
01974     return 1;
01975 
01976   sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname);
01977 
01978   /* Now that we have combined DIRNAME and MODULENAME, if there is
01979      also a PREFIX to contend with, simply recurse with the arguments
01980      shuffled.  Otherwise, attempt to open FILENAME as a module.  */
01981   if (prefix)
01982     {
01983       error += tryall_dlopen_module (handle,
01984              (const char *) 0, prefix, filename);
01985     }
01986   else if (tryall_dlopen (handle, filename) != 0)
01987     {
01988       ++error;
01989     }
01990 
01991   LT_DLFREE (filename);
01992   return error;
01993 }
01994 
01995 static int
01996 find_module (handle, dir, libdir, dlname, old_name, installed)
01997      lt_dlhandle *handle;
01998      const char *dir;
01999      const char *libdir;
02000      const char *dlname;
02001      const char *old_name;
02002      int installed;
02003 {
02004   /* Try to open the old library first; if it was dlpreopened,
02005      we want the preopened version of it, even if a dlopenable
02006      module is available.  */
02007   if (old_name && tryall_dlopen (handle, old_name) == 0)
02008     {
02009       return 0;
02010     }
02011 
02012   /* Try to open the dynamic library.  */
02013   if (dlname)
02014     {
02015       /* try to open the installed module */
02016       if (installed && libdir)
02017   {
02018     if (tryall_dlopen_module (handle,
02019             (const char *) 0, libdir, dlname) == 0)
02020       return 0;
02021   }
02022 
02023       /* try to open the not-installed module */
02024       if (!installed)
02025   {
02026     if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0)
02027       return 0;
02028   }
02029 
02030       /* maybe it was moved to another directory */
02031       {
02032     if (tryall_dlopen_module (handle,
02033             (const char *) 0, dir, dlname) == 0)
02034       return 0;
02035       }
02036     }
02037 
02038   return 1;
02039 }
02040 
02041 
02042 static int
02043 canonicalize_path (path, pcanonical)
02044      const char *path;
02045      char **pcanonical;
02046 {
02047   char *canonical = 0;
02048 
02049   assert (path && *path);
02050   assert (pcanonical);
02051 
02052   canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path));
02053   if (!canonical)
02054     return 1;
02055 
02056   {
02057     size_t dest = 0;
02058     size_t src;
02059     for (src = 0; path[src] != LT_EOS_CHAR; ++src)
02060       {
02061   /* Path separators are not copied to the beginning or end of
02062      the destination, or if another separator would follow
02063      immediately.  */
02064   if (path[src] == LT_PATHSEP_CHAR)
02065     {
02066       if ((dest == 0)
02067     || (path[1+ src] == LT_PATHSEP_CHAR)
02068     || (path[1+ src] == LT_EOS_CHAR))
02069         continue;
02070     }
02071 
02072   /* Anything other than a directory separator is copied verbatim.  */
02073   if ((path[src] != '/')
02074 #ifdef LT_DIRSEP_CHAR
02075       && (path[src] != LT_DIRSEP_CHAR)
02076 #endif
02077       )
02078     {
02079       canonical[dest++] = path[src];
02080     }
02081   /* Directory separators are converted and copied only if they are
02082      not at the end of a path -- i.e. before a path separator or
02083      NULL terminator.  */
02084   else if ((path[1+ src] != LT_PATHSEP_CHAR)
02085      && (path[1+ src] != LT_EOS_CHAR)
02086 #ifdef LT_DIRSEP_CHAR
02087      && (path[1+ src] != LT_DIRSEP_CHAR)
02088 #endif
02089      && (path[1+ src] != '/'))
02090     {
02091       canonical[dest++] = '/';
02092     }
02093       }
02094 
02095     /* Add an end-of-string marker at the end.  */
02096     canonical[dest] = LT_EOS_CHAR;
02097   }
02098 
02099   /* Assign new value.  */
02100   *pcanonical = canonical;
02101 
02102   return 0;
02103 }
02104 
02105 static int
02106 argzize_path (path, pargz, pargz_len)
02107      const char *path;
02108      char **pargz;
02109      size_t *pargz_len;
02110 {
02111   error_t error;
02112 
02113   assert (path);
02114   assert (pargz);
02115   assert (pargz_len);
02116 
02117   if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len)))
02118     {
02119       switch (error)
02120   {
02121   case ENOMEM:
02122     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
02123     break;
02124   default:
02125     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
02126     break;
02127   }
02128 
02129       return 1;
02130     }
02131 
02132   return 0;
02133 }
02134 
02135 /* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element
02136    of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns
02137    non-zero or all elements are exhausted.  If BASE_NAME is non-NULL,
02138    it is appended to each SEARCH_PATH element before FUNC is called.  */
02139 static int
02140 foreach_dirinpath (search_path, base_name, func, data1, data2)
02141      const char *search_path;
02142      const char *base_name;
02143      foreach_callback_func *func;
02144      lt_ptr data1;
02145      lt_ptr data2;
02146 {
02147   int  result   = 0;
02148   int  filenamesize = 0;
02149   int  lenbase  = LT_STRLEN (base_name);
02150   size_t argz_len = 0;
02151   char * argz   = 0;
02152   char * filename = 0;
02153   char * canonical  = 0;
02154 
02155   LT_DLMUTEX_LOCK ();
02156 
02157   if (!search_path || !*search_path)
02158     {
02159       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
02160       goto cleanup;
02161     }
02162 
02163   if (canonicalize_path (search_path, &canonical) != 0)
02164     goto cleanup;
02165 
02166   if (argzize_path (canonical, &argz, &argz_len) != 0)
02167     goto cleanup;
02168 
02169   {
02170     char *dir_name = 0;
02171     while ((dir_name = argz_next (argz, argz_len, dir_name)))
02172       {
02173   int lendir = LT_STRLEN (dir_name);
02174 
02175   if (lendir +1 +lenbase >= filenamesize)
02176   {
02177     LT_DLFREE (filename);
02178     filenamesize  = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */
02179     filename  = LT_EMALLOC (char, filenamesize);
02180     if (!filename)
02181       goto cleanup;
02182   }
02183 
02184   strncpy (filename, dir_name, lendir);
02185   if (base_name && *base_name)
02186     {
02187       if (filename[lendir -1] != '/')
02188         filename[lendir++] = '/';
02189       strcpy (filename +lendir, base_name);
02190     }
02191 
02192   if ((result = (*func) (filename, data1, data2)))
02193     {
02194       break;
02195     }
02196       }
02197   }
02198 
02199  cleanup:
02200   LT_DLFREE (argz);
02201   LT_DLFREE (canonical);
02202   LT_DLFREE (filename);
02203 
02204   LT_DLMUTEX_UNLOCK ();
02205 
02206   return result;
02207 }
02208 
02209 /* If FILEPATH can be opened, store the name of the directory component
02210    in DATA1, and the opened FILE* structure address in DATA2.  Otherwise
02211    DATA1 is unchanged, but DATA2 is set to a pointer to NULL.  */
02212 static int
02213 find_file_callback (filename, data1, data2)
02214      char *filename;
02215      lt_ptr data1;
02216      lt_ptr data2;
02217 {
02218   char       **pdir = (char **) data1;
02219   FILE       **pfile  = (FILE **) data2;
02220   int      is_done  = 0;
02221 
02222   assert (filename && *filename);
02223   assert (pdir);
02224   assert (pfile);
02225 
02226   if ((*pfile = fopen (filename, LT_READTEXT_MODE)))
02227     {
02228       char *dirend = strrchr (filename, '/');
02229 
02230       if (dirend > filename)
02231   *dirend   = LT_EOS_CHAR;
02232 
02233       LT_DLFREE (*pdir);
02234       *pdir   = lt_estrdup (filename);
02235       is_done = (*pdir == 0) ? -1 : 1;
02236     }
02237 
02238   return is_done;
02239 }
02240 
02241 static FILE *
02242 find_file (search_path, base_name, pdir)
02243      const char *search_path;
02244      const char *base_name;
02245      char **pdir;
02246 {
02247   FILE *file = 0;
02248 
02249   foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file);
02250 
02251   return file;
02252 }
02253 
02254 static int
02255 find_handle_callback (filename, data, ignored)
02256      char *filename;
02257      lt_ptr data;
02258      lt_ptr ignored;
02259 {
02260   lt_dlhandle  *handle  = (lt_dlhandle *) data;
02261   int   found = access (filename, R_OK);
02262 
02263   /* Bail out if file cannot be read...  */
02264   if (!found)
02265     return 0;
02266 
02267   /* Try to dlopen the file, but do not continue searching in any
02268      case.  */
02269   if (tryall_dlopen (handle, filename) != 0)
02270     *handle = 0;
02271 
02272   return 1;
02273 }
02274 
02275 /* If HANDLE was found return it, otherwise return 0.  If HANDLE was
02276    found but could not be opened, *HANDLE will be set to 0.  */
02277 static lt_dlhandle *
02278 find_handle (search_path, base_name, handle)
02279      const char *search_path;
02280      const char *base_name;
02281      lt_dlhandle *handle;
02282 {
02283   if (!search_path)
02284     return 0;
02285 
02286   if (!foreach_dirinpath (search_path, base_name, find_handle_callback,
02287         handle, 0))
02288     return 0;
02289 
02290   return handle;
02291 }
02292 
02293 static int
02294 load_deplibs (handle, deplibs)
02295      lt_dlhandle handle;
02296      char *deplibs;
02297 {
02298 #if LTDL_DLOPEN_DEPLIBS
02299   char  *p, *save_search_path = 0;
02300   int   depcount = 0;
02301   int i;
02302   char  **names = 0;
02303 #endif
02304   int errors = 0;
02305 
02306   handle->depcount = 0;
02307 
02308 #if LTDL_DLOPEN_DEPLIBS
02309   if (!deplibs)
02310     {
02311       return errors;
02312     }
02313   ++errors;
02314 
02315   LT_DLMUTEX_LOCK ();
02316   if (user_search_path)
02317     {
02318       save_search_path = lt_estrdup (user_search_path);
02319       if (!save_search_path)
02320   goto cleanup;
02321     }
02322 
02323   /* extract search paths and count deplibs */
02324   p = deplibs;
02325   while (*p)
02326     {
02327       if (!isspace ((int) *p))
02328   {
02329     char *end = p+1;
02330     while (*end && !isspace((int) *end))
02331       {
02332         ++end;
02333       }
02334 
02335     if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0)
02336       {
02337         char save = *end;
02338         *end = 0; /* set a temporary string terminator */
02339         if (lt_dladdsearchdir(p+2))
02340     {
02341       goto cleanup;
02342     }
02343         *end = save;
02344       }
02345     else
02346       {
02347         ++depcount;
02348       }
02349 
02350     p = end;
02351   }
02352       else
02353   {
02354     ++p;
02355   }
02356     }
02357 
02358   /* restore the old search path */
02359   LT_DLFREE (user_search_path);
02360   user_search_path = save_search_path;
02361 
02362   LT_DLMUTEX_UNLOCK ();
02363 
02364   if (!depcount)
02365     {
02366       errors = 0;
02367       goto cleanup;
02368     }
02369 
02370   names = LT_EMALLOC (char *, depcount * sizeof (char*));
02371   if (!names)
02372     goto cleanup;
02373 
02374   /* now only extract the actual deplibs */
02375   depcount = 0;
02376   p = deplibs;
02377   while (*p)
02378     {
02379       if (isspace ((int) *p))
02380   {
02381     ++p;
02382   }
02383       else
02384   {
02385     char *end = p+1;
02386     while (*end && !isspace ((int) *end))
02387       {
02388         ++end;
02389       }
02390 
02391     if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0)
02392       {
02393         char *name;
02394         char save = *end;
02395         *end = 0; /* set a temporary string terminator */
02396         if (strncmp(p, "-l", 2) == 0)
02397     {
02398       size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2);
02399       name = LT_EMALLOC (char, 1+ name_len);
02400       if (name)
02401         sprintf (name, "lib%s", p+2);
02402     }
02403         else
02404     name = lt_estrdup(p);
02405 
02406         if (!name)
02407     goto cleanup_names;
02408 
02409         names[depcount++] = name;
02410         *end = save;
02411       }
02412     p = end;
02413   }
02414     }
02415 
02416   /* load the deplibs (in reverse order)
02417      At this stage, don't worry if the deplibs do not load correctly,
02418      they may already be statically linked into the loading application
02419      for instance.  There will be a more enlightening error message
02420      later on if the loaded module cannot resolve all of its symbols.  */
02421   if (depcount)
02422     {
02423       int j = 0;
02424 
02425       handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount);
02426       if (!handle->deplibs)
02427   goto cleanup;
02428 
02429       for (i = 0; i < depcount; ++i)
02430   {
02431     handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]);
02432     if (handle->deplibs[j])
02433       {
02434         ++j;
02435       }
02436   }
02437 
02438       handle->depcount  = j;  /* Number of successfully loaded deplibs */
02439       errors    = 0;
02440     }
02441 
02442  cleanup_names:
02443   for (i = 0; i < depcount; ++i)
02444     {
02445       LT_DLFREE (names[i]);
02446     }
02447 
02448  cleanup:
02449   LT_DLFREE (names);
02450 #endif
02451 
02452   return errors;
02453 }
02454 
02455 static int
02456 unload_deplibs (handle)
02457      lt_dlhandle handle;
02458 {
02459   int i;
02460   int errors = 0;
02461 
02462   if (handle->depcount)
02463     {
02464       for (i = 0; i < handle->depcount; ++i)
02465   {
02466     if (!LT_DLIS_RESIDENT (handle->deplibs[i]))
02467       {
02468         errors += lt_dlclose (handle->deplibs[i]);
02469       }
02470   }
02471     }
02472 
02473   return errors;
02474 }
02475 
02476 static int
02477 trim (dest, str)
02478      char **dest;
02479      const char *str;
02480 {
02481   /* remove the leading and trailing "'" from str
02482      and store the result in dest */
02483   const char *end   = strrchr (str, '\'');
02484   int len     = LT_STRLEN (str);
02485   char *tmp;
02486 
02487   LT_DLFREE (*dest);
02488 
02489   if (len > 3 && str[0] == '\'')
02490     {
02491       tmp = LT_EMALLOC (char, end - str);
02492       if (!tmp)
02493   return 1;
02494 
02495       strncpy(tmp, &str[1], (end - str) - 1);
02496       tmp[len-3] = LT_EOS_CHAR;
02497       *dest = tmp;
02498     }
02499   else
02500     {
02501       *dest = 0;
02502     }
02503 
02504   return 0;
02505 }
02506 
02507 static int
02508 free_vars (dlname, oldname, libdir, deplibs)
02509      char *dlname;
02510      char *oldname;
02511      char *libdir;
02512      char *deplibs;
02513 {
02514   LT_DLFREE (dlname);
02515   LT_DLFREE (oldname);
02516   LT_DLFREE (libdir);
02517   LT_DLFREE (deplibs);
02518 
02519   return 0;
02520 }
02521 
02522 int
02523 try_dlopen (phandle, filename)
02524      lt_dlhandle *phandle;
02525      const char *filename;
02526 {
02527   const char *  ext   = 0;
02528   const char *  saved_error = 0;
02529   char *  canonical = 0;
02530   char *  base_name = 0;
02531   char *  dir   = 0;
02532   char *  name    = 0;
02533   int   errors    = 0;
02534   lt_dlhandle newhandle;
02535 
02536   assert (phandle);
02537   assert (*phandle == 0);
02538 
02539   LT_DLMUTEX_GETERROR (saved_error);
02540 
02541   /* dlopen self? */
02542   if (!filename)
02543     {
02544       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
02545       if (*phandle == 0)
02546   return 1;
02547 
02548       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
02549       newhandle = *phandle;
02550 
02551       /* lt_dlclose()ing yourself is very bad!  Disallow it.  */
02552       LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG);
02553 
02554       if (tryall_dlopen (&newhandle, 0) != 0)
02555   {
02556     LT_DLFREE (*phandle);
02557     return 1;
02558   }
02559 
02560       goto register_handle;
02561     }
02562 
02563   assert (filename && *filename);
02564 
02565   /* Doing this immediately allows internal functions to safely
02566      assume only canonicalized paths are passed.  */
02567   if (canonicalize_path (filename, &canonical) != 0)
02568     {
02569       ++errors;
02570       goto cleanup;
02571     }
02572 
02573   /* If the canonical module name is a path (relative or absolute)
02574      then split it into a directory part and a name part.  */
02575   base_name = strrchr (canonical, '/');
02576   if (base_name)
02577     {
02578       size_t dirlen = (1+ base_name) - canonical;
02579 
02580       dir = LT_EMALLOC (char, 1+ dirlen);
02581       if (!dir)
02582   {
02583     ++errors;
02584     goto cleanup;
02585   }
02586 
02587       strncpy (dir, canonical, dirlen);
02588       dir[dirlen] = LT_EOS_CHAR;
02589 
02590       ++base_name;
02591     }
02592   else
02593     LT_DLMEM_REASSIGN (base_name, canonical);
02594 
02595   assert (base_name && *base_name);
02596 
02597   /* Check whether we are opening a libtool module (.la extension).  */
02598   ext = strrchr (base_name, '.');
02599   if (ext && strcmp (ext, archive_ext) == 0)
02600     {
02601       /* this seems to be a libtool module */
02602       FILE *  file   = 0;
02603       char *  dlname   = 0;
02604       char *  old_name = 0;
02605       char *  libdir   = 0;
02606       char *  deplibs  = 0;
02607       char *    line   = 0;
02608       size_t  line_len;
02609       int i;
02610 
02611       /* if we can't find the installed flag, it is probably an
02612    installed libtool archive, produced with an old version
02613    of libtool */
02614       int installed = 1;
02615 
02616       /* extract the module name from the file name */
02617       name = LT_EMALLOC (char, ext - base_name + 1);
02618       if (!name)
02619   {
02620     ++errors;
02621     goto cleanup;
02622   }
02623 
02624       /* canonicalize the module name */
02625       for (i = 0; i < ext - base_name; ++i)
02626   {
02627     if (isalnum ((int)(base_name[i])))
02628       {
02629         name[i] = base_name[i];
02630       }
02631     else
02632       {
02633         name[i] = '_';
02634       }
02635   }
02636       name[ext - base_name] = LT_EOS_CHAR;
02637 
02638     /* Now try to open the .la file.  If there is no directory name
02639        component, try to find it first in user_search_path and then other
02640        prescribed paths.  Otherwise (or in any case if the module was not
02641        yet found) try opening just the module name as passed.  */
02642       if (!dir)
02643   {
02644     const char *search_path;
02645 
02646     LT_DLMUTEX_LOCK ();
02647     search_path = user_search_path;
02648     if (search_path)
02649       file = find_file (user_search_path, base_name, &dir);
02650     LT_DLMUTEX_UNLOCK ();
02651 
02652     if (!file)
02653       {
02654         search_path = getenv (LTDL_SEARCHPATH_VAR);
02655         if (search_path)
02656     file = find_file (search_path, base_name, &dir);
02657       }
02658 
02659 #ifdef LTDL_SHLIBPATH_VAR
02660     if (!file)
02661       {
02662         search_path = getenv (LTDL_SHLIBPATH_VAR);
02663         if (search_path)
02664     file = find_file (search_path, base_name, &dir);
02665       }
02666 #endif
02667 #ifdef LTDL_SYSSEARCHPATH
02668     if (!file && sys_search_path)
02669       {
02670         file = find_file (sys_search_path, base_name, &dir);
02671       }
02672 #endif
02673   }
02674       if (!file)
02675   {
02676     file = fopen (filename, LT_READTEXT_MODE);
02677   }
02678 
02679       /* If we didn't find the file by now, it really isn't there.  Set
02680    the status flag, and bail out.  */
02681       if (!file)
02682   {
02683     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
02684     ++errors;
02685     goto cleanup;
02686   }
02687 
02688       line_len = LT_FILENAME_MAX;
02689       line = LT_EMALLOC (char, line_len);
02690       if (!line)
02691   {
02692     fclose (file);
02693     ++errors;
02694     goto cleanup;
02695   }
02696 
02697       /* read the .la file */
02698       while (!feof (file))
02699   {
02700     if (!fgets (line, line_len, file))
02701       {
02702         break;
02703       }
02704 
02705     /* Handle the case where we occasionally need to read a line
02706        that is longer than the initial buffer size.  */
02707     while (line[LT_STRLEN(line) -1] != '\n')
02708       {
02709         line = LT_DLREALLOC (char, line, line_len *2);
02710         if (!fgets (&line[line_len -1], line_len +1, file))
02711     {
02712       break;
02713     }
02714         line_len *= 2;
02715       }
02716 
02717     if (line[0] == '\n' || line[0] == '#')
02718       {
02719         continue;
02720       }
02721 
02722 #undef  STR_DLNAME
02723 #define STR_DLNAME  "dlname="
02724     if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0)
02725       {
02726         errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]);
02727       }
02728 
02729 #undef  STR_OLD_LIBRARY
02730 #define STR_OLD_LIBRARY "old_library="
02731     else if (strncmp (line, STR_OLD_LIBRARY,
02732           sizeof (STR_OLD_LIBRARY) - 1) == 0)
02733       {
02734         errors += trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]);
02735       }
02736 #undef  STR_LIBDIR
02737 #define STR_LIBDIR  "libdir="
02738     else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0)
02739       {
02740         errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]);
02741       }
02742 
02743 #undef  STR_DL_DEPLIBS
02744 #define STR_DL_DEPLIBS  "dependency_libs="
02745     else if (strncmp (line, STR_DL_DEPLIBS,
02746           sizeof (STR_DL_DEPLIBS) - 1) == 0)
02747       {
02748         errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]);
02749       }
02750     else if (strcmp (line, "installed=yes\n") == 0)
02751       {
02752         installed = 1;
02753       }
02754     else if (strcmp (line, "installed=no\n") == 0)
02755       {
02756         installed = 0;
02757       }
02758 
02759 #undef  STR_LIBRARY_NAMES
02760 #define STR_LIBRARY_NAMES "library_names="
02761     else if (! dlname && strncmp (line, STR_LIBRARY_NAMES,
02762           sizeof (STR_LIBRARY_NAMES) - 1) == 0)
02763       {
02764         char *last_libname;
02765         errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]);
02766         if (!errors
02767       && dlname
02768       && (last_libname = strrchr (dlname, ' ')) != 0)
02769     {
02770       last_libname = lt_estrdup (last_libname + 1);
02771       if (!last_libname)
02772         {
02773           ++errors;
02774           goto cleanup;
02775         }
02776       LT_DLMEM_REASSIGN (dlname, last_libname);
02777     }
02778       }
02779 
02780     if (errors)
02781       break;
02782   }
02783 
02784       fclose (file);
02785       LT_DLFREE (line);
02786 
02787       /* allocate the handle */
02788       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
02789       if (*phandle == 0)
02790   ++errors;
02791 
02792       if (errors)
02793   {
02794     free_vars (dlname, old_name, libdir, deplibs);
02795     LT_DLFREE (*phandle);
02796     goto cleanup;
02797   }
02798 
02799       assert (*phandle);
02800 
02801       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
02802       if (load_deplibs (*phandle, deplibs) == 0)
02803   {
02804     newhandle = *phandle;
02805     /* find_module may replace newhandle */
02806     if (find_module (&newhandle, dir, libdir, dlname, old_name, installed))
02807       {
02808         unload_deplibs (*phandle);
02809         ++errors;
02810       }
02811   }
02812       else
02813   {
02814     ++errors;
02815   }
02816 
02817       free_vars (dlname, old_name, libdir, deplibs);
02818       if (errors)
02819   {
02820     LT_DLFREE (*phandle);
02821     goto cleanup;
02822   }
02823 
02824       if (*phandle != newhandle)
02825   {
02826     unload_deplibs (*phandle);
02827   }
02828     }
02829   else
02830     {
02831       /* not a libtool module */
02832       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
02833       if (*phandle == 0)
02834   {
02835     ++errors;
02836     goto cleanup;
02837   }
02838 
02839       memset (*phandle, 0, sizeof (struct lt_dlhandle_struct));
02840       newhandle = *phandle;
02841 
02842       /* If the module has no directory name component, try to find it
02843    first in user_search_path and then other prescribed paths.
02844    Otherwise (or in any case if the module was not yet found) try
02845    opening just the module name as passed.  */
02846       if ((dir || (!find_handle (user_search_path, base_name, &newhandle)
02847        && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name,
02848             &newhandle)
02849 #ifdef LTDL_SHLIBPATH_VAR
02850        && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name,
02851             &newhandle)
02852 #endif
02853 #ifdef LTDL_SYSSEARCHPATH
02854        && !find_handle (sys_search_path, base_name, &newhandle)
02855 #endif
02856        )))
02857   {
02858     if (0 != tryall_dlopen (&newhandle, filename))
02859       newhandle = 0;
02860   }
02861 
02862       if (!newhandle)
02863   {
02864     LT_DLFREE (*phandle);
02865     ++errors;
02866     goto cleanup;
02867   }
02868     }
02869 
02870  register_handle:
02871   LT_DLMEM_REASSIGN (*phandle, newhandle);
02872 
02873   if ((*phandle)->info.ref_count == 0)
02874     {
02875       (*phandle)->info.ref_count  = 1;
02876       LT_DLMEM_REASSIGN ((*phandle)->info.name, name);
02877 
02878       LT_DLMUTEX_LOCK ();
02879       (*phandle)->next    = handles;
02880       handles     = *phandle;
02881       LT_DLMUTEX_UNLOCK ();
02882     }
02883 
02884   LT_DLMUTEX_SETERROR (saved_error);
02885 
02886  cleanup:
02887   LT_DLFREE (dir);
02888   LT_DLFREE (name);
02889   LT_DLFREE (canonical);
02890 
02891   return errors;
02892 }
02893 
02894 lt_dlhandle
02895 lt_dlopen (filename)
02896      const char *filename;
02897 {
02898   lt_dlhandle handle = 0;
02899 
02900   /* Just incase we missed a code path in try_dlopen() that reports
02901      an error, but forgets to reset handle... */
02902   if (try_dlopen (&handle, filename) != 0)
02903     return 0;
02904 
02905   return handle;
02906 }
02907 
02908 /* If the last error messge store was `FILE_NOT_FOUND', then return
02909    non-zero.  */
02910 int
02911 file_not_found ()
02912 {
02913   const char *error = 0;
02914 
02915   LT_DLMUTEX_GETERROR (error);
02916   if (error == LT_DLSTRERROR (FILE_NOT_FOUND))
02917     return 1;
02918 
02919   return 0;
02920 }
02921 
02922 /* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to
02923    open the FILENAME as passed.  Otherwise try appending ARCHIVE_EXT,
02924    and if a file is still not found try again with SHLIB_EXT appended
02925    instead.  */
02926 lt_dlhandle
02927 lt_dlopenext (filename)
02928      const char *filename;
02929 {
02930   lt_dlhandle handle    = 0;
02931   char *  tmp   = 0;
02932   char *  ext   = 0;
02933   int   len;
02934   int   errors    = 0;
02935   int   file_found  = 1; /* until proven otherwise */
02936 
02937   if (!filename)
02938     {
02939       return lt_dlopen (filename);
02940     }
02941 
02942   assert (filename);
02943 
02944   len = LT_STRLEN (filename);
02945   ext = strrchr (filename, '.');
02946 
02947   /* If FILENAME already bears a suitable extension, there is no need
02948      to try appending additional extensions.  */
02949   if (ext && ((strcmp (ext, archive_ext) == 0)
02950 #ifdef LTDL_SHLIB_EXT
02951         || (strcmp (ext, shlib_ext) == 0)
02952 #endif
02953       ))
02954     {
02955       return lt_dlopen (filename);
02956     }
02957 
02958   /* First try appending ARCHIVE_EXT.  */
02959   tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1);
02960   if (!tmp)
02961     return 0;
02962 
02963   strcpy (tmp, filename);
02964   strcat (tmp, archive_ext);
02965   errors = try_dlopen (&handle, tmp);
02966 
02967   /* If we found FILENAME, stop searching -- whether we were able to
02968      load the file as a module or not.  If the file exists but loading
02969      failed, it is better to return an error message here than to
02970      report FILE_NOT_FOUND when the alternatives (foo.so etc) are not
02971      in the module search path.  */
02972   if (handle || ((errors > 0) && file_not_found ()))
02973     {
02974       LT_DLFREE (tmp);
02975       return handle;
02976     }
02977 
02978 #ifdef LTDL_SHLIB_EXT
02979   /* Try appending SHLIB_EXT.   */
02980   if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext))
02981     {
02982       LT_DLFREE (tmp);
02983       tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1);
02984       if (!tmp)
02985   return 0;
02986 
02987       strcpy (tmp, filename);
02988     }
02989   else
02990     {
02991       tmp[len] = LT_EOS_CHAR;
02992     }
02993 
02994   strcat(tmp, shlib_ext);
02995   errors = try_dlopen (&handle, tmp);
02996 
02997   /* As before, if the file was found but loading failed, return now
02998      with the current error message.  */
02999   if (handle || ((errors > 0) && file_not_found ()))
03000     {
03001       LT_DLFREE (tmp);
03002       return handle;
03003     }
03004 #endif
03005 
03006   /* Still here?  Then we really did fail to locate any of the file
03007      names we tried.  */
03008   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
03009   LT_DLFREE (tmp);
03010   return 0;
03011 }
03012 
03013 
03014 int
03015 lt_argz_insert (pargz, pargz_len, before, entry)
03016      char **pargz;
03017      size_t *pargz_len;
03018      char *before;
03019      const char *entry;
03020 {
03021   error_t error;
03022 
03023   if ((error = argz_insert (pargz, pargz_len, before, entry)))
03024     {
03025       switch (error)
03026   {
03027   case ENOMEM:
03028     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
03029     break;
03030   default:
03031     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
03032     break;
03033   }
03034       return 1;
03035     }
03036 
03037   return 0;
03038 }
03039 
03040 int
03041 lt_argz_insertinorder (pargz, pargz_len, entry)
03042      char **pargz;
03043      size_t *pargz_len;
03044      const char *entry;
03045 {
03046   char *before = 0;
03047 
03048   assert (pargz);
03049   assert (pargz_len);
03050   assert (entry && *entry);
03051 
03052   if (*pargz)
03053     while ((before = argz_next (*pargz, *pargz_len, before)))
03054       {
03055   int cmp = strcmp (entry, before);
03056 
03057   if (cmp < 0)  break;
03058   if (cmp == 0) return 0; /* No duplicates! */
03059       }
03060 
03061   return lt_argz_insert (pargz, pargz_len, before, entry);
03062 }
03063 
03064 int
03065 lt_argz_insertdir (pargz, pargz_len, dirnam, dp)
03066      char **pargz;
03067      size_t *pargz_len;
03068      const char *dirnam;
03069      struct dirent *dp;
03070 {
03071   char   *buf     = 0;
03072   size_t buf_len    = 0;
03073   char   *end     = 0;
03074   size_t end_offset = 0;
03075   size_t dir_len    = 0;
03076   int    errors     = 0;
03077 
03078   assert (pargz);
03079   assert (pargz_len);
03080   assert (dp);
03081 
03082   dir_len = LT_STRLEN (dirnam);
03083   end     = dp->d_name + LT_D_NAMLEN(dp);
03084 
03085   /* Ignore version numbers.  */
03086   {
03087     char *p;
03088     for (p = end; p -1 > dp->d_name; --p)
03089       if (strchr (".0123456789", p[-1]) == 0)
03090   break;
03091 
03092     if (*p == '.')
03093       end = p;
03094   }
03095 
03096   /* Ignore filename extension.  */
03097   {
03098     char *p;
03099     for (p = end -1; p > dp->d_name; --p)
03100       if (*p == '.')
03101   {
03102     end = p;
03103     break;
03104   }
03105   }
03106 
03107   /* Prepend the directory name.  */
03108   end_offset  = end - dp->d_name;
03109   buf_len = dir_len + 1+ end_offset;
03110   buf   = LT_EMALLOC (char, 1+ buf_len);
03111   if (!buf)
03112     return ++errors;
03113 
03114   assert (buf);
03115 
03116   strcpy  (buf, dirnam);
03117   strcat  (buf, "/");
03118   strncat (buf, dp->d_name, end_offset);
03119   buf[buf_len] = LT_EOS_CHAR;
03120 
03121   /* Try to insert (in order) into ARGZ/ARGZ_LEN.  */
03122   if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0)
03123     ++errors;
03124 
03125   LT_DLFREE (buf);
03126 
03127   return errors;
03128 }
03129 
03130 int
03131 list_files_by_dir (dirnam, pargz, pargz_len)
03132      const char *dirnam;
03133      char **pargz;
03134      size_t *pargz_len;
03135 {
03136   DIR *dirp   = 0;
03137   int    errors   = 0;
03138 
03139   assert (dirnam && *dirnam);
03140   assert (pargz);
03141   assert (pargz_len);
03142   assert (dirnam[LT_STRLEN(dirnam) -1] != '/');
03143 
03144   dirp = opendir (dirnam);
03145   if (dirp)
03146     {
03147       struct dirent *dp = 0;
03148 
03149       while ((dp = readdir (dirp)))
03150   if (dp->d_name[0] != '.')
03151     if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp))
03152       {
03153         ++errors;
03154         break;
03155       }
03156 
03157       closedir (dirp);
03158     }
03159   else
03160     ++errors;
03161 
03162   return errors;
03163 }
03164 
03165 
03166 /* If there are any files in DIRNAME, call the function passed in
03167    DATA1 (with the name of each file and DATA2 as arguments).  */
03168 static int
03169 foreachfile_callback (dirname, data1, data2)
03170      char *dirname;
03171      lt_ptr data1;
03172      lt_ptr data2;
03173 {
03174   int (*func) LT_PARAMS((const char *filename, lt_ptr data))
03175   = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1;
03176 
03177   int   is_done  = 0;
03178   char   *argz     = 0;
03179   size_t  argz_len = 0;
03180 
03181   if (list_files_by_dir (dirname, &argz, &argz_len) != 0)
03182     goto cleanup;
03183   if (!argz)
03184     goto cleanup;
03185 
03186   {
03187     char *filename = 0;
03188     while ((filename = argz_next (argz, argz_len, filename)))
03189       if ((is_done = (*func) (filename, data2)))
03190   break;
03191   }
03192 
03193  cleanup:
03194   LT_DLFREE (argz);
03195 
03196   return is_done;
03197 }
03198 
03199 
03200 /* Call FUNC for each unique extensionless file in SEARCH_PATH, along
03201    with DATA.  The filenames passed to FUNC would be suitable for
03202    passing to lt_dlopenext.  The extensions are stripped so that
03203    individual modules do not generate several entries (e.g. libfoo.la,
03204    libfoo.so, libfoo.so.1, libfoo.so.1.0.0).  If SEARCH_PATH is NULL,
03205    then the same directories that lt_dlopen would search are examined.  */
03206 int
03207 lt_dlforeachfile (search_path, func, data)
03208      const char *search_path;
03209      int (*func) LT_PARAMS ((const char *filename, lt_ptr data));
03210      lt_ptr data;
03211 {
03212   int is_done = 0;
03213 
03214   if (search_path)
03215     {
03216       /* If a specific path was passed, search only the directories
03217    listed in it.  */
03218       is_done = foreach_dirinpath (search_path, 0,
03219            foreachfile_callback, func, data);
03220     }
03221   else
03222     {
03223       /* Otherwise search the default paths.  */
03224       is_done = foreach_dirinpath (user_search_path, 0,
03225            foreachfile_callback, func, data);
03226       if (!is_done)
03227   {
03228     is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0,
03229                foreachfile_callback, func, data);
03230   }
03231 
03232 #ifdef LTDL_SHLIBPATH_VAR
03233       if (!is_done)
03234   {
03235     is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0,
03236                foreachfile_callback, func, data);
03237   }
03238 #endif
03239 #ifdef LTDL_SYSSEARCHPATH
03240       if (!is_done)
03241   {
03242     is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0,
03243                foreachfile_callback, func, data);
03244   }
03245 #endif
03246     }
03247 
03248   return is_done;
03249 }
03250 
03251 int
03252 lt_dlclose (handle)
03253      lt_dlhandle handle;
03254 {
03255   lt_dlhandle cur, last;
03256   int errors = 0;
03257 
03258   LT_DLMUTEX_LOCK ();
03259 
03260   /* check whether the handle is valid */
03261   last = cur = handles;
03262   while (cur && handle != cur)
03263     {
03264       last = cur;
03265       cur = cur->next;
03266     }
03267 
03268   if (!cur)
03269     {
03270       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
03271       ++errors;
03272       goto done;
03273     }
03274 
03275   handle->info.ref_count--;
03276 
03277   /* Note that even with resident modules, we must track the ref_count
03278      correctly incase the user decides to reset the residency flag
03279      later (even though the API makes no provision for that at the
03280      moment).  */
03281   if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle))
03282     {
03283       lt_user_data data = handle->loader->dlloader_data;
03284 
03285       if (handle != handles)
03286   {
03287     last->next = handle->next;
03288   }
03289       else
03290   {
03291     handles = handle->next;
03292   }
03293 
03294       errors += handle->loader->module_close (data, handle->module);
03295       errors += unload_deplibs(handle);
03296 
03297       LT_DLFREE (handle->info.filename);
03298       LT_DLFREE (handle->info.name);
03299       LT_DLFREE (handle);
03300 
03301       goto done;
03302     }
03303 
03304   if (LT_DLIS_RESIDENT (handle))
03305     {
03306       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE));
03307       ++errors;
03308     }
03309 
03310  done:
03311   LT_DLMUTEX_UNLOCK ();
03312 
03313   return errors;
03314 }
03315 
03316 lt_ptr
03317 lt_dlsym (handle, symbol)
03318      lt_dlhandle handle;
03319      const char *symbol;
03320 {
03321   int lensym;
03322   char  lsym[LT_SYMBOL_LENGTH];
03323   char  *sym;
03324   lt_ptr address;
03325   lt_user_data data;
03326 
03327   if (!handle)
03328     {
03329       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
03330       return 0;
03331     }
03332 
03333   if (!symbol)
03334     {
03335       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
03336       return 0;
03337     }
03338 
03339   lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix)
03340           + LT_STRLEN (handle->info.name);
03341 
03342   if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH)
03343     {
03344       sym = lsym;
03345     }
03346   else
03347     {
03348       sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1);
03349       if (!sym)
03350   {
03351     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW));
03352     return 0;
03353   }
03354     }
03355 
03356   data = handle->loader->dlloader_data;
03357   if (handle->info.name)
03358     {
03359       const char *saved_error;
03360 
03361       LT_DLMUTEX_GETERROR (saved_error);
03362 
03363       /* this is a libtool module */
03364       if (handle->loader->sym_prefix)
03365   {
03366     strcpy(sym, handle->loader->sym_prefix);
03367     strcat(sym, handle->info.name);
03368   }
03369       else
03370   {
03371     strcpy(sym, handle->info.name);
03372   }
03373 
03374       strcat(sym, "_LTX_");
03375       strcat(sym, symbol);
03376 
03377       /* try "modulename_LTX_symbol" */
03378       address = handle->loader->find_sym (data, handle->module, sym);
03379       if (address)
03380   {
03381     if (sym != lsym)
03382       {
03383         LT_DLFREE (sym);
03384       }
03385     return address;
03386   }
03387       LT_DLMUTEX_SETERROR (saved_error);
03388     }
03389 
03390   /* otherwise try "symbol" */
03391   if (handle->loader->sym_prefix)
03392     {
03393       strcpy(sym, handle->loader->sym_prefix);
03394       strcat(sym, symbol);
03395     }
03396   else
03397     {
03398       strcpy(sym, symbol);
03399     }
03400 
03401   address = handle->loader->find_sym (data, handle->module, sym);
03402   if (sym != lsym)
03403     {
03404       LT_DLFREE (sym);
03405     }
03406 
03407   return address;
03408 }
03409 
03410 const char *
03411 lt_dlerror ()
03412 {
03413   const char *error;
03414 
03415   LT_DLMUTEX_GETERROR (error);
03416   LT_DLMUTEX_SETERROR (0);
03417 
03418   return error ? error : LT_DLSTRERROR (UNKNOWN);
03419 }
03420 
03421 int
03422 lt_dlpath_insertdir (ppath, before, dir)
03423      char **ppath;
03424      char *before;
03425      const char *dir;
03426 {
03427   int    errors   = 0;
03428   char  *canonical  = 0;
03429   char  *argz   = 0;
03430   size_t argz_len = 0;
03431 
03432   assert (ppath);
03433   assert (dir && *dir);
03434 
03435   if (canonicalize_path (dir, &canonical) != 0)
03436     {
03437       ++errors;
03438       goto cleanup;
03439     }
03440 
03441   assert (canonical && *canonical);
03442 
03443   /* If *PPATH is empty, set it to DIR.  */
03444   if (*ppath == 0)
03445     {
03446       assert (!before);   /* BEFORE cannot be set without PPATH.  */
03447       assert (dir);   /* Without DIR, don't call this function!  */
03448 
03449       *ppath = lt_estrdup (dir);
03450       if (*ppath == 0)
03451   ++errors;
03452 
03453       return errors;
03454     }
03455 
03456   assert (ppath && *ppath);
03457 
03458   if (argzize_path (*ppath, &argz, &argz_len) != 0)
03459     {
03460       ++errors;
03461       goto cleanup;
03462     }
03463 
03464   /* Convert BEFORE into an equivalent offset into ARGZ.  This only works
03465      if *PPATH is already canonicalized, and hence does not change length
03466      with respect to ARGZ.  We canonicalize each entry as it is added to
03467      the search path, and don't call this function with (uncanonicalized)
03468      user paths, so this is a fair assumption.  */
03469   if (before)
03470     {
03471       assert (*ppath <= before);
03472       assert (before - *ppath <= strlen (*ppath));
03473 
03474       before = before - *ppath + argz;
03475     }
03476 
03477   if (lt_argz_insert (&argz, &argz_len, before, dir) != 0)
03478     {
03479       ++errors;
03480       goto cleanup;
03481     }
03482 
03483   argz_stringify (argz, argz_len, LT_PATHSEP_CHAR);
03484   LT_DLMEM_REASSIGN (*ppath,  argz);
03485 
03486  cleanup:
03487   LT_DLFREE (canonical);
03488   LT_DLFREE (argz);
03489 
03490   return errors;
03491 }
03492 
03493 int
03494 lt_dladdsearchdir (search_dir)
03495      const char *search_dir;
03496 {
03497   int errors = 0;
03498 
03499   if (search_dir && *search_dir)
03500     {
03501       LT_DLMUTEX_LOCK ();
03502       if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)
03503   ++errors;
03504       LT_DLMUTEX_UNLOCK ();
03505     }
03506 
03507   return errors;
03508 }
03509 
03510 int
03511 lt_dlinsertsearchdir (before, search_dir)
03512      const char *before;
03513      const char *search_dir;
03514 {
03515   int errors = 0;
03516 
03517   if (before)
03518     {
03519       LT_DLMUTEX_LOCK ();
03520       if ((before < user_search_path)
03521     || (before >= user_search_path + LT_STRLEN (user_search_path)))
03522   {
03523     LT_DLMUTEX_UNLOCK ();
03524     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION));
03525     return 1;
03526   }
03527       LT_DLMUTEX_UNLOCK ();
03528     }
03529 
03530   if (search_dir && *search_dir)
03531     {
03532       LT_DLMUTEX_LOCK ();
03533       if (lt_dlpath_insertdir (&user_search_path,
03534              (char *) before, search_dir) != 0)
03535   {
03536     ++errors;
03537   }
03538       LT_DLMUTEX_UNLOCK ();
03539     }
03540 
03541   return errors;
03542 }
03543 
03544 int
03545 lt_dlsetsearchpath (search_path)
03546      const char *search_path;
03547 {
03548   int   errors      = 0;
03549 
03550   LT_DLMUTEX_LOCK ();
03551   LT_DLFREE (user_search_path);
03552   LT_DLMUTEX_UNLOCK ();
03553 
03554   if (!search_path || !LT_STRLEN (search_path))
03555     {
03556       return errors;
03557     }
03558 
03559   LT_DLMUTEX_LOCK ();
03560   if (canonicalize_path (search_path, &user_search_path) != 0)
03561     ++errors;
03562   LT_DLMUTEX_UNLOCK ();
03563 
03564   return errors;
03565 }
03566 
03567 const char *
03568 lt_dlgetsearchpath ()
03569 {
03570   const char *saved_path;
03571 
03572   LT_DLMUTEX_LOCK ();
03573   saved_path = user_search_path;
03574   LT_DLMUTEX_UNLOCK ();
03575 
03576   return saved_path;
03577 }
03578 
03579 int
03580 lt_dlmakeresident (handle)
03581      lt_dlhandle handle;
03582 {
03583   int errors = 0;
03584 
03585   if (!handle)
03586     {
03587       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
03588       ++errors;
03589     }
03590   else
03591     {
03592       LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG);
03593     }
03594 
03595   return errors;
03596 }
03597 
03598 int
03599 lt_dlisresident (handle)
03600      lt_dlhandle handle;
03601 {
03602   if (!handle)
03603     {
03604       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
03605       return -1;
03606     }
03607 
03608   return LT_DLIS_RESIDENT (handle);
03609 }
03610 
03611 
03612 
03613 
03614 /* --- MODULE INFORMATION --- */
03615 
03616 const lt_dlinfo *
03617 lt_dlgetinfo (handle)
03618      lt_dlhandle handle;
03619 {
03620   if (!handle)
03621     {
03622       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
03623       return 0;
03624     }
03625 
03626   return &(handle->info);
03627 }
03628 
03629 lt_dlhandle
03630 lt_dlhandle_next (place)
03631      lt_dlhandle place;
03632 {
03633   return place ? place->next : handles;
03634 }
03635 
03636 int
03637 lt_dlforeach (func, data)
03638      int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data));
03639      lt_ptr data;
03640 {
03641   int errors = 0;
03642   lt_dlhandle cur;
03643 
03644   LT_DLMUTEX_LOCK ();
03645 
03646   cur = handles;
03647   while (cur)
03648     {
03649       lt_dlhandle tmp = cur;
03650 
03651       cur = cur->next;
03652       if ((*func) (tmp, data))
03653   {
03654     ++errors;
03655     break;
03656   }
03657     }
03658 
03659   LT_DLMUTEX_UNLOCK ();
03660 
03661   return errors;
03662 }
03663 
03664 lt_dlcaller_id
03665 lt_dlcaller_register ()
03666 {
03667   static lt_dlcaller_id last_caller_id = 0;
03668   int result;
03669 
03670   LT_DLMUTEX_LOCK ();
03671   result = ++last_caller_id;
03672   LT_DLMUTEX_UNLOCK ();
03673 
03674   return result;
03675 }
03676 
03677 lt_ptr
03678 lt_dlcaller_set_data (key, handle, data)
03679      lt_dlcaller_id key;
03680      lt_dlhandle handle;
03681      lt_ptr data;
03682 {
03683   int n_elements = 0;
03684   lt_ptr stale = (lt_ptr) 0;
03685   int i;
03686 
03687   /* This needs to be locked so that the caller data can be updated
03688      simultaneously by different threads.  */
03689   LT_DLMUTEX_LOCK ();
03690 
03691   if (handle->caller_data)
03692     while (handle->caller_data[n_elements].key)
03693       ++n_elements;
03694 
03695   for (i = 0; i < n_elements; ++i)
03696     {
03697       if (handle->caller_data[i].key == key)
03698   {
03699     stale = handle->caller_data[i].data;
03700     break;
03701   }
03702     }
03703 
03704   /* Ensure that there is enough room in this handle's caller_data
03705      array to accept a new element (and an empty end marker).  */
03706   if (i == n_elements)
03707     {
03708       lt_caller_data *temp
03709   = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements);
03710 
03711       if (!temp)
03712   {
03713     stale = 0;
03714     goto done;
03715   }
03716 
03717       handle->caller_data = temp;
03718 
03719       /* We only need this if we needed to allocate a new caller_data.  */
03720       handle->caller_data[i].key  = key;
03721       handle->caller_data[1+ i].key = 0;
03722     }
03723 
03724   handle->caller_data[i].data = data;
03725 
03726  done:
03727   LT_DLMUTEX_UNLOCK ();
03728 
03729   return stale;
03730 }
03731 
03732 lt_ptr
03733 lt_dlcaller_get_data  (key, handle)
03734      lt_dlcaller_id key;
03735      lt_dlhandle handle;
03736 {
03737   lt_ptr result = (lt_ptr) 0;
03738 
03739   /* This needs to be locked so that the caller data isn't updated by
03740      another thread part way through this function.  */
03741   LT_DLMUTEX_LOCK ();
03742 
03743   /* Locate the index of the element with a matching KEY.  */
03744   {
03745     int i;
03746     for (i = 0; handle->caller_data[i].key; ++i)
03747       {
03748   if (handle->caller_data[i].key == key)
03749     {
03750       result = handle->caller_data[i].data;
03751       break;
03752     }
03753       }
03754   }
03755 
03756   LT_DLMUTEX_UNLOCK ();
03757 
03758   return result;
03759 }
03760 
03761 
03762 
03763 /* --- USER MODULE LOADER API --- */
03764 
03765 
03766 int
03767 lt_dlloader_add (place, dlloader, loader_name)
03768      lt_dlloader *place;
03769      const struct lt_user_dlloader *dlloader;
03770      const char *loader_name;
03771 {
03772   int errors = 0;
03773   lt_dlloader *node = 0, *ptr = 0;
03774 
03775   if ((dlloader == 0) /* diagnose null parameters */
03776       || (dlloader->module_open == 0)
03777       || (dlloader->module_close == 0)
03778       || (dlloader->find_sym == 0))
03779     {
03780       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
03781       return 1;
03782     }
03783 
03784   /* Create a new dlloader node with copies of the user callbacks.  */
03785   node = LT_EMALLOC (lt_dlloader, 1);
03786   if (!node)
03787     return 1;
03788 
03789   node->next    = 0;
03790   node->loader_name = loader_name;
03791   node->sym_prefix  = dlloader->sym_prefix;
03792   node->dlloader_exit = dlloader->dlloader_exit;
03793   node->module_open = dlloader->module_open;
03794   node->module_close  = dlloader->module_close;
03795   node->find_sym  = dlloader->find_sym;
03796   node->dlloader_data = dlloader->dlloader_data;
03797 
03798   LT_DLMUTEX_LOCK ();
03799   if (!loaders)
03800     {
03801       /* If there are no loaders, NODE becomes the list! */
03802       loaders = node;
03803     }
03804   else if (!place)
03805     {
03806       /* If PLACE is not set, add NODE to the end of the
03807    LOADERS list. */
03808       for (ptr = loaders; ptr->next; ptr = ptr->next)
03809   {
03810     /*NOWORK*/;
03811   }
03812 
03813       ptr->next = node;
03814     }
03815   else if (loaders == place)
03816     {
03817       /* If PLACE is the first loader, NODE goes first. */
03818       node->next = place;
03819       loaders = node;
03820     }
03821   else
03822     {
03823       /* Find the node immediately preceding PLACE. */
03824       for (ptr = loaders; ptr->next != place; ptr = ptr->next)
03825   {
03826     /*NOWORK*/;
03827   }
03828 
03829       if (ptr->next != place)
03830   {
03831     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
03832     ++errors;
03833   }
03834       else
03835   {
03836     /* Insert NODE between PTR and PLACE. */
03837     node->next = place;
03838     ptr->next  = node;
03839   }
03840     }
03841 
03842   LT_DLMUTEX_UNLOCK ();
03843 
03844   return errors;
03845 }
03846 
03847 int
03848 lt_dlloader_remove (loader_name)
03849      const char *loader_name;
03850 {
03851   lt_dlloader *place = lt_dlloader_find (loader_name);
03852   lt_dlhandle handle;
03853   int errors = 0;
03854 
03855   if (!place)
03856     {
03857       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
03858       return 1;
03859     }
03860 
03861   LT_DLMUTEX_LOCK ();
03862 
03863   /* Fail if there are any open modules which use this loader. */
03864   for  (handle = handles; handle; handle = handle->next)
03865     {
03866       if (handle->loader == place)
03867   {
03868     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER));
03869     ++errors;
03870     goto done;
03871   }
03872     }
03873 
03874   if (place == loaders)
03875     {
03876       /* PLACE is the first loader in the list. */
03877       loaders = loaders->next;
03878     }
03879   else
03880     {
03881       /* Find the loader before the one being removed. */
03882       lt_dlloader *prev;
03883       for (prev = loaders; prev->next; prev = prev->next)
03884   {
03885     if (!strcmp (prev->next->loader_name, loader_name))
03886       {
03887         break;
03888       }
03889   }
03890 
03891       place = prev->next;
03892       prev->next = prev->next->next;
03893     }
03894 
03895   if (place->dlloader_exit)
03896     {
03897       errors = place->dlloader_exit (place->dlloader_data);
03898     }
03899 
03900   LT_DLFREE (place);
03901 
03902  done:
03903   LT_DLMUTEX_UNLOCK ();
03904 
03905   return errors;
03906 }
03907 
03908 lt_dlloader *
03909 lt_dlloader_next (place)
03910      lt_dlloader *place;
03911 {
03912   lt_dlloader *next;
03913 
03914   LT_DLMUTEX_LOCK ();
03915   next = place ? place->next : loaders;
03916   LT_DLMUTEX_UNLOCK ();
03917 
03918   return next;
03919 }
03920 
03921 const char *
03922 lt_dlloader_name (place)
03923      lt_dlloader *place;
03924 {
03925   const char *name = 0;
03926 
03927   if (place)
03928     {
03929       LT_DLMUTEX_LOCK ();
03930       name = place ? place->loader_name : 0;
03931       LT_DLMUTEX_UNLOCK ();
03932     }
03933   else
03934     {
03935       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
03936     }
03937 
03938   return name;
03939 }
03940 
03941 lt_user_data *
03942 lt_dlloader_data (place)
03943      lt_dlloader *place;
03944 {
03945   lt_user_data *data = 0;
03946 
03947   if (place)
03948     {
03949       LT_DLMUTEX_LOCK ();
03950       data = place ? &(place->dlloader_data) : 0;
03951       LT_DLMUTEX_UNLOCK ();
03952     }
03953   else
03954     {
03955       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
03956     }
03957 
03958   return data;
03959 }
03960 
03961 lt_dlloader *
03962 lt_dlloader_find (loader_name)
03963      const char *loader_name;
03964 {
03965   lt_dlloader *place = 0;
03966 
03967   LT_DLMUTEX_LOCK ();
03968   for (place = loaders; place; place = place->next)
03969     {
03970       if (strcmp (place->loader_name, loader_name) == 0)
03971   {
03972     break;
03973   }
03974     }
03975   LT_DLMUTEX_UNLOCK ();
03976 
03977   return place;
03978 }