(*---------------------------------------------------------------------------
  :Program.    MuchMore.mod
  :Author.     Fridtjof Siebert
  :Address.    Nobileweg 67, D-7000-Stuttgart-40
  :Phone.      (0)711/822509
  :Shortcut.   [fbs]
  :Version.    2.0
  :Copyright.  PD
  :Language.   OBERON
  :Translator. AMOK OBERON Compiler
  :History.    24-Sep-88: First published version                        [fbs]
  :History.    26-Nov-88: Now Shows Filelength & Percentage              [fbs]
  :History.    27-Nov-88: Mouse can be used instead of Space / BackSpace [fbs]
  :History.    29-Apr-89: Strong increase in speed, removed WarpText     [fbs]
  :History.    29-Apr-89: Now supports Numeric Keys (Home,PgUp etc.)     [fbs]
  :History.    29-Apr-89: Now opens Screen as big as gfx.normalDisplay   [fbs]
  :History.    29/30-Apr-89: Asynchronus loading / displaying. Very nice [fbs]
  :History.    30-Apr-89, 00:33: Removed bugs in Filelength & L-Command  [fbs]
  :History.    30-Apr-89, 02:21: Added Find-Command                      [fbs]
  :History.    30-Apr-89, 10:30: Scrolling stops when window is inactive [fbs]
  :History.    01-May-89: Allocates no more unneeded memory for text     [fbs]
  :History.    07-May-89: Allocates even less memory now                 [fbs]
  :History.    14-May-89: Removed deadlock-bug with Find-Window          [fbs]
  :History.    25-May-89: Added print feature                            [fbs]
  :History.    25-May-89: Removed all imports (apart from Arts)          [fbs]
  :History.    26-May-89: inspired by J. Kupfer, I added nk 5 to quit    [fbs]
  :History.    26-May-89: Now handle BS correctly                        [fbs]
  :History.    02-Jul-89: Now supports several fontstyles and colors     [fbs]
  :History.    03-Jul-89: Is again as fast as it was with 2 colors       [fbs]
  :History.    03-Jul-89: Now no more crashes when quitting while print  [fbs]
  :History.    07-Jul-89: removed bug with texts of length 0             [fbs]
  :History.    10-Jul-89: small bug in find-command removed              [fbs]
  :History.    10-Jul-89: now found strings are highlighted              [fbs]
  :History.    14-Jul-89: nk0 to display fileinfo                        [fbs]
  :History.    06-Aug-89: Ported this to OBERON                          [fbs]
  :History.    06-Aug-89: Added ARP-FileRequester                        [fbs]
  :History.    07-Aug-89: Added L - (load new file) Command              [fbs]
  :Contents.   A Soft-Scrolling ASCII-File Printer.
  :Usage.      Usage: MuchMore <FileName>
  :Remark.     Grüße an alle, die gerade bei der Post jobben!
---------------------------------------------------------------------------*)

DEFINITION MuchMore; END MuchMore.

IMPLEMENTATION MuchMore;

(* $OvflChk- $RangeChk- $StackChk- $NilChk- $ReturnChk- $CaseChk- *)

IMPORT o:  OberonLib,
       d:  Dos,
       e:  Exec,
       ie: InputEvent,
       I:  Intuition,
       g:  Graphics,
       wb: Workbench;

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

CONST
  empty = "";
  oom = "Out of memory!";
  cof = "Can't open file!";
  usage = "Usage: MuchMore <Text>";
  MuchText = "MuchMore V2.0 © 1989 AMOK";
  nil = "NIL:";
  w = TRUE;
  f = FALSE;
  MaxLen = 256;

(* Control codes for QText: *)
  plain    = CHAR(17);
  italic   = CHAR(18);
  bold     = CHAR(19);
  boldit   = CHAR(20);
  ulineon  = CHAR(21);
  ulineoff = CHAR(22);

  Italic = 0;
  Bold   = 1;
  Ulin   = 2;
  Inv    = 3;

TYPE
  TextLinePtr = POINTER TO TextLine;
  TextLine = RECORD
               next: TextLinePtr;
               prev: TextLinePtr;
               len:  INTEGER;
               size: INTEGER;
               text: ARRAY MaxLen+1 OF CHAR;
             END;
  String = ARRAY 256 OF CHAR;
  StringPtr = POINTER TO String;
  FontData = ARRAY 8, 192, 8 OF CHAR;
  FontDataPtr = POINTER TO FontData;

CONST
(* FileReqFlags *)
  listFunc    = 0;
  gEventFunc  = 1;
  addGadFunc  = 2;
  newWindFunc = 3;
  newIDCMP    = 4;
  doColor     = 5;
  doMsgFunc   = 6;
  doWildFunc  = 7;

  fChars = 32;
  dSize  = 33;
  frFirstGadg = 7680H;

TYPE
  FileName = ARRAY fChars OF CHAR;
  DirName  = ARRAY dSize OF CHAR;
  FileNamePtr = POINTER TO FileName;
  DirNamePtr  = POINTER TO DirName;

TYPE
  FileReqFunc = PROCEDURE(LONGINT,LONGINT): LONGINT;
  STRPTR = POINTER TO CHAR;

  FileRequesterPtr = POINTER TO FileRequester;
  FileRequester = RECORD
    hail: STRPTR;                (* Hailing text                     *)
    ddef: FileNamePtr;           (* Filename array (FCHARS+1)        *)
    ddir: DirNamePtr;            (* Directory array (DSIZE+1)        *)
    wind: I.WindowPtr;           (* Window requesting or NULL        *)
    funcFlags: SHORTSET;         (* Control. See above.              *)
    reserved1: SHORTINT;         (* Set this to 0                    *)
    function: FileReqFunc;       (* Your function, see btdef's       *)
    reserved2: LONGINT;          (* reserved                         *)
  END;

VAR
  Screen: I.ScreenPtr;           (* Screen that contains the Text     *)
  BM: g.BitMapPtr;               (* Screen's BitMap                   *)
  Window: I.WindowPtr;           (* My window                         *)
  FRWin: I.WindowPtr;            (* Window for FileReq (other sigTask)*)
  MyFont: g.TextAttr;            (* Topaz 8                           *)
  MyFile: d.FileHandlePtr;       (* For loading Textfile              *)
  FirstLine: TextLinePtr;        (* Saved Text                        *)
  TopLine: TextLinePtr;          (* Points to topmost Line            *)
  BottomLine: TextLinePtr;       (* Last Line displayed on Screen     *)
  LoadLine: TextLinePtr;         (* currently loaded Line             *)
  LastLine: TextLinePtr;         (* Last element of LineList          *)
  Name: String;                  (* Text's Name                       *)
  IStr,PStr: String;             (* different usages                  *)
  Buffer: ARRAY 512 OF CHAR;     (* Buffer for Reading                *)
  RQPos: LONGINT;                (* Position within ReadBuffer        *)
  RQLen: LONGINT;                (* Number of CHARs in Buffer         *)
  NumLines: INTEGER;             (* Number of Lines on Screen         *)
  NumColumns: INTEGER;           (* Number of Columns on Screen       *)
  PageSize: LONGINT;             (* 8*NumLines*NumColumns             *)
  AnzLines: LONGINT;             (* Length of Text in Lines           *)
  Font: g.TextFontPtr;           (* used Font                         *)
  fontdata: FontData;            (* Fonts used by QText()             *)
  MyLock,OldDir: d.FileLockPtr;  (* To Examine and Load File          *)
  FileInfo: d.FileInfoBlockPtr;  (* to get File's length              *)
  FileLength,TextLength: LONGINT;(* Length of File and of Displayed Text *)
  ScreenPos: INTEGER;            (* actual position within bitmap     *)
  ShowTask: e.Task;              (* the task that displays the text   *)
  ShowStack: ARRAY 4000 OF CHAR; (* it's stack                        *)
  ShowTaskRunning: BOOLEAN;      (* is Showtask activated?            *)
  mySigBit: INTEGER;             (* My SignalBit                      *)
  mySig: LONGSET;                (* My SignalSet = LONGSET{mySigBit}  *)
  SignalNewData: BOOLEAN;        (* Signal when new data is loaded    *)
  SignalAllRead: BOOLEAN;        (* send signal at end of text        *)
  Done: BOOLEAN;                 (* Quit                              *)
  print: BOOLEAN;                (* print text                        *)
  NewText: BOOLEAN;              (* load new text                     *)
  Me: e.TaskPtr;                 (* my main task                      *)
  Info: BOOLEAN;                 (* is info currently displayed ?     *)
  MyMsgPtr: I.IntuiMessagePtr;   (* for receiving Messages            *)
  i,j: INTEGER;                  (* count                             *)
  Scroll: BOOLEAN;               (* scrolling or waiting?             *)
  Fast: BOOLEAN;                 (* scrollquick?                      *)
  nili,nilo: d.FileHandlePtr;    (* i/o for TYPE xxx TO PRT:          *)
  fg,bg: INTEGER;                (* Text colors                       *)
  style: SHORTSET;               (* Text style                        *)
  CommLine: POINTER TO CHAR;     (* The CLI-commands                  *)
  ArgPtr: POINTER TO String;     (* to get WBArg                      *)
  ri: g.RasInfoPtr;              (* Screen's ViewPort's RasInfo       *)
  NuScreen: I.NewScreen;         (* to open screens                   *)
  NuWindow: I.NewWindow;         (* to open window                    *)
  StrGadget: I.Gadget;           (* Gadget for Find-Command           *)
  StrInfo: I.StringInfo;         (* its special info                  *)
  arp: LONGINT;                  (* ArpBase                           *)
  body,text,ok: I.IntuiText;     (* IntuiTexts for AutoRequest        *)
  FR: FileRequester;             (* The Requester                     *)
  Filename: FileName;            (* The Filename (without path)       *)
  Dirname: String;               (* its path                          *)
  NewDisp: BOOLEAN;              (* need to rebuild Display ?         *)

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


PROCEDURE Length(VAR s: String): INTEGER;
VAR l: INTEGER;
BEGIN l := 0; WHILE (l<=SIZE(s)) AND (s[l]#0X) DO INC(l) END; RETURN l;
END Length;


PROCEDURE Append(VAR s1: String; s2: StringPtr);
(* appends s2 to s1 *)
VAR p,q: INTEGER;
BEGIN
  p := Length(s1); q := 0;
  WHILE (p<=SIZE(s1)) AND (s2^[q]#0X) AND (p<NumColumns) DO
    s1[p] := s2^[q]; INC(p); INC(q)
  END;
  IF p<=SIZE(s1) THEN s1[p] := 0X END;
END Append;


(*-----------------------------  Requester:  ------------------------------*)


PROCEDURE Request(Text: StringPtr);

VAR
  out: d.FileHandlePtr;
  c: CHAR;

BEGIN
  IF wb.WBStarted THEN
    body.backPen  := 1;  body.drawMode := g.jam2;
    body.leftEdge := 12; body.topEdge  := 8;
    text := body; ok := body;
    body.iText    := ADR(MuchText);
    body.nextText := ADR(text);
    text.iText    := Text; text.topEdge := 22;
    ok.leftEdge   := 6; ok.topEdge := 3; ok.iText := ADR("  OK  ");
    SETREG(0,I.AutoRequest(NIL,ADR(body),NIL,ADR(ok),
                           LONGSET{I.rawKey},LONGSET{},320,65));
  ELSE
    out := d.Output();
    SETREG(0,d.Write(out,Text,Length(Text^)));
    c := 0AX;
    SETREG(0,d.Write(out,ADR(c),1));
  END;
  HALT(0);
END Request;


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


PROCEDURE AllocLine(sz: INTEGER): TextLinePtr;

VAR a: TextLinePtr;

BEGIN
  o.New(a,SIZE(TextLine)-MaxLen+sz);
  IF a=NIL THEN Request(ADR(oom)) END;
  RETURN a;
END AllocLine;


(*------  The fastest textoutput-Procedure in the world (maybe):  ------*)

PROCEDURE QText(y{1}: INTEGER;
                str{8}: LONGINT;
                bm{9}: g.BitMapPtr;
                fd{10}: FontDataPtr);  (* $EntryExitCode- *)

BEGIN
INLINE(
(*0000*) 02F0DH,04BFAH,001FEH,04244H,051C6H,050C7H,03429H,00000H,
(*0010*) 048C2H,0C2C2H,02869H,0000CH,02269H,00008H,0D3C1H,0D9C1H,
(*0020*) 02649H,02C4CH,03202H,05341H,0429BH,0429BH,0429EH,0429EH,
(*0030*) 051C9H,0FFF6H,03202H,0E741H,09242H,01018H,06700H,00500H,
(*0040*) 0B03CH,00020H,06400H,00100H,0B03CH,00011H,06D00H,00028H,
(*0050*) 0B03CH,00016H,0B03CH,00015H,06D00H,00008H,057C6H,056C7H,
(*0060*) 060D8H,062D6H,0903CH,00011H,04880H,03800H,0E344H,0D840H,
(*0070*) 0E144H,0D844H,060C4H,05300H,06600H,00008H,04BFAH,000DEH,
(*0080*) 060B8H,05300H,06600H,00008H,04BFAH,000D6H,060ACH,05300H,
(*0090*) 06600H,00008H,04BFAH,000F0H,060A0H,05300H,06600H,00008H,
(*00A0*) 04BFAH,0010AH,06094H,05300H,06600H,00008H,04BFAH,00154H,
(*00B0*) 06088H,05300H,06600H,0000AH,04BFAH,0016EH,06000H,0FF7CH,
(*00C0*) 05300H,06600H,0000AH,04BFAH,00190H,06000H,0FF6EH,05300H,
(*00D0*) 06600H,0000AH,04BFAH,001D8H,06000H,0FF60H,05300H,06600H,
(*00E0*) 0000AH,04BFAH,0021CH,06000H,0FF52H,05300H,06600H,0000AH,
(*00F0*) 04BFAH,00234H,06000H,0FF44H,05300H,06600H,0000AH,04BFAH,
(*0100*) 0027CH,06000H,0FF36H,05300H,06600H,0000AH,04BFAH,00292H,
(*0110*) 06000H,0FF28H,05300H,06600H,0000AH,04BFAH,002D6H,06000H,
(*0120*) 0FF1AH,05300H,06600H,0000AH,04BFAH,0031EH,06000H,0FF0CH,
(*0130*) 05300H,06600H,0000AH,04BFAH,00362H,06000H,0FEFEH,04BFAH,
(*0140*) 003ACH,06000H,0FEF6H,0903CH,00020H,0C07CH,000FFH,0E740H,
(*0150*) 0D044H,047F2H,00000H,04DEBH,01800H,04ED5H,06000H,003D8H,
(*0160*) 0129EH,0D2C2H,0129EH,0D2C2H,0129EH,0D2C2H,0129EH,0D2C2H,
(*0170*) 0129EH,0D2C2H,0129EH,0D2C2H,0129EH,0D2C2H,0129EH,0CF11H,
(*0180*) 092C1H,06000H,003B2H,0189EH,0D8C2H,0189EH,0D8C2H,0189EH,
(*0190*) 0D8C2H,0189EH,0D8C2H,0189EH,0D8C2H,0189EH,0D8C2H,0189EH,
(*01A0*) 0D8C2H,0189EH,0CF14H,098C1H,06000H,0038CH,01296H,0189EH,
(*01B0*) 03A02H,01396H,05000H,0199EH,05000H,0DA42H,01396H,05000H,
(*01C0*) 0199EH,05000H,0DA42H,01396H,05000H,0199EH,05000H,0DA42H,
(*01D0*) 01396H,05000H,0199EH,05000H,0DA42H,01396H,05000H,0199EH,
(*01E0*) 05000H,0DA42H,01396H,05000H,0199EH,05000H,0DA42H,01396H,
(*01F0*) 05000H,0199EH,05000H,0CF31H,05000H,0CF34H,05000H,06000H,
(*0200*) 00336H,0129BH,0D2C2H,0129BH,0D2C2H,0129BH,0D2C2H,0129BH,
(*0210*) 0D2C2H,0129BH,0D2C2H,0129BH,0D2C2H,0129BH,0D2C2H,0129BH,
(*0220*) 08D11H,092C1H,06000H,00310H,050D1H,03A02H,050F1H,05000H,
(*0230*) 0DA42H,050F1H,05000H,0DA42H,050F1H,05000H,0DA42H,050F1H,
(*0240*) 05000H,0DA42H,050F1H,05000H,0DA42H,050F1H,05000H,0DA42H,
(*0250*) 050F1H,05000H,06000H,002E0H,0129BH,0189EH,03A02H,0139BH,
(*0260*) 05000H,0199EH,05000H,0DA42H,0139BH,05000H,0199EH,05000H,
(*0270*) 0DA42H,0139BH,05000H,0199EH,05000H,0DA42H,0139BH,05000H,
(*0280*) 0199EH,05000H,0DA42H,0139BH,05000H,0199EH,05000H,0DA42H,
(*0290*) 0139BH,05000H,0199EH,05000H,0DA42H,0139BH,05000H,0199EH,
(*02A0*) 05000H,08D31H,05000H,0CF34H,05000H,06000H,0028AH,050D1H,
(*02B0*) 0189EH,03A02H,050F1H,05000H,0199EH,05000H,0DA42H,050F1H,
(*02C0*) 05000H,0199EH,05000H,0DA42H,050F1H,05000H,0199EH,05000H,
(*02D0*) 0DA42H,050F1H,05000H,0199EH,05000H,0DA42H,050F1H,05000H,
(*02E0*) 0199EH,05000H,0DA42H,050F1H,05000H,0199EH,05000H,0DA42H,
(*02F0*) 050F1H,05000H,0199EH,05000H,0CF34H,05000H,06000H,00238H,
(*0300*) 0189BH,0D8C2H,0189BH,0D8C2H,0189BH,0D8C2H,0189BH,0D8C2H,
(*0310*) 0189BH,0D8C2H,0189BH,0D8C2H,0189BH,0D8C2H,0189BH,08D14H,
(*0320*) 098C1H,06000H,00212H,0129EH,0189BH,03A02H,0139EH,05000H,
(*0330*) 0199BH,05000H,0DA42H,0139EH,05000H,0199BH,05000H,0DA42H,
(*0340*) 0139EH,05000H,0199BH,05000H,0DA42H,0139EH,05000H,0199BH,
(*0350*) 05000H,0DA42H,0139EH,05000H,0199BH,05000H,0DA42H,0139EH,
(*0360*) 05000H,0199BH,05000H,0DA42H,0139EH,05000H,0199BH,05000H,
(*0370*) 0CF31H,05000H,08D34H,05000H,06000H,001BCH,050D4H,0D8C2H,
(*0380*) 050D4H,0D8C2H,050D4H,0D8C2H,050D4H,0D8C2H,050D4H,0D8C2H,
(*0390*) 050D4H,0D8C2H,050D4H,0D8C2H,050D4H,098C1H,06000H,00198H,
(*03A0*) 0129EH,050D4H,03A02H,0139EH,05000H,050F4H,05000H,0DA42H,
(*03B0*) 0139EH,05000H,050F4H,05000H,0DA42H,0139EH,05000H,050F4H,
(*03C0*) 05000H,0DA42H,0139EH,05000H,050F4H,05000H,0DA42H,0139EH,
(*03D0*) 05000H,050F4H,05000H,0DA42H,0139EH,05000H,050F4H,05000H,
(*03E0*) 0DA42H,0139EH,05000H,050F4H,05000H,0CF31H,05000H,06000H,
(*03F0*) 00146H,01293H,0189BH,03A02H,01393H,05000H,0199BH,05000H,
(*0400*) 0DA42H,01393H,05000H,0199BH,05000H,0DA42H,01393H,05000H,
(*0410*) 0199BH,05000H,0DA42H,01393H,05000H,0199BH,05000H,0DA42H,
(*0420*) 01393H,05000H,0199BH,05000H,0DA42H,01393H,05000H,0199BH,
(*0430*) 05000H,0DA42H,01393H,05000H,0199BH,05000H,08D31H,05000H,
(*0440*) 08D34H,05000H,06000H,000F0H,050D1H,0189BH,03A02H,050F1H,
(*0450*) 05000H,0199BH,05000H,0DA42H,050F1H,05000H,0199BH,05000H,
(*0460*) 0DA42H,050F1H,05000H,0199BH,05000H,0DA42H,050F1H,05000H,
(*0470*) 0199BH,05000H,0DA42H,050F1H,05000H,0199BH,05000H,0DA42H,
(*0480*) 050F1H,05000H,0199BH,05000H,0DA42H,050F1H,05000H,0199BH,
(*0490*) 05000H,08D34H,05000H,06000H,0009EH,0129BH,050D4H,03A02H,
(*04A0*) 0139BH,05000H,050F4H,05000H,0DA42H,0139BH,05000H,050F4H,
(*04B0*) 05000H,0DA42H,0139BH,05000H,050F4H,05000H,0DA42H,0139BH,
(*04C0*) 05000H,050F4H,05000H,0DA42H,0139BH,05000H,050F4H,05000H,
(*04D0*) 0DA42H,0139BH,05000H,050F4H,05000H,0DA42H,0139BH,05000H,
(*04E0*) 050F4H,05000H,08D31H,05000H,06000H,0004CH,050D1H,050D4H,
(*04F0*) 03A02H,050F1H,05000H,050F4H,05000H,0DA42H,050F1H,05000H,
(*0500*) 050F4H,05000H,0DA42H,050F1H,05000H,050F4H,05000H,0DA42H,
(*0510*) 050F1H,05000H,050F4H,05000H,0DA42H,050F1H,05000H,050F4H,
(*0520*) 05000H,0DA42H,050F1H,05000H,050F4H,05000H,0DA42H,050F1H,
(*0530*) 05000H,050F4H,05000H,05249H,0524CH,06000H,0FAFEH,02A5FH,
(*0540*) 04E75H);
END QText;

(*------  Copy Line:  ------*)

PROCEDURE CopyLine1(BM{8}: g.BitMapPtr; w{0},h{1},pos{2}: INTEGER);

(* $EntryExitCode- *)

BEGIN
INLINE(
(*0000*) 02668H,00008H,02868H,0000CH,0E740H,0C5C0H,047F3H,02000H,
(*0010*) 049F4H,02000H,0C3C0H,043F3H,01000H,045F4H,01000H,0E440H,
(*0020*) 05340H,026D9H,028DAH,051C8H,0FFFAH,04E75H);
END CopyLine1;


PROCEDURE CopyLine2(BM{8}: g.BitMapPtr; w{0},h{1},pos{2}: INTEGER);

(* $EntryExitCode- *)

BEGIN
INLINE(
(*0000*) 02668H,00008H,02868H,0000CH,0E740H,0C5C0H,047F3H,02000H,
(*0010*) 049F4H,02000H,0C3C0H,043F3H,01000H,045F4H,01000H,0E440H,
(*0020*) 05340H,022DBH,024DCH,051C8H,0FFFAH,04E75H);
END CopyLine2;

(*------  Get Fonts:  ------*)

PROCEDURE GetFontData(from{8},to{9}: LONGINT);

(* $EntryExitCode- *)

BEGIN
INLINE(
(*0000*) 0303CH,000BFH,03200H,0E741H,03A01H,03C01H,03E01H,0DA7CH,
(*0010*) 00600H,0DC7CH,00C00H,0DE7CH,01200H,045F0H,00000H,01412H,
(*0020*) 01382H,01000H,01602H,0E40BH,06400H,00006H,008C3H,00000H,
(*0030*) 01383H,05000H,01802H,0E20CH,08802H,01384H,06000H,01803H,
(*0040*) 0E20CH,08803H,01384H,07000H,0D4FCH,000C0H,01412H,01382H,
(*0050*) 01001H,01602H,0E40BH,06400H,00006H,008C3H,00000H,01383H,
(*0060*) 05001H,01802H,0E20CH,08802H,01384H,06001H,01803H,0E20CH,
(*0070*) 08803H,01384H,07001H,0D4FCH,000C0H,01412H,01382H,01002H,
(*0080*) 01602H,0E20BH,06400H,00006H,008C3H,00000H,01383H,05002H,
(*0090*) 01802H,0E20CH,08802H,01384H,06002H,01803H,0E20CH,08803H,
(*00A0*) 01384H,07002H,0D4FCH,000C0H,01412H,01382H,01003H,01602H,
(*00B0*) 0E20BH,06400H,00006H,008C3H,00000H,01383H,05003H,01802H,
(*00C0*) 0E20CH,08802H,01384H,06003H,01803H,0E20CH,08803H,01384H,
(*00D0*) 07003H,0D4FCH,000C0H,01412H,01382H,01004H,01382H,05004H,
(*00E0*) 01802H,0E20CH,08802H,01384H,06004H,01384H,07004H,0D4FCH,
(*00F0*) 000C0H,01412H,01382H,01005H,01382H,05005H,01802H,0E20CH,
(*0100*) 08802H,01384H,06005H,01384H,07005H,0D4FCH,000C0H,01412H,
(*0110*) 01382H,01006H,01602H,0E30BH,06400H,00006H,008C3H,00007H,
(*0120*) 01383H,05006H,01802H,0E20CH,08802H,01384H,06006H,01803H,
(*0130*) 0E20CH,08803H,01384H,07006H,0D4FCH,000C0H,01412H,01382H,
(*0140*) 01007H,01602H,0E30BH,06400H,00006H,008C3H,00007H,01383H,
(*0150*) 05007H,01802H,0E20CH,08802H,01384H,06007H,01803H,0E20CH,
(*0160*) 08803H,01384H,07007H,051C8H,0FE9CH,02449H,0D4FCH,01800H,
(*0170*) 0303CH,005FFH,02419H,04682H,024C2H,051C8H,0FFF8H,04E75H);
END GetFontData;

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

PROCEDURE MakeThink;

BEGIN
  I.MakeScreen(Screen); I.RethinkDisplay;
END MakeThink;

(*------------------------  Open Display:  --------------------------------*)

PROCEDURE InitScreen();

BEGIN

(*------  Get Font:  ------*)

  MyFont.name := ADR("topaz.font");
  MyFont.ySize := 8;
  Font := g.OpenFont(ADR(MyFont));
  GetFontData(Font.charData,ADR(fontdata));
  g.CloseFont(Font);

(*------  Open Screen:  ------*)

  NumColumns := g.gfx.normalDisplayColumns DIV 32 * 4;
  IF NumColumns>MaxLen THEN NumColumns := MaxLen END;
  NumLines := g.gfx.normalDisplayRows DIV 8;
  NuScreen.width  := 8*NumColumns;
  PageSize := 8*LONG(NumLines*NumColumns);
  NuScreen.height := 16*NumLines;
  NuScreen.depth  := 2;
  NuScreen.viewModes := {g.hires};
  NuScreen.type := I.customScreen+{I.screenQuiet};
  Screen := I.OpenScreen(NuScreen);
  IF Screen=NIL THEN Request(ADR(oom)) END;
  BM := Screen.rastPort.bitMap;
  ri := Screen.viewPort.rasInfo;
  Screen.height := Screen.height DIV 2;
  MakeThink;

(*------  Open Window:  ------*)

  NuWindow.flags  := I.rmbTrap+I.activate+I.borderless+I.reportMouse;
  NuWindow.screen := Screen;
  NuWindow.type   := I.customScreen;
  NuWindow.width  := 1;
  NuWindow.height := 1;
  FRWin := I.OpenWindow(NuWindow);
  NuWindow.topEdge := 10;
  NuWindow.width  := NuScreen.width;
  NuWindow.height := Screen.height-10;
  NuWindow.idcmpFlags := LONGSET{I.inactiveWindow,I.activeWindow,I.rawKey,I.mouseButtons};
  Window := I.OpenWindow(NuWindow);
  IF Window=NIL THEN Request(ADR(oom)) END;

END InitScreen;

(*------  Read one TextLine into a Variable:  ------*)

PROCEDURE GetTextLine(): TextLinePtr;
(* returns NIL at EOF *)

VAR
  l: TextLinePtr;
  sz,wd,le,i: INTEGER;
  c: CHAR;
  txt: ARRAY MaxLen+1 OF CHAR;
  num: ARRAY 10 OF INTEGER;
  newcol: BOOLEAN;
  oldstyle: SHORTSET;

  PROCEDURE GetCh();

  BEGIN
    IF RQPos=RQLen THEN
      RQLen := d.Read(MyFile,ADR(Buffer),SIZE(Buffer));
      RQPos := 0;
    END;
    IF RQLen=0 THEN c := 0X ELSE
      c := Buffer[RQPos]; IF c=0X THEN c:=1X END;
      INC(RQPos); INC(le);
    END;
  END GetCh;

BEGIN
  IF RQLen=0 THEN RETURN NIL END;
  sz := 0; wd := 0; le := 0;
  IF Italic IN style THEN
    IF Bold IN style THEN txt[sz] := boldit ELSE txt[sz] := italic END; INC(sz);
  ELSE
    IF Bold IN style THEN txt[sz] := bold; INC(sz) END;
  END;
  IF Ulin IN style THEN txt[sz] := ulineon; INC(sz) END;
  IF    Inv IN style     THEN txt[sz] := CHR(fg+4*bg+1); INC(sz)
  ELSIF (fg#1) OR (bg#0) THEN txt[sz] := CHR(bg+4*fg+1); INC(sz) END;
  REPEAT
    LOOP
      GetCh;
      IF (c#1BX) AND (c#9BX) THEN EXIT END;
      i := -1;
      REPEAT
        GetCh;
        IF (c>=30X) AND (c<=39X) THEN
          INC(i); num[i] := 0;
          REPEAT
            num[i] := 10*num[i]+ORD(c)-ORD(30X); GetCh;
          UNTIL (c<30X) OR (c>39X);
        END;
        c := CAP(c);
      UNTIL (c>=3FX(*"?"*)) AND (c<=5AX) OR (c=0X) OR (i=9);
      IF c=4DX THEN
        newcol := f; oldstyle := style;
        WHILE (i>=0) AND (sz<MaxLen-1) DO
          CASE num[i] OF
          0: style := SHORTSET{}; fg := 1; bg := 0; newcol := w |
          1: INCL(style,Bold) |
          2: fg := 2; newcol := w (* I hope this is correct *) |
          3: INCL(style,Italic) |
          4: INCL(style,Ulin) |
          7: INCL(style,Inv); newcol := w |
          30..37: fg := INTEGER(SET(num[i]-30) * {0,1}); newcol := w |
          40..47: bg := INTEGER(SET(num[i]-40) * {0,1}); newcol := w |
          ELSE END;
          DEC(i);
        END;
        IF (oldstyle#style) AND (sz<MaxLen) THEN
          IF Italic IN style THEN
            IF Bold IN style THEN txt[sz] := boldit ELSE txt[sz] := italic END;
          ELSE
            IF Bold IN style THEN txt[sz] := bold   ELSE txt[sz] := plain  END;
          END;
          INC(sz);
          IF (Ulin IN style) THEN
            IF NOT((Ulin IN oldstyle)) AND (sz<MaxLen) THEN
              txt[sz] := ulineon;
              INC(sz);
            END;
          ELSE
            IF (Ulin IN oldstyle) AND (sz<MaxLen) THEN
              txt[sz] := ulineoff;
              INC(sz);
            END;
          END;
        END;
        IF newcol AND (sz<MaxLen) THEN
          IF Inv IN style THEN txt[sz] := CHR(fg+4*bg+1)
                          ELSE txt[sz] := CHR(bg+4*fg+1) END;
          INC(sz);
        END;
      END;
    END;
    CASE c OF
    20X..7FX:
    txt[sz] := c; INC(sz); INC(wd) |
    0A1X..0FFX:
    DEC(c,32); txt[sz] := c; INC(sz); INC(wd) |
    8X:
    IF wd>0 THEN DEC(sz); DEC(wd); END |
    9X:
      REPEAT
        txt[sz] := 20X; INC(sz); INC(wd)
      UNTIL (sz=MaxLen) OR (wd=NumColumns) OR (SET(sz)*{0..2}={}) |
    0A0X:
    txt[sz] := 20X; INC(sz); INC(wd) |
    ELSE
    END;
  UNTIL (c=0AX) OR (c=0X) OR (wd>=NumColumns) OR (sz>=MaxLen);
  l := AllocLine(sz);
  l.len := le; l.size:= sz;
  WHILE sz>0 DO DEC(sz); l.text[sz]:=txt[sz] END;
  RETURN l;
END GetTextLine;

(*------  Write Line at Bottom of Text:  ------*)

PROCEDURE AddBottomLine(Line: TextLinePtr; Fast: BOOLEAN);

VAR
  i,j: INTEGER;
  trash: LONGINT;
  s1,d1,s2,d2: POINTER TO LONGINT;
  a: LONGINT;

BEGIN
  QText(8*(ScreenPos+NumLines),ADR(Line.text),BM,ADR(fontdata));
  IF Fast THEN
    INC(ri.ryOffset,8); MakeThink;
    CopyLine1(BM,NumColumns,NumLines,ScreenPos);
  ELSE
    a := 8*LONG(ScreenPos*NumColumns);
    d1 := BM.planes[0] + a; s1 := LONGINT(d1) + PageSize;
    d2 := BM.planes[1] + a; s2 := LONGINT(d2) + PageSize;
    i := 8;
    REPEAT
      INC(ri.ryOffset);
      MakeThink;
      j := NumColumns DIV 4;
      REPEAT
        d1^ := s1^; INC(d1,4); INC(s1,4);
        d2^ := s2^; INC(d2,4); INC(s2,4);
        DEC(j);
      UNTIL j=0;
      DEC(i);
    UNTIL i=0;
  END;
  INC(ScreenPos);
  IF ScreenPos=NumLines THEN
    ScreenPos := 0;
    ri.ryOffset := 0;
  END;
END AddBottomLine;

(*------  Write String to Screen:  ------*)

PROCEDURE Write(String: StringPtr; Fast: BOOLEAN);

VAR text: TextLine;

BEGIN
  text := FirstLine^;
  i := Length(String^);
  IF i>=NumColumns THEN i := NumColumns-1 END;
  text.text[i+1] := 0X;
  REPEAT
    text.text[i] := String^[i];
    IF text.text[i]>80X THEN DEC(text.text[i],32) END;
    DEC(i)
  UNTIL i<0;
  AddBottomLine(ADR(text),Fast);
END Write;

(*------  Check whether BottomLine.next is NIL or not:  ------*)

PROCEDURE TryBottomnext(): BOOLEAN;
(* returns TRUE if BottomLine.next#NIL END; *)

BEGIN
  IF (BottomLine.next=NIL) AND (MyFile#NIL) THEN
    SignalNewData := w;
    REPEAT UNTIL mySigBit IN e.Wait(mySig);
    SignalNewData := f;
  END;
  RETURN BottomLine.next#NIL;
END TryBottomnext;

(*------  Scroll down one Line:  ------*)

PROCEDURE ScrollDown(Fast: BOOLEAN);

BEGIN
  IF TryBottomnext() THEN
    BottomLine := BottomLine.next;
    INC(AnzLines);
    INC(TextLength,BottomLine.len);
  ELSE RETURN END;
  IF AnzLines>=NumLines THEN TopLine := TopLine.next END;
  AddBottomLine(BottomLine,Fast);
END ScrollDown;

(*------  Scroll Up one Line:  ------*)

PROCEDURE ScrollUp(Fast: BOOLEAN);

VAR
  i,j: INTEGER;
  s1,d1,s2,d2: POINTER TO LONGINT;
  a: LONGINT;

BEGIN
  IF TopLine.prev#NIL THEN
    TopLine := TopLine.prev;
    DEC(TextLength,BottomLine.len);
    DEC(AnzLines);
    BottomLine := BottomLine.prev;
    IF ScreenPos=0 THEN
      ri.ryOffset  := NumLines*8;
      ScreenPos := NumLines-1;
    ELSE
      DEC(ScreenPos);
    END;
    QText(8*ScreenPos,ADR(TopLine.prev.text),BM,ADR(fontdata));
    IF Fast THEN
      DEC(ri.ryOffset,8); MakeThink;
      CopyLine2(BM,NumColumns,NumLines,ScreenPos);
    ELSE
      a := 8*LONG((ScreenPos+1)*NumColumns);
      s1 := BM.planes[0] + a; d1 := LONGINT(s1) + PageSize;
      s2 := BM.planes[1] + a; d2 := LONGINT(s2) + PageSize;
      i := 8;
      REPEAT
        DEC(ri.ryOffset);
        MakeThink;
        j := NumColumns DIV 4;
        REPEAT;
          DEC(d1,4); DEC(s1,4); d1^ := s1^;
          DEC(d2,4); DEC(s2,4); d2^ := s2^;
          DEC(j);
        UNTIL j=0;
        DEC(i);
      UNTIL i=0;
    END;
  END;   (* IF TopLine#NIL ... *)
END ScrollUp;

(*------  Undo last Write():  ------*)

PROCEDURE DelLine();

VAR
  i,j: INTEGER;
  s1,d1,s2,d2: POINTER TO LONGINT;
  a: LONGINT;
  text: TextLine;

BEGIN
  IF ScreenPos=0 THEN
    ri.ryOffset  := NumLines*8;
    ScreenPos := NumLines;
  END;
  DEC(ScreenPos);
  IF TopLine.prev#NIL THEN
    QText(8*ScreenPos,ADR(TopLine.prev.text),BM,ADR(fontdata));
  ELSE
    QText(8*ScreenPos,ADR(FirstLine.text),BM,ADR(fontdata));
  END;
  a := (LONG(ScreenPos)+1)*8*LONG(NumColumns);
  s1 := BM.planes[0] + a; d1 := LONGINT(s1) + PageSize;
  s2 := BM.planes[1] + a; d2 := LONGINT(s2) + PageSize;
  i := 8;
  REPEAT
    DEC(ri.ryOffset);
    MakeThink;
    j := NumColumns DIV 4;
    REPEAT
      DEC(d1,4); DEC(s1,4); d1^ := s1^;
      DEC(d2,4); DEC(s2,4); d2^ := s2^;
      DEC(j);
    UNTIL j=0;
    DEC(i);
  UNTIL i=0;
END DelLine;

(*------  Clear Display:  ------*)

PROCEDURE ClearBitMaps();

BEGIN
  g.BltClear(BM.planes[0],2*PageSize,0);
  g.BltClear(BM.planes[1],2*PageSize,0);
  ScreenPos := 0;
  ri.ryOffset := 0;
END ClearBitMaps;

(*------  Convert Integer to String:  ------*)

PROCEDURE IntToStr(VAR String: String;
                       At,Chars: INTEGER;
                       int: LONGINT);

VAR
  Cnt: INTEGER;
  Ziff: LONGINT;

BEGIN
  INC(Chars,At);
  IF (Length(String)<Chars) AND (SIZE(String)>=Chars) THEN
    String[Chars] := 0X;
  END;
  REPEAT
    DEC(Chars);
    String[Chars] := CHR(int MOD 10 + ORD(30X)); int := int DIV 10;
  UNTIL (Chars=At) OR (int=0);
  WHILE Chars>At DO DEC(Chars); String[Chars] := 20X END;
END IntToStr;

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

PROCEDURE GetLength(t: TextLinePtr);

BEGIN
  TextLength := 0; AnzLines := 0;
  WHILE t#NIL DO INC(AnzLines); INC(TextLength,t.len); t := t.prev END;
END GetLength;

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

PROCEDURE NewDisplay();
(* Zeichnet ab BottomLine neu *)

VAR
  i: INTEGER;
  l: TextLinePtr;

BEGIN
  ClearBitMaps;
  i := 1;
  l := BottomLine;
  WHILE (i<NumLines) AND (BottomLine.next#NIL) DO
    BottomLine := BottomLine.next;
    INC(i);
  END;
  WHILE (i<NumLines) AND (l.prev#NIL) DO l := l.prev; INC(i) END;
  BottomLine := l;
  GetLength(l);
  Write(ADR(empty),w);
  AddBottomLine(BottomLine,w);
  i := 1;
  WHILE i<NumLines DO
    TopLine := l;
    ScrollDown(w);
    INC(i);
  END;
  Scroll := f;
END NewDisplay;

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

PROCEDURE ShowProc();

VAR
  l: TextLinePtr;
  Down: BOOLEAN;               (* Scroll-Direction                  *)
  End: BOOLEAN;                (* Quit next time Space is pressed ? *)
  i,j,k,m: INTEGER;
  MyMsg: I.IntuiMessage;       (* contains Message                  *)
  Shift: BOOLEAN;              (* Shifted Keystroke ?               *)
  Alt: BOOLEAN;                (* Altered Keystroke ?               *)
  win: I.WindowPtr;
  Find,FindStr: String;
  flen: INTEGER;
  HiText: TextLine;            (* Highlited textline *)
  OldHiText: TextLinePtr;      (* original, un-hilited text *)
  found: BOOLEAN;

  PROCEDURE WaitAllRead();

  BEGIN
    IF MyFile#NIL THEN
      SignalAllRead := w;
      REPEAT UNTIL mySigBit IN e.Wait(mySig);
      SignalAllRead := f;
    END;
  END WaitAllRead;

  PROCEDURE HiLite(t: TextLinePtr; at,len: INTEGER);
  (* Hilites len chars of t.text starting from at *)

  VAR
    c: INTEGER;
    col: CHAR;

  BEGIN
    OldHiText := t; HiText := OldHiText^;
    IF at+len+2<MaxLen THEN
      c := 0; col := 5X;
      WHILE c<at DO
        IF HiText.text[c]<CHAR(17) THEN col := HiText.text[c] END;
        INC(c);
      END;
      HiText.text[at] := CHR(17-ORD(col));
      c := at; INC(len,at);
      WHILE c<len DO
        HiText.text[c+1] := OldHiText.text[c];
        INC(c);
      END;
      HiText.text[c+1] := col;
      REPEAT
        HiText.text[c+2] := OldHiText.text[c];
        INC(c);
      UNTIL HiText.text[c-1]=0X;
    END;
    IF HiText.next#NIL THEN HiText.next.prev := ADR(HiText) END;
    IF HiText.prev#NIL THEN HiText.prev.next := ADR(HiText) END;
  END HiLite;

  PROCEDURE UnHiLite();

  BEGIN
    IF HiText.next#NIL THEN HiText.next.prev := OldHiText END;
    IF HiText.prev#NIL THEN HiText.prev.next := OldHiText END;
  END UnHiLite;

  PROCEDURE ChkBotNewDisp();

  VAR c: INTEGER;

  BEGIN
    IF NOT found THEN
      I.DisplayBeep(Screen);
      IF TopLine.prev=NIL THEN BottomLine := TopLine
                          ELSE BottomLine := TopLine.prev END;
    ELSE BottomLine := BottomLine.prev.next END;
    NewDisplay;
    IF found THEN UnHiLite END;
  END ChkBotNewDisp;

  PROCEDURE Search(): BOOLEAN;
  (* searches string and hilites it if found. result is TRUE if string found *)

  BEGIN
    i := 0;
    IF BottomLine.len<NumColumns THEN m := BottomLine.len ELSE m := NumColumns END;
    WHILE i<BottomLine.size DO
      j := 0; k := i;
      WHILE CAP(BottomLine.text[k])=FindStr[j] DO
        INC(j); INC(k);
        IF FindStr[j]=0X THEN
          SETREG(0,TryBottomnext());
          HiLite(BottomLine,k-flen,flen);
          found := w; RETURN w;
        END;
      END;
      INC(i);
    END;
    RETURN f;
  END Search;

  PROCEDURE DisplayInfo();

  BEGIN
(* File: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xx % (xxxxxx of xxxxxx Bytes) xxxxxx Lines *)
    IStr := "XFile: "; IStr[0] := 7X;
    Append(IStr,ADR(Name));
    Append(IStr,ADR("                              "));
    IStr[36] := 0X;
    Append(IStr,ADR("xxx % (xxxxxx of xxxxxx Bytes) xxxxxx Lines"));
    IntToStr(IStr,36,3,TextLength * 100 DIV FileLength);
    IntToStr(IStr,43,6,TextLength);
    IntToStr(IStr,53,6,FileLength);
    IntToStr(IStr,67,6,AnzLines-1);
    i := 79;
    WHILE (i<255) AND (i<NumColumns+2) DO IStr[i] := " "; INC(i) END;
    IStr[i] := 0X; Write(ADR(IStr),f);
    Info := w;
  END DisplayInfo;

BEGIN

  REPEAT UNTIL mySig = e.Wait(mySig);

  Scroll := w; Fast := f; Down := w; End := f; Find := empty;

  LOOP

    IF NewDisp THEN NewDisp := f; NewDisplay END;

(*------  Type Text:  ------*)

    LOOP
      IF Scroll THEN
        IF Down THEN
          ScrollDown(Fast);
          Scroll := (MyFile#NIL) OR (BottomLine.next#NIL);
        ELSE
          ScrollUp(Fast);
          Scroll := TopLine.prev#NIL;
        END;
      ELSE
        e.WaitPort(Window.userPort);
      END;

      MyMsgPtr := LONGINT(e.GetMsg(Window.userPort));

      IF (MyMsgPtr#NIL) THEN
        IF NOT (I.inactiveWindow IN MyMsgPtr.class) THEN EXIT END;
        e.ReplyMsg(MyMsgPtr);
        e.WaitPort(Window.userPort);
        MyMsgPtr := LONGINT(e.GetMsg(Window.userPort));
      END;
    END;

    MyMsg := MyMsgPtr^;
    e.ReplyMsg(MyMsgPtr);

    IF I.mouseButtons IN MyMsg.class THEN
      MyMsg.class := LONGSET{I.rawKey};
      IF    ie.leftButton  IN MyMsg.qualifier THEN MyMsg.code := 40H
      ELSIF ie.rightButton IN MyMsg.qualifier THEN MyMsg.code := 41H END;
    END;

    IF (I.rawKey IN MyMsg.class) AND (MyMsg.code<80H) THEN

      IF    Info           THEN DelLine; Info := f;
      ELSIF MyMsg.code=0FH THEN DisplayInfo; Scroll := f END;

      Shift := {} # {ie.lShift,ie.rShift} * MyMsg.qualifier;
      Alt   := {} # {ie.lAlt  ,ie.rAlt}   * MyMsg.qualifier;

      CASE MyMsg.code OF

      40H:                                         (* Space *)
            Fast := Shift;
            IF (MyFile=NIL) AND (BottomLine.next=NIL) THEN
              IF End THEN EXIT ELSE End:=w END;
            ELSE
              End := f;
            END;
            IF Down THEN
              IF Scroll OR End THEN DisplayInfo END;
              Scroll := NOT(Scroll);
            ELSE
              Down := w;
              Scroll := w;
            END |

      41H:                                       (* BackSpace *)
            Fast := Shift;
            Scroll := Down OR NOT Scroll;
            Down := f |

      4DH,1EH,1FH:                                   (* Down *)
            IF Shift THEN
              Scroll := NOT(Down AND Scroll) OR NOT Fast;
              Fast := w; Down := w;
            ELSE
              i:=1; IF Alt OR (MyMsg.code=1FH) THEN i:=NumLines END;
              WHILE i#0 DO
                ScrollDown(NOT Shift);
                DEC(i);
              END;
              Scroll := f;
            END |

      4CH,3EH,3FH:                                        (* Up *)
            IF Shift THEN
              Scroll := Down OR NOT Scroll OR NOT Fast;
              Fast := w; Down := f;
            ELSE
              i:=1; IF Alt OR (MyMsg.code=3FH) THEN i:=NumLines END;
              WHILE i#0 DO
                ScrollUp(NOT Shift);
                Scroll := f;
                DEC(i);
              END;
            END; |

      44H,43H:                                        (* CR *)
            ScrollDown(f);
            Scroll := f; |

      14H,3DH:                                        (* Home *)
            i:=SHORT(NumLines-AnzLines);
            IF i>0 THEN
              REPEAT DEC(i); ScrollDown(w) UNTIL i=0; Scroll := f;
            ELSE
              BottomLine := FirstLine; NewDisplay;
            END |

      35H,1DH:                                         (* End *)
            WaitAllRead;
            BottomLine := LastLine;
            i := NumLines;
            WHILE (i>1) AND (BottomLine.prev#NIL) DO
              BottomLine := BottomLine.prev;
              DEC(i);
            END;
            NewDisplay |

      23H,36H:                                        (* Find, Next *)
            IF MyMsg.code=23H THEN
              INC(Screen.height,Screen.height);
              I.MakeScreen(Screen);
              NuWindow.leftEdge    := 100;
              NuWindow.topEdge     := NumLines*4-6+ri.ryOffset;
              NuWindow.width       := NuScreen.width-200;
              NuWindow.height      := 12;
              NuWindow.blockPen    := 1;
              NuWindow.idcmpFlags  := LONGSET{I.inactiveWindow,I.gadgetUp};
              NuWindow.flags       := I.activate;
              NuWindow.firstGadget := ADR(StrGadget);
              NuWindow.screen      := Screen;
              NuWindow.type        := I.customScreen;
              StrGadget.leftEdge   := 2;
              StrGadget.topEdge    := 2;
              StrGadget.width      := NuWindow.width-4;
              StrGadget.height     := 8;
              StrGadget.activation := {I.stringCenter,I.relVerify};
              StrGadget.gadgetType := I.strGadget;
              StrGadget.specialInfo:= ADR(StrInfo);
              StrInfo.buffer       := ADR(Find);
              StrInfo.maxChars     := 80;
              win := I.OpenWindow(NuWindow);
              IF win=NIL THEN EXIT END;
              SETREG(0,I.ActivateGadget(ADR(StrGadget),win,NIL));
              e.WaitPort(win.userPort);
              I.CloseWindow(win);
              Screen.height := Screen.height DIV 2;
            END;
            ClearBitMaps();
            flen := 0;
            LOOP
              FindStr[flen] := CAP(Find[flen]);
              IF    FindStr[flen]>80X THEN DEC(FindStr[flen],32)
              ELSIF FindStr[flen]=0X  THEN EXIT END;
              INC(flen);
            END;
            found := f;
            IF flen#0 THEN
              BottomLine := TopLine;
              LOOP
                IF Search() THEN EXIT END;
                SETREG(0,TryBottomnext());
                BottomLine := BottomLine.next;
                IF BottomLine=NIL THEN EXIT END;
              END;
            ELSE
              BottomLine := NIL;
            END;
            ChkBotNewDisp |

      19H:                                      (* find previous *)
            IF FindStr[0]#0X THEN
              ClearBitMaps;
              BottomLine := TopLine;
              IF BottomLine.prev#NIL THEN BottomLine:=BottomLine.prev END;
              found := f;
              REPEAT
                BottomLine := BottomLine.prev
              UNTIL Search() OR (BottomLine=NIL);
              ChkBotNewDisp
            END |

      18H:  IF Shift AND Alt AND NOT print THEN                (* Printout *)
              PStr := "TYPE "; Append(PStr,ADR(Name)); Append(PStr,ADR(" TO PRT:"));
              WaitAllRead; print := w; e.Signal(Me,mySig);
            END |

      28H:  ClearBitMaps;                          (* Load Text *)
            MakeThink; NewText := w; e.Signal(Me,mySig);
            REPEAT UNTIL (mySig = e.Wait(mySig)) AND NOT NewText |

      5FH,25H: ClearBitMaps();
            Write(ADR("\023               MuchMore V2.0 Commands:\005"),w);
            Write(ADR(empty),w);
            Write(ADR(" \015Space\005,\015 LMB\005:      Start / Stop scrolling. Quit at end of file."),w);
            Write(ADR(" \015BackSpace\005,\015 RMB\005:  Start / Stop scrolling backwards."),w);
            Write(ADR(" \015Up\005/\015Down\005:         Move one line \015up\005 or \015down\005."),w);
            Write(ADR(" \015Shift \005+\015 Up\005/\015Down\005: Start / Stop quick scrolling \015up\005 or \015down\005."),w);
            Write(ADR(" \015Alt \005+\015 Up\005/\015Dwn\005:    Move one page \015up\005 or \015down\005."),w);
            Write(ADR(" \015PgUp\005/\015PgDn\005:       Move one page \015up\005 or \015down\005."),w);
            Write(ADR(" \015T\005,\015 Home\005:         Jump to \015t\005op of text."),w);
            Write(ADR(" \015B\005,\015 End\005:          Jump to \015b\005ottom of text."),w);
            Write(ADR(" \015NK 0\005:            Display Filelength etc."),w);
            Write(ADR(" \015F\005/\015N\005/\015P\005:           \015F\005ind string / \015n\005ext / \015p\005revious occurance."),w);
            Write(ADR(" \015Shift \005+\015 Alt \005+\015 O\005: Create print\015o\005ut of the text"),w);
            Write(ADR(" \015L\005:               \015L\005oad new text"),w);
            Write(ADR(" \015HELP\005,\015 H\005:         Show Commands."),w);
            Write(ADR(" \015ESC\005,\015 Q\005,\015 X\005,\015 NK 5\005:\015 Q\005uit."),w);
            Write(ADR(empty),w);
            Write(ADR("© \0231989 Fridtjof Siebert, Nobileweg 67, D-7000-Stuttgart-40"),w);
            Write(ADR("  \023Please refer to MuchMore.ReadMe for a detailed copyright notice"),w);
            i := (NumLines-20) DIV 2;
            WHILE i>0 DO Write(ADR(empty),w); DEC(i) END;
            LOOP
              e.WaitPort(Window.userPort);
              MyMsgPtr := LONGINT(e.GetMsg(Window.userPort));
              IF (I.rawKey IN MyMsgPtr.class) AND (MyMsgPtr.code<128) THEN EXIT END;
              e.ReplyMsg(MyMsgPtr);
            END;
            e.ReplyMsg(MyMsgPtr);
            BottomLine := TopLine;
            NewDisplay |

      10H,45H,32H,2EH: EXIT |                        (* ESC, Q, X, NK 5 *)

      ELSE END;   (* CASE code OF *)
    END;   (* IF class=IDCMPFlagSet{rawKey} THEN *)
  END;   (* LOOP *)

  Done := w;
  e.Signal(Me,mySig);
  REPEAT UNTIL (1 IN e.Wait(LONGSET{})) AND f;

END ShowProc;


(*--------------------------  File Requester:  ----------------------------*)


PROCEDURE FileRequest{arp,-294}(filereq{8}: FileRequesterPtr): LONGINT;

PROCEDURE TackOn{arp,-624}(pathname{8},filename{9}: STRPTR);


PROCEDURE FileReq(first: BOOLEAN);

BEGIN
  NewDisp := TRUE;
  IF arp#NIL THEN
    FR.hail      := ADR(MuchText);
    FR.ddef      := ADR(Filename);
    FR.ddir      := ADR(Dirname);
    FR.wind      := FRWin;
    IF FileRequest(ADR(FR))#NIL THEN
      Name := Dirname; TackOn(ADR(Name),ADR(Filename));
      RETURN
    END;
  END;
  IF first THEN Request(ADR(usage)) ELSE HALT(0) END;
END FileReq;


(*------------------------------  MAIN:  ----------------------------------*)


BEGIN

(*------  Init:  ------*)

(* These variables are automatically set to zero:
  Screen := NIL; Window := NIL; FirstLine := NIL; TopLine := NIL;
  BottomLine := NIL; MyFile := NIL; AnzLines := 0; Info := f;
  MyLock := NIL; FileInfo := NIL; ScreenPos := 0; arp := NIL;
  ShowTaskRunning := f; SignalNewData := f; SignalAllRead := f;
  Done := f; print := f; bg := 0; style := StyleSet{}; OldDir := NIL;
*)
  mySigBit := -1; Me := e.FindTask(0); fg := 1;

  arp := e.OpenLibrary(ADR("arp.library"),34);
  mySigBit := SHORT(e.AllocSignal(-1));
  IF mySigBit<0 THEN HALT(0) END;
  mySig := LONGSET{mySigBit};

(*------  Setup:  ------*)

  FirstLine := AllocLine(0);
(*  FirstLine.size := 0;
    FirstLine.text[0] := 0X; *)
  NEW(FileInfo);

(*------  Start:  ------*)

  IF wb.WBStarted THEN

    IF wb.WBenchMsg.numArgs=2 THEN
      ArgPtr := wb.WBenchMsg.argList^[1].name; Name := ArgPtr^;
      OldDir := d.CurrentDir(wb.WBenchMsg.argList^[1].lock);
    ELSE FileReq(w) END

  ELSE

    IF o.dosCmdLen<=1 THEN
      FileReq(w)
    ELSE
      CommLine := o.dosCmdBuf; i:=0; j:=0;
      WHILE CommLine^=20X DO INC(CommLine); INC(j) END;
      WHILE (i+j<o.dosCmdLen) AND (CommLine^#0AX) DO
        Name[i] := CommLine^; INC(i); INC(CommLine);
      END;
      Name[i]:= 0X;
      IF Name="?" THEN Request(ADR(usage)) END;
    END;

  END;

  LOOP
    MyFile := d.Open(ADR(Name),d.oldFile);
    IF MyFile#NIL THEN EXIT END;
    FileReq(w);
  END;

  InitScreen();

  ShowTask.spLower := ADR(ShowStack);
  ShowTask.spUpper := ADR(ShowStack[3996]);
  ShowTask.spReg   := ShowTask.spUpper;
  ShowTask.node.type := e.task;
  ShowTask.node.name := ADR("Show.MM");
  ShowTask.node.pri  := Me.node.pri+1;

  e.Forbid;
    e.AddTask(ADR(ShowTask),ADR(ShowProc),NIL);
    ShowTaskRunning := w;
    Window.userPort.sigTask := ADR(ShowTask);
  e.Permit;

  LOOP

    RQLen := -1; RQPos := -1;
    AnzLines := 1;
    LastLine := FirstLine;
    BottomLine := FirstLine;
    TopLine    := FirstLine;
    TextLength := 0;

    MyLock := d.Lock(ADR(Name),d.sharedLock);
    IF MyLock=NIL THEN Request(ADR(cof)) END;
    IF NOT d.Examine(MyLock,FileInfo) THEN Request(ADR(cof)) END;
    FileLength := FileInfo.size;

    d.UnLock(MyLock); MyLock := NIL;
    IF FileLength=0 THEN HALT(0) END;

    e.Signal(ADR(ShowTask),mySig);

    i := 0;
    REPEAT
      INC(i);
      IF i=20 THEN
        IF e.AvailMem(LONGSET{e.largest})<16000 THEN Request(ADR(oom)) END;
        i := 0;
      END;
      LoadLine := GetTextLine();
      IF LoadLine=NIL THEN
        d.Close(MyFile);
        MyFile := NIL;
      ELSE
        LoadLine.prev := LastLine;
        e.Forbid;
          LastLine.next := LoadLine;
          LastLine := LoadLine;
        e.Permit;
      END;
      IF SignalNewData THEN e.Signal(ADR(ShowTask),mySig) END;
    UNTIL (MyFile=NIL) OR Done OR NewText;
    IF SignalAllRead THEN e.Signal(ADR(ShowTask),mySig) END;
    REPEAT
      REPEAT UNTIL mySig = e.Wait(mySig);
      IF print THEN
        nili := d.Open(ADR(nil),d.oldFile); nilo := d.Open(ADR(nil),d.newFile);
        SETREG(0,d.Execute(ADR(PStr),nili,nilo)); d.Close(nili); d.Close(nilo); print := f;
      END;
      IF Done THEN EXIT END;
    UNTIL NewText;
    IF MyFile#NIL THEN d.Close(MyFile); MyFile := NIL END;
    LoadLine := FirstLine^.next;
    WHILE LoadLine#NIL DO
      LastLine := LoadLine^.next;
      DISPOSE(LoadLine);
      LoadLine := LastLine;
    END;
    FirstLine^.next := NIL; NewText := f;
    WHILE MyFile=NIL DO
      FileReq(f);
      MyFile := d.Open(ADR(Name),d.oldFile);
    END;
  END;

CLOSE

  IF ShowTaskRunning THEN e.RemTask(ADR(ShowTask)) END;
  IF Window#NIL      THEN I.CloseWindow(Window) END;
  IF Screen#NIL      THEN I.CloseScreen(Screen) END;
  IF MyFile#NIL      THEN d.Close(MyFile) END;
  IF MyLock#NIL      THEN d.UnLock(MyLock) END;
  IF OldDir#NIL      THEN SETREG(0,d.CurrentDir(OldDir)) END;
  IF mySigBit>=0     THEN e.FreeSignal(mySigBit) END;
  IF arp#NIL         THEN e.CloseLibrary(arp) END;

END MuchMore.


