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 21namespace mcld { 22namespace sys { 23namespace fs { 24 25//===--------------------------------------------------------------------===// 26// Helper 27//===--------------------------------------------------------------------===// 28namespace { 29#if defined(MCLD_ON_WIN32) 30bool is_separator(char value) { 31 return (value == separator || value == preferred_separator); 32} 33 34const Path::StringType separator_str("/"); 35 36#else 37bool is_separator(char value) { 38 return (value == separator); 39} 40 41const Path::StringType separator_str("/"); 42 43#endif 44} // anonymous namespace 45 46//===--------------------------------------------------------------------===// 47// Path 48//===--------------------------------------------------------------------===// 49Path::Path() : m_PathName() { 50} 51 52Path::Path(const Path::ValueType* s) : m_PathName(s) { 53} 54 55Path::Path(const Path::StringType& s) : m_PathName(s) { 56} 57 58Path::Path(const Path& pCopy) : m_PathName(pCopy.m_PathName) { 59} 60 61Path::~Path() { 62} 63 64bool Path::isFromRoot() const { 65 if (m_PathName.empty()) 66 return false; 67 return (separator == m_PathName[0]); 68} 69 70bool Path::isFromPWD() const { 71 if (m_PathName.size() < 2) 72 return false; 73 return ('.' == m_PathName[0] && separator == m_PathName[1]); 74} 75 76Path& Path::assign(const Path::StringType& s) { 77 m_PathName.assign(s); 78 return *this; 79} 80 81Path& 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 89Path& 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 108Path& Path::append(const StringType& pPath) { 109 Path path(pPath); 110 this->append(path); 111 return *this; 112} 113 114bool Path::empty() const { 115 return m_PathName.empty(); 116} 117 118Path::StringType Path::generic_string() const { 119 StringType result = m_PathName; 120 detail::canonicalize(result); 121 return result; 122} 123 124bool Path::canonicalize() { 125 return detail::canonicalize(m_PathName); 126} 127 128Path::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 143void 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 158Path 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 165Path 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 174Path 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 181Path 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//===--------------------------------------------------------------------===// 191bool operator==(const Path& pLHS, const Path& pRHS) { 192 return (pLHS.generic_string() == pRHS.generic_string()); 193} 194 195bool operator!=(const Path& pLHS, const Path& pRHS) { 196 return !(pLHS == pRHS); 197} 198 199Path 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