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