
{***************** ANSI console Terminal Functions  ***********************}


  {derived from ... }
  {ANSI Alternative to turbo pascal CRT unit}
  {By Rick Housh - CIS PIN 72466,212}
  {Uses standard ANSI calls for all cursor placement, color attribute }
  { changes, etc., }

  { google "ansi console codes" for details }

(**************************************************************************)
{ All of the Text Color constants are supported.

  None of the Crt Mode constants are supplied.

  The variable CheckBreak is present, but not implemented.
  None of the other variables are supported, as almost all have to do
  with various aspects of direct screen writing, which is not supported.

  It is possible to do much more with ANSI actually, than with many of
  Turbo's standard CRT procedures, but no extras were implemented, in
  the interest of compatibility with Turbo.

  There is one major limitation.  The window procedure is not supported.
  In the interest of universal compatibility Textmode is also not supported,
  although it could be.

  The following CRT unit functions and procedures are supported as follows:
    AssignCrt      :   Not supported
    ClrEol         :   Fully supported
    ClrScr         :   Fully supported
    Delay          :   Not supported
    DelLine        :   Not supported    (Could easily be, but never used it)
    GotoXY         :   Fully supported
    HighVideo      :   Fully supported
    InsLine        :   Not Supported    (See DelLine)
    LowVideo       :   Fully supported
    NoSound        :   Not supported
    Sound          :   Not supported
    TextBackground :   Fully supported
    TextColor      :   Fully supported
    TextMode       :   Not supported
    Window         :   Not supported
    KeyPressed     :   Fully supported
    NormVideo      :   Fully supported
    ReadKey        :   Fully supported
    WhereX         :   Fully supported
    WhereY         :   Fully supported


        This program is dedicated to the public domain.
        No copyright is claimed.
        I would be interested in reports.
                    Rick Housh
                    5811 W. 85th Terr.
                    Overland Park, KS 66207
                    Tel. 913/341-7592
                    Compuserve PIN #72466,212

}

{@@ #include <termios.h> @@}
{@@ #include <sys/select.h> @@}


  Const
    Black = 0; Blue = 1; Green = 2; Cyan = 3; Red = 4; Magenta = 5;
    Brown = 6; LightGray = 7; DarkGray = 8; LightBlue = 9;
    LightGreen = 10; LightCyan = 11; LightRed = 12; LightMagenta = 13;
    Yellow = 14; White = 15; Blink = 128;

  type
     byte   = 0..255;

  Var
     CheckBreak, Blinking   : Boolean;
     ForeColour, BackColour : Byte;


  {Note:
     In pascal (and C), console i/o is line buffered.
     This means you can't read a character until the return key
     is pressed.
     The keyPressed and ReadKey functions below use low level trickery to
     get round this.
  }

  { Replacement for CRT.KeyPressed
    Detects whether a key is pressed
    Does nothing with the key
    Returns true if key is pressed
    Otherwise, false
    Key remains in kbd buffer}
Function KeyPressed : boolean;

  Begin

      KeyPressed := true; {dummy asign to prevent compile error}


/**
 (POSIX) implementation of _kbhit().
 Morgan McGuire, morgan@cs.brown.edu

eg see http://www.flipcode.com/archives/_kbhit_for_Linux.shtml

see also
http://www.linuxquestions.org/questions/programming-9/differences-between-ncurses-library-and-termios-struct-w-r-t-keyboard-reading-805611/#post3956458

 */
{@@ {}

    bool r;
    struct termios term, orig;

    // Use termios to turn off line buffering
    tcgetattr(STDIN_FILENO, &orig);
    term = orig;
    term.c_lflag &= ~ICANON & ~ECHO;
    tcsetattr(STDIN_FILENO, TCSANOW, &term);
    //setbuf(stdin, NULL);

    struct timeval timeout;
    timeout.tv_sec  = 0;
    timeout.tv_usec = 0;

    fd_set rdset;
    FD_ZERO(&rdset);
    FD_SET(STDIN_FILENO, &rdset);
    select(STDIN_FILENO + 1, &rdset, NULL, NULL, &timeout);
    r = FD_ISSET(STDIN_FILENO, &rdset);
    tcsetattr(STDIN_FILENO, TCSANOW, &orig);
    return r;
@@}

  end; { KeyPressed }

  Function ReadKey : char;  { Replacement for CRT.ReadKey }
                            { Just like ReadKey in CRT unit}
  var chrout: char;
    Begin

      {Char input w/o echo}
      If CheckBreak and (chrout = chr(3)) then  {If it's a ^C and CheckBreak}
        Begin                             {then execute Ctrl_Brk}
        end;

{@@ {}
   int            ch;
   struct termios old;
   struct termios tmp;

   tcgetattr(STDIN_FILENO, &old);
   tmp = old;
   tmp.c_lflag &= ~ICANON & ~ECHO;
   tcsetattr(STDIN_FILENO, TCSANOW, (const struct termios*) &tmp);
   ch = getchar();
   tcsetattr(STDIN_FILENO, TCSANOW, (const struct termios*) &old);

  return ch;
@@}

       ReadKey := ' ';      {unused code}
  end; {ReadKey()}


{@@

static void __attribute__((constructor)) ansiSetup(void) {

  CheckBreak_1 = 1;
  BackColour_1 = 0;
  ForeColour_1 = 7;
  Blinking_1 = 0;

  puts("\e[5n");
  if( !(   ReadKey_1() == '\e'
        && ReadKey_1() == '['
        && ReadKey_1() == '0'
        && ReadKey_1() == 'n' )
    ) {
        printf( "\r\tANSI console not found, quitting.\n" );
        exit(1);
      }

} /* ansiSetup() */

@@}

  Procedure  ClrEol;     { ANSI replacement for CRT.ClrEol }
    Begin
      Write(chr(27), '[K');
    end;

  Procedure ClrScr;     { ANSI replacement for CRT.ClrScr }
    Begin
      Write(chr(27), '[2J');
    end;

  Function WhereX : byte;       { ANSI replacement for CRT.WhereX }
    var                         { Cursor position report. }
      ch  : char;               { This is column or X axis report.}
      xPos,yPos   : byte;

    begin
       Write(chr(27), '[6n');    { Ansi string to get X-Y position }
       ch := readkey;                 { Return will be }
                                 { Esc - [ - Ypos - ; - Xpos - R }
       xPos := 0;
       if ch = chr(27) then begin
          ch := readkey;
          if ch = '[' then begin
             read(yPos);
             ch := readkey;
             if ch = ';' then begin
                read(xPos);
                ch := readkey;
                {if ch = 'R' then
                   writeln('ansi terminal, cursor is at (',
                        xPos:1, ',', yPos:1, ')');}
             end;
          end;
       end;

       WhereX := xPos;            { Return the number }
    end;

  Function WhereY : byte;       { ANSI replacement for CRT.WhereY }
    var                         { Cursor position report. }
      ch  : char;               { This is row or Y axis report.}
      xPos,yPos   : byte;

    begin

       Write(chr(27), '[6n');    { Ansi string to get X-Y position }
       ch := readkey;                 { Return will be }
                                 { Esc - [ - Ypos - ; - Xpos - R }
       yPos := 0;
       if ch = chr(27) then begin
          ch := readkey;
          if ch = '[' then begin
             read(yPos);
             ch := readkey;
             if ch = ';' then begin
                read(xPos);
                ch := readkey;
                {if ch = 'R' then
                   writeln('ansi terminal, cursor is at (',
                        xPos:1, ',', yPos:1, ')');}
             end;
          end;
       end;

        WhereY := yPos;            { Return the number }
    end;


    Procedure GotoXY(x : byte ; y : byte); { ANSI replacement for CRT.GoToXY}
      Begin
        If (x >= 1) and (y >= 1) {and
           (x <= 80) and (y <= 25)} then
        Write(chr(27), '[',y,';',x,'H');
      end;

   Procedure TextBackGround(Back : Byte);{Replacement for CRT.TextBackground}
     Begin
       If Back <= 7 then begin     { No illegal values allowed }
          BackColour := Back;
          Case Back of
            0  :  Write(chr(27), '[40m');
            1  :  Write(chr(27), '[44m');
            2  :  Write(chr(27), '[42m');
            3  :  Write(chr(27), '[46m');
            4  :  Write(chr(27), '[41m');
            5  :  Write(chr(27), '[45m');
            6  :  Write(chr(27), '[43m');
            7  :  Write(chr(27), '[47m');
          end;  { Case }
       end;
     end;


   Procedure TextColor(Fore : Byte);
   label 9;
     Begin
       If not ((Fore in [0..15]) or (Fore in [128..143])) then goto 9;
       ForeColour := Fore;
       Blinking := False;
       Write(chr(27), '[0m');
       TextBackGround(BackColour);
       If Fore >  127 then begin
          If Fore >= 128 then Fore := Fore - 128;
          Blinking := True;
          Write(chr(27), '[5m');
       end;
       Case Fore of
         0  :  Write(chr(27), '[30m');
         1  :  Write(chr(27), '[34m');
         2  :  Write(chr(27), '[32m');
         3  :  Write(chr(27), '[36m');
         4  :  Write(chr(27), '[31m');
         5  :  Write(chr(27), '[35m');
         6  :  Write(chr(27), '[33m');
         7  :  Write(chr(27), '[37m');
         8  :  Write(chr(27), '[1;30m');
         9  :  Write(chr(27), '[1;34m');
         10  :  Write(chr(27), '[1;32m');
         11  :  Write(chr(27), '[1;36m');
         12  :  Write(chr(27), '[1;31m');
         13  :  Write(chr(27), '[1;35m');
         14  :  Write(chr(27), '[1;33m');
         15  :  Write(chr(27), '[1;37m');
         otherwise
           writeln('unhandled value of fore(', fore:1, ')' );
       end;  { Case }
9:
     end;


   Procedure NormVideo;   { ANSI Replacement for CRT.NormVideo }
     Begin
       Write(chr(27), '[0m');
       ForeColour := LightGray;
       BackColour := Black;
     end;

   Procedure LowVideo;    { Replacement for CRT.LowVideo }
     Begin
       If ForeColour > 7 then ForeColour := ForeColour - 8;
       Write(chr(27), '[0m');
       TextBackGround(BackColour);
       If not Blinking then TextColor(ForeColour)
          else TextColor(ForeColour + 128);
     end;

   Procedure HighVideo;   { Replacement for CRT.HighVideo }
     Begin
       If ForeColour < 8 then ForeColour := ForeColour + 8;
       If Not Blinking then TextColor(ForeColour)
           else TextColor(ForeColour + 128);
     end;



{%%%%%%%%%%%%%%%%%%%%%%%%% end of console.inc.pas %%%%%%%%%%%%%%%%%%%%%%%%%%%%%}
