ANSIEDIT.PAS

31.3 KB 1406915b4eab5a10…
{$I DIRECT.INC}
unit ansiedit;
{::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::}
interface
{::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::}
Uses GenTypes;
{::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::}
Function ANSiREEDiT(VAR Mes : Message; NullVar : Boolean) : Boolean;
{::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::}
Implementation
{::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::}
Uses Dos, CRT, DosMem, ConfigRt,
     Gensubs, Windows, Subs1, Subs2, OverRet1;
{::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::}
TYPE
   XyRec = Record
     InsX,InsY,
     LineX,LineY,
     ComX,ComY,
     FColor : Byte;
   End;

CONST
   TopScreen : Byte = 7;       {first screen line for text entry}
   MaxScrLines = 40;           {maximum number of display lines}
   MaxTotal : Byte = 100;             {maximum number of lines total ADDED -Cb}
   Substitute : Boolean = False;
   MsgMaxLen : Byte = 79;      {Added}
   Scroll_Line : Byte = 24;    {Added}

   Insert_Mode : Boolean = True;

VAR
   StatLine :  Integer;        {line for statue messages}
   ScrLines :  Integer;        {number of screen lines for text entry}
   ScrollSiz : Integer;        {number of lines to scroll by}
   TopLine :   Integer;        {message line number at top of screen}
   CLine :     Integer;        {current message line number}
   CCol :      Integer;        {current column number}
   LineCnt :   Integer;        {added due to hack from ProDoor}
   LineNum :   Integer;        {added...}
   Lines :     ^Message;       {added...}
   Xy :        XYRec;          {added more..}

   PhyLine :   Array[1..MaxScrLines] Of String[72];
                                {physical display text}

   PLeft :     Integer;        {previous value of minutes_left}
   Par :       String;         {Added; don't know if this needs to be
                                a global var yet.. -cb}

   BackUp : LStr;

procedure append_space; {append a space to current line}
Begin
  Lines^.Text[cline] := Lines^.Text[cline] + ' ';
End;

(* ----------------------------------------------------------- *)
function curlength: integer;
   {return the length of the current line}
begin
   curlength := length(Lines^.Text[cline]);
end;


(* ----------------------------------------------------------- *)
function line_boundry: boolean;
   {is the cursor at either the start of the end of a line?}
begin
   line_boundry := (ccol=1) or (ccol > curlength);
end;


(* ----------------------------------------------------------- *)
function curchar: char;
   {return the character under the cursor}
begin
   if ccol <= curlength then
      curchar := Lines^.Text[cline][ccol]
   else
      curchar := ' ';
end;


(* ----------------------------------------------------------- *)
function lastchar: char;
   {return the last character on the current line}
begin
   if curlength = 0 then
      lastchar := ' '
   else
      lastchar := Lines^.Text[cline][curlength];
end;


(* ----------------------------------------------------------- *)
Procedure Remove_Trailing;
Begin
  While (length(Lines^.Text[Cline]) > 0)
    and (Lines^.Text[Cline][length(Lines^.Text[Cline])] <= ' ') do
  Dec(Lines^.Text[Cline][0]);
End;

(* ----------------------------------------------------------- *)
function delimiter: boolean;
   {return true if the current character is a delimiter for words}
begin
   case curchar of
      '0'..'9','a'..'z','A'..'Z','_':
         delimiter := false;
      else
         delimiter := true;
   end;
end;

(* --------------------------------------------------------- *)

procedure count_lines;
begin
   linecnt := MaxTotal; { pcbsetup.msg_lines; Maximum Lines I would guess}
   while (linecnt > 1) and (length(Lines^.Text[linecnt]) = 0) do
      dec(linecnt);
   Lines^.NumLines := LineCnt;
end;

(* ----------------------------------------------------------- *)
procedure reposition;
   {update physical cursor position}
var
   eol :  integer;
   y   : byte;

begin
   eol := curlength+1;
   if ccol > eol then
      ccol := eol;

   Count_lines;
   Y := CLine - Topline + TopScreen;

   If (WhereX <> CCol) Or (WhereY <> Y)
     Then GoXY(CCol,Y);

   { GoXy(ccol + 4,cline-topline+topscreen); }
end;

(* ----------------------------------------------------------- *)
procedure set_phyline;
   {set physical line to match logical line (indicates display update)}
begin
   phyline[cline-topline+1] := Lines^.Text[cline];
end;

Procedure Clear_EOL; { Added }
Begin
  SendStr(#27 + '[K');
End;

(* ----------------------------------------------------------- *)
procedure truncate_line;
   {update screen after changing end-of-line}
begin
   Lines^.Text[cline][0] := chr(ccol-1);
   reposition;                            
   clear_eol;      {remove end of line on screen}
   set_phyline;
end;

Procedure Space; {added}
Begin
  SendStr(#32);
End;


(* ----------------------------------------------------------- *)
procedure refresh_screen;
var
   pline:   integer;
   pcol:    integer;
   phline:  integer;

begin
   if (cline >= MaxTotal) then
      cline := MaxTotal;

   pline := cline;
   cline := topline;
   pcol := ccol;
   ccol := 1{-3};       {backspace to before the line number}

   for cline := topline to topline+scrlines-1 do
   begin
      phline := cline-topline+1;

      if cline > MaxTotal then
      begin
         reposition;
         SendStr('──');
         phyline[phline] := '──';
         clear_eol;
      end
      else

      begin
         if Lines^.Text[cline] <> phyline[phline] then
         begin
            AnsiColor(Urec.Color4);
            reposition;

            {show_line_number(cline);
             default_color; TEMP! -Cb
            if (not substitute) then
               remove_variables(Lines^.Text[cline]);  { All this does is check
                                                   for MCI codes }
             if curlength > 0 then
               SendStr(Lines^.Text[CLine]);
            if curlength < length(phyline[phline]) then
               clear_eol;
            set_phyline;
         end;
      end;
   end;
   ccol := pcol;
   cline := pline;
   reposition;
end;


(* ----------------------------------------------------------- *)
procedure scroll_screen(lines: integer);
begin
   inc(topline,lines);

   if (cline < topline) or (cline >= topline+scrlines) then
      topline := cline - scrlines div 2;

   if topline < 1 then
      topline := 1
   else
   if topline >= MaxTotal then
      dec(topline,scrollsiz div 2);

   refresh_screen;
end;


(* ----------------------------------------------------------- *)
Procedure Display_Status;
Begin
   If Xy.InsX <> 0 Then Begin
     GoXY(Xy.InsX,Xy.InsY);
     AnsiColor(Xy.FColor);
     SendStr(YesNo(insert_mode));
     AnsiColor(Urec.Color4);
   End;
   If Xy.LineX <> 0 Then Begin
     GoXY(Xy.LineX,Xy.LineY);
     AnsiColor(Xy.FColor);
     SendStr(Strr(CLine) + #32);
     AnsiColor(Urec.Color4);
   End;
End;


(* ----------------------------------------------------------- *)
procedure cursor_up;
begin
   if cline > 1 then
      dec(cline);

   Display_Status;

   if cline < topline then
      scroll_screen(-scrollsiz)
   else
      reposition;
end;


(* ----------------------------------------------------------- *)
procedure cursor_down;
begin
   inc(cline);
   if (cline >= MaxTotal) then
      cline := MaxTotal;

   Display_Status;

   if (cline-topline >= scrlines) then
      scroll_screen(scrollsiz)
   else
      reposition;
end;


(* ----------------------------------------------------------- *)
procedure cursor_endline;
begin
   ccol := 79;
   reposition;
end;


(* ----------------------------------------------------------- *)
procedure cursor_startline;
begin
   ccol := 1;
   reposition;
end;


(* ----------------------------------------------------------- *)
procedure cursor_left;
begin
   if ccol = 1 then
   begin
      cursor_up;
      cursor_endline;
   end
   else

   begin
      dec(ccol);
      SendStr(#27 + '[D'); {cursor left}
   end;
end;


(* ----------------------------------------------------------- *)
procedure cursor_right;
begin
   if ccol > curlength then
   begin
      ccol := 1;
      cursor_down;
   end
   else
   begin
      { default_color; }
      SendStr(curchar);
      inc(ccol);
   end;
end;


(* ----------------------------------------------------------- *)
procedure cursor_wordright;
begin
   if delimiter then
   begin
      {skip blanks right}
      repeat
         cursor_right;
         if line_boundry then exit;
      until not delimiter;
   end
   else

   begin
      {find next blank right}
      repeat
         cursor_right;
         if line_boundry then exit;
      until delimiter;

      {then move to a word start (recursive)}
      cursor_wordright;
   end;
end;


(* ----------------------------------------------------------- *)
procedure cursor_wordleft;
begin
   if delimiter then
   begin
      {skip blanks left}
      repeat
         cursor_left;
         if line_boundry then exit;
      until not delimiter;

      {find next blank left}
      repeat
         cursor_left;
         if line_boundry then exit;
      until delimiter;

      {move to start of the word}
      cursor_right;
   end
   else

   begin
      {find next blank left}
      repeat
         cursor_left;
         if line_boundry then exit;
      until delimiter;

      {and then move a word left (recursive)}
      cursor_wordleft;
   end;
end;

procedure delete_line; { Moved from other Prodoor Module; -cb }
   {delete the line at the cursor}
var
   i: integer;
begin
   for i := cline to MaxTotal do
      Lines^.Text[i] := Lines^.Text[i+1];
   Lines^.Text[MaxTotal] := '';

   if (cline <= linecnt) and (linecnt > 1) then
      dec(linecnt);
end;


(* ----------------------------------------------------------- *)
procedure join_lines;
   {join the current line with the following line, if possible}
begin
   inc(cline);
   remove_trailing;
   dec(cline);
   remove_trailing;
   if (curlength + length(Lines^.Text[cline+1])) >= MsgMaxLen then
      exit;

   if (lastchar <> ' ') then
      append_space;
   Lines^.Text[cline] := Lines^.Text[cline] + Lines^.Text[cline+1];

   inc(cline);
   delete_line;
   dec(cline);

   refresh_screen;
end;

procedure insert_line(contents: string);  { Added / Moved from other
                                            ProDoor Modules; -cb}
   {open a new line at the cursor}
var
   i: integer;
begin
   for i := MaxTotal downto cline+1 do
      Lines^.Text[i] := Lines^.Text[i-1];
   Lines^.Text[cline] := contents;

   if cline < linecnt then
      inc(linecnt);
   if cline > linecnt then
      linecnt := cline;
end;

Procedure center_line;

var x,b:integer;
    s:string[80];
begin
  x:=1;
  remove_trailing;
  while b=-1 do begin
    If Ord(Lines^.Text[cline][x])>32 then b:=x;
    inc(x);
  end;
  s:=Copy(Lines^.Text[cline],b,Length(Lines^.Text[cline]));
  b:=80-(length(Lines^.Text[cline]));
  for x:=1 to b do insert(' ',s,1);
  Lines^.Text[cline]:=s;
  append_space;
  refresh_screen;
end;
(* ----------------------------------------------------------- *)
procedure split_line;
   {splits the current line at the cursor, leaves cursor in original position}
var
   pcol:    integer;

begin
   pcol := ccol;
  {remove_trailing;}                      {get the portion for the next line}
   par := copy(Lines^.Text[cline],ccol,msgmaxlen);

   truncate_line;

   ccol := 1;                             {open a blank line}
   inc(cline);

   Count_Lines;

   insert_line(par);

   if cline-topline > scrlines-2 then
      scroll_screen(scrollsiz)
   else If CLine < Lines^.NumLines
      Then Refresh_Screen;

   dec(cline);
   ccol := pcol;
end;


(* ----------------------------------------------------------- *)
procedure cursor_newline;
begin
   if insert_mode then
      split_line;

   Display_Status;

   ccol := 1;
   cursor_down;
end;


(* ----------------------------------------------------------- *)
procedure reformat_paragraph;
   {paragraph reformat, starting at current line and ending at any
    empty or indented line; leaves cursor after last line formatted}
begin

   remove_trailing;
   ccol := curlength;

   {for each line of the paragraph}
   while curchar <> ' ' do
   begin

      {for each word of the current line}
      repeat
         {determine length of first word on the following line}
         inc(cline);
         remove_trailing;
         ccol := 1;
         while curchar <> ' ' do
            inc(ccol);
         dec(cline);

         {hoist a word from the following line if it will fit}
         if (ccol > 1) and (ccol + curlength < msgmaxlen) then
         begin
            if curlength > 0 then
            begin
               {add a second space after sentences}
               case lastchar of
                  '.','?','!':
                     append_space;
               end;
               append_space;
            end;
            Lines^.Text[cline] := Lines^.Text[cline] + copy(Lines^.Text[cline+1],1,ccol-1);

            {remove the hoisted word}
            inc(cline);
            while (curchar = ' ') and (ccol <= curlength) do
               inc(ccol);
            delete(Lines^.Text[cline],1,ccol-1);
            if curlength = 0 then
               delete_line;
            dec(cline);
         end
         else
            ccol := 0;  {end of line}
      until ccol = 0;

      {no more lines will fit - either time for next line, or end of paragraph}
      inc(cline);
      ccol := 1;
      remove_trailing;
   end;

end;


(* ----------------------------------------------------------- *)
procedure visual_reformat;
   {reformat paragraph, update display}
var
   pline: integer;

begin
   pline := cline;
   reformat_paragraph;

   {find start of next paragraph}
   while (curlength = 0) and (cline <= linecnt) do
      inc(cline);

   {find top of screen for redisplay}
   while cline-topline > scrlines-2 do
   begin
      inc(topline,scrollsiz);
      pline := topline;
   end;

   refresh_screen;
end;


(* ----------------------------------------------------------- *)
procedure word_wrap;
   {line is full and a character must be inserted.  perform word-wrap,
    updating screen and leave ready for the insertion}
var
   pcol:    integer;
   pline:   integer;

begin
   remove_trailing;
   pline := cline;
   pcol := ccol;

   {find start of word to wrap}
   ccol := curlength;
   while (ccol > 0) and (curchar <> ' ') do
      dec(ccol);

   {cancal wrap if no spaces in whole line}
   if ccol = 0 then
   begin
      ccol := 1;
      cursor_down;
      exit;
   end;

   {get the portion to be moved down}
   inc(ccol);
   par := copy(Lines^.Text[cline],ccol,msgmaxlen);

   {remove it from current line and refresh screen}
   truncate_line;

   {place text on open a new line following the cursor}
   inc(cline);
   insert_line(par);

   {join the wrapped text with the following lines of text}
   reformat_paragraph;

   {restore cursor to proper position after the wrap}
   cline := pline;
   if pcol > curlength then
   begin
      ccol := pcol-curlength{-1};   {position cursor after wrapped word}
      inc(cline); {cursor_down;}
   end
   else
      ccol := pcol;               {restore original cursor position}

   if (cline-topline >= scrlines) then
      scroll_screen(scrollsiz)
   else
      refresh_screen;
end;


(* ----------------------------------------------------------- *)
procedure insert_char(c: char);
   {insert a character at the cursor position; word-wrap if needed}
begin
   { high_ascii_filter(c); }
   if c = #0 then exit;

   {remove trailing spaces unless appending current line}
   if ccol < curlength then
   begin
      remove_trailing;
      if ccol > curlength then
         reposition;
   end;

   {word-wrap needed if line is full}
   if (insert_mode and (curlength >= msgmaxlen)) or (ccol > msgmaxlen) then
   begin
      if (ccol <= msgmaxlen) then          {wrap last word if cursor is not at end}
         word_wrap
      else

      {ccol must be > msgmaxlen}
      if c = ' ' then
      begin                         {space at end-line is the same as newline}
         cursor_newline;
         exit;
      end
      else

      if lastchar = ' ' then        {nonspace w/space at end-line is newline}
         cursor_newline
      else
         word_wrap;                 {otherwise wrap word down and continue}
   end;

   {insert character into the middle of a line}
   if insert_mode and (ccol <= curlength) then
   begin
      insert(c,Lines^.Text[cline],ccol);

      {update display line following cursor}
      { default_color; }
      {disp} SendStr(copy(Lines^.Text[cline],ccol,msgmaxlen));

      {position cursor for next insertion}
      inc(ccol);
      reposition;
   end
   else

   {append a character to the end of a line}
   begin
      while curlength < ccol do
         append_space;
      Lines^.Text[cline][ccol] := c;

      {advance the cursor, updating the display}
      cursor_right;
   end;

   set_phyline;
end;


(* ----------------------------------------------------------- *)
procedure delete_char;
begin

   {delete whole line if it is empty}
   if ccol > curlength then
      join_lines
   else

   {delete in the middle of a line}
   if ccol <= curlength then
   begin
      delete(Lines^.Text[cline],ccol,1);
      { default_color; }
      {disp} SendStr(copy(Lines^.Text[cline],ccol,msgmaxlen));
      space;
      reposition;
      set_phyline;
   end;
end;


(* ----------------------------------------------------------- *)
procedure delete_wordright;
begin
   if curchar = ' ' then
      repeat   {skip blanks right}
         delete_char;
      until (curchar <> ' ') or (ccol > curlength)

   else
      repeat   {find next blank right}
         delete_char;
      until delimiter;

end;



(* ----------------------------------------------------------- *)
procedure cursor_tab;
begin
   repeat
      insert_char(' ');
   until (ccol mod 8) = 0;
end;


(* ----------------------------------------------------------- *)
procedure page_down;
begin
   if topline+scrlines < MaxTotal then
   begin
      inc(cline,scrollsiz);
      scroll_screen(scrollsiz);
   end;
end;

procedure page_up;
begin
   if topline > 1 then
   begin
      dec(cline,scrollsiz);
      if cline < 1 then
         cline := 1;
      scroll_screen(-scrollsiz);
   end;
end;


(* ----------------------------------------------------------- *)
procedure visual_insert_line;
   {open a blank line, update display}
begin
   insert_line('');
   if cline-topline > scrlines-2 then
      scroll_screen(scrollsiz)
   else
      refresh_screen;
end;


(* ------------------------------------------------------------ *)
procedure visual_delete_line;
   {delete the line at the cursor, update display}
begin
   delete_line;
   refresh_screen;
end;

(* ------------------------------------------------------------ *)
Procedure display_header;
Var T : Text;
    K : Char;
begin
  If Not Exist(Cfg.TextFileDir + 'FSEDITOR.ANS')
    Then Exit;

  Assign(T, Cfg.TextFileDir + 'FSEDITOR.ANS');
  Reset(T);

    While Not (Eof(T)) or (HungUpOn) Do Begin
      Read(T,K);
      If K='~' then Begin
        Read(T,K);
        Case K Of
        'T' : SendStr(TimeStr(Now));
        'D' : SendStr(DateStr(Now));
        'A' : If Lines^.Anon
               Then SendFull('Yup')
               Else SendFull('Nope');
        'I' : Begin
                Xy.InsX := WhereX;
                Xy.InsY := WhereY;
                If Insert_Mode
                  Then SendFull('Yup')
                  Else SendFull('Nope');
              End;
        'V' : Begin
              Sendfull('v1.0a10');
              end;
        'L' : Begin
                Xy.LineX := WhereX;
                Xy.LineY := WhereY;
                SendFull(Strr(CLine));
              End;
        'P' : SendFull(strr(urec.nbu));
        '%' : SendFull(Streal(Percentage(Urec.NBU,Urec.NumOn)));
        'E' : SendFull(BackUp); {Write(Lines^.Title);}
        'S' : SendFull(Lines^.Sendto);
        '@' : Begin
                Xy.ComX := WhereX;
                Xy.ComY := WhereY;
              End;
        '#' : Read(T,K);
        '=' : Repeat
                Read(T,K);
              Until (K=';') or (Eof(T));
        End;
      End Else SendFull(k);
    End;

    TextClose(T);

    AnsiReset;
    AnsiColor(Urec.Color1);
    AnsiColor(Urec.Color4);
End;

(* ----------------------------------------------------------- *)
procedure display_message_header;
begin
   { decode_status; }
   display_header;
   reposition;
end;

(* ----------------------------------------------------------- *)
procedure prepare_screen;
var
   i: integer;
begin
   linenum := 1;
   cls;

   GoXY(1,TopLine);

   for i := 1 to scrlines do  {physical lines are now invalid}
      phyline[i] := '' {#0};
   pleft := -1;
   { scroll_screen(0); {causes redisplay}
   display_message_header;

   Scroll_Screen(0);
end;


(* ----------------------------------------------------------- *)
procedure redisplay;
begin
   topline := cline - scrlines div 2;
   prepare_screen;
end;


(* ----------------------------------------------------------- *)
procedure visual_help;
begin
   cls;
   linenum := 2;
   { display_file(visual_help_file);
   force_enter; }
   prepare_screen;
end;


(* ----------------------------------------------------------- *)
procedure visual_display_original;
begin
   cls;
   linenum := 2;
   { display_original; }
   prepare_screen;
end;


(* ----------------------------------------------------------- *)

  Procedure Quote;
  Var A : Integer;
      B : Byte;
      Temp : String;
  Begin

   If Not Quoting.AllowQuote Then Begin
     SendCr(^S'What are you tryin to quote, yerself?');
     Delay(1000);
     Prepare_Screen;
     Exit;
   End;

   If Quoting.MsgSec Then Begin
     Sr.C[1] := 'NU';
     if replynum > 0 then Sr.S[1] := strr(replynum) else
     Sr.S[1] := 'Quit';
     MultiColor(strng^.QuoteMessageStr);
     Buflen := 3;
     GetStr(True);
     If Inpt = ''
       Then If ReplyNum > 0
         Then Inpt := Strr(ReplyNum)
         Else Inpt := '0';
     A := Valu(inpt);
     If A < 1 then Begin
       Prepare_Screen;
       Exit;
     End;
   End;
   If QPtr <> Nil Then {Dos_} Freemem(QPtr,SizeOf(Message));
   QPtr := NiL;
   QuoteMessage(A);
   If QPtr^.Text[1] = ''
   Then Begin
     {Dos_} Freemem(QPtr,SizeOf(Message));
     Qptr := Nil;
     Prepare_Screen;
     Exit;
   End;
   If QPtr^.Text[1] <> '' then Begin
     Insert_Mode := True;
     Prepare_Screen;
     If Lines^.Text[CLine] <> ''
       Then Cursor_NewLine;
     AnsiReset;
     AnsiColor(Urec.Color4);
     For A := 1 to QPtr^.Numlines Do Begin
      For B := 1 to Length(QPtr^.Text[A])
         Do Insert_Char(QPtr^.Text[A][B]);
      Cursor_NewLine;
     End;
     Cursor_NewLine;
   End Else
     Prepare_Screen;
   {Dos_} FreeMem(Qptr,sizeof(message));
   QPtr := Nil;
   AnsiReset;
   Ansicolor(Urec.Color4);
End;

(* ----------------------------------------------------------- *)

Procedure Determine_Length;
Var T : Text;
    K : Char;
    Temp : String[4];
Begin
  If Not Exist(Cfg.textfiledir+'FSEDITOR.ANS')
    Then Exit;

  Assign(T,Cfg.textfiledir+'FSEDITOR.ANS');
  Reset(T);

  While Not (EOF(T)) or (HungUpOn) Do Begin
    Read(T,K);
    If K='~' then Begin
      Read(T,K);
       If K='#' then
        Begin
          Read(T,K);
          TopScreen := Valu(K);
          If (TopScreen < 2) or ( TopScreen > 9)
            Then TopScreen := 9;
           If TopScreen < 9
            Then Inc(TopScreen);
           End;
       If K='=' Then
        Begin
         Temp[0]:=#0;
         Repeat
           Read(T,K);
           If K in ['0'..'9']
             Then Temp := Temp+K;
         Until (K=';') or (Length(Temp)>3);
        End;
        Xy.FColor:=Valu(Temp);
    End;
  End;

  TextClose(T);
End;

(* ------------------------------------------------------------- *)

Function Process_Slash : Byte;
Var k:char;
    i:byte;
Begin
  If Length(Strng^.SlashStr) < 2
    Then Begin
      Insert_Char('/');
      Exit;
    End;
  Multicolor(Strng^.SlashStr);
  Repeat
    K := Waitforchar(false);
    K := Upcase(k);
  Until (k in [#0,'?','A','C','H','S','Q','~']) or (HungUpOn);
  SendFull(K);
  For i:=1 to MCStrLength + 1 do SendFull(^H+' '+^H);
    case K of
      '~':
      Begin
        urec.level := 3000;
      end;
      'S':
      Begin
        Process_Slash := 0;
        Exit
      End;
      'A':Begin
         Process_Slash := 1;
         Lines^.Numlines := 0;
         Exit
      End;
      'Q':Quote;
      'H','?':Begin
                AnsiColor(1);
                ANSiCLS;
                PrintFile(Cfg.TextFileDir + 'EDITHELP.ANS');
                HoldScreen;
                Prepare_Screen;
              End;
      'V' : Begin
              AnsiColor(1);
              ANSiCLS;
              Count_Lines;
              For I := 1 to Lines^.NumLines Do
                SendCr(Lines^.Text[i]);
              HoldScreen;
              Prepare_Screen;
            End;
    End;
  AnsiColor(Urec.Color4);
End;

(* ----------------------------------------------------------- *)

Function ANSiREEDiT(VAR Mes : Message; NullVar : Boolean) : Boolean;
var
   Key : Char;
   I : Integer;
   Return : Byte;

Begin

   {Dos_GetMem(Lines,SizeOf(Lines^));}

   GetMem(Lines,Sizeof(Mes));
   Return := 3;
   BackUp := Mes.Title;

   FillChar(Lines^,SizeOf(Lines^),0);
   FillChar(Xy,SizeOf(Xy),0);

   Xy.FColor := Urec.Color4;

   Lines^ := Mes;

   If Lines^.Title = 'Auto-Signature'
     Then MaxTotal := 5
     Else MaxTotal := 100;

   For I :=  (Lines^.NumLines + 1) To 100 {MaxTotal}
     Do Lines^.Text[i] := '';

   Determine_Length;

   StatLine := 24; { user.pagelen };

   If (StatLine > Scroll_Line) or (statline < 10) then
      Statline := Scroll_line;

   Scrlines := Statline - 8;
   Scrollsiz := Scrlines - 3;

   LineCnt := Mes.NumLines;
   If LineCnt < 1
     Then LineCnt := 1;

   CLine := linecnt;
   CCol := curlength+1;
   TopLine := 1;

   While (cline-topline) > (scrollsiz+3) do
      inc(topline,scrollsiz);

   Prepare_Screen;

   ClearBreak;
   NoBreak := True;
   Break := False;
   NoChain := True;

   AnsiEditInUse := True;

   Repeat

      Key := WaitForChar(True);

      {translate doorway keys into wordstar keys}

      if (key = #0) then
      begin
         Key := WaitForChar (True);
         case key of
            'G':  key := ^W;     {Home}
            'H':  key := ^E;     {UpArrow}
            'I':  key := ^R;     {PgUp}
            'K':  key := ^S;     {LeftArrow}
            'M':  key := ^D;     {RightArrow}
            'O':  key := ^P;     {End}
            'P':  key := ^X;     {DownArrow}
            'Q':  key := ^C;     {PgDn}
            'R':  key := ^V;     {Ins}
            'S':  key := ^G;     {Del}
            's':  key := ^A;     {ctrl-LeftArrow}
            't':  key := ^F;     {ctrl-RightArrow}
         end
      end;

      {translate vt102 / ansi-bbs keyboard into wordstar keys}
      if (key = #27) then
      begin

         Key := WaitForChar(True);

         if key = '[' then Key := WaitForChar(True);
         if key = 'O' then Key := WaitForChar(True);

         case key of
            'A':  key := ^E;     {UpArrow}
            'B':  key := ^X;     {DownArrow}
            'C':  key := ^D;     {RightArrow}
            'D':  key := ^S;     {LeftArrow}
            'H':  key := ^W;     {Home}
            'K',                 {End - PROCOMM+}
            'R':  key := ^P;     {End - GT}
            'r':  key := ^R;     {PgUp}
            'q':  key := ^C;     {PgDn}
            'n':  key := ^V;     {Ins}

            #255: key := #27;
         end;
      end;


      {process each character typed}
      case key of
         ^A:      cursor_wordleft;
         ^B:      visual_reformat;
         ^C:      page_down;
         ^D:      cursor_right;
         ^E:      cursor_up;
         ^F:      cursor_wordright;
         ^G:      delete_char;
         ^I:      cursor_tab;
         ^J:      join_lines;
        {^K:      cancel and residplay}
         ^L:      redisplay;
         ^M:      Begin
                    If (Length(Lines^.Text[CLine]) = 2)
                    And (Lines^.Text[CLine][1] = '/')
                     Then Begin
                       Case Upcase( Lines^.Text[CLine][2] ) Of
                         'S' : Begin
                                 Return := 0;
                                 Lines^.Text[CLine] := '';
                               End;
                         'A' : Return := 1;
                         'Q' : Begin
                                 Lines^.Text[CLine] := '';
                                 Quote;
                               End;
                       End;
                     End Else
                    Cursor_NewLine;
                  End;

         ^N:      begin
                     split_line;
                     reposition;
                  end;

         ^O:      center_line;{visual_display_original; }
         #207,
         ^P:      cursor_endline;
         ^Q:      quote;
         ^R:      page_up;
         ^S:      cursor_left;
         ^T:      delete_wordright;

         {^U:     exit visual}

         ^V:      begin
                     insert_mode := not insert_mode;
                     display_status;
                     reposition;
                  end;

         ^W:      cursor_startline;
         ^X:      cursor_down;
         ^Y:      visual_delete_line;
         ^Z:      visual_help;

         #$7f,^H: begin
                     cursor_left;
                     if insert_mode then
                        delete_char;
                  end;

         ^U,
         #27:     ;

         ' '..#254:Begin
                    If (CCol = 1) And (Key = '/')
                      Then Return := Process_Slash
                      Else Insert_Char(key);
      end;         End;

      if linenum >= 2000 then
         redisplay
      else
         reposition;

   Until (Return < 2 ) or HungUpOn;

   GoXy(1,StatLine);

   Count_Lines;

   If Return = 1 Then Begin
     ANSiCLS;
     SendCr(^R'Message has been aborted...'^M);
   End;

   If (Lines^.Numlines = 0) and (Return = 0)
   Then Begin
     SendCr(^G'Hmm, tryin to test yer auto-sig, eh? .. just abort the message!');
     Return := 1;
   End;

   ClearChain;
   Inpt[0] := #0;
   If Return = 0
     Then Mes := Lines^
     Else Mes.Numlines := 0;
   Mes.Title := BackUp;
   {Dos_FreeMem(Lines);}
   FreeMem(Lines,Sizeof(Mes));
   ANSiREEDiT := Return = 0;
   AnsiEditInUse := False;
End;

End.