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 <boost/format.hpp>
34 #include "../../Utils/senfassert.hh"
35 #include "../../Utils/Range.hh"
36 #include "../../Utils/String.hh"
37 #include "../../Utils/range.hh"
39 //#include "Executor.mpp"
41 ///////////////////////////////cc.p////////////////////////////////////////
45 struct TraversTokens {
46 typedef std::string const & result_type;
47 result_type operator()(senf::console::Token const & token) const {
54 ///////////////////////////////////////////////////////////////////////////
55 // senf::console::Executor
57 prefix_ senf::console::DirectoryNode & senf::console::Executor::cwd()
60 SENF_ASSERT( ! cwd_.empty() );
61 while (cwd_.size()>1 && (cwd_.back().expired() || ! cwd_.back().lock()->active()))
63 return * cwd_.back().lock();
66 prefix_ std::string senf::console::Executor::cwdPath()
71 (void) cwd(); // ensure, cwd is live.
72 return "/" + senf::stringJoin(
73 senf::make_transform_range(
74 boost::make_iterator_range(boost::next(cwd_.begin()), cwd_.end()),
75 boost::bind(&DirectoryNode::name, boost::bind(&DirectoryNode::weak_ptr::lock, _1))),
79 prefix_ void senf::console::Executor::execute(std::ostream & output,
80 ParseCommandInfo const & command)
82 SENF_LOG(( "Executing: " << command ));
85 (void) cwd(); // Prune the cwd path of expired entries
88 switch(command.builtin()) {
89 case ParseCommandInfo::NoBuiltin :
92 exec(output, command);
95 case ParseCommandInfo::BuiltinCD :
99 // The parser ensures, we have exactly one argument
100 cd(command.commandPath());
102 catch (IgnoreCommandException &) {
103 throw SyntaxErrorException(
104 "'cd' cannot be skipped (don't use 'cd' in conf-files)");
108 case ParseCommandInfo::BuiltinLS :
111 // The parser ensures, we have either one or no argument
112 ls( output, command.commandPath() );
115 case ParseCommandInfo::BuiltinPUSHD :
116 // The parser ensures, we have exactly one argument
118 pushd(command.commandPath());
120 exec(output, command);
123 case ParseCommandInfo::BuiltinPOPD :
124 // The parser ensures, we have no arguments
128 case ParseCommandInfo::BuiltinEXIT :
131 // The parser ensures, we have no arguments
135 case ParseCommandInfo::BuiltinHELP :
138 // The parser ensures, we have either one or no arguments
139 help( output, command.commandPath() );
144 catch (InvalidPathException & ex) {
145 throw SyntaxErrorException("invalid path") << " '" << ex.path << "'";
147 catch (InvalidDirectoryException & ex) {
148 throw SyntaxErrorException("invalid directory") << " '" << ex.path << "'";
150 catch (InvalidCommandException &) {
151 throw SyntaxErrorException("invalid command");
153 catch (IgnoreCommandException &) {}
156 prefix_ void senf::console::Executor::exec(std::ostream & output,
157 ParseCommandInfo const & command)
160 GenericNode & node ( traverseNode(command.commandPath()) );
161 DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&node) );
163 if (! command.tokens().empty())
164 throw InvalidCommandException();
165 if (command.builtin() == ParseCommandInfo::BuiltinPUSHD)
166 pushd( command.commandPath() );
168 cd(command.commandPath());
171 throw InvalidCommandException();
174 dynamic_cast<CommandNode &>(node)(rv, output, command);
175 if (command.builtin() == ParseCommandInfo::BuiltinPUSHD) {
176 DirectoryNode::ptr rvdir;
178 rvdir = boost::any_cast<DirectoryNode::ptr>(rv);
180 catch (boost::bad_any_cast &) {
181 throw InvalidCommandException();
184 newDir.push_back(rvdir);
185 dirstack_.push_back(Path());
186 dirstack_.back().swap(cwd_);
191 catch (IgnoreCommandException &) {
192 if (command.builtin() == ParseCommandInfo::BuiltinPUSHD) {
193 dirstack_.push_back(Path());
194 dirstack_.back().swap(cwd_);
202 prefix_ void senf::console::Executor::cd(ParseCommandInfo::TokensRange dir)
204 if (dir.size() == 1 && *dir.begin() == WordToken("-")) {
206 (void) cwd(); // Prune any expired items
209 // We need to use a temporary so an error somewhere while traversing the dir does not cause
210 // the current directory to change.
212 traverseDirectory(dir, newDir);
218 prefix_ void senf::console::Executor::ls(std::ostream & output,
219 ParseCommandInfo::TokensRange path)
222 traverseDirectory(path, dir);
223 DirectoryNode & node (*dir.back().lock());
224 DirectoryNode::child_iterator i (node.children().begin());
225 DirectoryNode::child_iterator const i_end (node.children().end());
226 boost::format fmt ("%s%s %|20t|%.59s\n");
227 for (; i != i_end; ++i)
230 % ( i->second->isDirectory()
232 : i->second->isLink()
235 % i->second->shorthelp();
238 prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir)
243 traverseDirectory(dir, newDir);
245 catch (IgnoreCommandException &) {
249 dirstack_.push_back(Path());
250 dirstack_.back().swap(cwd_);
254 prefix_ void senf::console::Executor::popd()
256 if (! dirstack_.empty()) {
257 cwd_.swap(dirstack_.back());
258 dirstack_.pop_back();
262 prefix_ void senf::console::Executor::exit()
264 throw ExitException();
267 prefix_ void senf::console::Executor::help(std::ostream & output,
268 ParseCommandInfo::TokensRange path)
270 GenericNode const & node (traverseNode(path));
271 // output << prettyName(typeid(node)) << " at " << node.path() << "\n\n";
273 output << std::flush;
276 prefix_ senf::console::GenericNode &
277 senf::console::Executor::traverseNode(ParseCommandInfo::TokensRange const & path)
280 return *cwd_.back().lock();
283 traverseDirectory(boost::make_iterator_range(
285 boost::prior(path.end())),
287 // For auto-cd support we need to check against '.' and '..' here too
288 Token const & tok (*boost::prior(path.end()));
289 if (tok == WordToken("..")) {
292 return *dir.back().lock();
294 DirectoryNode & base (*dir.back().lock());
295 if (tok == WordToken(".") || tok == NoneToken())
297 std::string const & name (complete(base, tok.value()));
299 policy_( base, name );
300 return dir.back().lock()->get(name);
302 catch (UnknownNodeNameException &) {
303 throw InvalidPathException(
305 senf::make_transform_range(path, boost::bind(&Token::value, _1)),
311 senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path,
314 std::string errorPath;
316 ParseCommandInfo::TokensRange::const_iterator i (path.begin());
317 ParseCommandInfo::TokensRange::const_iterator const i_end (path.end());
318 for (; i != i_end; ++i) {
319 if (i != path.begin())
321 errorPath += i->value();
322 if (*i == NoneToken()) {
323 if (i == path.begin()) {
325 dir.push_back(root_);
328 else if (*i == WordToken("..")) {
332 else if (*i == WordToken("."))
335 DirectoryNode & base (*dir.back().lock());
336 std::string name (complete(base, i->value()));
338 policy_( base, name );
339 dir.push_back(base[name].thisptr());
343 catch (std::bad_cast &) {
344 throw InvalidDirectoryException(errorPath);
346 catch (UnknownNodeNameException &) {
347 throw InvalidDirectoryException(errorPath);
351 prefix_ std::string senf::console::Executor::complete(DirectoryNode & dir,
352 std::string const & name)
354 if (! dir.hasChild(name)) {
355 DirectoryNode::ChildrenRange completions (dir.completions(name));
356 if (has_one_elt(completions))
357 return completions.begin()->first;
362 prefix_ void senf::console::senf_console_format_value(DirectoryNode::ptr value,
366 os << "<Directory at '" << value->path() << "'>";
368 os << "<Null Directory>";
371 ///////////////////////////////cc.e////////////////////////////////////////
373 //#include "Executor.mpp"
379 // comment-column: 40
380 // c-file-style: "senf"
381 // indent-tabs-mode: nil
382 // ispell-local-dictionary: "american"
383 // compile-command: "scons -u test"