14b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Copyright 2008, Google Inc.
24b6829f0d28990dd645e16386eb226d0f10c8731shiqian// All rights reserved.
34b6829f0d28990dd645e16386eb226d0f10c8731shiqian//
44b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Redistribution and use in source and binary forms, with or without
54b6829f0d28990dd645e16386eb226d0f10c8731shiqian// modification, are permitted provided that the following conditions are
64b6829f0d28990dd645e16386eb226d0f10c8731shiqian// met:
74b6829f0d28990dd645e16386eb226d0f10c8731shiqian//
84b6829f0d28990dd645e16386eb226d0f10c8731shiqian//     * Redistributions of source code must retain the above copyright
94b6829f0d28990dd645e16386eb226d0f10c8731shiqian// notice, this list of conditions and the following disclaimer.
104b6829f0d28990dd645e16386eb226d0f10c8731shiqian//     * Redistributions in binary form must reproduce the above
114b6829f0d28990dd645e16386eb226d0f10c8731shiqian// copyright notice, this list of conditions and the following disclaimer
124b6829f0d28990dd645e16386eb226d0f10c8731shiqian// in the documentation and/or other materials provided with the
134b6829f0d28990dd645e16386eb226d0f10c8731shiqian// distribution.
144b6829f0d28990dd645e16386eb226d0f10c8731shiqian//     * Neither the name of Google Inc. nor the names of its
154b6829f0d28990dd645e16386eb226d0f10c8731shiqian// contributors may be used to endorse or promote products derived from
164b6829f0d28990dd645e16386eb226d0f10c8731shiqian// this software without specific prior written permission.
174b6829f0d28990dd645e16386eb226d0f10c8731shiqian//
184b6829f0d28990dd645e16386eb226d0f10c8731shiqian// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
194b6829f0d28990dd645e16386eb226d0f10c8731shiqian// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
204b6829f0d28990dd645e16386eb226d0f10c8731shiqian// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
214b6829f0d28990dd645e16386eb226d0f10c8731shiqian// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
224b6829f0d28990dd645e16386eb226d0f10c8731shiqian// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
234b6829f0d28990dd645e16386eb226d0f10c8731shiqian// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
244b6829f0d28990dd645e16386eb226d0f10c8731shiqian// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
254b6829f0d28990dd645e16386eb226d0f10c8731shiqian// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
264b6829f0d28990dd645e16386eb226d0f10c8731shiqian// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
274b6829f0d28990dd645e16386eb226d0f10c8731shiqian// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
284b6829f0d28990dd645e16386eb226d0f10c8731shiqian// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
294b6829f0d28990dd645e16386eb226d0f10c8731shiqian//
304b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Authors: keith.ray@gmail.com (Keith Ray)
314b6829f0d28990dd645e16386eb226d0f10c8731shiqian
322733a36231e9e59dfe0648562ac021ccea0e27d8zhanyong.wan#include "gtest/gtest-message.h"
332620c79810d4741922e9fa89050c0af564994f24zhanyong.wan#include "gtest/internal/gtest-filepath.h"
342620c79810d4741922e9fa89050c0af564994f24zhanyong.wan#include "gtest/internal/gtest-port.h"
354b6829f0d28990dd645e16386eb226d0f10c8731shiqian
36c3b4de35a18a1f011e8009d4d794f787f7e4e0c1shiqian#include <stdlib.h>
37c3b4de35a18a1f011e8009d4d794f787f7e4e0c1shiqian
38fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#if GTEST_OS_WINDOWS_MOBILE
39733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# include <windows.h>
404cd62602913a032a7aec091d4c8055ff9af95e37zhanyong.wan#elif GTEST_OS_WINDOWS
41733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# include <direct.h>
42733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# include <io.h>
43a92a6f792395e1ad462472d474ab0c76949813favladlosev#elif GTEST_OS_SYMBIAN
44a92a6f792395e1ad462472d474ab0c76949813favladlosev// Symbian OpenC has PATH_MAX in sys/syslimits.h
45733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# include <sys/syslimits.h>
46dd4a17bc20377d250ed116b1083d851adbe45f25shiqian#else
47733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# include <limits.h>
48733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# include <climits>  // Some Linux distributions define PATH_MAX here.
49fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#endif  // GTEST_OS_WINDOWS_MOBILE
50941b5ee8ebaad627df59eaa03509021b3cfa3bafshiqian
514cd62602913a032a7aec091d4c8055ff9af95e37zhanyong.wan#if GTEST_OS_WINDOWS
52733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# define GTEST_PATH_MAX_ _MAX_PATH
53941b5ee8ebaad627df59eaa03509021b3cfa3bafshiqian#elif defined(PATH_MAX)
54733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# define GTEST_PATH_MAX_ PATH_MAX
55941b5ee8ebaad627df59eaa03509021b3cfa3bafshiqian#elif defined(_XOPEN_PATH_MAX)
56733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
57941b5ee8ebaad627df59eaa03509021b3cfa3bafshiqian#else
58733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
59941b5ee8ebaad627df59eaa03509021b3cfa3bafshiqian#endif  // GTEST_OS_WINDOWS
604b6829f0d28990dd645e16386eb226d0f10c8731shiqian
612620c79810d4741922e9fa89050c0af564994f24zhanyong.wan#include "gtest/internal/gtest-string.h"
624b6829f0d28990dd645e16386eb226d0f10c8731shiqian
634b6829f0d28990dd645e16386eb226d0f10c8731shiqiannamespace testing {
644b6829f0d28990dd645e16386eb226d0f10c8731shiqiannamespace internal {
654b6829f0d28990dd645e16386eb226d0f10c8731shiqian
664cd62602913a032a7aec091d4c8055ff9af95e37zhanyong.wan#if GTEST_OS_WINDOWS
678236131e25705a809d496672a3819e1741166c4bzhanyong.wan// On Windows, '\\' is the standard path separator, but many tools and the
688236131e25705a809d496672a3819e1741166c4bzhanyong.wan// Windows API also accept '/' as an alternate path separator. Unless otherwise
698236131e25705a809d496672a3819e1741166c4bzhanyong.wan// noted, a file path can contain either kind of path separators, or a mixture
708236131e25705a809d496672a3819e1741166c4bzhanyong.wan// of them.
714b6829f0d28990dd645e16386eb226d0f10c8731shiqianconst char kPathSeparator = '\\';
728236131e25705a809d496672a3819e1741166c4bzhanyong.wanconst char kAlternatePathSeparator = '/';
738236131e25705a809d496672a3819e1741166c4bzhanyong.wanconst char kAlternatePathSeparatorString[] = "/";
74733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# if GTEST_OS_WINDOWS_MOBILE
75dd4a17bc20377d250ed116b1083d851adbe45f25shiqian// Windows CE doesn't have a current directory. You should not use
76dd4a17bc20377d250ed116b1083d851adbe45f25shiqian// the current directory in tests on Windows CE, but this at least
77dd4a17bc20377d250ed116b1083d851adbe45f25shiqian// provides a reasonable fallback.
78dd4a17bc20377d250ed116b1083d851adbe45f25shiqianconst char kCurrentDirectoryString[] = "\\";
79dd4a17bc20377d250ed116b1083d851adbe45f25shiqian// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
80dd4a17bc20377d250ed116b1083d851adbe45f25shiqianconst DWORD kInvalidFileAttributes = 0xffffffff;
81733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# else
824b6829f0d28990dd645e16386eb226d0f10c8731shiqianconst char kCurrentDirectoryString[] = ".\\";
83733a54a398766289b74cf3daebe083d7115cf388zhanyong.wan# endif  // GTEST_OS_WINDOWS_MOBILE
844b6829f0d28990dd645e16386eb226d0f10c8731shiqian#else
854b6829f0d28990dd645e16386eb226d0f10c8731shiqianconst char kPathSeparator = '/';
864b6829f0d28990dd645e16386eb226d0f10c8731shiqianconst char kCurrentDirectoryString[] = "./";
874b6829f0d28990dd645e16386eb226d0f10c8731shiqian#endif  // GTEST_OS_WINDOWS
884b6829f0d28990dd645e16386eb226d0f10c8731shiqian
898236131e25705a809d496672a3819e1741166c4bzhanyong.wan// Returns whether the given character is a valid path separator.
908236131e25705a809d496672a3819e1741166c4bzhanyong.wanstatic bool IsPathSeparator(char c) {
918236131e25705a809d496672a3819e1741166c4bzhanyong.wan#if GTEST_HAS_ALT_PATH_SEP_
928236131e25705a809d496672a3819e1741166c4bzhanyong.wan  return (c == kPathSeparator) || (c == kAlternatePathSeparator);
938236131e25705a809d496672a3819e1741166c4bzhanyong.wan#else
948236131e25705a809d496672a3819e1741166c4bzhanyong.wan  return c == kPathSeparator;
958236131e25705a809d496672a3819e1741166c4bzhanyong.wan#endif
968236131e25705a809d496672a3819e1741166c4bzhanyong.wan}
978236131e25705a809d496672a3819e1741166c4bzhanyong.wan
98c3b4de35a18a1f011e8009d4d794f787f7e4e0c1shiqian// Returns the current working directory, or "" if unsuccessful.
99c3b4de35a18a1f011e8009d4d794f787f7e4e0c1shiqianFilePath FilePath::GetCurrentDir() {
100f0d7f455d0ba1b1da1891c3ee54961a162e8fbc4billydonahue@google.com#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
101fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan  // Windows CE doesn't have a current directory, so we just return
102fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan  // something reasonable.
103c3b4de35a18a1f011e8009d4d794f787f7e4e0c1shiqian  return FilePath(kCurrentDirectoryString);
1044cd62602913a032a7aec091d4c8055ff9af95e37zhanyong.wan#elif GTEST_OS_WINDOWS
10598efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
106c3b4de35a18a1f011e8009d4d794f787f7e4e0c1shiqian  return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
107c3b4de35a18a1f011e8009d4d794f787f7e4e0c1shiqian#else
10898efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
1094650552ff637bb44ecf7784060091cbed3252211kosak@google.com  char* result = getcwd(cwd, sizeof(cwd));
1104650552ff637bb44ecf7784060091cbed3252211kosak@google.com# if GTEST_OS_NACL
1114650552ff637bb44ecf7784060091cbed3252211kosak@google.com  // getcwd will likely fail in NaCl due to the sandbox, so return something
1124650552ff637bb44ecf7784060091cbed3252211kosak@google.com  // reasonable. The user may have provided a shim implementation for getcwd,
1134650552ff637bb44ecf7784060091cbed3252211kosak@google.com  // however, so fallback only when failure is detected.
1144650552ff637bb44ecf7784060091cbed3252211kosak@google.com  return FilePath(result == NULL ? kCurrentDirectoryString : cwd);
1154650552ff637bb44ecf7784060091cbed3252211kosak@google.com# endif  // GTEST_OS_NACL
1164650552ff637bb44ecf7784060091cbed3252211kosak@google.com  return FilePath(result == NULL ? "" : cwd);
117fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#endif  // GTEST_OS_WINDOWS_MOBILE
118c3b4de35a18a1f011e8009d4d794f787f7e4e0c1shiqian}
119c3b4de35a18a1f011e8009d4d794f787f7e4e0c1shiqian
1204b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Returns a copy of the FilePath with the case-insensitive extension removed.
1214b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
1224b6829f0d28990dd645e16386eb226d0f10c8731shiqian// FilePath("dir/file"). If a case-insensitive extension is not
1234b6829f0d28990dd645e16386eb226d0f10c8731shiqian// found, returns a copy of the original FilePath.
1244b6829f0d28990dd645e16386eb226d0f10c8731shiqianFilePath FilePath::RemoveExtension(const char* extension) const {
12503c314931649a999b0cf5deb0a434a1009157416jgm@google.com  const std::string dot_extension = std::string(".") + extension;
12603c314931649a999b0cf5deb0a434a1009157416jgm@google.com  if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
12703c314931649a999b0cf5deb0a434a1009157416jgm@google.com    return FilePath(pathname_.substr(
12803c314931649a999b0cf5deb0a434a1009157416jgm@google.com        0, pathname_.length() - dot_extension.length()));
1294b6829f0d28990dd645e16386eb226d0f10c8731shiqian  }
1304b6829f0d28990dd645e16386eb226d0f10c8731shiqian  return *this;
1314b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
1324b6829f0d28990dd645e16386eb226d0f10c8731shiqian
1338236131e25705a809d496672a3819e1741166c4bzhanyong.wan// Returns a pointer to the last occurence of a valid path separator in
1348236131e25705a809d496672a3819e1741166c4bzhanyong.wan// the FilePath. On Windows, for example, both '/' and '\' are valid path
1358236131e25705a809d496672a3819e1741166c4bzhanyong.wan// separators. Returns NULL if no path separator was found.
1368236131e25705a809d496672a3819e1741166c4bzhanyong.wanconst char* FilePath::FindLastPathSeparator() const {
1378236131e25705a809d496672a3819e1741166c4bzhanyong.wan  const char* const last_sep = strrchr(c_str(), kPathSeparator);
1388236131e25705a809d496672a3819e1741166c4bzhanyong.wan#if GTEST_HAS_ALT_PATH_SEP_
1398236131e25705a809d496672a3819e1741166c4bzhanyong.wan  const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
1408236131e25705a809d496672a3819e1741166c4bzhanyong.wan  // Comparing two pointers of which only one is NULL is undefined.
1418236131e25705a809d496672a3819e1741166c4bzhanyong.wan  if (last_alt_sep != NULL &&
1428236131e25705a809d496672a3819e1741166c4bzhanyong.wan      (last_sep == NULL || last_alt_sep > last_sep)) {
1438236131e25705a809d496672a3819e1741166c4bzhanyong.wan    return last_alt_sep;
1448236131e25705a809d496672a3819e1741166c4bzhanyong.wan  }
1458236131e25705a809d496672a3819e1741166c4bzhanyong.wan#endif
1468236131e25705a809d496672a3819e1741166c4bzhanyong.wan  return last_sep;
1478236131e25705a809d496672a3819e1741166c4bzhanyong.wan}
1488236131e25705a809d496672a3819e1741166c4bzhanyong.wan
1494b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Returns a copy of the FilePath with the directory part removed.
1504b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Example: FilePath("path/to/file").RemoveDirectoryName() returns
1514b6829f0d28990dd645e16386eb226d0f10c8731shiqian// FilePath("file"). If there is no directory part ("just_a_file"), it returns
1524b6829f0d28990dd645e16386eb226d0f10c8731shiqian// the FilePath unmodified. If there is no file part ("just_a_dir/") it
1534b6829f0d28990dd645e16386eb226d0f10c8731shiqian// returns an empty FilePath ("").
1544b6829f0d28990dd645e16386eb226d0f10c8731shiqian// On Windows platform, '\' is the path separator, otherwise it is '/'.
1554b6829f0d28990dd645e16386eb226d0f10c8731shiqianFilePath FilePath::RemoveDirectoryName() const {
1568236131e25705a809d496672a3819e1741166c4bzhanyong.wan  const char* const last_sep = FindLastPathSeparator();
15703c314931649a999b0cf5deb0a434a1009157416jgm@google.com  return last_sep ? FilePath(last_sep + 1) : *this;
1584b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
1594b6829f0d28990dd645e16386eb226d0f10c8731shiqian
1604b6829f0d28990dd645e16386eb226d0f10c8731shiqian// RemoveFileName returns the directory path with the filename removed.
1614b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
1624b6829f0d28990dd645e16386eb226d0f10c8731shiqian// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
1634b6829f0d28990dd645e16386eb226d0f10c8731shiqian// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
1644b6829f0d28990dd645e16386eb226d0f10c8731shiqian// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
1654b6829f0d28990dd645e16386eb226d0f10c8731shiqian// On Windows platform, '\' is the path separator, otherwise it is '/'.
1664b6829f0d28990dd645e16386eb226d0f10c8731shiqianFilePath FilePath::RemoveFileName() const {
1678236131e25705a809d496672a3819e1741166c4bzhanyong.wan  const char* const last_sep = FindLastPathSeparator();
16803c314931649a999b0cf5deb0a434a1009157416jgm@google.com  std::string dir;
16998efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  if (last_sep) {
17003c314931649a999b0cf5deb0a434a1009157416jgm@google.com    dir = std::string(c_str(), last_sep + 1 - c_str());
17198efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  } else {
17298efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan    dir = kCurrentDirectoryString;
17398efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  }
17498efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  return FilePath(dir);
1754b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
1764b6829f0d28990dd645e16386eb226d0f10c8731shiqian
1774b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Helper functions for naming files in a directory for xml output.
1784b6829f0d28990dd645e16386eb226d0f10c8731shiqian
1794b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Given directory = "dir", base_name = "test", number = 0,
1804b6829f0d28990dd645e16386eb226d0f10c8731shiqian// extension = "xml", returns "dir/test.xml". If number is greater
1814b6829f0d28990dd645e16386eb226d0f10c8731shiqian// than zero (e.g., 12), returns "dir/test_12.xml".
1824b6829f0d28990dd645e16386eb226d0f10c8731shiqian// On Windows platform, uses \ as the separator rather than /.
1834b6829f0d28990dd645e16386eb226d0f10c8731shiqianFilePath FilePath::MakeFileName(const FilePath& directory,
1844b6829f0d28990dd645e16386eb226d0f10c8731shiqian                                const FilePath& base_name,
1854b6829f0d28990dd645e16386eb226d0f10c8731shiqian                                int number,
1864b6829f0d28990dd645e16386eb226d0f10c8731shiqian                                const char* extension) {
18703c314931649a999b0cf5deb0a434a1009157416jgm@google.com  std::string file;
18898efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  if (number == 0) {
18903c314931649a999b0cf5deb0a434a1009157416jgm@google.com    file = base_name.string() + "." + extension;
19098efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  } else {
1913b8388d9490a64a47ed8cbdab2021935b1b2c76ckosak@google.com    file = base_name.string() + "_" + StreamableToString(number)
19203c314931649a999b0cf5deb0a434a1009157416jgm@google.com        + "." + extension;
19398efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  }
19498efcc49448a78cae3af3ed793a3ad6927620fc4zhanyong.wan  return ConcatPaths(directory, FilePath(file));
195e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan}
196e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan
197e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
198e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan// On Windows, uses \ as the separator rather than /.
199e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wanFilePath FilePath::ConcatPaths(const FilePath& directory,
200e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan                               const FilePath& relative_path) {
201e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan  if (directory.IsEmpty())
202e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan    return relative_path;
203e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan  const FilePath dir(directory.RemoveTrailingPathSeparator());
20403c314931649a999b0cf5deb0a434a1009157416jgm@google.com  return FilePath(dir.string() + kPathSeparator + relative_path.string());
2054b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
2064b6829f0d28990dd645e16386eb226d0f10c8731shiqian
2074b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Returns true if pathname describes something findable in the file-system,
2084b6829f0d28990dd645e16386eb226d0f10c8731shiqian// either a file, directory, or whatever.
2094b6829f0d28990dd645e16386eb226d0f10c8731shiqianbool FilePath::FileOrDirectoryExists() const {
210fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#if GTEST_OS_WINDOWS_MOBILE
211dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
212dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  const DWORD attributes = GetFileAttributes(unicode);
213dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  delete [] unicode;
214dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  return attributes != kInvalidFileAttributes;
2154b6829f0d28990dd645e16386eb226d0f10c8731shiqian#else
216c7f60f1514013d57a624c3a2966709998678f24bzhanyong.wan  posix::StatStruct file_stat;
217c7f60f1514013d57a624c3a2966709998678f24bzhanyong.wan  return posix::Stat(pathname_.c_str(), &file_stat) == 0;
218fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#endif  // GTEST_OS_WINDOWS_MOBILE
2194b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
2204b6829f0d28990dd645e16386eb226d0f10c8731shiqian
2214b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Returns true if pathname describes a directory in the file-system
2224b6829f0d28990dd645e16386eb226d0f10c8731shiqian// that exists.
2234b6829f0d28990dd645e16386eb226d0f10c8731shiqianbool FilePath::DirectoryExists() const {
2244b6829f0d28990dd645e16386eb226d0f10c8731shiqian  bool result = false;
2254cd62602913a032a7aec091d4c8055ff9af95e37zhanyong.wan#if GTEST_OS_WINDOWS
226f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  // Don't strip off trailing separator if path is a root directory on
227f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  // Windows (like "C:\\").
228f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  const FilePath& path(IsRootDirectory() ? *this :
229f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian                                           RemoveTrailingPathSeparator());
230a49bf25b24dd239a9da88e783f037d817a6287b0zhanyong.wan#else
231a49bf25b24dd239a9da88e783f037d817a6287b0zhanyong.wan  const FilePath& path(*this);
232a49bf25b24dd239a9da88e783f037d817a6287b0zhanyong.wan#endif
233a49bf25b24dd239a9da88e783f037d817a6287b0zhanyong.wan
234fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#if GTEST_OS_WINDOWS_MOBILE
235f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
236dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  const DWORD attributes = GetFileAttributes(unicode);
237dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  delete [] unicode;
238dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  if ((attributes != kInvalidFileAttributes) &&
239dd4a17bc20377d250ed116b1083d851adbe45f25shiqian      (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
240dd4a17bc20377d250ed116b1083d851adbe45f25shiqian    result = true;
241dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  }
242dd4a17bc20377d250ed116b1083d851adbe45f25shiqian#else
243c7f60f1514013d57a624c3a2966709998678f24bzhanyong.wan  posix::StatStruct file_stat;
244c7f60f1514013d57a624c3a2966709998678f24bzhanyong.wan  result = posix::Stat(path.c_str(), &file_stat) == 0 &&
245a49bf25b24dd239a9da88e783f037d817a6287b0zhanyong.wan      posix::IsDir(file_stat);
246fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#endif  // GTEST_OS_WINDOWS_MOBILE
247a49bf25b24dd239a9da88e783f037d817a6287b0zhanyong.wan
2484b6829f0d28990dd645e16386eb226d0f10c8731shiqian  return result;
2494b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
2504b6829f0d28990dd645e16386eb226d0f10c8731shiqian
251f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian// Returns true if pathname describes a root directory. (Windows has one
252f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian// root directory per disk drive.)
253f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqianbool FilePath::IsRootDirectory() const {
2544cd62602913a032a7aec091d4c8055ff9af95e37zhanyong.wan#if GTEST_OS_WINDOWS
255e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan  // TODO(wan@google.com): on Windows a network share like
256e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan  // \\server\share can be a root directory, although it cannot be the
257e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan  // current directory.  Handle this properly.
25889be5763249cbab785abfa310fb1cd6b5e9c4adfzhanyong.wan  return pathname_.length() == 3 && IsAbsolutePath();
259e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan#else
2608236131e25705a809d496672a3819e1741166c4bzhanyong.wan  return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
261e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan#endif
262e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan}
263e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan
264e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan// Returns true if pathname describes an absolute path.
265e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wanbool FilePath::IsAbsolutePath() const {
266e5722bdcf1680483a80d97707dd8b97a7c346759zhanyong.wan  const char* const name = pathname_.c_str();
2674cd62602913a032a7aec091d4c8055ff9af95e37zhanyong.wan#if GTEST_OS_WINDOWS
26889be5763249cbab785abfa310fb1cd6b5e9c4adfzhanyong.wan  return pathname_.length() >= 3 &&
269f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian     ((name[0] >= 'a' && name[0] <= 'z') ||
270f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian      (name[0] >= 'A' && name[0] <= 'Z')) &&
271f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian     name[1] == ':' &&
2728236131e25705a809d496672a3819e1741166c4bzhanyong.wan     IsPathSeparator(name[2]);
273f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian#else
2748236131e25705a809d496672a3819e1741166c4bzhanyong.wan  return IsPathSeparator(name[0]);
275f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian#endif
276f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian}
277f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian
2784b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Returns a pathname for a file that does not currently exist. The pathname
2794b6829f0d28990dd645e16386eb226d0f10c8731shiqian// will be directory/base_name.extension or
2804b6829f0d28990dd645e16386eb226d0f10c8731shiqian// directory/base_name_<number>.extension if directory/base_name.extension
2814b6829f0d28990dd645e16386eb226d0f10c8731shiqian// already exists. The number will be incremented until a pathname is found
2824b6829f0d28990dd645e16386eb226d0f10c8731shiqian// that does not already exist.
2834b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
2844b6829f0d28990dd645e16386eb226d0f10c8731shiqian// There could be a race condition if two or more processes are calling this
2854b6829f0d28990dd645e16386eb226d0f10c8731shiqian// function at the same time -- they could both pick the same filename.
2864b6829f0d28990dd645e16386eb226d0f10c8731shiqianFilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
2874b6829f0d28990dd645e16386eb226d0f10c8731shiqian                                          const FilePath& base_name,
2884b6829f0d28990dd645e16386eb226d0f10c8731shiqian                                          const char* extension) {
2894b6829f0d28990dd645e16386eb226d0f10c8731shiqian  FilePath full_pathname;
2904b6829f0d28990dd645e16386eb226d0f10c8731shiqian  int number = 0;
2914b6829f0d28990dd645e16386eb226d0f10c8731shiqian  do {
2924b6829f0d28990dd645e16386eb226d0f10c8731shiqian    full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
2934b6829f0d28990dd645e16386eb226d0f10c8731shiqian  } while (full_pathname.FileOrDirectoryExists());
2944b6829f0d28990dd645e16386eb226d0f10c8731shiqian  return full_pathname;
2954b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
2964b6829f0d28990dd645e16386eb226d0f10c8731shiqian
2974b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Returns true if FilePath ends with a path separator, which indicates that
2984b6829f0d28990dd645e16386eb226d0f10c8731shiqian// it is intended to represent a directory. Returns false otherwise.
2994b6829f0d28990dd645e16386eb226d0f10c8731shiqian// This does NOT check that a directory (or file) actually exists.
3004b6829f0d28990dd645e16386eb226d0f10c8731shiqianbool FilePath::IsDirectory() const {
3018236131e25705a809d496672a3819e1741166c4bzhanyong.wan  return !pathname_.empty() &&
3028236131e25705a809d496672a3819e1741166c4bzhanyong.wan         IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
3034b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
3044b6829f0d28990dd645e16386eb226d0f10c8731shiqian
3054b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Create directories so that path exists. Returns true if successful or if
3064b6829f0d28990dd645e16386eb226d0f10c8731shiqian// the directories already exist; returns false if unable to create directories
3074b6829f0d28990dd645e16386eb226d0f10c8731shiqian// for any reason.
3084b6829f0d28990dd645e16386eb226d0f10c8731shiqianbool FilePath::CreateDirectoriesRecursively() const {
3094b6829f0d28990dd645e16386eb226d0f10c8731shiqian  if (!this->IsDirectory()) {
3104b6829f0d28990dd645e16386eb226d0f10c8731shiqian    return false;
3114b6829f0d28990dd645e16386eb226d0f10c8731shiqian  }
3124b6829f0d28990dd645e16386eb226d0f10c8731shiqian
31389be5763249cbab785abfa310fb1cd6b5e9c4adfzhanyong.wan  if (pathname_.length() == 0 || this->DirectoryExists()) {
3144b6829f0d28990dd645e16386eb226d0f10c8731shiqian    return true;
3154b6829f0d28990dd645e16386eb226d0f10c8731shiqian  }
3164b6829f0d28990dd645e16386eb226d0f10c8731shiqian
3174b6829f0d28990dd645e16386eb226d0f10c8731shiqian  const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
3184b6829f0d28990dd645e16386eb226d0f10c8731shiqian  return parent.CreateDirectoriesRecursively() && this->CreateFolder();
3194b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
3204b6829f0d28990dd645e16386eb226d0f10c8731shiqian
3214b6829f0d28990dd645e16386eb226d0f10c8731shiqian// Create the directory so that path exists. Returns true if successful or
3224b6829f0d28990dd645e16386eb226d0f10c8731shiqian// if the directory already exists; returns false if unable to create the
3234b6829f0d28990dd645e16386eb226d0f10c8731shiqian// directory for any reason, including if the parent directory does not
3244b6829f0d28990dd645e16386eb226d0f10c8731shiqian// exist. Not named "CreateDirectory" because that's a macro on Windows.
3254b6829f0d28990dd645e16386eb226d0f10c8731shiqianbool FilePath::CreateFolder() const {
326fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#if GTEST_OS_WINDOWS_MOBILE
327dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  FilePath removed_sep(this->RemoveTrailingPathSeparator());
328dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
329dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  int result = CreateDirectory(unicode, NULL) ? 0 : -1;
330dd4a17bc20377d250ed116b1083d851adbe45f25shiqian  delete [] unicode;
331fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#elif GTEST_OS_WINDOWS
3324b6829f0d28990dd645e16386eb226d0f10c8731shiqian  int result = _mkdir(pathname_.c_str());
3334b6829f0d28990dd645e16386eb226d0f10c8731shiqian#else
3344b6829f0d28990dd645e16386eb226d0f10c8731shiqian  int result = mkdir(pathname_.c_str(), 0777);
335fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan#endif  // GTEST_OS_WINDOWS_MOBILE
336fff033497b70e96a5dcadb6ba9570c12b5921d74zhanyong.wan
3374b6829f0d28990dd645e16386eb226d0f10c8731shiqian  if (result == -1) {
3384b6829f0d28990dd645e16386eb226d0f10c8731shiqian    return this->DirectoryExists();  // An error is OK if the directory exists.
3394b6829f0d28990dd645e16386eb226d0f10c8731shiqian  }
3404b6829f0d28990dd645e16386eb226d0f10c8731shiqian  return true;  // No error.
3414b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
3424b6829f0d28990dd645e16386eb226d0f10c8731shiqian
3434b6829f0d28990dd645e16386eb226d0f10c8731shiqian// If input name has a trailing separator character, remove it and return the
3444b6829f0d28990dd645e16386eb226d0f10c8731shiqian// name, otherwise return the name string unmodified.
3454b6829f0d28990dd645e16386eb226d0f10c8731shiqian// On Windows platform, uses \ as the separator, other platforms use /.
3464b6829f0d28990dd645e16386eb226d0f10c8731shiqianFilePath FilePath::RemoveTrailingPathSeparator() const {
3478236131e25705a809d496672a3819e1741166c4bzhanyong.wan  return IsDirectory()
34803c314931649a999b0cf5deb0a434a1009157416jgm@google.com      ? FilePath(pathname_.substr(0, pathname_.length() - 1))
3494b6829f0d28990dd645e16386eb226d0f10c8731shiqian      : *this;
3504b6829f0d28990dd645e16386eb226d0f10c8731shiqian}
3514b6829f0d28990dd645e16386eb226d0f10c8731shiqian
352673a0cb9079f8f37bd61588a3160e12daf70ec44vladlosev// Removes any redundant separators that might be in the pathname.
353f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
354f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian// redundancies that might be in a pathname involving "." or "..".
355673a0cb9079f8f37bd61588a3160e12daf70ec44vladlosev// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
356f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqianvoid FilePath::Normalize() {
357f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  if (pathname_.c_str() == NULL) {
358f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian    pathname_ = "";
359f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian    return;
360f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  }
361f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  const char* src = pathname_.c_str();
36289be5763249cbab785abfa310fb1cd6b5e9c4adfzhanyong.wan  char* const dest = new char[pathname_.length() + 1];
363f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  char* dest_ptr = dest;
36489be5763249cbab785abfa310fb1cd6b5e9c4adfzhanyong.wan  memset(dest_ptr, 0, pathname_.length() + 1);
365f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian
366f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  while (*src != '\0') {
3678236131e25705a809d496672a3819e1741166c4bzhanyong.wan    *dest_ptr = *src;
3688236131e25705a809d496672a3819e1741166c4bzhanyong.wan    if (!IsPathSeparator(*src)) {
369f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian      src++;
3708236131e25705a809d496672a3819e1741166c4bzhanyong.wan    } else {
3718236131e25705a809d496672a3819e1741166c4bzhanyong.wan#if GTEST_HAS_ALT_PATH_SEP_
3728236131e25705a809d496672a3819e1741166c4bzhanyong.wan      if (*dest_ptr == kAlternatePathSeparator) {
3738236131e25705a809d496672a3819e1741166c4bzhanyong.wan        *dest_ptr = kPathSeparator;
3748236131e25705a809d496672a3819e1741166c4bzhanyong.wan      }
3758236131e25705a809d496672a3819e1741166c4bzhanyong.wan#endif
3768236131e25705a809d496672a3819e1741166c4bzhanyong.wan      while (IsPathSeparator(*src))
377f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian        src++;
3788236131e25705a809d496672a3819e1741166c4bzhanyong.wan    }
3798236131e25705a809d496672a3819e1741166c4bzhanyong.wan    dest_ptr++;
380f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  }
381f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  *dest_ptr = '\0';
382f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  pathname_ = dest;
383f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian  delete[] dest;
384f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian}
385f0e809a3c9946e99595d4faeb0a16bdc2ca9ffd5shiqian
3864b6829f0d28990dd645e16386eb226d0f10c8731shiqian}  // namespace internal
3874b6829f0d28990dd645e16386eb226d0f10c8731shiqian}  // namespace testing
388