Search:

SENF Extensible Network Framework

  • Home
  • Download
  • Wiki
  • BerliOS
  • ChangeLog
  • Browse SVN
  • Bug Tracker
  • Overview
  • Examples
  • HowTos
  • Glossary
  • PPI
  • Packets
  • Scheduler
  • Socket
  • Utils
  • Console
  • Daemon
  • Logger
  • Termlib
  • Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

Executor.cc

Go to the documentation of this file.
00001 // $Id: Executor.cc 1781 2011-04-11 12:10:19Z tho $
00002 //
00003 // Copyright (C) 2008
00004 // Fraunhofer (FOKUS)
00005 // Competence Center NETwork research (NET), St. Augustin, GERMANY
00006 //     Stefan Bund <g0dil@berlios.de>
00007 //
00008 // This program is free software; you can redistribute it and/or modify
00009 // it under the terms of the GNU General Public License as published by
00010 // the Free Software Foundation; either version 2 of the License, or
00011 // (at your option) any later version.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the
00020 // Free Software Foundation, Inc.,
00021 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00026 #include "Executor.hh"
00027 //#include "Executor.ih"
00028 
00029 // Custom includes
00030 #include <boost/utility.hpp>
00031 #include <boost/range/iterator_range.hpp>
00032 #include <boost/bind.hpp>
00033 #include <boost/format.hpp>
00034 #include <boost/preprocessor/stringize.hpp>
00035 #include <senf/Utils/senfassert.hh>
00036 #include <senf/Utils/Range.hh>
00037 #include "senf/Utils/IgnoreValue.hh"
00038 #include "Server.hh"
00039 
00040 //#include "Executor.mpp"
00041 #define prefix_
00042 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00043 
00044 namespace {
00045 
00046     struct TraversTokens {
00047         typedef std::string const & result_type;
00048         result_type operator()(senf::console::Token const & token) const {
00049             return token.value();
00050         }
00051     };
00052 
00053 }
00054 
00055 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00056 // senf::console::Executor
00057 
00058 prefix_ senf::console::DirectoryNode & senf::console::Executor::cwd()
00059     const
00060 {
00061     SENF_ASSERT( ! cwd_.empty(), "Internal error: CWD history empty ?" );
00062     while (cwd_.size()>1 && (cwd_.back().expired() || ! cwd_.back().lock()->active()))
00063         cwd_.pop_back();
00064     return * cwd_.back().lock();
00065 }
00066 
00067 prefix_ std::string senf::console::Executor::cwdPath()
00068     const
00069 {
00070     if (skipping())
00071         return "";
00072     senf::IGNORE( cwd() ); // ensure, cwd is live.
00073     return "/" + senf::stringJoin(
00074         senf::make_transform_range(
00075             boost::make_iterator_range(boost::next(cwd_.begin()), cwd_.end()),
00076             boost::bind(&DirectoryNode::name, boost::bind(&DirectoryNode::weak_ptr::lock, _1))),
00077         "/" );
00078 }
00079 
00080 prefix_ void senf::console::Executor::execute(std::ostream & output,
00081                                               ParseCommandInfo const & command)
00082 {
00083     SENF_LOG(( "Executing: " << command ));
00084 
00085     if (! skipping())
00086         senf::IGNORE( cwd() ); // Prune the cwd path of expired entries
00087 
00088     try {
00089         switch(command.builtin()) {
00090         case ParseCommandInfo::NoBuiltin :
00091             if (skipping())
00092                 return;
00093             exec(output, command);
00094             break;
00095 
00096         case ParseCommandInfo::BuiltinCD :
00097             if (skipping())
00098                 break;
00099             try {
00100                 // The parser ensures, we have exactly one argument
00101                 cd(command.commandPath());
00102             }
00103             catch (IgnoreCommandException &) {
00104                 throw SyntaxErrorException(
00105                     "'cd' cannot be skipped (don't use 'cd' in conf-files)");
00106             }
00107             break;
00108 
00109         case ParseCommandInfo::BuiltinLS :
00110             if (skipping())
00111                 break;
00112             // The parser ensures, we have either one or no argument
00113             ls( output, command.commandPath() );
00114             break;
00115 
00116         case ParseCommandInfo::BuiltinLL :
00117             if (skipping())
00118                 break;
00119             // The parser ensures, we have either one or no argument
00120             ll( output, command.commandPath() );
00121             break;
00122 
00123         case ParseCommandInfo::BuiltinLR :
00124             if (skipping())
00125                 break;
00126             // The parser ensures, we have either one or no argument
00127             lr( output, command.commandPath() );
00128             break;
00129 
00130         case ParseCommandInfo::BuiltinPUSHD :
00131             // The parser ensures, we have exactly one argument
00132             if (skipping())
00133                 pushd(command.commandPath());
00134             else
00135                 exec(output, command);
00136             break;
00137 
00138         case ParseCommandInfo::BuiltinPOPD :
00139             // The parser ensures, we have no arguments
00140             popd();
00141             break;
00142 
00143         case ParseCommandInfo::BuiltinEXIT :
00144             if (skipping())
00145                 break;
00146             // The parser ensures, we have no arguments
00147             exit();
00148             break;
00149 
00150         case ParseCommandInfo::BuiltinHELP :
00151             if (skipping())
00152                 break;
00153             // The parser ensures, we have either one or no arguments
00154             help( output, command.commandPath() );
00155             break;
00156 
00157         }
00158     }
00159     catch (InvalidPathException & ex) {
00160         throw SyntaxErrorException("invalid path") << " '" << ex.path << "'";
00161     }
00162     catch (InvalidDirectoryException & ex) {
00163         throw SyntaxErrorException("invalid directory") << " '" << ex.path << "'";
00164     }
00165     catch (InvalidCommandException &) {
00166         throw SyntaxErrorException("invalid command");
00167     }
00168     catch (IgnoreCommandException &) {}
00169 }
00170 
00171 prefix_ senf::console::GenericNode &
00172 senf::console::Executor::getNode(ParseCommandInfo const & command)
00173 {
00174     try {
00175         return traverseNode(command.commandPath());
00176     }
00177     catch (InvalidPathException & ex) {
00178         throw SyntaxErrorException("invalid path") << " '" << ex.path << "'";
00179     }
00180     catch (InvalidDirectoryException & ex) {
00181         throw SyntaxErrorException("invalid directory") << " '" << ex.path << "'";
00182     }
00183 }
00184 
00185 prefix_ void senf::console::Executor::exec(std::ostream & output,
00186                                            ParseCommandInfo const & command)
00187 {
00188     try {
00189         GenericNode & node ( traverseNode(command.commandPath()) );
00190         DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&node) );
00191         if ( dir ) {
00192             if (! command.tokens().empty())
00193                 throw InvalidCommandException();
00194             if (command.builtin() == ParseCommandInfo::BuiltinPUSHD)
00195                 pushd( command.commandPath() );
00196             else if (autocd_) {
00197                 cd(command.commandPath());
00198             }
00199             else
00200                 throw InvalidCommandException();
00201         } else {
00202             boost::any rv;
00203             dynamic_cast<CommandNode &>(node)(rv, output, command);
00204             if (command.builtin() == ParseCommandInfo::BuiltinPUSHD) {
00205                 DirectoryNode::ptr rvdir;
00206                 try {
00207                     rvdir = boost::any_cast<DirectoryNode::ptr>(rv);
00208                 }
00209                 catch (boost::bad_any_cast &) {
00210                     throw InvalidCommandException();
00211                 }
00212                 Path newDir (cwd_);
00213                 newDir.push_back(rvdir);
00214                 dirstack_.push_back(Path());
00215                 dirstack_.back().swap(cwd_);
00216                 cwd_.swap(newDir);
00217             }
00218         }
00219     }
00220     catch (IgnoreCommandException &) {
00221         if (command.builtin() == ParseCommandInfo::BuiltinPUSHD) {
00222             dirstack_.push_back(Path());
00223             dirstack_.back().swap(cwd_);
00224         }
00225         else
00226             throw;
00227     }
00228 }
00229 
00230 
00231 prefix_ void senf::console::Executor::cd(ParseCommandInfo::TokensRange dir)
00232 {
00233     if (dir.size() == 1 && *dir.begin() == WordToken("-")) {
00234         cwd_.swap(oldCwd_);
00235         senf::IGNORE( cwd() ); // Prune any expired items
00236     }
00237     else {
00238         // We need to use a temporary so an error somewhere while traversing the dir does not cause
00239         // the current directory to change.
00240         Path newDir (cwd_);
00241         traverseDirectory(dir, newDir);
00242         oldCwd_.swap(cwd_);
00243         cwd_.swap(newDir);
00244     }
00245 }
00246 
00247 prefix_ void senf::console::Executor::ls(std::ostream & output,
00248                                          ParseCommandInfo::TokensRange path)
00249 {
00250     Path dir (cwd_);
00251     traverseDirectory(path, dir);
00252     DirectoryNode & node (*dir.back().lock());
00253     DirectoryNode::child_iterator i (node.children().begin());
00254     DirectoryNode::child_iterator const i_end (node.children().end());
00255     for (; i != i_end; ++i)
00256         output << i->first << "\n";
00257 }
00258 
00259 prefix_ void senf::console::Executor::ll(std::ostream & output,
00260                                          ParseCommandInfo::TokensRange path)
00261 {
00262 #   define HELP_COLUMN 28
00263 
00264     unsigned width (Client::getWidth(output, 80u, 60u)-(HELP_COLUMN+1));
00265     Path dir (cwd_);
00266     traverseDirectory(path, dir);
00267     DirectoryNode & node (*dir.back().lock());
00268     DirectoryNode::child_iterator i (node.children().begin());
00269     DirectoryNode::child_iterator const i_end (node.children().end());
00270     boost::format fmt ("%s%s  %|" BOOST_PP_STRINGIZE(HELP_COLUMN) "t|%s\n");
00271     for (; i != i_end; ++i)
00272         output << fmt
00273             % i->first
00274             % ( i->second->isDirectory()
00275                 ? "/"
00276                 : i->second->isLink()
00277                 ? "@"
00278                 : "" )
00279             % i->second->shorthelp().substr(0,width);
00280 
00281 #   undef HELP_COLUMN
00282 }
00283 
00284 #   define HELP_COLUMN 40
00285 
00286 namespace {
00287 
00288     typedef std::map<senf::console::DirectoryNode*,std::string> NodesMap;
00289 
00290     void dolr(std::ostream & output, unsigned width, NodesMap & nodes, std::string const & base,
00291               unsigned level, senf::console::DirectoryNode & node)
00292     {
00293         boost::format fmt ("%s%s%s  %|" BOOST_PP_STRINGIZE(HELP_COLUMN) "t|%s\n");
00294         std::string pad (2*level, ' ');
00295         senf::console::DirectoryNode::child_iterator i (node.children().begin());
00296         senf::console::DirectoryNode::child_iterator const i_end (node.children().end());
00297         for (; i != i_end; ++i) {
00298             if (i->second->followLink().isDirectory()) {
00299                 senf::console::DirectoryNode & subnode (
00300                     static_cast<senf::console::DirectoryNode&>(i->second->followLink()));
00301                 NodesMap::iterator j (nodes.find(&subnode));
00302                 if (j == nodes.end()) {
00303                     output << fmt
00304                         % pad % i->first
00305                         % ( i->second->isDirectory() ? "/" : i->second->isLink() ? "@" : "" )
00306                         % i->second->shorthelp().substr(0,width);
00307                     std::string subbase (base);
00308                     if (! subbase.empty())
00309                         subbase += "/";
00310                     subbase += i->first;
00311                     nodes.insert(std::make_pair(&subnode, subbase));
00312                     dolr(output, width, nodes, subbase, level+1, subnode);
00313                 } else
00314                     output << pad << i->first
00315                            << ( i->second->isDirectory() ? "/" : i->second->isLink() ? "@" : "" )
00316                            << " -> " << j->second << "\n";
00317             } else {
00318                 output << fmt
00319                     % pad % i->first
00320                     % ( i->second->isDirectory() ? "/" : i->second->isLink() ? "@" : "" )
00321                     % i->second->shorthelp().substr(0,width);
00322             }
00323         }
00324     }
00325 
00326 }
00327 
00328 prefix_ void senf::console::Executor::lr(std::ostream & output,
00329                                          ParseCommandInfo::TokensRange path)
00330 {
00331     Path dir (cwd_);
00332     traverseDirectory(path, dir);
00333     DirectoryNode & node (*dir.back().lock());
00334     NodesMap nodes;
00335     dolr(output, Client::getWidth(output, 80u, 60u)-(HELP_COLUMN+1),
00336          nodes, "", 0, node);
00337 }
00338 
00339 #undef HELP_COLUMN
00340 
00341 prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir)
00342 {
00343     Path newDir (cwd_);
00344     if (! skipping()) {
00345         try {
00346             traverseDirectory(dir, newDir);
00347         }
00348         catch (IgnoreCommandException &) {
00349             newDir.clear();
00350         }
00351     }
00352     dirstack_.push_back(Path());
00353     dirstack_.back().swap(cwd_);
00354     cwd_.swap(newDir);
00355 }
00356 
00357 prefix_ void senf::console::Executor::popd()
00358 {
00359     if (! dirstack_.empty()) {
00360         cwd_.swap(dirstack_.back());
00361         dirstack_.pop_back();
00362     }
00363 }
00364 
00365 prefix_ void senf::console::Executor::exit()
00366 {
00367     throw ExitException();
00368 }
00369 
00370 prefix_ void senf::console::Executor::help(std::ostream & output,
00371                                            ParseCommandInfo::TokensRange path)
00372 {
00373     GenericNode const & node (traverseNode(path));
00374     // output << prettyName(typeid(node)) << " at " << node.path() << "\n\n";
00375     node.help(output);
00376     output << std::flush;
00377 }
00378 
00379 prefix_ senf::console::GenericNode &
00380 senf::console::Executor::traverseNode(ParseCommandInfo::TokensRange const & path)
00381 {
00382     if (path.empty())
00383         return *cwd_.back().lock();
00384     try {
00385         Path dir (cwd_);
00386         traverseDirectory(boost::make_iterator_range(
00387                               path.begin(),
00388                               boost::prior(path.end())),
00389                           dir);
00390         // For auto-cd support we need to check against '.' and '..' here too
00391         Token const & tok (*boost::prior(path.end()));
00392         if (tok == WordToken("..")) {
00393             if (dir.size() > 1)
00394                 dir.pop_back();
00395             return *dir.back().lock();
00396         }
00397         DirectoryNode & base (*dir.back().lock());
00398         if (tok == WordToken(".") || tok == NoneToken())
00399             return base;
00400         std::string const & name (complete(base, tok.value()));
00401         if (policy_)
00402             policy_( base, name );
00403         return dir.back().lock()->get(name);
00404     }
00405     catch (UnknownNodeNameException &) {
00406         throw InvalidPathException(
00407             senf::stringJoin(
00408                 senf::make_transform_range(path, boost::bind(&Token::value, _1)),
00409                 "/"));
00410     }
00411 }
00412 
00413 prefix_ void
00414 senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path,
00415                                            Path & dir)
00416 {
00417     std::string errorPath;
00418     try {
00419         ParseCommandInfo::TokensRange::const_iterator i (path.begin());
00420         ParseCommandInfo::TokensRange::const_iterator const i_end (path.end());
00421         for (; i != i_end; ++i) {
00422             if (i != path.begin())
00423                 errorPath += "/";
00424             errorPath += i->value();
00425             if (*i == NoneToken()) {
00426                 if (i == path.begin()) {
00427                     dir.clear();
00428                     dir.push_back(root_);
00429                 }
00430             }
00431             else if (*i == WordToken("..")) {
00432                 if (dir.size() > 1)
00433                     dir.pop_back();
00434             }
00435             else if (*i ==  WordToken("."))
00436                 ;
00437             else {
00438                 DirectoryNode & base (*dir.back().lock());
00439                 std::string name (complete(base, i->value()));
00440                 if (policy_)
00441                     policy_( base, name );
00442                 dir.push_back(base[name].thisptr());
00443             }
00444         }
00445     }
00446     catch (std::bad_cast &) {
00447         throw InvalidDirectoryException(errorPath);
00448     }
00449     catch (UnknownNodeNameException &) {
00450         throw InvalidDirectoryException(errorPath);
00451     }
00452 }
00453 
00454 prefix_ std::string senf::console::Executor::complete(DirectoryNode & dir,
00455                                                       std::string const & name)
00456 {
00457     if (! dir.hasChild(name)) {
00458         DirectoryNode::ChildrenRange completions (dir.completions(name));
00459         if (has_one_elt(completions))
00460             return completions.begin()->first;
00461     }
00462     return name;
00463 }
00464 
00465 prefix_ void senf::console::senf_console_format_value(DirectoryNode::ptr value,
00466                                                       std::ostream & os)
00467 {
00468     if (value)
00469         os << "<Directory at '" << value->path() << "'>";
00470     else
00471         os << "<Null Directory>";
00472 }
00473 
00474 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00475 #undef prefix_
00476 //#include "Executor.mpp"
00477 
00478 
00479 // Local Variables:
00480 // mode: c++
00481 // fill-column: 100
00482 // comment-column: 40
00483 // c-file-style: "senf"
00484 // indent-tabs-mode: nil
00485 // ispell-local-dictionary: "american"
00486 // compile-command: "scons -u test"
00487 // End:

Contact: senf-dev@lists.berlios.de | © 2006-2010 Fraunhofer Institute for Open Communication Systems, Network Research