13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/ADT/Triple.h"
17 #include "llvm/ADT/Twine.h"
18 #include "llvm/Support/ErrorOr.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/Program.h"
21 #include "llvm/Support/raw_ostream.h"
25 #include <system_error>
40 return FileSpec::Style::windows;
42 return FileSpec::Style::posix;
47 return llvm::sys::path::is_style_posix(style);
51 return llvm::sys::path::get_separator(style).data();
55 return GetPathSeparators(style)[0];
59 if (PathStyleIsPosix(style))
62 std::replace(path.begin(), path.end(),
'/',
'\\');
67 FileSpec::FileSpec() : m_style(GetNativeStyle()) {}
75 :
FileSpec{path, triple.isOSWindows() ? Style::windows : Style::posix} {}
89 inline char safeCharAtIndex(
const llvm::StringRef &path,
size_t i) {
112 bool needsNormalization(
const llvm::StringRef &path) {
118 for (
auto i = path.find_first_of(
"\\/"); i != llvm::StringRef::npos;
119 i = path.find_first_of(
"\\/", i + 1)) {
120 const auto next = safeCharAtIndex(path, i+1);
136 const auto next_next = safeCharAtIndex(path, i+2);
144 const auto next_next_next = safeCharAtIndex(path, i+3);
145 switch (next_next_next) {
175 m_style = (style == Style::native) ? GetNativeStyle() : style;
177 if (pathname.empty())
180 llvm::SmallString<128> resolved(pathname);
183 if (needsNormalization(resolved))
184 llvm::sys::path::remove_dots(resolved,
true,
m_style);
188 std::replace(resolved.begin(), resolved.end(),
'\\',
'/');
190 if (resolved.empty()) {
200 llvm::StringRef filename = llvm::sys::path::filename(resolved,
m_style);
201 if(!filename.empty())
204 llvm::StringRef directory = llvm::sys::path::parent_path(resolved,
m_style);
205 if(!directory.empty())
210 return SetFile(path, triple.isOSWindows() ? Style::windows : Style::posix);
218 FileSpec::operator bool()
const {
return m_filename || m_directory; }
302 return pattern == file;
308 std::optional<FileSpec::Style>
310 if (absolute_path.startswith(
"/"))
312 if (absolute_path.startswith(R
"(\\)"))
313 return Style::windows;
314 if (absolute_path.size() >= 3 && llvm::isAlpha(absolute_path[0]) &&
315 (absolute_path.substr(1, 2) == R
"(:\)" ||
316 absolute_path.substr(1, 2) == R"(:/)"))
317 return Style::windows;
327 char path_separator = GetPreferredPathSeparator(
m_style);
328 if (!
m_filename && !path.empty() && path.back() != path_separator)
367 bool denormalize)
const {
372 ::snprintf(path, path_max_len,
"%s", result.c_str());
373 return std::min(path_max_len - 1, result.length());
377 llvm::SmallString<64> result;
387 bool denormalize)
const {
395 path.insert(path.end(),
'/');
398 if (denormalize && !path.empty())
425 llvm::SmallString<64> current_path;
427 if (llvm::sys::path::has_parent_path(current_path,
m_style))
434 llvm::SmallString<64> current_path;
440 llvm::SmallString<64> new_path(component);
441 llvm::SmallString<64> current_path;
443 llvm::sys::path::append(new_path,
444 llvm::sys::path::begin(current_path,
m_style),
445 llvm::sys::path::end(current_path),
m_style);
454 llvm::SmallString<64> current_path;
456 llvm::sys::path::append(current_path,
m_style, component);
465 llvm::SmallString<64> current_path;
467 if (llvm::sys::path::has_parent_path(current_path,
m_style)) {
486 "^.([cC]|[mM]|[mM][mM]|[cC][pP][pP]|[cC]\\+\\+|[cC][xX][xX]|[cC][cC]|["
487 "cC][pP]|[sS]|[aA][sS][mM]|[fF]|[fF]77|[fF]90|[fF]95|[fF]03|[fF][oO]["
488 "rR]|[fF][tT][nN]|[fF][pP][pP]|[aA][dD][aA]|[aA][dD][bB]|[aA][dD][sS])"
504 llvm::SmallString<64> path;
509 if (path[0] ==
'~' || llvm::sys::path::is_absolute(path,
m_style))
521 void llvm::format_provider<FileSpec>::format(
const FileSpec &F,
524 assert((Style.empty() || Style.equals_insensitive(
"F") ||
525 Style.equals_insensitive(
"D")) &&
526 "Invalid FileSpec style!");
531 if (dir.empty() && file.empty()) {
536 if (Style.equals_insensitive(
"F")) {
537 Stream << (file.empty() ?
"(empty)" : file);
546 llvm::SmallString<64> denormalized_dir = dir;
548 Stream << denormalized_dir;
552 if (Style.equals_insensitive(
"D")) {