1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "nacl_io/path.h"
11 #include "sdk_util/string_util.h"
17 Path::Path(const Path& path) {
21 Path::Path(const std::string& path) {
27 bool Path::IsAbsolute() const {
28 return !paths_.empty() && paths_[0] == "/";
31 const std::string& Path::Part(size_t index) const {
35 size_t Path::Size() const {
39 bool Path::Top() const {
40 return (paths_.size() == 0) || (paths_.size() == 1 && paths_[0] == "/");
43 Path& Path::Append(const std::string& path) {
44 StringArray_t paths = Split(path);
46 for (size_t index = 0; index < paths.size(); index++) {
48 if (paths_.size() && index == 0 && paths[0] == "/") continue;
49 paths_.push_back(paths[index]);
52 paths_ = Normalize(paths_);
56 Path& Path::Prepend(const std::string& path) {
57 StringArray_t paths = Split(path);
59 for (size_t index = 0; index < paths_.size(); index++) {
61 if (index == 0 && paths_[0] == "/") continue;
62 paths.push_back(paths[index]);
64 paths_ = Normalize(paths);
68 Path& Path::Set(const std::string& path) {
69 StringArray_t paths = Split(path);
70 paths_ = Normalize(paths);
74 Path Path::Parent() const {
77 if (out.paths_.size()) out.paths_.pop_back();
81 std::string Path::Basename() const {
82 if (paths_.size()) return paths_.back();
86 std::string Path::Join() const {
87 return Range(paths_, 0, paths_.size());
90 std::string Path::Range(size_t start, size_t end) const {
91 return Range(paths_, start, end);
94 StringArray_t Path::Split() const {
99 StringArray_t Path::Normalize(const StringArray_t& paths) {
100 StringArray_t path_out;
102 for (size_t index = 0; index < paths.size(); index++) {
103 const std::string &curr = paths[index];
105 // Check if '/' was used excessively in the path.
106 // For example, in cd Desktop/////
107 if (curr == "/" && index != 0) continue;
109 // Check for '.' in the path and remove it
110 if (curr == ".") continue;
114 // If the path is empty, or "..", then add ".."
115 if (path_out.empty() || path_out.back() == "..") {
116 path_out.push_back(curr);
120 // If the path is at root, "/.." = "/"
121 if (path_out.back() == "/") {
125 // if we are already at root, then stay there (root/.. -> root)
126 if (path_out.back() == "/") {
130 // otherwise, pop off the top path component
135 // By now, we should have handled end cases so just append.
136 path_out.push_back(curr);
139 // If the path was valid, but now it's empty, return self
140 if (path_out.size() == 0) path_out.push_back(".");
146 std::string Path::Join(const StringArray_t& paths) {
147 return Range(paths, 0, paths.size());
151 std::string Path::Range(const StringArray_t& paths, size_t start, size_t end) {
152 std::string out_path;
153 size_t index = start;
155 if (end > paths.size()) end = paths.size();
157 // If this is an absolute path, paths[0] == "/". In this case, we don't want
158 // to add an additional / separator.
159 if (start == 0 && end > 0 && paths[0] == "/") {
164 for (; index < end; index++) {
165 out_path += paths[index];
174 StringArray_t Path::Split(const std::string& path) {
175 StringArray_t path_split;
176 StringArray_t components;
178 sdk_util::SplitString(path, '/', &path_split);
181 components.push_back("/");
183 // Copy path_split to components, removing empty path segments.
184 for (StringArray_t::const_iterator it = path_split.begin();
185 it != path_split.end(); ++it) {
186 if (!it->empty()) components.push_back(*it);
191 Path& Path::operator =(const Path& p) {
196 Path& Path::operator =(const std::string& p) {
200 } // namespace nacl_io