Path.cpp revision 22add6ff3426df1a85089fe6a6e1597ee3b6f300
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/FileSystem.h"
10#include "mcld/Support/Path.h"
11#include <llvm/ADT/StringRef.h>
12
13#include <locale>
14#include <string.h>
15#include <istream>
16#include <ostream>
17
18using namespace mcld;
19using namespace mcld::sys::fs;
20
21//===--------------------------------------------------------------------===//
22// Path
23Path::Path()
24  : m_PathName() {
25}
26
27Path::Path(const Path::ValueType* s )
28  : m_PathName(s) {
29}
30
31Path::Path(const Path::StringType &s )
32  : m_PathName(s) {
33}
34
35Path::Path(const Path& pCopy)
36 : m_PathName(pCopy.m_PathName) {
37}
38
39Path::~Path()
40{
41}
42
43bool Path::isFromRoot() const
44{
45  if (m_PathName.empty())
46    return false;
47  return (separator == m_PathName[0]);
48}
49
50bool Path::isFromPWD() const
51{
52  if (2 > m_PathName.size())
53    return false;
54  return ('.' == m_PathName[0] && separator == m_PathName[1]);
55}
56
57Path& Path::assign(const Path::StringType &s)
58{
59  m_PathName.assign(s);
60  return *this;
61}
62
63Path& Path::assign(const Path::ValueType* s, unsigned int length)
64{
65  if (0 == s || 0 == length)
66    assert(0 && "assign a null or empty string to Path");
67  m_PathName.assign(s, length);
68  return *this;
69}
70
71//a,/b a/,b a/,b/ a,b is a/b
72Path& Path::append(const Path& pPath)
73{
74  //first path is a/,second path is /b
75  if(m_PathName[m_PathName.length()-1] == separator &&
76     pPath.native()[0] == separator) {
77    unsigned int old_size = m_PathName.size()-1;
78    unsigned int new_size = old_size + pPath.native().size();
79
80    m_PathName.resize(new_size);
81    strcpy(const_cast<char*>(m_PathName.data()+old_size), pPath.native().data());
82  }
83  //first path is a,second path is b
84  else if(this->string()[this->native().size()-1] != separator &&
85          pPath.string()[0] != separator) {
86    m_PathName.append("/");
87    m_PathName.append(pPath.native());
88  }
89  // a/,b or a,/b just append
90  else {
91    m_PathName.append(pPath.native());
92  }
93  return *this;
94}
95
96bool Path::empty() const
97{
98  return m_PathName.empty();
99}
100
101std::string Path::string() const
102{
103  return m_PathName;
104}
105
106Path::StringType Path::generic_string() const
107{
108  std::string result = m_PathName;
109  detail::canonicalize(result);
110  return result;
111}
112
113bool Path::canonicalize()
114{
115  return detail::canonicalize(m_PathName);
116}
117
118Path::StringType::size_type Path::m_append_separator_if_needed()
119{
120  if (!m_PathName.empty() &&
121#if defined(MCLD_ON_WIN32)
122      *(m_PathName.end()-1) != colon &&
123#endif
124      !is_separator(*(m_PathName.end()-1))) {
125        StringType::size_type tmp(m_PathName.size());
126        m_PathName += preferred_separator;
127        return tmp;
128  }
129  return 0;
130}
131
132void Path::m_erase_redundant_separator(Path::StringType::size_type pSepPos)
133{
134  size_t begin=pSepPos;
135  // skip '/'
136  while(separator == m_PathName[pSepPos])
137    ++pSepPos;
138
139  if(begin!=pSepPos)
140    m_PathName.erase(begin+1,pSepPos-begin-1);
141}
142
143Path Path::parent_path() const
144{
145  size_t end_pos = m_PathName.find_last_of(separator);
146  if (end_pos != StringType::npos)
147    return Path(m_PathName.substr(0, end_pos));
148  return Path();
149}
150
151Path Path::filename() const
152{
153  size_t pos = m_PathName.find_last_of(separator);
154  if (pos != StringType::npos) {
155    ++pos;
156    return Path(m_PathName.substr(pos));
157  }
158  return Path(*this);
159}
160
161Path Path::stem() const
162{
163  size_t begin_pos = m_PathName.find_last_of(separator)+1;
164  size_t end_pos   = m_PathName.find_last_of(".");
165  Path result_path(m_PathName.substr(begin_pos, end_pos - begin_pos));
166  return result_path;
167}
168
169Path Path::extension() const
170{
171  size_t begin_pos = m_PathName.find_last_of('.');
172  Path result_path(m_PathName.substr(begin_pos));
173  return result_path;
174}
175
176//===--------------------------------------------------------------------===//
177// non-member functions
178//===--------------------------------------------------------------------===//
179bool mcld::sys::fs::operator==(const Path& pLHS,const Path& pRHS)
180{
181  return (pLHS.generic_string()==pRHS.generic_string());
182}
183
184bool mcld::sys::fs::operator!=(const Path& pLHS,const Path& pRHS)
185{
186  return !(pLHS==pRHS);
187}
188
189Path mcld::sys::fs::operator+(const Path& pLHS, const Path& pRHS)
190{
191  mcld::sys::fs::Path result = pLHS;
192  result.append(pRHS);
193  return result;
194}
195
196bool mcld::sys::fs::is_separator(char value)
197{
198  return (value == separator
199#if defined(MCLD_ON_WIN32)
200          || value == preferred_separator
201#endif
202          );
203}
204
205bool mcld::sys::fs::exists(const Path &pPath)
206{
207  FileStatus pFileStatus;
208  detail::status(pPath, pFileStatus);
209  return exists(pFileStatus);
210}
211
212bool mcld::sys::fs::is_directory(const Path &pPath)
213{
214  FileStatus pFileStatus;
215  detail::status(pPath, pFileStatus);
216  return is_directory(pFileStatus);
217}
218
219std::ostream &mcld::sys::fs::operator<<(std::ostream& pOS,
220                                        const Path& pPath)
221{
222  return pOS << pPath.native();
223}
224
225std::istream &mcld::sys::fs::operator>>(std::istream& pOS,
226                                        Path& pPath)
227{
228  return pOS >> pPath.native();
229}
230
231llvm::raw_ostream &mcld::sys::fs::operator<<(llvm::raw_ostream &pOS,
232                                             const Path &pPath)
233{
234  return pOS << pPath.native();
235}
236
237