1 //===-- StringExtras.cpp - Implement the StringExtras header --------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the StringExtras.h header 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ADT/StringExtras.h" 14 #include "llvm/ADT/SmallVector.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include <cctype> 17 18 using namespace llvm; 19 20 /// StrInStrNoCase - Portable version of strcasestr. Locates the first 21 /// occurrence of string 's1' in string 's2', ignoring case. Returns 22 /// the offset of s2 in s1 or npos if s2 cannot be found. 23 StringRef::size_type llvm::StrInStrNoCase(StringRef s1, StringRef s2) { 24 size_t N = s2.size(), M = s1.size(); 25 if (N > M) 26 return StringRef::npos; 27 for (size_t i = 0, e = M - N + 1; i != e; ++i) 28 if (s1.substr(i, N).equals_lower(s2)) 29 return i; 30 return StringRef::npos; 31 } 32 33 /// getToken - This function extracts one token from source, ignoring any 34 /// leading characters that appear in the Delimiters string, and ending the 35 /// token at any of the characters that appear in the Delimiters string. If 36 /// there are no tokens in the source string, an empty string is returned. 37 /// The function returns a pair containing the extracted token and the 38 /// remaining tail string. 39 std::pair<StringRef, StringRef> llvm::getToken(StringRef Source, 40 StringRef Delimiters) { 41 // Figure out where the token starts. 42 StringRef::size_type Start = Source.find_first_not_of(Delimiters); 43 44 // Find the next occurrence of the delimiter. 45 StringRef::size_type End = Source.find_first_of(Delimiters, Start); 46 47 return std::make_pair(Source.slice(Start, End), Source.substr(End)); 48 } 49 50 /// SplitString - Split up the specified string according to the specified 51 /// delimiters, appending the result fragments to the output list. 52 void llvm::SplitString(StringRef Source, 53 SmallVectorImpl<StringRef> &OutFragments, 54 StringRef Delimiters) { 55 std::pair<StringRef, StringRef> S = getToken(Source, Delimiters); 56 while (!S.first.empty()) { 57 OutFragments.push_back(S.first); 58 S = getToken(S.second, Delimiters); 59 } 60 } 61 62 void llvm::printEscapedString(StringRef Name, raw_ostream &Out) { 63 for (unsigned i = 0, e = Name.size(); i != e; ++i) { 64 unsigned char C = Name[i]; 65 if (C == '\\') 66 Out << '\\' << C; 67 else if (isPrint(C) && C != '"') 68 Out << C; 69 else 70 Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F); 71 } 72 } 73 74 void llvm::printHTMLEscaped(StringRef String, raw_ostream &Out) { 75 for (char C : String) { 76 if (C == '&') 77 Out << "&"; 78 else if (C == '<') 79 Out << "<"; 80 else if (C == '>') 81 Out << ">"; 82 else if (C == '\"') 83 Out << """; 84 else if (C == '\'') 85 Out << "'"; 86 else 87 Out << C; 88 } 89 } 90 91 void llvm::printLowerCase(StringRef String, raw_ostream &Out) { 92 for (const char C : String) 93 Out << toLower(C); 94 } 95 96 std::string llvm::convertToSnakeFromCamelCase(StringRef input) { 97 if (input.empty()) 98 return ""; 99 100 std::string snakeCase; 101 snakeCase.reserve(input.size()); 102 for (char c : input) { 103 if (!std::isupper(c)) { 104 snakeCase.push_back(c); 105 continue; 106 } 107 108 if (!snakeCase.empty() && snakeCase.back() != '_') 109 snakeCase.push_back('_'); 110 snakeCase.push_back(llvm::toLower(c)); 111 } 112 return snakeCase; 113 } 114 115 std::string llvm::convertToCamelFromSnakeCase(StringRef input, 116 bool capitalizeFirst) { 117 if (input.empty()) 118 return ""; 119 120 std::string output; 121 output.reserve(input.size()); 122 123 // Push the first character, capatilizing if necessary. 124 if (capitalizeFirst && std::islower(input.front())) 125 output.push_back(llvm::toUpper(input.front())); 126 else 127 output.push_back(input.front()); 128 129 // Walk the input converting any `*_[a-z]` snake case into `*[A-Z]` camelCase. 130 for (size_t pos = 1, e = input.size(); pos < e; ++pos) { 131 if (input[pos] == '_' && pos != (e - 1) && std::islower(input[pos + 1])) 132 output.push_back(llvm::toUpper(input[++pos])); 133 else 134 output.push_back(input[pos]); 135 } 136 return output; 137 } 138