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)
is_separator(char value)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 //===--------------------------------------------------------------------===//
Path()49 Path::Path() : m_PathName() {
50 }
51 
Path(const Path::ValueType * s)52 Path::Path(const Path::ValueType* s) : m_PathName(s) {
53 }
54 
Path(const Path::StringType & s)55 Path::Path(const Path::StringType& s) : m_PathName(s) {
56 }
57 
Path(const Path & pCopy)58 Path::Path(const Path& pCopy) : m_PathName(pCopy.m_PathName) {
59 }
60 
~Path()61 Path::~Path() {
62 }
63 
isFromRoot() const64 bool Path::isFromRoot() const {
65   if (m_PathName.empty())
66     return false;
67   return (separator == m_PathName[0]);
68 }
69 
isFromPWD() const70 bool Path::isFromPWD() const {
71   if (m_PathName.size() < 2)
72     return false;
73   return ('.' == m_PathName[0] && separator == m_PathName[1]);
74 }
75 
assign(const Path::StringType & s)76 Path& Path::assign(const Path::StringType& s) {
77   m_PathName.assign(s);
78   return *this;
79 }
80 
assign(const Path::ValueType * s,unsigned int length)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
append(const Path & pPath)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
append(const StringType & pPath)108 Path& Path::append(const StringType& pPath) {
109   Path path(pPath);
110   this->append(path);
111   return *this;
112 }
113 
empty() const114 bool Path::empty() const {
115   return m_PathName.empty();
116 }
117 
generic_string() const118 Path::StringType Path::generic_string() const {
119   StringType result = m_PathName;
120   detail::canonicalize(result);
121   return result;
122 }
123 
canonicalize()124 bool Path::canonicalize() {
125   return detail::canonicalize(m_PathName);
126 }
127 
m_append_separator_if_needed()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 
m_erase_redundant_separator(Path::StringType::size_type pSepPos)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 
parent_path() const158 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 
filename() const165 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 
stem() const174 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 
extension() const181 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 //===--------------------------------------------------------------------===//
operator ==(const Path & pLHS,const Path & pRHS)191 bool operator==(const Path& pLHS, const Path& pRHS) {
192   return (pLHS.generic_string() == pRHS.generic_string());
193 }
194 
operator !=(const Path & pLHS,const Path & pRHS)195 bool operator!=(const Path& pLHS, const Path& pRHS) {
196   return !(pLHS == pRHS);
197 }
198 
operator +(const Path & pLHS,const Path & pRHS)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