diff options
-rw-r--r-- | libbuild2/functions-builtin.cxx | 25 | ||||
-rw-r--r-- | libbuild2/name.cxx | 26 | ||||
-rw-r--r-- | libbuild2/name.hxx | 16 |
3 files changed, 59 insertions, 8 deletions
diff --git a/libbuild2/functions-builtin.cxx b/libbuild2/functions-builtin.cxx index 2acd5b4..6f1b704 100644 --- a/libbuild2/functions-builtin.cxx +++ b/libbuild2/functions-builtin.cxx @@ -2,9 +2,13 @@ // copyright : Copyright (c) 2014-2019 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file +#include <sstream> + #include <libbuild2/function.hxx> #include <libbuild2/variable.hxx> +using namespace std; + namespace build2 { // Return NULL value if an environment variable is not set, untyped value @@ -41,6 +45,27 @@ namespace build2 f["string"] = [](uint64_t i) {return to_string (i);}; f["string"] = [](name n) {return to_string (n);}; + // Quote a value returning its string representation. If escape is true, + // then also escape (with a backslash) the quote characters being added + // (this is useful if the result will be re-parsed, for example as a + // Testscript command line). + // + f["quote"] = [](value* v, optional<value> escape) + { + if (v->null) + return string (); + + untypify (*v); // Reverse to names. + + ostringstream os; + to_stream (os, + v->as<names> (), + true /* quote */, + '@' /* pair */, + escape && convert<bool> (move (*escape))); + return os.str (); + }; + // getenv // f["getenv"] = [](string name) diff --git a/libbuild2/name.cxx b/libbuild2/name.cxx index 4aac32f..84e03db 100644 --- a/libbuild2/name.cxx +++ b/libbuild2/name.cxx @@ -60,9 +60,9 @@ namespace build2 } ostream& - to_stream (ostream& os, const name& n, bool quote, char pair) + to_stream (ostream& os, const name& n, bool quote, char pair, bool escape) { - auto write_string = [quote, pair, &os](const string& v) + auto write_string = [quote, pair, escape, &os](const string& v) { char sc[] = { '{', '}', '[', ']', '$', '(', ')', // Token endings. @@ -78,6 +78,7 @@ namespace build2 // Quote the string with the double quotes rather than with the single // one. Escape some of the special characters. // + if (escape) os << '\\'; os << '"'; for (auto c: v) @@ -88,10 +89,19 @@ namespace build2 os << c; } + if (escape) os << '\\'; os << '"'; } else if (quote && v.find_first_of (sc) != string::npos) - os << "'" << v << "'"; + { + if (escape) os << '\\'; + os << '\''; + + os << v; + + if (escape) os << '\\'; + os << '\''; + } else os << v; }; @@ -115,7 +125,7 @@ namespace build2 // If quoted then print empty name as '' rather than {}. // if (quote && n.empty ()) - return os << "''"; + return os << (escape ? "\\'\\'" : "''"); if (n.proj) { @@ -168,13 +178,17 @@ namespace build2 } ostream& - to_stream (ostream& os, const names_view& ns, bool quote, char pair) + to_stream (ostream& os, + const names_view& ns, + bool quote, + char pair, + bool escape) { for (auto i (ns.begin ()), e (ns.end ()); i != e; ) { const name& n (*i); ++i; - to_stream (os, n, quote, pair); + to_stream (os, n, quote, pair, escape); if (n.pair) os << n.pair; diff --git a/libbuild2/name.hxx b/libbuild2/name.hxx index 1ce073a..738645d 100644 --- a/libbuild2/name.hxx +++ b/libbuild2/name.hxx @@ -129,11 +129,19 @@ namespace build2 // // \$(" // + // If escape is true, then escape (with a backslash) the quote characters + // being added (this is useful if the result will be re-parsed, for example + // as a Testscript command line). + // // Note that in the quoted mode empty unqualified name is printed as '', // not {}. // LIBBUILD2_SYMEXPORT ostream& - to_stream (ostream&, const name&, bool quote, char pair = '\0'); + to_stream (ostream&, + const name&, + bool quote, + char pair = '\0', + bool escape = false); inline ostream& operator<< (ostream& os, const name& n) {return to_stream (os, n, false);} @@ -153,7 +161,11 @@ namespace build2 // The same semantics as to_stream(name). // LIBBUILD2_SYMEXPORT ostream& - to_stream (ostream&, const names_view&, bool quote, char pair = '\0'); + to_stream (ostream&, + const names_view&, + bool quote, + char pair = '\0', + bool escape = false); inline ostream& operator<< (ostream& os, const names_view& ns) { |