From df62f20c75d0984aac06b8b998988eb91262e43c Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Thu, 7 Aug 2014 17:33:07 +0000 Subject: Fix FileSpec to be able to understand Windows paths. This patch adds the notion of a "path syntax" to FileSpec. There are two syntaxes (Posix and Windows) and one "meta syntax", Host Native, which uses the current platform to figure out the appropriate syntax for host paths. This allows paths from one platform to be represented and manipulated on another platform even if they have different path syntaxes. llvm-svn: 215123 --- lldb/source/Host/common/FileSpec.cpp | 109 ++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 45 deletions(-) (limited to 'lldb/source/Host/common/FileSpec.cpp') diff --git a/lldb/source/Host/common/FileSpec.cpp b/lldb/source/Host/common/FileSpec.cpp index 44eb3af118f..845a3183001 100644 --- a/lldb/source/Host/common/FileSpec.cpp +++ b/lldb/source/Host/common/FileSpec.cpp @@ -229,7 +229,8 @@ FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len) FileSpec::FileSpec() : m_directory(), - m_filename() + m_filename(), + m_syntax(Host::GetHostPathSyntax()) { } @@ -237,13 +238,13 @@ FileSpec::FileSpec() : // Default constructor that can take an optional full path to a // file on disk. //------------------------------------------------------------------ -FileSpec::FileSpec(const char *pathname, bool resolve_path) : +FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) : m_directory(), m_filename(), m_is_resolved(false) { if (pathname && pathname[0]) - SetFile(pathname, resolve_path); + SetFile(pathname, resolve_path, syntax); } //------------------------------------------------------------------ @@ -252,7 +253,8 @@ FileSpec::FileSpec(const char *pathname, bool resolve_path) : FileSpec::FileSpec(const FileSpec& rhs) : m_directory (rhs.m_directory), m_filename (rhs.m_filename), - m_is_resolved (rhs.m_is_resolved) + m_is_resolved (rhs.m_is_resolved), + m_syntax (rhs.m_syntax) { } @@ -285,46 +287,71 @@ FileSpec::operator= (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; } return *this; } +void FileSpec::Normalize(llvm::StringRef path, llvm::SmallVectorImpl &result, PathSyntax syntax) +{ + result.clear(); + result.append(path.begin(), path.end()); + if (syntax == ePathSyntaxPosix || (syntax == ePathSyntaxHostNative && Host::GetHostPathSyntax() == ePathSyntaxPosix)) + return; + + std::replace(result.begin(), result.end(), '\\', '/'); +} + +void FileSpec::DeNormalize(llvm::StringRef path, llvm::SmallVectorImpl &result, PathSyntax syntax) +{ + result.clear(); + result.append(path.begin(), path.end()); + if (syntax == ePathSyntaxPosix || (syntax == ePathSyntaxHostNative && Host::GetHostPathSyntax() == ePathSyntaxPosix)) + return; + + std::replace(result.begin(), result.end(), '/', '\\'); +} + //------------------------------------------------------------------ // Update the contents of this object with a new path. The path will // 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) +FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax) { m_filename.Clear(); m_directory.Clear(); m_is_resolved = false; + m_syntax = (syntax == ePathSyntaxHostNative) ? Host::GetHostPathSyntax() : syntax; + if (pathname == NULL || pathname[0] == '\0') return; - char resolved_path[PATH_MAX]; + llvm::SmallString<64> normalized; + Normalize(pathname, normalized, syntax); + + std::vector resolved_path(PATH_MAX); bool path_fit = true; if (resolve) { - path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1); + path_fit = (FileSpec::Resolve (normalized.c_str(), &resolved_path[0], resolved_path.size()) < resolved_path.size() - 1); m_is_resolved = path_fit; } else { // Copy the path because "basename" and "dirname" want to muck with the // path buffer - if (::strlen (pathname) > sizeof(resolved_path) - 1) + if (normalized.size() > resolved_path.size() - 1) path_fit = false; else - ::strcpy (resolved_path, pathname); + ::strcpy (&resolved_path[0], normalized.c_str()); } - if (path_fit) { - llvm::StringRef resolve_path_ref(resolved_path); + llvm::StringRef resolve_path_ref(&resolved_path[0]); llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref); if (!filename_ref.empty()) { @@ -334,7 +361,7 @@ FileSpec::SetFile (const char *pathname, bool resolve) m_directory.SetString(directory_ref); } else - m_directory.SetCString(resolved_path); + m_directory.SetCString(&resolved_path[0]); } } @@ -580,7 +607,7 @@ FileSpec::ResolvePath () return true; // We have already resolved this path char path_buf[PATH_MAX]; - if (!GetPath (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); @@ -596,6 +623,12 @@ FileSpec::GetByteSize() const return 0; } +FileSpec::PathSyntax +FileSpec::GetPathSyntax() const +{ + return m_syntax; +} + FileSpec::FileType FileSpec::GetFileType () const { @@ -681,45 +714,31 @@ FileSpec::GetFilename() const // values. //------------------------------------------------------------------ size_t -FileSpec::GetPath(char *path, size_t path_max_len) const +FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const { - if (path_max_len) - { - const char *dirname = m_directory.GetCString(); - const char *filename = m_filename.GetCString(); - if (dirname) - { - if (filename) - return ::snprintf (path, path_max_len, "%s/%s", dirname, filename); - else - return ::snprintf (path, path_max_len, "%s", dirname); - } - else if (filename) - { - return ::snprintf (path, path_max_len, "%s", filename); - } - } - if (path) - path[0] = '\0'; - return 0; + std::string result = GetPath(denormalize); + + size_t result_length = std::min(path_max_len-1, result.length()); + ::strncpy(path, result.c_str(), result_length + 1); + return result_length; } std::string -FileSpec::GetPath (void) const +FileSpec::GetPath (bool denormalize) const { - static ConstString g_slash_only ("/"); - std::string path; - const char *dirname = m_directory.GetCString(); - const char *filename = m_filename.GetCString(); - if (dirname) + llvm::SmallString<64> result; + if (m_directory) + result.append(m_directory.GetCString()); + if (m_filename) + llvm::sys::path::append(result, m_filename.GetCString()); + if (denormalize && !result.empty()) { - path.append (dirname); - if (filename && m_directory != g_slash_only) - path.append ("/"); + llvm::SmallString<64> denormalized; + DeNormalize(result.c_str(), denormalized, m_syntax); + result = denormalized; } - if (filename) - path.append (filename); - return path; + + return std::string(result.begin(), result.end()); } ConstString -- cgit v1.2.3