PROGRAM DIRFILE (INPUT, OUTPUT); {by Ed Reed Tailored Computer Solutions 1919 S. Newport Kennewick, WA 99336 } {This program reads the disk directory and writes it into a file named FILES.SUB} CONST MAXNAMES = 128; {Maximum number of file names in directory.} SECTRAK = 64; {Number of 128-byte sectors per track.} FIRSTRAK = 2; {First track to read directory from.} ENTRYLEN = 32; {Length of a directory entry.} TYPE CPMOPERATION = (COLDBOOT, WARMBOOT, CONSTAT, CONIN, CONOUT, LIST, PUNOUT, RDRIN, HOME, SELDSK, SETTRK, SETSEC, SETDMA, DSKREAD, DSKWRITE); NAMEREC = RECORD EXT : STRING[3]; NAME : STRING[12]; END; VAR I, J, K, L, M, NSTOR : INTEGER; MEMORY : ABSOLUTE [$0000] ARRAY [0 .. 0] OF BYTE; DIRECT : ARRAY [1 .. MAXNAMES, 1 .. ENTRYLEN] OF CHAR; LEADER, TRAILER, FNAME, EXTN : STRING; STORE : ARRAY [0 .. MAXNAMES] OF NAMEREC; FILEOUT : TEXT; OPTN : CHAR; {==========================================} {This routine was copied from MT's NSB.SRC} PROCEDURE SB_BIOS_CALL(FUNC:CPMOPERATION; PARM:INTEGER); VAR DISPATCH_LOC : INTEGER; BEGIN DISPATCH_LOC := (MEMORY[1] + SWAP(MEMORY[2])) + (ORD(FUNC)*3) - 3; INLINE("LHLD / PARM / "MOV C,L / "MOV B,H / "LHLD / DISPATCH_LOC / "PCHL); END; {=================================================} BEGIN {Read directory into direct access buffer} J := SECTRAK - 1; K := FIRSTRAK - 1; L := 0; I := ADDR (DIRECT); FOR M := 1 TO (MAXNAMES * ENTRYLEN DIV 128) DO BEGIN J := J + 1; IF J = SECTRAK THEN BEGIN J := 0; K := K + 1; SB_BIOS_CALL (SETTRK, K); END; SB_BIOS_CALL (SETSEC, J); SB_BIOS_CALL (SETDMA, I); SB_BIOS_CALL (DSKREAD, L); I := I + 128; END; {Get file names out of direct access buffer} NSTOR := 0; FOR I := 1 TO MAXNAMES DO BEGIN M := ORD (DIRECT[I, 1]); {Operate on active files only} IF M = 0 THEN BEGIN NSTOR := NSTOR + 1; {Put file name and extension in string variables for easy processing} MOVE (DIRECT[I, 2], FNAME[1], 8); MOVE (DIRECT[I, 10], EXTN[1], 3); FNAME[0] := CHR (8); EXTN[0] := CHR (3); {Eliminate blanks following file name} K := POS (' ', FNAME); IF K <> 0 THEN DELETE (FNAME, K, 9 - K); {Eliminate blanks following extension and store it for sorting} K := POS (' ', EXTN); IF K <> 0 THEN DELETE (EXTN, K, 4 - K); STORE[NSTOR].EXT := EXTN; {Concatenate extension onto file name and store the combination} IF LENGTH (EXTN) = 0 THEN STORE[NSTOR].NAME := FNAME ELSE STORE[NSTOR].NAME := CONCAT (FNAME, '.', EXTN); END; END; {Sort if requested} REPEAT WRITELN; WRITE ('SORT -- No, Extension, or File name (N, E, or F)? '); READLN (OPTN); IF OPTN IN ['a' .. 'z'] THEN OPTN := CHR (ORD (OPTN) - 32); UNTIL OPTN IN ['N', 'E', 'F']; IF OPTN = 'F' THEN {Blank out extensions stored separately} FOR I := 1 TO NSTOR DO STORE[I].EXT := ' '; IF (OPTN <> 'N') AND (NSTOR > 1) THEN {Inefficient bubble sort, but why get elegant on something used as little as this will be} BEGIN I := NSTOR; WHILE I > 1 DO BEGIN FOR J := 2 TO I DO BEGIN IF STORE[J].EXT < STORE[J - 1].EXT THEN BEGIN STORE[0] := STORE[J]; STORE[J] := STORE[J - 1]; STORE[J - 1] := STORE[0] END ELSE IF STORE[J].EXT = STORE[J - 1].EXT THEN BEGIN IF STORE[J].NAME < STORE[J - 1].NAME THEN BEGIN STORE[0] := STORE[J]; STORE[J] := STORE[J - 1]; STORE[J - 1] := STORE[0] END END END; I := I - 1 END END; WRITELN; {Example of useful leader: PIP A:} WRITE ('LEADER? '); READLN (LEADER); {Example of useful trailer: =B:} WRITE ('TRAILER? '); READLN (TRAILER); {Write out the results} ASSIGN (FILEOUT, 'FILES.SUB'); REWRITE (FILEOUT); FOR I := 1 TO NSTOR DO WRITELN (FILEOUT, LEADER, STORE[I].NAME, TRAILER); CLOSE (FILEOUT, I); WRITELN ('Results are in FILES.SUB on the currently logged in disk.'); END.