Utils/Termlib: Documentation
g0dil [Fri, 9 Jan 2009 13:54:35 +0000 (13:54 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1053 270642c3-0616-0410-b53a-bc976706d245

Utils/Termlib/AbstractTerminal.hh
Utils/Termlib/Doxyfile
Utils/Termlib/Editor.hh
Utils/Termlib/Mainpage.dox [new file with mode: 0644]
Utils/Termlib/Telnet.cc
Utils/Termlib/Telnet.hh
Utils/Termlib/TelnetTerminal.hh
Utils/Termlib/Terminfo.hh

index f38a4b5..22b3e0c 100644 (file)
 namespace senf {
 namespace term {
 
+    /** \brief Abstract terminal interface
+
+        This abstract interface base class provides an abstract interface to a terminal. There are
+        two parts to this interface:
+        
+        \li The interface which allows the terminal user to get information about the terminal
+        \li The interface which allows the terminal to send messages to the terminal user
+
+        The first part is implemented by providing abstract virtual members in AbstractTerminal. To
+        allow the terminal to send messages to the terminal user, the terminal user implements the
+        AbstractTerminal::Callbacks interface. The terminal user must register himself with the
+        AbstractTerminal by calling setCallbacks(). Afterwards, the AbstractTerminal implementation
+        will send calls to the terminal user via the AbstractTerminal::Callbacks API.
+     */
     struct AbstractTerminal
     {
+        /** \brief AbstractTerminal callbacks
+
+            \see AbastractTerminal
+         */
         struct Callbacks {
             virtual ~Callbacks() {}
-            virtual bool cb_init() = 0;
-            virtual void cb_charReceived(char ch) = 0;
-            virtual void cb_windowSizeChanged() = 0;
+            virtual bool cb_init() = 0; ///< Called after terminal initialization is complete
+                                        /**< This member may return \c false. In this case, the
+                                             terminal setup is considered to have failed. */
+            virtual void cb_charReceived(char ch) = 0; ///< Called whenever a char is received
+            virtual void cb_windowSizeChanged() = 0; ///< Called when the terminal window is changed
         };
 
         virtual ~AbstractTerminal() {}
 
-        virtual void setCallbacks(Callbacks & cb) = 0;
+        virtual void setCallbacks(Callbacks & cb) = 0; /// Register terminal callbacks
 
-        virtual std::string terminalType() = 0;
-        virtual unsigned width() = 0;
-        virtual unsigned height() = 0;
+        virtual std::string terminalType() = 0; ///< Get the terminal type
+        virtual unsigned width() = 0;   ///< Get current terminal window width
+        virtual unsigned height() = 0;  ///< Get current terminal window height
 
-        virtual void write(char ch) = 0;
+        virtual void write(char ch) = 0; ///< Write character to terminal
     };
 
 }}
index b7b820c..77c744b 100644 (file)
@@ -4,6 +4,7 @@ PROJECT_NAME = libTermlib
 GENERATE_TAGFILE = doc/Console.tag
 EXAMPLE_PATH = .
 EXCLUDE = telnetServer.cc
+ALPHABETICAL_INDEX = NO
 
 TAGFILES = \
     "$(TOPDIR)/Socket/doc/Socket.tag" \
index e173a29..8646d4a 100644 (file)
 namespace senf {
 namespace term {
 
+    /** \brief Provide editor support terminal functionality
+
+        This base class utilizes an arbitrary AbstractTerminal and provides terminfo based
+        terminal navigation and key parsing.
+
+        All navigation is relative to the current line. The display area can then be extended
+        downwards up to a maximum of height() lines. Resetting this extended display area will
+        return to a one line area containing only the top line.
+
+        All navigation is restricted to a width() x height() area. The last column may not be
+        written to since auto-margin terminals will move the cursor to the next line when writing to
+        that column.
+
+        This base class calls v_keyReceived() which must be defined in a derived class whenever a
+        key is fully parsed.
+     */
     class BaseEditor
         : public AbstractTerminal::Callbacks
     {
@@ -69,12 +85,16 @@ namespace term {
         unsigned height();              ///< Return current screen height
 
     protected:
-        virtual bool cb_init();
+        virtual bool cb_init();         ///< Called when terminal is initialized
         virtual void cb_windowSizeChanged();
+                                        ///< Called whenever the terminal window size changes
 
+#ifndef DOXYGEN
     private:
-        virtual void v_keyReceived(keycode_t key) = 0;
+#endif
+        virtual void v_keyReceived(keycode_t key) = 0; ///< Called whenever a key is received
 
+    private:
         virtual void cb_charReceived(char c);
 
         void keySequenceTimeout();
@@ -93,7 +113,88 @@ namespace term {
         unsigned displayHeight_;
         unsigned line_;
     };
+    
+    /** \brief Single line interactive text editor
+
+        LineEditor implements a single-line input widget on an arbitrary AbstractTerminal.
+
+        \li It supports all the customary editing functions
+        \li It is possible to arbitrarily assign functions to keys via a key map
+        \li LineEditor has builtin TAB completion support
+        \li The LineEditor has a built-in history
+        \li The LineEditor supports an arbitrary auxiliary display area below the input line
+        \li The LineEditor has hide() / show() support to allow editing to be temporarily
+            interrupted.
+        
+        The LineEditor will query the user for an input line. When the user accepts a line,
+        LineEditor will call a user callback function. After the callback has been called, the
+        editor is disabled. To accept a new input line, call show().
+
+        \section editor_keymap The editor key map
+
+        Keys are defined in the keymap using defineKey(). The default bindings are:
+
+        <table class="senf">
+        <tr><td>\c Return</td>    <td>bindings::accept</td></tr>
+        <tr><td>\c Right</td>     <td>bindings::forwardChar</td></tr>
+        <tr><td>\c Left</td>      <td>bindings::backwardChar</td></tr>
+        <tr><td>\c Up</td>        <td>bindings::prevHistory</td></tr>
+        <tr><td>\c Down</td>      <td>bindings::nextHistory</td></tr>
+        <tr><td>\c Backspace</td> <td>bindings::backwardDeleteChar</td></tr>
+        <tr><td>\c Delete</td>    <td>bindings::deleteChar</td></tr>
+        <tr><td>\c Home</td>      <td>bindings::beginningOfLine</td></tr>
+        <tr><td>\c End</td>       <td>bindings::endOfLine</td></tr>
+        <tr><td>\c Ctrl-K</td>    <td>bindings::deleteToEndOfLine</td></tr>
+        <tr><td>\c Ctrl-A</td>    <td>bindings::beginningOfLine</td></tr>
+        <tr><td>\c Ctrl-E</td>    <td>bindings::endOfLine</td></tr>
+        <tr><td>\c Ctrl-D</td>    <td>bindings::deleteChar</td></tr>
+        <tr><td>\c Ctrl-C</td>    <td>bindings::restartEdit</td></tr>
+        <tr><td>\c Ctrl-L</td>    <td>bindings::clearScreen</td></tr>
+        </table>
+
+        See the senf::term::bindings namespace for a list of all default provided key binding
+        functions.
+        
+
+        \section editor_complete Completion suppoprt
+
+        Completion support is provided by senf::term::bindings::complete(). To use the completer,
+        you need to implement a completion function and pass it as second argument to
+        bindings::complete():
+
+        \code
+        void myCompleter(senf::term::LineEditor & editor, unsigned b, unsigned e, 
+                         std::vector<std::string> & completions)
+        {
+            // Get text to complete
+            std::string text (editor.text().substr(b, e-b));
+
+            // Return possible completions in 'completions' array
+            completions.push_back( ... );
+        }
+
+        senf::term::LineEditor editor (...);
+        editor.defineKey(senf::term::KeyParser::TAB, 
+                         boost::bind(&senf::term::bindings::complete, _1, &myCompleter));
+        \endcode
+
+        When \c myCompleter is a class member, use senf::membind() and pass this instead of \c
+        &myCompleter to \c boost::bind() and thus to senf::term::bindings::complete.
+        
+
+        \section editor_auxarea The aux display area
+
+        The auxiliary display area is accessed using auxDisplay() and clearAuxDisplay(). The aux
+        display area is \e cleared \e before each new key is processed. Therefore it is only
+        temporary. The aux display area however will survive hide() / show().
+
 
+        \section editor_hideshow Temporarily disabling the editor
+
+        Calling hide() will temporarily disable the editor. All editor display will be
+        removed. Calling show() will redisplay the editor in it's current state including the aux
+        display area.
+     */
     class LineEditor
         : public BaseEditor
     {
@@ -101,56 +202,95 @@ namespace term {
         ///////////////////////////////////////////////////////////////////////////
         // Types
 
-        typedef boost::function<void (LineEditor&)> KeyBinding;
+        typedef boost::function<void (LineEditor&)> KeyBinding; ///< Type of a key binding function
         typedef boost::function<void (std::string const &)> AcceptCallback;
+                                        ///< Callback function type
 
         static unsigned const MAX_HISTORY_SIZE = 1024u;
 
         ///////////////////////////////////////////////////////////////////////////
 
         LineEditor(AbstractTerminal & terminal, AcceptCallback cb);
+                                        ///< Create a LineEditor
+                                        /**< \parm[in] terminal abstract terminal interface
+                                             \parm[in] cb callback to call for complete input
+                                             line */
         
         ///////////////////////////////////////////////////////////////////////////
 
-        void prompt(std::string const & text);
+        void prompt(std::string const & text); ///< Set prompt string
         void set(std::string const & text, unsigned pos = 0u);
+                                        ///< Set edit buffer contents
+                                        /**< The edit buffer contents will be replaced by \a
+                                             text. The cursor will be placed at position \a pos
+                                             within this text. */
 
-        // Overall edit control
-        void show();
-        void hide();
-        void accept();
-        void clear();
-        void redisplay();
-        void forceRedisplay();
-        
-        // Cursor and display movement
-        void gotoChar(unsigned n);
-        void scrollTo(unsigned n);
+        ///\name Overall edit control
+        ///\{
+
+        void show();                    ///< Enable editor widget
+        void hide();                    ///< Disable editor widget
+        void accept();                  ///< Accept current user input and call the accept callback
+        void clear();                   ///< Clear editor buffer
+        void redisplay();               ///< Mark the editor buffer for redisplay
+        void forceRedisplay();          ///< Redisplay the editor buffer \e now
+
+        ///\}
+
+        ///\name Cursor and display movement
+        ///\{
+
+        void gotoChar(unsigned n);      ///< Move cursor to position \a n
+        void scrollTo(unsigned n);      ///< Move positon \n to beginning of display line
+
+        ///\}
+
+        ///\name Text manipulation
+        ///\{
+
+        void deleteChar(unsigned n=1);  ///< Delete \a n characters at point
+        void insert(char ch);           ///< Insert \a ch at point
+        void insert(std::string const & text); ///< Insert \a text at point
 
-        // Text manipulation
-        void deleteChar(unsigned n=1);
-        void insert(char ch);
-        void insert(std::string const & text);
+        ///\}
 
-        // History
-        void pushHistory(std::string const & text);
-        void prevHistory();
-        void nextHistory();
+        ///\name History
+        ///\{
+
+        void pushHistory(std::string const & text); ///< Add string \a text to history
+        void prevHistory();             ///< Switch to previous history entry
+        void nextHistory();             ///< Switch to next history entry
+
+        ///\}
+
+        ///\name Aux Display
+        ///\{
 
-        // Aux Display
         void auxDisplay(int line, std::string const & text);
-        unsigned maxAuxDisplayHeight();
-        void clearAuxDisplay();
+                                        ///< Display \a text on aux display line \a lilne
+        unsigned maxAuxDisplayHeight(); ///< Get maximum height of the aux display area
+        void clearAuxDisplay();         ///< Clear the aux display area
+
+        ///\}
+
+        ///\name Get information
+        ///\{
 
-        // Get information
-        std::string const & text();
-        unsigned point();
-        unsigned displayPos();
-        keycode_t lastKey();
+        std::string const & text();     ///< Get current editor buffer contents
+        unsigned point();               ///< Get current cursor position
+        unsigned displayPos();          ///< Get current display position
+        keycode_t lastKey();            ///< Get last key code received
+
+        ///\}
+
+        ///\name Key bindings
+        ///\{
 
-        // Key bindings
         void defineKey(keycode_t key, KeyBinding binding);
-        void unsetKey(keycode_t key);
+                                        ///< Bind key \a key to \a binding
+        void unsetKey(keycode_t key);   ///< Remove all bindings for \a key
+
+        ///\}
         
     private:
         virtual bool cb_init();
@@ -177,24 +317,33 @@ namespace term {
         AuxDisplay auxDisplay_;
     };
 
+/** \brief LineEditor key bindings
+ */
 namespace bindings {
 
-    void selfInsertCommand   (LineEditor & editor);
-    void forwardChar         (LineEditor & editor);
-    void backwardChar        (LineEditor & editor);
-    void accept              (LineEditor & editor);
-    void backwardDeleteChar  (LineEditor & editor);
-    void deleteChar          (LineEditor & editor);
-    void beginningOfLine     (LineEditor & editor);
-    void endOfLine           (LineEditor & editor);
-    void deleteToEndOfLine   (LineEditor & editor);
-    void restartEdit         (LineEditor & editor);
-    void prevHistory         (LineEditor & editor);
-    void nextHistory         (LineEditor & editor);
-    void clearScreen         (LineEditor & editor);
+    void selfInsertCommand   (LineEditor & editor); ///< Insert key as literal character
+    void forwardChar         (LineEditor & editor); ///< Move one char forward
+    void backwardChar        (LineEditor & editor); ///< Move one char backwards
+    void accept              (LineEditor & editor); ///< Accept input line
+    void backwardDeleteChar  (LineEditor & editor); ///< Delete char before cursor
+    void deleteChar          (LineEditor & editor); ///< Delete char at cursor
+    void beginningOfLine     (LineEditor & editor); ///< Move to beginning of line
+    void endOfLine           (LineEditor & editor); ///< Move to end of line
+    void deleteToEndOfLine   (LineEditor & editor); ///< Delete from cursor to end of line
+    void restartEdit         (LineEditor & editor); ///< Clear edit buffer and restart edit
+    void prevHistory         (LineEditor & editor); ///< Move to previous history entry
+    void nextHistory         (LineEditor & editor); ///< Move to next history entry
+    void clearScreen         (LineEditor & editor); ///< Clear screen and redisplay editor
 
     typedef boost::function<void (LineEditor &, unsigned b, unsigned e, std::vector<std::string> &)> Completer;
     void complete            (LineEditor & editor, Completer completer);
+                                        ///< Complete text at cursor
+                                        /**< This function calls \a completer to find the list of
+                                             possible completions for the text between \a b and \a e
+                                             (as passed to the completer). The completer must add
+                                             all possible completions to the completions vector. 
+
+                                             \see \ref editor_complete */
 
 }
 
diff --git a/Utils/Termlib/Mainpage.dox b/Utils/Termlib/Mainpage.dox
new file mode 100644 (file)
index 0000000..8ca4408
--- /dev/null
@@ -0,0 +1,58 @@
+// $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.
+
+/** \mainpage Terminal utility functions
+
+    The Termlib module provides several facilities to help working with terminal I/O
+
+    \autotoc
+
+    \section termlib_sect_telnet Telnet protocol implementation
+    \seechapter \ref telnet_group
+
+    This is a partial implementation of the telnet protokoll. It provides enough functionality to
+    provide terminal access.
+
+    \section termlib_sect_terminfo Terminfo database access
+    \seechapter \ref terminfo_group
+
+    The senf::term::Terminfo class provides access to the termios database.
+
+    \section termlib_sect_editor Simple line-oriented text editor
+    \seechapter senf::term::LineEditor
+
+    Using the termios functionality, this class implements simple line editing
+
+ */
+
+\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"
+// mode: flyspell
+// mode: auto-fill
+// End:
index d962808..23e6984 100644 (file)
@@ -55,7 +55,9 @@ prefix_ senf::term::BaseTelnetProtocol::BaseTelnetProtocol()
       pendingRequests_ (0u),
       requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
       timeout_ ("senf::term::BaseTelnetProtocol::timeout", 0)
-{}
+{
+    SENF_ASSERT( false );
+}
 
 prefix_ void senf::term::BaseTelnetProtocol::write(std::string const & s)
 {
index 4cc6af4..e127a95 100644 (file)
 namespace senf {
 namespace term {
 
-    /** \brief  Telnet server
+    /** \defgroup telnet_group Telnet protocol
 
-        \see 
-            <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol \n
-            <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
+        The telnet protocol implementation is based on the relevant RFCs:
+
+        \li <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol
+        \li <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
+
+        BaseTelnetProtocol provides the basic protocol implementation with generic telnet option
+        support. Several other classes provide additional support for further telnet options:
+
+        \li telnethandler::TerminalType provides support for the TERMINAL_TYPE option
+        \li telnethandler::NAWS provides support for the NAWS (Negotiation About Window Size) option
+
+        There are some symbolic constants for telnet option in the senf::term::telnetopt namespace.
+     */
+
+    /** \brief Telnet protocol implementation
+
+        This class implements the basic telnet protocol. It provides option parsing and negotiation
+        and implements the necessary character quoting.
+
+        This class is a base class. Several virtual function hooks are provided which will be called
+        by the protocol implementation.
+
+        The telnet protocol implementation is symmetric: At this level, there is no difference
+        between a telnet client and a telnet server.
+
+        This telnet protocol base class integrates with the SENF Scheduler, it relies on the
+        scheduler main loop to be active.
+
+        \section telnethandlers Telnet option handlers
+
+        To support complex telnet option which require subnegotiation, TelnetHandler's are
+        provided. A telnet handler is a class derived from TelnetHandler and then inherited into the
+        target telnet implementation class:
+
+        \code
+        class MyTelnet
+            : public senf::term::telnethandler::TerminalType,
+              public senf::term::telnethandler::NAWS
+        {
+            MyTelnet(Handle handle) : BaseTelnetProtocol(handle) {}
+
+            // ...
+        };
+        \endcode
+
+        It is very important, the BaseTelnetProtocol is \e always inherited by \c public \c virtual
+        inheritance. This allows the BaseTelnetProtocol constructor to be called by the most derived
+        class directly as above.
+
+        Each terminal handler may provide an additional API and/or additional virtual function
+        callbacks.
+
+        To implement a new terminal handler, derive from TelnetHandler and register the
+        handler. BaseTelnetProtocol will automatically request the corresponding option to be
+        enabled and will call the handlers \c v_init() member as soon as the peer as asserted the
+        option.
+
+        Whenever a subnegotiation for the registered handler is received, the handlers
+        \c v_handleOptionParameters() member is called.
+
+        \code
+        class MyTelnetHandler 
+            : public senf::term::BaseTelnetProtocol::TelnetHandler
+        {
+        public:
+            // This constant is MANDATORY and gives the option code which this handler services
+            static option_type const OPTION_CODE = MY_OPTION_CODE;
+
+            void frobble() { // ... }
+
+        protected:
+            MyTelnetHandler() { registerHandler(this); }
+        
+        private:
+            virtual void v_init()
+            {
+                sendOptionParameters(OPTION_CODE, "my special subnegotiation");
+                incrementRequestCounter();
+            }
+        
+            virtual void v_handleOptionParameters(std::string const & data)
+            {
+                if (data == "another special subnegotiation")
+                    decrementRequestCounter();
+            }
+        };
+        \endcode
 
         \todo SYNCH handling
+
+        \ingroup telnet_group
      */
     class BaseTelnetProtocol
     {
@@ -56,68 +142,101 @@ namespace term {
             ConnectedCommunicationPolicy, 
             StreamFramingPolicy, 
             ReadablePolicy,
-            WriteablePolicy>::policy> Handle;
+            WriteablePolicy>::policy> Handle; ///< Type of socket handle required
 
-        typedef unsigned char option_type;
+        typedef unsigned char option_type; ///< Type of telnet option numbers
 
         struct TelnetHandler;
 
-        void write(std::string const & s);
-        void write(char c);
-
-        Handle handle();
-
-        void sendNOP();
-        void sendBRK();
-        void sendIP();
-        void sendAO();
-        void sendAYT();
-        void sendEC();
-        void sendEL();
-        void sendGA();
+        void write(std::string const & s); ///< Send string to peer
+                                        /**< The string will be correctly quoted and newline chars
+                                             will be sent as CR/LF pairs. */
+        void write(char c);             ///< Send single character to peer
+                                        /**< The character will be correctly quoted and newline
+                                             chars will be sent as CR/LF pairs. */
+
+        Handle handle();                ///< Get socket handle
+
+        void sendNOP();                 ///< Send NOP to peer
+        void sendBRK();                 ///< Send BReaK to peer
+        void sendIP();                  ///< Send InterruptProcess to peer
+        void sendAO();                  ///< Send AbortOutput to peer
+        void sendAYT();                 ///< Send AreYouThere to peer
+        void sendEC();                  ///< Send EraseCharacter to peer
+        void sendEL();                  ///< Send EraseLine to peer
+        void sendGA();                  ///< Send GoAhead to peer
         
         void sendOptionParameters(option_type option, std::string const & data);
+                                        ///< Send extended option parameter to peer
+                                        /**< This will send \a data as extended option parameter of
+                                             option \a option to peer via a subnegotiation. */
 
         void requestLocalOption(option_type option, bool enabled = true);
+                                        ///< Request option to be enabled here
+                                        /**< This will send a WILL \a option request to the peer */
         void acceptLocalOption(option_type option, bool enabled = true);
+                                        ///< Accept a request for an option to be enabled here
+                                        /**< If the peer sends a DO \a option request, the request
+                                             will be granted */
 
         void requestPeerOption(option_type option, bool enabled = true);
+                                        ///< Request peer to enable an option
+                                        /**< This will send a DO \a option request to the peer */
         void acceptPeerOption(option_type option, bool enabled = true);
+                                        ///< Accept a request by the peer to enable an option
+                                        /**< If the peer sends a WILL \a option request, the request
+                                             will be ganted */
 
-        bool localOption(option_type option);
-        bool peerOption(option_type option);
+        bool localOption(option_type option); ///< \c true, if \a option locally enabled
+        bool peerOption(option_type option); ///< \c true, if \a option enabled in peer
         
     protected:
-        explicit BaseTelnetProtocol(Handle handle);
-        BaseTelnetProtocol();
+        explicit BaseTelnetProtocol(Handle handle); ///< Construct telnet protocol handler
+        BaseTelnetProtocol();           ///< Provided for TelnetHandler mixins only
+
         virtual ~BaseTelnetProtocol();
 
         template <class Handler>
         void registerHandler(Handler * h, bool request=true);
+                                        ///< Register a TelnetHandler
 
-        void incrementRequestCounter();
-        void decrementRequestCounter();
-        bool requestsPending();
+        void incrementRequestCounter(); ///< Increment request counter
+                                        /**< This member may be called by a telnet handler to wait
+                                             for additional negotiations. It must be paired with a
+                                             corresponding decrementRequestCounter() call when that
+                                             negotiation is received. */
+        void decrementRequestCounter(); ///< Decrement request counter
+                                        /**< \see inrementRequestCounter() */
+        bool requestsPending();         ///< \c true, if there are pending requests
 
 #ifndef DOXYGEN
     private:
 #endif
-        virtual void v_setupComplete() = 0;
-        virtual void v_charReceived(char c) = 0;
-        virtual void v_eof() = 0;
-
-        virtual void v_handleNOP();
-        virtual void v_handleBRK();
-        virtual void v_handleIP();
-        virtual void v_handleAO();
-        virtual void v_handleAYT();
-        virtual void v_handleEC();
-        virtual void v_handleEL();
-        virtual void v_handleGA();
+        virtual void v_setupComplete() = 0; ///< Called, when no further requests are pending
+                                        /**< This callback will be called, when no further
+                                             negotiations are to be expected. The default
+                                             negotiation timeout is 500ms. If no reply is received
+                                             in this time, the request is abandoned and
+                                             v_setupComplete() is called.
+
+                                             mixin TelnetHandler's may additionally increment the
+                                             request counter to wait for specific
+                                             subnegotiations. v_setupComplete() will be called, when
+                                             all these negotiations are complete or have timed
+                                             out. */
+        virtual void v_charReceived(char c) = 0; ///< Called whenever a data character is received
+        virtual void v_eof() = 0;       ///< Called on input EOF
+
+        virtual void v_handleNOP();     ///< Called, when the peer sends a NOP
+        virtual void v_handleBRK();     ///< Called, when the peer sends a BReaK
+        virtual void v_handleIP();      ///< Called, when the peer sends an InterruptProcess
+        virtual void v_handleAO();      ///< Called, when the peer sends an AbortOutput
+        virtual void v_handleAYT();     ///< Called, when the peer sends an AreYouThere
+        virtual void v_handleEC();      ///< Called, when the peer sends an EraseCharacter
+        virtual void v_handleEL();      ///< Called, when the peer sends an EraseLine
+        virtual void v_handleGA();      ///< Called, when the peer sends a GoAhead
         
-#ifdef DOXYGEN
     private:
-#endif
         void handleChar(char c);
         void handleNormalChar(char c);
         void handleCommand(char c);
@@ -212,15 +331,25 @@ namespace term {
         friend class TelnetHandler;
     };
 
+    /** \brief Telnet handler base class
+        
+        \see BaseTelnetProtocol
+     */
     struct BaseTelnetProtocol::TelnetHandler
         : public virtual BaseTelnetProtocol
     {
         virtual ~TelnetHandler();
-        virtual void v_init() = 0;
+        virtual void v_init() = 0;      ///< Called, after option has been enabled
         virtual void v_handleOptionParameters(std::string const & data) = 0;
+                                        ///< Called, whenever a subnegotiation is received
     };
 
-    // See http://www.iana.org/assignments/telnet-options for a list of options
+    /** \brief Telnet option codes
+
+        See http://www.iana.org/assignments/telnet-options for a list of options
+
+        \ingroup telnet_group 
+     */
     namespace telnetopt { BaseTelnetProtocol::option_type const ECHO = 1u; }
     namespace telnetopt { BaseTelnetProtocol::option_type const TRANSMIT_BINARY = 0u; }
     namespace telnetopt { BaseTelnetProtocol::option_type const SUPPRESS_GO_AHEAD = 3u; }
@@ -228,16 +357,32 @@ namespace term {
     namespace telnetopt { BaseTelnetProtocol::option_type const NAWS = 31u; }
     namespace telnetopt { BaseTelnetProtocol::option_type const LINEMODE = 34u; }
 
+/** \brief Telnet handlers
+
+    \ingroup telnet_group */
 namespace telnethandler {
 
+    /** \brief Implement TERMINAL_TYPE option
+
+        This telnet handler implements the TERMINAL_TYPE option. The handler automatically requests
+        the first terminal type during initialization. Further terminal types may then be reqeusted
+        by calling nextTerminalType().
+
+        The last received terminal type will be returned by the terminalType() member.
+
+        This implementation only provides server support (querying the terminal type).
+
+        \see BaseTelnetProtocol for how to integrate this handler \n
+            <a href="http://tools.ietf.org/html/rfc1091">RFC 1091</a> Telnet Terminal-Type Option
+     */
     class TerminalType
         : public BaseTelnetProtocol::TelnetHandler
     {
     public:
         static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
 
-        void nextTerminalType();
-        std::string const & terminalType() const;
+        void nextTerminalType();        ///< Request another terminal type
+        std::string const & terminalType() const; ///< Return current terminal type
         
     protected:
         TerminalType();
@@ -249,21 +394,38 @@ namespace telnethandler {
         std::string type_;
     };
 
+    /** \brief Implement NAWS (Negotiation About Window Size) option
+        
+        This telnet handler implements the NAWS option. The client terminals window size will be
+        requested during initialization. The current window size may always be accessed using the
+        width() and height() members. 
+        
+        Whenever the window size is changed, the v_windowSizeChanged() function is called. This
+        function must be implemented in a derived class.
+
+        \see BaseTelnetProtocol for how to integrate this handler \n
+            <a href="http://tools.ietf.org/html/rfc1073">RFC 1073</a> Telnet Window Size Option
+     */
     class NAWS 
         : public BaseTelnetProtocol::TelnetHandler
     {
     public:
         static option_type const OPTION_CODE = telnetopt::NAWS;
 
-        unsigned width() const;
-        unsigned height() const;
+        unsigned width() const;         ///< Get current client window width
+        unsigned height() const;        ///< Get current client window height
 
     protected:
         NAWS();
         
+#   ifndef DOXYGEN
     private:
-        virtual void v_windowSizeChanged() = 0;
+#   endif
+        virtual void v_windowSizeChanged() = 0; ///< Called, whenever window size changes
+                                        /**< This member is called for every window size change \e
+                                             after initialization. */
 
+    private:
         virtual void v_init();
         virtual void v_handleOptionParameters(std::string const & data);
 
index ed2be42..8d31583 100644 (file)
 namespace senf {
 namespace term {
 
+    /** \brief AbstractTerminal interface implementation based on telnet
+
+        This class provides a telnet server implementation implementing the AbstractTerminal
+        interface. 
+
+        TelnetTerminal provides one additional callback which needs to be implemented in a derived
+        class: v_setupFailed(). This member will be called, when not all required telnet options are
+        supported by the telnet client. In this case, the communication will be switched back into
+        line-oriented mode and v_setupFailed() is called.
+
+        \ingroup telnet_group
+     */
     class TelnetTerminal
         : public telnethandler::TerminalType,
           public telnethandler::NAWS,
@@ -44,15 +56,23 @@ namespace term {
     public:
         TelnetTerminal();
 
+        ///\name AbstractTerminal interface implementation
+        ///\{
         virtual void setCallbacks(AbstractTerminal::Callbacks & cb);
         virtual std::string terminalType();
         virtual unsigned width();
         virtual unsigned height();
         virtual void write(char ch);
+        ///\}
 
+    protected:
+
+#   ifndef DOXYGEN
     private:
-        virtual void v_setupFailed() = 0;
+#   endif
+        virtual void v_setupFailed() = 0; ///< Called when the telnet setup has failed
 
+    private:
         virtual void v_setupComplete();
         virtual void v_charReceived(char ch);
         virtual void v_windowSizeChanged();
index 616f374..2413e66 100644 (file)
 namespace senf {
 namespace term {
 
+    /** \defgroup terminfo_group Terminfo
+
+        This facility provides access to the terminfo database. It partially re-implements the
+        terminfo suppoprt in \c libncurses.
+
+        \li The senf::term::Terminfo class provides basic terminfo property access and supports terminfo string
+            formatting
+        \li The senf::term::KeyParser class uses the properties found in a Terminfo instance to
+            parser keyboard escape sequences into key codes
+
+        The terminfo implementation is based on the \c utio library by Mike Sharov
+        <msharov@users.sourceforge.net> found at http://sourceforge.net/projects/utio.
+     */
+
+    /** \brief Terminfo database entry
+        
+        This class reads a single terminfo database entry and allows to access the terminfo
+        properties. 
+        
+        \ingroup terminfo_group 
+     */
     class Terminfo
     {
     public:
         ///////////////////////////////////////////////////////////////////////////
         // Types
 
+        /** \brief NoValue constant
+            This value represents the absence of a numeric property value */
         enum { NoValue = -1 };
 
+        /** \brief Terminfo property constants
+
+            This class provides a namespace for all Terminfo property constants
+         */
         struct properties
         {
+            /** \brief Boolean terminfo properties */
             enum Boolean {
                 AutoLeftMargin, AutoRightMargin, NoEscCtlc, CeolStandoutGlitch, EatNewlineGlitch,
                 EraseOverstrike, GenericType, HardCopy, HasMetaKey, HasStatusLine, InsertNullGlitch,
@@ -63,8 +91,11 @@ namespace term {
                 NoCorrectlyWorkingCr, GnuHasMetaKey, LinefeedIsNewline, HasHardwareTabs,
                 ReturnDoesClrEol };
             
+            /** \brief Boolean property names
+                \hideinitializer */
             static char const * const BooleanNames[];
-
+            
+            /** \brief Numeric terminfo properties */
             enum Numeric {
                 Columns, InitTabs, Lines, LinesOfMemory, MagicCookieGlitch, PaddingBaudRate,
                 VirtualTerminal, WidthStatusLine, NumLabels, LabelHeight, LabelWidth, MaxAttributes,
@@ -75,8 +106,11 @@ namespace term {
                 MagicCookieGlitchUl, CarriageReturnDelay, NewLineDelay, BackspaceDelay,
                 HorizontalTabDelay, NumberOfFunctionKeys };
 
+            /** \brief Numeric property names
+                \hideinitializer */
             static char const * const NumericNames[];
-            
+
+            /** \brief String terminfo properties */
             enum String {
                 BackTab, Bell, CarriageReturn, ChangeScrollRegion, ClearAllTabs, ClearScreen,
                 ClrEol, ClrEos, ColumnAddress, CommandCharacter, CursorAddress, CursorDown,
@@ -142,35 +176,43 @@ namespace term {
                 AcsLlcorner, AcsUrcorner, AcsLrcorner, AcsLtee, AcsRtee, AcsBtee, AcsTtee, AcsHline,
                 AcsVline, AcsPlus, MemoryLock, MemoryUnlock, BoxChars1 };
 
+            /** \brief String property names
+                \hideinitializer */
             static char const * const StringNames[];
         };
 
-        typedef boost::int16_t number_t;
-        typedef char const* string_t;
+        typedef boost::int16_t number_t; ///< Numeric terminfo property type
+        typedef char const* string_t;   ///< String terminfo property type
 
         ///////////////////////////////////////////////////////////////////////////
         
         Terminfo();
-        explicit Terminfo(std::string const & term);
-        void load(std::string const & term);
+        explicit Terminfo(std::string const & term); ///< Load terminfo entry \a term
+        void load(std::string const & term); ///< Load terminfo entry \a term
         
-        bool getFlag(properties::Boolean p) const;
-        number_t getNumber(properties::Numeric p) const;
-        string_t getString(properties::String p) const;
-        bool hasProperty(properties::Boolean p) const;
-        bool hasProperty(properties::Numeric p ) const;
-        bool hasProperty(properties::String p ) const;
+        bool getFlag(properties::Boolean p) const; ///< Get boolean property value
+        number_t getNumber(properties::Numeric p) const; ///< Get numeric property value
+        string_t getString(properties::String p) const; ///< Get string property value
+                                        /**< If the property does not exist, 0 is returned */
+        bool hasProperty(properties::Boolean p) const; ///< \c true, if boolean property \a p exists
+        bool hasProperty(properties::Numeric p ) const; ///< \c true, if numeric property \a p exists
+        bool hasProperty(properties::String p ) const; ///< \c true, if string property \a p exists
+
         std::string formatString(properties::String p,
                                  number_t arg1=NoValue, number_t arg2=NoValue, 
                                  number_t arg3=NoValue, number_t arg4=NoValue,
                                  number_t arg5=NoValue, number_t arg6=NoValue,
                                  number_t arg7=NoValue, number_t arg8=NoValue,
                                  number_t arg9=NoValue) const;
+                                        ///< Format string property value
+                                        /**< Formats the string property \a p containing special
+                                             terminfo codes. Terminfo supports up to 9 parameters. */
 
         ///////////////////////////////////////////////////////////////////////////
 
-        void dump(std::ostream & os) const;
+        void dump(std::ostream & os) const; ///< Dump a description of the terminfo entry
 
+        /** \brief Invalid, incomplete or non-existent terminfo entry exception */
         struct InvalidTerminfoException : public senf::Exception
         { InvalidTerminfoException() : senf::Exception("Unreadable terminfo file") {} };
 
@@ -190,13 +232,23 @@ namespace term {
         StringPool stringPool_;
     };
 
+    /** \brief Parse key escape sequences
 
+        The KeyParser will read the relevant properties from a terminfo entry and then provides
+        functions to parser keyboard escape sequences.
+
+        All keys are returned as keyboard code's. Values 0 to 255 represent ordinary ASCII
+        characters, larger values are special keys taken from the KeyCode \c enum
+        
+        \ingroup terminfo_group 
+     */
     class KeyParser
     {
     public:
         ///////////////////////////////////////////////////////////////////////////
         // Types
 
+        /** \brief Special keyboard key codes */
         enum KeyCode {
             Space = ' ', Tab = '\t', Return = '\r', First = 0xE000, Esc = First, Backspace, Backtab,
             Begin, CATab, CTab, Cancel, Center, Clear, ClearToEOL, ClearToEOS, Close, Command, Copy,
@@ -213,23 +265,46 @@ namespace term {
             ShiftRedo, ShiftReplace, ShiftResume, ShiftRight, ShiftSave, ShiftSuspend, ShiftTab,
             ShiftUndo, Suspend, Undo, Up, UpLeft, UpRight, Incomplete = 0xE0FF };
 
+        /** \brief Special key code names
+            \hideinitializer */
         static char const * const KeyNames[];
 
-        typedef wchar_t keycode_t;
-        typedef std::string::size_type size_type;
+        typedef wchar_t keycode_t;      ///< Key code data type
+        typedef std::string::size_type size_type; ///< String length type
 
+        /** \brief Helper to convert uppercase char to Control key code */
         static keycode_t Ctrl(char ch) { return ch-'@'; }
 
         ///////////////////////////////////////////////////////////////////////////
 
         KeyParser();
-        explicit KeyParser(Terminfo const & ti);
-        void load(Terminfo const & ti);
+        explicit KeyParser(Terminfo const & ti); ///< Load keymap information from \a ti
+        void load(Terminfo const & ti); ///< Load keymap information from \a ti
 
         std::pair<keycode_t, size_type> lookup(std::string const & key) const;
-        static std::string describe(keycode_t key);
-
-        void dump(std::ostream & os) const;
+                                        ///< Lookup up string \a key
+                                        /**< This call will look up the string in \a key in the
+                                             keymap. The return value is a pair.
+                                             \li the first value is the key code
+                                             \li the second value is the number of characters in \a
+                                                 key which have been interpreted and returned in the
+                                                 first value
+
+                                             If \a key is not a complete key sequence, the return
+                                             key code will be the \c Invalid value and the returned
+                                             escape sequence size will be 0.
+
+                                             If \a key does not start with an escape sequence, the
+                                             returned key code will be the first character from \a
+                                             key and the escape sequence size will be 1.
+
+                                             Otherwise \a key starts with a complete escape
+                                             sequence. The returned key code will be a value from
+                                             the KeyCode enum and the escape sequence size will be
+                                             returned accordingly. */
+        static std::string describe(keycode_t key); ///< Return descriptive, printable key name
+
+        void dump(std::ostream & os) const; ///< Dump keymap for debug purposes
 
     private:
         typedef std::map<std::string, KeyCode> Keytable;