aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbuild2/functions-builtin.cxx25
-rw-r--r--libbuild2/name.cxx26
-rw-r--r--libbuild2/name.hxx16
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) {