OSDN Git Service

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