Allow "bc" as suffix for bytecode files.
[oota-llvm.git] / lib / System / Unix / Path.cpp
1 //===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Reid Spencer and is distributed under the 
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Unix specific portion of the Path class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic UNIX code that
16 //===          is guaranteed to work on *all* UNIX variants.
17 //===----------------------------------------------------------------------===//
18
19 #include <llvm/Config/config.h>
20 #include "Unix.h"
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <fstream>
24
25 namespace llvm {
26 using namespace sys;
27
28 Path::Path(std::string unverified_path) 
29   : path(unverified_path)
30 {
31   if (unverified_path.empty())
32     return;
33   if (this->is_valid()) 
34     return;
35   // oops, not valid.
36   path.clear();
37   ThrowErrno(unverified_path + ": path is not valid");
38 }
39
40 Path
41 Path::GetRootDirectory() {
42   Path result;
43   result.set_directory("/");
44   return result;
45 }
46
47 static inline bool IsLibrary(Path& path, const std::string& basename) {
48   if (path.append_file(std::string("lib") + basename)) {
49     if (path.append_suffix(Path::GetDLLSuffix()) && path.readable())
50       return true;
51     else if (path.elide_suffix() && path.append_suffix("a") && path.readable())
52       return true;
53     else if (path.elide_suffix() && path.append_suffix("o") && path.readable())
54       return true;
55     else if (path.elide_suffix() && path.append_suffix("bc") && path.readable())
56       return true;
57   } else if (path.elide_file() && path.append_file(basename)) {
58     if (path.append_suffix(Path::GetDLLSuffix()) && path.readable())
59       return true;
60     else if (path.elide_suffix() && path.append_suffix("a") && path.readable())
61       return true;
62     else if (path.elide_suffix() && path.append_suffix("o") && path.readable())
63       return true;
64     else if (path.elide_suffix() && path.append_suffix("bc") && path.readable())
65       return true;
66   }
67   path.clear();
68   return false;
69 }
70
71 Path 
72 Path::GetLibraryPath(const std::string& basename, 
73                      const std::vector<std::string>& LibPaths) {
74   Path result;
75
76   // Try the paths provided
77   for (std::vector<std::string>::const_iterator I = LibPaths.begin(),
78        E = LibPaths.end(); I != E; ++I ) {
79     if (result.set_directory(*I) && IsLibrary(result,basename))
80       return result;
81   }
82
83   // Try the LLVM lib directory in the LLVM install area
84   if (result.set_directory(LLVM_LIBDIR) && IsLibrary(result,basename))
85     return result;
86
87   // Try /usr/lib
88   if (result.set_directory("/usr/lib/") && IsLibrary(result,basename))
89     return result;
90
91   // Try /lib
92   if (result.set_directory("/lib/") && IsLibrary(result,basename))
93     return result;
94
95   // Can't find it, give up and return invalid path.
96   result.clear();
97   return result;
98 }
99
100 Path 
101 Path::GetSystemLibraryPath1() {
102   return Path("/lib/");
103 }
104
105 Path 
106 Path::GetSystemLibraryPath2() {
107   return Path("/usr/lib/");
108 }
109
110 Path 
111 Path::GetLLVMDefaultConfigDir() {
112   return Path("/etc/llvm/");
113 }
114
115 Path 
116 Path::GetLLVMConfigDir() {
117   Path result;
118   if (result.set_directory(LLVM_ETCDIR))
119     return result;
120   return GetLLVMDefaultConfigDir();
121 }
122
123 Path
124 Path::GetUserHomeDirectory() {
125   const char* home = getenv("HOME");
126   if (home) {
127     Path result;
128     if (result.set_directory(home))
129       return result;
130   }
131   return GetRootDirectory();
132 }
133
134 bool
135 Path::is_file() const {
136   return (is_valid() && path[path.length()-1] != '/');
137 }
138
139 bool
140 Path::is_directory() const {
141   return (is_valid() && path[path.length()-1] == '/');
142 }
143
144 std::string
145 Path::get_basename() const {
146   // Find the last slash
147   size_t slash = path.rfind('/');
148   if (slash == std::string::npos)
149     slash = 0;
150   else
151     slash++;
152
153   return path.substr(slash, path.rfind('.'));
154 }
155
156 bool Path::has_magic_number(const std::string &Magic) const {
157   size_t len = Magic.size();
158   char buf[ 1 + len];
159   std::ifstream f(path.c_str());
160   f.read(buf, len);
161   buf[len] = '\0';
162   return Magic == buf;
163 }
164
165 bool 
166 Path::is_bytecode_file() const {
167   if (readable()) {
168     return has_magic_number("llvm");
169   }
170   return false;
171 }
172
173 bool
174 Path::is_archive() const {
175   if (readable()) {
176     return has_magic_number("!<arch>\012");
177   }
178   return false;
179 }
180
181 bool
182 Path::exists() const {
183   return 0 == access(path.c_str(), F_OK );
184 }
185
186 bool
187 Path::readable() const {
188   return 0 == access(path.c_str(), F_OK | R_OK );
189 }
190
191 bool
192 Path::writable() const {
193   return 0 == access(path.c_str(), F_OK | W_OK );
194 }
195
196 bool
197 Path::executable() const {
198   return 0 == access(path.c_str(), R_OK | X_OK );
199 }
200
201 std::string 
202 Path::getLast() const {
203   // Find the last slash
204   size_t pos = path.rfind('/');
205
206   // Handle the corner cases
207   if (pos == std::string::npos)
208     return path;
209
210   // If the last character is a slash
211   if (pos == path.length()-1) {
212     // Find the second to last slash
213     size_t pos2 = path.rfind('/', pos-1);
214     if (pos2 == std::string::npos)
215       return path.substr(0,pos);
216     else
217       return path.substr(pos2+1,pos-pos2-1);
218   }
219   // Return everything after the last slash
220   return path.substr(pos+1);
221 }
222
223 bool
224 Path::set_directory(const std::string& a_path) {
225   if (a_path.size() == 0)
226     return false;
227   Path save(*this);
228   path = a_path;
229   size_t last = a_path.size() -1;
230   if (last != 0 && a_path[last] != '/')
231     path += '/';
232   if (!is_valid()) {
233     path = save.path;
234     return false;
235   }
236   return true;
237 }
238
239 bool
240 Path::set_file(const std::string& a_path) {
241   if (a_path.size() == 0)
242     return false;
243   Path save(*this);
244   path = a_path;
245   size_t last = a_path.size() - 1;
246   while (last > 0 && a_path[last] == '/')
247     last--;
248   path.erase(last+1);
249   if (!is_valid()) {
250     path = save.path;
251     return false;
252   }
253   return true;
254 }
255
256 bool
257 Path::append_directory(const std::string& dir) {
258   if (is_file()) 
259     return false;
260   Path save(*this);
261   path += dir;
262   path += "/";
263   if (!is_valid()) {
264     path = save.path;
265     return false;
266   }
267   return true;
268 }
269
270 bool
271 Path::elide_directory() {
272   if (is_file()) 
273     return false;
274   size_t slashpos = path.rfind('/',path.size());
275   if (slashpos == 0 || slashpos == std::string::npos)
276     return false;
277   if (slashpos == path.size() - 1)
278     slashpos = path.rfind('/',slashpos-1);
279   if (slashpos == std::string::npos)
280     return false;
281   path.erase(slashpos);
282   return true;
283 }
284
285 bool
286 Path::append_file(const std::string& file) {
287   if (!is_directory()) 
288     return false;
289   Path save(*this);
290   path += file;
291   if (!is_valid()) {
292     path = save.path;
293     return false;
294   }
295   return true;
296 }
297
298 bool
299 Path::elide_file() {
300   if (is_directory()) 
301     return false;
302   size_t slashpos = path.rfind('/',path.size());
303   if (slashpos == std::string::npos)
304     return false;
305   path.erase(slashpos+1);
306   return true;
307 }
308
309 bool
310 Path::append_suffix(const std::string& suffix) {
311   if (is_directory()) 
312     return false;
313   Path save(*this);
314   path.append(".");
315   path.append(suffix);
316   if (!is_valid()) {
317     path = save.path;
318     return false;
319   }
320   return true;
321 }
322
323 bool 
324 Path::elide_suffix() {
325   if (is_directory()) return false;
326   size_t dotpos = path.rfind('.',path.size());
327   size_t slashpos = path.rfind('/',path.size());
328   if (slashpos != std::string::npos && dotpos != std::string::npos &&
329       dotpos > slashpos) {
330     path.erase(dotpos, path.size()-dotpos);
331     return true;
332   }
333   return false;
334 }
335
336
337 bool
338 Path::create_directory( bool create_parents) {
339   // Make sure we're dealing with a directory
340   if (!is_directory()) return false;
341
342   // Get a writeable copy of the path name
343   char pathname[MAXPATHLEN];
344   path.copy(pathname,MAXPATHLEN);
345
346   // Null-terminate the last component
347   int lastchar = path.length() - 1 ; 
348   if (pathname[lastchar] == '/') 
349     pathname[lastchar] = 0;
350
351   // If we're supposed to create intermediate directories
352   if ( create_parents ) {
353     // Find the end of the initial name component
354     char * next = strchr(pathname,'/');
355     if ( pathname[0] == '/') 
356       next = strchr(&pathname[1],'/');
357
358     // Loop through the directory components until we're done 
359     while ( next != 0 ) {
360       *next = 0;
361       if (0 != access(pathname, F_OK | R_OK | W_OK))
362         if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
363           ThrowErrno(std::string(pathname) + ": Can't create directory");
364       char* save = next;
365       next = strchr(pathname,'/');
366       *save = '/';
367     }
368   } else if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
369     ThrowErrno(std::string(pathname) + ": Can't create directory");
370   } 
371   return true;
372 }
373
374 bool
375 Path::create_file() {
376   // Make sure we're dealing with a file
377   if (!is_file()) return false; 
378
379   // Create the file
380   if (0 != creat(path.c_str(), S_IRUSR | S_IWUSR))
381     ThrowErrno(std::string(path.c_str()) + ": Can't create file");
382
383   return true;
384 }
385
386 bool
387 Path::destroy_directory(bool remove_contents) {
388   // Make sure we're dealing with a directory
389   if (!is_directory()) return false;
390
391   // If it doesn't exist, we're done.
392   if (!exists()) return true;
393
394   if (remove_contents) {
395     // Recursively descend the directory to remove its content
396     std::string cmd("/bin/rm -rf ");
397     cmd += path;
398     system(cmd.c_str());
399   } else {
400     // Otherwise, try to just remove the one directory
401     char pathname[MAXPATHLEN];
402     path.copy(pathname,MAXPATHLEN);
403     int lastchar = path.length() - 1 ; 
404     if (pathname[lastchar] == '/') 
405       pathname[lastchar] = 0;
406     if ( 0 != rmdir(pathname))
407       ThrowErrno(std::string(pathname) + ": Can't destroy directory");
408   }
409   return true;
410 }
411
412 bool
413 Path::destroy_file() {
414   if (!is_file()) return false;
415   if (0 != unlink(path.c_str()))
416     ThrowErrno(std::string(path.c_str()) + ": Can't destroy file");
417   return true;
418 }
419
420 }
421
422 // vim: sw=2