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