Home | History | Annotate | Download | only in Support
      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