Missing changes from last commit
[senf.git] / Console / Executor.cc
index 7e16765..3a8c228 100644 (file)
@@ -46,42 +46,64 @@ namespace {
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::Executor
 
-prefix_ bool senf::console::Executor::operator()(ParseCommandInfo const & command,
-                                                 std::ostream & output)
+prefix_ void senf::console::Executor::execute(std::ostream & output,
+                                              ParseCommandInfo const & command)
 {
     SENF_LOG(( "Executing: " << command ));
 
-    ///\fixme Whenever checking cwd_.expired(), we also need to check, wether
-    /// the node is still connected to the root.
-    if (cwd_.expired())
-        cwd_ = root().thisptr();
+    if (cwd_.expired() || ! cwd().active())
+        cwd_ = root_;
 
     try {
         switch(command.builtin()) {
-        case ParseCommandInfo::NoBuiltin :
-            traverseToCommand(command.commandPath())(output, command.arguments());
+        case ParseCommandInfo::NoBuiltin : {
+            if (skipping_)
+                break;
+            GenericNode & node ( traverseCommand(command.commandPath()) );
+            DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&node) );
+            if ( dir ) {
+                if (autocd_ && command.tokens().empty()) {
+                    oldCwd_ = cwd_;
+                    cwd_ = dir->thisptr();
+                } else
+                    throw InvalidCommandException();
+            } else {
+                dynamic_cast<CommandNode &>(node)(output, command);
+            }
             break;
+        }
 
         case ParseCommandInfo::BuiltinCD :
-            if ( command.arguments() ) {
-                if (command.arguments().begin()->size() == 1 
-                    && command.arguments().begin()->begin()->value() == "-") {
-                    if (oldCwd_.expired()) {
+            if (skipping_)
+                break;
+            try {
+                if ( command.arguments() ) {
+                    if (command.arguments().begin()->size() == 1 
+                        && command.arguments().begin()->begin()->value() == "-") {
+                        if (oldCwd_.expired() || ! oldCwd_.lock()->active()) {
+                            oldCwd_ = cwd_;
+                            cwd_ = root_;
+                        } else
+                            swap(cwd_, oldCwd_);
+                    }
+                    else {
                         oldCwd_ = cwd_;
-                        cwd_ = root().thisptr();
-                    } else
-                        swap(cwd_, oldCwd_);
-                }
-                else {
-                    oldCwd_ = cwd_;
-                    cwd_ = traverseTo(command.arguments().begin()[0]).thisptr();
+                    cwd_ = traverseDirectory(*command.arguments().begin()).thisptr();
+                    }
                 }
             }
+            catch (IgnoreCommandException &) {
+                throw SyntaxErrorException(
+                    "'cd' cannot be skipped (don't use 'cd' in conf-files)");
+            }
             break;
             
         case ParseCommandInfo::BuiltinLS : {
-            DirectoryNode const & dir (
-                command.arguments().empty() ? cwd() : traverseTo(command.arguments().begin()[0]));
+            if (skipping_)
+                break;
+            DirectoryNode const & dir ( command.arguments()
+                                        ? traverseDirectory(*command.arguments().begin())
+                                        : cwd() );
             for (DirectoryNode::child_iterator i (dir.children().begin());
                  i != dir.children().end(); ++i) {
                 output << i->first;
@@ -93,63 +115,102 @@ prefix_ bool senf::console::Executor::operator()(ParseCommandInfo const & comman
         }
 
         case ParseCommandInfo::BuiltinPUSHD :
-            dirstack_.push_back(cwd_);
-            if ( command.arguments() )
-                cwd_ = traverseTo(command.arguments().begin()[0]).thisptr();
+            dirstack_.push_back(DirEntry(cwd_, skipping_));
+            if ( ! skipping_ && command.arguments() ) {
+                try {
+                    cwd_ = traverseDirectory(*command.arguments().begin()).thisptr();
+                }
+                catch (IgnoreCommandException &) {
+                    cwd_.reset();
+                    skipping_ = true;
+                }
+            }
             break;
             
         case ParseCommandInfo::BuiltinPOPD :
             if (! dirstack_.empty()) {
-                cwd_ = dirstack_.back();
+                cwd_ = dirstack_.back().dir;
+                skipping_ = dirstack_.back().skip;
                 dirstack_.pop_back();
             }
             break;
             
         case ParseCommandInfo::BuiltinEXIT :
+            if (skipping_)
+                break;
             throw ExitException();
+
+        case ParseCommandInfo::BuiltinHELP :
+            if (skipping_)
+                break;
+            GenericNode const & node (command.arguments() 
+                                      ? traverseNode(*command.arguments().begin())
+                                      : cwd());
+            output << prettyName(typeid(node)) << " at " << node.path() << "\n\n";
+            node.help(output);
+            output << std::flush;
+            break;
+
         }
     }
+    catch (InvalidPathException &) {
+        output << "invalid path" << std::endl;
+    }
     catch (InvalidDirectoryException &) {
         output << "invalid directory" << std::endl;
     }
     catch (InvalidCommandException &) {
         output << "invalid command" << std::endl;
     }
-    return true;
+    catch (IgnoreCommandException &) {}
 }
 
-prefix_ senf::console::DirectoryNode &
-senf::console::Executor::traverseTo (ParseCommandInfo::argument_value_type const & path)
+prefix_ senf::console::GenericNode &
+senf::console::Executor::traverseNode(ParseCommandInfo::TokensRange const & path)
 {
     try {
-        return dynamic_cast<DirectoryNode&>(
-            cwd().traverse(
-                boost::make_iterator_range(
-                    boost::make_transform_iterator(path.begin(), TraverseTokens()),
-                    boost::make_transform_iterator(path.end(), TraverseTokens()))));
+        return traverse(
+            cwd(),
+            boost::make_iterator_range(
+                boost::make_transform_iterator(path.begin(), TraverseTokens()),
+                boost::make_transform_iterator(path.end(), TraverseTokens())) );
     }
     catch (std::bad_cast &) {
-        throw InvalidDirectoryException();
+        throw InvalidPathException();
     }
     catch (UnknownNodeNameException &) {
-        throw InvalidDirectoryException();
+        throw InvalidPathException();
     }
 }
 
-prefix_ senf::console::CommandNode &
-senf::console::Executor::traverseToCommand(ParseCommandInfo::CommandPathRange const & path)
+prefix_ senf::console::GenericNode &
+senf::console::Executor::traverseCommand(ParseCommandInfo::CommandPathRange const & path)
 {
     try {
-        return dynamic_cast<CommandNode &>( cwd().traverse(path) );
+        return traverse(cwd(), path);
     }
     catch (std::bad_cast &) {
-        throw InvalidCommandException();
+        throw InvalidPathException();
     }
     catch (UnknownNodeNameException &) {
-        throw InvalidCommandException();
-    }        
+        throw InvalidPathException();
+    }
+}
+
+prefix_ senf::console::DirectoryNode &
+senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path)
+{
+    try {
+        return dynamic_cast<DirectoryNode&>( traverseNode(path) );
+    }
+    catch (std::bad_cast &) {
+        throw InvalidDirectoryException();
+    }
+    catch (InvalidPathException &) {
+        throw InvalidDirectoryException();
+    }
 }
-        
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 //#include "Executor.mpp"