Index: llvm/include/llvm/Support/Path.h =================================================================== --- llvm/include/llvm/Support/Path.h +++ llvm/include/llvm/Support/Path.h @@ -24,6 +24,8 @@ namespace sys { namespace path { +enum class Style { windows, posix, native }; + /// @name Lexical Component Iterator /// @{ @@ -51,9 +53,10 @@ 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: @@ -77,8 +80,9 @@ 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: @@ -95,7 +99,7 @@ /// @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. @@ -105,7 +109,7 @@ /// @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. @@ -126,7 +130,7 @@ /// @endcode /// /// @param path A path that is modified to not have a file component. -void remove_filename(SmallVectorImpl &path); +void remove_filename(SmallVectorImpl &path, Style style = Style::native); /// @brief Replace the file extension of \a path with \a extension. /// @@ -140,7 +144,8 @@ /// @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 &path, const Twine &extension); +void replace_extension(SmallVectorImpl &path, const Twine &extension, + Style style = Style::native); /// @brief Replace matching path prefix with another path. /// @@ -156,8 +161,8 @@ /// @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 &Path, - const StringRef &OldPrefix, - const StringRef &NewPrefix); + const StringRef &OldPrefix, const StringRef &NewPrefix, + Style style = Style::native); /// @brief Append to path. /// @@ -174,6 +179,9 @@ const Twine &c = "", const Twine &d = ""); +void append(SmallVectorImpl &path, Style style, const Twine &a, + const Twine &b = "", const Twine &c = "", const Twine &d = ""); + /// @brief Append to path. /// /// @code @@ -185,8 +193,8 @@ /// @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 &path, - const_iterator begin, const_iterator end); +void append(SmallVectorImpl &path, const_iterator begin, + const_iterator end, Style style = Style::native); /// @} /// @name Transforms (or some other better name) @@ -198,14 +206,15 @@ /// /// @param path A path that is transformed to native format. /// @param result Holds the result of the transformation. -void native(const Twine &path, SmallVectorImpl &result); +void native(const Twine &path, SmallVectorImpl &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 &path); +void native(SmallVectorImpl &path, Style style = Style::native); /// @brief Replaces backslashes with slashes if Windows. /// @@ -213,7 +222,7 @@ /// @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 @@ -229,7 +238,7 @@ /// /// @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. /// @@ -242,7 +251,7 @@ /// @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. /// @@ -250,7 +259,7 @@ /// /// @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. /// @@ -262,7 +271,7 @@ /// /// @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. /// @@ -274,7 +283,7 @@ /// /// @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. /// @@ -288,7 +297,7 @@ /// @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. /// @@ -306,7 +315,7 @@ /// /// @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. /// @@ -322,18 +331,18 @@ /// /// @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" @@ -374,7 +383,7 @@ /// /// @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? /// @@ -382,7 +391,7 @@ /// /// @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? /// @@ -390,7 +399,7 @@ /// /// @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? /// @@ -398,7 +407,7 @@ /// /// @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? /// @@ -406,7 +415,7 @@ /// /// @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? /// @@ -414,7 +423,7 @@ /// /// @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? /// @@ -422,7 +431,7 @@ /// /// @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? /// @@ -430,25 +439,25 @@ /// /// @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. /// @@ -456,7 +465,8 @@ /// @param remove_dot_dot specify if '../' (except for leading "../") should be /// removed /// @result True if path was changed -bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot = false); +bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot = false, + Style style = Style::native); } // end namespace path } // end namespace sys Index: llvm/lib/Support/Path.cpp =================================================================== --- llvm/lib/Support/Path.cpp +++ llvm/lib/Support/Path.cpp @@ -34,16 +34,29 @@ namespace { using llvm::StringRef; using llvm::sys::path::is_separator; + using llvm::sys::path::Style; + 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 + } + + const char *separators(Style style) { + if (real_style(style) == Style::windows) + return "\\/"; + return "/"; + } - StringRef find_first_component(StringRef path) { + const 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. @@ -53,96 +66,85 @@ if (path.empty()) return path; -#ifdef LLVM_ON_WIN32 - // C: - if (path.size() >= 2 && std::isalpha(static_cast(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(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) @@ -230,11 +232,12 @@ 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; } @@ -259,27 +262,21 @@ // 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; } @@ -292,7 +289,7 @@ } // 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; @@ -306,10 +303,11 @@ 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; } @@ -324,10 +322,9 @@ 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; @@ -336,13 +333,12 @@ // 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; @@ -357,21 +353,15 @@ 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 { @@ -381,7 +371,7 @@ } // POSIX style root directory. - if (is_separator((*b)[0])) { + if (is_separator((*b)[0], style)) { return *b; } } @@ -389,17 +379,12 @@ 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. @@ -411,27 +396,21 @@ 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; } } @@ -440,15 +419,13 @@ 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 &path, const Twine &a, - const Twine &b, - const Twine &c, - const Twine &d) { +void append(SmallVectorImpl &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; @@ -461,13 +438,15 @@ 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. @@ -477,41 +456,47 @@ 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 &path, - const_iterator begin, const_iterator end) { +void append(SmallVectorImpl &path, const Twine &a, const Twine &b, + const Twine &c, const Twine &d) { + append(path, Style::native, a, b, c, d); +} + +void append(SmallVectorImpl &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 &path) { - size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); +void remove_filename(SmallVectorImpl &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 &path, const Twine &extension) { +void replace_extension(SmallVectorImpl &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. @@ -523,8 +508,8 @@ } void replace_path_prefix(SmallVectorImpl &Path, - const StringRef &OldPrefix, - const StringRef &NewPrefix) { + const StringRef &OldPrefix, const StringRef &NewPrefix, + Style style) { if (OldPrefix.empty() && NewPrefix.empty()) return; @@ -540,61 +525,58 @@ 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 &result) { +void native(const Twine &path, SmallVectorImpl &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 &Path) { +void native(SmallVectorImpl &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; @@ -606,8 +588,8 @@ 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(); @@ -619,110 +601,109 @@ 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 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. @@ -731,22 +712,23 @@ 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 &path, bool remove_dot_dot) { +bool remove_dots(SmallVectorImpl &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; @@ -784,7 +766,7 @@ llvm::SmallVectorImpl &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, @@ -826,12 +808,9 @@ 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) Index: llvm/lib/Support/Windows/Path.inc =================================================================== --- llvm/lib/Support/Windows/Path.inc +++ llvm/lib/Support/Windows/Path.inc @@ -990,7 +990,8 @@ StringRef PathStr(Path.begin(), Path.size()); PathStr = PathStr.drop_front(); - StringRef Expr = PathStr.take_until(path::is_separator); + StringRef Expr = + PathStr.take_until([](char c) { return path::is_separator(c); }); if (!Expr.empty()) { // This is probably a ~username/ expression. Don't support this on Windows. Index: llvm/unittests/Support/Path.cpp =================================================================== --- llvm/unittests/Support/Path.cpp +++ llvm/unittests/Support/Path.cpp @@ -53,10 +53,13 @@ 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 } @@ -252,7 +255,6 @@ } } -#ifdef LLVM_ON_WIN32 TEST(Support, AbsolutePathIteratorWin32) { SmallString<64> Path(StringRef("c:\\c\\e\\foo.txt")); typedef SmallVector PathComponents; @@ -265,8 +267,9 @@ // 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); } @@ -276,34 +279,29 @@ 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 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, 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 RootPaths; - RootPaths.push_back("/"); - RootPaths.push_back("//net/"); -#ifdef LLVM_ON_WIN32 - RootPaths.push_back("c:\\"); -#endif + SmallVector, 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)); } } @@ -977,40 +975,18 @@ } 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; + 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; @@ -1050,43 +1026,48 @@ 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) {