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 // Helper 24 //===--------------------------------------------------------------------===// 25 namespace { 26 #if defined(MCLD_ON_WIN32) 27 bool is_separator(char value) 28 { 29 return (value == separator || value == preferred_separator); 30 } 31 32 const Path::StringType separator_str("/"); 33 34 #else 35 bool is_separator(char value) 36 { 37 return (value == separator); 38 } 39 40 const Path::StringType separator_str("/"); 41 42 #endif 43 } // anonymous namespace 44 45 46 //===--------------------------------------------------------------------===// 47 // Path 48 //===--------------------------------------------------------------------===// 49 Path::Path() 50 : m_PathName() { 51 } 52 53 Path::Path(const Path::ValueType* s ) 54 : m_PathName(s) { 55 } 56 57 Path::Path(const Path::StringType &s ) 58 : m_PathName(s) { 59 } 60 61 Path::Path(const Path& pCopy) 62 : m_PathName(pCopy.m_PathName) { 63 } 64 65 Path::~Path() 66 { 67 } 68 69 bool Path::isFromRoot() const 70 { 71 if (m_PathName.empty()) 72 return false; 73 return (separator == m_PathName[0]); 74 } 75 76 bool Path::isFromPWD() const 77 { 78 if (2 > m_PathName.size()) 79 return false; 80 return ('.' == m_PathName[0] && separator == m_PathName[1]); 81 } 82 83 Path& Path::assign(const Path::StringType &s) 84 { 85 m_PathName.assign(s); 86 return *this; 87 } 88 89 Path& Path::assign(const Path::ValueType* s, unsigned int length) 90 { 91 if (0 == s || 0 == length) 92 assert(0 && "assign a null or empty string to Path"); 93 m_PathName.assign(s, length); 94 return *this; 95 } 96 97 //a,/b a/,b a/,b/ a,b is a/b 98 Path& Path::append(const Path& pPath) 99 { 100 //first path is a/,second path is /b 101 if(m_PathName[m_PathName.length()-1] == separator && 102 pPath.native()[0] == separator) { 103 unsigned int old_size = m_PathName.size()-1; 104 unsigned int new_size = old_size + pPath.native().size(); 105 106 m_PathName.resize(new_size); 107 strcpy(const_cast<ValueType*>(m_PathName.data()+old_size), pPath.native().data()); 108 } 109 //first path is a,second path is b 110 else if(this->native()[this->native().size()-1] != separator && 111 pPath.native()[0] != separator) { 112 m_PathName.append(separator_str); 113 m_PathName.append(pPath.native()); 114 } 115 // a/,b or a,/b just append 116 else { 117 m_PathName.append(pPath.native()); 118 } 119 return *this; 120 } 121 122 bool Path::empty() const 123 { 124 return m_PathName.empty(); 125 } 126 127 Path::StringType Path::generic_string() const 128 { 129 StringType result = m_PathName; 130 detail::canonicalize(result); 131 return result; 132 } 133 134 bool Path::canonicalize() 135 { 136 return detail::canonicalize(m_PathName); 137 } 138 139 Path::StringType::size_type Path::m_append_separator_if_needed() 140 { 141 #if defined(MCLD_ON_WIN32) 142 // On Windows platform, path can not append separator. 143 return 0; 144 #endif 145 146 StringType::value_type last_char = m_PathName[m_PathName.size() - 1]; 147 if (!m_PathName.empty() && 148 !is_separator(last_char)) { 149 StringType::size_type tmp(m_PathName.size()); 150 m_PathName += separator_str; 151 return tmp; 152 } 153 return 0; 154 } 155 156 void Path::m_erase_redundant_separator(Path::StringType::size_type pSepPos) 157 { 158 size_t begin=pSepPos; 159 // skip '/' or '\\' 160 while(separator == m_PathName[pSepPos]) { 161 #if defined(MCLD_ON_WIN32) 162 pSepPos += 2; 163 #else 164 ++pSepPos; 165 #endif 166 } 167 168 if(begin!=pSepPos) 169 m_PathName.erase(begin+1,pSepPos-begin-1); 170 } 171 172 Path Path::parent_path() const 173 { 174 size_t end_pos = m_PathName.find_last_of(separator); 175 if (end_pos != StringType::npos) 176 return Path(m_PathName.substr(0, end_pos)); 177 return Path(); 178 } 179 180 Path Path::filename() const 181 { 182 size_t pos = m_PathName.find_last_of(separator); 183 if (pos != StringType::npos) { 184 ++pos; 185 return Path(m_PathName.substr(pos)); 186 } 187 return Path(*this); 188 } 189 190 Path Path::stem() const 191 { 192 size_t begin_pos = m_PathName.find_last_of(separator)+1; 193 size_t end_pos = m_PathName.find_last_of(dot); 194 Path result_path(m_PathName.substr(begin_pos, end_pos - begin_pos)); 195 return result_path; 196 } 197 198 Path Path::extension() const 199 { 200 size_t pos = m_PathName.find_last_of('.'); 201 if (pos == StringType::npos) 202 return Path(); 203 return Path(m_PathName.substr(pos)); 204 } 205 206 //===--------------------------------------------------------------------===// 207 // non-member functions 208 //===--------------------------------------------------------------------===// 209 bool mcld::sys::fs::operator==(const Path& pLHS,const Path& pRHS) 210 { 211 return (pLHS.generic_string()==pRHS.generic_string()); 212 } 213 214 bool mcld::sys::fs::operator!=(const Path& pLHS,const Path& pRHS) 215 { 216 return !(pLHS==pRHS); 217 } 218 219 Path mcld::sys::fs::operator+(const Path& pLHS, const Path& pRHS) 220 { 221 mcld::sys::fs::Path result = pLHS; 222 result.append(pRHS); 223 return result; 224 } 225 226