home *** CD-ROM | disk | FTP | other *** search
- (* ----------------------------------------------------------------------- *)
- (* DFREECPM.PAS *)
- (* Ermittlung des freien Speicherplatzes einer Disk fuer CP/M 2.x & 3.x. *)
-
- TYPE (* MS-DOS kompatible Ergebnis-Struktur der DFree-Funktion: *)
- DSK_Info = RECORD
- FreeCluster, (* Anzahl freier Cluster der Disk *)
- TotalCluster, (* Anzahl Cluster insgesamt *)
- SectorSize, (* Groesse eines phys. Sektor in Bytes *)
- ClusterSize : REAL; (* Anzahl Sektoren pro Cluster *)
- END;
- (* Anm.: In den verfuegbaren Unterlagen (CP/M 2.2 Operating System Manual,
- CP/M 3 System & Programmers Guide) konnte ich keinen Hinweis finden, ob
- und wie die physikalische Sektorgroesse einer Disk bei CP/M 2.x ermit-
- telt werden kann. Dieses Info gibt CP/M 3.x im Disk Parameter Block
- (DPB). Aus diesem Grund wird in CP/M 2.x-Varianten einfach die logische
- Sektor-(Record-)groesse von 128 Bytes zu Grunde gelegt.
- Zur Ermittlung des freien Platzes unter CP/M 3.x ist das Verfahren fuer
- die 2.x Versionen nicht generell anwendbar (nur "nonbanked version" mit
- "single-Bit allocation vector"). Deshalb wird bei 3.x die entsprechende
- BDos-Funktion benutzt (s.u.). (MC) *)
- (* ----------------------------------------------------------------------- *)
- (* MS-DOS/TOS kompatible Funktion zur Ermittlung freien Speicherplatzes: *)
- (* Drive = 0: aktuelles Laufwerk, 1: Laufwerk A, 2: Laufwerk B, usw. *)
- PROCEDURE DFree(VAR Info: DSK_Info; Drive: INTEGER);
-
- TYPE
- DPB_Rec = RECORD (* ein CP/M 2.x/3.x Disk Parameter Block: *)
- RecsPerTrk : INTEGER; (* 128-Byte-Records pro Spur *)
- BlkShift, (* k.A. *)
- RecsPerBlk, (* 128-Byte-Records pro Block -1 *)
- ExtMask : BYTE; (* max. 16K-Extents pro FCB *)
- BlksPerDrv, (* Anzahl Bloecke - 1 der Disk *)
- DirEntrys, (* Anzahl Directory-Eintraege -1 *)
- DirBlkAlloc, (* Block-Belegung durch Directory *)
- DirChkVector, (* Groesse Dir.-Pruefvektors:
- (DirEntrys/4)+1 *)
- ReservedTrks : INTEGER; (* Anz. reservierter Spuren *)
- (* folgendes nur bei CP/M 3.x !!!! *)
- SecShift, (* k.A. *)
- RecsPerSec : BYTE; (* Anz. 128-Byte-Records p. Sektor *)
- END;
- DPB_Ptr = ^DPB_Rec;
- (* Der "Disk Allocation Vector" gibt die Block/Cluster-Belegung der Disk
- wieder. Bit gesetzt -> Cluster belegt, sonst frei. Seine Groesse in
- Bytes haengt von der Gesamtanzahl der Cluster einer Disk ab (s.u.) *)
- DAlloc_Ptr = ^BYTE;
- (* 3.x liefert Anz. freier 128-Rec. in den ersten 3 Bytes der akt. DTA: *)
- DFree_Inf = ARRAY[1..3] OF BYTE;
- DTA_Ptr = ^DFree_Inf;
-
- VAR
- CurDrv, AllocLen, FreeBlks, i: INTEGER;
- j, mask, shift : BYTE;
- DPB : DPB_Ptr;
- DAlloc : DAlloc_Ptr;
-
- FUNCTION DGetDPB: DPB_Ptr; (* Adr. des DPB des aktiven Laufwerks ermitteln *)
- BEGIN DGetDPB := Ptr(BDosHL($1F)) END;
-
- FUNCTION DGetAlloc: DAlloc_Ptr; (* Adr. des dazugehoerigen Alloc. Vectors *)
- BEGIN DGetAlloc := Ptr(BDosHL($1B)) END;
-
- FUNCTION DGetDrive: INTEGER; (* gerade aktives Laufwerk ermitteln *)
- BEGIN DGetDrive := BDos($19) END;
-
- PROCEDURE DSetDrive (Drive: INTEGER); (* obiges als selbiges setzen *)
- BEGIN
- BDos($0D); (* Laufwerke zuruecksetzen, dadurch akt. Alloc. Vect. *)
- BDos($0E, Drive) (* und neues Laufwerk waeh|en... *)
- END;
-
- FUNCTION DVersion: INTEGER; (* CP/M Versionsnummer ermitteln *)
- BEGIN DVersion := BDosHL($0C) END;
-
- FUNCTION FGetDTA: DTA_Ptr; (* akt. DTA ermitteln, nur CP/M 3.x *)
- VAR scbpb: RECORD ofs,com: BYTE; value: INTEGER; END;
- BEGIN
- scbpb.ofs := $3C; scbpb.com := 0; FGetDTA := Ptr(BDosHL($31,Addr(scbpb)));
- END;
-
- FUNCTION DFree3x (drv: INTEGER): REAL; (* Frei 128-Byte-Records ermit- *)
- VAR DTA: DTA_Ptr; (* teln, nur CP/M 3.x *)
- BEGIN
- DTA := FGetDTA; BDos($2E,drv);
- DFree3x := DTA^[1] + 256.0*DTA^[2] + 65536.0*DTA^[3];
- END;
-
- BEGIN (* DFree *)
- CurDrv := DGetDrive; (* aktuelles Laufwerk merken *)
- IF Drive IN [1..16] THEN Drive := Pred(Drive) ELSE Drive := CurDrv;
- DSetDrive(Drive); (* folgendes geht nur mit akt. Laufw., deshalb dieses *)
- DPB := DGetDPB; (* Adresse der Disk Parameter Blocks ermitteln *)
- IF (DVersion AND $FF) IN [$20..$2F] THEN BEGIN (* CP/M 2.x : *)
- (* Groesse des Alloc. Vectors in Bytes errechnen: *)
- AllocLen := Succ(DPB^.BlksPerDrv DIV 8);
- DAlloc := DGetAlloc; (* und seine Adresse holen *)
- FreeBlks := 0; (* logo !? *)
- shift := 8; (* Anz. zu maskierender Bits im akt. Byte des Alloc.-Vec. *)
- FOR i := 0 TO AllocLen DO BEGIN
- (* im letzten Byte des Alloc.-Vec. nicht mehr unbedingt 8 Bits mask.: *)
- IF i = Pred(AllocLen) THEN shift := DPB^.BlksPerDrv MOD 8;
- mask := 1; (* wir fangen beim' ersten Bit an *)
- FOR j := 1 TO shift DO BEGIN
- (* entsprechendes Cluster frei ? *)
- IF (DAlloc^ AND mask) = 0 THEN FreeBlks := Succ(FreeBlks);
- mask := mask SHL 1; (* zum naechsten Bit im Byte *)
- END; (* zum naechsten Byte im Allocation Vector: *)
- DAlloc := Ptr(Ord(DAlloc)+SizeOf(BYTE));
- END;
- WITH Info,DPB^ DO BEGIN
- FreeCluster := FreeBlks; SectorSize := 1.0;
- END;
- END
- ELSE IF (DVersion AND $FF) IN [$30..$3F] THEN (* CP/M 3.x : *)
- WITH Info,DPB^ DO BEGIN
- FreeCluster := DFree3x(Drive) / Succ(RecsPerBlk);
- SectorSize := Succ(RecsPerSec);
- END;
- WITH Info,DPB^ DO BEGIN (* gesammeltes Material der Aussenwelt mitteilen *)
- TotalCluster := Succ(BlksPerDrv);
- ClusterSize := Succ(RecsPerBlk) / SectorSize;
- SectorSize := SectorSize * 128.0;
- END;
- DSetDrive(CurDrv); (* wieder zum vorher aktiven Laufwerk zurueck *)
- END;
- (* ----------------------------------------------------------------------- *)
- (* und dies hier gibt schliesslich den freien Platz der Disk ganz einfach *)
- (* in Bytes aus. Wer kBytes moechte, teile den Ausdruck einfach durch 1024 *)
- FUNCTION DiskFree (Drive: CHAR): REAL;
- VAR Info: DSK_Info;
- BEGIN
- DFree(Info, Succ(Ord(UpCase(Drive))-Ord('A')));
- WITH Info DO
- DiskFree := SectorSize * ClusterSize * FreeCluster (* / 1024.0 *);
- END;
- (* ----------------------------------------------------------------------- *)
- (* DFREECPM.PAS *)