Gentoo Archives: gentoo-commits

From: "Petteri Räty" <betelgeuse@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/libbash:master commit in: src/builtins/tests/, src/core/, src/builtins/
Date: Sun, 08 Jul 2012 09:31:38
Message-Id: 1341278179.31f6bbe25a23e7e0d2b1411b3952ba39066a195b.betelgeuse@gentoo
1 commit: 31f6bbe25a23e7e0d2b1411b3952ba39066a195b
2 Author: André Aparício <aparicio99 <AT> gmail <DOT> com>
3 AuthorDate: Mon May 28 22:48:16 2012 +0000
4 Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
5 CommitDate: Tue Jul 3 01:16:19 2012 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=31f6bbe2
7
8 Builtin: Implement set -u option
9
10 ---
11 src/builtins/set_builtin.cpp | 2 +
12 src/builtins/tests/set_tests.cpp | 19 ++++++++++++++
13 src/core/interpreter.cpp | 22 +++++++++++++++-
14 src/core/interpreter.h | 49 +++++++++++++++++++++++++++++++++++--
15 4 files changed, 87 insertions(+), 5 deletions(-)
16
17 diff --git a/src/builtins/set_builtin.cpp b/src/builtins/set_builtin.cpp
18 index fca0f82..6becb76 100644
19 --- a/src/builtins/set_builtin.cpp
20 +++ b/src/builtins/set_builtin.cpp
21 @@ -62,6 +62,8 @@ int set_builtin::exec(const std::vector<std::string>& bash_args)
22 case 'p':
23 case 't':
24 case 'u':
25 + _walker.set_option('u', bash_args[0][0] == '-');
26 + return 0;
27 case 'v':
28 case 'x':
29 case 'B':
30
31 diff --git a/src/builtins/tests/set_tests.cpp b/src/builtins/tests/set_tests.cpp
32 index c4807c9..2b724bb 100644
33 --- a/src/builtins/tests/set_tests.cpp
34 +++ b/src/builtins/tests/set_tests.cpp
35 @@ -41,3 +41,22 @@ TEST(set_builtin_test, positional)
36 EXPECT_EQ(0, walker.get_array_length("*"));
37 EXPECT_STREQ("", walker.resolve<std::string>("*", 1).c_str());
38 }
39 +
40 +TEST(set_builtin_test, u_option)
41 +{
42 + interpreter walker;
43 +
44 + EXPECT_EQ(0, cppbash_builtin::exec("set", {"-u"}, std::cout, std::cerr, std::cin, walker));
45 + EXPECT_THROW(walker.resolve<std::string>("VAR1").c_str(), libbash::unsupported_exception);
46 +
47 + walker.set_value("ARRAY", "foo");
48 + EXPECT_NO_THROW(walker.resolve<std::string>("ARRAY").c_str());
49 + EXPECT_THROW(walker.resolve<std::string>("ARRAY", 2).c_str(), libbash::unsupported_exception);
50 +
51 + walker.set_value("ARRAY", "foo", 3);
52 + EXPECT_NO_THROW(walker.resolve<std::string>("ARRAY", 3).c_str());
53 +
54 + EXPECT_EQ(0, cppbash_builtin::exec("set", {"+u"}, std::cout, std::cerr, std::cin, walker));
55 + EXPECT_NO_THROW(walker.resolve<std::string>("VAR2", 1).c_str());
56 +
57 +}
58
59 diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
60 index 405023d..1b8ef0a 100644
61 --- a/src/core/interpreter.cpp
62 +++ b/src/core/interpreter.cpp
63 @@ -248,7 +248,7 @@ std::string::size_type interpreter::get_length(const std::string& name,
64 const unsigned index) const
65 {
66 auto var = resolve_variable(name);
67 - if(!var)
68 + if(!is_valid(var, name))
69 return 0;
70 return var->get_length(index);
71 }
72 @@ -256,7 +256,7 @@ std::string::size_type interpreter::get_length(const std::string& name,
73 variable::size_type interpreter::get_array_length(const std::string& name) const
74 {
75 auto var = resolve_variable(name);
76 - if(!var)
77 + if(!is_valid(var, name))
78 return 0;
79 return var->get_array_length();
80 }
81 @@ -471,6 +471,24 @@ void interpreter::set_additional_option(const std::string& name, bool value)
82 iter->second = value;
83 }
84
85 +bool interpreter::get_option(const char name) const
86 +{
87 + auto iter = options.find(name);
88 + if(iter == options.end())
89 + throw libbash::illegal_argument_exception("Invalid bash option");
90 +
91 + return iter->second;
92 +}
93 +
94 +void interpreter::set_option(const char name, bool value)
95 +{
96 + auto iter = options.find(name);
97 + if(iter == options.end())
98 + throw libbash::illegal_argument_exception(name + " is not a valid bash option");
99 +
100 + iter->second = value;
101 +}
102 +
103 long interpreter::eval_arithmetic(const std::string& expression)
104 {
105 bash_ast ast(std::stringstream(expression), &bash_ast::parser_arithmetics);
106
107 diff --git a/src/core/interpreter.h b/src/core/interpreter.h
108 index dd72377..3f77f5d 100644
109 --- a/src/core/interpreter.h
110 +++ b/src/core/interpreter.h
111 @@ -189,6 +189,20 @@ public:
112 _out = &std::cout;
113 }
114
115 + /// \brief check whether a variable is valid and can be used
116 + /// \param var variable
117 + /// \return whether the variable is valid
118 + bool is_valid(const std::shared_ptr<variable>& var, const std::string& name) const
119 + {
120 + if(var)
121 + return true;
122 +
123 + if(get_option('u'))
124 + throw libbash::unsupported_exception(name + ": unbound variable");
125 +
126 + return false;
127 + }
128 +
129 /// \brief resolve string/long variable, local scope will be
130 /// checked first, then global scope
131 /// \param name variable name
132 @@ -199,10 +213,25 @@ public:
133 T resolve(const std::string& name, const unsigned index=0) const
134 {
135 auto var = resolve_variable(name);
136 - if(var)
137 + if(is_valid(var, name))
138 + {
139 + if(get_option('u') && var->is_unset(index))
140 + {
141 + if(name == "*")
142 + throw libbash::unsupported_exception("$" + boost::lexical_cast<std::string>(index) + ": unbound variable");
143 + else if(index == 0)
144 + throw libbash::unsupported_exception(name + ": unbound variable");
145 + else
146 + throw libbash::unsupported_exception(name + "[" + boost::lexical_cast<std::string>(index) + "]: unbound variable");
147 + }
148 return var->get_value<T>(index);
149 + }
150 else
151 + {
152 + if(get_option('u'))
153 + throw libbash::unsupported_exception(name + ": unbound variable");
154 return T{};
155 + }
156 }
157
158 /// \brief resolve array variable
159 @@ -212,7 +241,7 @@ public:
160 bool resolve_array(const std::string& name, std::vector<T>& values) const
161 {
162 auto var = resolve_variable(name);
163 - if(!var)
164 + if(!is_valid(var, name))
165 return false;
166
167 var->get_all_values(values);
168 @@ -467,7 +496,10 @@ public:
169 variable::size_type get_max_index(const std::string& name) const
170 {
171 auto var = resolve_variable(name);
172 - return var ? var->get_max_index() : 0;
173 + if(is_valid(var, name))
174 + return var->get_max_index();
175 + else
176 + return 0;
177 }
178
179 /// \brief get all array elements concatenated by space
180 @@ -496,6 +528,17 @@ public:
181 /// \return zero unless the name is not a valid shell option
182 void set_additional_option(const std::string& name, bool value);
183
184 + /// \brief get the status of shell optional behavior
185 + /// \param name the option name
186 + /// \return zero unless the name is not a valid shell option
187 + bool get_option(const char name) const;
188 +
189 + /// \brief set the status of shell optional behavior
190 + /// \param name the option name
191 + /// \param[in] value true if option is enabled, false otherwise
192 + /// \return zero unless the name is not a valid shell option
193 + void set_option(const char name, bool value);
194 +
195 /// \brief return an iterator referring to the first variable
196 /// \return iterator referring to the first variable
197 option_iterator additional_options_begin() const