144 std::vector<std::string> result;
145 size_t pathStartIndex = 0;
149 if (format == PathFormat::kWindows && path.length() >= 2 &&
is_drive_component(path.substr(0, 2))) {
150 result.push_back(path.substr(0, 2));
156 size_t previousIndex = pathStartIndex;
157 size_t index = pathStartIndex;
158 bool foundNonRootSeparator =
false;
159 while ((index = path.find(separator, previousIndex)) != std::string::npos) {
162 if (index == pathStartIndex) {
163 result.push_back(path.substr(index, 1));
165 foundNonRootSeparator =
true;
167 size_t length = index - previousIndex;
169 result.push_back(path.substr(previousIndex, length));
171 previousIndex = index + 1;
173 if (previousIndex < path.length() || foundNonRootSeparator) {
174 result.push_back(path.substr(previousIndex));
181 auto begin = components.begin();
184 if (format == PathFormat::kWindows && components.size() >= 1 &&
is_drive_component(components[0])) {
185 drive += components[0];
192 for (
auto iterator = begin; iterator != components.end(); iterator++) {
193 if (iterator != begin && path.back() != separator) {
204 if ((*iterator).empty() && path.empty()) {
263 const std::string &basePath,
265 std::vector<std::string> pathComponents =
split(path, format);
266 std::vector<std::string> basePathComponents =
split(basePath, format);
276 std::string basePathDrive =
drive_component(basePathComponents, format);
277 if (!pathDrive.empty() && pathDrive != basePathDrive && !
is_rooted(pathComponents, format)) {
283 std::vector<std::string> resolvedPathRootComponents(basePathComponents.cbegin(), basePathComponentsPathBegin);
284 std::vector<std::string> resolvedPathRootlessComponents(basePathComponentsPathBegin, basePathComponents.cend());
289 std::string pathSeparator;
291 if (resolvedPathRootComponents.empty() || resolvedPathRootComponents.back() != pathSeparator) {
292 resolvedPathRootComponents.push_back(pathSeparator);
294 resolvedPathRootlessComponents = std::vector<std::string>(++pathComponents.begin(), pathComponents.end());
299 for (
const auto &pathComponent : pathComponents) {
302 while (!resolvedPathRootlessComponents.empty() && resolvedPathRootlessComponents.back().empty()) {
303 resolvedPathRootlessComponents.pop_back();
306 if (pathComponent ==
"..") {
307 if (resolvedPathRootlessComponents.empty() || resolvedPathRootlessComponents.back() ==
"..") {
308 resolvedPathRootlessComponents.push_back(
"..");
310 resolvedPathRootlessComponents.pop_back();
313 resolvedPathRootlessComponents.push_back(pathComponent);
320 std::vector<std::string> resolvedPathComponents = resolvedPathRootComponents;
321 resolvedPathComponents.insert(resolvedPathComponents.end(), resolvedPathRootlessComponents.begin(), resolvedPathRootlessComponents.end());
322 std::string resolvedPath =
join(resolvedPathComponents, format);
325 if (resolvedPath.empty()) {
std::vector< std::string > split(const std::string &path, const PathFormat format)
Split a path, path, into its components, using the path separator, separator.
std::string appending_components(const std::string &path, const std::vector< std::string > &components, const PathFormat format)
Convenience wrapper for join that returns a new path resulting from appending path components,...
std::string resolve_path(const std::string &path, const std::string &startingPath, const PathFormat format)
Returns a path by resolving a relative or absolute path against a starting path.
std::string join(const std::vector< std::string > &components, const PathFormat format)
Return a new path by joining the path components, components, with path separator,...
static std::vector< std::string >::const_iterator path_find_rootless_components_begin(const std::vector< std::string > &components, const pathutils::PathFormat format)
Return the iterator corresponding with the beginning of the path components.