30#include "gtest/internal/gtest-filepath.h"
33#include "gtest/internal/gtest-port.h"
34#include "gtest/gtest-message.h"
36#if GTEST_OS_WINDOWS_MOBILE
46#include "gtest/internal/gtest-string.h"
49# define GTEST_PATH_MAX_ _MAX_PATH
50#elif defined(PATH_MAX)
51# define GTEST_PATH_MAX_ PATH_MAX
52#elif defined(_XOPEN_PATH_MAX)
53# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
55# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
66const char kPathSeparator =
'\\';
67const char kAlternatePathSeparator =
'/';
68const char kAlternatePathSeparatorString[] =
"/";
69# if GTEST_OS_WINDOWS_MOBILE
73const char kCurrentDirectoryString[] =
"\\";
75const DWORD kInvalidFileAttributes = 0xffffffff;
77const char kCurrentDirectoryString[] =
".\\";
80const char kPathSeparator =
'/';
81const char kCurrentDirectoryString[] =
"./";
85static bool IsPathSeparator(
char c) {
86#if GTEST_HAS_ALT_PATH_SEP_
87 return (c == kPathSeparator) || (c == kAlternatePathSeparator);
89 return c == kPathSeparator;
94FilePath FilePath::GetCurrentDir() {
95#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
96 GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32
99 return FilePath(kCurrentDirectoryString);
100#elif GTEST_OS_WINDOWS
101 char cwd[GTEST_PATH_MAX_ + 1] = {
'\0' };
102 return FilePath(_getcwd(cwd,
sizeof(cwd)) ==
nullptr ?
"" : cwd);
104 char cwd[GTEST_PATH_MAX_ + 1] = {
'\0' };
105 char* result = getcwd(cwd,
sizeof(cwd));
110 return FilePath(result ==
nullptr ? kCurrentDirectoryString : cwd);
112 return FilePath(result ==
nullptr ?
"" : cwd);
120FilePath FilePath::RemoveExtension(
const char* extension)
const {
121 const std::string dot_extension = std::string(
".") + extension;
122 if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
123 return FilePath(pathname_.substr(
124 0, pathname_.length() - dot_extension.length()));
132const char* FilePath::FindLastPathSeparator()
const {
133 const char*
const last_sep = strrchr(c_str(), kPathSeparator);
134#if GTEST_HAS_ALT_PATH_SEP_
135 const char*
const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
137 if (last_alt_sep !=
nullptr &&
138 (last_sep ==
nullptr || last_alt_sep > last_sep)) {
151FilePath FilePath::RemoveDirectoryName()
const {
152 const char*
const last_sep = FindLastPathSeparator();
153 return last_sep ? FilePath(last_sep + 1) : *this;
162FilePath FilePath::RemoveFileName()
const {
163 const char*
const last_sep = FindLastPathSeparator();
166 dir = std::string(c_str(),
static_cast<size_t>(last_sep + 1 - c_str()));
168 dir = kCurrentDirectoryString;
170 return FilePath(dir);
179FilePath FilePath::MakeFileName(
const FilePath& directory,
180 const FilePath& base_name,
182 const char* extension) {
185 file = base_name.string() +
"." + extension;
187 file = base_name.string() +
"_" + StreamableToString(number)
190 return ConcatPaths(directory, FilePath(file));
195FilePath FilePath::ConcatPaths(
const FilePath& directory,
196 const FilePath& relative_path) {
197 if (directory.IsEmpty())
198 return relative_path;
199 const FilePath dir(directory.RemoveTrailingPathSeparator());
200 return FilePath(dir.string() + kPathSeparator + relative_path.string());
205bool FilePath::FileOrDirectoryExists()
const {
206#if GTEST_OS_WINDOWS_MOBILE
207 LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
208 const DWORD attributes = GetFileAttributes(unicode);
210 return attributes != kInvalidFileAttributes;
212 posix::StatStruct file_stat;
213 return posix::Stat(pathname_.c_str(), &file_stat) == 0;
219bool FilePath::DirectoryExists()
const {
224 const FilePath& path(IsRootDirectory() ? *
this :
225 RemoveTrailingPathSeparator());
227 const FilePath& path(*
this);
230#if GTEST_OS_WINDOWS_MOBILE
231 LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
232 const DWORD attributes = GetFileAttributes(unicode);
234 if ((attributes != kInvalidFileAttributes) &&
235 (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
239 posix::StatStruct file_stat;
240 result = posix::Stat(path.c_str(), &file_stat) == 0 &&
241 posix::IsDir(file_stat);
249bool FilePath::IsRootDirectory()
const {
251 return pathname_.length() == 3 && IsAbsolutePath();
253 return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
258bool FilePath::IsAbsolutePath()
const {
259 const char*
const name = pathname_.c_str();
261 return pathname_.length() >= 3 &&
262 ((name[0] >=
'a' && name[0] <=
'z') ||
263 (name[0] >=
'A' && name[0] <=
'Z')) &&
265 IsPathSeparator(name[2]);
267 return IsPathSeparator(name[0]);
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() &&
295 IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
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
330 int result = mkdir(pathname_.c_str(), 0777);
334 return this->DirectoryExists();
342FilePath FilePath::RemoveTrailingPathSeparator()
const {
344 ? FilePath(pathname_.substr(0, pathname_.length() - 1))
351void FilePath::Normalize() {
352 auto out = pathname_.begin();
354 for (
const char character : pathname_) {
355 if (!IsPathSeparator(character)) {
356 *(out++) = character;
357 }
else if (out == pathname_.begin() || *std::prev(out) != kPathSeparator) {
358 *(out++) = kPathSeparator;
364 pathname_.erase(out, pathname_.end());