Logo Search packages:      
Sourcecode: afnix version File versions

Terminal.cpp

// ---------------------------------------------------------------------------
// - Terminal.cpp                                                            -
// - afnix standard library - terminal class implementation                  -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - 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.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2007 amaury darsch                                   -
// ---------------------------------------------------------------------------

#include "Vector.hpp"
#include "Boolean.hpp"
#include "Terminal.hpp"
#include "Character.hpp"
#include "QuarkZone.hpp"
#include "Exception.hpp"

namespace afnix {

  // -------------------------------------------------------------------------
  // - private section                                                       -
  // -------------------------------------------------------------------------

  // default prompts
  static const char* DEFAULT_PROMPT1 = "(axi) ";
  static const char* DEFAULT_PROMPT2 = "(...) ";

  // -------------------------------------------------------------------------
  // - class section                                                         -
  // -------------------------------------------------------------------------

  // create a default terminal

00040   Terminal::Terminal (void) {
    // prompt initialize
    d_prt1 = DEFAULT_PROMPT1;
    d_prt2 = DEFAULT_PROMPT2;
    // save the input stream state
    save ();
  }

  // destroy this terminal

00050   Terminal::~Terminal (void) {
    // restore terminal state
    restore ();
  }

  // return the class name

00057   String Terminal::repr (void) const {
    return "Terminal";
  }

  // insert a character in this terminal

00063   void Terminal::insert (const t_quad c) {
    wrlock ();
    try {
      // check if we are at the eol
      if (d_lbuf.iseol () == true) {
      // insert the character in the buffer
      d_lbuf.add (c);
      // insert the character in the terminal
      OutputTerm::insert (c);
      // check if we need to move the cursor to the next line
      long cols = getcols ();
      long cpos = d_lbuf.getabs ();
      if ((cols != 0) && ((cpos % cols) == 0)) {
        if (OutputTerm::mvbol () == false) OutputTerm::movel (cols);
        OutputTerm::moved (1);
      }
      unlock ();
      return;
      }
      // if we are not in insert mode - just replace the character
      if (d_insert == false) {
      d_lbuf.add (c);
      OutputTerm::insert (c);
      // check if we need to move the cursor to the next line
      long cols = getcols ();
      long cpos = d_lbuf.getabs ();
      if ((cols != 0) && ((cpos % cols) == 0)) {
        if (OutputTerm::mvbol () == false) OutputTerm::movel (cols);
        OutputTerm::moved (1);
      }
      unlock ();
      return;
      }
      // here we are in the middle of the line - start by killing the line at
      // the cursor position - then insert the character and refresh the rest
      // of the line - we also need to restore the original cursor position
      // first save the context
      long   crem = d_lbuf.getrem ();
      String sstr = d_lbuf.substr ();
      // kill at the cursor position
      kbchr ();
      // insert the character, then the line
      insert (c);
      OutputTerm::insert (sstr);
      // restore the cursor position
      for (long i = 0; i < crem; i++) {
      if (movel () == false) break;
      }
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // delete a character in place

00120   void Terminal::rmchr (void) {
    wrlock ();
    try {
      // check if we operate at the eol
      if (d_lbuf.iseol () ==  true) {
      unlock ();
      return;
      }
      // check if we are at the last character
      if (d_lbuf.islst () ==  true) {
      // delete the buffer character
      if (d_lbuf.chdel () == true) {
        // delete the terminal character
        OutputTerm::chdel ();
      }
      unlock ();
      return;
      }
      // here we are in the middle of the line - start by saving the buffer
      // in the next position, kill the line at the cursor and restore
      // the remaining buffer
      if (d_lbuf.isdel () == true) {
      // save the buffer contents
      String sstr = d_lbuf.delstr ();
      // kill at the cursor position
      kbchr ();
      // insert the line
      OutputTerm::insert (sstr);
      // restore the cursor position
      long slen = sstr.length ();
      for (long i = 0; i < slen; i++) {
        if (movel () == false) break;
      }
      }
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // delete a character in backspace mode

00163   void Terminal::bkchr (void) {
    wrlock ();
    try {
      // move to the left and delete
      if (movel () == true) rmchr ();
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // move to the beginning of the line

00177   bool Terminal::mvbol (void) {
    wrlock ();
    try {
      // get the number of move
      long num  = d_lbuf.getrel ();
      // loop for the move
      for (long i = 0; i < num; i++) {
      if (movel () == false) {
        unlock ();
        return false;
      }
      }
      unlock ();
      return true;
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // move to the end of the line

00199   bool Terminal::mveol (void) {
    wrlock ();
    try {
      // get the number of moves
      long num  = d_lbuf.getrem ();
      // loop for the move
      for (long i = 0; i < num; i++) {
      if (mover () == false) {
        unlock ();
        return false;
      }
      }
      unlock ();
      return true;
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // move the terminal cursor to the left

00221   bool Terminal::movel (void) {
    wrlock ();
    try {
      // move the line cursor
      if (d_lbuf.movel () == false) {
      unlock ();
      return false;
      }
      // update the terminal 
      long cols = getcols ();
      long cpos = d_lbuf.getabs () + 1;
      if ((cols != 0) && ((cpos % cols) == 0)) {
      OutputTerm::moveu (1);
      OutputTerm::mover (cols);
      } else {
      OutputTerm::movel (1);
      }
      unlock ();
      return true;
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // move the terminal cursor to the right

00248   bool Terminal::mover (void) {
    wrlock ();
    try {
      // update the line buffer
      if (d_lbuf.mover () ==  false) {
      unlock ();
      return false;
      }
      // update the terminal cursor
      long cols = getcols ();
      long cpos = d_lbuf.getabs () - 1;
      if ((cols > 0) && ((cpos % cols) == (cols - 1))) {
      OutputTerm::movel (cols-1);
      OutputTerm::moved (1);
      } else {
      OutputTerm::mover (1);
      }
      unlock ();
      return true;
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // kill all characters from the current position

00275   void Terminal::kbchr (void) {
    wrlock ();
    try {
      // get the remaining characters
      long num = d_lbuf.getrem ();
      // move to the eol
      mveol ();
      // remove the characters
      for (long i = 0; i < num; i++) bkchr ();
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // kill all characters in the buffer

00293   void Terminal::kachr (void) {
    wrlock ();
    try {
      // move to the eol
      mveol ();
      // get the length
      long num = d_lbuf.length ();
      // remove the characters
      for (long i = 0; i < num; i++) bkchr ();
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // replace a buffer line with another one

00311   void Terminal::rline (const String& line) {
    wrlock ();
    try {
      // kill existing buffer
      kachr ();
      // reset buffer
      d_lbuf.clear ();
      // update the terminal
      OutputTerm::insert (line);
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // refresh the terminal

00329   void Terminal::rfrsh (void) {
    wrlock ();
    try {
      if (OutputTerm::clear () == true) {
      // get the string buffer
      String line = d_lbuf.tostring ();
      // clear the buffer
      d_lbuf.clear ();
      // write the prompt
      Output::write (d_lbuf.getprt ());
      // insert the line
      OutputTerm::insert (line);
      }
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // set the insert mode

00350   void Terminal::setim (void) {
    wrlock ();
    d_insert = !d_insert;
    d_lbuf.setim (d_insert);
    unlock ();
  }

  // read a line and return a string

00359   String Terminal::readline (bool pflag) {
    // reset the readline buffer
    d_lbuf.reset ();
    
    // check for the eof
    if (d_eof == true) return eofc;
    
    // turn off canonical mode and reset error mode
    bool canon = nocanon ();
    temode (false);

    // ok, print the prompt
    if (pflag == true) {
      Output::write (d_prt1);
      d_lbuf.setprt (d_prt1);
    } else {
      Output::write (d_prt2);
      d_lbuf.setprt (d_prt2);
    }

    // loop until we have an eol/eof
    while (true) {
      t_quad w = wread ();

      // check for backspace
      if ((canon == true ) && isbs (w) == true) {
      bkchr ();
      continue;
      }
      
      // check for delete
      if ((canon == true)  && isdel (w) == true) {
      rmchr ();
      continue;
      }
      
      // check for insert
      if ((canon == true) && (isins (w) == true)) {
      setim ();
      continue;
      }
      
      // check for move to begin line
      if ((canon == true) && (w == WIDE_STDBL)) {
      mvbol ();
      continue;
      }
      
      // check for move to end of line
      if ((canon == true) && (w == WIDE_STDEL)) {
      mveol ();
      continue;
      }
      
      // check for kill everything
      if ((canon == true) && (w == WIDE_STDKB)) {
      kachr ();
      continue;
      }
      
      // check for kill to eol
      if ((canon == true) && (w == WIDE_STDKL)) {
      kbchr ();
      continue;
      }

      // check for refresh
      if ((canon == true) && (w == WIDE_STDRF)) {
      rfrsh ();
        continue;
      }
      
      // check for move to left
      if ((canon == true) && (isle (w) == true)) {
      movel ();
      continue;
      }
      
      // check for move to right
      if ((canon == true)  && (isri (w) == true)) {
      mover ();
      continue;
      }

      // check for a move down
      if ((canon == true) && (isdo (w) == true)) {
      if (d_cilo.istop () == true) {
        kachr ();
        continue;
      }
      String* data = dynamic_cast <String*> (d_cilo.getup ());
      if (data == nilp)
        kachr ();
      else
        rline (*data);
      continue;
      }
      
      // check for a move up
      if ((canon == true) && (isup (w) == true)) {
      if (d_cilo.isbottom () == true) continue;
      String* data = dynamic_cast <String*> (d_cilo.getdown ());
      if (data == nilp)
        kachr ();
      else
        rline (*data);
      continue;
      }

      // make sure the cursor is reset to the end for a eol/eof
      if (w == WIDE_STDNL) d_lbuf.setce ();
      if (w == WIDE_STDEF) d_lbuf.setce ();
      
      // check for printable - if not we reject - we accept eol/eof as well
      if (ispr (w) == false) continue;

      // process normal character
      if ((w == WIDE_STDNL) || (w == WIDE_STDEF)) {
      if (d_lbuf.length () > 0) {
        d_cilo.add (new String (d_lbuf.tostring()));
      }
      d_lbuf.add (w);
      write (eolc);
      break;
      }
      // insert the character in the terminal
      insert (w);
    }
    // this is it - return the string buffer
    if (canon == true) restore ();
    return d_lbuf.tostring ();
  }

  // set the primary prompt

00494   void Terminal::setpp (const String& value) {
    wrlock ();
    d_prt1 = value;
    unlock ();
  }

  // set the seconday prompt

00502   void Terminal::setsp (const String& value) {
    wrlock ();
    d_prt2 = value;
    unlock ();
  }

  // get the primary prompt

00510   String Terminal::getpp (void) const {
    rdlock ();
    String result = d_prt1;
    unlock ();
    return result;
  }

  // get the secondary prompt

00519   String Terminal::getsp (void) const {
    rdlock ();
    String result = d_prt2;
    unlock ();
    return result;
  }

  // -------------------------------------------------------------------------
  // - object section                                                        -
  // -------------------------------------------------------------------------

  // the quark zone
  static const long QUARK_ZONE_LENGTH = 5;
  static QuarkZone  zone (QUARK_ZONE_LENGTH);

  // the object supported quarks
  static const long QUARK_GETPP    = zone.intern ("get-primary-prompt");
  static const long QUARK_GETSP    = zone.intern ("get-secondary-prompt");
  static const long QUARK_SETPP    = zone.intern ("set-primary-prompt");
  static const long QUARK_SETSP    = zone.intern ("set-secondary-prompt");
  static const long QUARK_READLINE = zone.intern ("read-line");

  // create a new object in a generic way

00543   Object* Terminal::mknew (Vector* argv) {
    long argc = (argv == nilp) ? 0 : argv->length ();
    if (argc != 0) 
      throw Exception ("argument-error", "invalid arguments with terminal"); 
    return new Terminal;
  }

  // return true if the given quark is defined

00552   bool Terminal::isquark (const long quark, const bool hflg) const {
    rdlock ();
    if (zone.exists (quark) == true) {
      unlock ();
      return true;
    }
    bool result = hflg ? InputTerm::isquark (quark, hflg) : false;
    if (result == false) {
      result = hflg ? OutputTerm::isquark (quark, hflg) : false;
    }
    unlock ();
    return result;
  }

  // apply this object with a set of arguments and a quark

00568   Object* Terminal::apply (Runnable* robj, Nameset* nset, const long quark,
                     Vector* argv) {
    // get the number of arguments
    long argc = (argv == nilp) ? 0 : argv->length ();

    // dispatch 0 argument
    if (argc == 0) {
      if (quark == QUARK_READLINE) return new String    (readline (true));
      if (quark == QUARK_GETPP)    return new String    (getpp ());
      if (quark == QUARK_GETSP)    return new String    (getsp ());
    }

    // dispatch 1 argument
    if (argc == 1) {
      if (quark == QUARK_READLINE) {
      bool flag = argv->getbool (0);
      String* result = new String (readline (flag));
      return result;
      }
      if (quark == QUARK_SETPP) {
      String val = argv->getstring (0);
      setpp (val);
      return nilp;
      }
      if (quark == QUARK_SETSP) {
      String val = argv->getstring (0);
      setsp (val);
      return nilp;
      }
    }

    // check the input terminal stream
    if (InputTerm::isquark (quark, true) == true)
      return InputTerm::apply (robj, nset, quark, argv);
    // default to the output terminal stream
    return OutputTerm::apply(robj, nset, quark, argv);
  }
}

Generated by  Doxygen 1.6.0   Back to index