Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

ltdl.c

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

Generated on Sun Feb 16 23:39:49 2003 for FreeLCD by doxygen1.2.18