home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1995 November
/
PCWK1195.iso
/
inne
/
podstawy
/
dos
/
4dos
/
4uzytki
/
4utils86.exe
/
4FF.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-07-09
|
18KB
|
555 lines
PROGRAM FileFind;
{$A+,B-,D-,E-,F-,G+,I-,L+,N-,O-,R-,S-,V-,X-}
{$M 16384,0,655360}
(* ----------------------------------------------------------------------
A 4DOS-aware file finder. It searches in various archives too.
(c) 1992, 1994 Copyright by David Frey,
Urdorferstrasse 30
8952 Schlieren ZH
Switzerland
Code created using Turbo Pascal 6.0 (c) Borland International 1990
DISCLAIMER: This program is freeware: you are allowed to use, copy
and change it free of charge, but you may not sell or hire
4FF. The copyright remains in my hands.
If you make any (considerable) changes to the source code,
please let me know. (send me a copy or a listing).
I would like to see what you have done.
I, David Frey, the author, provide absolutely no warranty of
any kind. The user of this software takes the entire risk of
damages, failures, data losses or other incidents.
NOTES: Turbo Pascal 6.0 required for compiling. (sorry, but I'm
using FormatStr for output)
ENHANCEMENTS: adapted to 4DOS 4.01 - when redirecting into files,
full descriptions will be shown, otherwise the
descriptions will be truncated at the right screen margin.
paging switch (/p) added.
Fast screen output when no redirected output has been used.
Searches for Read Only / Hidden directories, too.
ARJ File scanning added.
Supports now 4DOS 5.0, i.e. 200 characters description
length.
Old /d switch renamed to /f. /d stands now for description.
----------------------------------------------------------------------- *)
USES {$IFOPT G+} Test286, {$ENDIF}
Fix, Crt, Dos, Objects, Memory, Drivers,
StringDateHandling, DisplayKeyboardAndCursor, DescriptionHandling,
HandleINIFile,
ScanLZHFiles, ScanZIPFiles, ScanARJFiles, Globals;
CONST Header= '4FF 4DOS File Find 1.86 -- (c) David Frey 1992, 1995';
VAR ActDir, StartDir : STRING;
FileSpecArray : FileSpecArrayType;
DescFile : TEXT;
DescLine : STRING;
DescLineNr : WORD;
Desc : DescStr;
DescStart : BYTE;
DescEnd : BYTE;
DescFound : BOOLEAN;
i,l : WORD;
k : BYTE;
FileSpecs : BYTE;
ps,fs : STRING;
IORes : INTEGER;
Templ : STRING;
FormatTemplate : STRING;
OldCtrlBreakHandler : POINTER;
OldCtrlBreakState : BOOLEAN;
BrokeOut : BOOLEAN;
PROCEDURE MyCtrlBreakHandler; FAR;
BEGIN
ExitProc := OldCtrlBreakHandler; SetCBreak(OldCtrlBreakState);
{$I-}
ChDir(ActDir); IORes := IOResult;
IF BrokeOut THEN
BEGIN
WriteLn(Output);
WriteLn(Output,' EXITING - User broke out of program.');
WriteLn(Output);
END;
Close(Output);
IF NOT Redirected THEN NormVideo;
END;
PROCEDURE ShowFileData(Item: PFileData; VAR Path: PathStr);
VAR Index: INTEGER;
Date : DateStr;
Time : TimeStr;
BEGIN
IF BareOutput THEN
WriteLn(Output,Path,'\',Item^.Name)
ELSE
BEGIN
IF FileCount = 0 THEN
BEGIN
WriteLn(Output); IF DoPage THEN TestForMoreMsg;
WriteLn(Output,Path,'\'); IF DoPage THEN TestForMoreMsg;
END;
InfoArray[0] := @Item^.Name;
InfoArray[1] := @Item^.Ext;
IF Item^.Attr AND Directory = Directory THEN SizeStr := '<DIR>'
ELSE
SizeStr := FormattedLongIntStr(Item^.Size,10);
InfoArray[2] := @SizeStr;
Date := FormDate(Item^.DateRec); InfoArray[3] := @Date;
Time := FormTime(Item^.DateRec); InfoArray[4] := @Time;
AttrStr := '....';
IF Item^.Attr AND ReadOnly = ReadOnly THEN AttrStr[1] := 'r';
IF Item^.Attr AND Hidden = Hidden THEN AttrStr[2] := 'h';
IF Item^.Attr AND SysFile = SysFile THEN AttrStr[3] := 's';
IF Item^.Attr AND Archive = Archive THEN AttrStr[4] := 'a';
InfoArray[5] := @AttrStr;
InfoArray[6] := Item^.Desc;
FormatStr(s,FormatTemplate,InfoArray);
WriteLn(Output,s); IF DoPage THEN TestForMoreMsg;
INC(TotalSize,Item^.Size); INC(DirSize,Item^.Size);
INC(TotalFileCount); INC(FileCount);
END;
END; (* ShowFileData *)
PROCEDURE BuildList(Dir: DirStr; VAR FileSpec: FileSpecArrayType; FileSpecs: BYTE;
Attr: BYTE);
(* The starting point, dir, includes the drive *)
VAR Search: SearchRec;
DescFileExists: BOOLEAN;
DescFileList : PFileList;
l,i,k : BYTE;
PROCEDURE ExamineFile(Item: POINTER); FAR;
(* Print the file data, if the Attributes match *)
BEGIN
IF (((searchdesc = '') AND
(NOT ExactAttr OR
(ExactAttr AND (PFileData(Item)^.Attr = Attr)))) OR
(Pos(searchdesc,PFileData(Item)^.Desc^) > 0)) THEN
ShowFileData(PFileData(Item),Dir);
END;
BEGIN (* BuildList *)
FileCount := 0; DirSize := 0;
Attr := Attr AND NOT Directory AND NOT VolumeId;
OldLHFileName := ''; OldZipFileName := '';
s := Dir; l := Length(s);
IF (l>3) AND (s[l] = '\') THEN Delete(s,l,1);
l := Length(Dir); IF (s[l] = '\') THEN Delete(Dir,l,1);
{$I-}
ChDir(s); IORes := IOResult;
{$I+}
FOR k := 1 TO FileSpecs DO
BEGIN
DescFileList := NIL; DescFileList := New(PFileList,Init(Dir,FileSpec[k],0));
IF DescFileList = NIL THEN Abort('Unable to allocate DescFileList');
IF (FileList^.Status = ListTooManyFiles) OR
(FileList^.Status = ListOutofMem) THEN
BEGIN
IF FileList^.Status = ListTooManyFiles THEN
WriteLn('Warning! Too many files in directory, description file will be truncated!')
ELSE
WriteLn('Warning! Out of memory, description file will be truncated!');
END;
IF DescLong THEN
WriteLn('Warning! Some descriptions are too long; they will be truncated.');
DescFileList^.ForEach(@ExamineFile);
Dispose(DescFileList,Done);
END;
IF ScanLZHArchives THEN
BEGIN
FindFirst('????????.LZH',ReadOnly+Archive,Search);
WHILE DosError = 0 DO
BEGIN
SearchInLZHFile(FileSpec,FileSpecs,Dir,Search);
FindNext(Search);
END;
END;
IF ScanZIPArchives THEN
BEGIN
FindFirst('????????.ZIP',ReadOnly+Archive,Search);
WHILE DosError = 0 DO
BEGIN
SearchInZIPFile(FileSpec,FileSpecs,Dir,Search);
FindNext(Search);
END;
END;
IF ScanARJArchives THEN
BEGIN
FindFirst('????????.ARJ',ReadOnly+Archive,Search);
WHILE DosError = 0 DO
BEGIN
SearchInARJFile(FileSpec,FileSpecs,Dir,Search);
FindNext(Search);
END;
END;
IF NOT BareOutput AND (FileCount > 0) THEN
BEGIN
Templ := '%-4s entr';
IF FileCount = 1 THEN Templ := Templ + 'y, '
ELSE Templ := Templ + 'ies,';
Templ := Templ+' %10s Bytes';
FileStr := FormattedIntStr(FileCount,4); InfoArray[0] := @FileStr;
SizeStr := FormattedLongIntStr(DirSize,10); InfoArray[1] := @SizeStr;
FormatStr(s,Templ,InfoArray);
WriteLn(Output,s); IF DoPage THEN TestForMoreMsg;
END;
FindFirst('????????.???',Directory+ReadOnly+Hidden+SysFile,Search);
WHILE DosError = 0 DO
BEGIN
IF (Search.Attr AND Directory = Directory) AND
(Search.Name <> '.') AND (Search.Name <> '..') THEN
BuildList(Dir+'\'+Search.Name+'\',FileSpec,FileSpecs,Attr);
FindNext(Search);
END;
{$I-}
ChDir('..'); IORes := IOResult;
{$I+}
END; (* BuildList *)
FUNCTION DriveValid(C: CHAR): BOOLEAN; ASSEMBLER;
ASM
MOV DL,C
SUB DL,'A'-1
MOV AH,36H
Int 21H
INC AX
JE @@2
MOV AL,1
@@2:
END; (* DriveValid *)
FUNCTION DiskInDrive(C: CHAR): BOOLEAN; ASSEMBLER;
ASM
PUSH DS
MOV DL,C
SUB DL,'A'-1
MOV AH,1cH (* Get Drive Data, AL: Sec/Cluster, FF=drive empty ... *)
Int 21H
INC AX
JZ @@1
MOV AL,1
@@1:
POP DS
END;
FUNCTION DskExist(CONST D : CHAR) : BOOLEAN;
(* True if (physical) diskette drive D is present *)
(* BIOS numbering: 0=A: 1=B: *)
VAR Regs: Registers;
BB : Word;
BEGIN
Intr($11, Regs);
BB := 1 + (Byte(D)-65) SHL 6;
IF (Regs.AX AND BB) = BB THEN DskExist := True
ELSE DskExist := False;
END; (* DskExist *)
FUNCTION A_ReMapped: BOOLEAN;
(* True if A: is remapped to B: *)
VAR Regs: Registers;
BEGIN
WITH Regs DO
BEGIN
AX := $440E;
BL := 1;
MsDos(Regs);
IF ((Flags AND fCarry) = 0) AND (AL = 2) THEN A_ReMapped := True
ELSE A_ReMapped := False;
END;
END; (* A_ReMapped *)
PROCEDURE GiveHelp;
BEGIN
WriteLn(Output);
WriteLn(Output,Header);
WriteLn(Output);
WriteLn(Output,'This program is freeware: you are allowed to use, copy it free');
WriteLn(Output,'of charge, but you may not sell or hire 4FF.');
WriteLn(Output);
WriteLn(Output,'usage: 4FF [/a:[-]rash][/zx][/s][/b][/ddesc][/f][/m:nn][/?] [start dir\]{filenames}');
WriteLn(Output);
WriteLn(Output,' /a:rash search for files with these attributes set.');
WriteLn(Output,' /zx archive type x, x is one of the following:');
WriteLn(Output,' : all archives');
WriteLn(Output,' - : no archives');
WriteLn(Output,' a : add ARJ archives.');
WriteLn(Output,' l : add LZH archives.');
WriteLn(Output,' z : add ZIP archives.');
WriteLn(Output,' /s scan only subdirectories of given path `start-dir''');
WriteLn(Output,' /b bare listing (omits size, date, and descriptions)');
WriteLn(Output,' /ddesc list files with description desc');
WriteLn(Output,' /f scan all drives (floppy drives included)');
WriteLn(Output,' /x scan all fixed drives');
WriteLn(Output,' /m:nn set right margin to nn');
WriteLn(Output,' /p page output');
WriteLn(Output,' /? this help display.');
HALT;
END; (* GiveHelp *)
BEGIN
GetCBreak(OldCtrlBreakState); SetCBreak(FALSE);
OldCtrlBreakHandler := ExitProc; ExitProc := @MyCtrlBreakHandler;
BrokeOut := FALSE;
GetDir(0,ActDir);
ps := DownStr(ParamStr(1));
IF ps[1] = '/' THEN ps[1]:= '-';
IF (ps = '-?') OR (ps = '-h') THEN GiveHelp;
IF TextRec(Output).Name[0] <> #0 THEN
BEGIN
Str(DescLen,DescTempl); DescTempl := '%-'+DescTempl+'s';
END;
BareOutput := FALSE; ExactAttr := FALSE;
SubDirectories := FALSE; AllDrives := FALSE;
ScanARJArchives := TRUE; ScanLZHArchives := TRUE; ScanZIPArchives := TRUE;
FileSpecArray[1]:= '*.*'; FileSpecs := 1; StartDir := ''; searchdesc := '';
FormatTemplate := '%-8s%4s %10s '+DateTempl+' '+TimeTempl+' %4s '+DescTempl;
i := 1; l := 0; k := 0;
REPEAT
ps := ParamStr(i);
IF ps[1] = '/' THEN ps[1] := '-';
IF ps[1] = '-' THEN
BEGIN
s := Copy(ps,2,255);
(* Case sensitive options: *)
IF (s[1] = 'd') THEN
BEGIN
searchdesc := Copy(s,2,255);
ScanARJArchives := FALSE; ScanLZHArchives := FALSE; ScanZIPArchives := FALSE;
END;
(* Case insensitive options: *)
DownString(s);
IF NOT SubDirectories THEN SubDirectories := (s='s');
IF NOT BareOutput THEN BareOutput := (s='b');
IF NOT FixedDrives THEN FixedDrives := (s='x');
IF NOT AllDrives THEN AllDrives := (s='f');
IF NOT DoPage AND NOT Redirected THEN DoPage := (s='p');
IF s[1] = 'a' THEN
BEGIN
s := Copy(s,Pos(':',s)+1,255);
Attr := 0; AttrStr := '....'; ExactAttr := TRUE;
IF (Pos('r',s) > 0) AND (Pos('-r',s) = 0) THEN BEGIN INC(Attr,ReadOnly); AttrStr[1] := 'r'; END;
IF (Pos('h',s) > 0) AND (Pos('-h',s) = 0) THEN BEGIN INC(Attr,Hidden ); AttrStr[2] := 'h'; UseHidden := TRUE; END;
IF (Pos('s',s) > 0) AND (Pos('-s',s) = 0) THEN BEGIN INC(Attr,SysFile ); AttrStr[3] := 's'; END;
IF (Pos('a',s) > 0) AND (Pos('-a',s) = 0) THEN BEGIN INC(Attr,Archive ); AttrStr[4] := 'a'; END;
ScanARJArchives := FALSE; ScanLZHArchives := FALSE; ScanZIPArchives := FALSE;
END;
IF s[1] = 'm' THEN
BEGIN
Delete(ps,1,3); Val(ps,k,IORes);
MaxViewLength := k-31-Length(DateFormat)-Length(TimeFormat);
Str(MaxViewLength,DescTempl); DescTempl := '%-'+DescTempl+'s';
END;
IF (s[1] = 'z') AND (Length(s) > 1) THEN
FOR k := 1 TO Length(s)-1 DO
IF s[1+k] = '-' THEN
BEGIN
ScanARJArchives := FALSE;
ScanLZHArchives := FALSE;
ScanZIPArchives := FALSE;
END
ELSE
IF (s[1+k] = 'a') THEN ScanARJArchives := TRUE
ELSE
IF (s[1+k] = 'l') THEN ScanLZHArchives := TRUE
ELSE
IF (s[1+k] = 'z') THEN ScanZIPArchives := TRUE;
INC(l);
END;
INC(i);
UNTIL (i>ParamCount) OR (ps[1] <> '-');
(* Read the .INI files *)
InitMemory;
INIStrings := New(PINIStrings,Init); (* Read in the .INI file(s) *)
IF INIFileExists THEN StringDateHandling.EvaluateINIFileSettings;
(* The Date & Time Formats are country-specific and are pre-initialized
in the StringDateHandling initialize-section. Re-Initializing it
with "our" defaults is not what the users wants. *)
DescriptionHandling.EvaluateINIFileSettings;
DisplayKeyboardAndCursor.EvaluateINIFileSettings;
StartDir := '';
IF l < ParamCount THEN
BEGIN
FOR i := l+1 TO ParamCount DO
BEGIN
FSplit(ParamStr(i),Path,Name,Ext);
IF (Path <> '') AND (StartDir = '') THEN
BEGIN StartDir := UpStr(Path); SubDirectories := TRUE; END;
IF Name = '' THEN Name := '*';
IF Ext = '' THEN Ext := '.*';
FileSpecArray[i-l] := Name+Ext; DownString(FileSpecArray[i-l]);
END;
FileSpecs := ParamCount-l;
END;
IF StartDir = '' THEN StartDir := ActDir;
IF NOT SubDirectories THEN StartDir := Copy(StartDir,1,3);
IF NOT BareOutput THEN
BEGIN
WriteLn(Output,Header);
WriteLn(Output);
WriteLn(Output,'This program is freeware: you are allowed to use,');
WriteLn(Output,'copy it free of charge, but you may not sell or hire 4FF.');
WriteLn(Output);
IF FileSpecs = 1 THEN WriteLn(Output,'Filename = ',FileSpecArray[1],'.')
ELSE
BEGIN
Write(Output, 'Filenames = ');
FOR i := 1 TO FileSpecs DO
BEGIN
Write(Output,FileSpecArray[i]);
IF i < FileSpecs THEN Write(Output,', ')
ELSE WriteLn(Output,'.');
END;
END;
IF AllDrives THEN WriteLn(Output,'Scanning all drives.')
ELSE
BEGIN
IF FixedDrives THEN WriteLn(Output,'Scanning fixed drives.')
ELSE
BEGIN
Write(Output,'Path ');
IF Filespecs > 1 THEN Write(Output, ' ');
WriteLn('= ',StartDir);
END;
END;
IF searchdesc <> '' THEN
WriteLn(Output,'Searching for descriptions containing the string ''',searchdesc,'''');
Line := 7;
IF ExactAttr THEN
BEGIN
WriteLn(Output,'Attributes= ',AttrStr); INC(Line);
END;
END;
IF ScanLZHArchives OR ScanZIPArchives OR ScanARJArchives THEN InstallBuffer;
IF BareOutput THEN Justify := Left;
TotalFileCount := 0; TotalSize := 0; BrokeOut := TRUE;
IF (NOT AllDrives) AND (NOT FixedDrives) THEN
BEGIN
l := Length(StartDir);
IF (l > 3) AND (StartDir[l] = '\') THEN Delete(StartDir,l,1);
BuildList(StartDir,FileSpecArray,FileSpecs,Attr)
END
ELSE
BEGIN
IF AllDrives THEN
BEGIN
IF DskExist('B') THEN
BEGIN
FOR Drive := 'A' TO 'B' DO
IF DiskInDrive(Drive) THEN
BuildList(Drive+':\',FileSpecArray,FileSpecs,Attr)
END
ELSE
BEGIN
IF A_ReMapped THEN Drive := 'B'
ELSE Drive := 'A';
IF DiskInDrive(Drive) THEN
BuildList(Drive+':\',FileSpecArray,FileSpecs,Attr)
END;
END;
IF FixedDrives OR AllDrives THEN
FOR Drive := 'C' TO 'Z' DO
IF DriveValid(Drive) AND DiskInDrive(Drive) THEN
BuildList(Drive+':\',FileSpecArray,FileSpecs,Attr);
END;
BrokeOut := FALSE;
IF NOT BareOutput THEN
BEGIN
IF TotalFileCount = 0 THEN s := 'no files found.'
ELSE
BEGIN
Templ := '%6s file';
IF TotalFileCount = 1 THEN Templ := Templ +', '
ELSE Templ := Templ +'s,';
Templ := Templ+'%11s Bytes';
FileStr := FormattedIntStr(TotalFileCount,6); InfoArray[0] := @FileStr;
SizeStr := FormattedLongIntStr(TotalSize,11); InfoArray[1] := @SizeStr;
FormatStr(s,Templ,InfoArray);
END;
WriteLn(Output,'------------------------------------------------'); IF DoPage THEN TestForMoreMsg;
WriteLn(Output,s); IF DoPage THEN TestForMoreMsg;
END;
IF ScanLZHArchives OR ScanZIPArchives OR ScanARJArchives THEN FreeBuffer;
DoneMemory;
END.