diff options
author | dim <dim@FreeBSD.org> | 2017-04-02 17:24:58 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2017-04-02 17:24:58 +0000 |
commit | 60b571e49a90d38697b3aca23020d9da42fc7d7f (patch) | |
tree | 99351324c24d6cb146b6285b6caffa4d26fce188 /contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp | |
parent | bea1b22c7a9bce1dfdd73e6e5b65bc4752215180 (diff) | |
download | FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.zip FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.tar.gz |
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release:
MFC r309142 (by emaste):
Add WITH_LLD_AS_LD build knob
If set it installs LLD as /usr/bin/ld. LLD (as of version 3.9) is not
capable of linking the world and kernel, but can self-host and link many
substantial applications. GNU ld continues to be used for the world and
kernel build, regardless of how this knob is set.
It is on by default for arm64, and off for all other CPU architectures.
Sponsored by: The FreeBSD Foundation
MFC r310840:
Reapply 310775, now it also builds correctly if lldb is disabled:
Move llvm-objdump from CLANG_EXTRAS to installed by default
We currently install three tools from binutils 2.17.50: as, ld, and
objdump. Work is underway to migrate to a permissively-licensed
tool-chain, with one goal being the retirement of binutils 2.17.50.
LLVM's llvm-objdump is intended to be compatible with GNU objdump
although it is currently missing some options and may have formatting
differences. Enable it by default for testing and further investigation.
It may later be changed to install as /usr/bin/objdump, it becomes a
fully viable replacement.
Reviewed by: emaste
Differential Revision: https://reviews.freebsd.org/D8879
MFC r312855 (by emaste):
Rename LLD_AS_LD to LLD_IS_LD, for consistency with CLANG_IS_CC
Reported by: Dan McGregor <dan.mcgregor usask.ca>
MFC r313559 | glebius | 2017-02-10 18:34:48 +0100 (Fri, 10 Feb 2017) | 5 lines
Don't check struct rtentry on FreeBSD, it is an internal kernel structure.
On other systems it may be API structure for SIOCADDRT/SIOCDELRT.
Reviewed by: emaste, dim
MFC r314152 (by jkim):
Remove an assembler flag, which is redundant since r309124. The upstream
took care of it by introducing a macro NO_EXEC_STACK_DIRECTIVE.
http://llvm.org/viewvc/llvm-project?rev=273500&view=rev
Reviewed by: dim
MFC r314564:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
4.0.0 (branches/release_40 296509). The release will follow soon.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Also note that as of 4.0.0, lld should be able to link the base system
on amd64 and aarch64. See the WITH_LLD_IS_LLD setting in src.conf(5).
Though please be aware that this is work in progress.
Release notes for llvm, clang and lld will be available here:
<http://releases.llvm.org/4.0.0/docs/ReleaseNotes.html>
<http://releases.llvm.org/4.0.0/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/4.0.0/tools/lld/docs/ReleaseNotes.html>
Thanks to Ed Maste, Jan Beich, Antoine Brodin and Eric Fiselier for
their help.
Relnotes: yes
Exp-run: antoine
PR: 215969, 216008
MFC r314708:
For now, revert r287232 from upstream llvm trunk (by Daniil Fukalov):
[SCEV] limit recursion depth of CompareSCEVComplexity
Summary:
CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled
loop) and runs almost infinite time.
Added cache of "equal" SCEV pairs to earlier cutoff of further
estimation. Recursion depth limit was also introduced as a parameter.
Reviewers: sanjoy
Subscribers: mzolotukhin, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D26389
This commit is the cause of excessive compile times on skein_block.c
(and possibly other files) during kernel builds on amd64.
We never saw the problematic behavior described in this upstream commit,
so for now it is better to revert it. An upstream bug has been filed
here: https://bugs.llvm.org/show_bug.cgi?id=32142
Reported by: mjg
MFC r314795:
Reapply r287232 from upstream llvm trunk (by Daniil Fukalov):
[SCEV] limit recursion depth of CompareSCEVComplexity
Summary:
CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled
loop) and runs almost infinite time.
Added cache of "equal" SCEV pairs to earlier cutoff of further
estimation. Recursion depth limit was also introduced as a parameter.
Reviewers: sanjoy
Subscribers: mzolotukhin, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D26389
Pull in r296992 from upstream llvm trunk (by Sanjoy Das):
[SCEV] Decrease the recursion threshold for CompareValueComplexity
Fixes PR32142.
r287232 accidentally increased the recursion threshold for
CompareValueComplexity from 2 to 32. This change reverses that
change by introducing a separate flag for CompareValueComplexity's
threshold.
The latter revision fixes the excessive compile times for skein_block.c.
MFC r314907 | mmel | 2017-03-08 12:40:27 +0100 (Wed, 08 Mar 2017) | 7 lines
Unbreak ARMv6 world.
The new compiler_rt library imported with clang 4.0.0 have several fatal
issues (non-functional __udivsi3 for example) with ARM specific instrict
functions. As temporary workaround, until upstream solve these problems,
disable all thumb[1][2] related feature.
MFC r315016:
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release.
We were already very close to the last release candidate, so this is a
pretty minor update.
Relnotes: yes
MFC r316005:
Revert r314907, and pull in r298713 from upstream compiler-rt trunk (by
Weiming Zhao):
builtins: Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA.
Summary:
Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation
mode (-mthumb, -marm), it reflect's capability of given CPU.
Due to this:
- use __tbumb__ and __thumb2__ insteand of __ARM_ARCH_ISA_THUMB
- use '.thumb' directive consistently in all affected files
- decorate all thumb functions using
DEFINE_COMPILERRT_THUMB_FUNCTION()
---------
Note: This patch doesn't fix broken Thumb1 variant of __udivsi3 !
Reviewers: weimingz, rengolin, compnerd
Subscribers: aemerson, dim
Differential Revision: https://reviews.llvm.org/D30938
Discussed with: mmel
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp | 2341 |
1 files changed, 1050 insertions, 1291 deletions
diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp index 53c0ab4..7f46d30 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #ifndef _WIN32 #include <dirent.h> #else @@ -17,9 +16,9 @@ #ifndef _MSC_VER #include <libgen.h> #endif +#include <fstream> #include <set> #include <string.h> -#include <fstream> #include "lldb/Host/Config.h" // Have to include this before we test the define... #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER @@ -30,14 +29,15 @@ #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataBufferMemoryMap.h" #include "lldb/Core/RegularExpression.h" -#include "lldb/Core/StreamString.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamString.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Utility/CleanUp.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" @@ -49,339 +49,281 @@ using namespace lldb_private; namespace { -bool -PathSyntaxIsPosix(FileSpec::PathSyntax syntax) -{ - return (syntax == FileSpec::ePathSyntaxPosix || - (syntax == FileSpec::ePathSyntaxHostNative && - FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix)); +bool PathSyntaxIsPosix(FileSpec::PathSyntax syntax) { + return (syntax == FileSpec::ePathSyntaxPosix || + (syntax == FileSpec::ePathSyntaxHostNative && + FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix)); } -const char * -GetPathSeparators(FileSpec::PathSyntax syntax) -{ - return PathSyntaxIsPosix(syntax) ? "/" : "\\/"; +const char *GetPathSeparators(FileSpec::PathSyntax syntax) { + return PathSyntaxIsPosix(syntax) ? "/" : "\\/"; } -char -GetPrefferedPathSeparator(FileSpec::PathSyntax syntax) -{ - return GetPathSeparators(syntax)[0]; +char GetPreferredPathSeparator(FileSpec::PathSyntax syntax) { + return GetPathSeparators(syntax)[0]; } -bool -IsPathSeparator(char value, FileSpec::PathSyntax syntax) -{ - return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\'); +bool IsPathSeparator(char value, FileSpec::PathSyntax syntax) { + return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\'); } -void -Normalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) -{ - if (PathSyntaxIsPosix(syntax)) return; - - std::replace(path.begin(), path.end(), '\\', '/'); - // Windows path can have \\ slashes which can be changed by replace - // call above to //. Here we remove the duplicate. - auto iter = std::unique ( path.begin(), path.end(), - []( char &c1, char &c2 ){ - return (c1 == '/' && c2 == '/');}); - path.erase(iter, path.end()); +void Normalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) { + if (PathSyntaxIsPosix(syntax)) + return; + + std::replace(path.begin(), path.end(), '\\', '/'); + // Windows path can have \\ slashes which can be changed by replace + // call above to //. Here we remove the duplicate. + auto iter = std::unique(path.begin(), path.end(), [](char &c1, char &c2) { + return (c1 == '/' && c2 == '/'); + }); + path.erase(iter, path.end()); } -void -Denormalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) -{ - if (PathSyntaxIsPosix(syntax)) return; +void Denormalize(llvm::SmallVectorImpl<char> &path, + FileSpec::PathSyntax syntax) { + if (PathSyntaxIsPosix(syntax)) + return; - std::replace(path.begin(), path.end(), '/', '\\'); + std::replace(path.begin(), path.end(), '/', '\\'); } -bool -GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) -{ - char resolved_path[PATH_MAX]; - if (file_spec->GetPath (resolved_path, sizeof(resolved_path))) - return FileSystem::Stat(resolved_path, stats_ptr) == 0; - return false; +bool GetFileStats(const FileSpec *file_spec, struct stat *stats_ptr) { + char resolved_path[PATH_MAX]; + if (file_spec->GetPath(resolved_path, sizeof(resolved_path))) + return FileSystem::Stat(resolved_path, stats_ptr) == 0; + return false; } -size_t -FilenamePos(llvm::StringRef str, FileSpec::PathSyntax syntax) -{ - if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) - return 0; +size_t FilenamePos(llvm::StringRef str, FileSpec::PathSyntax syntax) { + if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) + return 0; - if (str.size() > 0 && IsPathSeparator(str.back(), syntax)) - return str.size() - 1; + if (str.size() > 0 && IsPathSeparator(str.back(), syntax)) + return str.size() - 1; - size_t pos = str.find_last_of(GetPathSeparators(syntax), str.size() - 1); + size_t pos = str.find_last_of(GetPathSeparators(syntax), str.size() - 1); - if (!PathSyntaxIsPosix(syntax) && pos == llvm::StringRef::npos) - pos = str.find_last_of(':', str.size() - 2); + if (!PathSyntaxIsPosix(syntax) && pos == llvm::StringRef::npos) + pos = str.find_last_of(':', str.size() - 2); - if (pos == llvm::StringRef::npos || (pos == 1 && IsPathSeparator(str[0], syntax))) - return 0; + if (pos == llvm::StringRef::npos || + (pos == 1 && IsPathSeparator(str[0], syntax))) + return 0; - return pos + 1; + return pos + 1; } -size_t -RootDirStart(llvm::StringRef str, FileSpec::PathSyntax syntax) -{ - // case "c:/" - if (!PathSyntaxIsPosix(syntax) && (str.size() > 2 && str[1] == ':' && IsPathSeparator(str[2], syntax))) - return 2; +size_t RootDirStart(llvm::StringRef str, FileSpec::PathSyntax syntax) { + // case "c:/" + if (!PathSyntaxIsPosix(syntax) && + (str.size() > 2 && str[1] == ':' && IsPathSeparator(str[2], syntax))) + return 2; - // case "//" - if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) - return llvm::StringRef::npos; + // case "//" + if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) + return llvm::StringRef::npos; - // case "//net" - if (str.size() > 3 && IsPathSeparator(str[0], syntax) && str[0] == str[1] && !IsPathSeparator(str[2], syntax)) - return str.find_first_of(GetPathSeparators(syntax), 2); + // case "//net" + if (str.size() > 3 && IsPathSeparator(str[0], syntax) && str[0] == str[1] && + !IsPathSeparator(str[2], syntax)) + return str.find_first_of(GetPathSeparators(syntax), 2); - // case "/" - if (str.size() > 0 && IsPathSeparator(str[0], syntax)) - return 0; + // case "/" + if (str.size() > 0 && IsPathSeparator(str[0], syntax)) + return 0; - return llvm::StringRef::npos; + return llvm::StringRef::npos; } -size_t -ParentPathEnd(llvm::StringRef path, FileSpec::PathSyntax syntax) -{ - size_t end_pos = FilenamePos(path, syntax); +size_t ParentPathEnd(llvm::StringRef path, FileSpec::PathSyntax syntax) { + size_t end_pos = FilenamePos(path, syntax); - bool filename_was_sep = path.size() > 0 && IsPathSeparator(path[end_pos], syntax); + bool filename_was_sep = + path.size() > 0 && IsPathSeparator(path[end_pos], syntax); - // Skip separators except for root dir. - size_t root_dir_pos = RootDirStart(path.substr(0, end_pos), syntax); + // Skip separators except for root dir. + size_t root_dir_pos = RootDirStart(path.substr(0, end_pos), syntax); - while (end_pos > 0 && (end_pos - 1) != root_dir_pos && IsPathSeparator(path[end_pos - 1], syntax)) - --end_pos; + while (end_pos > 0 && (end_pos - 1) != root_dir_pos && + IsPathSeparator(path[end_pos - 1], syntax)) + --end_pos; - if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) - return llvm::StringRef::npos; + if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) + return llvm::StringRef::npos; - return end_pos; + return end_pos; } } // end anonymous namespace // Resolves the username part of a path of the form ~user/other/directories, and -// writes the result into dst_path. This will also resolve "~" to the current user. -// If you want to complete "~" to the list of users, pass it to ResolvePartialUsername. -void -FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path) -{ +// writes the result into dst_path. This will also resolve "~" to the current +// user. +// If you want to complete "~" to the list of users, pass it to +// ResolvePartialUsername. +void FileSpec::ResolveUsername(llvm::SmallVectorImpl<char> &path) { #if LLDB_CONFIG_TILDE_RESOLVES_TO_USER - if (path.empty() || path[0] != '~') - return; - - llvm::StringRef path_str(path.data(), path.size()); - size_t slash_pos = path_str.find('/', 1); - if (slash_pos == 1 || path.size() == 1) - { - // A path of ~/ resolves to the current user's home dir - llvm::SmallString<64> home_dir; - // llvm::sys::path::home_directory() only checks if "HOME" is set in the - // environment and does nothing else to locate the user home directory - if (!llvm::sys::path::home_directory(home_dir)) - { - struct passwd *pw = getpwuid(getuid()); - if (pw && pw->pw_dir && pw->pw_dir[0]) - { - // Update our environemnt so llvm::sys::path::home_directory() works next time - setenv("HOME", pw->pw_dir, 0); - home_dir.assign(llvm::StringRef(pw->pw_dir)); - } - else - { - return; - } - } - - // Overwrite the ~ with the first character of the homedir, and insert - // the rest. This way we only trigger one move, whereas an insert - // followed by a delete (or vice versa) would trigger two. - path[0] = home_dir[0]; - path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end()); + if (path.empty() || path[0] != '~') + return; + + llvm::StringRef path_str(path.data(), path.size()); + size_t slash_pos = path_str.find('/', 1); + if (slash_pos == 1 || path.size() == 1) { + // A path of ~/ resolves to the current user's home dir + llvm::SmallString<64> home_dir; + // llvm::sys::path::home_directory() only checks if "HOME" is set in the + // environment and does nothing else to locate the user home directory + if (!llvm::sys::path::home_directory(home_dir)) { + struct passwd *pw = getpwuid(getuid()); + if (pw && pw->pw_dir && pw->pw_dir[0]) { + // Update our environemnt so llvm::sys::path::home_directory() works + // next time + setenv("HOME", pw->pw_dir, 0); + home_dir.assign(llvm::StringRef(pw->pw_dir)); + } else { return; + } } - - auto username_begin = path.begin()+1; - auto username_end = (slash_pos == llvm::StringRef::npos) - ? path.end() - : (path.begin() + slash_pos); - size_t replacement_length = std::distance(path.begin(), username_end); - - llvm::SmallString<20> username(username_begin, username_end); - struct passwd *user_entry = ::getpwnam(username.c_str()); - if (user_entry != nullptr) - { - // Copy over the first n characters of the path, where n is the smaller of the length - // of the home directory and the slash pos. - llvm::StringRef homedir(user_entry->pw_dir); - size_t initial_copy_length = std::min(homedir.size(), replacement_length); - auto src_begin = homedir.begin(); - auto src_end = src_begin + initial_copy_length; - std::copy(src_begin, src_end, path.begin()); - if (replacement_length > homedir.size()) - { - // We copied the entire home directory, but the ~username portion of the path was - // longer, so there's characters that need to be removed. - path.erase(path.begin() + initial_copy_length, username_end); - } - else if (replacement_length < homedir.size()) - { - // We copied all the way up to the slash in the destination, but there's still more - // characters that need to be inserted. - path.insert(username_end, src_end, homedir.end()); - } - } - else - { - // Unable to resolve username (user doesn't exist?) - path.clear(); + + // Overwrite the ~ with the first character of the homedir, and insert + // the rest. This way we only trigger one move, whereas an insert + // followed by a delete (or vice versa) would trigger two. + path[0] = home_dir[0]; + path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end()); + return; + } + + auto username_begin = path.begin() + 1; + auto username_end = (slash_pos == llvm::StringRef::npos) + ? path.end() + : (path.begin() + slash_pos); + size_t replacement_length = std::distance(path.begin(), username_end); + + llvm::SmallString<20> username(username_begin, username_end); + struct passwd *user_entry = ::getpwnam(username.c_str()); + if (user_entry != nullptr) { + // Copy over the first n characters of the path, where n is the smaller of + // the length + // of the home directory and the slash pos. + llvm::StringRef homedir(user_entry->pw_dir); + size_t initial_copy_length = std::min(homedir.size(), replacement_length); + auto src_begin = homedir.begin(); + auto src_end = src_begin + initial_copy_length; + std::copy(src_begin, src_end, path.begin()); + if (replacement_length > homedir.size()) { + // We copied the entire home directory, but the ~username portion of the + // path was + // longer, so there's characters that need to be removed. + path.erase(path.begin() + initial_copy_length, username_end); + } else if (replacement_length < homedir.size()) { + // We copied all the way up to the slash in the destination, but there's + // still more + // characters that need to be inserted. + path.insert(username_end, src_end, homedir.end()); } + } else { + // Unable to resolve username (user doesn't exist?) + path.clear(); + } #endif } -size_t -FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches) -{ +size_t FileSpec::ResolvePartialUsername(llvm::StringRef partial_name, + StringList &matches) { #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - size_t extant_entries = matches.GetSize(); - - setpwent(); - struct passwd *user_entry; - const char *name_start = partial_name + 1; - std::set<std::string> name_list; - - while ((user_entry = getpwent()) != NULL) - { - if (strstr(user_entry->pw_name, name_start) == user_entry->pw_name) - { - std::string tmp_buf("~"); - tmp_buf.append(user_entry->pw_name); - tmp_buf.push_back('/'); - name_list.insert(tmp_buf); - } - } - std::set<std::string>::iterator pos, end = name_list.end(); - for (pos = name_list.begin(); pos != end; pos++) - { - matches.AppendString((*pos).c_str()); + size_t extant_entries = matches.GetSize(); + + setpwent(); + struct passwd *user_entry; + partial_name = partial_name.drop_front(); + std::set<std::string> name_list; + + while ((user_entry = getpwent()) != NULL) { + if (llvm::StringRef(user_entry->pw_name).startswith(partial_name)) { + std::string tmp_buf("~"); + tmp_buf.append(user_entry->pw_name); + tmp_buf.push_back('/'); + name_list.insert(tmp_buf); } - return matches.GetSize() - extant_entries; + } + + for (auto &name : name_list) { + matches.AppendString(name); + } + return matches.GetSize() - extant_entries; #else - // Resolving home directories is not supported, just copy the path... - return 0; -#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER + // Resolving home directories is not supported, just copy the path... + return 0; +#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER } -void -FileSpec::Resolve (llvm::SmallVectorImpl<char> &path) -{ - if (path.empty()) - return; +void FileSpec::Resolve(llvm::SmallVectorImpl<char> &path) { + if (path.empty()) + return; #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - if (path[0] == '~') - ResolveUsername(path); + if (path[0] == '~') + ResolveUsername(path); #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - // Save a copy of the original path that's passed in - llvm::SmallString<128> original_path(path.begin(), path.end()); + // Save a copy of the original path that's passed in + llvm::SmallString<128> original_path(path.begin(), path.end()); - llvm::sys::fs::make_absolute(path); - if (!llvm::sys::fs::exists(path)) - { - path.clear(); - path.append(original_path.begin(), original_path.end()); - } + llvm::sys::fs::make_absolute(path); + if (!llvm::sys::fs::exists(path)) { + path.clear(); + path.append(original_path.begin(), original_path.end()); + } } -FileSpec::FileSpec() : - m_directory(), - m_filename(), - m_syntax(FileSystem::GetNativePathSyntax()) -{ -} +FileSpec::FileSpec() : m_syntax(FileSystem::GetNativePathSyntax()) {} //------------------------------------------------------------------ // Default constructor that can take an optional full path to a // file on disk. //------------------------------------------------------------------ -FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) : - m_directory(), - m_filename(), - m_is_resolved(false), - m_syntax(syntax) -{ - if (pathname && pathname[0]) - SetFile(pathname, resolve_path, syntax); -} - -FileSpec::FileSpec(const char *pathname, bool resolve_path, ArchSpec arch) : - FileSpec{pathname, resolve_path, arch.GetTriple().isOSWindows() ? ePathSyntaxWindows : ePathSyntaxPosix} -{ -} - -FileSpec::FileSpec(const std::string &path, bool resolve_path, PathSyntax syntax) : - FileSpec{path.c_str(), resolve_path, syntax} -{ +FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, PathSyntax syntax) + : m_syntax(syntax) { + SetFile(path, resolve_path, syntax); } -FileSpec::FileSpec(const std::string &path, bool resolve_path, ArchSpec arch) : - FileSpec{path.c_str(), resolve_path, arch} -{ -} +FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, ArchSpec arch) + : FileSpec{path, resolve_path, arch.GetTriple().isOSWindows() + ? ePathSyntaxWindows + : ePathSyntaxPosix} {} //------------------------------------------------------------------ // Copy constructor //------------------------------------------------------------------ -FileSpec::FileSpec(const FileSpec& rhs) : - m_directory (rhs.m_directory), - m_filename (rhs.m_filename), - m_is_resolved (rhs.m_is_resolved), - m_syntax (rhs.m_syntax) -{ -} +FileSpec::FileSpec(const FileSpec &rhs) + : m_directory(rhs.m_directory), m_filename(rhs.m_filename), + m_is_resolved(rhs.m_is_resolved), m_syntax(rhs.m_syntax) {} //------------------------------------------------------------------ // Copy constructor //------------------------------------------------------------------ -FileSpec::FileSpec(const FileSpec* rhs) : - m_directory(), - m_filename() -{ - if (rhs) - *this = *rhs; +FileSpec::FileSpec(const FileSpec *rhs) : m_directory(), m_filename() { + if (rhs) + *this = *rhs; } //------------------------------------------------------------------ // Virtual destructor in case anyone inherits from this class. //------------------------------------------------------------------ -FileSpec::~FileSpec() -{ -} +FileSpec::~FileSpec() {} //------------------------------------------------------------------ // Assignment operator. //------------------------------------------------------------------ -const FileSpec& -FileSpec::operator= (const FileSpec& rhs) -{ - if (this != &rhs) - { - m_directory = rhs.m_directory; - m_filename = rhs.m_filename; - m_is_resolved = rhs.m_is_resolved; - m_syntax = rhs.m_syntax; - } - return *this; +const FileSpec &FileSpec::operator=(const FileSpec &rhs) { + if (this != &rhs) { + m_directory = rhs.m_directory; + m_filename = rhs.m_filename; + m_is_resolved = rhs.m_is_resolved; + m_syntax = rhs.m_syntax; + } + return *this; } //------------------------------------------------------------------ @@ -389,66 +331,57 @@ FileSpec::operator= (const FileSpec& rhs) // be split up into a directory and filename and stored as uniqued // string values for quick comparison and efficient memory usage. //------------------------------------------------------------------ -void -FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax) -{ - m_filename.Clear(); - m_directory.Clear(); - m_is_resolved = false; - m_syntax = (syntax == ePathSyntaxHostNative) ? FileSystem::GetNativePathSyntax() : syntax; - - if (pathname == NULL || pathname[0] == '\0') - return; - - llvm::SmallString<64> resolved(pathname); - - if (resolve) - { - FileSpec::Resolve (resolved); - m_is_resolved = true; - } +void FileSpec::SetFile(llvm::StringRef pathname, bool resolve, + PathSyntax syntax) { + // CLEANUP: Use StringRef for string handling. This function is kind of a + // mess and the unclear semantics of RootDirStart and ParentPathEnd make + // it very difficult to understand this function. There's no reason this + // function should be particularly complicated or difficult to understand. + m_filename.Clear(); + m_directory.Clear(); + m_is_resolved = false; + m_syntax = (syntax == ePathSyntaxHostNative) + ? FileSystem::GetNativePathSyntax() + : syntax; + + if (pathname.empty()) + return; - Normalize(resolved, syntax); + llvm::SmallString<64> resolved(pathname); - llvm::StringRef resolve_path_ref(resolved.c_str()); - size_t dir_end = ParentPathEnd(resolve_path_ref, syntax); - if (dir_end == 0) - { - m_filename.SetString(resolve_path_ref); - return; - } + if (resolve) { + FileSpec::Resolve(resolved); + m_is_resolved = true; + } - m_directory.SetString(resolve_path_ref.substr(0, dir_end)); + Normalize(resolved, m_syntax); - size_t filename_begin = dir_end; - size_t root_dir_start = RootDirStart(resolve_path_ref, syntax); - while (filename_begin != llvm::StringRef::npos && filename_begin < resolve_path_ref.size() && - filename_begin != root_dir_start && IsPathSeparator(resolve_path_ref[filename_begin], syntax)) - ++filename_begin; - m_filename.SetString((filename_begin == llvm::StringRef::npos || filename_begin >= resolve_path_ref.size()) - ? "." - : resolve_path_ref.substr(filename_begin)); -} + llvm::StringRef resolve_path_ref(resolved.c_str()); + size_t dir_end = ParentPathEnd(resolve_path_ref, m_syntax); + if (dir_end == 0) { + m_filename.SetString(resolve_path_ref); + return; + } -void -FileSpec::SetFile(const char *pathname, bool resolve, ArchSpec arch) -{ - return SetFile(pathname, resolve, - arch.GetTriple().isOSWindows() - ? ePathSyntaxWindows - : ePathSyntaxPosix); -} + m_directory.SetString(resolve_path_ref.substr(0, dir_end)); -void -FileSpec::SetFile(const std::string &pathname, bool resolve, PathSyntax syntax) -{ - return SetFile(pathname.c_str(), resolve, syntax); + size_t filename_begin = dir_end; + size_t root_dir_start = RootDirStart(resolve_path_ref, m_syntax); + while (filename_begin != llvm::StringRef::npos && + filename_begin < resolve_path_ref.size() && + filename_begin != root_dir_start && + IsPathSeparator(resolve_path_ref[filename_begin], m_syntax)) + ++filename_begin; + m_filename.SetString((filename_begin == llvm::StringRef::npos || + filename_begin >= resolve_path_ref.size()) + ? "." + : resolve_path_ref.substr(filename_begin)); } -void -FileSpec::SetFile(const std::string &pathname, bool resolve, ArchSpec arch) -{ - return SetFile(pathname.c_str(), resolve, arch); +void FileSpec::SetFile(llvm::StringRef path, bool resolve, ArchSpec arch) { + return SetFile(path, resolve, arch.GetTriple().isOSWindows() + ? ePathSyntaxWindows + : ePathSyntaxPosix); } //---------------------------------------------------------------------- @@ -458,10 +391,7 @@ FileSpec::SetFile(const std::string &pathname, bool resolve, ArchSpec arch) // if (file_spec) // {} //---------------------------------------------------------------------- -FileSpec::operator bool() const -{ - return m_filename || m_directory; -} +FileSpec::operator bool() const { return m_filename || m_directory; } //---------------------------------------------------------------------- // Logical NOT operator. This allows code to check any FileSpec @@ -470,123 +400,96 @@ FileSpec::operator bool() const // if (!file_spec) // {} //---------------------------------------------------------------------- -bool -FileSpec::operator!() const -{ - return !m_directory && !m_filename; -} +bool FileSpec::operator!() const { return !m_directory && !m_filename; } -bool -FileSpec::DirectoryEquals(const FileSpec &rhs) const -{ - const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); - return ConstString::Equals(m_directory, rhs.m_directory, case_sensitive); +bool FileSpec::DirectoryEquals(const FileSpec &rhs) const { + const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); + return ConstString::Equals(m_directory, rhs.m_directory, case_sensitive); } -bool -FileSpec::FileEquals(const FileSpec &rhs) const -{ - const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); - return ConstString::Equals(m_filename, rhs.m_filename, case_sensitive); +bool FileSpec::FileEquals(const FileSpec &rhs) const { + const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); + return ConstString::Equals(m_filename, rhs.m_filename, case_sensitive); } //------------------------------------------------------------------ // Equal to operator //------------------------------------------------------------------ -bool -FileSpec::operator== (const FileSpec& rhs) const -{ - if (!FileEquals(rhs)) - return false; - if (DirectoryEquals(rhs)) - return true; - - // TODO: determine if we want to keep this code in here. - // The code below was added to handle a case where we were - // trying to set a file and line breakpoint and one path - // was resolved, and the other not and the directory was - // in a mount point that resolved to a more complete path: - // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling - // this out... - if (IsResolved() && rhs.IsResolved()) - { - // Both paths are resolved, no need to look further... - return false; - } - - FileSpec resolved_lhs(*this); - - // If "this" isn't resolved, resolve it - if (!IsResolved()) - { - if (resolved_lhs.ResolvePath()) - { - // This path wasn't resolved but now it is. Check if the resolved - // directory is the same as our unresolved directory, and if so, - // we can mark this object as resolved to avoid more future resolves - m_is_resolved = (m_directory == resolved_lhs.m_directory); - } - else - return false; - } - - FileSpec resolved_rhs(rhs); - if (!rhs.IsResolved()) - { - if (resolved_rhs.ResolvePath()) - { - // rhs's path wasn't resolved but now it is. Check if the resolved - // directory is the same as rhs's unresolved directory, and if so, - // we can mark this object as resolved to avoid more future resolves - rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory); - } - else - return false; - } - - // If we reach this point in the code we were able to resolve both paths - // and since we only resolve the paths if the basenames are equal, then - // we can just check if both directories are equal... - return DirectoryEquals(rhs); +bool FileSpec::operator==(const FileSpec &rhs) const { + if (!FileEquals(rhs)) + return false; + if (DirectoryEquals(rhs)) + return true; + + // TODO: determine if we want to keep this code in here. + // The code below was added to handle a case where we were + // trying to set a file and line breakpoint and one path + // was resolved, and the other not and the directory was + // in a mount point that resolved to a more complete path: + // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling + // this out... + if (IsResolved() && rhs.IsResolved()) { + // Both paths are resolved, no need to look further... + return false; + } + + FileSpec resolved_lhs(*this); + + // If "this" isn't resolved, resolve it + if (!IsResolved()) { + if (resolved_lhs.ResolvePath()) { + // This path wasn't resolved but now it is. Check if the resolved + // directory is the same as our unresolved directory, and if so, + // we can mark this object as resolved to avoid more future resolves + m_is_resolved = (m_directory == resolved_lhs.m_directory); + } else + return false; + } + + FileSpec resolved_rhs(rhs); + if (!rhs.IsResolved()) { + if (resolved_rhs.ResolvePath()) { + // rhs's path wasn't resolved but now it is. Check if the resolved + // directory is the same as rhs's unresolved directory, and if so, + // we can mark this object as resolved to avoid more future resolves + rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory); + } else + return false; + } + + // If we reach this point in the code we were able to resolve both paths + // and since we only resolve the paths if the basenames are equal, then + // we can just check if both directories are equal... + return DirectoryEquals(rhs); } //------------------------------------------------------------------ // Not equal to operator //------------------------------------------------------------------ -bool -FileSpec::operator!= (const FileSpec& rhs) const -{ - return !(*this == rhs); -} +bool FileSpec::operator!=(const FileSpec &rhs) const { return !(*this == rhs); } //------------------------------------------------------------------ // Less than operator //------------------------------------------------------------------ -bool -FileSpec::operator< (const FileSpec& rhs) const -{ - return FileSpec::Compare(*this, rhs, true) < 0; +bool FileSpec::operator<(const FileSpec &rhs) const { + return FileSpec::Compare(*this, rhs, true) < 0; } //------------------------------------------------------------------ // Dump a FileSpec object to a stream //------------------------------------------------------------------ -Stream& -lldb_private::operator << (Stream &s, const FileSpec& f) -{ - f.Dump(&s); - return s; +Stream &lldb_private::operator<<(Stream &s, const FileSpec &f) { + f.Dump(&s); + return s; } //------------------------------------------------------------------ // Clear this object by releasing both the directory and filename // string values and making them both the empty string. //------------------------------------------------------------------ -void -FileSpec::Clear() -{ - m_directory.Clear(); - m_filename.Clear(); +void FileSpec::Clear() { + m_directory.Clear(); + m_filename.Clear(); } //------------------------------------------------------------------ @@ -600,166 +503,102 @@ FileSpec::Clear() // Return -1 if the "a" is less than "b", 0 if "a" is equal to "b" // and "1" if "a" is greater than "b". //------------------------------------------------------------------ -int -FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full) -{ - int result = 0; - - // case sensitivity of compare - const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); - - // If full is true, then we must compare both the directory and filename. - - // If full is false, then if either directory is empty, then we match on - // the basename only, and if both directories have valid values, we still - // do a full compare. This allows for matching when we just have a filename - // in one of the FileSpec objects. - - if (full || (a.m_directory && b.m_directory)) - { - result = ConstString::Compare(a.m_directory, b.m_directory, case_sensitive); - if (result) - return result; - } - return ConstString::Compare(a.m_filename, b.m_filename, case_sensitive); -} +int FileSpec::Compare(const FileSpec &a, const FileSpec &b, bool full) { + int result = 0; -bool -FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_backups) -{ - // case sensitivity of equality test - const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); - - if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty())) - return ConstString::Equals(a.m_filename, b.m_filename, case_sensitive); - else if (remove_backups == false) - return a == b; - else - { - if (!ConstString::Equals(a.m_filename, b.m_filename, case_sensitive)) - return false; - if (ConstString::Equals(a.m_directory, b.m_directory, case_sensitive)) - return true; - ConstString a_without_dots; - ConstString b_without_dots; + // case sensitivity of compare + const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); - RemoveBackupDots (a.m_directory, a_without_dots); - RemoveBackupDots (b.m_directory, b_without_dots); - return ConstString::Equals(a_without_dots, b_without_dots, case_sensitive); - } + // If full is true, then we must compare both the directory and filename. + + // If full is false, then if either directory is empty, then we match on + // the basename only, and if both directories have valid values, we still + // do a full compare. This allows for matching when we just have a filename + // in one of the FileSpec objects. + + if (full || (a.m_directory && b.m_directory)) { + result = ConstString::Compare(a.m_directory, b.m_directory, case_sensitive); + if (result) + return result; + } + return ConstString::Compare(a.m_filename, b.m_filename, case_sensitive); } -void -FileSpec::NormalizePath () -{ - ConstString normalized_directory; - FileSpec::RemoveBackupDots(m_directory, normalized_directory); - m_directory = normalized_directory; +bool FileSpec::Equal(const FileSpec &a, const FileSpec &b, bool full, + bool remove_backups) { + // case sensitivity of equality test + const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); + + if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty())) + return ConstString::Equals(a.m_filename, b.m_filename, case_sensitive); + + if (remove_backups == false) + return a == b; + + if (a == b) + return true; + + return Equal(a.GetNormalizedPath(), b.GetNormalizedPath(), full, false); } -void -FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &result_const_str) -{ - const char *input = input_const_str.GetCString(); - result_const_str.Clear(); - if (!input || input[0] == '\0') - return; +FileSpec FileSpec::GetNormalizedPath() const { + // Fast path. Do nothing if the path is not interesting. + if (!m_directory.GetStringRef().contains(".") && + !m_directory.GetStringRef().contains("//") && + m_filename.GetStringRef() != ".." && m_filename.GetStringRef() != ".") + return *this; - const char win_sep = '\\'; - const char unix_sep = '/'; - char found_sep; - const char *win_backup = "\\.."; - const char *unix_backup = "/.."; - - bool is_win = false; - - // Determine the platform for the path (win or unix): - - if (input[0] == win_sep) - is_win = true; - else if (input[0] == unix_sep) - is_win = false; - else if (input[1] == ':') - is_win = true; - else if (strchr(input, unix_sep) != nullptr) - is_win = false; - else if (strchr(input, win_sep) != nullptr) - is_win = true; - else - { - // No separators at all, no reason to do any work here. - result_const_str = input_const_str; - return; + llvm::SmallString<64> path, result; + const bool normalize = false; + GetPath(path, normalize); + llvm::StringRef rest(path); + + // We will not go below root dir. + size_t root_dir_start = RootDirStart(path, m_syntax); + const bool absolute = root_dir_start != llvm::StringRef::npos; + if (absolute) { + result += rest.take_front(root_dir_start + 1); + rest = rest.drop_front(root_dir_start + 1); + } else { + if (m_syntax == ePathSyntaxWindows && path.size() > 2 && path[1] == ':') { + result += rest.take_front(2); + rest = rest.drop_front(2); } - - llvm::StringRef backup_sep; - if (is_win) - { - found_sep = win_sep; - backup_sep = win_backup; + } + + bool anything_added = false; + llvm::SmallVector<llvm::StringRef, 0> components, processed; + rest.split(components, '/', -1, false); + processed.reserve(components.size()); + for (auto component : components) { + if (component == ".") + continue; // Skip these. + if (component != "..") { + processed.push_back(component); + continue; // Regular file name. } - else - { - found_sep = unix_sep; - backup_sep = unix_backup; + if (!processed.empty()) { + processed.pop_back(); + continue; // Dots. Go one level up if we can. } - - llvm::StringRef input_ref(input); - llvm::StringRef curpos(input); - - bool had_dots = false; - std::string result; - - while (1) - { - // Start of loop - llvm::StringRef before_sep; - std::pair<llvm::StringRef, llvm::StringRef> around_sep = curpos.split(backup_sep); - - before_sep = around_sep.first; - curpos = around_sep.second; - - if (curpos.empty()) - { - if (had_dots) - { - while (before_sep.startswith("//")) - before_sep = before_sep.substr(1); - if (!before_sep.empty()) - { - result.append(before_sep.data(), before_sep.size()); - } - } - break; - } - had_dots = true; - - unsigned num_backups = 1; - while (curpos.startswith(backup_sep)) - { - num_backups++; - curpos = curpos.slice(backup_sep.size(), curpos.size()); - } - - size_t end_pos = before_sep.size(); - while (num_backups-- > 0) - { - end_pos = before_sep.rfind(found_sep, end_pos); - if (end_pos == llvm::StringRef::npos) - { - result_const_str = input_const_str; - return; - } - } - result.append(before_sep.data(), end_pos); - } - - if (had_dots) - result_const_str.SetCString(result.c_str()); - else - result_const_str = input_const_str; - - return; + if (absolute) + continue; // We're at the top level. Cannot go higher than that. Skip. + + result += component; // We're a relative path. We need to keep these. + result += '/'; + anything_added = true; + } + for (auto component : processed) { + result += component; + result += '/'; + anything_added = true; + } + if (anything_added) + result.pop_back(); // Pop last '/'. + else if (result.empty()) + result = "."; + + return FileSpec(result, false, m_syntax); } //------------------------------------------------------------------ @@ -767,279 +606,223 @@ FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &res // a valid directory name, it will be displayed followed by a // directory delimiter, and the filename. //------------------------------------------------------------------ -void -FileSpec::Dump(Stream *s) const -{ - if (s) - { - std::string path{GetPath(true)}; - s->PutCString(path.c_str()); - char path_separator = GetPrefferedPathSeparator(m_syntax); - if (!m_filename && !path.empty() && path.back() != path_separator) - s->PutChar(path_separator); - } +void FileSpec::Dump(Stream *s) const { + if (s) { + std::string path{GetPath(true)}; + s->PutCString(path); + char path_separator = GetPreferredPathSeparator(m_syntax); + if (!m_filename && !path.empty() && path.back() != path_separator) + s->PutChar(path_separator); + } } //------------------------------------------------------------------ // Returns true if the file exists. //------------------------------------------------------------------ -bool -FileSpec::Exists () const -{ - struct stat file_stats; - return GetFileStats (this, &file_stats); -} - -bool -FileSpec::Readable () const -{ - const uint32_t permissions = GetPermissions(); - if (permissions & eFilePermissionsEveryoneR) - return true; - return false; -} - -bool -FileSpec::ResolveExecutableLocation () -{ - if (!m_directory) - { - const char *file_cstr = m_filename.GetCString(); - if (file_cstr) - { - const std::string file_str (file_cstr); - llvm::ErrorOr<std::string> error_or_path = llvm::sys::findProgramByName (file_str); - if (!error_or_path) - return false; - std::string path = error_or_path.get(); - llvm::StringRef dir_ref = llvm::sys::path::parent_path(path); - if (!dir_ref.empty()) - { - // FindProgramByName returns "." if it can't find the file. - if (strcmp (".", dir_ref.data()) == 0) - return false; - - m_directory.SetCString (dir_ref.data()); - if (Exists()) - return true; - else - { - // If FindProgramByName found the file, it returns the directory + filename in its return results. - // We need to separate them. - FileSpec tmp_file (dir_ref.data(), false); - if (tmp_file.Exists()) - { - m_directory = tmp_file.m_directory; - return true; - } - } - } +bool FileSpec::Exists() const { + struct stat file_stats; + return GetFileStats(this, &file_stats); +} + +bool FileSpec::Readable() const { + const uint32_t permissions = GetPermissions(); + if (permissions & eFilePermissionsEveryoneR) + return true; + return false; +} + +bool FileSpec::ResolveExecutableLocation() { + // CLEANUP: Use StringRef for string handling. + if (!m_directory) { + const char *file_cstr = m_filename.GetCString(); + if (file_cstr) { + const std::string file_str(file_cstr); + llvm::ErrorOr<std::string> error_or_path = + llvm::sys::findProgramByName(file_str); + if (!error_or_path) + return false; + std::string path = error_or_path.get(); + llvm::StringRef dir_ref = llvm::sys::path::parent_path(path); + if (!dir_ref.empty()) { + // FindProgramByName returns "." if it can't find the file. + if (strcmp(".", dir_ref.data()) == 0) + return false; + + m_directory.SetCString(dir_ref.data()); + if (Exists()) + return true; + else { + // If FindProgramByName found the file, it returns the directory + + // filename in its return results. + // We need to separate them. + FileSpec tmp_file(dir_ref.data(), false); + if (tmp_file.Exists()) { + m_directory = tmp_file.m_directory; + return true; + } } + } } - - return false; + } + + return false; } -bool -FileSpec::ResolvePath () -{ - if (m_is_resolved) - return true; // We have already resolved this path +bool FileSpec::ResolvePath() { + if (m_is_resolved) + return true; // We have already resolved this path - char path_buf[PATH_MAX]; - if (!GetPath (path_buf, PATH_MAX, false)) - return false; - // SetFile(...) will set m_is_resolved correctly if it can resolve the path - SetFile (path_buf, true); - return m_is_resolved; + char path_buf[PATH_MAX]; + if (!GetPath(path_buf, PATH_MAX, false)) + return false; + // SetFile(...) will set m_is_resolved correctly if it can resolve the path + SetFile(path_buf, true); + return m_is_resolved; } -uint64_t -FileSpec::GetByteSize() const -{ - struct stat file_stats; - if (GetFileStats (this, &file_stats)) - return file_stats.st_size; - return 0; +uint64_t FileSpec::GetByteSize() const { + struct stat file_stats; + if (GetFileStats(this, &file_stats)) + return file_stats.st_size; + return 0; } -FileSpec::PathSyntax -FileSpec::GetPathSyntax() const -{ - return m_syntax; -} +FileSpec::PathSyntax FileSpec::GetPathSyntax() const { return m_syntax; } -FileSpec::FileType -FileSpec::GetFileType () const -{ - struct stat file_stats; - if (GetFileStats (this, &file_stats)) - { - mode_t file_type = file_stats.st_mode & S_IFMT; - switch (file_type) - { - case S_IFDIR: return eFileTypeDirectory; - case S_IFREG: return eFileTypeRegular; +FileSpec::FileType FileSpec::GetFileType() const { + struct stat file_stats; + if (GetFileStats(this, &file_stats)) { + mode_t file_type = file_stats.st_mode & S_IFMT; + switch (file_type) { + case S_IFDIR: + return eFileTypeDirectory; + case S_IFREG: + return eFileTypeRegular; #ifndef _WIN32 - case S_IFIFO: return eFileTypePipe; - case S_IFSOCK: return eFileTypeSocket; - case S_IFLNK: return eFileTypeSymbolicLink; + case S_IFIFO: + return eFileTypePipe; + case S_IFSOCK: + return eFileTypeSocket; + case S_IFLNK: + return eFileTypeSymbolicLink; #endif - default: - break; - } - return eFileTypeUnknown; + default: + break; } - return eFileTypeInvalid; + return eFileTypeUnknown; + } + return eFileTypeInvalid; } -bool -FileSpec::IsSymbolicLink () const -{ - char resolved_path[PATH_MAX]; - if (!GetPath (resolved_path, sizeof (resolved_path))) - return false; +bool FileSpec::IsSymbolicLink() const { + char resolved_path[PATH_MAX]; + if (!GetPath(resolved_path, sizeof(resolved_path))) + return false; #ifdef _WIN32 - std::wstring wpath; - if (!llvm::ConvertUTF8toWide(resolved_path, wpath)) - return false; - auto attrs = ::GetFileAttributesW(wpath.c_str()); - if (attrs == INVALID_FILE_ATTRIBUTES) - return false; + std::wstring wpath; + if (!llvm::ConvertUTF8toWide(resolved_path, wpath)) + return false; + auto attrs = ::GetFileAttributesW(wpath.c_str()); + if (attrs == INVALID_FILE_ATTRIBUTES) + return false; - return (attrs & FILE_ATTRIBUTE_REPARSE_POINT); + return (attrs & FILE_ATTRIBUTE_REPARSE_POINT); #else - struct stat file_stats; - if (::lstat (resolved_path, &file_stats) != 0) - return false; + struct stat file_stats; + if (::lstat(resolved_path, &file_stats) != 0) + return false; - return (file_stats.st_mode & S_IFMT) == S_IFLNK; + return (file_stats.st_mode & S_IFMT) == S_IFLNK; #endif } -uint32_t -FileSpec::GetPermissions () const -{ - uint32_t file_permissions = 0; - if (*this) - FileSystem::GetFilePermissions(*this, file_permissions); - return file_permissions; -} - -TimeValue -FileSpec::GetModificationTime () const -{ - TimeValue mod_time; - struct stat file_stats; - if (GetFileStats (this, &file_stats)) - mod_time.OffsetWithSeconds(file_stats.st_mtime); - return mod_time; +uint32_t FileSpec::GetPermissions() const { + uint32_t file_permissions = 0; + if (*this) + FileSystem::GetFilePermissions(*this, file_permissions); + return file_permissions; } //------------------------------------------------------------------ // Directory string get accessor. //------------------------------------------------------------------ -ConstString & -FileSpec::GetDirectory() -{ - return m_directory; -} +ConstString &FileSpec::GetDirectory() { return m_directory; } //------------------------------------------------------------------ // Directory string const get accessor. //------------------------------------------------------------------ -const ConstString & -FileSpec::GetDirectory() const -{ - return m_directory; -} +const ConstString &FileSpec::GetDirectory() const { return m_directory; } //------------------------------------------------------------------ // Filename string get accessor. //------------------------------------------------------------------ -ConstString & -FileSpec::GetFilename() -{ - return m_filename; -} +ConstString &FileSpec::GetFilename() { return m_filename; } //------------------------------------------------------------------ // Filename string const get accessor. //------------------------------------------------------------------ -const ConstString & -FileSpec::GetFilename() const -{ - return m_filename; -} +const ConstString &FileSpec::GetFilename() const { return m_filename; } //------------------------------------------------------------------ // Extract the directory and path into a fixed buffer. This is // needed as the directory and path are stored in separate string // values. //------------------------------------------------------------------ -size_t -FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const -{ - if (!path) - return 0; - - std::string result = GetPath(denormalize); - ::snprintf(path, path_max_len, "%s", result.c_str()); - return std::min(path_max_len-1, result.length()); -} +size_t FileSpec::GetPath(char *path, size_t path_max_len, + bool denormalize) const { + if (!path) + return 0; -std::string -FileSpec::GetPath(bool denormalize) const -{ - llvm::SmallString<64> result; - GetPath(result, denormalize); - return std::string(result.begin(), result.end()); + std::string result = GetPath(denormalize); + ::snprintf(path, path_max_len, "%s", result.c_str()); + return std::min(path_max_len - 1, result.length()); } -const char * -FileSpec::GetCString(bool denormalize) const -{ - return ConstString{GetPath(denormalize)}.AsCString(NULL); +std::string FileSpec::GetPath(bool denormalize) const { + llvm::SmallString<64> result; + GetPath(result, denormalize); + return std::string(result.begin(), result.end()); } -void -FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, bool denormalize) const -{ - path.append(m_directory.GetStringRef().begin(), m_directory.GetStringRef().end()); - if (m_directory && m_filename && !IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) - path.insert(path.end(), GetPrefferedPathSeparator(m_syntax)); - path.append(m_filename.GetStringRef().begin(), m_filename.GetStringRef().end()); - Normalize(path, m_syntax); - if (denormalize && !path.empty()) - Denormalize(path, m_syntax); +const char *FileSpec::GetCString(bool denormalize) const { + return ConstString{GetPath(denormalize)}.AsCString(NULL); } -ConstString -FileSpec::GetFileNameExtension () const -{ - if (m_filename) - { - const char *filename = m_filename.GetCString(); - const char* dot_pos = strrchr(filename, '.'); - if (dot_pos && dot_pos[1] != '\0') - return ConstString(dot_pos+1); - } - return ConstString(); +void FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, + bool denormalize) const { + path.append(m_directory.GetStringRef().begin(), + m_directory.GetStringRef().end()); + if (m_directory && m_filename && + !IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) + path.insert(path.end(), GetPreferredPathSeparator(m_syntax)); + path.append(m_filename.GetStringRef().begin(), + m_filename.GetStringRef().end()); + Normalize(path, m_syntax); + if (denormalize && !path.empty()) + Denormalize(path, m_syntax); } -ConstString -FileSpec::GetFileNameStrippingExtension () const -{ +ConstString FileSpec::GetFileNameExtension() const { + if (m_filename) { const char *filename = m_filename.GetCString(); - if (filename == NULL) - return ConstString(); - - const char* dot_pos = strrchr(filename, '.'); - if (dot_pos == NULL) - return m_filename; - - return ConstString(filename, dot_pos-filename); + const char *dot_pos = strrchr(filename, '.'); + if (dot_pos && dot_pos[1] != '\0') + return ConstString(dot_pos + 1); + } + return ConstString(); +} + +ConstString FileSpec::GetFileNameStrippingExtension() const { + const char *filename = m_filename.GetCString(); + if (filename == NULL) + return ConstString(); + + const char *dot_pos = strrchr(filename, '.'); + if (dot_pos == NULL) + return m_filename; + + return ConstString(filename, dot_pos - filename); } //------------------------------------------------------------------ @@ -1053,66 +836,56 @@ FileSpec::GetFileNameStrippingExtension () const // truncated. The final number of bytes that get mapped can be // verified using the DataBuffer::GetByteSize() function. //------------------------------------------------------------------ -DataBufferSP -FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const -{ - DataBufferSP data_sp; - std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap()); - if (mmap_data.get()) - { - const size_t mapped_length = mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size); - if (((file_size == SIZE_MAX) && (mapped_length > 0)) || (mapped_length >= file_size)) - data_sp.reset(mmap_data.release()); - } - return data_sp; +DataBufferSP FileSpec::MemoryMapFileContents(off_t file_offset, + size_t file_size) const { + DataBufferSP data_sp; + std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap()); + if (mmap_data.get()) { + const size_t mapped_length = + mmap_data->MemoryMapFromFileSpec(this, file_offset, file_size); + if (((file_size == SIZE_MAX) && (mapped_length > 0)) || + (mapped_length >= file_size)) + data_sp.reset(mmap_data.release()); + } + return data_sp; +} + +DataBufferSP FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset, + size_t file_size) const { + if (FileSystem::IsLocal(*this)) + return MemoryMapFileContents(file_offset, file_size); + else + return ReadFileContents(file_offset, file_size, NULL); } -DataBufferSP -FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset, size_t file_size) const -{ - if (FileSystem::IsLocal(*this)) - return MemoryMapFileContents(file_offset, file_size); - else - return ReadFileContents(file_offset, file_size, NULL); -} - - //------------------------------------------------------------------ // Return the size in bytes that this object takes in memory. This // returns the size in bytes of this object, not any shared string // values it may refer to. //------------------------------------------------------------------ -size_t -FileSpec::MemorySize() const -{ - return m_filename.MemorySize() + m_directory.MemorySize(); -} - - -size_t -FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error *error_ptr) const -{ - Error error; - size_t bytes_read = 0; - char resolved_path[PATH_MAX]; - if (GetPath(resolved_path, sizeof(resolved_path))) - { - File file; - error = file.Open(resolved_path, File::eOpenOptionRead); - if (error.Success()) - { - off_t file_offset_after_seek = file_offset; - bytes_read = dst_len; - error = file.Read(dst, bytes_read, file_offset_after_seek); - } - } - else - { - error.SetErrorString("invalid file specification"); +size_t FileSpec::MemorySize() const { + return m_filename.MemorySize() + m_directory.MemorySize(); +} + +size_t FileSpec::ReadFileContents(off_t file_offset, void *dst, size_t dst_len, + Error *error_ptr) const { + Error error; + size_t bytes_read = 0; + char resolved_path[PATH_MAX]; + if (GetPath(resolved_path, sizeof(resolved_path))) { + File file; + error = file.Open(resolved_path, File::eOpenOptionRead); + if (error.Success()) { + off_t file_offset_after_seek = file_offset; + bytes_read = dst_len; + error = file.Read(dst, bytes_read, file_offset_after_seek); } - if (error_ptr) - *error_ptr = error; - return bytes_read; + } else { + error.SetErrorString("invalid file specification"); + } + if (error_ptr) + *error_ptr = error; + return bytes_read; } //------------------------------------------------------------------ @@ -1126,486 +899,441 @@ FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error // truncated. The final number of bytes that get mapped can be // verified using the DataBuffer::GetByteSize() function. //------------------------------------------------------------------ -DataBufferSP -FileSpec::ReadFileContents (off_t file_offset, size_t file_size, Error *error_ptr) const -{ - Error error; - DataBufferSP data_sp; - char resolved_path[PATH_MAX]; - if (GetPath(resolved_path, sizeof(resolved_path))) - { - File file; - error = file.Open(resolved_path, File::eOpenOptionRead); - if (error.Success()) - { - const bool null_terminate = false; - error = file.Read (file_size, file_offset, null_terminate, data_sp); - } +DataBufferSP FileSpec::ReadFileContents(off_t file_offset, size_t file_size, + Error *error_ptr) const { + Error error; + DataBufferSP data_sp; + char resolved_path[PATH_MAX]; + if (GetPath(resolved_path, sizeof(resolved_path))) { + File file; + error = file.Open(resolved_path, File::eOpenOptionRead); + if (error.Success()) { + const bool null_terminate = false; + error = file.Read(file_size, file_offset, null_terminate, data_sp); + } + } else { + error.SetErrorString("invalid file specification"); + } + if (error_ptr) + *error_ptr = error; + return data_sp; +} + +DataBufferSP FileSpec::ReadFileContentsAsCString(Error *error_ptr) { + Error error; + DataBufferSP data_sp; + char resolved_path[PATH_MAX]; + if (GetPath(resolved_path, sizeof(resolved_path))) { + File file; + error = file.Open(resolved_path, File::eOpenOptionRead); + if (error.Success()) { + off_t offset = 0; + size_t length = SIZE_MAX; + const bool null_terminate = true; + error = file.Read(length, offset, null_terminate, data_sp); } - else - { - error.SetErrorString("invalid file specification"); + } else { + error.SetErrorString("invalid file specification"); + } + if (error_ptr) + *error_ptr = error; + return data_sp; +} + +size_t FileSpec::ReadFileLines(STLStringArray &lines) { + lines.clear(); + char path[PATH_MAX]; + if (GetPath(path, sizeof(path))) { + std::ifstream file_stream(path); + + if (file_stream) { + std::string line; + while (getline(file_stream, line)) + lines.push_back(line); } - if (error_ptr) - *error_ptr = error; - return data_sp; + } + return lines.size(); } -DataBufferSP -FileSpec::ReadFileContentsAsCString(Error *error_ptr) -{ - Error error; - DataBufferSP data_sp; - char resolved_path[PATH_MAX]; - if (GetPath(resolved_path, sizeof(resolved_path))) - { - File file; - error = file.Open(resolved_path, File::eOpenOptionRead); - if (error.Success()) - { - off_t offset = 0; - size_t length = SIZE_MAX; - const bool null_terminate = true; - error = file.Read (length, offset, null_terminate, data_sp); - } +FileSpec::EnumerateDirectoryResult +FileSpec::ForEachItemInDirectory(llvm::StringRef dir_path, + DirectoryCallback const &callback) { + if (dir_path.empty()) + return eEnumerateDirectoryResultNext; + +#ifdef _WIN32 + std::string szDir(dir_path); + szDir += "\\*"; + + std::wstring wszDir; + if (!llvm::ConvertUTF8toWide(szDir, wszDir)) { + return eEnumerateDirectoryResultNext; } - else - { - error.SetErrorString("invalid file specification"); + + WIN32_FIND_DATAW ffd; + HANDLE hFind = FindFirstFileW(wszDir.c_str(), &ffd); + + if (hFind == INVALID_HANDLE_VALUE) { + return eEnumerateDirectoryResultNext; } - if (error_ptr) - *error_ptr = error; - return data_sp; -} -size_t -FileSpec::ReadFileLines (STLStringArray &lines) -{ - lines.clear(); - char path[PATH_MAX]; - if (GetPath(path, sizeof(path))) - { - std::ifstream file_stream (path); - - if (file_stream) - { - std::string line; - while (getline (file_stream, line)) - lines.push_back (line); + do { + FileSpec::FileType file_type = eFileTypeUnknown; + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + size_t len = wcslen(ffd.cFileName); + + if (len == 1 && ffd.cFileName[0] == L'.') + continue; + + if (len == 2 && ffd.cFileName[0] == L'.' && ffd.cFileName[1] == L'.') + continue; + + file_type = eFileTypeDirectory; + } else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) { + file_type = eFileTypeOther; + } else { + file_type = eFileTypeRegular; + } + + std::string fileName; + if (!llvm::convertWideToUTF8(ffd.cFileName, fileName)) { + continue; + } + + std::string child_path = llvm::join_items("\\", dir_path, fileName); + // Don't resolve the file type or path + FileSpec child_path_spec(child_path.data(), false); + + EnumerateDirectoryResult result = callback(file_type, child_path_spec); + + switch (result) { + case eEnumerateDirectoryResultNext: + // Enumerate next entry in the current directory. We just + // exit this switch and will continue enumerating the + // current directory as we currently are... + break; + + case eEnumerateDirectoryResultEnter: // Recurse into the current entry + // if it is a directory or symlink, + // or next if not + if (FileSpec::ForEachItemInDirectory(child_path.data(), callback) == + eEnumerateDirectoryResultQuit) { + // The subdirectory returned Quit, which means to + // stop all directory enumerations at all levels. + return eEnumerateDirectoryResultQuit; } - } - return lines.size(); -} + break; -FileSpec::EnumerateDirectoryResult -FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const &callback) -{ - if (dir_path && dir_path[0]) - { -#ifdef _WIN32 - std::string szDir(dir_path); - szDir += "\\*"; + case eEnumerateDirectoryResultExit: // Exit from the current directory + // at the current level. + // Exit from this directory level and tell parent to + // keep enumerating. + return eEnumerateDirectoryResultNext; - std::wstring wszDir; - if (!llvm::ConvertUTF8toWide(szDir, wszDir)) - { - return eEnumerateDirectoryResultNext; + case eEnumerateDirectoryResultQuit: // Stop directory enumerations at + // any level + return eEnumerateDirectoryResultQuit; + } + } while (FindNextFileW(hFind, &ffd) != 0); + + FindClose(hFind); +#else + std::string dir_string(dir_path); + lldb_utility::CleanUp<DIR *, int> dir_path_dir(opendir(dir_string.c_str()), + NULL, closedir); + if (dir_path_dir.is_valid()) { + char dir_path_last_char = dir_path.back(); + + long path_max = fpathconf(dirfd(dir_path_dir.get()), _PC_NAME_MAX); +#if defined(__APPLE_) && defined(__DARWIN_MAXPATHLEN) + if (path_max < __DARWIN_MAXPATHLEN) + path_max = __DARWIN_MAXPATHLEN; +#endif + struct dirent *buf, *dp; + buf = (struct dirent *)malloc(offsetof(struct dirent, d_name) + path_max + + 1); + + while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp) { + // Only search directories + if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) { + size_t len = strlen(dp->d_name); + + if (len == 1 && dp->d_name[0] == '.') + continue; + + if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') + continue; } - WIN32_FIND_DATAW ffd; - HANDLE hFind = FindFirstFileW(wszDir.c_str(), &ffd); + FileSpec::FileType file_type = eFileTypeUnknown; - if (hFind == INVALID_HANDLE_VALUE) - { - return eEnumerateDirectoryResultNext; + switch (dp->d_type) { + default: + case DT_UNKNOWN: + file_type = eFileTypeUnknown; + break; + case DT_FIFO: + file_type = eFileTypePipe; + break; + case DT_CHR: + file_type = eFileTypeOther; + break; + case DT_DIR: + file_type = eFileTypeDirectory; + break; + case DT_BLK: + file_type = eFileTypeOther; + break; + case DT_REG: + file_type = eFileTypeRegular; + break; + case DT_LNK: + file_type = eFileTypeSymbolicLink; + break; + case DT_SOCK: + file_type = eFileTypeSocket; + break; +#if !defined(__OpenBSD__) + case DT_WHT: + file_type = eFileTypeOther; + break; +#endif } - do - { - FileSpec::FileType file_type = eFileTypeUnknown; - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - size_t len = wcslen(ffd.cFileName); + std::string child_path; + // Don't make paths with "/foo//bar", that just confuses everybody. + if (dir_path_last_char == '/') + child_path = llvm::join_items("", dir_path, dp->d_name); + else + child_path = llvm::join_items('/', dir_path, dp->d_name); - if (len == 1 && ffd.cFileName[0] == L'.') - continue; + // Don't resolve the file type or path + FileSpec child_path_spec(child_path, false); - if (len == 2 && ffd.cFileName[0] == L'.' && ffd.cFileName[1] == L'.') - continue; + EnumerateDirectoryResult result = + callback(file_type, child_path_spec); - file_type = eFileTypeDirectory; - } - else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) - { - file_type = eFileTypeOther; - } - else - { - file_type = eFileTypeRegular; - } + switch (result) { + case eEnumerateDirectoryResultNext: + // Enumerate next entry in the current directory. We just + // exit this switch and will continue enumerating the + // current directory as we currently are... + break; - std::string fileName; - if (!llvm::convertWideToUTF8(ffd.cFileName, fileName)) - { - continue; + case eEnumerateDirectoryResultEnter: // Recurse into the current entry + // if it is a directory or + // symlink, or next if not + if (FileSpec::ForEachItemInDirectory(child_path, callback) == + eEnumerateDirectoryResultQuit) { + // The subdirectory returned Quit, which means to + // stop all directory enumerations at all levels. + if (buf) + free(buf); + return eEnumerateDirectoryResultQuit; } + break; - std::vector<char> child_path(PATH_MAX); - const int child_path_len = - ::snprintf(child_path.data(), child_path.size(), "%s\\%s", dir_path, fileName.c_str()); - if (child_path_len < (int)(child_path.size() - 1)) - { - // Don't resolve the file type or path - FileSpec child_path_spec(child_path.data(), false); - - EnumerateDirectoryResult result = callback (file_type, child_path_spec); - - switch (result) - { - case eEnumerateDirectoryResultNext: - // Enumerate next entry in the current directory. We just - // exit this switch and will continue enumerating the - // current directory as we currently are... - break; - - case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not - if (FileSpec::ForEachItemInDirectory(child_path.data(), callback) == - eEnumerateDirectoryResultQuit) - { - // The subdirectory returned Quit, which means to - // stop all directory enumerations at all levels. - return eEnumerateDirectoryResultQuit; - } - break; - - case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level. - // Exit from this directory level and tell parent to - // keep enumerating. - return eEnumerateDirectoryResultNext; - - case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level - return eEnumerateDirectoryResultQuit; - } - } - } while (FindNextFileW(hFind, &ffd) != 0); + case eEnumerateDirectoryResultExit: // Exit from the current directory + // at the current level. + // Exit from this directory level and tell parent to + // keep enumerating. + if (buf) + free(buf); + return eEnumerateDirectoryResultNext; - FindClose(hFind); -#else - lldb_utility::CleanUp <DIR *, int> dir_path_dir(opendir(dir_path), NULL, closedir); - if (dir_path_dir.is_valid()) - { - char dir_path_last_char = dir_path[strlen(dir_path) - 1]; - - long path_max = fpathconf (dirfd (dir_path_dir.get()), _PC_NAME_MAX); -#if defined (__APPLE_) && defined (__DARWIN_MAXPATHLEN) - if (path_max < __DARWIN_MAXPATHLEN) - path_max = __DARWIN_MAXPATHLEN; -#endif - struct dirent *buf, *dp; - buf = (struct dirent *) malloc (offsetof (struct dirent, d_name) + path_max + 1); - - while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp) - { - // Only search directories - if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) - { - size_t len = strlen(dp->d_name); - - if (len == 1 && dp->d_name[0] == '.') - continue; - - if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') - continue; - } - - FileSpec::FileType file_type = eFileTypeUnknown; - - switch (dp->d_type) - { - default: - case DT_UNKNOWN: file_type = eFileTypeUnknown; break; - case DT_FIFO: file_type = eFileTypePipe; break; - case DT_CHR: file_type = eFileTypeOther; break; - case DT_DIR: file_type = eFileTypeDirectory; break; - case DT_BLK: file_type = eFileTypeOther; break; - case DT_REG: file_type = eFileTypeRegular; break; - case DT_LNK: file_type = eFileTypeSymbolicLink; break; - case DT_SOCK: file_type = eFileTypeSocket; break; -#if !defined(__OpenBSD__) - case DT_WHT: file_type = eFileTypeOther; break; -#endif - } - - char child_path[PATH_MAX]; - - // Don't make paths with "/foo//bar", that just confuses everybody. - int child_path_len; - if (dir_path_last_char == '/') - child_path_len = ::snprintf (child_path, sizeof(child_path), "%s%s", dir_path, dp->d_name); - else - child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name); - - if (child_path_len < (int)(sizeof(child_path) - 1)) - { - // Don't resolve the file type or path - FileSpec child_path_spec (child_path, false); - - EnumerateDirectoryResult result = callback (file_type, child_path_spec); - - switch (result) - { - case eEnumerateDirectoryResultNext: - // Enumerate next entry in the current directory. We just - // exit this switch and will continue enumerating the - // current directory as we currently are... - break; - - case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not - if (FileSpec::ForEachItemInDirectory (child_path, callback) == eEnumerateDirectoryResultQuit) - { - // The subdirectory returned Quit, which means to - // stop all directory enumerations at all levels. - if (buf) - free (buf); - return eEnumerateDirectoryResultQuit; - } - break; - - case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level. - // Exit from this directory level and tell parent to - // keep enumerating. - if (buf) - free (buf); - return eEnumerateDirectoryResultNext; - - case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level - if (buf) - free (buf); - return eEnumerateDirectoryResultQuit; - } - } - } + case eEnumerateDirectoryResultQuit: // Stop directory enumerations at + // any level if (buf) - { - free (buf); - } - } -#endif + free(buf); + return eEnumerateDirectoryResultQuit; + } + } + if (buf) { + free(buf); + } } - // By default when exiting a directory, we tell the parent enumeration - // to continue enumerating. - return eEnumerateDirectoryResultNext; +#endif + // By default when exiting a directory, we tell the parent enumeration + // to continue enumerating. + return eEnumerateDirectoryResultNext; } FileSpec::EnumerateDirectoryResult -FileSpec::EnumerateDirectory -( - const char *dir_path, - bool find_directories, - bool find_files, - bool find_other, - EnumerateDirectoryCallbackType callback, - void *callback_baton -) -{ - return ForEachItemInDirectory(dir_path, - [&find_directories, &find_files, &find_other, &callback, &callback_baton] - (FileType file_type, const FileSpec &file_spec) { - switch (file_type) - { - case FileType::eFileTypeDirectory: - if (find_directories) - return callback(callback_baton, file_type, file_spec); - break; - case FileType::eFileTypeRegular: - if (find_files) - return callback(callback_baton, file_type, file_spec); - break; - default: - if (find_other) - return callback(callback_baton, file_type, file_spec); - break; - } - return eEnumerateDirectoryResultNext; - }); -} - -FileSpec -FileSpec::CopyByAppendingPathComponent (const char *new_path) const -{ - FileSpec ret = *this; - ret.AppendPathComponent(new_path); - return ret; +FileSpec::EnumerateDirectory(llvm::StringRef dir_path, bool find_directories, + bool find_files, bool find_other, + EnumerateDirectoryCallbackType callback, + void *callback_baton) { + return ForEachItemInDirectory( + dir_path, + [&find_directories, &find_files, &find_other, &callback, + &callback_baton](FileType file_type, const FileSpec &file_spec) { + switch (file_type) { + case FileType::eFileTypeDirectory: + if (find_directories) + return callback(callback_baton, file_type, file_spec); + break; + case FileType::eFileTypeRegular: + if (find_files) + return callback(callback_baton, file_type, file_spec); + break; + default: + if (find_other) + return callback(callback_baton, file_type, file_spec); + break; + } + return eEnumerateDirectoryResultNext; + }); } FileSpec -FileSpec::CopyByRemovingLastPathComponent () const -{ - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - return FileSpec("",resolve); - if (m_directory.IsEmpty()) - return FileSpec("",resolve); - if (m_filename.IsEmpty()) - { - const char* dir_cstr = m_directory.GetCString(); - const char* last_slash_ptr = ::strrchr(dir_cstr, '/'); - - // check for obvious cases before doing the full thing - if (!last_slash_ptr) - return FileSpec("",resolve); - if (last_slash_ptr == dir_cstr) - return FileSpec("/",resolve); - - size_t last_slash_pos = last_slash_ptr - dir_cstr+1; - ConstString new_path(dir_cstr,last_slash_pos); - return FileSpec(new_path.GetCString(),resolve); +FileSpec::CopyByAppendingPathComponent(llvm::StringRef component) const { + FileSpec ret = *this; + ret.AppendPathComponent(component); + return ret; +} + +FileSpec FileSpec::CopyByRemovingLastPathComponent() const { + // CLEANUP: Use StringRef for string handling. + const bool resolve = false; + if (m_filename.IsEmpty() && m_directory.IsEmpty()) + return FileSpec("", resolve); + if (m_directory.IsEmpty()) + return FileSpec("", resolve); + if (m_filename.IsEmpty()) { + const char *dir_cstr = m_directory.GetCString(); + const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); + + // check for obvious cases before doing the full thing + if (!last_slash_ptr) + return FileSpec("", resolve); + if (last_slash_ptr == dir_cstr) + return FileSpec("/", resolve); + + size_t last_slash_pos = last_slash_ptr - dir_cstr + 1; + ConstString new_path(dir_cstr, last_slash_pos); + return FileSpec(new_path.GetCString(), resolve); + } else + return FileSpec(m_directory.GetCString(), resolve); +} + +ConstString FileSpec::GetLastPathComponent() const { + // CLEANUP: Use StringRef for string handling. + if (m_filename) + return m_filename; + if (m_directory) { + const char *dir_cstr = m_directory.GetCString(); + const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); + if (last_slash_ptr == NULL) + return m_directory; + if (last_slash_ptr == dir_cstr) { + if (last_slash_ptr[1] == 0) + return ConstString(last_slash_ptr); + else + return ConstString(last_slash_ptr + 1); } - else - return FileSpec(m_directory.GetCString(),resolve); -} - -ConstString -FileSpec::GetLastPathComponent () const -{ - if (m_filename) - return m_filename; - if (m_directory) - { - const char* dir_cstr = m_directory.GetCString(); - const char* last_slash_ptr = ::strrchr(dir_cstr, '/'); - if (last_slash_ptr == NULL) - return m_directory; - if (last_slash_ptr == dir_cstr) - { - if (last_slash_ptr[1] == 0) - return ConstString(last_slash_ptr); - else - return ConstString(last_slash_ptr+1); - } - if (last_slash_ptr[1] != 0) - return ConstString(last_slash_ptr+1); - const char* penultimate_slash_ptr = last_slash_ptr; - while (*penultimate_slash_ptr) - { - --penultimate_slash_ptr; - if (penultimate_slash_ptr == dir_cstr) - break; - if (*penultimate_slash_ptr == '/') - break; - } - ConstString result(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr); - return result; + if (last_slash_ptr[1] != 0) + return ConstString(last_slash_ptr + 1); + const char *penultimate_slash_ptr = last_slash_ptr; + while (*penultimate_slash_ptr) { + --penultimate_slash_ptr; + if (penultimate_slash_ptr == dir_cstr) + break; + if (*penultimate_slash_ptr == '/') + break; } - return ConstString(); + ConstString result(penultimate_slash_ptr + 1, + last_slash_ptr - penultimate_slash_ptr); + return result; + } + return ConstString(); } -void -FileSpec::PrependPathComponent(const char *new_path) -{ - if (!new_path) return; - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - { - SetFile(new_path, resolve); - return; - } - StreamString stream; - if (m_filename.IsEmpty()) - stream.Printf("%s/%s", new_path, m_directory.GetCString()); - else if (m_directory.IsEmpty()) - stream.Printf("%s/%s", new_path, m_filename.GetCString()); - else - stream.Printf("%s/%s/%s", new_path, m_directory.GetCString(), m_filename.GetCString()); - SetFile(stream.GetData(), resolve); -} +void FileSpec::PrependPathComponent(llvm::StringRef component) { + if (component.empty()) + return; + + const bool resolve = false; + if (m_filename.IsEmpty() && m_directory.IsEmpty()) { + SetFile(component, resolve); + return; + } + + char sep = GetPreferredPathSeparator(m_syntax); + std::string result; + if (m_filename.IsEmpty()) + result = llvm::join_items(sep, component, m_directory.GetStringRef()); + else if (m_directory.IsEmpty()) + result = llvm::join_items(sep, component, m_filename.GetStringRef()); + else + result = llvm::join_items(sep, component, m_directory.GetStringRef(), + m_filename.GetStringRef()); -void -FileSpec::PrependPathComponent(const std::string &new_path) -{ - return PrependPathComponent(new_path.c_str()); + SetFile(result, resolve); } -void -FileSpec::PrependPathComponent(const FileSpec &new_path) -{ - return PrependPathComponent(new_path.GetPath(false)); +void FileSpec::PrependPathComponent(const FileSpec &new_path) { + return PrependPathComponent(new_path.GetPath(false)); } -void -FileSpec::AppendPathComponent(const char *new_path) -{ - if (!new_path) return; - - StreamString stream; - if (!m_directory.IsEmpty()) - { - stream.PutCString(m_directory.GetCString()); - if (!IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) - stream.PutChar(GetPrefferedPathSeparator(m_syntax)); - } +void FileSpec::AppendPathComponent(llvm::StringRef component) { + if (component.empty()) + return; - if (!m_filename.IsEmpty()) - { - stream.PutCString(m_filename.GetCString()); - if (!IsPathSeparator(m_filename.GetStringRef().back(), m_syntax)) - stream.PutChar(GetPrefferedPathSeparator(m_syntax)); - } + std::string result; + if (!m_directory.IsEmpty()) { + result += m_directory.GetStringRef(); + if (!IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) + result += GetPreferredPathSeparator(m_syntax); + } - stream.PutCString(new_path); + if (!m_filename.IsEmpty()) { + result += m_filename.GetStringRef(); + if (!IsPathSeparator(m_filename.GetStringRef().back(), m_syntax)) + result += GetPreferredPathSeparator(m_syntax); + } - const bool resolve = false; - SetFile(stream.GetData(), resolve, m_syntax); -} + component = component.drop_while( + [this](char c) { return IsPathSeparator(c, m_syntax); }); + + result += component; -void -FileSpec::AppendPathComponent(const std::string &new_path) -{ - return AppendPathComponent(new_path.c_str()); + SetFile(result, false, m_syntax); } -void -FileSpec::AppendPathComponent(const FileSpec &new_path) -{ - return AppendPathComponent(new_path.GetPath(false)); +void FileSpec::AppendPathComponent(const FileSpec &new_path) { + return AppendPathComponent(new_path.GetPath(false)); } -void -FileSpec::RemoveLastPathComponent () -{ - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - { - SetFile("",resolve); - return; +void FileSpec::RemoveLastPathComponent() { + // CLEANUP: Use StringRef for string handling. + + const bool resolve = false; + if (m_filename.IsEmpty() && m_directory.IsEmpty()) { + SetFile("", resolve); + return; + } + if (m_directory.IsEmpty()) { + SetFile("", resolve); + return; + } + if (m_filename.IsEmpty()) { + const char *dir_cstr = m_directory.GetCString(); + const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); + + // check for obvious cases before doing the full thing + if (!last_slash_ptr) { + SetFile("", resolve); + return; } - if (m_directory.IsEmpty()) - { - SetFile("",resolve); - return; + if (last_slash_ptr == dir_cstr) { + SetFile("/", resolve); + return; } - if (m_filename.IsEmpty()) - { - const char* dir_cstr = m_directory.GetCString(); - const char* last_slash_ptr = ::strrchr(dir_cstr, '/'); - - // check for obvious cases before doing the full thing - if (!last_slash_ptr) - { - SetFile("",resolve); - return; - } - if (last_slash_ptr == dir_cstr) - { - SetFile("/",resolve); - return; - } - size_t last_slash_pos = last_slash_ptr - dir_cstr+1; - ConstString new_path(dir_cstr,last_slash_pos); - SetFile(new_path.GetCString(),resolve); - } - else - SetFile(m_directory.GetCString(),resolve); + size_t last_slash_pos = last_slash_ptr - dir_cstr + 1; + ConstString new_path(dir_cstr, last_slash_pos); + SetFile(new_path.GetCString(), resolve); + } else + SetFile(m_directory.GetCString(), resolve); } //------------------------------------------------------------------ /// Returns true if the filespec represents an implementation source @@ -1616,57 +1344,88 @@ FileSpec::RemoveLastPathComponent () /// \b true if the filespec represents an implementation source /// file, \b false otherwise. //------------------------------------------------------------------ -bool -FileSpec::IsSourceImplementationFile () const -{ - ConstString extension (GetFileNameExtension()); - if (extension) - { - static RegularExpression g_source_file_regex ("^([cC]|[mM]|[mM][mM]|[cC][pP][pP]|[cC]\\+\\+|[cC][xX][xX]|[cC][cC]|[cC][pP]|[sS]|[aA][sS][mM]|[fF]|[fF]77|[fF]90|[fF]95|[fF]03|[fF][oO][rR]|[fF][tT][nN]|[fF][pP][pP]|[aA][dD][aA]|[aA][dD][bB]|[aA][dD][sS])$"); - return g_source_file_regex.Execute (extension.GetCString()); - } +bool FileSpec::IsSourceImplementationFile() const { + ConstString extension(GetFileNameExtension()); + if (!extension) return false; + + static RegularExpression g_source_file_regex(llvm::StringRef( + "^([cC]|[mM]|[mM][mM]|[cC][pP][pP]|[cC]\\+\\+|[cC][xX][xX]|[cC][cC]|[" + "cC][pP]|[sS]|[aA][sS][mM]|[fF]|[fF]77|[fF]90|[fF]95|[fF]03|[fF][oO][" + "rR]|[fF][tT][nN]|[fF][pP][pP]|[aA][dD][aA]|[aA][dD][bB]|[aA][dD][sS])" + "$")); + return g_source_file_regex.Execute(extension.GetStringRef()); } -bool -FileSpec::IsRelative() const -{ - const char *dir = m_directory.GetCString(); - llvm::StringRef directory(dir ? dir : ""); - - if (directory.size() > 0) - { - if (PathSyntaxIsPosix(m_syntax)) - { - // If the path doesn't start with '/' or '~', return true - switch (directory[0]) - { - case '/': - case '~': - return false; - default: - return true; - } - } - else - { - if (directory.size() >= 2 && directory[1] == ':') - return false; - if (directory[0] == '/') - return false; - return true; - } - } - else if (m_filename) - { - // No directory, just a basename, return true +bool FileSpec::IsRelative() const { + const char *dir = m_directory.GetCString(); + llvm::StringRef directory(dir ? dir : ""); + + if (directory.size() > 0) { + if (PathSyntaxIsPosix(m_syntax)) { + // If the path doesn't start with '/' or '~', return true + switch (directory[0]) { + case '/': + case '~': + return false; + default: return true; + } + } else { + if (directory.size() >= 2 && directory[1] == ':') + return false; + if (directory[0] == '/') + return false; + return true; } - return false; + } else if (m_filename) { + // No directory, just a basename, return true + return true; + } + return false; } -bool -FileSpec::IsAbsolute() const -{ - return !FileSpec::IsRelative(); +bool FileSpec::IsAbsolute() const { return !FileSpec::IsRelative(); } + +void llvm::format_provider<FileSpec>::format(const FileSpec &F, + raw_ostream &Stream, + StringRef Style) { + assert( + (Style.empty() || Style.equals_lower("F") || Style.equals_lower("D")) && + "Invalid FileSpec style!"); + + StringRef dir = F.GetDirectory().GetStringRef(); + StringRef file = F.GetFilename().GetStringRef(); + + if (dir.empty() && file.empty()) { + Stream << "(empty)"; + return; + } + + if (Style.equals_lower("F")) { + Stream << (file.empty() ? "(empty)" : file); + return; + } + + // Style is either D or empty, either way we need to print the directory. + if (!dir.empty()) { + // Directory is stored in normalized form, which might be different + // than preferred form. In order to handle this, we need to cut off + // the filename, then denormalize, then write the entire denorm'ed + // directory. + llvm::SmallString<64> denormalized_dir = dir; + Denormalize(denormalized_dir, F.GetPathSyntax()); + Stream << denormalized_dir; + Stream << GetPreferredPathSeparator(F.GetPathSyntax()); + } + + if (Style.equals_lower("D")) { + // We only want to print the directory, so now just exit. + if (dir.empty()) + Stream << "(empty)"; + return; + } + + if (!file.empty()) + Stream << file; } |