{ 
    SemTel version 1.0.0 ... comfortable telnet client
    Copyright (C) 1995-2000 Jan Tomasek <jan@tomasek.cz>

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
}
{-------------------------------------------------------------------------------
Version  : 0.888
Date     : 10.08.98
Dialog   :
History  :
  08.07.98 Pridan virtualni terminal pro nacitani definice terminalu ze
           souboru
  23.07.98 Pridana vlastnost 'ignore' pro ignorovani vseho nechteneho
  10.08.98 Direct barvy, klavesy ...
TODO     :
-------------------------------------------------------------------------------}

unit xTerm;

interface
Uses
  Classes, Console, xTree, Graphics, WinTypes, STConfig;
Type
  TPrinterOnOff = Procedure(Sender:TObject) of object;
  TPrinterPrint = Procedure(Sender:TObject;Data:PChar;Len:Integer) of object;
  TOTP          = Procedure(Sender:TObject;Challenge:String) of object;
  TParams       = Record
    Count     : Integer;
    Separator : Boolean;
    Number    : Boolean;
    Data      : Array[0..9] of Integer;
  End;
  TCmdString     = String[16];
  TKeyState      = (ksN, ksC, ksS, ksA, ksCS, ksCA, ksSA, ksCSA);
  TKeyStrings    = Array[ksN..ksCSA] of String[50];

  TVirtualTerminal  = class(TPersistent)
    private
      Fk_ESC            : TKeyStrings;
      Fk_INS            : TKeyStrings;
      Fk_TAB            : TKeyStrings;
      Fk_BACK           : TKeyStrings;
      Fk_ENTER          : TKeyStrings;
      Fk_DELETE         : TKeyStrings;
      Fk_UPARROW        : TKeyStrings;
      Fk_DOWNARROW      : TKeyStrings;
      Fk_RIGHTARROW     : TKeyStrings;
      Fk_LEFTARROW      : TKeyStrings;
      Fk_F1             : TKeyStrings;
      Fk_F2             : TKeyStrings;
      Fk_F3             : TKeyStrings;
      Fk_F4             : TKeyStrings;
      Fk_F5             : TKeyStrings;
      Fk_F6             : TKeyStrings;
      Fk_F7             : TKeyStrings;
      Fk_F8             : TKeyStrings;
      Fk_F9             : TKeyStrings;
      Fk_F10            : TKeyStrings;
      Fk_F11            : TKeyStrings;
      Fk_F12            : TKeyStrings;
      Fk_HOME           : TKeyStrings;
      Fk_END            : TKeyStrings;
      Fk_PGDN           : TKeyStrings;
      Fk_PGUP           : TKeyStrings;

      Fk_N_NumLock      : TKeyStrings;
      Fk_N_Divide       : TKeyStrings;
      Fk_N_Multiply     : TKeyStrings;
      Fk_N_Minus        : TKeyStrings;
      Fk_N_Plus         : TKeyStrings;
      Fk_N_Decimal      : TKeyStrings;
      Fk_N_0            : TKeyStrings;
      Fk_N_1            : TKeyStrings;
      Fk_N_2            : TKeyStrings;
      Fk_N_3            : TKeyStrings;
      Fk_N_4            : TKeyStrings;
      Fk_N_5            : TKeyStrings;
      Fk_N_6            : TKeyStrings;
      Fk_N_7            : TKeyStrings;
      Fk_N_8            : TKeyStrings;
      Fk_N_9            : TKeyStrings;

      Fk_A              : TKeyStrings;
      Fk_B              : TKeyStrings;
      Fk_C              : TKeyStrings;
      Fk_D              : TKeyStrings;
      Fk_E              : TKeyStrings;
      Fk_F              : TKeyStrings;
      Fk_G              : TKeyStrings;
      Fk_H              : TKeyStrings;
      Fk_I              : TKeyStrings;
      Fk_J              : TKeyStrings;
      Fk_K              : TKeyStrings;
      Fk_L              : TKeyStrings;
      Fk_M              : TKeyStrings;
      Fk_N              : TKeyStrings;
      Fk_O              : TKeyStrings;
      Fk_P              : TKeyStrings;
      Fk_Q              : TKeyStrings;
      Fk_R              : TKeyStrings;
      Fk_S              : TKeyStrings;
      Fk_T              : TKeyStrings;
      Fk_U              : TKeyStrings;
      Fk_V              : TKeyStrings;
      Fk_W              : TKeyStrings;
      Fk_X              : TKeyStrings;
      Fk_Y              : TKeyStrings;
      Fk_Z              : TKeyStrings;
      Fk_0              : TKeyStrings;
      Fk_1              : TKeyStrings;
      Fk_2              : TKeyStrings;
      Fk_3              : TKeyStrings;
      Fk_4              : TKeyStrings;
      Fk_5              : TKeyStrings;
      Fk_6              : TKeyStrings;
      Fk_7              : TKeyStrings;
      Fk_8              : TKeyStrings;
      Fk_9              : TKeyStrings;

      Fk_LQuote         : TKeyStrings;
      Fk_Minus          : TKeyStrings;
      Fk_EQU            : TKeyStrings;
      Fk_Backslash      : TKeyStrings;
      Fk_LBracket       : TKeyStrings;
      Fk_RBracket       : TKeyStrings;
      Fk_Semicolon      : TKeyStrings;
      Fk_RQuoute        : TKeyStrings;
      Fk_Comma          : TKeyStrings;
      Fk_Decimal        : TKeyStrings;
      Fk_Divide         : TKeyStrings;
      Fk_ScrollLock     : TKeyStrings;
      Fk_CapsLock       : TKeyStrings;

      FAutoMargin       : Boolean;
      FCheckBeforeCh    : Boolean;

      Procedure SetCommands(Tree:TParserTree; Const FName:String);
      Function LoadTermCommandsFormFile(FName: String; SL: TStringList):Integer;
    public
      Constructor Create;
      Destructor Done;

      property k_ESC            : TKeyStrings read Fk_ESC;
      property k_INS            : TKeyStrings read Fk_INS;
      property k_TAB            : TKeyStrings read Fk_TAB;
      property k_BACK           : TKeyStrings read Fk_BACK;
      property k_ENTER          : TKeyStrings read Fk_ENTER;
      property k_DELETE         : TKeyStrings read Fk_DELETE;
      property k_UPARROW        : TKeyStrings read Fk_UPARROW;
      property k_DOWNARROW      : TKeyStrings read Fk_DOWNARROW;
      property k_RIGHTARROW     : TKeyStrings read Fk_RIGHTARROW;
      property k_LEFTARROW      : TKeyStrings read Fk_LEFTARROW;
      property k_F1             : TKeyStrings read Fk_F1;
      property k_F2             : TKeyStrings read Fk_F2;
      property k_F3             : TKeyStrings read Fk_F3;
      property k_F4             : TKeyStrings read Fk_F4;
      property k_F5             : TKeyStrings read Fk_F5;
      property k_F6             : TKeyStrings read Fk_F6;
      property k_F7             : TKeyStrings read Fk_F7;
      property k_F8             : TKeyStrings read Fk_F8;
      property k_F9             : TKeyStrings read Fk_F9;
      property k_F10            : TKeyStrings read Fk_F10;
      property k_F11            : TKeyStrings read Fk_F11;
      property k_F12            : TKeyStrings read Fk_F12;
      property k_HOME           : TKeyStrings read Fk_HOME;
      property k_END            : TKeyStrings read Fk_END;
      property k_PGDN           : TKeyStrings read Fk_PGDN;
      property k_PGUP           : TKeyStrings read Fk_PGUP;
      property k_N_NumLock      : TKeyStrings read Fk_N_NumLock;
      property k_N_Divide       : TKeyStrings read Fk_N_Divide;
      property k_N_Multiply     : TKeyStrings read Fk_N_Multiply;
      property k_N_Minus        : TKeyStrings read Fk_N_Minus;
      property k_N_Plus         : TKeyStrings read Fk_N_Plus;
      property k_N_Decimal      : TKeyStrings read Fk_N_Decimal;
      property k_N_0            : TKeyStrings read Fk_N_0;
      property k_N_1            : TKeyStrings read Fk_N_1;
      property k_N_2            : TKeyStrings read Fk_N_2;
      property k_N_3            : TKeyStrings read Fk_N_3;
      property k_N_4            : TKeyStrings read Fk_N_4;
      property k_N_5            : TKeyStrings read Fk_N_5;
      property k_N_6            : TKeyStrings read Fk_N_6;
      property k_N_7            : TKeyStrings read Fk_N_7;
      property k_N_8            : TKeyStrings read Fk_N_8;
      property k_N_9            : TKeyStrings read Fk_N_9;
      property k_A              : TKeyStrings read Fk_A;
      property k_B              : TKeyStrings read Fk_B;
      property k_C              : TKeyStrings read Fk_C;
      property k_D              : TKeyStrings read Fk_D;
      property k_E              : TKeyStrings read Fk_E;
      property k_F              : TKeyStrings read Fk_F;
      property k_G              : TKeyStrings read Fk_G;
      property k_H              : TKeyStrings read Fk_H;
      property k_I              : TKeyStrings read Fk_I;
      property k_J              : TKeyStrings read Fk_J;
      property k_K              : TKeyStrings read Fk_K;
      property k_L              : TKeyStrings read Fk_L;
      property k_M              : TKeyStrings read Fk_M;
      property k_N              : TKeyStrings read Fk_N;
      property k_O              : TKeyStrings read Fk_O;
      property k_P              : TKeyStrings read Fk_P;
      property k_Q              : TKeyStrings read Fk_Q;
      property k_R              : TKeyStrings read Fk_R;
      property k_S              : TKeyStrings read Fk_S;
      property k_T              : TKeyStrings read Fk_T;
      property k_U              : TKeyStrings read Fk_U;
      property k_V              : TKeyStrings read Fk_V;
      property k_W              : TKeyStrings read Fk_W;
      property k_X              : TKeyStrings read Fk_X;
      property k_Y              : TKeyStrings read Fk_Y;
      property k_Z              : TKeyStrings read Fk_Z;
      property k_0              : TKeyStrings read Fk_0;
      property k_1              : TKeyStrings read Fk_1;
      property k_2              : TKeyStrings read Fk_2;
      property k_3              : TKeyStrings read Fk_3;
      property k_4              : TKeyStrings read Fk_4;
      property k_5              : TKeyStrings read Fk_5;
      property k_6              : TKeyStrings read Fk_6;
      property k_7              : TKeyStrings read Fk_7;
      property k_8              : TKeyStrings read Fk_8;
      property k_9              : TKeyStrings read Fk_9;
      property k_LQuote         : TKeyStrings read Fk_LQuote;
      property k_Minus          : TKeyStrings read Fk_Minus;
      property k_EQU            : TKeyStrings read Fk_EQU;
      property k_Backslash      : TKeyStrings read Fk_Backslash;
      property k_LBracket       : TKeyStrings read Fk_LBracket;
      property k_RBracket       : TKeyStrings read Fk_RBracket;
      property k_Semicolon      : TKeyStrings read Fk_Semicolon;
      property k_RQuoute        : TKeyStrings read Fk_RQuoute;
      property k_Comma          : TKeyStrings read Fk_Comma;
      property k_Decimal        : TKeyStrings read Fk_Decimal;
      property k_Divide         : TKeyStrings read Fk_Divide;
      property k_ScrollLock     : TKeyStrings read Fk_ScrollLock;
      property k_CapsLock       : TKeyStrings read Fk_CapsLock;

      property AutoMargin       : Boolean     read FAutoMargin;
      property CheckBeforeCh    : Boolean     read FCheckBeforeCh;
  End;

  TTerminalEmulator = class(TComponent)
    private
      CConsole      : PxTermConsole;
      Buff          : String;
      Tree          : TParserTree;
      CursorPos     : TPoint;
      FPrinterActive: Boolean;
      FCharSetTable : TCPArray;
      FSemigrTable  : TCPArray;
      FCharEncEn    : Boolean;
      FCP           : PdConnectionParameters;
      FOTP          : TOTP;
      FPrinterOn    : TPrinterOnOff;
      FPrinterOff   : TPrinterOnOff;
      FPrinterPrint : TPrinterPrint;
      FSemigraphics : Boolean;
      Params        : TParams;
      PSearch       : TList;
      PNSearch      : TList;

      Procedure Print(Buffer:PChar;Len:Integer); {Print to console or printer, depends on FSemigraphics}
      Procedure SetColor(Foregr,Backgr: Byte);   {Sets console color}
      Procedure tcCursorHorizontal;
      Procedure tcCursorVertical;
      Procedure tcCursorUp;
      Procedure tcCursorDown;
      Procedure tcCursorRight;
      Procedure tcCursorLeft;
      Procedure tcCursorParam;
      Procedure tcCursorLeftBottom;
      Procedure tcSaveCursorPos;
      Procedure tcLoadCursorPos;
      Procedure tcBackTab;
      Procedure tcTab;
      Procedure tcCR;
      Procedure tcNel;

      Procedure tcColor;
      Procedure tcExitUnderlineMode;

      Procedure tcInsertCharacter;
      Procedure tcInsertLine;
      Procedure tcRepeatLastChar;
      Procedure tcDeleteCharacter;
      Procedure tcDeleteLine;
      Procedure tcClearScreen;
      Procedure tcDeleteToEOL;
      Procedure tcDeleteToBOL;
      Procedure tcClearEOS;

      Procedure tcCASemigrOn;
      Procedure tcCASemigrOff;
      Procedure tcCANormal;
      Procedure tcCABold;
      Procedure tcCABlink;
      Procedure tcCAUnderline;
      Procedure tcCAInverse;
      Procedure tcCANonvisible;

      Procedure tcCAfblack;
      Procedure tcCAfred;
      Procedure tcCAfgreen;
      Procedure tcCAfyellow;
      Procedure tcCAfblue;
      Procedure tcCAfmagenta;
      Procedure tcCAfcyan;
      Procedure tcCAfwhite;
      Procedure tcCAbblack;
      Procedure tcCAbred;
      Procedure tcCAbgreen;
      Procedure tcCAbyellow;
      Procedure tcCAbblue;
      Procedure tcCAbmagenta;
      Procedure tcCAbcyan;
      Procedure tcCAbwhite;

      Procedure tcBel;
      Procedure tcOtpCh;

      Procedure tcReverseScroll;
      Procedure tcNormalScroll;
      Procedure tcSetScrollRegion;

      Procedure tcPrinterOn;
      Procedure tcPrinterOff;

      Procedure ExecCmd(Cmd: Word);
      Procedure ParseNextChar(C:Char);
      Function  DoParallelSearch(C:Char):Boolean;
      Procedure StartParallelSearch;

      Procedure WConsole(C:PxTermConsole);
    public
      VirtT         : TVirtualTerminal;

      Constructor Create(aOwner:TComponent); override;
      Destructor Destroy; override;
      Procedure SetCommands;
      procedure Process(Buffer:PChar; Len:Integer);

      property Console       : PxTermConsole read CConsole write WConsole;
      property PrinterActive : Boolean read FPrinterActive;
      property CharEncEn     : Boolean read FCharEncEn write FCharEncEn;
      property CharsetTable  : TCPArray read FCharSetTable write FCharSetTable;
      property SemigrTable   : TCPArray read FSemigrTable write FSemigrTable;
      property Semigraphics  : Boolean read FSemigraphics;
      property CP            : PdConnectionParameters read FCP write FCP;
      property OnOTP         : TOTP          read FOTP          write FOTP;
      property OnPrinterOn   : TPrinterOnOff read FPrinterOn    write FPrinterOn;
      property OnPrinterOff  : TPrinterOnOff read FPrinterOff   write FPrinterOff;
      property OnPrinterPrint: TPrinterPrint read FPrinterPrint write FPrinterPrint;
  End;

  Function ProcessEscapes(si:String):String;


implementation

Uses
  C3216,    Forms,   SysUtils, WinProcs,
  Printers, INIFiles;

Const
{-- Cursor movement -----------------------------------------------------------}
  tc_cursor_up              = 10000;
  tc_param_cursor_up        = 10001;
  tc_cursor_down            = 10002;
  tc_param_cursor_down      = 10003;
  tc_cursor_right           = 10004;
  tc_param_cursor_right     = 10005;
  tc_cursor_left            = 10006;
  tc_param_cursor_left      = 10007;
  tc_cursor_home            = 10008;
  tc_param_cursor           = 10009;
  tc_cursor_to_line         = tc_param_cursor;
  tc_cursor_to_column       = tc_param_cursor;
  tc_cursor_left_bottom     = 10010;
  tc_cursor_horizontal      = 10011;
  tc_cursor_vertical        = 10012;
  tc_save_cursor_pos        = 10013;
  tc_load_cursor_pos        = 10014;
  tc_back_tab               = 10015;
  tc_tab                    = 10016;
  tc_cr                     = 10017;
  tc_nel                    = 10018;

{-- Deleting and clearing -----------------------------------------------------}
  tc_clear_eos              = 10020;
  tc_clear_screen           = 10021;
  tc_delete_character       = 10022;
  tc_delete_characters      = 10023;
  tc_delete_to_eol          = 10024;
  tc_delete_to_bol          = 10025;
  tc_delete_line            = 10026;
  tc_delete_lines           = 10027;

{-- Inserting -----------------------------------------------------------------}
  tc_insert_character       = 10030;
  tc_insert_characters      = 10031;
  tc_insert_line            = 10032;
  tc_insert_lines           = 10033;
  tc_repeat_last_char       = 10034;

{-- Colors and atributes ------------------------------------------------------}
  tc_set_attributes         = 10040;
  tc_exit_underline_mode    = 10041;
  tc_fblack                 = 10042;
  tc_fred                   = 10043;
  tc_fgreen                 = 10044;
  tc_fyellow                = 10045;
  tc_fblue                  = 10046;
  tc_fmagenta               = 10047;
  tc_fcyan                  = 10048;
  tc_fwhite                 = 10049;
  tc_bblack                 = 10050;
  tc_bred                   = 10051;
  tc_bgreen                 = 10052;
  tc_byellow                = 10053;
  tc_bblue                  = 10054;
  tc_bmagenta               = 10055;
  tc_bcyan                  = 10056;
  tc_bwhite                 = 10057;
  tc_bold                   = 10058;
  tc_underline              = 10059;
  tc_blink                  = 10060;
  tc_inverse                = 10061;
  tc_nonvisible             = 10062;
  tc_smacs                  = 10063;
  tc_rmacs                  = 10064;                   

{-- Misc ----------------------------------------------------------------------}
  tc_bel                    = 10070;
  tc_otp_ch                 = 10071;

{-- Scrolling -----------------------------------------------------------------}
  tc_reverse_scroll         = 10080;
  tc_normal_scroll          = 10081;
  tc_scroll_region          = 10082;

{-- Printing ------------------------------------------------------------------}
  tc_printer_on             = 10090;
  tc_printer_off            = 10091;

{-- Ignore this ---------------------------------------------------------------}
  tc_ignore                 = 10100;
  tc_test1                  = 10101;
  tc_test2                  = 10102;


Function ProcessEscapes(si:String):String;
Var
  I,J,K : Integer;
  so    : String;
  no    : String;
Begin
  so:='';

  I:=1;
  While I<=Length(si) Do Begin
    Case si[I] of
      '\' : Begin
              Case si[I+1] of
                '\' : Begin { backslash }
                  so:=so+'\'; Inc(I,2);
                End;
                'b' : Begin { backspace }
                  so:=so+#8; Inc(I,2);
                End;
                'E','e' : Begin { escape }
                  so:=so+#27; Inc(I,2);
                End;
                'n' : Begin { new line - DOS mode -> CRLF }
                  so:=so+#13#10; Inc(I,2);
                End;
                'r' : Begin { carriage-return }
                  so:=so+#13; Inc(I,2);
                End;
                't' : Begin { tab }
                  so:=so+#9; Inc(I,2);
                End;
                '1'..'9': Begin { decadic number }
                   no:='';
                   For I:=I+1 To Length(si) Do
                     If si[I] in ['0'..'9'] Then
                       no:=no+si[I]
                     Else
                       Break;
                   so:=so+chr(StrToIntDef(no, 0));
                End;
                'x': Begin { hexa number }
                   Inc(I, 2); no:='';
                   For I:=I To Length(si) Do
                     If UpperCase(si[I])[1] in ['0'..'9', 'A'..'F'] Then no:=no+si[I]
                     Else Break;
                   so:=so+chr(StrToIntDef('$'+no, 0));
                End;
                '0': Case si[I+2] of
                  'x' : Begin { hexa number }
                    Inc(I, 3); no:='';
                    For I:=I To Length(si) Do
                      If UpperCase(si[I])[1] in ['0'..'9', 'A'..'F'] Then no:=no+si[I]
                      Else Break;
                    so:=so+chr(StrToIntDef('$'+no, 0));
                  End;
                  '0'..'9': Begin { octal number }
                    Inc(I, 1); no:='';
                    For I:=I To Length(si) Do
                      If UpperCase(si[I])[1] in ['0'..'7'] Then no:=no+si[I]
                      Else Break;
                    K:=0; For J:=1 To Length(no) Do K:=K*8+Ord(no[J])-Ord('0');
                    so:=so+chr(K);
                  End;
                End;
                Else Begin
                  so:=so+si[I+1];
                  Inc(I,2);
                End;
              End;{si[I+1]}
            End;
      '^' : Begin
              so:=so+chr(ord(si[I+1])-ord('A')+1);
              Inc(I,2)
            End;
      Else  Begin
              so:=so+si[I];
              Inc(I)
            End;
    End;{si[I]}
  End;

  Result:=so;
End;

Constructor TVirtualTerminal.Create;
Begin
  Fk_ESC       [ksN] := ProcessEscapes('\E');
  Fk_INS       [ksN] := ProcessEscapes('\E[L');
  Fk_TAB       [ksN] := ProcessEscapes('^J');
  Fk_BACK      [ksN] := ProcessEscapes('^H');
  Fk_ENTER     [ksN] := ProcessEscapes('^M');
  FAutoMargin   := True;
  FCheckBeforeCh:= False;
End;

Destructor TVirtualTerminal.Done;
Begin
End;

Function EquColor(Const ColorStr, Value:String):Boolean;
Begin
  Result:=Pos(';'+Value+';', ColorStr)>0;
End;

Procedure AddColor(Var ColorStr:String; Value:String);
Begin
  If EquColor(ColorStr, Value) Then Exit;
  ColorStr:=ColorStr+Value+';';
End;

Function TVirtualTerminal.LoadTermCommandsFormFile(FName: String; SL: TStringList):Integer;
Var
  S       : ShortString;
  Code    : String;
  Value   : String;
  SL_temp : TStringList;
Begin
  SL_temp            := TStringList.Create;
  SL_temp.Duplicates := dupAccept;
  SL_temp.Sorted     := False;

  try  SL_temp.LoadFromFile(FName);
  except on EFOpenError do begin
  end; end;

  while SL_temp.Count>0 do begin
    S := Trim(SL_temp.Strings[0]); SL_temp.Delete(0);
    If (S[1]=';')or(S='') Then Continue;

    Code:=System.Copy(S, 1, Pos('=',S)-1);
      While Code[Length(Code)]=' ' Do System.Delete(Code, Length(Code), 1);
    System.Delete(S, 1, Pos('=',S));
      While S[1]=' ' Do System.Delete(S, 1, 1);
    System.Delete(S, Pos(' ',S), $FF);
    if Code='include'    then begin
      Value:=S; S:=ExtractFilePath(FName);
      LoadTermCommandsFormFile(S+Value, SL);
    end else begin
      SL.Add(Code + ' = ' + S);
    end;
  end;
  SL_temp.free;
end;

Procedure TVirtualTerminal.SetCommands(Tree:TParserTree; Const FName:String);
Var
  S        : ShortString;
  Code     : String;
  Value    : String;
  SL       : TStringList;
  SL1      : TStringList;
  J        : Integer;
  KeyState : TKeyState;
Begin
  SL            := TStringList.Create;
  SL.Duplicates := dupAccept;
  SL.Sorted     := False;

  LoadTermCommandsFormFile(FName, SL);
  if SL.Count=0 then begin
    S:=Format(ctNoMainTermFile+#0,[FName]);
    MessageBox(0, @S[1], @ctError[1], MB_ICONSTOP or MB_OK);
  end;

  While SL.Count>0 Do Begin
    S := Trim(SL.Strings[0]); SL.Delete(0);
    If (S[1]=';')or(S='') Then Continue;

    Code:=System.Copy(S, 1, Pos('=',S)-1);
      While Code[Length(Code)]=' ' Do System.Delete(Code, Length(Code), 1);
    System.Delete(S, 1, Pos('=',S));
      While S[1]=' ' Do System.Delete(S, 1, 1);
    System.Delete(S, Pos(' ',S), $FF);

    Value:=ProcessEscapes(S);

    if Code='cuu1'       Then Begin Tree.Add(tc_cursor_up           ,Value); Continue End;
    if Code='cuu'        Then Begin Tree.Add(tc_param_cursor_up     ,Value); Continue End;
    if Code='cud1'       Then Begin Tree.Add(tc_cursor_down         ,Value); Continue End;
    if Code='cud'        Then Begin Tree.Add(tc_param_cursor_down   ,Value); Continue End;
    if Code='cuf1'       Then Begin Tree.Add(tc_cursor_right        ,Value); Continue End;
    if Code='cuf'        Then Begin Tree.Add(tc_param_cursor_right  ,Value); Continue End;
    if Code='cub1'       Then Begin Tree.Add(tc_cursor_left         ,Value); Continue End;
    if Code='cub'        Then Begin Tree.Add(tc_param_cursor_left   ,Value); Continue End;
    if Code='home'       Then Begin Tree.Add(tc_cursor_home         ,Value); Continue End;
    if Code='ll'         Then Begin Tree.Add(tc_cursor_left_bottom  ,Value); Continue End;
    if Code='cup'        Then Begin Tree.Add(tc_param_cursor        ,Value); Continue End;
    if Code='cup'        Then Begin Tree.Add(tc_cursor_to_line      ,Value); Continue End;
    if Code='cup'        Then Begin Tree.Add(tc_cursor_to_column    ,Value); Continue End;
    if Code='hpa'        Then Begin Tree.Add(tc_cursor_horizontal   ,Value); Continue End;
    if Code='vpa'        Then Begin Tree.Add(tc_cursor_vertical     ,Value); Continue End;
    if Code='sc'         Then Begin Tree.Add(tc_save_cursor_pos     ,Value); Continue End;
    if Code='rc'         Then Begin Tree.Add(tc_load_cursor_pos     ,Value); Continue End;
    if Code='cbt'        Then Begin Tree.Add(tc_back_tab            ,Value); Continue End;
    if Code='ht'         Then Begin Tree.Add(tc_tab                 ,Value); Continue End;
    if Code='cr'         Then Begin Tree.Add(tc_cr                  ,Value); Continue End;
    if Code='nel'        Then Begin Tree.Add(tc_nel                 ,Value); Continue End;

    if Code='ed'         Then Begin Tree.Add(tc_clear_eos           ,Value); Continue End;
    if Code='clear'      Then Begin Tree.Add(tc_clear_screen        ,Value); Continue End;
    if Code='dch1'       Then Begin Tree.Add(tc_delete_character    ,Value); Continue End;
    if Code='dch'        Then Begin Tree.Add(tc_delete_characters   ,Value); Continue End;
    if Code='el'         Then Begin Tree.Add(tc_delete_to_eol       ,Value); Continue End;
    if Code='el1'        Then Begin Tree.Add(tc_delete_to_bol       ,Value); Continue End;
    if Code='dl1'        Then Begin Tree.Add(tc_delete_line         ,Value); Continue End;
    if Code='dl'         Then Begin Tree.Add(tc_delete_lines        ,Value); Continue End;

    if Code='ich1'       Then Begin Tree.Add(tc_insert_character    ,Value); Continue End;
    if Code='ich'        Then Begin Tree.Add(tc_insert_characters   ,Value); Continue End;
    if Code='il1'        Then Begin Tree.Add(tc_insert_line         ,Value); Continue End;
    if Code='il'         Then Begin Tree.Add(tc_insert_lines        ,Value); Continue End;
    if Code='rep'        Then Begin Tree.Add(tc_repeat_last_char    ,Value); Continue End;

    if Code='sgr'        Then Begin Tree.Add(tc_set_attributes      ,Value); Continue End;
    if Code='rmul'       Then Begin Tree.Add(tc_exit_underline_mode ,Value); Continue End;
    if Code='smacs'      Then Begin Tree.Add(tc_smacs               ,Value); Continue End;
    if Code='rmacs'      Then Begin Tree.Add(tc_rmacs               ,Value); Continue End;

    if Code='ri'         Then Begin Tree.Add(tc_reverse_scroll      ,Value); Continue End;
    if Code='ind'        Then Begin Tree.Add(tc_normal_scroll       ,Value); Continue End;
    if Code='csr'        Then Begin Tree.Add(tc_scroll_region       ,Value); Continue End;

    if Code='bel'        Then Begin Tree.Add(tc_bel                 ,Value); Continue End;

    if Code='mc4'        Then Begin Tree.Add(tc_printer_off         ,Value); Continue End;
    if Code='mc5'        Then Begin Tree.Add(tc_printer_on          ,Value); Continue End;
    if Code='fblack'     Then Begin Tree.Add(tc_fblack              ,Value); Continue End;
    if Code='fred'       Then Begin Tree.Add(tc_fred                ,Value); Continue End;
    if Code='fgreen'     Then Begin Tree.Add(tc_fgreen              ,Value); Continue End;
    if Code='fyellow'    Then Begin Tree.Add(tc_fyellow             ,Value); Continue End;
    if Code='fblue'      Then Begin Tree.Add(tc_fblue               ,Value); Continue End;
    if Code='fmagenta'   Then Begin Tree.Add(tc_fmagenta            ,Value); Continue End;
    if Code='fcyan'      Then Begin Tree.Add(tc_fcyan               ,Value); Continue End;
    if Code='fwhite'     Then Begin Tree.Add(tc_fwhite              ,Value); Continue End;
    if Code='bblack'     Then Begin Tree.Add(tc_bblack              ,Value); Continue End;
    if Code='bred'       Then Begin Tree.Add(tc_bred                ,Value); Continue End;
    if Code='bgreen'     Then Begin Tree.Add(tc_bgreen              ,Value); Continue End;
    if Code='byellow'    Then Begin Tree.Add(tc_byellow             ,Value); Continue End;
    if Code='bblue'      Then Begin Tree.Add(tc_bblue               ,Value); Continue End;
    if Code='bmagenta'   Then Begin Tree.Add(tc_bmagenta            ,Value); Continue End;
    if Code='bcyan'      Then Begin Tree.Add(tc_bcyan               ,Value); Continue End;
    if Code='bwhite'     Then Begin Tree.Add(tc_bwhite              ,Value); Continue End;
    if Code='bold'       Then Begin Tree.Add(tc_bold                ,Value); Continue End;
    if Code='underline'  Then Begin Tree.Add(tc_underline           ,Value); Continue End;
    if Code='blink'      Then Begin Tree.Add(tc_blink               ,Value); Continue End;
    if Code='inverse'    Then Begin Tree.Add(tc_inverse             ,Value); Continue End;
    if Code='nonvisible' Then Begin Tree.Add(tc_nonvisible          ,Value); Continue End;

    if Code='ignore'     Then Begin Tree.Add(tc_ignore              ,Value); Continue End;
    if Code='test1'      Then Begin Tree.Add(tc_test1               ,Value); Continue End;
    if Code='test2'      Then Begin Tree.Add(tc_test2               ,Value); Continue End;

    if Code='otp-ch'     Then Begin Tree.Add(tc_otp_ch              ,Value); Continue End;

    if Code='am'         Then Begin FAutoMargin   := Value='1';Continue End;
    if Code='ambc'       Then Begin FCheckBeforeCh:= Value='1';Continue End;


    if Pos('_', Code)=0     Then Continue;
    S:=Copy(Code, 1, Pos('_', Code)-1);
    Delete(Code, 1, Pos('_', Code));
    KeyState:=ksN;
    If S='kC'  Then KeyState:=ksC;
    If S='kS'  Then KeyState:=ksS;
    If S='kA'  Then KeyState:=ksA;
    If S='kCS' Then KeyState:=ksCS;
    If S='kCA' Then KeyState:=ksCA;
    If S='kSA' Then KeyState:=ksSA;
    If S='kCSA'Then KeyState:=ksCSA;

    if Code='esc'        Then Begin Fk_ESC        [KeyState]:= Value; Continue End;
    if Code='bs'         Then Begin Fk_BACK       [KeyState]:= Value; Continue End;

    if Code='f1'         Then Begin Fk_F1         [KeyState]:= Value; Continue End;
    if Code='f2'         Then Begin Fk_F2         [KeyState]:= Value; Continue End;
    if Code='f3'         Then Begin Fk_F3         [KeyState]:= Value; Continue End;
    if Code='f4'         Then Begin Fk_F4         [KeyState]:= Value; Continue End;
    if Code='f5'         Then Begin Fk_F5         [KeyState]:= Value; Continue End;
    if Code='f6'         Then Begin Fk_F6         [KeyState]:= Value; Continue End;
    if Code='f7'         Then Begin Fk_F7         [KeyState]:= Value; Continue End;
    if Code='f8'         Then Begin Fk_F8         [KeyState]:= Value; Continue End;
    if Code='f9'         Then Begin Fk_F9         [KeyState]:= Value; Continue End;
    if Code='f10'        Then Begin Fk_F10        [KeyState]:= Value; Continue End;
    if Code='f11'        Then Begin Fk_F11        [KeyState]:= Value; Continue End;
    if Code='f12'        Then Begin Fk_F12        [KeyState]:= Value; Continue End;
    if Code='home'       Then Begin Fk_HOME       [KeyState]:= Value; Continue End;
    if Code='end'        Then Begin Fk_END        [KeyState]:= Value; Continue End;
    if Code='np'         Then Begin Fk_PGDN       [KeyState]:= Value; Continue End;
    if Code='pp'         Then Begin Fk_PGUP       [KeyState]:= Value; Continue End;
    if Code='cuu1'       Then Begin Fk_UPARROW    [KeyState]:= Value; Continue End;
    if Code='cud1'       Then Begin Fk_DOWNARROW  [KeyState]:= Value; Continue End;
    if Code='cuf1'       Then Begin Fk_RIGHTARROW [KeyState]:= Value; Continue End;
    if Code='cub1'       Then Begin Fk_LEFTARROW  [KeyState]:= Value; Continue End;
    if Code='tb'         Then Begin Fk_TAB        [KeyState]:= Value; Continue End;
    if Code='ich1'       Then Begin Fk_INS        [KeyState]:= Value; Continue End;
    if Code='dch1'       Then Begin Fk_DELETE     [KeyState]:= Value; Continue End;
    if Code='ent'        Then Begin Fk_ENTER      [KeyState]:= Value; Continue End;
    if Code='N_NumLock'  Then Begin Fk_N_NumLock  [KeyState]:= Value; Continue End;
    if Code='N_Divide'   Then Begin Fk_N_Divide   [KeyState]:= Value; Continue End;
    if Code='N_Multiply' Then Begin Fk_N_Multiply [KeyState]:= Value; Continue End;
    if Code='N_Minus'    Then Begin Fk_N_Minus    [KeyState]:= Value; Continue End;
    if Code='N_Plus'     Then Begin Fk_N_Plus     [KeyState]:= Value; Continue End;
    if Code='N_Decimal'  Then Begin Fk_N_Decimal  [KeyState]:= Value; Continue End;
    if Code='N_0'        Then Begin Fk_N_0        [KeyState]:= Value; Continue End;
    if Code='N_1'        Then Begin Fk_N_1        [KeyState]:= Value; Continue End;
    if Code='N_2'        Then Begin Fk_N_2        [KeyState]:= Value; Continue End;
    if Code='N_3'        Then Begin Fk_N_3        [KeyState]:= Value; Continue End;
    if Code='N_4'        Then Begin Fk_N_4        [KeyState]:= Value; Continue End;
    if Code='N_5'        Then Begin Fk_N_5        [KeyState]:= Value; Continue End;
    if Code='N_6'        Then Begin Fk_N_6        [KeyState]:= Value; Continue End;
    if Code='N_7'        Then Begin Fk_N_7        [KeyState]:= Value; Continue End;
    if Code='N_8'        Then Begin Fk_N_8        [KeyState]:= Value; Continue End;
    if Code='N_9'        Then Begin Fk_N_9        [KeyState]:= Value; Continue End;
    if Code='A'          Then Begin Fk_A          [KeyState]:= Value; Continue End;
    if Code='B'          Then Begin Fk_B          [KeyState]:= Value; Continue End;
    if Code='C'          Then Begin Fk_C          [KeyState]:= Value; Continue End;
    if Code='D'          Then Begin Fk_D          [KeyState]:= Value; Continue End;
    if Code='E'          Then Begin Fk_E          [KeyState]:= Value; Continue End;
    if Code='F'          Then Begin Fk_F          [KeyState]:= Value; Continue End;
    if Code='G'          Then Begin Fk_G          [KeyState]:= Value; Continue End;
    if Code='H'          Then Begin Fk_H          [KeyState]:= Value; Continue End;
    if Code='I'          Then Begin Fk_I          [KeyState]:= Value; Continue End;
    if Code='J'          Then Begin Fk_J          [KeyState]:= Value; Continue End;
    if Code='K'          Then Begin Fk_K          [KeyState]:= Value; Continue End;
    if Code='L'          Then Begin Fk_L          [KeyState]:= Value; Continue End;
    if Code='M'          Then Begin Fk_M          [KeyState]:= Value; Continue End;
    if Code='N'          Then Begin Fk_N          [KeyState]:= Value; Continue End;
    if Code='O'          Then Begin Fk_O          [KeyState]:= Value; Continue End;
    if Code='P'          Then Begin Fk_P          [KeyState]:= Value; Continue End;
    if Code='Q'          Then Begin Fk_Q          [KeyState]:= Value; Continue End;
    if Code='R'          Then Begin Fk_R          [KeyState]:= Value; Continue End;
    if Code='S'          Then Begin Fk_S          [KeyState]:= Value; Continue End;
    if Code='T'          Then Begin Fk_T          [KeyState]:= Value; Continue End;
    if Code='U'          Then Begin Fk_U          [KeyState]:= Value; Continue End;
    if Code='V'          Then Begin Fk_V          [KeyState]:= Value; Continue End;
    if Code='W'          Then Begin Fk_W          [KeyState]:= Value; Continue End;
    if Code='X'          Then Begin Fk_X          [KeyState]:= Value; Continue End;
    if Code='Y'          Then Begin Fk_Y          [KeyState]:= Value; Continue End;
    if Code='Z'          Then Begin Fk_Z          [KeyState]:= Value; Continue End;

    if Code='0'          Then Begin Fk_0          [KeyState]:= Value; Continue End;
    if Code='1'          Then Begin Fk_1          [KeyState]:= Value; Continue End;
    if Code='2'          Then Begin Fk_2          [KeyState]:= Value; Continue End;
    if Code='3'          Then Begin Fk_3          [KeyState]:= Value; Continue End;
    if Code='4'          Then Begin Fk_4          [KeyState]:= Value; Continue End;
    if Code='5'          Then Begin Fk_5          [KeyState]:= Value; Continue End;
    if Code='6'          Then Begin Fk_6          [KeyState]:= Value; Continue End;
    if Code='7'          Then Begin Fk_7          [KeyState]:= Value; Continue End;
    if Code='8'          Then Begin Fk_8          [KeyState]:= Value; Continue End;
    if Code='9'          Then Begin Fk_9          [KeyState]:= Value; Continue End;

    if Code='LQuote'     Then Begin Fk_LQuote     [KeyState]:= Value; Continue End;
    if Code='Minus'      Then Begin Fk_Minus      [KeyState]:= Value; Continue End;
    if Code='EQU'        Then Begin Fk_EQU        [KeyState]:= Value; Continue End;
    if Code='Backslash'  Then Begin Fk_Backslash  [KeyState]:= Value; Continue End;
    if Code='LBracket'   Then Begin Fk_LBracket   [KeyState]:= Value; Continue End;
    if Code='RBracket'   Then Begin Fk_RBracket   [KeyState]:= Value; Continue End;
    if Code='Semicolon'  Then Begin Fk_Semicolon  [KeyState]:= Value; Continue End;
    if Code='RQuoute'    Then Begin Fk_RQuoute    [KeyState]:= Value; Continue End;
    if Code='Comma'      Then Begin Fk_Comma      [KeyState]:= Value; Continue End;
    if Code='Decimal'    Then Begin Fk_Decimal    [KeyState]:= Value; Continue End;
    if Code='Divide'     Then Begin Fk_Divide     [KeyState]:= Value; Continue End;
    if Code='ScrollLock' Then Begin Fk_ScrollLock [KeyState]:= Value; Continue End;
    if Code='CapsLock'   Then Begin Fk_CapsLock   [KeyState]:= Value; Continue End;
  End;
  SL.Free;
End;

Constructor TTerminalEmulator.Create(aOwner:TComponent);
Begin
  Inherited Create(aOwner);
  Buff            := '';
  Tree            := TParserTree.Create;
  FPrinterActive  := False;
  FSemigraphics   := False;
  Params.Count    := 0;
  Params.Separator:= True;
  Params.Number   := True;
  VirtT           := TVirtualTerminal.Create;
  PSearch         := TList.Create;
  PNSearch        := TList.Create;
  StartParallelSearch;

  SetCommands;
End;

Destructor TTerminalEmulator.Destroy;
Begin
  Tree            := TParserTree.Create;
  Tree.Free; Tree := nil;
  VirtT.Free; VirtT:= nil;
  PSearch.Clear; PSearch.Free; PSearch:=nil;
  PNSearch.Clear; PNSearch.Free; PNSearch:=nil;

  Inherited Destroy;
End;


Procedure TTerminalEmulator.Print(Buffer:PChar;Len:Integer);
Var
  I : Word;
Begin
  If FPrinterActive Then Begin
    If Assigned(FPrinterPrint) Then FPrinterPrint(Self,Buffer,Len);
  End Else Begin
    If FCharEncEn Then For I:=0 To Len-1 Do
      {Convert to valid charset table}
      If FSemigraphics Then Buffer[I]:=FSemigrTable[Buffer[I]]
      Else                  Buffer[I]:=FCharSetTable[Buffer[I]];
    CConsole^.WriteBuff(Buffer,Len);
  End;
End;{-- Print -----------------------------------------------------------------}

Procedure TTerminalEmulator.SetColor(Foregr,Backgr: Byte);
Begin
   CConsole^.PenColor  :=Foregr;
   CConsole^.PaperColor:=Backgr;
End;{-- SetColors -------------------------------------------------------------}

Procedure TTerminalEmulator.tcCASemigrOn;  Begin FSemigraphics:=True                                                       End;
Procedure TTerminalEmulator.tcCASemigrOff; Begin FSemigraphics:=False                                                      End;
Procedure TTerminalEmulator.tcCANormal;    Begin SetColor(clrNormal           , clrNormal);                                End;
Procedure TTerminalEmulator.tcCABlink;     Begin SetColor(clrBlink            , clrBlink);                                 End;
Procedure TTerminalEmulator.tcCABold;      Begin SetColor(clrBold             , clrBold);                                  End;
Procedure TTerminalEmulator.tcCAUnderline; Begin SetColor(clrUnderline        , clrUnderline);                             End;
Procedure TTerminalEmulator.tcCAInverse;   Begin SetColor(clrInverse          , clrInverse);                               End;
Procedure TTerminalEmulator.tcCANonvisible;Begin SetColor(CP^.Console.Colors.nonvisibleB , CP^.Console.Colors.nonvisibleB) End;

Procedure TTerminalEmulator.tcCAfblack;    Begin SetColor(clrBlack            , CConsole^.PaperColor); End;
Procedure TTerminalEmulator.tcCAfred;      Begin SetColor(clrRed              , CConsole^.PaperColor); End;
Procedure TTerminalEmulator.tcCAfgreen;    Begin SetColor(clrGreen            , CConsole^.PaperColor); End;
Procedure TTerminalEmulator.tcCAfyellow;   Begin SetColor(clrYellow           , CConsole^.PaperColor); End;
Procedure TTerminalEmulator.tcCAfblue;     Begin SetColor(clrBlue             , CConsole^.PaperColor); End;
Procedure TTerminalEmulator.tcCAfmagenta;  Begin SetColor(clrMagenta          , CConsole^.PaperColor); End;
Procedure TTerminalEmulator.tcCAfcyan;     Begin SetColor(clrCyan             , CConsole^.PaperColor); End;
Procedure TTerminalEmulator.tcCAfwhite;    Begin SetColor(clrWhite            , CConsole^.PaperColor); End;
Procedure TTerminalEmulator.tcCAbblack;    Begin SetColor(CConsole^.PenColor  , clrBlack);             End;
Procedure TTerminalEmulator.tcCAbred;      Begin SetColor(CConsole^.PenColor  , clrRed);               End;
Procedure TTerminalEmulator.tcCAbgreen;    Begin SetColor(CConsole^.PenColor  , clrGreen);             End;
Procedure TTerminalEmulator.tcCAbyellow;   Begin SetColor(CConsole^.PenColor  , clrYellow);            End;
Procedure TTerminalEmulator.tcCAbblue;     Begin SetColor(CConsole^.PenColor  , clrBlue);              End;
Procedure TTerminalEmulator.tcCAbmagenta;  Begin SetColor(CConsole^.PenColor  , clrMagenta);           End;
Procedure TTerminalEmulator.tcCAbcyan;     Begin SetColor(CConsole^.PenColor  , clrCyan);              End;
Procedure TTerminalEmulator.tcCAbwhite;    Begin SetColor(CConsole^.PenColor  , clrWhite);             End;

Procedure TTerminalEmulator.tcColor;
Var
  I : Integer;
Begin
  For I:=0 To Params.Count-1 Do
    Case Params.Data[I] of
    0 : If CP^.Console.Colors.normal     Then tcCANormal;
    1 : If CP^.Console.Colors.bold       Then tcCABold;
    4 : If CP^.Console.Colors.underline  Then tcCAUnderline;
    5 : If CP^.Console.Colors.black      Then tcCABlink;
    7 : If CP^.Console.Colors.reverse    Then tcCAInverse;
    8 : If CP^.Console.Colors.nonvisible Then tcCANonvisible;
    30: If CP^.Console.Colors.black      Then tcCAfblack;
    31: If CP^.Console.Colors.red        Then tcCAfred;
    32: If CP^.Console.Colors.green      Then tcCAfgreen;
    33: If CP^.Console.Colors.yellow     Then tcCAfyellow;
    34: If CP^.Console.Colors.blue       Then tcCAfblue;
    35: If CP^.Console.Colors.magenta    Then tcCAfmagenta;
    36: If CP^.Console.Colors.cyan       Then tcCAfcyan;
    37: If CP^.Console.Colors.white      Then tcCAfwhite;
    40: If CP^.Console.Colors.black      Then tcCAbblack;
    41: If CP^.Console.Colors.red        Then tcCAbred;
    42: If CP^.Console.Colors.green      Then tcCAbgreen;
    43: If CP^.Console.Colors.yellow     Then tcCAbyellow;
    44: If CP^.Console.Colors.blue       Then tcCAbblue;
    45: If CP^.Console.Colors.magenta    Then tcCAbmagenta;
    46: If CP^.Console.Colors.cyan       Then tcCAbcyan;
    47: If CP^.Console.Colors.white      Then tcCAbwhite;
  End;
End;{-- tcColor ---------------------------------------------------------------}

Procedure TTerminalEmulator.tcExitUnderlineMode;
Begin
  CConsole^.PenColor   :=clrNormal;
  CConsole^.PaperColor :=clrNormal;                
End;{-- tcExitUnderlineMode ---------------------------------------------------}

Procedure TTerminalEmulator.tcCursorHorizontal;
Begin
  If Params.Count=0 Then Exit;

  CConsole^.CursorTo(Params.Data[0]-1,CConsole^.CursorPos.Y);
End;{-- tcCursorHorizontal ----------------------------------------------------}

Procedure TTerminalEmulator.tcCursorVertical;
Begin
  If Params.Count=0 Then Exit;

  CConsole^.CursorTo(CConsole^.CursorPos.X,Params.Data[0]-1);
End;{-- tcCursorHorizontal ----------------------------------------------------}

Procedure TTerminalEmulator.tcCursorUp;
Begin
  If Params.Count=0 Then
    CConsole^.CursorTo(CConsole^.CursorPos.X,CConsole^.CursorPos.Y-1)
  Else
    CConsole^.CursorTo(CConsole^.CursorPos.X,CConsole^.CursorPos.Y-Params.Data[0]);
End;{-- tcCursorUp ------------------------------------------------------------}

Procedure TTerminalEmulator.tcCursorDown;
Begin
  If Params.Count=0 Then
    CConsole^.CursorTo(CConsole^.CursorPos.X,CConsole^.CursorPos.Y+1)
  Else
    CConsole^.CursorTo(CConsole^.CursorPos.X,CConsole^.CursorPos.Y+Params.Data[0]);
  CConsole^.ValidateCursorPos;
End;{-- tcCursorDown ----------------------------------------------------------}

Procedure TTerminalEmulator.tcCursorRight;
Begin
  If Params.Count=0 Then
    CConsole^.CursorTo(CConsole^.CursorPos.X+1,CConsole^.CursorPos.Y)
  Else
    CConsole^.CursorTo(CConsole^.CursorPos.X+Params.Data[0],CConsole^.CursorPos.Y);
End;{-- tcCursorRight ---------------------------------------------------------}

Procedure TTerminalEmulator.tcCursorLeft;
Begin
  If Params.Count=0 Then
    CConsole^.CursorTo(CConsole^.CursorPos.X-1,CConsole^.CursorPos.Y)
  Else
    CConsole^.CursorTo(CConsole^.CursorPos.X-Params.Data[0],CConsole^.CursorPos.Y);
End;{-- tcCursorLeft ----------------------------------------------------------}

Procedure TTerminalEmulator.tcCursorParam;
Begin
  If Params.Count=0 Then CConsole^.Cursor2Home; {\E[H}
  If Params.Count=1 Then CConsole^.CursorTo(0,Params.Data[0]-1);{\E[¤H to line}
  If Params.Count=2 Then
    If Params.Data[0]=0 Then {\E[;¤H to column}
      CConsole^.CursorTo(Params.Data[1]-1, 0)
    Else {\E[¤;¤H to line:column}
      CConsole^.CursorTo(Params.Data[1]-1, Params.Data[0]-1);
End;{-- tcParamCursor ---------------------------------------------------------}

Procedure TTerminalEmulator.tcCursorLeftBottom;
Begin
  CConsole^.Cursor2ll;
End;

Procedure TTerminalEmulator.tcInsertCharacter;
Begin
  If Params.Count>0 Then CConsole^.InsertCharacters(Params.Data[0])
  Else CConsole^.InsertCharacters(1);
End;{-- tcInsertCharacter -----------------------------------------------------}

Procedure TTerminalEmulator.tcRepeatLastChar;
Begin
  If Params.Count>0 Then CConsole^.RepeatLastChar(Params.Data[0])
  Else CConsole^.RepeatLastChar(1);
End;{-- tcRepeatLastChar ------------------------------------------------------}

Procedure TTerminalEmulator.tcInsertLine;
Begin
  If Params.Count>0 Then CConsole^.InsertLine(Params.Data[0])
  Else CConsole^.InsertLine(1);
End;{-- tcInsertLines ---------------------------------------------------------}

Procedure TTerminalEmulator.tcDeleteCharacter;
Begin
  If Params.Count>0 Then CConsole^.DeleteCharacters(Params.Data[0])
  Else CConsole^.DeleteCharacters(1);
End;{-- tcDeleteCharacter -----------------------------------------------------}

Procedure TTerminalEmulator.tcDeleteLine;
Begin
  If Params.Count>0 Then CConsole^.DeleteLine(Params.Data[0])
  Else CConsole^.DeleteLine(1);
End;{-- tcDeleteLines ---------------------------------------------------------}

Procedure TTerminalEmulator.tcSaveCursorPos;
Begin
  CursorPos:=CConsole^.CursorPos;
End;{-- tcSaveCursorPos -------------------------------------------------------}

Procedure TTerminalEmulator.tcLoadCursorPos;
Begin
  CConsole^.CursorTo(CursorPos.X,CursorPos.Y);
End;{-- tccLoadCursorPos ------------------------------------------------------}

Procedure TTerminalEmulator.tcBackTab;
Begin
  CConsole^.CursorTo(CConsole^.CursorPos.X-
                     (CConsole^.TabSize-(CConsole^.CursorPos.X mod CConsole^.TabSize)),
                     CConsole^.CursorPos.Y);
End;{-- tcBackTab -------------------------------------------------------------}
Procedure TTerminalEmulator.tcTab;
Var
  I: Integer;
Begin
  I:=8-(CConsole^.CursorPos.X mod 8);
  CConsole^.CursorTo(CConsole^.CursorPos.X+I, CConsole^.CursorPos.Y);
End;{-- tcTab -----------------------------------------------------------------}
Procedure TTerminalEmulator.tcCR;
Begin
  CConsole^.CursorTo(0, CConsole^.CursorPos.Y);
End;{-- tcCR ------------------------------------------------------------------}
Procedure TTerminalEmulator.tcNel;
Begin
  CConsole^.CursorTo(0, CConsole^.CursorPos.Y+1);
End;{-- tcNel -----------------------------------------------------------------}


Procedure TTerminalEmulator.tcClearScreen;
Begin
  CConsole^.ClrScr;
  FSemigraphics:=False;
End;{-- tcClearScreen ---------------------------------------------------------}

Procedure TTerminalEmulator.tcDeleteToEOL;
Begin
  CConsole^.ClrEol;
{  FSemigraphics:=False;}
End;{-- tcDeleteToEOL ---------------------------------------------------------}

Procedure TTerminalEmulator.tcDeleteToBOL;
Begin
  CConsole^.ClrBol;
{  FSemigraphics:=False;}
End;{-- tcDeleteToBOL ---------------------------------------------------------}

Procedure TTerminalEmulator.tcClearEOS;
Begin
  CConsole^.ClrEos;
{  FSemigraphics:=False;}
End;{-- tcClearEOS ------------------------------------------------------------}

Procedure TTerminalEmulator.tcBel;
Begin
  MessageBeep(0);
End;{-- tcBel -----------------------------------------------------------------}

Procedure TTerminalEmulator.tcOtpCh;
Begin
  If Assigned(FOTP) Then FOTP(Self, Buff);
  CConsole^.WriteString(Buff);
End;{-- tcOtpCh ---------------------------------------------------------------}

Procedure TTerminalEmulator.tcReverseScroll;
Begin
  CConsole^.ReverseScroll;
End;{-- tcReverseScroll -------------------------------------------------------}

Procedure TTerminalEmulator.tcNormalScroll;
Begin
  CConsole^.NormalScroll; 
End;{-- tcNormalScroll --------------------------------------------------------}

Procedure TTerminalEmulator.tcSetScrollRegion;
Begin
  CConsole^.ScrollRegY1 := Params.Data[0]-1;
  CConsole^.ScrollRegY2 := Params.Data[1]-1;
End;

Procedure TTerminalEmulator.tcPrinterOn;
Begin
  Buff:='';
  FPrinterActive := True;
  If Assigned(FPrinterOn) Then FPrinterOn(Self);
End;{-- tcPrinterOnOff --------------------------------------------------------}
Procedure TTerminalEmulator.tcPrinterOff;
Begin
  FPrinterActive := False;
  If Assigned(FPrinterOff) Then FPrinterOff(Self);
End;{-- tcPrinterOnOff --------------------------------------------------------}

Procedure TTerminalEmulator.ExecCmd(Cmd: Word);
Begin
  if FPrinterActive then begin
    if cmd = tc_printer_off then
      tcPrinterOff
    else
      Print(@Buff[1], Length(Buff));
  end else begin
    case Cmd of
      tc_cursor_up          ,
      tc_param_cursor_up    : tcCursorUp;
      tc_cursor_down        ,
      tc_param_cursor_down  : tcCursorDown;
      tc_cursor_right       ,
      tc_param_cursor_right : tcCursorRight;
      tc_cursor_left        ,
      tc_param_cursor_left  : tcCursorLeft;
      tc_cursor_home        ,
      tc_param_cursor       : tcCursorParam;
      tc_cursor_left_bottom : tcCursorLeftBottom;
      tc_cursor_horizontal  : tcCursorHorizontal;
      tc_cursor_vertical    : tcCursorVertical;
      tc_save_cursor_pos    : tcSaveCursorPos;
      tc_load_cursor_pos    : tcLoadCursorPos;
      tc_back_tab           : tcBackTab;
      tc_tab                : tcTab;
      tc_cr                 : tcCR;
      tc_nel                : tcNel;

      tc_insert_characters  : tcInsertCharacter;
      tc_insert_character   : tcInsertCharacter;
      tc_insert_lines       : tcInsertLine;
      tc_insert_line        : tcInsertLine;
      tc_repeat_last_char   : tcRepeatLastChar;
      tc_delete_characters  : tcDeleteCharacter;
      tc_delete_character   : tcDeleteCharacter;
      tc_delete_lines       : tcDeleteLine;
      tc_delete_line        : tcDeleteLine;
      tc_clear_screen       : tcClearScreen;
      tc_delete_to_eol      : tcDeleteToEOL;
      tc_delete_to_bol      : tcDeleteToBOL;
      tc_clear_eos          : tcClearEOS;

      tc_set_attributes     : tcColor;
      tc_fblack             : tcCAfblack;
      tc_fred               : tcCAfred;
      tc_fgreen             : tcCAfgreen;
      tc_fyellow            : tcCAfyellow;
      tc_fblue              : tcCAfblue;
      tc_fmagenta           : tcCAfmagenta;
      tc_fcyan              : tcCAfcyan;
      tc_fwhite             : tcCAfwhite;
      tc_bblack             : tcCAbblack;
      tc_bred               : tcCAbred;
      tc_bgreen             : tcCAbgreen;
      tc_byellow            : tcCAbyellow;
      tc_bblue              : tcCAbblue;
      tc_bmagenta           : tcCAbmagenta;
      tc_bcyan              : tcCAbcyan;
      tc_bwhite             : tcCAbwhite;
      tc_bold               : tcCAbold;      
      tc_underline          : tcCAunderline;
      tc_blink              : tcCAblink;
      tc_inverse            : tcCAinverse;
      tc_nonvisible         : tcCAnonvisible;
      tc_exit_underline_mode: tcExitUnderlineMode;
      tc_smacs              : tcCAsemigrOn;
      tc_rmacs              : tcCAsemigrOff;

      tc_reverse_scroll     : tcReverseScroll;
      tc_normal_scroll      : tcNormalScroll;
      tc_scroll_region      : tcSetScrollRegion;

      tc_bel                : tcBel;
      tc_otp_ch             : tcOtpCh;

      tc_printer_on         : tcPrinterOn;
      tc_printer_off        : tcPrinterOff;

      tc_ignore             : ;
      tc_test1              : Begin CConsole^.WriteString('[Test 1]'); End;
      tc_test2              : Begin CConsole^.WriteString('[Test 2]'); End;
    end;
  end;
End;{-- ExecCmd ---------------------------------------------------------------}

Procedure TTerminalEmulator.StartParallelSearch;
Begin
  PSearch.Clear;
  PSearch.Add(Tree.Root);
End;

Function TTerminalEmulator.DoParallelSearch(C:Char):Boolean;
{ Removed because is called to often, I want INLINE directive!!!
Function IsEqual(XValue,aValue: Char):Boolean;
Begin
  Result:=XValue=aValue;
  If not Result Then Result:=(XValue='¤')and(aValue>='0')and(aValue<='9');
End;}
Var
  I, J     : Integer;
  TreeE, X : TParserTreeElement;
  List     : TList;
  IsEqual  : Boolean;
Begin
  PNSearch.Clear;
  For I:=0 To PSearch.Count-1 Do Begin
    TreeE := PSearch.Items[I];
    For J:=0 To TreeE.Nodes.Count-1 Do Begin
      X:=TreeE.Nodes.Items[J];
      IsEqual:=X.Value=C;
      If not IsEqual Then IsEqual:=(X.Value='¤')and(C>='0')and(C<='9');
      If IsEqual Then If PNSearch.IndexOf(X)=-1 Then PNSearch.Add(X);
    End;
  End;
  List  :=PSearch; PSearch:=PNSearch; PNSearch:=List;
  Result:=PSearch.Count>0;
End;

Procedure TTerminalEmulator.ParseNextChar(C:Char);
Function Found:Integer;
Var
  I : Integer;
Begin
  Result:=-1;
  If PSearch.Count=0 Then Exit; {Nothing found}

  For I:=0 To PSearch.Count-1 Do {Finished searching? ... all command<>0}
    If TParserTreeElement(PSearch.Items[I]).Command=0 Then Exit;

  Result:=0; {Prednost ma prvni}
  If PSearch.Count>1 Then
    For I:=0 To PSearch.Count-1 Do {Prednost ma plne zadany prikaz}
      If Pos('¤', TParserTreeElement(PSearch.Items[I]).Seq)=0 Then Begin
        Result:=I;
        Exit;
      End;
End;

Var
  F       : Integer;
Begin
   If DoParallelSearch(C) Then Begin
     Buff:=Buff+C;
     Case C of
       '0' .. '9' : If Params.Number Then Begin
          If Params.Separator Then Begin
            Params.Data[Params.Count]:=0;
            Inc(Params.Count);
          End;
          Params.Data[Params.Count-1]:=Params.Data[Params.Count-1]*10+Ord(C)-Ord('0');
          Params.Separator:=False;
       End;
       ';': If Params.Separator Then Begin
              Params.Data[Params.Count]:=0;
              Params.Number:=True;
              Inc(Params.Count);
            End Else Begin
              Params.Separator:=True;
              Params.Number:=True;
            End;
       Else Begin
         Params.Separator:=True;
         If Params.Count>0 Then Params.Number:=False
       End;
     End;
     F:=Found;
     If F>=0 Then Begin
       ExecCmd(TParserTreeElement(PSearch.Items[F]).Command);
       Buff:='';
       StartParallelSearch;
       Params.Count:=0;
       Params.Separator:=True;
       Params.Number:=True;
     End;
   End Else Begin
     Params.Count:=0;
     Params.Separator:=True;
     StartParallelSearch;
     If not DoParallelSearch(C) Then Begin { Diky C neni Buff znama sekvence a }
                                           { ani C samo o sobe neni zacatek    }
                                           { nejake sekvence.                  }
       StartParallelSearch;
       Buff:=Buff+C;
       Print(@Buff[1],Length(Buff));
       {$IFDEF DEBUGTERMDEF}
       If Length(Buff)>1 Then Begin
         CConsole.InteligentPaint;
         Sleep(2500);
       End;
       {$ENDIF}
       Buff:='';
     End Else Begin                        { C je zacatek nejake sekvence.     }
       If Length(Buff)>0 Then Print(@Buff[1],Length(Buff));
       {$IFDEF DEBUGTERMDEF}
       If Length(Buff)>1 Then Begin
         CConsole.InteligentPaint;
         Sleep(2500);
       End;
       {$ENDIF}
       Buff:=C;
     End;
   End;
End;{-- ParseNextChar ---------------------------------------------------------}


Procedure TTerminalEmulator.Process(Buffer:PChar; Len: Integer);
Var
  I       : Word;
Begin
  if Len>0 then
    for I:=0 to Len-1 do ParseNextChar(Buffer[I]);
End;

Procedure TTerminalEmulator.SetCommands;
Var
  PT : PTerminal;
Begin
  If FCP=nil Then PT := PTerminal(CFG^.Terminals.Items[0])
  Else            PT := TerminalFind(FCP^.Connection.TerminalType);
  If PT=nil  Then PT := PTerminal(CFG^.Terminals.Items[0]);

  Tree.Free; Tree := nil;
  Tree            := TParserTree.Create;
  StartParallelSearch;

  VirtT.SetCommands(Tree, PT^.FName);
End;

Procedure TTerminalEmulator.WConsole(C:PxTermConsole);
Begin
  CConsole:=C;
  CConsole^.CheckBeforeCh:=VirtT.CheckBeforeCh;
End;

End.
