1 // $Id: Lib_Find.cpp 80826 2008-03-04 14:51:23Z wotte $
3 #include "ace/Lib_Find.h"
4 #include "ace/Log_Msg.h"
5 #include "ace/OS_NS_string.h"
6 #include "ace/OS_NS_errno.h"
7 #include "ace/OS_NS_stdio.h"
8 #include "ace/OS_NS_unistd.h"
9 #include "ace/OS_NS_stdlib.h"
10 #include "ace/OS_Memory.h"
11 #include "ace/OS_NS_fcntl.h"
13 #if defined (ACE_WIN32)
14 # include "ace/OS_NS_strings.h"
15 #endif /* ACE_WIN32 */
17 #if defined (ACE_OPENVMS)
18 #include "ace/RB_Tree.h"
19 #include "ace/Thread_Mutex.h"
20 #include "ace/Singleton.h"
22 #include /**/ "descrip.h"
23 #include /**/ "chfdef.h"
24 #include /**/ "stsdef.h"
25 #include /**/ "libdef.h"
27 extern "C" int LIB$
FIND_IMAGE_SYMBOL(...);
29 class ACE_LD_Symbol_Registry
33 // Implements a class to register symbols and addresses for use with DLL
37 // OpenVMS restricts symbol length to 31 characters encoding any symbols
38 // longer than that. In these cases dlsym() only works with the encoded
40 // This creates serious problems for the service configurator framework
41 // where the factory method names often exceed 31 chars and where loading
42 // is based on retrieval of method pointers using the *full* name.
43 // For OpenVMS we therefor added this singleton class and the
44 // ACE_Dynamic_Svc_Registrar class which registers full names and function
45 // pointers with this singleton at the time the static ACE_Dynamic_Svc_Registrar
46 // object is created in a (service) DLL.
47 // By forcing the DLL to load using a common symbol ("NULL") we trigger static
48 // object creation *before* the full names are referenced.
49 // Symbol references will be resolved as follows on OpenVMS:
50 // - first try directly from DLL using the RTL dlsym() function and if that fails;
51 // - try to find symbol in singleton registry.
54 typedef ACE_RB_Tree
<const ACE_TCHAR
*,
56 ACE_Less_Than
<const ACE_TCHAR
*>,
60 void register_symbol (const ACE_TCHAR
* symname
, void* symaddr
);
62 void* find_symbol (const ACE_TCHAR
* symname
);
64 ACE_LD_Symbol_Registry () {}
67 TREE symbol_registry_
;
71 ACE_LD_Symbol_Registry::register_symbol (const ACE_TCHAR
* symname
,
74 int const result
= symbol_registry_
.bind (symname
, symaddr
);
77 ACE_DEBUG((LM_INFO
, ACE_TEXT ("ACE_LD_Symbol_Registry:")
78 ACE_TEXT (" duplicate symbol %s registered\n"),
79 ACE_TEXT_ALWAYS_CHAR (symname
)));
81 else if (result
== -1)
83 ACE_ERROR((LM_ERROR
, ACE_TEXT ("ACE_LD_Symbol_Registry:")
84 ACE_TEXT (" failed to register symbol %s\n"),
85 ACE_TEXT_ALWAYS_CHAR (symname
)));
90 ACE_LD_Symbol_Registry::find_symbol (const ACE_TCHAR
* symname
)
93 int const result
= symbol_registry_
.find (symname
, symaddr
);
95 return (result
== 0 ? symaddr
: 0);
98 /// Declare a process wide singleton
99 ACE_SINGLETON_DECLARE (ACE_Singleton
,
100 ACE_LD_Symbol_Registry
,
103 typedef ACE_Singleton
<ACE_LD_Symbol_Registry
, ACE_Thread_Mutex
>
104 ACE_LD_SYMBOL_REGISTRY
;
106 #if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION)
107 template ACE_Singleton
<ACE_LD_Symbol_Registry
, ACE_Thread_Mutex
> *
108 ACE_Singleton
<ACE_LD_Symbol_Registry
, ACE_Thread_Mutex
>::singleton_
;
109 #endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */
112 ACE_RCSID(ace
, Lib_Find
, "$Id: Lib_Find.cpp 80826 2008-03-04 14:51:23Z wotte $")
114 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
117 ACE::ldfind (const ACE_TCHAR
* filename
,
118 ACE_TCHAR pathname
[],
119 size_t maxpathnamelen
)
121 ACE_TRACE ("ACE::ldfind");
122 #if defined (ACE_OPENVMS)
123 if (ACE_OS::strlen(filename
) >= maxpathnamelen
)
129 dsc$descriptor nameDsc
;
130 nameDsc
.dsc$b_class
= DSC$K_CLASS_S
;
131 nameDsc
.dsc$b_dtype
= DSC$K_DTYPE_T
;
132 nameDsc
.dsc$w_length
= ACE_OS::strlen(filename
);
133 nameDsc
.dsc$a_pointer
= (char*)filename
;
135 char symbol
[] = "NULL";
136 dsc$descriptor symbolDsc
;
137 symbolDsc
.dsc$b_class
= DSC$K_CLASS_S
;
138 symbolDsc
.dsc$b_dtype
= DSC$K_DTYPE_T
;
139 symbolDsc
.dsc$w_length
= ACE_OS::strlen(symbol
);
140 symbolDsc
.dsc$a_pointer
= symbol
;
146 result
= LIB$
FIND_IMAGE_SYMBOL(&nameDsc
, &symbolDsc
, &symbolValue
, 0, 0);
148 catch (chf$signal_array
& sig
)
150 result
= sig
.chf$l_sig_name
;
153 int severity
= result
& STS$M_SEVERITY
;
154 int conditionId
= result
& STS$M_COND_ID
;
155 if (severity
== STS$K_SUCCESS
|| severity
== STS$K_WARNING
|| severity
== STS$K_INFO
||
156 (severity
== STS$K_ERROR
&& conditionId
== (LIB$_KEYNOTFOU
& STS$M_COND_ID
)))
158 ACE_OS::strcpy(pathname
, filename
);
162 if (ACE_OS::strlen(filename
) + ACE_OS::strlen(ACE_DLL_PREFIX
) >= maxpathnamelen
)
169 ACE_OS::strcpy(pathname
, ACE_DLL_PREFIX
);
170 ACE_OS::strcat(pathname
, filename
);
171 nameDsc
.dsc$w_length
= ACE_OS::strlen(pathname
);
172 nameDsc
.dsc$a_pointer
= pathname
;
175 result
= LIB$
FIND_IMAGE_SYMBOL(&nameDsc
, &symbolDsc
, &symbolValue
, 0, 0);
177 catch (chf$signal_array
& sig
)
179 result
= sig
.chf$l_sig_name
;
182 severity
= result
& STS$M_SEVERITY
;
183 conditionId
= result
& STS$M_COND_ID
;
184 if (severity
== STS$K_SUCCESS
|| severity
== STS$K_WARNING
|| severity
== STS$K_INFO
||
185 (severity
== STS$K_ERROR
&& conditionId
== (LIB$_KEYNOTFOU
& STS$M_COND_ID
)))
191 #endif /* ACE_OPENVMS */
193 #if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) && \
194 !defined (ACE_HAS_PHARLAP)
195 ACE_TCHAR expanded_filename
[MAXPATHLEN
];
196 if (ACE_TEXT_ExpandEnvironmentStrings (filename
,
198 sizeof expanded_filename
199 / sizeof (ACE_TCHAR
)))
200 filename
= expanded_filename
;
201 #endif /* ACE_WIN32 && !ACE_HAS_WINCE && !ACE_HAS_PHARLAP */
203 ACE_TCHAR tempcopy
[MAXPATHLEN
+ 1];
204 ACE_TCHAR searchpathname
[MAXPATHLEN
+ 1];
205 #if defined (ACE_WIN32) && defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
206 ACE_TCHAR decorator
[] = ACE_LD_DECORATOR_STR
;
207 ACE_TCHAR searchfilename
[MAXPATHLEN
+ sizeof(decorator
) / sizeof (ACE_TCHAR
)];
209 ACE_TCHAR searchfilename
[MAXPATHLEN
+ 1];
210 #endif /* ACE_WIN32 && ACE_LD_DECORATOR_STR && !ACE_DISABLE_DEBUG_DLL_CHECK */
212 // Create a copy of filename to work with.
213 if (ACE_OS::strlen (filename
) + 1
214 > (sizeof tempcopy
/ sizeof (ACE_TCHAR
)))
220 ACE_OS::strcpy (tempcopy
, filename
);
222 // Insert canonical directory separators.
223 ACE_TCHAR
*separator_ptr
;
225 #if (ACE_DIRECTORY_SEPARATOR_CHAR != '/')
226 // Make all the directory separators "canonical" to simplify
228 ACE::strrepl (tempcopy
, ACE_DIRECTORY_SEPARATOR_CHAR
, '/');
229 #endif /* ACE_DIRECTORY_SEPARATOR_CHAR */
231 // Separate filename from pathname.
232 separator_ptr
= ACE_OS::strrchr (tempcopy
, '/');
234 // This is a relative path.
235 if (separator_ptr
== 0)
237 searchpathname
[0] = '\0';
238 ACE_OS::strcpy (searchfilename
, tempcopy
);
240 else // This is an absolute path.
242 ACE_OS::strcpy (searchfilename
, separator_ptr
+ 1);
243 separator_ptr
[1] = '\0';
244 ACE_OS::strcpy (searchpathname
, tempcopy
);
247 bool has_suffix
= false;
249 // Check to see if this has an appropriate DLL suffix for the OS
251 ACE_TCHAR
*s
= ACE_OS::strrchr (searchfilename
, '.');
253 const ACE_TCHAR
*dll_suffix
= ACE_DLL_SUFFIX
;
257 // If we have a dot, we have a suffix
260 // Check whether this matches the appropriate platform-specific
262 #if defined (ACE_WIN32)
263 // Use <ACE_OS::strcasecmp> on any platform with
264 // case-insensitive filenames.
265 if (ACE_OS::strcasecmp (s
, dll_suffix
) != 0)
267 if (ACE_OS::strcmp (s
, dll_suffix
) != 0)
268 #endif /* ACE_WIN32 */
270 ACE_ERROR ((LM_WARNING
,
271 ACE_TEXT ("Warning: improper suffix for a ")
272 ACE_TEXT ("shared library on this platform: %s\n"),
277 // Make sure we've got enough space in searchfilename.
278 if (ACE_OS::strlen (searchfilename
)
279 + ACE_OS::strlen (ACE_DLL_PREFIX
)
280 + (has_suffix
? 0 : ACE_OS::strlen (dll_suffix
))
281 >= (sizeof searchfilename
/ sizeof (ACE_TCHAR
)))
287 #if defined (ACE_WIN32) && defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
288 size_t len_searchfilename
= ACE_OS::strlen (searchfilename
);
290 ACE_OS::strcpy (searchfilename
+ len_searchfilename
,
293 for (int tag
= 1; tag
>= 0; tag
--)
296 searchfilename
[len_searchfilename
] = 0;
298 #endif /* ACE_WIN32 && ACE_LD_DECORATOR_STR && !ACE_DISABLE_DEBUG_DLL_CHECK */
299 // Use absolute pathname if there is one.
300 if (ACE_OS::strlen (searchpathname
) > 0)
302 if (ACE_OS::strlen (searchfilename
)
303 + ACE_OS::strlen (searchpathname
) >= maxpathnamelen
)
310 #if (ACE_DIRECTORY_SEPARATOR_CHAR != '/')
311 // Revert to native path name separators.
312 ACE::strrepl (searchpathname
,
314 ACE_DIRECTORY_SEPARATOR_CHAR
);
315 #endif /* ACE_DIRECTORY_SEPARATOR_CHAR */
316 // First, try matching the filename *without* adding a
318 ACE_OS::sprintf (pathname
,
322 has_suffix
? ACE_TEXT ("") : dll_suffix
);
323 if (ACE_OS::access (pathname
, F_OK
) == 0)
326 // Second, try matching the filename *with* adding a prefix.
327 ACE_OS::sprintf (pathname
,
328 ACE_TEXT ("%s%s%s%s"),
332 has_suffix
? ACE_TEXT ("") : dll_suffix
);
333 if (ACE_OS::access (pathname
, F_OK
) == 0)
338 // Use relative filenames via LD_LIBRARY_PATH or PATH (depending on
342 #if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
343 ACE_TCHAR
*file_component
= 0;
345 ACE_TEXT_SearchPath (0,
348 static_cast<DWORD
> (maxpathnamelen
),
351 if (pathlen
>= maxpathnamelen
)
356 else if (pathlen
> 0)
359 // In case not found we should try again with the ACE_DLL_PREFIX
361 ACE_OS::strcpy (searchfilename
, ACE_DLL_PREFIX
);
362 ACE_OS::strcat (searchfilename
, tempcopy
);
364 ACE_TEXT_SearchPath (0,
367 static_cast<DWORD
> (maxpathnamelen
),
370 if (pathlen
>= maxpathnamelen
)
375 else if (pathlen
> 0)
379 # if defined ACE_DEFAULT_LD_SEARCH_PATH
380 ld_path
= ACE_DEFAULT_LD_SEARCH_PATH
;
382 # if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR)
383 ld_path
= ACE_OS::getenv (ACE_LD_SEARCH_PATH
);
385 // Wide-char, non-Windows only offers char * getenv. So capture
386 // it, translate to wide-char, and continue.
387 ACE_Ascii_To_Wide wide_ldpath
388 (ACE_OS::getenv (ACE_TEXT_ALWAYS_CHAR (ACE_LD_SEARCH_PATH
)));
389 ld_path
= wide_ldpath
.wchar_rep ();
390 # endif /* ACE_WIN32 || !ACE_USES_WCHAR */
391 # endif /* ACE_DEFAULT_LD_SEARCH_PATH */
393 #if defined (ACE_HAS_WINCE)
394 ACE_TCHAR
*ld_path_temp
= 0;
397 ld_path_temp
= (ACE_TCHAR
*)
398 ACE_OS::malloc ((ACE_OS::strlen (ld_path
) + 2)
399 * sizeof (ACE_TCHAR
));
400 if (ld_path_temp
!= 0)
402 ACE_OS::strcpy (ld_path_temp
,
403 ACE_LD_SEARCH_PATH_SEPARATOR_STR
);
405 ACE_OS::strcat (ld_path_temp
, ld_path
);
406 ld_path
= ld_path_temp
;
410 ACE_OS::free ((void *) ld_path_temp
);
411 ld_path
= ld_path_temp
= 0;
414 #endif /* ACE_HAS_WINCE */
417 && (ld_path
= ACE_OS::strdup (ld_path
)) != 0)
419 // strtok has the strange behavior of not separating the
420 // string ":/foo:/bar" into THREE tokens. One would expect
421 // that the first iteration the token would be an empty
422 // string, the second iteration would be "/foo", and the
423 // third iteration would be "/bar". However, this is not
424 // the case; one only gets two iterations: "/foo" followed
427 // This is especially a problem in parsing Unix paths
428 // because it is permissible to specify 'the current
429 // directory' as an empty entry. So, we introduce the
430 // following special code to cope with this:
432 // Look at each dynamic lib directory in the search path.
434 ACE_TCHAR
*nextholder
= 0;
435 const ACE_TCHAR
*path_entry
=
436 ACE::strsplit_r (ld_path
,
437 ACE_LD_SEARCH_PATH_SEPARATOR_STR
,
443 // Check if at end of search path.
450 else if (ACE_OS::strlen (path_entry
)
452 + ACE_OS::strlen (searchfilename
)
459 // This works around the issue where a path might have
460 // an empty component indicating 'current directory'.
461 // We need to do it here rather than anywhere else so
462 // that the loop condition will still work.
463 else if (path_entry
[0] == '\0')
464 path_entry
= ACE_TEXT (".");
466 // First, try matching the filename *without* adding a
468 ACE_OS::sprintf (pathname
,
469 ACE_TEXT ("%s%c%s%s"),
471 ACE_DIRECTORY_SEPARATOR_CHAR
,
473 has_suffix
? ACE_TEXT ("") : dll_suffix
);
474 if (ACE_OS::access (pathname
, F_OK
) == 0)
477 // Second, try matching the filename *with* adding a
479 ACE_OS::sprintf (pathname
,
480 ACE_TEXT ("%s%c%s%s%s"),
482 ACE_DIRECTORY_SEPARATOR_CHAR
,
485 has_suffix
? ACE_TEXT ("") : dll_suffix
);
486 if (ACE_OS::access (pathname
, F_OK
) == 0)
489 // Fetch the next item in the path
492 ACE_LD_SEARCH_PATH_SEPARATOR_STR
,
496 #if defined (ACE_HAS_WINCE)
497 if (ld_path_temp
!= 0)
498 ACE_OS::free (ld_path_temp
);
499 #endif /* ACE_HAS_WINCE */
500 ACE_OS::free ((void *) ld_path
);
501 #if defined (ACE_HAS_WINCE) && defined (ACE_LD_DECORATOR_STR) && \
502 !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
503 if (result
== 0 || tag
== 0)
504 #endif /* ACE_HAS_WINCE && ACE_LD_DECORATOR_STR && !ACE_DISABLE_DEBUG_DLL_CHECK */
507 #endif /* ACE_WIN32 && !ACE_HAS_WINCE */
509 #if defined (ACE_WIN32) && defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
511 #endif /* ACE_WIN32 && ACE_LD_DECORATOR_STR && !ACE_DISABLE_DEBUG_DLL_CHECK */
518 ACE::ldopen (const ACE_TCHAR
*filename
,
519 const ACE_TCHAR
*type
)
521 ACE_TRACE ("ACE::ldopen");
523 ACE_TCHAR buf
[MAXPATHLEN
+ 1];
524 if (ACE::ldfind (filename
,
526 sizeof (buf
) /sizeof (ACE_TCHAR
)) == -1)
529 return ACE_OS::fopen (buf
, type
);
533 ACE::ldname (const ACE_TCHAR
*entry_point
)
535 ACE_TRACE ("ACE::ldname");
537 #if defined(ACE_NEEDS_DL_UNDERSCORE)
540 + ACE_OS::strlen (entry_point
)
544 ACE_NEW_RETURN (new_name
,
548 ACE_OS::strcpy (new_name
, ACE_TEXT ("_"));
549 ACE_OS::strcat (new_name
, entry_point
);
552 #else /* ACE_NEEDS_DL_UNDERSCORE */
554 ACE_OS::strlen (entry_point
)
558 ACE_NEW_RETURN (new_name
,
562 ACE_OS::strcpy (new_name
, entry_point
);
564 #endif /* ACE_NEEDS_DL_UNDERSCORE */
567 #if defined (ACE_OPENVMS)
569 ACE::ldregister (const ACE_TCHAR
*entry_point
,
572 ACE_LD_SYMBOL_REGISTRY::instance ()->register_symbol (entry_point
,
577 ACE::ldsymbol (ACE_SHLIB_HANDLE sh
, const ACE_TCHAR
*entry_point
)
579 void* symaddr
= ACE_OS::dlsym (sh
, entry_point
);
580 // if not found through dlsym() try registry
582 symaddr
= ACE_LD_SYMBOL_REGISTRY::instance ()->find_symbol (entry_point
);
589 ACE::get_temp_dir (ACE_TCHAR
*buffer
, size_t buffer_len
)
592 #if defined (ACE_WIN32)
593 result
= ACE_TEXT_GetTempPath (static_cast<DWORD
> (buffer_len
),
596 // Make sure to return -1 if there is an error
597 if (result
== 0 && ::GetLastError () != ERROR_SUCCESS
598 || result
> static_cast<int> (buffer_len
))
601 #else /* ACE_WIN32 */
603 // NOTE! Non-Windows platforms don't deal with wide chars for env.
604 // variables, so do this narrow-char and convert to wide for the
605 // caller if necessary.
607 // On non-win32 platforms, check to see what the TMPDIR environment
608 // variable is defined to be. If it doesn't exist, just use /tmp
609 const char *tmpdir
= ACE_OS::getenv ("TMPDIR");
614 size_t len
= ACE_OS::strlen (tmpdir
);
616 // Check to see if the buffer is large enough for the string,
617 // another /, and its null character (hence the + 2)
618 if ((len
+ 2) > buffer_len
)
624 ACE_OS::strcpy (buffer
, ACE_TEXT_CHAR_TO_TCHAR (tmpdir
));
626 // Add a trailing slash because we cannot assume there is already one
627 // at the end. And having an extra one should not cause problems.
628 buffer
[len
] = ACE_TEXT ('/');
632 #endif /* ACE_WIN32 */
637 ACE::open_temp_file (const ACE_TCHAR
*name
, int mode
, int perm
)
639 #if defined (ACE_WIN32)
640 ACE_UNUSED_ARG (perm
);
641 ACE_HANDLE handle
= ACE_OS::open (name
,
645 | FILE_SHARE_DELETE
);
648 ACE_HANDLE handle
= ACE_OS::open (name
, mode
, perm
);
649 #endif /* ACE_WIN32 */
651 if (handle
== ACE_INVALID_HANDLE
)
652 return ACE_INVALID_HANDLE
;
654 // Unlink it so that the file will be removed automatically when the
655 // process goes away.
656 if (ACE_OS::unlink (name
) == -1)
657 return ACE_INVALID_HANDLE
;
659 // Return the handle.
664 ACE::strrepl (char *s
, char search
, char replace
)
666 ACE_TRACE ("ACE::strrepl");
670 for (size_t i
= 0; s
[i
] != '\0'; i
++)
681 // Split a string up into 'token'-delimited pieces, ala Perl's
685 ACE::strsplit_r (char *str
,
696 char *tok_loc
= ACE_OS::strstr (next_start
, token
);
700 // Return the beginning of the string.
703 // Insure it's terminated.
705 next_start
= tok_loc
+ ACE_OS::strlen (token
);
710 next_start
= (char *) 0;
717 #if defined (ACE_HAS_WCHAR)
719 ACE::strsplit_r (wchar_t *str
,
720 const wchar_t *token
,
721 wchar_t *&next_start
)
730 wchar_t *tok_loc
= ACE_OS::strstr (next_start
, token
);
734 // Return the beginning of the string.
737 // Insure it's terminated.
739 next_start
= tok_loc
+ ACE_OS::strlen (token
);
744 next_start
= (wchar_t *) 0;
752 ACE::strrepl (wchar_t *s
, wchar_t search
, wchar_t replace
)
754 ACE_TRACE ("ACE::strrepl");
758 for (size_t i
= 0; s
[i
] != '\0'; i
++)
767 #endif /* ACE_HAS_WCHAR */
769 ACE_END_VERSIONED_NAMESPACE_DECL