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
22 {
23 
EndsWithSuffix(const char * str,const size_t strLen,const char * suffix,const size_t suffixLen)24 bool EndsWithSuffix(const char *str,
25                     const size_t strLen,
26                     const char *suffix,
27                     const size_t suffixLen)
28 {
29     return suffixLen <= strLen && strncmp(str + strLen - suffixLen, suffix, suffixLen) == 0;
30 }
31 
32 }  // anonymous namespace
33 
34 namespace angle
35 {
36 
37 const char kWhitespaceASCII[] = " \f\n\r\t\v";
38 
SplitString(const std::string & input,const std::string & delimiters,WhitespaceHandling whitespace,SplitResult resultType)39 std::vector<std::string> SplitString(const std::string &input,
40                                      const std::string &delimiters,
41                                      WhitespaceHandling whitespace,
42                                      SplitResult resultType)
43 {
44     std::vector<std::string> result;
45     if (input.empty())
46     {
47         return result;
48     }
49 
50     std::string::size_type start = 0;
51     while (start != std::string::npos)
52     {
53         auto end = input.find_first_of(delimiters, start);
54 
55         std::string piece;
56         if (end == std::string::npos)
57         {
58             piece = input.substr(start);
59             start = std::string::npos;
60         }
61         else
62         {
63             piece = input.substr(start, end - start);
64             start = end + 1;
65         }
66 
67         if (whitespace == TRIM_WHITESPACE)
68         {
69             piece = TrimString(piece, kWhitespaceASCII);
70         }
71 
72         if (resultType == SPLIT_WANT_ALL || !piece.empty())
73         {
74             result.push_back(std::move(piece));
75         }
76     }
77 
78     return result;
79 }
80 
SplitStringAlongWhitespace(const std::string & input,std::vector<std::string> * tokensOut)81 void SplitStringAlongWhitespace(const std::string &input, std::vector<std::string> *tokensOut)
82 {
83 
84     std::istringstream stream(input);
85     std::string line;
86 
87     while (std::getline(stream, line))
88     {
89         size_t prev = 0, pos;
90         while ((pos = line.find_first_of(kWhitespaceASCII, prev)) != std::string::npos)
91         {
92             if (pos > prev)
93                 tokensOut->push_back(line.substr(prev, pos - prev));
94             prev = pos + 1;
95         }
96         if (prev < line.length())
97             tokensOut->push_back(line.substr(prev, std::string::npos));
98     }
99 }
100 
TrimString(const std::string & input,const std::string & trimChars)101 std::string TrimString(const std::string &input, const std::string &trimChars)
102 {
103     auto begin = input.find_first_not_of(trimChars);
104     if (begin == std::string::npos)
105     {
106         return "";
107     }
108 
109     std::string::size_type end = input.find_last_not_of(trimChars);
110     if (end == std::string::npos)
111     {
112         return input.substr(begin);
113     }
114 
115     return input.substr(begin, end - begin + 1);
116 }
117 
GetPrefix(const std::string & input,size_t offset,const char * delimiter)118 std::string GetPrefix(const std::string &input, size_t offset, const char *delimiter)
119 {
120     size_t match = input.find(delimiter, offset);
121     if (match == std::string::npos)
122     {
123         return input.substr(offset);
124     }
125     return input.substr(offset, match - offset);
126 }
127 
GetPrefix(const std::string & input,size_t offset,char delimiter)128 std::string GetPrefix(const std::string &input, size_t offset, char delimiter)
129 {
130     size_t match = input.find(delimiter, offset);
131     if (match == std::string::npos)
132     {
133         return input.substr(offset);
134     }
135     return input.substr(offset, match - offset);
136 }
137 
HexStringToUInt(const std::string & input,unsigned int * uintOut)138 bool HexStringToUInt(const std::string &input, unsigned int *uintOut)
139 {
140     unsigned int offset = 0;
141 
142     if (input.size() >= 2 && input[0] == '0' && input[1] == 'x')
143     {
144         offset = 2u;
145     }
146 
147     // Simple validity check
148     if (input.find_first_not_of("0123456789ABCDEFabcdef", offset) != std::string::npos)
149     {
150         return false;
151     }
152 
153     std::stringstream inStream(input);
154     inStream >> std::hex >> *uintOut;
155     return !inStream.fail();
156 }
157 
ReadFileToString(const std::string & path,std::string * stringOut)158 bool ReadFileToString(const std::string &path, std::string *stringOut)
159 {
160     std::ifstream inFile(path.c_str());
161     if (inFile.fail())
162     {
163         return false;
164     }
165 
166     inFile.seekg(0, std::ios::end);
167     stringOut->reserve(static_cast<std::string::size_type>(inFile.tellg()));
168     inFile.seekg(0, std::ios::beg);
169 
170     stringOut->assign(std::istreambuf_iterator<char>(inFile), std::istreambuf_iterator<char>());
171     return !inFile.fail();
172 }
173 
BeginsWith(const std::string & str,const std::string & prefix)174 bool BeginsWith(const std::string &str, const std::string &prefix)
175 {
176     return strncmp(str.c_str(), prefix.c_str(), prefix.length()) == 0;
177 }
178 
BeginsWith(const std::string & str,const char * prefix)179 bool BeginsWith(const std::string &str, const char *prefix)
180 {
181     return strncmp(str.c_str(), prefix, strlen(prefix)) == 0;
182 }
183 
BeginsWith(const char * str,const char * prefix)184 bool BeginsWith(const char *str, const char *prefix)
185 {
186     return strncmp(str, prefix, strlen(prefix)) == 0;
187 }
188 
BeginsWith(const std::string & str,const std::string & prefix,const size_t prefixLength)189 bool BeginsWith(const std::string &str, const std::string &prefix, const size_t prefixLength)
190 {
191     return strncmp(str.c_str(), prefix.c_str(), prefixLength) == 0;
192 }
193 
EndsWith(const std::string & str,const std::string & suffix)194 bool EndsWith(const std::string &str, const std::string &suffix)
195 {
196     return EndsWithSuffix(str.c_str(), str.length(), suffix.c_str(), suffix.length());
197 }
198 
EndsWith(const std::string & str,const char * suffix)199 bool EndsWith(const std::string &str, const char *suffix)
200 {
201     return EndsWithSuffix(str.c_str(), str.length(), suffix, strlen(suffix));
202 }
203 
EndsWith(const char * str,const char * suffix)204 bool EndsWith(const char *str, const char *suffix)
205 {
206     return EndsWithSuffix(str, strlen(str), suffix, strlen(suffix));
207 }
208 
ToLower(std::string * str)209 void ToLower(std::string *str)
210 {
211     for (char &ch : *str)
212     {
213         ch = static_cast<char>(::tolower(ch));
214     }
215 }
216 
ToUpper(std::string * str)217 void ToUpper(std::string *str)
218 {
219     for (char &ch : *str)
220     {
221         ch = static_cast<char>(::toupper(ch));
222     }
223 }
224 
ReplaceSubstring(std::string * str,const std::string & substring,const std::string & replacement)225 bool ReplaceSubstring(std::string *str,
226                       const std::string &substring,
227                       const std::string &replacement)
228 {
229     size_t replacePos = str->find(substring);
230     if (replacePos == std::string::npos)
231     {
232         return false;
233     }
234     str->replace(replacePos, substring.size(), replacement);
235     return true;
236 }
237 
GetStringsFromEnvironmentVarOrAndroidProperty(const char * varName,const char * propertyName,const char * separator)238 std::vector<std::string> GetStringsFromEnvironmentVarOrAndroidProperty(const char *varName,
239                                                                        const char *propertyName,
240                                                                        const char *separator)
241 {
242     std::string environment = GetEnvironmentVarOrAndroidProperty(varName, propertyName);
243     return SplitString(environment, separator, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
244 }
245 
GetCachedStringsFromEnvironmentVarOrAndroidProperty(const char * varName,const char * propertyName,const char * separator)246 std::vector<std::string> GetCachedStringsFromEnvironmentVarOrAndroidProperty(
247     const char *varName,
248     const char *propertyName,
249     const char *separator)
250 {
251     std::string environment = GetEnvironmentVarOrAndroidProperty(varName, propertyName);
252     return SplitString(environment, separator, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
253 }
254 }  // namespace angle
255