1 /*
2  * Copyright 2019 WebAssembly Community Group participants
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //
18 // String helpers.
19 //
20 
21 #ifndef wasm_support_string_h
22 #define wasm_support_string_h
23 
24 #include <cctype>
25 #include <string>
26 #include <vector>
27 
28 namespace wasm {
29 
30 namespace String {
31 
32 // Creates a vector of the split parts of a string, by a delimiter.
33 class Split : public std::vector<std::string> {
34 public:
35   Split() = default;
36 
Split(const std::string & input,const std::string & delim)37   Split(const std::string& input, const std::string& delim) {
38     size_t lastEnd = 0;
39     while (lastEnd < input.size()) {
40       auto nextDelim = input.find(delim, lastEnd);
41       if (nextDelim == std::string::npos) {
42         nextDelim = input.size();
43       }
44       (*this).push_back(input.substr(lastEnd, nextDelim - lastEnd));
45       lastEnd = nextDelim + delim.size();
46     }
47   }
48 };
49 
50 // Handles bracketing in a list initially split by ",", but the list may
51 // contain nested ","s. For example,
52 //   void foo(int, double)
53 // must be kept together because of the "(". Likewise, "{", "<", "[" are
54 // handled.
handleBracketingOperators(String::Split split)55 inline String::Split handleBracketingOperators(String::Split split) {
56   String::Split ret;
57   std::string last;
58   int nesting = 0;
59   auto handlePart = [&](std::string part) {
60     if (part.empty()) {
61       return;
62     }
63     for (const char c : part) {
64       if (c == '(' || c == '<' || c == '[' || c == '{') {
65         nesting++;
66       } else if (c == ')' || c == '>' || c == ']' || c == '}') {
67         nesting--;
68       }
69     }
70     if (last.empty()) {
71       last = part;
72     } else {
73       last += ',' + part;
74     }
75     if (nesting == 0) {
76       ret.push_back(last);
77       last.clear();
78     }
79   };
80   for (auto& part : split) {
81     handlePart(part);
82   }
83   handlePart("");
84   if (nesting != 0) {
85     Fatal() << "Asyncify: failed to parse lists";
86   }
87   return ret;
88 }
89 
90 // Does a simple '*' wildcard match between a pattern and a value.
wildcardMatch(const std::string & pattern,const std::string & value)91 inline bool wildcardMatch(const std::string& pattern,
92                           const std::string& value) {
93   for (size_t i = 0; i < pattern.size(); i++) {
94     if (pattern[i] == '*') {
95       return wildcardMatch(pattern.substr(i + 1), value.substr(i)) ||
96              (value.size() > 0 &&
97               wildcardMatch(pattern.substr(i), value.substr(i + 1)));
98     }
99     if (i >= value.size()) {
100       return false;
101     }
102     if (pattern[i] != value[i]) {
103       return false;
104     }
105   }
106   return value.size() == pattern.size();
107 }
108 
109 // Removes any extra whitespace or \0.
trim(const std::string & input)110 inline std::string trim(const std::string& input) {
111   size_t size = input.size();
112   while (size > 0 && (isspace(input[size - 1]) || input[size - 1] == '\0')) {
113     size--;
114   }
115   return input.substr(0, size);
116 }
117 
118 } // namespace String
119 
120 } // namespace wasm
121 
122 #endif // wasm_support_string_h
123