4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief Executor non-inline non-template implementation */
26 #include "Executor.hh"
27 //#include "Executor.ih"
30 #include <boost/utility.hpp>
31 #include <boost/range/iterator_range.hpp>
32 #include <boost/bind.hpp>
33 #include "../Utils/senfassert.hh"
34 #include "../Utils/Range.hh"
35 #include "../Utils/String.hh"
37 //#include "Executor.mpp"
39 ///////////////////////////////cc.p////////////////////////////////////////
43 struct TraverseTokens {
44 typedef std::string const & result_type;
45 result_type operator()(senf::console::Token const & token) const {
52 ///////////////////////////////////////////////////////////////////////////
53 // senf::console::Executor
55 prefix_ senf::console::DirectoryNode & senf::console::Executor::cwd()
58 SENF_ASSERT( ! cwd_.empty() );
59 while (cwd_.size()>1 && (cwd_.back().expired() || ! cwd_.back().lock()->active()))
61 return * cwd_.back().lock();
64 prefix_ std::string senf::console::Executor::cwdPath()
69 return "/" + senf::stringJoin(
70 senf::make_transform_range(
71 boost::make_iterator_range(boost::next(cwd_.begin()), cwd_.end()),
72 boost::bind(&DirectoryNode::name, boost::bind(&DirectoryNode::weak_ptr::lock, _1))),
76 prefix_ void senf::console::Executor::execute(std::ostream & output,
77 ParseCommandInfo const & command)
79 SENF_LOG(( "Executing: " << command ));
82 (void) cwd(); // Prune the cwd path of expired entries
85 switch(command.builtin()) {
86 case ParseCommandInfo::NoBuiltin :
89 exec(output, command);
92 case ParseCommandInfo::BuiltinCD :
96 // The parser ensures, we have exactly one argument
97 cd(*command.arguments().begin());
99 catch (IgnoreCommandException &) {
100 throw SyntaxErrorException(
101 "'cd' cannot be skipped (don't use 'cd' in conf-files)");
105 case ParseCommandInfo::BuiltinLS :
108 // The parser ensures, we have either one or no argument
110 command.tokens().empty() ? command.tokens() : *command.arguments().begin() );
113 case ParseCommandInfo::BuiltinPUSHD :
114 // The parser ensures, we have exactly one argument
115 pushd( *command.arguments().begin() );
118 case ParseCommandInfo::BuiltinPOPD :
119 // The parser ensures, we have no arguments
123 case ParseCommandInfo::BuiltinEXIT :
126 // The parser ensures, we have no arguments
130 case ParseCommandInfo::BuiltinHELP :
133 // The parser ensures, we have either one or no arguments
135 command.tokens().empty() ? command.tokens() : *command.arguments().begin() );
140 catch (InvalidPathException &) {
141 throw SyntaxErrorException("invalid path");
143 catch (InvalidDirectoryException &) {
144 throw SyntaxErrorException("invalid directory");
146 catch (InvalidCommandException &) {
147 throw SyntaxErrorException("invalid command");
149 catch (IgnoreCommandException &) {}
152 prefix_ void senf::console::Executor::exec(std::ostream & output,
153 ParseCommandInfo const & command)
155 GenericNode & node ( traverseNode(command.commandPath()) );
156 DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&node) );
158 if (autocd_ && command.tokens().empty()) {
159 cd( boost::make_iterator_range(
160 command.commandPath().begin(),
161 command.commandPath().end()) );
163 throw InvalidCommandException();
165 dynamic_cast<CommandNode &>(node)(output, command);
170 prefix_ void senf::console::Executor::cd(ParseCommandInfo::TokensRange dir)
172 if (dir.size() == 1 && *dir.begin() == WordToken("-")) {
174 (void) cwd(); // Prune any expired items
177 // We need to use a temporary so an error somewhere while traversing the dir does not cause
178 // the current directory to change.
180 traverseDirectory(dir, newDir);
186 prefix_ void senf::console::Executor::ls(std::ostream & output,
187 ParseCommandInfo::TokensRange path)
190 traverseDirectory(path, dir);
191 DirectoryNode & node (*dir.back().lock());
192 DirectoryNode::child_iterator i (node.children().begin());
193 DirectoryNode::child_iterator const i_end (node.children().end());
194 for (; i != i_end; ++i) {
196 if (boost::dynamic_pointer_cast<DirectoryNode>(i->second))
202 prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir)
207 traverseDirectory(dir, newDir);
209 catch (IgnoreCommandException &) {
213 dirstack_.push_back(Path());
214 dirstack_.back().swap(cwd_);
218 prefix_ void senf::console::Executor::popd()
220 if (! dirstack_.empty()) {
221 cwd_.swap(dirstack_.back());
222 dirstack_.pop_back();
226 prefix_ void senf::console::Executor::exit()
228 throw ExitException();
231 prefix_ void senf::console::Executor::help(std::ostream & output,
232 ParseCommandInfo::TokensRange path)
234 GenericNode const & node (traverseNode(path));
235 output << prettyName(typeid(node)) << " at " << node.path() << "\n\n";
237 output << std::flush;
240 prefix_ senf::console::GenericNode &
241 senf::console::Executor::traverseNode(ParseCommandInfo::TokensRange const & path)
244 return *cwd_.back().lock();
247 traverseDirectory(boost::make_iterator_range(
249 boost::prior(path.end())),
251 DirectoryNode & base (*dir.back().lock());
252 std::string const & name (complete(base, boost::prior(path.end())->value()));
254 policy_( base, name );
255 return dir.back().lock()->get(name);
257 catch (UnknownNodeNameException &) {
258 throw InvalidPathException();
263 senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path,
267 ParseCommandInfo::TokensRange::const_iterator i (path.begin());
268 ParseCommandInfo::TokensRange::const_iterator const i_end (path.end());
269 for (; i != i_end; ++i) {
270 if (*i == NoneToken()) {
271 if (i == path.begin()) {
273 dir.push_back(root_);
276 else if (*i == WordToken("..")) {
280 else if (*i == WordToken("."))
283 DirectoryNode & base (*dir.back().lock());
284 std::string name (complete(base, i->value()));
286 policy_( base, name );
287 dir.push_back(base[name].thisptr());
291 catch (std::bad_cast &) {
292 throw InvalidDirectoryException();
294 catch (UnknownNodeNameException &) {
295 throw InvalidDirectoryException();
299 prefix_ std::string senf::console::Executor::complete(DirectoryNode & dir,
300 std::string const & name)
302 if (! dir.hasChild(name)) {
303 DirectoryNode::ChildrenRange completions (dir.completions(name));
304 if (completions.size() == 1)
305 return completions.begin()->first;
310 ///////////////////////////////cc.e////////////////////////////////////////
312 //#include "Executor.mpp"
318 // comment-column: 40
319 // c-file-style: "senf"
320 // indent-tabs-mode: nil
321 // ispell-local-dictionary: "american"
322 // compile-command: "scons -u test"