From 0e0842330d1ef11f9ac6fa70d9f84bdb16084c45 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 18 Oct 2019 15:20:49 +0200 Subject: Add $quote() function for quoting values This can be useful if we want to pass a value on the command line, for example, in a testscript: $* config.cxx=$quote($recall($cxx.path) $cxx.mode, true) --- libbuild2/functions-builtin.cxx | 25 +++++++++++++++++++++++++ libbuild2/name.cxx | 26 ++++++++++++++++++++------ libbuild2/name.hxx | 16 ++++++++++++++-- 3 files changed, 59 insertions(+), 8 deletions(-) (limited to 'libbuild2') 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 + #include #include +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 escape) + { + if (v->null) + return string (); + + untypify (*v); // Reverse to names. + + ostringstream os; + to_stream (os, + v->as (), + true /* quote */, + '@' /* pair */, + escape && convert (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) { -- cgit v1.1