diff options
author | Mu Qiao <qiaomuf@gentoo.org> | 2011-06-23 17:46:16 +0800 |
---|---|---|
committer | Petteri Räty <petsku@petteriraty.eu> | 2011-07-03 23:09:19 +0300 |
commit | 2bd9927e275728d55698592cc7534b636d34f797 (patch) | |
tree | 73252dc6d69ba161b3dc9a1b223e3031fe6a3b20 /src | |
parent | Build: remove auto generated files (diff) | |
download | libbash-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.cpp | 44 | ||||
-rw-r--r-- | src/builtins/shift_builtin.h | 35 | ||||
-rw-r--r-- | src/builtins/tests/shift_tests.cpp | 69 | ||||
-rw-r--r-- | src/core/interpreter.cpp | 9 | ||||
-rw-r--r-- | src/core/interpreter.h | 5 | ||||
-rw-r--r-- | src/core/symbols.hpp | 29 | ||||
-rw-r--r-- | src/cppbash_builtin.cpp | 2 |
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*>()}, |