|
|
@@ -72,6 +72,77 @@ std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep)
|
|
|
return tokens;
|
|
|
}
|
|
|
|
|
|
+void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut,
|
|
|
+ bool emptyArgs)
|
|
|
+{
|
|
|
+ // If argument is empty, it is an empty list.
|
|
|
+ if (!emptyArgs && arg.empty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // if there are no ; in the name then just copy the current string
|
|
|
+ if (arg.find(';') == cm::string_view::npos) {
|
|
|
+ argsOut.emplace_back(arg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string newArg;
|
|
|
+ // Break the string at non-escaped semicolons not nested in [].
|
|
|
+ int squareNesting = 0;
|
|
|
+ cm::string_view::iterator last = arg.begin();
|
|
|
+ cm::string_view::iterator const cend = arg.end();
|
|
|
+ for (cm::string_view::iterator c = last; c != cend; ++c) {
|
|
|
+ switch (*c) {
|
|
|
+ case '\\': {
|
|
|
+ // We only want to allow escaping of semicolons. Other
|
|
|
+ // escapes should not be processed here.
|
|
|
+ cm::string_view::iterator cnext = c + 1;
|
|
|
+ if ((cnext != cend) && *cnext == ';') {
|
|
|
+ newArg.append(last, c);
|
|
|
+ // Skip over the escape character
|
|
|
+ last = cnext;
|
|
|
+ c = cnext;
|
|
|
+ }
|
|
|
+ } break;
|
|
|
+ case '[': {
|
|
|
+ ++squareNesting;
|
|
|
+ } break;
|
|
|
+ case ']': {
|
|
|
+ --squareNesting;
|
|
|
+ } break;
|
|
|
+ case ';': {
|
|
|
+ // Break the string here if we are not nested inside square
|
|
|
+ // brackets.
|
|
|
+ if (squareNesting == 0) {
|
|
|
+ newArg.append(last, c);
|
|
|
+ // Skip over the semicolon
|
|
|
+ last = c + 1;
|
|
|
+ if (!newArg.empty() || emptyArgs) {
|
|
|
+ // Add the last argument if the string is not empty.
|
|
|
+ argsOut.push_back(newArg);
|
|
|
+ newArg.clear();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } break;
|
|
|
+ default: {
|
|
|
+ // Just append this character.
|
|
|
+ } break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ newArg.append(last, cend);
|
|
|
+ if (!newArg.empty() || emptyArgs) {
|
|
|
+ // Add the last argument if the string is not empty.
|
|
|
+ argsOut.push_back(std::move(newArg));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+std::vector<std::string> cmExpandedList(cm::string_view arg, bool emptyArgs)
|
|
|
+{
|
|
|
+ std::vector<std::string> argsOut;
|
|
|
+ cmExpandList(arg, argsOut, emptyArgs);
|
|
|
+ return argsOut;
|
|
|
+}
|
|
|
+
|
|
|
namespace {
|
|
|
template <std::size_t N, typename T>
|
|
|
inline void MakeDigits(cm::string_view& view, char (&digits)[N],
|