1 |
commit: 2bd9927e275728d55698592cc7534b636d34f797 |
2 |
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org> |
3 |
AuthorDate: Thu Jun 23 09:46:16 2011 +0000 |
4 |
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org> |
5 |
CommitDate: Sun Jul 3 20:09:19 2011 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=2bd9927e |
7 |
|
8 |
Builtin: support shift built-in |
9 |
|
10 |
--- |
11 |
Makefile.am | 3 ++ |
12 |
src/builtins/shift_builtin.cpp | 44 +++++++++++++++++++++++ |
13 |
src/builtins/shift_builtin.h | 35 ++++++++++++++++++ |
14 |
src/builtins/tests/shift_tests.cpp | 69 ++++++++++++++++++++++++++++++++++++ |
15 |
src/core/interpreter.cpp | 9 +++++ |
16 |
src/core/interpreter.h | 5 +++ |
17 |
src/core/symbols.hpp | 29 +++++++++++++++ |
18 |
src/cppbash_builtin.cpp | 2 + |
19 |
8 files changed, 196 insertions(+), 0 deletions(-) |
20 |
|
21 |
diff --git a/Makefile.am b/Makefile.am |
22 |
index fb36438..81ad4e1 100644 |
23 |
--- a/Makefile.am |
24 |
+++ b/Makefile.am |
25 |
@@ -109,6 +109,7 @@ cppunittests_SOURCES = test/run_tests.cpp \ |
26 |
src/builtins/tests/declare_tests.cpp \ |
27 |
src/builtins/tests/boolean_tests.cpp \ |
28 |
src/builtins/tests/source_tests.cpp \ |
29 |
+ src/builtins/tests/shift_tests.cpp \ |
30 |
src/builtins/tests/shopt_tests.cpp \ |
31 |
src/builtins/tests/return_tests.cpp \ |
32 |
src/builtins/tests/printf_tests.cpp \ |
33 |
@@ -204,6 +205,8 @@ libcppbash_la_SOURCES = src/common.h \ |
34 |
src/builtins/boolean_builtins.h \ |
35 |
src/builtins/source_builtin.h \ |
36 |
src/builtins/source_builtin.cpp \ |
37 |
+ src/builtins/shift_builtin.h \ |
38 |
+ src/builtins/shift_builtin.cpp \ |
39 |
src/builtins/shopt_builtin.h \ |
40 |
src/builtins/shopt_builtin.cpp \ |
41 |
src/builtins/return_builtin.h \ |
42 |
|
43 |
diff --git a/src/builtins/shift_builtin.cpp b/src/builtins/shift_builtin.cpp |
44 |
new file mode 100644 |
45 |
index 0000000..c78c6ae |
46 |
--- /dev/null |
47 |
+++ b/src/builtins/shift_builtin.cpp |
48 |
@@ -0,0 +1,44 @@ |
49 |
+/* |
50 |
+ Please use git log for copyright holder and year information |
51 |
+ |
52 |
+ This file is part of libbash. |
53 |
+ |
54 |
+ libbash is free software: you can redistribute it and/or modify |
55 |
+ it under the terms of the GNU General Public License as published by |
56 |
+ the Free Software Foundation, either version 2 of the License, or |
57 |
+ (at your option) any later version. |
58 |
+ |
59 |
+ libbash is distributed in the hope that it will be useful, |
60 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
61 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
62 |
+ GNU General Public License for more details. |
63 |
+ |
64 |
+ You should have received a copy of the GNU General Public License |
65 |
+ along with libbash. If not, see <http://www.gnu.org/licenses/>. |
66 |
+*/ |
67 |
+/// |
68 |
+/// \file shift_builtin.h |
69 |
+/// \brief implementation for the shift builtin |
70 |
+/// |
71 |
+#include "builtins/shift_builtin.h" |
72 |
+ |
73 |
+#include <boost/lexical_cast.hpp> |
74 |
+ |
75 |
+#include "builtins/builtin_exceptions.h" |
76 |
+#include "core/exceptions.h" |
77 |
+#include "core/interpreter.h" |
78 |
+ |
79 |
+int shift_builtin::exec(const std::vector<std::string>& bash_args) |
80 |
+{ |
81 |
+ int shift_number = 1; |
82 |
+ |
83 |
+ if(!bash_args.empty()) |
84 |
+ { |
85 |
+ if(bash_args.size() != 1) |
86 |
+ throw libbash::illegal_argument_exception("shift: the number of arguments should be 1"); |
87 |
+ |
88 |
+ shift_number = boost::lexical_cast<int>(bash_args[0]); |
89 |
+ } |
90 |
+ |
91 |
+ return _walker.shift(shift_number); |
92 |
+} |
93 |
|
94 |
diff --git a/src/builtins/shift_builtin.h b/src/builtins/shift_builtin.h |
95 |
new file mode 100644 |
96 |
index 0000000..c413380 |
97 |
--- /dev/null |
98 |
+++ b/src/builtins/shift_builtin.h |
99 |
@@ -0,0 +1,35 @@ |
100 |
+/* |
101 |
+ Please use git log for copyright holder and year information |
102 |
+ |
103 |
+ This file is part of libbash. |
104 |
+ |
105 |
+ libbash is free software: you can redistribute it and/or modify |
106 |
+ it under the terms of the GNU General Public License as published by |
107 |
+ the Free Software Foundation, either version 2 of the License, or |
108 |
+ (at your option) any later version. |
109 |
+ |
110 |
+ libbash is distributed in the hope that it will be useful, |
111 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
112 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
113 |
+ GNU General Public License for more details. |
114 |
+ |
115 |
+ You should have received a copy of the GNU General Public License |
116 |
+ along with libbash. If not, see <http://www.gnu.org/licenses/>. |
117 |
+*/ |
118 |
+/// |
119 |
+/// \file shift_builtin.h |
120 |
+/// \brief implementation for the shift builtin |
121 |
+/// |
122 |
+#ifndef LIBBASH_BUILTINS_SHIFT_BUILTIN_H_ |
123 |
+#define LIBBASH_BUILTINS_SHIFT_BUILTIN_H_ |
124 |
+ |
125 |
+#include "cppbash_builtin.h" |
126 |
+ |
127 |
+class shift_builtin : public virtual cppbash_builtin |
128 |
+{ |
129 |
+public: |
130 |
+ BUILTIN_CONSTRUCTOR(shift) |
131 |
+ virtual int exec(const std::vector<std::string>& ); |
132 |
+}; |
133 |
+ |
134 |
+#endif |
135 |
|
136 |
diff --git a/src/builtins/tests/shift_tests.cpp b/src/builtins/tests/shift_tests.cpp |
137 |
new file mode 100644 |
138 |
index 0000000..8625a6c |
139 |
--- /dev/null |
140 |
+++ b/src/builtins/tests/shift_tests.cpp |
141 |
@@ -0,0 +1,69 @@ |
142 |
+/* |
143 |
+ Please use git log for copyright holder and year information |
144 |
+ |
145 |
+ This file is part of libbash. |
146 |
+ |
147 |
+ libbash is free software: you can redistribute it and/or modify |
148 |
+ it under the terms of the GNU General Public License as published by |
149 |
+ the Free Software Foundation, either version 2 of the License, or |
150 |
+ (at your option) any later version. |
151 |
+ |
152 |
+ libbash is distributed in the hope that it will be useful, |
153 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
154 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
155 |
+ GNU General Public License for more details. |
156 |
+ |
157 |
+ You should have received a copy of the GNU General Public License |
158 |
+ along with libbash. If not, see <http://www.gnu.org/licenses/>. |
159 |
+*/ |
160 |
+/// |
161 |
+/// \file shift_tests.cpp |
162 |
+/// \brief series of unit tests for shift builtin |
163 |
+/// |
164 |
+#include <boost/lexical_cast.hpp> |
165 |
+#include <gtest/gtest.h> |
166 |
+ |
167 |
+#include "core/exceptions.h" |
168 |
+#include "core/interpreter.h" |
169 |
+#include "cppbash_builtin.h" |
170 |
+ |
171 |
+TEST(shift_builtin_test, bad_argument) |
172 |
+{ |
173 |
+ interpreter walker; |
174 |
+ std::map<unsigned, std::string> values = {{1, "1"}, {2, "2"}, {3, "3"}}; |
175 |
+ walker.define("*", values); |
176 |
+ |
177 |
+ EXPECT_NE(0, cppbash_builtin::exec("shift", {"-1"}, std::cout, std::cerr, std::cin, walker)); |
178 |
+ EXPECT_NE(0, cppbash_builtin::exec("shift", {"4"}, std::cout, std::cerr, std::cin, walker)); |
179 |
+ EXPECT_THROW(cppbash_builtin::exec("shift", {"1", "2"}, std::cout, std::cerr, std::cin, walker), |
180 |
+ libbash::illegal_argument_exception); |
181 |
+ EXPECT_THROW(cppbash_builtin::exec("shift", {"abc"}, std::cout, std::cerr, std::cin, walker), |
182 |
+ boost::bad_lexical_cast); |
183 |
+} |
184 |
+ |
185 |
+TEST(shift_builtin_test, shift_all) |
186 |
+{ |
187 |
+ interpreter walker; |
188 |
+ std::map<unsigned, std::string> values = {{1, "1"}, {2, "2"}, {3, "3"}}; |
189 |
+ walker.define("*", values); |
190 |
+ |
191 |
+ EXPECT_EQ(0, cppbash_builtin::exec("shift", {"3"}, std::cout, std::cerr, std::cin, walker)); |
192 |
+ EXPECT_EQ(0, walker.get_array_length("*")); |
193 |
+} |
194 |
+ |
195 |
+TEST(shift_builtin_test, normal) |
196 |
+{ |
197 |
+ interpreter walker; |
198 |
+ std::map<unsigned, std::string> values = {{1, "1"}, {2, "2"}, {3, "3"}}; |
199 |
+ walker.define("*", values); |
200 |
+ |
201 |
+ EXPECT_EQ(0, cppbash_builtin::exec("shift", {"2"}, std::cout, std::cerr, std::cin, walker)); |
202 |
+ EXPECT_EQ(1, walker.get_array_length("*")); |
203 |
+ EXPECT_STREQ("3", walker.resolve<std::string>("*", 1).c_str()); |
204 |
+ |
205 |
+ walker.define("*", values); |
206 |
+ EXPECT_EQ(0, cppbash_builtin::exec("shift", {"1"}, std::cout, std::cerr, std::cin, walker)); |
207 |
+ EXPECT_EQ(2, walker.get_array_length("*")); |
208 |
+ EXPECT_STREQ("2", walker.resolve<std::string>("*", 1).c_str()); |
209 |
+ EXPECT_STREQ("3", walker.resolve<std::string>("*", 2).c_str()); |
210 |
+} |
211 |
|
212 |
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp |
213 |
index ed9f626..bd19925 100644 |
214 |
--- a/src/core/interpreter.cpp |
215 |
+++ b/src/core/interpreter.cpp |
216 |
@@ -435,3 +435,12 @@ long interpreter::eval_arithmetic(const std::string& expression) |
217 |
bash_ast ast(std::stringstream(expression), &bash_ast::parser_arithmetics); |
218 |
return ast.interpret_with(*this, &bash_ast::walker_arithmetics); |
219 |
} |
220 |
+ |
221 |
+int interpreter::shift(int shift_number) |
222 |
+{ |
223 |
+ auto parameters = resolve_variable("*"); |
224 |
+ if(shift_number < 0) |
225 |
+ return 1; |
226 |
+ |
227 |
+ return parameters->shift(static_cast<unsigned>(shift_number)); |
228 |
+} |
229 |
|
230 |
diff --git a/src/core/interpreter.h b/src/core/interpreter.h |
231 |
index c623e86..3363ae7 100644 |
232 |
--- a/src/core/interpreter.h |
233 |
+++ b/src/core/interpreter.h |
234 |
@@ -508,6 +508,11 @@ public: |
235 |
/// \return the evaluated result |
236 |
long eval_arithmetic(const std::string& expression); |
237 |
|
238 |
+ /// \brief shift the positional parameters to the left by n. |
239 |
+ /// \param the number to be shifted |
240 |
+ /// \return zero unless n is greater than $# or less than zero, non-zero otherwise. |
241 |
+ int shift(int shift_number); |
242 |
+ |
243 |
/// \brief perform expansion like ${var//foo/bar} |
244 |
/// \param value the value to be expanded |
245 |
/// \param pattern the pattern used to match the value |
246 |
|
247 |
diff --git a/src/core/symbols.hpp b/src/core/symbols.hpp |
248 |
index c535f8f..5114df1 100644 |
249 |
--- a/src/core/symbols.hpp |
250 |
+++ b/src/core/symbols.hpp |
251 |
@@ -33,6 +33,7 @@ |
252 |
|
253 |
#include <boost/variant.hpp> |
254 |
#include <boost/lexical_cast.hpp> |
255 |
+#include <boost/numeric/conversion/cast.hpp> |
256 |
|
257 |
#include "core/exceptions.h" |
258 |
|
259 |
@@ -234,6 +235,34 @@ public: |
260 |
{ |
261 |
return readonly; |
262 |
} |
263 |
+ |
264 |
+ int shift(unsigned shift_number) |
265 |
+ { |
266 |
+ assert(!readonly&&"readonly variables shouldn't be shifted"); |
267 |
+ // Remove this cast after making arithmetic expansion follow POSIX |
268 |
+ unsigned size = boost::numeric_cast<unsigned>(value.size()); |
269 |
+ |
270 |
+ if(shift_number > size) |
271 |
+ { |
272 |
+ return 1; |
273 |
+ } |
274 |
+ else if(shift_number == size) |
275 |
+ { |
276 |
+ value.clear(); |
277 |
+ } |
278 |
+ else |
279 |
+ { |
280 |
+ // copy elements |
281 |
+ for(unsigned i = shift_number + 1; i <= size; ++i) |
282 |
+ value[i - shift_number] = value[i]; |
283 |
+ |
284 |
+ // remove tail elements |
285 |
+ for(unsigned i = size - shift_number + 1; i <= size; ++i) |
286 |
+ value.erase(i); |
287 |
+ } |
288 |
+ |
289 |
+ return 0; |
290 |
+ } |
291 |
}; |
292 |
|
293 |
/// \brief the specialized constructor for arrays |
294 |
|
295 |
diff --git a/src/cppbash_builtin.cpp b/src/cppbash_builtin.cpp |
296 |
index 52c5c9b..3cf4d18 100644 |
297 |
--- a/src/cppbash_builtin.cpp |
298 |
+++ b/src/cppbash_builtin.cpp |
299 |
@@ -38,6 +38,7 @@ |
300 |
#include "builtins/let_builtin.h" |
301 |
#include "builtins/return_builtin.h" |
302 |
#include "builtins/printf_builtin.h" |
303 |
+#include "builtins/shift_builtin.h" |
304 |
#include "builtins/shopt_builtin.h" |
305 |
#include "builtins/source_builtin.h" |
306 |
#include "builtins/unset_builtin.h" |
307 |
@@ -58,6 +59,7 @@ cppbash_builtin::builtins_type& cppbash_builtin::builtins() { |
308 |
{"eval", boost::factory<eval_builtin*>()}, |
309 |
{"declare", boost::factory<declare_builtin*>()}, |
310 |
{"source", boost::factory<source_builtin*>()}, |
311 |
+ {"shift", boost::factory<shift_builtin*>()}, |
312 |
{"shopt", boost::factory<shopt_builtin*>()}, |
313 |
{"inherit", boost::factory<inherit_builtin*>()}, |
314 |
{":", boost::factory<true_builtin*>()}, |