media/webrtc/trunk/testing/gtest/src/gtest-filepath.cc

Wed, 31 Dec 2014 07:53:36 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:53:36 +0100
branch
TOR_BUG_3246
changeset 5
4ab42b5ab56c
permissions
-rw-r--r--

Correct small whitespace inconsistency, lost while renaming variables.

     1 // Copyright 2008, Google Inc.
     2 // All rights reserved.
     3 //
     4 // Redistribution and use in source and binary forms, with or without
     5 // modification, are permitted provided that the following conditions are
     6 // met:
     7 //
     8 //     * Redistributions of source code must retain the above copyright
     9 // notice, this list of conditions and the following disclaimer.
    10 //     * Redistributions in binary form must reproduce the above
    11 // copyright notice, this list of conditions and the following disclaimer
    12 // in the documentation and/or other materials provided with the
    13 // distribution.
    14 //     * Neither the name of Google Inc. nor the names of its
    15 // contributors may be used to endorse or promote products derived from
    16 // this software without specific prior written permission.
    17 //
    18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    29 //
    30 // Authors: keith.ray@gmail.com (Keith Ray)
    32 #include "gtest/internal/gtest-filepath.h"
    33 #include "gtest/internal/gtest-port.h"
    35 #include <stdlib.h>
    37 #if GTEST_OS_WINDOWS_MOBILE
    38 # include <windows.h>
    39 #elif GTEST_OS_WINDOWS
    40 # include <direct.h>
    41 # include <io.h>
    42 #elif GTEST_OS_SYMBIAN
    43 // Symbian OpenC has PATH_MAX in sys/syslimits.h
    44 # include <sys/syslimits.h>
    45 #else
    46 # include <limits.h>
    47 # include <climits>  // Some Linux distributions define PATH_MAX here.
    48 #endif  // GTEST_OS_WINDOWS_MOBILE
    50 #if GTEST_OS_WINDOWS
    51 # define GTEST_PATH_MAX_ _MAX_PATH
    52 #elif defined(PATH_MAX)
    53 # define GTEST_PATH_MAX_ PATH_MAX
    54 #elif defined(_XOPEN_PATH_MAX)
    55 # define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
    56 #else
    57 # define GTEST_PATH_MAX_ _POSIX_PATH_MAX
    58 #endif  // GTEST_OS_WINDOWS
    60 #include "gtest/internal/gtest-string.h"
    62 namespace testing {
    63 namespace internal {
    65 #if GTEST_OS_WINDOWS
    66 // On Windows, '\\' is the standard path separator, but many tools and the
    67 // Windows API also accept '/' as an alternate path separator. Unless otherwise
    68 // noted, a file path can contain either kind of path separators, or a mixture
    69 // of them.
    70 const char kPathSeparator = '\\';
    71 const char kAlternatePathSeparator = '/';
    72 const char kPathSeparatorString[] = "\\";
    73 const char kAlternatePathSeparatorString[] = "/";
    74 # if GTEST_OS_WINDOWS_MOBILE
    75 // Windows CE doesn't have a current directory. You should not use
    76 // the current directory in tests on Windows CE, but this at least
    77 // provides a reasonable fallback.
    78 const char kCurrentDirectoryString[] = "\\";
    79 // Windows CE doesn't define INVALID_FILE_ATTRIBUTES
    80 const DWORD kInvalidFileAttributes = 0xffffffff;
    81 # else
    82 const char kCurrentDirectoryString[] = ".\\";
    83 # endif  // GTEST_OS_WINDOWS_MOBILE
    84 #else
    85 const char kPathSeparator = '/';
    86 const char kPathSeparatorString[] = "/";
    87 const char kCurrentDirectoryString[] = "./";
    88 #endif  // GTEST_OS_WINDOWS
    90 // Returns whether the given character is a valid path separator.
    91 static bool IsPathSeparator(char c) {
    92 #if GTEST_HAS_ALT_PATH_SEP_
    93   return (c == kPathSeparator) || (c == kAlternatePathSeparator);
    94 #else
    95   return c == kPathSeparator;
    96 #endif
    97 }
    99 // Returns the current working directory, or "" if unsuccessful.
   100 FilePath FilePath::GetCurrentDir() {
   101 #if GTEST_OS_WINDOWS_MOBILE
   102   // Windows CE doesn't have a current directory, so we just return
   103   // something reasonable.
   104   return FilePath(kCurrentDirectoryString);
   105 #elif GTEST_OS_WINDOWS
   106   char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
   107   return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
   108 #else
   109   char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
   110   return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
   111 #endif  // GTEST_OS_WINDOWS_MOBILE
   112 }
   114 // Returns a copy of the FilePath with the case-insensitive extension removed.
   115 // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
   116 // FilePath("dir/file"). If a case-insensitive extension is not
   117 // found, returns a copy of the original FilePath.
   118 FilePath FilePath::RemoveExtension(const char* extension) const {
   119   String dot_extension(String::Format(".%s", extension));
   120   if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
   121     return FilePath(String(pathname_.c_str(), pathname_.length() - 4));
   122   }
   123   return *this;
   124 }
   126 // Returns a pointer to the last occurence of a valid path separator in
   127 // the FilePath. On Windows, for example, both '/' and '\' are valid path
   128 // separators. Returns NULL if no path separator was found.
   129 const char* FilePath::FindLastPathSeparator() const {
   130   const char* const last_sep = strrchr(c_str(), kPathSeparator);
   131 #if GTEST_HAS_ALT_PATH_SEP_
   132   const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
   133   // Comparing two pointers of which only one is NULL is undefined.
   134   if (last_alt_sep != NULL &&
   135       (last_sep == NULL || last_alt_sep > last_sep)) {
   136     return last_alt_sep;
   137   }
   138 #endif
   139   return last_sep;
   140 }
   142 // Returns a copy of the FilePath with the directory part removed.
   143 // Example: FilePath("path/to/file").RemoveDirectoryName() returns
   144 // FilePath("file"). If there is no directory part ("just_a_file"), it returns
   145 // the FilePath unmodified. If there is no file part ("just_a_dir/") it
   146 // returns an empty FilePath ("").
   147 // On Windows platform, '\' is the path separator, otherwise it is '/'.
   148 FilePath FilePath::RemoveDirectoryName() const {
   149   const char* const last_sep = FindLastPathSeparator();
   150   return last_sep ? FilePath(String(last_sep + 1)) : *this;
   151 }
   153 // RemoveFileName returns the directory path with the filename removed.
   154 // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
   155 // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
   156 // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
   157 // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
   158 // On Windows platform, '\' is the path separator, otherwise it is '/'.
   159 FilePath FilePath::RemoveFileName() const {
   160   const char* const last_sep = FindLastPathSeparator();
   161   String dir;
   162   if (last_sep) {
   163     dir = String(c_str(), last_sep + 1 - c_str());
   164   } else {
   165     dir = kCurrentDirectoryString;
   166   }
   167   return FilePath(dir);
   168 }
   170 // Helper functions for naming files in a directory for xml output.
   172 // Given directory = "dir", base_name = "test", number = 0,
   173 // extension = "xml", returns "dir/test.xml". If number is greater
   174 // than zero (e.g., 12), returns "dir/test_12.xml".
   175 // On Windows platform, uses \ as the separator rather than /.
   176 FilePath FilePath::MakeFileName(const FilePath& directory,
   177                                 const FilePath& base_name,
   178                                 int number,
   179                                 const char* extension) {
   180   String file;
   181   if (number == 0) {
   182     file = String::Format("%s.%s", base_name.c_str(), extension);
   183   } else {
   184     file = String::Format("%s_%d.%s", base_name.c_str(), number, extension);
   185   }
   186   return ConcatPaths(directory, FilePath(file));
   187 }
   189 // Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
   190 // On Windows, uses \ as the separator rather than /.
   191 FilePath FilePath::ConcatPaths(const FilePath& directory,
   192                                const FilePath& relative_path) {
   193   if (directory.IsEmpty())
   194     return relative_path;
   195   const FilePath dir(directory.RemoveTrailingPathSeparator());
   196   return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator,
   197                                  relative_path.c_str()));
   198 }
   200 // Returns true if pathname describes something findable in the file-system,
   201 // either a file, directory, or whatever.
   202 bool FilePath::FileOrDirectoryExists() const {
   203 #if GTEST_OS_WINDOWS_MOBILE
   204   LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
   205   const DWORD attributes = GetFileAttributes(unicode);
   206   delete [] unicode;
   207   return attributes != kInvalidFileAttributes;
   208 #else
   209   posix::StatStruct file_stat;
   210   return posix::Stat(pathname_.c_str(), &file_stat) == 0;
   211 #endif  // GTEST_OS_WINDOWS_MOBILE
   212 }
   214 // Returns true if pathname describes a directory in the file-system
   215 // that exists.
   216 bool FilePath::DirectoryExists() const {
   217   bool result = false;
   218 #if GTEST_OS_WINDOWS
   219   // Don't strip off trailing separator if path is a root directory on
   220   // Windows (like "C:\\").
   221   const FilePath& path(IsRootDirectory() ? *this :
   222                                            RemoveTrailingPathSeparator());
   223 #else
   224   const FilePath& path(*this);
   225 #endif
   227 #if GTEST_OS_WINDOWS_MOBILE
   228   LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
   229   const DWORD attributes = GetFileAttributes(unicode);
   230   delete [] unicode;
   231   if ((attributes != kInvalidFileAttributes) &&
   232       (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
   233     result = true;
   234   }
   235 #else
   236   posix::StatStruct file_stat;
   237   result = posix::Stat(path.c_str(), &file_stat) == 0 &&
   238       posix::IsDir(file_stat);
   239 #endif  // GTEST_OS_WINDOWS_MOBILE
   241   return result;
   242 }
   244 // Returns true if pathname describes a root directory. (Windows has one
   245 // root directory per disk drive.)
   246 bool FilePath::IsRootDirectory() const {
   247 #if GTEST_OS_WINDOWS
   248   // TODO(wan@google.com): on Windows a network share like
   249   // \\server\share can be a root directory, although it cannot be the
   250   // current directory.  Handle this properly.
   251   return pathname_.length() == 3 && IsAbsolutePath();
   252 #else
   253   return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
   254 #endif
   255 }
   257 // Returns true if pathname describes an absolute path.
   258 bool FilePath::IsAbsolutePath() const {
   259   const char* const name = pathname_.c_str();
   260 #if GTEST_OS_WINDOWS
   261   return pathname_.length() >= 3 &&
   262      ((name[0] >= 'a' && name[0] <= 'z') ||
   263       (name[0] >= 'A' && name[0] <= 'Z')) &&
   264      name[1] == ':' &&
   265      IsPathSeparator(name[2]);
   266 #else
   267   return IsPathSeparator(name[0]);
   268 #endif
   269 }
   271 // Returns a pathname for a file that does not currently exist. The pathname
   272 // will be directory/base_name.extension or
   273 // directory/base_name_<number>.extension if directory/base_name.extension
   274 // already exists. The number will be incremented until a pathname is found
   275 // that does not already exist.
   276 // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
   277 // There could be a race condition if two or more processes are calling this
   278 // function at the same time -- they could both pick the same filename.
   279 FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
   280                                           const FilePath& base_name,
   281                                           const char* extension) {
   282   FilePath full_pathname;
   283   int number = 0;
   284   do {
   285     full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
   286   } while (full_pathname.FileOrDirectoryExists());
   287   return full_pathname;
   288 }
   290 // Returns true if FilePath ends with a path separator, which indicates that
   291 // it is intended to represent a directory. Returns false otherwise.
   292 // This does NOT check that a directory (or file) actually exists.
   293 bool FilePath::IsDirectory() const {
   294   return !pathname_.empty() &&
   295          IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
   296 }
   298 // Create directories so that path exists. Returns true if successful or if
   299 // the directories already exist; returns false if unable to create directories
   300 // for any reason.
   301 bool FilePath::CreateDirectoriesRecursively() const {
   302   if (!this->IsDirectory()) {
   303     return false;
   304   }
   306   if (pathname_.length() == 0 || this->DirectoryExists()) {
   307     return true;
   308   }
   310   const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
   311   return parent.CreateDirectoriesRecursively() && this->CreateFolder();
   312 }
   314 // Create the directory so that path exists. Returns true if successful or
   315 // if the directory already exists; returns false if unable to create the
   316 // directory for any reason, including if the parent directory does not
   317 // exist. Not named "CreateDirectory" because that's a macro on Windows.
   318 bool FilePath::CreateFolder() const {
   319 #if GTEST_OS_WINDOWS_MOBILE
   320   FilePath removed_sep(this->RemoveTrailingPathSeparator());
   321   LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
   322   int result = CreateDirectory(unicode, NULL) ? 0 : -1;
   323   delete [] unicode;
   324 #elif GTEST_OS_WINDOWS
   325   int result = _mkdir(pathname_.c_str());
   326 #else
   327   int result = mkdir(pathname_.c_str(), 0777);
   328 #endif  // GTEST_OS_WINDOWS_MOBILE
   330   if (result == -1) {
   331     return this->DirectoryExists();  // An error is OK if the directory exists.
   332   }
   333   return true;  // No error.
   334 }
   336 // If input name has a trailing separator character, remove it and return the
   337 // name, otherwise return the name string unmodified.
   338 // On Windows platform, uses \ as the separator, other platforms use /.
   339 FilePath FilePath::RemoveTrailingPathSeparator() const {
   340   return IsDirectory()
   341       ? FilePath(String(pathname_.c_str(), pathname_.length() - 1))
   342       : *this;
   343 }
   345 // Removes any redundant separators that might be in the pathname.
   346 // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
   347 // redundancies that might be in a pathname involving "." or "..".
   348 // TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
   349 void FilePath::Normalize() {
   350   if (pathname_.c_str() == NULL) {
   351     pathname_ = "";
   352     return;
   353   }
   354   const char* src = pathname_.c_str();
   355   char* const dest = new char[pathname_.length() + 1];
   356   char* dest_ptr = dest;
   357   memset(dest_ptr, 0, pathname_.length() + 1);
   359   while (*src != '\0') {
   360     *dest_ptr = *src;
   361     if (!IsPathSeparator(*src)) {
   362       src++;
   363     } else {
   364 #if GTEST_HAS_ALT_PATH_SEP_
   365       if (*dest_ptr == kAlternatePathSeparator) {
   366         *dest_ptr = kPathSeparator;
   367       }
   368 #endif
   369       while (IsPathSeparator(*src))
   370         src++;
   371     }
   372     dest_ptr++;
   373   }
   374   *dest_ptr = '\0';
   375   pathname_ = dest;
   376   delete[] dest;
   377 }
   379 }  // namespace internal
   380 }  // namespace testing

mercurial