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 19using namespace mcld; 20using namespace mcld::sys::fs; 21 22//===--------------------------------------------------------------------===// 23// Helper 24//===--------------------------------------------------------------------===// 25namespace { 26#if defined(MCLD_ON_WIN32) 27bool is_separator(char value) 28{ 29 return (value == separator || value == preferred_separator); 30} 31 32const Path::StringType separator_str("/"); 33 34#else 35bool is_separator(char value) 36{ 37 return (value == separator); 38} 39 40const Path::StringType separator_str("/"); 41 42#endif 43} // anonymous namespace 44 45 46//===--------------------------------------------------------------------===// 47// Path 48//===--------------------------------------------------------------------===// 49Path::Path() 50 : m_PathName() { 51} 52 53Path::Path(const Path::ValueType* s ) 54 : m_PathName(s) { 55} 56 57Path::Path(const Path::StringType &s ) 58 : m_PathName(s) { 59} 60 61Path::Path(const Path& pCopy) 62 : m_PathName(pCopy.m_PathName) { 63} 64 65Path::~Path() 66{ 67} 68 69bool Path::isFromRoot() const 70{ 71 if (m_PathName.empty()) 72 return false; 73 return (separator == m_PathName[0]); 74} 75 76bool Path::isFromPWD() const 77{ 78 if (2 > m_PathName.size()) 79 return false; 80 return ('.' == m_PathName[0] && separator == m_PathName[1]); 81} 82 83Path& Path::assign(const Path::StringType &s) 84{ 85 m_PathName.assign(s); 86 return *this; 87} 88 89Path& 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 98Path& 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 122bool Path::empty() const 123{ 124 return m_PathName.empty(); 125} 126 127Path::StringType Path::generic_string() const 128{ 129 StringType result = m_PathName; 130 detail::canonicalize(result); 131 return result; 132} 133 134bool Path::canonicalize() 135{ 136 return detail::canonicalize(m_PathName); 137} 138 139Path::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 156void 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 172Path 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 180Path 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 190Path 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 198Path Path::extension() const 199{ 200 size_t begin_pos = m_PathName.find_last_of('.'); 201 Path result_path(m_PathName.substr(begin_pos)); 202 return result_path; 203} 204 205//===--------------------------------------------------------------------===// 206// non-member functions 207//===--------------------------------------------------------------------===// 208bool mcld::sys::fs::operator==(const Path& pLHS,const Path& pRHS) 209{ 210 return (pLHS.generic_string()==pRHS.generic_string()); 211} 212 213bool mcld::sys::fs::operator!=(const Path& pLHS,const Path& pRHS) 214{ 215 return !(pLHS==pRHS); 216} 217 218Path mcld::sys::fs::operator+(const Path& pLHS, const Path& pRHS) 219{ 220 mcld::sys::fs::Path result = pLHS; 221 result.append(pRHS); 222 return result; 223} 224 225