Index: include/lldb/Host/FileSpec.h =================================================================== --- include/lldb/Host/FileSpec.h +++ include/lldb/Host/FileSpec.h @@ -51,6 +51,13 @@ eFileTypeOther } FileType; + enum PathSyntax + { + ePathSyntaxPosix, + ePathSyntaxWindows, + ePathSyntaxHostNative + }; + FileSpec(); //------------------------------------------------------------------ @@ -69,7 +76,7 @@ /// /// @see FileSpec::SetFile (const char *path, bool resolve) //------------------------------------------------------------------ - explicit FileSpec (const char *path, bool resolve_path); + explicit FileSpec (const char *path, bool resolve_path, PathSyntax syntax = ePathSyntaxHostNative); //------------------------------------------------------------------ /// Copy constructor @@ -291,6 +298,9 @@ uint64_t GetByteSize() const; + PathSyntax + GetPathSyntax() const; + //------------------------------------------------------------------ /// Directory string get accessor. /// @@ -375,7 +385,7 @@ /// still NULL terminated). //------------------------------------------------------------------ size_t - GetPath (char *path, size_t max_path_length) const; + GetPath (char *path, size_t max_path_length, bool denormalize = true) const; //------------------------------------------------------------------ /// Extract the full path to the file. @@ -387,7 +397,7 @@ /// concatenated. //------------------------------------------------------------------ std::string - GetPath () const; + GetPath (bool denormalize = true) const; //------------------------------------------------------------------ /// Extract the extension of the file. @@ -559,6 +569,10 @@ //------------------------------------------------------------------ lldb::DataBufferSP ReadFileContentsAsCString(Error *error_ptr = NULL); + + static void Normalize(llvm::StringRef path, llvm::SmallVectorImpl &result, PathSyntax syntax); + static void DeNormalize(llvm::StringRef path, llvm::SmallVectorImpl &result, PathSyntax syntax); + //------------------------------------------------------------------ /// Change the file specified with a new path. /// @@ -574,7 +588,7 @@ /// the static FileSpec::Resolve. //------------------------------------------------------------------ void - SetFile (const char *path, bool resolve_path); + SetFile (const char *path, bool resolve_path, PathSyntax syntax = ePathSyntaxHostNative); bool IsResolved () const @@ -709,6 +723,7 @@ ConstString m_directory; ///< The uniqued directory path ConstString m_filename; ///< The uniqued filename path mutable bool m_is_resolved; ///< True if this path has been resolved. + PathSyntax m_syntax; ///< The syntax that this path uses (e.g. Windows / Posix) }; //---------------------------------------------------------------------- Index: include/lldb/Host/Host.h =================================================================== --- include/lldb/Host/Host.h +++ include/lldb/Host/Host.h @@ -362,6 +362,15 @@ SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name, size_t len); //------------------------------------------------------------------ + /// Gets the host environment's native path syntax (Windows / Posix). + /// + /// @return + /// \b One of {FileSpec::ePathSyntaxWindows, FileSpec::ePathSyntaxPosix} + //------------------------------------------------------------------ + static FileSpec::PathSyntax + GetHostPathSyntax(); + + //------------------------------------------------------------------ /// Gets the FileSpec of the user profile directory. On Posix-platforms /// this is ~, and on windows this is generally something like /// C:\Users\Alice. Index: source/Host/common/FileSpec.cpp =================================================================== --- source/Host/common/FileSpec.cpp +++ source/Host/common/FileSpec.cpp @@ -237,13 +237,13 @@ // 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); } //------------------------------------------------------------------ @@ -289,42 +289,66 @@ 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 +358,7 @@ m_directory.SetString(directory_ref); } else - m_directory.SetCString(resolved_path); + m_directory.SetCString(&resolved_path[0]); } } @@ -580,7 +604,7 @@ 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 +620,12 @@ return 0; } +FileSpec::PathSyntax +FileSpec::GetPathSyntax() const +{ + return m_syntax; +} + FileSpec::FileType FileSpec::GetFileType () const { @@ -681,45 +711,31 @@ // 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 Index: source/Host/common/Host.cpp =================================================================== --- source/Host/common/Host.cpp +++ source/Host/common/Host.cpp @@ -825,6 +825,16 @@ #endif +FileSpec::PathSyntax +Host::GetHostPathSyntax() +{ +#if defined(_WIN32) + return FileSpec::ePathSyntaxWindows; +#else + return FileSpec::ePathSyntaxPosix; +#endif +} + FileSpec Host::GetUserProfileFileSpec () { @@ -881,7 +891,7 @@ #elif defined(_WIN32) std::vector buffer(PATH_MAX); ::GetModuleFileName(NULL, &buffer[0], buffer.size()); - g_program_filespec.SetFile(&buffer[0], false, FileSpec::ePathSyntaxWindows); + g_program_filespec.SetFile(&buffer[0], false); #endif } return g_program_filespec;