10a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Copyright 2008, Google Inc. 20a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// All rights reserved. 30a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// 40a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Redistribution and use in source and binary forms, with or without 50a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// modification, are permitted provided that the following conditions are 60a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// met: 70a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// 80a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// * Redistributions of source code must retain the above copyright 90a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// notice, this list of conditions and the following disclaimer. 100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// * Redistributions in binary form must reproduce the above 110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// copyright notice, this list of conditions and the following disclaimer 120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// in the documentation and/or other materials provided with the 130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// distribution. 140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// * Neither the name of Google Inc. nor the names of its 150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// contributors may be used to endorse or promote products derived from 160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// this software without specific prior written permission. 170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// 180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// 300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Authors: keith.ray@gmail.com (Keith Ray) 310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <gtest/internal/gtest-filepath.h> 330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <gtest/internal/gtest-port.h> 340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <stdlib.h> 360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS_MOBILE 380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <windows.h> 390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#elif GTEST_OS_WINDOWS 400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <direct.h> 410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <io.h> 420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#elif GTEST_OS_SYMBIAN 430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Symbian OpenC has PATH_MAX in sys/syslimits.h 440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <sys/syslimits.h> 450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <limits.h> 470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <climits> // Some Linux distributions define PATH_MAX here. 480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif // GTEST_OS_WINDOWS_MOBILE 490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS 510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#define GTEST_PATH_MAX_ _MAX_PATH 520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#elif defined(PATH_MAX) 530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#define GTEST_PATH_MAX_ PATH_MAX 540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#elif defined(_XOPEN_PATH_MAX) 550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX 560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#define GTEST_PATH_MAX_ _POSIX_PATH_MAX 580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif // GTEST_OS_WINDOWS 590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#include <gtest/internal/gtest-string.h> 610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathnamespace testing { 630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathnamespace internal { 640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS 660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathconst char kPathSeparator = '\\'; 670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathconst char kPathSeparatorString[] = "\\"; 680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS_MOBILE 690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Windows CE doesn't have a current directory. You should not use 700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// the current directory in tests on Windows CE, but this at least 710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// provides a reasonable fallback. 720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathconst char kCurrentDirectoryString[] = "\\"; 730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Windows CE doesn't define INVALID_FILE_ATTRIBUTES 740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathconst DWORD kInvalidFileAttributes = 0xffffffff; 750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathconst char kCurrentDirectoryString[] = ".\\"; 770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif // GTEST_OS_WINDOWS_MOBILE 780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathconst char kPathSeparator = '/'; 800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathconst char kPathSeparatorString[] = "/"; 810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathconst char kCurrentDirectoryString[] = "./"; 820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif // GTEST_OS_WINDOWS 830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Returns the current working directory, or "" if unsuccessful. 850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathFilePath FilePath::GetCurrentDir() { 860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS_MOBILE 870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath // Windows CE doesn't have a current directory, so we just return 880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath // something reasonable. 890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return FilePath(kCurrentDirectoryString); 900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#elif GTEST_OS_WINDOWS 910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; 920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); 930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; 950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); 960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif // GTEST_OS_WINDOWS_MOBILE 970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Returns a copy of the FilePath with the case-insensitive extension removed. 1000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns 1010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// FilePath("dir/file"). If a case-insensitive extension is not 1020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// found, returns a copy of the original FilePath. 1030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathFilePath FilePath::RemoveExtension(const char* extension) const { 1040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath String dot_extension(String::Format(".%s", extension)); 1050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { 1060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); 1070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } 1080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return *this; 1090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 1100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 1110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Returns a copy of the FilePath with the directory part removed. 1120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Example: FilePath("path/to/file").RemoveDirectoryName() returns 1130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// FilePath("file"). If there is no directory part ("just_a_file"), it returns 1140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// the FilePath unmodified. If there is no file part ("just_a_dir/") it 1150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// returns an empty FilePath (""). 1160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// On Windows platform, '\' is the path separator, otherwise it is '/'. 1170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathFilePath FilePath::RemoveDirectoryName() const { 1180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const char* const last_sep = strrchr(c_str(), kPathSeparator); 1190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return last_sep ? FilePath(String(last_sep + 1)) : *this; 1200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 1210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 1220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// RemoveFileName returns the directory path with the filename removed. 1230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". 1240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// If the FilePath is "a_file" or "/a_file", RemoveFileName returns 1250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does 1260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// not have a file, like "just/a/dir/", it returns the FilePath unmodified. 1270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// On Windows platform, '\' is the path separator, otherwise it is '/'. 1280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathFilePath FilePath::RemoveFileName() const { 1290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const char* const last_sep = strrchr(c_str(), kPathSeparator); 1300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath String dir; 1310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if (last_sep) { 1320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath dir = String(c_str(), last_sep + 1 - c_str()); 1330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } else { 1340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath dir = kCurrentDirectoryString; 1350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } 1360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return FilePath(dir); 1370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 1380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 1390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Helper functions for naming files in a directory for xml output. 1400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 1410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Given directory = "dir", base_name = "test", number = 0, 1420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// extension = "xml", returns "dir/test.xml". If number is greater 1430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// than zero (e.g., 12), returns "dir/test_12.xml". 1440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// On Windows platform, uses \ as the separator rather than /. 1450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathFilePath FilePath::MakeFileName(const FilePath& directory, 1460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const FilePath& base_name, 1470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath int number, 1480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const char* extension) { 1490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath String file; 1500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if (number == 0) { 1510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath file = String::Format("%s.%s", base_name.c_str(), extension); 1520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } else { 1530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); 1540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } 1550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return ConcatPaths(directory, FilePath(file)); 1560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 1570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 1580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". 1590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// On Windows, uses \ as the separator rather than /. 1600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathFilePath FilePath::ConcatPaths(const FilePath& directory, 1610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const FilePath& relative_path) { 1620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if (directory.IsEmpty()) 1630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return relative_path; 1640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const FilePath dir(directory.RemoveTrailingPathSeparator()); 1650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, 1660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath relative_path.c_str())); 1670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 1680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 1690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Returns true if pathname describes something findable in the file-system, 1700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// either a file, directory, or whatever. 1710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool FilePath::FileOrDirectoryExists() const { 1720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS_MOBILE 1730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); 1740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const DWORD attributes = GetFileAttributes(unicode); 1750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath delete [] unicode; 1760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return attributes != kInvalidFileAttributes; 1770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 1780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath posix::StatStruct file_stat; 1790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return posix::Stat(pathname_.c_str(), &file_stat) == 0; 1800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif // GTEST_OS_WINDOWS_MOBILE 1810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 1820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 1830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Returns true if pathname describes a directory in the file-system 1840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// that exists. 1850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool FilePath::DirectoryExists() const { 1860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath bool result = false; 1870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS 1880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath // Don't strip off trailing separator if path is a root directory on 1890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath // Windows (like "C:\\"). 1900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const FilePath& path(IsRootDirectory() ? *this : 1910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath RemoveTrailingPathSeparator()); 1920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 1930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const FilePath& path(*this); 1940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif 1950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 1960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS_MOBILE 1970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); 1980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const DWORD attributes = GetFileAttributes(unicode); 1990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath delete [] unicode; 2000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if ((attributes != kInvalidFileAttributes) && 2010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath (attributes & FILE_ATTRIBUTE_DIRECTORY)) { 2020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath result = true; 2030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } 2040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 2050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath posix::StatStruct file_stat; 2060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath result = posix::Stat(path.c_str(), &file_stat) == 0 && 2070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath posix::IsDir(file_stat); 2080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif // GTEST_OS_WINDOWS_MOBILE 2090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return result; 2110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 2120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Returns true if pathname describes a root directory. (Windows has one 2140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// root directory per disk drive.) 2150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool FilePath::IsRootDirectory() const { 2160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS 2170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath // TODO(wan@google.com): on Windows a network share like 2180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath // \\server\share can be a root directory, although it cannot be the 2190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath // current directory. Handle this properly. 2200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return pathname_.length() == 3 && IsAbsolutePath(); 2210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 2220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return pathname_ == kPathSeparatorString; 2230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif 2240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 2250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Returns true if pathname describes an absolute path. 2270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool FilePath::IsAbsolutePath() const { 2280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const char* const name = pathname_.c_str(); 2290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS 2300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return pathname_.length() >= 3 && 2310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath ((name[0] >= 'a' && name[0] <= 'z') || 2320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath (name[0] >= 'A' && name[0] <= 'Z')) && 2330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath name[1] == ':' && 2340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath name[2] == kPathSeparator; 2350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 2360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return name[0] == kPathSeparator; 2370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif 2380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 2390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Returns a pathname for a file that does not currently exist. The pathname 2410a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// will be directory/base_name.extension or 2420a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// directory/base_name_<number>.extension if directory/base_name.extension 2430a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// already exists. The number will be incremented until a pathname is found 2440a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// that does not already exist. 2450a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. 2460a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// There could be a race condition if two or more processes are calling this 2470a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// function at the same time -- they could both pick the same filename. 2480a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathFilePath FilePath::GenerateUniqueFileName(const FilePath& directory, 2490a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const FilePath& base_name, 2500a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const char* extension) { 2510a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath FilePath full_pathname; 2520a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath int number = 0; 2530a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath do { 2540a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); 2550a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } while (full_pathname.FileOrDirectoryExists()); 2560a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return full_pathname; 2570a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 2580a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2590a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Returns true if FilePath ends with a path separator, which indicates that 2600a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// it is intended to represent a directory. Returns false otherwise. 2610a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// This does NOT check that a directory (or file) actually exists. 2620a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool FilePath::IsDirectory() const { 2630a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return pathname_.EndsWith(kPathSeparatorString); 2640a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 2650a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2660a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Create directories so that path exists. Returns true if successful or if 2670a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// the directories already exist; returns false if unable to create directories 2680a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// for any reason. 2690a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool FilePath::CreateDirectoriesRecursively() const { 2700a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if (!this->IsDirectory()) { 2710a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return false; 2720a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } 2730a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2740a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if (pathname_.length() == 0 || this->DirectoryExists()) { 2750a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return true; 2760a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } 2770a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2780a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); 2790a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return parent.CreateDirectoriesRecursively() && this->CreateFolder(); 2800a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 2810a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2820a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Create the directory so that path exists. Returns true if successful or 2830a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// if the directory already exists; returns false if unable to create the 2840a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// directory for any reason, including if the parent directory does not 2850a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// exist. Not named "CreateDirectory" because that's a macro on Windows. 2860a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathbool FilePath::CreateFolder() const { 2870a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#if GTEST_OS_WINDOWS_MOBILE 2880a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath FilePath removed_sep(this->RemoveTrailingPathSeparator()); 2890a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); 2900a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath int result = CreateDirectory(unicode, NULL) ? 0 : -1; 2910a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath delete [] unicode; 2920a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#elif GTEST_OS_WINDOWS 2930a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath int result = _mkdir(pathname_.c_str()); 2940a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#else 2950a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath int result = mkdir(pathname_.c_str(), 0777); 2960a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath#endif // GTEST_OS_WINDOWS_MOBILE 2970a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 2980a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if (result == -1) { 2990a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return this->DirectoryExists(); // An error is OK if the directory exists. 3000a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } 3010a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return true; // No error. 3020a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 3030a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 3040a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// If input name has a trailing separator character, remove it and return the 3050a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// name, otherwise return the name string unmodified. 3060a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// On Windows platform, uses \ as the separator, other platforms use /. 3070a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan KamathFilePath FilePath::RemoveTrailingPathSeparator() const { 3080a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return pathname_.EndsWith(kPathSeparatorString) 3090a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) 3100a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath : *this; 3110a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 3120a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 3130a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// Normalize removes any redundant separators that might be in the pathname. 3140a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// For example, "bar///foo" becomes "bar/foo". Does not eliminate other 3150a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath// redundancies that might be in a pathname involving "." or "..". 3160a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamathvoid FilePath::Normalize() { 3170a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if (pathname_.c_str() == NULL) { 3180a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath pathname_ = ""; 3190a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath return; 3200a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } 3210a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath const char* src = pathname_.c_str(); 3220a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath char* const dest = new char[pathname_.length() + 1]; 3230a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath char* dest_ptr = dest; 3240a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath memset(dest_ptr, 0, pathname_.length() + 1); 3250a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 3260a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath while (*src != '\0') { 3270a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath *dest_ptr++ = *src; 3280a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath if (*src != kPathSeparator) 3290a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath src++; 3300a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath else 3310a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath while (*src == kPathSeparator) 3320a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath src++; 3330a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath } 3340a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath *dest_ptr = '\0'; 3350a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath pathname_ = dest; 3360a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath delete[] dest; 3370a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} 3380a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath 3390a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} // namespace internal 3400a58c5c2f73e5047b36f12b5f12b12d6f2a9f69dNarayan Kamath} // namespace testing 341