Port "use_tunneled_reply" fix for MS-CHAP from branch_1_1
[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       LT_DLFREE (user_search_path);
2351     }
2352
2353  done:
2354   LT_DLMUTEX_UNLOCK ();
2355   return errors;
2356 }
2357
2358 static int
2359 tryall_dlopen (handle, filename)
2360      lt_dlhandle *handle;
2361      const char *filename;
2362 {
2363   lt_dlhandle    cur;
2364   lt_dlloader   *loader;
2365   const char    *saved_error;
2366   int            errors         = 0;
2367
2368   LT_DLMUTEX_GETERROR (saved_error);
2369   LT_DLMUTEX_LOCK ();
2370
2371   cur    = handles;
2372   loader = loaders;
2373
2374   /* check whether the module was already opened */
2375   while (cur)
2376     {
2377       /* try to dlopen the program itself? */
2378       if (!cur->info.filename && !filename)
2379         {
2380           break;
2381         }
2382
2383       if (cur->info.filename && filename
2384           && strcmp (cur->info.filename, filename) == 0)
2385         {
2386           break;
2387         }
2388
2389       cur = cur->next;
2390     }
2391
2392   if (cur)
2393     {
2394       ++cur->info.ref_count;
2395       *handle = cur;
2396       goto done;
2397     }
2398
2399   cur = *handle;
2400   if (filename)
2401     {
2402       /* Comment out the check of file permissions using access.
2403          This call seems to always return -1 with error EACCES.
2404       */
2405       /* We need to catch missing file errors early so that
2406          file_not_found() can detect what happened.
2407       if (access (filename, R_OK) != 0)
2408         {
2409           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
2410           ++errors;
2411           goto done;
2412         } */
2413
2414       cur->info.filename = lt_estrdup (filename);
2415       if (!cur->info.filename)
2416         {
2417           ++errors;
2418           goto done;
2419         }
2420     }
2421   else
2422     {
2423       cur->info.filename = 0;
2424     }
2425
2426   while (loader)
2427     {
2428       lt_user_data data = loader->dlloader_data;
2429
2430       cur->module = loader->module_open (data, filename);
2431
2432       if (cur->module != 0)
2433         {
2434           break;
2435         }
2436       loader = loader->next;
2437     }
2438
2439   if (!loader)
2440     {
2441       LT_DLFREE (cur->info.filename);
2442       ++errors;
2443       goto done;
2444     }
2445
2446   cur->loader   = loader;
2447   LT_DLMUTEX_SETERROR (saved_error);
2448
2449  done:
2450   LT_DLMUTEX_UNLOCK ();
2451
2452   return errors;
2453 }
2454
2455 static int
2456 tryall_dlopen_module (handle, prefix, dirname, dlname)
2457      lt_dlhandle *handle;
2458      const char *prefix;
2459      const char *dirname;
2460      const char *dlname;
2461 {
2462   int      error        = 0;
2463   char     *filename    = 0;
2464   size_t   filename_len = 0;
2465   size_t   dirname_len  = LT_STRLEN (dirname);
2466
2467   assert (handle);
2468   assert (dirname);
2469   assert (dlname);
2470 #ifdef LT_DIRSEP_CHAR
2471   /* Only canonicalized names (i.e. with DIRSEP chars already converted)
2472      should make it into this function:  */
2473   assert (strchr (dirname, LT_DIRSEP_CHAR) == 0);
2474 #endif
2475
2476   if (dirname_len > 0)
2477     if (dirname[dirname_len -1] == '/')
2478       --dirname_len;
2479   filename_len = dirname_len + 1 + LT_STRLEN (dlname);
2480
2481   /* Allocate memory, and combine DIRNAME and MODULENAME into it.
2482      The PREFIX (if any) is handled below.  */
2483   filename  = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1);
2484   if (!filename)
2485     return 1;
2486
2487   sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname);
2488
2489   /* Now that we have combined DIRNAME and MODULENAME, if there is
2490      also a PREFIX to contend with, simply recurse with the arguments
2491      shuffled.  Otherwise, attempt to open FILENAME as a module.  */
2492   if (prefix)
2493     {
2494       error += tryall_dlopen_module (handle,
2495                                      (const char *) 0, prefix, filename);
2496     }
2497   else if (tryall_dlopen (handle, filename) != 0)
2498     {
2499       ++error;
2500     }
2501
2502   LT_DLFREE (filename);
2503   return error;
2504 }
2505
2506 static int
2507 find_module (handle, dir, libdir, dlname, old_name, installed)
2508      lt_dlhandle *handle;
2509      const char *dir;
2510      const char *libdir;
2511      const char *dlname;
2512      const char *old_name;
2513      int installed;
2514 {
2515   /* Try to open the old library first; if it was dlpreopened,
2516      we want the preopened version of it, even if a dlopenable
2517      module is available.  */
2518   if (old_name && tryall_dlopen (handle, old_name) == 0)
2519     {
2520       return 0;
2521     }
2522
2523   /* Try to open the dynamic library.  */
2524   if (dlname)
2525     {
2526       /* try to open the installed module */
2527       if (installed && libdir)
2528         {
2529           if (tryall_dlopen_module (handle,
2530                                     (const char *) 0, libdir, dlname) == 0)
2531             return 0;
2532         }
2533
2534       /* try to open the not-installed module */
2535       if (!installed)
2536         {
2537           if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0)
2538             return 0;
2539         }
2540
2541       /* maybe it was moved to another directory */
2542       {
2543           if (tryall_dlopen_module (handle,
2544                                     (const char *) 0, dir, dlname) == 0)
2545             return 0;
2546       }
2547     }
2548
2549   return 1;
2550 }
2551
2552
2553 static int
2554 canonicalize_path (path, pcanonical)
2555      const char *path;
2556      char **pcanonical;
2557 {
2558   char *canonical = 0;
2559
2560   assert (path && *path);
2561   assert (pcanonical);
2562
2563   canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path));
2564   if (!canonical)
2565     return 1;
2566
2567   {
2568     size_t dest = 0;
2569     size_t src;
2570     for (src = 0; path[src] != LT_EOS_CHAR; ++src)
2571       {
2572         /* Path separators are not copied to the beginning or end of
2573            the destination, or if another separator would follow
2574            immediately.  */
2575         if (path[src] == LT_PATHSEP_CHAR)
2576           {
2577             if ((dest == 0)
2578                 || (path[1+ src] == LT_PATHSEP_CHAR)
2579                 || (path[1+ src] == LT_EOS_CHAR))
2580               continue;
2581           }
2582
2583         /* Anything other than a directory separator is copied verbatim.  */
2584         if ((path[src] != '/')
2585 #ifdef LT_DIRSEP_CHAR
2586             && (path[src] != LT_DIRSEP_CHAR)
2587 #endif
2588             )
2589           {
2590             canonical[dest++] = path[src];
2591           }
2592         /* Directory separators are converted and copied only if they are
2593            not at the end of a path -- i.e. before a path separator or
2594            NULL terminator.  */
2595         else if ((path[1+ src] != LT_PATHSEP_CHAR)
2596                  && (path[1+ src] != LT_EOS_CHAR)
2597 #ifdef LT_DIRSEP_CHAR
2598                  && (path[1+ src] != LT_DIRSEP_CHAR)
2599 #endif
2600                  && (path[1+ src] != '/'))
2601           {
2602             canonical[dest++] = '/';
2603           }
2604       }
2605
2606     /* Add an end-of-string marker at the end.  */
2607     canonical[dest] = LT_EOS_CHAR;
2608   }
2609
2610   /* Assign new value.  */
2611   *pcanonical = canonical;
2612
2613   return 0;
2614 }
2615
2616 static int
2617 argzize_path (path, pargz, pargz_len)
2618      const char *path;
2619      char **pargz;
2620      size_t *pargz_len;
2621 {
2622   error_t error;
2623
2624   assert (path);
2625   assert (pargz);
2626   assert (pargz_len);
2627
2628   if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len)))
2629     {
2630       switch (error)
2631         {
2632         case ENOMEM:
2633           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
2634           break;
2635         default:
2636           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
2637           break;
2638         }
2639
2640       return 1;
2641     }
2642
2643   return 0;
2644 }
2645
2646 /* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element
2647    of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns
2648    non-zero or all elements are exhausted.  If BASE_NAME is non-NULL,
2649    it is appended to each SEARCH_PATH element before FUNC is called.  */
2650 static int
2651 foreach_dirinpath (search_path, base_name, func, data1, data2)
2652      const char *search_path;
2653      const char *base_name;
2654      foreach_callback_func *func;
2655      lt_ptr data1;
2656      lt_ptr data2;
2657 {
2658   int    result         = 0;
2659   int    filenamesize   = 0;
2660   size_t lenbase        = LT_STRLEN (base_name);
2661   size_t argz_len       = 0;
2662   char *argz            = 0;
2663   char *filename        = 0;
2664   char *canonical       = 0;
2665
2666   LT_DLMUTEX_LOCK ();
2667
2668   if (!search_path || !*search_path)
2669     {
2670       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
2671       goto cleanup;
2672     }
2673
2674   if (canonicalize_path (search_path, &canonical) != 0)
2675     goto cleanup;
2676
2677   if (argzize_path (canonical, &argz, &argz_len) != 0)
2678     goto cleanup;
2679
2680   {
2681     char *dir_name = 0;
2682     while ((dir_name = argz_next (argz, argz_len, dir_name)))
2683       {
2684         size_t lendir = LT_STRLEN (dir_name);
2685
2686         if (lendir +1 +lenbase >= filenamesize)
2687         {
2688           LT_DLFREE (filename);
2689           filenamesize  = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */
2690           filename      = LT_EMALLOC (char, filenamesize);
2691           if (!filename)
2692             goto cleanup;
2693         }
2694
2695         assert (filenamesize > lendir);
2696         strcpy (filename, dir_name);
2697
2698         if (base_name && *base_name)
2699           {
2700             if (filename[lendir -1] != '/')
2701               filename[lendir++] = '/';
2702             strcpy (filename +lendir, base_name);
2703           }
2704
2705         if ((result = (*func) (filename, data1, data2)))
2706           {
2707             break;
2708           }
2709       }
2710   }
2711
2712  cleanup:
2713   LT_DLFREE (argz);
2714   LT_DLFREE (canonical);
2715   LT_DLFREE (filename);
2716
2717   LT_DLMUTEX_UNLOCK ();
2718
2719   return result;
2720 }
2721
2722 /* If FILEPATH can be opened, store the name of the directory component
2723    in DATA1, and the opened FILE* structure address in DATA2.  Otherwise
2724    DATA1 is unchanged, but DATA2 is set to a pointer to NULL.  */
2725 static int
2726 find_file_callback (filename, data1, data2)
2727      char *filename;
2728      lt_ptr data1;
2729      lt_ptr data2;
2730 {
2731   char       **pdir     = (char **) data1;
2732   FILE       **pfile    = (FILE **) data2;
2733   int        is_done    = 0;
2734
2735   assert (filename && *filename);
2736   assert (pdir);
2737   assert (pfile);
2738
2739   if ((*pfile = fopen (filename, LT_READTEXT_MODE)))
2740     {
2741       char *dirend = strrchr (filename, '/');
2742
2743       if (dirend > filename)
2744         *dirend   = LT_EOS_CHAR;
2745
2746       LT_DLFREE (*pdir);
2747       *pdir   = lt_estrdup (filename);
2748       is_done = (*pdir == 0) ? -1 : 1;
2749     }
2750
2751   return is_done;
2752 }
2753
2754 static FILE *
2755 find_file (search_path, base_name, pdir)
2756      const char *search_path;
2757      const char *base_name;
2758      char **pdir;
2759 {
2760   FILE *file = 0;
2761
2762   foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file);
2763
2764   return file;
2765 }
2766
2767 static int
2768 find_handle_callback (filename, data, ignored)
2769      char *filename;
2770      lt_ptr data;
2771      lt_ptr ignored;
2772 {
2773   lt_dlhandle  *handle          = (lt_dlhandle *) data;
2774   int           notfound        = access (filename, R_OK);
2775
2776   /* Bail out if file cannot be read...  */
2777   if (notfound)
2778     return 0;
2779
2780   /* Try to dlopen the file, but do not continue searching in any
2781      case.  */
2782   if (tryall_dlopen (handle, filename) != 0)
2783     *handle = 0;
2784
2785   return 1;
2786 }
2787
2788 /* If HANDLE was found return it, otherwise return 0.  If HANDLE was
2789    found but could not be opened, *HANDLE will be set to 0.  */
2790 static lt_dlhandle *
2791 find_handle (search_path, base_name, handle)
2792      const char *search_path;
2793      const char *base_name;
2794      lt_dlhandle *handle;
2795 {
2796   if (!search_path)
2797     return 0;
2798
2799   if (!foreach_dirinpath (search_path, base_name, find_handle_callback,
2800                           handle, 0))
2801     return 0;
2802
2803   return handle;
2804 }
2805
2806 static int
2807 load_deplibs (handle, deplibs)
2808      lt_dlhandle handle;
2809      char *deplibs;
2810 {
2811 #if LTDL_DLOPEN_DEPLIBS
2812   char  *p, *save_search_path = 0;
2813   int   depcount = 0;
2814   int   i;
2815   char  **names = 0;
2816 #endif
2817   int   errors = 0;
2818
2819   handle->depcount = 0;
2820
2821 #if LTDL_DLOPEN_DEPLIBS
2822   if (!deplibs)
2823     {
2824       return errors;
2825     }
2826   ++errors;
2827
2828   LT_DLMUTEX_LOCK ();
2829   if (user_search_path)
2830     {
2831       save_search_path = lt_estrdup (user_search_path);
2832       if (!save_search_path)
2833         goto cleanup;
2834     }
2835
2836   /* extract search paths and count deplibs */
2837   p = deplibs;
2838   while (*p)
2839     {
2840       if (!isspace ((int) *p))
2841         {
2842           char *end = p+1;
2843           while (*end && !isspace((int) *end))
2844             {
2845               ++end;
2846             }
2847
2848           if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0)
2849             {
2850               char save = *end;
2851               *end = 0; /* set a temporary string terminator */
2852               if (lt_dladdsearchdir(p+2))
2853                 {
2854                   goto cleanup;
2855                 }
2856               *end = save;
2857             }
2858           else
2859             {
2860               ++depcount;
2861             }
2862
2863           p = end;
2864         }
2865       else
2866         {
2867           ++p;
2868         }
2869     }
2870
2871   /* restore the old search path */
2872   LT_DLFREE (user_search_path);
2873   user_search_path = save_search_path;
2874
2875   LT_DLMUTEX_UNLOCK ();
2876
2877   if (!depcount)
2878     {
2879       errors = 0;
2880       goto cleanup;
2881     }
2882
2883   names = LT_EMALLOC (char *, depcount * sizeof (char*));
2884   if (!names)
2885     goto cleanup;
2886
2887   /* now only extract the actual deplibs */
2888   depcount = 0;
2889   p = deplibs;
2890   while (*p)
2891     {
2892       if (isspace ((int) *p))
2893         {
2894           ++p;
2895         }
2896       else
2897         {
2898           char *end = p+1;
2899           while (*end && !isspace ((int) *end))
2900             {
2901               ++end;
2902             }
2903
2904           if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0)
2905             {
2906               char *name;
2907               char save = *end;
2908               *end = 0; /* set a temporary string terminator */
2909               if (strncmp(p, "-l", 2) == 0)
2910                 {
2911                   size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2);
2912                   name = LT_EMALLOC (char, 1+ name_len);
2913                   if (name)
2914                     sprintf (name, "lib%s", p+2);
2915                 }
2916               else
2917                 name = lt_estrdup(p);
2918
2919               if (!name)
2920                 goto cleanup_names;
2921
2922               names[depcount++] = name;
2923               *end = save;
2924             }
2925           p = end;
2926         }
2927     }
2928
2929   /* load the deplibs (in reverse order)
2930      At this stage, don't worry if the deplibs do not load correctly,
2931      they may already be statically linked into the loading application
2932      for instance.  There will be a more enlightening error message
2933      later on if the loaded module cannot resolve all of its symbols.  */
2934   if (depcount)
2935     {
2936       int       j = 0;
2937
2938       handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount);
2939       if (!handle->deplibs)
2940         goto cleanup;
2941
2942       for (i = 0; i < depcount; ++i)
2943         {
2944           handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]);
2945           if (handle->deplibs[j])
2946             {
2947               ++j;
2948             }
2949         }
2950
2951       handle->depcount  = j;    /* Number of successfully loaded deplibs */
2952       errors            = 0;
2953     }
2954
2955  cleanup_names:
2956   for (i = 0; i < depcount; ++i)
2957     {
2958       LT_DLFREE (names[i]);
2959     }
2960
2961  cleanup:
2962   LT_DLFREE (names);
2963 #endif
2964
2965   return errors;
2966 }
2967
2968 static int
2969 unload_deplibs (handle)
2970      lt_dlhandle handle;
2971 {
2972   int i;
2973   int errors = 0;
2974
2975   if (handle->depcount)
2976     {
2977       for (i = 0; i < handle->depcount; ++i)
2978         {
2979           if (!LT_DLIS_RESIDENT (handle->deplibs[i]))
2980             {
2981               errors += lt_dlclose (handle->deplibs[i]);
2982             }
2983         }
2984     }
2985
2986   return errors;
2987 }
2988
2989 static int
2990 trim (dest, str)
2991      char **dest;
2992      const char *str;
2993 {
2994   /* remove the leading and trailing "'" from str
2995      and store the result in dest */
2996   const char *end   = strrchr (str, '\'');
2997   size_t len        = LT_STRLEN (str);
2998   char *tmp;
2999
3000   LT_DLFREE (*dest);
3001
3002   if (len > 3 && str[0] == '\'')
3003     {
3004       tmp = LT_EMALLOC (char, end - str);
3005       if (!tmp)
3006         return 1;
3007
3008       strncpy(tmp, &str[1], (end - str) - 1);
3009       tmp[len-3] = LT_EOS_CHAR;
3010       *dest = tmp;
3011     }
3012   else
3013     {
3014       *dest = 0;
3015     }
3016
3017   return 0;
3018 }
3019
3020 static int
3021 free_vars (dlname, oldname, libdir, deplibs)
3022      char *dlname;
3023      char *oldname;
3024      char *libdir;
3025      char *deplibs;
3026 {
3027   LT_DLFREE (dlname);
3028   LT_DLFREE (oldname);
3029   LT_DLFREE (libdir);
3030   LT_DLFREE (deplibs);
3031
3032   return 0;
3033 }
3034
3035 static int
3036 try_dlopen (phandle, filename)
3037      lt_dlhandle *phandle;
3038      const char *filename;
3039 {
3040   const char *  ext             = 0;
3041   const char *  saved_error     = 0;
3042   char *        canonical       = 0;
3043   char *        base_name       = 0;
3044   char *        dir             = 0;
3045   char *        name            = 0;
3046   int           errors          = 0;
3047   int           free_base_name  = 0;
3048   lt_dlhandle   newhandle;
3049
3050   assert (phandle);
3051   assert (*phandle == 0);
3052
3053   LT_DLMUTEX_GETERROR (saved_error);
3054
3055   /* dlopen self? */
3056   if (!filename)
3057     {
3058       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
3059       if (*phandle == 0)
3060         return 1;
3061
3062       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
3063       newhandle = *phandle;
3064
3065       /* lt_dlclose()ing yourself is very bad!  Disallow it.  */
3066       LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG);
3067
3068       if (tryall_dlopen (&newhandle, 0) != 0)
3069         {
3070           LT_DLFREE (*phandle);
3071           return 1;
3072         }
3073
3074       goto register_handle;
3075     }
3076
3077   assert (filename && *filename);
3078
3079   /* Doing this immediately allows internal functions to safely
3080      assume only canonicalized paths are passed.  */
3081   if (canonicalize_path (filename, &canonical) != 0)
3082     {
3083       ++errors;
3084       goto cleanup;
3085     }
3086
3087   /* If the canonical module name is a path (relative or absolute)
3088      then split it into a directory part and a name part.  */
3089   base_name = strrchr (canonical, '/');
3090   if (base_name)
3091     {
3092       size_t dirlen = (1+ base_name) - canonical;
3093
3094       dir = LT_EMALLOC (char, 1+ dirlen);
3095       if (!dir)
3096         {
3097           ++errors;
3098           goto cleanup;
3099         }
3100
3101       strncpy (dir, canonical, dirlen);
3102       dir[dirlen] = LT_EOS_CHAR;
3103
3104       ++base_name;
3105     }
3106   else {
3107     LT_DLMEM_REASSIGN (base_name, canonical);
3108     free_base_name = 1;
3109   }
3110
3111   assert (base_name && *base_name);
3112
3113   /* Check whether we are opening a libtool module (.la extension).  */
3114   ext = strrchr (base_name, '.');
3115   if (ext && strcmp (ext, archive_ext) == 0)
3116     {
3117       /* this seems to be a libtool module */
3118       FILE *    file     = 0;
3119       char *    dlname   = 0;
3120       char *    old_name = 0;
3121       char *    libdir   = 0;
3122       char *    deplibs  = 0;
3123       char *    line     = 0;
3124       size_t    line_len;
3125
3126       /* if we can't find the installed flag, it is probably an
3127          installed libtool archive, produced with an old version
3128          of libtool */
3129       int       installed = 1;
3130
3131       /* extract the module name from the file name */
3132       name = LT_EMALLOC (char, ext - base_name + 1);
3133       if (!name)
3134         {
3135           ++errors;
3136           goto cleanup;
3137         }
3138
3139       /* canonicalize the module name */
3140       {
3141         size_t i;
3142         for (i = 0; i < ext - base_name; ++i)
3143           {
3144             if (isalnum ((int)(base_name[i])))
3145               {
3146                 name[i] = base_name[i];
3147               }
3148             else
3149               {
3150                 name[i] = '_';
3151               }
3152           }
3153         name[ext - base_name] = LT_EOS_CHAR;
3154       }
3155
3156       /* Now try to open the .la file.  If there is no directory name
3157          component, try to find it first in user_search_path and then other
3158          prescribed paths.  Otherwise (or in any case if the module was not
3159          yet found) try opening just the module name as passed.  */
3160       if (!dir)
3161         {
3162           const char *search_path;
3163
3164           LT_DLMUTEX_LOCK ();
3165           search_path = user_search_path;
3166           if (search_path)
3167             file = find_file (user_search_path, base_name, &dir);
3168           LT_DLMUTEX_UNLOCK ();
3169
3170           if (!file)
3171             {
3172               search_path = getenv (LTDL_SEARCHPATH_VAR);
3173               if (search_path)
3174                 file = find_file (search_path, base_name, &dir);
3175             }
3176
3177 #ifdef LTDL_SHLIBPATH_VAR
3178           if (!file)
3179             {
3180               search_path = getenv (LTDL_SHLIBPATH_VAR);
3181               if (search_path)
3182                 file = find_file (search_path, base_name, &dir);
3183             }
3184 #endif
3185 #ifdef LTDL_SYSSEARCHPATH
3186           if (!file && sys_search_path)
3187             {
3188               file = find_file (sys_search_path, base_name, &dir);
3189             }
3190 #endif
3191         }
3192       if (!file)
3193         {
3194           file = fopen (filename, LT_READTEXT_MODE);
3195         }
3196
3197       /* If we didn't find the file by now, it really isn't there.  Set
3198          the status flag, and bail out.  */
3199       if (!file)
3200         {
3201           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
3202           ++errors;
3203           goto cleanup;
3204         }
3205
3206       line_len = LT_FILENAME_MAX;
3207       line = LT_EMALLOC (char, line_len);
3208       if (!line)
3209         {
3210           fclose (file);
3211           ++errors;
3212           goto cleanup;
3213         }
3214
3215       /* read the .la file */
3216       while (!feof (file))
3217         {
3218           if (!fgets (line, (int) line_len, file))
3219             {
3220               break;
3221             }
3222
3223           /* Handle the case where we occasionally need to read a line
3224              that is longer than the initial buffer size.  */
3225           while ((line[LT_STRLEN(line) -1] != '\n') && (!feof (file)))
3226             {
3227               line = LT_DLREALLOC (char, line, line_len *2);
3228               if (!fgets (&line[line_len -1], (int) line_len +1, file))
3229                 {
3230                   break;
3231                 }
3232               line_len *= 2;
3233             }
3234
3235           if (line[0] == '\n' || line[0] == '#')
3236             {
3237               continue;
3238             }
3239
3240 #undef  STR_DLNAME
3241 #define STR_DLNAME      "dlname="
3242           if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0)
3243             {
3244               errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]);
3245             }
3246
3247 #undef  STR_OLD_LIBRARY
3248 #define STR_OLD_LIBRARY "old_library="
3249           else if (strncmp (line, STR_OLD_LIBRARY,
3250                             sizeof (STR_OLD_LIBRARY) - 1) == 0)
3251             {
3252               errors += trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]);
3253             }
3254 #undef  STR_LIBDIR
3255 #define STR_LIBDIR      "libdir="
3256           else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0)
3257             {
3258               errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]);
3259             }
3260
3261 #undef  STR_DL_DEPLIBS
3262 #define STR_DL_DEPLIBS  "dependency_libs="
3263           else if (strncmp (line, STR_DL_DEPLIBS,
3264                             sizeof (STR_DL_DEPLIBS) - 1) == 0)
3265             {
3266               errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]);
3267             }
3268           else if (strcmp (line, "installed=yes\n") == 0)
3269             {
3270               installed = 1;
3271             }
3272           else if (strcmp (line, "installed=no\n") == 0)
3273             {
3274               installed = 0;
3275             }
3276
3277 #undef  STR_LIBRARY_NAMES
3278 #define STR_LIBRARY_NAMES "library_names="
3279           else if (! dlname && strncmp (line, STR_LIBRARY_NAMES,
3280                                         sizeof (STR_LIBRARY_NAMES) - 1) == 0)
3281             {
3282               char *last_libname;
3283               errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]);
3284               if (!errors
3285                   && dlname
3286                   && (last_libname = strrchr (dlname, ' ')) != 0)
3287                 {
3288                   last_libname = lt_estrdup (last_libname + 1);
3289                   if (!last_libname)
3290                     {
3291                       ++errors;
3292                       goto cleanup;
3293                     }
3294                   LT_DLMEM_REASSIGN (dlname, last_libname);
3295                 }
3296             }
3297
3298           if (errors)
3299             break;
3300         }
3301
3302       fclose (file);
3303       LT_DLFREE (line);
3304
3305       /* allocate the handle */
3306       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
3307       if (*phandle == 0)
3308         ++errors;
3309
3310       if (errors)
3311         {
3312           free_vars (dlname, old_name, libdir, deplibs);
3313           LT_DLFREE (*phandle);
3314           goto cleanup;
3315         }
3316
3317       assert (*phandle);
3318
3319       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
3320       if (load_deplibs (*phandle, deplibs) == 0)
3321         {
3322           newhandle = *phandle;
3323           /* find_module may replace newhandle */
3324           if (find_module (&newhandle, dir, libdir, dlname, old_name, installed))
3325             {
3326               unload_deplibs (*phandle);
3327               ++errors;
3328             }
3329         }
3330       else
3331         {
3332           ++errors;
3333         }
3334
3335       free_vars (dlname, old_name, libdir, deplibs);
3336       if (errors)
3337         {
3338           LT_DLFREE (*phandle);
3339           goto cleanup;
3340         }
3341
3342       if (*phandle != newhandle)
3343         {
3344           unload_deplibs (*phandle);
3345         }
3346     }
3347   else
3348     {
3349       /* not a libtool module */
3350       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
3351       if (*phandle == 0)
3352         {
3353           ++errors;
3354           goto cleanup;
3355         }
3356
3357       memset (*phandle, 0, sizeof (struct lt_dlhandle_struct));
3358       newhandle = *phandle;
3359
3360       /* If the module has no directory name component, try to find it
3361          first in user_search_path and then other prescribed paths.
3362          Otherwise (or in any case if the module was not yet found) try
3363          opening just the module name as passed.  */
3364       if ((dir || (!find_handle (user_search_path, base_name, &newhandle)
3365                    && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name,
3366                                     &newhandle)
3367 #ifdef LTDL_SHLIBPATH_VAR
3368                    && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name,
3369                                     &newhandle)
3370 #endif
3371 #ifdef LTDL_SYSSEARCHPATH
3372                    && !find_handle (sys_search_path, base_name, &newhandle)
3373 #endif
3374                    )))
3375         {
3376           if (tryall_dlopen (&newhandle, filename) != 0)
3377             {
3378               newhandle = NULL;
3379             }
3380         }
3381
3382       if (!newhandle)
3383         {
3384           LT_DLFREE (*phandle);
3385           ++errors;
3386           goto cleanup;
3387         }
3388     }
3389
3390  register_handle:
3391   LT_DLMEM_REASSIGN (*phandle, newhandle);
3392
3393   if ((*phandle)->info.ref_count == 0)
3394     {
3395       (*phandle)->info.ref_count        = 1;
3396       LT_DLMEM_REASSIGN ((*phandle)->info.name, name);
3397
3398       LT_DLMUTEX_LOCK ();
3399       (*phandle)->next          = handles;
3400       handles                   = *phandle;
3401       LT_DLMUTEX_UNLOCK ();
3402     }
3403
3404   LT_DLMUTEX_SETERROR (saved_error);
3405
3406  cleanup:
3407   LT_DLFREE (dir);
3408   LT_DLFREE (name);
3409   LT_DLFREE (canonical);
3410   if (free_base_name) LT_DLFREE (base_name);
3411
3412   return errors;
3413 }
3414
3415 lt_dlhandle
3416 lt_dlopen (filename)
3417      const char *filename;
3418 {
3419   lt_dlhandle handle = 0;
3420
3421   /* Just incase we missed a code path in try_dlopen() that reports
3422      an error, but forgets to reset handle... */
3423   if (try_dlopen (&handle, filename) != 0)
3424     return 0;
3425
3426   return handle;
3427 }
3428
3429 /* If the last error messge store was `FILE_NOT_FOUND', then return
3430    non-zero.  */
3431 static int
3432 file_not_found ()
3433 {
3434   const char *error = 0;
3435
3436   LT_DLMUTEX_GETERROR (error);
3437   if (error == LT_DLSTRERROR (FILE_NOT_FOUND))
3438     return 1;
3439
3440   return 0;
3441 }
3442
3443 /* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to
3444    open the FILENAME as passed.  Otherwise try appending ARCHIVE_EXT,
3445    and if a file is still not found try again with SHLIB_EXT appended
3446    instead.  */
3447 lt_dlhandle
3448 lt_dlopenext (filename)
3449      const char *filename;
3450 {
3451   lt_dlhandle   handle          = 0;
3452   char *        tmp             = 0;
3453   char *        ext             = 0;
3454   size_t        len;
3455   int           errors          = 0;
3456
3457   if (!filename)
3458     {
3459       return lt_dlopen (filename);
3460     }
3461
3462   assert (filename);
3463
3464   len = LT_STRLEN (filename);
3465   ext = strrchr (filename, '.');
3466
3467   /* If FILENAME already bears a suitable extension, there is no need
3468      to try appending additional extensions.  */
3469   if (ext && ((strcmp (ext, archive_ext) == 0)
3470 #ifdef LTDL_SHLIB_EXT
3471               || (strcmp (ext, shlib_ext) == 0)
3472 #endif
3473       ))
3474     {
3475       return lt_dlopen (filename);
3476     }
3477
3478   /* First try appending ARCHIVE_EXT.  */
3479   tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1);
3480   if (!tmp)
3481     return 0;
3482
3483   strcpy (tmp, filename);
3484   strcat (tmp, archive_ext);
3485   errors = try_dlopen (&handle, tmp);
3486   if (errors) return 0;
3487
3488   /* If we found FILENAME, stop searching -- whether we were able to
3489      load the file as a module or not.  If the file exists but loading
3490      failed, it is better to return an error message here than to
3491      report FILE_NOT_FOUND when the alternatives (foo.so etc) are not
3492      in the module search path.  */
3493   if (handle || ((errors > 0) && !file_not_found ()))
3494     {
3495       LT_DLFREE (tmp);
3496       return handle;
3497     }
3498
3499 #ifdef LTDL_SHLIB_EXT
3500   /* Try appending SHLIB_EXT.   */
3501   if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext))
3502     {
3503       LT_DLFREE (tmp);
3504       tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1);
3505       if (!tmp)
3506         return 0;
3507
3508       strcpy (tmp, filename);
3509     }
3510   else
3511     {
3512       tmp[len] = LT_EOS_CHAR;
3513     }
3514
3515   strcat(tmp, shlib_ext);
3516   errors = try_dlopen (&handle, tmp);
3517   if (errors) return 0;
3518
3519   /* As before, if the file was found but loading failed, return now
3520      with the current error message.  */
3521   if (handle || ((errors > 0) && !file_not_found ()))
3522     {
3523       LT_DLFREE (tmp);
3524       return handle;
3525     }
3526 #endif
3527
3528   /* Still here?  Then we really did fail to locate any of the file
3529      names we tried.  */
3530   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
3531   LT_DLFREE (tmp);
3532   return 0;
3533 }
3534
3535
3536 static int
3537 lt_argz_insert (pargz, pargz_len, before, entry)
3538      char **pargz;
3539      size_t *pargz_len;
3540      char *before;
3541      const char *entry;
3542 {
3543   error_t error;
3544
3545   if ((error = argz_insert (pargz, pargz_len, before, entry)))
3546     {
3547       switch (error)
3548         {
3549         case ENOMEM:
3550           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
3551           break;
3552         default:
3553           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
3554           break;
3555         }
3556       return 1;
3557     }
3558
3559   return 0;
3560 }
3561
3562 static int
3563 lt_argz_insertinorder (pargz, pargz_len, entry)
3564      char **pargz;
3565      size_t *pargz_len;
3566      const char *entry;
3567 {
3568   char *before = 0;
3569
3570   assert (pargz);
3571   assert (pargz_len);
3572   assert (entry && *entry);
3573
3574   if (*pargz)
3575     while ((before = argz_next (*pargz, *pargz_len, before)))
3576       {
3577         int cmp = strcmp (entry, before);
3578
3579         if (cmp < 0)  break;
3580         if (cmp == 0) return 0; /* No duplicates! */
3581       }
3582
3583   return lt_argz_insert (pargz, pargz_len, before, entry);
3584 }
3585
3586 static int
3587 lt_argz_insertdir (pargz, pargz_len, dirnam, dp)
3588      char **pargz;
3589      size_t *pargz_len;
3590      const char *dirnam;
3591      struct dirent *dp;
3592 {
3593   char   *buf       = 0;
3594   size_t buf_len    = 0;
3595   char   *end       = 0;
3596   size_t end_offset = 0;
3597   size_t dir_len    = 0;
3598   int    errors     = 0;
3599
3600   assert (pargz);
3601   assert (pargz_len);
3602   assert (dp);
3603
3604   dir_len = LT_STRLEN (dirnam);
3605   end     = dp->d_name + LT_D_NAMLEN(dp);
3606
3607   /* Ignore version numbers.  */
3608   {
3609     char *p;
3610     for (p = end; p -1 > dp->d_name; --p)
3611       if (strchr (".0123456789", p[-1]) == 0)
3612         break;
3613
3614     if (*p == '.')
3615       end = p;
3616   }
3617
3618   /* Ignore filename extension.  */
3619   {
3620     char *p;
3621     for (p = end -1; p > dp->d_name; --p)
3622       if (*p == '.')
3623         {
3624           end = p;
3625           break;
3626         }
3627   }
3628
3629   /* Prepend the directory name.  */
3630   end_offset    = end - dp->d_name;
3631   buf_len       = dir_len + 1+ end_offset;
3632   buf           = LT_EMALLOC (char, 1+ buf_len);
3633   if (!buf)
3634     return ++errors;
3635
3636   assert (buf);
3637
3638   strcpy  (buf, dirnam);
3639   strcat  (buf, "/");
3640   strncat (buf, dp->d_name, end_offset);
3641   buf[buf_len] = LT_EOS_CHAR;
3642
3643   /* Try to insert (in order) into ARGZ/ARGZ_LEN.  */
3644   if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0)
3645     ++errors;
3646
3647   LT_DLFREE (buf);
3648
3649   return errors;
3650 }
3651
3652 static int
3653 list_files_by_dir (dirnam, pargz, pargz_len)
3654      const char *dirnam;
3655      char **pargz;
3656      size_t *pargz_len;
3657 {
3658   DIR   *dirp     = 0;
3659   int    errors   = 0;
3660
3661   assert (dirnam && *dirnam);
3662   assert (pargz);
3663   assert (pargz_len);
3664   assert (dirnam[LT_STRLEN(dirnam) -1] != '/');
3665
3666   dirp = opendir (dirnam);
3667   if (dirp)
3668     {
3669       struct dirent *dp = 0;
3670
3671       while ((dp = readdir (dirp)))
3672         if (dp->d_name[0] != '.')
3673           if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp))
3674             {
3675               ++errors;
3676               break;
3677             }
3678
3679       closedir (dirp);
3680     }
3681   else
3682     ++errors;
3683
3684   return errors;
3685 }
3686
3687
3688 /* If there are any files in DIRNAME, call the function passed in
3689    DATA1 (with the name of each file and DATA2 as arguments).  */
3690 static int
3691 foreachfile_callback (dirname, data1, data2)
3692      char *dirname;
3693      lt_ptr data1;
3694      lt_ptr data2;
3695 {
3696   int (*func) LT_PARAMS((const char *filename, lt_ptr data))
3697         = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1;
3698
3699   int     is_done  = 0;
3700   char   *argz     = 0;
3701   size_t  argz_len = 0;
3702
3703   if (list_files_by_dir (dirname, &argz, &argz_len) != 0)
3704     goto cleanup;
3705   if (!argz)
3706     goto cleanup;
3707
3708   {
3709     char *filename = 0;
3710     while ((filename = argz_next (argz, argz_len, filename)))
3711       if ((is_done = (*func) (filename, data2)))
3712         break;
3713   }
3714
3715  cleanup:
3716   LT_DLFREE (argz);
3717
3718   return is_done;
3719 }
3720
3721
3722 /* Call FUNC for each unique extensionless file in SEARCH_PATH, along
3723    with DATA.  The filenames passed to FUNC would be suitable for
3724    passing to lt_dlopenext.  The extensions are stripped so that
3725    individual modules do not generate several entries (e.g. libfoo.la,
3726    libfoo.so, libfoo.so.1, libfoo.so.1.0.0).  If SEARCH_PATH is NULL,
3727    then the same directories that lt_dlopen would search are examined.  */
3728 int
3729 lt_dlforeachfile (search_path, func, data)
3730      const char *search_path;
3731      int (*func) LT_PARAMS ((const char *filename, lt_ptr data));
3732      lt_ptr data;
3733 {
3734   int is_done = 0;
3735
3736   if (search_path)
3737     {
3738       /* If a specific path was passed, search only the directories
3739          listed in it.  */
3740       is_done = foreach_dirinpath (search_path, 0,
3741                                    foreachfile_callback, func, data);
3742     }
3743   else
3744     {
3745       /* Otherwise search the default paths.  */
3746       is_done = foreach_dirinpath (user_search_path, 0,
3747                                    foreachfile_callback, func, data);
3748       if (!is_done)
3749         {
3750           is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0,
3751                                        foreachfile_callback, func, data);
3752         }
3753
3754 #ifdef LTDL_SHLIBPATH_VAR
3755       if (!is_done)
3756         {
3757           is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0,
3758                                        foreachfile_callback, func, data);
3759         }
3760 #endif
3761 #ifdef LTDL_SYSSEARCHPATH
3762       if (!is_done)
3763         {
3764           is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0,
3765                                        foreachfile_callback, func, data);
3766         }
3767 #endif
3768     }
3769
3770   return is_done;
3771 }
3772
3773 int
3774 lt_dlclose (handle)
3775      lt_dlhandle handle;
3776 {
3777   lt_dlhandle cur, last;
3778   int errors = 0;
3779
3780   LT_DLMUTEX_LOCK ();
3781
3782   /* check whether the handle is valid */
3783   last = cur = handles;
3784   while (cur && handle != cur)
3785     {
3786       last = cur;
3787       cur = cur->next;
3788     }
3789
3790   if (!cur)
3791     {
3792       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
3793       ++errors;
3794       goto done;
3795     }
3796
3797   handle->info.ref_count--;
3798
3799   /* Note that even with resident modules, we must track the ref_count
3800      correctly incase the user decides to reset the residency flag
3801      later (even though the API makes no provision for that at the
3802      moment).  */
3803   if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle))
3804     {
3805       lt_user_data data = handle->loader->dlloader_data;
3806
3807       if (handle != handles)
3808         {
3809           last->next = handle->next;
3810         }
3811       else
3812         {
3813           handles = handle->next;
3814         }
3815
3816       errors += handle->loader->module_close (data, handle->module);
3817       errors += unload_deplibs(handle);
3818
3819       /* It is up to the callers to free the data itself.  */
3820       LT_DLFREE (handle->caller_data);
3821
3822       LT_DLFREE (handle->info.filename);
3823       LT_DLFREE (handle->info.name);
3824       LT_DLFREE (handle);
3825
3826       goto done;
3827     }
3828
3829   if (LT_DLIS_RESIDENT (handle))
3830     {
3831       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE));
3832       ++errors;
3833     }
3834
3835  done:
3836   LT_DLMUTEX_UNLOCK ();
3837
3838   return errors;
3839 }
3840
3841 lt_ptr
3842 lt_dlsym (handle, symbol)
3843      lt_dlhandle handle;
3844      const char *symbol;
3845 {
3846   size_t lensym;
3847   char  lsym[LT_SYMBOL_LENGTH];
3848   char  *sym;
3849   lt_ptr address;
3850   lt_user_data data;
3851
3852   if (!handle)
3853     {
3854       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
3855       return 0;
3856     }
3857
3858   if (!symbol)
3859     {
3860       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
3861       return 0;
3862     }
3863
3864   lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix)
3865                                         + LT_STRLEN (handle->info.name);
3866
3867   if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH)
3868     {
3869       sym = lsym;
3870     }
3871   else
3872     {
3873       sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1);
3874       if (!sym)
3875         {
3876           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW));
3877           return 0;
3878         }
3879     }
3880
3881   data = handle->loader->dlloader_data;
3882   if (handle->info.name)
3883     {
3884       const char *saved_error;
3885
3886       LT_DLMUTEX_GETERROR (saved_error);
3887
3888       /* this is a libtool module */
3889       if (handle->loader->sym_prefix)
3890         {
3891           strcpy(sym, handle->loader->sym_prefix);
3892           strcat(sym, handle->info.name);
3893         }
3894       else
3895         {
3896           strcpy(sym, handle->info.name);
3897         }
3898
3899       strcat(sym, "_LTX_");
3900       strcat(sym, symbol);
3901
3902       /* try "modulename_LTX_symbol" */
3903       address = handle->loader->find_sym (data, handle->module, sym);
3904       if (address)
3905         {
3906           if (sym != lsym)
3907             {
3908               LT_DLFREE (sym);
3909             }
3910           return address;
3911         }
3912       LT_DLMUTEX_SETERROR (saved_error);
3913     }
3914
3915   /* otherwise try "symbol" */
3916   if (handle->loader->sym_prefix)
3917     {
3918       strcpy(sym, handle->loader->sym_prefix);
3919       strcat(sym, symbol);
3920     }
3921   else
3922     {
3923       strcpy(sym, symbol);
3924     }
3925
3926   address = handle->loader->find_sym (data, handle->module, sym);
3927   if (sym != lsym)
3928     {
3929       LT_DLFREE (sym);
3930     }
3931
3932   return address;
3933 }
3934
3935 const char *
3936 lt_dlerror ()
3937 {
3938   const char *error;
3939
3940   LT_DLMUTEX_GETERROR (error);
3941   LT_DLMUTEX_SETERROR (0);
3942
3943   return error ? error : NULL;
3944 }
3945
3946 static int
3947 lt_dlpath_insertdir (ppath, before, dir)
3948      char **ppath;
3949      char *before;
3950      const char *dir;
3951 {
3952   int    errors         = 0;
3953   char  *canonical      = 0;
3954   char  *argz           = 0;
3955   size_t argz_len       = 0;
3956
3957   assert (ppath);
3958   assert (dir && *dir);
3959
3960   if (canonicalize_path (dir, &canonical) != 0)
3961     {
3962       ++errors;
3963       goto cleanup;
3964     }
3965
3966   assert (canonical && *canonical);
3967
3968   /* If *PPATH is empty, set it to DIR.  */
3969   if (*ppath == 0)
3970     {
3971       assert (!before);         /* BEFORE cannot be set without PPATH.  */
3972       assert (dir);             /* Without DIR, don't call this function!  */
3973
3974       *ppath = lt_estrdup (dir);
3975       if (*ppath == 0)
3976         ++errors;
3977
3978       return errors;
3979     }
3980
3981   assert (ppath && *ppath);
3982
3983   if (argzize_path (*ppath, &argz, &argz_len) != 0)
3984     {
3985       ++errors;
3986       goto cleanup;
3987     }
3988
3989   /* Convert BEFORE into an equivalent offset into ARGZ.  This only works
3990      if *PPATH is already canonicalized, and hence does not change length
3991      with respect to ARGZ.  We canonicalize each entry as it is added to
3992      the search path, and don't call this function with (uncanonicalized)
3993      user paths, so this is a fair assumption.  */
3994   if (before)
3995     {
3996       assert (*ppath <= before);
3997       assert (before - *ppath <= strlen (*ppath));
3998
3999       before = before - *ppath + argz;
4000     }
4001
4002   if (lt_argz_insert (&argz, &argz_len, before, dir) != 0)
4003     {
4004       ++errors;
4005       goto cleanup;
4006     }
4007
4008   argz_stringify (argz, argz_len, LT_PATHSEP_CHAR);
4009   LT_DLMEM_REASSIGN (*ppath,  argz);
4010
4011  cleanup:
4012   LT_DLFREE (canonical);
4013   LT_DLFREE (argz);
4014
4015   return errors;
4016 }
4017
4018 int
4019 lt_dladdsearchdir (search_dir)
4020      const char *search_dir;
4021 {
4022   int errors = 0;
4023
4024   if (search_dir && *search_dir)
4025     {
4026       LT_DLMUTEX_LOCK ();
4027       if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)
4028         ++errors;
4029       LT_DLMUTEX_UNLOCK ();
4030     }
4031
4032   return errors;
4033 }
4034
4035 int
4036 lt_dlinsertsearchdir (before, search_dir)
4037      const char *before;
4038      const char *search_dir;
4039 {
4040   int errors = 0;
4041
4042   if (before)
4043     {
4044       LT_DLMUTEX_LOCK ();
4045       if ((before < user_search_path)
4046           || (before >= user_search_path + LT_STRLEN (user_search_path)))
4047         {
4048           LT_DLMUTEX_UNLOCK ();
4049           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION));
4050           return 1;
4051         }
4052       LT_DLMUTEX_UNLOCK ();
4053     }
4054
4055   if (search_dir && *search_dir)
4056     {
4057       LT_DLMUTEX_LOCK ();
4058       if (lt_dlpath_insertdir (&user_search_path,
4059                                (char *) before, search_dir) != 0)
4060         {
4061           ++errors;
4062         }
4063       LT_DLMUTEX_UNLOCK ();
4064     }
4065
4066   return errors;
4067 }
4068
4069 int
4070 lt_dlsetsearchpath (search_path)
4071      const char *search_path;
4072 {
4073   int   errors      = 0;
4074
4075   LT_DLMUTEX_LOCK ();
4076   LT_DLFREE (user_search_path);
4077   LT_DLMUTEX_UNLOCK ();
4078
4079   if (!search_path || !LT_STRLEN (search_path))
4080     {
4081       return errors;
4082     }
4083
4084   LT_DLMUTEX_LOCK ();
4085   if (canonicalize_path (search_path, &user_search_path) != 0)
4086     ++errors;
4087   LT_DLMUTEX_UNLOCK ();
4088
4089   return errors;
4090 }
4091
4092 const char *
4093 lt_dlgetsearchpath ()
4094 {
4095   const char *saved_path;
4096
4097   LT_DLMUTEX_LOCK ();
4098   saved_path = user_search_path;
4099   LT_DLMUTEX_UNLOCK ();
4100
4101   return saved_path;
4102 }
4103
4104 int
4105 lt_dlmakeresident (handle)
4106      lt_dlhandle handle;
4107 {
4108   int errors = 0;
4109
4110   if (!handle)
4111     {
4112       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
4113       ++errors;
4114     }
4115   else
4116     {
4117       LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG);
4118     }
4119
4120   return errors;
4121 }
4122
4123 int
4124 lt_dlisresident (handle)
4125      lt_dlhandle handle;
4126 {
4127   if (!handle)
4128     {
4129       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
4130       return -1;
4131     }
4132
4133   return LT_DLIS_RESIDENT (handle);
4134 }
4135
4136
4137
4138 \f
4139 /* --- MODULE INFORMATION --- */
4140
4141 const lt_dlinfo *
4142 lt_dlgetinfo (handle)
4143      lt_dlhandle handle;
4144 {
4145   if (!handle)
4146     {
4147       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
4148       return 0;
4149     }
4150
4151   return &(handle->info);
4152 }
4153
4154 lt_dlhandle
4155 lt_dlhandle_next (place)
4156      lt_dlhandle place;
4157 {
4158   return place ? place->next : handles;
4159 }
4160
4161 int
4162 lt_dlforeach (func, data)
4163      int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data));
4164      lt_ptr data;
4165 {
4166   int errors = 0;
4167   lt_dlhandle cur;
4168
4169   LT_DLMUTEX_LOCK ();
4170
4171   cur = handles;
4172   while (cur)
4173     {
4174       lt_dlhandle tmp = cur;
4175
4176       cur = cur->next;
4177       if ((*func) (tmp, data))
4178         {
4179           ++errors;
4180           break;
4181         }
4182     }
4183
4184   LT_DLMUTEX_UNLOCK ();
4185
4186   return errors;
4187 }
4188
4189 lt_dlcaller_id
4190 lt_dlcaller_register ()
4191 {
4192   static lt_dlcaller_id last_caller_id = 0;
4193   int result;
4194
4195   LT_DLMUTEX_LOCK ();
4196   result = ++last_caller_id;
4197   LT_DLMUTEX_UNLOCK ();
4198
4199   return result;
4200 }
4201
4202 lt_ptr
4203 lt_dlcaller_set_data (key, handle, data)
4204      lt_dlcaller_id key;
4205      lt_dlhandle handle;
4206      lt_ptr data;
4207 {
4208   int n_elements = 0;
4209   lt_ptr stale = (lt_ptr) 0;
4210   int i;
4211
4212   /* This needs to be locked so that the caller data can be updated
4213      simultaneously by different threads.  */
4214   LT_DLMUTEX_LOCK ();
4215
4216   if (handle->caller_data)
4217     while (handle->caller_data[n_elements].key)
4218       ++n_elements;
4219
4220   for (i = 0; i < n_elements; ++i)
4221     {
4222       if (handle->caller_data[i].key == key)
4223         {
4224           stale = handle->caller_data[i].data;
4225           break;
4226         }
4227     }
4228
4229   /* Ensure that there is enough room in this handle's caller_data
4230      array to accept a new element (and an empty end marker).  */
4231   if (i == n_elements)
4232     {
4233       lt_caller_data *temp
4234         = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements);
4235
4236       if (!temp)
4237         {
4238           stale = 0;
4239           goto done;
4240         }
4241
4242       handle->caller_data = temp;
4243
4244       /* We only need this if we needed to allocate a new caller_data.  */
4245       handle->caller_data[i].key  = key;
4246       handle->caller_data[1+ i].key = 0;
4247     }
4248
4249   handle->caller_data[i].data = data;
4250
4251  done:
4252   LT_DLMUTEX_UNLOCK ();
4253
4254   return stale;
4255 }
4256
4257 lt_ptr
4258 lt_dlcaller_get_data  (key, handle)
4259      lt_dlcaller_id key;
4260      lt_dlhandle handle;
4261 {
4262   lt_ptr result = (lt_ptr) 0;
4263
4264   /* This needs to be locked so that the caller data isn't updated by
4265      another thread part way through this function.  */
4266   LT_DLMUTEX_LOCK ();
4267
4268   /* Locate the index of the element with a matching KEY.  */
4269   {
4270     int i;
4271     for (i = 0; handle->caller_data[i].key; ++i)
4272       {
4273         if (handle->caller_data[i].key == key)
4274           {
4275             result = handle->caller_data[i].data;
4276             break;
4277           }
4278       }
4279   }
4280
4281   LT_DLMUTEX_UNLOCK ();
4282
4283   return result;
4284 }
4285
4286
4287 \f
4288 /* --- USER MODULE LOADER API --- */
4289
4290
4291 int
4292 lt_dlloader_add (place, dlloader, loader_name)
4293      lt_dlloader *place;
4294      const struct lt_user_dlloader *dlloader;
4295      const char *loader_name;
4296 {
4297   int errors = 0;
4298   lt_dlloader *node = 0, *ptr = 0;
4299
4300   if ((dlloader == 0)   /* diagnose null parameters */
4301       || (dlloader->module_open == 0)
4302       || (dlloader->module_close == 0)
4303       || (dlloader->find_sym == 0))
4304     {
4305       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4306       return 1;
4307     }
4308
4309   /* Create a new dlloader node with copies of the user callbacks.  */
4310   node = LT_EMALLOC (lt_dlloader, 1);
4311   if (!node)
4312     return 1;
4313
4314   node->next            = 0;
4315   node->loader_name     = loader_name;
4316   node->sym_prefix      = dlloader->sym_prefix;
4317   node->dlloader_exit   = dlloader->dlloader_exit;
4318   node->module_open     = dlloader->module_open;
4319   node->module_close    = dlloader->module_close;
4320   node->find_sym        = dlloader->find_sym;
4321   node->dlloader_data   = dlloader->dlloader_data;
4322
4323   LT_DLMUTEX_LOCK ();
4324   if (!loaders)
4325     {
4326       /* If there are no loaders, NODE becomes the list! */
4327       loaders = node;
4328     }
4329   else if (!place)
4330     {
4331       /* If PLACE is not set, add NODE to the end of the
4332          LOADERS list. */
4333       for (ptr = loaders; ptr->next; ptr = ptr->next)
4334         {
4335           /*NOWORK*/;
4336         }
4337
4338       ptr->next = node;
4339     }
4340   else if (loaders == place)
4341     {
4342       /* If PLACE is the first loader, NODE goes first. */
4343       node->next = place;
4344       loaders = node;
4345     }
4346   else
4347     {
4348       /* Find the node immediately preceding PLACE. */
4349       for (ptr = loaders; ptr->next != place; ptr = ptr->next)
4350         {
4351           /*NOWORK*/;
4352         }
4353
4354       if (ptr->next != place)
4355         {
4356           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4357           ++errors;
4358         }
4359       else
4360         {
4361           /* Insert NODE between PTR and PLACE. */
4362           node->next = place;
4363           ptr->next  = node;
4364         }
4365     }
4366
4367   LT_DLMUTEX_UNLOCK ();
4368
4369   return errors;
4370 }
4371
4372 int
4373 lt_dlloader_remove (loader_name)
4374      const char *loader_name;
4375 {
4376   lt_dlloader *place = lt_dlloader_find (loader_name);
4377   lt_dlhandle handle;
4378   int errors = 0;
4379
4380   if (!place)
4381     {
4382       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4383       return 1;
4384     }
4385
4386   LT_DLMUTEX_LOCK ();
4387
4388   /* Fail if there are any open modules which use this loader. */
4389   for  (handle = handles; handle; handle = handle->next)
4390     {
4391       if (handle->loader == place)
4392         {
4393           LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER));
4394           ++errors;
4395           goto done;
4396         }
4397     }
4398
4399   if (place == loaders)
4400     {
4401       /* PLACE is the first loader in the list. */
4402       loaders = loaders->next;
4403     }
4404   else
4405     {
4406       /* Find the loader before the one being removed. */
4407       lt_dlloader *prev;
4408       for (prev = loaders; prev->next; prev = prev->next)
4409         {
4410           if (!strcmp (prev->next->loader_name, loader_name))
4411             {
4412               break;
4413             }
4414         }
4415
4416       place = prev->next;
4417       prev->next = prev->next->next;
4418     }
4419
4420   if (place->dlloader_exit)
4421     {
4422       errors = place->dlloader_exit (place->dlloader_data);
4423     }
4424
4425   LT_DLFREE (place);
4426
4427  done:
4428   LT_DLMUTEX_UNLOCK ();
4429
4430   return errors;
4431 }
4432
4433 lt_dlloader *
4434 lt_dlloader_next (place)
4435      lt_dlloader *place;
4436 {
4437   lt_dlloader *next;
4438
4439   LT_DLMUTEX_LOCK ();
4440   next = place ? place->next : loaders;
4441   LT_DLMUTEX_UNLOCK ();
4442
4443   return next;
4444 }
4445
4446 const char *
4447 lt_dlloader_name (place)
4448      lt_dlloader *place;
4449 {
4450   const char *name = 0;
4451
4452   if (place)
4453     {
4454       LT_DLMUTEX_LOCK ();
4455       name = place ? place->loader_name : 0;
4456       LT_DLMUTEX_UNLOCK ();
4457     }
4458   else
4459     {
4460       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4461     }
4462
4463   return name;
4464 }
4465
4466 lt_user_data *
4467 lt_dlloader_data (place)
4468      lt_dlloader *place;
4469 {
4470   lt_user_data *data = 0;
4471
4472   if (place)
4473     {
4474       LT_DLMUTEX_LOCK ();
4475       data = place ? &(place->dlloader_data) : 0;
4476       LT_DLMUTEX_UNLOCK ();
4477     }
4478   else
4479     {
4480       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
4481     }
4482
4483   return data;
4484 }
4485
4486 lt_dlloader *
4487 lt_dlloader_find (loader_name)
4488      const char *loader_name;
4489 {
4490   lt_dlloader *place = 0;
4491
4492   LT_DLMUTEX_LOCK ();
4493   for (place = loaders; place; place = place->next)
4494     {
4495       if (strcmp (place->loader_name, loader_name) == 0)
4496         {
4497           break;
4498         }
4499     }
4500   LT_DLMUTEX_UNLOCK ();
4501
4502   return place;
4503 }