PROGRAM PDIR; {$R+ $V+ $K+ } TYPE byte4 = ARRAY [1..4] OF BYTE; txt = STRING[255]; ENTRY = RECORD filename : ARRAY[1..8] OF BYTE; ext : ARRAY[1..3] OF BYTE; attr : BYTE; reserve : ARRAY[1..10] OF BYTE; cr_time : INTEGER; cr_date : INTEGER; fat_start : INTEGER; file_size : byte4; END; dir_type = ARRAY [1..16] OF entry; TYPE standardarray = ARRAY[1..512] OF STRING[8]; TYPE pointarray = ARRAY[1..512] OF INTEGER; VAR fat_fill : ARRAY[0..4095] OF BYTE; dir : dir_type; pointer : pointarray; cluster : ARRAY [1..50] OF INTEGER; father,son : ARRAY [0..50] OF BYTE; i,j,k : INTEGER; hour,min,sec, month,day,date : BYTE; year : INTEGER; side,track,sector : BYTE; no_dir : INTEGER; no_words : INTEGER; no_entry : INTEGER; no_lines,no_max : INTEGER; dir_name : ARRAY[1..50] OF STRING[50]; dir_root : STRING[20]; dir_num,dir_point : INTEGER; parent : INTEGER; size : REAL; drive,cl_size, no_sect, first_clust, no_side : BYTE; first_dir : BYTE; no_root : REAL; file_name : standardarray; ext_name : ARRAY [1..512] OF STRING[3]; fn_time : ARRAY [1..512] OF INTEGER; fn_date : ARRAY [1..512] OF INTEGER; fn_size : ARRAY [1..512] OF byte4; vol_id : STRING[11]; one_on,want_border : BOOLEAN; want_hidden : BOOLEAN; want_dir : BOOLEAN; want_deleted : BOOLEAN; compressed : BOOLEAN; response : INTEGER; alpha : STRING[1]; drive_no : INTEGER; border : STRING[80]; top_border : STRING[80]; left_border : STRING[5]; right_border : STRING[5]; side_border : STRING[1]; outfil_name : STRING[20]; outfil : TEXT; ff,comp,EXP, LL8,cancel : STRING[2]; short : STRING[3]; free_clusters : INTEGER; total_clusters : INTEGER; free_space : REAL; total_size : REAL; {$i biosread.inc} {$i getfree.inc} {$i getdate.inc} PROCEDURE getfntime(VAR hour,min,sec :BYTE ; cr_time:INTEGER); VAR scratch : INTEGER; BEGIN scratch := cr_time SHR 5; min := scratch MOD 64; hour := scratch DIV 64; sec := abs(cr_time) MOD 32; sec := sec * 2; END; PROCEDURE getfndate(VAR year: INTEGER; VAR month,day :BYTE; cr_date:INTEGER); BEGIN year := 80 + (cr_date DIV 512); month:= (cr_date MOD 512) DIV 32; day := cr_date MOD 32; END; PROCEDURE getfnsize(VAR size:REAL; file_size:byte4); BEGIN size := file_size[1]; size := size + 256.*file_size[2]; size := size + 65536.*file_size[3]; size := size + 256.*65536.*file_size[4]; END; FUNCTION fill_string(char_fill: txt ; no_char:BYTE): txt; VAR i : INTEGER; newstring : txt; BEGIN newstring := ''; FOR i := 1 TO no_char DO newstring := CONCAT(newstring,char_fill); fill_string := newstring; END; FUNCTION concatc(VAR chars; no_char:BYTE): txt; TYPE ch_array = ARRAY[1..255] OF BYTE; VAR i : INTEGER; newchars : ch_array ABSOLUTE chars; newstring : txt; BEGIN newstring := ''; FOR i := 1 TO no_char DO newstring := CONCAT(newstring,CHR(newchars[i])); concatc := newstring; END; PROCEDURE read_dir (VAR dir:dir_type; clust1 :INTEGER ; no_cluster:REAL); VAR lend : BOOLEAN; clust : INTEGER; fat_cluster,fat_offset : INTEGER; BEGIN no_words:= 0; clust := clust1; lend := FALSE; i := 0; WHILE NOT lend DO BEGIN i := i + 1; sector := clust MOD no_sect + 1; side := (clust DIV no_sect) MOD no_side; track := clust DIV (no_side*no_sect); biosread(dir[1],drive,side,track,sector,1); FOR j := 1 TO 16 DO BEGIN WITH dir[j] DO BEGIN IF filename[1] = $00 THEN lend := TRUE; IF (filename[1] <> $00) AND ( (filename[1] <> $e5) OR want_deleted ) THEN BEGIN IF ( ( (attr AND 2) <> 2) OR want_hidden ) AND ( ( (attr AND 16) <> 16) OR want_dir) AND ( ( (attr AND 8) <> 8) OR want_dir) THEN BEGIN no_words := no_words+1; file_name[no_words] :=concatc(filename,8); ext_name[no_words] :=concatc(ext,3); fn_time[no_words] := cr_time; fn_date[no_words] := cr_date; fn_size[no_words] := file_size; END; IF ( (attr AND 8) = 08) THEN BEGIN vol_id := CONCAT( concatc(filename,8) , concatc(ext,3) ); WRITE(outfil,left_border,EXP, ' VOLUME NAME IS: ',VOL_ID); IF LENGTH(cancel) <> 0 THEN WRITELN(outfil,cancel,right_border:18) ELSE WRITELN(outfil,right_border:43); no_lines := no_lines + 1; END; IF ( (attr AND 16) = 16) AND (CHR(filename[1]) <> '.') AND ( filename[1] <> $e5 ) THEN BEGIN dir_num := dir_num + 1; dir_name[dir_num] := dir_name[parent] + concatc(filename,8) + '\' ; father[dir_num] := parent; IF son[parent] = 0 THEN son[parent] := dir_num; cluster[dir_num] := fat_start*cl_size + first_clust; END; END; { good entries} END; {all entries} END; {directory loop} clust := clust + 1; IF ( i >= (no_cluster*cl_size) ) AND (no_cluster = 1.0) THEN BEGIN clust1 := (clust1 - first_clust) DIV cl_size; fat_offset := (clust1*3) DIV 2; IF clust1 MOD 2 = 0 THEN fat_cluster := fat_fill[fat_offset] + ( (fat_fill[fat_offset+1] MOD 16 ) * 256) ELSE fat_cluster := (fat_fill[fat_offset] SHR 4 ) + (fat_fill[fat_offset+1] * 16); IF fat_cluster > $ff0 THEN lend := TRUE ELSE BEGIN clust1 := fat_cluster*cl_size + first_clust; clust := clust1; i := 0; END; END; END; {lend} END; {read_dir} PROCEDURE SWAP( VAR a,b: INTEGER ); VAR t: INTEGER; BEGIN t := a; a := b; b := t END; PROCEDURE bsort( start, top: INTEGER; VAR arry: standardarray; VAR pointer: pointarray ); {bubble sort procedure. sorts array from start to top inclusive} VAR index: INTEGER; switched: BOOLEAN; BEGIN {bsort} REPEAT switched := FALSE; FOR index := start TO top-1 DO BEGIN IF arry[pointer[index]] > arry[pointer[index+1]] THEN BEGIN SWAP( pointer[index] , pointer[index+1] ); switched := TRUE; END END; UNTIL switched = FALSE; END; {bsort} PROCEDURE findmedian( start, top: INTEGER; VAR arry: standardarray; VAR pointer : pointarray ); {procedure to find a good median value in array and place it} VAR middle: INTEGER; sorted: ARRAY [1..3] OF STRING[8]; BEGIN {findmedian} middle := (start + top) DIV 2; sorted[1] := arry[pointer[start]]; sorted[2] := arry[pointer[top]]; sorted[3] := arry[pointer[middle]]; IF (sorted[2] > sorted[1]) AND (sorted[2] < sorted[3]) THEN SWAP( pointer[start], pointer[middle] ) ELSE IF (sorted[3] > sorted[1]) AND (sorted[3] < sorted[2]) THEN SWAP( pointer[start], pointer[top] ); END; {findmedian} PROCEDURE sortsection( start, top: INTEGER; VAR arry: standardarray; VAR pointer : pointarray); {procedure to sort a section of the main array, and } {then divide it into two partitions to be sorted } VAR swapup: BOOLEAN; s,e,m: INTEGER; BEGIN {sortsection} IF top - start < 6 THEN {sort small sections with bsort} bsort( start, top, arry , pointer ) ELSE BEGIN findmedian( start, top, arry , pointer ); swapup := TRUE; {start scanning from array top} s := start; {lower comparison limit} e := top; {upper comparison limit} m := start; {location of comparison value} WHILE e > s DO BEGIN IF swapup = TRUE THEN {scan downward from partition top} {and exchange if smaller than median} BEGIN WHILE( arry[pointer[e]] >= arry[pointer[m]] ) AND (e > m) DO e := e - 1; IF e > m THEN BEGIN SWAP( pointer[e], pointer[m] ); m := e; END; swapup := FALSE; END ELSE {scan upward from a partition start} {and exchange if larger than median} BEGIN WHILE( arry[pointer[s]] <= arry[pointer[m]] ) AND (s < m) DO s := s + 1; IF s < m THEN BEGIN SWAP( pointer[s], pointer[m] ); m := s; END; swapup := TRUE; END END; {sort lower half of partition} sortsection( start, m-1, arry , pointer ); {sort upper half of partition} sortsection( m+1, top, arry , pointer); END END; {sortsection} PROCEDURE sort_dir (VAR file_name:standardarray; no_words:INTEGER); BEGIN {qsort - main program} FOR i := 1 TO no_words DO pointer[i] := i; sortsection( 1, no_words , file_name , pointer ); no_entry := (no_words+1) DIV 2; IF no_lines + no_entry + 6 > no_max THEN BEGIN FOR i := no_lines TO no_max-1 DO IF want_border THEN WRITELN(outfil,border); no_lines := 0; IF want_border THEN WRITELN(outfil,top_border); CLRSCR; WRITE(outfil,ff); IF want_border THEN WRITELN(outfil,top_border); END; WRITE(outfil,left_border,' ',EXP); WRITE(outfil,'Directory:',dir_name[dir_point], fill_string(' ',26-LENGTH(dir_name[dir_point]) )); IF LENGTH(cancel) <> 0 THEN WRITELN(outfil,cancel,right_border) ELSE WRITELN(outfil,right_border:45); WRITELN(outfil,border); WRITELN(outfil,border); total_size := 0; FOR j := 1 TO no_entry DO BEGIN WRITE(outfil,left_border); FOR i := 0 TO 1 DO BEGIN IF j+i*no_entry <= no_words THEN BEGIN k := pointer[j+i*no_entry]; getfntime(hour,min,sec,fn_time[k]); getfndate(year,month,day,fn_date[k]); getfnsize(size,fn_size[k]); total_size := total_size + (cl_size*512) * INT( size/(cl_size*512) + 0.99 ); IF (size = 0) AND ( POS('.',file_name[k]) <> 1 ) THEN total_size := total_size + cl_size*512; WRITE(outfil,file_name[k],'.', ext_name[k]); WRITE(outfil,' ',month:2,'/',day:2,'/',year:2, ' ',hour:2,':',(min DIV 10):1,(min MOD 10):1, size:7:0); IF i = 0 THEN WRITE(outfil,' '); END ELSE WRITE(outfil,' ':35); END; WRITELN(outfil,right_border); END; WRITELN(outfil,left_border,' ':38,'TOTAL SIZE: ',' ':15, total_size:8:0,right_border); WRITELN(outfil,border); WRITELN(outfil,border); no_lines := no_lines + no_entry + 6; END; {qsort} PROCEDURE setup(drive_no:INTEGER); BEGIN comp := CHR(15); EXP := CHR(14); cancel := CHR(20); ff := CHR(12); LL8 := CHR(27)+CHR(48); short:= CHR(27)+'C'+CHR(44); IF NOT compressed THEN comp := ''; IF (outfil_name <> 'LPT1:') AND (outfil_name <> 'lpt1:') THEN BEGIN comp := ''; EXP := ''; cancel := ''; { ff := ''; GO AHEAD AND DO A FORM FEED } LL8 := ''; short := ''; END; IF (cl_size = 8) AND (drive_no = 3) THEN BEGIN {DOS 2.0/2 SIDE HARD DISK} drive := $80; { 80H } biosread(fat_fill,drive,0,0,3,8); no_sect := 17; { 17} no_root := 4; { 4} no_side := 4; { 4} cl_size := 8; { 8} first_clust := 34; { 34} first_dir := 18; { 18} END ELSE BEGIN drive := drive_no-1; {read FAT ...side 0, track 0, sector 2} biosread(fat_fill,drive,0,0,2,2); CASE fat_fill[0] OF {DOS 2.0/2 SIDE } $FD : BEGIN no_sect := 9; no_root := 3.5; no_side := 2; cl_size := 2; first_clust := 8; first_dir := 5; END; {DOS 1.1/2 SIDE } $FF : BEGIN no_sect := 8; no_root := 3.5; no_side := 2; cl_size := 2; first_clust := 7; first_dir := 3; END; {DOS 2.0/1 SIDE } $FC : BEGIN no_sect := 9; no_root := 2; no_side := 1; cl_size := 1; first_clust := 8; first_dir := 5; END; {DOS 1.1/1 SIDE } $FE : BEGIN no_sect := 8; no_root := 2; no_side := 1; cl_size := 1; first_clust := 7; first_dir := 3; END; ELSE END; END; one_on := FALSE; IF compressed THEN WRITE(outfil,comp,LL8,short); cluster[1] := first_dir; dir_name[1] := '\'; dir_num := 1; parent := 1; dir_point := 1; FOR i := 1 TO 50 DO BEGIN son[i] := 0; father[i] := 0; END; no_lines := 0; no_max := 60; IF compressed THEN no_max := 38; side_border := ' '; IF want_border THEN BEGIN no_max := no_max-2; side_border:= '|'; END; border := side_border + fill_string(' ',77) + side_border ; left_border := side_border + fill_string(' ',2) ; right_border := fill_string(' ',2) + side_border ; top_border := fill_string('-',79) ; IF want_border THEN WRITELN(outfil,top_border); free_space := free_clusters*(cl_size*512.0); WRITELN(outfil,left_border,' ':30,'Free: ',free_space:7:0,' ':19, month:2,'/',date:2,'/',year:2,' ',right_border); no_lines := no_lines + 1; END; PROCEDURE menu(VAR response:INTEGER); BEGIN CLRSCR; GOTOXY(10,3);WRITELN('1) Go'); GOTOXY(10,7);WRITELN('2) Change output defaults'); GOTOXY(10,11);WRITELN('3) Change file defaults'); GOTOXY(10,15);WRITELN('4) Stop'); GOTOXY(1,20);WRITELN('Output defaults: output to ',outfil_name, ' border ',want_border,' compressed ',compressed); GOTOXY(1,22);WRITELN('File defaults: Drive ',drive_no, ' show hidden ',want_hidden,' show deleted ',want_deleted, ' show dir ',want_dir); GOTOXY(15,24);WRITE('Enter option ');READLN(response); CLRSCR; END; PROCEDURE display_menu; BEGIN CLRSCR; GOTOXY(1,1);WRITELN('Output defaults: output to ',outfil_name, ' border ',want_border,' compressed ',compressed); GOTOXY(5,5) ; WRITE(' Output to: ');READLN(outfil_name); GOTOXY(5,8) ; WRITE(' Want border: ');READLN(alpha); IF LENGTH(alpha) <> 0 THEN want_border := (alpha = 'y') OR (alpha = 'Y'); GOTOXY(5,11) ; WRITE(' Compressed: ');READLN(alpha); IF LENGTH(alpha) <> 0 THEN compressed := (alpha = 'y') OR (alpha = 'Y'); CLRSCR; END; PROCEDURE file_menu; BEGIN CLRSCR; GOTOXY(1,1);WRITELN('File defaults: Drive ',drive_no, ' show hidden ',want_hidden,' show deleted ',want_deleted, ' show dir ',want_dir); GOTOXY(5,5) ; WRITE(' Drive: ');READLN(drive_no); GOTOXY(5,8) ; WRITE(' Show hidden files: ');READLN(alpha); IF LENGTH(alpha) <> 0 THEN want_hidden := (alpha = 'y') OR (alpha = 'Y'); GOTOXY(5,11) ; WRITE(' Show deleted files:');READLN(alpha); IF LENGTH(alpha) <> 0 THEN want_deleted:= (alpha = 'y') OR (alpha = 'Y'); GOTOXY(5,14) ; WRITE(' Show directories: ');READLN(alpha); IF LENGTH(alpha) <> 0 THEN want_dir := (alpha = 'y') OR (alpha = 'Y'); CLRSCR; END; BEGIN drive_no := 1; want_border := TRUE; compressed := TRUE; want_hidden := TRUE; want_deleted := FALSE; want_dir := FALSE; outfil_name := 'LPT1:'; response := 1; WHILE response <> 4 DO BEGIN menu(response); IF response = 2 THEN display_menu; IF response = 3 THEN file_menu; IF response = 1 THEN BEGIN ASSIGN(outfil,outfil_name); REWRITE(outfil); get_free_space(free_clusters,total_clusters,cl_size,drive_no); getdate(year,month,date,hour,min) ; year := year - 1900; setup(drive_no); read_dir (dir,cluster[1],no_root); sort_dir (file_name,no_words); WHILE parent <> 0 DO BEGIN IF son[parent] <> 0 THEN BEGIN { step down to son } dir_point := son[parent]; parent := dir_point; read_dir (dir,cluster[parent],1.0); sort_dir (file_name,no_words); END { then begin } ELSE BEGIN WHILE (son[parent] = 0) AND (parent <> 0) DO BEGIN { move to next son; or pop to parent } parent := father[dir_point]; IF father[dir_point+1] = parent THEN son[parent] := dir_point + 1 ELSE IF parent <> 0 THEN son[parent] := 0; dir_point := parent; END; { move to next son; or pop to parent } END; { else begin } END; { while parent <> 0 } FOR i := no_lines TO no_max-1 DO IF want_border THEN WRITELN(outfil,border); no_lines := 0; IF want_border THEN WRITELN(outfil,top_border); { CLRSCR; } WRITE(outfil,ff); CLOSE(outfil); END; END; end.