diff options
author | 2012-04-06 22:08:10 +0100 | |
---|---|---|
committer | 2012-07-03 02:16:10 +0100 | |
commit | fed16223f8539afc0a15fdd3496f625bc3f0b821 (patch) | |
tree | 5b4cc171593f174bc2ec850487ff9a469a7c9b4a | |
parent | Utils: add debug-print-function (diff) | |
download | libbash-fed16223f8539afc0a15fdd3496f625bc3f0b821.tar.gz libbash-fed16223f8539afc0a15fdd3496f625bc3f0b821.tar.bz2 libbash-fed16223f8539afc0a15fdd3496f625bc3f0b821.zip |
Builtin: implement read builtin
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | src/builtins/read_builtin.cpp | 94 | ||||
-rw-r--r-- | src/builtins/read_builtin.h | 54 | ||||
-rw-r--r-- | src/builtins/tests/read_tests.cpp | 76 | ||||
-rw-r--r-- | src/cppbash_builtin.cpp | 2 |
5 files changed, 229 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index cbc9f3b..ca61091 100644 --- a/Makefile.am +++ b/Makefile.am @@ -105,6 +105,7 @@ cppunittests_SOURCES = test/run_tests.cpp \ src/builtins/tests/shift_tests.cpp \ src/builtins/tests/shopt_tests.cpp \ src/builtins/tests/return_tests.cpp \ + src/builtins/tests/read_tests.cpp \ src/builtins/tests/printf_tests.cpp \ test/test.h \ test/test.cpp \ @@ -236,6 +237,8 @@ libbash_la_SOURCES = include/common.h \ src/builtins/inherit_builtin.cpp \ src/builtins/unset_builtin.h \ src/builtins/unset_builtin.cpp \ + src/builtins/read_builtin.h \ + src/builtins/read_builtin.cpp \ src/builtins/builtin_exceptions.h \ $(GENERATED_PARSER_C) \ $(GENERATED_PARSER_H) \ diff --git a/src/builtins/read_builtin.cpp b/src/builtins/read_builtin.cpp new file mode 100644 index 0000000..ca79094 --- /dev/null +++ b/src/builtins/read_builtin.cpp @@ -0,0 +1,94 @@ +/* + 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 read_builtin.cpp +/// \brief class that implements the read builtin +/// + +#include "builtins/read_builtin.h" + +#include <string.h> +#include <boost/algorithm/string.hpp> + +#include "core/interpreter.h" +#include "builtins/builtin_exceptions.h" + +void read_builtin::process(const std::vector<std::string>& args, const std::string& input) +{ + std::vector<std::string> split_input; + boost::split(split_input, input, boost::is_any_of(" ")); + + auto vars = args.begin(); + for(auto words = split_input.begin(); vars != args.end() && words != split_input.end(); ++vars, ++words) + { + if(vars != args.end() - 1) + { + _walker.set_value(*vars, *words); + } + else + { + std::string rest; + for(; words != split_input.end() - 1; ++words) + rest += *words + " "; + rest += *words; + _walker.set_value(*vars, rest); + } + } + + for(; vars != args.end(); ++vars) + _walker.set_value(*vars, ""); +} + +int read_builtin::exec(const std::vector<std::string>& bash_args) +{ + int return_value = 0; + std::string input; + std::stringstream formated_input; + + getline(this->input_buffer(), input); + + if(this->input_buffer().eof()) + return_value = 1; + + if(input.size() < 1) + return return_value; + + while(input[input.length()-1] == '\\') { + input.erase(input.end()-1); + std::string input_line; + getline(this->input_buffer(), input_line); + + if(this->input_buffer().eof()) + return_value = 1; + + if(input.size() < 1) + return return_value; + + input += input_line; + } + + cppbash_builtin::transform_escapes(input, formated_input, false); + + if(bash_args.empty()) + process({"REPLY"}, formated_input.str()); + else + process(bash_args, formated_input.str()); + + return return_value; +} diff --git a/src/builtins/read_builtin.h b/src/builtins/read_builtin.h new file mode 100644 index 0000000..caf8e86 --- /dev/null +++ b/src/builtins/read_builtin.h @@ -0,0 +1,54 @@ +/* + 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 read_builtin.h +/// \brief class that implements the read builtin +/// + +#ifndef LIBBASH_BUILTINS_READ_BUILTIN_H_ +#define LIBBASH_BUILTINS_READ_BUILTIN_H_ + +#include "../cppbash_builtin.h" + +/// +/// \class read_builtin +/// \brief the read builtin for bash +/// +class read_builtin: public virtual cppbash_builtin +{ + public: + BUILTIN_CONSTRUCTOR(read) + + /// + /// \brief runs the read builtin on the supplied arguments + /// \param bash_args the arguments to the read builtin + /// \return exit status of read + /// + virtual int exec(const std::vector<std::string>& bash_args); + + private: + /// + /// \brief assigns words from input to the variables + /// \param args the variables to be used + /// \param input the input to be assigned to the variables + /// + virtual void process(const std::vector<std::string>& bash_args, const std::string& input); +}; + +#endif diff --git a/src/builtins/tests/read_tests.cpp b/src/builtins/tests/read_tests.cpp new file mode 100644 index 0000000..9bc9683 --- /dev/null +++ b/src/builtins/tests/read_tests.cpp @@ -0,0 +1,76 @@ +/* + 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 read_tests.cpp +/// \brief series of unit tests for read builtin +/// +#include <iostream> +#include <sstream> +#include <vector> + +#include <gtest/gtest.h> + +#include "core/interpreter.h" +#include "cppbash_builtin.h" + +using namespace std; + +static void test_read(interpreter& walker, const string& input, std::initializer_list<string> args) +{ + stringstream test_input; + test_input << input; + cppbash_builtin::exec("read", args, std::cout, cerr, test_input, walker); +} + +TEST(read_builtin_test, argument_assignment) +{ + interpreter walker; + + test_read(walker, "foo bar", {}); + EXPECT_STREQ("foo bar", walker.resolve<std::string>("REPLY").c_str()); + + test_read(walker, "foo bar", {"var"}); + EXPECT_STREQ("foo bar", walker.resolve<std::string>("var").c_str()); + + test_read(walker, "foo bar", {"var1", "var2"}); + EXPECT_STREQ("foo", walker.resolve<std::string>("var1").c_str()); + EXPECT_STREQ("bar", walker.resolve<std::string>("var2").c_str()); + + test_read(walker, "1 2 3 4", {"var1", "var2"}); + EXPECT_STREQ("1", walker.resolve<std::string>("var1").c_str()); + EXPECT_STREQ("2 3 4", walker.resolve<std::string>("var2").c_str()); + + test_read(walker, "foo", {"var1", "var2"}); + EXPECT_STREQ("foo", walker.resolve<std::string>("var1").c_str()); + EXPECT_STREQ("", walker.resolve<std::string>("var2").c_str()); + + test_read(walker, "foo bar", {"var"}); + EXPECT_STREQ("foo bar", walker.resolve<std::string>("var").c_str()); +} + +TEST(read_builtin_test, line_continuation) +{ + interpreter walker; + + test_read(walker, "foo\\\nbar", {}); + EXPECT_STREQ("foobar", walker.resolve<std::string>("REPLY").c_str()); + + test_read(walker, "foo \\\n bar", {}); + EXPECT_STREQ("foo bar", walker.resolve<std::string>("REPLY").c_str()); +} diff --git a/src/cppbash_builtin.cpp b/src/cppbash_builtin.cpp index 452fe64..c93b94a 100644 --- a/src/cppbash_builtin.cpp +++ b/src/cppbash_builtin.cpp @@ -44,6 +44,7 @@ #include "builtins/shopt_builtin.h" #include "builtins/source_builtin.h" #include "builtins/unset_builtin.h" +#include "builtins/read_builtin.h" namespace qi = boost::spirit::qi; namespace karma = boost::spirit::karma; @@ -73,6 +74,7 @@ cppbash_builtin::builtins_type& cppbash_builtin::builtins() { {"printf", boost::factory<printf_builtin*>()}, {"let", boost::factory<let_builtin*>()}, {"unset", boost::factory<unset_builtin*>()}, + {"read", boost::factory<read_builtin*>()}, }); return *p; } |