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