1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // string_utils:
7 // String helper functions.
8 //
9
10 #include "common/string_utils.h"
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <algorithm>
15 #include <fstream>
16 #include <sstream>
17
18 #include "common/platform.h"
19 #include "common/system_utils.h"
20
21 namespace angle
22 {
23
24 const char kWhitespaceASCII[] = " \f\n\r\t\v";
25
SplitString(const std::string & input,const std::string & delimiters,WhitespaceHandling whitespace,SplitResult resultType)26 std::vector<std::string> SplitString(const std::string &input,
27 const std::string &delimiters,
28 WhitespaceHandling whitespace,
29 SplitResult resultType)
30 {
31 std::vector<std::string> result;
32 if (input.empty())
33 {
34 return result;
35 }
36
37 std::string::size_type start = 0;
38 while (start != std::string::npos)
39 {
40 auto end = input.find_first_of(delimiters, start);
41
42 std::string piece;
43 if (end == std::string::npos)
44 {
45 piece = input.substr(start);
46 start = std::string::npos;
47 }
48 else
49 {
50 piece = input.substr(start, end - start);
51 start = end + 1;
52 }
53
54 if (whitespace == TRIM_WHITESPACE)
55 {
56 piece = TrimString(piece, kWhitespaceASCII);
57 }
58
59 if (resultType == SPLIT_WANT_ALL || !piece.empty())
60 {
61 result.push_back(std::move(piece));
62 }
63 }
64
65 return result;
66 }
67
SplitStringAlongWhitespace(const std::string & input,std::vector<std::string> * tokensOut)68 void SplitStringAlongWhitespace(const std::string &input, std::vector<std::string> *tokensOut)
69 {
70
71 std::istringstream stream(input);
72 std::string line;
73
74 while (std::getline(stream, line))
75 {
76 size_t prev = 0, pos;
77 while ((pos = line.find_first_of(kWhitespaceASCII, prev)) != std::string::npos)
78 {
79 if (pos > prev)
80 tokensOut->push_back(line.substr(prev, pos - prev));
81 prev = pos + 1;
82 }
83 if (prev < line.length())
84 tokensOut->push_back(line.substr(prev, std::string::npos));
85 }
86 }
87
TrimString(const std::string & input,const std::string & trimChars)88 std::string TrimString(const std::string &input, const std::string &trimChars)
89 {
90 auto begin = input.find_first_not_of(trimChars);
91 if (begin == std::string::npos)
92 {
93 return "";
94 }
95
96 std::string::size_type end = input.find_last_not_of(trimChars);
97 if (end == std::string::npos)
98 {
99 return input.substr(begin);
100 }
101
102 return input.substr(begin, end - begin + 1);
103 }
104
GetPrefix(const std::string & input,size_t offset,const char * delimiter)105 std::string GetPrefix(const std::string &input, size_t offset, const char *delimiter)
106 {
107 size_t match = input.find(delimiter, offset);
108 if (match == std::string::npos)
109 {
110 return input.substr(offset);
111 }
112 return input.substr(offset, match - offset);
113 }
114
GetPrefix(const std::string & input,size_t offset,char delimiter)115 std::string GetPrefix(const std::string &input, size_t offset, char delimiter)
116 {
117 size_t match = input.find(delimiter, offset);
118 if (match == std::string::npos)
119 {
120 return input.substr(offset);
121 }
122 return input.substr(offset, match - offset);
123 }
124
HexStringToUInt(const std::string & input,unsigned int * uintOut)125 bool HexStringToUInt(const std::string &input, unsigned int *uintOut)
126 {
127 unsigned int offset = 0;
128
129 if (input.size() >= 2 && input[0] == '0' && input[1] == 'x')
130 {
131 offset = 2u;
132 }
133
134 // Simple validity check
135 if (input.find_first_not_of("0123456789ABCDEFabcdef", offset) != std::string::npos)
136 {
137 return false;
138 }
139
140 std::stringstream inStream(input);
141 inStream >> std::hex >> *uintOut;
142 return !inStream.fail();
143 }
144
ReadFileToString(const std::string & path,std::string * stringOut)145 bool ReadFileToString(const std::string &path, std::string *stringOut)
146 {
147 std::ifstream inFile(path.c_str());
148 if (inFile.fail())
149 {
150 return false;
151 }
152
153 inFile.seekg(0, std::ios::end);
154 stringOut->reserve(static_cast<std::string::size_type>(inFile.tellg()));
155 inFile.seekg(0, std::ios::beg);
156
157 stringOut->assign(std::istreambuf_iterator<char>(inFile), std::istreambuf_iterator<char>());
158 return !inFile.fail();
159 }
160
BeginsWith(const std::string & str,const std::string & prefix)161 bool BeginsWith(const std::string &str, const std::string &prefix)
162 {
163 return strncmp(str.c_str(), prefix.c_str(), prefix.length()) == 0;
164 }
165
BeginsWith(const std::string & str,const char * prefix)166 bool BeginsWith(const std::string &str, const char *prefix)
167 {
168 return strncmp(str.c_str(), prefix, strlen(prefix)) == 0;
169 }
170
BeginsWith(const char * str,const char * prefix)171 bool BeginsWith(const char *str, const char *prefix)
172 {
173 return strncmp(str, prefix, strlen(prefix)) == 0;
174 }
175
BeginsWith(const std::string & str,const std::string & prefix,const size_t prefixLength)176 bool BeginsWith(const std::string &str, const std::string &prefix, const size_t prefixLength)
177 {
178 return strncmp(str.c_str(), prefix.c_str(), prefixLength) == 0;
179 }
180
EndsWith(const std::string & str,const char * suffix)181 bool EndsWith(const std::string &str, const char *suffix)
182 {
183 const auto len = strlen(suffix);
184 if (len > str.size())
185 return false;
186
187 const char *end = str.c_str() + str.size() - len;
188
189 return memcmp(end, suffix, len) == 0;
190 }
191
ToLower(std::string * str)192 void ToLower(std::string *str)
193 {
194 for (auto &ch : *str)
195 {
196 ch = static_cast<char>(::tolower(ch));
197 }
198 }
199
ReplaceSubstring(std::string * str,const std::string & substring,const std::string & replacement)200 bool ReplaceSubstring(std::string *str,
201 const std::string &substring,
202 const std::string &replacement)
203 {
204 size_t replacePos = str->find(substring);
205 if (replacePos == std::string::npos)
206 {
207 return false;
208 }
209 str->replace(replacePos, substring.size(), replacement);
210 return true;
211 }
212
GetStringsFromEnvironmentVar(const char * varName,const char * separator)213 std::vector<std::string> GetStringsFromEnvironmentVar(const char *varName, const char *separator)
214 {
215 std::string environment = GetEnvironmentVar(varName);
216 return SplitString(environment, separator, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
217 }
218 } // namespace angle
219