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