diff options
author | emaste <emaste@FreeBSD.org> | 2015-02-06 22:25:21 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2015-02-06 22:25:21 +0000 |
commit | fa0e7b41694bc598cd3df2405d0384ea29d7537e (patch) | |
tree | 5e5b6a0774e0d93bb4cfa2f9f83b9c41b38c4448 /contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp | |
parent | d2b9c88b24f95cd9f8e7bd621cfa454ce759c687 (diff) | |
parent | 0c2019f4ca6b2dc6d710f6bb16a0e3ed10271531 (diff) | |
download | FreeBSD-src-fa0e7b41694bc598cd3df2405d0384ea29d7537e.zip FreeBSD-src-fa0e7b41694bc598cd3df2405d0384ea29d7537e.tar.gz |
Update LLDB snapshot to upstream r225923 (git 2b588ecd)
Sponsored by: DARPA, AFRL
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp | 189 |
1 files changed, 167 insertions, 22 deletions
diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp index 8c4014c..0af0556 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp @@ -56,7 +56,8 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) } // Resolves the username part of a path of the form ~user/other/directories, and -// writes the result into dst_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) { @@ -66,9 +67,9 @@ FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path) llvm::StringRef path_str(path.data()); size_t slash_pos = path_str.find_first_of("/", 1); - if (slash_pos == 1) + if (slash_pos == 1 || path.size() == 1) { - // A path of the form ~/ resolves to the current user's home dir + // A path of ~/ resolves to the current user's home dir llvm::SmallString<64> home_dir; if (!llvm::sys::path::home_directory(home_dir)) return; @@ -166,10 +167,10 @@ FileSpec::Resolve (llvm::SmallVectorImpl<char> &path) llvm::sys::fs::make_absolute(path); } -FileSpec::FileSpec() - : m_directory() - , m_filename() - , m_syntax(FileSystem::GetNativePathSyntax()) +FileSpec::FileSpec() : + m_directory(), + m_filename(), + m_syntax(FileSystem::GetNativePathSyntax()) { } @@ -180,7 +181,8 @@ FileSpec::FileSpec() FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) : m_directory(), m_filename(), - m_is_resolved(false) + m_is_resolved(false), + m_syntax(syntax) { if (pathname && pathname[0]) SetFile(pathname, resolve_path, syntax); @@ -266,14 +268,18 @@ FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax) return; llvm::SmallString<64> normalized(pathname); - Normalize(normalized, syntax); if (resolve) { FileSpec::Resolve (normalized); m_is_resolved = true; } - + + // Only normalize after resolving the path. Resolution will modify the path + // string, potentially adding wrong kinds of slashes to the path, that need + // to be re-normalized. + Normalize(normalized, syntax); + llvm::StringRef resolve_path_ref(normalized.c_str()); llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref); if (!filename_ref.empty()) @@ -446,15 +452,129 @@ FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full) } bool -FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full) +FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_backups) { if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty())) return a.m_filename == b.m_filename; - else + else if (remove_backups == false) return a == b; + else + { + if (a.m_filename != b.m_filename) + return false; + if (a.m_directory == b.m_directory) + return true; + ConstString a_without_dots; + ConstString b_without_dots; + + RemoveBackupDots (a.m_directory, a_without_dots); + RemoveBackupDots (b.m_directory, b_without_dots); + return a_without_dots == b_without_dots; + } } +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; + + 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::StringRef backup_sep; + if (is_win) + { + found_sep = win_sep; + backup_sep = win_backup; + } + else + { + found_sep = unix_sep; + backup_sep = unix_backup; + } + + 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) + { + 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; +} //------------------------------------------------------------------ // Dump the object to the supplied stream. If the object contains @@ -502,7 +622,10 @@ FileSpec::ResolveExecutableLocation () if (file_cstr) { const std::string file_str (file_cstr); - std::string path = llvm::sys::FindProgramByName (file_str); + 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()) { @@ -946,6 +1069,8 @@ FileSpec::EnumerateDirectory 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) @@ -990,7 +1115,14 @@ FileSpec::EnumerateDirectory if (call_callback) { char child_path[PATH_MAX]; - const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name); + + // 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 @@ -1208,18 +1340,31 @@ FileSpec::IsSourceImplementationFile () const bool FileSpec::IsRelativeToCurrentWorkingDirectory () const { - const char *directory = m_directory.GetCString(); - if (directory && directory[0]) + const char *dir = m_directory.GetCString(); + llvm::StringRef directory(dir ? dir : ""); + + if (directory.size() > 0) { - // If the path doesn't start with '/' or '~', return true - switch (directory[0]) + if (m_syntax == ePathSyntaxWindows) { - case '/': - case '~': - return false; - default: + if (directory.size() >= 2 && directory[1] == ':') + return false; + if (directory[0] == '/') + return false; return true; } + else + { + // If the path doesn't start with '/' or '~', return true + switch (directory[0]) + { + case '/': + case '~': + return false; + default: + return true; + } + } } else if (m_filename) { |