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