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