1 //===- Path.cpp -----------------------------------------------------------===// 2 // 3 // The MCLinker Project 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 #include "mcld/Config/Config.h" 10 #include "mcld/Support/FileSystem.h" 11 #include "mcld/Support/Path.h" 12 #include <llvm/ADT/StringRef.h> 13 14 #include <locale> 15 #include <string.h> 16 #include <istream> 17 #include <ostream> 18 19 using namespace mcld; 20 using namespace mcld::sys::fs; 21 22 //===--------------------------------------------------------------------===// 23 // Path 24 Path::Path() 25 : m_PathName() { 26 } 27 28 Path::Path(const Path::ValueType* s ) 29 : m_PathName(s) { 30 } 31 32 Path::Path(const Path::StringType &s ) 33 : m_PathName(s) { 34 } 35 36 Path::Path(const Path& pCopy) 37 : m_PathName(pCopy.m_PathName) { 38 } 39 40 Path::~Path() 41 { 42 } 43 44 bool Path::isFromRoot() const 45 { 46 if (m_PathName.empty()) 47 return false; 48 return (separator == m_PathName[0]); 49 } 50 51 bool Path::isFromPWD() const 52 { 53 if (2 > m_PathName.size()) 54 return false; 55 return ('.' == m_PathName[0] && separator == m_PathName[1]); 56 } 57 58 Path& Path::assign(const Path::StringType &s) 59 { 60 m_PathName.assign(s); 61 return *this; 62 } 63 64 Path& Path::assign(const Path::ValueType* s, unsigned int length) 65 { 66 if (0 == s || 0 == length) 67 assert(0 && "assign a null or empty string to Path"); 68 m_PathName.assign(s, length); 69 return *this; 70 } 71 72 //a,/b a/,b a/,b/ a,b is a/b 73 Path& Path::append(const Path& pPath) 74 { 75 //first path is a/,second path is /b 76 if(m_PathName[m_PathName.length()-1] == separator && 77 pPath.native()[0] == separator) { 78 unsigned int old_size = m_PathName.size()-1; 79 unsigned int new_size = old_size + pPath.native().size(); 80 81 m_PathName.resize(new_size); 82 strcpy(const_cast<char*>(m_PathName.data()+old_size), pPath.native().data()); 83 } 84 //first path is a,second path is b 85 else if(this->string()[this->native().size()-1] != separator && 86 pPath.string()[0] != separator) { 87 m_PathName.append("/"); 88 m_PathName.append(pPath.native()); 89 } 90 // a/,b or a,/b just append 91 else { 92 m_PathName.append(pPath.native()); 93 } 94 return *this; 95 } 96 97 bool Path::empty() const 98 { 99 return m_PathName.empty(); 100 } 101 102 std::string Path::string() const 103 { 104 return m_PathName; 105 } 106 107 Path::StringType Path::generic_string() const 108 { 109 std::string result = m_PathName; 110 detail::canonicalize(result); 111 return result; 112 } 113 114 bool Path::canonicalize() 115 { 116 return detail::canonicalize(m_PathName); 117 } 118 119 Path::StringType::size_type Path::m_append_separator_if_needed() 120 { 121 if (!m_PathName.empty() && 122 #if defined(MCLD_ON_WIN32) 123 *(m_PathName.end()-1) != colon && 124 #endif 125 !is_separator(*(m_PathName.end()-1))) { 126 StringType::size_type tmp(m_PathName.size()); 127 m_PathName += preferred_separator; 128 return tmp; 129 } 130 return 0; 131 } 132 133 void Path::m_erase_redundant_separator(Path::StringType::size_type pSepPos) 134 { 135 size_t begin=pSepPos; 136 // skip '/' 137 while(separator == m_PathName[pSepPos]) 138 ++pSepPos; 139 140 if(begin!=pSepPos) 141 m_PathName.erase(begin+1,pSepPos-begin-1); 142 } 143 144 Path Path::parent_path() const 145 { 146 size_t end_pos = m_PathName.find_last_of(separator); 147 if (end_pos != StringType::npos) 148 return Path(m_PathName.substr(0, end_pos)); 149 return Path(); 150 } 151 152 Path Path::filename() const 153 { 154 size_t pos = m_PathName.find_last_of(separator); 155 if (pos != StringType::npos) { 156 ++pos; 157 return Path(m_PathName.substr(pos)); 158 } 159 return Path(*this); 160 } 161 162 Path Path::stem() const 163 { 164 size_t begin_pos = m_PathName.find_last_of(separator)+1; 165 size_t end_pos = m_PathName.find_last_of("."); 166 Path result_path(m_PathName.substr(begin_pos, end_pos - begin_pos)); 167 return result_path; 168 } 169 170 Path Path::extension() const 171 { 172 size_t begin_pos = m_PathName.find_last_of('.'); 173 Path result_path(m_PathName.substr(begin_pos)); 174 return result_path; 175 } 176 177 //===--------------------------------------------------------------------===// 178 // non-member functions 179 //===--------------------------------------------------------------------===// 180 bool mcld::sys::fs::operator==(const Path& pLHS,const Path& pRHS) 181 { 182 return (pLHS.generic_string()==pRHS.generic_string()); 183 } 184 185 bool mcld::sys::fs::operator!=(const Path& pLHS,const Path& pRHS) 186 { 187 return !(pLHS==pRHS); 188 } 189 190 Path mcld::sys::fs::operator+(const Path& pLHS, const Path& pRHS) 191 { 192 mcld::sys::fs::Path result = pLHS; 193 result.append(pRHS); 194 return result; 195 } 196 197 bool mcld::sys::fs::is_separator(char value) 198 { 199 return (value == separator 200 #if defined(MCLD_ON_WIN32) 201 || value == preferred_separator 202 #endif 203 ); 204 } 205 206 bool mcld::sys::fs::exists(const Path &pPath) 207 { 208 FileStatus pFileStatus; 209 detail::status(pPath, pFileStatus); 210 return exists(pFileStatus); 211 } 212 213 bool mcld::sys::fs::is_directory(const Path &pPath) 214 { 215 FileStatus pFileStatus; 216 detail::status(pPath, pFileStatus); 217 return is_directory(pFileStatus); 218 } 219 220 std::ostream &mcld::sys::fs::operator<<(std::ostream& pOS, 221 const Path& pPath) 222 { 223 return pOS << pPath.native(); 224 } 225 226 std::istream &mcld::sys::fs::operator>>(std::istream& pOS, 227 Path& pPath) 228 { 229 return pOS >> pPath.native(); 230 } 231 232 llvm::raw_ostream &mcld::sys::fs::operator<<(llvm::raw_ostream &pOS, 233 const Path &pPath) 234 { 235 return pOS << pPath.native(); 236 } 237 238