home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 5
/
ctrom5b.zip
/
ctrom5b
/
PROGRAM
/
PASCAL
/
PAVT199
/
PAVT150.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-06-13
|
51KB
|
1,463 lines
(*******************************************************************)
(* Avatar level 1 Console driver. Unit for providing a program *)
(* with proper Avatar levels 0, 0+, and 1 emulations. *)
(* Copyright (c) 1991 - 93 Gregory P. Smith *)
(* All Rights Reserved *)
(*-----------------------------------------------------------------*)
(* Last Update: June 13, 1993 v 1.55 *)
(*=================================================================*)
(* Current Version # 1.50: VT-52 & "ANSI" music working. *)
(*******************************************************************)
unit PAvt150; { AVT/1 Console Driver (ANSI-BBS optional) }
{$I PAVTVER.INC}
{$IFDEF OVERLAY}
{$F+,O+ -- Allow overlaying of the main unit. }
{$ENDIF}
INTERFACE
uses Dos, Crt,
PAvtIO, PAvtSnd;
(*-- Declaration of Functions/Procedures useable by other programs ---*)
PROCEDURE Parse_AVT1(ch:char); { AVT/1 Parser }
PROCEDURE AvtTTY(ch:char); { Avatar TTY w/o AVT code processing }
PROCEDURE SetScreenSize(nc,nl:integer); { use a nl X nl size screen }
PROCEDURE ResetTerminal(nc,nl:integer); { Reset terminal & screen size }
{ to nc X nl }
{ Select the current terminal emulation using the TermXXXX constants }
PROCEDURE SetTerminal(t:TerminalType);
FUNCTION In_Command : boolean; { terminal is expecting more data to }
{ complete an AVT or ANSI command }
PROCEDURE UpdateCursor(x,y:byte); { update cursor position, passing 0 }
{ leaves that position unchanged. }
PROCEDURE Level0_Simulation(fallbck:boolean); { Set parser for AVT/0+ }
PROCEDURE ANSI_Only; { Makes it an ANSI terminal by putting it into }
{ sleep & non-fallback mode. }
{$IFDEF OVERLAY -- Only needed if we're overlaying the unit }
PROCEDURE InitUnit; { Unit initialization code! Must be called before }
{ anything else or the unit will crash the system }
{$ENDIF}
IMPLEMENTATION
{-- local type definitions -----------------------------------------}
type
(* Data/Action Object Definitions *)
Act_WindowObj = object { Holds the active window's data }
x1, y1, { window corners }
x2, y2,
cx, cy, { cursor position }
{$IFDEF VT102} miny, maxy, { vertical cursor limits }
st, sb, { top & bottom scrolling regions } {$ENDIF}
wrap, { EOL wrapping style }
cursor, { cursor shape }
attr, { current color }
def_attr, { default color }
width, { width: x2-x1+1 }
depth : byte; { depth: y2-y1+1 }
NormFlow, { foward or backward flow }
DownLF, { LineFeeds go down }
Insert, { Insert is on }
UpDown, { write Up & Down }
StaticOn : boolean; { don't move cursor }
Procedure SetXY(x,y:byte); { cursor position }
Procedure SetRelXY(x,y:integer); { relative position }
{$IFDEF DELAY_WRAP} Procedure WSetXY(x,y:byte); { delayed wrap cursor pos } {$ENDIF}
Procedure HighArea(xx1,yy1,xx2,yy2,a:byte); { win relative }
Procedure Scroll(dir,xx1,yy1,xx2,yy2,n:byte); { " " }
Procedure FillArea(xx1,yy1,xx2,yy2,a:byte;c:char); { " " }
Procedure DDelEOL; { Flag aware Delete to EOL (inclusive) }
Procedure DDelChar; { Flag Aware Delete char. }
Procedure DDelLine; { Flag aware delete line/column }
Procedure DInsertLine; { Flag aware insert line/column }
Procedure DHighEOL(a:byte); { Flag Aware Highlight to EOL }
Procedure HighlightIt(a:byte); { Highlight the window }
Procedure Clear(a:byte;c:char); { Clear the window }
Procedure WriteAT(x,y,a:byte;c:char); { Write char }
Procedure LoadWinData(anum : byte); { Load from WinList }
Procedure StoreWinData; { store data in WinList }
end; { Act_WindowObj }
AvtWindowObj = object { holds the other windows' data }
_x1,_y1, { upper corner of window }
_x2,_y2, { lower corner of window }
_cx,_cy, { relative cursor position within window }
WCFLf, { wrap type (bits 0-1) cursor style (bits2-3) }
{ Flow (foward | reverse bit 4) 1 = reverse }
{ LineFeed Translation ( Normal | Up bit 5) 1 = up}
{ Insert Mode ( On | Off bit 6) 1 = on }
{ Up&Down ( On | Off bit 7 ) 1 = on }
cattrib, { current writing color }
attrib : byte; { default color of window }
Static : boolean; { is static mode on? }
Procedure Init(NumCols,NumLines:integer); { set defaults }
Procedure Set_XY(x,y:byte); { Cursor position }
Procedure HighlightIt(a:byte); { Highlight the window }
end; { object }
AvtWinListType = Array[0..255] of AvtWindowObj; { Window Data Array }
AvtWinListPtr = ^AvtWinListType;
{-- local variable -------------------------------------------------}
const
WinList : AvtWinListPtr = nil; { Pointer to Avatar window data }
AWin : byte = 0; { Active Avatar Window }
FlowBackWard = 16; { > Flow Backward }
LineFeedUp = 32; { > LineFeeds go up }
InsertOn = 64; { > Insert Mode On }
UpDownOn = 128; { > Up&Down flow }
(* --- AvtWindowObj's Implementations --- *)
Procedure AvtWindowObj.Init(NumCols,NumLines:integer);
begin
_x1 := 1;
_y1 := 1;
_x2 := NumCols;
_y2 := NumLines;
_cx := 1;
_cy := 1;
WCFLf := None;
cattrib := 7;
Attrib := 7;
Static := False;
end;
Procedure AvtWindowObj.Set_XY(x,y:byte);
var
w,d : byte;
begin
w := succ(_x2-_x1); { width }
d := succ(_y2-_y1); { depth }
if x > w then _cx := w
else if x > 0 then _cx := x;
if y > d then _cy := d
else if y > 0 then _cy := y;
end;
Procedure AvtWindowObj.HighlightIt(a : byte);
begin
HighAreah(_x1,_y1,_x2,_y2,a);
end; { HighlightIt }
(* --- End of AvtWindowObj's Implementation --- *)
(* --- Act_WindowObj's Implementation --- *)
{$IFDEF DELAY_WRAP}
Procedure Act_WindowObj.WSetXY(x,y:byte);
begin
if x >= succ(width) then begin { compensate for delayed EOL wrapping }
cx := succ(width);
GotoXYh(cx+x1-2, pred(cy+miny)); { don't pass x > width to the hook }
exit;
end else
if x > 0 then cx := x;
if y > depth then cy := depth
else if y > 0 then cy := y;
{$IFDEF VT102}
GotoXYh(pred(cx+x1),pred(cy+miny))
{$ELSE}
GotoXYh(pred(cx+x1),pred(cy+y1));
{$ENDIF}
end;
{$ENDIF}
Procedure Act_WindowObj.SetXY(x,y:byte);
begin { a 0 in x or y leaves it unchanged }
if x > width then cx := width
else if x > 0 then cx := x;
if y > depth then cy := depth
else if y > 0 then cy := y;
{$IFDEF VT102}
GotoXYh(pred(cx+x1),pred(cy+miny))
{$ELSE}
GotoXYh(pred(cx+x1),pred(cy+y1));
{$ENDIF}
end;
Procedure Act_WindowObj.SetRelXY(x,y:integer);
begin { move cursor relative to current position }
x := cx + x;
y := cy + y;
if x < 1 then cx := 1
else if x > width then cx := width
else cx := x;
if y < 1 then cy := 1
else if y > depth then cy := depth
else cy := y;
{$IFDEF VT102}
GotoXYh(pred(cx+x1),pred(cy+miny));
{$ELSE}
GotoXYh(pred(cx+x1),pred(cy+y1));
{$ENDIF}
end;
Procedure Act_WindowObj.HighArea(xx1,yy1,xx2,yy2,a:byte);
begin
HighAreah(Pred(x1+xx1),Pred(y1+yy1),pred(x1+xx2),pred(y1+yy2),a);
end;
Procedure Act_WindowObj.Scroll(dir,xx1,yy1,xx2,yy2,n:byte);
begin
if n = 0 then { 0 = clear area }
if dir < 3 then
n := succ(yy2-yy1)
else n := succ(xx2-xx1);
Scrollh(dir,Pred(x1+xx1),Pred(y1+yy1),Pred(x1+xx2),Pred(y1+yy2),n,attr);
end;
Procedure Act_WindowObj.FillArea(xx1,yy1,xx2,yy2,a:byte;c:char);
var
g,h : byte;
begin
g := Pred(x1+xx2);
h := Pred(y1+yy2);
if g > x2 then g := x2;
if h > y2 then h := y2;
FillAreah(Pred(x1+xx1),Pred(y1+yy1),g,h,a,c);
end;
Procedure Act_WindowObj.DDelEOL; { Fully Aware of Direction Flags }
begin
if NormFlow then
if UpDown then
FillArea(cx,cy,cx,Depth,attr,' ')
else FillArea(cx,cy,Width,cy,attr,' ')
else
if UpDown then
FillArea(cx,1,cx,cy,attr,' ')
else FillArea(1,cy,cx,cy,attr,' ');
end;
Procedure Act_WindowObj.DDelChar; { Fully Flag Aware }
begin
if NormFlow then
if UpDown then
Scroll(1,cx,cy,cx,Depth,1) { updown }
else Scroll(3,cx,cy,Width,cy,1) { normal }
else
if UpDown then
Scroll(2,cx,1,cx,cy,1) { rev updown }
else Scroll(4,cy,cx,cy,1,1); { reverse }
end;
Procedure Act_WindowObj.DDelLine; { Flag Aware delete line }
begin
if not UpDown then
Scroll(1,1,succ(cy),Width,Depth,1) { delete line }
else
Scroll(3,succ(cx),1,Width,Depth,1); { delete column }
end; { ddelline }
Procedure Act_WindowObj.DInsertLine; { Flag aware insert line }
begin
if not UpDown then
Scroll(2,1,cy,Width,pred(Depth),1) { insert line }
else
Scroll(4,cx,1,pred(Width),Depth,1); { insert column }
end; { dinsertline }
Procedure Act_WindowObj.DHighEOL(a : byte); { Flag Aware Highlight EOL }
begin
if NormFlow then
if UpDown then
HighArea(cx,cy,cx,Depth,a) { updown }
else HighArea(cx,cy,Width,cy,a) { normal }
else
if UpDown then
HighArea(cx,1,cx,cy,a) { updown + reverse }
else HighArea(1,cy,cx,cy,a); { reverse }
end;
Procedure Act_WindowObj.HighlightIt(a : byte); { highlight the window }
begin
HighAreah(x1,y1,x2,y2,a);
end; { HighlightIt }
Procedure Act_WindowObj.Clear(a:byte;c:char); { Clear the window }
begin
FillAreah(x1,y1,x2,y2,a,c);
end;
Procedure Act_WindowObj.WriteAt(x,y,a:byte;c:char); { write a character }
begin
{$IFDEF VT102}
WriteATh(pred(x+x1),y+y1+miny-2,a,c); { x1.54 -- scrolling region }
{$ELSE}
WriteATh(pred(x+x1),pred(y+y1),a,c);
{$ENDIF}
end;
Procedure Act_WindowObj.LoadWinData(anum : byte);
begin
with WinList^[anum] do begin
x1 := _x1; y1 := _y1;
x2 := _x2; y2 := _y2;
cx := _cx; cy := _cy;
width := succ(x2-x1);
depth := succ(y2-y1);
attr := cattrib;
def_attr := attrib;
wrap := WCFLf and NoWrap;
cursor := WCFLf and HiddenCursor;
NormFlow := (WCFLf and FlowBackward) = 0;
DownLF := (WCFLf and LineFeedUp) = 0;
Insert := (WCFLf and InsertOn) = InsertOn;
UpDown := (WCFLf and UpDownOn) = UpDownOn;
StaticOn := Static;
end;
{$IFDEF VT102} miny := y1; maxy := y2; st := y1; sb := y2; {$ENDIF}
GotoXYh(pred(x1+cx),pred(y1+cy));
AWin := anum;
end;
Procedure Act_WindowObj.StoreWinData;
begin
with WinList^[AWin] do begin
_x1 := x1; _y1 := y1;
_x2 := x2; _y2 := y2;
_cx := cx; _cy := cy;
cattrib := attr;
attrib := def_attr;
WCFLf := wrap or cursor or (byte(not NormFlow) shl 4) or
(byte(not DownLF) shl 5) or (byte(Insert) shl 6) or
(byte(UpDown) shl 7);
Static := StaticOn;
end;
end;
(* --- End of Act_WindowObj's Implementation --- *)
(* --- More locals ----- *)
type
Arr255Type = Array[1..255] of char;
const
{$IFDEF ANSI_MUSIC}
NumPrms = 180;
{$ELSE}
NumPrms = 10;
{$ENDIF}
AvtIncome : byte = 0; { # of parameters expected to come }
AvtInString : byte = 0; { nesting level of ^V^Y command }
Cooked : boolean = True; { Parser: Raw or Cooked mode }
InDLE : boolean = False; { Parser: last char was ^P }
Awake : boolean = True; { Parser: Is the interpreter awake? }
TTY_Only : boolean = False; { in TTY only mode }
MaxStrNest = 6; { Maximum ^V^Y nesting level }
var
PrmArr : Array[1..NumPrms] of byte; { stores command parameters }
AvtStrPtr : Array[1..MaxStrNest] of ^Arr255Type; { strs storing ^V^Y cmds }
AvtInterp_Ptr : pointer absolute AvtInterp; { for referencing }
ActWin : Act_WindowObj; { Active Avatar window data }
{-- Forward Interp References -------------------------------------}
{$F+}
procedure AVT1_Waiting(ch:char); forward;
procedure AVT1_Command(ch:char); forward;
procedure AVT1_Param(ch:char); forward;
procedure AVT1_String(ch:char); forward;
procedure AVT1_InANSI(ch:char); forward;
{$IFNDEF OVERLAY}
{$F-}
{$ENDIF}
{-- ANSI include file ---------------------------------------------}
{$I PAVTANSI.INC}
{-- Inner workings of terminal ------------------------------------}
function In_Command : boolean; { Is the terminal inside a command? }
begin { only check offsets, segments are the same }
In_Command := (Word(AvtInterp_Ptr) <> Word(@AVT1_Waiting)) and
(Word(AvtInterp_Ptr) <> Word(@ANSI_Waiting)) or
(AvtInString > 0);
end;
procedure UpdateCursor(x,y:byte); { move cursor from application }
begin { a zero restores the known position }
ActWin.SetXY(x,y);
end;
procedure SetScreenSize(nc,nl:integer);
var
j : integer;
begin
for j := 0 to 255 do
with WinList^[j] do begin
_x1 := 1; _y1 := 1;
_x2 := nc; _y2 := nl;
end;
with ActWin do begin { x1.52 }
x1 := 1; y1 := 1;
x2 := nc; y2 := nl;
{$IFDEF VT102}
miny := 1; maxy := nl;
st := 1; sb := nl;
{$ENDIF}
end;
ScrnColumns := nc;
ScrnLines := nl;
end;
procedure ResetTerminal(nc,nl:integer);
var
j : integer;
begin
ScrnColumns := nc;
ScrnLines := nl;
ANSI_Reset;
for j := 0 to 255 do { reset all windows to the default }
WinList^[j].Init(nc,nl);
ActWin.LoadWinData(0);
AvtInCome := 0;
AvtInString := 0;
Cooked := True;
InDLE := False;
Awake := True;
TTY_Only := False;
AvtInterp := AVT1_Waiting; { waiting }
ANSI_MUSIC := True;
Fallback := False;
Dest_BS := True;
QueryReply[4] := '1'; { level 1 again }
{$IFDEF VT52}
EightBitControl := False;
VT52On := False;
{$ENDIF}
{$IFDEF VT102}
VT102On := False;
CRtoCRLF := False;
RelativePos := False;
InQMarkCmd := False;
{$ENDIF}
IgnoreNULL := False;
CurrentTerm := TermAVT1;
end; { ResetTerminal }
Procedure SetTerminal(t:TerminalType);
begin
ResetTerminal(ScrnColumns,ScrnLines);
case t of
TermTTY : begin
TTY_Only := True;
Cooked := False;
AvtInterp := AvtTTY;
end;
TermANSI : ANSI_Only;
TermAVT0 : Level0_Simulation(True);
{ TermAVT1 : default set by ResetTerminal }
{$IFDEF VT52}
TermVT52 : begin
ANSI_Only;
ActWin.wrap := NoWrap; { VTs don't wrap at EOL }
VT52On := True;
IgnoreNULL := True; { VTs ignore the null character }
Dest_BS := False;
ANSI_MUSIC := False;
end;
{$ENDIF} {$IFDEF VT102}
TermVT102 : begin
ANSI_Only;
ANSI_BBS := False;
ActWin.Wrap := NoWrap;
VT52On := False;
VT102On := True;
IgnoreNULL := True;
Dest_BS := False;
ANSI_MUSIC := False;
CrtoCRLF := False;
RelativePos := False;
end;
{$ENDIF}
end; { case }
CurrentTerm := t;
end;
(*************** AVT/1 TTY Processor *************************)
procedure AvtTTY(ch:char); {far;}
var
n : integer;
begin
with ActWin do
begin
{$IFDEF TTY_HOOK}
if not TTYCharH(ch,attr) then exit; { continue TTY process? }
{$ENDIF}
if ch in [^G,^H,^I,^J,^M] then
case ch of
^M : begin { CR }
if wrap = ClockWise then begin { cancel clockwise mode }
wrap := None;
NormFlow := True;
UpDown := False;
end;
if NormFlow then begin
if UpDown then
SetXY(0,1) { Top of screen }
else SetXY(1,0); { left of screen } { normal }
end else begin
if UpDown then
SetXY(0,255) { bottom }
else SetXY(255,0); { right }
end;
if Wrap = ZigZag then
NormFlow := not NormFlow; { reverse the direction }
end; { ^M }
^J : begin { LF }
if DownLF then
begin
if UpDown then begin
if cx = Width then
Scroll(3,1,1,Width,Depth,1);
SetRelXY(1,0) { right one column }
end else begin
if cy = Depth then
Scroll(1,1,1,Width,Depth,1);
SetRelXY(0,1); { down one line }
end;
end
else { DownLF }
begin
if UpDown then begin
if cx = 1 then
Scroll(4,1,1,Width,Depth,1);
SetRelXY(-1,0) { left one column }
end else begin
if cy = 1 then
Scroll(2,1,1,Width,Depth,1);
SetRelXY(0,-1); { up one line }
end;
end; { else DownLF }
end; { ^J }
^H : begin { BS }
if not StaticOn then
begin
if NormFlow then
if UpDown then
SetRelXY(0,-1)
else SetRelXY(-1,0) { normal }
else
if UpDown then
SetRelXY(0,1)
else SetRelXY(1,0); { reverse }
if Dest_BS then WriteAT(cx,cy,Attr,' ');
end { overstrike if destructive }
else { static mode }
begin
if NormFlow then { in static or insert on BS deletes }
if UpDown then
Scroll(1,cx,cy,cx,Depth,1)
else Scroll(3,cx,cy,Width,cy,1)
else
if UpDown then
Scroll(2,cx,1,cx,cy,1)
else Scroll(4,1,cy,cx,cy,1);
end;
end; { ^H }
^I : begin { Tab 8 }
if NormFlow then
if UpDown then
SetRelXY(0,8)
else SetRelXY(8,0) { normal }
else
if UpDown then
SetRelXY(0,-8)
else SetRelXY(-8,0); { reverse }
end; { ^I }
^G : begin { beep }
if ((Sound_Stat and 1) = 1) then { bell on }
SoundBell;
end; { ^G }
end { case }
else { if ch in ... }
begin
if (ch = #0) and IgnoreNULL then exit; { Ignore the null character }
if Insert then begin
if NormFlow then begin
if UpDown then
if cy < pred(Depth) then
Scroll(2,cx,cy,cx,Depth,1)
else { updown }
if cx < pred(Width) then
Scroll(4,cx,cy,Width,cy,1);
end else begin { normflow }
if UpDown then
if cy > 1 then
Scroll(1,cx,1,cx,cy,1)
else { updown }
if cx > 1 then
Scroll(3,1,cy,cx,cy,1);
end; { normflow }
end; { insert }
WriteAT(cx,cy,Attr,ch); { -- write the char -- }
if not StaticOn then
if NormFlow then
if UpDown then begin
if cy < Depth then
SetRelXY(0,1)
else begin
if DownLF then n := 1
else n := -1;
if wrap <= ZigZag then { wrap in [None, ZigZag] }
if DownLF and (cx = Width) then
Scroll(3,1,1,Width,Depth,1)
else if (not DownLF) and (cx = 1) then
Scroll(4,1,1,Width,Depth,1);
case wrap of
None : SetRelXY(n,-255);
ZigZag : begin
SetRelXY(n,255);
NormFlow := False;
end;
ClockWise : begin
SetRelXY(-1,255);
NormFlow := False;
UpDown := False; { <--- direction }
{ exit; { no scroll }
end;
{ NoWrap : exit; { don't do anything! }
end; { case wrap }
end; { cy < Depth .. else }
end else begin { UpDown }
if cx < Width then
SetRelXY(1,0)
else begin
if DownLF then n := 1
else n := -1;
if wrap <= ZigZag then { if wrap in [None, ZigZag] }
if DownLF and (cy = Depth) then
Scroll(1,1,1,Width,Depth,1)
else if (not DownLF) and (cy = 1) then
Scroll(2,1,1,Width,Depth,1);
case wrap of
None : SetRelXY(-255,n);
ZigZag : begin
SetRelXY(255,n);
NormFlow := False;
end;
ClockWise : begin
SetRelXY(255,1);
NormFlow := True; { | }
UpDown := True; { V direction }
{ exit; { no scroll }
end;
{ NoWrap : exit; { don't do anything! }
end; { case wrap }
end; { cx < Width .. else }
end { UpDown }
else { NormFlow }
if UpDown then begin
if cy > 1 then
SetRelXY(0,-1)
else begin
if DownLF then n := 1
else n := -1;
if wrap <= ZigZag then { wrap in [None, ZigZag] }
if DownLF and (cx = Width) then
Scroll(3,1,1,Width,Depth,1)
else if (not DownLF) and (cx = 1) then
Scroll(4,1,1,Width,Depth,1);
case wrap of
None : SetRelXY(n,255);
ZigZag : begin
SetRelXY(n,-255);
NormFlow := True;
end;
ClockWise : begin
SetRelXY(1,-255);
NormFlow := True;
UpDown := False; { ---> direction }
{ exit; { no scroll }
end;
{ NoWrap : exit; { don't do anything! }
end; { case wrap }
end; { cy > 1 .. else }
end else begin { UpDown }
if cx > 1 then
SetRelXY(-1,0)
else begin
if DownLF then n := 1
else n := -1;
if wrap <= ZigZag then { wrap in [None, ZigZag] }
if DownLF and (cy = Depth) then
Scroll(1,1,1,Width,Depth,1)
else if (not DownLF) and (cy = 1) then
Scroll(2,1,1,Width,Depth,1);
case wrap of
None : SetRelXY(255,n);
ZigZag : begin
SetRelXY(-255,n);
NormFlow := True;
end;
ClockWise : begin
SetRelXY(-255,-1);
NormFlow := False;
UpDown := True; { ^ direction }
{ exit; { no scroll }
end;
{ NoWrap : exit; { don't do anything! }
end; { case wrap }
end; { cx > 1 .. else }
end; { UpDown }
end; { if ch in ... else (write the char) }
end; { With ActWin }
end; { AvtTTY }
(*************** AVT/1 Query Handler *************************)
Procedure Process_Query(ch : char);
type
str2 = string[2];
Function DLEch(c:char): str2; { escape the proper characters }
begin
if Cooked and (c < #32) then
DLEch := ^P + chr(ord(c) or $40)
else DLEch := c;
end;
begin
with ActWin do
begin
case chr(ord(ch) and $3F) of
^A,^B : begin { return current color }
Query_Hook(^V+^A+DLEch(chr(Attr)));
end;
^H : begin { return cursor position }
Query_Hook(^V+DLEch(^H)+DLEch(chr(cy))+DLEch(chr(cx)));
end;
^Q : begin { terminal type query }
Query_Hook(QueryReply);
end;
^V : begin { return current window setup }
Query_Hook(^V+^V+DLEch(chr(AWin))+DLEch(chr(Def_Attr))+
DLEch(chr(y1))+DLEch(chr(x1))+DLEch(chr(y2))+
DLEch(chr(x2))); { a define window command }
end;
^W : begin { return current window }
Query_Hook(^V+^W+DLEch(chr(AWin)));
end;
FS,GS : begin { return sleep mode }
if Awake then
Query_Hook(^V+DLEch(GS))
else Query_Hook(^V+DLEch(FS));
end;
RS,US : begin { return vertical mode }
if UpDown then
Query_Hook(^V+DLEch(RS))
else Query_Hook(^V+DLEch(US));
end;
'"','$',
'#' : begin { return eol wrap type }
case wrap of
None : Query_Hook(^V+'$');
NoWrap : Query_Hook(^V+'"');
ClockWise : Query_Hook(^V+DLEch(^O));
ZigZag : Query_Hook(^V+'#');
end;
end;
'%','&' : begin { return linefeed type }
if DownLF then
Query_Hook(^V+'&')
else Query_Hook(^V+'%');
end;
'(',')' : begin { return flow direction }
if NormFlow then
Query_Hook(^V+'(')
else Query_Hook(^V+')');
end;
':' : begin { return keyboard type }
Query_Hook(^V+':0');
end;
'=' : begin { return cooked/raw status }
if Cooked then
Query_Hook(^V+'=C')
else Query_Hook(^V+'=R');
end;
end; { case } { all queries were found in AVATAR.SYS 0.10a }
end; { with }
end; { Process_Query }
(*************** Avatar level 1 Interpreter ******************)
procedure AVT1_Waiting(ch:char); {far;}
begin
if ch > #27 then
begin
{$IFDEF VT52}
if VT52On and EightBitControl and Fallback and
((ch >= #$80) and (ch <= #$9F)) and
(AVTInterp_Ptr = @AVT1_Waiting) then ANSI_Bracket(chr(ord(ch) - $40))
else {$ENDIF} { process 8 bit control chars }
AvtTTY(ch); { TTY char }
end
else
begin
case ch of
^V : AVTInterp := AVT1_Command;
^L : begin
with ActWin do
begin
Clear(Def_Attr,' '); { ClrScr }
Attr := Def_Attr;
SetXY(1,1);
Insert := False; { Turn Off Insert }
exit;
end; { with }
end;
^Y : begin
AvtInterp := AVT1_Param;
AvtInCome := 2; { expect 2 more params. }
end;
ESC : begin
if Fallback and (AvtInString = 0) then
AvtInterp := ANSI_Bracket
else
AvtInterp := AVT1_InANSI; { for Esc[2J processing }
end;
else { case }
begin
AvtTTY(ch);
exit;
end; { case else }
end; { case }
PrmArr[1] := ord(ch); { put command in parameter array }
end; { ch <= #27 }
end;
procedure AVT1_Command(ch:char); {far;}
begin { primary interpretation phase }
AvtInterp := AVT1_Waiting; { waiting }
PrmArr[2] := ord(ch); { store the command }
if not (ch in [^V,^W,^Y]) then ActWin.Insert := False; { no insert }
case ch of { order of frequency. }
^A : begin { set attribute }
AvtInCome := 1;
AvtInterp := AVT1_Param;
end;
^H : begin { set cursor position }
AvtInCome := 2;
AvtInterp := AVT1_Param;
end;
^B : begin { turn blink on }
with ActWin do
Attr := Attr or $80; { blink bit on }
end;
^E : begin { move cursor one column left }
with ActWin do
SetRelXY(-1,0);
end;
^F : begin { Move cursor one column right }
with ActWin do
SetRelXY(1,0);
end;
^C : begin { move cursor one line up }
with ActWin do
SetRelXY(0,-1);
end;
^D : begin { move cursor one line down }
with ActWin do
SetRelXY(0,1);
end;
^J,^K : begin { scroll up/down }
AvtInCome := 5;
AvtInterp := AVT1_Param;
if ch = ^J then PrmArr[7] := 1 else PrmArr[7] := 2;
end;
^L,^S : begin { clear an area / make a sound }
AvtInCome := 3;
AvtInterp := AVT1_Param;
end;
^I : begin { turn insert on }
ActWin.Insert := True; { guess! }
end;
^M : begin { initalize an area }
AvtInCome := 4;
AvtInterp := AVT1_Param;
end;
^G : begin { clear to EOL }
ActWin.DDelEOL; { easy huh? }
end;
^N : begin { delete character }
ActWin.DDelChar; { another easy one! }
end;
^V : begin { define a window }
AvtInCome := 6;
AvtInterp := AVT1_Param;
end;
^W : begin { activate window }
AvtInCome := 1;
AvtInterp := AVT1_Param;
end;
'-' : begin { delete line }
ActWin.DDelLine; { easy again?! }
end;
'+' : begin { insert line }
ActWin.DInsertLine; { guess what! }
end;
'.' : begin { delete column }
with ActWin do
begin
UpDown := not UpDown; { toggle it }
DDelLine; { now a column... }
UpDown := not UpDown; { restore it }
end;
end;
',' : begin { insert column }
with ActWin do
begin
UpDown := not UpDown; { toggle it }
DInsertLine; { now a column... }
UpDown := not UpDown; { restore it }
end;
end;
'>','<' : begin { scroll right/left }
AvtInCome := 5;
AvtInterp := AVT1_Param;
if ch = '<' then PrmArr[7] := 3 else PrmArr[7] := 4;
end;
^R : begin { reset the driver }
AvtInCome := 0;
if CurrentTerm <> TermAVT0 then { level 0 can't be reset to 1 }
ResetTerminal(ScrnColumns,ScrnLines);
end;
'"' : begin { Don't wrap at EOL }
ActWin.wrap := NoWrap;
end;
'#' : begin { Switch Direction at EOL wrap (ZigZag) }
ActWin.wrap := ZigZag;
end;
'$' : begin { Wrap at EOL (normal) }
ActWin.wrap := None; { normal }
end;
'%' : begin { Reverse LF action (Up) }
ActWin.DownLF := False;
end;
'&' : begin { Normalize LF action (Down) }
ActWin.DownLF := True; { down }
end;
'(' : begin { Do Not Print In Reverse }
ActWin.NormFlow := True; { foward }
end;
')' : begin { Print in Reverse }
ActWin.NormFlow := False; { Reverse! }
end;
RS : begin { Start vertical mode }
ActWin.UpDown := True; { vertical }
end;
US : begin { End vertical mode (horizontal) }
ActWin.UpDown := False; { horizontal }
end;
^O : begin { Turn Clockwise mode on. }
ActWin.wrap := Clockwise; { guess! }
end;
^Q,^T : begin { Query the driver, Highlight Cursor Position }
AvtInCome := 1;
AvtInterp := AVT1_Param;
end;
'!' : begin { Poke char on screen }
AvtInCome := 4;
AvtInterp := AVT1_Param;
end;
'?',^U : begin { Peek at char on screen, highlight window }
AvtInCome := 2;
AvtInterp := AVT1_Param;
end;
'0','1',':', { Highlight EOL,BOL, Set Keyboard mode, }
'=','/','*',
{ ' } #39 : begin { Parser Mode (cook|Raw), (re)set static mode, }
AvtInCome := 1; { Make System pause, Cursor type }
AvtInterp := AVT1_Param;
end;
^Y : begin { repeat AVT pattern }
AvtInCome := 255; { undefined as of yet }
AvtInterp := AVT1_Param;
end;
^X : begin { Flush Input }
FlushInputh;
end;
FS : begin { put interpreter to sleep. }
Awake := False; { ZZZZZZZZZzzzzzzzzzzz....... }
PrmArr[1] := 0; { sleeping }
AvtInterp := ANSI_Waiting; { ANSI is lower terminal }
end;
(* ^P,^Z,#27, Commented out as it only adds dead code
SP,'2'..'9',';' : { NOP, <reserved> (for etc.) } ; *)
end; { case ch of }
end; { AVT1_Command }
Procedure AVT1_Param(ch:char); {far;}
var
b : Array[1..2] of byte;
c1 : char absolute b; { for referencing purposes }
i1,i2 : integer;
begin
if PrmArr[1] = 22 then { if ^V then }
case chr(PrmArr[2]) of
^A : begin { Set Attribute }
ActWin.Attr := ord(ch) AND $7F;
AvtInCome := 0;
end;
^H : begin
if AvtInCome = 1 then
ActWin.SetXY(ord(ch),PrmArr[3])
else
PrmArr[5-AvtInCome] := ord(ch);
dec(AvtInCome);
end;
^J,^K,'<','>' : begin { scroll up/down/left/right }
if AvtInCome > 1 then
begin
PrmArr[8-AvtInCome] := ord(ch);
dec(AvtInCome);
end
else
begin { dir , x1 , y1 }
ActWin.Scroll(PrmArr[7],PrmArr[5],PrmArr[4],
ord(ch),PrmArr[6],PrmArr[3]); { x2, y2, #lines }
AvtInCome := 0;
end;
end; { ^J/^K }
^L : begin { clear area }
if AvtInCome > 1 then
begin
PrmArr[6-AvtInCome] := ord(ch);
dec(AvtInCome);
end
else
begin
with ActWin do
begin
FillArea(cx,cy,pred(cx+ord(ch)),
pred(cy+PrmArr[4]),PrmArr[3],' ');
Attr := PrmArr[3];
end;
AvtInCome := 0;
end;
end;
^M : begin { init area }
if AvtInCome > 1 then
begin
PrmArr[7-AvtInCome] := ord(ch);
dec(AvtInCome);
end
else
begin
with ActWin do
begin
FillArea(cx,cy,pred(cx+ord(ch)),
pred(cy+PrmArr[5]),PrmArr[3],
chr(PrmArr[4]));
Attr := PrmArr[3];
end;
AvtInCome := 0;
end;
end;
^Q : begin { Query the driver }
Process_Query(ch);
AvtInCome := 0;
end;
^S : begin { Sound a tone }
if AvtInCome > 1 then
begin
PrmArr[6-AvtInCome] := ord(ch);
Dec(AvtInCome);
end
else
begin { note , octave , duration }
if ((Sound_Stat and $02) = 2) then { Sound on }
AvtSound(PrmArr[3],PrmArr[4],ord(ch));
AvtInCome := 0;
end;
end;
^T : begin { highlight cursor position }
with ActWin do
HighArea(cx,cy,cx,cy,ord(ch));
AvtInCome := 0;
end;
^U : begin { highlight a window }
if AvtInCome > 1 then begin
PrmArr[5-AvtInCome] := ord(ch);
Dec(AvtInCome);
end else begin
WinList^[PrmArr[3]].HighlightIt(ord(ch));
AvtInCome := 0;
end; { else }
end;
^V : begin { Define a window! }
if AvtInCome > 1 then begin
PrmArr[9-AvtInCome] := ord(ch);
Dec(AvtInCome);
end else begin
if PrmArr[3] > 0 then begin { 0 is not redefinable }
with WinList^[PrmArr[3]] do begin
if PrmArr[3] = AWin then begin { change the active window }
with ActWin do begin
i1 := pred(x1+cx)-PrmArr[6];
i2 := pred(y1+cy)-PrmArr[5];
end;
if i1 < 1 then i1 := 1; { snap to closest }
if i2 < 1 then i2 := 1; { pt. in window }
if i1 > (ord(ch)-PrmArr[6]) then
i1 := ord(ch)-PrmArr[6];
if i2 > (ord(ch)-PrmArr[5]) then
i2 := ord(ch)-PrmArr[5];
Set_XY(i1,i2);
end else Set_XY(1,1); { init cursor at 1,1 otherwise }
_x1 := PrmArr[6];
_y1 := PrmArr[5];
_x2 := ord(ch);
_y2 := PrmArr[7];
attrib := PrmArr[4];
cattrib := attrib;
if PrmArr[3] = AWin then
ActWin.LoadWinData(AWin); { load in the new info }
end; { with }
end; { if win 0 }
AvtInCome := 0;
end; { else }
end; { ^V }
^W : begin { switch to a window }
With ActWin do begin
StoreWinData; { Save old window }
LoadWinData(ord(ch)); { Load new window }
end;
AvtInCome := 0;
end; { ^W }
'!' : begin { Poke character on physical screen }
if AvtInCome > 1 then begin
PrmArr[7-AvtInCome] := ord(ch);
dec(AvtInCome);
end else begin
WriteATh(ord(ch),PrmArr[5],PrmArr[4],chr(PrmArr[3]));
AvtInCome := 0;
end;
end; { ! }
#39 : begin { ' } { Set cursor type }
With ActWin do
case ch of
^A : cursor := NormCursor;
^B : cursor := HiddenCursor;
^C : cursor := BigCursor;
end;
AvtInCome := 0;
end; { ' }
'*' : begin { System Pause (allow break out!) }
if ord(ch) = 0 then Pauseh(36000) { 1 hour }
else Pauseh(ord(ch));
AvtInCome := 0;
end; { * }
'/' : begin { Set or reset static mode }
case ch of
'[' : ActWin.StaticOn := True;
']' : ActWin.StaticOn := False;
end;
AvtInCome := 0;
end; { / }
'0' : begin { Highlight EOL }
ActWin.DHighEOL(ord(ch));
AvtInCome := 0;
end; { 0 }
'1' : begin { Highlight BOL }
with ActWin do begin
NormFlow := not NormFlow; { toggle it }
DHighEOL(ord(ch));
NormFlow := not NormFlow; { restore it }
end;
AvtInCome := 0;
end; { 1 }
':' : begin { Keyboard mode (no extras supported) }
(* case ch of
'0' : { normal mode (IBM) };
'1'..'4' : { other modes };
end; *)
Query_Hook(^V+':0'); { return current mode }
{ clear Keyboard buffer here }
AvtInCome := 0;
end; { : }
'=' : begin { set parser mode }
ch := chr(ord(ch) AND $1F);
case ch of
^R : Cooked := False;
^C : Cooked := True;
end;
AvtInCome := 0;
end; { = }
'?' : begin { peek at physical screen }
if AvtInCome > 1 then begin
PrmArr[3] := ord(ch);
Dec(AvtInCome);
end else begin
GetATh(ord(ch),PrmArr[3],b[2],c1);
Query_Hook(^V+'!'+chr(PrmArr[3])+ch+chr(b[2])+c1);
AvtInCome := 0;
end;
end; { ? }
^Y : begin { get the defined params for ^V^Y }
PrmArr[3] := ord(ch); { # of bytes in pattern }
AvtInCome := ord(ch);
inc(AvtInString); { add 1 to str nesting level }
if AvtInString > MaxStrNest then begin { too many strings }
if AvtInCome > 0 then begin
dec(AvtInCome);
Parse_AVT1(ch); { parse it, but not repetitous }
end else
AvtInterp := AVT1_Waiting; { exit failed-rep pattern }
end else
if ord(ch) > 0 then begin
AvtInterp := AVT1_String;
PrmArr[9] := ord(ch);
GetMem(AvtStrPtr[AvtInString],PrmArr[9]);
if AvtStrPtr[AvtInString] = nil then begin
Writeln('PAVT120: GetMem Failure.');
AvtInterp := AVT1_Waiting; { abort sequence }
AvtInCome := 0;
end;
end; { length > 0 }
exit;
end; { ^Y }
end { GetParm case }
else { if PrmArr[1] = 22 }
if PrmArr[1] = 25 then
begin
if AvtInCome = 1 then
for PrmArr[3] := ord(ch) downto 1 do
AvtTTY(chr(PrmArr[2]))
else
PrmArr[2] := ord(ch);
dec(AvtInCome);
end; { if = 25 and if=22-else}
if AvtInCome = 0 then AvtInterp := AVT1_Waiting;
end; { AVT1_Param }
Procedure AVT1_String(ch:char); {far;}
var
b : Array[1..4] of byte;
cook : boolean;
begin
if AvtInCome >= 1 then
begin
dec(AvtInCome); { Add the char to the string }
AvtStrPtr[AvtInString]^[PrmArr[3]-AvtInCome] := ch;
end
else
begin
AvtInterp := AVT1_Waiting;
b[3] := PrmArr[3];
b[4] := AvtInString;
cook := Cooked;
Cooked := False; { raw in rep pat }
for b[1] := 1 to ord(ch) do { repeat # times }
for b[2] := 1 to b[3] do { each char in string }
Parse_AVT1(AvtStrPtr[b[4]]^[b[2]]);
FreeMem(AvtStrPtr[AvtInString],PrmArr[9]); { Free it up }
dec(AvtInString);
AvtInterp := AVT1_Waiting;
Cooked := cook;
end;
end; { AVT1_String }
procedure AVT1_InANSI(ch:char); { AVT/1 must process Esc[2J clear screens }
type
str3 = string[3];
const
lastchar : char = #0; { static variable }
procedure AvtType(s:str3);
var
j : byte;
begin
AvtTTY(ESC);
for j := 1 to length(s) do
AvtTTY(s[j]);
end;
begin
case lastchar of
#0 : if ch <> '[' then
begin
AvtInterp := AVT1_Waiting;
AvtType(ch);
lastchar := #0;
exit;
end;
'[' : if ch <> '2' then
begin
AvtInterp := AVT1_Waiting;
AvtType('['+ch);
lastchar := #0;
exit;
end;
'2' : begin
if ch <> 'J' then
AvtType('[2'+ch)
else ActWin.Clear(ActWin.Attr,' ');
AvtInterp := AVT1_Waiting;
lastchar := #0;
exit;
end;
end; { case }
lastchar := ch;
end; { AVT1_InANSI }
(******************* Avatar Terminal Parser *********************)
procedure Parse_AVT1(ch:char); { AVT/1 Parser }
begin
if Awake then
begin
if Cooked then
if ch <> ^P then
begin
if InDLE then
begin
ch := chr(ord(ch) AND $3F); { strip high bits }
InDLE := False;
end;
end
else
begin
InDLE := True;
exit; { don't pass ^P on }
end; { ^P and Cooked }
AVTInterp(ch); { Interpret Any Commands }
end { Awake }
else { if not Awake }
begin
case AvtInCome of
0 : begin { ** TTY Control Code Parser ** }
if ch = #27 then
AVTInterp := ANSI_Bracket
else {$IFNDEF VT52} begin {$ENDIF}
{$IFDEF VT52}
if EightBitControl and (ch >= #$80) and (ch <= #$9F) then
ANSI_Bracket(chr(ord(ch) - $40)) { treat as Esc <ch-$40> }
else begin
{$ENDIF}
if ch in [^M, ^J, ^H, ^I, ^L, ^G] then begin
with ActWin do begin
{$IFDEF TTY_HOOK}
if not TTYCharH(ch,attr) then exit; { Can TTY continue process? }
{$ENDIF}
case ch of
^M : SetXY(1,cy); { CR }
^J : begin { LF }
if (cy = Depth) then { scroll @ bottom of region }
Scroll(1, 1,{$IFDEF VT102}st{$ELSE} 1 {$ENDIF}, Width,{$IFDEF VT102}sb{$ELSE}cy{$ENDIF}, 1)
else SetXY(cx,succ(cy));
end; { ^J }
^H : begin { Destructive BS }
SetXY(pred(cx),cy);
if Dest_BS then WriteAT(cx,cy,attr,' ');
end;
^I : GotoTab; { Move to next set tab stop }
^L : begin
Clear(7,' '); { Clear Screen }
SetXY(1,1);
end;
^G : SoundBell; { bell }
end { case }
end { with }
end else { if ch in }
if ch = ^V then
if (CurrentTerm = TermAVT0) or
(CurrentTerm = TermAVT1) then AvtInCome := 2 { sleeping AVT command? }
else AvtInterp(^V)
else { ch <> ^V } AvtInterp(ch); { ANSI/VT-nnn interpreter }
end { if ch = / if 8bit .. else }
(* ... old ...
if ch <> ^V then AvtInterp(ch) { fall back to ANSI }
else AvtInCome := 2; *)
end;
2 : begin
case ch of
^Q : AvtInCome := 1; { get query type }
GS : begin { ZZZzzzzzz.. hrumph?!? (wake up) }
Awake := True;
AvtInCome := 0;
AvtInterp := AVT1_Waiting;
end;
else
begin
(* AvtInterp(^V); { display ^Vs in ANSI mode } *)
AvtInterp(ch); { send ANSI the characters }
AvtInCome := 0;
end;
end; { case }
end; { 2 }
1 : begin { AVT/1 queries are always active }
Process_Query(ch);
AvtInCome := 0;
end;
end; { case AvtInCome }
end; { Asleep }
end; { Parse_AVT1 }
(************* Special Effects Procedures *********************)
procedure ANSI_Only; { Actually just puts Avatar to sleep w/o fallback }
begin
fallback := false;
awake := false;
AvtInterp := ANSI_Waiting;
CurrentTerm := TermANSI;
end;
procedure Level0_Simulation(fallbck:boolean);
(*
const { this is the simulation string to send via modem }
s : string[14] = ^V+'=R'+^V+^V+#1+#3+#1+#1+#25+#80+^V+^W+#1;
{ raw, Cyan Window, Activate }
*)
begin
QueryReply[4] := '0'; { now it reads "AVT0, bla blaa blabla bla bla" }
Cooked := False; { Level 0+ works in raw mode }
Fallback := fallbck; { AVT/0+ can support fallback, AVT/1 just sleeps }
Dest_BS := False; { AVT/0 doesn't have destructive backspaces }
with WinList^[0] do
begin
cattrib := 3; { Cyan }
attrib := 3; { Cyan }
WCFLf := None; { reset all specialties }
end;
ActWin.LoadWinData(0);
CurrentTerm := TermAVT0;
end;
(***************** Unit Initialization ***********************)
{$S+} Procedure InitUnit; {$S-}
const
HeapErrStr = 'PAVATAR: Fatal Error! 3K Heap Space Needed.';
begin
DESQview_Init;
if MaxAvail-8 < SizeOf(WinList) then
begin
Writeln(HeapErrStr);
runerror(203); { Heap overflow error }
Writeln('Portions Copyright 1993 Gregory P. Smith');
end;
New(WinList); { Allocate the Window Data Table }
If Winlist = nil then
begin
Writeln(HeapErrStr);
runerror(203); { Heap overflow error }
end;
ResetTerminal(ScrnColumns,ScrnLines);
end;
{$IFNDEF OVERLAY -- Normal overlayed units can't initialize themselves }
BEGIN
InitUnit; {$ENDIF}
END.