Utils/Console: Replace Readline with LineEditor
g0dil [Thu, 8 Jan 2009 07:26:37 +0000 (07:26 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1045 270642c3-0616-0410-b53a-bc976706d245

12 files changed:
SConstruct
Utils/Console/LineEditor.cc [new file with mode: 0644]
Utils/Console/LineEditor.hh [new file with mode: 0644]
Utils/Console/Readline.cc [deleted file]
Utils/Console/Readline.cci [deleted file]
Utils/Console/Readline.hh [deleted file]
Utils/Console/Server.cc
Utils/Console/Server.cci
Utils/Console/Server.hh
Utils/Console/Server.ih
Utils/Termlib/telnetServer.cc
senfscons/senfutil.py

index 376a87d..dd2786a 100644 (file)
@@ -118,7 +118,7 @@ INLINE_OPTS = [ '-finline-limit=5000' ]
 env.Append(
    CPPPATH = [ '#/include' ],
    CXXFLAGS = [ '-Wall', '-Woverloaded-virtual', '-Wno-long-long' ] + INLINE_OPTS,
-   LIBS = [ 'readline', 'rt', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
+   LIBS = [ 'rt', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
             '$BOOSTFSLIB' ],
    TEST_EXTRA_LIBS = [ ],
    DOXY_XREF_TYPES = [ 'bug', 'fixme', 'todo', 'idea' ],
diff --git a/Utils/Console/LineEditor.cc b/Utils/Console/LineEditor.cc
new file mode 100644 (file)
index 0000000..ab2f548
--- /dev/null
@@ -0,0 +1,138 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief LineEditor non-inline non-template implementation */
+
+#include "LineEditor.hh"
+//#include "LineEditor.ih"
+
+// Custom includes
+#include "../Logger/SenfLog.hh"
+
+//#include "LineEditor.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::LineEditorSwitcher
+
+prefix_ senf::console::detail::LineEditorSwitcher::LineEditorSwitcher(Client & client)
+    : ClientReader(client),
+      reader_ (new LineEditorClientReader(client, *this))
+{}
+
+prefix_ void senf::console::detail::LineEditorSwitcher::editorSetupFailed()
+{
+    // We need to delete the old reader *before* creating the new one such that all old scheduler
+    // events are removed before installing the new ones.
+    reader_.reset(0);
+    reader_.reset(new DumbClientReader(client()));
+}
+
+prefix_ void senf::console::detail::LineEditorSwitcher::v_disablePrompt()
+{
+    reader_->disablePrompt();
+}
+
+prefix_ void senf::console::detail::LineEditorSwitcher::v_enablePrompt()
+{
+    reader_->enablePrompt();
+}
+
+prefix_ void senf::console::detail::LineEditorSwitcher::v_write(std::string const & data)
+{
+    reader_->write(data);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::LineEditorClientReader
+
+prefix_ senf::console::detail::LineEditorClientReader::
+LineEditorClientReader(Client & client, LineEditorSwitcher & switcher)
+    : term::BaseTelnetProtocol(client.handle()), ClientReader(client),
+      editor_ (*this, senf::membind(&LineEditorClientReader::executeLine, this)),
+      switcher_ (&switcher)
+{
+    editor_.prompt(promptString());
+    editor_.defineKey(senf::term::KeyParser::Ctrl('D'),
+                      senf::membind(&LineEditorClientReader::deleteCharOrExit, this));
+}
+
+prefix_ void senf::console::detail::LineEditorClientReader::v_setupFailed()
+{
+    // Commits suicide
+    switcher_->editorSetupFailed();
+}
+
+prefix_ void senf::console::detail::LineEditorClientReader::v_eof()
+{
+    stopClient();
+}
+
+prefix_ void senf::console::detail::LineEditorClientReader::v_disablePrompt()
+{
+    editor_.hide();
+}
+
+prefix_ void senf::console::detail::LineEditorClientReader::v_enablePrompt()
+{
+    editor_.show();
+}
+
+prefix_ void senf::console::detail::LineEditorClientReader::v_write(std::string const & data)
+{
+    BaseTelnetProtocol::write(data);
+}
+
+prefix_ void
+senf::console::detail::LineEditorClientReader::executeLine(std::string const & text)
+{
+    handleInput(text);
+    stream() << std::flush;
+    editor_.prompt(promptString());
+    editor_.show();
+}
+
+prefix_ void
+senf::console::detail::LineEditorClientReader::deleteCharOrExit(term::LineEditor & editor)
+{
+    if (editor.text().empty())
+        ClientReader::handle().facet<TCPSocketProtocol>().shutdown(TCPSocketProtocol::ShutRD);
+    else
+        term::bindings::deleteChar(editor);
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "LineEditor.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/Console/LineEditor.hh b/Utils/Console/LineEditor.hh
new file mode 100644 (file)
index 0000000..840ce5a
--- /dev/null
@@ -0,0 +1,99 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief LineEditor public header */
+
+#ifndef HH_SENF_Utils_Console_LineEditor_
+#define HH_SENF_Utils_Console_LineEditor_ 1
+
+// Custom includes
+#include <boost/scoped_ptr.hpp>
+#include "../Termlib/TelnetTerminal.hh"
+#include "../Termlib/Editor.hh"
+#include "Server.hh"
+
+//#include "LineEditor.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace console {
+namespace detail {
+
+    class LineEditorSwitcher
+        : public ClientReader
+    {
+    public:
+        explicit LineEditorSwitcher(Client & client);
+
+        void editorSetupFailed();
+
+    private:
+        virtual void v_disablePrompt();
+        virtual void v_enablePrompt();
+        virtual void v_write(std::string const & data);
+
+        boost::scoped_ptr<ClientReader> reader_;
+    };
+
+    class LineEditorClientReader
+        : public ClientReader, public term::TelnetTerminal
+    {
+    public:
+        explicit LineEditorClientReader(Client & client, LineEditorSwitcher & switcher);
+        
+    private:
+        // TelnetTerminal API implementation
+        virtual void v_setupFailed();
+        virtual void v_eof();
+
+        // ClientReader API implementation
+        virtual void v_disablePrompt();
+        virtual void v_enablePrompt();
+        virtual void v_write(std::string const & data);
+
+        // Editor callbacks
+        void executeLine(std::string const & text);
+        void deleteCharOrExit(term::LineEditor & editor);
+
+        term::LineEditor editor_;
+        LineEditorSwitcher * switcher_;
+    };
+
+}}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "LineEditor.cci"
+//#include "LineEditor.ct"
+//#include "LineEditor.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/Console/Readline.cc b/Utils/Console/Readline.cc
deleted file mode 100644 (file)
index 4b7f724..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-// $Id$
-//
-// Copyright (C) 2008 
-// Fraunhofer Institute for Open Communication Systems (FOKUS)
-// Competence Center NETwork research (NET), St. Augustin, GERMANY
-//     Stefan Bund <g0dil@berlios.de>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-/** \file
-    \brief Readline non-inline non-template implementation */
-
-#include "Readline.hh"
-//#include "Readline.ih"
-
-// Custom includes
-#include <stdio.h>
-#include <readline/readline.h>
-#include <readline/history.h>
-#include <boost/algorithm/string/trim.hpp>
-#include <boost/algorithm/string/replace.hpp>
-#include "../../Utils/membind.hh"
-
-//#include "Readline.mpp"
-#define prefix_
-///////////////////////////////cc.p////////////////////////////////////////
-
-//
-// Readline integration is a bit awkward. There are several things to it:
-//
-//  - Readline uses global variables for all state. Therefore, we can use readline only for one
-//    console.
-//  - We need to make readline to read from the socket handle instead of some input stream. We can
-//    do this by setting a custom rl_getc_function.
-//  - We need to make readline to write to the NonblockingSocketOStream. This is possible in glibc
-//    by using a 'cookie stream'.
-//  - We need to correctly handle the terminal mode settings. Currently we unconditionally
-//    initialize the remote telnet by sending a fixed telnet option string and ignoring any otpions
-//    sent back to us.
-//  - We need to make sure, readline never uses stderr -> we must disable beeping
-//  - There are places, where readline calls read_key unconditionally even when NOT prompted by the
-//    callback that another key is available. One such place is completion. (The 'show all
-//    completions (y/n)?' question). For now, we disable completion support.
-//
-
-///////////////////////////////////////////////////////////////////////////
-// senf::console::detail::ReadlineClientReader
-
-extern "C" {
-    extern int readline_echoing_p;
-    extern int _rl_bell_preference;
-
-    void _rl_erase_entire_line();
-}
-
-
-namespace {
-
-    int readline_getc_function(FILE *)
-    {
-        if (senf::console::detail::ReadlineClientReader::active())
-            return senf::console::detail::ReadlineClientReader::instance().getc();
-        else
-            return -1;
-    }
-
-    void readline_callback(char * input)
-    {
-        if (senf::console::detail::ReadlineClientReader::active()) {
-            if (input)
-                return senf::console::detail::ReadlineClientReader::instance().callback(
-                    std::string(input) );
-            else // input == 0 -> EOF (or Ctrl-D)
-                senf::console::detail::ReadlineClientReader::instance().eof();
-        }
-    }
-
-    ssize_t readline_cookie_write_function(void * cookie, char const * buffer, size_t size)
-    {
-        if (senf::console::detail::ReadlineClientReader::active() && buffer)
-            senf::console::detail::ReadlineClientReader::instance().write(
-                std::string(buffer, size));
-        return size;
-    }
-
-    void readline_prep_term(int meta)
-    {
-        readline_echoing_p = 1;
-    }
-
-    void readline_deprep_term()
-    {}
-
-    int restart_line(int count, int key)
-    {
-        rl_kill_full_line(count, key);
-        rl_crlf();
-        rl_forced_update_display();
-        return 0;
-    }
-
-}
-
-prefix_ senf::console::detail::ReadlineClientReader::ReadlineClientReader(Client & client)
-    : ClientReader(client), ch_ (-1), skipChars_ (0), 
-      readevent_ ( "senf::console::detail::ReadlineClientReader", senf::membind(&ReadlineClientReader::charEvent, this),
-                   client.handle(), scheduler::FdEvent::EV_READ, false ),
-      terminate_ (false)
-{
-    if (instance_ != 0)
-        throw DuplicateReaderException();
-    instance_ = this;
-
-    cookie_io_functions_t cookie_io = { 0, &readline_cookie_write_function, 0, 0 };
-    rl_outstream = fopencookie(0, "a", cookie_io);
-    if (rl_outstream == 0)
-        SENF_THROW_SYSTEM_EXCEPTION("");
-    if (setvbuf(rl_outstream, 0, _IONBF, BUFSIZ) < 0)
-        SENF_THROW_SYSTEM_EXCEPTION("");
-    rl_instream = rl_outstream;
-    rl_terminal_name = "vt100";
-    strncpy(nameBuffer_, client.name().c_str(), 128);
-    nameBuffer_[127] = 0;
-    rl_readline_name = nameBuffer_;
-    rl_prep_term_function = &readline_prep_term;
-    rl_deprep_term_function = &readline_deprep_term;
-    rl_getc_function = &readline_getc_function;
-    rl_bind_key('\t', &rl_insert);
-    rl_bind_key('\x03', &restart_line);
-    using_history();
-    
-    // Don't ask me, where I found this ...
-    static char options[] = { 0xFF, 0xFB, 0x01, // IAC WILL ECHO
-                              0xFF, 0xFE, 0x22, // IAC DONT LINEMODE
-                              0xFF, 0xFB, 0x03, // IAC WILL SGA
-                              0x00 };
-    handle().write(options, options+sizeof(options));
-    handle().write(std::string("(readline support enabled)\r\n"));
-
-    strncpy(promptBuffer_, promptString().c_str(), 1024);
-    promptBuffer_[1023] = 0;
-    rl_callback_handler_install(promptBuffer_, &readline_callback);
-
-    _rl_bell_preference = 0; // Set this *after* the config file has been read
-
-    readevent_.enable();
-}
-
-prefix_ senf::console::detail::ReadlineClientReader::~ReadlineClientReader()
-{
-    rl_callback_handler_remove();
-    fclose(rl_outstream);
-    rl_outstream = 0;
-    rl_instream = 0;
-    instance_ = 0;
-}
-
-prefix_ void senf::console::detail::ReadlineClientReader::callback(std::string line)
-{
-    boost::trim(line);
-    if (!line.empty())
-        add_history(line.c_str());
-    handleInput(line);
-    stream() << std::flush;
-    strncpy(promptBuffer_, promptString().c_str(), 1024);
-    promptBuffer_[1023] = 0;
-    rl_set_prompt(promptBuffer_);
-}
-
-prefix_ void senf::console::detail::ReadlineClientReader::v_disablePrompt()
-{
-    _rl_erase_entire_line();
-}
-
-prefix_ void senf::console::detail::ReadlineClientReader::v_enablePrompt()
-{
-    rl_forced_update_display();
-}
-
-prefix_ void senf::console::detail::ReadlineClientReader::v_translate(std::string & data)
-{
-    boost::replace_all(data, "\n", "\r\n");
-    boost::replace_all(data, "\r", "\r\0");
-    boost::replace_all(data, "\xff", "\xff\xff");
-}
-
-prefix_ void senf::console::detail::ReadlineClientReader::charEvent(int event)
-{
-    char ch;
-    if (event != scheduler::FdEvent::EV_READ || handle().read(&ch, &ch+1) <= &ch) {
-        stopClient();
-        return;
-    }
-    ch_ = static_cast<unsigned char>(ch);
-
-    if (skipChars_ > 0)
-        --skipChars_;
-    else if (ch_ == 0xff)
-        skipChars_ = 2;
-    else if (ch_ != 0)
-        rl_callback_read_char();
-
-    if (terminate_)
-        stopClient();
-}
-
-senf::console::detail::ReadlineClientReader * 
-    senf::console::detail::ReadlineClientReader::instance_ (0);
-
-///////////////////////////////////////////////////////////////////////////
-// senf::console::detail::SafeReadlineClientReader
-
-prefix_ void senf::console::detail::SafeReadlineClientReader::v_disablePrompt()
-{
-    reader_->disablePrompt();
-}
-
-prefix_ void senf::console::detail::SafeReadlineClientReader::v_enablePrompt()
-{
-    reader_->enablePrompt();
-}
-
-prefix_ void senf::console::detail::SafeReadlineClientReader::v_translate(std::string & data)
-{
-    reader_->translate(data);
-}
-
-///////////////////////////////cc.e////////////////////////////////////////
-#undef prefix_
-//#include "Readline.mpp"
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// comment-column: 40
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// End:
diff --git a/Utils/Console/Readline.cci b/Utils/Console/Readline.cci
deleted file mode 100644 (file)
index 200da7c..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-// $Id$
-//
-// Copyright (C) 2008 
-// Fraunhofer Institute for Open Communication Systems (FOKUS)
-// Competence Center NETwork research (NET), St. Augustin, GERMANY
-//     Stefan Bund <g0dil@berlios.de>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-/** \file
-    \brief Readline inline non-template implementation */
-
-//#include "Readline.ih"
-
-// Custom includes
-
-#define prefix_ inline
-///////////////////////////////cci.p///////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// senf::console::detail::ReadlineClientReader
-
-prefix_ bool senf::console::detail::ReadlineClientReader::active()
-{
-    return instance_ != 0;
-}
-
-prefix_ senf::console::detail::ReadlineClientReader &
-senf::console::detail::ReadlineClientReader::instance()
-{
-    return *instance_;
-}
-
-prefix_ int senf::console::detail::ReadlineClientReader::getc()
-{
-    char ch (ch_);
-    ch_ = -1;
-    return ch;
-}
-
-prefix_ void senf::console::detail::ReadlineClientReader::write(std::string text)
-{
-    try {
-        translate(text);
-        handle().write(text);
-    } catch (SystemException &) {
-        ;
-    }
-}
-
-prefix_ void senf::console::detail::ReadlineClientReader::terminate()
-{
-    terminate_ = true;
-}
-
-prefix_ void senf::console::detail::ReadlineClientReader::eof()
-{
-    stream() << '\n' << std::flush;
-    stopClient();
-}
-
-///////////////////////////////////////////////////////////////////////////
-// senf::console::detail::SafeReadlineClientReader
-
-prefix_
-senf::console::detail::SafeReadlineClientReader::SafeReadlineClientReader(Client & client)
-    : ClientReader (client),
-      reader_ ( ReadlineClientReader::active() 
-                ? static_cast<ClientReader*>(new DumbClientReader(client))
-                : static_cast<ClientReader*>(new ReadlineClientReader(client)) )
-{}
-
-///////////////////////////////cci.e///////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// comment-column: 40
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// End:
diff --git a/Utils/Console/Readline.hh b/Utils/Console/Readline.hh
deleted file mode 100644 (file)
index 7c26de6..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-// $Id$
-//
-// Copyright (C) 2008 
-// Fraunhofer Institute for Open Communication Systems (FOKUS)
-// Competence Center NETwork research (NET), St. Augustin, GERMANY
-//     Stefan Bund <g0dil@berlios.de>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-/** \file
-    \brief Readline public header */
-
-#ifndef HH_SENF_Scheduler_Console_Readline_
-#define HH_SENF_Scheduler_Console_Readline_ 1
-
-// Custom includes
-#include <boost/scoped_ptr.hpp>
-#include "Server.hh"
-#include "../../Utils/Exception.hh"
-#include "../../Scheduler/Scheduler.hh"
-
-//#include "Readline.mpp"
-///////////////////////////////hh.p////////////////////////////////////////
-
-namespace senf {
-namespace console {
-namespace detail {
-
-#ifndef DOXYGEN
-
-    /** \brief Internal: GNU readline based ClientReader implementation
-        
-        This implementation of the ClientReader interface uses GNU readline library to provide a
-        rich editing environment for console sessions. Since an application can only use readline
-        once, only one ReadlineReader can be allocated at any time.
-     */
-    class ReadlineClientReader
-        : public ClientReader
-    {
-    public:
-        ReadlineClientReader(Client & client);
-        ~ReadlineClientReader();
-
-        static bool active();
-        static ReadlineClientReader & instance();
-
-        struct DuplicateReaderException : public Exception
-        { DuplicateReaderException() : Exception("duplicate readline instantiation") {} };
-
-        int getc();
-        void callback(std::string line);
-        void write(std::string text);
-        void terminate();
-        void eof();
-        
-    private:
-        virtual void v_disablePrompt();
-        virtual void v_enablePrompt();
-        virtual void v_translate(std::string & data);
-
-        void charEvent(int event);
-
-        static ReadlineClientReader * instance_;
-        int ch_;
-        unsigned skipChars_;
-        char nameBuffer_[256];
-        char promptBuffer_[1024];
-        scheduler::FdEvent readevent_;
-        bool terminate_;
-
-        char * savedLineBuffer_;
-        int savedPoint_;
-        int savedEnd_;
-        int savedMark_;
-    };
-
-    /** \brief Internal: Safe GNU readline based ClientReader implementation
-        
-        This implementation of the ClientReader interface forwards all functionality to either
-        ReadlineClientReader or DumbClientReader. A RadlineClientReader is used, if none is active,
-        otherwise a DumbClientReader is allocated. Using this ClientReader implementation, the first
-        console client will have readline functionality enabled, all further will have it disabled.
-     */
-    class SafeReadlineClientReader
-        : public ClientReader
-    {
-    public:
-        SafeReadlineClientReader(Client & client);
-
-    private:
-        virtual void v_disablePrompt();
-        virtual void v_enablePrompt();
-        virtual void v_translate(std::string & data);
-
-        boost::scoped_ptr<ClientReader> reader_;
-    };
-
-#endif
-
-}}}
-
-///////////////////////////////hh.e////////////////////////////////////////
-#include "Readline.cci"
-//#include "Readline.ct"
-//#include "Readline.cti"
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// comment-column: 40
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// End:
index 04b54be..d326133 100644 (file)
@@ -35,7 +35,7 @@
 #include "../../Utils/senfassert.hh"
 #include "../../Utils/membind.hh"
 #include "../../Utils/Logger/SenfLog.hh"
-#include "Readline.hh"
+#include "LineEditor.hh"
 
 //#include "Server.mpp"
 #define prefix_
@@ -50,8 +50,7 @@ prefix_ std::streamsize senf::console::detail::NonblockingSocketSink::write(cons
     try {
         if (client_.handle().writeable()) {
             std::string data (s, n);
-            client_.translate(data);
-            client_.handle().write( data );
+            client_.write(data);
         }
     }
     catch (SystemException & ex) {
@@ -149,6 +148,7 @@ senf::console::detail::DumbClientReader::clientData(senf::ReadHelper<ClientHandl
 prefix_ void senf::console::detail::DumbClientReader::showPrompt()
 {
     std::string prompt (promptString());
+    prompt += " ";
 
     stream() << std::flush;
     handle().write(prompt);
@@ -170,8 +170,10 @@ prefix_ void senf::console::detail::DumbClientReader::v_enablePrompt()
         showPrompt();
 }
 
-prefix_ void senf::console::detail::DumbClientReader::v_translate(std::string & data)
-{}
+prefix_ void senf::console::detail::DumbClientReader::v_write(std::string const & data)
+{
+    handle().write(data);
+}
 
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::detail::NoninteractiveClientReader
@@ -190,8 +192,10 @@ prefix_ void senf::console::detail::NoninteractiveClientReader::v_disablePrompt(
 prefix_ void senf::console::detail::NoninteractiveClientReader::v_enablePrompt()
 {}
 
-prefix_ void senf::console::detail::NoninteractiveClientReader::v_translate(std::string & data)
-{}
+prefix_ void senf::console::detail::NoninteractiveClientReader::v_write(std::string const & data)
+{
+    handle().write(data);
+}
 
 prefix_ void
 senf::console::detail::NoninteractiveClientReader::newData(int event)
@@ -247,7 +251,7 @@ prefix_ void senf::console::Client::setInteractive()
     readevent_.disable();
     timer_.disable();
     mode_ = Server::Interactive;
-    reader_.reset(new detail::SafeReadlineClientReader (*this));
+    reader_.reset(new detail::LineEditorSwitcher (*this));
     executor_.autocd(true).autocomplete(true);
 }
 
@@ -259,11 +263,6 @@ prefix_ void senf::console::Client::setNoninteractive()
     reader_.reset(new detail::NoninteractiveClientReader(*this));
 }
 
-prefix_ void senf::console::Client::translate(std::string & data)
-{
-    reader_->translate(data);
-}
-
 prefix_ std::string::size_type senf::console::Client::handleInput(std::string data,
                                                                   bool incremental)
 {
index 81aaf6d..9f3f4e6 100644 (file)
@@ -130,7 +130,7 @@ prefix_ std::string const & senf::console::Client::name()
 prefix_ std::string senf::console::Client::promptString()
     const
 {
-    return name_ + ":" + executor_.cwdPath() + "$ ";
+    return name_ + ":" + executor_.cwdPath() + "$";
 }
 
 prefix_ senf::console::DirectoryNode & senf::console::Client::root()
@@ -145,6 +145,12 @@ prefix_ senf::console::Server::Mode senf::console::Client::mode()
     return mode_;
 }
 
+prefix_ void senf::console::Client::write(std::string const & data)
+    const
+{
+    reader_->write(data);
+}
+
 prefix_ senf::console::Client & senf::console::Client::get(std::ostream & os)
 {
     return dynamic_cast<detail::NonblockingSocketOStream&>(os)->client();
@@ -213,9 +219,9 @@ prefix_ void senf::console::detail::ClientReader::enablePrompt()
     v_enablePrompt();
 }
 
-prefix_ void senf::console::detail::ClientReader::translate(std::string & data)
+prefix_ void senf::console::detail::ClientReader::write(std::string const & data)
 {
-    v_translate(data);
+    v_write(data);
 }
 
 prefix_ senf::console::detail::ClientReader::ClientReader(Client & client)
index ef38917..4fac812 100644 (file)
@@ -174,6 +174,7 @@ namespace console {
         std::string promptString() const;
         DirectoryNode & root() const;
         Server::Mode mode() const;
+        void write(std::string const & data) const;
 
         static Client & get(std::ostream & os);
 
@@ -185,7 +186,6 @@ namespace console {
         void setInteractive();
         void setNoninteractive();
         
-        void translate(std::string & data);
         size_t handleInput(std::string input, bool incremental = false);
         virtual void v_write(senf::log::time_type timestamp, std::string const & stream, 
                              std::string const & area, unsigned level, 
index a886bb6..d7b73e7 100644 (file)
@@ -118,7 +118,7 @@ namespace detail {
 
         void disablePrompt();
         void enablePrompt();
-        void translate(std::string & data);
+        void write(std::string const & data);
 
     protected:
         ClientReader(Client & client);
@@ -126,7 +126,7 @@ namespace detail {
     private:
         virtual void v_disablePrompt() = 0;
         virtual void v_enablePrompt() = 0;
-        virtual void v_translate(std::string & data) = 0;
+        virtual void v_write(std::string const & data) = 0;
 
         Client & client_;
     };
@@ -145,7 +145,7 @@ namespace detail {
     private:
         virtual void v_disablePrompt();
         virtual void v_enablePrompt();
-        virtual void v_translate(std::string & data);
+        virtual void v_write(std::string const & data);
 
         void clientData(senf::ReadHelper<ClientHandle>::ptr helper);
         void showPrompt();
@@ -169,7 +169,7 @@ namespace detail {
     private:
         virtual void v_disablePrompt();
         virtual void v_enablePrompt();
-        virtual void v_translate(std::string & data);
+        virtual void v_write(std::string const & data);
 
         void newData(int event);
 
index 3c5c9fd..c9aeb7f 100644 (file)
@@ -80,7 +80,7 @@ namespace {
                 delete this;
             }
 
-        virtual void executeLine(std::string const & text)
+        void executeLine(std::string const & text)
             {
                 SENF_LOG(("Execute line: " << text));
                 editor_.show();
index d9f67ed..9560dd5 100644 (file)
@@ -8,7 +8,7 @@ from SCons.Script import *
 # c) check for a local SENF, set options accordingly and update that SENF if needed
 
 def SetupForSENF(env):
-    env.Append( LIBS           = [ 'senf', 'readline', 'rt', '$BOOSTREGEXLIB',
+    env.Append( LIBS           = [ 'senf', 'rt', '$BOOSTREGEXLIB',
                                    '$BOOSTIOSTREAMSLIB', '$BOOSTSIGNALSLIB',
                                    '$BOOSTFSLIB' ],
                 BOOSTREGEXLIB  = 'boost_regex',