summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2016-04-04 14:39:12 +0000
committerPavel Labath <labath@google.com>2016-04-04 14:39:12 +0000
commit144119b86d647f405159259bf4fbf5499578d648 (patch)
treefb961cf682fd35dd03348281de58e0d4f263e9d2
parent09464e63d842e1e0e6be300b6bb59bc9c1e7ecdf (diff)
downloadbcm5719-llvm-144119b86d647f405159259bf4fbf5499578d648.tar.gz
bcm5719-llvm-144119b86d647f405159259bf4fbf5499578d648.zip
Make FileSpec handling platform-independent
Summary: Even though FileSpec attempted to handle both kinds of path syntaxes (posix and windows) on both platforms, it relied on the llvm path library to do its work, whose behavior differed on different platforms. This led to subtle differences in FileSpec behavior between platforms. This replaces the pieces of the llvm library with our own implementations. The functions are simply copied from llvm, with #ifdefs replaced by runtime checks for ePathSyntaxWindows. Reviewers: zturner Subscribers: lldb-commits Differential Revision: http://reviews.llvm.org/D18689 llvm-svn: 265299
-rw-r--r--lldb/source/Host/common/FileSpec.cpp126
-rw-r--r--lldb/unittests/Host/FileSpecTest.cpp33
2 files changed, 119 insertions, 40 deletions
diff --git a/lldb/source/Host/common/FileSpec.cpp b/lldb/source/Host/common/FileSpec.cpp
index abfd5351350..0718b970603 100644
--- a/lldb/source/Host/common/FileSpec.cpp
+++ b/lldb/source/Host/common/FileSpec.cpp
@@ -57,10 +57,22 @@ PathSyntaxIsPosix(FileSpec::PathSyntax syntax)
FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix));
}
+const char *
+GetPathSeparators(FileSpec::PathSyntax syntax)
+{
+ return PathSyntaxIsPosix(syntax) ? "/" : "\\/";
+}
+
char
-GetPathSeparator(FileSpec::PathSyntax syntax)
+GetPrefferedPathSeparator(FileSpec::PathSyntax syntax)
{
- return PathSyntaxIsPosix(syntax) ? '/' : '\\';
+ return GetPathSeparators(syntax)[0];
+}
+
+bool
+IsPathSeparator(char value, FileSpec::PathSyntax syntax)
+{
+ return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\');
}
void
@@ -94,8 +106,69 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
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;
+
+ if (str.size() > 0 && IsPathSeparator(str.back(), syntax))
+ return 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 (pos == llvm::StringRef::npos || (pos == 1 && IsPathSeparator(str[0], syntax)))
+ return 0;
+
+ 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;
+
+ // 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 "/"
+ if (str.size() > 0 && IsPathSeparator(str[0], syntax))
+ return 0;
+
+ return llvm::StringRef::npos;
+}
+
+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);
+
+ // 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;
+
+ if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
+ return llvm::StringRef::npos;
+
+ 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.
@@ -313,30 +386,32 @@ FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax)
if (pathname == NULL || pathname[0] == '\0')
return;
- llvm::SmallString<64> normalized(pathname);
+ llvm::SmallString<64> resolved(pathname);
if (resolve)
{
- FileSpec::Resolve (normalized);
+ FileSpec::Resolve (resolved);
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())
+ llvm::StringRef resolve_path_ref(resolved.c_str());
+ size_t dir_end = ParentPathEnd(resolve_path_ref, syntax);
+ if (dir_end == 0)
{
- m_filename.SetString (filename_ref);
- llvm::StringRef directory_ref = llvm::sys::path::parent_path(resolve_path_ref);
- if (!directory_ref.empty())
- m_directory.SetString(directory_ref);
+ m_filename.SetString(resolve_path_ref);
+ return;
}
- else
- m_directory.SetCString(normalized.c_str());
+
+ m_directory.SetString(resolve_path_ref.substr(0, dir_end));
+
+ 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));
}
void
@@ -683,7 +758,7 @@ FileSpec::Dump(Stream *s) const
{
std::string path{GetPath(true)};
s->PutCString(path.c_str());
- char path_separator = GetPathSeparator(m_syntax);
+ char path_separator = GetPrefferedPathSeparator(m_syntax);
if (!m_filename && !path.empty() && path.back() != path_separator)
s->PutChar(path_separator);
}
@@ -916,11 +991,10 @@ void
FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, bool denormalize) const
{
path.append(m_directory.GetStringRef().begin(), m_directory.GetStringRef().end());
- if (m_directory && !(m_directory.GetLength() == 1 && m_directory.GetCString()[0] == '/'))
- path.insert(path.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 (path.size() > 1 && path.back() == '/') path.pop_back();
if (denormalize && !path.empty())
Denormalize(path, m_syntax);
}
@@ -1451,15 +1525,15 @@ FileSpec::AppendPathComponent(const char *new_path)
if (!m_directory.IsEmpty())
{
stream.PutCString(m_directory.GetCString());
- if (m_directory.GetLength() != 1 || m_directory.GetCString()[0] != '/')
- stream.PutChar('/');
+ if (!IsPathSeparator(m_directory.GetStringRef().back(), m_syntax))
+ stream.PutChar(GetPrefferedPathSeparator(m_syntax));
}
if (!m_filename.IsEmpty())
{
stream.PutCString(m_filename.GetCString());
- if (m_filename.GetLength() != 1 || m_filename.GetCString()[0] != '/')
- stream.PutChar('/');
+ if (!IsPathSeparator(m_filename.GetStringRef().back(), m_syntax))
+ stream.PutChar(GetPrefferedPathSeparator(m_syntax));
}
stream.PutCString(new_path);
diff --git a/lldb/unittests/Host/FileSpecTest.cpp b/lldb/unittests/Host/FileSpecTest.cpp
index 461be60ff13..89092c4604d 100644
--- a/lldb/unittests/Host/FileSpecTest.cpp
+++ b/lldb/unittests/Host/FileSpecTest.cpp
@@ -22,7 +22,7 @@ TEST(FileSpecTest, FileAndDirectoryComponents)
FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
EXPECT_STREQ("F:\\bar", fs_windows.GetCString());
- EXPECT_STREQ("F:", fs_windows.GetDirectory().GetCString());
+ EXPECT_STREQ("F:\\", fs_windows.GetDirectory().GetCString());
EXPECT_STREQ("bar", fs_windows.GetFilename().GetCString());
FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
@@ -30,10 +30,15 @@ TEST(FileSpecTest, FileAndDirectoryComponents)
EXPECT_EQ(nullptr, fs_posix_root.GetDirectory().GetCString());
EXPECT_STREQ("/", fs_posix_root.GetFilename().GetCString());
- FileSpec fs_windows_root("F:", false, FileSpec::ePathSyntaxWindows);
- EXPECT_STREQ("F:", fs_windows_root.GetCString());
- EXPECT_EQ(nullptr, fs_windows_root.GetDirectory().GetCString());
- EXPECT_STREQ("F:", fs_windows_root.GetFilename().GetCString());
+ FileSpec fs_windows_drive("F:", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:", fs_windows_drive.GetCString());
+ EXPECT_EQ(nullptr, fs_windows_drive.GetDirectory().GetCString());
+ EXPECT_STREQ("F:", fs_windows_drive.GetFilename().GetCString());
+
+ FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:\\", fs_windows_root.GetCString());
+ EXPECT_STREQ("F:", fs_windows_root.GetDirectory().GetCString());
+ EXPECT_STREQ("\\", fs_windows_root.GetFilename().GetCString());
FileSpec fs_posix_long("/foo/bar/baz", false, FileSpec::ePathSyntaxPosix);
EXPECT_STREQ("/foo/bar/baz", fs_posix_long.GetCString());
@@ -43,7 +48,7 @@ TEST(FileSpecTest, FileAndDirectoryComponents)
FileSpec fs_windows_long("F:\\bar\\baz", false, FileSpec::ePathSyntaxWindows);
EXPECT_STREQ("F:\\bar\\baz", fs_windows_long.GetCString());
// We get "F:/bar" instead.
- // EXPECT_STREQ("F:\\bar", fs_windows_long.GetDirectory().GetCString());
+ EXPECT_STREQ("F:\\bar", fs_windows_long.GetDirectory().GetCString());
EXPECT_STREQ("baz", fs_windows_long.GetFilename().GetCString());
FileSpec fs_posix_trailing_slash("/foo/bar/", false, FileSpec::ePathSyntaxPosix);
@@ -54,7 +59,7 @@ TEST(FileSpecTest, FileAndDirectoryComponents)
FileSpec fs_windows_trailing_slash("F:\\bar\\", false, FileSpec::ePathSyntaxWindows);
EXPECT_STREQ("F:\\bar\\.", fs_windows_trailing_slash.GetCString());
// We get "F:/bar" instead.
- // EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetDirectory().GetCString());
+ EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetDirectory().GetCString());
EXPECT_STREQ(".", fs_windows_trailing_slash.GetFilename().GetCString());
}
@@ -66,11 +71,11 @@ TEST(FileSpecTest, AppendPathComponent)
EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
- FileSpec fs_windows("F:", false, FileSpec::ePathSyntaxWindows);
- fs_windows.AppendPathComponent("bar");
- EXPECT_STREQ("F:\\bar", fs_windows.GetCString());
- EXPECT_STREQ("F:", fs_windows.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs_windows.GetFilename().GetCString());
+ FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
+ fs_windows.AppendPathComponent("baz");
+ EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
+ EXPECT_STREQ("F:\\bar", fs_windows.GetDirectory().GetCString());
+ EXPECT_STREQ("baz", fs_windows.GetFilename().GetCString());
FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
fs_posix_root.AppendPathComponent("bar");
@@ -78,10 +83,10 @@ TEST(FileSpecTest, AppendPathComponent)
EXPECT_STREQ("/", fs_posix_root.GetDirectory().GetCString());
EXPECT_STREQ("bar", fs_posix_root.GetFilename().GetCString());
- FileSpec fs_windows_root("F:", false, FileSpec::ePathSyntaxWindows);
+ FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
fs_windows_root.AppendPathComponent("bar");
EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
- EXPECT_STREQ("F:", fs_windows_root.GetDirectory().GetCString());
+ EXPECT_STREQ("F:\\", fs_windows_root.GetDirectory().GetCString());
EXPECT_STREQ("bar", fs_windows_root.GetFilename().GetCString());
}
OpenPOWER on IntegriCloud