(*---------------------------------------------------------------------------
  :Program.    FastLister
  :Author.     Thomas Stolze
  :Address.    Goslarsche Str. 32, 3000 Hannover 21, Germany
  :Phone.      (0)511 / 75 10 77
  :Version.    V2.5
  :Date.       05-Sep-90
  :Copyright.  Shareware
  :Language.   Modula-2
  :Translator. M2Amiga V4.0d
  :LastUpdate. 29-JUN-91
  :Contents.   Programming Utility.
  :Remark.     Needs "MuchMore" in C:-Directory © by F. Siebert
  :Imports.    QText © by F. Siebert AMOK#19
---------------------------------------------------------------------------*)
(*$ LargeVars:=FALSE NilChk:= FALSE OverflowChk:=FALSE RangeChk:=FALSE
    StackChk:=FALSE *)
MODULE FastLister;

IMPORT GraphicsL;
IMPORT IntuitionD;

FROM Arts             IMPORT Assert,BreakPoint,Terminate,wbStarted;
FROM Arguments        IMPORT GetArg,NumArgs;
FROM ASCII            IMPORT del,esc,lf;
FROM Conversions      IMPORT StrToVal,ValToStr;
FROM Console          IMPORT consoleName,RawKeyConvert;
FROM DosL             IMPORT Delay,Execute,Input,Output;
FROM DirSorter        IMPORT DirArray,DirColumn,DirEntries,FileTypes,
                             StoreDirectory;
FROM ExecL            IMPORT CloseDevice,Disable,DoIO,Enable,FindPort,Forbid,
                             GetMsg,OpenDevice,Permit,ReplyMsg,WaitPort;
FROM ExecD            IMPORT DevicePtr,Interrupt,IOStdReq,IOStdReqPtr,
                             MsgPortPtr;
FROM ExecSupport      IMPORT CreateExtIO,CreatePort,DeleteExtIO,DeletePort;
FROM GraphicsL        IMPORT ClearScreen,CloseFont,Move,OpenFont,RectFill,
                             SetAPen,SetBPen,SetDrMd,Text,WaitTOF,
                             ScrollRaster;
FROM GraphicsD        IMPORT DrawModes,DrawModeSet,FontFlags,FontFlagSet,
                             FontStyles,FontStyleSet,GfxBasePtr,jam2,TextAttr,
                             TextFontPtr,ViewModes,ViewModeSet;
FROM Images           IMPORT ArrowDown,ArrowUp;
FROM Input            IMPORT addHandler,inputName,remHandler;
FROM InputDevice      IMPORT ESC,Handler,HELP,inputMessagePtr,readIOPtr,
                             sleepPort;
FROM InputEvent       IMPORT InputEvent,Class,Qualifiers,QualifierSet;
FROM IntuitionL       IMPORT ActivateWindow,CloseScreen,CloseWindow,DisplayBeep,
                             NewModifyProp,OpenScreen,OpenWindow,RefreshGadgets,
                             ScreenToFront,SetWindowTitles,ShowTitle,
                             WindowToFront;
FROM IntuitionD       IMPORT ActivationFlags,ActivationFlagSet,boolGadget,
                             customScreen,Gadget,GadgetFlags,GadgetFlagSet,
                             GadgetPtr,IDCMPFlags,IDCMPFlagSet,Image,
                             IntuiMessage,IntuiMessagePtr,maxBody,maxPot,
                             menuDown,NewScreen,NewWindow,propGadget,PropInfo,
                             PropInfoFlagSet,ScreenFlags,ScreenFlagSet,
                             ScreenPtr,selectDown,WindowFlags,WindowFlagSet,
                             WindowPtr,cursorUp,cursorDown,cursorLeft,
                             cursorRight,altLeft,altRight;
FROM IntuitionSupport IMPORT SetGadget,SetImage,SetPropInfo;
FROM SYSTEM           IMPORT ADDRESS,ADR,LONGSET;
FROM String           IMPORT Concat,Length;
FROM QText            IMPORT QText;

(*FROM InOut            IMPORT WriteInt,WriteLn,WriteString;*)

CONST programName  = "FastLister V2.5  © by Thomas Stolze 1990";
      ConsoleError = "Couldn't open Console Device !";

      column = 57;

VAR argument    : ARRAY [0..9],[0..80] OF CHAR;
    Lister      : ARRAY [0..30] OF CHAR;
    GadgetArray : ARRAY [0..2] OF Gadget;
    ImageArray  : ARRAY [0..2] OF Image;
    propInfo    : PropInfo;
    screen      : ScreenPtr;
    window      : WindowPtr;
    ta,
    topaz       : TextAttr;
    topazPtr    : TextFontPtr;

    lastSelected,
    xcoor,ycoor,
    dirEntries,
    offSet,
    maxDisplayRows,
    dir            : CARDINAL;
    readPortPtr    : MsgPortPtr;
    interrupted    : Interrupt;

    ConsoleDevice  : DevicePtr;
    ConsoleRequest : IOStdReq;

PROCEDURE InputRead(command : CARDINAL; len : LONGCARD; adr : ADDRESS);
BEGIN
  readIOPtr^.command:=command;
  readIOPtr^.length:=len;
  readIOPtr^.data:=adr;

  DoIO(readIOPtr);
    Assert(readIOPtr^.error = 0,ADR("I/O Error"));
END InputRead;

PROCEDURE BlankDisplay;
BEGIN
  QText(column,1,ADR(" Nr.:           "),screen^.rastPort.bitMap,topazPtr);
END BlankDisplay;

PROCEDURE InitIntuition;
VAR ns  : NewScreen;
    nw  : NewWindow;
    gfx : GfxBasePtr;
    i   : SHORTCARD;
BEGIN
  gfx:=ADR(GraphicsL);
  WITH ta DO
    name:=ADR("Topaz.Font"); ySize:=8;
    style:=FontStyleSet{}; flags:=FontFlagSet{};
  END;
  WITH ns DO
    leftEdge:=0; topEdge:=0; width:=gfx^.normalDisplayColumns; height:=-1;
    detailPen:=0; blockPen:=1; depth:=1;
    viewModes:=ViewModeSet{hires};
    type:=customScreen+ScreenFlagSet{showTitle}; font:=ADR(ta);
    defaultTitle:=ADR(programName);
    gadgets:=NIL; customBitMap:=NIL;
  END;
  screen:=OpenScreen(ns);
    Assert(screen # NIL,ADR("Couldn't open Screen!"));
  maxDisplayRows:=screen^.height DIV 8;

  SetPropInfo(propInfo,PropInfoFlagSet{IntuitionD.autoKnob,
              IntuitionD.freeVert,IntuitionD.knobHit},0,0,0,maxBody);
  SetImage(ImageArray[1],-2,-1,16,10,1,ADR(ArrowUp)  ,1,0);
  SetImage(ImageArray[2],-2,-1,16,10,1,ADR(ArrowDown),1,0);

  SetGadget(GadgetArray[0],-17,25,16,((maxDisplayRows-4)*8)-10,
            GadgetFlagSet{gRelRight},
            ActivationFlagSet{gadgImmediate,relVerify},propGadget,
            ADR(ImageArray[0]),NIL,ADR(propInfo),0);
  SetGadget(GadgetArray[1],-15,15,12,8,GadgetFlagSet{gadgImage,gRelRight},
            ActivationFlagSet{gadgImmediate,relVerify},boolGadget,
            ADR(ImageArray[1]),NIL,NIL,1);
  SetGadget(GadgetArray[2],-15,15+((maxDisplayRows-4)*8)+2,12,8,
            GadgetFlagSet{gRelRight,gadgImage},
            ActivationFlagSet{gadgImmediate,relVerify},boolGadget,
            ADR(ImageArray[2]),NIL,NIL,2);

  FOR i:=1 TO 2 DO GadgetArray[i-1].nextGadget:=ADR(GadgetArray[i]) END;

    nw.height:=screen^.height-1; nw.maxHeight:=screen^.height-1;
  WITH nw DO
    leftEdge:=0; topEdge:=0; width:=gfx^.normalDisplayColumns;
    detailPen:=0; blockPen:=1;
    idcmpFlags:=IDCMPFlagSet{rawKey,mouseButtons,menuPick,gadgetDown,gadgetUp};
    flags:=WindowFlagSet{reportMouse,noCareRefresh,backDrop,menuState,
                         borderless,activate,windowActive};
    title:=ADR(programName); firstGadget:=ADR(GadgetArray[0]);
    checkMark:=NIL; bitMap:=NIL;
    minWidth:=110; minHeight:=10; maxWidth:=640;
    type:=customScreen;
  END;
  nw.screen:=screen;

  window:=OpenWindow(nw);
    Assert(window # NIL,ADR("Couldn't open Window!"));
  ShowTitle(screen,TRUE);

  BlankDisplay;
END InitIntuition;

PROCEDURE InstallHandler;
BEGIN
  interrupted.data:=NIL;
  interrupted.code:=ADR(Handler);
  interrupted.node.pri:=51;

  readIOPtr^.data:=ADR(interrupted);
  readIOPtr^.command:=addHandler;
  readIOPtr^.length:=SIZE(Interrupt);

  DoIO(readIOPtr);
    Assert(readIOPtr^.error = 0,ADR("I/O Error"));

END InstallHandler;

PROCEDURE StartupProgram(): BOOLEAN;
VAR arglen,
    args    : INTEGER;
    res     : BOOLEAN;
BEGIN
  Assert(NOT wbStarted,ADR("Run from CLI only!"));

  WITH topaz DO
     name:=ADR("topaz.font"); ySize:=8;
     style:=FontStyleSet{}; flags:=FontFlagSet{};
  END;
  topazPtr:=OpenFont(ADR(topaz));
    Assert(topazPtr # NIL,ADR("Couldn't find Topaz.font!"));

  sleepPort:=CreatePort(ADR("FastLister_Port"),0);
    Assert(sleepPort # NIL,ADR("Couldn't install MessagePort!"));

  readPortPtr:=CreatePort(NIL,0);
    Assert(readPortPtr # NIL,ADR("Couldn't install MessagePort!"));
  readIOPtr:=CreateExtIO(readPortPtr,SIZE(IOStdReq));
    Assert(readIOPtr # NIL,ADR("IOStdReq not allocated"));

  OpenDevice(ADR(inputName),0,readIOPtr,LONGSET{});

  args:=NumArgs(); dir:=0; DirColumn:=0;
    Assert(args # 0 ,ADR("No Arguments!"));

  REPEAT
    GetArg(DirColumn+1,argument[DirColumn],arglen);
    IF (argument[DirColumn,arglen-1] = "/") THEN
        argument[DirColumn,arglen-1]:=00C;
    END;
    res:=StoreDirectory(ADR(argument[DirColumn])); INC(DirColumn);
  UNTIL ((DirColumn >= CARDINAL(args)) AND res) OR (DirColumn = 9);

  RETURN res;
END StartupProgram;

(* x as character position; y as pixel position *)
PROCEDURE GetPixPos(nr : CARDINAL; VAR x,y : CARDINAL);
VAR new : CARDINAL;
BEGIN
  nr := nr - offSet;

  x := ((nr MOD 3) * 25);
  y := ((nr DIV 3) *  8) + 8;
END GetPixPos;

(* x as character position; y as pixel position *)
PROCEDURE PrintQEntry(nr,x,y : CARDINAL; invers : BOOLEAN);
VAR print : ARRAY [0..35] OF CHAR;
    err   : BOOLEAN;
BEGIN
  IF DirArray[dir,nr] # NIL THEN
     ValToStr(nr,FALSE,print,10,3," ",err); Concat(print,". ");
     Concat(print,DirArray[dir,nr]^.fileName); print[25]:=00C;
     IF invers THEN
        SetAPen(ADR(screen^.rastPort),0); SetBPen(ADR(screen^.rastPort),1);
          Move(ADR(screen^.rastPort),x*8,y+14);
          Text(ADR(screen^.rastPort),ADR(print),Length(print));
        SetAPen(ADR(screen^.rastPort),1); SetBPen(ADR(screen^.rastPort),0);
     ELSE
        Move(ADR(screen^.rastPort),0,16);
        QText(x,y,ADR(print),screen^.rastPort.bitMap,topazPtr);
     END;
  END;
END PrintQEntry;

PROCEDURE ListEntries(start : CARDINAL);
VAR i,j : CARDINAL;
BEGIN
  SetAPen(window^.rPort,0); SetDrMd(window^.rPort,jam2);
  RectFill(window^.rPort,0,12,screen^.width-20,screen^.height);

  FOR j:=1 TO maxDisplayRows-3 DO
    FOR i:=0 TO 2 DO
        PrintQEntry(start,i*25,8+j*8,FALSE); INC(start);
    END;
  END;

  lastSelected:=offSet; xcoor:=0; ycoor:=0;
  PrintQEntry(offSet,0,8,TRUE);
END ListEntries;

PROCEDURE ListAllEntries;
  PROCEDURE InitPropGadget;
  BEGIN
    dirEntries:=0; WHILE DirArray[dir,dirEntries] # NIL DO INC(dirEntries) END;

    propInfo.vertBody:=maxBody; offSet:=1;
    IF dirEntries > ((maxDisplayRows-3)*3) THEN
        propInfo.vertBody:=(maxBody DIV dirEntries)*((maxDisplayRows-3)*3);
    END;
    NewModifyProp(ADR(GadgetArray[0]),window,NIL,propInfo.flags,0,
                  0,0,propInfo.vertBody,1);
    WaitTOF(); RefreshGadgets(ADR(GadgetArray[0]),window,NIL);

  END InitPropGadget;

BEGIN
  IF dir < DirColumn THEN
     SetBPen(ADR(screen^.rastPort),0); SetDrMd(ADR(screen^.rastPort),jam2);

     BlankDisplay; InitPropGadget; ListEntries(offSet);
  ELSE
    DEC(dir);
  END;
END ListAllEntries;

PROCEDURE DoPropGadget;
BEGIN
  IF dirEntries > ((maxDisplayRows-3)*3) THEN
     offSet:=(LONGINT(propInfo.vertPot) *
             (LONGINT(dirEntries)-LONGINT((maxDisplayRows-3)*3))) DIV maxPot;
     IF offSet = 0 THEN offSet:=1 END;
     ListEntries(offSet); lastSelected:=offSet;
  END;
END DoPropGadget;

PROCEDURE LoadFile(nr : CARDINAL);
VAR execute : ARRAY [0..100] OF CHAR;
    res     : LONGINT;
    msg     : IntuiMessagePtr;
BEGIN
 IF DirArray[dir,nr] # NIL THEN
         execute:=("C:Run "); Concat(execute,Lister);
  Concat(execute," >NIL: ");  Concat(execute,argument[dir]);

  IF (argument[dir,Length(argument[dir])-1] # ":") THEN Concat(execute,"/") END;

  Concat(execute,DirArray[dir,nr]^.fileName);
  IF DirArray[dir,nr]^.typ = file THEN
     res:=Execute(ADR(execute),NIL,NIL);
       Assert(res # 0,ADR("FastLister fatal Error!"));
  END;

 END;
END LoadFile;

                      (* TRUE if file selected.   Number of selected file. *)
PROCEDURE CheckIfSelected(VAR load : BOOLEAN) : CARDINAL;
VAR k,xx,yy : CARDINAL;
BEGIN
  xx:=xcoor; yy:=ycoor; k:= yy * 3 + xx + offSet; load:=FALSE;
  IF DirArray[dir,k] # NIL THEN
     IF k = lastSelected THEN
        load:=TRUE;
     ELSE
       IF (lastSelected >= offSet) AND
          (lastSelected <  offSet+(maxDisplayRows-3)*3) THEN
          GetPixPos(lastSelected,xx,yy);
             PrintQEntry(lastSelected,xx,yy+8,FALSE);
       END;
       IF (k >= offSet) AND (k < offSet+(maxDisplayRows-3)*3) THEN
          GetPixPos(k,xx,yy);
             PrintQEntry(k,xx,yy,TRUE);
          lastSelected:=k;
       END;
     END;
  END;
  RETURN k;
END CheckIfSelected;
                            (* yy = y-Position in Char *)
PROCEDURE PrintTriple(start,yy : CARDINAL);
VAR i : CARDINAL;
BEGIN
  FOR i:=0 TO 2 DO
      PrintQEntry(start,i*25,8+yy*8,FALSE); INC(start);
  END;
END PrintTriple;

PROCEDURE ScrollUp;
BEGIN
  IF (INTEGER(offSet)-3 >= 1) THEN

    DEC(offSet,3); INC(ycoor);
    IF lastSelected > offSet+(maxDisplayRows-3)*3 THEN
       lastSelected:=offSet END;

     propInfo.vertPot:=(maxPot DIV (dirEntries-((maxDisplayRows-3)*3)))*offSet;

     WaitTOF(); NewModifyProp(ADR(GadgetArray[0]),window,NIL,propInfo.flags,0,
                              propInfo.vertPot,0,propInfo.vertBody,1);

     ScrollRaster(window^.rPort,0,-8,0,16,620,((maxDisplayRows-3)*8)+15);

     PrintTriple(offSet,1);
  END;
END ScrollUp;

PROCEDURE ScrollDown;
BEGIN
  IF (offSet+(maxDisplayRows-3)*3+3) <= dirEntries THEN

     INC(offSet,3); IF ycoor > 0 THEN DEC(ycoor) END;
     IF lastSelected < offSet THEN lastSelected:=offSet END;

     propInfo.vertPot:=(maxPot DIV (dirEntries-((maxDisplayRows-3)*3)))*offSet;

     WaitTOF(); NewModifyProp(ADR(GadgetArray[0]),window,NIL,propInfo.flags,0,
                              propInfo.vertPot,0,propInfo.vertBody,1);

     ScrollRaster(window^.rPort,0,8,0,16,620,((maxDisplayRows-3)*8)+15);

     PrintTriple((offSet+((maxDisplayRows-3)*3)-3),maxDisplayRows-3);
  END;
END ScrollDown;

PROCEDURE ShiftCursorUp;
VAR pos : CARDINAL;
    load: BOOLEAN;
BEGIN
  ycoor:=0; pos:=CheckIfSelected(load);
END ShiftCursorUp;

PROCEDURE ShiftCursorDown;
VAR pos : CARDINAL;
    load: BOOLEAN;
BEGIN
  IF dirEntries > (maxDisplayRows-3)*3 THEN
     ycoor:=maxDisplayRows-4;
  ELSE
     ycoor:=((dirEntries-offSet-1) DIV 3);
  END;
  pos:=CheckIfSelected(load);
END ShiftCursorDown;

PROCEDURE ShiftCursorLeft;
VAR pos : CARDINAL;
    load: BOOLEAN;
BEGIN
  xcoor:=0; pos:=CheckIfSelected(load);
END ShiftCursorLeft;

PROCEDURE ShiftCursorRight;
VAR pos : CARDINAL;
    load: BOOLEAN;
BEGIN
   IF (ycoor * 3 + 2 + offSet) < dirEntries THEN
       xcoor:=2; pos:=CheckIfSelected(load);
   END;
END ShiftCursorRight;

PROCEDURE ListLastEntries;
VAR pos  : CARDINAL;
    load : BOOLEAN;
BEGIN
  IF dirEntries > (maxDisplayRows-3)*3 THEN
     offSet:=dirEntries - (maxDisplayRows-3)*3;

     propInfo.vertPot:=(maxPot DIV (dirEntries-((maxDisplayRows-3)*3)))*offSet;
     WaitTOF(); NewModifyProp(ADR(GadgetArray[0]),window,NIL,propInfo.flags,0,
                              propInfo.vertPot,0,propInfo.vertBody,1);
     ListEntries(offSet);
     ShiftCursorDown; ShiftCursorRight;
  END;
END ListLastEntries;

PROCEDURE CursorUp;
VAR pos : CARDINAL;
    load: BOOLEAN;
BEGIN
  IF ycoor > 0 THEN DEC(ycoor); pos:=CheckIfSelected(load); END;
END CursorUp;

PROCEDURE CursorDown;
VAR pos : CARDINAL;
    load: BOOLEAN;
BEGIN
  IF (dirEntries > ((maxDisplayRows-3)*3)) THEN
     IF ycoor < maxDisplayRows-4 THEN
        INC(ycoor); pos:=CheckIfSelected(load);
     END;
  ELSE
     IF ((ycoor+1) * 3 + xcoor + offSet) < dirEntries THEN
        INC(ycoor); pos:=CheckIfSelected(load);
     END;
  END
END CursorDown;

PROCEDURE CursorLeft;
VAR pos : CARDINAL;
    load: BOOLEAN;
BEGIN
  IF xcoor > 0 THEN DEC(xcoor); pos:=CheckIfSelected(load); END;
END CursorLeft;

PROCEDURE CursorRight;
VAR pos : CARDINAL;
    load: BOOLEAN;
BEGIN
  IF ycoor * 3 + offSet + xcoor + 1 < dirEntries THEN
     IF xcoor < 2 THEN INC(xcoor); pos:=CheckIfSelected(load); END;
  END;
END CursorRight;

PROCEDURE RawToVanilla(Message           : IntuiMessage;
		       VAR VanillaString : ARRAY OF CHAR);

VAR actual : LONGINT;
    Event  : InputEvent;
BEGIN
WITH Event DO
  nextEvent	:= NIL;
  class		:= rawkey;
  code		:= Message.code;
  qualifier	:= Message.qualifier;
  eventAddress	:= Message.iAddress
END;
  actual := RawKeyConvert (ConsoleDevice,
       			   ADR (Event),
			   ADR (VanillaString),
			   HIGH (VanillaString),
			   NIL);
  IF (actual < 0) OR (actual > HIGH (VanillaString)) THEN
    VanillaString[0] := 00C;
  ELSE
    VanillaString[actual] := 00C;
  END
END RawToVanilla;

PROCEDURE HandleIntuiMessages;
VAR vanillaCode : CARDINAL;
    vanilla     : ARRAY [0..5] OF CHAR;
    print       : ARRAY [0..35] OF CHAR;
    gPtr        : GadgetPtr;
    msg         : IntuiMessagePtr;
    Message     : IntuiMessage;
    pos         : LONGINT;
    num         : ARRAY [0..5] OF CHAR;
    numCount           : CARDINAL;
    err,
    signed,
    pressed     : BOOLEAN;

    PROCEDURE ExamineNum;
    BEGIN
      StrToVal(num,pos,signed,10,err);
      IF err THEN
         numCount:=0; num[0]:=00C; BlankDisplay;
      ELSE
         IF (pos > 0) AND (pos <= INTEGER(DirEntries[dir])) THEN
            LoadFile(pos);
         END;
         numCount:=0; num[numCount]:=00C; BlankDisplay;
      END;
    END ExamineNum;

    PROCEDURE PrintNumber;
    VAR print : ARRAY [0..15] OF CHAR;
    BEGIN
      StrToVal(num,pos,signed,10,err);
      print:=(" Nr.: "); Concat(print,num); Concat(print,"   ");
      QText(column,1,ADR(print),screen^.rastPort.bitMap,topazPtr);
    END PrintNumber;

    PROCEDURE GetInput(chr : CHAR);
    BEGIN
      CASE chr OF
        lf: num[numCount]:=00C; INC(numCount); ExamineNum; numCount:=0;
      ELSE
        IF numCount < 5 THEN
           num[numCount]:=chr; INC(numCount); num[numCount]:=00C; PrintNumber;
        END;
      END;
    END GetInput;

BEGIN
  InitIntuition; ListAllEntries; numCount:=0; BlankDisplay; pressed:=FALSE;

  LOOP
    IF pressed THEN
       msg:=GetMsg(window^.userPort);
       IF msg # NIL THEN Message:=msg^; ReplyMsg(msg); ELSE pressed:=FALSE END;
    ELSE
      WaitPort(window^.userPort);
      msg:=GetMsg(window^.userPort);
         Message:=msg^;
      ReplyMsg(msg);
    END;

    IF (rawKey IN Message.class) THEN
       RawToVanilla(Message,vanilla);
       vanillaCode:=ORD(vanilla[0]);
       CASE vanillaCode OF
          8  (* backspace *) : IF numCount > 0 THEN
                                  DEC(numCount); num[numCount]:=00C; PrintNumber
                               END;
       |  ORD(" ")           : numCount:=0; num[numCount]:=00C; BlankDisplay;
       |  13 (* lf *)        : IF numCount = 0 THEN
                                  pos:=CheckIfSelected(err); LoadFile(pos);
                               ELSE
                                  ExamineNum;
                               END;
       |  27 (* esc *),ORD("q"),ORD(".") : EXIT;
       |  ORD("0")..ORD("9") : GetInput(CHR(vanillaCode));
       ELSE
         CASE Message.code OF
          (* F1-F10 *)
           50H..59H : dir:=Message.code-50H; numCount:=0;
                      BlankDisplay; ListAllEntries;
         | cursorUp,
           cursorDown,
           cursorLeft,
           cursorRight: IF (lAlt IN Message.qualifier) OR
                           (rAlt IN Message.qualifier) THEN
                           CASE Message.code OF
                             cursorUp   : ScrollUp;
                           | cursorRight: ListLastEntries;
                           | cursorDown : ScrollDown;
                           | cursorLeft : ListAllEntries;
                           ELSE
                           END;
                        ELSIF (lShift IN Message.qualifier) OR
                              (rShift IN Message.qualifier) THEN
                           CASE Message.code OF
                             cursorUp   : ShiftCursorUp;
                           | cursorRight: ShiftCursorRight;
                           | cursorDown : ShiftCursorDown;
                           | cursorLeft : ShiftCursorLeft;
                           ELSE
                           END;
                        ELSE
     			   CASE Message.code OF
                             cursorUp   : CursorUp;
                           | cursorRight: CursorRight;
                           | cursorDown : CursorDown;
                           | cursorLeft : CursorLeft;
     			   ELSE
     			   END;
                        END;
         ELSE
         END;
       END;
    ELSIF (mouseButtons IN Message.class) AND (selectDown = Message.code) THEN
      IF (Message.mouseX >  0) AND (Message.mouseX < 615)              THEN
      IF (Message.mouseY > 15) AND (Message.mouseY < screen^.height-8) THEN
         xcoor:=Message.mouseX DIV 210; ycoor:=(Message.mouseY DIV 8)-2;
         (* 0..2 *)                     (* 0..maxDisplayRows-3 *)

         pos:=CheckIfSelected(err);
         IF err THEN LoadFile(pos); numCount:=0; num[numCount]:=00C; END;

      END;
      END;
    ELSIF (gadgetUp IN Message.class) THEN
      gPtr:=Message.iAddress;
      CASE gPtr^.gadgetID OF
        0: DoPropGadget;
      ELSE
      END;
      pressed:=FALSE;
    ELSIF (gadgetDown IN Message.class) THEN
      gPtr:=Message.iAddress;
      CASE gPtr^.gadgetID OF
        1: ScrollUp;
      | 2: ScrollDown;
      ELSE
      END;
      pressed:=TRUE; Delay(2);
    ELSIF (menuPick IN Message.class) THEN
      EXIT;
    END;
  END;

  CloseWindow(window); window:=NIL;
  CloseScreen(screen); screen:=NIL;
END HandleIntuiMessages;

PROCEDURE Sleep;
VAR code : CARDINAL;
    msg  : inputMessagePtr;
BEGIN

  LOOP
    InstallHandler;

    WaitPort(sleepPort);
    msg:=GetMsg(sleepPort);
      code:=msg^.event.code;
    ReplyMsg(msg);

    InputRead(remHandler,0,ADR(interrupted)); interrupted.code:=NIL;

    CASE code OF
      HELP: HandleIntuiMessages;
    | ESC : EXIT;
    ELSE
    END;
  END;

END Sleep;

PROCEDURE Cleanup;
BEGIN
  IF interrupted.code # NIL THEN
     InputRead(remHandler,0,ADR(interrupted)); interrupted.code:=NIL;
  END;

  IF (readIOPtr # NIL) THEN
     CloseDevice(readIOPtr); DeleteExtIO(readIOPtr); readIOPtr:=NIL;
  END;

  IF (sleepPort   # NIL) THEN DeletePort(sleepPort);   sleepPort:=NIL;  END;
  IF (readPortPtr # NIL) THEN DeletePort(readPortPtr); readPortPtr:=NIL END;

  IF (topazPtr # NIL) THEN CloseFont(topazPtr); topazPtr:=NIL;  END;
  IF (window   # NIL) THEN CloseWindow(window); window:=NIL;    END;
  IF (screen   # NIL) THEN CloseScreen(screen); screen:=NIL;    END;
  IF ConsoleDevice # NIL THEN CloseDevice (ADR(ConsoleRequest)) END;
END Cleanup;

BEGIN
  Assert(FindPort(ADR("FastLister_Port")) = NIL,ADR("FastLister installed!"));
  ConsoleDevice := NIL; Lister:=("MuchMore");

  OpenDevice (ADR (consoleName), -1, ADR (ConsoleRequest), LONGSET {});
  Assert (ConsoleRequest.error = 0,  ADR (ConsoleError));
  ConsoleDevice := ConsoleRequest.device;

  IF StartupProgram() THEN Sleep END;

CLOSE
  Cleanup;
END FastLister.

