home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1989 / 01 / praxis / manager.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-10-20  |  26.6 KB  |  768 lines

  1. (* ------------------------------------------------------------------------- *)
  2. (*                            MANAGER.PAS                                    *)
  3. (*                Integrierter Resident-Software-Manager                     *)
  4. (*                                                                           *)
  5. (*               (c) 1988  TOOLBOX  &  Karsten Gieselmann                    *)
  6. (* ------------------------------------------------------------------------- *)
  7.  
  8. {$R-,S-,I-,V-,B-,N-}  (* keine Fehlerprüfung, größtmögliche Geschwindigkeit! *)
  9. {$M 8192,0,655360}
  10.  
  11. PROGRAM Manager;
  12.  
  13. USES
  14.   Crt, Dos, Scroll;                                       (* benötigte Units *)
  15.  
  16. (* ------------------------ Allgemeine Konstanten -------------------------- *)
  17.  
  18. CONST
  19.   Version   = 'RSM v1.0';                 (* Programmname und Versionsnummer *)
  20.   MonitorID = 'RSM Monitor v1.0';      (* Erkennung für das MONITOR-Programm *)
  21.   IFC       = $65;                        (* Nummer des Interface-Interrupts *)
  22.  
  23. (* ------------------------------ Dateinamen ------------------------------- *)
  24.  
  25. CONST
  26.   PickFileName  = 'C:\RSM\PICK.TSR';                        (* die Pickliste *)
  27.   BatchFileName = 'C:\RSM\LOAD.BAT';                 (* Batchdatei zum Laden *)
  28.   ComSpecName   = 'C:\COMMAND.COM';           (* Name des Kommandoprozessors *)
  29.  
  30. (* --------------------------- Farbdefinitionen ---------------------------- *)
  31.  
  32. CONST
  33.   FrameAttr   : BYTE = $0F;                    (* Rahmen des Manager-Windows *)
  34.   MenuAttr    : BYTE = $5F;                           (* Menü- und Kopfzeile *)
  35.   ProgAttr    : BYTE = $70;                                 (* Programmliste *)
  36.   PickAttr    : BYTE = $30;                                     (* Pickliste *)
  37.   SelectAttr  : BYTE = $1F;                                 (* Auswahlbalken *)
  38.   ReleaseAttr : BYTE = $4F;                                   (* Löschbalken *)
  39.  
  40. (* -------------- die Texte der Manager-Menüs und -Infobalken -------------- *)
  41.  
  42. CONST
  43.   MainMenu    =
  44.         'Blättern: '^X','^Y',PgUp,PgDn,Home,End    Löschen: Del    Laden: Ins';
  45.   PickMenu1   = 'Wählen: '^X','^Y',PgUp,PgDn,Home,End  ';
  46.   PickMenu2   = 'Markieren: +,-  Laden: Return  Abbruch: Esc';
  47.  
  48.   ReleaseMenu =
  49.    'Wählen: '^X','^Y',PgUp,PgDn,Home,End     Löschen: Return     Abbruch: Esc';
  50.   Header      =
  51.              '  Segment   Programm    Bytes   Vektoren (Erklärung mit Tab)   ';
  52.  
  53. (* --------------- Deklarationen für Programm- und Pickliste --------------- *)
  54.  
  55. TYPE
  56.   ScreenBuffer = ARRAY[1..4000] OF BYTE;                 (* Bildschirmpuffer *)
  57.   WindowType   = (Full, List, Pick);         (* die drei verwendeten Fenster *)
  58.   VectorTable  = ARRAY[0..$FF] OF POINTER;
  59.   StringPtr    = ^STRING;                           (* dynamischer Stringtyp *)
  60.   ProgramData  = RECORD
  61.                    ProgramName   : StringPtr;          (* Name des Programms *)
  62.                    ProgramSeg,                  (* Ladesegment des Programms *)
  63.                    EnvironSeg    : WORD;    (* Adresse des Umgebungsbereichs *)
  64.                    ProgramSize,                    (* Programmgröße in Bytes *)
  65.                    EnvironSize   : LONGINT;       (* Umgebungsgröße in Bytes *)
  66.                    TotalHooked   : BYTE;         (* Anzahl benutzte Vektoren *)
  67.                    HookedVectors : SET OF BYTE;          (* Vektoren-Nummern *)
  68.                    SavedVectors  : ^VectorTable;      (* gesicherte Vektoren *)
  69.                  END;
  70.  
  71. CONST
  72.   PickSize = 100;                            (* maximale Größe der Pickliste *)
  73.   ListSize = 100;                        (* maximale Größe der Programmliste *)
  74.  
  75. VAR
  76.   ProgramList      : ARRAY[1..ListSize] OF ^ProgramData;    (* Programmliste *)
  77.   InfoList         : ARRAY[1..ListSize] OF StringPtr;
  78.   PickList         : ARRAY[1..PickSize] OF RECORD               (* Pickliste *)
  79.                        Name,                                 (* Programmname *)
  80.                        Params,                    (* Kommandozeilenparameter *)
  81.                        Comment  : StringPtr;         (* beliebiger Kommentar *)
  82.                        Selected : BOOLEAN;                (* Programm laden? *)
  83.                      END;
  84.   NextPSP,                         (* PSP des nächsten zu ladenden Programms *)
  85.   LastPick        : WORD;           (* Index des letzten Picklisten-Eintrags *)
  86.   LastEntry       : INTEGER;    (* Index des letzten Programmlisten-Eintrags *)
  87.   ReleaseMode,                             (* ist der Manager im Löschmodus? *)
  88.   DisplayVectors,              (* werden Vektoren oder Kommentare angezeigt? *)
  89.   Quit            : BOOLEAN;    (* soll das Manager-Programm beendet werden? *)
  90.   BatchFile       : Text;             (* Hilfsdatei zum Laden von Programmen *)
  91.   SaveX, SaveY    : BYTE;                (* Cursorposition bei Programmstart *)
  92.   Key,                                       (* Variable zur Tastaturabfrage *)
  93.   VideoSegment    : WORD;          (* Segmentadresse des Bildschirmspeichers *)
  94.   MainBuffer,                         (* Puffer zum Sichern von Bildschirmen *)
  95.   TempBuffer      : ScreenBuffer;
  96.   PickMenu        : STRING;
  97.  
  98. (* ---------------- Routinen zur Zeichenkettenverarbeitung ----------------- *)
  99.  
  100. FUNCTION StringOf(Ch : Char; Len : BYTE) : STRING;
  101.              (* liefert eine Zeichenkette der Länge "Len" bestehend aus "Ch" *)
  102. VAR
  103.   Temp : STRING;
  104. BEGIN
  105.   FillChar(Temp[1], Len, Ch);
  106.   Temp[0] := Chr(Len);
  107.   StringOf := Temp;
  108. END;
  109.  
  110.  
  111. FUNCTION LeftAligned(St : STRING; Width : BYTE) : STRING;
  112.       (* liefert den String "St" linksbündig in "Width" Zeichen breitem Feld *)
  113. VAR
  114.   Temp : STRING;
  115. BEGIN
  116.   FillChar(Temp[1], Width, ' ');
  117.   Temp := St;
  118.   Temp[0] := Chr(Width);
  119.   LeftAligned := Temp;
  120. END;
  121.  
  122.  
  123. FUNCTION Centered(St : STRING; Width : BYTE) : STRING;
  124.         (* liefert den String "St" zentriert in "Width" Zeichen breitem Feld *)
  125. VAR
  126.   Temp : STRING;
  127. BEGIN
  128.   Temp := StringOf(' ', Width);
  129.   Move(St[1], Temp[1+(Width-Length(St)) DIV 2], Length(St));
  130.   Centered := Temp;
  131. END;
  132.  
  133.  
  134. FUNCTION NumStr(n : LONGINT; Width : BYTE) : STRING;
  135.   (* liefert die Ganzzahl "n" als Zeichenkette in einem "Width" breiten Feld *)
  136. VAR
  137.   St : STRING;
  138. BEGIN
  139.   Str(n:Width, St);
  140.   NumStr := St
  141. END;
  142.  
  143.  
  144. FUNCTION Hex(b : BYTE) : STRING;
  145.                         (* Konvertierung eines Dezimalbytes nach Hexadezimal *)
  146. CONST
  147.   HexDigit : ARRAY[0..15] OF Char = '0123456789ABCDEF';
  148. BEGIN
  149.   Hex := HexDigit[b SHR $04] + HexDigit[b AND $0F]
  150. END;
  151.  
  152.  
  153. FUNCTION HexW(w : WORD) : STRING;
  154.                         (* Konvertierung eines Dezimalworts nach Hexadezimal *)
  155. BEGIN
  156.   HexW := Hex(w SHR $08) + Hex(w AND $FF)
  157. END;
  158.  
  159.  
  160. FUNCTION JustName(FileName : STRING) : STRING;
  161.    (* liefert den reinen Dateinamen von "FileName" (ohne Pfad und Extension) *)
  162. VAR
  163.   j, k : BYTE;
  164. BEGIN
  165.   j := Length(FileName);
  166.   k := j;
  167.   WHILE (FileName[j] <> '\') AND (FileName[j] <> ':') AND (j > 0) DO Dec(j);
  168.   WHILE (FileName[k] <> '.') AND (k > j) DO Dec(k);
  169.   IF j = k THEN
  170.     k := Succ(Length(FileName));
  171.   JustName := Copy(FileName, Succ(j), Pred(k-j));
  172. END;
  173.  
  174.  
  175. PROCEDURE DisposeStr(VAR SPtr : StringPtr);
  176.             (* gibt den von "SPtr" belegten dynamischen Speicher wieder frei *)
  177. BEGIN
  178.   IF SPtr <> NIL THEN BEGIN   (* belegt Stringvariable dynamischen Speicher? *)
  179.     FreeMem(SPtr, Succ(Length(SPtr^)));                (* ja, dann freigeben *)
  180.     SPtr := NIL;
  181.   END;
  182. END;
  183.  
  184.  
  185. PROCEDURE AssignStr(VAR SPtr : StringPtr; St : STRING);
  186.    (* weist der dynamischen STRING-Variablen "SPtr" die Zeichenkette "St" zu *)
  187. BEGIN
  188.   IF SPtr <> NIL THEN          (* falls noch belegt, Speicher erst freigeben *)
  189.     DisposeStr(SPtr);
  190.   GetMem(SPtr, Succ(Length(St)));        (* neuen Speicherplatz anfordern... *)
  191.   Move(St, SPtr^, Succ(Length(St)));            (* ...und STRING abspeichern *)
  192. END;
  193.  
  194. (* ----------------- Routinen zur Bildschirmansteuerung -------------------- *)
  195.  
  196. TYPE
  197.   FrameChars = (LeftTop,RightTop,LeftBottom,RightBottom,Horizontal,Vertical);
  198.   FrameType  = ARRAY[FrameChars] OF Char;              (* Rahmen-Zeichensatz *)
  199.  
  200. CONST
  201.   Simple = '┌┐└┘─│';                         (* vordefinierte Rahmentypen *)
  202.   Double = '╔╗╚╝═║';
  203.  
  204. VAR
  205.   VideoMode : BYTE ABSOLUTE $0040:$0049;        (* aktueller Bildschirmmodus *)
  206.  
  207.  
  208. PROCEDURE SetAttribute(Attr : BYTE);
  209.                           (* setzt Vorder- und Hintergrundfarbe gemäß "Attr" *)
  210. BEGIN
  211.   TextAttr := Attr;        (* direkte Manipulation des Turbo-Videoattributs! *)
  212. END;
  213.  
  214.  
  215. PROCEDURE CursorOff;                          (* macht den Cursor unsichtbar *)
  216. INLINE($B4/$01/$B9/$00/$F0/$CD/$10);
  217.  
  218.  
  219. PROCEDURE WriteString(Col, Row : BYTE; St : STRING; Attr : BYTE);
  220.          (* Ausgabe der Zeichenkette "St" bei (Col,Row) mit der Farbe "Attr" *)
  221. VAR
  222.   Save : WORD;
  223. BEGIN
  224.   GotoXY(Col, Row);                                  (* Cursor positionieren *)
  225.   TextAttr := Attr;
  226.   Save := WindMax;                           (* obere Fenstergrenzen sichern *)
  227.   WindMax := $FFFF;          (* automatisches CR/LF am Zeilenende verhindern *)
  228.   Write(St);
  229.   WindMax := Save;                        (* Fenstergrenze wieder herstellen *)
  230. END;
  231.  
  232.  
  233. PROCEDURE DrawFrame(Left, Top, Right, Bottom : BYTE;       (* Eckpunkte      *)
  234.                     Title  : STRING;                       (* Überschrift    *)
  235.                     Offset : BYTE;                         (* Titel-Position *)
  236.                     Style  : FrameType);                   (* Zeichensatz    *)
  237.   (* zeichnet einen Rahmen mit den Eckpunkten (Left,Top) und (Right,Bottom). *)
  238.   (* Die Überschrift "Title" wird mit einem Abstand von "Offset" Positionen  *)
  239.   (* zum linken Rand des Rahmens in die obere Querleiste eingefügt; bei ei-  *)
  240.   (* nem "Offset" von Null wird die Überschrift zentriert.                   *)
  241. VAR
  242.   k, Len : BYTE;
  243.   Bar    : STRING;
  244. BEGIN
  245.   Len := Succ(Right-Left);
  246.   Bar := StringOf(Style[Horizontal], Len-2);
  247.   WriteString(Left, Top, Style[LeftTop]+Bar+Style[RightTop], TextAttr);
  248.   WriteString(Left, Bottom, Style[LeftBottom]+Bar+Style[RightBottom],TextAttr);
  249.   FOR k:=Succ(Top) TO Pred(Bottom) DO BEGIN
  250.     GotoXY(Left , k); Write(Style[Vertical]);
  251.     GotoXY(Right, k); Write(Style[Vertical]);
  252.   END;
  253.   IF Length(Title) <= Pred(Len) THEN BEGIN
  254.     IF Offset = 0 THEN                                  (* Titel zentrieren? *)
  255.       Offset := (Succ(Len)-Length(Title)) SHR 1;
  256.     WriteString(Left+Offset, Top, Title, TextAttr)
  257.   END
  258. END;
  259.  
  260.  
  261. PROCEDURE SaveScreenTo(VAR Buffer : ScreenBuffer);
  262.                                (* sichert den Bildschirminhalt nach "Buffer" *)
  263. BEGIN
  264.   Move(Mem[VideoSegment:0], Buffer, SizeOf(Buffer));
  265. END;
  266.  
  267.  
  268. PROCEDURE RestoreScreenFrom(VAR Buffer : ScreenBuffer);
  269.   (* restauriert den Bildschirminhalt mit "Buffer" *)
  270. BEGIN
  271.   Move(Buffer, Mem[VideoSegment:0], SizeOf(Buffer));
  272. END;
  273.  
  274. (* -------------------- Routinen zur Tastaturabfrage ----------------------- *)
  275.  
  276. CONST                                                         (* Tastencodes *)
  277.   Home   = $4700;   End_ = $4F00;   Tab  = $0F09;
  278.   Ins    = $5200;   Del  = $5300;   Esc  = $011B;
  279.   Return = $1C0D;   Down = $5000;   Left = $4B00;
  280.   Right  = $4D00;
  281.  
  282.  
  283. FUNCTION GetKey : WORD;
  284.   (* wartet auf Tastendruck und liefert den Scan-Code der Taste *)
  285. INLINE ($31/$C0/$CD/$16);
  286.  
  287. (* ----------------- Ausgaberoutinen für Scrollaktionen -------------------- *)
  288.  
  289. {$F+}
  290.  
  291. PROCEDURE WriteNormalTSR(Col, Row : BYTE; Index : LONGINT);
  292.                         (* Ausgabe eines normalen Eintrags der Programmliste *)
  293. BEGIN
  294.   IF ReleaseMode AND (Index >= SelectIndex) THEN
  295.     WriteString(Col, Row, LeftAligned(InfoList[Index]^, 78), ReleaseAttr)
  296.   ELSE
  297.     WriteString(Col, Row, LeftAligned(InfoList[Index]^, 78), ProgAttr);
  298. END;
  299.  
  300.  
  301. PROCEDURE WriteSelectedTSR(Col, Row : BYTE; Index : LONGINT);
  302.                       (* Ausgabe des selektierten Eintrags der Programmliste *)
  303. BEGIN
  304.   IF ReleaseMode THEN
  305.     WriteString(Col, Row, LeftAligned(InfoList[Index]^, 78), ReleaseAttr)
  306.   ELSE
  307.     WriteString(Col, Row, LeftAligned(InfoList[Index]^, 78), SelectAttr)
  308. END;
  309.  
  310.  
  311. PROCEDURE WriteNormalPick(Col, Row : BYTE; Index : LONGINT);
  312.                             (* Ausgabe eines normalen Eintrags der Pickliste *)
  313. VAR
  314.   Entry : STRING;
  315. BEGIN
  316.   WITH PickList[Index] DO BEGIN
  317.     Entry := LeftAligned('  '+JustName(Name^), 11);
  318.     IF Selected THEN
  319.       Entry[2] := #4;                                       (* Marker setzen *)
  320.     WriteString(Col, Row, Entry, PickAttr);
  321.   END;
  322. END;
  323.  
  324.  
  325. PROCEDURE WriteSelectedPick(Col, Row : BYTE; Index : LONGINT);
  326.                           (* Ausgabe des selektierten Eintrags der Pickliste *)
  327. VAR
  328.   Entry : STRING;
  329. BEGIN
  330.   WITH PickList[Index] DO BEGIN
  331.     Entry := LeftAligned('  '+JustName(Name^), 11);
  332.     IF Selected THEN
  333.       Entry[2] := #4;                                       (* Marker setzen *)
  334.     WriteString(Col, Row, Entry, SelectAttr);
  335.   END;
  336. END;
  337.  
  338. {$F-}
  339.  
  340. (* --------------------- Diverse High-Level-Utilities ---------------------- *)
  341.  
  342. PROCEDURE SwitchWindow(NewWindow : WindowType);
  343.                   (* leitet Bildschirmausgabe auf das Fenster "NewWindow" um *)
  344. VAR
  345.   ColSize : BYTE;
  346. BEGIN
  347.   CASE NewWindow OF
  348.     Full : Window(1, 1, 80, 25);
  349.     List : Window(2, 4, 79, 22);
  350.     Pick : BEGIN
  351.              SwitchWindow(Full);
  352.              SetAttribute(PickAttr);
  353.              ColSize := LastPick + 4;
  354.              IF ColSize > 21 THEN
  355.                ColSize := 21;
  356.              DrawFrame(66, 4, 78, Succ(ColSize), ' Laden ', 0, Simple);
  357.              Window(67, 5, 77, ColSize);
  358.            END;
  359.   END;
  360. END;
  361.  
  362.  
  363. PROCEDURE Inform(Message : STRING);
  364.                          (* gibt eine Meldung in der Menü- und Infozeile aus *)
  365. VAR
  366.   SaveMin, SaveMax : WORD;
  367. BEGIN
  368.   SaveMin := WindMin;                     (* aktuelle Fenstergrenzen sichern *)
  369.   SaveMax := WindMax;
  370.   SwitchWindow(Full);                                   (* ganzer Bildschirm *)
  371.   WriteString(2, 24, Centered(Message, 78), MenuAttr);
  372.   WindMin := SaveMin;                                (* Fenster restaurieren *)
  373.   WindMax := SaveMax;
  374. END;
  375.  
  376.  
  377. PROCEDURE Parse(CommandLine : STRING; VAR FileName, Params : STRING);
  378.              (* zerlegt eine Kommandozeile in Dateinamen plus Parameterzeile *)
  379. CONST
  380.   Seperators : SET OF Char = [^I, ' ', ',', '/', ';', '<', '=', '>', '|'];
  381. VAR
  382.   k : WORD;
  383. BEGIN
  384.   WHILE CommandLine[1] = ' ' DO Delete(CommandLine, 1, 1);
  385.   k := 1;
  386.   WHILE NOT(CommandLine[k] IN Seperators)          (* Trennzeichen gefunden? *)
  387.         AND (k <= Length(CommandLine)) DO Inc(k);
  388.   FileName := Copy(CommandLine, 1, Pred(k));
  389.   IF k <= Length(CommandLine) THEN
  390.     Params := Copy(CommandLine, k, Length(CommandLine))
  391.   ELSE
  392.     Params := '';
  393. END;
  394.  
  395.  
  396. PROCEDURE Error(ErrorMessage : STRING);
  397.      (* gibt Fehlermeldung plus -signal aus und wartet auf Tastendruck <Esc> *)
  398. VAR
  399.   k : BYTE;
  400.   Key : WORD;
  401.  
  402.   PROCEDURE Beep(Hz, MS : WORD);
  403.      (* erzeugt einen Ton der Frequenz "Hz" und der Länge "MS" Millisekunden *)
  404.   BEGIN
  405.     Sound(Hz); Delay(MS); NoSound;
  406.   END;
  407.  
  408. BEGIN
  409.   Inform(ErrorMessage+'. Weiter mit <Esc>');
  410.   FOR k:=1 TO 2 DO BEGIN
  411.     Beep(600, 40);  Beep( 400, 40);  Beep(1000, 40);
  412.     Beep(400, 40);  Beep(1200, 40);  NoSound; Delay(5)
  413.   END;
  414.   REPEAT Key:=GetKey UNTIL Key=Esc;                     (* auf Escape warten *)
  415. END;
  416.  
  417.  
  418. PROCEDURE ErrorHalt(ErrorMessage : STRING);
  419.                                         (* Fehlermeldung und Programmabbruch *)
  420. BEGIN
  421.   Error(ErrorMessage+', Programm muß abgebrochen werden');
  422.   TextMode(LastMode);
  423.   RestoreScreenFrom(MainBuffer);
  424.   GotoXY(SaveX, SaveY);
  425.   Halt;
  426. END;
  427.  
  428. (* ---------------------- Abfangen von Heap-Fehlern ------------------------ *)
  429.  
  430. {$F+}
  431.  
  432. FUNCTION HeapCheck(Size : WORD) : INTEGER;
  433. BEGIN
  434.   ErrorHalt('Zu wenig Speicher');
  435. END;
  436.  
  437. {$F-}
  438.  
  439. (* ----------------------------- Hauptprogramm ----------------------------- *)
  440.  
  441. PROCEDURE UpdateLastEntry;
  442.         (* aktualisiert den letzten Eintrag der Programmliste (Freispeicher) *)
  443. VAR
  444.   St         : STRING;
  445.   FreeSpace  : LONGINT;
  446.   MemorySize : WORD ABSOLUTE $0040:$0013;     (* Speicherausbau in Kilobytes *)
  447. BEGIN
  448.   FreeSpace := LONGINT(MemorySize*64-NextPSP) * 16;
  449.   St := '    ' + HexW(NextPSP) + '    Noch frei  ' + NumStr(FreeSpace, 6);
  450.   Inc(LastEntry);
  451.   AssignStr(InfoList[LastEntry], St);
  452. END;
  453.  
  454.  
  455. PROCEDURE Initialize;
  456.        (* Aufbau des Manager-Fensters und Durchführung von Initialisierungen *)
  457. VAR
  458.   k : WORD;
  459. BEGIN
  460.   PickMenu    := PickMenu1 + PickMenu2;
  461.   ReleaseMode := FALSE;
  462.   DisplayVectors := FALSE;             (* standardmäßig Erklärungen anzeigen *)
  463.   NextPSP := PrefixSeg;
  464.   HeapError := @HeapCheck;
  465.   Assign(BatchFile, BatchFileName);
  466.   Rewrite(BatchFile);
  467.   FOR k:=1 TO ListSize DO InfoList[k] := NIL;
  468.   IF VideoMode = 7 THEN
  469.     VideoSegment := $B000                               (* Monochrom-Adapter *)
  470.   ELSE
  471.     VideoSegment := $B800;                                  (* Color-Adapter *)
  472.   SaveScreenTo(MainBuffer);
  473.   SaveX := WhereX; SaveY := WhereY;
  474.   CursorOff;                                            (* Cursor abschalten *)
  475.   SetAttribute(ProgAttr);
  476.   ClrScr;                                             (* Bildschirm aufbauen *)
  477.   SetAttribute(FrameAttr);
  478.   DrawFrame(1, 1, 80, 25, '', 0, Double);
  479.   WriteString(2, 2, Header+'»» '+Version+' «« ', MenuAttr);
  480.   Inform(MainMenu);
  481.   SwitchWindow(List);
  482. END;
  483.  
  484.  
  485. PROCEDURE SetupInfoList(DisplayVectors : BOOLEAN);
  486.                        (* Aufbau der Infoliste aus der MONITOR-Programmliste *)
  487. VAR
  488.   St    : STRING;
  489.   j, k  : BYTE;
  490.   found : BOOLEAN;
  491.  
  492.   FUNCTION MonitorList : POINTER;
  493.         (* liefert einen Zeiger auf die Monitor-Programmliste bzw. bricht ab *)
  494.   VAR
  495.     Address : ^POINTER;                          (* der nullte Listeneintrag *)
  496.     Linear  : LONGINT ABSOLUTE Address;         (* lineare Zeigerdarstellung *)
  497.     ID      : ^STRING;
  498.   BEGIN
  499.     GetIntVec(IFC, POINTER(Address));
  500.     IF Address = Ptr($0000, $0000) THEN       (* Interface-Vektor unbenutzt? *)
  501.       ErrorHalt('Monitor nicht installiert')
  502.     ELSE IF Address = Ptr($FFFF, $FFFF) THEN          (* Liste übergelaufen? *)
  503.       ErrorHalt('Listenüberlauf')
  504.     ELSE BEGIN
  505.       ID := Address^;
  506.       IF ID^ = MonitorID THEN BEGIN       (* OK, Adresse der Liste übergeben *)
  507.         Inc(Linear, SizeOf(POINTER));     (* Zeiger auf ersten Listeneintrag *)
  508.         MonitorList := Address;
  509.       END ELSE
  510.         ErrorHalt('Monitor nicht installiert');
  511.     END;
  512.   END;
  513.  
  514. BEGIN
  515.   SwitchWindow(Full);
  516.   IF DisplayVectors THEN
  517.     WriteString(34, 2, 'Vektoren (Erklärung', MenuAttr)
  518.   ELSE
  519.     WriteString(34, 2, 'Erklärung (Vektoren', MenuAttr);
  520.   SwitchWindow(List);
  521.   Move(MonitorList^, ProgramList, ListSize*SizeOf(POINTER));
  522.   LastEntry := 0;
  523.   WHILE ProgramList[Succ(LastEntry)] <> NIL DO BEGIN
  524.     Inc(LastEntry);
  525.     WITH ProgramList[LastEntry]^ DO BEGIN     (* Daten aus Liste extrahieren *)
  526.      St := '    ' + HexW(ProgramSeg) + '    '
  527.            + LeftAligned(JustName(ProgramName^), 8)
  528.            + NumStr(ProgramSize+EnvironSize, 9) + ' ';
  529.       IF DisplayVectors THEN BEGIN            (* benutzte Vektoren auflisten *)
  530.         j := 0;
  531.         FOR k:=0 TO 255 DO
  532.           IF k IN HookedVectors THEN BEGIN
  533.             IF j <= 9 THEN
  534.               St := St + '  ' + Hex(k)
  535.             ELSE
  536.               IF j = 10 THEN
  537.                 St := St + '  ...';
  538.             Inc(j);
  539.           END;
  540.         END
  541.       ELSE BEGIN           (* Kommentar anfügen, falls Programm in Pickliste *)
  542.         j := 0;
  543.         found := FALSE;
  544.         WHILE (j < LastPick) AND NOT found DO BEGIN
  545.           Inc(j);
  546.           found := JustName(ProgramName^) = JustName(PickList[j].Name^);
  547.         END;
  548.         IF found AND (PickList[j].Comment <> NIL) THEN
  549.           St := St + '  ' + PickList[j].Comment^;
  550.       END;
  551.       AssignStr(InfoList[LastEntry], St);
  552.     END;
  553.   END;
  554.   UpdateLastEntry;          (* Segment und Größe des freien Blocks eintragen *)
  555. END;
  556.  
  557.  
  558. PROCEDURE SetupPickList;              (* Einlesen und Aufbauen der Pickliste *)
  559. VAR
  560.   PickFile : Text;
  561.   St, n, p : STRING;
  562. BEGIN
  563.   FOR LastPick:=1 TO PickSize DO            (* Pickliste vollständig löschen *)
  564.     WITH PickList[LastPick] DO BEGIN
  565.       Name := NIL;
  566.       Params := NIL;
  567.       Comment := NIL;
  568.     END;
  569.   LastPick := 0;                                      (* Pickliste ist leer! *)
  570.   Assign(PickFile, PickFileName);
  571.   Reset(PickFile);
  572.   IF IoResult <> 0 THEN BEGIN
  573.     Error('Pick-File nicht gefunden');
  574.     Inform(MainMenu);
  575.   END ELSE BEGIN                                       (* Pickliste einlesen *)
  576.     WHILE NOT EoF(PickFile) DO BEGIN
  577.       ReadLn(PickFile, St);
  578.       IF St <> '' THEN BEGIN
  579.         Inc(LastPick);
  580.         WITH PickList[LastPick] DO BEGIN
  581.           Selected := FALSE;
  582.           Parse(St, n, p);
  583.           AssignStr(Name, n);
  584.           IF p <> '' THEN
  585.             AssignStr(Params, p);
  586.           IF NOT EoF(PickFile) THEN BEGIN
  587.             ReadLn(PickFile, St);
  588.             IF St <> '' THEN
  589.               AssignStr(Comment, St);
  590.           END;
  591.         END;
  592.       END;
  593.     END;
  594.     Close(PickFile);
  595.   END;
  596. END;
  597.  
  598.  
  599. PROCEDURE ToggleDisplayMode;           (* Anzeigewechsel: Vektoren/Erklärung *)
  600. BEGIN
  601.   DisplayVectors := NOT DisplayVectors;
  602.   SetupInfoList(DisplayVectors);
  603.   RedrawScrollArea;                               (* Bildschirm neu ausgeben *)
  604. END;
  605.  
  606.  
  607. PROCEDURE PickChoice;
  608.             (* Auswahl aus der Pickliste zum Laden von residenten Programmen *)
  609. VAR
  610.   MainListArea : ScrollPB;
  611.   Aborted      : BOOLEAN;
  612.   j, k, Key    : WORD;
  613. BEGIN
  614.   Rewrite(BatchFile);
  615.   IF LastPick = 0 THEN Exit;                          (* Pickliste ist leer! *)
  616.   SaveScreenTo(TempBuffer);
  617.   Inform(PickMenu);
  618.   SaveScrollArea(MainListArea);
  619.   SwitchWindow(Pick);
  620.   SetupScrollArea(LastPick, @WriteNormalPick, @WriteSelectedPick);
  621.   ScrollResponse(Home);
  622.   Aborted := FALSE;
  623.   REPEAT
  624.     Key := GetKey;
  625.     ScrollResponse(Key);
  626.     CASE Key OF
  627.       Left,
  628.       Right  : BEGIN
  629.                  PickList[SelectIndex].Selected := (Key = Right);
  630.                  WriteSelectedPick(1, Succ(SelectIndex-TopIndex), SelectIndex);
  631.                  ScrollResponse(Down);
  632.                END;
  633.       Return : Quit := TRUE;
  634.       Esc    : Aborted := TRUE;
  635.     END;
  636.   UNTIL Quit OR Aborted;
  637.   RestoreScreenFrom(TempBuffer);
  638.   IF NOT Aborted THEN BEGIN                 (* es soll etwas geladen werden! *)
  639.     j := 0;
  640.     FOR k:=1 TO LastPick DO        (* Pickliste nach Selekt-Marken abchecken *)
  641.       WITH PickList[k] DO
  642.         IF Selected THEN BEGIN
  643.           Write(BatchFile, Name^);
  644.           IF Params <> NIL THEN              (* Kommandoparameter vorhanden? *)
  645.             Write(BatchFile, Params^);
  646.           WriteLn(BatchFile);
  647.           Inc(j);
  648.         END;
  649.     IF j = 0 THEN                  (* keine Marken gesetzt: Balken ist Marke *)
  650.       WITH PickList[SelectIndex] DO BEGIN
  651.         Write(BatchFile, Name^);
  652.         IF Params <> NIL THEN                (* Kommandoparameter vorhanden? *)
  653.           Write(BatchFile, Params^);
  654.         WriteLn(BatchFile);
  655.       END;
  656.   END ELSE
  657.     RestoreScrollArea(MainListArea);       (* alten Zustand wiederherstellen *)
  658. END;
  659.  
  660.  
  661. PROCEDURE ReleaseTSRs;
  662.        (* Auswahl, welche residenten Programme wieder gelöscht werden sollen *)
  663. VAR
  664.   Key : WORD;
  665.  
  666.   PROCEDURE RestoreVectors;
  667.                         (* von einem Programm benutzte Vektoren restaurieren *)
  668.   VAR
  669.     j, v : BYTE;
  670.   BEGIN
  671.     j := 0;
  672.     FOR v:=0 TO $FF DO
  673.       WITH ProgramList[LastEntry]^ DO
  674.         IF v IN HookedVectors THEN BEGIN
  675.           SetIntVec(v, SavedVectors^[j]);
  676.           Inc(j);
  677.         END;
  678.   END;
  679.  
  680.   PROCEDURE ReleaseMemory(Segment : WORD);
  681.         (* gibt den von DOS belegten Speicherblock bei "Segment" wieder frei *)
  682.   VAR
  683.     Regs : Registers;
  684.   BEGIN
  685.     WITH Regs DO BEGIN
  686.       ES := Segment;
  687.       AH := $49;                     (* DOS-Funktion "Free Allocated Memory" *)
  688.       MsDos(Regs);
  689.       IF Odd(Flags) THEN BEGIN
  690.         Error('Fehler bei Freigabe von Block ' + HexW(Segment));
  691.         Inform(ReleaseMenu);
  692.       END;
  693.     END
  694.   END;
  695.  
  696. BEGIN
  697.   ReleaseMode := TRUE;
  698.   DisposeStr(InfoList[LastEntry]);         (* Freispeicher-Eintrag entfernen *)
  699.   Dec(LastEntry);
  700.   Dec(LinesToScroll);
  701.   SetAttribute(ProgAttr); ClrScr;
  702.   Inform(ReleaseMenu);
  703.   ScrollResponse(End_);
  704.   REPEAT                      (* Scrollroutine dient jetzt zur Lösch-Anwahl! *)
  705.     Key := GetKey;
  706.     IF Key = Tab THEN
  707.       ToggleDisplayMode
  708.     ELSE
  709.       ScrollResponse(Key);
  710.   UNTIL (Key = Esc) OR (Key = Return);
  711.   IF Key = Return THEN BEGIN                (* markierte Programme entfernen *)
  712.     WHILE LastEntry >= SelectIndex DO                   (* Programm löschen? *)
  713.       WITH ProgramList[LastEntry]^ DO
  714.         IF JustName(ProgramName^) <> JustName(ComSpecName) THEN BEGIN
  715.           RestoreVectors;                  (* Interruptvektoren restaurieren *)
  716.           ReleaseMemory(ProgramSeg);           (* Programmspeicher freigeben *)
  717.           IF EnvironSize <> 0 THEN
  718.             ReleaseMemory(EnvironSeg);              (* Environment freigeben *)
  719.           NextPSP := ProgramSeg;
  720.           DisposeStr(InfoList[LastEntry]);            (* aus Liste entfernen *)
  721.           ProgramList[LastEntry] := NIL;
  722.           IF LastEntry = 1 THEN BEGIN                   (* MONITOR gelöscht? *)
  723.             Quit := TRUE; Exit;              (* dann sofort Programm beenden *)
  724.           END;
  725.           Dec(LastEntry);
  726.         END ELSE BEGIN
  727.           Error('Löschen außerhalb aktueller DOS-Umgebung nicht möglich');
  728.           SelectIndex := Succ(LastEntry);
  729.         END;
  730.   END;
  731.   UpdateLastEntry;          (* Segment und Größe des freien Blocks eintragen *)
  732.   ReleaseMode := FALSE;
  733.   SetAttribute(ProgAttr); ClrScr;
  734.   LinesToScroll := LastEntry;            (* neuen Listenumfang bekanntmachen *)
  735.   ScrollResponse(End_);
  736. END;
  737.  
  738.  
  739. BEGIN                                               (* Manager-Hauptprogramm *)
  740.   Initialize;
  741.   SetupPickList;
  742.   SetupInfoList(DisplayVectors);
  743.   SetupScrollArea(LastEntry, @WriteNormalTSR, @WriteSelectedTSR);
  744.   ScrollResponse(End_);
  745.   Quit := FALSE;
  746.   REPEAT
  747.     Key := GetKey;
  748.     ScrollResponse(Key);
  749.     CASE Key OF
  750.       Tab : ToggleDisplayMode;
  751.       Ins,
  752.       Del : BEGIN
  753.               IF Key = Ins THEN
  754.                 PickChoice
  755.               ELSE
  756.                 ReleaseTSRs;
  757.               Inform(MainMenu);
  758.             END;
  759.       Esc : Quit := TRUE;
  760.     END;
  761.   UNTIL Quit;                   (* bis <Esc> gedrückt oder MONITOR gelöscht! *)
  762.   Close(BatchFile);
  763.   TextMode(LastMode);
  764.   RestoreScreenFrom(MainBuffer);
  765.   GotoXY(SaveX, SaveY);
  766. END.
  767. (* ------------------------------------------------------------------------- *)
  768. (*                       Ende von MANAGER.PAS                                *)