aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--bashast/libbashWalker.g2
-rw-r--r--scripts/function_def.bash15
-rw-r--r--src/builtins/set_builtin.cpp79
-rw-r--r--src/builtins/set_builtin.h46
-rw-r--r--src/builtins/tests/set_tests.cpp43
-rw-r--r--src/core/interpreter.cpp15
-rw-r--r--src/core/interpreter.h3
-rw-r--r--src/cppbash_builtin.cpp2
9 files changed, 207 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index ca61091..cc57503 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -106,6 +106,7 @@ cppunittests_SOURCES = test/run_tests.cpp \
src/builtins/tests/shopt_tests.cpp \
src/builtins/tests/return_tests.cpp \
src/builtins/tests/read_tests.cpp \
+ src/builtins/tests/set_tests.cpp \
src/builtins/tests/printf_tests.cpp \
test/test.h \
test/test.cpp \
@@ -239,6 +240,8 @@ libbash_la_SOURCES = include/common.h \
src/builtins/unset_builtin.cpp \
src/builtins/read_builtin.h \
src/builtins/read_builtin.cpp \
+ src/builtins/set_builtin.h \
+ src/builtins/set_builtin.cpp \
src/builtins/builtin_exceptions.h \
$(GENERATED_PARSER_C) \
$(GENERATED_PARSER_H) \
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index fb1ca55..9157574 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -649,7 +649,7 @@ execute_command[std::string& name, std::vector<std::string>& libbash_args]
bool redirection = false;
}
@init {
- if(name != "local")
+ if(name != "local" && name != "set")
current_scope.reset(new interpreter::local_scope(*walker));
}
:var_def[true]* (redirect[out, err, in]{ redirection = true; })* {
diff --git a/scripts/function_def.bash b/scripts/function_def.bash
index b425221..53cc6da 100644
--- a/scripts/function_def.bash
+++ b/scripts/function_def.bash
@@ -76,6 +76,21 @@ func_positional_args() {
func_positional_args 1 2 3
IFS=" \t\n"
+nested_func_override_positional_args() {
+ echo $@
+ set -- 40 50 60
+ echo $@
+}
+func_override_positional_args() {
+ echo $@
+ nested_func_override_positional_args 4 5 6
+ set -- 10 20 30
+ echo $@
+}
+set -- foo bar
+func_override_positional_args 1 2 3
+echo $@
+
if true; then
function_in_compound_statement() {
echo "function_in_compound_statement"
diff --git a/src/builtins/set_builtin.cpp b/src/builtins/set_builtin.cpp
new file mode 100644
index 0000000..fca0f82
--- /dev/null
+++ b/src/builtins/set_builtin.cpp
@@ -0,0 +1,79 @@
+/*
+ Please use git log for copyright holder and year information
+
+ This file is part of libbash.
+
+ libbash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ libbash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libbash. If not, see <http://www.gnu.org/licenses/>.
+*/
+///
+/// \file set_builtin.cpp
+/// \brief class that implements the set builtin
+///
+#include "builtins/set_builtin.h"
+
+#include "core/interpreter.h"
+#include "exceptions.h"
+
+int set_builtin::exec(const std::vector<std::string>& bash_args)
+{
+ if(bash_args.empty())
+ {
+ throw libbash::unsupported_exception("set: variables printing are not supported");
+ return 1;
+ }
+
+ if(bash_args[0][0] != '-' && bash_args[0][0] != '+')
+ {
+ throw libbash::illegal_argument_exception("set: invalid option");
+ return 1;
+ }
+
+ switch(bash_args[0][1])
+ {
+ case '-':
+ if(bash_args[0][0] != '-') {
+ throw libbash::unsupported_exception("set: invalid option");
+ return 1;
+ }
+ else
+ {
+ _walker.define_positional_arguments(bash_args.begin() + 1, bash_args.end());
+ return 0;
+ }
+ case 'a':
+ case 'b':
+ case 'e':
+ case 'f':
+ case 'h':
+ case 'k':
+ case 'm':
+ case 'n':
+ case 'p':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'x':
+ case 'B':
+ case 'C':
+ case 'E':
+ case 'H':
+ case 'P':
+ case 'T':
+ throw libbash::unsupported_exception("set " + bash_args[0] + " is not supported yet");
+ return 1;
+ default:
+ throw libbash::illegal_argument_exception("set: unrecognized option: " + bash_args[0]);
+ return 1;
+ }
+}
diff --git a/src/builtins/set_builtin.h b/src/builtins/set_builtin.h
new file mode 100644
index 0000000..ad27243
--- /dev/null
+++ b/src/builtins/set_builtin.h
@@ -0,0 +1,46 @@
+/*
+ Please use git log for copyright holder and year information
+
+ This file is part of libbash.
+
+ libbash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ libbash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libbash. If not, see <http://www.gnu.org/licenses/>.
+*/
+///
+/// \file set_builtin.h
+/// \brief class that implements the set builtin
+///
+
+#ifndef LIBBASH_BUILTINS_SET_BUILTIN_H_
+#define LIBBASH_BUILTINS_SET_BUILTIN_H_
+
+#include "cppbash_builtin.h"
+
+///
+/// \class set_builtin
+/// \brief the set builtin for bash
+///
+class set_builtin: public virtual cppbash_builtin
+{
+public:
+ BUILTIN_CONSTRUCTOR(set)
+
+ ///
+ /// \brief runs the set builtin on the supplied arguments
+ /// \param bash_args the arguments to the set builtin
+ /// \return exit status of set
+ ///
+ virtual int exec(const std::vector<std::string>& bash_args);
+};
+
+#endif
diff --git a/src/builtins/tests/set_tests.cpp b/src/builtins/tests/set_tests.cpp
new file mode 100644
index 0000000..c4807c9
--- /dev/null
+++ b/src/builtins/tests/set_tests.cpp
@@ -0,0 +1,43 @@
+/*
+ Please use git log for copyright holder and year information
+
+ This file is part of libbash.
+
+ libbash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ libbash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libbash. If not, see <http://www.gnu.org/licenses/>.
+*/
+///
+/// \file set_tests.cpp
+/// \brief series of unit tests for set builtin
+///
+#include <boost/lexical_cast.hpp>
+#include <gtest/gtest.h>
+
+#include "core/interpreter.h"
+#include "cppbash_builtin.h"
+#include "exceptions.h"
+
+TEST(set_builtin_test, positional)
+{
+ interpreter walker;
+
+ EXPECT_EQ(0, cppbash_builtin::exec("set", {"--", "1", "2", "3"}, std::cout, std::cerr, std::cin, walker));
+ EXPECT_EQ(3, walker.get_array_length("*"));
+ EXPECT_STREQ("1", walker.resolve<std::string>("*", 1).c_str());
+ EXPECT_STREQ("2", walker.resolve<std::string>("*", 2).c_str());
+ EXPECT_STREQ("3", walker.resolve<std::string>("*", 3).c_str());
+
+ EXPECT_EQ(0, cppbash_builtin::exec("set", {"--"}, std::cout, std::cerr, std::cin, walker));
+ EXPECT_EQ(0, walker.get_array_length("*"));
+ EXPECT_STREQ("", walker.resolve<std::string>("*", 1).c_str());
+}
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
index b048353..405023d 100644
--- a/src/core/interpreter.cpp
+++ b/src/core/interpreter.cpp
@@ -312,6 +312,21 @@ void interpreter::define_function_arguments(scope& current_stack,
current_stack["*"].reset(new variable("*", positional_args));
}
+void interpreter::define_positional_arguments(const std::vector<std::string>::const_iterator begin,
+ const std::vector<std::string>::const_iterator end)
+{
+ std::map<unsigned, std::string> positional_args;
+ std::vector<std::string>::const_iterator iter = begin;
+
+ for(auto i = 1u; iter != end ; ++i, ++iter)
+ positional_args[i] = *iter;
+
+ if(local_members.size() < 1)
+ define("*", positional_args);
+ else
+ define_local("*", positional_args);
+}
+
namespace
{
bool check_function_name(const std::string& name)
diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index fbb9d48..dd72377 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -521,6 +521,9 @@ public:
/// \return zero unless n is greater than $# or less than zero, non-zero otherwise.
int shift(int shift_number);
+ void define_positional_arguments(const std::vector<std::string>::const_iterator begin,
+ const std::vector<std::string>::const_iterator end);
+
/// \brief perform expansion like ${var//foo/bar}
/// \param value the value to be expanded
/// \param pattern the pattern used to match the value
diff --git a/src/cppbash_builtin.cpp b/src/cppbash_builtin.cpp
index c93b94a..e4a7c29 100644
--- a/src/cppbash_builtin.cpp
+++ b/src/cppbash_builtin.cpp
@@ -45,6 +45,7 @@
#include "builtins/source_builtin.h"
#include "builtins/unset_builtin.h"
#include "builtins/read_builtin.h"
+#include "builtins/set_builtin.h"
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
@@ -75,6 +76,7 @@ cppbash_builtin::builtins_type& cppbash_builtin::builtins() {
{"let", boost::factory<let_builtin*>()},
{"unset", boost::factory<unset_builtin*>()},
{"read", boost::factory<read_builtin*>()},
+ {"set", boost::factory<set_builtin*>()},
});
return *p;
}