blob: a11d25b1f691b463317584473eb21c8472028608 [file] [log] [blame]
// Copyright 2010 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "path.h"
#include <stddef.h>
#include "glog/logging.h"
using std::string;
namespace {
// Appends |path2| to |path1|.
// Assuming |path1| and |path2| are not empty.
void AppendPath(string* path1, absl::string_view path2) {
DCHECK(!path1->empty());
DCHECK(!path2.empty());
#ifndef _WIN32
if (path2[0] == '/') {
path2.remove_prefix(1);
}
if (path1->back() != '/') {
path1->push_back('/');
}
#else
if (path2[0] == '\\' || path2[0] == '/') {
path2.remove_prefix(1);
}
if (path1->back() != '\\' && path1->back() != '/') {
path1->push_back('\\');
}
#endif
path1->append(path2.begin(), path2.end());
}
} // anonymous namespace
namespace file {
namespace internal {
string JoinPathIterators(const absl::string_view* begin,
const absl::string_view* end,
size_t cap) {
string result;
result.reserve(cap);
while (begin != end) {
const absl::string_view path = *begin++;
if (path.empty()) {
continue;
}
if (result.empty()) {
result.append(path.begin(), path.end());
continue;
}
AppendPath(&result, path);
}
return result;
}
string JoinPathImpl(std::initializer_list<absl::string_view> paths) {
size_t cap = 0;
for (const auto& path : paths) {
cap += path.size() + 1;
}
return JoinPathIterators(paths.begin(), paths.end(), cap);
}
string JoinPathRespectAbsoluteImpl(
std::initializer_list<absl::string_view> paths) {
size_t cap = 0;
auto start_iter = paths.end();
for (; start_iter != paths.begin();) {
--start_iter;
const auto& path = *start_iter;
cap += path.size() + 1;
if (IsAbsolutePath(path)) {
break;
}
}
return JoinPathIterators(start_iter, paths.end(), cap);
}
} // namespace internal
absl::string_view Basename(absl::string_view fname) {
#ifndef _WIN32
absl::string_view::size_type pos = fname.find_last_of('/');
// Handle the case with no '/' in |fname|.
if (pos == absl::string_view::npos)
return fname;
return fname.substr(pos + 1);
#else
// TODO: support UNC path.
char name[_MAX_FNAME] = {0};
char ext[_MAX_EXT] = {0};
CHECK_EQ(_splitpath_s(string(fname).c_str(), nullptr, 0, nullptr, 0,
name, sizeof name, ext, sizeof ext), 0);
size_t basename_length = strlen(name);
if (ext[0] == '.')
basename_length += strlen(ext);
fname.remove_prefix(fname.length() - basename_length);
return fname;
#endif
}
absl::string_view Dirname(absl::string_view fname) {
#ifndef _WIN32
absl::string_view::size_type pos = fname.find_last_of('/');
// Handle the case with no '/' in 'path'.
if (pos == absl::string_view::npos)
return fname.substr(0, 0);
// Handle the case with a single leading '/' in 'path'.
if (pos == 0)
return fname.substr(0, 1);
return fname.substr(0, pos);
#else
// TODO: support UNC path.
char drive[_MAX_DRIVE] = {0};
char dir[_MAX_DIR] = {0};
_splitpath_s(string(fname).c_str(), drive, sizeof drive, dir, sizeof dir,
nullptr, 0, nullptr, 0);
const size_t dir_length = strlen(dir);
size_t dirname_length = strlen(drive) + dir_length;
// Cut off last '\\' or '/' if dir is not single '\\' or '/'.
if (dir_length > 1) {
dirname_length--;
}
return fname.substr(0, dirname_length);
#endif
}
absl::string_view Stem(absl::string_view fname) {
absl::string_view path = Basename(fname);
absl::string_view::size_type pos = path.find_last_of('.');
if (pos == absl::string_view::npos)
return path;
return path.substr(0, pos);
}
absl::string_view Extension(absl::string_view fname) {
absl::string_view path = Basename(fname);
absl::string_view::size_type pos = path.find_last_of('.');
if (pos == absl::string_view::npos)
return fname.substr(fname.size());
return path.substr(pos + 1);
}
bool IsAbsolutePath(absl::string_view path) {
#ifndef _WIN32
return !path.empty() && path[0] == '/';
#else
return (!path.empty() && path[0] == '\\') ||
(!path.empty() && path[0] == '/') ||
(path.size() > 1 && path[1] == ':');
#endif
}
} // namespace file