OSDN Git Service

libstdc++/13823
[pf3gnuchains/gcc-fork.git] / libjava / libltdl / ltdl.c
1 /* ltdl.c -- system independent dlopen wrapper
2    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3    Originally by Thomas Tanner <tanner@ffii.org>
4    This file is part of GNU Libtool.
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 As a special exception to the GNU Lesser General Public License,
12 if you distribute this file as part of a program or library that
13 is built using GNU libtool, you may include it under the same
14 distribution terms that you use for the rest of that program.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 02111-1307  USA
25
26 */
27
28 #if HAVE_CONFIG_H
29 #  include <config.h>
30 #endif
31
32 #if HAVE_UNISTD_H
33 #  include <unistd.h>
34 #endif
35
36 #if HAVE_STDIO_H
37 #  include <stdio.h>
38 #endif
39
40 #if HAVE_STDLIB_H
41 #  include <stdlib.h>
42 #endif
43
44 #if HAVE_STRING_H
45 #  include <string.h>
46 #else
47 #  if HAVE_STRINGS_H
48 #    include <strings.h>
49 #  endif
50 #endif
51
52 #if HAVE_CTYPE_H
53 #  include <ctype.h>
54 #endif
55
56 #if HAVE_MALLOC_H
57 #  include <malloc.h>
58 #endif
59
60 #if HAVE_MEMORY_H
61 #  include <memory.h>
62 #endif
63
64 #if HAVE_ERRNO_H
65 #  include <errno.h>
66 #endif
67
68 #if HAVE_BOEHM_GC
69 #include <gc.h>
70 #endif
71
72
73 #ifndef __WINDOWS__
74 #  ifdef __WIN32__
75 #    define __WINDOWS__
76 #  endif
77 #endif
78
79
80 #undef LT_USE_POSIX_DIRENT
81 #ifdef HAVE_CLOSEDIR
82 #  ifdef HAVE_OPENDIR
83 #    ifdef HAVE_READDIR
84 #      ifdef HAVE_DIRENT_H
85 #        define LT_USE_POSIX_DIRENT
86 #      endif /* HAVE_DIRENT_H */
87 #    endif /* HAVE_READDIR */
88 #  endif /* HAVE_OPENDIR */
89 #endif /* HAVE_CLOSEDIR */
90
91
92 #undef LT_USE_WINDOWS_DIRENT_EMULATION
93 #ifndef LT_USE_POSIX_DIRENT
94 #  ifdef __WINDOWS__
95 #    define LT_USE_WINDOWS_DIRENT_EMULATION
96 #  endif /* __WINDOWS__ */
97 #endif /* LT_USE_POSIX_DIRENT */
98
99
100 #ifdef LT_USE_POSIX_DIRENT
101 #  include <dirent.h>
102 #  define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name))
103 #else
104 #  ifdef LT_USE_WINDOWS_DIRENT_EMULATION
105 #    define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name))
106 #  else
107 #    define dirent direct
108 #    define LT_D_NAMLEN(dirent) ((dirent)->d_namlen)
109 #    if HAVE_SYS_NDIR_H
110 #      include <sys/ndir.h>
111 #    endif
112 #    if HAVE_SYS_DIR_H
113 #      include <sys/dir.h>
114 #    endif
115 #    if HAVE_NDIR_H
116 #      include <ndir.h>
117 #    endif
118 #  endif
119 #endif
120
121 #if HAVE_ARGZ_H
122 #  include <argz.h>
123 #endif
124
125 #if HAVE_ASSERT_H
126 #  include <assert.h>
127 #else
128 #  define assert(arg)   ((void) 0)
129 #endif
130
131 #include "ltdl.h"
132
133 #if WITH_DMALLOC
134 #  include <dmalloc.h>
135 #endif
136
137
138
139 \f
140 /* --- WINDOWS SUPPORT --- */
141
142
143 #ifdef DLL_EXPORT
144 #  define LT_GLOBAL_DATA        __declspec(dllexport)
145 #else
146 #  define LT_GLOBAL_DATA
147 #endif
148
149 /* fopen() mode flags for reading a text file */
150 #undef  LT_READTEXT_MODE
151 #ifdef __WINDOWS__
152 #  define LT_READTEXT_MODE "rt"
153 #else
154 #  define LT_READTEXT_MODE "r"
155 #endif
156
157 #ifdef LT_USE_WINDOWS_DIRENT_EMULATION
158
159 #include <windows.h>
160
161 #define dirent lt_dirent
162 #define DIR lt_DIR
163
164 struct dirent
165 {
166   char d_name[2048];
167   int  d_namlen;
168 };
169
170 typedef struct _DIR
171 {
172   HANDLE hSearch;
173   WIN32_FIND_DATA Win32FindData;
174   BOOL firsttime;
175   struct dirent file_info;
176 } DIR;
177
178 #endif /* LT_USE_WINDOWS_DIRENT_EMULATION */
179
180 \f
181 /* --- MANIFEST CONSTANTS --- */
182
183
184 /* Standard libltdl search path environment variable name  */
185 #undef  LTDL_SEARCHPATH_VAR
186 #define LTDL_SEARCHPATH_VAR     "LTDL_LIBRARY_PATH"
187
188 /* Standard libtool archive file extension.  */
189 #undef  LTDL_ARCHIVE_EXT
190 #define LTDL_ARCHIVE_EXT        ".la"
191
192 /* max. filename length */
193 #ifndef LT_FILENAME_MAX
194 #  define LT_FILENAME_MAX       1024
195 #endif
196
197 /* This is the maximum symbol size that won't require malloc/free */
198 #undef  LT_SYMBOL_LENGTH
199 #define LT_SYMBOL_LENGTH        128
200
201 /* This accounts for the _LTX_ separator */
202 #undef  LT_SYMBOL_OVERHEAD
203 #define LT_SYMBOL_OVERHEAD      5
204
205
206
207 \f
208 /* --- MEMORY HANDLING --- */
209
210
211 /* These are the functions used internally.  In addition to making
212    use of the associated function pointers above, they also perform
213    error handling.  */
214 static char   *lt_estrdup       LT_PARAMS((const char *str));
215 static lt_ptr lt_emalloc        LT_PARAMS((size_t size));
216 static lt_ptr lt_erealloc       LT_PARAMS((lt_ptr addr, size_t size));
217
218 /* static lt_ptr rpl_realloc    LT_PARAMS((lt_ptr ptr, size_t size)); */
219 #define rpl_realloc realloc
220
221 /* These are the pointers that can be changed by the caller:  */
222 LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc)    LT_PARAMS((size_t size))
223                         = (lt_ptr (*) LT_PARAMS((size_t))) malloc;
224 LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc)   LT_PARAMS((lt_ptr ptr, size_t size))
225                         = (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc;
226 LT_GLOBAL_DATA void   (*lt_dlfree)      LT_PARAMS((lt_ptr ptr))
227                         = (void (*) LT_PARAMS((lt_ptr))) free;
228
229 /* The following macros reduce the amount of typing needed to cast
230    assigned memory.  */
231 #if WITH_DMALLOC
232
233 #define LT_DLMALLOC(tp, n)      ((tp *) xmalloc ((n) * sizeof(tp)))
234 #define LT_DLREALLOC(tp, p, n)  ((tp *) xrealloc ((p), (n) * sizeof(tp)))
235 #define LT_DLFREE(p)                                            \
236         LT_STMT_START { if (p) (p) = (xfree (p), (lt_ptr) 0); } LT_STMT_END
237
238 #define LT_EMALLOC(tp, n)       ((tp *) xmalloc ((n) * sizeof(tp)))
239 #define LT_EREALLOC(tp, p, n)   ((tp *) xrealloc ((p), (n) * sizeof(tp)))
240
241 #else
242
243 #define LT_DLMALLOC(tp, n)      ((tp *) lt_dlmalloc ((n) * sizeof(tp)))
244 #define LT_DLREALLOC(tp, p, n)  ((tp *) rpl_realloc ((p), (n) * sizeof(tp)))
245 #define LT_DLFREE(p)                                            \
246         LT_STMT_START { if (p) (p) = (lt_dlfree (p), (lt_ptr) 0); } LT_STMT_END
247
248 #define LT_EMALLOC(tp, n)       ((tp *) lt_emalloc ((n) * sizeof(tp)))
249 #define LT_EREALLOC(tp, p, n)   ((tp *) lt_erealloc ((p), (n) * sizeof(tp)))
250
251 #endif
252
253 #define LT_DLMEM_REASSIGN(p, q)                 LT_STMT_START { \
254         if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; }   \
255                                                 } LT_STMT_END
256
257 \f
258 /* --- REPLACEMENT FUNCTIONS --- */
259
260
261 #undef strdup
262 #define strdup rpl_strdup
263
264 static char *strdup LT_PARAMS((const char *str));
265
266 static char *
267 strdup(str)
268      const char *str;
269 {
270   char *tmp = 0;
271
272   if (str)
273     {
274       tmp = LT_DLMALLOC (char, 1+ strlen (str));
275       if (tmp)
276         {
277           strcpy(tmp, str);
278         }
279     }
280
281   return tmp;
282 }
283
284
285 #if ! HAVE_STRCMP
286
287 #undef strcmp
288 #define strcmp rpl_strcmp
289
290 static int strcmp LT_PARAMS((const char *str1, const char *str2));
291
292 static int
293 strcmp (str1, str2)
294      const char *str1;
295      const char *str2;
296 {
297   if (str1 == str2)
298     return 0;
299   if (str1 == 0)
300     return -1;
301   if (str2 == 0)
302     return 1;
303
304   for (;*str1 && *str2; ++str1, ++str2)
305     {
306       if (*str1 != *str2)
307         break;
308     }
309
310   return (int)(*str1 - *str2);
311 }
312 #endif
313
314
315 #if ! HAVE_STRCHR
316
317 #  if HAVE_INDEX
318 #    define strchr index
319 #  else
320 #    define strchr rpl_strchr
321
322 static const char *strchr LT_PARAMS((const char *str, int ch));
323
324 static const char*
325 strchr(str, ch)
326      const char *str;
327      int ch;
328 {
329   const char *p;
330
331   for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p)
332     /*NOWORK*/;
333
334   return (*p == (char)ch) ? p : 0;
335 }
336
337 #  endif
338 #endif /* !HAVE_STRCHR */
339
340
341 #if ! HAVE_STRRCHR
342
343 #  if HAVE_RINDEX
344 #    define strrchr rindex
345 #  else
346 #    define strrchr rpl_strrchr
347
348 static const char *strrchr LT_PARAMS((const char *str, int ch));
349
350 static const char*
351 strrchr(str, ch)
352      const char *str;
353      int ch;
354 {
355   const char *p, *q = 0;
356
357   for (p = str; *p != LT_EOS_CHAR; ++p)
358     {
359       if (*p == (char) ch)
360         {
361           q = p;
362         }
363     }
364
365   return q;
366 }
367
368 # endif
369 #endif
370
371 /* NOTE:  Neither bcopy nor the memcpy implementation below can
372           reliably handle copying in overlapping areas of memory.  Use
373           memmove (for which there is a fallback implmentation below)
374           if you need that behaviour.  */
375 #if ! HAVE_MEMCPY
376
377 #  if HAVE_BCOPY
378 #    define memcpy(dest, src, size)     bcopy (src, dest, size)
379 #  else
380 #    define memcpy rpl_memcpy
381
382 static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
383
384 static lt_ptr
385 memcpy (dest, src, size)
386      lt_ptr dest;
387      const lt_ptr src;
388      size_t size;
389 {
390   size_t i = 0;
391
392   for (i = 0; i < size; ++i)
393     {
394       dest[i] = src[i];
395     }
396
397   return dest;
398 }
399
400 #  endif /* !HAVE_BCOPY */
401 #endif   /* !HAVE_MEMCPY */
402
403 #if ! HAVE_MEMMOVE
404 #  define memmove rpl_memmove
405
406 static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
407
408 static lt_ptr
409 memmove (dest, src, size)
410      lt_ptr dest;
411      const lt_ptr src;
412      size_t size;
413 {
414   size_t i;
415
416   if (dest < src)
417     for (i = 0; i < size; ++i)
418       {
419         dest[i] = src[i];
420       }
421   else if (dest > src)
422     for (i = size -1; i >= 0; --i)
423       {
424         dest[i] = src[i];
425       }
426
427   return dest;
428 }
429
430 #endif /* !HAVE_MEMMOVE */
431
432 #ifdef LT_USE_WINDOWS_DIRENT_EMULATION
433
434 static void closedir LT_PARAMS((DIR *entry));
435
436 static void
437 closedir(entry)
438   DIR *entry;
439 {
440   assert(entry != (DIR *) NULL);
441   FindClose(entry->hSearch);
442   lt_dlfree((lt_ptr)entry);
443 }
444
445
446 static DIR * opendir LT_PARAMS((const char *path));
447
448 static DIR*
449 opendir (path)
450   const char *path;
451 {
452   char file_specification[LT_FILENAME_MAX];
453   DIR *entry;
454
455   assert(path != (char *) NULL);
456   (void) strncpy(file_specification,path,LT_FILENAME_MAX-1);
457   (void) strcat(file_specification,"\\");
458   entry = LT_DLMALLOC (DIR,sizeof(DIR));
459   if (entry != (DIR *) 0)
460     {
461       entry->firsttime = TRUE;
462       entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData);
463     }
464   if (entry->hSearch == INVALID_HANDLE_VALUE)
465     {
466       (void) strcat(file_specification,"\\*.*");
467       entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData);
468       if (entry->hSearch == INVALID_HANDLE_VALUE)
469         {
470           LT_DLFREE (entry);
471           return (DIR *) 0;
472         }
473     }
474   return(entry);
475 }
476
477
478 static struct dirent *readdir LT_PARAMS((DIR *entry));
479
480 static struct dirent *readdir(entry)
481   DIR *entry;
482 {
483   int
484     status;
485
486   if (entry == (DIR *) 0)
487     return((struct dirent *) 0);
488   if (!entry->firsttime)
489     {
490       status = FindNextFile(entry->hSearch,&entry->Win32FindData);
491       if (status == 0)
492         return((struct dirent *) 0);
493     }
494   entry->firsttime = FALSE;
495   (void) strncpy(entry->file_info.d_name,entry->Win32FindData.cFileName,
496     LT_FILENAME_MAX-1);
497   entry->file_info.d_namlen = strlen(entry->file_info.d_name);
498   return(&entry->file_info);
499 }
500
501 #endif /* LT_USE_WINDOWS_DIRENT_EMULATION */
502
503 /* According to Alexandre Oliva <oliva@lsd.ic.unicamp.br>,
504     ``realloc is not entirely portable''
505    In any case we want to use the allocator supplied by the user without
506    burdening them with an lt_dlrealloc function pointer to maintain.
507    Instead implement our own version (with known boundary conditions)
508    using lt_dlmalloc and lt_dlfree. */
509
510 /* #undef realloc
511    #define realloc rpl_realloc
512 */
513 #if 0
514   /* You can't (re)define realloc unless you also (re)define malloc.
515      Right now, this code uses the size of the *destination* to decide
516      how much to copy.  That's not right, but you can't know the size
517      of the source unless you know enough about, or wrote malloc.  So
518      this code is disabled... */
519
520 static lt_ptr
521 realloc (ptr, size)
522      lt_ptr ptr;
523      size_t size;
524 {
525   if (size == 0)
526     {
527       /* For zero or less bytes, free the original memory */
528       if (ptr != 0)
529         {
530           lt_dlfree (ptr);
531         }
532
533       return (lt_ptr) 0;
534     }
535   else if (ptr == 0)
536     {
537       /* Allow reallocation of a NULL pointer.  */
538       return lt_dlmalloc (size);
539     }
540   else
541     {
542       /* Allocate a new block, copy and free the old block.  */
543       lt_ptr mem = lt_dlmalloc (size);
544
545       if (mem)
546         {
547           memcpy (mem, ptr, size);
548           lt_dlfree (ptr);
549         }
550
551       /* Note that the contents of PTR are not damaged if there is
552          insufficient memory to realloc.  */
553       return mem;
554     }
555 }
556 #endif
557
558
559 #if ! HAVE_ARGZ_APPEND
560 #  define argz_append rpl_argz_append
561
562 static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len,
563                                         const char *buf, size_t buf_len));
564
565 static error_t
566 argz_append (pargz, pargz_len, buf, buf_len)
567      char **pargz;
568      size_t *pargz_len;
569      const char *buf;
570      size_t buf_len;
571 {
572   size_t argz_len;
573   char  *argz;
574
575   assert (pargz);
576   assert (pargz_len);
577   assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len));
578
579   /* If nothing needs to be appended, no more work is required.  */
580   if (buf_len == 0)
581     return 0;
582
583   /* Ensure there is enough room to append BUF_LEN.  */
584   argz_len = *pargz_len + buf_len;
585   argz = LT_DLREALLOC (char, *pargz, argz_len);
586   if (!argz)
587     return ENOMEM;
588
589   /* Copy characters from BUF after terminating '\0' in ARGZ.  */
590   memcpy (argz + *pargz_len, buf, buf_len);
591
592   /* Assign new values.  */
593   *pargz = argz;
594   *pargz_len = argz_len;
595
596   return 0;
597 }
598 #endif /* !HAVE_ARGZ_APPEND */
599
600
601 #if ! HAVE_ARGZ_CREATE_SEP
602 #  define argz_create_sep rpl_argz_create_sep
603
604 static error_t argz_create_sep LT_PARAMS((const char *str, int delim,
605                                             char **pargz, size_t *pargz_len));
606
607 static error_t
608 argz_create_sep (str, delim, pargz, pargz_len)
609      const char *str;
610      int delim;
611      char **pargz;
612      size_t *pargz_len;
613 {
614   size_t argz_len;
615   char *argz = 0;
616
617   assert (str);
618   assert (pargz);
619   assert (pargz_len);
620
621   /* Make a copy of STR, but replacing each occurence of
622      DELIM with '\0'.  */
623   argz_len = 1+ LT_STRLEN (str);
624   if (argz_len)
625     {
626       const char *p;
627       char *q;
628
629       argz = LT_DLMALLOC (char, argz_len);
630       if (!argz)
631         return ENOMEM;
632
633       for (p = str, q = argz; *p != LT_EOS_CHAR; ++p)
634         {
635           if (*p == delim)
636             {
637               /* Ignore leading delimiters, and fold consecutive
638                  delimiters in STR into a single '\0' in ARGZ.  */
639               if ((q > argz) && (q[-1] != LT_EOS_CHAR))
640                 *q++ = LT_EOS_CHAR;
641               else
642                 --argz_len;
643             }
644           else
645             *q++ = *p;
646         }
647       /* Copy terminating LT_EOS_CHAR.  */
648       *q = *p;
649     }
650
651   /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory.  */
652   if (!argz_len)
653     LT_DLFREE (argz);
654
655   /* Assign new values.  */
656   *pargz = argz;
657   *pargz_len = argz_len;
658
659   return 0;
660 }
661 #endif /* !HAVE_ARGZ_CREATE_SEP */
662
663
664 #if ! HAVE_ARGZ_INSERT
665 #  define argz_insert rpl_argz_insert
666
667 static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len,
668                                         char *before, const char *entry));
669
670 static error_t
671 argz_insert (pargz, pargz_len, before, entry)
672      char **pargz;
673      size_t *pargz_len;
674      char *before;
675      const char *entry;
676 {
677   assert (pargz);
678   assert (pargz_len);
679   assert (entry && *entry);
680
681   /* No BEFORE address indicates ENTRY should be inserted after the
682      current last element.  */
683   if (!before)
684     return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry));
685
686   /* This probably indicates a programmer error, but to preserve
687      semantics, scan back to the start of an entry if BEFORE points
688      into the middle of it.  */
689   while ((before >= *pargz) && (before[-1] != LT_EOS_CHAR))
690     --before;
691
692   {
693     size_t entry_len    = 1+ LT_STRLEN (entry);
694     size_t argz_len     = *pargz_len + entry_len;
695     size_t offset       = before - *pargz;
696     char   *argz        = LT_DLREALLOC (char, *pargz, argz_len);
697
698     if (!argz)
699       return ENOMEM;
700
701     /* Make BEFORE point to the equivalent offset in ARGZ that it
702        used to have in *PARGZ incase realloc() moved the block.  */
703     before = argz + offset;
704
705     /* Move the ARGZ entries starting at BEFORE up into the new
706        space at the end -- making room to copy ENTRY into the
707        resulting gap.  */
708     memmove (before + entry_len, before, *pargz_len - offset);
709     memcpy  (before, entry, entry_len);
710
711     /* Assign new values.  */
712     *pargz = argz;
713     *pargz_len = argz_len;
714   }
715
716   return 0;
717 }
718 #endif /* !HAVE_ARGZ_INSERT */
719
720
721 #if ! HAVE_ARGZ_NEXT
722 #  define argz_next rpl_argz_next
723
724 static char *argz_next LT_PARAMS((char *argz, size_t argz_len,
725                                     const char *entry));
726
727 static char *
728 argz_next (argz, argz_len, entry)
729      char *argz;
730      size_t argz_len;
731      const char *entry;
732 {
733   assert ((argz && argz_len) || (!argz && !argz_len));
734
735   if (entry)
736     {
737       /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address
738          within the ARGZ vector.  */
739       assert ((!argz && !argz_len)
740               || ((argz <= entry) && (entry < (argz + argz_len))));
741
742       /* Move to the char immediately after the terminating
743          '\0' of ENTRY.  */
744       entry = 1+ strchr (entry, LT_EOS_CHAR);
745
746       /* Return either the new ENTRY, or else NULL if ARGZ is
747          exhausted.  */
748       return (entry >= argz + argz_len) ? 0 : (char *) entry;
749     }
750   else
751     {
752       /* This should probably be flagged as a programmer error,
753          since starting an argz_next loop with the iterator set
754          to ARGZ is safer.  To preserve semantics, handle the NULL
755          case by returning the start of ARGZ (if any).  */
756       if (argz_len > 0)
757         return argz;
758       else
759         return 0;
760     }
761 }
762 #endif /* !HAVE_ARGZ_NEXT */
763
764
765
766 #if ! HAVE_ARGZ_STRINGIFY
767 #  define argz_stringify rpl_argz_stringify
768
769 static void argz_stringify LT_PARAMS((char *argz, size_t argz_len,
770                                        int sep));
771
772 static void
773 argz_stringify (argz, argz_len, sep)
774      char *argz;
775      size_t argz_len;
776      int sep;
777 {
778   assert ((argz && argz_len) || (!argz && !argz_len));
779
780   if (sep)
781     {
782       --argz_len;               /* don't stringify the terminating EOS */
783       while (--argz_len > 0)
784         {
785           if (argz[argz_len] == LT_EOS_CHAR)
786             argz[argz_len] = sep;
787         }
788     }
789 }
790 #endif /* !HAVE_ARGZ_STRINGIFY */
791
792
793
794 \f
795 /* --- TYPE DEFINITIONS -- */
796
797
798 /* This type is used for the array of caller data sets in each handler. */
799 typedef struct {
800   lt_dlcaller_id        key;
801   lt_ptr                data;
802 } lt_caller_data;
803
804
805
806 \f
807 /* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */
808
809
810 /* Extract the diagnostic strings from the error table macro in the same
811    order as the enumerated indices in ltdl.h. */
812
813 static const char *lt_dlerror_strings[] =
814   {
815 #define LT_ERROR(name, diagnostic)      (diagnostic),
816     lt_dlerror_table
817 #undef LT_ERROR
818
819     0
820   };
821
822 /* This structure is used for the list of registered loaders. */
823 struct lt_dlloader {
824   struct lt_dlloader   *next;
825   const char           *loader_name;    /* identifying name for each loader */
826   const char           *sym_prefix;     /* prefix for symbols */
827   lt_module_open       *module_open;
828   lt_module_close      *module_close;
829   lt_find_sym          *find_sym;
830   lt_dlloader_exit     *dlloader_exit;
831   lt_user_data          dlloader_data;
832 };
833
834 struct lt_dlhandle_struct {
835   struct lt_dlhandle_struct   *next;
836   lt_dlloader          *loader;         /* dlopening interface */
837   lt_dlinfo             info;
838   int                   depcount;       /* number of dependencies */
839   lt_dlhandle          *deplibs;        /* dependencies */
840   lt_module             module;         /* system module handle */
841   lt_ptr                system;         /* system specific data */
842   lt_caller_data       *caller_data;    /* per caller associated data */
843   int                   flags;          /* various boolean stats */
844 };
845
846 /* Various boolean flags can be stored in the flags field of an
847    lt_dlhandle_struct... */
848 #define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag))
849 #define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag))
850
851 #define LT_DLRESIDENT_FLAG          (0x01 << 0)
852 /* ...add more flags here... */
853
854 #define LT_DLIS_RESIDENT(handle)    LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG)
855
856
857 #define LT_DLSTRERROR(name)     lt_dlerror_strings[LT_CONC(LT_ERROR_,name)]
858
859 static  const char      objdir[]                = LTDL_OBJDIR;
860 static  const char      archive_ext[]           = LTDL_ARCHIVE_EXT;
861 #ifdef  LTDL_SHLIB_EXT
862 static  const char      shlib_ext[]             = LTDL_SHLIB_EXT;
863 #endif
864 #ifdef  LTDL_SYSSEARCHPATH
865 static  const char      sys_search_path[]       = LTDL_SYSSEARCHPATH;
866 #endif
867
868
869
870 \f
871 /* --- MUTEX LOCKING --- */
872
873
874 /* Macros to make it easier to run the lock functions only if they have
875    been registered.  The reason for the complicated lock macro is to
876    ensure that the stored error message from the last error is not
877    accidentally erased if the current function doesn't generate an
878    error of its own.  */
879 #define LT_DLMUTEX_LOCK()                       LT_STMT_START { \
880         if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)();    \
881                                                 } LT_STMT_END
882 #define LT_DLMUTEX_UNLOCK()                     LT_STMT_START { \
883         if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\
884                                                 } LT_STMT_END
885 #define LT_DLMUTEX_SETERROR(errormsg)           LT_STMT_START { \
886         if (lt_dlmutex_seterror_func)                           \
887                 (*lt_dlmutex_seterror_func) (errormsg);         \
888         else    lt_dllast_error = (errormsg);   } LT_STMT_END
889 #define LT_DLMUTEX_GETERROR(errormsg)           LT_STMT_START { \
890         if (lt_dlmutex_seterror_func)                           \
891                 (errormsg) = (*lt_dlmutex_geterror_func) ();    \
892         else    (errormsg) = lt_dllast_error;   } LT_STMT_END
893
894 /* The mutex functions stored here are global, and are necessarily the
895    same for all threads that wish to share access to libltdl.  */
896 static  lt_dlmutex_lock     *lt_dlmutex_lock_func     = 0;
897 static  lt_dlmutex_unlock   *lt_dlmutex_unlock_func   = 0;
898 static  lt_dlmutex_seterror *lt_dlmutex_seterror_func = 0;
899 static  lt_dlmutex_geterror *lt_dlmutex_geterror_func = 0;
900 static  const char          *lt_dllast_error          = 0;
901
902
903 /* Either set or reset the mutex functions.  Either all the arguments must
904    be valid functions, or else all can be NULL to turn off locking entirely.
905    The registered functions should be manipulating a static global lock
906    from the lock() and unlock() callbacks, which needs to be reentrant.  */
907 int
908 lt_dlmutex_register (lock, unlock, seterror, geterror)
909      lt_dlmutex_lock *lock;
910      lt_dlmutex_unlock *unlock;
911      lt_dlmutex_seterror *seterror;
912      lt_dlmutex_geterror *geterror;
913 {
914   lt_dlmutex_unlock *old_unlock = unlock;
915   int                errors     = 0;
916
917   /* Lock using the old lock() callback, if any.  */
918   LT_DLMUTEX_LOCK ();
919
920   if ((lock && unlock && seterror && geterror)
921       || !(lock || unlock || seterror || geterror))
922     {
923       lt_dlmutex_lock_func     = lock;
924       lt_dlmutex_unlock_func   = unlock;
925       lt_dlmutex_geterror_func = geterror;
926     }
927   else
928     {
929       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS));
930       ++errors;
931     }
932
933   /* Use the old unlock() callback we saved earlier, if any.  Otherwise
934      record any errors using internal storage.  */
935   if (old_unlock)
936     (*old_unlock) ();
937
938   /* Return the number of errors encountered during the execution of
939      this function.  */
940   return errors;
941 }
942
943
944
945 \f
946 /* --- ERROR HANDLING --- */
947
948
949 static  const char    **user_error_strings      = 0;
950 static  int             errorcount              = LT_ERROR_MAX;
951
952 int
953 lt_dladderror (diagnostic)
954      const char *diagnostic;
955 {
956   int           errindex = 0;
957   int           result   = -1;
958   const char  **temp     = (const char **) 0;
959
960   assert (diagnostic);
961
962   LT_DLMUTEX_LOCK ();
963
964   errindex = errorcount - LT_ERROR_MAX;
965   temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex);
966   if (temp)
967     {
968       user_error_strings                = temp;
969       user_error_strings[errindex]      = diagnostic;
970       result                            = errorcount++;
971     }
972
973   LT_DLMUTEX_UNLOCK ();
974
975   return result;
976 }
977
978 int
979 lt_dlseterror (errindex)
980      int errindex;
981 {
982   int           errors   = 0;
983
984   LT_DLMUTEX_LOCK ();
985
986   if (errindex >= errorcount || errindex < 0)
987     {
988       /* Ack!  Error setting the error message! */
989       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE));
990       ++errors;
991     }
992   else if (errindex < LT_ERROR_MAX)
993     {
994       /* No error setting the error message! */
995       LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]);
996     }
997   else
998     {
999       /* No error setting the error message! */
1000       LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]);
1001     }
1002
1003   LT_DLMUTEX_UNLOCK ();
1004
1005   return errors;
1006 }
1007
1008 static lt_ptr
1009 lt_emalloc (size)
1010      size_t size;
1011 {
1012   lt_ptr mem = lt_dlmalloc (size);
1013   if (size && !mem)
1014     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
1015   return mem;
1016 }
1017
1018 static lt_ptr
1019 lt_erealloc (addr, size)
1020      lt_ptr addr;
1021      size_t size;
1022 {
1023   lt_ptr mem = realloc (addr, size);
1024   if (size && !mem)
1025     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
1026   return mem;
1027 }
1028
1029 static char *
1030 lt_estrdup (str)
1031      const char *str;
1032 {
1033   char *copy = strdup (str);
1034   if (LT_STRLEN (str) && !copy)
1035     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
1036   return copy;
1037 }
1038
1039
1040
1041 \f
1042 /* --- DLOPEN() INTERFACE LOADER --- */
1043
1044
1045 #if HAVE_LIBDL
1046
1047 /* dynamic linking with dlopen/dlsym */
1048
1049 #if HAVE_DLFCN_H
1050 #  include <dlfcn.h>
1051 #endif
1052
1053 #if HAVE_SYS_DL_H
1054 #  include <sys/dl.h>
1055 #endif
1056
1057 #ifdef RTLD_GLOBAL
1058 #  define LT_GLOBAL             RTLD_GLOBAL
1059 #else
1060 #  ifdef DL_GLOBAL
1061 #    define LT_GLOBAL           DL_GLOBAL
1062 #  endif
1063 #endif /* !RTLD_GLOBAL */
1064 #ifndef LT_GLOBAL
1065 #  define LT_GLOBAL             0
1066 #endif /* !LT_GLOBAL */
1067
1068 /* We may have to define LT_LAZY_OR_NOW in the command line if we
1069    find out it does not work in some platform. */
1070 #ifndef LT_LAZY_OR_NOW
1071 #  ifdef RTLD_LAZY
1072 #    define LT_LAZY_OR_NOW      RTLD_LAZY
1073 #  else
1074 #    ifdef DL_LAZY
1075 #      define LT_LAZY_OR_NOW    DL_LAZY
1076 #    endif
1077 #  endif /* !RTLD_LAZY */
1078 #endif
1079 #ifndef LT_LAZY_OR_NOW
1080 #  ifdef RTLD_NOW
1081 #    define LT_LAZY_OR_NOW      RTLD_NOW
1082 #  else
1083 #    ifdef DL_NOW
1084 #      define LT_LAZY_OR_NOW    DL_NOW
1085 #    endif
1086 #  endif /* !RTLD_NOW */
1087 #endif
1088 #ifndef LT_LAZY_OR_NOW
1089 #  define LT_LAZY_OR_NOW        0
1090 #endif /* !LT_LAZY_OR_NOW */
1091
1092 #if HAVE_DLERROR
1093 #  define DLERROR(arg)  dlerror ()
1094 #else
1095 #  define DLERROR(arg)  LT_DLSTRERROR (arg)
1096 #endif
1097
1098 static lt_module
1099 sys_dl_open (loader_data, filename)
1100      lt_user_data loader_data;
1101      const char *filename;
1102 {
1103   lt_module   module   = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW);
1104
1105   if (!module)
1106     {
1107       LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN));
1108     }
1109
1110   return module;
1111 }
1112
1113 static int
1114 sys_dl_close (loader_data, module)
1115      lt_user_data loader_data;
1116      lt_module module;
1117 {
1118   int errors = 0;
1119
1120   if (dlclose (module) != 0)
1121     {
1122       LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE));
1123       ++errors;
1124     }
1125
1126   return errors;
1127 }
1128
1129 static lt_ptr
1130 sys_dl_sym (loader_data, module, symbol)
1131      lt_user_data loader_data;
1132      lt_module module;
1133      const char *symbol;
1134 {
1135   lt_ptr address = dlsym (module, symbol);
1136
1137   if (!address)
1138     {
1139       LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND));
1140     }
1141
1142   return address;
1143 }
1144
1145 static struct lt_user_dlloader sys_dl =
1146   {
1147 #  ifdef NEED_USCORE
1148     "_",
1149 #  else
1150     0,
1151 #  endif
1152     sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 };
1153
1154
1155 #endif /* HAVE_LIBDL */
1156
1157
1158 \f
1159 /* --- SHL_LOAD() INTERFACE LOADER --- */
1160
1161 #if HAVE_SHL_LOAD
1162
1163 /* dynamic linking with shl_load (HP-UX) (comments from gmodule) */
1164
1165 #ifdef HAVE_DL_H
1166 #  include <dl.h>
1167 #endif
1168
1169 /* some flags are missing on some systems, so we provide
1170  * harmless defaults.
1171  *
1172  * Mandatory:
1173  * BIND_IMMEDIATE  - Resolve symbol references when the library is loaded.
1174  * BIND_DEFERRED   - Delay code symbol resolution until actual reference.
1175  *
1176  * Optionally:
1177  * BIND_FIRST      - Place the library at the head of the symbol search
1178  *                   order.
1179  * BIND_NONFATAL   - The default BIND_IMMEDIATE behavior is to treat all
1180  *                   unsatisfied symbols as fatal.  This flag allows
1181  *                   binding of unsatisfied code symbols to be deferred
1182  *                   until use.
1183  *                   [Perl: For certain libraries, like DCE, deferred
1184  *                   binding often causes run time problems. Adding
1185  *                   BIND_NONFATAL to BIND_IMMEDIATE still allows
1186  *                   unresolved references in situations like this.]
1187  * BIND_NOSTART    - Do not call the initializer for the shared library
1188  *                   when the library is loaded, nor on a future call to
1189  *                   shl_unload().
1190  * BIND_VERBOSE    - Print verbose messages concerning possible
1191  *                   unsatisfied symbols.
1192  *
1193  * hp9000s700/hp9000s800:
1194  * BIND_RESTRICTED - Restrict symbols visible by the library to those
1195  *                   present at library load time.
1196  * DYNAMIC_PATH    - Allow the loader to dynamically search for the
1197  *                   library specified by the path argument.
1198  */
1199
1200 #ifndef DYNAMIC_PATH
1201 #  define DYNAMIC_PATH          0
1202 #endif
1203 #ifndef BIND_RESTRICTED
1204 #  define BIND_RESTRICTED       0
1205 #endif
1206
1207 #define LT_BIND_FLAGS   (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH)
1208
1209 static lt_module
1210 sys_shl_open (loader_data, filename)
1211      lt_user_data loader_data;
1212      const char *filename;
1213 {
1214   static shl_t self = (shl_t) 0;
1215   lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L);
1216
1217   /* Since searching for a symbol against a NULL module handle will also
1218      look in everything else that was already loaded and exported with
1219      the -E compiler flag, we always cache a handle saved before any
1220      modules are loaded.  */
1221   if (!self)
1222     {
1223       lt_ptr address;
1224       shl_findsym (&self, "main", TYPE_UNDEFINED, &address);
1225     }
1226
1227   if (!filename)
1228     {
1229       module = self;
1230     }
1231   else
1232     {
1233       module = shl_load (filename, LT_BIND_FLAGS, 0L);
1234
1235       if (!module)
1236         {
1237           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
1238         }
1239     }
1240
1241   return module;
1242 }
1243
1244 static int
1245 sys_shl_close (loader_data, module)
1246      lt_user_data loader_data;
1247      lt_module module;
1248 {
1249   int errors = 0;
1250
1251   if (module && (shl_unload ((shl_t) (module)) != 0))
1252     {
1253       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
1254       ++errors;
1255     }
1256
1257   return errors;
1258 }
1259
1260 static lt_ptr
1261 sys_shl_sym (loader_data, module, symbol)
1262      lt_user_data loader_data;
1263      lt_module module;
1264      const char *symbol;
1265 {
1266   lt_ptr address = 0;
1267
1268   /* sys_shl_open should never return a NULL module handle */
1269   if (module == (lt_module) 0)
1270   {
1271     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
1272   }
1273   else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address))
1274     {
1275       if (!address)
1276         {
1277           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
1278         }
1279     }
1280
1281   return address;
1282 }
1283
1284 static struct lt_user_dlloader sys_shl = {
1285   0, sys_shl_open, sys_shl_close, sys_shl_sym, 0, 0
1286 };
1287
1288 #endif /* HAVE_SHL_LOAD */
1289
1290
1291
1292 \f
1293 /* --- LOADLIBRARY() INTERFACE LOADER --- */
1294
1295 #ifdef __WINDOWS__
1296
1297 /* dynamic linking for Win32 */
1298
1299 #include <windows.h>
1300
1301 /* Forward declaration; required to implement handle search below. */
1302 static lt_dlhandle handles;
1303
1304 static lt_module
1305 sys_wll_open (loader_data, filename)
1306      lt_user_data loader_data;
1307      const char *filename;
1308 {
1309   lt_dlhandle   cur;
1310   lt_module     module     = 0;
1311   const char   *errormsg   = 0;
1312   char         *searchname = 0;
1313   char         *ext;
1314   char          self_name_buf[MAX_PATH];
1315
1316   if (!filename)
1317     {
1318       /* Get the name of main module */
1319       *self_name_buf = 0;
1320       GetModuleFileName (NULL, self_name_buf, sizeof (self_name_buf));
1321       filename = ext = self_name_buf;
1322     }
1323   else
1324     {
1325       ext = strrchr (filename, '.');
1326     }
1327
1328   if (ext)
1329     {
1330       /* FILENAME already has an extension. */
1331       searchname = lt_estrdup (filename);
1332     }
1333   else
1334     {
1335       /* Append a `.' to stop Windows from adding an
1336          implicit `.dll' extension. */
1337       searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename));
1338       if (searchname)
1339         sprintf (searchname, "%s.", filename);
1340     }
1341   if (!searchname)
1342     return 0;
1343
1344 #if __CYGWIN__
1345   {
1346     char wpath[MAX_PATH];
1347     cygwin_conv_to_full_win32_path(searchname, wpath);
1348     module = LoadLibrary(wpath);
1349   }
1350 #else
1351   module = LoadLibrary (searchname);
1352 #endif
1353   LT_DLFREE (searchname);
1354
1355   /* libltdl expects this function to fail if it is unable
1356      to physically load the library.  Sadly, LoadLibrary
1357      will search the loaded libraries for a match and return
1358      one of them if the path search load fails.
1359
1360      We check whether LoadLibrary is returning a handle to
1361      an already loaded module, and simulate failure if we
1362      find one. */
1363   LT_DLMUTEX_LOCK ();
1364   cur = handles;
1365   while (cur)
1366     {
1367       if (!cur->module)
1368         {
1369           cur = 0;
1370           break;
1371         }
1372
1373       if (cur->module == module)
1374         {
1375           break;
1376         }
1377
1378       cur = cur->next;
1379   }
1380   LT_DLMUTEX_UNLOCK ();
1381
1382   if (cur || !module)
1383     {
1384       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
1385       module = 0;
1386     }
1387
1388   return module;
1389 }
1390
1391 static int
1392 sys_wll_close (loader_data, module)
1393      lt_user_data loader_data;
1394      lt_module module;
1395 {
1396   int         errors   = 0;
1397
1398   if (FreeLibrary(module) == 0)
1399     {
1400       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
1401       ++errors;
1402     }
1403
1404   return errors;
1405 }
1406
1407 static lt_ptr
1408 sys_wll_sym (loader_data, module, symbol)
1409      lt_user_data loader_data;
1410      lt_module module;
1411      const char *symbol;
1412 {
1413   lt_ptr      address  = GetProcAddress (module, symbol);
1414
1415   if (!address)
1416     {
1417       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
1418     }
1419
1420   return address;
1421 }
1422
1423 static struct lt_user_dlloader sys_wll = {
1424   0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0
1425 };
1426
1427 #endif /* __WINDOWS__ */
1428
1429
1430
1431 \f
1432 /* --- LOAD_ADD_ON() INTERFACE LOADER --- */
1433
1434
1435 #ifdef __BEOS__
1436
1437 /* dynamic linking for BeOS */
1438
1439 #include <kernel/image.h>
1440
1441 static lt_module
1442 sys_bedl_open (loader_data, filename)
1443      lt_user_data loader_data;
1444      const char *filename;
1445 {
1446   image_id image = 0;
1447
1448   if (filename)
1449     {
1450       image = load_add_on (filename);
1451     }
1452   else
1453     {
1454       image_info info;
1455       int32 cookie = 0;
1456       if (get_next_image_info (0, &cookie, &info) == B_OK)
1457         image = load_add_on (info.name);
1458     }
1459
1460   if (image <= 0)
1461     {
1462       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
1463       image = 0;
1464     }
1465
1466   return (lt_module) image;
1467 }
1468
1469 static int
1470 sys_bedl_close (loader_data, module)
1471      lt_user_data loader_data;
1472      lt_module module;
1473 {
1474   int errors = 0;
1475
1476   if (unload_add_on ((image_id) module) != B_OK)
1477     {
1478       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
1479       ++errors;
1480     }
1481
1482   return errors;
1483 }
1484
1485 static lt_ptr
1486 sys_bedl_sym (loader_data, module, symbol)
1487      lt_user_data loader_data;
1488      lt_module module;
1489      const char *symbol;
1490 {
1491   lt_ptr address = 0;
1492   image_id image = (image_id) module;
1493
1494   if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK)
1495     {
1496       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
1497       address = 0;
1498     }
1499
1500   return address;
1501 }
1502
1503 static struct lt_user_dlloader sys_bedl = {
1504   0, sys_bedl_open, sys_bedl_close, sys_bedl_sym, 0, 0
1505 };
1506
1507 #endif /* __BEOS__ */
1508
1509
1510
1511 \f
1512 /* --- DLD_LINK() INTERFACE LOADER --- */
1513
1514
1515 #if HAVE_DLD
1516
1517 /* dynamic linking with dld */
1518
1519 #if HAVE_DLD_H
1520 #include <dld.h>
1521 #endif
1522
1523 static lt_module
1524 sys_dld_open (loader_data, filename)
1525      lt_user_data loader_data;
1526      const char *filename;
1527 {
1528   lt_module module = strdup (filename);
1529
1530   if (dld_link (filename) != 0)
1531     {
1532       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
1533       LT_DLFREE (module);
1534       module = 0;
1535     }
1536
1537   return module;
1538 }
1539
1540 static int
1541 sys_dld_close (loader_data, module)
1542      lt_user_data loader_data;
1543      lt_module module;
1544 {
1545   int errors = 0;
1546
1547   if (dld_unlink_by_file ((char*)(module), 1) != 0)
1548     {
1549       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
1550       ++errors;
1551     }
1552   else
1553     {
1554       LT_DLFREE (module);
1555     }
1556
1557   return errors;
1558 }
1559
1560 static lt_ptr
1561 sys_dld_sym (loader_data, module, symbol)
1562      lt_user_data loader_data;
1563      lt_module module;
1564      const char *symbol;
1565 {
1566   lt_ptr address = dld_get_func (symbol);
1567
1568   if (!address)
1569     {
1570       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
1571     }
1572
1573   return address;
1574 }
1575
1576 static struct lt_user_dlloader sys_dld = {
1577   0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0
1578 };
1579
1580 #endif /* HAVE_DLD */
1581
1582 /* --- DYLD() MACOSX/DARWIN INTERFACE LOADER --- */
1583 #if HAVE_DYLD
1584
1585
1586 #if HAVE_MACH_O_DYLD_H
1587 #  include <mach-o/dyld.h>
1588 #endif
1589 #include <mach-o/getsect.h>
1590
1591 /* We have to put some stuff here that isn't in older dyld.h files */
1592 #ifndef ENUM_DYLD_BOOL
1593 # define ENUM_DYLD_BOOL
1594 # undef FALSE
1595 # undef TRUE
1596  enum DYLD_BOOL {
1597     FALSE,
1598     TRUE
1599  };
1600 #endif
1601 #ifndef LC_REQ_DYLD
1602 # define LC_REQ_DYLD 0x80000000
1603 #endif
1604 #ifndef LC_LOAD_WEAK_DYLIB
1605 # define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
1606 #endif
1607 static const struct mach_header * (*ltdl_NSAddImage)(const char *image_name, unsigned long options) = 0;
1608 static NSSymbol (*ltdl_NSLookupSymbolInImage)(const struct mach_header *image,const char *symbolName, unsigned long options) = 0;
1609 static enum DYLD_BOOL (*ltdl_NSIsSymbolNameDefinedInImage)(const struct mach_header *image, const char *symbolName) = 0;
1610 static enum DYLD_BOOL (*ltdl_NSMakePrivateModulePublic)(NSModule module) = 0;
1611
1612 #ifndef NSADDIMAGE_OPTION_NONE
1613 #define NSADDIMAGE_OPTION_NONE                          0x0    
1614 #endif
1615 #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
1616 #define NSADDIMAGE_OPTION_RETURN_ON_ERROR               0x1
1617 #endif    
1618 #ifndef NSADDIMAGE_OPTION_WITH_SEARCHING
1619 #define NSADDIMAGE_OPTION_WITH_SEARCHING                0x2
1620 #endif    
1621 #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
1622 #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED         0x4
1623 #endif
1624 #ifndef NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME
1625 #define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8
1626 #endif
1627 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
1628 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND            0x0
1629 #endif   
1630 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW
1631 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW        0x1
1632 #endif
1633 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY
1634 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY      0x2
1635 #endif
1636 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
1637 #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
1638 #endif
1639
1640
1641 static const char *
1642 lt_int_dyld_error(othererror)
1643         char* othererror;
1644 {
1645 /* return the dyld error string, or the passed in error string if none */
1646         NSLinkEditErrors ler;
1647         int lerno;
1648         const char *errstr;
1649         const char *file;
1650         NSLinkEditError(&ler,&lerno,&file,&errstr);     
1651         if (!errstr || !strlen(errstr)) errstr = othererror;
1652         return errstr;
1653 }
1654  
1655 static const struct mach_header *
1656 lt_int_dyld_get_mach_header_from_nsmodule(module)
1657         NSModule module;
1658 {
1659 /* There should probably be an apple dyld api for this */
1660         int i=_dyld_image_count();
1661         int j;
1662         const char *modname=NSNameOfModule(module);
1663         const struct mach_header *mh=NULL;
1664         if (!modname) return NULL;
1665         for (j = 0; j < i; j++)
1666         {
1667                 if (!strcmp(_dyld_get_image_name(j),modname))
1668                 {
1669                         mh=_dyld_get_image_header(j);
1670                         break;
1671                 }
1672         }
1673         return mh;
1674 }
1675
1676 static const char* lt_int_dyld_lib_install_name(mh)
1677         const struct mach_header *mh;
1678 {       
1679 /* NSAddImage is also used to get the loaded image, but it only works if the lib
1680    is installed, for uninstalled libs we need to check the install_names against
1681    each other. Note that this is still broken if DYLD_IMAGE_SUFFIX is set and a
1682    different lib was loaded as a result
1683 */
1684         int j;
1685         struct load_command *lc;
1686         unsigned long offset = sizeof(struct mach_header);
1687         const struct mach_header *mh1;
1688         const char* retStr=NULL;
1689         for (j = 0; j < mh->ncmds; j++)
1690         {
1691                 lc = (struct load_command*)(((unsigned long)mh) + offset);
1692                 if (LC_ID_DYLIB == lc->cmd)
1693                 {
1694                         retStr=(char*)(((struct dylib_command*)lc)->dylib.name.offset + 
1695                                                                         (unsigned long)lc);
1696                 }
1697                 offset += lc->cmdsize;
1698         }
1699         return retStr;
1700 }
1701
1702 static const struct mach_header *
1703 lt_int_dyld_match_loaded_lib_by_install_name(const char *name)
1704 {
1705         int i=_dyld_image_count();
1706         int j;
1707         const struct mach_header *mh=NULL;
1708         const char *id=NULL;    
1709         for (j = 0; j < i; j++)
1710         {
1711                 id=lt_int_dyld_lib_install_name(_dyld_get_image_header(j));
1712                 if ((id) && (!strcmp(id,name)))
1713                 {
1714                         mh=_dyld_get_image_header(j);
1715                         break;
1716                 }
1717         }
1718         return mh;
1719 }
1720         
1721 static NSSymbol
1722 lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh)
1723         const char *symbol;
1724         const struct mach_header *mh;
1725 {
1726         /* Safe to assume our mh is good */
1727         int j;
1728         struct load_command *lc;
1729         unsigned long offset = sizeof(struct mach_header);
1730         NSSymbol retSym = 0;
1731         const struct mach_header *mh1;
1732         if ((ltdl_NSLookupSymbolInImage) && NSIsSymbolNameDefined(symbol) )
1733         {
1734                 for (j = 0; j < mh->ncmds; j++)
1735                 {
1736                         lc = (struct load_command*)(((unsigned long)mh) + offset);
1737                         if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
1738                         {
1739                                 mh1=lt_int_dyld_match_loaded_lib_by_install_name((char*)(((struct dylib_command*)lc)->dylib.name.offset + 
1740                                                                                 (unsigned long)lc));
1741                                 if (!mh1)
1742                                 {       
1743                                         /* Maybe NSAddImage can find it */                                                                                              
1744                                         mh1=ltdl_NSAddImage((char*)(((struct dylib_command*)lc)->dylib.name.offset + 
1745                                                                                 (unsigned long)lc),
1746                                                                                 NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED + 
1747                                                                                 NSADDIMAGE_OPTION_WITH_SEARCHING +
1748                                                                                 NSADDIMAGE_OPTION_RETURN_ON_ERROR );
1749                                 }                                               
1750                                 if (mh1)
1751                                 {
1752                                         retSym = ltdl_NSLookupSymbolInImage(mh1,
1753                                                                                         symbol,
1754                                                                                         NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 
1755                                                                                         | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
1756                                                                                         );
1757                                         if (retSym) break;                                              
1758                                 }                                               
1759                         }
1760                         offset += lc->cmdsize;
1761                 }
1762         }
1763         return retSym;
1764 }
1765
1766 static int
1767 sys_dyld_init()
1768 {
1769         int retCode = 0;
1770         int err = 0;
1771         if (!_dyld_present()) { 
1772                 retCode=1;
1773         }
1774         else {
1775       err = _dyld_func_lookup("__dyld_NSAddImage",(unsigned long*)&ltdl_NSAddImage);
1776       err = _dyld_func_lookup("__dyld_NSLookupSymbolInImage",(unsigned long*)&ltdl_NSLookupSymbolInImage);
1777       err = _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",(unsigned long*)&ltdl_NSIsSymbolNameDefinedInImage);
1778       err = _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",(unsigned long*)&ltdl_NSMakePrivateModulePublic);
1779     }
1780  return retCode;
1781 }
1782
1783 static lt_module
1784 sys_dyld_open (loader_data, filename)
1785      lt_user_data loader_data;
1786      const char *filename;
1787 {
1788         lt_module   module   = 0;
1789         NSObjectFileImage ofi = 0;
1790         NSObjectFileImageReturnCode ofirc;
1791         
1792         if (!filename) 
1793                 return (lt_module)-1;
1794         ofirc = NSCreateObjectFileImageFromFile(filename, &ofi);
1795         switch (ofirc)
1796         {
1797                 case NSObjectFileImageSuccess:
1798                         module = NSLinkModule(ofi, filename,
1799                                                 NSLINKMODULE_OPTION_RETURN_ON_ERROR
1800                                                  | NSLINKMODULE_OPTION_PRIVATE
1801                                                  | NSLINKMODULE_OPTION_BINDNOW);
1802                         NSDestroyObjectFileImage(ofi);
1803                         if (module)
1804                                 ltdl_NSMakePrivateModulePublic(module);
1805                         break;
1806                 case NSObjectFileImageInappropriateFile:
1807                     if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage)
1808                     {
1809                                 module = (lt_module)ltdl_NSAddImage(filename, NSADDIMAGE_OPTION_RETURN_ON_ERROR);       
1810                                 break;
1811                         }       
1812                 default:
1813                         LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN)));
1814                         return 0;
1815         }
1816         if (!module) LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN)));
1817   return module;
1818 }
1819
1820 static int
1821 sys_dyld_close (loader_data, module)
1822      lt_user_data loader_data;
1823      lt_module module;
1824 {
1825         int retCode = 0;
1826         int flags = 0;
1827         unsigned long size=0;
1828         if (module == (lt_module)-1) return 0;
1829 #ifdef __BIG_ENDIAN__   
1830         if (((struct mach_header *)module)->magic == MH_MAGIC)
1831 #else   
1832     if (((struct mach_header *)module)->magic == MH_CIGAM)
1833 #endif 
1834         {
1835           LT_DLMUTEX_SETERROR("Can not close a dylib");
1836           retCode = 1;
1837         }
1838         else
1839         {
1840 #if 1
1841 /* Currently, if a module contains c++ static destructors and it is unloaded, we
1842    get a segfault in atexit(), due to compiler and dynamic loader differences of
1843    opinion, this works around that.
1844 */   
1845                 if ((const struct section *)NULL != 
1846                    getsectbynamefromheader(lt_int_dyld_get_mach_header_from_nsmodule(module),
1847                    "__DATA","__mod_term_func"))
1848                 {
1849                         flags += NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
1850                 } 
1851 #endif          
1852 #ifdef __ppc__
1853                         flags += NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
1854 #endif
1855                 if (!NSUnLinkModule(module,flags))
1856                 {
1857                         retCode=1;
1858                         LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_CLOSE)));
1859                 }                                                                               
1860         }
1861         
1862  return retCode;
1863 }
1864
1865 static lt_ptr
1866 sys_dyld_sym (loader_data, module, symbol)
1867      lt_user_data loader_data;
1868      lt_module module;
1869      const char *symbol;
1870 {
1871         lt_ptr address = 0;
1872         NSSymbol *nssym = 0;
1873         void *unused;
1874         const struct mach_header *mh=NULL;
1875         if (module == (lt_module)-1)
1876         {
1877                 _dyld_lookup_and_bind(symbol,(unsigned long*)&address,&unused);
1878                 return address;
1879         }
1880 #ifdef __BIG_ENDIAN__   
1881         if (((struct mach_header *)module)->magic == MH_MAGIC)
1882 #else   
1883     if (((struct mach_header *)module)->magic == MH_CIGAM)
1884 #endif    
1885         {
1886             if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage)
1887             {
1888                 mh=module;
1889                         if (ltdl_NSIsSymbolNameDefinedInImage((struct mach_header*)module,symbol)) 
1890                         {
1891                                 nssym = ltdl_NSLookupSymbolInImage((struct mach_header*)module,
1892                                                                                         symbol,
1893                                                                                         NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 
1894                                                                                         | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
1895                                                                                         );
1896                         }
1897             }   
1898   
1899         }    
1900   else {
1901         nssym = NSLookupSymbolInModule(module, symbol);
1902         }
1903         if (!nssym) 
1904         {
1905                 if (!mh) mh=lt_int_dyld_get_mach_header_from_nsmodule(module);
1906                 nssym = lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh);
1907         }               
1908         if (!nssym) 
1909         {
1910                 LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(SYMBOL_NOT_FOUND)));
1911                 return NULL;
1912         }       
1913         return NSAddressOfSymbol(nssym);
1914 }
1915
1916 static struct lt_user_dlloader sys_dyld =
1917   { "_", sys_dyld_open, sys_dyld_close, sys_dyld_sym, 0, 0 };
1918
1919
1920 #endif /* HAVE_DYLD */
1921
1922 \f
1923 /* --- DLPREOPEN() INTERFACE LOADER --- */
1924
1925
1926 /* emulate dynamic linking using preloaded_symbols */
1927
1928 typedef struct lt_dlsymlists_t
1929 {
1930   struct lt_dlsymlists_t       *next;
1931   const lt_dlsymlist           *syms;
1932 } lt_dlsymlists_t;
1933
1934 static  const lt_dlsymlist     *default_preloaded_symbols       = 0;
1935 static  lt_dlsymlists_t        *preloaded_symbols               = 0;
1936
1937 static int
1938 presym_init (loader_data)
1939      lt_user_data loader_data;
1940 {
1941   int errors = 0;
1942
1943   LT_DLMUTEX_LOCK ();
1944
1945   preloaded_symbols = 0;
1946   if (default_preloaded_symbols)
1947     {
1948       errors = lt_dlpreload (default_preloaded_symbols);
1949     }
1950
1951   LT_DLMUTEX_UNLOCK ();
1952
1953   return errors;
1954 }
1955
1956 static int
1957 presym_free_symlists ()
1958 {
1959   lt_dlsymlists_t *lists;
1960
1961   LT_DLMUTEX_LOCK ();
1962
1963   lists = preloaded_symbols;
1964   while (lists)
1965     {
1966       lt_dlsymlists_t   *tmp = lists;
1967
1968       lists = lists->next;
1969       LT_DLFREE (tmp);
1970     }
1971   preloaded_symbols = 0;
1972
1973   LT_DLMUTEX_UNLOCK ();
1974
1975   return 0;
1976 }
1977
1978 static int
1979 presym_exit (loader_data)
1980      lt_user_data loader_data;
1981 {
1982   presym_free_symlists ();
1983   return 0;
1984 }
1985
1986 static int
1987 presym_add_symlist (preloaded)
1988      const lt_dlsymlist *preloaded;
1989 {
1990   lt_dlsymlists_t *tmp;
1991   lt_dlsymlists_t *lists;
1992   int              errors   = 0;
1993
1994   LT_DLMUTEX_LOCK ();
1995
1996   lists = preloaded_symbols;
1997   while (lists)
1998     {
1999       if (lists->syms == preloaded)
2000         {
2001           goto done;
2002         }
2003       lists = lists->next;
2004     }
2005
2006   tmp = LT_EMALLOC (lt_dlsymlists_t, 1);
2007   if (tmp)
2008     {
2009       memset (tmp, 0, sizeof(lt_dlsymlists_t));
2010       tmp->syms = preloaded;
2011       tmp->next = preloaded_symbols;
2012       preloaded_symbols = tmp;
2013     }
2014   else
2015     {
2016       ++errors;
2017     }
2018
2019  done:
2020   LT_DLMUTEX_UNLOCK ();
2021   return errors;
2022 }
2023
2024 static lt_module
2025 presym_open (loader_data, filename)
2026      lt_user_data loader_data;
2027      const char *filename;
2028 {
2029   lt_dlsymlists_t *lists;
2030   lt_module        module = (lt_module) 0;
2031
2032   LT_DLMUTEX_LOCK ();
2033   lists = preloaded_symbols;
2034
2035   if (!lists)
2036     {
2037       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS));
2038       goto done;
2039     }
2040
2041   /* Can't use NULL as the reflective symbol header, as NULL is
2042      used to mark the end of the entire symbol list.  Self-dlpreopened
2043      symbols follow this magic number, chosen to be an unlikely
2044      clash with a real module name.  */
2045   if (!filename)
2046     {
2047       filename = "@PROGRAM@";
2048     }
2049
2050   while (lists)
2051     {
2052       const lt_dlsymlist *syms = lists->syms;
2053
2054       while (syms->name)
2055         {
2056           if (!syms->address && strcmp(syms->name, filename) == 0)
2057             {
2058               module = (lt_module) syms;
2059               goto done;
2060             }
2061           ++syms;
2062         }
2063
2064       lists = lists->next;
2065     }
2066
2067   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
2068
2069  done:
2070   LT_DLMUTEX_UNLOCK ();
2071   return module;
2072 }
2073
2074 static int
2075 presym_close (loader_data, module)
2076      lt_user_data loader_data;
2077      lt_module module;
2078 {
2079   /* Just to silence gcc -Wall */
2080   module = 0;
2081   return 0;
2082 }
2083
2084 static lt_ptr
2085 presym_sym (loader_data, module, symbol)
2086      lt_user_data loader_data;
2087      lt_module module;
2088      const char *symbol;
2089 {
2090   lt_dlsymlist *syms = (lt_dlsymlist*) module;
2091
2092   ++syms;
2093   while (syms->address)
2094     {
2095       if (strcmp(syms->name, symbol) == 0)
2096         {
2097           return syms->address;
2098         }
2099
2100     ++syms;
2101   }
2102
2103   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
2104
2105   return 0;
2106 }
2107
2108 static struct lt_user_dlloader presym = {
2109   0, presym_open, presym_close, presym_sym, presym_exit, 0
2110 };
2111
2112
2113
2114
2115 \f
2116 /* --- DYNAMIC MODULE LOADING --- */
2117
2118
2119 /* The type of a function used at each iteration of  foreach_dirinpath().  */
2120 typedef int     foreach_callback_func LT_PARAMS((char *filename, lt_ptr data1,
2121                                                  lt_ptr data2));
2122
2123 static  int     foreach_dirinpath     LT_PARAMS((const char *search_path,
2124                                                  const char *base_name,
2125                                                  foreach_callback_func *func,
2126                                                  lt_ptr data1, lt_ptr data2));
2127
2128 static  int     find_file_callback    LT_PARAMS((char *filename, lt_ptr data,
2129                                                  lt_ptr ignored));
2130 static  int     find_handle_callback  LT_PARAMS((char *filename, lt_ptr data,
2131                                                  lt_ptr ignored));
2132 static  int     foreachfile_callback  LT_PARAMS((char *filename, lt_ptr data1,
2133                                                  lt_ptr data2));
2134
2135
2136 static  int     canonicalize_path     LT_PARAMS((const char *path,
2137                                                  char **pcanonical));
2138 static  int     argzize_path          LT_PARAMS((const char *path,
2139                                                  char **pargz,
2140                                                  size_t *pargz_len));
2141 static  FILE   *find_file             LT_PARAMS((const char *search_path,
2142                                                  const char *base_name,
2143                                                  char **pdir));
2144 static  lt_dlhandle *find_handle      LT_PARAMS((const char *search_path,
2145                                                  const char *base_name,
2146                                                  lt_dlhandle *handle));
2147 static  int     find_module           LT_PARAMS((lt_dlhandle *handle,
2148                                                  const char *dir,
2149                                                  const char *libdir,
2150                                                  const char *dlname,
2151                                                  const char *old_name,
2152                                                  int installed));
2153 static  int     free_vars             LT_PARAMS((char *dlname, char *oldname,
2154                                                  char *libdir, char *deplibs));
2155 static  int     load_deplibs          LT_PARAMS((lt_dlhandle handle,
2156                                                  char *deplibs));
2157 static  int     trim                  LT_PARAMS((char **dest,
2158                                                  const char *str));
2159 static  int     try_dlopen            LT_PARAMS((lt_dlhandle *handle,
2160                                                  const char *filename));
2161 static  int     tryall_dlopen         LT_PARAMS((lt_dlhandle *handle,
2162                                                  const char *filename));
2163 static  int     unload_deplibs        LT_PARAMS((lt_dlhandle handle));
2164 static  int     lt_argz_insert        LT_PARAMS((char **pargz,
2165                                                  size_t *pargz_len,
2166                                                  char *before,
2167                                                  const char *entry));
2168 static  int     lt_argz_insertinorder LT_PARAMS((char **pargz,
2169                                                  size_t *pargz_len,
2170                                                  const char *entry));
2171 static  int     lt_argz_insertdir     LT_PARAMS((char **pargz,
2172                                                  size_t *pargz_len,
2173                                                  const char *dirnam,
2174                                                  struct dirent *dp));
2175 static  int     lt_dlpath_insertdir   LT_PARAMS((char **ppath,
2176                                                  char *before,
2177                                                  const char *dir));
2178 static  int     list_files_by_dir     LT_PARAMS((const char *dirnam,
2179                                                  char **pargz,
2180                                                  size_t *pargz_len));
2181 static  int     file_not_found        LT_PARAMS((void));
2182
2183 static  char           *user_search_path= 0;
2184 static  lt_dlloader    *loaders         = 0;
2185 static  lt_dlhandle     handles         = 0;
2186 static  int             initialized     = 0;
2187
2188 /* Initialize libltdl. */
2189 int
2190 lt_dlinit ()
2191 {
2192   int         errors   = 0;
2193
2194   LT_DLMUTEX_LOCK ();
2195
2196   /* Initialize only at first call. */
2197   if (++initialized == 1)
2198     {
2199       handles = 0;
2200       user_search_path = 0; /* empty search path */
2201
2202 #if HAVE_LIBDL
2203       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen");
2204 #endif
2205 #if HAVE_SHL_LOAD
2206       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_shl, "dlopen");
2207 #endif
2208 #ifdef __WINDOWS__
2209       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_wll, "dlopen");
2210 #endif
2211 #ifdef __BEOS__
2212       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_bedl, "dlopen");
2213 #endif
2214 #if HAVE_DLD
2215       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dld, "dld");
2216 #endif
2217 #if HAVE_DYLD
2218        errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dyld, "dyld");
2219        errors += sys_dyld_init();
2220 #endif
2221       errors += lt_dlloader_add (lt_dlloader_next (0), &presym, "dlpreload");
2222
2223       if (presym_init (presym.dlloader_data))
2224         {
2225           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER));
2226           ++errors;
2227         }
2228       else if (errors != 0)
2229         {
2230           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED));
2231           ++errors;
2232         }
2233     }
2234
2235   LT_DLMUTEX_UNLOCK ();
2236
2237   return errors;
2238 }
2239
2240 int
2241 lt_dlpreload (preloaded)
2242      const lt_dlsymlist *preloaded;
2243 {
2244   int errors = 0;
2245
2246   if (preloaded)
2247     {
2248       errors = presym_add_symlist (preloaded);
2249     }
2250   else
2251     {
2252       presym_free_symlists();
2253
2254       LT_DLMUTEX_LOCK ();
2255       if (default_preloaded_symbols)
2256         {
2257           errors = lt_dlpreload (default_preloaded_symbols);
2258         }
2259       LT_DLMUTEX_UNLOCK ();
2260     }
2261
2262   return errors;
2263 }
2264
2265 int
2266 lt_dlpreload_default (preloaded)
2267      const lt_dlsymlist *preloaded;
2268 {
2269   LT_DLMUTEX_LOCK ();
2270   default_preloaded_symbols = preloaded;
2271   LT_DLMUTEX_UNLOCK ();
2272   return 0;
2273 }
2274
2275 int
2276 lt_dlexit ()
2277 {
2278   /* shut down libltdl */
2279   lt_dlloader *loader;
2280   int          errors   = 0;
2281
2282   LT_DLMUTEX_LOCK ();
2283   loader = loaders;
2284
2285   if (!initialized)
2286     {
2287       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN));
2288       ++errors;
2289       goto done;
2290     }
2291
2292   /* shut down only at last call. */
2293   if (--initialized == 0)
2294     {
2295       int       level;
2296
2297       while (handles && LT_DLIS_RESIDENT (handles))
2298         {
2299           handles = handles->next;
2300         }
2301
2302       /* close all modules */
2303       for (level = 1; handles; ++level)
2304         {
2305           lt_dlhandle cur = handles;
2306           int saw_nonresident = 0;
2307
2308           while (cur)
2309             {
2310               lt_dlhandle tmp = cur;
2311               cur = cur->next;
2312               if (!LT_DLIS_RESIDENT (tmp))
2313                 saw_nonresident = 1;
2314               if (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level)
2315                 {
2316                   if (lt_dlclose (tmp))
2317                     {
2318                       ++errors;
2319                     }
2320                 }
2321             }
2322           /* done if only resident modules are left */
2323           if (!saw_nonresident)
2324             break;
2325         }
2326
2327       /* close all loaders */
2328       while (loader)
2329         {
2330           lt_dlloader *next = loader->next;
2331           lt_user_data data = loader->dlloader_data;
2332           if (loader->dlloader_exit && loader->dlloader_exit (data))
2333             {
2334               ++errors;
2335             }
2336
2337           LT_DLMEM_REASSIGN (loader, next);
2338         }
2339       loaders = 0;
2340     }
2341
2342  done:
2343   LT_DLMUTEX_UNLOCK ();
2344   return errors;
2345 }
2346
2347 static int
2348 tryall_dlopen (handle, filename)
2349      lt_dlhandle *handle;
2350      const char *filename;
2351 {
2352   lt_dlhandle    cur;
2353   lt_dlloader   *loader;
2354   const char    *saved_error;
2355   int            errors         = 0;
2356
2357   LT_DLMUTEX_GETERROR (saved_error);
2358   LT_DLMUTEX_LOCK ();
2359
2360   cur    = handles;
2361   loader = loaders;
2362
2363   /* check whether the module was already opened */
2364   while (cur)
2365     {
2366       /* try to dlopen the program itself? */
2367       if (!cur->info.filename && !filename)
2368         {
2369           break;
2370         }
2371
2372       if (cur->info.filename && filename
2373           && strcmp (cur->info.filename, filename) == 0)
2374         {
2375           break;
2376         }
2377
2378       cur = cur->next;
2379     }
2380
2381   if (cur)
2382     {
2383       ++cur->info.ref_count;
2384       *handle = cur;
2385       goto done;
2386     }
2387
2388   cur = *handle;
2389   if (filename)
2390     {
2391       /* Comment out the check of file permissions using access.
2392          This call seems to always return -1 with error EACCES.
2393       */
2394       /* We need to catch missing file errors early so that
2395          file_not_found() can detect what happened.
2396       if (access (filename, R_OK) != 0)
2397         {
2398           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
2399           ++errors;
2400           goto done;
2401         } */
2402
2403       cur->info.filename = lt_estrdup (filename);
2404       if (!cur->info.filename)
2405         {
2406           ++errors;
2407           goto done;
2408         }
2409     }
2410   else
2411     {
2412       cur->info.filename = 0;
2413     }
2414
2415   while (loader)
2416     {
2417       lt_user_data data = loader->dlloader_data;
2418
2419       cur->module = loader->module_open (data, filename);
2420
2421       if (cur->module != 0)
2422         {
2423           break;
2424         }
2425       loader = loader->next;
2426     }
2427
2428   if (!loader)
2429     {
2430       LT_DLFREE (cur->info.filename);
2431       ++errors;
2432       goto done;
2433     }
2434
2435   cur->loader   = loader;
2436   LT_DLMUTEX_SETERROR (saved_error);
2437
2438  done:
2439   LT_DLMUTEX_UNLOCK ();
2440
2441   return errors;
2442 }
2443
2444 static int
2445 tryall_dlopen_module (handle, prefix, dirname, dlname)
2446      lt_dlhandle *handle;
2447      const char *prefix;
2448      const char *dirname;
2449      const char *dlname;
2450 {
2451   int      error        = 0;
2452   char     *filename    = 0;
2453   size_t   filename_len = 0;
2454   size_t   dirname_len  = LT_STRLEN (dirname);
2455
2456   assert (handle);
2457   assert (dirname);
2458   assert (dlname);
2459 #ifdef LT_DIRSEP_CHAR
2460   /* Only canonicalized names (i.e. with DIRSEP chars already converted)
2461      should make it into this function:  */
2462   assert (strchr (dirname, LT_DIRSEP_CHAR) == 0);
2463 #endif
2464
2465   if (dirname_len > 0)
2466     if (dirname[dirname_len -1] == '/')
2467       --dirname_len;
2468   filename_len = dirname_len + 1 + LT_STRLEN (dlname);
2469
2470   /* Allocate memory, and combine DIRNAME and MODULENAME into it.
2471      The PREFIX (if any) is handled below.  */
2472   filename  = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1);
2473   if (!filename)
2474     return 1;
2475
2476   sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname);
2477
2478   /* Now that we have combined DIRNAME and MODULENAME, if there is
2479      also a PREFIX to contend with, simply recurse with the arguments
2480      shuffled.  Otherwise, attempt to open FILENAME as a module.  */
2481   if (prefix)
2482     {
2483       error += tryall_dlopen_module (handle,
2484                                      (const char *) 0, prefix, filename);
2485     }
2486   else if (tryall_dlopen (handle, filename) != 0)
2487     {
2488       ++error;
2489     }
2490
2491   LT_DLFREE (filename);
2492   return error;
2493 }
2494
2495 static int
2496 find_module (handle, dir, libdir, dlname, old_name, installed)
2497      lt_dlhandle *handle;
2498      const char *dir;
2499      const char *libdir;
2500      const char *dlname;
2501      const char *old_name;
2502      int installed;
2503 {
2504   /* Try to open the old library first; if it was dlpreopened,
2505      we want the preopened version of it, even if a dlopenable
2506      module is available.  */
2507   if (old_name && tryall_dlopen (handle, old_name) == 0)
2508     {
2509       return 0;
2510     }
2511
2512   /* Try to open the dynamic library.  */
2513   if (dlname)
2514     {
2515       /* try to open the installed module */
2516       if (installed && libdir)
2517         {
2518           if (tryall_dlopen_module (handle,
2519                                     (const char *) 0, libdir, dlname) == 0)
2520             return 0;
2521         }
2522
2523       /* try to open the not-installed module */
2524       if (!installed)
2525         {
2526           if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0)
2527             return 0;
2528         }
2529
2530       /* maybe it was moved to another directory */
2531       {
2532           if (tryall_dlopen_module (handle,
2533                                     (const char *) 0, dir, dlname) == 0)
2534             return 0;
2535       }
2536     }
2537
2538   return 1;
2539 }
2540
2541
2542 static int
2543 canonicalize_path (path, pcanonical)
2544      const char *path;
2545      char **pcanonical;
2546 {
2547   char *canonical = 0;
2548
2549   assert (path && *path);
2550   assert (pcanonical);
2551
2552   canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path));
2553   if (!canonical)
2554     return 1;
2555
2556   {
2557     size_t dest = 0;
2558     size_t src;
2559     for (src = 0; path[src] != LT_EOS_CHAR; ++src)
2560       {
2561         /* Path separators are not copied to the beginning or end of
2562            the destination, or if another separator would follow
2563            immediately.  */
2564         if (path[src] == LT_PATHSEP_CHAR)
2565           {
2566             if ((dest == 0)
2567                 || (path[1+ src] == LT_PATHSEP_CHAR)
2568                 || (path[1+ src] == LT_EOS_CHAR))
2569               continue;
2570           }
2571
2572         /* Anything other than a directory separator is copied verbatim.  */
2573         if ((path[src] != '/')
2574 #ifdef LT_DIRSEP_CHAR
2575             && (path[src] != LT_DIRSEP_CHAR)
2576 #endif
2577             )
2578           {
2579             canonical[dest++] = path[src];
2580           }
2581         /* Directory separators are converted and copied only if they are
2582            not at the end of a path -- i.e. before a path separator or
2583            NULL terminator.  */
2584         else if ((path[1+ src] != LT_PATHSEP_CHAR)
2585                  && (path[1+ src] != LT_EOS_CHAR)
2586 #ifdef LT_DIRSEP_CHAR
2587                  && (path[1+ src] != LT_DIRSEP_CHAR)
2588 #endif
2589                  && (path[1+ src] != '/'))
2590           {
2591             canonical[dest++] = '/';
2592           }
2593       }
2594
2595     /* Add an end-of-string marker at the end.  */
2596     canonical[dest] = LT_EOS_CHAR;
2597   }
2598
2599   /* Assign new value.  */
2600   *pcanonical = canonical;
2601
2602   return 0;
2603 }
2604
2605 static int
2606 argzize_path (path, pargz, pargz_len)
2607      const char *path;
2608      char **pargz;
2609      size_t *pargz_len;
2610 {
2611   error_t error;
2612
2613   assert (path);
2614   assert (pargz);
2615   assert (pargz_len);
2616
2617   if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len)))
2618     {
2619       switch (error)
2620         {
2621         case ENOMEM:
2622           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
2623           break;
2624         default:
2625           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
2626           break;
2627         }
2628
2629       return 1;
2630     }
2631
2632   return 0;
2633 }
2634
2635 /* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element
2636    of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns
2637    non-zero or all elements are exhausted.  If BASE_NAME is non-NULL,
2638    it is appended to each SEARCH_PATH element before FUNC is called.  */
2639 static int
2640 foreach_dirinpath (search_path, base_name, func, data1, data2)
2641      const char *search_path;
2642      const char *base_name;
2643      foreach_callback_func *func;
2644      lt_ptr data1;
2645      lt_ptr data2;
2646 {
2647   int    result         = 0;
2648   int    filenamesize   = 0;
2649   size_t lenbase        = LT_STRLEN (base_name);
2650   size_t argz_len       = 0;
2651   char *argz            = 0;
2652   char *filename        = 0;
2653   char *canonical       = 0;
2654
2655   LT_DLMUTEX_LOCK ();
2656
2657   if (!search_path || !*search_path)
2658     {
2659       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
2660       goto cleanup;
2661     }
2662
2663   if (canonicalize_path (search_path, &canonical) != 0)
2664     goto cleanup;
2665
2666   if (argzize_path (canonical, &argz, &argz_len) != 0)
2667     goto cleanup;
2668
2669   {
2670     char *dir_name = 0;
2671     while ((dir_name = argz_next (argz, argz_len, dir_name)))
2672       {
2673         size_t lendir = LT_STRLEN (dir_name);
2674
2675         if (lendir +1 +lenbase >= filenamesize)
2676         {
2677           LT_DLFREE (filename);
2678           filenamesize  = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */
2679           filename      = LT_EMALLOC (char, filenamesize);
2680           if (!filename)
2681             goto cleanup;
2682         }
2683
2684         assert (filenamesize > lendir);
2685         strcpy (filename, dir_name);
2686
2687         if (base_name && *base_name)
2688           {
2689             if (filename[lendir -1] != '/')
2690               filename[lendir++] = '/';
2691             strcpy (filename +lendir, base_name);
2692           }
2693
2694         if ((result = (*func) (filename, data1, data2)))
2695           {
2696             break;
2697           }
2698       }
2699   }
2700
2701  cleanup:
2702   LT_DLFREE (argz);
2703   LT_DLFREE (canonical);
2704   LT_DLFREE (filename);
2705
2706   LT_DLMUTEX_UNLOCK ();
2707
2708   return result;
2709 }
2710
2711 /* If FILEPATH can be opened, store the name of the directory component
2712    in DATA1, and the opened FILE* structure address in DATA2.  Otherwise
2713    DATA1 is unchanged, but DATA2 is set to a pointer to NULL.  */
2714 static int
2715 find_file_callback (filename, data1, data2)
2716      char *filename;
2717      lt_ptr data1;
2718      lt_ptr data2;
2719 {
2720   char       **pdir     = (char **) data1;
2721   FILE       **pfile    = (FILE **) data2;
2722   int        is_done    = 0;
2723
2724   assert (filename && *filename);
2725   assert (pdir);
2726   assert (pfile);
2727
2728   if ((*pfile = fopen (filename, LT_READTEXT_MODE)))
2729     {
2730       char *dirend = strrchr (filename, '/');
2731
2732       if (dirend > filename)
2733         *dirend   = LT_EOS_CHAR;
2734
2735       LT_DLFREE (*pdir);
2736       *pdir   = lt_estrdup (filename);
2737       is_done = (*pdir == 0) ? -1 : 1;
2738     }
2739
2740   return is_done;
2741 }
2742
2743 static FILE *
2744 find_file (search_path, base_name, pdir)
2745      const char *search_path;
2746      const char *base_name;
2747      char **pdir;
2748 {
2749   FILE *file = 0;
2750
2751   foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file);
2752
2753   return file;
2754 }
2755
2756 static int
2757 find_handle_callback (filename, data, ignored)
2758      char *filename;
2759      lt_ptr data;
2760      lt_ptr ignored;
2761 {
2762   lt_dlhandle  *handle          = (lt_dlhandle *) data;
2763   int           notfound        = access (filename, R_OK);
2764
2765   /* Bail out if file cannot be read...  */
2766   if (notfound)
2767     return 0;
2768
2769   /* Try to dlopen the file, but do not continue searching in any
2770      case.  */
2771   if (tryall_dlopen (handle, filename) != 0)
2772     *handle = 0;
2773
2774   return 1;
2775 }
2776
2777 /* If HANDLE was found return it, otherwise return 0.  If HANDLE was
2778    found but could not be opened, *HANDLE will be set to 0.  */
2779 static lt_dlhandle *
2780 find_handle (search_path, base_name, handle)
2781      const char *search_path;
2782      const char *base_name;
2783      lt_dlhandle *handle;
2784 {
2785   if (!search_path)
2786     return 0;
2787
2788   if (!foreach_dirinpath (search_path, base_name, find_handle_callback,
2789                           handle, 0))
2790     return 0;
2791
2792   return handle;
2793 }
2794
2795 static int
2796 load_deplibs (handle, deplibs)
2797      lt_dlhandle handle;
2798      char *deplibs;
2799 {
2800 #if LTDL_DLOPEN_DEPLIBS
2801   char  *p, *save_search_path = 0;
2802   int   depcount = 0;
2803   int   i;
2804   char  **names = 0;
2805 #endif
2806   int   errors = 0;
2807
2808   handle->depcount = 0;
2809
2810 #if LTDL_DLOPEN_DEPLIBS
2811   if (!deplibs)
2812     {
2813       return errors;
2814     }
2815   ++errors;
2816
2817   LT_DLMUTEX_LOCK ();
2818   if (user_search_path)
2819     {
2820       save_search_path = lt_estrdup (user_search_path);
2821       if (!save_search_path)
2822         goto cleanup;
2823     }
2824
2825   /* extract search paths and count deplibs */
2826   p = deplibs;
2827   while (*p)
2828     {
2829       if (!isspace ((int) *p))
2830         {
2831           char *end = p+1;
2832           while (*end && !isspace((int) *end))
2833             {
2834               ++end;
2835             }
2836
2837           if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0)
2838             {
2839               char save = *end;
2840               *end = 0; /* set a temporary string terminator */
2841               if (lt_dladdsearchdir(p+2))
2842                 {
2843                   goto cleanup;
2844                 }
2845               *end = save;
2846             }
2847           else
2848             {
2849               ++depcount;
2850             }
2851
2852           p = end;
2853         }
2854       else
2855         {
2856           ++p;
2857         }
2858     }
2859
2860   /* restore the old search path */
2861   LT_DLFREE (user_search_path);
2862   user_search_path = save_search_path;
2863
2864   LT_DLMUTEX_UNLOCK ();
2865
2866   if (!depcount)
2867     {
2868       errors = 0;
2869       goto cleanup;
2870     }
2871
2872   names = LT_EMALLOC (char *, depcount * sizeof (char*));
2873   if (!names)
2874     goto cleanup;
2875
2876   /* now only extract the actual deplibs */
2877   depcount = 0;
2878   p = deplibs;
2879   while (*p)
2880     {
2881       if (isspace ((int) *p))
2882         {
2883           ++p;
2884         }
2885       else
2886         {
2887           char *end = p+1;
2888           while (*end && !isspace ((int) *end))
2889             {
2890               ++end;
2891             }
2892
2893           if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0)
2894             {
2895               char *name;
2896               char save = *end;
2897               *end = 0; /* set a temporary string terminator */
2898               if (strncmp(p, "-l", 2) == 0)
2899                 {
2900                   size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2);
2901                   name = LT_EMALLOC (char, 1+ name_len);
2902                   if (name)
2903                     sprintf (name, "lib%s", p+2);
2904                 }
2905               else
2906                 name = lt_estrdup(p);
2907
2908               if (!name)
2909                 goto cleanup_names;
2910
2911               names[depcount++] = name;
2912               *end = save;
2913             }
2914           p = end;
2915         }
2916     }
2917
2918   /* load the deplibs (in reverse order)
2919      At this stage, don't worry if the deplibs do not load correctly,
2920      they may already be statically linked into the loading application
2921      for instance.  There will be a more enlightening error message
2922      later on if the loaded module cannot resolve all of its symbols.  */
2923   if (depcount)
2924     {
2925       int       j = 0;
2926
2927       handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount);
2928       if (!handle->deplibs)
2929         goto cleanup;
2930
2931       for (i = 0; i < depcount; ++i)
2932         {
2933           handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]);
2934           if (handle->deplibs[j])
2935             {
2936               ++j;
2937             }
2938         }
2939
2940       handle->depcount  = j;    /* Number of successfully loaded deplibs */
2941       errors            = 0;
2942     }
2943
2944  cleanup_names:
2945   for (i = 0; i < depcount; ++i)
2946     {
2947       LT_DLFREE (names[i]);
2948     }
2949
2950  cleanup:
2951   LT_DLFREE (names);
2952 #endif
2953
2954   return errors;
2955 }
2956
2957 static int
2958 unload_deplibs (handle)
2959      lt_dlhandle handle;
2960 {
2961   int i;
2962   int errors = 0;
2963
2964   if (handle->depcount)
2965     {
2966       for (i = 0; i < handle->depcount; ++i)
2967         {
2968           if (!LT_DLIS_RESIDENT (handle->deplibs[i]))
2969             {
2970               errors += lt_dlclose (handle->deplibs[i]);
2971             }
2972         }
2973     }
2974
2975   return errors;
2976 }
2977
2978 static int
2979 trim (dest, str)
2980      char **dest;
2981      const char *str;
2982 {
2983   /* remove the leading and trailing "'" from str
2984      and store the result in dest */
2985   const char *end   = strrchr (str, '\'');
2986   size_t len        = LT_STRLEN (str);
2987   char *tmp;
2988
2989   LT_DLFREE (*dest);
2990
2991   if (len > 3 && str[0] == '\'')
2992     {
2993       tmp = LT_EMALLOC (char, end - str);
2994       if (!tmp)
2995         return 1;
2996
2997       strncpy(tmp, &str[1], (end - str) - 1);
2998       tmp[len-3] = LT_EOS_CHAR;
2999       *dest = tmp;
3000     }
3001   else
3002     {
3003       *dest = 0;
3004     }
3005
3006   return 0;
3007 }
3008
3009 static int
3010 free_vars (dlname, oldname, libdir, deplibs)
3011      char *dlname;
3012      char *oldname;
3013      char *libdir;
3014      char *deplibs;
3015 {
3016   LT_DLFREE (dlname);
3017   LT_DLFREE (oldname);
3018   LT_DLFREE (libdir);
3019   LT_DLFREE (deplibs);
3020
3021   return 0;
3022 }
3023
3024 static int
3025 try_dlopen (phandle, filename)
3026      lt_dlhandle *phandle;
3027      const char *filename;
3028 {
3029   const char *  ext             = 0;
3030   const char *  saved_error     = 0;
3031   char *        canonical       = 0;
3032   char *        base_name       = 0;
3033   char *        dir             = 0;
3034   char *        name            = 0;
3035   int           errors          = 0;
3036   lt_dlhandle   newhandle;
3037
3038   assert (phandle);
3039   assert (*phandle == 0);
3040
3041   LT_DLMUTEX_GETERROR (saved_error);
3042
3043   /* dlopen self? */
3044   if (!filename)
3045     {
3046       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
3047       if (*phandle == 0)
3048         return 1;
3049
3050       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
3051       newhandle = *phandle;
3052
3053       /* lt_dlclose()ing yourself is very bad!  Disallow it.  */
3054       LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG);
3055
3056       if (tryall_dlopen (&newhandle, 0) != 0)
3057         {
3058           LT_DLFREE (*phandle);
3059           return 1;
3060         }
3061
3062       goto register_handle;
3063     }
3064
3065   assert (filename && *filename);
3066
3067   /* Doing this immediately allows internal functions to safely
3068      assume only canonicalized paths are passed.  */
3069   if (canonicalize_path (filename, &canonical) != 0)
3070     {
3071       ++errors;
3072       goto cleanup;
3073     }
3074
3075   /* If the canonical module name is a path (relative or absolute)
3076      then split it into a directory part and a name part.  */
3077   base_name = strrchr (canonical, '/');
3078   if (base_name)
3079     {
3080       size_t dirlen = (1+ base_name) - canonical;
3081
3082       dir = LT_EMALLOC (char, 1+ dirlen);
3083       if (!dir)
3084         {
3085           ++errors;
3086           goto cleanup;
3087         }
3088
3089       strncpy (dir, canonical, dirlen);
3090       dir[dirlen] = LT_EOS_CHAR;
3091
3092       ++base_name;
3093     }
3094   else
3095     LT_DLMEM_REASSIGN (base_name, canonical);
3096
3097   assert (base_name && *base_name);
3098
3099   /* Check whether we are opening a libtool module (.la extension).  */
3100   ext = strrchr (base_name, '.');
3101   if (ext && strcmp (ext, archive_ext) == 0)
3102     {
3103       /* this seems to be a libtool module */
3104       FILE *    file     = 0;
3105       char *    dlname   = 0;
3106       char *    old_name = 0;
3107       char *    libdir   = 0;
3108       char *    deplibs  = 0;
3109       char *    line     = 0;
3110       size_t    line_len;
3111
3112       /* if we can't find the installed flag, it is probably an
3113          installed libtool archive, produced with an old version
3114          of libtool */
3115       int       installed = 1;
3116
3117       /* extract the module name from the file name */
3118       name = LT_EMALLOC (char, ext - base_name + 1);
3119       if (!name)
3120         {
3121           ++errors;
3122           goto cleanup;
3123         }
3124
3125       /* canonicalize the module name */
3126       {
3127         size_t i;
3128         for (i = 0; i < ext - base_name; ++i)
3129           {
3130             if (isalnum ((int)(base_name[i])))
3131               {
3132                 name[i] = base_name[i];
3133               }
3134             else
3135               {
3136                 name[i] = '_';
3137               }
3138           }
3139         name[ext - base_name] = LT_EOS_CHAR;
3140       }
3141
3142       /* Now try to open the .la file.  If there is no directory name
3143          component, try to find it first in user_search_path and then other
3144          prescribed paths.  Otherwise (or in any case if the module was not
3145          yet found) try opening just the module name as passed.  */
3146       if (!dir)
3147         {
3148           const char *search_path;
3149
3150           LT_DLMUTEX_LOCK ();
3151           search_path = user_search_path;
3152           if (search_path)
3153             file = find_file (user_search_path, base_name, &dir);
3154           LT_DLMUTEX_UNLOCK ();
3155
3156           if (!file)
3157             {
3158               search_path = getenv (LTDL_SEARCHPATH_VAR);
3159               if (search_path)
3160                 file = find_file (search_path, base_name, &dir);
3161             }
3162
3163 #ifdef LTDL_SHLIBPATH_VAR
3164           if (!file)
3165             {
3166               search_path = getenv (LTDL_SHLIBPATH_VAR);
3167               if (search_path)
3168                 file = find_file (search_path, base_name, &dir);
3169             }
3170 #endif
3171 #ifdef LTDL_SYSSEARCHPATH
3172           if (!file && sys_search_path)
3173             {
3174               file = find_file (sys_search_path, base_name, &dir);
3175             }
3176 #endif
3177         }
3178       if (!file)
3179         {
3180           file = fopen (filename, LT_READTEXT_MODE);
3181         }
3182
3183       /* If we didn't find the file by now, it really isn't there.  Set
3184          the status flag, and bail out.  */
3185       if (!file)
3186         {
3187           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
3188           ++errors;
3189           goto cleanup;
3190         }
3191
3192       line_len = LT_FILENAME_MAX;
3193       line = LT_EMALLOC (char, line_len);
3194       if (!line)
3195         {
3196           fclose (file);
3197           ++errors;
3198           goto cleanup;
3199         }
3200
3201       /* read the .la file */
3202       while (!feof (file))
3203         {
3204           if (!fgets (line, (int) line_len, file))
3205             {
3206               break;
3207             }
3208
3209           /* Handle the case where we occasionally need to read a line
3210              that is longer than the initial buffer size.  */
3211           while ((line[LT_STRLEN(line) -1] != '\n') && (!feof (file)))
3212             {
3213               line = LT_DLREALLOC (char, line, line_len *2);
3214               if (!fgets (&line[line_len -1], (int) line_len +1, file))
3215                 {
3216                   break;
3217                 }
3218               line_len *= 2;
3219             }
3220
3221           if (line[0] == '\n' || line[0] == '#')
3222             {
3223               continue;
3224             }
3225
3226 #undef  STR_DLNAME
3227 #define STR_DLNAME      "dlname="
3228           if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0)
3229             {
3230               errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]);
3231             }
3232
3233 #undef  STR_OLD_LIBRARY
3234 #define STR_OLD_LIBRARY "old_library="
3235           else if (strncmp (line, STR_OLD_LIBRARY,
3236                             sizeof (STR_OLD_LIBRARY) - 1) == 0)
3237             {
3238               errors += trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]);
3239             }
3240 #undef  STR_LIBDIR
3241 #define STR_LIBDIR      "libdir="
3242           else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0)
3243             {
3244               errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]);
3245             }
3246
3247 #undef  STR_DL_DEPLIBS
3248 #define STR_DL_DEPLIBS  "dependency_libs="
3249           else if (strncmp (line, STR_DL_DEPLIBS,
3250                             sizeof (STR_DL_DEPLIBS) - 1) == 0)
3251             {
3252               errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]);
3253             }
3254           else if (strcmp (line, "installed=yes\n") == 0)
3255             {
3256               installed = 1;
3257             }
3258           else if (strcmp (line, "installed=no\n") == 0)
3259             {
3260               installed = 0;
3261             }
3262
3263 #undef  STR_LIBRARY_NAMES
3264 #define STR_LIBRARY_NAMES "library_names="
3265           else if (! dlname && strncmp (line, STR_LIBRARY_NAMES,
3266                                         sizeof (STR_LIBRARY_NAMES) - 1) == 0)
3267             {
3268               char *last_libname;
3269               errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]);
3270               if (!errors
3271                   && dlname
3272                   && (last_libname = strrchr (dlname, ' ')) != 0)
3273                 {
3274                   last_libname = lt_estrdup (last_libname + 1);
3275                   if (!last_libname)
3276                     {
3277                       ++errors;
3278                       goto cleanup;
3279                     }
3280                   LT_DLMEM_REASSIGN (dlname, last_libname);
3281                 }
3282             }
3283
3284           if (errors)
3285             break;
3286         }
3287
3288       fclose (file);
3289       LT_DLFREE (line);
3290
3291       /* allocate the handle */
3292       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
3293       if (*phandle == 0)
3294         ++errors;
3295
3296       if (errors)
3297         {
3298           free_vars (dlname, old_name, libdir, deplibs);
3299           LT_DLFREE (*phandle);
3300           goto cleanup;
3301         }
3302
3303       assert (*phandle);
3304
3305       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
3306       if (load_deplibs (*phandle, deplibs) == 0)
3307         {
3308           newhandle = *phandle;
3309           /* find_module may replace newhandle */
3310           if (find_module (&newhandle, dir, libdir, dlname, old_name, installed))
3311             {
3312               unload_deplibs (*phandle);
3313               ++errors;
3314             }
3315         }
3316       else
3317         {
3318           ++errors;
3319         }
3320
3321       free_vars (dlname, old_name, libdir, deplibs);
3322       if (errors)
3323         {
3324           LT_DLFREE (*phandle);
3325           goto cleanup;
3326         }
3327
3328       if (*phandle != newhandle)
3329         {
3330           unload_deplibs (*phandle);
3331         }
3332     }
3333   else
3334     {
3335       /* not a libtool module */
3336       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
3337       if (*phandle == 0)
3338         {
3339           ++errors;
3340           goto cleanup;
3341         }
3342
3343       memset (*phandle, 0, sizeof (struct lt_dlhandle_struct));
3344       newhandle = *phandle;
3345
3346       /* If the module has no directory name component, try to find it
3347          first in user_search_path and then other prescribed paths.
3348          Otherwise (or in any case if the module was not yet found) try
3349          opening just the module name as passed.  */
3350       if ((dir || (!find_handle (user_search_path, base_name, &newhandle)
3351                    && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name,
3352                                     &newhandle)
3353 #ifdef LTDL_SHLIBPATH_VAR
3354                    && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name,
3355                                     &newhandle)
3356 #endif
3357 #ifdef LTDL_SYSSEARCHPATH
3358                    && !find_handle (sys_search_path, base_name, &newhandle)
3359 #endif
3360                    )))
3361         {
3362           if (tryall_dlopen (&newhandle, filename) != 0)
3363             {
3364               newhandle = NULL;
3365             }
3366         }
3367
3368       if (!newhandle)
3369         {
3370           LT_DLFREE (*phandle);
3371           ++errors;
3372           goto cleanup;
3373         }
3374     }
3375
3376  register_handle:
3377   LT_DLMEM_REASSIGN (*phandle, newhandle);
3378
3379   if ((*phandle)->info.ref_count == 0)
3380     {
3381       (*phandle)->info.ref_count        = 1;
3382       LT_DLMEM_REASSIGN ((*phandle)->info.name, name);
3383
3384       LT_DLMUTEX_LOCK ();
3385       (*phandle)->next          = handles;
3386       handles                   = *phandle;
3387       LT_DLMUTEX_UNLOCK ();
3388     }
3389
3390   LT_DLMUTEX_SETERROR (saved_error);
3391
3392  cleanup:
3393   LT_DLFREE (dir);
3394   LT_DLFREE (name);
3395   LT_DLFREE (canonical);
3396
3397   return errors;
3398 }
3399
3400 lt_dlhandle
3401 lt_dlopen (filename)
3402      const char *filename;
3403 {
3404   lt_dlhandle handle = 0;
3405
3406   /* Just incase we missed a code path in try_dlopen() that reports
3407      an error, but forgets to reset handle... */
3408   if (try_dlopen (&handle, filename) != 0)
3409     return 0;
3410
3411   return handle;
3412 }
3413
3414 /* If the last error messge store was `FILE_NOT_FOUND', then return
3415    non-zero.  */
3416 static int
3417 file_not_found ()
3418 {
3419   const char *error = 0;
3420
3421   LT_DLMUTEX_GETERROR (error);
3422   if (error == LT_DLSTRERROR (FILE_NOT_FOUND))
3423     return 1;
3424
3425   return 0;
3426 }
3427
3428 /* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to
3429    open the FILENAME as passed.  Otherwise try appending ARCHIVE_EXT,
3430    and if a file is still not found try again with SHLIB_EXT appended
3431    instead.  */
3432 lt_dlhandle
3433 lt_dlopenext (filename)
3434      const char *filename;
3435 {
3436   lt_dlhandle   handle          = 0;
3437   char *        tmp             = 0;
3438   char *        ext             = 0;
3439   size_t        len;
3440   int           errors          = 0;
3441
3442   if (!filename)
3443     {
3444       return lt_dlopen (filename);
3445     }
3446
3447   assert (filename);
3448
3449   len = LT_STRLEN (filename);
3450   ext = strrchr (filename, '.');
3451
3452   /* If FILENAME already bears a suitable extension, there is no need
3453      to try appending additional extensions.  */
3454   if (ext && ((strcmp (ext, archive_ext) == 0)
3455 #ifdef LTDL_SHLIB_EXT
3456               || (strcmp (ext, shlib_ext) == 0)
3457 #endif
3458       ))
3459     {
3460       return lt_dlopen (filename);
3461     }
3462
3463   /* First try appending ARCHIVE_EXT.  */
3464   tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1);
3465   if (!tmp)
3466     return 0;
3467
3468   strcpy (tmp, filename);
3469   strcat (tmp, archive_ext);
3470   errors = try_dlopen (&handle, tmp);
3471
3472   /* If we found FILENAME, stop searching -- whether we were able to
3473      load the file as a module or not.  If the file exists but loading
3474      failed, it is better to return an error message here than to
3475      report FILE_NOT_FOUND when the alternatives (foo.so etc) are not
3476      in the module search path.  */
3477   if (handle || ((errors > 0) && !file_not_found ()))
3478     {
3479       LT_DLFREE (tmp);
3480       return handle;
3481     }
3482
3483 #ifdef LTDL_SHLIB_EXT
3484   /* Try appending SHLIB_EXT.   */
3485   if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext))
3486     {
3487       LT_DLFREE (tmp);
3488       tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1);
3489       if (!tmp)
3490         return 0;
3491
3492       strcpy (tmp, filename);
3493     }
3494   else
3495     {
3496       tmp[len] = LT_EOS_CHAR;
3497     }
3498
3499   strcat(tmp, shlib_ext);
3500   errors = try_dlopen (&handle, tmp);
3501
3502   /* As before, if the file was found but loading failed, return now
3503      with the current error message.  */
3504   if (handle || ((errors > 0) && !file_not_found ()))
3505     {
3506       LT_DLFREE (tmp);
3507       return handle;
3508     }
3509 #endif
3510
3511   /* Still here?  Then we really did fail to locate any of the file
3512      names we tried.  */
3513   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
3514   LT_DLFREE (tmp);
3515   return 0;
3516 }
3517
3518
3519 static int
3520 lt_argz_insert (pargz, pargz_len, before, entry)
3521      char **pargz;
3522      size_t *pargz_len;
3523      char *before;
3524      const char *entry;
3525 {
3526   error_t error;
3527
3528   if ((error = argz_insert (pargz, pargz_len, before, entry)))
3529     {
3530       switch (error)
3531         {
3532         case ENOMEM:
3533           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
3534           break;
3535         default:
3536           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
3537           break;
3538         }
3539       return 1;
3540     }
3541
3542   return 0;
3543 }
3544
3545 static int
3546 lt_argz_insertinorder (pargz, pargz_len, entry)
3547      char **pargz;
3548      size_t *pargz_len;
3549      const char *entry;
3550 {
3551   char *before = 0;
3552
3553   assert (pargz);
3554   assert (pargz_len);
3555   assert (entry && *entry);
3556
3557   if (*pargz)
3558     while ((before = argz_next (*pargz, *pargz_len, before)))
3559       {
3560         int cmp = strcmp (entry, before);
3561
3562         if (cmp < 0)  break;
3563         if (cmp == 0) return 0; /* No duplicates! */
3564       }
3565
3566   return lt_argz_insert (pargz, pargz_len, before, entry);
3567 }
3568
3569 static int
3570 lt_argz_insertdir (pargz, pargz_len, dirnam, dp)
3571      char **pargz;
3572      size_t *pargz_len;
3573      const char *dirnam;
3574      struct dirent *dp;
3575 {
3576   char   *buf       = 0;
3577   size_t buf_len    = 0;
3578   char   *end       = 0;
3579   size_t end_offset = 0;
3580   size_t dir_len    = 0;
3581   int    errors     = 0;
3582
3583   assert (pargz);
3584   assert (pargz_len);
3585   assert (dp);
3586
3587   dir_len = LT_STRLEN (dirnam);
3588   end     = dp->d_name + LT_D_NAMLEN(dp);
3589
3590   /* Ignore version numbers.  */
3591   {
3592     char *p;
3593     for (p = end; p -1 > dp->d_name; --p)
3594       if (strchr (".0123456789", p[-1]) == 0)
3595         break;
3596
3597     if (*p == '.')
3598       end = p;
3599   }
3600
3601   /* Ignore filename extension.  */
3602   {
3603     char *p;
3604     for (p = end -1; p > dp->d_name; --p)
3605       if (*p == '.')
3606         {
3607           end = p;
3608           break;
3609         }
3610   }
3611
3612   /* Prepend the directory name.  */
3613   end_offset    = end - dp->d_name;
3614   buf_len       = dir_len + 1+ end_offset;
3615   buf           = LT_EMALLOC (char, 1+ buf_len);
3616   if (!buf)
3617     return ++errors;
3618
3619   assert (buf);
3620
3621   strcpy  (buf, dirnam);
3622   strcat  (buf, "/");
3623   strncat (buf, dp->d_name, end_offset);
3624   buf[buf_len] = LT_EOS_CHAR;
3625
3626   /* Try to insert (in order) into ARGZ/ARGZ_LEN.  */
3627   if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0)
3628     ++errors;
3629
3630   LT_DLFREE (buf);
3631
3632   return errors;
3633 }
3634
3635 static int
3636 list_files_by_dir (dirnam, pargz, pargz_len)
3637      const char *dirnam;
3638      char **pargz;
3639      size_t *pargz_len;
3640 {
3641   DIR   *dirp     = 0;
3642   int    errors   = 0;
3643
3644   assert (dirnam && *dirnam);
3645   assert (pargz);
3646   assert (pargz_len);
3647   assert (dirnam[LT_STRLEN(dirnam) -1] != '/');
3648
3649   dirp = opendir (dirnam);
3650   if (dirp)
3651     {
3652       struct dirent *dp = 0;
3653
3654       while ((dp = readdir (dirp)))
3655         if (dp->d_name[0] != '.')
3656           if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp))
3657             {
3658               ++errors;
3659               break;
3660             }
3661
3662       closedir (dirp);
3663     }
3664   else
3665     ++errors;
3666
3667   return errors;
3668 }
3669
3670
3671 /* If there are any files in DIRNAME, call the function passed in
3672    DATA1 (with the name of each file and DATA2 as arguments).  */
3673 static int
3674 foreachfile_callback (dirname, data1, data2)
3675      char *dirname;
3676      lt_ptr data1;
3677      lt_ptr data2;
3678 {
3679   int (*func) LT_PARAMS((const char *filename, lt_ptr data))
3680         = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1;
3681
3682   int     is_done  = 0;
3683   char   *argz     = 0;
3684   size_t  argz_len = 0;
3685
3686   if (list_files_by_dir (dirname, &argz, &argz_len) != 0)
3687     goto cleanup;
3688   if (!argz)
3689     goto cleanup;
3690
3691   {
3692     char *filename = 0;
3693     while ((filename = argz_next (argz, argz_len, filename)))
3694       if ((is_done = (*func) (filename, data2)))
3695         break;
3696   }
3697
3698  cleanup:
3699   LT_DLFREE (argz);
3700
3701   return is_done;
3702 }
3703
3704
3705 /* Call FUNC for each unique extensionless file in SEARCH_PATH, along
3706    with DATA.  The filenames passed to FUNC would be suitable for
3707    passing to lt_dlopenext.  The extensions are stripped so that
3708    individual modules do not generate several entries (e.g. libfoo.la,
3709    libfoo.so, libfoo.so.1, libfoo.so.1.0.0).  If SEARCH_PATH is NULL,
3710    then the same directories that lt_dlopen would search are examined.  */
3711 int
3712 lt_dlforeachfile (search_path, func, data)
3713      const char *search_path;
3714      int (*func) LT_PARAMS ((const char *filename, lt_ptr data));
3715      lt_ptr data;
3716 {
3717   int is_done = 0;
3718
3719   if (search_path)
3720     {
3721       /* If a specific path was passed, search only the directories
3722          listed in it.  */
3723       is_done = foreach_dirinpath (search_path, 0,
3724                                    foreachfile_callback, func, data);
3725     }
3726   else
3727     {
3728       /* Otherwise search the default paths.  */
3729       is_done = foreach_dirinpath (user_search_path, 0,
3730                                    foreachfile_callback, func, data);
3731       if (!is_done)
3732         {
3733           is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0,
3734                                        foreachfile_callback, func, data);
3735         }
3736
3737 #ifdef LTDL_SHLIBPATH_VAR
3738       if (!is_done)
3739         {
3740           is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0,
3741                                        foreachfile_callback, func, data);
3742         }
3743 #endif
3744 #ifdef LTDL_SYSSEARCHPATH
3745       if (!is_done)
3746         {
3747           is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0,
3748                                        foreachfile_callback, func, data);
3749         }
3750 #endif
3751     }
3752
3753   return is_done;
3754 }
3755
3756 int
3757 lt_dlclose (handle)
3758      lt_dlhandle handle;
3759 {
3760   lt_dlhandle cur, last;
3761   int errors = 0;
3762
3763   LT_DLMUTEX_LOCK ();
3764
3765   /* check whether the handle is valid */
3766   last = cur = handles;
3767   while (cur && handle != cur)
3768     {
3769       last = cur;
3770       cur = cur->next;
3771     }
3772
3773   if (!cur)
3774     {
3775       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
3776       ++errors;
3777       goto done;
3778     }
3779
3780   handle->info.ref_count--;
3781
3782   /* Note that even with resident modules, we must track the ref_count
3783      correctly incase the user decides to reset the residency flag
3784      later (even though the API makes no provision for that at the
3785      moment).  */
3786   if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle))
3787     {
3788       lt_user_data data = handle->loader->dlloader_data;
3789
3790       if (handle != handles)
3791         {
3792           last->next = handle->next;
3793         }
3794       else
3795         {
3796           handles = handle->next;
3797         }
3798
3799       errors += handle->loader->module_close (data, handle->module);
3800       errors += unload_deplibs(handle);
3801
3802       /* It is up to the callers to free the data itself.  */
3803       LT_DLFREE (handle->caller_data);
3804
3805       LT_DLFREE (handle->info.filename);
3806       LT_DLFREE (handle->info.name);
3807       LT_DLFREE (handle);
3808
3809       goto done;
3810     }
3811
3812   if (LT_DLIS_RESIDENT (handle))
3813     {
3814       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE));
3815       ++errors;
3816     }
3817
3818  done:
3819   LT_DLMUTEX_UNLOCK ();
3820
3821   return errors;
3822 }
3823
3824 lt_ptr
3825 lt_dlsym (handle, symbol)
3826      lt_dlhandle handle;
3827      const char *symbol;
3828 {
3829   size_t lensym;
3830   char  lsym[LT_SYMBOL_LENGTH];
3831   char  *sym;
3832   lt_ptr address;
3833   lt_user_data data;
3834
3835   if (!handle)
3836     {
3837       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
3838       return 0;
3839     }
3840
3841   if (!symbol)
3842     {
3843       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
3844       return 0;
3845     }
3846
3847   lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix)
3848                                         + LT_STRLEN (handle->info.name);
3849
3850   if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH)
3851     {
3852       sym = lsym;
3853     }
3854   else
3855     {
3856       sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1);
3857       if (!sym)
3858         {
3859           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW));
3860           return 0;
3861         }
3862     }
3863
3864   data = handle->loader->dlloader_data;
3865   if (handle->info.name)
3866     {
3867       const char *saved_error;
3868
3869       LT_DLMUTEX_GETERROR (saved_error);
3870
3871       /* this is a libtool module */
3872       if (handle->loader->sym_prefix)
3873         {
3874           strcpy(sym, handle->loader->sym_prefix);
3875           strcat(sym, handle->info.name);
3876         }
3877       else
3878         {
3879           strcpy(sym, handle->info.name);
3880         }
3881
3882       strcat(sym, "_LTX_");
3883       strcat(sym, symbol);
3884
3885       /* try "modulename_LTX_symbol" */
3886       address = handle->loader->find_sym (data, handle->module, sym);
3887       if (address)
3888         {
3889           if (sym != lsym)
3890             {
3891               LT_DLFREE (sym);
3892             }
3893           return address;
3894         }
3895       LT_DLMUTEX_SETERROR (saved_error);
3896     }
3897
3898   /* otherwise try "symbol" */
3899   if (handle->loader->sym_prefix)
3900     {
3901       strcpy(sym, handle->loader->sym_prefix);
3902       strcat(sym, symbol);
3903     }
3904   else
3905     {
3906       strcpy(sym, symbol);
3907     }
3908
3909   address = handle->loader->find_sym (data, handle->module, sym);
3910   if (sym != lsym)
3911     {
3912       LT_DLFREE (sym);
3913     }
3914
3915   return address;
3916 }
3917
3918 const char *
3919 lt_dlerror ()
3920 {
3921   const char *error;
3922
3923   LT_DLMUTEX_GETERROR (error);
3924   LT_DLMUTEX_SETERROR (0);
3925
3926   return error ? error : LT_DLSTRERROR (UNKNOWN);
3927 }
3928
3929 static int
3930 lt_dlpath_insertdir (ppath, before, dir)
3931      char **ppath;
3932      char *before;
3933      const char *dir;
3934 {
3935   int    errors         = 0;
3936   char  *canonical      = 0;
3937   char  *argz           = 0;
3938   size_t argz_len       = 0;
3939
3940   assert (ppath);
3941   assert (dir && *dir);
3942
3943   if (canonicalize_path (dir, &canonical) != 0)
3944     {
3945       ++errors;
3946       goto cleanup;
3947     }
3948
3949   assert (canonical && *canonical);
3950
3951   /* If *PPATH is empty, set it to DIR.  */
3952   if (*ppath == 0)
3953     {
3954       assert (!before);         /* BEFORE cannot be set without PPATH.  */
3955       assert (dir);             /* Without DIR, don't call this function!  */
3956
3957       *ppath = lt_estrdup (dir);
3958       if (*ppath == 0)
3959         ++errors;
3960
3961       return errors;
3962     }
3963
3964   assert (ppath && *ppath);
3965
3966   if (argzize_path (*ppath, &argz, &argz_len) != 0)
3967     {
3968       ++errors;
3969       goto cleanup;
3970     }
3971
3972   /* Convert BEFORE into an equivalent offset into ARGZ.  This only works
3973      if *PPATH is already canonicalized, and hence does not change length
3974      with respect to ARGZ.  We canonicalize each entry as it is added to
3975      the search path, and don't call this function with (uncanonicalized)
3976      user paths, so this is a fair assumption.  */
3977   if (before)
3978     {
3979       assert (*ppath <= before);
3980       assert (before - *ppath <= strlen (*ppath));
3981
3982       before = before - *ppath + argz;
3983     }
3984
3985   if (lt_argz_insert (&argz, &argz_len, before, dir) != 0)
3986     {
3987       ++errors;
3988       goto cleanup;
3989     }
3990
3991   argz_stringify (argz, argz_len, LT_PATHSEP_CHAR);
3992   LT_DLMEM_REASSIGN (*ppath,  argz);
3993
3994  cleanup:
3995   LT_DLFREE (canonical);
3996   LT_DLFREE (argz);
3997
3998   return errors;
3999 }
4000
4001 int
4002 lt_dladdsearchdir (search_dir)
4003      const char *search_dir;
4004 {
4005   int errors = 0;
4006
4007   if (search_dir && *search_dir)
4008     {
4009       LT_DLMUTEX_LOCK ();
4010       if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)
4011         ++errors;
4012       LT_DLMUTEX_UNLOCK ();
4013     }
4014
4015   return errors;
4016 }
4017
4018 int
4019 lt_dlinsertsearchdir (before, search_dir)
4020      const char *before;
4021      const char *search_dir;
4022 {
4023   int errors = 0;
4024
4025   if (before)
4026     {
4027       LT_DLMUTEX_LOCK ();
4028       if ((before < user_search_path)
4029           || (before >= user_search_path + LT_STRLEN (user_search_path)))
4030         {
4031           LT_DLMUTEX_UNLOCK ();
4032           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION));
4033           return 1;
4034         }
4035       LT_DLMUTEX_UNLOCK ();
4036     }
4037
4038   if (search_dir && *search_dir)
4039     {
4040       LT_DLMUTEX_LOCK ();
4041       if (lt_dlpath_insertdir (&user_search_path,
4042                                (char *) before, search_dir) != 0)
4043         {
4044           ++errors;
4045         }
4046       LT_DLMUTEX_UNLOCK ();
4047     }
4048
4049   return errors;
4050 }
4051
4052 int
4053 lt_dlsetsearchpath (search_path)
4054      const char *search_path;
4055 {
4056   int   errors      = 0;
4057
4058   LT_DLMUTEX_LOCK ();
4059   LT_DLFREE (user_search_path);
4060   LT_DLMUTEX_UNLOCK ();
4061
4062   if (!search_path || !LT_STRLEN (search_path))
4063     {
4064       return errors;
4065     }
4066
4067   LT_DLMUTEX_LOCK ();
4068   if (canonicalize_path (search_path, &user_search_path) != 0)
4069     ++errors;
4070   LT_DLMUTEX_UNLOCK ();
4071
4072   return errors;
4073 }
4074
4075 const char *
4076 lt_dlgetsearchpath ()
4077 {
4078   const char *saved_path;
4079
4080   LT_DLMUTEX_LOCK ();
4081   saved_path = user_search_path;
4082   LT_DLMUTEX_UNLOCK ();
4083
4084   return saved_path;
4085 }
4086
4087 int
4088 lt_dlmakeresident (handle)
4089      lt_dlhandle handle;
4090 {
4091   int errors = 0;
4092
4093   if (!handle)
4094     {
4095       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
4096       ++errors;
4097     }
4098   else
4099     {
4100       LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG);
4101     }
4102
4103   return errors;
4104 }
4105
4106 int
4107 lt_dlisresident (handle)
4108      lt_dlhandle handle;
4109 {
4110   if (!handle)
4111     {
4112       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
4113       return -1;
4114     }
4115
4116   return LT_DLIS_RESIDENT (handle);
4117 }
4118
4119
4120
4121 \f
4122 /* --- MODULE INFORMATION --- */
4123
4124 const lt_dlinfo *
4125 lt_dlgetinfo (handle)
4126      lt_dlhandle handle;
4127 {
4128   if (!handle)
4129     {
4130       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
4131       return 0;
4132     }
4133
4134   return &(handle->info);
4135 }
4136
4137 lt_dlhandle
4138 lt_dlhandle_next (place)
4139      lt_dlhandle place;
4140 {
4141   return place ? place->next : handles;
4142 }
4143
4144 int
4145 lt_dlforeach (func, data)
4146      int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data));
4147      lt_ptr data;
4148 {
4149   int errors = 0;
4150   lt_dlhandle cur;
4151
4152   LT_DLMUTEX_LOCK ();
4153
4154   cur = handles;
4155   while (cur)
4156     {
4157       lt_dlhandle tmp = cur;
4158
4159       cur = cur->next;
4160       if ((*func) (tmp, data))
4161         {
4162           ++errors;
4163           break;
4164         }
4165     }
4166
4167   LT_DLMUTEX_UNLOCK ();
4168
4169   return errors;
4170 }
4171
4172 lt_dlcaller_id
4173 lt_dlcaller_register ()
4174 {
4175   static lt_dlcaller_id last_caller_id = 0;
4176   int result;
4177
4178   LT_DLMUTEX_LOCK ();
4179   result = ++last_caller_id;
4180   LT_DLMUTEX_UNLOCK ();
4181
4182   return result;
4183 }
4184
4185 lt_ptr
4186 lt_dlcaller_set_data (key, handle, data)
4187      lt_dlcaller_id key;
4188      lt_dlhandle handle;
4189      lt_ptr data;
4190 {
4191   int n_elements = 0;
4192   lt_ptr stale = (lt_ptr) 0;
4193   int i;
4194
4195   /* This needs to be locked so that the caller data can be updated
4196      simultaneously by different threads.  */
4197   LT_DLMUTEX_LOCK ();
4198
4199   if (handle->caller_data)
4200     while (handle->caller_data[n_elements].key)
4201       ++n_elements;
4202
4203   for (i = 0; i < n_elements; ++i)
4204     {
4205       if (handle->caller_data[i].key == key)
4206         {
4207           stale = handle->caller_data[i].data;
4208           break;
4209         }
4210     }
4211
4212   /* Ensure that there is enough room in this handle's caller_data
4213      array to accept a new element (and an empty end marker).  */
4214   if (i == n_elements)
4215     {
4216       lt_caller_data *temp
4217         = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements);
4218
4219       if (!temp)
4220         {
4221           stale = 0;
4222           goto done;
4223         }
4224
4225       handle->caller_data = temp;
4226
4227       /* We only need this if we needed to allocate a new caller_data.  */
4228       handle->caller_data[i].key  = key;
4229       handle->caller_data[1+ i].key = 0;
4230     }
4231
4232   handle->caller_data[i].data = data;
4233
4234  done:
4235   LT_DLMUTEX_UNLOCK ();
4236
4237   return stale;
4238 }
4239
4240 lt_ptr
4241 lt_dlcaller_get_data  (key, handle)
4242      lt_dlcaller_id key;
4243      lt_dlhandle handle;
4244 {
4245   lt_ptr result = (lt_ptr) 0;
4246
4247   /* This needs to be locked so that the caller data isn't updated by
4248      another thread part way through this function.  */
4249   LT_DLMUTEX_LOCK ();
4250
4251   /* Locate the index of the element with a matching KEY.  */
4252   {
4253     int i;
4254     for (i = 0; handle->caller_data[i].key; ++i)
4255       {
4256         if (handle->caller_data[i].key == key)
4257           {
4258             result = handle->caller_data[i].data;
4259             break;
4260           }
4261       }
4262   }
4263
4264   LT_DLMUTEX_UNLOCK ();
4265
4266   return result;
4267 }
4268
4269
4270 \f
4271 /* --- USER MODULE LOADER API --- */
4272
4273
4274 int
4275 lt_dlloader_add (place, dlloader, loader_name)
4276      lt_dlloader *place;
4277      const struct lt_user_dlloader *dlloader;
4278      const char *loader_name;
4279 {
4280   int errors = 0;
4281   lt_dlloader *node = 0, *ptr = 0;
4282
4283   if ((dlloader == 0)   /* diagnose null parameters */
4284       || (dlloader->module_open == 0)
4285       || (dlloader->module_close == 0)
4286       || (dlloader->find_sym == 0))
4287     {
4288       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4289       return 1;
4290     }
4291
4292   /* Create a new dlloader node with copies of the user callbacks.  */
4293   node = LT_EMALLOC (lt_dlloader, 1);
4294   if (!node)
4295     return 1;
4296
4297   node->next            = 0;
4298   node->loader_name     = loader_name;
4299   node->sym_prefix      = dlloader->sym_prefix;
4300   node->dlloader_exit   = dlloader->dlloader_exit;
4301   node->module_open     = dlloader->module_open;
4302   node->module_close    = dlloader->module_close;
4303   node->find_sym        = dlloader->find_sym;
4304   node->dlloader_data   = dlloader->dlloader_data;
4305
4306   LT_DLMUTEX_LOCK ();
4307   if (!loaders)
4308     {
4309       /* If there are no loaders, NODE becomes the list! */
4310       loaders = node;
4311     }
4312   else if (!place)
4313     {
4314       /* If PLACE is not set, add NODE to the end of the
4315          LOADERS list. */
4316       for (ptr = loaders; ptr->next; ptr = ptr->next)
4317         {
4318           /*NOWORK*/;
4319         }
4320
4321       ptr->next = node;
4322     }
4323   else if (loaders == place)
4324     {
4325       /* If PLACE is the first loader, NODE goes first. */
4326       node->next = place;
4327       loaders = node;
4328     }
4329   else
4330     {
4331       /* Find the node immediately preceding PLACE. */
4332       for (ptr = loaders; ptr->next != place; ptr = ptr->next)
4333         {
4334           /*NOWORK*/;
4335         }
4336
4337       if (ptr->next != place)
4338         {
4339           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4340           ++errors;
4341         }
4342       else
4343         {
4344           /* Insert NODE between PTR and PLACE. */
4345           node->next = place;
4346           ptr->next  = node;
4347         }
4348     }
4349
4350   LT_DLMUTEX_UNLOCK ();
4351
4352   return errors;
4353 }
4354
4355 int
4356 lt_dlloader_remove (loader_name)
4357      const char *loader_name;
4358 {
4359   lt_dlloader *place = lt_dlloader_find (loader_name);
4360   lt_dlhandle handle;
4361   int errors = 0;
4362
4363   if (!place)
4364     {
4365       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4366       return 1;
4367     }
4368
4369   LT_DLMUTEX_LOCK ();
4370
4371   /* Fail if there are any open modules which use this loader. */
4372   for  (handle = handles; handle; handle = handle->next)
4373     {
4374       if (handle->loader == place)
4375         {
4376           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER));
4377           ++errors;
4378           goto done;
4379         }
4380     }
4381
4382   if (place == loaders)
4383     {
4384       /* PLACE is the first loader in the list. */
4385       loaders = loaders->next;
4386     }
4387   else
4388     {
4389       /* Find the loader before the one being removed. */
4390       lt_dlloader *prev;
4391       for (prev = loaders; prev->next; prev = prev->next)
4392         {
4393           if (!strcmp (prev->next->loader_name, loader_name))
4394             {
4395               break;
4396             }
4397         }
4398
4399       place = prev->next;
4400       prev->next = prev->next->next;
4401     }
4402
4403   if (place->dlloader_exit)
4404     {
4405       errors = place->dlloader_exit (place->dlloader_data);
4406     }
4407
4408   LT_DLFREE (place);
4409
4410  done:
4411   LT_DLMUTEX_UNLOCK ();
4412
4413   return errors;
4414 }
4415
4416 lt_dlloader *
4417 lt_dlloader_next (place)
4418      lt_dlloader *place;
4419 {
4420   lt_dlloader *next;
4421
4422   LT_DLMUTEX_LOCK ();
4423   next = place ? place->next : loaders;
4424   LT_DLMUTEX_UNLOCK ();
4425
4426   return next;
4427 }
4428
4429 const char *
4430 lt_dlloader_name (place)
4431      lt_dlloader *place;
4432 {
4433   const char *name = 0;
4434
4435   if (place)
4436     {
4437       LT_DLMUTEX_LOCK ();
4438       name = place ? place->loader_name : 0;
4439       LT_DLMUTEX_UNLOCK ();
4440     }
4441   else
4442     {
4443       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4444     }
4445
4446   return name;
4447 }
4448
4449 lt_user_data *
4450 lt_dlloader_data (place)
4451      lt_dlloader *place;
4452 {
4453   lt_user_data *data = 0;
4454
4455   if (place)
4456     {
4457       LT_DLMUTEX_LOCK ();
4458       data = place ? &(place->dlloader_data) : 0;
4459       LT_DLMUTEX_UNLOCK ();
4460     }
4461   else
4462     {
4463       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4464     }
4465
4466   return data;
4467 }
4468
4469 lt_dlloader *
4470 lt_dlloader_find (loader_name)
4471      const char *loader_name;
4472 {
4473   lt_dlloader *place = 0;
4474
4475   LT_DLMUTEX_LOCK ();
4476   for (place = loaders; place; place = place->next)
4477     {
4478       if (strcmp (place->loader_name, loader_name) == 0)
4479         {
4480           break;
4481         }
4482     }
4483   LT_DLMUTEX_UNLOCK ();
4484
4485   return place;
4486 }