1 //===- Path.cpp - Path Operating System Concept -----------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // Copyright (C) 2004 eXtensible Systems, Inc. All Rights Reserved.
7 // This program is open source software; you can redistribute it and/or modify
8 // it under the terms of the University of Illinois Open Source License. See
9 // LICENSE.TXT (distributed with this software) for details.
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 // or FITNESS FOR A PARTICULAR PURPOSE.
15 //===----------------------------------------------------------------------===//
16 //===----------------------------------------------------------------------===//
17 /// @file lib/System/linux/Path.cpp
18 /// @author Reid Spencer <raspencer@users.sourceforge.net> (original author)
19 /// @version \verbatim $Id$ \endverbatim
22 /// @brief Implements the linux specific portion of class llvm::sys::Path
23 ////////////////////////////////////////////////////////////////////////////////
25 #include "LinuxCommon.h"
32 Path::Path(ConstructSpecial which) throw() {
34 case CONSTRUCT_TEMP_FILE:
35 this->make_temp_file();
37 case CONSTRUCT_TEMP_DIR:
38 this->make_temp_directory();
44 Path::is_file() const throw() {
45 if ( !empty() && ((*this)[length()-1] != '/' ))
51 Path::is_directory() const throw() {
52 if ((!empty()) && ((*this)[length()-1] == '/' ))
58 Path::make_directory() throw() {
64 else if ( (*this)[length()-1] != '/' )
70 Path::make_temp_directory() throw() {
72 ::strcpy(temp_name,"/tmp/llvm_XXXXXX");
73 char* res = ::mkdtemp(temp_name);
82 Path::make_file() throw() {
83 if ( (*this)[length()-1] == '/' )
84 this->erase( this->length()-1, 1 );
89 Path::make_temp_file() throw() {
91 ::strcpy(temp_name,"/tmp/llvm_XXXXXX");
92 int fd = ::mkstemp(temp_name);
101 Path::exists() throw() {
102 char pathname[MAXPATHLEN];
103 this->fill(pathname,MAXPATHLEN);
104 int lastchar = this->length() - 1 ;
105 if (pathname[lastchar] == '/')
106 pathname[lastchar] = 0;
107 RETURN_ON_ERROR( access,( pathname, F_OK | R_OK ) );
112 Path::create_directory() throw() {
113 char pathname[MAXPATHLEN];
114 this->fill(pathname,MAXPATHLEN);
115 int lastchar = this->length() - 1 ;
116 if (pathname[lastchar] == '/')
117 pathname[lastchar] = 0;
118 RETURN_ON_ERROR( mkdir, ( pathname, S_IRWXU | S_IRWXG ) );
123 Path::create_directories() throw() {
124 char pathname[MAXPATHLEN];
125 this->fill(pathname,MAXPATHLEN);
126 int lastchar = this->length() - 1 ;
127 if (pathname[lastchar] == '/')
128 pathname[lastchar] = 0;
129 char * next = index(pathname,'/');
130 if ( pathname[0] == '/' )
131 next = index(&pathname[1],'/');
135 if ( 0 != access( pathname, F_OK | R_OK ) )
136 RETURN_ON_ERROR( mkdir, (pathname, S_IRWXU | S_IRWXG ) );
138 next = index(pathname,'/');
145 Path::remove_directory( ) throw() {
146 char pathname[MAXPATHLEN];
147 this->fill(pathname,MAXPATHLEN);
148 int lastchar = this->length() - 1 ;
149 if (pathname[lastchar] == '/')
150 pathname[lastchar] = 0;
151 RETURN_ON_ERROR( rmdir, (pathname) );
156 Path::create_file( ) throw() {
157 char pathname[MAXPATHLEN];
158 this->fill(pathname,MAXPATHLEN);
159 int lastchar = this->length() - 1 ;
160 if (pathname[lastchar] == '/')
161 pathname[lastchar] = 0;
162 RETURN_ON_ERROR( creat, ( pathname, S_IRUSR | S_IWUSR ) );
167 Path::remove_file( ) throw() {
168 char pathname[MAXPATHLEN];
169 this->fill(pathname,MAXPATHLEN);
170 int lastchar = this->length() - 1 ;
171 if (pathname[lastchar] == '/')
172 pathname[lastchar] = 0;
173 RETURN_ON_ERROR( unlink, (pathname) );
178 Path::find_lib( const char * file ) throw()
180 ASSERT_ARG( file != 0 );
183 ACE_TCHAR tempcopy[MAXPATHLEN + 1];
184 ACE_TCHAR searchpathname[MAXPATHLEN + 1];
185 ACE_TCHAR searchfilename[MAXPATHLEN + 1];
187 // Create a copy of filename to work with.
188 if (ACE_OS::strlen (filename) + 1
189 > (sizeof tempcopy / sizeof (ACE_TCHAR)))
195 ACE_OS::strcpy (tempcopy, filename);
197 // Insert canonical directory separators.
198 ACE_TCHAR *separator_ptr;
200 #if (ACE_DIRECTORY_SEPARATOR_CHAR != '/')
201 // Make all the directory separators "canonical" to simplify
203 ACE_Lib_Find::strrepl (tempcopy, ACE_DIRECTORY_SEPARATOR_CHAR, '/');
204 #endif /* ACE_DIRECTORY_SEPARATOR_CHAR */
206 // Separate filename from pathname.
207 separator_ptr = ACE_OS::strrchr (tempcopy, '/');
209 // This is a relative path.
210 if (separator_ptr == 0)
212 searchpathname[0] = '\0';
213 ACE_OS::strcpy (searchfilename, tempcopy);
215 else // This is an absolute path.
217 ACE_OS::strcpy (searchfilename, separator_ptr + 1);
218 separator_ptr[1] = '\0';
219 ACE_OS::strcpy (searchpathname, tempcopy);
224 // Check to see if this has an appropriate DLL suffix for the OS
226 ACE_TCHAR *s = ACE_OS::strrchr (searchfilename, '.');
228 const ACE_TCHAR *dll_suffix = ACE_DLL_SUFFIX;
232 // If we have a dot, we have a suffix
235 // Check whether this matches the appropriate platform-specific
237 if (ACE_OS::strcmp (s, dll_suffix) != 0)
239 ACE_ERROR ((LM_WARNING,
240 ACE_LIB_TEXT ("Warning: improper suffix for a ")
241 ACE_LIB_TEXT ("shared library on this platform: %s\n"),
246 // Make sure we've got enough space in searchfilename.
247 if (ACE_OS::strlen (searchfilename)
248 + ACE_OS::strlen (ACE_DLL_PREFIX)
249 + got_suffix ? 0 : ACE_OS::strlen (dll_suffix) >= (sizeof searchfilename /
256 // Use absolute pathname if there is one.
257 if (ACE_OS::strlen (searchpathname) > 0)
259 if (ACE_OS::strlen (searchfilename)
260 + ACE_OS::strlen (searchpathname) >= maxpathnamelen)
267 #if (ACE_DIRECTORY_SEPARATOR_CHAR != '/')
268 // Revert to native path name separators.
269 ACE_Lib_Find::strrepl (searchpathname,
271 ACE_DIRECTORY_SEPARATOR_CHAR);
272 #endif /* ACE_DIRECTORY_SEPARATOR_CHAR */
273 // First, try matching the filename *without* adding a
275 #if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
276 ACE_OS::sprintf (pathname,
277 ACE_LIB_TEXT ("%s%s%s"),
280 got_suffix ? ACE_static_cast (ACE_TCHAR *,
282 : ACE_static_cast (ACE_TCHAR *,
284 #else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
285 ACE_OS::sprintf (pathname,
286 ACE_LIB_TEXT ("%s%s%s"),
289 got_suffix ? ACE_LIB_TEXT ("") : dll_suffix);
290 #endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
291 if (ACE_OS::access (pathname, F_OK) == 0)
294 // Second, try matching the filename *with* adding a prefix.
295 #if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
296 ACE_OS::sprintf (pathname,
297 ACE_LIB_TEXT ("%s%s%s%s"),
301 got_suffix ? ACE_static_cast (ACE_TCHAR *,
303 : ACE_static_cast (ACE_TCHAR *,
305 #else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
306 ACE_OS::sprintf (pathname,
307 ACE_LIB_TEXT ("%s%s%s%s"),
311 got_suffix ? ACE_LIB_TEXT ("") : dll_suffix);
312 #endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
313 if (ACE_OS::access (pathname, F_OK) == 0)
318 // Use relative filenames via LD_LIBRARY_PATH or PATH (depending on
323 #if defined ACE_DEFAULT_LD_SEARCH_PATH
324 ACE_DEFAULT_LD_SEARCH_PATH;
326 ACE_OS::getenv (ACE_LD_SEARCH_PATH);
327 #endif /* ACE_DEFAULT_LD_SEARCH_PATH */
330 && (ld_path = ACE_OS::strdup (ld_path)) != 0)
332 // strtok has the strange behavior of not separating the
333 // string ":/foo:/bar" into THREE tokens. One would expect
334 // that the first iteration the token would be an empty
335 // string, the second iteration would be "/foo", and the
336 // third iteration would be "/bar". However, this is not
337 // the case; one only gets two iterations: "/foo" followed
340 // This is especially a problem in parsing Unix paths
341 // because it is permissible to specify 'the current
342 // directory' as an empty entry. So, we introduce the
343 // following special code to cope with this:
345 // Look at each dynamic lib directory in the search path.
347 ACE_TCHAR *nextholder = 0;
348 const ACE_TCHAR *path_entry =
349 ACE_Lib_Find::strsplit_r (ld_path,
350 ACE_LD_SEARCH_PATH_SEPARATOR_STR,
356 // Check if at end of search path.
363 else if (ACE_OS::strlen (path_entry)
365 + ACE_OS::strlen (searchfilename)
372 // This works around the issue where a path might have
373 // an empty component indicating 'current directory'.
374 // We need to do it here rather than anywhere else so
375 // that the loop condition will still work.
376 else if (path_entry[0] == '\0')
377 path_entry = ACE_LIB_TEXT (".");
379 // First, try matching the filename *without* adding a
381 #if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
382 ACE_OS::sprintf (pathname,
383 ACE_LIB_TEXT ("%s%c%s%s"),
385 ACE_DIRECTORY_SEPARATOR_CHAR,
387 got_suffix ? ACE_static_cast (ACE_TCHAR *,
389 : ACE_static_cast (ACE_TCHAR *,
391 #else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
392 ACE_OS::sprintf (pathname,
393 ACE_LIB_TEXT ("%s%c%s%s"),
395 ACE_DIRECTORY_SEPARATOR_CHAR,
397 got_suffix ? ACE_LIB_TEXT ("") : dll_suffix);
398 #endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
399 if (ACE_OS::access (pathname, F_OK) == 0)
402 // Second, try matching the filename *with* adding a
404 #if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
405 ACE_OS::sprintf (pathname,
406 ACE_LIB_TEXT ("%s%c%s%s%s"),
408 ACE_DIRECTORY_SEPARATOR_CHAR,
411 got_suffix ? ACE_static_cast (ACE_TCHAR *,
413 : ACE_static_cast (ACE_TCHAR *,
415 #else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
416 ACE_OS::sprintf (pathname,
417 ACE_LIB_TEXT ("%s%c%s%s%s"),
419 ACE_DIRECTORY_SEPARATOR_CHAR,
422 got_suffix ? ACE_LIB_TEXT ("") : dll_suffix);
423 #endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
424 if (ACE_OS::access (pathname, F_OK) == 0)
427 // Fetch the next item in the path
428 path_entry = ACE_Lib_Find::strsplit_r (0,
429 ACE_LD_SEARCH_PATH_SEPARATOR_STR,
433 ACE_OS::free ((void *) ld_path);
441 /// @todo FIXME: Convert ACE code
442 *this = Path( file );
450 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab