//===--- iwyu_string_util.h - string utilities for include-what-you-use ---===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // String utilities for the IWYU checker. // #ifndef INCLUDE_WHAT_YOU_USE_IWYU_STRING_UTIL_H_ #define INCLUDE_WHAT_YOU_USE_IWYU_STRING_UTIL_H_ #include #include #include #include #include "iwyu_port.h" namespace include_what_you_use { using std::string; using std::vector; // Returns true if str starts with prefix. inline bool StartsWith(const string& str, const string& prefix) { return str.substr(0, prefix.length()) == prefix; } // Returns true if str ends with suffix. inline bool EndsWith(const string& str, const string& suffix) { if (suffix.length() > str.length()) return false; return str.substr(str.length() - suffix.length()) == suffix; } // If *str starts with prefix, removes the prefix and returns true. inline bool StripLeft(string* str, const string& prefix) { if (StartsWith(*str, prefix)) { *str = str->substr(prefix.length()); return true; } return false; } // If *str ends with suffix, removes the suffix and returns true. inline bool StripRight(string* str, const string& suffix) { if (str->length() >= suffix.length() && str->substr(str->length() - suffix.length()) == suffix) { *str = str->substr(0, str->length() - suffix.length()); return true; } return false; } // Truncate str to width with ellipses to indicate truncation. // Return str unchanged if it fits within width. // Return empty string if width is too short to fit anything meaningful. // Otherwise return str truncated to width chars. inline string Ellipsize(const string& str, size_t width) { if (str.length() <= width) return str; // If we truncate strings too short, we'll end up with nonsense abbreviations // like '...', 'T...' or 'Ty...' so make sure we have at least three chars // from str and three chars for ellipsis. if (width < 6) return string(); return str.substr(0, width - 3) + "..."; } // Finds the first occurrence of substr in *str and removes from *str // everything before the occurrence and the occurrence itself. For // example, string s = "What a hat!"; StripPast(&s, "hat"); will make s // " a hat!". inline bool StripPast(string* str, const string& substr) { const size_t pos = str->find(substr); if (pos == string::npos) return false; *str = str->substr(pos + substr.length()); return true; } // Removes leading whitespace. inline void StripWhiteSpaceLeft(string* str) { for (string::size_type i = 0; i < str->size(); ++i) { if (!isspace((*str)[i])) { *str = str->substr(i); return; } } // Everything is whitespace. Return with an empty string. str->clear(); } // Removes trailing whitespace. inline void StripWhiteSpaceRight(string* str) { for (string::size_type end_of_string = str->size(); end_of_string > 0; --end_of_string) { if (!isspace((*str)[end_of_string - 1])) { *str = str->substr(0, end_of_string); return; } } // Everything is whitespace. Return with an empty string. str->clear(); } // Removes both leading and trailing whitespace. inline void StripWhiteSpace(string* str) { StripWhiteSpaceLeft(str); StripWhiteSpaceRight(str); } inline void ReplaceAll(std::string* str, const std::string& from, const std::string& to) { for (size_t pos = str->find(from); pos != std::string::npos; pos = str->find(from, pos + to.length())) { str->replace(pos, from.length(), to); } } // This is the same as split() in Python. If max_segs is 0, there's // no limit on the number of the generated segments. inline vector Split( string str, const string& divider, size_t max_segs) { CHECK_(!divider.empty()); vector retval; size_t pos; // If max_segs is 0, the first part of the condition will always be true. while (retval.size() + 1 != max_segs && (pos = str.find(divider)) != string::npos) { retval.push_back(str.substr(0, pos)); str = str.substr(pos + divider.length()); } retval.push_back(str); return retval; } // Like Split, but using a divider of arbitrary whitespace. // Whitespace at the beginning and end is ignored. inline vector SplitOnWhiteSpace(const string& str, size_t max_segs) { vector retval; size_t tokstart = string::npos; for (size_t pos = 0; pos < str.size(); ++pos) { if (isspace(str[pos])) { if (tokstart != string::npos) { retval.push_back(str.substr(tokstart, pos - tokstart)); if (retval.size() == max_segs) { return retval; } tokstart = string::npos; } } else { if (tokstart == string::npos) { tokstart = pos; } } } if (tokstart != string::npos) { retval.push_back(str.substr(tokstart)); } return retval; } // Like SplitOnWhiteSpace, but double-quoted and bracketed strings are // preserved. No error checking with respect to closing quotes is done. inline vector SplitOnWhiteSpacePreservingQuotes( const string& str, size_t max_segs) { vector retval; size_t tokstart = string::npos; char closing_quote = '\0'; for (size_t pos = 0; pos < str.size(); ++pos) { if (isspace(str[pos])) { if (tokstart != string::npos && closing_quote == '\0') { retval.push_back(str.substr(tokstart, pos - tokstart)); if (retval.size() == max_segs) { return retval; } tokstart = string::npos; } } else { if (tokstart == string::npos) { tokstart = pos; if (str[pos] == '"') { closing_quote = '"'; } else if (str[pos] == '<') { closing_quote = '>'; } else { closing_quote = '\0'; } } else if (str[pos] == closing_quote) { closing_quote = '\0'; } } } if (tokstart != string::npos) { retval.push_back(str.substr(tokstart)); } return retval; } } // namespace include_what_you_use #endif // INCLUDE_WHAT_YOU_USE_IWYU_STRING_UTIL_H_