aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bashast/libbashWalker.g17
-rw-r--r--scripts/command_execution.bash2
-rw-r--r--scripts/command_execution.bash.result4
-rw-r--r--src/builtins/echo_builtin.cpp2
-rw-r--r--src/builtins/printf_builtin.cpp2
-rw-r--r--src/builtins/tests/echo_tests.cpp9
-rw-r--r--src/core/interpreter.cpp3
-rw-r--r--src/cppbash_builtin.cpp6
-rw-r--r--src/cppbash_builtin.h11
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