Back out dependencies on lib/System/Path.h
[oota-llvm.git] / lib / System / linux / Path.cpp
1 //===- Path.cpp - Path Operating System Concept -----------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // Copyright (C) 2004 eXtensible Systems, Inc. All Rights Reserved.
6 //
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.
10 //
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.
14 //
15 //===----------------------------------------------------------------------===//
16 //===----------------------------------------------------------------------===//
17 /// @file lib/System/linux/Path.cpp
18 /// @author Reid Spencer <raspencer@users.sourceforge.net> (original author)
19 /// @version \verbatim $Id$ \endverbatim
20 /// @date 2003/04/17
21 /// @since 1.4
22 /// @brief Implements the linux specific portion of class llvm::sys::Path
23 ////////////////////////////////////////////////////////////////////////////////
24
25 #include "LinuxCommon.h"
26 #include <sys/stat.h>
27 #include <fcntl.h>
28
29 namespace llvm {
30 namespace sys {
31
32 Path::Path(ConstructSpecial which) throw() {
33   switch (which) {
34     case CONSTRUCT_TEMP_FILE:
35       this->make_temp_file();
36       break;
37     case CONSTRUCT_TEMP_DIR:
38       this->make_temp_directory();
39       break;
40   }
41 }
42
43 bool 
44 Path::is_file() const throw() {
45   if ( !empty() && ((*this)[length()-1] !=  '/' ))
46     return true;
47   return false;
48 }
49
50 bool 
51 Path::is_directory() const throw() {
52   if ((!empty()) && ((*this)[length()-1] ==  '/' ))
53       return true;
54   return false;
55 }
56
57 ErrorCode 
58 Path::make_directory() throw() {
59   char end[2];
60   end[0] = '/';
61   end[1] = 0;
62   if ( empty() )
63     this->assign( end );
64   else if ( (*this)[length()-1] != '/' )
65     this->append( end );
66   return NOT_AN_ERROR;
67 }
68
69 ErrorCode
70 Path::make_temp_directory() throw() {
71   char temp_name[64];
72   ::strcpy(temp_name,"/tmp/llvm_XXXXXX");
73   char* res = ::mkdtemp(temp_name);
74   if ( res == 0 )
75     RETURN_ERRNO;
76   *this = temp_name;
77   make_directory();
78   return NOT_AN_ERROR;
79 }
80
81 ErrorCode
82 Path::make_file() throw() {
83   if ( (*this)[length()-1] == '/' )
84     this->erase( this->length()-1, 1 );
85   return NOT_AN_ERROR;
86 }
87
88 ErrorCode
89 Path::make_temp_file() throw() {
90   char temp_name[64];
91   ::strcpy(temp_name,"/tmp/llvm_XXXXXX");
92   int fd = ::mkstemp(temp_name);
93   if ( fd == -1 )
94     RETURN_ERRNO;
95   ::close(fd);
96   *this = temp_name;
97   return NOT_AN_ERROR;
98 }
99
100 ErrorCode
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 ) );
108   return NOT_AN_ERROR;
109 }
110
111 ErrorCode
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 ) );
119   return NOT_AN_ERROR;
120 }
121
122 ErrorCode
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],'/');
132   while ( next != 0 )
133   {
134     *next = 0;
135     if ( 0 != access( pathname, F_OK | R_OK ) )
136       RETURN_ON_ERROR( mkdir, (pathname, S_IRWXU | S_IRWXG ) );
137     char* save = next;
138     next = index(pathname,'/');
139     *save = '/';
140   }
141   return NOT_AN_ERROR;
142 }
143
144 ErrorCode
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) );
152   return NOT_AN_ERROR;
153 }
154
155 ErrorCode
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 ) );
163   return NOT_AN_ERROR;
164 }
165
166 ErrorCode
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) );
174   return NOT_AN_ERROR;
175 }
176
177 ErrorCode
178 Path::find_lib( const char * file ) throw()
179 {
180     ASSERT_ARG( file != 0 );
181
182 #if 0
183   ACE_TCHAR tempcopy[MAXPATHLEN + 1];
184   ACE_TCHAR searchpathname[MAXPATHLEN + 1];
185   ACE_TCHAR searchfilename[MAXPATHLEN + 1];
186
187   // Create a copy of filename to work with.
188   if (ACE_OS::strlen (filename) + 1
189       > (sizeof tempcopy / sizeof (ACE_TCHAR)))
190     {
191       errno = ENOMEM;
192       return -1;
193     }
194   else
195     ACE_OS::strcpy (tempcopy, filename);
196
197   // Insert canonical directory separators.
198   ACE_TCHAR *separator_ptr;
199
200 #if (ACE_DIRECTORY_SEPARATOR_CHAR != '/')
201   // Make all the directory separators "canonical" to simplify
202   // subsequent code.
203   ACE_Lib_Find::strrepl (tempcopy, ACE_DIRECTORY_SEPARATOR_CHAR, '/');
204 #endif /* ACE_DIRECTORY_SEPARATOR_CHAR */
205
206   // Separate filename from pathname.
207   separator_ptr = ACE_OS::strrchr (tempcopy, '/');
208
209   // This is a relative path.
210   if (separator_ptr == 0)
211     {
212       searchpathname[0] = '\0';
213       ACE_OS::strcpy (searchfilename, tempcopy);
214     }
215   else // This is an absolute path.
216     {
217       ACE_OS::strcpy (searchfilename, separator_ptr + 1);
218       separator_ptr[1] = '\0';
219       ACE_OS::strcpy (searchpathname, tempcopy);
220     }
221
222   int got_suffix = 0;
223
224   // Check to see if this has an appropriate DLL suffix for the OS
225   // platform.
226   ACE_TCHAR *s = ACE_OS::strrchr (searchfilename, '.');
227
228   const ACE_TCHAR *dll_suffix = ACE_DLL_SUFFIX;
229
230   if (s != 0)
231     {
232       // If we have a dot, we have a suffix
233       got_suffix = 1;
234
235       // Check whether this matches the appropriate platform-specific
236       // suffix.
237       if (ACE_OS::strcmp (s, dll_suffix) != 0)
238         {
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"),
242                       s));
243         }
244     }
245
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 /
250                                                          sizeof (ACE_TCHAR)))
251     {
252       errno = ENOMEM;
253       return -1;
254     }
255
256       // Use absolute pathname if there is one.
257       if (ACE_OS::strlen (searchpathname) > 0)
258         {
259           if (ACE_OS::strlen (searchfilename)
260               + ACE_OS::strlen (searchpathname) >= maxpathnamelen)
261             {
262               errno = ENOMEM;
263               return -1;
264             }
265           else
266             {
267 #if (ACE_DIRECTORY_SEPARATOR_CHAR != '/')
268               // Revert to native path name separators.
269               ACE_Lib_Find::strrepl (searchpathname,
270                       '/',
271                                      ACE_DIRECTORY_SEPARATOR_CHAR);
272 #endif /* ACE_DIRECTORY_SEPARATOR_CHAR */
273               // First, try matching the filename *without* adding a
274               // prefix.
275 #if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
276               ACE_OS::sprintf (pathname,
277                                ACE_LIB_TEXT ("%s%s%s"),
278                                searchpathname,
279                                searchfilename,
280                                got_suffix ? ACE_static_cast (ACE_TCHAR *,
281                                                              ACE_LIB_TEXT (""))
282                                : ACE_static_cast (ACE_TCHAR *,
283                                                   dll_suffix));
284 #else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
285               ACE_OS::sprintf (pathname,
286                                ACE_LIB_TEXT ("%s%s%s"),
287                                searchpathname,
288                                searchfilename,
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)
292                 return 0;
293
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"),
298                                searchpathname,
299                                ACE_DLL_PREFIX,
300                                searchfilename,
301                                got_suffix ? ACE_static_cast (ACE_TCHAR *,
302                                                              ACE_LIB_TEXT (""))
303                                : ACE_static_cast (ACE_TCHAR *,
304                                                   dll_suffix));
305 #else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
306               ACE_OS::sprintf (pathname,
307                                ACE_LIB_TEXT ("%s%s%s%s"),
308                                searchpathname,
309                                ACE_DLL_PREFIX,
310                                searchfilename,
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)
314                 return 0;
315             }
316         }
317
318       // Use relative filenames via LD_LIBRARY_PATH or PATH (depending on
319       // OS platform).
320       else
321         {
322           ACE_TCHAR *ld_path =
323 #if defined ACE_DEFAULT_LD_SEARCH_PATH
324             ACE_DEFAULT_LD_SEARCH_PATH;
325 #else
326             ACE_OS::getenv (ACE_LD_SEARCH_PATH);
327 #endif /* ACE_DEFAULT_LD_SEARCH_PATH */
328
329           if (ld_path != 0
330               && (ld_path = ACE_OS::strdup (ld_path)) != 0)
331             {
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
338               // by "/bar".
339
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:
344
345               // Look at each dynamic lib directory in the search path.
346
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,
351                                           nextholder);
352               int result = 0;
353
354               for (;;)
355                 {
356                   // Check if at end of search path.
357                   if (path_entry == 0)
358                     {
359                       errno = ENOENT;
360                       result = -1;
361                       break;
362                     }
363                   else if (ACE_OS::strlen (path_entry)
364                            + 1
365                            + ACE_OS::strlen (searchfilename)
366                            >= maxpathnamelen)
367                     {
368                       errno = ENOMEM;
369                       result = -1;
370                       break;
371                     }
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 (".");
378
379                   // First, try matching the filename *without* adding a
380                   // prefix.
381 #if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
382                   ACE_OS::sprintf (pathname,
383                                    ACE_LIB_TEXT ("%s%c%s%s"),
384                                    path_entry,
385                                    ACE_DIRECTORY_SEPARATOR_CHAR,
386                                    searchfilename,
387                                    got_suffix ? ACE_static_cast (ACE_TCHAR *,
388                                                                  ACE_LIB_TEXT (""))
389                                    : ACE_static_cast (ACE_TCHAR *,
390                                                       dll_suffix));
391 #else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
392                   ACE_OS::sprintf (pathname,
393                                    ACE_LIB_TEXT ("%s%c%s%s"),
394                                    path_entry,
395                                    ACE_DIRECTORY_SEPARATOR_CHAR,
396                                    searchfilename,
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)
400                     break;
401
402                   // Second, try matching the filename *with* adding a
403                   // prefix.
404 #if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
405                   ACE_OS::sprintf (pathname,
406                                    ACE_LIB_TEXT ("%s%c%s%s%s"),
407                                    path_entry,
408                                    ACE_DIRECTORY_SEPARATOR_CHAR,
409                                    ACE_DLL_PREFIX,
410                                    searchfilename,
411                                    got_suffix ? ACE_static_cast (ACE_TCHAR *,
412                                                                  ACE_LIB_TEXT (""))
413                                    : ACE_static_cast (ACE_TCHAR *,
414                                                       dll_suffix));
415 #else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
416                   ACE_OS::sprintf (pathname,
417                                    ACE_LIB_TEXT ("%s%c%s%s%s"),
418                                    path_entry,
419                                    ACE_DIRECTORY_SEPARATOR_CHAR,
420                                    ACE_DLL_PREFIX,
421                                    searchfilename,
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)
425                     break;
426
427                   // Fetch the next item in the path
428                   path_entry = ACE_Lib_Find::strsplit_r (0,
429                                                          ACE_LD_SEARCH_PATH_SEPARATOR_STR,
430                                                          nextholder);
431                 }
432
433               ACE_OS::free ((void *) ld_path);
434                 return result;
435             }
436         }
437   errno = ENOENT;
438   return -1;
439 #endif
440
441     /// @todo FIXME: Convert ACE code
442     *this = Path( file ); 
443     
444     return NOT_AN_ERROR;
445 }
446
447 }
448 }
449
450 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab