This revision was automatically updated to reflect the committed changes.
Closed by commit rL265299: Make FileSpec handling platform-independent 
(authored by labath).

Changed prior to commit:
  http://reviews.llvm.org/D18689?vs=52348&id=52556#toc

Repository:
  rL LLVM

http://reviews.llvm.org/D18689

Files:
  lldb/trunk/source/Host/common/FileSpec.cpp
  lldb/trunk/unittests/Host/FileSpecTest.cpp

Index: lldb/trunk/unittests/Host/FileSpecTest.cpp
===================================================================
--- lldb/trunk/unittests/Host/FileSpecTest.cpp
+++ lldb/trunk/unittests/Host/FileSpecTest.cpp
@@ -22,18 +22,23 @@
 
     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);
     EXPECT_STREQ("/", fs_posix_root.GetCString());
     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 @@
     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 @@
     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,22 +71,22 @@
     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");
     EXPECT_STREQ("/bar", fs_posix_root.GetCString());
     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());
 }
 
Index: lldb/trunk/source/Host/common/FileSpec.cpp
===================================================================
--- lldb/trunk/source/Host/common/FileSpec.cpp
+++ lldb/trunk/source/Host/common/FileSpec.cpp
@@ -57,10 +57,22 @@
              FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix));
 }
 
+const char *
+GetPathSeparators(FileSpec::PathSyntax syntax)
+{
+    return PathSyntaxIsPosix(syntax) ? "/" : "\\/";
+}
+
 char
-GetPathSeparator(FileSpec::PathSyntax syntax)
+GetPrefferedPathSeparator(FileSpec::PathSyntax syntax)
+{
+    return GetPathSeparators(syntax)[0];
+}
+
+bool
+IsPathSeparator(char value, FileSpec::PathSyntax syntax)
 {
-    return PathSyntaxIsPosix(syntax) ? '/' : '\\';
+    return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\');
 }
 
 void
@@ -94,8 +106,69 @@
     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 @@
     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())
-    {
-        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);
+    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;
     }
-    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 @@
     {
         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 @@
 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 @@
     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);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to