namespace sys {
namespace path {
+enum class Style { windows, posix, native };
+
/// @name Lexical Component Iterator
/// @{
StringRef Path; ///< The entire path.
StringRef Component; ///< The current component. Not necessarily in Path.
size_t Position; ///< The iterators current position within Path.
+ Style S; ///< The path style to use.
// An end iterator has Position = Path.size() + 1.
- friend const_iterator begin(StringRef path);
+ friend const_iterator begin(StringRef path, Style style);
friend const_iterator end(StringRef path);
public:
StringRef Path; ///< The entire path.
StringRef Component; ///< The current component. Not necessarily in Path.
size_t Position; ///< The iterators current position within Path.
+ Style S; ///< The path style to use.
- friend reverse_iterator rbegin(StringRef path);
+ friend reverse_iterator rbegin(StringRef path, Style style);
friend reverse_iterator rend(StringRef path);
public:
/// @brief Get begin iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized with the first component of \a path.
-const_iterator begin(StringRef path);
+const_iterator begin(StringRef path, Style style = Style::native);
/// @brief Get end iterator over \a path.
/// @param path Input path.
/// @brief Get reverse begin iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized with the first reverse component of \a path.
-reverse_iterator rbegin(StringRef path);
+reverse_iterator rbegin(StringRef path, Style style = Style::native);
/// @brief Get reverse end iterator over \a path.
/// @param path Input path.
/// @endcode
///
/// @param path A path that is modified to not have a file component.
-void remove_filename(SmallVectorImpl<char> &path);
+void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native);
/// @brief Replace the file extension of \a path with \a extension.
///
/// @param extension The extension to be added. It may be empty. It may also
/// optionally start with a '.', if it does not, one will be
/// prepended.
-void replace_extension(SmallVectorImpl<char> &path, const Twine &extension);
+void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
+ Style style = Style::native);
/// @brief Replace matching path prefix with another path.
///
/// @param OldPrefix The path prefix to strip from \a Path.
/// @param NewPrefix The path prefix to replace \a NewPrefix with.
void replace_path_prefix(SmallVectorImpl<char> &Path,
- const StringRef &OldPrefix,
- const StringRef &NewPrefix);
+ const StringRef &OldPrefix, const StringRef &NewPrefix,
+ Style style = Style::native);
/// @brief Append to path.
///
const Twine &c = "",
const Twine &d = "");
+void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
+ const Twine &b = "", const Twine &c = "", const Twine &d = "");
+
/// @brief Append to path.
///
/// @code
/// @param path Set to \a path + [\a begin, \a end).
/// @param begin Start of components to append.
/// @param end One past the end of components to append.
-void append(SmallVectorImpl<char> &path,
- const_iterator begin, const_iterator end);
+void append(SmallVectorImpl<char> &path, const_iterator begin,
+ const_iterator end, Style style = Style::native);
/// @}
/// @name Transforms (or some other better name)
///
/// @param path A path that is transformed to native format.
/// @param result Holds the result of the transformation.
-void native(const Twine &path, SmallVectorImpl<char> &result);
+void native(const Twine &path, SmallVectorImpl<char> &result,
+ Style style = Style::native);
/// Convert path to the native form in place. This is used to give paths to
/// users and operating system calls in the platform's normal way. For example,
/// on Windows all '/' are converted to '\'.
///
/// @param path A path that is transformed to native format.
-void native(SmallVectorImpl<char> &path);
+void native(SmallVectorImpl<char> &path, Style style = Style::native);
/// @brief Replaces backslashes with slashes if Windows.
///
/// @result The result of replacing backslashes with forward slashes if Windows.
/// On Unix, this function is a no-op because backslashes are valid path
/// chracters.
-std::string convert_to_slash(StringRef path);
+std::string convert_to_slash(StringRef path, Style style = Style::native);
/// @}
/// @name Lexical Observers
///
/// @param path Input path.
/// @result The root name of \a path if it has one, otherwise "".
-StringRef root_name(StringRef path);
+StringRef root_name(StringRef path, Style style = Style::native);
/// @brief Get root directory.
///
/// @param path Input path.
/// @result The root directory of \a path if it has one, otherwise
/// "".
-StringRef root_directory(StringRef path);
+StringRef root_directory(StringRef path, Style style = Style::native);
/// @brief Get root path.
///
///
/// @param path Input path.
/// @result The root path of \a path if it has one, otherwise "".
-StringRef root_path(StringRef path);
+StringRef root_path(StringRef path, Style style = Style::native);
/// @brief Get relative path.
///
///
/// @param path Input path.
/// @result The path starting after root_path if one exists, otherwise "".
-StringRef relative_path(StringRef path);
+StringRef relative_path(StringRef path, Style style = Style::native);
/// @brief Get parent path.
///
///
/// @param path Input path.
/// @result The parent path of \a path if one exists, otherwise "".
-StringRef parent_path(StringRef path);
+StringRef parent_path(StringRef path, Style style = Style::native);
/// @brief Get filename.
///
/// @param path Input path.
/// @result The filename part of \a path. This is defined as the last component
/// of \a path.
-StringRef filename(StringRef path);
+StringRef filename(StringRef path, Style style = Style::native);
/// @brief Get stem.
///
///
/// @param path Input path.
/// @result The stem of \a path.
-StringRef stem(StringRef path);
+StringRef stem(StringRef path, Style style = Style::native);
/// @brief Get extension.
///
///
/// @param path Input path.
/// @result The extension of \a path.
-StringRef extension(StringRef path);
+StringRef extension(StringRef path, Style style = Style::native);
/// @brief Check whether the given char is a path separator on the host OS.
///
/// @param value a character
/// @result true if \a value is a path separator character on the host OS
-bool is_separator(char value);
+bool is_separator(char value, Style style = Style::native);
/// @brief Return the preferred separator for this platform.
///
/// @result StringRef of the preferred separator, null-terminated.
-StringRef get_separator();
+StringRef get_separator(Style style = Style::native);
/// @brief Get the typical temporary directory for the system, e.g.,
/// "/var/tmp" or "C:/TEMP"
///
/// @param path Input path.
/// @result True if the path has a root name, false otherwise.
-bool has_root_name(const Twine &path);
+bool has_root_name(const Twine &path, Style style = Style::native);
/// @brief Has root directory?
///
///
/// @param path Input path.
/// @result True if the path has a root directory, false otherwise.
-bool has_root_directory(const Twine &path);
+bool has_root_directory(const Twine &path, Style style = Style::native);
/// @brief Has root path?
///
///
/// @param path Input path.
/// @result True if the path has a root path, false otherwise.
-bool has_root_path(const Twine &path);
+bool has_root_path(const Twine &path, Style style = Style::native);
/// @brief Has relative path?
///
///
/// @param path Input path.
/// @result True if the path has a relative path, false otherwise.
-bool has_relative_path(const Twine &path);
+bool has_relative_path(const Twine &path, Style style = Style::native);
/// @brief Has parent path?
///
///
/// @param path Input path.
/// @result True if the path has a parent path, false otherwise.
-bool has_parent_path(const Twine &path);
+bool has_parent_path(const Twine &path, Style style = Style::native);
/// @brief Has filename?
///
///
/// @param path Input path.
/// @result True if the path has a filename, false otherwise.
-bool has_filename(const Twine &path);
+bool has_filename(const Twine &path, Style style = Style::native);
/// @brief Has stem?
///
///
/// @param path Input path.
/// @result True if the path has a stem, false otherwise.
-bool has_stem(const Twine &path);
+bool has_stem(const Twine &path, Style style = Style::native);
/// @brief Has extension?
///
///
/// @param path Input path.
/// @result True if the path has a extension, false otherwise.
-bool has_extension(const Twine &path);
+bool has_extension(const Twine &path, Style style = Style::native);
/// @brief Is path absolute?
///
/// @param path Input path.
/// @result True if the path is absolute, false if it is not.
-bool is_absolute(const Twine &path);
+bool is_absolute(const Twine &path, Style style = Style::native);
/// @brief Is path relative?
///
/// @param path Input path.
/// @result True if the path is relative, false if it is not.
-bool is_relative(const Twine &path);
+bool is_relative(const Twine &path, Style style = Style::native);
/// @brief Remove redundant leading "./" pieces and consecutive separators.
///
/// @param path Input path.
/// @result The cleaned-up \a path.
-StringRef remove_leading_dotslash(StringRef path);
+StringRef remove_leading_dotslash(StringRef path, Style style = Style::native);
/// @brief In-place remove any './' and optionally '../' components from a path.
///
/// @param remove_dot_dot specify if '../' (except for leading "../") should be
/// removed
/// @result True if path was changed
-bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false);
+bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false,
+ Style style = Style::native);
} // end namespace path
} // end namespace sys
namespace {
using llvm::StringRef;
using llvm::sys::path::is_separator;
+ using llvm::sys::path::Style;
+ inline Style real_style(Style style) {
#ifdef LLVM_ON_WIN32
- const char *separators = "\\/";
- const char preferred_separator = '\\';
+ return (style == Style::posix) ? Style::posix : Style::windows;
#else
- const char separators = '/';
- const char preferred_separator = '/';
+ return (style == Style::windows) ? Style::windows : Style::posix;
#endif
+ }
+
+ inline const char *separators(Style style) {
+ if (real_style(style) == Style::windows)
+ return "\\/";
+ return "/";
+ }
- StringRef find_first_component(StringRef path) {
+ inline char preferred_separator(Style style) {
+ if (real_style(style) == Style::windows)
+ return '\\';
+ return '/';
+ }
+
+ StringRef find_first_component(StringRef path, Style style) {
// Look for this first component in the following order.
// * empty (in this case we return an empty string)
// * either C: or {//,\\}net.
if (path.empty())
return path;
-#ifdef LLVM_ON_WIN32
- // C:
- if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) &&
- path[1] == ':')
- return path.substr(0, 2);
-#endif
+ if (real_style(style) == Style::windows) {
+ // C:
+ if (path.size() >= 2 &&
+ std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':')
+ return path.substr(0, 2);
+ }
// //net
- if ((path.size() > 2) &&
- is_separator(path[0]) &&
- path[0] == path[1] &&
- !is_separator(path[2])) {
+ if ((path.size() > 2) && is_separator(path[0], style) &&
+ path[0] == path[1] && !is_separator(path[2], style)) {
// Find the next directory separator.
- size_t end = path.find_first_of(separators, 2);
+ size_t end = path.find_first_of(separators(style), 2);
return path.substr(0, end);
}
// {/,\}
- if (is_separator(path[0]))
+ if (is_separator(path[0], style))
return path.substr(0, 1);
// * {file,directory}name
- size_t end = path.find_first_of(separators);
+ size_t end = path.find_first_of(separators(style));
return path.substr(0, end);
}
- size_t filename_pos(StringRef str) {
- if (str.size() == 2 &&
- is_separator(str[0]) &&
- str[0] == str[1])
+ size_t filename_pos(StringRef str, Style style) {
+ if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1])
return 0;
- if (str.size() > 0 && is_separator(str[str.size() - 1]))
+ if (str.size() > 0 && is_separator(str[str.size() - 1], style))
return str.size() - 1;
- size_t pos = str.find_last_of(separators, str.size() - 1);
+ size_t pos = str.find_last_of(separators(style), str.size() - 1);
-#ifdef LLVM_ON_WIN32
- if (pos == StringRef::npos)
- pos = str.find_last_of(':', str.size() - 2);
-#endif
+ if (real_style(style) == Style::windows) {
+ if (pos == StringRef::npos)
+ pos = str.find_last_of(':', str.size() - 2);
+ }
- if (pos == StringRef::npos ||
- (pos == 1 && is_separator(str[0])))
+ if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style)))
return 0;
return pos + 1;
}
- size_t root_dir_start(StringRef str) {
+ size_t root_dir_start(StringRef str, Style style) {
// case "c:/"
-#ifdef LLVM_ON_WIN32
- if (str.size() > 2 &&
- str[1] == ':' &&
- is_separator(str[2]))
- return 2;
-#endif
+ if (real_style(style) == Style::windows) {
+ if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style))
+ return 2;
+ }
// case "//"
- if (str.size() == 2 &&
- is_separator(str[0]) &&
- str[0] == str[1])
+ if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1])
return StringRef::npos;
// case "//net"
- if (str.size() > 3 &&
- is_separator(str[0]) &&
- str[0] == str[1] &&
- !is_separator(str[2])) {
- return str.find_first_of(separators, 2);
+ if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
+ !is_separator(str[2], style)) {
+ return str.find_first_of(separators(style), 2);
}
// case "/"
- if (str.size() > 0 && is_separator(str[0]))
+ if (str.size() > 0 && is_separator(str[0], style))
return 0;
return StringRef::npos;
}
- size_t parent_path_end(StringRef path) {
- size_t end_pos = filename_pos(path);
+ size_t parent_path_end(StringRef path, Style style) {
+ size_t end_pos = filename_pos(path, style);
- bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]);
+ bool filename_was_sep =
+ path.size() > 0 && is_separator(path[end_pos], style);
// Skip separators except for root dir.
- size_t root_dir_pos = root_dir_start(path.substr(0, end_pos));
+ size_t root_dir_pos = root_dir_start(path.substr(0, end_pos), style);
- while(end_pos > 0 &&
- (end_pos - 1) != root_dir_pos &&
- is_separator(path[end_pos - 1]))
+ while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
+ is_separator(path[end_pos - 1], style))
--end_pos;
if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
namespace sys {
namespace path {
-const_iterator begin(StringRef path) {
+const_iterator begin(StringRef path, Style style) {
const_iterator i;
i.Path = path;
- i.Component = find_first_component(path);
+ i.Component = find_first_component(path, style);
i.Position = 0;
+ i.S = style;
return i;
}
// Both POSIX and Windows treat paths that begin with exactly two separators
// specially.
- bool was_net = Component.size() > 2 &&
- is_separator(Component[0]) &&
- Component[1] == Component[0] &&
- !is_separator(Component[2]);
+ bool was_net = Component.size() > 2 && is_separator(Component[0], S) &&
+ Component[1] == Component[0] && !is_separator(Component[2], S);
// Handle separators.
- if (is_separator(Path[Position])) {
+ if (is_separator(Path[Position], S)) {
// Root dir.
- if (was_net
-#ifdef LLVM_ON_WIN32
+ if (was_net ||
// c:/
- || Component.endswith(":")
-#endif
- ) {
+ (real_style(S) == Style::windows && Component.endswith(":"))) {
Component = Path.substr(Position, 1);
return *this;
}
// Skip extra separators.
- while (Position != Path.size() &&
- is_separator(Path[Position])) {
+ while (Position != Path.size() && is_separator(Path[Position], S)) {
++Position;
}
}
// Find next component.
- size_t end_pos = Path.find_first_of(separators, Position);
+ size_t end_pos = Path.find_first_of(separators(S), Position);
Component = Path.slice(Position, end_pos);
return *this;
return Position - RHS.Position;
}
-reverse_iterator rbegin(StringRef Path) {
+reverse_iterator rbegin(StringRef Path, Style style) {
reverse_iterator I;
I.Path = Path;
I.Position = Path.size();
+ I.S = style;
return ++I;
}
reverse_iterator &reverse_iterator::operator++() {
// If we're at the end and the previous char was a '/', return '.' unless
// we are the root path.
- size_t root_dir_pos = root_dir_start(Path);
- if (Position == Path.size() &&
- Path.size() > root_dir_pos + 1 &&
- is_separator(Path[Position - 1])) {
+ size_t root_dir_pos = root_dir_start(Path, S);
+ if (Position == Path.size() && Path.size() > root_dir_pos + 1 &&
+ is_separator(Path[Position - 1], S)) {
--Position;
Component = ".";
return *this;
// Skip separators unless it's the root directory.
size_t end_pos = Position;
- while(end_pos > 0 &&
- (end_pos - 1) != root_dir_pos &&
- is_separator(Path[end_pos - 1]))
+ while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
+ is_separator(Path[end_pos - 1], S))
--end_pos;
// Find next separator.
- size_t start_pos = filename_pos(Path.substr(0, end_pos));
+ size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
Component = Path.slice(start_pos, end_pos);
Position = start_pos;
return *this;
return Position - RHS.Position;
}
-StringRef root_path(StringRef path) {
- const_iterator b = begin(path),
- pos = b,
- e = end(path);
+StringRef root_path(StringRef path, Style style) {
+ const_iterator b = begin(path, style), pos = b, e = end(path);
if (b != e) {
- bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
- bool has_drive =
-#ifdef LLVM_ON_WIN32
- b->endswith(":");
-#else
- false;
-#endif
+ bool has_net =
+ b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
+ bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
if (has_net || has_drive) {
- if ((++pos != e) && is_separator((*pos)[0])) {
+ if ((++pos != e) && is_separator((*pos)[0], style)) {
// {C:/,//net/}, so get the first two components.
return path.substr(0, b->size() + pos->size());
} else {
}
// POSIX style root directory.
- if (is_separator((*b)[0])) {
+ if (is_separator((*b)[0], style)) {
return *b;
}
}
return StringRef();
}
-StringRef root_name(StringRef path) {
- const_iterator b = begin(path),
- e = end(path);
+StringRef root_name(StringRef path, Style style) {
+ const_iterator b = begin(path, style), e = end(path);
if (b != e) {
- bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
- bool has_drive =
-#ifdef LLVM_ON_WIN32
- b->endswith(":");
-#else
- false;
-#endif
+ bool has_net =
+ b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
+ bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
if (has_net || has_drive) {
// just {C:,//net}, return the first component.
return StringRef();
}
-StringRef root_directory(StringRef path) {
- const_iterator b = begin(path),
- pos = b,
- e = end(path);
+StringRef root_directory(StringRef path, Style style) {
+ const_iterator b = begin(path, style), pos = b, e = end(path);
if (b != e) {
- bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
- bool has_drive =
-#ifdef LLVM_ON_WIN32
- b->endswith(":");
-#else
- false;
-#endif
+ bool has_net =
+ b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
+ bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
if ((has_net || has_drive) &&
// {C:,//net}, skip to the next component.
- (++pos != e) && is_separator((*pos)[0])) {
+ (++pos != e) && is_separator((*pos)[0], style)) {
return *pos;
}
// POSIX style root directory.
- if (!has_net && is_separator((*b)[0])) {
+ if (!has_net && is_separator((*b)[0], style)) {
return *b;
}
}
return StringRef();
}
-StringRef relative_path(StringRef path) {
- StringRef root = root_path(path);
+StringRef relative_path(StringRef path, Style style) {
+ StringRef root = root_path(path, style);
return path.substr(root.size());
}
-void append(SmallVectorImpl<char> &path, const Twine &a,
- const Twine &b,
- const Twine &c,
- const Twine &d) {
+void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
+ const Twine &b, const Twine &c, const Twine &d) {
SmallString<32> a_storage;
SmallString<32> b_storage;
SmallString<32> c_storage;
if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
for (auto &component : components) {
- bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]);
- bool component_has_sep = !component.empty() && is_separator(component[0]);
- bool is_root_name = has_root_name(component);
+ bool path_has_sep =
+ !path.empty() && is_separator(path[path.size() - 1], style);
+ bool component_has_sep =
+ !component.empty() && is_separator(component[0], style);
+ bool is_root_name = has_root_name(component, style);
if (path_has_sep) {
// Strip separators from beginning of component.
- size_t loc = component.find_first_not_of(separators);
+ size_t loc = component.find_first_not_of(separators(style));
StringRef c = component.substr(loc);
// Append it.
if (!component_has_sep && !(path.empty() || is_root_name)) {
// Add a separator.
- path.push_back(preferred_separator);
+ path.push_back(preferred_separator(style));
}
path.append(component.begin(), component.end());
}
}
-void append(SmallVectorImpl<char> &path,
- const_iterator begin, const_iterator end) {
+void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &b,
+ const Twine &c, const Twine &d) {
+ append(path, Style::native, a, b, c, d);
+}
+
+void append(SmallVectorImpl<char> &path, const_iterator begin,
+ const_iterator end, Style style) {
for (; begin != end; ++begin)
- path::append(path, *begin);
+ path::append(path, style, *begin);
}
-StringRef parent_path(StringRef path) {
- size_t end_pos = parent_path_end(path);
+StringRef parent_path(StringRef path, Style style) {
+ size_t end_pos = parent_path_end(path, style);
if (end_pos == StringRef::npos)
return StringRef();
else
return path.substr(0, end_pos);
}
-void remove_filename(SmallVectorImpl<char> &path) {
- size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()));
+void remove_filename(SmallVectorImpl<char> &path, Style style) {
+ size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style);
if (end_pos != StringRef::npos)
path.set_size(end_pos);
}
-void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) {
+void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
+ Style style) {
StringRef p(path.begin(), path.size());
SmallString<32> ext_storage;
StringRef ext = extension.toStringRef(ext_storage);
// Erase existing extension.
size_t pos = p.find_last_of('.');
- if (pos != StringRef::npos && pos >= filename_pos(p))
+ if (pos != StringRef::npos && pos >= filename_pos(p, style))
path.set_size(pos);
// Append '.' if needed.
}
void replace_path_prefix(SmallVectorImpl<char> &Path,
- const StringRef &OldPrefix,
- const StringRef &NewPrefix) {
+ const StringRef &OldPrefix, const StringRef &NewPrefix,
+ Style style) {
if (OldPrefix.empty() && NewPrefix.empty())
return;
StringRef RelPath = OrigPath.substr(OldPrefix.size());
SmallString<256> NewPath;
- path::append(NewPath, NewPrefix);
- path::append(NewPath, RelPath);
+ path::append(NewPath, style, NewPrefix);
+ path::append(NewPath, style, RelPath);
Path.swap(NewPath);
}
-void native(const Twine &path, SmallVectorImpl<char> &result) {
+void native(const Twine &path, SmallVectorImpl<char> &result, Style style) {
assert((!path.isSingleStringRef() ||
path.getSingleStringRef().data() != result.data()) &&
"path and result are not allowed to overlap!");
// Clear result.
result.clear();
path.toVector(result);
- native(result);
+ native(result, style);
}
-void native(SmallVectorImpl<char> &Path) {
+void native(SmallVectorImpl<char> &Path, Style style) {
if (Path.empty())
return;
-#ifdef LLVM_ON_WIN32
- std::replace(Path.begin(), Path.end(), '/', '\\');
- if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1]))) {
- SmallString<128> PathHome;
- home_directory(PathHome);
- PathHome.append(Path.begin() + 1, Path.end());
- Path = PathHome;
- }
-#else
- for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
- if (*PI == '\\') {
- auto PN = PI + 1;
- if (PN < PE && *PN == '\\')
- ++PI; // increment once, the for loop will move over the escaped slash
- else
- *PI = '/';
+ if (real_style(style) == Style::windows) {
+ std::replace(Path.begin(), Path.end(), '/', '\\');
+ if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
+ SmallString<128> PathHome;
+ home_directory(PathHome);
+ PathHome.append(Path.begin() + 1, Path.end());
+ Path = PathHome;
+ }
+ } else {
+ for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
+ if (*PI == '\\') {
+ auto PN = PI + 1;
+ if (PN < PE && *PN == '\\')
+ ++PI; // increment once, the for loop will move over the escaped slash
+ else
+ *PI = '/';
+ }
}
}
-#endif
}
-std::string convert_to_slash(StringRef path) {
-#ifdef LLVM_ON_WIN32
+std::string convert_to_slash(StringRef path, Style style) {
+ if (real_style(style) != Style::windows)
+ return path;
+
std::string s = path.str();
std::replace(s.begin(), s.end(), '\\', '/');
return s;
-#else
- return path;
-#endif
}
-StringRef filename(StringRef path) {
- return *rbegin(path);
-}
+StringRef filename(StringRef path, Style style) { return *rbegin(path, style); }
-StringRef stem(StringRef path) {
- StringRef fname = filename(path);
+StringRef stem(StringRef path, Style style) {
+ StringRef fname = filename(path, style);
size_t pos = fname.find_last_of('.');
if (pos == StringRef::npos)
return fname;
return fname.substr(0, pos);
}
-StringRef extension(StringRef path) {
- StringRef fname = filename(path);
+StringRef extension(StringRef path, Style style) {
+ StringRef fname = filename(path, style);
size_t pos = fname.find_last_of('.');
if (pos == StringRef::npos)
return StringRef();
return fname.substr(pos);
}
-bool is_separator(char value) {
- switch(value) {
-#ifdef LLVM_ON_WIN32
- case '\\': // fall through
-#endif
- case '/': return true;
- default: return false;
- }
+bool is_separator(char value, Style style) {
+ if (value == '/')
+ return true;
+ if (real_style(style) == Style::windows)
+ return value == '\\';
+ return false;
}
-static const char preferred_separator_string[] = { preferred_separator, '\0' };
-
-StringRef get_separator() {
- return preferred_separator_string;
+StringRef get_separator(Style style) {
+ if (real_style(style) == Style::windows)
+ return "\\";
+ return "/";
}
-bool has_root_name(const Twine &path) {
+bool has_root_name(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !root_name(p).empty();
+ return !root_name(p, style).empty();
}
-bool has_root_directory(const Twine &path) {
+bool has_root_directory(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !root_directory(p).empty();
+ return !root_directory(p, style).empty();
}
-bool has_root_path(const Twine &path) {
+bool has_root_path(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !root_path(p).empty();
+ return !root_path(p, style).empty();
}
-bool has_relative_path(const Twine &path) {
+bool has_relative_path(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !relative_path(p).empty();
+ return !relative_path(p, style).empty();
}
-bool has_filename(const Twine &path) {
+bool has_filename(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !filename(p).empty();
+ return !filename(p, style).empty();
}
-bool has_parent_path(const Twine &path) {
+bool has_parent_path(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !parent_path(p).empty();
+ return !parent_path(p, style).empty();
}
-bool has_stem(const Twine &path) {
+bool has_stem(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !stem(p).empty();
+ return !stem(p, style).empty();
}
-bool has_extension(const Twine &path) {
+bool has_extension(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- return !extension(p).empty();
+ return !extension(p, style).empty();
}
-bool is_absolute(const Twine &path) {
+bool is_absolute(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
- bool rootDir = has_root_directory(p),
-#ifdef LLVM_ON_WIN32
- rootName = has_root_name(p);
-#else
- rootName = true;
-#endif
+ bool rootDir = has_root_directory(p, style);
+ bool rootName =
+ (real_style(style) != Style::windows) || has_root_name(p, style);
return rootDir && rootName;
}
-bool is_relative(const Twine &path) { return !is_absolute(path); }
+bool is_relative(const Twine &path, Style style) {
+ return !is_absolute(path, style);
+}
-StringRef remove_leading_dotslash(StringRef Path) {
+StringRef remove_leading_dotslash(StringRef Path, Style style) {
// Remove leading "./" (or ".//" or "././" etc.)
- while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1])) {
+ while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) {
Path = Path.substr(2);
- while (Path.size() > 0 && is_separator(Path[0]))
+ while (Path.size() > 0 && is_separator(Path[0], style))
Path = Path.substr(1);
}
return Path;
}
-static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) {
+static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot,
+ Style style) {
SmallVector<StringRef, 16> components;
// Skip the root path, then look for traversal in the components.
- StringRef rel = path::relative_path(path);
- for (StringRef C : llvm::make_range(path::begin(rel), path::end(rel))) {
+ StringRef rel = path::relative_path(path, style);
+ for (StringRef C :
+ llvm::make_range(path::begin(rel, style), path::end(rel))) {
if (C == ".")
continue;
// Leading ".." will remain in the path unless it's at the root.
components.pop_back();
continue;
}
- if (path::is_absolute(path))
+ if (path::is_absolute(path, style))
continue;
}
components.push_back(C);
}
- SmallString<256> buffer = path::root_path(path);
+ SmallString<256> buffer = path::root_path(path, style);
for (StringRef C : components)
- path::append(buffer, C);
+ path::append(buffer, style, C);
return buffer;
}
-bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot) {
+bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot,
+ Style style) {
StringRef p(path.data(), path.size());
- SmallString<256> result = remove_dots(p, remove_dot_dot);
+ SmallString<256> result = remove_dots(p, remove_dot_dot, style);
if (result == path)
return false;
llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
SmallString<128> Storage;
StringRef P = Model.toNullTerminatedStringRef(Storage);
- assert(P.find_first_of(separators) == StringRef::npos &&
+ assert(P.find_first_of(separators(Style::native)) == StringRef::npos &&
"Model must be a simple filename.");
// Use P.begin() so that createUniqueEntity doesn't need to recreate Storage.
return createUniqueEntity(P.begin(), ResultFD, ResultPath,
bool use_current_directory) {
StringRef p(path.data(), path.size());
- bool rootDirectory = path::has_root_directory(p),
-#ifdef LLVM_ON_WIN32
- rootName = path::has_root_name(p);
-#else
- rootName = true;
-#endif
+ bool rootDirectory = path::has_root_directory(p);
+ bool rootName =
+ (real_style(Style::native) != Style::windows) || path::has_root_name(p);
// Already absolute.
if (rootName && rootDirectory)
EXPECT_FALSE(path::is_separator('-'));
EXPECT_FALSE(path::is_separator(' '));
+ EXPECT_TRUE(path::is_separator('\\', path::Style::windows));
+ EXPECT_FALSE(path::is_separator('\\', path::Style::posix));
+
#ifdef LLVM_ON_WIN32
EXPECT_TRUE(path::is_separator('\\'));
#else
- EXPECT_FALSE(path::is_separator('\\'));
+ EXPECT_FALSE(path::is_separator('\\', ));
#endif
}
}
}
-#ifdef LLVM_ON_WIN32
TEST(Support, AbsolutePathIteratorWin32) {
SmallString<64> Path(StringRef("c:\\c\\e\\foo.txt"));
typedef SmallVector<StringRef, 4> PathComponents;
// when iterating.
ExpectedPathComponents.insert(ExpectedPathComponents.begin()+1, "\\");
- for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E;
- ++I) {
+ for (path::const_iterator I = path::begin(Path, path::Style::windows),
+ E = path::end(Path);
+ I != E; ++I) {
ActualPathComponents.push_back(*I);
}
EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str());
}
}
-#endif // LLVM_ON_WIN32
TEST(Support, AbsolutePathIteratorEnd) {
// Trailing slashes are converted to '.' unless they are part of the root path.
- SmallVector<StringRef, 4> Paths;
- Paths.push_back("/foo/");
- Paths.push_back("/foo//");
- Paths.push_back("//net//");
-#ifdef LLVM_ON_WIN32
- Paths.push_back("c:\\\\");
-#endif
-
- for (StringRef Path : Paths) {
- StringRef LastComponent = *path::rbegin(Path);
+ SmallVector<std::pair<StringRef, path::Style>, 4> Paths;
+ Paths.emplace_back("/foo/", path::Style::native);
+ Paths.emplace_back("/foo//", path::Style::native);
+ Paths.emplace_back("//net//", path::Style::native);
+ Paths.emplace_back("c:\\\\", path::Style::windows);
+
+ for (auto &Path : Paths) {
+ StringRef LastComponent = *path::rbegin(Path.first, Path.second);
EXPECT_EQ(".", LastComponent);
}
- SmallVector<StringRef, 3> RootPaths;
- RootPaths.push_back("/");
- RootPaths.push_back("//net/");
-#ifdef LLVM_ON_WIN32
- RootPaths.push_back("c:\\");
-#endif
+ SmallVector<std::pair<StringRef, path::Style>, 3> RootPaths;
+ RootPaths.emplace_back("/", path::Style::native);
+ RootPaths.emplace_back("//net/", path::Style::native);
+ RootPaths.emplace_back("c:\\", path::Style::windows);
- for (StringRef Path : RootPaths) {
- StringRef LastComponent = *path::rbegin(Path);
+ for (auto &Path : RootPaths) {
+ StringRef LastComponent = *path::rbegin(Path.first, Path.second);
EXPECT_EQ(1u, LastComponent.size());
- EXPECT_TRUE(path::is_separator(LastComponent[0]));
+ EXPECT_TRUE(path::is_separator(LastComponent[0], Path.second));
}
}
}
TEST(Support, NormalizePath) {
-#if defined(LLVM_ON_WIN32)
-#define EXPECT_PATH_IS(path__, windows__, not_windows__) \
- EXPECT_EQ(path__, windows__);
-#else
-#define EXPECT_PATH_IS(path__, windows__, not_windows__) \
- EXPECT_EQ(path__, not_windows__);
-#endif
-
- SmallString<64> Path1("a");
- SmallString<64> Path2("a/b");
- SmallString<64> Path3("a\\b");
- SmallString<64> Path4("a\\\\b");
- SmallString<64> Path5("\\a");
- SmallString<64> Path6("a\\");
-
- path::native(Path1);
- EXPECT_PATH_IS(Path1, "a", "a");
-
- path::native(Path2);
- EXPECT_PATH_IS(Path2, "a\\b", "a/b");
-
- path::native(Path3);
- EXPECT_PATH_IS(Path3, "a\\b", "a/b");
-
- path::native(Path4);
- EXPECT_PATH_IS(Path4, "a\\\\b", "a\\\\b");
-
- path::native(Path5);
- EXPECT_PATH_IS(Path5, "\\a", "/a");
-
- path::native(Path6);
- EXPECT_PATH_IS(Path6, "a\\", "a/");
-
-#undef EXPECT_PATH_IS
+ using TestTuple = std::tuple<StringRef, StringRef, StringRef>;
+ TestTuple Tests[] = {{"a", "a", "a"}, {"a/b", "a\\b", "a/b"},
+ {"a\\b", "a\\b", "a/b"}, {"a\\\\b", "a\\\\b", "a\\\\b"},
+ {"\\a", "\\a", "/a"}, {"a\\", "a\\", "a/"}};
+ for (auto &T : Tests) {
+ SmallString<64> Win = std::get<0>(T);
+ SmallString<64> Posix = Win;
+ path::native(Win, path::Style::windows);
+ path::native(Posix, path::Style::posix);
+ EXPECT_EQ(std::get<1>(T), Win);
+ EXPECT_EQ(std::get<2>(T), Posix);
+ }
#if defined(LLVM_ON_WIN32)
SmallString<64> PathHome;
EXPECT_EQ(Path2, "");
}
-static std::string remove_dots(StringRef path,
- bool remove_dot_dot) {
+static std::string remove_dots(StringRef path, bool remove_dot_dot,
+ path::Style style) {
SmallString<256> buffer(path);
- path::remove_dots(buffer, remove_dot_dot);
+ path::remove_dots(buffer, remove_dot_dot, style);
return buffer.str();
}
TEST(Support, RemoveDots) {
-#if defined(LLVM_ON_WIN32)
- EXPECT_EQ("foolz\\wat", remove_dots(".\\.\\\\foolz\\wat", false));
- EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false));
-
- EXPECT_EQ("a\\..\\b\\c", remove_dots(".\\a\\..\\b\\c", false));
- EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true));
- EXPECT_EQ("c", remove_dots(".\\.\\c", true));
- EXPECT_EQ("..\\a\\c", remove_dots("..\\a\\b\\..\\c", true));
- EXPECT_EQ("..\\..\\a\\c", remove_dots("..\\..\\a\\b\\..\\c", true));
+ EXPECT_EQ("foolz\\wat",
+ remove_dots(".\\.\\\\foolz\\wat", false, path::Style::windows));
+ EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false, path::Style::windows));
+
+ EXPECT_EQ("a\\..\\b\\c",
+ remove_dots(".\\a\\..\\b\\c", false, path::Style::windows));
+ EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true, path::Style::windows));
+ EXPECT_EQ("c", remove_dots(".\\.\\c", true, path::Style::windows));
+ EXPECT_EQ("..\\a\\c",
+ remove_dots("..\\a\\b\\..\\c", true, path::Style::windows));
+ EXPECT_EQ("..\\..\\a\\c",
+ remove_dots("..\\..\\a\\b\\..\\c", true, path::Style::windows));
SmallString<64> Path1(".\\.\\c");
- EXPECT_TRUE(path::remove_dots(Path1, true));
- EXPECT_EQ("c", Path1);
-#else
- EXPECT_EQ("foolz/wat", remove_dots("././/foolz/wat", false));
- EXPECT_EQ("", remove_dots("./////", false));
-
- EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false));
- EXPECT_EQ("b/c", remove_dots("./a/../b/c", true));
- EXPECT_EQ("c", remove_dots("././c", true));
- EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true));
- EXPECT_EQ("../../a/c", remove_dots("../../a/b/../c", true));
- EXPECT_EQ("/a/c", remove_dots("/../../a/c", true));
- EXPECT_EQ("/a/c", remove_dots("/../a/b//../././/c", true));
-
- SmallString<64> Path1("././c");
- EXPECT_TRUE(path::remove_dots(Path1, true));
+ EXPECT_TRUE(path::remove_dots(Path1, true, path::Style::windows));
EXPECT_EQ("c", Path1);
-#endif
+
+ EXPECT_EQ("foolz/wat",
+ remove_dots("././/foolz/wat", false, path::Style::posix));
+ EXPECT_EQ("", remove_dots("./////", false, path::Style::posix));
+
+ EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false, path::Style::posix));
+ EXPECT_EQ("b/c", remove_dots("./a/../b/c", true, path::Style::posix));
+ EXPECT_EQ("c", remove_dots("././c", true, path::Style::posix));
+ EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true, path::Style::posix));
+ EXPECT_EQ("../../a/c",
+ remove_dots("../../a/b/../c", true, path::Style::posix));
+ EXPECT_EQ("/a/c", remove_dots("/../../a/c", true, path::Style::posix));
+ EXPECT_EQ("/a/c",
+ remove_dots("/../a/b//../././/c", true, path::Style::posix));
+
+ SmallString<64> Path2("././c");
+ EXPECT_TRUE(path::remove_dots(Path2, true, path::Style::posix));
+ EXPECT_EQ("c", Path2);
}
TEST(Support, ReplacePathPrefix) {