home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 5 / ctrom5b.zip / ctrom5b / PROGRAM / PASCAL / PAVT199 / PAVT150.PAS < prev    next >
Pascal/Delphi Source File  |  1993-06-13  |  51KB  |  1,463 lines

  1. (*******************************************************************)
  2. (*  Avatar level 1 Console driver.  Unit for providing a program   *)
  3. (*  with proper Avatar levels 0, 0+, and 1 emulations.             *)
  4. (*  Copyright (c) 1991 - 93 Gregory P. Smith                       *)
  5. (*  All Rights Reserved                                            *)
  6. (*-----------------------------------------------------------------*)
  7. (*  Last Update:  June  13, 1993       v 1.55                      *)
  8. (*=================================================================*)
  9. (*  Current Version # 1.50:  VT-52 & "ANSI" music working.         *)
  10. (*******************************************************************)
  11. unit PAvt150; { AVT/1 Console Driver (ANSI-BBS optional) }
  12. {$I PAVTVER.INC}
  13.  
  14. {$IFDEF OVERLAY}
  15. {$F+,O+     -- Allow overlaying of the main unit. }
  16. {$ENDIF}
  17.  
  18. INTERFACE
  19.  
  20. uses Dos, Crt,
  21.      PAvtIO, PAvtSnd;
  22.  
  23. (*-- Declaration of Functions/Procedures useable by other programs ---*)
  24.  
  25. PROCEDURE Parse_AVT1(ch:char);                          { AVT/1 Parser }
  26. PROCEDURE AvtTTY(ch:char);        { Avatar TTY w/o AVT code processing }
  27. PROCEDURE SetScreenSize(nc,nl:integer);    { use a nl X nl size screen }
  28. PROCEDURE ResetTerminal(nc,nl:integer); { Reset terminal & screen size }
  29.                                         { to nc X nl                   }
  30.  
  31.   { Select the current terminal emulation using the TermXXXX constants }
  32. PROCEDURE SetTerminal(t:TerminalType);
  33.  
  34. FUNCTION  In_Command : boolean;   { terminal is expecting more data to }
  35.                                   { complete an AVT or ANSI command    }
  36. PROCEDURE UpdateCursor(x,y:byte);  { update cursor position, passing 0 }
  37.                                    { leaves that position unchanged.   }
  38. PROCEDURE Level0_Simulation(fallbck:boolean); { Set parser for AVT/0+  }
  39. PROCEDURE ANSI_Only;    { Makes it an ANSI terminal by putting it into }
  40.                         { sleep & non-fallback mode.                   }
  41. {$IFDEF OVERLAY  -- Only needed if we're overlaying the unit }
  42. PROCEDURE InitUnit;  { Unit initialization code! Must be called before }
  43.                      { anything else or the unit will crash the system }
  44. {$ENDIF}
  45.  
  46. IMPLEMENTATION
  47.  
  48. {-- local type definitions -----------------------------------------}
  49. type
  50.   (* Data/Action Object Definitions *)
  51.   Act_WindowObj = object       { Holds the active window's data }
  52.                     x1, y1,                        { window corners }
  53.                     x2, y2,
  54.                     cx, cy,                       { cursor position }
  55.      {$IFDEF VT102} miny, maxy,            { vertical cursor limits }
  56.                     st, sb,        { top & bottom scrolling regions } {$ENDIF}
  57.                     wrap,                      { EOL wrapping style }
  58.                     cursor,                          { cursor shape }
  59.                     attr,                           { current color }
  60.                     def_attr,                       { default color }
  61.                     width,                         { width: x2-x1+1 }
  62.                     depth     : byte;              { depth: y2-y1+1 }
  63.                     NormFlow,             { foward or backward flow }
  64.                     DownLF,                     { LineFeeds go down }
  65.                     Insert,                          { Insert is on }
  66.                     UpDown,                       { write Up & Down }
  67.                     StaticOn  : boolean;        { don't move cursor }
  68.                     Procedure SetXY(x,y:byte);    { cursor position }
  69.                     Procedure SetRelXY(x,y:integer); { relative position }
  70. {$IFDEF DELAY_WRAP} Procedure WSetXY(x,y:byte);  { delayed wrap cursor pos } {$ENDIF}
  71.                     Procedure HighArea(xx1,yy1,xx2,yy2,a:byte); { win relative }
  72.                     Procedure Scroll(dir,xx1,yy1,xx2,yy2,n:byte); { "  " }
  73.                     Procedure FillArea(xx1,yy1,xx2,yy2,a:byte;c:char); { "  " }
  74.                     Procedure DDelEOL; { Flag aware Delete to EOL (inclusive) }
  75.                     Procedure DDelChar;             { Flag Aware Delete char. }
  76.                     Procedure DDelLine;       { Flag aware delete line/column }
  77.                     Procedure DInsertLine;    { Flag aware insert line/column }
  78.                     Procedure DHighEOL(a:byte); { Flag Aware Highlight to EOL }
  79.                     Procedure HighlightIt(a:byte);     { Highlight the window }
  80.                     Procedure Clear(a:byte;c:char);        { Clear the window }
  81.                     Procedure WriteAT(x,y,a:byte;c:char);        { Write char }
  82.                     Procedure LoadWinData(anum : byte);   { Load from WinList }
  83.                     Procedure StoreWinData;           { store data in WinList }
  84.                   end; { Act_WindowObj }
  85.   AvtWindowObj = object        { holds the other windows' data }
  86.                    _x1,_y1,                     { upper corner of window }
  87.                    _x2,_y2,                     { lower corner of window }
  88.                    _cx,_cy,     { relative cursor position within window }
  89.                    WCFLf,  { wrap type (bits 0-1) cursor style (bits2-3) }
  90.                            { Flow (foward | reverse bit 4) 1 = reverse   }
  91.                            { LineFeed Translation ( Normal | Up bit 5) 1 = up}
  92.                            { Insert Mode ( On | Off bit 6) 1 = on        }
  93.                            { Up&Down ( On | Off bit 7 ) 1 = on           }
  94.                    cattrib,                      { current writing color }
  95.                    attrib   : byte;            { default color of window }
  96.                    Static : boolean;                { is static mode on? }
  97.                    Procedure Init(NumCols,NumLines:integer); { set defaults }
  98.                    Procedure Set_XY(x,y:byte);         { Cursor position }
  99.                    Procedure HighlightIt(a:byte); { Highlight the window }
  100.                  end; { object }
  101.   AvtWinListType = Array[0..255] of AvtWindowObj; { Window Data Array }
  102.   AvtWinListPtr = ^AvtWinListType;
  103.  
  104. {-- local variable -------------------------------------------------}
  105. const
  106.   WinList : AvtWinListPtr = nil;    { Pointer to Avatar window data }
  107.   AWin    : byte = 0;                        { Active Avatar Window }
  108.   FlowBackWard = 16;                            { > Flow Backward   }
  109.   LineFeedUp = 32;                              { > LineFeeds go up }
  110.   InsertOn = 64;                                { > Insert Mode On  }
  111.   UpDownOn = 128;                               { > Up&Down flow    }
  112.  
  113. (* ---  AvtWindowObj's Implementations  --- *)
  114.  
  115. Procedure AvtWindowObj.Init(NumCols,NumLines:integer);
  116. begin
  117.   _x1 := 1;
  118.   _y1 := 1;
  119.   _x2 := NumCols;
  120.   _y2 := NumLines;
  121.   _cx := 1;
  122.   _cy := 1;
  123.   WCFLf := None;
  124.   cattrib := 7;
  125.   Attrib := 7;
  126.   Static := False;
  127. end;
  128.  
  129. Procedure AvtWindowObj.Set_XY(x,y:byte);
  130. var
  131.   w,d : byte;
  132. begin
  133.   w := succ(_x2-_x1); { width }
  134.   d := succ(_y2-_y1); { depth }
  135.   if x > w then _cx := w
  136.     else if x > 0 then _cx := x;
  137.   if y > d then _cy := d
  138.     else if y > 0 then _cy := y;
  139. end;
  140.  
  141. Procedure AvtWindowObj.HighlightIt(a : byte);
  142. begin
  143.   HighAreah(_x1,_y1,_x2,_y2,a);
  144. end; { HighlightIt }
  145.  
  146. (* ---  End of AvtWindowObj's Implementation  --- *)
  147.  
  148. (* ---  Act_WindowObj's Implementation --- *)
  149.  
  150. {$IFDEF DELAY_WRAP}
  151. Procedure Act_WindowObj.WSetXY(x,y:byte);
  152. begin
  153.   if x >= succ(width) then begin     { compensate for delayed EOL wrapping }
  154.     cx := succ(width);
  155.     GotoXYh(cx+x1-2, pred(cy+miny)); { don't pass x > width to the hook }
  156.     exit;
  157.   end else
  158.     if x > 0 then cx := x;
  159.   if y > depth then cy := depth
  160.     else if y > 0 then cy := y;
  161.  {$IFDEF VT102}
  162.   GotoXYh(pred(cx+x1),pred(cy+miny))
  163.  {$ELSE}
  164.   GotoXYh(pred(cx+x1),pred(cy+y1));
  165.  {$ENDIF}
  166. end;
  167. {$ENDIF}
  168.  
  169. Procedure Act_WindowObj.SetXY(x,y:byte);
  170. begin   { a 0 in x or y leaves it unchanged }
  171.   if x > width then cx := width
  172.     else if x > 0 then cx := x;
  173.   if y > depth then cy := depth
  174.     else if y > 0 then cy := y;
  175.  {$IFDEF VT102}
  176.   GotoXYh(pred(cx+x1),pred(cy+miny))
  177.  {$ELSE}
  178.   GotoXYh(pred(cx+x1),pred(cy+y1));
  179.  {$ENDIF}
  180. end;
  181.  
  182. Procedure Act_WindowObj.SetRelXY(x,y:integer);
  183. begin   { move cursor relative to current position }
  184.   x := cx + x;
  185.   y := cy + y;
  186.   if x < 1 then cx := 1
  187.     else if x > width then cx := width
  188.       else cx := x;
  189.   if y < 1 then cy := 1
  190.     else if y > depth then cy := depth
  191.       else cy := y;
  192.  {$IFDEF VT102}
  193.   GotoXYh(pred(cx+x1),pred(cy+miny));
  194.  {$ELSE}
  195.   GotoXYh(pred(cx+x1),pred(cy+y1));
  196.  {$ENDIF}
  197. end;
  198.  
  199. Procedure Act_WindowObj.HighArea(xx1,yy1,xx2,yy2,a:byte);
  200. begin
  201.   HighAreah(Pred(x1+xx1),Pred(y1+yy1),pred(x1+xx2),pred(y1+yy2),a);
  202. end;
  203.  
  204. Procedure Act_WindowObj.Scroll(dir,xx1,yy1,xx2,yy2,n:byte);
  205. begin
  206.   if n = 0 then { 0 = clear area }
  207.     if dir < 3 then
  208.       n := succ(yy2-yy1)
  209.     else n := succ(xx2-xx1);
  210.   Scrollh(dir,Pred(x1+xx1),Pred(y1+yy1),Pred(x1+xx2),Pred(y1+yy2),n,attr);
  211. end;
  212.  
  213. Procedure Act_WindowObj.FillArea(xx1,yy1,xx2,yy2,a:byte;c:char);
  214. var
  215.   g,h : byte;
  216. begin
  217.   g := Pred(x1+xx2);
  218.   h := Pred(y1+yy2);
  219.   if g > x2 then g := x2;
  220.   if h > y2 then h := y2;
  221.   FillAreah(Pred(x1+xx1),Pred(y1+yy1),g,h,a,c);
  222. end;
  223.  
  224. Procedure Act_WindowObj.DDelEOL; { Fully Aware of Direction Flags }
  225. begin
  226.   if NormFlow then
  227.     if UpDown then
  228.       FillArea(cx,cy,cx,Depth,attr,' ')
  229.     else FillArea(cx,cy,Width,cy,attr,' ')
  230.   else
  231.     if UpDown then
  232.       FillArea(cx,1,cx,cy,attr,' ')
  233.     else FillArea(1,cy,cx,cy,attr,' ');
  234. end;
  235.  
  236. Procedure Act_WindowObj.DDelChar; { Fully Flag Aware }
  237. begin
  238.   if NormFlow then
  239.     if UpDown then
  240.       Scroll(1,cx,cy,cx,Depth,1) { updown }
  241.     else Scroll(3,cx,cy,Width,cy,1) { normal }
  242.   else
  243.     if UpDown then
  244.       Scroll(2,cx,1,cx,cy,1) { rev updown }
  245.     else Scroll(4,cy,cx,cy,1,1); { reverse }
  246. end;
  247.  
  248. Procedure Act_WindowObj.DDelLine; { Flag Aware delete line }
  249. begin
  250.   if not UpDown then
  251.     Scroll(1,1,succ(cy),Width,Depth,1) { delete line }
  252.   else
  253.     Scroll(3,succ(cx),1,Width,Depth,1); { delete column }
  254. end; { ddelline }
  255.  
  256. Procedure Act_WindowObj.DInsertLine; { Flag aware insert line }
  257. begin
  258.   if not UpDown then
  259.     Scroll(2,1,cy,Width,pred(Depth),1)  { insert line }
  260.   else
  261.     Scroll(4,cx,1,pred(Width),Depth,1); { insert column }
  262. end; { dinsertline }
  263.  
  264. Procedure Act_WindowObj.DHighEOL(a : byte); { Flag Aware Highlight EOL }
  265. begin
  266.   if NormFlow then
  267.     if UpDown then
  268.       HighArea(cx,cy,cx,Depth,a) { updown }
  269.     else HighArea(cx,cy,Width,cy,a) { normal }
  270.   else
  271.     if UpDown then
  272.       HighArea(cx,1,cx,cy,a) { updown + reverse }
  273.     else HighArea(1,cy,cx,cy,a); { reverse }
  274. end;
  275.  
  276. Procedure Act_WindowObj.HighlightIt(a : byte); { highlight the window }
  277. begin
  278.   HighAreah(x1,y1,x2,y2,a);
  279. end; { HighlightIt }
  280.  
  281. Procedure Act_WindowObj.Clear(a:byte;c:char); { Clear the window }
  282. begin
  283.   FillAreah(x1,y1,x2,y2,a,c);
  284. end;
  285.  
  286. Procedure Act_WindowObj.WriteAt(x,y,a:byte;c:char); { write a character }
  287. begin
  288.  {$IFDEF VT102}
  289.   WriteATh(pred(x+x1),y+y1+miny-2,a,c); { x1.54 -- scrolling region }
  290.  {$ELSE}
  291.   WriteATh(pred(x+x1),pred(y+y1),a,c);
  292.  {$ENDIF}
  293. end;
  294.  
  295. Procedure Act_WindowObj.LoadWinData(anum : byte);
  296. begin
  297.   with WinList^[anum] do begin
  298.     x1 := _x1;  y1 := _y1;
  299.     x2 := _x2;  y2 := _y2;
  300.     cx := _cx;  cy := _cy;
  301.     width := succ(x2-x1);
  302.     depth := succ(y2-y1);
  303.     attr := cattrib;
  304.     def_attr := attrib;
  305.     wrap := WCFLf and NoWrap;
  306.     cursor := WCFLf and HiddenCursor;
  307.     NormFlow := (WCFLf and FlowBackward) = 0;
  308.     DownLF := (WCFLf and LineFeedUp) = 0;
  309.     Insert := (WCFLf and InsertOn) = InsertOn;
  310.     UpDown := (WCFLf and UpDownOn) = UpDownOn;
  311.     StaticOn := Static;
  312.   end;
  313.   {$IFDEF VT102} miny := y1;  maxy := y2;  st := y1;  sb := y2; {$ENDIF}
  314.   GotoXYh(pred(x1+cx),pred(y1+cy));
  315.   AWin := anum;
  316. end;
  317.  
  318. Procedure Act_WindowObj.StoreWinData;
  319. begin
  320.   with WinList^[AWin] do begin
  321.     _x1 := x1;  _y1 := y1;
  322.     _x2 := x2;  _y2 := y2;
  323.     _cx := cx;  _cy := cy;
  324.     cattrib := attr;
  325.     attrib := def_attr;
  326.     WCFLf := wrap or cursor or (byte(not NormFlow) shl 4) or
  327.              (byte(not DownLF) shl 5) or (byte(Insert) shl 6) or
  328.              (byte(UpDown) shl 7);
  329.     Static := StaticOn;
  330.   end;
  331. end;
  332.  
  333. (* ---  End of Act_WindowObj's Implementation  --- *)
  334.  
  335. (* ---  More locals  ----- *)
  336.  
  337. type
  338.   Arr255Type = Array[1..255] of char;
  339.  
  340. const
  341. {$IFDEF ANSI_MUSIC}
  342.   NumPrms = 180;
  343. {$ELSE}
  344.   NumPrms = 10;
  345. {$ENDIF}
  346.   AvtIncome   : byte = 0; { # of parameters expected to come }
  347.   AvtInString : byte = 0; { nesting level of ^V^Y command }
  348.   Cooked      : boolean = True;  { Parser: Raw or Cooked mode }
  349.   InDLE       : boolean = False; { Parser: last char was ^P }
  350.   Awake       : boolean = True;  { Parser: Is the interpreter awake? }
  351.   TTY_Only    : boolean = False; { in TTY only mode }
  352.   MaxStrNest  = 6;               { Maximum ^V^Y nesting level }
  353.  
  354. var
  355.   PrmArr    : Array[1..NumPrms] of byte;        { stores command parameters }
  356.   AvtStrPtr : Array[1..MaxStrNest] of ^Arr255Type; { strs storing ^V^Y cmds }
  357.   AvtInterp_Ptr : pointer absolute AvtInterp;             { for referencing }
  358.   ActWin        : Act_WindowObj;                { Active Avatar window data }
  359.  
  360. {-- Forward Interp References -------------------------------------}
  361.  
  362. {$F+}
  363. procedure AVT1_Waiting(ch:char); forward;
  364. procedure AVT1_Command(ch:char); forward;
  365. procedure AVT1_Param(ch:char); forward;
  366. procedure AVT1_String(ch:char); forward;
  367. procedure AVT1_InANSI(ch:char); forward;
  368. {$IFNDEF OVERLAY}
  369. {$F-}
  370. {$ENDIF}
  371.  
  372. {-- ANSI include file ---------------------------------------------}
  373.  
  374. {$I PAVTANSI.INC}
  375.  
  376. {-- Inner workings of terminal ------------------------------------}
  377.  
  378. function In_Command : boolean; { Is the terminal inside a command? }
  379. begin           { only check offsets, segments are the same }
  380.   In_Command := (Word(AvtInterp_Ptr) <> Word(@AVT1_Waiting)) and
  381.                 (Word(AvtInterp_Ptr) <> Word(@ANSI_Waiting)) or
  382.                 (AvtInString > 0);
  383. end;
  384.  
  385. procedure UpdateCursor(x,y:byte); { move cursor from application }
  386. begin                             { a zero restores the known position }
  387.   ActWin.SetXY(x,y);
  388. end;
  389.  
  390. procedure SetScreenSize(nc,nl:integer);
  391. var
  392.   j : integer;
  393. begin
  394.   for j := 0 to 255 do
  395.     with WinList^[j] do begin
  396.       _x1 := 1;   _y1 := 1;
  397.       _x2 := nc;  _y2 := nl;
  398.     end;
  399.   with ActWin do begin { x1.52 }
  400.     x1 := 1;    y1 := 1;
  401.     x2 := nc;   y2 := nl;
  402.    {$IFDEF VT102}
  403.     miny := 1;  maxy := nl;
  404.     st := 1;    sb := nl;
  405.    {$ENDIF}
  406.   end;
  407.   ScrnColumns := nc;
  408.   ScrnLines := nl;
  409. end;
  410.  
  411. procedure ResetTerminal(nc,nl:integer);
  412. var
  413.   j : integer;
  414. begin
  415.   ScrnColumns := nc;
  416.   ScrnLines := nl;
  417.   ANSI_Reset;
  418.   for j := 0 to 255 do       { reset all windows to the default }
  419.     WinList^[j].Init(nc,nl);
  420.   ActWin.LoadWinData(0);
  421.   AvtInCome := 0;
  422.   AvtInString := 0;
  423.   Cooked := True;
  424.   InDLE := False;
  425.   Awake := True;
  426.   TTY_Only := False;
  427.   AvtInterp := AVT1_Waiting; { waiting }
  428.   ANSI_MUSIC := True;
  429.   Fallback := False;
  430.   Dest_BS := True;
  431.   QueryReply[4] := '1'; { level 1 again }
  432. {$IFDEF VT52}
  433.   EightBitControl := False;
  434.   VT52On := False;
  435. {$ENDIF}
  436. {$IFDEF VT102}
  437.   VT102On := False;
  438.   CRtoCRLF := False;
  439.   RelativePos := False;
  440.   InQMarkCmd := False;
  441. {$ENDIF}
  442.   IgnoreNULL := False;
  443.   CurrentTerm := TermAVT1;
  444. end; { ResetTerminal }
  445.  
  446. Procedure SetTerminal(t:TerminalType);
  447. begin
  448.   ResetTerminal(ScrnColumns,ScrnLines);
  449.   case t of
  450.     TermTTY  : begin
  451.                  TTY_Only := True;
  452.                  Cooked := False;
  453.                  AvtInterp := AvtTTY;
  454.                end;
  455.     TermANSI : ANSI_Only;
  456.     TermAVT0 : Level0_Simulation(True);
  457. {   TermAVT1 : default set by ResetTerminal }
  458. {$IFDEF VT52}
  459.     TermVT52 : begin
  460.                  ANSI_Only;
  461.                  ActWin.wrap := NoWrap; { VTs don't wrap at EOL }
  462.                  VT52On := True;
  463.                  IgnoreNULL := True;    { VTs ignore the null character }
  464.                  Dest_BS := False;
  465.                  ANSI_MUSIC := False;
  466.                end;
  467. {$ENDIF} {$IFDEF VT102}
  468.     TermVT102 : begin
  469.                   ANSI_Only;
  470.                   ANSI_BBS := False;
  471.                   ActWin.Wrap := NoWrap;
  472.                   VT52On := False;
  473.                   VT102On := True;
  474.                   IgnoreNULL := True;
  475.                   Dest_BS := False;
  476.                   ANSI_MUSIC := False;
  477.                   CrtoCRLF := False;
  478.                   RelativePos := False;
  479.                 end;
  480. {$ENDIF}
  481.   end; { case }
  482.   CurrentTerm := t;
  483. end;
  484.  
  485. (*************** AVT/1 TTY Processor *************************)
  486.  
  487. procedure AvtTTY(ch:char); {far;}
  488. var
  489.   n : integer;
  490. begin
  491.   with ActWin do
  492.    begin
  493.     {$IFDEF TTY_HOOK}
  494.      if not TTYCharH(ch,attr) then exit; { continue TTY process? }
  495.     {$ENDIF}
  496.      if ch in [^G,^H,^I,^J,^M] then
  497.       case ch of
  498.          ^M : begin { CR }
  499.                 if wrap = ClockWise then begin  { cancel clockwise mode }
  500.                   wrap := None;
  501.                   NormFlow := True;
  502.                   UpDown := False;
  503.                 end;
  504.                 if NormFlow then begin
  505.                   if UpDown then
  506.                     SetXY(0,1)     { Top of screen }
  507.                   else SetXY(1,0); { left of screen } { normal }
  508.                 end else begin
  509.                   if UpDown then
  510.                     SetXY(0,255)     { bottom }
  511.                   else SetXY(255,0); { right }
  512.                 end;
  513.                 if Wrap = ZigZag then
  514.                   NormFlow := not NormFlow; { reverse the direction }
  515.               end; { ^M }
  516.          ^J : begin { LF }
  517.                 if DownLF then
  518.                  begin
  519.                    if UpDown then begin
  520.                      if cx = Width then
  521.                        Scroll(3,1,1,Width,Depth,1);
  522.                      SetRelXY(1,0) { right one column }
  523.                    end else begin
  524.                      if cy = Depth then
  525.                        Scroll(1,1,1,Width,Depth,1);
  526.                      SetRelXY(0,1); { down one line }
  527.                    end;
  528.                   end
  529.                  else { DownLF }
  530.                   begin
  531.                     if UpDown then begin
  532.                       if cx = 1 then
  533.                         Scroll(4,1,1,Width,Depth,1);
  534.                       SetRelXY(-1,0)             { left one column }
  535.                     end else begin
  536.                       if cy = 1 then
  537.                         Scroll(2,1,1,Width,Depth,1);
  538.                       SetRelXY(0,-1); { up one line }
  539.                     end;
  540.                   end; { else DownLF }
  541.               end; { ^J }
  542.          ^H : begin { BS }
  543.                 if not StaticOn then
  544.                  begin
  545.                    if NormFlow then
  546.                      if UpDown then
  547.                        SetRelXY(0,-1)
  548.                      else SetRelXY(-1,0) { normal }
  549.                    else
  550.                      if UpDown then
  551.                        SetRelXY(0,1)
  552.                      else SetRelXY(1,0); { reverse }
  553.                    if Dest_BS then WriteAT(cx,cy,Attr,' ');
  554.                  end                            { overstrike if destructive }
  555.                 else { static mode }
  556.                  begin
  557.                    if NormFlow then  { in static or insert on BS deletes }
  558.                      if UpDown then
  559.                        Scroll(1,cx,cy,cx,Depth,1)
  560.                      else Scroll(3,cx,cy,Width,cy,1)
  561.                    else
  562.                      if UpDown then
  563.                        Scroll(2,cx,1,cx,cy,1)
  564.                      else Scroll(4,1,cy,cx,cy,1);
  565.                  end;
  566.               end; { ^H }
  567.          ^I : begin { Tab 8 }
  568.                 if NormFlow then
  569.                   if UpDown then
  570.                     SetRelXY(0,8)
  571.                   else SetRelXY(8,0)   { normal }
  572.                 else
  573.                   if UpDown then
  574.                     SetRelXY(0,-8)
  575.                   else SetRelXY(-8,0); { reverse }
  576.               end; { ^I }
  577.          ^G : begin { beep }
  578.                 if ((Sound_Stat and 1) = 1) then { bell on }
  579.                   SoundBell;
  580.               end; { ^G }
  581.       end { case }
  582.      else { if ch in ... }
  583.       begin
  584.         if (ch = #0) and IgnoreNULL then exit;  { Ignore the null character }
  585.         if Insert then begin
  586.           if NormFlow then begin
  587.             if UpDown then
  588.               if cy < pred(Depth) then
  589.                 Scroll(2,cx,cy,cx,Depth,1)
  590.             else       { updown }
  591.               if cx < pred(Width) then
  592.                 Scroll(4,cx,cy,Width,cy,1);
  593.           end else begin { normflow }
  594.             if UpDown then
  595.               if cy > 1 then
  596.                 Scroll(1,cx,1,cx,cy,1)
  597.             else { updown }
  598.               if cx > 1 then
  599.                 Scroll(3,1,cy,cx,cy,1);
  600.           end; { normflow }
  601.         end; { insert }
  602.         WriteAT(cx,cy,Attr,ch); { -- write the char -- }
  603.         if not StaticOn then
  604.          if NormFlow then
  605.            if UpDown then begin
  606.              if cy < Depth then
  607.                SetRelXY(0,1)
  608.              else begin
  609.                if DownLF then n := 1
  610.                  else n := -1;
  611.                if wrap <= ZigZag then   { wrap in [None, ZigZag] }
  612.                  if DownLF and (cx = Width) then
  613.                    Scroll(3,1,1,Width,Depth,1)
  614.                  else if (not DownLF) and (cx = 1)  then
  615.                    Scroll(4,1,1,Width,Depth,1);
  616.                case wrap of
  617.                  None       : SetRelXY(n,-255);
  618.                  ZigZag     : begin
  619.                                 SetRelXY(n,255);
  620.                                 NormFlow := False;
  621.                               end;
  622.                  ClockWise  : begin
  623.                                 SetRelXY(-1,255);
  624.                                 NormFlow := False;
  625.                                 UpDown := False; {  <--- direction }
  626.                                 { exit; { no scroll }
  627.                               end;
  628.                  { NoWrap     : exit; { don't do anything! }
  629.                end; { case wrap }
  630.              end; { cy < Depth .. else }
  631.            end else begin { UpDown }
  632.              if cx < Width then
  633.                SetRelXY(1,0)
  634.              else begin
  635.                if DownLF then n := 1
  636.                   else n := -1;
  637.                if wrap <= ZigZag then   { if wrap in [None, ZigZag] }
  638.                  if DownLF and (cy = Depth) then
  639.                    Scroll(1,1,1,Width,Depth,1)
  640.                  else if (not DownLF) and (cy = 1) then
  641.                    Scroll(2,1,1,Width,Depth,1);
  642.                case wrap of
  643.                  None       : SetRelXY(-255,n);
  644.                  ZigZag     : begin
  645.                                 SetRelXY(255,n);
  646.                                 NormFlow := False;
  647.                               end;
  648.                  ClockWise  : begin
  649.                                 SetRelXY(255,1);
  650.                                 NormFlow := True;      {   |            }
  651.                                 UpDown := True;        {   V  direction }
  652.                                 { exit; { no scroll }
  653.                               end;
  654.                  { NoWrap     : exit; { don't do anything! }
  655.                end; { case wrap }
  656.              end; { cx < Width .. else }
  657.            end { UpDown }
  658.          else { NormFlow }
  659.            if UpDown then begin
  660.              if cy > 1 then
  661.                SetRelXY(0,-1)
  662.              else begin
  663.                if DownLF then n := 1
  664.                  else n := -1;
  665.                if wrap <= ZigZag then   { wrap in [None, ZigZag] }
  666.                  if DownLF and (cx = Width) then
  667.                    Scroll(3,1,1,Width,Depth,1)
  668.                  else if (not DownLF) and (cx = 1) then
  669.                    Scroll(4,1,1,Width,Depth,1);
  670.                case wrap of
  671.                  None       : SetRelXY(n,255);
  672.                  ZigZag     : begin
  673.                                 SetRelXY(n,-255);
  674.                                 NormFlow := True;
  675.                               end;
  676.                  ClockWise  : begin
  677.                                 SetRelXY(1,-255);
  678.                                 NormFlow := True;
  679.                                 UpDown := False; { ---> direction }
  680.                                 { exit; { no scroll }
  681.                               end;
  682.                  { NoWrap     : exit; { don't do anything! }
  683.                end; { case wrap }
  684.              end; { cy > 1 .. else }
  685.            end else begin { UpDown }
  686.              if cx > 1 then
  687.                SetRelXY(-1,0)
  688.              else begin
  689.                if DownLF then n := 1
  690.                  else n := -1;
  691.                if wrap <= ZigZag then   { wrap in [None, ZigZag] }
  692.                  if DownLF and (cy = Depth) then
  693.                    Scroll(1,1,1,Width,Depth,1)
  694.                  else if (not DownLF) and (cy = 1) then
  695.                    Scroll(2,1,1,Width,Depth,1);
  696.                case wrap of
  697.                  None       : SetRelXY(255,n);
  698.                  ZigZag     : begin
  699.                                 SetRelXY(-255,n);
  700.                                 NormFlow := True;
  701.                               end;
  702.                  ClockWise  : begin
  703.                                 SetRelXY(-255,-1);
  704.                                 NormFlow := False;
  705.                                 UpDown := True; { ^ direction }
  706.                                 { exit; { no scroll }
  707.                               end;
  708.                  { NoWrap     : exit; { don't do anything! }
  709.                end; { case wrap }
  710.              end; { cx > 1 .. else }
  711.            end; { UpDown }
  712.        end; { if ch in ... else (write the char) }
  713.    end; { With ActWin }
  714. end; { AvtTTY }
  715.  
  716. (*************** AVT/1 Query Handler *************************)
  717.  
  718. Procedure Process_Query(ch : char);
  719. type
  720.   str2 = string[2];
  721.  
  722.  Function DLEch(c:char): str2;  { escape the proper characters }
  723.  begin
  724.    if Cooked and (c < #32) then
  725.     DLEch := ^P + chr(ord(c) or $40)
  726.    else DLEch := c;
  727.  end;
  728.  
  729. begin
  730.   with ActWin do
  731.    begin
  732.      case chr(ord(ch) and $3F) of
  733.        ^A,^B : begin  { return current color }
  734.                  Query_Hook(^V+^A+DLEch(chr(Attr)));
  735.                end;
  736.        ^H : begin  { return cursor position }
  737.               Query_Hook(^V+DLEch(^H)+DLEch(chr(cy))+DLEch(chr(cx)));
  738.             end;
  739.        ^Q : begin  { terminal type query }
  740.               Query_Hook(QueryReply);
  741.             end;
  742.        ^V : begin  { return current window setup }
  743.               Query_Hook(^V+^V+DLEch(chr(AWin))+DLEch(chr(Def_Attr))+
  744.                          DLEch(chr(y1))+DLEch(chr(x1))+DLEch(chr(y2))+
  745.                          DLEch(chr(x2))); { a define window command }
  746.             end;
  747.        ^W : begin  { return current window }
  748.               Query_Hook(^V+^W+DLEch(chr(AWin)));
  749.             end;
  750.        FS,GS : begin  { return sleep mode }
  751.                  if Awake then
  752.                   Query_Hook(^V+DLEch(GS))
  753.                  else Query_Hook(^V+DLEch(FS));
  754.                end;
  755.        RS,US : begin  { return vertical mode }
  756.                  if UpDown then
  757.                   Query_Hook(^V+DLEch(RS))
  758.                  else Query_Hook(^V+DLEch(US));
  759.                end;
  760.        '"','$',
  761.        '#' : begin  { return eol wrap type }
  762.                case wrap of
  763.                  None : Query_Hook(^V+'$');
  764.                  NoWrap : Query_Hook(^V+'"');
  765.                  ClockWise : Query_Hook(^V+DLEch(^O));
  766.                  ZigZag : Query_Hook(^V+'#');
  767.                end;
  768.              end;
  769.        '%','&' : begin  { return linefeed type }
  770.                    if DownLF then
  771.                     Query_Hook(^V+'&')
  772.                    else Query_Hook(^V+'%');
  773.                  end;
  774.        '(',')' : begin  { return flow direction }
  775.                    if NormFlow then
  776.                     Query_Hook(^V+'(')
  777.                    else Query_Hook(^V+')');
  778.                  end;
  779.        ':' : begin  { return keyboard type }
  780.                Query_Hook(^V+':0');
  781.              end;
  782.        '=' : begin  { return cooked/raw status }
  783.                if Cooked then
  784.                 Query_Hook(^V+'=C')
  785.                else Query_Hook(^V+'=R');
  786.              end;
  787.      end; { case } { all queries were found in AVATAR.SYS 0.10a }
  788.    end; { with }
  789. end; { Process_Query }
  790.  
  791. (*************** Avatar level 1 Interpreter ******************)
  792.  
  793. procedure AVT1_Waiting(ch:char); {far;}
  794. begin
  795.   if ch > #27 then
  796.    begin
  797. {$IFDEF VT52}
  798.      if VT52On and EightBitControl and Fallback and
  799.         ((ch >= #$80) and (ch <= #$9F)) and
  800.         (AVTInterp_Ptr = @AVT1_Waiting) then ANSI_Bracket(chr(ord(ch) - $40))
  801.      else {$ENDIF}          { process 8 bit control chars }
  802.       AvtTTY(ch); { TTY char }
  803.    end
  804.   else
  805.    begin
  806.      case ch of
  807.        ^V : AVTInterp := AVT1_Command;
  808.        ^L : begin
  809.               with ActWin do
  810.                begin
  811.                  Clear(Def_Attr,' '); { ClrScr }
  812.                  Attr := Def_Attr;
  813.                  SetXY(1,1);
  814.                  Insert := False; { Turn Off Insert }
  815.                  exit;
  816.                end; { with }
  817.             end;
  818.        ^Y : begin
  819.               AvtInterp := AVT1_Param;
  820.               AvtInCome := 2; { expect 2 more params. }
  821.             end;
  822.       ESC : begin
  823.               if Fallback and (AvtInString = 0) then
  824.                AvtInterp := ANSI_Bracket
  825.               else
  826.                AvtInterp := AVT1_InANSI; { for Esc[2J processing }
  827.             end;
  828.       else { case }
  829.        begin
  830.          AvtTTY(ch);
  831.          exit;
  832.        end; { case else }
  833.      end; { case }
  834.      PrmArr[1] := ord(ch);  { put command in parameter array }
  835.    end; { ch <= #27 }
  836. end;
  837.  
  838. procedure AVT1_Command(ch:char); {far;}
  839. begin                                    { primary interpretation phase }
  840.   AvtInterp := AVT1_Waiting; { waiting }
  841.   PrmArr[2] := ord(ch); { store the command }
  842.   if not (ch in [^V,^W,^Y]) then ActWin.Insert := False; { no insert }
  843.   case ch of   { order of frequency. }
  844.     ^A : begin  { set attribute }
  845.            AvtInCome := 1;
  846.            AvtInterp := AVT1_Param;
  847.          end;
  848.     ^H : begin  { set cursor position }
  849.            AvtInCome := 2;
  850.            AvtInterp := AVT1_Param;
  851.          end;
  852.     ^B : begin  { turn blink on }
  853.            with ActWin do
  854.             Attr := Attr or $80; { blink bit on }
  855.          end;
  856.     ^E : begin  { move cursor one column left }
  857.            with ActWin do
  858.             SetRelXY(-1,0);
  859.          end;
  860.     ^F : begin  { Move cursor one column right }
  861.            with ActWin do
  862.             SetRelXY(1,0);
  863.          end;
  864.     ^C : begin  { move cursor one line up }
  865.            with ActWin do
  866.             SetRelXY(0,-1);
  867.          end;
  868.     ^D : begin  { move cursor one line down }
  869.            with ActWin do
  870.             SetRelXY(0,1);
  871.          end;
  872.     ^J,^K : begin  { scroll up/down }
  873.            AvtInCome := 5;
  874.            AvtInterp := AVT1_Param;
  875.            if ch = ^J then PrmArr[7] := 1 else PrmArr[7] := 2;
  876.          end;
  877.     ^L,^S : begin  { clear an area / make a sound }
  878.            AvtInCome := 3;
  879.            AvtInterp := AVT1_Param;
  880.          end;
  881.     ^I : begin  { turn insert on }
  882.            ActWin.Insert := True; { guess! }
  883.          end;
  884.     ^M : begin  { initalize an area }
  885.            AvtInCome := 4;
  886.            AvtInterp := AVT1_Param;
  887.          end;
  888.     ^G : begin  { clear to EOL }
  889.            ActWin.DDelEOL; { easy huh? }
  890.          end;
  891.     ^N : begin  { delete character }
  892.            ActWin.DDelChar; { another easy one! }
  893.          end;
  894.     ^V : begin  { define a window }
  895.            AvtInCome := 6;
  896.            AvtInterp := AVT1_Param;
  897.          end;
  898.     ^W : begin  { activate window }
  899.            AvtInCome := 1;
  900.            AvtInterp := AVT1_Param;
  901.          end;
  902.    '-' : begin  { delete line }
  903.            ActWin.DDelLine; { easy again?! }
  904.          end;
  905.    '+' : begin { insert line }
  906.            ActWin.DInsertLine; { guess what! }
  907.          end;
  908.    '.' : begin { delete column }
  909.            with ActWin do
  910.             begin
  911.               UpDown := not UpDown; { toggle it }
  912.               DDelLine; { now a column... }
  913.               UpDown := not UpDown; { restore it }
  914.             end;
  915.          end;
  916.    ',' : begin { insert column }
  917.            with ActWin do
  918.             begin
  919.               UpDown := not UpDown; { toggle it }
  920.               DInsertLine; { now a column... }
  921.               UpDown := not UpDown; { restore it }
  922.             end;
  923.          end;
  924.    '>','<' : begin { scroll right/left }
  925.            AvtInCome := 5;
  926.            AvtInterp := AVT1_Param;
  927.            if ch = '<' then PrmArr[7] := 3 else PrmArr[7] := 4;
  928.          end;
  929.     ^R : begin { reset the driver }
  930.            AvtInCome := 0;
  931.            if CurrentTerm <> TermAVT0 then { level 0 can't be reset to 1 }
  932.             ResetTerminal(ScrnColumns,ScrnLines);
  933.          end;
  934.    '"' : begin { Don't wrap at EOL }
  935.            ActWin.wrap := NoWrap;
  936.          end;
  937.    '#' : begin { Switch Direction at EOL wrap (ZigZag) }
  938.            ActWin.wrap := ZigZag;
  939.          end;
  940.    '$' : begin { Wrap at EOL (normal) }
  941.            ActWin.wrap := None; { normal }
  942.          end;
  943.    '%' : begin { Reverse LF action (Up) }
  944.            ActWin.DownLF := False;
  945.          end;
  946.    '&' : begin { Normalize LF action (Down) }
  947.            ActWin.DownLF := True; { down }
  948.          end;
  949.    '(' : begin { Do Not Print In Reverse }
  950.            ActWin.NormFlow := True; { foward }
  951.          end;
  952.    ')' : begin { Print in Reverse }
  953.            ActWin.NormFlow := False; { Reverse! }
  954.          end;
  955.     RS : begin { Start vertical mode }
  956.            ActWin.UpDown := True; { vertical }
  957.          end;
  958.     US : begin { End vertical mode (horizontal) }
  959.            ActWin.UpDown := False; { horizontal }
  960.          end;
  961.     ^O : begin { Turn Clockwise mode on. }
  962.            ActWin.wrap := Clockwise; { guess! }
  963.          end;
  964.     ^Q,^T : begin { Query the driver, Highlight Cursor Position }
  965.            AvtInCome := 1;
  966.            AvtInterp := AVT1_Param;
  967.          end;
  968.    '!' : begin { Poke char on screen }
  969.            AvtInCome := 4;
  970.            AvtInterp := AVT1_Param;
  971.          end;
  972.    '?',^U : begin { Peek at char on screen, highlight window }
  973.               AvtInCome := 2;
  974.               AvtInterp := AVT1_Param;
  975.             end;
  976.    '0','1',':',        { Highlight EOL,BOL, Set Keyboard mode, }
  977.    '=','/','*',
  978.    { ' } #39 : begin { Parser Mode (cook|Raw), (re)set static mode, }
  979.            AvtInCome := 1; { Make System pause, Cursor type }
  980.            AvtInterp := AVT1_Param;
  981.          end;
  982.     ^Y : begin { repeat AVT pattern }
  983.            AvtInCome := 255; { undefined as of yet }
  984.            AvtInterp := AVT1_Param;
  985.          end;
  986.     ^X : begin { Flush Input }
  987.            FlushInputh;
  988.          end;
  989.    FS : begin { put interpreter to sleep. }
  990.            Awake := False;  { ZZZZZZZZZzzzzzzzzzzz....... }
  991.            PrmArr[1] := 0;  { sleeping }
  992.            AvtInterp := ANSI_Waiting;  { ANSI is lower terminal }
  993.          end;
  994. (*   ^P,^Z,#27,       Commented out as it only adds dead code
  995.    SP,'2'..'9',';' : { NOP, <reserved> (for etc.) } ; *)
  996.   end; { case ch of }
  997. end; { AVT1_Command }
  998.  
  999. Procedure AVT1_Param(ch:char); {far;}
  1000. var
  1001.   b : Array[1..2] of byte;
  1002.   c1 : char absolute b;    { for referencing purposes }
  1003.   i1,i2 : integer;
  1004. begin
  1005.   if PrmArr[1] = 22 then { if ^V then }
  1006.   case chr(PrmArr[2]) of
  1007.     ^A : begin { Set Attribute }
  1008.            ActWin.Attr := ord(ch) AND $7F;
  1009.            AvtInCome := 0;
  1010.          end;
  1011.     ^H : begin
  1012.            if AvtInCome = 1 then
  1013.             ActWin.SetXY(ord(ch),PrmArr[3])
  1014.             else
  1015.              PrmArr[5-AvtInCome] := ord(ch);
  1016.            dec(AvtInCome);
  1017.          end;
  1018.    ^J,^K,'<','>' : begin { scroll up/down/left/right }
  1019.            if AvtInCome > 1 then
  1020.             begin
  1021.               PrmArr[8-AvtInCome] := ord(ch);
  1022.               dec(AvtInCome);
  1023.             end
  1024.            else
  1025.             begin             { dir   ,  x1   ,    y1   }
  1026.               ActWin.Scroll(PrmArr[7],PrmArr[5],PrmArr[4],
  1027.                ord(ch),PrmArr[6],PrmArr[3]);  { x2, y2, #lines }
  1028.               AvtInCome := 0;
  1029.             end;
  1030.          end; { ^J/^K }
  1031.     ^L : begin { clear area }
  1032.            if AvtInCome > 1 then
  1033.             begin
  1034.               PrmArr[6-AvtInCome] := ord(ch);
  1035.               dec(AvtInCome);
  1036.             end
  1037.            else
  1038.             begin
  1039.               with ActWin do
  1040.                begin
  1041.                  FillArea(cx,cy,pred(cx+ord(ch)),
  1042.                           pred(cy+PrmArr[4]),PrmArr[3],' ');
  1043.                  Attr := PrmArr[3];
  1044.                end;
  1045.               AvtInCome := 0;
  1046.             end;
  1047.          end;
  1048.     ^M : begin { init area }
  1049.            if AvtInCome > 1 then
  1050.             begin
  1051.               PrmArr[7-AvtInCome] := ord(ch);
  1052.               dec(AvtInCome);
  1053.             end
  1054.            else
  1055.             begin
  1056.               with ActWin do
  1057.                begin
  1058.                  FillArea(cx,cy,pred(cx+ord(ch)),
  1059.                           pred(cy+PrmArr[5]),PrmArr[3],
  1060.                           chr(PrmArr[4]));
  1061.                  Attr := PrmArr[3];
  1062.                end;
  1063.               AvtInCome := 0;
  1064.             end;
  1065.          end;
  1066.     ^Q : begin { Query the driver }
  1067.            Process_Query(ch);
  1068.            AvtInCome := 0;
  1069.          end;
  1070.     ^S : begin { Sound a tone }
  1071.            if AvtInCome > 1 then
  1072.             begin
  1073.               PrmArr[6-AvtInCome] := ord(ch);
  1074.               Dec(AvtInCome);
  1075.             end
  1076.            else
  1077.             begin       { note  , octave  , duration }
  1078.               if ((Sound_Stat and $02) = 2) then { Sound on }
  1079.                 AvtSound(PrmArr[3],PrmArr[4],ord(ch));
  1080.               AvtInCome := 0;
  1081.             end;
  1082.          end;
  1083.     ^T : begin { highlight cursor position }
  1084.            with ActWin do
  1085.             HighArea(cx,cy,cx,cy,ord(ch));
  1086.            AvtInCome := 0;
  1087.          end;
  1088.     ^U : begin { highlight a window }
  1089.            if AvtInCome > 1 then begin
  1090.              PrmArr[5-AvtInCome] := ord(ch);
  1091.              Dec(AvtInCome);
  1092.            end else begin
  1093.              WinList^[PrmArr[3]].HighlightIt(ord(ch));
  1094.              AvtInCome := 0;
  1095.            end; { else }
  1096.          end;
  1097.     ^V : begin { Define a window! }
  1098.            if AvtInCome > 1 then begin
  1099.              PrmArr[9-AvtInCome] := ord(ch);
  1100.              Dec(AvtInCome);
  1101.            end else begin
  1102.              if PrmArr[3] > 0 then begin { 0 is not redefinable }
  1103.                with WinList^[PrmArr[3]] do begin
  1104.                  if PrmArr[3] = AWin then begin  { change the active window }
  1105.                    with ActWin do begin
  1106.                      i1 := pred(x1+cx)-PrmArr[6];
  1107.                      i2 := pred(y1+cy)-PrmArr[5];
  1108.                    end;
  1109.                    if i1 < 1 then i1 := 1; { snap to closest }
  1110.                    if i2 < 1 then i2 := 1; { pt. in window   }
  1111.                    if i1 > (ord(ch)-PrmArr[6]) then
  1112.                      i1 := ord(ch)-PrmArr[6];
  1113.                    if i2 > (ord(ch)-PrmArr[5]) then
  1114.                      i2 := ord(ch)-PrmArr[5];
  1115.                    Set_XY(i1,i2);
  1116.                  end else Set_XY(1,1); { init cursor at 1,1 otherwise }
  1117.                  _x1 := PrmArr[6];
  1118.                  _y1 := PrmArr[5];
  1119.                  _x2 := ord(ch);
  1120.                  _y2 := PrmArr[7];
  1121.                  attrib := PrmArr[4];
  1122.                  cattrib := attrib;
  1123.                  if PrmArr[3] = AWin then
  1124.                    ActWin.LoadWinData(AWin); { load in the new info }
  1125.                end; { with }
  1126.              end; { if win 0 }
  1127.              AvtInCome := 0;
  1128.            end; { else }
  1129.          end; { ^V }
  1130.     ^W : begin { switch to a window }
  1131.            With ActWin do begin
  1132.              StoreWinData;         { Save old window }
  1133.              LoadWinData(ord(ch)); { Load new window }
  1134.            end;
  1135.            AvtInCome := 0;
  1136.          end; { ^W }
  1137.    '!' : begin { Poke character on physical screen }
  1138.            if AvtInCome > 1 then begin
  1139.              PrmArr[7-AvtInCome] := ord(ch);
  1140.              dec(AvtInCome);
  1141.            end else begin
  1142.              WriteATh(ord(ch),PrmArr[5],PrmArr[4],chr(PrmArr[3]));
  1143.              AvtInCome := 0;
  1144.            end;
  1145.          end; { ! }
  1146.    #39 : begin { ' } { Set cursor type }
  1147.            With ActWin do
  1148.              case ch of
  1149.                ^A : cursor := NormCursor;
  1150.                ^B : cursor := HiddenCursor;
  1151.                ^C : cursor := BigCursor;
  1152.              end;
  1153.            AvtInCome := 0;
  1154.          end; { ' }
  1155.    '*' : begin { System Pause (allow break out!) }
  1156.            if ord(ch) = 0 then Pauseh(36000) { 1 hour }
  1157.              else Pauseh(ord(ch));
  1158.            AvtInCome := 0;
  1159.          end; { * }
  1160.    '/' : begin { Set or reset static mode }
  1161.            case ch of
  1162.              '[' : ActWin.StaticOn := True;
  1163.              ']' : ActWin.StaticOn := False;
  1164.            end;
  1165.            AvtInCome := 0;
  1166.          end; { / }
  1167.    '0' : begin { Highlight EOL }
  1168.            ActWin.DHighEOL(ord(ch));
  1169.            AvtInCome := 0;
  1170.          end; { 0 }
  1171.    '1' : begin { Highlight BOL }
  1172.            with ActWin do begin
  1173.               NormFlow := not NormFlow; { toggle it }
  1174.               DHighEOL(ord(ch));
  1175.               NormFlow := not NormFlow; { restore it }
  1176.            end;
  1177.            AvtInCome := 0;
  1178.          end; { 1 }
  1179.    ':' : begin { Keyboard mode (no extras supported) }
  1180.         (* case ch of
  1181.              '0' : { normal mode (IBM) };
  1182.              '1'..'4' : { other modes };
  1183.            end; *)
  1184.            Query_Hook(^V+':0'); { return current mode }
  1185.            { clear Keyboard buffer here }
  1186.            AvtInCome := 0;
  1187.          end; { : }
  1188.    '=' : begin { set parser mode }
  1189.            ch := chr(ord(ch) AND $1F);
  1190.            case ch of
  1191.              ^R : Cooked := False;
  1192.              ^C : Cooked := True;
  1193.            end;
  1194.            AvtInCome := 0;
  1195.          end; { = }
  1196.    '?' : begin { peek at physical screen }
  1197.            if AvtInCome > 1 then begin
  1198.              PrmArr[3] := ord(ch);
  1199.              Dec(AvtInCome);
  1200.            end else begin
  1201.              GetATh(ord(ch),PrmArr[3],b[2],c1);
  1202.              Query_Hook(^V+'!'+chr(PrmArr[3])+ch+chr(b[2])+c1);
  1203.              AvtInCome := 0;
  1204.            end;
  1205.          end; { ? }
  1206.     ^Y : begin { get the defined params for ^V^Y }
  1207.            PrmArr[3] := ord(ch); { # of bytes in pattern }
  1208.            AvtInCome := ord(ch);
  1209.            inc(AvtInString); { add 1 to str nesting level }
  1210.            if AvtInString > MaxStrNest then begin { too many strings }
  1211.              if AvtInCome > 0 then begin
  1212.                dec(AvtInCome);
  1213.                Parse_AVT1(ch); { parse it, but not repetitous }
  1214.              end else
  1215.                AvtInterp := AVT1_Waiting; { exit failed-rep pattern }
  1216.            end else
  1217.              if ord(ch) > 0 then begin
  1218.                AvtInterp := AVT1_String;
  1219.                PrmArr[9] := ord(ch);
  1220.                GetMem(AvtStrPtr[AvtInString],PrmArr[9]);
  1221.                if AvtStrPtr[AvtInString] = nil then begin
  1222.                   Writeln('PAVT120: GetMem Failure.');
  1223.                   AvtInterp := AVT1_Waiting; { abort sequence }
  1224.                   AvtInCome := 0;
  1225.                end;
  1226.              end; { length > 0 }
  1227.            exit;
  1228.          end; { ^Y }
  1229.   end { GetParm case }
  1230.   else { if PrmArr[1] = 22 }
  1231.    if PrmArr[1] = 25 then
  1232.     begin
  1233.       if AvtInCome = 1 then
  1234.        for PrmArr[3] := ord(ch) downto 1 do
  1235.         AvtTTY(chr(PrmArr[2]))
  1236.        else
  1237.         PrmArr[2] := ord(ch);
  1238.       dec(AvtInCome);
  1239.     end; { if = 25 and if=22-else}
  1240.   if AvtInCome = 0 then AvtInterp := AVT1_Waiting;
  1241. end; { AVT1_Param }
  1242.  
  1243. Procedure AVT1_String(ch:char); {far;}
  1244. var
  1245.   b : Array[1..4] of byte;
  1246.   cook : boolean;
  1247. begin
  1248.   if AvtInCome >= 1 then
  1249.    begin
  1250.      dec(AvtInCome);     { Add the char to the string }
  1251.      AvtStrPtr[AvtInString]^[PrmArr[3]-AvtInCome] := ch;
  1252.    end
  1253.   else
  1254.    begin
  1255.      AvtInterp := AVT1_Waiting;
  1256.      b[3] := PrmArr[3];
  1257.      b[4] := AvtInString;
  1258.      cook := Cooked;
  1259.      Cooked := False; { raw in rep pat }
  1260.      for b[1] := 1 to ord(ch) do { repeat # times }
  1261.       for b[2] := 1 to b[3] do { each char in string }
  1262.        Parse_AVT1(AvtStrPtr[b[4]]^[b[2]]);
  1263.      FreeMem(AvtStrPtr[AvtInString],PrmArr[9]); { Free it up }
  1264.      dec(AvtInString);
  1265.      AvtInterp := AVT1_Waiting;
  1266.      Cooked := cook;
  1267.    end;
  1268. end; { AVT1_String }
  1269.  
  1270. procedure AVT1_InANSI(ch:char); { AVT/1 must process Esc[2J clear screens }
  1271. type
  1272.   str3 = string[3];
  1273. const
  1274.   lastchar : char = #0; { static variable }
  1275.  
  1276.  procedure AvtType(s:str3);
  1277.  var
  1278.    j : byte;
  1279.  begin
  1280.    AvtTTY(ESC);
  1281.    for j := 1 to length(s) do
  1282.     AvtTTY(s[j]);
  1283.  end;
  1284.  
  1285. begin
  1286.   case lastchar of
  1287.     #0  : if ch <> '[' then
  1288.            begin
  1289.              AvtInterp := AVT1_Waiting;
  1290.              AvtType(ch);
  1291.              lastchar := #0;
  1292.              exit;
  1293.            end;
  1294.     '[' : if ch <> '2' then
  1295.            begin
  1296.              AvtInterp := AVT1_Waiting;
  1297.              AvtType('['+ch);
  1298.              lastchar := #0;
  1299.              exit;
  1300.            end;
  1301.     '2' : begin
  1302.             if ch <> 'J' then
  1303.              AvtType('[2'+ch)
  1304.             else ActWin.Clear(ActWin.Attr,' ');
  1305.             AvtInterp := AVT1_Waiting;
  1306.             lastchar := #0;
  1307.             exit;
  1308.           end;
  1309.   end; { case }
  1310.   lastchar := ch;
  1311. end; { AVT1_InANSI }
  1312.  
  1313. (******************* Avatar Terminal Parser *********************)
  1314.  
  1315. procedure Parse_AVT1(ch:char); { AVT/1 Parser }
  1316. begin
  1317.   if Awake then
  1318.    begin
  1319.      if Cooked then
  1320.       if ch <> ^P then
  1321.        begin
  1322.          if InDLE then
  1323.           begin
  1324.             ch := chr(ord(ch) AND $3F); { strip high bits }
  1325.             InDLE := False;
  1326.           end;
  1327.        end
  1328.       else
  1329.        begin
  1330.          InDLE := True;
  1331.          exit; { don't pass ^P on }
  1332.        end; { ^P and Cooked }
  1333.      AVTInterp(ch); { Interpret Any Commands }
  1334.    end { Awake }
  1335.   else { if not Awake }
  1336.    begin
  1337.      case AvtInCome of
  1338.        0 : begin  { ** TTY Control Code Parser ** }
  1339.              if ch = #27 then
  1340.                AVTInterp := ANSI_Bracket
  1341.              else {$IFNDEF VT52} begin {$ENDIF}
  1342.             {$IFDEF VT52}
  1343.              if EightBitControl and (ch >= #$80) and (ch <= #$9F) then
  1344.                ANSI_Bracket(chr(ord(ch) - $40))  { treat as Esc <ch-$40> }
  1345.              else begin
  1346.             {$ENDIF}
  1347.              if ch in [^M, ^J, ^H, ^I, ^L, ^G] then begin
  1348.                with ActWin do begin
  1349.                 {$IFDEF TTY_HOOK}
  1350.                  if not TTYCharH(ch,attr) then exit; { Can TTY continue process? }
  1351.                 {$ENDIF}
  1352.                  case ch of
  1353.                    ^M : SetXY(1,cy); { CR }
  1354.                    ^J : begin { LF }
  1355.                           if (cy = Depth) then { scroll @ bottom of region }
  1356.                             Scroll(1, 1,{$IFDEF VT102}st{$ELSE} 1 {$ENDIF}, Width,{$IFDEF VT102}sb{$ELSE}cy{$ENDIF}, 1)
  1357.                           else SetXY(cx,succ(cy));
  1358.                         end; { ^J }
  1359.                    ^H : begin { Destructive BS }
  1360.                           SetXY(pred(cx),cy);
  1361.                           if Dest_BS then WriteAT(cx,cy,attr,' ');
  1362.                         end;
  1363.                    ^I : GotoTab; { Move to next set tab stop }
  1364.                    ^L : begin
  1365.                           Clear(7,' '); { Clear Screen }
  1366.                           SetXY(1,1);
  1367.                         end;
  1368.                    ^G : SoundBell; { bell }
  1369.                  end  { case }
  1370.                end  { with }
  1371.              end else { if ch in }
  1372.                if ch = ^V then
  1373.                  if (CurrentTerm = TermAVT0) or
  1374.                     (CurrentTerm = TermAVT1) then AvtInCome := 2 { sleeping AVT command? }
  1375.                  else AvtInterp(^V)
  1376.                else { ch <> ^V } AvtInterp(ch); { ANSI/VT-nnn interpreter }
  1377.              end  { if ch = / if 8bit .. else }
  1378.                (* ... old ...
  1379.                if ch <> ^V then AvtInterp(ch) { fall back to ANSI }
  1380.                  else AvtInCome := 2; *)
  1381.            end;
  1382.        2 : begin
  1383.              case ch of
  1384.                ^Q : AvtInCome := 1; { get query type }
  1385.                GS : begin  { ZZZzzzzzz.. hrumph?!?  (wake up) }
  1386.                       Awake := True;
  1387.                       AvtInCome := 0;
  1388.                       AvtInterp := AVT1_Waiting;
  1389.                     end;
  1390.              else
  1391.               begin
  1392.                 (* AvtInterp(^V);  { display ^Vs in ANSI mode } *)
  1393.                 AvtInterp(ch);  { send ANSI the characters }
  1394.                 AvtInCome := 0;
  1395.               end;
  1396.              end; { case }
  1397.            end; { 2 }
  1398.        1 : begin  { AVT/1 queries are always active }
  1399.              Process_Query(ch);
  1400.              AvtInCome := 0;
  1401.            end;
  1402.      end; { case AvtInCome }
  1403.    end; { Asleep }
  1404. end; { Parse_AVT1 }
  1405.  
  1406. (************* Special Effects Procedures *********************)
  1407.  
  1408. procedure ANSI_Only; { Actually just puts Avatar to sleep w/o fallback }
  1409. begin
  1410.   fallback := false;
  1411.   awake := false;
  1412.   AvtInterp := ANSI_Waiting;
  1413.   CurrentTerm := TermANSI;
  1414. end;
  1415.  
  1416. procedure Level0_Simulation(fallbck:boolean);
  1417. (*
  1418. const        { this is the simulation string to send via modem }
  1419.   s : string[14] = ^V+'=R'+^V+^V+#1+#3+#1+#1+#25+#80+^V+^W+#1;
  1420.                    { raw,        Cyan Window,        Activate }
  1421. *)
  1422. begin
  1423.   QueryReply[4] := '0'; { now it reads "AVT0, bla blaa blabla bla bla" }
  1424.   Cooked := False;  { Level 0+ works in raw mode }
  1425.   Fallback := fallbck; { AVT/0+ can support fallback, AVT/1 just sleeps }
  1426.   Dest_BS := False; { AVT/0 doesn't have destructive backspaces }
  1427.   with WinList^[0] do
  1428.    begin
  1429.      cattrib := 3; { Cyan }
  1430.      attrib := 3; { Cyan }
  1431.      WCFLf := None; { reset all specialties }
  1432.    end;
  1433.   ActWin.LoadWinData(0);
  1434.   CurrentTerm := TermAVT0;
  1435. end;
  1436.  
  1437. (***************** Unit Initialization ***********************)
  1438.  
  1439. {$S+} Procedure InitUnit; {$S-}
  1440. const
  1441.   HeapErrStr = 'PAVATAR: Fatal Error! 3K Heap Space Needed.';
  1442. begin
  1443.   DESQview_Init;
  1444.   if MaxAvail-8 < SizeOf(WinList) then
  1445.    begin
  1446.      Writeln(HeapErrStr);
  1447.      runerror(203); { Heap overflow error }
  1448.      Writeln('Portions Copyright 1993 Gregory P. Smith');
  1449.    end;
  1450.   New(WinList); { Allocate the Window Data Table }
  1451.   If Winlist = nil then
  1452.    begin
  1453.      Writeln(HeapErrStr);
  1454.      runerror(203); { Heap overflow error }
  1455.    end;
  1456.   ResetTerminal(ScrnColumns,ScrnLines);
  1457. end;
  1458.  
  1459. {$IFNDEF OVERLAY  -- Normal overlayed units can't initialize themselves }
  1460. BEGIN
  1461.   InitUnit;  {$ENDIF}
  1462. END.
  1463.