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