home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d2xx / d253 / muchmore.lha / MuchMore / src / MuchMore.imp < prev    next >
Text File  |  1989-10-19  |  51KB  |  1,612 lines

  1. (*---------------------------------------------------------------------------
  2.  :Program.      MuchMore.imp
  3.  :Author.       Fridtjof Siebert
  4.  :Address.      Nobileweg 67, D-7000 Stuttgart 40
  5.  :Shortcut.     [fbs]
  6.  :Copyright.    PD
  7.  :Language.     OBERON
  8.  :Translator.   AMOK OBERON Compiler
  9.  :History. V1.0 summer-88: First very slow internal version              [fbs]
  10.  :History. V1.1 24-Sep-88: First published version                       [fbs]
  11.  :History. V1.2 26-Nov-88: Now displays Filelength & Percentage          [fbs]
  12.  :History.      27-Nov-88: Mouse can be used instead of Space / BackSpace[fbs]
  13.  :History. V1.3 29-Apr-89: Strong increase in speed, removed WarpText    [fbs]
  14.  :History.      29-Apr-89: Now supports Numeric Keys (Home,PgUp etc.)    [fbs]
  15.  :History.      29-Apr-89: Now opens Screen as big as gfx.normalDisplay  [fbs]
  16.  :History. V1.4 29/30-Apr-89: Asynchronus loading / displaying. Very nice[fbs]
  17.  :History.      30-Apr-89, 00:33: Removed bugs in Filelength & L-Command [fbs]
  18.  :History.      30-Apr-89, 02:21: Added Find-Command                     [fbs]
  19.  :History.      30-Apr-89, 10:30: Scrolling stops when window is inactive[fbs]
  20.  :History.      01-May-89: Allocates no more unneeded memory for text    [fbs]
  21.  :History.      07-May-89: Allocates even less memory now                [fbs]
  22.  :History.      14-May-89: Removed deadlock-bug with Find-Window         [fbs]
  23.  :History. V1.5 25-May-89: Added print feature                           [fbs]
  24.  :History.      25-May-89: Removed all imports (apart from Arts)         [fbs]
  25.  :History.      26-May-89: inspired by J. Kupfer, I added nk 5 to quit   [fbs]
  26.  :History.      26-May-89: Now handle BS correctly                       [fbs]
  27.  :History. V1.6 02-Jul-89: Now supports several fontstyles and colors    [fbs]
  28.  :History. V1.7 03-Jul-89: Is again as fast as it was with 2 colors      [fbs]
  29.  :History.      03-Jul-89: Now no more crashes when quitting while print [fbs]
  30.  :History.      07-Jul-89: removed bug with texts of length 0            [fbs]
  31.  :History. V1.8 10-Jul-89: small bug in find-command removed             [fbs]
  32.  :History.      10-Jul-89: now found strings are highlighted             [fbs]
  33.  :History.      14-Jul-89: nk0 to display fileinfo                       [fbs]
  34.  :History. V2.0 06-Aug-89: Ported this to OBERON                         [fbs]
  35.  :History.      06-Aug-89: Added ARP-FileRequester                       [fbs]
  36.  :History.      07-Aug-89: Added L - (load new file) Command             [fbs]
  37.  :History. V2.1 03-Sep-89: no more gurus if an r/w error occures         [fbs]
  38.  :History.      03-Sep-89: MM used to execute CSI-Codes backwards. fixed [fbs]
  39.  :History.      03-Sep-89: ping / pong with Shift+Fn / Fn                [fbs]
  40.  :History.      03-Sep-89: new command: goto                             [fbs]
  41.  :History. V2.2 05-Sep-89: will run with any keymapping now              [fbs]
  42.  :History. V2.3 17-Sep-89: New command: sleep & Pop-Up feature           [fbs]
  43.  :History.      17-Sep-89: "MuchMore -s" will go to sleep immediately    [fbs]
  44.  :History.      17-Sep-89: Interprets <CSI>m as <CSI>0m now              [fbs]
  45.  :History. V2.4 17-Sep-89: New command: write block "w"                  [fbs]
  46.  :History.      17-Sep-89: rewritten argument parser to allow quotes     [fbs]
  47.  :History. V2.5 18-Sep-89: now uses the 8x8 font set with SetFont        [fbs]
  48.  :History.      19-Sep-89: no more scatters memory. Allocates 4K Chunks  [fbs]
  49.  :Contents.     A Soft-Scrolling ASCII-File Printer.
  50.  :Usage.        Usage: MuchMore <FileName> | -s
  51. ---------------------------------------------------------------------------*)
  52.  
  53. DEFINITION MuchMore; END MuchMore.
  54.  
  55. IMPLEMENTATION MuchMore;
  56.  
  57. (* $OvflChk- $RangeChk- $StackChk- $NilChk- $ReturnChk- $CaseChk- *)
  58.  
  59. IMPORT o:  OberonLib,
  60.        d:  Dos,
  61.        e:  Exec,
  62.            Input,
  63.        ie: InputEvent,
  64.        I:  Intuition,
  65.        g:  Graphics,
  66.        wb: Workbench,
  67.        C:  Console,
  68.        km: KeyMap;
  69.  
  70. (*-------------------------------------------------------------------------*)
  71.  
  72. CONST
  73.   empty = "";
  74.   oom = "Out of memory!";
  75.   cof = "Can't open file!";
  76.   usage = "Usage: MuchMore <Text> | -s";
  77.   rwerr = "Read/Write Error";
  78.   noarp = "Need arp for FileReq";
  79.   conerr = "Console problem";
  80.   MuchText = "MuchMore V2.5 © 1989 AMOK";
  81.   MMissleeping = "MM is sleeping";
  82.   MMisawake = "MM is awake";
  83.   nil = "NIL:";
  84.   w = TRUE;
  85.   f = FALSE;
  86.   MaxLen = 256;
  87.  
  88. (* Control codes for QText: *)
  89.   plain    = CHAR(17);
  90.   italic   = CHAR(18);
  91.   bold     = CHAR(19);
  92.   boldit   = CHAR(20);
  93.   ulineon  = CHAR(21);
  94.   ulineoff = CHAR(22);
  95.  
  96.   Italic = 0;
  97.   Bold   = 1;
  98.   Ulin   = 2;
  99.   Inv    = 3;
  100.  
  101.  
  102. TYPE
  103.   TextLinePtr = POINTER TO TextLine;
  104.   TextLine = RECORD
  105.                next: TextLinePtr;
  106.                prev: TextLinePtr;
  107.                len:  INTEGER;
  108.                size: INTEGER;
  109.                text: ARRAY MaxLen+1 OF CHAR;
  110.              END;
  111.   String = ARRAY 256 OF CHAR;
  112.   StringPtr = POINTER TO String;
  113.   FontData = ARRAY 8, 192, 8 OF CHAR;
  114.   FontDataPtr = POINTER TO FontData;
  115.  
  116.  
  117. CONST
  118. (* FileReqFlags *)
  119.   listFunc    = 0;
  120.   gEventFunc  = 1;
  121.   addGadFunc  = 2;
  122.   newWindFunc = 3;
  123.   newIDCMP    = 4;
  124.   doColor     = 5;
  125.   doMsgFunc   = 6;
  126.   doWildFunc  = 7;
  127.  
  128.   fChars = 32;
  129.   dSize  = 33;
  130.   frFirstGadg = 7680H;
  131.  
  132.  
  133. TYPE
  134.   FileName = ARRAY fChars OF CHAR;
  135.   DirName  = ARRAY dSize OF CHAR;
  136.   FileNamePtr = POINTER TO FileName;
  137.   DirNamePtr  = POINTER TO DirName;
  138.  
  139.   FileReqFunc = PROCEDURE(LONGINT,LONGINT): LONGINT;
  140.   STRPTR = POINTER TO CHAR;
  141.  
  142.   FileRequesterPtr = POINTER TO FileRequester;
  143.   FileRequester = RECORD
  144.     hail: STRPTR;                (* Hailing text                     *)
  145.     ddef: FileNamePtr;           (* Filename array (FCHARS+1)        *)
  146.     ddir: DirNamePtr;            (* Directory array (DSIZE+1)        *)
  147.     wind: I.WindowPtr;           (* Window requesting or NULL        *)
  148.     funcFlags: SHORTSET;         (* Control. See above.              *)
  149.     reserved1: SHORTINT;         (* Set this to 0                    *)
  150.     function: FileReqFunc;       (* Your function, see btdef's       *)
  151.     reserved2: LONGINT;          (* reserved                         *)
  152.   END;
  153.  
  154.  
  155. VAR
  156.   Screen: I.ScreenPtr;           (* Screen that contains the Text     *)
  157.   BM["BitMap"]: g.BitMapPtr;     (* Screen's BitMap (external)        *)
  158.   Window: I.WindowPtr;           (* My window                         *)
  159.   MyFont: g.TextAttr;            (* Topaz 8                           *)
  160.   MyFile: d.FileHandlePtr;       (* For loading Textfile              *)
  161.   FirstLine: TextLinePtr;        (* Saved Text                        *)
  162.   TopLine: TextLinePtr;          (* Points to topmost Line            *)
  163.   BottomLine: TextLinePtr;       (* Last Line displayed on Screen     *)
  164.   LoadLine: TextLinePtr;         (* currently loaded Line             *)
  165.   LastLine: TextLinePtr;         (* Last element of LineList          *)
  166.   Name: String;                  (* Text's Name                       *)
  167.   IStr,PStr: String;             (* differently used                  *)
  168.   Buffer: ARRAY 512 OF CHAR;     (* Buffer for Reading                *)
  169.   RQPos: LONGINT;                (* Position within ReadBuffer        *)
  170.   RQLen: LONGINT;                (* Number of CHARs in Buffer         *)
  171.   NumLines: INTEGER;             (* Number of Lines on Screen         *)
  172.   NumColumns: INTEGER;           (* Number of Columns on Screen       *)
  173.   PageSize: LONGINT;             (* 8*NumLines*NumColumns             *)
  174.   AnzLines: LONGINT;             (* Length of Text in Lines           *)
  175.   fontdata: FontData;            (* Fonts used by QText()             *)
  176.   MyLock,OldDir: d.FileLockPtr;  (* To Examine and Load File          *)
  177.   FileInfo: d.FileInfoBlockPtr;  (* to get File's length              *)
  178.   FileLength,TextLength: LONGINT;(* Length of File and of Displayed Text *)
  179.   ScreenPos: INTEGER;            (* actual position within bitmap     *)
  180.   ShowTask: e.Task;              (* the task that displays the text   *)
  181.   ShowStack: ARRAY 4000 OF CHAR; (* it's stack                        *)
  182.   ShowTaskRunning: BOOLEAN;      (* is Showtask activated?            *)
  183.   mySigBit: INTEGER;             (* My SignalBit                      *)
  184.   mySig: LONGSET;                (* My SignalSet = LONGSET{mySigBit}  *)
  185.   SignalNewData: BOOLEAN;        (* Signal when new data is loaded    *)
  186.   SignalAllRead: BOOLEAN;        (* send signal at end of text        *)
  187.   Done: BOOLEAN;                 (* Quit                              *)
  188.   print: BOOLEAN;                (* print text                        *)
  189.   NewText: BOOLEAN;              (* load new text                     *)
  190.   Me: e.TaskPtr;                 (* my main task                      *)
  191.   Info: BOOLEAN;                 (* is info currently displayed ?     *)
  192.   MyMsgPtr: I.IntuiMessagePtr;   (* for receiving Messages            *)
  193.   i,j: INTEGER;                  (* count                             *)
  194.   Scroll: BOOLEAN;               (* scrolling or waiting?             *)
  195.   Fast: BOOLEAN;                 (* scrollquick?                      *)
  196.   in,out: d.FileHandlePtr;       (* i/o for TYPE xxx TO PRT:          *)
  197.   fg,bg: INTEGER;                (* Text colors                       *)
  198.   style: SHORTSET;               (* Text style                        *)
  199.   CommLine: POINTER TO CHAR;     (* The CLI-commands                  *)
  200.   ArgPtr: POINTER TO String;     (* to get WBArg                      *)
  201.   ri: g.RasInfoPtr;              (* Screen's ViewPort's RasInfo       *)
  202.   NuScreen: I.NewScreen;         (* to open screens                   *)
  203.   NuWindow: I.NewWindow;         (* to open window                    *)
  204.   StrGadget: I.Gadget;           (* Gadget for Find-Command           *)
  205.   StrInfo: I.StringInfo;         (* its special info                  *)
  206.   arp: LONGINT;                  (* ArpBase                           *)
  207.   body,text,ok: I.IntuiText;     (* IntuiTexts for AutoRequest        *)
  208.   FR: FileRequester;             (* The Requester                     *)
  209.   Filename: String;              (* The Filename (without path)       *)
  210.   Dirname: String;               (* its path                          *)
  211.   NewDisp: BOOLEAN;              (* need to rebuild Display ?         *)
  212.   TextMarkers: ARRAY 10 OF TextLinePtr; (* Marked Positions in text   *)
  213.   FindLine: TextLinePtr;         (* Last found line                   *)
  214.   KeyMap: ARRAY 40H OF CHAR;     (* console's KeyMap                  *)
  215.   wreq: e.IOStdReq;              (* Request to communicate with the console *)
  216.   console: e.DevicePtr;          (* the console.device                *)
  217.   ievent: ie.InputEvent;         (* InputEvent to convert keycodes    *)
  218.  
  219.   WakeUpSignal["WakeUpSignal"]: SHORTINT; (* Signal that's wakes us up*)
  220.   SigTask["SigTask"]: e.TaskPtr; (* MM's main task                    *)
  221.   Sleeping["Sleeping"]: BOOLEAN; (* TRUE while we sleep               *)
  222.   InputDevPort: e.MsgPort;       (* Input.Device's Port               *)
  223.   InputRequestBlock: e.IOStdReq; (* its Requestblock                  *)
  224.   HandlerStuff: e.Interrupt;     (* contains data about Input Handler *)
  225.   InputOpen: BOOLEAN;            (* TRUE while input.device is open   *)
  226.   HandlerActive: BOOLEAN;        (* TRUE while InputHandler is active *)
  227.  
  228.   WriteName: String;             (* File to write Block               *)
  229.   savefrom,savesize: LONGINT;    (* How much to save?                 *)
  230.   save: BOOLEAN;                 (* save block                        *)
  231.   buffer: LONGINT;               (* buffer to save file               *)
  232.  
  233. (*------  Memory:  ------*)
  234.  
  235. CONST ChunkSize = 4096;          (* size of allocated chunks *)
  236.  
  237. TYPE
  238.   MemChunkPtr = POINTER TO MemChunk;  (* chunklist *)
  239.   MemChunk = RECORD
  240.                prev: MemChunkPtr;     (* link *)
  241.                data: ARRAY ChunkSize OF BYTE; (* ChinkSize Bytes of memory *)
  242.              END;
  243.  
  244. VAR
  245.   MemIndex: INTEGER;      (* index in current Chunk *)
  246.   CurChunk: MemChunkPtr;  (* current chunk          *)
  247.  
  248. (*-----------------  External Assembler Procedures:  ----------------------*)
  249.  
  250.  
  251. (*------  The fastest textoutput-Procedure in the world (maybe):  ------*)
  252.  
  253. PROCEDURE QText{"QText"}(y{1}: INTEGER;
  254.                          str{8}: LONGINT;
  255.                          fd{10}: FontDataPtr);
  256.  
  257. (*------  Get Font:  ------*)
  258.  
  259. PROCEDURE GetFontData{"GetFontData"}(from{8},to{9}: LONGINT; linelen{7}: INTEGER);
  260.  
  261. (*------  Copy Line:  ------*)
  262.  
  263. PROCEDURE CopyLine1{"CopyLine1"}(w{0},h{1},pos{2}: INTEGER);
  264.  
  265. PROCEDURE CopyLine2{"CopyLine2"}(w{0},h{1},pos{2}: INTEGER);
  266.  
  267.  
  268. (*------  Input Handler:  ------*)
  269.  
  270. PROCEDURE InputHandler{"MMInputHandler"};
  271.  
  272.  
  273. (*-------------------------------------------------------------------------*)
  274.  
  275. (*------  Console Procedure:  ------*)
  276.  
  277.  
  278. PROCEDURE RawKeyConvert{console,-48}(events{8}:ie.InputEventPtr;
  279.                                      buffer{9}:LONGINT;
  280.                                      length{1}:LONGINT;
  281.                                      keyMap{10}:LONGINT);
  282.  
  283.  
  284. (*-------------------------------------------------------------------------*)
  285.  
  286.  
  287. PROCEDURE Length(VAR s: String): INTEGER;
  288. VAR l: INTEGER;
  289. BEGIN l := -1; REPEAT INC(l) UNTIL (l>SIZE(s)) OR (s[l]=0X); RETURN l;
  290. END Length;
  291.  
  292.  
  293. PROCEDURE Append(VAR s1: String; s2: StringPtr);
  294. (* appends s2 to s1 *)
  295. VAR p,q: INTEGER;
  296. BEGIN
  297.   p := Length(s1); q := 0;
  298.   WHILE (p<=SIZE(s1)) AND (s2^[q]#0X) AND (p<NumColumns) DO
  299.     s1[p] := s2^[q]; INC(p); INC(q)
  300.   END;
  301.   IF p<=SIZE(s1) THEN s1[p] := 0X END;
  302. END Append;
  303.  
  304.  
  305. (*-----------------------------  Requester:  ------------------------------*)
  306.  
  307.  
  308. PROCEDURE Request(Text: StringPtr);
  309.  
  310. VAR
  311.   out: d.FileHandlePtr;
  312.   c: CHAR;
  313.  
  314. BEGIN
  315.   IF wb.WBStarted THEN
  316.     body.backPen  := 1;  body.drawMode := g.jam2;
  317.     body.leftEdge := 12; body.topEdge  := 8;
  318.     text := body; ok := body;
  319.     body.iText    := ADR(MuchText);
  320.     body.nextText := ADR(text);
  321.     text.iText    := Text; text.topEdge := 22;
  322.     ok.leftEdge   := 6; ok.topEdge := 3; ok.iText := ADR("  OK  ");
  323.     SETREG(0,I.AutoRequest(NIL,ADR(body),NIL,ADR(ok),
  324.                            LONGSET{I.rawKey},LONGSET{},320,65));
  325.   ELSE
  326.     out := d.Output();
  327.     SETREG(0,d.Write(out,Text,Length(Text^)));
  328.     c := 0AX;
  329.     SETREG(0,d.Write(out,ADR(c),1));
  330.   END;
  331.   HALT(0);
  332. END Request;
  333.  
  334.  
  335. (*-------------------------------------------------------------------------*)
  336.  
  337. PROCEDURE AllocLine(sz: INTEGER): TextLinePtr;
  338.  
  339. VAR
  340.   a: TextLinePtr;
  341.   newchunk: MemChunkPtr;
  342.  
  343. BEGIN
  344.   INC(sz,SIZE(TextLine)-MaxLen); IF ODD(sz) THEN INC(sz) END;
  345.   IF MemIndex+sz<=ChunkSize THEN     (* does mem fit into current chunk ? *)
  346.     INC(MemIndex,sz);                (* increment index in current chunk  *)
  347.   ELSE
  348.     NEW(newchunk);                   (* allocate new chunk                *)
  349.     IF newchunk=NIL THEN Request(ADR(oom)) END;
  350.     newchunk.prev := CurChunk;       (* link chunk into list              *)
  351.     CurChunk := newchunk;
  352.     MemIndex := sz;
  353.   END;
  354.   RETURN ADR(CurChunk.data[MemIndex-sz]);
  355. END AllocLine;
  356.  
  357.  
  358. PROCEDURE DisposeLines();
  359.  
  360. VAR chunk: MemChunkPtr;
  361.  
  362. BEGIN
  363.   WHILE CurChunk#NIL DO
  364.     chunk := CurChunk.prev;
  365.     DISPOSE(CurChunk);
  366.     CurChunk := chunk;
  367.   END;
  368.   MemIndex := ChunkSize;
  369. END DisposeLines;
  370.  
  371. (*-------------------------------------------------------------------------*)
  372.  
  373.  
  374. PROCEDURE MakeThink;
  375.  
  376. BEGIN
  377.   I.MakeScreen(Screen); I.RethinkDisplay;
  378. END MakeThink;
  379.  
  380.  
  381. (*------------------------  Open Display:  --------------------------------*)
  382.  
  383.  
  384. PROCEDURE InitScreen();
  385.  
  386. VAR c: CHAR;
  387.  
  388. BEGIN
  389.  
  390. (*------  Open Screen:  ------*)
  391.  
  392.   NumColumns := g.gfx.normalDisplayColumns DIV 32 * 4;
  393.   IF NumColumns>MaxLen THEN NumColumns := MaxLen END;
  394.   NumLines := g.gfx.normalDisplayRows DIV 8;
  395.   NuScreen.width  := 8*NumColumns;
  396.   PageSize := 8*LONG(NumLines*NumColumns);
  397.   NuScreen.height := 16*NumLines;
  398.   NuScreen.depth  := 2;
  399.   NuScreen.viewModes := {g.hires};
  400.   IF (I.int.activeScreen#NIL) AND
  401.      (I.int.activeScreen.rastPort.font.ySize=8) AND
  402.      (I.int.activeScreen.rastPort.font.xSize=8) THEN
  403.     NuScreen.font := I.int.activeScreen.font;
  404.   ELSE
  405.     MyFont.name := ADR("topaz.font");
  406.     MyFont.ySize := 8;
  407.     NuScreen.font := ADR(MyFont);
  408.   END;
  409.   NuScreen.type := I.customScreen+{I.screenQuiet};
  410.   Screen := I.OpenScreen(NuScreen);
  411.   IF Screen=NIL THEN Request(ADR(oom)) END;
  412.   BM := Screen.rastPort.bitMap;
  413.   ri := Screen.viewPort.rasInfo;
  414.   ri.ryOffset := 32;
  415.   Screen.height := Screen.height DIV 2;
  416.   MakeThink;
  417.  
  418. (*------  Get Font:  ------*)
  419.  
  420.   IStr[64] := 0X;
  421.   j := 0; c := 20X;
  422.   g.SetDrMd(ADR(Screen.rastPort),g.jam1);
  423.   g.SetAPen(ADR(Screen.rastPort),1);
  424.   WHILE j<32 DO
  425.     i := 0; WHILE i<48 DO IStr[i] := c; INC(i); INC(c) END;
  426.     IF c=80X THEN c := 0A0X END;
  427.     g.Move(ADR(Screen.rastPort),0,Screen.rastPort.font.baseline+j);
  428.     g.Text(ADR(Screen.rastPort),ADR(IStr),48);
  429.     INC(j,8);
  430.   END;
  431.   GetFontData(Screen.bitMap.planes[0],ADR(fontdata),NumColumns);
  432.  
  433. (*------  Open Window:  ------*)
  434.  
  435.   NuWindow.flags  := I.rmbTrap+I.activate+I.borderless+I.reportMouse;
  436.   NuWindow.screen := Screen;
  437.   NuWindow.type   := I.customScreen;
  438.   NuWindow.topEdge:= 10;
  439.   NuWindow.width  := NuScreen.width;
  440.   NuWindow.height := Screen.height-10;
  441.   NuWindow.idcmpFlags := LONGSET{I.inactiveWindow,I.activeWindow,I.rawKey,
  442.                                  I.mouseButtons};
  443.   Window := I.OpenWindow(NuWindow);
  444.   IF Window=NIL THEN Request(ADR(oom)) END;
  445.  
  446. END InitScreen;
  447.  
  448.  
  449. (*-------------------------------------------------------------------------*)
  450.  
  451. PROCEDURE CloseDisplay();
  452.  
  453. BEGIN
  454.   IF Window#NIL THEN I.CloseWindow(Window); Window := NIL END;
  455.   IF Screen#NIL THEN I.CloseScreen(Screen); Screen := NIL END;
  456. END CloseDisplay;
  457.  
  458. (*------  Read one TextLine into a Variable:  ------*)
  459.  
  460.  
  461. PROCEDURE GetTextLine(): TextLinePtr;
  462. (* returns NIL at EOF *)
  463.  
  464. VAR
  465.   l: TextLinePtr;
  466.   sz,wd,le,i,j: INTEGER;
  467.   c: CHAR;
  468.   txt: ARRAY MaxLen+1 OF CHAR;
  469.   num: ARRAY 10 OF INTEGER;
  470.   newcol: BOOLEAN;
  471.   oldstyle: SHORTSET;
  472.  
  473.   PROCEDURE GetCh();
  474.  
  475.   BEGIN
  476.     IF RQPos=RQLen THEN
  477.       RQLen := d.Read(MyFile,ADR(Buffer),SIZE(Buffer));
  478.       IF RQLen<0 THEN Request(ADR(rwerr)) END;
  479.       RQPos := 0;
  480.     END;
  481.     IF RQLen=0 THEN c := 0X ELSE
  482.       c := Buffer[RQPos]; IF c=0X THEN c:=1X END;
  483.       INC(RQPos); INC(le);
  484.     END;
  485.   END GetCh;
  486.  
  487. BEGIN
  488.   IF RQLen=0 THEN RETURN NIL END;
  489.   sz := 0; wd := 0; le := 0;
  490.   IF Italic IN style THEN
  491.     IF Bold IN style THEN txt[sz] := boldit ELSE txt[sz] := italic END; INC(sz);
  492.   ELSE
  493.     IF Bold IN style THEN txt[sz] := bold; INC(sz) END;
  494.   END;
  495.   IF Ulin IN style THEN txt[sz] := ulineon; INC(sz) END;
  496.   IF    Inv IN style     THEN txt[sz] := CHR(fg+4*bg+1); INC(sz)
  497.   ELSIF (fg#1) OR (bg#0) THEN txt[sz] := CHR(bg+4*fg+1); INC(sz) END;
  498.   REPEAT
  499.     LOOP
  500.       GetCh;
  501.       IF (c#1BX) AND (c#9BX) THEN EXIT END;
  502.       i := -1;
  503.       REPEAT
  504.         GetCh;
  505.         IF (c>=30X) AND (c<=39X) THEN
  506.           INC(i); num[i] := 0;
  507.           REPEAT
  508.             num[i] := 10*num[i]+ORD(c)-ORD(30X); GetCh;
  509.           UNTIL (c<30X) OR (c>39X);
  510.         END;
  511.         c := CAP(c);
  512.       UNTIL (c>=3FX(*"?"*)) AND (c<=5AX) OR (c=0X) OR (i=9);
  513.       IF c=4DX THEN
  514.         newcol := f; oldstyle := style; j := 0;
  515.         IF i=-1 THEN i:=0; num[0] := 0 END;
  516.         WHILE (i>=j) AND (sz<MaxLen-1) DO
  517.           CASE num[j] OF
  518.           0: style := SHORTSET{}; fg := 1; bg := 0; newcol := w |
  519.           1: INCL(style,Bold) |
  520.           2: fg := 2; newcol := w (* I hope this is correct *) |
  521.           3: INCL(style,Italic) |
  522.           4: INCL(style,Ulin) |
  523.           7: INCL(style,Inv); newcol := w |
  524.           30..37: fg := INTEGER(SET(num[j]-30) * {0,1}); newcol := w |
  525.           40..47: bg := INTEGER(SET(num[j]-40) * {0,1}); newcol := w |
  526.           ELSE END;
  527.           INC(j);
  528.         END;
  529.         IF (oldstyle#style) AND (sz<MaxLen) THEN
  530.           IF Italic IN style THEN
  531.             IF Bold IN style THEN txt[sz] := boldit ELSE txt[sz] := italic END;
  532.           ELSE
  533.             IF Bold IN style THEN txt[sz] := bold   ELSE txt[sz] := plain  END;
  534.           END;
  535.           INC(sz);
  536.           IF (Ulin IN style) THEN
  537.             IF NOT((Ulin IN oldstyle)) AND (sz<MaxLen) THEN
  538.               txt[sz] := ulineon;
  539.               INC(sz);
  540.             END;
  541.           ELSE
  542.             IF (Ulin IN oldstyle) AND (sz<MaxLen) THEN
  543.               txt[sz] := ulineoff;
  544.               INC(sz);
  545.             END;
  546.           END;
  547.         END;
  548.         IF newcol AND (sz<MaxLen) THEN
  549.           IF Inv IN style THEN txt[sz] := CHR(fg+4*bg+1)
  550.                           ELSE txt[sz] := CHR(bg+4*fg+1) END;
  551.           INC(sz);
  552.         END;
  553.       END;   (* IF c="m" THEN *)
  554.     END;   (* LOOP *)
  555.     CASE c OF
  556.     20X..7FX:              txt[sz] := c; INC(sz); INC(wd) |
  557.     0A1X..0FFX: DEC(c,32); txt[sz] := c; INC(sz); INC(wd) |
  558.     8X: (* BS *)       IF wd>0 THEN DEC(sz); DEC(wd); END |
  559.     9X: (* TAB *)
  560.       REPEAT
  561.         txt[sz] := 20X; INC(sz); INC(wd)
  562.       UNTIL (sz=MaxLen) OR (wd=NumColumns) OR (SET(sz)*{0..2}={}) |
  563.     0A0X:                txt[sz] := 20X; INC(sz); INC(wd) |
  564.     ELSE END;
  565.   UNTIL (c=0AX) OR (c=0X) OR (c=0CX) OR (wd>=NumColumns) OR (sz>=MaxLen);
  566.   l := AllocLine(sz);
  567.   l.len := le; l.size:= sz;
  568.   WHILE sz>0 DO DEC(sz); l.text[sz]:=txt[sz] END;
  569.   RETURN l;
  570. END GetTextLine;
  571.  
  572.  
  573. (*------  Write Line at Bottom of Text:  ------*)
  574.  
  575.  
  576. PROCEDURE AddBottomLine(Line: TextLinePtr; Fast: BOOLEAN);
  577.  
  578. VAR
  579.   i,j: INTEGER;
  580.   trash: LONGINT;
  581.   s1,d1,s2,d2: POINTER TO LONGINT;
  582.   a: LONGINT;
  583.  
  584. BEGIN
  585.   QText(8*(ScreenPos+NumLines),ADR(Line.text),ADR(fontdata));
  586.   IF Fast THEN
  587.     INC(ri.ryOffset,8); MakeThink;
  588.     CopyLine1(NumColumns,NumLines,ScreenPos);
  589.   ELSE
  590.     a := 8*LONG(ScreenPos*NumColumns);
  591.     d1 := BM.planes[0] + a; s1 := LONGINT(d1) + PageSize;
  592.     d2 := BM.planes[1] + a; s2 := LONGINT(d2) + PageSize;
  593.     i := 8;
  594.     REPEAT
  595.       INC(ri.ryOffset);
  596.       MakeThink;
  597.       j := NumColumns DIV 4;
  598.       REPEAT
  599.         d1^ := s1^; INC(d1,4); INC(s1,4);
  600.         d2^ := s2^; INC(d2,4); INC(s2,4);
  601.         DEC(j);
  602.       UNTIL j=0;
  603.       DEC(i);
  604.     UNTIL i=0;
  605.   END;
  606.   INC(ScreenPos);
  607.   IF ScreenPos=NumLines THEN
  608.     ScreenPos := 0;
  609.     ri.ryOffset := 0;
  610.   END;
  611. END AddBottomLine;
  612.  
  613.  
  614. (*------  Write String to Screen:  ------*)
  615.  
  616.  
  617. PROCEDURE Write(String: StringPtr; Fast: BOOLEAN);
  618.  
  619. VAR text: TextLine;
  620.  
  621. BEGIN
  622.   text := FirstLine^;
  623.   i := Length(String^);
  624.   IF i>=NumColumns THEN i := NumColumns-1 END;
  625.   text.text[i+1] := 0X;
  626.   REPEAT
  627.     text.text[i] := String^[i];
  628.     IF text.text[i]>80X THEN DEC(text.text[i],32) END;
  629.     DEC(i)
  630.   UNTIL i<0;
  631.   AddBottomLine(ADR(text),Fast);
  632. END Write;
  633.  
  634.  
  635. (*------  Check whether BottomLine.next is NIL or not:  ------*)
  636.  
  637.  
  638. PROCEDURE TryBottomnext(): BOOLEAN;
  639. (* returns TRUE if BottomLine.next#NIL END; *)
  640.  
  641. BEGIN
  642.   IF (BottomLine.next=NIL) AND (MyFile#NIL) THEN
  643.     SignalNewData := w;
  644.     SETREG(0,e.Wait(mySig));
  645.     SignalNewData := f;
  646.   END;
  647.   RETURN BottomLine.next#NIL;
  648. END TryBottomnext;
  649.  
  650.  
  651. (*------  Scroll down one Line:  ------*)
  652.  
  653.  
  654. PROCEDURE ScrollDown(Fast: BOOLEAN);
  655.  
  656. BEGIN
  657.   IF TryBottomnext() THEN
  658.     BottomLine := BottomLine.next;
  659.     INC(AnzLines);
  660.     INC(TextLength,BottomLine.len);
  661.   ELSE RETURN END;
  662.   IF AnzLines>=NumLines THEN TopLine := TopLine.next END;
  663.   AddBottomLine(BottomLine,Fast);
  664. END ScrollDown;
  665.  
  666.  
  667. (*------  Scroll Up one Line:  ------*)
  668.  
  669.  
  670. PROCEDURE ScrollUp(Fast: BOOLEAN);
  671.  
  672. VAR
  673.   i,j: INTEGER;
  674.   s1,d1,s2,d2: POINTER TO LONGINT;
  675.   a: LONGINT;
  676.  
  677. BEGIN
  678.   IF TopLine.prev#NIL THEN
  679.     TopLine := TopLine.prev;
  680.     DEC(TextLength,BottomLine.len);
  681.     DEC(AnzLines);
  682.     BottomLine := BottomLine.prev;
  683.     IF ScreenPos=0 THEN
  684.       ri.ryOffset  := NumLines*8;
  685.       ScreenPos := NumLines-1;
  686.     ELSE
  687.       DEC(ScreenPos);
  688.     END;
  689.     QText(8*ScreenPos,ADR(TopLine.prev.text),ADR(fontdata));
  690.     IF Fast THEN
  691.       DEC(ri.ryOffset,8); MakeThink;
  692.       CopyLine2(NumColumns,NumLines,ScreenPos);
  693.     ELSE
  694.       a := 8*LONG((ScreenPos+1)*NumColumns);
  695.       s1 := BM.planes[0] + a; d1 := LONGINT(s1) + PageSize;
  696.       s2 := BM.planes[1] + a; d2 := LONGINT(s2) + PageSize;
  697.       i := 8;
  698.       REPEAT
  699.         DEC(ri.ryOffset);
  700.         MakeThink;
  701.         j := NumColumns DIV 4;
  702.         REPEAT;
  703.           DEC(d1,4); DEC(s1,4); d1^ := s1^;
  704.           DEC(d2,4); DEC(s2,4); d2^ := s2^;
  705.           DEC(j);
  706.         UNTIL j=0;
  707.         DEC(i);
  708.       UNTIL i=0;
  709.     END;
  710.   END;   (* IF TopLine#NIL ... *)
  711. END ScrollUp;
  712.  
  713.  
  714. (*------  Undo last Write():  ------*)
  715.  
  716.  
  717. PROCEDURE DelLine();
  718.  
  719. VAR
  720.   i,j: INTEGER;
  721.   s1,d1,s2,d2: POINTER TO LONGINT;
  722.   a: LONGINT;
  723.   text: TextLine;
  724.  
  725. BEGIN
  726.   IF ScreenPos=0 THEN
  727.     ri.ryOffset  := NumLines*8;
  728.     ScreenPos := NumLines;
  729.   END;
  730.   DEC(ScreenPos);
  731.   IF TopLine.prev#NIL THEN
  732.     QText(8*ScreenPos,ADR(TopLine.prev.text),ADR(fontdata));
  733.   ELSE
  734.     QText(8*ScreenPos,ADR(FirstLine.text),ADR(fontdata));
  735.   END;
  736.   a := (LONG(ScreenPos)+1)*8*LONG(NumColumns);
  737.   s1 := BM.planes[0] + a; d1 := LONGINT(s1) + PageSize;
  738.   s2 := BM.planes[1] + a; d2 := LONGINT(s2) + PageSize;
  739.   i := 8;
  740.   REPEAT
  741.     DEC(ri.ryOffset);
  742.     MakeThink;
  743.     j := NumColumns DIV 4;
  744.     REPEAT
  745.       DEC(d1,4); DEC(s1,4); d1^ := s1^;
  746.       DEC(d2,4); DEC(s2,4); d2^ := s2^;
  747.       DEC(j);
  748.     UNTIL j=0;
  749.     DEC(i);
  750.   UNTIL i=0;
  751. END DelLine;
  752.  
  753.  
  754. (*------  Clear Display:  ------*)
  755.  
  756.  
  757. PROCEDURE ClearBitMaps();
  758.  
  759. BEGIN
  760.   g.BltClear(BM.planes[0],2*PageSize,0);
  761.   g.BltClear(BM.planes[1],2*PageSize,0);
  762.   ScreenPos := 0;
  763.   ri.ryOffset := 0;
  764. END ClearBitMaps;
  765.  
  766.  
  767. (*------  Convert Integer to String:  ------*)
  768.  
  769.  
  770. PROCEDURE IntToStr(VAR String: String;
  771.                        At,Chars: INTEGER;
  772.                        int: LONGINT);
  773.  
  774. VAR
  775.   Cnt: INTEGER;
  776.   Ziff: LONGINT;
  777.  
  778. BEGIN
  779.   INC(Chars,At);
  780.   IF (Length(String)<Chars) AND (SIZE(String)>=Chars) THEN
  781.     String[Chars] := 0X
  782.   END;
  783.   REPEAT
  784.     DEC(Chars);
  785.     String[Chars] := CHR(int MOD 10 + ORD(30X)); int := int DIV 10;
  786.   UNTIL (Chars=At) OR (int=0);
  787.   WHILE Chars>At DO DEC(Chars); String[Chars] := 20X END;
  788. END IntToStr;
  789.  
  790.  
  791. (*-------------------------------------------------------------------------*)
  792.  
  793.  
  794. PROCEDURE GetLength(t: TextLinePtr);
  795.  
  796. BEGIN
  797.   TextLength := 0; AnzLines := 0;
  798.   WHILE t#NIL DO INC(AnzLines); INC(TextLength,t.len); t := t.prev END;
  799. END GetLength;
  800.  
  801.  
  802. (*-------------------------------------------------------------------------*)
  803.  
  804.  
  805. PROCEDURE NewDisplay();
  806. (* Zeichnet ab BottomLine neu *)
  807.  
  808. VAR
  809.   i: INTEGER;
  810.   l: TextLinePtr;
  811.  
  812. BEGIN
  813.   ClearBitMaps;
  814.   i := 1;
  815.   l := BottomLine;
  816.   WHILE (i<NumLines) AND (BottomLine.next#NIL) DO
  817.     BottomLine := BottomLine.next;
  818.     INC(i);
  819.   END;
  820.   WHILE (i<NumLines) AND (l.prev#NIL) DO l := l.prev; INC(i) END;
  821.   BottomLine := l;
  822.   GetLength(l);
  823.   Write(ADR(empty),w);
  824.   AddBottomLine(BottomLine,w);
  825.   i := 1;
  826.   WHILE i<NumLines DO
  827.     TopLine := l;
  828.     ScrollDown(w);
  829.     INC(i);
  830.   END;
  831.   Scroll := f;
  832. END NewDisplay;
  833.  
  834.  
  835. (*-------------------------------------------------------------------------*)
  836.  
  837.  
  838. PROCEDURE ShowProc();
  839.  
  840. VAR
  841.   l: TextLinePtr;
  842.   Down: BOOLEAN;               (* Scroll-Direction                  *)
  843.   End: BOOLEAN;                (* Quit next time Space is pressed ? *)
  844.   i,j,k,m: INTEGER;
  845.   MyMsg: I.IntuiMessage;       (* contains Message                  *)
  846.   Shift: BOOLEAN;              (* Shifted Keystroke ?               *)
  847.   Alt: BOOLEAN;                (* Altered Keystroke ?               *)
  848.   win: I.WindowPtr;            (* window for Find & Goto            *)
  849.   Find,FindStr: ARRAY 80 OF CHAR; (* findstring / capitalized findstring *)
  850.   Goto: ARRAY 10 OF CHAR;      (* string containing goto line #  *)
  851.   li: LONGINT;                 (* longint value of line to go to *)
  852.   flen: INTEGER;               (* length of findstring *)
  853.   HiText: TextLine;            (* Highlited textline *)
  854.   OldHiText: TextLinePtr;      (* original, un-hilited text *)
  855.   found: BOOLEAN;              (* TRUE, if find was successful *)
  856.   chr: CHAR;                   (* converted keycode *)
  857.  
  858.  
  859.   PROCEDURE WaitAllRead();
  860.  
  861.   BEGIN
  862.     IF MyFile#NIL THEN
  863.       SignalAllRead := w;
  864.       SETREG(0,e.Wait(mySig));
  865.       SignalAllRead := f;
  866.     END;
  867.   END WaitAllRead;
  868.  
  869.  
  870.   PROCEDURE HiLite(at,len: INTEGER);
  871.   (* Hilites len chars of BottomLine.text starting at position at *)
  872.  
  873.   VAR
  874.     c: INTEGER;
  875.     col: CHAR;
  876.  
  877.   BEGIN
  878.     OldHiText := BottomLine; HiText := OldHiText^; BottomLine := ADR(HiText);
  879.     IF at+len+2<MaxLen THEN
  880.       c := 0; col := 5X;
  881.       WHILE c<at DO
  882.         IF HiText.text[c]<CHAR(17) THEN col := HiText.text[c] END;
  883.         INC(c);
  884.       END;
  885.       HiText.text[at] := CHR(17-ORD(col));
  886.       c := at; INC(len,at);
  887.       WHILE c<len DO
  888.         HiText.text[c+1] := OldHiText.text[c];
  889.         INC(c);
  890.       END;
  891.       HiText.text[c+1] := col;
  892.       REPEAT
  893.         HiText.text[c+2] := OldHiText.text[c];
  894.         INC(c);
  895.       UNTIL HiText.text[c-1]=0X;
  896.     END;
  897.     IF HiText.next#NIL THEN HiText.next.prev := ADR(HiText) END;
  898.     IF HiText.prev#NIL THEN HiText.prev.next := ADR(HiText) END;
  899.   END HiLite;
  900.  
  901.  
  902.   PROCEDURE UnHiLite();
  903.  
  904.   BEGIN
  905.     IF HiText.next#NIL THEN HiText.next.prev := OldHiText END;
  906.     IF HiText.prev#NIL THEN HiText.prev.next := OldHiText END;
  907.   END UnHiLite;
  908.  
  909.  
  910.   PROCEDURE ChkBotNewDisp();
  911.  
  912.   VAR c: INTEGER;
  913.  
  914.   BEGIN
  915.     IF NOT found THEN
  916.       I.DisplayBeep(NIL);
  917.       IF TopLine.prev=NIL THEN BottomLine := TopLine
  918.                           ELSE BottomLine := TopLine.prev END;
  919.     END;
  920.     NewDisplay;
  921.     IF found THEN UnHiLite END;
  922.   END ChkBotNewDisp;
  923.  
  924.  
  925.   PROCEDURE Search(): BOOLEAN;
  926.   (* searches string and hilites it if found. result is TRUE if string found *)
  927.  
  928.   BEGIN
  929.     i := 0;
  930.     IF BottomLine.len<NumColumns THEN m := BottomLine.len ELSE m := NumColumns END;
  931.     WHILE i<BottomLine.size DO
  932.       j := 0; k := i;
  933.       WHILE CAP(BottomLine.text[k])=FindStr[j] DO
  934.         INC(j); INC(k);
  935.         IF FindStr[j]=0X THEN
  936.           SETREG(0,TryBottomnext());
  937.           FindLine := BottomLine;
  938.           HiLite(k-flen,flen);
  939.           found := w; RETURN w;
  940.         END;
  941.       END;
  942.       INC(i);
  943.     END;
  944.     RETURN f;
  945.   END Search;
  946.  
  947.  
  948.   PROCEDURE DisplayInfo();
  949.  
  950.   BEGIN
  951. (* File: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xx % (xxxxxx of xxxxxx Bytes) xxxxxx Lines *)
  952.     IStr := "XFile: "; IStr[0] := 7X;
  953.     Append(IStr,ADR(Name));
  954.     Append(IStr,ADR("                              "));
  955.     IStr[36] := 0X;
  956.     Append(IStr,ADR("xxx % (xxxxxx of xxxxxx Bytes) xxxxxx Lines"));
  957.     IntToStr(IStr,36,3,TextLength * 100 DIV FileLength);
  958.     IntToStr(IStr,43,6,TextLength);
  959.     IntToStr(IStr,53,6,FileLength);
  960.     IntToStr(IStr,67,6,AnzLines-1);
  961.     i := 79;
  962.     REPEAT IStr[i] := 20X; INC(i) UNTIL (i>=255) OR (i>=NumColumns+2);
  963.     IStr[i] := 0X; Write(ADR(IStr),f);
  964.     Info := w;
  965.   END DisplayInfo;
  966.  
  967.   PROCEDURE GetString(VAR str: ARRAY OF CHAR; int: BOOLEAN);
  968.  
  969.   BEGIN
  970.     INC(Screen.height,Screen.height);
  971.     I.MakeScreen(Screen);
  972.     NuWindow.leftEdge    := 100;
  973.     NuWindow.topEdge     := NumLines*4-6+ri.ryOffset;
  974.     NuWindow.width       := NuScreen.width-200;
  975.     NuWindow.height      := 12;
  976.     NuWindow.blockPen    := 1;
  977.     NuWindow.idcmpFlags  := LONGSET{I.inactiveWindow,I.gadgetUp};
  978.     NuWindow.flags       := I.rmbTrap+I.activate;
  979.     NuWindow.firstGadget := ADR(StrGadget);
  980.     NuWindow.screen      := Screen;
  981.     NuWindow.type        := I.customScreen;
  982.     StrGadget.leftEdge   := 2;
  983.     StrGadget.topEdge    := 2;
  984.     StrGadget.width      := NuWindow.width-4;
  985.     StrGadget.height     := 8;
  986.     StrGadget.activation := {I.stringCenter,I.relVerify};
  987.     IF int THEN INCL(StrGadget.activation,I.longint) END;
  988.     StrGadget.gadgetType := I.strGadget;
  989.     StrGadget.specialInfo:= ADR(StrInfo);
  990.     StrInfo.buffer       := ADR(str);
  991.     StrInfo.maxChars     := LEN(str,1)-1;
  992.     win := I.OpenWindow(NuWindow);
  993.     IF win=NIL THEN RETURN END;
  994.     REPEAT
  995.       SETREG(0,I.ActivateGadget(ADR(StrGadget),win,NIL));
  996.     UNTIL SHORTINT(win.userPort.sigBit) IN
  997.            e.Wait(LONGSET{SHORTINT(win.userPort.sigBit),
  998.                        SHORTINT(Window.userPort.sigBit)});
  999.     I.CloseWindow(win);
  1000.     Screen.height := Screen.height DIV 2;
  1001.   END GetString;
  1002.  
  1003.  
  1004.   PROCEDURE Help; (* executed when HELP or H is pressed *)
  1005.  
  1006.   BEGIN
  1007.     ClearBitMaps();
  1008.     Write(ADR("\023             \025  MuchMore V2.5 Commands:  "),w);
  1009.     Write(ADR(empty),w);
  1010.     Write(ADR(" \015Space\005,\015 LMB\005:         Start / Stop scrolling. Quit at end of file."),w);
  1011.     Write(ADR(" \015BackSpace\005,\015 RMB\005:     Start / Stop scrolling backwards."),w);
  1012.     Write(ADR(" \015Up\005/\015Down\005:            Move one line \015up\005 or \015down\005."),w);
  1013.     Write(ADR(" \015Shift \005+\015 Up\005/\015Dn\005:      Start / Stop quick scrolling \015up\005 or \015down\005."),w);
  1014.     Write(ADR(" \015Alt\005+\015Up\005/\015Dn\005,\015 PgUp\005/\015Dn\005: Move one page \015up\005 or \015down\005."),w);
  1015.     Write(ADR(" \015T\005,\015 Home \005/\015 B\005,\015 End\005:   Goto \015t\005op / \015b\005ottom of text."),w);
  1016.     Write(ADR(" \015F\005,\015N\005,\015P\005:              \015F\005ind string, \015N\005ext, \015P\005revious occurance"),w);
  1017.     Write(ADR(" \015Shift \005+\015 Fn\005:         Set textmarker #n to current position"),w);
  1018.     Write(ADR(" \015Fn\005:                 Goto marker #n or set marker #n if it wasn't set yet"),w);
  1019.     Write(ADR(" \015G\005:                  \015G\005oto line #n"),w);
  1020.     Write(ADR(" \015NK 0\005:               Display Filelength etc."),w);
  1021.     Write(ADR(" \015Shift \005+\015 Alt \005+\015 O\005:    Create print\015o\005ut of the text"),w);
  1022.     Write(ADR(" \015W\005:                  \015W\005rite block between Marker #1 and #2 to file or prt"),w);
  1023.     Write(ADR(" \015L\005:                  \015L\005oad new text (arp necessary)"),w);
  1024.     Write(ADR(" \015HELP\005,\015 H\005:            Show Commands."),w);
  1025.     Write(ADR(" \015ESC\005,\015 Q\005,\015 X\005,\015 NK 5\005:\015    Q\005uit."),w);
  1026.     Write(ADR(" \015S\005:                  Go to \015S\005leep, pop up with left Alt-ESC."),w);
  1027.     Write(ADR(empty),w);
  1028.     Write(ADR("© \0231989 Fridtjof Siebert, Nobileweg 67, D-7000 Stuttgart 40"),w);
  1029.     Write(ADR("  \023Please refer to MuchMore.ReadMe for a detailed copyright notice"),w);
  1030.     Write(ADR(empty),w);
  1031.     Write(ADR("  This is another great product of the Amiga Modula-2 Klub Stuttgart - \015\023AMOK"),w);
  1032.     i := (NumLines-24) DIV 2;
  1033.     WHILE i>0 DO Write(ADR(empty),w); DEC(i) END;
  1034.     LOOP
  1035.       e.WaitPort(Window.userPort);
  1036.       MyMsgPtr := LONGINT(e.GetMsg(Window.userPort));
  1037.       IF (I.rawKey IN MyMsgPtr.class) AND (MyMsgPtr.code<128) THEN EXIT END;
  1038.       e.ReplyMsg(MyMsgPtr);
  1039.     END;
  1040.     e.ReplyMsg(MyMsgPtr);
  1041.     BottomLine := TopLine;
  1042.     NewDisplay
  1043.   END Help;
  1044.  
  1045.  
  1046.   PROCEDURE Home;  (* executed when HOME or T is pressed *)
  1047.  
  1048.   BEGIN
  1049.     i:=SHORT(NumLines-AnzLines);
  1050.     IF i>0 THEN
  1051.       REPEAT DEC(i); ScrollDown(w) UNTIL i=0; Scroll := f;
  1052.     ELSE
  1053.       BottomLine := FirstLine; NewDisplay;
  1054.     END
  1055.   END Home;
  1056.  
  1057.  
  1058.   PROCEDURE Bottom;  (* executed when END or B is pressed *)
  1059.  
  1060.   BEGIN
  1061.     WaitAllRead;
  1062.     BottomLine := LastLine;
  1063.     i := NumLines;
  1064.     WHILE (i>1) AND (BottomLine.prev#NIL) DO
  1065.       BottomLine := BottomLine.prev;
  1066.       DEC(i);
  1067.     END;
  1068.     NewDisplay
  1069.   END Bottom;
  1070.  
  1071.  
  1072.   PROCEDURE Space(): BOOLEAN;  (* executed if space or LMB is pressed *)
  1073.   (* IF result=w THEN EXIT END *)
  1074.  
  1075.   BEGIN
  1076.     Fast := Shift;
  1077.     IF (MyFile=NIL) AND (BottomLine.next=NIL) THEN
  1078.       IF End THEN RETURN w ELSE End:=w END;
  1079.     ELSE
  1080.       End := f;
  1081.     END;
  1082.     IF Down THEN
  1083.       IF Scroll OR End THEN DisplayInfo END;
  1084.       Scroll := NOT(Scroll);
  1085.     ELSE
  1086.       Down := w;
  1087.       Scroll := w;
  1088.     END;
  1089.     RETURN f;
  1090.   END Space;
  1091.  
  1092.  
  1093.   PROCEDURE BackSpace;  (* executed if backspace or RMB is pressed *)
  1094.  
  1095.   BEGIN
  1096.     Fast := Shift;
  1097.     Scroll := Down OR NOT Scroll;
  1098.     Down := f
  1099.   END BackSpace;
  1100.  
  1101.  
  1102. BEGIN
  1103.  
  1104.   SETREG(0,e.Wait(mySig));
  1105.  
  1106.   Down := w; End := f; Find[0] := 0X; Goto[0] := 0X;
  1107.  
  1108.   LOOP
  1109.  
  1110.     IF NewDisp THEN NewDisp := f; NewDisplay END;
  1111.  
  1112. (*------  Type Text:  ------*)
  1113.  
  1114.     LOOP
  1115.       IF Scroll THEN
  1116.         IF Down THEN
  1117.           ScrollDown(Fast);
  1118.           Scroll := (MyFile#NIL) OR (BottomLine.next#NIL);
  1119.         ELSE
  1120.           ScrollUp(Fast);
  1121.           Scroll := TopLine.prev#NIL;
  1122.         END;
  1123.       ELSE
  1124.         e.WaitPort(Window.userPort);
  1125.       END;
  1126.  
  1127.       MyMsgPtr := LONGINT(e.GetMsg(Window.userPort));
  1128.  
  1129.       IF (MyMsgPtr#NIL) THEN
  1130.         IF NOT (I.inactiveWindow IN MyMsgPtr.class) THEN EXIT END;
  1131.         EXCL(Window.idcmpFlags,I.mouseButtons);
  1132.         e.ReplyMsg(MyMsgPtr);
  1133.         e.WaitPort(Window.userPort);
  1134.         INCL(Window.idcmpFlags,I.mouseButtons);
  1135.       END;
  1136.     END;
  1137.  
  1138.     MyMsg := MyMsgPtr^;
  1139.     e.ReplyMsg(MyMsgPtr);
  1140.  
  1141.     IF MyMsg.code<80H THEN
  1142.       IF    Info           THEN DelLine; Info := f;
  1143.       ELSIF MyMsg.code=0FH THEN DisplayInfo; Scroll := f END;
  1144.     END;
  1145.  
  1146.     Shift := {} # {ie.lShift,ie.rShift,ie.capsLock} * MyMsg.qualifier;
  1147.     Alt   := {} # {ie.lAlt  ,ie.rAlt}               * MyMsg.qualifier;
  1148.  
  1149.     IF I.mouseButtons IN MyMsg.class THEN
  1150.  
  1151.       IF    (ie.leftButton  IN MyMsg.qualifier) AND Space() THEN EXIT
  1152.       ELSIF ie.rightButton IN MyMsg.qualifier               THEN BackSpace END;
  1153.  
  1154.     ELSIF (I.rawKey IN MyMsg.class) AND (MyMsg.code<80H) THEN
  1155.  
  1156.       CASE MyMsg.code OF
  1157.  
  1158.       40H:  IF Space() THEN EXIT END |                   (* Space *)
  1159.  
  1160.       41H:  BackSpace |                                (* BackSpace *)
  1161.  
  1162.       4DH,1EH,1FH:                                        (* Down *)
  1163.             IF Shift THEN
  1164.               Scroll := NOT(Down AND Scroll) OR NOT Fast;
  1165.               Fast := w; Down := w;
  1166.             ELSE
  1167.               IF Alt OR (MyMsg.code=1FH) THEN i:=NumLines-1 ELSE i:=1 END;
  1168.               REPEAT
  1169.                 ScrollDown(NOT Shift);
  1170.                 DEC(i);
  1171.               UNTIL i=0;
  1172.               Scroll := f;
  1173.             END |
  1174.  
  1175.       4CH,3EH,3FH:                                        (* Up *)
  1176.             IF Shift THEN
  1177.               Scroll := Down OR NOT Scroll OR NOT Fast;
  1178.               Fast := w; Down := f;
  1179.             ELSE
  1180.               IF Alt OR (MyMsg.code=3FH) THEN i:=NumLines-1 ELSE i:=1 END;
  1181.               REPEAT
  1182.                 ScrollUp(NOT Shift);
  1183.                 Scroll := f;
  1184.                 DEC(i);
  1185.               UNTIL i=0;
  1186.             END; |
  1187.  
  1188.       44H,43H:                                        (* CR *)
  1189.             ScrollDown(f);
  1190.             Scroll := f; |
  1191.  
  1192.       3DH: Home |                                     (* Home *)
  1193.  
  1194.       1DH: Bottom |                                   (* End *)
  1195.  
  1196.       50H..59H:                                       (* F1..F10 *)
  1197.             i := MyMsg.code-50H;
  1198.             IF NOT Shift AND (TextMarkers[i]#NIL) THEN
  1199.               BottomLine := TextMarkers[i];
  1200.               IF BottomLine.prev#NIL THEN BottomLine := BottomLine.prev END;
  1201.               NewDisplay;
  1202.             ELSE
  1203.               TextMarkers[i] := TopLine;
  1204.             END |
  1205.  
  1206.       5FH:  Help |
  1207.  
  1208.       45H,2EH: IF NOT Alt THEN EXIT END |             (* Quit *)
  1209.  
  1210.       ELSE
  1211.  
  1212.         IF MyMsg.code<40H THEN (* examine vanilla keycode: *)
  1213.  
  1214.           chr := KeyMap[MyMsg.code];
  1215.  
  1216.           CASE chr OF
  1217.  
  1218.           "t": Home |                                     (* Home *)
  1219.  
  1220.           "b": Bottom |                                   (* End *)
  1221.  
  1222.           "f","n","p":                            (* Find, Next, Previous *)
  1223.  
  1224.             IF chr="f" THEN
  1225.               GetString(Find,f); FindLine := NIL; flen := 0;
  1226.               LOOP
  1227.                 FindStr[flen] := CAP(Find[flen]);
  1228.                 IF    FindStr[flen]>80X THEN DEC(FindStr[flen],32)
  1229.                 ELSIF FindStr[flen]=0X  THEN EXIT END;
  1230.                 INC(flen);
  1231.               END;
  1232.             END;
  1233.             ClearBitMaps();
  1234.             found := f;
  1235.             IF FindStr[0]#0X THEN
  1236.               i := NumLines;
  1237.               IF FindLine#NIL THEN FindLine := FindLine.next END;
  1238.               WHILE (i>0) AND (BottomLine#NIL) AND (BottomLine#FindLine) DO
  1239.                 BottomLine := BottomLine^.prev; DEC(i);
  1240.               END;
  1241.               IF (BottomLine#FindLine) OR (BottomLine=NIL) THEN BottomLine := TopLine END;
  1242.               IF chr#"p" THEN (* next *)
  1243.                 WHILE (BottomLine#NIL) AND NOT Search() DO
  1244.                   SETREG(0,TryBottomnext());
  1245.                   BottomLine := BottomLine.next;
  1246.                 END;
  1247.               ELSE                   (* previous *)
  1248.                 IF BottomLine.prev#NIL THEN BottomLine:=BottomLine.prev END;
  1249.                 REPEAT
  1250.                   BottomLine := BottomLine.prev
  1251.                 UNTIL (BottomLine=NIL) OR Search();
  1252.               END;
  1253.             ELSE
  1254.               BottomLine := NIL
  1255.             END;
  1256.             ChkBotNewDisp |
  1257.  
  1258.           "w":                                                  (* write block *)
  1259.  
  1260.             IF (TextMarkers[0]#NIL) AND (TextMarkers[1]#NIL) AND NOT print AND NOT save THEN
  1261.               savefrom := 0; savesize := 0;
  1262.               l := TextMarkers[0].prev; WHILE l.prev#NIL DO l := l.prev; INC(savefrom,l.len) END;
  1263.               l := TextMarkers[1].prev; WHILE l#NIL DO INC(savesize,l.len); l := l.prev END;
  1264.               l := TextMarkers[1]; i := NumLines; WHILE (i>1) AND (l#NIL) DO DEC(i); INC(savesize,LONG(l.len)); l := l.next END;
  1265.               DEC(savesize,savefrom);
  1266.               IF savesize>0 THEN
  1267.                 GetString(WriteName,f);
  1268.                 WaitAllRead; save := w; e.Signal(Me,mySig); NewDisplay;
  1269.               END
  1270.             END |
  1271.  
  1272.           "o": IF Shift AND Alt AND NOT print AND NOT save THEN                (* Printout *)
  1273.                  PStr := "TYPE "; Append(PStr,ADR(Name)); Append(PStr,ADR(" TO PRT:"));
  1274.                  WaitAllRead; print := w; e.Signal(Me,mySig);
  1275.                END |
  1276.  
  1277.           "l": ClearBitMaps;                                      (* Load Text *)
  1278.                MakeThink; NewText := w; e.Signal(Me,mySig);
  1279.                REPEAT UNTIL (mySigBit IN e.Wait(mySig)) AND NOT NewText |
  1280.  
  1281.           "g":                                                     (* goto *)
  1282.             GetString(Goto,w);
  1283.             li := SHORT(StrInfo.longInt);
  1284.             BottomLine := FirstLine;
  1285.             WHILE (li>0) AND TryBottomnext() DO
  1286.               BottomLine := BottomLine.next;
  1287.               DEC(li)
  1288.             END;
  1289.             NewDisplay |
  1290.  
  1291.           "h": Help |                                              (* Help *)
  1292.  
  1293.           "q","x": EXIT |                                          (* Quit *)
  1294.  
  1295.           "s":                                                (* Disappear *)
  1296.  
  1297.             IF NOT print AND NOT save AND (e.FindPort(ADR(MMissleeping))=NIL) THEN
  1298.               Sleeping := w;
  1299.               e.Signal(Me,mySig);
  1300.               SETREG(0,e.Wait(mySig));
  1301.             END |
  1302.  
  1303.           ELSE END;
  1304.  
  1305.         END;   (* IF MyMsg.code<40H THEN *)
  1306.  
  1307.       END;   (* CASE MyMsg.code OF *)
  1308.  
  1309.     END;   (* IF I.rawKey IN MyMsg.class THEN *)
  1310.  
  1311.   END;   (* LOOP *)
  1312.  
  1313.   Done := w;
  1314.   e.Signal(Me,mySig);
  1315.   LOOP SETREG(0,e.Wait(LONGSET{})) END;
  1316.  
  1317. END ShowProc;
  1318.  
  1319.  
  1320. (*--------------------------  File Requester:  ----------------------------*)
  1321.  
  1322.  
  1323. PROCEDURE FileRequest{arp,-294}(filereq{8}: FileRequesterPtr): LONGINT;
  1324.  
  1325. PROCEDURE TackOn{arp,-624}(pathname{8},filename{9}: STRPTR);
  1326.  
  1327.  
  1328. PROCEDURE FileReq(first: BOOLEAN);
  1329.  
  1330. BEGIN
  1331.   IF arp=NIL THEN arp := e.OpenLibrary(ADR("arp.library"),34) END;
  1332.   IF arp#NIL THEN
  1333.     j := Length(Name);
  1334.     WHILE (j>0) AND (Name[j]#":") AND (Name[j]#"/") DO DEC(j) END;
  1335.     IF j=0 THEN j := -1 END;
  1336.     i := 0;
  1337.     WHILE i<=j DO Dirname[i] := Name[i]; INC(i) END; Dirname[i] := 0X;
  1338.     j := 0;
  1339.     REPEAT Filename[j] := Name[i]; INC(j); INC(i) UNTIL Name[i-1]=0X;
  1340.     SETREG(0,I.WBenchToFront());
  1341.     FR.hail := ADR(MuchText);
  1342.     FR.ddef := ADR(Filename);
  1343.     FR.ddir := ADR(Dirname);
  1344.     FR.wind := NIL;
  1345.     IF FileRequest(ADR(FR))#NIL THEN
  1346.       Name := Dirname; TackOn(ADR(Name),ADR(Filename));
  1347.       SETREG(0,I.WBenchToBack());
  1348.       IF Window#NIL THEN I.ActivateWindow(Window) END;
  1349.       RETURN
  1350.     END;
  1351.   ELSIF NOT first THEN
  1352.     Request(ADR(noarp))
  1353.   END;
  1354.   IF first THEN Request(ADR(usage)) ELSE HALT(0) END;
  1355. END FileReq;
  1356.  
  1357.  
  1358. (*------  Sleep:  ------*)
  1359.  
  1360. PROCEDURE Sleep();
  1361.  
  1362. BEGIN
  1363.   InputDevPort.node.name := ADR(MMissleeping);
  1364.   Sleeping := w;
  1365.   SETREG(0,e.Wait(mySig));
  1366.   InputDevPort.node.name := ADR(MMisawake);
  1367. END Sleep;
  1368.  
  1369. (*------------------------------  MAIN:  ----------------------------------*)
  1370.  
  1371.  
  1372. BEGIN
  1373.  
  1374. (*------  Init:  ------*)
  1375.  
  1376. (* These variables are automatically set to zero:
  1377.   Screen := NIL; Window := NIL; FirstLine := NIL; TopLine := NIL;
  1378.   BottomLine := NIL; MyFile := NIL; AnzLines := 0; Info := f;
  1379.   MyLock := NIL; FileInfo := NIL; ScreenPos := 0; arp := NIL;
  1380.   ShowTaskRunning := f; SignalNewData := f; SignalAllRead := f;
  1381.   Done := f; print := f; bg := 0; style := SHORTSET{}; OldDir := NIL;
  1382.   InputOpen := f; save := f; in := NIL; out := NIL;
  1383. *)
  1384.   mySigBit := -1; Me := e.FindTask(0); fg := 1; InputDevPort.sigBit := -1;
  1385.   WriteName := "PRT:"; MemIndex := ChunkSize;
  1386.  
  1387.   mySigBit := SHORT(e.AllocSignal(-1));
  1388.   IF mySigBit<0 THEN HALT(0) END;
  1389.   mySig := LONGSET{mySigBit};
  1390.  
  1391. (*------  Setup:  ------*)
  1392.  
  1393.   NEW(FirstLine);
  1394. (*FirstLine.size := 0;
  1395.   FirstLine.text[0] := 0X; *)
  1396.   NEW(FileInfo);
  1397.   IF FileInfo=NIL THEN Request(ADR(oom)) END;
  1398.  
  1399. (*------  Init InputHandler:  ------*)
  1400.  
  1401.   WakeUpSignal := SHORT(mySigBit);
  1402.   SigTask := Me;
  1403.   Sleeping := f;
  1404.  
  1405. (* InputDevPort := CreatePort(NIL,0) *)
  1406.   InputDevPort.node.name := ADR(MMisawake);
  1407.   InputDevPort.node.type:= e.msgPort;
  1408.   InputDevPort.flags := e.signal;
  1409.   InputDevPort.sigBit := BYTE(SHORT(SHORT(e.AllocSignal(-1))));
  1410.   IF SHORTINT(InputDevPort.sigBit)<0 THEN HALT(0) END;
  1411.   e.AddPort(ADR(InputDevPort));
  1412.   InputDevPort.sigTask := Me;
  1413. (* InputRequestBlock := CreateStdIO(InputDevPort) *)
  1414.   InputRequestBlock.message.node.type := e.message;
  1415.   InputRequestBlock.message.length := SIZE(InputRequestBlock);
  1416.   InputRequestBlock.message.replyPort := ADR(InputDevPort);
  1417.  
  1418.   HandlerStuff.data := NIL;
  1419.   HandlerStuff.node.pri := 51;
  1420.  
  1421.   IF e.OpenDevice(ADR("input.device"),0,ADR(InputRequestBlock),0)#0 THEN
  1422.     Request(ADR("Need input.device"))
  1423.   END;
  1424.   InputOpen := w;
  1425.  
  1426.   HandlerStuff.code := InputHandler;
  1427.   InputRequestBlock.command := Input.addHandler;
  1428.   InputRequestBlock.data := ADR(HandlerStuff);
  1429.   e.DoIO(ADR(InputRequestBlock));
  1430.   HandlerActive := w;
  1431.  
  1432. (*------  Start:  ------*)
  1433.  
  1434.   IF wb.WBStarted THEN
  1435.  
  1436.     IF wb.WBenchMsg.numArgs=2 THEN
  1437.       ArgPtr := wb.WBenchMsg.argList^[1].name; Name := ArgPtr^;
  1438.       OldDir := d.CurrentDir(wb.WBenchMsg.argList^[1].lock);
  1439.     ELSE FileReq(w) END
  1440.  
  1441.   ELSE
  1442.  
  1443.     IF o.dosCmdLen<=1 THEN
  1444.       FileReq(w)
  1445.     ELSE
  1446.       CommLine := o.dosCmdBuf; i:=0; j:=0;
  1447.       WHILE CommLine^=20X DO INC(CommLine); INC(j) END;
  1448.       IF CommLine^='"' THEN
  1449.         INC(j); INC(CommLine);
  1450.         WHILE (i+j<o.dosCmdLen) AND (CommLine^#'"') AND (CommLine^#0AX) DO
  1451.           Name[i] := CommLine^; INC(i); INC(CommLine);
  1452.         END;
  1453.       ELSE
  1454.         WHILE (i+j<o.dosCmdLen) AND (CommLine^#0AX) AND (CommLine^#20X) DO
  1455.           Name[i] := CommLine^; INC(i); INC(CommLine);
  1456.         END;
  1457.       END;
  1458.       Name[i]:= 0X;
  1459.       IF Name="?"  THEN Request(ADR(usage)) END;
  1460.       IF Name="-s" THEN Name[0] := 0X; Sleep END;
  1461.     END;
  1462.  
  1463.   END;
  1464.  
  1465.   LOOP
  1466.     MyFile := d.Open(ADR(Name),d.oldFile);
  1467.     IF MyFile#NIL THEN EXIT END;
  1468.     FileReq(w);
  1469.   END;
  1470.  
  1471.   InitScreen();
  1472.  
  1473. (*------  Get KeyMap:  ------*)
  1474.  
  1475.  
  1476.   IF e.OpenDevice(ADR("console.device"),-1,ADR(wreq),0)#0 THEN Request(ADR(conerr)) END;
  1477.   console := wreq.device;
  1478. (*ievent.nextEvent := NIL;
  1479.   ievent.qualifier := {};
  1480.   ievent.eventAddress := NIL; *)
  1481.   ievent.class := ie.rawkey;
  1482.   i := 0;
  1483.   WHILE i<40H DO
  1484.     ievent.code := i;
  1485.     RawKeyConvert(ADR(ievent),ADR(KeyMap[i]),32,NIL);
  1486.     INC(i);
  1487.   END;
  1488.  
  1489. (*------  Init 2nd Task:  ------*)
  1490.  
  1491.   ShowTask.spLower := ADR(ShowStack);
  1492.   ShowTask.spUpper := ADR(ShowStack[3996]);
  1493.   ShowTask.spReg   := ShowTask.spUpper;
  1494.   ShowTask.node.type := e.task;
  1495.   ShowTask.node.name := ADR("Show.MM");
  1496.   ShowTask.node.pri  := Me.node.pri+1;
  1497.  
  1498.   e.Forbid;
  1499.     e.AddTask(ADR(ShowTask),LONGINT(ShowProc),NIL);
  1500.     ShowTaskRunning := w;
  1501.     Window.userPort.sigTask := ADR(ShowTask);
  1502.   e.Permit;
  1503.  
  1504. (*------  Main Load / Display Loop:  ------*)
  1505.  
  1506.   LOOP
  1507.  
  1508.     RQLen := -1; RQPos := -1;
  1509.     AnzLines := 1;
  1510.     LastLine := FirstLine;
  1511.     BottomLine := FirstLine;
  1512.     TopLine    := FirstLine;
  1513.     TextLength := 0;
  1514.     FindLine   := NIL;
  1515.     i := 0; REPEAT TextMarkers[i] := NIL; INC(i) UNTIL i=10;
  1516.  
  1517.     MyLock := d.Lock(ADR(Name),d.sharedLock);
  1518.     IF MyLock=NIL THEN Request(ADR(cof)) END;
  1519.     IF NOT d.Examine(MyLock,FileInfo) THEN Request(ADR(cof)) END;
  1520.     FileLength := FileInfo.size;
  1521.  
  1522.     d.UnLock(MyLock); MyLock := NIL;
  1523.     IF FileLength=0 THEN Request(ADR("File empty")) END;
  1524.  
  1525.     (*------  Start displaying & Loading:  ------*)
  1526.  
  1527.     NewDisp := TRUE;
  1528.  
  1529.     e.Signal(ADR(ShowTask),mySig);
  1530.  
  1531.     REPEAT
  1532.       LoadLine := GetTextLine();
  1533.       IF LoadLine=NIL THEN
  1534.         d.Close(MyFile);
  1535.         MyFile := NIL;
  1536.       ELSE
  1537.         LoadLine.prev := LastLine;
  1538.         LastLine.next := LoadLine;
  1539.         LastLine := LoadLine;
  1540.       END;
  1541.       IF SignalNewData THEN e.Signal(ADR(ShowTask),mySig) END;
  1542.     UNTIL (MyFile=NIL) OR Done OR NewText OR Sleeping;
  1543.     IF SignalAllRead THEN e.Signal(ADR(ShowTask),mySig) END;
  1544.     REPEAT
  1545.       SETREG(0,e.Wait(mySig));
  1546.       IF print THEN
  1547.         in := d.Open(ADR(nil),d.oldFile); out := d.Open(ADR(nil),d.newFile);
  1548.         SETREG(0,d.Execute(ADR(PStr),in,out));
  1549.         d.Close(in); in := NIL; d.Close(out); out := NIL; print := f;
  1550.       END;
  1551.       IF save THEN
  1552.         in := d.Open(ADR(Name),d.oldFile);
  1553.         IF in=NIL THEN I.DisplayBeep(NIL) ELSE
  1554.           o.New(buffer,savesize);
  1555.           IF buffer=NIL THEN Request(ADR(oom)) END;
  1556.           SETREG(0,d.Seek(in,savefrom,0));
  1557.           IF d.Read(in,buffer,savesize)#savesize THEN
  1558.             I.DisplayBeep(NIL); d.Close(in); in := NIL;
  1559.           ELSE
  1560.             d.Close(in); in := NIL;
  1561.             out := d.Open(ADR(WriteName),d.newFile);
  1562.             IF out=NIL THEN I.DisplayBeep(NIL) ELSE
  1563.               IF d.Write(out,buffer,savesize)#savesize THEN I.DisplayBeep(NIL) END;
  1564.               d.Close(out); out := NIL;
  1565.             END;
  1566.           END;
  1567.           DISPOSE(buffer);
  1568.         END;
  1569.         save := f;
  1570.       END;
  1571.       IF Done THEN EXIT END;
  1572.     UNTIL NewText OR Sleeping;
  1573.     IF MyFile#NIL THEN d.Close(MyFile); MyFile := NIL END;
  1574.     DisposeLines();
  1575.     FirstLine^.next := NIL; NewText := f;
  1576.     IF Sleeping THEN
  1577.       CloseDisplay;
  1578.       Sleep;
  1579.       InitScreen;
  1580.       Window.userPort.sigTask := ADR(ShowTask);
  1581.     END;
  1582.     REPEAT
  1583.       FileReq(f);
  1584.       MyFile := d.Open(ADR(Name),d.oldFile);
  1585.     UNTIL MyFile#NIL;
  1586.   END;   (* LOOP *)
  1587.  
  1588. CLOSE   (* cleanup: *)
  1589.  
  1590.   IF ShowTaskRunning THEN e.RemTask(ADR(ShowTask))       END;
  1591.   CloseDisplay;
  1592.   IF MyFile#NIL      THEN d.Close(MyFile)                END;
  1593.   IF in#NIL          THEN d.Close(in)                    END;
  1594.   IF out#NIL         THEN d.Close(out)                   END;
  1595.   IF MyLock#NIL      THEN d.UnLock(MyLock)               END;
  1596.   IF OldDir#NIL      THEN SETREG(0,d.CurrentDir(OldDir)) END;
  1597.   IF mySigBit>=0     THEN e.FreeSignal(mySigBit)         END;
  1598.   IF arp#NIL         THEN e.CloseLibrary(arp)            END;
  1599.   IF HandlerActive THEN
  1600.     InputRequestBlock.command := Input.remHandler;
  1601.     InputRequestBlock.data := ADR(HandlerStuff);
  1602.     e.DoIO(ADR(InputRequestBlock));
  1603.   END;
  1604.   IF InputOpen THEN e.CloseDevice(ADR(InputRequestBlock)) END;
  1605.   IF SHORTINT(InputDevPort.sigBit)>0 THEN
  1606.     e.RemPort(ADR(InputDevPort));
  1607.     e.FreeSignal(SHORTINT(InputDevPort.sigBit))
  1608.   END;
  1609.  
  1610. END MuchMore.
  1611.  
  1612.