File: filefind.pas

package info (click to toggle)
lazarus 2.0.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 214,460 kB
  • sloc: pascal: 1,862,622; xml: 265,709; cpp: 56,595; sh: 3,008; java: 609; makefile: 535; perl: 297; sql: 222; ansic: 137
file content (300 lines) | stat: -rw-r--r-- 10,107 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
unit FileFind;
{
     This component performs file search with or without recursing subfolders,
     with events generated on file match and on change scanning folder.
     Written in Delphi3, but I suppose it will work on Delphi1 and Delphi2 also
     Version 1.0

     // following 3 Additions by David R Hazlehurst 4/6/98 (drarh@tcp.co.uk)
     TStringList to store list of files found. (called "FilesFound")
     Support for multiple wildcards in the one search. (SearchFile property)
     Added flag to indicate if searching already or not.

     Properties:
         property Stop : boolean - Set to true if you want to cancel searching.
	 property SearchFile : shortstring - Set starting path and file mask for searching (e.g. "c:\*.doc").
         property RecurseSubFolders : boolean - Do recursing or not.
         property FilesFound : TStringList - drh : list of files found (read only)
         property Searching : boolean - drh : Indicates if a search is in progress (read only)
     Event handlers:
         property OnFileFind : TFindFileEvent - On match found
         property OnChangeFolder : TChangeFolderEvent - On change folder
	 property OnFinish : TNotifyEvent - On end of searching
     Methods:
         procedure Start; - Start searching.

     This component is freeware.
     I guarantee you nothing concering this code, but you can use it as you wish.

     Happy coding

     This component is dedicated to the girl I love... B.

     Jem Naadi Ahmed
     Bulsoft
     Bulgaria
     25 May, 1998

     jemna@yahoo.com
     Any comments will be welcome.

     /////////////////////////////////////////////////////////////////////////////
     // Following changes by David R Hazlehurst (drarh@tcp.co.uk) 4th June 1998
     /////////////////////////////////////////////////////////////////////////////
     Reformatted some of the layout to suit my style (indents, tabs, spacing, etc).

     Create contructor moved to "public" block of type def.

     Added property to store list of files found ("FilesFound").
     This makes it easier for the user of the control to get the list info.

     Added code to create string list in contructor
     Added destructor event to handle destruction of string list created within the create event

     Added a public "Searching" flag to indicate if search is already underway.  This will
     not prevent you from calling "start" again, but does provide a means of checking to see
     if the user already started searching.  You can then decide if you want to start a new
     search.  Another reason for making this optional rather than stopping you from searching
     outright, is in case an error occurs while searching and you may not get past the search
     block.  Of course, you can add a block to the code if you really want it.

     Improved the "start" procedure as follows:
              the "SearchFile" parameter can now accept multiple wildcards to search
              for more than one file type.  Each wildcard is sepearted by ";" as per
              the shell.  Each type is searched in order given.  So, for example:

                  SearchFile := 'c:\*.bat;*.sys'

              could return "c:\autoexec.bat" and "c:\config.sys", as well as others.


     end of my list.

     Im not claiming ideal solutions here, they were just the first things that
     occurred to me (from my requirements), and hey, they work.  By all means, improve
     on my "improvements" if you wish.  I would also be interested in the results.
     /////////////////////////////////////////////////////////////////////////////

     29.11.2004 - ported to FPC/lazarus by barko, OPINFOS d.o.o.

}

interface

uses LResources,
     SysUtils, Classes, LazFileUtils, Graphics, Controls, Forms, Dialogs;

type
    TFindFileEvent = procedure(fullpath:string;info:TSearchRec)of object;
    TChangeFolderEvent = procedure(fullpath:string;info:TSearchRec)of object;

    TFileSearch = class(TComponent)
    private
	{ Private declarations }
	fRec : boolean;
	fStop : boolean;
        fSearching : boolean;
        fFilesFound : TStringList;
	fFileFindEvent : TFindFileEvent;
	fChangeFolderEvent : TChangeFolderEvent;
	fFinishEvent : TNotifyEvent;
	fdirName : shortstring;
    protected
	{ Protected declarations }
	procedure ScanDir(ffdirName:string;attr:word);

    public
    	{ Public declarations }
        constructor Create(aOwner:TComponent); override;
        destructor Destroy; override;

	procedure Start;

        property Searching : boolean read fSearching;

    published
	{ Published declarations }
	property Stop : boolean read fStop write fStop default false;
	property SearchFile : shortstring read fdirName write fdirName;
        property FilesFound : TStringList read fFilesFound;
	property RecurseSubFolders : boolean read fRec write fRec default true;
	property OnFileFind : TFindFileEvent read fFileFindEvent write fFileFindEvent;
	property OnChangeFolder : TChangeFolderEvent read fChangeFolderEvent write fChangeFolderEvent;
	property OnFinish : TNotifyEvent read fFinishEvent write fFinishEvent;
    end;

const
    {$IFNDEF LINUX} // barko
    delimeter = '\';
    {$ELSE}
    delimeter = '/';
    {$ENDIF} // barko


procedure Register;

implementation

{$R filefind.res}

procedure Register;
begin
     RegisterComponents('Samples', [TFileSearch]);
end;

constructor TFileSearch.Create(aOwner:TComponent);
begin
      inherited create(aOwner);

      fFilesFound := TStringList.Create;     // drh 4/6/98: Create results list
      fRec := true;
      fSearching := false;                   // drh 4/6/98: Initialise "Searching" flag
      fStop := false;
end;

// drh 4/6/98: Added destructor handler
destructor TFileSearch.Destroy;
begin
     fFilesFound.Free;
     inherited Destroy;
end;

procedure TFileSearch.Start;
var
   i, newWildCard : Integer;
   curSearchPath, wildCards : String;
   srchPaths : TStringList;
begin
     fStop := false;

     fSearching := True;   // drh 4/6/98: flag to indicate we are searching
     fFilesFound.Clear;    // drh 4/6/98: new search, so no files should be listed

     // Look for ";" wildcard seperators.
     // loop through replacing the "filename" with each wildcard...
     newWildCard := Pos( ';', fDirName);

     if newWildCard > 0 then
     begin
          curSearchPath := Copy( fdirName, 1, newWildCard-1);
          wildCards := Copy( fdirName, newWildCard+1, length(fDirName) );

          srchPaths := TStringList.Create;
          srchPaths.Add( curSearchPath );

          // Build up a list of search paths by looping through each wildcard
          while length(wildCards) > 0 do
          begin
               curSearchPath := ExtractFilePath( curSearchPath );
               newWildCard := Pos( ';', wildCards );

               if newWildCard > 0 then
               begin
                    curSearchPath := curSearchPath + Copy(wildCards, 1, newWildCard-1);
                    wildCards := Copy(wildCards, newWildCard+1, length(wildCards) );
               end
               else
               begin
                    curSearchPath := curSearchPath + wildCards;
                    wildCards := '';
               end;

               srchPaths.Add( curSearchPath );
          end;

          // Well, we got the paths, lets start searching them shall we?
          for i := 0 to srchPaths.Count - 1 do
              ScanDir(srchPaths.Strings[i], faAnyFile);

          // get rid of search paths.
          srchPaths.Free;
     end
     else // no other wildcards to search, just a single file def
         ScanDir(fdirName, faAnyFile);

     // drh 4/6/98:
     // the following was moved here from end of "ScanDir", just in
     // case multiple searches are being carried out (do not want
     // multiple end of search events being fired).
     if Assigned( fFinishEvent ) then
        fFinishEvent( Self );         // notify user that searching is complete.

     fSearching := False; // drh 4/6/98: flag indicates we arnt searching any more
end;

procedure TFileSearch.ScanDir(ffdirName:string; attr:word);
const
    {$IFNDEF LINUX} // barko
     fi : string = '*.*';
    {$ELSE}
     fi : string = '*';
    {$ENDIF} // barko
     p : string = '.';
     pp : string = '..' ;
var
   path : string;
   doserror : integer;
   sfi : string;

   procedure showq(fullpath:string; FolderInfo:TSearchRec);
   var
      dirq : TSearchRec;
   begin
        if assigned(fChangeFolderEvent) then
           fChangeFolderEvent(fullpath,FolderInfo);

        doserror := FindFirstUTF8(fullpath+sfi,attr,dirq);

        while (doserror = 0)and(not fstop) do
        begin
             if (dirq.name<>p) and (dirq.name<>pp) and (assigned(fFileFindEvent)) then
             begin
                fFileFindEvent( fullpath, dirq );
                fFilesFound.Add( fullpath + dirq.Name ); // drh 4/6/98: Add filename to list of those found thus far
             end;

             doserror := FindNextUTF8(dirq);
             application.processMessages;
        end;
        FindCloseUTF8(dirq);// barko

   end; // showq

   procedure ScanLDir(fffdirName:string; fInfo:TSearchRec);
   var
      dirinfo : TSearchRec;
   begin
        showq(fffDirName, fInfo);
        dosError := FindFirstUTF8(fffDirName+fi, faAnyfile, dirInfo);

        while (doserror = 0) and (not fstop) do
        begin
             application.ProcessMessages;

             if (dirInfo.name<>p) and (dirInfo.name<>pp) then
                if (dirInfo.attr and faDirectory <> 0) and (frec) then
                   ScanLDir(fffdirName+dirinfo.name+delimeter, dirInfo);

             dosError := FindNextUTF8(dirInfo);
             application.ProcessMessages;
        end;
        FindCloseUTF8(dirInfo); // barko

   end; // ScanLDir

var
   fInfo : TSearchRec;
   fPath : string;
begin    // ScanDir

     path := ExtractFilePath( ffDirName );
     sfi := ExtractFileName( ffDirName );

     fPath := Copy(path, 1, length(Path) - 1 );

     FindFirstUTF8(fPath, faAnyfile, fInfo);
     ScanLDir(Path, fInfo);
     FindCloseUTF8(fInfo); // barko
end; // ScanDir

end.