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