diff options
-rw-r--r-- | bashast/libbashWalker.g | 17 | ||||
-rw-r--r-- | scripts/command_execution.bash | 2 | ||||
-rw-r--r-- | scripts/command_execution.bash.result | 4 | ||||
-rw-r--r-- | src/builtins/echo_builtin.cpp | 2 | ||||
-rw-r--r-- | src/builtins/printf_builtin.cpp | 2 | ||||
-rw-r--r-- | src/builtins/tests/echo_tests.cpp | 9 | ||||
-rw-r--r-- | src/core/interpreter.cpp | 3 | ||||
-rw-r--r-- | src/cppbash_builtin.cpp | 6 | ||||
-rw-r--r-- | src/cppbash_builtin.h | 11 |
9 files changed, 45 insertions, 11 deletions
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g index f379183..a16d501 100644 --- a/bashast/libbashWalker.g +++ b/bashast/libbashWalker.g @@ -153,6 +153,13 @@ options boost::numeric_cast<unsigned>(token->stop - token->start + 1)); } + std::string get_single_quoted_string(pANTLR3_BASE_TREE node) + { + pANTLR3_COMMON_TOKEN token = node->getToken(node); + return std::string(reinterpret_cast<const char *>(token->start + 1), + boost::numeric_cast<unsigned>(token->stop - token->start - 1)); + } + char get_char(pANTLR3_BASE_TREE node) { return *reinterpret_cast<const char *>(node->getToken(node)->start); @@ -267,9 +274,7 @@ string_part returns[std::string libbash_value, bool quoted, bool is_raw_string] $quoted = true; })*) |(SINGLE_QUOTED_STRING) => ^(SINGLE_QUOTED_STRING node=SINGLE_QUOTED_STRING_TOKEN) { - pANTLR3_COMMON_TOKEN token = node->getToken(node); - $libbash_value = std::string(reinterpret_cast<const char *>(token->start + 1), - boost::numeric_cast<unsigned>(token->stop - token->start - 1)); + $libbash_value = get_single_quoted_string(node); } |(ARITHMETIC_EXPRESSION) => ^(ARITHMETIC_EXPRESSION value=arithmetics { @@ -284,6 +289,12 @@ string_part returns[std::string libbash_value, bool quoted, bool is_raw_string] $libbash_value = libbash_string; $is_raw_string = false; } + |(ANSI_C_QUOTING) => ^(ANSI_C_QUOTING node=SINGLE_QUOTED_STRING_TOKEN) { + std::stringstream transformed; + cppbash_builtin::transform_escapes(get_single_quoted_string(node), transformed, true); + $libbash_value = transformed.str(); + $quoted = true; + } |(libbash_string=any_string { $libbash_value = libbash_string; }); diff --git a/scripts/command_execution.bash b/scripts/command_execution.bash index 76e9c4c..dff9984 100644 --- a/scripts/command_execution.bash +++ b/scripts/command_execution.bash @@ -57,3 +57,5 @@ printf "%s %s\n" abc def printf "%s %s\n" $FOO001, def ((FOO010=1)) echo "abc #av### ##" # for comment +echo $'abc\tdef\nxyz' +echo -e "\'\"\t\n" diff --git a/scripts/command_execution.bash.result b/scripts/command_execution.bash.result index 5f9bede..0e2e1d6 100644 --- a/scripts/command_execution.bash.result +++ b/scripts/command_execution.bash.result @@ -56,6 +56,10 @@ shopt -u xpg_echo abc def hello, def abc #av### ## +abc def +xyz +\'" + DEFAULTED=yes FOO001=hello FOO002=Hello World diff --git a/src/builtins/echo_builtin.cpp b/src/builtins/echo_builtin.cpp index 8caecef..9440232 100644 --- a/src/builtins/echo_builtin.cpp +++ b/src/builtins/echo_builtin.cpp @@ -61,7 +61,7 @@ int echo_builtin::exec(const std::vector<std::string>& bash_args) { try { - transform_escapes(*i, out_buffer()); + cppbash_builtin::transform_escapes(*i, out_buffer(), false); } catch(suppress_output) { diff --git a/src/builtins/printf_builtin.cpp b/src/builtins/printf_builtin.cpp index 9b5fd41..db40fff 100644 --- a/src/builtins/printf_builtin.cpp +++ b/src/builtins/printf_builtin.cpp @@ -39,7 +39,7 @@ int printf_builtin::exec(const std::vector<std::string>& bash_args) begin = bash_args.begin() + 2; std::stringstream format_string; - transform_escapes(*begin, format_string); + cppbash_builtin::transform_escapes(*begin, format_string, false); boost::format formatter(format_string.str()); for(auto iter = begin + 1; iter != bash_args.end(); ++iter) formatter = formatter % *iter; diff --git a/src/builtins/tests/echo_tests.cpp b/src/builtins/tests/echo_tests.cpp index 7b38422..bd7e2d1 100644 --- a/src/builtins/tests/echo_tests.cpp +++ b/src/builtins/tests/echo_tests.cpp @@ -31,6 +31,15 @@ using namespace std; +TEST(echo_builtin_test, escaped_characters) +{ + stringstream test_output1, test_output2; + interpreter walker; + cppbash_builtin::exec("echo",{"-e", "\\e"},test_output1,cerr,cin,walker); + cppbash_builtin::exec("echo",{"-e", "\\E"},test_output2,cerr,cin,walker); + ASSERT_STREQ(test_output1.str().c_str(), test_output2.str().c_str()); +} + static void test_echo(const string& expected, std::initializer_list<string> args) { stringstream test_output; diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp index bd19925..ba69143 100644 --- a/src/core/interpreter.cpp +++ b/src/core/interpreter.cpp @@ -36,6 +36,9 @@ #include <boost/range/adaptor/filtered.hpp> #include <boost/range/adaptor/map.hpp> #include <boost/range/algorithm/copy.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/phoenix.hpp> +#include <boost/spirit/include/qi.hpp> #include "core/bash_ast.h" diff --git a/src/cppbash_builtin.cpp b/src/cppbash_builtin.cpp index 3cf4d18..c8eb5b9 100644 --- a/src/cppbash_builtin.cpp +++ b/src/cppbash_builtin.cpp @@ -74,7 +74,8 @@ cppbash_builtin::builtins_type& cppbash_builtin::builtins() { } void cppbash_builtin::transform_escapes(const std::string &string, - std::ostream& output) const + std::ostream& output, + bool ansi_c) { using phoenix::val; using qi::lit; @@ -87,11 +88,14 @@ void cppbash_builtin::transform_escapes(const std::string &string, lit('b')[output << val("\b")] | // \e is a GNU extension lit('e')[output << val("\033")] | + lit('E')[output << val("\033")] | lit('f')[output << val("\f")] | lit('n')[output << val("\n")] | lit('r')[output << val("\r")] | lit('t')[output << val("\t")] | lit('v')[output << val("\v")] | + lit('\'')[output << val(ansi_c ? "'" : "\\'")] | + lit('"')[output << val(ansi_c ? "\"" : "\\\"")] | lit('c')[phoenix::throw_(suppress_output())] | lit('\\')[output << val('\\')] | lit("0") >> qi::uint_parser<unsigned, 8, 1, 3>()[ output << phoenix::static_cast_<char>(qi::_1)] | diff --git a/src/cppbash_builtin.h b/src/cppbash_builtin.h index 04ff387..5b27fad 100644 --- a/src/cppbash_builtin.h +++ b/src/cppbash_builtin.h @@ -104,6 +104,12 @@ class cppbash_builtin: public boost::noncopyable return builtin_map.find(builtin) != builtin_map.end(); } + /// \brief transforms escapes in quoted string + /// \param string the target string + /// \param output the place to write + /// \param ansi_c whether to follow ANSI C standard + static void transform_escapes(const std::string &string, std::ostream& output, bool ansi_c); + protected: /// /// \var *_out_stream @@ -129,11 +135,6 @@ class cppbash_builtin: public boost::noncopyable /// holds factories for creating instances of child classes typedef std::map<std::string, boost::function< cppbash_builtin*(BUILTIN_ARGS) >> builtins_type; static builtins_type& builtins(); - - /// \brief transforms escapes in echo input - /// \param string the target string - /// \param output the place to write - void transform_escapes(const std::string &string, std::ostream& output) const; }; /// shortcut for builtin constructor |