| Index: native_client_sdk/src/libraries/nacl_io/path.cc
|
| diff --git a/native_client_sdk/src/libraries/nacl_io/path.cc b/native_client_sdk/src/libraries/nacl_io/path.cc
|
| index c524bfa35ed9b1040d433f0f17b2c6a5a9af46fe..21965607911902157416e8870a35ba24650c4e78 100644
|
| --- a/native_client_sdk/src/libraries/nacl_io/path.cc
|
| +++ b/native_client_sdk/src/libraries/nacl_io/path.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "nacl_io/path.h"
|
|
|
| +#include <assert.h>
|
| #include <stdio.h>
|
| #include <string.h>
|
| #include <string>
|
| @@ -12,8 +13,13 @@
|
|
|
| namespace nacl_io {
|
|
|
| +Path::Path() : len_(0) {
|
| + path_[0] = 0;
|
| +}
|
| +
|
| Path::Path(const Path& path) {
|
| - paths_ = path.paths_;
|
| + len_ = path.len_;
|
| + strcpy(path_, path.path_);
|
| }
|
|
|
| Path::Path(const std::string& path) {
|
| @@ -21,24 +27,54 @@ Path::Path(const std::string& path) {
|
| }
|
|
|
| bool Path::IsAbsolute() const {
|
| - return !paths_.empty() && paths_[0] == "/";
|
| + return path_[0] == '/';
|
| }
|
|
|
| -const std::string& Path::Part(size_t index) const {
|
| - return paths_[index];
|
| +std::string Path::Part(size_t index) const {
|
| + if (IsAbsolute() && index == 0) {
|
| + return std::string("/");
|
| + }
|
| +
|
| + const char* start = &path_[0];
|
| + size_t slashes = 0;
|
| + const char* p;
|
| + for (p = &path_[0]; *p; p++) {
|
| + if (*p == '/') {
|
| + if (++slashes == index + 1)
|
| + break;
|
| +
|
| + start = p + 1;
|
| + }
|
| + }
|
| +
|
| + return std::string(start, p - start);
|
| }
|
|
|
| size_t Path::Size() const {
|
| - return paths_.size();
|
| + if (len_ == 0)
|
| + return 0;
|
| +
|
| + const char* p = &path_[0];
|
| + if (len_ == 1 && *p == '/') {
|
| + return 1;
|
| + }
|
| +
|
| + size_t count = 1;
|
| + for (; *p; p++) {
|
| + if (*p == '/')
|
| + count++;
|
| + }
|
| + return count;
|
| }
|
|
|
| bool Path::IsRoot() const {
|
| - return paths_.empty() || (paths_.size() == 1 && paths_[0] == "/");
|
| + return strcmp(path_, "/") == 0;
|
| }
|
|
|
| Path& Path::MakeRelative() {
|
| if (IsAbsolute()) {
|
| - paths_.erase(paths_.begin());
|
| + memmove(&path_[0], &path_[1], PATH_MAX - 1);
|
| + len_--;
|
| }
|
| return *this;
|
| }
|
| @@ -47,14 +83,19 @@ Path& Path::Append(const Path& path) {
|
| // Appending an absolute path effectivly sets the path, ignoring
|
| // the current contents.
|
| if (path.IsAbsolute()) {
|
| - paths_ = path.paths_;
|
| + strcpy(path_, path.path_);
|
| } else {
|
| - for (size_t index = 0; index < path.paths_.size(); index++) {
|
| - paths_.push_back(path.paths_[index]);
|
| + strncat(path_, "/", PATH_MAX - len_ - 1);
|
| + len_++;
|
| + strncat(path_, path.path_, PATH_MAX - len_ - 1);
|
| + len_ += path.len_;
|
| +
|
| + if (len_ >= PATH_MAX - 1) {
|
| + len_ = PATH_MAX - 1;
|
| }
|
| }
|
|
|
| - paths_ = Normalize(paths_);
|
| + Normalize();
|
| return *this;
|
| }
|
|
|
| @@ -62,142 +103,157 @@ Path& Path::Append(const std::string& path) {
|
| return Append(Path(path));
|
| }
|
|
|
| -Path& Path::Set(const StringArray_t path) {
|
| - paths_ = Normalize(path);
|
| - return *this;
|
| -}
|
| -
|
| Path& Path::Set(const std::string& path) {
|
| - return Set(Split(path));
|
| + strncpy(path_, path.c_str(), PATH_MAX - 1);
|
| + path_[PATH_MAX - 1] = 0;
|
| + len_ = path.length();
|
| + if (len_ > PATH_MAX - 1)
|
| + len_ = PATH_MAX - 1;
|
| + Normalize();
|
| + return *this;
|
| }
|
|
|
| Path Path::Parent() const {
|
| - Path out;
|
| - out.paths_ = paths_;
|
| - if (out.paths_.size())
|
| - out.paths_.pop_back();
|
| - return out;
|
| + const char* last_slash = strrchr(path_, '/');
|
| + if (last_slash) {
|
| + Path out;
|
| + if (last_slash == &path_[0]) {
|
| + out.len_ = 1;
|
| + strcpy(out.path_, "/");
|
| + } else {
|
| + out.len_ = last_slash - &path_[0];
|
| + strncpy(out.path_, path_, out.len_);
|
| + out.path_[out.len_] = 0;
|
| + }
|
| +
|
| + return out;
|
| + }
|
| +
|
| + return Path(*this);
|
| }
|
|
|
| std::string Path::Basename() const {
|
| - if (paths_.size())
|
| - return paths_.back();
|
| - return std::string();
|
| -}
|
| + if (IsRoot())
|
| + return std::string(path_);
|
|
|
| -std::string Path::Join() const {
|
| - return Range(paths_, 0, paths_.size());
|
| -}
|
| + const char* last_slash = strrchr(path_, '/');
|
| + if (last_slash)
|
| + return std::string(last_slash + 1, path_ + len_ - (last_slash + 1));
|
|
|
| -std::string Path::Range(size_t start, size_t end) const {
|
| - return Range(paths_, start, end);
|
| + return std::string(path_);
|
| }
|
|
|
| -StringArray_t Path::Split() const {
|
| - return paths_;
|
| +std::string Path::Join() const {
|
| + return std::string(path_);
|
| }
|
|
|
| -// 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;
|
| +std::string Path::Range(size_t start, size_t end) const {
|
| + assert(start <= end);
|
|
|
| - // Check for '.' in the path and remove it
|
| - if (curr == ".")
|
| - continue;
|
| + const char* pstart = &path_[0];
|
| + const char* pend = &path_[len_];
|
|
|
| - // 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 (IsAbsolute() && start == 0 && end == 1)
|
| + return std::string("/");
|
|
|
| - // If the path is at root, "/.." = "/"
|
| - if (path_out.back() == "/") {
|
| - continue;
|
| - }
|
| + size_t slashes = 0;
|
| + for (const char* p = &path_[0]; *p; p++) {
|
| + if (*p == '/') {
|
| + ++slashes;
|
| + if (slashes == start)
|
| + pstart = p + 1;
|
|
|
| - // if we are already at root, then stay there (root/.. -> root)
|
| - if (path_out.back() == "/") {
|
| - continue;
|
| + if (slashes == end) {
|
| + pend = p;
|
| + break;
|
| }
|
| -
|
| - // 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.empty())
|
| - path_out.push_back(".");
|
| -
|
| - return path_out;
|
| -}
|
| + if (pstart > pend)
|
| + return std::string();
|
|
|
| -// static
|
| -std::string Path::Join(const StringArray_t& paths) {
|
| - return Range(paths, 0, paths.size());
|
| + return std::string(pstart, pend - pstart);
|
| }
|
|
|
| -// 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();
|
| +void Path::Normalize() {
|
| + char* outp = &path_[0];
|
| + const char* start = outp;
|
| + const char* part_start = start;
|
| + const char* next_slash;
|
| + bool is_absolute = false;
|
|
|
| - // 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++;
|
| + if (IsAbsolute()) {
|
| + // Absolute path. Append the slash, then continue the algorithm as if the
|
| + // path were relative.
|
| + start++;
|
| + outp++;
|
| + part_start++;
|
| + is_absolute = true;
|
| }
|
|
|
| - for (; index < end; index++) {
|
| - out_path += paths[index];
|
| - if (index < end - 1)
|
| - out_path += "/";
|
| - }
|
| + do {
|
| + next_slash = strchr(part_start, '/');
|
| + const char* part_end = next_slash;
|
| + if (!part_end)
|
| + part_end = part_start + strlen(part_start);
|
| +
|
| + size_t part_len = part_end - part_start;
|
| +
|
| + bool should_append = true;
|
| + if (part_len == 0) {
|
| + // Don't append if the part is empty.
|
| + should_append = false;
|
| + } else if (part_len == 1 && part_start[0] == '.') {
|
| + // Don't append "."
|
| + should_append = false;
|
| + } else if (part_len == 2 && part_start[0] == '.' && part_start[1] == '.') {
|
| + // If part is "..", only append if the output is empty or already has
|
| + // ".." at the end.
|
| + if (outp == start ||
|
| + (outp - start >= 2 && outp[-1] == '.' && outp[-2] == '.')) {
|
| + should_append = !is_absolute;
|
| + } else {
|
| + should_append = false;
|
| + // Move outp backward to the one past the previous slash, or to the
|
| + // beginning of the string. Unless outp == start, outp[-1] is a '/'.
|
| + if (outp > start)
|
| + --outp;
|
| + while (outp > start && outp[0] != '/')
|
| + --outp;
|
| + }
|
| + }
|
|
|
| - return out_path;
|
| -}
|
| + if (should_append) {
|
| + // Append [part_start, part_end) to outp.
|
| + if (outp != start) {
|
| + // Append slash to separate from previous path.
|
| + *outp++ = '/';
|
| + }
|
|
|
| -// static
|
| -StringArray_t Path::Split(const std::string& path) {
|
| - StringArray_t path_split;
|
| - StringArray_t components;
|
| + // Only need to copy bytes when the pointers are different.
|
| + if (outp != part_start) {
|
| + memmove(outp, part_start, part_len);
|
| + }
|
|
|
| - sdk_util::SplitString(path, '/', &path_split);
|
| + outp += part_len;
|
| + }
|
|
|
| - if (path[0] == '/')
|
| - components.push_back("/");
|
| + part_start = next_slash + 1;
|
| + } while (next_slash);
|
|
|
| - // Copy path_split to components, removing empty path segments.
|
| - for (StringArray_t::const_iterator it = path_split.begin();
|
| - it != path_split.end();
|
| - ++it) {
|
| - if (!it->empty())
|
| - components.push_back(*it);
|
| + // Return '.' instead of an empty path.
|
| + if (outp == start && !is_absolute) {
|
| + *outp++ = '.';
|
| }
|
| - return components;
|
| +
|
| + *outp = 0;
|
| + len_ = outp - &path_[0];
|
| }
|
|
|
| Path& Path::operator=(const Path& p) {
|
| - paths_ = p.paths_;
|
| + len_ = p.len_;
|
| + strcpy(path_, p.path_);
|
| return *this;
|
| }
|
|
|
| @@ -205,4 +261,12 @@ Path& Path::operator=(const std::string& p) {
|
| return Set(p);
|
| }
|
|
|
| +bool Path::operator==(const Path& other) {
|
| + return len_ == other.len_ && strncmp(path_, other.path_, len_) == 0;
|
| +}
|
| +
|
| +bool Path::operator!=(const Path& other) {
|
| + return !operator==(other);
|
| +}
|
| +
|
| } // namespace nacl_io
|
|
|