{$A+,B-,D-,E+,F-,I+,L-,N-,O-,R+,S-,V-}
{$M 4048,65536,655360}

Program ReadText;

{ Author Trevor J Carlsen - released into the public domain 1991         }
{        PO Box 568                                                      }
{        Port Hedland                                                    }
{        Western Australia 6721                                          }
{        Voice +61 91 73 2026  Data +61 91 73 2569                       }
{        FidoNet 3:690/644                                               }

{ This example Programs displays a Text File using simple Word wrap. The }
{ cursor keys are used to page Forward or backwards by page or by line.  }
{ The Program makes some important assumptions.  The main one is that no }
{ line in the File will ever exceed 255 Characters in length.  to get    }
{ around this restriction the ReadTxtLine Function would need to be      }
{ rewritten.                                                             }

{ The other major restriction is that Files exceeding a size able to be  }
{ totally placed in RAM cannot be viewed.                                }

{$DEFinE TurboPower (Remove the period if you have Turbo Power's TPro)  }

Uses
  {$ifDEF TurboPower }
  tpCrt,
  colordef;
  {$else}
  Crt;
  {$endif}

Const
  {$ifNDEF TurboPower }
  BlackOnLtGray = $70;      LtGrayOnBlue = $17;
  {$endif}
  LineLength    = 79;       MaxLines     = 6000;
  ScreenLines   = 22;       escape       = $011b;
  Home          = $4700;    _end         = $4f00;
  upArrow       = $4800;    downArrow    = $5000;
  PageUp        = $4900;    PageDown     = $5100;

Type
  LineStr    = String[Linelength];
  StrPtr     = ^LineStr;

Var
  TxtFile    : Text;
  Lines      : Array[1..MaxLines] of StrPtr;
  NumberLines: 1..MaxLines+1;
  CurrentLine: 1..MaxLines+1-ScreenLines;
  st         : String;
  finished   : Boolean;
  OldExitProc: Pointer;
  TxtBuffer  : Array[0..16383] of Byte;
  OldAttr    : Byte;

Function LastPos(ch : Char; S : String): Byte;
  { Returns the last position of ch in S or zero if ch not in S }
  Var
    x   : Word;
    len : Byte Absolute S;
  begin
    x := succ(len);
    Repeat
      dec(x);
    Until (x = 0) or (S[x] = ch);
    LastPos := x;
  end;  { LastPos }

Function Wrap(Var S,CarryOver: String): String;
  { Returns a String of maximum length Linelength from S. Any additional }
  { Characters remaining are placed into CarryOver.                      }
  Const
    space = #32;
  Var
    temp      : String;
    LastSpace : Byte;
    len       : Byte Absolute S;
  begin
    FillChar(temp,sizeof(temp),32);
    temp := S; CarryOver := ''; wrap := temp;
    if length(temp) > LineLength then begin
      LastSpace := LastPos(space,copy(temp,1,LineLength+1));
      if LastSpace <> 0 then begin
        Wrap[0]   := chr(LastSpace - 1);
        CarryOver := copy(temp,LastSpace + 1, 255)
      end  { if LastSpace... }
      else begin
        Wrap[0]   := chr(len);
        CarryOver := copy(temp,len,255);
      end; { else }
    end; { if (length(S))...}
  end;  { Wrap }

Function ReadTxtLine(Var f: Text; L: Byte): String;
  Var
    temp : String;
    len  : Byte Absolute temp;
    done : Boolean;
  begin
    len := 0; done := False;
    {$I-}
    While not eoln(f) do begin
      read(f,temp);
      if Ioresult <> 0 then begin
        Writeln('Error reading File - aborted');
        halt;
      end;
    end; { While }
    if eoln(f) then readln(f);
    ReadTxtLine := st + Wrap(temp,st);
    finished := eof(f);
  end;  { ReadTxtLine }

Procedure ReadTxtFile(Var f: Text);
  Var
    x : Word;
  begin
    st          := '';
    NumberLines := 1;
    Repeat
      if NumberLines > MaxLines then begin
        Writeln('File too big');
        halt;
      end;
      if (MaxAvail >= Sizeof(LineStr)) then
        new(Lines[NumberLines])
      else begin
        Writeln('Insufficient memory');
        halt;
      end;
      FillChar(Lines[NumberLines]^,LineLength+1,32);
      if length(st) > LineLength then
        Lines[NumberLines]^  := wrap(st,st)
      else if length(st) <> 0 then begin
        Lines[NumberLines]^  := st;
        st := '';
      end else
        Lines[NumberLines]^  := ReadTxtLine(f,LineLength+1);
      Lines[NumberLines]^[0] := chr(LineLength);
      if not finished then
        inc(NumberLines);
    Until finished;
  end;  { ReadTxtFile }

Procedure DisplayScreen(line: Word);
  Var
    x : Byte;
  begin
    GotoXY(1,1);
    For x := 1 to ScreenLines - 1 do
      Writeln(Lines[x-1+line]^);
    Write(Lines[x+line]^)
  end;

Procedure PreviousPage;
  begin
    if CurrentLine > ScreenLines then
      dec(CurrentLine,ScreenLines-1)
    else
      CurrentLine := 1;
  end;  { PreviousPage }

Procedure NextPage;
  begin
    if CurrentLine < (succ(NumberLines) - ScreenLines * 2) then
      inc(CurrentLine,ScreenLines-1)
    else
      CurrentLine := succ(NumberLines) - ScreenLines;
  end;   { NextPage }

Procedure PreviousLine;
  begin
    if CurrentLine > 1 then
      dec(CurrentLine)
    else
      CurrentLine := 1;
  end;  { PreviousLine }

Procedure NextLine;
  begin
    if CurrentLine < (succ(NumberLines) - ScreenLines) then
      inc(CurrentLine)
    else
      CurrentLine := succ(NumberLines) - ScreenLines;
  end; { NextLine }

Procedure StartofFile;
  begin
    CurrentLine := 1;
  end; { StartofFile }

Procedure endofFile;
  begin
    CurrentLine := succ(NumberLines) - ScreenLines;
  end;  { endofFile }

Procedure DisplayFile;

  Function KeyWord : Word; Assembler;
    Asm
      mov  ah,0
      int  16h
    end;

  begin
    DisplayScreen(CurrentLine);
    Repeat
      Case KeyWord of
        PageUp    : PreviousPage;
        PageDown  : NextPage;
        UpArrow   : PreviousLine;
        DownArrow : NextLine;
        Home      : StartofFile;
        _end      : endofFile;
        Escape    : halt;
      end; { Case }
      DisplayScreen(CurrentLine);
    Until False;
  end; { DisplayFile }

Procedure NewExitProc;Far;
  begin
    ExitProc := OldExitProc;
    {$ifDEF TurboPower}
    NormalCursor;
    {$endif}
    Window(1,1,80,25);
    TextAttr := OldAttr;
    ClrScr;
  end;

Procedure Initialise;
  begin
    CurrentLine := 1;
    if ParamCount <> 1 then begin
      Writeln('No File name parameter');
      halt;
    end;
    OldAttr := TextAttr;
    assign(TxtFile,Paramstr(1));
    {$I-}  reset(TxtFile);
    if Ioresult <> 0 then begin
      Writeln('Unable to open ',Paramstr(1));
      halt;
    end;
    SetTextBuf(TxtFile,TxtBuffer);
    Window(1,23,80,25);
    TextAttr := BlackOnCyan;
    ClrScr;
    Writeln('              Next Page = [PageDown]     Previous Page = [PageUp]');
    Writeln('              Next Line = [DownArrow]    Previous Line = [UpArrow]');
    Write('         Start of File = [Home]   end of File = [end]   Quit = [Escape]');
    Window(1,1,80,22);
    TextAttr := LtGrayOnBlue;
    ClrScr;
    {$ifDEF TurboPower}
    HiddenCursor;
    {$endif}
    OldExitProc := ExitProc;
    ExitProc    := @NewExitProc;
  end;

begin
  Initialise;
  ReadTxtFile(TxtFile);
  DisplayFile;
end.



