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
69const char kAlternatePathSeparator =
'/';
70const char kAlternatePathSeparatorString[] =
"/";
71#if GTEST_OS_WINDOWS_MOBILE
77const DWORD kInvalidFileAttributes = 0xffffffff;
88#if GTEST_HAS_ALT_PATH_SEP_
96FilePath FilePath::GetCurrentDir() {
97#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
98 GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32 || \
103#elif GTEST_OS_WINDOWS
105 return FilePath(_getcwd(cwd,
sizeof(cwd)) ==
nullptr ?
"" : cwd);
108 char* result = getcwd(cwd,
sizeof(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 {
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)) {
154FilePath FilePath::RemoveDirectoryName()
const {
155 const char*
const last_sep = FindLastPathSeparator();
156 return last_sep ? FilePath(last_sep + 1) : *this;
165FilePath FilePath::RemoveFileName()
const {
166 const char*
const last_sep = FindLastPathSeparator();
169 dir = std::string(c_str(),
static_cast<size_t>(last_sep + 1 - c_str()));
173 return FilePath(dir);
182FilePath FilePath::MakeFileName(
const FilePath& directory,
183 const FilePath& base_name,
int number,
184 const char* extension) {
187 file = base_name.string() +
"." + extension;
190 base_name.string() +
"_" + StreamableToString(number) +
"." + extension;
192 return ConcatPaths(directory, FilePath(file));
197FilePath FilePath::ConcatPaths(
const FilePath& directory,
198 const FilePath& relative_path) {
199 if (directory.IsEmpty())
return relative_path;
200 const FilePath dir(directory.RemoveTrailingPathSeparator());
201 return FilePath(dir.string() +
kPathSeparator + relative_path.string());
206bool FilePath::FileOrDirectoryExists()
const {
207#if GTEST_OS_WINDOWS_MOBILE
208 LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
209 const DWORD attributes = GetFileAttributes(unicode);
211 return attributes != kInvalidFileAttributes;
213 posix::StatStruct file_stat{};
214 return posix::Stat(pathname_.c_str(), &file_stat) == 0;
220bool FilePath::DirectoryExists()
const {
225 const FilePath& path(IsRootDirectory() ? *
this
226 : RemoveTrailingPathSeparator());
228 const FilePath& path(*
this);
231#if GTEST_OS_WINDOWS_MOBILE
232 LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
233 const DWORD attributes = GetFileAttributes(unicode);
235 if ((attributes != kInvalidFileAttributes) &&
236 (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
240 posix::StatStruct file_stat{};
242 posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat);
250bool FilePath::IsRootDirectory()
const {
252 return pathname_.length() == 3 && IsAbsolutePath();
254 return pathname_.length() == 1 &&
IsPathSeparator(pathname_.c_str()[0]);
259bool FilePath::IsAbsolutePath()
const {
260 const char*
const name = pathname_.c_str();
262 return pathname_.length() >= 3 &&
263 ((name[0] >=
'a' && name[0] <=
'z') ||
264 (name[0] >=
'A' && name[0] <=
'Z')) &&
279FilePath FilePath::GenerateUniqueFileName(
const FilePath& directory,
280 const FilePath& base_name,
281 const char* extension) {
282 FilePath full_pathname;
285 full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
286 }
while (full_pathname.FileOrDirectoryExists());
287 return full_pathname;
293bool FilePath::IsDirectory()
const {
294 return !pathname_.empty() &&
301bool FilePath::CreateDirectoriesRecursively()
const {
302 if (!this->IsDirectory()) {
306 if (pathname_.length() == 0 || this->DirectoryExists()) {
310 const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
311 return parent.CreateDirectoriesRecursively() && this->CreateFolder();
318bool FilePath::CreateFolder()
const {
319#if GTEST_OS_WINDOWS_MOBILE
320 FilePath removed_sep(this->RemoveTrailingPathSeparator());
321 LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
322 int result = CreateDirectory(unicode,
nullptr) ? 0 : -1;
324#elif GTEST_OS_WINDOWS
325 int result = _mkdir(pathname_.c_str());
326#elif GTEST_OS_ESP8266 || GTEST_OS_XTENSA
330 int result = mkdir(pathname_.c_str(), 0777);
334 return this->DirectoryExists();
342FilePath FilePath::RemoveTrailingPathSeparator()
const {
343 return IsDirectory() ? FilePath(pathname_.substr(0, pathname_.length() - 1))
350void FilePath::Normalize() {
351 auto out = pathname_.begin();
353 for (
const char character : pathname_) {
355 *(out++) = character;
356 }
else if (out == pathname_.begin() || *std::prev(out) !=
kPathSeparator) {
363 pathname_.erase(out, pathname_.end());
const char kCurrentDirectoryString[]
static bool IsPathSeparator(char c)
const char kPathSeparator