blob: 78c0769eed9142e5fe217aeb9342e1bf304274a9 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "nacl_io/path.h"
#include <stdio.h>
#include <string.h>
#include <string>
namespace nacl_io {
Path::Path() {}
Path::Path(const Path& path) {
paths_ = path.paths_;
}
Path::Path(const std::string& path) {
Set(path);
}
Path::~Path() {}
bool Path::IsAbsolute() const {
return !paths_.empty() && paths_[0] == "/";
}
const std::string& Path::Part(size_t index) const {
return paths_[index];
}
size_t Path::Size() const {
return paths_.size();
}
bool Path::Top() const {
return (paths_.size() == 0) || (paths_.size() == 1 && paths_[0] == "/");
}
Path& Path::Append(const std::string& path) {
StringArray_t paths = Split(path);
for (size_t index = 0; index < paths.size(); index++) {
// Skip ROOT
if (paths_.size() && index == 0 && paths[0] == "/") continue;
paths_.push_back(paths[index]);
}
paths_ = Normalize(paths_);
return *this;
}
Path& Path::Prepend(const std::string& path) {
StringArray_t paths = Split(path);
for (size_t index = 0; index < paths_.size(); index++) {
// Skip ROOT
if (index == 0 && paths_[0] == "/") continue;
paths.push_back(paths[index]);
}
paths_ = Normalize(paths);
return *this;
}
Path& Path::Set(const std::string& path) {
StringArray_t paths = Split(path);
paths_ = Normalize(paths);
return *this;
}
Path Path::Parent() const {
Path out;
out.paths_ = paths_;
if (out.paths_.size()) out.paths_.pop_back();
return out;
}
std::string Path::Basename() const {
if (paths_.size()) return paths_.back();
return std::string();
}
std::string Path::Join() const {
return Range(paths_, 0, paths_.size());
}
std::string Path::Range(size_t start, size_t end) const {
return Range(paths_, start, end);
}
StringArray_t Path::Split() const {
return paths_;
}
// static
StringArray_t Path::Normalize(const StringArray_t& paths) {
StringArray_t path_out;
for (size_t index = 0; index < paths.size(); index++) {
const std::string &curr = paths[index];
// Check if '/' was used excessively in the path.
// For example, in cd Desktop/////
if (curr == "/" && index != 0) continue;
// Check for '.' in the path and remove it
if (curr == ".") continue;
// Check for '..'
if (curr == "..") {
// If the path is empty, or "..", then add ".."
if (path_out.empty() || path_out.back() == "..") {
path_out.push_back(curr);
continue;
}
// If the path is at root, "/.." = "/"
if (path_out.back() == "/") {
continue;
}
// if we are already at root, then stay there (root/.. -> root)
if (path_out.back() == "/") {
continue;
}
// otherwise, pop off the top path component
path_out.pop_back();
continue;
}
// By now, we should have handled end cases so just append.
path_out.push_back(curr);
}
// If the path was valid, but now it's empty, return self
if (path_out.size() == 0) path_out.push_back(".");
return path_out;
}
// static
std::string Path::Join(const StringArray_t& paths) {
return Range(paths, 0, paths.size());
}
// static
std::string Path::Range(const StringArray_t& paths, size_t start, size_t end) {
std::string out_path;
size_t index = start;
if (end > paths.size()) end = paths.size();
// If this is an absolute path, paths[0] == "/". In this case, we don't want
// to add an additional / separator.
if (start == 0 && end > 0 && paths[0] == "/") {
out_path += "/";
index++;
}
for (; index < end; index++) {
out_path += paths[index];
if (index < end - 1)
out_path += "/";
}
return out_path;
}
// static
StringArray_t Path::Split(const std::string& path) {
StringArray_t components;
size_t offs = 0;
size_t next = 0;
if (path[0] == '/') {
offs = 1;
components.push_back("/");
}
while (next != std::string::npos) {
next = path.find('/', offs);
// Remove extra separators
if (next == offs) {
++offs;
continue;
}
std::string part = path.substr(offs, next - offs);
if (!part.empty()) components.push_back(part);
offs = next + 1;
}
return components;
}
Path& Path::operator =(const Path& p) {
paths_ = p.paths_;
return *this;
}
Path& Path::operator =(const std::string& p) {
return Set(p);
}
} // namespace nacl_io