| //===- Path.cpp -----------------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include "mcld/Support/Path.h" |
| |
| #include "mcld/Config/Config.h" |
| #include "mcld/Support/FileSystem.h" |
| |
| #include <llvm/ADT/StringRef.h> |
| |
| #include <istream> |
| #include <locale> |
| #include <ostream> |
| #include <string.h> |
| |
| namespace mcld { |
| namespace sys { |
| namespace fs { |
| |
| //===--------------------------------------------------------------------===// |
| // Helper |
| //===--------------------------------------------------------------------===// |
| namespace { |
| #if defined(MCLD_ON_WIN32) |
| bool is_separator(char value) { |
| return (value == separator || value == preferred_separator); |
| } |
| |
| const Path::StringType separator_str("/"); |
| |
| #else |
| bool is_separator(char value) { |
| return (value == separator); |
| } |
| |
| const Path::StringType separator_str("/"); |
| |
| #endif |
| } // anonymous namespace |
| |
| //===--------------------------------------------------------------------===// |
| // Path |
| //===--------------------------------------------------------------------===// |
| Path::Path() : m_PathName() { |
| } |
| |
| Path::Path(const Path::ValueType* s) : m_PathName(s) { |
| } |
| |
| Path::Path(const Path::StringType& s) : m_PathName(s) { |
| } |
| |
| Path::Path(const Path& pCopy) : m_PathName(pCopy.m_PathName) { |
| } |
| |
| Path::~Path() { |
| } |
| |
| bool Path::isFromRoot() const { |
| if (m_PathName.empty()) |
| return false; |
| return (separator == m_PathName[0]); |
| } |
| |
| bool Path::isFromPWD() const { |
| if (m_PathName.size() < 2) |
| return false; |
| return ('.' == m_PathName[0] && separator == m_PathName[1]); |
| } |
| |
| Path& Path::assign(const Path::StringType& s) { |
| m_PathName.assign(s); |
| return *this; |
| } |
| |
| Path& Path::assign(const Path::ValueType* s, unsigned int length) { |
| if (s == 0 || length == 0) |
| assert(0 && "assign a null or empty string to Path"); |
| m_PathName.assign(s, length); |
| return *this; |
| } |
| |
| // a,/b a/,b a/,b/ a,b is a/b |
| Path& Path::append(const Path& pPath) { |
| // first path is a/,second path is /b |
| if (m_PathName[m_PathName.length() - 1] == separator && |
| pPath.native()[0] == separator) { |
| llvm::StringRef path(pPath.native()); |
| m_PathName.append(path.begin() + 1, path.end()); |
| } else if (this->native()[this->native().size() - 1] != separator && |
| pPath.native()[0] != separator) { |
| // first path is a,second path is b |
| m_PathName.append(separator_str); |
| m_PathName.append(pPath.native()); |
| } else { |
| // a/,b or a,/b just append |
| m_PathName.append(pPath.native()); |
| } |
| return *this; |
| } |
| |
| // a,/b a/,b a/,b/ a,b is a/b |
| Path& Path::append(const StringType& pPath) { |
| Path path(pPath); |
| this->append(path); |
| return *this; |
| } |
| |
| bool Path::empty() const { |
| return m_PathName.empty(); |
| } |
| |
| Path::StringType Path::generic_string() const { |
| StringType result = m_PathName; |
| detail::canonicalize(result); |
| return result; |
| } |
| |
| bool Path::canonicalize() { |
| return detail::canonicalize(m_PathName); |
| } |
| |
| Path::StringType::size_type Path::m_append_separator_if_needed() { |
| #if defined(MCLD_ON_WIN32) |
| // On Windows platform, path can not append separator. |
| return 0; |
| #endif |
| |
| StringType::value_type last_char = m_PathName[m_PathName.size() - 1]; |
| if (!m_PathName.empty() && !is_separator(last_char)) { |
| StringType::size_type tmp(m_PathName.size()); |
| m_PathName += separator_str; |
| return tmp; |
| } |
| return 0; |
| } |
| |
| void Path::m_erase_redundant_separator(Path::StringType::size_type pSepPos) { |
| size_t begin = pSepPos; |
| // skip '/' or '\\' |
| while (separator == m_PathName[pSepPos]) { |
| #if defined(MCLD_ON_WIN32) |
| pSepPos += 2; |
| #else |
| ++pSepPos; |
| #endif |
| } |
| |
| if (begin != pSepPos) |
| m_PathName.erase(begin + 1, pSepPos - begin - 1); |
| } |
| |
| Path Path::parent_path() const { |
| size_t end_pos = m_PathName.find_last_of(separator); |
| if (end_pos != StringType::npos) |
| return Path(m_PathName.substr(0, end_pos)); |
| return Path(); |
| } |
| |
| Path Path::filename() const { |
| size_t pos = m_PathName.find_last_of(separator); |
| if (pos != StringType::npos) { |
| ++pos; |
| return Path(m_PathName.substr(pos)); |
| } |
| return Path(*this); |
| } |
| |
| Path Path::stem() const { |
| size_t begin_pos = m_PathName.find_last_of(separator) + 1; |
| size_t end_pos = m_PathName.find_last_of(dot); |
| Path result_path(m_PathName.substr(begin_pos, end_pos - begin_pos)); |
| return result_path; |
| } |
| |
| Path Path::extension() const { |
| size_t pos = m_PathName.find_last_of('.'); |
| if (pos == StringType::npos) |
| return Path(); |
| return Path(m_PathName.substr(pos)); |
| } |
| |
| //===--------------------------------------------------------------------===// |
| // non-member functions |
| //===--------------------------------------------------------------------===// |
| bool operator==(const Path& pLHS, const Path& pRHS) { |
| return (pLHS.generic_string() == pRHS.generic_string()); |
| } |
| |
| bool operator!=(const Path& pLHS, const Path& pRHS) { |
| return !(pLHS == pRHS); |
| } |
| |
| Path operator+(const Path& pLHS, const Path& pRHS) { |
| mcld::sys::fs::Path result = pLHS; |
| result.append(pRHS); |
| return result; |
| } |
| |
| } // namespace fs |
| } // namespace sys |
| } // namespace mcld |