path.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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. 4 5#include "nacl_io/path.h" 6 7#include <stdio.h> 8#include <string.h> 9#include <string> 10 11#include "sdk_util/string_util.h" 12 13namespace nacl_io { 14 15Path::Path() {} 16 17Path::Path(const Path& path) { 18 paths_ = path.paths_; 19} 20 21Path::Path(const std::string& path) { 22 Set(path); 23} 24 25Path::~Path() {} 26 27bool Path::IsAbsolute() const { 28 return !paths_.empty() && paths_[0] == "/"; 29} 30 31const std::string& Path::Part(size_t index) const { 32 return paths_[index]; 33} 34 35size_t Path::Size() const { 36 return paths_.size(); 37} 38 39bool Path::Top() const { 40 return (paths_.size() == 0) || (paths_.size() == 1 && paths_[0] == "/"); 41} 42 43Path& Path::Append(const std::string& path) { 44 StringArray_t paths = Split(path); 45 46 for (size_t index = 0; index < paths.size(); index++) { 47 // Skip ROOT 48 if (paths_.size() && index == 0 && paths[0] == "/") continue; 49 paths_.push_back(paths[index]); 50 } 51 52 paths_ = Normalize(paths_); 53 return *this; 54} 55 56Path& Path::Prepend(const std::string& path) { 57 StringArray_t paths = Split(path); 58 59 for (size_t index = 0; index < paths_.size(); index++) { 60 // Skip ROOT 61 if (index == 0 && paths_[0] == "/") continue; 62 paths.push_back(paths[index]); 63 } 64 paths_ = Normalize(paths); 65 return *this; 66} 67 68Path& Path::Set(const std::string& path) { 69 StringArray_t paths = Split(path); 70 paths_ = Normalize(paths); 71 return *this; 72} 73 74Path Path::Parent() const { 75 Path out; 76 out.paths_ = paths_; 77 if (out.paths_.size()) out.paths_.pop_back(); 78 return out; 79} 80 81std::string Path::Basename() const { 82 if (paths_.size()) return paths_.back(); 83 return std::string(); 84} 85 86std::string Path::Join() const { 87 return Range(paths_, 0, paths_.size()); 88} 89 90std::string Path::Range(size_t start, size_t end) const { 91 return Range(paths_, start, end); 92} 93 94StringArray_t Path::Split() const { 95 return paths_; 96} 97 98// static 99StringArray_t Path::Normalize(const StringArray_t& paths) { 100 StringArray_t path_out; 101 102 for (size_t index = 0; index < paths.size(); index++) { 103 const std::string &curr = paths[index]; 104 105 // Check if '/' was used excessively in the path. 106 // For example, in cd Desktop///// 107 if (curr == "/" && index != 0) continue; 108 109 // Check for '.' in the path and remove it 110 if (curr == ".") continue; 111 112 // Check for '..' 113 if (curr == "..") { 114 // If the path is empty, or "..", then add ".." 115 if (path_out.empty() || path_out.back() == "..") { 116 path_out.push_back(curr); 117 continue; 118 } 119 120 // If the path is at root, "/.." = "/" 121 if (path_out.back() == "/") { 122 continue; 123 } 124 125 // if we are already at root, then stay there (root/.. -> root) 126 if (path_out.back() == "/") { 127 continue; 128 } 129 130 // otherwise, pop off the top path component 131 path_out.pop_back(); 132 continue; 133 } 134 135 // By now, we should have handled end cases so just append. 136 path_out.push_back(curr); 137 } 138 139 // If the path was valid, but now it's empty, return self 140 if (path_out.size() == 0) path_out.push_back("."); 141 142 return path_out; 143} 144 145// static 146std::string Path::Join(const StringArray_t& paths) { 147 return Range(paths, 0, paths.size()); 148} 149 150// static 151std::string Path::Range(const StringArray_t& paths, size_t start, size_t end) { 152 std::string out_path; 153 size_t index = start; 154 155 if (end > paths.size()) end = paths.size(); 156 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] == "/") { 160 out_path += "/"; 161 index++; 162 } 163 164 for (; index < end; index++) { 165 out_path += paths[index]; 166 if (index < end - 1) 167 out_path += "/"; 168 } 169 170 return out_path; 171} 172 173// static 174StringArray_t Path::Split(const std::string& path) { 175 StringArray_t path_split; 176 StringArray_t components; 177 178 sdk_util::SplitString(path, '/', &path_split); 179 180 if (path[0] == '/') 181 components.push_back("/"); 182 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); 187 } 188 return components; 189} 190 191Path& Path::operator =(const Path& p) { 192 paths_ = p.paths_; 193 return *this; 194} 195 196Path& Path::operator =(const std::string& p) { 197 return Set(p); 198} 199 200} // namespace nacl_io 201 202