home *** CD-ROM | disk | FTP | other *** search
- PROGRAM nDR;
- (* Gets and writes a directory of a selected disk: gives file sizes
- in k, sorts alphabetically, correctly treats large files >1 extent. If
- procedure SIZ is included, it calculates and displays disk space data.
- Mike Yarus, 2231 16th Street, Boulder, CO 80302, Compuserve 73145,513. *)
-
- (* This adaptation by--Bob Durling, 12-8-85-- adds auccessive directories
- to an index file that includes a user-supplied disk name. Hereby placed
- in public all commercial use restricted. *)
-
- (* As now set up, the program must be run form disk A: (or ramdisk),
- since it provides for resetting disk B: when the disk to be catalogued
- is inserted. This could be changed, of course. *)
-
- TYPE
- TWELVESTR = STRING[12];
- DP = ^DIRENTRY;
- DIRENTRY = RECORD
- FNAME: TWELVESTR; (* file name *)
- FSIZE: BYTE; (* file size *)
- LEFTP, RIGHTP: DP (* l & r pointers *)
- END;
- VAR
- answer : char;
- flout : text;
- date, dskname, flname : twelvestr;
- MYFCB: ARRAY [0..35] OF BYTE; (* a special File Control Block *)
- MYDMA: ARRAY [0..127] OF BYTE; (* a special directory buffer *)
- NDEX,
- BDOSFN, (* number of the CP/M BDOS function required *)
- DIRPAGENDEX, (* which of the 4 dir entries in MYDMA is current? *)
- LINECONTROL, (* # directory entries, controls print position *)
- ENTRIES: BYTE; (* number of directory entries, including >1 extents *)
- FILES, (* nr files *)
- OCCUPADO: INTEGER; (* space now taken by files *)
- DUMMY,
- DRV: CHAR; (* A, B,.. drives *)
- ENTRYP, ROOP: DP; (* the root and new entry pointer *)
-
- FUNCTION DRIVENR: BYTE;
- { Asks for drive letter, converts to CP/M's number, updates global DRV as
- side effect; take that, Niklaus. }
- BEGIN
- WRITE('Directory of disk on which drive ? --> L<cr> ');
- READLN (DRV);
- DRV := UPCASE (DRV);
- WRITELN; {line above directory}
- DRIVENR := ORD (DRV) - $40 {1 = drive A:, 2 = B:, 4 = D:}
- END; { drivenr }
-
- PROCEDURE SIZ (ENTRIES: BYTE; FILES, OCCUPADO: INTEGER);
- (* Calculates storage params by consulting the current info in the BIOS.
- DR can be shortened by just removing this procedure and its call in
- the main program. *)
- TYPE
- IP = ^INTEGER;
- VAR
- DSMPTR, DRMPTR: IP;
- DPB, BLOCK, DSM, DRM, DIRSIZE, REMAINS, STORAGE: INTEGER;
- BLM, NEWD, CURRENTDSK, DIRBLOCKS, AL0, AL0MASK: BYTE;
-
- BEGIN
- NEWD := ORD (DRV) - $41; (* CP/M disk #, 00 = A:, etc *)
- CURRENTDSK := BDOS(25); (* get the present disk # *)
- BDOS (14, NEWD); (* select the new disk *)
- DPB := BDOSHL(31); (* get DPB (disk parameter block) address *)
- DRMPTR := PTR(DPB+7); (* point to DRM, max directory entries-1 *)
- DRM := DRMPTR^; (* get DRM *)
- DSMPTR := PTR(DPB+5); (* point to DSM, max # data blocks-1 *)
- DSM := DSMPTR^; (* get DSM *)
- BLM := MEM [DPB+3]; (* get BLM, related to data block size *)
- BLOCK := (BLM+1) DIV 8; (* calc data block size in kbytes *)
- DIRBLOCKS := 0; (* initiate # blocks for directory *)
- AL0 := MEM [DPB+9]; (* get AL0, directory storage allocation *)
- AL0MASK := $80; (* 10000000 binary, for bit masking *)
- WHILE ((AL0 AND AL0MASK) <> 0) AND (AL0MASK >= 1) DO
- BEGIN (* get the # of directory blocks *)
- DIRBLOCKS := DIRBLOCKS + 1;
- AL0MASK := AL0MASK DIV 2
- END;
- DIRSIZE := DIRBLOCKS * BLOCK; (* size of the tirectory, in kbytes *)
- STORAGE := BLOCK * (DSM+1); (* total storage (kbytes) = block X #blocks *)
- REMAINS := STORAGE - DIRSIZE - OCCUPADO;
- WRITELN; WRITELN; writeln(flout1);
- WRITELN (' ',DRV,': ',REMAINS,'k remain/',STORAGE,'k total -- ',
- FILES,' files = ',OCCUPADO,'k - ',
- ENTRIES,'/',DRM+1,' entries');
- WRITELN (' ',MEM [DPB+13],' system track(s) -- ', (* delete this statement *)
- MEM [DPB],' records/track -- ', (* if disk structure data *)
- DIRBLOCKS,' directory blocks -- ', (* is not wanted *)
- BLOCK,'k blocks');
- WRITELN;
- BDOS (14, CURRENTDSK) (* reselect original disk *)
- END;
-
- PROCEDURE FILECONTROLBLOCK (DR: BYTE);
- (* File control block set for reading all files, filename = ????????.???
- Note that when only the first extent of a big file is needed (eg, for a
- list of file names only) one sets 13th byte (ndex = 12) of the fcb to zero. *)
- BEGIN
- MYFCB [0] := DR; (* which drive? *)
- FOR NDEX := 1 TO 12 DO (* set for ambiguous file name AND extent *)
- MYFCB [NDEX] := ORD ('?');
- FOR NDEX := 13 TO 35 DO (* some of the other bytes must be = 0 *)
- MYFCB [NDEX] := 0 (* set them all, what the heck? *)
- END; (* filecontrolblock *)
-
- PROCEDURE WRITIT (AFILENAME: TWELVESTR; KBYTES: BYTE);
- (* Output of dir info in lines; set for 3 entries/line. *)
- BEGIN
- LINECONTROL := LINECONTROL + 1; (* increment entries *)
- IF LINECONTROL MOD 3 = 1 THEN
- begin
- WRITE(' ',AFILENAME,' ',KBYTES:3,'k ');
- writeln(flout, afilename,' ',kbytes:3, 'k ', dskname);
- end
- else begin
- WRITE(': ',AFILENAME,' ',KBYTES:3,'k ');
- writeln(flout,afilename,' ',kbytes:3,'k ', dskname);
- end;
- IF LINECONTROL MOD 3 = 0 THEN WRITELN;
- END; (* writit *)
-
- {$A-} (* **** recursive reference needed from here on **** *)
-
- PROCEDURE BUILDTREE (VAR ROP, ENTRYP: DP);
- (* Builds an ordered tree of directory entries. Note that replace
- function in code takes care of duplicate entries in dictionary due
- to large files present in >1 extent. *)
- BEGIN
- IF ROP = NIL THEN (* end of limb, place current entry *)
- ROP := ENTRYP
- ELSE
- IF ROP^.FNAME = ENTRYP^.FNAME THEN (* replace entry, if >1 extent *)
- BEGIN
- ROP^.FSIZE := ENTRYP^.FSIZE;
- DISPOSE (ENTRYP)
- END
- ELSE
- IF ROP^.FNAME > ENTRYP^.FNAME THEN (* left for small *)
- BUILDTREE (ROP^.LEFTP, ENTRYP)
- ELSE
- BUILDTREE (ROP^.RIGHTP, ENTRYP) (* right for large *)
- END; (* buildtree *)
-
- PROCEDURE WRITETREE (VAR ROP: DP; VAR FILES, OCCUPADO: INTEGER);
- (* Recursively writes the directory inorder (alphabetically) from the rop.
- Updates global OCCUPADO and FILES. Recalculates file sizes to make them
- end on allocation block borders, as they must. *)
- BEGIN
- IF ROP <> NIL THEN
- BEGIN
- WRITETREE (ROP^.LEFTP, FILES, OCCUPADO);
- ROP^.FSIZE := ROP^.FSIZE +
- ROP^.FSIZE MOD ((MEM [BDOSHL(31)+3] + 1) DIV 8); (* file size modulo *)
- WRITIT (ROP^.FNAME, ROP^.FSIZE); (* block size must be *)
- OCCUPADO := OCCUPADO + ROP^.FSIZE; (* equal zero *)
- FILES := FILES + 1;
- WRITETREE (ROP^.RIGHTP, FILES, OCCUPADO)
- END
- END; (* writetree *)
-
- PROCEDURE DISPOTREE (VAR ROP: DP);
- (* Disposes the storage devoted to the tree postorder. Required
- mainly for repetitive execution of the program within a larger
- program, since directory tree is fairly small. *)
- BEGIN
- IF ROP <> NIL THEN
- BEGIN
- DISPOTREE (ROP^.LEFTP);
- DISPOTREE (ROP^.RIGHTP);
- DISPOSE (ROP)
- END
- END; (* dispotree *)
-
- PROCEDURE GETENTRY (BDOSFN: BYTE; VAR ENTRIES: BYTE; VAR ROP: DP);
- (* Finds and writes a single directory entry from the disk directory
- to the directory tree; makes a tree via BUILDTREE. *)
- VAR
- NDEX: BYTE;
- ENTRYSIZE: REAL; (* in bytes, real because can be > maxint *)
- BEGIN
- NEW (ENTRYP);
- DIRPAGENDEX := BDOS (BDOSFN, ADDR (MYFCB)); (* get directory in MYDMA *)
- IF (MYDMA [DIRPAGENDEX * 32] = 0) AND (DIRPAGENDEX <> $FF) THEN
- BEGIN (* entry is not erased AND entry exists *)
- ENTRYP^.FNAME [0] := CHR (12); (* CP/M pads all filenames to full size *)
- FOR NDEX := 1 TO 8 DO (* get file name *)
- ENTRYP^.FNAME [NDEX] := CHR (MYDMA [DIRPAGENDEX * 32 + NDEX]);
- ENTRYP^.FNAME [9] := '.';
- FOR NDEX := 9 TO 11 DO (* get file extension *)
- ENTRYP^.FNAME [NDEX + 1] := CHR (MYDMA [DIRPAGENDEX * 32 + NDEX]);
- ENTRYSIZE := 1.0 * ((MYDMA [DIRPAGENDEX * 32 + 12] * 128) + (* 13th byte # extents *)
- MYDMA [DIRPAGENDEX * 32 + 15]) * 128; (* 16th byte is # records *)
- ENTRYP^.FSIZE := ROUND ((ENTRYSIZE/1024) + 0.499);(* round up to next kbyte *)
- ENTRYP^.LEFTP := NIL;
- ENTRYP^.RIGHTP := NIL;
- ENTRIES := ENTRIES + 1;
- BUILDTREE (ROOP, ENTRYP) (* put the entry in tree *)
- END (* if mydma.. *)
- END; (* getentry *)
-
- BEGIN (* main *)
- writeln('Program must be run from disk A: or ramdisk.');
- repeat
- write('Enter name of index file -- ');
- readln(flname);
- assign(flout2, flname);
- {$I-} reset(flout2); {$I+}
- if ioresult = 0 then
- begin
- write('File exists -- overwrite ? ');
- readln(answer);
- if upcase(answer) = 'Y' then rewrite(flout);
- end;
- until (upcase(answer) = 'Y') or (ioresult <> 0);
- write('Enter date -- ');
- readln(date);
- write('Enter name of disk -- ');
- readln(dskname);
- writeln(flout, ' ', date);
- writeln(flout);
- repeat
- LINECONTROL := 0; (* initiate for output print control *)
- ROOP := NIL; (* initiate directory tree *)
- ENTRIES := 0; (* nr entries in disk directory *)
- FILES := 0; (* nr files *)
- OCCUPADO := 0; (* disk storage used *)
- BDOS (26, ADDR (MYDMA)); (* define MYDMA to buffer directory *)
- FILECONTROLBLOCK (DRIVENR); (* get disk name, set ambiguous filenames *)
- BDOSFN := 17; (* search for first file *)
- REPEAT
- GETENTRY (BDOSFN, ENTRIES, ROOP); (* get'em and tree'em *)
- BDOSFN := 18 (* switch to search for next after first file *)
- UNTIL DIRPAGENDEX = $FF; (* no files left *)
- WRITETREE (ROOP, FILES, OCCUPADO); (* sorted directory OUT! *)
- SIZ (ENTRIES, FILES, OCCUPADO); (* get disk storage statistics *)
- DISPOTREE (ROOP); (* release storage *)
- {$A+}
- write('Continue ? ');
- read(kbd, answer);
- if upcase(answer) <> 'N' then
- begin
- write('Change disk in drive B: , then type <CR> --');
- read(answer); writeln;
- bdos($25,2);
- write('Enter name of disk -- ');
- readln(dskname);
- end;
- until upcase(answer) = 'N';
- close(flout);
- END. (* dr *)