home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------------------------- *)
- (* PROGMAP.PAS (v3.1) *)
- (* Anlegen eines Belegungsplanes des PC-Hauptspeichers *)
- (* Copyright (c) 1988 Karsten Gieselmann & TOOLBOX *)
- (* ------------------------------------------------------------------------- *)
-
- {$R-,S-,I-,V-,B-,N-} (* größtmögliche Geschwindigkeit! *)
-
- UNIT ProgMap;
-
- INTERFACE USES Dos; (* benötigte Units *)
-
- TYPE
- ProgName = STRING[8]; (* "reiner" Programmname (ohne Pfad und Suffix) *)
-
- EntryPtr = ^ProgEntry; (* Eintrag für ein Programm *)
- ProgEntry = RECORD
- Segment : WORD; (* Lade-Segment *)
- Name : ProgName; (* Name des Programms *)
- Segs : BYTE; (* Anzahl der Segmente *)
- Paragraphs : WORD; (* belegter Speicher *)
- Last, (* Zeiger auf letzten Eintrag *)
- Next : EntryPtr; (* Zeiger auf nächsten Eintrag *)
- END;
-
- VAR
- UnUsed : WORD; (* Größe der nicht belegten Blöcke in Paragraphen *)
-
-
- PROCEDURE MakeMemoryMap (VAR FirstProgPtr : EntryPtr);
- (* Diese Routine erstellt eine nach Segmenten aufsteigend geordnete Liste
- aller im Hauptspeicher befindlichen residenten Programme. Der durch un-
- benutzte Blöcke belegte Speicher wird in der globalen Variablen UnUsed
- mitgezählt (Angabe in Paragraphen). Der Zugriff auf die von MakeMemory-
- Map erstellte Liste erfolgt Über den VAR-Parameter FirstProgPtr, dieser
- enthält einen Zeiger auf den ersten Listeneintrag. *)
-
-
- IMPLEMENTATION
-
-
- PROCEDURE MakeMemoryMap (VAR FirstProgPtr : EntryPtr);
-
- TYPE
- MCB_Ptr = ^MCB_Type;
- MCB_Type = RECORD (* Aufbau eines Memory Control Blocks *)
- ID : CHAR;
- PSPSeg,Diff : WORD;
- END;
-
- VAR
- MCB : MCB_Type;
- CurrentMCB : MCB_Ptr;
- FirstProg, (* Listenkopf *)
- ProgPtr : EntryPtr; (* Arbeitszeiger *)
-
-
- FUNCTION First_MCB : MCB_Ptr;
- (* liefert einen Zeiger auf den ersten Memory Control Block *)
- VAR
- Regs : Registers;
- BEGIN
- WITH Regs DO BEGIN
- AH := $52; (* undokumentierte Funktion 52h *)
- MsDos (Regs);
- First_MCB := Ptr (MemW[ES:BX-2], 0);
- END
- END;
-
-
- PROCEDURE GetProgPos (PSPSeg : WORD; VAR ProgPtr : EntryPtr);
- (* durchsucht die nach Segmenten aufsteigend sortierte Programm-Liste
- und liefert die Einfüge-Position; befindet sich bereits ein Eintrag
- in der Liste, bei welchem das Segment mit "PSPSeg" übereinstimmt, so
- wird ein Zeiger auf diesen Eintrag übergeben *)
- BEGIN
- ProgPtr := FirstProg;
- WHILE (ProgPtr^.Next <> NIL) AND (ProgPtr^.Segment < PSPSeg) DO
- ProgPtr := ProgPtr^.Next;
- IF ProgPtr <> FirstProg THEN
- IF PSPSeg < ProgPtr^.Segment THEN
- ProgPtr := ProgPtr^.Last
- END;
-
-
- PROCEDURE InsertNewProg (VAR ProgPtr : EntryPtr);
- (* erzeugt ein neues Listenelement und fügt es hinter "ProgPtr" ein *)
- VAR
- NewProg : EntryPtr;
- BEGIN
- New (NewProg);
- NewProg^.Next := ProgPtr^.Next;
- NewProg^.Last := ProgPtr;
- ProgPtr^.Next := NewProg;
- IF NewProg^.Next <> NIL THEN
- NewProg^.Next^.Last := NewProg;
- ProgPtr := NewProg
- END;
-
-
- FUNCTION GetProgName (PSPSeg : WORD) : ProgName;
- (* holt das Environment-Segment aus dem PSP (Offset 2Ch) und schaut
- dort nach dem vom DOS (erst ab Version 3.0!) abgelegten Dateinamen;
- bei erfolgreicher Suche werden Pfad und Extension abgeschnitten und
- der reine Programmname übergeben *)
-
- VAR
- Name : STRING;
- EnvSeg,EnvOfs : WORD; (* Segment, Offset des Environments *)
- p : BYTE;
-
- BEGIN
- EnvSeg := MemW [MCB.PSPSeg:$002C];
- EnvOfs := 0;
- Name := '';
- WHILE MemW[EnvSeg:EnvOfs] <> $0000 DO (* bis Ende des Env.-Strings *)
- Inc(EnvOfs);
- IF MemW[EnvSeg:EnvOfs+2] = $0001 THEN BEGIN (* Dateiname ist eingetragen *)
- Inc(EnvOfs,4); (* EnvOfs auf Dateinamen *)
- WHILE Mem[EnvSeg:EnvOfs] <> $00 DO BEGIN (* bis zum Ende des Namens *)
- Name := Name + Chr(Mem[EnvSeg:EnvOfs]);
- Inc (EnvOfs)
- END;
- REPEAT (* Pfadnamen abspalten *)
- p := Pos ('\', Name);
- Delete (Name, 1, p);
- UNTIL p=0;
- END;
- p := Pred (Pos ('.', Name));
- GetProgName := Copy (Name, 1, p); (* Extension abspalten *)
- END;
-
-
- BEGIN
- New (FirstProg); (* Programm-Liste anlegen *)
- WITH FirstProg^ DO BEGIN
- Segment := 0;
- Next := NIL;
- Last := NIL;
- END;
- UnUsed := 0;
- CurrentMCB := First_MCB; (* Zeiger auf ersten MCB holen *)
- REPEAT
- MCB := CurrentMCB^;
- WITH MCB DO
- IF PSPSeg > $0070 THEN BEGIN (* belegt und nicht vom DOS benutzt? *)
- GetProgPos (PSPSeg, ProgPtr);
- IF (ProgPtr <> FirstProg) AND (ProgPtr^.Segment = PSPSeg) THEN
- WITH ProgPtr^ DO BEGIN
- Inc(Segs);
- IF Name <> 'DOS' THEN
- Name := GetProgName (PSPSeg);
- Inc (Paragraphs, Diff);
- END
- ELSE (* neuen Eintrag erzeugen *)
- BEGIN
- InsertNewProg (ProgPtr);
- WITH ProgPtr^ DO BEGIN
- Segment := PSPSeg;
- Segs := 1;
- Paragraphs := Diff;
- IF ProgPtr = FirstProg^.Next THEN (* Eintrag ist DOS! *)
- Name := 'DOS'
- ELSE
- Name := '???'
- END
- END
- END
- ELSE
- IF PSPSeg = $0000 THEN (* unbenutzer Speicherblock *)
- Inc (UnUsed, Diff);
- CurrentMCB := Ptr (Seg(CurrentMCB^)+MCB.Diff+1,0); (* nächster MCB *)
- UNTIL MCB.ID = 'Z';
- FirstProgPtr := FirstProg^.Next;
- END;
-
-
- END.
-