aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMu Qiao <qiaomuf@gentoo.org>2011-06-23 17:46:16 +0800
committerPetteri Räty <petsku@petteriraty.eu>2011-07-03 23:09:19 +0300
commit2bd9927e275728d55698592cc7534b636d34f797 (patch)
tree73252dc6d69ba161b3dc9a1b223e3031fe6a3b20 /src
parentBuild: remove auto generated files (diff)
downloadlibbash-2bd9927e275728d55698592cc7534b636d34f797.tar.gz
libbash-2bd9927e275728d55698592cc7534b636d34f797.tar.bz2
libbash-2bd9927e275728d55698592cc7534b636d34f797.zip
Builtin: support shift built-in
Diffstat (limited to 'src')
-rw-r--r--src/builtins/shift_builtin.cpp44
-rw-r--r--src/builtins/shift_builtin.h35
-rw-r--r--src/builtins/tests/shift_tests.cpp69
-rw-r--r--src/core/interpreter.cpp9
-rw-r--r--src/core/interpreter.h5
-rw-r--r--src/core/symbols.hpp29
-rw-r--r--src/cppbash_builtin.cpp2
7 files changed, 193 insertions, 0 deletions
diff --git a/src/builtins/shift_builtin.cpp b/src/builtins/shift_builtin.cpp
new file mode 100644
index 0000000..c78c6ae
--- /dev/null
+++ b/src/builtins/shift_builtin.cpp
@@ -0,0 +1,44 @@
+/*
+ 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 shift_builtin.h
+/// \brief implementation for the shift builtin
+///
+#include "builtins/shift_builtin.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "builtins/builtin_exceptions.h"
+#include "core/exceptions.h"
+#include "core/interpreter.h"
+
+int shift_builtin::exec(const std::vector<std::string>& bash_args)
+{
+ int shift_number = 1;
+
+ if(!bash_args.empty())
+ {
+ if(bash_args.size() != 1)
+ throw libbash::illegal_argument_exception("shift: the number of arguments should be 1");
+
+ shift_number = boost::lexical_cast<int>(bash_args[0]);
+ }
+
+ return _walker.shift(shift_number);
+}
diff --git a/src/builtins/shift_builtin.h b/src/builtins/shift_builtin.h
new file mode 100644
index 0000000..c413380
--- /dev/null
+++ b/src/builtins/shift_builtin.h
@@ -0,0 +1,35 @@
+/*
+ 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 shift_builtin.h
+/// \brief implementation for the shift builtin
+///
+#ifndef LIBBASH_BUILTINS_SHIFT_BUILTIN_H_
+#define LIBBASH_BUILTINS_SHIFT_BUILTIN_H_
+
+#include "cppbash_builtin.h"
+
+class shift_builtin : public virtual cppbash_builtin
+{
+public:
+ BUILTIN_CONSTRUCTOR(shift)
+ virtual int exec(const std::vector<std::string>& );
+};
+
+#endif
diff --git a/src/builtins/tests/shift_tests.cpp b/src/builtins/tests/shift_tests.cpp
new file mode 100644
index 0000000..8625a6c
--- /dev/null
+++ b/src/builtins/tests/shift_tests.cpp
@@ -0,0 +1,69 @@
+/*
+ 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 shift_tests.cpp
+/// \brief series of unit tests for shift builtin
+///
+#include <boost/lexical_cast.hpp>
+#include <gtest/gtest.h>
+
+#include "core/exceptions.h"
+#include "core/interpreter.h"
+#include "cppbash_builtin.h"
+
+TEST(shift_builtin_test, bad_argument)
+{
+ interpreter walker;
+ std::map<unsigned, std::string> values = {{1, "1"}, {2, "2"}, {3, "3"}};
+ walker.define("*", values);
+
+ EXPECT_NE(0, cppbash_builtin::exec("shift", {"-1"}, std::cout, std::cerr, std::cin, walker));
+ EXPECT_NE(0, cppbash_builtin::exec("shift", {"4"}, std::cout, std::cerr, std::cin, walker));
+ EXPECT_THROW(cppbash_builtin::exec("shift", {"1", "2"}, std::cout, std::cerr, std::cin, walker),
+ libbash::illegal_argument_exception);
+ EXPECT_THROW(cppbash_builtin::exec("shift", {"abc"}, std::cout, std::cerr, std::cin, walker),
+ boost::bad_lexical_cast);
+}
+
+TEST(shift_builtin_test, shift_all)
+{
+ interpreter walker;
+ std::map<unsigned, std::string> values = {{1, "1"}, {2, "2"}, {3, "3"}};
+ walker.define("*", values);
+
+ EXPECT_EQ(0, cppbash_builtin::exec("shift", {"3"}, std::cout, std::cerr, std::cin, walker));
+ EXPECT_EQ(0, walker.get_array_length("*"));
+}
+
+TEST(shift_builtin_test, normal)
+{
+ interpreter walker;
+ std::map<unsigned, std::string> values = {{1, "1"}, {2, "2"}, {3, "3"}};
+ walker.define("*", values);
+
+ EXPECT_EQ(0, cppbash_builtin::exec("shift", {"2"}, std::cout, std::cerr, std::cin, walker));
+ EXPECT_EQ(1, walker.get_array_length("*"));
+ EXPECT_STREQ("3", walker.resolve<std::string>("*", 1).c_str());
+
+ walker.define("*", values);
+ EXPECT_EQ(0, cppbash_builtin::exec("shift", {"1"}, std::cout, std::cerr, std::cin, walker));
+ EXPECT_EQ(2, walker.get_array_length("*"));
+ EXPECT_STREQ("2", walker.resolve<std::string>("*", 1).c_str());
+ EXPECT_STREQ("3", walker.resolve<std::string>("*", 2).c_str());
+}
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
index ed9f626..bd19925 100644
--- a/src/core/interpreter.cpp
+++ b/src/core/interpreter.cpp
@@ -435,3 +435,12 @@ long interpreter::eval_arithmetic(const std::string& expression)
bash_ast ast(std::stringstream(expression), &bash_ast::parser_arithmetics);
return ast.interpret_with(*this, &bash_ast::walker_arithmetics);
}
+
+int interpreter::shift(int shift_number)
+{
+ auto parameters = resolve_variable("*");
+ if(shift_number < 0)
+ return 1;
+
+ return parameters->shift(static_cast<unsigned>(shift_number));
+}
diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index c623e86..3363ae7 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -508,6 +508,11 @@ public:
/// \return the evaluated result
long eval_arithmetic(const std::string& expression);
+ /// \brief shift the positional parameters to the left by n.
+ /// \param the number to be shifted
+ /// \return zero unless n is greater than $# or less than zero, non-zero otherwise.
+ int shift(int shift_number);
+
/// \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/core/symbols.hpp b/src/core/symbols.hpp
index c535f8f..5114df1 100644
--- a/src/core/symbols.hpp
+++ b/src/core/symbols.hpp
@@ -33,6 +33,7 @@
#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/numeric/conversion/cast.hpp>
#include "core/exceptions.h"
@@ -234,6 +235,34 @@ public:
{
return readonly;
}
+
+ int shift(unsigned shift_number)
+ {
+ assert(!readonly&&"readonly variables shouldn't be shifted");
+ // Remove this cast after making arithmetic expansion follow POSIX
+ unsigned size = boost::numeric_cast<unsigned>(value.size());
+
+ if(shift_number > size)
+ {
+ return 1;
+ }
+ else if(shift_number == size)
+ {
+ value.clear();
+ }
+ else
+ {
+ // copy elements
+ for(unsigned i = shift_number + 1; i <= size; ++i)
+ value[i - shift_number] = value[i];
+
+ // remove tail elements
+ for(unsigned i = size - shift_number + 1; i <= size; ++i)
+ value.erase(i);
+ }
+
+ return 0;
+ }
};
/// \brief the specialized constructor for arrays
diff --git a/src/cppbash_builtin.cpp b/src/cppbash_builtin.cpp
index 52c5c9b..3cf4d18 100644
--- a/src/cppbash_builtin.cpp
+++ b/src/cppbash_builtin.cpp
@@ -38,6 +38,7 @@
#include "builtins/let_builtin.h"
#include "builtins/return_builtin.h"
#include "builtins/printf_builtin.h"
+#include "builtins/shift_builtin.h"
#include "builtins/shopt_builtin.h"
#include "builtins/source_builtin.h"
#include "builtins/unset_builtin.h"
@@ -58,6 +59,7 @@ cppbash_builtin::builtins_type& cppbash_builtin::builtins() {
{"eval", boost::factory<eval_builtin*>()},
{"declare", boost::factory<declare_builtin*>()},
{"source", boost::factory<source_builtin*>()},
+ {"shift", boost::factory<shift_builtin*>()},
{"shopt", boost::factory<shopt_builtin*>()},
{"inherit", boost::factory<inherit_builtin*>()},
{":", boost::factory<true_builtin*>()},