namespace sys {
namespace path {
-enum class Style { windows, posix, native };
+enum class Style {
+ native,
+ posix,
+ windows_slash,
+ windows_backslash,
+ windows = windows_backslash, // deprecated
+};
/// Check if \p S uses POSIX path rules.
constexpr bool is_style_posix(Style S) {
/// @param path A path that is transformed to native format.
void native(SmallVectorImpl<char> &path, Style style = Style::native);
+/// For Windows path styles, convert path to use the preferred path separators.
+/// For other styles, do nothing.
+///
+/// @param path A path that is transformed to preferred format.
+inline void make_preferred(SmallVectorImpl<char> &path,
+ Style style = Style::native) {
+ if (!is_style_windows(style))
+ return;
+ native(path, style);
+}
+
/// Replaces backslashes with slashes if Windows.
///
/// @param path processed path
using llvm::sys::path::Style;
inline Style real_style(Style style) {
+ if (style != Style::native)
+ return style;
if (is_style_posix(style))
return Style::posix;
return Style::windows;
}
inline const char *separators(Style style) {
- if (real_style(style) == Style::windows)
+ if (is_style_windows(style))
return "\\/";
return "/";
}
if (Path.empty())
return;
if (is_style_windows(style)) {
- std::replace(Path.begin(), Path.end(), '/', '\\');
+ for (char &Ch : Path)
+ if (is_separator(Ch, style))
+ Ch = preferred_separator(style);
if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
SmallString<128> PathHome;
home_directory(PathHome);
}
StringRef get_separator(Style style) {
- if (is_style_windows(style))
+ if (real_style(style) == Style::windows)
return "\\";
return "/";
}
// Check platform-independent results.
EXPECT_TRUE(is_style_posix(Style::posix));
EXPECT_TRUE(is_style_windows(Style::windows));
+ EXPECT_TRUE(is_style_windows(Style::windows_slash));
EXPECT_FALSE(is_style_posix(Style::windows));
+ EXPECT_FALSE(is_style_posix(Style::windows_slash));
EXPECT_FALSE(is_style_windows(Style::posix));
// Check platform-dependent results.
EXPECT_FALSE(path::is_separator(' '));
EXPECT_TRUE(path::is_separator('\\', path::Style::windows));
+ EXPECT_TRUE(path::is_separator('\\', path::Style::windows_slash));
EXPECT_FALSE(path::is_separator('\\', path::Style::posix));
EXPECT_EQ(path::is_style_windows(path::Style::native),
path::is_separator('\\'));
}
+TEST(get_separator, Works) {
+ EXPECT_EQ(path::get_separator(path::Style::posix), "/");
+ EXPECT_EQ(path::get_separator(path::Style::windows_backslash), "\\");
+ EXPECT_EQ(path::get_separator(path::Style::windows_slash), "/");
+}
+
TEST(is_absolute_gnu, Works) {
// Test tuple <Path, ExpectedPosixValue, ExpectedWindowsValue>.
const std::tuple<StringRef, bool, bool> Paths[] = {
testing::ElementsAre("/", ".c", ".d", "..", "."));
EXPECT_THAT(GetComponents("c:\\c\\e\\foo.txt", path::Style::windows),
testing::ElementsAre("c:", "\\", "c", "e", "foo.txt"));
+ EXPECT_THAT(GetComponents("c:\\c\\e\\foo.txt", path::Style::windows_slash),
+ testing::ElementsAre("c:", "\\", "c", "e", "foo.txt"));
EXPECT_THAT(GetComponents("//net/"), testing::ElementsAre("//net", "/"));
EXPECT_THAT(GetComponents("//net/c/foo.txt"),
testing::ElementsAre("//net", "/", "c", "foo.txt"));
for (auto &T : Tests) {
SmallString<64> Win(std::get<0>(T));
SmallString<64> Posix(Win);
+ SmallString<64> WinSlash(Win);
path::native(Win, path::Style::windows);
path::native(Posix, path::Style::posix);
+ path::native(WinSlash, path::Style::windows_slash);
EXPECT_EQ(std::get<1>(T), Win);
EXPECT_EQ(std::get<2>(T), Posix);
+ EXPECT_EQ(std::get<2>(T), WinSlash);
+ }
+
+ for (auto &T : Tests) {
+ SmallString<64> WinBackslash(std::get<0>(T));
+ SmallString<64> Posix(WinBackslash);
+ SmallString<64> WinSlash(WinBackslash);
+ path::make_preferred(WinBackslash, path::Style::windows_backslash);
+ path::make_preferred(Posix, path::Style::posix);
+ path::make_preferred(WinSlash, path::Style::windows_slash);
+ EXPECT_EQ(std::get<1>(T), WinBackslash);
+ EXPECT_EQ(std::get<0>(T), Posix); // Posix remains unchanged here
+ EXPECT_EQ(std::get<2>(T), WinSlash);
}
#if defined(_WIN32)
const char *Path7a = "~/aaa";
SmallString<64> Path7(Path7a);
- path::native(Path7);
+ path::native(Path7, path::Style::windows_backslash);
EXPECT_TRUE(Path7.endswith("\\aaa"));
EXPECT_TRUE(Path7.startswith(PathHome));
EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1));
+ Path7 = Path7a;
+ path::native(Path7, path::Style::windows_slash);
+ EXPECT_TRUE(Path7.endswith("/aaa"));
+ EXPECT_TRUE(Path7.startswith(PathHome));
+ EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1));
const char *Path8a = "~";
SmallString<64> Path8(Path8a);
const char *Path10a = "aaa/~/b";
SmallString<64> Path10(Path10a);
- path::native(Path10);
+ path::native(Path10, path::Style::windows_backslash);
EXPECT_EQ(Path10, "aaa\\~\\b");
#endif
}