30#include "gtest/internal/gtest-filepath.h"
34#include "gtest/gtest-message.h"
35#include "gtest/internal/gtest-port.h"
37#if GTEST_OS_WINDOWS_MOBILE
48#include "gtest/internal/gtest-string.h"
51#define GTEST_PATH_MAX_ _MAX_PATH
52#elif defined(PATH_MAX)
53#define GTEST_PATH_MAX_ PATH_MAX
54#elif defined(_XOPEN_PATH_MAX)
55#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
57#define GTEST_PATH_MAX_ _POSIX_PATH_MAX
68const char kPathSeparator =
'\\';
69const char kAlternatePathSeparator =
'/';
70const char kAlternatePathSeparatorString[] =
"/";
71#if GTEST_OS_WINDOWS_MOBILE
75const char kCurrentDirectoryString[] =
"\\";
77const DWORD kInvalidFileAttributes = 0xffffffff;
79const char kCurrentDirectoryString[] =
".\\";
82const char kPathSeparator =
'/';
83const char kCurrentDirectoryString[] =
"./";
87static bool IsPathSeparator(
char c) {
88#if GTEST_HAS_ALT_PATH_SEP_
89 return (c == kPathSeparator) || (c == kAlternatePathSeparator);
91 return c == kPathSeparator;
96FilePath FilePath::GetCurrentDir() {
97#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
98 GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32 || \
99 GTEST_OS_XTENSA || GTEST_OS_QURT
102 return FilePath(kCurrentDirectoryString);
103#elif GTEST_OS_WINDOWS
104 char cwd[GTEST_PATH_MAX_ + 1] = {
'\0'};
105 return FilePath(_getcwd(cwd,
sizeof(cwd)) ==
nullptr ?
"" : cwd);
107 char cwd[GTEST_PATH_MAX_ + 1] = {
'\0'};
108 char* result = getcwd(cwd,
sizeof(cwd));
113 return FilePath(result ==
nullptr ? kCurrentDirectoryString : cwd);
115 return FilePath(result ==
nullptr ?
"" : cwd);
123FilePath FilePath::RemoveExtension(
const char* extension)
const {
124 const std::string dot_extension = std::string(
".") + extension;
125 if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
127 pathname_.substr(0, pathname_.length() - dot_extension.length()));
135const char* FilePath::FindLastPathSeparator()
const {
136 const char*
const last_sep = strrchr(c_str(), kPathSeparator);
137#if GTEST_HAS_ALT_PATH_SEP_
138 const char*
const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
140 if (last_alt_sep !=
nullptr &&
141 (last_sep ==
nullptr || last_alt_sep > last_sep)) {
148size_t FilePath::CalculateRootLength()
const {
149 const auto &path = pathname_;
150 auto s = path.begin();
151 auto end = path.end();
153 if (end - s >= 2 && s[1] ==
':' &&
154 (end - s == 2 || IsPathSeparator(s[2])) &&
155 ((
'A' <= s[0] && s[0] <=
'Z') || (
'a' <= s[0] && s[0] <=
'z'))) {
161 }
else if (end - s >= 3 && IsPathSeparator(*s) && IsPathSeparator(*(s + 1))
162 && !IsPathSeparator(*(s + 2))) {
166 for (
int i = 0; i < 2; ++i) {
168 bool stop = IsPathSeparator(*s);
175 }
else if (s != end && IsPathSeparator(*s)) {
180 if (s != end && IsPathSeparator(*s)) {
184 return static_cast<size_t>(s - path.begin());
193FilePath FilePath::RemoveDirectoryName()
const {
194 const char*
const last_sep = FindLastPathSeparator();
195 return last_sep ? FilePath(last_sep + 1) : *this;
204FilePath FilePath::RemoveFileName()
const {
205 const char*
const last_sep = FindLastPathSeparator();
208 dir = std::string(c_str(),
static_cast<size_t>(last_sep + 1 - c_str()));
210 dir = kCurrentDirectoryString;
212 return FilePath(dir);
221FilePath FilePath::MakeFileName(
const FilePath& directory,
222 const FilePath& base_name,
int number,
223 const char* extension) {
226 file = base_name.string() +
"." + extension;
229 base_name.string() +
"_" + StreamableToString(number) +
"." + extension;
231 return ConcatPaths(directory, FilePath(file));
236FilePath FilePath::ConcatPaths(
const FilePath& directory,
237 const FilePath& relative_path) {
238 if (directory.IsEmpty())
return relative_path;
239 const FilePath dir(directory.RemoveTrailingPathSeparator());
240 return FilePath(dir.string() + kPathSeparator + relative_path.string());
245bool FilePath::FileOrDirectoryExists()
const {
246#if GTEST_OS_WINDOWS_MOBILE
247 LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
248 const DWORD attributes = GetFileAttributes(unicode);
250 return attributes != kInvalidFileAttributes;
252 posix::StatStruct file_stat{};
253 return posix::Stat(pathname_.c_str(), &file_stat) == 0;
259bool FilePath::DirectoryExists()
const {
264 const FilePath& path(IsRootDirectory() ? *
this
265 : RemoveTrailingPathSeparator());
267 const FilePath& path(*
this);
270#if GTEST_OS_WINDOWS_MOBILE
271 LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
272 const DWORD attributes = GetFileAttributes(unicode);
274 if ((attributes != kInvalidFileAttributes) &&
275 (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
279 posix::StatStruct file_stat{};
281 posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat);
289bool FilePath::IsRootDirectory()
const {
290 size_t root_length = CalculateRootLength();
291 return root_length > 0 && root_length == pathname_.size() &&
292 IsPathSeparator(pathname_[root_length - 1]);
296bool FilePath::IsAbsolutePath()
const {
297 return CalculateRootLength() > 0;
308FilePath FilePath::GenerateUniqueFileName(
const FilePath& directory,
309 const FilePath& base_name,
310 const char* extension) {
311 FilePath full_pathname;
314 full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
315 }
while (full_pathname.FileOrDirectoryExists());
316 return full_pathname;
322bool FilePath::IsDirectory()
const {
323 return !pathname_.empty() &&
324 IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
330bool FilePath::CreateDirectoriesRecursively()
const {
331 if (!this->IsDirectory()) {
335 if (pathname_.length() == 0 || this->DirectoryExists()) {
339 const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
340 return parent.CreateDirectoriesRecursively() && this->CreateFolder();
347bool FilePath::CreateFolder()
const {
348#if GTEST_OS_WINDOWS_MOBILE
349 FilePath removed_sep(this->RemoveTrailingPathSeparator());
350 LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
351 int result = CreateDirectory(unicode,
nullptr) ? 0 : -1;
353#elif GTEST_OS_WINDOWS
354 int result = _mkdir(pathname_.c_str());
355#elif GTEST_OS_ESP8266 || GTEST_OS_XTENSA || GTEST_OS_QURT
359 int result = mkdir(pathname_.c_str(), 0777);
363 return this->DirectoryExists();
371FilePath FilePath::RemoveTrailingPathSeparator()
const {
372 return IsDirectory() ? FilePath(pathname_.substr(0, pathname_.length() - 1))
380void FilePath::Normalize() {
381 auto out = pathname_.begin();
383 auto i = pathname_.cbegin();
386 if (pathname_.end() - i >= 3 && IsPathSeparator(*i) &&
387 IsPathSeparator(*(i + 1)) && !IsPathSeparator(*(i + 2))) {
388 *(out++) = kPathSeparator;
389 *(out++) = kPathSeparator;
392 while (i != pathname_.end()) {
393 const char character = *i;
394 if (!IsPathSeparator(character)) {
395 *(out++) = character;
396 }
else if (out == pathname_.begin() || *std::prev(out) != kPathSeparator) {
397 *(out++) = kPathSeparator;
402 pathname_.erase(out, pathname_.end());