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