home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1989 / 01 / praxis / manherc.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-09-16  |  25.8 KB  |  762 lines

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