From a473abe80f4c42a366f0573bbbc762fa440b7fe6 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 26 Apr 2022 10:39:03 +0200 Subject: Use new cmdline type for canned command lines in {Build,Test}script --- libbuild2/test/init.cxx | 4 +- .../script/parser+command-re-parse.test.testscript | 2 +- .../test/script/parser+expansion.test.testscript | 2 +- libbuild2/test/script/parser.hxx | 2 +- libbuild2/test/script/script.cxx | 111 +++++++++++++++++++-- 5 files changed, 105 insertions(+), 16 deletions(-) (limited to 'libbuild2/test') diff --git a/libbuild2/test/init.cxx b/libbuild2/test/init.cxx index c2fc831..c80d3f0 100644 --- a/libbuild2/test/init.cxx +++ b/libbuild2/test/init.cxx @@ -115,8 +115,8 @@ namespace build2 // These are only used in testscript. // - vp.insert ("test.redirects"); - vp.insert ("test.cleanups"); + vp.insert ("test.redirects"); + vp.insert ("test.cleanups"); // Unless already set, default test.target to build.host. Note that it // can still be overriden by the user, e.g., in root.build. diff --git a/libbuild2/test/script/parser+command-re-parse.test.testscript b/libbuild2/test/script/parser+command-re-parse.test.testscript index 84465b3..5a082eb 100644 --- a/libbuild2/test/script/parser+command-re-parse.test.testscript +++ b/libbuild2/test/script/parser+command-re-parse.test.testscript @@ -4,7 +4,7 @@ : double-quote : $* <>EOO -x = cmd \">-\" "'<-'" +x = [cmdline] cmd \">-\" "'<-'" $x EOI cmd '>-' '<-' diff --git a/libbuild2/test/script/parser+expansion.test.testscript b/libbuild2/test/script/parser+expansion.test.testscript index 77a7d6d..c31b0ad 100644 --- a/libbuild2/test/script/parser+expansion.test.testscript +++ b/libbuild2/test/script/parser+expansion.test.testscript @@ -27,7 +27,7 @@ EOE : invalid-redirect : $* <>EOE != 0 -x = "1>&a" +x = [cmdline] "1>&a" cmd $x EOI :1:4: error: stdout merge redirect file descriptor must be 2 diff --git a/libbuild2/test/script/parser.hxx b/libbuild2/test/script/parser.hxx index 66160d9..0d15580 100644 --- a/libbuild2/test/script/parser.hxx +++ b/libbuild2/test/script/parser.hxx @@ -30,7 +30,7 @@ namespace build2 // Pre-parse. Issue diagnostics and throw failed in case of an error. // public: - parser (context& c): build2::script::parser (c, true /* relex */) {} + parser (context& c): build2::script::parser (c) {} void pre_parse (script&); diff --git a/libbuild2/test/script/script.cxx b/libbuild2/test/script/script.cxx index 3a8ceac..be86117 100644 --- a/libbuild2/test/script/script.cxx +++ b/libbuild2/test/script/script.cxx @@ -197,12 +197,12 @@ namespace build2 test_var (var_pool.insert ("test")), options_var (var_pool.insert ("test.options")), arguments_var (var_pool.insert ("test.arguments")), - redirects_var (var_pool.insert ("test.redirects")), - cleanups_var (var_pool.insert ("test.cleanups")), + redirects_var (var_pool.insert ("test.redirects")), + cleanups_var (var_pool.insert ("test.cleanups")), wd_var (var_pool.insert ("~")), id_var (var_pool.insert ("@")), - cmd_var (var_pool.insert ("*")), + cmd_var (var_pool.insert ("*")), cmdN_var { &var_pool.insert ("0"), &var_pool.insert ("1"), @@ -410,11 +410,12 @@ namespace build2 // First assemble the $* value and save the test variable value into // the test program set. // - strings s; + cmdline s; - auto append = [&s] (const strings& v) + auto append = [&s] (const strings& vs) { - s.insert (s.end (), v.begin (), v.end ()); + for (const string& v: vs) + s.push_back (name (v)); // Simple name. }; // If the test variable can't be looked up for any reason (is NULL, @@ -423,7 +424,7 @@ namespace build2 if (auto l = lookup (root.test_var)) { const path& p (cast (l)); - s.push_back (p.representation ()); + s.push_back (name (p.representation ())); test_programs[0] = &p; @@ -441,10 +442,16 @@ namespace build2 size_t n (s.size ()); if (auto l = lookup (root.redirects_var)) - append (cast (l)); + { + const auto& v (cast (l)); + s.insert (s.end (), v.begin (), v.end ()); + } if (auto l = lookup (root.cleanups_var)) - append (cast (l)); + { + const auto& v (cast (l)); + s.insert (s.end (), v.begin (), v.end ()); + } // Set the $N values if present. // @@ -455,9 +462,9 @@ namespace build2 if (i < n) { if (i == 0) - v = path (s[i]); + v = path (s[i].value); else - v = s[i]; + v = s[i].value; } else v = nullptr; // Clear any old values. @@ -465,6 +472,88 @@ namespace build2 // Set $*. // + // We need to effective-quote the $test $test.options, $test.arguments + // part of it since they will be re-lexed. See the Testscript manual + // for details on quoting semantics. In particular, we cannot escape + // the special character (|<>&) so we have to rely on quoting. We can + // use single-quoting for everything except if the value contains a + // single quote. In which case we should probably just do separately- + // quoted regions (similar to shell), for example: + // + // <''> + // + // Can be quoted as: + // + // '<'"''"'>' + // + for (size_t i (0); i != n; ++i) + { + string& v (s[i].value); + + // Check if the quoting is required for this value. + // + if (!parser::need_cmdline_relex (v)) + continue; + + // If the value doesn't contain the single-quote character, then + // single-quote it. + // + size_t p (v.find ('\'')); + + if (p == string::npos) + { + v = "'" + v + "'"; + continue; + } + + // Otherwise quote the regions. + // + // Note that we double-quote the single-quote character sequences + // and single-quote all the other regions. + // + string r; + char q (p == 0 ? '"' : '\''); // Current region quoting mode. + + r += q; // Open the first region. + + for (char c: v) + { + // If we are in the double-quoting mode, then switch to the + // single-quoting mode if a non-single-quote character is + // encountered. + // + if (q == '"') + { + if (c != '\'') + { + r += q; // Close the double-quoted region. + q = '\''; // Set the single-quoting mode. + r += q; // Open the single-quoted region. + } + } + // + // If we are in the single-quoting mode, then switch to the + // double-quoting mode if the single-quote character is + // encountered. + // + else + { + if (c == '\'') + { + r += q; // Close the single-quoted region. + q = '"'; // Set the double-quoting mode. + r += q; // Open the double-quoted region. + } + } + + r += c; + } + + r += q; // Close the last region. + + v = move (r); + } + assign (root.cmd_var) = move (s); } -- cgit v1.1