Browse Source

+ new files from Gabor

pierre 25 years ago
parent
commit
d2fd96beb1
2 changed files with 1741 additions and 0 deletions
  1. 728 0
      ide/text/pmode.pas
  2. 1013 0
      ide/text/wansi.pas

+ 728 - 0
ide/text/pmode.pas

@@ -0,0 +1,728 @@
+{
+    $Id$
+    This file is part of the Free Sockets Interface
+    Copyright (c) 1999 by Berczi Gabor
+
+    Support routines for DPMI programs
+
+    See the file COPYING.FCL, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+{$ifdef VER70}{$define TP}{$endif}
+unit PMode;
+
+interface
+
+uses Dos;
+
+type
+    MemPtr = object
+      Ofs,Seg: word;
+      Size   : word;
+    {$ifdef DPMI}
+      Sel    : word;
+    {$endif}
+      function  DosPtr: pointer;
+      function  DataPtr: pointer;
+      function  DosSeg: word;
+      function  DosOfs: word;
+      procedure MoveDataTo(const Src; DSize: word);
+      procedure MoveDataFrom(DSize: word; var Dest);
+      procedure Clear;
+    private
+      function DataSeg: word;
+      function DataOfs: word;
+    end;
+
+    PtrRec = packed record
+      Ofs,Seg: word;
+    end;
+
+    registers32 = packed record     { DPMI call structure }
+      EDI     : LongInt;
+      ESI     : LongInt;
+      EBP     : LongInt;
+      Reserved: LongInt;
+      EBX     : LongInt;
+      EDX     : LongInt;
+      ECX     : LongInt;
+      EAX     : LongInt;
+      Flags   : Word;
+      ES      : Word;
+      DS      : Word;
+      FS      : Word;
+      GS      : Word;
+      IP      : Word;
+      CS      : Word;
+      SP      : Word;
+      SS      : Word;
+    end;
+
+    pregisters = ^registers;
+
+function  GetDosMem(var M: MemPtr; Size: word): boolean;
+procedure FreeDosMem(var M: MemPtr);
+procedure realintr(IntNo: byte; var r: registers);
+{procedure realintr32(IntNo: byte; var r: registers32);}
+procedure realcall(Proc: pointer; var r: registers);
+function  MoveDosToPM(DosPtr: pointer; PMPtr: pointer; Size: word): boolean;
+function  MovePMToDos(PMPtr: pointer; DosPtr: pointer; Size: word): boolean;
+procedure realGetIntVec(IntNo: byte; var P: pointer);
+function  allocrmcallback(PMAddr: pointer; RealRegs: pregisters): pointer;
+procedure freermcallback(RealCallAddr: pointer);
+
+function MakePtr(ASeg,AOfs: word): pointer;
+
+implementation
+
+{$ifdef TP}
+{$ifdef DPMI}uses WinAPI;{$endif}
+
+{$IFDEF DPMI}
+const
+    DPMI_INTR      = $31;
+
+type
+    TDPMIRegisters = {$ifdef TP}Registers32{$else}TRegisters32{$endif};
+
+  var
+    DPMIRegs: TDPMIRegisters;
+{$ENDIF DPMI}
+
+procedure realintr(IntNo: byte; var r: registers);
+{$ifdef DPMI}
+var Regs: Registers;
+begin
+  FillChar(DPMIRegs, SizeOf(TDPMIRegisters), 0);
+  DPMIRegs.EAX := r.ax;
+  DPMIRegs.EBX := r.bx;
+  DPMIRegs.ECX := r.cx;
+  DPMIRegs.EDX := r.dx;
+  DPMIRegs.EDI := r.di;
+  DPMIRegs.ESI := r.si;
+  DPMIRegs.EBP := r.bp;
+  DPMIRegs.DS := r.ds;
+  DPMIRegs.ES := r.es;
+  DPMIRegs.Flags := r.flags;
+  Regs.AX := $0300;
+  Regs.BL := IntNo;
+  Regs.BH := 0;
+  Regs.CX := 0;
+  Regs.ES := Seg(DPMIRegs);
+  Regs.DI := Ofs(DPMIRegs);
+  Intr(DPMI_INTR, Regs);
+  r.ax := DPMIRegs.EAX;
+  r.bx := DPMIRegs.EBX;
+  r.cx := DPMIRegs.ECX;
+  r.dx := DPMIRegs.EDX;
+  r.di := DPMIRegs.EDI;
+  r.si := DPMIRegs.ESI;
+  r.bp := DPMIRegs.EBP;
+  r.ds := DPMIRegs.DS;
+  r.es := DPMIRegs.ES;
+  r.Flags := DPMIRegs.Flags;
+end;
+{$else}
+begin
+  intr(IntNo,r);
+end;
+{$endif}
+
+(*procedure realintr32(IntNo: byte; var r: registers32);
+{$ifdef DPMI}
+var Regs: Registers;
+begin
+  FillChar(DPMIRegs, SizeOf(TDPMIRegisters), 0);
+  DPMIRegs:=r;
+
+  Regs.AX := $0300;
+  Regs.BL := IntNo;
+  Regs.BH := 0;
+  Regs.CX := 0;
+  Regs.ES := Seg(DPMIRegs);
+  Regs.DI := Ofs(DPMIRegs);
+  Intr(DPMI_INTR, Regs);
+  r:=DPMIRegs;
+end;
+{$else}
+begin
+  { not implemented }
+  Halt(99);
+end;
+{$endif}
+*)
+
+{$ifndef DPMI}
+const DummyIntRedir: boolean = false;
+      CallAddr: pointer = nil;
+      DummyInt = $ef;
+procedure CallInt; assembler;
+asm
+  push  ax
+  push  ds
+
+  mov   ax, seg CallAddr
+  mov   ds, ax
+  mov   ax, ds:CallAddr.word[0]
+  mov   cs:@JmpAddr.word[0], ax
+  mov   ax, ds:CallAddr.word[2]
+  mov   cs:@JmpAddr.word[2], ax
+
+  pop   ds
+  pop   ax
+
+  sti
+
+  db    $9a
+@JmpAddr:
+  dw    0,0
+  jmp   @over
+@regax: dw  0
+@over:
+  mov  word ptr cs:@regax, ax
+  push bx
+  pushf
+  pop  ax
+  mov  bx, sp
+  mov  word ptr ss:[bx+6], ax
+  pop  bx
+  mov  ax, word ptr cs:@regax
+
+  iret
+end;
+{$endif}
+
+procedure realcall(Proc: pointer; var r: registers);
+{$ifdef DPMI}
+var Regs: Registers;
+begin
+  FillChar(DPMIRegs, SizeOf(TDPMIRegisters), 0);
+  DPMIRegs.EAX := r.ax;
+  DPMIRegs.EBX := r.bx;
+  DPMIRegs.ECX := r.cx;
+  DPMIRegs.EDX := r.dx;
+  DPMIRegs.EDI := r.di;
+  DPMIRegs.ESI := r.si;
+  DPMIRegs.EBP := r.bp;
+  DPMIRegs.DS := r.ds;
+  DPMIRegs.ES := r.es;
+  DPMIRegs.Flags := r.flags;
+  DPMIRegs.CS := PtrRec(Proc).Seg;
+  DPMIRegs.IP := PtrRec(Proc).Ofs;
+  DPMIRegs.SS :=0; DPMIRegs.SP:=0;
+  Regs.AX := $0301;
+  Regs.BH := 0;
+  Regs.CX := 0;
+  Regs.ES := Seg(DPMIRegs);
+  Regs.DI := Ofs(DPMIRegs);
+  Intr(DPMI_INTR, Regs);
+  r.ax := DPMIRegs.EAX and $ffff;
+  r.bx := DPMIRegs.EBX and $ffff;
+  r.cx := DPMIRegs.ECX and $ffff;
+  r.dx := DPMIRegs.EDX and $ffff;
+  r.di := DPMIRegs.EDI and $ffff;
+  r.si := DPMIRegs.ESI and $ffff;
+  r.bp := DPMIRegs.EBP and $ffff;
+  r.ds := DPMIRegs.DS;
+  r.es := DPMIRegs.ES;
+  r.Flags := DPMIRegs.Flags and $ffff;
+end;
+{$else}
+(*begin
+  asm
+    push ds
+    push bp
+
+    mov  ax, Proc.word[2]
+    mov  bx, Proc.word[0]
+    mov  cs:@Call+1.word, bx
+    mov  cs:@Call+3.word, ax
+
+    lds  si, r
+    mov  @rptr.word[2], ds
+    mov  @rptr.word[0], si
+
+    lodsw
+    push ax { -> ax }
+    lodsw
+    mov  bx, ax
+    lodsw
+    mov  cx, ax
+    lodsw
+    mov  dx, ax
+    lodsw
+    mov  bp, ax
+    lodsw
+    push ax { -> si }
+    lodsw
+    mov  di, ax
+    lodsw
+    push ax { -> ds }
+    lodsw
+    mov  es, ax
+    lodsw
+    push ax { -> flags }
+    popf
+
+    pop  si
+    pop  ds
+    pop  ax
+
+@Call:
+    db   9ah
+    dd   0
+
+    jmp  @skipover
+@rptr: dd  0
+@skipover:
+
+    pushf
+    push es
+    push di
+
+    mov  es, @rptr.word[2]
+    mov  di, @rptr.word[0]
+    stosw
+    mov  ax, bx
+    stosw
+    mov  ax, cx
+    stosw
+    mov  ax, dx
+    stosw
+    mov  ax, bp
+    stosw
+    mov  ax, si
+    stosw
+    pop  ax { <- di }
+    stosw
+    mov  ax, ds
+    stosw
+    pop  ax { <- es }
+    stosw
+    pop  ax { <- flags }
+    stosw
+
+    pop  bp
+    pop  ds
+  end;
+end;
+*)
+begin
+  if DummyIntRedir=false then
+    begin
+      SetIntVec(DummyInt,@CallInt);
+      DummyIntRedir:=true;
+    end;
+  CallAddr:=Proc;
+  dos.intr(DummyInt,r);
+end;
+
+{$endif}
+
+(*const ActiveBlocks: word = 0;*)
+
+function GetDosMem(var M: MemPtr; Size: word): boolean;
+var P: pointer;
+    L: longint;
+begin
+  M.Size:=Size;
+{$ifndef DPMI}
+  GetMem(P,Size);
+  M.Seg:=PtrRec(P).Seg; M.Ofs:=PtrRec(P).Ofs;
+{$else}
+  L:=GlobalDosAlloc(Size);
+  M.Seg:=(L shr 16); M.Ofs:=0;
+  M.Sel:=(L and $ffff);
+{$endif}
+  if M.Seg<>0 then M.Clear;
+  GetDosMem:=M.Seg<>0;
+(*  Inc(ActiveBlocks);
+  write('|DMC:',ActiveBlocks,'-S:',M.Sel,'-S:',M.Seg);*)
+end;
+
+procedure FreeDosMem(var M: MemPtr);
+begin
+  if M.Size=0 then Exit;
+{$ifndef DPMI}
+  if M.Seg<>0 then
+  FreeMem(Ptr(M.Seg,M.Ofs),M.Size);
+{$else}
+  if M.Sel<>0 then
+   if GlobalDosFree(M.Sel)<>0 then
+    writeln('!!!Failed to deallocate Dos block!!!');
+{$endif}
+
+  FillChar(M,SizeOf(M),0);
+end;
+
+{$ifdef DPMI}
+function GetSelectorForSeg(Seg: word): word;
+var Sel: word;
+    r: registers;
+begin
+  r.ax:=$0002; r.bx:=Seg;
+  intr(DPMI_Intr,r);
+  if (r.flags and fCarry)=0 then
+    Sel:=r.ax
+  else
+    Sel:=0;
+  GetSelectorForSeg:=Sel;
+end;
+{$endif}
+
+function MoveDosToPM(DosPtr: pointer; PMPtr: pointer; Size: word): boolean;
+{$ifndef DPMI}
+begin
+  Move(DosPtr^,PMPtr^,Size);
+  MoveDosToPM:=true;
+end;
+{$else}
+var Sel: word;
+    OK,DisposeSel: boolean;
+begin
+  Sel:=GetSelectorForSeg(PtrRec(DosPtr).Seg);
+  OK:=Sel<>0; DisposeSel:=false;
+  if OK=false then
+    begin
+      Sel:=AllocSelector(0);
+      OK:=Sel<>0;
+      if OK then
+        begin
+          SetSelectorLimit(Sel,PtrRec(DosPtr).Ofs+Size);
+          OK:=SetSelectorBase(Sel,PtrRec(DosPtr).Seg shl 4)=Sel;
+        end;
+      if OK then DisposeSel:=true;
+    end;
+  if OK then
+    begin
+      Move(ptr(Sel,PtrRec(DosPtr).Ofs)^,PMPtr^,Size);
+      if DisposeSel then FreeSelector(Sel);
+    end;
+  MoveDosToPM:=OK;
+end;
+{$endif}
+
+function MovePMToDos(PMPtr: pointer; DosPtr: pointer; Size: word): boolean;
+{$ifndef DPMI}
+begin
+  Move(PMPtr^,DosPtr^,Size);
+  MovePMToDos:=true;
+end;
+{$else}
+var Sel: word;
+    OK,DisposeSel: boolean;
+begin
+  Sel:=GetSelectorForSeg(PtrRec(DosPtr).Seg);
+  OK:=Sel<>0; DisposeSel:=false;
+  if OK=false then
+    begin
+      Sel:=AllocSelector(0);
+      OK:=Sel<>0;
+      if OK then
+        begin
+          SetSelectorLimit(Sel,PtrRec(DosPtr).Ofs+Size);
+          OK:=SetSelectorBase(Sel,PtrRec(DosPtr).Seg shl 4)=Sel;
+        end;
+      if OK then DisposeSel:=true;
+    end;
+  if OK then
+    begin
+      Move(PMPtr^,ptr(Sel,PtrRec(DosPtr).Ofs)^,Size);
+      if DisposeSel then FreeSelector(Sel);
+    end;
+  MovePMToDos:=OK;
+end;
+{$endif}
+
+procedure realGetIntVec(IntNo: byte; var P: pointer);
+{$ifndef DPMI}
+begin
+  GetIntVec(IntNo,P);
+end;
+{$else}
+var r: registers;
+begin
+  r.ax:=$200; r.bl:=IntNo;
+  intr(DPMI_Intr,r);
+  P:=Ptr(r.cx,r.dx);
+end;
+{$endif}
+
+procedure MemPtr.MoveDataTo(const Src; DSize: word);
+begin
+  if DSize>Size then
+    RunError(216);
+  Move(Src,Ptr(DataSeg,DataOfs)^,DSize);
+end;
+
+procedure MemPtr.MoveDataFrom(DSize: word; var Dest);
+begin
+  if DSize>Size then
+    RunError(216);
+  Move(Ptr(DataSeg,DataOfs)^,Dest,DSize);
+end;
+
+procedure MemPtr.Clear;
+begin
+  FillChar(Ptr(DataSeg,DataOfs)^,Size,0);
+end;
+
+procedure RealAbstract;
+begin
+  writeln('Abstract call in real mode...');
+  RunError(255);
+end;
+
+function  allocrmcallback(PMAddr: pointer; RealRegs: pregisters): pointer;
+{$ifdef DPMI}
+var r: registers;
+    P: pointer;
+begin
+  r.ax:=$0303;
+  r.ds:=PtrRec(PMAddr).Seg; r.si:=PtrRec(PMAddr).Ofs;
+  r.es:=PtrRec(RealRegs).Seg; r.di:=PtrRec(RealRegs).Ofs;
+  intr(DPMI_Intr,r);
+  if (r.flags and fCarry)=0 then
+    P:=MakePtr(r.cx,r.dx)
+  else
+    P:=nil;
+  allocrmcallback:=P;
+end;
+{$else}
+begin
+  RealAbstract;
+end;
+{$endif}
+
+procedure freermcallback(RealCallAddr: pointer);
+{$ifdef DPMI}
+var r: registers;
+begin
+  r.ax:=$0304;
+  r.cx:=PtrRec(RealCallAddr).Seg; r.dx:=PtrRec(RealCallAddr).Seg;
+  intr(DPMI_Intr,r);
+end;
+{$else}
+begin
+  RealAbstract;
+end;
+{$endif}
+
+{$endif TP}
+
+{$ifdef GO32V2}
+
+{ --------------------- GO32 --------------------- }
+
+uses go32;
+
+function  GetDosMem(var M: MemPtr; Size: word): boolean;
+var L: longint;
+begin
+  M.Size:=Size;
+  L:=global_dos_alloc(Size);
+  M.Seg:=(L shr 16); M.Ofs:=0;
+  M.Sel:=(L and $ffff);
+  GetDosMem:=M.Seg<>0;
+end;
+
+procedure FreeDosMem(var M: MemPtr);
+begin
+  if M.Size=0 then Exit;
+  if M.Sel<>0 then
+  if global_dos_free(M.Sel)=false then
+    writeln('!!!Failed to deallocate Dos block!!!');
+  FillChar(M,SizeOf(M),0);
+end;
+
+procedure realintr(IntNo: byte; var r: registers);
+var rr: trealregs;
+begin
+  rr.realeax:=r.ax;
+  rr.realebx:=r.bx;
+  rr.realecx:=r.cx;
+  rr.realedx:=r.dx;
+  rr.realesi:=r.si;
+  rr.realedi:=r.di;
+  rr.reales:=r.es;
+  rr.realds:=r.ds;
+  go32.realintr(IntNo,rr);
+  r.ax:=rr.realeax and $ffff;
+  r.bx:=rr.realebx and $ffff;
+  r.cx:=rr.realecx and $ffff;
+  r.dx:=rr.realedx and $ffff;
+  r.si:=rr.realesi and $ffff;
+  r.di:=rr.realedi and $ffff;
+  r.es:=rr.reales and $ffff;
+  r.ds:=rr.realds and $ffff;
+end;
+
+function dorealcall(var regs : trealregs) : boolean;
+begin
+  regs.realsp:=0;
+  regs.realss:=0;
+  asm
+    movw  $0x0,%bx
+    xorl  %ecx,%ecx
+    movl  regs,%edi
+    { es is always equal ds }
+    movl  $0x301,%eax
+    int   $0x31
+    setnc %al
+    movb  %al,__RESULT
+  end;
+end;
+
+
+procedure realcall(Proc: pointer; var r: registers);
+var rr: trealregs;
+const DPMI_INTR = $31;
+begin
+  rr.realeax:=r.ax;
+  rr.realebx:=r.bx;
+  rr.realecx:=r.cx;
+  rr.realedx:=r.dx;
+  rr.realesi:=r.si;
+  rr.realedi:=r.di;
+  rr.reales:=r.es;
+  rr.realds:=r.ds;
+  rr.flags:=r.flags;
+  rr.CS:=PtrRec(Proc).Seg;
+  rr.IP:=PtrRec(Proc).Ofs;
+
+  rr.realss:=0; rr.realsp:=0;
+
+  dorealcall(rr);
+
+  r.ax:=rr.realeax and $ffff;
+  r.bx:=rr.realebx and $ffff;
+  r.cx:=rr.realecx and $ffff;
+  r.dx:=rr.realedx and $ffff;
+  r.si:=rr.realesi and $ffff;
+  r.di:=rr.realedi and $ffff;
+  r.es:=rr.reales and $ffff;
+  r.ds:=rr.realds and $ffff;
+  r.flags:=rr.Flags and $ffff;
+end;
+
+function MoveDosToPM(DosPtr: pointer; PMPtr: pointer; Size: word): boolean;
+begin
+  dosmemget(PtrRec(DosPtr).Seg,PtrRec(DosPtr).Ofs,PMPtr^,Size);
+  MoveDosToPM:=true;
+end;
+
+function MovePMToDos(PMPtr, DosPtr: pointer; Size: word): boolean;
+begin
+  dosmemput(PtrRec(DosPtr).Seg,PtrRec(DosPtr).Ofs,PMPtr^,Size);
+  MovePMToDos:=true;
+end;
+
+procedure realGetIntVec(IntNo: byte; var P: pointer);
+var si: tseginfo;
+begin
+  get_rm_interrupt(IntNo,si);
+  PtrRec(P).Seg:=si.segment; PtrRec(P).Ofs:=longint(si.offset);
+end;
+
+procedure MemPtr.MoveDataTo(const Src; DSize: word);
+begin
+  dpmi_dosmemput(DosSeg,DosOfs,Src,DSize);
+end;
+
+procedure MemPtr.MoveDataFrom(DSize: word; var Dest);
+begin
+  dpmi_dosmemget(DosSeg,DosOfs,Dest,DSize);
+end;
+
+procedure MemPtr.Clear;
+begin
+  dpmi_dosmemfillchar(DosSeg,DosOfs,Size,#0);
+end;
+
+
+function  allocrmcallback(PMAddr: pointer; RealRegs: pregisters): pointer;
+var s: tseginfo;
+    P: pointer;
+begin
+  if get_rm_callback(PMAddr,RealRegs^,s) then
+    P:=MakePtr(s.segment,longint(s.offset))
+  else  
+    P:=nil;
+  allocrmcallback:=P;
+end;
+
+procedure freermcallback(RealCallAddr: pointer);
+var s: tseginfo;
+begin
+  s.segment:=PtrRec(RealCallAddr).seg; s.offset:=ptr(0,PtrRec(RealCallAddr).ofs);
+  free_rm_callback(s);
+end;
+
+{$endif GO32V2}
+
+{ ---------------------- COMMON ---------------------- }
+
+function MemPtr.DosPtr: pointer;
+begin
+  DosPtr:=MakePtr(Seg,Ofs);
+end;
+
+function MemPtr.DataPtr: pointer;
+begin
+  DataPtr:=MakePtr(DataSeg,DataOfs);
+end;
+
+function MemPtr.DataSeg: word;
+begin
+{$ifndef DPMI}
+  DataSeg:=Seg;
+{$else}
+  DataSeg:=Sel;
+{$endif}
+end;
+
+function MemPtr.DataOfs: word;
+begin
+{$ifndef DPMI}
+  DataOfs:=Ofs;
+{$else}
+  DataOfs:=0;
+{$endif}
+end;
+
+function MemPtr.DosSeg: word;
+begin
+  DosSeg:=Seg;
+end;
+
+function MemPtr.DosOfs: word;
+begin
+  DosOfs:=Ofs;
+end;
+
+function MakePtr(ASeg, AOfs: word): pointer;
+var P: pointer;
+begin
+  with PtrRec(P) do
+  begin
+    Seg:=ASeg; Ofs:=AOfs;
+  end;
+  MakePtr:=P;
+end;
+
+END.
+{
+  $Log$
+  Revision 1.1  2000-04-20 08:47:39  pierre
+   + new files from Gabor
+
+
+  Revision 1.0  1999/07/07 09:46:55  gabor
+     Original implementation
+
+}

+ 1013 - 0
ide/text/wansi.pas

@@ -0,0 +1,1013 @@
+{
+    $Id$
+    This file is part of the Free Pascal Integrated Development Environment
+    Copyright (c) 1996-2000 by Berczi Gabor
+
+    ANSI support
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+{.$DEFINE DEBUG}
+unit WANSI;
+
+interface
+
+uses Objects,Drivers,Crt,Dos,Views,App;
+
+const
+      ANSIMaxParamLen     = 30; { max ANSI escape sequence length }
+      ANSICurPosStackSize = 20; { max number of cursor positions stored at the same time }
+
+      Esc = #27;
+
+      MaxVideoLine = 65520 div (2*MaxViewWidth); { maximum number of lines that fit in 64K }
+
+      { BoundCheck constants }
+      bc_MinX    = 1;
+      bc_MinY    = 2;
+      bc_MaxX    = 4;
+      bc_MaxY    = 8;
+      bc_X       = bc_MinX or bc_MaxX;
+      bc_Y       = bc_MinY or bc_MaxY;
+      bc_Min     = bc_MinX or bc_MinY;
+      bc_Max     = bc_MaxX or bc_MaxY;
+      bc_All     = bc_X or bc_Y;
+
+type
+     TANSIParam = string[ANSIMaxParamLen];
+
+     PHookProc = ^THookProc;
+     THookProc = procedure (S: string);
+
+     PConsoleObject = ^TConsoleObject;
+     TConsoleObject = object(TObject)
+       CurPos   : TPoint;
+       Size     : TPoint;
+       TextAttr : byte;
+       BoldOn   : boolean;
+       BlinkOn  : boolean;
+       BoundChecks: byte;
+       LineWrapping: boolean;
+       ReplyHook   : PHookProc;
+       KeyHook     : PHookProc;
+       WriteHook   : PHookProc;
+       constructor Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
+       procedure   Home; virtual;
+       procedure   ClrScr; virtual;
+       procedure   FillScreen(B: byte); virtual;
+       procedure   ClrEol; virtual;
+       procedure   GotoXY(X,Y: integer); virtual;
+       procedure   Write(S: string); virtual;
+       procedure   WriteLn(S: string); virtual;
+       procedure   WriteChar(C: char); virtual;
+       procedure   DelLine(LineCount: integer); virtual;
+       procedure   InsLine(LineCount: integer); virtual;
+       procedure   HighVideo; virtual;
+       procedure   BlinkVideo; virtual;
+       procedure   NoBlinkVideo; virtual;
+       procedure   NormVideo; virtual;
+       procedure   LowVideo; virtual;
+       procedure   TextBackground(Color: byte); virtual;
+       procedure   TextColor(Color: byte); virtual;
+       function    WhereX: integer; virtual;
+       function    WhereY: integer; virtual;
+       procedure   CursorOn; virtual;
+       procedure   CursorOff; virtual;
+       procedure   UpdateCursor; virtual;
+       { --- Hook procedures --- }
+       procedure   Reply(S: string); virtual;
+       procedure   PutKey(S: string); virtual;
+       destructor  Done; virtual;
+       private
+       procedure   ProcessChar(C: char); virtual;
+     end;
+
+     PANSIConsole = ^TANSIConsole;
+     TANSIConsole = object(TConsoleObject)
+       ANSIParam          : TANSIParam;
+       ANSILevel          : byte;
+       ANSICurPosStack    : array[1..ANSICurPosStackSize] of TPoint;
+       ANSICurPosStackPtr : byte;
+       constructor Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
+       procedure   ProcessChar(C: char); virtual;
+       function    GetANSIParam: integer; virtual;
+       { --- ANSI functions --- }
+       procedure   PushCurPos; virtual;
+       procedure   PopCurPos; virtual;
+       procedure   CursorUp(LineCount: integer); virtual;
+       procedure   CursorDown(LineCount: integer); virtual;
+       procedure   CursorForward(CharCount: integer); virtual;
+       procedure   CursorBack(CharCount: integer); virtual;
+       procedure   SetAttr(Color: integer); virtual;
+     end;
+
+     PCrtConsole = ^TCrtConsole;
+     TCrtConsole = object(TANSIConsole)
+       constructor Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
+       procedure   CursorOn; virtual;
+       procedure   CursorOff; virtual;
+       procedure   ClrScr; virtual;
+       procedure   ClrEol; virtual;
+       procedure   WriteChar(C: char); virtual;
+       procedure   DelLine(LineCount: integer); virtual;
+       procedure   InsLine(LineCount: integer); virtual;
+       procedure   UpdateCursor; virtual;
+       procedure   TextBackground(Color: byte); virtual;
+       procedure   TextColor(Color: byte); virtual;
+     end;
+
+     PANSIView = ^TANSIView;
+
+     PANSIViewConsole = ^TANSIViewConsole;
+     TANSIViewConsole = object(TANSIConsole)
+       Owner : PANSIView;
+       constructor Init(AOwner: PANSIView);
+       procedure   CursorOn; virtual;
+       procedure   CursorOff; virtual;
+       procedure   ClrScr; virtual;
+       procedure   ClrEol; virtual;
+       procedure   WriteChar(C: char); virtual;
+       procedure   DelLine(LineCount: integer); virtual;
+       procedure   InsLine(LineCount: integer); virtual;
+       procedure   UpdateCursor; virtual;
+       procedure   GotoXY(X,Y: integer); virtual;
+     end;
+
+     TVideoBuf = array[0..MaxViewWidth*MaxVideoLine] of word;
+
+     TANSIView = object(TScroller)
+       Console : PANSIViewConsole;
+       Buffer  : TVideoBuf;
+       LockCount : word;
+       constructor Init(var Bounds: TRect; AHScrollBar, AVScrollBar:PScrollBar);
+       function    LoadFile(const FileName: string): boolean;
+       procedure   Draw; virtual;
+       destructor  Done; virtual;
+       procedure   Write(S: string); virtual;
+       procedure   WriteLn(S: string); virtual;
+       procedure   Lock; virtual;
+       procedure   UnLock; virtual;
+       procedure   ChangeBounds(var Bounds: TRect); virtual;
+       procedure   HandleEvent(var Event: TEvent); virtual;
+       private
+     end;
+
+     PANSIBackground = ^TANSIBackground;
+
+     PANSIBackgroundConsole = ^TANSIBackgroundConsole;
+     TANSIBackgroundConsole = object(TANSIConsole)
+       Owner : PANSIBackground;
+       constructor Init(AOwner: PANSIBackground);
+       procedure   CursorOn; virtual;
+       procedure   CursorOff; virtual;
+       procedure   ClrScr; virtual;
+       procedure   ClrEol; virtual;
+       procedure   WriteChar(C: char); virtual;
+       procedure   DelLine(LineCount: integer); virtual;
+       procedure   InsLine(LineCount: integer); virtual;
+       procedure   UpdateCursor; virtual;
+       procedure   GotoXY(X,Y: integer); virtual;
+     end;
+
+     TANSIBackground = object(TBackground)
+       Console : PANSIBackgroundConsole;
+       Buffer  : TVideoBuf;
+       LockCount : word;
+       constructor Init(var Bounds: TRect);
+       function    LoadFile(const FileName: string): boolean;
+       procedure   Draw; virtual;
+       destructor  Done; virtual;
+       procedure   Write(S: string); virtual;
+       procedure   WriteLn(S: string); virtual;
+       procedure   Lock; virtual;
+       procedure   UnLock; virtual;
+       procedure   ChangeBounds(var Bounds: TRect); virtual;
+       procedure   HandleEvent(var Event: TEvent); virtual;
+       private
+     end;
+
+implementation
+
+uses WUtils;
+
+constructor TConsoleObject.Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
+begin
+  inherited Init;
+  ReplyHook:=AReplyHook; KeyHook:=AKeyHook; WriteHook:=AWriteHook;
+  BoundChecks:=bc_All; LineWrapping:=true;
+  TextColor(LightGray); TextBackground(Black);
+  NormVideo;
+  ClrScr;
+end;
+
+procedure TConsoleObject.Home;
+begin
+  GotoXY(1,1);
+end;
+
+procedure TConsoleObject.ClrScr;
+begin
+  Abstract;
+end;
+
+procedure TConsoleObject.FillScreen(B: byte);
+var X,Y: integer;
+    S  : string;
+begin
+  GotoXY(1,1);
+  for Y:=1 to Size.Y do
+      begin
+        S:='';
+        for X:=1 to Size.X do S:=S+chr(B);
+        WriteLn(S);
+      end;
+end;
+
+procedure TConsoleObject.ClrEol;
+begin
+  Abstract;
+end;
+
+procedure TConsoleObject.GotoXY(X,Y: integer);
+begin
+  if (BoundChecks and bc_MinX)<>0 then X:=Max(X,1);
+  if (BoundChecks and bc_MaxX)<>0 then
+     if LineWrapping then while (X>Size.X) and (Size.X<>0)
+                                do begin
+                                     Inc(Y);
+                                     X:=X-Size.X;
+                                   end
+                     else X:=Min(X,Size.X);
+  if (BoundChecks and bc_MinY)<>0 then Y:=Max(Y,1);
+  if (BoundChecks and bc_MaxY)<>0 then Y:=Min(Y,Size.Y);
+  CurPos.X:=X; CurPos.Y:=Y;
+  UpdateCursor;
+end;
+
+procedure TConsoleObject.ProcessChar(C: char);
+begin
+  WriteChar(C);
+end;
+
+procedure TConsoleObject.WriteChar(C: char);
+begin
+  Abstract;
+end;
+
+procedure TConsoleObject.Write(S: string); {assembler;
+asm
+  push   ds
+  lds    si, S
+  lodsb
+  xor    ah, ah
+  mov    cx, ax
+@loop:
+  or     cx, cx
+  je     @exitloop
+  lodsb
+  pop    ds
+  push   ax
+  call   ProcessChar
+  push   ds
+  dec    cx
+  jmp    @loop
+@exitloop:
+  pop    ds
+end;}
+var Len: byte;
+    I  : byte;
+begin
+  Len:=length(S);
+  for I:=1 to Len do ProcessChar(S[I]);
+end;
+
+procedure TConsoleObject.WriteLn(S: string);
+begin
+  Write(S+#10);
+end;
+
+procedure TConsoleObject.DelLine(LineCount: integer);
+begin
+  Abstract;
+end;
+
+procedure TConsoleObject.InsLine(LineCount: integer);
+begin
+  Abstract;
+end;
+
+procedure TConsoleObject.NormVideo;
+begin
+  BoldOn:=false; BlinkOn:=false;
+  TextColor(LightGray);
+  TextBackground(Black);
+end;
+
+procedure TConsoleObject.BlinkVideo;
+begin
+  BlinkOn:=true;
+  TextBackground(TextAttr shr 4);
+end;
+
+procedure TConsoleObject.NoBlinkVideo;
+begin
+  BlinkOn:=false;
+  TextBackground(TextAttr shr 4);
+end;
+
+procedure TConsoleObject.HighVideo;
+begin
+  BoldOn:=true;
+  TextColor(TextAttr);
+end;
+
+procedure TConsoleObject.LowVideo;
+begin
+  BoldOn:=false;
+  TextColor(TextAttr);
+end;
+
+procedure TConsoleObject.TextBackground(Color: byte);
+begin
+  if BlinkOn=false then TextAttr:=TextAttr and $7f;
+  TextAttr:=(TextAttr and $0f) or (Color shl 4) or byte(BlinkOn)*$80;
+end;
+
+procedure TConsoleObject.TextColor(Color: byte);
+begin
+  if BoldOn=false then TextAttr:=TextAttr and not $08;
+  TextAttr:=((TextAttr and $f0) or (Color and $0f) or byte(BoldOn)*$08);
+end;
+
+function TConsoleObject.WhereX: integer;
+begin
+  WhereX:=CurPos.X;
+end;
+
+function TConsoleObject.WhereY: integer;
+begin
+  WhereY:=CurPos.Y;
+end;
+
+procedure TConsoleObject.CursorOn;
+begin
+  Abstract;
+end;
+
+procedure TConsoleObject.CursorOff;
+begin
+  Abstract;
+end;
+
+procedure TConsoleObject.UpdateCursor;
+begin
+  Abstract;
+end;
+
+procedure TConsoleObject.Reply(S: string);
+begin
+  if ReplyHook<>nil then ReplyHook^(S);
+end;
+
+procedure TConsoleObject.PutKey(S: string);
+begin
+  if KeyHook<>nil then KeyHook^(S);
+end;
+
+destructor TConsoleObject.Done;
+begin
+  inherited Done;
+end;
+
+constructor TCrtConsole.Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
+begin
+  inherited Init(AReplyHook, AKeyHook, AWriteHook);
+  Size.X:=Lo(Crt.WindMax); Size.Y:=Hi(Crt.WindMax);
+end;
+
+procedure TCrtConsole.CursorOn;
+begin
+end;
+
+procedure TCrtConsole.CursorOff;
+begin
+end;
+
+procedure TCrtConsole.ClrScr;
+begin
+  Crt.ClrScr;
+  GotoXY(Crt.WhereX,Crt.WhereY);
+end;
+
+procedure TCrtConsole.ClrEol;
+begin
+  Crt.ClrEol;
+  GotoXY(Crt.WhereX,Crt.WhereY);
+end;
+
+procedure TCrtConsole.WriteChar(C: char);
+{var OK: boolean;}
+begin
+{  OK:=((C>=#32) and (WhereX<Size.X)) or (C<#32);
+  if OK then
+  begin}
+  System.Write(C);
+  GotoXY(Crt.WhereX,Crt.WhereY);
+{  end
+  else Inc(CurPos.X);}
+end;
+
+procedure TCrtConsole.DelLine(LineCount: integer);
+var I: integer;
+begin
+  for I:=1 to LineCount do Crt.DelLine;
+end;
+
+procedure TCrtConsole.InsLine(LineCount: integer);
+var I: integer;
+begin
+  for I:=1 to LineCount do Crt.InsLine;
+end;
+
+procedure TCrtConsole.UpdateCursor;
+begin
+  Crt.GotoXY(CurPos.X,CurPos.Y);
+end;
+
+procedure TCrtConsole.TextBackground(Color: byte);
+begin
+  inherited TextBackground(Color);
+  Crt.TextAttr:=TextAttr;
+end;
+
+procedure TCrtConsole.TextColor(Color: byte);
+begin
+  inherited TextColor(Color);
+  Crt.TextAttr:=TextAttr;
+end;
+
+constructor TANSIConsole.Init(AReplyHook, AKeyHook, AWriteHook: PHookProc);
+begin
+  inherited Init(AReplyHook, AKeyHook, AWriteHook);
+  BoundChecks:=bc_MaxX;
+  ANSIParam:=''; ANSILevel:=0; ANSICurPosStackPtr:=0;
+end;
+
+procedure TANSIConsole.ProcessChar(C: char);
+var SkipThis : boolean;
+    ANSIDone : boolean;
+    X,Y,Z    : integer;
+begin
+  SkipThis:=false; 
+  if C=Esc then begin ANSILevel:=1; SkipThis:=true; end else
+  if (ANSILevel=1) then
+     begin
+       ANSILevel:=0;
+       case C of
+            '[' : begin ANSILevel:=2; SkipThis:=true; end;
+       end;
+     end;
+  if SkipThis=false then
+  if (ANSILevel=2)
+     then begin
+            ANSIDone:=true;
+            case C of
+                 'H','f' : if ANSIParam='' then GotoXY(1,1) else
+                           begin
+                             X:=WhereX; Y:=WhereY;
+                             Z:=Pos(';',ANSIParam);
+                             if Z=0
+                                then Y:=GetANSIParam
+                                else if Z=1 then X:=GetANSIParam
+                                            else begin Y:=GetANSIParam; X:=GetANSIParam; end;
+                             GotoXY(X,Y);
+                           end;
+                 'A'     : if ANSIParam='' then CursorUp(1)
+                                           else CursorUp(GetANSIParam);
+                 'B'     : if ANSIParam='' then CursorDown(1)
+                                           else CursorDown(GetANSIParam);
+                 'C'     : if ANSIParam='' then CursorForward(1)
+                                           else CursorForward(GetANSIParam);
+                 'D'     : if ANSIParam='' then CursorBack(1)
+                                           else CursorBack(GetANSIParam);
+                 's'     : if ANSIParam='' then PushCurPos;
+                 'u'     : if ANSIParam='' then PopCurPos;
+                 'J'     : if ANSIParam='2' then begin ANSIParam:=''; ClrScr; end
+                                            else FillScreen(GetANSIParam);
+                 'K'     : if ANSIParam='' then ClrEol;
+                 'L'     : if ANSIParam='' then InsLine(1)
+                                           else InsLine(GetANSIParam);
+                 'M'     : if ANSIParam='' then DelLine(1)
+                                           else DelLine(GetANSIParam);
+                 'm'     : while ANSIParam<>'' do SetAttr(GetANSIParam);
+            else begin ANSIParam:=ANSIParam+C; ANSIDone:=false; end;
+            end;
+            if ANSIDone then
+               begin
+{$IFDEF DEBUG}
+                 if ANSIParam<>'' then RunError(240);
+{$ENDIF}
+                 ANSIParam:=''; ANSILevel:=0;
+               end;
+          end
+     else begin
+            WriteChar(C);
+            if C=#10 then WriteChar(#13);
+          end;
+end;
+
+function TANSIConsole.GetANSIParam: integer;
+var P: byte;
+    I,C: integer;
+begin
+  P:=Pos(';',ANSIParam);
+  if P=0 then P:=length(ANSIParam)+1;
+  Val(copy(ANSIParam,1,P-1),I,C);
+  if C<>0 then I:=0;
+  Delete(ANSIParam,1,P);
+  GetANSIParam:=I;
+end;
+procedure TANSIConsole.CursorUp(LineCount: integer);
+begin
+  GotoXY(WhereX,WhereY-LineCount);
+end;
+
+procedure TANSIConsole.CursorDown(LineCount: integer);
+begin
+  GotoXY(WhereX,WhereY+LineCount);
+end;
+
+procedure TANSIConsole.CursorForward(CharCount: integer);
+var X, Y: integer;
+begin
+  X:=WhereX; Y:=WhereY;
+  X:=X+CharCount;
+  while (X>Size.X) do
+        begin Inc(Y); Dec(X,Size.X); end;
+  GotoXY(X,Y);
+end;
+
+procedure TANSIConsole.CursorBack(CharCount: integer);
+var X, Y: integer;
+begin
+  X:=WhereX; Y:=WhereY;
+  X:=X-CharCount;
+  while (X<1) do begin Dec(Y); Inc(X,Size.X); end;
+  GotoXY(X,Y);
+end;
+
+procedure TANSIConsole.PushCurPos;
+begin
+  if ANSICurPosStackPtr=ANSICurPosStackSize then Exit;
+  Inc(ANSICurPosStackPtr);
+  ANSICurPosStack[ANSICurPosStackPtr].X:=WhereX;
+  ANSICurPosStack[ANSICurPosStackPtr].Y:=WhereY;
+end;
+
+procedure TANSIConsole.PopCurPos;
+begin
+  if ANSICurPosStackPtr=0 then Exit;
+  GotoXY(ANSICurPosStack[ANSICurPosStackPtr].X,ANSICurPosStack[ANSICurPosStackPtr].Y);
+  Dec(ANSICurPosStackPtr);
+end;
+
+procedure TANSIConsole.SetAttr(Color: integer);
+const ColorTab : array[0..7] of byte =
+      (Black,Red,Green,Brown,Blue,Magenta,Cyan,LightGray);
+begin
+  case Color of
+    0      : NormVideo;
+    1      : HighVideo;
+    5      : BlinkVideo;
+    7,27   : TextAttr:=(TextAttr shl 4) or (TextAttr shr 4);
+    8      : TextColor(TextAttr shr 4);
+    21,22  : LowVideo;
+    25     : NoBlinkVideo;
+    30..37 : TextColor(ColorTab[Color-30]);
+    40..47 : TextBackground(ColorTab[Color-40]);
+(*  else {$IFDEF DEBUG}begin system.writeln('Unknown attr : ',Color); Halt; end{$ENDIF};*)
+  end;
+end;
+
+constructor TANSIViewConsole.Init(AOwner: PANSIView);
+begin
+  if AOwner=nil then Fail;
+  inherited Init(nil,nil,nil);
+  Owner:=AOwner;
+  Size:=Owner^.Size;
+end;
+
+procedure TANSIViewConsole.CursorOn;
+begin
+  Owner^.ShowCursor;
+end;
+
+procedure TANSIViewConsole.CursorOff;
+begin
+  Owner^.HideCursor;
+end;
+
+procedure TANSIViewConsole.ClrScr;
+var X,Y: word;
+    Pos: longint;
+begin
+  GotoXY(1,1);
+  if Owner<>nil then
+  for X:=0 to MaxViewWidth-1 do for Y:=0 to Size.Y-1 do
+      begin
+        Pos:=(Owner^.Delta.Y*MaxViewWidth)+X+Y*MaxViewWidth;
+        Owner^.Buffer[Pos]:=32+256*word(TextAttr);
+      end;
+end;
+
+procedure TANSIViewConsole.ClrEol;
+var X,Y: word;
+    Pos: longint;
+begin
+  if Owner<>nil then
+  begin
+    Y:=CurPos.Y;
+    for X:=CurPos.X to MaxViewWidth-1 do
+        begin
+          Pos:=(Owner^.Delta.Y*MaxViewWidth)+X+Y*MaxViewWidth;
+          Owner^.Buffer[Pos]:=32+256*word(TextAttr);
+        end;
+  end;
+end;
+
+procedure TANSIViewConsole.WriteChar(C: char);
+var Pos: longint;
+begin
+  case C of
+       #8 : begin
+              CursorBack(1);
+              Pos:=(CurPos.Y-1)*MaxViewWidth+(WhereX-1);
+              Owner^.Buffer[Pos]:=ord(' ')+256*word(TextAttr);
+            end;
+       #0..#7,#9,
+       #11..#12,
+       #14..#31,
+       #32..#255
+            : begin
+                Pos:=(CurPos.Y-1)*MaxViewWidth+(WhereX-1);
+                Owner^.Buffer[Pos]:=ord(C)+256*word(TextAttr);
+                GotoXY(WhereX+1,WhereY);
+              end;
+       #10  :
+              GotoXY(WhereX,WhereY+1);
+       #13  :
+              GotoXY(1,WhereY);
+  else {$IFDEF DEBUG}RunError(241){$ENDIF};
+  end;
+end;
+
+procedure TANSIViewConsole.DelLine(LineCount: integer);
+begin
+  Abstract;
+end;
+
+procedure TANSIViewConsole.InsLine(LineCount: integer);
+begin
+  Abstract;
+end;
+
+procedure TANSIViewConsole.UpdateCursor;
+begin
+  if Owner<>nil then
+  if Owner^.LockCount=0 then Owner^.SetCursor(WhereX-1,WhereY-1);
+end;
+
+procedure TANSIViewConsole.GotoXY(X,Y: integer);
+var W: word;
+begin
+  if Owner<>nil then
+  while Y>MaxVideoLine do
+  begin
+    Move(Owner^.Buffer[MaxViewWidth],Owner^.Buffer,SizeOf(Owner^.Buffer)-(MaxViewWidth*2));
+    W:=(MaxViewWidth*MaxVideoLine)-1-(MaxViewWidth);
+    FillChar(Owner^.Buffer[W],MaxViewWidth*2,0);
+    Dec(Y);
+  end;
+  inherited GotoXY(X,Y);
+end;
+
+constructor TANSIView.Init(var Bounds: TRect; AHScrollBar, AVScrollBar:
+    PScrollBar);
+begin
+  inherited Init(Bounds,AHScrollBar,AVScrollBar);
+  LockCount:=0; Options:=Options or ofTopSelect;
+  GrowMode:=gfGrowHiX or gfGrowHiY;
+  SetLimit({MaxViewWidth}80,MaxVideoLine);
+  New(Console, Init(@Self));
+  Console^.Size.X:=80; Console^.Size.Y:=25;
+  Console^.ClrScr;
+  Console^.CursorOn;
+end;
+
+function TANSIView.LoadFile(const FileName: string): boolean;
+var S: PBufStream;
+    OK: boolean;
+    B: array[0..1023] of char;
+    I,FragSize: integer;
+begin
+{$I-}
+  New(S, Init(FileName, stOpenRead, 4096));
+  OK:=Assigned(S);
+  while OK and (S^.Status=stOK) do
+  begin
+    FragSize:=Min(Sizeof(B),S^.GetSize-S^.GetPos);
+    if FragSize=0 then Break;
+    S^.Read(B,FragSize);
+    OK:=(S^.Status=stOK);
+    if OK then
+      for I:=0 to FragSize-1 do
+        self.Write(B[I]);
+  end;
+  if Assigned(S) then Dispose(S, Done); S:=nil;
+{$I+}
+  LoadFile:=OK;
+end;
+
+procedure TANSIView.Draw;
+type PDrawBuffer = ^TDrawBuffer;
+var I: integer;
+    Pos: longint;
+    X,Y: integer;
+begin
+  if LockCount<>0 then Exit;
+  for I:=0 to Size.Y-1 do
+  begin
+    Pos:=Delta.X+(Delta.Y+I)*MaxViewWidth;
+    WriteLine(0,I,Size.X,1,Buffer[Pos]);
+  end;
+  if Console=nil then Exit;
+  X:=Console^.WhereX-Delta.X; Y:=Console^.WhereY-Delta.Y;
+  if (X<0) or (Y<0) or (X>Size.X-1) or (Y>Size.X-1)
+     then HideCursor
+     else begin
+            ShowCursor;
+            SetCursor(X-1,Y-1);
+          end;
+end;
+
+procedure TANSIView.Write(S: string);
+begin
+  Console^.Write(S);
+  DrawView;
+end;
+
+procedure TANSIView.WriteLn(S: string);
+begin
+  Console^.WriteLn(S);
+  DrawView;
+end;
+
+procedure TANSIView.Lock;
+begin
+  Inc(LockCount);
+end;
+
+procedure TANSIView.UnLock;
+begin
+  Dec(LockCount);
+  if LockCount=0 then DrawView;
+end;
+
+procedure TANSIView.ChangeBounds(var Bounds: TRect);
+begin
+  inherited ChangeBounds(Bounds);
+{  Console^.Size.X:=Size.X; Console^.Size.Y:=Size.Y;}
+end;
+
+procedure TANSIView.HandleEvent(var Event: TEvent);
+begin
+  inherited HandleEvent(Event);
+{  if Event.What=evKeyDown then
+     begin
+       if VScrollBar<>nil then VScrollBar^.HandleEvent(Event);
+       if HScrollBar<>nil then HScrollBar^.HandleEvent(Event);
+     end;}
+end;
+
+destructor TANSIView.Done;
+begin
+  Dispose(Console, Done);
+  inherited Done;
+end;
+
+constructor TANSIBackgroundConsole.Init(AOwner: PANSIBackground);
+begin
+  if AOwner=nil then Fail;
+  inherited Init(nil,nil,nil);
+  Owner:=AOwner;
+  Size:=Owner^.Size;
+end;
+
+procedure TANSIBackgroundConsole.CursorOn;
+begin
+  Owner^.ShowCursor;
+end;
+
+procedure TANSIBackgroundConsole.CursorOff;
+begin
+  Owner^.HideCursor;
+end;
+
+procedure TANSIBackgroundConsole.ClrScr;
+var X,Y: word;
+    Pos: longint;
+begin
+  GotoXY(1,1);
+  if Owner<>nil then
+  for X:=0 to MaxViewWidth-1 do
+    for Y:=0 to Size.Y-1 do
+      begin
+        Pos:=X+Y*MaxViewWidth;
+        Owner^.Buffer[Pos]:=32+256*word(TextAttr);
+      end;
+end;
+
+procedure TANSIBackgroundConsole.ClrEol;
+var X,Y: word;
+    Pos: longint;
+begin
+  if Owner<>nil then
+  begin
+    Y:=CurPos.Y;
+    for X:=CurPos.X to MaxViewWidth-1 do
+        begin
+          Pos:=X+Y*MaxViewWidth;
+          Owner^.Buffer[Pos]:=32+256*word(TextAttr);
+        end;
+  end;
+end;
+
+procedure TANSIBackgroundConsole.WriteChar(C: char);
+var Pos: longint;
+begin
+  case C of
+       #8 : begin
+              CursorBack(1);
+              Pos:=(CurPos.Y-1)*MaxViewWidth+(WhereX-1);
+              Owner^.Buffer[Pos]:=ord(' ')+256*word(TextAttr);
+            end;
+       #0..#7,#9,
+       #11..#12,
+       #14..#31,
+       #32..#255
+            : begin
+                Pos:=(CurPos.Y-1)*MaxViewWidth+(WhereX-1);
+                Owner^.Buffer[Pos]:=ord(C)+256*word(TextAttr);
+                GotoXY(WhereX+1,WhereY);
+              end;
+       #10  :
+              GotoXY(WhereX,WhereY+1);
+       #13  :
+              GotoXY(1,WhereY);
+  else {$IFDEF DEBUG}RunError(241){$ENDIF};
+  end;
+end;
+
+procedure TANSIBackgroundConsole.DelLine(LineCount: integer);
+begin
+  Abstract;
+end;
+
+procedure TANSIBackgroundConsole.InsLine(LineCount: integer);
+begin
+  Abstract;
+end;
+
+procedure TANSIBackgroundConsole.UpdateCursor;
+begin
+  if Owner<>nil then
+  if Owner^.LockCount=0 then Owner^.SetCursor(WhereX-1,WhereY-1);
+end;
+
+procedure TANSIBackgroundConsole.GotoXY(X,Y: integer);
+var W: word;
+begin
+  if Owner<>nil then
+  while Y>MaxVideoLine do
+  begin
+    Move(Owner^.Buffer[MaxViewWidth],Owner^.Buffer,SizeOf(Owner^.Buffer)-(MaxViewWidth*2));
+    W:=(MaxViewWidth*MaxVideoLine)-1-(MaxViewWidth);
+    FillChar(Owner^.Buffer[W],MaxViewWidth*2,0);
+    Dec(Y);
+  end;
+  inherited GotoXY(X,Y);
+end;
+
+constructor TANSIBackground.Init(var Bounds: TRect);
+begin
+  inherited Init(Bounds,' ');
+  LockCount:=0;
+  GrowMode:=gfGrowHiX or gfGrowHiY;
+  New(Console, Init(@Self));
+  Console^.Size.X:=132; Console^.Size.Y:=50;
+  Console^.ClrScr;
+  Console^.CursorOn;
+end;
+
+function TANSIBackground.LoadFile(const FileName: string): boolean;
+var S: PBufStream;
+    OK: boolean;
+    B: array[0..1023] of char;
+    I,FragSize: integer;
+begin
+{$I-}
+  New(S, Init(FileName, stOpenRead, 4096));
+  OK:=Assigned(S);
+  while OK and (S^.Status=stOK) do
+  begin
+    FragSize:=Min(Sizeof(B),S^.GetSize-S^.GetPos);
+    if FragSize=0 then Break;
+    S^.Read(B,FragSize);
+    OK:=(S^.Status=stOK);
+    if OK then
+      for I:=0 to FragSize-1 do
+        self.Write(B[I]);
+  end;
+  if Assigned(S) then Dispose(S, Done); S:=nil;
+{$I+}
+  LoadFile:=OK;
+end;
+
+procedure TANSIBackground.Draw;
+type PDrawBuffer = ^TDrawBuffer;
+var I: integer;
+    Pos: longint;
+    X,Y: integer;
+begin
+  if LockCount<>0 then Exit;
+  for I:=0 to Size.Y-1 do
+  begin
+    Pos:=I*MaxViewWidth;
+    WriteLine(0,I,Size.X,1,Buffer[Pos]);
+  end;
+  if Console=nil then Exit;
+  X:=Console^.WhereX; Y:=Console^.WhereY;
+  if (X<0) or (Y<0) or (X>Size.X-1) or (Y>Size.X-1)
+     then HideCursor
+     else begin
+            ShowCursor;
+            SetCursor(X-1,Y-1);
+          end;
+end;
+
+procedure TANSIBackground.Write(S: string);
+begin
+  Console^.Write(S);
+  DrawView;
+end;
+
+procedure TANSIBackground.WriteLn(S: string);
+begin
+  Console^.WriteLn(S);
+  DrawView;
+end;
+
+procedure TANSIBackground.Lock;
+begin
+  Inc(LockCount);
+end;
+
+procedure TANSIBackground.UnLock;
+begin
+  Dec(LockCount);
+  if LockCount=0 then DrawView;
+end;
+
+procedure TANSIBackground.ChangeBounds(var Bounds: TRect);
+begin
+  inherited ChangeBounds(Bounds);
+{  Console^.Size.X:=Size.X; Console^.Size.Y:=Size.Y;}
+end;
+
+procedure TANSIBackground.HandleEvent(var Event: TEvent);
+begin
+  inherited HandleEvent(Event);
+{  if Event.What=evKeyDown then
+     begin
+       if VScrollBar<>nil then VScrollBar^.HandleEvent(Event);
+       if HScrollBar<>nil then HScrollBar^.HandleEvent(Event);
+     end;}
+end;
+
+destructor TANSIBackground.Done;
+begin
+  Dispose(Console, Done);
+  inherited Done;
+end;
+
+END.
+{
+ $Log $ 
+ 
+}