Contributor: DESCLIN JEAN { A few days ago, Bryan Ellis (gt6918b@prism.gatech.edu) mentioned that he had trouble with the DiskFree function of TP. I did'nt see any answer on this subject posted to the list. Since I also feel that this function yields misleading results to the unaware, and available clusters on the disk are also a requisite for full information, I post below a small program to document another way to implement the Diskfree function. That part of the following code referring to the identification of ramdisks has already been posted on info-pascal@brl.mil; I have added the procedure DiskEval to display info about the drive, because I have found that many users are not aware of the notion of 'slack' which is the consequence of the use of clusters. } {$N+,E+} program diskall; { displays all drives (except network drives :-() actually in use by the system, mentions when one is mapped to another one (such as B: to A: in systems with only one floppy drive), tries to identify RAM disks but fails to do so with 'Stacked' disks and possibly also with 'Doublespaced' drives: I refrained from trying the latter on _MY_ stacked HD! The program further shows the available space on the disk chosen by the user among available drives. From what I have gathered in books and on the net, there is no fail- safe way of identifying RAM disks. If somebody among the readers of this should know otherwise, I would be grateful if he could email me the solution at: desclinj@ulb.ac.be (internet; Dr Jean Desclin) (Lab. of Histology, Fac. of Medicine) (Brussels Free University (U.L.B.) Belgium) } uses Dos,CRT; Type String25 = String[25]; var ver : byte; DrvStr : String; DrvLet : char; Count : shortint; car : char; Procedure Pinsert(var chain: string25); {Eases reading long numbers by inserting decimal points(commas)} Const pdec : string[1] = ','; var nv : string25; loc : integer; begin nv := chain; if length(chain) > 3 then begin loc := length(chain) - 2; Move(Nv[loc],Nv[succ(loc)],succ(Length(Nv))-loc); Move(Pdec[1],Nv[loc],1); inc(Nv[0]); while (pos(pdec[1],Nv) > 4) do begin chain := Nv; loc := pos(pdec[1],Nv) - 3; Move(Nv[loc],Nv[succ(loc)],succ(length(Nv)) - loc); Move(pdec[1],Nv[loc],1); inc(Nv[0]) end; end; chain := nv end; procedure GetDrives1(var DS: string);{for DOS >= 3.x but <4.0 } {Adapted from Michael Tischer's Turbo Pascal 6 System Programming, } {Abacus 1991, ISBN 1-55755-124-3 } type DPBPTR = ^DPB; { pointer to a DOS Parameter Block } DPBPTRPTR = ^DPBPTR; { pointer to a pointer to a DPB } DPB = record { recreation of a DOS Parameter Block } Code : byte; { drive code (0=A, 1=B etc. } dummy1: array [1..$07] of byte;{irrelevant bytes} FatNb : byte; {Number of File Allocation Tables } dummy2: array [9..$17] of byte;{irrelevant bytes} Next : DPBPTR; { pointer to next DPB } end; { xxxx:FFFF marks last DPB } var Regs : Registers; { register for interrupt call } CurrDpbP : DPBPTR; { pointer to DPBs in memory } begin {-- get pointer to first DPB ------------------------------------} Regs.AH := $52;{ function $52 returns ptr to 'List of Lists' } MsDos( Regs );{ that's an UNDOCUMENTED DOS function ! } CurrDpbP := DPBPTRPTR( ptr( Regs.ES, Regs.BX ) )^; {-- follow the chain of DPBs--------------------------------------} repeat begin write(chr(ord('A')+CurrDpbP^.Code ),{ display device code } ': ' ); DS := DS + chr(ord('A')+CurrDpbP^.Code); if CurrDpbP^.Code > 0 then begin Regs.AX := $440E; Regs.BL := CurrDpbP^.Code; MsDos(Regs); if Regs.AL <> 0 then writeln(' is actually mapped to ', chr(ord('A')+pred(CurrDpbP^.Code))) end; if ((CurrDpbP^.FatNb > 0) AND (CurrDpbP^.FatNb < 2)) then writeln(' (RAMDISK)'); end; CurrDpbP := CurrDpbP^.Next; { set pointer to next DPB } until ( Ofs( CurrDpbP^ ) = $FFFF ); { until last DPB is reached } writeln end; procedure GetDrives2(var DS: string);{for DOS versions>=4.0 } {almost the same as GetDrives1, but for dummy2 which is one byte } {longer in DOS 4+ } type DPBPTR = ^DPB; { pointer to a DOS Parameter Block } DPBPTRPTR = ^DPBPTR; { pointer to a pointer to a DPB } DPB = record { recreation of a DOS Parameter Block } Code : byte; { drive code ( 0=A, 1=B etc. } dummy1 : array [1..$07] of byte;{ irrelevant bytes} FatNb : byte;{ Number of File Allocation Tables } dummy2 : array [9..$18] of byte;{ irrelevant bytes} Next : DPBPTR; { pointer to next DPB } end; { xxxx:FFFF marks last DPB } var Regs : Registers; { register for interrupt call } CurrDpbP : DPBPTR; { pointer to DPBs in memory } begin {-- get pointer to first DPB-------------------------------------} Regs.AH := $52;{ function $52 returns ptr to Dos 'List of lists' } MsDos( Regs );{ that's an UNDOCUMENTED DOS function ! } CurrDpbP := DPBPTRPTR( ptr( Regs.ES, Regs.BX ) )^; {-- follow the chain of DPBs -------------------------------------} repeat begin write( chr( ord('A') + CurrDpbP^.Code ),{ display device code } ': '); DS := DS + chr(ord('A')+CurrDpbP^.Code); if CurrDpbP^.Code > 0 then begin Regs.AX := $440E; Regs.BL := CurrDpbP^.Code; MsDos(Regs); if Regs.AL <> 0 then writeln(' is actually mapped to ', chr(ord('A')+pred(CurrDpbP^.Code))) end; if ((CurrDpbP^.FatNb > 0) AND (CurrDpbP^.FatNb < 2)) then writeln(' (RAMDISK)'); end; CurrDpbP := CurrDpbP^.Next; { set pointer to next DPB } until ( Ofs( CurrDpbP^ ) = $FFFF ); { until last DPB is reached } writeln end; Procedure DiskEval; {computes statistics of disk chosen by user} var Reg : registers; Drive : char; column,row : shortint; SectorsPerCluster : Word; AvailClusters : Word; BytesPerSector : Word; TotalClusters : Word; BytesAvail,Clut : longint; Kilos : extended; ByAl : string25; TotClut : string25; OneClut : string25; AvailClut : string25; begin write(''); column := whereX; row := whereY; repeat gotoXY(column,row); write('Which drive to read from? ',' ',chr(8)); read(Drive); Drive := UpCase(Drive); until (pos(Drive,DrvStr) <> 0); writeln; with Reg do begin DL := ord(Drive) - 64; AH := $36; Intr($21,Reg); SectorsPerCluster := AX; AvailClusters := BX; BytesPerSector := CX; TotalClusters := DX end; BytesAvail := longint(BytesPerSector) * longint(SectorsPerCluster) * longint(AvailClusters); Kilos := BytesAvail/1024; clut := longint(SectorsPerCluster)*longint(BytesPerSector); Str(BytesAvail,Byal); Pinsert(Byal); Str(AvailClusters,AvailClut); Pinsert(AvailClut); Str(Clut,OneClut); Pinsert(OneClut); Str(TotalClusters,TotClut); Pinsert(Totclut); clrscr; if SectorsPerCluster <> 65535 then begin write('For drive '); HighVideo; write(Drive); LowVideo; writeln(':'); writeln('Sectors per cluster: ',SectorsPerCluster); writeln('Bytes per sector: ',BytesPerSector); writeln('Total clusters: ',TotClut); writeln('Available clusters: ',AvailClut); write('(One cluster = ',oneclut,' bytes: the smallest'); writeln(' allocatable space!)'); write('A TOTAL of ',ByAl,' BYTES are AVAILABLE (',Kilos:6:3); writeln(' K)') {previous line split for display: length <73 } end else writeln('There is no diskette in drive ',Drive,': !') end; begin car := #0; repeat DrvStr := ''; DrvLet := #0; clrscr; ver := Lo(DosVersion); writeln('Installed logical drives are : '#13#10); if ver < 4 then GetDrives1(DrvStr) else GetDrives2(DrvStr); DiskEval; writeln; write('type ''Y'' to continue, any other key to exit.'); car := upcase(readkey); until (car <> 'Y') end.