~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/gtest/src/gtest-filepath.cc

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
#include "gtest/internal/gtest-filepath.h"
31
 
 
32
 
#include <stdlib.h>
33
 
#include "gtest/internal/gtest-port.h"
34
 
#include "gtest/gtest-message.h"
35
 
 
36
 
#if GTEST_OS_WINDOWS_MOBILE
37
 
# include <windows.h>
38
 
#elif GTEST_OS_WINDOWS
39
 
# include <direct.h>
40
 
# include <io.h>
41
 
#else
42
 
# include <limits.h>
43
 
# include <climits>  // Some Linux distributions define PATH_MAX here.
44
 
#endif  // GTEST_OS_WINDOWS_MOBILE
45
 
 
46
 
#include "gtest/internal/gtest-string.h"
47
 
 
48
 
#if GTEST_OS_WINDOWS
49
 
# define GTEST_PATH_MAX_ _MAX_PATH
50
 
#elif defined(PATH_MAX)
51
 
# define GTEST_PATH_MAX_ PATH_MAX
52
 
#elif defined(_XOPEN_PATH_MAX)
53
 
# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
54
 
#else
55
 
# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
56
 
#endif  // GTEST_OS_WINDOWS
57
 
 
58
 
namespace testing {
59
 
namespace internal {
60
 
 
61
 
#if GTEST_OS_WINDOWS
62
 
// On Windows, '\\' is the standard path separator, but many tools and the
63
 
// Windows API also accept '/' as an alternate path separator. Unless otherwise
64
 
// noted, a file path can contain either kind of path separators, or a mixture
65
 
// of them.
66
 
const char kPathSeparator = '\\';
67
 
const char kAlternatePathSeparator = '/';
68
 
const char kAlternatePathSeparatorString[] = "/";
69
 
# if GTEST_OS_WINDOWS_MOBILE
70
 
// Windows CE doesn't have a current directory. You should not use
71
 
// the current directory in tests on Windows CE, but this at least
72
 
// provides a reasonable fallback.
73
 
const char kCurrentDirectoryString[] = "\\";
74
 
// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
75
 
const DWORD kInvalidFileAttributes = 0xffffffff;
76
 
# else
77
 
const char kCurrentDirectoryString[] = ".\\";
78
 
# endif  // GTEST_OS_WINDOWS_MOBILE
79
 
#else
80
 
const char kPathSeparator = '/';
81
 
const char kCurrentDirectoryString[] = "./";
82
 
#endif  // GTEST_OS_WINDOWS
83
 
 
84
 
// Returns whether the given character is a valid path separator.
85
 
static bool IsPathSeparator(char c) {
86
 
#if GTEST_HAS_ALT_PATH_SEP_
87
 
  return (c == kPathSeparator) || (c == kAlternatePathSeparator);
88
 
#else
89
 
  return c == kPathSeparator;
90
 
#endif
91
 
}
92
 
 
93
 
// Returns the current working directory, or "" if unsuccessful.
94
 
FilePath FilePath::GetCurrentDir() {
95
 
#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
96
 
    GTEST_OS_WINDOWS_RT || ARDUINO || defined(ESP_PLATFORM)
97
 
  // These platforms do not have a current directory, so we just return
98
 
  // something reasonable.
99
 
  return FilePath(kCurrentDirectoryString);
100
 
#elif GTEST_OS_WINDOWS
101
 
  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
102
 
  return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd);
103
 
#else
104
 
  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
105
 
  char* result = getcwd(cwd, sizeof(cwd));
106
 
# if GTEST_OS_NACL
107
 
  // getcwd will likely fail in NaCl due to the sandbox, so return something
108
 
  // reasonable. The user may have provided a shim implementation for getcwd,
109
 
  // however, so fallback only when failure is detected.
110
 
  return FilePath(result == nullptr ? kCurrentDirectoryString : cwd);
111
 
# endif  // GTEST_OS_NACL
112
 
  return FilePath(result == nullptr ? "" : cwd);
113
 
#endif  // GTEST_OS_WINDOWS_MOBILE
114
 
}
115
 
 
116
 
// Returns a copy of the FilePath with the case-insensitive extension removed.
117
 
// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
118
 
// FilePath("dir/file"). If a case-insensitive extension is not
119
 
// found, returns a copy of the original FilePath.
120
 
FilePath FilePath::RemoveExtension(const char* extension) const {
121
 
  const std::string dot_extension = std::string(".") + extension;
122
 
  if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
123
 
    return FilePath(pathname_.substr(
124
 
        0, pathname_.length() - dot_extension.length()));
125
 
  }
126
 
  return *this;
127
 
}
128
 
 
129
 
// Returns a pointer to the last occurrence of a valid path separator in
130
 
// the FilePath. On Windows, for example, both '/' and '\' are valid path
131
 
// separators. Returns NULL if no path separator was found.
132
 
const char* FilePath::FindLastPathSeparator() const {
133
 
  const char* const last_sep = strrchr(c_str(), kPathSeparator);
134
 
#if GTEST_HAS_ALT_PATH_SEP_
135
 
  const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
136
 
  // Comparing two pointers of which only one is NULL is undefined.
137
 
  if (last_alt_sep != nullptr &&
138
 
      (last_sep == nullptr || last_alt_sep > last_sep)) {
139
 
    return last_alt_sep;
140
 
  }
141
 
#endif
142
 
  return last_sep;
143
 
}
144
 
 
145
 
// Returns a copy of the FilePath with the directory part removed.
146
 
// Example: FilePath("path/to/file").RemoveDirectoryName() returns
147
 
// FilePath("file"). If there is no directory part ("just_a_file"), it returns
148
 
// the FilePath unmodified. If there is no file part ("just_a_dir/") it
149
 
// returns an empty FilePath ("").
150
 
// On Windows platform, '\' is the path separator, otherwise it is '/'.
151
 
FilePath FilePath::RemoveDirectoryName() const {
152
 
  const char* const last_sep = FindLastPathSeparator();
153
 
  return last_sep ? FilePath(last_sep + 1) : *this;
154
 
}
155
 
 
156
 
// RemoveFileName returns the directory path with the filename removed.
157
 
// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
158
 
// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
159
 
// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
160
 
// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
161
 
// On Windows platform, '\' is the path separator, otherwise it is '/'.
162
 
FilePath FilePath::RemoveFileName() const {
163
 
  const char* const last_sep = FindLastPathSeparator();
164
 
  std::string dir;
165
 
  if (last_sep) {
166
 
    dir = std::string(c_str(), static_cast<size_t>(last_sep + 1 - c_str()));
167
 
  } else {
168
 
    dir = kCurrentDirectoryString;
169
 
  }
170
 
  return FilePath(dir);
171
 
}
172
 
 
173
 
// Helper functions for naming files in a directory for xml output.
174
 
 
175
 
// Given directory = "dir", base_name = "test", number = 0,
176
 
// extension = "xml", returns "dir/test.xml". If number is greater
177
 
// than zero (e.g., 12), returns "dir/test_12.xml".
178
 
// On Windows platform, uses \ as the separator rather than /.
179
 
FilePath FilePath::MakeFileName(const FilePath& directory,
180
 
                                const FilePath& base_name,
181
 
                                int number,
182
 
                                const char* extension) {
183
 
  std::string file;
184
 
  if (number == 0) {
185
 
    file = base_name.string() + "." + extension;
186
 
  } else {
187
 
    file = base_name.string() + "_" + StreamableToString(number)
188
 
        + "." + extension;
189
 
  }
190
 
  return ConcatPaths(directory, FilePath(file));
191
 
}
192
 
 
193
 
// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
194
 
// On Windows, uses \ as the separator rather than /.
195
 
FilePath FilePath::ConcatPaths(const FilePath& directory,
196
 
                               const FilePath& relative_path) {
197
 
  if (directory.IsEmpty())
198
 
    return relative_path;
199
 
  const FilePath dir(directory.RemoveTrailingPathSeparator());
200
 
  return FilePath(dir.string() + kPathSeparator + relative_path.string());
201
 
}
202
 
 
203
 
// Returns true if pathname describes something findable in the file-system,
204
 
// either a file, directory, or whatever.
205
 
bool FilePath::FileOrDirectoryExists() const {
206
 
#if GTEST_OS_WINDOWS_MOBILE
207
 
  LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
208
 
  const DWORD attributes = GetFileAttributes(unicode);
209
 
  delete [] unicode;
210
 
  return attributes != kInvalidFileAttributes;
211
 
#else
212
 
  posix::StatStruct file_stat;
213
 
  return posix::Stat(pathname_.c_str(), &file_stat) == 0;
214
 
#endif  // GTEST_OS_WINDOWS_MOBILE
215
 
}
216
 
 
217
 
// Returns true if pathname describes a directory in the file-system
218
 
// that exists.
219
 
bool FilePath::DirectoryExists() const {
220
 
  bool result = false;
221
 
#if GTEST_OS_WINDOWS
222
 
  // Don't strip off trailing separator if path is a root directory on
223
 
  // Windows (like "C:\\").
224
 
  const FilePath& path(IsRootDirectory() ? *this :
225
 
                                           RemoveTrailingPathSeparator());
226
 
#else
227
 
  const FilePath& path(*this);
228
 
#endif
229
 
 
230
 
#if GTEST_OS_WINDOWS_MOBILE
231
 
  LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
232
 
  const DWORD attributes = GetFileAttributes(unicode);
233
 
  delete [] unicode;
234
 
  if ((attributes != kInvalidFileAttributes) &&
235
 
      (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
236
 
    result = true;
237
 
  }
238
 
#else
239
 
  posix::StatStruct file_stat;
240
 
  result = posix::Stat(path.c_str(), &file_stat) == 0 &&
241
 
      posix::IsDir(file_stat);
242
 
#endif  // GTEST_OS_WINDOWS_MOBILE
243
 
 
244
 
  return result;
245
 
}
246
 
 
247
 
// Returns true if pathname describes a root directory. (Windows has one
248
 
// root directory per disk drive.)
249
 
bool FilePath::IsRootDirectory() const {
250
 
#if GTEST_OS_WINDOWS
251
 
  return pathname_.length() == 3 && IsAbsolutePath();
252
 
#else
253
 
  return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
254
 
#endif
255
 
}
256
 
 
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
 
}
270
 
 
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
 
}
289
 
 
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
 
}
297
 
 
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
 
  }
305
 
 
306
 
  if (pathname_.length() == 0 || this->DirectoryExists()) {
307
 
    return true;
308
 
  }
309
 
 
310
 
  const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
311
 
  return parent.CreateDirectoriesRecursively() && this->CreateFolder();
312
 
}
313
 
 
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, nullptr) ? 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
329
 
 
330
 
  if (result == -1) {
331
 
    return this->DirectoryExists();  // An error is OK if the directory exists.
332
 
  }
333
 
  return true;  // No error.
334
 
}
335
 
 
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(pathname_.substr(0, pathname_.length() - 1))
342
 
      : *this;
343
 
}
344
 
 
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
 
void FilePath::Normalize() {
349
 
  if (pathname_.c_str() == nullptr) {
350
 
    pathname_ = "";
351
 
    return;
352
 
  }
353
 
  const char* src = pathname_.c_str();
354
 
  char* const dest = new char[pathname_.length() + 1];
355
 
  char* dest_ptr = dest;
356
 
  memset(dest_ptr, 0, pathname_.length() + 1);
357
 
 
358
 
  while (*src != '\0') {
359
 
    *dest_ptr = *src;
360
 
    if (!IsPathSeparator(*src)) {
361
 
      src++;
362
 
    } else {
363
 
#if GTEST_HAS_ALT_PATH_SEP_
364
 
      if (*dest_ptr == kAlternatePathSeparator) {
365
 
        *dest_ptr = kPathSeparator;
366
 
      }
367
 
#endif
368
 
      while (IsPathSeparator(*src))
369
 
        src++;
370
 
    }
371
 
    dest_ptr++;
372
 
  }
373
 
  *dest_ptr = '\0';
374
 
  pathname_ = dest;
375
 
  delete[] dest;
376
 
}
377
 
 
378
 
}  // namespace internal
379
 
}  // namespace testing