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